@sarj/eslint-plugin 15.6.8 → 15.7.0
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 +329 -195
- package/dist/index.d.cts +10 -2
- package/dist/index.d.ts +10 -2
- package/dist/index.js +329 -195
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -4292,6 +4292,87 @@ var no_long_comment_default = createRule({
|
|
|
4292
4292
|
}
|
|
4293
4293
|
});
|
|
4294
4294
|
|
|
4295
|
+
// src/rules/no-vague-suppression-description.ts
|
|
4296
|
+
var DIRECTIVE_RE3 = /(?:eslint-(?:disable|disable-next-line|disable-line)|@ts-(?:expect-error|ignore))\b/iu;
|
|
4297
|
+
var DESCRIPTION_RE = /(?::|--)\s*(.+?)\s*$/u;
|
|
4298
|
+
var VAGUE_RE = /^(?:needed|required|intentional(?:ly)?|ignore(?:d)?|false positive|type error|typescript|to satisfy (?:the )?(?:linter|typescript|type checker))\.?$/iu;
|
|
4299
|
+
var noVagueSuppressionDescriptionDocumentation = {
|
|
4300
|
+
summary: "Require suppression descriptions to name the concrete mismatch or invariant instead of a generic non-reason.",
|
|
4301
|
+
rationale: "Generic phrases satisfy require-description mechanically while leaving reviewers unable to audit the risk or remove stale debt.",
|
|
4302
|
+
remediation: "Name the exact type/runtime mismatch, external contract, or safety invariant that makes this suppression acceptable.",
|
|
4303
|
+
category: "maintainability",
|
|
4304
|
+
limitations: [
|
|
4305
|
+
"Only ESLint disable comments and TypeScript expect-error/ignore directives are checked.",
|
|
4306
|
+
"The rule uses a small anchored vocabulary and does not score prose quality generally.",
|
|
4307
|
+
"Generated files and descriptions containing any concrete context are excluded."
|
|
4308
|
+
],
|
|
4309
|
+
examples: [
|
|
4310
|
+
{
|
|
4311
|
+
id: "concrete-runtime-mismatch",
|
|
4312
|
+
title: "Explain the concrete runtime contract",
|
|
4313
|
+
outcome: "no-match",
|
|
4314
|
+
files: [
|
|
4315
|
+
{
|
|
4316
|
+
path: "src/adapter.ts",
|
|
4317
|
+
source: "// @ts-expect-error -- vendor types omit the runtime requestId field\nreturn response.requestId;"
|
|
4318
|
+
}
|
|
4319
|
+
],
|
|
4320
|
+
focusPath: "src/adapter.ts",
|
|
4321
|
+
expectedCount: 0,
|
|
4322
|
+
public: true
|
|
4323
|
+
},
|
|
4324
|
+
{
|
|
4325
|
+
id: "generic-suppression-reason",
|
|
4326
|
+
title: "Reject a suppression with no auditable reason",
|
|
4327
|
+
outcome: "match",
|
|
4328
|
+
files: [
|
|
4329
|
+
{
|
|
4330
|
+
path: "src/adapter.ts",
|
|
4331
|
+
source: "// @ts-expect-error -- false positive\nreturn response.requestId;"
|
|
4332
|
+
}
|
|
4333
|
+
],
|
|
4334
|
+
focusPath: "src/adapter.ts",
|
|
4335
|
+
expectedCount: 1,
|
|
4336
|
+
public: true
|
|
4337
|
+
}
|
|
4338
|
+
]
|
|
4339
|
+
};
|
|
4340
|
+
var no_vague_suppression_description_default = createRule({
|
|
4341
|
+
name: "no-vague-suppression-description",
|
|
4342
|
+
documentation: noVagueSuppressionDescriptionDocumentation,
|
|
4343
|
+
meta: {
|
|
4344
|
+
type: "suggestion",
|
|
4345
|
+
docs: {
|
|
4346
|
+
description: "Require suppression descriptions to name the concrete mismatch or invariant instead of a generic non-reason."
|
|
4347
|
+
},
|
|
4348
|
+
schema: [],
|
|
4349
|
+
messages: {
|
|
4350
|
+
vagueDescription: "Suppression description `{{description}}` does not explain why the suppressed diagnostic is safe here. Name the concrete type/runtime mismatch, external contract, or invariant."
|
|
4351
|
+
}
|
|
4352
|
+
},
|
|
4353
|
+
defaultOptions: [],
|
|
4354
|
+
create(context) {
|
|
4355
|
+
if (isGeneratedFile(context.filename, context.sourceCode.text)) {
|
|
4356
|
+
return {};
|
|
4357
|
+
}
|
|
4358
|
+
return {
|
|
4359
|
+
Program() {
|
|
4360
|
+
for (const comment of context.sourceCode.getAllComments()) {
|
|
4361
|
+
const text = comment.value.trim();
|
|
4362
|
+
if (!DIRECTIVE_RE3.test(text)) continue;
|
|
4363
|
+
const description = DESCRIPTION_RE.exec(text)?.[1]?.trim();
|
|
4364
|
+
if (description === void 0 || !VAGUE_RE.test(description)) continue;
|
|
4365
|
+
context.report({
|
|
4366
|
+
loc: comment.loc,
|
|
4367
|
+
messageId: "vagueDescription",
|
|
4368
|
+
data: { description }
|
|
4369
|
+
});
|
|
4370
|
+
}
|
|
4371
|
+
}
|
|
4372
|
+
};
|
|
4373
|
+
}
|
|
4374
|
+
});
|
|
4375
|
+
|
|
4295
4376
|
// src/rules/no-generic-single-export-module.ts
|
|
4296
4377
|
var import_utils21 = require("@typescript-eslint/utils");
|
|
4297
4378
|
var noGenericSingleExportModuleDocumentation = {
|
|
@@ -5431,7 +5512,7 @@ var no_repeated_string_literal_default = createRule({
|
|
|
5431
5512
|
var import_utils28 = require("@typescript-eslint/utils");
|
|
5432
5513
|
var MAX_WORDS = 8;
|
|
5433
5514
|
var MIN_CONTENT_TOKENS = 2;
|
|
5434
|
-
var
|
|
5515
|
+
var DIRECTIVE_RE4 = /^(eslint\b|eslint-|sarj-noqa\b|@ts-|prettier-ignore|prettier\b|biome-|c8\b|v8\b|istanbul\b|@type\b|@vite|webpack|<reference|<amd|global\b|noinspection|todo\b|fixme\b|hack\b|xxx\b)/i;
|
|
5435
5516
|
var CODEY_RE = /^[\w.$[\]'"]+\s*[:=]\s*\S|^[\w.$]+\s*\(|^(?:return|throw|await|import|export|const|let|var)\b.*[=()[\]{}]/;
|
|
5436
5517
|
var BANNERISH_RE = /[=\-─-╿*#~_.]{3,}|^[A-Z0-9 _:-]+$/;
|
|
5437
5518
|
var MODALITY_RE = /\b(?:can|could|should|shall|may|might|must|will|would|cannot)\b/i;
|
|
@@ -5530,7 +5611,7 @@ var no_restated_comment_default = createRule({
|
|
|
5530
5611
|
}
|
|
5531
5612
|
const body2 = comment.value.replace(/^\/*/, "").trim();
|
|
5532
5613
|
if (body2.length === 0 || body2.endsWith("?")) continue;
|
|
5533
|
-
if (
|
|
5614
|
+
if (DIRECTIVE_RE4.test(body2) || CODEY_RE.test(body2) || BANNERISH_RE.test(body2)) continue;
|
|
5534
5615
|
if (NON_ASCII_LETTER_RE.test(body2) || isProtected(body2)) continue;
|
|
5535
5616
|
if (MODALITY_RE.test(body2) || LEAD_IN_RE.test(body2) || EMPHASIS_RE.test(body2)) continue;
|
|
5536
5617
|
if (NEGATION_WORD_RE.test(body2)) continue;
|
|
@@ -5578,7 +5659,7 @@ var MODELLED_TAGS = /* @__PURE__ */ new Set([
|
|
|
5578
5659
|
]);
|
|
5579
5660
|
var PARAM_TAGS = /* @__PURE__ */ new Set(["arg", "argument", "param"]);
|
|
5580
5661
|
var RETURN_TAGS = /* @__PURE__ */ new Set(["return", "returns"]);
|
|
5581
|
-
var
|
|
5662
|
+
var DIRECTIVE_RE5 = /^\s*(?:eslint\b|eslint-|@ts-|prettier|biome-|c8\b|v8\b|istanbul\b|@vite|webpack|@jsx|@jest-environment|@vitest-environment|#__)/i;
|
|
5582
5663
|
var STOPWORDS2 = new Set(
|
|
5583
5664
|
`the a an of to for in on with and or as at by is are was be been being
|
|
5584
5665
|
this that it its if whether when where which what will would can could should
|
|
@@ -5694,7 +5775,7 @@ var no_restated_jsdoc_default = createRule({
|
|
|
5694
5775
|
description,
|
|
5695
5776
|
...tags.filter((tag) => tag.name === "description").map((tag) => tag.text)
|
|
5696
5777
|
].filter((text) => text.length > 0).join("\n");
|
|
5697
|
-
if (
|
|
5778
|
+
if (DIRECTIVE_RE5.test(describedText)) continue;
|
|
5698
5779
|
const tagNames = new Set(tags.map((tag) => tag.name));
|
|
5699
5780
|
if ([...tagNames].some((name) => !MODELLED_TAGS.has(name))) continue;
|
|
5700
5781
|
if (isProtected(describedText)) continue;
|
|
@@ -7656,10 +7737,10 @@ var STOPWORDS3 = /* @__PURE__ */ new Set([
|
|
|
7656
7737
|
"we",
|
|
7657
7738
|
"with"
|
|
7658
7739
|
]);
|
|
7659
|
-
var
|
|
7740
|
+
var DIRECTIVE_RE6 = /^\s*(?:eslint\b|eslint-|sarj-noqa\b|@ts-|prettier|biome-|c8\b|v8\b|istanbul\b|todo\b|fixme\b|hack\b|xxx\b)/i;
|
|
7660
7741
|
var UNIT_NAME_SUFFIX_RE = /(?:_(?:NS|US|MS|S|SEC|SECS|SECOND|SECONDS|MIN|MINS|MINUTE|MINUTES|HOUR|HOURS|DAY|DAYS|BYTE|BYTES|KB|MB|GB|HZ|KHZ|MHZ|PX)|(?:Ns|Us|Ms|Sec|Secs|Second|Seconds|Min|Mins|Minute|Minutes|Hour|Hours|Day|Days|Byte|Bytes|Kb|Mb|Gb|Hz|Khz|Mhz|Px))$/u;
|
|
7661
7742
|
function narratesValue(body2, code) {
|
|
7662
|
-
if (body2.length === 0 ||
|
|
7743
|
+
if (body2.length === 0 || DIRECTIVE_RE6.test(body2) || hasExternalReference(body2)) return false;
|
|
7663
7744
|
const codeNumbers = numbersIn(code);
|
|
7664
7745
|
if (codeNumbers.size === 0) return false;
|
|
7665
7746
|
const words2 = (body2.match(WORD_RE3) ?? []).map((word) => word.toLowerCase());
|
|
@@ -14787,7 +14868,7 @@ var stepdown_default = createRule({
|
|
|
14787
14868
|
|
|
14788
14869
|
// src/rules/source-coupled-test.ts
|
|
14789
14870
|
var import_utils70 = require("@typescript-eslint/utils");
|
|
14790
|
-
var
|
|
14871
|
+
var GENERAL_SOURCE_SUFFIX_RE = /\.(?:bash|sh|ya?ml|py|[cm]?[jt]s)$/iu;
|
|
14791
14872
|
var FS_MODULES = /* @__PURE__ */ new Set(["fs", "node:fs", "fs/promises", "node:fs/promises"]);
|
|
14792
14873
|
var FS_READERS = /* @__PURE__ */ new Set(["readFile", "readFileSync"]);
|
|
14793
14874
|
var TEXT_TRANSFORMS = /* @__PURE__ */ new Set([
|
|
@@ -14801,7 +14882,8 @@ var TEXT_TRANSFORMS = /* @__PURE__ */ new Set([
|
|
|
14801
14882
|
"trimEnd",
|
|
14802
14883
|
"trimStart",
|
|
14803
14884
|
"replace",
|
|
14804
|
-
"replaceAll"
|
|
14885
|
+
"replaceAll",
|
|
14886
|
+
"split"
|
|
14805
14887
|
]);
|
|
14806
14888
|
var TEXT_PREDICATES = /* @__PURE__ */ new Set(["endsWith", "includes", "indexOf", "lastIndexOf", "match", "matchAll", "search", "startsWith"]);
|
|
14807
14889
|
var REGEXP_PREDICATES = /* @__PURE__ */ new Set(["exec", "test"]);
|
|
@@ -14826,7 +14908,7 @@ var ASSERT_MATCHERS = /* @__PURE__ */ new Set(["deepEqual", "doesNotMatch", "equ
|
|
|
14826
14908
|
var sourceCoupledTestDocumentation = {
|
|
14827
14909
|
summary: "Disallow raw repository source text as a test oracle; parse or execute the artifact instead.",
|
|
14828
14910
|
rationale: "Substring and regex checks can pass on comments or unreachable configuration and fail after behavior-preserving formatting changes.",
|
|
14829
|
-
remediation: "Parse the artifact, execute its validator, or assert on
|
|
14911
|
+
remediation: "Parse the artifact, execute its validator, or assert on another runtime contract.",
|
|
14830
14912
|
category: "testing",
|
|
14831
14913
|
limitations: [
|
|
14832
14914
|
"The rule follows lexical aliases, source-path collections, awaited reads, and common text operations; interprocedural flows remain unreported.",
|
|
@@ -14843,10 +14925,10 @@ var sourceCoupledTestDocumentation = {
|
|
|
14843
14925
|
public: true
|
|
14844
14926
|
},
|
|
14845
14927
|
{
|
|
14846
|
-
id: "
|
|
14847
|
-
title: "Do not prove
|
|
14928
|
+
id: "workflow-substring-contract",
|
|
14929
|
+
title: "Do not prove workflow behavior with a regex",
|
|
14848
14930
|
outcome: "match",
|
|
14849
|
-
files: [{ path: "src/policy.test.ts", source: "import { readFileSync } from 'node:fs'; test('policy', () => { const source = readFileSync('
|
|
14931
|
+
files: [{ path: "src/policy.test.ts", source: "import { readFileSync } from 'node:fs'; test('policy', () => { const source = readFileSync('workflow.yml', 'utf8'); expect(source).toMatch(/permissions/); });" }],
|
|
14850
14932
|
focusPath: "src/policy.test.ts",
|
|
14851
14933
|
expectedCount: 1,
|
|
14852
14934
|
public: true
|
|
@@ -14881,191 +14963,237 @@ function requireSource(node) {
|
|
|
14881
14963
|
function newScope() {
|
|
14882
14964
|
return { collections: /* @__PURE__ */ new Set(), declared: /* @__PURE__ */ new Set(), fsObjects: /* @__PURE__ */ new Set(), fsReaders: /* @__PURE__ */ new Set(), paths: /* @__PURE__ */ new Set(), rawOrigins: /* @__PURE__ */ new Map() };
|
|
14883
14965
|
}
|
|
14884
|
-
|
|
14885
|
-
|
|
14886
|
-
|
|
14887
|
-
|
|
14888
|
-
|
|
14889
|
-
|
|
14890
|
-
|
|
14891
|
-
|
|
14892
|
-
|
|
14893
|
-
|
|
14894
|
-
|
|
14895
|
-
|
|
14896
|
-
|
|
14897
|
-
|
|
14898
|
-
|
|
14899
|
-
|
|
14900
|
-
|
|
14901
|
-
|
|
14902
|
-
|
|
14903
|
-
|
|
14904
|
-
return false;
|
|
14905
|
-
};
|
|
14906
|
-
const visibleRawOrigins = (name) => {
|
|
14907
|
-
for (let index = scopes.length - 1; index >= 0; index--) {
|
|
14908
|
-
const scope = scopes[index];
|
|
14909
|
-
if (scope.declared.has(name)) return scope.rawOrigins.get(name) ?? /* @__PURE__ */ new Set();
|
|
14910
|
-
}
|
|
14911
|
-
return /* @__PURE__ */ new Set();
|
|
14912
|
-
};
|
|
14913
|
-
const sourcePath = (node) => {
|
|
14914
|
-
const current = unwrap5(node);
|
|
14915
|
-
const value = stringValue(current);
|
|
14916
|
-
if (value !== null) return SOURCE_SUFFIX_RE.test(value);
|
|
14917
|
-
if (current.type === import_utils70.AST_NODE_TYPES.Identifier) return visible("paths", current.name);
|
|
14918
|
-
if (current.type === import_utils70.AST_NODE_TYPES.BinaryExpression && current.operator === "+") {
|
|
14919
|
-
return sourcePath(current.left) || sourcePath(current.right);
|
|
14920
|
-
}
|
|
14921
|
-
if (current.type === import_utils70.AST_NODE_TYPES.TemplateLiteral) return current.expressions.some(sourcePath);
|
|
14922
|
-
if (current.type === import_utils70.AST_NODE_TYPES.CallExpression || current.type === import_utils70.AST_NODE_TYPES.NewExpression) {
|
|
14923
|
-
return current.arguments.some((argument) => argument.type !== import_utils70.AST_NODE_TYPES.SpreadElement && sourcePath(argument));
|
|
14924
|
-
}
|
|
14925
|
-
if (current.type === import_utils70.AST_NODE_TYPES.MemberExpression) return sourcePath(current.object);
|
|
14926
|
-
return false;
|
|
14927
|
-
};
|
|
14928
|
-
const rawRead = (node) => {
|
|
14929
|
-
const current = unwrap5(node);
|
|
14930
|
-
if (current.type !== import_utils70.AST_NODE_TYPES.CallExpression || current.arguments.length === 0) return false;
|
|
14931
|
-
const callee = unwrap5(current.callee);
|
|
14932
|
-
if (callee.type === import_utils70.AST_NODE_TYPES.Identifier) {
|
|
14933
|
-
return visible("fsReaders", callee.name) && sourcePath(current.arguments[0]);
|
|
14934
|
-
}
|
|
14935
|
-
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return false;
|
|
14936
|
-
const name = staticMemberName5(callee);
|
|
14937
|
-
const object = unwrap5(callee.object);
|
|
14938
|
-
return name !== null && FS_READERS.has(name) && object.type === import_utils70.AST_NODE_TYPES.Identifier && visible("fsObjects", object.name) && sourcePath(current.arguments[0]);
|
|
14939
|
-
};
|
|
14940
|
-
const rawOrigins = (node) => {
|
|
14941
|
-
const current = unwrap5(node);
|
|
14942
|
-
if (current.type === import_utils70.AST_NODE_TYPES.Identifier) return visibleRawOrigins(current.name);
|
|
14943
|
-
if (rawRead(current)) return /* @__PURE__ */ new Set([`${current.range[0]}:${current.range[1]}`]);
|
|
14944
|
-
if (current.type === import_utils70.AST_NODE_TYPES.BinaryExpression && current.operator === "+") return /* @__PURE__ */ new Set([...rawOrigins(current.left), ...rawOrigins(current.right)]);
|
|
14945
|
-
if (current.type !== import_utils70.AST_NODE_TYPES.CallExpression) return /* @__PURE__ */ new Set();
|
|
14946
|
-
const callee = unwrap5(current.callee);
|
|
14947
|
-
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return /* @__PURE__ */ new Set();
|
|
14948
|
-
const name = staticMemberName5(callee);
|
|
14949
|
-
return name !== null && TEXT_TRANSFORMS.has(name) ? rawOrigins(callee.object) : /* @__PURE__ */ new Set();
|
|
14950
|
-
};
|
|
14951
|
-
const evidenceOrigins = (node) => {
|
|
14952
|
-
const current = unwrap5(node);
|
|
14953
|
-
const direct = rawOrigins(current);
|
|
14954
|
-
if (direct.size > 0) return direct;
|
|
14955
|
-
if (current.type === import_utils70.AST_NODE_TYPES.BinaryExpression || current.type === import_utils70.AST_NODE_TYPES.LogicalExpression) return /* @__PURE__ */ new Set([...evidenceOrigins(current.left), ...evidenceOrigins(current.right)]);
|
|
14956
|
-
if (current.type === import_utils70.AST_NODE_TYPES.UnaryExpression) return evidenceOrigins(current.argument);
|
|
14957
|
-
if (current.type !== import_utils70.AST_NODE_TYPES.CallExpression) return /* @__PURE__ */ new Set();
|
|
14958
|
-
const callee = unwrap5(current.callee);
|
|
14959
|
-
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return /* @__PURE__ */ new Set();
|
|
14960
|
-
const name = staticMemberName5(callee);
|
|
14961
|
-
if (name !== null && TEXT_PREDICATES.has(name)) return rawOrigins(callee.object);
|
|
14962
|
-
if (name !== null && REGEXP_PREDICATES.has(name)) return new Set(current.arguments.flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...rawOrigins(argument)]));
|
|
14963
|
-
return /* @__PURE__ */ new Set();
|
|
14964
|
-
};
|
|
14965
|
-
const rawAssertionOrigins = (node) => {
|
|
14966
|
-
const callee = unwrap5(node.callee);
|
|
14967
|
-
if (callee.type === import_utils70.AST_NODE_TYPES.Identifier && callee.name === "assert") {
|
|
14968
|
-
return new Set(node.arguments.flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
14969
|
-
}
|
|
14970
|
-
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return /* @__PURE__ */ new Set();
|
|
14971
|
-
const matcher = staticMemberName5(callee);
|
|
14972
|
-
if (matcher === null) return /* @__PURE__ */ new Set();
|
|
14973
|
-
let receiver = unwrap5(callee.object);
|
|
14974
|
-
while (receiver.type === import_utils70.AST_NODE_TYPES.MemberExpression && EXPECT_MODIFIERS.has(staticMemberName5(receiver) ?? "")) receiver = unwrap5(receiver.object);
|
|
14975
|
-
if (receiver.type === import_utils70.AST_NODE_TYPES.CallExpression && receiver.callee.type === import_utils70.AST_NODE_TYPES.Identifier && receiver.callee.name === "expect") {
|
|
14976
|
-
if (!EXPECT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
|
|
14977
|
-
return new Set([...receiver.arguments, ...node.arguments].flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
14978
|
-
}
|
|
14979
|
-
if (receiver.type !== import_utils70.AST_NODE_TYPES.Identifier || receiver.name !== "assert" || !ASSERT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
|
|
14980
|
-
return new Set(node.arguments.flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
14981
|
-
};
|
|
14982
|
-
const declare = (name, state) => {
|
|
14983
|
-
const scope = currentScope();
|
|
14984
|
-
scope.declared.add(name);
|
|
14985
|
-
scope.collections.delete(name);
|
|
14986
|
-
scope.fsObjects.delete(name);
|
|
14987
|
-
scope.fsReaders.delete(name);
|
|
14988
|
-
scope.paths.delete(name);
|
|
14989
|
-
scope.rawOrigins.delete(name);
|
|
14990
|
-
if (state.collection === true) scope.collections.add(name);
|
|
14991
|
-
if (state.fsObject === true) scope.fsObjects.add(name);
|
|
14992
|
-
if (state.fsReader === true) scope.fsReaders.add(name);
|
|
14993
|
-
if (state.path === true) scope.paths.add(name);
|
|
14994
|
-
if (state.rawOrigins !== void 0 && state.rawOrigins.size > 0) {
|
|
14995
|
-
scope.rawOrigins.set(name, state.rawOrigins);
|
|
14996
|
-
}
|
|
14997
|
-
};
|
|
14998
|
-
const sourceCollection = (node) => {
|
|
14999
|
-
const current = unwrap5(node);
|
|
15000
|
-
return current.type === import_utils70.AST_NODE_TYPES.ArrayExpression && current.elements.length > 0 && current.elements.every((element) => element !== null && element.type !== import_utils70.AST_NODE_TYPES.SpreadElement && sourcePath(element));
|
|
15001
|
-
};
|
|
15002
|
-
const declaredNames2 = (node) => {
|
|
15003
|
-
const current = unwrap5(node);
|
|
15004
|
-
if (current.type === import_utils70.AST_NODE_TYPES.Identifier) return [current.name];
|
|
15005
|
-
if (current.type === import_utils70.AST_NODE_TYPES.AssignmentPattern) return declaredNames2(current.left);
|
|
15006
|
-
if (current.type === import_utils70.AST_NODE_TYPES.RestElement) return declaredNames2(current.argument);
|
|
15007
|
-
if (current.type === import_utils70.AST_NODE_TYPES.ArrayPattern) return current.elements.flatMap((element) => element === null ? [] : declaredNames2(element));
|
|
15008
|
-
if (current.type === import_utils70.AST_NODE_TYPES.ObjectPattern) return current.properties.flatMap((property) => property.type === import_utils70.AST_NODE_TYPES.RestElement ? declaredNames2(property.argument) : declaredNames2(property.value));
|
|
15009
|
-
return [];
|
|
15010
|
-
};
|
|
15011
|
-
const enterFunction = (node) => {
|
|
15012
|
-
scopes.push(newScope());
|
|
15013
|
-
for (const parameter of node.params) for (const name of declaredNames2(parameter)) declare(name, {});
|
|
15014
|
-
};
|
|
15015
|
-
const exitFunction = () => {
|
|
15016
|
-
scopes.pop();
|
|
15017
|
-
};
|
|
15018
|
-
return {
|
|
15019
|
-
ImportDeclaration(node) {
|
|
15020
|
-
const source = importSource(node);
|
|
15021
|
-
if (source === null || !FS_MODULES.has(source)) return;
|
|
15022
|
-
for (const specifier of node.specifiers) {
|
|
15023
|
-
if (specifier.type === import_utils70.AST_NODE_TYPES.ImportSpecifier) {
|
|
15024
|
-
const imported = specifier.imported.type === import_utils70.AST_NODE_TYPES.Identifier ? specifier.imported.name : String(specifier.imported.value);
|
|
15025
|
-
if (FS_READERS.has(imported)) declare(specifier.local.name, { fsReader: true });
|
|
15026
|
-
} else {
|
|
15027
|
-
declare(specifier.local.name, { fsObject: true });
|
|
15028
|
-
}
|
|
14966
|
+
function createSourceCoupledRule(name, documentation, sourceSuffixRe) {
|
|
14967
|
+
return createRule({
|
|
14968
|
+
name,
|
|
14969
|
+
documentation,
|
|
14970
|
+
meta: {
|
|
14971
|
+
type: "suggestion",
|
|
14972
|
+
docs: { description: documentation.summary },
|
|
14973
|
+
schema: [],
|
|
14974
|
+
messages: { rawSourceOracle: "Raw repository source text is the oracle. Parse or execute the artifact so comments, formatting, and unreachable blocks cannot satisfy the contract." }
|
|
14975
|
+
},
|
|
14976
|
+
defaultOptions: [],
|
|
14977
|
+
create(context) {
|
|
14978
|
+
if (!isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) return {};
|
|
14979
|
+
const scopes = [newScope()];
|
|
14980
|
+
const reportedOrigins = /* @__PURE__ */ new Set();
|
|
14981
|
+
const currentScope = () => scopes.at(-1) ?? scopes[0];
|
|
14982
|
+
const visible = (kind, name2) => {
|
|
14983
|
+
for (let index = scopes.length - 1; index >= 0; index--) {
|
|
14984
|
+
const scope = scopes[index];
|
|
14985
|
+
if (scope.declared.has(name2)) return scope[kind].has(name2);
|
|
15029
14986
|
}
|
|
15030
|
-
|
|
15031
|
-
|
|
15032
|
-
|
|
15033
|
-
|
|
15034
|
-
|
|
15035
|
-
|
|
15036
|
-
|
|
15037
|
-
|
|
15038
|
-
|
|
14987
|
+
return false;
|
|
14988
|
+
};
|
|
14989
|
+
const visibleRawOrigins = (name2) => {
|
|
14990
|
+
for (let index = scopes.length - 1; index >= 0; index--) {
|
|
14991
|
+
const scope = scopes[index];
|
|
14992
|
+
if (scope.declared.has(name2)) return scope.rawOrigins.get(name2) ?? /* @__PURE__ */ new Set();
|
|
14993
|
+
}
|
|
14994
|
+
return /* @__PURE__ */ new Set();
|
|
14995
|
+
};
|
|
14996
|
+
const sourcePath = (node) => {
|
|
14997
|
+
const current = unwrap5(node);
|
|
14998
|
+
const value = stringValue(current);
|
|
14999
|
+
if (value !== null) return sourceSuffixRe.test(value);
|
|
15000
|
+
if (current.type === import_utils70.AST_NODE_TYPES.Identifier) return visible("paths", current.name);
|
|
15001
|
+
if (current.type === import_utils70.AST_NODE_TYPES.BinaryExpression && current.operator === "+") {
|
|
15002
|
+
return sourcePath(current.left) || sourcePath(current.right);
|
|
15003
|
+
}
|
|
15004
|
+
if (current.type === import_utils70.AST_NODE_TYPES.TemplateLiteral) return current.expressions.some(sourcePath);
|
|
15005
|
+
if (current.type === import_utils70.AST_NODE_TYPES.CallExpression || current.type === import_utils70.AST_NODE_TYPES.NewExpression) {
|
|
15006
|
+
return current.arguments.some((argument) => argument.type !== import_utils70.AST_NODE_TYPES.SpreadElement && sourcePath(argument));
|
|
15007
|
+
}
|
|
15008
|
+
if (current.type === import_utils70.AST_NODE_TYPES.MemberExpression) return sourcePath(current.object);
|
|
15009
|
+
return false;
|
|
15010
|
+
};
|
|
15011
|
+
const rawRead = (node) => {
|
|
15012
|
+
const current = unwrap5(node);
|
|
15013
|
+
if (current.type !== import_utils70.AST_NODE_TYPES.CallExpression || current.arguments.length === 0) return false;
|
|
15014
|
+
const callee = unwrap5(current.callee);
|
|
15015
|
+
if (callee.type === import_utils70.AST_NODE_TYPES.Identifier) {
|
|
15016
|
+
return visible("fsReaders", callee.name) && sourcePath(current.arguments[0]);
|
|
15017
|
+
}
|
|
15018
|
+
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return false;
|
|
15019
|
+
const name2 = staticMemberName5(callee);
|
|
15020
|
+
const object = unwrap5(callee.object);
|
|
15021
|
+
return name2 !== null && FS_READERS.has(name2) && object.type === import_utils70.AST_NODE_TYPES.Identifier && visible("fsObjects", object.name) && sourcePath(current.arguments[0]);
|
|
15022
|
+
};
|
|
15023
|
+
const rawOrigins = (node) => {
|
|
15024
|
+
const current = unwrap5(node);
|
|
15025
|
+
if (current.type === import_utils70.AST_NODE_TYPES.Identifier) return visibleRawOrigins(current.name);
|
|
15026
|
+
if (rawRead(current)) return /* @__PURE__ */ new Set([`${current.range[0]}:${current.range[1]}`]);
|
|
15027
|
+
if (current.type === import_utils70.AST_NODE_TYPES.BinaryExpression && current.operator === "+") return /* @__PURE__ */ new Set([...rawOrigins(current.left), ...rawOrigins(current.right)]);
|
|
15028
|
+
if (current.type === import_utils70.AST_NODE_TYPES.MemberExpression && staticMemberName5(current) === "length") return rawOrigins(current.object);
|
|
15029
|
+
if (current.type !== import_utils70.AST_NODE_TYPES.CallExpression) return /* @__PURE__ */ new Set();
|
|
15030
|
+
const callee = unwrap5(current.callee);
|
|
15031
|
+
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return /* @__PURE__ */ new Set();
|
|
15032
|
+
const name2 = staticMemberName5(callee);
|
|
15033
|
+
return name2 !== null && TEXT_TRANSFORMS.has(name2) ? rawOrigins(callee.object) : /* @__PURE__ */ new Set();
|
|
15034
|
+
};
|
|
15035
|
+
const evidenceOrigins = (node) => {
|
|
15036
|
+
const current = unwrap5(node);
|
|
15037
|
+
const direct = rawOrigins(current);
|
|
15038
|
+
if (direct.size > 0) return direct;
|
|
15039
|
+
if (current.type === import_utils70.AST_NODE_TYPES.BinaryExpression || current.type === import_utils70.AST_NODE_TYPES.LogicalExpression) return /* @__PURE__ */ new Set([...evidenceOrigins(current.left), ...evidenceOrigins(current.right)]);
|
|
15040
|
+
if (current.type === import_utils70.AST_NODE_TYPES.UnaryExpression) return evidenceOrigins(current.argument);
|
|
15041
|
+
if (current.type !== import_utils70.AST_NODE_TYPES.CallExpression) return /* @__PURE__ */ new Set();
|
|
15042
|
+
const callee = unwrap5(current.callee);
|
|
15043
|
+
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return /* @__PURE__ */ new Set();
|
|
15044
|
+
const name2 = staticMemberName5(callee);
|
|
15045
|
+
if (name2 !== null && TEXT_PREDICATES.has(name2)) return rawOrigins(callee.object);
|
|
15046
|
+
if (name2 !== null && REGEXP_PREDICATES.has(name2)) return new Set(current.arguments.flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...rawOrigins(argument)]));
|
|
15047
|
+
return /* @__PURE__ */ new Set();
|
|
15048
|
+
};
|
|
15049
|
+
const rawAssertionOrigins = (node) => {
|
|
15050
|
+
const callee = unwrap5(node.callee);
|
|
15051
|
+
if (callee.type === import_utils70.AST_NODE_TYPES.Identifier && callee.name === "assert") {
|
|
15052
|
+
return new Set(node.arguments.flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
15053
|
+
}
|
|
15054
|
+
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return /* @__PURE__ */ new Set();
|
|
15055
|
+
const matcher = staticMemberName5(callee);
|
|
15056
|
+
if (matcher === null) return /* @__PURE__ */ new Set();
|
|
15057
|
+
let receiver = unwrap5(callee.object);
|
|
15058
|
+
while (receiver.type === import_utils70.AST_NODE_TYPES.MemberExpression && EXPECT_MODIFIERS.has(staticMemberName5(receiver) ?? "")) receiver = unwrap5(receiver.object);
|
|
15059
|
+
if (receiver.type === import_utils70.AST_NODE_TYPES.CallExpression && receiver.callee.type === import_utils70.AST_NODE_TYPES.Identifier && receiver.callee.name === "expect") {
|
|
15060
|
+
if (!EXPECT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
|
|
15061
|
+
return new Set([...receiver.arguments, ...node.arguments].flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
15062
|
+
}
|
|
15063
|
+
if (receiver.type !== import_utils70.AST_NODE_TYPES.Identifier || receiver.name !== "assert" || !ASSERT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
|
|
15064
|
+
return new Set(node.arguments.flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
15065
|
+
};
|
|
15066
|
+
const declare = (name2, state) => {
|
|
15067
|
+
const scope = currentScope();
|
|
15068
|
+
scope.declared.add(name2);
|
|
15069
|
+
scope.collections.delete(name2);
|
|
15070
|
+
scope.fsObjects.delete(name2);
|
|
15071
|
+
scope.fsReaders.delete(name2);
|
|
15072
|
+
scope.paths.delete(name2);
|
|
15073
|
+
scope.rawOrigins.delete(name2);
|
|
15074
|
+
if (state.collection === true) scope.collections.add(name2);
|
|
15075
|
+
if (state.fsObject === true) scope.fsObjects.add(name2);
|
|
15076
|
+
if (state.fsReader === true) scope.fsReaders.add(name2);
|
|
15077
|
+
if (state.path === true) scope.paths.add(name2);
|
|
15078
|
+
if (state.rawOrigins !== void 0 && state.rawOrigins.size > 0) {
|
|
15079
|
+
scope.rawOrigins.set(name2, state.rawOrigins);
|
|
15039
15080
|
}
|
|
15040
|
-
|
|
15041
|
-
|
|
15042
|
-
|
|
15043
|
-
|
|
15044
|
-
|
|
15081
|
+
};
|
|
15082
|
+
const sourceCollection = (node) => {
|
|
15083
|
+
const current = unwrap5(node);
|
|
15084
|
+
return current.type === import_utils70.AST_NODE_TYPES.ArrayExpression && current.elements.length > 0 && current.elements.every((element) => element !== null && element.type !== import_utils70.AST_NODE_TYPES.SpreadElement && sourcePath(element));
|
|
15085
|
+
};
|
|
15086
|
+
const declaredNames2 = (node) => {
|
|
15087
|
+
const current = unwrap5(node);
|
|
15088
|
+
if (current.type === import_utils70.AST_NODE_TYPES.Identifier) return [current.name];
|
|
15089
|
+
if (current.type === import_utils70.AST_NODE_TYPES.AssignmentPattern) return declaredNames2(current.left);
|
|
15090
|
+
if (current.type === import_utils70.AST_NODE_TYPES.RestElement) return declaredNames2(current.argument);
|
|
15091
|
+
if (current.type === import_utils70.AST_NODE_TYPES.ArrayPattern) return current.elements.flatMap((element) => element === null ? [] : declaredNames2(element));
|
|
15092
|
+
if (current.type === import_utils70.AST_NODE_TYPES.ObjectPattern) return current.properties.flatMap((property) => property.type === import_utils70.AST_NODE_TYPES.RestElement ? declaredNames2(property.argument) : declaredNames2(property.value));
|
|
15093
|
+
return [];
|
|
15094
|
+
};
|
|
15095
|
+
const enterFunction = (node) => {
|
|
15096
|
+
scopes.push(newScope());
|
|
15097
|
+
for (const parameter of node.params) for (const name2 of declaredNames2(parameter)) declare(name2, {});
|
|
15098
|
+
};
|
|
15099
|
+
const exitFunction = () => {
|
|
15100
|
+
scopes.pop();
|
|
15101
|
+
};
|
|
15102
|
+
return {
|
|
15103
|
+
ImportDeclaration(node) {
|
|
15104
|
+
const source = importSource(node);
|
|
15105
|
+
if (source === null || !FS_MODULES.has(source)) return;
|
|
15106
|
+
for (const specifier of node.specifiers) {
|
|
15107
|
+
if (specifier.type === import_utils70.AST_NODE_TYPES.ImportSpecifier) {
|
|
15108
|
+
const imported = specifier.imported.type === import_utils70.AST_NODE_TYPES.Identifier ? specifier.imported.name : String(specifier.imported.value);
|
|
15109
|
+
if (FS_READERS.has(imported)) declare(specifier.local.name, { fsReader: true });
|
|
15110
|
+
} else {
|
|
15111
|
+
declare(specifier.local.name, { fsObject: true });
|
|
15112
|
+
}
|
|
15045
15113
|
}
|
|
15046
|
-
|
|
15114
|
+
},
|
|
15115
|
+
":function": enterFunction,
|
|
15116
|
+
":function:exit": exitFunction,
|
|
15117
|
+
VariableDeclarator(node) {
|
|
15118
|
+
if (node.init === null) return;
|
|
15119
|
+
const required = requireSource(node.init);
|
|
15120
|
+
if (required !== null && FS_MODULES.has(required) && node.id.type === import_utils70.AST_NODE_TYPES.Identifier) {
|
|
15121
|
+
declare(node.id.name, { fsObject: true });
|
|
15122
|
+
return;
|
|
15123
|
+
}
|
|
15124
|
+
if (node.id.type === import_utils70.AST_NODE_TYPES.ObjectPattern && required !== null && FS_MODULES.has(required)) {
|
|
15125
|
+
for (const property of node.id.properties) {
|
|
15126
|
+
if (property.type !== import_utils70.AST_NODE_TYPES.Property || property.value.type !== import_utils70.AST_NODE_TYPES.Identifier) continue;
|
|
15127
|
+
const key = property.key.type === import_utils70.AST_NODE_TYPES.Identifier ? property.key.name : property.key.type === import_utils70.AST_NODE_TYPES.Literal ? String(property.key.value) : "";
|
|
15128
|
+
if (FS_READERS.has(key)) declare(property.value.name, { fsReader: true });
|
|
15129
|
+
}
|
|
15130
|
+
return;
|
|
15131
|
+
}
|
|
15132
|
+
if (node.id.type !== import_utils70.AST_NODE_TYPES.Identifier) return;
|
|
15133
|
+
declare(node.id.name, { collection: sourceCollection(node.init), path: sourcePath(node.init), rawOrigins: rawOrigins(node.init) });
|
|
15134
|
+
},
|
|
15135
|
+
AssignmentExpression(node) {
|
|
15136
|
+
if (node.left.type === import_utils70.AST_NODE_TYPES.Identifier) declare(node.left.name, { path: sourcePath(node.right), rawOrigins: rawOrigins(node.right) });
|
|
15137
|
+
},
|
|
15138
|
+
ForOfStatement(node) {
|
|
15139
|
+
const right = unwrap5(node.right);
|
|
15140
|
+
const collection = right.type === import_utils70.AST_NODE_TYPES.Identifier && visible("collections", right.name);
|
|
15141
|
+
const left = node.left.type === import_utils70.AST_NODE_TYPES.VariableDeclaration ? node.left.declarations[0]?.id : node.left;
|
|
15142
|
+
if (collection && left?.type === import_utils70.AST_NODE_TYPES.Identifier) declare(left.name, { path: true });
|
|
15143
|
+
},
|
|
15144
|
+
CallExpression(node) {
|
|
15145
|
+
const origins = rawAssertionOrigins(node);
|
|
15146
|
+
if (origins.size === 0 || [...origins].every((origin) => reportedOrigins.has(origin))) return;
|
|
15147
|
+
for (const origin of origins) reportedOrigins.add(origin);
|
|
15148
|
+
context.report({ node, messageId: "rawSourceOracle" });
|
|
15047
15149
|
}
|
|
15048
|
-
|
|
15049
|
-
|
|
15050
|
-
|
|
15051
|
-
|
|
15052
|
-
|
|
15053
|
-
|
|
15054
|
-
|
|
15055
|
-
|
|
15056
|
-
|
|
15057
|
-
|
|
15058
|
-
|
|
15059
|
-
|
|
15060
|
-
|
|
15061
|
-
|
|
15062
|
-
|
|
15063
|
-
|
|
15064
|
-
|
|
15065
|
-
|
|
15066
|
-
|
|
15067
|
-
|
|
15068
|
-
|
|
15150
|
+
};
|
|
15151
|
+
}
|
|
15152
|
+
});
|
|
15153
|
+
}
|
|
15154
|
+
var source_coupled_test_default = createSourceCoupledRule(
|
|
15155
|
+
"source-coupled-test",
|
|
15156
|
+
sourceCoupledTestDocumentation,
|
|
15157
|
+
GENERAL_SOURCE_SUFFIX_RE
|
|
15158
|
+
);
|
|
15159
|
+
|
|
15160
|
+
// src/rules/iac-source-coupled-test.ts
|
|
15161
|
+
var IAC_SOURCE_SUFFIX_RE = /(?:\.tf\.json|\.tftest\.(?:hcl|json)|\.(?:hcl|tf|tfvars))$/iu;
|
|
15162
|
+
var iacSourceCoupledTestDocumentation = {
|
|
15163
|
+
summary: "Disallow raw IaC source text as a test oracle; inspect a rendered plan, provider state, or runtime behavior.",
|
|
15164
|
+
rationale: "Substring and regex checks can pass on comments, formatting, or unreachable Terraform configuration while clients fail silently.",
|
|
15165
|
+
remediation: "Parse rendered plan JSON, query the provider, or exercise the deployed runtime contract.",
|
|
15166
|
+
category: "testing",
|
|
15167
|
+
limitations: [
|
|
15168
|
+
"The rule follows lexical aliases, source-path collections, awaited reads, and common text operations; interprocedural flows remain unreported.",
|
|
15169
|
+
"The warning-stage rule remains suppressible for calibration; promotion may make the locked policy non-suppressible."
|
|
15170
|
+
],
|
|
15171
|
+
examples: [
|
|
15172
|
+
{
|
|
15173
|
+
id: "rendered-plan-contract",
|
|
15174
|
+
title: "Assert on rendered plan behavior",
|
|
15175
|
+
outcome: "no-match",
|
|
15176
|
+
files: [{ path: "src/policy.test.ts", source: "import { readFileSync } from 'node:fs'; test('policy', () => { const plan = JSON.parse(readFileSync('plan.json', 'utf8')); expect(validate(plan)).toEqual([]); });" }],
|
|
15177
|
+
focusPath: "src/policy.test.ts",
|
|
15178
|
+
expectedCount: 0,
|
|
15179
|
+
public: true
|
|
15180
|
+
},
|
|
15181
|
+
{
|
|
15182
|
+
id: "terraform-substring-contract",
|
|
15183
|
+
title: "Do not prove Terraform behavior with a regex",
|
|
15184
|
+
outcome: "match",
|
|
15185
|
+
files: [{ path: "src/policy.test.ts", source: "import { readFileSync } from 'node:fs'; test('policy', () => { const source = readFileSync('main.tf', 'utf8'); expect(source).toMatch(/prevent_destroy/); });" }],
|
|
15186
|
+
focusPath: "src/policy.test.ts",
|
|
15187
|
+
expectedCount: 1,
|
|
15188
|
+
public: true
|
|
15189
|
+
}
|
|
15190
|
+
]
|
|
15191
|
+
};
|
|
15192
|
+
var iac_source_coupled_test_default = createSourceCoupledRule(
|
|
15193
|
+
"iac-source-coupled-test",
|
|
15194
|
+
iacSourceCoupledTestDocumentation,
|
|
15195
|
+
IAC_SOURCE_SUFFIX_RE
|
|
15196
|
+
);
|
|
15069
15197
|
|
|
15070
15198
|
// src/rules/zod-naming-convention.ts
|
|
15071
15199
|
var import_utils71 = require("@typescript-eslint/utils");
|
|
@@ -15290,6 +15418,7 @@ var retiredRules = {
|
|
|
15290
15418
|
|
|
15291
15419
|
// src/index.ts
|
|
15292
15420
|
var rules = {
|
|
15421
|
+
"iac-source-coupled-test": iac_source_coupled_test_default,
|
|
15293
15422
|
"duplicate-test-body": duplicate_test_body_default,
|
|
15294
15423
|
"enforce-file-structure": enforce_file_structure_default,
|
|
15295
15424
|
"no-client-side-data-fetching": no_client_side_data_fetching_default,
|
|
@@ -15305,6 +15434,7 @@ var rules = {
|
|
|
15305
15434
|
"no-impossible-zod-literal-bounds": no_impossible_zod_literal_bounds_default,
|
|
15306
15435
|
"no-log-only-catch": no_log_only_catch_default,
|
|
15307
15436
|
"no-long-comment": no_long_comment_default,
|
|
15437
|
+
"no-vague-suppression-description": no_vague_suppression_description_default,
|
|
15308
15438
|
"no-generic-single-export-module": no_generic_single_export_module_default,
|
|
15309
15439
|
"no-offset-pagination": no_offset_pagination_default,
|
|
15310
15440
|
"no-positional-tuple-return": no_positional_tuple_return_default,
|
|
@@ -15358,15 +15488,16 @@ var rules = {
|
|
|
15358
15488
|
};
|
|
15359
15489
|
var meta = {
|
|
15360
15490
|
name: "@sarj/eslint-plugin",
|
|
15361
|
-
version: "15.
|
|
15491
|
+
version: "15.7.0"
|
|
15362
15492
|
};
|
|
15363
15493
|
var applicationOnlyRules = [
|
|
15364
15494
|
"no-restricted-library-load",
|
|
15365
15495
|
"prefer-native-random-uuid",
|
|
15366
15496
|
"prefer-shadcn-primitives"
|
|
15367
15497
|
];
|
|
15368
|
-
var advisoryRules = ["source-coupled-test"];
|
|
15498
|
+
var advisoryRules = ["no-vague-suppression-description", "iac-source-coupled-test", "source-coupled-test"];
|
|
15369
15499
|
var recommendedRules = {
|
|
15500
|
+
"@sarj/iac-source-coupled-test": "warn",
|
|
15370
15501
|
"@sarj/duplicate-test-body": "error",
|
|
15371
15502
|
"@sarj/enforce-file-structure": "error",
|
|
15372
15503
|
"@sarj/no-client-side-data-fetching": "error",
|
|
@@ -15381,6 +15512,7 @@ var recommendedRules = {
|
|
|
15381
15512
|
"@sarj/no-impossible-zod-literal-bounds": "error",
|
|
15382
15513
|
"@sarj/no-log-only-catch": "error",
|
|
15383
15514
|
"@sarj/no-long-comment": "error",
|
|
15515
|
+
"@sarj/no-vague-suppression-description": "warn",
|
|
15384
15516
|
"@sarj/no-generic-single-export-module": "error",
|
|
15385
15517
|
"@sarj/no-offset-pagination": "error",
|
|
15386
15518
|
"@sarj/no-positional-tuple-return": "error",
|
|
@@ -15427,6 +15559,7 @@ var recommendedRules = {
|
|
|
15427
15559
|
"@sarj/zod-naming-convention": "error"
|
|
15428
15560
|
};
|
|
15429
15561
|
var strictRules = {
|
|
15562
|
+
"@sarj/iac-source-coupled-test": "warn",
|
|
15430
15563
|
"@sarj/duplicate-test-body": "error",
|
|
15431
15564
|
"@sarj/enforce-file-structure": "error",
|
|
15432
15565
|
"@sarj/no-client-side-data-fetching": "error",
|
|
@@ -15442,6 +15575,7 @@ var strictRules = {
|
|
|
15442
15575
|
"@sarj/no-impossible-zod-literal-bounds": "error",
|
|
15443
15576
|
"@sarj/no-log-only-catch": "error",
|
|
15444
15577
|
"@sarj/no-long-comment": "error",
|
|
15578
|
+
"@sarj/no-vague-suppression-description": "warn",
|
|
15445
15579
|
"@sarj/no-generic-single-export-module": "error",
|
|
15446
15580
|
"@sarj/no-offset-pagination": "error",
|
|
15447
15581
|
"@sarj/no-positional-tuple-return": "error",
|