'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 }} 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" ], ExportDefaultDeclaration: [ "declaration" ], ExportNamedDeclaration: [ "declaration", "specifiers", "source" ], ExportSpecifier: [ "exported", "local" ], 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" ], ImportDeclaration: [ "specifiers", "source" ], ImportDefaultSpecifier: [ "local" ], ImportExpression: [ "source" ], 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 * 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 }} */ (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;