// Checks if the source ast implements the target ast. Ignores extra keys on source ast export default function assertImplementsAST(target, source, path) { if (!path) { path = []; } function error(text) { const err = new Error(`At ${path.join(".")}: ${text}:`); err.depth = path.length + 1; throw err; } const typeA = target === null ? "null" : typeof target; const typeB = source === null ? "null" : typeof source; if (typeA !== typeB) { error( `have different types (${typeA} !== ${typeB}) (${target} !== ${source})`, ); } else if ( typeA === "object" && ["RegExp"].indexOf(target.constructor.name) !== -1 && target.constructor.name !== source.constructor.name ) { error( `object have different constructors (${target.constructor.name} !== ${source.constructor.name}`, ); } else if (typeA === "object") { const keysTarget = Object.keys(target); for (const i in keysTarget) { const key = keysTarget[i]; path.push(key); assertImplementsAST(target[key], source[key], path); path.pop(); } } else if (target !== source) { error( `are different (${JSON.stringify(target)} !== ${JSON.stringify(source)})`, ); } }