@sarj/eslint-plugin 15.17.5 → 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.cjs +50 -26
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +57 -33
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -1448,6 +1448,10 @@ function normalizeToken(word) {
|
|
|
1448
1448
|
return lower.length > TOKEN_PLURAL_MIN && lower.endsWith("s") && !lower.endsWith("ss") ? lower.slice(0, -1) : lower;
|
|
1449
1449
|
}
|
|
1450
1450
|
function restatableStatementBelow(comment, sourceCode) {
|
|
1451
|
+
const node = restatableStatementNodeBelow(comment, sourceCode);
|
|
1452
|
+
return node === null ? null : sourceCode.getText(node);
|
|
1453
|
+
}
|
|
1454
|
+
function restatableStatementNodeBelow(comment, sourceCode) {
|
|
1451
1455
|
const token = sourceCode.getTokenAfter(comment, { includeComments: false });
|
|
1452
1456
|
if (token === null || token.loc.start.line !== comment.loc.end.line + 1) return null;
|
|
1453
1457
|
for (let node = sourceCode.getNodeByRangeIndex(token.range[0]); node != null && node.type !== import_utils7.AST_NODE_TYPES.Program; node = node.parent) {
|
|
@@ -1458,7 +1462,7 @@ function restatableStatementBelow(comment, sourceCode) {
|
|
|
1458
1462
|
if (node.type === import_utils7.AST_NODE_TYPES.VariableDeclaration && isTrivialInitializer(node)) {
|
|
1459
1463
|
return null;
|
|
1460
1464
|
}
|
|
1461
|
-
return
|
|
1465
|
+
return node;
|
|
1462
1466
|
}
|
|
1463
1467
|
return null;
|
|
1464
1468
|
}
|
|
@@ -6716,25 +6720,31 @@ var MODALITY_RE = /\b(?:can|could|should|shall|may|might|must|will|would|cannot)
|
|
|
6716
6720
|
var LEAD_IN_RE = /:$/;
|
|
6717
6721
|
var EMPHASIS_RE = /\*\w[^*]*\*|`[^`]+`/;
|
|
6718
6722
|
var NEGATION_WORD_RE = /\b(?:no|not|never|neither|nor|without|none|non)\b/i;
|
|
6723
|
+
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;
|
|
6719
6724
|
var ACTION_STMT_RE = /[\w.$\])]\s*\(|^\s*(?:return|throw|await|yield)\b/;
|
|
6720
6725
|
var NON_ASCII_LETTER_RE = /[^\p{ASCII}\p{N}\p{P}\p{Z}]/u;
|
|
6721
6726
|
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;
|
|
6722
6727
|
var WALL_CLUSTER_MAX_LINE_GAP = 8;
|
|
6723
6728
|
var WALL_CLUSTER_MIN_COMMENTS = 3;
|
|
6724
6729
|
var NO_RESTATED_COMMENT_DOCUMENTATION = {
|
|
6725
|
-
summary: "Flag
|
|
6730
|
+
summary: "Flag short standalone comments that repeat the adjacent statement's identifiers.",
|
|
6726
6731
|
rationale: "A comment that only repeats code adds no context and can become stale independently.",
|
|
6727
|
-
remediation: "
|
|
6732
|
+
remediation: "Remove a genuine restatement; retain conditions, constraints, rationale, and information absent from the statement.",
|
|
6728
6733
|
category: "maintainability",
|
|
6729
6734
|
autofix: "suggestion",
|
|
6730
|
-
limitations: [
|
|
6735
|
+
limitations: [
|
|
6736
|
+
"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.",
|
|
6737
|
+
"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.",
|
|
6738
|
+
"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.",
|
|
6739
|
+
"The conservative sibling-group exemption includes enclosing sibling groups and declaration/type-query pairs; it can miss genuine restatements inside those groups."
|
|
6740
|
+
],
|
|
6731
6741
|
examples: [
|
|
6732
|
-
{ id: "reason-comment", title: "Keep
|
|
6742
|
+
{ 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 },
|
|
6733
6743
|
{ 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 }
|
|
6734
6744
|
]
|
|
6735
6745
|
};
|
|
6736
|
-
function areAdjacentLineComments2(a, b) {
|
|
6737
|
-
return a !== void 0 && b !== void 0 && a.type === "Line" && b.type === "Line" && b.loc.start.line === a.loc.end.line + 1;
|
|
6746
|
+
function areAdjacentLineComments2(a, b, isStandalone) {
|
|
6747
|
+
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;
|
|
6738
6748
|
}
|
|
6739
6749
|
function headsSiblingRun(node) {
|
|
6740
6750
|
const parent = node.parent;
|
|
@@ -6752,12 +6762,12 @@ var no_restated_comment_default = createRule({
|
|
|
6752
6762
|
type: "suggestion",
|
|
6753
6763
|
hasSuggestions: true,
|
|
6754
6764
|
docs: {
|
|
6755
|
-
description:
|
|
6765
|
+
description: NO_RESTATED_COMMENT_DOCUMENTATION.summary
|
|
6756
6766
|
},
|
|
6757
6767
|
schema: [],
|
|
6758
6768
|
messages: {
|
|
6759
6769
|
deleteComment: "Delete the redundant comment.",
|
|
6760
|
-
restatesLineBelow: "Comment
|
|
6770
|
+
restatesLineBelow: "Comment repeats the adjacent statement's identifiers \u2014 consider removing it; retain any condition, constraint, or rationale absent from the code."
|
|
6761
6771
|
}
|
|
6762
6772
|
},
|
|
6763
6773
|
defaultOptions: [],
|
|
@@ -6766,19 +6776,30 @@ var no_restated_comment_default = createRule({
|
|
|
6766
6776
|
return {};
|
|
6767
6777
|
}
|
|
6768
6778
|
const sourceCode = context.sourceCode;
|
|
6769
|
-
const lines = sourceCode.lines;
|
|
6770
6779
|
function isStandalone(comment) {
|
|
6771
6780
|
const before = sourceCode.getTokenBefore(comment, { includeComments: false });
|
|
6772
6781
|
return !before || before.loc.end.line < comment.loc.start.line;
|
|
6773
6782
|
}
|
|
6774
|
-
function labelsASiblingRun(
|
|
6775
|
-
|
|
6776
|
-
if (token === null) return false;
|
|
6777
|
-
for (let node = sourceCode.getNodeByRangeIndex(token.range[0]); node != null && node.type !== import_utils38.AST_NODE_TYPES.Program; node = node.parent) {
|
|
6783
|
+
function labelsASiblingRun(statement) {
|
|
6784
|
+
for (let node = statement; node !== void 0 && node.type !== import_utils38.AST_NODE_TYPES.Program; node = node.parent) {
|
|
6778
6785
|
if (headsSiblingRun(node)) return true;
|
|
6779
6786
|
}
|
|
6780
6787
|
return false;
|
|
6781
6788
|
}
|
|
6789
|
+
function headsValueTypeGroup(statement) {
|
|
6790
|
+
if (statement.type !== import_utils38.AST_NODE_TYPES.VariableDeclaration) return false;
|
|
6791
|
+
const parent = statement.parent;
|
|
6792
|
+
if (!("body" in parent) || !Array.isArray(parent.body)) return false;
|
|
6793
|
+
const body2 = parent.body;
|
|
6794
|
+
const next = body2[body2.indexOf(statement) + 1];
|
|
6795
|
+
if (next?.type !== import_utils38.AST_NODE_TYPES.TSTypeAliasDeclaration) return false;
|
|
6796
|
+
const names = new Set(statement.declarations.flatMap(({ id }) => id.type === import_utils38.AST_NODE_TYPES.Identifier ? [id.name] : []));
|
|
6797
|
+
const tokens = sourceCode.getTokens(next);
|
|
6798
|
+
return tokens.some((token, index) => {
|
|
6799
|
+
const nextToken = tokens[index + 1];
|
|
6800
|
+
return token.value === "typeof" && nextToken?.type === import_utils38.AST_TOKEN_TYPES.Identifier && names.has(nextToken.value);
|
|
6801
|
+
});
|
|
6802
|
+
}
|
|
6782
6803
|
return {
|
|
6783
6804
|
Program() {
|
|
6784
6805
|
const comments = sourceCode.getAllComments();
|
|
@@ -6806,7 +6827,7 @@ var no_restated_comment_default = createRule({
|
|
|
6806
6827
|
if (comment === void 0 || comment.type !== "Line") continue;
|
|
6807
6828
|
if (wallMembers.has(comment)) continue;
|
|
6808
6829
|
if (!isStandalone(comment)) continue;
|
|
6809
|
-
if (areAdjacentLineComments2(comments[i - 1], comment) || areAdjacentLineComments2(comment, comments[i + 1])) {
|
|
6830
|
+
if (areAdjacentLineComments2(comments[i - 1], comment, isStandalone) || areAdjacentLineComments2(comment, comments[i + 1], isStandalone)) {
|
|
6810
6831
|
continue;
|
|
6811
6832
|
}
|
|
6812
6833
|
const body2 = comment.value.replace(/^\/*/, "").trim();
|
|
@@ -6814,17 +6835,19 @@ var no_restated_comment_default = createRule({
|
|
|
6814
6835
|
if (DIRECTIVE_RE3.test(body2) || CODEY_RE.test(body2) || BANNERISH_RE.test(body2)) continue;
|
|
6815
6836
|
if (NON_ASCII_LETTER_RE.test(body2) || isProtected(body2)) continue;
|
|
6816
6837
|
if (MODALITY_RE.test(body2) || LEAD_IN_RE.test(body2) || EMPHASIS_RE.test(body2)) continue;
|
|
6817
|
-
if (NEGATION_WORD_RE.test(body2)) continue;
|
|
6818
|
-
|
|
6838
|
+
if (NEGATION_WORD_RE.test(body2) || SEMANTIC_RELATION_RE.test(body2)) continue;
|
|
6839
|
+
const wordCount2 = body2.split(/\s+/).length;
|
|
6840
|
+
if (wordCount2 < 2 || wordCount2 > MAX_WORDS || /[.!?]$/.test(body2)) continue;
|
|
6819
6841
|
const tokens = contentTokens(body2);
|
|
6820
6842
|
if (tokens.length < MIN_CONTENT_TOKENS) continue;
|
|
6821
|
-
const
|
|
6822
|
-
if (
|
|
6843
|
+
const statementNode = restatableStatementNodeBelow(comment, sourceCode);
|
|
6844
|
+
if (statementNode === null) continue;
|
|
6845
|
+
const statement = sourceCode.getText(statementNode);
|
|
6823
6846
|
if (restatesStatementHead(body2, statement)) continue;
|
|
6824
|
-
|
|
6825
|
-
if (
|
|
6826
|
-
|
|
6827
|
-
if (restates(tokens, codeTokens(
|
|
6847
|
+
if (!ACTION_STMT_RE.test(statement)) continue;
|
|
6848
|
+
if (labelsASiblingRun(statementNode) || headsValueTypeGroup(statementNode)) continue;
|
|
6849
|
+
const identifiers = sourceCode.getTokens(statementNode).filter((token) => token.type === import_utils38.AST_TOKEN_TYPES.Identifier).map((token) => token.value).join(" ");
|
|
6850
|
+
if (restates(tokens, codeTokens(identifiers))) {
|
|
6828
6851
|
const removal = wholeLineRemovalRange(sourceCode.text, comment);
|
|
6829
6852
|
context.report({
|
|
6830
6853
|
node: comment,
|
|
@@ -19729,7 +19752,7 @@ var RULES = {
|
|
|
19729
19752
|
};
|
|
19730
19753
|
var meta = {
|
|
19731
19754
|
name: "@sarj/eslint-plugin",
|
|
19732
|
-
version: "15.17.
|
|
19755
|
+
version: "15.17.6"
|
|
19733
19756
|
};
|
|
19734
19757
|
var APPLICATION_ONLY_RULES = [];
|
|
19735
19758
|
var LIBRARY_IMPORT_POLICY = ["error", {
|
|
@@ -19739,6 +19762,7 @@ var LIBRARY_IMPORT_POLICY = ["error", {
|
|
|
19739
19762
|
var ADVISORY_RULES = [
|
|
19740
19763
|
"@sarj/excessive-commentary",
|
|
19741
19764
|
"@sarj/no-bespoke-api-case-conversion",
|
|
19765
|
+
"@sarj/no-restated-comment",
|
|
19742
19766
|
"@sarj/prefer-millisecond-control-duration-schema",
|
|
19743
19767
|
"@sarj/prefer-module-level-refined-schema",
|
|
19744
19768
|
"@sarj/prefer-multi-value-zod-literal",
|
|
@@ -19786,7 +19810,7 @@ var RECOMMENDED_RULES = {
|
|
|
19786
19810
|
"@sarj/no-production-browser-source-maps": "error",
|
|
19787
19811
|
"@sarj/no-repeated-string-literal": "error",
|
|
19788
19812
|
"@sarj/no-router-refresh-polling": "error",
|
|
19789
|
-
"@sarj/no-restated-comment": "
|
|
19813
|
+
"@sarj/no-restated-comment": "warn",
|
|
19790
19814
|
"@sarj/no-restated-jsdoc": "error",
|
|
19791
19815
|
"@sarj/no-secret-in-log": "error",
|
|
19792
19816
|
"@sarj/no-server-env-in-client-component": "error",
|
|
@@ -19882,7 +19906,7 @@ var STRICT_RULES = {
|
|
|
19882
19906
|
"@sarj/no-raw-fetch-outside-clients": "error",
|
|
19883
19907
|
"@sarj/no-repeated-string-literal": "error",
|
|
19884
19908
|
"@sarj/no-router-refresh-polling": "error",
|
|
19885
|
-
"@sarj/no-restated-comment": "
|
|
19909
|
+
"@sarj/no-restated-comment": "warn",
|
|
19886
19910
|
"@sarj/no-restated-jsdoc": "error",
|
|
19887
19911
|
"@sarj/no-secret-in-log": "error",
|
|
19888
19912
|
"@sarj/no-server-env-in-client-component": "error",
|
package/dist/index.d.cts
CHANGED
|
@@ -320,7 +320,7 @@ declare const RULES: {
|
|
|
320
320
|
/** @deprecated All repositories use one policy; retained for import compatibility. */
|
|
321
321
|
declare const APPLICATION_ONLY_RULES: readonly [];
|
|
322
322
|
/** Rules staged as non-blocking warnings while corpus adoption evidence accumulates. */
|
|
323
|
-
declare const ADVISORY_RULES: readonly ["@sarj/excessive-commentary", "@sarj/no-bespoke-api-case-conversion", "@sarj/prefer-millisecond-control-duration-schema", "@sarj/prefer-module-level-refined-schema", "@sarj/prefer-multi-value-zod-literal", "@sarj/prefer-named-callback-domain", "@sarj/prefer-named-complex-return-type", "@sarj/prefer-node-crypto-hash", "@sarj/prefer-node-fs-promises", "@sarj/prefer-nullish-filter-predicate", "@sarj/prefer-shared-zod-enum", "@sarj/prefer-switch-for-repeated-equality", "@sarj/require-interface-for-exported-class", "@sarj/require-sql-access-class", "@sarj/sole-export-matches-filename"];
|
|
323
|
+
declare const ADVISORY_RULES: readonly ["@sarj/excessive-commentary", "@sarj/no-bespoke-api-case-conversion", "@sarj/no-restated-comment", "@sarj/prefer-millisecond-control-duration-schema", "@sarj/prefer-module-level-refined-schema", "@sarj/prefer-multi-value-zod-literal", "@sarj/prefer-named-callback-domain", "@sarj/prefer-named-complex-return-type", "@sarj/prefer-node-crypto-hash", "@sarj/prefer-node-fs-promises", "@sarj/prefer-nullish-filter-predicate", "@sarj/prefer-shared-zod-enum", "@sarj/prefer-switch-for-repeated-equality", "@sarj/require-interface-for-exported-class", "@sarj/require-sql-access-class", "@sarj/sole-export-matches-filename"];
|
|
324
324
|
declare const RECOMMENDED_RULES: {
|
|
325
325
|
readonly "no-restricted-imports": readonly ["error", {
|
|
326
326
|
readonly paths: {
|
|
@@ -537,7 +537,7 @@ declare const RECOMMENDED_RULES: {
|
|
|
537
537
|
readonly "@sarj/no-production-browser-source-maps": "error";
|
|
538
538
|
readonly "@sarj/no-repeated-string-literal": "error";
|
|
539
539
|
readonly "@sarj/no-router-refresh-polling": "error";
|
|
540
|
-
readonly "@sarj/no-restated-comment": "
|
|
540
|
+
readonly "@sarj/no-restated-comment": "warn";
|
|
541
541
|
readonly "@sarj/no-restated-jsdoc": "error";
|
|
542
542
|
readonly "@sarj/no-secret-in-log": "error";
|
|
543
543
|
readonly "@sarj/no-server-env-in-client-component": "error";
|
|
@@ -820,7 +820,7 @@ declare const STRICT_RULES: {
|
|
|
820
820
|
readonly "@sarj/no-raw-fetch-outside-clients": "error";
|
|
821
821
|
readonly "@sarj/no-repeated-string-literal": "error";
|
|
822
822
|
readonly "@sarj/no-router-refresh-polling": "error";
|
|
823
|
-
readonly "@sarj/no-restated-comment": "
|
|
823
|
+
readonly "@sarj/no-restated-comment": "warn";
|
|
824
824
|
readonly "@sarj/no-restated-jsdoc": "error";
|
|
825
825
|
readonly "@sarj/no-secret-in-log": "error";
|
|
826
826
|
readonly "@sarj/no-server-env-in-client-component": "error";
|
|
@@ -893,7 +893,7 @@ type FlatPreset = {
|
|
|
893
893
|
declare const PLUGIN: {
|
|
894
894
|
readonly meta: {
|
|
895
895
|
readonly name: "@sarj/eslint-plugin";
|
|
896
|
-
readonly version: "15.17.
|
|
896
|
+
readonly version: "15.17.6";
|
|
897
897
|
};
|
|
898
898
|
readonly rules: {
|
|
899
899
|
readonly "excessive-commentary": DocumentedRule<readonly [], "excessive">;
|
package/dist/index.d.ts
CHANGED
|
@@ -320,7 +320,7 @@ declare const RULES: {
|
|
|
320
320
|
/** @deprecated All repositories use one policy; retained for import compatibility. */
|
|
321
321
|
declare const APPLICATION_ONLY_RULES: readonly [];
|
|
322
322
|
/** Rules staged as non-blocking warnings while corpus adoption evidence accumulates. */
|
|
323
|
-
declare const ADVISORY_RULES: readonly ["@sarj/excessive-commentary", "@sarj/no-bespoke-api-case-conversion", "@sarj/prefer-millisecond-control-duration-schema", "@sarj/prefer-module-level-refined-schema", "@sarj/prefer-multi-value-zod-literal", "@sarj/prefer-named-callback-domain", "@sarj/prefer-named-complex-return-type", "@sarj/prefer-node-crypto-hash", "@sarj/prefer-node-fs-promises", "@sarj/prefer-nullish-filter-predicate", "@sarj/prefer-shared-zod-enum", "@sarj/prefer-switch-for-repeated-equality", "@sarj/require-interface-for-exported-class", "@sarj/require-sql-access-class", "@sarj/sole-export-matches-filename"];
|
|
323
|
+
declare const ADVISORY_RULES: readonly ["@sarj/excessive-commentary", "@sarj/no-bespoke-api-case-conversion", "@sarj/no-restated-comment", "@sarj/prefer-millisecond-control-duration-schema", "@sarj/prefer-module-level-refined-schema", "@sarj/prefer-multi-value-zod-literal", "@sarj/prefer-named-callback-domain", "@sarj/prefer-named-complex-return-type", "@sarj/prefer-node-crypto-hash", "@sarj/prefer-node-fs-promises", "@sarj/prefer-nullish-filter-predicate", "@sarj/prefer-shared-zod-enum", "@sarj/prefer-switch-for-repeated-equality", "@sarj/require-interface-for-exported-class", "@sarj/require-sql-access-class", "@sarj/sole-export-matches-filename"];
|
|
324
324
|
declare const RECOMMENDED_RULES: {
|
|
325
325
|
readonly "no-restricted-imports": readonly ["error", {
|
|
326
326
|
readonly paths: {
|
|
@@ -537,7 +537,7 @@ declare const RECOMMENDED_RULES: {
|
|
|
537
537
|
readonly "@sarj/no-production-browser-source-maps": "error";
|
|
538
538
|
readonly "@sarj/no-repeated-string-literal": "error";
|
|
539
539
|
readonly "@sarj/no-router-refresh-polling": "error";
|
|
540
|
-
readonly "@sarj/no-restated-comment": "
|
|
540
|
+
readonly "@sarj/no-restated-comment": "warn";
|
|
541
541
|
readonly "@sarj/no-restated-jsdoc": "error";
|
|
542
542
|
readonly "@sarj/no-secret-in-log": "error";
|
|
543
543
|
readonly "@sarj/no-server-env-in-client-component": "error";
|
|
@@ -820,7 +820,7 @@ declare const STRICT_RULES: {
|
|
|
820
820
|
readonly "@sarj/no-raw-fetch-outside-clients": "error";
|
|
821
821
|
readonly "@sarj/no-repeated-string-literal": "error";
|
|
822
822
|
readonly "@sarj/no-router-refresh-polling": "error";
|
|
823
|
-
readonly "@sarj/no-restated-comment": "
|
|
823
|
+
readonly "@sarj/no-restated-comment": "warn";
|
|
824
824
|
readonly "@sarj/no-restated-jsdoc": "error";
|
|
825
825
|
readonly "@sarj/no-secret-in-log": "error";
|
|
826
826
|
readonly "@sarj/no-server-env-in-client-component": "error";
|
|
@@ -893,7 +893,7 @@ type FlatPreset = {
|
|
|
893
893
|
declare const PLUGIN: {
|
|
894
894
|
readonly meta: {
|
|
895
895
|
readonly name: "@sarj/eslint-plugin";
|
|
896
|
-
readonly version: "15.17.
|
|
896
|
+
readonly version: "15.17.6";
|
|
897
897
|
};
|
|
898
898
|
readonly rules: {
|
|
899
899
|
readonly "excessive-commentary": DocumentedRule<readonly [], "excessive">;
|
package/dist/index.js
CHANGED
|
@@ -1397,6 +1397,10 @@ function normalizeToken(word) {
|
|
|
1397
1397
|
return lower.length > TOKEN_PLURAL_MIN && lower.endsWith("s") && !lower.endsWith("ss") ? lower.slice(0, -1) : lower;
|
|
1398
1398
|
}
|
|
1399
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) {
|
|
1400
1404
|
const token = sourceCode.getTokenAfter(comment, { includeComments: false });
|
|
1401
1405
|
if (token === null || token.loc.start.line !== comment.loc.end.line + 1) return null;
|
|
1402
1406
|
for (let node = sourceCode.getNodeByRangeIndex(token.range[0]); node != null && node.type !== AST_NODE_TYPES6.Program; node = node.parent) {
|
|
@@ -1407,7 +1411,7 @@ function restatableStatementBelow(comment, sourceCode) {
|
|
|
1407
1411
|
if (node.type === AST_NODE_TYPES6.VariableDeclaration && isTrivialInitializer(node)) {
|
|
1408
1412
|
return null;
|
|
1409
1413
|
}
|
|
1410
|
-
return
|
|
1414
|
+
return node;
|
|
1411
1415
|
}
|
|
1412
1416
|
return null;
|
|
1413
1417
|
}
|
|
@@ -6633,7 +6637,7 @@ var no_repeated_string_literal_default = createRule({
|
|
|
6633
6637
|
});
|
|
6634
6638
|
|
|
6635
6639
|
// src/rules/no-restated-comment.ts
|
|
6636
|
-
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";
|
|
6637
6641
|
|
|
6638
6642
|
// src/rules/_comment-edits.ts
|
|
6639
6643
|
import "@typescript-eslint/utils";
|
|
@@ -6675,25 +6679,31 @@ var MODALITY_RE = /\b(?:can|could|should|shall|may|might|must|will|would|cannot)
|
|
|
6675
6679
|
var LEAD_IN_RE = /:$/;
|
|
6676
6680
|
var EMPHASIS_RE = /\*\w[^*]*\*|`[^`]+`/;
|
|
6677
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;
|
|
6678
6683
|
var ACTION_STMT_RE = /[\w.$\])]\s*\(|^\s*(?:return|throw|await|yield)\b/;
|
|
6679
6684
|
var NON_ASCII_LETTER_RE = /[^\p{ASCII}\p{N}\p{P}\p{Z}]/u;
|
|
6680
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;
|
|
6681
6686
|
var WALL_CLUSTER_MAX_LINE_GAP = 8;
|
|
6682
6687
|
var WALL_CLUSTER_MIN_COMMENTS = 3;
|
|
6683
6688
|
var NO_RESTATED_COMMENT_DOCUMENTATION = {
|
|
6684
|
-
summary: "Flag
|
|
6689
|
+
summary: "Flag short standalone comments that repeat the adjacent statement's identifiers.",
|
|
6685
6690
|
rationale: "A comment that only repeats code adds no context and can become stale independently.",
|
|
6686
|
-
remediation: "
|
|
6691
|
+
remediation: "Remove a genuine restatement; retain conditions, constraints, rationale, and information absent from the statement.",
|
|
6687
6692
|
category: "maintainability",
|
|
6688
6693
|
autofix: "suggestion",
|
|
6689
|
-
limitations: [
|
|
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
|
+
],
|
|
6690
6700
|
examples: [
|
|
6691
|
-
{ id: "reason-comment", title: "Keep
|
|
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 },
|
|
6692
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 }
|
|
6693
6703
|
]
|
|
6694
6704
|
};
|
|
6695
|
-
function areAdjacentLineComments2(a, b) {
|
|
6696
|
-
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;
|
|
6697
6707
|
}
|
|
6698
6708
|
function headsSiblingRun(node) {
|
|
6699
6709
|
const parent = node.parent;
|
|
@@ -6711,12 +6721,12 @@ var no_restated_comment_default = createRule({
|
|
|
6711
6721
|
type: "suggestion",
|
|
6712
6722
|
hasSuggestions: true,
|
|
6713
6723
|
docs: {
|
|
6714
|
-
description:
|
|
6724
|
+
description: NO_RESTATED_COMMENT_DOCUMENTATION.summary
|
|
6715
6725
|
},
|
|
6716
6726
|
schema: [],
|
|
6717
6727
|
messages: {
|
|
6718
6728
|
deleteComment: "Delete the redundant comment.",
|
|
6719
|
-
restatesLineBelow: "Comment
|
|
6729
|
+
restatesLineBelow: "Comment repeats the adjacent statement's identifiers \u2014 consider removing it; retain any condition, constraint, or rationale absent from the code."
|
|
6720
6730
|
}
|
|
6721
6731
|
},
|
|
6722
6732
|
defaultOptions: [],
|
|
@@ -6725,19 +6735,30 @@ var no_restated_comment_default = createRule({
|
|
|
6725
6735
|
return {};
|
|
6726
6736
|
}
|
|
6727
6737
|
const sourceCode = context.sourceCode;
|
|
6728
|
-
const lines = sourceCode.lines;
|
|
6729
6738
|
function isStandalone(comment) {
|
|
6730
6739
|
const before = sourceCode.getTokenBefore(comment, { includeComments: false });
|
|
6731
6740
|
return !before || before.loc.end.line < comment.loc.start.line;
|
|
6732
6741
|
}
|
|
6733
|
-
function labelsASiblingRun(
|
|
6734
|
-
|
|
6735
|
-
if (token === null) return false;
|
|
6736
|
-
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) {
|
|
6737
6744
|
if (headsSiblingRun(node)) return true;
|
|
6738
6745
|
}
|
|
6739
6746
|
return false;
|
|
6740
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
|
+
}
|
|
6741
6762
|
return {
|
|
6742
6763
|
Program() {
|
|
6743
6764
|
const comments = sourceCode.getAllComments();
|
|
@@ -6765,7 +6786,7 @@ var no_restated_comment_default = createRule({
|
|
|
6765
6786
|
if (comment === void 0 || comment.type !== "Line") continue;
|
|
6766
6787
|
if (wallMembers.has(comment)) continue;
|
|
6767
6788
|
if (!isStandalone(comment)) continue;
|
|
6768
|
-
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)) {
|
|
6769
6790
|
continue;
|
|
6770
6791
|
}
|
|
6771
6792
|
const body2 = comment.value.replace(/^\/*/, "").trim();
|
|
@@ -6773,17 +6794,19 @@ var no_restated_comment_default = createRule({
|
|
|
6773
6794
|
if (DIRECTIVE_RE3.test(body2) || CODEY_RE.test(body2) || BANNERISH_RE.test(body2)) continue;
|
|
6774
6795
|
if (NON_ASCII_LETTER_RE.test(body2) || isProtected(body2)) continue;
|
|
6775
6796
|
if (MODALITY_RE.test(body2) || LEAD_IN_RE.test(body2) || EMPHASIS_RE.test(body2)) continue;
|
|
6776
|
-
if (NEGATION_WORD_RE.test(body2)) continue;
|
|
6777
|
-
|
|
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;
|
|
6778
6800
|
const tokens = contentTokens(body2);
|
|
6779
6801
|
if (tokens.length < MIN_CONTENT_TOKENS) continue;
|
|
6780
|
-
const
|
|
6781
|
-
if (
|
|
6802
|
+
const statementNode = restatableStatementNodeBelow(comment, sourceCode);
|
|
6803
|
+
if (statementNode === null) continue;
|
|
6804
|
+
const statement = sourceCode.getText(statementNode);
|
|
6782
6805
|
if (restatesStatementHead(body2, statement)) continue;
|
|
6783
|
-
|
|
6784
|
-
if (
|
|
6785
|
-
|
|
6786
|
-
if (restates(tokens, codeTokens(
|
|
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))) {
|
|
6787
6810
|
const removal = wholeLineRemovalRange(sourceCode.text, comment);
|
|
6788
6811
|
context.report({
|
|
6789
6812
|
node: comment,
|
|
@@ -9078,10 +9101,10 @@ var no_trailing_value_narration_default = createRule({
|
|
|
9078
9101
|
});
|
|
9079
9102
|
|
|
9080
9103
|
// src/rules/no-declaration-comment-wall.ts
|
|
9081
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES36, AST_TOKEN_TYPES as
|
|
9104
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES36, AST_TOKEN_TYPES as AST_TOKEN_TYPES3 } from "@typescript-eslint/utils";
|
|
9082
9105
|
|
|
9083
9106
|
// src/rules/_comment-wall.ts
|
|
9084
|
-
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";
|
|
9085
9108
|
var WALL_DEFAULTS = {
|
|
9086
9109
|
// Below three rows "a wall" is not a fair description of what the reader sees.
|
|
9087
9110
|
minCommentedMembers: 3,
|
|
@@ -9147,7 +9170,7 @@ function commentBody(comment) {
|
|
|
9147
9170
|
return comment.value.replace(/^\*+/, "").replace(/^[ \t]*\*[ \t]?/gm, "").trim();
|
|
9148
9171
|
}
|
|
9149
9172
|
function hasJsDocTag(comment) {
|
|
9150
|
-
return comment.type ===
|
|
9173
|
+
return comment.type === AST_TOKEN_TYPES2.Block && comment.value.startsWith("*") && /(?:^|\s)@[A-Za-z][\w-]*\b/u.test(commentBody(comment));
|
|
9151
9174
|
}
|
|
9152
9175
|
function carriesValue(body2) {
|
|
9153
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);
|
|
@@ -9283,7 +9306,7 @@ var no_declaration_comment_wall_default = createRule({
|
|
|
9283
9306
|
const before = sourceCode.getTokenBefore(lead, { includeComments: false });
|
|
9284
9307
|
if (before === null || before.loc.end.line < lead.loc.start.line) {
|
|
9285
9308
|
const previousLine = endingOn.get(lead.loc.start.line - 1);
|
|
9286
|
-
if (lead.type ===
|
|
9309
|
+
if (lead.type === AST_TOKEN_TYPES3.Line && previousLine?.type === AST_TOKEN_TYPES3.Line && previousLine.loc.start.column === lead.loc.start.column) {
|
|
9287
9310
|
return void 0;
|
|
9288
9311
|
}
|
|
9289
9312
|
return lead;
|
|
@@ -9526,7 +9549,7 @@ var no_union_in_comment_default = createRule({
|
|
|
9526
9549
|
});
|
|
9527
9550
|
|
|
9528
9551
|
// src/rules/no-type-member-comment-wall.ts
|
|
9529
|
-
import { AST_NODE_TYPES as AST_NODE_TYPES38, AST_TOKEN_TYPES as
|
|
9552
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES38, AST_TOKEN_TYPES as AST_TOKEN_TYPES4 } from "@typescript-eslint/utils";
|
|
9530
9553
|
var NO_TYPE_MEMBER_COMMENT_WALL_DOCUMENTATION = {
|
|
9531
9554
|
summary: "Flag an object type whose member comments mostly re-spell the members' own names and types.",
|
|
9532
9555
|
rationale: "Repetitive member comments add scanning cost while hiding the comments that describe facts absent from the type.",
|
|
@@ -9591,7 +9614,7 @@ var no_type_member_comment_wall_default = createRule({
|
|
|
9591
9614
|
const before = sourceCode.getTokenBefore(lead, { includeComments: false });
|
|
9592
9615
|
if (before === null || before.loc.end.line < lead.loc.start.line) {
|
|
9593
9616
|
const previousLine = endingOn.get(lead.loc.start.line - 1);
|
|
9594
|
-
if (lead.type ===
|
|
9617
|
+
if (lead.type === AST_TOKEN_TYPES4.Line && previousLine?.type === AST_TOKEN_TYPES4.Line && previousLine.loc.start.column === lead.loc.start.column) {
|
|
9595
9618
|
return void 0;
|
|
9596
9619
|
}
|
|
9597
9620
|
return lead;
|
|
@@ -19724,7 +19747,7 @@ var RULES = {
|
|
|
19724
19747
|
};
|
|
19725
19748
|
var meta = {
|
|
19726
19749
|
name: "@sarj/eslint-plugin",
|
|
19727
|
-
version: "15.17.
|
|
19750
|
+
version: "15.17.6"
|
|
19728
19751
|
};
|
|
19729
19752
|
var APPLICATION_ONLY_RULES = [];
|
|
19730
19753
|
var LIBRARY_IMPORT_POLICY = ["error", {
|
|
@@ -19734,6 +19757,7 @@ var LIBRARY_IMPORT_POLICY = ["error", {
|
|
|
19734
19757
|
var ADVISORY_RULES = [
|
|
19735
19758
|
"@sarj/excessive-commentary",
|
|
19736
19759
|
"@sarj/no-bespoke-api-case-conversion",
|
|
19760
|
+
"@sarj/no-restated-comment",
|
|
19737
19761
|
"@sarj/prefer-millisecond-control-duration-schema",
|
|
19738
19762
|
"@sarj/prefer-module-level-refined-schema",
|
|
19739
19763
|
"@sarj/prefer-multi-value-zod-literal",
|
|
@@ -19781,7 +19805,7 @@ var RECOMMENDED_RULES = {
|
|
|
19781
19805
|
"@sarj/no-production-browser-source-maps": "error",
|
|
19782
19806
|
"@sarj/no-repeated-string-literal": "error",
|
|
19783
19807
|
"@sarj/no-router-refresh-polling": "error",
|
|
19784
|
-
"@sarj/no-restated-comment": "
|
|
19808
|
+
"@sarj/no-restated-comment": "warn",
|
|
19785
19809
|
"@sarj/no-restated-jsdoc": "error",
|
|
19786
19810
|
"@sarj/no-secret-in-log": "error",
|
|
19787
19811
|
"@sarj/no-server-env-in-client-component": "error",
|
|
@@ -19877,7 +19901,7 @@ var STRICT_RULES = {
|
|
|
19877
19901
|
"@sarj/no-raw-fetch-outside-clients": "error",
|
|
19878
19902
|
"@sarj/no-repeated-string-literal": "error",
|
|
19879
19903
|
"@sarj/no-router-refresh-polling": "error",
|
|
19880
|
-
"@sarj/no-restated-comment": "
|
|
19904
|
+
"@sarj/no-restated-comment": "warn",
|
|
19881
19905
|
"@sarj/no-restated-jsdoc": "error",
|
|
19882
19906
|
"@sarj/no-secret-in-log": "error",
|
|
19883
19907
|
"@sarj/no-server-env-in-client-component": "error",
|