uilint-eslint 0.1.1 → 0.1.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -86,6 +86,48 @@ declare function clearCacheEntry(projectRoot: string, filePath: string): void;
86
86
  */
87
87
  declare function clearCache(projectRoot: string): void;
88
88
 
89
+ /**
90
+ * Rule Registry
91
+ *
92
+ * Central registry of all UILint ESLint rules with metadata for CLI tooling.
93
+ * This allows the installer to auto-discover available rules and present them
94
+ * to the user with descriptions.
95
+ */
96
+ interface RuleMetadata {
97
+ /** Rule identifier (e.g., "no-arbitrary-tailwind") */
98
+ id: string;
99
+ /** Display name for CLI */
100
+ name: string;
101
+ /** Short description for CLI selection prompts */
102
+ description: string;
103
+ /** Default severity level */
104
+ defaultSeverity: "error" | "warn" | "off";
105
+ /** Default options for the rule */
106
+ defaultOptions?: unknown[];
107
+ /** Whether this rule requires a styleguide file */
108
+ requiresStyleguide?: boolean;
109
+ /** Category for grouping */
110
+ category: "static" | "semantic";
111
+ }
112
+ /**
113
+ * Registry of all available UILint ESLint rules
114
+ *
115
+ * When adding a new rule:
116
+ * 1. Add the rule implementation to src/rules/
117
+ * 2. Add an entry here with metadata
118
+ * 3. Export the rule from src/index.ts
119
+ * 4. The CLI installer will automatically discover and offer it
120
+ */
121
+ declare const ruleRegistry: RuleMetadata[];
122
+ /**
123
+ * Get rule metadata by ID
124
+ */
125
+ declare function getRuleMetadata(id: string): RuleMetadata | undefined;
126
+ /**
127
+ * Get all rules in a category
128
+ */
129
+ declare function getRulesByCategory(category: "static" | "semantic"): RuleMetadata[];
130
+
89
131
  /**
90
132
  * All available rules
91
133
  */
@@ -175,4 +217,4 @@ interface UILintESLint {
175
217
  */
176
218
  declare const uilintEslint: UILintESLint;
177
219
 
178
- export { type CacheEntry, type CacheStore, type CachedIssue, type UILintESLint, clearCache, clearCacheEntry, configs, createRule, uilintEslint as default, findStyleguidePath, getCacheEntry, getStyleguide, hashContent, hashContentSync, loadCache, loadStyleguide, meta, plugin, rules, saveCache, setCacheEntry };
220
+ export { type CacheEntry, type CacheStore, type CachedIssue, type RuleMetadata, type UILintESLint, clearCache, clearCacheEntry, configs, createRule, uilintEslint as default, findStyleguidePath, getCacheEntry, getRuleMetadata, getRulesByCategory, getStyleguide, hashContent, hashContentSync, loadCache, loadStyleguide, meta, plugin, ruleRegistry, rules, saveCache, setCacheEntry };
package/dist/index.js CHANGED
@@ -1,10 +1,3 @@
1
- var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
- get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
- }) : x)(function(x) {
4
- if (typeof require !== "undefined") return require.apply(this, arguments);
5
- throw Error('Dynamic require of "' + x + '" is not supported');
6
- });
7
-
8
1
  // src/utils/create-rule.ts
9
2
  import { ESLintUtils } from "@typescript-eslint/utils";
10
3
  var createRule = ESLintUtils.RuleCreator(
@@ -329,7 +322,7 @@ var no_mixed_component_libraries_default = createRule({
329
322
  properties: {
330
323
  libraries: {
331
324
  type: "array",
332
- items: { enum: ["shadcn", "mui"] }
325
+ items: { type: "string", enum: ["shadcn", "mui"] }
333
326
  }
334
327
  },
335
328
  additionalProperties: false
@@ -370,8 +363,9 @@ var no_mixed_component_libraries_default = createRule({
370
363
  });
371
364
 
372
365
  // src/rules/semantic.ts
373
- import { readFileSync as readFileSync3 } from "fs";
374
- import { dirname as dirname3, relative } from "path";
366
+ import { existsSync as existsSync3, readFileSync as readFileSync3 } from "fs";
367
+ import { spawnSync } from "child_process";
368
+ import { dirname as dirname3, join as join3, relative } from "path";
375
369
 
376
370
  // src/utils/cache.ts
377
371
  import { existsSync, mkdirSync, readFileSync, writeFileSync } from "fs";
@@ -477,11 +471,31 @@ function findWorkspaceRoot(startDir) {
477
471
  }
478
472
  return startDir;
479
473
  }
474
+ function findNearestPackageRoot(startDir, workspaceRoot) {
475
+ let dir = startDir;
476
+ for (let i = 0; i < 30; i++) {
477
+ if (existsSync2(join2(dir, "package.json"))) return dir;
478
+ if (dir === workspaceRoot) break;
479
+ const parent = dirname2(dir);
480
+ if (parent === dir) break;
481
+ dir = parent;
482
+ }
483
+ return startDir;
484
+ }
480
485
  function findStyleguidePath(startDir, explicitPath) {
481
486
  if (explicitPath) {
482
- const resolved = isAbsolute(explicitPath) ? explicitPath : resolve(startDir, explicitPath);
483
- if (existsSync2(resolved)) {
484
- return resolved;
487
+ if (isAbsolute(explicitPath)) {
488
+ return existsSync2(explicitPath) ? explicitPath : null;
489
+ }
490
+ const workspaceRoot2 = findWorkspaceRoot(startDir);
491
+ const packageRoot = findNearestPackageRoot(startDir, workspaceRoot2);
492
+ const candidates = [
493
+ resolve(startDir, explicitPath),
494
+ resolve(packageRoot, explicitPath),
495
+ resolve(workspaceRoot2, explicitPath)
496
+ ];
497
+ for (const p of candidates) {
498
+ if (existsSync2(p)) return p;
485
499
  }
486
500
  return null;
487
501
  }
@@ -522,7 +536,8 @@ function getStyleguide(startDir, explicitPath) {
522
536
  }
523
537
 
524
538
  // src/rules/semantic.ts
525
- var pendingAnalysis = /* @__PURE__ */ new Map();
539
+ import { UILINT_DEFAULT_OLLAMA_MODEL } from "uilint-core";
540
+ import { buildSourceScanPrompt } from "uilint-core";
526
541
  var semantic_default = createRule({
527
542
  name: "semantic",
528
543
  meta: {
@@ -552,7 +567,7 @@ var semantic_default = createRule({
552
567
  }
553
568
  ]
554
569
  },
555
- defaultOptions: [{ model: "qwen3:8b" }],
570
+ defaultOptions: [{ model: UILINT_DEFAULT_OLLAMA_MODEL }],
556
571
  create(context) {
557
572
  const options = context.options[0] || {};
558
573
  const filePath = context.filename;
@@ -562,6 +577,11 @@ var semantic_default = createRule({
562
577
  options.styleguidePath
563
578
  );
564
579
  if (!styleguide) {
580
+ console.error(
581
+ `[uilint] Styleguide not found (styleguidePath=${String(
582
+ options.styleguidePath ?? ""
583
+ )}, startDir=${fileDir})`
584
+ );
565
585
  return {
566
586
  Program(node) {
567
587
  context.report({
@@ -575,7 +595,16 @@ var semantic_default = createRule({
575
595
  try {
576
596
  fileContent = readFileSync3(filePath, "utf-8");
577
597
  } catch {
578
- return {};
598
+ console.error(`[uilint] Failed to read file ${filePath}`);
599
+ return {
600
+ Program(node) {
601
+ context.report({
602
+ node,
603
+ messageId: "analysisError",
604
+ data: { error: `Failed to read source file ${filePath}` }
605
+ });
606
+ }
607
+ };
579
608
  }
580
609
  const fileHash = hashContentSync(fileContent);
581
610
  const styleguideHash = hashContentSync(styleguide);
@@ -587,7 +616,9 @@ var semantic_default = createRule({
587
616
  fileHash,
588
617
  styleguideHash
589
618
  );
590
- if (cached) {
619
+ const ENABLE_CACHE = false;
620
+ if (ENABLE_CACHE && cached) {
621
+ console.error(`[uilint] Cache hit for ${filePath}`);
591
622
  return {
592
623
  Program(node) {
593
624
  for (const issue of cached.issues) {
@@ -601,67 +632,199 @@ var semantic_default = createRule({
601
632
  }
602
633
  };
603
634
  }
604
- if (!pendingAnalysis.has(filePath)) {
605
- const analysisPromise = runSemanticAnalysis(
606
- fileContent,
607
- styleguide,
608
- options.model || "qwen3:8b"
609
- );
610
- pendingAnalysis.set(filePath, analysisPromise);
611
- analysisPromise.then((issues) => {
635
+ ENABLE_CACHE && console.error(
636
+ `[uilint] Cache miss for ${filePath}, running semantic analysis`
637
+ );
638
+ return {
639
+ Program(node) {
640
+ const issues = runSemanticAnalysisSync(
641
+ fileContent,
642
+ styleguide,
643
+ options.model || UILINT_DEFAULT_OLLAMA_MODEL,
644
+ filePath
645
+ );
612
646
  setCacheEntry(projectRoot, relativeFilePath, {
613
647
  fileHash,
614
648
  styleguideHash,
615
649
  issues,
616
650
  timestamp: Date.now()
617
651
  });
618
- }).catch(() => {
619
- }).finally(() => {
620
- pendingAnalysis.delete(filePath);
621
- });
622
- }
623
- return {};
652
+ for (const issue of issues) {
653
+ context.report({
654
+ node,
655
+ loc: { line: issue.line, column: issue.column || 0 },
656
+ messageId: "semanticIssue",
657
+ data: { message: issue.message }
658
+ });
659
+ }
660
+ }
661
+ };
624
662
  }
625
663
  });
626
664
  function findProjectRoot(startDir) {
627
- const { existsSync: existsSync3 } = __require("fs");
628
- const { dirname: dirname4, join: join3 } = __require("path");
629
665
  let dir = startDir;
630
666
  for (let i = 0; i < 20; i++) {
631
667
  if (existsSync3(join3(dir, "package.json"))) {
632
668
  return dir;
633
669
  }
634
- const parent = dirname4(dir);
670
+ const parent = dirname3(dir);
635
671
  if (parent === dir) break;
636
672
  dir = parent;
637
673
  }
638
674
  return startDir;
639
675
  }
640
- async function runSemanticAnalysis(sourceCode, styleguide, model) {
641
- try {
642
- const { OllamaClient, buildSourceScanPrompt } = await import("uilint-core");
676
+ function runSemanticAnalysisSync(sourceCode, styleguide, model, filePath) {
677
+ const startTime = Date.now();
678
+ const fileDisplay = filePath ? ` ${filePath}` : "";
679
+ console.error(`[uilint] Starting semantic analysis (sync)${fileDisplay}`);
680
+ console.error(`[uilint] Model: ${model}`);
681
+ const prompt = buildSourceScanPrompt(sourceCode, styleguide, {});
682
+ const coreNodeUrl = new URL(
683
+ "../node_modules/uilint-core/dist/node.js",
684
+ import.meta.url
685
+ ).href;
686
+ const childScript = `
687
+ import * as coreNode from ${JSON.stringify(coreNodeUrl)};
688
+ const { OllamaClient, logInfo, logWarning, createProgress, pc } = coreNode;
689
+ const chunks = [];
690
+ for await (const c of process.stdin) chunks.push(c);
691
+ const input = JSON.parse(Buffer.concat(chunks).toString("utf8"));
692
+ const model = input.model;
693
+ const prompt = input.prompt;
694
+
643
695
  const client = new OllamaClient({ model });
644
- const available = await client.isAvailable();
645
- if (!available) {
646
- console.warn("[uilint-eslint] Ollama not available, skipping semantic analysis");
647
- return [];
696
+ const ok = await client.isAvailable();
697
+ if (!ok) {
698
+ logWarning("Ollama not available, skipping semantic analysis");
699
+ process.stdout.write(JSON.stringify({ issues: [] }));
700
+ process.exit(0);
701
+ }
702
+
703
+ logInfo(\`Ollama connected \${pc.dim(\`(model: \${model})\`)}\`);
704
+ const progress = createProgress("Analyzing with LLM...");
705
+ try {
706
+ const response = await client.complete(prompt, {
707
+ json: true,
708
+ stream: true,
709
+ onProgress: (latestLine) => {
710
+ const maxLen = 60;
711
+ const display =
712
+ latestLine.length > maxLen
713
+ ? latestLine.slice(0, maxLen) + "\u2026"
714
+ : latestLine;
715
+ progress.update(\`LLM: \${pc.dim(display || "...")}\`);
716
+ },
717
+ });
718
+ progress.succeed("LLM complete");
719
+ process.stdout.write(response);
720
+ } catch (e) {
721
+ progress.fail(\`LLM failed: \${e instanceof Error ? e.message : String(e)}\`);
722
+ process.exit(1);
723
+ }
724
+ `;
725
+ const child = spawnSync(
726
+ process.execPath,
727
+ ["--input-type=module", "-e", childScript],
728
+ {
729
+ input: JSON.stringify({ model, prompt }),
730
+ encoding: "utf8",
731
+ stdio: ["pipe", "pipe", "inherit"],
732
+ maxBuffer: 20 * 1024 * 1024
648
733
  }
649
- const prompt = buildSourceScanPrompt(sourceCode, styleguide, {});
650
- const response = await client.complete(prompt, { json: true });
651
- const parsed = JSON.parse(response);
652
- return (parsed.issues || []).map((issue) => ({
734
+ );
735
+ const elapsed = Date.now() - startTime;
736
+ if (child.error) {
737
+ console.error(
738
+ `[uilint] Semantic analysis failed after ${elapsed}ms: ${child.error.message}`
739
+ );
740
+ return [];
741
+ }
742
+ if (typeof child.status === "number" && child.status !== 0) {
743
+ console.error(
744
+ `[uilint] Semantic analysis failed after ${elapsed}ms: child exited ${child.status}`
745
+ );
746
+ return [];
747
+ }
748
+ const responseText = (child.stdout || "").trim();
749
+ if (!responseText) {
750
+ console.error(
751
+ `[uilint] Semantic analysis returned empty response (${elapsed}ms)`
752
+ );
753
+ return [];
754
+ }
755
+ try {
756
+ const parsed = JSON.parse(responseText);
757
+ const issues = (parsed.issues || []).map((issue) => ({
653
758
  line: issue.line || 1,
654
759
  column: issue.column,
655
760
  message: issue.message || "Semantic issue detected",
656
761
  ruleId: "uilint/semantic",
657
762
  severity: 1
658
763
  }));
659
- } catch (error) {
660
- console.error("[uilint-eslint] Semantic analysis error:", error);
764
+ if (issues.length > 0) {
765
+ console.error(`[uilint] Found ${issues.length} issue(s) (${elapsed}ms)`);
766
+ } else {
767
+ console.error(`[uilint] No issues found (${elapsed}ms)`);
768
+ }
769
+ return issues;
770
+ } catch (e) {
771
+ console.error(
772
+ `[uilint] Semantic analysis failed to parse response after ${elapsed}ms: ${e instanceof Error ? e.message : String(e)}`
773
+ );
661
774
  return [];
662
775
  }
663
776
  }
664
777
 
778
+ // src/rule-registry.ts
779
+ var ruleRegistry = [
780
+ {
781
+ id: "no-arbitrary-tailwind",
782
+ name: "No Arbitrary Tailwind",
783
+ description: "Forbid arbitrary values like w-[123px], bg-[#fff]",
784
+ defaultSeverity: "error",
785
+ category: "static"
786
+ },
787
+ {
788
+ id: "consistent-spacing",
789
+ name: "Consistent Spacing",
790
+ description: "Enforce spacing scale (no magic numbers in gap/padding)",
791
+ defaultSeverity: "warn",
792
+ defaultOptions: [{ scale: [0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16] }],
793
+ category: "static"
794
+ },
795
+ {
796
+ id: "no-direct-store-import",
797
+ name: "No Direct Store Import",
798
+ description: "Forbid direct Zustand store imports (use context hooks)",
799
+ defaultSeverity: "warn",
800
+ defaultOptions: [{ storePattern: "use*Store" }],
801
+ category: "static"
802
+ },
803
+ {
804
+ id: "no-mixed-component-libraries",
805
+ name: "No Mixed Component Libraries",
806
+ description: "Forbid mixing component libraries (e.g., shadcn + MUI)",
807
+ defaultSeverity: "error",
808
+ defaultOptions: [{ libraries: ["shadcn", "mui"] }],
809
+ category: "static"
810
+ },
811
+ {
812
+ id: "semantic",
813
+ name: "Semantic Analysis",
814
+ description: "LLM-powered semantic UI analysis using your styleguide",
815
+ defaultSeverity: "warn",
816
+ defaultOptions: [{ model: "qwen3-coder:30b", styleguidePath: ".uilint/styleguide.md" }],
817
+ requiresStyleguide: true,
818
+ category: "semantic"
819
+ }
820
+ ];
821
+ function getRuleMetadata(id) {
822
+ return ruleRegistry.find((rule) => rule.id === id);
823
+ }
824
+ function getRulesByCategory(category) {
825
+ return ruleRegistry.filter((rule) => rule.category === category);
826
+ }
827
+
665
828
  // src/index.ts
666
829
  var version = "0.1.0";
667
830
  var rules = {
@@ -734,6 +897,8 @@ export {
734
897
  index_default as default,
735
898
  findStyleguidePath,
736
899
  getCacheEntry,
900
+ getRuleMetadata,
901
+ getRulesByCategory,
737
902
  getStyleguide,
738
903
  hashContent,
739
904
  hashContentSync,
@@ -741,6 +906,7 @@ export {
741
906
  loadStyleguide,
742
907
  meta,
743
908
  plugin,
909
+ ruleRegistry,
744
910
  rules,
745
911
  saveCache,
746
912
  setCacheEntry
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/utils/create-rule.ts","../src/rules/no-arbitrary-tailwind.ts","../src/rules/consistent-spacing.ts","../src/rules/no-direct-store-import.ts","../src/rules/no-mixed-component-libraries.ts","../src/rules/semantic.ts","../src/utils/cache.ts","../src/utils/styleguide-loader.ts","../src/index.ts"],"sourcesContent":["/**\n * Rule creation helper using @typescript-eslint/utils\n */\n\nimport { ESLintUtils } from \"@typescript-eslint/utils\";\n\nexport const createRule = ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/peter-suggate/uilint/blob/main/packages/uilint-eslint/docs/rules/${name}.md`\n);\n","/**\n * Rule: no-arbitrary-tailwind\n *\n * Forbids arbitrary Tailwind values like w-[123px], bg-[#fff], etc.\n */\n\nimport { createRule } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"noArbitraryValue\";\ntype Options = [];\n\n// Regex to match arbitrary Tailwind values: word-[anything]\nconst ARBITRARY_VALUE_REGEX = /\\b[\\w-]+-\\[[^\\]]+\\]/g;\n\nexport default createRule<Options, MessageIds>({\n name: \"no-arbitrary-tailwind\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Forbid arbitrary Tailwind values like w-[123px]\",\n },\n messages: {\n noArbitraryValue:\n \"Avoid arbitrary Tailwind value '{{value}}'. Use the spacing/color scale instead.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n return {\n // Check className attributes in JSX\n JSXAttribute(node) {\n if (\n node.name.type === \"JSXIdentifier\" &&\n (node.name.name === \"className\" || node.name.name === \"class\")\n ) {\n const value = node.value;\n\n // Handle string literal: className=\"...\"\n if (value?.type === \"Literal\" && typeof value.value === \"string\") {\n checkClassString(context, value, value.value);\n }\n\n // Handle JSX expression: className={...}\n if (value?.type === \"JSXExpressionContainer\") {\n const expr = value.expression;\n\n // Direct string: className={\"...\"}\n if (expr.type === \"Literal\" && typeof expr.value === \"string\") {\n checkClassString(context, expr, expr.value);\n }\n\n // Template literal: className={`...`}\n if (expr.type === \"TemplateLiteral\") {\n for (const quasi of expr.quasis) {\n checkClassString(context, quasi, quasi.value.raw);\n }\n }\n }\n }\n },\n\n // Check cn(), clsx(), classnames() calls\n CallExpression(node) {\n if (node.callee.type !== \"Identifier\") return;\n const name = node.callee.name;\n\n if (name === \"cn\" || name === \"clsx\" || name === \"classnames\") {\n for (const arg of node.arguments) {\n if (arg.type === \"Literal\" && typeof arg.value === \"string\") {\n checkClassString(context, arg, arg.value);\n }\n if (arg.type === \"TemplateLiteral\") {\n for (const quasi of arg.quasis) {\n checkClassString(context, quasi, quasi.value.raw);\n }\n }\n }\n }\n },\n };\n },\n});\n\nfunction checkClassString(\n context: Parameters<\n ReturnType<typeof createRule<[], \"noArbitraryValue\">>[\"create\"]\n >[0],\n node: Parameters<typeof context.report>[0][\"node\"],\n classString: string\n) {\n const matches = classString.matchAll(ARBITRARY_VALUE_REGEX);\n\n for (const match of matches) {\n context.report({\n node,\n messageId: \"noArbitraryValue\",\n data: { value: match[0] },\n });\n }\n}\n","/**\n * Rule: consistent-spacing\n *\n * Enforces use of spacing scale values in gap, padding, margin utilities.\n */\n\nimport { createRule } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"invalidSpacing\";\ntype Options = [\n {\n scale?: number[];\n }\n];\n\n// Default Tailwind spacing scale\nconst DEFAULT_SCALE = [\n 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 24,\n 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 96,\n];\n\n// Spacing utilities that take numeric values\nconst SPACING_PREFIXES = [\n \"p-\",\n \"px-\",\n \"py-\",\n \"pt-\",\n \"pr-\",\n \"pb-\",\n \"pl-\",\n \"ps-\",\n \"pe-\",\n \"m-\",\n \"mx-\",\n \"my-\",\n \"mt-\",\n \"mr-\",\n \"mb-\",\n \"ml-\",\n \"ms-\",\n \"me-\",\n \"gap-\",\n \"gap-x-\",\n \"gap-y-\",\n \"space-x-\",\n \"space-y-\",\n \"inset-\",\n \"inset-x-\",\n \"inset-y-\",\n \"top-\",\n \"right-\",\n \"bottom-\",\n \"left-\",\n \"w-\",\n \"h-\",\n \"min-w-\",\n \"min-h-\",\n \"max-w-\",\n \"max-h-\",\n \"size-\",\n];\n\n// Build regex to match spacing utilities with numeric values\nfunction buildSpacingRegex(): RegExp {\n const prefixes = SPACING_PREFIXES.map((p) => p.replace(\"-\", \"\\\\-\")).join(\"|\");\n // Match prefix followed by a number (possibly with decimal)\n return new RegExp(`\\\\b(${prefixes})(\\\\d+\\\\.?\\\\d*)\\\\b`, \"g\");\n}\n\nconst SPACING_REGEX = buildSpacingRegex();\n\nexport default createRule<Options, MessageIds>({\n name: \"consistent-spacing\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Enforce spacing scale (no magic numbers in gap/padding)\",\n },\n messages: {\n invalidSpacing:\n \"Spacing value '{{value}}' is not in the allowed scale. Use one of: {{allowed}}\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n scale: {\n type: \"array\",\n items: { type: \"number\" },\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ scale: DEFAULT_SCALE }],\n create(context) {\n const options = context.options[0] || {};\n const scale = new Set((options.scale || DEFAULT_SCALE).map(String));\n const scaleList = [...scale].slice(0, 10).join(\", \") + \"...\";\n\n return {\n // Check className attributes in JSX\n JSXAttribute(node) {\n if (\n node.name.type === \"JSXIdentifier\" &&\n (node.name.name === \"className\" || node.name.name === \"class\")\n ) {\n const value = node.value;\n\n if (value?.type === \"Literal\" && typeof value.value === \"string\") {\n checkSpacing(context, node, value.value, scale, scaleList);\n }\n\n if (value?.type === \"JSXExpressionContainer\") {\n const expr = value.expression;\n if (expr.type === \"Literal\" && typeof expr.value === \"string\") {\n checkSpacing(context, node, expr.value, scale, scaleList);\n }\n if (expr.type === \"TemplateLiteral\") {\n for (const quasi of expr.quasis) {\n checkSpacing(context, node, quasi.value.raw, scale, scaleList);\n }\n }\n }\n }\n },\n\n // Check cn(), clsx(), classnames() calls\n CallExpression(node) {\n if (node.callee.type !== \"Identifier\") return;\n const name = node.callee.name;\n\n if (name === \"cn\" || name === \"clsx\" || name === \"classnames\") {\n for (const arg of node.arguments) {\n if (arg.type === \"Literal\" && typeof arg.value === \"string\") {\n checkSpacing(context, arg, arg.value, scale, scaleList);\n }\n if (arg.type === \"TemplateLiteral\") {\n for (const quasi of arg.quasis) {\n checkSpacing(context, quasi, quasi.value.raw, scale, scaleList);\n }\n }\n }\n }\n },\n };\n },\n});\n\nfunction checkSpacing(\n context: Parameters<\n ReturnType<typeof createRule<Options, \"invalidSpacing\">>[\"create\"]\n >[0],\n node: Parameters<typeof context.report>[0][\"node\"],\n classString: string,\n scale: Set<string>,\n scaleList: string\n) {\n // Reset regex state\n SPACING_REGEX.lastIndex = 0;\n\n let match;\n while ((match = SPACING_REGEX.exec(classString)) !== null) {\n const [, , value] = match;\n if (value && !scale.has(value)) {\n context.report({\n node,\n messageId: \"invalidSpacing\",\n data: { value, allowed: scaleList },\n });\n }\n }\n}\n","/**\n * Rule: no-direct-store-import\n *\n * Forbids direct Zustand store imports - prefer using hooks via context.\n */\n\nimport { createRule } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"noDirectImport\";\ntype Options = [\n {\n storePattern?: string;\n }\n];\n\n// Convert glob pattern to regex\nfunction patternToRegex(pattern: string): RegExp {\n const escaped = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\");\n return new RegExp(`^${escaped}$`);\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-direct-store-import\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Forbid direct Zustand store imports (use hooks via context)\",\n },\n messages: {\n noDirectImport:\n \"Avoid importing store '{{name}}' directly. Use the store via a context hook instead.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n storePattern: {\n type: \"string\",\n description: \"Glob pattern for store names\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ storePattern: \"use*Store\" }],\n create(context) {\n const options = context.options[0] || {};\n const pattern = options.storePattern || \"use*Store\";\n const regex = patternToRegex(pattern);\n\n return {\n ImportDeclaration(node) {\n // Check if importing from a store file\n const source = node.source.value as string;\n if (!source.includes(\"store\")) return;\n\n // Check imported specifiers\n for (const specifier of node.specifiers) {\n if (specifier.type === \"ImportSpecifier\") {\n const importedName =\n specifier.imported.type === \"Identifier\"\n ? specifier.imported.name\n : specifier.imported.value;\n\n if (regex.test(importedName)) {\n context.report({\n node: specifier,\n messageId: \"noDirectImport\",\n data: { name: importedName },\n });\n }\n }\n\n if (specifier.type === \"ImportDefaultSpecifier\") {\n const localName = specifier.local.name;\n if (regex.test(localName)) {\n context.report({\n node: specifier,\n messageId: \"noDirectImport\",\n data: { name: localName },\n });\n }\n }\n }\n },\n };\n },\n});\n","/**\n * Rule: no-mixed-component-libraries\n *\n * Forbids mixing shadcn/ui and MUI components in the same file.\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { createRule } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"mixedLibraries\";\ntype LibraryName = \"shadcn\" | \"mui\";\ntype Options = [\n {\n libraries?: LibraryName[];\n }\n];\n\nconst LIBRARY_PATTERNS: Record<LibraryName, string[]> = {\n shadcn: [\"@/components/ui\", \"@radix-ui/\", \"components/ui/\"],\n mui: [\"@mui/material\", \"@mui/icons-material\", \"@emotion/\"],\n};\n\nexport default createRule<Options, MessageIds>({\n name: \"no-mixed-component-libraries\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Forbid mixing component libraries in the same file\",\n },\n messages: {\n mixedLibraries:\n \"Mixing {{lib1}} and {{lib2}} components. Choose one library per file.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n libraries: {\n type: \"array\",\n items: { enum: [\"shadcn\", \"mui\"] },\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ libraries: [\"shadcn\", \"mui\"] }],\n create(context) {\n const options = context.options[0] || {};\n const libraries = (options.libraries || [\"shadcn\", \"mui\"]) as LibraryName[];\n const detected: Map<LibraryName, TSESTree.ImportDeclaration> = new Map();\n\n return {\n ImportDeclaration(node) {\n const source = node.source.value as string;\n\n for (const lib of libraries) {\n const patterns = LIBRARY_PATTERNS[lib];\n if (patterns?.some((p) => source.includes(p))) {\n if (!detected.has(lib)) {\n detected.set(lib, node);\n }\n }\n }\n },\n\n \"Program:exit\"() {\n if (detected.size > 1) {\n const libs = [...detected.keys()];\n const secondLib = libs[1]!;\n const secondNode = detected.get(secondLib)!;\n\n context.report({\n node: secondNode,\n messageId: \"mixedLibraries\",\n data: { lib1: libs[0], lib2: secondLib },\n });\n }\n },\n };\n },\n});\n","/**\n * Rule: semantic\n *\n * LLM-powered semantic UI analysis using the project's styleguide.\n * This is the only rule that reads .uilint/styleguide.md.\n */\n\nimport { readFileSync } from \"fs\";\nimport { dirname, relative } from \"path\";\nimport { createRule } from \"../utils/create-rule.js\";\nimport {\n getCacheEntry,\n hashContentSync,\n setCacheEntry,\n type CachedIssue,\n} from \"../utils/cache.js\";\nimport { getStyleguide } from \"../utils/styleguide-loader.js\";\n\ntype MessageIds = \"semanticIssue\" | \"styleguideNotFound\" | \"analysisError\";\ntype Options = [\n {\n model?: string;\n styleguidePath?: string;\n },\n];\n\n// Store for async analysis results that will be reported on next lint\nconst pendingAnalysis = new Map<string, Promise<CachedIssue[]>>();\n\nexport default createRule<Options, MessageIds>({\n name: \"semantic\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"LLM-powered semantic UI analysis using styleguide\",\n },\n messages: {\n semanticIssue: \"{{message}}\",\n styleguideNotFound:\n \"No styleguide found. Create .uilint/styleguide.md or specify styleguidePath.\",\n analysisError: \"Semantic analysis failed: {{error}}\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n model: {\n type: \"string\",\n description: \"Ollama model to use\",\n },\n styleguidePath: {\n type: \"string\",\n description: \"Path to styleguide file\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ model: \"qwen3:8b\" }],\n create(context) {\n const options = context.options[0] || {};\n const filePath = context.filename;\n const fileDir = dirname(filePath);\n\n // Get styleguide\n const { path: styleguidePath, content: styleguide } = getStyleguide(\n fileDir,\n options.styleguidePath\n );\n\n // Skip if no styleguide\n if (!styleguide) {\n return {\n Program(node) {\n context.report({\n node,\n messageId: \"styleguideNotFound\",\n });\n },\n };\n }\n\n // Read and hash file contents\n let fileContent: string;\n try {\n fileContent = readFileSync(filePath, \"utf-8\");\n } catch {\n return {};\n }\n\n const fileHash = hashContentSync(fileContent);\n const styleguideHash = hashContentSync(styleguide);\n\n // Check cache\n const projectRoot = findProjectRoot(fileDir);\n const relativeFilePath = relative(projectRoot, filePath);\n const cached = getCacheEntry(\n projectRoot,\n relativeFilePath,\n fileHash,\n styleguideHash\n );\n\n if (cached) {\n // Report cached issues\n return {\n Program(node) {\n for (const issue of cached.issues) {\n context.report({\n node,\n loc: { line: issue.line, column: issue.column || 0 },\n messageId: \"semanticIssue\",\n data: { message: issue.message },\n });\n }\n },\n };\n }\n\n // Queue async analysis (will be picked up on next lint)\n if (!pendingAnalysis.has(filePath)) {\n const analysisPromise = runSemanticAnalysis(\n fileContent,\n styleguide,\n options.model || \"qwen3:8b\"\n );\n\n pendingAnalysis.set(filePath, analysisPromise);\n\n // Store result in cache when complete\n analysisPromise\n .then((issues) => {\n setCacheEntry(projectRoot, relativeFilePath, {\n fileHash,\n styleguideHash,\n issues,\n timestamp: Date.now(),\n });\n })\n .catch(() => {\n // Ignore errors - will retry on next lint\n })\n .finally(() => {\n pendingAnalysis.delete(filePath);\n });\n }\n\n // No issues to report yet - will be cached for next run\n return {};\n },\n});\n\n/**\n * Find project root by looking for package.json\n */\nfunction findProjectRoot(startDir: string): string {\n const { existsSync } = require(\"fs\");\n const { dirname, join } = require(\"path\");\n\n let dir = startDir;\n for (let i = 0; i < 20; i++) {\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Run semantic analysis using Ollama\n */\nasync function runSemanticAnalysis(\n sourceCode: string,\n styleguide: string,\n model: string\n): Promise<CachedIssue[]> {\n try {\n // Dynamic import of uilint-core to avoid circular dependencies at load time\n const { OllamaClient, buildSourceScanPrompt } = await import(\"uilint-core\");\n\n const client = new OllamaClient({ model });\n\n // Check if Ollama is available\n const available = await client.isAvailable();\n if (!available) {\n console.warn(\"[uilint-eslint] Ollama not available, skipping semantic analysis\");\n return [];\n }\n\n const prompt = buildSourceScanPrompt(sourceCode, styleguide, {});\n const response = await client.complete(prompt, { json: true });\n\n const parsed = JSON.parse(response) as {\n issues?: Array<{ line?: number; column?: number; message?: string }>;\n };\n\n return (parsed.issues || []).map((issue) => ({\n line: issue.line || 1,\n column: issue.column,\n message: issue.message || \"Semantic issue detected\",\n ruleId: \"uilint/semantic\",\n severity: 1 as const,\n }));\n } catch (error) {\n console.error(\"[uilint-eslint] Semantic analysis error:\", error);\n return [];\n }\n}\n","/**\n * File-hash based caching for LLM semantic rule\n *\n * Uses xxhash for fast hashing of file contents.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\n// Lazy-loaded xxhash\nlet xxhashInstance: Awaited<ReturnType<typeof import(\"xxhash-wasm\")[\"default\"]>> | null = null;\n\nasync function getXxhash() {\n if (!xxhashInstance) {\n const xxhash = await import(\"xxhash-wasm\");\n xxhashInstance = await xxhash.default();\n }\n return xxhashInstance;\n}\n\n/**\n * Synchronous hash using a simple djb2 algorithm (fallback when xxhash not available)\n */\nfunction djb2Hash(str: string): string {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash * 33) ^ str.charCodeAt(i);\n }\n return (hash >>> 0).toString(16);\n}\n\n/**\n * Hash content using xxhash (async) or djb2 (sync fallback)\n */\nexport async function hashContent(content: string): Promise<string> {\n try {\n const xxhash = await getXxhash();\n return xxhash.h64ToString(content);\n } catch {\n return djb2Hash(content);\n }\n}\n\n/**\n * Synchronous hash for when async is not possible\n */\nexport function hashContentSync(content: string): string {\n return djb2Hash(content);\n}\n\nexport interface CacheEntry {\n fileHash: string;\n styleguideHash: string;\n issues: CachedIssue[];\n timestamp: number;\n}\n\nexport interface CachedIssue {\n line: number;\n column?: number;\n message: string;\n ruleId: string;\n severity: 1 | 2; // 1 = warn, 2 = error\n}\n\nexport interface CacheStore {\n version: number;\n entries: Record<string, CacheEntry>;\n}\n\nconst CACHE_VERSION = 1;\nconst CACHE_FILE = \".uilint/.cache/eslint-semantic.json\";\n\n/**\n * Get the cache file path for a project\n */\nexport function getCachePath(projectRoot: string): string {\n return join(projectRoot, CACHE_FILE);\n}\n\n/**\n * Load the cache store\n */\nexport function loadCache(projectRoot: string): CacheStore {\n const cachePath = getCachePath(projectRoot);\n\n if (!existsSync(cachePath)) {\n return { version: CACHE_VERSION, entries: {} };\n }\n\n try {\n const content = readFileSync(cachePath, \"utf-8\");\n const cache = JSON.parse(content) as CacheStore;\n\n // Invalidate if version mismatch\n if (cache.version !== CACHE_VERSION) {\n return { version: CACHE_VERSION, entries: {} };\n }\n\n return cache;\n } catch {\n return { version: CACHE_VERSION, entries: {} };\n }\n}\n\n/**\n * Save the cache store\n */\nexport function saveCache(projectRoot: string, cache: CacheStore): void {\n const cachePath = getCachePath(projectRoot);\n\n try {\n const cacheDir = dirname(cachePath);\n if (!existsSync(cacheDir)) {\n mkdirSync(cacheDir, { recursive: true });\n }\n\n writeFileSync(cachePath, JSON.stringify(cache, null, 2), \"utf-8\");\n } catch {\n // Silently fail - caching is optional\n }\n}\n\n/**\n * Get cached entry for a file\n */\nexport function getCacheEntry(\n projectRoot: string,\n filePath: string,\n fileHash: string,\n styleguideHash: string\n): CacheEntry | null {\n const cache = loadCache(projectRoot);\n const entry = cache.entries[filePath];\n\n if (!entry) return null;\n\n // Check if hashes match\n if (entry.fileHash !== fileHash || entry.styleguideHash !== styleguideHash) {\n return null;\n }\n\n return entry;\n}\n\n/**\n * Set cached entry for a file\n */\nexport function setCacheEntry(\n projectRoot: string,\n filePath: string,\n entry: CacheEntry\n): void {\n const cache = loadCache(projectRoot);\n cache.entries[filePath] = entry;\n saveCache(projectRoot, cache);\n}\n\n/**\n * Clear cache for a specific file\n */\nexport function clearCacheEntry(projectRoot: string, filePath: string): void {\n const cache = loadCache(projectRoot);\n delete cache.entries[filePath];\n saveCache(projectRoot, cache);\n}\n\n/**\n * Clear entire cache\n */\nexport function clearCache(projectRoot: string): void {\n saveCache(projectRoot, { version: CACHE_VERSION, entries: {} });\n}\n","/**\n * Styleguide loader for the LLM semantic rule\n *\n * Only the semantic rule reads the styleguide - static rules use ESLint options.\n */\n\nimport { existsSync, readFileSync } from \"fs\";\nimport { dirname, isAbsolute, join, resolve } from \"path\";\n\nconst DEFAULT_STYLEGUIDE_PATHS = [\n \".uilint/styleguide.md\",\n \".uilint/styleguide.yaml\",\n \".uilint/styleguide.yml\",\n];\n\n/**\n * Find workspace root by walking up looking for pnpm-workspace.yaml, package.json, or .git\n */\nfunction findWorkspaceRoot(startDir: string): string {\n let dir = startDir;\n for (let i = 0; i < 20; i++) {\n if (\n existsSync(join(dir, \"pnpm-workspace.yaml\")) ||\n existsSync(join(dir, \".git\"))\n ) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Find the styleguide file path\n */\nexport function findStyleguidePath(\n startDir: string,\n explicitPath?: string\n): string | null {\n // Explicit path takes precedence\n if (explicitPath) {\n const resolved = isAbsolute(explicitPath)\n ? explicitPath\n : resolve(startDir, explicitPath);\n if (existsSync(resolved)) {\n return resolved;\n }\n return null;\n }\n\n // Check from start dir up to workspace root\n const workspaceRoot = findWorkspaceRoot(startDir);\n let dir = startDir;\n\n while (true) {\n for (const relativePath of DEFAULT_STYLEGUIDE_PATHS) {\n const fullPath = join(dir, relativePath);\n if (existsSync(fullPath)) {\n return fullPath;\n }\n }\n\n // Stop at workspace root\n if (dir === workspaceRoot) break;\n\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n return null;\n}\n\n/**\n * Load styleguide content from file\n */\nexport function loadStyleguide(\n startDir: string,\n explicitPath?: string\n): string | null {\n const path = findStyleguidePath(startDir, explicitPath);\n if (!path) return null;\n\n try {\n return readFileSync(path, \"utf-8\");\n } catch {\n return null;\n }\n}\n\n/**\n * Get styleguide path and content\n */\nexport function getStyleguide(\n startDir: string,\n explicitPath?: string\n): { path: string | null; content: string | null } {\n const path = findStyleguidePath(startDir, explicitPath);\n if (!path) return { path: null, content: null };\n\n try {\n const content = readFileSync(path, \"utf-8\");\n return { path, content };\n } catch {\n return { path, content: null };\n }\n}\n","/**\n * UILint ESLint Plugin\n *\n * Provides ESLint rules for UI consistency checking:\n * - Static rules for common patterns (arbitrary values, spacing, component libraries)\n * - LLM-powered semantic rule that reads your styleguide\n */\n\nimport type { Linter } from \"eslint\";\nimport noArbitraryTailwind from \"./rules/no-arbitrary-tailwind.js\";\nimport consistentSpacing from \"./rules/consistent-spacing.js\";\nimport noDirectStoreImport from \"./rules/no-direct-store-import.js\";\nimport noMixedComponentLibraries from \"./rules/no-mixed-component-libraries.js\";\nimport semantic from \"./rules/semantic.js\";\n\n// Package version (injected at build time or fallback)\nconst version = \"0.1.0\";\n\n/**\n * All available rules\n */\nconst rules = {\n \"no-arbitrary-tailwind\": noArbitraryTailwind,\n \"consistent-spacing\": consistentSpacing,\n \"no-direct-store-import\": noDirectStoreImport,\n \"no-mixed-component-libraries\": noMixedComponentLibraries,\n semantic: semantic,\n};\n\n/**\n * Plugin metadata\n */\nconst meta = {\n name: \"uilint\",\n version,\n};\n\n/**\n * The ESLint plugin object\n */\nconst plugin = {\n meta,\n rules,\n};\n\n/**\n * Shared language options for all configs\n */\nconst jsxLanguageOptions: Linter.Config[\"languageOptions\"] = {\n parserOptions: {\n ecmaFeatures: {\n jsx: true,\n },\n },\n};\n\n/**\n * Recommended config - static rules only\n *\n * Usage:\n * ```js\n * import uilint from 'uilint-eslint';\n * export default [uilint.configs.recommended];\n * ```\n */\nconst recommendedConfig: Linter.Config = {\n name: \"uilint/recommended\",\n plugins: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n uilint: plugin as any,\n },\n languageOptions: jsxLanguageOptions,\n rules: {\n \"uilint/no-arbitrary-tailwind\": \"error\",\n \"uilint/consistent-spacing\": \"warn\",\n \"uilint/no-direct-store-import\": \"warn\",\n \"uilint/no-mixed-component-libraries\": \"error\",\n },\n};\n\n/**\n * Strict config - static rules + LLM semantic rule\n *\n * Usage:\n * ```js\n * import uilint from 'uilint-eslint';\n * export default [uilint.configs.strict];\n * ```\n */\nconst strictConfig: Linter.Config = {\n name: \"uilint/strict\",\n plugins: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n uilint: plugin as any,\n },\n languageOptions: jsxLanguageOptions,\n rules: {\n \"uilint/no-arbitrary-tailwind\": \"error\",\n \"uilint/consistent-spacing\": \"warn\",\n \"uilint/no-direct-store-import\": \"error\",\n \"uilint/no-mixed-component-libraries\": \"error\",\n \"uilint/semantic\": \"warn\",\n },\n};\n\n/**\n * Pre-configured configs\n */\nconst configs: Record<string, Linter.Config> = {\n recommended: recommendedConfig,\n strict: strictConfig,\n};\n\n/**\n * UILint ESLint export interface\n */\nexport interface UILintESLint {\n meta: typeof meta;\n plugin: typeof plugin;\n rules: typeof rules;\n configs: Record<string, Linter.Config>;\n}\n\n/**\n * Default export for ESLint flat config\n */\nconst uilintEslint: UILintESLint = {\n meta,\n plugin,\n rules,\n configs,\n};\n\nexport default uilintEslint;\n\n// Named exports for convenience\nexport { plugin, rules, configs, meta };\n\n// Re-export utilities for custom rule creation\nexport { createRule } from \"./utils/create-rule.js\";\nexport {\n loadStyleguide,\n findStyleguidePath,\n getStyleguide,\n} from \"./utils/styleguide-loader.js\";\nexport {\n hashContent,\n hashContentSync,\n getCacheEntry,\n setCacheEntry,\n clearCache,\n clearCacheEntry,\n loadCache,\n saveCache,\n type CacheEntry,\n type CachedIssue,\n type CacheStore,\n} from \"./utils/cache.js\";\n"],"mappings":";;;;;;;;AAIA,SAAS,mBAAmB;AAErB,IAAM,aAAa,YAAY;AAAA,EACpC,CAAC,SACC,uFAAuF,IAAI;AAC/F;;;ACGA,IAAM,wBAAwB;AAE9B,IAAO,gCAAQ,WAAgC;AAAA,EAC7C,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,kBACE;AAAA,IACJ;AAAA,IACA,QAAQ,CAAC;AAAA,EACX;AAAA,EACA,gBAAgB,CAAC;AAAA,EACjB,OAAO,SAAS;AACd,WAAO;AAAA;AAAA,MAEL,aAAa,MAAM;AACjB,YACE,KAAK,KAAK,SAAS,oBAClB,KAAK,KAAK,SAAS,eAAe,KAAK,KAAK,SAAS,UACtD;AACA,gBAAM,QAAQ,KAAK;AAGnB,cAAI,OAAO,SAAS,aAAa,OAAO,MAAM,UAAU,UAAU;AAChE,6BAAiB,SAAS,OAAO,MAAM,KAAK;AAAA,UAC9C;AAGA,cAAI,OAAO,SAAS,0BAA0B;AAC5C,kBAAM,OAAO,MAAM;AAGnB,gBAAI,KAAK,SAAS,aAAa,OAAO,KAAK,UAAU,UAAU;AAC7D,+BAAiB,SAAS,MAAM,KAAK,KAAK;AAAA,YAC5C;AAGA,gBAAI,KAAK,SAAS,mBAAmB;AACnC,yBAAW,SAAS,KAAK,QAAQ;AAC/B,iCAAiB,SAAS,OAAO,MAAM,MAAM,GAAG;AAAA,cAClD;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA;AAAA,MAGA,eAAe,MAAM;AACnB,YAAI,KAAK,OAAO,SAAS,aAAc;AACvC,cAAM,OAAO,KAAK,OAAO;AAEzB,YAAI,SAAS,QAAQ,SAAS,UAAU,SAAS,cAAc;AAC7D,qBAAW,OAAO,KAAK,WAAW;AAChC,gBAAI,IAAI,SAAS,aAAa,OAAO,IAAI,UAAU,UAAU;AAC3D,+BAAiB,SAAS,KAAK,IAAI,KAAK;AAAA,YAC1C;AACA,gBAAI,IAAI,SAAS,mBAAmB;AAClC,yBAAW,SAAS,IAAI,QAAQ;AAC9B,iCAAiB,SAAS,OAAO,MAAM,MAAM,GAAG;AAAA,cAClD;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAED,SAAS,iBACP,SAGA,MACA,aACA;AACA,QAAM,UAAU,YAAY,SAAS,qBAAqB;AAE1D,aAAW,SAAS,SAAS;AAC3B,YAAQ,OAAO;AAAA,MACb;AAAA,MACA,WAAW;AAAA,MACX,MAAM,EAAE,OAAO,MAAM,CAAC,EAAE;AAAA,IAC1B,CAAC;AAAA,EACH;AACF;;;ACpFA,IAAM,gBAAgB;AAAA,EACpB;AAAA,EAAG;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAG;AAAA,EAAK;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAG;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAC1E;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAAA,EAAI;AAClD;AAGA,IAAM,mBAAmB;AAAA,EACvB;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAGA,SAAS,oBAA4B;AACnC,QAAM,WAAW,iBAAiB,IAAI,CAAC,MAAM,EAAE,QAAQ,KAAK,KAAK,CAAC,EAAE,KAAK,GAAG;AAE5E,SAAO,IAAI,OAAO,OAAO,QAAQ,sBAAsB,GAAG;AAC5D;AAEA,IAAM,gBAAgB,kBAAkB;AAExC,IAAO,6BAAQ,WAAgC;AAAA,EAC7C,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,gBACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,YAAY;AAAA,UACV,OAAO;AAAA,YACL,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,SAAS;AAAA,UAC1B;AAAA,QACF;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,EAAE,OAAO,cAAc,CAAC;AAAA,EACzC,OAAO,SAAS;AACd,UAAM,UAAU,QAAQ,QAAQ,CAAC,KAAK,CAAC;AACvC,UAAM,QAAQ,IAAI,KAAK,QAAQ,SAAS,eAAe,IAAI,MAAM,CAAC;AAClE,UAAM,YAAY,CAAC,GAAG,KAAK,EAAE,MAAM,GAAG,EAAE,EAAE,KAAK,IAAI,IAAI;AAEvD,WAAO;AAAA;AAAA,MAEL,aAAa,MAAM;AACjB,YACE,KAAK,KAAK,SAAS,oBAClB,KAAK,KAAK,SAAS,eAAe,KAAK,KAAK,SAAS,UACtD;AACA,gBAAM,QAAQ,KAAK;AAEnB,cAAI,OAAO,SAAS,aAAa,OAAO,MAAM,UAAU,UAAU;AAChE,yBAAa,SAAS,MAAM,MAAM,OAAO,OAAO,SAAS;AAAA,UAC3D;AAEA,cAAI,OAAO,SAAS,0BAA0B;AAC5C,kBAAM,OAAO,MAAM;AACnB,gBAAI,KAAK,SAAS,aAAa,OAAO,KAAK,UAAU,UAAU;AAC7D,2BAAa,SAAS,MAAM,KAAK,OAAO,OAAO,SAAS;AAAA,YAC1D;AACA,gBAAI,KAAK,SAAS,mBAAmB;AACnC,yBAAW,SAAS,KAAK,QAAQ;AAC/B,6BAAa,SAAS,MAAM,MAAM,MAAM,KAAK,OAAO,SAAS;AAAA,cAC/D;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA;AAAA,MAGA,eAAe,MAAM;AACnB,YAAI,KAAK,OAAO,SAAS,aAAc;AACvC,cAAM,OAAO,KAAK,OAAO;AAEzB,YAAI,SAAS,QAAQ,SAAS,UAAU,SAAS,cAAc;AAC7D,qBAAW,OAAO,KAAK,WAAW;AAChC,gBAAI,IAAI,SAAS,aAAa,OAAO,IAAI,UAAU,UAAU;AAC3D,2BAAa,SAAS,KAAK,IAAI,OAAO,OAAO,SAAS;AAAA,YACxD;AACA,gBAAI,IAAI,SAAS,mBAAmB;AAClC,yBAAW,SAAS,IAAI,QAAQ;AAC9B,6BAAa,SAAS,OAAO,MAAM,MAAM,KAAK,OAAO,SAAS;AAAA,cAChE;AAAA,YACF;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;AAED,SAAS,aACP,SAGA,MACA,aACA,OACA,WACA;AAEA,gBAAc,YAAY;AAE1B,MAAI;AACJ,UAAQ,QAAQ,cAAc,KAAK,WAAW,OAAO,MAAM;AACzD,UAAM,CAAC,EAAE,EAAE,KAAK,IAAI;AACpB,QAAI,SAAS,CAAC,MAAM,IAAI,KAAK,GAAG;AAC9B,cAAQ,OAAO;AAAA,QACb;AAAA,QACA,WAAW;AAAA,QACX,MAAM,EAAE,OAAO,SAAS,UAAU;AAAA,MACpC,CAAC;AAAA,IACH;AAAA,EACF;AACF;;;AC7JA,SAAS,eAAe,SAAyB;AAC/C,QAAM,UAAU,QACb,QAAQ,qBAAqB,MAAM,EACnC,QAAQ,OAAO,IAAI,EACnB,QAAQ,OAAO,GAAG;AACrB,SAAO,IAAI,OAAO,IAAI,OAAO,GAAG;AAClC;AAEA,IAAO,iCAAQ,WAAgC;AAAA,EAC7C,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aACE;AAAA,IACJ;AAAA,IACA,UAAU;AAAA,MACR,gBACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,YAAY;AAAA,UACV,cAAc;AAAA,YACZ,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,QACF;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,EAAE,cAAc,YAAY,CAAC;AAAA,EAC9C,OAAO,SAAS;AACd,UAAM,UAAU,QAAQ,QAAQ,CAAC,KAAK,CAAC;AACvC,UAAM,UAAU,QAAQ,gBAAgB;AACxC,UAAM,QAAQ,eAAe,OAAO;AAEpC,WAAO;AAAA,MACL,kBAAkB,MAAM;AAEtB,cAAM,SAAS,KAAK,OAAO;AAC3B,YAAI,CAAC,OAAO,SAAS,OAAO,EAAG;AAG/B,mBAAW,aAAa,KAAK,YAAY;AACvC,cAAI,UAAU,SAAS,mBAAmB;AACxC,kBAAM,eACJ,UAAU,SAAS,SAAS,eACxB,UAAU,SAAS,OACnB,UAAU,SAAS;AAEzB,gBAAI,MAAM,KAAK,YAAY,GAAG;AAC5B,sBAAQ,OAAO;AAAA,gBACb,MAAM;AAAA,gBACN,WAAW;AAAA,gBACX,MAAM,EAAE,MAAM,aAAa;AAAA,cAC7B,CAAC;AAAA,YACH;AAAA,UACF;AAEA,cAAI,UAAU,SAAS,0BAA0B;AAC/C,kBAAM,YAAY,UAAU,MAAM;AAClC,gBAAI,MAAM,KAAK,SAAS,GAAG;AACzB,sBAAQ,OAAO;AAAA,gBACb,MAAM;AAAA,gBACN,WAAW;AAAA,gBACX,MAAM,EAAE,MAAM,UAAU;AAAA,cAC1B,CAAC;AAAA,YACH;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AC3ED,IAAM,mBAAkD;AAAA,EACtD,QAAQ,CAAC,mBAAmB,cAAc,gBAAgB;AAAA,EAC1D,KAAK,CAAC,iBAAiB,uBAAuB,WAAW;AAC3D;AAEA,IAAO,uCAAQ,WAAgC;AAAA,EAC7C,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,gBACE;AAAA,IACJ;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,YAAY;AAAA,UACV,WAAW;AAAA,YACT,MAAM;AAAA,YACN,OAAO,EAAE,MAAM,CAAC,UAAU,KAAK,EAAE;AAAA,UACnC;AAAA,QACF;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,EAAE,WAAW,CAAC,UAAU,KAAK,EAAE,CAAC;AAAA,EACjD,OAAO,SAAS;AACd,UAAM,UAAU,QAAQ,QAAQ,CAAC,KAAK,CAAC;AACvC,UAAM,YAAa,QAAQ,aAAa,CAAC,UAAU,KAAK;AACxD,UAAM,WAAyD,oBAAI,IAAI;AAEvE,WAAO;AAAA,MACL,kBAAkB,MAAM;AACtB,cAAM,SAAS,KAAK,OAAO;AAE3B,mBAAW,OAAO,WAAW;AAC3B,gBAAM,WAAW,iBAAiB,GAAG;AACrC,cAAI,UAAU,KAAK,CAAC,MAAM,OAAO,SAAS,CAAC,CAAC,GAAG;AAC7C,gBAAI,CAAC,SAAS,IAAI,GAAG,GAAG;AACtB,uBAAS,IAAI,KAAK,IAAI;AAAA,YACxB;AAAA,UACF;AAAA,QACF;AAAA,MACF;AAAA,MAEA,iBAAiB;AACf,YAAI,SAAS,OAAO,GAAG;AACrB,gBAAM,OAAO,CAAC,GAAG,SAAS,KAAK,CAAC;AAChC,gBAAM,YAAY,KAAK,CAAC;AACxB,gBAAM,aAAa,SAAS,IAAI,SAAS;AAEzC,kBAAQ,OAAO;AAAA,YACb,MAAM;AAAA,YACN,WAAW;AAAA,YACX,MAAM,EAAE,MAAM,KAAK,CAAC,GAAG,MAAM,UAAU;AAAA,UACzC,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF,CAAC;;;AC1ED,SAAS,gBAAAA,qBAAoB;AAC7B,SAAS,WAAAC,UAAS,gBAAgB;;;ACFlC,SAAS,YAAY,WAAW,cAAc,qBAAqB;AACnE,SAAS,SAAS,YAAY;AAG9B,IAAI,iBAAsF;AAE1F,eAAe,YAAY;AACzB,MAAI,CAAC,gBAAgB;AACnB,UAAM,SAAS,MAAM,OAAO,aAAa;AACzC,qBAAiB,MAAM,OAAO,QAAQ;AAAA,EACxC;AACA,SAAO;AACT;AAKA,SAAS,SAAS,KAAqB;AACrC,MAAI,OAAO;AACX,WAAS,IAAI,GAAG,IAAI,IAAI,QAAQ,KAAK;AACnC,WAAQ,OAAO,KAAM,IAAI,WAAW,CAAC;AAAA,EACvC;AACA,UAAQ,SAAS,GAAG,SAAS,EAAE;AACjC;AAKA,eAAsB,YAAY,SAAkC;AAClE,MAAI;AACF,UAAM,SAAS,MAAM,UAAU;AAC/B,WAAO,OAAO,YAAY,OAAO;AAAA,EACnC,QAAQ;AACN,WAAO,SAAS,OAAO;AAAA,EACzB;AACF;AAKO,SAAS,gBAAgB,SAAyB;AACvD,SAAO,SAAS,OAAO;AACzB;AAsBA,IAAM,gBAAgB;AACtB,IAAM,aAAa;AAKZ,SAAS,aAAa,aAA6B;AACxD,SAAO,KAAK,aAAa,UAAU;AACrC;AAKO,SAAS,UAAU,aAAiC;AACzD,QAAM,YAAY,aAAa,WAAW;AAE1C,MAAI,CAAC,WAAW,SAAS,GAAG;AAC1B,WAAO,EAAE,SAAS,eAAe,SAAS,CAAC,EAAE;AAAA,EAC/C;AAEA,MAAI;AACF,UAAM,UAAU,aAAa,WAAW,OAAO;AAC/C,UAAM,QAAQ,KAAK,MAAM,OAAO;AAGhC,QAAI,MAAM,YAAY,eAAe;AACnC,aAAO,EAAE,SAAS,eAAe,SAAS,CAAC,EAAE;AAAA,IAC/C;AAEA,WAAO;AAAA,EACT,QAAQ;AACN,WAAO,EAAE,SAAS,eAAe,SAAS,CAAC,EAAE;AAAA,EAC/C;AACF;AAKO,SAAS,UAAU,aAAqB,OAAyB;AACtE,QAAM,YAAY,aAAa,WAAW;AAE1C,MAAI;AACF,UAAM,WAAW,QAAQ,SAAS;AAClC,QAAI,CAAC,WAAW,QAAQ,GAAG;AACzB,gBAAU,UAAU,EAAE,WAAW,KAAK,CAAC;AAAA,IACzC;AAEA,kBAAc,WAAW,KAAK,UAAU,OAAO,MAAM,CAAC,GAAG,OAAO;AAAA,EAClE,QAAQ;AAAA,EAER;AACF;AAKO,SAAS,cACd,aACA,UACA,UACA,gBACmB;AACnB,QAAM,QAAQ,UAAU,WAAW;AACnC,QAAM,QAAQ,MAAM,QAAQ,QAAQ;AAEpC,MAAI,CAAC,MAAO,QAAO;AAGnB,MAAI,MAAM,aAAa,YAAY,MAAM,mBAAmB,gBAAgB;AAC1E,WAAO;AAAA,EACT;AAEA,SAAO;AACT;AAKO,SAAS,cACd,aACA,UACA,OACM;AACN,QAAM,QAAQ,UAAU,WAAW;AACnC,QAAM,QAAQ,QAAQ,IAAI;AAC1B,YAAU,aAAa,KAAK;AAC9B;AAKO,SAAS,gBAAgB,aAAqB,UAAwB;AAC3E,QAAM,QAAQ,UAAU,WAAW;AACnC,SAAO,MAAM,QAAQ,QAAQ;AAC7B,YAAU,aAAa,KAAK;AAC9B;AAKO,SAAS,WAAW,aAA2B;AACpD,YAAU,aAAa,EAAE,SAAS,eAAe,SAAS,CAAC,EAAE,CAAC;AAChE;;;ACtKA,SAAS,cAAAC,aAAY,gBAAAC,qBAAoB;AACzC,SAAS,WAAAC,UAAS,YAAY,QAAAC,OAAM,eAAe;AAEnD,IAAM,2BAA2B;AAAA,EAC/B;AAAA,EACA;AAAA,EACA;AACF;AAKA,SAAS,kBAAkB,UAA0B;AACnD,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,QACEH,YAAWG,MAAK,KAAK,qBAAqB,CAAC,KAC3CH,YAAWG,MAAK,KAAK,MAAM,CAAC,GAC5B;AACA,aAAO;AAAA,IACT;AACA,UAAM,SAASD,SAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK;AACpB,UAAM;AAAA,EACR;AACA,SAAO;AACT;AAKO,SAAS,mBACd,UACA,cACe;AAEf,MAAI,cAAc;AAChB,UAAM,WAAW,WAAW,YAAY,IACpC,eACA,QAAQ,UAAU,YAAY;AAClC,QAAIF,YAAW,QAAQ,GAAG;AACxB,aAAO;AAAA,IACT;AACA,WAAO;AAAA,EACT;AAGA,QAAM,gBAAgB,kBAAkB,QAAQ;AAChD,MAAI,MAAM;AAEV,SAAO,MAAM;AACX,eAAW,gBAAgB,0BAA0B;AACnD,YAAM,WAAWG,MAAK,KAAK,YAAY;AACvC,UAAIH,YAAW,QAAQ,GAAG;AACxB,eAAO;AAAA,MACT;AAAA,IACF;AAGA,QAAI,QAAQ,cAAe;AAE3B,UAAM,SAASE,SAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK;AACpB,UAAM;AAAA,EACR;AAEA,SAAO;AACT;AAKO,SAAS,eACd,UACA,cACe;AACf,QAAM,OAAO,mBAAmB,UAAU,YAAY;AACtD,MAAI,CAAC,KAAM,QAAO;AAElB,MAAI;AACF,WAAOD,cAAa,MAAM,OAAO;AAAA,EACnC,QAAQ;AACN,WAAO;AAAA,EACT;AACF;AAKO,SAAS,cACd,UACA,cACiD;AACjD,QAAM,OAAO,mBAAmB,UAAU,YAAY;AACtD,MAAI,CAAC,KAAM,QAAO,EAAE,MAAM,MAAM,SAAS,KAAK;AAE9C,MAAI;AACF,UAAM,UAAUA,cAAa,MAAM,OAAO;AAC1C,WAAO,EAAE,MAAM,QAAQ;AAAA,EACzB,QAAQ;AACN,WAAO,EAAE,MAAM,SAAS,KAAK;AAAA,EAC/B;AACF;;;AFjFA,IAAM,kBAAkB,oBAAI,IAAoC;AAEhE,IAAO,mBAAQ,WAAgC;AAAA,EAC7C,MAAM;AAAA,EACN,MAAM;AAAA,IACJ,MAAM;AAAA,IACN,MAAM;AAAA,MACJ,aAAa;AAAA,IACf;AAAA,IACA,UAAU;AAAA,MACR,eAAe;AAAA,MACf,oBACE;AAAA,MACF,eAAe;AAAA,IACjB;AAAA,IACA,QAAQ;AAAA,MACN;AAAA,QACE,MAAM;AAAA,QACN,YAAY;AAAA,UACV,OAAO;AAAA,YACL,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,UACA,gBAAgB;AAAA,YACd,MAAM;AAAA,YACN,aAAa;AAAA,UACf;AAAA,QACF;AAAA,QACA,sBAAsB;AAAA,MACxB;AAAA,IACF;AAAA,EACF;AAAA,EACA,gBAAgB,CAAC,EAAE,OAAO,WAAW,CAAC;AAAA,EACtC,OAAO,SAAS;AACd,UAAM,UAAU,QAAQ,QAAQ,CAAC,KAAK,CAAC;AACvC,UAAM,WAAW,QAAQ;AACzB,UAAM,UAAUG,SAAQ,QAAQ;AAGhC,UAAM,EAAE,MAAM,gBAAgB,SAAS,WAAW,IAAI;AAAA,MACpD;AAAA,MACA,QAAQ;AAAA,IACV;AAGA,QAAI,CAAC,YAAY;AACf,aAAO;AAAA,QACL,QAAQ,MAAM;AACZ,kBAAQ,OAAO;AAAA,YACb;AAAA,YACA,WAAW;AAAA,UACb,CAAC;AAAA,QACH;AAAA,MACF;AAAA,IACF;AAGA,QAAI;AACJ,QAAI;AACF,oBAAcC,cAAa,UAAU,OAAO;AAAA,IAC9C,QAAQ;AACN,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,WAAW,gBAAgB,WAAW;AAC5C,UAAM,iBAAiB,gBAAgB,UAAU;AAGjD,UAAM,cAAc,gBAAgB,OAAO;AAC3C,UAAM,mBAAmB,SAAS,aAAa,QAAQ;AACvD,UAAM,SAAS;AAAA,MACb;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF;AAEA,QAAI,QAAQ;AAEV,aAAO;AAAA,QACL,QAAQ,MAAM;AACZ,qBAAW,SAAS,OAAO,QAAQ;AACjC,oBAAQ,OAAO;AAAA,cACb;AAAA,cACA,KAAK,EAAE,MAAM,MAAM,MAAM,QAAQ,MAAM,UAAU,EAAE;AAAA,cACnD,WAAW;AAAA,cACX,MAAM,EAAE,SAAS,MAAM,QAAQ;AAAA,YACjC,CAAC;AAAA,UACH;AAAA,QACF;AAAA,MACF;AAAA,IACF;AAGA,QAAI,CAAC,gBAAgB,IAAI,QAAQ,GAAG;AAClC,YAAM,kBAAkB;AAAA,QACtB;AAAA,QACA;AAAA,QACA,QAAQ,SAAS;AAAA,MACnB;AAEA,sBAAgB,IAAI,UAAU,eAAe;AAG7C,sBACG,KAAK,CAAC,WAAW;AAChB,sBAAc,aAAa,kBAAkB;AAAA,UAC3C;AAAA,UACA;AAAA,UACA;AAAA,UACA,WAAW,KAAK,IAAI;AAAA,QACtB,CAAC;AAAA,MACH,CAAC,EACA,MAAM,MAAM;AAAA,MAEb,CAAC,EACA,QAAQ,MAAM;AACb,wBAAgB,OAAO,QAAQ;AAAA,MACjC,CAAC;AAAA,IACL;AAGA,WAAO,CAAC;AAAA,EACV;AACF,CAAC;AAKD,SAAS,gBAAgB,UAA0B;AACjD,QAAM,EAAE,YAAAC,YAAW,IAAI,UAAQ,IAAI;AACnC,QAAM,EAAE,SAAAF,UAAS,MAAAG,MAAK,IAAI,UAAQ,MAAM;AAExC,MAAI,MAAM;AACV,WAAS,IAAI,GAAG,IAAI,IAAI,KAAK;AAC3B,QAAID,YAAWC,MAAK,KAAK,cAAc,CAAC,GAAG;AACzC,aAAO;AAAA,IACT;AACA,UAAM,SAASH,SAAQ,GAAG;AAC1B,QAAI,WAAW,IAAK;AACpB,UAAM;AAAA,EACR;AACA,SAAO;AACT;AAKA,eAAe,oBACb,YACA,YACA,OACwB;AACxB,MAAI;AAEF,UAAM,EAAE,cAAc,sBAAsB,IAAI,MAAM,OAAO,aAAa;AAE1E,UAAM,SAAS,IAAI,aAAa,EAAE,MAAM,CAAC;AAGzC,UAAM,YAAY,MAAM,OAAO,YAAY;AAC3C,QAAI,CAAC,WAAW;AACd,cAAQ,KAAK,kEAAkE;AAC/E,aAAO,CAAC;AAAA,IACV;AAEA,UAAM,SAAS,sBAAsB,YAAY,YAAY,CAAC,CAAC;AAC/D,UAAM,WAAW,MAAM,OAAO,SAAS,QAAQ,EAAE,MAAM,KAAK,CAAC;AAE7D,UAAM,SAAS,KAAK,MAAM,QAAQ;AAIlC,YAAQ,OAAO,UAAU,CAAC,GAAG,IAAI,CAAC,WAAW;AAAA,MAC3C,MAAM,MAAM,QAAQ;AAAA,MACpB,QAAQ,MAAM;AAAA,MACd,SAAS,MAAM,WAAW;AAAA,MAC1B,QAAQ;AAAA,MACR,UAAU;AAAA,IACZ,EAAE;AAAA,EACJ,SAAS,OAAO;AACd,YAAQ,MAAM,4CAA4C,KAAK;AAC/D,WAAO,CAAC;AAAA,EACV;AACF;;;AGnMA,IAAM,UAAU;AAKhB,IAAM,QAAQ;AAAA,EACZ,yBAAyB;AAAA,EACzB,sBAAsB;AAAA,EACtB,0BAA0B;AAAA,EAC1B,gCAAgC;AAAA,EAChC,UAAU;AACZ;AAKA,IAAM,OAAO;AAAA,EACX,MAAM;AAAA,EACN;AACF;AAKA,IAAM,SAAS;AAAA,EACb;AAAA,EACA;AACF;AAKA,IAAM,qBAAuD;AAAA,EAC3D,eAAe;AAAA,IACb,cAAc;AAAA,MACZ,KAAK;AAAA,IACP;AAAA,EACF;AACF;AAWA,IAAM,oBAAmC;AAAA,EACvC,MAAM;AAAA,EACN,SAAS;AAAA;AAAA,IAEP,QAAQ;AAAA,EACV;AAAA,EACA,iBAAiB;AAAA,EACjB,OAAO;AAAA,IACL,gCAAgC;AAAA,IAChC,6BAA6B;AAAA,IAC7B,iCAAiC;AAAA,IACjC,uCAAuC;AAAA,EACzC;AACF;AAWA,IAAM,eAA8B;AAAA,EAClC,MAAM;AAAA,EACN,SAAS;AAAA;AAAA,IAEP,QAAQ;AAAA,EACV;AAAA,EACA,iBAAiB;AAAA,EACjB,OAAO;AAAA,IACL,gCAAgC;AAAA,IAChC,6BAA6B;AAAA,IAC7B,iCAAiC;AAAA,IACjC,uCAAuC;AAAA,IACvC,mBAAmB;AAAA,EACrB;AACF;AAKA,IAAM,UAAyC;AAAA,EAC7C,aAAa;AAAA,EACb,QAAQ;AACV;AAeA,IAAM,eAA6B;AAAA,EACjC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF;AAEA,IAAO,gBAAQ;","names":["readFileSync","dirname","existsSync","readFileSync","dirname","join","dirname","readFileSync","existsSync","join"]}
1
+ {"version":3,"sources":["../src/utils/create-rule.ts","../src/rules/no-arbitrary-tailwind.ts","../src/rules/consistent-spacing.ts","../src/rules/no-direct-store-import.ts","../src/rules/no-mixed-component-libraries.ts","../src/rules/semantic.ts","../src/utils/cache.ts","../src/utils/styleguide-loader.ts","../src/rule-registry.ts","../src/index.ts"],"sourcesContent":["/**\n * Rule creation helper using @typescript-eslint/utils\n */\n\nimport { ESLintUtils } from \"@typescript-eslint/utils\";\n\nexport const createRule = ESLintUtils.RuleCreator(\n (name) =>\n `https://github.com/peter-suggate/uilint/blob/main/packages/uilint-eslint/docs/rules/${name}.md`\n);\n","/**\n * Rule: no-arbitrary-tailwind\n *\n * Forbids arbitrary Tailwind values like w-[123px], bg-[#fff], etc.\n */\n\nimport { createRule } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"noArbitraryValue\";\ntype Options = [];\n\n// Regex to match arbitrary Tailwind values: word-[anything]\nconst ARBITRARY_VALUE_REGEX = /\\b[\\w-]+-\\[[^\\]]+\\]/g;\n\nexport default createRule<Options, MessageIds>({\n name: \"no-arbitrary-tailwind\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Forbid arbitrary Tailwind values like w-[123px]\",\n },\n messages: {\n noArbitraryValue:\n \"Avoid arbitrary Tailwind value '{{value}}'. Use the spacing/color scale instead.\",\n },\n schema: [],\n },\n defaultOptions: [],\n create(context) {\n return {\n // Check className attributes in JSX\n JSXAttribute(node) {\n if (\n node.name.type === \"JSXIdentifier\" &&\n (node.name.name === \"className\" || node.name.name === \"class\")\n ) {\n const value = node.value;\n\n // Handle string literal: className=\"...\"\n if (value?.type === \"Literal\" && typeof value.value === \"string\") {\n checkClassString(context, value, value.value);\n }\n\n // Handle JSX expression: className={...}\n if (value?.type === \"JSXExpressionContainer\") {\n const expr = value.expression;\n\n // Direct string: className={\"...\"}\n if (expr.type === \"Literal\" && typeof expr.value === \"string\") {\n checkClassString(context, expr, expr.value);\n }\n\n // Template literal: className={`...`}\n if (expr.type === \"TemplateLiteral\") {\n for (const quasi of expr.quasis) {\n checkClassString(context, quasi, quasi.value.raw);\n }\n }\n }\n }\n },\n\n // Check cn(), clsx(), classnames() calls\n CallExpression(node) {\n if (node.callee.type !== \"Identifier\") return;\n const name = node.callee.name;\n\n if (name === \"cn\" || name === \"clsx\" || name === \"classnames\") {\n for (const arg of node.arguments) {\n if (arg.type === \"Literal\" && typeof arg.value === \"string\") {\n checkClassString(context, arg, arg.value);\n }\n if (arg.type === \"TemplateLiteral\") {\n for (const quasi of arg.quasis) {\n checkClassString(context, quasi, quasi.value.raw);\n }\n }\n }\n }\n },\n };\n },\n});\n\nfunction checkClassString(\n context: Parameters<\n ReturnType<typeof createRule<[], \"noArbitraryValue\">>[\"create\"]\n >[0],\n node: TSESTree.Node,\n classString: string\n) {\n const matches = classString.matchAll(ARBITRARY_VALUE_REGEX);\n\n for (const match of matches) {\n context.report({\n node,\n messageId: \"noArbitraryValue\",\n data: { value: match[0] },\n });\n }\n}\n","/**\n * Rule: consistent-spacing\n *\n * Enforces use of spacing scale values in gap, padding, margin utilities.\n */\n\nimport { createRule } from \"../utils/create-rule.js\";\nimport type { TSESTree } from \"@typescript-eslint/utils\";\n\ntype MessageIds = \"invalidSpacing\";\ntype Options = [\n {\n scale?: number[];\n }\n];\n\n// Default Tailwind spacing scale\nconst DEFAULT_SCALE = [\n 0, 0.5, 1, 1.5, 2, 2.5, 3, 3.5, 4, 5, 6, 7, 8, 9, 10, 11, 12, 14, 16, 20, 24,\n 28, 32, 36, 40, 44, 48, 52, 56, 60, 64, 72, 80, 96,\n];\n\n// Spacing utilities that take numeric values\nconst SPACING_PREFIXES = [\n \"p-\",\n \"px-\",\n \"py-\",\n \"pt-\",\n \"pr-\",\n \"pb-\",\n \"pl-\",\n \"ps-\",\n \"pe-\",\n \"m-\",\n \"mx-\",\n \"my-\",\n \"mt-\",\n \"mr-\",\n \"mb-\",\n \"ml-\",\n \"ms-\",\n \"me-\",\n \"gap-\",\n \"gap-x-\",\n \"gap-y-\",\n \"space-x-\",\n \"space-y-\",\n \"inset-\",\n \"inset-x-\",\n \"inset-y-\",\n \"top-\",\n \"right-\",\n \"bottom-\",\n \"left-\",\n \"w-\",\n \"h-\",\n \"min-w-\",\n \"min-h-\",\n \"max-w-\",\n \"max-h-\",\n \"size-\",\n];\n\n// Build regex to match spacing utilities with numeric values\nfunction buildSpacingRegex(): RegExp {\n const prefixes = SPACING_PREFIXES.map((p) => p.replace(\"-\", \"\\\\-\")).join(\"|\");\n // Match prefix followed by a number (possibly with decimal)\n return new RegExp(`\\\\b(${prefixes})(\\\\d+\\\\.?\\\\d*)\\\\b`, \"g\");\n}\n\nconst SPACING_REGEX = buildSpacingRegex();\n\nexport default createRule<Options, MessageIds>({\n name: \"consistent-spacing\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"Enforce spacing scale (no magic numbers in gap/padding)\",\n },\n messages: {\n invalidSpacing:\n \"Spacing value '{{value}}' is not in the allowed scale. Use one of: {{allowed}}\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n scale: {\n type: \"array\",\n items: { type: \"number\" },\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ scale: DEFAULT_SCALE }],\n create(context) {\n const options = context.options[0] || {};\n const scale = new Set((options.scale || DEFAULT_SCALE).map(String));\n const scaleList = [...scale].slice(0, 10).join(\", \") + \"...\";\n\n return {\n // Check className attributes in JSX\n JSXAttribute(node) {\n if (\n node.name.type === \"JSXIdentifier\" &&\n (node.name.name === \"className\" || node.name.name === \"class\")\n ) {\n const value = node.value;\n\n if (value?.type === \"Literal\" && typeof value.value === \"string\") {\n checkSpacing(context, node, value.value, scale, scaleList);\n }\n\n if (value?.type === \"JSXExpressionContainer\") {\n const expr = value.expression;\n if (expr.type === \"Literal\" && typeof expr.value === \"string\") {\n checkSpacing(context, node, expr.value, scale, scaleList);\n }\n if (expr.type === \"TemplateLiteral\") {\n for (const quasi of expr.quasis) {\n checkSpacing(context, node, quasi.value.raw, scale, scaleList);\n }\n }\n }\n }\n },\n\n // Check cn(), clsx(), classnames() calls\n CallExpression(node) {\n if (node.callee.type !== \"Identifier\") return;\n const name = node.callee.name;\n\n if (name === \"cn\" || name === \"clsx\" || name === \"classnames\") {\n for (const arg of node.arguments) {\n if (arg.type === \"Literal\" && typeof arg.value === \"string\") {\n checkSpacing(context, arg, arg.value, scale, scaleList);\n }\n if (arg.type === \"TemplateLiteral\") {\n for (const quasi of arg.quasis) {\n checkSpacing(context, quasi, quasi.value.raw, scale, scaleList);\n }\n }\n }\n }\n },\n };\n },\n});\n\nfunction checkSpacing(\n context: Parameters<\n ReturnType<typeof createRule<Options, \"invalidSpacing\">>[\"create\"]\n >[0],\n node: TSESTree.Node,\n classString: string,\n scale: Set<string>,\n scaleList: string\n) {\n // Reset regex state\n SPACING_REGEX.lastIndex = 0;\n\n let match;\n while ((match = SPACING_REGEX.exec(classString)) !== null) {\n const [, , value] = match;\n if (value && !scale.has(value)) {\n context.report({\n node,\n messageId: \"invalidSpacing\",\n data: { value, allowed: scaleList },\n });\n }\n }\n}\n","/**\n * Rule: no-direct-store-import\n *\n * Forbids direct Zustand store imports - prefer using hooks via context.\n */\n\nimport { createRule } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"noDirectImport\";\ntype Options = [\n {\n storePattern?: string;\n }\n];\n\n// Convert glob pattern to regex\nfunction patternToRegex(pattern: string): RegExp {\n const escaped = pattern\n .replace(/[.+^${}()|[\\]\\\\]/g, \"\\\\$&\")\n .replace(/\\*/g, \".*\")\n .replace(/\\?/g, \".\");\n return new RegExp(`^${escaped}$`);\n}\n\nexport default createRule<Options, MessageIds>({\n name: \"no-direct-store-import\",\n meta: {\n type: \"problem\",\n docs: {\n description:\n \"Forbid direct Zustand store imports (use hooks via context)\",\n },\n messages: {\n noDirectImport:\n \"Avoid importing store '{{name}}' directly. Use the store via a context hook instead.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n storePattern: {\n type: \"string\",\n description: \"Glob pattern for store names\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ storePattern: \"use*Store\" }],\n create(context) {\n const options = context.options[0] || {};\n const pattern = options.storePattern || \"use*Store\";\n const regex = patternToRegex(pattern);\n\n return {\n ImportDeclaration(node) {\n // Check if importing from a store file\n const source = node.source.value as string;\n if (!source.includes(\"store\")) return;\n\n // Check imported specifiers\n for (const specifier of node.specifiers) {\n if (specifier.type === \"ImportSpecifier\") {\n const importedName =\n specifier.imported.type === \"Identifier\"\n ? specifier.imported.name\n : specifier.imported.value;\n\n if (regex.test(importedName)) {\n context.report({\n node: specifier,\n messageId: \"noDirectImport\",\n data: { name: importedName },\n });\n }\n }\n\n if (specifier.type === \"ImportDefaultSpecifier\") {\n const localName = specifier.local.name;\n if (regex.test(localName)) {\n context.report({\n node: specifier,\n messageId: \"noDirectImport\",\n data: { name: localName },\n });\n }\n }\n }\n },\n };\n },\n});\n","/**\n * Rule: no-mixed-component-libraries\n *\n * Forbids mixing shadcn/ui and MUI components in the same file.\n */\n\nimport type { TSESTree } from \"@typescript-eslint/utils\";\nimport { createRule } from \"../utils/create-rule.js\";\n\ntype MessageIds = \"mixedLibraries\";\ntype LibraryName = \"shadcn\" | \"mui\";\ntype Options = [\n {\n libraries?: LibraryName[];\n }\n];\n\nconst LIBRARY_PATTERNS: Record<LibraryName, string[]> = {\n shadcn: [\"@/components/ui\", \"@radix-ui/\", \"components/ui/\"],\n mui: [\"@mui/material\", \"@mui/icons-material\", \"@emotion/\"],\n};\n\nexport default createRule<Options, MessageIds>({\n name: \"no-mixed-component-libraries\",\n meta: {\n type: \"problem\",\n docs: {\n description: \"Forbid mixing component libraries in the same file\",\n },\n messages: {\n mixedLibraries:\n \"Mixing {{lib1}} and {{lib2}} components. Choose one library per file.\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n libraries: {\n type: \"array\",\n items: { type: \"string\", enum: [\"shadcn\", \"mui\"] },\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ libraries: [\"shadcn\", \"mui\"] }],\n create(context) {\n const options = context.options[0] || {};\n const libraries = (options.libraries || [\"shadcn\", \"mui\"]) as LibraryName[];\n const detected: Map<LibraryName, TSESTree.ImportDeclaration> = new Map();\n\n return {\n ImportDeclaration(node) {\n const source = node.source.value as string;\n\n for (const lib of libraries) {\n const patterns = LIBRARY_PATTERNS[lib];\n if (patterns?.some((p) => source.includes(p))) {\n if (!detected.has(lib)) {\n detected.set(lib, node);\n }\n }\n }\n },\n\n \"Program:exit\"() {\n if (detected.size > 1) {\n const libs = [...detected.keys()];\n const secondLib = libs[1]!;\n const secondNode = detected.get(secondLib)!;\n\n context.report({\n node: secondNode,\n messageId: \"mixedLibraries\",\n data: { lib1: libs[0], lib2: secondLib },\n });\n }\n },\n };\n },\n});\n","/**\n * Rule: semantic\n *\n * LLM-powered semantic UI analysis using the project's styleguide.\n * This is the only rule that reads .uilint/styleguide.md.\n */\n\nimport { existsSync, readFileSync } from \"fs\";\nimport { spawnSync } from \"child_process\";\nimport { dirname, join, relative } from \"path\";\nimport { createRule } from \"../utils/create-rule.js\";\nimport {\n getCacheEntry,\n hashContentSync,\n setCacheEntry,\n type CachedIssue,\n} from \"../utils/cache.js\";\nimport { getStyleguide } from \"../utils/styleguide-loader.js\";\nimport { UILINT_DEFAULT_OLLAMA_MODEL } from \"uilint-core\";\nimport { buildSourceScanPrompt } from \"uilint-core\";\n\ntype MessageIds = \"semanticIssue\" | \"styleguideNotFound\" | \"analysisError\";\ntype Options = [\n {\n model?: string;\n styleguidePath?: string;\n }\n];\n\nexport default createRule<Options, MessageIds>({\n name: \"semantic\",\n meta: {\n type: \"suggestion\",\n docs: {\n description: \"LLM-powered semantic UI analysis using styleguide\",\n },\n messages: {\n semanticIssue: \"{{message}}\",\n styleguideNotFound:\n \"No styleguide found. Create .uilint/styleguide.md or specify styleguidePath.\",\n analysisError: \"Semantic analysis failed: {{error}}\",\n },\n schema: [\n {\n type: \"object\",\n properties: {\n model: {\n type: \"string\",\n description: \"Ollama model to use\",\n },\n styleguidePath: {\n type: \"string\",\n description: \"Path to styleguide file\",\n },\n },\n additionalProperties: false,\n },\n ],\n },\n defaultOptions: [{ model: UILINT_DEFAULT_OLLAMA_MODEL }],\n create(context) {\n const options = context.options[0] || {};\n const filePath = context.filename;\n const fileDir = dirname(filePath);\n\n // Get styleguide\n const { path: styleguidePath, content: styleguide } = getStyleguide(\n fileDir,\n options.styleguidePath\n );\n\n // Skip if no styleguide\n if (!styleguide) {\n console.error(\n `[uilint] Styleguide not found (styleguidePath=${String(\n options.styleguidePath ?? \"\"\n )}, startDir=${fileDir})`\n );\n\n return {\n Program(node) {\n context.report({\n node,\n messageId: \"styleguideNotFound\",\n });\n },\n };\n }\n\n // Read and hash file contents\n let fileContent: string;\n try {\n fileContent = readFileSync(filePath, \"utf-8\");\n } catch {\n console.error(`[uilint] Failed to read file ${filePath}`);\n return {\n Program(node) {\n context.report({\n node,\n messageId: \"analysisError\",\n data: { error: `Failed to read source file ${filePath}` },\n });\n },\n };\n }\n\n const fileHash = hashContentSync(fileContent);\n const styleguideHash = hashContentSync(styleguide);\n\n // Check cache\n const projectRoot = findProjectRoot(fileDir);\n const relativeFilePath = relative(projectRoot, filePath);\n const cached = getCacheEntry(\n projectRoot,\n relativeFilePath,\n fileHash,\n styleguideHash\n );\n\n const ENABLE_CACHE = false;\n if (ENABLE_CACHE && cached) {\n console.error(`[uilint] Cache hit for ${filePath}`);\n\n // Report cached issues\n return {\n Program(node) {\n for (const issue of cached.issues) {\n context.report({\n node,\n loc: { line: issue.line, column: issue.column || 0 },\n messageId: \"semanticIssue\",\n data: { message: issue.message },\n });\n }\n },\n };\n }\n\n // Cache miss: run sync analysis now (slow), cache, then report.\n ENABLE_CACHE &&\n console.error(\n `[uilint] Cache miss for ${filePath}, running semantic analysis`\n );\n\n return {\n Program(node) {\n const issues = runSemanticAnalysisSync(\n fileContent,\n styleguide,\n options.model || UILINT_DEFAULT_OLLAMA_MODEL,\n filePath\n );\n\n setCacheEntry(projectRoot, relativeFilePath, {\n fileHash,\n styleguideHash,\n issues,\n timestamp: Date.now(),\n });\n\n for (const issue of issues) {\n context.report({\n node,\n loc: { line: issue.line, column: issue.column || 0 },\n messageId: \"semanticIssue\",\n data: { message: issue.message },\n });\n }\n },\n };\n },\n});\n\n/**\n * Find project root by looking for package.json\n */\nfunction findProjectRoot(startDir: string): string {\n let dir = startDir;\n for (let i = 0; i < 20; i++) {\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Run semantic analysis using Ollama (synchronously).\n *\n * Implementation detail:\n * - ESLint rules are synchronous.\n * - Blocking on a Promise (sleep-loop/Atomics) would also block Node's event loop,\n * preventing the HTTP request to Ollama from ever completing.\n * - To keep this simple & debuggable, we run the async LLM call in a child Node\n * process and synchronously wait for it to exit.\n */\nfunction runSemanticAnalysisSync(\n sourceCode: string,\n styleguide: string,\n model: string,\n filePath?: string\n): CachedIssue[] {\n const startTime = Date.now();\n const fileDisplay = filePath ? ` ${filePath}` : \"\";\n\n console.error(`[uilint] Starting semantic analysis (sync)${fileDisplay}`);\n console.error(`[uilint] Model: ${model}`);\n\n // Build prompt in-process (pure string building).\n const prompt = buildSourceScanPrompt(sourceCode, styleguide, {});\n\n // Avoid `uilint-core/node` exports *and* CJS resolution:\n // resolve the installed dependency by file URL relative to this plugin bundle.\n // When built, `import.meta.url` points at `.../uilint-eslint/dist/index.js`,\n // and the dependency lives at `.../uilint-eslint/node_modules/uilint-core/dist/node.js`.\n const coreNodeUrl = new URL(\n \"../node_modules/uilint-core/dist/node.js\",\n import.meta.url\n ).href;\n\n const childScript = `\n import * as coreNode from ${JSON.stringify(coreNodeUrl)};\n const { OllamaClient, logInfo, logWarning, createProgress, pc } = coreNode;\n const chunks = [];\n for await (const c of process.stdin) chunks.push(c);\n const input = JSON.parse(Buffer.concat(chunks).toString(\"utf8\"));\n const model = input.model;\n const prompt = input.prompt;\n\n const client = new OllamaClient({ model });\n const ok = await client.isAvailable();\n if (!ok) {\n logWarning(\"Ollama not available, skipping semantic analysis\");\n process.stdout.write(JSON.stringify({ issues: [] }));\n process.exit(0);\n }\n\n logInfo(\\`Ollama connected \\${pc.dim(\\`(model: \\${model})\\`)}\\`);\n const progress = createProgress(\"Analyzing with LLM...\");\n try {\n const response = await client.complete(prompt, {\n json: true,\n stream: true,\n onProgress: (latestLine) => {\n const maxLen = 60;\n const display =\n latestLine.length > maxLen\n ? latestLine.slice(0, maxLen) + \"…\"\n : latestLine;\n progress.update(\\`LLM: \\${pc.dim(display || \"...\")}\\`);\n },\n });\n progress.succeed(\"LLM complete\");\n process.stdout.write(response);\n } catch (e) {\n progress.fail(\\`LLM failed: \\${e instanceof Error ? e.message : String(e)}\\`);\n process.exit(1);\n }\n `;\n\n const child = spawnSync(\n process.execPath,\n [\"--input-type=module\", \"-e\", childScript],\n {\n input: JSON.stringify({ model, prompt }),\n encoding: \"utf8\",\n stdio: [\"pipe\", \"pipe\", \"inherit\"],\n maxBuffer: 20 * 1024 * 1024,\n }\n );\n\n const elapsed = Date.now() - startTime;\n\n if (child.error) {\n console.error(\n `[uilint] Semantic analysis failed after ${elapsed}ms: ${child.error.message}`\n );\n return [];\n }\n\n if (typeof child.status === \"number\" && child.status !== 0) {\n console.error(\n `[uilint] Semantic analysis failed after ${elapsed}ms: child exited ${child.status}`\n );\n return [];\n }\n\n const responseText = (child.stdout || \"\").trim();\n if (!responseText) {\n console.error(\n `[uilint] Semantic analysis returned empty response (${elapsed}ms)`\n );\n return [];\n }\n\n try {\n const parsed = JSON.parse(responseText) as {\n issues?: Array<{ line?: number; column?: number; message?: string }>;\n };\n\n const issues = (parsed.issues || []).map((issue) => ({\n line: issue.line || 1,\n column: issue.column,\n message: issue.message || \"Semantic issue detected\",\n ruleId: \"uilint/semantic\",\n severity: 1 as const,\n }));\n\n if (issues.length > 0) {\n console.error(`[uilint] Found ${issues.length} issue(s) (${elapsed}ms)`);\n } else {\n console.error(`[uilint] No issues found (${elapsed}ms)`);\n }\n\n return issues;\n } catch (e) {\n console.error(\n `[uilint] Semantic analysis failed to parse response after ${elapsed}ms: ${\n e instanceof Error ? e.message : String(e)\n }`\n );\n return [];\n }\n}\n","/**\n * File-hash based caching for LLM semantic rule\n *\n * Uses xxhash for fast hashing of file contents.\n */\n\nimport { existsSync, mkdirSync, readFileSync, writeFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\n// Lazy-loaded xxhash\nlet xxhashInstance: Awaited<ReturnType<typeof import(\"xxhash-wasm\")[\"default\"]>> | null = null;\n\nasync function getXxhash() {\n if (!xxhashInstance) {\n const xxhash = await import(\"xxhash-wasm\");\n xxhashInstance = await xxhash.default();\n }\n return xxhashInstance;\n}\n\n/**\n * Synchronous hash using a simple djb2 algorithm (fallback when xxhash not available)\n */\nfunction djb2Hash(str: string): string {\n let hash = 5381;\n for (let i = 0; i < str.length; i++) {\n hash = (hash * 33) ^ str.charCodeAt(i);\n }\n return (hash >>> 0).toString(16);\n}\n\n/**\n * Hash content using xxhash (async) or djb2 (sync fallback)\n */\nexport async function hashContent(content: string): Promise<string> {\n try {\n const xxhash = await getXxhash();\n return xxhash.h64ToString(content);\n } catch {\n return djb2Hash(content);\n }\n}\n\n/**\n * Synchronous hash for when async is not possible\n */\nexport function hashContentSync(content: string): string {\n return djb2Hash(content);\n}\n\nexport interface CacheEntry {\n fileHash: string;\n styleguideHash: string;\n issues: CachedIssue[];\n timestamp: number;\n}\n\nexport interface CachedIssue {\n line: number;\n column?: number;\n message: string;\n ruleId: string;\n severity: 1 | 2; // 1 = warn, 2 = error\n}\n\nexport interface CacheStore {\n version: number;\n entries: Record<string, CacheEntry>;\n}\n\nconst CACHE_VERSION = 1;\nconst CACHE_FILE = \".uilint/.cache/eslint-semantic.json\";\n\n/**\n * Get the cache file path for a project\n */\nexport function getCachePath(projectRoot: string): string {\n return join(projectRoot, CACHE_FILE);\n}\n\n/**\n * Load the cache store\n */\nexport function loadCache(projectRoot: string): CacheStore {\n const cachePath = getCachePath(projectRoot);\n\n if (!existsSync(cachePath)) {\n return { version: CACHE_VERSION, entries: {} };\n }\n\n try {\n const content = readFileSync(cachePath, \"utf-8\");\n const cache = JSON.parse(content) as CacheStore;\n\n // Invalidate if version mismatch\n if (cache.version !== CACHE_VERSION) {\n return { version: CACHE_VERSION, entries: {} };\n }\n\n return cache;\n } catch {\n return { version: CACHE_VERSION, entries: {} };\n }\n}\n\n/**\n * Save the cache store\n */\nexport function saveCache(projectRoot: string, cache: CacheStore): void {\n const cachePath = getCachePath(projectRoot);\n\n try {\n const cacheDir = dirname(cachePath);\n if (!existsSync(cacheDir)) {\n mkdirSync(cacheDir, { recursive: true });\n }\n\n writeFileSync(cachePath, JSON.stringify(cache, null, 2), \"utf-8\");\n } catch {\n // Silently fail - caching is optional\n }\n}\n\n/**\n * Get cached entry for a file\n */\nexport function getCacheEntry(\n projectRoot: string,\n filePath: string,\n fileHash: string,\n styleguideHash: string\n): CacheEntry | null {\n const cache = loadCache(projectRoot);\n const entry = cache.entries[filePath];\n\n if (!entry) return null;\n\n // Check if hashes match\n if (entry.fileHash !== fileHash || entry.styleguideHash !== styleguideHash) {\n return null;\n }\n\n return entry;\n}\n\n/**\n * Set cached entry for a file\n */\nexport function setCacheEntry(\n projectRoot: string,\n filePath: string,\n entry: CacheEntry\n): void {\n const cache = loadCache(projectRoot);\n cache.entries[filePath] = entry;\n saveCache(projectRoot, cache);\n}\n\n/**\n * Clear cache for a specific file\n */\nexport function clearCacheEntry(projectRoot: string, filePath: string): void {\n const cache = loadCache(projectRoot);\n delete cache.entries[filePath];\n saveCache(projectRoot, cache);\n}\n\n/**\n * Clear entire cache\n */\nexport function clearCache(projectRoot: string): void {\n saveCache(projectRoot, { version: CACHE_VERSION, entries: {} });\n}\n","/**\n * Styleguide loader for the LLM semantic rule\n *\n * Only the semantic rule reads the styleguide - static rules use ESLint options.\n */\n\nimport { existsSync, readFileSync } from \"fs\";\nimport { dirname, isAbsolute, join, resolve } from \"path\";\n\nconst DEFAULT_STYLEGUIDE_PATHS = [\n \".uilint/styleguide.md\",\n \".uilint/styleguide.yaml\",\n \".uilint/styleguide.yml\",\n];\n\n/**\n * Find workspace root by walking up looking for pnpm-workspace.yaml, package.json, or .git\n */\nfunction findWorkspaceRoot(startDir: string): string {\n let dir = startDir;\n for (let i = 0; i < 20; i++) {\n if (\n existsSync(join(dir, \"pnpm-workspace.yaml\")) ||\n existsSync(join(dir, \".git\"))\n ) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Find the nearest package root (directory containing package.json),\n * stopping at the workspace root.\n */\nfunction findNearestPackageRoot(startDir: string, workspaceRoot: string): string {\n let dir = startDir;\n for (let i = 0; i < 30; i++) {\n if (existsSync(join(dir, \"package.json\"))) return dir;\n if (dir === workspaceRoot) break;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return startDir;\n}\n\n/**\n * Find the styleguide file path\n */\nexport function findStyleguidePath(\n startDir: string,\n explicitPath?: string\n): string | null {\n // Explicit path takes precedence\n if (explicitPath) {\n if (isAbsolute(explicitPath)) {\n return existsSync(explicitPath) ? explicitPath : null;\n }\n\n // For relative explicit paths, try:\n // 1) relative to the file dir (back-compat)\n // 2) relative to the nearest package root (typical \"project root\")\n // 3) relative to workspace root (monorepo root)\n const workspaceRoot = findWorkspaceRoot(startDir);\n const packageRoot = findNearestPackageRoot(startDir, workspaceRoot);\n\n const candidates = [\n resolve(startDir, explicitPath),\n resolve(packageRoot, explicitPath),\n resolve(workspaceRoot, explicitPath),\n ];\n\n for (const p of candidates) {\n if (existsSync(p)) return p;\n }\n\n return null;\n }\n\n // Check from start dir up to workspace root\n const workspaceRoot = findWorkspaceRoot(startDir);\n let dir = startDir;\n\n while (true) {\n for (const relativePath of DEFAULT_STYLEGUIDE_PATHS) {\n const fullPath = join(dir, relativePath);\n if (existsSync(fullPath)) {\n return fullPath;\n }\n }\n\n // Stop at workspace root\n if (dir === workspaceRoot) break;\n\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n\n return null;\n}\n\n/**\n * Load styleguide content from file\n */\nexport function loadStyleguide(\n startDir: string,\n explicitPath?: string\n): string | null {\n const path = findStyleguidePath(startDir, explicitPath);\n if (!path) return null;\n\n try {\n return readFileSync(path, \"utf-8\");\n } catch {\n return null;\n }\n}\n\n/**\n * Get styleguide path and content\n */\nexport function getStyleguide(\n startDir: string,\n explicitPath?: string\n): { path: string | null; content: string | null } {\n const path = findStyleguidePath(startDir, explicitPath);\n if (!path) return { path: null, content: null };\n\n try {\n const content = readFileSync(path, \"utf-8\");\n return { path, content };\n } catch {\n return { path, content: null };\n }\n}\n","/**\n * Rule Registry\n *\n * Central registry of all UILint ESLint rules with metadata for CLI tooling.\n * This allows the installer to auto-discover available rules and present them\n * to the user with descriptions.\n */\n\nexport interface RuleMetadata {\n /** Rule identifier (e.g., \"no-arbitrary-tailwind\") */\n id: string;\n /** Display name for CLI */\n name: string;\n /** Short description for CLI selection prompts */\n description: string;\n /** Default severity level */\n defaultSeverity: \"error\" | \"warn\" | \"off\";\n /** Default options for the rule */\n defaultOptions?: unknown[];\n /** Whether this rule requires a styleguide file */\n requiresStyleguide?: boolean;\n /** Category for grouping */\n category: \"static\" | \"semantic\";\n}\n\n/**\n * Registry of all available UILint ESLint rules\n *\n * When adding a new rule:\n * 1. Add the rule implementation to src/rules/\n * 2. Add an entry here with metadata\n * 3. Export the rule from src/index.ts\n * 4. The CLI installer will automatically discover and offer it\n */\nexport const ruleRegistry: RuleMetadata[] = [\n {\n id: \"no-arbitrary-tailwind\",\n name: \"No Arbitrary Tailwind\",\n description: \"Forbid arbitrary values like w-[123px], bg-[#fff]\",\n defaultSeverity: \"error\",\n category: \"static\",\n },\n {\n id: \"consistent-spacing\",\n name: \"Consistent Spacing\",\n description: \"Enforce spacing scale (no magic numbers in gap/padding)\",\n defaultSeverity: \"warn\",\n defaultOptions: [{ scale: [0, 1, 2, 3, 4, 5, 6, 8, 10, 12, 16] }],\n category: \"static\",\n },\n {\n id: \"no-direct-store-import\",\n name: \"No Direct Store Import\",\n description: \"Forbid direct Zustand store imports (use context hooks)\",\n defaultSeverity: \"warn\",\n defaultOptions: [{ storePattern: \"use*Store\" }],\n category: \"static\",\n },\n {\n id: \"no-mixed-component-libraries\",\n name: \"No Mixed Component Libraries\",\n description: \"Forbid mixing component libraries (e.g., shadcn + MUI)\",\n defaultSeverity: \"error\",\n defaultOptions: [{ libraries: [\"shadcn\", \"mui\"] }],\n category: \"static\",\n },\n {\n id: \"semantic\",\n name: \"Semantic Analysis\",\n description: \"LLM-powered semantic UI analysis using your styleguide\",\n defaultSeverity: \"warn\",\n defaultOptions: [{ model: \"qwen3-coder:30b\", styleguidePath: \".uilint/styleguide.md\" }],\n requiresStyleguide: true,\n category: \"semantic\",\n },\n];\n\n/**\n * Get rule metadata by ID\n */\nexport function getRuleMetadata(id: string): RuleMetadata | undefined {\n return ruleRegistry.find((rule) => rule.id === id);\n}\n\n/**\n * Get all rules in a category\n */\nexport function getRulesByCategory(\n category: \"static\" | \"semantic\"\n): RuleMetadata[] {\n return ruleRegistry.filter((rule) => rule.category === category);\n}\n","/**\n * UILint ESLint Plugin\n *\n * Provides ESLint rules for UI consistency checking:\n * - Static rules for common patterns (arbitrary values, spacing, component libraries)\n * - LLM-powered semantic rule that reads your styleguide\n */\n\nimport type { Linter } from \"eslint\";\nimport noArbitraryTailwind from \"./rules/no-arbitrary-tailwind.js\";\nimport consistentSpacing from \"./rules/consistent-spacing.js\";\nimport noDirectStoreImport from \"./rules/no-direct-store-import.js\";\nimport noMixedComponentLibraries from \"./rules/no-mixed-component-libraries.js\";\nimport semantic from \"./rules/semantic.js\";\n\n// Package version (injected at build time or fallback)\nconst version = \"0.1.0\";\n\n/**\n * All available rules\n */\nconst rules = {\n \"no-arbitrary-tailwind\": noArbitraryTailwind,\n \"consistent-spacing\": consistentSpacing,\n \"no-direct-store-import\": noDirectStoreImport,\n \"no-mixed-component-libraries\": noMixedComponentLibraries,\n semantic: semantic,\n};\n\n/**\n * Plugin metadata\n */\nconst meta = {\n name: \"uilint\",\n version,\n};\n\n/**\n * The ESLint plugin object\n */\nconst plugin = {\n meta,\n rules,\n};\n\n/**\n * Shared language options for all configs\n */\nconst jsxLanguageOptions: Linter.Config[\"languageOptions\"] = {\n parserOptions: {\n ecmaFeatures: {\n jsx: true,\n },\n },\n};\n\n/**\n * Recommended config - static rules only\n *\n * Usage:\n * ```js\n * import uilint from 'uilint-eslint';\n * export default [uilint.configs.recommended];\n * ```\n */\nconst recommendedConfig: Linter.Config = {\n name: \"uilint/recommended\",\n plugins: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n uilint: plugin as any,\n },\n languageOptions: jsxLanguageOptions,\n rules: {\n \"uilint/no-arbitrary-tailwind\": \"error\",\n \"uilint/consistent-spacing\": \"warn\",\n \"uilint/no-direct-store-import\": \"warn\",\n \"uilint/no-mixed-component-libraries\": \"error\",\n },\n};\n\n/**\n * Strict config - static rules + LLM semantic rule\n *\n * Usage:\n * ```js\n * import uilint from 'uilint-eslint';\n * export default [uilint.configs.strict];\n * ```\n */\nconst strictConfig: Linter.Config = {\n name: \"uilint/strict\",\n plugins: {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n uilint: plugin as any,\n },\n languageOptions: jsxLanguageOptions,\n rules: {\n \"uilint/no-arbitrary-tailwind\": \"error\",\n \"uilint/consistent-spacing\": \"warn\",\n \"uilint/no-direct-store-import\": \"error\",\n \"uilint/no-mixed-component-libraries\": \"error\",\n \"uilint/semantic\": \"warn\",\n },\n};\n\n/**\n * Pre-configured configs\n */\nconst configs: Record<string, Linter.Config> = {\n recommended: recommendedConfig,\n strict: strictConfig,\n};\n\n/**\n * UILint ESLint export interface\n */\nexport interface UILintESLint {\n meta: typeof meta;\n plugin: typeof plugin;\n rules: typeof rules;\n configs: Record<string, Linter.Config>;\n}\n\n/**\n * Default export for ESLint flat config\n */\nconst uilintEslint: UILintESLint = {\n meta,\n plugin,\n rules,\n configs,\n};\n\nexport default uilintEslint;\n\n// Named exports for convenience\nexport { plugin, rules, configs, meta };\n\n// Re-export utilities for custom rule creation\nexport { createRule } from \"./utils/create-rule.js\";\nexport {\n loadStyleguide,\n findStyleguidePath,\n getStyleguide,\n} from \"./utils/styleguide-loader.js\";\nexport {\n hashContent,\n hashContentSync,\n getCacheEntry,\n setCacheEntry,\n clearCache,\n clearCacheEntry,\n loadCache,\n saveCache,\n type CacheEntry,\n type CachedIssue,\n type CacheStore,\n} from \"./utils/cache.js\";\n\n// Re-export rule registry for CLI tooling\nexport {\n ruleRegistry,\n getRuleMetadata,\n getRulesByCategory,\n type RuleMetadata,\n} from \"./rule-registry.js\";\n"],"mappings":"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","names":["existsSync","readFileSync","dirname","join","existsSync","readFileSync","dirname","join","workspaceRoot","dirname","readFileSync","existsSync","join"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uilint-eslint",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "ESLint plugin for UILint - AI-powered UI consistency checking",
5
5
  "author": "Peter Suggate",
6
6
  "repository": {
@@ -31,7 +31,7 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "@typescript-eslint/utils": "^8.35.1",
34
- "uilint-core": "^0.1.32",
34
+ "uilint-core": "^0.1.33",
35
35
  "xxhash-wasm": "^1.1.0"
36
36
  },
37
37
  "devDependencies": {