uilint-react 0.1.32 → 0.1.33

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.
@@ -272,53 +272,25 @@ function getDataLocFromId(id) {
272
272
  }
273
273
  async function scanFileForIssues(sourceFile, store) {
274
274
  if (sourceFile.elements.length === 0) {
275
- return { issues: [], eslintIssues: [] };
275
+ return { issues: [] };
276
276
  }
277
277
  const filePath = sourceFile.path;
278
- let eslintIssues = [];
279
- let llmIssues = [];
278
+ let issues = [];
280
279
  if (store.wsConnected && store.wsConnection) {
281
280
  try {
282
- eslintIssues = await store.requestFileLint(filePath);
281
+ issues = await store.requestFileLint(filePath);
282
+ console.log("[UILint] ESLint issues:", issues);
283
283
  } catch (err) {
284
- console.warn("[UILint] WebSocket lint failed, will use HTTP:", err);
284
+ console.warn("[UILint] WebSocket lint failed:", err);
285
+ return { issues: [], error: true };
285
286
  }
287
+ } else {
288
+ console.warn("[UILint] WebSocket not connected");
289
+ return { issues: [], error: true };
286
290
  }
287
- try {
288
- const sourceResponse = await fetch(
289
- `/api/.uilint/source?path=${encodeURIComponent(filePath)}`
290
- );
291
- if (!sourceResponse.ok) {
292
- return { issues: [], eslintIssues, error: true };
293
- }
294
- const sourceData = await sourceResponse.json();
295
- const dataLocs = [];
296
- for (const el of sourceFile.elements) {
297
- const dataLoc = getDataLocFromId(el.id);
298
- if (dataLoc) {
299
- dataLocs.push(dataLoc);
300
- }
301
- }
302
- const analyzeResponse = await fetch("/api/.uilint/analyze", {
303
- method: "POST",
304
- headers: { "Content-Type": "application/json" },
305
- body: JSON.stringify({
306
- sourceCode: sourceData.content,
307
- filePath: sourceData.relativePath || filePath,
308
- dataLocs
309
- })
310
- });
311
- if (!analyzeResponse.ok) {
312
- return { issues: [], eslintIssues, error: true };
313
- }
314
- const result = await analyzeResponse.json();
315
- llmIssues = result.issues || [];
316
- } catch {
317
- return { issues: [], eslintIssues, error: true };
318
- }
319
- return { issues: llmIssues, eslintIssues };
291
+ return { issues };
320
292
  }
321
- function distributeIssuesToElements(issues, eslintIssues, elements, updateElementIssue, hasError) {
293
+ function distributeIssuesToElements(issues, elements, updateElementIssue, hasError) {
322
294
  const dataLocToElementId = /* @__PURE__ */ new Map();
323
295
  for (const el of elements) {
324
296
  const dataLoc = getDataLocFromId(el.id);
@@ -337,24 +309,11 @@ function distributeIssuesToElements(issues, eslintIssues, elements, updateElemen
337
309
  }
338
310
  }
339
311
  }
340
- const eslintByElement = /* @__PURE__ */ new Map();
341
- for (const issue of eslintIssues) {
342
- if (issue.dataLoc) {
343
- const elementId = dataLocToElementId.get(issue.dataLoc);
344
- if (elementId) {
345
- const existing = eslintByElement.get(elementId) || [];
346
- existing.push(issue);
347
- eslintByElement.set(elementId, existing);
348
- }
349
- }
350
- }
351
312
  for (const el of elements) {
352
313
  const elementIssues = issuesByElement.get(el.id) || [];
353
- const elementEslintIssues = eslintByElement.get(el.id) || [];
354
314
  updateElementIssue(el.id, {
355
315
  elementId: el.id,
356
316
  issues: elementIssues,
357
- eslintIssues: elementEslintIssues,
358
317
  status: hasError ? "error" : "complete"
359
318
  });
360
319
  }
@@ -363,6 +322,15 @@ var DEFAULT_WS_URL = "ws://localhost:9234";
363
322
  var MAX_RECONNECT_ATTEMPTS = 5;
364
323
  var RECONNECT_BASE_DELAY = 1e3;
365
324
  var pendingRequests = /* @__PURE__ */ new Map();
325
+ var WS_REQUEST_TIMEOUT_MS = 12e4;
326
+ function makeRequestId() {
327
+ try {
328
+ const c = globalThis.crypto;
329
+ if (c?.randomUUID) return c.randomUUID();
330
+ } catch {
331
+ }
332
+ return `req_${Date.now()}_${Math.random().toString(16).slice(2)}`;
333
+ }
366
334
  var useUILintStore = create()((set, get) => ({
367
335
  // ============ Settings ============
368
336
  settings: DEFAULT_SETTINGS,
@@ -389,31 +357,6 @@ var useUILintStore = create()((set, get) => ({
389
357
  // ============ Inspection ============
390
358
  inspectedElement: null,
391
359
  setInspectedElement: (el) => set({ inspectedElement: el }),
392
- // ============ Manual Scan (InspectionPanel) ============
393
- manualScanCache: /* @__PURE__ */ new Map(),
394
- upsertManualScan: (key, patch) => set((state) => {
395
- const next = new Map(state.manualScanCache);
396
- const existing = next.get(key);
397
- const base = existing ?? {
398
- key,
399
- status: "idle",
400
- issues: [],
401
- updatedAt: Date.now()
402
- };
403
- next.set(key, {
404
- ...base,
405
- ...patch,
406
- key,
407
- updatedAt: Date.now()
408
- });
409
- return { manualScanCache: next };
410
- }),
411
- clearManualScan: (key) => set((state) => {
412
- if (!state.manualScanCache.has(key)) return state;
413
- const next = new Map(state.manualScanCache);
414
- next.delete(key);
415
- return { manualScanCache: next };
416
- }),
417
360
  // ============ Auto-Scan ============
418
361
  autoScanState: DEFAULT_AUTO_SCAN_STATE,
419
362
  elementIssuesCache: /* @__PURE__ */ new Map(),
@@ -519,14 +462,16 @@ var useUILintStore = create()((set, get) => ({
519
462
  });
520
463
  }
521
464
  await new Promise((resolve) => requestAnimationFrame(resolve));
522
- const { issues, eslintIssues, error } = await scanFileForIssues(sourceFile, get());
465
+ const { issues, error } = await scanFileForIssues(sourceFile, get());
523
466
  distributeIssuesToElements(
524
467
  issues,
525
- eslintIssues,
526
468
  sourceFile.elements,
527
469
  get().updateElementIssue,
528
470
  error ?? false
529
471
  );
472
+ if (get().wsConnected && get().wsConnection) {
473
+ get().subscribeToFile(sourceFile.path);
474
+ }
530
475
  processedElements += sourceFile.elements.length;
531
476
  await new Promise((resolve) => requestAnimationFrame(resolve));
532
477
  }
@@ -546,6 +491,8 @@ var useUILintStore = create()((set, get) => ({
546
491
  wsReconnectAttempts: 0,
547
492
  eslintIssuesCache: /* @__PURE__ */ new Map(),
548
493
  wsProgressPhase: /* @__PURE__ */ new Map(),
494
+ wsLastActivity: null,
495
+ wsRecentResults: [],
549
496
  connectWebSocket: (url) => {
550
497
  const targetUrl = url || get().wsUrl;
551
498
  const existing = get().wsConnection;
@@ -572,7 +519,9 @@ var useUILintStore = create()((set, get) => ({
572
519
  const attempts = get().wsReconnectAttempts;
573
520
  if (attempts < MAX_RECONNECT_ATTEMPTS) {
574
521
  const delay = RECONNECT_BASE_DELAY * Math.pow(2, attempts);
575
- console.log(`[UILint] Reconnecting in ${delay}ms (attempt ${attempts + 1})`);
522
+ console.log(
523
+ `[UILint] Reconnecting in ${delay}ms (attempt ${attempts + 1})`
524
+ );
576
525
  setTimeout(() => {
577
526
  set({ wsReconnectAttempts: attempts + 1 });
578
527
  get()._reconnectWebSocket();
@@ -599,13 +548,18 @@ var useUILintStore = create()((set, get) => ({
599
548
  const ws = get().wsConnection;
600
549
  if (ws) {
601
550
  ws.close();
602
- set({ wsConnection: null, wsConnected: false, wsReconnectAttempts: MAX_RECONNECT_ATTEMPTS });
551
+ set({
552
+ wsConnection: null,
553
+ wsConnected: false,
554
+ wsReconnectAttempts: MAX_RECONNECT_ATTEMPTS
555
+ });
603
556
  }
604
557
  },
605
558
  requestFileLint: async (filePath) => {
606
559
  const { wsConnection, wsConnected, eslintIssuesCache } = get();
607
560
  const cached = eslintIssuesCache.get(filePath);
608
561
  if (cached) {
562
+ console.log("[UILint] using cached issues for", filePath);
609
563
  return cached;
610
564
  }
611
565
  if (!wsConnected || !wsConnection) {
@@ -613,16 +567,20 @@ var useUILintStore = create()((set, get) => ({
613
567
  return [];
614
568
  }
615
569
  return new Promise((resolve, reject) => {
616
- const requestKey = `file:${filePath}`;
617
- pendingRequests.set(requestKey, { resolve, reject });
618
- const message = { type: "lint:file", filePath };
570
+ const requestId = makeRequestId();
571
+ pendingRequests.set(requestId, { resolve, reject });
572
+ const message = {
573
+ type: "lint:file",
574
+ filePath,
575
+ requestId
576
+ };
619
577
  wsConnection.send(JSON.stringify(message));
620
578
  setTimeout(() => {
621
- if (pendingRequests.has(requestKey)) {
622
- pendingRequests.delete(requestKey);
579
+ if (pendingRequests.has(requestId)) {
580
+ pendingRequests.delete(requestId);
623
581
  reject(new Error("Request timed out"));
624
582
  }
625
- }, 3e4);
583
+ }, WS_REQUEST_TIMEOUT_MS);
626
584
  });
627
585
  },
628
586
  requestElementLint: async (filePath, dataLoc) => {
@@ -632,16 +590,21 @@ var useUILintStore = create()((set, get) => ({
632
590
  return [];
633
591
  }
634
592
  return new Promise((resolve, reject) => {
635
- const requestKey = `element:${filePath}:${dataLoc}`;
636
- pendingRequests.set(requestKey, { resolve, reject });
637
- const message = { type: "lint:element", filePath, dataLoc };
593
+ const requestId = makeRequestId();
594
+ pendingRequests.set(requestId, { resolve, reject });
595
+ const message = {
596
+ type: "lint:element",
597
+ filePath,
598
+ dataLoc,
599
+ requestId
600
+ };
638
601
  wsConnection.send(JSON.stringify(message));
639
602
  setTimeout(() => {
640
- if (pendingRequests.has(requestKey)) {
641
- pendingRequests.delete(requestKey);
603
+ if (pendingRequests.has(requestId)) {
604
+ pendingRequests.delete(requestId);
642
605
  reject(new Error("Request timed out"));
643
606
  }
644
- }, 3e4);
607
+ }, WS_REQUEST_TIMEOUT_MS);
645
608
  });
646
609
  },
647
610
  subscribeToFile: (filePath) => {
@@ -662,36 +625,59 @@ var useUILintStore = create()((set, get) => ({
662
625
  set({ eslintIssuesCache: /* @__PURE__ */ new Map() });
663
626
  }
664
627
  if (wsConnected && wsConnection) {
665
- const message = { type: "cache:invalidate", filePath };
628
+ const message = {
629
+ type: "cache:invalidate",
630
+ filePath
631
+ };
666
632
  wsConnection.send(JSON.stringify(message));
667
633
  }
668
634
  },
669
635
  _handleWsMessage: (data) => {
670
636
  switch (data.type) {
671
637
  case "lint:result": {
672
- const { filePath, issues } = data;
673
- set((state) => {
674
- const next = new Map(state.eslintIssuesCache);
638
+ const { filePath, issues, requestId } = data;
639
+ set((state2) => {
640
+ const next = new Map(state2.eslintIssuesCache);
675
641
  next.set(filePath, issues);
676
642
  return { eslintIssuesCache: next };
677
643
  });
678
- set((state) => {
679
- const next = new Map(state.wsProgressPhase);
644
+ const state = get();
645
+ if (state.autoScanState.status !== "idle") {
646
+ const sourceFiles = groupBySourceFile(state.autoScanState.elements);
647
+ const sf = sourceFiles.find((s) => s.path === filePath);
648
+ if (sf) {
649
+ distributeIssuesToElements(
650
+ issues,
651
+ sf.elements,
652
+ state.updateElementIssue,
653
+ false
654
+ );
655
+ }
656
+ }
657
+ set((state2) => {
658
+ const next = new Map(state2.wsProgressPhase);
680
659
  next.delete(filePath);
681
660
  return { wsProgressPhase: next };
682
661
  });
683
- const fileKey = `file:${filePath}`;
684
- const pending = pendingRequests.get(fileKey);
685
- if (pending) {
686
- pending.resolve(issues);
687
- pendingRequests.delete(fileKey);
688
- }
689
- for (const [key, req] of pendingRequests.entries()) {
690
- if (key.startsWith(`element:${filePath}:`)) {
691
- const dataLoc = key.split(":").slice(2).join(":");
692
- const filtered = issues.filter((i) => i.dataLoc === dataLoc);
693
- req.resolve(filtered);
694
- pendingRequests.delete(key);
662
+ set((state2) => {
663
+ const next = [
664
+ { filePath, issueCount: issues.length, updatedAt: Date.now() },
665
+ ...state2.wsRecentResults.filter((r) => r.filePath !== filePath)
666
+ ].slice(0, 8);
667
+ return { wsRecentResults: next };
668
+ });
669
+ set({
670
+ wsLastActivity: {
671
+ filePath,
672
+ phase: `Done (${issues.length} issues)`,
673
+ updatedAt: Date.now()
674
+ }
675
+ });
676
+ if (requestId) {
677
+ const pending = pendingRequests.get(requestId);
678
+ if (pending) {
679
+ pending.resolve(issues);
680
+ pendingRequests.delete(requestId);
695
681
  }
696
682
  }
697
683
  break;
@@ -701,17 +687,45 @@ var useUILintStore = create()((set, get) => ({
701
687
  set((state) => {
702
688
  const next = new Map(state.wsProgressPhase);
703
689
  next.set(filePath, phase);
704
- return { wsProgressPhase: next };
690
+ return {
691
+ wsProgressPhase: next,
692
+ wsLastActivity: { filePath, phase, updatedAt: Date.now() }
693
+ };
705
694
  });
706
695
  break;
707
696
  }
708
697
  case "file:changed": {
709
698
  const { filePath } = data;
710
- set((state) => {
711
- const next = new Map(state.eslintIssuesCache);
699
+ set((state2) => {
700
+ const next = new Map(state2.eslintIssuesCache);
712
701
  next.delete(filePath);
713
702
  return { eslintIssuesCache: next };
714
703
  });
704
+ const state = get();
705
+ if (state.autoScanState.status !== "idle") {
706
+ const sourceFiles = groupBySourceFile(state.autoScanState.elements);
707
+ const sf = sourceFiles.find((s) => s.path === filePath);
708
+ if (sf) {
709
+ for (const el of sf.elements) {
710
+ const existing = state.elementIssuesCache.get(el.id);
711
+ state.updateElementIssue(el.id, {
712
+ elementId: el.id,
713
+ issues: existing?.issues || [],
714
+ status: "scanning"
715
+ });
716
+ }
717
+ state.requestFileLint(filePath).catch(() => {
718
+ for (const el of sf.elements) {
719
+ const existing = state.elementIssuesCache.get(el.id);
720
+ state.updateElementIssue(el.id, {
721
+ elementId: el.id,
722
+ issues: existing?.issues || [],
723
+ status: "error"
724
+ });
725
+ }
726
+ });
727
+ }
728
+ }
715
729
  break;
716
730
  }
717
731
  }
@@ -788,6 +802,12 @@ function UILintProvider({
788
802
  const pauseAutoScan = useUILintStore((s) => s.pauseAutoScan);
789
803
  const resumeAutoScan = useUILintStore((s) => s.resumeAutoScan);
790
804
  const stopAutoScan = useUILintStore((s) => s.stopAutoScan);
805
+ const connectWebSocket = useUILintStore(
806
+ (s) => s.connectWebSocket
807
+ );
808
+ const disconnectWebSocket = useUILintStore(
809
+ (s) => s.disconnectWebSocket
810
+ );
791
811
  const effectiveLocatorTarget = useEffectiveLocatorTarget();
792
812
  const getLocatorTargetFromElement = useCallback(
793
813
  (element) => {
@@ -957,6 +977,14 @@ function UILintProvider({
957
977
  useEffect(() => {
958
978
  setIsMounted(true);
959
979
  }, []);
980
+ useEffect(() => {
981
+ if (!isBrowser() || !enabled) return;
982
+ if (!isMounted) return;
983
+ connectWebSocket();
984
+ return () => {
985
+ disconnectWebSocket();
986
+ };
987
+ }, [enabled, isMounted, connectWebSocket, disconnectWebSocket]);
960
988
  const wrappedStartAutoScan = useCallback(() => {
961
989
  startAutoScan(settings.hideNodeModules);
962
990
  }, [startAutoScan, settings.hideNodeModules]);
@@ -1005,10 +1033,10 @@ function UILintUI() {
1005
1033
  const [components, setComponents] = useState(null);
1006
1034
  useEffect(() => {
1007
1035
  Promise.all([
1008
- import("./UILintToolbar-PRX3LYZD.js"),
1009
- import("./InspectionPanel-AU4SJPQN.js"),
1010
- import("./LocatorOverlay-XCNSUM34.js"),
1011
- import("./ElementBadges-IQIPOHBN.js")
1036
+ import("./UILintToolbar-WNV5RS2L.js"),
1037
+ import("./InspectionPanel-JNLWBL4D.js"),
1038
+ import("./LocatorOverlay-6SAH7LN2.js"),
1039
+ import("./ElementBadges-TBAUB3KM.js")
1012
1040
  ]).then(([toolbar, panel, locator, badges]) => {
1013
1041
  setComponents({
1014
1042
  Toolbar: toolbar.UILintToolbar,
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  useUILintContext
4
- } from "./chunk-Y44J7QO6.js";
4
+ } from "./chunk-MO4NS6EG.js";
5
5
 
6
6
  // src/components/ui-lint/LocatorOverlay.tsx
7
7
  import { useState, useEffect, useMemo } from "react";
package/dist/index.d.ts CHANGED
@@ -58,17 +58,6 @@ interface AutoScanState {
58
58
  totalElements: number;
59
59
  elements: ScannedElement[];
60
60
  }
61
- /**
62
- * A single issue found during scanning
63
- */
64
- interface ScanIssue {
65
- /** Line number in source file */
66
- line?: number;
67
- /** Issue description */
68
- message: string;
69
- /** data-loc value to match to DOM element (format: path:line:column) */
70
- dataLoc?: string;
71
- }
72
61
  /**
73
62
  * ESLint issue from WebSocket server (uilint serve)
74
63
  */
@@ -89,10 +78,8 @@ interface ESLintIssue {
89
78
  */
90
79
  interface ElementIssue {
91
80
  elementId: string;
92
- /** LLM-based issues from styleguide analysis */
93
- issues: ScanIssue[];
94
- /** ESLint rule violations from uilint-eslint */
95
- eslintIssues?: ESLintIssue[];
81
+ /** ESLint rule violations from uilint-eslint (including semantic rule) */
82
+ issues: ESLintIssue[];
96
83
  status: "pending" | "scanning" | "complete" | "error";
97
84
  }
98
85
  /**
@@ -379,43 +366,4 @@ declare function isJSDOM(): boolean;
379
366
  */
380
367
  declare function isNode(): boolean;
381
368
 
382
- /**
383
- * LLM client for browser environment
384
- * Wraps API calls to the dev server analyze route (browser environment)
385
- */
386
- type UILintScanIssue = {
387
- line?: number;
388
- message: string;
389
- dataLoc?: string;
390
- };
391
- interface LLMClientOptions {
392
- apiEndpoint?: string;
393
- model?: string;
394
- }
395
- /**
396
- * Client for communicating with the LLM via API route (browser environment)
397
- */
398
- declare class LLMClient {
399
- private apiEndpoint;
400
- private model;
401
- constructor(options?: LLMClientOptions);
402
- /**
403
- * Analyze a source file/snippet and return issues.
404
- *
405
- * NOTE: This matches the (simplified) `/api/.uilint/analyze` route which is
406
- * now source-only (no styleSummary / styleguide generation).
407
- */
408
- analyzeSource(input: {
409
- sourceCode: string;
410
- filePath?: string;
411
- styleGuide?: string | null;
412
- componentName?: string;
413
- componentLine?: number;
414
- includeChildren?: boolean;
415
- dataLocs?: string[];
416
- }): Promise<{
417
- issues: UILintScanIssue[];
418
- }>;
419
- }
420
-
421
- export { type CachedSource, type ComponentInfo, ConsistencyHighlighter, DATA_UILINT_ID, DEFAULT_SETTINGS, FILE_COLORS, type InspectedElement, InspectionPanel, LLMClient, LocatorOverlay, type LocatorTarget, type ScannedElement, type SourceApiResponse, type SourceFile, type SourceLocation, type UILintContextValue, UILintProvider, type UILintProviderProps, type UILintSettings, UILintToolbar, buildEditorUrl, cleanupDataAttributes, cleanupDataElements, clearSourceCache, createSnapshot, fetchSource, fetchSourceWithContext, getCachedSource, getComponentStack, getDebugOwner, getDebugSource, getDisplayName, getElementById, getElementBySnapshotId, getFiberFromElement, groupBySourceFile, isBrowser, isJSDOM, isNode, isNodeModulesPath, prefetchSources, scanDOM, scanDOMForSources, updateElementRects, useUILintContext };
369
+ export { type CachedSource, type ComponentInfo, ConsistencyHighlighter, DATA_UILINT_ID, DEFAULT_SETTINGS, FILE_COLORS, type InspectedElement, InspectionPanel, LocatorOverlay, type LocatorTarget, type ScannedElement, type SourceApiResponse, type SourceFile, type SourceLocation, type UILintContextValue, UILintProvider, type UILintProviderProps, type UILintSettings, UILintToolbar, buildEditorUrl, cleanupDataAttributes, cleanupDataElements, clearSourceCache, createSnapshot, fetchSource, fetchSourceWithContext, getCachedSource, getComponentStack, getDebugOwner, getDebugSource, getDisplayName, getElementById, getElementBySnapshotId, getFiberFromElement, groupBySourceFile, isBrowser, isJSDOM, isNode, isNodeModulesPath, prefetchSources, scanDOM, scanDOMForSources, updateElementRects, useUILintContext };
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  "use client";
2
2
  import {
3
3
  UILintToolbar
4
- } from "./chunk-K7SUEWNV.js";
4
+ } from "./chunk-HTNIKCEM.js";
5
5
  import {
6
6
  InspectionPanel,
7
7
  clearSourceCache,
@@ -9,10 +9,10 @@ import {
9
9
  fetchSourceWithContext,
10
10
  getCachedSource,
11
11
  prefetchSources
12
- } from "./chunk-NY7Q5DSG.js";
12
+ } from "./chunk-JBBUE3Y5.js";
13
13
  import {
14
14
  LocatorOverlay
15
- } from "./chunk-VBU72FKU.js";
15
+ } from "./chunk-Z6PWYQGW.js";
16
16
  import {
17
17
  DATA_UILINT_ID,
18
18
  DEFAULT_SETTINGS,
@@ -31,7 +31,7 @@ import {
31
31
  scanDOMForSources,
32
32
  updateElementRects,
33
33
  useUILintContext
34
- } from "./chunk-Y44J7QO6.js";
34
+ } from "./chunk-MO4NS6EG.js";
35
35
 
36
36
  // src/consistency/snapshot.ts
37
37
  var DATA_ELEMENTS_ATTR = "data-elements";
@@ -441,52 +441,6 @@ import {
441
441
  serializeStyles as serializeStyles2,
442
442
  createStyleSummary as createStyleSummary2
443
443
  } from "uilint-core";
444
-
445
- // src/analyzer/llm-client.ts
446
- import { UILINT_DEFAULT_OLLAMA_MODEL } from "uilint-core";
447
- var DEFAULT_API_ENDPOINT = "/api/.uilint/analyze";
448
- var LLMClient = class {
449
- apiEndpoint;
450
- model;
451
- constructor(options = {}) {
452
- this.apiEndpoint = options.apiEndpoint || DEFAULT_API_ENDPOINT;
453
- this.model = options.model || UILINT_DEFAULT_OLLAMA_MODEL;
454
- }
455
- /**
456
- * Analyze a source file/snippet and return issues.
457
- *
458
- * NOTE: This matches the (simplified) `/api/.uilint/analyze` route which is
459
- * now source-only (no styleSummary / styleguide generation).
460
- */
461
- async analyzeSource(input) {
462
- try {
463
- const response = await fetch(this.apiEndpoint, {
464
- method: "POST",
465
- headers: { "Content-Type": "application/json" },
466
- body: JSON.stringify({
467
- sourceCode: input.sourceCode,
468
- filePath: input.filePath,
469
- styleGuide: input.styleGuide ?? void 0,
470
- componentName: input.componentName,
471
- componentLine: input.componentLine,
472
- includeChildren: input.includeChildren,
473
- dataLocs: input.dataLocs,
474
- model: this.model
475
- })
476
- });
477
- if (!response.ok) {
478
- throw new Error(`API request failed: ${response.status}`);
479
- }
480
- const data = await response.json();
481
- return { issues: data.issues || [] };
482
- } catch (error) {
483
- console.error("[UILint] Analysis failed:", error);
484
- return { issues: [] };
485
- }
486
- }
487
- };
488
-
489
- // src/index.ts
490
444
  import { parseStyleGuide } from "uilint-core";
491
445
  import { generateStyleGuideFromStyles } from "uilint-core";
492
446
  import { createEmptyStyleGuide, mergeStyleGuides } from "uilint-core";
@@ -496,7 +450,6 @@ export {
496
450
  DEFAULT_SETTINGS,
497
451
  FILE_COLORS,
498
452
  InspectionPanel,
499
- LLMClient,
500
453
  LocatorOverlay,
501
454
  UILintProvider,
502
455
  UILintToolbar,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uilint-react",
3
- "version": "0.1.32",
3
+ "version": "0.1.33",
4
4
  "description": "React component for AI-powered UI consistency checking",
5
5
  "author": "Peter Suggate",
6
6
  "repository": {
@@ -34,7 +34,7 @@
34
34
  "node": ">=20.0.0"
35
35
  },
36
36
  "dependencies": {
37
- "uilint-core": "^0.1.32",
37
+ "uilint-core": "^0.1.33",
38
38
  "zustand": "^5.0.5"
39
39
  },
40
40
  "peerDependencies": {