UNPKG

eslint-plugin-jsdoc

Version:
502 lines (463 loc) 19.8 kB
import checkAccess from './rules/checkAccess.js'; import checkAlignment from './rules/checkAlignment.js'; import checkExamples from './rules/checkExamples.js'; import checkIndentation from './rules/checkIndentation.js'; import checkLineAlignment from './rules/checkLineAlignment.js'; import checkParamNames from './rules/checkParamNames.js'; import checkPropertyNames from './rules/checkPropertyNames.js'; import checkSyntax from './rules/checkSyntax.js'; import checkTagNames from './rules/checkTagNames.js'; import checkTemplateNames from './rules/checkTemplateNames.js'; import checkTypes from './rules/checkTypes.js'; import checkValues from './rules/checkValues.js'; import convertToJsdocComments from './rules/convertToJsdocComments.js'; import emptyTags from './rules/emptyTags.js'; import implementsOnClasses from './rules/implementsOnClasses.js'; import importsAsDependencies from './rules/importsAsDependencies.js'; import informativeDocs from './rules/informativeDocs.js'; import linesBeforeBlock from './rules/linesBeforeBlock.js'; import matchDescription from './rules/matchDescription.js'; import matchName from './rules/matchName.js'; import multilineBlocks from './rules/multilineBlocks.js'; import noBadBlocks from './rules/noBadBlocks.js'; import noBlankBlockDescriptions from './rules/noBlankBlockDescriptions.js'; import noBlankBlocks from './rules/noBlankBlocks.js'; import noDefaults from './rules/noDefaults.js'; import noMissingSyntax from './rules/noMissingSyntax.js'; import noMultiAsterisks from './rules/noMultiAsterisks.js'; import noRestrictedSyntax from './rules/noRestrictedSyntax.js'; import noTypes from './rules/noTypes.js'; import noUndefinedTypes from './rules/noUndefinedTypes.js'; import requireAsteriskPrefix from './rules/requireAsteriskPrefix.js'; import requireDescription from './rules/requireDescription.js'; import requireDescriptionCompleteSentence from './rules/requireDescriptionCompleteSentence.js'; import requireExample from './rules/requireExample.js'; import requireFileOverview from './rules/requireFileOverview.js'; import requireHyphenBeforeParamDescription from './rules/requireHyphenBeforeParamDescription.js'; import requireJsdoc from './rules/requireJsdoc.js'; import requireParam from './rules/requireParam.js'; import requireParamDescription from './rules/requireParamDescription.js'; import requireParamName from './rules/requireParamName.js'; import requireParamType from './rules/requireParamType.js'; import requireProperty from './rules/requireProperty.js'; import requirePropertyDescription from './rules/requirePropertyDescription.js'; import requirePropertyName from './rules/requirePropertyName.js'; import requirePropertyType from './rules/requirePropertyType.js'; import requireReturns from './rules/requireReturns.js'; import requireReturnsCheck from './rules/requireReturnsCheck.js'; import requireReturnsDescription from './rules/requireReturnsDescription.js'; import requireReturnsType from './rules/requireReturnsType.js'; import requireTemplate from './rules/requireTemplate.js'; import requireThrows from './rules/requireThrows.js'; import requireYields from './rules/requireYields.js'; import requireYieldsCheck from './rules/requireYieldsCheck.js'; import sortTags from './rules/sortTags.js'; import tagLines from './rules/tagLines.js'; import textEscaping from './rules/textEscaping.js'; import validTypes from './rules/validTypes.js'; import { getJsdocProcessorPlugin } from './getJsdocProcessorPlugin.js'; /** * @typedef {"recommended" | "stylistic" | "contents" | "logical" | "requirements"} ConfigGroups * @typedef {"" | "-typescript" | "-typescript-flavor"} ConfigVariants * @typedef {"" | "-error"} ErrorLevelVariants * @type {import('eslint').ESLint.Plugin & { * configs: Record<`flat/${ConfigGroups}${ConfigVariants}${ErrorLevelVariants}`, import('eslint').Linter.Config> * }} */ const index = { // @ts-expect-error Ok configs: {}, rules: { 'check-access': checkAccess, 'check-alignment': checkAlignment, 'check-examples': checkExamples, 'check-indentation': checkIndentation, 'check-line-alignment': checkLineAlignment, 'check-param-names': checkParamNames, 'check-property-names': checkPropertyNames, 'check-syntax': checkSyntax, 'check-tag-names': checkTagNames, 'check-template-names': checkTemplateNames, 'check-types': checkTypes, 'check-values': checkValues, 'convert-to-jsdoc-comments': convertToJsdocComments, 'empty-tags': emptyTags, 'implements-on-classes': implementsOnClasses, 'imports-as-dependencies': importsAsDependencies, 'informative-docs': informativeDocs, 'lines-before-block': linesBeforeBlock, 'match-description': matchDescription, 'match-name': matchName, 'multiline-blocks': multilineBlocks, 'no-bad-blocks': noBadBlocks, 'no-blank-block-descriptions': noBlankBlockDescriptions, 'no-blank-blocks': noBlankBlocks, 'no-defaults': noDefaults, 'no-missing-syntax': noMissingSyntax, 'no-multi-asterisks': noMultiAsterisks, 'no-restricted-syntax': noRestrictedSyntax, 'no-types': noTypes, 'no-undefined-types': noUndefinedTypes, 'require-asterisk-prefix': requireAsteriskPrefix, 'require-description': requireDescription, 'require-description-complete-sentence': requireDescriptionCompleteSentence, 'require-example': requireExample, 'require-file-overview': requireFileOverview, 'require-hyphen-before-param-description': requireHyphenBeforeParamDescription, 'require-jsdoc': requireJsdoc, 'require-param': requireParam, 'require-param-description': requireParamDescription, 'require-param-name': requireParamName, 'require-param-type': requireParamType, 'require-property': requireProperty, 'require-property-description': requirePropertyDescription, 'require-property-name': requirePropertyName, 'require-property-type': requirePropertyType, 'require-returns': requireReturns, 'require-returns-check': requireReturnsCheck, 'require-returns-description': requireReturnsDescription, 'require-returns-type': requireReturnsType, 'require-template': requireTemplate, 'require-throws': requireThrows, 'require-yields': requireYields, 'require-yields-check': requireYieldsCheck, 'sort-tags': sortTags, 'tag-lines': tagLines, 'text-escaping': textEscaping, 'valid-types': validTypes, }, }; /** * @param {"warn"|"error"} warnOrError * @param {string} [flatName] * @returns {import('eslint').Linter.FlatConfig} */ const createRecommendedRuleset = (warnOrError, flatName) => { return { ...(flatName ? {name: 'jsdoc/' + flatName} : {}), // @ts-expect-error Ok plugins: flatName ? { jsdoc: index, } : [ 'jsdoc', ], rules: { 'jsdoc/check-access': warnOrError, 'jsdoc/check-alignment': warnOrError, 'jsdoc/check-examples': 'off', 'jsdoc/check-indentation': 'off', 'jsdoc/check-line-alignment': 'off', 'jsdoc/check-param-names': warnOrError, 'jsdoc/check-property-names': warnOrError, 'jsdoc/check-syntax': 'off', 'jsdoc/check-tag-names': warnOrError, 'jsdoc/check-template-names': 'off', 'jsdoc/check-types': warnOrError, 'jsdoc/check-values': warnOrError, 'jsdoc/convert-to-jsdoc-comments': 'off', 'jsdoc/empty-tags': warnOrError, 'jsdoc/implements-on-classes': warnOrError, 'jsdoc/imports-as-dependencies': 'off', 'jsdoc/informative-docs': 'off', 'jsdoc/lines-before-block': 'off', 'jsdoc/match-description': 'off', 'jsdoc/match-name': 'off', 'jsdoc/multiline-blocks': warnOrError, 'jsdoc/no-bad-blocks': 'off', 'jsdoc/no-blank-block-descriptions': 'off', 'jsdoc/no-blank-blocks': 'off', 'jsdoc/no-defaults': warnOrError, 'jsdoc/no-missing-syntax': 'off', 'jsdoc/no-multi-asterisks': warnOrError, 'jsdoc/no-restricted-syntax': 'off', 'jsdoc/no-types': 'off', 'jsdoc/no-undefined-types': warnOrError, 'jsdoc/require-asterisk-prefix': 'off', 'jsdoc/require-description': 'off', 'jsdoc/require-description-complete-sentence': 'off', 'jsdoc/require-example': 'off', 'jsdoc/require-file-overview': 'off', 'jsdoc/require-hyphen-before-param-description': 'off', 'jsdoc/require-jsdoc': warnOrError, 'jsdoc/require-param': warnOrError, 'jsdoc/require-param-description': warnOrError, 'jsdoc/require-param-name': warnOrError, 'jsdoc/require-param-type': warnOrError, 'jsdoc/require-property': warnOrError, 'jsdoc/require-property-description': warnOrError, 'jsdoc/require-property-name': warnOrError, 'jsdoc/require-property-type': warnOrError, 'jsdoc/require-returns': warnOrError, 'jsdoc/require-returns-check': warnOrError, 'jsdoc/require-returns-description': warnOrError, 'jsdoc/require-returns-type': warnOrError, 'jsdoc/require-template': 'off', 'jsdoc/require-throws': 'off', 'jsdoc/require-yields': warnOrError, 'jsdoc/require-yields-check': warnOrError, 'jsdoc/sort-tags': 'off', 'jsdoc/tag-lines': warnOrError, 'jsdoc/text-escaping': 'off', 'jsdoc/valid-types': warnOrError, }, }; }; /** * @param {"warn"|"error"} warnOrError * @param {string} [flatName] * @returns {import('eslint').Linter.FlatConfig} */ const createRecommendedTypeScriptRuleset = (warnOrError, flatName) => { const ruleset = createRecommendedRuleset(warnOrError, flatName); return { ...ruleset, rules: { ...ruleset.rules, /* eslint-disable indent -- Extra indent to avoid use by auto-rule-editing */ 'jsdoc/check-tag-names': [ warnOrError, { typed: true, }, ], 'jsdoc/no-types': warnOrError, 'jsdoc/no-undefined-types': 'off', 'jsdoc/require-param-type': 'off', 'jsdoc/require-property-type': 'off', 'jsdoc/require-returns-type': 'off', /* eslint-enable indent */ }, }; }; /** * @param {"warn"|"error"} warnOrError * @param {string} [flatName] * @returns {import('eslint').Linter.FlatConfig} */ const createRecommendedTypeScriptFlavorRuleset = (warnOrError, flatName) => { const ruleset = createRecommendedRuleset(warnOrError, flatName); return { ...ruleset, rules: { ...ruleset.rules, /* eslint-disable indent -- Extra indent to avoid use by auto-rule-editing */ 'jsdoc/no-undefined-types': 'off', /* eslint-enable indent */ }, }; }; /** * @param {(string | unknown[])[]} ruleNames */ const createStandaloneRulesetFactory = (ruleNames) => { /** * @param {"warn"|"error"} warnOrError * @param {string} [flatName] * @returns {import('eslint').Linter.FlatConfig} */ return (warnOrError, flatName) => { return { name: 'jsdoc/' + flatName, plugins: { jsdoc: index }, rules: Object.fromEntries( ruleNames.map( ruleName => typeof ruleName === "string" ? [ruleName, warnOrError] : [ruleName[0], [warnOrError, ...ruleName.slice(1)]] ) ), }; }; } const contentsRules = [ 'jsdoc/informative-docs', 'jsdoc/match-description', 'jsdoc/no-blank-block-descriptions', 'jsdoc/no-blank-blocks', ['jsdoc/text-escaping', { escapeHTML: true }] ] const createContentsTypescriptRuleset = createStandaloneRulesetFactory(contentsRules); const createContentsTypescriptFlavorRuleset = createStandaloneRulesetFactory(contentsRules); const logicalRules = [ 'jsdoc/check-access', 'jsdoc/check-param-names', 'jsdoc/check-property-names', 'jsdoc/check-syntax', 'jsdoc/check-tag-names', 'jsdoc/check-template-names', 'jsdoc/check-types', 'jsdoc/check-values', 'jsdoc/empty-tags', 'jsdoc/implements-on-classes', 'jsdoc/require-returns-check', 'jsdoc/require-yields-check', 'jsdoc/no-bad-blocks', 'jsdoc/no-defaults', 'jsdoc/no-types', 'jsdoc/no-undefined-types', 'jsdoc/valid-types', ]; const createLogicalTypescriptRuleset = createStandaloneRulesetFactory(logicalRules); const createLogicalTypescriptFlavorRuleset = createStandaloneRulesetFactory(logicalRules); const requirementsRules = [ 'jsdoc/require-example', 'jsdoc/require-jsdoc', 'jsdoc/require-param', 'jsdoc/require-param-description', 'jsdoc/require-param-name', 'jsdoc/require-property', 'jsdoc/require-property-description', 'jsdoc/require-property-name', 'jsdoc/require-returns', 'jsdoc/require-returns-description', 'jsdoc/require-yields', ]; const createRequirementsTypeScriptRuleset = createStandaloneRulesetFactory(requirementsRules); const createRequirementsTypeScriptFlavorRuleset = createStandaloneRulesetFactory([ ...requirementsRules, 'jsdoc/require-param-type', 'jsdoc/require-property-type', 'jsdoc/require-returns-type', 'jsdoc/require-template', ]); const stylisticRules = [ 'jsdoc/check-alignment', 'jsdoc/check-line-alignment', 'jsdoc/lines-before-block', 'jsdoc/multiline-blocks', 'jsdoc/no-multi-asterisks', 'jsdoc/require-asterisk-prefix', ['jsdoc/require-hyphen-before-param-description', 'never'], 'jsdoc/tag-lines', ]; const createStylisticTypeScriptRuleset = createStandaloneRulesetFactory(stylisticRules); const createStylisticTypeScriptFlavorRuleset = createStandaloneRulesetFactory(stylisticRules); /* c8 ignore next 3 -- TS */ if (!index.configs) { throw new Error('TypeScript guard'); } index.configs.recommended = createRecommendedRuleset('warn'); index.configs['recommended-error'] = createRecommendedRuleset('error'); index.configs['recommended-typescript'] = createRecommendedTypeScriptRuleset('warn'); index.configs['recommended-typescript-error'] = createRecommendedTypeScriptRuleset('error'); index.configs['recommended-typescript-flavor'] = createRecommendedTypeScriptFlavorRuleset('warn'); index.configs['recommended-typescript-flavor-error'] = createRecommendedTypeScriptFlavorRuleset('error'); index.configs['flat/recommended'] = createRecommendedRuleset('warn', 'flat/recommended'); index.configs['flat/recommended-error'] = createRecommendedRuleset('error', 'flat/recommended-error'); index.configs['flat/recommended-typescript'] = createRecommendedTypeScriptRuleset('warn', 'flat/recommended-typescript'); index.configs['flat/recommended-typescript-error'] = createRecommendedTypeScriptRuleset('error', 'flat/recommended-typescript-error'); index.configs['flat/recommended-typescript-flavor'] = createRecommendedTypeScriptFlavorRuleset('warn', 'flat/recommended-typescript-flavor'); index.configs['flat/recommended-typescript-flavor-error'] = createRecommendedTypeScriptFlavorRuleset('error', 'flat/recommended-typescript-flavor-error'); index.configs['flat/contents-typescript'] = createContentsTypescriptRuleset('warn', 'flat/contents-typescript'); index.configs['flat/contents-typescript-error'] = createContentsTypescriptRuleset('error', 'flat/contents-typescript-error'); index.configs['flat/contents-typescript-flavor'] = createContentsTypescriptFlavorRuleset('warn', 'flat/contents-typescript-flavor'); index.configs['flat/contents-typescript-flavor-error'] = createContentsTypescriptFlavorRuleset('error', 'flat/contents-typescript-error-flavor'); index.configs['flat/logical-typescript'] = createLogicalTypescriptRuleset('warn', 'flat/logical-typescript'); index.configs['flat/logical-typescript-error'] = createLogicalTypescriptRuleset('error', 'flat/logical-typescript-error'); index.configs['flat/logical-typescript-flavor'] = createLogicalTypescriptFlavorRuleset('warn', 'flat/logical-typescript-flavor'); index.configs['flat/logical-typescript-flavor-error'] = createLogicalTypescriptFlavorRuleset('error', 'flat/logical-typescript-error-flavor'); index.configs['flat/requirements-typescript'] = createRequirementsTypeScriptRuleset('warn', 'flat/requirements-typescript'); index.configs['flat/requirements-typescript-error'] = createRequirementsTypeScriptRuleset('error', 'flat/requirements-typescript-error'); index.configs['flat/requirements-typescript-flavor'] = createRequirementsTypeScriptFlavorRuleset('warn', 'flat/requirements-typescript-flavor'); index.configs['flat/requirements-typescript-flavor-error'] = createRequirementsTypeScriptFlavorRuleset('error', 'flat/requirements-typescript-error-flavor'); index.configs['flat/stylistic-typescript'] = createStylisticTypeScriptRuleset('warn', 'flat/stylistic-typescript'); index.configs['flat/stylistic-typescript-error'] = createStylisticTypeScriptRuleset('error', 'flat/stylistic-typescript-error'); index.configs['flat/stylistic-typescript-flavor'] = createStylisticTypeScriptFlavorRuleset('warn', 'flat/stylistic-typescript-flavor'); index.configs['flat/stylistic-typescript-flavor-error'] = createStylisticTypeScriptFlavorRuleset('error', 'flat/stylistic-typescript-error-flavor'); index.configs.examples = /** @type {import('eslint').Linter.FlatConfig[]} */ ([ { name: 'jsdoc/examples/processor', files: ['**/*.js'], plugins: { examples: getJsdocProcessorPlugin() }, processor: 'examples/examples', }, { name: 'jsdoc/examples/rules', files: ['**/*.md/*.js'], rules: { // "always" newline rule at end unlikely in sample code 'eol-last': 0, // Wouldn't generally expect example paths to resolve relative to JS file 'import/no-unresolved': 0, // Snippets likely too short to always include import/export info 'import/unambiguous': 0, 'jsdoc/require-file-overview': 0, // The end of a multiline comment would end the comment the example is in. 'jsdoc/require-jsdoc': 0, // Unlikely to have inadvertent debugging within examples 'no-console': 0, // Often wish to start `@example` code after newline; also may use // empty lines for spacing 'no-multiple-empty-lines': 0, // Many variables in examples will be `undefined` 'no-undef': 0, // Common to define variables for clarity without always using them 'no-unused-vars': 0, // See import/no-unresolved 'node/no-missing-import': 0, 'node/no-missing-require': 0, // Can generally look nicer to pad a little even if code imposes more stringency 'padded-blocks': 0, } } ]); index.configs['default-expressions'] = /** @type {import('eslint').Linter.FlatConfig[]} */ ([ { files: ['**/*.js'], name: 'jsdoc/default-expressions/processor', plugins: { examples: getJsdocProcessorPlugin({ checkDefaults: true, checkParams: true, checkProperties: true }) }, processor: 'examples/examples' }, { name: 'jsdoc/default-expressions/rules', files: ['**/*.jsdoc-defaults', '**/*.jsdoc-params', '**/*.jsdoc-properties'], rules: { ...index.configs.examples[1].rules, 'chai-friendly/no-unused-expressions': 0, 'no-empty-function': 0, 'no-new': 0, 'no-unused-expressions': 0, quotes: [ 'error', 'double', ], semi: [ 'error', 'never', ], strict: 0 }, } ]); index.configs['examples-and-default-expressions'] = /** @type {import('eslint').Linter.FlatConfig[]} */ ([ { name: 'jsdoc/examples-and-default-expressions', plugins: { examples: getJsdocProcessorPlugin({ checkDefaults: true, checkParams: true, checkProperties: true }) }, }, ...index.configs.examples.map((config) => { return { ...config, plugins: {} }; }), ...index.configs['default-expressions'].map((config) => { return { ...config, plugins: {} }; }) ]); export default index;