UNPKG

eslint-plugin-jsdoc

Version:
215 lines (169 loc) 6.31 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _jsdoctypeparser = require("jsdoctypeparser"); var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc")); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } const asExpression = /as\s+/u; var _default = (0, _iterateJsdoc.default)(({ jsdoc, report, utils, context, settings }) => { const { allowEmptyNamepaths = false } = context.options[0] || {}; const { mode } = settings; const tryParseIgnoreError = path => { try { (0, _jsdoctypeparser.parse)(path, { mode }); return true; } catch {// Keep the original error for including the whole type } return false; }; // eslint-disable-next-line complexity jsdoc.tags.forEach(tag => { const validNamepathParsing = function (namepath, tagName) { if (tryParseIgnoreError(namepath)) { return true; } let handled = false; if (tagName) { switch (tagName) { case 'module': { if (!namepath.startsWith('module:')) { handled = tryParseIgnoreError(`module:${namepath}`); } break; } case 'memberof': case 'memberof!': { const endChar = namepath.slice(-1); if (['#', '.', '~'].includes(endChar)) { handled = tryParseIgnoreError(namepath.slice(0, -1)); } break; } case 'borrows': { const startChar = namepath.charAt(); if (['#', '.', '~'].includes(startChar)) { handled = tryParseIgnoreError(namepath.slice(1)); } } } } if (!handled) { report(`Syntax error in namepath: ${namepath}`, null, tag); return false; } return true; }; const validTypeParsing = function (type) { try { (0, _jsdoctypeparser.parse)(type, { mode }); } catch { report(`Syntax error in type: ${type}`, null, tag); return false; } return true; }; if (tag.tag === 'borrows') { const thisNamepath = tag.description.replace(asExpression, '').trim(); if (!asExpression.test(tag.description) || !thisNamepath) { report(`@borrows must have an "as" expression. Found "${tag.description}"`, null, tag); return; } if (validNamepathParsing(thisNamepath, 'borrows')) { const thatNamepath = tag.name; validNamepathParsing(thatNamepath); } return; } const otherModeMaps = ['jsdoc', 'typescript', 'closure', 'permissive'].filter(mde => { return mde !== mode; }).map(mde => { return utils.getTagStructureForMode(mde); }); const tagMightHaveNamePosition = utils.tagMightHaveNamePosition(tag.tag, otherModeMaps); if (tagMightHaveNamePosition !== true && tag.name) { const modeInfo = tagMightHaveNamePosition === false ? '' : ` in "${mode}" mode`; report(`@${tag.tag} should not have a name${modeInfo}.`, null, tag); return; } const mightHaveTypePosition = utils.tagMightHaveTypePosition(tag.tag, otherModeMaps); if (mightHaveTypePosition !== true && tag.type) { const modeInfo = mightHaveTypePosition === false ? '' : ` in "${mode}" mode`; report(`@${tag.tag} should not have a bracketed type${modeInfo}.`, null, tag); return; } // REQUIRED NAME const tagMustHaveNamePosition = utils.tagMustHaveNamePosition(tag.tag, otherModeMaps); // Don't handle `@param` here though it does require name as handled by // `require-param-name` (`@property` would similarly seem to require one, // but is handled by `require-property-name`) if (tagMustHaveNamePosition !== false && !tag.name && !allowEmptyNamepaths && !['param', 'arg', 'argument', 'property', 'prop'].includes(tag.tag) && (tag.tag !== 'see' || !tag.description.includes('{@link'))) { const modeInfo = tagMustHaveNamePosition === true ? '' : ` in "${mode}" mode`; report(`Tag @${tag.tag} must have a name/namepath${modeInfo}.`, null, tag); return; } // REQUIRED TYPE const mustHaveTypePosition = utils.tagMustHaveTypePosition(tag.tag, otherModeMaps); if (mustHaveTypePosition !== false && !tag.type) { const modeInfo = mustHaveTypePosition === true ? '' : ` in "${mode}" mode`; report(`Tag @${tag.tag} must have a type${modeInfo}.`, null, tag); return; } // REQUIRED TYPE OR NAME/NAMEPATH const tagMissingRequiredTypeOrNamepath = utils.tagMissingRequiredTypeOrNamepath(tag, otherModeMaps); if (tagMissingRequiredTypeOrNamepath !== false && !allowEmptyNamepaths) { const modeInfo = tagMissingRequiredTypeOrNamepath === true ? '' : ` in "${mode}" mode`; report(`Tag @${tag.tag} must have either a type or namepath${modeInfo}.`, null, tag); return; } // VALID TYPE const hasTypePosition = mightHaveTypePosition === true && Boolean(tag.type); if (hasTypePosition) { validTypeParsing(tag.type); } // VALID NAME/NAMEPATH const hasNameOrNamepathPosition = (tagMustHaveNamePosition !== false || utils.tagMightHaveNamepath(tag.tag)) && Boolean(tag.name); if (hasNameOrNamepathPosition) { if (mode !== 'jsdoc' && tag.tag === 'template') { utils.parseClosureTemplateTag(tag).forEach(namepath => { validNamepathParsing(namepath); }); } else { validNamepathParsing(tag.name, tag.tag); } } }); }, { iterateAllJsdocs: true, meta: { docs: { description: 'Requires all types to be valid JSDoc or Closure compiler types without syntax errors.', url: 'https://github.com/gajus/eslint-plugin-jsdoc#eslint-plugin-jsdoc-rules-valid-types' }, schema: [{ additionalProperies: false, properties: { allowEmptyNamepaths: { default: false, type: 'boolean' } }, type: 'object' }], type: 'suggestion' } }); exports.default = _default; module.exports = exports.default; //# sourceMappingURL=validTypes.js.map