eslint-plugin-jsdoc 48.5.2 → 48.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -0
- package/dist/generateRule.cjs +1 -1
- package/dist/generateRule.cjs.map +1 -1
- package/dist/index.cjs +6 -0
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.d.ts.map +1 -1
- package/dist/jsdocUtils.cjs +1 -1
- package/dist/jsdocUtils.cjs.map +1 -1
- package/dist/rules/convertToJsdocComments.cjs +313 -0
- package/dist/rules/convertToJsdocComments.cjs.map +1 -0
- package/dist/rules/requireJsdoc.cjs +8 -2
- package/dist/rules/requireJsdoc.cjs.map +1 -1
- package/dist/rules/requireTemplate.cjs +124 -0
- package/dist/rules/requireTemplate.cjs.map +1 -0
- package/package.json +17 -17
- package/src/index.js +6 -0
- package/src/jsdocUtils.js +1 -1
- package/src/rules/convertToJsdocComments.js +384 -0
- package/src/rules/requireJsdoc.js +10 -2
- package/src/rules/requireTemplate.js +119 -0
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, "__esModule", {
|
|
4
|
+
value: true
|
|
5
|
+
});
|
|
6
|
+
exports.default = void 0;
|
|
7
|
+
var _jsdoccomment = require("@es-joy/jsdoccomment");
|
|
8
|
+
var _iterateJsdoc = _interopRequireDefault(require("../iterateJsdoc.cjs"));
|
|
9
|
+
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
|
|
10
|
+
var _default = exports.default = (0, _iterateJsdoc.default)(({
|
|
11
|
+
context,
|
|
12
|
+
utils,
|
|
13
|
+
node,
|
|
14
|
+
settings,
|
|
15
|
+
report
|
|
16
|
+
}) => {
|
|
17
|
+
const {
|
|
18
|
+
requireSeparateTemplates = false
|
|
19
|
+
} = context.options[0] || {};
|
|
20
|
+
const {
|
|
21
|
+
mode
|
|
22
|
+
} = settings;
|
|
23
|
+
const usedNames = new Set();
|
|
24
|
+
const templateTags = utils.getTags('template');
|
|
25
|
+
const templateNames = templateTags.flatMap(({
|
|
26
|
+
name
|
|
27
|
+
}) => {
|
|
28
|
+
return name.split(/,\s*/);
|
|
29
|
+
});
|
|
30
|
+
for (const tag of templateTags) {
|
|
31
|
+
const {
|
|
32
|
+
name
|
|
33
|
+
} = tag;
|
|
34
|
+
const names = name.split(/,\s*/);
|
|
35
|
+
if (requireSeparateTemplates && names.length > 1) {
|
|
36
|
+
report(`Missing separate @template for ${names[1]}`, null, tag);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
/**
|
|
41
|
+
* @param {import('@typescript-eslint/types').TSESTree.TSTypeAliasDeclaration} aliasDeclaration
|
|
42
|
+
*/
|
|
43
|
+
const checkParameters = aliasDeclaration => {
|
|
44
|
+
/* c8 ignore next -- Guard */
|
|
45
|
+
const {
|
|
46
|
+
params
|
|
47
|
+
} = aliasDeclaration.typeParameters ?? {
|
|
48
|
+
params: []
|
|
49
|
+
};
|
|
50
|
+
for (const {
|
|
51
|
+
name: {
|
|
52
|
+
name
|
|
53
|
+
}
|
|
54
|
+
} of params) {
|
|
55
|
+
usedNames.add(name);
|
|
56
|
+
}
|
|
57
|
+
for (const usedName of usedNames) {
|
|
58
|
+
if (!templateNames.includes(usedName)) {
|
|
59
|
+
report(`Missing @template ${usedName}`);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
const handleTypeAliases = () => {
|
|
64
|
+
var _nde$declaration;
|
|
65
|
+
const nde = /** @type {import('@typescript-eslint/types').TSESTree.Node} */
|
|
66
|
+
node;
|
|
67
|
+
if (!nde) {
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
switch (nde.type) {
|
|
71
|
+
case 'ExportNamedDeclaration':
|
|
72
|
+
if (((_nde$declaration = nde.declaration) === null || _nde$declaration === void 0 ? void 0 : _nde$declaration.type) === 'TSTypeAliasDeclaration') {
|
|
73
|
+
checkParameters(nde.declaration);
|
|
74
|
+
}
|
|
75
|
+
break;
|
|
76
|
+
case 'TSTypeAliasDeclaration':
|
|
77
|
+
checkParameters(nde);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
const typedefTags = utils.getTags('typedef');
|
|
82
|
+
if (!typedefTags.length || typedefTags.length >= 2) {
|
|
83
|
+
handleTypeAliases();
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
const potentialType = typedefTags[0].type;
|
|
87
|
+
const parsedType = mode === 'permissive' ? (0, _jsdoccomment.tryParse)( /** @type {string} */potentialType) : (0, _jsdoccomment.parse)( /** @type {string} */potentialType, mode);
|
|
88
|
+
(0, _jsdoccomment.traverse)(parsedType, nde => {
|
|
89
|
+
const {
|
|
90
|
+
type,
|
|
91
|
+
value
|
|
92
|
+
} = /** @type {import('jsdoc-type-pratt-parser').NameResult} */nde;
|
|
93
|
+
if (type === 'JsdocTypeName' && /^[A-Z]$/.test(value)) {
|
|
94
|
+
usedNames.add(value);
|
|
95
|
+
}
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
// Could check against whitelist/blacklist
|
|
99
|
+
for (const usedName of usedNames) {
|
|
100
|
+
if (!templateNames.includes(usedName)) {
|
|
101
|
+
report(`Missing @template ${usedName}`, null, typedefTags[0]);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}, {
|
|
105
|
+
iterateAllJsdocs: true,
|
|
106
|
+
meta: {
|
|
107
|
+
docs: {
|
|
108
|
+
description: 'Requires template tags for each generic type parameter',
|
|
109
|
+
url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-template.md#repos-sticky-header'
|
|
110
|
+
},
|
|
111
|
+
schema: [{
|
|
112
|
+
additionalProperties: false,
|
|
113
|
+
properties: {
|
|
114
|
+
requireSeparateTemplates: {
|
|
115
|
+
type: 'boolean'
|
|
116
|
+
}
|
|
117
|
+
},
|
|
118
|
+
type: 'object'
|
|
119
|
+
}],
|
|
120
|
+
type: 'suggestion'
|
|
121
|
+
}
|
|
122
|
+
});
|
|
123
|
+
module.exports = exports.default;
|
|
124
|
+
//# sourceMappingURL=requireTemplate.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requireTemplate.cjs","names":["_jsdoccomment","require","_iterateJsdoc","_interopRequireDefault","e","__esModule","default","_default","exports","iterateJsdoc","context","utils","node","settings","report","requireSeparateTemplates","options","mode","usedNames","Set","templateTags","getTags","templateNames","flatMap","name","split","tag","names","length","checkParameters","aliasDeclaration","params","typeParameters","add","usedName","includes","handleTypeAliases","_nde$declaration","nde","type","declaration","typedefTags","potentialType","parsedType","tryParseType","parseType","traverse","value","test","iterateAllJsdocs","meta","docs","description","url","schema","additionalProperties","properties","module"],"sources":["../../src/rules/requireTemplate.js"],"sourcesContent":["import {\n parse as parseType,\n traverse,\n tryParse as tryParseType,\n} from '@es-joy/jsdoccomment';\nimport iterateJsdoc from '../iterateJsdoc.js';\n\nexport default iterateJsdoc(({\n context,\n utils,\n node,\n settings,\n report,\n}) => {\n const {\n requireSeparateTemplates = false,\n } = context.options[0] || {};\n\n const {\n mode\n } = settings;\n\n const usedNames = new Set();\n const templateTags = utils.getTags('template');\n const templateNames = templateTags.flatMap(({name}) => {\n return name.split(/,\\s*/);\n });\n\n for (const tag of templateTags) {\n const {name} = tag;\n const names = name.split(/,\\s*/);\n if (requireSeparateTemplates && names.length > 1) {\n report(`Missing separate @template for ${names[1]}`, null, tag);\n }\n }\n\n /**\n * @param {import('@typescript-eslint/types').TSESTree.TSTypeAliasDeclaration} aliasDeclaration\n */\n const checkParameters = (aliasDeclaration) => {\n /* c8 ignore next -- Guard */\n const {params} = aliasDeclaration.typeParameters ?? {params: []};\n for (const {name: {name}} of params) {\n usedNames.add(name);\n }\n for (const usedName of usedNames) {\n if (!templateNames.includes(usedName)) {\n report(`Missing @template ${usedName}`);\n }\n }\n };\n\n const handleTypeAliases = () => {\n const nde = /** @type {import('@typescript-eslint/types').TSESTree.Node} */ (\n node\n );\n if (!nde) {\n return;\n }\n switch (nde.type) {\n case 'ExportNamedDeclaration':\n if (nde.declaration?.type === 'TSTypeAliasDeclaration') {\n checkParameters(nde.declaration);\n }\n break;\n case 'TSTypeAliasDeclaration':\n checkParameters(nde);\n break;\n }\n };\n\n const typedefTags = utils.getTags('typedef');\n if (!typedefTags.length || typedefTags.length >= 2) {\n handleTypeAliases();\n return;\n }\n\n const potentialType = typedefTags[0].type;\n const parsedType = mode === 'permissive' ?\n tryParseType(/** @type {string} */ (potentialType)) :\n parseType(/** @type {string} */ (potentialType), mode)\n\n traverse(parsedType, (nde) => {\n const {\n type,\n value,\n } = /** @type {import('jsdoc-type-pratt-parser').NameResult} */ (nde);\n if (type === 'JsdocTypeName' && (/^[A-Z]$/).test(value)) {\n usedNames.add(value);\n }\n });\n\n // Could check against whitelist/blacklist\n for (const usedName of usedNames) {\n if (!templateNames.includes(usedName)) {\n report(`Missing @template ${usedName}`, null, typedefTags[0]);\n }\n }\n}, {\n iterateAllJsdocs: true,\n meta: {\n docs: {\n description: 'Requires template tags for each generic type parameter',\n url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-template.md#repos-sticky-header',\n },\n schema: [\n {\n additionalProperties: false,\n properties: {\n requireSeparateTemplates: {\n type: 'boolean'\n }\n },\n type: 'object',\n },\n ],\n type: 'suggestion',\n },\n});\n"],"mappings":"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","ignoreList":[]}
|
package/package.json
CHANGED
|
@@ -5,13 +5,13 @@
|
|
|
5
5
|
"url": "http://gajus.com"
|
|
6
6
|
},
|
|
7
7
|
"dependencies": {
|
|
8
|
-
"@es-joy/jsdoccomment": "~0.
|
|
8
|
+
"@es-joy/jsdoccomment": "~0.46.0",
|
|
9
9
|
"are-docs-informative": "^0.0.2",
|
|
10
10
|
"comment-parser": "1.4.1",
|
|
11
11
|
"debug": "^4.3.5",
|
|
12
12
|
"escape-string-regexp": "^4.0.0",
|
|
13
|
-
"esquery": "^1.
|
|
14
|
-
"parse-imports": "^2.1.
|
|
13
|
+
"esquery": "^1.6.0",
|
|
14
|
+
"parse-imports": "^2.1.1",
|
|
15
15
|
"semver": "^7.6.2",
|
|
16
16
|
"spdx-expression-parse": "^4.0.0",
|
|
17
17
|
"synckit": "^0.9.0"
|
|
@@ -29,7 +29,7 @@
|
|
|
29
29
|
"@es-joy/jsdoc-eslint-parser": "^0.21.1",
|
|
30
30
|
"@hkdobrev/run-if-changed": "^0.3.1",
|
|
31
31
|
"@semantic-release/commit-analyzer": "^13.0.0",
|
|
32
|
-
"@semantic-release/github": "^10.0
|
|
32
|
+
"@semantic-release/github": "^10.1.0",
|
|
33
33
|
"@semantic-release/npm": "^12.0.1",
|
|
34
34
|
"@types/chai": "^4.3.16",
|
|
35
35
|
"@types/debug": "^4.1.12",
|
|
@@ -39,35 +39,35 @@
|
|
|
39
39
|
"@types/json-schema": "^7.0.15",
|
|
40
40
|
"@types/lodash.defaultsdeep": "^4.6.9",
|
|
41
41
|
"@types/mocha": "^10.0.7",
|
|
42
|
-
"@types/node": "^20.14.
|
|
42
|
+
"@types/node": "^20.14.10",
|
|
43
43
|
"@types/semver": "^7.5.8",
|
|
44
44
|
"@types/spdx-expression-parse": "^3.0.5",
|
|
45
|
-
"@typescript-eslint/types": "^7.
|
|
45
|
+
"@typescript-eslint/types": "^7.16.0",
|
|
46
46
|
"babel-plugin-add-module-exports": "^1.0.4",
|
|
47
|
-
"babel-plugin-istanbul": "^
|
|
47
|
+
"babel-plugin-istanbul": "^7.0.0",
|
|
48
48
|
"babel-plugin-transform-import-meta": "^2.2.1",
|
|
49
49
|
"c8": "^10.1.2",
|
|
50
|
-
"camelcase": "^
|
|
51
|
-
"chai": "^
|
|
50
|
+
"camelcase": "^8.0.0",
|
|
51
|
+
"chai": "^5.1.1",
|
|
52
52
|
"cross-env": "^7.0.3",
|
|
53
|
-
"decamelize": "^
|
|
54
|
-
"eslint": "9.
|
|
53
|
+
"decamelize": "^6.0.0",
|
|
54
|
+
"eslint": "9.6.0",
|
|
55
55
|
"eslint-config-canonical": "~43.0.13",
|
|
56
56
|
"espree": "^10.1.0",
|
|
57
|
-
"gitdown": "^
|
|
57
|
+
"gitdown": "^4.0.0",
|
|
58
58
|
"glob": "^10.4.2",
|
|
59
|
-
"globals": "^15.
|
|
59
|
+
"globals": "^15.8.0",
|
|
60
60
|
"husky": "^9.0.11",
|
|
61
61
|
"jsdoc-type-pratt-parser": "^4.0.0",
|
|
62
62
|
"json-schema": "^0.4.0",
|
|
63
63
|
"lint-staged": "^15.2.7",
|
|
64
64
|
"lodash.defaultsdeep": "^4.6.1",
|
|
65
|
-
"mocha": "^10.
|
|
66
|
-
"open-editor": "^
|
|
65
|
+
"mocha": "^10.6.0",
|
|
66
|
+
"open-editor": "^4.1.1",
|
|
67
67
|
"replace": "^1.2.2",
|
|
68
68
|
"rimraf": "^5.0.7",
|
|
69
69
|
"semantic-release": "^24.0.0",
|
|
70
|
-
"typescript": "5.
|
|
70
|
+
"typescript": "5.5.x",
|
|
71
71
|
"typescript-eslint": "^8.0.0-alpha.34"
|
|
72
72
|
},
|
|
73
73
|
"engines": {
|
|
@@ -144,5 +144,5 @@
|
|
|
144
144
|
"test-cov": "cross-env TIMING=1 c8 --reporter text npm run test-no-cov",
|
|
145
145
|
"test-index": "npm run test-no-cov -- test/rules/index.js"
|
|
146
146
|
},
|
|
147
|
-
"version": "48.
|
|
147
|
+
"version": "48.7.0"
|
|
148
148
|
}
|
package/src/index.js
CHANGED
|
@@ -9,6 +9,7 @@ import checkSyntax from './rules/checkSyntax.js';
|
|
|
9
9
|
import checkTagNames from './rules/checkTagNames.js';
|
|
10
10
|
import checkTypes from './rules/checkTypes.js';
|
|
11
11
|
import checkValues from './rules/checkValues.js';
|
|
12
|
+
import convertToJsdocComments from './rules/convertToJsdocComments.js';
|
|
12
13
|
import emptyTags from './rules/emptyTags.js';
|
|
13
14
|
import implementsOnClasses from './rules/implementsOnClasses.js';
|
|
14
15
|
import importsAsDependencies from './rules/importsAsDependencies.js';
|
|
@@ -44,6 +45,7 @@ import requireReturns from './rules/requireReturns.js';
|
|
|
44
45
|
import requireReturnsCheck from './rules/requireReturnsCheck.js';
|
|
45
46
|
import requireReturnsDescription from './rules/requireReturnsDescription.js';
|
|
46
47
|
import requireReturnsType from './rules/requireReturnsType.js';
|
|
48
|
+
import requireTemplate from './rules/requireTemplate.js';
|
|
47
49
|
import requireThrows from './rules/requireThrows.js';
|
|
48
50
|
import requireYields from './rules/requireYields.js';
|
|
49
51
|
import requireYieldsCheck from './rules/requireYieldsCheck.js';
|
|
@@ -81,6 +83,7 @@ const index = {
|
|
|
81
83
|
'check-tag-names': checkTagNames,
|
|
82
84
|
'check-types': checkTypes,
|
|
83
85
|
'check-values': checkValues,
|
|
86
|
+
'convert-to-jsdoc-comments': convertToJsdocComments,
|
|
84
87
|
'empty-tags': emptyTags,
|
|
85
88
|
'implements-on-classes': implementsOnClasses,
|
|
86
89
|
'imports-as-dependencies': importsAsDependencies,
|
|
@@ -116,6 +119,7 @@ const index = {
|
|
|
116
119
|
'require-returns-check': requireReturnsCheck,
|
|
117
120
|
'require-returns-description': requireReturnsDescription,
|
|
118
121
|
'require-returns-type': requireReturnsType,
|
|
122
|
+
'require-template': requireTemplate,
|
|
119
123
|
'require-throws': requireThrows,
|
|
120
124
|
'require-yields': requireYields,
|
|
121
125
|
'require-yields-check': requireYieldsCheck,
|
|
@@ -153,6 +157,7 @@ const createRecommendedRuleset = (warnOrError, flatName) => {
|
|
|
153
157
|
'jsdoc/check-tag-names': warnOrError,
|
|
154
158
|
'jsdoc/check-types': warnOrError,
|
|
155
159
|
'jsdoc/check-values': warnOrError,
|
|
160
|
+
'jsdoc/convert-to-jsdoc-comments': 'off',
|
|
156
161
|
'jsdoc/empty-tags': warnOrError,
|
|
157
162
|
'jsdoc/implements-on-classes': warnOrError,
|
|
158
163
|
'jsdoc/imports-as-dependencies': 'off',
|
|
@@ -188,6 +193,7 @@ const createRecommendedRuleset = (warnOrError, flatName) => {
|
|
|
188
193
|
'jsdoc/require-returns-check': warnOrError,
|
|
189
194
|
'jsdoc/require-returns-description': warnOrError,
|
|
190
195
|
'jsdoc/require-returns-type': warnOrError,
|
|
196
|
+
'jsdoc/require-template': 'off',
|
|
191
197
|
'jsdoc/require-throws': 'off',
|
|
192
198
|
'jsdoc/require-yields': warnOrError,
|
|
193
199
|
'jsdoc/require-yields-check': warnOrError,
|
package/src/jsdocUtils.js
CHANGED
|
@@ -1321,7 +1321,7 @@ const parseClosureTemplateTag = (tag) => {
|
|
|
1321
1321
|
* @param {{
|
|
1322
1322
|
* contexts?: import('./iterateJsdoc.js').Context[]
|
|
1323
1323
|
* }} settings
|
|
1324
|
-
* @returns {string[]}
|
|
1324
|
+
* @returns {(string|import('./iterateJsdoc.js').ContextObject)[]}
|
|
1325
1325
|
*/
|
|
1326
1326
|
const enforcedContexts = (context, defaultContexts, settings) => {
|
|
1327
1327
|
const contexts = context.options[0]?.contexts || settings.contexts || (defaultContexts === true ? [
|
|
@@ -0,0 +1,384 @@
|
|
|
1
|
+
import iterateJsdoc from '../iterateJsdoc.js';
|
|
2
|
+
import {
|
|
3
|
+
getSettings,
|
|
4
|
+
} from '../iterateJsdoc.js';
|
|
5
|
+
import jsdocUtils from '../jsdocUtils.js';
|
|
6
|
+
import {
|
|
7
|
+
getNonJsdocComment,
|
|
8
|
+
getDecorator,
|
|
9
|
+
getReducedASTNode,
|
|
10
|
+
getFollowingComment,
|
|
11
|
+
} from '@es-joy/jsdoccomment';
|
|
12
|
+
|
|
13
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
14
|
+
export default {
|
|
15
|
+
create (context) {
|
|
16
|
+
/**
|
|
17
|
+
* @typedef {import('eslint').AST.Token | import('estree').Comment | {
|
|
18
|
+
* type: import('eslint').AST.TokenType|"Line"|"Block"|"Shebang",
|
|
19
|
+
* range: [number, number],
|
|
20
|
+
* value: string
|
|
21
|
+
* }} Token
|
|
22
|
+
*/
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* @callback AddComment
|
|
26
|
+
* @param {boolean|undefined} inlineCommentBlock
|
|
27
|
+
* @param {Token} comment
|
|
28
|
+
* @param {string} indent
|
|
29
|
+
* @param {number} lines
|
|
30
|
+
* @param {import('eslint').Rule.RuleFixer} fixer
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/* c8 ignore next -- Fallback to deprecated method */
|
|
34
|
+
const {
|
|
35
|
+
sourceCode = context.getSourceCode(),
|
|
36
|
+
} = context;
|
|
37
|
+
const settings = getSettings(context);
|
|
38
|
+
if (!settings) {
|
|
39
|
+
return {};
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const {
|
|
43
|
+
contexts = settings.contexts || [],
|
|
44
|
+
contextsAfter = /** @type {string[]} */ ([]),
|
|
45
|
+
contextsBeforeAndAfter = [
|
|
46
|
+
'VariableDeclarator', 'TSPropertySignature', 'PropertyDefinition'
|
|
47
|
+
],
|
|
48
|
+
enableFixer = true,
|
|
49
|
+
enforceJsdocLineStyle = 'multi',
|
|
50
|
+
lineOrBlockStyle = 'both',
|
|
51
|
+
allowedPrefixes = ['@ts-', 'istanbul ', 'c8 ', 'v8 ', 'eslint', 'prettier-']
|
|
52
|
+
} = context.options[0] ?? {};
|
|
53
|
+
|
|
54
|
+
let reportingNonJsdoc = false;
|
|
55
|
+
|
|
56
|
+
/**
|
|
57
|
+
* @param {string} messageId
|
|
58
|
+
* @param {import('estree').Comment|Token} comment
|
|
59
|
+
* @param {import('eslint').Rule.Node} node
|
|
60
|
+
* @param {import('eslint').Rule.ReportFixer} fixer
|
|
61
|
+
*/
|
|
62
|
+
const report = (messageId, comment, node, fixer) => {
|
|
63
|
+
const loc = {
|
|
64
|
+
end: {
|
|
65
|
+
column: 0,
|
|
66
|
+
/* c8 ignore next 2 -- Guard */
|
|
67
|
+
// @ts-expect-error Ok
|
|
68
|
+
line: (comment.loc?.start?.line ?? 1),
|
|
69
|
+
},
|
|
70
|
+
start: {
|
|
71
|
+
column: 0,
|
|
72
|
+
/* c8 ignore next 2 -- Guard */
|
|
73
|
+
// @ts-expect-error Ok
|
|
74
|
+
line: (comment.loc?.start?.line ?? 1)
|
|
75
|
+
},
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
context.report({
|
|
79
|
+
fix: enableFixer ? fixer : null,
|
|
80
|
+
loc,
|
|
81
|
+
messageId,
|
|
82
|
+
node,
|
|
83
|
+
});
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* @param {import('eslint').Rule.Node} node
|
|
88
|
+
* @param {import('eslint').AST.Token | import('estree').Comment | {
|
|
89
|
+
* type: import('eslint').AST.TokenType|"Line"|"Block"|"Shebang",
|
|
90
|
+
* range: [number, number],
|
|
91
|
+
* value: string
|
|
92
|
+
* }} comment
|
|
93
|
+
* @param {AddComment} addComment
|
|
94
|
+
* @param {import('../iterateJsdoc.js').Context[]} ctxts
|
|
95
|
+
*/
|
|
96
|
+
const getFixer = (node, comment, addComment, ctxts) => {
|
|
97
|
+
return /** @type {import('eslint').Rule.ReportFixer} */ (fixer) => {
|
|
98
|
+
// Default to one line break if the `minLines`/`maxLines` settings allow
|
|
99
|
+
const lines = settings.minLines === 0 && settings.maxLines >= 1 ? 1 : settings.minLines;
|
|
100
|
+
let baseNode =
|
|
101
|
+
/**
|
|
102
|
+
* @type {import('@typescript-eslint/types').TSESTree.Node|import('eslint').Rule.Node}
|
|
103
|
+
*/ (
|
|
104
|
+
getReducedASTNode(node, sourceCode)
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
const decorator = getDecorator(
|
|
108
|
+
/** @type {import('eslint').Rule.Node} */
|
|
109
|
+
(baseNode)
|
|
110
|
+
);
|
|
111
|
+
if (decorator) {
|
|
112
|
+
baseNode = /** @type {import('@typescript-eslint/types').TSESTree.Decorator} */ (
|
|
113
|
+
decorator
|
|
114
|
+
);
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const indent = jsdocUtils.getIndent({
|
|
118
|
+
text: sourceCode.getText(
|
|
119
|
+
/** @type {import('eslint').Rule.Node} */ (baseNode),
|
|
120
|
+
/** @type {import('eslint').AST.SourceLocation} */
|
|
121
|
+
(
|
|
122
|
+
/** @type {import('eslint').Rule.Node} */ (baseNode).loc
|
|
123
|
+
).start.column,
|
|
124
|
+
),
|
|
125
|
+
});
|
|
126
|
+
|
|
127
|
+
const {
|
|
128
|
+
inlineCommentBlock,
|
|
129
|
+
} =
|
|
130
|
+
/**
|
|
131
|
+
* @type {{
|
|
132
|
+
* context: string,
|
|
133
|
+
* inlineCommentBlock: boolean,
|
|
134
|
+
* minLineCount: import('../iterateJsdoc.js').Integer
|
|
135
|
+
* }[]}
|
|
136
|
+
*/ (ctxts).find((contxt) => {
|
|
137
|
+
if (typeof contxt === 'string') {
|
|
138
|
+
return false;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
const {
|
|
142
|
+
context: ctxt,
|
|
143
|
+
} = contxt;
|
|
144
|
+
return ctxt === node.type;
|
|
145
|
+
}) || {};
|
|
146
|
+
|
|
147
|
+
return addComment(inlineCommentBlock, comment, indent, lines, fixer);
|
|
148
|
+
};
|
|
149
|
+
};
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* @param {import('eslint').AST.Token | import('estree').Comment | {
|
|
153
|
+
* type: import('eslint').AST.TokenType|"Line"|"Block"|"Shebang",
|
|
154
|
+
* range: [number, number],
|
|
155
|
+
* value: string
|
|
156
|
+
* }} comment
|
|
157
|
+
* @param {import('eslint').Rule.Node} node
|
|
158
|
+
* @param {AddComment} addComment
|
|
159
|
+
* @param {import('../iterateJsdoc.js').Context[]} ctxts
|
|
160
|
+
*/
|
|
161
|
+
const reportings = (comment, node, addComment, ctxts) => {
|
|
162
|
+
const fixer = getFixer(node, comment, addComment, ctxts);
|
|
163
|
+
|
|
164
|
+
if (comment.type === 'Block') {
|
|
165
|
+
if (lineOrBlockStyle === 'line') {
|
|
166
|
+
return;
|
|
167
|
+
}
|
|
168
|
+
report('blockCommentsJsdocStyle', comment, node, fixer);
|
|
169
|
+
return;
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
if (comment.type === 'Line') {
|
|
173
|
+
if (lineOrBlockStyle === 'block') {
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
report('lineCommentsJsdocStyle', comment, node, fixer);
|
|
177
|
+
}
|
|
178
|
+
};
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* @type {import('../iterateJsdoc.js').CheckJsdoc}
|
|
182
|
+
*/
|
|
183
|
+
const checkNonJsdoc = (_info, _handler, node) => {
|
|
184
|
+
const comment = getNonJsdocComment(sourceCode, node, settings);
|
|
185
|
+
|
|
186
|
+
if (
|
|
187
|
+
!comment ||
|
|
188
|
+
/** @type {string[]} */
|
|
189
|
+
(allowedPrefixes).some((prefix) => {
|
|
190
|
+
return comment.value.trimStart().startsWith(prefix);
|
|
191
|
+
})
|
|
192
|
+
) {
|
|
193
|
+
return;
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
reportingNonJsdoc = true;
|
|
197
|
+
|
|
198
|
+
/** @type {AddComment} */
|
|
199
|
+
const addComment = (inlineCommentBlock, comment, indent, lines, fixer) => {
|
|
200
|
+
const insertion = (
|
|
201
|
+
inlineCommentBlock || enforceJsdocLineStyle === 'single'
|
|
202
|
+
? `/** ${comment.value.trim()} `
|
|
203
|
+
: `/**\n${indent}*${comment.value.trimEnd()}\n${indent}`
|
|
204
|
+
) +
|
|
205
|
+
`*/${'\n'.repeat((lines || 1) - 1)}`;
|
|
206
|
+
|
|
207
|
+
return fixer.replaceText(
|
|
208
|
+
/** @type {import('eslint').AST.Token} */
|
|
209
|
+
(comment),
|
|
210
|
+
insertion,
|
|
211
|
+
);
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
reportings(comment, node, addComment, contexts);
|
|
215
|
+
};
|
|
216
|
+
|
|
217
|
+
/**
|
|
218
|
+
* @param {import('eslint').Rule.Node} node
|
|
219
|
+
* @param {import('../iterateJsdoc.js').Context[]} ctxts
|
|
220
|
+
*/
|
|
221
|
+
const checkNonJsdocAfter = (node, ctxts) => {
|
|
222
|
+
const comment = getFollowingComment(sourceCode, node);
|
|
223
|
+
|
|
224
|
+
if (
|
|
225
|
+
!comment ||
|
|
226
|
+
comment.value.startsWith('*') ||
|
|
227
|
+
/** @type {string[]} */
|
|
228
|
+
(allowedPrefixes).some((prefix) => {
|
|
229
|
+
return comment.value.trimStart().startsWith(prefix);
|
|
230
|
+
})
|
|
231
|
+
) {
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** @type {AddComment} */
|
|
236
|
+
const addComment = (inlineCommentBlock, comment, indent, lines, fixer) => {
|
|
237
|
+
const insertion = (
|
|
238
|
+
inlineCommentBlock || enforceJsdocLineStyle === 'single'
|
|
239
|
+
? `/** ${comment.value.trim()} `
|
|
240
|
+
: `/**\n${indent}*${comment.value.trimEnd()}\n${indent}`
|
|
241
|
+
) +
|
|
242
|
+
`*/${'\n'.repeat((lines || 1) - 1)}${lines ? `\n${indent.slice(1)}` : ' '}`;
|
|
243
|
+
|
|
244
|
+
return [fixer.remove(
|
|
245
|
+
/** @type {import('eslint').AST.Token} */
|
|
246
|
+
(comment)
|
|
247
|
+
), fixer.insertTextBefore(
|
|
248
|
+
node.type === 'VariableDeclarator' ? node.parent : node,
|
|
249
|
+
insertion,
|
|
250
|
+
)];
|
|
251
|
+
};
|
|
252
|
+
|
|
253
|
+
reportings(comment, node, addComment, ctxts);
|
|
254
|
+
};
|
|
255
|
+
|
|
256
|
+
// Todo: add contexts to check after (and handle if want both before and after)
|
|
257
|
+
return {
|
|
258
|
+
...jsdocUtils.getContextObject(
|
|
259
|
+
jsdocUtils.enforcedContexts(context, true, settings),
|
|
260
|
+
checkNonJsdoc,
|
|
261
|
+
),
|
|
262
|
+
...jsdocUtils.getContextObject(
|
|
263
|
+
contextsAfter,
|
|
264
|
+
(_info, _handler, node) => {
|
|
265
|
+
checkNonJsdocAfter(node, contextsAfter);
|
|
266
|
+
},
|
|
267
|
+
),
|
|
268
|
+
...jsdocUtils.getContextObject(
|
|
269
|
+
contextsBeforeAndAfter,
|
|
270
|
+
(_info, _handler, node) => {
|
|
271
|
+
checkNonJsdoc({}, null, node);
|
|
272
|
+
if (!reportingNonJsdoc) {
|
|
273
|
+
checkNonJsdocAfter(node, contextsBeforeAndAfter);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
)
|
|
277
|
+
};
|
|
278
|
+
},
|
|
279
|
+
meta: {
|
|
280
|
+
fixable: 'code',
|
|
281
|
+
|
|
282
|
+
messages: {
|
|
283
|
+
blockCommentsJsdocStyle: 'Block comments should be JSDoc-style.',
|
|
284
|
+
lineCommentsJsdocStyle: 'Line comments should be JSDoc-style.',
|
|
285
|
+
},
|
|
286
|
+
|
|
287
|
+
docs: {
|
|
288
|
+
description: 'Converts non-JSDoc comments preceding or following nodes into JSDoc ones',
|
|
289
|
+
url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/convert-to-jsdoc-comments.md#repos-sticky-header',
|
|
290
|
+
},
|
|
291
|
+
schema: [
|
|
292
|
+
{
|
|
293
|
+
additionalProperties: false,
|
|
294
|
+
properties: {
|
|
295
|
+
allowedPrefixes: {
|
|
296
|
+
type: 'array',
|
|
297
|
+
items: {
|
|
298
|
+
type: 'string'
|
|
299
|
+
}
|
|
300
|
+
},
|
|
301
|
+
contexts: {
|
|
302
|
+
items: {
|
|
303
|
+
anyOf: [
|
|
304
|
+
{
|
|
305
|
+
type: 'string',
|
|
306
|
+
},
|
|
307
|
+
{
|
|
308
|
+
additionalProperties: false,
|
|
309
|
+
properties: {
|
|
310
|
+
context: {
|
|
311
|
+
type: 'string',
|
|
312
|
+
},
|
|
313
|
+
inlineCommentBlock: {
|
|
314
|
+
type: 'boolean',
|
|
315
|
+
},
|
|
316
|
+
},
|
|
317
|
+
type: 'object',
|
|
318
|
+
},
|
|
319
|
+
],
|
|
320
|
+
},
|
|
321
|
+
type: 'array',
|
|
322
|
+
},
|
|
323
|
+
contextsAfter: {
|
|
324
|
+
items: {
|
|
325
|
+
anyOf: [
|
|
326
|
+
{
|
|
327
|
+
type: 'string',
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
additionalProperties: false,
|
|
331
|
+
properties: {
|
|
332
|
+
context: {
|
|
333
|
+
type: 'string',
|
|
334
|
+
},
|
|
335
|
+
inlineCommentBlock: {
|
|
336
|
+
type: 'boolean',
|
|
337
|
+
},
|
|
338
|
+
},
|
|
339
|
+
type: 'object',
|
|
340
|
+
},
|
|
341
|
+
],
|
|
342
|
+
},
|
|
343
|
+
type: 'array',
|
|
344
|
+
},
|
|
345
|
+
contextsBeforeAndAfter: {
|
|
346
|
+
items: {
|
|
347
|
+
anyOf: [
|
|
348
|
+
{
|
|
349
|
+
type: 'string',
|
|
350
|
+
},
|
|
351
|
+
{
|
|
352
|
+
additionalProperties: false,
|
|
353
|
+
properties: {
|
|
354
|
+
context: {
|
|
355
|
+
type: 'string',
|
|
356
|
+
},
|
|
357
|
+
inlineCommentBlock: {
|
|
358
|
+
type: 'boolean',
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
type: 'object',
|
|
362
|
+
},
|
|
363
|
+
],
|
|
364
|
+
},
|
|
365
|
+
type: 'array',
|
|
366
|
+
},
|
|
367
|
+
enableFixer: {
|
|
368
|
+
type: 'boolean'
|
|
369
|
+
},
|
|
370
|
+
enforceJsdocLineStyle: {
|
|
371
|
+
type: 'string',
|
|
372
|
+
enum: ['multi', 'single']
|
|
373
|
+
},
|
|
374
|
+
lineOrBlockStyle: {
|
|
375
|
+
type: 'string',
|
|
376
|
+
enum: ['block', 'line', 'both']
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
type: 'object',
|
|
380
|
+
},
|
|
381
|
+
],
|
|
382
|
+
type: 'suggestion',
|
|
383
|
+
},
|
|
384
|
+
};
|
|
@@ -18,6 +18,11 @@ import {
|
|
|
18
18
|
* }} RequireJsdocOpts
|
|
19
19
|
*/
|
|
20
20
|
|
|
21
|
+
/**
|
|
22
|
+
* @typedef {import('eslint').Rule.Node|
|
|
23
|
+
* import('@typescript-eslint/types').TSESTree.Node} ESLintOrTSNode
|
|
24
|
+
*/
|
|
25
|
+
|
|
21
26
|
/** @type {import('json-schema').JSONSchema4} */
|
|
22
27
|
const OPTIONS_SCHEMA = {
|
|
23
28
|
additionalProperties: false,
|
|
@@ -411,10 +416,13 @@ export default {
|
|
|
411
416
|
const fix = /** @type {import('eslint').Rule.ReportFixer} */ (fixer) => {
|
|
412
417
|
// Default to one line break if the `minLines`/`maxLines` settings allow
|
|
413
418
|
const lines = settings.minLines === 0 && settings.maxLines >= 1 ? 1 : settings.minLines;
|
|
414
|
-
/** @type {
|
|
419
|
+
/** @type {ESLintOrTSNode|import('@typescript-eslint/types').TSESTree.Decorator} */
|
|
415
420
|
let baseNode = getReducedASTNode(node, sourceCode);
|
|
416
421
|
|
|
417
|
-
const decorator = getDecorator(
|
|
422
|
+
const decorator = getDecorator(
|
|
423
|
+
/** @type {import('eslint').Rule.Node} */
|
|
424
|
+
(baseNode)
|
|
425
|
+
);
|
|
418
426
|
if (decorator) {
|
|
419
427
|
baseNode = decorator;
|
|
420
428
|
}
|