pasika 0.4.2 → 0.5.0

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.
@@ -2,6 +2,7 @@
2
2
  import css from "@eslint/css";
3
3
  import jsonPlugin from "@eslint/json";
4
4
  import markdown from "@eslint/markdown";
5
+ import tsParser from "@typescript-eslint/parser";
5
6
 
6
7
  // eslint/rules/filename-case.ts
7
8
  import path2 from "path";
@@ -66,11 +67,12 @@ function componentFromVariable(node) {
66
67
  smart: containsSmartCall(initializer)
67
68
  };
68
69
  }
69
- function parseComponentInfo(text, filename) {
70
+ function parseComponentInfo(text, filename, options) {
70
71
  const sourceFile = ts.createSourceFile(path.resolve(filename), text, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
71
72
  const components = [];
72
73
  for (const statement of sourceFile.statements) {
73
- if (!isExported(statement)) continue;
74
+ const exported = isExported(statement);
75
+ if (!exported && !options?.includeNonExported) continue;
74
76
  if (ts.isFunctionDeclaration(statement)) {
75
77
  const component = componentFromFunction(statement);
76
78
  if (component) components.push(component);
@@ -227,33 +229,40 @@ function report(context, filename, ext) {
227
229
  }
228
230
 
229
231
  // eslint/rules/import-boundaries.ts
232
+ import path4 from "path";
233
+
234
+ // eslint/rules/project-root.ts
230
235
  import path3 from "path";
231
- var sourceRoot = path3.resolve("src");
236
+ function sourceRootOf(context) {
237
+ return path3.resolve(context.cwd ?? process.cwd(), "src");
238
+ }
239
+
240
+ // eslint/rules/import-boundaries.ts
232
241
  var rootSupportFolders = /* @__PURE__ */ new Set(["config", "constants", "hooks", "locales", "schemas", "types", "utils"]);
233
242
  var moduleExtensions = /* @__PURE__ */ new Set([".cjs", ".cts", ".js", ".jsx", ".mjs", ".mts", ".ts", ".tsx"]);
234
243
  var styleExtensions = /* @__PURE__ */ new Set([".css", ".less", ".sass", ".scss"]);
235
- function resolveSourceImport(filename, importPath) {
244
+ function resolveSourceImport(sourceRoot, filename, importPath) {
236
245
  if (importPath.startsWith("@/")) {
237
- return path3.resolve(sourceRoot, importPath.slice(2));
246
+ return path4.resolve(sourceRoot, importPath.slice(2));
238
247
  }
239
248
  if (importPath.startsWith(".")) {
240
- return path3.resolve(path3.dirname(filename), importPath);
249
+ return path4.resolve(path4.dirname(filename), importPath);
241
250
  }
242
251
  return void 0;
243
252
  }
244
- function sourceSegments(absolutePath) {
245
- const relativePath = path3.relative(sourceRoot, absolutePath);
246
- if (relativePath.startsWith("..") || path3.isAbsolute(relativePath)) {
253
+ function sourceSegments(sourceRoot, absolutePath) {
254
+ const relativePath = path4.relative(sourceRoot, absolutePath);
255
+ if (relativePath.startsWith("..") || path4.isAbsolute(relativePath)) {
247
256
  return void 0;
248
257
  }
249
- return relativePath.split(path3.sep);
258
+ return relativePath.split(path4.sep);
250
259
  }
251
260
  function relativeSpecifier(filename, resolvedPath) {
252
- const relativePath = path3.relative(path3.dirname(filename), resolvedPath).split(path3.sep).join("/");
261
+ const relativePath = path4.relative(path4.dirname(filename), resolvedPath).split(path4.sep).join("/");
253
262
  return relativePath.startsWith(".") ? relativePath : `./${relativePath}`;
254
263
  }
255
- function aliasSpecifier(resolvedPath) {
256
- return `@/${(sourceSegments(resolvedPath) ?? []).join("/")}`;
264
+ function aliasSpecifier(sourceRoot, resolvedPath) {
265
+ return `@/${(sourceSegments(sourceRoot, resolvedPath) ?? []).join("/")}`;
257
266
  }
258
267
  function segmentCount(specifier) {
259
268
  return specifier.replace(/^@\//, "").split("/").filter((segment) => segment !== "." && segment !== "").length;
@@ -261,8 +270,8 @@ function segmentCount(specifier) {
261
270
  function describeSegments(count) {
262
271
  return `${String(count)} segment${count === 1 ? "" : "s"}`;
263
272
  }
264
- function prefersRelative(filename, resolvedPath) {
265
- return segmentCount(relativeSpecifier(filename, resolvedPath)) <= segmentCount(aliasSpecifier(resolvedPath));
273
+ function prefersRelative(sourceRoot, filename, resolvedPath) {
274
+ return segmentCount(relativeSpecifier(filename, resolvedPath)) <= segmentCount(aliasSpecifier(sourceRoot, resolvedPath));
266
275
  }
267
276
  var importBoundariesRule = {
268
277
  meta: {
@@ -271,6 +280,7 @@ var importBoundariesRule = {
271
280
  },
272
281
  create(context) {
273
282
  const filename = context.filename;
283
+ const sourceRoot = sourceRootOf(context);
274
284
  if (!filename) {
275
285
  return {};
276
286
  }
@@ -279,18 +289,18 @@ var importBoundariesRule = {
279
289
  return;
280
290
  }
281
291
  const importPath = source.value;
282
- const resolvedPath = resolveSourceImport(filename, importPath);
292
+ const resolvedPath = resolveSourceImport(sourceRoot, filename, importPath);
283
293
  if (!resolvedPath) {
284
294
  return;
285
295
  }
286
- const importer = sourceSegments(filename);
287
- const imported = sourceSegments(resolvedPath);
296
+ const importer = sourceSegments(sourceRoot, filename);
297
+ const imported = sourceSegments(sourceRoot, resolvedPath);
288
298
  if (!importer || !imported || importer.length === 0 || imported.length === 0) {
289
299
  return;
290
300
  }
291
301
  const [importerLayer = "", importerFeature] = importer;
292
302
  const [importedLayer = "", importedFeature] = imported;
293
- const extension = path3.extname(importPath);
303
+ const extension = path4.extname(importPath);
294
304
  const isCodeModule = !extension || moduleExtensions.has(extension);
295
305
  const isAppLocalStyleImport = importerLayer === "app" && importedLayer === "app" && styleExtensions.has(extension);
296
306
  const importedIsRootSupport = rootSupportFolders.has(importedLayer);
@@ -304,21 +314,21 @@ var importBoundariesRule = {
304
314
  return;
305
315
  }
306
316
  const relativeForm = relativeSpecifier(filename, resolvedPath);
307
- const aliasForm = aliasSpecifier(resolvedPath);
317
+ const aliasForm = aliasSpecifier(sourceRoot, resolvedPath);
308
318
  const relativeSegments = segmentCount(relativeForm);
309
319
  const aliasSegments = segmentCount(aliasForm);
310
320
  function describeChoice(preferred, preferredSegments, other, otherSegments) {
311
321
  const tie = preferredSegments === otherSegments ? ", and a tie goes to the relative path" : "";
312
322
  return `Use "${preferred}" (${describeSegments(preferredSegments)}) instead of "${other}" (${describeSegments(otherSegments)})${tie}.`;
313
323
  }
314
- if (prefersRelative(filename, resolvedPath) && importPath.startsWith("@/")) {
324
+ if (prefersRelative(sourceRoot, filename, resolvedPath) && importPath.startsWith("@/")) {
315
325
  context.report({
316
326
  node: source,
317
327
  message: describeChoice(relativeForm, relativeSegments, aliasForm, aliasSegments)
318
328
  });
319
329
  return;
320
330
  }
321
- if (!prefersRelative(filename, resolvedPath) && importPath.startsWith(".")) {
331
+ if (!prefersRelative(sourceRoot, filename, resolvedPath) && importPath.startsWith(".")) {
322
332
  context.report({
323
333
  node: source,
324
334
  message: describeChoice(aliasForm, aliasSegments, relativeForm, relativeSegments)
@@ -350,59 +360,26 @@ var importBoundariesRule = {
350
360
  };
351
361
 
352
362
  // 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
363
  var noMixedConcernsRule = {
372
364
  meta: {
373
365
  schema: [],
374
366
  type: "problem",
375
367
  docs: {
376
- description: "Enforce one exported React component per .tsx file."
368
+ description: "Enforce one React component per .tsx file, counting private components."
377
369
  }
378
370
  },
379
371
  create(context) {
380
372
  if (!context.filename.endsWith(".tsx")) return {};
381
- let exportedComponentCount = 0;
382
- const extraExports = [];
383
- function registerExport(name) {
384
- exportedComponentCount++;
385
- if (exportedComponentCount > 1) {
386
- extraExports.push({ name });
387
- }
388
- }
373
+ const sourceCode = context.sourceCode.text;
389
374
  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
375
  "Program:exit"() {
399
- if (exportedComponentCount > 1) {
400
- for (const extra of extraExports) {
401
- context.report({
402
- loc: { line: 1, column: 0 },
403
- message: `File exports multiple components. "${extra.name}" is an extra component export. Move it to its own file. Each .tsx file MUST contain exactly one component. See docs/code-organization-guide/rules/no-mixed-concerns-rule.md`
404
- });
405
- }
376
+ const components = parseComponentInfo(sourceCode, context.filename, { includeNonExported: true });
377
+ if (components.length <= 1) return;
378
+ for (const extra of components.slice(1)) {
379
+ context.report({
380
+ loc: { line: 1, column: 0 },
381
+ 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`
382
+ });
406
383
  }
407
384
  }
408
385
  };
@@ -480,7 +457,7 @@ var noArbitraryTailwindRule = {
480
457
 
481
458
  // eslint/rules/unknown-utility.ts
482
459
  import { readdirSync, readFileSync, statSync } from "fs";
483
- import path4 from "path";
460
+ import path5 from "path";
484
461
  var PREFIX_NAMESPACES = {
485
462
  bg: ["color"],
486
463
  text: ["color", "text"],
@@ -642,7 +619,19 @@ var DEFAULT_TOKENS = {
642
619
  blur: ["none", "xs", "sm", "md", "lg", "xl", "2xl", "3xl"],
643
620
  animate: ["none", "spin", "ping", "pulse", "bounce"],
644
621
  ease: ["linear", "in", "out", "in-out"],
645
- aspect: ["auto", "video", "square"]
622
+ // Note: aspect's auto/square, radius's none/full, leading's none, blur's
623
+ // none, animate's none, and ease's linear are static built-ins covered by
624
+ // STATIC_VALUE_TOKENS; the remainder are theme-derived.
625
+ aspect: ["video"]
626
+ };
627
+ var STATIC_VALUE_TOKENS = {
628
+ aspect: ["auto", "square"],
629
+ radius: ["none", "full"],
630
+ leading: ["none"],
631
+ blur: ["none"],
632
+ animate: ["none"],
633
+ ease: ["linear", "initial"],
634
+ z: ["auto"]
646
635
  };
647
636
  var DEFAULT_PALETTE_FAMILIES = /* @__PURE__ */ new Set([
648
637
  "red",
@@ -670,6 +659,7 @@ var DEFAULT_PALETTE_FAMILIES = /* @__PURE__ */ new Set([
670
659
  ]);
671
660
  var DEFAULT_PALETTE_SHADES = /* @__PURE__ */ new Set(["50", "100", "200", "300", "400", "500", "600", "700", "800", "900", "950"]);
672
661
  var DEFAULT_COLOR_SPECIALS = /* @__PURE__ */ new Set(["white", "black", "transparent", "current", "inherit"]);
662
+ var STATIC_COLOR_SPECIALS = /* @__PURE__ */ new Set(["transparent", "current", "inherit"]);
673
663
  var NUMERIC_TOKEN_RE = /^-?(?:\d+\.?\d*|\.\d+)(?:%|px|rem|em)?$/;
674
664
  var SIDE_WIDTH_TOKEN_RE = /^(?:x|y|t|r|b|l|s|e)-(?:\d+\.?\d*|\.\d+)(?:%|px|rem|em)?$/;
675
665
  var OFFSET_TOKEN_RE = /^offset-(?:\d+\.?\d*|\.\d+)(?:%|px|rem|em)?$/;
@@ -682,7 +672,7 @@ function stylesheetFiles(dir) {
682
672
  }
683
673
  return entries.flatMap((entry) => {
684
674
  if (entry.startsWith(".") || entry === "node_modules") return [];
685
- const entryPath = path4.join(dir, entry);
675
+ const entryPath = path5.join(dir, entry);
686
676
  let stats;
687
677
  try {
688
678
  stats = statSync(entryPath);
@@ -690,7 +680,7 @@ function stylesheetFiles(dir) {
690
680
  return [];
691
681
  }
692
682
  if (stats.isDirectory()) return stylesheetFiles(entryPath);
693
- return path4.extname(entry) === ".css" ? [entryPath] : [];
683
+ return path5.extname(entry) === ".css" ? [entryPath] : [];
694
684
  });
695
685
  }
696
686
  function themeBlocks(css2) {
@@ -711,10 +701,36 @@ function themeBlocks(css2) {
711
701
  }
712
702
  return blocks;
713
703
  }
704
+ function classSelectors(css2) {
705
+ const blocks = [];
706
+ let index = 0;
707
+ while (index < css2.length) {
708
+ const match = /@utility\s*\{/.exec(css2.slice(index));
709
+ if (!match) break;
710
+ const open = index + match.index + match[0].length - 1;
711
+ let depth = 1;
712
+ let cursor = open + 1;
713
+ for (; cursor < css2.length && depth > 0; cursor++) {
714
+ if (css2[cursor] === "{") depth++;
715
+ else if (css2[cursor] === "}") depth--;
716
+ }
717
+ blocks.push(css2.slice(open + 1, cursor - 1));
718
+ index = cursor;
719
+ }
720
+ let selectors = css2;
721
+ for (const block of blocks) selectors = selectors.replace(block, "");
722
+ const names = [];
723
+ for (const match of selectors.matchAll(/\.(?<className>[a-z][a-z0-9_-]*)(?=\s*[.,:#>{]|$)/gi)) {
724
+ const className = match.groups?.className;
725
+ if (className) names.push(className);
726
+ }
727
+ return names;
728
+ }
714
729
  function readInventory(files) {
715
730
  const utilities = /* @__PURE__ */ new Set();
716
731
  const utilityPrefixes = /* @__PURE__ */ new Set();
717
732
  const themeTokensByNamespace = /* @__PURE__ */ new Map();
733
+ const plainClasses = /* @__PURE__ */ new Set();
718
734
  let defaultsReset = false;
719
735
  for (const file of files) {
720
736
  let css2;
@@ -730,6 +746,7 @@ function readInventory(files) {
730
746
  const dash = utilityName.indexOf("-");
731
747
  if (dash > 0) utilityPrefixes.add(utilityName.slice(0, dash));
732
748
  }
749
+ for (const plainClass of classSelectors(css2)) plainClasses.add(plainClass);
733
750
  for (const block of themeBlocks(css2)) {
734
751
  if (/--\*\s*:\s*initial\b/.test(block)) defaultsReset = true;
735
752
  for (const decl of block.matchAll(/--(?<namespace>[a-z][a-z0-9]*)-(?<token>[a-z0-9][a-z0-9_-]*)\s*:/g)) {
@@ -745,10 +762,11 @@ function readInventory(files) {
745
762
  }
746
763
  }
747
764
  }
748
- return { utilities, utilityPrefixes, themeTokens: themeTokensByNamespace, defaultsReset };
765
+ return { utilities, utilityPrefixes, themeTokens: themeTokensByNamespace, defaultsReset, plainClasses };
749
766
  }
750
767
  function isColorToken(token, inventory) {
751
768
  if (inventory.themeTokens.get("color")?.has(token)) return true;
769
+ if (STATIC_COLOR_SPECIALS.has(token)) return true;
752
770
  if (inventory.defaultsReset) return false;
753
771
  if (DEFAULT_COLOR_SPECIALS.has(token)) return true;
754
772
  const hyphen = token.lastIndexOf("-");
@@ -770,6 +788,7 @@ function isKnown(className, inventory) {
770
788
  if (inventory.utilities.has(utility)) return true;
771
789
  const namespaces = PREFIX_NAMESPACES[prefix];
772
790
  if (!namespaces) {
791
+ if (STATIC_VALUE_TOKENS[prefix]?.includes(token)) return true;
773
792
  const projectTokens = inventory.themeTokens.get(prefix);
774
793
  if (projectTokens) {
775
794
  if (projectTokens.has(token)) return true;
@@ -786,6 +805,7 @@ function isKnown(className, inventory) {
786
805
  continue;
787
806
  }
788
807
  if (inventory.themeTokens.get(namespace)?.has(token)) return true;
808
+ if (STATIC_VALUE_TOKENS[namespace]?.includes(token)) return true;
789
809
  if (!inventory.defaultsReset && DEFAULT_TOKENS[namespace]?.includes(token)) return true;
790
810
  }
791
811
  return false;
@@ -800,11 +820,11 @@ var unknownUtilityRule = {
800
820
  }
801
821
  },
802
822
  create(context) {
803
- const sourceRoot2 = path4.resolve("src");
823
+ const sourceRoot = sourceRootOf(context);
804
824
  let inventory;
805
825
  try {
806
- if (!statSync(sourceRoot2).isDirectory()) return {};
807
- inventory = readInventory(stylesheetFiles(sourceRoot2));
826
+ if (!statSync(sourceRoot).isDirectory()) return {};
827
+ inventory = readInventory(stylesheetFiles(sourceRoot));
808
828
  } catch {
809
829
  return {};
810
830
  }
@@ -813,12 +833,19 @@ var unknownUtilityRule = {
813
833
  for (const candidate of value.split(/\s+/)) {
814
834
  if (!candidate || seen.has(candidate)) continue;
815
835
  seen.add(candidate);
816
- if (!isKnown(candidate, inventory)) {
836
+ if (isKnown(candidate, inventory)) continue;
837
+ const plainBase = candidate.replace(/!+$/, "").split(":").pop() ?? "";
838
+ if (inventory.plainClasses.has(plainBase)) {
817
839
  context.report({
818
840
  node,
819
- message: `Utility class "${candidate}" is not a custom @utility, a theme-generated utility, or a built-in Tailwind utility.`
841
+ message: `Utility class "${candidate}" is defined as a plain CSS selector in a stylesheet, not as an @utility (or @theme variable). Define it with @utility so the framework can own and validate it.`
820
842
  });
843
+ continue;
821
844
  }
845
+ context.report({
846
+ node,
847
+ message: `Utility class "${candidate}" is not a custom @utility, a theme-generated utility, or a built-in Tailwind utility.`
848
+ });
822
849
  }
823
850
  }
824
851
  function checkExpression(node, expression) {
@@ -885,7 +912,9 @@ function isOuterLayoutClass(className) {
885
912
  function stringArguments(node) {
886
913
  if (node?.type === "Literal" && typeof node.value === "string") return [node.value];
887
914
  if (node?.type === "TemplateLiteral") return node.quasis.map((quasi) => quasi.value.raw);
888
- if (node?.type === "ConditionalExpression") return [...stringArguments(node.consequent), ...stringArguments(node.alternate)];
915
+ if (node?.type === "ConditionalExpression") {
916
+ return [...stringArguments(node.consequent), ...stringArguments(node.alternate)];
917
+ }
889
918
  if (node?.type === "LogicalExpression") return [...stringArguments(node.left), ...stringArguments(node.right)];
890
919
  if (node?.type === "CallExpression" && node.callee.type === "Identifier" && node.callee.name === "cn") {
891
920
  return node.arguments.flatMap((argument) => stringArguments(argument));
@@ -901,7 +930,10 @@ var enforceCnMergeRule = {
901
930
  const element = node.parent.parent;
902
931
  const isComponentProp = isComponentName(element.openingElement?.name);
903
932
  if (isComponentProp && attributeName !== "className" && attributeName.endsWith("ClassName")) {
904
- context.report({ node, message: "Expose appearance through typed variant props instead of separate internal class-name props. See docs/styling-guide/rules/class-composition-rule.md" });
933
+ context.report({
934
+ node,
935
+ message: "Expose appearance through typed variant props instead of separate internal class-name props. See docs/styling-guide/rules/class-composition-rule.md"
936
+ });
905
937
  return;
906
938
  }
907
939
  if (attributeName !== "className" && attributeName !== "class") return;
@@ -910,31 +942,60 @@ var enforceCnMergeRule = {
910
942
  if (isComponentProp && attributeName === "className") {
911
943
  const expression = valueNode.type === "JSXExpressionContainer" ? valueNode.expression : valueNode;
912
944
  const invalidClass = stringArguments(expression).flatMap((value) => value.split(/\s+/).filter(Boolean)).find((className) => !isOuterLayoutClass(className));
913
- if (invalidClass) context.report({ node, message: `Passed className contains non-layout utility "${invalidClass}". Expose appearance through typed variant props. See docs/styling-guide/rules/class-composition-rule.md` });
945
+ if (invalidClass) {
946
+ context.report({
947
+ node,
948
+ message: `Passed className contains non-layout utility "${invalidClass}". Expose appearance through typed variant props. See docs/styling-guide/rules/class-composition-rule.md`
949
+ });
950
+ }
914
951
  return;
915
952
  }
916
953
  if (valueNode.type === "Literal" && typeof valueNode.value === "string") {
917
- if (classCount(valueNode.value) > 5) context.report({ node, message: "Static className with more than 5 classes must use cn() with grouped string literals. See docs/styling-guide/rules/class-composition-rule.md" });
954
+ if (classCount(valueNode.value) > 5) {
955
+ context.report({
956
+ node,
957
+ message: "Static className with more than 5 classes must use cn() with grouped string literals. See docs/styling-guide/rules/class-composition-rule.md"
958
+ });
959
+ }
918
960
  return;
919
961
  }
920
962
  if (valueNode.type !== "JSXExpressionContainer") return;
921
963
  const expr = valueNode.expression;
922
964
  if (expr.type === "BinaryExpression" && expr.operator === "+") {
923
- context.report({ node, message: "Use cn() instead of + operator for className. See docs/styling-guide/rules/class-composition-rule.md" });
965
+ context.report({
966
+ node,
967
+ message: "Use cn() instead of + operator for className. See docs/styling-guide/rules/class-composition-rule.md"
968
+ });
924
969
  return;
925
970
  }
926
971
  if (expr.type === "TemplateLiteral" && expr.expressions.length > 0) {
927
- context.report({ node, message: "Use cn() instead of template literals with conditionals for className. See docs/styling-guide/rules/class-composition-rule.md" });
972
+ context.report({
973
+ node,
974
+ message: "Use cn() instead of template literals with conditionals for className. See docs/styling-guide/rules/class-composition-rule.md"
975
+ });
976
+ return;
977
+ }
978
+ if (expr.type === "LogicalExpression" || expr.type === "ConditionalExpression") {
979
+ context.report({
980
+ node,
981
+ message: "Use cn() for conditional classes in className. See docs/styling-guide/rules/class-composition-rule.md"
982
+ });
928
983
  return;
929
984
  }
930
985
  if (expr.type === "Literal" && typeof expr.value === "string" && classCount(expr.value) > 5) {
931
- context.report({ node, message: "Static className with more than 5 classes must use cn() with grouped string literals. See docs/styling-guide/rules/class-composition-rule.md" });
986
+ context.report({
987
+ node,
988
+ message: "Static className with more than 5 classes must use cn() with grouped string literals. See docs/styling-guide/rules/class-composition-rule.md"
989
+ });
932
990
  return;
933
991
  }
934
992
  if (expr.type === "CallExpression" && expr.callee.type === "Identifier" && expr.callee.name === "cn") {
935
993
  for (const arg of expr.arguments) {
936
994
  if (arg.type === "Literal" && typeof arg.value === "string" && classCount(arg.value) > 5) {
937
- context.report({ node: arg, 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" });
995
+ context.report({
996
+ node: arg,
997
+ 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"
998
+ });
938
999
  }
939
1000
  }
940
1001
  }
@@ -1044,7 +1105,7 @@ var enforceCvaVariantPropsRule = {
1044
1105
  };
1045
1106
 
1046
1107
  // eslint/rules/enforce-barrel-exports.ts
1047
- import path5 from "path";
1108
+ import path6 from "path";
1048
1109
  import fs from "fs";
1049
1110
  function isPascalCase3(str) {
1050
1111
  return /^[A-Z][A-Za-z0-9]*$/.test(str);
@@ -1064,14 +1125,14 @@ var enforceBarrelExportsRule = {
1064
1125
  create(context) {
1065
1126
  const filename = context.filename;
1066
1127
  if (!filename) return {};
1067
- const baseName = path5.basename(filename);
1128
+ const baseName = path6.basename(filename);
1068
1129
  if (baseName !== "index.ts" && baseName !== "index.cts" && baseName !== "index.mts") return {};
1069
- const dirPath = path5.dirname(filename);
1070
- const folderName = path5.basename(dirPath);
1071
- const parentFolderName = path5.basename(path5.dirname(dirPath));
1130
+ const dirPath = path6.dirname(filename);
1131
+ const folderName = path6.basename(dirPath);
1132
+ const parentFolderName = path6.basename(path6.dirname(dirPath));
1072
1133
  if (SUPPORT_FOLDERS.has(folderName)) return {};
1073
1134
  if (!isPascalCase3(folderName) && !isKebabCase2(folderName)) return {};
1074
- const matchingTsx = fs.existsSync(path5.join(dirPath, `${folderName}.tsx`)) ? folderName : null;
1135
+ const matchingTsx = fs.existsSync(path6.join(dirPath, `${folderName}.tsx`)) ? folderName : null;
1075
1136
  if (!matchingTsx) return {};
1076
1137
  if (!isPascalCase3(parentFolderName) && !isKebabCase2(parentFolderName)) return {};
1077
1138
  const reExportedNames = /* @__PURE__ */ new Set();
@@ -1106,14 +1167,14 @@ var enforceBarrelExportsRule = {
1106
1167
  };
1107
1168
 
1108
1169
  // eslint/rules/component-placement.ts
1109
- import path9 from "path";
1170
+ import path10 from "path";
1110
1171
 
1111
1172
  // eslint/project/index.ts
1112
1173
  import { readdirSync as readdirSync2, statSync as statSync2 } from "fs";
1113
- import path7 from "path";
1174
+ import path8 from "path";
1114
1175
 
1115
1176
  // eslint/project/parse-module.ts
1116
- import path6 from "path";
1177
+ import path7 from "path";
1117
1178
  import { readFileSync as readFileSync2 } from "fs";
1118
1179
  import ts2 from "typescript";
1119
1180
  var isPascalCase4 = (name) => /^[A-Z][A-Za-z0-9]*$/.test(name);
@@ -1214,7 +1275,7 @@ function parseModule(file) {
1214
1275
  exports.push({ name: statement.name.text, kind: "type", line: lineOf(sourceFile, statement) });
1215
1276
  }
1216
1277
  }
1217
- return { file: path6.resolve(file), imports, exports };
1278
+ return { file: path7.resolve(file), imports, exports };
1218
1279
  }
1219
1280
 
1220
1281
  // eslint/project/index.ts
@@ -1231,7 +1292,7 @@ function listSourceFiles(dir) {
1231
1292
  }
1232
1293
  return entries.flatMap((entry) => {
1233
1294
  if (entry.startsWith(".") || entry === "node_modules") return [];
1234
- const entryPath = path7.join(dir, entry);
1295
+ const entryPath = path8.join(dir, entry);
1235
1296
  let stats;
1236
1297
  try {
1237
1298
  stats = statSync2(entryPath);
@@ -1239,7 +1300,7 @@ function listSourceFiles(dir) {
1239
1300
  return [];
1240
1301
  }
1241
1302
  if (stats.isDirectory()) return listSourceFiles(entryPath);
1242
- return MODULE_EXTENSIONS.includes(path7.extname(entry)) ? [entryPath] : [];
1303
+ return MODULE_EXTENSIONS.includes(path8.extname(entry)) ? [entryPath] : [];
1243
1304
  });
1244
1305
  }
1245
1306
  function fingerprint(files) {
@@ -1252,19 +1313,19 @@ function fingerprint(files) {
1252
1313
  }
1253
1314
  return `${String(files.length)}:${String(total)}`;
1254
1315
  }
1255
- function resolveSpecifier(fromFile, specifier, sourceRoot2) {
1316
+ function resolveSpecifier(fromFile, specifier, sourceRoot) {
1256
1317
  let base;
1257
1318
  if (specifier.startsWith("@/")) {
1258
- base = path7.resolve(sourceRoot2, specifier.slice(2));
1319
+ base = path8.resolve(sourceRoot, specifier.slice(2));
1259
1320
  } else if (specifier.startsWith(".")) {
1260
- base = path7.resolve(path7.dirname(fromFile), specifier);
1321
+ base = path8.resolve(path8.dirname(fromFile), specifier);
1261
1322
  } else {
1262
1323
  return void 0;
1263
1324
  }
1264
1325
  const candidates = [
1265
1326
  base,
1266
1327
  ...MODULE_EXTENSIONS.map((extension) => `${base}${extension}`),
1267
- ...INDEX_BASENAMES.map((name) => path7.join(base, name))
1328
+ ...INDEX_BASENAMES.map((name) => path8.join(base, name))
1268
1329
  ];
1269
1330
  for (const candidate of candidates) {
1270
1331
  try {
@@ -1274,7 +1335,7 @@ function resolveSpecifier(fromFile, specifier, sourceRoot2) {
1274
1335
  }
1275
1336
  return void 0;
1276
1337
  }
1277
- function build(sourceRoot2, files) {
1338
+ function build(sourceRoot, files) {
1278
1339
  const modules = /* @__PURE__ */ new Map();
1279
1340
  const consumers = /* @__PURE__ */ new Map();
1280
1341
  const symbolConsumers = /* @__PURE__ */ new Map();
@@ -1286,7 +1347,7 @@ function build(sourceRoot2, files) {
1286
1347
  }
1287
1348
  for (const [file, module] of modules) {
1288
1349
  for (const moduleImport of module.imports) {
1289
- const target = resolveSpecifier(file, moduleImport.specifier, sourceRoot2);
1350
+ const target = resolveSpecifier(file, moduleImport.specifier, sourceRoot);
1290
1351
  if (!target || !modules.has(target)) continue;
1291
1352
  const fileConsumers = consumers.get(target) ?? /* @__PURE__ */ new Set();
1292
1353
  fileConsumers.add(file);
@@ -1299,39 +1360,39 @@ function build(sourceRoot2, files) {
1299
1360
  }
1300
1361
  }
1301
1362
  }
1302
- return { sourceRoot: sourceRoot2, modules, consumers, symbolConsumers };
1363
+ return { sourceRoot, modules, consumers, symbolConsumers };
1303
1364
  }
1304
1365
  var cache;
1305
- function getProjectIndex(sourceRoot2) {
1366
+ function getProjectIndex(sourceRoot) {
1306
1367
  const now = Date.now();
1307
- if (cache?.index.sourceRoot === sourceRoot2 && now - cache.checkedAt < REVALIDATE_AFTER_MS) {
1368
+ if (cache?.index.sourceRoot === sourceRoot && now - cache.checkedAt < REVALIDATE_AFTER_MS) {
1308
1369
  return cache.index;
1309
1370
  }
1310
1371
  try {
1311
- if (!statSync2(sourceRoot2).isDirectory()) return void 0;
1372
+ if (!statSync2(sourceRoot).isDirectory()) return void 0;
1312
1373
  } catch {
1313
1374
  return void 0;
1314
1375
  }
1315
- const files = listSourceFiles(sourceRoot2).sort((left, right) => left.localeCompare(right));
1376
+ const files = listSourceFiles(sourceRoot).sort((left, right) => left.localeCompare(right));
1316
1377
  const currentFingerprint = fingerprint(files);
1317
- if (cache?.index.sourceRoot === sourceRoot2 && cache.fingerprint === currentFingerprint) {
1378
+ if (cache?.index.sourceRoot === sourceRoot && cache.fingerprint === currentFingerprint) {
1318
1379
  cache.checkedAt = now;
1319
1380
  return cache.index;
1320
1381
  }
1321
- const index = build(sourceRoot2, files);
1382
+ const index = build(sourceRoot, files);
1322
1383
  cache = { index, checkedAt: now, fingerprint: currentFingerprint };
1323
1384
  return index;
1324
1385
  }
1325
1386
 
1326
1387
  // eslint/project/ccf.ts
1327
- import path8 from "path";
1388
+ import path9 from "path";
1328
1389
  var SUPPORT_FOLDERS2 = /* @__PURE__ */ new Set(["hooks", "types", "schemas", "constants", "utils"]);
1329
- function segmentsOf(file, sourceRoot2) {
1330
- const relative = path8.relative(sourceRoot2, file);
1331
- return relative.startsWith("..") ? [] : relative.split(path8.sep);
1390
+ function segmentsOf(file, sourceRoot) {
1391
+ const relative = path9.relative(sourceRoot, file);
1392
+ return relative.startsWith("..") ? [] : relative.split(path9.sep);
1332
1393
  }
1333
- function folderSegmentsOf(file, sourceRoot2) {
1334
- return segmentsOf(file, sourceRoot2).slice(0, -1);
1394
+ function folderSegmentsOf(file, sourceRoot) {
1395
+ return segmentsOf(file, sourceRoot).slice(0, -1);
1335
1396
  }
1336
1397
  var isUnderApp = (segments) => segments[0] === "app";
1337
1398
  var isConfigModule = (segments) => segments[0] === "config";
@@ -1374,8 +1435,8 @@ function resolveComponentPlacement(componentFile, index) {
1374
1435
  return { countedConsumers: counted, expectedFolder: shared, reason: "ccf" };
1375
1436
  }
1376
1437
  var formatFolder = (folder) => `src/${folder.join("/")}/`;
1377
- function owningFolderOf(consumer, sourceRoot2) {
1378
- return outOfSupportFolders(folderSegmentsOf(consumer, sourceRoot2));
1438
+ function owningFolderOf(consumer, sourceRoot) {
1439
+ return outOfSupportFolders(folderSegmentsOf(consumer, sourceRoot));
1379
1440
  }
1380
1441
  var configModuleOf = (segments) => isConfigModule(segments) && segments.length >= 3 ? segments[1] : void 0;
1381
1442
  function resolveSupportPlacement(supportFile, supportFolder, index) {
@@ -1405,9 +1466,9 @@ function resolveSupportPlacement(supportFile, supportFolder, index) {
1405
1466
  }
1406
1467
  return { countedConsumers: consumers, expectedFolder: [...shared, supportFolder], reason: "ccf" };
1407
1468
  }
1408
- function describeConsumers(consumers, sourceRoot2) {
1469
+ function describeConsumers(consumers, sourceRoot) {
1409
1470
  const shown = 3;
1410
- const names = consumers.map((consumer) => path8.relative(path8.dirname(sourceRoot2), consumer).split(path8.sep).join("/")).sort((left, right) => left.localeCompare(right));
1471
+ const names = consumers.map((consumer) => path9.relative(path9.dirname(sourceRoot), consumer).split(path9.sep).join("/")).sort((left, right) => left.localeCompare(right));
1411
1472
  if (names.length <= shown) return names.join(", ");
1412
1473
  return `${names.slice(0, shown).join(", ")} and ${String(names.length - shown)} more`;
1413
1474
  }
@@ -1430,16 +1491,16 @@ var componentPlacementRule = {
1430
1491
  create(context) {
1431
1492
  const filename = context.filename;
1432
1493
  if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
1433
- const sourceRoot2 = path9.resolve("src");
1434
- const index = getProjectIndex(sourceRoot2);
1494
+ const sourceRoot = sourceRootOf(context);
1495
+ const index = getProjectIndex(sourceRoot);
1435
1496
  if (!index) return {};
1436
- const componentFile = path9.resolve(filename);
1437
- const segments = segmentsOf(componentFile, sourceRoot2);
1497
+ const componentFile = path10.resolve(filename);
1498
+ const segments = segmentsOf(componentFile, sourceRoot);
1438
1499
  if (segments.length === 0) return {};
1439
1500
  if (isUnderApp(segments) || isConfigModule(segments)) return {};
1440
1501
  const module = index.modules.get(componentFile);
1441
1502
  if (!module?.exports.some((moduleExport) => moduleExport.kind === "component")) return {};
1442
- const currentFolder = folderSegmentsOf(componentFile, sourceRoot2);
1503
+ const currentFolder = folderSegmentsOf(componentFile, sourceRoot);
1443
1504
  const placement = resolveComponentPlacement(componentFile, index);
1444
1505
  return {
1445
1506
  Program(node) {
@@ -1458,7 +1519,7 @@ var componentPlacementRule = {
1458
1519
  context.report({
1459
1520
  node,
1460
1521
  loc: { line: 1, column: 0 },
1461
- message: `Move this component to ${formatFolder(placement.expectedFolder)} \u2014 ${explanation}. Imported by ${describeConsumers(placement.countedConsumers, sourceRoot2)}. See docs/code-organization-guide/rules/component-placement-rule.md`
1522
+ message: `Move this component to ${formatFolder(placement.expectedFolder)} \u2014 ${explanation}. Imported by ${describeConsumers(placement.countedConsumers, sourceRoot)}. See docs/code-organization-guide/rules/component-placement-rule.md`
1462
1523
  });
1463
1524
  }
1464
1525
  };
@@ -1466,7 +1527,7 @@ var componentPlacementRule = {
1466
1527
  };
1467
1528
 
1468
1529
  // eslint/rules/support-file-placement.ts
1469
- import path10 from "path";
1530
+ import path11 from "path";
1470
1531
  var CONFIG_OWNED_FOLDERS = /* @__PURE__ */ new Set(["types", "constants"]);
1471
1532
  var REASON_TEXT2 = {
1472
1533
  "app-consumer": "a file under src/app/ imports it, so it belongs to the app-wide support folder",
@@ -1485,16 +1546,16 @@ var supportFilePlacementRule = {
1485
1546
  }
1486
1547
  },
1487
1548
  create(context) {
1488
- const sourceRoot2 = path10.resolve("src");
1489
- const supportFile = path10.resolve(context.filename);
1490
- const currentFolder = folderSegmentsOf(supportFile, sourceRoot2);
1549
+ const sourceRoot = sourceRootOf(context);
1550
+ const supportFile = path11.resolve(context.filename);
1551
+ const currentFolder = folderSegmentsOf(supportFile, sourceRoot);
1491
1552
  const supportFolder = currentFolder[currentFolder.length - 1];
1492
1553
  if (supportFolder === void 0 || !SUPPORT_FOLDERS2.has(supportFolder)) return {};
1493
- const index = getProjectIndex(sourceRoot2);
1554
+ const index = getProjectIndex(sourceRoot);
1494
1555
  if (!index) return {};
1495
1556
  const placement = resolveSupportPlacement(supportFile, supportFolder, index);
1496
1557
  if (!placement || sameFolder2(currentFolder, placement.expectedFolder)) return {};
1497
- if (isConfigModule(segmentsOf(supportFile, sourceRoot2)) && CONFIG_OWNED_FOLDERS.has(supportFolder)) {
1558
+ if (isConfigModule(segmentsOf(supportFile, sourceRoot)) && CONFIG_OWNED_FOLDERS.has(supportFolder)) {
1498
1559
  if (placement.reason !== "config-module") return {};
1499
1560
  }
1500
1561
  return {
@@ -1502,7 +1563,7 @@ var supportFilePlacementRule = {
1502
1563
  context.report({
1503
1564
  node,
1504
1565
  loc: { line: 1, column: 0 },
1505
- message: `Move this file to ${formatFolder(placement.expectedFolder)} \u2014 ${REASON_TEXT2[placement.reason] ?? "that is where its consumers place it"}. Imported by ${describeConsumers(placement.countedConsumers, sourceRoot2)}.`
1566
+ message: `Move this file to ${formatFolder(placement.expectedFolder)} \u2014 ${REASON_TEXT2[placement.reason] ?? "that is where its consumers place it"}. Imported by ${describeConsumers(placement.countedConsumers, sourceRoot)}.`
1506
1567
  });
1507
1568
  }
1508
1569
  };
@@ -1511,7 +1572,7 @@ var supportFilePlacementRule = {
1511
1572
 
1512
1573
  // eslint/rules/application-structure.ts
1513
1574
  import fs2 from "fs";
1514
- import path11 from "path";
1575
+ import path12 from "path";
1515
1576
  var MODULE_EXTENSIONS2 = /* @__PURE__ */ new Set([".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"]);
1516
1577
  var ROUTING_FILES = /* @__PURE__ */ new Set([
1517
1578
  "default",
@@ -1540,7 +1601,7 @@ function report2(context, message) {
1540
1601
  };
1541
1602
  }
1542
1603
  function isCodeFile(filename) {
1543
- return MODULE_EXTENSIONS2.has(path11.extname(filename));
1604
+ return MODULE_EXTENSIONS2.has(path12.extname(filename));
1544
1605
  }
1545
1606
  function isRootSupportFolder(folder) {
1546
1607
  return SUPPORT_FOLDERS2.has(folder);
@@ -1558,28 +1619,28 @@ function expectedSupportFolder(kinds) {
1558
1619
  }
1559
1620
  return void 0;
1560
1621
  }
1561
- function configModuleRoot(filename, sourceRoot2) {
1562
- const segments = segmentsOf(filename, sourceRoot2);
1622
+ function configModuleRoot(filename, sourceRoot) {
1623
+ const segments = segmentsOf(filename, sourceRoot);
1563
1624
  if (segments[0] !== "config" || segments.length < 3) return void 0;
1564
- return path11.join(sourceRoot2, "config", segments[1] ?? "");
1625
+ return path12.join(sourceRoot, "config", segments[1] ?? "");
1565
1626
  }
1566
1627
  function componentFolderStart(segments) {
1567
1628
  if (segments[0] === "features") return 2;
1568
1629
  if (segments[0] === "compositions" || segments[0] === "shared") return 1;
1569
1630
  return -1;
1570
1631
  }
1571
- function componentFolderViolation(segments, sourceRoot2) {
1632
+ function componentFolderViolation(segments, sourceRoot) {
1572
1633
  const start = componentFolderStart(segments);
1573
1634
  if (start < 0) return void 0;
1574
1635
  for (let depth = segments.length - 2; depth >= start; depth -= 1) {
1575
1636
  const folder = segments[depth];
1576
1637
  if (!folder || SUPPORT_FOLDERS2.has(folder)) continue;
1577
- const folderPath = path11.join(sourceRoot2, ...segments.slice(0, depth + 1));
1638
+ const folderPath = path12.join(sourceRoot, ...segments.slice(0, depth + 1));
1578
1639
  const label = `src/${segments.slice(0, depth + 1).join("/")}/`;
1579
- if (!fs2.existsSync(path11.join(folderPath, `${folder}.tsx`))) {
1640
+ if (!fs2.existsSync(path12.join(folderPath, `${folder}.tsx`))) {
1580
1641
  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.`;
1581
1642
  }
1582
- if (!fs2.existsSync(path11.join(folderPath, "index.ts"))) {
1643
+ if (!fs2.existsSync(path12.join(folderPath, "index.ts"))) {
1583
1644
  return `A component folder must have an index.ts that named-re-exports its component; add index.ts to ${label}.`;
1584
1645
  }
1585
1646
  }
@@ -1594,9 +1655,9 @@ var applicationStructureRule = {
1594
1655
  }
1595
1656
  },
1596
1657
  create(context) {
1597
- const filename = path11.resolve(context.filename);
1598
- const sourceRoot2 = path11.resolve("src");
1599
- const segments = segmentsOf(filename, sourceRoot2);
1658
+ const filename = path12.resolve(context.filename);
1659
+ const sourceRoot = sourceRootOf(context);
1660
+ const segments = segmentsOf(filename, sourceRoot);
1600
1661
  if (segments.length === 0) return {};
1601
1662
  const [topLevel, secondLevel] = segments;
1602
1663
  if (topLevel === void 0) return {};
@@ -1624,43 +1685,43 @@ var applicationStructureRule = {
1624
1685
  "A configuration module must be a src/config/<config-name>/ folder with index.ts as its entry point."
1625
1686
  );
1626
1687
  }
1627
- const moduleRoot = configModuleRoot(filename, sourceRoot2);
1628
- if (moduleRoot && !fs2.existsSync(path11.join(moduleRoot, "index.ts"))) {
1688
+ const moduleRoot = configModuleRoot(filename, sourceRoot);
1689
+ if (moduleRoot && !fs2.existsSync(path12.join(moduleRoot, "index.ts"))) {
1629
1690
  return report2(
1630
1691
  context,
1631
- `Add src/config/${path11.basename(moduleRoot)}/index.ts as the configuration module entry point.`
1692
+ `Add src/config/${path12.basename(moduleRoot)}/index.ts as the configuration module entry point.`
1632
1693
  );
1633
1694
  }
1634
- if (moduleRoot && segments.length === 3 && path11.basename(filename) !== "index.ts") {
1695
+ if (moduleRoot && segments.length === 3 && path12.basename(filename) !== "index.ts") {
1635
1696
  const kinds2 = exportedKinds(filename);
1636
1697
  const expected2 = expectedSupportFolder(kinds2);
1637
1698
  if (expected2 !== void 0) {
1638
1699
  return report2(
1639
1700
  context,
1640
- `Move this configuration support file into src/config/${path11.basename(moduleRoot)}/${expected2}/.`
1701
+ `Move this configuration support file into src/config/${path12.basename(moduleRoot)}/${expected2}/.`
1641
1702
  );
1642
1703
  }
1643
1704
  }
1644
1705
  }
1645
1706
  if (topLevel === "app" && isCodeFile(filename)) {
1646
- const basename = path11.basename(filename, path11.extname(filename));
1647
- const currentFolder2 = path11.basename(path11.dirname(filename));
1707
+ const basename = path12.basename(filename, path12.extname(filename));
1708
+ const currentFolder2 = path12.basename(path12.dirname(filename));
1648
1709
  if (SUPPORT_FOLDERS2.has(currentFolder2)) {
1649
1710
  return report2(
1650
1711
  context,
1651
1712
  "src/app/ may contain routing files and framework assets, but ordinary components and support files must live outside src/app/."
1652
1713
  );
1653
1714
  }
1654
- if (!ROUTING_FILES.has(basename) && path11.extname(filename) !== ".css") {
1715
+ if (!ROUTING_FILES.has(basename) && path12.extname(filename) !== ".css") {
1655
1716
  return report2(
1656
1717
  context,
1657
1718
  "src/app/ may contain routing files and framework assets, but ordinary components and support files must live outside src/app/."
1658
1719
  );
1659
1720
  }
1660
1721
  }
1661
- const currentFolder = path11.basename(path11.dirname(filename));
1722
+ const currentFolder = path12.basename(path12.dirname(filename));
1662
1723
  const kinds = exportedKinds(filename);
1663
- const isConfigModuleRoot = topLevel === "config" && segments.length === 3 && path11.basename(filename) === "index.ts";
1724
+ const isConfigModuleRoot = topLevel === "config" && segments.length === 3 && path12.basename(filename) === "index.ts";
1664
1725
  if (isConfigModuleRoot) return {};
1665
1726
  if (!SUPPORT_FOLDERS2.has(currentFolder)) {
1666
1727
  const expected2 = expectedSupportFolder(kinds);
@@ -1670,14 +1731,14 @@ var applicationStructureRule = {
1670
1731
  `Move this file to a ${expected2}/ folder; ${currentFolder}/ is not a recognized support folder.`
1671
1732
  );
1672
1733
  }
1673
- const violation2 = componentFolderViolation(segments, sourceRoot2);
1734
+ const violation2 = componentFolderViolation(segments, sourceRoot);
1674
1735
  if (violation2 !== void 0) return report2(context, violation2);
1675
1736
  return {};
1676
1737
  }
1677
1738
  if (kinds.has("component")) {
1678
1739
  return report2(
1679
1740
  context,
1680
- `A support folder must not contain a component; move ${path11.basename(filename)} beside ${currentFolder}/.`
1741
+ `A support folder must not contain a component; move ${path12.basename(filename)} beside ${currentFolder}/.`
1681
1742
  );
1682
1743
  }
1683
1744
  const expected = expectedSupportFolder(kinds);
@@ -1687,14 +1748,14 @@ var applicationStructureRule = {
1687
1748
  `Move this file to a ${expected}/ folder; ${currentFolder}/ is reserved for ${expected === "utils" ? "utilities" : expected}.`
1688
1749
  );
1689
1750
  }
1690
- const violation = componentFolderViolation(segments, sourceRoot2);
1751
+ const violation = componentFolderViolation(segments, sourceRoot);
1691
1752
  if (violation !== void 0) return report2(context, violation);
1692
1753
  return {};
1693
1754
  }
1694
1755
  };
1695
1756
 
1696
1757
  // eslint/rules/named-exports.ts
1697
- import path12 from "path";
1758
+ import path13 from "path";
1698
1759
  var FRAMEWORK_DEFAULT_EXPORT_FILES = /* @__PURE__ */ new Set([
1699
1760
  "default",
1700
1761
  "error",
@@ -1706,9 +1767,9 @@ var FRAMEWORK_DEFAULT_EXPORT_FILES = /* @__PURE__ */ new Set([
1706
1767
  "template"
1707
1768
  ]);
1708
1769
  function isFrameworkDefaultExportFile(filename) {
1709
- const normalized = filename.replaceAll(path12.sep, "/");
1770
+ const normalized = filename.replaceAll(path13.sep, "/");
1710
1771
  if (!normalized.includes("/src/app/")) return false;
1711
- const basename = path12.basename(filename, path12.extname(filename));
1772
+ const basename = path13.basename(filename, path13.extname(filename));
1712
1773
  return FRAMEWORK_DEFAULT_EXPORT_FILES.has(basename);
1713
1774
  }
1714
1775
  var namedExportsRule = {
@@ -1733,7 +1794,7 @@ var namedExportsRule = {
1733
1794
  };
1734
1795
 
1735
1796
  // eslint/rules/data-testid-case.ts
1736
- import path13 from "path";
1797
+ import path14 from "path";
1737
1798
  var NEXT_ROUTING_FILES2 = /* @__PURE__ */ new Set([
1738
1799
  "page",
1739
1800
  "layout",
@@ -1757,9 +1818,9 @@ var dataTestIdCaseRule = {
1757
1818
  }
1758
1819
  },
1759
1820
  create(context) {
1760
- const filename = path13.resolve(context.filename);
1821
+ const filename = path14.resolve(context.filename);
1761
1822
  if (!filename.endsWith(".tsx")) return {};
1762
- const base = path13.basename(filename, path13.extname(filename));
1823
+ const base = path14.basename(filename, path14.extname(filename));
1763
1824
  if (NEXT_ROUTING_FILES2.has(base)) return {};
1764
1825
  const text = context.sourceCode.text;
1765
1826
  const components = parseComponentInfo(text, filename);
@@ -1801,7 +1862,7 @@ function toKebabCase(value) {
1801
1862
 
1802
1863
  // eslint/rules/support-folder-shape.ts
1803
1864
  import fs3 from "fs";
1804
- import path14 from "path";
1865
+ import path15 from "path";
1805
1866
  var SUPPORT_FOLDERS3 = /* @__PURE__ */ new Set(["constants", "types", "schemas"]);
1806
1867
  var INDEX_NAMES = /* @__PURE__ */ new Set(["index.ts", "index.tsx", "index.mts", "index.cts"]);
1807
1868
  var supportFolderShapeRule = {
@@ -1813,12 +1874,12 @@ var supportFolderShapeRule = {
1813
1874
  }
1814
1875
  },
1815
1876
  create(context) {
1816
- const filename = path14.resolve(context.filename);
1817
- const baseName = path14.basename(filename);
1877
+ const filename = path15.resolve(context.filename);
1878
+ const baseName = path15.basename(filename);
1818
1879
  if (!INDEX_NAMES.has(baseName)) return {};
1819
- const folder = path14.basename(path14.dirname(filename));
1880
+ const folder = path15.basename(path15.dirname(filename));
1820
1881
  if (!SUPPORT_FOLDERS3.has(folder)) return {};
1821
- const directory = path14.dirname(filename);
1882
+ const directory = path15.dirname(filename);
1822
1883
  let entries;
1823
1884
  try {
1824
1885
  entries = fs3.readdirSync(directory);
@@ -1836,7 +1897,7 @@ var supportFolderShapeRule = {
1836
1897
  const exportPattern = /export\s+(?:\{[^}]*\}|\*[^;]*)\s+from\s+["'](?<specifier>\.[^"']+)["']/g;
1837
1898
  for (const match of source.matchAll(exportPattern)) {
1838
1899
  const specifier = match.groups?.specifier;
1839
- if (specifier) exportedFiles.add(path14.basename(specifier));
1900
+ if (specifier) exportedFiles.add(path15.basename(specifier));
1840
1901
  }
1841
1902
  const missing = siblingModules.filter((entry) => {
1842
1903
  const stem = entry.replace(/\.(?:[cm]?tsx?|jsx?)$/, "");
@@ -1853,7 +1914,7 @@ var supportFolderShapeRule = {
1853
1914
  };
1854
1915
 
1855
1916
  // eslint/rules/import-through-index.ts
1856
- import path15 from "path";
1917
+ import path16 from "path";
1857
1918
  var importThroughIndexRule = {
1858
1919
  meta: {
1859
1920
  schema: [],
@@ -1863,19 +1924,19 @@ var importThroughIndexRule = {
1863
1924
  }
1864
1925
  },
1865
1926
  create(context) {
1866
- const filename = path15.resolve(context.filename);
1867
- const sourceRoot2 = sourceRootOf(filename);
1927
+ const filename = path16.resolve(context.filename);
1928
+ const sourceRoot = sourceRootOf2(context, filename);
1868
1929
  return {
1869
1930
  Program(node) {
1870
1931
  for (const specifier of importSpecifiers(context.sourceCode.text)) {
1871
- const target = resolveSpecifier(filename, specifier, sourceRoot2);
1932
+ const target = resolveSpecifier(filename, specifier, sourceRoot);
1872
1933
  if (!target) continue;
1873
- const targetSegments = segmentsOf(target, sourceRoot2);
1934
+ const targetSegments = segmentsOf(target, sourceRoot);
1874
1935
  const supportFolderIndex = targetSegments.findIndex(
1875
1936
  (segment) => ["constants", "types", "schemas"].includes(segment)
1876
1937
  );
1877
1938
  const supportFolder = supportFolderIndex >= 0 ? targetSegments[supportFolderIndex] : void 0;
1878
- if (!supportFolder || path15.basename(target).startsWith("index.")) continue;
1939
+ if (!supportFolder || path16.basename(target).startsWith("index.")) continue;
1879
1940
  const folderIndex = targetSegments.slice(0, supportFolderIndex + 1);
1880
1941
  const expected = `@/${folderIndex.join("/")}`;
1881
1942
  context.report({
@@ -1896,14 +1957,15 @@ function importSpecifiers(source) {
1896
1957
  }
1897
1958
  return specifiers;
1898
1959
  }
1899
- function sourceRootOf(filename) {
1900
- const marker = `${path15.sep}src${path15.sep}`;
1960
+ function sourceRootOf2(context, filename) {
1961
+ const marker = `${path16.sep}src${path16.sep}`;
1901
1962
  const srcIndex = filename.lastIndexOf(marker);
1902
- return srcIndex >= 0 ? filename.slice(0, srcIndex + marker.length - 1) : path15.resolve("src");
1963
+ if (srcIndex >= 0) return filename.slice(0, srcIndex + marker.length - 1);
1964
+ return path16.resolve(context.cwd ?? process.cwd(), "src");
1903
1965
  }
1904
1966
 
1905
1967
  // eslint/rules/util-file-name.ts
1906
- import path16 from "path";
1968
+ import path17 from "path";
1907
1969
  function toKebabCase2(value) {
1908
1970
  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();
1909
1971
  }
@@ -1916,7 +1978,7 @@ var utilFileNameRule = {
1916
1978
  }
1917
1979
  },
1918
1980
  create(context) {
1919
- const filename = path16.resolve(context.filename);
1981
+ const filename = path17.resolve(context.filename);
1920
1982
  const segments = filename.replace(/\\/g, "/").split("/");
1921
1983
  if (!segments.includes("utils")) return {};
1922
1984
  let module;
@@ -1930,13 +1992,13 @@ var utilFileNameRule = {
1930
1992
  const functionName = functions[0]?.name;
1931
1993
  if (!functionName) return {};
1932
1994
  const expected = toKebabCase2(functionName);
1933
- const actual = path16.basename(filename, path16.extname(filename));
1995
+ const actual = path17.basename(filename, path17.extname(filename));
1934
1996
  if (!expected || actual === expected) return {};
1935
1997
  return {
1936
1998
  Program(node) {
1937
1999
  context.report({
1938
2000
  node,
1939
- message: `A utility file exporting ${functionName} must be named ${expected}.${path16.extname(filename).slice(1)}.`
2001
+ message: `A utility file exporting ${functionName} must be named ${expected}.${path17.extname(filename).slice(1)}.`
1940
2002
  });
1941
2003
  }
1942
2004
  };
@@ -1944,7 +2006,7 @@ var utilFileNameRule = {
1944
2006
  };
1945
2007
 
1946
2008
  // eslint/rules/no-util-barrel.ts
1947
- import path17 from "path";
2009
+ import path18 from "path";
1948
2010
  var noUtilBarrelRule = {
1949
2011
  meta: {
1950
2012
  schema: [],
@@ -1954,16 +2016,16 @@ var noUtilBarrelRule = {
1954
2016
  }
1955
2017
  },
1956
2018
  create(context) {
1957
- const filename = path17.resolve(context.filename);
1958
- const sourceRoot2 = sourceRootOf2(filename);
2019
+ const filename = path18.resolve(context.filename);
2020
+ const sourceRoot = sourceRootOf3(context, filename);
1959
2021
  return {
1960
2022
  Program(node) {
1961
2023
  for (const specifier of importSpecifiers2(context.sourceCode.text)) {
1962
- const target = resolveSpecifier(filename, specifier, sourceRoot2);
2024
+ const target = resolveSpecifier(filename, specifier, sourceRoot);
1963
2025
  if (!target) continue;
1964
2026
  const segments = target.replace(/\\/g, "/").split("/");
1965
2027
  const utilsIndex = segments.lastIndexOf("utils");
1966
- if (utilsIndex < 0 || !path17.basename(target).startsWith("index.")) continue;
2028
+ if (utilsIndex < 0 || !path18.basename(target).startsWith("index.")) continue;
1967
2029
  context.report({
1968
2030
  node,
1969
2031
  message: `Import utilities directly instead of through "${specifier}". See docs/code-organization-guide/rules/utilities-rule.md`
@@ -1982,10 +2044,11 @@ function importSpecifiers2(source) {
1982
2044
  }
1983
2045
  return specifiers;
1984
2046
  }
1985
- function sourceRootOf2(filename) {
1986
- const marker = `${path17.sep}src${path17.sep}`;
2047
+ function sourceRootOf3(context, filename) {
2048
+ const marker = `${path18.sep}src${path18.sep}`;
1987
2049
  const srcIndex = filename.lastIndexOf(marker);
1988
- return srcIndex >= 0 ? filename.slice(0, srcIndex + marker.length - 1) : path17.resolve("src");
2050
+ if (srcIndex >= 0) return filename.slice(0, srcIndex + marker.length - 1);
2051
+ return path18.resolve(context.cwd ?? process.cwd(), "src");
1989
2052
  }
1990
2053
 
1991
2054
  // eslint/rules/jsx-hygiene.ts
@@ -2361,12 +2424,12 @@ var cvaBooleanVariantsRule = {
2361
2424
  };
2362
2425
 
2363
2426
  // eslint/rules/cross-feature-import.ts
2364
- import path18 from "path";
2427
+ import path19 from "path";
2365
2428
  var FEATURES_SEGMENT = "features";
2366
- function featureNameOf(resolvedPath, sourceRoot2) {
2367
- const relative = path18.relative(sourceRoot2, resolvedPath);
2429
+ function featureNameOf(resolvedPath, sourceRoot) {
2430
+ const relative = path19.relative(sourceRoot, resolvedPath);
2368
2431
  if (relative.startsWith("..")) return void 0;
2369
- const segments = relative.split(path18.sep);
2432
+ const segments = relative.split(path19.sep);
2370
2433
  if (segments[0] !== FEATURES_SEGMENT || segments.length < 2) return void 0;
2371
2434
  return segments[1];
2372
2435
  }
@@ -2381,10 +2444,10 @@ var crossFeatureImportRule = {
2381
2444
  create(context) {
2382
2445
  const filename = context.filename;
2383
2446
  if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
2384
- const sourceRoot2 = path18.resolve("src");
2385
- const fileRelative = path18.relative(sourceRoot2, filename);
2447
+ const sourceRoot = sourceRootOf(context);
2448
+ const fileRelative = path19.relative(sourceRoot, filename);
2386
2449
  if (fileRelative.startsWith("..")) return {};
2387
- const fileSegments = fileRelative.split(path18.sep);
2450
+ const fileSegments = fileRelative.split(path19.sep);
2388
2451
  const isInCompositions = fileSegments[0] === "compositions";
2389
2452
  const isInApp = fileSegments[0] === "app";
2390
2453
  const isConfig = fileSegments[0] === "config";
@@ -2398,12 +2461,12 @@ var crossFeatureImportRule = {
2398
2461
  if (typeof source.value !== "string") return;
2399
2462
  let resolved;
2400
2463
  if (source.value.startsWith("@/")) {
2401
- resolved = path18.resolve(sourceRoot2, source.value.slice(2));
2464
+ resolved = path19.resolve(sourceRoot, source.value.slice(2));
2402
2465
  } else if (source.value.startsWith(".")) {
2403
- resolved = path18.resolve(path18.dirname(filename), source.value);
2466
+ resolved = path19.resolve(path19.dirname(filename), source.value);
2404
2467
  }
2405
2468
  if (!resolved) return;
2406
- const feature = featureNameOf(resolved, sourceRoot2);
2469
+ const feature = featureNameOf(resolved, sourceRoot);
2407
2470
  if (feature) importedFeatures.add(feature);
2408
2471
  if (importedFeatures.size >= 2) {
2409
2472
  alreadyReported = true;
@@ -2419,7 +2482,7 @@ var crossFeatureImportRule = {
2419
2482
  };
2420
2483
 
2421
2484
  // eslint/rules/pure-function-extract.ts
2422
- import path19 from "path";
2485
+ import path20 from "path";
2423
2486
  function isComponentLikeName(name) {
2424
2487
  return /^[A-Z]/.test(name);
2425
2488
  }
@@ -2447,10 +2510,10 @@ var pureFunctionExtractRule = {
2447
2510
  create(context) {
2448
2511
  const filename = context.filename;
2449
2512
  if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
2450
- const sourceRoot2 = path19.resolve("src");
2451
- const relative = path19.relative(sourceRoot2, filename);
2513
+ const sourceRoot = sourceRootOf(context);
2514
+ const relative = path20.relative(sourceRoot, filename);
2452
2515
  if (relative.startsWith("..")) return {};
2453
- const segments = relative.split(path19.sep);
2516
+ const segments = relative.split(path20.sep);
2454
2517
  if (segments[0] === "utils") return {};
2455
2518
  if (segments[0] === "app") return {};
2456
2519
  const supportFolders = /* @__PURE__ */ new Set(["hooks", "types", "schemas", "constants", "utils"]);
@@ -2490,7 +2553,7 @@ var pureFunctionExtractRule = {
2490
2553
  };
2491
2554
 
2492
2555
  // eslint/rules/hook-complexity.ts
2493
- import path20 from "path";
2556
+ import path21 from "path";
2494
2557
  import ts4 from "typescript";
2495
2558
  var REACT_HOOKS = /* @__PURE__ */ new Set([
2496
2559
  "useState",
@@ -2542,10 +2605,10 @@ var hookComplexityRule = {
2542
2605
  },
2543
2606
  create(context) {
2544
2607
  const filename = context.filename;
2545
- const sourceRoot2 = path20.resolve("src");
2546
- const relative = path20.relative(sourceRoot2, filename);
2608
+ const sourceRoot = sourceRootOf(context);
2609
+ const relative = path21.relative(sourceRoot, filename);
2547
2610
  if (relative.startsWith("..")) return {};
2548
- const segments = relative.split(path20.sep);
2611
+ const segments = relative.split(path21.sep);
2549
2612
  const sourceText = context.sourceCode.text;
2550
2613
  function checkHook(node, name, body, exported) {
2551
2614
  if (!exported) return;
@@ -2587,9 +2650,9 @@ var hookComplexityRule = {
2587
2650
  };
2588
2651
 
2589
2652
  // eslint/rules/locale-dotted-path.ts
2590
- import path21 from "path";
2653
+ import path22 from "path";
2591
2654
  function isInLocalesDir(filename) {
2592
- const segments = path21.resolve(filename).split(path21.sep);
2655
+ const segments = path22.resolve(filename).split(path22.sep);
2593
2656
  const srcIdx = segments.lastIndexOf("src");
2594
2657
  return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
2595
2658
  }
@@ -2638,9 +2701,9 @@ var localeDottedPathRule = {
2638
2701
  };
2639
2702
 
2640
2703
  // eslint/rules/locales-location.ts
2641
- import path22 from "path";
2704
+ import path23 from "path";
2642
2705
  function isLocalesFile(filename) {
2643
- const segments = path22.resolve(filename).split(path22.sep);
2706
+ const segments = path23.resolve(filename).split(path23.sep);
2644
2707
  const srcIdx = segments.lastIndexOf("src");
2645
2708
  return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
2646
2709
  }
@@ -2659,7 +2722,7 @@ var localesLocationRule = {
2659
2722
  create(context) {
2660
2723
  if (isLocalesFile(context.filename)) return {};
2661
2724
  const filename = context.filename;
2662
- const segments = path22.resolve(filename).split(path22.sep);
2725
+ const segments = path23.resolve(filename).split(path23.sep);
2663
2726
  const srcIdx = segments.lastIndexOf("src");
2664
2727
  if (srcIdx === -1) return {};
2665
2728
  const folder = segments[srcIdx + 1];
@@ -2681,7 +2744,7 @@ var localesLocationRule = {
2681
2744
  };
2682
2745
 
2683
2746
  // eslint/rules/hook-extraction.ts
2684
- import path23 from "path";
2747
+ import path24 from "path";
2685
2748
  var hookExtractionRule = {
2686
2749
  meta: {
2687
2750
  schema: [],
@@ -2691,15 +2754,15 @@ var hookExtractionRule = {
2691
2754
  }
2692
2755
  },
2693
2756
  create(context) {
2694
- const sourceRoot2 = path23.resolve("src");
2695
- const file = path23.resolve(context.filename);
2696
- const segments = segmentsOf(file, sourceRoot2);
2757
+ const sourceRoot = sourceRootOf(context);
2758
+ const file = path24.resolve(context.filename);
2759
+ const segments = segmentsOf(file, sourceRoot);
2697
2760
  if (segments.length === 0) return {};
2698
- const index = getProjectIndex(sourceRoot2);
2761
+ const index = getProjectIndex(sourceRoot);
2699
2762
  if (!index) return {};
2700
2763
  const module = index.modules.get(file);
2701
2764
  if (!module) return {};
2702
- const folder = folderSegmentsOf(file, sourceRoot2);
2765
+ const folder = folderSegmentsOf(file, sourceRoot);
2703
2766
  const alreadyInHooksFolder = folder.length > 0 && folder[folder.length - 1] === "hooks";
2704
2767
  const reusedHooks = module.exports.filter((exp) => exp.kind === "hook" && !alreadyInHooksFolder).map((exp) => ({ exp, consumers: index.symbolConsumers.get(symbolKey(file, exp.name)) })).filter(({ consumers }) => (consumers?.size ?? 0) >= 2);
2705
2768
  if (reusedHooks.length === 0) return {};
@@ -2718,7 +2781,7 @@ var hookExtractionRule = {
2718
2781
  };
2719
2782
 
2720
2783
  // eslint/rules/value-extraction.ts
2721
- import path24 from "path";
2784
+ import path25 from "path";
2722
2785
  var valueExtractionRule = {
2723
2786
  meta: {
2724
2787
  schema: [],
@@ -2728,21 +2791,21 @@ var valueExtractionRule = {
2728
2791
  }
2729
2792
  },
2730
2793
  create(context) {
2731
- const sourceRoot2 = path24.resolve("src");
2732
- const file = path24.resolve(context.filename);
2733
- const segments = segmentsOf(file, sourceRoot2);
2794
+ const sourceRoot = sourceRootOf(context);
2795
+ const file = path25.resolve(context.filename);
2796
+ const segments = segmentsOf(file, sourceRoot);
2734
2797
  if (segments.length === 0 || segments[0] !== "app") return {};
2735
- const index = getProjectIndex(sourceRoot2);
2798
+ const index = getProjectIndex(sourceRoot);
2736
2799
  if (!index) return {};
2737
2800
  const consumers = [...index.consumers.get(file) ?? []];
2738
- const outsideApp = consumers.filter((consumer) => segmentsOf(consumer, sourceRoot2)[0] !== "app");
2801
+ const outsideApp = consumers.filter((consumer) => segmentsOf(consumer, sourceRoot)[0] !== "app");
2739
2802
  if (outsideApp.length === 0) return {};
2740
2803
  return {
2741
2804
  Program(node) {
2742
2805
  context.report({
2743
2806
  node,
2744
2807
  loc: { line: 1, column: 0 },
2745
- message: `This file in src/app/ is imported by ${describeConsumers(outsideApp, sourceRoot2)} outside src/app/. Extract the value to a shared or feature folder so it can be imported independently. See docs/code-organization-guide/rules/constants-rule.md`
2808
+ message: `This file in src/app/ is imported by ${describeConsumers(outsideApp, sourceRoot)} outside src/app/. Extract the value to a shared or feature folder so it can be imported independently. See docs/code-organization-guide/rules/constants-rule.md`
2746
2809
  });
2747
2810
  }
2748
2811
  };
@@ -2750,7 +2813,7 @@ var valueExtractionRule = {
2750
2813
  };
2751
2814
 
2752
2815
  // eslint/rules/config-extraction.ts
2753
- import path25 from "path";
2816
+ import path26 from "path";
2754
2817
  var configExtractionRule = {
2755
2818
  meta: {
2756
2819
  schema: [],
@@ -2760,12 +2823,12 @@ var configExtractionRule = {
2760
2823
  }
2761
2824
  },
2762
2825
  create(context) {
2763
- const sourceRoot2 = path25.resolve("src");
2764
- const file = path25.resolve(context.filename);
2765
- const segments = segmentsOf(file, sourceRoot2);
2826
+ const sourceRoot = sourceRootOf(context);
2827
+ const file = path26.resolve(context.filename);
2828
+ const segments = segmentsOf(file, sourceRoot);
2766
2829
  if (segments.length < 3 || segments[0] !== "config") return {};
2767
2830
  if (SUPPORT_FOLDERS2.has(segments[2] ?? "")) return {};
2768
- const index = getProjectIndex(sourceRoot2);
2831
+ const index = getProjectIndex(sourceRoot);
2769
2832
  if (!index) return {};
2770
2833
  const module = index.modules.get(file);
2771
2834
  if (!module) return {};
@@ -2774,11 +2837,11 @@ var configExtractionRule = {
2774
2837
  const findings = [];
2775
2838
  for (const exp of suspects) {
2776
2839
  const consumers = [...index.symbolConsumers.get(symbolKey(file, exp.name)) ?? []];
2777
- const outsideConfig = consumers.filter((consumer) => segmentsOf(consumer, sourceRoot2)[0] !== "config");
2840
+ const outsideConfig = consumers.filter((consumer) => segmentsOf(consumer, sourceRoot)[0] !== "config");
2778
2841
  if (outsideConfig.length > 0) {
2779
2842
  findings.push({
2780
2843
  line: exp.line,
2781
- message: `${exp.kind} "${exp.name}" in a configuration module is imported by ${describeConsumers(outsideConfig, sourceRoot2)} outside src/config/. Move it to the matching root support folder. See docs/code-organization-guide/rules/configuration-rule.md`
2844
+ message: `${exp.kind} "${exp.name}" in a configuration module is imported by ${describeConsumers(outsideConfig, sourceRoot)} outside src/config/. Move it to the matching root support folder. See docs/code-organization-guide/rules/configuration-rule.md`
2782
2845
  });
2783
2846
  } else if (consumers.length > 0) {
2784
2847
  findings.push({
@@ -2799,7 +2862,7 @@ var configExtractionRule = {
2799
2862
  };
2800
2863
 
2801
2864
  // eslint/rules/component-nesting.ts
2802
- import path26 from "path";
2865
+ import path27 from "path";
2803
2866
  var componentNestingRule = {
2804
2867
  meta: {
2805
2868
  schema: [],
@@ -2809,18 +2872,18 @@ var componentNestingRule = {
2809
2872
  }
2810
2873
  },
2811
2874
  create(context) {
2812
- const sourceRoot2 = path26.resolve("src");
2813
- const file = path26.resolve(context.filename);
2814
- const segments = segmentsOf(file, sourceRoot2);
2875
+ const sourceRoot = sourceRootOf(context);
2876
+ const file = path27.resolve(context.filename);
2877
+ const segments = segmentsOf(file, sourceRoot);
2815
2878
  if (segments.length !== 4 || segments[0] !== "features") return {};
2816
- const index = getProjectIndex(sourceRoot2);
2879
+ const index = getProjectIndex(sourceRoot);
2817
2880
  if (!index) return {};
2818
2881
  const module = index.modules.get(file);
2819
2882
  if (!module?.exports.some((exp) => exp.kind === "component")) return {};
2820
2883
  const folder = segments.slice(0, 3);
2821
2884
  const hasChildComponent = [...index.modules.values()].some((candidate) => {
2822
2885
  if (candidate.file === file) return false;
2823
- const candidateSegments = segmentsOf(candidate.file, sourceRoot2);
2886
+ const candidateSegments = segmentsOf(candidate.file, sourceRoot);
2824
2887
  if (candidateSegments.length !== 4) return false;
2825
2888
  if (candidateSegments[0] !== folder[0] || candidateSegments[1] !== folder[1] || candidateSegments[2] !== folder[2]) {
2826
2889
  return false;
@@ -2843,7 +2906,7 @@ var componentNestingRule = {
2843
2906
  };
2844
2907
 
2845
2908
  // eslint/rules/stay-flat.ts
2846
- import path27 from "path";
2909
+ import path28 from "path";
2847
2910
  var stayFlatRule = {
2848
2911
  meta: {
2849
2912
  schema: [],
@@ -2853,11 +2916,11 @@ var stayFlatRule = {
2853
2916
  }
2854
2917
  },
2855
2918
  create(context) {
2856
- const sourceRoot2 = path27.resolve("src");
2857
- const file = path27.resolve(context.filename);
2858
- const segments = segmentsOf(file, sourceRoot2);
2919
+ const sourceRoot = sourceRootOf(context);
2920
+ const file = path28.resolve(context.filename);
2921
+ const segments = segmentsOf(file, sourceRoot);
2859
2922
  if (segments.length !== 3 || segments[0] !== "features") return {};
2860
- const index = getProjectIndex(sourceRoot2);
2923
+ const index = getProjectIndex(sourceRoot);
2861
2924
  if (!index) return {};
2862
2925
  const module = index.modules.get(file);
2863
2926
  if (!module?.exports.some((exp) => exp.kind === "component")) return {};
@@ -2865,7 +2928,7 @@ var stayFlatRule = {
2865
2928
  if (!featureName) return {};
2866
2929
  const exclusiveChildren = [...index.modules.values()].filter((candidate) => {
2867
2930
  if (candidate.file === file) return false;
2868
- const candidateSegments = segmentsOf(candidate.file, sourceRoot2);
2931
+ const candidateSegments = segmentsOf(candidate.file, sourceRoot);
2869
2932
  if (candidateSegments.length !== 3) return false;
2870
2933
  if (candidateSegments[0] !== "features" || candidateSegments[1] !== featureName) return false;
2871
2934
  if (candidateSegments[2]?.startsWith("index.")) return false;
@@ -2874,7 +2937,7 @@ var stayFlatRule = {
2874
2937
  if (consumers.size === 0) return false;
2875
2938
  return [...consumers].every((consumer) => {
2876
2939
  if (consumer === file) return true;
2877
- const consumerSegments = segmentsOf(consumer, sourceRoot2);
2940
+ const consumerSegments = segmentsOf(consumer, sourceRoot);
2878
2941
  if (consumerSegments[0] !== "features" || consumerSegments[1] !== featureName) return false;
2879
2942
  return !(index.modules.get(consumer)?.exports.some((exp) => exp.kind === "component") ?? false);
2880
2943
  });
@@ -2894,7 +2957,7 @@ var stayFlatRule = {
2894
2957
  };
2895
2958
 
2896
2959
  // eslint/rules/type-extraction.ts
2897
- import path28 from "path";
2960
+ import path29 from "path";
2898
2961
  var typeExtractionRule = {
2899
2962
  meta: {
2900
2963
  schema: [],
@@ -2904,11 +2967,11 @@ var typeExtractionRule = {
2904
2967
  }
2905
2968
  },
2906
2969
  create(context) {
2907
- const sourceRoot2 = path28.resolve("src");
2908
- const file = path28.resolve(context.filename);
2909
- const segments = segmentsOf(file, sourceRoot2);
2970
+ const sourceRoot = sourceRootOf(context);
2971
+ const file = path29.resolve(context.filename);
2972
+ const segments = segmentsOf(file, sourceRoot);
2910
2973
  if (segments.length === 0) return {};
2911
- const index = getProjectIndex(sourceRoot2);
2974
+ const index = getProjectIndex(sourceRoot);
2912
2975
  if (!index) return {};
2913
2976
  const module = index.modules.get(file);
2914
2977
  if (!module) return {};
@@ -2925,7 +2988,7 @@ var typeExtractionRule = {
2925
2988
  if (independent2.length === 0) continue;
2926
2989
  findings.push({
2927
2990
  line: exp.line,
2928
- message: `${exp.kind} "${exp.name}" is imported by ${describeConsumers(independent2, sourceRoot2)} without the component "${componentExport.name}" that defines it. Extract it to a types/ or schemas/ folder. See docs/code-organization-guide/rules/types-and-schemas-rule.md`
2991
+ message: `${exp.kind} "${exp.name}" is imported by ${describeConsumers(independent2, sourceRoot)} without the component "${componentExport.name}" that defines it. Extract it to a types/ or schemas/ folder. See docs/code-organization-guide/rules/types-and-schemas-rule.md`
2929
2992
  });
2930
2993
  continue;
2931
2994
  }
@@ -2936,7 +2999,7 @@ var typeExtractionRule = {
2936
2999
  if (independent.length === 0) continue;
2937
3000
  findings.push({
2938
3001
  line: exp.line,
2939
- message: `${exp.kind} "${exp.name}" is imported by ${describeConsumers(independent, sourceRoot2)} without using the code in this file. Extract it to a types/ or schemas/ folder. See docs/code-organization-guide/rules/types-and-schemas-rule.md`
3002
+ message: `${exp.kind} "${exp.name}" is imported by ${describeConsumers(independent, sourceRoot)} without using the code in this file. Extract it to a types/ or schemas/ folder. See docs/code-organization-guide/rules/types-and-schemas-rule.md`
2940
3003
  });
2941
3004
  }
2942
3005
  if (findings.length === 0) return {};
@@ -2951,7 +3014,7 @@ var typeExtractionRule = {
2951
3014
  };
2952
3015
 
2953
3016
  // eslint/rules/locale-placement.ts
2954
- import path29 from "path";
3017
+ import path30 from "path";
2955
3018
  import { readFileSync as readFileSync3 } from "fs";
2956
3019
  import ts5 from "typescript";
2957
3020
  var LOCALE_ACCESS = /\blocales\.(?<key>[A-Za-z_$][\w$]*)/g;
@@ -2998,14 +3061,14 @@ var localePlacementRule = {
2998
3061
  }
2999
3062
  },
3000
3063
  create(context) {
3001
- const sourceRoot2 = path29.resolve("src");
3002
- const file = path29.resolve(context.filename);
3003
- const segments = segmentsOf(file, sourceRoot2);
3064
+ const sourceRoot = sourceRootOf(context);
3065
+ const file = path30.resolve(context.filename);
3066
+ const segments = segmentsOf(file, sourceRoot);
3004
3067
  if (segments.length === 0) return {};
3005
- const index = getProjectIndex(sourceRoot2);
3068
+ const index = getProjectIndex(sourceRoot);
3006
3069
  if (!index) return {};
3007
3070
  const localesFile = [...index.modules.keys()].find((candidate) => {
3008
- const candidateSegments = segmentsOf(candidate, sourceRoot2);
3071
+ const candidateSegments = segmentsOf(candidate, sourceRoot);
3009
3072
  return candidateSegments.length === 2 && candidateSegments[0] === "locales" && candidateSegments[1]?.startsWith("index.");
3010
3073
  });
3011
3074
  if (!localesFile || file !== localesFile) return {};
@@ -3017,10 +3080,10 @@ var localePlacementRule = {
3017
3080
  for (const [candidateFile, module] of index.modules) {
3018
3081
  if (candidateFile === localesFile) continue;
3019
3082
  const importsLocales = module.imports.some(
3020
- (moduleImport) => resolveSpecifier(candidateFile, moduleImport.specifier, sourceRoot2) === localesFile
3083
+ (moduleImport) => resolveSpecifier(candidateFile, moduleImport.specifier, sourceRoot) === localesFile
3021
3084
  );
3022
3085
  if (!importsLocales) continue;
3023
- const candidateSegments = segmentsOf(candidateFile, sourceRoot2);
3086
+ const candidateSegments = segmentsOf(candidateFile, sourceRoot);
3024
3087
  for (const match of readFileSync3(candidateFile, "utf8").matchAll(LOCALE_ACCESS)) {
3025
3088
  const key = match.groups?.key;
3026
3089
  if (key === void 0) continue;
@@ -3045,7 +3108,7 @@ var localePlacementRule = {
3045
3108
  if (current?.kind === "nested") {
3046
3109
  findings.push({
3047
3110
  line: current.line,
3048
- message: `Locale "${key}" is read by ${describeConsumers([...readers], sourceRoot2)} and must live at the top level of locales. See docs/code-organization-guide/rules/locales-rule.md`
3111
+ message: `Locale "${key}" is read by ${describeConsumers([...readers], sourceRoot)} and must live at the top level of locales. See docs/code-organization-guide/rules/locales-rule.md`
3049
3112
  });
3050
3113
  }
3051
3114
  continue;
@@ -3077,7 +3140,7 @@ var localePlacementRule = {
3077
3140
  };
3078
3141
 
3079
3142
  // eslint/rules/sole-state-owner.ts
3080
- import path30 from "path";
3143
+ import path31 from "path";
3081
3144
  import ts6 from "typescript";
3082
3145
  function findStateHooks(node) {
3083
3146
  const hooks = [];
@@ -3157,7 +3220,7 @@ var soleStateOwnerRule = {
3157
3220
  }
3158
3221
  },
3159
3222
  create(context) {
3160
- const filename = path30.resolve(context.filename);
3223
+ const filename = path31.resolve(context.filename);
3161
3224
  if (!filename.endsWith(".tsx") && !filename.endsWith(".jsx")) return {};
3162
3225
  const text = context.sourceCode.text;
3163
3226
  const components = parseComponentInfo(text, filename);
@@ -3236,7 +3299,7 @@ function usesOutsideJsx(declaration, hook, children) {
3236
3299
  }
3237
3300
 
3238
3301
  // eslint/rules/locale-key-shape.ts
3239
- import path31 from "path";
3302
+ import path32 from "path";
3240
3303
  var MAX_KEY_LENGTH = 30;
3241
3304
  var ROLE_POSTFIXES = /* @__PURE__ */ new Set([
3242
3305
  "Button",
@@ -3284,8 +3347,9 @@ var ROLE_POSTFIXES = /* @__PURE__ */ new Set([
3284
3347
  "ScrollBar"
3285
3348
  ]);
3286
3349
  var CAMEL_CASE = /^[a-z][a-zA-Z0-9]*$/;
3350
+ var ENGLISH = /^[A-Za-z0-9_]*$/;
3287
3351
  function isLocalesFile2(filename) {
3288
- const segments = path31.resolve(filename).split(path31.sep);
3352
+ const segments = path32.resolve(filename).split(path32.sep);
3289
3353
  const srcIdx = segments.lastIndexOf("src");
3290
3354
  return srcIdx !== -1 && segments[srcIdx + 1] === "locales";
3291
3355
  }
@@ -3298,6 +3362,14 @@ function reportFor(context, node, message) {
3298
3362
  context.report({ node, message });
3299
3363
  }
3300
3364
  function checkKey(context, node, name) {
3365
+ if (!ENGLISH.test(name)) {
3366
+ reportFor(
3367
+ context,
3368
+ node,
3369
+ `Locale key "${name}" must be English; write it in the Latin alphabet. See docs/code-organization-guide/rules/locales-rule.md`
3370
+ );
3371
+ return;
3372
+ }
3301
3373
  if (!CAMEL_CASE.test(name)) {
3302
3374
  reportFor(
3303
3375
  context,
@@ -3348,7 +3420,7 @@ var localeKeyShapeRule = {
3348
3420
  };
3349
3421
 
3350
3422
  // eslint/rules/shared-style-dedup.ts
3351
- import path32 from "path";
3423
+ import path33 from "path";
3352
3424
  import { readFileSync as readFileSync4, statSync as statSync3 } from "fs";
3353
3425
  var CLASS_NAME = /className="(?<classes>[^"]+)"/g;
3354
3426
  var comboCache;
@@ -3389,11 +3461,11 @@ var sharedStyleDedupRule = {
3389
3461
  }
3390
3462
  },
3391
3463
  create(context) {
3392
- const sourceRoot2 = path32.resolve("src");
3393
- const file = path32.resolve(context.filename);
3394
- const segments = segmentsOf(file, sourceRoot2);
3464
+ const sourceRoot = sourceRootOf(context);
3465
+ const file = path33.resolve(context.filename);
3466
+ const segments = segmentsOf(file, sourceRoot);
3395
3467
  if (segments.length === 0) return {};
3396
- const index = getProjectIndex(sourceRoot2);
3468
+ const index = getProjectIndex(sourceRoot);
3397
3469
  if (!index) return {};
3398
3470
  const combos = combosFor(index);
3399
3471
  const sharedHere = [...combos.entries()].filter(([, users]) => users.size >= 2 && users.has(file)).filter(([, users]) => [...users].sort((left, right) => left.localeCompare(right))[0] === file);
@@ -3594,7 +3666,7 @@ var zodSchemaValidationRule = {
3594
3666
  };
3595
3667
 
3596
3668
  // eslint/rules/source-under-src.ts
3597
- import path33 from "path";
3669
+ import path34 from "path";
3598
3670
  var NON_SOURCE_ROOT_DIRS = /* @__PURE__ */ new Set([
3599
3671
  ".agents",
3600
3672
  ".cache",
@@ -3635,14 +3707,14 @@ var sourceUnderSrcRule = {
3635
3707
  }
3636
3708
  },
3637
3709
  create(context) {
3638
- const filename = path33.resolve(context.filename);
3710
+ const filename = path34.resolve(context.filename);
3639
3711
  if (!MODULE_EXTENSION.test(filename)) return {};
3640
- const relative = path33.relative(process.cwd(), filename).replace(/\\/g, "/");
3712
+ const relative = path34.relative(context.cwd, filename).replace(/\\/g, "/");
3641
3713
  if (relative === "src" || relative.startsWith("src/")) return {};
3642
3714
  const topLevel = relative.split("/")[0] ?? "";
3643
3715
  if (NON_SOURCE_ROOT_DIRS.has(topLevel)) return {};
3644
3716
  if (!relative.includes("/")) {
3645
- const basename = path33.basename(filename);
3717
+ const basename = path34.basename(filename);
3646
3718
  if (CONFIG_FILE.test(basename) || DECLARATION_FILE.test(basename) || basename.startsWith(".")) return {};
3647
3719
  }
3648
3720
  return {
@@ -3659,7 +3731,7 @@ var sourceUnderSrcRule = {
3659
3731
 
3660
3732
  // eslint/rules/zirka-baseline.ts
3661
3733
  import fs4 from "fs";
3662
- import path34 from "path";
3734
+ import path35 from "path";
3663
3735
  var ESLINT_CONFIG = /^eslint\.config\.(?:ts|mts|cts|js|mjs|cjs)$/;
3664
3736
  var PRETTIER_CONFIGS = [
3665
3737
  "prettier.config.mjs",
@@ -3678,10 +3750,10 @@ var zirkaBaselineRule = {
3678
3750
  }
3679
3751
  },
3680
3752
  create(context) {
3681
- const filename = path34.resolve(context.filename);
3682
- const basename = path34.basename(filename);
3753
+ const filename = path35.resolve(context.filename);
3754
+ const basename = path35.basename(filename);
3683
3755
  if (!ESLINT_CONFIG.test(basename)) return {};
3684
- const projectRoot = path34.dirname(filename);
3756
+ const projectRoot = path35.dirname(filename);
3685
3757
  const report3 = (message) => {
3686
3758
  context.report({
3687
3759
  node: context.sourceCode.ast,
@@ -3696,7 +3768,7 @@ var zirkaBaselineRule = {
3696
3768
  'ESLint config must take its configuration from zirka (import { styleguide } from "zirka") instead of restating rules locally.'
3697
3769
  );
3698
3770
  }
3699
- const tsconfigPath = path34.join(projectRoot, "tsconfig.json");
3771
+ const tsconfigPath = path35.join(projectRoot, "tsconfig.json");
3700
3772
  if (!fs4.existsSync(tsconfigPath)) {
3701
3773
  report3('No tsconfig.json found. Create one extending the zirka TypeScript base config ("zirka/typescript").');
3702
3774
  } else {
@@ -3714,13 +3786,13 @@ var zirkaBaselineRule = {
3714
3786
  report3('tsconfig.json must extend the zirka TypeScript base config ("zirka/typescript").');
3715
3787
  }
3716
3788
  }
3717
- const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs4.existsSync(path34.join(projectRoot, name)));
3789
+ const prettierConfigFile = PRETTIER_CONFIGS.find((name) => fs4.existsSync(path35.join(projectRoot, name)));
3718
3790
  if (!prettierConfigFile) {
3719
3791
  report3(
3720
3792
  "No prettier config found. Create one that takes its configuration from zirka (styleguide({ prettier: true }).prettierConfig)."
3721
3793
  );
3722
3794
  } else {
3723
- const content = fs4.readFileSync(path34.join(projectRoot, prettierConfigFile), "utf8");
3795
+ const content = fs4.readFileSync(path35.join(projectRoot, prettierConfigFile), "utf8");
3724
3796
  if (!content.includes("zirka")) {
3725
3797
  report3(
3726
3798
  "The prettier config must take its configuration from zirka (styleguide({ prettier: true }).prettierConfig) instead of restating it locally."
@@ -3790,7 +3862,7 @@ var docKindSuffixRule = {
3790
3862
  };
3791
3863
 
3792
3864
  // eslint/rules/documentation/title-matches-file-name.ts
3793
- import path35 from "path";
3865
+ import path36 from "path";
3794
3866
  function toExpectedFileName(title) {
3795
3867
  return `${title.toLowerCase().replaceAll(/[^a-z0-9]+/g, "-").replace(/^-|-$/g, "")}.md`;
3796
3868
  }
@@ -3810,7 +3882,7 @@ var titleMatchesFileNameRule = {
3810
3882
  if (!filename.endsWith(".md")) return;
3811
3883
  const title = getTextContent(node).trim();
3812
3884
  const expectedFileName = toExpectedFileName(title);
3813
- const actualFileName = path35.basename(filename);
3885
+ const actualFileName = path36.basename(filename);
3814
3886
  if (!title) {
3815
3887
  context.report({
3816
3888
  node,
@@ -4217,7 +4289,7 @@ var referenceBlockHeadingsRule = {
4217
4289
  };
4218
4290
 
4219
4291
  // eslint/rules/documentation/support-document-placement.ts
4220
- import path36 from "path";
4292
+ import path37 from "path";
4221
4293
  var supportDocumentPlacementRule = {
4222
4294
  meta: {
4223
4295
  type: "problem",
@@ -4231,7 +4303,7 @@ var supportDocumentPlacementRule = {
4231
4303
  root(node) {
4232
4304
  const filename = getFilename(context);
4233
4305
  if (!filename.endsWith(".md")) return;
4234
- const parentFolder = path36.basename(path36.dirname(filename));
4306
+ const parentFolder = path37.basename(path37.dirname(filename));
4235
4307
  if (filename.endsWith("-rule.md") && parentFolder !== "rules") {
4236
4308
  context.report({
4237
4309
  node,
@@ -4274,11 +4346,11 @@ var noTemplatePromptRule = {
4274
4346
  };
4275
4347
 
4276
4348
  // eslint/rules/documentation/guide-folder-entry-point.ts
4277
- import path38 from "path";
4349
+ import path39 from "path";
4278
4350
 
4279
4351
  // eslint/rules/documentation/project-index.ts
4280
4352
  import { readdirSync as readdirSync3, readFileSync as readFileSync5, statSync as statSync4 } from "fs";
4281
- import path37 from "path";
4353
+ import path38 from "path";
4282
4354
  var KIND_BY_SUFFIX = [
4283
4355
  ["-rule.md", "rule"],
4284
4356
  ["-guide.md", "guide"],
@@ -4287,7 +4359,7 @@ var KIND_BY_SUFFIX = [
4287
4359
  ];
4288
4360
  function listMarkdownFiles(dir) {
4289
4361
  return readdirSync3(dir).flatMap((entry) => {
4290
- const entryPath = path37.join(dir, entry);
4362
+ const entryPath = path38.join(dir, entry);
4291
4363
  if (statSync4(entryPath).isDirectory()) {
4292
4364
  return entry.startsWith("_") ? [] : listMarkdownFiles(entryPath);
4293
4365
  }
@@ -4305,11 +4377,11 @@ function getProjectDocs(docsRoot) {
4305
4377
  if (cached) return cached;
4306
4378
  const files = listMarkdownFiles(docsRoot);
4307
4379
  const docs = files.sort((a, b) => a.localeCompare(b)).map((filePath) => {
4308
- const fileName = path37.basename(filePath);
4380
+ const fileName = path38.basename(filePath);
4309
4381
  const kind = KIND_BY_SUFFIX.find(([suffix]) => fileName.endsWith(suffix))?.[1];
4310
4382
  return {
4311
4383
  filePath,
4312
- doc: path37.relative(docsRoot, filePath).split(path37.sep).join("/"),
4384
+ doc: path38.relative(docsRoot, filePath).split(path38.sep).join("/"),
4313
4385
  fileName,
4314
4386
  kind,
4315
4387
  title: extractTitle(filePath)
@@ -4319,12 +4391,12 @@ function getProjectDocs(docsRoot) {
4319
4391
  return docs;
4320
4392
  }
4321
4393
  function findDocsRoot(filePath) {
4322
- let dir = path37.dirname(filePath);
4394
+ let dir = path38.dirname(filePath);
4323
4395
  for (; ; ) {
4324
- if (path37.basename(dir) === "docs" && statSync4(dir).isDirectory()) {
4396
+ if (path38.basename(dir) === "docs" && statSync4(dir).isDirectory()) {
4325
4397
  return dir;
4326
4398
  }
4327
- const parent = path37.dirname(dir);
4399
+ const parent = path38.dirname(dir);
4328
4400
  if (parent === dir) return void 0;
4329
4401
  dir = parent;
4330
4402
  }
@@ -4348,13 +4420,13 @@ var guideFolderEntryPointRule = {
4348
4420
  if (!docsRoot) return;
4349
4421
  const docs = getProjectDocs(docsRoot);
4350
4422
  const guideFolders = new Set(
4351
- 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))
4423
+ docs.filter((doc) => ["rules", "references"].includes(path39.basename(path39.dirname(doc.filePath)))).map((doc) => path39.dirname(path39.dirname(doc.filePath))).filter((folder) => path39.resolve(folder) !== path39.resolve(docsRoot))
4352
4424
  );
4353
- const currentDir = path38.dirname(filename);
4425
+ const currentDir = path39.dirname(filename);
4354
4426
  if (guideFolders.has(currentDir)) {
4355
- const expectedEntryPoint = `${path38.basename(currentDir)}.md`;
4427
+ const expectedEntryPoint = `${path39.basename(currentDir)}.md`;
4356
4428
  const hasEntryPoint = docs.some(
4357
- (doc) => doc.kind === "guide" && path38.dirname(doc.filePath) === currentDir && doc.fileName === expectedEntryPoint
4429
+ (doc) => doc.kind === "guide" && path39.dirname(doc.filePath) === currentDir && doc.fileName === expectedEntryPoint
4358
4430
  );
4359
4431
  if (!hasEntryPoint) {
4360
4432
  context.report({
@@ -4579,7 +4651,7 @@ var noNestedHowToRule = {
4579
4651
 
4580
4652
  // eslint/rules/documentation/glossary-term-linking.ts
4581
4653
  import { readFileSync as readFileSync6 } from "fs";
4582
- import path39 from "path";
4654
+ import path40 from "path";
4583
4655
  function extractGlossaryTerms(filePath) {
4584
4656
  const content = readFileSync6(filePath, "utf8");
4585
4657
  const terms = [];
@@ -4633,9 +4705,9 @@ var glossaryTermLinkingRule = {
4633
4705
  const docsRoot = findDocsRoot(filename);
4634
4706
  if (!docsRoot) return;
4635
4707
  const docs = getProjectDocs(docsRoot);
4636
- const guideDir = path39.dirname(filename);
4708
+ const guideDir = path40.dirname(filename);
4637
4709
  const guideReferences = docs.filter(
4638
- (doc) => doc.kind === "reference" && path39.dirname(doc.filePath) === guideDir
4710
+ (doc) => doc.kind === "reference" && path40.dirname(doc.filePath) === guideDir
4639
4711
  );
4640
4712
  if (guideReferences.length === 0) return;
4641
4713
  const glossaryTerms = [];
@@ -4660,7 +4732,7 @@ var glossaryTermLinkingRule = {
4660
4732
 
4661
4733
  // eslint/rules/documentation/guide-mentions-documents.ts
4662
4734
  import { existsSync } from "fs";
4663
- import path40 from "path";
4735
+ import path41 from "path";
4664
4736
  function visitSteps3(node, check) {
4665
4737
  if (node.type === "list" && node.ordered) {
4666
4738
  for (const child of node.children) check(child);
@@ -4693,12 +4765,12 @@ var guideMentionsDocumentsRule = {
4693
4765
  if (!filename.endsWith("-guide.md")) return;
4694
4766
  const docsRoot = findDocsRoot(filename);
4695
4767
  if (!docsRoot) return;
4696
- const guideDir = path40.dirname(filename);
4697
- if (path40.basename(filename, ".md") !== path40.basename(guideDir)) return;
4768
+ const guideDir = path41.dirname(filename);
4769
+ if (path41.basename(filename, ".md") !== path41.basename(guideDir)) return;
4698
4770
  const docs = getProjectDocs(docsRoot);
4699
4771
  const owned = docs.filter((doc) => {
4700
- const parent = path40.dirname(doc.filePath);
4701
- return parent === path40.join(guideDir, "rules") || parent === path40.join(guideDir, "references");
4772
+ const parent = path41.dirname(doc.filePath);
4773
+ return parent === path41.join(guideDir, "rules") || parent === path41.join(guideDir, "references");
4702
4774
  });
4703
4775
  const allLinks = [];
4704
4776
  collectMarkdownLinks(node, allLinks);
@@ -4725,7 +4797,7 @@ var guideMentionsDocumentsRule = {
4725
4797
  for (const link of allLinks) {
4726
4798
  const target = linkTarget(link.url);
4727
4799
  if (!target.endsWith(".md")) continue;
4728
- const resolved = path40.normalize(path40.join(guideDir, target));
4800
+ const resolved = path41.normalize(path41.join(guideDir, target));
4729
4801
  if (!existsSync(resolved)) {
4730
4802
  context.report({
4731
4803
  node: link,
@@ -5166,32 +5238,170 @@ var themeVariableNamespaceRule = {
5166
5238
  }
5167
5239
  };
5168
5240
 
5169
- // eslint/rules/tailwind/global-css-location.ts
5170
- var globalCssLocationRule = {
5241
+ // eslint/rules/tailwind/css-entry-point.ts
5242
+ import { statSync as statSync6 } from "fs";
5243
+ import path44 from "path";
5244
+
5245
+ // eslint/rules/tailwind/source-files.ts
5246
+ import { readdirSync as readdirSync4, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
5247
+ import path42 from "path";
5248
+ var CSS_EXTENSIONS = [".css"];
5249
+ var MODULE_EXTENSIONS3 = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs"];
5250
+ var SOURCE_EXTENSIONS = [...MODULE_EXTENSIONS3, ...CSS_EXTENSIONS];
5251
+ function findFiles(dir, extensions) {
5252
+ let entries;
5253
+ try {
5254
+ entries = readdirSync4(dir);
5255
+ } catch {
5256
+ return [];
5257
+ }
5258
+ return entries.flatMap((entry) => {
5259
+ if (entry.startsWith(".") || entry === "node_modules") return [];
5260
+ const entryPath = path42.join(dir, entry);
5261
+ let stats;
5262
+ try {
5263
+ stats = statSync5(entryPath);
5264
+ } catch {
5265
+ return [];
5266
+ }
5267
+ if (stats.isDirectory()) return findFiles(entryPath, extensions);
5268
+ return extensions.includes(path42.extname(entry)) ? [entryPath] : [];
5269
+ });
5270
+ }
5271
+ function cachedTextReader() {
5272
+ const texts = /* @__PURE__ */ new Map();
5273
+ return (file) => {
5274
+ let text = texts.get(file);
5275
+ if (text === void 0) {
5276
+ try {
5277
+ text = readFileSync7(file, "utf8");
5278
+ } catch {
5279
+ text = "";
5280
+ }
5281
+ texts.set(file, text);
5282
+ }
5283
+ return text;
5284
+ };
5285
+ }
5286
+ function escapeRegExp(text) {
5287
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5288
+ }
5289
+
5290
+ // eslint/rules/tailwind/stylesheet-graph.ts
5291
+ import path43 from "path";
5292
+ function registersTailwind(text) {
5293
+ return /@import\s+(?:url\(\s*)?["']tailwindcss["']\s*\)?/i.test(text);
5294
+ }
5295
+ function importedSpecifiers(text) {
5296
+ return [...text.matchAll(/@import\s+(?:url\(\s*)?["'](?<spec>[^"']+)["']/gi)].map(
5297
+ (match) => match.groups?.spec ?? ""
5298
+ );
5299
+ }
5300
+ function moduleImports(text, fileName) {
5301
+ const escaped = fileName.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5302
+ return new RegExp(`(?:import|require)\\s*\\(?\\s*["'][^"']*${escaped}["']`, "i").test(text);
5303
+ }
5304
+ function resolveSpecifier2(fromFile, spec, sourceRoot) {
5305
+ if (spec.startsWith("/")) return path43.resolve(spec);
5306
+ if (spec.startsWith("./") || spec.startsWith("../")) return path43.resolve(path43.dirname(fromFile), spec);
5307
+ if (spec.startsWith("@/")) return path43.resolve(sourceRoot, spec.slice(2));
5308
+ return void 0;
5309
+ }
5310
+ function buildStylesheetGraph(options) {
5311
+ const { cssFiles, sourceRoot, textOf } = options;
5312
+ const cssSet = new Set(cssFiles.map((file) => path43.normalize(file)));
5313
+ const globals = cssFiles.filter((file) => registersTailwind(textOf(file)));
5314
+ const reachable = /* @__PURE__ */ new Set();
5315
+ const queue = [...globals];
5316
+ for (const global of globals) reachable.add(path43.normalize(global));
5317
+ while (queue.length > 0) {
5318
+ const from = queue.shift();
5319
+ if (!from) continue;
5320
+ for (const spec of importedSpecifiers(textOf(from))) {
5321
+ const target = resolveSpecifier2(from, spec, sourceRoot);
5322
+ if (!target) continue;
5323
+ const normalized = path43.normalize(target);
5324
+ if (cssSet.has(normalized) && !reachable.has(normalized)) {
5325
+ reachable.add(normalized);
5326
+ queue.push(normalized);
5327
+ }
5328
+ }
5329
+ }
5330
+ const directChildren = /* @__PURE__ */ new Set();
5331
+ for (const global of globals) {
5332
+ for (const spec of importedSpecifiers(textOf(global))) {
5333
+ const target = resolveSpecifier2(global, spec, sourceRoot);
5334
+ if (!target) continue;
5335
+ const normalized = path43.normalize(target);
5336
+ if (cssSet.has(normalized)) directChildren.add(normalized);
5337
+ }
5338
+ }
5339
+ return { globals, reachable, directChildren };
5340
+ }
5341
+
5342
+ // eslint/rules/tailwind/css-entry-point.ts
5343
+ var cssEntryPointRule = {
5171
5344
  meta: {
5172
5345
  schema: [],
5173
5346
  type: "problem",
5174
5347
  docs: {
5175
- description: "Require project global CSS to live only in the entry point stylesheet."
5348
+ description: "Require one global entry point; project CSS only in a stylesheet it imports directly."
5176
5349
  }
5177
5350
  },
5178
5351
  create(context) {
5352
+ const sourceRoot = sourceRootOf(context);
5353
+ let cssFiles;
5354
+ let moduleFiles;
5355
+ try {
5356
+ if (!statSync6(sourceRoot).isDirectory()) return {};
5357
+ cssFiles = findFiles(sourceRoot, CSS_EXTENSIONS);
5358
+ moduleFiles = findFiles(sourceRoot, MODULE_EXTENSIONS3);
5359
+ } catch {
5360
+ return {};
5361
+ }
5362
+ const textOf = cachedTextReader();
5363
+ const graph = buildStylesheetGraph({ cssFiles, sourceRoot, textOf });
5364
+ const { globals, reachable, directChildren } = graph;
5179
5365
  return {
5180
5366
  "StyleSheet:exit"(node) {
5181
- const registersTailwind = node.children.some(
5182
- (child) => child.type === "Atrule" && child.name === "import" && JSON.stringify(child.prelude).includes("tailwindcss")
5183
- );
5184
- if (registersTailwind) return;
5367
+ if (globals.length === 0) return;
5368
+ const current = path44.normalize(path44.resolve(context.filename));
5369
+ if (globals.includes(current)) {
5370
+ if (globals.length > 1) {
5371
+ context.report({
5372
+ node,
5373
+ message: "Only one stylesheet may register Tailwind as the global entry point."
5374
+ });
5375
+ return;
5376
+ }
5377
+ const basename = path44.basename(current);
5378
+ const importCount = moduleFiles.filter((modulePath) => moduleImports(textOf(modulePath), basename)).length;
5379
+ if (importCount !== 1) {
5380
+ context.report({
5381
+ node,
5382
+ message: `The global stylesheet entry point must be imported by exactly one module (the root layout), but it is imported by ${String(importCount)} module(s).`
5383
+ });
5384
+ }
5385
+ return;
5386
+ }
5185
5387
  const hasProjectCss = node.children.some((child) => {
5186
5388
  if (child.type === "Atrule" && child.name === "import") return false;
5187
5389
  if (child.type === "Comment") return false;
5188
5390
  return true;
5189
5391
  });
5190
- if (!hasProjectCss) return;
5191
- context.report({
5192
- node,
5193
- message: "Global CSS must live in the global stylesheet entry point that registers Tailwind, not in this file."
5194
- });
5392
+ if (hasProjectCss && !directChildren.has(current)) {
5393
+ context.report({
5394
+ node,
5395
+ message: "Project CSS may only live in a stylesheet the global entry point imports directly; route it through a direct import or into the entry point."
5396
+ });
5397
+ return;
5398
+ }
5399
+ if (!reachable.has(current)) {
5400
+ context.report({
5401
+ node,
5402
+ message: "This stylesheet must be imported by the global stylesheet entry point via @import, so CSS arrives through one door."
5403
+ });
5404
+ }
5195
5405
  }
5196
5406
  };
5197
5407
  }
@@ -5209,10 +5419,10 @@ var globalStylesheetRule = {
5209
5419
  create(context) {
5210
5420
  return {
5211
5421
  "StyleSheet:exit"(node) {
5212
- const registersTailwind = node.children.some(
5422
+ const registersTailwind2 = node.children.some(
5213
5423
  (child) => child.type === "Atrule" && child.name === "import" && JSON.stringify(child.prelude).includes("tailwindcss")
5214
5424
  );
5215
- if (!registersTailwind) {
5425
+ if (!registersTailwind2) {
5216
5426
  const hasProjectCss = node.children.some((child) => {
5217
5427
  if (child.type === "Atrule" && child.name === "import") return false;
5218
5428
  if (child.type === "Comment") return false;
@@ -5231,32 +5441,9 @@ var globalStylesheetRule = {
5231
5441
  };
5232
5442
 
5233
5443
  // eslint/rules/tailwind/unused-utility.ts
5234
- import { readdirSync as readdirSync4, readFileSync as readFileSync7, statSync as statSync5 } from "fs";
5235
- import path41 from "path";
5236
- var SOURCE_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".css"];
5237
- function sourceFiles(dir) {
5238
- let entries;
5239
- try {
5240
- entries = readdirSync4(dir);
5241
- } catch {
5242
- return [];
5243
- }
5244
- return entries.flatMap((entry) => {
5245
- if (entry.startsWith(".") || entry === "node_modules") return [];
5246
- const entryPath = path41.join(dir, entry);
5247
- let stats;
5248
- try {
5249
- stats = statSync5(entryPath);
5250
- } catch {
5251
- return [];
5252
- }
5253
- if (stats.isDirectory()) return sourceFiles(entryPath);
5254
- return SOURCE_EXTENSIONS.includes(path41.extname(entry)) ? [entryPath] : [];
5255
- });
5256
- }
5444
+ import { statSync as statSync7 } from "fs";
5257
5445
  function usagePattern(name) {
5258
- const escaped = name.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
5259
- return new RegExp(`(?<![\\w-])${escaped}(?![\\w-])`);
5446
+ return new RegExp(`(?<![\\w-])${escapeRegExp(name)}(?![\\w-])`);
5260
5447
  }
5261
5448
  var unusedUtilityRule = {
5262
5449
  meta: {
@@ -5267,27 +5454,15 @@ var unusedUtilityRule = {
5267
5454
  }
5268
5455
  },
5269
5456
  create(context) {
5270
- const sourceRoot2 = path41.resolve("src");
5457
+ const sourceRoot = sourceRootOf(context);
5271
5458
  let files;
5272
5459
  try {
5273
- if (!statSync5(sourceRoot2).isDirectory()) return {};
5274
- files = sourceFiles(sourceRoot2);
5460
+ if (!statSync7(sourceRoot).isDirectory()) return {};
5461
+ files = findFiles(sourceRoot, SOURCE_EXTENSIONS);
5275
5462
  } catch {
5276
5463
  return {};
5277
5464
  }
5278
- const texts = /* @__PURE__ */ new Map();
5279
- const textOf = (file) => {
5280
- let text = texts.get(file);
5281
- if (text === void 0) {
5282
- try {
5283
- text = readFileSync7(file, "utf8");
5284
- } catch {
5285
- text = "";
5286
- }
5287
- texts.set(file, text);
5288
- }
5289
- return text;
5290
- };
5465
+ const textOf = cachedTextReader();
5291
5466
  return {
5292
5467
  "StyleSheet:exit"(node) {
5293
5468
  for (const utility of atrulesNamed(node, "utility")) {
@@ -5318,7 +5493,7 @@ var tailwindRules = {
5318
5493
  "custom-utility-apply": customUtilityApplyRule,
5319
5494
  "surface-utility": surfaceUtilityRule,
5320
5495
  "theme-variable-namespace": themeVariableNamespaceRule,
5321
- "global-css-location": globalCssLocationRule,
5496
+ "css-entry-point": cssEntryPointRule,
5322
5497
  "global-stylesheet": globalStylesheetRule,
5323
5498
  "unused-utility": unusedUtilityRule
5324
5499
  };
@@ -5462,13 +5637,13 @@ var repoPackageJsonRules = {
5462
5637
  "no-vulyk-dependency": noVulykDependencyRule,
5463
5638
  "exact-version": exactVersionRule
5464
5639
  };
5465
- var nextPackageJsonRules = {
5640
+ var nextjsPackageJsonRules = {
5466
5641
  "nextjs-stack": nextjsStackRule
5467
5642
  };
5468
5643
 
5469
5644
  // eslint/rules/husky/husky-hook.ts
5470
5645
  import { existsSync as existsSync2, readFileSync as readFileSync8 } from "fs";
5471
- import path42 from "path";
5646
+ import path45 from "path";
5472
5647
  function memberName4(member) {
5473
5648
  return member.name.type === "String" ? member.name.value : member.name.name;
5474
5649
  }
@@ -5487,7 +5662,7 @@ var huskyHookRule = {
5487
5662
  if (root.type !== "Object") return;
5488
5663
  const scriptName = context.filename;
5489
5664
  if (!scriptName.endsWith("package.json")) return;
5490
- const hookPath = path42.join(process.cwd(), ".husky", "pre-commit");
5665
+ const hookPath = path45.join(context.cwd, ".husky", "pre-commit");
5491
5666
  if (!existsSync2(hookPath)) {
5492
5667
  context.report({
5493
5668
  node,
@@ -5527,7 +5702,7 @@ var huskyRules = {
5527
5702
 
5528
5703
  // eslint/rules/vulyk/vulyk-docs.ts
5529
5704
  import { existsSync as existsSync3, readFileSync as readFileSync9 } from "fs";
5530
- import path43 from "path";
5705
+ import path46 from "path";
5531
5706
  var PASIKA_REPO = "Bredansky/pasika";
5532
5707
  var vulykDocsRule = {
5533
5708
  meta: {
@@ -5541,8 +5716,8 @@ var vulykDocsRule = {
5541
5716
  return {
5542
5717
  Document(node) {
5543
5718
  if (!context.filename.endsWith("package.json")) return;
5544
- const projectRoot = path43.dirname(path43.resolve(context.filename));
5545
- const configPath = path43.join(projectRoot, "vulyk.config.ts");
5719
+ const projectRoot = path46.dirname(path46.resolve(context.filename));
5720
+ const configPath = path46.join(projectRoot, "vulyk.config.ts");
5546
5721
  if (!existsSync3(configPath)) {
5547
5722
  context.report({
5548
5723
  node,
@@ -5557,7 +5732,7 @@ var vulykDocsRule = {
5557
5732
  message: "vulyk.config.ts must track the framework's docs from the pasika repository."
5558
5733
  });
5559
5734
  }
5560
- const agentsPath = path43.join(projectRoot, "AGENTS.md");
5735
+ const agentsPath = path46.join(projectRoot, "AGENTS.md");
5561
5736
  if (!existsSync3(agentsPath)) {
5562
5737
  context.report({
5563
5738
  node,
@@ -5575,7 +5750,8 @@ var vulykRules = {
5575
5750
  };
5576
5751
 
5577
5752
  // eslint/index.ts
5578
- var typescriptAppRules = {
5753
+ var nextjsAppRules = {
5754
+ // Framework-agnostic TypeScript rules.
5579
5755
  "filename-case": filenameCaseRule,
5580
5756
  "import-boundaries": importBoundariesRule,
5581
5757
  "named-exports": namedExportsRule,
@@ -5590,9 +5766,8 @@ var typescriptAppRules = {
5590
5766
  "type-extraction": typeExtractionRule,
5591
5767
  "zod-schema-validation": zodSchemaValidationRule,
5592
5768
  "source-under-src": sourceUnderSrcRule,
5593
- "zirka-baseline": zirkaBaselineRule
5594
- };
5595
- var nextjsAppRules = {
5769
+ "zirka-baseline": zirkaBaselineRule,
5770
+ // Next.js/React application rules.
5596
5771
  "component-placement": componentPlacementRule,
5597
5772
  "application-structure": applicationStructureRule,
5598
5773
  "data-testid-case": dataTestIdCaseRule,
@@ -5621,58 +5796,56 @@ var nextjsAppRules = {
5621
5796
  "shared-style-dedup": sharedStyleDedupRule,
5622
5797
  "repeated-structure": repeatedStructureRule
5623
5798
  };
5624
- var pasikaRules = {
5625
- ...typescriptAppRules,
5626
- ...nextjsAppRules
5627
- };
5628
5799
  var pasikaPlugin = {
5629
5800
  rules: {
5630
- ...pasikaRules,
5801
+ // The shared plugin must register every rule the preset blocks reference,
5802
+ // so all rule sets live here.
5803
+ ...nextjsAppRules,
5631
5804
  ...documentationRules,
5632
5805
  ...tailwindRules,
5633
5806
  ...repoPackageJsonRules,
5634
- ...nextPackageJsonRules,
5807
+ ...nextjsPackageJsonRules,
5635
5808
  ...huskyRules,
5636
5809
  ...vulykRules
5637
5810
  }
5638
5811
  };
5639
- var jsonLanguagePlugin = { languages: { json: jsonPlugin.languages.json } };
5812
+ var jsonLanguage = { languages: { json: jsonPlugin.languages.json } };
5640
5813
  function ruleIds(rules2) {
5641
5814
  return Object.keys(rules2).map((name) => `pasika/${name}`);
5642
5815
  }
5643
- var typescriptAppRuleIds = ruleIds(typescriptAppRules);
5644
5816
  var nextjsAppRuleIds = ruleIds(nextjsAppRules);
5645
- var pasikaRuleIds = ruleIds(pasikaRules);
5646
5817
  var documentationRuleIds = ruleIds(documentationRules);
5647
5818
  var tailwindRuleIds = ruleIds(tailwindRules);
5648
5819
  var repoPackageJsonRuleIds = ruleIds(repoPackageJsonRules);
5649
- var nextPackageJsonRuleIds = ruleIds(nextPackageJsonRules);
5820
+ var nextjsPackageJsonRuleIds = ruleIds(nextjsPackageJsonRules);
5650
5821
  var huskyRuleIds = ruleIds(huskyRules);
5651
5822
  var vulykRuleIds = ruleIds(vulykRules);
5652
5823
  var allPasikaRuleIds = [
5653
- ...pasikaRuleIds,
5824
+ ...nextjsAppRuleIds,
5654
5825
  ...documentationRuleIds,
5655
5826
  ...tailwindRuleIds,
5656
5827
  ...repoPackageJsonRuleIds,
5657
- ...nextPackageJsonRuleIds,
5828
+ ...nextjsPackageJsonRuleIds,
5658
5829
  ...huskyRuleIds,
5659
5830
  ...vulykRuleIds
5660
5831
  ];
5661
- var typescriptAppBlock = {
5662
- files: ["src/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx}"],
5663
- plugins: {
5664
- pasika: pasikaPlugin
5665
- },
5666
- rules: Object.fromEntries(typescriptAppRuleIds.map((id) => [id, "error"]))
5832
+ var typescriptAppLanguageOptions = {
5833
+ parser: tsParser,
5834
+ parserOptions: {
5835
+ ecmaVersion: "latest",
5836
+ sourceType: "module",
5837
+ ecmaFeatures: { jsx: true }
5838
+ }
5667
5839
  };
5668
- var nextjsAppBlock = {
5840
+ var nextjsAppConfig = {
5669
5841
  files: ["src/**/*.{cjs,cts,js,jsx,mjs,mts,ts,tsx}"],
5842
+ languageOptions: typescriptAppLanguageOptions,
5670
5843
  plugins: {
5671
5844
  pasika: pasikaPlugin
5672
5845
  },
5673
5846
  rules: Object.fromEntries(nextjsAppRuleIds.map((id) => [id, "error"]))
5674
5847
  };
5675
- var tailwindGlobalsBlock = {
5848
+ var tailwindStructureRules = {
5676
5849
  files: ["src/**/globals.css"],
5677
5850
  plugins: {
5678
5851
  css,
@@ -5681,10 +5854,10 @@ var tailwindGlobalsBlock = {
5681
5854
  language: "css/css",
5682
5855
  languageOptions: { tolerant: true },
5683
5856
  rules: Object.fromEntries(
5684
- tailwindRuleIds.filter((id) => id !== "pasika/global-css-location").map((id) => [id, "error"])
5857
+ tailwindRuleIds.filter((id) => id !== "pasika/css-entry-point").map((id) => [id, "error"])
5685
5858
  )
5686
5859
  };
5687
- var tailwindAnyCssBlock = {
5860
+ var tailwindImportGraph = {
5688
5861
  files: ["src/**/*.css"],
5689
5862
  plugins: {
5690
5863
  css,
@@ -5692,32 +5865,32 @@ var tailwindAnyCssBlock = {
5692
5865
  },
5693
5866
  language: "css/css",
5694
5867
  languageOptions: { tolerant: true },
5695
- rules: { "pasika/global-css-location": "error" }
5868
+ rules: { "pasika/css-entry-point": "error" }
5696
5869
  };
5697
- var repoManifestBlock = {
5870
+ var typescriptAppPackageJsonConfig = {
5698
5871
  files: ["package.json"],
5699
5872
  plugins: {
5700
- json: jsonLanguagePlugin,
5873
+ json: jsonLanguage,
5701
5874
  pasika: pasikaPlugin
5702
5875
  },
5703
5876
  language: "json/json",
5704
5877
  rules: Object.fromEntries([...repoPackageJsonRuleIds, ...huskyRuleIds, ...vulykRuleIds].map((id) => [id, "error"]))
5705
5878
  };
5706
- var nextManifestBlock = {
5879
+ var nextjsAppPackageJsonConfig = {
5707
5880
  files: ["package.json"],
5708
5881
  plugins: {
5709
- json: jsonLanguagePlugin,
5882
+ json: jsonLanguage,
5710
5883
  pasika: pasikaPlugin
5711
5884
  },
5712
5885
  language: "json/json",
5713
- rules: Object.fromEntries(nextPackageJsonRuleIds.map((id) => [id, "error"]))
5886
+ rules: Object.fromEntries(nextjsPackageJsonRuleIds.map((id) => [id, "error"]))
5714
5887
  };
5715
- var zirkaBlock = {
5888
+ var zirkaConfig = {
5716
5889
  files: ["eslint.config.{ts,mts,cts,js,mjs,cjs}"],
5717
5890
  plugins: { pasika: pasikaPlugin },
5718
5891
  rules: { "pasika/zirka-baseline": "error" }
5719
5892
  };
5720
- var docsBlock = {
5893
+ var documentationConfig = {
5721
5894
  files: ["docs/**/*.md"],
5722
5895
  ignores: ["**/_*/**"],
5723
5896
  plugins: {
@@ -5727,22 +5900,25 @@ var docsBlock = {
5727
5900
  language: "markdown/gfm",
5728
5901
  rules: Object.fromEntries(documentationRuleIds.map((id) => [id, "error"]))
5729
5902
  };
5730
- var typescriptApp = [repoManifestBlock, zirkaBlock, typescriptAppBlock, docsBlock];
5903
+ var typescriptApp = [
5904
+ typescriptAppPackageJsonConfig,
5905
+ zirkaConfig,
5906
+ documentationConfig
5907
+ ];
5731
5908
  var nextjsApp = [
5732
5909
  ...typescriptApp,
5733
- nextManifestBlock,
5734
- nextjsAppBlock,
5735
- tailwindGlobalsBlock,
5736
- tailwindAnyCssBlock
5910
+ nextjsAppPackageJsonConfig,
5911
+ nextjsAppConfig,
5912
+ tailwindStructureRules,
5913
+ tailwindImportGraph
5737
5914
  ];
5738
5915
  export {
5739
5916
  allPasikaRuleIds,
5740
5917
  documentationRules,
5741
5918
  huskyRules,
5742
- nextPackageJsonRules,
5743
5919
  nextjsApp,
5920
+ nextjsPackageJsonRules,
5744
5921
  pasikaPlugin,
5745
- pasikaRules,
5746
5922
  repoPackageJsonRules,
5747
5923
  tailwindRules,
5748
5924
  typescriptApp,