@tony.ganchev/eslint-plugin-header 3.1.5 → 3.1.7

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/LICENSE.md CHANGED
@@ -1,7 +1,18 @@
1
- Copyright (c) 2015-present Stuart Knightley and contributors
1
+ Copyright (c) 2015-present Stuart Knightley, Tony Ganchev and contributors
2
2
 
3
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of
4
+ this software and associated documentation files (the “Software”), to deal in
5
+ the Software without restriction, including without limitation the rights to
6
+ use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
7
+ the Software, and to permit persons to whom the Software is furnished to do so,
8
+ subject to the following conditions:
4
9
 
5
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
+ The above copyright notice and this permission notice shall be included in all
11
+ copies or substantial portions of the Software.
6
12
 
7
- THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
13
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
15
+ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
16
+ COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
17
+ IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
18
+ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md CHANGED
@@ -1,19 +1,57 @@
1
- This is a fork of https://github.com/Stuk/eslint-plugin-header intended to make the plugin work with ESLint v9
1
+ This is a fork of https://github.com/Stuk/eslint-plugin-header.
2
+
3
+ It addresses the following issus:
4
+
5
+ - Adds bugfixes where the original project has not been updated in the last
6
+ three years.
7
+ - Adds support for ESLint 9 with a fully-validated configuration schema.
8
+ - Addresses a number of bugs on Windows and adds significant amount of tests to
9
+ verify there are no future regressions.
10
+ - Fixes issues with she-bangs and empty lines before the header. See PR history
11
+ for more details.
12
+ - Provides the foundation to evolve the plugin to add more capabilities moving
13
+ forward. This would come at the expense of plugin compatibility and the
14
+ portability of fixes to the upstream repository.
2
15
 
3
16
  eslint-plugin-header
4
17
  ====================
5
18
 
6
19
  ESLint plugin to ensure that files begin with given comment.
7
20
 
8
- Often you will want to have a copyright notice at the top of every file. This ESLint plugin checks that the first comment in every file has the contents defined in the rule settings.
21
+ Often you will want to have a copyright notice at the top of every file. This
22
+ ESLint plugin checks that the first comment in every file has the contents
23
+ defined in the rule settings.
9
24
 
10
25
  ## Usage
11
26
 
12
- This rule takes 1, 2 or 3 arguments with an optional settings object.
27
+ This rule takes between 1 and 4 arguments after the rule validation severity.
28
+
29
+ The configuration can take any of the following forms:
30
+
31
+ * File-based Configuration
32
+ * `[<severity>, "<file>"]` - read the header template from a file.
33
+ * `[<severity>, "<file>", {<settings>}]` - read the header template from a
34
+ file with additional settings.
35
+ * Inline Configuration
36
+ * `"<severity>", "<comment-type>", <header-contents>` - define the header
37
+ contents inline.
38
+ * `[<severity>, "<comment-type>", <header-contents>, {<settings>}]` - define
39
+ the header contents inline and pass additional settings.
40
+ * `[<severity>, "<comment-type>", <header-contents>, <n-empty-lines>]` -
41
+ define the header contents inline and an expected number of empty lines
42
+ after the header.
43
+ * `[<severity>, "<comment-type>", <header-contents>, <n-empty-lines>, {<settings>}]` -
44
+ define the header contents inline and an expected number of empty lines
45
+ after the header and pass additional settings.
13
46
 
14
- ### 1 argument
47
+ ### File-based Configuration
15
48
 
16
- In the 1 argument form the argument is the filename of a file that contains the comment(s) that should appear at the top of every file:
49
+ In this configuration mode, the first argument is a string pointing to a JS
50
+ file containing the header contents. The rule would expect an exact match to be
51
+ found in the source code.
52
+
53
+ The second argument can be a settings object that will be covered later in this
54
+ document.
17
55
 
18
56
  ```json
19
57
  {
@@ -33,128 +71,287 @@ config/header.js:
33
71
  // My company
34
72
  ```
35
73
 
36
- Due to limitations in eslint plugins, the file is read relative to the working directory that eslint is executed in. If you run eslint from elsewhere in your tree then the header file will not be found.
74
+ Due to limitations in ESLint plugins, the file is read relative to the working
75
+ directory that ESLint is executed in. If you run ESLint from elsewhere in your
76
+ tree then the header file will not be found.
77
+
78
+ ### Inline Configuration
37
79
 
38
- ### 2 arguments
80
+ The inline configuration expects at least two arguments to be given:
81
+ - _comment-type_ which is either `"block"` or `"line"` to indicate what style
82
+ of comment should be used.
83
+ - _header-contents_ which defines the lines of the header. It can be either a
84
+ single multiline string / regular expression with the full contents of the
85
+ header comment or an array with comment lines or regular expressions matching
86
+ each line.
39
87
 
40
- In the 2 argument form the first must be either `"block"` or `"line"` to indicate what style of comment should be used. The second is either a string (including newlines) of the comment, or an array of each line of the comment.
88
+ #### Header Contents Configuration
89
+
90
+ Suppose we want our header to look like this:
91
+ ```js
92
+ /*
93
+ * Copyright (c) 2015
94
+ * My Company
95
+ */
96
+ ...
97
+ ```
98
+
99
+ All of the following configurations will match the header:
100
+ * **Single string**:
101
+ ```json
102
+ {
103
+ ...
104
+ "rules": {
105
+ "header/header": [
106
+ 2,
107
+ "block",
108
+ "\n * Copyright (c) 2015\n * My Company\n "
109
+ ]
110
+ }
111
+ }
112
+ ```
113
+ Note that the above would work for both Windows and POSIX systems even
114
+ though the EOL in the header content was specified as `\n`.
115
+
116
+ Also, notice how we have an empty space before each line. This is because
117
+ the plugin only strips the leading `//` characters from a line comment/
118
+ Similar for a block comment, only the opening `/*` and closing `*/` will be
119
+ preserved.
120
+
121
+ * **Single regular expression**:
122
+ ```json
123
+ {
124
+ ...
125
+ "rules": {
126
+ "header/header": [
127
+ 2,
128
+ "block",
129
+ { "pattern": "\\n \\* Copyright \\(c\\) 2015\\n \\* My Company\\n " }
130
+ ]
131
+ }
132
+ }
133
+ ```
134
+
135
+ Notice the double escaping of the braces. Since these pattern strings into
136
+ `RegExp` objects, the backslashes need to be present in the string instead
137
+ of disappear as escape characters.
138
+
139
+ For the comparable example using line comments we cannot use a single
140
+ expression as the second argument after the severity instead of a string or
141
+ an array. This is because the pattern will be matched against the first
142
+ single-line line comment and validation would fail. In general, using the
143
+ array form is preferable as it is easier to follow.
144
+
145
+ * **Array of strings**:
146
+ ```json
147
+ {
148
+ ...
149
+ "rules": {
150
+ "header/header": [
151
+ 2,
152
+ "block",
153
+ [
154
+ "",
155
+ " * Copyright (c) 2015",
156
+ " * My Company",
157
+ " "
158
+ ]
159
+ ]
160
+ }
161
+ }
162
+ ```
163
+ * **Array of strings and/or patterns**:
164
+ ```json
165
+ {
166
+ ...
167
+ "rules": {
168
+ "header/header": [
169
+ 2,
170
+ "block",
171
+ [
172
+ "",
173
+ { "pattern": " \\* Copyright \\(c\\) 2015" },
174
+ " * My Company",
175
+ " "
176
+ ]
177
+ ]
178
+ }
179
+ }
180
+ ```
181
+
182
+ Regular expressions allow for a number of improvements in the maintainability
183
+ of the headers. Given the example above, what is clear is that new sources may
184
+ have been created later than 2015 and a comment with a different year should be
185
+ perfectly valid such as:
186
+
187
+ ```js
188
+ /*
189
+ * Copyright 2020
190
+ * My company
191
+ */
192
+ ...
193
+ ```
194
+ Moreover, suppose legal expects that the year of first and last change be added
195
+ except if all changes happen in the same year, we also need to support:
196
+ ```js
197
+ /*
198
+ * Copyright 2017-2022
199
+ * My company
200
+ */
201
+ ...
202
+ ```
203
+ We can use a regular expression to support all of these cases for your header:
41
204
 
42
205
  ```json
43
206
  {
44
- "plugins": [
45
- "header"
46
- ],
207
+ ...
47
208
  "rules": {
48
- "header/header": [2, "block", "Copyright 2015\nMy Company"]
209
+ "header/header": [
210
+ 2,
211
+ "block",
212
+ [
213
+ "",
214
+ { "pattern": " \\* Copyright \\(c\\) (\\d{4}-)?\\d{4}" },
215
+ " * My Company",
216
+ " "
217
+ ]
218
+ ]
49
219
  }
50
220
  }
51
221
  ```
52
222
 
53
- ### 3 arguments
54
-
55
- The optional third argument which defaults to 1 specifies the number of newlines that are enforced after the header.
223
+ Note on auto-fixes i.e. `eslint --fix`: whenever strings are used to define the
224
+ header - counting in file-based configuration - the same strings would be used
225
+ to replace a header comment that did not pass validation. This is not possible
226
+ with regular expressions. For regular expression pattern-objects, a second
227
+ property `template` adds a replacement string.
56
228
 
57
- Zero newlines:
58
229
  ```json
59
230
  {
60
- "plugins": [
61
- "header"
62
- ],
231
+ ...
63
232
  "rules": {
64
- "header/header": [2, "block", [" Copyright now","My Company "], 0]
233
+ "header/header": [
234
+ 2,
235
+ "line",
236
+ [
237
+ {
238
+ "pattern": " Copyright \\(c\\) (\\d{4}-)?\\d{4}",
239
+ "template": " Copyright 2025",
240
+ },
241
+ " My Company"
242
+ ]
243
+ ]
65
244
  }
66
245
  }
67
246
  ```
68
- ```js
69
- /* Copyright now
70
- My Company */ console.log(1)
71
- ```
247
+ There are a number of things to consider:
248
+ - Templates need to be matched by the regular expression pattern or otherwise
249
+ an auto-fixed source would again fail linting. This needs to be validated
250
+ manually today as the plugin does not do it for you.
251
+ - Templates are hardcoded strings therefore it may be better to hand-fix a bad
252
+ header in order not to lose the from- and to-years in the copyright notice.
253
+
254
+ #### Trailing Empty Lines Configuration
72
255
 
73
- One newline (default)
256
+ The third argument of the rule configuration which defaults to 1 specifies the
257
+ number of newlines that are enforced after the header.
258
+
259
+ Zero newlines:
74
260
  ```json
75
261
  {
76
262
  "plugins": [
77
263
  "header"
78
264
  ],
79
265
  "rules": {
80
- "header/header": [2, "block", [" Copyright now","My Company "], 1]
266
+ "header/header": [
267
+ 2,
268
+ "block",
269
+ [
270
+ " Copyright now",
271
+ "My Company "
272
+ ],
273
+ 0
274
+ ]
81
275
  }
82
276
  }
83
277
  ```
84
278
  ```js
85
279
  /* Copyright now
86
- My Company */
87
- console.log(1)
280
+ My Company */ console.log(1)
88
281
  ```
89
282
 
90
- two newlines
283
+ One newline (default):
91
284
  ```json
92
285
  {
93
286
  "plugins": [
94
287
  "header"
95
288
  ],
96
289
  "rules": {
97
- "header/header": [2, "block", [" Copyright now","My Company "], 2]
290
+ "header/header": [
291
+ 2,
292
+ "block",
293
+ [
294
+ " Copyright now",
295
+ "My Company "
296
+ ],
297
+ 1
298
+ ]
98
299
  }
99
300
  }
100
301
  ```
101
302
  ```js
102
303
  /* Copyright now
103
304
  My Company */
104
-
105
305
  console.log(1)
106
306
  ```
107
307
 
108
- #### Regular expressions
109
-
110
- Instead of a string to be checked for exact matching you can also supply a regular expression. Be aware that you have to escape backslashes:
111
-
308
+ Two newlines:
112
309
  ```json
113
310
  {
114
311
  "plugins": [
115
312
  "header"
116
313
  ],
117
314
  "rules": {
118
- "header/header": [2, "block", [
119
- {"pattern": " Copyright \\d{4}"},
120
- "My Company"
121
- ]]
315
+ "header/header": [
316
+ 2,
317
+ "block",
318
+ [
319
+ " Copyright now",
320
+ "My Company "
321
+ ],
322
+ 2
323
+ ]
122
324
  }
123
325
  }
124
326
  ```
125
-
126
- This would match:
127
-
128
327
  ```js
129
- /* Copyright 2808
130
- My Company*/
131
- ```
132
-
133
- When you use a regular expression `pattern`, you can also provide a `template` property, to provide the comment value when using `eslint --fix`:
328
+ /* Copyright now
329
+ My Company */
134
330
 
135
- ```json
136
- {
137
- "plugins": [
138
- "header"
139
- ],
140
- "rules": {
141
- "header/header": [2, "block", [
142
- {"pattern": " Copyright \\d{4}", "template": " Copyright 2019"},
143
- "My Company"
144
- ]]
145
- }
146
- }
331
+ console.log(1)
147
332
  ```
148
333
 
149
- ### Line Endings
334
+ #### Line Endings
150
335
 
151
- The rule works with both unix and windows line endings. For ESLint `--fix`, the rule will use the line ending format of the current operating system (via the node `os` package). This setting can be overwritten as follows:
336
+ The rule works with both Unix/POSIX and Windows line endings. For ESLint
337
+ `--fix`, the rule will use the line ending format of the current operating
338
+ system (via Node's `os` package). This setting can be overwritten as follows:
152
339
  ```json
153
340
  "rules": {
154
- "header/header": [2, "block", ["Copyright 2018", "My Company"], {"lineEndings": "windows"}]
341
+ "header/header": [
342
+ 2,
343
+ "block",
344
+ [
345
+ "Copyright 2018",
346
+ "My Company"
347
+ ],
348
+ {
349
+ "lineEndings": "windows"
350
+ }
351
+ ]
155
352
  }
156
353
  ```
157
- Possible values are `unix` for `\n` and `windows` for `\r\n` line endings.
354
+ Possible values are `"unix"` for `\n` and `"windows"` for `\r\n` line endings.
158
355
 
159
356
  ## Examples
160
357
 
@@ -191,7 +388,7 @@ console.log(1)
191
388
  " * Copyright 2015",
192
389
  " * My Company",
193
390
  " ************************"
194
- ]
391
+ ]]
195
392
  ```
196
393
 
197
394
  ```js
@@ -160,18 +160,28 @@ function genCommentsRange(context, comments, eol) {
160
160
  /**
161
161
  * Factory for fixer that adds a missing header.
162
162
  * @param {'block' | 'line'} commentType type of comment to use.
163
- * @param {Program} node ESLint AST program node.
163
+ * @param {RuleContext} context ESLint execution runtime.
164
164
  * @param {string[]} headerLines lines of the header comment.
165
165
  * @param {'\n' | '\r\n'} eol end-of-line characters
166
166
  * @param {number} numNewlines number of trailing lines after the comment.
167
167
  * @returns {ReportFixer} the fixer.
168
168
  */
169
- function genPrependFixer(commentType, node, headerLines, eol, numNewlines) {
169
+ function genPrependFixer(commentType, context, headerLines, eol, numNewlines) {
170
170
  return function(fixer) {
171
- return fixer.insertTextBefore(
172
- node,
173
- genCommentBody(commentType, headerLines, eol, numNewlines)
174
- );
171
+ const newHeader = genCommentBody(commentType, headerLines, eol, numNewlines);
172
+ if (context.sourceCode.text.substring(0, 2) === "#!") {
173
+ const firstNewLinePos = context.sourceCode.text.indexOf("\n");
174
+ const insertPos = firstNewLinePos === -1 ? context.sourceCode.text.length : firstNewLinePos + 1;
175
+ return fixer.insertTextBeforeRange(
176
+ [insertPos, insertPos /* don't care */],
177
+ (firstNewLinePos === -1 ? eol : "") + newHeader
178
+ );
179
+ } else {
180
+ return fixer.insertTextBeforeRange(
181
+ [0, 0 /* don't care */],
182
+ newHeader
183
+ );
184
+ }
175
185
  };
176
186
  }
177
187
 
@@ -402,11 +412,11 @@ module.exports = {
402
412
 
403
413
  return {
404
414
  Program: function(node) {
405
- if (!hasHeader(context.getSourceCode().getText())) {
415
+ if (!hasHeader(context.sourceCode.getText())) {
406
416
  context.report({
407
417
  loc: node.loc,
408
418
  message: "missing header",
409
- fix: genPrependFixer(commentType, node, fixLines, eol, numNewlines)
419
+ fix: genPrependFixer(commentType, context, fixLines, eol, numNewlines)
410
420
  });
411
421
  } else {
412
422
  var leadingComments = getLeadingComments(context, node);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tony.ganchev/eslint-plugin-header",
3
- "version": "3.1.5",
3
+ "version": "3.1.7",
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
6
  "files": [
@@ -9,7 +9,7 @@
9
9
  ],
10
10
  "scripts": {
11
11
  "test": "npm run lint && npm run unit",
12
- "unit": "nyc --reporter=html --reporter=text --reporter=text-summary mocha tests/lib/**/*.js",
12
+ "unit": "nyc --reporter=html --reporter=text --reporter=text-summary --check-coverage=true --statements=98 --branches=90 --lines=98 --functions=100 mocha tests/lib/**/*.js",
13
13
  "lint": "eslint ."
14
14
  },
15
15
  "devDependencies": {