pasika 0.10.84 → 0.10.86
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.js +381 -316
- package/package.json +1 -1
|
@@ -164,7 +164,7 @@ var apiContractRule = {
|
|
|
164
164
|
|
|
165
165
|
// eslint/rules/application-structure.ts
|
|
166
166
|
import fs2 from "fs";
|
|
167
|
-
import
|
|
167
|
+
import path6 from "path";
|
|
168
168
|
|
|
169
169
|
// eslint/project/ccf.ts
|
|
170
170
|
import fs from "fs";
|
|
@@ -494,264 +494,8 @@ function parseModule(file) {
|
|
|
494
494
|
return { file: path3.resolve(file), imports, reexports, exports, namedNumericLiterals };
|
|
495
495
|
}
|
|
496
496
|
|
|
497
|
-
// eslint/rules/project-root.ts
|
|
498
|
-
import path4 from "path";
|
|
499
|
-
function sourceRootOf(context) {
|
|
500
|
-
return path4.resolve(context.cwd ?? process.cwd(), "src");
|
|
501
|
-
}
|
|
502
|
-
|
|
503
|
-
// eslint/rules/application-structure.ts
|
|
504
|
-
var MODULE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
505
|
-
var ROUTING_FILES = /* @__PURE__ */ new Set([
|
|
506
|
-
"default",
|
|
507
|
-
"error",
|
|
508
|
-
"global-error",
|
|
509
|
-
"instrumentation",
|
|
510
|
-
"layout",
|
|
511
|
-
"loading",
|
|
512
|
-
"middleware",
|
|
513
|
-
"not-found",
|
|
514
|
-
"page",
|
|
515
|
-
"route",
|
|
516
|
-
"template",
|
|
517
|
-
// File conventions Next.js requires to keep their exact names in src/app/
|
|
518
|
-
"apple-icon",
|
|
519
|
-
"icon",
|
|
520
|
-
"manifest",
|
|
521
|
-
"opengraph-image",
|
|
522
|
-
"robots",
|
|
523
|
-
"sitemap",
|
|
524
|
-
"twitter-image"
|
|
525
|
-
]);
|
|
526
|
-
var EXPECTED_SUPPORT_FOLDER = {
|
|
527
|
-
hook: "hooks",
|
|
528
|
-
type: "types",
|
|
529
|
-
schema: "schemas",
|
|
530
|
-
constant: "constants",
|
|
531
|
-
function: "utils"
|
|
532
|
-
};
|
|
533
|
-
function report(context, message) {
|
|
534
|
-
return {
|
|
535
|
-
Program(node) {
|
|
536
|
-
context.report({ node, loc: { line: 1, column: 0 }, message });
|
|
537
|
-
}
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
function isCodeFile(filename) {
|
|
541
|
-
return MODULE_EXTENSIONS.has(path5.extname(filename));
|
|
542
|
-
}
|
|
543
|
-
function isRootSupportFolder(folder) {
|
|
544
|
-
return SUPPORT_FOLDERS.has(folder);
|
|
545
|
-
}
|
|
546
|
-
function exportedKinds(filename) {
|
|
547
|
-
try {
|
|
548
|
-
return new Set(parseModule(filename).exports.map((moduleExport) => moduleExport.kind));
|
|
549
|
-
} catch {
|
|
550
|
-
return /* @__PURE__ */ new Set();
|
|
551
|
-
}
|
|
552
|
-
}
|
|
553
|
-
function expectedSupportFolder(kinds) {
|
|
554
|
-
for (const kind of ["component", "hook", "schema", "function", "constant", "type"]) {
|
|
555
|
-
if (kinds.has(kind)) return EXPECTED_SUPPORT_FOLDER[kind];
|
|
556
|
-
}
|
|
557
|
-
return void 0;
|
|
558
|
-
}
|
|
559
|
-
function mixedSupportKinds(folder, kinds) {
|
|
560
|
-
if (folder === "types") return kinds.has("type") && (kinds.has("constant") || kinds.has("schema"));
|
|
561
|
-
if (folder === "schemas") return kinds.has("schema") && (kinds.has("constant") || kinds.has("type"));
|
|
562
|
-
if (folder === "constants") return kinds.has("constant") && kinds.has("schema");
|
|
563
|
-
return false;
|
|
564
|
-
}
|
|
565
|
-
function configModuleRoot(filename, sourceRoot) {
|
|
566
|
-
const segments = segmentsOf(filename, sourceRoot);
|
|
567
|
-
if (segments[0] !== "config" || segments.length < 3) return void 0;
|
|
568
|
-
return path5.join(sourceRoot, "config", segments[1] ?? "");
|
|
569
|
-
}
|
|
570
|
-
function componentFolderStart(segments) {
|
|
571
|
-
if (segments[0] === "features") return 2;
|
|
572
|
-
if (segments[0] === "compositions" || segments[0] === "shared") return 1;
|
|
573
|
-
return -1;
|
|
574
|
-
}
|
|
575
|
-
function hasComponentBarrel(folderPath) {
|
|
576
|
-
return hasExactEntry(folderPath, "index.ts");
|
|
577
|
-
}
|
|
578
|
-
function componentFolderViolation(segments, sourceRoot) {
|
|
579
|
-
const start = componentFolderStart(segments);
|
|
580
|
-
if (start < 0) return void 0;
|
|
581
|
-
for (let depth = segments.length - 2; depth >= start; depth -= 1) {
|
|
582
|
-
const folder = segments[depth];
|
|
583
|
-
if (!folder || SUPPORT_FOLDERS.has(folder)) continue;
|
|
584
|
-
const folderPath = path5.join(sourceRoot, ...segments.slice(0, depth + 1));
|
|
585
|
-
const label = `src/${segments.slice(0, depth + 1).join("/")}/`;
|
|
586
|
-
if (!hasComponentOwner(folderPath, folder)) {
|
|
587
|
-
return `A folder that is not a support folder must be a component folder; add "${folder}.tsx" to ${label} or move its files into a support folder.`;
|
|
588
|
-
}
|
|
589
|
-
if (!hasComponentBarrel(folderPath)) {
|
|
590
|
-
return `A component folder must have an index.ts that named-re-exports its component; add index.ts to ${label}.`;
|
|
591
|
-
}
|
|
592
|
-
}
|
|
593
|
-
return void 0;
|
|
594
|
-
}
|
|
595
|
-
var applicationStructureRule = {
|
|
596
|
-
meta: {
|
|
597
|
-
schema: [],
|
|
598
|
-
type: "problem",
|
|
599
|
-
docs: {
|
|
600
|
-
description: "Enforce the repository's application, configuration, and support-folder structure."
|
|
601
|
-
}
|
|
602
|
-
},
|
|
603
|
-
create(context) {
|
|
604
|
-
const filename = path5.resolve(context.filename);
|
|
605
|
-
const sourceRoot = sourceRootOf(context);
|
|
606
|
-
const segments = segmentsOf(filename, sourceRoot);
|
|
607
|
-
if (segments.length === 0) return {};
|
|
608
|
-
const [topLevel, secondLevel] = segments;
|
|
609
|
-
if (topLevel === void 0) return {};
|
|
610
|
-
if (segments.length > 1 && topLevel !== "app" && topLevel !== "compositions" && topLevel !== "features" && topLevel !== "shared" && topLevel !== "config" && topLevel !== "locales" && !isRootSupportFolder(topLevel)) {
|
|
611
|
-
return report(
|
|
612
|
-
context,
|
|
613
|
-
`Move this source file under an allowed src/ folder; "src/${topLevel}/" is not part of the application structure.`
|
|
614
|
-
);
|
|
615
|
-
}
|
|
616
|
-
if (topLevel === "features" && segments.length >= 2 && secondLevel !== void 0) {
|
|
617
|
-
if (SUPPORT_FOLDERS.has(secondLevel)) {
|
|
618
|
-
return report(
|
|
619
|
-
context,
|
|
620
|
-
`Move this support folder inside a feature folder; "src/features/${secondLevel}/" does not belong to a feature.`
|
|
621
|
-
);
|
|
622
|
-
}
|
|
623
|
-
if (segments.length === 2) {
|
|
624
|
-
return report(context, "src/features/ must contain only feature folders, not source files.");
|
|
625
|
-
}
|
|
626
|
-
}
|
|
627
|
-
if (topLevel === "config") {
|
|
628
|
-
if (segments.length === 2) {
|
|
629
|
-
return report(
|
|
630
|
-
context,
|
|
631
|
-
"A configuration module must be a src/config/<config-name>/ folder with index.ts as its entry point."
|
|
632
|
-
);
|
|
633
|
-
}
|
|
634
|
-
const moduleRoot = configModuleRoot(filename, sourceRoot);
|
|
635
|
-
if (moduleRoot && !fs2.existsSync(path5.join(moduleRoot, "index.ts"))) {
|
|
636
|
-
return report(
|
|
637
|
-
context,
|
|
638
|
-
`Add src/config/${path5.basename(moduleRoot)}/index.ts as the configuration module entry point.`
|
|
639
|
-
);
|
|
640
|
-
}
|
|
641
|
-
if (moduleRoot && segments.length === 3 && path5.basename(filename) !== "index.ts") {
|
|
642
|
-
const kinds2 = exportedKinds(filename);
|
|
643
|
-
const expected2 = expectedSupportFolder(kinds2);
|
|
644
|
-
if (expected2 !== void 0) {
|
|
645
|
-
return report(
|
|
646
|
-
context,
|
|
647
|
-
`Move this configuration support file into src/config/${path5.basename(moduleRoot)}/${expected2}/.`
|
|
648
|
-
);
|
|
649
|
-
}
|
|
650
|
-
}
|
|
651
|
-
}
|
|
652
|
-
if (topLevel === "app" && isCodeFile(filename)) {
|
|
653
|
-
const basename = path5.basename(filename, path5.extname(filename));
|
|
654
|
-
const currentFolder2 = path5.basename(path5.dirname(filename));
|
|
655
|
-
if (SUPPORT_FOLDERS.has(currentFolder2)) {
|
|
656
|
-
return report(
|
|
657
|
-
context,
|
|
658
|
-
"src/app/ may contain routing files and framework assets, but ordinary components and support files must live outside src/app/."
|
|
659
|
-
);
|
|
660
|
-
}
|
|
661
|
-
if (!ROUTING_FILES.has(basename) && path5.extname(filename) !== ".css") {
|
|
662
|
-
return report(
|
|
663
|
-
context,
|
|
664
|
-
"src/app/ may contain routing files and framework assets, but ordinary components and support files must live outside src/app/."
|
|
665
|
-
);
|
|
666
|
-
}
|
|
667
|
-
if (ROUTING_FILES.has(basename) || path5.extname(filename) === ".css") return {};
|
|
668
|
-
}
|
|
669
|
-
const currentFolder = path5.basename(path5.dirname(filename));
|
|
670
|
-
const kinds = exportedKinds(filename);
|
|
671
|
-
const isConfigModuleRoot = topLevel === "config" && segments.length === 3 && path5.basename(filename) === "index.ts";
|
|
672
|
-
if (isConfigModuleRoot) return {};
|
|
673
|
-
if (!SUPPORT_FOLDERS.has(currentFolder)) {
|
|
674
|
-
const expected2 = expectedSupportFolder(kinds);
|
|
675
|
-
if (expected2 !== void 0 && segments.length > 2) {
|
|
676
|
-
return report(
|
|
677
|
-
context,
|
|
678
|
-
`Move this file to a ${expected2}/ folder; ${currentFolder}/ is not a recognized support folder.`
|
|
679
|
-
);
|
|
680
|
-
}
|
|
681
|
-
const violation2 = componentFolderViolation(segments, sourceRoot);
|
|
682
|
-
if (violation2 !== void 0) return report(context, violation2);
|
|
683
|
-
return {};
|
|
684
|
-
}
|
|
685
|
-
if (kinds.has("component")) {
|
|
686
|
-
return report(
|
|
687
|
-
context,
|
|
688
|
-
`A support folder must not contain a component; move ${path5.basename(filename)} beside ${currentFolder}/.`
|
|
689
|
-
);
|
|
690
|
-
}
|
|
691
|
-
if (mixedSupportKinds(currentFolder, kinds)) {
|
|
692
|
-
return report(
|
|
693
|
-
context,
|
|
694
|
-
`A ${currentFolder}/ folder must not mix unrelated support kinds; keep types, schemas, and constants in their matching folders.`
|
|
695
|
-
);
|
|
696
|
-
}
|
|
697
|
-
const expected = expectedSupportFolder(kinds);
|
|
698
|
-
if (expected !== void 0 && expected !== currentFolder) {
|
|
699
|
-
return report(
|
|
700
|
-
context,
|
|
701
|
-
`Move this file to a ${expected}/ folder; ${currentFolder}/ is reserved for ${expected === "utils" ? "utilities" : expected}.`
|
|
702
|
-
);
|
|
703
|
-
}
|
|
704
|
-
const violation = componentFolderViolation(segments, sourceRoot);
|
|
705
|
-
if (violation !== void 0) return report(context, violation);
|
|
706
|
-
return {};
|
|
707
|
-
}
|
|
708
|
-
};
|
|
709
|
-
|
|
710
|
-
// eslint/rules/cn-helper.ts
|
|
711
|
-
var HELPER2 = "cn";
|
|
712
|
-
var ENTRY2 = "pasika/cn";
|
|
713
|
-
var DOC2 = "docs/pasika-adoption-guide/rules/cn-helper-rule.md";
|
|
714
|
-
var DECLARED2 = `A file must not declare its own ${HELPER2}; import it from ${ENTRY2}. See ${DOC2}`;
|
|
715
|
-
var IMPORTED2 = `${HELPER2} must be imported from ${ENTRY2}. See ${DOC2}`;
|
|
716
|
-
function isNamed2(node, name) {
|
|
717
|
-
return node?.type === "Identifier" && node.name === name;
|
|
718
|
-
}
|
|
719
|
-
var cnHelperRule = {
|
|
720
|
-
meta: {
|
|
721
|
-
schema: [],
|
|
722
|
-
type: "problem",
|
|
723
|
-
docs: {
|
|
724
|
-
description: `Require ${HELPER2} to be imported from ${ENTRY2} rather than declared in the repository.`
|
|
725
|
-
}
|
|
726
|
-
},
|
|
727
|
-
create(context) {
|
|
728
|
-
const checkSource = (node) => {
|
|
729
|
-
if (!node.source || node.source.value === ENTRY2) return;
|
|
730
|
-
for (const specifier of node.specifiers) {
|
|
731
|
-
if (!isNamed2(specifier.local, HELPER2)) continue;
|
|
732
|
-
context.report({ node: specifier, message: IMPORTED2 });
|
|
733
|
-
}
|
|
734
|
-
};
|
|
735
|
-
return {
|
|
736
|
-
FunctionDeclaration(node) {
|
|
737
|
-
if (isNamed2(node.id, HELPER2)) context.report({ node, message: DECLARED2 });
|
|
738
|
-
},
|
|
739
|
-
VariableDeclarator(node) {
|
|
740
|
-
if (isNamed2(node.id.type === "Identifier" ? node.id : null, HELPER2)) {
|
|
741
|
-
context.report({ node, message: DECLARED2 });
|
|
742
|
-
}
|
|
743
|
-
},
|
|
744
|
-
ImportDeclaration: checkSource,
|
|
745
|
-
ExportNamedDeclaration: checkSource
|
|
746
|
-
};
|
|
747
|
-
}
|
|
748
|
-
};
|
|
749
|
-
|
|
750
|
-
// eslint/rules/component-casing.ts
|
|
751
|
-
import path7 from "path";
|
|
752
|
-
|
|
753
497
|
// eslint/rules/component-conventions.ts
|
|
754
|
-
import
|
|
498
|
+
import path4 from "path";
|
|
755
499
|
import ts2 from "typescript";
|
|
756
500
|
var isPascalCase2 = (name) => /^[A-Z][A-Za-z0-9]*$/.test(name);
|
|
757
501
|
var isHookCallName = (name) => /^use[A-Z]/.test(name);
|
|
@@ -868,7 +612,7 @@ function componentFromVariable(node) {
|
|
|
868
612
|
};
|
|
869
613
|
}
|
|
870
614
|
function parseComponentInfo(text, filename, options) {
|
|
871
|
-
const sourceFile = ts2.createSourceFile(
|
|
615
|
+
const sourceFile = ts2.createSourceFile(path4.resolve(filename), text, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
|
|
872
616
|
const components = [];
|
|
873
617
|
const namedExports = namedExportedLocalNames(sourceFile);
|
|
874
618
|
for (const statement of sourceFile.statements) {
|
|
@@ -892,7 +636,7 @@ function parseComponentInfo(text, filename, options) {
|
|
|
892
636
|
return components;
|
|
893
637
|
}
|
|
894
638
|
function findJsxReturningDeclarations(text, filename) {
|
|
895
|
-
const sourceFile = ts2.createSourceFile(
|
|
639
|
+
const sourceFile = ts2.createSourceFile(path4.resolve(filename), text, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
|
|
896
640
|
const results = [];
|
|
897
641
|
const record = (identifier, body) => {
|
|
898
642
|
if (isHookCallName(identifier.text) || !containsJsx(body)) return;
|
|
@@ -996,7 +740,286 @@ function findRenderedComponentMarkerPaths(component) {
|
|
|
996
740
|
});
|
|
997
741
|
}
|
|
998
742
|
|
|
743
|
+
// eslint/rules/project-root.ts
|
|
744
|
+
import path5 from "path";
|
|
745
|
+
function sourceRootOf(context) {
|
|
746
|
+
return path5.resolve(context.cwd ?? process.cwd(), "src");
|
|
747
|
+
}
|
|
748
|
+
|
|
749
|
+
// eslint/rules/application-structure.ts
|
|
750
|
+
var MODULE_EXTENSIONS = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
751
|
+
var ROUTING_FILES = /* @__PURE__ */ new Set([
|
|
752
|
+
"default",
|
|
753
|
+
"error",
|
|
754
|
+
"global-error",
|
|
755
|
+
"instrumentation",
|
|
756
|
+
"layout",
|
|
757
|
+
"loading",
|
|
758
|
+
"middleware",
|
|
759
|
+
"not-found",
|
|
760
|
+
"page",
|
|
761
|
+
"route",
|
|
762
|
+
"template",
|
|
763
|
+
// File conventions Next.js requires to keep their exact names in src/app/
|
|
764
|
+
"apple-icon",
|
|
765
|
+
"icon",
|
|
766
|
+
"manifest",
|
|
767
|
+
"opengraph-image",
|
|
768
|
+
"robots",
|
|
769
|
+
"sitemap",
|
|
770
|
+
"twitter-image"
|
|
771
|
+
]);
|
|
772
|
+
var EXPECTED_SUPPORT_FOLDER = {
|
|
773
|
+
hook: "hooks",
|
|
774
|
+
type: "types",
|
|
775
|
+
schema: "schemas",
|
|
776
|
+
constant: "constants",
|
|
777
|
+
function: "utils"
|
|
778
|
+
};
|
|
779
|
+
function report(context, message) {
|
|
780
|
+
return {
|
|
781
|
+
Program(node) {
|
|
782
|
+
context.report({ node, loc: { line: 1, column: 0 }, message });
|
|
783
|
+
}
|
|
784
|
+
};
|
|
785
|
+
}
|
|
786
|
+
function isCodeFile(filename) {
|
|
787
|
+
return MODULE_EXTENSIONS.has(path6.extname(filename));
|
|
788
|
+
}
|
|
789
|
+
function isRootSupportFolder(folder) {
|
|
790
|
+
return SUPPORT_FOLDERS.has(folder);
|
|
791
|
+
}
|
|
792
|
+
function exportedKinds(filename) {
|
|
793
|
+
try {
|
|
794
|
+
return new Set(parseModule(filename).exports.map((moduleExport) => moduleExport.kind));
|
|
795
|
+
} catch {
|
|
796
|
+
return /* @__PURE__ */ new Set();
|
|
797
|
+
}
|
|
798
|
+
}
|
|
799
|
+
function expectedSupportFolder(kinds) {
|
|
800
|
+
for (const kind of ["component", "hook", "schema", "function", "constant", "type"]) {
|
|
801
|
+
if (kinds.has(kind)) return EXPECTED_SUPPORT_FOLDER[kind];
|
|
802
|
+
}
|
|
803
|
+
return void 0;
|
|
804
|
+
}
|
|
805
|
+
function mixedSupportKinds(folder, kinds) {
|
|
806
|
+
if (folder === "types") return kinds.has("type") && (kinds.has("constant") || kinds.has("schema"));
|
|
807
|
+
if (folder === "schemas") return kinds.has("schema") && (kinds.has("constant") || kinds.has("type"));
|
|
808
|
+
if (folder === "constants") return kinds.has("constant") && kinds.has("schema");
|
|
809
|
+
return false;
|
|
810
|
+
}
|
|
811
|
+
function configModuleRoot(filename, sourceRoot) {
|
|
812
|
+
const segments = segmentsOf(filename, sourceRoot);
|
|
813
|
+
if (segments[0] !== "config" || segments.length < 3) return void 0;
|
|
814
|
+
return path6.join(sourceRoot, "config", segments[1] ?? "");
|
|
815
|
+
}
|
|
816
|
+
function componentFolderStart(segments) {
|
|
817
|
+
if (segments[0] === "features") return 2;
|
|
818
|
+
if (segments[0] === "compositions" || segments[0] === "shared") return 1;
|
|
819
|
+
return -1;
|
|
820
|
+
}
|
|
821
|
+
function hasComponentBarrel(folderPath) {
|
|
822
|
+
return hasExactEntry(folderPath, "index.ts");
|
|
823
|
+
}
|
|
824
|
+
function componentFolderViolation(segments, sourceRoot) {
|
|
825
|
+
const start = componentFolderStart(segments);
|
|
826
|
+
if (start < 0) return void 0;
|
|
827
|
+
for (let depth = segments.length - 2; depth >= start; depth -= 1) {
|
|
828
|
+
const folder = segments[depth];
|
|
829
|
+
if (!folder || SUPPORT_FOLDERS.has(folder)) continue;
|
|
830
|
+
const folderPath = path6.join(sourceRoot, ...segments.slice(0, depth + 1));
|
|
831
|
+
const label = `src/${segments.slice(0, depth + 1).join("/")}/`;
|
|
832
|
+
if (!hasComponentOwner(folderPath, folder)) {
|
|
833
|
+
return `A folder that is not a support folder must be a component folder; add "${folder}.tsx" to ${label} or move its files into a support folder.`;
|
|
834
|
+
}
|
|
835
|
+
if (!hasComponentBarrel(folderPath)) {
|
|
836
|
+
return `A component folder must have an index.ts that named-re-exports its component; add index.ts to ${label}.`;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
return void 0;
|
|
840
|
+
}
|
|
841
|
+
function componentFacadeTarget(context, filename) {
|
|
842
|
+
if (path6.extname(filename) !== ".ts" || path6.basename(filename) === "index.ts") return void 0;
|
|
843
|
+
const statements = context.sourceCode.ast.body;
|
|
844
|
+
if (statements.length === 0 || statements.some((node) => node.type !== "ExportNamedDeclaration" || !node.source)) {
|
|
845
|
+
return void 0;
|
|
846
|
+
}
|
|
847
|
+
const exports = statements.flatMap((node) => node.type === "ExportNamedDeclaration" ? node.specifiers : []);
|
|
848
|
+
const sources = statements.map((node) => node.type === "ExportNamedDeclaration" ? node.source?.value : void 0);
|
|
849
|
+
if (new Set(sources).size !== 1 || typeof sources[0] !== "string" || !sources[0].startsWith("./")) {
|
|
850
|
+
return void 0;
|
|
851
|
+
}
|
|
852
|
+
const componentFile = path6.resolve(path6.dirname(filename), `${sources[0]}.tsx`);
|
|
853
|
+
if (!fs2.existsSync(componentFile)) return void 0;
|
|
854
|
+
const components = parseComponentInfo(fs2.readFileSync(componentFile, "utf8"), componentFile);
|
|
855
|
+
return components.some(
|
|
856
|
+
({ name }) => exports.some((specifier) => specifier.local.type === "Identifier" && specifier.local.name === name)
|
|
857
|
+
) ? componentFile : void 0;
|
|
858
|
+
}
|
|
859
|
+
var applicationStructureRule = {
|
|
860
|
+
meta: {
|
|
861
|
+
schema: [],
|
|
862
|
+
type: "problem",
|
|
863
|
+
docs: {
|
|
864
|
+
description: "Enforce the repository's application, configuration, and support-folder structure."
|
|
865
|
+
}
|
|
866
|
+
},
|
|
867
|
+
create(context) {
|
|
868
|
+
const filename = path6.resolve(context.filename);
|
|
869
|
+
const sourceRoot = sourceRootOf(context);
|
|
870
|
+
const segments = segmentsOf(filename, sourceRoot);
|
|
871
|
+
if (segments.length === 0) return {};
|
|
872
|
+
const componentTarget = componentFacadeTarget(context, filename);
|
|
873
|
+
if (componentTarget) {
|
|
874
|
+
return report(
|
|
875
|
+
context,
|
|
876
|
+
`Avoid a forwarding .ts file for a sibling component: move the implementation from ${path6.basename(componentTarget)} to ${path6.basename(filename, ".ts")}.tsx and remove the .ts facade.`
|
|
877
|
+
);
|
|
878
|
+
}
|
|
879
|
+
const [topLevel, secondLevel] = segments;
|
|
880
|
+
if (topLevel === void 0) return {};
|
|
881
|
+
if (segments.length > 1 && topLevel !== "app" && topLevel !== "compositions" && topLevel !== "features" && topLevel !== "shared" && topLevel !== "config" && topLevel !== "locales" && !isRootSupportFolder(topLevel)) {
|
|
882
|
+
return report(
|
|
883
|
+
context,
|
|
884
|
+
`Move this source file under an allowed src/ folder; "src/${topLevel}/" is not part of the application structure.`
|
|
885
|
+
);
|
|
886
|
+
}
|
|
887
|
+
if (topLevel === "features" && segments.length >= 2 && secondLevel !== void 0) {
|
|
888
|
+
if (SUPPORT_FOLDERS.has(secondLevel)) {
|
|
889
|
+
return report(
|
|
890
|
+
context,
|
|
891
|
+
`Move this support folder inside a feature folder; "src/features/${secondLevel}/" does not belong to a feature.`
|
|
892
|
+
);
|
|
893
|
+
}
|
|
894
|
+
if (segments.length === 2) {
|
|
895
|
+
return report(context, "src/features/ must contain only feature folders, not source files.");
|
|
896
|
+
}
|
|
897
|
+
}
|
|
898
|
+
if (topLevel === "config") {
|
|
899
|
+
if (segments.length === 2) {
|
|
900
|
+
return report(
|
|
901
|
+
context,
|
|
902
|
+
"A configuration module must be a src/config/<config-name>/ folder with index.ts as its entry point."
|
|
903
|
+
);
|
|
904
|
+
}
|
|
905
|
+
const moduleRoot = configModuleRoot(filename, sourceRoot);
|
|
906
|
+
if (moduleRoot && !fs2.existsSync(path6.join(moduleRoot, "index.ts"))) {
|
|
907
|
+
return report(
|
|
908
|
+
context,
|
|
909
|
+
`Add src/config/${path6.basename(moduleRoot)}/index.ts as the configuration module entry point.`
|
|
910
|
+
);
|
|
911
|
+
}
|
|
912
|
+
if (moduleRoot && segments.length === 3 && path6.basename(filename) !== "index.ts") {
|
|
913
|
+
const kinds2 = exportedKinds(filename);
|
|
914
|
+
const expected2 = expectedSupportFolder(kinds2);
|
|
915
|
+
if (expected2 !== void 0) {
|
|
916
|
+
return report(
|
|
917
|
+
context,
|
|
918
|
+
`Move this configuration support file into src/config/${path6.basename(moduleRoot)}/${expected2}/.`
|
|
919
|
+
);
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
}
|
|
923
|
+
if (topLevel === "app" && isCodeFile(filename)) {
|
|
924
|
+
const basename = path6.basename(filename, path6.extname(filename));
|
|
925
|
+
const currentFolder2 = path6.basename(path6.dirname(filename));
|
|
926
|
+
if (SUPPORT_FOLDERS.has(currentFolder2)) {
|
|
927
|
+
return report(
|
|
928
|
+
context,
|
|
929
|
+
"src/app/ may contain routing files and framework assets, but ordinary components and support files must live outside src/app/."
|
|
930
|
+
);
|
|
931
|
+
}
|
|
932
|
+
if (!ROUTING_FILES.has(basename) && path6.extname(filename) !== ".css") {
|
|
933
|
+
return report(
|
|
934
|
+
context,
|
|
935
|
+
"src/app/ may contain routing files and framework assets, but ordinary components and support files must live outside src/app/."
|
|
936
|
+
);
|
|
937
|
+
}
|
|
938
|
+
if (ROUTING_FILES.has(basename) || path6.extname(filename) === ".css") return {};
|
|
939
|
+
}
|
|
940
|
+
const currentFolder = path6.basename(path6.dirname(filename));
|
|
941
|
+
const kinds = exportedKinds(filename);
|
|
942
|
+
const isConfigModuleRoot = topLevel === "config" && segments.length === 3 && path6.basename(filename) === "index.ts";
|
|
943
|
+
if (isConfigModuleRoot) return {};
|
|
944
|
+
if (!SUPPORT_FOLDERS.has(currentFolder)) {
|
|
945
|
+
const expected2 = expectedSupportFolder(kinds);
|
|
946
|
+
if (expected2 !== void 0 && segments.length > 2) {
|
|
947
|
+
return report(
|
|
948
|
+
context,
|
|
949
|
+
`Move this file to a ${expected2}/ folder; ${currentFolder}/ is not a recognized support folder.`
|
|
950
|
+
);
|
|
951
|
+
}
|
|
952
|
+
const violation2 = componentFolderViolation(segments, sourceRoot);
|
|
953
|
+
if (violation2 !== void 0) return report(context, violation2);
|
|
954
|
+
return {};
|
|
955
|
+
}
|
|
956
|
+
if (kinds.has("component")) {
|
|
957
|
+
return report(
|
|
958
|
+
context,
|
|
959
|
+
`A support folder must not contain a component; move ${path6.basename(filename)} beside ${currentFolder}/.`
|
|
960
|
+
);
|
|
961
|
+
}
|
|
962
|
+
if (mixedSupportKinds(currentFolder, kinds)) {
|
|
963
|
+
return report(
|
|
964
|
+
context,
|
|
965
|
+
`A ${currentFolder}/ folder must not mix unrelated support kinds; keep types, schemas, and constants in their matching folders.`
|
|
966
|
+
);
|
|
967
|
+
}
|
|
968
|
+
const expected = expectedSupportFolder(kinds);
|
|
969
|
+
if (expected !== void 0 && expected !== currentFolder) {
|
|
970
|
+
return report(
|
|
971
|
+
context,
|
|
972
|
+
`Move this file to a ${expected}/ folder; ${currentFolder}/ is reserved for ${expected === "utils" ? "utilities" : expected}.`
|
|
973
|
+
);
|
|
974
|
+
}
|
|
975
|
+
const violation = componentFolderViolation(segments, sourceRoot);
|
|
976
|
+
if (violation !== void 0) return report(context, violation);
|
|
977
|
+
return {};
|
|
978
|
+
}
|
|
979
|
+
};
|
|
980
|
+
|
|
981
|
+
// eslint/rules/cn-helper.ts
|
|
982
|
+
var HELPER2 = "cn";
|
|
983
|
+
var ENTRY2 = "pasika/cn";
|
|
984
|
+
var DOC2 = "docs/pasika-adoption-guide/rules/cn-helper-rule.md";
|
|
985
|
+
var DECLARED2 = `A file must not declare its own ${HELPER2}; import it from ${ENTRY2}. See ${DOC2}`;
|
|
986
|
+
var IMPORTED2 = `${HELPER2} must be imported from ${ENTRY2}. See ${DOC2}`;
|
|
987
|
+
function isNamed2(node, name) {
|
|
988
|
+
return node?.type === "Identifier" && node.name === name;
|
|
989
|
+
}
|
|
990
|
+
var cnHelperRule = {
|
|
991
|
+
meta: {
|
|
992
|
+
schema: [],
|
|
993
|
+
type: "problem",
|
|
994
|
+
docs: {
|
|
995
|
+
description: `Require ${HELPER2} to be imported from ${ENTRY2} rather than declared in the repository.`
|
|
996
|
+
}
|
|
997
|
+
},
|
|
998
|
+
create(context) {
|
|
999
|
+
const checkSource = (node) => {
|
|
1000
|
+
if (!node.source || node.source.value === ENTRY2) return;
|
|
1001
|
+
for (const specifier of node.specifiers) {
|
|
1002
|
+
if (!isNamed2(specifier.local, HELPER2)) continue;
|
|
1003
|
+
context.report({ node: specifier, message: IMPORTED2 });
|
|
1004
|
+
}
|
|
1005
|
+
};
|
|
1006
|
+
return {
|
|
1007
|
+
FunctionDeclaration(node) {
|
|
1008
|
+
if (isNamed2(node.id, HELPER2)) context.report({ node, message: DECLARED2 });
|
|
1009
|
+
},
|
|
1010
|
+
VariableDeclarator(node) {
|
|
1011
|
+
if (isNamed2(node.id.type === "Identifier" ? node.id : null, HELPER2)) {
|
|
1012
|
+
context.report({ node, message: DECLARED2 });
|
|
1013
|
+
}
|
|
1014
|
+
},
|
|
1015
|
+
ImportDeclaration: checkSource,
|
|
1016
|
+
ExportNamedDeclaration: checkSource
|
|
1017
|
+
};
|
|
1018
|
+
}
|
|
1019
|
+
};
|
|
1020
|
+
|
|
999
1021
|
// eslint/rules/component-casing.ts
|
|
1022
|
+
import path7 from "path";
|
|
1000
1023
|
function isPascalCase3(name) {
|
|
1001
1024
|
return /^[A-Z][A-Za-z0-9]*$/.test(name);
|
|
1002
1025
|
}
|
|
@@ -6221,14 +6244,16 @@ var preferEnumRule = {
|
|
|
6221
6244
|
};
|
|
6222
6245
|
|
|
6223
6246
|
// eslint/rules/prefer-object-destructuring.ts
|
|
6247
|
+
import ts8 from "typescript";
|
|
6224
6248
|
var DOC5 = "See docs/next-codebase-guide/rules/redundant-aliases-rule.md";
|
|
6225
6249
|
function hasTypeAnnotation(identifier) {
|
|
6226
6250
|
return "typeAnnotation" in identifier && identifier.typeAnnotation !== void 0;
|
|
6227
6251
|
}
|
|
6228
|
-
function directPropertyBinding(context, declarator) {
|
|
6252
|
+
function directPropertyBinding(context, declarator, isEnumValue) {
|
|
6229
6253
|
if (declarator.id.type !== "Identifier" || hasTypeAnnotation(declarator.id)) return void 0;
|
|
6230
6254
|
if (declarator.init?.type !== "MemberExpression") return void 0;
|
|
6231
6255
|
const member = declarator.init;
|
|
6256
|
+
if (isEnumValue(member.object)) return void 0;
|
|
6232
6257
|
if (member.computed || member.optional || member.property.type !== "Identifier") return void 0;
|
|
6233
6258
|
if (!memberCanBecomeLocal(member)) return void 0;
|
|
6234
6259
|
if (context.sourceCode.getCommentsInside(declarator).length > 0) return void 0;
|
|
@@ -6289,6 +6314,37 @@ function memberCanBecomeLocal(member) {
|
|
|
6289
6314
|
if (rootIdentifierName(member) === "locales") return false;
|
|
6290
6315
|
return member.property.type === "Identifier" && isCompliantLocalName(member.property.name);
|
|
6291
6316
|
}
|
|
6317
|
+
function isEnumDefinition(definition) {
|
|
6318
|
+
return typeof definition === "object" && definition !== null && "type" in definition && definition.type === "TSEnumName";
|
|
6319
|
+
}
|
|
6320
|
+
function localEnumBinding(context, node) {
|
|
6321
|
+
if (node.type !== "Identifier") return false;
|
|
6322
|
+
let scope = context.sourceCode.getScope(node);
|
|
6323
|
+
for (; ; ) {
|
|
6324
|
+
const variable = scope.variables.find(({ name }) => name === node.name);
|
|
6325
|
+
if (variable) return variable.defs.some(isEnumDefinition);
|
|
6326
|
+
if (scope.upper === null) return false;
|
|
6327
|
+
scope = scope.upper;
|
|
6328
|
+
}
|
|
6329
|
+
}
|
|
6330
|
+
function enumValueResolver(context) {
|
|
6331
|
+
const services = typedParserServices(context.sourceCode.parserServices);
|
|
6332
|
+
if (!services) return (node) => localEnumBinding(context, node);
|
|
6333
|
+
const checker = services.program.getTypeChecker();
|
|
6334
|
+
const { esTreeNodeToTSNodeMap: nodeMap } = services;
|
|
6335
|
+
const isEnumSymbol = (symbol) => {
|
|
6336
|
+
const resolved = symbol.flags === ts8.SymbolFlags.Alias ? checker.getAliasedSymbol(symbol) : symbol;
|
|
6337
|
+
return (resolved.declarations ?? []).some((declaration) => ts8.isEnumDeclaration(declaration));
|
|
6338
|
+
};
|
|
6339
|
+
return (node) => {
|
|
6340
|
+
const tsNode = nodeMap.get(node);
|
|
6341
|
+
if (!tsNode) return localEnumBinding(context, node);
|
|
6342
|
+
const symbol = checker.getSymbolAtLocation(tsNode);
|
|
6343
|
+
if (symbol && isEnumSymbol(symbol)) return true;
|
|
6344
|
+
const typeSymbol = checker.getTypeAtLocation(tsNode).getSymbol();
|
|
6345
|
+
return typeSymbol ? isEnumSymbol(typeSymbol) : localEnumBinding(context, node);
|
|
6346
|
+
};
|
|
6347
|
+
}
|
|
6292
6348
|
function directMappingRequiresQualifiedAccess(context, ownershipResolver, member) {
|
|
6293
6349
|
const mapping = renamedDirectMapping(context, member);
|
|
6294
6350
|
if (!mapping || !ownershipResolver) return false;
|
|
@@ -6296,8 +6352,8 @@ function directMappingRequiresQualifiedAccess(context, ownershipResolver, member
|
|
|
6296
6352
|
const targetResolution = ownershipResolver.targetProperty(mapping.property, mapping.targetName);
|
|
6297
6353
|
return sourceResolution.kind === "data-contract" || targetResolution.kind === "data-contract";
|
|
6298
6354
|
}
|
|
6299
|
-
function memberCanBeDestructured(context, ownershipResolver, member) {
|
|
6300
|
-
return memberCanBecomeLocal(member) && !directMappingRequiresQualifiedAccess(context, ownershipResolver, member);
|
|
6355
|
+
function memberCanBeDestructured(context, ownershipResolver, member, isEnumValue) {
|
|
6356
|
+
return !isEnumValue(member.object) && memberCanBecomeLocal(member) && !directMappingRequiresQualifiedAccess(context, ownershipResolver, member);
|
|
6301
6357
|
}
|
|
6302
6358
|
function objectUsage(scope, sourceText) {
|
|
6303
6359
|
let usage = scope.objects.get(sourceText);
|
|
@@ -6322,9 +6378,9 @@ function memberIsDirectVariableInitializer(context, member) {
|
|
|
6322
6378
|
const parent = context.sourceCode.getAncestors(member).at(-1);
|
|
6323
6379
|
return parent?.type === "VariableDeclarator" && parent.init === member;
|
|
6324
6380
|
}
|
|
6325
|
-
function recordMemberUsage(context, scope, ownershipResolver, member) {
|
|
6381
|
+
function recordMemberUsage(context, scope, ownershipResolver, member, isEnumValue) {
|
|
6326
6382
|
if (!scope || member.computed || member.optional || member.property.type !== "Identifier") return;
|
|
6327
|
-
if (!memberCanBeDestructured(context, ownershipResolver, member)) return;
|
|
6383
|
+
if (!memberCanBeDestructured(context, ownershipResolver, member, isEnumValue)) return;
|
|
6328
6384
|
if (!isGroupedUsageSource(member.object) || !memberIsRead(context, member)) return;
|
|
6329
6385
|
const sourceText = context.sourceCode.getText(member.object);
|
|
6330
6386
|
const usage = objectUsage(scope, sourceText);
|
|
@@ -6334,11 +6390,11 @@ function recordMemberUsage(context, scope, ownershipResolver, member) {
|
|
|
6334
6390
|
usage.directMembers.push({ member, propertyName: propertyName5 });
|
|
6335
6391
|
}
|
|
6336
6392
|
}
|
|
6337
|
-
function recordDestructuringUsage(context, scope, declaration) {
|
|
6393
|
+
function recordDestructuringUsage(context, scope, declaration, isEnumValue) {
|
|
6338
6394
|
if (!scope) return;
|
|
6339
6395
|
for (const declarator of declaration.declarations) {
|
|
6340
6396
|
if (declarator.id.type !== "ObjectPattern" || !declarator.init || !isGroupedUsageSource(declarator.init)) continue;
|
|
6341
|
-
if (rootIdentifierName(declarator.init) === "locales") continue;
|
|
6397
|
+
if (rootIdentifierName(declarator.init) === "locales" || isEnumValue(declarator.init)) continue;
|
|
6342
6398
|
const sourceText = context.sourceCode.getText(declarator.init);
|
|
6343
6399
|
const usage = objectUsage(scope, sourceText);
|
|
6344
6400
|
if (usage.directMembers.length > 0) continue;
|
|
@@ -6385,7 +6441,7 @@ function whitespaceKeepsStatementsAdjacent(text) {
|
|
|
6385
6441
|
if (text.trim() !== "") return false;
|
|
6386
6442
|
return (text.match(/\n/gu) ?? []).length <= 1;
|
|
6387
6443
|
}
|
|
6388
|
-
function groupedDeclarations(context, declaration, firstBinding) {
|
|
6444
|
+
function groupedDeclarations(context, declaration, firstBinding, isEnumValue) {
|
|
6389
6445
|
if (declaration.declarations.length !== 1) {
|
|
6390
6446
|
return [{ declaration, binding: firstBinding }];
|
|
6391
6447
|
}
|
|
@@ -6405,7 +6461,7 @@ function groupedDeclarations(context, declaration, firstBinding) {
|
|
|
6405
6461
|
if (nextNode.declarations.length !== 1) break;
|
|
6406
6462
|
const nextDeclarator = nextNode.declarations[0];
|
|
6407
6463
|
if (!nextDeclarator) break;
|
|
6408
|
-
const nextBinding = directPropertyBinding(context, nextDeclarator);
|
|
6464
|
+
const nextBinding = directPropertyBinding(context, nextDeclarator, isEnumValue);
|
|
6409
6465
|
if (nextBinding?.sourceText !== firstBinding.sourceText) break;
|
|
6410
6466
|
if (seenProperties.has(nextBinding.propertyName)) break;
|
|
6411
6467
|
const [, previousEnd] = context.sourceCode.getRange(previous);
|
|
@@ -6417,11 +6473,11 @@ function groupedDeclarations(context, declaration, firstBinding) {
|
|
|
6417
6473
|
}
|
|
6418
6474
|
return group;
|
|
6419
6475
|
}
|
|
6420
|
-
function destructuringSelection(context, declaration) {
|
|
6476
|
+
function destructuringSelection(context, declaration, isEnumValue) {
|
|
6421
6477
|
if (declaration.declarations.length !== 1) return void 0;
|
|
6422
6478
|
const declarator = declaration.declarations[0];
|
|
6423
6479
|
if (declarator?.id.type !== "ObjectPattern" || !declarator.init) return void 0;
|
|
6424
|
-
if (rootIdentifierName(declarator.init) === "locales") return void 0;
|
|
6480
|
+
if (rootIdentifierName(declarator.init) === "locales" || isEnumValue(declarator.init)) return void 0;
|
|
6425
6481
|
if (context.sourceCode.getCommentsInside(declarator).length > 0) return void 0;
|
|
6426
6482
|
const bindingTexts = [];
|
|
6427
6483
|
const localNames = [];
|
|
@@ -6444,7 +6500,7 @@ function destructuringSelection(context, declaration) {
|
|
|
6444
6500
|
propertyNames
|
|
6445
6501
|
};
|
|
6446
6502
|
}
|
|
6447
|
-
function groupedDestructuringSelections(context, first) {
|
|
6503
|
+
function groupedDestructuringSelections(context, first, isEnumValue) {
|
|
6448
6504
|
const parent = context.sourceCode.getAncestors(first.declaration).at(-1);
|
|
6449
6505
|
if (parent?.type !== "Program" && parent?.type !== "BlockStatement") return [first];
|
|
6450
6506
|
const body = parent.body;
|
|
@@ -6456,7 +6512,7 @@ function groupedDestructuringSelections(context, first) {
|
|
|
6456
6512
|
const nextNode = body[index];
|
|
6457
6513
|
const previous = group.at(-1)?.declaration;
|
|
6458
6514
|
if (!previous || nextNode?.type !== "VariableDeclaration" || nextNode.kind !== first.declaration.kind) break;
|
|
6459
|
-
const next = destructuringSelection(context, nextNode);
|
|
6515
|
+
const next = destructuringSelection(context, nextNode, isEnumValue);
|
|
6460
6516
|
if (next?.sourceText !== first.sourceText) break;
|
|
6461
6517
|
if (next.propertyNames.some((propertyName5) => seenProperties.has(propertyName5))) break;
|
|
6462
6518
|
const [, previousEnd] = context.sourceCode.getRange(previous);
|
|
@@ -6497,6 +6553,7 @@ var preferObjectDestructuringRule = {
|
|
|
6497
6553
|
},
|
|
6498
6554
|
create(context) {
|
|
6499
6555
|
const ownershipResolver = contractOwnershipResolver(context);
|
|
6556
|
+
const isEnumValue = enumValueResolver(context);
|
|
6500
6557
|
const grouped = /* @__PURE__ */ new Set();
|
|
6501
6558
|
const usageScopes = [];
|
|
6502
6559
|
const currentUsageScope = () => usageScopes.at(-1);
|
|
@@ -6561,14 +6618,22 @@ ${indentation}`;
|
|
|
6561
6618
|
ArrowFunctionExpression: enterUsageBarrier,
|
|
6562
6619
|
"ArrowFunctionExpression:exit": exitUsageScope,
|
|
6563
6620
|
MemberExpression(node) {
|
|
6564
|
-
recordMemberUsage(context, currentUsageScope(), ownershipResolver, node);
|
|
6621
|
+
recordMemberUsage(context, currentUsageScope(), ownershipResolver, node, isEnumValue);
|
|
6565
6622
|
},
|
|
6566
6623
|
VariableDeclaration(node) {
|
|
6567
|
-
|
|
6624
|
+
for (const declarator of node.declarations) {
|
|
6625
|
+
if (declarator.id.type !== "ObjectPattern" || !declarator.init || !isEnumValue(declarator.init)) continue;
|
|
6626
|
+
const sourceText = context.sourceCode.getText(declarator.init);
|
|
6627
|
+
context.report({
|
|
6628
|
+
node: declarator.id,
|
|
6629
|
+
message: `"${sourceText}" is an enum. Keep enum member accesses qualified instead of destructuring it. ${DOC5}`
|
|
6630
|
+
});
|
|
6631
|
+
}
|
|
6632
|
+
recordDestructuringUsage(context, currentUsageScope(), node, isEnumValue);
|
|
6568
6633
|
if (grouped.has(node)) return;
|
|
6569
|
-
const selection = destructuringSelection(context, node);
|
|
6634
|
+
const selection = destructuringSelection(context, node, isEnumValue);
|
|
6570
6635
|
if (selection) {
|
|
6571
|
-
const group = groupedDestructuringSelections(context, selection);
|
|
6636
|
+
const group = groupedDestructuringSelections(context, selection, isEnumValue);
|
|
6572
6637
|
if (group.length <= 1) return;
|
|
6573
6638
|
for (const item of group.slice(1)) grouped.add(item.declaration);
|
|
6574
6639
|
const lastDeclaration = group.at(-1)?.declaration;
|
|
@@ -6590,7 +6655,7 @@ ${indentation}`;
|
|
|
6590
6655
|
});
|
|
6591
6656
|
return;
|
|
6592
6657
|
}
|
|
6593
|
-
const bindings = node.declarations.map((declarator) => directPropertyBinding(context, declarator)).filter((binding) => binding !== void 0);
|
|
6658
|
+
const bindings = node.declarations.map((declarator) => directPropertyBinding(context, declarator, isEnumValue)).filter((binding) => binding !== void 0);
|
|
6594
6659
|
if (bindings.length === 0) return;
|
|
6595
6660
|
const firstBinding = bindings[0];
|
|
6596
6661
|
if (!firstBinding) return;
|
|
@@ -6611,7 +6676,7 @@ ${indentation}`;
|
|
|
6611
6676
|
return;
|
|
6612
6677
|
}
|
|
6613
6678
|
if (node.declarations.length === 1 && bindings.length === 1) {
|
|
6614
|
-
const group = groupedDeclarations(context, node, firstBinding);
|
|
6679
|
+
const group = groupedDeclarations(context, node, firstBinding, isEnumValue);
|
|
6615
6680
|
if (group.length > 1) {
|
|
6616
6681
|
for (const item of group.slice(1)) grouped.add(item.declaration);
|
|
6617
6682
|
const groupBindings = group.map(({ binding }) => binding);
|
|
@@ -7184,7 +7249,7 @@ var rootSupportPlacementRule = {
|
|
|
7184
7249
|
|
|
7185
7250
|
// eslint/rules/route-handler-shape.ts
|
|
7186
7251
|
import path48 from "path";
|
|
7187
|
-
import
|
|
7252
|
+
import ts9 from "typescript";
|
|
7188
7253
|
var HTTP_METHODS2 = /* @__PURE__ */ new Set(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
|
|
7189
7254
|
var REQUIRED_BOUNDARY = "withResponse";
|
|
7190
7255
|
function isFunctionLike(node) {
|
|
@@ -7202,33 +7267,33 @@ function findHandler(node) {
|
|
|
7202
7267
|
return void 0;
|
|
7203
7268
|
}
|
|
7204
7269
|
function isLoop(node) {
|
|
7205
|
-
return
|
|
7270
|
+
return ts9.isForStatement(node) || ts9.isForOfStatement(node) || ts9.isForInStatement(node) || ts9.isWhileStatement(node) || ts9.isDoStatement(node);
|
|
7206
7271
|
}
|
|
7207
7272
|
function isFunctionBoundary(node) {
|
|
7208
|
-
return
|
|
7273
|
+
return ts9.isFunctionExpression(node) || ts9.isArrowFunction(node) || ts9.isFunctionDeclaration(node);
|
|
7209
7274
|
}
|
|
7210
7275
|
function analyzeHandlerBody(body, sourceText) {
|
|
7211
7276
|
const start = body.range?.[0] ?? 0;
|
|
7212
7277
|
const end = body.range?.[1] ?? sourceText.length;
|
|
7213
|
-
const sourceFile =
|
|
7278
|
+
const sourceFile = ts9.createSourceFile(
|
|
7214
7279
|
"route.ts",
|
|
7215
7280
|
sourceText.slice(start, end),
|
|
7216
|
-
|
|
7281
|
+
ts9.ScriptTarget.Latest,
|
|
7217
7282
|
true,
|
|
7218
|
-
|
|
7283
|
+
ts9.ScriptKind.TS
|
|
7219
7284
|
);
|
|
7220
7285
|
const kinds = /* @__PURE__ */ new Set();
|
|
7221
7286
|
const calledNames = /* @__PURE__ */ new Set();
|
|
7222
7287
|
const visit = (node) => {
|
|
7223
|
-
if (
|
|
7288
|
+
if (ts9.isTryStatement(node)) kinds.add("try");
|
|
7224
7289
|
if (isLoop(node)) kinds.add("loop");
|
|
7225
|
-
if (
|
|
7226
|
-
if (
|
|
7290
|
+
if (ts9.isIfStatement(node)) kinds.add("if");
|
|
7291
|
+
if (ts9.isCallExpression(node) && ts9.isPropertyAccessExpression(node.expression) && node.expression.name.text === "map") {
|
|
7227
7292
|
kinds.add("map");
|
|
7228
7293
|
}
|
|
7229
|
-
if (
|
|
7294
|
+
if (ts9.isCallExpression(node) && ts9.isIdentifier(node.expression)) calledNames.add(node.expression.text);
|
|
7230
7295
|
if (isFunctionBoundary(node)) return;
|
|
7231
|
-
|
|
7296
|
+
ts9.forEachChild(node, visit);
|
|
7232
7297
|
};
|
|
7233
7298
|
visit(sourceFile);
|
|
7234
7299
|
return { kinds, calledNames };
|
|
@@ -7390,38 +7455,38 @@ var schemaCasingRule = {
|
|
|
7390
7455
|
|
|
7391
7456
|
// eslint/rules/sole-state-owner.ts
|
|
7392
7457
|
import path50 from "path";
|
|
7393
|
-
import
|
|
7458
|
+
import ts10 from "typescript";
|
|
7394
7459
|
function findStateHooks(node) {
|
|
7395
7460
|
const hooks = [];
|
|
7396
7461
|
const visit = (child) => {
|
|
7397
|
-
if (
|
|
7398
|
-
if (
|
|
7462
|
+
if (ts10.isCallExpression(child) && ts10.isIdentifier(child.expression) && child.expression.text === "useState") {
|
|
7463
|
+
if (ts10.isVariableDeclaration(child.parent)) {
|
|
7399
7464
|
const { name } = child.parent;
|
|
7400
|
-
if (
|
|
7465
|
+
if (ts10.isArrayBindingPattern(name) && name.elements.length >= 2) {
|
|
7401
7466
|
const value = name.elements[0];
|
|
7402
7467
|
const updater = name.elements[1];
|
|
7403
|
-
if (value && updater &&
|
|
7468
|
+
if (value && updater && ts10.isBindingElement(value) && ts10.isBindingElement(updater)) {
|
|
7404
7469
|
const valueName = value.name;
|
|
7405
7470
|
const updaterName = updater.name;
|
|
7406
|
-
if (
|
|
7471
|
+
if (ts10.isIdentifier(valueName) && ts10.isIdentifier(updaterName)) {
|
|
7407
7472
|
hooks.push({ value: valueName.text, updater: updaterName.text });
|
|
7408
7473
|
}
|
|
7409
7474
|
}
|
|
7410
7475
|
}
|
|
7411
7476
|
}
|
|
7412
7477
|
}
|
|
7413
|
-
|
|
7478
|
+
ts10.forEachChild(child, visit);
|
|
7414
7479
|
};
|
|
7415
7480
|
visit(node);
|
|
7416
7481
|
return hooks;
|
|
7417
7482
|
}
|
|
7418
7483
|
function isHookUsage(node, hook) {
|
|
7419
|
-
if (
|
|
7484
|
+
if (ts10.isCallExpression(node) && ts10.isIdentifier(node.expression) && node.expression.text === hook.updater) {
|
|
7420
7485
|
return "updater";
|
|
7421
7486
|
}
|
|
7422
|
-
if (
|
|
7487
|
+
if (ts10.isIdentifier(node) && node.text === hook.value) {
|
|
7423
7488
|
const parent = node.parent;
|
|
7424
|
-
if (
|
|
7489
|
+
if (ts10.isBindingElement(parent) || ts10.isPropertyAccessExpression(parent) || ts10.isShorthandPropertyAssignment(parent)) {
|
|
7425
7490
|
return void 0;
|
|
7426
7491
|
}
|
|
7427
7492
|
return "value";
|
|
@@ -7431,16 +7496,16 @@ function isHookUsage(node, hook) {
|
|
|
7431
7496
|
function topLevelJsxChildren(initial) {
|
|
7432
7497
|
if (!initial) return void 0;
|
|
7433
7498
|
let expression = initial;
|
|
7434
|
-
while (
|
|
7435
|
-
if (
|
|
7499
|
+
while (ts10.isParenthesizedExpression(expression)) expression = expression.expression;
|
|
7500
|
+
if (ts10.isJsxFragment(expression)) {
|
|
7436
7501
|
const children = expression.children.filter(
|
|
7437
|
-
(c) => !
|
|
7502
|
+
(c) => !ts10.isJsxText(c) && !ts10.isJsxSpreadAttribute(c)
|
|
7438
7503
|
);
|
|
7439
7504
|
return { root: expression, children };
|
|
7440
7505
|
}
|
|
7441
|
-
if (
|
|
7506
|
+
if (ts10.isJsxElement(expression)) {
|
|
7442
7507
|
const children = expression.children.filter(
|
|
7443
|
-
(c) => !
|
|
7508
|
+
(c) => !ts10.isJsxText(c) && !ts10.isJsxSpreadAttribute(c)
|
|
7444
7509
|
);
|
|
7445
7510
|
return { root: expression, children };
|
|
7446
7511
|
}
|
|
@@ -7454,8 +7519,8 @@ function collectUsesIn(child, hook) {
|
|
|
7454
7519
|
positions.push(node);
|
|
7455
7520
|
count += 1;
|
|
7456
7521
|
}
|
|
7457
|
-
if (
|
|
7458
|
-
|
|
7522
|
+
if (ts10.isFunctionDeclaration(node) || ts10.isClassDeclaration(node)) return;
|
|
7523
|
+
ts10.forEachChild(node, visit);
|
|
7459
7524
|
};
|
|
7460
7525
|
visit(child);
|
|
7461
7526
|
return { positions, count };
|
|
@@ -7494,18 +7559,18 @@ var soleStateOwnerRule = {
|
|
|
7494
7559
|
}
|
|
7495
7560
|
};
|
|
7496
7561
|
function analyzeSoleOwner(declaration, hook) {
|
|
7497
|
-
const body =
|
|
7498
|
-
if (!body || !
|
|
7562
|
+
const body = ts10.isFunctionDeclaration(declaration) ? declaration.body : void 0;
|
|
7563
|
+
if (!body || !ts10.isBlock(body)) return void 0;
|
|
7499
7564
|
const returns = [];
|
|
7500
7565
|
const visit = (node) => {
|
|
7501
|
-
if (node !== body && (
|
|
7502
|
-
if (
|
|
7503
|
-
|
|
7566
|
+
if (node !== body && (ts10.isFunctionLike(node) || ts10.isClassLike(node))) return;
|
|
7567
|
+
if (ts10.isReturnStatement(node)) returns.push(node);
|
|
7568
|
+
ts10.forEachChild(node, visit);
|
|
7504
7569
|
};
|
|
7505
7570
|
visit(body);
|
|
7506
7571
|
if (returns.length !== 1) return void 0;
|
|
7507
7572
|
const single = returns[0];
|
|
7508
|
-
if (!single?.expression || !
|
|
7573
|
+
if (!single?.expression || !ts10.isExpression(single.expression)) return void 0;
|
|
7509
7574
|
const returnExpression = single.expression;
|
|
7510
7575
|
const root = topLevelJsxChildren(returnExpression);
|
|
7511
7576
|
if (!root || root.children.length === 0) return void 0;
|
|
@@ -7528,11 +7593,11 @@ function usesOutsideJsx(declaration, hook, children) {
|
|
|
7528
7593
|
let outside = false;
|
|
7529
7594
|
const visit = (node) => {
|
|
7530
7595
|
if (outside) return;
|
|
7531
|
-
if (node !== declaration && (
|
|
7596
|
+
if (node !== declaration && (ts10.isFunctionDeclaration(node) || ts10.isClassDeclaration(node))) return;
|
|
7532
7597
|
if (isHookUsage(node, hook)) {
|
|
7533
7598
|
let current = node;
|
|
7534
7599
|
let isInJsxChild = false;
|
|
7535
|
-
while (!
|
|
7600
|
+
while (!ts10.isSourceFile(current)) {
|
|
7536
7601
|
if (children.includes(current)) {
|
|
7537
7602
|
isInJsxChild = true;
|
|
7538
7603
|
break;
|
|
@@ -7541,7 +7606,7 @@ function usesOutsideJsx(declaration, hook, children) {
|
|
|
7541
7606
|
}
|
|
7542
7607
|
if (!isInJsxChild) outside = true;
|
|
7543
7608
|
}
|
|
7544
|
-
|
|
7609
|
+
ts10.forEachChild(node, visit);
|
|
7545
7610
|
};
|
|
7546
7611
|
visit(declaration);
|
|
7547
7612
|
return outside;
|