@ingcreators/annot-product-docs 0.3.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -1,84 +1,93 @@
1
- import { annotSourceResolvers as e, test as t } from "@ingcreators/annot-playwright";
2
- import { mkdir as n, readFile as r, readdir as i, writeFile as a } from "node:fs/promises";
3
- import o from "js-yaml";
4
- import s from "remark-frontmatter";
5
- import c from "remark-mdx";
6
- import l from "remark-parse";
7
- import { unified as u } from "unified";
8
- import { visit as d } from "unist-util-visit";
9
- import { z as f } from "zod";
10
- import { dirname as p, isAbsolute as ee, join as te, relative as m, resolve as h } from "node:path";
11
- import { bboxAnnotationsToSvg as g } from "@ingcreators/annot-annotator";
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";
4
+ import u from "remark-frontmatter";
5
+ import d from "remark-mdx";
6
+ import f from "remark-parse";
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";
12
13
  //#region src/config.ts
13
- var ne = f.enum([
14
+ var se = p.enum([
14
15
  "cover",
15
16
  "history",
16
17
  "list",
17
18
  "screen",
18
19
  "reference"
19
- ]), re = f.object({
20
- book: f.string().optional(),
21
- sheet: f.string().optional(),
22
- sheets: f.record(f.string(), f.string()).optional(),
23
- role: ne.optional(),
24
- order: f.number().optional()
25
- }).strict().refine((e) => !(e.sheet && e.sheets), "Specify either `xlsx.sheet` (single sheet) or `xlsx.sheets` (multi-sheet), not both."), ie = f.record(f.string(), f.unknown()), _ = f.object({
26
- id: f.string().min(1, "`annot.id` is required."),
27
- title: f.string().optional(),
28
- purpose: f.string().optional(),
29
- meta: ie.optional(),
30
- xlsx: re.optional()
31
- }).strict(), ae = f.object({
32
- template: f.string().optional(),
33
- templateSheets: f.object({
34
- cover: f.string().optional(),
35
- history: f.string().optional(),
36
- list: f.string().optional(),
37
- screen: f.string().optional(),
38
- reference: f.string().optional()
39
- }).strict().optional()
40
- }).strict(), v = f.object({
41
- meta: f.record(f.string(), f.unknown()).optional(),
42
- xlsx: f.object({
43
- defaultBook: f.string().optional(),
44
- books: f.record(f.string(), ae).optional()
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(),
30
+ meta: le.optional(),
31
+ xlsx: ce.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()
45
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()
46
55
  }).strict();
47
- function oe(e) {
48
- let t = v.safeParse(e);
56
+ function me(e) {
57
+ let t = pe.safeParse(e);
49
58
  if (!t.success) {
50
59
  let e = t.error.issues.map((e) => ` - ${e.path.length ? e.path.join(".") + ": " : ""}${e.message}`).join("\n");
51
60
  throw Error(`Invalid \`annot-docs.config.ts\`:\n${e}`);
52
61
  }
53
62
  return t.data;
54
63
  }
55
- function se(e) {
64
+ function he(e) {
56
65
  return (e.xlsx?.role ?? "screen") === "screen";
57
66
  }
58
67
  //#endregion
59
68
  //#region src/mdx.ts
60
- var y = "annot:snapshot", ce = "/annot:snapshot", b = "annot:attributes", le = "/annot:attributes", ue = /^\s*\/\*\s*([^\s*]+)\s*([\s\S]*?)\*\/\s*$/;
61
- async function x(e) {
62
- return S(await r(e, "utf8"), { filePath: e });
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 });
63
72
  }
64
- function S(e, t = {}) {
65
- let n = u().use(l).use(s, ["yaml"]).use(c).parse(e), r = de(n, t.filePath);
73
+ function xe(e, t = {}) {
74
+ let n = ee().use(f).use(u, ["yaml"]).use(d).parse(e), r = Se(n, t.filePath);
66
75
  if (!r) return null;
67
- let i = [], a = [], o = [], f = [], p = {};
68
- return d(n, (t) => {
76
+ let i = [], a = [], o = [], s = [], c = {};
77
+ return te(n, (t) => {
69
78
  switch (t.type) {
70
79
  case "mdxJsxFlowElement":
71
80
  case "mdxJsxTextElement":
72
- pe(t, e, {
81
+ we(t, e, {
73
82
  screens: i,
74
83
  transitions: a,
75
84
  history: o,
76
- screenLists: f
85
+ screenLists: s
77
86
  });
78
87
  return;
79
88
  case "mdxFlowExpression":
80
89
  case "mdxTextExpression":
81
- ye(t, p);
90
+ je(t, c);
82
91
  return;
83
92
  }
84
93
  }), {
@@ -86,118 +95,132 @@ function S(e, t = {}) {
86
95
  screens: i,
87
96
  transitions: a,
88
97
  history: o,
89
- screenLists: f,
90
- commentBlocks: p,
98
+ screenLists: s,
99
+ commentBlocks: c,
91
100
  source: e
92
101
  };
93
102
  }
94
- function de(e, t) {
103
+ function Se(e, t) {
95
104
  let n = e.children.find((e) => e.type === "yaml");
96
105
  if (!n || !n.value) return null;
97
- let r = o.load(n.value);
106
+ let r = s.load(n.value);
98
107
  if (!r || typeof r != "object") return null;
99
108
  let i = r.annot;
100
109
  if (!i || typeof i != "object") return null;
101
- let a = _.safeParse(i);
110
+ let a = ue.safeParse(i);
102
111
  if (!a.success) {
103
112
  let e = t ? ` in ${t}` : "";
104
- throw Error(`Invalid \`annot:\` frontmatter${e}:\n${fe(a.error)}`);
113
+ throw Error(`Invalid \`annot:\` frontmatter${e}:\n${Ce(a.error)}`);
105
114
  }
106
115
  return a.data;
107
116
  }
108
- function fe(e) {
109
- 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");
110
119
  }
111
- function pe(e, t, n) {
120
+ function we(e, t, n) {
112
121
  let r = e;
113
122
  switch (r.name) {
114
123
  case "Screen":
115
- n.screens.push(me(r, t));
124
+ n.screens.push(Te(r, t));
116
125
  return;
117
126
  case "Transition":
118
- n.transitions.push(ge(r, t));
127
+ n.transitions.push(Oe(r, t));
119
128
  return;
120
129
  case "HistoryEntry":
121
- n.history.push(_e(r, t));
130
+ n.history.push(ke(r, t));
122
131
  return;
123
132
  case "ScreenList":
124
- n.screenLists.push(ve(r));
133
+ n.screenLists.push(Ae(r));
125
134
  return;
126
135
  }
127
136
  }
128
- function me(e, t) {
129
- let n = C(e), r = [], i = (n) => {
130
- let a = n;
131
- if (a.name === "Overlay") {
132
- r.push(he(a, t));
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));
133
146
  return;
134
147
  }
135
- if (!(a.name === "Screen" && a !== e)) for (let e of a.children ?? []) i(e);
148
+ if (!(o.name === "Screen" && o !== e)) for (let e of o.children ?? []) a(e);
136
149
  };
137
- for (let t of e.children ?? []) i(t);
138
- let a = w(n.id);
139
- if (!a) throw Error("<Screen> requires an `id` prop.");
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
158
+ };
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.");
140
164
  return {
141
- id: a,
142
- src: w(n.src),
143
- overlays: r
165
+ for: n,
166
+ body: C(e, t)
144
167
  };
145
168
  }
146
- function he(e, t) {
147
- let n = C(e), r = n.match;
148
- if (!T(r)) throw Error("<Overlay> requires a `match` prop with at least `{ role, name }`.");
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 }`.");
149
172
  return {
150
173
  match: r,
151
- intent: w(n.intent),
152
- number: xe(n.number),
153
- body: E(e, t)
174
+ intent: x(n.intent),
175
+ number: Ne(n.number),
176
+ body: C(e, t)
154
177
  };
155
178
  }
156
- function ge(e, t) {
157
- let n = C(e), r = n.trigger;
158
- if (!T(r)) throw Error("<Transition> requires a `trigger` prop with at least `{ role, name }`.");
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 }`.");
159
182
  return {
160
183
  trigger: r,
161
- on: w(n.on),
162
- to: w(n.to),
163
- body: E(e, t)
184
+ on: x(n.on),
185
+ to: x(n.to),
186
+ body: C(e, t)
164
187
  };
165
188
  }
166
- function _e(e, t) {
167
- let n = C(e), r = w(n.version) ?? "", i = w(n.date) ?? "", a = w(n.author) ?? "";
189
+ function ke(e, t) {
190
+ let n = b(e), r = x(n.version) ?? "", i = x(n.date) ?? "", a = x(n.author) ?? "";
168
191
  if (!r || !i) throw Error("<HistoryEntry> requires `version` and `date` props.");
169
192
  return {
170
193
  version: r,
171
194
  date: i,
172
195
  author: a,
173
- body: E(e, t)
196
+ body: C(e, t)
174
197
  };
175
198
  }
176
- function ve(e) {
177
- let t = C(e);
199
+ function Ae(e) {
200
+ let t = b(e);
178
201
  return {
179
- book: w(t.book),
180
- sort: w(t.sort)
202
+ book: x(t.book),
203
+ sort: x(t.sort)
181
204
  };
182
205
  }
183
- function ye(e, t) {
206
+ function je(e, t) {
184
207
  let n = e.value;
185
208
  if (typeof n != "string") return;
186
- let r = n.match(ue);
209
+ let r = n.match(be);
187
210
  if (!r) return;
188
211
  let i = (r[1] ?? "").trim(), a = (r[2] ?? "").trim();
189
212
  switch (i) {
190
- case y:
213
+ case ge:
191
214
  t.snapshot = a;
192
215
  return;
193
- case b:
216
+ case ve:
194
217
  t.attributes = a;
195
218
  return;
196
- case ce:
197
- case le: return;
219
+ case _e:
220
+ case ye: return;
198
221
  }
199
222
  }
200
- function C(e) {
223
+ function b(e) {
201
224
  let t = {};
202
225
  for (let n of e.attributes ?? []) {
203
226
  let e = n;
@@ -211,11 +234,11 @@ function C(e) {
211
234
  continue;
212
235
  }
213
236
  let r = e.value;
214
- r.type === "mdxJsxAttributeValueExpression" && typeof r.value == "string" && (t[e.name] = be(r.value));
237
+ r.type === "mdxJsxAttributeValueExpression" && typeof r.value == "string" && (t[e.name] = Me(r.value));
215
238
  }
216
239
  return t;
217
240
  }
218
- function be(e) {
241
+ function Me(e) {
219
242
  let t = e.trim();
220
243
  if (t) {
221
244
  if (t === "true") return !0;
@@ -246,18 +269,18 @@ function be(e) {
246
269
  return t;
247
270
  }
248
271
  }
249
- function w(e) {
272
+ function x(e) {
250
273
  return typeof e == "string" ? e : void 0;
251
274
  }
252
- function xe(e) {
275
+ function Ne(e) {
253
276
  return typeof e == "number" ? e : void 0;
254
277
  }
255
- function T(e) {
278
+ function S(e) {
256
279
  if (!e || typeof e != "object") return !1;
257
280
  let t = e;
258
- return !(typeof t.role != "string" || typeof t.name != "string" || t.under !== void 0 && !T(t.under));
281
+ return !(typeof t.role != "string" || typeof t.name != "string" || t.under !== void 0 && !S(t.under));
259
282
  }
260
- function E(e, t) {
283
+ function C(e, t) {
261
284
  let n = e.position;
262
285
  if (!n) return "";
263
286
  let r = t.slice(n.start.offset, n.end.offset);
@@ -265,24 +288,24 @@ function E(e, t) {
265
288
  let i = r.indexOf(">"), a = r.lastIndexOf("</");
266
289
  return i < 0 || a < 0 || a <= i ? "" : r.slice(i + 1, a).trim();
267
290
  }
268
- function D(e, t) {
291
+ function w(e, t) {
269
292
  let n = e;
270
- return t.snapshot !== void 0 && (n = O(n, y, t.snapshot)), t.attributes !== void 0 && (n = O(n, b, t.attributes)), n;
293
+ return t.snapshot !== void 0 && (n = T(n, ge, t.snapshot)), t.attributes !== void 0 && (n = T(n, ve, t.attributes)), n;
271
294
  }
272
- function O(e, t, n) {
273
- let r = new RegExp(String.raw`\{\s*/\*\s*` + Ce(t) + String.raw`\s*[\s\S]*?\*/\s*\}`, "m"), i = Se(t, n);
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);
274
297
  return r.test(e) ? e.replace(r, i) : `${e.trimEnd()}\n\n${i}\n`;
275
298
  }
276
- function Se(e, t) {
299
+ function Pe(e, t) {
277
300
  let n = t.trim();
278
301
  return n ? `{/* ${e}\n${n}\n*/}` : `{/* ${e} */}`;
279
302
  }
280
- function Ce(e) {
303
+ function Fe(e) {
281
304
  return e.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
282
305
  }
283
306
  //#endregion
284
307
  //#region src/fixture.ts
285
- var k = [
308
+ var E = [
286
309
  "type",
287
310
  "required",
288
311
  "placeholder",
@@ -298,34 +321,34 @@ var k = [
298
321
  "aria-required",
299
322
  "aria-disabled",
300
323
  "aria-readonly"
301
- ], we = t.extend({
324
+ ], Ie = n.extend({
302
325
  productDocs: async ({ page: e }, t) => {
303
- await t({ sync: (t) => A(e, t) });
326
+ await t({ sync: (t) => D(e, t) });
304
327
  },
305
328
  screen: async ({ page: e }, t) => {
306
- let n = (t) => A(e, t);
329
+ let n = (t) => D(e, t);
307
330
  await t({
308
331
  sync: n,
309
332
  capture: n
310
333
  });
311
334
  }
312
335
  });
313
- async function A(e, t) {
314
- let n = await x(t.mdxPath);
336
+ async function D(e, t) {
337
+ let n = await y(t.mdxPath);
315
338
  if (!n) throw Error(`syncProductDocs: ${t.mdxPath} has no \`annot:\` frontmatter — refusing to write.`);
316
339
  let r = n.screens.find((e) => e.id === t.id);
317
340
  if (!r) throw Error(`syncProductDocs: ${t.mdxPath} has no <Screen id="${t.id}"> block.`);
318
341
  let i = await (t.rootLocator ?? e.locator("body")).ariaSnapshot({
319
342
  mode: "ai",
320
343
  boxes: !0
321
- }), o = await j(e, r.overlays, t.attributeWhitelist ?? k), s = D(n.source, {
344
+ }), a = await O(e, r.overlays, t.attributeWhitelist ?? E), s = w(n.source, {
322
345
  snapshot: i.trim(),
323
- attributes: o
346
+ attributes: a
324
347
  });
325
- await a(t.mdxPath, s, "utf8");
348
+ await o(t.mdxPath, s, "utf8");
326
349
  }
327
- var Te = A;
328
- async function j(e, t, n) {
350
+ var Le = D;
351
+ async function O(e, t, n) {
329
352
  let r = [];
330
353
  for (let i of t) {
331
354
  let t = e.getByRole(i.match.role, {
@@ -350,7 +373,7 @@ async function j(e, t, n) {
350
373
  }
351
374
  //#endregion
352
375
  //#region src/mdx-annotations.ts
353
- function M(e) {
376
+ function k(e) {
354
377
  let t = [];
355
378
  for (let n of e.split(/\r?\n/)) {
356
379
  if (!n.trim()) continue;
@@ -371,7 +394,18 @@ function M(e) {
371
394
  }
372
395
  return t;
373
396
  }
374
- function N(e, t, n) {
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) {
375
409
  let r = [], i = 1;
376
410
  for (let a of e) {
377
411
  let e = t.find((e) => e.role === a.match.role && e.name === a.match.name);
@@ -389,44 +423,747 @@ function N(e, t, n) {
389
423
  }
390
424
  return r;
391
425
  }
392
- async function P(e) {
393
- let t = e.cwd ?? process.cwd(), n = await x(ee(e.mdxPath) ? e.mdxPath : h(t, e.mdxPath));
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));
394
444
  if (!n) throw Error(`resolveMdxAnnotations: ${e.mdxPath} has no \`annot:\` frontmatter — cannot resolve.`);
395
445
  let r = n.screens.find((t) => t.id === e.screenId);
396
446
  if (!r) throw Error(`resolveMdxAnnotations: ${e.mdxPath} has no <Screen id="${e.screenId}"> block.`);
397
- let i = M(n.commentBlocks.snapshot ?? "");
398
- return N(r.overlays, i, e.dims);
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
+ }
399
491
  }
400
- function Ee(e) {
401
- return `<svg xmlns="http://www.w3.org/2000/svg">${g(e)}</svg>`;
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);
402
613
  }
403
- function De(e) {
404
- return e.length === 0 ? F() : `<svg xmlns="http://www.w3.org/2000/svg">${g(e)}</svg>`;
614
+ function $e(e) {
615
+ return N({
616
+ type: "freehand",
617
+ path: e.path
618
+ }, e);
405
619
  }
406
- function F() {
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() {
407
699
  return "<svg xmlns=\"http://www.w3.org/2000/svg\"></svg>";
408
700
  }
409
701
  //#endregion
410
702
  //#region src/playwright-screenshot-hook.ts
411
- var I = Symbol.for("@ingcreators/annot-product-docs:mdx-resolver"), L = async ({ annot: e, page: t }) => {
703
+ var ct = Symbol.for("@ingcreators/annot-product-docs:mdx-resolver"), lt = async ({ annot: e, page: t }) => {
412
704
  if (!e.mdx) return null;
413
705
  let { id: n, path: r } = e.mdx;
414
706
  return {
415
- prepare: () => A(t, {
707
+ prepare: () => D(t, {
416
708
  id: n,
417
709
  mdxPath: r
418
710
  }),
419
- resolveAnnotations: (e) => P({
711
+ resolveAnnotations: (e) => Ve({
420
712
  mdxPath: r,
421
713
  screenId: n,
422
714
  dims: e
423
715
  })
424
716
  };
425
- }, R = L;
426
- R[I] || (R[I] = !0, e.push(L));
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
+ }
427
1164
  //#endregion
428
1165
  //#region src/resolver.ts
429
- function z(e) {
1166
+ function G(e) {
430
1167
  let t = [], n = e.split(/\r?\n/), r = [];
431
1168
  for (let e of n) {
432
1169
  if (!e.trim()) continue;
@@ -452,16 +1189,16 @@ function z(e) {
452
1189
  }
453
1190
  return t;
454
1191
  }
455
- async function B(e, t, n) {
456
- let r = Ae(t.filter((t) => t.role === e.role && t.name === e.name), e.under);
457
- if (r.length === 0) return je(e, t);
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);
458
1195
  if (r.length > 1) return {
459
1196
  ok: !1,
460
1197
  kind: "ambiguous",
461
1198
  reason: `Multiple elements match role="${e.role}" name="${e.name}". Use \`under\` to disambiguate.`,
462
1199
  candidates: r.map((e) => `[ref=${e.ref}]`)
463
1200
  };
464
- let i = r[0], a = ke(n, e), o = await a.count();
1201
+ let i = r[0], a = Lt(n, e), o = await a.count();
465
1202
  return o === 0 ? {
466
1203
  ok: !1,
467
1204
  kind: "live-mismatch",
@@ -476,15 +1213,15 @@ async function B(e, t, n) {
476
1213
  entry: i
477
1214
  };
478
1215
  }
479
- async function Oe(e, t, n) {
1216
+ async function It(e, t, n) {
480
1217
  let r = [];
481
1218
  for (let i of e) r.push({
482
1219
  overlay: i,
483
- result: await B(i.match, t, n)
1220
+ result: await Ft(i.match, t, n)
484
1221
  });
485
1222
  return r;
486
1223
  }
487
- function ke(e, t) {
1224
+ function Lt(e, t) {
488
1225
  let n = e.getByRole(t.role, {
489
1226
  name: t.name,
490
1227
  exact: !0
@@ -497,10 +1234,10 @@ function ke(e, t) {
497
1234
  exact: !0
498
1235
  })), n;
499
1236
  }
500
- function Ae(e, t) {
1237
+ function Rt(e, t) {
501
1238
  return t ? e.filter((e) => e.ancestors.some((e) => e.role === t.role && e.name === t.name)) : e;
502
1239
  }
503
- function je(e, t) {
1240
+ function zt(e, t) {
504
1241
  let n = t.filter((t) => t.name === e.name);
505
1242
  if (n.length === 1 && n[0].role !== e.role) return {
506
1243
  ok: !1,
@@ -510,7 +1247,7 @@ function je(e, t) {
510
1247
  };
511
1248
  let r = t.filter((t) => t.role === e.role);
512
1249
  if (r.length > 0) {
513
- let t = Me(e.name, r.map((e) => e.name));
1250
+ let t = Bt(e.name, r.map((e) => e.name));
514
1251
  if (t) return {
515
1252
  ok: !1,
516
1253
  kind: "renamed",
@@ -524,16 +1261,16 @@ function je(e, t) {
524
1261
  reason: `No element with role="${e.role}" name="${e.name}".`
525
1262
  };
526
1263
  }
527
- function Me(e, t) {
1264
+ function Bt(e, t) {
528
1265
  if (t.length === 0) return null;
529
- let n = t[0], r = V(e, n);
1266
+ let n = t[0], r = Vt(e, n);
530
1267
  for (let i of t.slice(1)) {
531
- let t = V(e, i);
1268
+ let t = Vt(e, i);
532
1269
  t > r && (n = i, r = t);
533
1270
  }
534
1271
  return r > .3 ? n : null;
535
1272
  }
536
- function V(e, t) {
1273
+ function Vt(e, t) {
537
1274
  if (!e || !t) return 0;
538
1275
  let n = (e) => {
539
1276
  let t = /* @__PURE__ */ new Set();
@@ -547,12 +1284,12 @@ function V(e, t) {
547
1284
  }
548
1285
  //#endregion
549
1286
  //#region src/drift.ts
550
- function H(e) {
551
- let { screen: t, liveSnapshot: n, storedAttributesYaml: r, freshAttributesYaml: i } = e, a = [], o = /* @__PURE__ */ new Set();
552
- for (let e of t.overlays) {
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) {
553
1290
  let r = n.filter((t) => t.role === e.match.role && t.name === e.match.name);
554
1291
  if (r.length > 1) {
555
- a.push({
1292
+ s.push({
556
1293
  severity: "error",
557
1294
  kind: "duplicated",
558
1295
  screenId: t.id,
@@ -565,7 +1302,7 @@ function H(e) {
565
1302
  let i = n.filter((t) => t.name === e.match.name);
566
1303
  if (i.length === 1 && i[0].role !== e.match.role) {
567
1304
  let n = i[0];
568
- o.add(`${n.role}|${n.name}`), a.push({
1305
+ l.add(`${n.role}|${n.name}`), s.push({
569
1306
  severity: "warning",
570
1307
  kind: "role-changed",
571
1308
  screenId: t.id,
@@ -575,11 +1312,11 @@ function H(e) {
575
1312
  });
576
1313
  continue;
577
1314
  }
578
- let s = n.filter((t) => t.role === e.match.role);
579
- if (s.length > 0) {
580
- let n = Ie(e.match.name, s.map((e) => e.name));
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));
581
1318
  if (n) {
582
- o.add(`${e.match.role}|${n}`), a.push({
1319
+ l.add(`${e.match.role}|${n}`), s.push({
583
1320
  severity: "warning",
584
1321
  kind: "renamed",
585
1322
  screenId: t.id,
@@ -590,7 +1327,7 @@ function H(e) {
590
1327
  continue;
591
1328
  }
592
1329
  }
593
- a.push({
1330
+ s.push({
594
1331
  severity: "error",
595
1332
  kind: "removed",
596
1333
  screenId: t.id,
@@ -598,11 +1335,11 @@ function H(e) {
598
1335
  match: e.match
599
1336
  });
600
1337
  }
601
- let s = new Set(t.overlays.map((e) => `${e.match.role}|${e.match.name}`));
1338
+ let u = new Set(c.map((e) => `${e.match.role}|${e.match.name}`));
602
1339
  for (let e of n) {
603
- if (!Fe(e.role)) continue;
1340
+ if (!Kt(e.role)) continue;
604
1341
  let n = `${e.role}|${e.name}`;
605
- s.has(n) || o.has(n) || a.push({
1342
+ u.has(n) || l.has(n) || s.push({
606
1343
  severity: "warning",
607
1344
  kind: "added",
608
1345
  screenId: t.id,
@@ -613,22 +1350,114 @@ function H(e) {
613
1350
  }
614
1351
  });
615
1352
  }
616
- return r !== void 0 && i !== void 0 && G(r) !== G(i) && a.push({
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({
617
1419
  severity: "info",
618
1420
  kind: "attribute-drift",
619
1421
  screenId: t.id,
620
1422
  message: "`annot:attributes` block no longer matches live element attributes. Run `annot docs sync` to update."
621
- }), a;
1423
+ }), s;
622
1424
  }
623
- function Ne(e) {
624
- return H({
1425
+ function Ht(e) {
1426
+ return K({
625
1427
  screen: e.screen,
626
- liveSnapshot: z(e.liveSnapshotYaml),
1428
+ liveSnapshot: G(e.liveSnapshotYaml),
627
1429
  storedAttributesYaml: e.storedAttributesYaml,
628
- freshAttributesYaml: e.freshAttributesYaml
1430
+ freshAttributesYaml: e.freshAttributesYaml,
1431
+ yamlOverlays: e.yamlOverlays,
1432
+ yamlAnnotations: e.yamlAnnotations
629
1433
  });
630
1434
  }
631
- function U(e) {
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) {
632
1461
  let t = 0, n = 0, r = 0;
633
1462
  for (let i of e) i.severity === "error" ? t++ : i.severity === "warning" ? n++ : r++;
634
1463
  return {
@@ -637,7 +1466,7 @@ function U(e) {
637
1466
  infos: r
638
1467
  };
639
1468
  }
640
- var Pe = new Set([
1469
+ var Gt = /* @__PURE__ */ new Set([
641
1470
  "button",
642
1471
  "checkbox",
643
1472
  "combobox",
@@ -655,19 +1484,19 @@ var Pe = new Set([
655
1484
  "textbox",
656
1485
  "treeitem"
657
1486
  ]);
658
- function Fe(e) {
659
- return Pe.has(e);
1487
+ function Kt(e) {
1488
+ return Gt.has(e);
660
1489
  }
661
- function Ie(e, t) {
1490
+ function qt(e, t) {
662
1491
  if (t.length === 0) return null;
663
- let n = t[0], r = W(e, n);
1492
+ let n = t[0], r = Jt(e, n);
664
1493
  for (let i of t.slice(1)) {
665
- let t = W(e, i);
1494
+ let t = Jt(e, i);
666
1495
  t > r && (n = i, r = t);
667
1496
  }
668
1497
  return r > .3 ? n : null;
669
1498
  }
670
- function W(e, t) {
1499
+ function Jt(e, t) {
671
1500
  if (!e || !t) return 0;
672
1501
  let n = (e) => {
673
1502
  let t = /* @__PURE__ */ new Set();
@@ -679,76 +1508,395 @@ function W(e, t) {
679
1508
  for (let e of r) i.has(e) && a++;
680
1509
  return a / Math.max(r.size, i.size);
681
1510
  }
682
- function G(e) {
1511
+ function Yt(e) {
683
1512
  return e.split(/\r?\n/).map((e) => e.trimEnd()).filter((e) => e.length > 0).join("\n");
684
1513
  }
685
- function K(e) {
686
- return e.overlays.length > 0;
1514
+ function Xt(e) {
1515
+ return e.overlays.length > 0 || e.annotations !== void 0 || e.callouts.length > 0;
687
1516
  }
688
- function q(e) {
689
- return e.filter(K);
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);
690
1813
  }
691
1814
  //#endregion
692
1815
  //#region src/cli.ts
693
- async function Le(e, t = {}) {
1816
+ async function pn(e, t = {}) {
694
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;
695
- if (a !== "init" && a !== "sync" && a !== "lint") return r(Re), +!!a;
1818
+ if (a !== "init" && a !== "sync" && a !== "lint" && a !== "migrate-to-element-tree" && a !== "migrate-overlays-to-annotations") return r(mn), +!!a;
696
1819
  try {
697
1820
  switch (a) {
698
- case "init": return await ze(o, {
1821
+ case "init": return await hn(o, {
699
1822
  cwd: i,
700
1823
  stdout: n,
701
1824
  stderr: r
702
1825
  });
703
- case "sync": return await He(o, {
1826
+ case "sync": return await yn(o, {
704
1827
  ...t,
705
1828
  cwd: i,
706
1829
  stdout: n,
707
1830
  stderr: r
708
1831
  });
709
- case "lint": return await Ue(o, {
1832
+ case "lint": return await bn(o, {
710
1833
  ...t,
711
1834
  cwd: i,
712
1835
  stdout: n,
713
1836
  stderr: r
714
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
+ });
715
1848
  }
716
1849
  } catch (e) {
717
1850
  return r(`annot docs ${a}: ${e.message}`), 1;
718
1851
  }
719
1852
  }
720
- var Re = [
1853
+ var mn = [
721
1854
  "annot docs <command> [options]",
722
1855
  "",
723
1856
  "Commands:",
724
1857
  " init Scaffold annot-docs.config.ts + sample files",
725
1858
  " sync --url <baseUrl> Re-capture snapshot + attrs into every annot MDX",
726
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)",
727
1870
  "",
728
1871
  "Options:",
729
1872
  " --url <baseUrl> Base URL Playwright navigates to (sync / lint)",
730
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)",
731
1879
  " --help Show this help"
732
1880
  ].join("\n");
733
- async function ze(e, t) {
734
- let { cwd: r, stdout: i } = t, o = [
1881
+ async function hn(e, t) {
1882
+ let { cwd: n, stdout: i } = t, a = [
735
1883
  {
736
1884
  path: "annot-docs.config.ts",
737
- content: Be
1885
+ content: gn
738
1886
  },
739
1887
  {
740
1888
  path: "tests/docs/example.spec.ts",
741
- content: J
1889
+ content: _n
742
1890
  },
743
1891
  {
744
1892
  path: "docs/books/example/SC-001-login.mdx",
745
- content: Ve
1893
+ content: vn
746
1894
  }
747
1895
  ], s = 0;
748
- for (let e of o) {
749
- let t = h(r, e.path);
1896
+ for (let e of a) {
1897
+ let t = _(n, e.path);
750
1898
  try {
751
- await n(p(t), { recursive: !0 }), await a(t, e.content, { flag: "wx" }), i(` created ${e.path}`), s++;
1899
+ await r(m(t), { recursive: !0 }), await o(t, e.content, { flag: "wx" }), i(` created ${e.path}`), s++;
752
1900
  } catch (t) {
753
1901
  if (t.code === "EEXIST") i(` exists ${e.path} (skipped)`);
754
1902
  else throw t;
@@ -756,30 +1904,30 @@ async function ze(e, t) {
756
1904
  }
757
1905
  return i(s === 0 ? "annot docs init: nothing to do (all targets exist)" : `annot docs init: wrote ${s} file(s)`), 0;
758
1906
  }
759
- var Be = "// 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", J = "// 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", Ve = "---\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";
760
- async function He(e, t) {
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) {
761
1909
  let { cwd: n, stdout: r, stderr: i } = t, a = Z(e);
762
1910
  if (!a.url) return i("annot docs sync: --url <baseUrl> is required."), 1;
763
- let o = await $(await Q(h(n, a.root ?? "docs")));
1911
+ let o = await $(await Q(_(n, a.root ?? "docs")));
764
1912
  if (o.length === 0) return r(`annot docs sync: no MDX files with \`annot:\` frontmatter under ${a.root ?? "docs"}.`), 0;
765
1913
  r(`annot docs sync: ${o.length} MDX file(s) → ${a.url}`);
766
- let { newPage: s, close: c } = await Y(a.url, t);
1914
+ let { newPage: s, close: c } = await X(a.url, t);
767
1915
  try {
768
1916
  for (let e of o) {
769
- let t = await x(e);
1917
+ let t = await y(e);
770
1918
  if (!t) continue;
771
- let i = q(t.screens);
1919
+ let i = J(t.screens);
772
1920
  if (i.length === 0) {
773
- r(` skip ${m(n, e)} (no <Screen> blocks)`);
1921
+ r(` skip ${g(n, e)} (no <Screen> blocks)`);
774
1922
  continue;
775
1923
  }
776
1924
  for (let t of i) {
777
1925
  let { page: i, dispose: a } = await s(t.src ?? "/");
778
1926
  try {
779
- await A(i, {
1927
+ await D(i, {
780
1928
  id: t.id,
781
1929
  mdxPath: e
782
- }), r(` synced ${m(n, e)} (screen=${t.id})`);
1930
+ }), r(` synced ${g(n, e)} (screen=${t.id})`);
783
1931
  } finally {
784
1932
  await a();
785
1933
  }
@@ -790,10 +1938,10 @@ async function He(e, t) {
790
1938
  }
791
1939
  return 0;
792
1940
  }
793
- async function Ue(e, t) {
1941
+ async function bn(e, t) {
794
1942
  let { cwd: n, stdout: r, stderr: i } = t, a = Z(e);
795
1943
  if (!a.url) return i("annot docs lint: --url <baseUrl> is required."), 1;
796
- let o = await $(await Q(h(n, a.root ?? "docs")));
1944
+ let o = await $(await Q(_(n, a.root ?? "docs")));
797
1945
  if (o.length === 0) return a.json ? r(JSON.stringify({
798
1946
  findings: [],
799
1947
  summary: {
@@ -803,23 +1951,30 @@ async function Ue(e, t) {
803
1951
  }
804
1952
  })) : r(`annot docs lint: no MDX files with \`annot:\` frontmatter under ${a.root ?? "docs"}.`), 0;
805
1953
  a.json || r(`annot docs lint: ${o.length} MDX file(s) → ${a.url}`);
806
- let s = [], c = /* @__PURE__ */ new Set(), { newPage: l, close: u } = await Y(a.url, t);
1954
+ let s = [], c = /* @__PURE__ */ new Set(), { newPage: l, close: u } = await X(a.url, t);
807
1955
  try {
808
1956
  for (let e of o) {
809
- let t = await x(e);
810
- if (t) for (let r of q(t.screens)) {
811
- let { page: t, dispose: i } = await l(r.src ?? "/");
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 ?? "/");
812
1960
  try {
813
- let i = H({
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({
814
1968
  screen: r,
815
- liveSnapshot: z(await t.locator("body").ariaSnapshot({ mode: "ai" }))
1969
+ liveSnapshot: o,
1970
+ yamlOverlays: l
816
1971
  });
817
- for (let t of i) s.push({
818
- file: m(n, e),
1972
+ for (let t of u) s.push({
1973
+ file: g(n, e),
819
1974
  finding: t
820
1975
  }), c.add(e);
821
1976
  } finally {
822
- await i();
1977
+ await o();
823
1978
  }
824
1979
  }
825
1980
  }
@@ -827,7 +1982,7 @@ async function Ue(e, t) {
827
1982
  await u();
828
1983
  }
829
1984
  if (a.json) {
830
- let e = U(s.map((e) => e.finding));
1985
+ let e = q(s.map((e) => e.finding));
831
1986
  r(JSON.stringify({
832
1987
  findings: s.map(({ file: e, finding: t }) => ({
833
1988
  file: e,
@@ -841,20 +1996,20 @@ async function Ue(e, t) {
841
1996
  summary: e
842
1997
  }));
843
1998
  } else {
844
- for (let { file: e, finding: t } of s) r(`${We(t.severity)} ${e} [${t.screenId}] ${t.kind}: ${t.message}`);
845
- let e = U(s.map((e) => e.finding));
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));
846
2001
  r(`annot docs lint: ${e.errors} error(s), ${e.warnings} warning(s), ${e.infos} info(s).`);
847
2002
  }
848
2003
  let d = 0;
849
2004
  if (a.fix && c.size > 0) {
850
- let { newPage: e, close: n } = await Y(a.url, t);
2005
+ let { newPage: e, close: n } = await X(a.url, t);
851
2006
  try {
852
2007
  for (let t of c) {
853
- let n = await x(t);
854
- if (n) for (let r of q(n.screens)) {
2008
+ let n = await y(t);
2009
+ if (n) for (let r of J(n.screens)) {
855
2010
  let { page: n, dispose: i } = await e(r.src ?? "/");
856
2011
  try {
857
- await A(n, {
2012
+ await D(n, {
858
2013
  id: r.id,
859
2014
  mdxPath: t
860
2015
  }), d++;
@@ -868,13 +2023,23 @@ async function Ue(e, t) {
868
2023
  }
869
2024
  a.json || r(`annot docs lint --fix: refreshed snapshot/attributes for ${d} screen(s).`);
870
2025
  }
871
- let f = U(s.map((e) => e.finding));
2026
+ let f = q(s.map((e) => e.finding));
872
2027
  return a.ci ? +(f.errors + f.warnings > 0) : +(f.errors > 0);
873
2028
  }
874
- async function Y(e, t) {
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) {
875
2040
  if (t.newPage) return {
876
2041
  async newPage(n) {
877
- let { page: r, close: i } = await t.newPage(X(e, n));
2042
+ let { page: r, close: i } = await t.newPage(wn(e, n));
878
2043
  return {
879
2044
  page: r,
880
2045
  dispose: i
@@ -886,7 +2051,7 @@ async function Y(e, t) {
886
2051
  return {
887
2052
  async newPage(t) {
888
2053
  let n = await r.newContext(), i = await n.newPage();
889
- return await i.goto(X(e, t)), {
2054
+ return await i.goto(wn(e, t)), {
890
2055
  page: i,
891
2056
  dispose: async () => {
892
2057
  await n.close();
@@ -898,14 +2063,42 @@ async function Y(e, t) {
898
2063
  }
899
2064
  };
900
2065
  }
901
- function X(e, t) {
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) {
902
2095
  return /^https?:\/\//.test(t) ? t : t.startsWith("/") ? e.replace(/\/$/, "") + t : e;
903
2096
  }
904
2097
  function Z(e) {
905
2098
  let t = {};
906
2099
  for (let n = 0; n < e.length; n++) {
907
2100
  let r = e[n];
908
- 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);
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);
909
2102
  }
910
2103
  return t;
911
2104
  }
@@ -914,13 +2107,13 @@ async function Q(e) {
914
2107
  for (; n.length > 0;) {
915
2108
  let e = n.pop(), r;
916
2109
  try {
917
- r = await i(e, { withFileTypes: !0 });
2110
+ r = await a(e, { withFileTypes: !0 });
918
2111
  } catch (e) {
919
2112
  if (e.code === "ENOENT") continue;
920
2113
  throw e;
921
2114
  }
922
2115
  for (let i of r) {
923
- let r = te(e, i.name);
2116
+ let r = re(e, i.name);
924
2117
  if (i.isDirectory()) {
925
2118
  if (i.name === "node_modules" || i.name.startsWith(".")) continue;
926
2119
  n.push(r);
@@ -932,11 +2125,11 @@ async function Q(e) {
932
2125
  async function $(e) {
933
2126
  let t = [];
934
2127
  for (let n of e) try {
935
- await x(n) && t.push(n);
2128
+ await y(n) && t.push(n);
936
2129
  } catch {}
937
2130
  return t;
938
2131
  }
939
- function We(e) {
2132
+ function Tn(e) {
940
2133
  switch (e) {
941
2134
  case "error": return "ERROR ";
942
2135
  case "warning": return "WARN ";
@@ -944,4 +2137,4 @@ function We(e) {
944
2137
  }
945
2138
  }
946
2139
  //#endregion
947
- export { k as DEFAULT_ATTR_WHITELIST, v as annotDocsConfigSchema, _ as annotFrontmatterSchema, N as buildBadgeAnnotations, Te as captureScreen, j as collectAttributesYaml, oe as defineConfig, H as detectDrift, Ne as detectDriftFromYaml, F as emptyAnnotationsSvg, $ as filterAnnotMdxFiles, K as isLintableScreen, se as isScreenRole, q as lintableScreens, Le as main, S as parseMdx, x as parseMdxFile, z as parseSnapshot, M as parseSnapshotBoxes, B as resolveMatch, P as resolveMdxAnnotations, Oe as resolveOverlays, U as summariseDrift, Ee as svgFromBadges, De as svgFromBboxAnnotations, A as syncProductDocs, we as test, D as updateCommentBlocks, Q as walkMdx };
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 };