@tony.ganchev/eslint-plugin-header 3.1.11 → 3.1.13
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 +21 -5
- package/index.d.ts +29 -0
- package/index.js +7 -5
- package/lib/comment-parser.js +1 -1
- package/lib/rules/eslint-utils.js +42 -0
- package/lib/rules/header.docs.js +2 -2
- package/lib/rules/header.js +205 -110
- package/lib/rules/header.schema.js +1 -0
- package/package.json +30 -14
- package/types/index.d.ts +4 -0
- package/types/index.d.ts.map +1 -0
- package/types/lib/comment-parser.d.ts +3 -0
- package/types/lib/comment-parser.d.ts.map +1 -0
- package/types/lib/rules/eslint-utils.d.ts +10 -0
- package/types/lib/rules/eslint-utils.d.ts.map +1 -0
- package/types/lib/rules/header.d.ts +73 -0
- package/types/lib/rules/header.d.ts.map +1 -0
- package/types/lib/rules/header.docs.d.ts +4 -0
- package/types/lib/rules/header.docs.d.ts.map +1 -0
- package/types/lib/rules/header.schema.d.ts +20 -0
- package/types/lib/rules/header.schema.d.ts.map +1 -0
- package/types/lib/rules/test-utils.d.ts +10 -0
- package/types/lib/rules/test-utils.d.ts.map +1 -0
package/README.md
CHANGED
|
@@ -10,17 +10,18 @@ defined in the rule settings.
|
|
|
10
10
|
## Table of Contents
|
|
11
11
|
|
|
12
12
|
1. [Scope and Acknowledgements](#scope-and-acknowledgements)
|
|
13
|
-
2. [
|
|
13
|
+
2. [Compatibility](#compatibility)
|
|
14
|
+
3. [Usage](#usage)
|
|
14
15
|
1. [File-based Configuration](#file-based-configuration)
|
|
15
16
|
2. [Inline Configuration](#inline-configuration)
|
|
16
17
|
1. [Header Contents Configuration](#header-contents-configuration)
|
|
17
18
|
2. [Trailing Empty Lines Configuration](#trailing-empty-lines-configuration)
|
|
18
19
|
3. [Line Endings](#line-endings)
|
|
19
|
-
|
|
20
|
-
|
|
20
|
+
4. [Examples](#examples)
|
|
21
|
+
5. [Versioning](#versioning)
|
|
21
22
|
1. [What is a Feature?](#what-is-a-feature)
|
|
22
23
|
2. [What is Backward-compatibility?](#what-is-backward-compatibility)
|
|
23
|
-
|
|
24
|
+
6. [License](#license)
|
|
24
25
|
|
|
25
26
|
## Scope and Acknowledgements
|
|
26
27
|
|
|
@@ -39,6 +40,15 @@ It addresses the following issus:
|
|
|
39
40
|
forward. This would come at the expense of plugin compatibility and the
|
|
40
41
|
portability of fixes to the upstream repository.
|
|
41
42
|
|
|
43
|
+
## Compatibility
|
|
44
|
+
|
|
45
|
+
The plugin supports ESLint 7 / 8 / 9 / 10rc0 (check package.json for details).
|
|
46
|
+
Both flat config and legacy, hierarchical config can be used.
|
|
47
|
+
|
|
48
|
+
The NPM package provides TypeScript type definitions and can be used with
|
|
49
|
+
TypeScript-based ESLint flat configuration without the need for `@ts-ignore`
|
|
50
|
+
statements.
|
|
51
|
+
|
|
42
52
|
## Usage
|
|
43
53
|
|
|
44
54
|
This rule takes between 1 and 4 arguments after the rule validation severity.
|
|
@@ -61,6 +71,12 @@ The configuration can take any of the following forms:
|
|
|
61
71
|
{<settings>}]` - define the header contents inline and an expected number of
|
|
62
72
|
empty lines after the header and pass additional settings.
|
|
63
73
|
|
|
74
|
+
For TypesScript-based flat ESLint configuration, the following type is provided:
|
|
75
|
+
|
|
76
|
+
- `HeaderRuleConfig` defines the overall rule configuration for the `header`
|
|
77
|
+
rule and includes severity level and supports both the modern object-based
|
|
78
|
+
configuration and the legacy array-based configuration.
|
|
79
|
+
|
|
64
80
|
### File-based Configuration
|
|
65
81
|
|
|
66
82
|
In this configuration mode, the first argument is a string pointing to a JS
|
|
@@ -440,7 +456,7 @@ The following guidelines apply:
|
|
|
440
456
|
- **major versions** - new functionality that breaks compatibility.
|
|
441
457
|
- **minor versions** - new features that do not break compatibility. For the
|
|
442
458
|
most part we would aim to continue releasing new versions in the 3.x product
|
|
443
|
-
line and have opt-in flags for changes in behavior of
|
|
459
|
+
line and have opt-in flags for changes in behavior of existing features.
|
|
444
460
|
- **revisions** - bugfixes and minor non-feature improvements that do not break
|
|
445
461
|
compatibility. Note that bug-fixes are allowed to break compatibility with
|
|
446
462
|
previous version if the older version regressed previous expected behavior.
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2026-present Tony Ganchev and contributors
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the “Software”), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
|
14
|
+
* all copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
export { HeaderOptions, HeaderRuleConfig } from "./types/lib/rules/header";
|
|
26
|
+
|
|
27
|
+
import plugin = require("./types");
|
|
28
|
+
|
|
29
|
+
export default plugin;
|
package/index.js
CHANGED
|
@@ -24,11 +24,13 @@
|
|
|
24
24
|
|
|
25
25
|
"use strict";
|
|
26
26
|
|
|
27
|
-
|
|
27
|
+
const { header } = require("./lib/rules/header");
|
|
28
|
+
|
|
29
|
+
/** @type {import('eslint').ESLint.Plugin} */
|
|
30
|
+
const pluginDefinition = {
|
|
28
31
|
rules: {
|
|
29
|
-
|
|
30
|
-
},
|
|
31
|
-
rulesConfig: {
|
|
32
|
-
"header": 0
|
|
32
|
+
header
|
|
33
33
|
}
|
|
34
34
|
};
|
|
35
|
+
|
|
36
|
+
module.exports = pluginDefinition;
|
package/lib/comment-parser.js
CHANGED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* MIT License
|
|
3
|
+
*
|
|
4
|
+
* Copyright (c) 2025-present Tony Ganchev and contributors
|
|
5
|
+
*
|
|
6
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
7
|
+
* of this software and associated documentation files (the “Software”), to deal
|
|
8
|
+
* in the Software without restriction, including without limitation the rights
|
|
9
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
10
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
11
|
+
* furnished to do so, subject to the following conditions:
|
|
12
|
+
*
|
|
13
|
+
* The above copyright notice and this permission notice shall be included in
|
|
14
|
+
* all copies or substantial portions of the Software.
|
|
15
|
+
*
|
|
16
|
+
* THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
17
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
18
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
19
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
20
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
21
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
22
|
+
* SOFTWARE.
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
"use strict";
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* @typedef {import('eslint').Rule.RuleContext} RuleContext
|
|
29
|
+
* @typedef {import('eslint').SourceCode} SourceCode
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
module.exports = {
|
|
33
|
+
/**
|
|
34
|
+
* Provides compatibility wrapper for ESLint 7 through 10 for getting the
|
|
35
|
+
* full source code object from the execution context.
|
|
36
|
+
* @param {RuleContext} context ESLint execution context.
|
|
37
|
+
* @returns {SourceCode} the source-code object.
|
|
38
|
+
*/
|
|
39
|
+
contextSourceCode: function(context) {
|
|
40
|
+
return context.sourceCode || context.getSourceCode();
|
|
41
|
+
}
|
|
42
|
+
};
|
package/lib/rules/header.docs.js
CHANGED
|
@@ -29,11 +29,11 @@ const assert = require("node:assert");
|
|
|
29
29
|
const fs = require("node:fs");
|
|
30
30
|
const path = require("node:path");
|
|
31
31
|
|
|
32
|
-
const packageJsonContent = fs.readFileSync(path.resolve(__dirname, "../../package.json"));
|
|
32
|
+
const packageJsonContent = fs.readFileSync(path.resolve(__dirname, "../../package.json"), "utf8");
|
|
33
33
|
const packageJson = JSON.parse(packageJsonContent);
|
|
34
34
|
assert.equal(Object.prototype.hasOwnProperty.call(packageJson, "version"), true,
|
|
35
35
|
"The plugin's package.json should be available two directories above the rule.");
|
|
36
|
-
const pluginVersion =
|
|
36
|
+
const pluginVersion = packageJson.version;
|
|
37
37
|
|
|
38
38
|
exports.description = "";
|
|
39
39
|
exports.recommended = true;
|
package/lib/rules/header.js
CHANGED
|
@@ -24,10 +24,11 @@
|
|
|
24
24
|
|
|
25
25
|
"use strict";
|
|
26
26
|
|
|
27
|
-
const assert = require("assert");
|
|
28
|
-
const fs = require("fs");
|
|
29
|
-
const os = require("os");
|
|
27
|
+
const assert = require("node:assert");
|
|
28
|
+
const fs = require("node:fs");
|
|
29
|
+
const os = require("node:os");
|
|
30
30
|
const commentParser = require("../comment-parser");
|
|
31
|
+
const { contextSourceCode } = require("./eslint-utils");
|
|
31
32
|
const { description, recommended, url } = require("./header.docs");
|
|
32
33
|
const { commentTypeOptions, lineEndingOptions, schema } = require("./header.schema");
|
|
33
34
|
|
|
@@ -37,8 +38,6 @@ const { commentTypeOptions, lineEndingOptions, schema } = require("./header.sche
|
|
|
37
38
|
* @typedef {import('eslint').Rule.NodeListener} NodeListener
|
|
38
39
|
* @typedef {import('eslint').Rule.ReportFixer} ReportFixer
|
|
39
40
|
* @typedef {import('eslint').Rule.RuleFixer} RuleFixer
|
|
40
|
-
* @typedef {import('eslint').Rule.RuleTextEdit} RuleTextEdit
|
|
41
|
-
* @typedef {import('eslint').Rule.RuleTextEditor} RuleTextEditor
|
|
42
41
|
* @typedef {import('eslint').Rule.RuleContext} RuleContext
|
|
43
42
|
* @typedef {import('estree').Comment} Comment
|
|
44
43
|
* @typedef {import('estree').Program} Program
|
|
@@ -46,26 +45,36 @@ const { commentTypeOptions, lineEndingOptions, schema } = require("./header.sche
|
|
|
46
45
|
*/
|
|
47
46
|
|
|
48
47
|
/**
|
|
49
|
-
* Local type
|
|
50
|
-
* @typedef {
|
|
48
|
+
* Local type definitions.
|
|
49
|
+
* @typedef {{ pattern: string, template?: string }} HeaderLinePattern
|
|
50
|
+
* @typedef {string | HeaderLinePattern} HeaderLine
|
|
51
51
|
* @typedef {(HeaderLine | HeaderLine[])} HeaderLines
|
|
52
|
-
* @typedef {
|
|
53
|
-
* @typedef {
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
*
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
52
|
+
* @typedef {'unix' | 'windows'} LineEndingOption
|
|
53
|
+
* @typedef {{ lineEndings?: LineEndingOption }} HeaderSettings
|
|
54
|
+
* @typedef {'block' | 'line'} CommentType
|
|
55
|
+
* @typedef {[template: string] |
|
|
56
|
+
* [template: string, settings: HeaderSettings] |
|
|
57
|
+
* [type: CommentType, lines: HeaderLines] |
|
|
58
|
+
* [type: CommentType, lines: HeaderLines, settings: HeaderSettings] |
|
|
59
|
+
* [type: CommentType, lines: HeaderLines, minLines: number] |
|
|
60
|
+
* [
|
|
61
|
+
* type: CommentType,
|
|
62
|
+
* lines: HeaderLines,
|
|
63
|
+
* minLines: number,
|
|
64
|
+
* settings: HeaderSettings
|
|
65
|
+
* ]
|
|
66
|
+
* } AllHeaderOptions
|
|
67
|
+
* @typedef {import('eslint').Linter.RuleEntry<AllHeaderOptions>
|
|
68
|
+
* } HeaderRuleConfig
|
|
61
69
|
*/
|
|
62
70
|
|
|
63
71
|
/**
|
|
64
72
|
* Tests if the passed line configuration string or object is a pattern
|
|
65
73
|
* definition.
|
|
66
74
|
* @param {HeaderLine} object line configuration object or string
|
|
67
|
-
* @returns {
|
|
68
|
-
*
|
|
75
|
+
* @returns {object is HeaderLinePattern} `true` if the line configuration is a
|
|
76
|
+
* pattern-defining object or `false`
|
|
77
|
+
* otherwise.
|
|
69
78
|
*/
|
|
70
79
|
function isPattern(object) {
|
|
71
80
|
return typeof object === "object" && Object.prototype.hasOwnProperty.call(object, "pattern");
|
|
@@ -74,13 +83,13 @@ function isPattern(object) {
|
|
|
74
83
|
/**
|
|
75
84
|
* Utility over a line config argument to match an expected string either
|
|
76
85
|
* against a regex or for full match against a string.
|
|
77
|
-
* @param {
|
|
78
|
-
* @param {string} expected The string or regex to test again.
|
|
86
|
+
* @param {string} actual the string to test.
|
|
87
|
+
* @param {string | RegExp} expected The string or regex to test again.
|
|
79
88
|
* @returns {boolean} `true` if the passed string matches the expected line
|
|
80
89
|
* config or `false` otherwise.
|
|
81
90
|
*/
|
|
82
91
|
function match(actual, expected) {
|
|
83
|
-
if (expected
|
|
92
|
+
if (expected instanceof RegExp) {
|
|
84
93
|
return expected.test(actual);
|
|
85
94
|
} else {
|
|
86
95
|
return expected === actual;
|
|
@@ -89,34 +98,62 @@ function match(actual, expected) {
|
|
|
89
98
|
|
|
90
99
|
/**
|
|
91
100
|
* Remove Unix she-bangs from the list of comments.
|
|
92
|
-
* @param {Comment[]} comments the list of comment
|
|
93
|
-
*
|
|
101
|
+
* @param {(Comment | { type: "Shebang" })[]} comments the list of comment
|
|
102
|
+
* lines.
|
|
103
|
+
* @returns {Comment[]} the list of comments with containing all incoming
|
|
94
104
|
* comments from `comments` with the shebang comments
|
|
95
105
|
* omitted.
|
|
96
106
|
*/
|
|
97
107
|
function excludeShebangs(comments) {
|
|
108
|
+
/** @type {Comment[]} */
|
|
98
109
|
return comments.filter(function(comment) {
|
|
99
110
|
return comment.type !== "Shebang";
|
|
100
111
|
});
|
|
101
112
|
}
|
|
102
113
|
|
|
114
|
+
/**
|
|
115
|
+
* TypeScript helper to confirm defined type.
|
|
116
|
+
* @template T
|
|
117
|
+
* @param {T | undefined} val the value to validate.
|
|
118
|
+
* @returns {asserts val is T} validates defined type
|
|
119
|
+
*/
|
|
120
|
+
function assertDefined(val) {
|
|
121
|
+
assert.strict.notEqual(typeof val, "undefined");
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* TypeScript helper to confirm non-null type.
|
|
126
|
+
* @template T
|
|
127
|
+
* @param {T | null} val the value to validate.
|
|
128
|
+
* @returns {asserts val is T} validates non-null type
|
|
129
|
+
*/
|
|
130
|
+
function assertNotNull(val) {
|
|
131
|
+
assert.strict.notEqual(val, null);
|
|
132
|
+
}
|
|
133
|
+
|
|
103
134
|
/**
|
|
104
135
|
* Returns either the first block comment or the first set of line comments that
|
|
105
136
|
* are ONLY separated by a single newline. Note that this does not actually
|
|
106
137
|
* check if they are at the start of the file since that is already checked by
|
|
107
138
|
* `hasHeader()`.
|
|
108
139
|
* @param {RuleContext} context ESLint execution environment.
|
|
109
|
-
* @param {Program} node ESLint AST treee node being processed.
|
|
110
140
|
* @returns {Comment[]} lines that constitute the leading comment.
|
|
111
141
|
*/
|
|
112
|
-
function getLeadingComments(context
|
|
113
|
-
const
|
|
142
|
+
function getLeadingComments(context) {
|
|
143
|
+
const sourceCode = contextSourceCode(context);
|
|
144
|
+
const all = excludeShebangs(sourceCode.getAllComments());
|
|
145
|
+
assert.ok(all);
|
|
146
|
+
assert.ok(all.length);
|
|
114
147
|
if (all[0].type.toLowerCase() === commentTypeOptions.block) {
|
|
115
148
|
return [all[0]];
|
|
116
149
|
}
|
|
117
150
|
let i = 1;
|
|
118
151
|
for (; i < all.length; ++i) {
|
|
119
|
-
const
|
|
152
|
+
const previousRange = all[i - 1].range;
|
|
153
|
+
assertDefined(previousRange);
|
|
154
|
+
const currentRange = all[i].range;
|
|
155
|
+
assertDefined(currentRange);
|
|
156
|
+
const txt = sourceCode.text.slice(previousRange[1], currentRange[0]);
|
|
120
157
|
if (!txt.match(/^(\r\n|\r|\n)$/)) {
|
|
121
158
|
break;
|
|
122
159
|
}
|
|
@@ -127,7 +164,7 @@ function getLeadingComments(context, node) {
|
|
|
127
164
|
/**
|
|
128
165
|
* Generate a comment including trailing spaces out of a number of comment body
|
|
129
166
|
* lines.
|
|
130
|
-
* @param {
|
|
167
|
+
* @param {CommentType} commentType the type of comment to generate.
|
|
131
168
|
* @param {string[]} textArray list of lines of the comment content.
|
|
132
169
|
* @param {'\n' | '\r\n'} eol end-of-line characters.
|
|
133
170
|
* @returns {string} resulting comment.
|
|
@@ -145,12 +182,21 @@ function genCommentBody(commentType, textArray, eol) {
|
|
|
145
182
|
/**
|
|
146
183
|
* Determines the start and end position in the source code of the leading
|
|
147
184
|
* comment.
|
|
148
|
-
* @param {
|
|
185
|
+
* @param {Comment[]} comments list of comments.
|
|
149
186
|
* @returns {[number, number]} resulting range.
|
|
150
187
|
*/
|
|
151
188
|
function genCommentsRange(comments) {
|
|
152
|
-
|
|
153
|
-
const
|
|
189
|
+
assert.ok(comments.length);
|
|
190
|
+
const firstComment = comments[0];
|
|
191
|
+
assertDefined(firstComment);
|
|
192
|
+
const firstCommentRange = firstComment.range;
|
|
193
|
+
assertDefined(firstCommentRange);
|
|
194
|
+
const start = firstCommentRange[0];
|
|
195
|
+
const lastComment = comments.slice(-1)[0];
|
|
196
|
+
assertDefined(lastComment);
|
|
197
|
+
const lastCommentRange = lastComment.range;
|
|
198
|
+
assertDefined(lastCommentRange);
|
|
199
|
+
const end = lastCommentRange[1];
|
|
154
200
|
return [start, end];
|
|
155
201
|
}
|
|
156
202
|
|
|
@@ -176,7 +222,7 @@ function leadingEmptyLines(src) {
|
|
|
176
222
|
|
|
177
223
|
/**
|
|
178
224
|
* Factory for fixer that adds a missing header.
|
|
179
|
-
* @param {
|
|
225
|
+
* @param {CommentType} commentType type of comment to use.
|
|
180
226
|
* @param {RuleContext} context ESLint execution runtime.
|
|
181
227
|
* @param {string[]} headerLines lines of the header comment.
|
|
182
228
|
* @param {'\n' | '\r\n'} eol end-of-line characters
|
|
@@ -186,15 +232,16 @@ function leadingEmptyLines(src) {
|
|
|
186
232
|
function genPrependFixer(commentType, context, headerLines, eol, numNewlines) {
|
|
187
233
|
return function(fixer) {
|
|
188
234
|
let insertPos = 0;
|
|
189
|
-
let newHeader = genCommentBody(commentType, headerLines, eol
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
235
|
+
let newHeader = genCommentBody(commentType, headerLines, eol);
|
|
236
|
+
const sourceCode = contextSourceCode(context);
|
|
237
|
+
if (sourceCode.text.startsWith("#!")) {
|
|
238
|
+
const firstNewLinePos = sourceCode.text.indexOf("\n");
|
|
239
|
+
insertPos = firstNewLinePos === -1 ? sourceCode.text.length : firstNewLinePos + 1;
|
|
193
240
|
if (firstNewLinePos === -1) {
|
|
194
241
|
newHeader = eol + newHeader;
|
|
195
242
|
}
|
|
196
243
|
}
|
|
197
|
-
const numEmptyLines = leadingEmptyLines(
|
|
244
|
+
const numEmptyLines = leadingEmptyLines(sourceCode.text.substring(insertPos));
|
|
198
245
|
const additionalEmptyLines = Math.max(0, numNewlines - numEmptyLines);
|
|
199
246
|
newHeader += eol.repeat(additionalEmptyLines);
|
|
200
247
|
return fixer.insertTextBeforeRange(
|
|
@@ -206,25 +253,23 @@ function genPrependFixer(commentType, context, headerLines, eol, numNewlines) {
|
|
|
206
253
|
|
|
207
254
|
/**
|
|
208
255
|
* Factory for fixer that replaces an incorrect header.
|
|
209
|
-
* @param {
|
|
256
|
+
* @param {CommentType} commentType type of comment to use.
|
|
210
257
|
* @param {RuleContext} context ESLint execution context.
|
|
211
258
|
* @param {Comment[]} leadingComments comment elements to replace.
|
|
212
259
|
* @param {string[]} headerLines lines of the header comment.
|
|
213
260
|
* @param {'\n' | '\r\n'} eol end-of-line characters
|
|
214
261
|
* @param {number} numNewlines number of trailing lines after the comment.
|
|
215
|
-
* @returns {
|
|
216
|
-
* (fixer: RuleTextEditor) => RuleTextEdit | RuleTextEdit[] | null
|
|
217
|
-
* } the fixer.
|
|
262
|
+
* @returns {(fixer: RuleFixer) => Fix | Fix[] | null} the fixer.
|
|
218
263
|
*/
|
|
219
264
|
function genReplaceFixer(commentType, context, leadingComments, headerLines, eol, numNewlines) {
|
|
220
265
|
return function(fixer) {
|
|
221
266
|
const commentRange = genCommentsRange(leadingComments);
|
|
222
|
-
const emptyLines = leadingEmptyLines(context.
|
|
267
|
+
const emptyLines = leadingEmptyLines(contextSourceCode(context).text.substring(commentRange[1]));
|
|
223
268
|
const missingNewlines = Math.max(0, numNewlines - emptyLines);
|
|
224
269
|
const eols = eol.repeat(missingNewlines);
|
|
225
270
|
return fixer.replaceTextRange(
|
|
226
271
|
commentRange,
|
|
227
|
-
genCommentBody(commentType, headerLines, eol
|
|
272
|
+
genCommentBody(commentType, headerLines, eol) + eols
|
|
228
273
|
);
|
|
229
274
|
};
|
|
230
275
|
}
|
|
@@ -235,9 +280,7 @@ function genReplaceFixer(commentType, context, leadingComments, headerLines, eol
|
|
|
235
280
|
* @param {'\n' | '\r\n'} eol end-of-line characters
|
|
236
281
|
* @param {number} missingEmptyLinesCount number of trailing lines after the
|
|
237
282
|
* comment.
|
|
238
|
-
* @returns {
|
|
239
|
-
* (fixer: RuleTextEditor) => RuleTextEdit | RuleTextEdit[] | null
|
|
240
|
-
* } the fixer.
|
|
283
|
+
* @returns {(fixer: RuleFixer) => Fix | Fix[] | null} the fixer.
|
|
241
284
|
*/
|
|
242
285
|
function genEmptyLinesFixer(leadingComments, eol, missingEmptyLinesCount) {
|
|
243
286
|
return function(fixer) {
|
|
@@ -250,7 +293,7 @@ function genEmptyLinesFixer(leadingComments, eol, missingEmptyLinesCount) {
|
|
|
250
293
|
|
|
251
294
|
/**
|
|
252
295
|
* Finds the option parameter within the list of rule config options.
|
|
253
|
-
* @param {
|
|
296
|
+
* @param {AllHeaderOptions} options the config options passed to the rule.
|
|
254
297
|
* @returns {HeaderSettings | null} the settings parameter or `null` if no such
|
|
255
298
|
* is defined.
|
|
256
299
|
*/
|
|
@@ -258,7 +301,7 @@ function findSettings(options) {
|
|
|
258
301
|
const lastOption = options[options.length - 1];
|
|
259
302
|
if (typeof lastOption === "object" && !Array.isArray(lastOption) && lastOption !== null
|
|
260
303
|
&& !Object.prototype.hasOwnProperty.call(lastOption, "pattern")) {
|
|
261
|
-
return lastOption;
|
|
304
|
+
return /** @type {HeaderSettings} */ (lastOption);
|
|
262
305
|
}
|
|
263
306
|
return null;
|
|
264
307
|
}
|
|
@@ -266,7 +309,7 @@ function findSettings(options) {
|
|
|
266
309
|
/**
|
|
267
310
|
* Returns the used line-termination characters per the rule's config if any or
|
|
268
311
|
* else based on the runtime environments.
|
|
269
|
-
* @param {
|
|
312
|
+
* @param {AllHeaderOptions} options rule configuration.
|
|
270
313
|
* @returns {'\n' | '\r\n'} the correct line ending characters for the
|
|
271
314
|
* environment.
|
|
272
315
|
*/
|
|
@@ -280,7 +323,7 @@ function getEOL(options) {
|
|
|
280
323
|
return "\r\n";
|
|
281
324
|
}
|
|
282
325
|
}
|
|
283
|
-
return os.EOL;
|
|
326
|
+
return /** @type {'\n' | '\r\n'} */ (os.EOL);
|
|
284
327
|
}
|
|
285
328
|
|
|
286
329
|
/**
|
|
@@ -308,7 +351,11 @@ function hasHeader(src) {
|
|
|
308
351
|
* @returns {SourceLocation} the location (line and column) of the violation.
|
|
309
352
|
*/
|
|
310
353
|
function missingEmptyLinesViolationLoc(leadingComments, actualEmptyLines) {
|
|
311
|
-
|
|
354
|
+
assert.ok(leadingComments);
|
|
355
|
+
const loc = leadingComments[leadingComments.length - 1].loc;
|
|
356
|
+
assertDefined(loc);
|
|
357
|
+
assertNotNull(loc);
|
|
358
|
+
const lastCommentLineLocEnd = loc.end;
|
|
312
359
|
return {
|
|
313
360
|
start: lastCommentLineLocEnd,
|
|
314
361
|
end: {
|
|
@@ -318,7 +365,8 @@ function missingEmptyLinesViolationLoc(leadingComments, actualEmptyLines) {
|
|
|
318
365
|
};
|
|
319
366
|
}
|
|
320
367
|
|
|
321
|
-
|
|
368
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
369
|
+
const headerRule = {
|
|
322
370
|
meta: {
|
|
323
371
|
type: "layout",
|
|
324
372
|
docs: {
|
|
@@ -348,7 +396,7 @@ module.exports = {
|
|
|
348
396
|
* @returns {NodeListener} the rule definition.
|
|
349
397
|
*/
|
|
350
398
|
create: function(context) {
|
|
351
|
-
let options = context.options;
|
|
399
|
+
let options = /** @type {AllHeaderOptions} */ (context.options);
|
|
352
400
|
const numNewlines = options.length > 2 && typeof options[2] === "number" ? options[2] : 1;
|
|
353
401
|
const eol = getEOL(options);
|
|
354
402
|
|
|
@@ -358,9 +406,10 @@ module.exports = {
|
|
|
358
406
|
options = commentParser(text);
|
|
359
407
|
}
|
|
360
408
|
|
|
361
|
-
const commentType = options[0].toLowerCase();
|
|
362
|
-
/** @type {(string | RegExp)[]} */
|
|
409
|
+
const commentType = /** @type {CommentType} */ (options[0].toLowerCase());
|
|
410
|
+
/** @type {(string | RegExp)[] | string[]} */
|
|
363
411
|
let headerLines;
|
|
412
|
+
/** @type {string[]} */
|
|
364
413
|
let fixLines = [];
|
|
365
414
|
// If any of the lines are regular expressions, then we can't
|
|
366
415
|
// automatically fix them. We set this to true below once we
|
|
@@ -371,34 +420,42 @@ module.exports = {
|
|
|
371
420
|
headerLines = options[1].map(function(line) {
|
|
372
421
|
const isRegex = isPattern(line);
|
|
373
422
|
// Can only fix regex option if a template is also provided
|
|
374
|
-
if (isRegex
|
|
375
|
-
|
|
423
|
+
if (isRegex) {
|
|
424
|
+
if (line.template) {
|
|
425
|
+
fixLines.push(line.template);
|
|
426
|
+
} else {
|
|
427
|
+
canFix = false;
|
|
428
|
+
}
|
|
429
|
+
return new RegExp(line.pattern);
|
|
430
|
+
} else {
|
|
431
|
+
fixLines.push(line);
|
|
432
|
+
return line;
|
|
376
433
|
}
|
|
377
|
-
fixLines.push(line.template || line);
|
|
378
|
-
return isRegex ? new RegExp(line.pattern) : line;
|
|
379
434
|
});
|
|
380
|
-
} else if (isPattern(options[1])) {
|
|
381
|
-
const line = options[1];
|
|
382
|
-
headerLines = [new RegExp(line.pattern)];
|
|
383
|
-
fixLines.push(line.template || line);
|
|
384
|
-
// Same as above for regex and template
|
|
385
|
-
canFix = !!line.template;
|
|
386
435
|
} else {
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
436
|
+
const line = /** @type {HeaderLine} */ (options[1]);
|
|
437
|
+
if (isPattern(line)) {
|
|
438
|
+
headerLines = [new RegExp(line.pattern)];
|
|
439
|
+
fixLines.push(line.template || "");
|
|
440
|
+
// Same as above for regex and template
|
|
441
|
+
canFix = !!line.template;
|
|
442
|
+
} else {
|
|
443
|
+
canFix = true;
|
|
444
|
+
headerLines = line.split(/\r?\n/);
|
|
445
|
+
fixLines = /** @type {string[]} */ (headerLines);
|
|
446
|
+
}
|
|
390
447
|
}
|
|
391
448
|
|
|
392
449
|
return {
|
|
393
450
|
/**
|
|
394
451
|
* Hooks into the processing of the overall script node to do the
|
|
395
452
|
* header validation.
|
|
396
|
-
* @param {Program} node the whole script node
|
|
397
453
|
* @returns {void}
|
|
398
454
|
*/
|
|
399
|
-
Program: function(
|
|
400
|
-
|
|
401
|
-
|
|
455
|
+
Program: function() {
|
|
456
|
+
const sourceCode = contextSourceCode(context);
|
|
457
|
+
if (!hasHeader(sourceCode.text)) {
|
|
458
|
+
const hasShebang = sourceCode.text.startsWith("#!");
|
|
402
459
|
const line = hasShebang ? 2 : 1;
|
|
403
460
|
context.report({
|
|
404
461
|
loc: {
|
|
@@ -416,13 +473,22 @@ module.exports = {
|
|
|
416
473
|
});
|
|
417
474
|
return;
|
|
418
475
|
}
|
|
419
|
-
const leadingComments = getLeadingComments(context
|
|
476
|
+
const leadingComments = getLeadingComments(context);
|
|
477
|
+
const firstLeadingCommentLoc = leadingComments[0].loc;
|
|
478
|
+
const firstLeadingCommentRange = leadingComments[0].range;
|
|
479
|
+
assertDefined(firstLeadingCommentRange);
|
|
480
|
+
|
|
481
|
+
const lastLeadingCommentLoc = leadingComments[leadingComments.length - 1].loc;
|
|
420
482
|
|
|
421
483
|
if (leadingComments[0].type.toLowerCase() !== commentType) {
|
|
484
|
+
assertDefined(firstLeadingCommentLoc);
|
|
485
|
+
assertNotNull(firstLeadingCommentLoc);
|
|
486
|
+
assertDefined(lastLeadingCommentLoc);
|
|
487
|
+
assertNotNull(lastLeadingCommentLoc);
|
|
422
488
|
context.report({
|
|
423
489
|
loc: {
|
|
424
|
-
start:
|
|
425
|
-
end:
|
|
490
|
+
start: firstLeadingCommentLoc.start,
|
|
491
|
+
end: lastLeadingCommentLoc.end
|
|
426
492
|
},
|
|
427
493
|
messageId: "incorrectCommentType",
|
|
428
494
|
data: {
|
|
@@ -441,10 +507,14 @@ module.exports = {
|
|
|
441
507
|
!match(leadingCommentValues.join("\n"), headerLines[0])
|
|
442
508
|
&& !match(leadingCommentValues.join("\r\n"), headerLines[0])
|
|
443
509
|
) {
|
|
510
|
+
assertDefined(firstLeadingCommentLoc);
|
|
511
|
+
assertNotNull(firstLeadingCommentLoc);
|
|
512
|
+
assertDefined(lastLeadingCommentLoc);
|
|
513
|
+
assertNotNull(lastLeadingCommentLoc);
|
|
444
514
|
context.report({
|
|
445
515
|
loc: {
|
|
446
|
-
start:
|
|
447
|
-
end:
|
|
516
|
+
start: firstLeadingCommentLoc.start,
|
|
517
|
+
end: lastLeadingCommentLoc.end
|
|
448
518
|
},
|
|
449
519
|
messageId: "incorrectHeader",
|
|
450
520
|
fix: canFix
|
|
@@ -456,9 +526,12 @@ module.exports = {
|
|
|
456
526
|
} else {
|
|
457
527
|
for (let i = 0; i < headerLines.length; i++) {
|
|
458
528
|
if (leadingComments.length - 1 < i) {
|
|
529
|
+
assertDefined(lastLeadingCommentLoc);
|
|
530
|
+
assertNotNull(lastLeadingCommentLoc);
|
|
459
531
|
context.report({
|
|
460
532
|
loc: {
|
|
461
|
-
start:
|
|
533
|
+
start: lastLeadingCommentLoc.end,
|
|
534
|
+
end: lastLeadingCommentLoc.end
|
|
462
535
|
},
|
|
463
536
|
messageId: "headerTooShort",
|
|
464
537
|
data: {
|
|
@@ -476,22 +549,27 @@ module.exports = {
|
|
|
476
549
|
});
|
|
477
550
|
return;
|
|
478
551
|
}
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
552
|
+
const headerLine = headerLines[i];
|
|
553
|
+
const comment = leadingComments[i];
|
|
554
|
+
const commentLoc = comment.loc;
|
|
555
|
+
assertDefined(commentLoc);
|
|
556
|
+
assertNotNull(commentLoc);
|
|
557
|
+
if (typeof headerLine === "string") {
|
|
558
|
+
const leadingCommentLength = comment.value.length;
|
|
559
|
+
const headerLineLength = headerLine.length;
|
|
482
560
|
for (let j = 0; j < Math.min(leadingCommentLength, headerLineLength); j++) {
|
|
483
|
-
if (
|
|
561
|
+
if (comment.value[j] !== headerLine[j]) {
|
|
484
562
|
context.report({
|
|
485
563
|
loc: {
|
|
486
564
|
start: {
|
|
487
565
|
column: "//".length + j,
|
|
488
|
-
line:
|
|
566
|
+
line: commentLoc.start.line
|
|
489
567
|
},
|
|
490
|
-
end:
|
|
568
|
+
end: commentLoc.end
|
|
491
569
|
},
|
|
492
570
|
messageId: "headerLineMismatchAtPos",
|
|
493
571
|
data: {
|
|
494
|
-
expected:
|
|
572
|
+
expected: headerLine.substring(j)
|
|
495
573
|
},
|
|
496
574
|
fix: genReplaceFixer(
|
|
497
575
|
commentType,
|
|
@@ -507,11 +585,12 @@ module.exports = {
|
|
|
507
585
|
if (leadingCommentLength < headerLineLength) {
|
|
508
586
|
context.report({
|
|
509
587
|
loc: {
|
|
510
|
-
start:
|
|
588
|
+
start: commentLoc.end,
|
|
589
|
+
end: commentLoc.end,
|
|
511
590
|
},
|
|
512
591
|
messageId: "headerLineTooShort",
|
|
513
592
|
data: {
|
|
514
|
-
remainder:
|
|
593
|
+
remainder: headerLine.substring(leadingCommentLength)
|
|
515
594
|
},
|
|
516
595
|
fix: canFix
|
|
517
596
|
? genReplaceFixer(
|
|
@@ -530,9 +609,9 @@ module.exports = {
|
|
|
530
609
|
loc: {
|
|
531
610
|
start: {
|
|
532
611
|
column: "//".length + headerLineLength,
|
|
533
|
-
line:
|
|
612
|
+
line: commentLoc.start.line
|
|
534
613
|
},
|
|
535
|
-
end:
|
|
614
|
+
end: commentLoc.end,
|
|
536
615
|
},
|
|
537
616
|
messageId: "headerLineTooLong",
|
|
538
617
|
fix: canFix
|
|
@@ -548,18 +627,18 @@ module.exports = {
|
|
|
548
627
|
return;
|
|
549
628
|
}
|
|
550
629
|
} else {
|
|
551
|
-
if (!match(
|
|
630
|
+
if (!match(comment.value, headerLine)) {
|
|
552
631
|
context.report({
|
|
553
632
|
loc: {
|
|
554
633
|
start: {
|
|
555
634
|
column: "//".length,
|
|
556
|
-
line:
|
|
635
|
+
line: commentLoc.start.line,
|
|
557
636
|
},
|
|
558
|
-
end:
|
|
637
|
+
end: commentLoc.end,
|
|
559
638
|
},
|
|
560
639
|
messageId: "incorrectHeaderLine",
|
|
561
640
|
data: {
|
|
562
|
-
pattern:
|
|
641
|
+
pattern: headerLine
|
|
563
642
|
},
|
|
564
643
|
fix: canFix
|
|
565
644
|
? genReplaceFixer(
|
|
@@ -577,8 +656,9 @@ module.exports = {
|
|
|
577
656
|
}
|
|
578
657
|
}
|
|
579
658
|
|
|
580
|
-
const
|
|
581
|
-
|
|
659
|
+
const commentRange = leadingComments[headerLines.length - 1].range;
|
|
660
|
+
assertDefined(commentRange);
|
|
661
|
+
const actualLeadingEmptyLines = leadingEmptyLines(sourceCode.text.substring(commentRange[1]));
|
|
582
662
|
const missingEmptyLines = numNewlines - actualLeadingEmptyLines;
|
|
583
663
|
if (missingEmptyLines > 0) {
|
|
584
664
|
context.report({
|
|
@@ -602,8 +682,8 @@ module.exports = {
|
|
|
602
682
|
|
|
603
683
|
/** @type {null | string} */
|
|
604
684
|
let errorMessageId = null;
|
|
605
|
-
/** @type {
|
|
606
|
-
let errorMessageData
|
|
685
|
+
/** @type {undefined | Record<string, string | RegExp>} */
|
|
686
|
+
let errorMessageData;
|
|
607
687
|
/** @type {null | SourceLocation} */
|
|
608
688
|
let errorMessageLoc = null;
|
|
609
689
|
for (let i = 0; i < headerLines.length; i++) {
|
|
@@ -614,7 +694,9 @@ module.exports = {
|
|
|
614
694
|
if (leadingLine[j] !== headerLine[j]) {
|
|
615
695
|
errorMessageId = "headerLineMismatchAtPos";
|
|
616
696
|
const columnOffset = i === 0 ? "/*".length : 0;
|
|
617
|
-
|
|
697
|
+
assertDefined(firstLeadingCommentLoc);
|
|
698
|
+
assertNotNull(firstLeadingCommentLoc);
|
|
699
|
+
const line = firstLeadingCommentLoc.start.line + i;
|
|
618
700
|
errorMessageLoc = {
|
|
619
701
|
start: {
|
|
620
702
|
column: columnOffset + j,
|
|
@@ -637,31 +719,35 @@ module.exports = {
|
|
|
637
719
|
if (leadingLine.length < headerLine.length) {
|
|
638
720
|
errorMessageId = "headerLineTooShort";
|
|
639
721
|
const startColumn = (i === 0 ? "/*".length : 0) + leadingLine.length;
|
|
722
|
+
assertDefined(firstLeadingCommentLoc);
|
|
723
|
+
assertNotNull(firstLeadingCommentLoc);
|
|
640
724
|
errorMessageLoc = {
|
|
641
725
|
start: {
|
|
642
726
|
column: startColumn,
|
|
643
|
-
line:
|
|
727
|
+
line: firstLeadingCommentLoc.start.line + i
|
|
644
728
|
},
|
|
645
729
|
end: {
|
|
646
730
|
column: startColumn + 1,
|
|
647
|
-
line:
|
|
731
|
+
line: firstLeadingCommentLoc.start.line + i
|
|
648
732
|
}
|
|
649
733
|
};
|
|
650
734
|
errorMessageData = {
|
|
651
|
-
remainder:
|
|
735
|
+
remainder: headerLine.substring(leadingLine.length)
|
|
652
736
|
};
|
|
653
737
|
break;
|
|
654
738
|
}
|
|
655
739
|
if (leadingLine.length > headerLine.length) {
|
|
740
|
+
assertDefined(firstLeadingCommentLoc);
|
|
741
|
+
assertNotNull(firstLeadingCommentLoc);
|
|
656
742
|
errorMessageId = "headerLineTooLong";
|
|
657
743
|
errorMessageLoc = {
|
|
658
744
|
start: {
|
|
659
745
|
column: (i === 0 ? "/*".length : 0) + headerLine.length,
|
|
660
|
-
line:
|
|
746
|
+
line: firstLeadingCommentLoc.start.line + i
|
|
661
747
|
},
|
|
662
748
|
end: {
|
|
663
749
|
column: (i === 0 ? "/*".length : 0) + leadingLine.length,
|
|
664
|
-
line:
|
|
750
|
+
line: firstLeadingCommentLoc.start.line + i
|
|
665
751
|
}
|
|
666
752
|
};
|
|
667
753
|
break;
|
|
@@ -673,14 +759,16 @@ module.exports = {
|
|
|
673
759
|
pattern: headerLine
|
|
674
760
|
};
|
|
675
761
|
const columnOffset = i === 0 ? "/*".length : 0;
|
|
762
|
+
assertDefined(firstLeadingCommentLoc);
|
|
763
|
+
assertNotNull(firstLeadingCommentLoc);
|
|
676
764
|
errorMessageLoc = {
|
|
677
765
|
start: {
|
|
678
766
|
column: columnOffset + 0,
|
|
679
|
-
line:
|
|
767
|
+
line: firstLeadingCommentLoc.start.line + i
|
|
680
768
|
},
|
|
681
769
|
end: {
|
|
682
770
|
column: columnOffset + leadingLine.length,
|
|
683
|
-
line:
|
|
771
|
+
line: firstLeadingCommentLoc.start.line + i
|
|
684
772
|
}
|
|
685
773
|
};
|
|
686
774
|
break;
|
|
@@ -690,14 +778,18 @@ module.exports = {
|
|
|
690
778
|
|
|
691
779
|
if (!errorMessageId && leadingLines.length > headerLines.length) {
|
|
692
780
|
errorMessageId = "headerTooLong";
|
|
781
|
+
assertDefined(firstLeadingCommentLoc);
|
|
782
|
+
assertNotNull(firstLeadingCommentLoc);
|
|
783
|
+
assertDefined(lastLeadingCommentLoc);
|
|
784
|
+
assertNotNull(lastLeadingCommentLoc);
|
|
693
785
|
errorMessageLoc = {
|
|
694
786
|
start: {
|
|
695
787
|
column: (headerLines.length === 0 ? "/*".length : 0) + 0,
|
|
696
|
-
line:
|
|
788
|
+
line: firstLeadingCommentLoc.start.line + headerLines.length
|
|
697
789
|
},
|
|
698
790
|
end: {
|
|
699
|
-
column:
|
|
700
|
-
line:
|
|
791
|
+
column: lastLeadingCommentLoc.end.column - "*/".length,
|
|
792
|
+
line: lastLeadingCommentLoc.end.line
|
|
701
793
|
}
|
|
702
794
|
};
|
|
703
795
|
}
|
|
@@ -706,6 +798,7 @@ module.exports = {
|
|
|
706
798
|
if (canFix && headerLines.length > 1) {
|
|
707
799
|
fixLines = [fixLines.join(eol)];
|
|
708
800
|
}
|
|
801
|
+
assertNotNull(errorMessageLoc);
|
|
709
802
|
context.report({
|
|
710
803
|
loc: errorMessageLoc,
|
|
711
804
|
messageId: errorMessageId,
|
|
@@ -717,8 +810,8 @@ module.exports = {
|
|
|
717
810
|
return;
|
|
718
811
|
}
|
|
719
812
|
|
|
720
|
-
const actualLeadingEmptyLines =
|
|
721
|
-
|
|
813
|
+
const actualLeadingEmptyLines =
|
|
814
|
+
leadingEmptyLines(sourceCode.text.substring(firstLeadingCommentRange[1]));
|
|
722
815
|
const missingEmptyLines = numNewlines - actualLeadingEmptyLines;
|
|
723
816
|
if (missingEmptyLines > 0) {
|
|
724
817
|
context.report({
|
|
@@ -735,3 +828,5 @@ module.exports = {
|
|
|
735
828
|
};
|
|
736
829
|
}
|
|
737
830
|
};
|
|
831
|
+
|
|
832
|
+
exports.header = headerRule;
|
package/package.json
CHANGED
|
@@ -1,31 +1,47 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tony.ganchev/eslint-plugin-header",
|
|
3
|
-
"version": "3.1.
|
|
3
|
+
"version": "3.1.13",
|
|
4
4
|
"description": "ESLint plugin to ensure files begin with a given comment, usually a copyright or license notice.",
|
|
5
5
|
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"types": "./index.d.ts",
|
|
10
|
+
"import": "./index.js",
|
|
11
|
+
"require": "./index.js"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
6
14
|
"files": [
|
|
7
|
-
"
|
|
8
|
-
"
|
|
15
|
+
"lib/**/*.js",
|
|
16
|
+
"index.d.ts*",
|
|
17
|
+
"types",
|
|
18
|
+
"!lib/rules/test-utils.js"
|
|
9
19
|
],
|
|
10
20
|
"scripts": {
|
|
21
|
+
"build": "npx tsc",
|
|
22
|
+
"e2e": "npm run build && npx mocha --timeout 60000 tests/e2e/*.js",
|
|
11
23
|
"eslint": "npx eslint .",
|
|
12
24
|
"lint": "npm run eslint && npm run markdownlint",
|
|
13
25
|
"markdownlint": "npx markdownlint-cli *.md",
|
|
14
|
-
"test": "npm run lint && npm run unit",
|
|
26
|
+
"test": "npm run lint && npm run unit && npm run e2e",
|
|
15
27
|
"unit": "npx nyc --reporter=html --reporter=text --reporter=text-summary --reporter=lcov --check-coverage=true --statements=100 --branches=100 --lines=100 --functions=100 mocha tests/lib/*.js tests/lib/**/*.js"
|
|
16
28
|
},
|
|
17
29
|
"devDependencies": {
|
|
18
|
-
"@eslint/eslintrc": "^3.3.
|
|
19
|
-
"@eslint/js": "^9.39.
|
|
30
|
+
"@eslint/eslintrc": "^3.3.3",
|
|
31
|
+
"@eslint/js": "^9.39.2",
|
|
20
32
|
"@eslint/markdown": "^7.5.1",
|
|
21
|
-
"@stylistic/eslint-plugin": "^5.
|
|
22
|
-
"
|
|
23
|
-
"eslint
|
|
24
|
-
"eslint-plugin-
|
|
25
|
-
"eslint-plugin-
|
|
26
|
-
"
|
|
33
|
+
"@stylistic/eslint-plugin": "^5.7.1",
|
|
34
|
+
"@types/node": "^25.2.1",
|
|
35
|
+
"eslint": "^9.39.2",
|
|
36
|
+
"eslint-plugin-eslint-plugin": "^7.3.0",
|
|
37
|
+
"eslint-plugin-jsdoc": "^62.5.2",
|
|
38
|
+
"eslint-plugin-n": "^17.23.2",
|
|
39
|
+
"markdownlint-cli": "^0.47.0",
|
|
40
|
+
"mocha": "^12.0.0-beta-6",
|
|
27
41
|
"nyc": "^17.1.0",
|
|
28
|
-
"testdouble": "^3.20.2"
|
|
42
|
+
"testdouble": "^3.20.2",
|
|
43
|
+
"typescript": "^5.9.3",
|
|
44
|
+
"typescript-eslint": "^8.54.0"
|
|
29
45
|
},
|
|
30
46
|
"peerDependencies": {
|
|
31
47
|
"eslint": ">=7.7.0"
|
|
@@ -40,7 +56,7 @@
|
|
|
40
56
|
},
|
|
41
57
|
"author": "Stuart Knightley",
|
|
42
58
|
"license": "MIT",
|
|
43
|
-
"
|
|
59
|
+
"maintainers": [
|
|
44
60
|
"Tony Ganchev"
|
|
45
61
|
]
|
|
46
62
|
}
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.js"],"names":[],"mappings":";AA4BA,6CAA6C;AAC7C,gCADW,OAAO,QAAQ,EAAE,MAAM,CAAC,MAAM,CAKvC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"comment-parser.d.ts","sourceRoot":"","sources":["../../lib/comment-parser.js"],"names":[],"mappings":"AAsCiB,uCAJN,MAAM,GACJ,CAAC,OAAO,GAAG,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAAC,CAmBjD"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare namespace _exports {
|
|
2
|
+
export { RuleContext, SourceCode };
|
|
3
|
+
}
|
|
4
|
+
declare namespace _exports {
|
|
5
|
+
function contextSourceCode(context: RuleContext): SourceCode;
|
|
6
|
+
}
|
|
7
|
+
export = _exports;
|
|
8
|
+
type RuleContext = import("eslint").Rule.RuleContext;
|
|
9
|
+
type SourceCode = import("eslint").SourceCode;
|
|
10
|
+
//# sourceMappingURL=eslint-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"eslint-utils.d.ts","sourceRoot":"","sources":["../../../lib/rules/eslint-utils.js"],"names":[],"mappings":";;;;IAsCuB,oCAHR,WAAW,GACT,UAAU,CAItB;;;mBAbQ,OAAO,QAAQ,EAAE,IAAI,CAAC,WAAW;kBACjC,OAAO,QAAQ,EAAE,UAAU"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
export { headerRule as header };
|
|
2
|
+
/**
|
|
3
|
+
* Import type definitions.
|
|
4
|
+
*/
|
|
5
|
+
export type Fix = import("eslint").Rule.Fix;
|
|
6
|
+
/**
|
|
7
|
+
* Import type definitions.
|
|
8
|
+
*/
|
|
9
|
+
export type NodeListener = import("eslint").Rule.NodeListener;
|
|
10
|
+
/**
|
|
11
|
+
* Import type definitions.
|
|
12
|
+
*/
|
|
13
|
+
export type ReportFixer = import("eslint").Rule.ReportFixer;
|
|
14
|
+
/**
|
|
15
|
+
* Import type definitions.
|
|
16
|
+
*/
|
|
17
|
+
export type RuleFixer = import("eslint").Rule.RuleFixer;
|
|
18
|
+
/**
|
|
19
|
+
* Import type definitions.
|
|
20
|
+
*/
|
|
21
|
+
export type RuleContext = import("eslint").Rule.RuleContext;
|
|
22
|
+
/**
|
|
23
|
+
* Import type definitions.
|
|
24
|
+
*/
|
|
25
|
+
export type Comment = import("estree").Comment;
|
|
26
|
+
/**
|
|
27
|
+
* Import type definitions.
|
|
28
|
+
*/
|
|
29
|
+
export type Program = import("estree").Program;
|
|
30
|
+
/**
|
|
31
|
+
* Import type definitions.
|
|
32
|
+
*/
|
|
33
|
+
export type SourceLocation = import("estree").SourceLocation;
|
|
34
|
+
/**
|
|
35
|
+
* Local type definitions.
|
|
36
|
+
*/
|
|
37
|
+
export type HeaderLinePattern = {
|
|
38
|
+
pattern: string;
|
|
39
|
+
template?: string;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Local type definitions.
|
|
43
|
+
*/
|
|
44
|
+
export type HeaderLine = string | HeaderLinePattern;
|
|
45
|
+
/**
|
|
46
|
+
* Local type definitions.
|
|
47
|
+
*/
|
|
48
|
+
export type HeaderLines = (HeaderLine | HeaderLine[]);
|
|
49
|
+
/**
|
|
50
|
+
* Local type definitions.
|
|
51
|
+
*/
|
|
52
|
+
export type LineEndingOption = "unix" | "windows";
|
|
53
|
+
/**
|
|
54
|
+
* Local type definitions.
|
|
55
|
+
*/
|
|
56
|
+
export type HeaderSettings = {
|
|
57
|
+
lineEndings?: LineEndingOption;
|
|
58
|
+
};
|
|
59
|
+
/**
|
|
60
|
+
* Local type definitions.
|
|
61
|
+
*/
|
|
62
|
+
export type CommentType = "block" | "line";
|
|
63
|
+
/**
|
|
64
|
+
* Local type definitions.
|
|
65
|
+
*/
|
|
66
|
+
export type AllHeaderOptions = [template: string] | [template: string, settings: HeaderSettings] | [type: CommentType, lines: HeaderLines] | [type: CommentType, lines: HeaderLines, settings: HeaderSettings] | [type: CommentType, lines: HeaderLines, minLines: number] | [type: CommentType, lines: HeaderLines, minLines: number, settings: HeaderSettings];
|
|
67
|
+
/**
|
|
68
|
+
* Local type definitions.
|
|
69
|
+
*/
|
|
70
|
+
export type HeaderRuleConfig = import("eslint").Linter.RuleEntry<AllHeaderOptions>;
|
|
71
|
+
/** @type {import('eslint').Rule.RuleModule} */
|
|
72
|
+
declare const headerRule: import("eslint").Rule.RuleModule;
|
|
73
|
+
//# sourceMappingURL=header.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.d.ts","sourceRoot":"","sources":["../../../lib/rules/header.js"],"names":[],"mappings":";;;;kBAoCa,OAAO,QAAQ,EAAE,IAAI,CAAC,GAAG;;;;2BACzB,OAAO,QAAQ,EAAE,IAAI,CAAC,YAAY;;;;0BAClC,OAAO,QAAQ,EAAE,IAAI,CAAC,WAAW;;;;wBACjC,OAAO,QAAQ,EAAE,IAAI,CAAC,SAAS;;;;0BAC/B,OAAO,QAAQ,EAAE,IAAI,CAAC,WAAW;;;;sBACjC,OAAO,QAAQ,EAAE,OAAO;;;;sBACxB,OAAO,QAAQ,EAAE,OAAO;;;;6BACxB,OAAO,QAAQ,EAAE,cAAc;;;;gCAK/B;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,CAAC,EAAE,MAAM,CAAA;CAAE;;;;yBACtC,MAAM,GAAG,iBAAiB;;;;0BAC1B,CAAC,UAAU,GAAG,UAAU,EAAE,CAAC;;;;+BAC3B,MAAM,GAAG,SAAS;;;;6BAClB;IAAE,WAAW,CAAC,EAAE,gBAAgB,CAAA;CAAE;;;;0BAClC,OAAO,GAAG,MAAM;;;;+BAChB,CAAC,QAAQ,EAAE,MAAM,CAAC,GAC9B,CAAI,QAAQ,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,CAAC,GAC/C,CAAI,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,CAAC,GAC1C,CAAI,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,cAAc,CAAC,GACpE,CAAI,IAAI,EAAE,WAAW,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,MAAM,CAAC,GAC5D,CACM,IAAI,EAAE,WAAW,EACjB,KAAK,EAAE,WAAW,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,cAAc,CAC1B;;;;+BAEQ,OAAO,QAAQ,EAAE,MAAM,CAAC,SAAS,CAAC,gBAAgB,CAAC;AA6ShE,+CAA+C;AAC/C,0BADW,OAAO,QAAQ,EAAE,IAAI,CAAC,UAAU,CA8czC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.docs.d.ts","sourceRoot":"","sources":["../../../lib/rules/header.docs.js"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type lineEndingOptions = string;
|
|
2
|
+
/**
|
|
3
|
+
* @enum {string}
|
|
4
|
+
*/
|
|
5
|
+
export const lineEndingOptions: Readonly<{
|
|
6
|
+
os: "os";
|
|
7
|
+
unix: "unix";
|
|
8
|
+
windows: "windows";
|
|
9
|
+
}>;
|
|
10
|
+
export type commentTypeOptions = string;
|
|
11
|
+
/**
|
|
12
|
+
* @enum {string}
|
|
13
|
+
*/
|
|
14
|
+
export const commentTypeOptions: Readonly<{
|
|
15
|
+
block: "block";
|
|
16
|
+
line: "line";
|
|
17
|
+
}>;
|
|
18
|
+
/** @type {import('json-schema').JSONSchema4} */
|
|
19
|
+
export const schema: import("json-schema").JSONSchema4;
|
|
20
|
+
//# sourceMappingURL=header.schema.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"header.schema.d.ts","sourceRoot":"","sources":["../../../lib/rules/header.schema.js"],"names":[],"mappings":"gCA2BU,MAAM;AADhB;;GAEG;AACH;;;;GAIG;iCAGO,MAAM;AADhB;;GAEG;AACH;;;GAGG;AAEH,gDAAgD;AAChD,qBADW,OAAO,aAAa,EAAE,WAAW,CA0FzC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
declare namespace _exports {
|
|
2
|
+
export { InvalidTestCase, TestCaseError };
|
|
3
|
+
}
|
|
4
|
+
declare namespace _exports {
|
|
5
|
+
function generateInvalidTestCaseNames(invalidTests: InvalidTestCase[]): InvalidTestCase[];
|
|
6
|
+
}
|
|
7
|
+
export = _exports;
|
|
8
|
+
type InvalidTestCase = import("eslint").RuleTester.InvalidTestCase;
|
|
9
|
+
type TestCaseError = import("eslint").RuleTester.TestCaseError;
|
|
10
|
+
//# sourceMappingURL=test-utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test-utils.d.ts","sourceRoot":"","sources":["../../../lib/rules/test-utils.js"],"names":[],"mappings":";;;;IA4EkC,oDAJnB,eAAe,EAAE,GACf,eAAe,EAAE,CA4B7B;;;uBAxEQ,OAAO,QAAQ,EAAE,UAAU,CAAC,eAAe;qBAC3C,OAAO,QAAQ,EAAE,UAAU,CAAC,aAAa"}
|