123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299 |
- "use strict";
- Object.defineProperty(exports, "__esModule", {
- value: true
- });
- exports.default = void 0;
- var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc.js"));
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
- /**
- * @param {string} targetTagName
- * @param {boolean} allowExtraTrailingParamDocs
- * @param {boolean} checkDestructured
- * @param {boolean} checkRestProperty
- * @param {RegExp} checkTypesRegex
- * @param {boolean} disableExtraPropertyReporting
- * @param {boolean} enableFixer
- * @param {import('../jsdocUtils.js').ParamNameInfo[]} functionParameterNames
- * @param {import('comment-parser').Block} jsdoc
- * @param {import('../iterateJsdoc.js').Utils} utils
- * @param {import('../iterateJsdoc.js').Report} report
- * @returns {boolean}
- */
- const validateParameterNames = (targetTagName, allowExtraTrailingParamDocs, checkDestructured, checkRestProperty, checkTypesRegex, disableExtraPropertyReporting, enableFixer, functionParameterNames, jsdoc, utils, report) => {
- const paramTags = Object.entries(jsdoc.tags).filter(([, tag]) => {
- return tag.tag === targetTagName;
- });
- const paramTagsNonNested = paramTags.filter(([, tag]) => {
- return !tag.name.includes('.');
- });
- let dotted = 0;
- let thisOffset = 0;
- // eslint-disable-next-line complexity
- return paramTags.some(([, tag], index) => {
- /** @type {import('../iterateJsdoc.js').Integer} */
- let tagsIndex;
- const dupeTagInfo = paramTags.find(([tgsIndex, tg], idx) => {
- tagsIndex = Number(tgsIndex);
- return tg.name === tag.name && idx !== index;
- });
- if (dupeTagInfo) {
- utils.reportJSDoc(`Duplicate @${targetTagName} "${tag.name}"`, dupeTagInfo[1], enableFixer ? () => {
- utils.removeTag(tagsIndex);
- } : null);
- return true;
- }
- if (tag.name.includes('.')) {
- dotted++;
- return false;
- }
- let functionParameterName = functionParameterNames[index - dotted + thisOffset];
- if (functionParameterName === 'this' && tag.name.trim() !== 'this') {
- ++thisOffset;
- functionParameterName = functionParameterNames[index - dotted + thisOffset];
- }
- if (!functionParameterName) {
- if (allowExtraTrailingParamDocs) {
- return false;
- }
- report(`@${targetTagName} "${tag.name}" does not match an existing function parameter.`, null, tag);
- return true;
- }
- if (Array.isArray(functionParameterName)) {
- if (!checkDestructured) {
- return false;
- }
- if (tag.type && tag.type.search(checkTypesRegex) === -1) {
- return false;
- }
- const [parameterName, {
- names: properties,
- hasPropertyRest,
- rests,
- annotationParamName
- }] =
- /**
- * @type {[string | undefined, import('../jsdocUtils.js').FlattendRootInfo & {
- * annotationParamName?: string | undefined;
- }]} */
- functionParameterName;
- if (annotationParamName !== undefined) {
- const name = tag.name.trim();
- if (name !== annotationParamName) {
- report(`@${targetTagName} "${name}" does not match parameter name "${annotationParamName}"`, null, tag);
- }
- }
- const tagName = parameterName === undefined ? tag.name.trim() : parameterName;
- const expectedNames = properties.map(name => {
- return `${tagName}.${name}`;
- });
- const actualNames = paramTags.map(([, paramTag]) => {
- return paramTag.name.trim();
- });
- const actualTypes = paramTags.map(([, paramTag]) => {
- return paramTag.type;
- });
- const missingProperties = [];
- /** @type {string[]} */
- const notCheckingNames = [];
- for (const [idx, name] of expectedNames.entries()) {
- if (notCheckingNames.some(notCheckingName => {
- return name.startsWith(notCheckingName);
- })) {
- continue;
- }
- const actualNameIdx = actualNames.findIndex(actualName => {
- return utils.comparePaths(name)(actualName);
- });
- if (actualNameIdx === -1) {
- if (!checkRestProperty && rests[idx]) {
- continue;
- }
- const missingIndex = actualNames.findIndex(actualName => {
- return utils.pathDoesNotBeginWith(name, actualName);
- });
- const line = tag.source[0].number - 1 + (missingIndex > -1 ? missingIndex : actualNames.length);
- missingProperties.push({
- name,
- tagPlacement: {
- line: line === 0 ? 1 : line
- }
- });
- } else if (actualTypes[actualNameIdx].search(checkTypesRegex) === -1 && actualTypes[actualNameIdx] !== '') {
- notCheckingNames.push(name);
- }
- }
- const hasMissing = missingProperties.length;
- if (hasMissing) {
- for (const {
- tagPlacement,
- name: missingProperty
- } of missingProperties) {
- report(`Missing @${targetTagName} "${missingProperty}"`, null, tagPlacement);
- }
- }
- if (!hasPropertyRest || checkRestProperty) {
- /** @type {[string, import('comment-parser').Spec][]} */
- const extraProperties = [];
- for (const [idx, name] of actualNames.entries()) {
- const match = name.startsWith(tag.name.trim() + '.');
- if (match && !expectedNames.some(utils.comparePaths(name)) && !utils.comparePaths(name)(tag.name) && (!disableExtraPropertyReporting || properties.some(prop => {
- return prop.split('.').length >= name.split('.').length - 1;
- }))) {
- extraProperties.push([name, paramTags[idx][1]]);
- }
- }
- if (extraProperties.length) {
- for (const [extraProperty, tg] of extraProperties) {
- report(`@${targetTagName} "${extraProperty}" does not exist on ${tag.name}`, null, tg);
- }
- return true;
- }
- }
- return hasMissing;
- }
- let funcParamName;
- if (typeof functionParameterName === 'object') {
- const {
- name
- } = functionParameterName;
- funcParamName = name;
- } else {
- funcParamName = functionParameterName;
- }
- if (funcParamName !== tag.name.trim()) {
- // Todo: Improve for array or object child items
- const actualNames = paramTagsNonNested.map(([, {
- name
- }]) => {
- return name.trim();
- });
- const expectedNames = functionParameterNames.map((item, idx) => {
- var _item$;
- if (
- /**
- * @type {[string|undefined, (import('../jsdocUtils.js').FlattendRootInfo & {
- * annotationParamName?: string,
- })]} */
- item !== null && item !== void 0 && (_item$ = item[1]) !== null && _item$ !== void 0 && _item$.names) {
- return actualNames[idx];
- }
- return item;
- }).filter(item => {
- return item !== 'this';
- }).join(', ');
- report(`Expected @${targetTagName} names to be "${expectedNames}". Got "${actualNames.join(', ')}".`, null, tag);
- return true;
- }
- return false;
- });
- };
- /**
- * @param {string} targetTagName
- * @param {boolean} _allowExtraTrailingParamDocs
- * @param {{
- * name: string,
- * idx: import('../iterateJsdoc.js').Integer
- * }[]} jsdocParameterNames
- * @param {import('comment-parser').Block} jsdoc
- * @param {Function} report
- * @returns {boolean}
- */
- const validateParameterNamesDeep = (targetTagName, _allowExtraTrailingParamDocs, jsdocParameterNames, jsdoc, report) => {
- /** @type {string} */
- let lastRealParameter;
- return jsdocParameterNames.some(({
- name: jsdocParameterName,
- idx
- }) => {
- const isPropertyPath = jsdocParameterName.includes('.');
- if (isPropertyPath) {
- if (!lastRealParameter) {
- report(`@${targetTagName} path declaration ("${jsdocParameterName}") appears before any real parameter.`, null, jsdoc.tags[idx]);
- return true;
- }
- let pathRootNodeName = jsdocParameterName.slice(0, jsdocParameterName.indexOf('.'));
- if (pathRootNodeName.endsWith('[]')) {
- pathRootNodeName = pathRootNodeName.slice(0, -2);
- }
- if (pathRootNodeName !== lastRealParameter) {
- report(`@${targetTagName} path declaration ("${jsdocParameterName}") root node name ("${pathRootNodeName}") ` + `does not match previous real parameter name ("${lastRealParameter}").`, null, jsdoc.tags[idx]);
- return true;
- }
- } else {
- lastRealParameter = jsdocParameterName;
- }
- return false;
- });
- };
- var _default = exports.default = (0, _iterateJsdoc.default)(({
- context,
- jsdoc,
- report,
- utils
- }) => {
- const {
- allowExtraTrailingParamDocs,
- checkDestructured = true,
- checkRestProperty = false,
- checkTypesPattern = '/^(?:[oO]bject|[aA]rray|PlainObject|Generic(?:Object|Array))$/',
- enableFixer = false,
- useDefaultObjectProperties = false,
- disableExtraPropertyReporting = false
- } = context.options[0] || {};
- const checkTypesRegex = utils.getRegexFromString(checkTypesPattern);
- const jsdocParameterNamesDeep = utils.getJsdocTagsDeep('param');
- if (!jsdocParameterNamesDeep || !jsdocParameterNamesDeep.length) {
- return;
- }
- const functionParameterNames = utils.getFunctionParameterNames(useDefaultObjectProperties);
- const targetTagName = /** @type {string} */utils.getPreferredTagName({
- tagName: 'param'
- });
- const isError = validateParameterNames(targetTagName, allowExtraTrailingParamDocs, checkDestructured, checkRestProperty, checkTypesRegex, disableExtraPropertyReporting, enableFixer, functionParameterNames, jsdoc, utils, report);
- if (isError || !checkDestructured) {
- return;
- }
- validateParameterNamesDeep(targetTagName, allowExtraTrailingParamDocs, jsdocParameterNamesDeep, jsdoc, report);
- }, {
- meta: {
- docs: {
- description: 'Ensures that parameter names in JSDoc match those in the function declaration.',
- url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/check-param-names.md#repos-sticky-header'
- },
- fixable: 'code',
- schema: [{
- additionalProperties: false,
- properties: {
- allowExtraTrailingParamDocs: {
- type: 'boolean'
- },
- checkDestructured: {
- type: 'boolean'
- },
- checkRestProperty: {
- type: 'boolean'
- },
- checkTypesPattern: {
- type: 'string'
- },
- disableExtraPropertyReporting: {
- type: 'boolean'
- },
- enableFixer: {
- type: 'boolean'
- },
- useDefaultObjectProperties: {
- type: 'boolean'
- }
- },
- type: 'object'
- }],
- type: 'suggestion'
- }
- });
- module.exports = exports.default;
- //# sourceMappingURL=checkParamNames.js.map
|