uilint-core 0.1.5 → 0.1.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,143 @@
1
+ # uilint-core
2
+
3
+ Core library for UILint - AI-powered UI consistency checking for React and Next.js applications.
4
+
5
+ ## Overview
6
+
7
+ `uilint-core` provides the foundational functionality for UILint, including:
8
+
9
+ - **Style extraction** - Parses HTML/CSS to extract colors, typography, spacing, and component patterns
10
+ - **Ollama integration** - Client for local LLM analysis via Ollama
11
+ - **Style guide management** - Read, write, and generate style guides
12
+ - **Tailwind support** - Extract and validate Tailwind CSS class usage
13
+ - **Validation** - Core validation logic for detecting UI inconsistencies
14
+
15
+ This package is typically used as a dependency by `uilint-cli`, `uilint-react`, or `uilint-mcp`.
16
+
17
+ ## Installation
18
+
19
+ ```bash
20
+ npm install uilint-core
21
+ ```
22
+
23
+ ## Usage
24
+
25
+ ### Ollama Client
26
+
27
+ ```typescript
28
+ import { OllamaClient } from "uilint-core";
29
+
30
+ const client = new OllamaClient({ model: "qwen2.5-coder:7b" });
31
+
32
+ // Generate a style guide from extracted styles
33
+ const styleGuide = await client.generateStyleGuide({
34
+ colors: { "#3B82F6": 10, "#1E40AF": 5 },
35
+ fontSizes: ["14px", "16px", "18px"],
36
+ spacing: ["8px", "16px", "24px"],
37
+ });
38
+
39
+ // Analyze UI for inconsistencies
40
+ const result = await client.analyzeStyles(styleSummary, styleGuide);
41
+ console.log(result.issues);
42
+ ```
43
+
44
+ ### Style Extraction
45
+
46
+ ```typescript
47
+ import { extractStylesFromHTML } from "uilint-core";
48
+
49
+ const html = `<div style="color: #3B82F6; font-size: 16px;">Hello</div>`;
50
+ const styles = extractStylesFromHTML(html);
51
+
52
+ console.log(styles.colors); // { "#3B82F6": 1 }
53
+ console.log(styles.fontSizes); // ["16px"]
54
+ ```
55
+
56
+ ### Style Guide Management (Node.js)
57
+
58
+ ```typescript
59
+ import {
60
+ readStyleGuideFromProject,
61
+ writeStyleGuide,
62
+ styleGuideExists,
63
+ getDefaultStyleGuidePath,
64
+ } from "uilint-core/node";
65
+
66
+ const projectPath = process.cwd();
67
+
68
+ // Check if style guide exists
69
+ if (styleGuideExists(projectPath)) {
70
+ // Read the style guide
71
+ const content = await readStyleGuideFromProject(projectPath);
72
+ console.log(content);
73
+ }
74
+
75
+ // Write a new style guide
76
+ const guidePath = getDefaultStyleGuidePath(projectPath);
77
+ await writeStyleGuide(guidePath, "# My Style Guide\n...");
78
+ ```
79
+
80
+ ## API
81
+
82
+ ### OllamaClient
83
+
84
+ ```typescript
85
+ class OllamaClient {
86
+ constructor(options: { model?: string; baseUrl?: string });
87
+
88
+ generateStyleGuide(styleSummary: StyleSummary): Promise<string>;
89
+ analyzeStyles(
90
+ styleSummary: StyleSummary,
91
+ styleGuide: string
92
+ ): Promise<AnalysisResult>;
93
+ queryStyleGuide(styleGuide: string, query: string): Promise<string>;
94
+ }
95
+ ```
96
+
97
+ ### Style Extraction
98
+
99
+ ```typescript
100
+ function extractStylesFromHTML(html: string): StyleSummary;
101
+
102
+ interface StyleSummary {
103
+ colors: Record<string, number>;
104
+ fontSizes: string[];
105
+ fontFamilies: string[];
106
+ spacing: string[];
107
+ borderRadius: string[];
108
+ shadows: string[];
109
+ tailwindClasses?: Record<string, number>;
110
+ }
111
+ ```
112
+
113
+ ### Style Guide Management
114
+
115
+ ```typescript
116
+ function readStyleGuideFromProject(projectPath: string): Promise<string>;
117
+ function writeStyleGuide(path: string, content: string): Promise<void>;
118
+ function styleGuideExists(projectPath: string): boolean;
119
+ function getDefaultStyleGuidePath(projectPath: string): string;
120
+ ```
121
+
122
+ ## Prerequisites
123
+
124
+ For LLM-powered features, you need [Ollama](https://ollama.ai) installed locally:
125
+
126
+ ```bash
127
+ # Install Ollama, then pull the default model
128
+ ollama pull qwen2.5-coder:7b
129
+ ```
130
+
131
+ ## Related Packages
132
+
133
+ - [`uilint-cli`](https://www.npmjs.com/package/uilint-cli) - Command-line interface
134
+ - [`uilint-react`](https://www.npmjs.com/package/uilint-react) - React component for runtime analysis
135
+ - [`uilint-mcp`](https://www.npmjs.com/package/uilint-mcp) - MCP server for editor integration
136
+
137
+ ## Documentation
138
+
139
+ For full documentation, visit the [UILint GitHub repository](https://github.com/peter-suggate/uilint).
140
+
141
+ ## License
142
+
143
+ MIT
@@ -81,7 +81,7 @@ function buildQueryPrompt(query, styleGuide) {
81
81
  if (!styleGuide) {
82
82
  return `The user is asking: "${query}"
83
83
 
84
- No style guide has been created yet. Explain that they should run "uilint init" to create a style guide from their existing styles.`;
84
+ No style guide has been created yet. Explain that they should create ".uilint/styleguide.md" (recommended: run "/genstyleguide" in Cursor) and then try again.`;
85
85
  }
86
86
  return `You are a helpful assistant that answers questions about a UI style guide.
87
87
 
@@ -110,11 +110,11 @@ var OllamaClient = class {
110
110
  /**
111
111
  * Analyzes styles and returns issues
112
112
  */
113
- async analyzeStyles(styleSummary, styleGuide) {
113
+ async analyzeStyles(styleSummary, styleGuide, onProgress) {
114
114
  const startTime = Date.now();
115
115
  const prompt = buildAnalysisPrompt(styleSummary, styleGuide);
116
116
  try {
117
- const response = await this.generate(prompt);
117
+ const response = onProgress ? await this.generateStreaming(prompt, true, onProgress) : await this.generate(prompt);
118
118
  const issues = this.parseIssuesResponse(response);
119
119
  return {
120
120
  issues,
@@ -181,6 +181,69 @@ var OllamaClient = class {
181
181
  clearTimeout(timeoutId);
182
182
  }
183
183
  }
184
+ /**
185
+ * Streaming generate method that calls Ollama API with streaming
186
+ * and reports progress via callback
187
+ */
188
+ async generateStreaming(prompt, jsonFormat = true, onProgress) {
189
+ const controller = new AbortController();
190
+ const timeoutId = setTimeout(() => controller.abort(), this.timeout);
191
+ try {
192
+ const response = await fetch(`${this.baseUrl}/api/generate`, {
193
+ method: "POST",
194
+ headers: { "Content-Type": "application/json" },
195
+ body: JSON.stringify({
196
+ model: this.model,
197
+ prompt,
198
+ stream: true,
199
+ ...jsonFormat && { format: "json" }
200
+ }),
201
+ signal: controller.signal
202
+ });
203
+ if (!response.ok) {
204
+ throw new Error(`Ollama API error: ${response.status}`);
205
+ }
206
+ if (!response.body) {
207
+ throw new Error("No response body for streaming");
208
+ }
209
+ const reader = response.body.getReader();
210
+ const decoder = new TextDecoder();
211
+ let fullResponse = "";
212
+ let buffer = "";
213
+ while (true) {
214
+ const { done, value } = await reader.read();
215
+ if (done) break;
216
+ buffer += decoder.decode(value, { stream: true });
217
+ const lines = buffer.split("\n");
218
+ buffer = lines.pop() || "";
219
+ for (const line of lines) {
220
+ if (!line.trim()) continue;
221
+ try {
222
+ const chunk = JSON.parse(line);
223
+ if (chunk.response) {
224
+ fullResponse += chunk.response;
225
+ const responseLines = fullResponse.split("\n");
226
+ const latestLine = responseLines[responseLines.length - 1] || responseLines[responseLines.length - 2] || "";
227
+ onProgress(latestLine.trim(), fullResponse);
228
+ }
229
+ } catch {
230
+ }
231
+ }
232
+ }
233
+ if (buffer.trim()) {
234
+ try {
235
+ const chunk = JSON.parse(buffer);
236
+ if (chunk.response) {
237
+ fullResponse += chunk.response;
238
+ }
239
+ } catch {
240
+ }
241
+ }
242
+ return fullResponse;
243
+ } finally {
244
+ clearTimeout(timeoutId);
245
+ }
246
+ }
184
247
  /**
185
248
  * Parses issues from LLM response
186
249
  */
@@ -725,11 +788,21 @@ function extractTailwindAllowlist(content) {
725
788
  (u) => typeof u === "string"
726
789
  ) : [];
727
790
  const themeTokens = parsed.themeTokens ?? {};
728
- const themeColors = Array.isArray(themeTokens.colors) ? themeTokens.colors.filter((c) => typeof c === "string") : [];
729
- const spacingKeys = Array.isArray(themeTokens.spacingKeys) ? themeTokens.spacingKeys.filter((k) => typeof k === "string") : [];
730
- const borderRadiusKeys = Array.isArray(themeTokens.borderRadiusKeys) ? themeTokens.borderRadiusKeys.filter((k) => typeof k === "string") : [];
731
- const fontFamilyKeys = Array.isArray(themeTokens.fontFamilyKeys) ? themeTokens.fontFamilyKeys.filter((k) => typeof k === "string") : [];
732
- const fontSizeKeys = Array.isArray(themeTokens.fontSizeKeys) ? themeTokens.fontSizeKeys.filter((k) => typeof k === "string") : [];
791
+ const themeColors = Array.isArray(themeTokens.colors) ? themeTokens.colors.filter(
792
+ (c) => typeof c === "string"
793
+ ) : [];
794
+ const spacingKeys = Array.isArray(themeTokens.spacingKeys) ? themeTokens.spacingKeys.filter(
795
+ (k) => typeof k === "string"
796
+ ) : [];
797
+ const borderRadiusKeys = Array.isArray(themeTokens.borderRadiusKeys) ? themeTokens.borderRadiusKeys.filter(
798
+ (k) => typeof k === "string"
799
+ ) : [];
800
+ const fontFamilyKeys = Array.isArray(themeTokens.fontFamilyKeys) ? themeTokens.fontFamilyKeys.filter(
801
+ (k) => typeof k === "string"
802
+ ) : [];
803
+ const fontSizeKeys = Array.isArray(themeTokens.fontSizeKeys) ? themeTokens.fontSizeKeys.filter(
804
+ (k) => typeof k === "string"
805
+ ) : [];
733
806
  const allowedTailwindColors = /* @__PURE__ */ new Set();
734
807
  for (const c of themeColors) {
735
808
  const raw = c.trim();
@@ -747,11 +820,21 @@ function extractTailwindAllowlist(content) {
747
820
  allowAnyColor,
748
821
  allowStandardSpacing,
749
822
  allowedTailwindColors,
750
- allowedUtilities: new Set(allowedUtilitiesArr.map((s) => s.trim()).filter(Boolean)),
751
- allowedSpacingKeys: new Set(spacingKeys.map((s) => s.trim()).filter(Boolean)),
752
- allowedBorderRadiusKeys: new Set(borderRadiusKeys.map((s) => s.trim()).filter(Boolean)),
753
- allowedFontSizeKeys: new Set(fontSizeKeys.map((s) => s.trim()).filter(Boolean)),
754
- allowedFontFamilyKeys: new Set(fontFamilyKeys.map((s) => s.trim()).filter(Boolean))
823
+ allowedUtilities: new Set(
824
+ allowedUtilitiesArr.map((s) => s.trim()).filter(Boolean)
825
+ ),
826
+ allowedSpacingKeys: new Set(
827
+ spacingKeys.map((s) => s.trim()).filter(Boolean)
828
+ ),
829
+ allowedBorderRadiusKeys: new Set(
830
+ borderRadiusKeys.map((s) => s.trim()).filter(Boolean)
831
+ ),
832
+ allowedFontSizeKeys: new Set(
833
+ fontSizeKeys.map((s) => s.trim()).filter(Boolean)
834
+ ),
835
+ allowedFontFamilyKeys: new Set(
836
+ fontFamilyKeys.map((s) => s.trim()).filter(Boolean)
837
+ )
755
838
  };
756
839
  }
757
840
  const backticked = [];
@@ -768,7 +851,9 @@ function extractTailwindAllowlist(content) {
768
851
  function tryParseFirstJsonCodeBlock(section) {
769
852
  const jsonBlocks = [...section.matchAll(/```json\s*([\s\S]*?)```/gi)];
770
853
  const anyBlocks = [...section.matchAll(/```\s*([\s\S]*?)```/g)];
771
- const candidates = (jsonBlocks.length ? jsonBlocks : anyBlocks).map((m) => m[1]);
854
+ const candidates = (jsonBlocks.length ? jsonBlocks : anyBlocks).map(
855
+ (m) => m[1]
856
+ );
772
857
  for (const raw of candidates) {
773
858
  const trimmed = raw.trim();
774
859
  if (!trimmed) continue;
@@ -1021,4 +1106,4 @@ export {
1021
1106
  generateStyleGuideFromStyles,
1022
1107
  styleGuideToMarkdown
1023
1108
  };
1024
- //# sourceMappingURL=chunk-P2QQGDQS.js.map
1109
+ //# sourceMappingURL=chunk-5VPZOH2K.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/ollama/prompts.ts","../src/ollama/client.ts","../src/tailwind/class-tokens.ts","../src/scanner/style-extractor.ts","../src/styleguide/schema.ts","../src/styleguide/parser.ts","../src/styleguide/generator.ts"],"sourcesContent":["/**\n * LLM prompt builders for UILint analysis\n */\n\n/**\n * Builds a prompt for style analysis\n */\nexport function buildAnalysisPrompt(\n styleSummary: string,\n styleGuide: string | null\n): string {\n const guideSection = styleGuide\n ? `## Current Style Guide\\n${styleGuide}\\n\\n`\n : \"## No Style Guide Found\\nAnalyze the styles and identify inconsistencies.\\n\\n\";\n\n return `You are a UI consistency analyzer. Analyze the following extracted styles and identify inconsistencies.\n\n${guideSection}\n\n${styleSummary}\n\nRespond with a JSON object containing an \"issues\" array. Each issue should have:\n- id: unique string identifier\n- type: one of \"color\", \"typography\", \"spacing\", \"component\", \"responsive\", \"accessibility\"\n- message: human-readable description of the issue\n- currentValue: the problematic value found\n- expectedValue: what it should be (if known from style guide)\n- suggestion: how to fix it\n\nFocus on:\n1. Similar but not identical colors (e.g., #3B82F6 vs #3575E2)\n2. Inconsistent font sizes or weights\n3. Spacing values that don't follow a consistent scale (e.g., 4px base unit)\n4. Mixed border-radius values\n5. If utility/Tailwind classes are present in the summary, treat them as the styling surface area and flag inconsistent utility usage (e.g., mixing px-4 and px-5 for the same component type)\n\nBe concise and actionable. Only report significant inconsistencies.\n\nExample response:\n{\n \"issues\": [\n {\n \"id\": \"color-1\",\n \"type\": \"color\",\n \"message\": \"Found similar blue colors that should be consolidated\",\n \"currentValue\": \"#3575E2\",\n \"expectedValue\": \"#3B82F6\",\n \"suggestion\": \"Use the primary blue #3B82F6 consistently\"\n }\n ]\n}`;\n}\n\n/**\n * Builds a prompt for style guide generation\n */\nexport function buildStyleGuidePrompt(styleSummary: string): string {\n return `You are a design system expert. Based on the following detected styles, generate a clean, organized style guide in Markdown format.\n\n${styleSummary}\n\nGenerate a style guide with these sections:\n1. Colors - List the main colors with semantic names (Primary, Secondary, etc.)\n2. Typography - Font families, sizes, and weights\n3. Spacing - Base unit and common spacing values\n4. Components - Common component patterns\n5. Tailwind (if utility classes are present) - list commonly used utilities and any relevant theme tokens\n\nUse this format:\n# UI Style Guide\n\n## Colors\n- **Primary**: #HEXCODE (usage description)\n- **Secondary**: #HEXCODE (usage description)\n...\n\n## Typography\n- **Font Family**: FontName\n- **Font Sizes**: list of sizes\n- **Font Weights**: list of weights\n\n## Spacing\n- **Base unit**: Xpx\n- **Common values**: list of values\n\n## Components\n- **Buttons**: styles\n- **Cards**: styles\n...\n\nBe concise and focus on the most used values.`;\n}\n\n/**\n * Builds a prompt for querying the style guide\n */\nexport function buildQueryPrompt(\n query: string,\n styleGuide: string | null\n): string {\n if (!styleGuide) {\n return `The user is asking: \"${query}\"\n\nNo style guide has been created yet. Explain that they should create \".uilint/styleguide.md\" (recommended: run \"/genstyleguide\" in Cursor) and then try again.`;\n }\n\n return `You are a helpful assistant that answers questions about a UI style guide.\n\n## Style Guide\n${styleGuide}\n\n## User Question\n${query}\n\nProvide a clear, concise answer based on the style guide above. If the style guide doesn't contain the information needed, say so and suggest what might be missing.`;\n}\n","/**\n * Ollama API client for LLM interactions\n */\n\nimport type {\n UILintIssue,\n AnalysisResult,\n OllamaClientOptions,\n StreamProgressCallback,\n} from \"../types.js\";\nimport {\n buildAnalysisPrompt,\n buildStyleGuidePrompt,\n buildQueryPrompt,\n} from \"./prompts.js\";\n\nconst DEFAULT_BASE_URL = \"http://localhost:11434\";\nconst DEFAULT_MODEL = \"qwen2.5-coder:7b\";\nconst DEFAULT_TIMEOUT = 60000;\n\nexport class OllamaClient {\n private baseUrl: string;\n private model: string;\n private timeout: number;\n\n constructor(options: OllamaClientOptions = {}) {\n this.baseUrl = options.baseUrl || DEFAULT_BASE_URL;\n this.model = options.model || DEFAULT_MODEL;\n this.timeout = options.timeout || DEFAULT_TIMEOUT;\n }\n\n /**\n * Analyzes styles and returns issues\n */\n async analyzeStyles(\n styleSummary: string,\n styleGuide: string | null,\n onProgress?: StreamProgressCallback\n ): Promise<AnalysisResult> {\n const startTime = Date.now();\n const prompt = buildAnalysisPrompt(styleSummary, styleGuide);\n\n try {\n const response = onProgress\n ? await this.generateStreaming(prompt, true, onProgress)\n : await this.generate(prompt);\n const issues = this.parseIssuesResponse(response);\n\n return {\n issues,\n analysisTime: Date.now() - startTime,\n };\n } catch (error) {\n console.error(\"[UILint] Analysis failed:\", error);\n return {\n issues: [],\n analysisTime: Date.now() - startTime,\n };\n }\n }\n\n /**\n * Generates a style guide from detected styles\n */\n async generateStyleGuide(styleSummary: string): Promise<string | null> {\n const prompt = buildStyleGuidePrompt(styleSummary);\n\n try {\n const response = await this.generate(prompt, false);\n return response;\n } catch (error) {\n console.error(\"[UILint] Style guide generation failed:\", error);\n return null;\n }\n }\n\n /**\n * Queries the style guide for specific information\n */\n async queryStyleGuide(\n query: string,\n styleGuide: string | null\n ): Promise<string> {\n const prompt = buildQueryPrompt(query, styleGuide);\n\n try {\n const response = await this.generate(prompt, false);\n return response;\n } catch (error) {\n console.error(\"[UILint] Query failed:\", error);\n return \"Failed to query style guide. Please try again.\";\n }\n }\n\n /**\n * Core generate method that calls Ollama API\n */\n private async generate(\n prompt: string,\n jsonFormat: boolean = true\n ): Promise<string> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}/api/generate`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n prompt,\n stream: false,\n ...(jsonFormat && { format: \"json\" }),\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`Ollama API error: ${response.status}`);\n }\n\n const data = await response.json();\n return data.response || \"\";\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Streaming generate method that calls Ollama API with streaming\n * and reports progress via callback\n */\n private async generateStreaming(\n prompt: string,\n jsonFormat: boolean = true,\n onProgress: StreamProgressCallback\n ): Promise<string> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}/api/generate`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n prompt,\n stream: true,\n ...(jsonFormat && { format: \"json\" }),\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`Ollama API error: ${response.status}`);\n }\n\n if (!response.body) {\n throw new Error(\"No response body for streaming\");\n }\n\n const reader = response.body.getReader();\n const decoder = new TextDecoder();\n let fullResponse = \"\";\n let buffer = \"\";\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n\n // Process complete JSON lines from the buffer\n const lines = buffer.split(\"\\n\");\n buffer = lines.pop() || \"\"; // Keep incomplete line in buffer\n\n for (const line of lines) {\n if (!line.trim()) continue;\n try {\n const chunk = JSON.parse(line);\n if (chunk.response) {\n fullResponse += chunk.response;\n // Get the latest line from the response for progress display\n const responseLines = fullResponse.split(\"\\n\");\n const latestLine =\n responseLines[responseLines.length - 1] ||\n responseLines[responseLines.length - 2] ||\n \"\";\n onProgress(latestLine.trim(), fullResponse);\n }\n } catch {\n // Skip malformed JSON chunks\n }\n }\n }\n\n // Process any remaining content in buffer\n if (buffer.trim()) {\n try {\n const chunk = JSON.parse(buffer);\n if (chunk.response) {\n fullResponse += chunk.response;\n }\n } catch {\n // Skip malformed JSON\n }\n }\n\n return fullResponse;\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Parses issues from LLM response\n */\n private parseIssuesResponse(response: string): UILintIssue[] {\n try {\n const parsed = JSON.parse(response);\n return parsed.issues || [];\n } catch {\n console.warn(\"[UILint] Failed to parse LLM response as JSON\");\n return [];\n }\n }\n\n /**\n * Checks if Ollama is available\n */\n async isAvailable(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n method: \"GET\",\n signal: AbortSignal.timeout(5000),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * Gets the current model\n */\n getModel(): string {\n return this.model;\n }\n\n /**\n * Sets the model\n */\n setModel(model: string): void {\n this.model = model;\n }\n}\n\n// Default singleton instance\nlet defaultClient: OllamaClient | null = null;\n\nexport function getOllamaClient(options?: OllamaClientOptions): OllamaClient {\n if (!defaultClient || options) {\n defaultClient = new OllamaClient(options);\n }\n return defaultClient;\n}\n","/**\n * Tailwind / utility-class token extraction helpers.\n *\n * Notes:\n * - Works on HTML (class=\"...\") and TSX-ish input (className=\"...\") via regex.\n * - Variant parsing is bracket-aware so arbitrary values like bg-[color:var(--x)]\n * don't get split incorrectly on \":\".\n */\n\nexport interface ClassTokenCounts {\n /**\n * Base utilities with variants stripped.\n * Example: \"sm:hover:bg-gray-50\" => utility \"bg-gray-50\"\n */\n utilities: Map<string, number>;\n /**\n * Individual variant prefixes.\n * Example: \"sm:hover:bg-gray-50\" => variants \"sm\", \"hover\"\n */\n variants: Map<string, number>;\n}\n\nexport interface ExtractClassTokenOptions {\n /**\n * Maximum number of tokens to process (guardrail for very large inputs).\n */\n maxTokens?: number;\n}\n\nexport function extractClassTokensFromHtml(\n html: string,\n options: ExtractClassTokenOptions = {}\n): ClassTokenCounts {\n const { maxTokens = 20000 } = options;\n\n const utilities = new Map<string, number>();\n const variants = new Map<string, number>();\n\n if (!html) return { utilities, variants };\n\n // Match both HTML and JSX-ish attributes.\n // - class=\"...\"\n // - className=\"...\"\n const attrPattern = /\\b(?:class|className)\\s*=\\s*[\"']([^\"']+)[\"']/g;\n\n let tokenBudget = maxTokens;\n let match: RegExpExecArray | null;\n while ((match = attrPattern.exec(html)) && tokenBudget > 0) {\n const raw = match[1];\n if (!raw) continue;\n\n const tokens = raw.split(/\\s+/g).filter(Boolean);\n for (const token of tokens) {\n if (tokenBudget-- <= 0) break;\n\n const { base, variantList } = splitVariants(token);\n const normalizedBase = normalizeUtility(base);\n if (!normalizedBase) continue;\n\n increment(utilities, normalizedBase);\n for (const v of variantList) increment(variants, v);\n }\n }\n\n return { utilities, variants };\n}\n\nexport function topEntries(\n map: Map<string, number>,\n limit: number\n): Array<{ token: string; count: number }> {\n return [...map.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, limit)\n .map(([token, count]) => ({ token, count }));\n}\n\nfunction increment(map: Map<string, number>, key: string): void {\n map.set(key, (map.get(key) || 0) + 1);\n}\n\nfunction normalizeUtility(token: string): string | null {\n const t = token.trim();\n if (!t) return null;\n\n // Strip important modifier\n const noImportant = t.startsWith(\"!\") ? t.slice(1) : t;\n\n // Ignore obviously non-class tokens\n if (!noImportant || noImportant === \"{\" || noImportant === \"}\") return null;\n\n return noImportant;\n}\n\n/**\n * Splits a class token into variants and base utility.\n * Bracket-aware to avoid splitting arbitrary values on \":\".\n *\n * Examples:\n * - \"sm:hover:bg-gray-50\" => variants [\"sm\",\"hover\"], base \"bg-gray-50\"\n * - \"bg-[color:var(--x)]\" => variants [], base \"bg-[color:var(--x)]\"\n * - \"sm:bg-[color:var(--x)]\" => variants [\"sm\"], base \"bg-[color:var(--x)]\"\n */\nfunction splitVariants(token: string): { base: string; variantList: string[] } {\n const parts: string[] = [];\n let buf = \"\";\n let bracketDepth = 0;\n\n for (let i = 0; i < token.length; i++) {\n const ch = token[i];\n if (ch === \"[\") bracketDepth++;\n if (ch === \"]\" && bracketDepth > 0) bracketDepth--;\n\n if (ch === \":\" && bracketDepth === 0) {\n parts.push(buf);\n buf = \"\";\n continue;\n }\n\n buf += ch;\n }\n parts.push(buf);\n\n if (parts.length <= 1) return { base: token, variantList: [] };\n\n const base = parts[parts.length - 1] || \"\";\n const variantList = parts\n .slice(0, -1)\n .map((v) => v.trim())\n .filter(Boolean);\n\n return { base, variantList };\n}\n","/**\n * Style extraction from DOM elements\n */\n\nimport type {\n ExtractedStyles,\n SerializedStyles,\n TailwindThemeTokens,\n} from \"../types.js\";\nimport {\n extractClassTokensFromHtml,\n topEntries,\n} from \"../tailwind/class-tokens.js\";\n\n/**\n * Extracts all computed styles from elements in the document\n * Works in both browser and JSDOM environments\n */\nexport function extractStyles(\n root: Element | Document,\n getComputedStyle: (el: Element) => CSSStyleDeclaration\n): ExtractedStyles {\n const styles: ExtractedStyles = {\n colors: new Map(),\n fontSizes: new Map(),\n fontFamilies: new Map(),\n fontWeights: new Map(),\n spacing: new Map(),\n borderRadius: new Map(),\n };\n\n const elements = root.querySelectorAll(\"*\");\n\n elements.forEach((element) => {\n // nodeType === 1 means Element node (works in both browser and JSDOM)\n if (element.nodeType !== 1) return;\n\n const computed = getComputedStyle(element);\n\n // Extract colors\n extractColor(computed.color, styles.colors);\n extractColor(computed.backgroundColor, styles.colors);\n extractColor(computed.borderColor, styles.colors);\n\n // Extract typography\n incrementMap(styles.fontSizes, computed.fontSize);\n incrementMap(styles.fontFamilies, normalizeFontFamily(computed.fontFamily));\n incrementMap(styles.fontWeights, computed.fontWeight);\n\n // Extract spacing\n extractSpacing(computed.margin, styles.spacing);\n extractSpacing(computed.padding, styles.spacing);\n incrementMap(styles.spacing, computed.gap);\n\n // Extract border radius\n incrementMap(styles.borderRadius, computed.borderRadius);\n });\n\n return styles;\n}\n\n/**\n * Extracts styles from browser DOM (uses window.getComputedStyle)\n */\nexport function extractStylesFromDOM(\n root?: Element | Document\n): ExtractedStyles {\n const targetRoot = root || document.body;\n return extractStyles(targetRoot, (el) => window.getComputedStyle(el));\n}\n\nfunction extractColor(color: string, map: Map<string, number>): void {\n if (!color || color === \"transparent\" || color === \"rgba(0, 0, 0, 0)\") return;\n\n // Normalize to hex\n const hex = rgbToHex(color);\n if (hex) {\n incrementMap(map, hex);\n }\n}\n\nfunction extractSpacing(value: string, map: Map<string, number>): void {\n if (!value || value === \"0px\") return;\n\n // Split compound values (e.g., \"10px 20px 10px 20px\")\n const values = value.split(\" \").filter((v) => v && v !== \"0px\");\n values.forEach((v) => incrementMap(map, v));\n}\n\nfunction incrementMap(map: Map<string, number>, value: string): void {\n if (!value || value === \"normal\" || value === \"auto\") return;\n map.set(value, (map.get(value) || 0) + 1);\n}\n\nfunction normalizeFontFamily(fontFamily: string): string {\n // Get the primary font (first in the stack)\n const primary = fontFamily.split(\",\")[0].trim();\n return primary.replace(/['\"]/g, \"\");\n}\n\nfunction rgbToHex(rgb: string): string | null {\n // Handle hex values\n if (rgb.startsWith(\"#\")) return rgb.toUpperCase();\n\n // Handle rgb/rgba values\n const match = rgb.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (!match) return null;\n\n const [, r, g, b] = match;\n const toHex = (n: string) => parseInt(n).toString(16).padStart(2, \"0\");\n\n return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();\n}\n\n/**\n * Converts ExtractedStyles maps to plain objects for serialization\n */\nexport function serializeStyles(styles: ExtractedStyles): SerializedStyles {\n return {\n colors: Object.fromEntries(styles.colors),\n fontSizes: Object.fromEntries(styles.fontSizes),\n fontFamilies: Object.fromEntries(styles.fontFamilies),\n fontWeights: Object.fromEntries(styles.fontWeights),\n spacing: Object.fromEntries(styles.spacing),\n borderRadius: Object.fromEntries(styles.borderRadius),\n };\n}\n\n/**\n * Converts SerializedStyles back to ExtractedStyles\n */\nexport function deserializeStyles(\n serialized: SerializedStyles\n): ExtractedStyles {\n return {\n colors: new Map(Object.entries(serialized.colors)),\n fontSizes: new Map(Object.entries(serialized.fontSizes)),\n fontFamilies: new Map(Object.entries(serialized.fontFamilies)),\n fontWeights: new Map(Object.entries(serialized.fontWeights)),\n spacing: new Map(Object.entries(serialized.spacing)),\n borderRadius: new Map(Object.entries(serialized.borderRadius)),\n };\n}\n\n/**\n * Creates a summary of extracted styles for LLM analysis\n */\nexport function createStyleSummary(\n styles: ExtractedStyles,\n options: CreateStyleSummaryOptions = {}\n): string {\n return createStyleSummaryWithOptions(styles, options);\n}\n\nexport interface CreateStyleSummaryOptions {\n /**\n * Optional HTML/TSX-ish string used to extract utility classes (Tailwind etc).\n */\n html?: string;\n /**\n * Optional Tailwind theme tokens (typically from tailwind.config.*).\n */\n tailwindTheme?: TailwindThemeTokens | null;\n}\n\n/**\n * Creates a summary of extracted styles for LLM analysis.\n * Accepts optional Tailwind context to make Tailwind-heavy projects analyzable\n * even when computed styles are sparse (e.g., JSDOM without loaded CSS).\n */\nexport function createStyleSummaryWithOptions(\n styles: ExtractedStyles,\n options: CreateStyleSummaryOptions = {}\n): string {\n const lines: string[] = [];\n\n lines.push(\"## Detected Styles Summary\\n\");\n\n // Colors\n lines.push(\"### Colors\");\n const sortedColors = [...styles.colors.entries()].sort((a, b) => b[1] - a[1]);\n sortedColors.slice(0, 20).forEach(([color, count]) => {\n lines.push(`- ${color}: ${count} occurrences`);\n });\n lines.push(\"\");\n\n // Font sizes\n lines.push(\"### Font Sizes\");\n const sortedFontSizes = [...styles.fontSizes.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n sortedFontSizes.forEach(([size, count]) => {\n lines.push(`- ${size}: ${count} occurrences`);\n });\n lines.push(\"\");\n\n // Font families\n lines.push(\"### Font Families\");\n const sortedFontFamilies = [...styles.fontFamilies.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n sortedFontFamilies.forEach(([family, count]) => {\n lines.push(`- ${family}: ${count} occurrences`);\n });\n lines.push(\"\");\n\n // Font weights\n lines.push(\"### Font Weights\");\n const sortedFontWeights = [...styles.fontWeights.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n sortedFontWeights.forEach(([weight, count]) => {\n lines.push(`- ${weight}: ${count} occurrences`);\n });\n lines.push(\"\");\n\n // Spacing\n lines.push(\"### Spacing Values\");\n const sortedSpacing = [...styles.spacing.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n sortedSpacing.slice(0, 15).forEach(([value, count]) => {\n lines.push(`- ${value}: ${count} occurrences`);\n });\n lines.push(\"\");\n\n // Border radius\n lines.push(\"### Border Radius\");\n const sortedBorderRadius = [...styles.borderRadius.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n sortedBorderRadius.forEach(([value, count]) => {\n lines.push(`- ${value}: ${count} occurrences`);\n });\n\n // Tailwind / utility classes (optional)\n if (options.html) {\n const tokens = extractClassTokensFromHtml(options.html);\n const topUtilities = topEntries(tokens.utilities, 40);\n const topVariants = topEntries(tokens.variants, 15);\n\n lines.push(\"\");\n lines.push(\"### Utility Classes (from markup)\");\n if (topUtilities.length === 0) {\n lines.push(\"- (none detected)\");\n } else {\n topUtilities.forEach(({ token, count }) => {\n lines.push(`- ${token}: ${count} occurrences`);\n });\n }\n\n if (topVariants.length > 0) {\n lines.push(\"\");\n lines.push(\"### Common Variants\");\n topVariants.forEach(({ token, count }) => {\n lines.push(`- ${token}: ${count} occurrences`);\n });\n }\n }\n\n // Tailwind theme tokens (optional)\n if (options.tailwindTheme) {\n const tt = options.tailwindTheme;\n lines.push(\"\");\n lines.push(\"### Tailwind Theme Tokens (from config)\");\n lines.push(`- configPath: ${tt.configPath}`);\n lines.push(`- colors: ${tt.colors.length}`);\n lines.push(`- spacingKeys: ${tt.spacingKeys.length}`);\n lines.push(`- borderRadiusKeys: ${tt.borderRadiusKeys.length}`);\n lines.push(`- fontFamilyKeys: ${tt.fontFamilyKeys.length}`);\n lines.push(`- fontSizeKeys: ${tt.fontSizeKeys.length}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Truncates HTML to a maximum length\n */\nexport function truncateHTML(html: string, maxLength: number = 50000): string {\n if (html.length <= maxLength) return html;\n return html.slice(0, maxLength) + \"<!-- truncated -->\";\n}\n","/**\n * Style guide schema and utilities\n */\n\nimport type { StyleGuide, ColorRule, TypographyRule, SpacingRule, ComponentRule } from \"../types.js\";\n\n/**\n * Creates an empty style guide structure\n */\nexport function createEmptyStyleGuide(): StyleGuide {\n return {\n colors: [],\n typography: [],\n spacing: [],\n components: [],\n };\n}\n\n/**\n * Validates a style guide object\n */\nexport function validateStyleGuide(guide: unknown): guide is StyleGuide {\n if (!guide || typeof guide !== \"object\") return false;\n\n const g = guide as Record<string, unknown>;\n\n return (\n Array.isArray(g.colors) &&\n Array.isArray(g.typography) &&\n Array.isArray(g.spacing) &&\n Array.isArray(g.components)\n );\n}\n\n/**\n * Merges detected styles into an existing style guide\n */\nexport function mergeStyleGuides(\n existing: StyleGuide,\n detected: Partial<StyleGuide>\n): StyleGuide {\n return {\n colors: mergeColorRules(existing.colors, detected.colors || []),\n typography: mergeTypographyRules(existing.typography, detected.typography || []),\n spacing: mergeSpacingRules(existing.spacing, detected.spacing || []),\n components: mergeComponentRules(existing.components, detected.components || []),\n };\n}\n\nfunction mergeColorRules(existing: ColorRule[], detected: ColorRule[]): ColorRule[] {\n const merged = [...existing];\n detected.forEach((rule) => {\n const existingIndex = merged.findIndex(\n (e) => e.name === rule.name || e.value === rule.value\n );\n if (existingIndex === -1) {\n merged.push(rule);\n }\n });\n return merged;\n}\n\nfunction mergeTypographyRules(existing: TypographyRule[], detected: TypographyRule[]): TypographyRule[] {\n const merged = [...existing];\n detected.forEach((rule) => {\n const existingIndex = merged.findIndex((e) => e.element === rule.element);\n if (existingIndex === -1) {\n merged.push(rule);\n }\n });\n return merged;\n}\n\nfunction mergeSpacingRules(existing: SpacingRule[], detected: SpacingRule[]): SpacingRule[] {\n const merged = [...existing];\n detected.forEach((rule) => {\n const existingIndex = merged.findIndex(\n (e) => e.name === rule.name || e.value === rule.value\n );\n if (existingIndex === -1) {\n merged.push(rule);\n }\n });\n return merged;\n}\n\nfunction mergeComponentRules(existing: ComponentRule[], detected: ComponentRule[]): ComponentRule[] {\n const merged = [...existing];\n detected.forEach((rule) => {\n const existingIndex = merged.findIndex((e) => e.name === rule.name);\n if (existingIndex === -1) {\n merged.push(rule);\n }\n });\n return merged;\n}\n\n/**\n * Creates a color rule\n */\nexport function createColorRule(\n name: string,\n value: string,\n usage: string = \"\"\n): ColorRule {\n return { name, value: value.toUpperCase(), usage };\n}\n\n/**\n * Creates a typography rule\n */\nexport function createTypographyRule(\n element: string,\n options: Partial<Omit<TypographyRule, \"element\">> = {}\n): TypographyRule {\n return { element, ...options };\n}\n\n/**\n * Creates a spacing rule\n */\nexport function createSpacingRule(name: string, value: string): SpacingRule {\n return { name, value };\n}\n\n/**\n * Creates a component rule\n */\nexport function createComponentRule(name: string, styles: string[]): ComponentRule {\n return { name, styles };\n}\n\n","/**\n * Parse Markdown style guides into structured data\n */\n\nimport type {\n StyleGuide,\n ColorRule,\n TypographyRule,\n SpacingRule,\n ComponentRule,\n ExtractedStyleValues,\n} from \"../types.js\";\nimport { createEmptyStyleGuide } from \"./schema.js\";\n\n/**\n * Parses a Markdown style guide into a structured object\n */\nexport function parseStyleGuide(markdown: string): StyleGuide {\n const guide = createEmptyStyleGuide();\n const sections = splitIntoSections(markdown);\n\n sections.forEach(({ title, content }) => {\n const lowerTitle = title.toLowerCase();\n\n if (lowerTitle.includes(\"color\")) {\n guide.colors = parseColorSection(content);\n } else if (\n lowerTitle.includes(\"typography\") ||\n lowerTitle.includes(\"font\")\n ) {\n guide.typography = parseTypographySection(content);\n } else if (lowerTitle.includes(\"spacing\")) {\n guide.spacing = parseSpacingSection(content);\n } else if (lowerTitle.includes(\"component\")) {\n guide.components = parseComponentSection(content);\n }\n });\n\n return guide;\n}\n\ninterface Section {\n title: string;\n content: string;\n}\n\nfunction splitIntoSections(markdown: string): Section[] {\n const sections: Section[] = [];\n const lines = markdown.split(\"\\n\");\n\n let currentTitle = \"\";\n let currentContent: string[] = [];\n\n lines.forEach((line) => {\n const headerMatch = line.match(/^##\\s+(.+)$/);\n\n if (headerMatch) {\n if (currentTitle) {\n sections.push({\n title: currentTitle,\n content: currentContent.join(\"\\n\"),\n });\n }\n currentTitle = headerMatch[1];\n currentContent = [];\n } else {\n currentContent.push(line);\n }\n });\n\n if (currentTitle) {\n sections.push({\n title: currentTitle,\n content: currentContent.join(\"\\n\"),\n });\n }\n\n return sections;\n}\n\nfunction parseColorSection(content: string): ColorRule[] {\n const colors: ColorRule[] = [];\n const lines = content.split(\"\\n\");\n\n lines.forEach((line) => {\n // Match patterns like: - **Primary**: #3B82F6 (used in buttons)\n const match = line.match(\n /[-*]\\s*\\*?\\*?([^*:]+)\\*?\\*?:\\s*(#[A-Fa-f0-9]{6})\\s*(?:\\(([^)]+)\\))?/\n );\n\n if (match) {\n colors.push({\n name: match[1].trim(),\n value: match[2].toUpperCase(),\n usage: match[3] || \"\",\n });\n }\n });\n\n return colors;\n}\n\nfunction parseTypographySection(content: string): TypographyRule[] {\n const typography: TypographyRule[] = [];\n const lines = content.split(\"\\n\");\n\n lines.forEach((line) => {\n // Match patterns like: - **Headings**: font-family: \"Inter\", font-size: 24px\n const elementMatch = line.match(/[-*]\\s*\\*?\\*?([^*:]+)\\*?\\*?:\\s*(.+)/);\n\n if (elementMatch) {\n const rule: TypographyRule = {\n element: elementMatch[1].trim(),\n };\n\n const props = elementMatch[2];\n\n const fontFamilyMatch = props.match(/font-family:\\s*\"?([^\",]+)\"?/);\n if (fontFamilyMatch) rule.fontFamily = fontFamilyMatch[1].trim();\n\n const fontSizeMatch = props.match(/font-size:\\s*(\\d+px)/);\n if (fontSizeMatch) rule.fontSize = fontSizeMatch[1];\n\n const fontWeightMatch = props.match(/font-weight:\\s*(\\d+)/);\n if (fontWeightMatch) rule.fontWeight = fontWeightMatch[1];\n\n const lineHeightMatch = props.match(/line-height:\\s*([\\d.]+)/);\n if (lineHeightMatch) rule.lineHeight = lineHeightMatch[1];\n\n typography.push(rule);\n }\n });\n\n return typography;\n}\n\nfunction parseSpacingSection(content: string): SpacingRule[] {\n const spacing: SpacingRule[] = [];\n const lines = content.split(\"\\n\");\n\n lines.forEach((line) => {\n // Match patterns like: - **Base unit**: 4px\n const match = line.match(/[-*]\\s*\\*?\\*?([^*:]+)\\*?\\*?:\\s*(.+)/);\n\n if (match) {\n spacing.push({\n name: match[1].trim(),\n value: match[2].trim(),\n });\n }\n });\n\n return spacing;\n}\n\nfunction parseComponentSection(content: string): ComponentRule[] {\n const components: ComponentRule[] = [];\n const lines = content.split(\"\\n\");\n\n lines.forEach((line) => {\n // Match patterns like: - **Buttons**: rounded-lg, px-4 py-2\n const match = line.match(/[-*]\\s*\\*?\\*?([^*:]+)\\*?\\*?:\\s*(.+)/);\n\n if (match) {\n components.push({\n name: match[1].trim(),\n styles: match[2].split(\",\").map((s) => s.trim()),\n });\n }\n });\n\n return components;\n}\n\n/**\n * Parses sections from a Markdown style guide (simpler format)\n */\nexport function parseStyleGuideSections(\n content: string\n): Record<string, string> {\n const sections: Record<string, string> = {};\n const lines = content.split(\"\\n\");\n\n let currentSection = \"intro\";\n let currentContent: string[] = [];\n\n for (const line of lines) {\n const headerMatch = line.match(/^##\\s+(.+)$/);\n\n if (headerMatch) {\n if (currentContent.length > 0) {\n sections[currentSection.toLowerCase()] = currentContent\n .join(\"\\n\")\n .trim();\n }\n\n currentSection = headerMatch[1];\n currentContent = [];\n } else {\n currentContent.push(line);\n }\n }\n\n if (currentContent.length > 0) {\n sections[currentSection.toLowerCase()] = currentContent.join(\"\\n\").trim();\n }\n\n return sections;\n}\n\n/**\n * Extracts specific values from the style guide\n */\nexport function extractStyleValues(content: string): ExtractedStyleValues {\n const result: ExtractedStyleValues = {\n colors: [],\n fontSizes: [],\n fontFamilies: [],\n spacing: [],\n borderRadius: [],\n };\n\n // Extract hex colors\n const colorMatches = content.matchAll(/#[A-Fa-f0-9]{6}\\b/g);\n for (const match of colorMatches) {\n if (!result.colors.includes(match[0].toUpperCase())) {\n result.colors.push(match[0].toUpperCase());\n }\n }\n\n // Extract font sizes (e.g., 16px, 1.5rem)\n const fontSizeMatches = content.matchAll(/\\b(\\d+(?:\\.\\d+)?(?:px|rem|em))\\b/g);\n for (const match of fontSizeMatches) {\n if (!result.fontSizes.includes(match[1])) {\n result.fontSizes.push(match[1]);\n }\n }\n\n // Extract font families (quoted strings in font context)\n const fontFamilyMatches = content.matchAll(\n /font-family:\\s*[\"']?([^\"',\\n]+)/gi\n );\n for (const match of fontFamilyMatches) {\n const family = match[1].trim();\n if (!result.fontFamilies.includes(family)) {\n result.fontFamilies.push(family);\n }\n }\n\n return result;\n}\n\nexport interface TailwindAllowlist {\n allowAnyColor: boolean;\n allowStandardSpacing: boolean;\n allowedTailwindColors: Set<string>;\n allowedUtilities: Set<string>;\n allowedSpacingKeys: Set<string>;\n allowedBorderRadiusKeys: Set<string>;\n allowedFontSizeKeys: Set<string>;\n allowedFontFamilyKeys: Set<string>;\n}\n\n/**\n * Extract Tailwind / utility-class allowlist configuration from a style guide.\n *\n * Expected formats:\n * - A JSON code block inside a \"## Tailwind\" section (preferred; produced by UILint)\n * - Fallback: inline backticked utilities within the Tailwind section\n */\nexport function extractTailwindAllowlist(content: string): TailwindAllowlist {\n const empty: TailwindAllowlist = {\n allowAnyColor: false,\n allowStandardSpacing: false,\n allowedTailwindColors: new Set(),\n allowedUtilities: new Set(),\n allowedSpacingKeys: new Set(),\n allowedBorderRadiusKeys: new Set(),\n allowedFontSizeKeys: new Set(),\n allowedFontFamilyKeys: new Set(),\n };\n\n // Only look for allowlist details in the Tailwind section.\n const sections = parseStyleGuideSections(content);\n const tailwindSection =\n sections[\"tailwind\"] ??\n // defensive: some styleguides use different casing/spacing\n sections[\"tailwind utilities\"] ??\n \"\";\n\n if (!tailwindSection) return empty;\n\n const parsed = tryParseFirstJsonCodeBlock(tailwindSection);\n if (parsed && typeof parsed === \"object\") {\n const allowAnyColor = Boolean((parsed as any).allowAnyColor);\n const allowStandardSpacing = Boolean((parsed as any).allowStandardSpacing);\n\n const allowedUtilitiesArr = Array.isArray((parsed as any).allowedUtilities)\n ? ((parsed as any).allowedUtilities as unknown[]).filter(\n (u): u is string => typeof u === \"string\"\n )\n : [];\n\n const themeTokens = (parsed as any).themeTokens ?? {};\n const themeColors = Array.isArray(themeTokens.colors)\n ? (themeTokens.colors as unknown[]).filter(\n (c): c is string => typeof c === \"string\"\n )\n : [];\n const spacingKeys = Array.isArray(themeTokens.spacingKeys)\n ? (themeTokens.spacingKeys as unknown[]).filter(\n (k): k is string => typeof k === \"string\"\n )\n : [];\n const borderRadiusKeys = Array.isArray(themeTokens.borderRadiusKeys)\n ? (themeTokens.borderRadiusKeys as unknown[]).filter(\n (k): k is string => typeof k === \"string\"\n )\n : [];\n const fontFamilyKeys = Array.isArray(themeTokens.fontFamilyKeys)\n ? (themeTokens.fontFamilyKeys as unknown[]).filter(\n (k): k is string => typeof k === \"string\"\n )\n : [];\n const fontSizeKeys = Array.isArray(themeTokens.fontSizeKeys)\n ? (themeTokens.fontSizeKeys as unknown[]).filter(\n (k): k is string => typeof k === \"string\"\n )\n : [];\n\n const allowedTailwindColors = new Set<string>();\n for (const c of themeColors) {\n const raw = c.trim();\n if (!raw) continue;\n if (raw.toLowerCase().startsWith(\"tailwind:\")) {\n allowedTailwindColors.add(raw.toLowerCase());\n continue;\n }\n const m = raw.match(/^([a-zA-Z]+)-(\\d{2,3})$/);\n if (m) {\n allowedTailwindColors.add(`tailwind:${m[1].toLowerCase()}-${m[2]}`);\n }\n }\n\n return {\n allowAnyColor,\n allowStandardSpacing,\n allowedTailwindColors,\n allowedUtilities: new Set(\n allowedUtilitiesArr.map((s) => s.trim()).filter(Boolean)\n ),\n allowedSpacingKeys: new Set(\n spacingKeys.map((s) => s.trim()).filter(Boolean)\n ),\n allowedBorderRadiusKeys: new Set(\n borderRadiusKeys.map((s) => s.trim()).filter(Boolean)\n ),\n allowedFontSizeKeys: new Set(\n fontSizeKeys.map((s) => s.trim()).filter(Boolean)\n ),\n allowedFontFamilyKeys: new Set(\n fontFamilyKeys.map((s) => s.trim()).filter(Boolean)\n ),\n };\n }\n\n // Fallback: harvest backticked utilities from markdown.\n const backticked: string[] = [];\n for (const m of tailwindSection.matchAll(/`([^`]+)`/g)) {\n backticked.push(m[1]);\n }\n\n return {\n ...empty,\n allowedUtilities: new Set(\n backticked\n .flatMap((s) => s.split(/[,\\s]+/g))\n .map((s) => s.trim())\n .filter(Boolean)\n ),\n };\n}\n\nfunction tryParseFirstJsonCodeBlock(section: string): unknown | null {\n // Prefer ```json fenced blocks, but fall back to any fenced block.\n const jsonBlocks = [...section.matchAll(/```json\\s*([\\s\\S]*?)```/gi)];\n const anyBlocks = [...section.matchAll(/```\\s*([\\s\\S]*?)```/g)];\n\n const candidates = (jsonBlocks.length ? jsonBlocks : anyBlocks).map(\n (m) => m[1]\n );\n for (const raw of candidates) {\n const trimmed = raw.trim();\n if (!trimmed) continue;\n try {\n return JSON.parse(trimmed);\n } catch {\n continue;\n }\n }\n return null;\n}\n","/**\n * Generate Markdown style guides from extracted styles\n */\n\nimport type {\n ExtractedStyles,\n StyleGuide,\n TailwindThemeTokens,\n} from \"../types.js\";\nimport {\n extractClassTokensFromHtml,\n topEntries,\n} from \"../tailwind/class-tokens.js\";\n\n/**\n * Generates a Markdown style guide from extracted styles\n */\nexport interface GenerateStyleGuideOptions {\n /**\n * Optional HTML/TSX-ish string used to extract utility classes (Tailwind etc).\n */\n html?: string;\n /**\n * Optional Tailwind theme tokens (typically from tailwind.config.*).\n */\n tailwindTheme?: TailwindThemeTokens | null;\n}\n\nexport function generateStyleGuideFromStyles(\n styles: ExtractedStyles,\n options: GenerateStyleGuideOptions = {}\n): string {\n const lines: string[] = [];\n\n lines.push(\"# UI Style Guide\");\n lines.push(\"\");\n lines.push(\n \"> Auto-generated by UILint. Edit this file to define your design system.\"\n );\n lines.push(\"\");\n\n // Merge in any literal hex colors found in the input markup/code.\n // This is important when the input is TSX/JSX or Tailwind-heavy, where\n // computed styles (JSDOM) may be sparse or unavailable.\n const html = options.html || \"\";\n const mergedColors = new Map(styles.colors);\n if (html) {\n for (const m of html.matchAll(/#[A-Fa-f0-9]{6}\\b/g)) {\n const hex = (m[0] || \"\").toUpperCase();\n if (!hex) continue;\n mergedColors.set(hex, (mergedColors.get(hex) || 0) + 1);\n }\n }\n\n // Colors section\n lines.push(\"## Colors\");\n lines.push(\"\");\n const sortedColors = [...mergedColors.entries()].sort((a, b) => b[1] - a[1]);\n\n if (sortedColors.length > 0) {\n const colorNames = [\n \"Primary\",\n \"Secondary\",\n \"Accent\",\n \"Background\",\n \"Text\",\n \"Muted\",\n \"Border\",\n \"Success\",\n \"Warning\",\n \"Error\",\n ];\n sortedColors.forEach(([color, count], index) => {\n const name = colorNames[index] || `Color ${index + 1}`;\n lines.push(`- **${name}**: ${color} (${count} occurrences)`);\n });\n } else {\n lines.push(\"- No colors detected\");\n }\n lines.push(\"\");\n\n // Typography section\n lines.push(\"## Typography\");\n lines.push(\"\");\n\n // Font families\n const sortedFontFamilies = [...styles.fontFamilies.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n\n if (sortedFontFamilies.length > 0) {\n lines.push(`- **Font Family**: ${sortedFontFamilies[0][0]}`);\n }\n\n // Font sizes\n const sortedFontSizes = [...styles.fontSizes.entries()].sort(\n (a, b) => parseFloat(a[0]) - parseFloat(b[0])\n );\n\n if (sortedFontSizes.length > 0) {\n const sizes = sortedFontSizes.map(([size]) => size).join(\", \");\n lines.push(`- **Font Sizes**: ${sizes}`);\n }\n\n // Font weights\n const sortedFontWeights = [...styles.fontWeights.entries()].sort(\n (a, b) => parseInt(a[0]) - parseInt(b[0])\n );\n\n if (sortedFontWeights.length > 0) {\n const weights = sortedFontWeights.map(([weight]) => weight).join(\", \");\n lines.push(`- **Font Weights**: ${weights}`);\n }\n lines.push(\"\");\n\n // Spacing section\n lines.push(\"## Spacing\");\n lines.push(\"\");\n\n const sortedSpacing = [...styles.spacing.entries()]\n .filter(([value]) => value.endsWith(\"px\"))\n .sort((a, b) => parseFloat(a[0]) - parseFloat(b[0]));\n\n if (sortedSpacing.length > 0) {\n // Try to detect base unit\n const spacingValues = sortedSpacing.map(([value]) => parseFloat(value));\n const gcd = findGCD(spacingValues.filter((v) => v > 0));\n\n if (gcd >= 4) {\n lines.push(`- **Base unit**: ${gcd}px`);\n }\n\n const uniqueSpacing = [...new Set(sortedSpacing.map(([v]) => v))].slice(\n 0,\n 8\n );\n lines.push(`- **Common values**: ${uniqueSpacing.join(\", \")}`);\n } else {\n lines.push(\"- No spacing values detected\");\n }\n lines.push(\"\");\n\n // Border radius section\n lines.push(\"## Border Radius\");\n lines.push(\"\");\n\n const sortedBorderRadius = [...styles.borderRadius.entries()]\n .filter(([value]) => value !== \"0px\")\n .sort((a, b) => b[1] - a[1]);\n\n if (sortedBorderRadius.length > 0) {\n sortedBorderRadius.slice(0, 5).forEach(([value, count]) => {\n lines.push(`- ${value} (${count} occurrences)`);\n });\n } else {\n lines.push(\"- No border radius values detected\");\n }\n lines.push(\"\");\n\n // Components section (placeholder)\n lines.push(\"## Components\");\n lines.push(\"\");\n lines.push(\"- **Buttons**: Define button styles here\");\n lines.push(\"- **Cards**: Define card styles here\");\n lines.push(\"- **Inputs**: Define input styles here\");\n lines.push(\"\");\n\n // Tailwind / utility classes (optional)\n const classTokens = html ? extractClassTokensFromHtml(html) : null;\n const topUtilities = classTokens ? topEntries(classTokens.utilities, 50) : [];\n const topVariants = classTokens ? topEntries(classTokens.variants, 20) : [];\n const allUtilities = classTokens\n ? [...classTokens.utilities.entries()]\n .sort((a, b) => (b[1] - a[1] ? b[1] - a[1] : a[0].localeCompare(b[0])))\n .map(([token]) => token)\n : [];\n\n const theme = options.tailwindTheme;\n const themeColors = theme?.colors || [];\n const themeSpacingKeys = theme?.spacingKeys || [];\n const themeBorderRadiusKeys = theme?.borderRadiusKeys || [];\n const themeFontFamilyKeys = theme?.fontFamilyKeys || [];\n const themeFontSizeKeys = theme?.fontSizeKeys || [];\n\n const hasTailwindSection =\n topUtilities.length > 0 ||\n themeColors.length > 0 ||\n themeSpacingKeys.length > 0 ||\n themeBorderRadiusKeys.length > 0 ||\n themeFontFamilyKeys.length > 0 ||\n themeFontSizeKeys.length > 0;\n\n if (hasTailwindSection) {\n lines.push(\"## Tailwind\");\n lines.push(\"\");\n lines.push(\n \"> Optional. Captures Tailwind/utility class conventions for validation and consistency.\"\n );\n lines.push(\"\");\n\n if (topUtilities.length > 0) {\n const utilityList = topUtilities\n .slice(0, 25)\n .map((u) => `\\`${u.token}\\``)\n .join(\", \");\n lines.push(`- **Observed utilities (top)**: ${utilityList}`);\n } else {\n lines.push(\"- **Observed utilities (top)**: (none detected)\");\n }\n\n if (topVariants.length > 0) {\n const variantList = topVariants\n .slice(0, 12)\n .map((v) => `\\`${v.token}\\``)\n .join(\", \");\n lines.push(`- **Common variants**: ${variantList}`);\n }\n\n if (theme) {\n lines.push(`- **Config path**: \\`${theme.configPath}\\``);\n if (themeColors.length > 0) {\n lines.push(\n `- **Theme colors (tokens)**: ${themeColors\n .slice(0, 25)\n .map((t) => `\\`${t}\\``)\n .join(\", \")}${themeColors.length > 25 ? \", ...\" : \"\"}`\n );\n } else {\n lines.push(\"- **Theme colors (tokens)**: (none specified in config)\");\n }\n\n if (themeSpacingKeys.length > 0) {\n lines.push(\n `- **Theme spacing keys**: ${themeSpacingKeys\n .slice(0, 25)\n .map((k) => `\\`${k}\\``)\n .join(\", \")}${themeSpacingKeys.length > 25 ? \", ...\" : \"\"}`\n );\n }\n }\n\n // Machine-readable payload to make parsing/validation robust.\n const payload = {\n // IMPORTANT: include all observed utilities (not just \"top N\"), otherwise\n // init+validate on the same file can be inconsistent.\n allowedUtilities: allUtilities,\n allowAnyColor: !!theme && themeColors.length === 0, // avoid noisy warnings when config doesn't define colors\n allowStandardSpacing: !!theme && themeSpacingKeys.length === 0,\n themeTokens: theme\n ? {\n configPath: theme.configPath,\n colors: themeColors,\n spacingKeys: themeSpacingKeys,\n borderRadiusKeys: themeBorderRadiusKeys,\n fontFamilyKeys: themeFontFamilyKeys,\n fontSizeKeys: themeFontSizeKeys,\n }\n : null,\n };\n\n lines.push(\"\");\n lines.push(\"```json\");\n lines.push(JSON.stringify(payload, null, 2));\n lines.push(\"```\");\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Finds the greatest common divisor of an array of numbers\n */\nfunction findGCD(numbers: number[]): number {\n if (numbers.length === 0) return 0;\n if (numbers.length === 1) return numbers[0];\n\n const gcd = (a: number, b: number): number => {\n a = Math.abs(Math.round(a));\n b = Math.abs(Math.round(b));\n while (b) {\n const t = b;\n b = a % b;\n a = t;\n }\n return a;\n };\n\n return numbers.reduce((acc, n) => gcd(acc, n));\n}\n\n/**\n * Converts a StyleGuide object back to Markdown\n */\nexport function styleGuideToMarkdown(guide: StyleGuide): string {\n const lines: string[] = [];\n\n lines.push(\"# UI Style Guide\");\n lines.push(\"\");\n\n // Colors\n lines.push(\"## Colors\");\n guide.colors.forEach((color) => {\n const usage = color.usage ? ` (${color.usage})` : \"\";\n lines.push(`- **${color.name}**: ${color.value}${usage}`);\n });\n lines.push(\"\");\n\n // Typography\n lines.push(\"## Typography\");\n guide.typography.forEach((typo) => {\n const props: string[] = [];\n if (typo.fontFamily) props.push(`font-family: \"${typo.fontFamily}\"`);\n if (typo.fontSize) props.push(`font-size: ${typo.fontSize}`);\n if (typo.fontWeight) props.push(`font-weight: ${typo.fontWeight}`);\n if (typo.lineHeight) props.push(`line-height: ${typo.lineHeight}`);\n lines.push(`- **${typo.element}**: ${props.join(\", \")}`);\n });\n lines.push(\"\");\n\n // Spacing\n lines.push(\"## Spacing\");\n guide.spacing.forEach((space) => {\n lines.push(`- **${space.name}**: ${space.value}`);\n });\n lines.push(\"\");\n\n // Components\n lines.push(\"## Components\");\n guide.components.forEach((comp) => {\n lines.push(`- **${comp.name}**: ${comp.styles.join(\", \")}`);\n });\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}
package/dist/index.d.ts CHANGED
@@ -69,6 +69,7 @@ interface OllamaClientOptions {
69
69
  model?: string;
70
70
  timeout?: number;
71
71
  }
72
+ type StreamProgressCallback = (latestLine: string, fullResponse: string) => void;
72
73
  interface ExtractedStyleValues {
73
74
  colors: string[];
74
75
  fontSizes: string[];
@@ -97,7 +98,7 @@ declare class OllamaClient {
97
98
  /**
98
99
  * Analyzes styles and returns issues
99
100
  */
100
- analyzeStyles(styleSummary: string, styleGuide: string | null): Promise<AnalysisResult>;
101
+ analyzeStyles(styleSummary: string, styleGuide: string | null, onProgress?: StreamProgressCallback): Promise<AnalysisResult>;
101
102
  /**
102
103
  * Generates a style guide from detected styles
103
104
  */
@@ -110,6 +111,11 @@ declare class OllamaClient {
110
111
  * Core generate method that calls Ollama API
111
112
  */
112
113
  private generate;
114
+ /**
115
+ * Streaming generate method that calls Ollama API with streaming
116
+ * and reports progress via callback
117
+ */
118
+ private generateStreaming;
113
119
  /**
114
120
  * Parses issues from LLM response
115
121
  */
@@ -276,4 +282,4 @@ declare function createSpacingRule(name: string, value: string): SpacingRule;
276
282
  */
277
283
  declare function createComponentRule(name: string, styles: string[]): ComponentRule;
278
284
 
279
- export { type AnalysisResult, type ColorRule, type ComponentRule, type DOMSnapshot, type ExtractedStyleValues, type ExtractedStyles, OllamaClient, type OllamaClientOptions, type SerializedStyles, type SpacingRule, type StyleGuide, type TailwindThemeTokens, type TypographyRule, type UILintIssue, buildAnalysisPrompt, buildQueryPrompt, buildStyleGuidePrompt, createColorRule, createComponentRule, createEmptyStyleGuide, createSpacingRule, createStyleSummary, createTypographyRule, deserializeStyles, extractStyleValues, extractStyles, extractStylesFromDOM, extractTailwindAllowlist, generateStyleGuideFromStyles, getOllamaClient, mergeStyleGuides, parseStyleGuide, parseStyleGuideSections, serializeStyles, styleGuideToMarkdown, truncateHTML, validateStyleGuide };
285
+ export { type AnalysisResult, type ColorRule, type ComponentRule, type DOMSnapshot, type ExtractedStyleValues, type ExtractedStyles, OllamaClient, type OllamaClientOptions, type SerializedStyles, type SpacingRule, type StreamProgressCallback, type StyleGuide, type TailwindThemeTokens, type TypographyRule, type UILintIssue, buildAnalysisPrompt, buildQueryPrompt, buildStyleGuidePrompt, createColorRule, createComponentRule, createEmptyStyleGuide, createSpacingRule, createStyleSummary, createTypographyRule, deserializeStyles, extractStyleValues, extractStyles, extractStylesFromDOM, extractTailwindAllowlist, generateStyleGuideFromStyles, getOllamaClient, mergeStyleGuides, parseStyleGuide, parseStyleGuideSections, serializeStyles, styleGuideToMarkdown, truncateHTML, validateStyleGuide };
package/dist/index.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  styleGuideToMarkdown,
24
24
  truncateHTML,
25
25
  validateStyleGuide
26
- } from "./chunk-P2QQGDQS.js";
26
+ } from "./chunk-5VPZOH2K.js";
27
27
  export {
28
28
  OllamaClient,
29
29
  buildAnalysisPrompt,
package/dist/node.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { DOMSnapshot, TailwindThemeTokens } from './index.js';
2
- export { AnalysisResult, ColorRule, ComponentRule, ExtractedStyleValues, ExtractedStyles, OllamaClient, OllamaClientOptions, SerializedStyles, SpacingRule, StyleGuide, TypographyRule, UILintIssue, buildAnalysisPrompt, buildQueryPrompt, buildStyleGuidePrompt, createColorRule, createComponentRule, createEmptyStyleGuide, createSpacingRule, createStyleSummary, createTypographyRule, deserializeStyles, extractStyleValues, extractStyles, extractStylesFromDOM, extractTailwindAllowlist, generateStyleGuideFromStyles, getOllamaClient, mergeStyleGuides, parseStyleGuide, parseStyleGuideSections, serializeStyles, styleGuideToMarkdown, truncateHTML, validateStyleGuide } from './index.js';
2
+ export { AnalysisResult, ColorRule, ComponentRule, ExtractedStyleValues, ExtractedStyles, OllamaClient, OllamaClientOptions, SerializedStyles, SpacingRule, StreamProgressCallback, StyleGuide, TypographyRule, UILintIssue, buildAnalysisPrompt, buildQueryPrompt, buildStyleGuidePrompt, createColorRule, createComponentRule, createEmptyStyleGuide, createSpacingRule, createStyleSummary, createTypographyRule, deserializeStyles, extractStyleValues, extractStyles, extractStylesFromDOM, extractTailwindAllowlist, generateStyleGuideFromStyles, getOllamaClient, mergeStyleGuides, parseStyleGuide, parseStyleGuideSections, serializeStyles, styleGuideToMarkdown, truncateHTML, validateStyleGuide } from './index.js';
3
3
 
4
4
  /**
5
5
  * Ollama bootstrapping utilities (Node.js only).
package/dist/node.js CHANGED
@@ -23,7 +23,7 @@ import {
23
23
  styleGuideToMarkdown,
24
24
  truncateHTML,
25
25
  validateStyleGuide
26
- } from "./chunk-P2QQGDQS.js";
26
+ } from "./chunk-5VPZOH2K.js";
27
27
 
28
28
  // src/ollama/bootstrap.ts
29
29
  import { spawn, spawnSync } from "child_process";
package/package.json CHANGED
@@ -1,7 +1,17 @@
1
1
  {
2
2
  "name": "uilint-core",
3
- "version": "0.1.5",
3
+ "version": "0.1.7",
4
4
  "description": "Core library for UILint - AI-powered UI consistency checking",
5
+ "author": "Peter Suggate",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/peter-suggate/uilint.git",
9
+ "directory": "packages/uilint-core"
10
+ },
11
+ "homepage": "https://github.com/peter-suggate/uilint#readme",
12
+ "bugs": {
13
+ "url": "https://github.com/peter-suggate/uilint/issues"
14
+ },
5
15
  "type": "module",
6
16
  "main": "./dist/index.js",
7
17
  "module": "./dist/index.js",
@@ -27,7 +37,8 @@
27
37
  }
28
38
  },
29
39
  "files": [
30
- "dist"
40
+ "dist",
41
+ "README.md"
31
42
  ],
32
43
  "engines": {
33
44
  "node": ">=20.0.0"
@@ -1 +0,0 @@
1
- {"version":3,"sources":["../src/ollama/prompts.ts","../src/ollama/client.ts","../src/tailwind/class-tokens.ts","../src/scanner/style-extractor.ts","../src/styleguide/schema.ts","../src/styleguide/parser.ts","../src/styleguide/generator.ts"],"sourcesContent":["/**\n * LLM prompt builders for UILint analysis\n */\n\n/**\n * Builds a prompt for style analysis\n */\nexport function buildAnalysisPrompt(\n styleSummary: string,\n styleGuide: string | null\n): string {\n const guideSection = styleGuide\n ? `## Current Style Guide\\n${styleGuide}\\n\\n`\n : \"## No Style Guide Found\\nAnalyze the styles and identify inconsistencies.\\n\\n\";\n\n return `You are a UI consistency analyzer. Analyze the following extracted styles and identify inconsistencies.\n\n${guideSection}\n\n${styleSummary}\n\nRespond with a JSON object containing an \"issues\" array. Each issue should have:\n- id: unique string identifier\n- type: one of \"color\", \"typography\", \"spacing\", \"component\", \"responsive\", \"accessibility\"\n- message: human-readable description of the issue\n- currentValue: the problematic value found\n- expectedValue: what it should be (if known from style guide)\n- suggestion: how to fix it\n\nFocus on:\n1. Similar but not identical colors (e.g., #3B82F6 vs #3575E2)\n2. Inconsistent font sizes or weights\n3. Spacing values that don't follow a consistent scale (e.g., 4px base unit)\n4. Mixed border-radius values\n5. If utility/Tailwind classes are present in the summary, treat them as the styling surface area and flag inconsistent utility usage (e.g., mixing px-4 and px-5 for the same component type)\n\nBe concise and actionable. Only report significant inconsistencies.\n\nExample response:\n{\n \"issues\": [\n {\n \"id\": \"color-1\",\n \"type\": \"color\",\n \"message\": \"Found similar blue colors that should be consolidated\",\n \"currentValue\": \"#3575E2\",\n \"expectedValue\": \"#3B82F6\",\n \"suggestion\": \"Use the primary blue #3B82F6 consistently\"\n }\n ]\n}`;\n}\n\n/**\n * Builds a prompt for style guide generation\n */\nexport function buildStyleGuidePrompt(styleSummary: string): string {\n return `You are a design system expert. Based on the following detected styles, generate a clean, organized style guide in Markdown format.\n\n${styleSummary}\n\nGenerate a style guide with these sections:\n1. Colors - List the main colors with semantic names (Primary, Secondary, etc.)\n2. Typography - Font families, sizes, and weights\n3. Spacing - Base unit and common spacing values\n4. Components - Common component patterns\n5. Tailwind (if utility classes are present) - list commonly used utilities and any relevant theme tokens\n\nUse this format:\n# UI Style Guide\n\n## Colors\n- **Primary**: #HEXCODE (usage description)\n- **Secondary**: #HEXCODE (usage description)\n...\n\n## Typography\n- **Font Family**: FontName\n- **Font Sizes**: list of sizes\n- **Font Weights**: list of weights\n\n## Spacing\n- **Base unit**: Xpx\n- **Common values**: list of values\n\n## Components\n- **Buttons**: styles\n- **Cards**: styles\n...\n\nBe concise and focus on the most used values.`;\n}\n\n/**\n * Builds a prompt for querying the style guide\n */\nexport function buildQueryPrompt(\n query: string,\n styleGuide: string | null\n): string {\n if (!styleGuide) {\n return `The user is asking: \"${query}\"\n\nNo style guide has been created yet. Explain that they should run \"uilint init\" to create a style guide from their existing styles.`;\n }\n\n return `You are a helpful assistant that answers questions about a UI style guide.\n\n## Style Guide\n${styleGuide}\n\n## User Question\n${query}\n\nProvide a clear, concise answer based on the style guide above. If the style guide doesn't contain the information needed, say so and suggest what might be missing.`;\n}\n","/**\n * Ollama API client for LLM interactions\n */\n\nimport type {\n UILintIssue,\n AnalysisResult,\n OllamaClientOptions,\n} from \"../types.js\";\nimport {\n buildAnalysisPrompt,\n buildStyleGuidePrompt,\n buildQueryPrompt,\n} from \"./prompts.js\";\n\nconst DEFAULT_BASE_URL = \"http://localhost:11434\";\nconst DEFAULT_MODEL = \"qwen2.5-coder:7b\";\nconst DEFAULT_TIMEOUT = 60000;\n\nexport class OllamaClient {\n private baseUrl: string;\n private model: string;\n private timeout: number;\n\n constructor(options: OllamaClientOptions = {}) {\n this.baseUrl = options.baseUrl || DEFAULT_BASE_URL;\n this.model = options.model || DEFAULT_MODEL;\n this.timeout = options.timeout || DEFAULT_TIMEOUT;\n }\n\n /**\n * Analyzes styles and returns issues\n */\n async analyzeStyles(\n styleSummary: string,\n styleGuide: string | null\n ): Promise<AnalysisResult> {\n const startTime = Date.now();\n const prompt = buildAnalysisPrompt(styleSummary, styleGuide);\n\n try {\n const response = await this.generate(prompt);\n const issues = this.parseIssuesResponse(response);\n\n return {\n issues,\n analysisTime: Date.now() - startTime,\n };\n } catch (error) {\n console.error(\"[UILint] Analysis failed:\", error);\n return {\n issues: [],\n analysisTime: Date.now() - startTime,\n };\n }\n }\n\n /**\n * Generates a style guide from detected styles\n */\n async generateStyleGuide(styleSummary: string): Promise<string | null> {\n const prompt = buildStyleGuidePrompt(styleSummary);\n\n try {\n const response = await this.generate(prompt, false);\n return response;\n } catch (error) {\n console.error(\"[UILint] Style guide generation failed:\", error);\n return null;\n }\n }\n\n /**\n * Queries the style guide for specific information\n */\n async queryStyleGuide(\n query: string,\n styleGuide: string | null\n ): Promise<string> {\n const prompt = buildQueryPrompt(query, styleGuide);\n\n try {\n const response = await this.generate(prompt, false);\n return response;\n } catch (error) {\n console.error(\"[UILint] Query failed:\", error);\n return \"Failed to query style guide. Please try again.\";\n }\n }\n\n /**\n * Core generate method that calls Ollama API\n */\n private async generate(\n prompt: string,\n jsonFormat: boolean = true\n ): Promise<string> {\n const controller = new AbortController();\n const timeoutId = setTimeout(() => controller.abort(), this.timeout);\n\n try {\n const response = await fetch(`${this.baseUrl}/api/generate`, {\n method: \"POST\",\n headers: { \"Content-Type\": \"application/json\" },\n body: JSON.stringify({\n model: this.model,\n prompt,\n stream: false,\n ...(jsonFormat && { format: \"json\" }),\n }),\n signal: controller.signal,\n });\n\n if (!response.ok) {\n throw new Error(`Ollama API error: ${response.status}`);\n }\n\n const data = await response.json();\n return data.response || \"\";\n } finally {\n clearTimeout(timeoutId);\n }\n }\n\n /**\n * Parses issues from LLM response\n */\n private parseIssuesResponse(response: string): UILintIssue[] {\n try {\n const parsed = JSON.parse(response);\n return parsed.issues || [];\n } catch {\n console.warn(\"[UILint] Failed to parse LLM response as JSON\");\n return [];\n }\n }\n\n /**\n * Checks if Ollama is available\n */\n async isAvailable(): Promise<boolean> {\n try {\n const response = await fetch(`${this.baseUrl}/api/tags`, {\n method: \"GET\",\n signal: AbortSignal.timeout(5000),\n });\n return response.ok;\n } catch {\n return false;\n }\n }\n\n /**\n * Gets the current model\n */\n getModel(): string {\n return this.model;\n }\n\n /**\n * Sets the model\n */\n setModel(model: string): void {\n this.model = model;\n }\n}\n\n// Default singleton instance\nlet defaultClient: OllamaClient | null = null;\n\nexport function getOllamaClient(options?: OllamaClientOptions): OllamaClient {\n if (!defaultClient || options) {\n defaultClient = new OllamaClient(options);\n }\n return defaultClient;\n}\n","/**\n * Tailwind / utility-class token extraction helpers.\n *\n * Notes:\n * - Works on HTML (class=\"...\") and TSX-ish input (className=\"...\") via regex.\n * - Variant parsing is bracket-aware so arbitrary values like bg-[color:var(--x)]\n * don't get split incorrectly on \":\".\n */\n\nexport interface ClassTokenCounts {\n /**\n * Base utilities with variants stripped.\n * Example: \"sm:hover:bg-gray-50\" => utility \"bg-gray-50\"\n */\n utilities: Map<string, number>;\n /**\n * Individual variant prefixes.\n * Example: \"sm:hover:bg-gray-50\" => variants \"sm\", \"hover\"\n */\n variants: Map<string, number>;\n}\n\nexport interface ExtractClassTokenOptions {\n /**\n * Maximum number of tokens to process (guardrail for very large inputs).\n */\n maxTokens?: number;\n}\n\nexport function extractClassTokensFromHtml(\n html: string,\n options: ExtractClassTokenOptions = {}\n): ClassTokenCounts {\n const { maxTokens = 20000 } = options;\n\n const utilities = new Map<string, number>();\n const variants = new Map<string, number>();\n\n if (!html) return { utilities, variants };\n\n // Match both HTML and JSX-ish attributes.\n // - class=\"...\"\n // - className=\"...\"\n const attrPattern = /\\b(?:class|className)\\s*=\\s*[\"']([^\"']+)[\"']/g;\n\n let tokenBudget = maxTokens;\n let match: RegExpExecArray | null;\n while ((match = attrPattern.exec(html)) && tokenBudget > 0) {\n const raw = match[1];\n if (!raw) continue;\n\n const tokens = raw.split(/\\s+/g).filter(Boolean);\n for (const token of tokens) {\n if (tokenBudget-- <= 0) break;\n\n const { base, variantList } = splitVariants(token);\n const normalizedBase = normalizeUtility(base);\n if (!normalizedBase) continue;\n\n increment(utilities, normalizedBase);\n for (const v of variantList) increment(variants, v);\n }\n }\n\n return { utilities, variants };\n}\n\nexport function topEntries(\n map: Map<string, number>,\n limit: number\n): Array<{ token: string; count: number }> {\n return [...map.entries()]\n .sort((a, b) => b[1] - a[1])\n .slice(0, limit)\n .map(([token, count]) => ({ token, count }));\n}\n\nfunction increment(map: Map<string, number>, key: string): void {\n map.set(key, (map.get(key) || 0) + 1);\n}\n\nfunction normalizeUtility(token: string): string | null {\n const t = token.trim();\n if (!t) return null;\n\n // Strip important modifier\n const noImportant = t.startsWith(\"!\") ? t.slice(1) : t;\n\n // Ignore obviously non-class tokens\n if (!noImportant || noImportant === \"{\" || noImportant === \"}\") return null;\n\n return noImportant;\n}\n\n/**\n * Splits a class token into variants and base utility.\n * Bracket-aware to avoid splitting arbitrary values on \":\".\n *\n * Examples:\n * - \"sm:hover:bg-gray-50\" => variants [\"sm\",\"hover\"], base \"bg-gray-50\"\n * - \"bg-[color:var(--x)]\" => variants [], base \"bg-[color:var(--x)]\"\n * - \"sm:bg-[color:var(--x)]\" => variants [\"sm\"], base \"bg-[color:var(--x)]\"\n */\nfunction splitVariants(token: string): { base: string; variantList: string[] } {\n const parts: string[] = [];\n let buf = \"\";\n let bracketDepth = 0;\n\n for (let i = 0; i < token.length; i++) {\n const ch = token[i];\n if (ch === \"[\") bracketDepth++;\n if (ch === \"]\" && bracketDepth > 0) bracketDepth--;\n\n if (ch === \":\" && bracketDepth === 0) {\n parts.push(buf);\n buf = \"\";\n continue;\n }\n\n buf += ch;\n }\n parts.push(buf);\n\n if (parts.length <= 1) return { base: token, variantList: [] };\n\n const base = parts[parts.length - 1] || \"\";\n const variantList = parts\n .slice(0, -1)\n .map((v) => v.trim())\n .filter(Boolean);\n\n return { base, variantList };\n}\n","/**\n * Style extraction from DOM elements\n */\n\nimport type {\n ExtractedStyles,\n SerializedStyles,\n TailwindThemeTokens,\n} from \"../types.js\";\nimport {\n extractClassTokensFromHtml,\n topEntries,\n} from \"../tailwind/class-tokens.js\";\n\n/**\n * Extracts all computed styles from elements in the document\n * Works in both browser and JSDOM environments\n */\nexport function extractStyles(\n root: Element | Document,\n getComputedStyle: (el: Element) => CSSStyleDeclaration\n): ExtractedStyles {\n const styles: ExtractedStyles = {\n colors: new Map(),\n fontSizes: new Map(),\n fontFamilies: new Map(),\n fontWeights: new Map(),\n spacing: new Map(),\n borderRadius: new Map(),\n };\n\n const elements = root.querySelectorAll(\"*\");\n\n elements.forEach((element) => {\n // nodeType === 1 means Element node (works in both browser and JSDOM)\n if (element.nodeType !== 1) return;\n\n const computed = getComputedStyle(element);\n\n // Extract colors\n extractColor(computed.color, styles.colors);\n extractColor(computed.backgroundColor, styles.colors);\n extractColor(computed.borderColor, styles.colors);\n\n // Extract typography\n incrementMap(styles.fontSizes, computed.fontSize);\n incrementMap(styles.fontFamilies, normalizeFontFamily(computed.fontFamily));\n incrementMap(styles.fontWeights, computed.fontWeight);\n\n // Extract spacing\n extractSpacing(computed.margin, styles.spacing);\n extractSpacing(computed.padding, styles.spacing);\n incrementMap(styles.spacing, computed.gap);\n\n // Extract border radius\n incrementMap(styles.borderRadius, computed.borderRadius);\n });\n\n return styles;\n}\n\n/**\n * Extracts styles from browser DOM (uses window.getComputedStyle)\n */\nexport function extractStylesFromDOM(\n root?: Element | Document\n): ExtractedStyles {\n const targetRoot = root || document.body;\n return extractStyles(targetRoot, (el) => window.getComputedStyle(el));\n}\n\nfunction extractColor(color: string, map: Map<string, number>): void {\n if (!color || color === \"transparent\" || color === \"rgba(0, 0, 0, 0)\") return;\n\n // Normalize to hex\n const hex = rgbToHex(color);\n if (hex) {\n incrementMap(map, hex);\n }\n}\n\nfunction extractSpacing(value: string, map: Map<string, number>): void {\n if (!value || value === \"0px\") return;\n\n // Split compound values (e.g., \"10px 20px 10px 20px\")\n const values = value.split(\" \").filter((v) => v && v !== \"0px\");\n values.forEach((v) => incrementMap(map, v));\n}\n\nfunction incrementMap(map: Map<string, number>, value: string): void {\n if (!value || value === \"normal\" || value === \"auto\") return;\n map.set(value, (map.get(value) || 0) + 1);\n}\n\nfunction normalizeFontFamily(fontFamily: string): string {\n // Get the primary font (first in the stack)\n const primary = fontFamily.split(\",\")[0].trim();\n return primary.replace(/['\"]/g, \"\");\n}\n\nfunction rgbToHex(rgb: string): string | null {\n // Handle hex values\n if (rgb.startsWith(\"#\")) return rgb.toUpperCase();\n\n // Handle rgb/rgba values\n const match = rgb.match(/rgba?\\((\\d+),\\s*(\\d+),\\s*(\\d+)/);\n if (!match) return null;\n\n const [, r, g, b] = match;\n const toHex = (n: string) => parseInt(n).toString(16).padStart(2, \"0\");\n\n return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();\n}\n\n/**\n * Converts ExtractedStyles maps to plain objects for serialization\n */\nexport function serializeStyles(styles: ExtractedStyles): SerializedStyles {\n return {\n colors: Object.fromEntries(styles.colors),\n fontSizes: Object.fromEntries(styles.fontSizes),\n fontFamilies: Object.fromEntries(styles.fontFamilies),\n fontWeights: Object.fromEntries(styles.fontWeights),\n spacing: Object.fromEntries(styles.spacing),\n borderRadius: Object.fromEntries(styles.borderRadius),\n };\n}\n\n/**\n * Converts SerializedStyles back to ExtractedStyles\n */\nexport function deserializeStyles(\n serialized: SerializedStyles\n): ExtractedStyles {\n return {\n colors: new Map(Object.entries(serialized.colors)),\n fontSizes: new Map(Object.entries(serialized.fontSizes)),\n fontFamilies: new Map(Object.entries(serialized.fontFamilies)),\n fontWeights: new Map(Object.entries(serialized.fontWeights)),\n spacing: new Map(Object.entries(serialized.spacing)),\n borderRadius: new Map(Object.entries(serialized.borderRadius)),\n };\n}\n\n/**\n * Creates a summary of extracted styles for LLM analysis\n */\nexport function createStyleSummary(\n styles: ExtractedStyles,\n options: CreateStyleSummaryOptions = {}\n): string {\n return createStyleSummaryWithOptions(styles, options);\n}\n\nexport interface CreateStyleSummaryOptions {\n /**\n * Optional HTML/TSX-ish string used to extract utility classes (Tailwind etc).\n */\n html?: string;\n /**\n * Optional Tailwind theme tokens (typically from tailwind.config.*).\n */\n tailwindTheme?: TailwindThemeTokens | null;\n}\n\n/**\n * Creates a summary of extracted styles for LLM analysis.\n * Accepts optional Tailwind context to make Tailwind-heavy projects analyzable\n * even when computed styles are sparse (e.g., JSDOM without loaded CSS).\n */\nexport function createStyleSummaryWithOptions(\n styles: ExtractedStyles,\n options: CreateStyleSummaryOptions = {}\n): string {\n const lines: string[] = [];\n\n lines.push(\"## Detected Styles Summary\\n\");\n\n // Colors\n lines.push(\"### Colors\");\n const sortedColors = [...styles.colors.entries()].sort((a, b) => b[1] - a[1]);\n sortedColors.slice(0, 20).forEach(([color, count]) => {\n lines.push(`- ${color}: ${count} occurrences`);\n });\n lines.push(\"\");\n\n // Font sizes\n lines.push(\"### Font Sizes\");\n const sortedFontSizes = [...styles.fontSizes.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n sortedFontSizes.forEach(([size, count]) => {\n lines.push(`- ${size}: ${count} occurrences`);\n });\n lines.push(\"\");\n\n // Font families\n lines.push(\"### Font Families\");\n const sortedFontFamilies = [...styles.fontFamilies.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n sortedFontFamilies.forEach(([family, count]) => {\n lines.push(`- ${family}: ${count} occurrences`);\n });\n lines.push(\"\");\n\n // Font weights\n lines.push(\"### Font Weights\");\n const sortedFontWeights = [...styles.fontWeights.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n sortedFontWeights.forEach(([weight, count]) => {\n lines.push(`- ${weight}: ${count} occurrences`);\n });\n lines.push(\"\");\n\n // Spacing\n lines.push(\"### Spacing Values\");\n const sortedSpacing = [...styles.spacing.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n sortedSpacing.slice(0, 15).forEach(([value, count]) => {\n lines.push(`- ${value}: ${count} occurrences`);\n });\n lines.push(\"\");\n\n // Border radius\n lines.push(\"### Border Radius\");\n const sortedBorderRadius = [...styles.borderRadius.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n sortedBorderRadius.forEach(([value, count]) => {\n lines.push(`- ${value}: ${count} occurrences`);\n });\n\n // Tailwind / utility classes (optional)\n if (options.html) {\n const tokens = extractClassTokensFromHtml(options.html);\n const topUtilities = topEntries(tokens.utilities, 40);\n const topVariants = topEntries(tokens.variants, 15);\n\n lines.push(\"\");\n lines.push(\"### Utility Classes (from markup)\");\n if (topUtilities.length === 0) {\n lines.push(\"- (none detected)\");\n } else {\n topUtilities.forEach(({ token, count }) => {\n lines.push(`- ${token}: ${count} occurrences`);\n });\n }\n\n if (topVariants.length > 0) {\n lines.push(\"\");\n lines.push(\"### Common Variants\");\n topVariants.forEach(({ token, count }) => {\n lines.push(`- ${token}: ${count} occurrences`);\n });\n }\n }\n\n // Tailwind theme tokens (optional)\n if (options.tailwindTheme) {\n const tt = options.tailwindTheme;\n lines.push(\"\");\n lines.push(\"### Tailwind Theme Tokens (from config)\");\n lines.push(`- configPath: ${tt.configPath}`);\n lines.push(`- colors: ${tt.colors.length}`);\n lines.push(`- spacingKeys: ${tt.spacingKeys.length}`);\n lines.push(`- borderRadiusKeys: ${tt.borderRadiusKeys.length}`);\n lines.push(`- fontFamilyKeys: ${tt.fontFamilyKeys.length}`);\n lines.push(`- fontSizeKeys: ${tt.fontSizeKeys.length}`);\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Truncates HTML to a maximum length\n */\nexport function truncateHTML(html: string, maxLength: number = 50000): string {\n if (html.length <= maxLength) return html;\n return html.slice(0, maxLength) + \"<!-- truncated -->\";\n}\n","/**\n * Style guide schema and utilities\n */\n\nimport type { StyleGuide, ColorRule, TypographyRule, SpacingRule, ComponentRule } from \"../types.js\";\n\n/**\n * Creates an empty style guide structure\n */\nexport function createEmptyStyleGuide(): StyleGuide {\n return {\n colors: [],\n typography: [],\n spacing: [],\n components: [],\n };\n}\n\n/**\n * Validates a style guide object\n */\nexport function validateStyleGuide(guide: unknown): guide is StyleGuide {\n if (!guide || typeof guide !== \"object\") return false;\n\n const g = guide as Record<string, unknown>;\n\n return (\n Array.isArray(g.colors) &&\n Array.isArray(g.typography) &&\n Array.isArray(g.spacing) &&\n Array.isArray(g.components)\n );\n}\n\n/**\n * Merges detected styles into an existing style guide\n */\nexport function mergeStyleGuides(\n existing: StyleGuide,\n detected: Partial<StyleGuide>\n): StyleGuide {\n return {\n colors: mergeColorRules(existing.colors, detected.colors || []),\n typography: mergeTypographyRules(existing.typography, detected.typography || []),\n spacing: mergeSpacingRules(existing.spacing, detected.spacing || []),\n components: mergeComponentRules(existing.components, detected.components || []),\n };\n}\n\nfunction mergeColorRules(existing: ColorRule[], detected: ColorRule[]): ColorRule[] {\n const merged = [...existing];\n detected.forEach((rule) => {\n const existingIndex = merged.findIndex(\n (e) => e.name === rule.name || e.value === rule.value\n );\n if (existingIndex === -1) {\n merged.push(rule);\n }\n });\n return merged;\n}\n\nfunction mergeTypographyRules(existing: TypographyRule[], detected: TypographyRule[]): TypographyRule[] {\n const merged = [...existing];\n detected.forEach((rule) => {\n const existingIndex = merged.findIndex((e) => e.element === rule.element);\n if (existingIndex === -1) {\n merged.push(rule);\n }\n });\n return merged;\n}\n\nfunction mergeSpacingRules(existing: SpacingRule[], detected: SpacingRule[]): SpacingRule[] {\n const merged = [...existing];\n detected.forEach((rule) => {\n const existingIndex = merged.findIndex(\n (e) => e.name === rule.name || e.value === rule.value\n );\n if (existingIndex === -1) {\n merged.push(rule);\n }\n });\n return merged;\n}\n\nfunction mergeComponentRules(existing: ComponentRule[], detected: ComponentRule[]): ComponentRule[] {\n const merged = [...existing];\n detected.forEach((rule) => {\n const existingIndex = merged.findIndex((e) => e.name === rule.name);\n if (existingIndex === -1) {\n merged.push(rule);\n }\n });\n return merged;\n}\n\n/**\n * Creates a color rule\n */\nexport function createColorRule(\n name: string,\n value: string,\n usage: string = \"\"\n): ColorRule {\n return { name, value: value.toUpperCase(), usage };\n}\n\n/**\n * Creates a typography rule\n */\nexport function createTypographyRule(\n element: string,\n options: Partial<Omit<TypographyRule, \"element\">> = {}\n): TypographyRule {\n return { element, ...options };\n}\n\n/**\n * Creates a spacing rule\n */\nexport function createSpacingRule(name: string, value: string): SpacingRule {\n return { name, value };\n}\n\n/**\n * Creates a component rule\n */\nexport function createComponentRule(name: string, styles: string[]): ComponentRule {\n return { name, styles };\n}\n\n","/**\n * Parse Markdown style guides into structured data\n */\n\nimport type {\n StyleGuide,\n ColorRule,\n TypographyRule,\n SpacingRule,\n ComponentRule,\n ExtractedStyleValues,\n} from \"../types.js\";\nimport { createEmptyStyleGuide } from \"./schema.js\";\n\n/**\n * Parses a Markdown style guide into a structured object\n */\nexport function parseStyleGuide(markdown: string): StyleGuide {\n const guide = createEmptyStyleGuide();\n const sections = splitIntoSections(markdown);\n\n sections.forEach(({ title, content }) => {\n const lowerTitle = title.toLowerCase();\n\n if (lowerTitle.includes(\"color\")) {\n guide.colors = parseColorSection(content);\n } else if (\n lowerTitle.includes(\"typography\") ||\n lowerTitle.includes(\"font\")\n ) {\n guide.typography = parseTypographySection(content);\n } else if (lowerTitle.includes(\"spacing\")) {\n guide.spacing = parseSpacingSection(content);\n } else if (lowerTitle.includes(\"component\")) {\n guide.components = parseComponentSection(content);\n }\n });\n\n return guide;\n}\n\ninterface Section {\n title: string;\n content: string;\n}\n\nfunction splitIntoSections(markdown: string): Section[] {\n const sections: Section[] = [];\n const lines = markdown.split(\"\\n\");\n\n let currentTitle = \"\";\n let currentContent: string[] = [];\n\n lines.forEach((line) => {\n const headerMatch = line.match(/^##\\s+(.+)$/);\n\n if (headerMatch) {\n if (currentTitle) {\n sections.push({\n title: currentTitle,\n content: currentContent.join(\"\\n\"),\n });\n }\n currentTitle = headerMatch[1];\n currentContent = [];\n } else {\n currentContent.push(line);\n }\n });\n\n if (currentTitle) {\n sections.push({\n title: currentTitle,\n content: currentContent.join(\"\\n\"),\n });\n }\n\n return sections;\n}\n\nfunction parseColorSection(content: string): ColorRule[] {\n const colors: ColorRule[] = [];\n const lines = content.split(\"\\n\");\n\n lines.forEach((line) => {\n // Match patterns like: - **Primary**: #3B82F6 (used in buttons)\n const match = line.match(\n /[-*]\\s*\\*?\\*?([^*:]+)\\*?\\*?:\\s*(#[A-Fa-f0-9]{6})\\s*(?:\\(([^)]+)\\))?/\n );\n\n if (match) {\n colors.push({\n name: match[1].trim(),\n value: match[2].toUpperCase(),\n usage: match[3] || \"\",\n });\n }\n });\n\n return colors;\n}\n\nfunction parseTypographySection(content: string): TypographyRule[] {\n const typography: TypographyRule[] = [];\n const lines = content.split(\"\\n\");\n\n lines.forEach((line) => {\n // Match patterns like: - **Headings**: font-family: \"Inter\", font-size: 24px\n const elementMatch = line.match(/[-*]\\s*\\*?\\*?([^*:]+)\\*?\\*?:\\s*(.+)/);\n\n if (elementMatch) {\n const rule: TypographyRule = {\n element: elementMatch[1].trim(),\n };\n\n const props = elementMatch[2];\n\n const fontFamilyMatch = props.match(/font-family:\\s*\"?([^\",]+)\"?/);\n if (fontFamilyMatch) rule.fontFamily = fontFamilyMatch[1].trim();\n\n const fontSizeMatch = props.match(/font-size:\\s*(\\d+px)/);\n if (fontSizeMatch) rule.fontSize = fontSizeMatch[1];\n\n const fontWeightMatch = props.match(/font-weight:\\s*(\\d+)/);\n if (fontWeightMatch) rule.fontWeight = fontWeightMatch[1];\n\n const lineHeightMatch = props.match(/line-height:\\s*([\\d.]+)/);\n if (lineHeightMatch) rule.lineHeight = lineHeightMatch[1];\n\n typography.push(rule);\n }\n });\n\n return typography;\n}\n\nfunction parseSpacingSection(content: string): SpacingRule[] {\n const spacing: SpacingRule[] = [];\n const lines = content.split(\"\\n\");\n\n lines.forEach((line) => {\n // Match patterns like: - **Base unit**: 4px\n const match = line.match(/[-*]\\s*\\*?\\*?([^*:]+)\\*?\\*?:\\s*(.+)/);\n\n if (match) {\n spacing.push({\n name: match[1].trim(),\n value: match[2].trim(),\n });\n }\n });\n\n return spacing;\n}\n\nfunction parseComponentSection(content: string): ComponentRule[] {\n const components: ComponentRule[] = [];\n const lines = content.split(\"\\n\");\n\n lines.forEach((line) => {\n // Match patterns like: - **Buttons**: rounded-lg, px-4 py-2\n const match = line.match(/[-*]\\s*\\*?\\*?([^*:]+)\\*?\\*?:\\s*(.+)/);\n\n if (match) {\n components.push({\n name: match[1].trim(),\n styles: match[2].split(\",\").map((s) => s.trim()),\n });\n }\n });\n\n return components;\n}\n\n/**\n * Parses sections from a Markdown style guide (simpler format)\n */\nexport function parseStyleGuideSections(\n content: string\n): Record<string, string> {\n const sections: Record<string, string> = {};\n const lines = content.split(\"\\n\");\n\n let currentSection = \"intro\";\n let currentContent: string[] = [];\n\n for (const line of lines) {\n const headerMatch = line.match(/^##\\s+(.+)$/);\n\n if (headerMatch) {\n if (currentContent.length > 0) {\n sections[currentSection.toLowerCase()] = currentContent\n .join(\"\\n\")\n .trim();\n }\n\n currentSection = headerMatch[1];\n currentContent = [];\n } else {\n currentContent.push(line);\n }\n }\n\n if (currentContent.length > 0) {\n sections[currentSection.toLowerCase()] = currentContent.join(\"\\n\").trim();\n }\n\n return sections;\n}\n\n/**\n * Extracts specific values from the style guide\n */\nexport function extractStyleValues(content: string): ExtractedStyleValues {\n const result: ExtractedStyleValues = {\n colors: [],\n fontSizes: [],\n fontFamilies: [],\n spacing: [],\n borderRadius: [],\n };\n\n // Extract hex colors\n const colorMatches = content.matchAll(/#[A-Fa-f0-9]{6}\\b/g);\n for (const match of colorMatches) {\n if (!result.colors.includes(match[0].toUpperCase())) {\n result.colors.push(match[0].toUpperCase());\n }\n }\n\n // Extract font sizes (e.g., 16px, 1.5rem)\n const fontSizeMatches = content.matchAll(/\\b(\\d+(?:\\.\\d+)?(?:px|rem|em))\\b/g);\n for (const match of fontSizeMatches) {\n if (!result.fontSizes.includes(match[1])) {\n result.fontSizes.push(match[1]);\n }\n }\n\n // Extract font families (quoted strings in font context)\n const fontFamilyMatches = content.matchAll(\n /font-family:\\s*[\"']?([^\"',\\n]+)/gi\n );\n for (const match of fontFamilyMatches) {\n const family = match[1].trim();\n if (!result.fontFamilies.includes(family)) {\n result.fontFamilies.push(family);\n }\n }\n\n return result;\n}\n\nexport interface TailwindAllowlist {\n allowAnyColor: boolean;\n allowStandardSpacing: boolean;\n allowedTailwindColors: Set<string>;\n allowedUtilities: Set<string>;\n allowedSpacingKeys: Set<string>;\n allowedBorderRadiusKeys: Set<string>;\n allowedFontSizeKeys: Set<string>;\n allowedFontFamilyKeys: Set<string>;\n}\n\n/**\n * Extract Tailwind / utility-class allowlist configuration from a style guide.\n *\n * Expected formats:\n * - A JSON code block inside a \"## Tailwind\" section (preferred; produced by UILint)\n * - Fallback: inline backticked utilities within the Tailwind section\n */\nexport function extractTailwindAllowlist(content: string): TailwindAllowlist {\n const empty: TailwindAllowlist = {\n allowAnyColor: false,\n allowStandardSpacing: false,\n allowedTailwindColors: new Set(),\n allowedUtilities: new Set(),\n allowedSpacingKeys: new Set(),\n allowedBorderRadiusKeys: new Set(),\n allowedFontSizeKeys: new Set(),\n allowedFontFamilyKeys: new Set(),\n };\n\n // Only look for allowlist details in the Tailwind section.\n const sections = parseStyleGuideSections(content);\n const tailwindSection =\n sections[\"tailwind\"] ??\n // defensive: some styleguides use different casing/spacing\n sections[\"tailwind utilities\"] ??\n \"\";\n\n if (!tailwindSection) return empty;\n\n const parsed = tryParseFirstJsonCodeBlock(tailwindSection);\n if (parsed && typeof parsed === \"object\") {\n const allowAnyColor = Boolean((parsed as any).allowAnyColor);\n const allowStandardSpacing = Boolean((parsed as any).allowStandardSpacing);\n\n const allowedUtilitiesArr = Array.isArray((parsed as any).allowedUtilities)\n ? ((parsed as any).allowedUtilities as unknown[]).filter(\n (u): u is string => typeof u === \"string\"\n )\n : [];\n\n const themeTokens = (parsed as any).themeTokens ?? {};\n const themeColors = Array.isArray(themeTokens.colors)\n ? (themeTokens.colors as unknown[]).filter((c): c is string => typeof c === \"string\")\n : [];\n const spacingKeys = Array.isArray(themeTokens.spacingKeys)\n ? (themeTokens.spacingKeys as unknown[]).filter((k): k is string => typeof k === \"string\")\n : [];\n const borderRadiusKeys = Array.isArray(themeTokens.borderRadiusKeys)\n ? (themeTokens.borderRadiusKeys as unknown[]).filter((k): k is string => typeof k === \"string\")\n : [];\n const fontFamilyKeys = Array.isArray(themeTokens.fontFamilyKeys)\n ? (themeTokens.fontFamilyKeys as unknown[]).filter((k): k is string => typeof k === \"string\")\n : [];\n const fontSizeKeys = Array.isArray(themeTokens.fontSizeKeys)\n ? (themeTokens.fontSizeKeys as unknown[]).filter((k): k is string => typeof k === \"string\")\n : [];\n\n const allowedTailwindColors = new Set<string>();\n for (const c of themeColors) {\n const raw = c.trim();\n if (!raw) continue;\n if (raw.toLowerCase().startsWith(\"tailwind:\")) {\n allowedTailwindColors.add(raw.toLowerCase());\n continue;\n }\n const m = raw.match(/^([a-zA-Z]+)-(\\d{2,3})$/);\n if (m) {\n allowedTailwindColors.add(`tailwind:${m[1].toLowerCase()}-${m[2]}`);\n }\n }\n\n return {\n allowAnyColor,\n allowStandardSpacing,\n allowedTailwindColors,\n allowedUtilities: new Set(allowedUtilitiesArr.map((s) => s.trim()).filter(Boolean)),\n allowedSpacingKeys: new Set(spacingKeys.map((s) => s.trim()).filter(Boolean)),\n allowedBorderRadiusKeys: new Set(borderRadiusKeys.map((s) => s.trim()).filter(Boolean)),\n allowedFontSizeKeys: new Set(fontSizeKeys.map((s) => s.trim()).filter(Boolean)),\n allowedFontFamilyKeys: new Set(fontFamilyKeys.map((s) => s.trim()).filter(Boolean)),\n };\n }\n\n // Fallback: harvest backticked utilities from markdown.\n const backticked: string[] = [];\n for (const m of tailwindSection.matchAll(/`([^`]+)`/g)) {\n backticked.push(m[1]);\n }\n\n return {\n ...empty,\n allowedUtilities: new Set(\n backticked\n .flatMap((s) => s.split(/[,\\s]+/g))\n .map((s) => s.trim())\n .filter(Boolean)\n ),\n };\n}\n\nfunction tryParseFirstJsonCodeBlock(section: string): unknown | null {\n // Prefer ```json fenced blocks, but fall back to any fenced block.\n const jsonBlocks = [...section.matchAll(/```json\\s*([\\s\\S]*?)```/gi)];\n const anyBlocks = [...section.matchAll(/```\\s*([\\s\\S]*?)```/g)];\n\n const candidates = (jsonBlocks.length ? jsonBlocks : anyBlocks).map((m) => m[1]);\n for (const raw of candidates) {\n const trimmed = raw.trim();\n if (!trimmed) continue;\n try {\n return JSON.parse(trimmed);\n } catch {\n continue;\n }\n }\n return null;\n}\n","/**\n * Generate Markdown style guides from extracted styles\n */\n\nimport type {\n ExtractedStyles,\n StyleGuide,\n TailwindThemeTokens,\n} from \"../types.js\";\nimport {\n extractClassTokensFromHtml,\n topEntries,\n} from \"../tailwind/class-tokens.js\";\n\n/**\n * Generates a Markdown style guide from extracted styles\n */\nexport interface GenerateStyleGuideOptions {\n /**\n * Optional HTML/TSX-ish string used to extract utility classes (Tailwind etc).\n */\n html?: string;\n /**\n * Optional Tailwind theme tokens (typically from tailwind.config.*).\n */\n tailwindTheme?: TailwindThemeTokens | null;\n}\n\nexport function generateStyleGuideFromStyles(\n styles: ExtractedStyles,\n options: GenerateStyleGuideOptions = {}\n): string {\n const lines: string[] = [];\n\n lines.push(\"# UI Style Guide\");\n lines.push(\"\");\n lines.push(\n \"> Auto-generated by UILint. Edit this file to define your design system.\"\n );\n lines.push(\"\");\n\n // Merge in any literal hex colors found in the input markup/code.\n // This is important when the input is TSX/JSX or Tailwind-heavy, where\n // computed styles (JSDOM) may be sparse or unavailable.\n const html = options.html || \"\";\n const mergedColors = new Map(styles.colors);\n if (html) {\n for (const m of html.matchAll(/#[A-Fa-f0-9]{6}\\b/g)) {\n const hex = (m[0] || \"\").toUpperCase();\n if (!hex) continue;\n mergedColors.set(hex, (mergedColors.get(hex) || 0) + 1);\n }\n }\n\n // Colors section\n lines.push(\"## Colors\");\n lines.push(\"\");\n const sortedColors = [...mergedColors.entries()].sort((a, b) => b[1] - a[1]);\n\n if (sortedColors.length > 0) {\n const colorNames = [\n \"Primary\",\n \"Secondary\",\n \"Accent\",\n \"Background\",\n \"Text\",\n \"Muted\",\n \"Border\",\n \"Success\",\n \"Warning\",\n \"Error\",\n ];\n sortedColors.forEach(([color, count], index) => {\n const name = colorNames[index] || `Color ${index + 1}`;\n lines.push(`- **${name}**: ${color} (${count} occurrences)`);\n });\n } else {\n lines.push(\"- No colors detected\");\n }\n lines.push(\"\");\n\n // Typography section\n lines.push(\"## Typography\");\n lines.push(\"\");\n\n // Font families\n const sortedFontFamilies = [...styles.fontFamilies.entries()].sort(\n (a, b) => b[1] - a[1]\n );\n\n if (sortedFontFamilies.length > 0) {\n lines.push(`- **Font Family**: ${sortedFontFamilies[0][0]}`);\n }\n\n // Font sizes\n const sortedFontSizes = [...styles.fontSizes.entries()].sort(\n (a, b) => parseFloat(a[0]) - parseFloat(b[0])\n );\n\n if (sortedFontSizes.length > 0) {\n const sizes = sortedFontSizes.map(([size]) => size).join(\", \");\n lines.push(`- **Font Sizes**: ${sizes}`);\n }\n\n // Font weights\n const sortedFontWeights = [...styles.fontWeights.entries()].sort(\n (a, b) => parseInt(a[0]) - parseInt(b[0])\n );\n\n if (sortedFontWeights.length > 0) {\n const weights = sortedFontWeights.map(([weight]) => weight).join(\", \");\n lines.push(`- **Font Weights**: ${weights}`);\n }\n lines.push(\"\");\n\n // Spacing section\n lines.push(\"## Spacing\");\n lines.push(\"\");\n\n const sortedSpacing = [...styles.spacing.entries()]\n .filter(([value]) => value.endsWith(\"px\"))\n .sort((a, b) => parseFloat(a[0]) - parseFloat(b[0]));\n\n if (sortedSpacing.length > 0) {\n // Try to detect base unit\n const spacingValues = sortedSpacing.map(([value]) => parseFloat(value));\n const gcd = findGCD(spacingValues.filter((v) => v > 0));\n\n if (gcd >= 4) {\n lines.push(`- **Base unit**: ${gcd}px`);\n }\n\n const uniqueSpacing = [...new Set(sortedSpacing.map(([v]) => v))].slice(\n 0,\n 8\n );\n lines.push(`- **Common values**: ${uniqueSpacing.join(\", \")}`);\n } else {\n lines.push(\"- No spacing values detected\");\n }\n lines.push(\"\");\n\n // Border radius section\n lines.push(\"## Border Radius\");\n lines.push(\"\");\n\n const sortedBorderRadius = [...styles.borderRadius.entries()]\n .filter(([value]) => value !== \"0px\")\n .sort((a, b) => b[1] - a[1]);\n\n if (sortedBorderRadius.length > 0) {\n sortedBorderRadius.slice(0, 5).forEach(([value, count]) => {\n lines.push(`- ${value} (${count} occurrences)`);\n });\n } else {\n lines.push(\"- No border radius values detected\");\n }\n lines.push(\"\");\n\n // Components section (placeholder)\n lines.push(\"## Components\");\n lines.push(\"\");\n lines.push(\"- **Buttons**: Define button styles here\");\n lines.push(\"- **Cards**: Define card styles here\");\n lines.push(\"- **Inputs**: Define input styles here\");\n lines.push(\"\");\n\n // Tailwind / utility classes (optional)\n const classTokens = html ? extractClassTokensFromHtml(html) : null;\n const topUtilities = classTokens ? topEntries(classTokens.utilities, 50) : [];\n const topVariants = classTokens ? topEntries(classTokens.variants, 20) : [];\n const allUtilities = classTokens\n ? [...classTokens.utilities.entries()]\n .sort((a, b) => (b[1] - a[1] ? b[1] - a[1] : a[0].localeCompare(b[0])))\n .map(([token]) => token)\n : [];\n\n const theme = options.tailwindTheme;\n const themeColors = theme?.colors || [];\n const themeSpacingKeys = theme?.spacingKeys || [];\n const themeBorderRadiusKeys = theme?.borderRadiusKeys || [];\n const themeFontFamilyKeys = theme?.fontFamilyKeys || [];\n const themeFontSizeKeys = theme?.fontSizeKeys || [];\n\n const hasTailwindSection =\n topUtilities.length > 0 ||\n themeColors.length > 0 ||\n themeSpacingKeys.length > 0 ||\n themeBorderRadiusKeys.length > 0 ||\n themeFontFamilyKeys.length > 0 ||\n themeFontSizeKeys.length > 0;\n\n if (hasTailwindSection) {\n lines.push(\"## Tailwind\");\n lines.push(\"\");\n lines.push(\n \"> Optional. Captures Tailwind/utility class conventions for validation and consistency.\"\n );\n lines.push(\"\");\n\n if (topUtilities.length > 0) {\n const utilityList = topUtilities\n .slice(0, 25)\n .map((u) => `\\`${u.token}\\``)\n .join(\", \");\n lines.push(`- **Observed utilities (top)**: ${utilityList}`);\n } else {\n lines.push(\"- **Observed utilities (top)**: (none detected)\");\n }\n\n if (topVariants.length > 0) {\n const variantList = topVariants\n .slice(0, 12)\n .map((v) => `\\`${v.token}\\``)\n .join(\", \");\n lines.push(`- **Common variants**: ${variantList}`);\n }\n\n if (theme) {\n lines.push(`- **Config path**: \\`${theme.configPath}\\``);\n if (themeColors.length > 0) {\n lines.push(\n `- **Theme colors (tokens)**: ${themeColors\n .slice(0, 25)\n .map((t) => `\\`${t}\\``)\n .join(\", \")}${themeColors.length > 25 ? \", ...\" : \"\"}`\n );\n } else {\n lines.push(\"- **Theme colors (tokens)**: (none specified in config)\");\n }\n\n if (themeSpacingKeys.length > 0) {\n lines.push(\n `- **Theme spacing keys**: ${themeSpacingKeys\n .slice(0, 25)\n .map((k) => `\\`${k}\\``)\n .join(\", \")}${themeSpacingKeys.length > 25 ? \", ...\" : \"\"}`\n );\n }\n }\n\n // Machine-readable payload to make parsing/validation robust.\n const payload = {\n // IMPORTANT: include all observed utilities (not just \"top N\"), otherwise\n // init+validate on the same file can be inconsistent.\n allowedUtilities: allUtilities,\n allowAnyColor: !!theme && themeColors.length === 0, // avoid noisy warnings when config doesn't define colors\n allowStandardSpacing: !!theme && themeSpacingKeys.length === 0,\n themeTokens: theme\n ? {\n configPath: theme.configPath,\n colors: themeColors,\n spacingKeys: themeSpacingKeys,\n borderRadiusKeys: themeBorderRadiusKeys,\n fontFamilyKeys: themeFontFamilyKeys,\n fontSizeKeys: themeFontSizeKeys,\n }\n : null,\n };\n\n lines.push(\"\");\n lines.push(\"```json\");\n lines.push(JSON.stringify(payload, null, 2));\n lines.push(\"```\");\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\n/**\n * Finds the greatest common divisor of an array of numbers\n */\nfunction findGCD(numbers: number[]): number {\n if (numbers.length === 0) return 0;\n if (numbers.length === 1) return numbers[0];\n\n const gcd = (a: number, b: number): number => {\n a = Math.abs(Math.round(a));\n b = Math.abs(Math.round(b));\n while (b) {\n const t = b;\n b = a % b;\n a = t;\n }\n return a;\n };\n\n return numbers.reduce((acc, n) => gcd(acc, n));\n}\n\n/**\n * Converts a StyleGuide object back to Markdown\n */\nexport function styleGuideToMarkdown(guide: StyleGuide): string {\n const lines: string[] = [];\n\n lines.push(\"# UI Style Guide\");\n lines.push(\"\");\n\n // Colors\n lines.push(\"## Colors\");\n guide.colors.forEach((color) => {\n const usage = color.usage ? ` (${color.usage})` : \"\";\n lines.push(`- **${color.name}**: ${color.value}${usage}`);\n });\n lines.push(\"\");\n\n // Typography\n lines.push(\"## Typography\");\n guide.typography.forEach((typo) => {\n const props: string[] = [];\n if (typo.fontFamily) props.push(`font-family: \"${typo.fontFamily}\"`);\n if (typo.fontSize) props.push(`font-size: ${typo.fontSize}`);\n if (typo.fontWeight) props.push(`font-weight: ${typo.fontWeight}`);\n if (typo.lineHeight) props.push(`line-height: ${typo.lineHeight}`);\n lines.push(`- **${typo.element}**: ${props.join(\", \")}`);\n });\n lines.push(\"\");\n\n // Spacing\n lines.push(\"## Spacing\");\n guide.spacing.forEach((space) => {\n lines.push(`- **${space.name}**: ${space.value}`);\n });\n lines.push(\"\");\n\n // Components\n lines.push(\"## Components\");\n guide.components.forEach((comp) => {\n lines.push(`- **${comp.name}**: ${comp.styles.join(\", \")}`);\n });\n\n return lines.join(\"\\n\");\n}\n"],"mappings":"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","names":[]}