@tony.ganchev/eslint-plugin-header 3.1.13 → 3.2.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.
@@ -33,8 +33,8 @@ const assert = require("node:assert");
33
33
  * This is a really simple and dumb parser, that looks just for a
34
34
  * single kind of comment. It won't detect multiple block comments.
35
35
  * @param {string} commentText comment text.
36
- * @returns {['block' | 'line', string | string[]]} comment type and comment
37
- * content broken into lines.
36
+ * @returns {['block' | 'line', string[]]} comment type and comment content
37
+ * broken into lines.
38
38
  */
39
39
  module.exports = function commentParser(commentText) {
40
40
  assert.strictEqual(typeof commentText, "string");
@@ -46,7 +46,7 @@ module.exports = function commentParser(commentText) {
46
46
  text.split(/\r?\n/).map((line) => line.substring(2))
47
47
  ];
48
48
  } else if (text.startsWith("/*") && text.endsWith("*/")) {
49
- return ["block", text.substring(2, text.length - 2)];
49
+ return ["block", text.substring(2, text.length - 2).split(/\r?\n/)];
50
50
  } else {
51
51
  throw new Error(
52
52
  "Could not parse comment file: the file must contain either just line comments (//) or a single block " +
@@ -30,7 +30,7 @@ const os = require("node:os");
30
30
  const commentParser = require("../comment-parser");
31
31
  const { contextSourceCode } = require("./eslint-utils");
32
32
  const { description, recommended, url } = require("./header.docs");
33
- const { commentTypeOptions, lineEndingOptions, schema } = require("./header.schema");
33
+ const { lineEndingOptions, commentTypeOptions, schema } = require("./header.schema");
34
34
 
35
35
  /**
36
36
  * Import type definitions.
@@ -46,13 +46,31 @@ const { commentTypeOptions, lineEndingOptions, schema } = require("./header.sche
46
46
 
47
47
  /**
48
48
  * Local type definitions.
49
- * @typedef {{ pattern: string, template?: string }} HeaderLinePattern
50
- * @typedef {string | HeaderLinePattern} HeaderLine
51
- * @typedef {(HeaderLine | HeaderLine[])} HeaderLines
52
- * @typedef {'unix' | 'windows'} LineEndingOption
49
+ * @typedef {{ pattern: string | RegExp, template?: string }} HeaderLinePattern
50
+ * @typedef {string | RegExp | HeaderLinePattern} HeaderLine
51
+ * @typedef {HeaderLine | HeaderLine[]} HeaderLines
52
+ * @typedef {'os' | 'unix' | 'windows'} LineEndingOption
53
53
  * @typedef {{ lineEndings?: LineEndingOption }} HeaderSettings
54
54
  * @typedef {'block' | 'line'} CommentType
55
- * @typedef {[template: string] |
55
+ * @typedef {{
56
+ * file: string,
57
+ * encoding?: BufferEncoding
58
+ * }
59
+ * } FileBasedConfig
60
+ * @typedef {{
61
+ * commentType: CommentType,
62
+ * lines: HeaderLine[]
63
+ * }
64
+ * } InlineConfig
65
+ * @typedef {{ minimum?: number }} TrailingEmptyLines
66
+ * @typedef {{
67
+ * header: FileBasedConfig | InlineConfig,
68
+ * trailingEmptyLines?: TrailingEmptyLines
69
+ * }
70
+ * & HeaderSettings
71
+ * } HeaderOptions
72
+ * @typedef {[HeaderOptions] |
73
+ * [template: string] |
56
74
  * [template: string, settings: HeaderSettings] |
57
75
  * [type: CommentType, lines: HeaderLines] |
58
76
  * [type: CommentType, lines: HeaderLines, settings: HeaderSettings] |
@@ -77,7 +95,8 @@ const { commentTypeOptions, lineEndingOptions, schema } = require("./header.sche
77
95
  * otherwise.
78
96
  */
79
97
  function isPattern(object) {
80
- return typeof object === "object" && Object.prototype.hasOwnProperty.call(object, "pattern");
98
+ return typeof object === "object"
99
+ && (Object.prototype.hasOwnProperty.call(object, "pattern"));
81
100
  }
82
101
 
83
102
  /**
@@ -291,39 +310,25 @@ function genEmptyLinesFixer(leadingComments, eol, missingEmptyLinesCount) {
291
310
  };
292
311
  }
293
312
 
294
- /**
295
- * Finds the option parameter within the list of rule config options.
296
- * @param {AllHeaderOptions} options the config options passed to the rule.
297
- * @returns {HeaderSettings | null} the settings parameter or `null` if no such
298
- * is defined.
299
- */
300
- function findSettings(options) {
301
- const lastOption = options[options.length - 1];
302
- if (typeof lastOption === "object" && !Array.isArray(lastOption) && lastOption !== null
303
- && !Object.prototype.hasOwnProperty.call(lastOption, "pattern")) {
304
- return /** @type {HeaderSettings} */ (lastOption);
305
- }
306
- return null;
307
- }
308
-
309
313
  /**
310
314
  * Returns the used line-termination characters per the rule's config if any or
311
315
  * else based on the runtime environments.
312
- * @param {AllHeaderOptions} options rule configuration.
316
+ * @param {LineEndingOption} style line-ending styles.
313
317
  * @returns {'\n' | '\r\n'} the correct line ending characters for the
314
- * environment.
318
+ * environment.
315
319
  */
316
- function getEOL(options) {
317
- const settings = findSettings(options);
318
- if (settings) {
319
- if (settings.lineEndings === lineEndingOptions.unix) {
320
+ function getEol(style) {
321
+ assert.strictEqual(Object.prototype.hasOwnProperty.call(lineEndingOptions, style), true,
322
+ "lineEnding style should have been populated in normalizeOptions().");
323
+ switch (style) {
324
+ case lineEndingOptions.unix:
320
325
  return "\n";
321
- }
322
- if (settings.lineEndings === lineEndingOptions.windows) {
326
+ case lineEndingOptions.windows:
323
327
  return "\r\n";
324
- }
328
+ case lineEndingOptions.os:
329
+ default:
330
+ return /** @type {'\n' | '\r\n'} */ (os.EOL);
325
331
  }
326
- return /** @type {'\n' | '\r\n'} */ (os.EOL);
327
332
  }
328
333
 
329
334
  /**
@@ -337,6 +342,155 @@ function hasHeader(src) {
337
342
  return srcWithoutShebang.startsWith("/*") || srcWithoutShebang.startsWith("//");
338
343
  }
339
344
 
345
+ /**
346
+ * asserts on an expression and adds template texts to the failure message.
347
+ * Helper to write cleaner code.
348
+ * @param {boolean} condition assert condition.
349
+ * @param {string} message assert message on violation.
350
+ */
351
+ function schemaAssert(condition, message) {
352
+ assert.strictEqual(condition, true, message + " - should have been handled by eslint schema validation.");
353
+ }
354
+
355
+ /**
356
+ * Ensures that if legacy options as defined in the original
357
+ * `eslint-plugin-header` are used, they'd be converted to the new object-based
358
+ * configuration. This is not a normalized internal representation of the
359
+ * options in that some settings are still union types and unspecified
360
+ * properties are not replaced by defaults. If the options follow the new
361
+ * format, a simple seep copy would be returned.
362
+ * @param {AllHeaderOptions} originalOptions the options as configured by the
363
+ * user.
364
+ * @returns {HeaderOptions} the transformed new-style options with no
365
+ * normalization.
366
+ */
367
+ function transformLegacyOptions(originalOptions) {
368
+ schemaAssert(originalOptions?.length > 0,
369
+ "header options are required (at least one in addition to the severity)");
370
+ schemaAssert(originalOptions.length <= 4,
371
+ "header options should not be more than four (five including issue severity)");
372
+ if (originalOptions.length === 1 && typeof originalOptions[0] === "object") {
373
+ // The user chose to use the new-style config. We pass a copy of the
374
+ // incoming sole option to not mess with ESLint not relying on the old
375
+ // values of the option.
376
+ return structuredClone(originalOptions[0]);
377
+ }
378
+ // The user chose the legacy-style config. Transform them to new-style
379
+ // config.
380
+ schemaAssert(typeof originalOptions[0] === "string",
381
+ "first header option after severity should be either a filename or 'block' | 'line'");
382
+ /** @type {HeaderOptions} */
383
+ const transformedOptions = {};
384
+ // populate header
385
+ if (
386
+ originalOptions.length === 1
387
+ || (
388
+ originalOptions.length === 2
389
+ && typeof originalOptions[1] === "object"
390
+ && !Array.isArray(originalOptions[1])
391
+ && !isPattern(/** @type {HeaderLine} */(originalOptions[1]))
392
+ )) {
393
+ transformedOptions.header = { file: originalOptions[0], encoding: "utf8" };
394
+ } else {
395
+ schemaAssert(Object.prototype.hasOwnProperty.call(commentTypeOptions, originalOptions[0]),
396
+ "Only 'block' or 'line' is accepted as comment type");
397
+ schemaAssert(
398
+ typeof originalOptions[1] === "string"
399
+ || Array.isArray(originalOptions[1])
400
+ || isPattern(/** @type {HeaderLine} */(originalOptions[1])),
401
+ "second header option after severity should be a string, a pattern, or an array of the previous two");
402
+ transformedOptions.header = {
403
+ commentType: /** @type {CommentType} */ (originalOptions[0]),
404
+ lines: /** @type {HeaderLine[]} */ (
405
+ Array.isArray(originalOptions[1])
406
+ ? originalOptions[1]
407
+ : [originalOptions[1]])
408
+ };
409
+ }
410
+ // configure required line settings
411
+ if (originalOptions.length >= 3) {
412
+ if (typeof originalOptions[2] === "number") {
413
+ transformedOptions.trailingEmptyLines = { minimum: originalOptions[2] };
414
+ if (originalOptions.length === 4) {
415
+ schemaAssert(typeof originalOptions[3] === "object",
416
+ "Fourth header option after severity should be either number of required trailing empty lines or " +
417
+ "a settings object");
418
+ Object.assign(transformedOptions, originalOptions[3]);
419
+ }
420
+ } else {
421
+ schemaAssert(typeof originalOptions[2] === "object",
422
+ "Third header option after severity should be either number of required trailing empty lines or a " +
423
+ "settings object");
424
+ Object.assign(transformedOptions, originalOptions[2]);
425
+ }
426
+ }
427
+ return transformedOptions;
428
+ }
429
+
430
+ /**
431
+ * @param {FileBasedConfig | InlineConfig} config the header configuration.
432
+ * @returns {config is FileBasedConfig} true if `config` is `FileBasedConfig`.
433
+ */
434
+ function isFileBasedHeaderConfig(config) {
435
+ return Object.prototype.hasOwnProperty.call(config, "file");
436
+ }
437
+
438
+ /**
439
+ * @param {FileBasedConfig | InlineConfig} config the header configuration.
440
+ * @returns {asserts config is InlineConfig} asserts `config` is
441
+ * `LineBasedConfig`.
442
+ */
443
+ function assertLineBasedHeaderConfig(config) {
444
+ assert.ok(Object.prototype.hasOwnProperty.call(config, "lines"));
445
+ }
446
+
447
+ /**
448
+ * Transforms a set of new-style options adding defaults and standardizing on
449
+ * one of multiple config styles.
450
+ * @param {HeaderOptions} originalOptions new-style options to normalize.
451
+ * @returns {HeaderOptions} normalized options.
452
+ */
453
+ function normalizeOptions(originalOptions) {
454
+ const options = structuredClone(originalOptions);
455
+
456
+ if (isFileBasedHeaderConfig(originalOptions.header)) {
457
+ const text = fs.readFileSync(originalOptions.header.file, originalOptions.header.encoding || "utf8");
458
+ const [commentType, lines] = commentParser(text);
459
+ options.header = { commentType, lines };
460
+ }
461
+ assertLineBasedHeaderConfig(options.header);
462
+ options.header.lines = options.header.lines.flatMap(
463
+ (line) => {
464
+ if (typeof line === "string") {
465
+ return /** @type {HeaderLine[]} */(line.split(/\r?\n/));
466
+ }
467
+ if (line instanceof RegExp) {
468
+ return [{ pattern: line }];
469
+ }
470
+ assert.ok(Object.prototype.hasOwnProperty.call(line, "pattern"));
471
+ const pattern = line.pattern instanceof RegExp ? line.pattern : new RegExp(line.pattern);
472
+ if (Object.prototype.hasOwnProperty.call(line, "template")) {
473
+ return [{
474
+ pattern,
475
+ template: line.template
476
+ }];
477
+ }
478
+ return [{ pattern }];
479
+ });
480
+
481
+ if (!options.lineEndings) {
482
+ options.lineEndings = "os";
483
+ }
484
+
485
+ if (!options.trailingEmptyLines) {
486
+ options.trailingEmptyLines = {};
487
+ }
488
+ if (typeof options.trailingEmptyLines.minimum !== "number") {
489
+ options.trailingEmptyLines.minimum = 1;
490
+ }
491
+ return options;
492
+ }
493
+
340
494
  /**
341
495
  * Calculates the source location of the violation that not enough empty lines
342
496
  * follow the header.
@@ -376,7 +530,15 @@ const headerRule = {
376
530
  },
377
531
  fixable: "whitespace",
378
532
  schema,
379
- defaultOptions: [{}],
533
+ defaultOptions: [
534
+ /** @type {AllHeaderOptions} */
535
+ {
536
+ lineEndings: lineEndingOptions.os,
537
+ trailingEmptyLines: {
538
+ minimum: 1
539
+ }
540
+ }
541
+ ],
380
542
  messages: {
381
543
  headerLineMismatchAtPos: "header line does not match expected after this position; expected: {{expected}}",
382
544
  headerLineTooLong: "header line longer than expected",
@@ -396,55 +558,41 @@ const headerRule = {
396
558
  * @returns {NodeListener} the rule definition.
397
559
  */
398
560
  create: function(context) {
399
- let options = /** @type {AllHeaderOptions} */ (context.options);
400
- const numNewlines = options.length > 2 && typeof options[2] === "number" ? options[2] : 1;
401
- const eol = getEOL(options);
402
-
403
- // If just one option then read comment from file
404
- if (options.length === 1 || (options.length === 2 && findSettings(options))) {
405
- const text = fs.readFileSync(context.options[0], "utf8");
406
- options = commentParser(text);
407
- }
408
561
 
409
- const commentType = /** @type {CommentType} */ (options[0].toLowerCase());
410
- /** @type {(string | RegExp)[] | string[]} */
411
- let headerLines;
562
+ const newStyleOptions = transformLegacyOptions(/** @type {AllHeaderOptions} */ (context.options));
563
+ const options = normalizeOptions(newStyleOptions);
564
+
565
+ assertLineBasedHeaderConfig(options.header);
566
+ const commentType = /** @type {CommentType} */ (options.header.commentType);
567
+
568
+ const eol = getEol(
569
+ /** @type {LineEndingOption} */ (options.lineEndings)
570
+ );
571
+
412
572
  /** @type {string[]} */
413
573
  let fixLines = [];
414
574
  // If any of the lines are regular expressions, then we can't
415
575
  // automatically fix them. We set this to true below once we
416
576
  // ensure none of the lines are of type RegExp
417
- let canFix = false;
418
- if (Array.isArray(options[1])) {
419
- canFix = true;
420
- headerLines = options[1].map(function(line) {
421
- const isRegex = isPattern(line);
422
- // Can only fix regex option if a template is also provided
423
- if (isRegex) {
424
- if (line.template) {
425
- fixLines.push(line.template);
426
- } else {
427
- canFix = false;
428
- }
429
- return new RegExp(line.pattern);
577
+ let canFix = true;
578
+ const headerLines = options.header.lines.map(function(line) {
579
+ // Can only fix regex option if a template is also provided
580
+ if (isPattern(line)) {
581
+ if (Object.prototype.hasOwnProperty.call(line, "template")) {
582
+ fixLines.push(/** @type {string} */ (line.template));
430
583
  } else {
431
- fixLines.push(line);
432
- return line;
584
+ canFix = false;
585
+ fixLines.push("");
433
586
  }
434
- });
435
- } else {
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;
587
+ return line.pattern;
442
588
  } else {
443
- canFix = true;
444
- headerLines = line.split(/\r?\n/);
445
- fixLines = /** @type {string[]} */ (headerLines);
589
+ fixLines.push(/** @type {string} */ (line));
590
+ return line;
446
591
  }
447
- }
592
+ });
593
+
594
+
595
+ const numLines = /** @type {number} */ (options.trailingEmptyLines?.minimum);
448
596
 
449
597
  return {
450
598
  /**
@@ -469,7 +617,12 @@ const headerRule = {
469
617
  }
470
618
  },
471
619
  messageId: "missingHeader",
472
- fix: genPrependFixer(commentType, context, fixLines, eol, numNewlines)
620
+ fix: genPrependFixer(
621
+ commentType,
622
+ context,
623
+ fixLines,
624
+ eol,
625
+ numLines)
473
626
  });
474
627
  return;
475
628
  }
@@ -495,7 +648,13 @@ const headerRule = {
495
648
  commentType: commentType
496
649
  },
497
650
  fix: canFix
498
- ? genReplaceFixer(commentType, context, leadingComments, fixLines, eol, numNewlines)
651
+ ? genReplaceFixer(
652
+ commentType,
653
+ context,
654
+ leadingComments,
655
+ fixLines,
656
+ eol,
657
+ numLines)
499
658
  : null
500
659
  });
501
660
  return;
@@ -518,7 +677,13 @@ const headerRule = {
518
677
  },
519
678
  messageId: "incorrectHeader",
520
679
  fix: canFix
521
- ? genReplaceFixer(commentType, context, leadingComments, fixLines, eol, numNewlines)
680
+ ? genReplaceFixer(
681
+ commentType,
682
+ context,
683
+ leadingComments,
684
+ fixLines,
685
+ eol,
686
+ numLines)
522
687
  : null
523
688
  });
524
689
  return;
@@ -544,7 +709,7 @@ const headerRule = {
544
709
  leadingComments,
545
710
  fixLines,
546
711
  eol,
547
- numNewlines)
712
+ numLines)
548
713
  : null
549
714
  });
550
715
  return;
@@ -577,7 +742,7 @@ const headerRule = {
577
742
  leadingComments,
578
743
  fixLines,
579
744
  eol,
580
- numNewlines)
745
+ numLines)
581
746
  });
582
747
  return;
583
748
  }
@@ -599,7 +764,7 @@ const headerRule = {
599
764
  leadingComments,
600
765
  fixLines,
601
766
  eol,
602
- numNewlines)
767
+ numLines)
603
768
  : null
604
769
  });
605
770
  return;
@@ -621,7 +786,7 @@ const headerRule = {
621
786
  leadingComments,
622
787
  fixLines,
623
788
  eol,
624
- numNewlines)
789
+ numLines)
625
790
  : null
626
791
  });
627
792
  return;
@@ -647,7 +812,7 @@ const headerRule = {
647
812
  leadingComments,
648
813
  fixLines,
649
814
  eol,
650
- numNewlines)
815
+ numLines)
651
816
  : null
652
817
  });
653
818
  return;
@@ -659,13 +824,13 @@ const headerRule = {
659
824
  const commentRange = leadingComments[headerLines.length - 1].range;
660
825
  assertDefined(commentRange);
661
826
  const actualLeadingEmptyLines = leadingEmptyLines(sourceCode.text.substring(commentRange[1]));
662
- const missingEmptyLines = numNewlines - actualLeadingEmptyLines;
827
+ const missingEmptyLines = numLines - actualLeadingEmptyLines;
663
828
  if (missingEmptyLines > 0) {
664
829
  context.report({
665
830
  loc: missingEmptyLinesViolationLoc(leadingComments, actualLeadingEmptyLines),
666
831
  messageId: "noNewlineAfterHeader",
667
832
  data: {
668
- expected: numNewlines,
833
+ expected: numLines,
669
834
  actual: actualLeadingEmptyLines
670
835
  },
671
836
  fix: genEmptyLinesFixer(leadingComments, eol, missingEmptyLines)
@@ -804,7 +969,13 @@ const headerRule = {
804
969
  messageId: errorMessageId,
805
970
  data: errorMessageData,
806
971
  fix: canFix
807
- ? genReplaceFixer(commentType, context, leadingComments, fixLines, eol, numNewlines)
972
+ ? genReplaceFixer(
973
+ commentType,
974
+ context,
975
+ leadingComments,
976
+ fixLines,
977
+ eol,
978
+ numLines)
808
979
  : null
809
980
  });
810
981
  return;
@@ -812,13 +983,13 @@ const headerRule = {
812
983
 
813
984
  const actualLeadingEmptyLines =
814
985
  leadingEmptyLines(sourceCode.text.substring(firstLeadingCommentRange[1]));
815
- const missingEmptyLines = numNewlines - actualLeadingEmptyLines;
986
+ const missingEmptyLines = numLines - actualLeadingEmptyLines;
816
987
  if (missingEmptyLines > 0) {
817
988
  context.report({
818
989
  loc: missingEmptyLinesViolationLoc(leadingComments, actualLeadingEmptyLines),
819
990
  messageId: "noNewlineAfterHeader",
820
991
  data: {
821
- expected: numNewlines,
992
+ expected: numLines,
822
993
  actual: actualLeadingEmptyLines
823
994
  },
824
995
  fix: genEmptyLinesFixer(leadingComments, eol, missingEmptyLines)
@@ -47,22 +47,31 @@ const schema = Object.freeze({
47
47
  definitions: {
48
48
  commentType: {
49
49
  type: "string",
50
- enum: [commentTypeOptions.block, commentTypeOptions.line]
50
+ enum: [commentTypeOptions.block, commentTypeOptions.line],
51
+ description: "Type of comment to expect as the header."
52
+ },
53
+ regExp: {
54
+ type: "object",
55
+ properties: {
56
+ source: { type: "string" }
57
+ },
58
+ required: ["source"],
59
+ additionalProperties: true,
51
60
  },
52
61
  line: {
53
62
  anyOf: [
54
- {
55
- type: "string"
56
- },
63
+ { type: "string" },
64
+ { $ref: "#/definitions/regExp" },
57
65
  {
58
66
  type: "object",
59
67
  properties: {
60
68
  pattern: {
61
- type: "string"
69
+ anyOf: [
70
+ { type: "string" },
71
+ { $ref: "#/definitions/regExp" },
72
+ ]
62
73
  },
63
- template: {
64
- type: "string"
65
- }
74
+ template: { type: "string" }
66
75
  },
67
76
  required: ["pattern"],
68
77
  additionalProperties: false
@@ -71,9 +80,7 @@ const schema = Object.freeze({
71
80
  },
72
81
  headerLines: {
73
82
  anyOf: [
74
- {
75
- $ref: "#/definitions/line"
76
- },
83
+ { $ref: "#/definitions/line" },
77
84
  {
78
85
  type: "array",
79
86
  items: {
@@ -86,18 +93,89 @@ const schema = Object.freeze({
86
93
  type: "integer",
87
94
  minimum: 0
88
95
  },
96
+ lineEndings: {
97
+ type: "string",
98
+ enum: [lineEndingOptions.unix, lineEndingOptions.windows, lineEndingOptions.os],
99
+ description: "Line endings to use when aut-fixing the violations. Defaults to 'os' which means 'same as " +
100
+ "system'."
101
+ },
89
102
  settings: {
90
103
  type: "object",
91
104
  properties: {
92
- lineEndings: {
105
+ lineEndings: { $ref: "#/definitions/lineEndings" },
106
+ },
107
+ additionalProperties: false
108
+ },
109
+ fileBasedHeader: {
110
+ type: "object",
111
+ properties: {
112
+ file: {
93
113
  type: "string",
94
- enum: [lineEndingOptions.unix, lineEndingOptions.windows]
114
+ description: "Name of a file relative to the current directory (no back-tracking) that contains " +
115
+ "the header template. It should contain a single block comment or a contiguous number of " +
116
+ "line comments."
117
+ },
118
+ encoding: {
119
+ type: "string",
120
+ description: "Character encoding to use when parsing the file. Valid values are all encodings " +
121
+ "that can be passed to `fs.readFileSync()`. If not specified, 'utf8' would be used."
122
+ // NOTE: default value not supported by the ajv schema
123
+ // validator and there is no way to fix it through the
124
+ // plugin's `meta.defaultOptions`.
95
125
  }
96
126
  },
127
+ required: ["file"],
97
128
  additionalProperties: false
98
129
  },
130
+ inlineHeader: {
131
+ type: "object",
132
+ properties: {
133
+ commentType: { $ref: "#/definitions/commentType" },
134
+ lines: {
135
+ type: "array",
136
+ items: { $ref: "#/definitions/line" },
137
+ description: "List of each line of the header - each being a string to match exactly or a " +
138
+ "combination of a regex pattern to match and an optional template string as the fix."
139
+ }
140
+ },
141
+ required: ["commentType", "lines"],
142
+ additionalProperties: false
143
+ },
144
+ trailingEmptyLines: {
145
+ type: "object",
146
+ properties: {
147
+ minimum: {
148
+ type: "number",
149
+ description: "Number of empty lines required after the header. Defaults to 1.",
150
+ }
151
+ },
152
+ additionalProperties: false,
153
+ description: "Configuration for how to validate and fix the set of empty lines after the header."
154
+ },
155
+ newOptions: {
156
+ type: "object",
157
+ properties: {
158
+ header: {
159
+ anyOf: [
160
+ { $ref: "#/definitions/fileBasedHeader" },
161
+ { $ref: "#/definitions/inlineHeader" }
162
+ ]
163
+ },
164
+ lineEndings: { $ref: "#/definitions/lineEndings" },
165
+ trailingEmptyLines: { $ref: "#/definitions/trailingEmptyLines" }
166
+ },
167
+ required: ["header"],
168
+ additionalProperties: false,
169
+ description: "Object-based extensible configuration format to use with the `header` rule."
170
+ },
99
171
  options: {
100
172
  anyOf: [
173
+ {
174
+ type: "array",
175
+ minItems: 1,
176
+ maxItems: 1,
177
+ items: { $ref: "#/definitions/newOptions" }
178
+ },
101
179
  {
102
180
  type: "array",
103
181
  minItems: 1,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tony.ganchev/eslint-plugin-header",
3
- "version": "3.1.13",
3
+ "version": "3.2.1",
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
  "types": "index.d.ts",
@@ -52,7 +52,7 @@
52
52
  ],
53
53
  "repository": {
54
54
  "type": "git",
55
- "url": "https://github.com/tonyganchev/eslint-plugin-header.git"
55
+ "url": "git+https://github.com/tonyganchev/eslint-plugin-header.git"
56
56
  },
57
57
  "author": "Stuart Knightley",
58
58
  "license": "MIT",
@@ -1,3 +1,3 @@
1
- declare function _exports(commentText: string): ["block" | "line", string | string[]];
1
+ declare function _exports(commentText: string): ["block" | "line", string[]];
2
2
  export = _exports;
3
3
  //# sourceMappingURL=comment-parser.d.ts.map