@nodesecure/js-x-ray
Version:
JavaScript AST XRay analysis
62 lines • 1.79 kB
JavaScript
// Import Third-party Dependencies
import FrequencySet from "frequency-set";
// Import Internal Dependencies
import { isNode } from "./estree/types.js";
function noop() {
return true;
}
export class NodeCounter {
type;
name;
lookup = null;
#count = 0;
#properties = null;
#filterFn = noop;
#matchFn = noop;
/**
* @example
* new NodeCounter("FunctionDeclaration");
* new NodeCounter("VariableDeclaration[kind]");
*/
constructor(type, options = {}) {
if (typeof type !== "string") {
throw new TypeError("type must be a string");
}
const typeResult = /([A-Za-z]+)(\[[a-zA-Z]+\])?/g.exec(type);
if (typeResult === null) {
throw new Error("invalid type argument syntax");
}
this.type = typeResult[1];
this.lookup = typeResult[2]?.slice(1, -1) ?? null;
this.name = options?.name ?? this.type;
if (this.lookup) {
this.#properties = new FrequencySet();
}
this.#filterFn = options.filter ?? noop;
this.#matchFn = options.match ?? noop;
}
get count() {
return this.#count;
}
get properties() {
return Object.fromEntries(this.#properties?.entries() ?? []);
}
walk(node) {
if (!isNode(node) || node.type !== this.type) {
return;
}
const castedNode = node;
if (!this.#filterFn(castedNode)) {
return;
}
this.#count++;
if (this.lookup === null) {
this.#matchFn(castedNode, this);
}
else if (this.lookup in node) {
this.#properties?.add(node[this.lookup]);
this.#matchFn(castedNode, this);
}
}
}
//# sourceMappingURL=NodeCounter.js.map