188 lines
5.5 KiB
JavaScript
188 lines
5.5 KiB
JavaScript
'use strict';
|
|
|
|
/* eslint-disable jsdoc/valid-types -- doesn't allow `readonly`.
|
|
TODO: remove eslint-disable when https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/164 is fixed
|
|
*/
|
|
/**
|
|
* @typedef {{ readonly [type: string]: ReadonlyArray<string> }} VisitorKeys
|
|
*/
|
|
/* eslint-enable jsdoc/valid-types -- doesn't allow `readonly string[]`. TODO: check why */
|
|
|
|
/**
|
|
* @type {VisitorKeys}
|
|
*/
|
|
const KEYS = {
|
|
ArrayExpression: ["elements"],
|
|
ArrayPattern: ["elements"],
|
|
ArrowFunctionExpression: ["params", "body"],
|
|
AssignmentExpression: ["left", "right"],
|
|
AssignmentPattern: ["left", "right"],
|
|
AwaitExpression: ["argument"],
|
|
BinaryExpression: ["left", "right"],
|
|
BlockStatement: ["body"],
|
|
BreakStatement: ["label"],
|
|
CallExpression: ["callee", "arguments"],
|
|
CatchClause: ["param", "body"],
|
|
ChainExpression: ["expression"],
|
|
ClassBody: ["body"],
|
|
ClassDeclaration: ["id", "superClass", "body"],
|
|
ClassExpression: ["id", "superClass", "body"],
|
|
ConditionalExpression: ["test", "consequent", "alternate"],
|
|
ContinueStatement: ["label"],
|
|
DebuggerStatement: [],
|
|
DoWhileStatement: ["body", "test"],
|
|
EmptyStatement: [],
|
|
ExperimentalRestProperty: ["argument"],
|
|
ExperimentalSpreadProperty: ["argument"],
|
|
ExportAllDeclaration: ["exported", "source", "attributes"],
|
|
ExportDefaultDeclaration: ["declaration"],
|
|
ExportNamedDeclaration: [
|
|
"declaration",
|
|
"specifiers",
|
|
"source",
|
|
"attributes",
|
|
],
|
|
ExportSpecifier: ["local", "exported"],
|
|
ExpressionStatement: ["expression"],
|
|
ForInStatement: ["left", "right", "body"],
|
|
ForOfStatement: ["left", "right", "body"],
|
|
ForStatement: ["init", "test", "update", "body"],
|
|
FunctionDeclaration: ["id", "params", "body"],
|
|
FunctionExpression: ["id", "params", "body"],
|
|
Identifier: [],
|
|
IfStatement: ["test", "consequent", "alternate"],
|
|
ImportAttribute: ["key", "value"],
|
|
ImportDeclaration: ["specifiers", "source", "attributes"],
|
|
ImportDefaultSpecifier: ["local"],
|
|
ImportExpression: ["source", "options"],
|
|
ImportNamespaceSpecifier: ["local"],
|
|
ImportSpecifier: ["imported", "local"],
|
|
JSXAttribute: ["name", "value"],
|
|
JSXClosingElement: ["name"],
|
|
JSXClosingFragment: [],
|
|
JSXElement: ["openingElement", "children", "closingElement"],
|
|
JSXEmptyExpression: [],
|
|
JSXExpressionContainer: ["expression"],
|
|
JSXFragment: ["openingFragment", "children", "closingFragment"],
|
|
JSXIdentifier: [],
|
|
JSXMemberExpression: ["object", "property"],
|
|
JSXNamespacedName: ["namespace", "name"],
|
|
JSXOpeningElement: ["name", "attributes"],
|
|
JSXOpeningFragment: [],
|
|
JSXSpreadAttribute: ["argument"],
|
|
JSXSpreadChild: ["expression"],
|
|
JSXText: [],
|
|
LabeledStatement: ["label", "body"],
|
|
Literal: [],
|
|
LogicalExpression: ["left", "right"],
|
|
MemberExpression: ["object", "property"],
|
|
MetaProperty: ["meta", "property"],
|
|
MethodDefinition: ["key", "value"],
|
|
NewExpression: ["callee", "arguments"],
|
|
ObjectExpression: ["properties"],
|
|
ObjectPattern: ["properties"],
|
|
PrivateIdentifier: [],
|
|
Program: ["body"],
|
|
Property: ["key", "value"],
|
|
PropertyDefinition: ["key", "value"],
|
|
RestElement: ["argument"],
|
|
ReturnStatement: ["argument"],
|
|
SequenceExpression: ["expressions"],
|
|
SpreadElement: ["argument"],
|
|
StaticBlock: ["body"],
|
|
Super: [],
|
|
SwitchCase: ["test", "consequent"],
|
|
SwitchStatement: ["discriminant", "cases"],
|
|
TaggedTemplateExpression: ["tag", "quasi"],
|
|
TemplateElement: [],
|
|
TemplateLiteral: ["quasis", "expressions"],
|
|
ThisExpression: [],
|
|
ThrowStatement: ["argument"],
|
|
TryStatement: ["block", "handler", "finalizer"],
|
|
UnaryExpression: ["argument"],
|
|
UpdateExpression: ["argument"],
|
|
VariableDeclaration: ["declarations"],
|
|
VariableDeclarator: ["id", "init"],
|
|
WhileStatement: ["test", "body"],
|
|
WithStatement: ["object", "body"],
|
|
YieldExpression: ["argument"],
|
|
};
|
|
|
|
// Types.
|
|
const NODE_TYPES = Object.keys(KEYS);
|
|
|
|
// Freeze the keys.
|
|
for (const type of NODE_TYPES) {
|
|
Object.freeze(KEYS[type]);
|
|
}
|
|
Object.freeze(KEYS);
|
|
|
|
/**
|
|
* @author Toru Nagashima <https://github.com/mysticatea>
|
|
* See LICENSE file in root directory for full license.
|
|
*/
|
|
|
|
/**
|
|
* @typedef {import('./visitor-keys.js').VisitorKeys} VisitorKeys
|
|
*/
|
|
|
|
// List to ignore keys.
|
|
const KEY_BLACKLIST = new Set([
|
|
"parent",
|
|
"leadingComments",
|
|
"trailingComments",
|
|
]);
|
|
|
|
/**
|
|
* Check whether a given key should be used or not.
|
|
* @param {string} key The key to check.
|
|
* @returns {boolean} `true` if the key should be used.
|
|
*/
|
|
function filterKey(key) {
|
|
return !KEY_BLACKLIST.has(key) && key[0] !== "_";
|
|
}
|
|
|
|
/* eslint-disable jsdoc/valid-types -- doesn't allow `readonly`.
|
|
TODO: remove eslint-disable when https://github.com/jsdoc-type-pratt-parser/jsdoc-type-pratt-parser/issues/164 is fixed
|
|
*/
|
|
/**
|
|
* Get visitor keys of a given node.
|
|
* @param {Object} node The AST node to get keys.
|
|
* @returns {readonly string[]} Visitor keys of the node.
|
|
*/
|
|
function getKeys(node) {
|
|
return Object.keys(node).filter(filterKey);
|
|
}
|
|
/* eslint-enable jsdoc/valid-types -- doesn't allow `readonly` */
|
|
|
|
/**
|
|
* Make the union set with `KEYS` and given keys.
|
|
* @param {VisitorKeys} additionalKeys The additional keys.
|
|
* @returns {VisitorKeys} The union set.
|
|
*/
|
|
function unionWith(additionalKeys) {
|
|
const retv =
|
|
/** @type {{ [type: string]: ReadonlyArray<string> }} */
|
|
(Object.assign({}, KEYS));
|
|
|
|
for (const type of Object.keys(additionalKeys)) {
|
|
if (Object.hasOwn(retv, type)) {
|
|
const keys = new Set(additionalKeys[type]);
|
|
|
|
for (const key of retv[type]) {
|
|
keys.add(key);
|
|
}
|
|
|
|
retv[type] = Object.freeze(Array.from(keys));
|
|
} else {
|
|
retv[type] = Object.freeze(Array.from(additionalKeys[type]));
|
|
}
|
|
}
|
|
|
|
return Object.freeze(retv);
|
|
}
|
|
|
|
exports.KEYS = KEYS;
|
|
exports.getKeys = getKeys;
|
|
exports.unionWith = unionWith;
|