eslint-plugin-jsdoc
Version:
JSDoc linting rules for ESLint.
1 lines • 13.5 kB
Source Map (JSON)
{"version":3,"file":"requireReturnsCheck.cjs","names":["iterateJsdoc","getDocumentNamepathDefiningTags","tryParseType","traverse","strictNativeTypes"],"sources":["../../src/rules/requireReturnsCheck.js"],"sourcesContent":["import iterateJsdoc from '../iterateJsdoc.js';\nimport {\n getDocumentNamepathDefiningTags,\n strictNativeTypes,\n} from '../jsdocUtils.js';\nimport {\n traverse,\n tryParse as tryParseType,\n} from '@es-joy/jsdoccomment';\n\n/**\n * @type {Partial<Record<import('../jsdocUtils.js').ParserMode, import('jsdoc-type-pratt-parser').ParseMode[]>>}\n */\nconst parseTypeModes = {\n closure: [\n 'closure',\n ],\n jsdoc: [\n 'jsdoc',\n ],\n typescript: [\n 'typescript',\n ],\n};\n\n/**\n * @param {import('../iterateJsdoc.js').Utils} utils\n * @param {import('../iterateJsdoc.js').Settings} settings\n * @returns {boolean}\n */\nconst canSkip = (utils, settings) => {\n const voidingTags = [\n // An abstract function is by definition incomplete\n // so it is perfectly fine if a return is documented but\n // not present within the function.\n // A subclass may inherit the doc and implement the\n // missing return.\n 'abstract',\n 'virtual',\n\n // A constructor function returns `this` by default, so may be `@returns`\n // tag indicating this but no explicit return\n 'class',\n 'constructor',\n 'interface',\n ];\n\n if (settings.mode === 'closure') {\n // Structural Interface in GCC terms, equivalent to @interface tag as far as this rule is concerned\n voidingTags.push('record');\n }\n\n return utils.hasATag(voidingTags) ||\n utils.isConstructor() ||\n utils.classHasTag('interface') ||\n settings.mode === 'closure' && utils.classHasTag('record');\n};\n\n/**\n * @param {import('jsdoc-type-pratt-parser').RootResult} parsedType\n * @returns {import('jsdoc-type-pratt-parser').RootResult}\n */\nconst getReturnTypeLevelNode = (parsedType) => {\n return parsedType.type === 'JsdocTypeParenthesis' ?\n parsedType.element :\n parsedType;\n};\n\n/**\n * @param {import('eslint').Rule.RuleContext} context\n * @param {import('../jsdocUtils.js').ParserMode} mode\n * @returns {import('../jsdocUtils.js').ParserMode}\n */\nconst getParseMode = (context, mode) => {\n const {\n jsdoc,\n } = /** @type {{jsdoc?: {mode?: import('../jsdocUtils.js').ParserMode}}} */ (context.settings);\n\n return jsdoc?.mode ?? mode;\n};\n\nexport default iterateJsdoc(({\n context,\n node,\n report,\n settings,\n sourceCode,\n utils,\n}) => {\n const {\n exemptAsync = true,\n exemptGenerators = settings.mode === 'typescript',\n noNativeTypes = true,\n reportMissingReturnForUndefinedTypes = false,\n } = context.options[0] || {};\n const {\n mode,\n } = settings;\n const parseMode = getParseMode(context, mode);\n\n if (canSkip(utils, settings)) {\n return;\n }\n\n const isAsync = utils.isAsync();\n if (exemptAsync && isAsync) {\n return;\n }\n\n const tagName = /** @type {string} */ (utils.getPreferredTagName({\n tagName: 'returns',\n }));\n if (!tagName) {\n return;\n }\n\n const tags = utils.getTags(tagName);\n\n if (tags.length === 0) {\n return;\n }\n\n if (tags.length > 1) {\n report(`Found more than one @${tagName} declaration.`);\n\n return;\n }\n\n const [\n tag,\n ] = tags;\n\n const type = tag.type.trim();\n\n // https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-7.html#assertion-functions\n if (/asserts\\s/v.test(type)) {\n return;\n }\n\n const returnNever = type === 'never';\n const typedefs = getDocumentNamepathDefiningTags(sourceCode);\n\n /**\n * @param {import('comment-parser').Spec} returnTag\n * @returns {boolean}\n */\n const mayReturnUndefined = (returnTag) => {\n if (utils.mayBeUndefinedTypeTag(returnTag)) {\n return true;\n }\n\n const returnType = returnTag.type.trim();\n let parsedType;\n try {\n parsedType = tryParseType(returnType, parseTypeModes[parseMode]);\n } catch {\n return false;\n }\n\n const returnTypeLevelNode = getReturnTypeLevelNode(parsedType);\n let returnIsUndefined = false;\n traverse(returnTypeLevelNode, (nde, parentNode) => {\n const isReturnLevelNode = !parentNode ||\n returnTypeLevelNode.type === 'JsdocTypeUnion' && parentNode === returnTypeLevelNode;\n if (!isReturnLevelNode) {\n return;\n }\n\n const {\n type: nodeType,\n } = /** @type {import('jsdoc-type-pratt-parser').RootResult} */ (nde);\n\n if (nodeType === 'JsdocTypeUndefined') {\n returnIsUndefined = true;\n return;\n }\n\n if (nodeType !== 'JsdocTypeName') {\n return;\n }\n\n const {\n value,\n } = /** @type {import('jsdoc-type-pratt-parser').NameResult} */ (nde);\n\n if (value === 'void') {\n returnIsUndefined = true;\n return;\n }\n\n const referencedTypedef = typedefs.find((typedefTag) => {\n return typedefTag.name === value;\n });\n\n if (referencedTypedef && utils.mayBeUndefinedTypeTag(referencedTypedef)) {\n returnIsUndefined = true;\n }\n });\n\n return returnIsUndefined;\n };\n\n if (returnNever && utils.hasValueOrExecutorHasNonEmptyResolveValue(false)) {\n report(`JSDoc @${tagName} declaration set with \"never\" but return expression is present in function.`);\n\n return;\n }\n\n if (noNativeTypes && isAsync && strictNativeTypes.includes(type)) {\n report('Function is async or otherwise returns a Promise but the return type is a native type.');\n return;\n }\n\n // In case a return value is declared in JSDoc, we also expect one in the code.\n if (\n !returnNever &&\n (\n reportMissingReturnForUndefinedTypes ||\n !mayReturnUndefined(tag)\n ) &&\n (tag.type === '' && !utils.hasValueOrExecutorHasNonEmptyResolveValue(\n exemptAsync,\n ) ||\n tag.type !== '' && !utils.hasValueOrExecutorHasNonEmptyResolveValue(\n exemptAsync,\n true,\n )) &&\n Boolean(\n !exemptGenerators || !node ||\n !('generator' in /** @type {import('../iterateJsdoc.js').Node} */ (node)) ||\n !(/** @type {import('@typescript-eslint/types').TSESTree.FunctionDeclaration} */ (node)).generator,\n )\n ) {\n report(`JSDoc @${tagName} declaration present but return expression not available in function.`);\n }\n}, {\n meta: {\n docs: {\n description: 'Requires a return statement in function body if a `@returns` tag is specified in JSDoc comment(and reports if multiple `@returns` tags are present).',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-returns-check.md#repos-sticky-header',\n },\n schema: [\n {\n additionalProperties: false,\n properties: {\n exemptAsync: {\n default: true,\n description: `By default, functions which return a \\`Promise\\` that are not\ndetected as resolving with a non-\\`undefined\\` value and \\`async\\` functions\n(even ones that do not explicitly return a value, as these are returning a\n\\`Promise\\` implicitly) will be exempted from reporting by this rule.\nIf you wish to insist that only \\`Promise\\`'s which resolve to\nnon-\\`undefined\\` values or \\`async\\` functions with explicit \\`return\\`'s will\nbe exempted from reporting (i.e., that \\`async\\` functions can be reported\nif they lack an explicit (non-\\`undefined\\`) \\`return\\` when a \\`@returns\\` is\npresent), you can set \\`exemptAsync\\` to \\`false\\` on the options object.`,\n type: 'boolean',\n },\n exemptGenerators: {\n description: `Because a generator might be labeled as having a\n\\`IterableIterator\\` \\`@returns\\` value (along with an iterator type\ncorresponding to the type of any \\`yield\\` statements), projects might wish to\nleverage \\`@returns\\` in generators even without a \\`return\\` statement. This\noption is therefore \\`true\\` by default in \\`typescript\\` mode (in \"jsdoc\" mode,\none might be more likely to take advantage of \\`@yields\\`). Set it to \\`false\\`\nif you wish for a missing \\`return\\` to be flagged regardless.`,\n type: 'boolean',\n },\n noNativeTypes: {\n description: `Whether to check that async functions do not\nindicate they return non-native types. Defaults to \\`true\\`.`,\n type: 'boolean',\n },\n reportMissingReturnForUndefinedTypes: {\n default: false,\n description: `If \\`true\\` and no return or\nresolve value is found, this setting will even insist that reporting occur\nwith \\`void\\` or \\`undefined\\` (including as an indicated \\`Promise\\` type).\nUnlike \\`require-returns\\`, with this option in the rule, one can\n*discourage* the labeling of \\`undefined\\` types. Defaults to \\`false\\`.`,\n type: 'boolean',\n },\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n"],"mappings":"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","ignoreList":[]}