@sarj/eslint-plugin 15.17.4 → 15.17.6

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/dist/index.js CHANGED
@@ -1,3 +1,211 @@
1
+ // src/library-policy.ts
2
+ var LIBRARY_POLICY = [
3
+ {
4
+ "id": "LIB101",
5
+ "module": "request",
6
+ "note": "Standards standardizes HTTP clients on Ky; review errors, retries, hooks, and response parsing.",
7
+ "replacement": "ky"
8
+ },
9
+ {
10
+ "id": "LIB101",
11
+ "module": "node-fetch",
12
+ "note": "Standards standardizes HTTP clients on Ky; review errors, retries, hooks, and response parsing.",
13
+ "replacement": "ky"
14
+ },
15
+ {
16
+ "id": "LIB101",
17
+ "module": "cross-fetch",
18
+ "note": "Standards standardizes HTTP clients on Ky; review errors, retries, hooks, and response parsing.",
19
+ "replacement": "ky"
20
+ },
21
+ {
22
+ "id": "LIB101",
23
+ "module": "isomorphic-fetch",
24
+ "note": "Standards standardizes HTTP clients on Ky; review errors, retries, hooks, and response parsing.",
25
+ "replacement": "ky"
26
+ },
27
+ {
28
+ "id": "LIB101",
29
+ "module": "axios",
30
+ "note": "Standards standardizes HTTP clients on Ky; review errors, retries, hooks, and response parsing.",
31
+ "replacement": "ky"
32
+ },
33
+ {
34
+ "id": "LIB102",
35
+ "module": "moment",
36
+ "note": "Standards standardizes date utilities on date-fns; migration is not API-compatible.",
37
+ "replacement": "date-fns"
38
+ },
39
+ {
40
+ "id": "LIB102",
41
+ "module": "dayjs",
42
+ "note": "Standards standardizes date utilities on date-fns; migration is not API-compatible.",
43
+ "replacement": "date-fns"
44
+ },
45
+ {
46
+ "id": "LIB103",
47
+ "module": "lodash",
48
+ "note": "Standards standardizes collection utilities on Remeda and native APIs.",
49
+ "replacement": "remeda"
50
+ },
51
+ {
52
+ "id": "LIB103",
53
+ "module": "lodash-es",
54
+ "note": "Standards standardizes collection utilities on Remeda and native APIs.",
55
+ "replacement": "remeda"
56
+ },
57
+ {
58
+ "id": "LIB103",
59
+ "module": "underscore",
60
+ "note": "Standards standardizes collection utilities on Remeda and native APIs.",
61
+ "replacement": "remeda"
62
+ },
63
+ {
64
+ "id": "LIB104",
65
+ "module": "classnames",
66
+ "note": "Use clsx for conditional class-name composition.",
67
+ "replacement": "clsx"
68
+ },
69
+ {
70
+ "id": "LIB105",
71
+ "module": "joi",
72
+ "note": "Standards standardizes runtime validation on Zod; schemas are not drop-in compatible.",
73
+ "replacement": "zod"
74
+ },
75
+ {
76
+ "id": "LIB105",
77
+ "module": "yup",
78
+ "note": "Standards standardizes runtime validation on Zod; schemas are not drop-in compatible.",
79
+ "replacement": "zod"
80
+ },
81
+ {
82
+ "id": "LIB105",
83
+ "module": "superstruct",
84
+ "note": "Standards standardizes runtime validation on Zod; schemas are not drop-in compatible.",
85
+ "replacement": "zod"
86
+ },
87
+ {
88
+ "id": "LIB105",
89
+ "module": "io-ts",
90
+ "note": "Standards standardizes runtime validation on Zod; schemas are not drop-in compatible.",
91
+ "replacement": "zod"
92
+ },
93
+ {
94
+ "id": "LIB105",
95
+ "module": "runtypes",
96
+ "note": "Standards standardizes runtime validation on Zod; schemas are not drop-in compatible.",
97
+ "replacement": "zod"
98
+ },
99
+ {
100
+ "id": "LIB106",
101
+ "module": "jsonwebtoken",
102
+ "note": "Use jose; review key formats and async signing and verification APIs.",
103
+ "replacement": "jose"
104
+ },
105
+ {
106
+ "id": "LIB107",
107
+ "module": "express",
108
+ "note": "Standards standardizes servers on Hono; Node deployments also need @hono/node-server.",
109
+ "replacement": "hono"
110
+ },
111
+ {
112
+ "id": "LIB107",
113
+ "module": "koa",
114
+ "note": "Standards standardizes servers on Hono; Node deployments also need @hono/node-server.",
115
+ "replacement": "hono"
116
+ },
117
+ {
118
+ "id": "LIB108",
119
+ "module": "jest",
120
+ "note": "Standards standardizes tests on Vitest; review globals, timers, mocks, and environment setup.",
121
+ "replacement": "vitest"
122
+ },
123
+ {
124
+ "id": "LIB108",
125
+ "module": "mocha",
126
+ "note": "Standards standardizes tests on Vitest; review globals, timers, mocks, and environment setup.",
127
+ "replacement": "vitest"
128
+ },
129
+ {
130
+ "id": "LIB109",
131
+ "module": "sinon",
132
+ "note": "Use Vitest spies, mocks, and fake timers instead of Sinon.",
133
+ "replacement": "Vitest mocks"
134
+ },
135
+ {
136
+ "id": "LIB110",
137
+ "module": "commander",
138
+ "note": "Standards standardizes command-line interfaces on citty.",
139
+ "replacement": "citty"
140
+ },
141
+ {
142
+ "id": "LIB110",
143
+ "module": "yargs",
144
+ "note": "Standards standardizes command-line interfaces on citty.",
145
+ "replacement": "citty"
146
+ },
147
+ {
148
+ "id": "LIB111",
149
+ "module": "bluebird",
150
+ "note": "Use native Promise, adding p-limit or p-map only for the extensions actually needed.",
151
+ "replacement": "native Promise"
152
+ },
153
+ {
154
+ "id": "LIB112",
155
+ "module": "rimraf",
156
+ "note": "Prefer node:fs/promises; verify recursive removal, copy, path, and error semantics.",
157
+ "replacement": "node:fs/promises"
158
+ },
159
+ {
160
+ "id": "LIB112",
161
+ "module": "fs-extra",
162
+ "note": "Prefer node:fs/promises; verify recursive removal, copy, path, and error semantics.",
163
+ "replacement": "node:fs/promises"
164
+ },
165
+ {
166
+ "id": "LIB113",
167
+ "module": "abort-controller",
168
+ "note": "Node 22 provides global AbortController.",
169
+ "replacement": "AbortController"
170
+ },
171
+ {
172
+ "id": "LIB114",
173
+ "module": "querystring",
174
+ "note": "Use URLSearchParams and explicitly review repeated keys, escaping, arrays, and object coercion.",
175
+ "replacement": "URLSearchParams"
176
+ },
177
+ {
178
+ "id": "LIB115",
179
+ "module": "dotenv",
180
+ "note": "Standards standardizes environment loading on @dotenvx/dotenvx.",
181
+ "replacement": "@dotenvx/dotenvx"
182
+ },
183
+ {
184
+ "id": "LIB116",
185
+ "module": "chalk",
186
+ "note": "Use picocolors for terminal colors.",
187
+ "replacement": "picocolors"
188
+ },
189
+ {
190
+ "id": "LIB117",
191
+ "module": "faker",
192
+ "note": "The original faker package is abandoned; use @faker-js/faker.",
193
+ "replacement": "@faker-js/faker"
194
+ },
195
+ {
196
+ "id": "LIB118",
197
+ "module": "node-sass",
198
+ "note": "node-sass is end-of-life; use Dart Sass.",
199
+ "replacement": "sass"
200
+ },
201
+ {
202
+ "id": "LIB119",
203
+ "module": "tslint",
204
+ "note": "TSLint is deprecated; use ESLint with typescript-eslint.",
205
+ "replacement": "eslint"
206
+ }
207
+ ];
208
+
1
209
  // src/rules/enforce-file-structure.ts
2
210
  import { AST_NODE_TYPES } from "@typescript-eslint/utils";
3
211
 
@@ -1189,6 +1397,10 @@ function normalizeToken(word) {
1189
1397
  return lower.length > TOKEN_PLURAL_MIN && lower.endsWith("s") && !lower.endsWith("ss") ? lower.slice(0, -1) : lower;
1190
1398
  }
1191
1399
  function restatableStatementBelow(comment, sourceCode) {
1400
+ const node = restatableStatementNodeBelow(comment, sourceCode);
1401
+ return node === null ? null : sourceCode.getText(node);
1402
+ }
1403
+ function restatableStatementNodeBelow(comment, sourceCode) {
1192
1404
  const token = sourceCode.getTokenAfter(comment, { includeComments: false });
1193
1405
  if (token === null || token.loc.start.line !== comment.loc.end.line + 1) return null;
1194
1406
  for (let node = sourceCode.getNodeByRangeIndex(token.range[0]); node != null && node.type !== AST_NODE_TYPES6.Program; node = node.parent) {
@@ -1199,7 +1411,7 @@ function restatableStatementBelow(comment, sourceCode) {
1199
1411
  if (node.type === AST_NODE_TYPES6.VariableDeclaration && isTrivialInitializer(node)) {
1200
1412
  return null;
1201
1413
  }
1202
- return sourceCode.getText(node);
1414
+ return node;
1203
1415
  }
1204
1416
  return null;
1205
1417
  }
@@ -6425,7 +6637,7 @@ var no_repeated_string_literal_default = createRule({
6425
6637
  });
6426
6638
 
6427
6639
  // src/rules/no-restated-comment.ts
6428
- import { AST_NODE_TYPES as AST_NODE_TYPES28 } from "@typescript-eslint/utils";
6640
+ import { AST_NODE_TYPES as AST_NODE_TYPES28, AST_TOKEN_TYPES } from "@typescript-eslint/utils";
6429
6641
 
6430
6642
  // src/rules/_comment-edits.ts
6431
6643
  import "@typescript-eslint/utils";
@@ -6467,25 +6679,31 @@ var MODALITY_RE = /\b(?:can|could|should|shall|may|might|must|will|would|cannot)
6467
6679
  var LEAD_IN_RE = /:$/;
6468
6680
  var EMPHASIS_RE = /\*\w[^*]*\*|`[^`]+`/;
6469
6681
  var NEGATION_WORD_RE = /\b(?:no|not|never|neither|nor|without|none|non)\b/i;
6682
+ var SEMANTIC_RELATION_RE = /\b(?:only|if|unless|when|while|except|each|every|any|all|before|after|until|since|again|once|twice|already|still|from|to|into|onto|back|versus|rather|instead)\b/i;
6470
6683
  var ACTION_STMT_RE = /[\w.$\])]\s*\(|^\s*(?:return|throw|await|yield)\b/;
6471
6684
  var NON_ASCII_LETTER_RE = /[^\p{ASCII}\p{N}\p{P}\p{Z}]/u;
6472
6685
  var WALL_NARRATION_RE2 = /^(?:(?:\d+[.)]|(?:phase|step)\s+\d+\s*:?)\s*)?(?:add|build|call|check|compute|copy|count|create|fetch|filter|find|get|handle|load|map|merge|parse|process|read|remove|return|save|send|set|sort|store|update|validate|write)(?:s|es|d|ed|ing)?\b/i;
6473
6686
  var WALL_CLUSTER_MAX_LINE_GAP = 8;
6474
6687
  var WALL_CLUSTER_MIN_COMMENTS = 3;
6475
6688
  var NO_RESTATED_COMMENT_DOCUMENTATION = {
6476
- summary: "Flag a single-line comment whose every word already appears on the statement below it.",
6689
+ summary: "Flag short standalone comments that repeat the adjacent statement's identifiers.",
6477
6690
  rationale: "A comment that only repeats code adds no context and can become stale independently.",
6478
- remediation: "Delete the comment or replace it with the reason, constraint, or consequence absent from the code.",
6691
+ remediation: "Remove a genuine restatement; retain conditions, constraints, rationale, and information absent from the statement.",
6479
6692
  category: "maintainability",
6480
6693
  autofix: "suggestion",
6481
- limitations: ["Directives, protected references, questions, multi-line prose, comments with novel content, and generated files are excluded."],
6694
+ limitations: [
6695
+ "Only standalone line comments of two to eight words with at least two content tokens directly above a supported single-line statement are inspected; one-word headings and sentence-ending punctuation are excluded.",
6696
+ "Evidence comes from that statement's identifier tokens, not strings, template text, comments, or neighboring statements. Stopwords and inflection folding are heuristic, not proof of semantic equivalence.",
6697
+ "Directives, protected references, conditions, restrictions, ordering, repetition, direction, questions, prose paragraphs, sibling-group labels, novel content, and generated files are excluded. Deletion is an optional suggestion, never an automatic fix.",
6698
+ "The conservative sibling-group exemption includes enclosing sibling groups and declaration/type-query pairs; it can miss genuine restatements inside those groups."
6699
+ ],
6482
6700
  examples: [
6483
- { id: "reason-comment", title: "Keep the reason the code cannot express", outcome: "no-match", files: [{ path: "src/cache.ts", source: "// Serialize because the cache key is stable across deploys.\nconst key = serialize(input);" }], focusPath: "src/cache.ts", expectedCount: 0, public: true },
6701
+ { id: "reason-comment", title: "Keep a condition the statement does not establish", outcome: "no-match", files: [{ path: "src/cache.ts", source: "// Serialize key only after validation.\nconst key = serialize(input);" }], focusPath: "src/cache.ts", expectedCount: 0, public: true },
6484
6702
  { id: "restated-comment", title: "Remove a comment that repeats the statement", outcome: "match", files: [{ path: "src/cache.ts", source: "// Serialize key\nconst key = serialize(input);" }], focusPath: "src/cache.ts", expectedCount: 1, public: true }
6485
6703
  ]
6486
6704
  };
6487
- function areAdjacentLineComments2(a, b) {
6488
- return a !== void 0 && b !== void 0 && a.type === "Line" && b.type === "Line" && b.loc.start.line === a.loc.end.line + 1;
6705
+ function areAdjacentLineComments2(a, b, isStandalone) {
6706
+ return a !== void 0 && b !== void 0 && a.type === "Line" && b.type === "Line" && isStandalone(a) && isStandalone(b) && b.loc.start.line === a.loc.end.line + 1;
6489
6707
  }
6490
6708
  function headsSiblingRun(node) {
6491
6709
  const parent = node.parent;
@@ -6503,12 +6721,12 @@ var no_restated_comment_default = createRule({
6503
6721
  type: "suggestion",
6504
6722
  hasSuggestions: true,
6505
6723
  docs: {
6506
- description: "Flag a single-line comment whose every word already appears on the statement below it."
6724
+ description: NO_RESTATED_COMMENT_DOCUMENTATION.summary
6507
6725
  },
6508
6726
  schema: [],
6509
6727
  messages: {
6510
6728
  deleteComment: "Delete the redundant comment.",
6511
- restatesLineBelow: "Comment restates the statement below it \u2014 delete it, or replace it with the *why*; the code already carries the *what*."
6729
+ restatesLineBelow: "Comment repeats the adjacent statement's identifiers \u2014 consider removing it; retain any condition, constraint, or rationale absent from the code."
6512
6730
  }
6513
6731
  },
6514
6732
  defaultOptions: [],
@@ -6517,19 +6735,30 @@ var no_restated_comment_default = createRule({
6517
6735
  return {};
6518
6736
  }
6519
6737
  const sourceCode = context.sourceCode;
6520
- const lines = sourceCode.lines;
6521
6738
  function isStandalone(comment) {
6522
6739
  const before = sourceCode.getTokenBefore(comment, { includeComments: false });
6523
6740
  return !before || before.loc.end.line < comment.loc.start.line;
6524
6741
  }
6525
- function labelsASiblingRun(comment) {
6526
- const token = sourceCode.getTokenAfter(comment, { includeComments: false });
6527
- if (token === null) return false;
6528
- for (let node = sourceCode.getNodeByRangeIndex(token.range[0]); node != null && node.type !== AST_NODE_TYPES28.Program; node = node.parent) {
6742
+ function labelsASiblingRun(statement) {
6743
+ for (let node = statement; node !== void 0 && node.type !== AST_NODE_TYPES28.Program; node = node.parent) {
6529
6744
  if (headsSiblingRun(node)) return true;
6530
6745
  }
6531
6746
  return false;
6532
6747
  }
6748
+ function headsValueTypeGroup(statement) {
6749
+ if (statement.type !== AST_NODE_TYPES28.VariableDeclaration) return false;
6750
+ const parent = statement.parent;
6751
+ if (!("body" in parent) || !Array.isArray(parent.body)) return false;
6752
+ const body2 = parent.body;
6753
+ const next = body2[body2.indexOf(statement) + 1];
6754
+ if (next?.type !== AST_NODE_TYPES28.TSTypeAliasDeclaration) return false;
6755
+ const names = new Set(statement.declarations.flatMap(({ id }) => id.type === AST_NODE_TYPES28.Identifier ? [id.name] : []));
6756
+ const tokens = sourceCode.getTokens(next);
6757
+ return tokens.some((token, index) => {
6758
+ const nextToken = tokens[index + 1];
6759
+ return token.value === "typeof" && nextToken?.type === AST_TOKEN_TYPES.Identifier && names.has(nextToken.value);
6760
+ });
6761
+ }
6533
6762
  return {
6534
6763
  Program() {
6535
6764
  const comments = sourceCode.getAllComments();
@@ -6557,7 +6786,7 @@ var no_restated_comment_default = createRule({
6557
6786
  if (comment === void 0 || comment.type !== "Line") continue;
6558
6787
  if (wallMembers.has(comment)) continue;
6559
6788
  if (!isStandalone(comment)) continue;
6560
- if (areAdjacentLineComments2(comments[i - 1], comment) || areAdjacentLineComments2(comment, comments[i + 1])) {
6789
+ if (areAdjacentLineComments2(comments[i - 1], comment, isStandalone) || areAdjacentLineComments2(comment, comments[i + 1], isStandalone)) {
6561
6790
  continue;
6562
6791
  }
6563
6792
  const body2 = comment.value.replace(/^\/*/, "").trim();
@@ -6565,17 +6794,19 @@ var no_restated_comment_default = createRule({
6565
6794
  if (DIRECTIVE_RE3.test(body2) || CODEY_RE.test(body2) || BANNERISH_RE.test(body2)) continue;
6566
6795
  if (NON_ASCII_LETTER_RE.test(body2) || isProtected(body2)) continue;
6567
6796
  if (MODALITY_RE.test(body2) || LEAD_IN_RE.test(body2) || EMPHASIS_RE.test(body2)) continue;
6568
- if (NEGATION_WORD_RE.test(body2)) continue;
6569
- if (body2.split(/\s+/).length > MAX_WORDS) continue;
6797
+ if (NEGATION_WORD_RE.test(body2) || SEMANTIC_RELATION_RE.test(body2)) continue;
6798
+ const wordCount2 = body2.split(/\s+/).length;
6799
+ if (wordCount2 < 2 || wordCount2 > MAX_WORDS || /[.!?]$/.test(body2)) continue;
6570
6800
  const tokens = contentTokens(body2);
6571
6801
  if (tokens.length < MIN_CONTENT_TOKENS) continue;
6572
- const statement = restatableStatementBelow(comment, sourceCode);
6573
- if (statement === null) continue;
6802
+ const statementNode = restatableStatementNodeBelow(comment, sourceCode);
6803
+ if (statementNode === null) continue;
6804
+ const statement = sourceCode.getText(statementNode);
6574
6805
  if (restatesStatementHead(body2, statement)) continue;
6575
- const line = lines[comment.loc.start.line] ?? "";
6576
- if (!ACTION_STMT_RE.test(line)) continue;
6577
- if (labelsASiblingRun(comment)) continue;
6578
- if (restates(tokens, codeTokens(line))) {
6806
+ if (!ACTION_STMT_RE.test(statement)) continue;
6807
+ if (labelsASiblingRun(statementNode) || headsValueTypeGroup(statementNode)) continue;
6808
+ const identifiers = sourceCode.getTokens(statementNode).filter((token) => token.type === AST_TOKEN_TYPES.Identifier).map((token) => token.value).join(" ");
6809
+ if (restates(tokens, codeTokens(identifiers))) {
6579
6810
  const removal = wholeLineRemovalRange(sourceCode.text, comment);
6580
6811
  context.report({
6581
6812
  node: comment,
@@ -8870,10 +9101,10 @@ var no_trailing_value_narration_default = createRule({
8870
9101
  });
8871
9102
 
8872
9103
  // src/rules/no-declaration-comment-wall.ts
8873
- import { AST_NODE_TYPES as AST_NODE_TYPES36, AST_TOKEN_TYPES as AST_TOKEN_TYPES2 } from "@typescript-eslint/utils";
9104
+ import { AST_NODE_TYPES as AST_NODE_TYPES36, AST_TOKEN_TYPES as AST_TOKEN_TYPES3 } from "@typescript-eslint/utils";
8874
9105
 
8875
9106
  // src/rules/_comment-wall.ts
8876
- import { AST_NODE_TYPES as AST_NODE_TYPES35, AST_TOKEN_TYPES } from "@typescript-eslint/utils";
9107
+ import { AST_NODE_TYPES as AST_NODE_TYPES35, AST_TOKEN_TYPES as AST_TOKEN_TYPES2 } from "@typescript-eslint/utils";
8877
9108
  var WALL_DEFAULTS = {
8878
9109
  // Below three rows "a wall" is not a fair description of what the reader sees.
8879
9110
  minCommentedMembers: 3,
@@ -8939,7 +9170,7 @@ function commentBody(comment) {
8939
9170
  return comment.value.replace(/^\*+/, "").replace(/^[ \t]*\*[ \t]?/gm, "").trim();
8940
9171
  }
8941
9172
  function hasJsDocTag(comment) {
8942
- return comment.type === AST_TOKEN_TYPES.Block && comment.value.startsWith("*") && /(?:^|\s)@[A-Za-z][\w-]*\b/u.test(commentBody(comment));
9173
+ return comment.type === AST_TOKEN_TYPES2.Block && comment.value.startsWith("*") && /(?:^|\s)@[A-Za-z][\w-]*\b/u.test(commentBody(comment));
8943
9174
  }
8944
9175
  function carriesValue(body2) {
8945
9176
  return isProtected(body2) || VALUE_TAG_RE2.test(body2) || DEFAULT_RE.test(body2) || DIGIT_RE.test(body2) || UNIT_WORD_RE.test(body2) || EXAMPLE_RE.test(body2) || BANNER_RE.test(body2) || NON_ASCII_LETTER_RE2.test(body2);
@@ -9075,7 +9306,7 @@ var no_declaration_comment_wall_default = createRule({
9075
9306
  const before = sourceCode.getTokenBefore(lead, { includeComments: false });
9076
9307
  if (before === null || before.loc.end.line < lead.loc.start.line) {
9077
9308
  const previousLine = endingOn.get(lead.loc.start.line - 1);
9078
- if (lead.type === AST_TOKEN_TYPES2.Line && previousLine?.type === AST_TOKEN_TYPES2.Line && previousLine.loc.start.column === lead.loc.start.column) {
9309
+ if (lead.type === AST_TOKEN_TYPES3.Line && previousLine?.type === AST_TOKEN_TYPES3.Line && previousLine.loc.start.column === lead.loc.start.column) {
9079
9310
  return void 0;
9080
9311
  }
9081
9312
  return lead;
@@ -9318,7 +9549,7 @@ var no_union_in_comment_default = createRule({
9318
9549
  });
9319
9550
 
9320
9551
  // src/rules/no-type-member-comment-wall.ts
9321
- import { AST_NODE_TYPES as AST_NODE_TYPES38, AST_TOKEN_TYPES as AST_TOKEN_TYPES3 } from "@typescript-eslint/utils";
9552
+ import { AST_NODE_TYPES as AST_NODE_TYPES38, AST_TOKEN_TYPES as AST_TOKEN_TYPES4 } from "@typescript-eslint/utils";
9322
9553
  var NO_TYPE_MEMBER_COMMENT_WALL_DOCUMENTATION = {
9323
9554
  summary: "Flag an object type whose member comments mostly re-spell the members' own names and types.",
9324
9555
  rationale: "Repetitive member comments add scanning cost while hiding the comments that describe facts absent from the type.",
@@ -9383,7 +9614,7 @@ var no_type_member_comment_wall_default = createRule({
9383
9614
  const before = sourceCode.getTokenBefore(lead, { includeComments: false });
9384
9615
  if (before === null || before.loc.end.line < lead.loc.start.line) {
9385
9616
  const previousLine = endingOn.get(lead.loc.start.line - 1);
9386
- if (lead.type === AST_TOKEN_TYPES3.Line && previousLine?.type === AST_TOKEN_TYPES3.Line && previousLine.loc.start.column === lead.loc.start.column) {
9617
+ if (lead.type === AST_TOKEN_TYPES4.Line && previousLine?.type === AST_TOKEN_TYPES4.Line && previousLine.loc.start.column === lead.loc.start.column) {
9387
9618
  return void 0;
9388
9619
  }
9389
9620
  return lead;
@@ -19516,16 +19747,17 @@ var RULES = {
19516
19747
  };
19517
19748
  var meta = {
19518
19749
  name: "@sarj/eslint-plugin",
19519
- version: "15.17.4"
19750
+ version: "15.17.6"
19520
19751
  };
19521
- var APPLICATION_ONLY_RULES = [
19522
- "no-restricted-library-load",
19523
- "prefer-native-random-uuid",
19524
- "prefer-shadcn-primitives"
19525
- ];
19752
+ var APPLICATION_ONLY_RULES = [];
19753
+ var LIBRARY_IMPORT_POLICY = ["error", {
19754
+ paths: LIBRARY_POLICY.map(({ module, note }) => ({ name: module, message: note })),
19755
+ patterns: LIBRARY_POLICY.map(({ module, note }) => ({ group: [`${module}/*`], message: note }))
19756
+ }];
19526
19757
  var ADVISORY_RULES = [
19527
19758
  "@sarj/excessive-commentary",
19528
19759
  "@sarj/no-bespoke-api-case-conversion",
19760
+ "@sarj/no-restated-comment",
19529
19761
  "@sarj/prefer-millisecond-control-duration-schema",
19530
19762
  "@sarj/prefer-module-level-refined-schema",
19531
19763
  "@sarj/prefer-multi-value-zod-literal",
@@ -19541,6 +19773,10 @@ var ADVISORY_RULES = [
19541
19773
  "@sarj/sole-export-matches-filename"
19542
19774
  ];
19543
19775
  var RECOMMENDED_RULES = {
19776
+ "no-restricted-imports": LIBRARY_IMPORT_POLICY,
19777
+ "@sarj/no-restricted-library-load": ["error", { libraries: LIBRARY_POLICY }],
19778
+ "@sarj/prefer-native-random-uuid": "error",
19779
+ "@sarj/prefer-shadcn-primitives": "error",
19544
19780
  "@sarj/excessive-commentary": "warn",
19545
19781
  "@sarj/interface-contract-members-private": "error",
19546
19782
  "@sarj/iac-source-coupled-test": "error",
@@ -19569,7 +19805,7 @@ var RECOMMENDED_RULES = {
19569
19805
  "@sarj/no-production-browser-source-maps": "error",
19570
19806
  "@sarj/no-repeated-string-literal": "error",
19571
19807
  "@sarj/no-router-refresh-polling": "error",
19572
- "@sarj/no-restated-comment": "error",
19808
+ "@sarj/no-restated-comment": "warn",
19573
19809
  "@sarj/no-restated-jsdoc": "error",
19574
19810
  "@sarj/no-secret-in-log": "error",
19575
19811
  "@sarj/no-server-env-in-client-component": "error",
@@ -19630,6 +19866,10 @@ var RECOMMENDED_RULES = {
19630
19866
  "@sarj/require-pascal-case-zod-schema-name": "error"
19631
19867
  };
19632
19868
  var STRICT_RULES = {
19869
+ "no-restricted-imports": LIBRARY_IMPORT_POLICY,
19870
+ "@sarj/no-restricted-library-load": ["error", { libraries: LIBRARY_POLICY }],
19871
+ "@sarj/prefer-native-random-uuid": "error",
19872
+ "@sarj/prefer-shadcn-primitives": "error",
19633
19873
  "@sarj/excessive-commentary": "warn",
19634
19874
  "@sarj/interface-contract-members-private": "error",
19635
19875
  "@sarj/iac-source-coupled-test": "error",
@@ -19661,7 +19901,7 @@ var STRICT_RULES = {
19661
19901
  "@sarj/no-raw-fetch-outside-clients": "error",
19662
19902
  "@sarj/no-repeated-string-literal": "error",
19663
19903
  "@sarj/no-router-refresh-polling": "error",
19664
- "@sarj/no-restated-comment": "error",
19904
+ "@sarj/no-restated-comment": "warn",
19665
19905
  "@sarj/no-restated-jsdoc": "error",
19666
19906
  "@sarj/no-secret-in-log": "error",
19667
19907
  "@sarj/no-server-env-in-client-component": "error",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sarj/eslint-plugin",
3
- "version": "15.17.4",
3
+ "version": "15.17.6",
4
4
  "packageManager": "npm@12.0.2",
5
5
  "description": "Custom ESLint rules for hypermodern TypeScript / React / Next.js projects",
6
6
  "type": "module",