pasika 0.10.101 → 0.10.102
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 +1045 -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,146 @@ 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
|
+
if (scripts.has("build")) requiredScripts.push("build");
|
|
6647
|
+
const checkJobs = Object.values(jobs(check));
|
|
6648
|
+
const allSteps = checkJobs.flatMap(steps);
|
|
6649
|
+
for (const job of checkJobs) {
|
|
6650
|
+
const jobSteps = steps(job);
|
|
6651
|
+
const firstCheck = jobSteps.findIndex((step) => requiredScripts.some((name) => runsScript(step.run, name)));
|
|
6652
|
+
if (firstCheck < 0) continue;
|
|
6653
|
+
const checkout = jobSteps.findIndex((step) => usesAction(step.uses, "actions/checkout"));
|
|
6654
|
+
const install = jobSteps.findIndex((step) => runsNpmCi(step.run));
|
|
6655
|
+
if (checkout < 0 || checkout >= firstCheck) {
|
|
6656
|
+
report3("GitHub Actions checks must check out the repository before running npm scripts.");
|
|
6657
|
+
}
|
|
6658
|
+
if (install < 0 || install >= firstCheck || checkout >= 0 && install <= checkout) {
|
|
6659
|
+
report3("GitHub Actions checks must install dependencies with npm ci.");
|
|
6660
|
+
}
|
|
6661
|
+
}
|
|
6662
|
+
for (const name of requiredScripts) {
|
|
6663
|
+
if (!allSteps.some((step) => runsScript(step.run, name))) {
|
|
6664
|
+
report3(`GitHub Actions checks must run npm run ${name}.`);
|
|
6665
|
+
}
|
|
6666
|
+
}
|
|
6667
|
+
const coverage = scripts.get("test:unit:coverage:check");
|
|
6668
|
+
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)) {
|
|
6669
|
+
report3(
|
|
6670
|
+
"package.json must declare test:unit:coverage:check that runs coverage with autoUpdate=false and verifies no Git diff."
|
|
6671
|
+
);
|
|
6672
|
+
}
|
|
6673
|
+
}
|
|
6674
|
+
};
|
|
6675
|
+
}
|
|
6676
|
+
};
|
|
6677
|
+
|
|
6678
|
+
// eslint/rules/package-json/exact-version.ts
|
|
6679
|
+
function memberName3(member) {
|
|
6680
|
+
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
6681
|
+
}
|
|
6291
6682
|
var EXACT_VERSION_PATTERN = /^\d+\.\d+\.\d+$/;
|
|
6292
6683
|
function memberValue(member) {
|
|
6293
6684
|
return member.value.type === "String" ? member.value.value : null;
|
|
@@ -6306,7 +6697,7 @@ var exactVersionRule = {
|
|
|
6306
6697
|
const root = node.body;
|
|
6307
6698
|
if (root.type !== "Object") return;
|
|
6308
6699
|
for (const key of ["dependencies", "devDependencies"]) {
|
|
6309
|
-
const section = root.members.find((member) =>
|
|
6700
|
+
const section = root.members.find((member) => memberName3(member) === key);
|
|
6310
6701
|
if (section?.value.type !== "Object") continue;
|
|
6311
6702
|
for (const member of section.value.members) {
|
|
6312
6703
|
const version = memberValue(member);
|
|
@@ -6314,7 +6705,7 @@ var exactVersionRule = {
|
|
|
6314
6705
|
if (!EXACT_VERSION_PATTERN.test(version)) {
|
|
6315
6706
|
context.report({
|
|
6316
6707
|
node: member,
|
|
6317
|
-
message: `${
|
|
6708
|
+
message: `${memberName3(member)} must pin an exact version (e.g. "1.2.3"), not a range or cap such as "${version}".`
|
|
6318
6709
|
});
|
|
6319
6710
|
}
|
|
6320
6711
|
}
|
|
@@ -6325,7 +6716,7 @@ var exactVersionRule = {
|
|
|
6325
6716
|
};
|
|
6326
6717
|
|
|
6327
6718
|
// eslint/rules/package-json/lint-setup.ts
|
|
6328
|
-
function
|
|
6719
|
+
function memberName4(member) {
|
|
6329
6720
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
6330
6721
|
}
|
|
6331
6722
|
function memberValue2(member) {
|
|
@@ -6367,9 +6758,9 @@ var lintSetupRule = {
|
|
|
6367
6758
|
Document(node) {
|
|
6368
6759
|
const root = node.body;
|
|
6369
6760
|
if (root.type !== "Object") return;
|
|
6370
|
-
const scripts = root.members.find((member) =>
|
|
6761
|
+
const scripts = root.members.find((member) => memberName4(member) === "scripts");
|
|
6371
6762
|
const scriptMembers = scripts?.value.type === "Object" ? scripts.value.members : [];
|
|
6372
|
-
const findScript = (name) => scriptMembers.find((member) =>
|
|
6763
|
+
const findScript = (name) => scriptMembers.find((member) => memberName4(member) === name);
|
|
6373
6764
|
const lint = findScript("lint");
|
|
6374
6765
|
const lintCommand = memberValue2(lint);
|
|
6375
6766
|
if (lintCommand === void 0 || !runsEslintDirectly(lintCommand) || !REPOSITORY_ARGUMENT_PATTERN.test(lintCommand)) {
|
|
@@ -6402,10 +6793,10 @@ var lintSetupRule = {
|
|
|
6402
6793
|
message: 'package.json must declare a "format:staged" script that runs prettier with no repository-wide argument (e.g. "prettier --write").'
|
|
6403
6794
|
});
|
|
6404
6795
|
}
|
|
6405
|
-
const lintStagedConfig = root.members.find((member) =>
|
|
6796
|
+
const lintStagedConfig = root.members.find((member) => memberName4(member) === "lint-staged");
|
|
6406
6797
|
const stagedMembers = lintStagedConfig?.value.type === "Object" ? lintStagedConfig.value.members : [];
|
|
6407
6798
|
const runsStagedScriptForGlob = (name, matchesGlob) => stagedMembers.some(
|
|
6408
|
-
(member) => matchesGlob(
|
|
6799
|
+
(member) => matchesGlob(memberName4(member)) && stringValues(member.value).some((command) => runsNamedScript(command, name))
|
|
6409
6800
|
);
|
|
6410
6801
|
const runsStagedScriptForExtension = (name, extension) => runsStagedScriptForGlob(name, (glob) => globIncludesExtension(glob, extension));
|
|
6411
6802
|
const hasStagedSourceLint = runsStagedScriptForGlob("lint:staged", (glob) => SOURCE_GLOB_PATTERN.test(glob));
|
|
@@ -6456,13 +6847,13 @@ var NEXTJS_STACK_DEV_DEPENDENCIES = [
|
|
|
6456
6847
|
"@testing-library/react",
|
|
6457
6848
|
"@testing-library/dom"
|
|
6458
6849
|
];
|
|
6459
|
-
function
|
|
6850
|
+
function memberName5(member) {
|
|
6460
6851
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
6461
6852
|
}
|
|
6462
6853
|
function sectionPackages(root, section) {
|
|
6463
|
-
const member = root.type === "Object" ? root.members.find((entry) =>
|
|
6854
|
+
const member = root.type === "Object" ? root.members.find((entry) => memberName5(entry) === section) : void 0;
|
|
6464
6855
|
if (member?.value.type !== "Object") return /* @__PURE__ */ new Set();
|
|
6465
|
-
return new Set(member.value.members.map(
|
|
6856
|
+
return new Set(member.value.members.map(memberName5));
|
|
6466
6857
|
}
|
|
6467
6858
|
var nextjsStackRule = {
|
|
6468
6859
|
meta: {
|
|
@@ -6499,9 +6890,9 @@ var nextjsStackRule = {
|
|
|
6499
6890
|
};
|
|
6500
6891
|
|
|
6501
6892
|
// eslint/rules/package-json/vitest-coverage.ts
|
|
6502
|
-
import { existsSync as
|
|
6503
|
-
import
|
|
6504
|
-
function
|
|
6893
|
+
import { existsSync as existsSync7, readFileSync as readFileSync12 } from "fs";
|
|
6894
|
+
import path47 from "path";
|
|
6895
|
+
function memberName6(member) {
|
|
6505
6896
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
6506
6897
|
}
|
|
6507
6898
|
function memberValue3(member) {
|
|
@@ -6539,9 +6930,9 @@ var vitestCoverageRule = {
|
|
|
6539
6930
|
Document(node) {
|
|
6540
6931
|
const root = node.body;
|
|
6541
6932
|
if (root.type !== "Object") return;
|
|
6542
|
-
const devDependencies = root.members.find((member) =>
|
|
6933
|
+
const devDependencies = root.members.find((member) => memberName6(member) === "devDependencies");
|
|
6543
6934
|
const devDependencyNames = new Set(
|
|
6544
|
-
devDependencies?.value.type === "Object" ? devDependencies.value.members.map(
|
|
6935
|
+
devDependencies?.value.type === "Object" ? devDependencies.value.members.map(memberName6) : []
|
|
6545
6936
|
);
|
|
6546
6937
|
if (!devDependencyNames.has("vitest")) {
|
|
6547
6938
|
context.report({ node, message: "vitest must be listed in package.json as a devDependency." });
|
|
@@ -6552,9 +6943,9 @@ var vitestCoverageRule = {
|
|
|
6552
6943
|
message: "@vitest/coverage-v8 must be listed in package.json as a devDependency."
|
|
6553
6944
|
});
|
|
6554
6945
|
}
|
|
6555
|
-
const scripts = root.members.find((member) =>
|
|
6946
|
+
const scripts = root.members.find((member) => memberName6(member) === "scripts");
|
|
6556
6947
|
const scriptMembers = scripts?.value.type === "Object" ? scripts.value.members : [];
|
|
6557
|
-
const unit = scriptMembers.find((member) =>
|
|
6948
|
+
const unit = scriptMembers.find((member) => memberName6(member) === "test:unit");
|
|
6558
6949
|
const unitCommand = memberValue3(unit);
|
|
6559
6950
|
if (unitCommand === void 0 || !/\bvitest\b/.test(unitCommand) || COVERAGE_FLAG_PATTERN.test(unitCommand)) {
|
|
6560
6951
|
context.report({
|
|
@@ -6562,7 +6953,7 @@ var vitestCoverageRule = {
|
|
|
6562
6953
|
message: 'package.json must declare a "test:unit" script that runs Vitest without coverage.'
|
|
6563
6954
|
});
|
|
6564
6955
|
}
|
|
6565
|
-
const coverage = scriptMembers.find((member) =>
|
|
6956
|
+
const coverage = scriptMembers.find((member) => memberName6(member) === "test:unit:coverage");
|
|
6566
6957
|
const coverageCommand = memberValue3(coverage);
|
|
6567
6958
|
if (coverageCommand === void 0 || !/\bvitest\b/.test(coverageCommand) || !COVERAGE_FLAG_PATTERN.test(coverageCommand)) {
|
|
6568
6959
|
context.report({
|
|
@@ -6570,7 +6961,7 @@ var vitestCoverageRule = {
|
|
|
6570
6961
|
message: 'package.json must declare a "test:unit:coverage" script that runs Vitest with coverage.'
|
|
6571
6962
|
});
|
|
6572
6963
|
}
|
|
6573
|
-
const configName = VITEST_CONFIG_NAMES.find((name) =>
|
|
6964
|
+
const configName = VITEST_CONFIG_NAMES.find((name) => existsSync7(path47.join(context.cwd, name)));
|
|
6574
6965
|
if (!configName) {
|
|
6575
6966
|
context.report({
|
|
6576
6967
|
node,
|
|
@@ -6578,7 +6969,7 @@ var vitestCoverageRule = {
|
|
|
6578
6969
|
});
|
|
6579
6970
|
return;
|
|
6580
6971
|
}
|
|
6581
|
-
const content =
|
|
6972
|
+
const content = readFileSync12(path47.join(context.cwd, configName), "utf8");
|
|
6582
6973
|
for (const metric of THRESHOLD_METRICS) {
|
|
6583
6974
|
if (!new RegExp(`\\b${metric}\\s*:\\s*[1-9]\\d*`).test(content)) {
|
|
6584
6975
|
context.report({ node, message: `${configName} must set a coverage threshold above zero for ${metric}.` });
|
|
@@ -6590,7 +6981,7 @@ var vitestCoverageRule = {
|
|
|
6590
6981
|
message: `${configName} must enable coverage.thresholds.autoUpdate with true or the monotonic 0.1-point buffered formatter.`
|
|
6591
6982
|
});
|
|
6592
6983
|
}
|
|
6593
|
-
const stagedTests = scriptMembers.find((member) =>
|
|
6984
|
+
const stagedTests = scriptMembers.find((member) => memberName6(member) === "test:unit:staged");
|
|
6594
6985
|
const stagedTestsCommand = memberValue3(stagedTests);
|
|
6595
6986
|
if (stagedTestsCommand === void 0 || !/\bvitest\b/.test(stagedTestsCommand) || !RELATED_PATTERN.test(stagedTestsCommand) || COVERAGE_FLAG_PATTERN.test(stagedTestsCommand)) {
|
|
6596
6987
|
context.report({
|
|
@@ -6598,9 +6989,9 @@ var vitestCoverageRule = {
|
|
|
6598
6989
|
message: 'package.json must declare a "test:unit:staged" script that runs vitest related without coverage.'
|
|
6599
6990
|
});
|
|
6600
6991
|
}
|
|
6601
|
-
const lintStaged = root.members.find((member) =>
|
|
6992
|
+
const lintStaged = root.members.find((member) => memberName6(member) === "lint-staged");
|
|
6602
6993
|
const hasStagedTests = lintStaged?.value.type === "Object" && lintStaged.value.members.some(
|
|
6603
|
-
(member) => SOURCE_GLOB_PATTERN2.test(
|
|
6994
|
+
(member) => SOURCE_GLOB_PATTERN2.test(memberName6(member)) && stringValues2(member.value).some((command) => command.includes("npm run test:unit:staged"))
|
|
6604
6995
|
);
|
|
6605
6996
|
if (!hasStagedTests) {
|
|
6606
6997
|
context.report({
|
|
@@ -6615,6 +7006,7 @@ var vitestCoverageRule = {
|
|
|
6615
7006
|
|
|
6616
7007
|
// eslint/rules/package-json/index.ts
|
|
6617
7008
|
var repoPackageJsonRules = {
|
|
7009
|
+
"ci-checks": ciChecksRule,
|
|
6618
7010
|
"exact-version": exactVersionRule,
|
|
6619
7011
|
"lint-setup": lintSetupRule,
|
|
6620
7012
|
"vitest-coverage": vitestCoverageRule
|
|
@@ -6624,8 +7016,8 @@ var nextjsPackageJsonRules = {
|
|
|
6624
7016
|
};
|
|
6625
7017
|
|
|
6626
7018
|
// eslint/rules/prefer-enum.ts
|
|
6627
|
-
import
|
|
6628
|
-
import
|
|
7019
|
+
import path48 from "path";
|
|
7020
|
+
import ts10 from "typescript";
|
|
6629
7021
|
function isConstAssertion(node) {
|
|
6630
7022
|
const typeAnnotation = node.typeAnnotation;
|
|
6631
7023
|
return typeAnnotation?.type === "TSTypeReference" && typeAnnotation.typeName?.type === "Identifier" && typeAnnotation.typeName.name === "const";
|
|
@@ -6647,7 +7039,7 @@ function isZodCall(node, method) {
|
|
|
6647
7039
|
const { callee } = node;
|
|
6648
7040
|
return callee?.type === "MemberExpression" && !callee.computed && callee.object.type === "Identifier" && callee.object.name === "z" && callee.property.type === "Identifier" && callee.property.name === method;
|
|
6649
7041
|
}
|
|
6650
|
-
function
|
|
7042
|
+
function propertyName5(property) {
|
|
6651
7043
|
if (property.computed) return void 0;
|
|
6652
7044
|
if (property.key.type === "Identifier") return property.key.name;
|
|
6653
7045
|
if (property.key.type === "Literal" && typeof property.key.value === "string") return property.key.value;
|
|
@@ -6658,7 +7050,7 @@ function rawZodDiscriminantLiteral(schemaCall, discriminator) {
|
|
|
6658
7050
|
const shape = schemaCall.arguments[0];
|
|
6659
7051
|
if (shape?.type !== "ObjectExpression") return void 0;
|
|
6660
7052
|
for (const property of shape.properties) {
|
|
6661
|
-
if (property.type !== "Property" ||
|
|
7053
|
+
if (property.type !== "Property" || propertyName5(property) !== discriminator) continue;
|
|
6662
7054
|
if (property.value.type !== "CallExpression" || !isZodCall(property.value, "literal")) return void 0;
|
|
6663
7055
|
const literal = property.value.arguments[0];
|
|
6664
7056
|
if (literal?.type === "Literal" && (typeof literal.value === "string" || typeof literal.value === "number")) {
|
|
@@ -6679,13 +7071,13 @@ function isLiteralTupleAssertion(node) {
|
|
|
6679
7071
|
return values.every((value) => value !== void 0) && new Set(values).size >= 2;
|
|
6680
7072
|
}
|
|
6681
7073
|
function isTsLiteralTupleDeclaration(declaration) {
|
|
6682
|
-
if (!
|
|
7074
|
+
if (!ts10.isVariableDeclaration(declaration) || !declaration.initializer) return false;
|
|
6683
7075
|
const init = declaration.initializer;
|
|
6684
|
-
if (!
|
|
7076
|
+
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
7077
|
return false;
|
|
6686
7078
|
}
|
|
6687
7079
|
const values = init.expression.elements.map(
|
|
6688
|
-
(element) =>
|
|
7080
|
+
(element) => ts10.isStringLiteral(element) || ts10.isNumericLiteral(element) ? element.text : void 0
|
|
6689
7081
|
);
|
|
6690
7082
|
return values.every((value) => value !== void 0) && new Set(values).size >= 2;
|
|
6691
7083
|
}
|
|
@@ -6698,9 +7090,9 @@ var preferEnumRule = {
|
|
|
6698
7090
|
}
|
|
6699
7091
|
},
|
|
6700
7092
|
create(context) {
|
|
6701
|
-
const filename =
|
|
7093
|
+
const filename = path48.resolve(context.filename);
|
|
6702
7094
|
const sourceRoot = sourceRootOf(context);
|
|
6703
|
-
if (!filename.startsWith(sourceRoot +
|
|
7095
|
+
if (!filename.startsWith(sourceRoot + path48.sep)) return {};
|
|
6704
7096
|
const objectSchemas = /* @__PURE__ */ new Map();
|
|
6705
7097
|
const literalTuples = /* @__PURE__ */ new Set();
|
|
6706
7098
|
const enumTupleUses = [];
|
|
@@ -6714,7 +7106,7 @@ var preferEnumRule = {
|
|
|
6714
7106
|
const checker = services.program.getTypeChecker();
|
|
6715
7107
|
const symbol = checker.getSymbolAtLocation(tsNode);
|
|
6716
7108
|
if (!symbol) return false;
|
|
6717
|
-
const original = symbol.flags ===
|
|
7109
|
+
const original = symbol.flags === ts10.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
6718
7110
|
return (original.declarations ?? []).some(isTsLiteralTupleDeclaration);
|
|
6719
7111
|
}
|
|
6720
7112
|
return {
|
|
@@ -6809,8 +7201,8 @@ var preferEnumRule = {
|
|
|
6809
7201
|
};
|
|
6810
7202
|
|
|
6811
7203
|
// eslint/rules/prefer-object-destructuring.ts
|
|
6812
|
-
import
|
|
6813
|
-
var
|
|
7204
|
+
import ts11 from "typescript";
|
|
7205
|
+
var DOC7 = "See docs/next-codebase-guide/rules/redundant-aliases-rule.md";
|
|
6814
7206
|
function hasTypeAnnotation(identifier) {
|
|
6815
7207
|
return "typeAnnotation" in identifier && identifier.typeAnnotation !== void 0;
|
|
6816
7208
|
}
|
|
@@ -6822,19 +7214,19 @@ function directPropertyBinding(context, declarator, isEnumValue) {
|
|
|
6822
7214
|
if (member.computed || member.optional || member.property.type !== "Identifier") return void 0;
|
|
6823
7215
|
if (!memberCanBecomeLocal(member)) return void 0;
|
|
6824
7216
|
if (context.sourceCode.getCommentsInside(declarator).length > 0) return void 0;
|
|
6825
|
-
const
|
|
7217
|
+
const propertyName6 = member.property.name;
|
|
6826
7218
|
const localName = declarator.id.name;
|
|
6827
|
-
if (
|
|
7219
|
+
if (propertyName6 !== localName) return void 0;
|
|
6828
7220
|
const source = member.object;
|
|
6829
7221
|
const sourceText = context.sourceCode.getText(source);
|
|
6830
7222
|
return {
|
|
6831
7223
|
declarator,
|
|
6832
7224
|
member,
|
|
6833
|
-
propertyName:
|
|
7225
|
+
propertyName: propertyName6,
|
|
6834
7226
|
localName,
|
|
6835
7227
|
source,
|
|
6836
7228
|
sourceText,
|
|
6837
|
-
bindingText:
|
|
7229
|
+
bindingText: propertyName6
|
|
6838
7230
|
};
|
|
6839
7231
|
}
|
|
6840
7232
|
function canGroupSource(source) {
|
|
@@ -6852,8 +7244,8 @@ function rootIdentifierName(node) {
|
|
|
6852
7244
|
if (node.type !== "MemberExpression" || node.object.type === "Super") return void 0;
|
|
6853
7245
|
return rootIdentifierName(node.object);
|
|
6854
7246
|
}
|
|
6855
|
-
function isCompliantLocalName(
|
|
6856
|
-
return !
|
|
7247
|
+
function isCompliantLocalName(propertyName6) {
|
|
7248
|
+
return !propertyName6.includes("_") || /^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$/u.test(propertyName6);
|
|
6857
7249
|
}
|
|
6858
7250
|
function propertyNameOf(node) {
|
|
6859
7251
|
if (node.type !== "Property" || node.computed) return void 0;
|
|
@@ -6902,8 +7294,8 @@ function enumValueResolver(context) {
|
|
|
6902
7294
|
const checker = services.program.getTypeChecker();
|
|
6903
7295
|
const { esTreeNodeToTSNodeMap: nodeMap } = services;
|
|
6904
7296
|
const isEnumSymbol = (symbol) => {
|
|
6905
|
-
const resolved = symbol.flags ===
|
|
6906
|
-
return (resolved.declarations ?? []).some((declaration) =>
|
|
7297
|
+
const resolved = symbol.flags === ts11.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
7298
|
+
return (resolved.declarations ?? []).some((declaration) => ts11.isEnumDeclaration(declaration));
|
|
6907
7299
|
};
|
|
6908
7300
|
return (node) => {
|
|
6909
7301
|
const tsNode = nodeMap.get(node);
|
|
@@ -6919,27 +7311,27 @@ function detachableCallResolver(context) {
|
|
|
6919
7311
|
if (!services) return () => false;
|
|
6920
7312
|
const checker = services.program.getTypeChecker();
|
|
6921
7313
|
const { esTreeNodeToTSNodeMap: nodeMap } = services;
|
|
6922
|
-
const isUnboundFunctionType = (type) =>
|
|
7314
|
+
const isUnboundFunctionType = (type) => ts11.isFunctionTypeNode(type) && !type.parameters.some((parameter) => ts11.isIdentifier(parameter.name) && parameter.name.text === "this");
|
|
6923
7315
|
return (member) => {
|
|
6924
7316
|
const node = nodeMap.get(member);
|
|
6925
|
-
if (!node || !
|
|
7317
|
+
if (!node || !ts11.isPropertyAccessExpression(node)) return false;
|
|
6926
7318
|
const symbol = checker.getSymbolAtLocation(node.name);
|
|
6927
7319
|
const declarations = symbol?.declarations;
|
|
6928
7320
|
if (!declarations?.length) return false;
|
|
6929
7321
|
return declarations.every((declaration) => {
|
|
6930
|
-
if (
|
|
6931
|
-
return declaration.type !== void 0 && isUnboundFunctionType(declaration.type) ||
|
|
7322
|
+
if (ts11.isPropertySignature(declaration) || ts11.isPropertyDeclaration(declaration)) {
|
|
7323
|
+
return declaration.type !== void 0 && isUnboundFunctionType(declaration.type) || ts11.isPropertyDeclaration(declaration) && declaration.initializer !== void 0 && ts11.isArrowFunction(declaration.initializer);
|
|
6932
7324
|
}
|
|
6933
|
-
if (
|
|
7325
|
+
if (ts11.isPropertyAssignment(declaration)) return ts11.isArrowFunction(declaration.initializer);
|
|
6934
7326
|
return false;
|
|
6935
7327
|
});
|
|
6936
7328
|
};
|
|
6937
7329
|
}
|
|
6938
7330
|
function directMappingRequiresQualifiedAccess(context, ownershipResolver, member) {
|
|
6939
|
-
const
|
|
6940
|
-
if (!
|
|
6941
|
-
const sourceResolution = ownershipResolver.sourceMember(
|
|
6942
|
-
const targetResolution = ownershipResolver.targetProperty(
|
|
7331
|
+
const mapping2 = renamedDirectMapping(context, member);
|
|
7332
|
+
if (!mapping2 || !ownershipResolver) return false;
|
|
7333
|
+
const sourceResolution = ownershipResolver.sourceMember(mapping2.sourceMember);
|
|
7334
|
+
const targetResolution = ownershipResolver.targetProperty(mapping2.property, mapping2.targetName);
|
|
6943
7335
|
return sourceResolution.kind === "data-contract" || targetResolution.kind === "data-contract";
|
|
6944
7336
|
}
|
|
6945
7337
|
function memberCanBeDestructured(context, ownershipResolver, member, isEnumValue) {
|
|
@@ -6975,10 +7367,10 @@ function recordMemberUsage(context, scope, ownershipResolver, member, isEnumValu
|
|
|
6975
7367
|
if (!isGroupedUsageSource(member.object) || !memberIsRead(context, member, detachableCall)) return;
|
|
6976
7368
|
const sourceText = context.sourceCode.getText(member.object);
|
|
6977
7369
|
const usage = objectUsage(scope, sourceText);
|
|
6978
|
-
const
|
|
6979
|
-
usage.propertyNames.add(
|
|
7370
|
+
const propertyName6 = member.property.name;
|
|
7371
|
+
usage.propertyNames.add(propertyName6);
|
|
6980
7372
|
if (!memberIsDirectVariableInitializer(context, member)) {
|
|
6981
|
-
usage.directMembers.push({ member, propertyName:
|
|
7373
|
+
usage.directMembers.push({ member, propertyName: propertyName6 });
|
|
6982
7374
|
}
|
|
6983
7375
|
}
|
|
6984
7376
|
function recordDestructuringUsage(context, scope, declaration, isEnumValue) {
|
|
@@ -7001,7 +7393,7 @@ function recordDestructuringUsage(context, scope, declaration, isEnumValue) {
|
|
|
7001
7393
|
}
|
|
7002
7394
|
function scopeUsageMessage(sourceText, propertyNames) {
|
|
7003
7395
|
const names = [...propertyNames].map((name) => `"${name}"`).join(", ");
|
|
7004
|
-
return `${names} are read from "${sourceText}" in the same block. Destructure them together in one declaration. ${
|
|
7396
|
+
return `${names} are read from "${sourceText}" in the same block. Destructure them together in one declaration. ${DOC7}`;
|
|
7005
7397
|
}
|
|
7006
7398
|
function hasBinding(context, node, name) {
|
|
7007
7399
|
const initialScope = context.sourceCode.getScope(node);
|
|
@@ -7105,13 +7497,13 @@ function groupedDestructuringSelections(context, first, isEnumValue) {
|
|
|
7105
7497
|
if (!previous || nextNode?.type !== "VariableDeclaration" || nextNode.kind !== first.declaration.kind) break;
|
|
7106
7498
|
const next = destructuringSelection(context, nextNode, isEnumValue);
|
|
7107
7499
|
if (next?.sourceText !== first.sourceText) break;
|
|
7108
|
-
if (next.propertyNames.some((
|
|
7500
|
+
if (next.propertyNames.some((propertyName6) => seenProperties.has(propertyName6))) break;
|
|
7109
7501
|
const [, previousEnd] = context.sourceCode.getRange(previous);
|
|
7110
7502
|
const [nextStart] = context.sourceCode.getRange(nextNode);
|
|
7111
7503
|
const gap = context.sourceCode.text.slice(previousEnd, nextStart);
|
|
7112
7504
|
if (!whitespaceKeepsStatementsAdjacent(gap)) break;
|
|
7113
7505
|
group.push(next);
|
|
7114
|
-
for (const
|
|
7506
|
+
for (const propertyName6 of next.propertyNames) seenProperties.add(propertyName6);
|
|
7115
7507
|
}
|
|
7116
7508
|
return group;
|
|
7117
7509
|
}
|
|
@@ -7119,19 +7511,19 @@ function declarationTerminator(context, declaration) {
|
|
|
7119
7511
|
return context.sourceCode.getText(declaration).trimEnd().endsWith(";") ? ";" : "";
|
|
7120
7512
|
}
|
|
7121
7513
|
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. ${
|
|
7514
|
+
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
7515
|
}
|
|
7124
7516
|
function groupMessage(bindings) {
|
|
7125
7517
|
const firstBinding = bindings[0];
|
|
7126
|
-
if (!firstBinding) return `Use one object destructuring declaration. ${
|
|
7518
|
+
if (!firstBinding) return `Use one object destructuring declaration. ${DOC7}`;
|
|
7127
7519
|
const names = bindings.map(({ localName }) => `"${localName}"`).join(", ");
|
|
7128
|
-
return `${names} are derived directly from properties of "${firstBinding.sourceText}". Use one object destructuring declaration. ${
|
|
7520
|
+
return `${names} are derived directly from properties of "${firstBinding.sourceText}". Use one object destructuring declaration. ${DOC7}`;
|
|
7129
7521
|
}
|
|
7130
7522
|
function repeatedDestructuringMessage(group) {
|
|
7131
7523
|
const first = group[0];
|
|
7132
|
-
if (!first) return `Combine repeated destructuring into one declaration. ${
|
|
7524
|
+
if (!first) return `Combine repeated destructuring into one declaration. ${DOC7}`;
|
|
7133
7525
|
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. ${
|
|
7526
|
+
return `${names} destructure the same source "${first.sourceText}" repeatedly. Combine them into one object destructuring declaration. ${DOC7}`;
|
|
7135
7527
|
}
|
|
7136
7528
|
var preferObjectDestructuringRule = {
|
|
7137
7529
|
meta: {
|
|
@@ -7165,9 +7557,9 @@ var preferObjectDestructuringRule = {
|
|
|
7165
7557
|
const { member: firstDirectMember } = firstDirectUsage;
|
|
7166
7558
|
const propertyNames = [...usage.propertyNames];
|
|
7167
7559
|
const missingPropertyNames = propertyNames.filter(
|
|
7168
|
-
(
|
|
7560
|
+
(propertyName6) => !usage.destructuring?.propertyNames.has(propertyName6)
|
|
7169
7561
|
);
|
|
7170
|
-
if (missingPropertyNames.some((
|
|
7562
|
+
if (missingPropertyNames.some((propertyName6) => hasBinding(context, firstDirectMember, propertyName6))) {
|
|
7171
7563
|
continue;
|
|
7172
7564
|
}
|
|
7173
7565
|
context.report({
|
|
@@ -7181,7 +7573,7 @@ var preferObjectDestructuringRule = {
|
|
|
7181
7573
|
return null;
|
|
7182
7574
|
}
|
|
7183
7575
|
const memberFixes = usage.directMembers.map(
|
|
7184
|
-
({ member, propertyName:
|
|
7576
|
+
({ member, propertyName: propertyName6 }) => fixer.replaceText(member, propertyName6)
|
|
7185
7577
|
);
|
|
7186
7578
|
if (usage.destructuring) {
|
|
7187
7579
|
if (missingPropertyNames.length === 0) return memberFixes;
|
|
@@ -7220,7 +7612,7 @@ ${indentation}`;
|
|
|
7220
7612
|
continue;
|
|
7221
7613
|
}
|
|
7222
7614
|
if (fromSameSource.length > 1) {
|
|
7223
|
-
const names = new Set(fromSameSource.map(({ propertyName:
|
|
7615
|
+
const names = new Set(fromSameSource.map(({ propertyName: propertyName6 }) => propertyName6));
|
|
7224
7616
|
if (names.size > 1) {
|
|
7225
7617
|
context.report({ node: binding.node, message: scopeUsageMessage(binding.sourceText, names) });
|
|
7226
7618
|
continue;
|
|
@@ -7249,7 +7641,7 @@ ${indentation}`;
|
|
|
7249
7641
|
const sourceText = context.sourceCode.getText(declarator.init);
|
|
7250
7642
|
context.report({
|
|
7251
7643
|
node: declarator.id,
|
|
7252
|
-
message: `"${sourceText}" is an enum. Keep enum member accesses qualified instead of destructuring it. ${
|
|
7644
|
+
message: `"${sourceText}" is an enum. Keep enum member accesses qualified instead of destructuring it. ${DOC7}`
|
|
7253
7645
|
});
|
|
7254
7646
|
}
|
|
7255
7647
|
recordDestructuringUsage(context, currentUsageScope(), node, isEnumValue);
|
|
@@ -7260,12 +7652,12 @@ ${indentation}`;
|
|
|
7260
7652
|
if (group.length <= 1) {
|
|
7261
7653
|
if (node.kind === "const" && selection.propertyNames.length === 1 && supportsSinglePropertySource(selection.source)) {
|
|
7262
7654
|
const declarator = node.declarations[0];
|
|
7263
|
-
const
|
|
7264
|
-
if (declarator &&
|
|
7655
|
+
const propertyName6 = selection.propertyNames[0];
|
|
7656
|
+
if (declarator && propertyName6) {
|
|
7265
7657
|
currentUsageScope()?.singleProperties.push({
|
|
7266
7658
|
node: declarator.id,
|
|
7267
7659
|
sourceText: selection.sourceText,
|
|
7268
|
-
propertyName:
|
|
7660
|
+
propertyName: propertyName6
|
|
7269
7661
|
});
|
|
7270
7662
|
}
|
|
7271
7663
|
}
|
|
@@ -7295,7 +7687,7 @@ ${indentation}`;
|
|
|
7295
7687
|
if (bindings.length === 0) return;
|
|
7296
7688
|
const firstBinding = bindings[0];
|
|
7297
7689
|
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:
|
|
7690
|
+
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
7691
|
if (sameSourceBindings) {
|
|
7300
7692
|
context.report({
|
|
7301
7693
|
node,
|
|
@@ -7350,7 +7742,7 @@ ${indentation}`;
|
|
|
7350
7742
|
};
|
|
7351
7743
|
|
|
7352
7744
|
// eslint/rules/pure-function-extract.ts
|
|
7353
|
-
import
|
|
7745
|
+
import path49 from "path";
|
|
7354
7746
|
var ROUTE_HANDLER_EXPORT_NAMES = /* @__PURE__ */ new Set([
|
|
7355
7747
|
"GET",
|
|
7356
7748
|
"POST",
|
|
@@ -7415,12 +7807,12 @@ var pureFunctionExtractRule = {
|
|
|
7415
7807
|
},
|
|
7416
7808
|
create(context) {
|
|
7417
7809
|
const filename = context.filename;
|
|
7418
|
-
const isRouteFile =
|
|
7810
|
+
const isRouteFile = path49.basename(filename) === "route.ts";
|
|
7419
7811
|
const isComponentFile = filename.endsWith(".tsx") || filename.endsWith(".jsx");
|
|
7420
7812
|
const sourceRoot = sourceRootOf(context);
|
|
7421
|
-
const relative =
|
|
7813
|
+
const relative = path49.relative(sourceRoot, filename);
|
|
7422
7814
|
if (relative.startsWith("..")) return {};
|
|
7423
|
-
const segments = relative.split(
|
|
7815
|
+
const segments = relative.split(path49.sep);
|
|
7424
7816
|
const folders = segments.slice(0, -1);
|
|
7425
7817
|
const isHookSupportFile = folders.includes("hooks") && /\.(?:[cm]?[jt]s)$/.test(filename);
|
|
7426
7818
|
if (!isComponentFile && !isRouteFile && !isHookSupportFile) return {};
|
|
@@ -7480,15 +7872,15 @@ var pureFunctionExtractRule = {
|
|
|
7480
7872
|
};
|
|
7481
7873
|
|
|
7482
7874
|
// eslint/rules/repeated-numeric-value.ts
|
|
7483
|
-
import
|
|
7875
|
+
import path50 from "path";
|
|
7484
7876
|
function isNonProductionFile(file, sourceRoot) {
|
|
7485
|
-
const relative =
|
|
7486
|
-
const segments = relative.split(
|
|
7487
|
-
const basename =
|
|
7877
|
+
const relative = path50.relative(sourceRoot, file);
|
|
7878
|
+
const segments = relative.split(path50.sep);
|
|
7879
|
+
const basename = path50.basename(file);
|
|
7488
7880
|
return /\.(?:test|spec|mock)\.[^.]+$/.test(basename) || segments.some((segment) => segment === "__tests__" || segment === "__mocks__" || segment === "mocks");
|
|
7489
7881
|
}
|
|
7490
7882
|
function isCanonicalConstantFile(file, sourceRoot) {
|
|
7491
|
-
const segments =
|
|
7883
|
+
const segments = path50.relative(sourceRoot, file).split(path50.sep);
|
|
7492
7884
|
return segments.includes("constants") || segments[0] === "config";
|
|
7493
7885
|
}
|
|
7494
7886
|
function groupKey(literal) {
|
|
@@ -7504,7 +7896,7 @@ var repeatedNumericValueRule = {
|
|
|
7504
7896
|
},
|
|
7505
7897
|
create(context) {
|
|
7506
7898
|
const sourceRoot = sourceRootOf(context);
|
|
7507
|
-
const file =
|
|
7899
|
+
const file = path50.resolve(context.filename);
|
|
7508
7900
|
if (isNonProductionFile(file, sourceRoot) || isCanonicalConstantFile(file, sourceRoot)) return {};
|
|
7509
7901
|
const index = getProjectIndex(sourceRoot);
|
|
7510
7902
|
if (!index) return {};
|
|
@@ -7541,11 +7933,11 @@ var repeatedNumericValueRule = {
|
|
|
7541
7933
|
};
|
|
7542
7934
|
|
|
7543
7935
|
// eslint/rules/repeated-semantic-literal.ts
|
|
7544
|
-
import
|
|
7936
|
+
import path52 from "path";
|
|
7545
7937
|
|
|
7546
7938
|
// eslint/rules/imported-enum-literals.ts
|
|
7547
|
-
import
|
|
7548
|
-
import
|
|
7939
|
+
import path51 from "path";
|
|
7940
|
+
import ts12 from "typescript";
|
|
7549
7941
|
var columnMethods2 = /* @__PURE__ */ new Set([
|
|
7550
7942
|
"eq",
|
|
7551
7943
|
"neq",
|
|
@@ -7561,13 +7953,13 @@ var columnMethods2 = /* @__PURE__ */ new Set([
|
|
|
7561
7953
|
"filter",
|
|
7562
7954
|
"not"
|
|
7563
7955
|
]);
|
|
7564
|
-
function
|
|
7565
|
-
if (
|
|
7956
|
+
function memberName7(name) {
|
|
7957
|
+
if (ts12.isIdentifier(name) || ts12.isStringLiteral(name)) return name.text;
|
|
7566
7958
|
return void 0;
|
|
7567
7959
|
}
|
|
7568
7960
|
function isWithin3(root, file) {
|
|
7569
|
-
const relative =
|
|
7570
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
7961
|
+
const relative = path51.relative(root, file);
|
|
7962
|
+
return relative === "" || !relative.startsWith("..") && !path51.isAbsolute(relative);
|
|
7571
7963
|
}
|
|
7572
7964
|
function domainOf(name) {
|
|
7573
7965
|
if (name.endsWith("ColumnEnum")) return "column";
|
|
@@ -7577,23 +7969,23 @@ function domainOf(name) {
|
|
|
7577
7969
|
function importedEnums(file, checker, sourceRoot, importedNames) {
|
|
7578
7970
|
const matches = /* @__PURE__ */ new Map();
|
|
7579
7971
|
for (const statement of file.statements) {
|
|
7580
|
-
if (!
|
|
7972
|
+
if (!ts12.isImportDeclaration(statement) || !statement.importClause?.namedBindings || !ts12.isNamedImports(statement.importClause.namedBindings)) {
|
|
7581
7973
|
continue;
|
|
7582
7974
|
}
|
|
7583
7975
|
for (const specifier of statement.importClause.namedBindings.elements) {
|
|
7584
7976
|
if (!importedNames.has(specifier.name.text)) continue;
|
|
7585
7977
|
const symbol = checker.getSymbolAtLocation(specifier.name);
|
|
7586
7978
|
if (!symbol) continue;
|
|
7587
|
-
const resolved = symbol.flags ===
|
|
7979
|
+
const resolved = symbol.flags === ts12.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
7588
7980
|
for (const declaration of resolved.declarations ?? []) {
|
|
7589
|
-
if (!
|
|
7590
|
-
const declarationFile =
|
|
7981
|
+
if (!ts12.isEnumDeclaration(declaration)) continue;
|
|
7982
|
+
const declarationFile = path51.resolve(declaration.getSourceFile().fileName);
|
|
7591
7983
|
if (!isWithin3(sourceRoot, declarationFile)) continue;
|
|
7592
7984
|
const domain = domainOf(declaration.name.text);
|
|
7593
7985
|
if (!domain) continue;
|
|
7594
7986
|
for (const member of declaration.members) {
|
|
7595
|
-
if (!member.initializer || !
|
|
7596
|
-
const name =
|
|
7987
|
+
if (!member.initializer || !ts12.isStringLiteral(member.initializer)) continue;
|
|
7988
|
+
const name = memberName7(member.name);
|
|
7597
7989
|
if (!name) continue;
|
|
7598
7990
|
const entries = matches.get(member.initializer.text) ?? [];
|
|
7599
7991
|
entries.push({
|
|
@@ -7609,25 +8001,25 @@ function importedEnums(file, checker, sourceRoot, importedNames) {
|
|
|
7609
8001
|
return matches;
|
|
7610
8002
|
}
|
|
7611
8003
|
function isPathname2(node) {
|
|
7612
|
-
return
|
|
8004
|
+
return ts12.isPropertyAccessExpression(node) && node.name.text === "pathname";
|
|
7613
8005
|
}
|
|
7614
8006
|
function domainForUse(node) {
|
|
7615
8007
|
const parent = node.parent;
|
|
7616
|
-
if (
|
|
8008
|
+
if (ts12.isPropertyAssignment(parent) && parent.initializer === node && memberName7(parent.name) === "path") {
|
|
7617
8009
|
return "route";
|
|
7618
8010
|
}
|
|
7619
|
-
if (
|
|
8011
|
+
if (ts12.isCallExpression(parent) && parent.arguments[0] === node && ts12.isPropertyAccessExpression(parent.expression)) {
|
|
7620
8012
|
const { expression, name } = parent.expression;
|
|
7621
8013
|
if (columnMethods2.has(name.text)) return "column";
|
|
7622
8014
|
if (name.text === "startsWith" && isPathname2(expression)) return "route";
|
|
7623
8015
|
}
|
|
7624
|
-
if (
|
|
8016
|
+
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
8017
|
return "route";
|
|
7626
8018
|
}
|
|
7627
8019
|
return void 0;
|
|
7628
8020
|
}
|
|
7629
8021
|
function importedEnumLiteralUses(context, root) {
|
|
7630
|
-
const filename =
|
|
8022
|
+
const filename = path51.resolve(context.filename);
|
|
7631
8023
|
if (!isWithin3(root, filename)) return [];
|
|
7632
8024
|
const services = typedParserServices(context.sourceCode.parserServices);
|
|
7633
8025
|
if (!services) return [];
|
|
@@ -7643,7 +8035,7 @@ function importedEnumLiteralUses(context, root) {
|
|
|
7643
8035
|
if (matches.size === 0) return [];
|
|
7644
8036
|
const uses = [];
|
|
7645
8037
|
const visit = (node) => {
|
|
7646
|
-
if (
|
|
8038
|
+
if (ts12.isStringLiteral(node)) {
|
|
7647
8039
|
const domain = domainForUse(node);
|
|
7648
8040
|
const candidates = matches.get(node.text)?.filter((entry) => entry.domain === domain) ?? [];
|
|
7649
8041
|
if (candidates.length === 1) {
|
|
@@ -7660,14 +8052,14 @@ function importedEnumLiteralUses(context, root) {
|
|
|
7660
8052
|
}
|
|
7661
8053
|
}
|
|
7662
8054
|
}
|
|
7663
|
-
|
|
8055
|
+
ts12.forEachChild(node, visit);
|
|
7664
8056
|
};
|
|
7665
8057
|
visit(file);
|
|
7666
8058
|
return uses;
|
|
7667
8059
|
}
|
|
7668
8060
|
|
|
7669
8061
|
// eslint/rules/repeated-semantic-literal.ts
|
|
7670
|
-
var
|
|
8062
|
+
var DOC8 = "See docs/next-codebase-guide/rules/constants-rule.md";
|
|
7671
8063
|
var closedDomainFamilies = /* @__PURE__ */ new Set(["api-route", "event", "storage"]);
|
|
7672
8064
|
function canonicalMatches(use, canonical, sourceRoot) {
|
|
7673
8065
|
if (use.kind !== canonical.kind || use.value !== canonical.value) return false;
|
|
@@ -7681,7 +8073,7 @@ function canonicalMatches(use, canonical, sourceRoot) {
|
|
|
7681
8073
|
const semanticName2 = use.family.split(":")[1];
|
|
7682
8074
|
if (!semanticName2 || !name.toLowerCase().includes(semanticName2.toLowerCase())) return false;
|
|
7683
8075
|
const location = featureOf(canonical.file, sourceRoot);
|
|
7684
|
-
return location === featureOf(use.file, sourceRoot) ||
|
|
8076
|
+
return location === featureOf(use.file, sourceRoot) || path52.relative(sourceRoot, canonical.file).split(path52.sep)[0] === "constants";
|
|
7685
8077
|
}
|
|
7686
8078
|
return false;
|
|
7687
8079
|
}
|
|
@@ -7695,14 +8087,14 @@ function messageFor(use, matches, duplicateRouteDomains, existingRouteEnum, root
|
|
|
7695
8087
|
const count = new Set(matches.map((match) => match.file)).size;
|
|
7696
8088
|
const kind = use.kind === "string" ? "string" : "numeric";
|
|
7697
8089
|
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. ${
|
|
8090
|
+
const location = path52.relative(root, existingRouteEnum.file).replaceAll(path52.sep, "/");
|
|
8091
|
+
return `The route ${formatValue(use)} repeats; add a member to existing ${existingRouteEnum.owner} in src/${location} and reuse it. ${DOC8}`;
|
|
7700
8092
|
}
|
|
7701
8093
|
if (count === 1) {
|
|
7702
|
-
return `The ${kind} literal ${formatValue(use)} repeats in the same semantic role in this file. Extract a file-local const. ${
|
|
8094
|
+
return `The ${kind} literal ${formatValue(use)} repeats in the same semantic role in this file. Extract a file-local const. ${DOC8}`;
|
|
7703
8095
|
}
|
|
7704
8096
|
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. ${
|
|
8097
|
+
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
8098
|
}
|
|
7707
8099
|
var repeatedSemanticLiteralRule = {
|
|
7708
8100
|
meta: {
|
|
@@ -7714,7 +8106,7 @@ var repeatedSemanticLiteralRule = {
|
|
|
7714
8106
|
},
|
|
7715
8107
|
create(context) {
|
|
7716
8108
|
const root = sourceRootOf(context);
|
|
7717
|
-
const file =
|
|
8109
|
+
const file = path52.resolve(context.filename);
|
|
7718
8110
|
if (!isProductionSource(file, root)) return {};
|
|
7719
8111
|
const project = getProjectIndex(root);
|
|
7720
8112
|
if (!project?.modules.has(file)) return {};
|
|
@@ -7759,11 +8151,11 @@ var repeatedSemanticLiteralRule = {
|
|
|
7759
8151
|
return {
|
|
7760
8152
|
Program(node) {
|
|
7761
8153
|
for (const use of imported) {
|
|
7762
|
-
const relative =
|
|
8154
|
+
const relative = path52.relative(root, use.sourceFile).replaceAll(path52.sep, "/");
|
|
7763
8155
|
context.report({
|
|
7764
8156
|
node,
|
|
7765
8157
|
loc: { line: use.line, column: use.column },
|
|
7766
|
-
message: `Reuse ${use.reference} from src/${relative} instead of raw ${JSON.stringify(use.value)}. ${
|
|
8158
|
+
message: `Reuse ${use.reference} from src/${relative} instead of raw ${JSON.stringify(use.value)}. ${DOC8}`
|
|
7767
8159
|
});
|
|
7768
8160
|
}
|
|
7769
8161
|
for (const use of current) {
|
|
@@ -7774,11 +8166,11 @@ var repeatedSemanticLiteralRule = {
|
|
|
7774
8166
|
if (candidates.length === 1) {
|
|
7775
8167
|
const canonical = candidates[0];
|
|
7776
8168
|
if (!canonical) continue;
|
|
7777
|
-
const relative =
|
|
8169
|
+
const relative = path52.relative(root, canonical.file).replaceAll(path52.sep, "/");
|
|
7778
8170
|
context.report({
|
|
7779
8171
|
node,
|
|
7780
8172
|
loc: { line: use.line, column: use.column },
|
|
7781
|
-
message: `Reuse ${canonicalName(canonical)} from src/${relative} instead of raw ${formatValue(use)}. ${
|
|
8173
|
+
message: `Reuse ${canonicalName(canonical)} from src/${relative} instead of raw ${formatValue(use)}. ${DOC8}`
|
|
7782
8174
|
});
|
|
7783
8175
|
continue;
|
|
7784
8176
|
}
|
|
@@ -7787,11 +8179,11 @@ var repeatedSemanticLiteralRule = {
|
|
|
7787
8179
|
const peers = groups.get(key) ?? [];
|
|
7788
8180
|
if (peers.length < 2) {
|
|
7789
8181
|
if (use.family === "api-route" && existingRouteEnum?.owner) {
|
|
7790
|
-
const location =
|
|
8182
|
+
const location = path52.relative(root, existingRouteEnum.file).replaceAll(path52.sep, "/");
|
|
7791
8183
|
context.report({
|
|
7792
8184
|
node,
|
|
7793
8185
|
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. ${
|
|
8186
|
+
message: `The route ${formatValue(use)} belongs to existing ${existingRouteEnum.owner}; add a member in src/${location} and reuse it. ${DOC8}`
|
|
7795
8187
|
});
|
|
7796
8188
|
continue;
|
|
7797
8189
|
}
|
|
@@ -7800,7 +8192,7 @@ var repeatedSemanticLiteralRule = {
|
|
|
7800
8192
|
context.report({
|
|
7801
8193
|
node,
|
|
7802
8194
|
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. ${
|
|
8195
|
+
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
8196
|
});
|
|
7805
8197
|
}
|
|
7806
8198
|
continue;
|
|
@@ -7999,7 +8391,7 @@ var repeatedStructureRule = {
|
|
|
7999
8391
|
|
|
8000
8392
|
// eslint/rules/require-barrel-star-exports.ts
|
|
8001
8393
|
import fs5 from "fs";
|
|
8002
|
-
import
|
|
8394
|
+
import path53 from "path";
|
|
8003
8395
|
var SUPPORT_FOLDERS3 = /* @__PURE__ */ new Set(["constants", "types", "schemas"]);
|
|
8004
8396
|
var INDEX_NAMES = /* @__PURE__ */ new Set(["index.ts", "index.tsx", "index.mts", "index.cts"]);
|
|
8005
8397
|
var MODULE_EXTENSIONS3 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
@@ -8007,9 +8399,9 @@ function resolveSiblingModule(indexFile, specifier) {
|
|
|
8007
8399
|
if (!specifier.startsWith("./")) return void 0;
|
|
8008
8400
|
const relative = specifier.slice(2);
|
|
8009
8401
|
if (!relative || relative.includes("/")) return void 0;
|
|
8010
|
-
const directory =
|
|
8011
|
-
const direct =
|
|
8012
|
-
const candidates =
|
|
8402
|
+
const directory = path53.dirname(indexFile);
|
|
8403
|
+
const direct = path53.resolve(directory, relative);
|
|
8404
|
+
const candidates = path53.extname(direct) ? [direct] : MODULE_EXTENSIONS3.map((extension) => `${direct}${extension}`);
|
|
8013
8405
|
return candidates.find((candidate) => fs5.existsSync(candidate) && fs5.statSync(candidate).isFile());
|
|
8014
8406
|
}
|
|
8015
8407
|
var requireBarrelStarExportsRule = {
|
|
@@ -8022,9 +8414,9 @@ var requireBarrelStarExportsRule = {
|
|
|
8022
8414
|
fixable: "code"
|
|
8023
8415
|
},
|
|
8024
8416
|
create(context) {
|
|
8025
|
-
const filename =
|
|
8026
|
-
if (!INDEX_NAMES.has(
|
|
8027
|
-
if (!SUPPORT_FOLDERS3.has(
|
|
8417
|
+
const filename = path53.resolve(context.filename);
|
|
8418
|
+
if (!INDEX_NAMES.has(path53.basename(filename))) return {};
|
|
8419
|
+
if (!SUPPORT_FOLDERS3.has(path53.basename(path53.dirname(filename)))) return {};
|
|
8028
8420
|
return {
|
|
8029
8421
|
ExportNamedDeclaration(node) {
|
|
8030
8422
|
const sourceNode = node.source;
|
|
@@ -8077,7 +8469,7 @@ var requireBarrelStarExportsRule = {
|
|
|
8077
8469
|
};
|
|
8078
8470
|
|
|
8079
8471
|
// eslint/rules/root-support-placement.ts
|
|
8080
|
-
import
|
|
8472
|
+
import path54 from "path";
|
|
8081
8473
|
function isSupportFolder(value) {
|
|
8082
8474
|
return value === "utils" || value === "types" || value === "schemas" || value === "constants";
|
|
8083
8475
|
}
|
|
@@ -8110,7 +8502,7 @@ var rootSupportPlacementRule = {
|
|
|
8110
8502
|
},
|
|
8111
8503
|
create(context) {
|
|
8112
8504
|
const sourceRoot = sourceRootOf(context);
|
|
8113
|
-
const file =
|
|
8505
|
+
const file = path54.resolve(context.filename);
|
|
8114
8506
|
const segments = segmentsOf(file, sourceRoot);
|
|
8115
8507
|
const folderSegments = folderSegmentsOf(file, sourceRoot);
|
|
8116
8508
|
const supportFolder = folderSegments[folderSegments.length - 1];
|
|
@@ -8156,8 +8548,104 @@ var rootSupportPlacementRule = {
|
|
|
8156
8548
|
};
|
|
8157
8549
|
|
|
8158
8550
|
// eslint/rules/route-handler-shape.ts
|
|
8159
|
-
import
|
|
8160
|
-
import
|
|
8551
|
+
import path56 from "path";
|
|
8552
|
+
import ts13 from "typescript";
|
|
8553
|
+
|
|
8554
|
+
// eslint/rules/route-single-use-delegation.ts
|
|
8555
|
+
import path55 from "path";
|
|
8556
|
+
function responseCall(expression) {
|
|
8557
|
+
if (!expression) return void 0;
|
|
8558
|
+
if (expression.type === "AwaitExpression") return responseCall(expression.argument);
|
|
8559
|
+
if (expression.type === "CallExpression" && expression.callee.type === "Identifier") return expression;
|
|
8560
|
+
if (expression.type !== "ObjectExpression") return void 0;
|
|
8561
|
+
const dataProperties = expression.properties.filter(
|
|
8562
|
+
(property) => property.type === "Property" && !property.computed && (property.key.type === "Identifier" && property.key.name === "data" || property.key.type === "Literal" && property.key.value === "data")
|
|
8563
|
+
);
|
|
8564
|
+
if (dataProperties.length !== 1) return void 0;
|
|
8565
|
+
const otherProperties = expression.properties.filter((property) => !dataProperties.includes(property));
|
|
8566
|
+
if (otherProperties.some(
|
|
8567
|
+
(property) => property.type !== "Property" || property.value.type !== "Literal" || property.computed
|
|
8568
|
+
)) {
|
|
8569
|
+
return void 0;
|
|
8570
|
+
}
|
|
8571
|
+
return responseCall(dataProperties[0]?.type === "Property" ? dataProperties[0].value : void 0);
|
|
8572
|
+
}
|
|
8573
|
+
function soleDelegation(handler) {
|
|
8574
|
+
if (handler.body.type !== "BlockStatement") return responseCall(handler.body);
|
|
8575
|
+
const statements = handler.body.body;
|
|
8576
|
+
if (statements.length === 1 && statements[0]?.type === "ReturnStatement") {
|
|
8577
|
+
return responseCall(statements[0].argument);
|
|
8578
|
+
}
|
|
8579
|
+
const [declaration, returned] = statements;
|
|
8580
|
+
if (statements.length !== 2 || declaration?.type !== "VariableDeclaration" || declaration.declarations.length !== 1 || returned?.type !== "ReturnStatement") {
|
|
8581
|
+
return void 0;
|
|
8582
|
+
}
|
|
8583
|
+
const variable = declaration.declarations[0];
|
|
8584
|
+
if (variable?.id.type !== "Identifier") return void 0;
|
|
8585
|
+
const call = responseCall(variable.init);
|
|
8586
|
+
if (!call || !returned.argument) return void 0;
|
|
8587
|
+
if (returned.argument.type === "Identifier" && returned.argument.name === variable.id.name) return call;
|
|
8588
|
+
if (returned.argument.type !== "ObjectExpression") return void 0;
|
|
8589
|
+
const properties = returned.argument.properties;
|
|
8590
|
+
if (properties.length !== 1 || properties[0]?.type !== "Property") return void 0;
|
|
8591
|
+
const property = properties[0];
|
|
8592
|
+
const key = property.key;
|
|
8593
|
+
const isData = !property.computed && (key.type === "Identifier" && key.name === "data" || key.type === "Literal" && key.value === "data");
|
|
8594
|
+
return isData && property.value.type === "Identifier" && property.value.name === variable.id.name ? call : void 0;
|
|
8595
|
+
}
|
|
8596
|
+
function isTestFile2(file) {
|
|
8597
|
+
return /(?:\.test|\.spec)\.[cm]?[jt]sx?$/.test(file) || path55.normalize(file).split(path55.sep).includes("__tests__");
|
|
8598
|
+
}
|
|
8599
|
+
function functionSource(index, file, name, sourceRoot, visited = /* @__PURE__ */ new Set()) {
|
|
8600
|
+
if (visited.has(file)) return void 0;
|
|
8601
|
+
visited.add(file);
|
|
8602
|
+
const module = index.modules.get(file);
|
|
8603
|
+
if (!module) return void 0;
|
|
8604
|
+
if (module.exports.some((entry) => entry.name === name && entry.kind === "function")) return file;
|
|
8605
|
+
if (!module.exports.some((entry) => entry.name === name) && !module.reexports.some((entry) => entry.names.length === 0)) {
|
|
8606
|
+
return void 0;
|
|
8607
|
+
}
|
|
8608
|
+
for (const entry of module.reexports) {
|
|
8609
|
+
if (entry.names.length > 0 && !entry.names.includes(name)) continue;
|
|
8610
|
+
const target = resolveSpecifier(file, entry.specifier, sourceRoot);
|
|
8611
|
+
if (!target) continue;
|
|
8612
|
+
const original = functionSource(index, target, name, sourceRoot, visited);
|
|
8613
|
+
if (original) return original;
|
|
8614
|
+
}
|
|
8615
|
+
return void 0;
|
|
8616
|
+
}
|
|
8617
|
+
function singleUseResponseDelegate(context, handler) {
|
|
8618
|
+
const call = soleDelegation(handler);
|
|
8619
|
+
if (call?.callee.type !== "Identifier") return void 0;
|
|
8620
|
+
const name = call.callee.name;
|
|
8621
|
+
const sourceRoot = sourceRootOf(context);
|
|
8622
|
+
const index = getProjectIndex(sourceRoot);
|
|
8623
|
+
if (!index) return void 0;
|
|
8624
|
+
for (const statement of context.sourceCode.ast.body) {
|
|
8625
|
+
if (statement.type !== "ImportDeclaration" || typeof statement.source.value !== "string") continue;
|
|
8626
|
+
const target = resolveSpecifier(context.filename, statement.source.value, sourceRoot);
|
|
8627
|
+
if (target === void 0 || target === context.filename) continue;
|
|
8628
|
+
for (const specifier of statement.specifiers) {
|
|
8629
|
+
if (specifier.type !== "ImportSpecifier" || specifier.local.name !== name) continue;
|
|
8630
|
+
const original = specifier.imported.type === "Identifier" ? specifier.imported.name : String(specifier.imported.value);
|
|
8631
|
+
const source = functionSource(index, target, original, sourceRoot);
|
|
8632
|
+
if (!source) continue;
|
|
8633
|
+
const bindings = context.sourceCode.getDeclaredVariables(specifier);
|
|
8634
|
+
if (!bindings.some((binding) => binding.references.length === 1)) continue;
|
|
8635
|
+
const consumers = index.symbolConsumers.get(symbolKey(source, original));
|
|
8636
|
+
if (!consumers?.has(context.filename)) continue;
|
|
8637
|
+
const activeConsumers = [...consumers].filter((consumer) => {
|
|
8638
|
+
if (isTestFile2(consumer)) return false;
|
|
8639
|
+
const module = index.modules.get(consumer);
|
|
8640
|
+
return !(module && module.reexports.length > 0 && module.imports.length === module.reexports.length && module.exports.every((entry) => entry.kind === "other"));
|
|
8641
|
+
});
|
|
8642
|
+
if (activeConsumers.length === 1 && activeConsumers[0] === context.filename) return original;
|
|
8643
|
+
}
|
|
8644
|
+
}
|
|
8645
|
+
return void 0;
|
|
8646
|
+
}
|
|
8647
|
+
|
|
8648
|
+
// eslint/rules/route-handler-shape.ts
|
|
8161
8649
|
var HTTP_METHODS2 = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
8162
8650
|
var REQUIRED_BOUNDARY = "withResponse";
|
|
8163
8651
|
function isFunctionLike(node) {
|
|
@@ -8175,33 +8663,33 @@ function findHandler(node) {
|
|
|
8175
8663
|
return void 0;
|
|
8176
8664
|
}
|
|
8177
8665
|
function isLoop(node) {
|
|
8178
|
-
return
|
|
8666
|
+
return ts13.isForStatement(node) || ts13.isForOfStatement(node) || ts13.isForInStatement(node) || ts13.isWhileStatement(node) || ts13.isDoStatement(node);
|
|
8179
8667
|
}
|
|
8180
8668
|
function isFunctionBoundary(node) {
|
|
8181
|
-
return
|
|
8669
|
+
return ts13.isFunctionExpression(node) || ts13.isArrowFunction(node) || ts13.isFunctionDeclaration(node);
|
|
8182
8670
|
}
|
|
8183
8671
|
function analyzeHandlerBody(body, sourceText) {
|
|
8184
8672
|
const start = body.range?.[0] ?? 0;
|
|
8185
8673
|
const end = body.range?.[1] ?? sourceText.length;
|
|
8186
|
-
const sourceFile =
|
|
8674
|
+
const sourceFile = ts13.createSourceFile(
|
|
8187
8675
|
"route.ts",
|
|
8188
8676
|
sourceText.slice(start, end),
|
|
8189
|
-
|
|
8677
|
+
ts13.ScriptTarget.Latest,
|
|
8190
8678
|
true,
|
|
8191
|
-
|
|
8679
|
+
ts13.ScriptKind.TS
|
|
8192
8680
|
);
|
|
8193
8681
|
const kinds = /* @__PURE__ */ new Set();
|
|
8194
8682
|
const calledNames = /* @__PURE__ */ new Set();
|
|
8195
8683
|
const visit = (node) => {
|
|
8196
|
-
if (
|
|
8684
|
+
if (ts13.isTryStatement(node)) kinds.add("try");
|
|
8197
8685
|
if (isLoop(node)) kinds.add("loop");
|
|
8198
|
-
if (
|
|
8199
|
-
if (
|
|
8686
|
+
if (ts13.isIfStatement(node)) kinds.add("if");
|
|
8687
|
+
if (ts13.isCallExpression(node) && ts13.isPropertyAccessExpression(node.expression) && node.expression.name.text === "map") {
|
|
8200
8688
|
kinds.add("map");
|
|
8201
8689
|
}
|
|
8202
|
-
if (
|
|
8690
|
+
if (ts13.isCallExpression(node) && ts13.isIdentifier(node.expression)) calledNames.add(node.expression.text);
|
|
8203
8691
|
if (isFunctionBoundary(node)) return;
|
|
8204
|
-
|
|
8692
|
+
ts13.forEachChild(node, visit);
|
|
8205
8693
|
};
|
|
8206
8694
|
visit(sourceFile);
|
|
8207
8695
|
return { kinds, calledNames };
|
|
@@ -8241,7 +8729,7 @@ var routeHandlerShapeRule = {
|
|
|
8241
8729
|
}
|
|
8242
8730
|
},
|
|
8243
8731
|
create(context) {
|
|
8244
|
-
if (
|
|
8732
|
+
if (path56.basename(context.filename) !== "route.ts") return {};
|
|
8245
8733
|
const sourceText = context.sourceCode.text;
|
|
8246
8734
|
function reportUnwrapped(node, name) {
|
|
8247
8735
|
context.report({
|
|
@@ -8264,6 +8752,13 @@ var routeHandlerShapeRule = {
|
|
|
8264
8752
|
});
|
|
8265
8753
|
return;
|
|
8266
8754
|
}
|
|
8755
|
+
const singleUseDelegate = singleUseResponseDelegate(context, handler);
|
|
8756
|
+
if (singleUseDelegate) {
|
|
8757
|
+
context.report({
|
|
8758
|
+
node,
|
|
8759
|
+
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`
|
|
8760
|
+
});
|
|
8761
|
+
}
|
|
8267
8762
|
const { kinds, calledNames } = analyzeHandlerBody(handler.body, sourceText);
|
|
8268
8763
|
for (const kind of kinds) {
|
|
8269
8764
|
context.report({
|
|
@@ -8300,7 +8795,7 @@ var routeHandlerShapeRule = {
|
|
|
8300
8795
|
};
|
|
8301
8796
|
|
|
8302
8797
|
// eslint/rules/schema-casing.ts
|
|
8303
|
-
import
|
|
8798
|
+
import path57 from "path";
|
|
8304
8799
|
function isCamelCase(name) {
|
|
8305
8800
|
return /^[a-z][a-zA-Z0-9]*$/.test(name);
|
|
8306
8801
|
}
|
|
@@ -8328,9 +8823,9 @@ var schemaCasingRule = {
|
|
|
8328
8823
|
}
|
|
8329
8824
|
},
|
|
8330
8825
|
create(context) {
|
|
8331
|
-
const filename =
|
|
8826
|
+
const filename = path57.resolve(context.filename);
|
|
8332
8827
|
const sourceRoot = sourceRootOf(context);
|
|
8333
|
-
if (!filename.startsWith(sourceRoot +
|
|
8828
|
+
if (!filename.startsWith(sourceRoot + path57.sep)) return {};
|
|
8334
8829
|
let zodLocalName;
|
|
8335
8830
|
return {
|
|
8336
8831
|
ImportDeclaration(node) {
|
|
@@ -8362,39 +8857,39 @@ var schemaCasingRule = {
|
|
|
8362
8857
|
};
|
|
8363
8858
|
|
|
8364
8859
|
// eslint/rules/sole-state-owner.ts
|
|
8365
|
-
import
|
|
8366
|
-
import
|
|
8860
|
+
import path58 from "path";
|
|
8861
|
+
import ts14 from "typescript";
|
|
8367
8862
|
function findStateHooks(node) {
|
|
8368
8863
|
const hooks = [];
|
|
8369
8864
|
const visit = (child) => {
|
|
8370
|
-
if (
|
|
8371
|
-
if (
|
|
8865
|
+
if (ts14.isCallExpression(child) && ts14.isIdentifier(child.expression) && child.expression.text === "useState") {
|
|
8866
|
+
if (ts14.isVariableDeclaration(child.parent)) {
|
|
8372
8867
|
const { name } = child.parent;
|
|
8373
|
-
if (
|
|
8868
|
+
if (ts14.isArrayBindingPattern(name) && name.elements.length >= 2) {
|
|
8374
8869
|
const value = name.elements[0];
|
|
8375
8870
|
const updater = name.elements[1];
|
|
8376
|
-
if (value && updater &&
|
|
8871
|
+
if (value && updater && ts14.isBindingElement(value) && ts14.isBindingElement(updater)) {
|
|
8377
8872
|
const valueName = value.name;
|
|
8378
8873
|
const updaterName = updater.name;
|
|
8379
|
-
if (
|
|
8874
|
+
if (ts14.isIdentifier(valueName) && ts14.isIdentifier(updaterName)) {
|
|
8380
8875
|
hooks.push({ value: valueName.text, updater: updaterName.text });
|
|
8381
8876
|
}
|
|
8382
8877
|
}
|
|
8383
8878
|
}
|
|
8384
8879
|
}
|
|
8385
8880
|
}
|
|
8386
|
-
|
|
8881
|
+
ts14.forEachChild(child, visit);
|
|
8387
8882
|
};
|
|
8388
8883
|
visit(node);
|
|
8389
8884
|
return hooks;
|
|
8390
8885
|
}
|
|
8391
8886
|
function isHookUsage(node, hook) {
|
|
8392
|
-
if (
|
|
8887
|
+
if (ts14.isCallExpression(node) && ts14.isIdentifier(node.expression) && node.expression.text === hook.updater) {
|
|
8393
8888
|
return "updater";
|
|
8394
8889
|
}
|
|
8395
|
-
if (
|
|
8890
|
+
if (ts14.isIdentifier(node) && node.text === hook.value) {
|
|
8396
8891
|
const parent = node.parent;
|
|
8397
|
-
if (
|
|
8892
|
+
if (ts14.isBindingElement(parent) || ts14.isPropertyAccessExpression(parent) || ts14.isShorthandPropertyAssignment(parent)) {
|
|
8398
8893
|
return void 0;
|
|
8399
8894
|
}
|
|
8400
8895
|
return "value";
|
|
@@ -8404,16 +8899,16 @@ function isHookUsage(node, hook) {
|
|
|
8404
8899
|
function topLevelJsxChildren(initial) {
|
|
8405
8900
|
if (!initial) return void 0;
|
|
8406
8901
|
let expression = initial;
|
|
8407
|
-
while (
|
|
8408
|
-
if (
|
|
8902
|
+
while (ts14.isParenthesizedExpression(expression)) expression = expression.expression;
|
|
8903
|
+
if (ts14.isJsxFragment(expression)) {
|
|
8409
8904
|
const children = expression.children.filter(
|
|
8410
|
-
(c) => !
|
|
8905
|
+
(c) => !ts14.isJsxText(c) && !ts14.isJsxSpreadAttribute(c)
|
|
8411
8906
|
);
|
|
8412
8907
|
return { root: expression, children };
|
|
8413
8908
|
}
|
|
8414
|
-
if (
|
|
8909
|
+
if (ts14.isJsxElement(expression)) {
|
|
8415
8910
|
const children = expression.children.filter(
|
|
8416
|
-
(c) => !
|
|
8911
|
+
(c) => !ts14.isJsxText(c) && !ts14.isJsxSpreadAttribute(c)
|
|
8417
8912
|
);
|
|
8418
8913
|
return { root: expression, children };
|
|
8419
8914
|
}
|
|
@@ -8427,8 +8922,8 @@ function collectUsesIn(child, hook) {
|
|
|
8427
8922
|
positions.push(node);
|
|
8428
8923
|
count += 1;
|
|
8429
8924
|
}
|
|
8430
|
-
if (
|
|
8431
|
-
|
|
8925
|
+
if (ts14.isFunctionDeclaration(node) || ts14.isClassDeclaration(node)) return;
|
|
8926
|
+
ts14.forEachChild(node, visit);
|
|
8432
8927
|
};
|
|
8433
8928
|
visit(child);
|
|
8434
8929
|
return { positions, count };
|
|
@@ -8442,7 +8937,7 @@ var soleStateOwnerRule = {
|
|
|
8442
8937
|
}
|
|
8443
8938
|
},
|
|
8444
8939
|
create(context) {
|
|
8445
|
-
const filename =
|
|
8940
|
+
const filename = path58.resolve(context.filename);
|
|
8446
8941
|
if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
|
|
8447
8942
|
const text = context.sourceCode.text;
|
|
8448
8943
|
const components = parseComponentInfo(text, filename);
|
|
@@ -8467,18 +8962,18 @@ var soleStateOwnerRule = {
|
|
|
8467
8962
|
}
|
|
8468
8963
|
};
|
|
8469
8964
|
function analyzeSoleOwner(declaration, hook) {
|
|
8470
|
-
const body =
|
|
8471
|
-
if (!body || !
|
|
8965
|
+
const body = ts14.isFunctionDeclaration(declaration) ? declaration.body : void 0;
|
|
8966
|
+
if (!body || !ts14.isBlock(body)) return void 0;
|
|
8472
8967
|
const returns = [];
|
|
8473
8968
|
const visit = (node) => {
|
|
8474
|
-
if (node !== body && (
|
|
8475
|
-
if (
|
|
8476
|
-
|
|
8969
|
+
if (node !== body && (ts14.isFunctionLike(node) || ts14.isClassLike(node))) return;
|
|
8970
|
+
if (ts14.isReturnStatement(node)) returns.push(node);
|
|
8971
|
+
ts14.forEachChild(node, visit);
|
|
8477
8972
|
};
|
|
8478
8973
|
visit(body);
|
|
8479
8974
|
if (returns.length !== 1) return void 0;
|
|
8480
8975
|
const single = returns[0];
|
|
8481
|
-
if (!single?.expression || !
|
|
8976
|
+
if (!single?.expression || !ts14.isExpression(single.expression)) return void 0;
|
|
8482
8977
|
const returnExpression = single.expression;
|
|
8483
8978
|
const root = topLevelJsxChildren(returnExpression);
|
|
8484
8979
|
if (!root || root.children.length === 0) return void 0;
|
|
@@ -8501,11 +8996,11 @@ function usesOutsideJsx(declaration, hook, children) {
|
|
|
8501
8996
|
let outside = false;
|
|
8502
8997
|
const visit = (node) => {
|
|
8503
8998
|
if (outside) return;
|
|
8504
|
-
if (node !== declaration && (
|
|
8999
|
+
if (node !== declaration && (ts14.isFunctionDeclaration(node) || ts14.isClassDeclaration(node))) return;
|
|
8505
9000
|
if (isHookUsage(node, hook)) {
|
|
8506
9001
|
let current = node;
|
|
8507
9002
|
let isInJsxChild = false;
|
|
8508
|
-
while (!
|
|
9003
|
+
while (!ts14.isSourceFile(current)) {
|
|
8509
9004
|
if (children.includes(current)) {
|
|
8510
9005
|
isInJsxChild = true;
|
|
8511
9006
|
break;
|
|
@@ -8514,14 +9009,14 @@ function usesOutsideJsx(declaration, hook, children) {
|
|
|
8514
9009
|
}
|
|
8515
9010
|
if (!isInJsxChild) outside = true;
|
|
8516
9011
|
}
|
|
8517
|
-
|
|
9012
|
+
ts14.forEachChild(node, visit);
|
|
8518
9013
|
};
|
|
8519
9014
|
visit(declaration);
|
|
8520
9015
|
return outside;
|
|
8521
9016
|
}
|
|
8522
9017
|
|
|
8523
9018
|
// eslint/rules/source-under-src.ts
|
|
8524
|
-
import
|
|
9019
|
+
import path59 from "path";
|
|
8525
9020
|
var NON_SOURCE_ROOT_DIRS = /* @__PURE__ */ new Set([
|
|
8526
9021
|
".agents",
|
|
8527
9022
|
".cache",
|
|
@@ -8562,14 +9057,14 @@ var sourceUnderSrcRule = {
|
|
|
8562
9057
|
}
|
|
8563
9058
|
},
|
|
8564
9059
|
create(context) {
|
|
8565
|
-
const filename =
|
|
9060
|
+
const filename = path59.resolve(context.filename);
|
|
8566
9061
|
if (!MODULE_EXTENSION.test(filename)) return {};
|
|
8567
|
-
const relative =
|
|
9062
|
+
const relative = path59.relative(context.cwd, filename).replace(/\\/g, "/");
|
|
8568
9063
|
if (relative === "src" || relative.startsWith("src/")) return {};
|
|
8569
9064
|
const topLevel = relative.split("/")[0] ?? "";
|
|
8570
9065
|
if (NON_SOURCE_ROOT_DIRS.has(topLevel)) return {};
|
|
8571
9066
|
if (!relative.includes("/")) {
|
|
8572
|
-
const basename =
|
|
9067
|
+
const basename = path59.basename(filename);
|
|
8573
9068
|
if (CONFIG_FILE.test(basename) || DECLARATION_FILE.test(basename) || basename.startsWith(".")) return {};
|
|
8574
9069
|
}
|
|
8575
9070
|
return {
|
|
@@ -8585,7 +9080,7 @@ var sourceUnderSrcRule = {
|
|
|
8585
9080
|
};
|
|
8586
9081
|
|
|
8587
9082
|
// eslint/rules/stay-flat.ts
|
|
8588
|
-
import
|
|
9083
|
+
import path60 from "path";
|
|
8589
9084
|
var stayFlatRule = {
|
|
8590
9085
|
meta: {
|
|
8591
9086
|
schema: [],
|
|
@@ -8596,7 +9091,7 @@ var stayFlatRule = {
|
|
|
8596
9091
|
},
|
|
8597
9092
|
create(context) {
|
|
8598
9093
|
const sourceRoot = sourceRootOf(context);
|
|
8599
|
-
const file =
|
|
9094
|
+
const file = path60.resolve(context.filename);
|
|
8600
9095
|
const segments = segmentsOf(file, sourceRoot);
|
|
8601
9096
|
if (segments.length !== 3 || segments[0] !== "features") return {};
|
|
8602
9097
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -8636,7 +9131,7 @@ var stayFlatRule = {
|
|
|
8636
9131
|
};
|
|
8637
9132
|
|
|
8638
9133
|
// eslint/rules/support-file-placement.ts
|
|
8639
|
-
import
|
|
9134
|
+
import path61 from "path";
|
|
8640
9135
|
var CONFIG_OWNED_FOLDERS = /* @__PURE__ */ new Set(["types", "constants"]);
|
|
8641
9136
|
var EXPORT_KIND_BY_SUPPORT_FOLDER = /* @__PURE__ */ new Map([
|
|
8642
9137
|
["constants", "constant"],
|
|
@@ -8661,7 +9156,7 @@ var supportFilePlacementRule = {
|
|
|
8661
9156
|
},
|
|
8662
9157
|
create(context) {
|
|
8663
9158
|
const sourceRoot = sourceRootOf(context);
|
|
8664
|
-
const supportFile =
|
|
9159
|
+
const supportFile = path61.resolve(context.filename);
|
|
8665
9160
|
const currentFolder = folderSegmentsOf(supportFile, sourceRoot);
|
|
8666
9161
|
const supportFolder = currentFolder[currentFolder.length - 1];
|
|
8667
9162
|
if (supportFolder === void 0 || !SUPPORT_FOLDERS.has(supportFolder)) return {};
|
|
@@ -8715,7 +9210,7 @@ var supportFilePlacementRule = {
|
|
|
8715
9210
|
|
|
8716
9211
|
// eslint/rules/support-folder-shape.ts
|
|
8717
9212
|
import fs6 from "fs";
|
|
8718
|
-
import
|
|
9213
|
+
import path62 from "path";
|
|
8719
9214
|
var SUPPORT_FOLDERS4 = /* @__PURE__ */ new Set(["constants", "types", "schemas"]);
|
|
8720
9215
|
var INDEX_NAMES2 = /* @__PURE__ */ new Set(["index.ts", "index.tsx", "index.mts", "index.cts"]);
|
|
8721
9216
|
var supportFolderShapeRule = {
|
|
@@ -8727,12 +9222,12 @@ var supportFolderShapeRule = {
|
|
|
8727
9222
|
}
|
|
8728
9223
|
},
|
|
8729
9224
|
create(context) {
|
|
8730
|
-
const filename =
|
|
8731
|
-
const baseName =
|
|
9225
|
+
const filename = path62.resolve(context.filename);
|
|
9226
|
+
const baseName = path62.basename(filename);
|
|
8732
9227
|
if (!INDEX_NAMES2.has(baseName)) return {};
|
|
8733
|
-
const folder =
|
|
9228
|
+
const folder = path62.basename(path62.dirname(filename));
|
|
8734
9229
|
if (!SUPPORT_FOLDERS4.has(folder)) return {};
|
|
8735
|
-
const directory =
|
|
9230
|
+
const directory = path62.dirname(filename);
|
|
8736
9231
|
let entries;
|
|
8737
9232
|
try {
|
|
8738
9233
|
entries = fs6.readdirSync(directory);
|
|
@@ -8750,7 +9245,7 @@ var supportFolderShapeRule = {
|
|
|
8750
9245
|
for (const match of source.matchAll(exportPattern)) {
|
|
8751
9246
|
hasAnyReExport = true;
|
|
8752
9247
|
const specifier = match.groups?.specifier;
|
|
8753
|
-
if (specifier?.startsWith(".")) exportedFiles.add(
|
|
9248
|
+
if (specifier?.startsWith(".")) exportedFiles.add(path62.basename(specifier));
|
|
8754
9249
|
}
|
|
8755
9250
|
const guide = `docs/next-codebase-guide/rules/${folder === "constants" ? "constants" : "types-and-schemas"}-rule.md`;
|
|
8756
9251
|
if (siblingModules.length === 0) {
|
|
@@ -8929,24 +9424,24 @@ var baseLayerPairRule = {
|
|
|
8929
9424
|
|
|
8930
9425
|
// eslint/rules/tailwind/css-entry-point.ts
|
|
8931
9426
|
import { statSync as statSync4 } from "fs";
|
|
8932
|
-
import
|
|
9427
|
+
import path65 from "path";
|
|
8933
9428
|
|
|
8934
9429
|
// eslint/rules/tailwind/source-files.ts
|
|
8935
|
-
import { readdirSync as
|
|
8936
|
-
import
|
|
9430
|
+
import { readdirSync as readdirSync5, readFileSync as readFileSync13, statSync as statSync3 } from "fs";
|
|
9431
|
+
import path63 from "path";
|
|
8937
9432
|
var CSS_EXTENSIONS = [".css"];
|
|
8938
9433
|
var MODULE_EXTENSIONS4 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
|
|
8939
9434
|
var SOURCE_EXTENSIONS = [...MODULE_EXTENSIONS4, ...CSS_EXTENSIONS];
|
|
8940
9435
|
function findFiles(dir, extensions) {
|
|
8941
9436
|
let entries;
|
|
8942
9437
|
try {
|
|
8943
|
-
entries =
|
|
9438
|
+
entries = readdirSync5(dir);
|
|
8944
9439
|
} catch {
|
|
8945
9440
|
return [];
|
|
8946
9441
|
}
|
|
8947
9442
|
return entries.flatMap((entry) => {
|
|
8948
9443
|
if (entry.startsWith(".") || entry === "node_modules") return [];
|
|
8949
|
-
const entryPath =
|
|
9444
|
+
const entryPath = path63.join(dir, entry);
|
|
8950
9445
|
let stats;
|
|
8951
9446
|
try {
|
|
8952
9447
|
stats = statSync3(entryPath);
|
|
@@ -8954,7 +9449,7 @@ function findFiles(dir, extensions) {
|
|
|
8954
9449
|
return [];
|
|
8955
9450
|
}
|
|
8956
9451
|
if (stats.isDirectory()) return findFiles(entryPath, extensions);
|
|
8957
|
-
return extensions.includes(
|
|
9452
|
+
return extensions.includes(path63.extname(entry)) ? [entryPath] : [];
|
|
8958
9453
|
});
|
|
8959
9454
|
}
|
|
8960
9455
|
function cachedTextReader() {
|
|
@@ -8963,7 +9458,7 @@ function cachedTextReader() {
|
|
|
8963
9458
|
let text = texts.get(file);
|
|
8964
9459
|
if (text === void 0) {
|
|
8965
9460
|
try {
|
|
8966
|
-
text =
|
|
9461
|
+
text = readFileSync13(file, "utf8");
|
|
8967
9462
|
} catch {
|
|
8968
9463
|
text = "";
|
|
8969
9464
|
}
|
|
@@ -8977,7 +9472,7 @@ function escapeRegExp(text) {
|
|
|
8977
9472
|
}
|
|
8978
9473
|
|
|
8979
9474
|
// eslint/rules/tailwind/stylesheet-graph.ts
|
|
8980
|
-
import
|
|
9475
|
+
import path64 from "path";
|
|
8981
9476
|
function registersTailwind(text) {
|
|
8982
9477
|
return /@import\s+(?:url\(\s*)?["']tailwindcss["']\s*\)?/i.test(text);
|
|
8983
9478
|
}
|
|
@@ -8991,25 +9486,25 @@ function moduleImports(text, fileName) {
|
|
|
8991
9486
|
return new RegExp(`(?:import|require)\\s*\\(?\\s*["'][^"']*${escaped}["']`, "i").test(text);
|
|
8992
9487
|
}
|
|
8993
9488
|
function resolveSpecifier2(fromFile, spec, sourceRoot) {
|
|
8994
|
-
if (spec.startsWith("/")) return
|
|
8995
|
-
if (spec.startsWith("./") || spec.startsWith("../")) return
|
|
8996
|
-
if (spec.startsWith("@/")) return
|
|
9489
|
+
if (spec.startsWith("/")) return path64.resolve(spec);
|
|
9490
|
+
if (spec.startsWith("./") || spec.startsWith("../")) return path64.resolve(path64.dirname(fromFile), spec);
|
|
9491
|
+
if (spec.startsWith("@/")) return path64.resolve(sourceRoot, spec.slice(2));
|
|
8997
9492
|
return void 0;
|
|
8998
9493
|
}
|
|
8999
9494
|
function buildStylesheetGraph(options) {
|
|
9000
9495
|
const { cssFiles, sourceRoot, textOf } = options;
|
|
9001
|
-
const cssSet = new Set(cssFiles.map((file) =>
|
|
9496
|
+
const cssSet = new Set(cssFiles.map((file) => path64.normalize(file)));
|
|
9002
9497
|
const globals = cssFiles.filter((file) => registersTailwind(textOf(file)));
|
|
9003
9498
|
const reachable = /* @__PURE__ */ new Set();
|
|
9004
9499
|
const queue = [...globals];
|
|
9005
|
-
for (const global of globals) reachable.add(
|
|
9500
|
+
for (const global of globals) reachable.add(path64.normalize(global));
|
|
9006
9501
|
while (queue.length > 0) {
|
|
9007
9502
|
const from = queue.shift();
|
|
9008
9503
|
if (!from) continue;
|
|
9009
9504
|
for (const spec of importedSpecifiers(textOf(from))) {
|
|
9010
9505
|
const target = resolveSpecifier2(from, spec, sourceRoot);
|
|
9011
9506
|
if (!target) continue;
|
|
9012
|
-
const normalized =
|
|
9507
|
+
const normalized = path64.normalize(target);
|
|
9013
9508
|
if (cssSet.has(normalized) && !reachable.has(normalized)) {
|
|
9014
9509
|
reachable.add(normalized);
|
|
9015
9510
|
queue.push(normalized);
|
|
@@ -9021,7 +9516,7 @@ function buildStylesheetGraph(options) {
|
|
|
9021
9516
|
for (const spec of importedSpecifiers(textOf(global))) {
|
|
9022
9517
|
const target = resolveSpecifier2(global, spec, sourceRoot);
|
|
9023
9518
|
if (!target) continue;
|
|
9024
|
-
const normalized =
|
|
9519
|
+
const normalized = path64.normalize(target);
|
|
9025
9520
|
if (cssSet.has(normalized)) directChildren.add(normalized);
|
|
9026
9521
|
}
|
|
9027
9522
|
}
|
|
@@ -9029,8 +9524,8 @@ function buildStylesheetGraph(options) {
|
|
|
9029
9524
|
}
|
|
9030
9525
|
|
|
9031
9526
|
// eslint/rules/tailwind/css-entry-point.ts
|
|
9032
|
-
var APP_STYLES_DIR =
|
|
9033
|
-
var GLOBAL_STYLESHEET_PATH =
|
|
9527
|
+
var APP_STYLES_DIR = path65.join("app", "styles");
|
|
9528
|
+
var GLOBAL_STYLESHEET_PATH = path65.join(APP_STYLES_DIR, "globals.css");
|
|
9034
9529
|
var cssEntryPointRule = {
|
|
9035
9530
|
meta: {
|
|
9036
9531
|
schema: [],
|
|
@@ -9056,8 +9551,8 @@ var cssEntryPointRule = {
|
|
|
9056
9551
|
return {
|
|
9057
9552
|
"StyleSheet:exit"(node) {
|
|
9058
9553
|
if (globals.length === 0) return;
|
|
9059
|
-
const current =
|
|
9060
|
-
const relative =
|
|
9554
|
+
const current = path65.normalize(path65.resolve(context.filename));
|
|
9555
|
+
const relative = path65.relative(sourceRoot, current);
|
|
9061
9556
|
if (globals.includes(current)) {
|
|
9062
9557
|
if (globals.length > 1) {
|
|
9063
9558
|
context.report({
|
|
@@ -9073,7 +9568,7 @@ var cssEntryPointRule = {
|
|
|
9073
9568
|
});
|
|
9074
9569
|
return;
|
|
9075
9570
|
}
|
|
9076
|
-
const basename =
|
|
9571
|
+
const basename = path65.basename(current);
|
|
9077
9572
|
const importCount = moduleFiles.filter((modulePath) => moduleImports(textOf(modulePath), basename)).length;
|
|
9078
9573
|
if (importCount !== 1) {
|
|
9079
9574
|
context.report({
|
|
@@ -9083,7 +9578,7 @@ var cssEntryPointRule = {
|
|
|
9083
9578
|
}
|
|
9084
9579
|
return;
|
|
9085
9580
|
}
|
|
9086
|
-
const isInAppStyles = relative === APP_STYLES_DIR || relative.startsWith(`${APP_STYLES_DIR}${
|
|
9581
|
+
const isInAppStyles = relative === APP_STYLES_DIR || relative.startsWith(`${APP_STYLES_DIR}${path65.sep}`);
|
|
9087
9582
|
if (!isInAppStyles) {
|
|
9088
9583
|
context.report({
|
|
9089
9584
|
node,
|
|
@@ -9572,7 +10067,7 @@ var tailwindRules = {
|
|
|
9572
10067
|
};
|
|
9573
10068
|
|
|
9574
10069
|
// eslint/rules/type-extraction.ts
|
|
9575
|
-
import
|
|
10070
|
+
import path66 from "path";
|
|
9576
10071
|
var typeExtractionRule = {
|
|
9577
10072
|
meta: {
|
|
9578
10073
|
schema: [],
|
|
@@ -9583,7 +10078,7 @@ var typeExtractionRule = {
|
|
|
9583
10078
|
},
|
|
9584
10079
|
create(context) {
|
|
9585
10080
|
const sourceRoot = sourceRootOf(context);
|
|
9586
|
-
const file =
|
|
10081
|
+
const file = path66.resolve(context.filename);
|
|
9587
10082
|
const segments = segmentsOf(file, sourceRoot);
|
|
9588
10083
|
if (segments.length === 0) return {};
|
|
9589
10084
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -9722,9 +10217,9 @@ var uiStateRule = {
|
|
|
9722
10217
|
};
|
|
9723
10218
|
|
|
9724
10219
|
// eslint/rules/unknown-utility.ts
|
|
9725
|
-
import { existsSync as
|
|
10220
|
+
import { existsSync as existsSync8, readdirSync as readdirSync6, readFileSync as readFileSync14, statSync as statSync6 } from "fs";
|
|
9726
10221
|
import { createRequire } from "module";
|
|
9727
|
-
import
|
|
10222
|
+
import path67 from "path";
|
|
9728
10223
|
var PREFIX_NAMESPACES = {
|
|
9729
10224
|
bg: ["color"],
|
|
9730
10225
|
text: ["color", "text"],
|
|
@@ -9958,13 +10453,13 @@ function isBuiltInTailwindUtility(utility) {
|
|
|
9958
10453
|
function stylesheetFiles(dir) {
|
|
9959
10454
|
let entries;
|
|
9960
10455
|
try {
|
|
9961
|
-
entries =
|
|
10456
|
+
entries = readdirSync6(dir);
|
|
9962
10457
|
} catch {
|
|
9963
10458
|
return [];
|
|
9964
10459
|
}
|
|
9965
10460
|
return entries.flatMap((entry) => {
|
|
9966
10461
|
if (entry.startsWith(".") || entry === "node_modules") return [];
|
|
9967
|
-
const entryPath =
|
|
10462
|
+
const entryPath = path67.join(dir, entry);
|
|
9968
10463
|
let stats;
|
|
9969
10464
|
try {
|
|
9970
10465
|
stats = statSync6(entryPath);
|
|
@@ -9972,7 +10467,7 @@ function stylesheetFiles(dir) {
|
|
|
9972
10467
|
return [];
|
|
9973
10468
|
}
|
|
9974
10469
|
if (stats.isDirectory()) return stylesheetFiles(entryPath);
|
|
9975
|
-
return
|
|
10470
|
+
return path67.extname(entry) === ".css" ? [entryPath] : [];
|
|
9976
10471
|
});
|
|
9977
10472
|
}
|
|
9978
10473
|
function packageNameOf(specifier) {
|
|
@@ -9983,24 +10478,24 @@ function packageNameOf(specifier) {
|
|
|
9983
10478
|
function resolvePackageStylesheet(fromFile, specifier) {
|
|
9984
10479
|
const packageName = packageNameOf(specifier);
|
|
9985
10480
|
if (!packageName || packageName === "tailwindcss") return void 0;
|
|
9986
|
-
let directory =
|
|
9987
|
-
while (directory !==
|
|
9988
|
-
const packageRoot =
|
|
9989
|
-
const manifestPath =
|
|
9990
|
-
if (
|
|
10481
|
+
let directory = path67.dirname(fromFile);
|
|
10482
|
+
while (directory !== path67.dirname(directory)) {
|
|
10483
|
+
const packageRoot = path67.join(directory, "node_modules", packageName);
|
|
10484
|
+
const manifestPath = path67.join(packageRoot, "package.json");
|
|
10485
|
+
if (existsSync8(manifestPath)) {
|
|
9991
10486
|
try {
|
|
9992
|
-
const manifest =
|
|
10487
|
+
const manifest = readFileSync14(manifestPath, "utf8");
|
|
9993
10488
|
const stylesheet = /"style"\s*:\s*"(?<file>[^"]+\.css)"/.exec(manifest)?.groups?.file;
|
|
9994
10489
|
const main = /"main"\s*:\s*"(?<file>[^"]+\.css)"/.exec(manifest)?.groups?.file;
|
|
9995
10490
|
const target = stylesheet ?? main;
|
|
9996
10491
|
if (!target) return void 0;
|
|
9997
|
-
const resolved =
|
|
9998
|
-
return
|
|
10492
|
+
const resolved = path67.resolve(packageRoot, target);
|
|
10493
|
+
return existsSync8(resolved) ? resolved : void 0;
|
|
9999
10494
|
} catch {
|
|
10000
10495
|
return void 0;
|
|
10001
10496
|
}
|
|
10002
10497
|
}
|
|
10003
|
-
directory =
|
|
10498
|
+
directory = path67.dirname(directory);
|
|
10004
10499
|
}
|
|
10005
10500
|
return void 0;
|
|
10006
10501
|
}
|
|
@@ -10009,7 +10504,7 @@ function inventoryStylesheetFiles(projectFiles) {
|
|
|
10009
10504
|
for (const file of projectFiles) {
|
|
10010
10505
|
let css2;
|
|
10011
10506
|
try {
|
|
10012
|
-
css2 =
|
|
10507
|
+
css2 = readFileSync14(file, "utf8");
|
|
10013
10508
|
} catch {
|
|
10014
10509
|
continue;
|
|
10015
10510
|
}
|
|
@@ -10075,7 +10570,7 @@ function readInventory(files) {
|
|
|
10075
10570
|
for (const file of files) {
|
|
10076
10571
|
let css2;
|
|
10077
10572
|
try {
|
|
10078
|
-
css2 =
|
|
10573
|
+
css2 = readFileSync14(file, "utf8");
|
|
10079
10574
|
} catch {
|
|
10080
10575
|
continue;
|
|
10081
10576
|
}
|
|
@@ -10251,7 +10746,7 @@ var unknownUtilityRule = {
|
|
|
10251
10746
|
};
|
|
10252
10747
|
|
|
10253
10748
|
// eslint/rules/util-file-name.ts
|
|
10254
|
-
import
|
|
10749
|
+
import path68 from "path";
|
|
10255
10750
|
function toKebabCase2(value) {
|
|
10256
10751
|
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
10752
|
}
|
|
@@ -10264,7 +10759,7 @@ var utilFileNameRule = {
|
|
|
10264
10759
|
}
|
|
10265
10760
|
},
|
|
10266
10761
|
create(context) {
|
|
10267
|
-
const filename =
|
|
10762
|
+
const filename = path68.resolve(context.filename);
|
|
10268
10763
|
const segments = filename.replace(/\\/g, "/").split("/");
|
|
10269
10764
|
if (!segments.includes("utils")) return {};
|
|
10270
10765
|
let module;
|
|
@@ -10278,13 +10773,13 @@ var utilFileNameRule = {
|
|
|
10278
10773
|
const functionName = functions[0]?.name;
|
|
10279
10774
|
if (!functionName) return {};
|
|
10280
10775
|
const expected = toKebabCase2(functionName);
|
|
10281
|
-
const actual =
|
|
10776
|
+
const actual = path68.basename(filename, path68.extname(filename));
|
|
10282
10777
|
if (!expected || actual === expected) return {};
|
|
10283
10778
|
return {
|
|
10284
10779
|
Program(node) {
|
|
10285
10780
|
context.report({
|
|
10286
10781
|
node,
|
|
10287
|
-
message: `A utility file exporting ${functionName} must be named ${expected}.${
|
|
10782
|
+
message: `A utility file exporting ${functionName} must be named ${expected}.${path68.extname(filename).slice(1)}.`
|
|
10288
10783
|
});
|
|
10289
10784
|
}
|
|
10290
10785
|
};
|
|
@@ -10292,7 +10787,7 @@ var utilFileNameRule = {
|
|
|
10292
10787
|
};
|
|
10293
10788
|
|
|
10294
10789
|
// eslint/rules/value-extraction.ts
|
|
10295
|
-
import
|
|
10790
|
+
import path69 from "path";
|
|
10296
10791
|
var valueExtractionRule = {
|
|
10297
10792
|
meta: {
|
|
10298
10793
|
schema: [],
|
|
@@ -10303,7 +10798,7 @@ var valueExtractionRule = {
|
|
|
10303
10798
|
},
|
|
10304
10799
|
create(context) {
|
|
10305
10800
|
const sourceRoot = sourceRootOf(context);
|
|
10306
|
-
const file =
|
|
10801
|
+
const file = path69.resolve(context.filename);
|
|
10307
10802
|
const segments = segmentsOf(file, sourceRoot);
|
|
10308
10803
|
if (segments.length === 0 || segments[0] !== "app") return {};
|
|
10309
10804
|
const index = getProjectIndex(sourceRoot);
|
|
@@ -10324,8 +10819,8 @@ var valueExtractionRule = {
|
|
|
10324
10819
|
};
|
|
10325
10820
|
|
|
10326
10821
|
// eslint/rules/vulyk/tracked-docs.ts
|
|
10327
|
-
import { existsSync as
|
|
10328
|
-
import
|
|
10822
|
+
import { existsSync as existsSync9, readFileSync as readFileSync15 } from "fs";
|
|
10823
|
+
import path70 from "path";
|
|
10329
10824
|
var PASIKA_REPO = "Bredansky/pasika";
|
|
10330
10825
|
var BASE_REQUIRED_TRACKED_DOCS = [
|
|
10331
10826
|
{ name: "documentation-guide", path: "docs/documentation-guide" },
|
|
@@ -10336,13 +10831,13 @@ var NEXTJS_REQUIRED_TRACKED_DOCS = [
|
|
|
10336
10831
|
{ name: "next-codebase-guide", path: "docs/next-codebase-guide" },
|
|
10337
10832
|
{ name: "next-tailwind-guide", path: "docs/next-tailwind-guide" }
|
|
10338
10833
|
];
|
|
10339
|
-
function
|
|
10834
|
+
function memberName8(member) {
|
|
10340
10835
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
10341
10836
|
}
|
|
10342
10837
|
function hasDependency(root, name) {
|
|
10343
|
-
const section = root.members.find((member) =>
|
|
10838
|
+
const section = root.members.find((member) => memberName8(member) === "dependencies");
|
|
10344
10839
|
if (section?.value.type !== "Object") return false;
|
|
10345
|
-
return section.value.members.some((member) =>
|
|
10840
|
+
return section.value.members.some((member) => memberName8(member) === name);
|
|
10346
10841
|
}
|
|
10347
10842
|
var trackedDocsRule = {
|
|
10348
10843
|
meta: {
|
|
@@ -10358,16 +10853,16 @@ var trackedDocsRule = {
|
|
|
10358
10853
|
if (!context.filename.endsWith("package.json")) return;
|
|
10359
10854
|
const root = node.body;
|
|
10360
10855
|
if (root.type !== "Object") return;
|
|
10361
|
-
const projectRoot =
|
|
10362
|
-
const configPath =
|
|
10363
|
-
if (!
|
|
10856
|
+
const projectRoot = path70.dirname(path70.resolve(context.filename));
|
|
10857
|
+
const configPath = path70.join(projectRoot, "vulyk.config.ts");
|
|
10858
|
+
if (!existsSync9(configPath)) {
|
|
10364
10859
|
context.report({
|
|
10365
10860
|
node,
|
|
10366
10861
|
message: "No vulyk.config.ts found. Run npx vulyk init to create one that tracks the framework's required tracked docs."
|
|
10367
10862
|
});
|
|
10368
10863
|
return;
|
|
10369
10864
|
}
|
|
10370
|
-
const config =
|
|
10865
|
+
const config = readFileSync15(configPath, "utf8");
|
|
10371
10866
|
if (!config.includes(PASIKA_REPO)) {
|
|
10372
10867
|
context.report({
|
|
10373
10868
|
node,
|
|
@@ -10384,8 +10879,8 @@ var trackedDocsRule = {
|
|
|
10384
10879
|
});
|
|
10385
10880
|
}
|
|
10386
10881
|
}
|
|
10387
|
-
const agentsPath =
|
|
10388
|
-
if (!
|
|
10882
|
+
const agentsPath = path70.join(projectRoot, "AGENTS.md");
|
|
10883
|
+
if (!existsSync9(agentsPath)) {
|
|
10389
10884
|
context.report({
|
|
10390
10885
|
node,
|
|
10391
10886
|
message: "No AGENTS.md found. Run npx vulyk agents to generate the agent file that routes to the tracked docs."
|
|
@@ -10397,14 +10892,14 @@ var trackedDocsRule = {
|
|
|
10397
10892
|
};
|
|
10398
10893
|
|
|
10399
10894
|
// eslint/rules/vulyk/vulyk-dependency.ts
|
|
10400
|
-
function
|
|
10895
|
+
function memberName9(member) {
|
|
10401
10896
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
10402
10897
|
}
|
|
10403
10898
|
function dependency(root, sectionName) {
|
|
10404
10899
|
if (root.type !== "Object") return void 0;
|
|
10405
|
-
const section = root.members.find((member) =>
|
|
10900
|
+
const section = root.members.find((member) => memberName9(member) === sectionName);
|
|
10406
10901
|
if (section?.value.type !== "Object") return void 0;
|
|
10407
|
-
return section.value.members.find((member) =>
|
|
10902
|
+
return section.value.members.find((member) => memberName9(member) === "vulyk");
|
|
10408
10903
|
}
|
|
10409
10904
|
var vulykDependencyRule = {
|
|
10410
10905
|
meta: {
|
|
@@ -10445,9 +10940,9 @@ var vulykRules = {
|
|
|
10445
10940
|
// eslint/rules/with-response-helper.ts
|
|
10446
10941
|
var HELPER3 = "withResponse";
|
|
10447
10942
|
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 ${
|
|
10943
|
+
var DOC9 = "docs/pasika-adoption-guide/rules/with-response-helper-rule.md";
|
|
10944
|
+
var DECLARED3 = `A repository must not declare its own ${HELPER3}; import it from ${ENTRY3}. See ${DOC9}`;
|
|
10945
|
+
var IMPORTED3 = `${HELPER3} must be imported from ${ENTRY3}. See ${DOC9}`;
|
|
10451
10946
|
function isNamed3(node, name) {
|
|
10452
10947
|
return node?.type === "Identifier" && node.name === name;
|
|
10453
10948
|
}
|
|
@@ -10484,7 +10979,7 @@ var withResponseHelperRule = {
|
|
|
10484
10979
|
|
|
10485
10980
|
// eslint/rules/zirka-baseline.ts
|
|
10486
10981
|
import fs7 from "fs";
|
|
10487
|
-
import
|
|
10982
|
+
import path71 from "path";
|
|
10488
10983
|
var ESLINT_CONFIG = /^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/;
|
|
10489
10984
|
var PRETTIER_CONFIGS = [
|
|
10490
10985
|
"prettier.config.mjs",
|
|
@@ -10503,10 +10998,10 @@ var zirkaBaselineRule = {
|
|
|
10503
10998
|
}
|
|
10504
10999
|
},
|
|
10505
11000
|
create(context) {
|
|
10506
|
-
const filename =
|
|
10507
|
-
const basename =
|
|
11001
|
+
const filename = path71.resolve(context.filename);
|
|
11002
|
+
const basename = path71.basename(filename);
|
|
10508
11003
|
if (!ESLINT_CONFIG.test(basename)) return {};
|
|
10509
|
-
const projectRoot =
|
|
11004
|
+
const projectRoot = path71.dirname(filename);
|
|
10510
11005
|
const report3 = (message) => {
|
|
10511
11006
|
context.report({
|
|
10512
11007
|
node: context.sourceCode.ast,
|
|
@@ -10521,7 +11016,7 @@ var zirkaBaselineRule = {
|
|
|
10521
11016
|
'ESLint config must take its configuration from zirka (import { styleguide } from "zirka") instead of restating rules locally.'
|
|
10522
11017
|
);
|
|
10523
11018
|
}
|
|
10524
|
-
const tsconfigPath =
|
|
11019
|
+
const tsconfigPath = path71.join(projectRoot, "tsconfig.json");
|
|
10525
11020
|
if (!fs7.existsSync(tsconfigPath)) {
|
|
10526
11021
|
report3('No tsconfig.json found. Create one extending the zirka TypeScript base config ("zirka/typescript").');
|
|
10527
11022
|
} else {
|
|
@@ -10539,13 +11034,13 @@ var zirkaBaselineRule = {
|
|
|
10539
11034
|
report3('tsconfig.json must extend the zirka TypeScript base config ("zirka/typescript").');
|
|
10540
11035
|
}
|
|
10541
11036
|
}
|
|
10542
|
-
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs7.existsSync(
|
|
11037
|
+
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs7.existsSync(path71.join(projectRoot, name)));
|
|
10543
11038
|
if (!prettierConfigFile) {
|
|
10544
11039
|
report3(
|
|
10545
11040
|
"No prettier config found. Create one that takes its configuration from zirka (styleguide({ prettier: true }).prettierConfig)."
|
|
10546
11041
|
);
|
|
10547
11042
|
} else {
|
|
10548
|
-
const content = fs7.readFileSync(
|
|
11043
|
+
const content = fs7.readFileSync(path71.join(projectRoot, prettierConfigFile), "utf8");
|
|
10549
11044
|
if (!content.includes("zirka")) {
|
|
10550
11045
|
report3(
|
|
10551
11046
|
"The prettier config must take its configuration from zirka (styleguide({ prettier: true }).prettierConfig) instead of restating it locally."
|
|
@@ -10568,10 +11063,10 @@ function referencesZirka(sourceCode) {
|
|
|
10568
11063
|
// eslint/rules/zod-fetch-helper.ts
|
|
10569
11064
|
var HELPER4 = "zodFetch";
|
|
10570
11065
|
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 ${
|
|
11066
|
+
var DOC10 = "docs/pasika-adoption-guide/rules/zod-fetch-helper-rule.md";
|
|
11067
|
+
var FETCHED = `fetch must not be called; make the request through ${HELPER4} from ${ENTRY4}. See ${DOC10}`;
|
|
11068
|
+
var DECLARED4 = `A file must not declare its own ${HELPER4}; import it from ${ENTRY4}. See ${DOC10}`;
|
|
11069
|
+
var IMPORTED4 = `${HELPER4} must be imported from ${ENTRY4}. See ${DOC10}`;
|
|
10575
11070
|
var GLOBAL_OBJECTS = /* @__PURE__ */ new Set(["globalThis", "window", "self", "global"]);
|
|
10576
11071
|
var TEST_FILE2 = /(?:^|[\\/])(?:__tests__|tests)[\\/]|[.](?:test|spec)[.][cm]?[jt]sx?$/;
|
|
10577
11072
|
function isNamed4(node, name) {
|
|
@@ -10691,14 +11186,14 @@ var zodSchemaValidationRule = {
|
|
|
10691
11186
|
};
|
|
10692
11187
|
|
|
10693
11188
|
// eslint/ts-alignment.ts
|
|
10694
|
-
import { readFileSync as
|
|
11189
|
+
import { readFileSync as readFileSync16 } from "fs";
|
|
10695
11190
|
import { createRequire as createRequire2 } from "module";
|
|
10696
11191
|
import { join } from "path";
|
|
10697
11192
|
var ownRequire = createRequire2(import.meta.url);
|
|
10698
11193
|
var majorOf = (version) => Number(version.split(".")[0]);
|
|
10699
11194
|
function versionOf(packagePath) {
|
|
10700
11195
|
try {
|
|
10701
|
-
const parsed = JSON.parse(
|
|
11196
|
+
const parsed = JSON.parse(readFileSync16(packagePath, "utf8"));
|
|
10702
11197
|
if (typeof parsed !== "object" || parsed === null || !("version" in parsed)) return null;
|
|
10703
11198
|
return typeof parsed.version === "string" ? parsed.version : null;
|
|
10704
11199
|
} catch {
|