pasika 0.4.1 → 0.4.3
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/README.md +2 -0
- package/dist/eslint/pasika/index.d.ts +4 -0
- package/dist/eslint/pasika/index.js +717 -236
- package/package.json +2 -2
|
@@ -66,11 +66,12 @@ function componentFromVariable(node) {
|
|
|
66
66
|
smart: containsSmartCall(initializer)
|
|
67
67
|
};
|
|
68
68
|
}
|
|
69
|
-
function parseComponentInfo(text, filename) {
|
|
69
|
+
function parseComponentInfo(text, filename, options) {
|
|
70
70
|
const sourceFile = ts.createSourceFile(path.resolve(filename), text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
71
71
|
const components = [];
|
|
72
72
|
for (const statement of sourceFile.statements) {
|
|
73
|
-
|
|
73
|
+
const exported = isExported(statement);
|
|
74
|
+
if (!exported && !options?.includeNonExported) continue;
|
|
74
75
|
if (ts.isFunctionDeclaration(statement)) {
|
|
75
76
|
const component = componentFromFunction(statement);
|
|
76
77
|
if (component) components.push(component);
|
|
@@ -350,59 +351,26 @@ var importBoundariesRule = {
|
|
|
350
351
|
};
|
|
351
352
|
|
|
352
353
|
// eslint/rules/no-mixed-concerns.ts
|
|
353
|
-
function getExportName(declaration) {
|
|
354
|
-
if (declaration?.type === "FunctionDeclaration" && declaration.id) {
|
|
355
|
-
return declaration.id.name ?? null;
|
|
356
|
-
}
|
|
357
|
-
if (declaration?.type === "VariableDeclaration") {
|
|
358
|
-
const declarator = declaration.declarations?.[0];
|
|
359
|
-
if (declarator?.id?.type === "Identifier" && (declarator.init?.type === "ArrowFunctionExpression" || declarator.init?.type === "FunctionExpression")) {
|
|
360
|
-
return declarator.id.name ?? null;
|
|
361
|
-
}
|
|
362
|
-
}
|
|
363
|
-
if (declaration?.type === "ArrowFunctionExpression") {
|
|
364
|
-
return "default";
|
|
365
|
-
}
|
|
366
|
-
if (declaration?.type === "FunctionExpression" && declaration.id) {
|
|
367
|
-
return declaration.id.name ?? null;
|
|
368
|
-
}
|
|
369
|
-
return null;
|
|
370
|
-
}
|
|
371
354
|
var noMixedConcernsRule = {
|
|
372
355
|
meta: {
|
|
373
356
|
schema: [],
|
|
374
357
|
type: "problem",
|
|
375
358
|
docs: {
|
|
376
|
-
description: "Enforce one
|
|
359
|
+
description: "Enforce one React component per .tsx file, counting private components."
|
|
377
360
|
}
|
|
378
361
|
},
|
|
379
362
|
create(context) {
|
|
380
363
|
if (!context.filename.endsWith(".tsx")) return {};
|
|
381
|
-
|
|
382
|
-
const extraExports = [];
|
|
383
|
-
function registerExport(name) {
|
|
384
|
-
exportedComponentCount++;
|
|
385
|
-
if (exportedComponentCount > 1) {
|
|
386
|
-
extraExports.push({ name });
|
|
387
|
-
}
|
|
388
|
-
}
|
|
364
|
+
const sourceCode = context.sourceCode.text;
|
|
389
365
|
return {
|
|
390
|
-
ExportNamedDeclaration(node) {
|
|
391
|
-
const name = getExportName(node.declaration);
|
|
392
|
-
if (name) registerExport(name);
|
|
393
|
-
},
|
|
394
|
-
ExportDefaultDeclaration(node) {
|
|
395
|
-
const name = getExportName(node.declaration);
|
|
396
|
-
if (name) registerExport(name);
|
|
397
|
-
},
|
|
398
366
|
"Program:exit"() {
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
}
|
|
405
|
-
}
|
|
367
|
+
const components = parseComponentInfo(sourceCode, context.filename, { includeNonExported: true });
|
|
368
|
+
if (components.length <= 1) return;
|
|
369
|
+
for (const extra of components.slice(1)) {
|
|
370
|
+
context.report({
|
|
371
|
+
loc: { line: 1, column: 0 },
|
|
372
|
+
message: `File defines multiple components. "${extra.name}" is an extra component. Move it to its own file. Each component file MUST define exactly one component. See docs/code-organization-guide/rules/no-mixed-concerns-rule.md`
|
|
373
|
+
});
|
|
406
374
|
}
|
|
407
375
|
}
|
|
408
376
|
};
|
|
@@ -478,6 +446,397 @@ var noArbitraryTailwindRule = {
|
|
|
478
446
|
}
|
|
479
447
|
};
|
|
480
448
|
|
|
449
|
+
// eslint/rules/unknown-utility.ts
|
|
450
|
+
import { readdirSync, readFileSync, statSync } from "fs";
|
|
451
|
+
import path4 from "path";
|
|
452
|
+
var PREFIX_NAMESPACES = {
|
|
453
|
+
bg: ["color"],
|
|
454
|
+
text: ["color", "text"],
|
|
455
|
+
border: ["color"],
|
|
456
|
+
ring: ["color"],
|
|
457
|
+
fill: ["color"],
|
|
458
|
+
stroke: ["color"],
|
|
459
|
+
accent: ["color"],
|
|
460
|
+
caret: ["color"],
|
|
461
|
+
decoration: ["color"],
|
|
462
|
+
outline: ["color"],
|
|
463
|
+
divide: ["color"],
|
|
464
|
+
from: ["color"],
|
|
465
|
+
via: ["color"],
|
|
466
|
+
to: ["color"],
|
|
467
|
+
shadow: ["color", "shadow"],
|
|
468
|
+
rounded: ["radius"],
|
|
469
|
+
font: ["font"],
|
|
470
|
+
tracking: ["tracking"],
|
|
471
|
+
leading: ["leading"],
|
|
472
|
+
opacity: ["opacity"],
|
|
473
|
+
z: ["z"],
|
|
474
|
+
blur: ["blur"],
|
|
475
|
+
"backdrop-blur": ["blur"],
|
|
476
|
+
"ring-offset": ["color"]
|
|
477
|
+
};
|
|
478
|
+
var PREFIX_BUILTINS = {
|
|
479
|
+
bg: [
|
|
480
|
+
"none",
|
|
481
|
+
"cover",
|
|
482
|
+
"contain",
|
|
483
|
+
"auto",
|
|
484
|
+
"fixed",
|
|
485
|
+
"local",
|
|
486
|
+
"scroll",
|
|
487
|
+
"center",
|
|
488
|
+
"top",
|
|
489
|
+
"bottom",
|
|
490
|
+
"left",
|
|
491
|
+
"right",
|
|
492
|
+
"left-top",
|
|
493
|
+
"left-bottom",
|
|
494
|
+
"right-top",
|
|
495
|
+
"right-bottom",
|
|
496
|
+
"repeat",
|
|
497
|
+
"no-repeat",
|
|
498
|
+
"repeat-x",
|
|
499
|
+
"repeat-y",
|
|
500
|
+
"repeat-round",
|
|
501
|
+
"repeat-space",
|
|
502
|
+
"clip-border",
|
|
503
|
+
"clip-padding",
|
|
504
|
+
"clip-content",
|
|
505
|
+
"clip-text",
|
|
506
|
+
"origin-border",
|
|
507
|
+
"origin-padding",
|
|
508
|
+
"origin-content",
|
|
509
|
+
"gradient-to-t",
|
|
510
|
+
"gradient-to-tr",
|
|
511
|
+
"gradient-to-r",
|
|
512
|
+
"gradient-to-br",
|
|
513
|
+
"gradient-to-b",
|
|
514
|
+
"gradient-to-bl",
|
|
515
|
+
"gradient-to-l",
|
|
516
|
+
"gradient-to-tl",
|
|
517
|
+
"linear-to-t",
|
|
518
|
+
"linear-to-tr",
|
|
519
|
+
"linear-to-r",
|
|
520
|
+
"linear-to-br",
|
|
521
|
+
"linear-to-b",
|
|
522
|
+
"linear-to-bl",
|
|
523
|
+
"linear-to-l",
|
|
524
|
+
"linear-to-tl"
|
|
525
|
+
],
|
|
526
|
+
text: [
|
|
527
|
+
"left",
|
|
528
|
+
"center",
|
|
529
|
+
"right",
|
|
530
|
+
"justify",
|
|
531
|
+
"start",
|
|
532
|
+
"end",
|
|
533
|
+
"wrap",
|
|
534
|
+
"nowrap",
|
|
535
|
+
"balance",
|
|
536
|
+
"pretty",
|
|
537
|
+
"ellipsis",
|
|
538
|
+
"clip",
|
|
539
|
+
"truncate",
|
|
540
|
+
"uppercase",
|
|
541
|
+
"lowercase",
|
|
542
|
+
"capitalize",
|
|
543
|
+
"normal-case",
|
|
544
|
+
"underline",
|
|
545
|
+
"overline",
|
|
546
|
+
"line-through",
|
|
547
|
+
"no-underline"
|
|
548
|
+
],
|
|
549
|
+
border: [
|
|
550
|
+
"solid",
|
|
551
|
+
"dashed",
|
|
552
|
+
"dotted",
|
|
553
|
+
"double",
|
|
554
|
+
"hidden",
|
|
555
|
+
"none",
|
|
556
|
+
"collapse",
|
|
557
|
+
"separate",
|
|
558
|
+
"x",
|
|
559
|
+
"y",
|
|
560
|
+
"t",
|
|
561
|
+
"r",
|
|
562
|
+
"b",
|
|
563
|
+
"l",
|
|
564
|
+
"s",
|
|
565
|
+
"e"
|
|
566
|
+
],
|
|
567
|
+
ring: ["inset"],
|
|
568
|
+
divide: ["x", "y", "reverse"],
|
|
569
|
+
from: ["t", "r", "b", "l", "tr", "tl", "br", "bl", "top", "right", "bottom", "left"],
|
|
570
|
+
via: ["t", "r", "b", "l", "tr", "tl", "br", "bl", "top", "right", "bottom", "left"],
|
|
571
|
+
to: ["t", "r", "b", "l", "tr", "tl", "br", "bl", "top", "right", "bottom", "left"],
|
|
572
|
+
fill: ["none"],
|
|
573
|
+
stroke: ["none"],
|
|
574
|
+
accent: ["auto"],
|
|
575
|
+
decoration: ["solid", "double", "dotted", "dashed", "wavy", "none"],
|
|
576
|
+
outline: ["none", "hidden", "dashed", "dotted", "double", "solid"],
|
|
577
|
+
font: ["thin", "extralight", "light", "normal", "medium", "semibold", "bold", "extrabold", "black"]
|
|
578
|
+
};
|
|
579
|
+
var DEFAULT_TOKENS = {
|
|
580
|
+
text: ["xs", "sm", "base", "lg", "xl", "2xl", "3xl", "4xl", "5xl", "6xl", "7xl", "8xl", "9xl"],
|
|
581
|
+
radius: ["none", "xs", "sm", "md", "lg", "xl", "2xl", "3xl", "4xl", "full"],
|
|
582
|
+
font: ["sans", "serif", "mono"],
|
|
583
|
+
shadow: ["2xs", "xs", "sm", "md", "lg", "xl", "2xl", "inner", "none"],
|
|
584
|
+
tracking: ["tighter", "tight", "normal", "wide", "wider", "widest"],
|
|
585
|
+
leading: ["none", "tight", "snug", "normal", "relaxed", "loose"],
|
|
586
|
+
opacity: [
|
|
587
|
+
"0",
|
|
588
|
+
"5",
|
|
589
|
+
"10",
|
|
590
|
+
"15",
|
|
591
|
+
"20",
|
|
592
|
+
"25",
|
|
593
|
+
"30",
|
|
594
|
+
"35",
|
|
595
|
+
"40",
|
|
596
|
+
"45",
|
|
597
|
+
"50",
|
|
598
|
+
"55",
|
|
599
|
+
"60",
|
|
600
|
+
"65",
|
|
601
|
+
"70",
|
|
602
|
+
"75",
|
|
603
|
+
"80",
|
|
604
|
+
"85",
|
|
605
|
+
"90",
|
|
606
|
+
"95",
|
|
607
|
+
"100"
|
|
608
|
+
],
|
|
609
|
+
z: ["0", "10", "20", "30", "40", "50", "auto"],
|
|
610
|
+
blur: ["none", "xs", "sm", "md", "lg", "xl", "2xl", "3xl"],
|
|
611
|
+
animate: ["none", "spin", "ping", "pulse", "bounce"],
|
|
612
|
+
ease: ["linear", "in", "out", "in-out"],
|
|
613
|
+
aspect: ["auto", "video", "square"]
|
|
614
|
+
};
|
|
615
|
+
var DEFAULT_PALETTE_FAMILIES = /* @__PURE__ */ new Set([
|
|
616
|
+
"red",
|
|
617
|
+
"orange",
|
|
618
|
+
"amber",
|
|
619
|
+
"yellow",
|
|
620
|
+
"lime",
|
|
621
|
+
"green",
|
|
622
|
+
"emerald",
|
|
623
|
+
"teal",
|
|
624
|
+
"cyan",
|
|
625
|
+
"sky",
|
|
626
|
+
"blue",
|
|
627
|
+
"indigo",
|
|
628
|
+
"violet",
|
|
629
|
+
"purple",
|
|
630
|
+
"fuchsia",
|
|
631
|
+
"pink",
|
|
632
|
+
"rose",
|
|
633
|
+
"slate",
|
|
634
|
+
"gray",
|
|
635
|
+
"zinc",
|
|
636
|
+
"neutral",
|
|
637
|
+
"stone"
|
|
638
|
+
]);
|
|
639
|
+
var DEFAULT_PALETTE_SHADES = /* @__PURE__ */ new Set(["50", "100", "200", "300", "400", "500", "600", "700", "800", "900", "950"]);
|
|
640
|
+
var DEFAULT_COLOR_SPECIALS = /* @__PURE__ */ new Set(["white", "black", "transparent", "current", "inherit"]);
|
|
641
|
+
var NUMERIC_TOKEN_RE = /^-?(?:\d+\.?\d*|\.\d+)(?:%|px|rem|em)?$/;
|
|
642
|
+
var SIDE_WIDTH_TOKEN_RE = /^(?:x|y|t|r|b|l|s|e)-(?:\d+\.?\d*|\.\d+)(?:%|px|rem|em)?$/;
|
|
643
|
+
var OFFSET_TOKEN_RE = /^offset-(?:\d+\.?\d*|\.\d+)(?:%|px|rem|em)?$/;
|
|
644
|
+
function stylesheetFiles(dir) {
|
|
645
|
+
let entries;
|
|
646
|
+
try {
|
|
647
|
+
entries = readdirSync(dir);
|
|
648
|
+
} catch {
|
|
649
|
+
return [];
|
|
650
|
+
}
|
|
651
|
+
return entries.flatMap((entry) => {
|
|
652
|
+
if (entry.startsWith(".") || entry === "node_modules") return [];
|
|
653
|
+
const entryPath = path4.join(dir, entry);
|
|
654
|
+
let stats;
|
|
655
|
+
try {
|
|
656
|
+
stats = statSync(entryPath);
|
|
657
|
+
} catch {
|
|
658
|
+
return [];
|
|
659
|
+
}
|
|
660
|
+
if (stats.isDirectory()) return stylesheetFiles(entryPath);
|
|
661
|
+
return path4.extname(entry) === ".css" ? [entryPath] : [];
|
|
662
|
+
});
|
|
663
|
+
}
|
|
664
|
+
function themeBlocks(css2) {
|
|
665
|
+
const blocks = [];
|
|
666
|
+
let index = 0;
|
|
667
|
+
while (index < css2.length) {
|
|
668
|
+
const match = /@theme(?:\s+inline)?\s*\{/.exec(css2.slice(index));
|
|
669
|
+
if (!match) break;
|
|
670
|
+
const open = index + match.index + match[0].length - 1;
|
|
671
|
+
let depth = 1;
|
|
672
|
+
let cursor = open + 1;
|
|
673
|
+
for (; cursor < css2.length && depth > 0; cursor++) {
|
|
674
|
+
if (css2[cursor] === "{") depth++;
|
|
675
|
+
else if (css2[cursor] === "}") depth--;
|
|
676
|
+
}
|
|
677
|
+
blocks.push(css2.slice(open + 1, cursor - 1));
|
|
678
|
+
index = cursor;
|
|
679
|
+
}
|
|
680
|
+
return blocks;
|
|
681
|
+
}
|
|
682
|
+
function readInventory(files) {
|
|
683
|
+
const utilities = /* @__PURE__ */ new Set();
|
|
684
|
+
const utilityPrefixes = /* @__PURE__ */ new Set();
|
|
685
|
+
const themeTokensByNamespace = /* @__PURE__ */ new Map();
|
|
686
|
+
let defaultsReset = false;
|
|
687
|
+
for (const file of files) {
|
|
688
|
+
let css2;
|
|
689
|
+
try {
|
|
690
|
+
css2 = readFileSync(file, "utf8");
|
|
691
|
+
} catch {
|
|
692
|
+
continue;
|
|
693
|
+
}
|
|
694
|
+
for (const name of css2.matchAll(/@utility\s+(?<utilityName>[a-zA-Z0-9_-]+)/g)) {
|
|
695
|
+
const utilityName = name.groups?.utilityName;
|
|
696
|
+
if (!utilityName) continue;
|
|
697
|
+
utilities.add(utilityName);
|
|
698
|
+
const dash = utilityName.indexOf("-");
|
|
699
|
+
if (dash > 0) utilityPrefixes.add(utilityName.slice(0, dash));
|
|
700
|
+
}
|
|
701
|
+
for (const block of themeBlocks(css2)) {
|
|
702
|
+
if (/--\*\s*:\s*initial\b/.test(block)) defaultsReset = true;
|
|
703
|
+
for (const decl of block.matchAll(/--(?<namespace>[a-z][a-z0-9]*)-(?<token>[a-z0-9][a-z0-9_-]*)\s*:/g)) {
|
|
704
|
+
const namespace = decl.groups?.namespace;
|
|
705
|
+
const token = decl.groups?.token;
|
|
706
|
+
if (!namespace || !token) continue;
|
|
707
|
+
let set = themeTokensByNamespace.get(namespace);
|
|
708
|
+
if (!set) {
|
|
709
|
+
set = /* @__PURE__ */ new Set();
|
|
710
|
+
themeTokensByNamespace.set(namespace, set);
|
|
711
|
+
}
|
|
712
|
+
set.add(token);
|
|
713
|
+
}
|
|
714
|
+
}
|
|
715
|
+
}
|
|
716
|
+
return { utilities, utilityPrefixes, themeTokens: themeTokensByNamespace, defaultsReset };
|
|
717
|
+
}
|
|
718
|
+
function isColorToken(token, inventory) {
|
|
719
|
+
if (inventory.themeTokens.get("color")?.has(token)) return true;
|
|
720
|
+
if (inventory.defaultsReset) return false;
|
|
721
|
+
if (DEFAULT_COLOR_SPECIALS.has(token)) return true;
|
|
722
|
+
const hyphen = token.lastIndexOf("-");
|
|
723
|
+
if (hyphen === -1) return false;
|
|
724
|
+
return DEFAULT_PALETTE_FAMILIES.has(token.slice(0, hyphen)) && DEFAULT_PALETTE_SHADES.has(token.slice(hyphen + 1));
|
|
725
|
+
}
|
|
726
|
+
function isKnown(className, inventory) {
|
|
727
|
+
if (className.includes("[") || className.includes("(")) return true;
|
|
728
|
+
const base = className.replace(/!+$/, "").split("/")[0] ?? "";
|
|
729
|
+
const segments = base.split(":");
|
|
730
|
+
const utility = segments[segments.length - 1] ?? "";
|
|
731
|
+
if (!utility.includes("-")) return true;
|
|
732
|
+
const dash = utility.indexOf("-");
|
|
733
|
+
const firstTwo = utility.split("-").slice(0, 2).join("-");
|
|
734
|
+
const compound = PREFIX_NAMESPACES[firstTwo] ? firstTwo : void 0;
|
|
735
|
+
const prefix = compound ?? utility.slice(0, dash);
|
|
736
|
+
const token = compound ? utility.slice(compound.length + 1) : utility.slice(dash + 1);
|
|
737
|
+
if (!token) return true;
|
|
738
|
+
if (inventory.utilities.has(utility)) return true;
|
|
739
|
+
const namespaces = PREFIX_NAMESPACES[prefix];
|
|
740
|
+
if (!namespaces) {
|
|
741
|
+
const projectTokens = inventory.themeTokens.get(prefix);
|
|
742
|
+
if (projectTokens) {
|
|
743
|
+
if (projectTokens.has(token)) return true;
|
|
744
|
+
if (!inventory.defaultsReset && DEFAULT_TOKENS[prefix]?.includes(token)) return true;
|
|
745
|
+
return false;
|
|
746
|
+
}
|
|
747
|
+
return !inventory.utilityPrefixes.has(prefix);
|
|
748
|
+
}
|
|
749
|
+
if (NUMERIC_TOKEN_RE.test(token) || SIDE_WIDTH_TOKEN_RE.test(token) || OFFSET_TOKEN_RE.test(token)) return true;
|
|
750
|
+
if (PREFIX_BUILTINS[prefix]?.includes(token)) return true;
|
|
751
|
+
for (const namespace of namespaces) {
|
|
752
|
+
if (namespace === "color") {
|
|
753
|
+
if (isColorToken(token, inventory)) return true;
|
|
754
|
+
continue;
|
|
755
|
+
}
|
|
756
|
+
if (inventory.themeTokens.get(namespace)?.has(token)) return true;
|
|
757
|
+
if (!inventory.defaultsReset && DEFAULT_TOKENS[namespace]?.includes(token)) return true;
|
|
758
|
+
}
|
|
759
|
+
return false;
|
|
760
|
+
}
|
|
761
|
+
var CLASS_HELPERS2 = /* @__PURE__ */ new Set(["cn", "clsx", "twMerge", "twJoin"]);
|
|
762
|
+
var unknownUtilityRule = {
|
|
763
|
+
meta: {
|
|
764
|
+
schema: [],
|
|
765
|
+
type: "problem",
|
|
766
|
+
docs: {
|
|
767
|
+
description: "Require component class names to be a custom utility, theme-generated utility, or built-in."
|
|
768
|
+
}
|
|
769
|
+
},
|
|
770
|
+
create(context) {
|
|
771
|
+
const sourceRoot2 = path4.resolve("src");
|
|
772
|
+
let inventory;
|
|
773
|
+
try {
|
|
774
|
+
if (!statSync(sourceRoot2).isDirectory()) return {};
|
|
775
|
+
inventory = readInventory(stylesheetFiles(sourceRoot2));
|
|
776
|
+
} catch {
|
|
777
|
+
return {};
|
|
778
|
+
}
|
|
779
|
+
function reportUnknownClasses(node, value) {
|
|
780
|
+
const seen = /* @__PURE__ */ new Set();
|
|
781
|
+
for (const candidate of value.split(/\s+/)) {
|
|
782
|
+
if (!candidate || seen.has(candidate)) continue;
|
|
783
|
+
seen.add(candidate);
|
|
784
|
+
if (!isKnown(candidate, inventory)) {
|
|
785
|
+
context.report({
|
|
786
|
+
node,
|
|
787
|
+
message: `Utility class "${candidate}" is not a custom @utility, a theme-generated utility, or a built-in Tailwind utility.`
|
|
788
|
+
});
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
}
|
|
792
|
+
function checkExpression(node, expression) {
|
|
793
|
+
if (!expression) return;
|
|
794
|
+
if (expression.type === "Literal") {
|
|
795
|
+
if (typeof expression.value === "string") reportUnknownClasses(node, expression.value);
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
if (expression.type === "TemplateLiteral") {
|
|
799
|
+
for (const quasi of expression.quasis) reportUnknownClasses(node, quasi.value.raw);
|
|
800
|
+
return;
|
|
801
|
+
}
|
|
802
|
+
if (expression.type === "LogicalExpression") {
|
|
803
|
+
checkExpression(node, expression.left);
|
|
804
|
+
checkExpression(node, expression.right);
|
|
805
|
+
return;
|
|
806
|
+
}
|
|
807
|
+
if (expression.type === "ConditionalExpression") {
|
|
808
|
+
checkExpression(node, expression.consequent);
|
|
809
|
+
checkExpression(node, expression.alternate);
|
|
810
|
+
return;
|
|
811
|
+
}
|
|
812
|
+
if (expression.type === "ArrayExpression") {
|
|
813
|
+
for (const element of expression.elements) checkExpression(node, element);
|
|
814
|
+
return;
|
|
815
|
+
}
|
|
816
|
+
if (expression.type === "ObjectExpression") {
|
|
817
|
+
for (const property of expression.properties) {
|
|
818
|
+
if (property.type === "Property") checkExpression(node, property.key);
|
|
819
|
+
}
|
|
820
|
+
}
|
|
821
|
+
}
|
|
822
|
+
return {
|
|
823
|
+
JSXAttribute(node) {
|
|
824
|
+
const attributeName = node.name?.name;
|
|
825
|
+
if (attributeName !== "className" && attributeName !== "class") return;
|
|
826
|
+
const value = node.value;
|
|
827
|
+
if (!value) return;
|
|
828
|
+
checkExpression(node, value.type === "JSXExpressionContainer" ? value.expression : value);
|
|
829
|
+
},
|
|
830
|
+
CallExpression(node) {
|
|
831
|
+
if (node.callee.type !== "Identifier" || !CLASS_HELPERS2.has(node.callee.name)) return;
|
|
832
|
+
for (const argument of node.arguments) {
|
|
833
|
+
checkExpression(node, argument);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
};
|
|
837
|
+
}
|
|
838
|
+
};
|
|
839
|
+
|
|
481
840
|
// eslint/rules/enforce-cn-merge.ts
|
|
482
841
|
function classCount(str) {
|
|
483
842
|
return str.split(/\s+/).filter(Boolean).length;
|
|
@@ -494,7 +853,9 @@ function isOuterLayoutClass(className) {
|
|
|
494
853
|
function stringArguments(node) {
|
|
495
854
|
if (node?.type === "Literal" && typeof node.value === "string") return [node.value];
|
|
496
855
|
if (node?.type === "TemplateLiteral") return node.quasis.map((quasi) => quasi.value.raw);
|
|
497
|
-
if (node?.type === "ConditionalExpression")
|
|
856
|
+
if (node?.type === "ConditionalExpression") {
|
|
857
|
+
return [...stringArguments(node.consequent), ...stringArguments(node.alternate)];
|
|
858
|
+
}
|
|
498
859
|
if (node?.type === "LogicalExpression") return [...stringArguments(node.left), ...stringArguments(node.right)];
|
|
499
860
|
if (node?.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "cn") {
|
|
500
861
|
return node.arguments.flatMap((argument) => stringArguments(argument));
|
|
@@ -510,7 +871,10 @@ var enforceCnMergeRule = {
|
|
|
510
871
|
const element = node.parent.parent;
|
|
511
872
|
const isComponentProp = isComponentName(element.openingElement?.name);
|
|
512
873
|
if (isComponentProp && attributeName !== "className" && attributeName.endsWith("ClassName")) {
|
|
513
|
-
context.report({
|
|
874
|
+
context.report({
|
|
875
|
+
node,
|
|
876
|
+
message: "Expose appearance through typed variant props instead of separate internal class-name props. See docs/styling-guide/rules/class-composition-rule.md"
|
|
877
|
+
});
|
|
514
878
|
return;
|
|
515
879
|
}
|
|
516
880
|
if (attributeName !== "className" && attributeName !== "class") return;
|
|
@@ -519,31 +883,60 @@ var enforceCnMergeRule = {
|
|
|
519
883
|
if (isComponentProp && attributeName === "className") {
|
|
520
884
|
const expression = valueNode.type === "JSXExpressionContainer" ? valueNode.expression : valueNode;
|
|
521
885
|
const invalidClass = stringArguments(expression).flatMap((value) => value.split(/\s+/).filter(Boolean)).find((className) => !isOuterLayoutClass(className));
|
|
522
|
-
if (invalidClass)
|
|
886
|
+
if (invalidClass) {
|
|
887
|
+
context.report({
|
|
888
|
+
node,
|
|
889
|
+
message: `Passed className contains non-layout utility "${invalidClass}". Expose appearance through typed variant props. See docs/styling-guide/rules/class-composition-rule.md`
|
|
890
|
+
});
|
|
891
|
+
}
|
|
523
892
|
return;
|
|
524
893
|
}
|
|
525
894
|
if (valueNode.type === "Literal" && typeof valueNode.value === "string") {
|
|
526
|
-
if (classCount(valueNode.value) > 5)
|
|
895
|
+
if (classCount(valueNode.value) > 5) {
|
|
896
|
+
context.report({
|
|
897
|
+
node,
|
|
898
|
+
message: "Static className with more than 5 classes must use cn() with grouped string literals. See docs/styling-guide/rules/class-composition-rule.md"
|
|
899
|
+
});
|
|
900
|
+
}
|
|
527
901
|
return;
|
|
528
902
|
}
|
|
529
903
|
if (valueNode.type !== "JSXExpressionContainer") return;
|
|
530
904
|
const expr = valueNode.expression;
|
|
531
905
|
if (expr.type === "BinaryExpression" && expr.operator === "+") {
|
|
532
|
-
context.report({
|
|
906
|
+
context.report({
|
|
907
|
+
node,
|
|
908
|
+
message: "Use cn() instead of + operator for className. See docs/styling-guide/rules/class-composition-rule.md"
|
|
909
|
+
});
|
|
533
910
|
return;
|
|
534
911
|
}
|
|
535
912
|
if (expr.type === "TemplateLiteral" && expr.expressions.length > 0) {
|
|
536
|
-
context.report({
|
|
913
|
+
context.report({
|
|
914
|
+
node,
|
|
915
|
+
message: "Use cn() instead of template literals with conditionals for className. See docs/styling-guide/rules/class-composition-rule.md"
|
|
916
|
+
});
|
|
917
|
+
return;
|
|
918
|
+
}
|
|
919
|
+
if (expr.type === "LogicalExpression" || expr.type === "ConditionalExpression") {
|
|
920
|
+
context.report({
|
|
921
|
+
node,
|
|
922
|
+
message: "Use cn() for conditional classes in className. See docs/styling-guide/rules/class-composition-rule.md"
|
|
923
|
+
});
|
|
537
924
|
return;
|
|
538
925
|
}
|
|
539
926
|
if (expr.type === "Literal" && typeof expr.value === "string" && classCount(expr.value) > 5) {
|
|
540
|
-
context.report({
|
|
927
|
+
context.report({
|
|
928
|
+
node,
|
|
929
|
+
message: "Static className with more than 5 classes must use cn() with grouped string literals. See docs/styling-guide/rules/class-composition-rule.md"
|
|
930
|
+
});
|
|
541
931
|
return;
|
|
542
932
|
}
|
|
543
933
|
if (expr.type === "CallExpression" && expr.callee.type === "Identifier" && expr.callee.name === "cn") {
|
|
544
934
|
for (const arg of expr.arguments) {
|
|
545
935
|
if (arg.type === "Literal" && typeof arg.value === "string" && classCount(arg.value) > 5) {
|
|
546
|
-
context.report({
|
|
936
|
+
context.report({
|
|
937
|
+
node: arg,
|
|
938
|
+
message: "Each cn() string argument must contain at most 5 class names. Group by styling concern. See docs/styling-guide/rules/class-composition-rule.md"
|
|
939
|
+
});
|
|
547
940
|
}
|
|
548
941
|
}
|
|
549
942
|
}
|
|
@@ -653,7 +1046,7 @@ var enforceCvaVariantPropsRule = {
|
|
|
653
1046
|
};
|
|
654
1047
|
|
|
655
1048
|
// eslint/rules/enforce-barrel-exports.ts
|
|
656
|
-
import
|
|
1049
|
+
import path5 from "path";
|
|
657
1050
|
import fs from "fs";
|
|
658
1051
|
function isPascalCase3(str) {
|
|
659
1052
|
return /^[A-Z][A-Za-z0-9]*$/.test(str);
|
|
@@ -673,14 +1066,14 @@ var enforceBarrelExportsRule = {
|
|
|
673
1066
|
create(context) {
|
|
674
1067
|
const filename = context.filename;
|
|
675
1068
|
if (!filename) return {};
|
|
676
|
-
const baseName =
|
|
1069
|
+
const baseName = path5.basename(filename);
|
|
677
1070
|
if (baseName !== "index.ts" && baseName !== "index.cts" && baseName !== "index.mts") return {};
|
|
678
|
-
const dirPath =
|
|
679
|
-
const folderName =
|
|
680
|
-
const parentFolderName =
|
|
1071
|
+
const dirPath = path5.dirname(filename);
|
|
1072
|
+
const folderName = path5.basename(dirPath);
|
|
1073
|
+
const parentFolderName = path5.basename(path5.dirname(dirPath));
|
|
681
1074
|
if (SUPPORT_FOLDERS.has(folderName)) return {};
|
|
682
1075
|
if (!isPascalCase3(folderName) && !isKebabCase2(folderName)) return {};
|
|
683
|
-
const matchingTsx = fs.existsSync(
|
|
1076
|
+
const matchingTsx = fs.existsSync(path5.join(dirPath, `${folderName}.tsx`)) ? folderName : null;
|
|
684
1077
|
if (!matchingTsx) return {};
|
|
685
1078
|
if (!isPascalCase3(parentFolderName) && !isKebabCase2(parentFolderName)) return {};
|
|
686
1079
|
const reExportedNames = /* @__PURE__ */ new Set();
|
|
@@ -715,15 +1108,15 @@ var enforceBarrelExportsRule = {
|
|
|
715
1108
|
};
|
|
716
1109
|
|
|
717
1110
|
// eslint/rules/component-placement.ts
|
|
718
|
-
import
|
|
1111
|
+
import path9 from "path";
|
|
719
1112
|
|
|
720
1113
|
// eslint/project/index.ts
|
|
721
|
-
import { readdirSync, statSync } from "fs";
|
|
722
|
-
import
|
|
1114
|
+
import { readdirSync as readdirSync2, statSync as statSync2 } from "fs";
|
|
1115
|
+
import path7 from "path";
|
|
723
1116
|
|
|
724
1117
|
// eslint/project/parse-module.ts
|
|
725
|
-
import
|
|
726
|
-
import { readFileSync } from "fs";
|
|
1118
|
+
import path6 from "path";
|
|
1119
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
727
1120
|
import ts2 from "typescript";
|
|
728
1121
|
var isPascalCase4 = (name) => /^[A-Z][A-Za-z0-9]*$/.test(name);
|
|
729
1122
|
var isHookName = (name) => /^use[A-Z]/.test(name);
|
|
@@ -760,7 +1153,7 @@ function classifyValue(name, initializer, isTsx) {
|
|
|
760
1153
|
return "constant";
|
|
761
1154
|
}
|
|
762
1155
|
function parseModule(file) {
|
|
763
|
-
const text =
|
|
1156
|
+
const text = readFileSync2(file, "utf8");
|
|
764
1157
|
const isTsx = file.endsWith(".tsx") || file.endsWith(".jsx");
|
|
765
1158
|
const sourceFile = ts2.createSourceFile(file, text, ts2.ScriptTarget.Latest, true, ts2.ScriptKind.TSX);
|
|
766
1159
|
const imports = [];
|
|
@@ -823,7 +1216,7 @@ function parseModule(file) {
|
|
|
823
1216
|
exports.push({ name: statement.name.text, kind: "type", line: lineOf(sourceFile, statement) });
|
|
824
1217
|
}
|
|
825
1218
|
}
|
|
826
|
-
return { file:
|
|
1219
|
+
return { file: path6.resolve(file), imports, exports };
|
|
827
1220
|
}
|
|
828
1221
|
|
|
829
1222
|
// eslint/project/index.ts
|
|
@@ -834,28 +1227,28 @@ var symbolKey = (file, name) => `${file}\0${name}`;
|
|
|
834
1227
|
function listSourceFiles(dir) {
|
|
835
1228
|
let entries;
|
|
836
1229
|
try {
|
|
837
|
-
entries =
|
|
1230
|
+
entries = readdirSync2(dir);
|
|
838
1231
|
} catch {
|
|
839
1232
|
return [];
|
|
840
1233
|
}
|
|
841
1234
|
return entries.flatMap((entry) => {
|
|
842
1235
|
if (entry.startsWith(".") || entry === "node_modules") return [];
|
|
843
|
-
const entryPath =
|
|
1236
|
+
const entryPath = path7.join(dir, entry);
|
|
844
1237
|
let stats;
|
|
845
1238
|
try {
|
|
846
|
-
stats =
|
|
1239
|
+
stats = statSync2(entryPath);
|
|
847
1240
|
} catch {
|
|
848
1241
|
return [];
|
|
849
1242
|
}
|
|
850
1243
|
if (stats.isDirectory()) return listSourceFiles(entryPath);
|
|
851
|
-
return MODULE_EXTENSIONS.includes(
|
|
1244
|
+
return MODULE_EXTENSIONS.includes(path7.extname(entry)) ? [entryPath] : [];
|
|
852
1245
|
});
|
|
853
1246
|
}
|
|
854
1247
|
function fingerprint(files) {
|
|
855
1248
|
let total = 0;
|
|
856
1249
|
for (const file of files) {
|
|
857
1250
|
try {
|
|
858
|
-
total +=
|
|
1251
|
+
total += statSync2(file).mtimeMs;
|
|
859
1252
|
} catch {
|
|
860
1253
|
}
|
|
861
1254
|
}
|
|
@@ -864,20 +1257,20 @@ function fingerprint(files) {
|
|
|
864
1257
|
function resolveSpecifier(fromFile, specifier, sourceRoot2) {
|
|
865
1258
|
let base;
|
|
866
1259
|
if (specifier.startsWith("@/")) {
|
|
867
|
-
base =
|
|
1260
|
+
base = path7.resolve(sourceRoot2, specifier.slice(2));
|
|
868
1261
|
} else if (specifier.startsWith(".")) {
|
|
869
|
-
base =
|
|
1262
|
+
base = path7.resolve(path7.dirname(fromFile), specifier);
|
|
870
1263
|
} else {
|
|
871
1264
|
return void 0;
|
|
872
1265
|
}
|
|
873
1266
|
const candidates = [
|
|
874
1267
|
base,
|
|
875
1268
|
...MODULE_EXTENSIONS.map((extension) => `${base}${extension}`),
|
|
876
|
-
...INDEX_BASENAMES.map((name) =>
|
|
1269
|
+
...INDEX_BASENAMES.map((name) => path7.join(base, name))
|
|
877
1270
|
];
|
|
878
1271
|
for (const candidate of candidates) {
|
|
879
1272
|
try {
|
|
880
|
-
if (
|
|
1273
|
+
if (statSync2(candidate).isFile()) return candidate;
|
|
881
1274
|
} catch {
|
|
882
1275
|
}
|
|
883
1276
|
}
|
|
@@ -917,7 +1310,7 @@ function getProjectIndex(sourceRoot2) {
|
|
|
917
1310
|
return cache.index;
|
|
918
1311
|
}
|
|
919
1312
|
try {
|
|
920
|
-
if (!
|
|
1313
|
+
if (!statSync2(sourceRoot2).isDirectory()) return void 0;
|
|
921
1314
|
} catch {
|
|
922
1315
|
return void 0;
|
|
923
1316
|
}
|
|
@@ -933,11 +1326,11 @@ function getProjectIndex(sourceRoot2) {
|
|
|
933
1326
|
}
|
|
934
1327
|
|
|
935
1328
|
// eslint/project/ccf.ts
|
|
936
|
-
import
|
|
1329
|
+
import path8 from "path";
|
|
937
1330
|
var SUPPORT_FOLDERS2 = /* @__PURE__ */ new Set(["hooks", "types", "schemas", "constants", "utils"]);
|
|
938
1331
|
function segmentsOf(file, sourceRoot2) {
|
|
939
|
-
const relative =
|
|
940
|
-
return relative.startsWith("..") ? [] : relative.split(
|
|
1332
|
+
const relative = path8.relative(sourceRoot2, file);
|
|
1333
|
+
return relative.startsWith("..") ? [] : relative.split(path8.sep);
|
|
941
1334
|
}
|
|
942
1335
|
function folderSegmentsOf(file, sourceRoot2) {
|
|
943
1336
|
return segmentsOf(file, sourceRoot2).slice(0, -1);
|
|
@@ -1016,7 +1409,7 @@ function resolveSupportPlacement(supportFile, supportFolder, index) {
|
|
|
1016
1409
|
}
|
|
1017
1410
|
function describeConsumers(consumers, sourceRoot2) {
|
|
1018
1411
|
const shown = 3;
|
|
1019
|
-
const names = consumers.map((consumer) =>
|
|
1412
|
+
const names = consumers.map((consumer) => path8.relative(path8.dirname(sourceRoot2), consumer).split(path8.sep).join("/")).sort((left, right) => left.localeCompare(right));
|
|
1020
1413
|
if (names.length <= shown) return names.join(", ");
|
|
1021
1414
|
return `${names.slice(0, shown).join(", ")} and ${String(names.length - shown)} more`;
|
|
1022
1415
|
}
|
|
@@ -1039,10 +1432,10 @@ var componentPlacementRule = {
|
|
|
1039
1432
|
create(context) {
|
|
1040
1433
|
const filename = context.filename;
|
|
1041
1434
|
if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
|
|
1042
|
-
const sourceRoot2 =
|
|
1435
|
+
const sourceRoot2 = path9.resolve("src");
|
|
1043
1436
|
const index = getProjectIndex(sourceRoot2);
|
|
1044
1437
|
if (!index) return {};
|
|
1045
|
-
const componentFile =
|
|
1438
|
+
const componentFile = path9.resolve(filename);
|
|
1046
1439
|
const segments = segmentsOf(componentFile, sourceRoot2);
|
|
1047
1440
|
if (segments.length === 0) return {};
|
|
1048
1441
|
if (isUnderApp(segments) || isConfigModule(segments)) return {};
|
|
@@ -1075,7 +1468,7 @@ var componentPlacementRule = {
|
|
|
1075
1468
|
};
|
|
1076
1469
|
|
|
1077
1470
|
// eslint/rules/support-file-placement.ts
|
|
1078
|
-
import
|
|
1471
|
+
import path10 from "path";
|
|
1079
1472
|
var CONFIG_OWNED_FOLDERS = /* @__PURE__ */ new Set(["types", "constants"]);
|
|
1080
1473
|
var REASON_TEXT2 = {
|
|
1081
1474
|
"app-consumer": "a file under src/app/ imports it, so it belongs to the app-wide support folder",
|
|
@@ -1094,8 +1487,8 @@ var supportFilePlacementRule = {
|
|
|
1094
1487
|
}
|
|
1095
1488
|
},
|
|
1096
1489
|
create(context) {
|
|
1097
|
-
const sourceRoot2 =
|
|
1098
|
-
const supportFile =
|
|
1490
|
+
const sourceRoot2 = path10.resolve("src");
|
|
1491
|
+
const supportFile = path10.resolve(context.filename);
|
|
1099
1492
|
const currentFolder = folderSegmentsOf(supportFile, sourceRoot2);
|
|
1100
1493
|
const supportFolder = currentFolder[currentFolder.length - 1];
|
|
1101
1494
|
if (supportFolder === void 0 || !SUPPORT_FOLDERS2.has(supportFolder)) return {};
|
|
@@ -1120,7 +1513,7 @@ var supportFilePlacementRule = {
|
|
|
1120
1513
|
|
|
1121
1514
|
// eslint/rules/application-structure.ts
|
|
1122
1515
|
import fs2 from "fs";
|
|
1123
|
-
import
|
|
1516
|
+
import path11 from "path";
|
|
1124
1517
|
var MODULE_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
|
|
1125
1518
|
var ROUTING_FILES = /* @__PURE__ */ new Set([
|
|
1126
1519
|
"default",
|
|
@@ -1149,7 +1542,7 @@ function report2(context, message) {
|
|
|
1149
1542
|
};
|
|
1150
1543
|
}
|
|
1151
1544
|
function isCodeFile(filename) {
|
|
1152
|
-
return MODULE_EXTENSIONS2.has(
|
|
1545
|
+
return MODULE_EXTENSIONS2.has(path11.extname(filename));
|
|
1153
1546
|
}
|
|
1154
1547
|
function isRootSupportFolder(folder) {
|
|
1155
1548
|
return SUPPORT_FOLDERS2.has(folder);
|
|
@@ -1170,7 +1563,7 @@ function expectedSupportFolder(kinds) {
|
|
|
1170
1563
|
function configModuleRoot(filename, sourceRoot2) {
|
|
1171
1564
|
const segments = segmentsOf(filename, sourceRoot2);
|
|
1172
1565
|
if (segments[0] !== "config" || segments.length < 3) return void 0;
|
|
1173
|
-
return
|
|
1566
|
+
return path11.join(sourceRoot2, "config", segments[1] ?? "");
|
|
1174
1567
|
}
|
|
1175
1568
|
function componentFolderStart(segments) {
|
|
1176
1569
|
if (segments[0] === "features") return 2;
|
|
@@ -1183,12 +1576,12 @@ function componentFolderViolation(segments, sourceRoot2) {
|
|
|
1183
1576
|
for (let depth = segments.length - 2; depth >= start; depth -= 1) {
|
|
1184
1577
|
const folder = segments[depth];
|
|
1185
1578
|
if (!folder || SUPPORT_FOLDERS2.has(folder)) continue;
|
|
1186
|
-
const folderPath =
|
|
1579
|
+
const folderPath = path11.join(sourceRoot2, ...segments.slice(0, depth + 1));
|
|
1187
1580
|
const label = `src/${segments.slice(0, depth + 1).join("/")}/`;
|
|
1188
|
-
if (!fs2.existsSync(
|
|
1581
|
+
if (!fs2.existsSync(path11.join(folderPath, `${folder}.tsx`))) {
|
|
1189
1582
|
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.`;
|
|
1190
1583
|
}
|
|
1191
|
-
if (!fs2.existsSync(
|
|
1584
|
+
if (!fs2.existsSync(path11.join(folderPath, "index.ts"))) {
|
|
1192
1585
|
return `A component folder must have an index.ts that named-re-exports its component; add index.ts to ${label}.`;
|
|
1193
1586
|
}
|
|
1194
1587
|
}
|
|
@@ -1203,8 +1596,8 @@ var applicationStructureRule = {
|
|
|
1203
1596
|
}
|
|
1204
1597
|
},
|
|
1205
1598
|
create(context) {
|
|
1206
|
-
const filename =
|
|
1207
|
-
const sourceRoot2 =
|
|
1599
|
+
const filename = path11.resolve(context.filename);
|
|
1600
|
+
const sourceRoot2 = path11.resolve("src");
|
|
1208
1601
|
const segments = segmentsOf(filename, sourceRoot2);
|
|
1209
1602
|
if (segments.length === 0) return {};
|
|
1210
1603
|
const [topLevel, secondLevel] = segments;
|
|
@@ -1234,42 +1627,42 @@ var applicationStructureRule = {
|
|
|
1234
1627
|
);
|
|
1235
1628
|
}
|
|
1236
1629
|
const moduleRoot = configModuleRoot(filename, sourceRoot2);
|
|
1237
|
-
if (moduleRoot && !fs2.existsSync(
|
|
1630
|
+
if (moduleRoot && !fs2.existsSync(path11.join(moduleRoot, "index.ts"))) {
|
|
1238
1631
|
return report2(
|
|
1239
1632
|
context,
|
|
1240
|
-
`Add src/config/${
|
|
1633
|
+
`Add src/config/${path11.basename(moduleRoot)}/index.ts as the configuration module entry point.`
|
|
1241
1634
|
);
|
|
1242
1635
|
}
|
|
1243
|
-
if (moduleRoot && segments.length === 3 &&
|
|
1636
|
+
if (moduleRoot && segments.length === 3 && path11.basename(filename) !== "index.ts") {
|
|
1244
1637
|
const kinds2 = exportedKinds(filename);
|
|
1245
1638
|
const expected2 = expectedSupportFolder(kinds2);
|
|
1246
1639
|
if (expected2 !== void 0) {
|
|
1247
1640
|
return report2(
|
|
1248
1641
|
context,
|
|
1249
|
-
`Move this configuration support file into src/config/${
|
|
1642
|
+
`Move this configuration support file into src/config/${path11.basename(moduleRoot)}/${expected2}/.`
|
|
1250
1643
|
);
|
|
1251
1644
|
}
|
|
1252
1645
|
}
|
|
1253
1646
|
}
|
|
1254
1647
|
if (topLevel === "app" && isCodeFile(filename)) {
|
|
1255
|
-
const basename =
|
|
1256
|
-
const currentFolder2 =
|
|
1648
|
+
const basename = path11.basename(filename, path11.extname(filename));
|
|
1649
|
+
const currentFolder2 = path11.basename(path11.dirname(filename));
|
|
1257
1650
|
if (SUPPORT_FOLDERS2.has(currentFolder2)) {
|
|
1258
1651
|
return report2(
|
|
1259
1652
|
context,
|
|
1260
1653
|
"src/app/ may contain routing files and framework assets, but ordinary components and support files must live outside src/app/."
|
|
1261
1654
|
);
|
|
1262
1655
|
}
|
|
1263
|
-
if (!ROUTING_FILES.has(basename) &&
|
|
1656
|
+
if (!ROUTING_FILES.has(basename) && path11.extname(filename) !== ".css") {
|
|
1264
1657
|
return report2(
|
|
1265
1658
|
context,
|
|
1266
1659
|
"src/app/ may contain routing files and framework assets, but ordinary components and support files must live outside src/app/."
|
|
1267
1660
|
);
|
|
1268
1661
|
}
|
|
1269
1662
|
}
|
|
1270
|
-
const currentFolder =
|
|
1663
|
+
const currentFolder = path11.basename(path11.dirname(filename));
|
|
1271
1664
|
const kinds = exportedKinds(filename);
|
|
1272
|
-
const isConfigModuleRoot = topLevel === "config" && segments.length === 3 &&
|
|
1665
|
+
const isConfigModuleRoot = topLevel === "config" && segments.length === 3 && path11.basename(filename) === "index.ts";
|
|
1273
1666
|
if (isConfigModuleRoot) return {};
|
|
1274
1667
|
if (!SUPPORT_FOLDERS2.has(currentFolder)) {
|
|
1275
1668
|
const expected2 = expectedSupportFolder(kinds);
|
|
@@ -1286,7 +1679,7 @@ var applicationStructureRule = {
|
|
|
1286
1679
|
if (kinds.has("component")) {
|
|
1287
1680
|
return report2(
|
|
1288
1681
|
context,
|
|
1289
|
-
`A support folder must not contain a component; move ${
|
|
1682
|
+
`A support folder must not contain a component; move ${path11.basename(filename)} beside ${currentFolder}/.`
|
|
1290
1683
|
);
|
|
1291
1684
|
}
|
|
1292
1685
|
const expected = expectedSupportFolder(kinds);
|
|
@@ -1303,7 +1696,7 @@ var applicationStructureRule = {
|
|
|
1303
1696
|
};
|
|
1304
1697
|
|
|
1305
1698
|
// eslint/rules/named-exports.ts
|
|
1306
|
-
import
|
|
1699
|
+
import path12 from "path";
|
|
1307
1700
|
var FRAMEWORK_DEFAULT_EXPORT_FILES = /* @__PURE__ */ new Set([
|
|
1308
1701
|
"default",
|
|
1309
1702
|
"error",
|
|
@@ -1315,9 +1708,9 @@ var FRAMEWORK_DEFAULT_EXPORT_FILES = /* @__PURE__ */ new Set([
|
|
|
1315
1708
|
"template"
|
|
1316
1709
|
]);
|
|
1317
1710
|
function isFrameworkDefaultExportFile(filename) {
|
|
1318
|
-
const normalized = filename.replaceAll(
|
|
1711
|
+
const normalized = filename.replaceAll(path12.sep, "/");
|
|
1319
1712
|
if (!normalized.includes("/src/app/")) return false;
|
|
1320
|
-
const basename =
|
|
1713
|
+
const basename = path12.basename(filename, path12.extname(filename));
|
|
1321
1714
|
return FRAMEWORK_DEFAULT_EXPORT_FILES.has(basename);
|
|
1322
1715
|
}
|
|
1323
1716
|
var namedExportsRule = {
|
|
@@ -1342,7 +1735,7 @@ var namedExportsRule = {
|
|
|
1342
1735
|
};
|
|
1343
1736
|
|
|
1344
1737
|
// eslint/rules/data-testid-case.ts
|
|
1345
|
-
import
|
|
1738
|
+
import path13 from "path";
|
|
1346
1739
|
var NEXT_ROUTING_FILES2 = /* @__PURE__ */ new Set([
|
|
1347
1740
|
"page",
|
|
1348
1741
|
"layout",
|
|
@@ -1366,9 +1759,9 @@ var dataTestIdCaseRule = {
|
|
|
1366
1759
|
}
|
|
1367
1760
|
},
|
|
1368
1761
|
create(context) {
|
|
1369
|
-
const filename =
|
|
1762
|
+
const filename = path13.resolve(context.filename);
|
|
1370
1763
|
if (!filename.endsWith(".tsx")) return {};
|
|
1371
|
-
const base =
|
|
1764
|
+
const base = path13.basename(filename, path13.extname(filename));
|
|
1372
1765
|
if (NEXT_ROUTING_FILES2.has(base)) return {};
|
|
1373
1766
|
const text = context.sourceCode.text;
|
|
1374
1767
|
const components = parseComponentInfo(text, filename);
|
|
@@ -1410,7 +1803,7 @@ function toKebabCase(value) {
|
|
|
1410
1803
|
|
|
1411
1804
|
// eslint/rules/support-folder-shape.ts
|
|
1412
1805
|
import fs3 from "fs";
|
|
1413
|
-
import
|
|
1806
|
+
import path14 from "path";
|
|
1414
1807
|
var SUPPORT_FOLDERS3 = /* @__PURE__ */ new Set(["constants", "types", "schemas"]);
|
|
1415
1808
|
var INDEX_NAMES = /* @__PURE__ */ new Set(["index.ts", "index.tsx", "index.mts", "index.cts"]);
|
|
1416
1809
|
var supportFolderShapeRule = {
|
|
@@ -1422,12 +1815,12 @@ var supportFolderShapeRule = {
|
|
|
1422
1815
|
}
|
|
1423
1816
|
},
|
|
1424
1817
|
create(context) {
|
|
1425
|
-
const filename =
|
|
1426
|
-
const baseName =
|
|
1818
|
+
const filename = path14.resolve(context.filename);
|
|
1819
|
+
const baseName = path14.basename(filename);
|
|
1427
1820
|
if (!INDEX_NAMES.has(baseName)) return {};
|
|
1428
|
-
const folder =
|
|
1821
|
+
const folder = path14.basename(path14.dirname(filename));
|
|
1429
1822
|
if (!SUPPORT_FOLDERS3.has(folder)) return {};
|
|
1430
|
-
const directory =
|
|
1823
|
+
const directory = path14.dirname(filename);
|
|
1431
1824
|
let entries;
|
|
1432
1825
|
try {
|
|
1433
1826
|
entries = fs3.readdirSync(directory);
|
|
@@ -1445,7 +1838,7 @@ var supportFolderShapeRule = {
|
|
|
1445
1838
|
const exportPattern = /export\s+(?:\{[^}]*\}|\*[^;]*)\s+from\s+["'](?<specifier>\.[^"']+)["']/g;
|
|
1446
1839
|
for (const match of source.matchAll(exportPattern)) {
|
|
1447
1840
|
const specifier = match.groups?.specifier;
|
|
1448
|
-
if (specifier) exportedFiles.add(
|
|
1841
|
+
if (specifier) exportedFiles.add(path14.basename(specifier));
|
|
1449
1842
|
}
|
|
1450
1843
|
const missing = siblingModules.filter((entry) => {
|
|
1451
1844
|
const stem = entry.replace(/\.(?:[cm]?tsx?|jsx?)$/, "");
|
|
@@ -1462,7 +1855,7 @@ var supportFolderShapeRule = {
|
|
|
1462
1855
|
};
|
|
1463
1856
|
|
|
1464
1857
|
// eslint/rules/import-through-index.ts
|
|
1465
|
-
import
|
|
1858
|
+
import path15 from "path";
|
|
1466
1859
|
var importThroughIndexRule = {
|
|
1467
1860
|
meta: {
|
|
1468
1861
|
schema: [],
|
|
@@ -1472,7 +1865,7 @@ var importThroughIndexRule = {
|
|
|
1472
1865
|
}
|
|
1473
1866
|
},
|
|
1474
1867
|
create(context) {
|
|
1475
|
-
const filename =
|
|
1868
|
+
const filename = path15.resolve(context.filename);
|
|
1476
1869
|
const sourceRoot2 = sourceRootOf(filename);
|
|
1477
1870
|
return {
|
|
1478
1871
|
Program(node) {
|
|
@@ -1484,7 +1877,7 @@ var importThroughIndexRule = {
|
|
|
1484
1877
|
(segment) => ["constants", "types", "schemas"].includes(segment)
|
|
1485
1878
|
);
|
|
1486
1879
|
const supportFolder = supportFolderIndex >= 0 ? targetSegments[supportFolderIndex] : void 0;
|
|
1487
|
-
if (!supportFolder ||
|
|
1880
|
+
if (!supportFolder || path15.basename(target).startsWith("index.")) continue;
|
|
1488
1881
|
const folderIndex = targetSegments.slice(0, supportFolderIndex + 1);
|
|
1489
1882
|
const expected = `@/${folderIndex.join("/")}`;
|
|
1490
1883
|
context.report({
|
|
@@ -1506,13 +1899,13 @@ function importSpecifiers(source) {
|
|
|
1506
1899
|
return specifiers;
|
|
1507
1900
|
}
|
|
1508
1901
|
function sourceRootOf(filename) {
|
|
1509
|
-
const marker = `${
|
|
1902
|
+
const marker = `${path15.sep}src${path15.sep}`;
|
|
1510
1903
|
const srcIndex = filename.lastIndexOf(marker);
|
|
1511
|
-
return srcIndex >= 0 ? filename.slice(0, srcIndex + marker.length - 1) :
|
|
1904
|
+
return srcIndex >= 0 ? filename.slice(0, srcIndex + marker.length - 1) : path15.resolve("src");
|
|
1512
1905
|
}
|
|
1513
1906
|
|
|
1514
1907
|
// eslint/rules/util-file-name.ts
|
|
1515
|
-
import
|
|
1908
|
+
import path16 from "path";
|
|
1516
1909
|
function toKebabCase2(value) {
|
|
1517
1910
|
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();
|
|
1518
1911
|
}
|
|
@@ -1525,7 +1918,7 @@ var utilFileNameRule = {
|
|
|
1525
1918
|
}
|
|
1526
1919
|
},
|
|
1527
1920
|
create(context) {
|
|
1528
|
-
const filename =
|
|
1921
|
+
const filename = path16.resolve(context.filename);
|
|
1529
1922
|
const segments = filename.replace(/\\/g, "/").split("/");
|
|
1530
1923
|
if (!segments.includes("utils")) return {};
|
|
1531
1924
|
let module;
|
|
@@ -1539,13 +1932,13 @@ var utilFileNameRule = {
|
|
|
1539
1932
|
const functionName = functions[0]?.name;
|
|
1540
1933
|
if (!functionName) return {};
|
|
1541
1934
|
const expected = toKebabCase2(functionName);
|
|
1542
|
-
const actual =
|
|
1935
|
+
const actual = path16.basename(filename, path16.extname(filename));
|
|
1543
1936
|
if (!expected || actual === expected) return {};
|
|
1544
1937
|
return {
|
|
1545
1938
|
Program(node) {
|
|
1546
1939
|
context.report({
|
|
1547
1940
|
node,
|
|
1548
|
-
message: `A utility file exporting ${functionName} must be named ${expected}.${
|
|
1941
|
+
message: `A utility file exporting ${functionName} must be named ${expected}.${path16.extname(filename).slice(1)}.`
|
|
1549
1942
|
});
|
|
1550
1943
|
}
|
|
1551
1944
|
};
|
|
@@ -1553,7 +1946,7 @@ var utilFileNameRule = {
|
|
|
1553
1946
|
};
|
|
1554
1947
|
|
|
1555
1948
|
// eslint/rules/no-util-barrel.ts
|
|
1556
|
-
import
|
|
1949
|
+
import path17 from "path";
|
|
1557
1950
|
var noUtilBarrelRule = {
|
|
1558
1951
|
meta: {
|
|
1559
1952
|
schema: [],
|
|
@@ -1563,7 +1956,7 @@ var noUtilBarrelRule = {
|
|
|
1563
1956
|
}
|
|
1564
1957
|
},
|
|
1565
1958
|
create(context) {
|
|
1566
|
-
const filename =
|
|
1959
|
+
const filename = path17.resolve(context.filename);
|
|
1567
1960
|
const sourceRoot2 = sourceRootOf2(filename);
|
|
1568
1961
|
return {
|
|
1569
1962
|
Program(node) {
|
|
@@ -1572,7 +1965,7 @@ var noUtilBarrelRule = {
|
|
|
1572
1965
|
if (!target) continue;
|
|
1573
1966
|
const segments = target.replace(/\\/g, "/").split("/");
|
|
1574
1967
|
const utilsIndex = segments.lastIndexOf("utils");
|
|
1575
|
-
if (utilsIndex < 0 || !
|
|
1968
|
+
if (utilsIndex < 0 || !path17.basename(target).startsWith("index.")) continue;
|
|
1576
1969
|
context.report({
|
|
1577
1970
|
node,
|
|
1578
1971
|
message: `Import utilities directly instead of through "${specifier}". See docs/code-organization-guide/rules/utilities-rule.md`
|
|
@@ -1592,9 +1985,9 @@ function importSpecifiers2(source) {
|
|
|
1592
1985
|
return specifiers;
|
|
1593
1986
|
}
|
|
1594
1987
|
function sourceRootOf2(filename) {
|
|
1595
|
-
const marker = `${
|
|
1988
|
+
const marker = `${path17.sep}src${path17.sep}`;
|
|
1596
1989
|
const srcIndex = filename.lastIndexOf(marker);
|
|
1597
|
-
return srcIndex >= 0 ? filename.slice(0, srcIndex + marker.length - 1) :
|
|
1990
|
+
return srcIndex >= 0 ? filename.slice(0, srcIndex + marker.length - 1) : path17.resolve("src");
|
|
1598
1991
|
}
|
|
1599
1992
|
|
|
1600
1993
|
// eslint/rules/jsx-hygiene.ts
|
|
@@ -1970,12 +2363,12 @@ var cvaBooleanVariantsRule = {
|
|
|
1970
2363
|
};
|
|
1971
2364
|
|
|
1972
2365
|
// eslint/rules/cross-feature-import.ts
|
|
1973
|
-
import
|
|
2366
|
+
import path18 from "path";
|
|
1974
2367
|
var FEATURES_SEGMENT = "features";
|
|
1975
2368
|
function featureNameOf(resolvedPath, sourceRoot2) {
|
|
1976
|
-
const relative =
|
|
2369
|
+
const relative = path18.relative(sourceRoot2, resolvedPath);
|
|
1977
2370
|
if (relative.startsWith("..")) return void 0;
|
|
1978
|
-
const segments = relative.split(
|
|
2371
|
+
const segments = relative.split(path18.sep);
|
|
1979
2372
|
if (segments[0] !== FEATURES_SEGMENT || segments.length < 2) return void 0;
|
|
1980
2373
|
return segments[1];
|
|
1981
2374
|
}
|
|
@@ -1990,10 +2383,10 @@ var crossFeatureImportRule = {
|
|
|
1990
2383
|
create(context) {
|
|
1991
2384
|
const filename = context.filename;
|
|
1992
2385
|
if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
|
|
1993
|
-
const sourceRoot2 =
|
|
1994
|
-
const fileRelative =
|
|
2386
|
+
const sourceRoot2 = path18.resolve("src");
|
|
2387
|
+
const fileRelative = path18.relative(sourceRoot2, filename);
|
|
1995
2388
|
if (fileRelative.startsWith("..")) return {};
|
|
1996
|
-
const fileSegments = fileRelative.split(
|
|
2389
|
+
const fileSegments = fileRelative.split(path18.sep);
|
|
1997
2390
|
const isInCompositions = fileSegments[0] === "compositions";
|
|
1998
2391
|
const isInApp = fileSegments[0] === "app";
|
|
1999
2392
|
const isConfig = fileSegments[0] === "config";
|
|
@@ -2007,9 +2400,9 @@ var crossFeatureImportRule = {
|
|
|
2007
2400
|
if (typeof source.value !== "string") return;
|
|
2008
2401
|
let resolved;
|
|
2009
2402
|
if (source.value.startsWith("@/")) {
|
|
2010
|
-
resolved =
|
|
2403
|
+
resolved = path18.resolve(sourceRoot2, source.value.slice(2));
|
|
2011
2404
|
} else if (source.value.startsWith(".")) {
|
|
2012
|
-
resolved =
|
|
2405
|
+
resolved = path18.resolve(path18.dirname(filename), source.value);
|
|
2013
2406
|
}
|
|
2014
2407
|
if (!resolved) return;
|
|
2015
2408
|
const feature = featureNameOf(resolved, sourceRoot2);
|
|
@@ -2028,7 +2421,7 @@ var crossFeatureImportRule = {
|
|
|
2028
2421
|
};
|
|
2029
2422
|
|
|
2030
2423
|
// eslint/rules/pure-function-extract.ts
|
|
2031
|
-
import
|
|
2424
|
+
import path19 from "path";
|
|
2032
2425
|
function isComponentLikeName(name) {
|
|
2033
2426
|
return /^[A-Z]/.test(name);
|
|
2034
2427
|
}
|
|
@@ -2056,10 +2449,10 @@ var pureFunctionExtractRule = {
|
|
|
2056
2449
|
create(context) {
|
|
2057
2450
|
const filename = context.filename;
|
|
2058
2451
|
if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
|
|
2059
|
-
const sourceRoot2 =
|
|
2060
|
-
const relative =
|
|
2452
|
+
const sourceRoot2 = path19.resolve("src");
|
|
2453
|
+
const relative = path19.relative(sourceRoot2, filename);
|
|
2061
2454
|
if (relative.startsWith("..")) return {};
|
|
2062
|
-
const segments = relative.split(
|
|
2455
|
+
const segments = relative.split(path19.sep);
|
|
2063
2456
|
if (segments[0] === "utils") return {};
|
|
2064
2457
|
if (segments[0] === "app") return {};
|
|
2065
2458
|
const supportFolders = /* @__PURE__ */ new Set(["hooks", "types", "schemas", "constants", "utils"]);
|
|
@@ -2099,7 +2492,7 @@ var pureFunctionExtractRule = {
|
|
|
2099
2492
|
};
|
|
2100
2493
|
|
|
2101
2494
|
// eslint/rules/hook-complexity.ts
|
|
2102
|
-
import
|
|
2495
|
+
import path20 from "path";
|
|
2103
2496
|
import ts4 from "typescript";
|
|
2104
2497
|
var REACT_HOOKS = /* @__PURE__ */ new Set([
|
|
2105
2498
|
"useState",
|
|
@@ -2151,10 +2544,10 @@ var hookComplexityRule = {
|
|
|
2151
2544
|
},
|
|
2152
2545
|
create(context) {
|
|
2153
2546
|
const filename = context.filename;
|
|
2154
|
-
const sourceRoot2 =
|
|
2155
|
-
const relative =
|
|
2547
|
+
const sourceRoot2 = path20.resolve("src");
|
|
2548
|
+
const relative = path20.relative(sourceRoot2, filename);
|
|
2156
2549
|
if (relative.startsWith("..")) return {};
|
|
2157
|
-
const segments = relative.split(
|
|
2550
|
+
const segments = relative.split(path20.sep);
|
|
2158
2551
|
const sourceText = context.sourceCode.text;
|
|
2159
2552
|
function checkHook(node, name, body, exported) {
|
|
2160
2553
|
if (!exported) return;
|
|
@@ -2196,9 +2589,9 @@ var hookComplexityRule = {
|
|
|
2196
2589
|
};
|
|
2197
2590
|
|
|
2198
2591
|
// eslint/rules/locale-dotted-path.ts
|
|
2199
|
-
import
|
|
2592
|
+
import path21 from "path";
|
|
2200
2593
|
function isInLocalesDir(filename) {
|
|
2201
|
-
const segments =
|
|
2594
|
+
const segments = path21.resolve(filename).split(path21.sep);
|
|
2202
2595
|
const srcIdx = segments.lastIndexOf("src");
|
|
2203
2596
|
return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
|
|
2204
2597
|
}
|
|
@@ -2247,9 +2640,9 @@ var localeDottedPathRule = {
|
|
|
2247
2640
|
};
|
|
2248
2641
|
|
|
2249
2642
|
// eslint/rules/locales-location.ts
|
|
2250
|
-
import
|
|
2643
|
+
import path22 from "path";
|
|
2251
2644
|
function isLocalesFile(filename) {
|
|
2252
|
-
const segments =
|
|
2645
|
+
const segments = path22.resolve(filename).split(path22.sep);
|
|
2253
2646
|
const srcIdx = segments.lastIndexOf("src");
|
|
2254
2647
|
return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
|
|
2255
2648
|
}
|
|
@@ -2268,7 +2661,7 @@ var localesLocationRule = {
|
|
|
2268
2661
|
create(context) {
|
|
2269
2662
|
if (isLocalesFile(context.filename)) return {};
|
|
2270
2663
|
const filename = context.filename;
|
|
2271
|
-
const segments =
|
|
2664
|
+
const segments = path22.resolve(filename).split(path22.sep);
|
|
2272
2665
|
const srcIdx = segments.lastIndexOf("src");
|
|
2273
2666
|
if (srcIdx === -1) return {};
|
|
2274
2667
|
const folder = segments[srcIdx + 1];
|
|
@@ -2290,7 +2683,7 @@ var localesLocationRule = {
|
|
|
2290
2683
|
};
|
|
2291
2684
|
|
|
2292
2685
|
// eslint/rules/hook-extraction.ts
|
|
2293
|
-
import
|
|
2686
|
+
import path23 from "path";
|
|
2294
2687
|
var hookExtractionRule = {
|
|
2295
2688
|
meta: {
|
|
2296
2689
|
schema: [],
|
|
@@ -2300,8 +2693,8 @@ var hookExtractionRule = {
|
|
|
2300
2693
|
}
|
|
2301
2694
|
},
|
|
2302
2695
|
create(context) {
|
|
2303
|
-
const sourceRoot2 =
|
|
2304
|
-
const file =
|
|
2696
|
+
const sourceRoot2 = path23.resolve("src");
|
|
2697
|
+
const file = path23.resolve(context.filename);
|
|
2305
2698
|
const segments = segmentsOf(file, sourceRoot2);
|
|
2306
2699
|
if (segments.length === 0) return {};
|
|
2307
2700
|
const index = getProjectIndex(sourceRoot2);
|
|
@@ -2327,7 +2720,7 @@ var hookExtractionRule = {
|
|
|
2327
2720
|
};
|
|
2328
2721
|
|
|
2329
2722
|
// eslint/rules/value-extraction.ts
|
|
2330
|
-
import
|
|
2723
|
+
import path24 from "path";
|
|
2331
2724
|
var valueExtractionRule = {
|
|
2332
2725
|
meta: {
|
|
2333
2726
|
schema: [],
|
|
@@ -2337,8 +2730,8 @@ var valueExtractionRule = {
|
|
|
2337
2730
|
}
|
|
2338
2731
|
},
|
|
2339
2732
|
create(context) {
|
|
2340
|
-
const sourceRoot2 =
|
|
2341
|
-
const file =
|
|
2733
|
+
const sourceRoot2 = path24.resolve("src");
|
|
2734
|
+
const file = path24.resolve(context.filename);
|
|
2342
2735
|
const segments = segmentsOf(file, sourceRoot2);
|
|
2343
2736
|
if (segments.length === 0 || segments[0] !== "app") return {};
|
|
2344
2737
|
const index = getProjectIndex(sourceRoot2);
|
|
@@ -2359,7 +2752,7 @@ var valueExtractionRule = {
|
|
|
2359
2752
|
};
|
|
2360
2753
|
|
|
2361
2754
|
// eslint/rules/config-extraction.ts
|
|
2362
|
-
import
|
|
2755
|
+
import path25 from "path";
|
|
2363
2756
|
var configExtractionRule = {
|
|
2364
2757
|
meta: {
|
|
2365
2758
|
schema: [],
|
|
@@ -2369,8 +2762,8 @@ var configExtractionRule = {
|
|
|
2369
2762
|
}
|
|
2370
2763
|
},
|
|
2371
2764
|
create(context) {
|
|
2372
|
-
const sourceRoot2 =
|
|
2373
|
-
const file =
|
|
2765
|
+
const sourceRoot2 = path25.resolve("src");
|
|
2766
|
+
const file = path25.resolve(context.filename);
|
|
2374
2767
|
const segments = segmentsOf(file, sourceRoot2);
|
|
2375
2768
|
if (segments.length < 3 || segments[0] !== "config") return {};
|
|
2376
2769
|
if (SUPPORT_FOLDERS2.has(segments[2] ?? "")) return {};
|
|
@@ -2408,7 +2801,7 @@ var configExtractionRule = {
|
|
|
2408
2801
|
};
|
|
2409
2802
|
|
|
2410
2803
|
// eslint/rules/component-nesting.ts
|
|
2411
|
-
import
|
|
2804
|
+
import path26 from "path";
|
|
2412
2805
|
var componentNestingRule = {
|
|
2413
2806
|
meta: {
|
|
2414
2807
|
schema: [],
|
|
@@ -2418,8 +2811,8 @@ var componentNestingRule = {
|
|
|
2418
2811
|
}
|
|
2419
2812
|
},
|
|
2420
2813
|
create(context) {
|
|
2421
|
-
const sourceRoot2 =
|
|
2422
|
-
const file =
|
|
2814
|
+
const sourceRoot2 = path26.resolve("src");
|
|
2815
|
+
const file = path26.resolve(context.filename);
|
|
2423
2816
|
const segments = segmentsOf(file, sourceRoot2);
|
|
2424
2817
|
if (segments.length !== 4 || segments[0] !== "features") return {};
|
|
2425
2818
|
const index = getProjectIndex(sourceRoot2);
|
|
@@ -2452,7 +2845,7 @@ var componentNestingRule = {
|
|
|
2452
2845
|
};
|
|
2453
2846
|
|
|
2454
2847
|
// eslint/rules/stay-flat.ts
|
|
2455
|
-
import
|
|
2848
|
+
import path27 from "path";
|
|
2456
2849
|
var stayFlatRule = {
|
|
2457
2850
|
meta: {
|
|
2458
2851
|
schema: [],
|
|
@@ -2462,8 +2855,8 @@ var stayFlatRule = {
|
|
|
2462
2855
|
}
|
|
2463
2856
|
},
|
|
2464
2857
|
create(context) {
|
|
2465
|
-
const sourceRoot2 =
|
|
2466
|
-
const file =
|
|
2858
|
+
const sourceRoot2 = path27.resolve("src");
|
|
2859
|
+
const file = path27.resolve(context.filename);
|
|
2467
2860
|
const segments = segmentsOf(file, sourceRoot2);
|
|
2468
2861
|
if (segments.length !== 3 || segments[0] !== "features") return {};
|
|
2469
2862
|
const index = getProjectIndex(sourceRoot2);
|
|
@@ -2503,7 +2896,7 @@ var stayFlatRule = {
|
|
|
2503
2896
|
};
|
|
2504
2897
|
|
|
2505
2898
|
// eslint/rules/type-extraction.ts
|
|
2506
|
-
import
|
|
2899
|
+
import path28 from "path";
|
|
2507
2900
|
var typeExtractionRule = {
|
|
2508
2901
|
meta: {
|
|
2509
2902
|
schema: [],
|
|
@@ -2513,8 +2906,8 @@ var typeExtractionRule = {
|
|
|
2513
2906
|
}
|
|
2514
2907
|
},
|
|
2515
2908
|
create(context) {
|
|
2516
|
-
const sourceRoot2 =
|
|
2517
|
-
const file =
|
|
2909
|
+
const sourceRoot2 = path28.resolve("src");
|
|
2910
|
+
const file = path28.resolve(context.filename);
|
|
2518
2911
|
const segments = segmentsOf(file, sourceRoot2);
|
|
2519
2912
|
if (segments.length === 0) return {};
|
|
2520
2913
|
const index = getProjectIndex(sourceRoot2);
|
|
@@ -2560,8 +2953,8 @@ var typeExtractionRule = {
|
|
|
2560
2953
|
};
|
|
2561
2954
|
|
|
2562
2955
|
// eslint/rules/locale-placement.ts
|
|
2563
|
-
import
|
|
2564
|
-
import { readFileSync as
|
|
2956
|
+
import path29 from "path";
|
|
2957
|
+
import { readFileSync as readFileSync3 } from "fs";
|
|
2565
2958
|
import ts5 from "typescript";
|
|
2566
2959
|
var LOCALE_ACCESS = /\blocales\.(?<key>[A-Za-z_$][\w$]*)/g;
|
|
2567
2960
|
var camelCase = (name) => name.replace(/-[a-z]/g, (match) => match.slice(1).toUpperCase());
|
|
@@ -2607,8 +3000,8 @@ var localePlacementRule = {
|
|
|
2607
3000
|
}
|
|
2608
3001
|
},
|
|
2609
3002
|
create(context) {
|
|
2610
|
-
const sourceRoot2 =
|
|
2611
|
-
const file =
|
|
3003
|
+
const sourceRoot2 = path29.resolve("src");
|
|
3004
|
+
const file = path29.resolve(context.filename);
|
|
2612
3005
|
const segments = segmentsOf(file, sourceRoot2);
|
|
2613
3006
|
if (segments.length === 0) return {};
|
|
2614
3007
|
const index = getProjectIndex(sourceRoot2);
|
|
@@ -2618,7 +3011,7 @@ var localePlacementRule = {
|
|
|
2618
3011
|
return candidateSegments.length === 2 && candidateSegments[0] === "locales" && candidateSegments[1]?.startsWith("index.");
|
|
2619
3012
|
});
|
|
2620
3013
|
if (!localesFile || file !== localesFile) return {};
|
|
2621
|
-
const placement = localePlacement(
|
|
3014
|
+
const placement = localePlacement(readFileSync3(localesFile, "utf8"));
|
|
2622
3015
|
if (!placement) return {};
|
|
2623
3016
|
const keyReaders = /* @__PURE__ */ new Map();
|
|
2624
3017
|
const keyFeatures = /* @__PURE__ */ new Map();
|
|
@@ -2630,7 +3023,7 @@ var localePlacementRule = {
|
|
|
2630
3023
|
);
|
|
2631
3024
|
if (!importsLocales) continue;
|
|
2632
3025
|
const candidateSegments = segmentsOf(candidateFile, sourceRoot2);
|
|
2633
|
-
for (const match of
|
|
3026
|
+
for (const match of readFileSync3(candidateFile, "utf8").matchAll(LOCALE_ACCESS)) {
|
|
2634
3027
|
const key = match.groups?.key;
|
|
2635
3028
|
if (key === void 0) continue;
|
|
2636
3029
|
const readers = keyReaders.get(key) ?? /* @__PURE__ */ new Set();
|
|
@@ -2686,7 +3079,7 @@ var localePlacementRule = {
|
|
|
2686
3079
|
};
|
|
2687
3080
|
|
|
2688
3081
|
// eslint/rules/sole-state-owner.ts
|
|
2689
|
-
import
|
|
3082
|
+
import path30 from "path";
|
|
2690
3083
|
import ts6 from "typescript";
|
|
2691
3084
|
function findStateHooks(node) {
|
|
2692
3085
|
const hooks = [];
|
|
@@ -2766,7 +3159,7 @@ var soleStateOwnerRule = {
|
|
|
2766
3159
|
}
|
|
2767
3160
|
},
|
|
2768
3161
|
create(context) {
|
|
2769
|
-
const filename =
|
|
3162
|
+
const filename = path30.resolve(context.filename);
|
|
2770
3163
|
if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
|
|
2771
3164
|
const text = context.sourceCode.text;
|
|
2772
3165
|
const components = parseComponentInfo(text, filename);
|
|
@@ -2845,7 +3238,7 @@ function usesOutsideJsx(declaration, hook, children) {
|
|
|
2845
3238
|
}
|
|
2846
3239
|
|
|
2847
3240
|
// eslint/rules/locale-key-shape.ts
|
|
2848
|
-
import
|
|
3241
|
+
import path31 from "path";
|
|
2849
3242
|
var MAX_KEY_LENGTH = 30;
|
|
2850
3243
|
var ROLE_POSTFIXES = /* @__PURE__ */ new Set([
|
|
2851
3244
|
"Button",
|
|
@@ -2893,8 +3286,9 @@ var ROLE_POSTFIXES = /* @__PURE__ */ new Set([
|
|
|
2893
3286
|
"ScrollBar"
|
|
2894
3287
|
]);
|
|
2895
3288
|
var CAMEL_CASE = /^[a-z][a-zA-Z0-9]*$/;
|
|
3289
|
+
var ENGLISH = /^[A-Za-z0-9_]*$/;
|
|
2896
3290
|
function isLocalesFile2(filename) {
|
|
2897
|
-
const segments =
|
|
3291
|
+
const segments = path31.resolve(filename).split(path31.sep);
|
|
2898
3292
|
const srcIdx = segments.lastIndexOf("src");
|
|
2899
3293
|
return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
|
|
2900
3294
|
}
|
|
@@ -2907,6 +3301,14 @@ function reportFor(context, node, message) {
|
|
|
2907
3301
|
context.report({ node, message });
|
|
2908
3302
|
}
|
|
2909
3303
|
function checkKey(context, node, name) {
|
|
3304
|
+
if (!ENGLISH.test(name)) {
|
|
3305
|
+
reportFor(
|
|
3306
|
+
context,
|
|
3307
|
+
node,
|
|
3308
|
+
`Locale key "${name}" must be English; write it in the Latin alphabet. See docs/code-organization-guide/rules/locales-rule.md`
|
|
3309
|
+
);
|
|
3310
|
+
return;
|
|
3311
|
+
}
|
|
2910
3312
|
if (!CAMEL_CASE.test(name)) {
|
|
2911
3313
|
reportFor(
|
|
2912
3314
|
context,
|
|
@@ -2957,8 +3359,8 @@ var localeKeyShapeRule = {
|
|
|
2957
3359
|
};
|
|
2958
3360
|
|
|
2959
3361
|
// eslint/rules/shared-style-dedup.ts
|
|
2960
|
-
import
|
|
2961
|
-
import { readFileSync as
|
|
3362
|
+
import path32 from "path";
|
|
3363
|
+
import { readFileSync as readFileSync4, statSync as statSync3 } from "fs";
|
|
2962
3364
|
var CLASS_NAME = /className="(?<classes>[^"]+)"/g;
|
|
2963
3365
|
var comboCache;
|
|
2964
3366
|
function combosFor(index) {
|
|
@@ -2966,7 +3368,7 @@ function combosFor(index) {
|
|
|
2966
3368
|
let fingerprint2 = "";
|
|
2967
3369
|
for (const file of files) {
|
|
2968
3370
|
try {
|
|
2969
|
-
fingerprint2 += String(
|
|
3371
|
+
fingerprint2 += String(statSync3(file).mtimeMs);
|
|
2970
3372
|
} catch {
|
|
2971
3373
|
fingerprint2 += "0";
|
|
2972
3374
|
}
|
|
@@ -2976,7 +3378,7 @@ function combosFor(index) {
|
|
|
2976
3378
|
}
|
|
2977
3379
|
const combos = /* @__PURE__ */ new Map();
|
|
2978
3380
|
for (const file of files) {
|
|
2979
|
-
const text =
|
|
3381
|
+
const text = readFileSync4(file, "utf8");
|
|
2980
3382
|
for (const match of text.matchAll(CLASS_NAME)) {
|
|
2981
3383
|
const classes = (match.groups?.classes ?? "").split(/\s+/).filter(Boolean);
|
|
2982
3384
|
if (classes.length < 2) continue;
|
|
@@ -2998,8 +3400,8 @@ var sharedStyleDedupRule = {
|
|
|
2998
3400
|
}
|
|
2999
3401
|
},
|
|
3000
3402
|
create(context) {
|
|
3001
|
-
const sourceRoot2 =
|
|
3002
|
-
const file =
|
|
3403
|
+
const sourceRoot2 = path32.resolve("src");
|
|
3404
|
+
const file = path32.resolve(context.filename);
|
|
3003
3405
|
const segments = segmentsOf(file, sourceRoot2);
|
|
3004
3406
|
if (segments.length === 0) return {};
|
|
3005
3407
|
const index = getProjectIndex(sourceRoot2);
|
|
@@ -3203,7 +3605,7 @@ var zodSchemaValidationRule = {
|
|
|
3203
3605
|
};
|
|
3204
3606
|
|
|
3205
3607
|
// eslint/rules/source-under-src.ts
|
|
3206
|
-
import
|
|
3608
|
+
import path33 from "path";
|
|
3207
3609
|
var NON_SOURCE_ROOT_DIRS = /* @__PURE__ */ new Set([
|
|
3208
3610
|
".agents",
|
|
3209
3611
|
".cache",
|
|
@@ -3244,14 +3646,14 @@ var sourceUnderSrcRule = {
|
|
|
3244
3646
|
}
|
|
3245
3647
|
},
|
|
3246
3648
|
create(context) {
|
|
3247
|
-
const filename =
|
|
3649
|
+
const filename = path33.resolve(context.filename);
|
|
3248
3650
|
if (!MODULE_EXTENSION.test(filename)) return {};
|
|
3249
|
-
const relative =
|
|
3651
|
+
const relative = path33.relative(process.cwd(), filename).replace(/\\/g, "/");
|
|
3250
3652
|
if (relative === "src" || relative.startsWith("src/")) return {};
|
|
3251
3653
|
const topLevel = relative.split("/")[0] ?? "";
|
|
3252
3654
|
if (NON_SOURCE_ROOT_DIRS.has(topLevel)) return {};
|
|
3253
3655
|
if (!relative.includes("/")) {
|
|
3254
|
-
const basename =
|
|
3656
|
+
const basename = path33.basename(filename);
|
|
3255
3657
|
if (CONFIG_FILE.test(basename) || DECLARATION_FILE.test(basename) || basename.startsWith(".")) return {};
|
|
3256
3658
|
}
|
|
3257
3659
|
return {
|
|
@@ -3268,7 +3670,7 @@ var sourceUnderSrcRule = {
|
|
|
3268
3670
|
|
|
3269
3671
|
// eslint/rules/zirka-baseline.ts
|
|
3270
3672
|
import fs4 from "fs";
|
|
3271
|
-
import
|
|
3673
|
+
import path34 from "path";
|
|
3272
3674
|
var ESLINT_CONFIG = /^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/;
|
|
3273
3675
|
var PRETTIER_CONFIGS = [
|
|
3274
3676
|
"prettier.config.mjs",
|
|
@@ -3287,10 +3689,10 @@ var zirkaBaselineRule = {
|
|
|
3287
3689
|
}
|
|
3288
3690
|
},
|
|
3289
3691
|
create(context) {
|
|
3290
|
-
const filename =
|
|
3291
|
-
const basename =
|
|
3692
|
+
const filename = path34.resolve(context.filename);
|
|
3693
|
+
const basename = path34.basename(filename);
|
|
3292
3694
|
if (!ESLINT_CONFIG.test(basename)) return {};
|
|
3293
|
-
const projectRoot =
|
|
3695
|
+
const projectRoot = path34.dirname(filename);
|
|
3294
3696
|
const report3 = (message) => {
|
|
3295
3697
|
context.report({
|
|
3296
3698
|
node: context.sourceCode.ast,
|
|
@@ -3305,7 +3707,7 @@ var zirkaBaselineRule = {
|
|
|
3305
3707
|
'ESLint config must take its configuration from zirka (import { styleguide } from "zirka") instead of restating rules locally.'
|
|
3306
3708
|
);
|
|
3307
3709
|
}
|
|
3308
|
-
const tsconfigPath =
|
|
3710
|
+
const tsconfigPath = path34.join(projectRoot, "tsconfig.json");
|
|
3309
3711
|
if (!fs4.existsSync(tsconfigPath)) {
|
|
3310
3712
|
report3('No tsconfig.json found. Create one extending the zirka TypeScript base config ("zirka/typescript").');
|
|
3311
3713
|
} else {
|
|
@@ -3323,13 +3725,13 @@ var zirkaBaselineRule = {
|
|
|
3323
3725
|
report3('tsconfig.json must extend the zirka TypeScript base config ("zirka/typescript").');
|
|
3324
3726
|
}
|
|
3325
3727
|
}
|
|
3326
|
-
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs4.existsSync(
|
|
3728
|
+
const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs4.existsSync(path34.join(projectRoot, name)));
|
|
3327
3729
|
if (!prettierConfigFile) {
|
|
3328
3730
|
report3(
|
|
3329
3731
|
"No prettier config found. Create one that takes its configuration from zirka (styleguide({ prettier: true }).prettierConfig)."
|
|
3330
3732
|
);
|
|
3331
3733
|
} else {
|
|
3332
|
-
const content = fs4.readFileSync(
|
|
3734
|
+
const content = fs4.readFileSync(path34.join(projectRoot, prettierConfigFile), "utf8");
|
|
3333
3735
|
if (!content.includes("zirka")) {
|
|
3334
3736
|
report3(
|
|
3335
3737
|
"The prettier config must take its configuration from zirka (styleguide({ prettier: true }).prettierConfig) instead of restating it locally."
|
|
@@ -3399,7 +3801,7 @@ var docKindSuffixRule = {
|
|
|
3399
3801
|
};
|
|
3400
3802
|
|
|
3401
3803
|
// eslint/rules/documentation/title-matches-file-name.ts
|
|
3402
|
-
import
|
|
3804
|
+
import path35 from "path";
|
|
3403
3805
|
function toExpectedFileName(title) {
|
|
3404
3806
|
return `${title.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")}.md`;
|
|
3405
3807
|
}
|
|
@@ -3419,7 +3821,7 @@ var titleMatchesFileNameRule = {
|
|
|
3419
3821
|
if (!filename.endsWith(".md")) return;
|
|
3420
3822
|
const title = getTextContent(node).trim();
|
|
3421
3823
|
const expectedFileName = toExpectedFileName(title);
|
|
3422
|
-
const actualFileName =
|
|
3824
|
+
const actualFileName = path35.basename(filename);
|
|
3423
3825
|
if (!title) {
|
|
3424
3826
|
context.report({
|
|
3425
3827
|
node,
|
|
@@ -3826,7 +4228,7 @@ var referenceBlockHeadingsRule = {
|
|
|
3826
4228
|
};
|
|
3827
4229
|
|
|
3828
4230
|
// eslint/rules/documentation/support-document-placement.ts
|
|
3829
|
-
import
|
|
4231
|
+
import path36 from "path";
|
|
3830
4232
|
var supportDocumentPlacementRule = {
|
|
3831
4233
|
meta: {
|
|
3832
4234
|
type: "problem",
|
|
@@ -3840,7 +4242,7 @@ var supportDocumentPlacementRule = {
|
|
|
3840
4242
|
root(node) {
|
|
3841
4243
|
const filename = getFilename(context);
|
|
3842
4244
|
if (!filename.endsWith(".md")) return;
|
|
3843
|
-
const parentFolder =
|
|
4245
|
+
const parentFolder = path36.basename(path36.dirname(filename));
|
|
3844
4246
|
if (filename.endsWith("-rule.md") && parentFolder !== "rules") {
|
|
3845
4247
|
context.report({
|
|
3846
4248
|
node,
|
|
@@ -3883,11 +4285,11 @@ var noTemplatePromptRule = {
|
|
|
3883
4285
|
};
|
|
3884
4286
|
|
|
3885
4287
|
// eslint/rules/documentation/guide-folder-entry-point.ts
|
|
3886
|
-
import
|
|
4288
|
+
import path38 from "path";
|
|
3887
4289
|
|
|
3888
4290
|
// eslint/rules/documentation/project-index.ts
|
|
3889
|
-
import { readdirSync as
|
|
3890
|
-
import
|
|
4291
|
+
import { readdirSync as readdirSync3, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
|
|
4292
|
+
import path37 from "path";
|
|
3891
4293
|
var KIND_BY_SUFFIX = [
|
|
3892
4294
|
["-rule.md", "rule"],
|
|
3893
4295
|
["-guide.md", "guide"],
|
|
@@ -3895,16 +4297,16 @@ var KIND_BY_SUFFIX = [
|
|
|
3895
4297
|
["-policy.md", "policy"]
|
|
3896
4298
|
];
|
|
3897
4299
|
function listMarkdownFiles(dir) {
|
|
3898
|
-
return
|
|
3899
|
-
const entryPath =
|
|
3900
|
-
if (
|
|
4300
|
+
return readdirSync3(dir).flatMap((entry) => {
|
|
4301
|
+
const entryPath = path37.join(dir, entry);
|
|
4302
|
+
if (statSync4(entryPath).isDirectory()) {
|
|
3901
4303
|
return entry.startsWith("_") ? [] : listMarkdownFiles(entryPath);
|
|
3902
4304
|
}
|
|
3903
4305
|
return entry.endsWith(".md") ? [entryPath] : [];
|
|
3904
4306
|
});
|
|
3905
4307
|
}
|
|
3906
4308
|
function extractTitle(filePath) {
|
|
3907
|
-
const content =
|
|
4309
|
+
const content = readFileSync5(filePath, "utf8");
|
|
3908
4310
|
const match = /^# (?<title>.+)$/m.exec(content);
|
|
3909
4311
|
return match?.groups?.title?.trim() ?? "";
|
|
3910
4312
|
}
|
|
@@ -3914,11 +4316,11 @@ function getProjectDocs(docsRoot) {
|
|
|
3914
4316
|
if (cached) return cached;
|
|
3915
4317
|
const files = listMarkdownFiles(docsRoot);
|
|
3916
4318
|
const docs = files.sort((a, b) => a.localeCompare(b)).map((filePath) => {
|
|
3917
|
-
const fileName =
|
|
4319
|
+
const fileName = path37.basename(filePath);
|
|
3918
4320
|
const kind = KIND_BY_SUFFIX.find(([suffix]) => fileName.endsWith(suffix))?.[1];
|
|
3919
4321
|
return {
|
|
3920
4322
|
filePath,
|
|
3921
|
-
doc:
|
|
4323
|
+
doc: path37.relative(docsRoot, filePath).split(path37.sep).join("/"),
|
|
3922
4324
|
fileName,
|
|
3923
4325
|
kind,
|
|
3924
4326
|
title: extractTitle(filePath)
|
|
@@ -3928,12 +4330,12 @@ function getProjectDocs(docsRoot) {
|
|
|
3928
4330
|
return docs;
|
|
3929
4331
|
}
|
|
3930
4332
|
function findDocsRoot(filePath) {
|
|
3931
|
-
let dir =
|
|
4333
|
+
let dir = path37.dirname(filePath);
|
|
3932
4334
|
for (; ; ) {
|
|
3933
|
-
if (
|
|
4335
|
+
if (path37.basename(dir) === "docs" && statSync4(dir).isDirectory()) {
|
|
3934
4336
|
return dir;
|
|
3935
4337
|
}
|
|
3936
|
-
const parent =
|
|
4338
|
+
const parent = path37.dirname(dir);
|
|
3937
4339
|
if (parent === dir) return void 0;
|
|
3938
4340
|
dir = parent;
|
|
3939
4341
|
}
|
|
@@ -3957,13 +4359,13 @@ var guideFolderEntryPointRule = {
|
|
|
3957
4359
|
if (!docsRoot) return;
|
|
3958
4360
|
const docs = getProjectDocs(docsRoot);
|
|
3959
4361
|
const guideFolders = new Set(
|
|
3960
|
-
docs.filter((doc) => ["rules", "references"].includes(
|
|
4362
|
+
docs.filter((doc) => ["rules", "references"].includes(path38.basename(path38.dirname(doc.filePath)))).map((doc) => path38.dirname(path38.dirname(doc.filePath))).filter((folder) => path38.resolve(folder) !== path38.resolve(docsRoot))
|
|
3961
4363
|
);
|
|
3962
|
-
const currentDir =
|
|
4364
|
+
const currentDir = path38.dirname(filename);
|
|
3963
4365
|
if (guideFolders.has(currentDir)) {
|
|
3964
|
-
const expectedEntryPoint = `${
|
|
4366
|
+
const expectedEntryPoint = `${path38.basename(currentDir)}.md`;
|
|
3965
4367
|
const hasEntryPoint = docs.some(
|
|
3966
|
-
(doc) => doc.kind === "guide" &&
|
|
4368
|
+
(doc) => doc.kind === "guide" && path38.dirname(doc.filePath) === currentDir && doc.fileName === expectedEntryPoint
|
|
3967
4369
|
);
|
|
3968
4370
|
if (!hasEntryPoint) {
|
|
3969
4371
|
context.report({
|
|
@@ -4187,10 +4589,10 @@ var noNestedHowToRule = {
|
|
|
4187
4589
|
};
|
|
4188
4590
|
|
|
4189
4591
|
// eslint/rules/documentation/glossary-term-linking.ts
|
|
4190
|
-
import { readFileSync as
|
|
4191
|
-
import
|
|
4592
|
+
import { readFileSync as readFileSync6 } from "fs";
|
|
4593
|
+
import path39 from "path";
|
|
4192
4594
|
function extractGlossaryTerms(filePath) {
|
|
4193
|
-
const content =
|
|
4595
|
+
const content = readFileSync6(filePath, "utf8");
|
|
4194
4596
|
const terms = [];
|
|
4195
4597
|
const headingPattern = /^## (?<term>.+)$/gm;
|
|
4196
4598
|
let match;
|
|
@@ -4242,9 +4644,9 @@ var glossaryTermLinkingRule = {
|
|
|
4242
4644
|
const docsRoot = findDocsRoot(filename);
|
|
4243
4645
|
if (!docsRoot) return;
|
|
4244
4646
|
const docs = getProjectDocs(docsRoot);
|
|
4245
|
-
const guideDir =
|
|
4647
|
+
const guideDir = path39.dirname(filename);
|
|
4246
4648
|
const guideReferences = docs.filter(
|
|
4247
|
-
(doc) => doc.kind === "reference" &&
|
|
4649
|
+
(doc) => doc.kind === "reference" && path39.dirname(doc.filePath) === guideDir
|
|
4248
4650
|
);
|
|
4249
4651
|
if (guideReferences.length === 0) return;
|
|
4250
4652
|
const glossaryTerms = [];
|
|
@@ -4269,7 +4671,7 @@ var glossaryTermLinkingRule = {
|
|
|
4269
4671
|
|
|
4270
4672
|
// eslint/rules/documentation/guide-mentions-documents.ts
|
|
4271
4673
|
import { existsSync } from "fs";
|
|
4272
|
-
import
|
|
4674
|
+
import path40 from "path";
|
|
4273
4675
|
function visitSteps3(node, check) {
|
|
4274
4676
|
if (node.type === "list" && node.ordered) {
|
|
4275
4677
|
for (const child of node.children) check(child);
|
|
@@ -4302,12 +4704,12 @@ var guideMentionsDocumentsRule = {
|
|
|
4302
4704
|
if (!filename.endsWith("-guide.md")) return;
|
|
4303
4705
|
const docsRoot = findDocsRoot(filename);
|
|
4304
4706
|
if (!docsRoot) return;
|
|
4305
|
-
const guideDir =
|
|
4306
|
-
if (
|
|
4707
|
+
const guideDir = path40.dirname(filename);
|
|
4708
|
+
if (path40.basename(filename, ".md") !== path40.basename(guideDir)) return;
|
|
4307
4709
|
const docs = getProjectDocs(docsRoot);
|
|
4308
4710
|
const owned = docs.filter((doc) => {
|
|
4309
|
-
const parent =
|
|
4310
|
-
return parent ===
|
|
4711
|
+
const parent = path40.dirname(doc.filePath);
|
|
4712
|
+
return parent === path40.join(guideDir, "rules") || parent === path40.join(guideDir, "references");
|
|
4311
4713
|
});
|
|
4312
4714
|
const allLinks = [];
|
|
4313
4715
|
collectMarkdownLinks(node, allLinks);
|
|
@@ -4334,7 +4736,7 @@ var guideMentionsDocumentsRule = {
|
|
|
4334
4736
|
for (const link of allLinks) {
|
|
4335
4737
|
const target = linkTarget(link.url);
|
|
4336
4738
|
if (!target.endsWith(".md")) continue;
|
|
4337
|
-
const resolved =
|
|
4739
|
+
const resolved = path40.normalize(path40.join(guideDir, target));
|
|
4338
4740
|
if (!existsSync(resolved)) {
|
|
4339
4741
|
context.report({
|
|
4340
4742
|
node: link,
|
|
@@ -4839,6 +5241,83 @@ var globalStylesheetRule = {
|
|
|
4839
5241
|
}
|
|
4840
5242
|
};
|
|
4841
5243
|
|
|
5244
|
+
// eslint/rules/tailwind/unused-utility.ts
|
|
5245
|
+
import { readdirSync as readdirSync4, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
|
|
5246
|
+
import path41 from "path";
|
|
5247
|
+
var SOURCE_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".css"];
|
|
5248
|
+
function sourceFiles(dir) {
|
|
5249
|
+
let entries;
|
|
5250
|
+
try {
|
|
5251
|
+
entries = readdirSync4(dir);
|
|
5252
|
+
} catch {
|
|
5253
|
+
return [];
|
|
5254
|
+
}
|
|
5255
|
+
return entries.flatMap((entry) => {
|
|
5256
|
+
if (entry.startsWith(".") || entry === "node_modules") return [];
|
|
5257
|
+
const entryPath = path41.join(dir, entry);
|
|
5258
|
+
let stats;
|
|
5259
|
+
try {
|
|
5260
|
+
stats = statSync5(entryPath);
|
|
5261
|
+
} catch {
|
|
5262
|
+
return [];
|
|
5263
|
+
}
|
|
5264
|
+
if (stats.isDirectory()) return sourceFiles(entryPath);
|
|
5265
|
+
return SOURCE_EXTENSIONS.includes(path41.extname(entry)) ? [entryPath] : [];
|
|
5266
|
+
});
|
|
5267
|
+
}
|
|
5268
|
+
function usagePattern(name) {
|
|
5269
|
+
const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
5270
|
+
return new RegExp(`(?<![\\w-])${escaped}(?![\\w-])`);
|
|
5271
|
+
}
|
|
5272
|
+
var unusedUtilityRule = {
|
|
5273
|
+
meta: {
|
|
5274
|
+
schema: [],
|
|
5275
|
+
type: "problem",
|
|
5276
|
+
docs: {
|
|
5277
|
+
description: "Require every custom @utility to be referenced by the repository's source."
|
|
5278
|
+
}
|
|
5279
|
+
},
|
|
5280
|
+
create(context) {
|
|
5281
|
+
const sourceRoot2 = path41.resolve("src");
|
|
5282
|
+
let files;
|
|
5283
|
+
try {
|
|
5284
|
+
if (!statSync5(sourceRoot2).isDirectory()) return {};
|
|
5285
|
+
files = sourceFiles(sourceRoot2);
|
|
5286
|
+
} catch {
|
|
5287
|
+
return {};
|
|
5288
|
+
}
|
|
5289
|
+
const texts = /* @__PURE__ */ new Map();
|
|
5290
|
+
const textOf = (file) => {
|
|
5291
|
+
let text = texts.get(file);
|
|
5292
|
+
if (text === void 0) {
|
|
5293
|
+
try {
|
|
5294
|
+
text = readFileSync7(file, "utf8");
|
|
5295
|
+
} catch {
|
|
5296
|
+
text = "";
|
|
5297
|
+
}
|
|
5298
|
+
texts.set(file, text);
|
|
5299
|
+
}
|
|
5300
|
+
return text;
|
|
5301
|
+
};
|
|
5302
|
+
return {
|
|
5303
|
+
"StyleSheet:exit"(node) {
|
|
5304
|
+
for (const utility of atrulesNamed(node, "utility")) {
|
|
5305
|
+
const name = preludeIdentifiers(utility)[0];
|
|
5306
|
+
if (!name) continue;
|
|
5307
|
+
const pattern = usagePattern(name);
|
|
5308
|
+
const definition = `@utility ${name}`;
|
|
5309
|
+
const used = files.some((file) => pattern.test(textOf(file).replaceAll(definition, "")));
|
|
5310
|
+
if (used) continue;
|
|
5311
|
+
context.report({
|
|
5312
|
+
node: utility,
|
|
5313
|
+
message: `Custom utility "${name}" is never used by the repository's source; remove it or use it.`
|
|
5314
|
+
});
|
|
5315
|
+
}
|
|
5316
|
+
}
|
|
5317
|
+
};
|
|
5318
|
+
}
|
|
5319
|
+
};
|
|
5320
|
+
|
|
4842
5321
|
// eslint/rules/tailwind/index.ts
|
|
4843
5322
|
var tailwindRules = {
|
|
4844
5323
|
"theme-reset": themeResetRule,
|
|
@@ -4851,7 +5330,8 @@ var tailwindRules = {
|
|
|
4851
5330
|
"surface-utility": surfaceUtilityRule,
|
|
4852
5331
|
"theme-variable-namespace": themeVariableNamespaceRule,
|
|
4853
5332
|
"global-css-location": globalCssLocationRule,
|
|
4854
|
-
"global-stylesheet": globalStylesheetRule
|
|
5333
|
+
"global-stylesheet": globalStylesheetRule,
|
|
5334
|
+
"unused-utility": unusedUtilityRule
|
|
4855
5335
|
};
|
|
4856
5336
|
|
|
4857
5337
|
// eslint/rules/package-json/exact-version.ts
|
|
@@ -4998,8 +5478,8 @@ var nextPackageJsonRules = {
|
|
|
4998
5478
|
};
|
|
4999
5479
|
|
|
5000
5480
|
// eslint/rules/husky/husky-hook.ts
|
|
5001
|
-
import { existsSync as existsSync2, readFileSync as
|
|
5002
|
-
import
|
|
5481
|
+
import { existsSync as existsSync2, readFileSync as readFileSync8 } from "fs";
|
|
5482
|
+
import path42 from "path";
|
|
5003
5483
|
function memberName4(member) {
|
|
5004
5484
|
return member.name.type === "String" ? member.name.value : member.name.name;
|
|
5005
5485
|
}
|
|
@@ -5018,7 +5498,7 @@ var huskyHookRule = {
|
|
|
5018
5498
|
if (root.type !== "Object") return;
|
|
5019
5499
|
const scriptName = context.filename;
|
|
5020
5500
|
if (!scriptName.endsWith("package.json")) return;
|
|
5021
|
-
const hookPath =
|
|
5501
|
+
const hookPath = path42.join(process.cwd(), ".husky", "pre-commit");
|
|
5022
5502
|
if (!existsSync2(hookPath)) {
|
|
5023
5503
|
context.report({
|
|
5024
5504
|
node,
|
|
@@ -5026,7 +5506,7 @@ var huskyHookRule = {
|
|
|
5026
5506
|
});
|
|
5027
5507
|
return;
|
|
5028
5508
|
}
|
|
5029
|
-
const content =
|
|
5509
|
+
const content = readFileSync8(hookPath, "utf8");
|
|
5030
5510
|
if (!content.includes("lint-staged")) {
|
|
5031
5511
|
context.report({ node, message: ".husky/pre-commit must run lint-staged." });
|
|
5032
5512
|
}
|
|
@@ -5057,8 +5537,8 @@ var huskyRules = {
|
|
|
5057
5537
|
};
|
|
5058
5538
|
|
|
5059
5539
|
// eslint/rules/vulyk/vulyk-docs.ts
|
|
5060
|
-
import { existsSync as existsSync3, readFileSync as
|
|
5061
|
-
import
|
|
5540
|
+
import { existsSync as existsSync3, readFileSync as readFileSync9 } from "fs";
|
|
5541
|
+
import path43 from "path";
|
|
5062
5542
|
var PASIKA_REPO = "Bredansky/pasika";
|
|
5063
5543
|
var vulykDocsRule = {
|
|
5064
5544
|
meta: {
|
|
@@ -5072,8 +5552,8 @@ var vulykDocsRule = {
|
|
|
5072
5552
|
return {
|
|
5073
5553
|
Document(node) {
|
|
5074
5554
|
if (!context.filename.endsWith("package.json")) return;
|
|
5075
|
-
const projectRoot =
|
|
5076
|
-
const configPath =
|
|
5555
|
+
const projectRoot = path43.dirname(path43.resolve(context.filename));
|
|
5556
|
+
const configPath = path43.join(projectRoot, "vulyk.config.ts");
|
|
5077
5557
|
if (!existsSync3(configPath)) {
|
|
5078
5558
|
context.report({
|
|
5079
5559
|
node,
|
|
@@ -5081,14 +5561,14 @@ var vulykDocsRule = {
|
|
|
5081
5561
|
});
|
|
5082
5562
|
return;
|
|
5083
5563
|
}
|
|
5084
|
-
const config =
|
|
5564
|
+
const config = readFileSync9(configPath, "utf8");
|
|
5085
5565
|
if (!config.includes(PASIKA_REPO)) {
|
|
5086
5566
|
context.report({
|
|
5087
5567
|
node,
|
|
5088
5568
|
message: "vulyk.config.ts must track the framework's docs from the pasika repository."
|
|
5089
5569
|
});
|
|
5090
5570
|
}
|
|
5091
|
-
const agentsPath =
|
|
5571
|
+
const agentsPath = path43.join(projectRoot, "AGENTS.md");
|
|
5092
5572
|
if (!existsSync3(agentsPath)) {
|
|
5093
5573
|
context.report({
|
|
5094
5574
|
node,
|
|
@@ -5132,6 +5612,7 @@ var nextjsAppRules = {
|
|
|
5132
5612
|
"ui-state": uiStateRule,
|
|
5133
5613
|
"no-mixed-concerns": noMixedConcernsRule,
|
|
5134
5614
|
"no-arbitrary-tailwind": noArbitraryTailwindRule,
|
|
5615
|
+
"unknown-utility": unknownUtilityRule,
|
|
5135
5616
|
"enforce-cn-merge": enforceCnMergeRule,
|
|
5136
5617
|
"cn-helper": cnHelperRule,
|
|
5137
5618
|
"enforce-cva-variant-props": enforceCvaVariantPropsRule,
|