eslint-plugin-jsdoc 56.0.0 → 56.0.1

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.
Files changed (73) hide show
  1. package/package.json +4 -4
  2. package/dist/cjs/WarnSettings.js +0 -30
  3. package/dist/cjs/alignTransform.js +0 -285
  4. package/dist/cjs/defaultTagOrder.js +0 -152
  5. package/dist/cjs/exportParser.js +0 -754
  6. package/dist/cjs/getDefaultTagStructureForMode.js +0 -840
  7. package/dist/cjs/getJsdocProcessorPlugin.cjs +0 -4
  8. package/dist/cjs/getJsdocProcessorPlugin.js +0 -553
  9. package/dist/cjs/index-cjs.js +0 -492
  10. package/dist/cjs/index.cjs.cjs +0 -6
  11. package/dist/cjs/iterateJsdoc.cjs +0 -38
  12. package/dist/cjs/iterateJsdoc.js +0 -1981
  13. package/dist/cjs/jsdocUtils.js +0 -1470
  14. package/dist/cjs/rules/checkAccess.js +0 -35
  15. package/dist/cjs/rules/checkAlignment.js +0 -63
  16. package/dist/cjs/rules/checkExamples.js +0 -486
  17. package/dist/cjs/rules/checkIndentation.js +0 -66
  18. package/dist/cjs/rules/checkLineAlignment.js +0 -297
  19. package/dist/cjs/rules/checkParamNames.js +0 -320
  20. package/dist/cjs/rules/checkPropertyNames.js +0 -105
  21. package/dist/cjs/rules/checkSyntax.js +0 -27
  22. package/dist/cjs/rules/checkTagNames.js +0 -252
  23. package/dist/cjs/rules/checkTemplateNames.js +0 -189
  24. package/dist/cjs/rules/checkTypes.js +0 -421
  25. package/dist/cjs/rules/checkValues.js +0 -163
  26. package/dist/cjs/rules/convertToJsdocComments.js +0 -313
  27. package/dist/cjs/rules/emptyTags.js +0 -79
  28. package/dist/cjs/rules/implementsOnClasses.js +0 -63
  29. package/dist/cjs/rules/importsAsDependencies.js +0 -105
  30. package/dist/cjs/rules/informativeDocs.js +0 -153
  31. package/dist/cjs/rules/linesBeforeBlock.js +0 -106
  32. package/dist/cjs/rules/matchDescription.js +0 -240
  33. package/dist/cjs/rules/matchName.js +0 -122
  34. package/dist/cjs/rules/multilineBlocks.js +0 -339
  35. package/dist/cjs/rules/noBadBlocks.js +0 -88
  36. package/dist/cjs/rules/noBlankBlockDescriptions.js +0 -56
  37. package/dist/cjs/rules/noBlankBlocks.js +0 -41
  38. package/dist/cjs/rules/noDefaults.js +0 -84
  39. package/dist/cjs/rules/noMissingSyntax.js +0 -164
  40. package/dist/cjs/rules/noMultiAsterisks.js +0 -83
  41. package/dist/cjs/rules/noRestrictedSyntax.js +0 -75
  42. package/dist/cjs/rules/noTypes.js +0 -88
  43. package/dist/cjs/rules/noUndefinedTypes.js +0 -451
  44. package/dist/cjs/rules/requireAsteriskPrefix.js +0 -144
  45. package/dist/cjs/rules/requireDescription.js +0 -136
  46. package/dist/cjs/rules/requireDescriptionCompleteSentence.js +0 -258
  47. package/dist/cjs/rules/requireExample.js +0 -103
  48. package/dist/cjs/rules/requireFileOverview.js +0 -117
  49. package/dist/cjs/rules/requireHyphenBeforeParamDescription.js +0 -144
  50. package/dist/cjs/rules/requireJsdoc.js +0 -629
  51. package/dist/cjs/rules/requireParam.js +0 -480
  52. package/dist/cjs/rules/requireParamDescription.js +0 -77
  53. package/dist/cjs/rules/requireParamName.js +0 -52
  54. package/dist/cjs/rules/requireParamType.js +0 -77
  55. package/dist/cjs/rules/requireProperty.js +0 -44
  56. package/dist/cjs/rules/requirePropertyDescription.js +0 -22
  57. package/dist/cjs/rules/requirePropertyName.js +0 -22
  58. package/dist/cjs/rules/requirePropertyType.js +0 -22
  59. package/dist/cjs/rules/requireReturns.js +0 -197
  60. package/dist/cjs/rules/requireReturnsCheck.js +0 -108
  61. package/dist/cjs/rules/requireReturnsDescription.js +0 -58
  62. package/dist/cjs/rules/requireReturnsType.js +0 -52
  63. package/dist/cjs/rules/requireTemplate.js +0 -173
  64. package/dist/cjs/rules/requireThrows.js +0 -101
  65. package/dist/cjs/rules/requireYields.js +0 -172
  66. package/dist/cjs/rules/requireYieldsCheck.js +0 -164
  67. package/dist/cjs/rules/sortTags.js +0 -392
  68. package/dist/cjs/rules/tagLines.js +0 -259
  69. package/dist/cjs/rules/textEscaping.js +0 -125
  70. package/dist/cjs/rules/typeFormatting.js +0 -328
  71. package/dist/cjs/rules/validTypes.js +0 -333
  72. package/dist/cjs/tagNames.js +0 -209
  73. package/dist/cjs/utils/hasReturnValue.js +0 -469
@@ -1,136 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const iterateJsdoc_js_1 = __importDefault(require("../iterateJsdoc.js"));
7
- /**
8
- * @param {string} description
9
- * @returns {import('../iterateJsdoc.js').Integer}
10
- */
11
- const checkDescription = (description) => {
12
- return description
13
- .trim()
14
- .split('\n')
15
- .filter(Boolean)
16
- .length;
17
- };
18
- exports.default = (0, iterateJsdoc_js_1.default)(({ context, jsdoc, report, utils, }) => {
19
- if (utils.avoidDocs()) {
20
- return;
21
- }
22
- const { descriptionStyle = 'body', } = context.options[0] || {};
23
- let targetTagName = utils.getPreferredTagName({
24
- // We skip reporting except when `@description` is essential to the rule,
25
- // so user can block the tag and still meaningfully use this rule
26
- // even if the tag is present (and `check-tag-names` is the one to
27
- // normally report the fact that it is blocked but present)
28
- skipReportingBlockedTag: descriptionStyle !== 'tag',
29
- tagName: 'description',
30
- });
31
- if (!targetTagName) {
32
- return;
33
- }
34
- const isBlocked = typeof targetTagName === 'object' && 'blocked' in targetTagName && targetTagName.blocked;
35
- if (isBlocked) {
36
- targetTagName = /** @type {{blocked: true; tagName: string;}} */ (targetTagName).tagName;
37
- }
38
- if (descriptionStyle !== 'tag') {
39
- const { description, } = utils.getDescription();
40
- if (checkDescription(description || '')) {
41
- return;
42
- }
43
- if (descriptionStyle === 'body') {
44
- const descTags = utils.getPresentTags([
45
- 'desc', 'description',
46
- ]);
47
- if (descTags.length) {
48
- const [{ tag: tagName, },] = descTags;
49
- report(`Remove the @${tagName} tag to leave a plain block description or add additional description text above the @${tagName} line.`);
50
- }
51
- else {
52
- report('Missing JSDoc block description.');
53
- }
54
- return;
55
- }
56
- }
57
- const functionExamples = isBlocked ?
58
- [] :
59
- jsdoc.tags.filter(({ tag, }) => {
60
- return tag === targetTagName;
61
- });
62
- if (!functionExamples.length) {
63
- report(descriptionStyle === 'any' ?
64
- `Missing JSDoc block description or @${targetTagName} declaration.` :
65
- `Missing JSDoc @${targetTagName} declaration.`);
66
- return;
67
- }
68
- for (const example of functionExamples) {
69
- if (!checkDescription(`${example.name} ${utils.getTagDescription(example)}`)) {
70
- report(`Missing JSDoc @${targetTagName} description.`, null, example);
71
- }
72
- }
73
- }, {
74
- contextDefaults: true,
75
- meta: {
76
- docs: {
77
- description: 'Requires that all functions have a description.',
78
- url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-description.md#repos-sticky-header',
79
- },
80
- schema: [
81
- {
82
- additionalProperties: false,
83
- properties: {
84
- checkConstructors: {
85
- default: true,
86
- type: 'boolean',
87
- },
88
- checkGetters: {
89
- default: true,
90
- type: 'boolean',
91
- },
92
- checkSetters: {
93
- default: true,
94
- type: 'boolean',
95
- },
96
- contexts: {
97
- items: {
98
- anyOf: [
99
- {
100
- type: 'string',
101
- },
102
- {
103
- additionalProperties: false,
104
- properties: {
105
- comment: {
106
- type: 'string',
107
- },
108
- context: {
109
- type: 'string',
110
- },
111
- },
112
- type: 'object',
113
- },
114
- ],
115
- },
116
- type: 'array',
117
- },
118
- descriptionStyle: {
119
- enum: [
120
- 'body', 'tag', 'any',
121
- ],
122
- type: 'string',
123
- },
124
- exemptedBy: {
125
- items: {
126
- type: 'string',
127
- },
128
- type: 'array',
129
- },
130
- },
131
- type: 'object',
132
- },
133
- ],
134
- type: 'suggestion',
135
- },
136
- });
@@ -1,258 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const iterateJsdoc_js_1 = __importDefault(require("../iterateJsdoc.js"));
7
- const escape_string_regexp_1 = __importDefault(require("escape-string-regexp"));
8
- const otherDescriptiveTags = new Set([
9
- 'classdesc', 'deprecated', 'exception', 'file', 'fileoverview', 'overview',
10
- // 'copyright' and 'see' might be good addition, but as the former may be
11
- // sensitive text, and the latter may have just a link, they are not
12
- // included by default
13
- 'summary', 'throws', 'todo', 'yield', 'yields',
14
- ]);
15
- /**
16
- * @param {string} text
17
- * @returns {string[]}
18
- */
19
- const extractParagraphs = (text) => {
20
- return text.split(/(?<![;:])\n\n+/v);
21
- };
22
- /**
23
- * @param {string} text
24
- * @param {string|RegExp} abbreviationsRegex
25
- * @returns {string[]}
26
- */
27
- const extractSentences = (text, abbreviationsRegex) => {
28
- const txt = text
29
- // Remove all {} tags.
30
- .replaceAll(/(?<!^)\{[\s\S]*?\}\s*/gv, '')
31
- // Remove custom abbreviations
32
- .replace(abbreviationsRegex, '');
33
- const sentenceEndGrouping = /([.?!])(?:\s+|$)/gv;
34
- const puncts = [
35
- ...txt.matchAll(sentenceEndGrouping),
36
- ].map((sentEnd) => {
37
- return sentEnd[0];
38
- });
39
- return txt
40
- .split(/[.?!](?:\s+|$)/v)
41
- // Re-add the dot.
42
- .map((sentence, idx) => {
43
- return !puncts[idx] && /^\s*$/v.test(sentence) ? sentence : `${sentence}${puncts[idx] || ''}`;
44
- });
45
- };
46
- /**
47
- * @param {string} text
48
- * @returns {boolean}
49
- */
50
- const isNewLinePrecededByAPeriod = (text) => {
51
- /** @type {boolean} */
52
- let lastLineEndsSentence;
53
- const lines = text.split('\n');
54
- return !lines.some((line) => {
55
- if (lastLineEndsSentence === false && /^[A-Z][a-z]/v.test(line)) {
56
- return true;
57
- }
58
- lastLineEndsSentence = /[.:?!\|]$/v.test(line);
59
- return false;
60
- });
61
- };
62
- /**
63
- * @param {string} str
64
- * @returns {boolean}
65
- */
66
- const isCapitalized = (str) => {
67
- return str[0] === str[0].toUpperCase();
68
- };
69
- /**
70
- * @param {string} str
71
- * @returns {boolean}
72
- */
73
- const isTable = (str) => {
74
- return str.charAt(0) === '|';
75
- };
76
- /**
77
- * @param {string} str
78
- * @returns {string}
79
- */
80
- const capitalize = (str) => {
81
- return str.charAt(0).toUpperCase() + str.slice(1);
82
- };
83
- /**
84
- * @param {string} description
85
- * @param {import('../iterateJsdoc.js').Report} reportOrig
86
- * @param {import('eslint').Rule.Node} jsdocNode
87
- * @param {string|RegExp} abbreviationsRegex
88
- * @param {import('eslint').SourceCode} sourceCode
89
- * @param {import('comment-parser').Spec|{
90
- * line: import('../iterateJsdoc.js').Integer
91
- * }} tag
92
- * @param {boolean} newlineBeforeCapsAssumesBadSentenceEnd
93
- * @returns {boolean}
94
- */
95
- const validateDescription = (description, reportOrig, jsdocNode, abbreviationsRegex, sourceCode, tag, newlineBeforeCapsAssumesBadSentenceEnd) => {
96
- if (!description || (/^\n+$/v).test(description)) {
97
- return false;
98
- }
99
- const descriptionNoHeadings = description.replaceAll(/^\s*#[^\n]*(\n|$)/gmv, '');
100
- const paragraphs = extractParagraphs(descriptionNoHeadings).filter(Boolean);
101
- return paragraphs.some((paragraph, parIdx) => {
102
- const sentences = extractSentences(paragraph, abbreviationsRegex);
103
- const fix = /** @type {import('eslint').Rule.ReportFixer} */ (fixer) => {
104
- let text = sourceCode.getText(jsdocNode);
105
- if (!/[.:?!]$/v.test(paragraph)) {
106
- const line = paragraph.split('\n').findLast(Boolean);
107
- text = text.replace(new RegExp(`${(0, escape_string_regexp_1.default)(
108
- /** @type {string} */
109
- (line))}$`, 'mv'), `${line}.`);
110
- }
111
- for (const sentence of sentences.filter((sentence_) => {
112
- return !(/^\s*$/v).test(sentence_) && !isCapitalized(sentence_) &&
113
- !isTable(sentence_);
114
- })) {
115
- const beginning = sentence.split('\n')[0];
116
- if ('tag' in tag && tag.tag) {
117
- const reg = new RegExp(`(@${(0, escape_string_regexp_1.default)(tag.tag)}.*)${(0, escape_string_regexp_1.default)(beginning)}`, 'v');
118
- text = text.replace(reg, (_$0, $1) => {
119
- return $1 + capitalize(beginning);
120
- });
121
- }
122
- else {
123
- text = text.replace(new RegExp('((?:[.?!]|\\*|\\})\\s*)' + (0, escape_string_regexp_1.default)(beginning), 'v'), '$1' + capitalize(beginning));
124
- }
125
- }
126
- return fixer.replaceText(jsdocNode, text);
127
- };
128
- /**
129
- * @param {string} msg
130
- * @param {import('eslint').Rule.ReportFixer | null | undefined} fixer
131
- * @param {{
132
- * line?: number | undefined;
133
- * column?: number | undefined;
134
- * } | (import('comment-parser').Spec & {
135
- * line?: number | undefined;
136
- * column?: number | undefined;
137
- * })} tagObj
138
- * @returns {void}
139
- */
140
- const report = (msg, fixer, tagObj) => {
141
- if ('line' in tagObj) {
142
- /**
143
- * @type {{
144
- * line: number;
145
- * }}
146
- */ (tagObj).line += parIdx * 2;
147
- }
148
- else {
149
- /** @type {import('comment-parser').Spec} */ (tagObj).source[0].number += parIdx * 2;
150
- }
151
- // Avoid errors if old column doesn't exist here
152
- tagObj.column = 0;
153
- reportOrig(msg, fixer, tagObj);
154
- };
155
- if (sentences.some((sentence) => {
156
- return (/^[.?!]$/v).test(sentence);
157
- })) {
158
- report('Sentences must be more than punctuation.', null, tag);
159
- }
160
- if (sentences.some((sentence) => {
161
- return !(/^\s*$/v).test(sentence) && !isCapitalized(sentence) && !isTable(sentence);
162
- })) {
163
- report('Sentences should start with an uppercase character.', fix, tag);
164
- }
165
- const paragraphNoAbbreviations = paragraph.replace(abbreviationsRegex, '');
166
- if (!/(?:[.?!\|]|```)\s*$/v.test(paragraphNoAbbreviations)) {
167
- report('Sentences must end with a period.', fix, tag);
168
- return true;
169
- }
170
- if (newlineBeforeCapsAssumesBadSentenceEnd && !isNewLinePrecededByAPeriod(paragraphNoAbbreviations)) {
171
- report('A line of text is started with an uppercase character, but the preceding line does not end the sentence.', null, tag);
172
- return true;
173
- }
174
- return false;
175
- });
176
- };
177
- exports.default = (0, iterateJsdoc_js_1.default)(({ context, jsdoc, jsdocNode, report, sourceCode, utils, }) => {
178
- const /** @type {{abbreviations: string[], newlineBeforeCapsAssumesBadSentenceEnd: boolean}} */ { abbreviations = [], newlineBeforeCapsAssumesBadSentenceEnd = false, } = context.options[0] || {};
179
- const abbreviationsRegex = abbreviations.length ?
180
- new RegExp('\\b' + abbreviations.map((abbreviation) => {
181
- return (0, escape_string_regexp_1.default)(abbreviation.replaceAll(/\.$/gv, '') + '.');
182
- }).join('|') + '(?:$|\\s)', 'gv') :
183
- '';
184
- let { description, } = utils.getDescription();
185
- const indices = [
186
- ...description.matchAll(/```[\s\S]*```/gv),
187
- ].map((match) => {
188
- const { index, } = match;
189
- const [{ length, },] = match;
190
- return {
191
- index,
192
- length,
193
- };
194
- }).toReversed();
195
- for (const { index, length, } of indices) {
196
- description = description.slice(0, index) +
197
- description.slice(/** @type {import('../iterateJsdoc.js').Integer} */ (index) + length);
198
- }
199
- if (validateDescription(description, report, jsdocNode, abbreviationsRegex, sourceCode, {
200
- line: jsdoc.source[0].number + 1,
201
- }, newlineBeforeCapsAssumesBadSentenceEnd)) {
202
- return;
203
- }
204
- utils.forEachPreferredTag('description', (matchingJsdocTag) => {
205
- const desc = `${matchingJsdocTag.name} ${utils.getTagDescription(matchingJsdocTag)}`.trim();
206
- validateDescription(desc, report, jsdocNode, abbreviationsRegex, sourceCode, matchingJsdocTag, newlineBeforeCapsAssumesBadSentenceEnd);
207
- }, true);
208
- const { tagsWithNames, } = utils.getTagsByType(jsdoc.tags);
209
- const tagsWithoutNames = utils.filterTags(({ tag: tagName, }) => {
210
- return otherDescriptiveTags.has(tagName) ||
211
- utils.hasOptionTag(tagName) && !tagsWithNames.some(({ tag, }) => {
212
- // If user accidentally adds tags with names (or like `returns`
213
- // get parsed as having names), do not add to this list
214
- return tag === tagName;
215
- });
216
- });
217
- tagsWithNames.some((tag) => {
218
- const desc = /** @type {string} */ (utils.getTagDescription(tag)).replace(/^- /v, '').trimEnd();
219
- return validateDescription(desc, report, jsdocNode, abbreviationsRegex, sourceCode, tag, newlineBeforeCapsAssumesBadSentenceEnd);
220
- });
221
- tagsWithoutNames.some((tag) => {
222
- const desc = `${tag.name} ${utils.getTagDescription(tag)}`.trim();
223
- return validateDescription(desc, report, jsdocNode, abbreviationsRegex, sourceCode, tag, newlineBeforeCapsAssumesBadSentenceEnd);
224
- });
225
- }, {
226
- iterateAllJsdocs: true,
227
- meta: {
228
- docs: {
229
- description: 'Requires that block description, explicit `@description`, and `@param`/`@returns` tag descriptions are written in complete sentences.',
230
- url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-description-complete-sentence.md#repos-sticky-header',
231
- },
232
- fixable: 'code',
233
- schema: [
234
- {
235
- additionalProperties: false,
236
- properties: {
237
- abbreviations: {
238
- items: {
239
- type: 'string',
240
- },
241
- type: 'array',
242
- },
243
- newlineBeforeCapsAssumesBadSentenceEnd: {
244
- type: 'boolean',
245
- },
246
- tags: {
247
- items: {
248
- type: 'string',
249
- },
250
- type: 'array',
251
- },
252
- },
253
- type: 'object',
254
- },
255
- ],
256
- type: 'suggestion',
257
- },
258
- });
@@ -1,103 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const iterateJsdoc_js_1 = __importDefault(require("../iterateJsdoc.js"));
7
- exports.default = (0, iterateJsdoc_js_1.default)(({ context, jsdoc, report, utils, }) => {
8
- if (utils.avoidDocs()) {
9
- return;
10
- }
11
- const { enableFixer = true, exemptNoArguments = false, } = context.options[0] || {};
12
- const targetTagName = 'example';
13
- const functionExamples = jsdoc.tags.filter(({ tag, }) => {
14
- return tag === targetTagName;
15
- });
16
- if (!functionExamples.length) {
17
- if (exemptNoArguments && utils.isIteratingFunctionOrVariable() &&
18
- !utils.hasParams()) {
19
- return;
20
- }
21
- utils.reportJSDoc(`Missing JSDoc @${targetTagName} declaration.`, null, () => {
22
- if (enableFixer) {
23
- utils.addTag(targetTagName);
24
- }
25
- });
26
- return;
27
- }
28
- for (const example of functionExamples) {
29
- const exampleContent = `${example.name} ${utils.getTagDescription(example)}`
30
- .trim()
31
- .split('\n')
32
- .filter(Boolean);
33
- if (!exampleContent.length) {
34
- report(`Missing JSDoc @${targetTagName} description.`, null, example);
35
- }
36
- }
37
- }, {
38
- contextDefaults: true,
39
- meta: {
40
- docs: {
41
- description: 'Requires that all functions have examples.',
42
- url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-example.md#repos-sticky-header',
43
- },
44
- fixable: 'code',
45
- schema: [
46
- {
47
- additionalProperties: false,
48
- properties: {
49
- checkConstructors: {
50
- default: true,
51
- type: 'boolean',
52
- },
53
- checkGetters: {
54
- default: false,
55
- type: 'boolean',
56
- },
57
- checkSetters: {
58
- default: false,
59
- type: 'boolean',
60
- },
61
- contexts: {
62
- items: {
63
- anyOf: [
64
- {
65
- type: 'string',
66
- },
67
- {
68
- additionalProperties: false,
69
- properties: {
70
- comment: {
71
- type: 'string',
72
- },
73
- context: {
74
- type: 'string',
75
- },
76
- },
77
- type: 'object',
78
- },
79
- ],
80
- },
81
- type: 'array',
82
- },
83
- enableFixer: {
84
- default: true,
85
- type: 'boolean',
86
- },
87
- exemptedBy: {
88
- items: {
89
- type: 'string',
90
- },
91
- type: 'array',
92
- },
93
- exemptNoArguments: {
94
- default: false,
95
- type: 'boolean',
96
- },
97
- },
98
- type: 'object',
99
- },
100
- ],
101
- type: 'suggestion',
102
- },
103
- });
@@ -1,117 +0,0 @@
1
- "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
- Object.defineProperty(exports, "__esModule", { value: true });
6
- const iterateJsdoc_js_1 = __importDefault(require("../iterateJsdoc.js"));
7
- const defaultTags = {
8
- file: {
9
- initialCommentsOnly: true,
10
- mustExist: true,
11
- preventDuplicates: true,
12
- },
13
- };
14
- /**
15
- * @param {import('../iterateJsdoc.js').StateObject} state
16
- * @returns {void}
17
- */
18
- const setDefaults = (state) => {
19
- // First iteration
20
- if (!state.globalTags) {
21
- state.globalTags = {};
22
- state.hasDuplicates = {};
23
- state.hasTag = {};
24
- state.hasNonCommentBeforeTag = {};
25
- }
26
- };
27
- exports.default = (0, iterateJsdoc_js_1.default)(({ context, jsdocNode, state, utils, }) => {
28
- const { tags = defaultTags, } = context.options[0] || {};
29
- setDefaults(state);
30
- for (const tagName of Object.keys(tags)) {
31
- const targetTagName = /** @type {string} */ (utils.getPreferredTagName({
32
- tagName,
33
- }));
34
- const hasTag = Boolean(targetTagName && utils.hasTag(targetTagName));
35
- state.hasTag[tagName] = hasTag || state.hasTag[tagName];
36
- const hasDuplicate = state.hasDuplicates[tagName];
37
- if (hasDuplicate === false) {
38
- // Was marked before, so if a tag now, is a dupe
39
- state.hasDuplicates[tagName] = hasTag;
40
- }
41
- else if (!hasDuplicate && hasTag) {
42
- // No dupes set before, but has first tag, so change state
43
- // from `undefined` to `false` so can detect next time
44
- state.hasDuplicates[tagName] = false;
45
- state.hasNonCommentBeforeTag[tagName] = state.hasNonComment &&
46
- state.hasNonComment < jsdocNode.range[0];
47
- }
48
- }
49
- }, {
50
- exit({ context, state, utils, }) {
51
- setDefaults(state);
52
- const { tags = defaultTags, } = context.options[0] || {};
53
- for (const [tagName, { initialCommentsOnly = false, mustExist = false, preventDuplicates = false, },] of Object.entries(tags)) {
54
- const obj = utils.getPreferredTagNameObject({
55
- tagName,
56
- });
57
- if (obj && typeof obj === 'object' && 'blocked' in obj) {
58
- utils.reportSettings(`\`settings.jsdoc.tagNamePreference\` cannot block @${obj.tagName} ` +
59
- 'for the `require-file-overview` rule');
60
- }
61
- else {
62
- const targetTagName = (obj && typeof obj === 'object' && obj.replacement) || obj;
63
- if (mustExist && !state.hasTag[tagName]) {
64
- utils.reportSettings(`Missing @${targetTagName}`);
65
- }
66
- if (preventDuplicates && state.hasDuplicates[tagName]) {
67
- utils.reportSettings(`Duplicate @${targetTagName}`);
68
- }
69
- if (initialCommentsOnly &&
70
- state.hasNonCommentBeforeTag[tagName]) {
71
- utils.reportSettings(`@${targetTagName} should be at the beginning of the file`);
72
- }
73
- }
74
- }
75
- },
76
- iterateAllJsdocs: true,
77
- meta: {
78
- docs: {
79
- description: 'Checks that all files have one `@file`, `@fileoverview`, or `@overview` tag at the beginning of the file.',
80
- url: 'https://github.com/gajus/eslint-plugin-jsdoc/blob/main/docs/rules/require-file-overview.md#repos-sticky-header',
81
- },
82
- schema: [
83
- {
84
- additionalProperties: false,
85
- properties: {
86
- tags: {
87
- patternProperties: {
88
- '.*': {
89
- additionalProperties: false,
90
- properties: {
91
- initialCommentsOnly: {
92
- type: 'boolean',
93
- },
94
- mustExist: {
95
- type: 'boolean',
96
- },
97
- preventDuplicates: {
98
- type: 'boolean',
99
- },
100
- },
101
- type: 'object',
102
- },
103
- },
104
- type: 'object',
105
- },
106
- },
107
- type: 'object',
108
- },
109
- ],
110
- type: 'suggestion',
111
- },
112
- nonComment({ node, state, }) {
113
- if (!state.hasNonComment) {
114
- state.hasNonComment = node.range[0];
115
- }
116
- },
117
- });