"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _lodash = _interopRequireDefault(require("lodash")); var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const rootNamer = (desiredRoots, currentIndex) => { let name; let idx = currentIndex; const incremented = desiredRoots.length <= 1; if (incremented) { const base = desiredRoots[0]; const suffix = idx++; name = `${base}${suffix}`; } else { name = desiredRoots.shift(); } return [name, incremented, () => { return rootNamer(desiredRoots, idx); }]; }; var _default = (0, _iterateJsdoc.default)(({ jsdoc, utils, context }) => { const preferredTagName = utils.getPreferredTagName({ tagName: 'param' }); if (!preferredTagName) { return; } const jsdocParameterNames = utils.getJsdocTagsDeep(preferredTagName); const shallowJsdocParameterNames = jsdocParameterNames.filter(tag => { return !tag.name.includes('.'); }).map((tag, idx) => { return { ...tag, idx }; }); if (utils.avoidDocs()) { return; } // Param type is specified by type in @type if (utils.hasTag('type')) { return; } const { autoIncrementBase = 0, checkRestProperty = false, checkDestructured = true, checkDestructuredRoots = true, checkTypesPattern = '/^(?:[oO]bject|[aA]rray|PlainObject|Generic(?:Object|Array))$/', enableFixer = true, enableRootFixer = true, enableRestElementFixer = true, unnamedRootBase = ['root'], useDefaultObjectProperties = false } = context.options[0] || {}; const checkTypesRegex = utils.getRegexFromString(checkTypesPattern); const missingTags = []; const functionParameterNames = utils.getFunctionParameterNames(useDefaultObjectProperties); const flattenedRoots = utils.flattenRoots(functionParameterNames).names; const paramIndex = {}; const hasParamIndex = cur => { return _lodash.default.has(paramIndex, utils.dropPathSegmentQuotes(String(cur))); }; const getParamIndex = cur => { return paramIndex[utils.dropPathSegmentQuotes(String(cur))]; }; const setParamIndex = (cur, idx) => { paramIndex[utils.dropPathSegmentQuotes(String(cur))] = idx; }; flattenedRoots.forEach((cur, idx) => { setParamIndex(cur, idx); }); const findExpectedIndex = (jsdocTags, indexAtFunctionParams) => { const remainingRoots = functionParameterNames.slice(indexAtFunctionParams || 0); const foundIndex = jsdocTags.findIndex(({ name, newAdd }) => { return !newAdd && remainingRoots.some(remainingRoot => { if (Array.isArray(remainingRoot)) { return remainingRoot[1].names.includes(name); } if (typeof remainingRoot === 'object') { return name === remainingRoot.name; } return name === remainingRoot; }); }); const tags = foundIndex > -1 ? jsdocTags.slice(0, foundIndex) : jsdocTags.filter(({ tag }) => { return tag === preferredTagName; }); let tagLineCount = 0; tags.forEach(({ source }) => { source.forEach(({ tokens: { end } }) => { if (!end) { tagLineCount++; } }); }); return tagLineCount; }; let [nextRootName, incremented, namer] = rootNamer([...unnamedRootBase], autoIncrementBase); functionParameterNames.forEach((functionParameterName, functionParameterIdx) => { let inc; if (Array.isArray(functionParameterName)) { const matchedJsdoc = shallowJsdocParameterNames[functionParameterIdx] || jsdocParameterNames[functionParameterIdx]; let rootName; if (functionParameterName[0]) { rootName = functionParameterName[0]; } else if (matchedJsdoc && matchedJsdoc.name) { rootName = matchedJsdoc.name; if (matchedJsdoc.type && matchedJsdoc.type.search(checkTypesRegex) === -1) { return; } } else { rootName = nextRootName; inc = incremented; [nextRootName, incremented, namer] = namer(); } const { hasRestElement, hasPropertyRest, rests, names } = functionParameterName[1]; const notCheckingNames = []; if (!enableRestElementFixer && hasRestElement) { return; } if (!checkDestructuredRoots) { return; } names.forEach((paramName, idx) => { // Add root if the root name is not in the docs (and is not already // in the tags to be fixed) if (!jsdocParameterNames.find(({ name }) => { return name === rootName; }) && !missingTags.find(({ functionParameterName: fpn }) => { return fpn === rootName; })) { const emptyParamIdx = jsdocParameterNames.findIndex(({ name }) => { return !name; }); if (emptyParamIdx > -1) { missingTags.push({ functionParameterIdx: emptyParamIdx, functionParameterName: rootName, inc, remove: true }); } else { missingTags.push({ functionParameterIdx: hasParamIndex(rootName) ? getParamIndex(rootName) : getParamIndex(paramName), functionParameterName: rootName, inc }); } } if (!checkDestructured) { return; } if (!checkRestProperty && rests[idx]) { return; } const fullParamName = `${rootName}.${paramName}`; const notCheckingName = jsdocParameterNames.find(({ name, type: paramType }) => { return utils.comparePaths(name)(fullParamName) && paramType.search(checkTypesRegex) === -1 && paramType !== ''; }); if (notCheckingName !== undefined) { notCheckingNames.push(notCheckingName.name); } if (notCheckingNames.find(name => { return fullParamName.startsWith(name); })) { return; } if (jsdocParameterNames && !jsdocParameterNames.find(({ name }) => { return utils.comparePaths(name)(fullParamName); })) { missingTags.push({ functionParameterIdx: getParamIndex(functionParameterName[0] ? fullParamName : paramName), functionParameterName: fullParamName, inc, type: hasRestElement && !hasPropertyRest ? '{...any}' : undefined }); } }); return; } let funcParamName; let type; if (typeof functionParameterName === 'object') { if (!enableRestElementFixer && functionParameterName.restElement) { return; } funcParamName = functionParameterName.name; type = '{...any}'; } else { funcParamName = functionParameterName; } if (jsdocParameterNames && !jsdocParameterNames.find(({ name }) => { return name === funcParamName; })) { missingTags.push({ functionParameterIdx: getParamIndex(funcParamName), functionParameterName: funcParamName, inc, type }); } }); const fix = ({ functionParameterIdx, functionParameterName, remove, inc, type }) => { if (inc && !enableRootFixer) { return; } const createTokens = (tagIndex, sourceIndex, spliceCount) => { // console.log(sourceIndex, tagIndex, jsdoc.tags, jsdoc.source); const tokens = { number: sourceIndex + 1, tokens: { delimiter: '*', description: '', end: '', lineEnd: '', name: functionParameterName, newAdd: true, postDelimiter: ' ', postName: '', postTag: ' ', postType: type ? ' ' : '', start: jsdoc.source[sourceIndex].tokens.start, tag: `@${preferredTagName}`, type: type !== null && type !== void 0 ? type : '' } }; jsdoc.tags.splice(tagIndex, spliceCount, { name: functionParameterName, newAdd: true, source: [tokens], tag: preferredTagName, type: type !== null && type !== void 0 ? type : '' }); const firstNumber = jsdoc.source[0].number; jsdoc.source.splice(sourceIndex, spliceCount, tokens); jsdoc.source.slice(sourceIndex).forEach((src, idx) => { src.number = firstNumber + sourceIndex + idx; }); }; const offset = jsdoc.source.findIndex(({ tokens: { tag, end } }) => { return tag || end; }); if (remove) { createTokens(functionParameterIdx, offset + functionParameterIdx, 1); } else { const expectedIdx = findExpectedIndex(jsdoc.tags, functionParameterIdx); createTokens(expectedIdx, offset + expectedIdx, 0); } }; const fixer = () => { missingTags.forEach(missingTag => { fix(missingTag); }); }; if (missingTags.length && jsdoc.source.length === 1) { utils.makeMultiline(); } missingTags.forEach(({ functionParameterName }) => { utils.reportJSDoc(`Missing JSDoc @${preferredTagName} "${functionParameterName}" declaration.`, null, enableFixer ? fixer : null); }); }, { contextDefaults: true, meta: { docs: { description: 'Requires that all function parameters are documented.', url: 'https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-require-param' }, fixable: 'code', schema: [{ additionalProperties: false, properties: { autoIncrementBase: { default: 0, type: 'integer' }, checkConstructors: { default: true, type: 'boolean' }, checkDestructured: { default: true, type: 'boolean' }, checkDestructuredRoots: { default: true, type: 'boolean' }, checkGetters: { default: false, type: 'boolean' }, checkRestProperty: { default: false, type: 'boolean' }, checkSetters: { default: false, type: 'boolean' }, checkTypesPattern: { type: 'string' }, contexts: { items: { anyOf: [{ type: 'string' }, { additionalProperties: false, properties: { comment: { type: 'string' }, context: { type: 'string' } }, type: 'object' }] }, type: 'array' }, enableFixer: { type: 'boolean' }, enableRestElementFixer: { type: 'boolean' }, enableRootFixer: { type: 'boolean' }, exemptedBy: { items: { type: 'string' }, type: 'array' }, unnamedRootBase: { items: { type: 'string' }, type: 'array' }, useDefaultObjectProperties: { type: 'boolean' } }, type: 'object' }], type: 'suggestion' } }); exports.default = _default; module.exports = exports.default; //# sourceMappingURL=requireParam.js.map