123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735 |
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var _jsdoccomment = require("@es-joy/jsdoccomment");
- var _debug = _interopRequireDefault(require("debug"));
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- const debug = (0, _debug.default)('requireExportJsdoc');
- /**
- * @typedef {{
- * value: string
- * }} ValueObject
- */
- /**
- * @typedef {{
- * type?: string,
- * value?: ValueObject|import('eslint').Rule.Node,
- * props: {
- * [key: string]: CreatedNode|null,
- * },
- * special?: true,
- * globalVars?: CreatedNode,
- * exported?: boolean,
- * ANONYMOUS_DEFAULT?: import('eslint').Rule.Node
- * }} CreatedNode
- */
- /**
- * @returns {CreatedNode}
- */
- const createNode = function () {
- return {
- props: {}
- };
- };
- /**
- * @param {CreatedNode|null} symbol
- * @returns {string|null}
- */
- const getSymbolValue = function (symbol) {
- /* istanbul ignore if */
- if (!symbol) {
- return null;
- }
- /* istanbul ignore else */
- if (symbol.type === 'literal') {
- return /** @type {ValueObject} */symbol.value.value;
- }
- /* istanbul ignore next */
- return null;
- };
- /**
- *
- * @param {import('estree').Identifier} node
- * @param {CreatedNode} globals
- * @param {CreatedNode} scope
- * @param {SymbolOptions} opts
- * @returns {CreatedNode|null}
- */
- const getIdentifier = function (node, globals, scope, opts) {
- if (opts.simpleIdentifier) {
- // Type is Identier for noncomputed properties
- const identifierLiteral = createNode();
- identifierLiteral.type = 'literal';
- identifierLiteral.value = {
- value: node.name
- };
- return identifierLiteral;
- }
- /* istanbul ignore next */
- const block = scope || globals;
- // As scopes are not currently supported, they are not traversed upwards recursively
- if (block.props[node.name]) {
- return block.props[node.name];
- }
- // Seems this will only be entered once scopes added and entered
- /* istanbul ignore next */
- if (globals.props[node.name]) {
- return globals.props[node.name];
- }
- return null;
- };
- /**
- * @callback CreateSymbol
- * @param {import('eslint').Rule.Node|null} node
- * @param {CreatedNode} globals
- * @param {import('eslint').Rule.Node|null} value
- * @param {CreatedNode} [scope]
- * @param {boolean|SymbolOptions} [isGlobal]
- * @returns {CreatedNode|null}
- */
- /** @type {CreateSymbol} */
- let createSymbol; // eslint-disable-line prefer-const
- /* eslint-disable complexity -- Temporary */
- /**
- * @typedef {{
- * simpleIdentifier?: boolean
- * }} SymbolOptions
- */
- /**
- *
- * @param {import('eslint').Rule.Node} node
- * @param {CreatedNode} globals
- * @param {CreatedNode} scope
- * @param {SymbolOptions} [opt]
- * @returns {CreatedNode|null}
- */
- const getSymbol = function (node, globals, scope, opt) {
- /* eslint-enable complexity -- Temporary */
- const opts = opt || {};
- /* istanbul ignore next */
- switch (node.type) {
- case 'Identifier':
- {
- return getIdentifier(node, globals, scope, opts);
- }
- case 'MemberExpression':
- {
- const obj = getSymbol( /** @type {import('eslint').Rule.Node} */
- node.object, globals, scope, opts);
- const propertySymbol = getSymbol( /** @type {import('eslint').Rule.Node} */
- node.property, globals, scope, {
- simpleIdentifier: !node.computed
- });
- const propertyValue = getSymbolValue(propertySymbol);
- /* istanbul ignore else */
- if (obj && propertyValue && obj.props[propertyValue]) {
- const block = obj.props[propertyValue];
- return block;
- }
- /*
- if (opts.createMissingProps && propertyValue) {
- obj.props[propertyValue] = createNode();
- return obj.props[propertyValue];
- }
- */
- /* istanbul ignore next */
- debug(`MemberExpression: Missing property ${
- /** @type {import('estree').PrivateIdentifier} */node.property.name}`);
- /* istanbul ignore next */
- return null;
- }
- case 'ClassExpression':
- {
- return getSymbol( /** @type {import('eslint').Rule.Node} */
- node.body, globals, scope, opts);
- }
- // @ts-expect-error TS OK
- case 'TSTypeAliasDeclaration':
- // @ts-expect-error TS OK
- // Fallthrough
- case 'TSEnumDeclaration':
- case 'TSInterfaceDeclaration':
- case 'ClassDeclaration':
- case 'FunctionExpression':
- case 'FunctionDeclaration':
- case 'ArrowFunctionExpression':
- {
- const val = createNode();
- val.props.prototype = createNode();
- val.props.prototype.type = 'object';
- val.type = 'object';
- val.value = node;
- return val;
- }
- case 'AssignmentExpression':
- {
- return createSymbol( /** @type {import('eslint').Rule.Node} */
- node.left, globals, /** @type {import('eslint').Rule.Node} */
- node.right, scope, opts);
- }
- case 'ClassBody':
- {
- const val = createNode();
- for (const method of node.body) {
- val.props[/** @type {import('estree').Identifier} */( /** @type {import('estree').MethodDefinition} */method.key).name] = createNode();
- /** @type {{[key: string]: CreatedNode}} */
- val.props[/** @type {import('estree').Identifier} */( /** @type {import('estree').MethodDefinition} */method.key).name].type = 'object';
- /** @type {{[key: string]: CreatedNode}} */
- val.props[/** @type {import('estree').Identifier} */( /** @type {import('estree').MethodDefinition} */method.key).name].value = /** @type {import('eslint').Rule.Node} */
- /** @type {import('estree').MethodDefinition} */method.value;
- }
- val.type = 'object';
- val.value = node.parent;
- return val;
- }
- case 'ObjectExpression':
- {
- const val = createNode();
- val.type = 'object';
- for (const prop of node.properties) {
- if ([
- // @typescript-eslint/parser, espree, acorn, etc.
- 'SpreadElement',
- // @babel/eslint-parser
- 'ExperimentalSpreadProperty'].includes(prop.type)) {
- continue;
- }
- const propVal = getSymbol( /** @type {import('eslint').Rule.Node} */
- /** @type {import('estree').Property} */
- prop.value, globals, scope, opts);
- /* istanbul ignore if */
- if (propVal) {
- val.props[/** @type {import('estree').PrivateIdentifier} */
- ( /** @type {import('estree').Property} */prop.key).name] = propVal;
- }
- }
- return val;
- }
- case 'Literal':
- {
- const val = createNode();
- val.type = 'literal';
- val.value = node;
- return val;
- }
- }
- /* istanbul ignore next */
- return null;
- };
- /**
- *
- * @param {CreatedNode} block
- * @param {string} name
- * @param {CreatedNode|null} value
- * @param {CreatedNode} globals
- * @param {boolean|SymbolOptions|undefined} isGlobal
- * @returns {void}
- */
- const createBlockSymbol = function (block, name, value, globals, isGlobal) {
- block.props[name] = value;
- if (isGlobal && globals.props.window && globals.props.window.special) {
- globals.props.window.props[name] = value;
- }
- };
- createSymbol = function (node, globals, value, scope, isGlobal) {
- const block = scope || globals;
- /* istanbul ignore if */
- if (!node) {
- return null;
- }
- let symbol;
- switch (node.type) {
- case 'FunctionDeclaration':
- /* istanbul ignore next */
- // @ts-expect-error TS OK
- // Fall through
- case 'TSEnumDeclaration':
- case 'TSInterfaceDeclaration':
- /* istanbul ignore next */
- // @ts-expect-error TS OK
- // Fall through
- case 'TSTypeAliasDeclaration':
- case 'ClassDeclaration':
- {
- const nde = /** @type {import('estree').ClassDeclaration} */node;
- /* istanbul ignore else */
- if (nde.id && nde.id.type === 'Identifier') {
- return createSymbol( /** @type {import('eslint').Rule.Node} */nde.id, globals, node, globals);
- }
- /* istanbul ignore next */
- break;
- }
- case 'Identifier':
- {
- const nde = /** @type {import('estree').Identifier} */node;
- if (value) {
- const valueSymbol = getSymbol(value, globals, block);
- /* istanbul ignore else */
- if (valueSymbol) {
- createBlockSymbol(block, nde.name, valueSymbol, globals, isGlobal);
- return block.props[nde.name];
- }
- /* istanbul ignore next */
- debug('Identifier: Missing value symbol for %s', nde.name);
- } else {
- createBlockSymbol(block, nde.name, createNode(), globals, isGlobal);
- return block.props[nde.name];
- }
- /* istanbul ignore next */
- break;
- }
- case 'MemberExpression':
- {
- const nde = /** @type {import('estree').MemberExpression} */node;
- symbol = getSymbol( /** @type {import('eslint').Rule.Node} */nde.object, globals, block);
- const propertySymbol = getSymbol( /** @type {import('eslint').Rule.Node} */nde.property, globals, block, {
- simpleIdentifier: !nde.computed
- });
- const propertyValue = getSymbolValue(propertySymbol);
- if (symbol && propertyValue) {
- createBlockSymbol(symbol, propertyValue, getSymbol( /** @type {import('eslint').Rule.Node} */
- value, globals, block), globals, isGlobal);
- return symbol.props[propertyValue];
- }
- debug('MemberExpression: Missing symbol: %s', /** @type {import('estree').Identifier} */nde.property.name);
- break;
- }
- }
- return null;
- };
- /**
- * Creates variables from variable definitions
- * @param {import('eslint').Rule.Node} node
- * @param {CreatedNode} globals
- * @param {import('./rules/requireJsdoc.js').RequireJsdocOpts} opts
- * @returns {void}
- */
- const initVariables = function (node, globals, opts) {
- switch (node.type) {
- case 'Program':
- {
- for (const childNode of node.body) {
- initVariables( /** @type {import('eslint').Rule.Node} */
- childNode, globals, opts);
- }
- break;
- }
- case 'ExpressionStatement':
- {
- initVariables( /** @type {import('eslint').Rule.Node} */
- node.expression, globals, opts);
- break;
- }
- case 'VariableDeclaration':
- {
- for (const declaration of node.declarations) {
- // let and const
- const symbol = createSymbol( /** @type {import('eslint').Rule.Node} */
- declaration.id, globals, null, globals);
- if (opts.initWindow && node.kind === 'var' && globals.props.window) {
- // If var, also add to window
- globals.props.window.props[/** @type {import('estree').Identifier} */
- declaration.id.name] = symbol;
- }
- }
- break;
- }
- case 'ExportNamedDeclaration':
- {
- if (node.declaration) {
- initVariables( /** @type {import('eslint').Rule.Node} */
- node.declaration, globals, opts);
- }
- break;
- }
- }
- };
- /* eslint-disable complexity -- Temporary */
- /**
- * Populates variable maps using AST
- * @param {import('eslint').Rule.Node} node
- * @param {CreatedNode} globals
- * @param {import('./rules/requireJsdoc.js').RequireJsdocOpts} opt
- * @param {true} [isExport]
- * @returns {boolean}
- */
- const mapVariables = function (node, globals, opt, isExport) {
- /* eslint-enable complexity -- Temporary */
- /* istanbul ignore next */
- const opts = opt || {};
- /* istanbul ignore next */
- switch (node.type) {
- case 'Program':
- {
- if (opts.ancestorsOnly) {
- return false;
- }
- for (const childNode of node.body) {
- mapVariables( /** @type {import('eslint').Rule.Node} */
- childNode, globals, opts);
- }
- break;
- }
- case 'ExpressionStatement':
- {
- mapVariables( /** @type {import('eslint').Rule.Node} */
- node.expression, globals, opts);
- break;
- }
- case 'AssignmentExpression':
- {
- createSymbol( /** @type {import('eslint').Rule.Node} */
- node.left, globals, /** @type {import('eslint').Rule.Node} */
- node.right);
- break;
- }
- case 'VariableDeclaration':
- {
- for (const declaration of node.declarations) {
- const isGlobal = Boolean(opts.initWindow && node.kind === 'var' && globals.props.window);
- const symbol = createSymbol( /** @type {import('eslint').Rule.Node} */
- declaration.id, globals, /** @type {import('eslint').Rule.Node} */
- declaration.init, globals, isGlobal);
- if (symbol && isExport) {
- symbol.exported = true;
- }
- }
- break;
- }
- case 'FunctionDeclaration':
- {
- /* istanbul ignore if */
- if ( /** @type {import('estree').Identifier} */node.id.type === 'Identifier') {
- createSymbol( /** @type {import('eslint').Rule.Node} */
- node.id, globals, node, globals, true);
- }
- break;
- }
- case 'ExportDefaultDeclaration':
- {
- const symbol = createSymbol( /** @type {import('eslint').Rule.Node} */
- node.declaration, globals, /** @type {import('eslint').Rule.Node} */
- node.declaration);
- if (symbol) {
- symbol.exported = true;
- } else {
- // if (!node.id) {
- globals.ANONYMOUS_DEFAULT = /** @type {import('eslint').Rule.Node} */
- node.declaration;
- }
- break;
- }
- case 'ExportNamedDeclaration':
- {
- if (node.declaration) {
- if (node.declaration.type === 'VariableDeclaration') {
- mapVariables( /** @type {import('eslint').Rule.Node} */
- node.declaration, globals, opts, true);
- } else {
- const symbol = createSymbol( /** @type {import('eslint').Rule.Node} */
- node.declaration, globals, /** @type {import('eslint').Rule.Node} */
- node.declaration);
- /* istanbul ignore if */
- if (symbol) {
- symbol.exported = true;
- }
- }
- }
- for (const specifier of node.specifiers) {
- mapVariables( /** @type {import('eslint').Rule.Node} */
- specifier, globals, opts);
- }
- break;
- }
- case 'ExportSpecifier':
- {
- const symbol = getSymbol( /** @type {import('eslint').Rule.Node} */
- node.local, globals, globals);
- /* istanbul ignore if */
- if (symbol) {
- symbol.exported = true;
- }
- break;
- }
- case 'ClassDeclaration':
- {
- createSymbol( /** @type {import('eslint').Rule.Node|null} */node.id, globals, /** @type {import('eslint').Rule.Node} */node.body, globals);
- break;
- }
- default:
- {
- /* istanbul ignore next */
- return false;
- }
- }
- return true;
- };
- /**
- *
- * @param {import('eslint').Rule.Node} node
- * @param {CreatedNode|ValueObject|string|undefined|
- * import('eslint').Rule.Node} block
- * @param {(CreatedNode|ValueObject|string|
- * import('eslint').Rule.Node)[]} [cache]
- * @returns {boolean}
- */
- const findNode = function (node, block, cache) {
- let blockCache = cache || [];
- if (!block || blockCache.includes(block)) {
- return false;
- }
- blockCache = blockCache.slice();
- blockCache.push(block);
- if (typeof block === 'object' && 'type' in block && (block.type === 'object' || block.type === 'MethodDefinition') && block.value === node) {
- return true;
- }
- if (typeof block !== 'object') {
- return false;
- }
- const props = 'props' in block && block.props || 'body' in block && block.body;
- for (const propval of Object.values(props || {})) {
- if (Array.isArray(propval)) {
- /* istanbul ignore if */
- if (propval.some(val => {
- return findNode(node, val, blockCache);
- })) {
- return true;
- }
- } else if (findNode(node, propval, blockCache)) {
- return true;
- }
- }
- return false;
- };
- const exportTypes = new Set(['ExportNamedDeclaration', 'ExportDefaultDeclaration']);
- const ignorableNestedTypes = new Set(['FunctionDeclaration', 'ArrowFunctionExpression', 'FunctionExpression']);
- /**
- * @param {import('eslint').Rule.Node} nde
- * @returns {import('eslint').Rule.Node|false}
- */
- const getExportAncestor = function (nde) {
- let node = nde;
- let idx = 0;
- const ignorableIfDeep = ignorableNestedTypes.has(nde === null || nde === void 0 ? void 0 : nde.type);
- while (node) {
- // Ignore functions nested more deeply than say `export default function () {}`
- if (idx >= 2 && ignorableIfDeep) {
- break;
- }
- if (exportTypes.has(node.type)) {
- return node;
- }
- node = node.parent;
- idx++;
- }
- return false;
- };
- const canBeExportedByAncestorType = new Set(['TSPropertySignature', 'TSMethodSignature', 'ClassProperty', 'PropertyDefinition', 'Method']);
- const canExportChildrenType = new Set(['TSInterfaceBody', 'TSInterfaceDeclaration', 'TSTypeLiteral', 'TSTypeAliasDeclaration', 'ClassDeclaration', 'ClassBody', 'ClassDefinition', 'ClassExpression', 'Program']);
- /**
- * @param {import('eslint').Rule.Node} nde
- * @returns {false|import('eslint').Rule.Node}
- */
- const isExportByAncestor = function (nde) {
- if (!canBeExportedByAncestorType.has(nde.type)) {
- return false;
- }
- let node = nde.parent;
- while (node) {
- if (exportTypes.has(node.type)) {
- return node;
- }
- if (!canExportChildrenType.has(node.type)) {
- return false;
- }
- node = node.parent;
- }
- return false;
- };
- /**
- *
- * @param {CreatedNode} block
- * @param {import('eslint').Rule.Node} node
- * @param {CreatedNode[]} [cache] Currently unused
- * @returns {boolean}
- */
- const findExportedNode = function (block, node, cache) {
- /* istanbul ignore if */
- if (block === null) {
- return false;
- }
- const blockCache = cache || [];
- const {
- props
- } = block;
- for (const propval of Object.values(props)) {
- const pval = /** @type {CreatedNode} */propval;
- blockCache.push(pval);
- if (pval.exported && (node === pval.value || findNode(node, pval.value))) {
- return true;
- }
- // No need to check `propval` for exported nodes as ESM
- // exports are only global
- }
- return false;
- };
- /**
- *
- * @param {import('eslint').Rule.Node} node
- * @param {CreatedNode} globals
- * @param {import('./rules/requireJsdoc.js').RequireJsdocOpts} opt
- * @returns {boolean}
- */
- const isNodeExported = function (node, globals, opt) {
- var _globals$props$module;
- const moduleExports = (_globals$props$module = globals.props.module) === null || _globals$props$module === void 0 || (_globals$props$module = _globals$props$module.props) === null || _globals$props$module === void 0 ? void 0 : _globals$props$module.exports;
- if (opt.initModuleExports && moduleExports && findNode(node, moduleExports)) {
- return true;
- }
- if (opt.initWindow && globals.props.window && findNode(node, globals.props.window)) {
- return true;
- }
- if (opt.esm && findExportedNode(globals, node)) {
- return true;
- }
- return false;
- };
- /**
- *
- * @param {import('eslint').Rule.Node} node
- * @param {CreatedNode} globalVars
- * @param {import('./rules/requireJsdoc.js').RequireJsdocOpts} opts
- * @returns {boolean}
- */
- const parseRecursive = function (node, globalVars, opts) {
- // Iterate from top using recursion - stop at first processed node from top
- if (node.parent && parseRecursive(node.parent, globalVars, opts)) {
- return true;
- }
- return mapVariables(node, globalVars, opts);
- };
- /**
- *
- * @param {import('eslint').Rule.Node} ast
- * @param {import('eslint').Rule.Node} node
- * @param {import('./rules/requireJsdoc.js').RequireJsdocOpts} opt
- * @returns {CreatedNode}
- */
- const parse = function (ast, node, opt) {
- /* istanbul ignore next */
- const opts = opt || {
- ancestorsOnly: false,
- esm: true,
- initModuleExports: true,
- initWindow: true
- };
- const globalVars = createNode();
- if (opts.initModuleExports) {
- globalVars.props.module = createNode();
- globalVars.props.module.props.exports = createNode();
- globalVars.props.exports = globalVars.props.module.props.exports;
- }
- if (opts.initWindow) {
- globalVars.props.window = createNode();
- globalVars.props.window.special = true;
- }
- if (opts.ancestorsOnly) {
- parseRecursive(node, globalVars, opts);
- } else {
- initVariables(ast, globalVars, opts);
- mapVariables(ast, globalVars, opts);
- }
- return {
- globalVars,
- props: {}
- };
- };
- const accessibilityNodes = new Set(['PropertyDefinition', 'MethodDefinition']);
- /**
- *
- * @param {import('eslint').Rule.Node} node
- * @returns {boolean}
- */
- const hasAccessibility = node => {
- return accessibilityNodes.has(node.type) && 'accessibility' in node && node.accessibility !== 'public' && node.accessibility !== undefined;
- };
- /**
- *
- * @param {import('eslint').Rule.Node} node
- * @param {import('eslint').SourceCode} sourceCode
- * @param {import('./rules/requireJsdoc.js').RequireJsdocOpts} opt
- * @param {import('./iterateJsdoc.js').Settings} settings
- * @returns {boolean}
- */
- const isUncommentedExport = function (node, sourceCode, opt, settings) {
- // console.log({node});
- // Optimize with ancestor check for esm
- if (opt.esm) {
- if (hasAccessibility(node) || node.parent && hasAccessibility(node.parent)) {
- return false;
- }
- const exportNode = getExportAncestor(node);
- // Is export node comment
- if (exportNode && !(0, _jsdoccomment.findJSDocComment)(exportNode, sourceCode, settings)) {
- return true;
- }
- /**
- * Some typescript types are not in variable map, but inherit exported (interface property and method)
- */
- if (isExportByAncestor(node) && !(0, _jsdoccomment.findJSDocComment)(node, sourceCode, settings)) {
- return true;
- }
- }
- const ast = /** @type {unknown} */sourceCode.ast;
- const parseResult = parse( /** @type {import('eslint').Rule.Node} */
- ast, node, opt);
- return isNodeExported(node, /** @type {CreatedNode} */parseResult.globalVars, opt);
- };
- var _default = exports.default = {
- isUncommentedExport,
- parse
- };
- module.exports = exports.default;
- //# sourceMappingURL=exportParser.js.map
|