pasika 0.10.101 → 0.10.103
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/eslint/pasika/index.d.ts +4 -0
- package/dist/eslint/pasika/index.js +1044 -550
- package/package.json +5 -3
|
@@ -38,8 +38,8 @@ function memberPropertyName(node) {
|
|
|
38
38
|
}
|
|
39
39
|
return void 0;
|
|
40
40
|
}
|
|
41
|
-
function importedContractMember(expression,
|
|
42
|
-
if (expression?.type !== "MemberExpression" || memberPropertyName(expression) !==
|
|
41
|
+
function importedContractMember(expression, propertyName6, imports) {
|
|
42
|
+
if (expression?.type !== "MemberExpression" || memberPropertyName(expression) !== propertyName6 || expression.object.type !== "Identifier" || !imports.has(expression.object.name)) {
|
|
43
43
|
return void 0;
|
|
44
44
|
}
|
|
45
45
|
return expression.object.name;
|
|
@@ -1878,8 +1878,8 @@ function collectSections(node) {
|
|
|
1878
1878
|
function collectSteps(content, section) {
|
|
1879
1879
|
const lists = content.filter((node) => node.type === "list");
|
|
1880
1880
|
const paragraphs = content.filter((node) => node.type === "paragraph");
|
|
1881
|
-
const
|
|
1882
|
-
for (const step of
|
|
1881
|
+
const steps2 = lists.length > 0 ? lists.flatMap((list) => list.children) : paragraphs.slice(content[0]?.type === "paragraph" ? 1 : 0);
|
|
1882
|
+
for (const step of steps2) {
|
|
1883
1883
|
section.stepTexts.push(getTextContent(step));
|
|
1884
1884
|
if (section.stepTexts.length === 1) collectDocLinks(step, section.firstStepLinks);
|
|
1885
1885
|
}
|
|
@@ -2316,11 +2316,11 @@ var guideStepSingleSentenceRule = {
|
|
|
2316
2316
|
if (!filename.endsWith("-guide.md")) return;
|
|
2317
2317
|
if (!listsOnPath.at(-1)?.ordered) return;
|
|
2318
2318
|
const text = getTextContent(node).trim();
|
|
2319
|
-
const
|
|
2320
|
-
if (
|
|
2319
|
+
const sentenceCount2 = countSentences(text);
|
|
2320
|
+
if (sentenceCount2 > 1) {
|
|
2321
2321
|
context.report({
|
|
2322
2322
|
node,
|
|
2323
|
-
message: `step uses ${String(
|
|
2323
|
+
message: `step uses ${String(sentenceCount2)} sentences`
|
|
2324
2324
|
});
|
|
2325
2325
|
}
|
|
2326
2326
|
}
|
|
@@ -2453,7 +2453,7 @@ var overviewRule = {
|
|
|
2453
2453
|
}
|
|
2454
2454
|
}
|
|
2455
2455
|
if (!titleLine) return;
|
|
2456
|
-
let
|
|
2456
|
+
let sentenceCount2 = 0;
|
|
2457
2457
|
let found = false;
|
|
2458
2458
|
for (const child of node.children) {
|
|
2459
2459
|
if (child.type === "heading" && getLine(child) > titleLine) break;
|
|
@@ -2467,11 +2467,11 @@ var overviewRule = {
|
|
|
2467
2467
|
message: "overview links another document"
|
|
2468
2468
|
});
|
|
2469
2469
|
}
|
|
2470
|
-
|
|
2471
|
-
if (
|
|
2470
|
+
sentenceCount2 += countSentences2(text);
|
|
2471
|
+
if (sentenceCount2 > 2) {
|
|
2472
2472
|
context.report({
|
|
2473
2473
|
node: child,
|
|
2474
|
-
message: `overview uses ${String(
|
|
2474
|
+
message: `overview uses ${String(sentenceCount2)} sentences, at most two are allowed`
|
|
2475
2475
|
});
|
|
2476
2476
|
break;
|
|
2477
2477
|
}
|
|
@@ -2822,6 +2822,43 @@ var rulePairedExamplesRule = {
|
|
|
2822
2822
|
message: `Rule level-2 heading must be an Incorrect/Correct example: ${text}`
|
|
2823
2823
|
});
|
|
2824
2824
|
}
|
|
2825
|
+
const firstExampleIndex = node.children.findIndex((child) => child.type === "heading" && child.depth === 2);
|
|
2826
|
+
const requirementsIndex = node.children.findIndex(
|
|
2827
|
+
(child, index) => index < firstExampleIndex && child.type === "list" && !child.ordered
|
|
2828
|
+
);
|
|
2829
|
+
if (requirementsIndex !== -1) {
|
|
2830
|
+
const requirements = node.children[requirementsIndex];
|
|
2831
|
+
if (requirements?.type === "list" && requirements.spread) {
|
|
2832
|
+
context.report({
|
|
2833
|
+
node: requirements,
|
|
2834
|
+
message: "Rule requirement bullets must form one uninterrupted list without blank lines"
|
|
2835
|
+
});
|
|
2836
|
+
}
|
|
2837
|
+
for (const child of node.children.slice(requirementsIndex + 1, firstExampleIndex)) {
|
|
2838
|
+
context.report({
|
|
2839
|
+
node: child,
|
|
2840
|
+
message: "Rule requirements must be followed directly by the first Incorrect/Correct example"
|
|
2841
|
+
});
|
|
2842
|
+
}
|
|
2843
|
+
}
|
|
2844
|
+
let inExample = false;
|
|
2845
|
+
let afterWhy = false;
|
|
2846
|
+
for (const child of node.children) {
|
|
2847
|
+
if (child.type === "heading" && child.depth === 2) {
|
|
2848
|
+
inExample = true;
|
|
2849
|
+
afterWhy = false;
|
|
2850
|
+
continue;
|
|
2851
|
+
}
|
|
2852
|
+
if (!inExample) continue;
|
|
2853
|
+
if (afterWhy) {
|
|
2854
|
+
context.report({
|
|
2855
|
+
node: child,
|
|
2856
|
+
message: "A Why explanation must be the final block of its example"
|
|
2857
|
+
});
|
|
2858
|
+
} else if (child.type === "paragraph" && getTextContent(child).trim().startsWith("Why:")) {
|
|
2859
|
+
afterWhy = true;
|
|
2860
|
+
}
|
|
2861
|
+
}
|
|
2825
2862
|
const incorrect = exampleHeadings.filter((h) => h.text.startsWith("Incorrect"));
|
|
2826
2863
|
const correct = exampleHeadings.filter((h) => h.text.startsWith("Correct"));
|
|
2827
2864
|
if (incorrect.length === 0 || incorrect.length !== correct.length) {
|
|
@@ -2922,6 +2959,38 @@ var titleMatchesFileNameRule = {
|
|
|
2922
2959
|
}
|
|
2923
2960
|
};
|
|
2924
2961
|
|
|
2962
|
+
// eslint/rules/documentation/why-sentence-limit.ts
|
|
2963
|
+
var MAX_SENTENCES = 2;
|
|
2964
|
+
function sentenceCount(text) {
|
|
2965
|
+
const normalized = text.replace(/\b(?:e\.g|i\.e)\./gi, (match) => match.replaceAll(".", ""));
|
|
2966
|
+
return normalized.split(/[.!?]+["'’”\])]*(?:\s+|$)/).filter((part) => part.trim().length > 0).length;
|
|
2967
|
+
}
|
|
2968
|
+
var whySentenceLimitRule = {
|
|
2969
|
+
meta: {
|
|
2970
|
+
type: "problem",
|
|
2971
|
+
docs: {
|
|
2972
|
+
description: "Why explanations in Rules may use at most two sentences.",
|
|
2973
|
+
recommended: true
|
|
2974
|
+
}
|
|
2975
|
+
},
|
|
2976
|
+
create(context) {
|
|
2977
|
+
return {
|
|
2978
|
+
paragraph(node) {
|
|
2979
|
+
if (!getFilename(context).endsWith("-rule.md")) return;
|
|
2980
|
+
const text = node.children.map((child) => child.type === "inlineCode" ? "code" : getTextContent(child)).join("").trim();
|
|
2981
|
+
if (!text.startsWith("Why:")) return;
|
|
2982
|
+
const count = sentenceCount(text.slice("Why:".length).trim());
|
|
2983
|
+
if (count > MAX_SENTENCES) {
|
|
2984
|
+
context.report({
|
|
2985
|
+
node,
|
|
2986
|
+
message: `Why explanation has ${String(count)} sentences; maximum is ${String(MAX_SENTENCES)}.`
|
|
2987
|
+
});
|
|
2988
|
+
}
|
|
2989
|
+
}
|
|
2990
|
+
};
|
|
2991
|
+
}
|
|
2992
|
+
};
|
|
2993
|
+
|
|
2925
2994
|
// eslint/rules/documentation/index.ts
|
|
2926
2995
|
var documentationRules = {
|
|
2927
2996
|
"doc-kind-suffix": docKindSuffixRule,
|
|
@@ -2932,6 +3001,7 @@ var documentationRules = {
|
|
|
2932
3001
|
"guide-states-no-requirement": guideStatesNoRequirementRule,
|
|
2933
3002
|
"requirement-present": requirementPresentRule,
|
|
2934
3003
|
"rule-paired-examples": rulePairedExamplesRule,
|
|
3004
|
+
"why-sentence-limit": whySentenceLimitRule,
|
|
2935
3005
|
"example-heading-description": exampleHeadingDescriptionRule,
|
|
2936
3006
|
"policy-no-examples": policyNoExamplesRule,
|
|
2937
3007
|
"no-cross-document-link": noCrossDocumentLinkRule,
|
|
@@ -3850,10 +3920,9 @@ var huskyHookRule = {
|
|
|
3850
3920
|
requireNamedScript("test:unit:coverage");
|
|
3851
3921
|
const autoStageAll = /^\s*git\s+add\s+(?:--\s+)?(?:-A|--all|-u|\.)(?:\s*(?:#.*)?)?$/m.test(commands);
|
|
3852
3922
|
const coverageIndex = commands.indexOf("npm run test:unit:coverage");
|
|
3853
|
-
const
|
|
3854
|
-
|
|
3855
|
-
)
|
|
3856
|
-
if (coverageIndex >= 0 && (!coverageGuard || coverageGuard.index <= coverageIndex)) {
|
|
3923
|
+
const coverageGuards = /if\s+!\s+git\s+diff\s+--quiet\s+--\s+vitest\.config\.ts\s*;\s*then[\s\S]*?\bexit\s+1\b[\s\S]*?\bfi\b|git\s+diff\s+--exit-code\s+--\s+vitest\.config\.ts\s*\|\|\s*exit\s+1\b/g;
|
|
3924
|
+
const hasCoverageGuard = [...commands.matchAll(coverageGuards)].some((match) => match.index > coverageIndex);
|
|
3925
|
+
if (coverageIndex >= 0 && !hasCoverageGuard) {
|
|
3857
3926
|
context.report({
|
|
3858
3927
|
node,
|
|
3859
3928
|
message: ".husky/pre-commit must reject unstaged vitest.config.ts changes after coverage."
|
|
@@ -3872,25 +3941,11 @@ var huskyHookRule = {
|
|
|
3872
3941
|
message: ".husky/pre-commit must run npx vulyk sync and npx vulyk agents before lint-staged."
|
|
3873
3942
|
});
|
|
3874
3943
|
}
|
|
3875
|
-
const
|
|
3876
|
-
|
|
3877
|
-
);
|
|
3878
|
-
const tracked = /git diff --quiet -- (?<paths>[^\r\n]*)/.exec(vulykGuard?.[0] ?? "")?.groups?.paths;
|
|
3879
|
-
const untracked = /git ls-files --others --exclude-standard -- (?<paths>[^\r\n)]*)/.exec(
|
|
3880
|
-
vulykGuard?.[0] ?? ""
|
|
3881
|
-
)?.groups?.paths;
|
|
3882
|
-
const outputPaths = ["AGENTS.md", "CLAUDE.md", "docs/managed"];
|
|
3883
|
-
const hasPaths = outputPaths.every((output) => tracked?.includes(output) && untracked?.includes(output));
|
|
3884
|
-
if (!hasPaths || !vulykGuard || vulykGuard.index <= agentsIndex || vulykGuard.index >= stagedIndex) {
|
|
3885
|
-
context.report({
|
|
3886
|
-
node,
|
|
3887
|
-
message: ".husky/pre-commit must reject unstaged and untracked Vulyk-generated files before lint-staged."
|
|
3888
|
-
});
|
|
3889
|
-
}
|
|
3890
|
-
if (autoStageAll || /\bgit\s+add\s+(?:-A\s+|--all\s+|--\s+)?(?:AGENTS\.md|CLAUDE\.md|docs\/managed)\b/.test(commands)) {
|
|
3944
|
+
const stageIndex = commands.search(/\bnpx\s+vulyk\s+stage\b/);
|
|
3945
|
+
if (stageIndex <= agentsIndex || stageIndex >= stagedIndex) {
|
|
3891
3946
|
context.report({
|
|
3892
3947
|
node,
|
|
3893
|
-
message: ".husky/pre-commit must
|
|
3948
|
+
message: ".husky/pre-commit must run npx vulyk stage after agents and before lint-staged."
|
|
3894
3949
|
});
|
|
3895
3950
|
}
|
|
3896
3951
|
}
|
|
@@ -4489,7 +4544,7 @@ var localeDottedPathRule = {
|
|
|
4489
4544
|
schema: [],
|
|
4490
4545
|
type: "problem",
|
|
4491
4546
|
docs: {
|
|
4492
|
-
description: "Require
|
|
4547
|
+
description: "Require direct global and feature locale access without destructuring."
|
|
4493
4548
|
}
|
|
4494
4549
|
},
|
|
4495
4550
|
create(context) {
|
|
@@ -4510,7 +4565,7 @@ var localeDottedPathRule = {
|
|
|
4510
4565
|
if (valueName) {
|
|
4511
4566
|
context.report({
|
|
4512
4567
|
node,
|
|
4513
|
-
message: `Destructuring locales.${valueName}
|
|
4568
|
+
message: `Destructuring locales.${valueName} hides its key path; access locales directly instead.`
|
|
4514
4569
|
});
|
|
4515
4570
|
}
|
|
4516
4571
|
}
|
|
@@ -4569,10 +4624,15 @@ var ROLE_POSTFIXES = /* @__PURE__ */ new Set([
|
|
|
4569
4624
|
]);
|
|
4570
4625
|
var CAMEL_CASE = /^[a-z][a-zA-Z0-9]*$/;
|
|
4571
4626
|
var ENGLISH = /^[A-Za-z0-9_]*$/;
|
|
4572
|
-
function
|
|
4627
|
+
function dictionaryName(filename) {
|
|
4573
4628
|
const segments = path35.resolve(filename).split(path35.sep);
|
|
4574
4629
|
const srcIdx = segments.lastIndexOf("src");
|
|
4575
|
-
|
|
4630
|
+
if (srcIdx < 0 || segments[srcIdx + 1] !== "locales") return void 0;
|
|
4631
|
+
const remaining = segments.slice(srcIdx + 2);
|
|
4632
|
+
if (remaining.length === 1 && remaining[0] !== "index.ts" && /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*\.ts$/.test(remaining[0] ?? "")) {
|
|
4633
|
+
return remaining[0]?.slice(0, -3).replace(/-[a-z]/g, (match) => match.slice(1).toUpperCase());
|
|
4634
|
+
}
|
|
4635
|
+
return void 0;
|
|
4576
4636
|
}
|
|
4577
4637
|
function keyName(key) {
|
|
4578
4638
|
if (key.type === "Identifier") return key.name;
|
|
@@ -4629,31 +4689,28 @@ var localeKeyShapeRule = {
|
|
|
4629
4689
|
}
|
|
4630
4690
|
},
|
|
4631
4691
|
create(context) {
|
|
4632
|
-
|
|
4633
|
-
|
|
4692
|
+
const dictionary = dictionaryName(context.filename) ?? "";
|
|
4693
|
+
if (!dictionary) return {};
|
|
4694
|
+
function visitObject(node) {
|
|
4634
4695
|
for (const property of node.properties) {
|
|
4635
4696
|
if (property.type !== "Property") continue;
|
|
4636
4697
|
const name = keyName(property.key);
|
|
4637
4698
|
if (name === void 0) continue;
|
|
4638
4699
|
const nested = localeObject(property.value);
|
|
4639
4700
|
if (nested) {
|
|
4640
|
-
|
|
4641
|
-
|
|
4642
|
-
|
|
4643
|
-
|
|
4644
|
-
|
|
4645
|
-
|
|
4646
|
-
} else {
|
|
4647
|
-
visitObject(nested, name);
|
|
4648
|
-
}
|
|
4649
|
-
} else if (property.value.type === "Literal" && typeof property.value.value === "string") {
|
|
4701
|
+
reportFor(
|
|
4702
|
+
context,
|
|
4703
|
+
property,
|
|
4704
|
+
`Locale "${dictionary}.${name}" must not be a nested object. Keep string keys directly inside the "${dictionary}" namespace. See docs/next-codebase-guide/rules/locales-rule.md`
|
|
4705
|
+
);
|
|
4706
|
+
} else if (property.value.type === "Literal" && typeof property.value.value === "string" || property.value.type === "TemplateLiteral" && property.value.expressions.length === 0) {
|
|
4650
4707
|
checkKey(context, property, name);
|
|
4651
4708
|
}
|
|
4652
4709
|
}
|
|
4653
4710
|
}
|
|
4654
4711
|
return {
|
|
4655
4712
|
VariableDeclarator(node) {
|
|
4656
|
-
if (node.id.type !== "Identifier" || node.id.name !==
|
|
4713
|
+
if (node.id.type !== "Identifier" || node.id.name !== dictionary) return;
|
|
4657
4714
|
const root = localeObject(node.init);
|
|
4658
4715
|
if (!root) return;
|
|
4659
4716
|
visitObject(root);
|
|
@@ -4663,135 +4720,307 @@ var localeKeyShapeRule = {
|
|
|
4663
4720
|
};
|
|
4664
4721
|
|
|
4665
4722
|
// eslint/rules/locale-placement.ts
|
|
4666
|
-
import { readFileSync as
|
|
4723
|
+
import { readFileSync as readFileSync8 } from "fs";
|
|
4724
|
+
import path37 from "path";
|
|
4725
|
+
import ts7 from "typescript";
|
|
4726
|
+
|
|
4727
|
+
// eslint/rules/locale-definitions.ts
|
|
4728
|
+
import { existsSync as existsSync5, readFileSync as readFileSync7, readdirSync as readdirSync3 } from "fs";
|
|
4667
4729
|
import path36 from "path";
|
|
4668
4730
|
import ts6 from "typescript";
|
|
4669
|
-
var LOCALE_ACCESS = /\blocales\.(?<key>[A-Za-z_$][\w$]*)/g;
|
|
4670
4731
|
var camelCase = (name) => name.replace(/-[a-z]/g, (match) => match.slice(1).toUpperCase());
|
|
4671
|
-
|
|
4672
|
-
|
|
4673
|
-
|
|
4732
|
+
function unwrap(expression) {
|
|
4733
|
+
if (ts6.isAsExpression(expression) || ts6.isSatisfiesExpression(expression) || ts6.isParenthesizedExpression(expression)) {
|
|
4734
|
+
return unwrap(expression.expression);
|
|
4735
|
+
}
|
|
4736
|
+
return expression;
|
|
4674
4737
|
}
|
|
4675
|
-
function
|
|
4676
|
-
|
|
4677
|
-
for (const statement of sourceFile.statements) {
|
|
4738
|
+
function exportedDictionary(source, name) {
|
|
4739
|
+
for (const statement of source.statements) {
|
|
4678
4740
|
if (!ts6.isVariableStatement(statement)) continue;
|
|
4679
|
-
const
|
|
4741
|
+
const exported = (ts6.getModifiers(statement) ?? []).some(
|
|
4680
4742
|
(modifier) => modifier.kind === ts6.SyntaxKind.ExportKeyword
|
|
4681
4743
|
);
|
|
4682
|
-
if (!
|
|
4744
|
+
if (!exported || !(statement.declarationList.flags & ts6.NodeFlags.Const)) continue;
|
|
4745
|
+
if (statement.declarationList.declarations.length !== 1) continue;
|
|
4683
4746
|
for (const declaration of statement.declarationList.declarations) {
|
|
4684
|
-
if (
|
|
4685
|
-
|
|
4686
|
-
|
|
4687
|
-
for (const property of declaration.initializer.properties) {
|
|
4688
|
-
if (!ts6.isPropertyAssignment(property)) continue;
|
|
4689
|
-
let name;
|
|
4690
|
-
if (ts6.isIdentifier(property.name)) name = property.name.text;
|
|
4691
|
-
else if (ts6.isStringLiteral(property.name)) name = property.name.text;
|
|
4692
|
-
if (name === void 0) continue;
|
|
4693
|
-
const line = sourceFile.getLineAndCharacterOfPosition(property.getStart(sourceFile)).line + 1;
|
|
4694
|
-
placement.set(name, {
|
|
4695
|
-
kind: ts6.isObjectLiteralExpression(property.initializer) ? "nested" : "top",
|
|
4696
|
-
line
|
|
4697
|
-
});
|
|
4747
|
+
if (ts6.isIdentifier(declaration.name) && declaration.name.text === name && declaration.initializer) {
|
|
4748
|
+
const value = unwrap(declaration.initializer);
|
|
4749
|
+
if (ts6.isObjectLiteralExpression(value)) return value;
|
|
4698
4750
|
}
|
|
4699
|
-
return placement;
|
|
4700
4751
|
}
|
|
4701
4752
|
}
|
|
4702
4753
|
return void 0;
|
|
4703
4754
|
}
|
|
4755
|
+
function propertyName2(property) {
|
|
4756
|
+
if (ts6.isIdentifier(property) || ts6.isStringLiteral(property)) return property.text;
|
|
4757
|
+
return void 0;
|
|
4758
|
+
}
|
|
4759
|
+
function expectedPath(localesRoot, namespace) {
|
|
4760
|
+
const kebab = namespace.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
4761
|
+
return path36.join(localesRoot, `${kebab}.ts`);
|
|
4762
|
+
}
|
|
4763
|
+
function validateDictionary(file, namespace, errors) {
|
|
4764
|
+
const values = /* @__PURE__ */ new Map();
|
|
4765
|
+
if (!existsSync5(file)) {
|
|
4766
|
+
errors.push(`Missing locale dictionary for ${namespace}.`);
|
|
4767
|
+
return values;
|
|
4768
|
+
}
|
|
4769
|
+
const source = ts6.createSourceFile(file, readFileSync7(file, "utf8"), ts6.ScriptTarget.Latest, true, ts6.ScriptKind.TS);
|
|
4770
|
+
const dictionary = exportedDictionary(source, namespace);
|
|
4771
|
+
if (!dictionary || source.statements.length !== 1) {
|
|
4772
|
+
errors.push(`Locale module ${file} must contain only an exported const ${namespace} string dictionary.`);
|
|
4773
|
+
return values;
|
|
4774
|
+
}
|
|
4775
|
+
for (const property of dictionary.properties) {
|
|
4776
|
+
if (!ts6.isPropertyAssignment(property)) {
|
|
4777
|
+
errors.push(`Locale dictionary ${namespace} must use explicit string properties.`);
|
|
4778
|
+
continue;
|
|
4779
|
+
}
|
|
4780
|
+
const name = propertyName2(property.name);
|
|
4781
|
+
const value = unwrap(property.initializer);
|
|
4782
|
+
if (!name || !/^[a-z][a-zA-Z0-9]*$/.test(name) || values.has(name) || !ts6.isStringLiteral(value) && !ts6.isNoSubstitutionTemplateLiteral(value)) {
|
|
4783
|
+
errors.push(`Locale dictionary ${namespace} has an invalid, duplicate, or non-string key.`);
|
|
4784
|
+
continue;
|
|
4785
|
+
}
|
|
4786
|
+
values.set(name, value.text);
|
|
4787
|
+
}
|
|
4788
|
+
return values;
|
|
4789
|
+
}
|
|
4790
|
+
function readLocaleDefinitions(indexFile) {
|
|
4791
|
+
const definitions = /* @__PURE__ */ new Map();
|
|
4792
|
+
const errors = [];
|
|
4793
|
+
const root = path36.dirname(indexFile);
|
|
4794
|
+
const source = ts6.createSourceFile(
|
|
4795
|
+
indexFile,
|
|
4796
|
+
readFileSync7(indexFile, "utf8"),
|
|
4797
|
+
ts6.ScriptTarget.Latest,
|
|
4798
|
+
true,
|
|
4799
|
+
ts6.ScriptKind.TS
|
|
4800
|
+
);
|
|
4801
|
+
const imports = /* @__PURE__ */ new Map();
|
|
4802
|
+
for (const statement of source.statements) {
|
|
4803
|
+
if (ts6.isImportDeclaration(statement) && ts6.isStringLiteral(statement.moduleSpecifier)) {
|
|
4804
|
+
const named = statement.importClause?.namedBindings;
|
|
4805
|
+
if (!named || !ts6.isNamedImports(named)) {
|
|
4806
|
+
errors.push("Locale index imports must use named imports.");
|
|
4807
|
+
continue;
|
|
4808
|
+
}
|
|
4809
|
+
for (const element of named.elements) {
|
|
4810
|
+
if (element.propertyName || imports.has(element.name.text)) {
|
|
4811
|
+
errors.push("Locale index must import dictionaries by their original names without aliases.");
|
|
4812
|
+
}
|
|
4813
|
+
imports.set(element.name.text, statement.moduleSpecifier.text);
|
|
4814
|
+
}
|
|
4815
|
+
} else if (!ts6.isVariableStatement(statement)) {
|
|
4816
|
+
errors.push("Locale index may contain only imports and the exported locales dictionary.");
|
|
4817
|
+
}
|
|
4818
|
+
}
|
|
4819
|
+
const dictionary = exportedDictionary(source, "locales");
|
|
4820
|
+
if (!dictionary || source.statements.filter(ts6.isVariableStatement).length !== 1) {
|
|
4821
|
+
errors.push("Locale index must export a single const locales dictionary.");
|
|
4822
|
+
return { definitions, errors };
|
|
4823
|
+
}
|
|
4824
|
+
for (const property of dictionary.properties) {
|
|
4825
|
+
let name;
|
|
4826
|
+
let value;
|
|
4827
|
+
if (ts6.isSpreadAssignment(property)) {
|
|
4828
|
+
if (!ts6.isIdentifier(property.expression) || property.expression.text !== "global") {
|
|
4829
|
+
errors.push("Locale index may only spread the global dictionary.");
|
|
4830
|
+
continue;
|
|
4831
|
+
}
|
|
4832
|
+
name = "global";
|
|
4833
|
+
value = "global";
|
|
4834
|
+
} else if (ts6.isShorthandPropertyAssignment(property)) {
|
|
4835
|
+
name = property.name.text;
|
|
4836
|
+
value = name;
|
|
4837
|
+
} else if (ts6.isPropertyAssignment(property)) {
|
|
4838
|
+
name = propertyName2(property.name);
|
|
4839
|
+
const initial = unwrap(property.initializer);
|
|
4840
|
+
if (ts6.isIdentifier(initial)) value = initial.text;
|
|
4841
|
+
}
|
|
4842
|
+
if (!name || !value || name !== value || definitions.has(name) || !/^[a-z][a-zA-Z0-9]*$/.test(name)) {
|
|
4843
|
+
errors.push("Locale index must expose feature dictionaries by name and spread only global, without aliases.");
|
|
4844
|
+
continue;
|
|
4845
|
+
}
|
|
4846
|
+
if (name === "global" && !ts6.isSpreadAssignment(property)) {
|
|
4847
|
+
errors.push("Locale index must spread global keys into the top level.");
|
|
4848
|
+
continue;
|
|
4849
|
+
}
|
|
4850
|
+
if (name === "shared" || name === "compositions") {
|
|
4851
|
+
errors.push(`Locale namespace ${name} must not be used as a catch-all dictionary.`);
|
|
4852
|
+
continue;
|
|
4853
|
+
}
|
|
4854
|
+
const expected = expectedPath(root, name);
|
|
4855
|
+
const actualImport = imports.get(name);
|
|
4856
|
+
if (!actualImport || path36.resolve(root, actualImport + (path36.extname(actualImport) ? "" : ".ts")) !== expected) {
|
|
4857
|
+
errors.push(`Locale namespace ${name} must import its dictionary from ${path36.relative(root, expected)}.`);
|
|
4858
|
+
continue;
|
|
4859
|
+
}
|
|
4860
|
+
const values = validateDictionary(expected, name, errors);
|
|
4861
|
+
definitions.set(name, { namespace: name, file: expected, keys: new Set(values.keys()), values });
|
|
4862
|
+
}
|
|
4863
|
+
if (!definitions.has("global")) {
|
|
4864
|
+
errors.push("Locale index must spread the global dictionary.");
|
|
4865
|
+
}
|
|
4866
|
+
for (const imported of imports.keys()) {
|
|
4867
|
+
if (!definitions.has(imported)) {
|
|
4868
|
+
errors.push(`Imported locale dictionary ${imported} is not exposed in locales.`);
|
|
4869
|
+
}
|
|
4870
|
+
}
|
|
4871
|
+
for (const entry of readdirSync3(root, { withFileTypes: true })) {
|
|
4872
|
+
if (entry.isDirectory()) {
|
|
4873
|
+
errors.push(
|
|
4874
|
+
`Locale dictionaries must live directly in src/locales/; nested folder ${entry.name} is not allowed.`
|
|
4875
|
+
);
|
|
4876
|
+
} else if (entry.isFile() && entry.name.endsWith(".ts") && entry.name !== "index.ts" && !entry.name.endsWith(".test.ts") && !entry.name.endsWith(".d.ts")) {
|
|
4877
|
+
const name = camelCase(entry.name.slice(0, -3));
|
|
4878
|
+
if (!definitions.has(name) && !imports.has(name)) {
|
|
4879
|
+
errors.push(`Locale module ${entry.name} is not exposed in locales.`);
|
|
4880
|
+
}
|
|
4881
|
+
}
|
|
4882
|
+
}
|
|
4883
|
+
const global = definitions.get("global");
|
|
4884
|
+
if (global) {
|
|
4885
|
+
for (const key of global.keys) {
|
|
4886
|
+
if (definitions.has(key)) {
|
|
4887
|
+
errors.push(`Global locale key ${key} conflicts with a feature namespace.`);
|
|
4888
|
+
}
|
|
4889
|
+
}
|
|
4890
|
+
}
|
|
4891
|
+
return { definitions, errors };
|
|
4892
|
+
}
|
|
4893
|
+
|
|
4894
|
+
// eslint/rules/locale-placement.ts
|
|
4895
|
+
var DOC4 = "See docs/next-codebase-guide/rules/locales-rule.md";
|
|
4896
|
+
function localeAccesses(file) {
|
|
4897
|
+
const contents = readFileSync8(file, "utf8");
|
|
4898
|
+
const kind = /\.[jt]sx$/.test(file) ? ts7.ScriptKind.TSX : ts7.ScriptKind.TS;
|
|
4899
|
+
const source = ts7.createSourceFile(file, contents, ts7.ScriptTarget.Latest, true, kind);
|
|
4900
|
+
const accesses = [];
|
|
4901
|
+
const visit = (node) => {
|
|
4902
|
+
if (ts7.isPropertyAccessExpression(node)) {
|
|
4903
|
+
const receiver = node.expression;
|
|
4904
|
+
if (ts7.isPropertyAccessExpression(receiver) && ts7.isIdentifier(receiver.expression) && receiver.expression.text === "locales") {
|
|
4905
|
+
accesses.push({ namespace: receiver.name.text, key: node.name.text });
|
|
4906
|
+
} else if (ts7.isIdentifier(receiver) && receiver.text === "locales" && !(ts7.isPropertyAccessExpression(node.parent) && node.parent.expression === node)) {
|
|
4907
|
+
accesses.push({ namespace: node.name.text });
|
|
4908
|
+
}
|
|
4909
|
+
}
|
|
4910
|
+
ts7.forEachChild(node, visit);
|
|
4911
|
+
};
|
|
4912
|
+
visit(source);
|
|
4913
|
+
return accesses;
|
|
4914
|
+
}
|
|
4704
4915
|
var localePlacementRule = {
|
|
4705
4916
|
meta: {
|
|
4706
4917
|
schema: [],
|
|
4707
4918
|
type: "problem",
|
|
4708
4919
|
docs: {
|
|
4709
|
-
description: "
|
|
4920
|
+
description: "Enforce locale placement from consumer folders, with cross-scope strings in global."
|
|
4710
4921
|
}
|
|
4711
4922
|
},
|
|
4712
4923
|
create(context) {
|
|
4713
4924
|
const sourceRoot = sourceRootOf(context);
|
|
4714
|
-
const file =
|
|
4925
|
+
const file = path37.resolve(context.filename);
|
|
4715
4926
|
const segments = segmentsOf(file, sourceRoot);
|
|
4716
4927
|
if (segments.length === 0) return {};
|
|
4717
4928
|
const index = getProjectIndex(sourceRoot);
|
|
4718
4929
|
if (!index) return {};
|
|
4719
4930
|
const localesFile = [...index.modules.keys()].find((candidate) => {
|
|
4720
|
-
const
|
|
4721
|
-
return
|
|
4931
|
+
const parts = segmentsOf(candidate, sourceRoot);
|
|
4932
|
+
return parts.length === 2 && parts[0] === "locales" && parts[1] === "index.ts";
|
|
4722
4933
|
});
|
|
4723
4934
|
if (!localesFile || file !== localesFile) return {};
|
|
4724
|
-
const
|
|
4725
|
-
|
|
4726
|
-
const
|
|
4727
|
-
const
|
|
4728
|
-
const keyForcedTopLevel = /* @__PURE__ */ new Set();
|
|
4935
|
+
const { definitions, errors } = readLocaleDefinitions(localesFile);
|
|
4936
|
+
const findings = [...errors];
|
|
4937
|
+
const globalKeys = definitions.get("global")?.keys;
|
|
4938
|
+
const consumers = /* @__PURE__ */ new Map();
|
|
4729
4939
|
for (const [candidateFile, module] of index.modules) {
|
|
4730
4940
|
if (candidateFile === localesFile) continue;
|
|
4941
|
+
const candidateSegments = segmentsOf(candidateFile, sourceRoot);
|
|
4942
|
+
if (candidateSegments[0] !== "locales") {
|
|
4943
|
+
const bypassesIndex = module.imports.some((moduleImport) => {
|
|
4944
|
+
const resolved = resolveSpecifier(candidateFile, moduleImport.specifier, sourceRoot);
|
|
4945
|
+
if (!resolved) return false;
|
|
4946
|
+
const target = segmentsOf(resolved, sourceRoot);
|
|
4947
|
+
return target[0] === "locales" && target.length > 1 && target[1] !== "index.ts";
|
|
4948
|
+
});
|
|
4949
|
+
if (bypassesIndex) findings.push(`Locale dictionaries must be imported through src/locales/index.ts. ${DOC4}`);
|
|
4950
|
+
}
|
|
4731
4951
|
const importsLocales = module.imports.some(
|
|
4732
4952
|
(moduleImport) => resolveSpecifier(candidateFile, moduleImport.specifier, sourceRoot) === localesFile
|
|
4733
4953
|
);
|
|
4734
4954
|
if (!importsLocales) continue;
|
|
4735
|
-
const
|
|
4736
|
-
|
|
4737
|
-
|
|
4738
|
-
|
|
4739
|
-
|
|
4740
|
-
|
|
4741
|
-
|
|
4742
|
-
if (
|
|
4743
|
-
|
|
4744
|
-
|
|
4745
|
-
|
|
4746
|
-
|
|
4747
|
-
|
|
4955
|
+
for (const { namespace, key } of localeAccesses(candidateFile)) {
|
|
4956
|
+
if (key) {
|
|
4957
|
+
if (!definitions.get(namespace)?.keys.has(key) || namespace === "global") {
|
|
4958
|
+
findings.push(`Locale locales.${namespace}.${key} is not defined in a feature dictionary. ${DOC4}`);
|
|
4959
|
+
}
|
|
4960
|
+
} else if (definitions.has(namespace)) {
|
|
4961
|
+
findings.push(`Locale access locales.${namespace} must include a feature key. ${DOC4}`);
|
|
4962
|
+
} else if (!globalKeys?.has(namespace)) {
|
|
4963
|
+
findings.push(`Locale locales.${namespace} is not defined in the global dictionary. ${DOC4}`);
|
|
4964
|
+
}
|
|
4965
|
+
const access = key ? `${namespace}.${key}` : `global.${namespace}`;
|
|
4966
|
+
const used = consumers.get(access) ?? /* @__PURE__ */ new Set();
|
|
4967
|
+
used.add(candidateFile);
|
|
4968
|
+
consumers.set(access, used);
|
|
4969
|
+
}
|
|
4970
|
+
}
|
|
4971
|
+
for (const [namespace, definition] of definitions) {
|
|
4972
|
+
const folder = namespace.replace(/[A-Z]/g, (letter) => `-${letter.toLowerCase()}`);
|
|
4973
|
+
for (const key of definition.keys) {
|
|
4974
|
+
const used = [...consumers.get(`${namespace}.${key}`) ?? []];
|
|
4975
|
+
if (used.length === 0) continue;
|
|
4976
|
+
const featureOf2 = (candidate) => {
|
|
4977
|
+
const parts = segmentsOf(candidate, sourceRoot);
|
|
4978
|
+
return parts[0] === "features" ? parts[1] : void 0;
|
|
4979
|
+
};
|
|
4980
|
+
if (namespace === "global") {
|
|
4981
|
+
const features = new Set(used.map(featureOf2));
|
|
4982
|
+
const feature = [...features][0];
|
|
4983
|
+
if (features.size === 1 && feature !== void 0) {
|
|
4984
|
+
findings.push(
|
|
4985
|
+
`Locale locales.${key} is consumed only by src/features/${feature}/; move it into that feature dictionary. ${DOC4}`
|
|
4986
|
+
);
|
|
4987
|
+
}
|
|
4988
|
+
} else if (used.some((candidate) => featureOf2(candidate) !== folder)) {
|
|
4989
|
+
findings.push(
|
|
4990
|
+
`Locale locales.${namespace}.${key} is used outside src/features/${folder}/; move it into global. ${DOC4}`
|
|
4991
|
+
);
|
|
4748
4992
|
}
|
|
4749
4993
|
}
|
|
4750
4994
|
}
|
|
4751
|
-
const
|
|
4752
|
-
for (const [
|
|
4753
|
-
const
|
|
4754
|
-
|
|
4755
|
-
|
|
4756
|
-
|
|
4757
|
-
if (current?.kind === "nested") {
|
|
4758
|
-
findings.push({
|
|
4759
|
-
line: current.line,
|
|
4760
|
-
message: `Locale "${key}" is read by ${describeConsumers([...readers], sourceRoot)} and must live at the top level of locales. See docs/next-codebase-guide/rules/locales-rule.md`
|
|
4761
|
-
});
|
|
4762
|
-
}
|
|
4763
|
-
continue;
|
|
4995
|
+
const translations = /* @__PURE__ */ new Map();
|
|
4996
|
+
for (const [namespace, definition] of definitions) {
|
|
4997
|
+
for (const [key, value] of definition.values) {
|
|
4998
|
+
const entries = translations.get(value) ?? /* @__PURE__ */ new Set();
|
|
4999
|
+
entries.add(`${namespace}.${key}`);
|
|
5000
|
+
translations.set(value, entries);
|
|
4764
5001
|
}
|
|
4765
|
-
|
|
4766
|
-
|
|
4767
|
-
const
|
|
4768
|
-
if (
|
|
4769
|
-
findings.push(
|
|
4770
|
-
|
|
4771
|
-
|
|
4772
|
-
});
|
|
4773
|
-
} else if (current?.kind === "nested" && key !== expected) {
|
|
4774
|
-
findings.push({
|
|
4775
|
-
line: current.line,
|
|
4776
|
-
message: `Locale "${key}" is read only by the ${featureName} feature; it must live in an object named "${expected}", not "${key}". See docs/next-codebase-guide/rules/locales-rule.md`
|
|
4777
|
-
});
|
|
5002
|
+
}
|
|
5003
|
+
for (const [value, entries] of translations) {
|
|
5004
|
+
const namespaces = new Set([...entries].map((entry) => entry.split(".")[0]));
|
|
5005
|
+
if (namespaces.size > 1) {
|
|
5006
|
+
findings.push(
|
|
5007
|
+
`Locale text ${JSON.stringify(value)} is duplicated across dictionaries (${[...entries].join(", ")}); reuse one global key. ${DOC4}`
|
|
5008
|
+
);
|
|
4778
5009
|
}
|
|
4779
5010
|
}
|
|
4780
5011
|
if (findings.length === 0) return {};
|
|
4781
5012
|
return {
|
|
4782
5013
|
Program(node) {
|
|
4783
|
-
for (const
|
|
4784
|
-
context.report({ node, loc: { line: finding.line, column: 0 }, message: finding.message });
|
|
4785
|
-
}
|
|
5014
|
+
for (const message of findings) context.report({ node, message });
|
|
4786
5015
|
}
|
|
4787
5016
|
};
|
|
4788
5017
|
}
|
|
4789
5018
|
};
|
|
4790
5019
|
|
|
4791
5020
|
// eslint/rules/locales-location.ts
|
|
4792
|
-
import
|
|
4793
|
-
function
|
|
4794
|
-
const segments =
|
|
5021
|
+
import path38 from "path";
|
|
5022
|
+
function isLocalesFile(filename) {
|
|
5023
|
+
const segments = path38.resolve(filename).split(path38.sep);
|
|
4795
5024
|
const srcIdx = segments.lastIndexOf("src");
|
|
4796
5025
|
return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
|
|
4797
5026
|
}
|
|
@@ -4869,9 +5098,9 @@ var localesLocationRule = {
|
|
|
4869
5098
|
}
|
|
4870
5099
|
},
|
|
4871
5100
|
create(context) {
|
|
4872
|
-
if (
|
|
5101
|
+
if (isLocalesFile(context.filename) || isTestFile(context.filename)) return {};
|
|
4873
5102
|
const filename = context.filename;
|
|
4874
|
-
const segments =
|
|
5103
|
+
const segments = path38.resolve(filename).split(path38.sep);
|
|
4875
5104
|
const srcIdx = segments.lastIndexOf("src");
|
|
4876
5105
|
if (srcIdx === -1) return {};
|
|
4877
5106
|
const folder = segments[srcIdx + 1];
|
|
@@ -4956,7 +5185,7 @@ var localesLocationRule = {
|
|
|
4956
5185
|
};
|
|
4957
5186
|
|
|
4958
5187
|
// eslint/rules/named-exports.ts
|
|
4959
|
-
import
|
|
5188
|
+
import path39 from "path";
|
|
4960
5189
|
var FRAMEWORK_DEFAULT_EXPORT_FILES = /* @__PURE__ */ new Set([
|
|
4961
5190
|
// App Router routing files
|
|
4962
5191
|
"default",
|
|
@@ -4978,9 +5207,9 @@ var FRAMEWORK_DEFAULT_EXPORT_FILES = /* @__PURE__ */ new Set([
|
|
|
4978
5207
|
"twitter-image"
|
|
4979
5208
|
]);
|
|
4980
5209
|
function isFrameworkDefaultExportFile(filename) {
|
|
4981
|
-
const normalized = filename.replaceAll(
|
|
5210
|
+
const normalized = filename.replaceAll(path39.sep, "/");
|
|
4982
5211
|
if (!normalized.includes("/src/app/")) return false;
|
|
4983
|
-
const basename =
|
|
5212
|
+
const basename = path39.basename(filename, path39.extname(filename));
|
|
4984
5213
|
return FRAMEWORK_DEFAULT_EXPORT_FILES.has(basename);
|
|
4985
5214
|
}
|
|
4986
5215
|
var namedExportsRule = {
|
|
@@ -5148,12 +5377,12 @@ var noArbitraryTailwindRule = {
|
|
|
5148
5377
|
};
|
|
5149
5378
|
|
|
5150
5379
|
// eslint/rules/no-inline-runtime-literal.ts
|
|
5151
|
-
import
|
|
5380
|
+
import path41 from "path";
|
|
5152
5381
|
|
|
5153
5382
|
// eslint/project/semantic-literals.ts
|
|
5154
|
-
import { readFileSync as
|
|
5155
|
-
import
|
|
5156
|
-
import
|
|
5383
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
5384
|
+
import path40 from "path";
|
|
5385
|
+
import ts8 from "typescript";
|
|
5157
5386
|
var excludedProperties = /* @__PURE__ */ new Set([
|
|
5158
5387
|
"label",
|
|
5159
5388
|
"title",
|
|
@@ -5191,33 +5420,33 @@ var columnMethods = /* @__PURE__ */ new Set([
|
|
|
5191
5420
|
var eventMethods = /* @__PURE__ */ new Set(["emit", "on", "off", "once", "addListener", "removeListener"]);
|
|
5192
5421
|
var ignoredNumbers = /* @__PURE__ */ new Set([-1, 0, 1]);
|
|
5193
5422
|
function isProductionSource(file, root) {
|
|
5194
|
-
const parts =
|
|
5195
|
-
return !(/\.(?:test|spec|mock)\.[^.]+$/.test(
|
|
5423
|
+
const parts = path40.relative(root, file).split(path40.sep);
|
|
5424
|
+
return !(/\.(?:test|spec|mock)\.[^.]+$/.test(path40.basename(file)) || parts.some((part) => part === "__tests__" || part === "__mocks__" || part === "mocks"));
|
|
5196
5425
|
}
|
|
5197
5426
|
function featureOf(file, root) {
|
|
5198
|
-
const parts =
|
|
5427
|
+
const parts = path40.relative(root, file).split(path40.sep);
|
|
5199
5428
|
if (parts[0] === "features" && parts[1]) return `feature:${parts[1]}`;
|
|
5200
5429
|
return `layer:${parts[0] ?? "src"}`;
|
|
5201
5430
|
}
|
|
5202
5431
|
function nameOf(property) {
|
|
5203
|
-
if (
|
|
5432
|
+
if (ts8.isIdentifier(property) || ts8.isStringLiteral(property)) return property.text;
|
|
5204
5433
|
return void 0;
|
|
5205
5434
|
}
|
|
5206
5435
|
function literalOf(node) {
|
|
5207
|
-
if (
|
|
5208
|
-
if (
|
|
5209
|
-
if (
|
|
5436
|
+
if (ts8.isStringLiteral(node)) return node.text;
|
|
5437
|
+
if (ts8.isNumericLiteral(node)) return Number(node.text.replaceAll("_", ""));
|
|
5438
|
+
if (ts8.isPrefixUnaryExpression(node) && node.operator === ts8.SyntaxKind.MinusToken && ts8.isNumericLiteral(node.operand)) {
|
|
5210
5439
|
return -Number(node.operand.text.replaceAll("_", ""));
|
|
5211
5440
|
}
|
|
5212
5441
|
return void 0;
|
|
5213
5442
|
}
|
|
5214
5443
|
function isLiteralRoot(node) {
|
|
5215
|
-
if (
|
|
5216
|
-
return (
|
|
5444
|
+
if (ts8.isPrefixUnaryExpression(node)) return literalOf(node) !== void 0;
|
|
5445
|
+
return (ts8.isStringLiteral(node) || ts8.isNumericLiteral(node)) && !(ts8.isPrefixUnaryExpression(node.parent) && node.parent.operand === node);
|
|
5217
5446
|
}
|
|
5218
5447
|
function invocation(node) {
|
|
5219
|
-
if (
|
|
5220
|
-
if (
|
|
5448
|
+
if (ts8.isIdentifier(node.expression)) return { method: node.expression.text };
|
|
5449
|
+
if (ts8.isPropertyAccessExpression(node.expression)) {
|
|
5221
5450
|
const receiver = node.expression.expression.getText();
|
|
5222
5451
|
if (!/^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*)?$/.test(receiver)) return void 0;
|
|
5223
5452
|
return { method: node.expression.name.text, receiver };
|
|
@@ -5225,7 +5454,7 @@ function invocation(node) {
|
|
|
5225
5454
|
return void 0;
|
|
5226
5455
|
}
|
|
5227
5456
|
function isPathname(node) {
|
|
5228
|
-
return
|
|
5457
|
+
return ts8.isPropertyAccessExpression(node) && node.name.text === "pathname";
|
|
5229
5458
|
}
|
|
5230
5459
|
function contextFor(node, value, file, root) {
|
|
5231
5460
|
if (typeof value === "number" && ignoredNumbers.has(value)) return void 0;
|
|
@@ -5234,7 +5463,7 @@ function contextFor(node, value, file, root) {
|
|
|
5234
5463
|
const scope = featureOf(file, root);
|
|
5235
5464
|
const isApiRoute = typeof value === "string" && value.startsWith("/api/") && !/[?&#\s]/.test(value);
|
|
5236
5465
|
const route = () => ({ role: "api-route", family: "api-route" });
|
|
5237
|
-
if (
|
|
5466
|
+
if (ts8.isPropertyAssignment(parent) && parent.initializer === node) {
|
|
5238
5467
|
const name = nameOf(parent.name);
|
|
5239
5468
|
if (!name) return void 0;
|
|
5240
5469
|
if (name === "path" && isApiRoute) return route();
|
|
@@ -5243,14 +5472,14 @@ function contextFor(node, value, file, root) {
|
|
|
5243
5472
|
if (isApiRoute && /route|path|endpoint/i.test(name)) return route();
|
|
5244
5473
|
return { role: `property:${name}:${scope}`, family: `property:${name}` };
|
|
5245
5474
|
}
|
|
5246
|
-
if (
|
|
5475
|
+
if (ts8.isVariableDeclaration(parent) && parent.initializer === node && ts8.isIdentifier(parent.name)) {
|
|
5247
5476
|
if (typeof value === "number") return void 0;
|
|
5248
5477
|
const name = parent.name.text;
|
|
5249
5478
|
if (excludedProperties.has(name) || !semanticVariableName.test(name)) return void 0;
|
|
5250
5479
|
if (isApiRoute && /route|path|endpoint/i.test(name)) return route();
|
|
5251
5480
|
return { role: `variable:${name}:${scope}`, family: `variable:${name}` };
|
|
5252
5481
|
}
|
|
5253
|
-
if (
|
|
5482
|
+
if (ts8.isCallExpression(parent)) {
|
|
5254
5483
|
const position = parent.arguments.findIndex((argument) => argument === node);
|
|
5255
5484
|
if (position < 0) return void 0;
|
|
5256
5485
|
const call = invocation(parent);
|
|
@@ -5269,45 +5498,45 @@ function contextFor(node, value, file, root) {
|
|
|
5269
5498
|
return { role: `column:${scope}`, family: "column" };
|
|
5270
5499
|
}
|
|
5271
5500
|
}
|
|
5272
|
-
if (isApiRoute &&
|
|
5501
|
+
if (isApiRoute && ts8.isBinaryExpression(parent) && (parent.operatorToken.kind === ts8.SyntaxKind.EqualsEqualsEqualsToken || parent.operatorToken.kind === ts8.SyntaxKind.ExclamationEqualsEqualsToken) && (parent.left === node && isPathname(parent.right) || parent.right === node && isPathname(parent.left))) {
|
|
5273
5502
|
return route();
|
|
5274
5503
|
}
|
|
5275
|
-
if (isApiRoute &&
|
|
5504
|
+
if (isApiRoute && ts8.isCallExpression(parent) && parent.arguments[0] === node && ts8.isPropertyAccessExpression(parent.expression) && parent.expression.name.text === "startsWith" && isPathname(parent.expression.expression)) {
|
|
5276
5505
|
return route();
|
|
5277
5506
|
}
|
|
5278
5507
|
return void 0;
|
|
5279
5508
|
}
|
|
5280
5509
|
function isExported2(node) {
|
|
5281
|
-
return
|
|
5510
|
+
return ts8.canHaveModifiers(node) && (ts8.getModifiers(node) ?? []).some((modifier) => modifier.kind === ts8.SyntaxKind.ExportKeyword);
|
|
5282
5511
|
}
|
|
5283
5512
|
function parse(file, root, output) {
|
|
5284
5513
|
if (!isProductionSource(file, root)) return;
|
|
5285
|
-
const source =
|
|
5514
|
+
const source = ts8.createSourceFile(
|
|
5286
5515
|
file,
|
|
5287
|
-
|
|
5288
|
-
|
|
5516
|
+
readFileSync9(file, "utf8"),
|
|
5517
|
+
ts8.ScriptTarget.Latest,
|
|
5289
5518
|
true,
|
|
5290
|
-
file.endsWith(".tsx") || file.endsWith(".jsx") ?
|
|
5519
|
+
file.endsWith(".tsx") || file.endsWith(".jsx") ? ts8.ScriptKind.TSX : ts8.ScriptKind.TS
|
|
5291
5520
|
);
|
|
5292
|
-
const inConstants =
|
|
5521
|
+
const inConstants = path40.relative(root, file).split(path40.sep).includes("constants");
|
|
5293
5522
|
for (const statement of source.statements) {
|
|
5294
|
-
if (inConstants &&
|
|
5523
|
+
if (inConstants && ts8.isEnumDeclaration(statement) && isExported2(statement)) {
|
|
5295
5524
|
for (const member of statement.members) {
|
|
5296
5525
|
const value = member.initializer && literalOf(member.initializer);
|
|
5297
|
-
const
|
|
5298
|
-
if (value === void 0 || !
|
|
5526
|
+
const memberName10 = nameOf(member.name);
|
|
5527
|
+
if (value === void 0 || !memberName10) continue;
|
|
5299
5528
|
output.canonicals.push({
|
|
5300
5529
|
file,
|
|
5301
|
-
name:
|
|
5530
|
+
name: memberName10,
|
|
5302
5531
|
owner: statement.name.text,
|
|
5303
5532
|
kind: typeof value === "string" ? "string" : "number",
|
|
5304
5533
|
value
|
|
5305
5534
|
});
|
|
5306
5535
|
}
|
|
5307
5536
|
}
|
|
5308
|
-
if (inConstants &&
|
|
5537
|
+
if (inConstants && ts8.isVariableStatement(statement) && isExported2(statement)) {
|
|
5309
5538
|
for (const declaration of statement.declarationList.declarations) {
|
|
5310
|
-
if (!
|
|
5539
|
+
if (!ts8.isIdentifier(declaration.name) || !declaration.initializer) continue;
|
|
5311
5540
|
const value = literalOf(declaration.initializer);
|
|
5312
5541
|
if (value === void 0) continue;
|
|
5313
5542
|
output.canonicals.push({
|
|
@@ -5326,7 +5555,7 @@ function parse(file, root, output) {
|
|
|
5326
5555
|
const semantic = contextFor(node, value, file, root);
|
|
5327
5556
|
if (semantic) {
|
|
5328
5557
|
const declaration = node.parent;
|
|
5329
|
-
const isCanonicalDefinition = inConstants && (
|
|
5558
|
+
const isCanonicalDefinition = inConstants && (ts8.isVariableDeclaration(declaration) && ts8.isVariableStatement(declaration.parent.parent) && isExported2(declaration.parent.parent) || ts8.isEnumMember(declaration));
|
|
5330
5559
|
if ((!inConstants || semantic.family === "api-route") && !isCanonicalDefinition) {
|
|
5331
5560
|
const position = source.getLineAndCharacterOfPosition(node.getStart(source));
|
|
5332
5561
|
output.uses.push({
|
|
@@ -5341,7 +5570,7 @@ function parse(file, root, output) {
|
|
|
5341
5570
|
}
|
|
5342
5571
|
}
|
|
5343
5572
|
}
|
|
5344
|
-
|
|
5573
|
+
ts8.forEachChild(node, visit);
|
|
5345
5574
|
};
|
|
5346
5575
|
visit(source);
|
|
5347
5576
|
}
|
|
@@ -5361,8 +5590,8 @@ function getSemanticLiteralIndex(index) {
|
|
|
5361
5590
|
}
|
|
5362
5591
|
|
|
5363
5592
|
// eslint/rules/no-inline-runtime-literal.ts
|
|
5364
|
-
var
|
|
5365
|
-
var MESSAGE2 = `Every runtime string or numeric value must use a named constant or enum member, including single-use values. Inline JSX className
|
|
5593
|
+
var DOC5 = "See docs/next-codebase-guide/rules/constants-rule.md";
|
|
5594
|
+
var MESSAGE2 = `Every runtime string or numeric value must use a named constant or enum member, including single-use values. Inline JSX className/data-component, canonical locale strings, and static Next.js matchers are exempt. ${DOC5}`;
|
|
5366
5595
|
function isClassNameProp(node) {
|
|
5367
5596
|
let current = node;
|
|
5368
5597
|
while (current.parent) {
|
|
@@ -5375,15 +5604,43 @@ function isClassNameProp(node) {
|
|
|
5375
5604
|
}
|
|
5376
5605
|
return false;
|
|
5377
5606
|
}
|
|
5378
|
-
function
|
|
5379
|
-
|
|
5380
|
-
if (
|
|
5381
|
-
|
|
5382
|
-
|
|
5383
|
-
|
|
5384
|
-
|
|
5385
|
-
|
|
5386
|
-
|
|
5607
|
+
function isStaticDataComponentMarker(node) {
|
|
5608
|
+
const parent = node.parent;
|
|
5609
|
+
if (parent?.type !== "JSXAttribute" || parent.value !== node) return false;
|
|
5610
|
+
const name = parent.name;
|
|
5611
|
+
return typeof name === "object" && name !== null && "name" in name && name.name === "data-component";
|
|
5612
|
+
}
|
|
5613
|
+
function isStaticMatcherValue(node, root, file) {
|
|
5614
|
+
const relativeFile = path41.relative(root, file);
|
|
5615
|
+
if (relativeFile !== "middleware.ts" && relativeFile !== "proxy.ts") return false;
|
|
5616
|
+
let current = node;
|
|
5617
|
+
while (current.parent) {
|
|
5618
|
+
const parent = current.parent;
|
|
5619
|
+
if (parent.type === "ArrayExpression" && Array.isArray(parent.elements) && parent.elements.includes(current)) {
|
|
5620
|
+
current = parent;
|
|
5621
|
+
continue;
|
|
5622
|
+
}
|
|
5623
|
+
if (parent.type === "ObjectExpression" && Array.isArray(parent.properties) && parent.properties.includes(current)) {
|
|
5624
|
+
current = parent;
|
|
5625
|
+
continue;
|
|
5626
|
+
}
|
|
5627
|
+
if (parent.type !== "Property" || parent.value !== current || parent.computed) return false;
|
|
5628
|
+
const key = parent.key;
|
|
5629
|
+
if (typeof key !== "object" || key === null) return false;
|
|
5630
|
+
const isMatcher = "name" in key && key.name === "matcher" || "value" in key && key.value === "matcher";
|
|
5631
|
+
if (!isMatcher) {
|
|
5632
|
+
current = parent;
|
|
5633
|
+
continue;
|
|
5634
|
+
}
|
|
5635
|
+
const object = parent.parent;
|
|
5636
|
+
if (object?.type !== "ObjectExpression") return false;
|
|
5637
|
+
let configValue = object;
|
|
5638
|
+
while ((configValue.parent?.type === "TSAsExpression" || configValue.parent?.type === "TSSatisfiesExpression") && configValue.parent.expression === configValue) {
|
|
5639
|
+
configValue = configValue.parent;
|
|
5640
|
+
}
|
|
5641
|
+
const declaration = configValue.parent;
|
|
5642
|
+
const id = declaration?.id;
|
|
5643
|
+
return declaration?.type === "VariableDeclarator" && declaration.init === configValue && typeof id === "object" && id !== null && "name" in id && id.name === "config" && declaration.parent?.type === "VariableDeclaration" && declaration.parent.kind === "const" && declaration.parent.parent?.type === "ExportNamedDeclaration";
|
|
5387
5644
|
}
|
|
5388
5645
|
return false;
|
|
5389
5646
|
}
|
|
@@ -5393,8 +5650,7 @@ function isNamedValue(node) {
|
|
|
5393
5650
|
const parent2 = current.parent;
|
|
5394
5651
|
const isTypeWrapper = parent2.type === "TSAsExpression" || parent2.type === "TSSatisfiesExpression";
|
|
5395
5652
|
const isSignedNumber = parent2.type === "UnaryExpression" && parent2.argument === current && (parent2.operator === "-" || parent2.operator === "+");
|
|
5396
|
-
|
|
5397
|
-
if (!isTypeWrapper && !isSignedNumber && !isArithmetic) break;
|
|
5653
|
+
if (!isTypeWrapper && !isSignedNumber) break;
|
|
5398
5654
|
current = parent2;
|
|
5399
5655
|
}
|
|
5400
5656
|
const parent = current.parent;
|
|
@@ -5407,6 +5663,7 @@ function isNamedValue(node) {
|
|
|
5407
5663
|
function isSyntacticString(node) {
|
|
5408
5664
|
const parent = node.parent;
|
|
5409
5665
|
if (!parent) return false;
|
|
5666
|
+
if (parent.type === "TSModuleDeclaration" && parent.id === node) return true;
|
|
5410
5667
|
if (parent.type === "ImportDeclaration" || parent.type === "ExportNamedDeclaration" || parent.type === "ExportAllDeclaration" || parent.type === "ImportExpression" || parent.type === "TSLiteralType" || parent.type === "TSExternalModuleReference") {
|
|
5411
5668
|
return true;
|
|
5412
5669
|
}
|
|
@@ -5417,27 +5674,25 @@ function isSyntacticString(node) {
|
|
|
5417
5674
|
return false;
|
|
5418
5675
|
}
|
|
5419
5676
|
function isRuntimeMockSource(file, root) {
|
|
5420
|
-
const parts =
|
|
5421
|
-
return parts.includes("mocks") && !parts.some((part) => part === "__tests__" || part === "__mocks__") && !/\.(?:test|spec|mock)\.[^.]+$/.test(
|
|
5677
|
+
const parts = path41.relative(root, file).split(path41.sep);
|
|
5678
|
+
return parts.includes("mocks") && !parts.some((part) => part === "__tests__" || part === "__mocks__") && !/\.(?:test|spec|mock)\.[^.]+$/.test(path41.basename(file));
|
|
5422
5679
|
}
|
|
5423
5680
|
function isCanonicalLocaleString(node, root, file) {
|
|
5424
|
-
|
|
5425
|
-
let
|
|
5426
|
-
|
|
5427
|
-
|
|
5428
|
-
|
|
5429
|
-
|
|
5430
|
-
|
|
5431
|
-
|
|
5432
|
-
|
|
5433
|
-
if (depth < 1 || depth > 2) return false;
|
|
5681
|
+
const relative = path41.relative(root, file).split(path41.sep);
|
|
5682
|
+
let namespace;
|
|
5683
|
+
if (relative.length === 2 && relative[0] === "locales" && relative[1] !== "index.ts" && /^[a-z][a-z0-9]*(?:-[a-z0-9]+)*\.ts$/.test(relative[1] ?? "")) {
|
|
5684
|
+
namespace = (relative[1] ?? "").slice(0, -3).replace(/-[a-z]/g, (match) => match.slice(1).toUpperCase());
|
|
5685
|
+
}
|
|
5686
|
+
if (!namespace) return false;
|
|
5687
|
+
if (node.parent?.type !== "Property" || node.parent.value !== node) return false;
|
|
5688
|
+
let current = node.parent.parent;
|
|
5689
|
+
if (current?.type !== "ObjectExpression") return false;
|
|
5434
5690
|
while ((current.parent?.type === "TSAsExpression" || current.parent?.type === "TSSatisfiesExpression") && current.parent.expression === current) {
|
|
5435
5691
|
current = current.parent;
|
|
5436
5692
|
}
|
|
5437
5693
|
const declaration = current.parent;
|
|
5438
|
-
|
|
5439
|
-
|
|
5440
|
-
return typeof id === "object" && id !== null && "type" in id && id.type === "Identifier" && "name" in id && id.name === "locales" && declaration.parent?.type === "VariableDeclaration" && declaration.parent.kind === "const" && declaration.parent.parent?.type === "ExportNamedDeclaration";
|
|
5694
|
+
const id = declaration?.id;
|
|
5695
|
+
return declaration?.type === "VariableDeclarator" && declaration.init === current && typeof id === "object" && id !== null && "type" in id && id.type === "Identifier" && "name" in id && id.name === namespace && declaration.parent?.type === "VariableDeclaration" && declaration.parent.kind === "const" && declaration.parent.parent?.type === "ExportNamedDeclaration";
|
|
5441
5696
|
}
|
|
5442
5697
|
var noInlineRuntimeLiteralRule = {
|
|
5443
5698
|
meta: {
|
|
@@ -5447,8 +5702,8 @@ var noInlineRuntimeLiteralRule = {
|
|
|
5447
5702
|
},
|
|
5448
5703
|
create(context) {
|
|
5449
5704
|
const root = sourceRootOf(context);
|
|
5450
|
-
const file =
|
|
5451
|
-
if (!file.startsWith(root +
|
|
5705
|
+
const file = path41.resolve(context.filename);
|
|
5706
|
+
if (!file.startsWith(root + path41.sep) || !isProductionSource(file, root) && !isRuntimeMockSource(file, root)) {
|
|
5452
5707
|
return {};
|
|
5453
5708
|
}
|
|
5454
5709
|
return {
|
|
@@ -5456,7 +5711,7 @@ var noInlineRuntimeLiteralRule = {
|
|
|
5456
5711
|
if (typeof node.value !== "string" && typeof node.value !== "number" && typeof node.value !== "bigint" && !("bigint" in node && typeof node.bigint === "string")) {
|
|
5457
5712
|
return;
|
|
5458
5713
|
}
|
|
5459
|
-
if (typeof node.value === "string" && (isClassNameProp(node) || isCanonicalLocaleString(node, root, file)) || isNamedValue(node) || isSyntacticString(node)) {
|
|
5714
|
+
if (typeof node.value === "string" && (isClassNameProp(node) || isStaticDataComponentMarker(node) || isCanonicalLocaleString(node, root, file)) || isStaticMatcherValue(node, root, file) || isNamedValue(node) || isSyntacticString(node)) {
|
|
5460
5715
|
return;
|
|
5461
5716
|
}
|
|
5462
5717
|
context.report({ node, message: MESSAGE2 });
|
|
@@ -5495,7 +5750,7 @@ function isStaticValue(value) {
|
|
|
5495
5750
|
}
|
|
5496
5751
|
return false;
|
|
5497
5752
|
}
|
|
5498
|
-
function
|
|
5753
|
+
function propertyName3(property) {
|
|
5499
5754
|
if (!property.computed && property.key.type === "Identifier") return property.key.name;
|
|
5500
5755
|
if (property.key.type === "Literal" && typeof property.key.value === "string") return property.key.value;
|
|
5501
5756
|
return void 0;
|
|
@@ -5503,7 +5758,7 @@ function propertyName2(property) {
|
|
|
5503
5758
|
function findStaticDeclaration(expression) {
|
|
5504
5759
|
for (const property of expression.properties) {
|
|
5505
5760
|
if (property.type !== "Property" || property.kind !== "init") continue;
|
|
5506
|
-
const name =
|
|
5761
|
+
const name = propertyName3(property);
|
|
5507
5762
|
if (!name) continue;
|
|
5508
5763
|
if (isStaticValue(property.value)) return name;
|
|
5509
5764
|
}
|
|
@@ -5545,8 +5800,8 @@ var noLiteralInlineStyleRule = {
|
|
|
5545
5800
|
};
|
|
5546
5801
|
|
|
5547
5802
|
// eslint/rules/no-mixed-concerns.ts
|
|
5548
|
-
import { readFileSync as
|
|
5549
|
-
import
|
|
5803
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
5804
|
+
import path42 from "path";
|
|
5550
5805
|
var noMixedConcernsRule = {
|
|
5551
5806
|
meta: {
|
|
5552
5807
|
schema: [],
|
|
@@ -5570,7 +5825,7 @@ var noMixedConcernsRule = {
|
|
|
5570
5825
|
if (components.length > 1) return;
|
|
5571
5826
|
const componentName = components[0]?.name;
|
|
5572
5827
|
if (!componentName) return;
|
|
5573
|
-
const file =
|
|
5828
|
+
const file = path42.resolve(context.filename);
|
|
5574
5829
|
const sourceRoot = sourceRootOf(context);
|
|
5575
5830
|
const index = getProjectIndex(sourceRoot);
|
|
5576
5831
|
const componentConsumers = index?.symbolConsumers.get(symbolKey(file, componentName)) ?? /* @__PURE__ */ new Set();
|
|
@@ -5581,6 +5836,7 @@ var noMixedConcernsRule = {
|
|
|
5581
5836
|
if (name === componentName) return;
|
|
5582
5837
|
if (isNextPageOrLayout) {
|
|
5583
5838
|
if (["metadata", "viewport", "generateMetadata", "generateViewport"].includes(name)) return;
|
|
5839
|
+
if (name === "generateStaticParams" && /\[[^\]]+\]/.test(context.filename)) return;
|
|
5584
5840
|
context.report({
|
|
5585
5841
|
loc,
|
|
5586
5842
|
message: `Next.js page/layout files cannot export "${name}". Use a separate module for supporting values.`
|
|
@@ -5614,7 +5870,7 @@ var noMixedConcernsRule = {
|
|
|
5614
5870
|
continue;
|
|
5615
5871
|
}
|
|
5616
5872
|
const target = typeof statement.source?.value === "string" ? resolveSpecifier(file, statement.source.value, sourceRoot) : void 0;
|
|
5617
|
-
const forwardedComponents = target?.endsWith(".tsx") ? parseComponentInfo(
|
|
5873
|
+
const forwardedComponents = target?.endsWith(".tsx") ? parseComponentInfo(readFileSync10(target, "utf8"), target).map((component) => component.name) : [];
|
|
5618
5874
|
for (const specifier of statement.specifiers) {
|
|
5619
5875
|
if (/^type\b/.test(context.sourceCode.getText(specifier))) continue;
|
|
5620
5876
|
if (specifier.local.type !== "Identifier") continue;
|
|
@@ -5648,11 +5904,11 @@ var noMixedConcernsRule = {
|
|
|
5648
5904
|
};
|
|
5649
5905
|
|
|
5650
5906
|
// eslint/rules/no-redundant-alias.ts
|
|
5651
|
-
import
|
|
5907
|
+
import path44 from "path";
|
|
5652
5908
|
|
|
5653
5909
|
// eslint/rules/contract-ownership.ts
|
|
5654
|
-
import
|
|
5655
|
-
import
|
|
5910
|
+
import path43 from "path";
|
|
5911
|
+
import ts9 from "typescript";
|
|
5656
5912
|
function isTsProgram(value) {
|
|
5657
5913
|
return typeof value === "object" && value !== null && "getTypeChecker" in value && typeof value.getTypeChecker === "function" && "getSourceFiles" in value && typeof value.getSourceFiles === "function";
|
|
5658
5914
|
}
|
|
@@ -5670,8 +5926,8 @@ function normalizePath(value) {
|
|
|
5670
5926
|
return value.replaceAll("\\", "/").toLowerCase();
|
|
5671
5927
|
}
|
|
5672
5928
|
function isWithin2(root, file) {
|
|
5673
|
-
const relative =
|
|
5674
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
5929
|
+
const relative = path43.relative(root, file);
|
|
5930
|
+
return relative === "" || !relative.startsWith("..") && !path43.isAbsolute(relative);
|
|
5675
5931
|
}
|
|
5676
5932
|
function mergeOwnership(values) {
|
|
5677
5933
|
if (values.length === 0 || values.includes("unknown")) return "unknown";
|
|
@@ -5686,11 +5942,11 @@ function endpointOwnership(pathValue) {
|
|
|
5686
5942
|
return "unknown";
|
|
5687
5943
|
}
|
|
5688
5944
|
function resolvedSymbol(checker, symbol) {
|
|
5689
|
-
return symbol.flags ===
|
|
5945
|
+
return symbol.flags === ts9.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
5690
5946
|
}
|
|
5691
|
-
function
|
|
5947
|
+
function propertyName4(node) {
|
|
5692
5948
|
if (!node) return void 0;
|
|
5693
|
-
if (
|
|
5949
|
+
if (ts9.isIdentifier(node) || ts9.isStringLiteral(node) || ts9.isNumericLiteral(node)) return node.text;
|
|
5694
5950
|
return void 0;
|
|
5695
5951
|
}
|
|
5696
5952
|
var ContractOwnershipIndex = class {
|
|
@@ -5714,7 +5970,7 @@ var ContractOwnershipIndex = class {
|
|
|
5714
5970
|
}
|
|
5715
5971
|
if (declarations.length > 0) return this.endpointFromDeclarations(declarations);
|
|
5716
5972
|
let object;
|
|
5717
|
-
if (
|
|
5973
|
+
if (ts9.isPropertyAccessExpression(node) || ts9.isElementAccessExpression(node)) object = node.expression;
|
|
5718
5974
|
if (!object) return { kind: "missing", ownership: "unknown" };
|
|
5719
5975
|
const type = this.checker.getTypeAtLocation(object);
|
|
5720
5976
|
const typeDeclarations = this.typeDeclarations(type);
|
|
@@ -5722,7 +5978,7 @@ var ContractOwnershipIndex = class {
|
|
|
5722
5978
|
return this.endpointFromDeclarations(typeDeclarations);
|
|
5723
5979
|
}
|
|
5724
5980
|
sourceBinding(node, name) {
|
|
5725
|
-
if (!
|
|
5981
|
+
if (!ts9.isVariableDeclaration(node) || !node.initializer) {
|
|
5726
5982
|
return { kind: "missing", ownership: "unknown" };
|
|
5727
5983
|
}
|
|
5728
5984
|
const sourceType = this.checker.getTypeAtLocation(node.initializer);
|
|
@@ -5731,11 +5987,11 @@ var ContractOwnershipIndex = class {
|
|
|
5731
5987
|
return this.endpointFromDeclarations(declarations);
|
|
5732
5988
|
}
|
|
5733
5989
|
targetProperty(node, name) {
|
|
5734
|
-
if (!
|
|
5990
|
+
if (!ts9.isPropertyAssignment(node) && !ts9.isShorthandPropertyAssignment(node)) {
|
|
5735
5991
|
return { kind: "missing", ownership: "unknown" };
|
|
5736
5992
|
}
|
|
5737
5993
|
const object = node.parent;
|
|
5738
|
-
if (!
|
|
5994
|
+
if (!ts9.isObjectLiteralExpression(object)) return { kind: "missing", ownership: "unknown" };
|
|
5739
5995
|
const contextualType = this.checker.getContextualType(object);
|
|
5740
5996
|
if (!contextualType) return { kind: "missing", ownership: "unknown" };
|
|
5741
5997
|
const declarations = this.propertyDeclarations(contextualType, name);
|
|
@@ -5743,8 +5999,8 @@ var ContractOwnershipIndex = class {
|
|
|
5743
5999
|
return this.endpointFromDeclarations(declarations);
|
|
5744
6000
|
}
|
|
5745
6001
|
memberNameSymbol(node) {
|
|
5746
|
-
if (
|
|
5747
|
-
if (
|
|
6002
|
+
if (ts9.isPropertyAccessExpression(node)) return this.checker.getSymbolAtLocation(node.name);
|
|
6003
|
+
if (ts9.isElementAccessExpression(node)) return this.checker.getSymbolAtLocation(node.argumentExpression);
|
|
5748
6004
|
return void 0;
|
|
5749
6005
|
}
|
|
5750
6006
|
propertyDeclarations(type, name) {
|
|
@@ -5774,14 +6030,14 @@ var ContractOwnershipIndex = class {
|
|
|
5774
6030
|
if (declarations.some((declaration) => this.isDataContractField(declaration))) {
|
|
5775
6031
|
return { kind: "data-contract", ownership };
|
|
5776
6032
|
}
|
|
5777
|
-
if (declarations.some((declaration) =>
|
|
6033
|
+
if (declarations.some((declaration) => ts9.isPropertySignature(declaration) || ts9.isPropertyDeclaration(declaration))) {
|
|
5778
6034
|
return { kind: "typed-local", ownership };
|
|
5779
6035
|
}
|
|
5780
6036
|
return { kind: "non-contract", ownership };
|
|
5781
6037
|
}
|
|
5782
6038
|
isDataContractField(declaration) {
|
|
5783
6039
|
if (this.isZodSchemaField(declaration)) return true;
|
|
5784
|
-
if (!
|
|
6040
|
+
if (!ts9.isPropertySignature(declaration) && !ts9.isPropertyDeclaration(declaration)) return false;
|
|
5785
6041
|
const fileName = normalizePath(declaration.getSourceFile().fileName);
|
|
5786
6042
|
return /(?:^|\/)database(?:[-.]generated)?\.ts$/u.test(fileName);
|
|
5787
6043
|
}
|
|
@@ -5790,10 +6046,10 @@ var ContractOwnershipIndex = class {
|
|
|
5790
6046
|
return this.checker.getPropertyOfType(type, "_zod") !== void 0 && this.checker.getPropertyOfType(type, "parse") !== void 0 && this.checker.getPropertyOfType(type, "safeParse") !== void 0;
|
|
5791
6047
|
}
|
|
5792
6048
|
isZodSchemaField(declaration) {
|
|
5793
|
-
if (!
|
|
6049
|
+
if (!ts9.isPropertyAssignment(declaration)) return false;
|
|
5794
6050
|
let current = declaration.parent;
|
|
5795
|
-
while (!
|
|
5796
|
-
if (
|
|
6051
|
+
while (!ts9.isSourceFile(current)) {
|
|
6052
|
+
if (ts9.isVariableDeclaration(current) && ts9.isIdentifier(current.name) && current.name.text.endsWith("Schema")) {
|
|
5797
6053
|
return true;
|
|
5798
6054
|
}
|
|
5799
6055
|
current = current.parent;
|
|
@@ -5811,12 +6067,12 @@ var ContractOwnershipIndex = class {
|
|
|
5811
6067
|
const normalized = normalizePath(fileName);
|
|
5812
6068
|
if (/\/typescript\/lib\/lib\.[^/]+\.d\.ts$/u.test(normalized)) return "platform";
|
|
5813
6069
|
if (normalized.includes("/node_modules/")) return "third-party";
|
|
5814
|
-
if (isWithin2(this.cwd,
|
|
6070
|
+
if (isWithin2(this.cwd, path43.resolve(fileName))) return "first-party";
|
|
5815
6071
|
return "unknown";
|
|
5816
6072
|
}
|
|
5817
6073
|
schemaOwnership(declaration) {
|
|
5818
6074
|
let current = declaration;
|
|
5819
|
-
while (!
|
|
6075
|
+
while (!ts9.isSourceFile(current)) {
|
|
5820
6076
|
const ownership = this.schemaNodeOwnership.get(current);
|
|
5821
6077
|
if (ownership !== void 0) return ownership;
|
|
5822
6078
|
current = current.parent;
|
|
@@ -5825,31 +6081,31 @@ var ContractOwnershipIndex = class {
|
|
|
5825
6081
|
}
|
|
5826
6082
|
indexApiContracts() {
|
|
5827
6083
|
for (const sourceFile of this.program.getSourceFiles()) {
|
|
5828
|
-
if (sourceFile.isDeclarationFile || !isWithin2(this.cwd,
|
|
6084
|
+
if (sourceFile.isDeclarationFile || !isWithin2(this.cwd, path43.resolve(sourceFile.fileName))) continue;
|
|
5829
6085
|
const visit = (node) => {
|
|
5830
|
-
if (
|
|
5831
|
-
|
|
6086
|
+
if (ts9.isCallExpression(node) && this.isDefineApiContractCall(node)) this.indexApiContractCall(node);
|
|
6087
|
+
ts9.forEachChild(node, visit);
|
|
5832
6088
|
};
|
|
5833
6089
|
visit(sourceFile);
|
|
5834
6090
|
}
|
|
5835
6091
|
}
|
|
5836
6092
|
isDefineApiContractCall(node) {
|
|
5837
|
-
if (
|
|
5838
|
-
return
|
|
6093
|
+
if (ts9.isIdentifier(node.expression)) return node.expression.text === "defineApiContract";
|
|
6094
|
+
return ts9.isPropertyAccessExpression(node.expression) && node.expression.name.text === "defineApiContract";
|
|
5839
6095
|
}
|
|
5840
6096
|
indexApiContractCall(node) {
|
|
5841
6097
|
const argument = node.arguments[0];
|
|
5842
|
-
if (!argument || !
|
|
6098
|
+
if (!argument || !ts9.isObjectLiteralExpression(argument)) return;
|
|
5843
6099
|
let pathExpression;
|
|
5844
6100
|
const schemaExpressions = [];
|
|
5845
6101
|
for (const property of argument.properties) {
|
|
5846
|
-
if (
|
|
5847
|
-
const name =
|
|
6102
|
+
if (ts9.isPropertyAssignment(property)) {
|
|
6103
|
+
const name = propertyName4(property.name);
|
|
5848
6104
|
if (name === "path") pathExpression = property.initializer;
|
|
5849
6105
|
if (name === "requestSchema" || name === "responseSchema") schemaExpressions.push(property.initializer);
|
|
5850
6106
|
continue;
|
|
5851
6107
|
}
|
|
5852
|
-
if (
|
|
6108
|
+
if (ts9.isShorthandPropertyAssignment(property)) {
|
|
5853
6109
|
const name = property.name.text;
|
|
5854
6110
|
if (name === "path") pathExpression = property.name;
|
|
5855
6111
|
if (name === "requestSchema" || name === "responseSchema") schemaExpressions.push(property.name);
|
|
@@ -5863,13 +6119,13 @@ var ContractOwnershipIndex = class {
|
|
|
5863
6119
|
}
|
|
5864
6120
|
staticString(node, seen) {
|
|
5865
6121
|
if (!node) return void 0;
|
|
5866
|
-
if (
|
|
5867
|
-
if (
|
|
6122
|
+
if (ts9.isStringLiteralLike(node)) return node.text;
|
|
6123
|
+
if (ts9.isIdentifier(node)) {
|
|
5868
6124
|
const symbol = this.checker.getSymbolAtLocation(node);
|
|
5869
6125
|
if (!symbol || seen.has(symbol)) return void 0;
|
|
5870
6126
|
seen.add(symbol);
|
|
5871
6127
|
for (const declaration of resolvedSymbol(this.checker, symbol).declarations ?? []) {
|
|
5872
|
-
if (
|
|
6128
|
+
if (ts9.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
5873
6129
|
const value = this.staticString(declaration.initializer, seen);
|
|
5874
6130
|
if (value !== void 0) return value;
|
|
5875
6131
|
}
|
|
@@ -5887,20 +6143,20 @@ var ContractOwnershipIndex = class {
|
|
|
5887
6143
|
this.followSchemaDeclaration(declaration, ownership, seen);
|
|
5888
6144
|
}
|
|
5889
6145
|
}
|
|
5890
|
-
|
|
6146
|
+
ts9.forEachChild(node, (child) => {
|
|
5891
6147
|
this.markSchemaExpression(child, ownership, seen);
|
|
5892
6148
|
});
|
|
5893
6149
|
}
|
|
5894
6150
|
schemaReferenceSymbol(node) {
|
|
5895
|
-
if (
|
|
6151
|
+
if (ts9.isIdentifier(node)) {
|
|
5896
6152
|
if (!node.text.endsWith("Schema")) return void 0;
|
|
5897
6153
|
return this.checker.getSymbolAtLocation(node);
|
|
5898
6154
|
}
|
|
5899
|
-
if (
|
|
6155
|
+
if (ts9.isPropertyAccessExpression(node)) {
|
|
5900
6156
|
if (!node.name.text.endsWith("Schema")) return void 0;
|
|
5901
6157
|
return this.checker.getSymbolAtLocation(node.name);
|
|
5902
6158
|
}
|
|
5903
|
-
if (
|
|
6159
|
+
if (ts9.isElementAccessExpression(node) && ts9.isStringLiteralLike(node.argumentExpression)) {
|
|
5904
6160
|
if (!node.argumentExpression.text.endsWith("Schema")) return void 0;
|
|
5905
6161
|
return this.checker.getSymbolAtLocation(node.argumentExpression);
|
|
5906
6162
|
}
|
|
@@ -5908,15 +6164,15 @@ var ContractOwnershipIndex = class {
|
|
|
5908
6164
|
}
|
|
5909
6165
|
followSchemaDeclaration(declaration, ownership, seen) {
|
|
5910
6166
|
this.setSchemaOwnership(declaration, ownership);
|
|
5911
|
-
if (
|
|
6167
|
+
if (ts9.isVariableDeclaration(declaration) && declaration.initializer) {
|
|
5912
6168
|
this.markSchemaExpression(declaration.initializer, ownership, seen);
|
|
5913
6169
|
return;
|
|
5914
6170
|
}
|
|
5915
|
-
if (
|
|
6171
|
+
if (ts9.isPropertyAssignment(declaration)) {
|
|
5916
6172
|
this.markSchemaExpression(declaration.initializer, ownership, seen);
|
|
5917
6173
|
return;
|
|
5918
6174
|
}
|
|
5919
|
-
if (
|
|
6175
|
+
if (ts9.isShorthandPropertyAssignment(declaration)) {
|
|
5920
6176
|
const valueSymbol = this.checker.getShorthandAssignmentValueSymbol(declaration);
|
|
5921
6177
|
if (!valueSymbol || seen.has(valueSymbol)) return;
|
|
5922
6178
|
seen.add(valueSymbol);
|
|
@@ -5960,7 +6216,7 @@ function contractOwnershipResolver(context) {
|
|
|
5960
6216
|
}
|
|
5961
6217
|
|
|
5962
6218
|
// eslint/rules/no-redundant-alias.ts
|
|
5963
|
-
var
|
|
6219
|
+
var DOC6 = "See docs/next-codebase-guide/rules/redundant-aliases-rule.md";
|
|
5964
6220
|
var VALUE_SENTINELS = /* @__PURE__ */ new Set(["undefined", "NaN", "Infinity"]);
|
|
5965
6221
|
var HTTP_METHODS = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
5966
6222
|
var FRAMEWORK_MAPPING_KEYS = /* @__PURE__ */ new Set(["default", "apiRoutePath"]);
|
|
@@ -5993,14 +6249,14 @@ function aliasedTypeName(annotation) {
|
|
|
5993
6249
|
function aliasMessage(alias, source) {
|
|
5994
6250
|
const aliasName = alias ?? "This declaration";
|
|
5995
6251
|
const sourceName = source ?? "the original symbol";
|
|
5996
|
-
return `"${aliasName}" only renames "${sourceName}". Use "${sourceName}" directly or rename the original symbol and its consumers. ${
|
|
6252
|
+
return `"${aliasName}" only renames "${sourceName}". Use "${sourceName}" directly or rename the original symbol and its consumers. ${DOC6}`;
|
|
5997
6253
|
}
|
|
5998
6254
|
function bindingAliasMessage(alias, source) {
|
|
5999
|
-
return `"${alias}" renames "${source}" while creating a binding. Keep the original name and map it only at the object boundary. ${
|
|
6255
|
+
return `"${alias}" renames "${source}" while creating a binding. Keep the original name and map it only at the object boundary. ${DOC6}`;
|
|
6000
6256
|
}
|
|
6001
|
-
function objectPropertyMessage(
|
|
6002
|
-
if (source ===
|
|
6003
|
-
return `"${
|
|
6257
|
+
function objectPropertyMessage(propertyName6, source) {
|
|
6258
|
+
if (source === propertyName6) return `Use property shorthand for "${propertyName6}". ${DOC6}`;
|
|
6259
|
+
return `"${propertyName6}" maps the local "${source}". Keep the local name or map directly from its source object instead. ${DOC6}`;
|
|
6004
6260
|
}
|
|
6005
6261
|
function normalizePropertyName(name) {
|
|
6006
6262
|
return name.replace(/[-_\s]/g, "").toLowerCase();
|
|
@@ -6013,12 +6269,12 @@ function memberPropertyName2(node) {
|
|
|
6013
6269
|
}
|
|
6014
6270
|
return void 0;
|
|
6015
6271
|
}
|
|
6016
|
-
function isNamedMemberValue(
|
|
6017
|
-
return /^[A-Z]/.test(
|
|
6272
|
+
function isNamedMemberValue(propertyName6) {
|
|
6273
|
+
return /^[A-Z]/.test(propertyName6);
|
|
6018
6274
|
}
|
|
6019
|
-
function isQualifiedSourceField(
|
|
6275
|
+
function isQualifiedSourceField(propertyName6, sourceMember, sourcePropertyName) {
|
|
6020
6276
|
if (sourceMember.type !== "MemberExpression" || sourceMember.object.type !== "Identifier") return false;
|
|
6021
|
-
return normalizePropertyName(
|
|
6277
|
+
return normalizePropertyName(propertyName6) === normalizePropertyName(`${sourceMember.object.name}${sourcePropertyName}`);
|
|
6022
6278
|
}
|
|
6023
6279
|
function isInsideSchemaDeclaration(node) {
|
|
6024
6280
|
let current = node;
|
|
@@ -6030,11 +6286,11 @@ function isInsideSchemaDeclaration(node) {
|
|
|
6030
6286
|
}
|
|
6031
6287
|
return false;
|
|
6032
6288
|
}
|
|
6033
|
-
function semanticMappingMessage(
|
|
6034
|
-
return `"${
|
|
6289
|
+
function semanticMappingMessage(propertyName6, sourcePropertyName) {
|
|
6290
|
+
return `"${propertyName6}" maps from "${sourcePropertyName}" between first-party contracts. Use one canonical field name across the contracts. ${DOC6}`;
|
|
6035
6291
|
}
|
|
6036
|
-
function unknownContractOwnershipMessage(
|
|
6037
|
-
return `Cannot determine contract ownership for mapping "${
|
|
6292
|
+
function unknownContractOwnershipMessage(propertyName6, sourcePropertyName) {
|
|
6293
|
+
return `Cannot determine contract ownership for mapping "${propertyName6}" from "${sourcePropertyName}". Define or propagate a concrete contract, make the boundary schema explicit, or connect a mirrored external schema to its defineApiContract. ${DOC6}`;
|
|
6038
6294
|
}
|
|
6039
6295
|
function destructuredBindingSource(context, identifier) {
|
|
6040
6296
|
const initialScope = context.sourceCode.getScope(identifier);
|
|
@@ -6061,7 +6317,7 @@ function destructuredBindingSource(context, identifier) {
|
|
|
6061
6317
|
}
|
|
6062
6318
|
return void 0;
|
|
6063
6319
|
}
|
|
6064
|
-
function contractMappingViolation(
|
|
6320
|
+
function contractMappingViolation(propertyName6, sourcePropertyName, sourceResolution, targetResolution) {
|
|
6065
6321
|
if (sourceResolution.kind === "non-contract" || targetResolution.kind === "non-contract") return void 0;
|
|
6066
6322
|
if ((sourceResolution.ownership === "third-party" || sourceResolution.ownership === "platform") && targetResolution.kind !== "missing") {
|
|
6067
6323
|
return void 0;
|
|
@@ -6072,11 +6328,11 @@ function contractMappingViolation(propertyName5, sourcePropertyName, sourceResol
|
|
|
6072
6328
|
const hasDataContract = sourceResolution.kind === "data-contract" || targetResolution.kind === "data-contract";
|
|
6073
6329
|
if (!hasDataContract) return void 0;
|
|
6074
6330
|
if (sourceResolution.kind === "missing" || targetResolution.kind === "missing" || sourceResolution.ownership === "unknown" || targetResolution.ownership === "unknown") {
|
|
6075
|
-
return unknownContractOwnershipMessage(
|
|
6331
|
+
return unknownContractOwnershipMessage(propertyName6, sourcePropertyName);
|
|
6076
6332
|
}
|
|
6077
6333
|
if (sourceResolution.kind !== "data-contract") return void 0;
|
|
6078
6334
|
if (sourceResolution.ownership !== "first-party" || targetResolution.ownership !== "first-party") return void 0;
|
|
6079
|
-
return semanticMappingMessage(
|
|
6335
|
+
return semanticMappingMessage(propertyName6, sourcePropertyName);
|
|
6080
6336
|
}
|
|
6081
6337
|
var noRedundantAliasRule = {
|
|
6082
6338
|
meta: {
|
|
@@ -6096,7 +6352,7 @@ var noRedundantAliasRule = {
|
|
|
6096
6352
|
if (declaration.type !== "VariableDeclaration" || declaration.kind !== "const") return;
|
|
6097
6353
|
if (node.init.type === "Identifier") {
|
|
6098
6354
|
const exported = declaration.parent.type === "ExportNamedDeclaration";
|
|
6099
|
-
const frameworkRouteAlias =
|
|
6355
|
+
const frameworkRouteAlias = path44.basename(context.filename) === "route.ts" && exported && HTTP_METHODS.has(node.id.name);
|
|
6100
6356
|
if (frameworkRouteAlias || VALUE_SENTINELS.has(node.init.name)) return;
|
|
6101
6357
|
context.report({
|
|
6102
6358
|
node,
|
|
@@ -6105,14 +6361,14 @@ var noRedundantAliasRule = {
|
|
|
6105
6361
|
return;
|
|
6106
6362
|
}
|
|
6107
6363
|
if (node.init.type !== "MemberExpression") return;
|
|
6108
|
-
let
|
|
6364
|
+
let propertyName6;
|
|
6109
6365
|
if (!node.init.computed && node.init.property.type === "Identifier") {
|
|
6110
|
-
|
|
6366
|
+
propertyName6 = node.init.property.name;
|
|
6111
6367
|
}
|
|
6112
6368
|
if (node.init.computed && node.init.property.type === "Literal" && typeof node.init.property.value === "string") {
|
|
6113
|
-
|
|
6369
|
+
propertyName6 = node.init.property.value;
|
|
6114
6370
|
}
|
|
6115
|
-
if (
|
|
6371
|
+
if (propertyName6 === void 0 || propertyName6 === node.id.name) return;
|
|
6116
6372
|
context.report({
|
|
6117
6373
|
node,
|
|
6118
6374
|
message: bindingAliasMessage(node.id.name, context.sourceCode.getText(node.init))
|
|
@@ -6120,22 +6376,22 @@ var noRedundantAliasRule = {
|
|
|
6120
6376
|
},
|
|
6121
6377
|
Property(node) {
|
|
6122
6378
|
if (node.computed) return;
|
|
6123
|
-
let
|
|
6124
|
-
if (node.key.type === "Identifier")
|
|
6379
|
+
let propertyName6;
|
|
6380
|
+
if (node.key.type === "Identifier") propertyName6 = node.key.name;
|
|
6125
6381
|
if (node.key.type === "Literal" && typeof node.key.value === "string") {
|
|
6126
|
-
|
|
6382
|
+
propertyName6 = node.key.value;
|
|
6127
6383
|
}
|
|
6128
|
-
if (
|
|
6384
|
+
if (propertyName6 === void 0) return;
|
|
6129
6385
|
if (node.parent.type === "ObjectPattern") {
|
|
6130
6386
|
let binding;
|
|
6131
6387
|
if (node.value.type === "Identifier") binding = node.value;
|
|
6132
6388
|
if (node.value.type === "AssignmentPattern" && node.value.left.type === "Identifier") {
|
|
6133
6389
|
binding = node.value.left;
|
|
6134
6390
|
}
|
|
6135
|
-
if (!binding || binding.name ===
|
|
6391
|
+
if (!binding || binding.name === propertyName6) return;
|
|
6136
6392
|
context.report({
|
|
6137
6393
|
node,
|
|
6138
|
-
message: bindingAliasMessage(binding.name,
|
|
6394
|
+
message: bindingAliasMessage(binding.name, propertyName6)
|
|
6139
6395
|
});
|
|
6140
6396
|
return;
|
|
6141
6397
|
}
|
|
@@ -6144,12 +6400,12 @@ var noRedundantAliasRule = {
|
|
|
6144
6400
|
if (node.value.type === "Identifier") {
|
|
6145
6401
|
if (node.shorthand) return;
|
|
6146
6402
|
const source = node.value.name;
|
|
6147
|
-
if (
|
|
6403
|
+
if (propertyName6 === source) {
|
|
6148
6404
|
context.report({
|
|
6149
6405
|
node,
|
|
6150
|
-
message: objectPropertyMessage(
|
|
6406
|
+
message: objectPropertyMessage(propertyName6, source),
|
|
6151
6407
|
fix(fixer) {
|
|
6152
|
-
return fixer.replaceText(node,
|
|
6408
|
+
return fixer.replaceText(node, propertyName6);
|
|
6153
6409
|
}
|
|
6154
6410
|
});
|
|
6155
6411
|
return;
|
|
@@ -6157,29 +6413,29 @@ var noRedundantAliasRule = {
|
|
|
6157
6413
|
const bindingSource = destructuredBindingSource(context, node.value);
|
|
6158
6414
|
if (!bindingSource || !ownershipResolver) return;
|
|
6159
6415
|
const sourcePropertyName2 = bindingSource.propertyName;
|
|
6160
|
-
if (normalizePropertyName(
|
|
6161
|
-
if (FRAMEWORK_MAPPING_KEYS.has(
|
|
6416
|
+
if (normalizePropertyName(propertyName6) === normalizePropertyName(sourcePropertyName2)) return;
|
|
6417
|
+
if (FRAMEWORK_MAPPING_KEYS.has(propertyName6) || isNamedMemberValue(sourcePropertyName2)) return;
|
|
6162
6418
|
const sourceResolution2 = ownershipResolver.sourceBinding(bindingSource.declarator, sourcePropertyName2);
|
|
6163
|
-
const targetResolution2 = ownershipResolver.targetProperty(node,
|
|
6419
|
+
const targetResolution2 = ownershipResolver.targetProperty(node, propertyName6);
|
|
6164
6420
|
const hasDataContract = sourceResolution2.kind === "data-contract" || targetResolution2.kind === "data-contract";
|
|
6165
6421
|
if (!hasDataContract) return;
|
|
6166
6422
|
context.report({
|
|
6167
6423
|
node,
|
|
6168
|
-
message: contractMappingViolation(
|
|
6424
|
+
message: contractMappingViolation(propertyName6, sourcePropertyName2, sourceResolution2, targetResolution2) ?? objectPropertyMessage(propertyName6, source)
|
|
6169
6425
|
});
|
|
6170
6426
|
return;
|
|
6171
6427
|
}
|
|
6172
6428
|
if (node.value.type !== "MemberExpression") return;
|
|
6173
6429
|
const sourcePropertyName = memberPropertyName2(node.value);
|
|
6174
6430
|
if (sourcePropertyName === void 0) return;
|
|
6175
|
-
if (normalizePropertyName(
|
|
6176
|
-
if (FRAMEWORK_MAPPING_KEYS.has(
|
|
6177
|
-
if (isQualifiedSourceField(
|
|
6431
|
+
if (normalizePropertyName(propertyName6) === normalizePropertyName(sourcePropertyName)) return;
|
|
6432
|
+
if (FRAMEWORK_MAPPING_KEYS.has(propertyName6) || isNamedMemberValue(sourcePropertyName)) return;
|
|
6433
|
+
if (isQualifiedSourceField(propertyName6, node.value, sourcePropertyName)) return;
|
|
6178
6434
|
if (!ownershipResolver) return;
|
|
6179
6435
|
const sourceResolution = ownershipResolver.sourceMember(node.value);
|
|
6180
|
-
const targetResolution = ownershipResolver.targetProperty(node,
|
|
6436
|
+
const targetResolution = ownershipResolver.targetProperty(node, propertyName6);
|
|
6181
6437
|
const violation = contractMappingViolation(
|
|
6182
|
-
|
|
6438
|
+
propertyName6,
|
|
6183
6439
|
sourcePropertyName,
|
|
6184
6440
|
sourceResolution,
|
|
6185
6441
|
targetResolution
|
|
@@ -6203,6 +6459,11 @@ var noRedundantAliasRule = {
|
|
|
6203
6459
|
},
|
|
6204
6460
|
ImportSpecifier(node) {
|
|
6205
6461
|
if (node.imported.type !== "Identifier" || node.imported.name === node.local.name) return;
|
|
6462
|
+
const importDeclaration = node.parent;
|
|
6463
|
+
const source = importDeclaration.type === "ImportDeclaration" ? importDeclaration.source.value : void 0;
|
|
6464
|
+
if (typeof source === "string" && !source.startsWith(".") && !source.startsWith("/") && !source.startsWith("@/") && !source.startsWith("~/") && node.imported.name.includes("_") && /^[a-z][A-Za-z0-9]*$/.test(node.local.name)) {
|
|
6465
|
+
return;
|
|
6466
|
+
}
|
|
6206
6467
|
context.report({
|
|
6207
6468
|
node,
|
|
6208
6469
|
message: bindingAliasMessage(node.local.name, node.imported.name)
|
|
@@ -6214,7 +6475,7 @@ var noRedundantAliasRule = {
|
|
|
6214
6475
|
const source = specifier.local.name;
|
|
6215
6476
|
const alias = specifier.exported.name;
|
|
6216
6477
|
if (source === alias) continue;
|
|
6217
|
-
const frameworkRouteAlias =
|
|
6478
|
+
const frameworkRouteAlias = path44.basename(context.filename) === "route.ts" && HTTP_METHODS.has(alias);
|
|
6218
6479
|
if (frameworkRouteAlias) continue;
|
|
6219
6480
|
context.report({
|
|
6220
6481
|
node: specifier,
|
|
@@ -6239,7 +6500,7 @@ var noRedundantAliasRule = {
|
|
|
6239
6500
|
};
|
|
6240
6501
|
|
|
6241
6502
|
// eslint/rules/no-util-barrel.ts
|
|
6242
|
-
import
|
|
6503
|
+
import path45 from "path";
|
|
6243
6504
|
var noUtilBarrelRule = {
|
|
6244
6505
|
meta: {
|
|
6245
6506
|
schema: [],
|
|
@@ -6249,7 +6510,7 @@ var noUtilBarrelRule = {
|
|
|
6249
6510
|
}
|
|
6250
6511
|
},
|
|
6251
6512
|
create(context) {
|
|
6252
|
-
const filename =
|
|
6513
|
+
const filename = path45.resolve(context.filename);
|
|
6253
6514
|
const sourceRoot = sourceRootOf3(context, filename);
|
|
6254
6515
|
return {
|
|
6255
6516
|
Program(node) {
|
|
@@ -6258,7 +6519,7 @@ var noUtilBarrelRule = {
|
|
|
6258
6519
|
if (!target) continue;
|
|
6259
6520
|
const segments = target.replace(/\\/g, "/").split("/");
|
|
6260
6521
|
const utilsIndex = segments.lastIndexOf("utils");
|
|
6261
|
-
if (utilsIndex < 0 || !
|
|
6522
|
+
if (utilsIndex < 0 || !path45.basename(target).startsWith("index.")) continue;
|
|
6262
6523
|
context.report({
|
|
6263
6524
|
node,
|
|
6264
6525
|
message: `Import utilities directly instead of through "${specifier}". See docs/next-codebase-guide/rules/utilities-rule.md`
|
|
@@ -6278,16 +6539,145 @@ function importSpecifiers2(source) {
|
|
|
6278
6539
|
return specifiers;
|
|
6279
6540
|
}
|
|
6280
6541
|
function sourceRootOf3(context, filename) {
|
|
6281
|
-
const marker = `${
|
|
6542
|
+
const marker = `${path45.sep}src${path45.sep}`;
|
|
6282
6543
|
const srcIndex = filename.lastIndexOf(marker);
|
|
6283
6544
|
if (srcIndex >= 0) return filename.slice(0, srcIndex + marker.length - 1);
|
|
6284
|
-
return
|
|
6545
|
+
return path45.resolve(context.cwd ?? process.cwd(), "src");
|
|
6285
6546
|
}
|
|
6286
6547
|
|
|
6287
|
-
// eslint/rules/package-json/
|
|
6548
|
+
// eslint/rules/package-json/ci-checks.ts
|
|
6549
|
+
import { existsSync as existsSync6, readFileSync as readFileSync11, readdirSync as readdirSync4 } from "fs";
|
|
6550
|
+
import path46 from "path";
|
|
6551
|
+
import { parse as parse2 } from "yaml";
|
|
6552
|
+
function mapping(value) {
|
|
6553
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? Object.fromEntries(Object.entries(value)) : void 0;
|
|
6554
|
+
}
|
|
6288
6555
|
function memberName2(member) {
|
|
6289
6556
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
6290
6557
|
}
|
|
6558
|
+
function scriptsOf(root) {
|
|
6559
|
+
if (root.type !== "Object") return /* @__PURE__ */ new Map();
|
|
6560
|
+
const scripts = root.members.find((member) => memberName2(member) === "scripts");
|
|
6561
|
+
const members = scripts?.value.type === "Object" ? scripts.value.members : [];
|
|
6562
|
+
return new Map(
|
|
6563
|
+
members.flatMap(
|
|
6564
|
+
(member) => member.value.type === "String" ? [[memberName2(member), member.value.value]] : []
|
|
6565
|
+
)
|
|
6566
|
+
);
|
|
6567
|
+
}
|
|
6568
|
+
function events(workflow) {
|
|
6569
|
+
const on = workflow.on;
|
|
6570
|
+
if (typeof on === "string") return { [on]: null };
|
|
6571
|
+
if (Array.isArray(on)) {
|
|
6572
|
+
return Object.fromEntries(
|
|
6573
|
+
on.filter((item) => typeof item === "string").map((item) => [item, null])
|
|
6574
|
+
);
|
|
6575
|
+
}
|
|
6576
|
+
return mapping(on) ?? {};
|
|
6577
|
+
}
|
|
6578
|
+
function branchesTrigger(workflow) {
|
|
6579
|
+
const push = events(workflow).push;
|
|
6580
|
+
const branches = mapping(push)?.branches;
|
|
6581
|
+
return typeof branches === "string" ? branches.length > 0 : Array.isArray(branches) && branches.some((branch) => typeof branch === "string" && branch.length > 0);
|
|
6582
|
+
}
|
|
6583
|
+
function jobs(workflow) {
|
|
6584
|
+
return mapping(workflow.jobs) ?? {};
|
|
6585
|
+
}
|
|
6586
|
+
function steps(job) {
|
|
6587
|
+
const entries = mapping(job)?.steps;
|
|
6588
|
+
return Array.isArray(entries) ? entries.flatMap((entry) => {
|
|
6589
|
+
const step = mapping(entry);
|
|
6590
|
+
return step ? [step] : [];
|
|
6591
|
+
}) : [];
|
|
6592
|
+
}
|
|
6593
|
+
function runsScript(run, name) {
|
|
6594
|
+
if (typeof run !== "string") return false;
|
|
6595
|
+
return new RegExp(`(?:^|[\\n;&|])\\s*npm\\s+run\\s+${name}(?=\\s|$)`).test(run);
|
|
6596
|
+
}
|
|
6597
|
+
function runsNpmCi(run) {
|
|
6598
|
+
return typeof run === "string" && /(?:^|[\n;&|])\s*npm\s+ci(?=\s|$)/.test(run);
|
|
6599
|
+
}
|
|
6600
|
+
function usesAction(value, action) {
|
|
6601
|
+
return typeof value === "string" && value.startsWith(`${action}@`);
|
|
6602
|
+
}
|
|
6603
|
+
function readWorkflows(dir) {
|
|
6604
|
+
const workflows = [];
|
|
6605
|
+
const errors = [];
|
|
6606
|
+
for (const file of readdirSync4(dir).filter((name) => /\.ya?ml$/i.test(name)).sort()) {
|
|
6607
|
+
try {
|
|
6608
|
+
const parsed = parse2(readFileSync11(path46.join(dir, file), "utf8"), { uniqueKeys: true });
|
|
6609
|
+
const content = mapping(parsed);
|
|
6610
|
+
if (!content) throw new Error("expected a YAML mapping");
|
|
6611
|
+
workflows.push(content);
|
|
6612
|
+
} catch (error) {
|
|
6613
|
+
errors.push(`${file}: ${error instanceof Error ? error.message : String(error)}`);
|
|
6614
|
+
}
|
|
6615
|
+
}
|
|
6616
|
+
return { workflows, errors };
|
|
6617
|
+
}
|
|
6618
|
+
var ciChecksRule = {
|
|
6619
|
+
meta: {
|
|
6620
|
+
schema: [],
|
|
6621
|
+
type: "problem",
|
|
6622
|
+
docs: {
|
|
6623
|
+
description: "Require GitHub Actions validation for pull requests and branch pushes."
|
|
6624
|
+
}
|
|
6625
|
+
},
|
|
6626
|
+
create(context) {
|
|
6627
|
+
return {
|
|
6628
|
+
Document(node) {
|
|
6629
|
+
if (!context.filename.endsWith("package.json")) return;
|
|
6630
|
+
const dir = path46.join(context.cwd, ".github", "workflows");
|
|
6631
|
+
if (!existsSync6(dir)) return;
|
|
6632
|
+
const report3 = (message) => {
|
|
6633
|
+
context.report({ node, message });
|
|
6634
|
+
};
|
|
6635
|
+
const { workflows, errors } = readWorkflows(dir);
|
|
6636
|
+
for (const error of errors) report3(`Invalid GitHub Actions workflow: ${error}`);
|
|
6637
|
+
const check = workflows.find(
|
|
6638
|
+
(workflow) => Object.hasOwn(events(workflow), "pull_request") && branchesTrigger(workflow)
|
|
6639
|
+
);
|
|
6640
|
+
if (!check) {
|
|
6641
|
+
report3("GitHub Actions must run shared checks for pull requests and branch pushes.");
|
|
6642
|
+
return;
|
|
6643
|
+
}
|
|
6644
|
+
const scripts = scriptsOf(node.body);
|
|
6645
|
+
const requiredScripts = ["format", "lint", "typecheck", "test:unit:coverage:check"];
|
|
6646
|
+
const checkJobs = Object.values(jobs(check));
|
|
6647
|
+
const allSteps = checkJobs.flatMap(steps);
|
|
6648
|
+
for (const job of checkJobs) {
|
|
6649
|
+
const jobSteps = steps(job);
|
|
6650
|
+
const firstCheck = jobSteps.findIndex((step) => requiredScripts.some((name) => runsScript(step.run, name)));
|
|
6651
|
+
if (firstCheck < 0) continue;
|
|
6652
|
+
const checkout = jobSteps.findIndex((step) => usesAction(step.uses, "actions/checkout"));
|
|
6653
|
+
const install = jobSteps.findIndex((step) => runsNpmCi(step.run));
|
|
6654
|
+
if (checkout < 0 || checkout >= firstCheck) {
|
|
6655
|
+
report3("GitHub Actions checks must check out the repository before running npm scripts.");
|
|
6656
|
+
}
|
|
6657
|
+
if (install < 0 || install >= firstCheck || checkout >= 0 && install <= checkout) {
|
|
6658
|
+
report3("GitHub Actions checks must install dependencies with npm ci.");
|
|
6659
|
+
}
|
|
6660
|
+
}
|
|
6661
|
+
for (const name of requiredScripts) {
|
|
6662
|
+
if (!allSteps.some((step) => runsScript(step.run, name))) {
|
|
6663
|
+
report3(`GitHub Actions checks must run npm run ${name}.`);
|
|
6664
|
+
}
|
|
6665
|
+
}
|
|
6666
|
+
const coverage = scripts.get("test:unit:coverage:check");
|
|
6667
|
+
if (!coverage || !/npm\s+run\s+test:unit:coverage(?=\s|$)/.test(coverage) || !coverage.includes("--coverage.thresholds.autoUpdate=false") || !/&&\s*git\s+diff\s+--exit-code/.test(coverage)) {
|
|
6668
|
+
report3(
|
|
6669
|
+
"package.json must declare test:unit:coverage:check that runs coverage with autoUpdate=false and verifies no Git diff."
|
|
6670
|
+
);
|
|
6671
|
+
}
|
|
6672
|
+
}
|
|
6673
|
+
};
|
|
6674
|
+
}
|
|
6675
|
+
};
|
|
6676
|
+
|
|
6677
|
+
// eslint/rules/package-json/exact-version.ts
|
|
6678
|
+
function memberName3(member) {
|
|
6679
|
+
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
6680
|
+
}
|
|
6291
6681
|
var EXACT_VERSION_PATTERN = /^\d+\.\d+\.\d+$/;
|
|
6292
6682
|
function memberValue(member) {
|
|
6293
6683
|
return member.value.type === "String" ? member.value.value : null;
|
|
@@ -6306,7 +6696,7 @@ var exactVersionRule = {
|
|
|
6306
6696
|
const root = node.body;
|
|
6307
6697
|
if (root.type !== "Object") return;
|
|
6308
6698
|
for (const key of ["dependencies", "devDependencies"]) {
|
|
6309
|
-
const section = root.members.find((member) =>
|
|
6699
|
+
const section = root.members.find((member) => memberName3(member) === key);
|
|
6310
6700
|
if (section?.value.type !== "Object") continue;
|
|
6311
6701
|
for (const member of section.value.members) {
|
|
6312
6702
|
const version = memberValue(member);
|
|
@@ -6314,7 +6704,7 @@ var exactVersionRule = {
|
|
|
6314
6704
|
if (!EXACT_VERSION_PATTERN.test(version)) {
|
|
6315
6705
|
context.report({
|
|
6316
6706
|
node: member,
|
|
6317
|
-
message: `${
|
|
6707
|
+
message: `${memberName3(member)} must pin an exact version (e.g. "1.2.3"), not a range or cap such as "${version}".`
|
|
6318
6708
|
});
|
|
6319
6709
|
}
|
|
6320
6710
|
}
|
|
@@ -6325,7 +6715,7 @@ var exactVersionRule = {
|
|
|
6325
6715
|
};
|
|
6326
6716
|
|
|
6327
6717
|
// eslint/rules/package-json/lint-setup.ts
|
|
6328
|
-
function
|
|
6718
|
+
function memberName4(member) {
|
|
6329
6719
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
6330
6720
|
}
|
|
6331
6721
|
function memberValue2(member) {
|
|
@@ -6367,9 +6757,9 @@ var lintSetupRule = {
|
|
|
6367
6757
|
Document(node) {
|
|
6368
6758
|
const root = node.body;
|
|
6369
6759
|
if (root.type !== "Object") return;
|
|
6370
|
-
const scripts = root.members.find((member) =>
|
|
6760
|
+
const scripts = root.members.find((member) => memberName4(member) === "scripts");
|
|
6371
6761
|
const scriptMembers = scripts?.value.type === "Object" ? scripts.value.members : [];
|
|
6372
|
-
const findScript = (name) => scriptMembers.find((member) =>
|
|
6762
|
+
const findScript = (name) => scriptMembers.find((member) => memberName4(member) === name);
|
|
6373
6763
|
const lint = findScript("lint");
|
|
6374
6764
|
const lintCommand = memberValue2(lint);
|
|
6375
6765
|
if (lintCommand === void 0 || !runsEslintDirectly(lintCommand) || !REPOSITORY_ARGUMENT_PATTERN.test(lintCommand)) {
|
|
@@ -6402,10 +6792,10 @@ var lintSetupRule = {
|
|
|
6402
6792
|
message: 'package.json must declare a "format:staged" script that runs prettier with no repository-wide argument (e.g. "prettier --write").'
|
|
6403
6793
|
});
|
|
6404
6794
|
}
|
|
6405
|
-
const lintStagedConfig = root.members.find((member) =>
|
|
6795
|
+
const lintStagedConfig = root.members.find((member) => memberName4(member) === "lint-staged");
|
|
6406
6796
|
const stagedMembers = lintStagedConfig?.value.type === "Object" ? lintStagedConfig.value.members : [];
|
|
6407
6797
|
const runsStagedScriptForGlob = (name, matchesGlob) => stagedMembers.some(
|
|
6408
|
-
(member) => matchesGlob(
|
|
6798
|
+
(member) => matchesGlob(memberName4(member)) && stringValues(member.value).some((command) => runsNamedScript(command, name))
|
|
6409
6799
|
);
|
|
6410
6800
|
const runsStagedScriptForExtension = (name, extension) => runsStagedScriptForGlob(name, (glob) => globIncludesExtension(glob, extension));
|
|
6411
6801
|
const hasStagedSourceLint = runsStagedScriptForGlob("lint:staged", (glob) => SOURCE_GLOB_PATTERN.test(glob));
|
|
@@ -6456,13 +6846,13 @@ var NEXTJS_STACK_DEV_DEPENDENCIES = [
|
|
|
6456
6846
|
"@testing-library/react",
|
|
6457
6847
|
"@testing-library/dom"
|
|
6458
6848
|
];
|
|
6459
|
-
function
|
|
6849
|
+
function memberName5(member) {
|
|
6460
6850
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
6461
6851
|
}
|
|
6462
6852
|
function sectionPackages(root, section) {
|
|
6463
|
-
const member = root.type === "Object" ? root.members.find((entry) =>
|
|
6853
|
+
const member = root.type === "Object" ? root.members.find((entry) => memberName5(entry) === section) : void 0;
|
|
6464
6854
|
if (member?.value.type !== "Object") return /* @__PURE__ */ new Set();
|
|
6465
|
-
return new Set(member.value.members.map(
|
|
6855
|
+
return new Set(member.value.members.map(memberName5));
|
|
6466
6856
|
}
|
|
6467
6857
|
var nextjsStackRule = {
|
|
6468
6858
|
meta: {
|
|
@@ -6499,9 +6889,9 @@ var nextjsStackRule = {
|
|
|
6499
6889
|
};
|
|
6500
6890
|
|
|
6501
6891
|
// eslint/rules/package-json/vitest-coverage.ts
|
|
6502
|
-
import { existsSync as
|
|
6503
|
-
import
|
|
6504
|
-
function
|
|
6892
|
+
import { existsSync as existsSync7, readFileSync as readFileSync12 } from "fs";
|
|
6893
|
+
import path47 from "path";
|
|
6894
|
+
function memberName6(member) {
|
|
6505
6895
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
6506
6896
|
}
|
|
6507
6897
|
function memberValue3(member) {
|
|
@@ -6539,9 +6929,9 @@ var vitestCoverageRule = {
|
|
|
6539
6929
|
Document(node) {
|
|
6540
6930
|
const root = node.body;
|
|
6541
6931
|
if (root.type !== "Object") return;
|
|
6542
|
-
const devDependencies = root.members.find((member) =>
|
|
6932
|
+
const devDependencies = root.members.find((member) => memberName6(member) === "devDependencies");
|
|
6543
6933
|
const devDependencyNames = new Set(
|
|
6544
|
-
devDependencies?.value.type === "Object" ? devDependencies.value.members.map(
|
|
6934
|
+
devDependencies?.value.type === "Object" ? devDependencies.value.members.map(memberName6) : []
|
|
6545
6935
|
);
|
|
6546
6936
|
if (!devDependencyNames.has("vitest")) {
|
|
6547
6937
|
context.report({ node, message: "vitest must be listed in package.json as a devDependency." });
|
|
@@ -6552,9 +6942,9 @@ var vitestCoverageRule = {
|
|
|
6552
6942
|
message: "@vitest/coverage-v8 must be listed in package.json as a devDependency."
|
|
6553
6943
|
});
|
|
6554
6944
|
}
|
|
6555
|
-
const scripts = root.members.find((member) =>
|
|
6945
|
+
const scripts = root.members.find((member) => memberName6(member) === "scripts");
|
|
6556
6946
|
const scriptMembers = scripts?.value.type === "Object" ? scripts.value.members : [];
|
|
6557
|
-
const unit = scriptMembers.find((member) =>
|
|
6947
|
+
const unit = scriptMembers.find((member) => memberName6(member) === "test:unit");
|
|
6558
6948
|
const unitCommand = memberValue3(unit);
|
|
6559
6949
|
if (unitCommand === void 0 || !/\bvitest\b/.test(unitCommand) || COVERAGE_FLAG_PATTERN.test(unitCommand)) {
|
|
6560
6950
|
context.report({
|
|
@@ -6562,7 +6952,7 @@ var vitestCoverageRule = {
|
|
|
6562
6952
|
message: 'package.json must declare a "test:unit" script that runs Vitest without coverage.'
|
|
6563
6953
|
});
|
|
6564
6954
|
}
|
|
6565
|
-
const coverage = scriptMembers.find((member) =>
|
|
6955
|
+
const coverage = scriptMembers.find((member) => memberName6(member) === "test:unit:coverage");
|
|
6566
6956
|
const coverageCommand = memberValue3(coverage);
|
|
6567
6957
|
if (coverageCommand === void 0 || !/\bvitest\b/.test(coverageCommand) || !COVERAGE_FLAG_PATTERN.test(coverageCommand)) {
|
|
6568
6958
|
context.report({
|
|
@@ -6570,7 +6960,7 @@ var vitestCoverageRule = {
|
|
|
6570
6960
|
message: 'package.json must declare a "test:unit:coverage" script that runs Vitest with coverage.'
|
|
6571
6961
|
});
|
|
6572
6962
|
}
|
|
6573
|
-
const configName = VITEST_CONFIG_NAMES.find((name) =>
|
|
6963
|
+
const configName = VITEST_CONFIG_NAMES.find((name) => existsSync7(path47.join(context.cwd, name)));
|
|
6574
6964
|
if (!configName) {
|
|
6575
6965
|
context.report({
|
|
6576
6966
|
node,
|
|
@@ -6578,7 +6968,7 @@ var vitestCoverageRule = {
|
|
|
6578
6968
|
});
|
|
6579
6969
|
return;
|
|
6580
6970
|
}
|
|
6581
|
-
const content =
|
|
6971
|
+
const content = readFileSync12(path47.join(context.cwd, configName), "utf8");
|
|
6582
6972
|
for (const metric of THRESHOLD_METRICS) {
|
|
6583
6973
|
if (!new RegExp(`\\b${metric}\\s*:\\s*[1-9]\\d*`).test(content)) {
|
|
6584
6974
|
context.report({ node, message: `${configName} must set a coverage threshold above zero for ${metric}.` });
|
|
@@ -6590,7 +6980,7 @@ var vitestCoverageRule = {
|
|
|
6590
6980
|
message: `${configName} must enable coverage.thresholds.autoUpdate with true or the monotonic 0.1-point buffered formatter.`
|
|
6591
6981
|
});
|
|
6592
6982
|
}
|
|
6593
|
-
const stagedTests = scriptMembers.find((member) =>
|
|
6983
|
+
const stagedTests = scriptMembers.find((member) => memberName6(member) === "test:unit:staged");
|
|
6594
6984
|
const stagedTestsCommand = memberValue3(stagedTests);
|
|
6595
6985
|
if (stagedTestsCommand === void 0 || !/\bvitest\b/.test(stagedTestsCommand) || !RELATED_PATTERN.test(stagedTestsCommand) || COVERAGE_FLAG_PATTERN.test(stagedTestsCommand)) {
|
|
6596
6986
|
context.report({
|
|
@@ -6598,9 +6988,9 @@ var vitestCoverageRule = {
|
|
|
6598
6988
|
message: 'package.json must declare a "test:unit:staged" script that runs vitest related without coverage.'
|
|
6599
6989
|
});
|
|
6600
6990
|
}
|
|
6601
|
-
const lintStaged = root.members.find((member) =>
|
|
6991
|
+
const lintStaged = root.members.find((member) => memberName6(member) === "lint-staged");
|
|
6602
6992
|
const hasStagedTests = lintStaged?.value.type === "Object" && lintStaged.value.members.some(
|
|
6603
|
-
(member) => SOURCE_GLOB_PATTERN2.test(
|
|
6993
|
+
(member) => SOURCE_GLOB_PATTERN2.test(memberName6(member)) && stringValues2(member.value).some((command) => command.includes("npm run test:unit:staged"))
|
|
6604
6994
|
);
|
|
6605
6995
|
if (!hasStagedTests) {
|
|
6606
6996
|
context.report({
|
|
@@ -6615,6 +7005,7 @@ var vitestCoverageRule = {
|
|
|
6615
7005
|
|
|
6616
7006
|
// eslint/rules/package-json/index.ts
|
|
6617
7007
|
var repoPackageJsonRules = {
|
|
7008
|
+
"ci-checks": ciChecksRule,
|
|
6618
7009
|
"exact-version": exactVersionRule,
|
|
6619
7010
|
"lint-setup": lintSetupRule,
|
|
6620
7011
|
"vitest-coverage": vitestCoverageRule
|
|
@@ -6624,8 +7015,8 @@ var nextjsPackageJsonRules = {
|
|
|
6624
7015
|
};
|
|
6625
7016
|
|
|
6626
7017
|
// eslint/rules/prefer-enum.ts
|
|
6627
|
-
import
|
|
6628
|
-
import
|
|
7018
|
+
import path48 from "path";
|
|
7019
|
+
import ts10 from "typescript";
|
|
6629
7020
|
function isConstAssertion(node) {
|
|
6630
7021
|
const typeAnnotation = node.typeAnnotation;
|
|
6631
7022
|
return typeAnnotation?.type === "TSTypeReference" && typeAnnotation.typeName?.type === "Identifier" && typeAnnotation.typeName.name === "const";
|
|
@@ -6647,7 +7038,7 @@ function isZodCall(node, method) {
|
|
|
6647
7038
|
const { callee } = node;
|
|
6648
7039
|
return callee?.type === "MemberExpression" && !callee.computed && callee.object.type === "Identifier" && callee.object.name === "z" && callee.property.type === "Identifier" && callee.property.name === method;
|
|
6649
7040
|
}
|
|
6650
|
-
function
|
|
7041
|
+
function propertyName5(property) {
|
|
6651
7042
|
if (property.computed) return void 0;
|
|
6652
7043
|
if (property.key.type === "Identifier") return property.key.name;
|
|
6653
7044
|
if (property.key.type === "Literal" && typeof property.key.value === "string") return property.key.value;
|
|
@@ -6658,7 +7049,7 @@ function rawZodDiscriminantLiteral(schemaCall, discriminator) {
|
|
|
6658
7049
|
const shape = schemaCall.arguments[0];
|
|
6659
7050
|
if (shape?.type !== "ObjectExpression") return void 0;
|
|
6660
7051
|
for (const property of shape.properties) {
|
|
6661
|
-
if (property.type !== "Property" ||
|
|
7052
|
+
if (property.type !== "Property" || propertyName5(property) !== discriminator) continue;
|
|
6662
7053
|
if (property.value.type !== "CallExpression" || !isZodCall(property.value, "literal")) return void 0;
|
|
6663
7054
|
const literal = property.value.arguments[0];
|
|
6664
7055
|
if (literal?.type === "Literal" && (typeof literal.value === "string" || typeof literal.value === "number")) {
|
|
@@ -6679,13 +7070,13 @@ function isLiteralTupleAssertion(node) {
|
|
|
6679
7070
|
return values.every((value) => value !== void 0) && new Set(values).size >= 2;
|
|
6680
7071
|
}
|
|
6681
7072
|
function isTsLiteralTupleDeclaration(declaration) {
|
|
6682
|
-
if (!
|
|
7073
|
+
if (!ts10.isVariableDeclaration(declaration) || !declaration.initializer) return false;
|
|
6683
7074
|
const init = declaration.initializer;
|
|
6684
|
-
if (!
|
|
7075
|
+
if (!ts10.isAsExpression(init) || !ts10.isTypeReferenceNode(init.type) || !ts10.isIdentifier(init.type.typeName) || init.type.typeName.text !== "const" || !ts10.isArrayLiteralExpression(init.expression) || init.expression.elements.length < 2) {
|
|
6685
7076
|
return false;
|
|
6686
7077
|
}
|
|
6687
7078
|
const values = init.expression.elements.map(
|
|
6688
|
-
(element) =>
|
|
7079
|
+
(element) => ts10.isStringLiteral(element) || ts10.isNumericLiteral(element) ? element.text : void 0
|
|
6689
7080
|
);
|
|
6690
7081
|
return values.every((value) => value !== void 0) && new Set(values).size >= 2;
|
|
6691
7082
|
}
|
|
@@ -6698,9 +7089,9 @@ var preferEnumRule = {
|
|
|
6698
7089
|
}
|
|
6699
7090
|
},
|
|
6700
7091
|
create(context) {
|
|
6701
|
-
const filename =
|
|
7092
|
+
const filename = path48.resolve(context.filename);
|
|
6702
7093
|
const sourceRoot = sourceRootOf(context);
|
|
6703
|
-
if (!filename.startsWith(sourceRoot +
|
|
7094
|
+
if (!filename.startsWith(sourceRoot + path48.sep)) return {};
|
|
6704
7095
|
const objectSchemas = /* @__PURE__ */ new Map();
|
|
6705
7096
|
const literalTuples = /* @__PURE__ */ new Set();
|
|
6706
7097
|
const enumTupleUses = [];
|
|
@@ -6714,7 +7105,7 @@ var preferEnumRule = {
|
|
|
6714
7105
|
const checker = services.program.getTypeChecker();
|
|
6715
7106
|
const symbol = checker.getSymbolAtLocation(tsNode);
|
|
6716
7107
|
if (!symbol) return false;
|
|
6717
|
-
const original = symbol.flags ===
|
|
7108
|
+
const original = symbol.flags === ts10.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
6718
7109
|
return (original.declarations ?? []).some(isTsLiteralTupleDeclaration);
|
|
6719
7110
|
}
|
|
6720
7111
|
return {
|
|
@@ -6809,8 +7200,8 @@ var preferEnumRule = {
|
|
|
6809
7200
|
};
|
|
6810
7201
|
|
|
6811
7202
|
// eslint/rules/prefer-object-destructuring.ts
|
|
6812
|
-
import
|
|
6813
|
-
var
|
|
7203
|
+
import ts11 from "typescript";
|
|
7204
|
+
var DOC7 = "See docs/next-codebase-guide/rules/redundant-aliases-rule.md";
|
|
6814
7205
|
function hasTypeAnnotation(identifier) {
|
|
6815
7206
|
return "typeAnnotation" in identifier && identifier.typeAnnotation !== void 0;
|
|
6816
7207
|
}
|
|
@@ -6822,19 +7213,19 @@ function directPropertyBinding(context, declarator, isEnumValue) {
|
|
|
6822
7213
|
if (member.computed || member.optional || member.property.type !== "Identifier") return void 0;
|
|
6823
7214
|
if (!memberCanBecomeLocal(member)) return void 0;
|
|
6824
7215
|
if (context.sourceCode.getCommentsInside(declarator).length > 0) return void 0;
|
|
6825
|
-
const
|
|
7216
|
+
const propertyName6 = member.property.name;
|
|
6826
7217
|
const localName = declarator.id.name;
|
|
6827
|
-
if (
|
|
7218
|
+
if (propertyName6 !== localName) return void 0;
|
|
6828
7219
|
const source = member.object;
|
|
6829
7220
|
const sourceText = context.sourceCode.getText(source);
|
|
6830
7221
|
return {
|
|
6831
7222
|
declarator,
|
|
6832
7223
|
member,
|
|
6833
|
-
propertyName:
|
|
7224
|
+
propertyName: propertyName6,
|
|
6834
7225
|
localName,
|
|
6835
7226
|
source,
|
|
6836
7227
|
sourceText,
|
|
6837
|
-
bindingText:
|
|
7228
|
+
bindingText: propertyName6
|
|
6838
7229
|
};
|
|
6839
7230
|
}
|
|
6840
7231
|
function canGroupSource(source) {
|
|
@@ -6852,8 +7243,8 @@ function rootIdentifierName(node) {
|
|
|
6852
7243
|
if (node.type !== "MemberExpression" || node.object.type === "Super") return void 0;
|
|
6853
7244
|
return rootIdentifierName(node.object);
|
|
6854
7245
|
}
|
|
6855
|
-
function isCompliantLocalName(
|
|
6856
|
-
return !
|
|
7246
|
+
function isCompliantLocalName(propertyName6) {
|
|
7247
|
+
return !propertyName6.includes("_") || /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$/u.test(propertyName6);
|
|
6857
7248
|
}
|
|
6858
7249
|
function propertyNameOf(node) {
|
|
6859
7250
|
if (node.type !== "Property" || node.computed) return void 0;
|
|
@@ -6902,8 +7293,8 @@ function enumValueResolver(context) {
|
|
|
6902
7293
|
const checker = services.program.getTypeChecker();
|
|
6903
7294
|
const { esTreeNodeToTSNodeMap: nodeMap } = services;
|
|
6904
7295
|
const isEnumSymbol = (symbol) => {
|
|
6905
|
-
const resolved = symbol.flags ===
|
|
6906
|
-
return (resolved.declarations ?? []).some((declaration) =>
|
|
7296
|
+
const resolved = symbol.flags === ts11.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
7297
|
+
return (resolved.declarations ?? []).some((declaration) => ts11.isEnumDeclaration(declaration));
|
|
6907
7298
|
};
|
|
6908
7299
|
return (node) => {
|
|
6909
7300
|
const tsNode = nodeMap.get(node);
|
|
@@ -6919,27 +7310,27 @@ function detachableCallResolver(context) {
|
|
|
6919
7310
|
if (!services) return () => false;
|
|
6920
7311
|
const checker = services.program.getTypeChecker();
|
|
6921
7312
|
const { esTreeNodeToTSNodeMap: nodeMap } = services;
|
|
6922
|
-
const isUnboundFunctionType = (type) =>
|
|
7313
|
+
const isUnboundFunctionType = (type) => ts11.isFunctionTypeNode(type) && !type.parameters.some((parameter) => ts11.isIdentifier(parameter.name) && parameter.name.text === "this");
|
|
6923
7314
|
return (member) => {
|
|
6924
7315
|
const node = nodeMap.get(member);
|
|
6925
|
-
if (!node || !
|
|
7316
|
+
if (!node || !ts11.isPropertyAccessExpression(node)) return false;
|
|
6926
7317
|
const symbol = checker.getSymbolAtLocation(node.name);
|
|
6927
7318
|
const declarations = symbol?.declarations;
|
|
6928
7319
|
if (!declarations?.length) return false;
|
|
6929
7320
|
return declarations.every((declaration) => {
|
|
6930
|
-
if (
|
|
6931
|
-
return declaration.type !== void 0 && isUnboundFunctionType(declaration.type) ||
|
|
7321
|
+
if (ts11.isPropertySignature(declaration) || ts11.isPropertyDeclaration(declaration)) {
|
|
7322
|
+
return declaration.type !== void 0 && isUnboundFunctionType(declaration.type) || ts11.isPropertyDeclaration(declaration) && declaration.initializer !== void 0 && ts11.isArrowFunction(declaration.initializer);
|
|
6932
7323
|
}
|
|
6933
|
-
if (
|
|
7324
|
+
if (ts11.isPropertyAssignment(declaration)) return ts11.isArrowFunction(declaration.initializer);
|
|
6934
7325
|
return false;
|
|
6935
7326
|
});
|
|
6936
7327
|
};
|
|
6937
7328
|
}
|
|
6938
7329
|
function directMappingRequiresQualifiedAccess(context, ownershipResolver, member) {
|
|
6939
|
-
const
|
|
6940
|
-
if (!
|
|
6941
|
-
const sourceResolution = ownershipResolver.sourceMember(
|
|
6942
|
-
const targetResolution = ownershipResolver.targetProperty(
|
|
7330
|
+
const mapping2 = renamedDirectMapping(context, member);
|
|
7331
|
+
if (!mapping2 || !ownershipResolver) return false;
|
|
7332
|
+
const sourceResolution = ownershipResolver.sourceMember(mapping2.sourceMember);
|
|
7333
|
+
const targetResolution = ownershipResolver.targetProperty(mapping2.property, mapping2.targetName);
|
|
6943
7334
|
return sourceResolution.kind === "data-contract" || targetResolution.kind === "data-contract";
|
|
6944
7335
|
}
|
|
6945
7336
|
function memberCanBeDestructured(context, ownershipResolver, member, isEnumValue) {
|
|
@@ -6975,10 +7366,10 @@ function recordMemberUsage(context, scope, ownershipResolver, member, isEnumValu
|
|
|
6975
7366
|
if (!isGroupedUsageSource(member.object) || !memberIsRead(context, member, detachableCall)) return;
|
|
6976
7367
|
const sourceText = context.sourceCode.getText(member.object);
|
|
6977
7368
|
const usage = objectUsage(scope, sourceText);
|
|
6978
|
-
const
|
|
6979
|
-
usage.propertyNames.add(
|
|
7369
|
+
const propertyName6 = member.property.name;
|
|
7370
|
+
usage.propertyNames.add(propertyName6);
|
|
6980
7371
|
if (!memberIsDirectVariableInitializer(context, member)) {
|
|
6981
|
-
usage.directMembers.push({ member, propertyName:
|
|
7372
|
+
usage.directMembers.push({ member, propertyName: propertyName6 });
|
|
6982
7373
|
}
|
|
6983
7374
|
}
|
|
6984
7375
|
function recordDestructuringUsage(context, scope, declaration, isEnumValue) {
|
|
@@ -7001,7 +7392,7 @@ function recordDestructuringUsage(context, scope, declaration, isEnumValue) {
|
|
|
7001
7392
|
}
|
|
7002
7393
|
function scopeUsageMessage(sourceText, propertyNames) {
|
|
7003
7394
|
const names = [...propertyNames].map((name) => `"${name}"`).join(", ");
|
|
7004
|
-
return `${names} are read from "${sourceText}" in the same block. Destructure them together in one declaration. ${
|
|
7395
|
+
return `${names} are read from "${sourceText}" in the same block. Destructure them together in one declaration. ${DOC7}`;
|
|
7005
7396
|
}
|
|
7006
7397
|
function hasBinding(context, node, name) {
|
|
7007
7398
|
const initialScope = context.sourceCode.getScope(node);
|
|
@@ -7105,13 +7496,13 @@ function groupedDestructuringSelections(context, first, isEnumValue) {
|
|
|
7105
7496
|
if (!previous || nextNode?.type !== "VariableDeclaration" || nextNode.kind !== first.declaration.kind) break;
|
|
7106
7497
|
const next = destructuringSelection(context, nextNode, isEnumValue);
|
|
7107
7498
|
if (next?.sourceText !== first.sourceText) break;
|
|
7108
|
-
if (next.propertyNames.some((
|
|
7499
|
+
if (next.propertyNames.some((propertyName6) => seenProperties.has(propertyName6))) break;
|
|
7109
7500
|
const [, previousEnd] = context.sourceCode.getRange(previous);
|
|
7110
7501
|
const [nextStart] = context.sourceCode.getRange(nextNode);
|
|
7111
7502
|
const gap = context.sourceCode.text.slice(previousEnd, nextStart);
|
|
7112
7503
|
if (!whitespaceKeepsStatementsAdjacent(gap)) break;
|
|
7113
7504
|
group.push(next);
|
|
7114
|
-
for (const
|
|
7505
|
+
for (const propertyName6 of next.propertyNames) seenProperties.add(propertyName6);
|
|
7115
7506
|
}
|
|
7116
7507
|
return group;
|
|
7117
7508
|
}
|
|
@@ -7119,19 +7510,19 @@ function declarationTerminator(context, declaration) {
|
|
|
7119
7510
|
return context.sourceCode.getText(declaration).trimEnd().endsWith(";") ? ";" : "";
|
|
7120
7511
|
}
|
|
7121
7512
|
function singlePropertyMessage(binding) {
|
|
7122
|
-
return `"${binding.propertyName}" is the only property bound from "${binding.sourceText}". Read "${binding.sourceText}.${binding.propertyName}" directly instead of creating a local binding. ${
|
|
7513
|
+
return `"${binding.propertyName}" is the only property bound from "${binding.sourceText}". Read "${binding.sourceText}.${binding.propertyName}" directly instead of creating a local binding. ${DOC7}`;
|
|
7123
7514
|
}
|
|
7124
7515
|
function groupMessage(bindings) {
|
|
7125
7516
|
const firstBinding = bindings[0];
|
|
7126
|
-
if (!firstBinding) return `Use one object destructuring declaration. ${
|
|
7517
|
+
if (!firstBinding) return `Use one object destructuring declaration. ${DOC7}`;
|
|
7127
7518
|
const names = bindings.map(({ localName }) => `"${localName}"`).join(", ");
|
|
7128
|
-
return `${names} are derived directly from properties of "${firstBinding.sourceText}". Use one object destructuring declaration. ${
|
|
7519
|
+
return `${names} are derived directly from properties of "${firstBinding.sourceText}". Use one object destructuring declaration. ${DOC7}`;
|
|
7129
7520
|
}
|
|
7130
7521
|
function repeatedDestructuringMessage(group) {
|
|
7131
7522
|
const first = group[0];
|
|
7132
|
-
if (!first) return `Combine repeated destructuring into one declaration. ${
|
|
7523
|
+
if (!first) return `Combine repeated destructuring into one declaration. ${DOC7}`;
|
|
7133
7524
|
const names = group.flatMap(({ localNames }) => localNames).map((name) => `"${name}"`).join(", ");
|
|
7134
|
-
return `${names} destructure the same source "${first.sourceText}" repeatedly. Combine them into one object destructuring declaration. ${
|
|
7525
|
+
return `${names} destructure the same source "${first.sourceText}" repeatedly. Combine them into one object destructuring declaration. ${DOC7}`;
|
|
7135
7526
|
}
|
|
7136
7527
|
var preferObjectDestructuringRule = {
|
|
7137
7528
|
meta: {
|
|
@@ -7165,9 +7556,9 @@ var preferObjectDestructuringRule = {
|
|
|
7165
7556
|
const { member: firstDirectMember } = firstDirectUsage;
|
|
7166
7557
|
const propertyNames = [...usage.propertyNames];
|
|
7167
7558
|
const missingPropertyNames = propertyNames.filter(
|
|
7168
|
-
(
|
|
7559
|
+
(propertyName6) => !usage.destructuring?.propertyNames.has(propertyName6)
|
|
7169
7560
|
);
|
|
7170
|
-
if (missingPropertyNames.some((
|
|
7561
|
+
if (missingPropertyNames.some((propertyName6) => hasBinding(context, firstDirectMember, propertyName6))) {
|
|
7171
7562
|
continue;
|
|
7172
7563
|
}
|
|
7173
7564
|
context.report({
|
|
@@ -7181,7 +7572,7 @@ var preferObjectDestructuringRule = {
|
|
|
7181
7572
|
return null;
|
|
7182
7573
|
}
|
|
7183
7574
|
const memberFixes = usage.directMembers.map(
|
|
7184
|
-
({ member, propertyName:
|
|
7575
|
+
({ member, propertyName: propertyName6 }) => fixer.replaceText(member, propertyName6)
|
|
7185
7576
|
);
|
|
7186
7577
|
if (usage.destructuring) {
|
|
7187
7578
|
if (missingPropertyNames.length === 0) return memberFixes;
|
|
@@ -7220,7 +7611,7 @@ ${indentation}`;
|
|
|
7220
7611
|
continue;
|
|
7221
7612
|
}
|
|
7222
7613
|
if (fromSameSource.length > 1) {
|
|
7223
|
-
const names = new Set(fromSameSource.map(({ propertyName:
|
|
7614
|
+
const names = new Set(fromSameSource.map(({ propertyName: propertyName6 }) => propertyName6));
|
|
7224
7615
|
if (names.size > 1) {
|
|
7225
7616
|
context.report({ node: binding.node, message: scopeUsageMessage(binding.sourceText, names) });
|
|
7226
7617
|
continue;
|
|
@@ -7249,7 +7640,7 @@ ${indentation}`;
|
|
|
7249
7640
|
const sourceText = context.sourceCode.getText(declarator.init);
|
|
7250
7641
|
context.report({
|
|
7251
7642
|
node: declarator.id,
|
|
7252
|
-
message: `"${sourceText}" is an enum. Keep enum member accesses qualified instead of destructuring it. ${
|
|
7643
|
+
message: `"${sourceText}" is an enum. Keep enum member accesses qualified instead of destructuring it. ${DOC7}`
|
|
7253
7644
|
});
|
|
7254
7645
|
}
|
|
7255
7646
|
recordDestructuringUsage(context, currentUsageScope(), node, isEnumValue);
|
|
@@ -7260,12 +7651,12 @@ ${indentation}`;
|
|
|
7260
7651
|
if (group.length <= 1) {
|
|
7261
7652
|
if (node.kind === "const" && selection.propertyNames.length === 1 && supportsSinglePropertySource(selection.source)) {
|
|
7262
7653
|
const declarator = node.declarations[0];
|
|
7263
|
-
const
|
|
7264
|
-
if (declarator &&
|
|
7654
|
+
const propertyName6 = selection.propertyNames[0];
|
|
7655
|
+
if (declarator && propertyName6) {
|
|
7265
7656
|
currentUsageScope()?.singleProperties.push({
|
|
7266
7657
|
node: declarator.id,
|
|
7267
7658
|
sourceText: selection.sourceText,
|
|
7268
|
-
propertyName:
|
|
7659
|
+
propertyName: propertyName6
|
|
7269
7660
|
});
|
|
7270
7661
|
}
|
|
7271
7662
|
}
|
|
@@ -7295,7 +7686,7 @@ ${indentation}`;
|
|
|
7295
7686
|
if (bindings.length === 0) return;
|
|
7296
7687
|
const firstBinding = bindings[0];
|
|
7297
7688
|
if (!firstBinding) return;
|
|
7298
|
-
const sameSourceBindings = bindings.length > 1 && bindings.length === node.declarations.length && bindings.every(({ sourceText }) => sourceText === firstBinding.sourceText) && new Set(bindings.map(({ propertyName:
|
|
7689
|
+
const sameSourceBindings = bindings.length > 1 && bindings.length === node.declarations.length && bindings.every(({ sourceText }) => sourceText === firstBinding.sourceText) && new Set(bindings.map(({ propertyName: propertyName6 }) => propertyName6)).size === bindings.length;
|
|
7299
7690
|
if (sameSourceBindings) {
|
|
7300
7691
|
context.report({
|
|
7301
7692
|
node,
|
|
@@ -7350,7 +7741,7 @@ ${indentation}`;
|
|
|
7350
7741
|
};
|
|
7351
7742
|
|
|
7352
7743
|
// eslint/rules/pure-function-extract.ts
|
|
7353
|
-
import
|
|
7744
|
+
import path49 from "path";
|
|
7354
7745
|
var ROUTE_HANDLER_EXPORT_NAMES = /* @__PURE__ */ new Set([
|
|
7355
7746
|
"GET",
|
|
7356
7747
|
"POST",
|
|
@@ -7415,12 +7806,12 @@ var pureFunctionExtractRule = {
|
|
|
7415
7806
|
},
|
|
7416
7807
|
create(context) {
|
|
7417
7808
|
const filename = context.filename;
|
|
7418
|
-
const isRouteFile =
|
|
7809
|
+
const isRouteFile = path49.basename(filename) === "route.ts";
|
|
7419
7810
|
const isComponentFile = filename.endsWith(".tsx") || filename.endsWith(".jsx");
|
|
7420
7811
|
const sourceRoot = sourceRootOf(context);
|
|
7421
|
-
const relative =
|
|
7812
|
+
const relative = path49.relative(sourceRoot, filename);
|
|
7422
7813
|
if (relative.startsWith("..")) return {};
|
|
7423
|
-
const segments = relative.split(
|
|
7814
|
+
const segments = relative.split(path49.sep);
|
|
7424
7815
|
const folders = segments.slice(0, -1);
|
|
7425
7816
|
const isHookSupportFile = folders.includes("hooks") && /\.(?:[cm]?[jt]s)$/.test(filename);
|
|
7426
7817
|
if (!isComponentFile && !isRouteFile && !isHookSupportFile) return {};
|
|
@@ -7480,15 +7871,15 @@ var pureFunctionExtractRule = {
|
|
|
7480
7871
|
};
|
|
7481
7872
|
|
|
7482
7873
|
// eslint/rules/repeated-numeric-value.ts
|
|
7483
|
-
import
|
|
7874
|
+
import path50 from "path";
|
|
7484
7875
|
function isNonProductionFile(file, sourceRoot) {
|
|
7485
|
-
const relative =
|
|
7486
|
-
const segments = relative.split(
|
|
7487
|
-
const basename =
|
|
7876
|
+
const relative = path50.relative(sourceRoot, file);
|
|
7877
|
+
const segments = relative.split(path50.sep);
|
|
7878
|
+
const basename = path50.basename(file);
|
|
7488
7879
|
return /\.(?:test|spec|mock)\.[^.]+$/.test(basename) || segments.some((segment) => segment === "__tests__" || segment === "__mocks__" || segment === "mocks");
|
|
7489
7880
|
}
|
|
7490
7881
|
function isCanonicalConstantFile(file, sourceRoot) {
|
|
7491
|
-
const segments =
|
|
7882
|
+
const segments = path50.relative(sourceRoot, file).split(path50.sep);
|
|
7492
7883
|
return segments.includes("constants") || segments[0] === "config";
|
|
7493
7884
|
}
|
|
7494
7885
|
function groupKey(literal) {
|
|
@@ -7504,7 +7895,7 @@ var repeatedNumericValueRule = {
|
|
|
7504
7895
|
},
|
|
7505
7896
|
create(context) {
|
|
7506
7897
|
const sourceRoot = sourceRootOf(context);
|
|
7507
|
-
const file =
|
|
7898
|
+
const file = path50.resolve(context.filename);
|
|
7508
7899
|
if (isNonProductionFile(file, sourceRoot) || isCanonicalConstantFile(file, sourceRoot)) return {};
|
|
7509
7900
|
const index = getProjectIndex(sourceRoot);
|
|
7510
7901
|
if (!index) return {};
|
|
@@ -7541,11 +7932,11 @@ var repeatedNumericValueRule = {
|
|
|
7541
7932
|
};
|
|
7542
7933
|
|
|
7543
7934
|
// eslint/rules/repeated-semantic-literal.ts
|
|
7544
|
-
import
|
|
7935
|
+
import path52 from "path";
|
|
7545
7936
|
|
|
7546
7937
|
// eslint/rules/imported-enum-literals.ts
|
|
7547
|
-
import
|
|
7548
|
-
import
|
|
7938
|
+
import path51 from "path";
|
|
7939
|
+
import ts12 from "typescript";
|
|
7549
7940
|
var columnMethods2 = /* @__PURE__ */ new Set([
|
|
7550
7941
|
"eq",
|
|
7551
7942
|
"neq",
|
|
@@ -7561,13 +7952,13 @@ var columnMethods2 = /* @__PURE__ */ new Set([
|
|
|
7561
7952
|
"filter",
|
|
7562
7953
|
"not"
|
|
7563
7954
|
]);
|
|
7564
|
-
function
|
|
7565
|
-
if (
|
|
7955
|
+
function memberName7(name) {
|
|
7956
|
+
if (ts12.isIdentifier(name) || ts12.isStringLiteral(name)) return name.text;
|
|
7566
7957
|
return void 0;
|
|
7567
7958
|
}
|
|
7568
7959
|
function isWithin3(root, file) {
|
|
7569
|
-
const relative =
|
|
7570
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
7960
|
+
const relative = path51.relative(root, file);
|
|
7961
|
+
return relative === "" || !relative.startsWith("..") && !path51.isAbsolute(relative);
|
|
7571
7962
|
}
|
|
7572
7963
|
function domainOf(name) {
|
|
7573
7964
|
if (name.endsWith("ColumnEnum")) return "column";
|
|
@@ -7577,23 +7968,23 @@ function domainOf(name) {
|
|
|
7577
7968
|
function importedEnums(file, checker, sourceRoot, importedNames) {
|
|
7578
7969
|
const matches = /* @__PURE__ */ new Map();
|
|
7579
7970
|
for (const statement of file.statements) {
|
|
7580
|
-
if (!
|
|
7971
|
+
if (!ts12.isImportDeclaration(statement) || !statement.importClause?.namedBindings || !ts12.isNamedImports(statement.importClause.namedBindings)) {
|
|
7581
7972
|
continue;
|
|
7582
7973
|
}
|
|
7583
7974
|
for (const specifier of statement.importClause.namedBindings.elements) {
|
|
7584
7975
|
if (!importedNames.has(specifier.name.text)) continue;
|
|
7585
7976
|
const symbol = checker.getSymbolAtLocation(specifier.name);
|
|
7586
7977
|
if (!symbol) continue;
|
|
7587
|
-
const resolved = symbol.flags ===
|
|
7978
|
+
const resolved = symbol.flags === ts12.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
7588
7979
|
for (const declaration of resolved.declarations ?? []) {
|
|
7589
|
-
if (!
|
|
7590
|
-
const declarationFile =
|
|
7980
|
+
if (!ts12.isEnumDeclaration(declaration)) continue;
|
|
7981
|
+
const declarationFile = path51.resolve(declaration.getSourceFile().fileName);
|
|
7591
7982
|
if (!isWithin3(sourceRoot, declarationFile)) continue;
|
|
7592
7983
|
const domain = domainOf(declaration.name.text);
|
|
7593
7984
|
if (!domain) continue;
|
|
7594
7985
|
for (const member of declaration.members) {
|
|
7595
|
-
if (!member.initializer || !
|
|
7596
|
-
const name =
|
|
7986
|
+
if (!member.initializer || !ts12.isStringLiteral(member.initializer)) continue;
|
|
7987
|
+
const name = memberName7(member.name);
|
|
7597
7988
|
if (!name) continue;
|
|
7598
7989
|
const entries = matches.get(member.initializer.text) ?? [];
|
|
7599
7990
|
entries.push({
|
|
@@ -7609,25 +8000,25 @@ function importedEnums(file, checker, sourceRoot, importedNames) {
|
|
|
7609
8000
|
return matches;
|
|
7610
8001
|
}
|
|
7611
8002
|
function isPathname2(node) {
|
|
7612
|
-
return
|
|
8003
|
+
return ts12.isPropertyAccessExpression(node) && node.name.text === "pathname";
|
|
7613
8004
|
}
|
|
7614
8005
|
function domainForUse(node) {
|
|
7615
8006
|
const parent = node.parent;
|
|
7616
|
-
if (
|
|
8007
|
+
if (ts12.isPropertyAssignment(parent) && parent.initializer === node && memberName7(parent.name) === "path") {
|
|
7617
8008
|
return "route";
|
|
7618
8009
|
}
|
|
7619
|
-
if (
|
|
8010
|
+
if (ts12.isCallExpression(parent) && parent.arguments[0] === node && ts12.isPropertyAccessExpression(parent.expression)) {
|
|
7620
8011
|
const { expression, name } = parent.expression;
|
|
7621
8012
|
if (columnMethods2.has(name.text)) return "column";
|
|
7622
8013
|
if (name.text === "startsWith" && isPathname2(expression)) return "route";
|
|
7623
8014
|
}
|
|
7624
|
-
if (
|
|
8015
|
+
if (ts12.isBinaryExpression(parent) && (parent.operatorToken.kind === ts12.SyntaxKind.EqualsEqualsEqualsToken || parent.operatorToken.kind === ts12.SyntaxKind.ExclamationEqualsEqualsToken) && (parent.left === node && isPathname2(parent.right) || parent.right === node && isPathname2(parent.left))) {
|
|
7625
8016
|
return "route";
|
|
7626
8017
|
}
|
|
7627
8018
|
return void 0;
|
|
7628
8019
|
}
|
|
7629
8020
|
function importedEnumLiteralUses(context, root) {
|
|
7630
|
-
const filename =
|
|
8021
|
+
const filename = path51.resolve(context.filename);
|
|
7631
8022
|
if (!isWithin3(root, filename)) return [];
|
|
7632
8023
|
const services = typedParserServices(context.sourceCode.parserServices);
|
|
7633
8024
|
if (!services) return [];
|
|
@@ -7643,7 +8034,7 @@ function importedEnumLiteralUses(context, root) {
|
|
|
7643
8034
|
if (matches.size === 0) return [];
|
|
7644
8035
|
const uses = [];
|
|
7645
8036
|
const visit = (node) => {
|
|
7646
|
-
if (
|
|
8037
|
+
if (ts12.isStringLiteral(node)) {
|
|
7647
8038
|
const domain = domainForUse(node);
|
|
7648
8039
|
const candidates = matches.get(node.text)?.filter((entry) => entry.domain === domain) ?? [];
|
|
7649
8040
|
if (candidates.length === 1) {
|
|
@@ -7660,14 +8051,14 @@ function importedEnumLiteralUses(context, root) {
|
|
|
7660
8051
|
}
|
|
7661
8052
|
}
|
|
7662
8053
|
}
|
|
7663
|
-
|
|
8054
|
+
ts12.forEachChild(node, visit);
|
|
7664
8055
|
};
|
|
7665
8056
|
visit(file);
|
|
7666
8057
|
return uses;
|
|
7667
8058
|
}
|
|
7668
8059
|
|
|
7669
8060
|
// eslint/rules/repeated-semantic-literal.ts
|
|
7670
|
-
var
|
|
8061
|
+
var DOC8 = "See docs/next-codebase-guide/rules/constants-rule.md";
|
|
7671
8062
|
var closedDomainFamilies = /* @__PURE__ */ new Set(["api-route", "event", "storage"]);
|
|
7672
8063
|
function canonicalMatches(use, canonical, sourceRoot) {
|
|
7673
8064
|
if (use.kind !== canonical.kind || use.value !== canonical.value) return false;
|
|
@@ -7681,7 +8072,7 @@ function canonicalMatches(use, canonical, sourceRoot) {
|
|
|
7681
8072
|
const semanticName2 = use.family.split(":")[1];
|
|
7682
8073
|
if (!semanticName2 || !name.toLowerCase().includes(semanticName2.toLowerCase())) return false;
|
|
7683
8074
|
const location = featureOf(canonical.file, sourceRoot);
|
|
7684
|
-
return location === featureOf(use.file, sourceRoot) ||
|
|
8075
|
+
return location === featureOf(use.file, sourceRoot) || path52.relative(sourceRoot, canonical.file).split(path52.sep)[0] === "constants";
|
|
7685
8076
|
}
|
|
7686
8077
|
return false;
|
|
7687
8078
|
}
|
|
@@ -7695,14 +8086,14 @@ function messageFor(use, matches, duplicateRouteDomains, existingRouteEnum, root
|
|
|
7695
8086
|
const count = new Set(matches.map((match) => match.file)).size;
|
|
7696
8087
|
const kind = use.kind === "string" ? "string" : "numeric";
|
|
7697
8088
|
if (use.family === "api-route" && existingRouteEnum?.owner) {
|
|
7698
|
-
const location =
|
|
7699
|
-
return `The route ${formatValue(use)} repeats; add a member to existing ${existingRouteEnum.owner} in src/${location} and reuse it. ${
|
|
8089
|
+
const location = path52.relative(root, existingRouteEnum.file).replaceAll(path52.sep, "/");
|
|
8090
|
+
return `The route ${formatValue(use)} repeats; add a member to existing ${existingRouteEnum.owner} in src/${location} and reuse it. ${DOC8}`;
|
|
7700
8091
|
}
|
|
7701
8092
|
if (count === 1) {
|
|
7702
|
-
return `The ${kind} literal ${formatValue(use)} repeats in the same semantic role in this file. Extract a file-local const. ${
|
|
8093
|
+
return `The ${kind} literal ${formatValue(use)} repeats in the same semantic role in this file. Extract a file-local const. ${DOC8}`;
|
|
7703
8094
|
}
|
|
7704
8095
|
const placement = use.family === "api-route" && duplicateRouteDomains.has(use.role) ? "a shared enum for this closed route domain" : "one shared const";
|
|
7705
|
-
return `The ${kind} literal ${formatValue(use)} repeats in ${String(count)} production files for the same semantic role. Extract ${placement} at the consumers' CCF and import it. ${
|
|
8096
|
+
return `The ${kind} literal ${formatValue(use)} repeats in ${String(count)} production files for the same semantic role. Extract ${placement} at the consumers' CCF and import it. ${DOC8}`;
|
|
7706
8097
|
}
|
|
7707
8098
|
var repeatedSemanticLiteralRule = {
|
|
7708
8099
|
meta: {
|
|
@@ -7714,7 +8105,7 @@ var repeatedSemanticLiteralRule = {
|
|
|
7714
8105
|
},
|
|
7715
8106
|
create(context) {
|
|
7716
8107
|
const root = sourceRootOf(context);
|
|
7717
|
-
const file =
|
|
8108
|
+
const file = path52.resolve(context.filename);
|
|
7718
8109
|
if (!isProductionSource(file, root)) return {};
|
|
7719
8110
|
const project = getProjectIndex(root);
|
|
7720
8111
|
if (!project?.modules.has(file)) return {};
|
|
@@ -7759,11 +8150,11 @@ var repeatedSemanticLiteralRule = {
|
|
|
7759
8150
|
return {
|
|
7760
8151
|
Program(node) {
|
|
7761
8152
|
for (const use of imported) {
|
|
7762
|
-
const relative =
|
|
8153
|
+
const relative = path52.relative(root, use.sourceFile).replaceAll(path52.sep, "/");
|
|
7763
8154
|
context.report({
|
|
7764
8155
|
node,
|
|
7765
8156
|
loc: { line: use.line, column: use.column },
|
|
7766
|
-
message: `Reuse ${use.reference} from src/${relative} instead of raw ${JSON.stringify(use.value)}. ${
|
|
8157
|
+
message: `Reuse ${use.reference} from src/${relative} instead of raw ${JSON.stringify(use.value)}. ${DOC8}`
|
|
7767
8158
|
});
|
|
7768
8159
|
}
|
|
7769
8160
|
for (const use of current) {
|
|
@@ -7774,11 +8165,11 @@ var repeatedSemanticLiteralRule = {
|
|
|
7774
8165
|
if (candidates.length === 1) {
|
|
7775
8166
|
const canonical = candidates[0];
|
|
7776
8167
|
if (!canonical) continue;
|
|
7777
|
-
const relative =
|
|
8168
|
+
const relative = path52.relative(root, canonical.file).replaceAll(path52.sep, "/");
|
|
7778
8169
|
context.report({
|
|
7779
8170
|
node,
|
|
7780
8171
|
loc: { line: use.line, column: use.column },
|
|
7781
|
-
message: `Reuse ${canonicalName(canonical)} from src/${relative} instead of raw ${formatValue(use)}. ${
|
|
8172
|
+
message: `Reuse ${canonicalName(canonical)} from src/${relative} instead of raw ${formatValue(use)}. ${DOC8}`
|
|
7782
8173
|
});
|
|
7783
8174
|
continue;
|
|
7784
8175
|
}
|
|
@@ -7787,11 +8178,11 @@ var repeatedSemanticLiteralRule = {
|
|
|
7787
8178
|
const peers = groups.get(key) ?? [];
|
|
7788
8179
|
if (peers.length < 2) {
|
|
7789
8180
|
if (use.family === "api-route" && existingRouteEnum?.owner) {
|
|
7790
|
-
const location =
|
|
8181
|
+
const location = path52.relative(root, existingRouteEnum.file).replaceAll(path52.sep, "/");
|
|
7791
8182
|
context.report({
|
|
7792
8183
|
node,
|
|
7793
8184
|
loc: { line: use.line, column: use.column },
|
|
7794
|
-
message: `The route ${formatValue(use)} belongs to existing ${existingRouteEnum.owner}; add a member in src/${location} and reuse it. ${
|
|
8185
|
+
message: `The route ${formatValue(use)} belongs to existing ${existingRouteEnum.owner}; add a member in src/${location} and reuse it. ${DOC8}`
|
|
7795
8186
|
});
|
|
7796
8187
|
continue;
|
|
7797
8188
|
}
|
|
@@ -7800,7 +8191,7 @@ var repeatedSemanticLiteralRule = {
|
|
|
7800
8191
|
context.report({
|
|
7801
8192
|
node,
|
|
7802
8193
|
loc: { line: use.line, column: use.column },
|
|
7803
|
-
message: `The string literal ${formatValue(use)} is one of ${String(domain.size)} values in a closed ${use.family} domain. Declare the domain in a shared enum at the consumers' CCF and reuse it. ${
|
|
8194
|
+
message: `The string literal ${formatValue(use)} is one of ${String(domain.size)} values in a closed ${use.family} domain. Declare the domain in a shared enum at the consumers' CCF and reuse it. ${DOC8}`
|
|
7804
8195
|
});
|
|
7805
8196
|
}
|
|
7806
8197
|
continue;
|
|
@@ -7999,7 +8390,7 @@ var repeatedStructureRule = {
|
|
|
7999
8390
|
|
|
8000
8391
|
// eslint/rules/require-barrel-star-exports.ts
|
|
8001
8392
|
import fs5 from "fs";
|
|
8002
|
-
import
|
|
8393
|
+
import path53 from "path";
|
|
8003
8394
|
var SUPPORT_FOLDERS3 = /* @__PURE__ */ new Set(["constants", "types", "schemas"]);
|
|
8004
8395
|
var INDEX_NAMES = /* @__PURE__ */ new Set(["index.ts", "index.tsx", "index.mts", "index.cts"]);
|
|
8005
8396
|
var MODULE_EXTENSIONS3 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
@@ -8007,9 +8398,9 @@ function resolveSiblingModule(indexFile, specifier) {
|
|
|
8007
8398
|
if (!specifier.startsWith("./")) return void 0;
|
|
8008
8399
|
const relative = specifier.slice(2);
|
|
8009
8400
|
if (!relative || relative.includes("/")) return void 0;
|
|
8010
|
-
const directory =
|
|
8011
|
-
const direct =
|
|
8012
|
-
const candidates =
|
|
8401
|
+
const directory = path53.dirname(indexFile);
|
|
8402
|
+
const direct = path53.resolve(directory, relative);
|
|
8403
|
+
const candidates = path53.extname(direct) ? [direct] : MODULE_EXTENSIONS3.map((extension) => `${direct}${extension}`);
|
|
8013
8404
|
return candidates.find((candidate) => fs5.existsSync(candidate) && fs5.statSync(candidate).isFile());
|
|
8014
8405
|
}
|
|
8015
8406
|
var requireBarrelStarExportsRule = {
|
|
@@ -8022,9 +8413,9 @@ var requireBarrelStarExportsRule = {
|
|
|
8022
8413
|
fixable: "code"
|
|
8023
8414
|
},
|
|
8024
8415
|
create(context) {
|
|
8025
|
-
const filename =
|
|
8026
|
-
if (!INDEX_NAMES.has(
|
|
8027
|
-
if (!SUPPORT_FOLDERS3.has(
|
|
8416
|
+
const filename = path53.resolve(context.filename);
|
|
8417
|
+
if (!INDEX_NAMES.has(path53.basename(filename))) return {};
|
|
8418
|
+
if (!SUPPORT_FOLDERS3.has(path53.basename(path53.dirname(filename)))) return {};
|
|
8028
8419
|
return {
|
|
8029
8420
|
ExportNamedDeclaration(node) {
|
|
8030
8421
|
const sourceNode = node.source;
|
|
@@ -8077,7 +8468,7 @@ var requireBarrelStarExportsRule = {
|
|
|
8077
8468
|
};
|
|
8078
8469
|
|
|
8079
8470
|
// eslint/rules/root-support-placement.ts
|
|
8080
|
-
import
|
|
8471
|
+
import path54 from "path";
|
|
8081
8472
|
function isSupportFolder(value) {
|
|
8082
8473
|
return value === "utils" || value === "types" || value === "schemas" || value === "constants";
|
|
8083
8474
|
}
|
|
@@ -8110,7 +8501,7 @@ var rootSupportPlacementRule = {
|
|
|
8110
8501
|
},
|
|
8111
8502
|
create(context) {
|
|
8112
8503
|
const sourceRoot = sourceRootOf(context);
|
|
8113
|
-
const file =
|
|
8504
|
+
const file = path54.resolve(context.filename);
|
|
8114
8505
|
const segments = segmentsOf(file, sourceRoot);
|
|
8115
8506
|
const folderSegments = folderSegmentsOf(file, sourceRoot);
|
|
8116
8507
|
const supportFolder = folderSegments[folderSegments.length - 1];
|
|
@@ -8156,8 +8547,104 @@ var rootSupportPlacementRule = {
|
|
|
8156
8547
|
};
|
|
8157
8548
|
|
|
8158
8549
|
// eslint/rules/route-handler-shape.ts
|
|
8159
|
-
import
|
|
8160
|
-
import
|
|
8550
|
+
import path56 from "path";
|
|
8551
|
+
import ts13 from "typescript";
|
|
8552
|
+
|
|
8553
|
+
// eslint/rules/route-single-use-delegation.ts
|
|
8554
|
+
import path55 from "path";
|
|
8555
|
+
function responseCall(expression) {
|
|
8556
|
+
if (!expression) return void 0;
|
|
8557
|
+
if (expression.type === "AwaitExpression") return responseCall(expression.argument);
|
|
8558
|
+
if (expression.type === "CallExpression" && expression.callee.type === "Identifier") return expression;
|
|
8559
|
+
if (expression.type !== "ObjectExpression") return void 0;
|
|
8560
|
+
const dataProperties = expression.properties.filter(
|
|
8561
|
+
(property) => property.type === "Property" && !property.computed && (property.key.type === "Identifier" && property.key.name === "data" || property.key.type === "Literal" && property.key.value === "data")
|
|
8562
|
+
);
|
|
8563
|
+
if (dataProperties.length !== 1) return void 0;
|
|
8564
|
+
const otherProperties = expression.properties.filter((property) => !dataProperties.includes(property));
|
|
8565
|
+
if (otherProperties.some(
|
|
8566
|
+
(property) => property.type !== "Property" || property.value.type !== "Literal" || property.computed
|
|
8567
|
+
)) {
|
|
8568
|
+
return void 0;
|
|
8569
|
+
}
|
|
8570
|
+
return responseCall(dataProperties[0]?.type === "Property" ? dataProperties[0].value : void 0);
|
|
8571
|
+
}
|
|
8572
|
+
function soleDelegation(handler) {
|
|
8573
|
+
if (handler.body.type !== "BlockStatement") return responseCall(handler.body);
|
|
8574
|
+
const statements = handler.body.body;
|
|
8575
|
+
if (statements.length === 1 && statements[0]?.type === "ReturnStatement") {
|
|
8576
|
+
return responseCall(statements[0].argument);
|
|
8577
|
+
}
|
|
8578
|
+
const [declaration, returned] = statements;
|
|
8579
|
+
if (statements.length !== 2 || declaration?.type !== "VariableDeclaration" || declaration.declarations.length !== 1 || returned?.type !== "ReturnStatement") {
|
|
8580
|
+
return void 0;
|
|
8581
|
+
}
|
|
8582
|
+
const variable = declaration.declarations[0];
|
|
8583
|
+
if (variable?.id.type !== "Identifier") return void 0;
|
|
8584
|
+
const call = responseCall(variable.init);
|
|
8585
|
+
if (!call || !returned.argument) return void 0;
|
|
8586
|
+
if (returned.argument.type === "Identifier" && returned.argument.name === variable.id.name) return call;
|
|
8587
|
+
if (returned.argument.type !== "ObjectExpression") return void 0;
|
|
8588
|
+
const properties = returned.argument.properties;
|
|
8589
|
+
if (properties.length !== 1 || properties[0]?.type !== "Property") return void 0;
|
|
8590
|
+
const property = properties[0];
|
|
8591
|
+
const key = property.key;
|
|
8592
|
+
const isData = !property.computed && (key.type === "Identifier" && key.name === "data" || key.type === "Literal" && key.value === "data");
|
|
8593
|
+
return isData && property.value.type === "Identifier" && property.value.name === variable.id.name ? call : void 0;
|
|
8594
|
+
}
|
|
8595
|
+
function isTestFile2(file) {
|
|
8596
|
+
return /(?:\.test|\.spec)\.[cm]?[jt]sx?$/.test(file) || path55.normalize(file).split(path55.sep).includes("__tests__");
|
|
8597
|
+
}
|
|
8598
|
+
function functionSource(index, file, name, sourceRoot, visited = /* @__PURE__ */ new Set()) {
|
|
8599
|
+
if (visited.has(file)) return void 0;
|
|
8600
|
+
visited.add(file);
|
|
8601
|
+
const module = index.modules.get(file);
|
|
8602
|
+
if (!module) return void 0;
|
|
8603
|
+
if (module.exports.some((entry) => entry.name === name && entry.kind === "function")) return file;
|
|
8604
|
+
if (!module.exports.some((entry) => entry.name === name) && !module.reexports.some((entry) => entry.names.length === 0)) {
|
|
8605
|
+
return void 0;
|
|
8606
|
+
}
|
|
8607
|
+
for (const entry of module.reexports) {
|
|
8608
|
+
if (entry.names.length > 0 && !entry.names.includes(name)) continue;
|
|
8609
|
+
const target = resolveSpecifier(file, entry.specifier, sourceRoot);
|
|
8610
|
+
if (!target) continue;
|
|
8611
|
+
const original = functionSource(index, target, name, sourceRoot, visited);
|
|
8612
|
+
if (original) return original;
|
|
8613
|
+
}
|
|
8614
|
+
return void 0;
|
|
8615
|
+
}
|
|
8616
|
+
function singleUseResponseDelegate(context, handler) {
|
|
8617
|
+
const call = soleDelegation(handler);
|
|
8618
|
+
if (call?.callee.type !== "Identifier") return void 0;
|
|
8619
|
+
const name = call.callee.name;
|
|
8620
|
+
const sourceRoot = sourceRootOf(context);
|
|
8621
|
+
const index = getProjectIndex(sourceRoot);
|
|
8622
|
+
if (!index) return void 0;
|
|
8623
|
+
for (const statement of context.sourceCode.ast.body) {
|
|
8624
|
+
if (statement.type !== "ImportDeclaration" || typeof statement.source.value !== "string") continue;
|
|
8625
|
+
const target = resolveSpecifier(context.filename, statement.source.value, sourceRoot);
|
|
8626
|
+
if (target === void 0 || target === context.filename) continue;
|
|
8627
|
+
for (const specifier of statement.specifiers) {
|
|
8628
|
+
if (specifier.type !== "ImportSpecifier" || specifier.local.name !== name) continue;
|
|
8629
|
+
const original = specifier.imported.type === "Identifier" ? specifier.imported.name : String(specifier.imported.value);
|
|
8630
|
+
const source = functionSource(index, target, original, sourceRoot);
|
|
8631
|
+
if (!source) continue;
|
|
8632
|
+
const bindings = context.sourceCode.getDeclaredVariables(specifier);
|
|
8633
|
+
if (!bindings.some((binding) => binding.references.length === 1)) continue;
|
|
8634
|
+
const consumers = index.symbolConsumers.get(symbolKey(source, original));
|
|
8635
|
+
if (!consumers?.has(context.filename)) continue;
|
|
8636
|
+
const activeConsumers = [...consumers].filter((consumer) => {
|
|
8637
|
+
if (isTestFile2(consumer)) return false;
|
|
8638
|
+
const module = index.modules.get(consumer);
|
|
8639
|
+
return !(module && module.reexports.length > 0 && module.imports.length === module.reexports.length && module.exports.every((entry) => entry.kind === "other"));
|
|
8640
|
+
});
|
|
8641
|
+
if (activeConsumers.length === 1 && activeConsumers[0] === context.filename) return original;
|
|
8642
|
+
}
|
|
8643
|
+
}
|
|
8644
|
+
return void 0;
|
|
8645
|
+
}
|
|
8646
|
+
|
|
8647
|
+
// eslint/rules/route-handler-shape.ts
|
|
8161
8648
|
var HTTP_METHODS2 = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
8162
8649
|
var REQUIRED_BOUNDARY = "withResponse";
|
|
8163
8650
|
function isFunctionLike(node) {
|
|
@@ -8175,33 +8662,33 @@ function findHandler(node) {
|
|
|
8175
8662
|
return void 0;
|
|
8176
8663
|
}
|
|
8177
8664
|
function isLoop(node) {
|
|
8178
|
-
return
|
|
8665
|
+
return ts13.isForStatement(node) || ts13.isForOfStatement(node) || ts13.isForInStatement(node) || ts13.isWhileStatement(node) || ts13.isDoStatement(node);
|
|
8179
8666
|
}
|
|
8180
8667
|
function isFunctionBoundary(node) {
|
|
8181
|
-
return
|
|
8668
|
+
return ts13.isFunctionExpression(node) || ts13.isArrowFunction(node) || ts13.isFunctionDeclaration(node);
|
|
8182
8669
|
}
|
|
8183
8670
|
function analyzeHandlerBody(body, sourceText) {
|
|
8184
8671
|
const start = body.range?.[0] ?? 0;
|
|
8185
8672
|
const end = body.range?.[1] ?? sourceText.length;
|
|
8186
|
-
const sourceFile =
|
|
8673
|
+
const sourceFile = ts13.createSourceFile(
|
|
8187
8674
|
"route.ts",
|
|
8188
8675
|
sourceText.slice(start, end),
|
|
8189
|
-
|
|
8676
|
+
ts13.ScriptTarget.Latest,
|
|
8190
8677
|
true,
|
|
8191
|
-
|
|
8678
|
+
ts13.ScriptKind.TS
|
|
8192
8679
|
);
|
|
8193
8680
|
const kinds = /* @__PURE__ */ new Set();
|
|
8194
8681
|
const calledNames = /* @__PURE__ */ new Set();
|
|
8195
8682
|
const visit = (node) => {
|
|
8196
|
-
if (
|
|
8683
|
+
if (ts13.isTryStatement(node)) kinds.add("try");
|
|
8197
8684
|
if (isLoop(node)) kinds.add("loop");
|
|
8198
|
-
if (
|
|
8199
|
-
if (
|
|
8685
|
+
if (ts13.isIfStatement(node)) kinds.add("if");
|
|
8686
|
+
if (ts13.isCallExpression(node) && ts13.isPropertyAccessExpression(node.expression) && node.expression.name.text === "map") {
|
|
8200
8687
|
kinds.add("map");
|
|
8201
8688
|
}
|
|
8202
|
-
if (
|
|
8689
|
+
if (ts13.isCallExpression(node) && ts13.isIdentifier(node.expression)) calledNames.add(node.expression.text);
|
|
8203
8690
|
if (isFunctionBoundary(node)) return;
|
|
8204
|
-
|
|
8691
|
+
ts13.forEachChild(node, visit);
|
|
8205
8692
|
};
|
|
8206
8693
|
visit(sourceFile);
|
|
8207
8694
|
return { kinds, calledNames };
|
|
@@ -8241,7 +8728,7 @@ var routeHandlerShapeRule = {
|
|
|
8241
8728
|
}
|
|
8242
8729
|
},
|
|
8243
8730
|
create(context) {
|
|
8244
|
-
if (
|
|
8731
|
+
if (path56.basename(context.filename) !== "route.ts") return {};
|
|
8245
8732
|
const sourceText = context.sourceCode.text;
|
|
8246
8733
|
function reportUnwrapped(node, name) {
|
|
8247
8734
|
context.report({
|
|
@@ -8264,6 +8751,13 @@ var routeHandlerShapeRule = {
|
|
|
8264
8751
|
});
|
|
8265
8752
|
return;
|
|
8266
8753
|
}
|
|
8754
|
+
const singleUseDelegate = singleUseResponseDelegate(context, handler);
|
|
8755
|
+
if (singleUseDelegate) {
|
|
8756
|
+
context.report({
|
|
8757
|
+
node,
|
|
8758
|
+
message: `Handler "${name}" delegates its entire response to single-use utility "${singleUseDelegate}"; inline its workflow in route.ts. See docs/next-codebase-guide/rules/route-handler-rule.md`
|
|
8759
|
+
});
|
|
8760
|
+
}
|
|
8267
8761
|
const { kinds, calledNames } = analyzeHandlerBody(handler.body, sourceText);
|
|
8268
8762
|
for (const kind of kinds) {
|
|
8269
8763
|
context.report({
|
|
@@ -8300,7 +8794,7 @@ var routeHandlerShapeRule = {
|
|
|
8300
8794
|
};
|
|
8301
8795
|
|
|
8302
8796
|
// eslint/rules/schema-casing.ts
|
|
8303
|
-
import
|
|
8797
|
+
import path57 from "path";
|
|
8304
8798
|
function isCamelCase(name) {
|
|
8305
8799
|
return /^[a-z][a-zA-Z0-9]*$/.test(name);
|
|
8306
8800
|
}
|
|
@@ -8328,9 +8822,9 @@ var schemaCasingRule = {
|
|
|
8328
8822
|
}
|
|
8329
8823
|
},
|
|
8330
8824
|
create(context) {
|
|
8331
|
-
const filename =
|
|
8825
|
+
const filename = path57.resolve(context.filename);
|
|
8332
8826
|
const sourceRoot = sourceRootOf(context);
|
|
8333
|
-
if (!filename.startsWith(sourceRoot +
|
|
8827
|
+
if (!filename.startsWith(sourceRoot + path57.sep)) return {};
|
|
8334
8828
|
let zodLocalName;
|
|
8335
8829
|
return {
|
|
8336
8830
|
ImportDeclaration(node) {
|
|
@@ -8362,39 +8856,39 @@ var schemaCasingRule = {
|
|
|
8362
8856
|
};
|
|
8363
8857
|
|
|
8364
8858
|
// eslint/rules/sole-state-owner.ts
|
|
8365
|
-
import
|
|
8366
|
-
import
|
|
8859
|
+
import path58 from "path";
|
|
8860
|
+
import ts14 from "typescript";
|
|
8367
8861
|
function findStateHooks(node) {
|
|
8368
8862
|
const hooks = [];
|
|
8369
8863
|
const visit = (child) => {
|
|
8370
|
-
if (
|
|
8371
|
-
if (
|
|
8864
|
+
if (ts14.isCallExpression(child) && ts14.isIdentifier(child.expression) && child.expression.text === "useState") {
|
|
8865
|
+
if (ts14.isVariableDeclaration(child.parent)) {
|
|
8372
8866
|
const { name } = child.parent;
|
|
8373
|
-
if (
|
|
8867
|
+
if (ts14.isArrayBindingPattern(name) && name.elements.length >= 2) {
|
|
8374
8868
|
const value = name.elements[0];
|
|
8375
8869
|
const updater = name.elements[1];
|
|
8376
|
-
if (value && updater &&
|
|
8870
|
+
if (value && updater && ts14.isBindingElement(value) && ts14.isBindingElement(updater)) {
|
|
8377
8871
|
const valueName = value.name;
|
|
8378
8872
|
const updaterName = updater.name;
|
|
8379
|
-
if (
|
|
8873
|
+
if (ts14.isIdentifier(valueName) && ts14.isIdentifier(updaterName)) {
|
|
8380
8874
|
hooks.push({ value: valueName.text, updater: updaterName.text });
|
|
8381
8875
|
}
|
|
8382
8876
|
}
|
|
8383
8877
|
}
|
|
8384
8878
|
}
|
|
8385
8879
|
}
|
|
8386
|
-
|
|
8880
|
+
ts14.forEachChild(child, visit);
|
|
8387
8881
|
};
|
|
8388
8882
|
visit(node);
|
|
8389
8883
|
return hooks;
|
|
8390
8884
|
}
|
|
8391
8885
|
function isHookUsage(node, hook) {
|
|
8392
|
-
if (
|
|
8886
|
+
if (ts14.isCallExpression(node) && ts14.isIdentifier(node.expression) && node.expression.text === hook.updater) {
|
|
8393
8887
|
return "updater";
|
|
8394
8888
|
}
|
|
8395
|
-
if (
|
|
8889
|
+
if (ts14.isIdentifier(node) && node.text === hook.value) {
|
|
8396
8890
|
const parent = node.parent;
|
|
8397
|
-
if (
|
|
8891
|
+
if (ts14.isBindingElement(parent) || ts14.isPropertyAccessExpression(parent) || ts14.isShorthandPropertyAssignment(parent)) {
|
|
8398
8892
|
return void 0;
|
|
8399
8893
|
}
|
|
8400
8894
|
return "value";
|
|
@@ -8404,16 +8898,16 @@ function isHookUsage(node, hook) {
|
|
|
8404
8898
|
function topLevelJsxChildren(initial) {
|
|
8405
8899
|
if (!initial) return void 0;
|
|
8406
8900
|
let expression = initial;
|
|
8407
|
-
while (
|
|
8408
|
-
if (
|
|
8901
|
+
while (ts14.isParenthesizedExpression(expression)) expression = expression.expression;
|
|
8902
|
+
if (ts14.isJsxFragment(expression)) {
|
|
8409
8903
|
const children = expression.children.filter(
|
|
8410
|
-
(c) => !
|
|
8904
|
+
(c) => !ts14.isJsxText(c) && !ts14.isJsxSpreadAttribute(c)
|
|
8411
8905
|
);
|
|
8412
8906
|
return { root: expression, children };
|
|
8413
8907
|
}
|
|
8414
|
-
if (
|
|
8908
|
+
if (ts14.isJsxElement(expression)) {
|
|
8415
8909
|
const children = expression.children.filter(
|
|
8416
|
-
(c) => !
|
|
8910
|
+
(c) => !ts14.isJsxText(c) && !ts14.isJsxSpreadAttribute(c)
|
|
8417
8911
|
);
|
|
8418
8912
|
return { root: expression, children };
|
|
8419
8913
|
}
|
|
@@ -8427,8 +8921,8 @@ function collectUsesIn(child, hook) {
|
|
|
8427
8921
|
positions.push(node);
|
|
8428
8922
|
count += 1;
|
|
8429
8923
|
}
|
|
8430
|
-
if (
|
|
8431
|
-
|
|
8924
|
+
if (ts14.isFunctionDeclaration(node) || ts14.isClassDeclaration(node)) return;
|
|
8925
|
+
ts14.forEachChild(node, visit);
|
|
8432
8926
|
};
|
|
8433
8927
|
visit(child);
|
|
8434
8928
|
return { positions, count };
|
|
@@ -8442,7 +8936,7 @@ var soleStateOwnerRule = {
|
|
|
8442
8936
|
}
|
|
8443
8937
|
},
|
|
8444
8938
|
create(context) {
|
|
8445
|
-
const filename =
|
|
8939
|
+
const filename = path58.resolve(context.filename);
|
|
8446
8940
|
if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
|
|
8447
8941
|
const text = context.sourceCode.text;
|
|
8448
8942
|
const components = parseComponentInfo(text, filename);
|
|
@@ -8467,18 +8961,18 @@ var soleStateOwnerRule = {
|
|
|
8467
8961
|
}
|
|
8468
8962
|
};
|
|
8469
8963
|
function analyzeSoleOwner(declaration, hook) {
|
|
8470
|
-
const body =
|
|
8471
|
-
if (!body || !
|
|
8964
|
+
const body = ts14.isFunctionDeclaration(declaration) ? declaration.body : void 0;
|
|
8965
|
+
if (!body || !ts14.isBlock(body)) return void 0;
|
|
8472
8966
|
const returns = [];
|
|
8473
8967
|
const visit = (node) => {
|
|
8474
|
-
if (node !== body && (
|
|
8475
|
-
if (
|
|
8476
|
-
|
|
8968
|
+
if (node !== body && (ts14.isFunctionLike(node) || ts14.isClassLike(node))) return;
|
|
8969
|
+
if (ts14.isReturnStatement(node)) returns.push(node);
|
|
8970
|
+
ts14.forEachChild(node, visit);
|
|
8477
8971
|
};
|
|
8478
8972
|
visit(body);
|
|
8479
8973
|
if (returns.length !== 1) return void 0;
|
|
8480
8974
|
const single = returns[0];
|
|
8481
|
-
if (!single?.expression || !
|
|
8975
|
+
if (!single?.expression || !ts14.isExpression(single.expression)) return void 0;
|
|
8482
8976
|
const returnExpression = single.expression;
|
|
8483
8977
|
const root = topLevelJsxChildren(returnExpression);
|
|
8484
8978
|
if (!root || root.children.length === 0) return void 0;
|
|
@@ -8501,11 +8995,11 @@ function usesOutsideJsx(declaration, hook, children) {
|
|
|
8501
8995
|
let outside = false;
|
|
8502
8996
|
const visit = (node) => {
|
|
8503
8997
|
if (outside) return;
|
|
8504
|
-
if (node !== declaration && (
|
|
8998
|
+
if (node !== declaration && (ts14.isFunctionDeclaration(node) || ts14.isClassDeclaration(node))) return;
|
|
8505
8999
|
if (isHookUsage(node, hook)) {
|
|
8506
9000
|
let current = node;
|
|
8507
9001
|
let isInJsxChild = false;
|
|
8508
|
-
while (!
|
|
9002
|
+
while (!ts14.isSourceFile(current)) {
|
|
8509
9003
|
if (children.includes(current)) {
|
|
8510
9004
|
isInJsxChild = true;
|
|
8511
9005
|
break;
|
|
@@ -8514,14 +9008,14 @@ function usesOutsideJsx(declaration, hook, children) {
|
|
|
8514
9008
|
}
|
|
8515
9009
|
if (!isInJsxChild) outside = true;
|
|
8516
9010
|
}
|
|
8517
|
-
|
|
9011
|
+
ts14.forEachChild(node, visit);
|
|
8518
9012
|
};
|
|
8519
9013
|
visit(declaration);
|
|
8520
9014
|
return outside;
|
|
8521
9015
|
}
|
|
8522
9016
|
|
|
8523
9017
|
// eslint/rules/source-under-src.ts
|
|
8524
|
-
import
|
|
9018
|
+
import path59 from "path";
|
|
8525
9019
|
var NON_SOURCE_ROOT_DIRS = /* @__PURE__ */ new Set([
|
|
8526
9020
|
".agents",
|
|
8527
9021
|
".cache",
|
|
@@ -8562,14 +9056,14 @@ var sourceUnderSrcRule = {
|
|
|
8562
9056
|
}
|
|
8563
9057
|
},
|
|
8564
9058
|
create(context) {
|
|
8565
|
-
const filename =
|
|
9059
|
+
const filename = path59.resolve(context.filename);
|
|
8566
9060
|
if (!MODULE_EXTENSION.test(filename)) return {};
|
|
8567
|
-
const relative =
|
|
9061
|
+
const relative = path59.relative(context.cwd, filename).replace(/\\/g, "/");
|
|
8568
9062
|
if (relative === "src" || relative.startsWith("src/")) return {};
|
|
8569
9063
|
const topLevel = relative.split("/")[0] ?? "";
|
|
8570
9064
|
if (NON_SOURCE_ROOT_DIRS.has(topLevel)) return {};
|
|
8571
9065
|
if (!relative.includes("/")) {
|
|
8572
|
-
const basename =
|
|
9066
|
+
const basename = path59.basename(filename);
|
|
8573
9067
|
if (CONFIG_FILE.test(basename) || DECLARATION_FILE.test(basename) || basename.startsWith(".")) return {};
|
|
8574
9068
|
}
|
|
8575
9069
|
return {
|
|
@@ -8585,7 +9079,7 @@ var sourceUnderSrcRule = {
|
|
|
8585
9079
|
};
|
|
8586
9080
|
|
|
8587
9081
|
// eslint/rules/stay-flat.ts
|
|
8588
|
-
import
|
|
9082
|
+
import path60 from "path";
|
|
8589
9083
|
var stayFlatRule = {
|
|
8590
9084
|
meta: {
|
|
8591
9085
|
schema: [],
|
|
@@ -8596,7 +9090,7 @@ var stayFlatRule = {
|
|
|
8596
9090
|
},
|
|
8597
9091
|
create(context) {
|
|
8598
9092
|
const sourceRoot = sourceRootOf(context);
|
|
8599
|
-
const file =
|
|
9093
|
+
const file = path60.resolve(context.filename);
|
|
8600
9094
|
const segments = segmentsOf(file, sourceRoot);
|
|
8601
9095
|
if (segments.length !== 3 || segments[0] !== "features") return {};
|
|
8602
9096
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -8636,7 +9130,7 @@ var stayFlatRule = {
|
|
|
8636
9130
|
};
|
|
8637
9131
|
|
|
8638
9132
|
// eslint/rules/support-file-placement.ts
|
|
8639
|
-
import
|
|
9133
|
+
import path61 from "path";
|
|
8640
9134
|
var CONFIG_OWNED_FOLDERS = /* @__PURE__ */ new Set(["types", "constants"]);
|
|
8641
9135
|
var EXPORT_KIND_BY_SUPPORT_FOLDER = /* @__PURE__ */ new Map([
|
|
8642
9136
|
["constants", "constant"],
|
|
@@ -8661,7 +9155,7 @@ var supportFilePlacementRule = {
|
|
|
8661
9155
|
},
|
|
8662
9156
|
create(context) {
|
|
8663
9157
|
const sourceRoot = sourceRootOf(context);
|
|
8664
|
-
const supportFile =
|
|
9158
|
+
const supportFile = path61.resolve(context.filename);
|
|
8665
9159
|
const currentFolder = folderSegmentsOf(supportFile, sourceRoot);
|
|
8666
9160
|
const supportFolder = currentFolder[currentFolder.length - 1];
|
|
8667
9161
|
if (supportFolder === void 0 || !SUPPORT_FOLDERS.has(supportFolder)) return {};
|
|
@@ -8715,7 +9209,7 @@ var supportFilePlacementRule = {
|
|
|
8715
9209
|
|
|
8716
9210
|
// eslint/rules/support-folder-shape.ts
|
|
8717
9211
|
import fs6 from "fs";
|
|
8718
|
-
import
|
|
9212
|
+
import path62 from "path";
|
|
8719
9213
|
var SUPPORT_FOLDERS4 = /* @__PURE__ */ new Set(["constants", "types", "schemas"]);
|
|
8720
9214
|
var INDEX_NAMES2 = /* @__PURE__ */ new Set(["index.ts", "index.tsx", "index.mts", "index.cts"]);
|
|
8721
9215
|
var supportFolderShapeRule = {
|
|
@@ -8727,12 +9221,12 @@ var supportFolderShapeRule = {
|
|
|
8727
9221
|
}
|
|
8728
9222
|
},
|
|
8729
9223
|
create(context) {
|
|
8730
|
-
const filename =
|
|
8731
|
-
const baseName =
|
|
9224
|
+
const filename = path62.resolve(context.filename);
|
|
9225
|
+
const baseName = path62.basename(filename);
|
|
8732
9226
|
if (!INDEX_NAMES2.has(baseName)) return {};
|
|
8733
|
-
const folder =
|
|
9227
|
+
const folder = path62.basename(path62.dirname(filename));
|
|
8734
9228
|
if (!SUPPORT_FOLDERS4.has(folder)) return {};
|
|
8735
|
-
const directory =
|
|
9229
|
+
const directory = path62.dirname(filename);
|
|
8736
9230
|
let entries;
|
|
8737
9231
|
try {
|
|
8738
9232
|
entries = fs6.readdirSync(directory);
|
|
@@ -8750,7 +9244,7 @@ var supportFolderShapeRule = {
|
|
|
8750
9244
|
for (const match of source.matchAll(exportPattern)) {
|
|
8751
9245
|
hasAnyReExport = true;
|
|
8752
9246
|
const specifier = match.groups?.specifier;
|
|
8753
|
-
if (specifier?.startsWith(".")) exportedFiles.add(
|
|
9247
|
+
if (specifier?.startsWith(".")) exportedFiles.add(path62.basename(specifier));
|
|
8754
9248
|
}
|
|
8755
9249
|
const guide = `docs/next-codebase-guide/rules/${folder === "constants" ? "constants" : "types-and-schemas"}-rule.md`;
|
|
8756
9250
|
if (siblingModules.length === 0) {
|
|
@@ -8929,24 +9423,24 @@ var baseLayerPairRule = {
|
|
|
8929
9423
|
|
|
8930
9424
|
// eslint/rules/tailwind/css-entry-point.ts
|
|
8931
9425
|
import { statSync as statSync4 } from "fs";
|
|
8932
|
-
import
|
|
9426
|
+
import path65 from "path";
|
|
8933
9427
|
|
|
8934
9428
|
// eslint/rules/tailwind/source-files.ts
|
|
8935
|
-
import { readdirSync as
|
|
8936
|
-
import
|
|
9429
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync13, statSync as statSync3 } from "fs";
|
|
9430
|
+
import path63 from "path";
|
|
8937
9431
|
var CSS_EXTENSIONS = [".css"];
|
|
8938
9432
|
var MODULE_EXTENSIONS4 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
8939
9433
|
var SOURCE_EXTENSIONS = [...MODULE_EXTENSIONS4, ...CSS_EXTENSIONS];
|
|
8940
9434
|
function findFiles(dir, extensions) {
|
|
8941
9435
|
let entries;
|
|
8942
9436
|
try {
|
|
8943
|
-
entries =
|
|
9437
|
+
entries = readdirSync5(dir);
|
|
8944
9438
|
} catch {
|
|
8945
9439
|
return [];
|
|
8946
9440
|
}
|
|
8947
9441
|
return entries.flatMap((entry) => {
|
|
8948
9442
|
if (entry.startsWith(".") || entry === "node_modules") return [];
|
|
8949
|
-
const entryPath =
|
|
9443
|
+
const entryPath = path63.join(dir, entry);
|
|
8950
9444
|
let stats;
|
|
8951
9445
|
try {
|
|
8952
9446
|
stats = statSync3(entryPath);
|
|
@@ -8954,7 +9448,7 @@ function findFiles(dir, extensions) {
|
|
|
8954
9448
|
return [];
|
|
8955
9449
|
}
|
|
8956
9450
|
if (stats.isDirectory()) return findFiles(entryPath, extensions);
|
|
8957
|
-
return extensions.includes(
|
|
9451
|
+
return extensions.includes(path63.extname(entry)) ? [entryPath] : [];
|
|
8958
9452
|
});
|
|
8959
9453
|
}
|
|
8960
9454
|
function cachedTextReader() {
|
|
@@ -8963,7 +9457,7 @@ function cachedTextReader() {
|
|
|
8963
9457
|
let text = texts.get(file);
|
|
8964
9458
|
if (text === void 0) {
|
|
8965
9459
|
try {
|
|
8966
|
-
text =
|
|
9460
|
+
text = readFileSync13(file, "utf8");
|
|
8967
9461
|
} catch {
|
|
8968
9462
|
text = "";
|
|
8969
9463
|
}
|
|
@@ -8977,7 +9471,7 @@ function escapeRegExp(text) {
|
|
|
8977
9471
|
}
|
|
8978
9472
|
|
|
8979
9473
|
// eslint/rules/tailwind/stylesheet-graph.ts
|
|
8980
|
-
import
|
|
9474
|
+
import path64 from "path";
|
|
8981
9475
|
function registersTailwind(text) {
|
|
8982
9476
|
return /@import\s+(?:url\(\s*)?["']tailwindcss["']\s*\)?/i.test(text);
|
|
8983
9477
|
}
|
|
@@ -8991,25 +9485,25 @@ function moduleImports(text, fileName) {
|
|
|
8991
9485
|
return new RegExp(`(?:import|require)\\s*\\(?\\s*["'][^"']*${escaped}["']`, "i").test(text);
|
|
8992
9486
|
}
|
|
8993
9487
|
function resolveSpecifier2(fromFile, spec, sourceRoot) {
|
|
8994
|
-
if (spec.startsWith("/")) return
|
|
8995
|
-
if (spec.startsWith("./") || spec.startsWith("../")) return
|
|
8996
|
-
if (spec.startsWith("@/")) return
|
|
9488
|
+
if (spec.startsWith("/")) return path64.resolve(spec);
|
|
9489
|
+
if (spec.startsWith("./") || spec.startsWith("../")) return path64.resolve(path64.dirname(fromFile), spec);
|
|
9490
|
+
if (spec.startsWith("@/")) return path64.resolve(sourceRoot, spec.slice(2));
|
|
8997
9491
|
return void 0;
|
|
8998
9492
|
}
|
|
8999
9493
|
function buildStylesheetGraph(options) {
|
|
9000
9494
|
const { cssFiles, sourceRoot, textOf } = options;
|
|
9001
|
-
const cssSet = new Set(cssFiles.map((file) =>
|
|
9495
|
+
const cssSet = new Set(cssFiles.map((file) => path64.normalize(file)));
|
|
9002
9496
|
const globals = cssFiles.filter((file) => registersTailwind(textOf(file)));
|
|
9003
9497
|
const reachable = /* @__PURE__ */ new Set();
|
|
9004
9498
|
const queue = [...globals];
|
|
9005
|
-
for (const global of globals) reachable.add(
|
|
9499
|
+
for (const global of globals) reachable.add(path64.normalize(global));
|
|
9006
9500
|
while (queue.length > 0) {
|
|
9007
9501
|
const from = queue.shift();
|
|
9008
9502
|
if (!from) continue;
|
|
9009
9503
|
for (const spec of importedSpecifiers(textOf(from))) {
|
|
9010
9504
|
const target = resolveSpecifier2(from, spec, sourceRoot);
|
|
9011
9505
|
if (!target) continue;
|
|
9012
|
-
const normalized =
|
|
9506
|
+
const normalized = path64.normalize(target);
|
|
9013
9507
|
if (cssSet.has(normalized) && !reachable.has(normalized)) {
|
|
9014
9508
|
reachable.add(normalized);
|
|
9015
9509
|
queue.push(normalized);
|
|
@@ -9021,7 +9515,7 @@ function buildStylesheetGraph(options) {
|
|
|
9021
9515
|
for (const spec of importedSpecifiers(textOf(global))) {
|
|
9022
9516
|
const target = resolveSpecifier2(global, spec, sourceRoot);
|
|
9023
9517
|
if (!target) continue;
|
|
9024
|
-
const normalized =
|
|
9518
|
+
const normalized = path64.normalize(target);
|
|
9025
9519
|
if (cssSet.has(normalized)) directChildren.add(normalized);
|
|
9026
9520
|
}
|
|
9027
9521
|
}
|
|
@@ -9029,8 +9523,8 @@ function buildStylesheetGraph(options) {
|
|
|
9029
9523
|
}
|
|
9030
9524
|
|
|
9031
9525
|
// eslint/rules/tailwind/css-entry-point.ts
|
|
9032
|
-
var APP_STYLES_DIR =
|
|
9033
|
-
var GLOBAL_STYLESHEET_PATH =
|
|
9526
|
+
var APP_STYLES_DIR = path65.join("app", "styles");
|
|
9527
|
+
var GLOBAL_STYLESHEET_PATH = path65.join(APP_STYLES_DIR, "globals.css");
|
|
9034
9528
|
var cssEntryPointRule = {
|
|
9035
9529
|
meta: {
|
|
9036
9530
|
schema: [],
|
|
@@ -9056,8 +9550,8 @@ var cssEntryPointRule = {
|
|
|
9056
9550
|
return {
|
|
9057
9551
|
"StyleSheet:exit"(node) {
|
|
9058
9552
|
if (globals.length === 0) return;
|
|
9059
|
-
const current =
|
|
9060
|
-
const relative =
|
|
9553
|
+
const current = path65.normalize(path65.resolve(context.filename));
|
|
9554
|
+
const relative = path65.relative(sourceRoot, current);
|
|
9061
9555
|
if (globals.includes(current)) {
|
|
9062
9556
|
if (globals.length > 1) {
|
|
9063
9557
|
context.report({
|
|
@@ -9073,7 +9567,7 @@ var cssEntryPointRule = {
|
|
|
9073
9567
|
});
|
|
9074
9568
|
return;
|
|
9075
9569
|
}
|
|
9076
|
-
const basename =
|
|
9570
|
+
const basename = path65.basename(current);
|
|
9077
9571
|
const importCount = moduleFiles.filter((modulePath) => moduleImports(textOf(modulePath), basename)).length;
|
|
9078
9572
|
if (importCount !== 1) {
|
|
9079
9573
|
context.report({
|
|
@@ -9083,7 +9577,7 @@ var cssEntryPointRule = {
|
|
|
9083
9577
|
}
|
|
9084
9578
|
return;
|
|
9085
9579
|
}
|
|
9086
|
-
const isInAppStyles = relative === APP_STYLES_DIR || relative.startsWith(`${APP_STYLES_DIR}${
|
|
9580
|
+
const isInAppStyles = relative === APP_STYLES_DIR || relative.startsWith(`${APP_STYLES_DIR}${path65.sep}`);
|
|
9087
9581
|
if (!isInAppStyles) {
|
|
9088
9582
|
context.report({
|
|
9089
9583
|
node,
|
|
@@ -9572,7 +10066,7 @@ var tailwindRules = {
|
|
|
9572
10066
|
};
|
|
9573
10067
|
|
|
9574
10068
|
// eslint/rules/type-extraction.ts
|
|
9575
|
-
import
|
|
10069
|
+
import path66 from "path";
|
|
9576
10070
|
var typeExtractionRule = {
|
|
9577
10071
|
meta: {
|
|
9578
10072
|
schema: [],
|
|
@@ -9583,7 +10077,7 @@ var typeExtractionRule = {
|
|
|
9583
10077
|
},
|
|
9584
10078
|
create(context) {
|
|
9585
10079
|
const sourceRoot = sourceRootOf(context);
|
|
9586
|
-
const file =
|
|
10080
|
+
const file = path66.resolve(context.filename);
|
|
9587
10081
|
const segments = segmentsOf(file, sourceRoot);
|
|
9588
10082
|
if (segments.length === 0) return {};
|
|
9589
10083
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -9722,9 +10216,9 @@ var uiStateRule = {
|
|
|
9722
10216
|
};
|
|
9723
10217
|
|
|
9724
10218
|
// eslint/rules/unknown-utility.ts
|
|
9725
|
-
import { existsSync as
|
|
10219
|
+
import { existsSync as existsSync8, readdirSync as readdirSync6, readFileSync as readFileSync14, statSync as statSync6 } from "fs";
|
|
9726
10220
|
import { createRequire } from "module";
|
|
9727
|
-
import
|
|
10221
|
+
import path67 from "path";
|
|
9728
10222
|
var PREFIX_NAMESPACES = {
|
|
9729
10223
|
bg: ["color"],
|
|
9730
10224
|
text: ["color", "text"],
|
|
@@ -9958,13 +10452,13 @@ function isBuiltInTailwindUtility(utility) {
|
|
|
9958
10452
|
function stylesheetFiles(dir) {
|
|
9959
10453
|
let entries;
|
|
9960
10454
|
try {
|
|
9961
|
-
entries =
|
|
10455
|
+
entries = readdirSync6(dir);
|
|
9962
10456
|
} catch {
|
|
9963
10457
|
return [];
|
|
9964
10458
|
}
|
|
9965
10459
|
return entries.flatMap((entry) => {
|
|
9966
10460
|
if (entry.startsWith(".") || entry === "node_modules") return [];
|
|
9967
|
-
const entryPath =
|
|
10461
|
+
const entryPath = path67.join(dir, entry);
|
|
9968
10462
|
let stats;
|
|
9969
10463
|
try {
|
|
9970
10464
|
stats = statSync6(entryPath);
|
|
@@ -9972,7 +10466,7 @@ function stylesheetFiles(dir) {
|
|
|
9972
10466
|
return [];
|
|
9973
10467
|
}
|
|
9974
10468
|
if (stats.isDirectory()) return stylesheetFiles(entryPath);
|
|
9975
|
-
return
|
|
10469
|
+
return path67.extname(entry) === ".css" ? [entryPath] : [];
|
|
9976
10470
|
});
|
|
9977
10471
|
}
|
|
9978
10472
|
function packageNameOf(specifier) {
|
|
@@ -9983,24 +10477,24 @@ function packageNameOf(specifier) {
|
|
|
9983
10477
|
function resolvePackageStylesheet(fromFile, specifier) {
|
|
9984
10478
|
const packageName = packageNameOf(specifier);
|
|
9985
10479
|
if (!packageName || packageName === "tailwindcss") return void 0;
|
|
9986
|
-
let directory =
|
|
9987
|
-
while (directory !==
|
|
9988
|
-
const packageRoot =
|
|
9989
|
-
const manifestPath =
|
|
9990
|
-
if (
|
|
10480
|
+
let directory = path67.dirname(fromFile);
|
|
10481
|
+
while (directory !== path67.dirname(directory)) {
|
|
10482
|
+
const packageRoot = path67.join(directory, "node_modules", packageName);
|
|
10483
|
+
const manifestPath = path67.join(packageRoot, "package.json");
|
|
10484
|
+
if (existsSync8(manifestPath)) {
|
|
9991
10485
|
try {
|
|
9992
|
-
const manifest =
|
|
10486
|
+
const manifest = readFileSync14(manifestPath, "utf8");
|
|
9993
10487
|
const stylesheet = /"style"\s*:\s*"(?<file>[^"]+\.css)"/.exec(manifest)?.groups?.file;
|
|
9994
10488
|
const main = /"main"\s*:\s*"(?<file>[^"]+\.css)"/.exec(manifest)?.groups?.file;
|
|
9995
10489
|
const target = stylesheet ?? main;
|
|
9996
10490
|
if (!target) return void 0;
|
|
9997
|
-
const resolved =
|
|
9998
|
-
return
|
|
10491
|
+
const resolved = path67.resolve(packageRoot, target);
|
|
10492
|
+
return existsSync8(resolved) ? resolved : void 0;
|
|
9999
10493
|
} catch {
|
|
10000
10494
|
return void 0;
|
|
10001
10495
|
}
|
|
10002
10496
|
}
|
|
10003
|
-
directory =
|
|
10497
|
+
directory = path67.dirname(directory);
|
|
10004
10498
|
}
|
|
10005
10499
|
return void 0;
|
|
10006
10500
|
}
|
|
@@ -10009,7 +10503,7 @@ function inventoryStylesheetFiles(projectFiles) {
|
|
|
10009
10503
|
for (const file of projectFiles) {
|
|
10010
10504
|
let css2;
|
|
10011
10505
|
try {
|
|
10012
|
-
css2 =
|
|
10506
|
+
css2 = readFileSync14(file, "utf8");
|
|
10013
10507
|
} catch {
|
|
10014
10508
|
continue;
|
|
10015
10509
|
}
|
|
@@ -10075,7 +10569,7 @@ function readInventory(files) {
|
|
|
10075
10569
|
for (const file of files) {
|
|
10076
10570
|
let css2;
|
|
10077
10571
|
try {
|
|
10078
|
-
css2 =
|
|
10572
|
+
css2 = readFileSync14(file, "utf8");
|
|
10079
10573
|
} catch {
|
|
10080
10574
|
continue;
|
|
10081
10575
|
}
|
|
@@ -10251,7 +10745,7 @@ var unknownUtilityRule = {
|
|
|
10251
10745
|
};
|
|
10252
10746
|
|
|
10253
10747
|
// eslint/rules/util-file-name.ts
|
|
10254
|
-
import
|
|
10748
|
+
import path68 from "path";
|
|
10255
10749
|
function toKebabCase2(value) {
|
|
10256
10750
|
return value.replace(/(?<lower>[a-z0-9])(?<upper>[A-Z])/g, "$<lower>-$<upper>").replace(/(?<first>[A-Z])(?<rest>[A-Z][a-z])/g, "$<first>-$<rest>").toLowerCase();
|
|
10257
10751
|
}
|
|
@@ -10264,7 +10758,7 @@ var utilFileNameRule = {
|
|
|
10264
10758
|
}
|
|
10265
10759
|
},
|
|
10266
10760
|
create(context) {
|
|
10267
|
-
const filename =
|
|
10761
|
+
const filename = path68.resolve(context.filename);
|
|
10268
10762
|
const segments = filename.replace(/\\/g, "/").split("/");
|
|
10269
10763
|
if (!segments.includes("utils")) return {};
|
|
10270
10764
|
let module;
|
|
@@ -10278,13 +10772,13 @@ var utilFileNameRule = {
|
|
|
10278
10772
|
const functionName = functions[0]?.name;
|
|
10279
10773
|
if (!functionName) return {};
|
|
10280
10774
|
const expected = toKebabCase2(functionName);
|
|
10281
|
-
const actual =
|
|
10775
|
+
const actual = path68.basename(filename, path68.extname(filename));
|
|
10282
10776
|
if (!expected || actual === expected) return {};
|
|
10283
10777
|
return {
|
|
10284
10778
|
Program(node) {
|
|
10285
10779
|
context.report({
|
|
10286
10780
|
node,
|
|
10287
|
-
message: `A utility file exporting ${functionName} must be named ${expected}.${
|
|
10781
|
+
message: `A utility file exporting ${functionName} must be named ${expected}.${path68.extname(filename).slice(1)}.`
|
|
10288
10782
|
});
|
|
10289
10783
|
}
|
|
10290
10784
|
};
|
|
@@ -10292,7 +10786,7 @@ var utilFileNameRule = {
|
|
|
10292
10786
|
};
|
|
10293
10787
|
|
|
10294
10788
|
// eslint/rules/value-extraction.ts
|
|
10295
|
-
import
|
|
10789
|
+
import path69 from "path";
|
|
10296
10790
|
var valueExtractionRule = {
|
|
10297
10791
|
meta: {
|
|
10298
10792
|
schema: [],
|
|
@@ -10303,7 +10797,7 @@ var valueExtractionRule = {
|
|
|
10303
10797
|
},
|
|
10304
10798
|
create(context) {
|
|
10305
10799
|
const sourceRoot = sourceRootOf(context);
|
|
10306
|
-
const file =
|
|
10800
|
+
const file = path69.resolve(context.filename);
|
|
10307
10801
|
const segments = segmentsOf(file, sourceRoot);
|
|
10308
10802
|
if (segments.length === 0 || segments[0] !== "app") return {};
|
|
10309
10803
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -10324,8 +10818,8 @@ var valueExtractionRule = {
|
|
|
10324
10818
|
};
|
|
10325
10819
|
|
|
10326
10820
|
// eslint/rules/vulyk/tracked-docs.ts
|
|
10327
|
-
import { existsSync as
|
|
10328
|
-
import
|
|
10821
|
+
import { existsSync as existsSync9, readFileSync as readFileSync15 } from "fs";
|
|
10822
|
+
import path70 from "path";
|
|
10329
10823
|
var PASIKA_REPO = "Bredansky/pasika";
|
|
10330
10824
|
var BASE_REQUIRED_TRACKED_DOCS = [
|
|
10331
10825
|
{ name: "documentation-guide", path: "docs/documentation-guide" },
|
|
@@ -10336,13 +10830,13 @@ var NEXTJS_REQUIRED_TRACKED_DOCS = [
|
|
|
10336
10830
|
{ name: "next-codebase-guide", path: "docs/next-codebase-guide" },
|
|
10337
10831
|
{ name: "next-tailwind-guide", path: "docs/next-tailwind-guide" }
|
|
10338
10832
|
];
|
|
10339
|
-
function
|
|
10833
|
+
function memberName8(member) {
|
|
10340
10834
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
10341
10835
|
}
|
|
10342
10836
|
function hasDependency(root, name) {
|
|
10343
|
-
const section = root.members.find((member) =>
|
|
10837
|
+
const section = root.members.find((member) => memberName8(member) === "dependencies");
|
|
10344
10838
|
if (section?.value.type !== "Object") return false;
|
|
10345
|
-
return section.value.members.some((member) =>
|
|
10839
|
+
return section.value.members.some((member) => memberName8(member) === name);
|
|
10346
10840
|
}
|
|
10347
10841
|
var trackedDocsRule = {
|
|
10348
10842
|
meta: {
|
|
@@ -10358,16 +10852,16 @@ var trackedDocsRule = {
|
|
|
10358
10852
|
if (!context.filename.endsWith("package.json")) return;
|
|
10359
10853
|
const root = node.body;
|
|
10360
10854
|
if (root.type !== "Object") return;
|
|
10361
|
-
const projectRoot =
|
|
10362
|
-
const configPath =
|
|
10363
|
-
if (!
|
|
10855
|
+
const projectRoot = path70.dirname(path70.resolve(context.filename));
|
|
10856
|
+
const configPath = path70.join(projectRoot, "vulyk.config.ts");
|
|
10857
|
+
if (!existsSync9(configPath)) {
|
|
10364
10858
|
context.report({
|
|
10365
10859
|
node,
|
|
10366
10860
|
message: "No vulyk.config.ts found. Run npx vulyk init to create one that tracks the framework's required tracked docs."
|
|
10367
10861
|
});
|
|
10368
10862
|
return;
|
|
10369
10863
|
}
|
|
10370
|
-
const config =
|
|
10864
|
+
const config = readFileSync15(configPath, "utf8");
|
|
10371
10865
|
if (!config.includes(PASIKA_REPO)) {
|
|
10372
10866
|
context.report({
|
|
10373
10867
|
node,
|
|
@@ -10384,8 +10878,8 @@ var trackedDocsRule = {
|
|
|
10384
10878
|
});
|
|
10385
10879
|
}
|
|
10386
10880
|
}
|
|
10387
|
-
const agentsPath =
|
|
10388
|
-
if (!
|
|
10881
|
+
const agentsPath = path70.join(projectRoot, "AGENTS.md");
|
|
10882
|
+
if (!existsSync9(agentsPath)) {
|
|
10389
10883
|
context.report({
|
|
10390
10884
|
node,
|
|
10391
10885
|
message: "No AGENTS.md found. Run npx vulyk agents to generate the agent file that routes to the tracked docs."
|
|
@@ -10397,14 +10891,14 @@ var trackedDocsRule = {
|
|
|
10397
10891
|
};
|
|
10398
10892
|
|
|
10399
10893
|
// eslint/rules/vulyk/vulyk-dependency.ts
|
|
10400
|
-
function
|
|
10894
|
+
function memberName9(member) {
|
|
10401
10895
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
10402
10896
|
}
|
|
10403
10897
|
function dependency(root, sectionName) {
|
|
10404
10898
|
if (root.type !== "Object") return void 0;
|
|
10405
|
-
const section = root.members.find((member) =>
|
|
10899
|
+
const section = root.members.find((member) => memberName9(member) === sectionName);
|
|
10406
10900
|
if (section?.value.type !== "Object") return void 0;
|
|
10407
|
-
return section.value.members.find((member) =>
|
|
10901
|
+
return section.value.members.find((member) => memberName9(member) === "vulyk");
|
|
10408
10902
|
}
|
|
10409
10903
|
var vulykDependencyRule = {
|
|
10410
10904
|
meta: {
|
|
@@ -10445,9 +10939,9 @@ var vulykRules = {
|
|
|
10445
10939
|
// eslint/rules/with-response-helper.ts
|
|
10446
10940
|
var HELPER3 = "withResponse";
|
|
10447
10941
|
var ENTRY3 = "pasika/with-response";
|
|
10448
|
-
var
|
|
10449
|
-
var DECLARED3 = `A repository must not declare its own ${HELPER3}; import it from ${ENTRY3}. See ${
|
|
10450
|
-
var IMPORTED3 = `${HELPER3} must be imported from ${ENTRY3}. See ${
|
|
10942
|
+
var DOC9 = "docs/pasika-adoption-guide/rules/with-response-helper-rule.md";
|
|
10943
|
+
var DECLARED3 = `A repository must not declare its own ${HELPER3}; import it from ${ENTRY3}. See ${DOC9}`;
|
|
10944
|
+
var IMPORTED3 = `${HELPER3} must be imported from ${ENTRY3}. See ${DOC9}`;
|
|
10451
10945
|
function isNamed3(node, name) {
|
|
10452
10946
|
return node?.type === "Identifier" && node.name === name;
|
|
10453
10947
|
}
|
|
@@ -10484,7 +10978,7 @@ var withResponseHelperRule = {
|
|
|
10484
10978
|
|
|
10485
10979
|
// eslint/rules/zirka-baseline.ts
|
|
10486
10980
|
import fs7 from "fs";
|
|
10487
|
-
import
|
|
10981
|
+
import path71 from "path";
|
|
10488
10982
|
var ESLINT_CONFIG = /^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/;
|
|
10489
10983
|
var PRETTIER_CONFIGS = [
|
|
10490
10984
|
"prettier.config.mjs",
|
|
@@ -10503,10 +10997,10 @@ var zirkaBaselineRule = {
|
|
|
10503
10997
|
}
|
|
10504
10998
|
},
|
|
10505
10999
|
create(context) {
|
|
10506
|
-
const filename =
|
|
10507
|
-
const basename =
|
|
11000
|
+
const filename = path71.resolve(context.filename);
|
|
11001
|
+
const basename = path71.basename(filename);
|
|
10508
11002
|
if (!ESLINT_CONFIG.test(basename)) return {};
|
|
10509
|
-
const projectRoot =
|
|
11003
|
+
const projectRoot = path71.dirname(filename);
|
|
10510
11004
|
const report3 = (message) => {
|
|
10511
11005
|
context.report({
|
|
10512
11006
|
node: context.sourceCode.ast,
|
|
@@ -10521,7 +11015,7 @@ var zirkaBaselineRule = {
|
|
|
10521
11015
|
'ESLint config must take its configuration from zirka (import { styleguide } from "zirka") instead of restating rules locally.'
|
|
10522
11016
|
);
|
|
10523
11017
|
}
|
|
10524
|
-
const tsconfigPath =
|
|
11018
|
+
const tsconfigPath = path71.join(projectRoot, "tsconfig.json");
|
|
10525
11019
|
if (!fs7.existsSync(tsconfigPath)) {
|
|
10526
11020
|
report3('No tsconfig.json found. Create one extending the zirka TypeScript base config ("zirka/typescript").');
|
|
10527
11021
|
} else {
|
|
@@ -10539,13 +11033,13 @@ var zirkaBaselineRule = {
|
|
|
10539
11033
|
report3('tsconfig.json must extend the zirka TypeScript base config ("zirka/typescript").');
|
|
10540
11034
|
}
|
|
10541
11035
|
}
|
|
10542
|
-
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs7.existsSync(
|
|
11036
|
+
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs7.existsSync(path71.join(projectRoot, name)));
|
|
10543
11037
|
if (!prettierConfigFile) {
|
|
10544
11038
|
report3(
|
|
10545
11039
|
"No prettier config found. Create one that takes its configuration from zirka (styleguide({ prettier: true }).prettierConfig)."
|
|
10546
11040
|
);
|
|
10547
11041
|
} else {
|
|
10548
|
-
const content = fs7.readFileSync(
|
|
11042
|
+
const content = fs7.readFileSync(path71.join(projectRoot, prettierConfigFile), "utf8");
|
|
10549
11043
|
if (!content.includes("zirka")) {
|
|
10550
11044
|
report3(
|
|
10551
11045
|
"The prettier config must take its configuration from zirka (styleguide({ prettier: true }).prettierConfig) instead of restating it locally."
|
|
@@ -10568,10 +11062,10 @@ function referencesZirka(sourceCode) {
|
|
|
10568
11062
|
// eslint/rules/zod-fetch-helper.ts
|
|
10569
11063
|
var HELPER4 = "zodFetch";
|
|
10570
11064
|
var ENTRY4 = "pasika/zod-fetch";
|
|
10571
|
-
var
|
|
10572
|
-
var FETCHED = `fetch must not be called; make the request through ${HELPER4} from ${ENTRY4}. See ${
|
|
10573
|
-
var DECLARED4 = `A file must not declare its own ${HELPER4}; import it from ${ENTRY4}. See ${
|
|
10574
|
-
var IMPORTED4 = `${HELPER4} must be imported from ${ENTRY4}. See ${
|
|
11065
|
+
var DOC10 = "docs/pasika-adoption-guide/rules/zod-fetch-helper-rule.md";
|
|
11066
|
+
var FETCHED = `fetch must not be called; make the request through ${HELPER4} from ${ENTRY4}. See ${DOC10}`;
|
|
11067
|
+
var DECLARED4 = `A file must not declare its own ${HELPER4}; import it from ${ENTRY4}. See ${DOC10}`;
|
|
11068
|
+
var IMPORTED4 = `${HELPER4} must be imported from ${ENTRY4}. See ${DOC10}`;
|
|
10575
11069
|
var GLOBAL_OBJECTS = /* @__PURE__ */ new Set(["globalThis", "window", "self", "global"]);
|
|
10576
11070
|
var TEST_FILE2 = /(?:^|[\\/])(?:__tests__|tests)[\\/]|[.](?:test|spec)[.][cm]?[jt]sx?$/;
|
|
10577
11071
|
function isNamed4(node, name) {
|
|
@@ -10691,14 +11185,14 @@ var zodSchemaValidationRule = {
|
|
|
10691
11185
|
};
|
|
10692
11186
|
|
|
10693
11187
|
// eslint/ts-alignment.ts
|
|
10694
|
-
import { readFileSync as
|
|
11188
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
10695
11189
|
import { createRequire as createRequire2 } from "module";
|
|
10696
11190
|
import { join } from "path";
|
|
10697
11191
|
var ownRequire = createRequire2(import.meta.url);
|
|
10698
11192
|
var majorOf = (version) => Number(version.split(".")[0]);
|
|
10699
11193
|
function versionOf(packagePath) {
|
|
10700
11194
|
try {
|
|
10701
|
-
const parsed = JSON.parse(
|
|
11195
|
+
const parsed = JSON.parse(readFileSync16(packagePath, "utf8"));
|
|
10702
11196
|
if (typeof parsed !== "object" || parsed === null || !("version" in parsed)) return null;
|
|
10703
11197
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
10704
11198
|
} catch {
|