@sarj/eslint-plugin 15.6.7 → 15.6.9
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 +389 -17
- package/dist/index.d.cts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +387 -16
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -30,6 +30,7 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
|
|
|
30
30
|
// src/index.ts
|
|
31
31
|
var index_exports = {};
|
|
32
32
|
__export(index_exports, {
|
|
33
|
+
advisoryRules: () => advisoryRules,
|
|
33
34
|
applicationOnlyRules: () => applicationOnlyRules,
|
|
34
35
|
default: () => index_default,
|
|
35
36
|
publicDocumentation: () => publicDocumentation,
|
|
@@ -4291,6 +4292,87 @@ var no_long_comment_default = createRule({
|
|
|
4291
4292
|
}
|
|
4292
4293
|
});
|
|
4293
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
|
+
|
|
4294
4376
|
// src/rules/no-generic-single-export-module.ts
|
|
4295
4377
|
var import_utils21 = require("@typescript-eslint/utils");
|
|
4296
4378
|
var noGenericSingleExportModuleDocumentation = {
|
|
@@ -5430,7 +5512,7 @@ var no_repeated_string_literal_default = createRule({
|
|
|
5430
5512
|
var import_utils28 = require("@typescript-eslint/utils");
|
|
5431
5513
|
var MAX_WORDS = 8;
|
|
5432
5514
|
var MIN_CONTENT_TOKENS = 2;
|
|
5433
|
-
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;
|
|
5434
5516
|
var CODEY_RE = /^[\w.$[\]'"]+\s*[:=]\s*\S|^[\w.$]+\s*\(|^(?:return|throw|await|import|export|const|let|var)\b.*[=()[\]{}]/;
|
|
5435
5517
|
var BANNERISH_RE = /[=\-─-╿*#~_.]{3,}|^[A-Z0-9 _:-]+$/;
|
|
5436
5518
|
var MODALITY_RE = /\b(?:can|could|should|shall|may|might|must|will|would|cannot)\b/i;
|
|
@@ -5529,7 +5611,7 @@ var no_restated_comment_default = createRule({
|
|
|
5529
5611
|
}
|
|
5530
5612
|
const body2 = comment.value.replace(/^\/*/, "").trim();
|
|
5531
5613
|
if (body2.length === 0 || body2.endsWith("?")) continue;
|
|
5532
|
-
if (
|
|
5614
|
+
if (DIRECTIVE_RE4.test(body2) || CODEY_RE.test(body2) || BANNERISH_RE.test(body2)) continue;
|
|
5533
5615
|
if (NON_ASCII_LETTER_RE.test(body2) || isProtected(body2)) continue;
|
|
5534
5616
|
if (MODALITY_RE.test(body2) || LEAD_IN_RE.test(body2) || EMPHASIS_RE.test(body2)) continue;
|
|
5535
5617
|
if (NEGATION_WORD_RE.test(body2)) continue;
|
|
@@ -5577,7 +5659,7 @@ var MODELLED_TAGS = /* @__PURE__ */ new Set([
|
|
|
5577
5659
|
]);
|
|
5578
5660
|
var PARAM_TAGS = /* @__PURE__ */ new Set(["arg", "argument", "param"]);
|
|
5579
5661
|
var RETURN_TAGS = /* @__PURE__ */ new Set(["return", "returns"]);
|
|
5580
|
-
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;
|
|
5581
5663
|
var STOPWORDS2 = new Set(
|
|
5582
5664
|
`the a an of to for in on with and or as at by is are was be been being
|
|
5583
5665
|
this that it its if whether when where which what will would can could should
|
|
@@ -5693,7 +5775,7 @@ var no_restated_jsdoc_default = createRule({
|
|
|
5693
5775
|
description,
|
|
5694
5776
|
...tags.filter((tag) => tag.name === "description").map((tag) => tag.text)
|
|
5695
5777
|
].filter((text) => text.length > 0).join("\n");
|
|
5696
|
-
if (
|
|
5778
|
+
if (DIRECTIVE_RE5.test(describedText)) continue;
|
|
5697
5779
|
const tagNames = new Set(tags.map((tag) => tag.name));
|
|
5698
5780
|
if ([...tagNames].some((name) => !MODELLED_TAGS.has(name))) continue;
|
|
5699
5781
|
if (isProtected(describedText)) continue;
|
|
@@ -7655,10 +7737,10 @@ var STOPWORDS3 = /* @__PURE__ */ new Set([
|
|
|
7655
7737
|
"we",
|
|
7656
7738
|
"with"
|
|
7657
7739
|
]);
|
|
7658
|
-
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;
|
|
7659
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;
|
|
7660
7742
|
function narratesValue(body2, code) {
|
|
7661
|
-
if (body2.length === 0 ||
|
|
7743
|
+
if (body2.length === 0 || DIRECTIVE_RE6.test(body2) || hasExternalReference(body2)) return false;
|
|
7662
7744
|
const codeNumbers = numbersIn(code);
|
|
7663
7745
|
if (codeNumbers.size === 0) return false;
|
|
7664
7746
|
const words2 = (body2.match(WORD_RE3) ?? []).map((word) => word.toLowerCase());
|
|
@@ -14784,8 +14866,290 @@ var stepdown_default = createRule({
|
|
|
14784
14866
|
}
|
|
14785
14867
|
});
|
|
14786
14868
|
|
|
14787
|
-
// src/rules/
|
|
14869
|
+
// src/rules/source-coupled-test.ts
|
|
14788
14870
|
var import_utils70 = require("@typescript-eslint/utils");
|
|
14871
|
+
var SOURCE_SUFFIX_RE = /\.(?:bash|hcl|sh|tf|tfvars|ya?ml|py|[cm]?[jt]s)$/iu;
|
|
14872
|
+
var FS_MODULES = /* @__PURE__ */ new Set(["fs", "node:fs", "fs/promises", "node:fs/promises"]);
|
|
14873
|
+
var FS_READERS = /* @__PURE__ */ new Set(["readFile", "readFileSync"]);
|
|
14874
|
+
var TEXT_TRANSFORMS = /* @__PURE__ */ new Set([
|
|
14875
|
+
"slice",
|
|
14876
|
+
"substring",
|
|
14877
|
+
"substr",
|
|
14878
|
+
"toLowerCase",
|
|
14879
|
+
"toString",
|
|
14880
|
+
"toUpperCase",
|
|
14881
|
+
"trim",
|
|
14882
|
+
"trimEnd",
|
|
14883
|
+
"trimStart",
|
|
14884
|
+
"replace",
|
|
14885
|
+
"replaceAll"
|
|
14886
|
+
]);
|
|
14887
|
+
var TEXT_PREDICATES = /* @__PURE__ */ new Set(["endsWith", "includes", "indexOf", "lastIndexOf", "match", "matchAll", "search", "startsWith"]);
|
|
14888
|
+
var REGEXP_PREDICATES = /* @__PURE__ */ new Set(["exec", "test"]);
|
|
14889
|
+
var EXPECT_MATCHERS = /* @__PURE__ */ new Set([
|
|
14890
|
+
"toBe",
|
|
14891
|
+
"toBeFalsy",
|
|
14892
|
+
"toBeGreaterThan",
|
|
14893
|
+
"toBeGreaterThanOrEqual",
|
|
14894
|
+
"toBeLessThan",
|
|
14895
|
+
"toBeLessThanOrEqual",
|
|
14896
|
+
"toBeNull",
|
|
14897
|
+
"toBeTruthy",
|
|
14898
|
+
"toContain",
|
|
14899
|
+
"toEqual",
|
|
14900
|
+
"toHaveLength",
|
|
14901
|
+
"toMatch",
|
|
14902
|
+
"toMatchSnapshot",
|
|
14903
|
+
"toStrictEqual"
|
|
14904
|
+
]);
|
|
14905
|
+
var EXPECT_MODIFIERS = /* @__PURE__ */ new Set(["not", "rejects", "resolves"]);
|
|
14906
|
+
var ASSERT_MATCHERS = /* @__PURE__ */ new Set(["deepEqual", "doesNotMatch", "equal", "match", "notDeepEqual", "notEqual", "notStrictEqual", "ok", "strictEqual"]);
|
|
14907
|
+
var sourceCoupledTestDocumentation = {
|
|
14908
|
+
summary: "Disallow raw repository source text as a test oracle; parse or execute the artifact instead.",
|
|
14909
|
+
rationale: "Substring and regex checks can pass on comments or unreachable configuration and fail after behavior-preserving formatting changes.",
|
|
14910
|
+
remediation: "Parse the artifact, execute its validator, or assert on Terraform plan JSON or another runtime contract.",
|
|
14911
|
+
category: "testing",
|
|
14912
|
+
limitations: [
|
|
14913
|
+
"The rule follows lexical aliases, source-path collections, awaited reads, and common text operations; interprocedural flows remain unreported.",
|
|
14914
|
+
"When raw representation is genuinely the contract (for example a golden or compatibility sentinel), use an exact line suppression with the reason."
|
|
14915
|
+
],
|
|
14916
|
+
examples: [
|
|
14917
|
+
{
|
|
14918
|
+
id: "parsed-policy-contract",
|
|
14919
|
+
title: "Assert on parsed policy behavior",
|
|
14920
|
+
outcome: "no-match",
|
|
14921
|
+
files: [{ path: "src/policy.test.ts", source: "import { readFileSync } from 'node:fs'; test('policy', () => { const policy = JSON.parse(readFileSync('policy.json', 'utf8')); expect(validate(policy)).toEqual([]); });" }],
|
|
14922
|
+
focusPath: "src/policy.test.ts",
|
|
14923
|
+
expectedCount: 0,
|
|
14924
|
+
public: true
|
|
14925
|
+
},
|
|
14926
|
+
{
|
|
14927
|
+
id: "terraform-substring-contract",
|
|
14928
|
+
title: "Do not prove Terraform behavior with a regex",
|
|
14929
|
+
outcome: "match",
|
|
14930
|
+
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/); });" }],
|
|
14931
|
+
focusPath: "src/policy.test.ts",
|
|
14932
|
+
expectedCount: 1,
|
|
14933
|
+
public: true
|
|
14934
|
+
}
|
|
14935
|
+
]
|
|
14936
|
+
};
|
|
14937
|
+
function staticMemberName5(node) {
|
|
14938
|
+
if (!node.computed && node.property.type === import_utils70.AST_NODE_TYPES.Identifier) return node.property.name;
|
|
14939
|
+
if (node.computed && node.property.type === import_utils70.AST_NODE_TYPES.Literal && typeof node.property.value === "string") return node.property.value;
|
|
14940
|
+
return null;
|
|
14941
|
+
}
|
|
14942
|
+
function unwrap5(node) {
|
|
14943
|
+
if (node.type === import_utils70.AST_NODE_TYPES.AwaitExpression) return unwrap5(node.argument);
|
|
14944
|
+
if (node.type === import_utils70.AST_NODE_TYPES.ChainExpression) return unwrap5(node.expression);
|
|
14945
|
+
if (node.type === import_utils70.AST_NODE_TYPES.TSAsExpression || node.type === import_utils70.AST_NODE_TYPES.TSNonNullExpression || node.type === import_utils70.AST_NODE_TYPES.TSTypeAssertion) return unwrap5(node.expression);
|
|
14946
|
+
return node;
|
|
14947
|
+
}
|
|
14948
|
+
function stringValue(node) {
|
|
14949
|
+
const current = unwrap5(node);
|
|
14950
|
+
if (current.type === import_utils70.AST_NODE_TYPES.Literal && typeof current.value === "string") return current.value;
|
|
14951
|
+
if (current.type === import_utils70.AST_NODE_TYPES.TemplateLiteral && current.expressions.length === 0) return current.quasis[0]?.value.cooked ?? null;
|
|
14952
|
+
return null;
|
|
14953
|
+
}
|
|
14954
|
+
function importSource(node) {
|
|
14955
|
+
return typeof node.source.value === "string" ? node.source.value : null;
|
|
14956
|
+
}
|
|
14957
|
+
function requireSource(node) {
|
|
14958
|
+
const current = unwrap5(node);
|
|
14959
|
+
if (current.type !== import_utils70.AST_NODE_TYPES.CallExpression || current.callee.type !== import_utils70.AST_NODE_TYPES.Identifier || current.callee.name !== "require" || current.arguments.length !== 1 || current.arguments[0]?.type === import_utils70.AST_NODE_TYPES.SpreadElement) return null;
|
|
14960
|
+
return stringValue(current.arguments[0]);
|
|
14961
|
+
}
|
|
14962
|
+
function newScope() {
|
|
14963
|
+
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() };
|
|
14964
|
+
}
|
|
14965
|
+
var source_coupled_test_default = createRule({
|
|
14966
|
+
name: "source-coupled-test",
|
|
14967
|
+
documentation: sourceCoupledTestDocumentation,
|
|
14968
|
+
meta: {
|
|
14969
|
+
type: "suggestion",
|
|
14970
|
+
docs: { description: sourceCoupledTestDocumentation.summary },
|
|
14971
|
+
schema: [],
|
|
14972
|
+
messages: { rawSourceOracle: "Raw repository source text is the oracle. Parse or execute the artifact so comments, formatting, and unreachable blocks cannot satisfy the contract." }
|
|
14973
|
+
},
|
|
14974
|
+
defaultOptions: [],
|
|
14975
|
+
create(context) {
|
|
14976
|
+
if (!isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) return {};
|
|
14977
|
+
const scopes = [newScope()];
|
|
14978
|
+
const reportedOrigins = /* @__PURE__ */ new Set();
|
|
14979
|
+
const currentScope = () => scopes.at(-1) ?? scopes[0];
|
|
14980
|
+
const visible = (kind, name) => {
|
|
14981
|
+
for (let index = scopes.length - 1; index >= 0; index--) {
|
|
14982
|
+
const scope = scopes[index];
|
|
14983
|
+
if (scope.declared.has(name)) return scope[kind].has(name);
|
|
14984
|
+
}
|
|
14985
|
+
return false;
|
|
14986
|
+
};
|
|
14987
|
+
const visibleRawOrigins = (name) => {
|
|
14988
|
+
for (let index = scopes.length - 1; index >= 0; index--) {
|
|
14989
|
+
const scope = scopes[index];
|
|
14990
|
+
if (scope.declared.has(name)) return scope.rawOrigins.get(name) ?? /* @__PURE__ */ new Set();
|
|
14991
|
+
}
|
|
14992
|
+
return /* @__PURE__ */ new Set();
|
|
14993
|
+
};
|
|
14994
|
+
const sourcePath = (node) => {
|
|
14995
|
+
const current = unwrap5(node);
|
|
14996
|
+
const value = stringValue(current);
|
|
14997
|
+
if (value !== null) return SOURCE_SUFFIX_RE.test(value);
|
|
14998
|
+
if (current.type === import_utils70.AST_NODE_TYPES.Identifier) return visible("paths", current.name);
|
|
14999
|
+
if (current.type === import_utils70.AST_NODE_TYPES.BinaryExpression && current.operator === "+") {
|
|
15000
|
+
return sourcePath(current.left) || sourcePath(current.right);
|
|
15001
|
+
}
|
|
15002
|
+
if (current.type === import_utils70.AST_NODE_TYPES.TemplateLiteral) return current.expressions.some(sourcePath);
|
|
15003
|
+
if (current.type === import_utils70.AST_NODE_TYPES.CallExpression || current.type === import_utils70.AST_NODE_TYPES.NewExpression) {
|
|
15004
|
+
return current.arguments.some((argument) => argument.type !== import_utils70.AST_NODE_TYPES.SpreadElement && sourcePath(argument));
|
|
15005
|
+
}
|
|
15006
|
+
if (current.type === import_utils70.AST_NODE_TYPES.MemberExpression) return sourcePath(current.object);
|
|
15007
|
+
return false;
|
|
15008
|
+
};
|
|
15009
|
+
const rawRead = (node) => {
|
|
15010
|
+
const current = unwrap5(node);
|
|
15011
|
+
if (current.type !== import_utils70.AST_NODE_TYPES.CallExpression || current.arguments.length === 0) return false;
|
|
15012
|
+
const callee = unwrap5(current.callee);
|
|
15013
|
+
if (callee.type === import_utils70.AST_NODE_TYPES.Identifier) {
|
|
15014
|
+
return visible("fsReaders", callee.name) && sourcePath(current.arguments[0]);
|
|
15015
|
+
}
|
|
15016
|
+
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return false;
|
|
15017
|
+
const name = staticMemberName5(callee);
|
|
15018
|
+
const object = unwrap5(callee.object);
|
|
15019
|
+
return name !== null && FS_READERS.has(name) && object.type === import_utils70.AST_NODE_TYPES.Identifier && visible("fsObjects", object.name) && sourcePath(current.arguments[0]);
|
|
15020
|
+
};
|
|
15021
|
+
const rawOrigins = (node) => {
|
|
15022
|
+
const current = unwrap5(node);
|
|
15023
|
+
if (current.type === import_utils70.AST_NODE_TYPES.Identifier) return visibleRawOrigins(current.name);
|
|
15024
|
+
if (rawRead(current)) return /* @__PURE__ */ new Set([`${current.range[0]}:${current.range[1]}`]);
|
|
15025
|
+
if (current.type === import_utils70.AST_NODE_TYPES.BinaryExpression && current.operator === "+") return /* @__PURE__ */ new Set([...rawOrigins(current.left), ...rawOrigins(current.right)]);
|
|
15026
|
+
if (current.type !== import_utils70.AST_NODE_TYPES.CallExpression) return /* @__PURE__ */ new Set();
|
|
15027
|
+
const callee = unwrap5(current.callee);
|
|
15028
|
+
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return /* @__PURE__ */ new Set();
|
|
15029
|
+
const name = staticMemberName5(callee);
|
|
15030
|
+
return name !== null && TEXT_TRANSFORMS.has(name) ? rawOrigins(callee.object) : /* @__PURE__ */ new Set();
|
|
15031
|
+
};
|
|
15032
|
+
const evidenceOrigins = (node) => {
|
|
15033
|
+
const current = unwrap5(node);
|
|
15034
|
+
const direct = rawOrigins(current);
|
|
15035
|
+
if (direct.size > 0) return direct;
|
|
15036
|
+
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)]);
|
|
15037
|
+
if (current.type === import_utils70.AST_NODE_TYPES.UnaryExpression) return evidenceOrigins(current.argument);
|
|
15038
|
+
if (current.type !== import_utils70.AST_NODE_TYPES.CallExpression) return /* @__PURE__ */ new Set();
|
|
15039
|
+
const callee = unwrap5(current.callee);
|
|
15040
|
+
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return /* @__PURE__ */ new Set();
|
|
15041
|
+
const name = staticMemberName5(callee);
|
|
15042
|
+
if (name !== null && TEXT_PREDICATES.has(name)) return rawOrigins(callee.object);
|
|
15043
|
+
if (name !== null && REGEXP_PREDICATES.has(name)) return new Set(current.arguments.flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...rawOrigins(argument)]));
|
|
15044
|
+
return /* @__PURE__ */ new Set();
|
|
15045
|
+
};
|
|
15046
|
+
const rawAssertionOrigins = (node) => {
|
|
15047
|
+
const callee = unwrap5(node.callee);
|
|
15048
|
+
if (callee.type === import_utils70.AST_NODE_TYPES.Identifier && callee.name === "assert") {
|
|
15049
|
+
return new Set(node.arguments.flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
15050
|
+
}
|
|
15051
|
+
if (callee.type !== import_utils70.AST_NODE_TYPES.MemberExpression) return /* @__PURE__ */ new Set();
|
|
15052
|
+
const matcher = staticMemberName5(callee);
|
|
15053
|
+
if (matcher === null) return /* @__PURE__ */ new Set();
|
|
15054
|
+
let receiver = unwrap5(callee.object);
|
|
15055
|
+
while (receiver.type === import_utils70.AST_NODE_TYPES.MemberExpression && EXPECT_MODIFIERS.has(staticMemberName5(receiver) ?? "")) receiver = unwrap5(receiver.object);
|
|
15056
|
+
if (receiver.type === import_utils70.AST_NODE_TYPES.CallExpression && receiver.callee.type === import_utils70.AST_NODE_TYPES.Identifier && receiver.callee.name === "expect") {
|
|
15057
|
+
if (!EXPECT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
|
|
15058
|
+
return new Set([...receiver.arguments, ...node.arguments].flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
15059
|
+
}
|
|
15060
|
+
if (receiver.type !== import_utils70.AST_NODE_TYPES.Identifier || receiver.name !== "assert" || !ASSERT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
|
|
15061
|
+
return new Set(node.arguments.flatMap((argument) => argument.type === import_utils70.AST_NODE_TYPES.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
15062
|
+
};
|
|
15063
|
+
const declare = (name, state) => {
|
|
15064
|
+
const scope = currentScope();
|
|
15065
|
+
scope.declared.add(name);
|
|
15066
|
+
scope.collections.delete(name);
|
|
15067
|
+
scope.fsObjects.delete(name);
|
|
15068
|
+
scope.fsReaders.delete(name);
|
|
15069
|
+
scope.paths.delete(name);
|
|
15070
|
+
scope.rawOrigins.delete(name);
|
|
15071
|
+
if (state.collection === true) scope.collections.add(name);
|
|
15072
|
+
if (state.fsObject === true) scope.fsObjects.add(name);
|
|
15073
|
+
if (state.fsReader === true) scope.fsReaders.add(name);
|
|
15074
|
+
if (state.path === true) scope.paths.add(name);
|
|
15075
|
+
if (state.rawOrigins !== void 0 && state.rawOrigins.size > 0) {
|
|
15076
|
+
scope.rawOrigins.set(name, state.rawOrigins);
|
|
15077
|
+
}
|
|
15078
|
+
};
|
|
15079
|
+
const sourceCollection = (node) => {
|
|
15080
|
+
const current = unwrap5(node);
|
|
15081
|
+
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));
|
|
15082
|
+
};
|
|
15083
|
+
const declaredNames2 = (node) => {
|
|
15084
|
+
const current = unwrap5(node);
|
|
15085
|
+
if (current.type === import_utils70.AST_NODE_TYPES.Identifier) return [current.name];
|
|
15086
|
+
if (current.type === import_utils70.AST_NODE_TYPES.AssignmentPattern) return declaredNames2(current.left);
|
|
15087
|
+
if (current.type === import_utils70.AST_NODE_TYPES.RestElement) return declaredNames2(current.argument);
|
|
15088
|
+
if (current.type === import_utils70.AST_NODE_TYPES.ArrayPattern) return current.elements.flatMap((element) => element === null ? [] : declaredNames2(element));
|
|
15089
|
+
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));
|
|
15090
|
+
return [];
|
|
15091
|
+
};
|
|
15092
|
+
const enterFunction = (node) => {
|
|
15093
|
+
scopes.push(newScope());
|
|
15094
|
+
for (const parameter of node.params) for (const name of declaredNames2(parameter)) declare(name, {});
|
|
15095
|
+
};
|
|
15096
|
+
const exitFunction = () => {
|
|
15097
|
+
scopes.pop();
|
|
15098
|
+
};
|
|
15099
|
+
return {
|
|
15100
|
+
ImportDeclaration(node) {
|
|
15101
|
+
const source = importSource(node);
|
|
15102
|
+
if (source === null || !FS_MODULES.has(source)) return;
|
|
15103
|
+
for (const specifier of node.specifiers) {
|
|
15104
|
+
if (specifier.type === import_utils70.AST_NODE_TYPES.ImportSpecifier) {
|
|
15105
|
+
const imported = specifier.imported.type === import_utils70.AST_NODE_TYPES.Identifier ? specifier.imported.name : String(specifier.imported.value);
|
|
15106
|
+
if (FS_READERS.has(imported)) declare(specifier.local.name, { fsReader: true });
|
|
15107
|
+
} else {
|
|
15108
|
+
declare(specifier.local.name, { fsObject: true });
|
|
15109
|
+
}
|
|
15110
|
+
}
|
|
15111
|
+
},
|
|
15112
|
+
":function": enterFunction,
|
|
15113
|
+
":function:exit": exitFunction,
|
|
15114
|
+
VariableDeclarator(node) {
|
|
15115
|
+
if (node.init === null) return;
|
|
15116
|
+
const required = requireSource(node.init);
|
|
15117
|
+
if (required !== null && FS_MODULES.has(required) && node.id.type === import_utils70.AST_NODE_TYPES.Identifier) {
|
|
15118
|
+
declare(node.id.name, { fsObject: true });
|
|
15119
|
+
return;
|
|
15120
|
+
}
|
|
15121
|
+
if (node.id.type === import_utils70.AST_NODE_TYPES.ObjectPattern && required !== null && FS_MODULES.has(required)) {
|
|
15122
|
+
for (const property of node.id.properties) {
|
|
15123
|
+
if (property.type !== import_utils70.AST_NODE_TYPES.Property || property.value.type !== import_utils70.AST_NODE_TYPES.Identifier) continue;
|
|
15124
|
+
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) : "";
|
|
15125
|
+
if (FS_READERS.has(key)) declare(property.value.name, { fsReader: true });
|
|
15126
|
+
}
|
|
15127
|
+
return;
|
|
15128
|
+
}
|
|
15129
|
+
if (node.id.type !== import_utils70.AST_NODE_TYPES.Identifier) return;
|
|
15130
|
+
declare(node.id.name, { collection: sourceCollection(node.init), path: sourcePath(node.init), rawOrigins: rawOrigins(node.init) });
|
|
15131
|
+
},
|
|
15132
|
+
AssignmentExpression(node) {
|
|
15133
|
+
if (node.left.type === import_utils70.AST_NODE_TYPES.Identifier) declare(node.left.name, { path: sourcePath(node.right), rawOrigins: rawOrigins(node.right) });
|
|
15134
|
+
},
|
|
15135
|
+
ForOfStatement(node) {
|
|
15136
|
+
const right = unwrap5(node.right);
|
|
15137
|
+
const collection = right.type === import_utils70.AST_NODE_TYPES.Identifier && visible("collections", right.name);
|
|
15138
|
+
const left = node.left.type === import_utils70.AST_NODE_TYPES.VariableDeclaration ? node.left.declarations[0]?.id : node.left;
|
|
15139
|
+
if (collection && left?.type === import_utils70.AST_NODE_TYPES.Identifier) declare(left.name, { path: true });
|
|
15140
|
+
},
|
|
15141
|
+
CallExpression(node) {
|
|
15142
|
+
const origins = rawAssertionOrigins(node);
|
|
15143
|
+
if (origins.size === 0 || [...origins].every((origin) => reportedOrigins.has(origin))) return;
|
|
15144
|
+
for (const origin of origins) reportedOrigins.add(origin);
|
|
15145
|
+
context.report({ node, messageId: "rawSourceOracle" });
|
|
15146
|
+
}
|
|
15147
|
+
};
|
|
15148
|
+
}
|
|
15149
|
+
});
|
|
15150
|
+
|
|
15151
|
+
// src/rules/zod-naming-convention.ts
|
|
15152
|
+
var import_utils71 = require("@typescript-eslint/utils");
|
|
14789
15153
|
var zodNamingConventionDocumentation = {
|
|
14790
15154
|
summary: "Enforce a consistent Zod schema naming convention \u2014 a `Z` prefix (`ZUser`) or a `Schema` suffix (`userSchema`); both are accepted by default.",
|
|
14791
15155
|
rationale: "A recognizable schema name distinguishes runtime validators from ordinary values at each use site.",
|
|
@@ -14826,18 +15190,18 @@ var NON_SCHEMA_TERMINALS = /* @__PURE__ */ new Set([
|
|
|
14826
15190
|
"prettifyError",
|
|
14827
15191
|
"treeifyError"
|
|
14828
15192
|
]);
|
|
14829
|
-
var terminalMethodName = (callee) => !callee.computed && callee.property.type ===
|
|
15193
|
+
var terminalMethodName = (callee) => !callee.computed && callee.property.type === import_utils71.AST_NODE_TYPES.Identifier ? callee.property.name : null;
|
|
14830
15194
|
var calleeChainRoot = (node) => {
|
|
14831
15195
|
let current = node;
|
|
14832
15196
|
for (; ; ) {
|
|
14833
|
-
if (current.type ===
|
|
15197
|
+
if (current.type === import_utils71.AST_NODE_TYPES.Identifier) {
|
|
14834
15198
|
return current;
|
|
14835
15199
|
}
|
|
14836
|
-
if (current.type ===
|
|
15200
|
+
if (current.type === import_utils71.AST_NODE_TYPES.MemberExpression) {
|
|
14837
15201
|
current = current.object;
|
|
14838
15202
|
continue;
|
|
14839
15203
|
}
|
|
14840
|
-
if (current.type ===
|
|
15204
|
+
if (current.type === import_utils71.AST_NODE_TYPES.CallExpression) {
|
|
14841
15205
|
current = current.callee;
|
|
14842
15206
|
continue;
|
|
14843
15207
|
}
|
|
@@ -14877,7 +15241,7 @@ var zod_naming_convention_default = createRule({
|
|
|
14877
15241
|
const acceptsSchemaWord = convention !== "prefix";
|
|
14878
15242
|
const zodBindings = /* @__PURE__ */ new Set();
|
|
14879
15243
|
function resolvedBinding(identifier) {
|
|
14880
|
-
return
|
|
15244
|
+
return import_utils71.ASTUtils.findVariable(
|
|
14881
15245
|
context.sourceCode.getScope(identifier),
|
|
14882
15246
|
identifier.name
|
|
14883
15247
|
);
|
|
@@ -14899,7 +15263,7 @@ var zod_naming_convention_default = createRule({
|
|
|
14899
15263
|
ImportDeclaration(node) {
|
|
14900
15264
|
if (!isZodModule(node.source.value)) return;
|
|
14901
15265
|
for (const specifier of node.specifiers) {
|
|
14902
|
-
if (specifier.type ===
|
|
15266
|
+
if (specifier.type === import_utils71.AST_NODE_TYPES.ImportNamespaceSpecifier || specifier.type === import_utils71.AST_NODE_TYPES.ImportDefaultSpecifier || specifier.type === import_utils71.AST_NODE_TYPES.ImportSpecifier && (specifier.imported.type === import_utils71.AST_NODE_TYPES.Identifier ? specifier.imported.name === "z" : specifier.imported.value === "z")) {
|
|
14903
15267
|
recordZodBinding(specifier.local);
|
|
14904
15268
|
}
|
|
14905
15269
|
}
|
|
@@ -14907,13 +15271,13 @@ var zod_naming_convention_default = createRule({
|
|
|
14907
15271
|
VariableDeclarator(node) {
|
|
14908
15272
|
const init = node.init;
|
|
14909
15273
|
if (init === null || init === void 0) return;
|
|
14910
|
-
if (init.type !==
|
|
15274
|
+
if (init.type !== import_utils71.AST_NODE_TYPES.CallExpression) return;
|
|
14911
15275
|
const callee = init.callee;
|
|
14912
|
-
if (callee.type !==
|
|
15276
|
+
if (callee.type !== import_utils71.AST_NODE_TYPES.MemberExpression) return;
|
|
14913
15277
|
if (!isZodChain(callee)) return;
|
|
14914
15278
|
const terminal = terminalMethodName(callee);
|
|
14915
15279
|
if (terminal !== null && NON_SCHEMA_TERMINALS.has(terminal)) return;
|
|
14916
|
-
if (node.id.type !==
|
|
15280
|
+
if (node.id.type !== import_utils71.AST_NODE_TYPES.Identifier) return;
|
|
14917
15281
|
if (test.test(node.id.name)) return;
|
|
14918
15282
|
if (acceptsSchemaWord && CONTAINS_SCHEMA_RE.test(node.id.name)) return;
|
|
14919
15283
|
context.report({
|
|
@@ -15022,6 +15386,7 @@ var rules = {
|
|
|
15022
15386
|
"no-impossible-zod-literal-bounds": no_impossible_zod_literal_bounds_default,
|
|
15023
15387
|
"no-log-only-catch": no_log_only_catch_default,
|
|
15024
15388
|
"no-long-comment": no_long_comment_default,
|
|
15389
|
+
"no-vague-suppression-description": no_vague_suppression_description_default,
|
|
15025
15390
|
"no-generic-single-export-module": no_generic_single_export_module_default,
|
|
15026
15391
|
"no-offset-pagination": no_offset_pagination_default,
|
|
15027
15392
|
"no-positional-tuple-return": no_positional_tuple_return_default,
|
|
@@ -15070,17 +15435,19 @@ var rules = {
|
|
|
15070
15435
|
"require-zod-form-validation": require_zod_form_validation_default,
|
|
15071
15436
|
"store-insert-requires-on-conflict": store_insert_requires_on_conflict_default,
|
|
15072
15437
|
"stepdown": stepdown_default,
|
|
15438
|
+
"source-coupled-test": source_coupled_test_default,
|
|
15073
15439
|
"zod-naming-convention": zod_naming_convention_default
|
|
15074
15440
|
};
|
|
15075
15441
|
var meta = {
|
|
15076
15442
|
name: "@sarj/eslint-plugin",
|
|
15077
|
-
version: "15.6.
|
|
15443
|
+
version: "15.6.9"
|
|
15078
15444
|
};
|
|
15079
15445
|
var applicationOnlyRules = [
|
|
15080
15446
|
"no-restricted-library-load",
|
|
15081
15447
|
"prefer-native-random-uuid",
|
|
15082
15448
|
"prefer-shadcn-primitives"
|
|
15083
15449
|
];
|
|
15450
|
+
var advisoryRules = ["no-vague-suppression-description", "source-coupled-test"];
|
|
15084
15451
|
var recommendedRules = {
|
|
15085
15452
|
"@sarj/duplicate-test-body": "error",
|
|
15086
15453
|
"@sarj/enforce-file-structure": "error",
|
|
@@ -15096,6 +15463,7 @@ var recommendedRules = {
|
|
|
15096
15463
|
"@sarj/no-impossible-zod-literal-bounds": "error",
|
|
15097
15464
|
"@sarj/no-log-only-catch": "error",
|
|
15098
15465
|
"@sarj/no-long-comment": "error",
|
|
15466
|
+
"@sarj/no-vague-suppression-description": "warn",
|
|
15099
15467
|
"@sarj/no-generic-single-export-module": "error",
|
|
15100
15468
|
"@sarj/no-offset-pagination": "error",
|
|
15101
15469
|
"@sarj/no-positional-tuple-return": "error",
|
|
@@ -15138,6 +15506,7 @@ var recommendedRules = {
|
|
|
15138
15506
|
"@sarj/require-zod-form-validation": "error",
|
|
15139
15507
|
"@sarj/store-insert-requires-on-conflict": "error",
|
|
15140
15508
|
"@sarj/stepdown": "error",
|
|
15509
|
+
"@sarj/source-coupled-test": "warn",
|
|
15141
15510
|
"@sarj/zod-naming-convention": "error"
|
|
15142
15511
|
};
|
|
15143
15512
|
var strictRules = {
|
|
@@ -15156,6 +15525,7 @@ var strictRules = {
|
|
|
15156
15525
|
"@sarj/no-impossible-zod-literal-bounds": "error",
|
|
15157
15526
|
"@sarj/no-log-only-catch": "error",
|
|
15158
15527
|
"@sarj/no-long-comment": "error",
|
|
15528
|
+
"@sarj/no-vague-suppression-description": "warn",
|
|
15159
15529
|
"@sarj/no-generic-single-export-module": "error",
|
|
15160
15530
|
"@sarj/no-offset-pagination": "error",
|
|
15161
15531
|
"@sarj/no-positional-tuple-return": "error",
|
|
@@ -15201,6 +15571,7 @@ var strictRules = {
|
|
|
15201
15571
|
"@sarj/require-zod-form-validation": "error",
|
|
15202
15572
|
"@sarj/store-insert-requires-on-conflict": "error",
|
|
15203
15573
|
"@sarj/stepdown": "error",
|
|
15574
|
+
"@sarj/source-coupled-test": "warn",
|
|
15204
15575
|
"@sarj/zod-naming-convention": "error"
|
|
15205
15576
|
};
|
|
15206
15577
|
var plugin = {
|
|
@@ -15225,6 +15596,7 @@ var plugin = {
|
|
|
15225
15596
|
var index_default = plugin;
|
|
15226
15597
|
// Annotate the CommonJS export names for ESM import in node:
|
|
15227
15598
|
0 && (module.exports = {
|
|
15599
|
+
advisoryRules,
|
|
15228
15600
|
applicationOnlyRules,
|
|
15229
15601
|
publicDocumentation,
|
|
15230
15602
|
recommendedRules,
|
package/dist/index.d.cts
CHANGED
|
@@ -208,6 +208,7 @@ declare const rules: {
|
|
|
208
208
|
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [], "impossibleBounds">;
|
|
209
209
|
readonly "no-log-only-catch": DocumentedRule<readonly [LoggingOptions?], "noLogOnlyCatch" | "emptyCatch">;
|
|
210
210
|
readonly "no-long-comment": DocumentedRule<readonly [], "tooLong">;
|
|
211
|
+
readonly "no-vague-suppression-description": DocumentedRule<readonly [], "vagueDescription">;
|
|
211
212
|
readonly "no-generic-single-export-module": DocumentedRule<[], "genericSingleExport">;
|
|
212
213
|
readonly "no-offset-pagination": DocumentedRule<readonly [], "noOffsetPagination">;
|
|
213
214
|
readonly "no-positional-tuple-return": DocumentedRule<readonly [], "noPositionalTupleReturn">;
|
|
@@ -274,12 +275,15 @@ declare const rules: {
|
|
|
274
275
|
readonly "require-zod-form-validation": DocumentedRule<readonly [], "missingZodValidation">;
|
|
275
276
|
readonly "store-insert-requires-on-conflict": DocumentedRule<readonly [], "storeInsertRequiresOnConflict">;
|
|
276
277
|
readonly stepdown: DocumentedRule<[], "helperAboveOnlyCaller">;
|
|
278
|
+
readonly "source-coupled-test": DocumentedRule<readonly [], "rawSourceOracle">;
|
|
277
279
|
readonly "zod-naming-convention": DocumentedRule<readonly [{
|
|
278
280
|
convention?: "prefix" | "suffix" | "either";
|
|
279
281
|
}?], "zPrefix" | "schemaSuffix" | "zodSchemaName">;
|
|
280
282
|
};
|
|
281
283
|
/** Rules registered for application-profile configs but intentionally absent from general presets. */
|
|
282
284
|
declare const applicationOnlyRules: readonly ["no-restricted-library-load", "prefer-native-random-uuid", "prefer-shadcn-primitives"];
|
|
285
|
+
/** Calibrated rules that intentionally remain warnings until consumer-corpus precision is proven. */
|
|
286
|
+
declare const advisoryRules: readonly ["no-vague-suppression-description", "source-coupled-test"];
|
|
283
287
|
declare const recommendedRules: {
|
|
284
288
|
readonly "@sarj/duplicate-test-body": "error";
|
|
285
289
|
readonly "@sarj/enforce-file-structure": "error";
|
|
@@ -297,6 +301,7 @@ declare const recommendedRules: {
|
|
|
297
301
|
readonly "@sarj/no-impossible-zod-literal-bounds": "error";
|
|
298
302
|
readonly "@sarj/no-log-only-catch": "error";
|
|
299
303
|
readonly "@sarj/no-long-comment": "error";
|
|
304
|
+
readonly "@sarj/no-vague-suppression-description": "warn";
|
|
300
305
|
readonly "@sarj/no-generic-single-export-module": "error";
|
|
301
306
|
readonly "@sarj/no-offset-pagination": "error";
|
|
302
307
|
readonly "@sarj/no-positional-tuple-return": "error";
|
|
@@ -341,6 +346,7 @@ declare const recommendedRules: {
|
|
|
341
346
|
readonly "@sarj/require-zod-form-validation": "error";
|
|
342
347
|
readonly "@sarj/store-insert-requires-on-conflict": "error";
|
|
343
348
|
readonly "@sarj/stepdown": "error";
|
|
349
|
+
readonly "@sarj/source-coupled-test": "warn";
|
|
344
350
|
readonly "@sarj/zod-naming-convention": "error";
|
|
345
351
|
};
|
|
346
352
|
declare const strictRules: {
|
|
@@ -361,6 +367,7 @@ declare const strictRules: {
|
|
|
361
367
|
readonly "@sarj/no-impossible-zod-literal-bounds": "error";
|
|
362
368
|
readonly "@sarj/no-log-only-catch": "error";
|
|
363
369
|
readonly "@sarj/no-long-comment": "error";
|
|
370
|
+
readonly "@sarj/no-vague-suppression-description": "warn";
|
|
364
371
|
readonly "@sarj/no-generic-single-export-module": "error";
|
|
365
372
|
readonly "@sarj/no-offset-pagination": "error";
|
|
366
373
|
readonly "@sarj/no-positional-tuple-return": "error";
|
|
@@ -408,6 +415,7 @@ declare const strictRules: {
|
|
|
408
415
|
readonly "@sarj/require-zod-form-validation": "error";
|
|
409
416
|
readonly "@sarj/store-insert-requires-on-conflict": "error";
|
|
410
417
|
readonly "@sarj/stepdown": "error";
|
|
418
|
+
readonly "@sarj/source-coupled-test": "warn";
|
|
411
419
|
readonly "@sarj/zod-naming-convention": "error";
|
|
412
420
|
};
|
|
413
421
|
type FlatPreset = {
|
|
@@ -418,7 +426,7 @@ type FlatPreset = {
|
|
|
418
426
|
declare const plugin: {
|
|
419
427
|
readonly meta: {
|
|
420
428
|
readonly name: "@sarj/eslint-plugin";
|
|
421
|
-
readonly version: "15.6.
|
|
429
|
+
readonly version: "15.6.9";
|
|
422
430
|
};
|
|
423
431
|
readonly rules: {
|
|
424
432
|
readonly "duplicate-test-body": DocumentedRule<readonly [], "duplicateTestBody">;
|
|
@@ -441,6 +449,7 @@ declare const plugin: {
|
|
|
441
449
|
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [], "impossibleBounds">;
|
|
442
450
|
readonly "no-log-only-catch": DocumentedRule<readonly [LoggingOptions?], "noLogOnlyCatch" | "emptyCatch">;
|
|
443
451
|
readonly "no-long-comment": DocumentedRule<readonly [], "tooLong">;
|
|
452
|
+
readonly "no-vague-suppression-description": DocumentedRule<readonly [], "vagueDescription">;
|
|
444
453
|
readonly "no-generic-single-export-module": DocumentedRule<[], "genericSingleExport">;
|
|
445
454
|
readonly "no-offset-pagination": DocumentedRule<readonly [], "noOffsetPagination">;
|
|
446
455
|
readonly "no-positional-tuple-return": DocumentedRule<readonly [], "noPositionalTupleReturn">;
|
|
@@ -507,6 +516,7 @@ declare const plugin: {
|
|
|
507
516
|
readonly "require-zod-form-validation": DocumentedRule<readonly [], "missingZodValidation">;
|
|
508
517
|
readonly "store-insert-requires-on-conflict": DocumentedRule<readonly [], "storeInsertRequiresOnConflict">;
|
|
509
518
|
readonly stepdown: DocumentedRule<[], "helperAboveOnlyCaller">;
|
|
519
|
+
readonly "source-coupled-test": DocumentedRule<readonly [], "rawSourceOracle">;
|
|
510
520
|
readonly "zod-naming-convention": DocumentedRule<readonly [{
|
|
511
521
|
convention?: "prefix" | "suffix" | "either";
|
|
512
522
|
}?], "zPrefix" | "schemaSuffix" | "zodSchemaName">;
|
|
@@ -518,4 +528,4 @@ declare const plugin: {
|
|
|
518
528
|
};
|
|
519
529
|
};
|
|
520
530
|
|
|
521
|
-
export { type RetiredRule, applicationOnlyRules, plugin as default, publicDocumentation, recommendedRules, renamedRules, retiredRules, rules, strictRules };
|
|
531
|
+
export { type RetiredRule, advisoryRules, applicationOnlyRules, plugin as default, publicDocumentation, recommendedRules, renamedRules, retiredRules, rules, strictRules };
|
package/dist/index.d.ts
CHANGED
|
@@ -208,6 +208,7 @@ declare const rules: {
|
|
|
208
208
|
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [], "impossibleBounds">;
|
|
209
209
|
readonly "no-log-only-catch": DocumentedRule<readonly [LoggingOptions?], "noLogOnlyCatch" | "emptyCatch">;
|
|
210
210
|
readonly "no-long-comment": DocumentedRule<readonly [], "tooLong">;
|
|
211
|
+
readonly "no-vague-suppression-description": DocumentedRule<readonly [], "vagueDescription">;
|
|
211
212
|
readonly "no-generic-single-export-module": DocumentedRule<[], "genericSingleExport">;
|
|
212
213
|
readonly "no-offset-pagination": DocumentedRule<readonly [], "noOffsetPagination">;
|
|
213
214
|
readonly "no-positional-tuple-return": DocumentedRule<readonly [], "noPositionalTupleReturn">;
|
|
@@ -274,12 +275,15 @@ declare const rules: {
|
|
|
274
275
|
readonly "require-zod-form-validation": DocumentedRule<readonly [], "missingZodValidation">;
|
|
275
276
|
readonly "store-insert-requires-on-conflict": DocumentedRule<readonly [], "storeInsertRequiresOnConflict">;
|
|
276
277
|
readonly stepdown: DocumentedRule<[], "helperAboveOnlyCaller">;
|
|
278
|
+
readonly "source-coupled-test": DocumentedRule<readonly [], "rawSourceOracle">;
|
|
277
279
|
readonly "zod-naming-convention": DocumentedRule<readonly [{
|
|
278
280
|
convention?: "prefix" | "suffix" | "either";
|
|
279
281
|
}?], "zPrefix" | "schemaSuffix" | "zodSchemaName">;
|
|
280
282
|
};
|
|
281
283
|
/** Rules registered for application-profile configs but intentionally absent from general presets. */
|
|
282
284
|
declare const applicationOnlyRules: readonly ["no-restricted-library-load", "prefer-native-random-uuid", "prefer-shadcn-primitives"];
|
|
285
|
+
/** Calibrated rules that intentionally remain warnings until consumer-corpus precision is proven. */
|
|
286
|
+
declare const advisoryRules: readonly ["no-vague-suppression-description", "source-coupled-test"];
|
|
283
287
|
declare const recommendedRules: {
|
|
284
288
|
readonly "@sarj/duplicate-test-body": "error";
|
|
285
289
|
readonly "@sarj/enforce-file-structure": "error";
|
|
@@ -297,6 +301,7 @@ declare const recommendedRules: {
|
|
|
297
301
|
readonly "@sarj/no-impossible-zod-literal-bounds": "error";
|
|
298
302
|
readonly "@sarj/no-log-only-catch": "error";
|
|
299
303
|
readonly "@sarj/no-long-comment": "error";
|
|
304
|
+
readonly "@sarj/no-vague-suppression-description": "warn";
|
|
300
305
|
readonly "@sarj/no-generic-single-export-module": "error";
|
|
301
306
|
readonly "@sarj/no-offset-pagination": "error";
|
|
302
307
|
readonly "@sarj/no-positional-tuple-return": "error";
|
|
@@ -341,6 +346,7 @@ declare const recommendedRules: {
|
|
|
341
346
|
readonly "@sarj/require-zod-form-validation": "error";
|
|
342
347
|
readonly "@sarj/store-insert-requires-on-conflict": "error";
|
|
343
348
|
readonly "@sarj/stepdown": "error";
|
|
349
|
+
readonly "@sarj/source-coupled-test": "warn";
|
|
344
350
|
readonly "@sarj/zod-naming-convention": "error";
|
|
345
351
|
};
|
|
346
352
|
declare const strictRules: {
|
|
@@ -361,6 +367,7 @@ declare const strictRules: {
|
|
|
361
367
|
readonly "@sarj/no-impossible-zod-literal-bounds": "error";
|
|
362
368
|
readonly "@sarj/no-log-only-catch": "error";
|
|
363
369
|
readonly "@sarj/no-long-comment": "error";
|
|
370
|
+
readonly "@sarj/no-vague-suppression-description": "warn";
|
|
364
371
|
readonly "@sarj/no-generic-single-export-module": "error";
|
|
365
372
|
readonly "@sarj/no-offset-pagination": "error";
|
|
366
373
|
readonly "@sarj/no-positional-tuple-return": "error";
|
|
@@ -408,6 +415,7 @@ declare const strictRules: {
|
|
|
408
415
|
readonly "@sarj/require-zod-form-validation": "error";
|
|
409
416
|
readonly "@sarj/store-insert-requires-on-conflict": "error";
|
|
410
417
|
readonly "@sarj/stepdown": "error";
|
|
418
|
+
readonly "@sarj/source-coupled-test": "warn";
|
|
411
419
|
readonly "@sarj/zod-naming-convention": "error";
|
|
412
420
|
};
|
|
413
421
|
type FlatPreset = {
|
|
@@ -418,7 +426,7 @@ type FlatPreset = {
|
|
|
418
426
|
declare const plugin: {
|
|
419
427
|
readonly meta: {
|
|
420
428
|
readonly name: "@sarj/eslint-plugin";
|
|
421
|
-
readonly version: "15.6.
|
|
429
|
+
readonly version: "15.6.9";
|
|
422
430
|
};
|
|
423
431
|
readonly rules: {
|
|
424
432
|
readonly "duplicate-test-body": DocumentedRule<readonly [], "duplicateTestBody">;
|
|
@@ -441,6 +449,7 @@ declare const plugin: {
|
|
|
441
449
|
readonly "no-impossible-zod-literal-bounds": DocumentedRule<readonly [], "impossibleBounds">;
|
|
442
450
|
readonly "no-log-only-catch": DocumentedRule<readonly [LoggingOptions?], "noLogOnlyCatch" | "emptyCatch">;
|
|
443
451
|
readonly "no-long-comment": DocumentedRule<readonly [], "tooLong">;
|
|
452
|
+
readonly "no-vague-suppression-description": DocumentedRule<readonly [], "vagueDescription">;
|
|
444
453
|
readonly "no-generic-single-export-module": DocumentedRule<[], "genericSingleExport">;
|
|
445
454
|
readonly "no-offset-pagination": DocumentedRule<readonly [], "noOffsetPagination">;
|
|
446
455
|
readonly "no-positional-tuple-return": DocumentedRule<readonly [], "noPositionalTupleReturn">;
|
|
@@ -507,6 +516,7 @@ declare const plugin: {
|
|
|
507
516
|
readonly "require-zod-form-validation": DocumentedRule<readonly [], "missingZodValidation">;
|
|
508
517
|
readonly "store-insert-requires-on-conflict": DocumentedRule<readonly [], "storeInsertRequiresOnConflict">;
|
|
509
518
|
readonly stepdown: DocumentedRule<[], "helperAboveOnlyCaller">;
|
|
519
|
+
readonly "source-coupled-test": DocumentedRule<readonly [], "rawSourceOracle">;
|
|
510
520
|
readonly "zod-naming-convention": DocumentedRule<readonly [{
|
|
511
521
|
convention?: "prefix" | "suffix" | "either";
|
|
512
522
|
}?], "zPrefix" | "schemaSuffix" | "zodSchemaName">;
|
|
@@ -518,4 +528,4 @@ declare const plugin: {
|
|
|
518
528
|
};
|
|
519
529
|
};
|
|
520
530
|
|
|
521
|
-
export { type RetiredRule, applicationOnlyRules, plugin as default, publicDocumentation, recommendedRules, renamedRules, retiredRules, rules, strictRules };
|
|
531
|
+
export { type RetiredRule, advisoryRules, applicationOnlyRules, plugin as default, publicDocumentation, recommendedRules, renamedRules, retiredRules, rules, strictRules };
|
package/dist/index.js
CHANGED
|
@@ -4253,6 +4253,87 @@ var no_long_comment_default = createRule({
|
|
|
4253
4253
|
}
|
|
4254
4254
|
});
|
|
4255
4255
|
|
|
4256
|
+
// src/rules/no-vague-suppression-description.ts
|
|
4257
|
+
var DIRECTIVE_RE3 = /(?:eslint-(?:disable|disable-next-line|disable-line)|@ts-(?:expect-error|ignore))\b/iu;
|
|
4258
|
+
var DESCRIPTION_RE = /(?::|--)\s*(.+?)\s*$/u;
|
|
4259
|
+
var VAGUE_RE = /^(?:needed|required|intentional(?:ly)?|ignore(?:d)?|false positive|type error|typescript|to satisfy (?:the )?(?:linter|typescript|type checker))\.?$/iu;
|
|
4260
|
+
var noVagueSuppressionDescriptionDocumentation = {
|
|
4261
|
+
summary: "Require suppression descriptions to name the concrete mismatch or invariant instead of a generic non-reason.",
|
|
4262
|
+
rationale: "Generic phrases satisfy require-description mechanically while leaving reviewers unable to audit the risk or remove stale debt.",
|
|
4263
|
+
remediation: "Name the exact type/runtime mismatch, external contract, or safety invariant that makes this suppression acceptable.",
|
|
4264
|
+
category: "maintainability",
|
|
4265
|
+
limitations: [
|
|
4266
|
+
"Only ESLint disable comments and TypeScript expect-error/ignore directives are checked.",
|
|
4267
|
+
"The rule uses a small anchored vocabulary and does not score prose quality generally.",
|
|
4268
|
+
"Generated files and descriptions containing any concrete context are excluded."
|
|
4269
|
+
],
|
|
4270
|
+
examples: [
|
|
4271
|
+
{
|
|
4272
|
+
id: "concrete-runtime-mismatch",
|
|
4273
|
+
title: "Explain the concrete runtime contract",
|
|
4274
|
+
outcome: "no-match",
|
|
4275
|
+
files: [
|
|
4276
|
+
{
|
|
4277
|
+
path: "src/adapter.ts",
|
|
4278
|
+
source: "// @ts-expect-error -- vendor types omit the runtime requestId field\nreturn response.requestId;"
|
|
4279
|
+
}
|
|
4280
|
+
],
|
|
4281
|
+
focusPath: "src/adapter.ts",
|
|
4282
|
+
expectedCount: 0,
|
|
4283
|
+
public: true
|
|
4284
|
+
},
|
|
4285
|
+
{
|
|
4286
|
+
id: "generic-suppression-reason",
|
|
4287
|
+
title: "Reject a suppression with no auditable reason",
|
|
4288
|
+
outcome: "match",
|
|
4289
|
+
files: [
|
|
4290
|
+
{
|
|
4291
|
+
path: "src/adapter.ts",
|
|
4292
|
+
source: "// @ts-expect-error -- false positive\nreturn response.requestId;"
|
|
4293
|
+
}
|
|
4294
|
+
],
|
|
4295
|
+
focusPath: "src/adapter.ts",
|
|
4296
|
+
expectedCount: 1,
|
|
4297
|
+
public: true
|
|
4298
|
+
}
|
|
4299
|
+
]
|
|
4300
|
+
};
|
|
4301
|
+
var no_vague_suppression_description_default = createRule({
|
|
4302
|
+
name: "no-vague-suppression-description",
|
|
4303
|
+
documentation: noVagueSuppressionDescriptionDocumentation,
|
|
4304
|
+
meta: {
|
|
4305
|
+
type: "suggestion",
|
|
4306
|
+
docs: {
|
|
4307
|
+
description: "Require suppression descriptions to name the concrete mismatch or invariant instead of a generic non-reason."
|
|
4308
|
+
},
|
|
4309
|
+
schema: [],
|
|
4310
|
+
messages: {
|
|
4311
|
+
vagueDescription: "Suppression description `{{description}}` does not explain why the suppressed diagnostic is safe here. Name the concrete type/runtime mismatch, external contract, or invariant."
|
|
4312
|
+
}
|
|
4313
|
+
},
|
|
4314
|
+
defaultOptions: [],
|
|
4315
|
+
create(context) {
|
|
4316
|
+
if (isGeneratedFile(context.filename, context.sourceCode.text)) {
|
|
4317
|
+
return {};
|
|
4318
|
+
}
|
|
4319
|
+
return {
|
|
4320
|
+
Program() {
|
|
4321
|
+
for (const comment of context.sourceCode.getAllComments()) {
|
|
4322
|
+
const text = comment.value.trim();
|
|
4323
|
+
if (!DIRECTIVE_RE3.test(text)) continue;
|
|
4324
|
+
const description = DESCRIPTION_RE.exec(text)?.[1]?.trim();
|
|
4325
|
+
if (description === void 0 || !VAGUE_RE.test(description)) continue;
|
|
4326
|
+
context.report({
|
|
4327
|
+
loc: comment.loc,
|
|
4328
|
+
messageId: "vagueDescription",
|
|
4329
|
+
data: { description }
|
|
4330
|
+
});
|
|
4331
|
+
}
|
|
4332
|
+
}
|
|
4333
|
+
};
|
|
4334
|
+
}
|
|
4335
|
+
});
|
|
4336
|
+
|
|
4256
4337
|
// src/rules/no-generic-single-export-module.ts
|
|
4257
4338
|
import { AST_NODE_TYPES as AST_NODE_TYPES16, ASTUtils as ASTUtils4 } from "@typescript-eslint/utils";
|
|
4258
4339
|
var noGenericSingleExportModuleDocumentation = {
|
|
@@ -5392,7 +5473,7 @@ var no_repeated_string_literal_default = createRule({
|
|
|
5392
5473
|
import { AST_NODE_TYPES as AST_NODE_TYPES21 } from "@typescript-eslint/utils";
|
|
5393
5474
|
var MAX_WORDS = 8;
|
|
5394
5475
|
var MIN_CONTENT_TOKENS = 2;
|
|
5395
|
-
var
|
|
5476
|
+
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;
|
|
5396
5477
|
var CODEY_RE = /^[\w.$[\]'"]+\s*[:=]\s*\S|^[\w.$]+\s*\(|^(?:return|throw|await|import|export|const|let|var)\b.*[=()[\]{}]/;
|
|
5397
5478
|
var BANNERISH_RE = /[=\-─-╿*#~_.]{3,}|^[A-Z0-9 _:-]+$/;
|
|
5398
5479
|
var MODALITY_RE = /\b(?:can|could|should|shall|may|might|must|will|would|cannot)\b/i;
|
|
@@ -5491,7 +5572,7 @@ var no_restated_comment_default = createRule({
|
|
|
5491
5572
|
}
|
|
5492
5573
|
const body2 = comment.value.replace(/^\/*/, "").trim();
|
|
5493
5574
|
if (body2.length === 0 || body2.endsWith("?")) continue;
|
|
5494
|
-
if (
|
|
5575
|
+
if (DIRECTIVE_RE4.test(body2) || CODEY_RE.test(body2) || BANNERISH_RE.test(body2)) continue;
|
|
5495
5576
|
if (NON_ASCII_LETTER_RE.test(body2) || isProtected(body2)) continue;
|
|
5496
5577
|
if (MODALITY_RE.test(body2) || LEAD_IN_RE.test(body2) || EMPHASIS_RE.test(body2)) continue;
|
|
5497
5578
|
if (NEGATION_WORD_RE.test(body2)) continue;
|
|
@@ -5539,7 +5620,7 @@ var MODELLED_TAGS = /* @__PURE__ */ new Set([
|
|
|
5539
5620
|
]);
|
|
5540
5621
|
var PARAM_TAGS = /* @__PURE__ */ new Set(["arg", "argument", "param"]);
|
|
5541
5622
|
var RETURN_TAGS = /* @__PURE__ */ new Set(["return", "returns"]);
|
|
5542
|
-
var
|
|
5623
|
+
var DIRECTIVE_RE5 = /^\s*(?:eslint\b|eslint-|@ts-|prettier|biome-|c8\b|v8\b|istanbul\b|@vite|webpack|@jsx|@jest-environment|@vitest-environment|#__)/i;
|
|
5543
5624
|
var STOPWORDS2 = new Set(
|
|
5544
5625
|
`the a an of to for in on with and or as at by is are was be been being
|
|
5545
5626
|
this that it its if whether when where which what will would can could should
|
|
@@ -5655,7 +5736,7 @@ var no_restated_jsdoc_default = createRule({
|
|
|
5655
5736
|
description,
|
|
5656
5737
|
...tags.filter((tag) => tag.name === "description").map((tag) => tag.text)
|
|
5657
5738
|
].filter((text) => text.length > 0).join("\n");
|
|
5658
|
-
if (
|
|
5739
|
+
if (DIRECTIVE_RE5.test(describedText)) continue;
|
|
5659
5740
|
const tagNames = new Set(tags.map((tag) => tag.name));
|
|
5660
5741
|
if ([...tagNames].some((name) => !MODELLED_TAGS.has(name))) continue;
|
|
5661
5742
|
if (isProtected(describedText)) continue;
|
|
@@ -7617,10 +7698,10 @@ var STOPWORDS3 = /* @__PURE__ */ new Set([
|
|
|
7617
7698
|
"we",
|
|
7618
7699
|
"with"
|
|
7619
7700
|
]);
|
|
7620
|
-
var
|
|
7701
|
+
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;
|
|
7621
7702
|
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;
|
|
7622
7703
|
function narratesValue(body2, code) {
|
|
7623
|
-
if (body2.length === 0 ||
|
|
7704
|
+
if (body2.length === 0 || DIRECTIVE_RE6.test(body2) || hasExternalReference(body2)) return false;
|
|
7624
7705
|
const codeNumbers = numbersIn(code);
|
|
7625
7706
|
if (codeNumbers.size === 0) return false;
|
|
7626
7707
|
const words2 = (body2.match(WORD_RE3) ?? []).map((word) => word.toLowerCase());
|
|
@@ -14762,9 +14843,291 @@ var stepdown_default = createRule({
|
|
|
14762
14843
|
}
|
|
14763
14844
|
});
|
|
14764
14845
|
|
|
14846
|
+
// src/rules/source-coupled-test.ts
|
|
14847
|
+
import { AST_NODE_TYPES as AST_NODE_TYPES56 } from "@typescript-eslint/utils";
|
|
14848
|
+
var SOURCE_SUFFIX_RE = /\.(?:bash|hcl|sh|tf|tfvars|ya?ml|py|[cm]?[jt]s)$/iu;
|
|
14849
|
+
var FS_MODULES = /* @__PURE__ */ new Set(["fs", "node:fs", "fs/promises", "node:fs/promises"]);
|
|
14850
|
+
var FS_READERS = /* @__PURE__ */ new Set(["readFile", "readFileSync"]);
|
|
14851
|
+
var TEXT_TRANSFORMS = /* @__PURE__ */ new Set([
|
|
14852
|
+
"slice",
|
|
14853
|
+
"substring",
|
|
14854
|
+
"substr",
|
|
14855
|
+
"toLowerCase",
|
|
14856
|
+
"toString",
|
|
14857
|
+
"toUpperCase",
|
|
14858
|
+
"trim",
|
|
14859
|
+
"trimEnd",
|
|
14860
|
+
"trimStart",
|
|
14861
|
+
"replace",
|
|
14862
|
+
"replaceAll"
|
|
14863
|
+
]);
|
|
14864
|
+
var TEXT_PREDICATES = /* @__PURE__ */ new Set(["endsWith", "includes", "indexOf", "lastIndexOf", "match", "matchAll", "search", "startsWith"]);
|
|
14865
|
+
var REGEXP_PREDICATES = /* @__PURE__ */ new Set(["exec", "test"]);
|
|
14866
|
+
var EXPECT_MATCHERS = /* @__PURE__ */ new Set([
|
|
14867
|
+
"toBe",
|
|
14868
|
+
"toBeFalsy",
|
|
14869
|
+
"toBeGreaterThan",
|
|
14870
|
+
"toBeGreaterThanOrEqual",
|
|
14871
|
+
"toBeLessThan",
|
|
14872
|
+
"toBeLessThanOrEqual",
|
|
14873
|
+
"toBeNull",
|
|
14874
|
+
"toBeTruthy",
|
|
14875
|
+
"toContain",
|
|
14876
|
+
"toEqual",
|
|
14877
|
+
"toHaveLength",
|
|
14878
|
+
"toMatch",
|
|
14879
|
+
"toMatchSnapshot",
|
|
14880
|
+
"toStrictEqual"
|
|
14881
|
+
]);
|
|
14882
|
+
var EXPECT_MODIFIERS = /* @__PURE__ */ new Set(["not", "rejects", "resolves"]);
|
|
14883
|
+
var ASSERT_MATCHERS = /* @__PURE__ */ new Set(["deepEqual", "doesNotMatch", "equal", "match", "notDeepEqual", "notEqual", "notStrictEqual", "ok", "strictEqual"]);
|
|
14884
|
+
var sourceCoupledTestDocumentation = {
|
|
14885
|
+
summary: "Disallow raw repository source text as a test oracle; parse or execute the artifact instead.",
|
|
14886
|
+
rationale: "Substring and regex checks can pass on comments or unreachable configuration and fail after behavior-preserving formatting changes.",
|
|
14887
|
+
remediation: "Parse the artifact, execute its validator, or assert on Terraform plan JSON or another runtime contract.",
|
|
14888
|
+
category: "testing",
|
|
14889
|
+
limitations: [
|
|
14890
|
+
"The rule follows lexical aliases, source-path collections, awaited reads, and common text operations; interprocedural flows remain unreported.",
|
|
14891
|
+
"When raw representation is genuinely the contract (for example a golden or compatibility sentinel), use an exact line suppression with the reason."
|
|
14892
|
+
],
|
|
14893
|
+
examples: [
|
|
14894
|
+
{
|
|
14895
|
+
id: "parsed-policy-contract",
|
|
14896
|
+
title: "Assert on parsed policy behavior",
|
|
14897
|
+
outcome: "no-match",
|
|
14898
|
+
files: [{ path: "src/policy.test.ts", source: "import { readFileSync } from 'node:fs'; test('policy', () => { const policy = JSON.parse(readFileSync('policy.json', 'utf8')); expect(validate(policy)).toEqual([]); });" }],
|
|
14899
|
+
focusPath: "src/policy.test.ts",
|
|
14900
|
+
expectedCount: 0,
|
|
14901
|
+
public: true
|
|
14902
|
+
},
|
|
14903
|
+
{
|
|
14904
|
+
id: "terraform-substring-contract",
|
|
14905
|
+
title: "Do not prove Terraform behavior with a regex",
|
|
14906
|
+
outcome: "match",
|
|
14907
|
+
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/); });" }],
|
|
14908
|
+
focusPath: "src/policy.test.ts",
|
|
14909
|
+
expectedCount: 1,
|
|
14910
|
+
public: true
|
|
14911
|
+
}
|
|
14912
|
+
]
|
|
14913
|
+
};
|
|
14914
|
+
function staticMemberName5(node) {
|
|
14915
|
+
if (!node.computed && node.property.type === AST_NODE_TYPES56.Identifier) return node.property.name;
|
|
14916
|
+
if (node.computed && node.property.type === AST_NODE_TYPES56.Literal && typeof node.property.value === "string") return node.property.value;
|
|
14917
|
+
return null;
|
|
14918
|
+
}
|
|
14919
|
+
function unwrap5(node) {
|
|
14920
|
+
if (node.type === AST_NODE_TYPES56.AwaitExpression) return unwrap5(node.argument);
|
|
14921
|
+
if (node.type === AST_NODE_TYPES56.ChainExpression) return unwrap5(node.expression);
|
|
14922
|
+
if (node.type === AST_NODE_TYPES56.TSAsExpression || node.type === AST_NODE_TYPES56.TSNonNullExpression || node.type === AST_NODE_TYPES56.TSTypeAssertion) return unwrap5(node.expression);
|
|
14923
|
+
return node;
|
|
14924
|
+
}
|
|
14925
|
+
function stringValue(node) {
|
|
14926
|
+
const current = unwrap5(node);
|
|
14927
|
+
if (current.type === AST_NODE_TYPES56.Literal && typeof current.value === "string") return current.value;
|
|
14928
|
+
if (current.type === AST_NODE_TYPES56.TemplateLiteral && current.expressions.length === 0) return current.quasis[0]?.value.cooked ?? null;
|
|
14929
|
+
return null;
|
|
14930
|
+
}
|
|
14931
|
+
function importSource(node) {
|
|
14932
|
+
return typeof node.source.value === "string" ? node.source.value : null;
|
|
14933
|
+
}
|
|
14934
|
+
function requireSource(node) {
|
|
14935
|
+
const current = unwrap5(node);
|
|
14936
|
+
if (current.type !== AST_NODE_TYPES56.CallExpression || current.callee.type !== AST_NODE_TYPES56.Identifier || current.callee.name !== "require" || current.arguments.length !== 1 || current.arguments[0]?.type === AST_NODE_TYPES56.SpreadElement) return null;
|
|
14937
|
+
return stringValue(current.arguments[0]);
|
|
14938
|
+
}
|
|
14939
|
+
function newScope() {
|
|
14940
|
+
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() };
|
|
14941
|
+
}
|
|
14942
|
+
var source_coupled_test_default = createRule({
|
|
14943
|
+
name: "source-coupled-test",
|
|
14944
|
+
documentation: sourceCoupledTestDocumentation,
|
|
14945
|
+
meta: {
|
|
14946
|
+
type: "suggestion",
|
|
14947
|
+
docs: { description: sourceCoupledTestDocumentation.summary },
|
|
14948
|
+
schema: [],
|
|
14949
|
+
messages: { rawSourceOracle: "Raw repository source text is the oracle. Parse or execute the artifact so comments, formatting, and unreachable blocks cannot satisfy the contract." }
|
|
14950
|
+
},
|
|
14951
|
+
defaultOptions: [],
|
|
14952
|
+
create(context) {
|
|
14953
|
+
if (!isTestFile(context.filename) || isGeneratedFile(context.filename, context.sourceCode.text)) return {};
|
|
14954
|
+
const scopes = [newScope()];
|
|
14955
|
+
const reportedOrigins = /* @__PURE__ */ new Set();
|
|
14956
|
+
const currentScope = () => scopes.at(-1) ?? scopes[0];
|
|
14957
|
+
const visible = (kind, name) => {
|
|
14958
|
+
for (let index = scopes.length - 1; index >= 0; index--) {
|
|
14959
|
+
const scope = scopes[index];
|
|
14960
|
+
if (scope.declared.has(name)) return scope[kind].has(name);
|
|
14961
|
+
}
|
|
14962
|
+
return false;
|
|
14963
|
+
};
|
|
14964
|
+
const visibleRawOrigins = (name) => {
|
|
14965
|
+
for (let index = scopes.length - 1; index >= 0; index--) {
|
|
14966
|
+
const scope = scopes[index];
|
|
14967
|
+
if (scope.declared.has(name)) return scope.rawOrigins.get(name) ?? /* @__PURE__ */ new Set();
|
|
14968
|
+
}
|
|
14969
|
+
return /* @__PURE__ */ new Set();
|
|
14970
|
+
};
|
|
14971
|
+
const sourcePath = (node) => {
|
|
14972
|
+
const current = unwrap5(node);
|
|
14973
|
+
const value = stringValue(current);
|
|
14974
|
+
if (value !== null) return SOURCE_SUFFIX_RE.test(value);
|
|
14975
|
+
if (current.type === AST_NODE_TYPES56.Identifier) return visible("paths", current.name);
|
|
14976
|
+
if (current.type === AST_NODE_TYPES56.BinaryExpression && current.operator === "+") {
|
|
14977
|
+
return sourcePath(current.left) || sourcePath(current.right);
|
|
14978
|
+
}
|
|
14979
|
+
if (current.type === AST_NODE_TYPES56.TemplateLiteral) return current.expressions.some(sourcePath);
|
|
14980
|
+
if (current.type === AST_NODE_TYPES56.CallExpression || current.type === AST_NODE_TYPES56.NewExpression) {
|
|
14981
|
+
return current.arguments.some((argument) => argument.type !== AST_NODE_TYPES56.SpreadElement && sourcePath(argument));
|
|
14982
|
+
}
|
|
14983
|
+
if (current.type === AST_NODE_TYPES56.MemberExpression) return sourcePath(current.object);
|
|
14984
|
+
return false;
|
|
14985
|
+
};
|
|
14986
|
+
const rawRead = (node) => {
|
|
14987
|
+
const current = unwrap5(node);
|
|
14988
|
+
if (current.type !== AST_NODE_TYPES56.CallExpression || current.arguments.length === 0) return false;
|
|
14989
|
+
const callee = unwrap5(current.callee);
|
|
14990
|
+
if (callee.type === AST_NODE_TYPES56.Identifier) {
|
|
14991
|
+
return visible("fsReaders", callee.name) && sourcePath(current.arguments[0]);
|
|
14992
|
+
}
|
|
14993
|
+
if (callee.type !== AST_NODE_TYPES56.MemberExpression) return false;
|
|
14994
|
+
const name = staticMemberName5(callee);
|
|
14995
|
+
const object = unwrap5(callee.object);
|
|
14996
|
+
return name !== null && FS_READERS.has(name) && object.type === AST_NODE_TYPES56.Identifier && visible("fsObjects", object.name) && sourcePath(current.arguments[0]);
|
|
14997
|
+
};
|
|
14998
|
+
const rawOrigins = (node) => {
|
|
14999
|
+
const current = unwrap5(node);
|
|
15000
|
+
if (current.type === AST_NODE_TYPES56.Identifier) return visibleRawOrigins(current.name);
|
|
15001
|
+
if (rawRead(current)) return /* @__PURE__ */ new Set([`${current.range[0]}:${current.range[1]}`]);
|
|
15002
|
+
if (current.type === AST_NODE_TYPES56.BinaryExpression && current.operator === "+") return /* @__PURE__ */ new Set([...rawOrigins(current.left), ...rawOrigins(current.right)]);
|
|
15003
|
+
if (current.type !== AST_NODE_TYPES56.CallExpression) return /* @__PURE__ */ new Set();
|
|
15004
|
+
const callee = unwrap5(current.callee);
|
|
15005
|
+
if (callee.type !== AST_NODE_TYPES56.MemberExpression) return /* @__PURE__ */ new Set();
|
|
15006
|
+
const name = staticMemberName5(callee);
|
|
15007
|
+
return name !== null && TEXT_TRANSFORMS.has(name) ? rawOrigins(callee.object) : /* @__PURE__ */ new Set();
|
|
15008
|
+
};
|
|
15009
|
+
const evidenceOrigins = (node) => {
|
|
15010
|
+
const current = unwrap5(node);
|
|
15011
|
+
const direct = rawOrigins(current);
|
|
15012
|
+
if (direct.size > 0) return direct;
|
|
15013
|
+
if (current.type === AST_NODE_TYPES56.BinaryExpression || current.type === AST_NODE_TYPES56.LogicalExpression) return /* @__PURE__ */ new Set([...evidenceOrigins(current.left), ...evidenceOrigins(current.right)]);
|
|
15014
|
+
if (current.type === AST_NODE_TYPES56.UnaryExpression) return evidenceOrigins(current.argument);
|
|
15015
|
+
if (current.type !== AST_NODE_TYPES56.CallExpression) return /* @__PURE__ */ new Set();
|
|
15016
|
+
const callee = unwrap5(current.callee);
|
|
15017
|
+
if (callee.type !== AST_NODE_TYPES56.MemberExpression) return /* @__PURE__ */ new Set();
|
|
15018
|
+
const name = staticMemberName5(callee);
|
|
15019
|
+
if (name !== null && TEXT_PREDICATES.has(name)) return rawOrigins(callee.object);
|
|
15020
|
+
if (name !== null && REGEXP_PREDICATES.has(name)) return new Set(current.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES56.SpreadElement ? [] : [...rawOrigins(argument)]));
|
|
15021
|
+
return /* @__PURE__ */ new Set();
|
|
15022
|
+
};
|
|
15023
|
+
const rawAssertionOrigins = (node) => {
|
|
15024
|
+
const callee = unwrap5(node.callee);
|
|
15025
|
+
if (callee.type === AST_NODE_TYPES56.Identifier && callee.name === "assert") {
|
|
15026
|
+
return new Set(node.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES56.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
15027
|
+
}
|
|
15028
|
+
if (callee.type !== AST_NODE_TYPES56.MemberExpression) return /* @__PURE__ */ new Set();
|
|
15029
|
+
const matcher = staticMemberName5(callee);
|
|
15030
|
+
if (matcher === null) return /* @__PURE__ */ new Set();
|
|
15031
|
+
let receiver = unwrap5(callee.object);
|
|
15032
|
+
while (receiver.type === AST_NODE_TYPES56.MemberExpression && EXPECT_MODIFIERS.has(staticMemberName5(receiver) ?? "")) receiver = unwrap5(receiver.object);
|
|
15033
|
+
if (receiver.type === AST_NODE_TYPES56.CallExpression && receiver.callee.type === AST_NODE_TYPES56.Identifier && receiver.callee.name === "expect") {
|
|
15034
|
+
if (!EXPECT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
|
|
15035
|
+
return new Set([...receiver.arguments, ...node.arguments].flatMap((argument) => argument.type === AST_NODE_TYPES56.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
15036
|
+
}
|
|
15037
|
+
if (receiver.type !== AST_NODE_TYPES56.Identifier || receiver.name !== "assert" || !ASSERT_MATCHERS.has(matcher)) return /* @__PURE__ */ new Set();
|
|
15038
|
+
return new Set(node.arguments.flatMap((argument) => argument.type === AST_NODE_TYPES56.SpreadElement ? [] : [...evidenceOrigins(argument)]));
|
|
15039
|
+
};
|
|
15040
|
+
const declare = (name, state) => {
|
|
15041
|
+
const scope = currentScope();
|
|
15042
|
+
scope.declared.add(name);
|
|
15043
|
+
scope.collections.delete(name);
|
|
15044
|
+
scope.fsObjects.delete(name);
|
|
15045
|
+
scope.fsReaders.delete(name);
|
|
15046
|
+
scope.paths.delete(name);
|
|
15047
|
+
scope.rawOrigins.delete(name);
|
|
15048
|
+
if (state.collection === true) scope.collections.add(name);
|
|
15049
|
+
if (state.fsObject === true) scope.fsObjects.add(name);
|
|
15050
|
+
if (state.fsReader === true) scope.fsReaders.add(name);
|
|
15051
|
+
if (state.path === true) scope.paths.add(name);
|
|
15052
|
+
if (state.rawOrigins !== void 0 && state.rawOrigins.size > 0) {
|
|
15053
|
+
scope.rawOrigins.set(name, state.rawOrigins);
|
|
15054
|
+
}
|
|
15055
|
+
};
|
|
15056
|
+
const sourceCollection = (node) => {
|
|
15057
|
+
const current = unwrap5(node);
|
|
15058
|
+
return current.type === AST_NODE_TYPES56.ArrayExpression && current.elements.length > 0 && current.elements.every((element) => element !== null && element.type !== AST_NODE_TYPES56.SpreadElement && sourcePath(element));
|
|
15059
|
+
};
|
|
15060
|
+
const declaredNames2 = (node) => {
|
|
15061
|
+
const current = unwrap5(node);
|
|
15062
|
+
if (current.type === AST_NODE_TYPES56.Identifier) return [current.name];
|
|
15063
|
+
if (current.type === AST_NODE_TYPES56.AssignmentPattern) return declaredNames2(current.left);
|
|
15064
|
+
if (current.type === AST_NODE_TYPES56.RestElement) return declaredNames2(current.argument);
|
|
15065
|
+
if (current.type === AST_NODE_TYPES56.ArrayPattern) return current.elements.flatMap((element) => element === null ? [] : declaredNames2(element));
|
|
15066
|
+
if (current.type === AST_NODE_TYPES56.ObjectPattern) return current.properties.flatMap((property) => property.type === AST_NODE_TYPES56.RestElement ? declaredNames2(property.argument) : declaredNames2(property.value));
|
|
15067
|
+
return [];
|
|
15068
|
+
};
|
|
15069
|
+
const enterFunction = (node) => {
|
|
15070
|
+
scopes.push(newScope());
|
|
15071
|
+
for (const parameter of node.params) for (const name of declaredNames2(parameter)) declare(name, {});
|
|
15072
|
+
};
|
|
15073
|
+
const exitFunction = () => {
|
|
15074
|
+
scopes.pop();
|
|
15075
|
+
};
|
|
15076
|
+
return {
|
|
15077
|
+
ImportDeclaration(node) {
|
|
15078
|
+
const source = importSource(node);
|
|
15079
|
+
if (source === null || !FS_MODULES.has(source)) return;
|
|
15080
|
+
for (const specifier of node.specifiers) {
|
|
15081
|
+
if (specifier.type === AST_NODE_TYPES56.ImportSpecifier) {
|
|
15082
|
+
const imported = specifier.imported.type === AST_NODE_TYPES56.Identifier ? specifier.imported.name : String(specifier.imported.value);
|
|
15083
|
+
if (FS_READERS.has(imported)) declare(specifier.local.name, { fsReader: true });
|
|
15084
|
+
} else {
|
|
15085
|
+
declare(specifier.local.name, { fsObject: true });
|
|
15086
|
+
}
|
|
15087
|
+
}
|
|
15088
|
+
},
|
|
15089
|
+
":function": enterFunction,
|
|
15090
|
+
":function:exit": exitFunction,
|
|
15091
|
+
VariableDeclarator(node) {
|
|
15092
|
+
if (node.init === null) return;
|
|
15093
|
+
const required = requireSource(node.init);
|
|
15094
|
+
if (required !== null && FS_MODULES.has(required) && node.id.type === AST_NODE_TYPES56.Identifier) {
|
|
15095
|
+
declare(node.id.name, { fsObject: true });
|
|
15096
|
+
return;
|
|
15097
|
+
}
|
|
15098
|
+
if (node.id.type === AST_NODE_TYPES56.ObjectPattern && required !== null && FS_MODULES.has(required)) {
|
|
15099
|
+
for (const property of node.id.properties) {
|
|
15100
|
+
if (property.type !== AST_NODE_TYPES56.Property || property.value.type !== AST_NODE_TYPES56.Identifier) continue;
|
|
15101
|
+
const key = property.key.type === AST_NODE_TYPES56.Identifier ? property.key.name : property.key.type === AST_NODE_TYPES56.Literal ? String(property.key.value) : "";
|
|
15102
|
+
if (FS_READERS.has(key)) declare(property.value.name, { fsReader: true });
|
|
15103
|
+
}
|
|
15104
|
+
return;
|
|
15105
|
+
}
|
|
15106
|
+
if (node.id.type !== AST_NODE_TYPES56.Identifier) return;
|
|
15107
|
+
declare(node.id.name, { collection: sourceCollection(node.init), path: sourcePath(node.init), rawOrigins: rawOrigins(node.init) });
|
|
15108
|
+
},
|
|
15109
|
+
AssignmentExpression(node) {
|
|
15110
|
+
if (node.left.type === AST_NODE_TYPES56.Identifier) declare(node.left.name, { path: sourcePath(node.right), rawOrigins: rawOrigins(node.right) });
|
|
15111
|
+
},
|
|
15112
|
+
ForOfStatement(node) {
|
|
15113
|
+
const right = unwrap5(node.right);
|
|
15114
|
+
const collection = right.type === AST_NODE_TYPES56.Identifier && visible("collections", right.name);
|
|
15115
|
+
const left = node.left.type === AST_NODE_TYPES56.VariableDeclaration ? node.left.declarations[0]?.id : node.left;
|
|
15116
|
+
if (collection && left?.type === AST_NODE_TYPES56.Identifier) declare(left.name, { path: true });
|
|
15117
|
+
},
|
|
15118
|
+
CallExpression(node) {
|
|
15119
|
+
const origins = rawAssertionOrigins(node);
|
|
15120
|
+
if (origins.size === 0 || [...origins].every((origin) => reportedOrigins.has(origin))) return;
|
|
15121
|
+
for (const origin of origins) reportedOrigins.add(origin);
|
|
15122
|
+
context.report({ node, messageId: "rawSourceOracle" });
|
|
15123
|
+
}
|
|
15124
|
+
};
|
|
15125
|
+
}
|
|
15126
|
+
});
|
|
15127
|
+
|
|
14765
15128
|
// src/rules/zod-naming-convention.ts
|
|
14766
15129
|
import {
|
|
14767
|
-
AST_NODE_TYPES as
|
|
15130
|
+
AST_NODE_TYPES as AST_NODE_TYPES57,
|
|
14768
15131
|
ASTUtils as ASTUtils16
|
|
14769
15132
|
} from "@typescript-eslint/utils";
|
|
14770
15133
|
var zodNamingConventionDocumentation = {
|
|
@@ -14807,18 +15170,18 @@ var NON_SCHEMA_TERMINALS = /* @__PURE__ */ new Set([
|
|
|
14807
15170
|
"prettifyError",
|
|
14808
15171
|
"treeifyError"
|
|
14809
15172
|
]);
|
|
14810
|
-
var terminalMethodName = (callee) => !callee.computed && callee.property.type ===
|
|
15173
|
+
var terminalMethodName = (callee) => !callee.computed && callee.property.type === AST_NODE_TYPES57.Identifier ? callee.property.name : null;
|
|
14811
15174
|
var calleeChainRoot = (node) => {
|
|
14812
15175
|
let current = node;
|
|
14813
15176
|
for (; ; ) {
|
|
14814
|
-
if (current.type ===
|
|
15177
|
+
if (current.type === AST_NODE_TYPES57.Identifier) {
|
|
14815
15178
|
return current;
|
|
14816
15179
|
}
|
|
14817
|
-
if (current.type ===
|
|
15180
|
+
if (current.type === AST_NODE_TYPES57.MemberExpression) {
|
|
14818
15181
|
current = current.object;
|
|
14819
15182
|
continue;
|
|
14820
15183
|
}
|
|
14821
|
-
if (current.type ===
|
|
15184
|
+
if (current.type === AST_NODE_TYPES57.CallExpression) {
|
|
14822
15185
|
current = current.callee;
|
|
14823
15186
|
continue;
|
|
14824
15187
|
}
|
|
@@ -14880,7 +15243,7 @@ var zod_naming_convention_default = createRule({
|
|
|
14880
15243
|
ImportDeclaration(node) {
|
|
14881
15244
|
if (!isZodModule(node.source.value)) return;
|
|
14882
15245
|
for (const specifier of node.specifiers) {
|
|
14883
|
-
if (specifier.type ===
|
|
15246
|
+
if (specifier.type === AST_NODE_TYPES57.ImportNamespaceSpecifier || specifier.type === AST_NODE_TYPES57.ImportDefaultSpecifier || specifier.type === AST_NODE_TYPES57.ImportSpecifier && (specifier.imported.type === AST_NODE_TYPES57.Identifier ? specifier.imported.name === "z" : specifier.imported.value === "z")) {
|
|
14884
15247
|
recordZodBinding(specifier.local);
|
|
14885
15248
|
}
|
|
14886
15249
|
}
|
|
@@ -14888,13 +15251,13 @@ var zod_naming_convention_default = createRule({
|
|
|
14888
15251
|
VariableDeclarator(node) {
|
|
14889
15252
|
const init = node.init;
|
|
14890
15253
|
if (init === null || init === void 0) return;
|
|
14891
|
-
if (init.type !==
|
|
15254
|
+
if (init.type !== AST_NODE_TYPES57.CallExpression) return;
|
|
14892
15255
|
const callee = init.callee;
|
|
14893
|
-
if (callee.type !==
|
|
15256
|
+
if (callee.type !== AST_NODE_TYPES57.MemberExpression) return;
|
|
14894
15257
|
if (!isZodChain(callee)) return;
|
|
14895
15258
|
const terminal = terminalMethodName(callee);
|
|
14896
15259
|
if (terminal !== null && NON_SCHEMA_TERMINALS.has(terminal)) return;
|
|
14897
|
-
if (node.id.type !==
|
|
15260
|
+
if (node.id.type !== AST_NODE_TYPES57.Identifier) return;
|
|
14898
15261
|
if (test.test(node.id.name)) return;
|
|
14899
15262
|
if (acceptsSchemaWord && CONTAINS_SCHEMA_RE.test(node.id.name)) return;
|
|
14900
15263
|
context.report({
|
|
@@ -15003,6 +15366,7 @@ var rules = {
|
|
|
15003
15366
|
"no-impossible-zod-literal-bounds": no_impossible_zod_literal_bounds_default,
|
|
15004
15367
|
"no-log-only-catch": no_log_only_catch_default,
|
|
15005
15368
|
"no-long-comment": no_long_comment_default,
|
|
15369
|
+
"no-vague-suppression-description": no_vague_suppression_description_default,
|
|
15006
15370
|
"no-generic-single-export-module": no_generic_single_export_module_default,
|
|
15007
15371
|
"no-offset-pagination": no_offset_pagination_default,
|
|
15008
15372
|
"no-positional-tuple-return": no_positional_tuple_return_default,
|
|
@@ -15051,17 +15415,19 @@ var rules = {
|
|
|
15051
15415
|
"require-zod-form-validation": require_zod_form_validation_default,
|
|
15052
15416
|
"store-insert-requires-on-conflict": store_insert_requires_on_conflict_default,
|
|
15053
15417
|
"stepdown": stepdown_default,
|
|
15418
|
+
"source-coupled-test": source_coupled_test_default,
|
|
15054
15419
|
"zod-naming-convention": zod_naming_convention_default
|
|
15055
15420
|
};
|
|
15056
15421
|
var meta = {
|
|
15057
15422
|
name: "@sarj/eslint-plugin",
|
|
15058
|
-
version: "15.6.
|
|
15423
|
+
version: "15.6.9"
|
|
15059
15424
|
};
|
|
15060
15425
|
var applicationOnlyRules = [
|
|
15061
15426
|
"no-restricted-library-load",
|
|
15062
15427
|
"prefer-native-random-uuid",
|
|
15063
15428
|
"prefer-shadcn-primitives"
|
|
15064
15429
|
];
|
|
15430
|
+
var advisoryRules = ["no-vague-suppression-description", "source-coupled-test"];
|
|
15065
15431
|
var recommendedRules = {
|
|
15066
15432
|
"@sarj/duplicate-test-body": "error",
|
|
15067
15433
|
"@sarj/enforce-file-structure": "error",
|
|
@@ -15077,6 +15443,7 @@ var recommendedRules = {
|
|
|
15077
15443
|
"@sarj/no-impossible-zod-literal-bounds": "error",
|
|
15078
15444
|
"@sarj/no-log-only-catch": "error",
|
|
15079
15445
|
"@sarj/no-long-comment": "error",
|
|
15446
|
+
"@sarj/no-vague-suppression-description": "warn",
|
|
15080
15447
|
"@sarj/no-generic-single-export-module": "error",
|
|
15081
15448
|
"@sarj/no-offset-pagination": "error",
|
|
15082
15449
|
"@sarj/no-positional-tuple-return": "error",
|
|
@@ -15119,6 +15486,7 @@ var recommendedRules = {
|
|
|
15119
15486
|
"@sarj/require-zod-form-validation": "error",
|
|
15120
15487
|
"@sarj/store-insert-requires-on-conflict": "error",
|
|
15121
15488
|
"@sarj/stepdown": "error",
|
|
15489
|
+
"@sarj/source-coupled-test": "warn",
|
|
15122
15490
|
"@sarj/zod-naming-convention": "error"
|
|
15123
15491
|
};
|
|
15124
15492
|
var strictRules = {
|
|
@@ -15137,6 +15505,7 @@ var strictRules = {
|
|
|
15137
15505
|
"@sarj/no-impossible-zod-literal-bounds": "error",
|
|
15138
15506
|
"@sarj/no-log-only-catch": "error",
|
|
15139
15507
|
"@sarj/no-long-comment": "error",
|
|
15508
|
+
"@sarj/no-vague-suppression-description": "warn",
|
|
15140
15509
|
"@sarj/no-generic-single-export-module": "error",
|
|
15141
15510
|
"@sarj/no-offset-pagination": "error",
|
|
15142
15511
|
"@sarj/no-positional-tuple-return": "error",
|
|
@@ -15182,6 +15551,7 @@ var strictRules = {
|
|
|
15182
15551
|
"@sarj/require-zod-form-validation": "error",
|
|
15183
15552
|
"@sarj/store-insert-requires-on-conflict": "error",
|
|
15184
15553
|
"@sarj/stepdown": "error",
|
|
15554
|
+
"@sarj/source-coupled-test": "warn",
|
|
15185
15555
|
"@sarj/zod-naming-convention": "error"
|
|
15186
15556
|
};
|
|
15187
15557
|
var plugin = {
|
|
@@ -15205,6 +15575,7 @@ var plugin = {
|
|
|
15205
15575
|
};
|
|
15206
15576
|
var index_default = plugin;
|
|
15207
15577
|
export {
|
|
15578
|
+
advisoryRules,
|
|
15208
15579
|
applicationOnlyRules,
|
|
15209
15580
|
index_default as default,
|
|
15210
15581
|
publicDocumentation,
|