uidex 0.7.0 → 0.9.0
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/cli/cli.cjs +1112 -1054
- package/dist/cli/cli.cjs.map +1 -1
- package/dist/headless/index.cjs +4 -448
- package/dist/headless/index.cjs.map +1 -1
- package/dist/headless/index.d.cts +41 -11
- package/dist/headless/index.d.ts +41 -11
- package/dist/headless/index.js +4 -450
- package/dist/headless/index.js.map +1 -1
- package/dist/index.cjs +147 -3252
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +43 -316
- package/dist/index.d.ts +43 -316
- package/dist/index.js +133 -3254
- package/dist/index.js.map +1 -1
- package/dist/playwright/index.cjs +175 -0
- package/dist/playwright/index.cjs.map +1 -1
- package/dist/playwright/index.d.cts +2 -0
- package/dist/playwright/index.d.ts +2 -0
- package/dist/playwright/index.js +167 -0
- package/dist/playwright/index.js.map +1 -1
- package/dist/playwright/states-reporter.cjs +123 -0
- package/dist/playwright/states-reporter.cjs.map +1 -0
- package/dist/playwright/states-reporter.d.cts +46 -0
- package/dist/playwright/states-reporter.d.ts +46 -0
- package/dist/playwright/states-reporter.js +88 -0
- package/dist/playwright/states-reporter.js.map +1 -0
- package/dist/playwright/states.cjs +118 -0
- package/dist/playwright/states.cjs.map +1 -0
- package/dist/playwright/states.d.cts +120 -0
- package/dist/playwright/states.d.ts +120 -0
- package/dist/playwright/states.js +88 -0
- package/dist/playwright/states.js.map +1 -0
- package/dist/react/index.cjs +163 -3255
- package/dist/react/index.cjs.map +1 -1
- package/dist/react/index.d.cts +62 -275
- package/dist/react/index.d.ts +62 -275
- package/dist/react/index.js +151 -3268
- package/dist/react/index.js.map +1 -1
- package/dist/scan/index.cjs +1292 -345
- package/dist/scan/index.cjs.map +1 -1
- package/dist/scan/index.d.cts +305 -12
- package/dist/scan/index.d.ts +305 -12
- package/dist/scan/index.js +1283 -345
- package/dist/scan/index.js.map +1 -1
- package/package.json +12 -16
- package/dist/cloud/index.cjs +0 -682
- package/dist/cloud/index.cjs.map +0 -1
- package/dist/cloud/index.d.cts +0 -270
- package/dist/cloud/index.d.ts +0 -270
- package/dist/cloud/index.js +0 -645
- package/dist/cloud/index.js.map +0 -1
package/dist/scan/index.d.ts
CHANGED
|
@@ -12,6 +12,32 @@ interface EntityRef {
|
|
|
12
12
|
kind: EntityKind;
|
|
13
13
|
id: string;
|
|
14
14
|
}
|
|
15
|
+
/**
|
|
16
|
+
* The four kinds every captured route is expected to render — the state-matrix
|
|
17
|
+
* axis. A capture that only shoots the happy path leaves most of the value on
|
|
18
|
+
* the table, so a missing core kind must be captured, waived (the page CANNOT
|
|
19
|
+
* render it), or acknowledged in the MISSING_KINDS baseline.
|
|
20
|
+
*/
|
|
21
|
+
declare const CORE_STATE_KINDS: readonly ["loading", "empty", "populated", "error"];
|
|
22
|
+
type CoreStateKind = (typeof CORE_STATE_KINDS)[number];
|
|
23
|
+
/** `variant` is any state outside the matrix (a dialog, wizard step, multi-currency…). */
|
|
24
|
+
type StateKind = CoreStateKind | "variant";
|
|
25
|
+
/**
|
|
26
|
+
* A declared render state of an entity — the "story"-like unit: a named
|
|
27
|
+
* condition the page/feature/widget can render in (loading / empty / error /
|
|
28
|
+
* multi-currency / …). Enumerated on the entity (not derived from syntax), it
|
|
29
|
+
* is the contract the visual-states capture must satisfy and the anchor for
|
|
30
|
+
* per-state acceptance criteria. Fixtures + capture mechanics stay in the spec;
|
|
31
|
+
* the registry holds only the name (+ optional kind / per-state acceptance).
|
|
32
|
+
*/
|
|
33
|
+
interface StateDecl {
|
|
34
|
+
name: string;
|
|
35
|
+
/** Canonical kind for the state-matrix axis (defaults to `variant`). */
|
|
36
|
+
kind?: StateKind;
|
|
37
|
+
/** Acceptance criteria that only this state can evidence. */
|
|
38
|
+
acceptance?: string[];
|
|
39
|
+
description?: string;
|
|
40
|
+
}
|
|
15
41
|
interface Metadata {
|
|
16
42
|
name?: string;
|
|
17
43
|
description?: string;
|
|
@@ -21,6 +47,21 @@ interface Metadata {
|
|
|
21
47
|
flows?: readonly string[];
|
|
22
48
|
features?: string[];
|
|
23
49
|
widgets?: string[];
|
|
50
|
+
/** Declared render states (see StateDecl); the capture-completeness gate. */
|
|
51
|
+
states?: StateDecl[];
|
|
52
|
+
/**
|
|
53
|
+
* `false` opts this page/feature/widget out of visual-states capture forever
|
|
54
|
+
* (a redirect, a static notice, an internal target). The page-coverage gate
|
|
55
|
+
* treats an opted-out route as accounted-for. Reason belongs in `description`.
|
|
56
|
+
*/
|
|
57
|
+
capture?: boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Per-core-kind waivers: a core kind this page's route legitimately CANNOT
|
|
60
|
+
* render (a create form has no `empty`), mapped to a substantive reason. The
|
|
61
|
+
* state-matrix gate treats a waived kind as accounted-for. A waiver is a
|
|
62
|
+
* permanent design statement — unlike MISSING_KINDS backlog, which is debt.
|
|
63
|
+
*/
|
|
64
|
+
waivers?: Partial<Record<CoreStateKind, string>>;
|
|
24
65
|
}
|
|
25
66
|
interface EntityWithMetaBase {
|
|
26
67
|
id: string;
|
|
@@ -66,6 +107,7 @@ type Entity = Route | Page | Feature | Widget | Region | Element | Primitive | F
|
|
|
66
107
|
type EntityByKind<K extends EntityKind> = Extract<Entity, {
|
|
67
108
|
kind: K;
|
|
68
109
|
}>;
|
|
110
|
+
type MetaEntityKind = Exclude<EntityKind, "route" | "flow">;
|
|
69
111
|
|
|
70
112
|
interface ReportRecord {
|
|
71
113
|
id: string;
|
|
@@ -111,7 +153,18 @@ interface SourceConfig {
|
|
|
111
153
|
interface ConventionsConfig {
|
|
112
154
|
primitives?: string[] | false;
|
|
113
155
|
features?: string | false;
|
|
114
|
-
|
|
156
|
+
/**
|
|
157
|
+
* How Page entities are derived from route files.
|
|
158
|
+
* - `"auto"` (default): infer the route root from the `app`/`pages`/
|
|
159
|
+
* `routes` directory-name heuristic.
|
|
160
|
+
* - `{ routesDir }`: the route root is exactly this dir (relative to the
|
|
161
|
+
* config dir), detected with the TanStack / React Router `routes/`-style
|
|
162
|
+
* convention. Use for a custom TanStack `routesDirectory`.
|
|
163
|
+
* - `false`: do not derive pages from routes.
|
|
164
|
+
*/
|
|
165
|
+
pages?: "auto" | false | {
|
|
166
|
+
routesDir: string;
|
|
167
|
+
};
|
|
115
168
|
flows?: string[] | false;
|
|
116
169
|
regions?: "landmarks" | false;
|
|
117
170
|
}
|
|
@@ -119,6 +172,12 @@ interface AuditConfig {
|
|
|
119
172
|
scopeLeak?: boolean;
|
|
120
173
|
coverage?: boolean;
|
|
121
174
|
acceptance?: boolean;
|
|
175
|
+
/** State-capture completeness gate (default on when a manifest is present). */
|
|
176
|
+
states?: boolean;
|
|
177
|
+
/** Page-capture coverage gate (default on when a manifest is present). */
|
|
178
|
+
pageCoverage?: boolean;
|
|
179
|
+
/** State-matrix (core-kind) gate (default on when a manifest is present). */
|
|
180
|
+
stateMatrix?: boolean;
|
|
122
181
|
}
|
|
123
182
|
interface UidexConfig {
|
|
124
183
|
$schema?: string;
|
|
@@ -128,6 +187,18 @@ interface UidexConfig {
|
|
|
128
187
|
flows?: string[];
|
|
129
188
|
audit?: AuditConfig;
|
|
130
189
|
conventions?: ConventionsConfig;
|
|
190
|
+
/**
|
|
191
|
+
* Path (relative to the config dir) of the captured-states manifest the
|
|
192
|
+
* Playwright states reporter writes. The completeness gate reads it when
|
|
193
|
+
* present. Defaults to `uidex-states.json`.
|
|
194
|
+
*/
|
|
195
|
+
statesManifest?: string;
|
|
196
|
+
/**
|
|
197
|
+
* Path (relative to the config dir) of the page-coverage baseline — the
|
|
198
|
+
* tool-managed, shrink-only backlog written by `uidex scan --update-baseline`.
|
|
199
|
+
* Defaults to `uidex-coverage-baseline.json`.
|
|
200
|
+
*/
|
|
201
|
+
coverageBaseline?: string;
|
|
131
202
|
}
|
|
132
203
|
interface DiscoveredConfig {
|
|
133
204
|
configPath: string;
|
|
@@ -186,6 +257,26 @@ interface MetadataExport {
|
|
|
186
257
|
featureSpans?: Span[];
|
|
187
258
|
/** Spans of the string-literal items in `widgets`, parallel to `widgets`. */
|
|
188
259
|
widgetSpans?: Span[];
|
|
260
|
+
/** Declared render states (page/feature/widget); see ParsedState. */
|
|
261
|
+
states?: ParsedState[];
|
|
262
|
+
/** `capture: false` opts the entity out of the page-coverage gate. */
|
|
263
|
+
capture?: boolean;
|
|
264
|
+
/** Per-core-kind waivers: kind → reason the route cannot render it. */
|
|
265
|
+
waivers?: Record<string, string>;
|
|
266
|
+
}
|
|
267
|
+
/**
|
|
268
|
+
* A parsed `states` entry from `export const uidex`. The authored form is a
|
|
269
|
+
* string (bare name) or an object `{ name, acceptance?, description? }`; both
|
|
270
|
+
* normalize to this. `nameSpan` powers a future `uidex rename state`.
|
|
271
|
+
*/
|
|
272
|
+
interface ParsedState {
|
|
273
|
+
name: string;
|
|
274
|
+
/** Canonical kind: loading | empty | populated | error | variant. */
|
|
275
|
+
kind?: string;
|
|
276
|
+
acceptance?: string[];
|
|
277
|
+
description?: string;
|
|
278
|
+
/** Span of the state's name string literal. */
|
|
279
|
+
nameSpan?: Span;
|
|
189
280
|
}
|
|
190
281
|
/** A data-uidex* attribute whose value the scanner could not resolve. */
|
|
191
282
|
interface DynamicAttrFact {
|
|
@@ -383,6 +474,83 @@ interface ResolveOutput {
|
|
|
383
474
|
*/
|
|
384
475
|
declare function resolve(ctx: ResolveContext): ResolveOutput;
|
|
385
476
|
|
|
477
|
+
/**
|
|
478
|
+
* State-capture completeness — the deterministic replacement for a bespoke
|
|
479
|
+
* `check-states.mjs`. Cross-checks the states DECLARED on registry entities
|
|
480
|
+
* (`export const uidex = { states: [...] }`) against the states a capture run
|
|
481
|
+
* actually produced (a `uidex-states.json` manifest written by the Playwright
|
|
482
|
+
* states reporter):
|
|
483
|
+
*
|
|
484
|
+
* - `missing-state-capture` — a declared state no run captured. The gap the
|
|
485
|
+
* acceptance-grounded analysis surfaces (a promised behavior with no pixel
|
|
486
|
+
* evidence) becomes a mechanical audit failure.
|
|
487
|
+
* - `orphan-state-capture` — a run captured a state the entity never declared,
|
|
488
|
+
* so the contact sheet shows a state the registry doesn't know about.
|
|
489
|
+
*
|
|
490
|
+
* Pure: same (registry, manifest) → same diagnostics. Only runs when a manifest
|
|
491
|
+
* is present, so a plain `uidex scan` (no capture run) never fails on it.
|
|
492
|
+
*/
|
|
493
|
+
/** One `entity/state` a capture run recorded. */
|
|
494
|
+
interface CapturedState {
|
|
495
|
+
/** Registry entity id the capture rendered (e.g. "products"). */
|
|
496
|
+
entity: string;
|
|
497
|
+
/** Entity kind, when the capture recorded it (page/feature/widget). */
|
|
498
|
+
kind?: MetaEntityKind;
|
|
499
|
+
/** The declared state name captured (e.g. "new-filled"). */
|
|
500
|
+
state: string;
|
|
501
|
+
/** Canonical matrix kind (loading/empty/populated/error/variant). */
|
|
502
|
+
stateKind?: string;
|
|
503
|
+
/** URL pathname the capture ran against (page-coverage gate matches it to a route). */
|
|
504
|
+
url?: string;
|
|
505
|
+
/** Explicit route pattern the capture covers, when supplied. */
|
|
506
|
+
route?: string;
|
|
507
|
+
}
|
|
508
|
+
interface CapturedStatesManifest {
|
|
509
|
+
captured: CapturedState[];
|
|
510
|
+
}
|
|
511
|
+
declare function checkStateCoverage(registry: Registry, manifest: CapturedStatesManifest): Diagnostic[];
|
|
512
|
+
|
|
513
|
+
/**
|
|
514
|
+
* Page-capture coverage — the coarse gate above the per-state gate. Every
|
|
515
|
+
* derived route must be accounted for: captured (a run drove it), opted out
|
|
516
|
+
* (`export const uidex = { page, capture: false }`), or acknowledged backlog (a
|
|
517
|
+
* tool-managed, shrink-only baseline). A route in none of those is a *new*
|
|
518
|
+
* uncaptured page and fails hard — the ratchet that keeps debt from growing.
|
|
519
|
+
*
|
|
520
|
+
* uidex derives the route set (route groups stripped, dynamic segments kept), so
|
|
521
|
+
* unlike a hand-rolled `src/app/**` walk there is no page list to enumerate or
|
|
522
|
+
* keep from rotting: a route exists in the registry or it doesn't. And captures
|
|
523
|
+
* observe the URL they ran against, so which route a capture covers is matched,
|
|
524
|
+
* never hand-declared.
|
|
525
|
+
*/
|
|
526
|
+
/** The committed, tool-managed backlog. Shrinks as pages/kinds get captured. */
|
|
527
|
+
interface PageCoverageBaseline {
|
|
528
|
+
/** Route patterns acknowledged as uncaptured (e.g. "/[scope]/collections"). */
|
|
529
|
+
uncapturedPages: string[];
|
|
530
|
+
/** route → core kinds acknowledged as not-yet-captured (the matrix backlog). */
|
|
531
|
+
missingKinds?: Record<string, string[]>;
|
|
532
|
+
}
|
|
533
|
+
/**
|
|
534
|
+
* Turn a Next-style route pattern into an anchored matcher.
|
|
535
|
+
* `/[scope]/products/[productId]/edit` → matches `/acme/products/p1/edit`
|
|
536
|
+
* `/[...slug]` (catch-all) → matches one or more segments
|
|
537
|
+
* Returns the literal-segment count as a specificity score, so the most literal
|
|
538
|
+
* matching pattern wins when several match (e.g. `/x/new` beats `/x/[id]`).
|
|
539
|
+
*/
|
|
540
|
+
declare function compileRoute(pattern: string): {
|
|
541
|
+
test: (url: string) => boolean;
|
|
542
|
+
specificity: number;
|
|
543
|
+
};
|
|
544
|
+
/** The route pattern (from the given set) that most-specifically matches a URL. */
|
|
545
|
+
declare function matchUrlToRoute(url: string, routePaths: string[]): string | null;
|
|
546
|
+
declare function checkPageCoverage(registry: Registry, manifest: CapturedStatesManifest, baseline?: PageCoverageBaseline): Diagnostic[];
|
|
547
|
+
/**
|
|
548
|
+
* Compute the shrink-only baseline for `--update-baseline`: every route with no
|
|
549
|
+
* capture and no opt-out. Seeds on first run and prunes on later runs; growth
|
|
550
|
+
* only ever happens through this explicit command, visible in the file's diff.
|
|
551
|
+
*/
|
|
552
|
+
declare function computePageBaseline(registry: Registry, manifest: CapturedStatesManifest): PageCoverageBaseline;
|
|
553
|
+
|
|
386
554
|
interface AuditOptions {
|
|
387
555
|
registry: Registry;
|
|
388
556
|
extracted: ExtractedFile[];
|
|
@@ -393,12 +561,28 @@ interface AuditOptions {
|
|
|
393
561
|
check?: boolean;
|
|
394
562
|
lint?: boolean;
|
|
395
563
|
resolveDiagnostics?: Diagnostic[];
|
|
396
|
-
/** Freshly-emitted
|
|
564
|
+
/** Freshly-emitted DATA-file bytes (the entity array), required for --check. */
|
|
397
565
|
generated?: string;
|
|
398
|
-
/** On-disk contents of the
|
|
566
|
+
/** On-disk contents of the data file at scan time; `null` if it does not exist. */
|
|
399
567
|
existingOnDisk?: string | null;
|
|
400
|
-
/** Relative path of the
|
|
568
|
+
/** Relative path of the data file; used in diagnostics. */
|
|
401
569
|
outputPath?: string;
|
|
570
|
+
/** Freshly-emitted TYPES-file bytes; enables the types-file --check compare. */
|
|
571
|
+
typesGenerated?: string;
|
|
572
|
+
/** On-disk contents of the types file at scan time; `null` if it does not exist. */
|
|
573
|
+
typesOnDisk?: string | null;
|
|
574
|
+
/** Relative path of the configured `output` (types) file; used in diagnostics. */
|
|
575
|
+
typesOutputPath?: string;
|
|
576
|
+
/** Freshly-emitted LOCS-file bytes; enables the locs-file --check compare. */
|
|
577
|
+
locsGenerated?: string;
|
|
578
|
+
/** On-disk contents of the locs file at scan time; `null` if it does not exist. */
|
|
579
|
+
locsOnDisk?: string | null;
|
|
580
|
+
/** Relative path of the `.locs` file; used in diagnostics. */
|
|
581
|
+
locsOutputPath?: string;
|
|
582
|
+
/** Captured-states manifest for the completeness gate; absent → gate skipped. */
|
|
583
|
+
capturedStates?: CapturedStatesManifest;
|
|
584
|
+
/** Page-coverage baseline (the shrink-only backlog); absent → empty baseline. */
|
|
585
|
+
pageBaseline?: PageCoverageBaseline;
|
|
402
586
|
}
|
|
403
587
|
declare function audit(opts: AuditOptions): AuditSummary;
|
|
404
588
|
|
|
@@ -408,16 +592,56 @@ interface EmitOptions {
|
|
|
408
592
|
/** The import source for `createUidex` in the generated preconfigured export. */
|
|
409
593
|
uidexImport?: string;
|
|
410
594
|
}
|
|
411
|
-
|
|
595
|
+
/**
|
|
596
|
+
* The scanner emits THREE artifacts, split by consumer:
|
|
597
|
+
*
|
|
598
|
+
* - `types` — the id unions + the `Uidex` authoring-shape namespace. Pure types,
|
|
599
|
+
* no runtime, no `@ts-nocheck`. This is the file the ~dozens of
|
|
600
|
+
* `import type { Uidex } from "@/uidex.gen"` sites resolve, so it must stay
|
|
601
|
+
* small: an `import type` still forces tsc/tsserver to fully parse the target
|
|
602
|
+
* module, so keeping the runtime entity data out of it is what keeps the editor
|
|
603
|
+
* and type-checker responsive across every consumer file.
|
|
604
|
+
* - `data` — the AUTHORED registry (route/page/feature/widget/primitive/flow) +
|
|
605
|
+
* `gitContext` + `loadRegistry` + the preconfigured `uidex` instance. Runtime,
|
|
606
|
+
* `@ts-nocheck`. Loaded eagerly by the devtools on mount.
|
|
607
|
+
* - `locs` — the thin element/region `{ id, loc }` entities, emitted as positional
|
|
608
|
+
* tuples (see `emitLocsModule`). Loaded lazily by the devtools (idle / first
|
|
609
|
+
* inspect) via `loadLocs`, so ~90% of the entity count stays out of the initial
|
|
610
|
+
* devtools chunk.
|
|
611
|
+
*/
|
|
612
|
+
interface EmitResult {
|
|
613
|
+
types: string;
|
|
614
|
+
/** Authored-metadata registry (pages/features/widgets/flows/…). */
|
|
615
|
+
data: string;
|
|
616
|
+
/** Deferred `id → loc` module for the thin element/region entities. */
|
|
617
|
+
locs: string;
|
|
618
|
+
}
|
|
619
|
+
declare function emit(opts: EmitOptions): EmitResult;
|
|
412
620
|
|
|
413
621
|
/**
|
|
414
622
|
* Detect framework-aware routes:
|
|
415
623
|
* - Next.js App Router: `**\/app/**\/page.tsx` -> `/segments`
|
|
416
624
|
* - Next.js Pages Router: `**\/pages/**\/*.tsx` -> `/segments` (excludes _app, _document, api/)
|
|
417
|
-
* - Vite +
|
|
418
|
-
*
|
|
625
|
+
* - Vite + TanStack Router / React Router: `**\/routes/**\/*.tsx` -> `/segments`.
|
|
626
|
+
* Honors TanStack conventions: pathless layouts (`_layout`) and route
|
|
627
|
+
* groups (`(group)`) drop from the path, the folder route file
|
|
628
|
+
* (`route.tsx`) collapses like `index`, `-`-prefixed and `api/` files are
|
|
629
|
+
* excluded, and flat dot-notation filenames (`a.b.$c.tsx`) split into
|
|
630
|
+
* nested segments. Dynamic segments are normalized to the canonical
|
|
631
|
+
* `[param]` form used everywhere else in the pipeline: `$id` -> `[id]`,
|
|
632
|
+
* the splat `$` -> `[...splat]`, and `[.]`-escaped literals are unwrapped.
|
|
419
633
|
*/
|
|
420
|
-
|
|
634
|
+
interface DetectRoutesOptions {
|
|
635
|
+
/**
|
|
636
|
+
* Explicit routes root, as it appears in `displayPath` (relative to the
|
|
637
|
+
* config dir). When set, only files under this dir are routes and the
|
|
638
|
+
* TanStack / React Router `routes/`-style convention is applied — overriding
|
|
639
|
+
* the `app`/`pages`/`routes` directory-name heuristic. Use for a custom
|
|
640
|
+
* TanStack `routesDirectory`.
|
|
641
|
+
*/
|
|
642
|
+
routesDir?: string;
|
|
643
|
+
}
|
|
644
|
+
declare function detectRoutes(files: ScannedFile[], options?: DetectRoutesOptions): DetectedRoute[];
|
|
421
645
|
declare function pathToId(routePath: string): string;
|
|
422
646
|
|
|
423
647
|
interface GitResolveOptions {
|
|
@@ -462,6 +686,20 @@ interface RunScanOptions {
|
|
|
462
686
|
check?: boolean;
|
|
463
687
|
lint?: boolean;
|
|
464
688
|
configs?: DiscoveredConfig[];
|
|
689
|
+
/** Captured-states manifest for the completeness gate; overrides on-disk load. */
|
|
690
|
+
capturedStates?: CapturedStatesManifest;
|
|
691
|
+
/** Page-coverage baseline; overrides on-disk load. */
|
|
692
|
+
pageBaseline?: PageCoverageBaseline;
|
|
693
|
+
}
|
|
694
|
+
/** Load the page-coverage baseline from disk, if present + well-formed. */
|
|
695
|
+
declare function loadPageBaseline(configDir: string, config: UidexConfig): PageCoverageBaseline | undefined;
|
|
696
|
+
/** One generated artifact: its bytes plus where it lands (abs + repo-relative). */
|
|
697
|
+
interface ScanArtifact {
|
|
698
|
+
generated: string;
|
|
699
|
+
/** Absolute path on disk. */
|
|
700
|
+
outputPath: string;
|
|
701
|
+
/** Path relative to the config dir, for diagnostics. */
|
|
702
|
+
outputRel: string;
|
|
465
703
|
}
|
|
466
704
|
interface ScanResult {
|
|
467
705
|
config: UidexConfig;
|
|
@@ -469,11 +707,50 @@ interface ScanResult {
|
|
|
469
707
|
registry: Registry;
|
|
470
708
|
gitContext: GitContext;
|
|
471
709
|
audit?: AuditSummary;
|
|
472
|
-
|
|
473
|
-
|
|
710
|
+
/** Pure-types artifact (`config.output`, e.g. `uidex.gen.ts`). */
|
|
711
|
+
types: ScanArtifact;
|
|
712
|
+
/** Authored-registry artifact (the sibling `.data` module). */
|
|
713
|
+
data: ScanArtifact;
|
|
714
|
+
/** Deferred element/region source-location artifact (the sibling `.locs` module). */
|
|
715
|
+
locs: ScanArtifact;
|
|
716
|
+
/** The captured-states manifest in effect this run, if any (for --update-baseline). */
|
|
717
|
+
capturedStates?: CapturedStatesManifest;
|
|
474
718
|
}
|
|
475
719
|
declare function runScan(opts?: RunScanOptions): ScanResult[];
|
|
476
|
-
|
|
720
|
+
/**
|
|
721
|
+
* Write all three generated artifacts (types + data + locs), each only if
|
|
722
|
+
* changed. Splitting them means a change confined to one (e.g. adding an element
|
|
723
|
+
* only touches `.locs`) never rewrites the others, so watchers recompile only what
|
|
724
|
+
* actually moved. Returns `true` if any file was written.
|
|
725
|
+
*/
|
|
726
|
+
declare function writeScanResult(result: ScanResult): boolean;
|
|
727
|
+
/** Absolute path of the page-coverage baseline for a scan result. */
|
|
728
|
+
declare function pageBaselinePath(result: ScanResult): string;
|
|
729
|
+
|
|
730
|
+
/**
|
|
731
|
+
* State-matrix coverage — the second completeness axis. A capture that only ever
|
|
732
|
+
* shoots the happy path leaves most of the harness's value on the table, so
|
|
733
|
+
* every *captured* route must render each of the four core kinds
|
|
734
|
+
* (loading / empty / populated / error), or account for the gap:
|
|
735
|
+
*
|
|
736
|
+
* - a **waiver** (`export const uidex = { page, waivers: { empty: "…" } }`) —
|
|
737
|
+
* the route CANNOT render that kind (a create form has no empty state);
|
|
738
|
+
* - the **MISSING_KINDS baseline** — the route CAN render it and nobody has
|
|
739
|
+
* captured it yet (a per-(route, kind) shrink-only backlog).
|
|
740
|
+
*
|
|
741
|
+
* Anything else is a `core-kind` error. Only *captured* routes are in scope: a
|
|
742
|
+
* route with no capture at all is a page-coverage concern, not a matrix hole.
|
|
743
|
+
*/
|
|
744
|
+
/** route → core kinds acknowledged as not-yet-captured (the finer ratchet). */
|
|
745
|
+
interface StateMatrixBaseline {
|
|
746
|
+
missingKinds: Record<string, string[]>;
|
|
747
|
+
}
|
|
748
|
+
declare function checkStateMatrix(registry: Registry, manifest: CapturedStatesManifest, baseline?: StateMatrixBaseline): Diagnostic[];
|
|
749
|
+
/**
|
|
750
|
+
* Compute the shrink-only MISSING_KINDS baseline for `--update-baseline`: every
|
|
751
|
+
* (captured route, core kind) that is neither captured nor waived.
|
|
752
|
+
*/
|
|
753
|
+
declare function computeMissingKinds(registry: Registry, manifest: CapturedStatesManifest): Record<string, string[]>;
|
|
477
754
|
|
|
478
755
|
/**
|
|
479
756
|
* Applies the machine-generated fixes attached to diagnostics.
|
|
@@ -563,12 +840,26 @@ declare const DEFAULT_CONVENTIONS: Required<Pick<NonNullable<UidexConfig["conven
|
|
|
563
840
|
* bootstrapping before the first scan).
|
|
564
841
|
*/
|
|
565
842
|
declare namespace Uidex {
|
|
843
|
+
type CoreStateKind = "loading" | "empty" | "populated" | "error";
|
|
844
|
+
type StateKind = CoreStateKind | "variant";
|
|
845
|
+
/** A declared render state, as authored in `states: [{ name, ... }]`. */
|
|
846
|
+
interface State {
|
|
847
|
+
name: string;
|
|
848
|
+
kind?: StateKind;
|
|
849
|
+
acceptance?: readonly string[];
|
|
850
|
+
description?: string;
|
|
851
|
+
}
|
|
852
|
+
/** Per-core-kind waivers: a kind this route cannot render → reason. */
|
|
853
|
+
type Waivers = Partial<Record<CoreStateKind, string>>;
|
|
566
854
|
interface Page<PageIds extends string = string, FeatureIds extends string = string, WidgetIds extends string = string> {
|
|
567
855
|
page: PageIds | false;
|
|
568
856
|
name?: string;
|
|
569
857
|
features?: readonly FeatureIds[];
|
|
570
858
|
widgets?: readonly WidgetIds[];
|
|
571
859
|
acceptance?: readonly string[];
|
|
860
|
+
states?: readonly (string | State)[];
|
|
861
|
+
capture?: boolean;
|
|
862
|
+
waivers?: Waivers;
|
|
572
863
|
description?: string;
|
|
573
864
|
}
|
|
574
865
|
interface Feature<FeatureIds extends string = string> {
|
|
@@ -576,6 +867,7 @@ declare namespace Uidex {
|
|
|
576
867
|
name?: string;
|
|
577
868
|
features?: readonly FeatureIds[];
|
|
578
869
|
acceptance?: readonly string[];
|
|
870
|
+
states?: readonly (string | State)[];
|
|
579
871
|
description?: string;
|
|
580
872
|
}
|
|
581
873
|
interface Primitive<PrimitiveIds extends string = string> {
|
|
@@ -587,6 +879,7 @@ declare namespace Uidex {
|
|
|
587
879
|
widget: WidgetIds;
|
|
588
880
|
name?: string;
|
|
589
881
|
acceptance?: readonly string[];
|
|
882
|
+
states?: readonly (string | State)[];
|
|
590
883
|
description?: string;
|
|
591
884
|
}
|
|
592
885
|
interface Flow<FlowIds extends string = string> {
|
|
@@ -599,4 +892,4 @@ declare namespace Uidex {
|
|
|
599
892
|
}
|
|
600
893
|
}
|
|
601
894
|
|
|
602
|
-
export { type Annotation, type AnnotationKind, type AppliedFix, type ApplyFixesResult, type AuditConfig, type AuditSummary, CONFIG_FILENAME, type CliOptions, type CliResult, ConfigError, type ConventionsConfig, DEFAULT_CONVENTIONS, type DetectedRoute, type Diagnostic, type DiagnosticFix, type DiagnosticSeverity, type DiscoveredConfig, type ExtractedFile, type FixEdit, type GitContext, type ImportFact, type LandmarkFact, type MetadataExport, type MetadataExportKind, type RenameKind, type RenameOptions, type RenameResult, type RunScanOptions, type ScaffoldKind, type ScaffoldOptions, type ScaffoldResult, type ScaffoldSpecOptions, type ScanResult, type ScannedFile, type SourceConfig, type Span, Uidex, type UidexConfig, applyFixes, audit, detectRoutes, discover, emit, extract, extractUidexExports, globToRegExp, parseConfig, pathToId, renameEntity, resolve, resolveGitContext, run as runCli, runScan, scaffoldSpec, scaffoldWidgetSpec, validateConfig, walk, writeScanResult };
|
|
895
|
+
export { type Annotation, type AnnotationKind, type AppliedFix, type ApplyFixesResult, type AuditConfig, type AuditSummary, CONFIG_FILENAME, type CapturedState, type CapturedStatesManifest, type CliOptions, type CliResult, ConfigError, type ConventionsConfig, DEFAULT_CONVENTIONS, type DetectedRoute, type Diagnostic, type DiagnosticFix, type DiagnosticSeverity, type DiscoveredConfig, type ExtractedFile, type FixEdit, type GitContext, type ImportFact, type LandmarkFact, type MetadataExport, type MetadataExportKind, type PageCoverageBaseline, type ParsedState, type RenameKind, type RenameOptions, type RenameResult, type RunScanOptions, type ScaffoldKind, type ScaffoldOptions, type ScaffoldResult, type ScaffoldSpecOptions, type ScanResult, type ScannedFile, type SourceConfig, type Span, type StateMatrixBaseline, Uidex, type UidexConfig, applyFixes, audit, checkPageCoverage, checkStateCoverage, checkStateMatrix, compileRoute, computeMissingKinds, computePageBaseline, detectRoutes, discover, emit, extract, extractUidexExports, globToRegExp, loadPageBaseline, matchUrlToRoute, pageBaselinePath, parseConfig, pathToId, renameEntity, resolve, resolveGitContext, run as runCli, runScan, scaffoldSpec, scaffoldWidgetSpec, validateConfig, walk, writeScanResult };
|