eslint-plugin-jsdoc
Advanced tools
Comparing version 48.8.3 to 48.9.0
@@ -0,2 +1,4 @@ | ||
export { getJsdocProcessorPlugin }; | ||
export default index; | ||
import { getJsdocProcessorPlugin } from './getJsdocProcessorPlugin.js'; | ||
/** | ||
@@ -3,0 +5,0 @@ * @type {import('eslint').ESLint.Plugin & { |
@@ -12,3 +12,3 @@ import globals from 'globals'; | ||
jsdoc | ||
} | ||
}, | ||
}; | ||
@@ -19,5 +19,6 @@ | ||
// canonicalJsdoc, | ||
...jsdoc.configs['examples-and-default-expressions'], | ||
{ | ||
// Must be by itself | ||
ignores: ['dist/**/*.js', '.ignore/**/*.js'], | ||
ignores: ['dist/**', '.ignore/**/*.js'], | ||
}, | ||
@@ -24,0 +25,0 @@ { |
@@ -37,2 +37,3 @@ { | ||
"@types/eslint": "^8.56.10", | ||
"@types/espree": "^10.1.0", | ||
"@types/esquery": "^1.5.4", | ||
@@ -148,3 +149,3 @@ "@types/estree": "^1.0.5", | ||
}, | ||
"version": "48.8.3" | ||
"version": "48.9.0" | ||
} |
@@ -20,2 +20,3 @@ <a name="user-content-eslint-plugin-jsdoc"></a> | ||
* [Advanced](#user-content-eslint-plugin-jsdoc-advanced) | ||
* [Processors](#user-content-eslint-plugin-jsdoc-processors) | ||
* [Rules](#user-content-eslint-plugin-jsdoc-rules) | ||
@@ -245,2 +246,8 @@ | ||
<a name="user-content-eslint-plugin-jsdoc-processors"></a> | ||
<a name="eslint-plugin-jsdoc-processors"></a> | ||
## Processors | ||
See our `@example` and other item [processors](./docs/processors.md#readme). | ||
<a name="user-content-eslint-plugin-jsdoc-rules"></a> | ||
@@ -247,0 +254,0 @@ <a name="eslint-plugin-jsdoc-rules"></a> |
108
src/index.js
@@ -58,2 +58,4 @@ import checkAccess from './rules/checkAccess.js'; | ||
import { getJsdocProcessorPlugin } from './getJsdocProcessorPlugin.js'; | ||
/** | ||
@@ -278,2 +280,108 @@ * @type {import('eslint').ESLint.Plugin & { | ||
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) => { | ||
delete config.plugins; | ||
return config; | ||
}), | ||
...index.configs['default-expressions'].map((config) => { | ||
delete config.plugins; | ||
return config; | ||
}) | ||
]); | ||
export { getJsdocProcessorPlugin }; | ||
export default index; |
@@ -1,2 +0,2 @@ | ||
import jsdocUtils from './jsdocUtils.js'; | ||
import * as jsdocUtils from './jsdocUtils.js'; | ||
import { | ||
@@ -631,7 +631,7 @@ commentHandler, | ||
}) => { | ||
const ret = jsdocUtils.getPreferredTagName( | ||
context, | ||
const ret = jsdocUtils.getPreferredTagNameSimple( | ||
tagName, | ||
/** @type {import('./jsdocUtils.js').ParserMode} */ (mode), | ||
tagName, | ||
tagNamePreference, | ||
context, | ||
); | ||
@@ -787,40 +787,3 @@ const isObject = ret && typeof ret === 'object'; | ||
utils.getTagDescription = (tg, returnArray) => { | ||
/** | ||
* @type {string[]} | ||
*/ | ||
const descriptions = []; | ||
tg.source.some(({ | ||
tokens: { | ||
end, | ||
lineEnd, | ||
postDelimiter, | ||
tag, | ||
postTag, | ||
name, | ||
type, | ||
description, | ||
}, | ||
}) => { | ||
const desc = ( | ||
tag && postTag || | ||
!tag && !name && !type && postDelimiter || '' | ||
// Remove space | ||
).slice(1) + | ||
(description || '') + (lineEnd || ''); | ||
if (end) { | ||
if (desc) { | ||
descriptions.push(desc); | ||
} | ||
return true; | ||
} | ||
descriptions.push(desc); | ||
return false; | ||
}); | ||
return returnArray ? descriptions : descriptions.join('\n'); | ||
return jsdocUtils.getTagDescription(tg, returnArray); | ||
}; | ||
@@ -1380,25 +1343,9 @@ | ||
/** @type {GetPreferredTagName} */ | ||
utils.getPreferredTagName = ({ | ||
tagName, | ||
skipReportingBlockedTag = false, | ||
allowObjectReturn = false, | ||
defaultMessage = `Unexpected tag \`@${tagName}\``, | ||
}) => { | ||
const ret = jsdocUtils.getPreferredTagName(context, mode, tagName, tagNamePreference); | ||
const isObject = ret && typeof ret === 'object'; | ||
if (utils.hasTag(tagName) && (ret === false || isObject && !ret.replacement)) { | ||
if (skipReportingBlockedTag) { | ||
return { | ||
blocked: true, | ||
tagName, | ||
}; | ||
utils.getPreferredTagName = (args) => { | ||
return jsdocUtils.getPreferredTagName( | ||
jsdoc, { | ||
...args, | ||
context, mode, report, tagNamePreference, | ||
} | ||
const message = isObject && ret.message || defaultMessage; | ||
report(message, null, utils.getTags(tagName)[0]); | ||
return false; | ||
} | ||
return isObject && !allowObjectReturn ? ret.replacement : ret; | ||
); | ||
}; | ||
@@ -1625,5 +1572,3 @@ | ||
utils.getTags = (tagName) => { | ||
return utils.filterTags((item) => { | ||
return item.tag === tagName; | ||
}); | ||
return jsdocUtils.getTags(jsdoc, tagName); | ||
}; | ||
@@ -1633,3 +1578,3 @@ | ||
utils.getPresentTags = (tagList) => { | ||
return utils.filterTags((tag) => { | ||
return jsdocUtils.filterTags(jsdoc, (tag) => { | ||
return tagList.includes(tag.tag); | ||
@@ -1641,3 +1586,3 @@ }); | ||
utils.filterTags = (filter) => { | ||
return jsdoc.tags.filter((tag) => { | ||
return jsdocUtils.filterTags(jsdoc, (tag) => { | ||
return filter(tag); | ||
@@ -1708,30 +1653,9 @@ }); | ||
/** @type {ForEachPreferredTag} */ | ||
utils.forEachPreferredTag = (tagName, arrayHandler, skipReportingBlockedTag = false) => { | ||
const targetTagName = /** @type {string|false} */ ( | ||
utils.getPreferredTagName({ | ||
utils.forEachPreferredTag = (tagName, arrayHandler, skipReportingBlockedTag) => { | ||
return jsdocUtils.forEachPreferredTag( | ||
jsdoc, tagName, arrayHandler, { | ||
skipReportingBlockedTag, | ||
tagName, | ||
}) | ||
context, mode, report, tagNamePreference | ||
} | ||
); | ||
if (!targetTagName || | ||
skipReportingBlockedTag && targetTagName && typeof targetTagName === 'object' | ||
) { | ||
return; | ||
} | ||
const matchingJsdocTags = jsdoc.tags.filter(({ | ||
tag, | ||
}) => { | ||
return tag === targetTagName; | ||
}); | ||
for (const matchingJsdocTag of matchingJsdocTags) { | ||
arrayHandler( | ||
/** | ||
* @type {import('@es-joy/jsdoccomment').JsdocTagWithInline} | ||
*/ ( | ||
matchingJsdocTag | ||
), targetTagName, | ||
); | ||
} | ||
}; | ||
@@ -2040,4 +1964,4 @@ | ||
utils.hasTag('private') || | ||
jsdoc.tags | ||
.filter(({ | ||
jsdocUtils | ||
.filterTags(jsdoc, ({ | ||
tag, | ||
@@ -2044,0 +1968,0 @@ }) => { |
@@ -524,3 +524,3 @@ import getDefaultTagStructureForMode from './getDefaultTagStructureForMode.js'; | ||
* @param {ParserMode|undefined} mode | ||
* @param {import('eslint').Rule.RuleContext} context | ||
* @param {Reporter} context | ||
* @returns {import('./tagNames.js').AliasedTags} | ||
@@ -560,6 +560,58 @@ */ | ||
/** | ||
* @param {import('eslint').Rule.RuleContext} context | ||
* @param {import('comment-parser').Spec} tg | ||
* @param {boolean} [returnArray] | ||
* @returns {string[]|string} | ||
*/ | ||
const getTagDescription = (tg, returnArray) => { | ||
/** | ||
* @type {string[]} | ||
*/ | ||
const descriptions = []; | ||
tg.source.some(({ | ||
tokens: { | ||
end, | ||
lineEnd, | ||
postDelimiter, | ||
tag, | ||
postTag, | ||
name, | ||
type, | ||
description, | ||
}, | ||
}) => { | ||
const desc = ( | ||
tag && postTag || | ||
!tag && !name && !type && postDelimiter || '' | ||
// Remove space | ||
).slice(1) + | ||
(description || '') + (lineEnd || ''); | ||
if (end) { | ||
if (desc) { | ||
descriptions.push(desc); | ||
} | ||
return true; | ||
} | ||
descriptions.push(desc); | ||
return false; | ||
}); | ||
return returnArray ? descriptions : descriptions.join('\n'); | ||
}; | ||
/** | ||
* @typedef {{ | ||
* report: (descriptor: import('eslint').Rule.ReportDescriptor) => void | ||
* }} Reporter | ||
*/ | ||
/** | ||
* @param {string} name | ||
* @param {ParserMode|undefined} mode | ||
* @param {string} name | ||
* @param {TagNamePreference} tagPreference | ||
* @param {Reporter} context | ||
* @returns {string|false|{ | ||
@@ -570,7 +622,11 @@ * message: string; | ||
*/ | ||
const getPreferredTagName = ( | ||
context, | ||
const getPreferredTagNameSimple = ( | ||
name, | ||
mode, | ||
name, | ||
tagPreference = {}, | ||
context = { | ||
report () { | ||
// No-op | ||
} | ||
}, | ||
) => { | ||
@@ -656,2 +712,125 @@ const prefValues = Object.values(tagPreference); | ||
/** | ||
* @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc | ||
* @param {(tag: import('@es-joy/jsdoccomment').JsdocTagWithInline) => boolean} filter | ||
* @returns {import('@es-joy/jsdoccomment').JsdocTagWithInline[]} | ||
*/ | ||
const filterTags = (jsdoc, filter) => { | ||
return jsdoc.tags.filter((tag) => { | ||
return filter(tag); | ||
}); | ||
}; | ||
/** | ||
* @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc | ||
* @param {string} tagName | ||
* @returns {import('comment-parser').Spec[]} | ||
*/ | ||
const getTags = (jsdoc, tagName) => { | ||
return filterTags(jsdoc, (item) => { | ||
return item.tag === tagName; | ||
}); | ||
}; | ||
/** | ||
* @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc | ||
* @param {{ | ||
* tagName: string, | ||
* context?: import('eslint').Rule.RuleContext, | ||
* mode?: ParserMode, | ||
* report?: import('./iterateJsdoc.js').Report | ||
* tagNamePreference?: TagNamePreference | ||
* skipReportingBlockedTag?: boolean, | ||
* allowObjectReturn?: boolean, | ||
* defaultMessage?: string, | ||
* }} cfg | ||
* @returns {string|undefined|false|{ | ||
* message: string; | ||
* replacement?: string|undefined; | ||
* }|{ | ||
* blocked: true, | ||
* tagName: string | ||
* }} | ||
*/ | ||
const getPreferredTagName = (jsdoc, { | ||
tagName, | ||
context, mode, | ||
tagNamePreference, | ||
report = () => {}, | ||
skipReportingBlockedTag = false, | ||
allowObjectReturn = false, | ||
defaultMessage = `Unexpected tag \`@${tagName}\``, | ||
}) => { | ||
const ret = getPreferredTagNameSimple(tagName, mode, tagNamePreference, context); | ||
const isObject = ret && typeof ret === 'object'; | ||
if (hasTag(jsdoc, tagName) && (ret === false || isObject && !ret.replacement)) { | ||
if (skipReportingBlockedTag) { | ||
return { | ||
blocked: true, | ||
tagName, | ||
}; | ||
} | ||
const message = isObject && ret.message || defaultMessage; | ||
report(message, null, getTags(jsdoc, tagName)[0]); | ||
return false; | ||
} | ||
return isObject && !allowObjectReturn ? ret.replacement : ret; | ||
}; | ||
/** | ||
* @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc | ||
* @param {string} tagName | ||
* @param {( | ||
* matchingJsdocTag: import('@es-joy/jsdoccomment').JsdocTagWithInline, | ||
* targetTagName: string | ||
* ) => void} arrayHandler | ||
* @param {object} cfg | ||
* @param {import('eslint').Rule.RuleContext} [cfg.context] | ||
* @param {ParserMode} [cfg.mode] | ||
* @param {import('./iterateJsdoc.js').Report} [cfg.report] | ||
* @param {TagNamePreference} [cfg.tagNamePreference] | ||
* @param {boolean} [cfg.skipReportingBlockedTag] | ||
* @returns {void} | ||
*/ | ||
const forEachPreferredTag = ( | ||
jsdoc, tagName, arrayHandler, | ||
{ | ||
context, mode, report, | ||
tagNamePreference, | ||
skipReportingBlockedTag = false, | ||
} = {} | ||
) => { | ||
const targetTagName = /** @type {string|false} */ ( | ||
getPreferredTagName(jsdoc, { | ||
skipReportingBlockedTag, | ||
tagName, | ||
context, mode, report, tagNamePreference | ||
}) | ||
); | ||
if (!targetTagName || | ||
skipReportingBlockedTag && targetTagName && typeof targetTagName === 'object' | ||
) { | ||
return; | ||
} | ||
const matchingJsdocTags = jsdoc.tags.filter(({ | ||
tag, | ||
}) => { | ||
return tag === targetTagName; | ||
}); | ||
for (const matchingJsdocTag of matchingJsdocTags) { | ||
arrayHandler( | ||
/** | ||
* @type {import('@es-joy/jsdoccomment').JsdocTagWithInline} | ||
*/ ( | ||
matchingJsdocTag | ||
), targetTagName, | ||
); | ||
} | ||
}; | ||
/** | ||
* Get all tags, inline tags and inline tags in tags | ||
@@ -1659,3 +1838,3 @@ * @param {import('./iterateJsdoc.js').JsdocBlockWithInline} jsdoc | ||
export default { | ||
export { | ||
comparePaths, | ||
@@ -1665,3 +1844,5 @@ dropPathSegmentQuotes, | ||
exemptSpeciaMethods, | ||
filterTags, | ||
flattenRoots, | ||
forEachPreferredTag, | ||
getAllTags, | ||
@@ -1673,3 +1854,6 @@ getContextObject, | ||
getPreferredTagName, | ||
getPreferredTagNameSimple, | ||
getRegexFromString, | ||
getTagDescription, | ||
getTags, | ||
getTagsByType, | ||
@@ -1676,0 +1860,0 @@ getTagStructureForMode, |
@@ -5,4 +5,8 @@ import iterateJsdoc from '../iterateJsdoc.js'; | ||
} from '../iterateJsdoc.js'; | ||
import jsdocUtils from '../jsdocUtils.js'; | ||
import { | ||
getIndent, | ||
getContextObject, | ||
enforcedContexts, | ||
} from '../jsdocUtils.js'; | ||
import { | ||
getNonJsdocComment, | ||
@@ -118,3 +122,3 @@ getDecorator, | ||
const indent = jsdocUtils.getIndent({ | ||
const indent = getIndent({ | ||
text: sourceCode.getText( | ||
@@ -260,7 +264,7 @@ /** @type {import('eslint').Rule.Node} */ (baseNode), | ||
return { | ||
...jsdocUtils.getContextObject( | ||
jsdocUtils.enforcedContexts(context, true, settings), | ||
...getContextObject( | ||
enforcedContexts(context, true, settings), | ||
checkNonJsdoc, | ||
), | ||
...jsdocUtils.getContextObject( | ||
...getContextObject( | ||
contextsAfter, | ||
@@ -271,3 +275,3 @@ (_info, _handler, node) => { | ||
), | ||
...jsdocUtils.getContextObject( | ||
...getContextObject( | ||
contextsBeforeAndAfter, | ||
@@ -274,0 +278,0 @@ (_info, _handler, node) => { |
@@ -5,4 +5,12 @@ import exportParser from '../exportParser.js'; | ||
} from '../iterateJsdoc.js'; | ||
import jsdocUtils from '../jsdocUtils.js'; | ||
import { | ||
exemptSpeciaMethods, | ||
isConstructor, | ||
getFunctionParameterNames, | ||
hasReturnValue, | ||
getIndent, | ||
getContextObject, | ||
enforcedContexts, | ||
} from '../jsdocUtils.js'; | ||
import { | ||
getDecorator, | ||
@@ -385,3 +393,3 @@ getJSDocComment, | ||
// setters or getters) being reported | ||
if (jsdocUtils.exemptSpeciaMethods( | ||
if (exemptSpeciaMethods( | ||
{ | ||
@@ -410,6 +418,6 @@ description: '', | ||
// `exemptEmptyConstructors` option is set) | ||
exemptEmptyConstructors && jsdocUtils.isConstructor(node) | ||
exemptEmptyConstructors && isConstructor(node) | ||
) { | ||
const functionParameterNames = jsdocUtils.getFunctionParameterNames(node); | ||
if (!functionParameterNames.length && !jsdocUtils.hasReturnValue(node)) { | ||
const functionParameterNames = getFunctionParameterNames(node); | ||
if (!functionParameterNames.length && !hasReturnValue(node)) { | ||
return; | ||
@@ -433,3 +441,3 @@ } | ||
const indent = jsdocUtils.getIndent({ | ||
const indent = getIndent({ | ||
text: sourceCode.getText( | ||
@@ -523,4 +531,4 @@ /** @type {import('eslint').Rule.Node} */ (baseNode), | ||
return { | ||
...jsdocUtils.getContextObject( | ||
jsdocUtils.enforcedContexts(context, [], settings), | ||
...getContextObject( | ||
enforcedContexts(context, [], settings), | ||
checkJsDoc, | ||
@@ -527,0 +535,0 @@ ), |
@@ -8,3 +8,3 @@ const WarnSettings = function () { | ||
* Warn only once for each context and setting | ||
* @param {import('eslint').Rule.RuleContext} context | ||
* @param {{}} context | ||
* @param {string} setting | ||
@@ -20,3 +20,3 @@ * @returns {boolean} | ||
/** | ||
* @param {import('eslint').Rule.RuleContext} context | ||
* @param {{}} context | ||
* @param {string} setting | ||
@@ -23,0 +23,0 @@ * @returns {void} |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
2030532
213
33294
319
52
6