"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'); const createNode = function () { return { props: {} }; }; const getSymbolValue = function (symbol) { /* istanbul ignore next */ if (!symbol) { /* istanbul ignore next */ return null; } /* istanbul ignore next */ if (symbol.type === 'literal') { return symbol.value.value; } /* istanbul ignore next */ return 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; }; let createSymbol = null; const getSymbol = function (node, globals, scope, opt) { const opts = opt || {}; /* istanbul ignore next */ switch (node.type) { case 'Identifier': { return getIdentifier(node, globals, scope, opts); } case 'MemberExpression': { const obj = getSymbol(node.object, globals, scope, opts); const propertySymbol = getSymbol(node.property, globals, scope, { simpleIdentifier: !node.computed }); const propertyValue = getSymbolValue(propertySymbol); /* istanbul ignore next */ 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 ${node.property.name}`); /* istanbul ignore next */ return null; } case 'TSTypeAliasDeclaration': case 'TSEnumDeclaration': case 'TSInterfaceDeclaration': case 'ClassDeclaration': case 'ClassExpression': 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(node.left, globals, node.right, scope, opts); } case 'ClassBody': { const val = createNode(); node.body.forEach(method => { val.props[method.key.name] = createNode(); val.props[method.key.name].type = 'object'; val.props[method.key.name].value = method.value; }); val.type = 'object'; val.value = node; return val; } case 'ObjectExpression': { const val = createNode(); val.type = 'object'; node.properties.forEach(prop => { if ([// @typescript-eslint/parser, espree, acorn, etc. 'SpreadElement', // @babel/eslint-parser 'ExperimentalSpreadProperty'].includes(prop.type)) { return; } const propVal = getSymbol(prop.value, globals, scope, opts); /* istanbul ignore next */ if (propVal) { val.props[prop.key.name] = propVal; } }); return val; } case 'Literal': { const val = createNode(); val.type = 'literal'; val.value = node; return val; } } /* istanbul ignore next */ return null; }; 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; let symbol; switch (node.type) { case 'FunctionDeclaration': /* istanbul ignore next */ // Fall through case 'TSEnumDeclaration': case 'TSInterfaceDeclaration': /* istanbul ignore next */ // Fall through case 'TSTypeAliasDeclaration': case 'ClassDeclaration': { /* istanbul ignore next */ if (node.id && node.id.type === 'Identifier') { return createSymbol(node.id, globals, node, globals); } /* istanbul ignore next */ break; } case 'Identifier': { if (value) { const valueSymbol = getSymbol(value, globals, block); /* istanbul ignore next */ if (valueSymbol) { createBlockSymbol(block, node.name, valueSymbol, globals, isGlobal); return block.props[node.name]; } /* istanbul ignore next */ debug('Identifier: Missing value symbol for %s', node.name); } else { createBlockSymbol(block, node.name, createNode(), globals, isGlobal); return block.props[node.name]; } /* istanbul ignore next */ break; } case 'MemberExpression': { symbol = getSymbol(node.object, globals, block); const propertySymbol = getSymbol(node.property, globals, block, { simpleIdentifier: !node.computed }); const propertyValue = getSymbolValue(propertySymbol); if (symbol && propertyValue) { createBlockSymbol(symbol, propertyValue, getSymbol(value, globals, block), globals, isGlobal); return symbol.props[propertyValue]; } /* istanbul ignore next */ debug('MemberExpression: Missing symbol: %s', node.property.name); break; } } return null; }; // Creates variables from variable definitions const initVariables = function (node, globals, opts) { switch (node.type) { case 'Program': { node.body.forEach(childNode => { initVariables(childNode, globals, opts); }); break; } case 'ExpressionStatement': { initVariables(node.expression, globals, opts); break; } case 'VariableDeclaration': { node.declarations.forEach(declaration => { // let and const const symbol = createSymbol(declaration.id, globals, null, globals); if (opts.initWindow && node.kind === 'var' && globals.props.window) { // If var, also add to window globals.props.window.props[declaration.id.name] = symbol; } }); break; } case 'ExportNamedDeclaration': { if (node.declaration) { initVariables(node.declaration, globals, opts); } break; } } }; // Populates variable maps using AST const mapVariables = function (node, globals, opt, isExport) { /* istanbul ignore next */ const opts = opt || {}; /* istanbul ignore next */ switch (node.type) { case 'Program': { if (opts.ancestorsOnly) { return false; } node.body.forEach(childNode => { mapVariables(childNode, globals, opts); }); break; } case 'ExpressionStatement': { mapVariables(node.expression, globals, opts); break; } case 'AssignmentExpression': { createSymbol(node.left, globals, node.right); break; } case 'VariableDeclaration': { node.declarations.forEach(declaration => { const isGlobal = opts.initWindow && node.kind === 'var' && globals.props.window; const symbol = createSymbol(declaration.id, globals, declaration.init, globals, isGlobal); if (symbol && isExport) { symbol.exported = true; } }); break; } case 'FunctionDeclaration': { /* istanbul ignore next */ if (node.id.type === 'Identifier') { createSymbol(node.id, globals, node, globals, true); } break; } case 'ExportDefaultDeclaration': { const symbol = createSymbol(node.declaration, globals, node.declaration); if (symbol) { symbol.exported = true; } else if (!node.id) { globals.ANONYMOUS_DEFAULT = node.declaration; } break; } case 'ExportNamedDeclaration': { if (node.declaration) { if (node.declaration.type === 'VariableDeclaration') { mapVariables(node.declaration, globals, opts, true); } else { const symbol = createSymbol(node.declaration, globals, node.declaration); /* istanbul ignore next */ if (symbol) { symbol.exported = true; } } } node.specifiers.forEach(specifier => { mapVariables(specifier, globals, opts); }); break; } case 'ExportSpecifier': { const symbol = getSymbol(node.local, globals, globals); /* istanbul ignore next */ if (symbol) { symbol.exported = true; } break; } case 'ClassDeclaration': { createSymbol(node.id, globals, node.body, globals); break; } default: { /* istanbul ignore next */ return false; } } return true; }; const findNode = function (node, block, cache) { let blockCache = cache || []; /* istanbul ignore next */ if (!block || blockCache.includes(block)) { return false; } blockCache = blockCache.slice(); blockCache.push(block); if ((block.type === 'object' || block.type === 'MethodDefinition') && block.value === node) { return true; } const { props = block.body } = block; 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 getExportAncestor = function (nde) { let node = nde; while (node) { if (exportTypes.has(node.type)) { return node; } node = node.parent; } return false; }; const canExportedByAncestorType = new Set(['TSPropertySignature', 'TSMethodSignature', 'ClassProperty', 'Method']); const canExportChildrenType = new Set(['TSInterfaceBody', 'TSInterfaceDeclaration', 'ClassDefinition', 'ClassExpression', 'Program']); const isExportByAncestor = function (nde) { if (!canExportedByAncestorType.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; }; const findExportedNode = function (block, node, cache) { /* istanbul ignore next */ if (block === null) { return false; } const blockCache = cache || []; const { props } = block; for (const propval of Object.values(props)) { blockCache.push(propval); if (propval.exported && (node === propval.value || findNode(node, propval.value))) { return true; } // No need to check `propval` for exported nodes as ESM // exports are only global } return false; }; const isNodeExported = function (node, globals, opt) { if (opt.initModuleExports && globals.props.module && globals.props.module.props.exports && findNode(node, globals.props.module.props.exports)) { 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; }; 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); }; 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 }; }; const isUncommentedExport = function (node, sourceCode, opt, settings) { // console.log({node}); // Optimize with ancestor check for esm if (opt.esm) { 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 parseResult = parse(sourceCode.ast, node, opt); return isNodeExported(node, parseResult.globalVars, opt); }; var _default = { isUncommentedExport, parse }; exports.default = _default; module.exports = exports.default; //# sourceMappingURL=exportParser.js.map