@polyxd/verifier 0.1.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/static.js ADDED
@@ -0,0 +1,235 @@
1
+ import { validateDocument } from "@polyxd/spec";
2
+ import { checkPattern, evaluateRules } from "@polyxd/spec/patterns";
3
+ import { checkCapabilities } from "@polyxd/spec/capabilities";
4
+ import { readingOrder, runCheck } from "@polyxd/spec/checks";
5
+ const INPUTS = new Set(["TextInput", "Choice", "Toggle", "DateInput", "RangeInput"]);
6
+ const GENERIC = /^(ok|okay|yes|no|submit|go|click here|here|more|continue|next|done)$/i;
7
+ const TEXT_PROPS = ["title", "label", "summary", "caption", "text", "message", "consequence"];
8
+ /** Reads a JSON Pointer out of the document's data snapshot, when there is one. */
9
+ function valueAt(data, pointer) {
10
+ if (!pointer || data === undefined)
11
+ return undefined;
12
+ let cur = data;
13
+ for (const part of pointer.replace(/^\//, "").split("/")) {
14
+ if (cur === null || typeof cur !== "object")
15
+ return undefined;
16
+ cur = cur[part.replace(/~1/g, "/").replace(/~0/g, "~")];
17
+ }
18
+ return cur;
19
+ }
20
+ /**
21
+ * The first item a component renders, when it is a collection's template rather than a component
22
+ * in its own right: a Card inside a Collection reads its bindings from each item, so a path like
23
+ * `progress` means the item's progress, not the document's.
24
+ */
25
+ function itemScope(doc, node) {
26
+ const owner = (doc.components ?? []).find((c) => c.items?.componentId === node.id);
27
+ const items = owner ? valueAt(doc.data, owner.items.path) : undefined;
28
+ return Array.isArray(items) ? items[0] : undefined;
29
+ }
30
+ /** An item-scoped path has no leading slash; make it a pointer either way. */
31
+ const pointerIn = (path) => (path === undefined ? undefined : path.startsWith("/") ? path : `/${path}`);
32
+ /**
33
+ * Document-level checks that need no rendering: the spec validator, the declared pattern,
34
+ * capabilities, direction/acceptance rules, plus agent-readiness heuristics.
35
+ */
36
+ export function staticAudit(doc, opts = {}) {
37
+ const out = [];
38
+ const v = validateDocument(doc, { emphasisBudget: opts.emphasisBudget });
39
+ for (const i of v.issues)
40
+ out.push({ severity: i.severity, check: "spec", message: `${i.at}: ${i.message}` });
41
+ if (!v.valid)
42
+ return out;
43
+ for (const r of checkPattern(doc))
44
+ if (!r.pass)
45
+ out.push({ severity: r.severity, check: `pattern:${r.id}`, message: `${r.description}: ${r.message}` });
46
+ if (opts.registry)
47
+ for (const i of checkCapabilities(doc, opts.registry))
48
+ out.push({ severity: i.severity, check: "capability", message: `${i.at}: ${i.message}` });
49
+ if (opts.rules)
50
+ for (const r of evaluateRules(opts.rules, doc))
51
+ if (!r.pass)
52
+ out.push({ severity: r.severity, check: `rule:${r.id}`, message: `${r.description}: ${r.message}` });
53
+ // Short views everywhere, not only in surfaces that declare the multi-step-form pattern.
54
+ if (doc.surface?.pattern !== "multi-step-form") {
55
+ const r = runCheck({ check: "maxInputsPerView", max: 6 }, doc);
56
+ if (!r.pass)
57
+ out.push({ severity: "error", check: "load:inputs-per-view", message: r.message });
58
+ }
59
+ const order = readingOrder(doc);
60
+ // Visible text must say something.
61
+ for (const c of order) {
62
+ for (const p of TEXT_PROPS) {
63
+ if (typeof c[p] === "string" && c[p].trim() === "")
64
+ out.push({ severity: "error", check: "text:empty", message: `${c.id}.${p} is empty` });
65
+ }
66
+ }
67
+ // Controls in one view need distinct names, or neither people nor agents can tell them apart.
68
+ const names = new Map();
69
+ const named = (id, label) => typeof label === "string" && names.set(label.toLowerCase(), [...(names.get(label.toLowerCase()) ?? []), id]);
70
+ for (const c of order) {
71
+ if (INPUTS.has(c.component) || c.component === "Action")
72
+ named(c.id, c.label);
73
+ for (const p of ["submit", "cancel", "confirm", "finish"])
74
+ if (c[p])
75
+ named(`${c.id}.${p}`, c[p].label);
76
+ }
77
+ for (const [label, ids] of names) {
78
+ if (ids.length > 1)
79
+ out.push({ severity: "error", check: "agent:ambiguous-name", message: `"${label}" names ${ids.length} controls (${ids.join(", ")})` });
80
+ }
81
+ // Who or what the task is about comes before its details: who before how much, who before when.
82
+ const detail = (c) => (c.component === "TextInput" && ["currency", "number"].includes(c.kind)) || c.component === "DateInput" || c.component === "RangeInput";
83
+ // The entity is a picker of people or things from host data: faces, or a "who is this for" label.
84
+ const WHO = /\b(who|whom|recipient|payee|person|people|contact|customer|account|guest|attendee|member|supplier|client)\b/i;
85
+ const entity = (c) => c.component === "Choice" && !Array.isArray(c.options) && (!!c.options?.avatarPath || !!c.options?.imagePath || (typeof c.label === "string" && WHO.test(c.label)));
86
+ const firstDetail = order.findIndex(detail);
87
+ const firstEntity = order.findIndex(entity);
88
+ if (firstEntity > -1 && firstDetail > -1 && firstEntity > firstDetail) {
89
+ out.push({
90
+ severity: "warning",
91
+ check: "flow:entity-first",
92
+ message: `"${order[firstEntity].id}" names who this is for but comes after "${order[firstDetail].id}": ask who before how much`,
93
+ });
94
+ }
95
+ // A typed confirmation is for irreversible, high-impact actions. Asking for it elsewhere
96
+ // teaches people to type past it.
97
+ for (const c of order) {
98
+ if (c.component === "Confirm" && c.typeToConfirm !== undefined && c.severity !== "destructive") {
99
+ out.push({ severity: "warning", check: "safety:typed-confirm", message: `${c.id} asks people to type "${c.typeToConfirm}" for an action that is not destructive` });
100
+ }
101
+ }
102
+ // Exactly one option may be recommended, or the recommendation means nothing.
103
+ for (const c of order) {
104
+ if (c.component !== "Comparison" || c.recommended === undefined)
105
+ continue;
106
+ const items = valueAt(doc.data, c.items?.path);
107
+ if (!Array.isArray(items))
108
+ continue;
109
+ const wanted = typeof c.recommended === "string" ? c.recommended : valueAt(doc.data, c.recommended.path);
110
+ const matches = items.filter((it) => String(valueAt(it, "/" + c.itemTitle) ?? "") === String(wanted ?? ""));
111
+ if (matches.length !== 1) {
112
+ out.push({ severity: matches.length ? "error" : "warning", check: "choice:one-recommendation", message: `${c.id} recommends "${wanted}", which matches ${matches.length} of ${items.length} options` });
113
+ }
114
+ }
115
+ // A whole-card click has no label of its own: its accessible name is the card's title, which
116
+ // says what the thing is, not what pressing it does. Opening something that way is fine (risk
117
+ // "none"); inviting people to a meeting is not. A card opens a thing, a button does a thing.
118
+ if (opts.registry) {
119
+ for (const c of order) {
120
+ if (c.component !== "Card" && c.component !== "Collection")
121
+ continue;
122
+ const event = c.action?.event?.name;
123
+ const risk = event ? opts.registry.capabilities[event]?.risk : undefined;
124
+ if (risk && risk !== "none") {
125
+ out.push({
126
+ severity: "error",
127
+ check: "flow:unnamed-commit",
128
+ message: `${c.id} runs ${event} (${risk}) when the whole card is clicked: a card opens a thing, a button does a thing`,
129
+ });
130
+ }
131
+ }
132
+ }
133
+ // A progress bar is a fraction of something finished. Bound to an amount of money, or to a
134
+ // field that isn't there, it draws a bar whose length means nothing.
135
+ for (const c of order) {
136
+ if (!c.progress)
137
+ continue;
138
+ const value = typeof c.progress.value === "number" ? c.progress.value : valueAt(itemScope(doc, c) ?? doc.data, pointerIn(c.progress.value?.path));
139
+ if (typeof value !== "number" || Number.isNaN(value)) {
140
+ out.push({ severity: "error", check: "data:progress-not-a-fraction", message: `${c.id}.progress reads ${c.progress.value?.path ?? "a value"}, which isn't a number` });
141
+ }
142
+ else if (value < 0 || value > 1) {
143
+ out.push({ severity: "error", check: "data:progress-not-a-fraction", message: `${c.id}.progress is ${value}: progress runs from 0 to 1, so this bar's length means nothing` });
144
+ }
145
+ }
146
+ // A description under a label has to add something. "Email → Receive email alerts" is the label
147
+ // again with filler around it, and it costs a line of reading for nothing.
148
+ const FILLER = /^(receive|get|send|show|enable|allow|turn|on|off|and|or|the|a|an|your|you|via|by|to|for|of|with|in|me|us|notification|notifications|alert|alerts|email|emails|message|messages|update|updates|setting|settings)$/i;
149
+ const words = (s) => s.toLowerCase().match(/[a-z0-9']+/g) ?? [];
150
+ for (const c of order) {
151
+ const label = typeof c.label === "string" ? c.label : typeof c.title === "string" ? c.title : undefined;
152
+ const description = typeof c.description === "string" ? c.description : typeof c.subtitle === "string" ? c.subtitle : undefined;
153
+ if (!label || !description)
154
+ continue;
155
+ const inLabel = new Set(words(label));
156
+ const extra = words(description).filter((w) => !inLabel.has(w) && !FILLER.test(w));
157
+ if (extra.length === 0) {
158
+ out.push({ severity: "warning", check: "copy:empty-description", message: `${c.id}: "${description}" is "${label}" again — a description has to say something the label doesn't` });
159
+ }
160
+ }
161
+ // A template the model has no engine for. "{{budget}}" reaches the screen verbatim.
162
+ for (const c of order) {
163
+ for (const [prop, value] of Object.entries(c)) {
164
+ if (typeof value !== "string")
165
+ continue;
166
+ const found = value.match(/\{\{[^}]*\}\}|\$\{[^}]*\}/)?.[0];
167
+ if (found)
168
+ out.push({ severity: "error", check: "text:template-placeholder", message: `${c.id}.${prop}: "${found}" is a template placeholder, not text — bind the value instead` });
169
+ }
170
+ }
171
+ // A binding that resolves to an object or an array where text belongs prints "[object Object]".
172
+ const TEXT_BINDINGS = [
173
+ ["items", (c) => (Array.isArray(c.items) ? c.items.flatMap((i, n) => [{ where: `items[${n}].value`, path: i.value?.path }]) : [])],
174
+ ["value", (c) => [{ where: "value", path: c.value?.path }]],
175
+ ["text", (c) => [{ where: "text", path: c.text?.path }]],
176
+ ["title", (c) => [{ where: "title", path: c.title?.path }]],
177
+ ["subtitle", (c) => [{ where: "subtitle", path: c.subtitle?.path }]],
178
+ ];
179
+ for (const c of order) {
180
+ // An input's `value` is its state, not text: a multi-select holds a list, a range holds a pair.
181
+ if (INPUTS.has(c.component))
182
+ continue;
183
+ for (const [, read] of TEXT_BINDINGS) {
184
+ for (const { where, path } of read(c)) {
185
+ if (!path)
186
+ continue;
187
+ const value = valueAt(itemScope(doc, c) ?? doc.data, pointerIn(path));
188
+ if (value !== null && typeof value === "object") {
189
+ out.push({ severity: "error", check: "data:not-text", message: `${c.id}.${where} reads ${path}, which is ${Array.isArray(value) ? "a list" : "an object"}: it would print as [object Object]` });
190
+ }
191
+ }
192
+ }
193
+ }
194
+ // An internal id is not a name. "pr_1" tells a person nothing about which project they are
195
+ // deleting, and the record it came from usually carries the name right next to it.
196
+ const ID = /^[a-z]{1,4}[-_]?\d+$/i;
197
+ for (const c of order) {
198
+ // Same reason: the value an input holds is a key, and a key is allowed to look like one.
199
+ if (INPUTS.has(c.component))
200
+ continue;
201
+ const scope = itemScope(doc, c) ?? doc.data;
202
+ const shown = [
203
+ ...(Array.isArray(c.items) ? c.items.map((i, n) => ({ where: `items[${n}]`, path: i.value?.path })) : []),
204
+ { where: "value", path: c.value?.path },
205
+ { where: "title", path: c.title?.path },
206
+ ];
207
+ for (const { where, path } of shown) {
208
+ if (!path)
209
+ continue;
210
+ const value = valueAt(scope, pointerIn(path));
211
+ if (typeof value !== "string" || !ID.test(value))
212
+ continue;
213
+ // Only a problem when the same record offers something readable instead.
214
+ const record = valueAt(scope, pointerIn(path.replace(/\/[^/]+$/, "")));
215
+ const better = record && typeof record === "object" ? ["name", "title", "label"].find((k) => typeof record[k] === "string") : undefined;
216
+ if (better)
217
+ out.push({ severity: "warning", check: "copy:raw-identifier", message: `${c.id}.${where} shows "${value}", an internal id, where ${path.replace(/\/[^/]+$/, "")}/${better} is a name` });
218
+ }
219
+ }
220
+ // Action labels should say what happens.
221
+ for (const c of order) {
222
+ const labels = [[c.id, c.component === "Action" ? c.label : undefined], ...["submit", "confirm", "finish"].map((p) => [`${c.id}.${p}`, c[p]?.label])];
223
+ for (const [where, label] of labels) {
224
+ if (typeof label !== "string")
225
+ continue;
226
+ if (GENERIC.test(label.trim()) && !(where.endsWith(".submit") && c.component === "Form" && doc.surface?.pattern === "multi-step-form" && /^continue$/i.test(label))) {
227
+ out.push({ severity: "warning", check: "copy:generic-label", message: `${where}: "${label}" doesn't say what happens` });
228
+ }
229
+ if (label.length > 40)
230
+ out.push({ severity: "warning", check: "copy:long-label", message: `${where}: ${label.length}-character button label` });
231
+ }
232
+ }
233
+ return out;
234
+ }
235
+ //# sourceMappingURL=static.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"static.js","sourceRoot":"","sources":["../src/static.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,43 @@
1
+ import type { Browser } from "playwright";
2
+ import { type RenderTarget } from "./browser.ts";
3
+ import { type Finding } from "./rendered.ts";
4
+ import { type AgentResult, type Task } from "./agent.ts";
5
+ import { type StaticOptions } from "./static.ts";
6
+ export interface VerifyOptions extends StaticOptions {
7
+ themes?: string[];
8
+ modes?: ("light" | "dark")[];
9
+ widths?: number[];
10
+ /** Agent tasks to run on this document, in every target */
11
+ tasks?: Task[];
12
+ /** Reuse a browser across many documents */
13
+ browser?: Browser;
14
+ }
15
+ export interface TargetReport extends RenderTarget {
16
+ findings: Finding[];
17
+ agent: (AgentResult & {
18
+ task: string;
19
+ })[];
20
+ }
21
+ export interface Report {
22
+ surface: string;
23
+ static: Finding[];
24
+ targets: TargetReport[];
25
+ errors: number;
26
+ warnings: number;
27
+ agentSuccess: number;
28
+ agentRuns: number;
29
+ /** 0–100. 100 = no errors, warnings or failed tasks anywhere. */
30
+ score: number;
31
+ }
32
+ export declare const DEFAULTS: {
33
+ themes: string[];
34
+ modes: ("light" | "dark")[];
35
+ widths: number[];
36
+ };
37
+ /**
38
+ * Scoring (v0): start at 100; each distinct error check costs 20 (once per check, not per target,
39
+ * so one broken thing isn't counted six times), each distinct warning 4, and failed agent runs
40
+ * cost up to 40 in proportion. Floors at 0.
41
+ */
42
+ export declare function score(r: Omit<Report, "score">): number;
43
+ export declare function verifyDocument(doc: any, opts?: VerifyOptions): Promise<Report>;
package/dist/verify.js ADDED
@@ -0,0 +1,81 @@
1
+ import { launch, renderPage } from "./browser.js";
2
+ import { axeAudit, layoutAudit } from "./rendered.js";
3
+ import { runTask } from "./agent.js";
4
+ import { staticAudit } from "./static.js";
5
+ export const DEFAULTS = { themes: ["material3", "carbon", "antd"], modes: ["light", "dark"], widths: [390, 1100] };
6
+ /**
7
+ * Scoring (v0): start at 100; each distinct error check costs 20 (once per check, not per target,
8
+ * so one broken thing isn't counted six times), each distinct warning 4, and failed agent runs
9
+ * cost up to 40 in proportion. Floors at 0.
10
+ */
11
+ export function score(r) {
12
+ const all = [...r.static, ...r.targets.flatMap((t) => t.findings)];
13
+ const distinct = (sev) => new Set(all.filter((f) => f.severity === sev).map((f) => f.check)).size;
14
+ const agentPenalty = r.agentRuns ? 40 * (1 - r.agentSuccess / r.agentRuns) : 0;
15
+ return Math.max(0, Math.round(100 - 20 * distinct("error") - 4 * distinct("warning") - agentPenalty));
16
+ }
17
+ export async function verifyDocument(doc, opts = {}) {
18
+ const staticFindings = staticAudit(doc, opts);
19
+ const targets = [];
20
+ const invalid = staticFindings.some((f) => f.check === "spec" && f.severity === "error");
21
+ if (!invalid) {
22
+ const browser = opts.browser ?? (await launch());
23
+ try {
24
+ for (const theme of opts.themes ?? DEFAULTS.themes) {
25
+ for (const mode of opts.modes ?? DEFAULTS.modes) {
26
+ for (const width of opts.widths ?? DEFAULTS.widths) {
27
+ const target = { theme, mode, width };
28
+ let page;
29
+ let errors;
30
+ try {
31
+ ({ page, errors } = await renderPage(browser, doc, target));
32
+ }
33
+ catch (e) {
34
+ // Timed out or crashed before the surface was ready: that is the renderer's problem
35
+ // with this document, and the run carries on.
36
+ targets.push({ ...target, findings: [{ severity: "error", check: "runtime:render", message: `did not finish rendering: ${e.message.split("\n")[0]}` }], agent: [] });
37
+ continue;
38
+ }
39
+ const rendered = await page.evaluate(() => !!document.querySelector(".pxd-surface"));
40
+ if (!rendered) {
41
+ // The renderer threw: a schema-valid document it can't display is a renderer bug.
42
+ targets.push({ ...target, findings: [{ severity: "error", check: "runtime:render", message: errors[0] ?? "surface did not render" }], agent: [] });
43
+ await page.close();
44
+ continue;
45
+ }
46
+ const findings = [...(await axeAudit(page)), ...(await layoutAudit(page))];
47
+ const agent = [];
48
+ for (const task of opts.tasks ?? []) {
49
+ // Each task gets a fresh render so earlier tasks can't leave state behind.
50
+ const fresh = agent.length === 0 ? page : (await renderPage(browser, doc, target)).page;
51
+ agent.push({ task: task.id, ...(await runTask(fresh, task)) });
52
+ if (fresh !== page)
53
+ await fresh.close();
54
+ }
55
+ for (const e of errors)
56
+ findings.push({ severity: "error", check: "runtime", message: e });
57
+ targets.push({ ...target, findings, agent });
58
+ await page.close();
59
+ }
60
+ }
61
+ }
62
+ }
63
+ finally {
64
+ if (!opts.browser)
65
+ await browser.close();
66
+ }
67
+ }
68
+ const all = [...staticFindings, ...targets.flatMap((t) => t.findings)];
69
+ const runs = targets.flatMap((t) => t.agent);
70
+ const base = {
71
+ surface: doc?.surface?.id ?? "(invalid)",
72
+ static: staticFindings,
73
+ targets,
74
+ errors: all.filter((f) => f.severity === "error").length,
75
+ warnings: all.filter((f) => f.severity === "warning").length,
76
+ agentSuccess: runs.filter((r) => r.success).length,
77
+ agentRuns: runs.length,
78
+ };
79
+ return { ...base, score: invalid ? 0 : score(base) };
80
+ }
81
+ //# sourceMappingURL=verify.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verify.js","sourceRoot":"","sources":["../src/verify.ts"],"names":[],"mappings":"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"}