Skip to content

Instantly share code, notes, and snippets.

@nojvek
Created June 15, 2021 08:41
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save nojvek/416560c9723da23f5aa0b72887c3286e to your computer and use it in GitHub Desktop.
Save nojvek/416560c9723da23f5aa0b72887c3286e to your computer and use it in GitHub Desktop.
/**
* returns a function that returns true when node matches the matcher.
* matchers can be built recursively. If a property of a matcher is a function, it is evaluated.
*
* @see https://astexplorer.net/ to explore how ESTree nodes are structured
* @example nodeMatcher({type: `Identifier`, name: `foo`})(node)
*
* @param {Obj} matcher
* @param {Obj} refObj
* @param {string} refKey
* @return {(node: Obj) => boolean}
*/
exports.nodeMatcher = function nodeMatcher(matcher, refObj = null, refKey = ``) {
return function (node) {
// typeof null === `object`. handle that case
if (node === null || typeof node !== `object`) {
return false;
}
for (const [prop, matchValue] of Object.entries(matcher)) {
const nodeValue = node[prop];
if (!(typeof matchValue === `function` && matchValue(nodeValue)) && matchValue !== nodeValue) {
// uncomment for debugging why a node didn't match
// console.log(`nodeMatcher '${prop}'`, typeof matchValue !== `function` ? `${matchValue} !== ${nodeValue}` : ``);
return false;
}
}
// if refObj is passed and node matches, save node reference
// this makes it easier to traverse an AST and capture reference of nodes of interest
if (refObj) {
refObj[refKey] = node;
}
return true;
};
};
/**
* returns a function that returns true when node matches any of the matchers.
*
* @param {Array<(node: Obj) => boolean>} matchers
* @return {(node: Obj) => boolean}
*/
exports.anyMatcher = function anyMatcher(matchers) {
return function (node) {
for (const matcher of matchers) {
if (matcher(node)) {
return true;
}
}
return false;
};
};
/**
* returns a function that returns true when node matches all of the matchers.
*
* @param {Array<(node: Obj) => boolean>} matchers
* @return {(node: Obj) => boolean}
*/
exports.allMatcher = function allMatcher(matchers) {
return function (node) {
for (const matcher of matchers) {
if (!matcher(node)) {
return false;
}
}
return true;
};
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment