@tony.ganchev/eslint-plugin-header 3.3.4 → 3.4.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.
package/README.md CHANGED
@@ -7,13 +7,17 @@
7
7
  The native ESLint 9/10 standard header-validating plugin. A zero-bloat, drop-in
8
8
  replacement for [eslint-plugin-header](https://github.com/Stuk/eslint-plugin-header)
9
9
  with first-class Flat Config & TypeScript support. Auto-fix copyright, license,
10
- and banner comments in JavaScript and TypeScript files. Supports _oxlint_.
10
+ and banner comments in JavaScript, TypeScript, Vue, CSS, HTML, and Markdown files.
11
+ Supports _oxlint_.
11
12
 
12
13
  ## Table of Contents
13
14
 
14
15
  1. [Motivation and Acknowledgements](#motivation-and-acknowledgements)
15
16
  2. [Major Consumers](#major-consumers)
16
17
  3. [Compatibility](#compatibility)
18
+ 1. [Runtimes](#runtimes)
19
+ 2. [Configuration Formats](#configuration-formats)
20
+ 3. [Languages](#languages)
17
21
  4. [Usage](#usage)
18
22
  1. [File-based Configuration](#file-based-configuration)
19
23
  2. [Inline Configuration](#inline-configuration)
@@ -24,10 +28,15 @@ and banner comments in JavaScript and TypeScript files. Supports _oxlint_.
24
28
  3. [Support for Leading Comments](#support-for-leading-comments)
25
29
  1. [Notes on Behavior](#notes-on-behavior)
26
30
  4. [Examples](#examples)
31
+ 5. [Linting CSS](#linting-css)
32
+ 6. [Linting HTML](#linting-html)
33
+ 7. [Linting Vue](#linting-vue)
34
+ 8. [Linting Markdown](#linting-markdown)
27
35
  5. [Comparison to Alternatives](#comparison-to-alternatives)
28
36
  1. [Compared to eslint-plugin-headers](#compared-to-eslint-plugin-headers)
29
37
  1. [Health Scans](#health-scans)
30
38
  2. [Compared to eslint-plugin-license-header](#compared-to-eslint-plugin-license-header)
39
+ 3. [Compared to eslint-plugin-notice](#compared-to-eslint-plugin-notice)
31
40
  6. [Versioning](#versioning)
32
41
  1. [What is a Feature?](#what-is-a-feature)
33
42
  2. [What is Backward-compatibility?](#what-is-backward-compatibility)
@@ -88,6 +97,8 @@ consistent header structures. Notable adopters include:
88
97
     
89
98
  [![Mysten Labs](https://github.com/MystenLabs.png?size=48)](./docs/consumers.md#mysten-labs)
90
99
     
100
+ [![Suwayomi](https://github.com/Suwayomi.png?size=48)](./docs/consumers.md#suwayomi)
101
+    
91
102
  [![Wire Swiss GmbH](https://github.com/wireapp.png?size=48)](./docs/consumers.md#wire-swiss-gmbh)
92
103
     
93
104
  [![WPPConnect](https://github.com/wppconnect-team.png?size=48)](./docs/consumers.md#wppconnect)
@@ -97,17 +108,46 @@ Learn more about how these organizations use the plugin on our
97
108
 
98
109
  ## Compatibility
99
110
 
111
+ ### Runtimes
112
+
100
113
  The plugin supports **ESLint 7 / 8 / 9 / 10**. Both **flat** config and legacy,
101
114
  **hierarchical** config can be used. We have a smoke-test running to confirm the
102
- plugin works with the latest version of ESLint.
115
+ plugin works with the latest version of ESLint. Certain features such as linting
116
+ copyright headers in CSS, HTML, or Markdown rely on APIs introduced with ESLint
117
+ 9 and cannot be used with older ESLint versions.
103
118
 
104
119
  The plugin works with latest version of **oxlint** too. We have a smoke-test
105
- running to confirm the plugin works with the latest version of oxlint.
120
+ running to confirm the plugin works with the latest version of oxlint. Features
121
+ relying on the use of non-standard parsers such as linting headers in CSS, HTML,
122
+ Vue, or Markdown cannot be supported.
123
+
124
+ ### Configuration Formats
125
+
126
+ The plugin supports hierarchical and flat configuration format for ESLint as
127
+ well as the configuration format for oxlint.
106
128
 
107
129
  The NPM package provides TypeScript type definitions and can be used with
108
130
  TypeScript-based ESLint flat configuration without the need for `@ts-ignore`
109
131
  statements. Smoke tests cover this support as well.
110
132
 
133
+ ### Languages
134
+
135
+ Currently the plugin supports linting copyright headers in JavaScript,
136
+ TypeScript and their JSX / TSX flavors; Vue, CSS, HTML, and Markdown files. As
137
+ mentioned in the previous sections, not all languages are supported for oxlint
138
+ or ESLint older than 9. Refer to the table below for more details.
139
+
140
+ | Language | ESLint 7 / 8 | ESLint 9 / 10 | oxlint |
141
+ |------------|---------------|---------------|--------|
142
+ | JavaScript | ✅ Yes | ✅ Yes | ✅ Yes |
143
+ | TypeScript | ✅ Yes | ✅ Yes | ✅ Yes |
144
+ | JSX | ✅ Yes | ✅ Yes | ✅ Yes |
145
+ | TSX | ✅ Yes | ✅ Yes | ✅ Yes |
146
+ | Vue | ✅ Yes | ✅ Yes | ❌ No |
147
+ | CSS | ❌ No | ✅ Yes | ❌ No |
148
+ | HTML | ❌ No | ✅ Yes | ❌ No |
149
+ | Markdown | ❌ No | ✅ Yes | ❌ No |
150
+
111
151
  ## Usage
112
152
 
113
153
  The plugin and its _header_ rule goes through evolution of its configuration in
@@ -1146,10 +1186,55 @@ export default defineConfig([
1146
1186
  ]);
1147
1187
  ```
1148
1188
 
1189
+ ### Linting CSS
1190
+
1191
+ The rule supports validating and auto-fixing headers in CSS files. To
1192
+ use the plugin with these file types, you need to configure the official
1193
+ `@eslint/css` plugin.
1194
+
1195
+ **Note: the plugin does not support SCSS** as no current popular parser for
1196
+ ESLint supports SCSS / LESS that being a prerequisite for this plugin to be
1197
+ called. It is possible to rely on a dummy pass-through parser to ensure the SCSS
1198
+ / LESS sources simply reach the rule but as of the time of the publisihng of
1199
+ this document we have not tested this approach.
1200
+
1201
+ Back to CSS, let us use the following configuration:
1202
+
1203
+ _eslint.config.js_:
1204
+
1149
1205
  ```js
1150
- //Copyright 2017
1151
- //My Company
1152
- console.log(1)
1206
+ import header from "@tony.ganchev/eslint-plugin-header";
1207
+ import css from "@eslint/css";
1208
+
1209
+ export default [
1210
+ {
1211
+ files: ["**/*.css"],
1212
+ plugins: {
1213
+ "@tony.ganchev": header,
1214
+ css
1215
+ },
1216
+ language: "css/css",
1217
+ rules: {
1218
+ "@tony.ganchev/header": [
1219
+ "error",
1220
+ {
1221
+ header: {
1222
+ commentType: "block",
1223
+ lines: [" Copyright 2025 "]
1224
+ }
1225
+ }
1226
+ ]
1227
+ }
1228
+ }
1229
+ ];
1230
+ ```
1231
+
1232
+ ```css
1233
+ /* Copyright 2025 */
1234
+
1235
+ .foo {
1236
+ color: blue;
1237
+ }
1153
1238
  ```
1154
1239
 
1155
1240
  With more decoration:
@@ -1184,14 +1269,174 @@ export default defineConfig([
1184
1269
  ]);
1185
1270
  ```
1186
1271
 
1187
- ```js
1272
+ ```css
1188
1273
  /*************************
1189
1274
  * Copyright 2015
1190
1275
  * My Company
1191
1276
  *************************/
1192
- console.log(1);
1277
+
1278
+ .foo {
1279
+ color: blue
1280
+ }
1281
+ ```
1282
+
1283
+ As you can expect with CSS syntax, line comments and shebangs are not supported.
1284
+ All other features of the rule remain the same.
1285
+
1286
+ ### Linting HTML
1287
+
1288
+ The rule supports linting copyright notices in HTML files. The rule works with
1289
+ the _@html-eslint/eslint-plugin_ plugin and its parser.
1290
+
1291
+ Similar to CSS, all you need to do to turn on header validation is to configure
1292
+ the _\@html-eslint/eslint-plugin_ plugin and the rule:
1293
+
1294
+ ```ts
1295
+ import header from "@tony.ganchev/eslint-plugin-header";
1296
+ import html from "@html-eslint/eslint-plugin";
1297
+
1298
+ export default [
1299
+ {
1300
+ files: ["**/*.html"],
1301
+ plugins: {
1302
+ "@tony.ganchev": header,
1303
+ html
1304
+ },
1305
+ language: "html/html",
1306
+ rules: {
1307
+ "@tony.ganchev/header": [
1308
+ "error",
1309
+ {
1310
+ header: {
1311
+ commentType: "block",
1312
+ lines: [" Copyright 2025 "]
1313
+ }
1314
+ }
1315
+ ]
1316
+ }
1317
+ }
1318
+ ];
1319
+ ```
1320
+
1321
+ ```html
1322
+ <!-- Copyright 2025 -->
1323
+
1324
+ <html>
1325
+ <body>
1326
+ <h1>Hello, world!</h1>
1327
+ <p>Lorem ipsum dolor.</p>
1328
+ </body>
1329
+ </html>
1330
+ ```
1331
+
1332
+ As with CSS, only block comments are supported - no line- or shebang comments.
1333
+
1334
+ ### Linting Vue
1335
+
1336
+ The rule supports linting copyright notices in Vue files. The rule works with
1337
+ the _eslint-plugin-vue_ plugin and its parser.
1338
+
1339
+ To turn on header validation for Vue files, configure the parser, the plugin,
1340
+ and the rule:
1341
+
1342
+ ```ts
1343
+ import header from "@tony.ganchev/eslint-plugin-header";
1344
+ import vueParser from "vue-eslint-parser";
1345
+ import vuePlugin from "eslint-plugin-vue";
1346
+
1347
+ export default [
1348
+ {
1349
+ files: ["**/*.vue"],
1350
+ plugins: {
1351
+ "@tony.ganchev": header,
1352
+ vue: vuePlugin
1353
+ },
1354
+ languageOptions: {
1355
+ parser: vueParser
1356
+ },
1357
+ rules: {
1358
+ "@tony.ganchev/header": [
1359
+ "error",
1360
+ {
1361
+ header: {
1362
+ commentType: "block",
1363
+ lines: [" Copyright 2025 "]
1364
+ }
1365
+ }
1366
+ ]
1367
+ }
1368
+ }
1369
+ ];
1370
+ ```
1371
+
1372
+ ```vue
1373
+ <!-- Copyright 2025 -->
1374
+ <template>
1375
+ <div>Hello, world!</div>
1376
+ </template>
1377
+ ```
1378
+
1379
+ As with HTML and CSS, only block comments are supported at the top of the file -
1380
+ no line- or shebang comments.
1381
+
1382
+ ### Linting Markdown
1383
+
1384
+ The rule supports copyright comments in Markdown syntax in both _commonmark_ and
1385
+ _gfm_ flavors using the _\@eslint/markdown_ plugin and parser. Only HTML
1386
+ comments are supported - no anchor hacks or similar are accepted.
1387
+
1388
+ Similar to CSS, all you need to do to turn on header validation is to configure
1389
+ the _\@eslint/markdown_ plugin and the rule:
1390
+
1391
+ ```ts
1392
+ import header from "@tony.ganchev/eslint-plugin-header";
1393
+ import markdown from "@eslint/markdown";
1394
+
1395
+ export default [
1396
+ {
1397
+ files: ["**/*.md"],
1398
+ plugins: {
1399
+ "@tony.ganchev": header,
1400
+ markdown
1401
+ },
1402
+ // ... or "markdown/gfm"
1403
+ language: "markdown/commonmark",
1404
+ rules: {
1405
+ "@tony.ganchev/header": [
1406
+ "error",
1407
+ {
1408
+ header: {
1409
+ commentType: "block",
1410
+ lines: [" Copyright 2025 "]
1411
+ }
1412
+ }
1413
+ ]
1414
+ }
1415
+ }
1416
+ ];
1193
1417
  ```
1194
1418
 
1419
+ ```md
1420
+ <!-- Copyright 2025 -->
1421
+
1422
+ # Title
1423
+
1424
+ ## Subtitle
1425
+
1426
+ ## Code
1427
+
1428
+ ```js
1429
+ console.log("Hello, world!");
1430
+ ```
1431
+ ```
1432
+
1433
+ Note that if you have configured header for `*.js` files, the linter would fail
1434
+ on the first line of the nested JavaScript snippet. Look up how to differentiate
1435
+ the configuration of JavaScript sources (`**/*.js`) from JavaScript snippets in
1436
+ Markdown (`**/*.md/*.js`). Same applies to `*.ts`, `*.jsx`, `*.tsx`, etc.
1437
+
1438
+ As with CSS, only block comments are supported - no line- or shebang comments.
1439
+
1195
1440
  ## Comparison to Alternatives
1196
1441
 
1197
1442
  A number of projects have been aiming to solve problems similar to
@@ -1209,12 +1454,16 @@ _eslint-plugin-header_ and all plugins that already use the latter can migrate
1209
1454
  to the fork right away. At the same time, it provides improved user experience
1210
1455
  and windows support.
1211
1456
 
1212
- eslint-plugin-headers is not a drop-in replacement. It offers additional
1213
- features. Some of them, such as support for Vue templates do not have an
1214
- analogue in the current version of _\@tony.ganchev/eslint-plugin-header_ while
1215
- others such as `{year}` variable placeholders are redundant in the world of
1216
- ESLint 9's flat, JavaScript-based configuration as [already pointed out in this
1217
- document](#providing-to-year-in-auto-fix).
1457
+ _eslint-plugin-headers_ is not a drop-in replacement. It offers additional
1458
+ features that are not first-level use-cases for
1459
+ _\@tony.ganchev/eslint-plugin-header_. One example is support for `{year}`
1460
+ variable placeholders which are redundant with ESLint's JavaScript-based
1461
+ configuration as [already pointed out in this document](#providing-to-year-in-auto-fix).
1462
+ JSDoc support can be achieved with regular expressions and the overall
1463
+ configuration capabilities of _\@tony.ganchev/eslint-plugin-header_. It is worth
1464
+ noting that the source code of _\@tony.ganchev/eslint-plugin-header_ already
1465
+ uses JSDoc-style comments for its own header which are in turn validated using
1466
+ _\@tony.ganchev/eslint-plugin-header/header_ rule.
1218
1467
 
1219
1468
  The configuration format philosophy of the two plugin differs.
1220
1469
  _\@tony.ganchev/eslint-plugin-header_ supports both the legacy model inherited
@@ -1281,6 +1530,30 @@ We have prepared a detailed
1281
1530
  [migration guide](docs/migrate-from-license-header.md) for anyone eager to
1282
1531
  migrate to _\@tony.ganchev/eslint-plugin-header_.
1283
1532
 
1533
+ ### Compared to [eslint-plugin-notice](https://github.com/earl-man/eslint-plugin-notice)
1534
+
1535
+ _eslint-plugin-notice_ is another alternative that uses a template-based approach
1536
+ (powered by Lodash templates) to manage headers. This makes it quite powerful for
1537
+ dynamic content but also brings in more dependencies and a more complex
1538
+ configuration schema that doesn't always feel "native" to the new ESLint Flat
1539
+ Config era.
1540
+
1541
+ Key differences:
1542
+
1543
+ - **Philosophy**: _\@tony.ganchev/eslint-plugin-header_ focuses on a zero-bloat,
1544
+ native ESLint feel with first-class support for Flat Config and TypeScript.
1545
+ - **ESLint 9/10**: Our plugin is built from the ground up to support the latest
1546
+ ESLint versions and their core features.
1547
+ - **Languages**: We provide native support for linting headers in HTML, CSS,
1548
+ and Markdown via their respective ESLint ecosystem plugins.
1549
+ - **Simplicity**: No need for external template engines or complex variable
1550
+ mappings. Use standard JavaScript template literals in your `eslint.config.ts`
1551
+ to handle dynamic years or other variables.
1552
+
1553
+ We have prepared a detailed
1554
+ [migration guide](docs/migrate-from-notice.md) for anyone eager to
1555
+ migrate to _\@tony.ganchev/eslint-plugin-header_.
1556
+
1284
1557
  ## Versioning
1285
1558
 
1286
1559
  The project follows standard [NPM semantic versioning policy](
@@ -26,6 +26,10 @@
26
26
 
27
27
  const assert = require("node:assert");
28
28
 
29
+ /**
30
+ * @import { CommentType, Language } from './rules/header'
31
+ */
32
+
29
33
  /**
30
34
  * Parses a line or block comment and returns the type of comment and an array
31
35
  * of content lines.
@@ -33,24 +37,34 @@ const assert = require("node:assert");
33
37
  * This is a really simple and dumb parser, that looks just for a
34
38
  * single kind of comment. It won't detect multiple block comments.
35
39
  * @param {string} commentText Content to parse.
36
- * @returns {[import("./rules/header").CommentType, string[]]} Comment type and
37
- * comment content broken into lines.
40
+ * @param {Language} language The language
41
+ * configuration.
42
+ * @returns {[CommentType, string[]]} Comment type and
43
+ * content.
38
44
  * @throws {Error} If `commentText` starts with an unrecognized comment token.
39
45
  */
40
- module.exports = function commentParser(commentText) {
46
+ module.exports = function commentParser(commentText, language) {
41
47
  assert.strictEqual(typeof commentText, "string");
48
+ assert.ok(language);
49
+
42
50
  const text = commentText.trim();
51
+ const lc = language.lineComment;
52
+ const bc = language.blockComment;
43
53
 
44
- if (text.startsWith("//")) {
54
+ if (lc && text.startsWith(lc.startDelimiter)) {
45
55
  return [
46
56
  "line",
47
- text.split(/\r?\n/).map((line) => line.substring(2))
57
+ text.split(/\r?\n/).map((line) => line.substring(lc.startDelimiter.length))
58
+ ];
59
+ } else if (bc && text.startsWith(bc.startDelimiter) && text.endsWith(bc.endDelimiter)) {
60
+ return [
61
+ "block",
62
+ text.substring(bc.startDelimiter.length, text.length - bc.endDelimiter.length).split(/\r?\n/)
48
63
  ];
49
- } else if (text.startsWith("/*") && text.endsWith("*/")) {
50
- return ["block", text.substring(2, text.length - 2).split(/\r?\n/)];
51
64
  } else {
52
65
  throw new Error(
53
- "Could not parse comment file: the file must contain either just line comments (//) or a single block " +
54
- "comment (/* ... */)");
66
+ "Could not parse comment file: the file must contain a comment " +
67
+ "that matches the supplied language delimiters."
68
+ );
55
69
  }
56
70
  };