UNPKG

eslint-plugin-jsdoc

Version:
182 lines (177 loc) 5.24 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc.cjs")); var _jsdoccomment = require("@es-joy/jsdoccomment"); function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; } var _default = exports.default = (0, _iterateJsdoc.default)(({ context, node, report, settings, utils }) => { const { requireSeparateTemplates = false } = context.options[0] || {}; const { mode } = settings; const usedNames = new Set(); const templateTags = utils.getTags('template'); const templateNames = templateTags.flatMap(tag => { return utils.parseClosureTemplateTag(tag); }); if (requireSeparateTemplates) { for (const tag of templateTags) { const { name } = tag; const names = name.split(/,\s*/u); if (names.length > 1) { report(`Missing separate @template for ${names[1]}`, null, tag); } } } /** * @param {import('@typescript-eslint/types').TSESTree.FunctionDeclaration| * import('@typescript-eslint/types').TSESTree.ClassDeclaration| * import('@typescript-eslint/types').TSESTree.TSInterfaceDeclaration| * import('@typescript-eslint/types').TSESTree.TSTypeAliasDeclaration} aliasDeclaration */ const checkTypeParams = aliasDeclaration => { const { params /* c8 ignore next -- Guard */ } = aliasDeclaration.typeParameters ?? { /* c8 ignore next -- Guard */ params: [] }; for (const { name: { name } } of params) { usedNames.add(name); } for (const usedName of usedNames) { if (!templateNames.includes(usedName)) { report(`Missing @template ${usedName}`); } } }; const handleTypes = () => { const nde = /** @type {import('@typescript-eslint/types').TSESTree.Node} */ node; if (!nde) { return; } switch (nde.type) { case 'ClassDeclaration': case 'FunctionDeclaration': case 'TSInterfaceDeclaration': case 'TSTypeAliasDeclaration': checkTypeParams(nde); break; case 'ExportDefaultDeclaration': switch (nde.declaration?.type) { case 'ClassDeclaration': case 'FunctionDeclaration': case 'TSInterfaceDeclaration': checkTypeParams(nde.declaration); break; } break; case 'ExportNamedDeclaration': switch (nde.declaration?.type) { case 'ClassDeclaration': case 'FunctionDeclaration': case 'TSInterfaceDeclaration': case 'TSTypeAliasDeclaration': checkTypeParams(nde.declaration); break; } break; } }; const usedNameToTag = new Map(); /** * @param {import('comment-parser').Spec} potentialTag */ const checkForUsedTypes = potentialTag => { let parsedType; try { parsedType = mode === 'permissive' ? (0, _jsdoccomment.tryParse)(/** @type {string} */potentialTag.type) : (0, _jsdoccomment.parse)(/** @type {string} */potentialTag.type, mode); } catch { return; } (0, _jsdoccomment.traverse)(parsedType, nde => { const { type, value } = /** @type {import('jsdoc-type-pratt-parser').NameResult} */nde; if (type === 'JsdocTypeName' && /^[A-Z]$/u.test(value)) { usedNames.add(value); if (!usedNameToTag.has(value)) { usedNameToTag.set(value, potentialTag); } } }); }; /** * @param {string[]} tagNames */ const checkTagsAndTemplates = tagNames => { for (const tagName of tagNames) { const preferredTagName = /** @type {string} */utils.getPreferredTagName({ tagName }); const matchingTags = utils.getTags(preferredTagName); for (const matchingTag of matchingTags) { checkForUsedTypes(matchingTag); } } // Could check against whitelist/blacklist for (const usedName of usedNames) { if (!templateNames.includes(usedName)) { report(`Missing @template ${usedName}`, null, usedNameToTag.get(usedName)); } } }; const callbackTags = utils.getTags('callback'); const functionTags = utils.getTags('function'); if (callbackTags.length || functionTags.length) { checkTagsAndTemplates(['param', 'returns']); return; } const typedefTags = utils.getTags('typedef'); if (!typedefTags.length || typedefTags.length >= 2) { handleTypes(); return; } const potentialTypedef = typedefTags[0]; checkForUsedTypes(potentialTypedef); checkTagsAndTemplates(['property']); }, { iterateAllJsdocs: true, meta: { docs: { description: 'Requires template tags for each generic type parameter', url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-template.md#repos-sticky-header' }, schema: [{ additionalProperties: false, properties: { requireSeparateTemplates: { type: 'boolean' } }, type: 'object' }], type: 'suggestion' } }); module.exports = exports.default; //# sourceMappingURL=requireTemplate.cjs.map