@ingcreators/annot-product-docs 0.2.0 → 0.4.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/CHANGELOG.md +453 -0
- package/README.md +37 -2
- package/dist/annotations-yaml.d.ts +291 -0
- package/dist/config.d.ts +23 -141
- package/dist/deprecation.d.ts +58 -0
- package/dist/drift.d.ts +98 -3
- package/dist/fixture.d.ts +45 -15
- package/dist/index.d.ts +13 -5
- package/dist/index.js +1768 -488
- package/dist/mdx-annotations.d.ts +162 -0
- package/dist/migrate-overlays-to-annotations.d.ts +49 -0
- package/dist/migrate-to-element-tree.d.ts +102 -0
- package/dist/playwright-screenshot-hook.d.ts +17 -0
- package/dist/types-config.d.ts +22 -0
- package/dist/types.d.ts +45 -0
- package/package.json +13 -8
package/dist/index.js
CHANGED
|
@@ -1,338 +1,84 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import l from "js-yaml";
|
|
1
|
+
import { annotSourceResolvers as e, playwrightYamlToElementTree as t, test as n } from "@ingcreators/annot-playwright";
|
|
2
|
+
import { mkdir as r, readFile as i, readdir as a, writeFile as o } from "node:fs/promises";
|
|
3
|
+
import s, { dump as c, load as l } from "js-yaml";
|
|
5
4
|
import u from "remark-frontmatter";
|
|
6
5
|
import d from "remark-mdx";
|
|
7
6
|
import f from "remark-parse";
|
|
8
|
-
import { unified as
|
|
9
|
-
import { visit as
|
|
10
|
-
import { z as
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
for (let e of n) {
|
|
15
|
-
if (!e.trim()) continue;
|
|
16
|
-
let n = e.length - e.replace(/^\s+/, "").length, i = Math.floor(n / 2), a = e.match(/^\s*-\s+([a-z]+)(?:\s+"([^"]*?)")?/);
|
|
17
|
-
if (!a) continue;
|
|
18
|
-
let o = a[1] ?? "", s = a[2] ?? "";
|
|
19
|
-
for (; r.length > 0 && (r[r.length - 1]?.depth ?? -1) >= i;) r.pop();
|
|
20
|
-
let c = r.map((e) => ({
|
|
21
|
-
role: e.role,
|
|
22
|
-
name: e.name
|
|
23
|
-
})), l = e.match(/\[ref=(e\d+)\]/);
|
|
24
|
-
l && t.push({
|
|
25
|
-
role: o,
|
|
26
|
-
name: s,
|
|
27
|
-
ref: l[1] ?? "",
|
|
28
|
-
depth: i,
|
|
29
|
-
ancestors: c
|
|
30
|
-
}), /:\s*$/.test(e) && r.push({
|
|
31
|
-
depth: i,
|
|
32
|
-
role: o,
|
|
33
|
-
name: s
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
return t;
|
|
37
|
-
}
|
|
38
|
-
async function _(e, t, n) {
|
|
39
|
-
let r = te(t.filter((t) => t.role === e.role && t.name === e.name), e.under);
|
|
40
|
-
if (r.length === 0) return ne(e, t);
|
|
41
|
-
if (r.length > 1) return {
|
|
42
|
-
ok: !1,
|
|
43
|
-
kind: "ambiguous",
|
|
44
|
-
reason: `Multiple elements match role="${e.role}" name="${e.name}". Use \`under\` to disambiguate.`,
|
|
45
|
-
candidates: r.map((e) => `[ref=${e.ref}]`)
|
|
46
|
-
};
|
|
47
|
-
let i = r[0], a = v(n, e), o = await a.count();
|
|
48
|
-
return o === 0 ? {
|
|
49
|
-
ok: !1,
|
|
50
|
-
kind: "live-mismatch",
|
|
51
|
-
reason: `Snapshot says element exists but live locator failed: role="${e.role}" name="${e.name}".`
|
|
52
|
-
} : o > 1 ? {
|
|
53
|
-
ok: !1,
|
|
54
|
-
kind: "ambiguous",
|
|
55
|
-
reason: `Live locator returns ${o} elements for role="${e.role}" name="${e.name}".`
|
|
56
|
-
} : {
|
|
57
|
-
ok: !0,
|
|
58
|
-
locator: a,
|
|
59
|
-
entry: i
|
|
60
|
-
};
|
|
61
|
-
}
|
|
62
|
-
async function ee(e, t, n) {
|
|
63
|
-
let r = [];
|
|
64
|
-
for (let i of e) r.push({
|
|
65
|
-
overlay: i,
|
|
66
|
-
result: await _(i.match, t, n)
|
|
67
|
-
});
|
|
68
|
-
return r;
|
|
69
|
-
}
|
|
70
|
-
function v(e, t) {
|
|
71
|
-
let n = e.getByRole(t.role, {
|
|
72
|
-
name: t.name,
|
|
73
|
-
exact: !0
|
|
74
|
-
});
|
|
75
|
-
return t.under && (n = e.getByRole(t.under.role, {
|
|
76
|
-
name: t.under.name,
|
|
77
|
-
exact: !0
|
|
78
|
-
}).getByRole(t.role, {
|
|
79
|
-
name: t.name,
|
|
80
|
-
exact: !0
|
|
81
|
-
})), n;
|
|
82
|
-
}
|
|
83
|
-
function te(e, t) {
|
|
84
|
-
return t ? e.filter((e) => e.ancestors.some((e) => e.role === t.role && e.name === t.name)) : e;
|
|
85
|
-
}
|
|
86
|
-
function ne(e, t) {
|
|
87
|
-
let n = t.filter((t) => t.name === e.name);
|
|
88
|
-
if (n.length === 1 && n[0].role !== e.role) return {
|
|
89
|
-
ok: !1,
|
|
90
|
-
kind: "role-changed",
|
|
91
|
-
reason: `Element with name="${e.name}" exists but has role="${n[0].role}", not "${e.role}".`,
|
|
92
|
-
suggestion: n[0].role
|
|
93
|
-
};
|
|
94
|
-
let r = t.filter((t) => t.role === e.role);
|
|
95
|
-
if (r.length > 0) {
|
|
96
|
-
let t = re(e.name, r.map((e) => e.name));
|
|
97
|
-
if (t) return {
|
|
98
|
-
ok: !1,
|
|
99
|
-
kind: "renamed",
|
|
100
|
-
reason: `No element with role="${e.role}" name="${e.name}". Closest match: name="${t}".`,
|
|
101
|
-
suggestion: t
|
|
102
|
-
};
|
|
103
|
-
}
|
|
104
|
-
return {
|
|
105
|
-
ok: !1,
|
|
106
|
-
kind: "not-found",
|
|
107
|
-
reason: `No element with role="${e.role}" name="${e.name}".`
|
|
108
|
-
};
|
|
109
|
-
}
|
|
110
|
-
function re(e, t) {
|
|
111
|
-
if (t.length === 0) return null;
|
|
112
|
-
let n = t[0], r = y(e, n);
|
|
113
|
-
for (let i of t.slice(1)) {
|
|
114
|
-
let t = y(e, i);
|
|
115
|
-
t > r && (n = i, r = t);
|
|
116
|
-
}
|
|
117
|
-
return r > .3 ? n : null;
|
|
118
|
-
}
|
|
119
|
-
function y(e, t) {
|
|
120
|
-
if (!e || !t) return 0;
|
|
121
|
-
let n = (e) => {
|
|
122
|
-
let t = /* @__PURE__ */ new Set();
|
|
123
|
-
for (let n = 0; n < e.length - 2; n++) t.add(e.slice(n, n + 3));
|
|
124
|
-
return t;
|
|
125
|
-
}, r = n(e), i = n(t);
|
|
126
|
-
if (r.size === 0 || i.size === 0) return 0;
|
|
127
|
-
let a = 0;
|
|
128
|
-
for (let e of r) i.has(e) && a++;
|
|
129
|
-
return a / Math.max(r.size, i.size);
|
|
130
|
-
}
|
|
131
|
-
//#endregion
|
|
132
|
-
//#region src/drift.ts
|
|
133
|
-
function b(e) {
|
|
134
|
-
let { screen: t, liveSnapshot: n, storedAttributesYaml: r, freshAttributesYaml: i } = e, a = [], o = /* @__PURE__ */ new Set();
|
|
135
|
-
for (let e of t.overlays) {
|
|
136
|
-
let r = n.filter((t) => t.role === e.match.role && t.name === e.match.name);
|
|
137
|
-
if (r.length > 1) {
|
|
138
|
-
a.push({
|
|
139
|
-
severity: "error",
|
|
140
|
-
kind: "duplicated",
|
|
141
|
-
screenId: t.id,
|
|
142
|
-
message: `Multiple elements match role="${e.match.role}" name="${e.match.name}". Use \`under\` to disambiguate.`,
|
|
143
|
-
match: e.match
|
|
144
|
-
});
|
|
145
|
-
continue;
|
|
146
|
-
}
|
|
147
|
-
if (r.length === 1) continue;
|
|
148
|
-
let i = n.filter((t) => t.name === e.match.name);
|
|
149
|
-
if (i.length === 1 && i[0].role !== e.match.role) {
|
|
150
|
-
let n = i[0];
|
|
151
|
-
o.add(`${n.role}|${n.name}`), a.push({
|
|
152
|
-
severity: "warning",
|
|
153
|
-
kind: "role-changed",
|
|
154
|
-
screenId: t.id,
|
|
155
|
-
message: `Element with name="${e.match.name}" exists but has role="${n.role}", not "${e.match.role}".`,
|
|
156
|
-
match: e.match,
|
|
157
|
-
suggestion: { role: n.role }
|
|
158
|
-
});
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
let s = n.filter((t) => t.role === e.match.role);
|
|
162
|
-
if (s.length > 0) {
|
|
163
|
-
let n = se(e.match.name, s.map((e) => e.name));
|
|
164
|
-
if (n) {
|
|
165
|
-
o.add(`${e.match.role}|${n}`), a.push({
|
|
166
|
-
severity: "warning",
|
|
167
|
-
kind: "renamed",
|
|
168
|
-
screenId: t.id,
|
|
169
|
-
message: `No element with role="${e.match.role}" name="${e.match.name}". Closest match: name="${n}".`,
|
|
170
|
-
match: e.match,
|
|
171
|
-
suggestion: { name: n }
|
|
172
|
-
});
|
|
173
|
-
continue;
|
|
174
|
-
}
|
|
175
|
-
}
|
|
176
|
-
a.push({
|
|
177
|
-
severity: "error",
|
|
178
|
-
kind: "removed",
|
|
179
|
-
screenId: t.id,
|
|
180
|
-
message: `No element with role="${e.match.role}" name="${e.match.name}".`,
|
|
181
|
-
match: e.match
|
|
182
|
-
});
|
|
183
|
-
}
|
|
184
|
-
let s = new Set(t.overlays.map((e) => `${e.match.role}|${e.match.name}`));
|
|
185
|
-
for (let e of n) {
|
|
186
|
-
if (!oe(e.role)) continue;
|
|
187
|
-
let n = `${e.role}|${e.name}`;
|
|
188
|
-
s.has(n) || o.has(n) || a.push({
|
|
189
|
-
severity: "warning",
|
|
190
|
-
kind: "added",
|
|
191
|
-
screenId: t.id,
|
|
192
|
-
message: `New ${e.role} "${e.name}" on the page has no <Overlay>.`,
|
|
193
|
-
suggestion: {
|
|
194
|
-
role: e.role,
|
|
195
|
-
name: e.name
|
|
196
|
-
}
|
|
197
|
-
});
|
|
198
|
-
}
|
|
199
|
-
return r !== void 0 && i !== void 0 && C(r) !== C(i) && a.push({
|
|
200
|
-
severity: "info",
|
|
201
|
-
kind: "attribute-drift",
|
|
202
|
-
screenId: t.id,
|
|
203
|
-
message: "`annot:attributes` block no longer matches live element attributes. Run `annot docs sync` to update."
|
|
204
|
-
}), a;
|
|
205
|
-
}
|
|
206
|
-
function ie(e) {
|
|
207
|
-
return b({
|
|
208
|
-
screen: e.screen,
|
|
209
|
-
liveSnapshot: g(e.liveSnapshotYaml),
|
|
210
|
-
storedAttributesYaml: e.storedAttributesYaml,
|
|
211
|
-
freshAttributesYaml: e.freshAttributesYaml
|
|
212
|
-
});
|
|
213
|
-
}
|
|
214
|
-
function x(e) {
|
|
215
|
-
let t = 0, n = 0, r = 0;
|
|
216
|
-
for (let i of e) i.severity === "error" ? t++ : i.severity === "warning" ? n++ : r++;
|
|
217
|
-
return {
|
|
218
|
-
errors: t,
|
|
219
|
-
warnings: n,
|
|
220
|
-
infos: r
|
|
221
|
-
};
|
|
222
|
-
}
|
|
223
|
-
var ae = new Set([
|
|
224
|
-
"button",
|
|
225
|
-
"checkbox",
|
|
226
|
-
"combobox",
|
|
227
|
-
"link",
|
|
228
|
-
"menuitem",
|
|
229
|
-
"menuitemcheckbox",
|
|
230
|
-
"menuitemradio",
|
|
231
|
-
"option",
|
|
232
|
-
"radio",
|
|
233
|
-
"searchbox",
|
|
234
|
-
"slider",
|
|
235
|
-
"spinbutton",
|
|
236
|
-
"switch",
|
|
237
|
-
"tab",
|
|
238
|
-
"textbox",
|
|
239
|
-
"treeitem"
|
|
240
|
-
]);
|
|
241
|
-
function oe(e) {
|
|
242
|
-
return ae.has(e);
|
|
243
|
-
}
|
|
244
|
-
function se(e, t) {
|
|
245
|
-
if (t.length === 0) return null;
|
|
246
|
-
let n = t[0], r = S(e, n);
|
|
247
|
-
for (let i of t.slice(1)) {
|
|
248
|
-
let t = S(e, i);
|
|
249
|
-
t > r && (n = i, r = t);
|
|
250
|
-
}
|
|
251
|
-
return r > .3 ? n : null;
|
|
252
|
-
}
|
|
253
|
-
function S(e, t) {
|
|
254
|
-
if (!e || !t) return 0;
|
|
255
|
-
let n = (e) => {
|
|
256
|
-
let t = /* @__PURE__ */ new Set();
|
|
257
|
-
for (let n = 0; n < e.length - 2; n++) t.add(e.slice(n, n + 3));
|
|
258
|
-
return t;
|
|
259
|
-
}, r = n(e), i = n(t);
|
|
260
|
-
if (r.size === 0 || i.size === 0) return 0;
|
|
261
|
-
let a = 0;
|
|
262
|
-
for (let e of r) i.has(e) && a++;
|
|
263
|
-
return a / Math.max(r.size, i.size);
|
|
264
|
-
}
|
|
265
|
-
function C(e) {
|
|
266
|
-
return e.split(/\r?\n/).map((e) => e.trimEnd()).filter((e) => e.length > 0).join("\n");
|
|
267
|
-
}
|
|
268
|
-
function w(e) {
|
|
269
|
-
return e.overlays.length > 0;
|
|
270
|
-
}
|
|
271
|
-
function T(e) {
|
|
272
|
-
return e.filter(w);
|
|
273
|
-
}
|
|
274
|
-
//#endregion
|
|
7
|
+
import { unified as ee } from "unified";
|
|
8
|
+
import { visit as te } from "unist-util-visit";
|
|
9
|
+
import { z as p } from "zod";
|
|
10
|
+
import { basename as ne, dirname as m, isAbsolute as h, join as re, relative as g, resolve as _ } from "node:path";
|
|
11
|
+
import { bboxAnnotationsToSvg as v } from "@ingcreators/annot-annotator";
|
|
12
|
+
import { findByMatch as ie, walkTree as ae, writeElementTreePng as oe } from "@ingcreators/annot-core";
|
|
275
13
|
//#region src/config.ts
|
|
276
|
-
var
|
|
14
|
+
var se = p.enum([
|
|
277
15
|
"cover",
|
|
278
16
|
"history",
|
|
279
17
|
"list",
|
|
280
18
|
"screen",
|
|
281
19
|
"reference"
|
|
282
|
-
]), ce =
|
|
283
|
-
book:
|
|
284
|
-
sheet:
|
|
285
|
-
sheets:
|
|
286
|
-
role:
|
|
287
|
-
order:
|
|
288
|
-
}).strict().refine((e) => !(e.sheet && e.sheets), "Specify either `xlsx.sheet` (single sheet) or `xlsx.sheets` (multi-sheet), not both."), le =
|
|
289
|
-
id:
|
|
290
|
-
title:
|
|
291
|
-
purpose:
|
|
20
|
+
]), ce = p.object({
|
|
21
|
+
book: p.string().optional(),
|
|
22
|
+
sheet: p.string().optional(),
|
|
23
|
+
sheets: p.record(p.string(), p.string()).optional(),
|
|
24
|
+
role: se.optional(),
|
|
25
|
+
order: p.number().optional()
|
|
26
|
+
}).strict().refine((e) => !(e.sheet && e.sheets), "Specify either `xlsx.sheet` (single sheet) or `xlsx.sheets` (multi-sheet), not both."), le = p.record(p.string(), p.unknown()), ue = p.object({
|
|
27
|
+
id: p.string().min(1, "`annot.id` is required."),
|
|
28
|
+
title: p.string().optional(),
|
|
29
|
+
purpose: p.string().optional(),
|
|
292
30
|
meta: le.optional(),
|
|
293
31
|
xlsx: ce.optional()
|
|
294
|
-
}).strict(),
|
|
295
|
-
template:
|
|
296
|
-
templateSheets:
|
|
297
|
-
cover:
|
|
298
|
-
history:
|
|
299
|
-
list:
|
|
300
|
-
screen:
|
|
301
|
-
reference:
|
|
302
|
-
}).strict().optional()
|
|
303
|
-
}).strict(), O = h.object({
|
|
304
|
-
meta: h.record(h.string(), h.unknown()).optional(),
|
|
305
|
-
xlsx: h.object({
|
|
306
|
-
defaultBook: h.string().optional(),
|
|
307
|
-
books: h.record(h.string(), ue).optional()
|
|
32
|
+
}).strict(), de = p.object({
|
|
33
|
+
template: p.string().optional(),
|
|
34
|
+
templateSheets: p.object({
|
|
35
|
+
cover: p.string().optional(),
|
|
36
|
+
history: p.string().optional(),
|
|
37
|
+
list: p.string().optional(),
|
|
38
|
+
screen: p.string().optional(),
|
|
39
|
+
reference: p.string().optional()
|
|
308
40
|
}).strict().optional()
|
|
41
|
+
}).strict(), fe = p.object({
|
|
42
|
+
embedMode: p.enum([
|
|
43
|
+
"newTab",
|
|
44
|
+
"inline",
|
|
45
|
+
"disabled"
|
|
46
|
+
]).optional(),
|
|
47
|
+
cloudUrl: p.string().url("editor.cloudUrl must be an absolute URL").optional()
|
|
48
|
+
}).strict(), pe = p.object({
|
|
49
|
+
meta: p.record(p.string(), p.unknown()).optional(),
|
|
50
|
+
xlsx: p.object({
|
|
51
|
+
defaultBook: p.string().optional(),
|
|
52
|
+
books: p.record(p.string(), de).optional()
|
|
53
|
+
}).strict().optional(),
|
|
54
|
+
editor: fe.optional()
|
|
309
55
|
}).strict();
|
|
310
|
-
function
|
|
311
|
-
let t =
|
|
56
|
+
function me(e) {
|
|
57
|
+
let t = pe.safeParse(e);
|
|
312
58
|
if (!t.success) {
|
|
313
59
|
let e = t.error.issues.map((e) => ` - ${e.path.length ? e.path.join(".") + ": " : ""}${e.message}`).join("\n");
|
|
314
60
|
throw Error(`Invalid \`annot-docs.config.ts\`:\n${e}`);
|
|
315
61
|
}
|
|
316
62
|
return t.data;
|
|
317
63
|
}
|
|
318
|
-
function
|
|
64
|
+
function he(e) {
|
|
319
65
|
return (e.xlsx?.role ?? "screen") === "screen";
|
|
320
66
|
}
|
|
321
67
|
//#endregion
|
|
322
68
|
//#region src/mdx.ts
|
|
323
|
-
var
|
|
324
|
-
async function
|
|
325
|
-
return
|
|
69
|
+
var ge = "annot:snapshot", _e = "/annot:snapshot", ve = "annot:attributes", ye = "/annot:attributes", be = /^\s*\/\*\s*([^\s*]+)\s*([\s\S]*?)\*\/\s*$/;
|
|
70
|
+
async function y(e) {
|
|
71
|
+
return xe(await i(e, "utf8"), { filePath: e });
|
|
326
72
|
}
|
|
327
|
-
function
|
|
328
|
-
let n =
|
|
73
|
+
function xe(e, t = {}) {
|
|
74
|
+
let n = ee().use(f).use(u, ["yaml"]).use(d).parse(e), r = Se(n, t.filePath);
|
|
329
75
|
if (!r) return null;
|
|
330
76
|
let i = [], a = [], o = [], s = [], c = {};
|
|
331
|
-
return
|
|
77
|
+
return te(n, (t) => {
|
|
332
78
|
switch (t.type) {
|
|
333
79
|
case "mdxJsxFlowElement":
|
|
334
80
|
case "mdxJsxTextElement":
|
|
335
|
-
|
|
81
|
+
we(t, e, {
|
|
336
82
|
screens: i,
|
|
337
83
|
transitions: a,
|
|
338
84
|
history: o,
|
|
@@ -341,7 +87,7 @@ function M(e, t = {}) {
|
|
|
341
87
|
return;
|
|
342
88
|
case "mdxFlowExpression":
|
|
343
89
|
case "mdxTextExpression":
|
|
344
|
-
|
|
90
|
+
je(t, c);
|
|
345
91
|
return;
|
|
346
92
|
}
|
|
347
93
|
}), {
|
|
@@ -354,113 +100,127 @@ function M(e, t = {}) {
|
|
|
354
100
|
source: e
|
|
355
101
|
};
|
|
356
102
|
}
|
|
357
|
-
function
|
|
103
|
+
function Se(e, t) {
|
|
358
104
|
let n = e.children.find((e) => e.type === "yaml");
|
|
359
105
|
if (!n || !n.value) return null;
|
|
360
|
-
let r =
|
|
106
|
+
let r = s.load(n.value);
|
|
361
107
|
if (!r || typeof r != "object") return null;
|
|
362
108
|
let i = r.annot;
|
|
363
109
|
if (!i || typeof i != "object") return null;
|
|
364
|
-
let a =
|
|
110
|
+
let a = ue.safeParse(i);
|
|
365
111
|
if (!a.success) {
|
|
366
112
|
let e = t ? ` in ${t}` : "";
|
|
367
|
-
throw Error(`Invalid \`annot:\` frontmatter${e}:\n${
|
|
113
|
+
throw Error(`Invalid \`annot:\` frontmatter${e}:\n${Ce(a.error)}`);
|
|
368
114
|
}
|
|
369
115
|
return a.data;
|
|
370
116
|
}
|
|
371
|
-
function
|
|
372
|
-
return e.issues.map((e) => ` - ${e.path.length ? e.path.join(".") + ": " : ""}${e.message}`).join("\n");
|
|
117
|
+
function Ce(e) {
|
|
118
|
+
return e.issues.map((e) => ` - ${e.path.length ? e.path.map(String).join(".") + ": " : ""}${e.message}`).join("\n");
|
|
373
119
|
}
|
|
374
|
-
function
|
|
120
|
+
function we(e, t, n) {
|
|
375
121
|
let r = e;
|
|
376
122
|
switch (r.name) {
|
|
377
123
|
case "Screen":
|
|
378
|
-
n.screens.push(
|
|
124
|
+
n.screens.push(Te(r, t));
|
|
379
125
|
return;
|
|
380
126
|
case "Transition":
|
|
381
|
-
n.transitions.push(
|
|
127
|
+
n.transitions.push(Oe(r, t));
|
|
382
128
|
return;
|
|
383
129
|
case "HistoryEntry":
|
|
384
|
-
n.history.push(
|
|
130
|
+
n.history.push(ke(r, t));
|
|
385
131
|
return;
|
|
386
132
|
case "ScreenList":
|
|
387
|
-
n.screenLists.push(
|
|
133
|
+
n.screenLists.push(Ae(r));
|
|
388
134
|
return;
|
|
389
135
|
}
|
|
390
136
|
}
|
|
391
|
-
function
|
|
392
|
-
let n =
|
|
393
|
-
let
|
|
394
|
-
if (
|
|
395
|
-
r.push(
|
|
137
|
+
function Te(e, t) {
|
|
138
|
+
let n = b(e), r = [], i = [], a = (n) => {
|
|
139
|
+
let o = n;
|
|
140
|
+
if (o.name === "Overlay") {
|
|
141
|
+
r.push(De(o, t));
|
|
142
|
+
return;
|
|
143
|
+
}
|
|
144
|
+
if (o.name === "AnnotCallout") {
|
|
145
|
+
i.push(Ee(o, t));
|
|
396
146
|
return;
|
|
397
147
|
}
|
|
398
|
-
if (!(
|
|
148
|
+
if (!(o.name === "Screen" && o !== e)) for (let e of o.children ?? []) a(e);
|
|
149
|
+
};
|
|
150
|
+
for (let t of e.children ?? []) a(t);
|
|
151
|
+
let o = x(n.id);
|
|
152
|
+
if (!o) throw Error("<Screen> requires an `id` prop.");
|
|
153
|
+
let s = x(n.annotations), c = {
|
|
154
|
+
id: o,
|
|
155
|
+
src: x(n.src),
|
|
156
|
+
overlays: r,
|
|
157
|
+
callouts: i
|
|
399
158
|
};
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
159
|
+
return s && (c.annotations = s), c;
|
|
160
|
+
}
|
|
161
|
+
function Ee(e, t) {
|
|
162
|
+
let n = x(b(e).for);
|
|
163
|
+
if (!n) throw Error("<AnnotCallout> requires a `for=\"<overlay id>\"` prop.");
|
|
403
164
|
return {
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
overlays: r
|
|
165
|
+
for: n,
|
|
166
|
+
body: C(e, t)
|
|
407
167
|
};
|
|
408
168
|
}
|
|
409
|
-
function
|
|
410
|
-
let n =
|
|
411
|
-
if (!
|
|
169
|
+
function De(e, t) {
|
|
170
|
+
let n = b(e), r = n.match;
|
|
171
|
+
if (!S(r)) throw Error("<Overlay> requires a `match` prop with at least `{ role, name }`.");
|
|
412
172
|
return {
|
|
413
173
|
match: r,
|
|
414
|
-
intent:
|
|
415
|
-
number:
|
|
416
|
-
body:
|
|
174
|
+
intent: x(n.intent),
|
|
175
|
+
number: Ne(n.number),
|
|
176
|
+
body: C(e, t)
|
|
417
177
|
};
|
|
418
178
|
}
|
|
419
|
-
function
|
|
420
|
-
let n =
|
|
421
|
-
if (!
|
|
179
|
+
function Oe(e, t) {
|
|
180
|
+
let n = b(e), r = n.trigger;
|
|
181
|
+
if (!S(r)) throw Error("<Transition> requires a `trigger` prop with at least `{ role, name }`.");
|
|
422
182
|
return {
|
|
423
183
|
trigger: r,
|
|
424
|
-
on:
|
|
425
|
-
to:
|
|
426
|
-
body:
|
|
184
|
+
on: x(n.on),
|
|
185
|
+
to: x(n.to),
|
|
186
|
+
body: C(e, t)
|
|
427
187
|
};
|
|
428
188
|
}
|
|
429
|
-
function
|
|
430
|
-
let n =
|
|
189
|
+
function ke(e, t) {
|
|
190
|
+
let n = b(e), r = x(n.version) ?? "", i = x(n.date) ?? "", a = x(n.author) ?? "";
|
|
431
191
|
if (!r || !i) throw Error("<HistoryEntry> requires `version` and `date` props.");
|
|
432
192
|
return {
|
|
433
193
|
version: r,
|
|
434
194
|
date: i,
|
|
435
195
|
author: a,
|
|
436
|
-
body:
|
|
196
|
+
body: C(e, t)
|
|
437
197
|
};
|
|
438
198
|
}
|
|
439
|
-
function
|
|
440
|
-
let t =
|
|
199
|
+
function Ae(e) {
|
|
200
|
+
let t = b(e);
|
|
441
201
|
return {
|
|
442
|
-
book:
|
|
443
|
-
sort:
|
|
202
|
+
book: x(t.book),
|
|
203
|
+
sort: x(t.sort)
|
|
444
204
|
};
|
|
445
205
|
}
|
|
446
|
-
function
|
|
206
|
+
function je(e, t) {
|
|
447
207
|
let n = e.value;
|
|
448
208
|
if (typeof n != "string") return;
|
|
449
|
-
let r = n.match(
|
|
209
|
+
let r = n.match(be);
|
|
450
210
|
if (!r) return;
|
|
451
211
|
let i = (r[1] ?? "").trim(), a = (r[2] ?? "").trim();
|
|
452
212
|
switch (i) {
|
|
453
|
-
case
|
|
213
|
+
case ge:
|
|
454
214
|
t.snapshot = a;
|
|
455
215
|
return;
|
|
456
|
-
case
|
|
216
|
+
case ve:
|
|
457
217
|
t.attributes = a;
|
|
458
218
|
return;
|
|
459
|
-
case
|
|
460
|
-
case
|
|
219
|
+
case _e:
|
|
220
|
+
case ye: return;
|
|
461
221
|
}
|
|
462
222
|
}
|
|
463
|
-
function
|
|
223
|
+
function b(e) {
|
|
464
224
|
let t = {};
|
|
465
225
|
for (let n of e.attributes ?? []) {
|
|
466
226
|
let e = n;
|
|
@@ -474,11 +234,11 @@ function B(e) {
|
|
|
474
234
|
continue;
|
|
475
235
|
}
|
|
476
236
|
let r = e.value;
|
|
477
|
-
r.type === "mdxJsxAttributeValueExpression" && typeof r.value == "string" && (t[e.name] =
|
|
237
|
+
r.type === "mdxJsxAttributeValueExpression" && typeof r.value == "string" && (t[e.name] = Me(r.value));
|
|
478
238
|
}
|
|
479
239
|
return t;
|
|
480
240
|
}
|
|
481
|
-
function
|
|
241
|
+
function Me(e) {
|
|
482
242
|
let t = e.trim();
|
|
483
243
|
if (t) {
|
|
484
244
|
if (t === "true") return !0;
|
|
@@ -509,18 +269,18 @@ function ve(e) {
|
|
|
509
269
|
return t;
|
|
510
270
|
}
|
|
511
271
|
}
|
|
512
|
-
function
|
|
272
|
+
function x(e) {
|
|
513
273
|
return typeof e == "string" ? e : void 0;
|
|
514
274
|
}
|
|
515
|
-
function
|
|
275
|
+
function Ne(e) {
|
|
516
276
|
return typeof e == "number" ? e : void 0;
|
|
517
277
|
}
|
|
518
|
-
function
|
|
278
|
+
function S(e) {
|
|
519
279
|
if (!e || typeof e != "object") return !1;
|
|
520
280
|
let t = e;
|
|
521
|
-
return !(typeof t.role != "string" || typeof t.name != "string" || t.under !== void 0 && !
|
|
281
|
+
return !(typeof t.role != "string" || typeof t.name != "string" || t.under !== void 0 && !S(t.under));
|
|
522
282
|
}
|
|
523
|
-
function
|
|
283
|
+
function C(e, t) {
|
|
524
284
|
let n = e.position;
|
|
525
285
|
if (!n) return "";
|
|
526
286
|
let r = t.slice(n.start.offset, n.end.offset);
|
|
@@ -528,24 +288,24 @@ function U(e, t) {
|
|
|
528
288
|
let i = r.indexOf(">"), a = r.lastIndexOf("</");
|
|
529
289
|
return i < 0 || a < 0 || a <= i ? "" : r.slice(i + 1, a).trim();
|
|
530
290
|
}
|
|
531
|
-
function
|
|
291
|
+
function w(e, t) {
|
|
532
292
|
let n = e;
|
|
533
|
-
return t.snapshot !== void 0 && (n =
|
|
293
|
+
return t.snapshot !== void 0 && (n = T(n, ge, t.snapshot)), t.attributes !== void 0 && (n = T(n, ve, t.attributes)), n;
|
|
534
294
|
}
|
|
535
|
-
function
|
|
536
|
-
let r = new RegExp(String.raw`\{\s*/\*\s*` +
|
|
295
|
+
function T(e, t, n) {
|
|
296
|
+
let r = new RegExp(String.raw`\{\s*/\*\s*` + Fe(t) + String.raw`\s*[\s\S]*?\*/\s*\}`, "m"), i = Pe(t, n);
|
|
537
297
|
return r.test(e) ? e.replace(r, i) : `${e.trimEnd()}\n\n${i}\n`;
|
|
538
298
|
}
|
|
539
|
-
function
|
|
299
|
+
function Pe(e, t) {
|
|
540
300
|
let n = t.trim();
|
|
541
301
|
return n ? `{/* ${e}\n${n}\n*/}` : `{/* ${e} */}`;
|
|
542
302
|
}
|
|
543
|
-
function
|
|
303
|
+
function Fe(e) {
|
|
544
304
|
return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
545
305
|
}
|
|
546
306
|
//#endregion
|
|
547
307
|
//#region src/fixture.ts
|
|
548
|
-
var
|
|
308
|
+
var E = [
|
|
549
309
|
"type",
|
|
550
310
|
"required",
|
|
551
311
|
"placeholder",
|
|
@@ -561,24 +321,34 @@ var K = [
|
|
|
561
321
|
"aria-required",
|
|
562
322
|
"aria-disabled",
|
|
563
323
|
"aria-readonly"
|
|
564
|
-
],
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
324
|
+
], Ie = n.extend({
|
|
325
|
+
productDocs: async ({ page: e }, t) => {
|
|
326
|
+
await t({ sync: (t) => D(e, t) });
|
|
327
|
+
},
|
|
328
|
+
screen: async ({ page: e }, t) => {
|
|
329
|
+
let n = (t) => D(e, t);
|
|
330
|
+
await t({
|
|
331
|
+
sync: n,
|
|
332
|
+
capture: n
|
|
333
|
+
});
|
|
334
|
+
}
|
|
335
|
+
});
|
|
336
|
+
async function D(e, t) {
|
|
337
|
+
let n = await y(t.mdxPath);
|
|
338
|
+
if (!n) throw Error(`syncProductDocs: ${t.mdxPath} has no \`annot:\` frontmatter — refusing to write.`);
|
|
339
|
+
let r = n.screens.find((e) => e.id === t.id);
|
|
340
|
+
if (!r) throw Error(`syncProductDocs: ${t.mdxPath} has no <Screen id="${t.id}"> block.`);
|
|
341
|
+
let i = await (t.rootLocator ?? e.locator("body")).ariaSnapshot({
|
|
573
342
|
mode: "ai",
|
|
574
343
|
boxes: !0
|
|
575
|
-
}),
|
|
576
|
-
snapshot:
|
|
577
|
-
attributes:
|
|
344
|
+
}), a = await O(e, r.overlays, t.attributeWhitelist ?? E), s = w(n.source, {
|
|
345
|
+
snapshot: i.trim(),
|
|
346
|
+
attributes: a
|
|
578
347
|
});
|
|
579
|
-
await
|
|
348
|
+
await o(t.mdxPath, s, "utf8");
|
|
580
349
|
}
|
|
581
|
-
|
|
350
|
+
var Le = D;
|
|
351
|
+
async function O(e, t, n) {
|
|
582
352
|
let r = [];
|
|
583
353
|
for (let i of t) {
|
|
584
354
|
let t = e.getByRole(i.match.role, {
|
|
@@ -602,112 +372,1577 @@ async function J(e, t, n) {
|
|
|
602
372
|
return r.join("\n");
|
|
603
373
|
}
|
|
604
374
|
//#endregion
|
|
605
|
-
//#region src/
|
|
606
|
-
|
|
607
|
-
let
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
375
|
+
//#region src/mdx-annotations.ts
|
|
376
|
+
function k(e) {
|
|
377
|
+
let t = [];
|
|
378
|
+
for (let n of e.split(/\r?\n/)) {
|
|
379
|
+
if (!n.trim()) continue;
|
|
380
|
+
let e = n.match(/^\s*-\s+([a-z]+)(?:\s+"([^"]*?)")?/);
|
|
381
|
+
if (!e) continue;
|
|
382
|
+
let r = e[1] ?? "", i = e[2] ?? "", a = n.match(/\[ref=(e\d+)\]/)?.[1], o = n.match(/\[box=(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?),(-?\d+(?:\.\d+)?)\]/);
|
|
383
|
+
!a || !o || t.push({
|
|
384
|
+
role: r,
|
|
385
|
+
name: i,
|
|
386
|
+
ref: a,
|
|
387
|
+
box: {
|
|
388
|
+
x: Number.parseFloat(o[1] ?? "0"),
|
|
389
|
+
y: Number.parseFloat(o[2] ?? "0"),
|
|
390
|
+
width: Number.parseFloat(o[3] ?? "0"),
|
|
391
|
+
height: Number.parseFloat(o[4] ?? "0")
|
|
392
|
+
}
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
return t;
|
|
396
|
+
}
|
|
397
|
+
function Re(e) {
|
|
398
|
+
let t = [];
|
|
399
|
+
return ae(e, (e) => {
|
|
400
|
+
e.bbox && e.name && t.push({
|
|
401
|
+
role: e.role,
|
|
402
|
+
name: e.name,
|
|
403
|
+
ref: e.ref,
|
|
404
|
+
box: e.bbox
|
|
405
|
+
});
|
|
406
|
+
}), t;
|
|
407
|
+
}
|
|
408
|
+
function ze(e, t, n) {
|
|
409
|
+
let r = [], i = 1;
|
|
410
|
+
for (let a of e) {
|
|
411
|
+
let e = t.find((e) => e.role === a.match.role && e.name === a.match.name);
|
|
412
|
+
if (!e) continue;
|
|
413
|
+
let o = a.number ?? i++;
|
|
414
|
+
r.push({
|
|
415
|
+
type: "numberedBadge",
|
|
416
|
+
bbox: e.box,
|
|
417
|
+
number: o,
|
|
418
|
+
placement: "auto",
|
|
419
|
+
imageWidth: n.width,
|
|
420
|
+
imageHeight: n.height,
|
|
421
|
+
intent: a.intent === "action" ? "warning" : a.intent === "required" ? "error" : "info"
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
return r;
|
|
425
|
+
}
|
|
426
|
+
function Be(e, t, n) {
|
|
427
|
+
let r = [];
|
|
428
|
+
for (let i of e) {
|
|
429
|
+
let e = t.find((e) => e.role === i.match.role && e.name === i.match.name);
|
|
430
|
+
e && r.push({
|
|
431
|
+
type: "numberedBadge",
|
|
432
|
+
bbox: e.box,
|
|
433
|
+
number: i.number,
|
|
434
|
+
placement: "auto",
|
|
435
|
+
imageWidth: n.width,
|
|
436
|
+
imageHeight: n.height,
|
|
437
|
+
intent: i.intent === "action" ? "warning" : i.intent === "required" ? "error" : "info"
|
|
438
|
+
});
|
|
439
|
+
}
|
|
440
|
+
return r;
|
|
441
|
+
}
|
|
442
|
+
async function Ve(e) {
|
|
443
|
+
let t = e.cwd ?? process.cwd(), n = await y(h(e.mdxPath) ? e.mdxPath : _(t, e.mdxPath));
|
|
444
|
+
if (!n) throw Error(`resolveMdxAnnotations: ${e.mdxPath} has no \`annot:\` frontmatter — cannot resolve.`);
|
|
445
|
+
let r = n.screens.find((t) => t.id === e.screenId);
|
|
446
|
+
if (!r) throw Error(`resolveMdxAnnotations: ${e.mdxPath} has no <Screen id="${e.screenId}"> block.`);
|
|
447
|
+
let i = k(n.commentBlocks.snapshot ?? "");
|
|
448
|
+
return ze(r.overlays, i, e.dims);
|
|
449
|
+
}
|
|
450
|
+
function He(e) {
|
|
451
|
+
return `<svg xmlns="http://www.w3.org/2000/svg">${v(e)}</svg>`;
|
|
452
|
+
}
|
|
453
|
+
function Ue(e, t, n) {
|
|
454
|
+
let r = [];
|
|
455
|
+
for (let i of e) {
|
|
456
|
+
let e = Ge(i, t, n);
|
|
457
|
+
e && r.push(e);
|
|
458
|
+
}
|
|
459
|
+
return r;
|
|
460
|
+
}
|
|
461
|
+
function We(e, t) {
|
|
462
|
+
let n = [];
|
|
463
|
+
for (let r of e) {
|
|
464
|
+
if (r.kind !== "redact" || r.style !== "mosaic" && r.style !== "blur") continue;
|
|
465
|
+
let e = null;
|
|
466
|
+
if (r.match) {
|
|
467
|
+
let n = j(t, r.match);
|
|
468
|
+
if (!n) continue;
|
|
469
|
+
e = n.box;
|
|
470
|
+
} else r.bbox && (e = r.bbox);
|
|
471
|
+
if (!e) continue;
|
|
472
|
+
let i = {
|
|
473
|
+
bbox: e,
|
|
474
|
+
style: r.style
|
|
475
|
+
};
|
|
476
|
+
r.color !== void 0 && (i.color = r.color), n.push(i);
|
|
477
|
+
}
|
|
478
|
+
return n;
|
|
479
|
+
}
|
|
480
|
+
function Ge(e, t, n) {
|
|
481
|
+
switch (e.kind) {
|
|
482
|
+
case "rect": return Ke(e, t);
|
|
483
|
+
case "circle": return qe(e, t);
|
|
484
|
+
case "arrow": return Je(e, t);
|
|
485
|
+
case "text": return Xe(e, t);
|
|
486
|
+
case "callout": return Qe(e, t);
|
|
487
|
+
case "freehand": return $e(e);
|
|
488
|
+
case "redact": return tt(e, t);
|
|
489
|
+
case "focusMask": return nt(e, t, n);
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
function Ke(e, t) {
|
|
493
|
+
let n = null;
|
|
494
|
+
if (e.match) {
|
|
495
|
+
let r = j(t, e.match);
|
|
496
|
+
if (!r) return null;
|
|
497
|
+
n = r.box;
|
|
498
|
+
} else if (e.coversElements) {
|
|
499
|
+
let r = [];
|
|
500
|
+
for (let n of e.coversElements) {
|
|
501
|
+
let e = j(t, n);
|
|
502
|
+
if (!e) return null;
|
|
503
|
+
r.push(e.box);
|
|
504
|
+
}
|
|
505
|
+
n = it(r);
|
|
506
|
+
} else e.bbox && (n = e.bbox);
|
|
507
|
+
return n ? N({
|
|
508
|
+
type: "rect",
|
|
509
|
+
bbox: n
|
|
510
|
+
}, e) : null;
|
|
511
|
+
}
|
|
512
|
+
function qe(e, t) {
|
|
513
|
+
if (e.match) {
|
|
514
|
+
let n = j(t, e.match);
|
|
515
|
+
return n ? N({
|
|
516
|
+
type: "circle",
|
|
517
|
+
center: rt(n.box),
|
|
518
|
+
radius: e.radius ?? Math.max(n.box.width, n.box.height) / 2
|
|
519
|
+
}, e) : null;
|
|
520
|
+
}
|
|
521
|
+
return e.center && e.radius !== void 0 ? N({
|
|
522
|
+
type: "circle",
|
|
523
|
+
center: e.center,
|
|
524
|
+
radius: e.radius
|
|
525
|
+
}, e) : null;
|
|
526
|
+
}
|
|
527
|
+
function Je(e, t) {
|
|
528
|
+
let n = Ye(e.from, t);
|
|
529
|
+
if (!n) return null;
|
|
530
|
+
let r = Ye(e.to, t);
|
|
531
|
+
return r ? N({
|
|
532
|
+
type: "arrow",
|
|
533
|
+
from: n,
|
|
534
|
+
to: r
|
|
535
|
+
}, e) : null;
|
|
536
|
+
}
|
|
537
|
+
function Ye(e, t) {
|
|
538
|
+
if ("point" in e) return e.point;
|
|
539
|
+
let n = j(t, e.match);
|
|
540
|
+
return n ? rt(n.box) : null;
|
|
541
|
+
}
|
|
542
|
+
var A = 8;
|
|
543
|
+
function Xe(e, t) {
|
|
544
|
+
let n, r;
|
|
545
|
+
if (e.anchor) {
|
|
546
|
+
let i = j(t, e.anchor.match);
|
|
547
|
+
if (!i) return null;
|
|
548
|
+
let a = Ze(i.box, e.anchor.position ?? "above");
|
|
549
|
+
n = a.at, r = a.anchor;
|
|
550
|
+
} else if (e.at) n = e.at, r = "start";
|
|
551
|
+
else return null;
|
|
552
|
+
let i = {
|
|
553
|
+
type: "text",
|
|
554
|
+
at: n,
|
|
555
|
+
content: e.text,
|
|
556
|
+
anchor: r
|
|
557
|
+
};
|
|
558
|
+
return e.fontSize !== void 0 && (i.fontSize = e.fontSize), N(i, e);
|
|
559
|
+
}
|
|
560
|
+
function Ze(e, t) {
|
|
561
|
+
let n = e.x + e.width / 2, r = e.y + e.height / 2;
|
|
562
|
+
switch (t) {
|
|
563
|
+
case "above": return {
|
|
564
|
+
at: {
|
|
565
|
+
x: n,
|
|
566
|
+
y: e.y - A
|
|
567
|
+
},
|
|
568
|
+
anchor: "middle"
|
|
569
|
+
};
|
|
570
|
+
case "below": return {
|
|
571
|
+
at: {
|
|
572
|
+
x: n,
|
|
573
|
+
y: e.y + e.height + A
|
|
574
|
+
},
|
|
575
|
+
anchor: "middle"
|
|
576
|
+
};
|
|
577
|
+
case "left": return {
|
|
578
|
+
at: {
|
|
579
|
+
x: e.x - A,
|
|
580
|
+
y: r
|
|
581
|
+
},
|
|
582
|
+
anchor: "end"
|
|
583
|
+
};
|
|
584
|
+
case "right": return {
|
|
585
|
+
at: {
|
|
586
|
+
x: e.x + e.width + A,
|
|
587
|
+
y: r
|
|
588
|
+
},
|
|
589
|
+
anchor: "start"
|
|
590
|
+
};
|
|
591
|
+
case "center": return {
|
|
592
|
+
at: {
|
|
593
|
+
x: n,
|
|
594
|
+
y: r
|
|
595
|
+
},
|
|
596
|
+
anchor: "middle"
|
|
597
|
+
};
|
|
598
|
+
}
|
|
599
|
+
}
|
|
600
|
+
function Qe(e, t) {
|
|
601
|
+
let n = null;
|
|
602
|
+
if ("match" in e.target) {
|
|
603
|
+
let r = j(t, e.target.match);
|
|
604
|
+
if (!r) return null;
|
|
605
|
+
n = r.box;
|
|
606
|
+
} else n = e.target.bbox;
|
|
607
|
+
return N({
|
|
608
|
+
type: "callout",
|
|
609
|
+
at: e.at,
|
|
610
|
+
targetBbox: n,
|
|
611
|
+
content: e.text
|
|
612
|
+
}, e);
|
|
613
|
+
}
|
|
614
|
+
function $e(e) {
|
|
615
|
+
return N({
|
|
616
|
+
type: "freehand",
|
|
617
|
+
path: e.path
|
|
618
|
+
}, e);
|
|
619
|
+
}
|
|
620
|
+
var et = "#222222";
|
|
621
|
+
function tt(e, t) {
|
|
622
|
+
if (e.style === "mosaic" || e.style === "blur") return null;
|
|
623
|
+
let n = null;
|
|
624
|
+
if (e.match) {
|
|
625
|
+
let r = j(t, e.match);
|
|
626
|
+
if (!r) return null;
|
|
627
|
+
n = r.box;
|
|
628
|
+
} else e.bbox && (n = e.bbox);
|
|
629
|
+
return n ? {
|
|
630
|
+
type: "rect",
|
|
631
|
+
bbox: n,
|
|
632
|
+
fill: e.fill ?? et,
|
|
633
|
+
stroke: e.stroke ?? "none",
|
|
634
|
+
strokeWidth: e.strokeWidth ?? 0,
|
|
635
|
+
...e.intent ? { intent: M(e.intent) } : {}
|
|
636
|
+
} : null;
|
|
637
|
+
}
|
|
638
|
+
function nt(e, t, n) {
|
|
639
|
+
let r = null;
|
|
640
|
+
if ("match" in e.cutout) {
|
|
641
|
+
let n = j(t, e.cutout.match);
|
|
642
|
+
if (!n) return null;
|
|
643
|
+
let i = e.cutout.padding ?? 0;
|
|
644
|
+
r = at(n.box, i);
|
|
645
|
+
} else r = e.cutout.bbox;
|
|
646
|
+
let i = {
|
|
647
|
+
type: "focusMask",
|
|
648
|
+
cutout: r,
|
|
649
|
+
imageWidth: n.width,
|
|
650
|
+
imageHeight: n.height
|
|
651
|
+
};
|
|
652
|
+
return e.dimColor !== void 0 && (i.dimColor = e.dimColor), N(i, e);
|
|
653
|
+
}
|
|
654
|
+
function j(e, t) {
|
|
655
|
+
return e.find((e) => e.role === t.role && e.name === t.name);
|
|
656
|
+
}
|
|
657
|
+
function rt(e) {
|
|
658
|
+
return {
|
|
659
|
+
x: e.x + e.width / 2,
|
|
660
|
+
y: e.y + e.height / 2
|
|
661
|
+
};
|
|
662
|
+
}
|
|
663
|
+
function it(e) {
|
|
664
|
+
let t = Math.min(...e.map((e) => e.x)), n = Math.min(...e.map((e) => e.y)), r = Math.max(...e.map((e) => e.x + e.width)), i = Math.max(...e.map((e) => e.y + e.height));
|
|
665
|
+
return {
|
|
666
|
+
x: t,
|
|
667
|
+
y: n,
|
|
668
|
+
width: r - t,
|
|
669
|
+
height: i - n
|
|
670
|
+
};
|
|
671
|
+
}
|
|
672
|
+
function at(e, t) {
|
|
673
|
+
return t <= 0 ? e : {
|
|
674
|
+
x: e.x - t,
|
|
675
|
+
y: e.y - t,
|
|
676
|
+
width: e.width + t * 2,
|
|
677
|
+
height: e.height + t * 2
|
|
678
|
+
};
|
|
679
|
+
}
|
|
680
|
+
function M(e) {
|
|
681
|
+
if (e !== void 0) switch (e) {
|
|
682
|
+
case "required": return "error";
|
|
683
|
+
case "action": return "warning";
|
|
684
|
+
case "info":
|
|
685
|
+
case "warning":
|
|
686
|
+
case "error":
|
|
687
|
+
case "success":
|
|
688
|
+
case "neutral": return e;
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
function N(e, t) {
|
|
692
|
+
let n = M(t.intent), r = { ...e };
|
|
693
|
+
return n !== void 0 && !("intent" in r) && (r.intent = n), n !== void 0 && r.intent === void 0 && (r.intent = n), t.stroke !== void 0 && (r.stroke = t.stroke), t.strokeWidth !== void 0 && (r.strokeWidth = t.strokeWidth), t.fill !== void 0 && (r.fill = t.fill), t.color !== void 0 && (r.color = t.color), r;
|
|
694
|
+
}
|
|
695
|
+
function ot(e) {
|
|
696
|
+
return e.length === 0 ? st() : `<svg xmlns="http://www.w3.org/2000/svg">${v(e)}</svg>`;
|
|
697
|
+
}
|
|
698
|
+
function st() {
|
|
699
|
+
return "<svg xmlns=\"http://www.w3.org/2000/svg\"></svg>";
|
|
700
|
+
}
|
|
701
|
+
//#endregion
|
|
702
|
+
//#region src/playwright-screenshot-hook.ts
|
|
703
|
+
var ct = Symbol.for("@ingcreators/annot-product-docs:mdx-resolver"), lt = async ({ annot: e, page: t }) => {
|
|
704
|
+
if (!e.mdx) return null;
|
|
705
|
+
let { id: n, path: r } = e.mdx;
|
|
706
|
+
return {
|
|
707
|
+
prepare: () => D(t, {
|
|
708
|
+
id: n,
|
|
709
|
+
mdxPath: r
|
|
710
|
+
}),
|
|
711
|
+
resolveAnnotations: (e) => Ve({
|
|
712
|
+
mdxPath: r,
|
|
713
|
+
screenId: n,
|
|
714
|
+
dims: e
|
|
715
|
+
})
|
|
716
|
+
};
|
|
717
|
+
}, ut = lt;
|
|
718
|
+
ut[ct] || (ut[ct] = !0, e.push(lt));
|
|
719
|
+
//#endregion
|
|
720
|
+
//#region src/annotations-yaml.ts
|
|
721
|
+
var dt = 1, P = [
|
|
722
|
+
"rect",
|
|
723
|
+
"circle",
|
|
724
|
+
"arrow",
|
|
725
|
+
"text",
|
|
726
|
+
"callout",
|
|
727
|
+
"freehand",
|
|
728
|
+
"redact",
|
|
729
|
+
"focusMask"
|
|
730
|
+
], F = class extends Error {
|
|
731
|
+
source;
|
|
732
|
+
constructor(e, t) {
|
|
733
|
+
super(e), this.source = t, this.name = "AnnotationsYamlError";
|
|
734
|
+
}
|
|
735
|
+
};
|
|
736
|
+
function ft(e) {
|
|
737
|
+
let t;
|
|
738
|
+
try {
|
|
739
|
+
t = l(e);
|
|
740
|
+
} catch (t) {
|
|
741
|
+
throw new F(`Failed to parse annotations yaml: ${t.message}`, e);
|
|
742
|
+
}
|
|
743
|
+
if (!t || typeof t != "object") throw new F("Annotations yaml must be a mapping", e);
|
|
744
|
+
let n = t, r = n.version;
|
|
745
|
+
if (r !== 1) throw new F(`Unsupported annotations yaml version: expected 1, got ${JSON.stringify(r)}`, e);
|
|
746
|
+
let i = n.overlays;
|
|
747
|
+
if (!Array.isArray(i)) throw new F("Annotations yaml `overlays` must be an array", e);
|
|
748
|
+
let a = {
|
|
749
|
+
version: 1,
|
|
750
|
+
overlays: i.map((e, t) => mt(e, t))
|
|
751
|
+
}, o = n.annotations;
|
|
752
|
+
if (o !== void 0) {
|
|
753
|
+
if (!Array.isArray(o)) throw new F("Annotations yaml `annotations` must be an array", e);
|
|
754
|
+
let t = o.map((e, t) => _t(e, t));
|
|
755
|
+
t.length > 0 && (a.annotations = t);
|
|
756
|
+
}
|
|
757
|
+
let s = n.meta;
|
|
758
|
+
if (s && typeof s == "object" && !Array.isArray(s)) {
|
|
759
|
+
let e = {};
|
|
760
|
+
for (let [t, n] of Object.entries(s)) typeof n == "string" && (e[t] = n);
|
|
761
|
+
Object.keys(e).length > 0 && (a.meta = e);
|
|
762
|
+
}
|
|
763
|
+
return a;
|
|
764
|
+
}
|
|
765
|
+
function pt(e) {
|
|
766
|
+
for (let t of e.overlays) {
|
|
767
|
+
if (typeof t.id != "string" || t.id.length === 0) throw new F(`Overlay entry missing id: ${JSON.stringify(t)}`);
|
|
768
|
+
if (!t.match || typeof t.match.role != "string" || typeof t.match.name != "string") throw new F(`Overlay entry ${t.id}: match must have string role + name`);
|
|
769
|
+
if (typeof t.number != "number" || !Number.isFinite(t.number)) throw new F(`Overlay entry ${t.id}: number must be a finite number`);
|
|
770
|
+
}
|
|
771
|
+
if (e.annotations) for (let t of e.annotations) jt(t);
|
|
772
|
+
let t = {
|
|
773
|
+
version: e.version,
|
|
774
|
+
overlays: e.overlays.map(gt)
|
|
775
|
+
};
|
|
776
|
+
return e.annotations && e.annotations.length > 0 && (t.annotations = e.annotations.map(Ot)), e.meta && Object.keys(e.meta).length > 0 && (t.meta = { ...e.meta }), c(t, {
|
|
777
|
+
lineWidth: -1,
|
|
778
|
+
noRefs: !0,
|
|
779
|
+
sortKeys: !1
|
|
780
|
+
});
|
|
781
|
+
}
|
|
782
|
+
function mt(e, t) {
|
|
783
|
+
if (!e || typeof e != "object") throw new F(`Overlay #${t}: not a mapping`);
|
|
784
|
+
let n = e, r = n.id;
|
|
785
|
+
if (typeof r != "string" || r.length === 0) throw new F(`Overlay #${t}: missing or empty id`);
|
|
786
|
+
let i = n.kind;
|
|
787
|
+
if (i !== "numberedBadge") throw new F(`Overlay ${r}: unsupported kind ${JSON.stringify(i)} (expected "numberedBadge")`);
|
|
788
|
+
let a = ht(n.match, r), o = n.number;
|
|
789
|
+
if (typeof o != "number" || !Number.isFinite(o)) throw new F(`Overlay ${r}: number must be a finite number`);
|
|
790
|
+
let s = {
|
|
791
|
+
id: r,
|
|
792
|
+
kind: "numberedBadge",
|
|
793
|
+
match: a,
|
|
794
|
+
number: o
|
|
795
|
+
}, c = n.intent;
|
|
796
|
+
return typeof c == "string" && (s.intent = c), s;
|
|
797
|
+
}
|
|
798
|
+
function ht(e, t) {
|
|
799
|
+
if (!e || typeof e != "object") throw new F(`Overlay ${t}: match must be a mapping`);
|
|
800
|
+
let n = e, r = n.role, i = n.name;
|
|
801
|
+
if (typeof r != "string" || typeof i != "string") throw new F(`Overlay ${t}: match.role and match.name must both be strings`);
|
|
802
|
+
let a = {
|
|
803
|
+
role: r,
|
|
804
|
+
name: i
|
|
805
|
+
};
|
|
806
|
+
return n.under !== void 0 && (a.under = ht(n.under, t)), a;
|
|
807
|
+
}
|
|
808
|
+
function gt(e) {
|
|
809
|
+
let t = {
|
|
810
|
+
id: e.id,
|
|
811
|
+
kind: e.kind,
|
|
812
|
+
match: I(e.match)
|
|
813
|
+
};
|
|
814
|
+
return e.intent !== void 0 && (t.intent = e.intent), t.number = e.number, t;
|
|
815
|
+
}
|
|
816
|
+
function I(e) {
|
|
817
|
+
let t = {
|
|
818
|
+
role: e.role,
|
|
819
|
+
name: e.name
|
|
820
|
+
};
|
|
821
|
+
return e.under && (t.under = I(e.under)), t;
|
|
822
|
+
}
|
|
823
|
+
function _t(e, t) {
|
|
824
|
+
if (!e || typeof e != "object") throw new F(`Annotation #${t}: not a mapping`);
|
|
825
|
+
let n = e, r = n.id;
|
|
826
|
+
if (typeof r != "string" || r.length === 0) throw new F(`Annotation #${t}: missing or empty id`);
|
|
827
|
+
let i = n.kind;
|
|
828
|
+
if (typeof i != "string" || !P.includes(i)) throw new F(`Annotation ${r}: unsupported kind ${JSON.stringify(i)} (expected one of ${P.join(", ")})`);
|
|
829
|
+
switch (i) {
|
|
830
|
+
case "rect": return vt(r, n);
|
|
831
|
+
case "circle": return yt(r, n);
|
|
832
|
+
case "arrow": return bt(r, n);
|
|
833
|
+
case "text": return St(r, n);
|
|
834
|
+
case "callout": return Ct(r, n);
|
|
835
|
+
case "freehand": return wt(r, n);
|
|
836
|
+
case "redact": return Tt(r, n);
|
|
837
|
+
case "focusMask": return Et(r, n);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
function vt(e, t) {
|
|
841
|
+
let n = t.match !== void 0, r = t.coversElements !== void 0, i = t.bbox !== void 0;
|
|
842
|
+
B(e, "rect", {
|
|
843
|
+
match: n,
|
|
844
|
+
coversElements: r,
|
|
845
|
+
bbox: i
|
|
846
|
+
});
|
|
847
|
+
let a = {
|
|
848
|
+
id: e,
|
|
849
|
+
kind: "rect"
|
|
850
|
+
};
|
|
851
|
+
return n && (a.match = L(e, t.match)), r && (a.coversElements = Dt(e, t.coversElements)), i && (a.bbox = z(e, t.bbox)), V(t, a), a;
|
|
852
|
+
}
|
|
853
|
+
function yt(e, t) {
|
|
854
|
+
let n = t.match !== void 0, r = t.center !== void 0;
|
|
855
|
+
B(e, "circle", {
|
|
856
|
+
match: n,
|
|
857
|
+
center: r
|
|
858
|
+
});
|
|
859
|
+
let i = {
|
|
860
|
+
id: e,
|
|
861
|
+
kind: "circle"
|
|
862
|
+
};
|
|
863
|
+
if (n && (i.match = L(e, t.match)), r) {
|
|
864
|
+
i.center = R(e, t.center);
|
|
865
|
+
let n = t.radius;
|
|
866
|
+
if (typeof n != "number" || !Number.isFinite(n) || n < 0) throw new F(`Annotation ${e}: circle with \`center\` requires a finite non-negative \`radius\``);
|
|
867
|
+
i.radius = n;
|
|
868
|
+
} else {
|
|
869
|
+
let n = t.radius;
|
|
870
|
+
if (n !== void 0) {
|
|
871
|
+
if (typeof n != "number" || !Number.isFinite(n) || n < 0) throw new F(`Annotation ${e}: circle \`radius\` must be a finite non-negative number`);
|
|
872
|
+
i.radius = n;
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
return V(t, i), i;
|
|
876
|
+
}
|
|
877
|
+
function bt(e, t) {
|
|
878
|
+
let n = {
|
|
879
|
+
id: e,
|
|
880
|
+
kind: "arrow",
|
|
881
|
+
from: xt(e, "from", t.from),
|
|
882
|
+
to: xt(e, "to", t.to)
|
|
883
|
+
};
|
|
884
|
+
return V(t, n), n;
|
|
885
|
+
}
|
|
886
|
+
function xt(e, t, n) {
|
|
887
|
+
if (!n || typeof n != "object") throw new F(`Annotation ${e}: arrow.${t} must be a mapping with \`match\` or \`point\``);
|
|
888
|
+
let r = n, i = r.match !== void 0;
|
|
889
|
+
if (i === (r.point !== void 0)) throw new F(`Annotation ${e}: arrow.${t} requires exactly one of \`match\` / \`point\``);
|
|
890
|
+
return i ? { match: L(e, r.match) } : { point: R(e, r.point) };
|
|
891
|
+
}
|
|
892
|
+
function St(e, t) {
|
|
893
|
+
let n = t.text;
|
|
894
|
+
if (typeof n != "string" || n.length === 0) throw new F(`Annotation ${e}: text requires a non-empty \`text\` string`);
|
|
895
|
+
let r = t.anchor !== void 0, i = t.at !== void 0;
|
|
896
|
+
B(e, "text", {
|
|
897
|
+
anchor: r,
|
|
898
|
+
at: i
|
|
899
|
+
});
|
|
900
|
+
let a = {
|
|
901
|
+
id: e,
|
|
902
|
+
kind: "text",
|
|
903
|
+
text: n
|
|
904
|
+
};
|
|
905
|
+
if (r) {
|
|
906
|
+
let n = t.anchor;
|
|
907
|
+
if (!n || typeof n != "object") throw new F(`Annotation ${e}: text.anchor must be a mapping`);
|
|
908
|
+
let r = n, i = { match: L(e, r.match) }, o = r.position;
|
|
909
|
+
if (o !== void 0) {
|
|
910
|
+
if (typeof o != "string" || ![
|
|
911
|
+
"above",
|
|
912
|
+
"below",
|
|
913
|
+
"left",
|
|
914
|
+
"right",
|
|
915
|
+
"center"
|
|
916
|
+
].includes(o)) throw new F(`Annotation ${e}: text.anchor.position must be one of above / below / left / right / center`);
|
|
917
|
+
i.position = o;
|
|
918
|
+
}
|
|
919
|
+
a.anchor = i;
|
|
920
|
+
}
|
|
921
|
+
i && (a.at = R(e, t.at));
|
|
922
|
+
let o = t.fontSize;
|
|
923
|
+
if (o !== void 0) {
|
|
924
|
+
if (typeof o != "number" || !Number.isFinite(o) || o <= 0) throw new F(`Annotation ${e}: text.fontSize must be a finite positive number`);
|
|
925
|
+
a.fontSize = o;
|
|
926
|
+
}
|
|
927
|
+
return V(t, a), a;
|
|
928
|
+
}
|
|
929
|
+
function Ct(e, t) {
|
|
930
|
+
let n = t.text;
|
|
931
|
+
if (typeof n != "string" || n.length === 0) throw new F(`Annotation ${e}: callout requires a non-empty \`text\` string`);
|
|
932
|
+
let r = t.target;
|
|
933
|
+
if (!r || typeof r != "object") throw new F(`Annotation ${e}: callout.target must be a mapping with \`match\` or \`bbox\``);
|
|
934
|
+
let i = r, a = i.match !== void 0;
|
|
935
|
+
if (a === (i.bbox !== void 0)) throw new F(`Annotation ${e}: callout.target requires exactly one of \`match\` / \`bbox\``);
|
|
936
|
+
let o = a ? { match: L(e, i.match) } : { bbox: z(e, i.bbox) }, s = t.at;
|
|
937
|
+
if (s === void 0) throw new F(`Annotation ${e}: callout requires an \`at\` point`);
|
|
938
|
+
let c = {
|
|
939
|
+
id: e,
|
|
940
|
+
kind: "callout",
|
|
941
|
+
text: n,
|
|
942
|
+
target: o,
|
|
943
|
+
at: R(e, s)
|
|
944
|
+
};
|
|
945
|
+
return V(t, c), c;
|
|
946
|
+
}
|
|
947
|
+
function wt(e, t) {
|
|
948
|
+
let n = t.path;
|
|
949
|
+
if (typeof n != "string" || n.length === 0) throw new F(`Annotation ${e}: freehand requires a non-empty \`path\` string`);
|
|
950
|
+
let r = {
|
|
951
|
+
id: e,
|
|
952
|
+
kind: "freehand",
|
|
953
|
+
path: n
|
|
954
|
+
};
|
|
955
|
+
return V(t, r), r;
|
|
956
|
+
}
|
|
957
|
+
function Tt(e, t) {
|
|
958
|
+
let n = t.match !== void 0, r = t.bbox !== void 0;
|
|
959
|
+
B(e, "redact", {
|
|
960
|
+
match: n,
|
|
961
|
+
bbox: r
|
|
962
|
+
});
|
|
963
|
+
let i = {
|
|
964
|
+
id: e,
|
|
965
|
+
kind: "redact"
|
|
966
|
+
};
|
|
967
|
+
n && (i.match = L(e, t.match)), r && (i.bbox = z(e, t.bbox));
|
|
968
|
+
let a = t.style;
|
|
969
|
+
if (a !== void 0) {
|
|
970
|
+
if (a !== "solid" && a !== "mosaic" && a !== "blur") throw new F(`Annotation ${e}: redact.style must be one of "solid" / "mosaic" / "blur"`);
|
|
971
|
+
i.style = a;
|
|
972
|
+
}
|
|
973
|
+
return V(t, i), i;
|
|
974
|
+
}
|
|
975
|
+
function Et(e, t) {
|
|
976
|
+
let n = t.cutout;
|
|
977
|
+
if (!n || typeof n != "object") throw new F(`Annotation ${e}: focusMask.cutout must be a mapping with \`match\` or \`bbox\``);
|
|
978
|
+
let r = n, i = r.match !== void 0;
|
|
979
|
+
if (i === (r.bbox !== void 0)) throw new F(`Annotation ${e}: focusMask.cutout requires exactly one of \`match\` / \`bbox\``);
|
|
980
|
+
let a;
|
|
981
|
+
if (i) {
|
|
982
|
+
let t = L(e, r.match), n = r.padding;
|
|
983
|
+
if (n !== void 0) {
|
|
984
|
+
if (typeof n != "number" || !Number.isFinite(n) || n < 0) throw new F(`Annotation ${e}: focusMask.cutout.padding must be a finite non-negative number`);
|
|
985
|
+
a = {
|
|
986
|
+
match: t,
|
|
987
|
+
padding: n
|
|
988
|
+
};
|
|
989
|
+
} else a = { match: t };
|
|
990
|
+
} else a = { bbox: z(e, r.bbox) };
|
|
991
|
+
let o = {
|
|
992
|
+
id: e,
|
|
993
|
+
kind: "focusMask",
|
|
994
|
+
cutout: a
|
|
995
|
+
}, s = t.dimColor;
|
|
996
|
+
if (s !== void 0) {
|
|
997
|
+
if (typeof s != "string") throw new F(`Annotation ${e}: focusMask.dimColor must be a string`);
|
|
998
|
+
o.dimColor = s;
|
|
999
|
+
}
|
|
1000
|
+
return V(t, o), o;
|
|
1001
|
+
}
|
|
1002
|
+
function L(e, t) {
|
|
1003
|
+
if (!t || typeof t != "object") throw new F(`Annotation ${e}: match must be a mapping`);
|
|
1004
|
+
let n = t, r = n.role, i = n.name;
|
|
1005
|
+
if (typeof r != "string" || typeof i != "string") throw new F(`Annotation ${e}: match.role and match.name must both be strings`);
|
|
1006
|
+
let a = {
|
|
1007
|
+
role: r,
|
|
1008
|
+
name: i
|
|
1009
|
+
};
|
|
1010
|
+
return n.under !== void 0 && (a.under = L(e, n.under)), a;
|
|
1011
|
+
}
|
|
1012
|
+
function Dt(e, t) {
|
|
1013
|
+
if (!Array.isArray(t) || t.length === 0) throw new F(`Annotation ${e}: coversElements must be a non-empty array of match objects`);
|
|
1014
|
+
return t.map((t) => L(e, t));
|
|
1015
|
+
}
|
|
1016
|
+
function R(e, t) {
|
|
1017
|
+
if (!t || typeof t != "object") throw new F(`Annotation ${e}: point must be a mapping`);
|
|
1018
|
+
let n = t, r = n.x, i = n.y;
|
|
1019
|
+
if (typeof r != "number" || !Number.isFinite(r) || typeof i != "number" || !Number.isFinite(i)) throw new F(`Annotation ${e}: point.x and point.y must be finite numbers`);
|
|
1020
|
+
return {
|
|
1021
|
+
x: r,
|
|
1022
|
+
y: i
|
|
1023
|
+
};
|
|
1024
|
+
}
|
|
1025
|
+
function z(e, t) {
|
|
1026
|
+
if (!t || typeof t != "object") throw new F(`Annotation ${e}: bbox must be a mapping`);
|
|
1027
|
+
let n = t, r = n.x, i = n.y, a = n.width, o = n.height;
|
|
1028
|
+
if (typeof r != "number" || !Number.isFinite(r) || typeof i != "number" || !Number.isFinite(i) || typeof a != "number" || !Number.isFinite(a) || a < 0 || typeof o != "number" || !Number.isFinite(o) || o < 0) throw new F(`Annotation ${e}: bbox requires finite numeric x / y + non-negative width / height`);
|
|
1029
|
+
return {
|
|
1030
|
+
x: r,
|
|
1031
|
+
y: i,
|
|
1032
|
+
width: a,
|
|
1033
|
+
height: o
|
|
1034
|
+
};
|
|
1035
|
+
}
|
|
1036
|
+
function B(e, t, n) {
|
|
1037
|
+
if (Object.entries(n).filter(([, e]) => e).length !== 1) throw new F(`Annotation ${e}: ${t} requires exactly one of ${Object.keys(n).join(" / ")}`);
|
|
1038
|
+
}
|
|
1039
|
+
function V(e, t) {
|
|
1040
|
+
let n = e.intent;
|
|
1041
|
+
typeof n == "string" && (t.intent = n);
|
|
1042
|
+
let r = e.stroke;
|
|
1043
|
+
typeof r == "string" && (t.stroke = r);
|
|
1044
|
+
let i = e.strokeWidth;
|
|
1045
|
+
typeof i == "number" && Number.isFinite(i) && i >= 0 && (t.strokeWidth = i);
|
|
1046
|
+
let a = e.fill;
|
|
1047
|
+
typeof a == "string" && (t.fill = a);
|
|
1048
|
+
let o = e.color;
|
|
1049
|
+
typeof o == "string" && (t.color = o);
|
|
1050
|
+
}
|
|
1051
|
+
function Ot(e) {
|
|
1052
|
+
let t = {
|
|
1053
|
+
id: e.id,
|
|
1054
|
+
kind: e.kind
|
|
1055
|
+
};
|
|
1056
|
+
switch (e.kind) {
|
|
1057
|
+
case "rect":
|
|
1058
|
+
e.match && (t.match = I(e.match)), e.coversElements && (t.coversElements = e.coversElements.map(I)), e.bbox && (t.bbox = H(e.bbox));
|
|
1059
|
+
break;
|
|
1060
|
+
case "circle":
|
|
1061
|
+
e.match && (t.match = I(e.match)), e.center && (t.center = U(e.center)), e.radius !== void 0 && (t.radius = e.radius);
|
|
1062
|
+
break;
|
|
1063
|
+
case "arrow":
|
|
1064
|
+
t.from = kt(e.from), t.to = kt(e.to);
|
|
1065
|
+
break;
|
|
1066
|
+
case "text":
|
|
1067
|
+
if (t.text = e.text, e.anchor) {
|
|
1068
|
+
let n = { match: I(e.anchor.match) };
|
|
1069
|
+
e.anchor.position && (n.position = e.anchor.position), t.anchor = n;
|
|
1070
|
+
}
|
|
1071
|
+
e.at && (t.at = U(e.at)), e.fontSize !== void 0 && (t.fontSize = e.fontSize);
|
|
1072
|
+
break;
|
|
1073
|
+
case "callout":
|
|
1074
|
+
t.text = e.text, "match" in e.target ? t.target = { match: I(e.target.match) } : t.target = { bbox: H(e.target.bbox) }, t.at = U(e.at);
|
|
1075
|
+
break;
|
|
1076
|
+
case "freehand":
|
|
1077
|
+
t.path = e.path;
|
|
1078
|
+
break;
|
|
1079
|
+
case "redact":
|
|
1080
|
+
e.match && (t.match = I(e.match)), e.bbox && (t.bbox = H(e.bbox)), e.style !== void 0 && (t.style = e.style);
|
|
1081
|
+
break;
|
|
1082
|
+
case "focusMask":
|
|
1083
|
+
if ("match" in e.cutout) {
|
|
1084
|
+
let n = { match: I(e.cutout.match) };
|
|
1085
|
+
e.cutout.padding !== void 0 && (n.padding = e.cutout.padding), t.cutout = n;
|
|
1086
|
+
} else t.cutout = { bbox: H(e.cutout.bbox) };
|
|
1087
|
+
e.dimColor !== void 0 && (t.dimColor = e.dimColor);
|
|
1088
|
+
break;
|
|
1089
|
+
}
|
|
1090
|
+
return At(t, e), t;
|
|
1091
|
+
}
|
|
1092
|
+
function kt(e) {
|
|
1093
|
+
return "match" in e ? { match: I(e.match) } : { point: U(e.point) };
|
|
1094
|
+
}
|
|
1095
|
+
function H(e) {
|
|
1096
|
+
return {
|
|
1097
|
+
x: e.x,
|
|
1098
|
+
y: e.y,
|
|
1099
|
+
width: e.width,
|
|
1100
|
+
height: e.height
|
|
1101
|
+
};
|
|
1102
|
+
}
|
|
1103
|
+
function U(e) {
|
|
1104
|
+
return {
|
|
1105
|
+
x: e.x,
|
|
1106
|
+
y: e.y
|
|
1107
|
+
};
|
|
1108
|
+
}
|
|
1109
|
+
function At(e, t) {
|
|
1110
|
+
t.intent !== void 0 && (e.intent = t.intent), t.stroke !== void 0 && (e.stroke = t.stroke), t.strokeWidth !== void 0 && (e.strokeWidth = t.strokeWidth), t.fill !== void 0 && (e.fill = t.fill), t.color !== void 0 && (e.color = t.color);
|
|
1111
|
+
}
|
|
1112
|
+
function jt(e) {
|
|
1113
|
+
if (typeof e.id != "string" || e.id.length === 0) throw new F(`Annotation entry missing id: ${JSON.stringify(e)}`);
|
|
1114
|
+
if (!P.includes(e.kind)) throw new F(`Annotation ${e.id}: unknown kind ${JSON.stringify(e.kind)}`);
|
|
1115
|
+
switch (e.kind) {
|
|
1116
|
+
case "rect":
|
|
1117
|
+
if ([
|
|
1118
|
+
e.match !== void 0,
|
|
1119
|
+
e.coversElements !== void 0,
|
|
1120
|
+
e.bbox !== void 0
|
|
1121
|
+
].filter(Boolean).length !== 1) throw new F(`Annotation ${e.id}: rect requires exactly one of match / coversElements / bbox`);
|
|
1122
|
+
if (e.coversElements && e.coversElements.length === 0) throw new F(`Annotation ${e.id}: rect.coversElements must be non-empty`);
|
|
1123
|
+
break;
|
|
1124
|
+
case "circle":
|
|
1125
|
+
if ([e.match !== void 0, e.center !== void 0].filter(Boolean).length !== 1) throw new F(`Annotation ${e.id}: circle requires exactly one of match / center`);
|
|
1126
|
+
if (e.center && (e.radius === void 0 || !Number.isFinite(e.radius) || e.radius < 0)) throw new F(`Annotation ${e.id}: circle with center requires a finite non-negative radius`);
|
|
1127
|
+
break;
|
|
1128
|
+
case "arrow":
|
|
1129
|
+
if (!e.from || !e.to) throw new F(`Annotation ${e.id}: arrow requires both from + to`);
|
|
1130
|
+
break;
|
|
1131
|
+
case "text":
|
|
1132
|
+
if (typeof e.text != "string" || e.text.length === 0) throw new F(`Annotation ${e.id}: text requires non-empty \`text\``);
|
|
1133
|
+
if ([e.anchor !== void 0, e.at !== void 0].filter(Boolean).length !== 1) throw new F(`Annotation ${e.id}: text requires exactly one of anchor / at`);
|
|
1134
|
+
break;
|
|
1135
|
+
case "callout":
|
|
1136
|
+
if (typeof e.text != "string" || e.text.length === 0) throw new F(`Annotation ${e.id}: callout requires non-empty \`text\``);
|
|
1137
|
+
if (!e.target || !e.at) throw new F(`Annotation ${e.id}: callout requires target + at`);
|
|
1138
|
+
break;
|
|
1139
|
+
case "freehand":
|
|
1140
|
+
if (typeof e.path != "string" || e.path.length === 0) throw new F(`Annotation ${e.id}: freehand requires non-empty \`path\``);
|
|
1141
|
+
break;
|
|
1142
|
+
case "redact":
|
|
1143
|
+
if ([e.match !== void 0, e.bbox !== void 0].filter(Boolean).length !== 1) throw new F(`Annotation ${e.id}: redact requires exactly one of match / bbox`);
|
|
1144
|
+
if (e.style !== void 0 && e.style !== "solid" && e.style !== "mosaic" && e.style !== "blur") throw new F(`Annotation ${e.id}: redact.style must be one of "solid" / "mosaic" / "blur"`);
|
|
1145
|
+
break;
|
|
1146
|
+
case "focusMask":
|
|
1147
|
+
if (!e.cutout) throw new F(`Annotation ${e.id}: focusMask requires cutout`);
|
|
1148
|
+
break;
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
//#endregion
|
|
1152
|
+
//#region src/deprecation.ts
|
|
1153
|
+
var W = /* @__PURE__ */ new Set();
|
|
1154
|
+
function Mt(e, t = (e) => console.warn(e)) {
|
|
1155
|
+
let n = `${e.mdxPath}\0${e.screenId}`;
|
|
1156
|
+
W.has(n) || (W.add(n), t(Nt(e)));
|
|
1157
|
+
}
|
|
1158
|
+
function Nt(e) {
|
|
1159
|
+
return `[annot-docs] DEPRECATED: ${e.mdxPath} screen "${e.screenId}" uses ${e.overlayCount} inline <Overlay> block(s). Run \`annot docs migrate-overlays-to-annotations\` to extract them into a \`.annotations.yaml\` file + <AnnotCallout for=…> JSX. The inline <Overlay> form is supported during a deprecation window; see OQ-08 in docs/plans/living-spec-authoring-roadmap.md for the removal schedule.`;
|
|
1160
|
+
}
|
|
1161
|
+
function Pt() {
|
|
1162
|
+
W.clear();
|
|
1163
|
+
}
|
|
1164
|
+
//#endregion
|
|
1165
|
+
//#region src/resolver.ts
|
|
1166
|
+
function G(e) {
|
|
1167
|
+
let t = [], n = e.split(/\r?\n/), r = [];
|
|
1168
|
+
for (let e of n) {
|
|
1169
|
+
if (!e.trim()) continue;
|
|
1170
|
+
let n = e.length - e.replace(/^\s+/, "").length, i = Math.floor(n / 2), a = e.match(/^\s*-\s+([a-z]+)(?:\s+"([^"]*?)")?/);
|
|
1171
|
+
if (!a) continue;
|
|
1172
|
+
let o = a[1] ?? "", s = a[2] ?? "";
|
|
1173
|
+
for (; r.length > 0 && (r[r.length - 1]?.depth ?? -1) >= i;) r.pop();
|
|
1174
|
+
let c = r.map((e) => ({
|
|
1175
|
+
role: e.role,
|
|
1176
|
+
name: e.name
|
|
1177
|
+
})), l = e.match(/\[ref=(e\d+)\]/);
|
|
1178
|
+
l && t.push({
|
|
1179
|
+
role: o,
|
|
1180
|
+
name: s,
|
|
1181
|
+
ref: l[1] ?? "",
|
|
1182
|
+
depth: i,
|
|
1183
|
+
ancestors: c
|
|
1184
|
+
}), /:\s*$/.test(e) && r.push({
|
|
1185
|
+
depth: i,
|
|
1186
|
+
role: o,
|
|
1187
|
+
name: s
|
|
1188
|
+
});
|
|
1189
|
+
}
|
|
1190
|
+
return t;
|
|
1191
|
+
}
|
|
1192
|
+
async function Ft(e, t, n) {
|
|
1193
|
+
let r = Rt(t.filter((t) => t.role === e.role && t.name === e.name), e.under);
|
|
1194
|
+
if (r.length === 0) return zt(e, t);
|
|
1195
|
+
if (r.length > 1) return {
|
|
1196
|
+
ok: !1,
|
|
1197
|
+
kind: "ambiguous",
|
|
1198
|
+
reason: `Multiple elements match role="${e.role}" name="${e.name}". Use \`under\` to disambiguate.`,
|
|
1199
|
+
candidates: r.map((e) => `[ref=${e.ref}]`)
|
|
1200
|
+
};
|
|
1201
|
+
let i = r[0], a = Lt(n, e), o = await a.count();
|
|
1202
|
+
return o === 0 ? {
|
|
1203
|
+
ok: !1,
|
|
1204
|
+
kind: "live-mismatch",
|
|
1205
|
+
reason: `Snapshot says element exists but live locator failed: role="${e.role}" name="${e.name}".`
|
|
1206
|
+
} : o > 1 ? {
|
|
1207
|
+
ok: !1,
|
|
1208
|
+
kind: "ambiguous",
|
|
1209
|
+
reason: `Live locator returns ${o} elements for role="${e.role}" name="${e.name}".`
|
|
1210
|
+
} : {
|
|
1211
|
+
ok: !0,
|
|
1212
|
+
locator: a,
|
|
1213
|
+
entry: i
|
|
1214
|
+
};
|
|
1215
|
+
}
|
|
1216
|
+
async function It(e, t, n) {
|
|
1217
|
+
let r = [];
|
|
1218
|
+
for (let i of e) r.push({
|
|
1219
|
+
overlay: i,
|
|
1220
|
+
result: await Ft(i.match, t, n)
|
|
1221
|
+
});
|
|
1222
|
+
return r;
|
|
1223
|
+
}
|
|
1224
|
+
function Lt(e, t) {
|
|
1225
|
+
let n = e.getByRole(t.role, {
|
|
1226
|
+
name: t.name,
|
|
1227
|
+
exact: !0
|
|
1228
|
+
});
|
|
1229
|
+
return t.under && (n = e.getByRole(t.under.role, {
|
|
1230
|
+
name: t.under.name,
|
|
1231
|
+
exact: !0
|
|
1232
|
+
}).getByRole(t.role, {
|
|
1233
|
+
name: t.name,
|
|
1234
|
+
exact: !0
|
|
1235
|
+
})), n;
|
|
1236
|
+
}
|
|
1237
|
+
function Rt(e, t) {
|
|
1238
|
+
return t ? e.filter((e) => e.ancestors.some((e) => e.role === t.role && e.name === t.name)) : e;
|
|
1239
|
+
}
|
|
1240
|
+
function zt(e, t) {
|
|
1241
|
+
let n = t.filter((t) => t.name === e.name);
|
|
1242
|
+
if (n.length === 1 && n[0].role !== e.role) return {
|
|
1243
|
+
ok: !1,
|
|
1244
|
+
kind: "role-changed",
|
|
1245
|
+
reason: `Element with name="${e.name}" exists but has role="${n[0].role}", not "${e.role}".`,
|
|
1246
|
+
suggestion: n[0].role
|
|
1247
|
+
};
|
|
1248
|
+
let r = t.filter((t) => t.role === e.role);
|
|
1249
|
+
if (r.length > 0) {
|
|
1250
|
+
let t = Bt(e.name, r.map((e) => e.name));
|
|
1251
|
+
if (t) return {
|
|
1252
|
+
ok: !1,
|
|
1253
|
+
kind: "renamed",
|
|
1254
|
+
reason: `No element with role="${e.role}" name="${e.name}". Closest match: name="${t}".`,
|
|
1255
|
+
suggestion: t
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
return {
|
|
1259
|
+
ok: !1,
|
|
1260
|
+
kind: "not-found",
|
|
1261
|
+
reason: `No element with role="${e.role}" name="${e.name}".`
|
|
1262
|
+
};
|
|
1263
|
+
}
|
|
1264
|
+
function Bt(e, t) {
|
|
1265
|
+
if (t.length === 0) return null;
|
|
1266
|
+
let n = t[0], r = Vt(e, n);
|
|
1267
|
+
for (let i of t.slice(1)) {
|
|
1268
|
+
let t = Vt(e, i);
|
|
1269
|
+
t > r && (n = i, r = t);
|
|
1270
|
+
}
|
|
1271
|
+
return r > .3 ? n : null;
|
|
1272
|
+
}
|
|
1273
|
+
function Vt(e, t) {
|
|
1274
|
+
if (!e || !t) return 0;
|
|
1275
|
+
let n = (e) => {
|
|
1276
|
+
let t = /* @__PURE__ */ new Set();
|
|
1277
|
+
for (let n = 0; n < e.length - 2; n++) t.add(e.slice(n, n + 3));
|
|
1278
|
+
return t;
|
|
1279
|
+
}, r = n(e), i = n(t);
|
|
1280
|
+
if (r.size === 0 || i.size === 0) return 0;
|
|
1281
|
+
let a = 0;
|
|
1282
|
+
for (let e of r) i.has(e) && a++;
|
|
1283
|
+
return a / Math.max(r.size, i.size);
|
|
1284
|
+
}
|
|
1285
|
+
//#endregion
|
|
1286
|
+
//#region src/drift.ts
|
|
1287
|
+
function K(e) {
|
|
1288
|
+
let { screen: t, liveSnapshot: n, storedAttributesYaml: r, freshAttributesYaml: i, yamlOverlays: a, yamlAnnotations: o } = e, s = [], c = a ?? t.overlays, l = /* @__PURE__ */ new Set();
|
|
1289
|
+
for (let e of c) {
|
|
1290
|
+
let r = n.filter((t) => t.role === e.match.role && t.name === e.match.name);
|
|
1291
|
+
if (r.length > 1) {
|
|
1292
|
+
s.push({
|
|
1293
|
+
severity: "error",
|
|
1294
|
+
kind: "duplicated",
|
|
1295
|
+
screenId: t.id,
|
|
1296
|
+
message: `Multiple elements match role="${e.match.role}" name="${e.match.name}". Use \`under\` to disambiguate.`,
|
|
1297
|
+
match: e.match
|
|
1298
|
+
});
|
|
1299
|
+
continue;
|
|
1300
|
+
}
|
|
1301
|
+
if (r.length === 1) continue;
|
|
1302
|
+
let i = n.filter((t) => t.name === e.match.name);
|
|
1303
|
+
if (i.length === 1 && i[0].role !== e.match.role) {
|
|
1304
|
+
let n = i[0];
|
|
1305
|
+
l.add(`${n.role}|${n.name}`), s.push({
|
|
1306
|
+
severity: "warning",
|
|
1307
|
+
kind: "role-changed",
|
|
1308
|
+
screenId: t.id,
|
|
1309
|
+
message: `Element with name="${e.match.name}" exists but has role="${n.role}", not "${e.match.role}".`,
|
|
1310
|
+
match: e.match,
|
|
1311
|
+
suggestion: { role: n.role }
|
|
1312
|
+
});
|
|
1313
|
+
continue;
|
|
1314
|
+
}
|
|
1315
|
+
let a = n.filter((t) => t.role === e.match.role);
|
|
1316
|
+
if (a.length > 0) {
|
|
1317
|
+
let n = qt(e.match.name, a.map((e) => e.name));
|
|
1318
|
+
if (n) {
|
|
1319
|
+
l.add(`${e.match.role}|${n}`), s.push({
|
|
1320
|
+
severity: "warning",
|
|
1321
|
+
kind: "renamed",
|
|
1322
|
+
screenId: t.id,
|
|
1323
|
+
message: `No element with role="${e.match.role}" name="${e.match.name}". Closest match: name="${n}".`,
|
|
1324
|
+
match: e.match,
|
|
1325
|
+
suggestion: { name: n }
|
|
1326
|
+
});
|
|
1327
|
+
continue;
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
s.push({
|
|
1331
|
+
severity: "error",
|
|
1332
|
+
kind: "removed",
|
|
1333
|
+
screenId: t.id,
|
|
1334
|
+
message: `No element with role="${e.match.role}" name="${e.match.name}".`,
|
|
1335
|
+
match: e.match
|
|
1336
|
+
});
|
|
1337
|
+
}
|
|
1338
|
+
let u = new Set(c.map((e) => `${e.match.role}|${e.match.name}`));
|
|
1339
|
+
for (let e of n) {
|
|
1340
|
+
if (!Kt(e.role)) continue;
|
|
1341
|
+
let n = `${e.role}|${e.name}`;
|
|
1342
|
+
u.has(n) || l.has(n) || s.push({
|
|
1343
|
+
severity: "warning",
|
|
1344
|
+
kind: "added",
|
|
1345
|
+
screenId: t.id,
|
|
1346
|
+
message: `New ${e.role} "${e.name}" on the page has no <Overlay>.`,
|
|
1347
|
+
suggestion: {
|
|
1348
|
+
role: e.role,
|
|
1349
|
+
name: e.name
|
|
1350
|
+
}
|
|
1351
|
+
});
|
|
1352
|
+
}
|
|
1353
|
+
if (o !== void 0) for (let e of o) for (let r of Zt(e)) {
|
|
1354
|
+
let i = n.filter((e) => e.role === r.role && e.name === r.name);
|
|
1355
|
+
if (i.length > 1) {
|
|
1356
|
+
s.push({
|
|
1357
|
+
severity: "error",
|
|
1358
|
+
kind: "duplicated",
|
|
1359
|
+
screenId: t.id,
|
|
1360
|
+
message: `Annotation ${e.id}: multiple elements match role="${r.role}" name="${r.name}". Use \`under\` to disambiguate.`,
|
|
1361
|
+
match: r
|
|
1362
|
+
});
|
|
1363
|
+
continue;
|
|
1364
|
+
}
|
|
1365
|
+
if (i.length === 1) continue;
|
|
1366
|
+
let a = n.filter((e) => e.name === r.name);
|
|
1367
|
+
if (a.length === 1 && a[0].role !== r.role) {
|
|
1368
|
+
let n = a[0];
|
|
1369
|
+
l.add(`${n.role}|${n.name}`), s.push({
|
|
1370
|
+
severity: "warning",
|
|
1371
|
+
kind: "role-changed",
|
|
1372
|
+
screenId: t.id,
|
|
1373
|
+
message: `Annotation ${e.id}: element with name="${r.name}" exists but has role="${n.role}", not "${r.role}".`,
|
|
1374
|
+
match: r,
|
|
1375
|
+
suggestion: { role: n.role }
|
|
1376
|
+
});
|
|
1377
|
+
continue;
|
|
1378
|
+
}
|
|
1379
|
+
let o = n.filter((e) => e.role === r.role);
|
|
1380
|
+
if (o.length > 0) {
|
|
1381
|
+
let n = qt(r.name, o.map((e) => e.name));
|
|
1382
|
+
if (n) {
|
|
1383
|
+
l.add(`${r.role}|${n}`), s.push({
|
|
1384
|
+
severity: "warning",
|
|
1385
|
+
kind: "renamed",
|
|
1386
|
+
screenId: t.id,
|
|
1387
|
+
message: `Annotation ${e.id}: no element with role="${r.role}" name="${r.name}". Closest match: name="${n}".`,
|
|
1388
|
+
match: r,
|
|
1389
|
+
suggestion: { name: n }
|
|
1390
|
+
});
|
|
1391
|
+
continue;
|
|
1392
|
+
}
|
|
1393
|
+
}
|
|
1394
|
+
s.push({
|
|
1395
|
+
severity: "error",
|
|
1396
|
+
kind: "removed",
|
|
1397
|
+
screenId: t.id,
|
|
1398
|
+
message: `Annotation ${e.id}: no element with role="${r.role}" name="${r.name}".`,
|
|
1399
|
+
match: r
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
if (a !== void 0) {
|
|
1403
|
+
let e = new Set(a.map((e) => e.id)), n = new Set(t.callouts.map((e) => e.for));
|
|
1404
|
+
for (let e of a) n.has(e.id) || s.push({
|
|
1405
|
+
severity: "warning",
|
|
1406
|
+
kind: "description-missing",
|
|
1407
|
+
screenId: t.id,
|
|
1408
|
+
message: `annotations yaml has \`overlays[].id="${e.id}"\` but no <AnnotCallout for="${e.id}"> in MDX.`,
|
|
1409
|
+
match: e.match
|
|
1410
|
+
});
|
|
1411
|
+
for (let n of t.callouts) e.has(n.for) || s.push({
|
|
1412
|
+
severity: "error",
|
|
1413
|
+
kind: "description-orphan",
|
|
1414
|
+
screenId: t.id,
|
|
1415
|
+
message: `<AnnotCallout for="${n.for}"> has no matching entry in annotations yaml \`overlays[]\`.`
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1418
|
+
return r !== void 0 && i !== void 0 && Yt(r) !== Yt(i) && s.push({
|
|
1419
|
+
severity: "info",
|
|
1420
|
+
kind: "attribute-drift",
|
|
1421
|
+
screenId: t.id,
|
|
1422
|
+
message: "`annot:attributes` block no longer matches live element attributes. Run `annot docs sync` to update."
|
|
1423
|
+
}), s;
|
|
1424
|
+
}
|
|
1425
|
+
function Ht(e) {
|
|
1426
|
+
return K({
|
|
1427
|
+
screen: e.screen,
|
|
1428
|
+
liveSnapshot: G(e.liveSnapshotYaml),
|
|
1429
|
+
storedAttributesYaml: e.storedAttributesYaml,
|
|
1430
|
+
freshAttributesYaml: e.freshAttributesYaml,
|
|
1431
|
+
yamlOverlays: e.yamlOverlays,
|
|
1432
|
+
yamlAnnotations: e.yamlAnnotations
|
|
1433
|
+
});
|
|
1434
|
+
}
|
|
1435
|
+
function Ut(e) {
|
|
1436
|
+
let t = [];
|
|
1437
|
+
return ae(e, (e, n) => {
|
|
1438
|
+
!e.role || !e.name || t.push({
|
|
1439
|
+
role: e.role,
|
|
1440
|
+
name: e.name,
|
|
1441
|
+
ref: e.ref,
|
|
1442
|
+
depth: n.length,
|
|
1443
|
+
ancestors: n.filter((e) => typeof e.name == "string").map((e) => ({
|
|
1444
|
+
role: e.role,
|
|
1445
|
+
name: e.name
|
|
1446
|
+
}))
|
|
1447
|
+
});
|
|
1448
|
+
}), t;
|
|
1449
|
+
}
|
|
1450
|
+
function Wt(e) {
|
|
1451
|
+
return K({
|
|
1452
|
+
screen: e.screen,
|
|
1453
|
+
liveSnapshot: Ut(e.liveElementTree),
|
|
1454
|
+
storedAttributesYaml: e.storedAttributesYaml,
|
|
1455
|
+
freshAttributesYaml: e.freshAttributesYaml,
|
|
1456
|
+
yamlOverlays: e.yamlOverlays,
|
|
1457
|
+
yamlAnnotations: e.yamlAnnotations
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
function q(e) {
|
|
1461
|
+
let t = 0, n = 0, r = 0;
|
|
1462
|
+
for (let i of e) i.severity === "error" ? t++ : i.severity === "warning" ? n++ : r++;
|
|
1463
|
+
return {
|
|
1464
|
+
errors: t,
|
|
1465
|
+
warnings: n,
|
|
1466
|
+
infos: r
|
|
1467
|
+
};
|
|
1468
|
+
}
|
|
1469
|
+
var Gt = /* @__PURE__ */ new Set([
|
|
1470
|
+
"button",
|
|
1471
|
+
"checkbox",
|
|
1472
|
+
"combobox",
|
|
1473
|
+
"link",
|
|
1474
|
+
"menuitem",
|
|
1475
|
+
"menuitemcheckbox",
|
|
1476
|
+
"menuitemradio",
|
|
1477
|
+
"option",
|
|
1478
|
+
"radio",
|
|
1479
|
+
"searchbox",
|
|
1480
|
+
"slider",
|
|
1481
|
+
"spinbutton",
|
|
1482
|
+
"switch",
|
|
1483
|
+
"tab",
|
|
1484
|
+
"textbox",
|
|
1485
|
+
"treeitem"
|
|
1486
|
+
]);
|
|
1487
|
+
function Kt(e) {
|
|
1488
|
+
return Gt.has(e);
|
|
1489
|
+
}
|
|
1490
|
+
function qt(e, t) {
|
|
1491
|
+
if (t.length === 0) return null;
|
|
1492
|
+
let n = t[0], r = Jt(e, n);
|
|
1493
|
+
for (let i of t.slice(1)) {
|
|
1494
|
+
let t = Jt(e, i);
|
|
1495
|
+
t > r && (n = i, r = t);
|
|
1496
|
+
}
|
|
1497
|
+
return r > .3 ? n : null;
|
|
1498
|
+
}
|
|
1499
|
+
function Jt(e, t) {
|
|
1500
|
+
if (!e || !t) return 0;
|
|
1501
|
+
let n = (e) => {
|
|
1502
|
+
let t = /* @__PURE__ */ new Set();
|
|
1503
|
+
for (let n = 0; n < e.length - 2; n++) t.add(e.slice(n, n + 3));
|
|
1504
|
+
return t;
|
|
1505
|
+
}, r = n(e), i = n(t);
|
|
1506
|
+
if (r.size === 0 || i.size === 0) return 0;
|
|
1507
|
+
let a = 0;
|
|
1508
|
+
for (let e of r) i.has(e) && a++;
|
|
1509
|
+
return a / Math.max(r.size, i.size);
|
|
1510
|
+
}
|
|
1511
|
+
function Yt(e) {
|
|
1512
|
+
return e.split(/\r?\n/).map((e) => e.trimEnd()).filter((e) => e.length > 0).join("\n");
|
|
1513
|
+
}
|
|
1514
|
+
function Xt(e) {
|
|
1515
|
+
return e.overlays.length > 0 || e.annotations !== void 0 || e.callouts.length > 0;
|
|
1516
|
+
}
|
|
1517
|
+
function J(e) {
|
|
1518
|
+
return e.filter(Xt);
|
|
1519
|
+
}
|
|
1520
|
+
function Zt(e) {
|
|
1521
|
+
switch (e.kind) {
|
|
1522
|
+
case "rect": return e.match ? [e.match] : e.coversElements ? [...e.coversElements] : [];
|
|
1523
|
+
case "circle": return e.match ? [e.match] : [];
|
|
1524
|
+
case "arrow": {
|
|
1525
|
+
let t = [];
|
|
1526
|
+
return "match" in e.from && t.push(e.from.match), "match" in e.to && t.push(e.to.match), t;
|
|
1527
|
+
}
|
|
1528
|
+
case "text": return e.anchor ? [e.anchor.match] : [];
|
|
1529
|
+
case "callout": return "match" in e.target ? [e.target.match] : [];
|
|
1530
|
+
case "freehand": return [];
|
|
1531
|
+
case "redact": return e.match ? [e.match] : [];
|
|
1532
|
+
case "focusMask": return "match" in e.cutout ? [e.cutout.match] : [];
|
|
1533
|
+
}
|
|
1534
|
+
}
|
|
1535
|
+
//#endregion
|
|
1536
|
+
//#region src/migrate-overlays-to-annotations.ts
|
|
1537
|
+
async function Qt(e, t = {}) {
|
|
1538
|
+
let n = await y(e);
|
|
1539
|
+
if (!n) return {
|
|
1540
|
+
mdxPath: e,
|
|
1541
|
+
screens: [],
|
|
1542
|
+
mdxRewritten: !1
|
|
1543
|
+
};
|
|
1544
|
+
let i = [], a = [];
|
|
1545
|
+
for (let s of n.screens) {
|
|
1546
|
+
if (s.annotations !== void 0) {
|
|
1547
|
+
a.push({
|
|
1548
|
+
id: s.id,
|
|
1549
|
+
overlayCount: 0,
|
|
1550
|
+
yamlWritten: !1,
|
|
1551
|
+
skipReason: "already-migrated"
|
|
1552
|
+
});
|
|
1553
|
+
continue;
|
|
1554
|
+
}
|
|
1555
|
+
if (s.overlays.length === 0) {
|
|
1556
|
+
a.push({
|
|
1557
|
+
id: s.id,
|
|
1558
|
+
overlayCount: 0,
|
|
1559
|
+
yamlWritten: !1,
|
|
1560
|
+
skipReason: "no-overlays"
|
|
1561
|
+
});
|
|
1562
|
+
continue;
|
|
1563
|
+
}
|
|
1564
|
+
if (!s.src) {
|
|
1565
|
+
a.push({
|
|
1566
|
+
id: s.id,
|
|
1567
|
+
overlayCount: s.overlays.length,
|
|
1568
|
+
yamlWritten: !1,
|
|
1569
|
+
skipReason: "no-src"
|
|
1570
|
+
});
|
|
1571
|
+
continue;
|
|
1572
|
+
}
|
|
1573
|
+
let c = tn({
|
|
1574
|
+
mdxPath: e,
|
|
1575
|
+
screenId: s.id,
|
|
1576
|
+
src: s.src,
|
|
1577
|
+
override: t.yamlPathFor
|
|
1578
|
+
}), l = nn(m(e), c), u = an(n.source, s), d = rn(n.source, s, l);
|
|
1579
|
+
if (!d || u.length !== s.overlays.length) throw Error(`migrateOverlaysToAnnotationsFile: ${e} screen "${s.id}" position data incomplete — cannot rewrite safely.`);
|
|
1580
|
+
i.push(d, ...u.map((e) => e.edit));
|
|
1581
|
+
let f = $t(s.overlays);
|
|
1582
|
+
a.push({
|
|
1583
|
+
id: s.id,
|
|
1584
|
+
yamlPath: c,
|
|
1585
|
+
yamlWritten: !1,
|
|
1586
|
+
overlayCount: s.overlays.length
|
|
1587
|
+
}), t.dryRun || (await r(m(c), { recursive: !0 }), await o(c, pt(f), "utf8"), a[a.length - 1].yamlWritten = !0);
|
|
1588
|
+
}
|
|
1589
|
+
let s = !1;
|
|
1590
|
+
if (i.length > 0 && !t.dryRun) {
|
|
1591
|
+
let t = en(n.source, i);
|
|
1592
|
+
t !== n.source && (await o(e, t, "utf8"), s = !0);
|
|
1593
|
+
}
|
|
1594
|
+
return {
|
|
1595
|
+
mdxPath: e,
|
|
1596
|
+
screens: a,
|
|
1597
|
+
mdxRewritten: s
|
|
1598
|
+
};
|
|
1599
|
+
}
|
|
1600
|
+
function $t(e) {
|
|
1601
|
+
return {
|
|
1602
|
+
version: 1,
|
|
1603
|
+
overlays: e.map((e, t) => {
|
|
1604
|
+
let n = {
|
|
1605
|
+
id: `o${t + 1}`,
|
|
1606
|
+
kind: "numberedBadge",
|
|
1607
|
+
match: e.match,
|
|
1608
|
+
number: e.number ?? t + 1
|
|
1609
|
+
};
|
|
1610
|
+
return e.intent && (n.intent = e.intent), n;
|
|
1611
|
+
}),
|
|
1612
|
+
meta: { generator: "annot-docs migrate-overlays-to-annotations@1" }
|
|
1613
|
+
};
|
|
1614
|
+
}
|
|
1615
|
+
function en(e, t) {
|
|
1616
|
+
let n = [...t].sort((e, t) => t.start - e.start), r = e;
|
|
1617
|
+
for (let e of n) r = r.slice(0, e.start) + e.replacement + r.slice(e.end);
|
|
1618
|
+
return r;
|
|
1619
|
+
}
|
|
1620
|
+
function tn(e) {
|
|
1621
|
+
if (e.override) return e.override({
|
|
1622
|
+
mdxPath: e.mdxPath,
|
|
1623
|
+
screenId: e.screenId,
|
|
1624
|
+
src: e.src
|
|
1625
|
+
});
|
|
1626
|
+
let t = h(e.src) ? e.src : _(m(e.mdxPath), e.src), n = ne(t).replace(/\.(png|jpe?g|webp|gif|svg)$/i, "");
|
|
1627
|
+
return _(m(t), `${n}.annotations.yaml`);
|
|
1628
|
+
}
|
|
1629
|
+
function nn(e, t) {
|
|
1630
|
+
let n = g(e, t).split(/[\\/]/).join("/");
|
|
1631
|
+
return n.startsWith(".") || n.startsWith("/") ? n : `./${n}`;
|
|
1632
|
+
}
|
|
1633
|
+
function rn(e, t, n) {
|
|
1634
|
+
let r = new RegExp(String.raw`<Screen\b[^>]*\bid=(?:"${Y(t.id)}"|'${Y(t.id)}'|\{["']${Y(t.id)}["']\})[^>]*?(/?)>`, "m").exec(e);
|
|
1635
|
+
if (!r || r.index === void 0) return null;
|
|
1636
|
+
let i = r.index, a = i + r[0].length, o = r[1] === "/" ? a - 2 : a - 1, s = e.slice(i, o);
|
|
1637
|
+
return {
|
|
1638
|
+
start: o,
|
|
1639
|
+
end: o,
|
|
1640
|
+
replacement: `${/\s$/.test(s) ? "" : " "}annotations="${n}"`
|
|
1641
|
+
};
|
|
1642
|
+
}
|
|
1643
|
+
function an(e, t) {
|
|
1644
|
+
let n = new RegExp(String.raw`<Screen\b[^>]*\bid=(?:"${Y(t.id)}"|'${Y(t.id)}'|\{["']${Y(t.id)}["']\})[^>]*?>`, "m").exec(e);
|
|
1645
|
+
if (!n || n.index === void 0) return [];
|
|
1646
|
+
let r = n.index + n[0].length, i = e.indexOf("</Screen>", r);
|
|
1647
|
+
if (i === -1) return [];
|
|
1648
|
+
let a = i, o = [], s = r;
|
|
1649
|
+
for (let n = 0; n < t.overlays.length; n++) {
|
|
1650
|
+
let r = t.overlays[n], i = e.indexOf("<Overlay", s);
|
|
1651
|
+
if (i === -1 || i >= a) return o;
|
|
1652
|
+
let c = e.indexOf("</Overlay>", i);
|
|
1653
|
+
if (c === -1 || c >= a) return o;
|
|
1654
|
+
let l = c + 10, u = e.indexOf(">", i);
|
|
1655
|
+
if (u === -1 || u >= c) return o;
|
|
1656
|
+
let d = e.slice(u + 1, c), f = `<AnnotCallout for="${`o${n + 1}`}">${d}</AnnotCallout>`;
|
|
1657
|
+
o.push({
|
|
1658
|
+
overlay: r,
|
|
1659
|
+
edit: {
|
|
1660
|
+
start: i,
|
|
1661
|
+
end: l,
|
|
1662
|
+
replacement: f
|
|
1663
|
+
}
|
|
1664
|
+
}), s = l;
|
|
1665
|
+
}
|
|
1666
|
+
return o;
|
|
1667
|
+
}
|
|
1668
|
+
function Y(e) {
|
|
1669
|
+
return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
1670
|
+
}
|
|
1671
|
+
//#endregion
|
|
1672
|
+
//#region src/migrate-to-element-tree.ts
|
|
1673
|
+
var on = [
|
|
1674
|
+
"type",
|
|
1675
|
+
"required",
|
|
1676
|
+
"placeholder",
|
|
1677
|
+
"name",
|
|
1678
|
+
"id",
|
|
1679
|
+
"href",
|
|
1680
|
+
"aria-checked",
|
|
1681
|
+
"aria-expanded",
|
|
1682
|
+
"aria-selected",
|
|
1683
|
+
"aria-disabled",
|
|
1684
|
+
"aria-invalid"
|
|
1685
|
+
];
|
|
1686
|
+
async function sn(e, t = {}) {
|
|
1687
|
+
let n = await y(e);
|
|
1688
|
+
if (!n) return {
|
|
1689
|
+
mdxPath: e,
|
|
1690
|
+
screens: [],
|
|
1691
|
+
mdxRewritten: !1
|
|
1692
|
+
};
|
|
1693
|
+
let r = n.commentBlocks.snapshot?.trim() ?? "", a = n.commentBlocks.attributes?.trim() ?? "", s = [];
|
|
1694
|
+
for (let c of n.screens) {
|
|
1695
|
+
if (!r) {
|
|
1696
|
+
s.push({
|
|
1697
|
+
id: c.id,
|
|
1698
|
+
xmpWritten: !1,
|
|
1699
|
+
skipReason: "no-snapshot"
|
|
1700
|
+
});
|
|
1701
|
+
continue;
|
|
1702
|
+
}
|
|
1703
|
+
if (!c.src) {
|
|
1704
|
+
s.push({
|
|
1705
|
+
id: c.id,
|
|
1706
|
+
xmpWritten: !1,
|
|
1707
|
+
skipReason: "no-src"
|
|
1708
|
+
});
|
|
1709
|
+
continue;
|
|
1710
|
+
}
|
|
1711
|
+
let n = un(e, c.src);
|
|
1712
|
+
if (!n) {
|
|
1713
|
+
s.push({
|
|
1714
|
+
id: c.id,
|
|
1715
|
+
xmpWritten: !1,
|
|
1716
|
+
skipReason: "no-src"
|
|
1717
|
+
});
|
|
1718
|
+
continue;
|
|
1719
|
+
}
|
|
1720
|
+
let l = cn({
|
|
1721
|
+
snapshotYaml: r,
|
|
1722
|
+
attributesYaml: a,
|
|
1723
|
+
whitelist: t.attributeWhitelist ?? on
|
|
1724
|
+
});
|
|
1725
|
+
if (t.dryRun) {
|
|
1726
|
+
s.push({
|
|
1727
|
+
id: c.id,
|
|
1728
|
+
pngPath: n,
|
|
1729
|
+
xmpWritten: !0
|
|
1730
|
+
});
|
|
1731
|
+
continue;
|
|
1732
|
+
}
|
|
1733
|
+
await o(n, oe(await i(n), l)), s.push({
|
|
1734
|
+
id: c.id,
|
|
1735
|
+
pngPath: n,
|
|
1736
|
+
xmpWritten: !0
|
|
1737
|
+
});
|
|
1738
|
+
}
|
|
1739
|
+
let c = !!(n.commentBlocks.snapshot || n.commentBlocks.attributes), l = !1;
|
|
1740
|
+
if (c && !t.dryRun) {
|
|
1741
|
+
let t = dn(n.source);
|
|
1742
|
+
t !== n.source && (await o(e, t, "utf8"), l = !0);
|
|
1743
|
+
}
|
|
1744
|
+
return {
|
|
1745
|
+
mdxPath: e,
|
|
1746
|
+
screens: s,
|
|
1747
|
+
mdxRewritten: l
|
|
1748
|
+
};
|
|
1749
|
+
}
|
|
1750
|
+
function cn(e) {
|
|
1751
|
+
let n = t({
|
|
1752
|
+
yaml: e.snapshotYaml,
|
|
1753
|
+
viewport: {
|
|
1754
|
+
width: 0,
|
|
1755
|
+
height: 0,
|
|
1756
|
+
scale: 1
|
|
1757
|
+
},
|
|
1758
|
+
agent: "annot-docs-migrate-to-element-tree@1",
|
|
1759
|
+
capturedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
1760
|
+
}), r = ln(e.attributesYaml, e.whitelist);
|
|
1761
|
+
for (let e of r) {
|
|
1762
|
+
let t = ie(n, {
|
|
1763
|
+
role: e.role,
|
|
1764
|
+
name: e.name
|
|
1765
|
+
});
|
|
1766
|
+
if (t.length !== 1) continue;
|
|
1767
|
+
let r = t[0];
|
|
1768
|
+
Object.keys(e.attributes).length !== 0 && (r.attributes = {
|
|
1769
|
+
...r.attributes ?? {},
|
|
1770
|
+
...e.attributes
|
|
1771
|
+
});
|
|
1772
|
+
}
|
|
1773
|
+
return n;
|
|
1774
|
+
}
|
|
1775
|
+
function ln(e, t) {
|
|
1776
|
+
let n = [];
|
|
1777
|
+
if (!e.trim()) return n;
|
|
1778
|
+
let r = new Set(t), i = e.split(/\r?\n/), a = null, o = /^([a-z]+)\s+"([^"]*)"\s*:\s*$/;
|
|
1779
|
+
for (let e of i) {
|
|
1780
|
+
let t = e.trim();
|
|
1781
|
+
if (!t) continue;
|
|
1782
|
+
let i = t.match(o);
|
|
1783
|
+
if (i) {
|
|
1784
|
+
a = {
|
|
1785
|
+
role: i[1] ?? "",
|
|
1786
|
+
name: i[2] ?? "",
|
|
1787
|
+
attributes: {}
|
|
1788
|
+
}, n.push(a);
|
|
1789
|
+
continue;
|
|
1790
|
+
}
|
|
1791
|
+
if (!a) continue;
|
|
1792
|
+
let s = t.indexOf(":");
|
|
1793
|
+
if (s <= 0) continue;
|
|
1794
|
+
let c = t.slice(0, s).trim(), l = t.slice(s + 1).trim();
|
|
1795
|
+
r.has(c) && ((l.startsWith("\"") && l.endsWith("\"") || l.startsWith("'") && l.endsWith("'")) && (l = l.slice(1, -1)), a.attributes[c] = l);
|
|
1796
|
+
}
|
|
1797
|
+
return n;
|
|
1798
|
+
}
|
|
1799
|
+
function un(e, t) {
|
|
1800
|
+
return /^[a-z][a-z0-9+.-]*:/i.test(t) ? null : h(t) ? t : _(m(e), t);
|
|
1801
|
+
}
|
|
1802
|
+
function dn(e) {
|
|
1803
|
+
let t = e;
|
|
1804
|
+
return t = fn(t, "annot:snapshot"), t = fn(t, "annot:attributes"), t;
|
|
1805
|
+
}
|
|
1806
|
+
function fn(e, t) {
|
|
1807
|
+
let n = `{/* ${t}`, r = e.indexOf(n);
|
|
1808
|
+
if (r === -1) return e;
|
|
1809
|
+
let i = e.indexOf("*/}", r);
|
|
1810
|
+
if (i === -1) return e;
|
|
1811
|
+
let a = i + 3, o = e[a] === "\n" ? a + 1 : a;
|
|
1812
|
+
return e.slice(0, r) + e.slice(o);
|
|
1813
|
+
}
|
|
1814
|
+
//#endregion
|
|
1815
|
+
//#region src/cli.ts
|
|
1816
|
+
async function pn(e, t = {}) {
|
|
1817
|
+
let n = t.stdout ?? ((e) => process.stdout.write(`${e}\n`)), r = t.stderr ?? ((e) => process.stderr.write(`${e}\n`)), i = t.cwd ?? process.cwd(), [, , a, ...o] = e;
|
|
1818
|
+
if (a !== "init" && a !== "sync" && a !== "lint" && a !== "migrate-to-element-tree" && a !== "migrate-overlays-to-annotations") return r(mn), +!!a;
|
|
1819
|
+
try {
|
|
1820
|
+
switch (a) {
|
|
1821
|
+
case "init": return await hn(o, {
|
|
1822
|
+
cwd: i,
|
|
1823
|
+
stdout: n,
|
|
1824
|
+
stderr: r
|
|
1825
|
+
});
|
|
1826
|
+
case "sync": return await yn(o, {
|
|
1827
|
+
...t,
|
|
1828
|
+
cwd: i,
|
|
1829
|
+
stdout: n,
|
|
1830
|
+
stderr: r
|
|
1831
|
+
});
|
|
1832
|
+
case "lint": return await bn(o, {
|
|
1833
|
+
...t,
|
|
1834
|
+
cwd: i,
|
|
1835
|
+
stdout: n,
|
|
1836
|
+
stderr: r
|
|
1837
|
+
});
|
|
1838
|
+
case "migrate-to-element-tree": return await Sn(o, {
|
|
1839
|
+
cwd: i,
|
|
1840
|
+
stdout: n,
|
|
1841
|
+
stderr: r
|
|
1842
|
+
});
|
|
1843
|
+
case "migrate-overlays-to-annotations": return await Cn(o, {
|
|
1844
|
+
cwd: i,
|
|
1845
|
+
stdout: n,
|
|
1846
|
+
stderr: r
|
|
1847
|
+
});
|
|
1848
|
+
}
|
|
1849
|
+
} catch (e) {
|
|
1850
|
+
return r(`annot docs ${a}: ${e.message}`), 1;
|
|
1851
|
+
}
|
|
632
1852
|
}
|
|
633
|
-
var
|
|
1853
|
+
var mn = [
|
|
634
1854
|
"annot docs <command> [options]",
|
|
635
1855
|
"",
|
|
636
1856
|
"Commands:",
|
|
637
1857
|
" init Scaffold annot-docs.config.ts + sample files",
|
|
638
1858
|
" sync --url <baseUrl> Re-capture snapshot + attrs into every annot MDX",
|
|
639
1859
|
" lint --url <baseUrl> Report drift between annot MDXs and the live page",
|
|
1860
|
+
" migrate-to-element-tree Convert legacy annot:snapshot / annot:attributes",
|
|
1861
|
+
" MDX blocks into PNG XMP annot:elementTree chunks",
|
|
1862
|
+
" (one-time, per Phase 1g of",
|
|
1863
|
+
" docs/plans/living-spec-authoring-roadmap.md)",
|
|
1864
|
+
" migrate-overlays-to-annotations",
|
|
1865
|
+
" Extract inline <Overlay> JSX into",
|
|
1866
|
+
" .annotations.yaml files and rewrite the MDX to use",
|
|
1867
|
+
" <Screen annotations> + <AnnotCallout for> (one-time,",
|
|
1868
|
+
" per Phase 2d of",
|
|
1869
|
+
" docs/plans/living-spec-authoring-roadmap.md)",
|
|
640
1870
|
"",
|
|
641
1871
|
"Options:",
|
|
642
1872
|
" --url <baseUrl> Base URL Playwright navigates to (sync / lint)",
|
|
643
1873
|
" --root <dir> Override MDX search root (default: docs/)",
|
|
1874
|
+
" --dry-run migrate-to-element-tree only — report what would",
|
|
1875
|
+
" be changed without writing back",
|
|
1876
|
+
" --check-descriptions lint only — also validate <AnnotCallout for> IDs",
|
|
1877
|
+
" against the screen's annotations yaml overlays[]",
|
|
1878
|
+
" (Phase 2c of living-spec-authoring-roadmap.md)",
|
|
644
1879
|
" --help Show this help"
|
|
645
1880
|
].join("\n");
|
|
646
|
-
async function
|
|
647
|
-
let { cwd:
|
|
1881
|
+
async function hn(e, t) {
|
|
1882
|
+
let { cwd: n, stdout: i } = t, a = [
|
|
648
1883
|
{
|
|
649
1884
|
path: "annot-docs.config.ts",
|
|
650
|
-
content:
|
|
1885
|
+
content: gn
|
|
651
1886
|
},
|
|
652
1887
|
{
|
|
653
1888
|
path: "tests/docs/example.spec.ts",
|
|
654
|
-
content:
|
|
1889
|
+
content: _n
|
|
655
1890
|
},
|
|
656
1891
|
{
|
|
657
1892
|
path: "docs/books/example/SC-001-login.mdx",
|
|
658
|
-
content:
|
|
1893
|
+
content: vn
|
|
659
1894
|
}
|
|
660
|
-
],
|
|
661
|
-
for (let
|
|
662
|
-
let
|
|
1895
|
+
], s = 0;
|
|
1896
|
+
for (let e of a) {
|
|
1897
|
+
let t = _(n, e.path);
|
|
663
1898
|
try {
|
|
664
|
-
await
|
|
665
|
-
} catch (
|
|
666
|
-
if (
|
|
667
|
-
else throw
|
|
1899
|
+
await r(m(t), { recursive: !0 }), await o(t, e.content, { flag: "wx" }), i(` created ${e.path}`), s++;
|
|
1900
|
+
} catch (t) {
|
|
1901
|
+
if (t.code === "EEXIST") i(` exists ${e.path} (skipped)`);
|
|
1902
|
+
else throw t;
|
|
668
1903
|
}
|
|
669
1904
|
}
|
|
670
|
-
return
|
|
1905
|
+
return i(s === 0 ? "annot docs init: nothing to do (all targets exist)" : `annot docs init: wrote ${s} file(s)`), 0;
|
|
671
1906
|
}
|
|
672
|
-
var
|
|
673
|
-
async function
|
|
1907
|
+
var gn = "// Living product docs config for annot.\n// See https://github.com/ingcreators/annot/blob/main/docs/plans/living-product-docs.md\nimport { defineConfig } from \"@ingcreators/annot-product-docs\";\n\nexport default defineConfig({\n meta: {\n projectName: \"Example\",\n },\n xlsx: {\n defaultBook: \"Screen spec\",\n books: {\n \"Screen spec\": {\n // Drop your customer-supplied template here (Phase 3) and\n // the Excel adapter will fill it. Until then the OSS\n // default layout applies.\n // template: \"./templates/customer-screen-spec.xlsx\",\n },\n },\n },\n});\n", _n = "// Tour file — runs through every screen and refreshes the\n// matching MDX's annot:snapshot / annot:attributes blocks.\n//\n// Run with: pnpm playwright test tests/docs/\n\nimport { test } from \"@ingcreators/annot-product-docs\";\n\ntest.describe.configure({ mode: \"serial\" });\n\ntest(\"login flow\", async ({ page, productDocs }) => {\n await page.goto(\"/login\");\n await productDocs.sync({\n id: \"login\",\n mdxPath: \"docs/books/example/SC-001-login.mdx\",\n });\n});\n", vn = "---\nannot:\n id: SC-001\n title: Login screen\n meta:\n author: TODO\n xlsx:\n book: Screen spec\n sheet: SC-001 Login\n role: screen\n order: 100\n---\n\nimport { Screen, Overlay } from \"@ingcreators/annot-product-docs-astro\";\n\n# Login screen\n\nEnter your credentials to access the system.\n\n<Screen id=\"login\" src=\"./shots/login.png\">\n\n<Overlay match={{ role: \"textbox\", name: \"Email\" }} intent=\"required\" number={1}>\n**Email** — Enter your registered email address.\n</Overlay>\n\n<Overlay match={{ role: \"button\", name: \"Sign in\" }} intent=\"action\" number={2}>\nClick to sign in.\n</Overlay>\n\n</Screen>\n";
|
|
1908
|
+
async function yn(e, t) {
|
|
674
1909
|
let { cwd: n, stdout: r, stderr: i } = t, a = Z(e);
|
|
675
1910
|
if (!a.url) return i("annot docs sync: --url <baseUrl> is required."), 1;
|
|
676
|
-
let
|
|
677
|
-
if (
|
|
678
|
-
r(`annot docs sync: ${
|
|
679
|
-
let { newPage:
|
|
1911
|
+
let o = await $(await Q(_(n, a.root ?? "docs")));
|
|
1912
|
+
if (o.length === 0) return r(`annot docs sync: no MDX files with \`annot:\` frontmatter under ${a.root ?? "docs"}.`), 0;
|
|
1913
|
+
r(`annot docs sync: ${o.length} MDX file(s) → ${a.url}`);
|
|
1914
|
+
let { newPage: s, close: c } = await X(a.url, t);
|
|
680
1915
|
try {
|
|
681
|
-
for (let e of
|
|
682
|
-
let t = await
|
|
1916
|
+
for (let e of o) {
|
|
1917
|
+
let t = await y(e);
|
|
683
1918
|
if (!t) continue;
|
|
684
|
-
let i =
|
|
1919
|
+
let i = J(t.screens);
|
|
685
1920
|
if (i.length === 0) {
|
|
686
|
-
r(` skip ${
|
|
1921
|
+
r(` skip ${g(n, e)} (no <Screen> blocks)`);
|
|
687
1922
|
continue;
|
|
688
1923
|
}
|
|
689
1924
|
for (let t of i) {
|
|
690
|
-
let { page: i, dispose: a } = await
|
|
1925
|
+
let { page: i, dispose: a } = await s(t.src ?? "/");
|
|
691
1926
|
try {
|
|
692
|
-
await
|
|
1927
|
+
await D(i, {
|
|
693
1928
|
id: t.id,
|
|
694
1929
|
mdxPath: e
|
|
695
|
-
}), r(` synced ${
|
|
1930
|
+
}), r(` synced ${g(n, e)} (screen=${t.id})`);
|
|
696
1931
|
} finally {
|
|
697
1932
|
await a();
|
|
698
1933
|
}
|
|
699
1934
|
}
|
|
700
1935
|
}
|
|
701
1936
|
} finally {
|
|
702
|
-
await
|
|
1937
|
+
await c();
|
|
703
1938
|
}
|
|
704
1939
|
return 0;
|
|
705
1940
|
}
|
|
706
|
-
async function
|
|
1941
|
+
async function bn(e, t) {
|
|
707
1942
|
let { cwd: n, stdout: r, stderr: i } = t, a = Z(e);
|
|
708
1943
|
if (!a.url) return i("annot docs lint: --url <baseUrl> is required."), 1;
|
|
709
|
-
let
|
|
710
|
-
if (
|
|
1944
|
+
let o = await $(await Q(_(n, a.root ?? "docs")));
|
|
1945
|
+
if (o.length === 0) return a.json ? r(JSON.stringify({
|
|
711
1946
|
findings: [],
|
|
712
1947
|
summary: {
|
|
713
1948
|
errors: 0,
|
|
@@ -715,34 +1950,41 @@ async function Ae(e, t) {
|
|
|
715
1950
|
infos: 0
|
|
716
1951
|
}
|
|
717
1952
|
})) : r(`annot docs lint: no MDX files with \`annot:\` frontmatter under ${a.root ?? "docs"}.`), 0;
|
|
718
|
-
a.json || r(`annot docs lint: ${
|
|
719
|
-
let
|
|
1953
|
+
a.json || r(`annot docs lint: ${o.length} MDX file(s) → ${a.url}`);
|
|
1954
|
+
let s = [], c = /* @__PURE__ */ new Set(), { newPage: l, close: u } = await X(a.url, t);
|
|
720
1955
|
try {
|
|
721
|
-
for (let e of
|
|
722
|
-
let t = await
|
|
723
|
-
if (t) for (let r of
|
|
724
|
-
let { page: t, dispose:
|
|
1956
|
+
for (let e of o) {
|
|
1957
|
+
let t = await y(e);
|
|
1958
|
+
if (t) for (let r of J(t.screens)) {
|
|
1959
|
+
let { page: t, dispose: o } = await l(r.src ?? "/");
|
|
725
1960
|
try {
|
|
726
|
-
let
|
|
1961
|
+
let o = G(await t.locator("body").ariaSnapshot({ mode: "ai" })), l = a.checkDescriptions ? await xn(r, e, i) : void 0;
|
|
1962
|
+
r.overlays.length > 0 && r.annotations === void 0 && Mt({
|
|
1963
|
+
mdxPath: e,
|
|
1964
|
+
screenId: r.id,
|
|
1965
|
+
overlayCount: r.overlays.length
|
|
1966
|
+
}, i);
|
|
1967
|
+
let u = K({
|
|
727
1968
|
screen: r,
|
|
728
|
-
liveSnapshot:
|
|
1969
|
+
liveSnapshot: o,
|
|
1970
|
+
yamlOverlays: l
|
|
729
1971
|
});
|
|
730
|
-
for (let t of
|
|
731
|
-
file:
|
|
1972
|
+
for (let t of u) s.push({
|
|
1973
|
+
file: g(n, e),
|
|
732
1974
|
finding: t
|
|
733
|
-
}),
|
|
1975
|
+
}), c.add(e);
|
|
734
1976
|
} finally {
|
|
735
|
-
await
|
|
1977
|
+
await o();
|
|
736
1978
|
}
|
|
737
1979
|
}
|
|
738
1980
|
}
|
|
739
1981
|
} finally {
|
|
740
|
-
await
|
|
1982
|
+
await u();
|
|
741
1983
|
}
|
|
742
1984
|
if (a.json) {
|
|
743
|
-
let e =
|
|
1985
|
+
let e = q(s.map((e) => e.finding));
|
|
744
1986
|
r(JSON.stringify({
|
|
745
|
-
findings:
|
|
1987
|
+
findings: s.map(({ file: e, finding: t }) => ({
|
|
746
1988
|
file: e,
|
|
747
1989
|
severity: t.severity,
|
|
748
1990
|
kind: t.kind,
|
|
@@ -754,23 +1996,23 @@ async function Ae(e, t) {
|
|
|
754
1996
|
summary: e
|
|
755
1997
|
}));
|
|
756
1998
|
} else {
|
|
757
|
-
for (let { file: e, finding: t } of
|
|
758
|
-
let e =
|
|
1999
|
+
for (let { file: e, finding: t } of s) r(`${Tn(t.severity)} ${e} [${t.screenId}] ${t.kind}: ${t.message}`);
|
|
2000
|
+
let e = q(s.map((e) => e.finding));
|
|
759
2001
|
r(`annot docs lint: ${e.errors} error(s), ${e.warnings} warning(s), ${e.infos} info(s).`);
|
|
760
2002
|
}
|
|
761
|
-
let
|
|
762
|
-
if (a.fix &&
|
|
763
|
-
let { newPage: e, close: n } = await
|
|
2003
|
+
let d = 0;
|
|
2004
|
+
if (a.fix && c.size > 0) {
|
|
2005
|
+
let { newPage: e, close: n } = await X(a.url, t);
|
|
764
2006
|
try {
|
|
765
|
-
for (let t of
|
|
766
|
-
let n = await
|
|
767
|
-
if (n) for (let r of
|
|
2007
|
+
for (let t of c) {
|
|
2008
|
+
let n = await y(t);
|
|
2009
|
+
if (n) for (let r of J(n.screens)) {
|
|
768
2010
|
let { page: n, dispose: i } = await e(r.src ?? "/");
|
|
769
2011
|
try {
|
|
770
|
-
await
|
|
2012
|
+
await D(n, {
|
|
771
2013
|
id: r.id,
|
|
772
2014
|
mdxPath: t
|
|
773
|
-
}),
|
|
2015
|
+
}), d++;
|
|
774
2016
|
} finally {
|
|
775
2017
|
await i();
|
|
776
2018
|
}
|
|
@@ -779,15 +2021,25 @@ async function Ae(e, t) {
|
|
|
779
2021
|
} finally {
|
|
780
2022
|
await n();
|
|
781
2023
|
}
|
|
782
|
-
a.json || r(`annot docs lint --fix: refreshed snapshot/attributes for ${
|
|
2024
|
+
a.json || r(`annot docs lint --fix: refreshed snapshot/attributes for ${d} screen(s).`);
|
|
783
2025
|
}
|
|
784
|
-
let
|
|
785
|
-
return a.ci ? +(
|
|
2026
|
+
let f = q(s.map((e) => e.finding));
|
|
2027
|
+
return a.ci ? +(f.errors + f.warnings > 0) : +(f.errors > 0);
|
|
786
2028
|
}
|
|
787
|
-
async function
|
|
2029
|
+
async function xn(e, t, n) {
|
|
2030
|
+
if (!e.annotations) return;
|
|
2031
|
+
let r = h(e.annotations) ? e.annotations : _(m(t), e.annotations);
|
|
2032
|
+
try {
|
|
2033
|
+
return ft(await i(r, "utf8")).overlays;
|
|
2034
|
+
} catch (e) {
|
|
2035
|
+
n(`annot docs lint --check-descriptions: failed to load ${r} (${e.message}). Skipping description cross-refs for this screen.`);
|
|
2036
|
+
return;
|
|
2037
|
+
}
|
|
2038
|
+
}
|
|
2039
|
+
async function X(e, t) {
|
|
788
2040
|
if (t.newPage) return {
|
|
789
2041
|
async newPage(n) {
|
|
790
|
-
let { page: r, close: i } = await t.newPage(
|
|
2042
|
+
let { page: r, close: i } = await t.newPage(wn(e, n));
|
|
791
2043
|
return {
|
|
792
2044
|
page: r,
|
|
793
2045
|
dispose: i
|
|
@@ -799,7 +2051,7 @@ async function Y(e, t) {
|
|
|
799
2051
|
return {
|
|
800
2052
|
async newPage(t) {
|
|
801
2053
|
let n = await r.newContext(), i = await n.newPage();
|
|
802
|
-
return await i.goto(
|
|
2054
|
+
return await i.goto(wn(e, t)), {
|
|
803
2055
|
page: i,
|
|
804
2056
|
dispose: async () => {
|
|
805
2057
|
await n.close();
|
|
@@ -811,33 +2063,61 @@ async function Y(e, t) {
|
|
|
811
2063
|
}
|
|
812
2064
|
};
|
|
813
2065
|
}
|
|
814
|
-
function
|
|
2066
|
+
async function Sn(e, t) {
|
|
2067
|
+
let { cwd: n, stdout: r, stderr: i } = t, a = Z(e), o = await $(await Q(_(n, a.root ?? "docs")));
|
|
2068
|
+
if (o.length === 0) return r(`annot docs migrate-to-element-tree: no MDX files with \`annot:\` frontmatter under ${a.root ?? "docs"}.`), 0;
|
|
2069
|
+
r(`annot docs migrate-to-element-tree: ${o.length} MDX file(s)${a.dryRun ? " (dry run)" : ""}`);
|
|
2070
|
+
let s = 0, c = 0, l = 0;
|
|
2071
|
+
for (let e of o) try {
|
|
2072
|
+
let t = await sn(e, { dryRun: a.dryRun });
|
|
2073
|
+
for (let i of t.screens) i.xmpWritten ? (s++, r(` xmp ${g(n, e)} (screen=${i.id})`)) : i.skipReason && (l++, r(` skip ${g(n, e)} (screen=${i.id}, ${i.skipReason})`));
|
|
2074
|
+
t.mdxRewritten && (c++, r(` rewrote ${g(n, e)} (legacy blocks stripped)`));
|
|
2075
|
+
} catch (t) {
|
|
2076
|
+
return i(`annot docs migrate-to-element-tree: ${g(n, e)}: ${t.message}`), 1;
|
|
2077
|
+
}
|
|
2078
|
+
return r(`annot docs migrate-to-element-tree: ${s} XMP write(s), ${c} MDX rewrite(s), ${l} skip(s).`), 0;
|
|
2079
|
+
}
|
|
2080
|
+
async function Cn(e, t) {
|
|
2081
|
+
let { cwd: n, stdout: r, stderr: i } = t, a = Z(e), o = await $(await Q(_(n, a.root ?? "docs")));
|
|
2082
|
+
if (o.length === 0) return r(`annot docs migrate-overlays-to-annotations: no MDX files with \`annot:\` frontmatter under ${a.root ?? "docs"}.`), 0;
|
|
2083
|
+
r(`annot docs migrate-overlays-to-annotations: ${o.length} MDX file(s)${a.dryRun ? " (dry run)" : ""}`);
|
|
2084
|
+
let s = 0, c = 0, l = 0;
|
|
2085
|
+
for (let e of o) try {
|
|
2086
|
+
let t = await Qt(e, { dryRun: a.dryRun });
|
|
2087
|
+
for (let i of t.screens) i.yamlPath && !i.skipReason ? (s++, r(` yaml ${g(n, e)} (screen=${i.id}, overlays=${i.overlayCount}) → ${g(n, i.yamlPath)}`)) : i.skipReason && (l++, r(` skip ${g(n, e)} (screen=${i.id}, ${i.skipReason})`));
|
|
2088
|
+
t.mdxRewritten && (c++, r(` rewrote ${g(n, e)} (Overlay → AnnotCallout)`));
|
|
2089
|
+
} catch (t) {
|
|
2090
|
+
return i(`annot docs migrate-overlays-to-annotations: ${g(n, e)}: ${t.message}`), 1;
|
|
2091
|
+
}
|
|
2092
|
+
return r(`annot docs migrate-overlays-to-annotations: ${s} yaml write(s), ${c} MDX rewrite(s), ${l} skip(s).`), 0;
|
|
2093
|
+
}
|
|
2094
|
+
function wn(e, t) {
|
|
815
2095
|
return /^https?:\/\//.test(t) ? t : t.startsWith("/") ? e.replace(/\/$/, "") + t : e;
|
|
816
2096
|
}
|
|
817
2097
|
function Z(e) {
|
|
818
2098
|
let t = {};
|
|
819
2099
|
for (let n = 0; n < e.length; n++) {
|
|
820
2100
|
let r = e[n];
|
|
821
|
-
r === "--url" || r === "-u" ? t.url = e[++n] : r === "--root" || r === "-r" ? t.root = e[++n] : r === "--json" ? t.json = !0 : r === "--ci" ? t.ci = !0 : r === "--fix" && (t.
|
|
2101
|
+
r === "--url" || r === "-u" ? t.url = e[++n] : r === "--root" || r === "-r" ? t.root = e[++n] : r === "--json" ? t.json = !0 : r === "--ci" ? t.ci = !0 : r === "--fix" ? t.fix = !0 : r === "--dry-run" ? t.dryRun = !0 : r === "--check-descriptions" && (t.checkDescriptions = !0);
|
|
822
2102
|
}
|
|
823
2103
|
return t;
|
|
824
2104
|
}
|
|
825
2105
|
async function Q(e) {
|
|
826
|
-
let t = [],
|
|
827
|
-
for (;
|
|
828
|
-
let e =
|
|
2106
|
+
let t = [], n = [e];
|
|
2107
|
+
for (; n.length > 0;) {
|
|
2108
|
+
let e = n.pop(), r;
|
|
829
2109
|
try {
|
|
830
|
-
|
|
2110
|
+
r = await a(e, { withFileTypes: !0 });
|
|
831
2111
|
} catch (e) {
|
|
832
2112
|
if (e.code === "ENOENT") continue;
|
|
833
2113
|
throw e;
|
|
834
2114
|
}
|
|
835
|
-
for (let
|
|
836
|
-
let
|
|
837
|
-
if (
|
|
838
|
-
if (
|
|
839
|
-
|
|
840
|
-
} else
|
|
2115
|
+
for (let i of r) {
|
|
2116
|
+
let r = re(e, i.name);
|
|
2117
|
+
if (i.isDirectory()) {
|
|
2118
|
+
if (i.name === "node_modules" || i.name.startsWith(".")) continue;
|
|
2119
|
+
n.push(r);
|
|
2120
|
+
} else i.isFile() && i.name.endsWith(".mdx") && t.push(r);
|
|
841
2121
|
}
|
|
842
2122
|
}
|
|
843
2123
|
return t.sort();
|
|
@@ -845,11 +2125,11 @@ async function Q(e) {
|
|
|
845
2125
|
async function $(e) {
|
|
846
2126
|
let t = [];
|
|
847
2127
|
for (let n of e) try {
|
|
848
|
-
await
|
|
2128
|
+
await y(n) && t.push(n);
|
|
849
2129
|
} catch {}
|
|
850
2130
|
return t;
|
|
851
2131
|
}
|
|
852
|
-
function
|
|
2132
|
+
function Tn(e) {
|
|
853
2133
|
switch (e) {
|
|
854
2134
|
case "error": return "ERROR ";
|
|
855
2135
|
case "warning": return "WARN ";
|
|
@@ -857,4 +2137,4 @@ function je(e) {
|
|
|
857
2137
|
}
|
|
858
2138
|
}
|
|
859
2139
|
//#endregion
|
|
860
|
-
export {
|
|
2140
|
+
export { dt as ANNOTATIONS_YAML_VERSION, P as ANNOTATION_KINDS, F as AnnotationsYamlError, E as DEFAULT_ATTR_WHITELIST, Pt as _resetLegacyOverlayDedupForTests, pe as annotDocsConfigSchema, ue as annotFrontmatterSchema, $t as buildAnnotationsFile, ze as buildBadgeAnnotations, Be as buildBadgeAnnotationsFromYaml, We as buildRasterRedactRegionsFromYaml, Ue as buildShapeAnnotationsFromYaml, Le as captureScreen, O as collectAttributesYaml, Zt as collectMatchKeysFromAnnotation, me as defineConfig, K as detectDrift, Wt as detectDriftFromElementTree, Ht as detectDriftFromYaml, Re as elementTreeToBoxedEntries, Ut as elementTreeToSnapshotEntries, st as emptyAnnotationsSvg, $ as filterAnnotMdxFiles, Nt as formatLegacyOverlayWarning, Xt as isLintableScreen, he as isScreenRole, J as lintableScreens, pn as main, Qt as migrateOverlaysToAnnotationsFile, ft as parseAnnotationsYaml, xe as parseMdx, y as parseMdxFile, G as parseSnapshot, k as parseSnapshotBoxes, Ft as resolveMatch, Ve as resolveMdxAnnotations, It as resolveOverlays, pt as serializeAnnotationsYaml, q as summariseDrift, He as svgFromBadges, ot as svgFromBboxAnnotations, D as syncProductDocs, Ie as test, w as updateCommentBlocks, Q as walkMdx, Mt as warnLegacyOverlay };
|