uilint-semantic 0.2.142 → 0.2.144
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
|
@@ -2,32 +2,26 @@
|
|
|
2
2
|
import { pluginRegistry } from "uilint-core";
|
|
3
3
|
|
|
4
4
|
// src/plugin/state.ts
|
|
5
|
+
import { createOperationInitialState, createOperationComputed } from "uilint-core";
|
|
5
6
|
var styleguideInitialState = {
|
|
6
7
|
styleguideLoaded: false,
|
|
7
8
|
styleguidePath: null,
|
|
8
9
|
modelAvailable: false,
|
|
9
10
|
modelName: "qwen3-vl:8b-instruct",
|
|
10
|
-
|
|
11
|
-
analysisProgress: null,
|
|
12
|
-
lastAnalysisError: null,
|
|
13
|
-
analyzedFileCount: 0,
|
|
14
|
-
issueCount: 0
|
|
11
|
+
analysis: createOperationInitialState()
|
|
15
12
|
};
|
|
13
|
+
var opComputed = createOperationComputed((s) => s.analysis);
|
|
16
14
|
var styleguideStateDefinition = {
|
|
17
15
|
initialState: styleguideInitialState,
|
|
18
16
|
computed: {
|
|
19
17
|
/** Whether the plugin is ready to analyze (styleguide loaded + model available) */
|
|
20
18
|
isReady: (state) => state.styleguideLoaded && state.modelAvailable,
|
|
21
19
|
/** Whether analysis is currently running */
|
|
22
|
-
isAnalyzing:
|
|
20
|
+
isAnalyzing: opComputed.isActive,
|
|
23
21
|
/** Whether there was an error */
|
|
24
|
-
hasError:
|
|
22
|
+
hasError: opComputed.hasError,
|
|
25
23
|
/** Progress percentage (0-100) */
|
|
26
|
-
progressPercent:
|
|
27
|
-
if (!state.analysisProgress) return 0;
|
|
28
|
-
if (state.analysisProgress.total === 0) return 0;
|
|
29
|
-
return Math.round(state.analysisProgress.current / state.analysisProgress.total * 100);
|
|
30
|
-
}
|
|
24
|
+
progressPercent: opComputed.progressPercent
|
|
31
25
|
},
|
|
32
26
|
persist: {
|
|
33
27
|
key: "uilint-styleguide",
|
|
@@ -36,8 +30,18 @@ var styleguideStateDefinition = {
|
|
|
36
30
|
};
|
|
37
31
|
|
|
38
32
|
// src/plugin/actions.ts
|
|
33
|
+
import { createOperationActions } from "uilint-core";
|
|
39
34
|
var h = (fn) => fn;
|
|
35
|
+
var analysisActions = createOperationActions(
|
|
36
|
+
"analysis",
|
|
37
|
+
{
|
|
38
|
+
getOp: (s) => s.analysis,
|
|
39
|
+
setOp: (op) => ({ analysis: op })
|
|
40
|
+
}
|
|
41
|
+
);
|
|
40
42
|
var styleguideActionHandlers = {
|
|
43
|
+
// Spread in generated lifecycle handlers
|
|
44
|
+
...analysisActions,
|
|
41
45
|
/**
|
|
42
46
|
* Check styleguide and model status
|
|
43
47
|
*/
|
|
@@ -55,37 +59,6 @@ var styleguideActionHandlers = {
|
|
|
55
59
|
modelName: payload.modelName
|
|
56
60
|
});
|
|
57
61
|
}),
|
|
58
|
-
/**
|
|
59
|
-
* Handle analysis progress
|
|
60
|
-
*/
|
|
61
|
-
"handle-analysis-progress": h((ctx, payload) => {
|
|
62
|
-
ctx.setState({
|
|
63
|
-
analysisStatus: "analyzing",
|
|
64
|
-
analysisProgress: payload
|
|
65
|
-
});
|
|
66
|
-
}),
|
|
67
|
-
/**
|
|
68
|
-
* Handle analysis complete
|
|
69
|
-
*/
|
|
70
|
-
"handle-analysis-complete": h((ctx, payload) => {
|
|
71
|
-
ctx.setState({
|
|
72
|
-
analysisStatus: "complete",
|
|
73
|
-
analysisProgress: null,
|
|
74
|
-
analyzedFileCount: payload.analyzedFileCount,
|
|
75
|
-
issueCount: payload.issueCount,
|
|
76
|
-
lastAnalysisError: null
|
|
77
|
-
});
|
|
78
|
-
}),
|
|
79
|
-
/**
|
|
80
|
-
* Handle analysis error
|
|
81
|
-
*/
|
|
82
|
-
"handle-analysis-error": h((ctx, payload) => {
|
|
83
|
-
ctx.setState({
|
|
84
|
-
analysisStatus: "error",
|
|
85
|
-
analysisProgress: null,
|
|
86
|
-
lastAnalysisError: payload.error
|
|
87
|
-
});
|
|
88
|
-
}),
|
|
89
62
|
/**
|
|
90
63
|
* Reload styleguide file from disk
|
|
91
64
|
*/
|
|
@@ -179,23 +152,23 @@ var styleguideStatusPanelDefinition = {
|
|
|
179
152
|
// Analysis progress (when analyzing)
|
|
180
153
|
{
|
|
181
154
|
type: "conditional",
|
|
182
|
-
condition: { expression: "
|
|
155
|
+
condition: { expression: "analysis.status === 'active'" },
|
|
183
156
|
then: [
|
|
184
157
|
{
|
|
185
158
|
type: "progress",
|
|
186
159
|
value: { binding: "progressPercent" },
|
|
187
|
-
label: { binding: "
|
|
160
|
+
label: { binding: "analysis.progress.message" }
|
|
188
161
|
}
|
|
189
162
|
]
|
|
190
163
|
},
|
|
191
164
|
// Error (when error)
|
|
192
165
|
{
|
|
193
166
|
type: "conditional",
|
|
194
|
-
condition: { expression: "
|
|
167
|
+
condition: { expression: "analysis.status === 'error'" },
|
|
195
168
|
then: [
|
|
196
169
|
{
|
|
197
170
|
type: "text",
|
|
198
|
-
content: { binding: "
|
|
171
|
+
content: { binding: "analysis.lastError" },
|
|
199
172
|
variant: "error"
|
|
200
173
|
}
|
|
201
174
|
]
|
|
@@ -203,11 +176,11 @@ var styleguideStatusPanelDefinition = {
|
|
|
203
176
|
// Stats (when analysis complete)
|
|
204
177
|
{
|
|
205
178
|
type: "conditional",
|
|
206
|
-
condition: { expression: "
|
|
179
|
+
condition: { expression: "analysis.status === 'complete'" },
|
|
207
180
|
then: [
|
|
208
181
|
{
|
|
209
182
|
type: "text",
|
|
210
|
-
content: { binding: "analyzedFileCount" },
|
|
183
|
+
content: { binding: "analysis.stats.analyzedFileCount" },
|
|
211
184
|
variant: "body"
|
|
212
185
|
}
|
|
213
186
|
]
|
|
@@ -319,9 +292,31 @@ var styleguideRuleDefinitions = [
|
|
|
319
292
|
];
|
|
320
293
|
|
|
321
294
|
// src/plugin/messages.ts
|
|
295
|
+
import { createOperationMessageHandlers } from "uilint-core";
|
|
322
296
|
var styleguideMessageHandlers = {
|
|
297
|
+
...createOperationMessageHandlers({
|
|
298
|
+
actionPrefix: "analysis",
|
|
299
|
+
progressMessage: "styleguide:analysis:progress",
|
|
300
|
+
completeMessage: "styleguide:analysis:complete",
|
|
301
|
+
errorMessage: "styleguide:analysis:error",
|
|
302
|
+
extractProgress: (msg) => {
|
|
303
|
+
const m = msg;
|
|
304
|
+
return {
|
|
305
|
+
current: m.current,
|
|
306
|
+
total: m.total,
|
|
307
|
+
message: m.filePath
|
|
308
|
+
};
|
|
309
|
+
},
|
|
310
|
+
extractStats: (msg) => {
|
|
311
|
+
const m = msg;
|
|
312
|
+
return {
|
|
313
|
+
analyzedFileCount: m.analyzedFileCount,
|
|
314
|
+
issueCount: m.issueCount
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
}),
|
|
323
318
|
/**
|
|
324
|
-
* Handle styleguide status response
|
|
319
|
+
* Handle styleguide status response (plugin-specific, not operation lifecycle)
|
|
325
320
|
*/
|
|
326
321
|
"styleguide:status": (ctx, message) => {
|
|
327
322
|
const msg = message;
|
|
@@ -331,34 +326,6 @@ var styleguideMessageHandlers = {
|
|
|
331
326
|
modelAvailable: msg.modelAvailable,
|
|
332
327
|
modelName: msg.modelName
|
|
333
328
|
});
|
|
334
|
-
},
|
|
335
|
-
/**
|
|
336
|
-
* Handle analysis progress
|
|
337
|
-
*/
|
|
338
|
-
"styleguide:analysis:progress": (ctx, message) => {
|
|
339
|
-
const msg = message;
|
|
340
|
-
ctx.dispatch("handle-analysis-progress", {
|
|
341
|
-
filePath: msg.filePath,
|
|
342
|
-
current: msg.current,
|
|
343
|
-
total: msg.total
|
|
344
|
-
});
|
|
345
|
-
},
|
|
346
|
-
/**
|
|
347
|
-
* Handle analysis complete
|
|
348
|
-
*/
|
|
349
|
-
"styleguide:analysis:complete": (ctx, message) => {
|
|
350
|
-
const msg = message;
|
|
351
|
-
ctx.dispatch("handle-analysis-complete", {
|
|
352
|
-
analyzedFileCount: msg.analyzedFileCount,
|
|
353
|
-
issueCount: msg.issueCount
|
|
354
|
-
});
|
|
355
|
-
},
|
|
356
|
-
/**
|
|
357
|
-
* Handle analysis error
|
|
358
|
-
*/
|
|
359
|
-
"styleguide:analysis:error": (ctx, message) => {
|
|
360
|
-
const msg = message;
|
|
361
|
-
ctx.dispatch("handle-analysis-error", { error: msg.error });
|
|
362
329
|
}
|
|
363
330
|
};
|
|
364
331
|
|
|
@@ -403,4 +370,4 @@ export {
|
|
|
403
370
|
styleguidePlugin,
|
|
404
371
|
plugin_default
|
|
405
372
|
};
|
|
406
|
-
//# sourceMappingURL=chunk-
|
|
373
|
+
//# sourceMappingURL=chunk-N4GIABM5.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/plugin/index.ts","../src/plugin/state.ts","../src/plugin/actions.ts","../src/plugin/commands.ts","../src/plugin/panels.ts","../src/plugin/rules.ts","../src/plugin/messages.ts"],"sourcesContent":["/**\n * Styleguide Plugin Definition\n *\n * Complete plugin export - NO REACT.\n * This is the main plugin definition that gets registered with pluginRegistry.\n */\n\nimport type { PluginWithHandlers, IssueContribution } from \"uilint-core\";\nimport { pluginRegistry } from \"uilint-core\";\n\nimport { styleguideStateDefinition, type StyleguideState } from \"./state.js\";\nimport { styleguideActionHandlers } from \"./actions.js\";\nimport { styleguideCommands } from \"./commands.js\";\nimport { styleguidePanelDefinitions } from \"./panels.js\";\nimport { styleguideRuleDefinitions } from \"./rules.js\";\nimport { styleguideMessageHandlers } from \"./messages.js\";\n\n/**\n * Styleguide plugin definition\n *\n * Contains everything needed for styleguide checking EXCEPT React components.\n * The host (uilint-react) imports this and renders the appropriate UI.\n */\nexport const styleguidePlugin: PluginWithHandlers<StyleguideState> = {\n // === Metadata ===\n id: \"styleguide\",\n name: \"Styleguide Checking\",\n version: \"1.0.0\",\n description: \"LLM-powered styleguide enforcement\",\n icon: \"book\",\n\n // === State ===\n state: styleguideStateDefinition,\n actions: styleguideActionHandlers,\n\n // === UI Contributions (Declarative) ===\n commands: styleguideCommands,\n panels: styleguidePanelDefinitions,\n\n // === Rules ===\n rules: styleguideRuleDefinitions,\n handlesRuleCategories: [\"styleguide\"],\n\n // === WebSocket ===\n messageHandlers: styleguideMessageHandlers,\n\n // === Issue Aggregation ===\n // Styleguide issues are reported by the semantic ESLint rule.\n // They don't come from plugin state, so we return empty.\n getIssues: (_state: StyleguideState): IssueContribution => {\n return { pluginId: \"styleguide\", issues: new Map() };\n },\n\n // === Browser Actions ===\n browserActions: [],\n\n // === Lifecycle ===\n onLoad: (ctx) => {\n // Check styleguide + model availability on load if connected\n if (ctx.websocket.isConnected) {\n ctx.websocket.send({ type: \"styleguide:check\" });\n }\n },\n};\n\n// Auto-register with plugin registry on import\npluginRegistry.register(styleguidePlugin);\n\n// Export types for host apps\nexport type { StyleguideState } from \"./state.js\";\n\nexport default styleguidePlugin;\n","/**\n * Styleguide Plugin State\n *\n * State shape and initial state for the styleguide checking plugin.\n * No React - pure TypeScript.\n */\n\nimport type { StateDefinition, OperationState } from \"uilint-core\";\nimport { createOperationInitialState, createOperationComputed } from \"uilint-core\";\n\n/**\n * Analysis completion statistics\n */\nexport interface AnalysisStats {\n analyzedFileCount: number;\n issueCount: number;\n}\n\n/**\n * Styleguide plugin state shape\n */\nexport interface StyleguideState {\n // === Styleguide Loading ===\n /** Whether a styleguide file was found */\n styleguideLoaded: boolean;\n /** Resolved path to the styleguide file */\n styleguidePath: string | null;\n\n // === Model Availability ===\n /** Whether the required Ollama model is available */\n modelAvailable: boolean;\n /** Name of the configured model */\n modelName: string;\n\n // === Analysis Operation ===\n /** Analysis operation lifecycle state */\n analysis: OperationState<AnalysisStats>;\n}\n\n/**\n * Initial state for the styleguide plugin\n */\nexport const styleguideInitialState: StyleguideState = {\n styleguideLoaded: false,\n styleguidePath: null,\n modelAvailable: false,\n modelName: \"qwen3-vl:8b-instruct\",\n analysis: createOperationInitialState<AnalysisStats>(),\n};\n\nconst opComputed = createOperationComputed<StyleguideState>((s) => s.analysis);\n\n/**\n * State definition for the plugin system\n */\nexport const styleguideStateDefinition: StateDefinition<StyleguideState> = {\n initialState: styleguideInitialState,\n\n computed: {\n /** Whether the plugin is ready to analyze (styleguide loaded + model available) */\n isReady: (state) => state.styleguideLoaded && state.modelAvailable,\n\n /** Whether analysis is currently running */\n isAnalyzing: opComputed.isActive,\n\n /** Whether there was an error */\n hasError: opComputed.hasError,\n\n /** Progress percentage (0-100) */\n progressPercent: opComputed.progressPercent,\n },\n\n persist: {\n key: \"uilint-styleguide\",\n include: [],\n },\n};\n","/**\n * Styleguide Plugin Action Handlers\n *\n * Plain functions that handle plugin actions.\n * No React - uses PluginContext for state management.\n */\n\nimport type { ActionHandlers, PluginContext } from \"uilint-core\";\nimport { createOperationActions } from \"uilint-core\";\nimport type { StyleguideState, AnalysisStats } from \"./state.js\";\n\n// Helper type for cleaner action handler definitions\ntype Handler<TPayload = void> = (\n ctx: PluginContext<StyleguideState>,\n payload: TPayload\n) => void | Promise<void>;\n\n// Cast helper for proper typing\nconst h = <TPayload = void>(fn: Handler<TPayload>): Handler<unknown> =>\n fn as Handler<unknown>;\n\n/**\n * Generated lifecycle action handlers for the analysis operation.\n *\n * Provides: handle-analysis-start, handle-analysis-progress,\n * handle-analysis-complete, handle-analysis-error\n */\nconst analysisActions = createOperationActions<StyleguideState, AnalysisStats>(\n \"analysis\",\n {\n getOp: (s) => s.analysis,\n setOp: (op) => ({ analysis: op }),\n }\n);\n\n/**\n * Action handlers for the styleguide plugin\n */\nexport const styleguideActionHandlers: ActionHandlers<StyleguideState> = {\n // Spread in generated lifecycle handlers\n ...analysisActions,\n\n /**\n * Check styleguide and model status\n */\n \"check-styleguide-status\": h((ctx) => {\n ctx.websocket.send({ type: \"styleguide:check\" });\n }),\n\n /**\n * Handle styleguide status response from server\n */\n \"handle-styleguide-status\": h<{\n styleguideLoaded: boolean;\n styleguidePath: string | null;\n modelAvailable: boolean;\n modelName: string;\n }>((ctx, payload) => {\n ctx.setState({\n styleguideLoaded: payload.styleguideLoaded,\n styleguidePath: payload.styleguidePath,\n modelAvailable: payload.modelAvailable,\n modelName: payload.modelName,\n });\n }),\n\n /**\n * Reload styleguide file from disk\n */\n \"reload-styleguide\": h((ctx) => {\n ctx.websocket.send({ type: \"styleguide:reload\" });\n }),\n\n /**\n * Open file in editor\n */\n \"open-editor\": h<{ dataLoc: string }>((ctx, payload) => {\n ctx.openInEditor(payload.dataLoc);\n }),\n};\n","/**\n * Styleguide Plugin Commands\n *\n * Command palette commands for the styleguide plugin.\n * Declarative - no React.\n */\n\nimport type { CommandDefinition } from \"uilint-core\";\n\n/**\n * Styleguide plugin commands\n */\nexport const styleguideCommands: CommandDefinition[] = [\n {\n id: \"styleguide:check-status\",\n title: \"Check Styleguide Status\",\n keywords: [\"styleguide\", \"status\", \"check\", \"model\", \"ollama\"],\n category: \"Styleguide\",\n subtitle: \"Check if styleguide and LLM model are available\",\n icon: \"check-circle\",\n action: { type: \"check-styleguide-status\" },\n },\n {\n id: \"styleguide:reload\",\n title: \"Reload Styleguide\",\n keywords: [\"styleguide\", \"reload\", \"refresh\"],\n category: \"Styleguide\",\n subtitle: \"Reload the styleguide file from disk\",\n icon: \"refresh\",\n action: { type: \"reload-styleguide\" },\n },\n];\n","/**\n * Styleguide Plugin Panels\n *\n * Inspector panel definitions for the styleguide plugin.\n * Declarative - no React.\n */\n\nimport type { PanelDefinition } from \"uilint-core\";\n\n/**\n * Styleguide status panel\n */\nexport const styleguideStatusPanelDefinition: PanelDefinition = {\n id: \"styleguide-status\",\n title: \"Styleguide Status\",\n priority: 5,\n\n layout: [\n // Styleguide loaded status\n {\n type: \"badge\",\n variant: \"status\",\n value: {\n condition: { binding: \"styleguideLoaded\" },\n true: \"Styleguide Loaded\",\n false: \"No Styleguide\",\n },\n centered: true,\n },\n\n // Styleguide path (when loaded)\n {\n type: \"conditional\",\n condition: { binding: \"styleguideLoaded\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"styleguidePath\" },\n variant: \"caption\",\n },\n ],\n else: [\n {\n type: \"text\",\n content: \"Create a styleguide at .uilint/styleguide.md to enable LLM-powered analysis.\",\n variant: \"body\",\n },\n ],\n },\n\n { type: \"divider\", spacing: \"small\" },\n\n // Model availability\n {\n type: \"badge\",\n variant: \"status\",\n value: {\n condition: { binding: \"modelAvailable\" },\n true: \"Model Ready\",\n false: \"Model Unavailable\",\n },\n centered: true,\n },\n\n // Model name\n {\n type: \"text\",\n content: { binding: \"modelName\" },\n variant: \"caption\",\n },\n\n // Analysis progress (when analyzing)\n {\n type: \"conditional\",\n condition: { expression: \"analysis.status === 'active'\" },\n then: [\n {\n type: \"progress\",\n value: { binding: \"progressPercent\" },\n label: { binding: \"analysis.progress.message\" },\n },\n ],\n },\n\n // Error (when error)\n {\n type: \"conditional\",\n condition: { expression: \"analysis.status === 'error'\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"analysis.lastError\" },\n variant: \"error\",\n },\n ],\n },\n\n // Stats (when analysis complete)\n {\n type: \"conditional\",\n condition: { expression: \"analysis.status === 'complete'\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"analysis.stats.analyzedFileCount\" },\n variant: \"body\",\n },\n ],\n },\n\n { type: \"divider\" },\n\n // Actions\n {\n type: \"actions\",\n direction: \"column\",\n actions: [\n {\n id: \"check-status\",\n label: \"Check Status\",\n icon: \"check-circle\",\n variant: \"secondary\",\n action: { type: \"check-styleguide-status\" },\n },\n {\n id: \"reload-styleguide\",\n label: \"Reload Styleguide\",\n icon: \"refresh\",\n variant: \"secondary\",\n action: { type: \"reload-styleguide\" },\n disabled: { expression: \"!styleguideLoaded\" },\n },\n ],\n },\n ],\n};\n\n/**\n * All styleguide panel definitions\n */\nexport const styleguidePanelDefinitions: PanelDefinition[] = [\n styleguideStatusPanelDefinition,\n];\n","/**\n * Styleguide Plugin Rules\n *\n * Rule definitions for the styleguide plugin.\n * Declarative - no React.\n */\n\nimport type { RuleDefinition } from \"uilint-core\";\n\n/**\n * semantic rule definition (styleguide checking via LLM)\n */\nexport const semanticRuleDefinition: RuleDefinition = {\n id: \"semantic\",\n name: \"Semantic Analysis\",\n description: \"LLM-powered semantic UI analysis using your styleguide\",\n category: \"styleguide\",\n icon: \"brain\",\n defaultSeverity: \"warn\",\n defaultEnabled: false,\n heatmapColor: \"#8b5cf6\", // Purple\n customInspectorPanel: \"semantic-issue\",\n requirements: [\n {\n type: \"ollama\",\n description: \"Requires Ollama running locally\",\n setupHint: \"Run: ollama serve && ollama pull qwen3-vl:8b-instruct\",\n },\n {\n type: \"styleguide\",\n description: \"Requires a styleguide file\",\n setupHint: \"Run: uilint genstyleguide\",\n },\n ],\n defaultOptions: [\n {\n model: \"qwen3-vl:8b-instruct\",\n styleguidePath: \".uilint/styleguide.md\",\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"model\",\n label: \"Ollama Model\",\n type: \"text\",\n defaultValue: \"qwen3-vl:8b-instruct\",\n description: \"The Ollama model name for semantic analysis.\",\n },\n {\n key: \"styleguidePath\",\n label: \"Styleguide Path\",\n type: \"text\",\n defaultValue: \".uilint/styleguide.md\",\n description: \"Relative path to the styleguide markdown file.\",\n },\n ],\n },\n docs: `\n## Semantic Analysis Rule\n\nUses a local LLM (via Ollama) to analyze your React components against your project's\nstyleguide. It catches semantic issues that pattern-based rules can't detect.\n\n### How it Works\n\n1. Your styleguide at \\`.uilint/styleguide.md\\` defines your conventions\n2. The LLM analyzes each component against those conventions\n3. Issues like incorrect spacing, inconsistent styles, and missing patterns are reported\n\n### Prerequisites\n\n1. **Ollama installed**: \\`brew install ollama\\` or from ollama.ai\n2. **Model pulled**: \\`ollama pull qwen3-vl:8b-instruct\\`\n3. **Styleguide created**: Create \\`.uilint/styleguide.md\\` describing your conventions\n\n### Performance\n\n- Results are cached based on file content and styleguide hash\n- First run may be slow as the model loads; subsequent runs use cache\n- Set to \"off\" in CI to avoid slow builds\n `.trim(),\n};\n\n/**\n * All styleguide rule definitions\n */\nexport const styleguideRuleDefinitions: RuleDefinition[] = [\n semanticRuleDefinition,\n];\n","/**\n * Styleguide Plugin Message Handlers\n *\n * WebSocket message handlers for the styleguide plugin.\n * Plain functions - no React.\n */\n\nimport type { MessageHandlers } from \"uilint-core\";\nimport { createOperationMessageHandlers } from \"uilint-core\";\nimport type { StyleguideState } from \"./state.js\";\n\n/**\n * WebSocket message types for styleguide\n */\nexport interface StyleguideStatusMessage {\n type: \"styleguide:status\";\n styleguideLoaded: boolean;\n styleguidePath: string | null;\n modelAvailable: boolean;\n modelName: string;\n}\n\nexport interface StyleguideAnalysisProgressMessage {\n type: \"styleguide:analysis:progress\";\n filePath: string;\n current: number;\n total: number;\n}\n\nexport interface StyleguideAnalysisCompleteMessage {\n type: \"styleguide:analysis:complete\";\n analyzedFileCount: number;\n issueCount: number;\n}\n\nexport interface StyleguideAnalysisErrorMessage {\n type: \"styleguide:analysis:error\";\n error: string;\n}\n\nexport type StyleguideMessage =\n | StyleguideStatusMessage\n | StyleguideAnalysisProgressMessage\n | StyleguideAnalysisCompleteMessage\n | StyleguideAnalysisErrorMessage;\n\n/**\n * Message handlers for the styleguide plugin.\n *\n * Uses the operation lifecycle framework for the standard\n * progress -> complete/error message flow.\n *\n * The styleguide:status message is handled separately via the\n * \"handle-styleguide-status\" action (plugin-specific, not operation lifecycle).\n */\nexport const styleguideMessageHandlers: MessageHandlers<StyleguideState> = {\n ...createOperationMessageHandlers<StyleguideState>({\n actionPrefix: \"analysis\",\n progressMessage: \"styleguide:analysis:progress\",\n completeMessage: \"styleguide:analysis:complete\",\n errorMessage: \"styleguide:analysis:error\",\n extractProgress: (msg) => {\n const m = msg as StyleguideAnalysisProgressMessage;\n return {\n current: m.current,\n total: m.total,\n message: m.filePath,\n };\n },\n extractStats: (msg) => {\n const m = msg as StyleguideAnalysisCompleteMessage;\n return {\n analyzedFileCount: m.analyzedFileCount,\n issueCount: m.issueCount,\n };\n },\n }),\n\n /**\n * Handle styleguide status response (plugin-specific, not operation lifecycle)\n */\n \"styleguide:status\": (ctx, message) => {\n const msg = message as StyleguideStatusMessage;\n ctx.dispatch(\"handle-styleguide-status\", {\n styleguideLoaded: msg.styleguideLoaded,\n styleguidePath: msg.styleguidePath,\n modelAvailable: msg.modelAvailable,\n modelName: msg.modelName,\n });\n },\n};\n"],"mappings":"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","names":[]}
|
package/dist/index.js
CHANGED
package/dist/node.js
CHANGED
package/dist/plugin/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { PluginWithHandlers } from 'uilint-core';
|
|
1
|
+
import { OperationState, PluginWithHandlers } from 'uilint-core';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* Styleguide Plugin State
|
|
@@ -7,6 +7,13 @@ import { PluginWithHandlers } from 'uilint-core';
|
|
|
7
7
|
* No React - pure TypeScript.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
+
/**
|
|
11
|
+
* Analysis completion statistics
|
|
12
|
+
*/
|
|
13
|
+
interface AnalysisStats {
|
|
14
|
+
analyzedFileCount: number;
|
|
15
|
+
issueCount: number;
|
|
16
|
+
}
|
|
10
17
|
/**
|
|
11
18
|
* Styleguide plugin state shape
|
|
12
19
|
*/
|
|
@@ -19,20 +26,8 @@ interface StyleguideState {
|
|
|
19
26
|
modelAvailable: boolean;
|
|
20
27
|
/** Name of the configured model */
|
|
21
28
|
modelName: string;
|
|
22
|
-
/**
|
|
23
|
-
|
|
24
|
-
/** Analysis progress */
|
|
25
|
-
analysisProgress: {
|
|
26
|
-
filePath: string;
|
|
27
|
-
current: number;
|
|
28
|
-
total: number;
|
|
29
|
-
} | null;
|
|
30
|
-
/** Last analysis error */
|
|
31
|
-
lastAnalysisError: string | null;
|
|
32
|
-
/** Number of files analyzed */
|
|
33
|
-
analyzedFileCount: number;
|
|
34
|
-
/** Number of issues found */
|
|
35
|
-
issueCount: number;
|
|
29
|
+
/** Analysis operation lifecycle state */
|
|
30
|
+
analysis: OperationState<AnalysisStats>;
|
|
36
31
|
}
|
|
37
32
|
|
|
38
33
|
/**
|
package/dist/plugin/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uilint-semantic",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.144",
|
|
4
4
|
"description": "LLM-powered styleguide checking for UILint",
|
|
5
5
|
"author": "Peter Suggate",
|
|
6
6
|
"repository": {
|
|
@@ -46,8 +46,8 @@
|
|
|
46
46
|
"dist"
|
|
47
47
|
],
|
|
48
48
|
"peerDependencies": {
|
|
49
|
-
"uilint-
|
|
50
|
-
"uilint-
|
|
49
|
+
"uilint-core": "0.2.144",
|
|
50
|
+
"uilint-eslint": "0.2.144"
|
|
51
51
|
},
|
|
52
52
|
"dependencies": {
|
|
53
53
|
"@typescript-eslint/typescript-estree": "^8.35.1",
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/plugin/index.ts","../src/plugin/state.ts","../src/plugin/actions.ts","../src/plugin/commands.ts","../src/plugin/panels.ts","../src/plugin/rules.ts","../src/plugin/messages.ts"],"sourcesContent":["/**\n * Styleguide Plugin Definition\n *\n * Complete plugin export - NO REACT.\n * This is the main plugin definition that gets registered with pluginRegistry.\n */\n\nimport type { PluginWithHandlers, IssueContribution } from \"uilint-core\";\nimport { pluginRegistry } from \"uilint-core\";\n\nimport { styleguideStateDefinition, type StyleguideState } from \"./state.js\";\nimport { styleguideActionHandlers } from \"./actions.js\";\nimport { styleguideCommands } from \"./commands.js\";\nimport { styleguidePanelDefinitions } from \"./panels.js\";\nimport { styleguideRuleDefinitions } from \"./rules.js\";\nimport { styleguideMessageHandlers } from \"./messages.js\";\n\n/**\n * Styleguide plugin definition\n *\n * Contains everything needed for styleguide checking EXCEPT React components.\n * The host (uilint-react) imports this and renders the appropriate UI.\n */\nexport const styleguidePlugin: PluginWithHandlers<StyleguideState> = {\n // === Metadata ===\n id: \"styleguide\",\n name: \"Styleguide Checking\",\n version: \"1.0.0\",\n description: \"LLM-powered styleguide enforcement\",\n icon: \"book\",\n\n // === State ===\n state: styleguideStateDefinition,\n actions: styleguideActionHandlers,\n\n // === UI Contributions (Declarative) ===\n commands: styleguideCommands,\n panels: styleguidePanelDefinitions,\n\n // === Rules ===\n rules: styleguideRuleDefinitions,\n handlesRuleCategories: [\"styleguide\"],\n\n // === WebSocket ===\n messageHandlers: styleguideMessageHandlers,\n\n // === Issue Aggregation ===\n // Styleguide issues are reported by the semantic ESLint rule.\n // They don't come from plugin state, so we return empty.\n getIssues: (_state: StyleguideState): IssueContribution => {\n return { pluginId: \"styleguide\", issues: new Map() };\n },\n\n // === Browser Actions ===\n browserActions: [],\n\n // === Lifecycle ===\n onLoad: (ctx) => {\n // Check styleguide + model availability on load if connected\n if (ctx.websocket.isConnected) {\n ctx.websocket.send({ type: \"styleguide:check\" });\n }\n },\n};\n\n// Auto-register with plugin registry on import\npluginRegistry.register(styleguidePlugin);\n\n// Export types for host apps\nexport type { StyleguideState } from \"./state.js\";\n\nexport default styleguidePlugin;\n","/**\n * Styleguide Plugin State\n *\n * State shape and initial state for the styleguide checking plugin.\n * No React - pure TypeScript.\n */\n\nimport type { StateDefinition } from \"uilint-core\";\n\n/**\n * Styleguide plugin state shape\n */\nexport interface StyleguideState {\n // === Styleguide Loading ===\n /** Whether a styleguide file was found */\n styleguideLoaded: boolean;\n /** Resolved path to the styleguide file */\n styleguidePath: string | null;\n\n // === Model Availability ===\n /** Whether the required Ollama model is available */\n modelAvailable: boolean;\n /** Name of the configured model */\n modelName: string;\n\n // === Analysis State ===\n /** Current analysis status */\n analysisStatus: \"idle\" | \"analyzing\" | \"complete\" | \"error\";\n /** Analysis progress */\n analysisProgress: {\n filePath: string;\n current: number;\n total: number;\n } | null;\n /** Last analysis error */\n lastAnalysisError: string | null;\n\n // === Stats ===\n /** Number of files analyzed */\n analyzedFileCount: number;\n /** Number of issues found */\n issueCount: number;\n}\n\n/**\n * Initial state for the styleguide plugin\n */\nexport const styleguideInitialState: StyleguideState = {\n styleguideLoaded: false,\n styleguidePath: null,\n modelAvailable: false,\n modelName: \"qwen3-vl:8b-instruct\",\n analysisStatus: \"idle\",\n analysisProgress: null,\n lastAnalysisError: null,\n analyzedFileCount: 0,\n issueCount: 0,\n};\n\n/**\n * State definition for the plugin system\n */\nexport const styleguideStateDefinition: StateDefinition<StyleguideState> = {\n initialState: styleguideInitialState,\n\n computed: {\n /** Whether the plugin is ready to analyze (styleguide loaded + model available) */\n isReady: (state) => state.styleguideLoaded && state.modelAvailable,\n\n /** Whether analysis is currently running */\n isAnalyzing: (state) => state.analysisStatus === \"analyzing\",\n\n /** Whether there was an error */\n hasError: (state) => state.analysisStatus === \"error\" || state.lastAnalysisError !== null,\n\n /** Progress percentage (0-100) */\n progressPercent: (state) => {\n if (!state.analysisProgress) return 0;\n if (state.analysisProgress.total === 0) return 0;\n return Math.round((state.analysisProgress.current / state.analysisProgress.total) * 100);\n },\n },\n\n persist: {\n key: \"uilint-styleguide\",\n include: [],\n },\n};\n","/**\n * Styleguide Plugin Action Handlers\n *\n * Plain functions that handle plugin actions.\n * No React - uses PluginContext for state management.\n */\n\nimport type { ActionHandlers, PluginContext } from \"uilint-core\";\nimport type { StyleguideState } from \"./state.js\";\n\n// Helper type for cleaner action handler definitions\ntype Handler<TPayload = void> = (\n ctx: PluginContext<StyleguideState>,\n payload: TPayload\n) => void | Promise<void>;\n\n// Cast helper for proper typing\nconst h = <TPayload = void>(fn: Handler<TPayload>): Handler<unknown> =>\n fn as Handler<unknown>;\n\n/**\n * Action handlers for the styleguide plugin\n */\nexport const styleguideActionHandlers: ActionHandlers<StyleguideState> = {\n /**\n * Check styleguide and model status\n */\n \"check-styleguide-status\": h((ctx) => {\n ctx.websocket.send({ type: \"styleguide:check\" });\n }),\n\n /**\n * Handle styleguide status response from server\n */\n \"handle-styleguide-status\": h<{\n styleguideLoaded: boolean;\n styleguidePath: string | null;\n modelAvailable: boolean;\n modelName: string;\n }>((ctx, payload) => {\n ctx.setState({\n styleguideLoaded: payload.styleguideLoaded,\n styleguidePath: payload.styleguidePath,\n modelAvailable: payload.modelAvailable,\n modelName: payload.modelName,\n });\n }),\n\n /**\n * Handle analysis progress\n */\n \"handle-analysis-progress\": h<{\n filePath: string;\n current: number;\n total: number;\n }>((ctx, payload) => {\n ctx.setState({\n analysisStatus: \"analyzing\",\n analysisProgress: payload,\n });\n }),\n\n /**\n * Handle analysis complete\n */\n \"handle-analysis-complete\": h<{\n analyzedFileCount: number;\n issueCount: number;\n }>((ctx, payload) => {\n ctx.setState({\n analysisStatus: \"complete\",\n analysisProgress: null,\n analyzedFileCount: payload.analyzedFileCount,\n issueCount: payload.issueCount,\n lastAnalysisError: null,\n });\n }),\n\n /**\n * Handle analysis error\n */\n \"handle-analysis-error\": h<{ error: string }>((ctx, payload) => {\n ctx.setState({\n analysisStatus: \"error\",\n analysisProgress: null,\n lastAnalysisError: payload.error,\n });\n }),\n\n /**\n * Reload styleguide file from disk\n */\n \"reload-styleguide\": h((ctx) => {\n ctx.websocket.send({ type: \"styleguide:reload\" });\n }),\n\n /**\n * Open file in editor\n */\n \"open-editor\": h<{ dataLoc: string }>((ctx, payload) => {\n ctx.openInEditor(payload.dataLoc);\n }),\n};\n","/**\n * Styleguide Plugin Commands\n *\n * Command palette commands for the styleguide plugin.\n * Declarative - no React.\n */\n\nimport type { CommandDefinition } from \"uilint-core\";\n\n/**\n * Styleguide plugin commands\n */\nexport const styleguideCommands: CommandDefinition[] = [\n {\n id: \"styleguide:check-status\",\n title: \"Check Styleguide Status\",\n keywords: [\"styleguide\", \"status\", \"check\", \"model\", \"ollama\"],\n category: \"Styleguide\",\n subtitle: \"Check if styleguide and LLM model are available\",\n icon: \"check-circle\",\n action: { type: \"check-styleguide-status\" },\n },\n {\n id: \"styleguide:reload\",\n title: \"Reload Styleguide\",\n keywords: [\"styleguide\", \"reload\", \"refresh\"],\n category: \"Styleguide\",\n subtitle: \"Reload the styleguide file from disk\",\n icon: \"refresh\",\n action: { type: \"reload-styleguide\" },\n },\n];\n","/**\n * Styleguide Plugin Panels\n *\n * Inspector panel definitions for the styleguide plugin.\n * Declarative - no React.\n */\n\nimport type { PanelDefinition } from \"uilint-core\";\n\n/**\n * Styleguide status panel\n */\nexport const styleguideStatusPanelDefinition: PanelDefinition = {\n id: \"styleguide-status\",\n title: \"Styleguide Status\",\n priority: 5,\n\n layout: [\n // Styleguide loaded status\n {\n type: \"badge\",\n variant: \"status\",\n value: {\n condition: { binding: \"styleguideLoaded\" },\n true: \"Styleguide Loaded\",\n false: \"No Styleguide\",\n },\n centered: true,\n },\n\n // Styleguide path (when loaded)\n {\n type: \"conditional\",\n condition: { binding: \"styleguideLoaded\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"styleguidePath\" },\n variant: \"caption\",\n },\n ],\n else: [\n {\n type: \"text\",\n content: \"Create a styleguide at .uilint/styleguide.md to enable LLM-powered analysis.\",\n variant: \"body\",\n },\n ],\n },\n\n { type: \"divider\", spacing: \"small\" },\n\n // Model availability\n {\n type: \"badge\",\n variant: \"status\",\n value: {\n condition: { binding: \"modelAvailable\" },\n true: \"Model Ready\",\n false: \"Model Unavailable\",\n },\n centered: true,\n },\n\n // Model name\n {\n type: \"text\",\n content: { binding: \"modelName\" },\n variant: \"caption\",\n },\n\n // Analysis progress (when analyzing)\n {\n type: \"conditional\",\n condition: { expression: \"analysisStatus === 'analyzing'\" },\n then: [\n {\n type: \"progress\",\n value: { binding: \"progressPercent\" },\n label: { binding: \"analysisProgress.filePath\" },\n },\n ],\n },\n\n // Error (when error)\n {\n type: \"conditional\",\n condition: { expression: \"analysisStatus === 'error'\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"lastAnalysisError\" },\n variant: \"error\",\n },\n ],\n },\n\n // Stats (when analysis complete)\n {\n type: \"conditional\",\n condition: { expression: \"analysisStatus === 'complete'\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"analyzedFileCount\" },\n variant: \"body\",\n },\n ],\n },\n\n { type: \"divider\" },\n\n // Actions\n {\n type: \"actions\",\n direction: \"column\",\n actions: [\n {\n id: \"check-status\",\n label: \"Check Status\",\n icon: \"check-circle\",\n variant: \"secondary\",\n action: { type: \"check-styleguide-status\" },\n },\n {\n id: \"reload-styleguide\",\n label: \"Reload Styleguide\",\n icon: \"refresh\",\n variant: \"secondary\",\n action: { type: \"reload-styleguide\" },\n disabled: { expression: \"!styleguideLoaded\" },\n },\n ],\n },\n ],\n};\n\n/**\n * All styleguide panel definitions\n */\nexport const styleguidePanelDefinitions: PanelDefinition[] = [\n styleguideStatusPanelDefinition,\n];\n","/**\n * Styleguide Plugin Rules\n *\n * Rule definitions for the styleguide plugin.\n * Declarative - no React.\n */\n\nimport type { RuleDefinition } from \"uilint-core\";\n\n/**\n * semantic rule definition (styleguide checking via LLM)\n */\nexport const semanticRuleDefinition: RuleDefinition = {\n id: \"semantic\",\n name: \"Semantic Analysis\",\n description: \"LLM-powered semantic UI analysis using your styleguide\",\n category: \"styleguide\",\n icon: \"brain\",\n defaultSeverity: \"warn\",\n defaultEnabled: false,\n heatmapColor: \"#8b5cf6\", // Purple\n customInspectorPanel: \"semantic-issue\",\n requirements: [\n {\n type: \"ollama\",\n description: \"Requires Ollama running locally\",\n setupHint: \"Run: ollama serve && ollama pull qwen3-vl:8b-instruct\",\n },\n {\n type: \"styleguide\",\n description: \"Requires a styleguide file\",\n setupHint: \"Run: uilint genstyleguide\",\n },\n ],\n defaultOptions: [\n {\n model: \"qwen3-vl:8b-instruct\",\n styleguidePath: \".uilint/styleguide.md\",\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"model\",\n label: \"Ollama Model\",\n type: \"text\",\n defaultValue: \"qwen3-vl:8b-instruct\",\n description: \"The Ollama model name for semantic analysis.\",\n },\n {\n key: \"styleguidePath\",\n label: \"Styleguide Path\",\n type: \"text\",\n defaultValue: \".uilint/styleguide.md\",\n description: \"Relative path to the styleguide markdown file.\",\n },\n ],\n },\n docs: `\n## Semantic Analysis Rule\n\nUses a local LLM (via Ollama) to analyze your React components against your project's\nstyleguide. It catches semantic issues that pattern-based rules can't detect.\n\n### How it Works\n\n1. Your styleguide at \\`.uilint/styleguide.md\\` defines your conventions\n2. The LLM analyzes each component against those conventions\n3. Issues like incorrect spacing, inconsistent styles, and missing patterns are reported\n\n### Prerequisites\n\n1. **Ollama installed**: \\`brew install ollama\\` or from ollama.ai\n2. **Model pulled**: \\`ollama pull qwen3-vl:8b-instruct\\`\n3. **Styleguide created**: Create \\`.uilint/styleguide.md\\` describing your conventions\n\n### Performance\n\n- Results are cached based on file content and styleguide hash\n- First run may be slow as the model loads; subsequent runs use cache\n- Set to \"off\" in CI to avoid slow builds\n `.trim(),\n};\n\n/**\n * All styleguide rule definitions\n */\nexport const styleguideRuleDefinitions: RuleDefinition[] = [\n semanticRuleDefinition,\n];\n","/**\n * Styleguide Plugin Message Handlers\n *\n * WebSocket message handlers for the styleguide plugin.\n * Plain functions - no React.\n */\n\nimport type { MessageHandlers, PluginContext } from \"uilint-core\";\nimport type { StyleguideState } from \"./state.js\";\n\n/**\n * WebSocket message types for styleguide\n */\nexport interface StyleguideStatusMessage {\n type: \"styleguide:status\";\n styleguideLoaded: boolean;\n styleguidePath: string | null;\n modelAvailable: boolean;\n modelName: string;\n}\n\nexport interface StyleguideAnalysisProgressMessage {\n type: \"styleguide:analysis:progress\";\n filePath: string;\n current: number;\n total: number;\n}\n\nexport interface StyleguideAnalysisCompleteMessage {\n type: \"styleguide:analysis:complete\";\n analyzedFileCount: number;\n issueCount: number;\n}\n\nexport interface StyleguideAnalysisErrorMessage {\n type: \"styleguide:analysis:error\";\n error: string;\n}\n\nexport type StyleguideMessage =\n | StyleguideStatusMessage\n | StyleguideAnalysisProgressMessage\n | StyleguideAnalysisCompleteMessage\n | StyleguideAnalysisErrorMessage;\n\n/**\n * Message handlers for the styleguide plugin\n */\nexport const styleguideMessageHandlers: MessageHandlers<StyleguideState> = {\n /**\n * Handle styleguide status response\n */\n \"styleguide:status\": (\n ctx: PluginContext<StyleguideState>,\n message: unknown\n ) => {\n const msg = message as StyleguideStatusMessage;\n ctx.dispatch(\"handle-styleguide-status\", {\n styleguideLoaded: msg.styleguideLoaded,\n styleguidePath: msg.styleguidePath,\n modelAvailable: msg.modelAvailable,\n modelName: msg.modelName,\n });\n },\n\n /**\n * Handle analysis progress\n */\n \"styleguide:analysis:progress\": (\n ctx: PluginContext<StyleguideState>,\n message: unknown\n ) => {\n const msg = message as StyleguideAnalysisProgressMessage;\n ctx.dispatch(\"handle-analysis-progress\", {\n filePath: msg.filePath,\n current: msg.current,\n total: msg.total,\n });\n },\n\n /**\n * Handle analysis complete\n */\n \"styleguide:analysis:complete\": (\n ctx: PluginContext<StyleguideState>,\n message: unknown\n ) => {\n const msg = message as StyleguideAnalysisCompleteMessage;\n ctx.dispatch(\"handle-analysis-complete\", {\n analyzedFileCount: msg.analyzedFileCount,\n issueCount: msg.issueCount,\n });\n },\n\n /**\n * Handle analysis error\n */\n \"styleguide:analysis:error\": (\n ctx: PluginContext<StyleguideState>,\n message: unknown\n ) => {\n const msg = message as StyleguideAnalysisErrorMessage;\n ctx.dispatch(\"handle-analysis-error\", { error: msg.error });\n },\n};\n"],"mappings":"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","names":[]}
|