uilint-coverage 0.2.151 โ 0.2.152
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/chunk-3XMA7KZX.js +15 -0
- package/dist/chunk-3XMA7KZX.js.map +1 -0
- package/dist/{chunk-TJZF52KU.js โ chunk-OUFXDT77.js} +7 -1
- package/dist/chunk-OUFXDT77.js.map +1 -0
- package/dist/cli-manifest.js +3 -10
- package/dist/cli-manifest.js.map +1 -1
- package/dist/index.js +2 -1
- package/dist/plugin/index.js +2 -1
- package/package.json +3 -3
- package/dist/chunk-TJZF52KU.js.map +0 -1
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
// src/cli-manifest.ts
|
|
2
|
+
var cliManifest = {
|
|
3
|
+
packageName: "uilint-coverage",
|
|
4
|
+
cliFlag: "coverage",
|
|
5
|
+
cliDescription: "Install test coverage rules (non-interactive)",
|
|
6
|
+
registerSpecifier: "uilint-coverage/eslint-rules/register",
|
|
7
|
+
displayName: "Test Coverage",
|
|
8
|
+
displayDescription: "Enforce test coverage thresholds for source files",
|
|
9
|
+
displayIcon: "\u{1F9EA}"
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export {
|
|
13
|
+
cliManifest
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=chunk-3XMA7KZX.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/cli-manifest.ts"],"sourcesContent":["/**\n * CLI manifest for the uilint-coverage plugin.\n */\nexport const cliManifest = {\n packageName: \"uilint-coverage\",\n cliFlag: \"coverage\",\n cliDescription: \"Install test coverage rules (non-interactive)\",\n registerSpecifier: \"uilint-coverage/eslint-rules/register\",\n displayName: \"Test Coverage\",\n displayDescription: \"Enforce test coverage thresholds for source files\",\n displayIcon: \"๐งช\",\n} as const;\n"],"mappings":";AAGO,IAAM,cAAc;AAAA,EACzB,aAAa;AAAA,EACb,SAAS;AAAA,EACT,gBAAgB;AAAA,EAChB,mBAAmB;AAAA,EACnB,aAAa;AAAA,EACb,oBAAoB;AAAA,EACpB,aAAa;AACf;","names":[]}
|
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import {
|
|
2
|
+
cliManifest
|
|
3
|
+
} from "./chunk-3XMA7KZX.js";
|
|
4
|
+
|
|
1
5
|
// src/plugin/index.ts
|
|
2
6
|
import { pluginRegistry } from "uilint-core";
|
|
3
7
|
|
|
@@ -282,6 +286,8 @@ var coveragePlugin = {
|
|
|
282
286
|
version: "1.0.0",
|
|
283
287
|
description: "Test coverage analysis and threshold enforcement",
|
|
284
288
|
icon: "test-tube",
|
|
289
|
+
// CLI (derived from cli-manifest โ single source of truth)
|
|
290
|
+
cli: cliManifest,
|
|
285
291
|
state: coverageStateDefinition,
|
|
286
292
|
actions: coverageActionHandlers,
|
|
287
293
|
commands: coverageCommands,
|
|
@@ -301,4 +307,4 @@ export {
|
|
|
301
307
|
coveragePlugin,
|
|
302
308
|
plugin_default
|
|
303
309
|
};
|
|
304
|
-
//# sourceMappingURL=chunk-
|
|
310
|
+
//# sourceMappingURL=chunk-OUFXDT77.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 * Coverage Plugin Definition\n *\n * Complete plugin export - NO REACT.\n */\n\nimport type { PluginWithHandlers, IssueContribution } from \"uilint-core\";\nimport { pluginRegistry } from \"uilint-core\";\n\nimport { cliManifest } from \"../cli-manifest.js\";\nimport { coverageStateDefinition, type CoverageState } from \"./state.js\";\nimport { coverageActionHandlers } from \"./actions.js\";\nimport { coverageCommands } from \"./commands.js\";\nimport { coveragePanelDefinitions } from \"./panels.js\";\nimport { coverageRuleDefinitions } from \"./rules.js\";\nimport { coverageMessageHandlers } from \"./messages.js\";\n\nexport const coveragePlugin: PluginWithHandlers<CoverageState> = {\n id: \"coverage\",\n name: \"Test Coverage\",\n version: \"1.0.0\",\n description: \"Test coverage analysis and threshold enforcement\",\n icon: \"test-tube\",\n\n // CLI (derived from cli-manifest โ single source of truth)\n cli: cliManifest,\n\n state: coverageStateDefinition,\n actions: coverageActionHandlers,\n\n commands: coverageCommands,\n panels: coveragePanelDefinitions,\n\n rules: coverageRuleDefinitions,\n handlesRuleCategories: [\"coverage\"],\n\n messageHandlers: coverageMessageHandlers,\n\n getIssues: (_state: CoverageState): IssueContribution => {\n return { pluginId: \"coverage\", issues: new Map() };\n },\n\n browserActions: [],\n};\n\n// Auto-register with plugin registry on import\npluginRegistry.register(coveragePlugin);\n\nexport type { CoverageState } from \"./state.js\";\n\nexport default coveragePlugin;\n","import type { StateDefinition, OperationState } from \"uilint-core\";\nimport { createOperationInitialState, createOperationComputed } from \"uilint-core\";\n\nexport interface CoveragePreparationStats {\n packageAdded: boolean;\n configModified: boolean;\n testsRan: boolean;\n coverageGenerated: boolean;\n duration: number;\n}\n\nexport interface CoverageState {\n preparation: OperationState<CoveragePreparationStats>;\n coverageAvailable: boolean;\n fileCount: number;\n}\n\nexport const coverageInitialState: CoverageState = {\n preparation: createOperationInitialState<CoveragePreparationStats>(),\n coverageAvailable: false,\n fileCount: 0,\n};\n\nconst opComputed = createOperationComputed<CoverageState>((s) => s.preparation);\n\nexport const coverageStateDefinition: StateDefinition<CoverageState> = {\n initialState: coverageInitialState,\n computed: {\n isReady: opComputed.isReady,\n isActive: opComputed.isActive,\n hasError: opComputed.hasError,\n progressPercent: opComputed.progressPercent,\n },\n persist: {\n key: \"uilint-coverage\",\n include: [],\n },\n};\n","import type { ActionHandlers, PluginContext } from \"uilint-core\";\nimport { createOperationActions } from \"uilint-core\";\nimport type { CoverageState, CoveragePreparationStats } from \"./state.js\";\n\ntype Handler<TPayload = void> = (\n ctx: PluginContext<CoverageState>,\n payload: TPayload\n) => void | Promise<void>;\n\nconst h = <TPayload = void>(fn: Handler<TPayload>): Handler<unknown> =>\n fn as Handler<unknown>;\n\nconst preparationActions = createOperationActions<CoverageState, CoveragePreparationStats>(\n \"preparation\",\n {\n getOp: (s) => s.preparation,\n setOp: (op) => ({ preparation: op }),\n }\n);\n\nexport const coverageActionHandlers: ActionHandlers<CoverageState> = {\n ...preparationActions,\n\n \"start-preparation\": h((ctx) => {\n ctx.dispatch(\"handle-preparation-start\");\n ctx.websocket.send({ type: \"coverage:prepare\" });\n }),\n\n \"set-coverage-available\": h<{ available: boolean; fileCount: number }>((ctx, payload) => {\n ctx.setState({ coverageAvailable: payload.available, fileCount: payload.fileCount });\n }),\n};\n","import type { CommandDefinition } from \"uilint-core\";\n\nexport const coverageCommands: CommandDefinition[] = [\n {\n id: \"coverage:regenerate\",\n title: \"Regenerate Coverage Data\",\n keywords: [\"coverage\", \"test\", \"regenerate\", \"rebuild\"],\n category: \"Coverage\",\n subtitle: \"Run tests and regenerate coverage data\",\n icon: \"refresh\",\n action: { type: \"start-preparation\" },\n },\n];\n","import type { PanelDefinition } from \"uilint-core\";\n\nexport const coverageStatusPanelDefinition: PanelDefinition = {\n id: \"coverage-status\",\n title: \"Coverage Status\",\n priority: 5,\n layout: [\n {\n type: \"badge\",\n variant: \"status\",\n value: { binding: \"preparation.status\" },\n centered: true,\n },\n {\n type: \"conditional\",\n condition: { expression: \"preparation.status === 'active'\" },\n then: [\n {\n type: \"progress\",\n value: { binding: \"progressPercent\" },\n label: { binding: \"preparation.progress.message\" },\n },\n ],\n },\n {\n type: \"conditional\",\n condition: { expression: \"preparation.status === 'complete'\" },\n then: [\n {\n type: \"text\",\n content: { expression: \"coverageAvailable ? fileCount + ' files covered' : 'No coverage data'\" },\n variant: \"body\",\n },\n ],\n },\n {\n type: \"conditional\",\n condition: { expression: \"preparation.status === 'error'\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"preparation.lastError\" },\n variant: \"error\",\n },\n ],\n },\n { type: \"divider\" },\n {\n type: \"actions\",\n direction: \"column\",\n actions: [\n {\n id: \"regenerate-coverage\",\n label: \"Regenerate Coverage\",\n icon: \"refresh\",\n variant: \"secondary\",\n action: { type: \"start-preparation\" },\n disabled: { binding: \"isActive\" },\n },\n ],\n },\n ],\n};\n\nexport const coveragePanelDefinitions: PanelDefinition[] = [\n coverageStatusPanelDefinition,\n];\n","import type { RuleDefinition } from \"uilint-core\";\n\nexport const requireTestCoverageRuleDefinition: RuleDefinition = {\n id: \"require-test-coverage\",\n name: \"Require Test Coverage\",\n description: \"Enforce that source files have adequate test coverage\",\n category: \"coverage\",\n icon: \"test-tube\",\n defaultSeverity: \"warn\",\n defaultEnabled: true,\n requirements: [\n {\n type: \"coverage\",\n description: \"Requires test coverage data\",\n setupHint: \"Run tests with coverage: npm test -- --coverage\",\n },\n ],\n defaultOptions: [\n {\n coveragePath: \"coverage/coverage-final.json\",\n threshold: 80,\n thresholdsByPattern: [],\n severity: {\n noCoverage: \"error\",\n belowThreshold: \"warn\",\n },\n testPatterns: [\".test.ts\", \".test.tsx\", \".spec.ts\", \".spec.tsx\", \"__tests__/\"],\n ignorePatterns: [\"**/*.d.ts\", \"**/index.ts\"],\n mode: \"all\",\n baseBranch: \"main\",\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"threshold\",\n label: \"Coverage threshold\",\n type: \"number\",\n defaultValue: 80,\n description: \"Minimum coverage percentage required (0-100)\",\n },\n {\n key: \"coveragePath\",\n label: \"Coverage file path\",\n type: \"text\",\n defaultValue: \"coverage/coverage-final.json\",\n description: \"Path to Istanbul coverage JSON file\",\n },\n {\n key: \"mode\",\n label: \"Mode\",\n type: \"select\",\n defaultValue: \"all\",\n options: [\n { value: \"all\", label: \"Check all code\" },\n { value: \"changed\", label: \"Only check changed lines\" },\n ],\n description: \"Whether to check all code or only git-changed lines\",\n },\n {\n key: \"chunkCoverage\",\n label: \"Enable chunk-level coverage\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Report coverage for individual functions instead of file level\",\n },\n {\n key: \"focusNonReact\",\n label: \"Focus on non-React code\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Apply strict thresholds to utilities/stores/hooks, relaxed to components\",\n },\n {\n key: \"chunkThreshold\",\n label: \"Chunk coverage threshold\",\n type: \"number\",\n defaultValue: 80,\n description: \"Minimum coverage for utility/hook/store chunks (0-100)\",\n },\n {\n key: \"relaxedThreshold\",\n label: \"Relaxed threshold for React code\",\n type: \"number\",\n defaultValue: 50,\n description: \"Threshold for components/handlers when focusNonReact is enabled\",\n },\n {\n key: \"minStatements\",\n label: \"Minimum statements for coverage\",\n type: \"number\",\n defaultValue: 5,\n description: \"Files with fewer statements are exempt from coverage requirements\",\n },\n ],\n },\n docs: `\n## Require Test Coverage\n\nEnforces that source files have test coverage above a configurable threshold.\n\n### How it Works\n\n1. Reads Istanbul JSON coverage data (generated by vitest or jest)\n2. Analyzes coverage at file, chunk (function/hook/component), and JSX element levels\n3. Reports functions and files below the configured threshold\n\n### Setup\n\n1. Run tests with coverage: \\`vitest run --coverage\\`\n2. Enable this rule in your ESLint config\n3. Coverage data is automatically prepared when the UILint server starts\n\n### Modes\n\n- **All**: Checks all code against thresholds\n- **Changed**: Only checks git-changed lines (useful for incremental coverage)\n `.trim(),\n};\n\nexport const coverageRuleDefinitions: RuleDefinition[] = [\n requireTestCoverageRuleDefinition,\n];\n","import type { MessageHandlers } from \"uilint-core\";\nimport { createOperationMessageHandlers } from \"uilint-core\";\nimport type { CoverageState } from \"./state.js\";\n\nexport interface CoverageSetupStartMessage {\n type: \"coverage:setup:start\";\n}\n\nexport interface CoverageSetupProgressMessage {\n type: \"coverage:setup:progress\";\n message: string;\n phase: string;\n}\n\nexport interface CoverageSetupCompleteMessage {\n type: \"coverage:setup:complete\";\n packageAdded: boolean;\n configModified: boolean;\n testsRan: boolean;\n coverageGenerated: boolean;\n duration: number;\n error?: string;\n}\n\nexport interface CoverageSetupErrorMessage {\n type: \"coverage:setup:error\";\n error: string;\n}\n\nexport type CoverageMessage =\n | CoverageSetupStartMessage\n | CoverageSetupProgressMessage\n | CoverageSetupCompleteMessage\n | CoverageSetupErrorMessage;\n\nexport const coverageMessageHandlers: MessageHandlers<CoverageState> = {\n ...createOperationMessageHandlers<CoverageState>({\n actionPrefix: \"preparation\",\n startMessage: \"coverage:setup:start\",\n progressMessage: \"coverage:setup:progress\",\n completeMessage: \"coverage:setup:complete\",\n errorMessage: \"coverage:setup:error\",\n extractProgress: (msg) => {\n const m = msg as CoverageSetupProgressMessage;\n return {\n current: 0,\n total: 0,\n message: m.message,\n };\n },\n extractStats: (msg) => {\n const m = msg as CoverageSetupCompleteMessage;\n return {\n packageAdded: m.packageAdded,\n configModified: m.configModified,\n testsRan: m.testsRan,\n coverageGenerated: m.coverageGenerated,\n duration: m.duration,\n };\n },\n }),\n};\n"],"mappings":";;;;;AAOA,SAAS,sBAAsB;;;ACN/B,SAAS,6BAA6B,+BAA+B;AAgB9D,IAAM,uBAAsC;AAAA,EACjD,aAAa,4BAAsD;AAAA,EACnE,mBAAmB;AAAA,EACnB,WAAW;AACb;AAEA,IAAM,aAAa,wBAAuC,CAAC,MAAM,EAAE,WAAW;AAEvE,IAAM,0BAA0D;AAAA,EACrE,cAAc;AAAA,EACd,UAAU;AAAA,IACR,SAAS,WAAW;AAAA,IACpB,UAAU,WAAW;AAAA,IACrB,UAAU,WAAW;AAAA,IACrB,iBAAiB,WAAW;AAAA,EAC9B;AAAA,EACA,SAAS;AAAA,IACP,KAAK;AAAA,IACL,SAAS,CAAC;AAAA,EACZ;AACF;;;ACpCA,SAAS,8BAA8B;AAQvC,IAAM,IAAI,CAAkB,OAC1B;AAEF,IAAM,qBAAqB;AAAA,EACzB;AAAA,EACA;AAAA,IACE,OAAO,CAAC,MAAM,EAAE;AAAA,IAChB,OAAO,CAAC,QAAQ,EAAE,aAAa,GAAG;AAAA,EACpC;AACF;AAEO,IAAM,yBAAwD;AAAA,EACnE,GAAG;AAAA,EAEH,qBAAqB,EAAE,CAAC,QAAQ;AAC9B,QAAI,SAAS,0BAA0B;AACvC,QAAI,UAAU,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAAA,EACjD,CAAC;AAAA,EAED,0BAA0B,EAA6C,CAAC,KAAK,YAAY;AACvF,QAAI,SAAS,EAAE,mBAAmB,QAAQ,WAAW,WAAW,QAAQ,UAAU,CAAC;AAAA,EACrF,CAAC;AACH;;;AC7BO,IAAM,mBAAwC;AAAA,EACnD;AAAA,IACE,IAAI;AAAA,IACJ,OAAO;AAAA,IACP,UAAU,CAAC,YAAY,QAAQ,cAAc,SAAS;AAAA,IACtD,UAAU;AAAA,IACV,UAAU;AAAA,IACV,MAAM;AAAA,IACN,QAAQ,EAAE,MAAM,oBAAoB;AAAA,EACtC;AACF;;;ACVO,IAAM,gCAAiD;AAAA,EAC5D,IAAI;AAAA,EACJ,OAAO;AAAA,EACP,UAAU;AAAA,EACV,QAAQ;AAAA,IACN;AAAA,MACE,MAAM;AAAA,MACN,SAAS;AAAA,MACT,OAAO,EAAE,SAAS,qBAAqB;AAAA,MACvC,UAAU;AAAA,IACZ;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,WAAW,EAAE,YAAY,kCAAkC;AAAA,MAC3D,MAAM;AAAA,QACJ;AAAA,UACE,MAAM;AAAA,UACN,OAAO,EAAE,SAAS,kBAAkB;AAAA,UACpC,OAAO,EAAE,SAAS,+BAA+B;AAAA,QACnD;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,WAAW,EAAE,YAAY,oCAAoC;AAAA,MAC7D,MAAM;AAAA,QACJ;AAAA,UACE,MAAM;AAAA,UACN,SAAS,EAAE,YAAY,wEAAwE;AAAA,UAC/F,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,IACA;AAAA,MACE,MAAM;AAAA,MACN,WAAW,EAAE,YAAY,iCAAiC;AAAA,MAC1D,MAAM;AAAA,QACJ;AAAA,UACE,MAAM;AAAA,UACN,SAAS,EAAE,SAAS,wBAAwB;AAAA,UAC5C,SAAS;AAAA,QACX;AAAA,MACF;AAAA,IACF;AAAA,IACA,EAAE,MAAM,UAAU;AAAA,IAClB;AAAA,MACE,MAAM;AAAA,MACN,WAAW;AAAA,MACX,SAAS;AAAA,QACP;AAAA,UACE,IAAI;AAAA,UACJ,OAAO;AAAA,UACP,MAAM;AAAA,UACN,SAAS;AAAA,UACT,QAAQ,EAAE,MAAM,oBAAoB;AAAA,UACpC,UAAU,EAAE,SAAS,WAAW;AAAA,QAClC;AAAA,MACF;AAAA,IACF;AAAA,EACF;AACF;AAEO,IAAM,2BAA8C;AAAA,EACzD;AACF;;;AChEO,IAAM,oCAAoD;AAAA,EAC/D,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,aAAa;AAAA,EACb,UAAU;AAAA,EACV,MAAM;AAAA,EACN,iBAAiB;AAAA,EACjB,gBAAgB;AAAA,EAChB,cAAc;AAAA,IACZ;AAAA,MACE,MAAM;AAAA,MACN,aAAa;AAAA,MACb,WAAW;AAAA,IACb;AAAA,EACF;AAAA,EACA,gBAAgB;AAAA,IACd;AAAA,MACE,cAAc;AAAA,MACd,WAAW;AAAA,MACX,qBAAqB,CAAC;AAAA,MACtB,UAAU;AAAA,QACR,YAAY;AAAA,QACZ,gBAAgB;AAAA,MAClB;AAAA,MACA,cAAc,CAAC,YAAY,aAAa,YAAY,aAAa,YAAY;AAAA,MAC7E,gBAAgB,CAAC,aAAa,aAAa;AAAA,MAC3C,MAAM;AAAA,MACN,YAAY;AAAA,IACd;AAAA,EACF;AAAA,EACA,cAAc;AAAA,IACZ,QAAQ;AAAA,MACN;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,cAAc;AAAA,QACd,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,cAAc;AAAA,QACd,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,cAAc;AAAA,QACd,SAAS;AAAA,UACP,EAAE,OAAO,OAAO,OAAO,iBAAiB;AAAA,UACxC,EAAE,OAAO,WAAW,OAAO,2BAA2B;AAAA,QACxD;AAAA,QACA,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,cAAc;AAAA,QACd,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,cAAc;AAAA,QACd,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,cAAc;AAAA,QACd,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,cAAc;AAAA,QACd,aAAa;AAAA,MACf;AAAA,MACA;AAAA,QACE,KAAK;AAAA,QACL,OAAO;AAAA,QACP,MAAM;AAAA,QACN,cAAc;AAAA,QACd,aAAa;AAAA,MACf;AAAA,IACF;AAAA,EACF;AAAA,EACA,MAAM;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,IAqBJ,KAAK;AACT;AAEO,IAAM,0BAA4C;AAAA,EACvD;AACF;;;ACzHA,SAAS,sCAAsC;AAkCxC,IAAM,0BAA0D;AAAA,EACrE,GAAG,+BAA8C;AAAA,IAC/C,cAAc;AAAA,IACd,cAAc;AAAA,IACd,iBAAiB;AAAA,IACjB,iBAAiB;AAAA,IACjB,cAAc;AAAA,IACd,iBAAiB,CAAC,QAAQ;AACxB,YAAM,IAAI;AACV,aAAO;AAAA,QACL,SAAS;AAAA,QACT,OAAO;AAAA,QACP,SAAS,EAAE;AAAA,MACb;AAAA,IACF;AAAA,IACA,cAAc,CAAC,QAAQ;AACrB,YAAM,IAAI;AACV,aAAO;AAAA,QACL,cAAc,EAAE;AAAA,QAChB,gBAAgB,EAAE;AAAA,QAClB,UAAU,EAAE;AAAA,QACZ,mBAAmB,EAAE;AAAA,QACrB,UAAU,EAAE;AAAA,MACd;AAAA,IACF;AAAA,EACF,CAAC;AACH;;;AN5CO,IAAM,iBAAoD;AAAA,EAC/D,IAAI;AAAA,EACJ,MAAM;AAAA,EACN,SAAS;AAAA,EACT,aAAa;AAAA,EACb,MAAM;AAAA;AAAA,EAGN,KAAK;AAAA,EAEL,OAAO;AAAA,EACP,SAAS;AAAA,EAET,UAAU;AAAA,EACV,QAAQ;AAAA,EAER,OAAO;AAAA,EACP,uBAAuB,CAAC,UAAU;AAAA,EAElC,iBAAiB;AAAA,EAEjB,WAAW,CAAC,WAA6C;AACvD,WAAO,EAAE,UAAU,YAAY,QAAQ,oBAAI,IAAI,EAAE;AAAA,EACnD;AAAA,EAEA,gBAAgB,CAAC;AACnB;AAGA,eAAe,SAAS,cAAc;AAItC,IAAO,iBAAQ;","names":[]}
|
package/dist/cli-manifest.js
CHANGED
|
@@ -1,13 +1,6 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
cliFlag: "coverage",
|
|
5
|
-
cliDescription: "Install test coverage rules (non-interactive)",
|
|
6
|
-
registerSpecifier: "uilint-coverage/eslint-rules/register",
|
|
7
|
-
displayName: "Test Coverage",
|
|
8
|
-
displayDescription: "Enforce test coverage thresholds for source files",
|
|
9
|
-
displayIcon: "\u{1F9EA}"
|
|
10
|
-
};
|
|
1
|
+
import {
|
|
2
|
+
cliManifest
|
|
3
|
+
} from "./chunk-3XMA7KZX.js";
|
|
11
4
|
export {
|
|
12
5
|
cliManifest
|
|
13
6
|
};
|
package/dist/cli-manifest.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":[
|
|
1
|
+
{"version":3,"sources":[],"sourcesContent":[],"mappings":"","names":[]}
|
package/dist/index.js
CHANGED
package/dist/plugin/index.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "uilint-coverage",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.152",
|
|
4
4
|
"description": "Test coverage analysis plugin for UILint",
|
|
5
5
|
"author": "Peter Suggate",
|
|
6
6
|
"repository": {
|
|
@@ -76,8 +76,8 @@
|
|
|
76
76
|
"vitest": "^4.0.16"
|
|
77
77
|
},
|
|
78
78
|
"peerDependencies": {
|
|
79
|
-
"uilint-core": "0.2.
|
|
80
|
-
"uilint-eslint": "0.2.
|
|
79
|
+
"uilint-core": "0.2.154",
|
|
80
|
+
"uilint-eslint": "0.2.154"
|
|
81
81
|
},
|
|
82
82
|
"keywords": [
|
|
83
83
|
"test-coverage",
|
|
@@ -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 * Coverage Plugin Definition\n *\n * Complete plugin export - NO REACT.\n */\n\nimport type { PluginWithHandlers, IssueContribution } from \"uilint-core\";\nimport { pluginRegistry } from \"uilint-core\";\n\nimport { coverageStateDefinition, type CoverageState } from \"./state.js\";\nimport { coverageActionHandlers } from \"./actions.js\";\nimport { coverageCommands } from \"./commands.js\";\nimport { coveragePanelDefinitions } from \"./panels.js\";\nimport { coverageRuleDefinitions } from \"./rules.js\";\nimport { coverageMessageHandlers } from \"./messages.js\";\n\nexport const coveragePlugin: PluginWithHandlers<CoverageState> = {\n id: \"coverage\",\n name: \"Test Coverage\",\n version: \"1.0.0\",\n description: \"Test coverage analysis and threshold enforcement\",\n icon: \"test-tube\",\n\n state: coverageStateDefinition,\n actions: coverageActionHandlers,\n\n commands: coverageCommands,\n panels: coveragePanelDefinitions,\n\n rules: coverageRuleDefinitions,\n handlesRuleCategories: [\"coverage\"],\n\n messageHandlers: coverageMessageHandlers,\n\n getIssues: (_state: CoverageState): IssueContribution => {\n return { pluginId: \"coverage\", issues: new Map() };\n },\n\n browserActions: [],\n};\n\n// Auto-register with plugin registry on import\npluginRegistry.register(coveragePlugin);\n\nexport type { CoverageState } from \"./state.js\";\n\nexport default coveragePlugin;\n","import type { StateDefinition, OperationState } from \"uilint-core\";\nimport { createOperationInitialState, createOperationComputed } from \"uilint-core\";\n\nexport interface CoveragePreparationStats {\n packageAdded: boolean;\n configModified: boolean;\n testsRan: boolean;\n coverageGenerated: boolean;\n duration: number;\n}\n\nexport interface CoverageState {\n preparation: OperationState<CoveragePreparationStats>;\n coverageAvailable: boolean;\n fileCount: number;\n}\n\nexport const coverageInitialState: CoverageState = {\n preparation: createOperationInitialState<CoveragePreparationStats>(),\n coverageAvailable: false,\n fileCount: 0,\n};\n\nconst opComputed = createOperationComputed<CoverageState>((s) => s.preparation);\n\nexport const coverageStateDefinition: StateDefinition<CoverageState> = {\n initialState: coverageInitialState,\n computed: {\n isReady: opComputed.isReady,\n isActive: opComputed.isActive,\n hasError: opComputed.hasError,\n progressPercent: opComputed.progressPercent,\n },\n persist: {\n key: \"uilint-coverage\",\n include: [],\n },\n};\n","import type { ActionHandlers, PluginContext } from \"uilint-core\";\nimport { createOperationActions } from \"uilint-core\";\nimport type { CoverageState, CoveragePreparationStats } from \"./state.js\";\n\ntype Handler<TPayload = void> = (\n ctx: PluginContext<CoverageState>,\n payload: TPayload\n) => void | Promise<void>;\n\nconst h = <TPayload = void>(fn: Handler<TPayload>): Handler<unknown> =>\n fn as Handler<unknown>;\n\nconst preparationActions = createOperationActions<CoverageState, CoveragePreparationStats>(\n \"preparation\",\n {\n getOp: (s) => s.preparation,\n setOp: (op) => ({ preparation: op }),\n }\n);\n\nexport const coverageActionHandlers: ActionHandlers<CoverageState> = {\n ...preparationActions,\n\n \"start-preparation\": h((ctx) => {\n ctx.dispatch(\"handle-preparation-start\");\n ctx.websocket.send({ type: \"coverage:prepare\" });\n }),\n\n \"set-coverage-available\": h<{ available: boolean; fileCount: number }>((ctx, payload) => {\n ctx.setState({ coverageAvailable: payload.available, fileCount: payload.fileCount });\n }),\n};\n","import type { CommandDefinition } from \"uilint-core\";\n\nexport const coverageCommands: CommandDefinition[] = [\n {\n id: \"coverage:regenerate\",\n title: \"Regenerate Coverage Data\",\n keywords: [\"coverage\", \"test\", \"regenerate\", \"rebuild\"],\n category: \"Coverage\",\n subtitle: \"Run tests and regenerate coverage data\",\n icon: \"refresh\",\n action: { type: \"start-preparation\" },\n },\n];\n","import type { PanelDefinition } from \"uilint-core\";\n\nexport const coverageStatusPanelDefinition: PanelDefinition = {\n id: \"coverage-status\",\n title: \"Coverage Status\",\n priority: 5,\n layout: [\n {\n type: \"badge\",\n variant: \"status\",\n value: { binding: \"preparation.status\" },\n centered: true,\n },\n {\n type: \"conditional\",\n condition: { expression: \"preparation.status === 'active'\" },\n then: [\n {\n type: \"progress\",\n value: { binding: \"progressPercent\" },\n label: { binding: \"preparation.progress.message\" },\n },\n ],\n },\n {\n type: \"conditional\",\n condition: { expression: \"preparation.status === 'complete'\" },\n then: [\n {\n type: \"text\",\n content: { expression: \"coverageAvailable ? fileCount + ' files covered' : 'No coverage data'\" },\n variant: \"body\",\n },\n ],\n },\n {\n type: \"conditional\",\n condition: { expression: \"preparation.status === 'error'\" },\n then: [\n {\n type: \"text\",\n content: { binding: \"preparation.lastError\" },\n variant: \"error\",\n },\n ],\n },\n { type: \"divider\" },\n {\n type: \"actions\",\n direction: \"column\",\n actions: [\n {\n id: \"regenerate-coverage\",\n label: \"Regenerate Coverage\",\n icon: \"refresh\",\n variant: \"secondary\",\n action: { type: \"start-preparation\" },\n disabled: { binding: \"isActive\" },\n },\n ],\n },\n ],\n};\n\nexport const coveragePanelDefinitions: PanelDefinition[] = [\n coverageStatusPanelDefinition,\n];\n","import type { RuleDefinition } from \"uilint-core\";\n\nexport const requireTestCoverageRuleDefinition: RuleDefinition = {\n id: \"require-test-coverage\",\n name: \"Require Test Coverage\",\n description: \"Enforce that source files have adequate test coverage\",\n category: \"coverage\",\n icon: \"test-tube\",\n defaultSeverity: \"warn\",\n defaultEnabled: true,\n requirements: [\n {\n type: \"coverage\",\n description: \"Requires test coverage data\",\n setupHint: \"Run tests with coverage: npm test -- --coverage\",\n },\n ],\n defaultOptions: [\n {\n coveragePath: \"coverage/coverage-final.json\",\n threshold: 80,\n thresholdsByPattern: [],\n severity: {\n noCoverage: \"error\",\n belowThreshold: \"warn\",\n },\n testPatterns: [\".test.ts\", \".test.tsx\", \".spec.ts\", \".spec.tsx\", \"__tests__/\"],\n ignorePatterns: [\"**/*.d.ts\", \"**/index.ts\"],\n mode: \"all\",\n baseBranch: \"main\",\n },\n ],\n optionSchema: {\n fields: [\n {\n key: \"threshold\",\n label: \"Coverage threshold\",\n type: \"number\",\n defaultValue: 80,\n description: \"Minimum coverage percentage required (0-100)\",\n },\n {\n key: \"coveragePath\",\n label: \"Coverage file path\",\n type: \"text\",\n defaultValue: \"coverage/coverage-final.json\",\n description: \"Path to Istanbul coverage JSON file\",\n },\n {\n key: \"mode\",\n label: \"Mode\",\n type: \"select\",\n defaultValue: \"all\",\n options: [\n { value: \"all\", label: \"Check all code\" },\n { value: \"changed\", label: \"Only check changed lines\" },\n ],\n description: \"Whether to check all code or only git-changed lines\",\n },\n {\n key: \"chunkCoverage\",\n label: \"Enable chunk-level coverage\",\n type: \"boolean\",\n defaultValue: true,\n description: \"Report coverage for individual functions instead of file level\",\n },\n {\n key: \"focusNonReact\",\n label: \"Focus on non-React code\",\n type: \"boolean\",\n defaultValue: false,\n description: \"Apply strict thresholds to utilities/stores/hooks, relaxed to components\",\n },\n {\n key: \"chunkThreshold\",\n label: \"Chunk coverage threshold\",\n type: \"number\",\n defaultValue: 80,\n description: \"Minimum coverage for utility/hook/store chunks (0-100)\",\n },\n {\n key: \"relaxedThreshold\",\n label: \"Relaxed threshold for React code\",\n type: \"number\",\n defaultValue: 50,\n description: \"Threshold for components/handlers when focusNonReact is enabled\",\n },\n {\n key: \"minStatements\",\n label: \"Minimum statements for coverage\",\n type: \"number\",\n defaultValue: 5,\n description: \"Files with fewer statements are exempt from coverage requirements\",\n },\n ],\n },\n docs: `\n## Require Test Coverage\n\nEnforces that source files have test coverage above a configurable threshold.\n\n### How it Works\n\n1. Reads Istanbul JSON coverage data (generated by vitest or jest)\n2. Analyzes coverage at file, chunk (function/hook/component), and JSX element levels\n3. Reports functions and files below the configured threshold\n\n### Setup\n\n1. Run tests with coverage: \\`vitest run --coverage\\`\n2. Enable this rule in your ESLint config\n3. Coverage data is automatically prepared when the UILint server starts\n\n### Modes\n\n- **All**: Checks all code against thresholds\n- **Changed**: Only checks git-changed lines (useful for incremental coverage)\n `.trim(),\n};\n\nexport const coverageRuleDefinitions: RuleDefinition[] = [\n requireTestCoverageRuleDefinition,\n];\n","import type { MessageHandlers } from \"uilint-core\";\nimport { createOperationMessageHandlers } from \"uilint-core\";\nimport type { CoverageState } from \"./state.js\";\n\nexport interface CoverageSetupStartMessage {\n type: \"coverage:setup:start\";\n}\n\nexport interface CoverageSetupProgressMessage {\n type: \"coverage:setup:progress\";\n message: string;\n phase: string;\n}\n\nexport interface CoverageSetupCompleteMessage {\n type: \"coverage:setup:complete\";\n packageAdded: boolean;\n configModified: boolean;\n testsRan: boolean;\n coverageGenerated: boolean;\n duration: number;\n error?: string;\n}\n\nexport interface CoverageSetupErrorMessage {\n type: \"coverage:setup:error\";\n error: string;\n}\n\nexport type CoverageMessage =\n | CoverageSetupStartMessage\n | CoverageSetupProgressMessage\n | CoverageSetupCompleteMessage\n | CoverageSetupErrorMessage;\n\nexport const coverageMessageHandlers: MessageHandlers<CoverageState> = {\n ...createOperationMessageHandlers<CoverageState>({\n actionPrefix: \"preparation\",\n startMessage: \"coverage:setup:start\",\n progressMessage: \"coverage:setup:progress\",\n completeMessage: \"coverage:setup:complete\",\n errorMessage: \"coverage:setup:error\",\n extractProgress: (msg) => {\n const m = msg as CoverageSetupProgressMessage;\n return {\n current: 0,\n total: 0,\n message: m.message,\n };\n },\n extractStats: (msg) => {\n const m = msg as CoverageSetupCompleteMessage;\n return {\n packageAdded: m.packageAdded,\n configModified: m.configModified,\n testsRan: m.testsRan,\n coverageGenerated: m.coverageGenerated,\n duration: m.duration,\n };\n },\n }),\n};\n"],"mappings":"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","names":[]}
|