usedesign 0.9.0 → 0.10.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.
@@ -0,0 +1,66 @@
1
+ /**
2
+ * The form-inventory producer helper — the missing half of check 5's adoption story (issue #7:
3
+ * checks 1–3 were adoptable in an hour because a tool turns an existing artefact into their
4
+ * inventory; check 5 had nothing, so authored contracts sat verifying nothing).
5
+ *
6
+ * The division of labour follows the issue's own suggestion: the FRAMEWORK-SPECIFIC part —
7
+ * rendering a component in each entity state — stays in the adopter's test, where it belongs;
8
+ * the CONVENTION — which anchors count, how containers chain — lives here, where it belongs,
9
+ * so that projects stop inventing divergent conventions in every copy of the same file.
10
+ *
11
+ * The convention, proven on two panels and a modal before it was written down:
12
+ * data-field — a value the user sees → fields
13
+ * data-section — a container with an identity → fields (containers are content too)
14
+ * data-panel-head — the panel's chrome header → the fixed name "panel-head"
15
+ * data-action — an interactive control → controls
16
+ * data-control — a container-flavoured control → a container in `within` chains
17
+ * `within` records, per anchor, EVERY container ancestor (data-section / data-panel-head /
18
+ * data-control) across all instances — the full chain, not the nearest parent, deliberately:
19
+ * a flat contract may seat a member at any level, and intermediate undescribed containers must
20
+ * not read as misplacement. Collect from document.body when menus or overlays render through a
21
+ * portal — a component that renders outside its own container is honestly rendered all the same.
22
+ *
23
+ * No DOM library is imported: the structural types below match any standards-shaped DOM
24
+ * (jsdom under vitest/jest, happy-dom, a real browser). No dependencies — this must run inside
25
+ * somebody else's test file via `npx`-installed usedesign.
26
+ */
27
+ interface ElementLike {
28
+ getAttribute(name: string): string | null;
29
+ hasAttribute(name: string): boolean;
30
+ parentElement: ElementLike | null;
31
+ }
32
+ interface RootLike {
33
+ querySelectorAll(selector: string): Iterable<ElementLike> & ArrayLike<ElementLike>;
34
+ querySelector(selector: string): ElementLike | null;
35
+ }
36
+ export interface CollectedState {
37
+ fields: Set<string>;
38
+ controls: Set<string>;
39
+ within: Map<string, Set<string>>;
40
+ }
41
+ /** Walk one rendered root and collect the anchors the convention defines. */
42
+ export declare function collectScreenState(root: RootLike): CollectedState;
43
+ /** Merge several renders of ONE state (a screen re-rendered with different data still carries one state). */
44
+ export declare function mergeStates(states: CollectedState[]): CollectedState;
45
+ /** One state entry, JSON-ready, with a stable order — a regenerated inventory that did not change must be byte-identical. */
46
+ export declare function stateEntry(state: string, collected: CollectedState): {
47
+ state: string;
48
+ fields: string[];
49
+ controls: string[];
50
+ within: {
51
+ [k: string]: string[];
52
+ };
53
+ };
54
+ /** The whole document check 5 consumes. `producedBy` must say HOW it was made — and its limits. */
55
+ export declare function formInventoryDocument(producedBy: string, forms: {
56
+ screen: string;
57
+ states: ReturnType<typeof stateEntry>[];
58
+ }[]): {
59
+ usedesign_form_inventory: number;
60
+ produced_by: string;
61
+ forms: {
62
+ screen: string;
63
+ states: ReturnType<typeof stateEntry>[];
64
+ }[];
65
+ };
66
+ export {};
@@ -0,0 +1,96 @@
1
+ /**
2
+ * The form-inventory producer helper — the missing half of check 5's adoption story (issue #7:
3
+ * checks 1–3 were adoptable in an hour because a tool turns an existing artefact into their
4
+ * inventory; check 5 had nothing, so authored contracts sat verifying nothing).
5
+ *
6
+ * The division of labour follows the issue's own suggestion: the FRAMEWORK-SPECIFIC part —
7
+ * rendering a component in each entity state — stays in the adopter's test, where it belongs;
8
+ * the CONVENTION — which anchors count, how containers chain — lives here, where it belongs,
9
+ * so that projects stop inventing divergent conventions in every copy of the same file.
10
+ *
11
+ * The convention, proven on two panels and a modal before it was written down:
12
+ * data-field — a value the user sees → fields
13
+ * data-section — a container with an identity → fields (containers are content too)
14
+ * data-panel-head — the panel's chrome header → the fixed name "panel-head"
15
+ * data-action — an interactive control → controls
16
+ * data-control — a container-flavoured control → a container in `within` chains
17
+ * `within` records, per anchor, EVERY container ancestor (data-section / data-panel-head /
18
+ * data-control) across all instances — the full chain, not the nearest parent, deliberately:
19
+ * a flat contract may seat a member at any level, and intermediate undescribed containers must
20
+ * not read as misplacement. Collect from document.body when menus or overlays render through a
21
+ * portal — a component that renders outside its own container is honestly rendered all the same.
22
+ *
23
+ * No DOM library is imported: the structural types below match any standards-shaped DOM
24
+ * (jsdom under vitest/jest, happy-dom, a real browser). No dependencies — this must run inside
25
+ * somebody else's test file via `npx`-installed usedesign.
26
+ */
27
+ /** Walk one rendered root and collect the anchors the convention defines. */
28
+ export function collectScreenState(root) {
29
+ const fields = new Set();
30
+ const controls = new Set();
31
+ const within = new Map();
32
+ const note = (name, el) => {
33
+ const chain = within.get(name) ?? new Set();
34
+ for (let p = el.parentElement; p; p = p.parentElement) {
35
+ if (p.hasAttribute("data-section"))
36
+ chain.add(p.getAttribute("data-section"));
37
+ if (p.hasAttribute("data-panel-head"))
38
+ chain.add("panel-head");
39
+ if (p.hasAttribute("data-control"))
40
+ chain.add(p.getAttribute("data-control"));
41
+ }
42
+ within.set(name, chain);
43
+ };
44
+ for (const el of Array.from(root.querySelectorAll("[data-field]"))) {
45
+ const name = el.getAttribute("data-field");
46
+ fields.add(name);
47
+ note(name, el);
48
+ }
49
+ for (const el of Array.from(root.querySelectorAll("[data-section]"))) {
50
+ const name = el.getAttribute("data-section");
51
+ fields.add(name);
52
+ note(name, el);
53
+ }
54
+ const head = root.querySelector("[data-panel-head]");
55
+ if (head) {
56
+ fields.add("panel-head");
57
+ note("panel-head", head);
58
+ }
59
+ for (const el of Array.from(root.querySelectorAll("[data-action]"))) {
60
+ const name = el.getAttribute("data-action");
61
+ controls.add(name);
62
+ note(name, el);
63
+ }
64
+ return { fields, controls, within };
65
+ }
66
+ /** Merge several renders of ONE state (a screen re-rendered with different data still carries one state). */
67
+ export function mergeStates(states) {
68
+ const merged = { fields: new Set(), controls: new Set(), within: new Map() };
69
+ for (const state of states) {
70
+ for (const f of state.fields)
71
+ merged.fields.add(f);
72
+ for (const c of state.controls)
73
+ merged.controls.add(c);
74
+ for (const [name, chain] of state.within) {
75
+ const mine = merged.within.get(name) ?? new Set();
76
+ for (const c of chain)
77
+ mine.add(c);
78
+ merged.within.set(name, mine);
79
+ }
80
+ }
81
+ return merged;
82
+ }
83
+ /** One state entry, JSON-ready, with a stable order — a regenerated inventory that did not change must be byte-identical. */
84
+ export function stateEntry(state, collected) {
85
+ return {
86
+ state,
87
+ fields: [...collected.fields].sort(),
88
+ controls: [...collected.controls].sort(),
89
+ within: Object.fromEntries([...collected.within.entries()].sort(([a], [b]) => a.localeCompare(b)).map(([k, v]) => [k, [...v].sort()])),
90
+ };
91
+ }
92
+ /** The whole document check 5 consumes. `producedBy` must say HOW it was made — and its limits. */
93
+ export function formInventoryDocument(producedBy, forms) {
94
+ return { usedesign_form_inventory: 1, produced_by: producedBy, forms };
95
+ }
96
+ //# sourceMappingURL=formInventory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"formInventory.js","sourceRoot":"","sources":["../src/formInventory.ts"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -5,3 +5,5 @@ export { validate, validateSchema, schemaPathFor, MATURITY } from "./validate.js
5
5
  export { CHECKS, checkRoutes, checkCoverage, checkMaturity, normalise, findCases, evidencePaths } from "./checks.js";
6
6
  export type { CheckResult, TestCase } from "./checks.js";
7
7
  export { runCardCorpus, runChecksCorpus } from "./conformance.js";
8
+ export { collectScreenState, mergeStates, stateEntry, formInventoryDocument } from "./formInventory.js";
9
+ export type { CollectedState } from "./formInventory.js";
package/dist/index.js CHANGED
@@ -3,4 +3,5 @@ export { Finding, codesOf, errors, warnings, frontMatter, loadConfig, loadCardFi
3
3
  export { validate, validateSchema, schemaPathFor, MATURITY } from "./validate.js";
4
4
  export { CHECKS, checkRoutes, checkCoverage, checkMaturity, normalise, findCases, evidencePaths } from "./checks.js";
5
5
  export { runCardCorpus, runChecksCorpus } from "./conformance.js";
6
+ export { collectScreenState, mergeStates, stateEntry, formInventoryDocument } from "./formInventory.js";
6
7
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEjI,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAErH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,4FAA4F;AAC5F,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,WAAW,EAAE,UAAU,EAAE,aAAa,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,WAAW,CAAC;AAEjI,OAAO,EAAE,QAAQ,EAAE,cAAc,EAAE,aAAa,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAClF,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,EAAE,aAAa,EAAE,SAAS,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAErH,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAClE,OAAO,EAAE,kBAAkB,EAAE,WAAW,EAAE,UAAU,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "usedesign",
3
- "version": "0.9.0",
3
+ "version": "0.10.0",
4
4
  "description": "Validate and check Operation Cards: no wild endpoints, no unproven steps, no maturity beyond its evidence.",
5
5
  "license": "Apache-2.0",
6
6
  "repository": {