UNPKG

vue-docgen-api

Version:

Toolbox to extract information from Vue component files for documentation generation purposes.

1,217 lines (1,187 loc) 224 kB
'use strict'; var fs = require('fs'); var path = require('path'); var util = require('util'); var recast = require('recast'); var parser$2 = require('@babel/parser'); var LRUCache = require('lru-cache'); var hash = require('hash-sum'); var bt = require('@babel/types'); var esmResolveNative = require('esm-resolve'); var astTypes = require('ast-types'); var compilerSfc = require('@vue/compiler-sfc'); var pug = require('pug'); var compilerDom = require('@vue/compiler-dom'); var vueInbrowserCompilerIndependentUtils = require('vue-inbrowser-compiler-independent-utils'); function _interopNamespaceDefault(e) { var n = Object.create(null); if (e) { Object.keys(e).forEach(function (k) { if (k !== 'default') { var d = Object.getOwnPropertyDescriptor(e, k); Object.defineProperty(n, k, d.get ? d : { enumerable: true, get: function () { return e[k]; } }); } }); } n.default = e; return Object.freeze(n); } var fs__namespace = /*#__PURE__*/_interopNamespaceDefault(fs); var path__namespace = /*#__PURE__*/_interopNamespaceDefault(path); var bt__namespace = /*#__PURE__*/_interopNamespaceDefault(bt); var pug__namespace = /*#__PURE__*/_interopNamespaceDefault(pug); /****************************************************************************** Copyright (c) Microsoft Corporation. Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ***************************************************************************** */ var __assign = function() { __assign = Object.assign || function __assign(t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } return t; }; return __assign.apply(this, arguments); }; function __awaiter(thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); } function __generator(thisArg, body) { var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; function verb(n) { return function (v) { return step([n, v]); }; } function step(op) { if (f) throw new TypeError("Generator is already executing."); while (g && (g = 0, op[0] && (_ = 0)), _) try { if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; if (y = 0, t) op = [op[0] & 2, t.value]; switch (op[0]) { case 0: case 1: t = op; break; case 4: _.label++; return { value: op[1], done: false }; case 5: _.label++; y = op[1]; op = [0]; continue; case 7: op = _.ops.pop(); _.trys.pop(); continue; default: if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } if (t[2]) _.ops.pop(); _.trys.pop(); continue; } op = body.call(thisArg, _); } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; } } function __values(o) { var s = typeof Symbol === "function" && Symbol.iterator, m = s && o[s], i = 0; if (m) return m.call(o); if (o && typeof o.length === "number") return { next: function () { if (o && i >= o.length) o = void 0; return { value: o && o[i++], done: !o }; } }; throw new TypeError(s ? "Object is not iterable." : "Symbol.iterator is not defined."); } function __read(o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value); } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; } function __spreadArray(to, from, pack) { if (pack || arguments.length === 2) for (var i = 0, l = from.length, ar; i < l; i++) { if (ar || !(i in from)) { if (!ar) ar = Array.prototype.slice.call(from, 0, i); ar[i] = from[i]; } } return to.concat(ar || Array.prototype.slice.call(from)); } var tsMap = {}; Object.defineProperty(tsMap, "__esModule", { value: true }); var TsMap = (function () { // Accept an optional parameter, // The parameter's type: // [ // [K, V], [K, V], ... // ] function TsMap(intrator) { // Used to store keys. this.keyStore = []; // Used to store values. this.valueStore = []; // The Map's size, // increase at function set, // decrease at function remove, // clear at function clear. this.size = 0; if (intrator) { for (var _i = 0, intrator_1 = intrator; _i < intrator_1.length; _i++) { var item = intrator_1[_i]; this.keyStore.push(item[0]); this.valueStore.push(item[1]); this.size++; } } } // set a key-value to Map, // return this to chain called. TsMap.prototype.set = function (k, v) { var existed = false; var ks = this.keyStore; var vs = this.valueStore; // if key is existed, replace it. for (var i = ks.length; i > -1; i--) { if (ks[i] === k) { vs[i] = v; existed = true; } } if (!existed) { this.keyStore.push(k); this.valueStore.push(v); this.size++; } return this; }; // Return the value of the corresponding key, // if dosn't has, return undefind. TsMap.prototype.get = function (k) { var ks = this.keyStore; for (var i = ks.length; i > -1; i--) { if (ks[i] === k) { return this.valueStore[i]; } } return undefined; }; // Determine if a key is included. TsMap.prototype.has = function (k) { var ks = this.keyStore; for (var i = ks.length; i > -1; i--) { if (ks[i] === k) { return true; } } return false; }; // Delete all the corresponding keys and its value, // if detele success, return true. // else return false. TsMap.prototype.delete = function (k) { var ks = this.keyStore; var len = ks.length; var deleteFlag = false; while (len--) { if (ks[len] === k) { ks.splice(len, 1); this.size--; deleteFlag = true; } } return deleteFlag; }; // Empty the Map. TsMap.prototype.clear = function () { this.keyStore.splice(0, this.size); this.valueStore.splice(0, this.size); this.size = 0; }; // return all Map's key. TsMap.prototype.keys = function () { return this.keyStore; }; // return all Map's value. TsMap.prototype.values = function () { return this.valueStore; }; // return all Map's key-value. TsMap.prototype.entries = function () { var entries = []; var ks = this.keyStore; var vs = this.valueStore; for (var i = 0; i < this.size; i++) { entries.push([ks[i], vs[i]]); } return entries; }; // Traversal the Map, // Accept two parameters, first is a callback, second is a optional context. // callback function accepts 3 optional params. // first is value, second is key, last is the map TsMap.prototype.forEach = function (cb, context) { var size = this.size; var ks = this.keyStore; var vs = this.valueStore; for (var i = 0; i < size; i++) { cb.bind(context || this)(vs[i], ks[i], this); } }; return TsMap; }()); var _default = tsMap.default = TsMap; var Documentation = /** @class */ (function () { function Documentation(fullFilePath) { this.componentFullfilePath = fullFilePath; this.propsMap = new _default(); this.eventsMap = new _default(); this.slotsMap = new _default(); this.methodsMap = new _default(); this.exposedMap = new _default(); this.sourceFiles = new Set([fullFilePath]); this.originExtendsMixin = {}; this.dataMap = new _default(); } Documentation.prototype.setOrigin = function (origin) { this.originExtendsMixin = origin.extends ? { extends: origin.extends } : {}; this.originExtendsMixin = origin.mixin ? { mixin: origin.mixin } : {}; }; Documentation.prototype.setDocsBlocks = function (docsBlocks) { this.docsBlocks = docsBlocks; }; Documentation.prototype.set = function (key, value) { this.dataMap.set(key, value); }; Documentation.prototype.get = function (key) { return this.dataMap.get(key); }; Documentation.prototype.getPropDescriptor = function (propName) { var vModelDescriptor = this.propsMap.get('v-model'); return vModelDescriptor && vModelDescriptor.name === propName ? vModelDescriptor : this.getDescriptor(propName, this.propsMap, function () { return ({ name: propName }); }); }; Documentation.prototype.getEventDescriptor = function (eventName) { return this.getDescriptor(eventName, this.eventsMap, function () { return ({ name: eventName }); }); }; Documentation.prototype.getSlotDescriptor = function (slotName) { return this.getDescriptor(slotName, this.slotsMap, function () { return ({ name: slotName }); }); }; Documentation.prototype.getMethodDescriptor = function (methodName) { return this.getDescriptor(methodName, this.methodsMap, function () { return ({ name: methodName }); }); }; Documentation.prototype.getExposeDescriptor = function (exposedName) { return this.getDescriptor(exposedName, this.exposedMap, function () { return ({ name: exposedName }); }); }; Documentation.prototype.toObject = function () { var props = this.getObjectFromDescriptor(this.propsMap); var methods = this.getObjectFromDescriptor(this.methodsMap); var events = this.getObjectFromDescriptor(this.eventsMap); var slots = this.getObjectFromDescriptor(this.slotsMap); var expose = this.getObjectFromDescriptor(this.exposedMap); var sourceFiles = __spreadArray([], __read(this.sourceFiles), false).sort(); var obj = {}; this.dataMap.forEach(function (value, key) { if (key) { obj[key] = value; } }); if (this.docsBlocks) { obj.docsBlocks = this.docsBlocks; } return __assign(__assign({}, obj), { // initialize non null params description: obj.description || '', tags: obj.tags || {}, // set all the static properties exportName: obj.exportName, displayName: obj.displayName, expose: expose, props: props, events: events, methods: methods, slots: slots, sourceFiles: sourceFiles }); }; Documentation.prototype.getDescriptor = function (name, map, init) { var descriptor = map.get(name); if (!descriptor) { descriptor = init(); descriptor = __assign(__assign({}, descriptor), this.originExtendsMixin); map.set(name, descriptor); } return descriptor; }; Documentation.prototype.getObjectFromDescriptor = function (map) { if (map.size > 0) { var obj_1 = []; map.forEach(function (descriptor, name) { if (name && descriptor) { obj_1.push(descriptor); } }); return obj_1; } else { return undefined; } }; return Documentation; }()); var babelParserOptions = { sourceType: 'module', strictMode: false, tokens: true, plugins: [ 'decorators-legacy', 'doExpressions', 'objectRestSpread', 'classProperties', 'classPrivateProperties', 'classPrivateMethods', 'exportDefaultFrom', 'exportNamespaceFrom', 'asyncGenerators', 'functionBind', 'functionSent', 'dynamicImport', 'numericSeparator', 'optionalChaining', 'importMeta', 'bigInt', 'optionalCatchBinding', 'throwExpressions', 'nullishCoalescingOperator', 'importAssertions' ] }; function buildParse(options) { if (options === void 0) { options = {}; } options = __assign(__assign(__assign({}, babelParserOptions), options), { plugins: __spreadArray(__spreadArray([], __read((babelParserOptions.plugins || [])), false), __read((options.plugins || [])), false) }); return { parse: function (src) { return parser$2.parse(src, options); } }; } var cache = new LRUCache({ max: 250 }); function cacher (creator) { var argsKey = []; for (var _i = 1; _i < arguments.length; _i++) { argsKey[_i - 1] = arguments[_i]; } var cacheKey = hash(argsKey.join('')); // source-map cache busting for hot-reloadded modules var output = cache.get(cacheKey); if (output) { return output; } output = creator(); cache.set(cacheKey, output); return output; } /** * true if the left part of the expression of the NodePath is of form `exports.foo = ...;` or * `modules.exports = ...;`. */ function isExportedAssignment(path) { if (bt__namespace.isExpressionStatement(path.node)) { path = path.get('expression'); } if (!bt__namespace.isAssignmentExpression(path.node)) { return false; } var pathLeft = path.get('left'); var isSimpleExports = bt__namespace.isIdentifier(pathLeft.node) && pathLeft.node.name === 'exports'; // check if we are looking at obj.member = value` var isModuleExports = false; if (!isSimpleExports && !bt__namespace.isMemberExpression(pathLeft.node)) { return false; } else if (bt__namespace.isMemberExpression(pathLeft.node)) { var leftObject = pathLeft.get('object'); var leftProp = pathLeft.get('property'); isModuleExports = !Array.isArray(leftProp) && bt__namespace.isIdentifier(leftProp.node) && bt__namespace.isIdentifier(leftObject.node) && // if exports.xx = (leftObject.node.name === 'exports' || // if module.exports = (leftObject.node.name === 'module' && leftProp.node.name === 'exports')); } return isSimpleExports || isModuleExports; } function resolveExportDeclaration(path) { var definitions = new _default(); if (bt__namespace.isExportDefaultDeclaration(path.node)) { var defaultPath = path; definitions.set('default', defaultPath.get('declaration')); } else if (bt__namespace.isExportNamedDeclaration(path.node)) { var declaration = path.get('declaration'); // export const example = {} if (declaration && bt__namespace.isVariableDeclaration(declaration.node)) { declaration.get('declarations').each(function (declarator) { var nodeId = declarator.node.id; if (bt__namespace.isIdentifier(nodeId)) { definitions.set(nodeId.name, declarator); } }); } else if (declaration && bt__namespace.isClassDeclaration(declaration.node)) { var nodeId = declaration.node.id; if (bt__namespace.isIdentifier(nodeId)) { definitions.set(nodeId.name, declaration); } } else { // const example = {} // export { example } getDefinitionsFromPathSpecifiers(path, definitions); } } else if (bt__namespace.isExportDeclaration(path.node)) { getDefinitionsFromPathSpecifiers(path, definitions); } return definitions; } function getDefinitionsFromPathSpecifiers(path, defs) { var specifiersPath = path.get('specifiers'); specifiersPath.each(function (specifier) { if (bt__namespace.isIdentifier(specifier.node.exported)) { defs.set(specifier.node.exported.name, bt__namespace.isExportSpecifier(specifier.node) ? specifier.get('local') : specifier.get('exported')); } }); } function ignore$2() { return false; } function resolveIdentifier(ast, path) { if (!bt__namespace.isIdentifier(path.node)) { return path; } var varName = path.node.name; var comp = null; recast.visit(ast.program, { // to look only at the root we ignore all traversing visitFunctionDeclaration: ignore$2, visitFunctionExpression: ignore$2, visitClassExpression: ignore$2, visitIfStatement: ignore$2, visitWithStatement: ignore$2, visitSwitchStatement: ignore$2, visitWhileStatement: ignore$2, visitDoWhileStatement: ignore$2, visitForStatement: ignore$2, visitForInStatement: ignore$2, visitVariableDeclaration: function (variablePath) { if (variablePath.node.type !== 'VariableDeclaration') { return false; } var firstDeclaration = variablePath.node.declarations[0]; var varID = firstDeclaration.type === 'VariableDeclarator' ? firstDeclaration.id : firstDeclaration; if (!varID || varID.type !== 'Identifier' || varID.name !== varName) { return false; } comp = variablePath.get('declarations', 0).get('init'); return false; }, visitClassDeclaration: function (classPath) { var classID = classPath.node.id; if (!classID || classID.type !== 'Identifier' || classID.name !== varName) { return false; } comp = classPath; return false; } }); return comp; } /** * * @param ast * @param varNameFilter */ function resolveRequired(ast, varNameFilter) { var varToFilePath = {}; recast.visit(ast.program, { visitImportDeclaration: function (astPath) { var specifiers = astPath.get('specifiers'); // if `import 'module'` without variable name cannot be a mixin specifiers.each(function (sp) { var nodeSpecifier = sp.node; if (bt__namespace.isImportDefaultSpecifier(nodeSpecifier) || bt__namespace.isImportSpecifier(nodeSpecifier)) { var localVariableName = nodeSpecifier.local.name; var exportName = bt__namespace.isImportDefaultSpecifier(nodeSpecifier) ? 'default' : bt__namespace.isIdentifier(nodeSpecifier.imported) ? nodeSpecifier.imported.name : 'default'; if (!varNameFilter || varNameFilter.indexOf(localVariableName) > -1) { var nodeSource = astPath.get('source').node; if (bt__namespace.isStringLiteral(nodeSource)) { var filePath = [nodeSource.value]; varToFilePath[localVariableName] = { filePath: filePath, exportName: exportName }; } } } }); return false; }, visitVariableDeclaration: function (astPath) { // only look at variable declarations if (!bt__namespace.isVariableDeclaration(astPath.node)) { return false; } astPath.node.declarations.forEach(function (nodeDeclaration) { var sourceNode; var source = ''; var _a = nodeDeclaration.init && bt__namespace.isMemberExpression(nodeDeclaration.init) ? { init: nodeDeclaration.init.object, exportName: bt__namespace.isIdentifier(nodeDeclaration.init.property) ? nodeDeclaration.init.property.name : 'default' } : { init: nodeDeclaration.init, exportName: 'default' }, init = _a.init, exportName = _a.exportName; if (!init) { return; } if (bt__namespace.isCallExpression(init)) { if (!bt__namespace.isIdentifier(init.callee) || init.callee.name !== 'require') { return; } sourceNode = init.arguments[0]; if (!bt__namespace.isStringLiteral(sourceNode)) { return; } source = sourceNode.value; } else { return; } if (bt__namespace.isIdentifier(nodeDeclaration.id)) { var varName = nodeDeclaration.id.name; varToFilePath[varName] = { filePath: [source], exportName: exportName }; } else if (bt__namespace.isObjectPattern(nodeDeclaration.id)) { nodeDeclaration.id.properties.forEach(function (p) { if (bt__namespace.isIdentifier(p.key)) { var varName = p.key.name; varToFilePath[varName] = { filePath: [source], exportName: exportName }; } }); } }); return false; } }); return varToFilePath; } function ignore$1() { return false; } /** * List of all keys that could contain documentation */ var VUE_COMPONENTS_KEYS = ['data', 'props', 'methods', 'computed', 'emits']; function isObjectExpressionComponentDefinition(node) { return ( // export const test = {} node.properties.length === 0 || // export const compo = {data(){ return {cpm:"Button"}} node.properties.some(function (p) { return (bt__namespace.isObjectMethod(p) || bt__namespace.isObjectProperty(p)) && bt__namespace.isIdentifier(p.key) && VUE_COMPONENTS_KEYS.includes(p.key.name); })); } function isComponentDefinition(path) { var node = path.node; return ( // export default {} (always exported even when empty) bt__namespace.isObjectExpression(node) || // export const myComp = {} (exported only when there is a componente definition or if empty) (bt__namespace.isVariableDeclarator(node) && node.init && bt__namespace.isObjectExpression(node.init) && isObjectExpressionComponentDefinition(node.init)) || // export default class MyComp extends VueComp bt__namespace.isClassDeclaration(node) || // export default whatever.extend({}) (bt__namespace.isCallExpression(node) && bt__namespace.isObjectExpression(node.arguments[0])) || // export const myComp = whatever.extend({}) (bt__namespace.isVariableDeclarator(node) && node.init && bt__namespace.isCallExpression(node.init) && bt__namespace.isObjectExpression(node.init.arguments[0])) || false); } function getReturnStatementObject(realDef) { var returnedObjectPath; recast.visit(realDef.get('body'), { visitReturnStatement: function (rPath) { var returnArg = rPath.get('argument'); if (bt__namespace.isObjectExpression(returnArg.node)) { returnedObjectPath = returnArg; } return false; } }); return returnedObjectPath; } function getReturnedObject(realDef) { var node = realDef.node; if (bt__namespace.isArrowFunctionExpression(node)) { if (bt__namespace.isObjectExpression(realDef.get('body').node)) { return realDef.get('body'); } return getReturnStatementObject(realDef); } if (bt__namespace.isFunctionDeclaration(node) || bt__namespace.isFunctionExpression(node)) { return getReturnStatementObject(realDef); } return undefined; } /** * Given an AST, this function tries to find the exported component definitions. * * If a definition is part of the following statements, it is considered to be * exported: * * modules.exports = Definition; * exports.foo = Definition; * export default Definition; * export var Definition = ...; */ function resolveExportedComponent(ast) { var components = new _default(); var ievPureExports = {}; var nonComponentsIdentifiers = []; function setComponent(exportName, definition) { if (definition && !components.get(exportName)) { components.set(exportName, normalizeComponentPath(definition)); } } // function run for every non "assignment" export declaration // in extenso export default or export myvar function exportDeclaration(path) { var _a; var definitions = resolveExportDeclaration(path); // if it is a pure export { compo } from "./compo" load the source here var sourcePath = (_a = path.get('source').value) === null || _a === void 0 ? void 0 : _a.value; definitions.forEach(function (definition, name) { if (sourcePath) { ievPureExports[name] = { exportName: definition.value.name, filePath: [sourcePath] }; } else { // if we look at a TS "as" expression the variable is "contained" // in its expression member. In this case, resolve the expression member if (bt__namespace.isTSAsExpression(definition.node)) { definition = definition.get('expression'); } var realDef = resolveIdentifier(ast, definition); if (realDef) { if (isComponentDefinition(realDef)) { setComponent(name, realDef); } else { var returnedObject = getReturnedObject(realDef); if (returnedObject && isObjectExpressionComponentDefinition(returnedObject.node)) { setComponent(name, returnedObject); } } } else { nonComponentsIdentifiers.push(definition.value.name); } } }); return false; } recast.visit(ast.program, { // for perf resons, // look only at the root, // ignore all traversing except for if visitFunctionDeclaration: ignore$1, visitFunctionExpression: ignore$1, visitClassDeclaration: ignore$1, visitClassExpression: ignore$1, visitWithStatement: ignore$1, visitSwitchStatement: ignore$1, visitWhileStatement: ignore$1, visitDoWhileStatement: ignore$1, visitForStatement: ignore$1, visitForInStatement: ignore$1, visitDeclareExportDeclaration: exportDeclaration, visitExportNamedDeclaration: exportDeclaration, visitExportDefaultDeclaration: exportDeclaration, visitAssignmentExpression: function (path) { // function run on every assignments (with an =) // Ignore anything that is not `exports.X = ...;` or // `module.exports = ...;` if (!isExportedAssignment(path)) { return false; } // Resolve the value of the right hand side. It should resolve to a call // expression, something like Vue.extend({}) var pathRight = path.get('right'); var pathLeft = path.get('left'); var realComp = resolveIdentifier(ast, pathRight); var name = bt__namespace.isMemberExpression(pathLeft.node) && bt__namespace.isIdentifier(pathLeft.node.property) && pathLeft.node.property.name !== 'exports' ? pathLeft.node.property.name : 'default'; if (realComp) { if (isComponentDefinition(realComp)) { setComponent(name, realComp); } else { var returnedObject = getReturnedObject(realComp); if (returnedObject && isObjectExpressionComponentDefinition(returnedObject.node)) { setComponent(name, returnedObject); } } } else { nonComponentsIdentifiers.push(name); } return false; } }); var requiredValues = Object.assign(ievPureExports, resolveRequired(ast, nonComponentsIdentifiers)); return [components, requiredValues]; } function normalizeComponentPath(path) { if (bt__namespace.isVariableDeclarator(path.node)) { path = path.get('init'); } if (bt__namespace.isObjectExpression(path.node)) { return path; } else if (bt__namespace.isCallExpression(path.node)) { return path.get('arguments', 0); } return path; } function resolveImmediatelyExported (ast, variableFilter) { var variables = {}; var importedVariablePaths = {}; var exportAllFiles = []; // get imported variable names and filepath recast.visit(ast.program, { visitImportDeclaration: function (astPath) { if (!astPath.node.source) { return false; } var filePath = astPath.node.source.value; if (typeof filePath !== 'string') { return false; } var specifiers = astPath.get('specifiers'); specifiers.each(function (s) { var varName = s.node.local.name; var exportName = bt__namespace.isImportSpecifier(s.node) && bt__namespace.isIdentifier(s.node.imported) ? s.node.imported.name : 'default'; importedVariablePaths[varName] = { filePath: [filePath], exportName: exportName }; }); return false; } }); recast.visit(ast.program, { visitExportNamedDeclaration: function (astPath) { var specifiers = astPath.get('specifiers'); if (astPath.node.source) { var filePath_1 = astPath.node.source.value; if (typeof filePath_1 !== 'string') { return false; } specifiers.each(function (s) { if (bt__namespace.isIdentifier(s.node.exported)) { var varName = s.node.exported.name; var exportName = s.node.local ? s.node.local.name : varName; if (variableFilter.indexOf(varName) > -1) { variables[varName] = { filePath: [filePath_1], exportName: exportName }; } } }); } else { specifiers.each(function (s) { if (bt__namespace.isIdentifier(s.node.exported)) { var varName = s.node.exported.name; var middleName = s.node.local.name; var importedVar = importedVariablePaths[middleName]; if (importedVar && variableFilter.indexOf(varName) > -1) { variables[varName] = importedVar; } } }); } return false; }, visitExportDefaultDeclaration: function (astPath) { if (variableFilter.indexOf('default') > -1) { var middleNameDeclaration = astPath.node.declaration; if (middleNameDeclaration.type === 'Identifier') { var middleName = middleNameDeclaration.name; var importedVar = importedVariablePaths[middleName]; if (importedVar) { variables.default = importedVar; } } } return false; }, visitExportAllDeclaration: function (astPath) { var newFilePath = astPath.get('source').node.value; exportAllFiles.push(newFilePath); return false; } }); if (exportAllFiles.length) { variableFilter .filter(function (v) { return !variables[v]; }) .forEach(function (exportName) { variables[exportName] = { filePath: exportAllFiles, exportName: exportName }; }); } return { variables: variables, exportAll: exportAllFiles.length > 0 }; } /** * Recursively resolves specified variables to their actual files * Useful when using intermediary files like this * * ```js * export mixin from "path/to/mixin" * ``` * * @param pathResolver function to resolve relative to absolute path * @param varToFilePath set of variables to be resolved (will be mutated into the final mapping) */ function recursiveResolveIEV(pathResolver, varToFilePath, validExtends) { return __awaiter(this, void 0, void 0, function () { var hashes; return __generator(this, function (_a) { switch (_a.label) { case 0: hashes = new Set(); _a.label = 1; case 1: // in this case I need to resolve IEV in sequence in case they are defined multiple times // eslint-disable-next-line no-await-in-loop return [4 /*yield*/, resolveIEV(pathResolver, varToFilePath, validExtends) // we iterate until there is no change in the set of variables or there is a loop ]; case 2: // in this case I need to resolve IEV in sequence in case they are defined multiple times // eslint-disable-next-line no-await-in-loop _a.sent(); _a.label = 3; case 3: if (!hashes.has(hash(varToFilePath)) && hashes.add(hash(varToFilePath))) return [3 /*break*/, 1]; _a.label = 4; case 4: return [2 /*return*/]; } }); }); } /** * Resolves specified variables to their actual files * Useful when using intermediary files like this * * ```js * export mixin from "path/to/mixin" * export * from "path/to/another/mixin" * ``` * * @param pathResolver function to resolve relative to absolute path * @param varToFilePath set of variables to be resolved (will be mutated into the final mapping) */ function resolveIEV(pathResolver, varToFilePath, validExtends) { return __awaiter(this, void 0, void 0, function () { var filePathToVars; var _this = this; return __generator(this, function (_a) { switch (_a.label) { case 0: filePathToVars = new _default(); Object.keys(varToFilePath).forEach(function (k) { // the only way a variable can be exported by multiple files // is if one of those files is exported as follows // export * from 'path/to/file' var exportedVariable = varToFilePath[k]; exportedVariable.filePath.forEach(function (filePath, i) { var exportToLocalMap = filePathToVars.get(filePath) || new _default(); exportToLocalMap.set(k, exportedVariable.exportName); filePathToVars.set(filePath, exportToLocalMap); }); }); // then roll though this map and replace varToFilePath elements with their final destinations // { // nameOfVariable: { filePath:['filesWhereToFindIt'], exportedName:'nameUsedInExportThatCanBeUsedForFiltering' } // } return [4 /*yield*/, Promise.all(filePathToVars.entries().map(function (_a) { var _b = __read(_a, 2), filePath = _b[0], exportToLocal = _b[1]; return __awaiter(_this, void 0, void 0, function () { var exportedVariableNames_1, fullFilePath_1, source_1, astRemote, returnedVariables_1; return __generator(this, function (_c) { switch (_c.label) { case 0: if (!(filePath && exportToLocal)) return [3 /*break*/, 4]; exportedVariableNames_1 = []; exportToLocal.forEach(function (exportedName) { if (exportedName) { exportedVariableNames_1.push(exportedName); } }); _c.label = 1; case 1: _c.trys.push([1, 3, , 4]); fullFilePath_1 = pathResolver(filePath); if (!fullFilePath_1 || !validExtends(fullFilePath_1)) { // if the file is not in scope of the analysis, skip it // if no variable export corresponds to this local name, we delete it at the very end return [2 /*return*/]; } return [4 /*yield*/, fs.promises.readFile(fullFilePath_1, { encoding: 'utf-8' })]; case 2: source_1 = _c.sent(); astRemote = cacher(function () { return recast.parse(source_1, { parser: buildParse() }); }, source_1); returnedVariables_1 = resolveImmediatelyExported(astRemote, exportedVariableNames_1).variables; if (Object.keys(returnedVariables_1).length) { exportToLocal.forEach(function (exported, local) { var aliasedVariable = returnedVariables_1[exported]; if (aliasedVariable) { aliasedVariable.filePath = aliasedVariable.filePath .map(function (p) { return pathResolver(p, path__namespace.dirname(fullFilePath_1)); }) .filter(function (a) { return a; }); varToFilePath[local] = aliasedVariable; } }); } return [3 /*break*/, 4]; case 3: _c.sent(); return [3 /*break*/, 4]; case 4: return [2 /*return*/]; } }); }); }))]; case 1: // then roll though this map and replace varToFilePath elements with their final destinations // { // nameOfVariable: { filePath:['filesWhereToFindIt'], exportedName:'nameUsedInExportThatCanBeUsedForFiltering' } // } _a.sent(); return [2 /*return*/]; } }); }); } function resolveAliases(filePath, aliases, refDirName) { var e_1, _a, e_2, _b; if (refDirName === void 0) { refDirName = ''; } var aliasKeys = Object.keys(aliases); var aliasResolved = null; if (!aliasKeys.length) { return filePath; } try { for (var aliasKeys_1 = __values(aliasKeys), aliasKeys_1_1 = aliasKeys_1.next(); !aliasKeys_1_1.done; aliasKeys_1_1 = aliasKeys_1.next()) { var aliasKey = aliasKeys_1_1.value; var aliasValueWithSlash = aliasKey + '/'; var aliasMatch = filePath.substring(0, aliasValueWithSlash.length) === aliasValueWithSlash; var aliasValue = aliases[aliasKey]; if (!aliasMatch) { continue; } if (!Array.isArray(aliasValue)) { aliasResolved = path__namespace.join(aliasValue, filePath.substring(aliasKey.length + 1)); continue; } try { for (var aliasValue_1 = (e_2 = void 0, __values(aliasValue)), aliasValue_1_1 = aliasValue_1.next(); !aliasValue_1_1.done; aliasValue_1_1 = aliasValue_1.next()) { var alias = aliasValue_1_1.value; var absolutePath = path__namespace.resolve(refDirName, alias, filePath.substring(aliasKey.length + 1)); if (fs__namespace.existsSync(absolutePath)) { aliasResolved = absolutePath; break; } } } catch (e_2_1) { e_2 = { error: e_2_1 }; } finally { try { if (aliasValue_1_1 && !aliasValue_1_1.done && (_b = aliasValue_1.return)) _b.call(aliasValue_1); } finally { if (e_2) throw e_2.error; } } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (aliasKeys_1_1 && !aliasKeys_1_1.done && (_a = aliasKeys_1.return)) _a.call(aliasKeys_1); } finally { if (e_1) throw e_1.error; } } return aliasResolved === null ? filePath : aliasResolved; } var missingFilesCache = {}; // fix issues with babel bundles in cjs var esmResolve = ('default' in esmResolveNative ? esmResolveNative.default : esmResolveNative); var SUFFIXES = ['', '.js', '.ts', '.vue', '.jsx', '.tsx']; function resolvePathFrom(path$1, from) { var e_1, _a; var _b; var finalPath = null; try { for (var SUFFIXES_1 = __values(SUFFIXES), SUFFIXES_1_1 = SUFFIXES_1.next(); !SUFFIXES_1_1.done; SUFFIXES_1_1 = SUFFIXES_1.next()) { var s = SUFFIXES_1_1.value; if (!finalPath) { try { finalPath = require.resolve("".concat(path$1).concat(s), { paths: from }); } catch (e) { // eat the error } } if (!finalPath) { try { finalPath = require.resolve(path.join(path$1, "index".concat(s)), { paths: from }); } catch (e) { // eat the error } } if (!finalPath) { for (var i = 0; i < from.length; i++) { try { finalPath = require.resolve(path.join(from[i], "".concat(path$1).concat(s))); if (finalPath.length) { break; } } catch (e) { // eat the error } } } if (finalPath) { break; } } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (SUFFIXES_1_1 && !SUFFIXES_1_1.done && (_a = SUFFIXES_1.return)) _a.call(SUFFIXES_1); } finally { if (e_1) throw e_1.error; } } try { var packagePath = require.resolve(path.join(path$1, 'package.json'), { paths: from }); // eslint-disable-next-line @typescript-eslint/no-var-requires var pkg = require(packagePath); // if it is an es6 module use the module instead of commonjs finalPath = require.resolve(path.join(path$1, pkg.module || pkg.main)); } catch (e) { // if the error is about the package.json not being found, // try to resolve the path naturally if (e.code === 'ERR_PACKAGE_PATH_NOT_EXPORTED') { try { finalPath = (_b = esmResolve(from[0])(path$1)) !== null && _b !== void 0 ? _b : null; } catch (e) { // dismiss the error } } // else dismiss the error } if (!finalPath) { if (!missingFilesCache[path$1]) { // eslint-disable-next-line no-console console.warn("Neither '".concat(path$1, ".vue' nor '").concat(path$1, ".js(x)' or '").concat(path$1, "/index.js(x)' or '").concat(path$1, "/index.ts(x)' could be found in '").concat(from, "'")); missingFilesCache[path$1] = true; } } return finalPath; } function makePathResolver(refDirName, aliases, modules) { /** * Emulate the module import logic as much as necessary to resolve a module containing the * interface or type. * * @param base Path to the file that is importing the module * @param module Relative path to the module * @returns The absolute path to the file that contains the module to be imported */ return function (filePath, originalDirNameOverride) { return resolvePathFrom(resolveAliases(filePath, aliases || {}, refDirName), __spreadArray([ originalDirNameOverride || refDirName ], __read((modules || [])), false)); }; } /** * Document all components in varToFilePath in documentation * Instead of giving it only one component file, here we give it a whole set of variable -> file * * @param documentation if omitted (undefined), it will return all docs in an array * @param varToFilePath variable of object to document * @param originObject to build the origin flag * @param opt parsing options */ function documentRequiredComponents(parseFile, documentation, varToFilePath, originObject, opt) { return __awaiter(this, void 0, void 0, function () { var originalDirName, pathResolver, files, _loop_1, _a, _b, varName, docsArray; var e_1, _c; var _this = this; return __generator(this, function (_d) { switch (_d.label) { case 0: originalDirName = path__namespace.dirname(opt.filePath); pathResolver = makePathResolver(originalDirName, opt.alias, opt.modules);