@ingcreators/annot-product-docs-astro 0.2.0 → 0.2.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/CHANGELOG.md +32 -0
- package/dist/index.js +6 -168
- package/dist/playwright/index.js +225 -0
- package/dist/render-BSQOeqPB.js +164 -0
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
# @ingcreators/annot-product-docs-astro
|
|
2
2
|
|
|
3
|
+
## 0.2.1
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 87a8bad: **Fix `./playwright` subpath build.** The published `0.1.0`
|
|
8
|
+
and `0.2.0` tarballs shipped `dist/playwright/*.d.ts` (type
|
|
9
|
+
declarations) but NOT the runtime `dist/playwright/index.js`,
|
|
10
|
+
because `vite.config.ts`'s `lib.entry` was single-entry —
|
|
11
|
+
only the top-level `src/index.ts` got built.
|
|
12
|
+
|
|
13
|
+
Multi-entry library mode now emits both bundles:
|
|
14
|
+
|
|
15
|
+
```
|
|
16
|
+
dist/
|
|
17
|
+
index.js # main entry (re-exports integration + components + render)
|
|
18
|
+
playwright/index.js # `test`, `expect`, `patchScreenshot`, `rebaseAnnotations`
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
Any consumer doing `import { test } from
|
|
22
|
+
"@ingcreators/annot-product-docs-astro/playwright"`
|
|
23
|
+
previously got `Cannot find module ...dist/playwright/index.js`
|
|
24
|
+
at runtime; the `0.2.1` republish makes the subpath actually
|
|
25
|
+
loadable.
|
|
26
|
+
|
|
27
|
+
Also marks `@playwright/test` as external in the Rollup
|
|
28
|
+
config (matches the package.json `peerDependencies` shape;
|
|
29
|
+
prevents accidentally bundling Playwright into the playwright
|
|
30
|
+
adapter).
|
|
31
|
+
|
|
32
|
+
No public-API change — same exports, same call shapes,
|
|
33
|
+
same TypeScript types. Pure packaging fix.
|
|
34
|
+
|
|
3
35
|
## 0.2.0
|
|
4
36
|
|
|
5
37
|
### Minor Changes
|
package/dist/index.js
CHANGED
|
@@ -1,180 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { mkdir as t, readFile as n, writeFile as r } from "node:fs/promises";
|
|
3
|
-
import { dirname as i, isAbsolute as a, join as o, resolve as s } from "node:path";
|
|
4
|
-
import { bboxAnnotationsToSvg as c, createAnnotator as l } from "@ingcreators/annot-annotator";
|
|
5
|
-
import { parseMdxFile as u } from "@ingcreators/annot-product-docs";
|
|
6
|
-
//#region src/cache.ts
|
|
7
|
-
var d = 1;
|
|
8
|
-
function f(t) {
|
|
9
|
-
let n = e("sha256");
|
|
10
|
-
return n.update("v1\n"), n.update(t.mdxSource), n.update("\0"), n.update(t.screenId), t.editable && n.update("\0editable"), n.digest("hex");
|
|
11
|
-
}
|
|
12
|
-
function p(e) {
|
|
13
|
-
return {
|
|
14
|
-
dir: e,
|
|
15
|
-
async get(t) {
|
|
16
|
-
try {
|
|
17
|
-
let r = await n(o(e, `${t}.png`));
|
|
18
|
-
return new Uint8Array(r.buffer, r.byteOffset, r.byteLength);
|
|
19
|
-
} catch (e) {
|
|
20
|
-
if (e.code === "ENOENT") return null;
|
|
21
|
-
throw e;
|
|
22
|
-
}
|
|
23
|
-
},
|
|
24
|
-
async set(n, a) {
|
|
25
|
-
let s = o(e, `${n}.png`);
|
|
26
|
-
await t(i(s), { recursive: !0 }), await r(s, a);
|
|
27
|
-
}
|
|
28
|
-
};
|
|
29
|
-
}
|
|
30
|
-
function m() {
|
|
31
|
-
let e = /* @__PURE__ */ new Map();
|
|
32
|
-
return {
|
|
33
|
-
dir: ":memory:",
|
|
34
|
-
async get(t) {
|
|
35
|
-
return e.get(t) ?? null;
|
|
36
|
-
},
|
|
37
|
-
async set(t, n) {
|
|
38
|
-
e.set(t, n);
|
|
39
|
-
}
|
|
40
|
-
};
|
|
41
|
-
}
|
|
42
|
-
//#endregion
|
|
1
|
+
import { a as e, c as t, i as n, n as r, o as i, r as a, s as o, t as s } from "./render-BSQOeqPB.js";
|
|
43
2
|
//#region src/integration.ts
|
|
44
|
-
var
|
|
45
|
-
function
|
|
3
|
+
var c = "@ingcreators/annot-product-docs-astro";
|
|
4
|
+
function l(e = {}) {
|
|
46
5
|
let t = {
|
|
47
6
|
contentDir: e.contentDir ?? "docs",
|
|
48
7
|
configPath: e.configPath ?? "annot-docs.config.ts",
|
|
49
8
|
verbose: e.verbose ?? !1
|
|
50
9
|
};
|
|
51
10
|
return {
|
|
52
|
-
name:
|
|
11
|
+
name: c,
|
|
53
12
|
hooks: { "astro:config:setup": ({ logger: e }) => {
|
|
54
|
-
t.verbose && e.info(`${
|
|
13
|
+
t.verbose && e.info(`${c} installed — contentDir=${t.contentDir} configPath=${t.configPath}`);
|
|
55
14
|
} }
|
|
56
15
|
};
|
|
57
16
|
}
|
|
58
17
|
//#endregion
|
|
59
|
-
|
|
60
|
-
async function _(e) {
|
|
61
|
-
let t = e.cwd ?? process.cwd(), n = a(e.mdxPath) ? e.mdxPath : s(t, e.mdxPath), r = await u(n);
|
|
62
|
-
if (!r) throw Error(`renderAnnotatedScreen: ${e.mdxPath} has no \`annot:\` frontmatter — cannot render.`);
|
|
63
|
-
let o = r.screens.find((t) => t.id === e.screenId);
|
|
64
|
-
if (!o) throw Error(`renderAnnotatedScreen: ${e.mdxPath} has no <Screen id="${e.screenId}"> block.`);
|
|
65
|
-
let c = v(e.editable), d = f({
|
|
66
|
-
mdxSource: r.source,
|
|
67
|
-
screenId: e.screenId,
|
|
68
|
-
editable: c !== null
|
|
69
|
-
});
|
|
70
|
-
if (e.cache) {
|
|
71
|
-
let t = await e.cache.get(d);
|
|
72
|
-
if (t) return {
|
|
73
|
-
bytes: t,
|
|
74
|
-
fromCache: !0,
|
|
75
|
-
hadBoundingBoxes: !0
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
let p = e.basePngBytes ?? await T(r, o.src, i(n)), m = E(p), h = b(r.commentBlocks.snapshot ?? ""), g = S(o.overlays, h, m), _, x;
|
|
79
|
-
if (g.length === 0) if (x = !1, c !== null) {
|
|
80
|
-
let e = `data:image/png;base64,${Buffer.from(p).toString("base64")}`;
|
|
81
|
-
_ = l({ loadSystemFonts: !0 }).toEditablePng({
|
|
82
|
-
originalDataUrl: e,
|
|
83
|
-
annotationsSvg: y(),
|
|
84
|
-
width: m.width,
|
|
85
|
-
height: m.height,
|
|
86
|
-
tags: c.tags
|
|
87
|
-
});
|
|
88
|
-
} else _ = p;
|
|
89
|
-
else {
|
|
90
|
-
let e = `data:image/png;base64,${Buffer.from(p).toString("base64")}`, t = C(g), n = l({ loadSystemFonts: !0 }), r = {
|
|
91
|
-
originalDataUrl: e,
|
|
92
|
-
annotationsSvg: t,
|
|
93
|
-
width: m.width,
|
|
94
|
-
height: m.height
|
|
95
|
-
};
|
|
96
|
-
_ = c === null ? n.toPng(r) : n.toEditablePng({
|
|
97
|
-
...r,
|
|
98
|
-
tags: c.tags
|
|
99
|
-
}), x = !0;
|
|
100
|
-
}
|
|
101
|
-
return e.cache && await e.cache.set(d, _), {
|
|
102
|
-
bytes: _,
|
|
103
|
-
fromCache: !1,
|
|
104
|
-
hadBoundingBoxes: x
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
|
-
function v(e) {
|
|
108
|
-
return e ? e === !0 ? {} : e : null;
|
|
109
|
-
}
|
|
110
|
-
function y() {
|
|
111
|
-
return "<svg xmlns=\"http://www.w3.org/2000/svg\"></svg>";
|
|
112
|
-
}
|
|
113
|
-
function b(e) {
|
|
114
|
-
let t = [];
|
|
115
|
-
for (let n of e.split(/\r?\n/)) {
|
|
116
|
-
if (!n.trim()) continue;
|
|
117
|
-
let e = n.match(/^\s*-\s+([a-z]+)(?:\s+"([^"]*?)")?/);
|
|
118
|
-
if (!e) continue;
|
|
119
|
-
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+)?)\]/);
|
|
120
|
-
!a || !o || t.push({
|
|
121
|
-
role: r,
|
|
122
|
-
name: i,
|
|
123
|
-
ref: a,
|
|
124
|
-
box: {
|
|
125
|
-
x: Number.parseFloat(o[1]),
|
|
126
|
-
y: Number.parseFloat(o[2]),
|
|
127
|
-
width: Number.parseFloat(o[3]),
|
|
128
|
-
height: Number.parseFloat(o[4])
|
|
129
|
-
}
|
|
130
|
-
});
|
|
131
|
-
}
|
|
132
|
-
return t;
|
|
133
|
-
}
|
|
134
|
-
async function x(e) {
|
|
135
|
-
let t = e.cwd ?? process.cwd(), n = await u(a(e.mdxPath) ? e.mdxPath : s(t, e.mdxPath));
|
|
136
|
-
if (!n) throw Error(`resolveMdxAnnotations: ${e.mdxPath} has no \`annot:\` frontmatter — cannot resolve.`);
|
|
137
|
-
let r = n.screens.find((t) => t.id === e.screenId);
|
|
138
|
-
if (!r) throw Error(`resolveMdxAnnotations: ${e.mdxPath} has no <Screen id="${e.screenId}"> block.`);
|
|
139
|
-
let i = b(n.commentBlocks.snapshot ?? "");
|
|
140
|
-
return S(r.overlays, i, e.dims);
|
|
141
|
-
}
|
|
142
|
-
function S(e, t, n) {
|
|
143
|
-
let r = [], i = 1;
|
|
144
|
-
for (let a of e) {
|
|
145
|
-
let e = t.find((e) => e.role === a.match.role && e.name === a.match.name);
|
|
146
|
-
if (!e) continue;
|
|
147
|
-
let o = a.number ?? i++;
|
|
148
|
-
r.push({
|
|
149
|
-
type: "numberedBadge",
|
|
150
|
-
bbox: e.box,
|
|
151
|
-
number: o,
|
|
152
|
-
placement: "auto",
|
|
153
|
-
imageWidth: n.width,
|
|
154
|
-
imageHeight: n.height,
|
|
155
|
-
intent: a.intent === "action" ? "warning" : a.intent === "required" ? "error" : "info"
|
|
156
|
-
});
|
|
157
|
-
}
|
|
158
|
-
return r;
|
|
159
|
-
}
|
|
160
|
-
function C(e) {
|
|
161
|
-
return `<svg xmlns="http://www.w3.org/2000/svg">${c(e)}</svg>`;
|
|
162
|
-
}
|
|
163
|
-
function w(e) {
|
|
164
|
-
return e.length === 0 ? "<svg xmlns=\"http://www.w3.org/2000/svg\"></svg>" : `<svg xmlns="http://www.w3.org/2000/svg">${c(e)}</svg>`;
|
|
165
|
-
}
|
|
166
|
-
async function T(e, t, r) {
|
|
167
|
-
if (!t) throw Error("renderAnnotatedScreen: <Screen src=...> is required — cannot render without a base image.");
|
|
168
|
-
let i = await n(a(t) ? t : s(r, t));
|
|
169
|
-
return new Uint8Array(i.buffer, i.byteOffset, i.byteLength);
|
|
170
|
-
}
|
|
171
|
-
function E(e) {
|
|
172
|
-
if (e.length < 24) throw Error("renderAnnotatedScreen: base PNG too short to contain IHDR.");
|
|
173
|
-
let t = new DataView(e.buffer, e.byteOffset, e.byteLength);
|
|
174
|
-
return {
|
|
175
|
-
width: t.getUint32(16, !1),
|
|
176
|
-
height: t.getUint32(20, !1)
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
//#endregion
|
|
180
|
-
export { d as RENDER_PIPELINE_VERSION, f as cacheKey, p as createFileCache, m as createMemoryCache, b as parseSnapshotBoxes, g as productDocsIntegration, _ as renderAnnotatedScreen, x as resolveMdxAnnotations, w as svgFromBboxAnnotations };
|
|
18
|
+
export { e as RENDER_PIPELINE_VERSION, i as cacheKey, o as createFileCache, t as createMemoryCache, s as parseSnapshotBoxes, l as productDocsIntegration, r as renderAnnotatedScreen, a as resolveMdxAnnotations, n as svgFromBboxAnnotations };
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
import { i as e, r as t } from "../render-BSQOeqPB.js";
|
|
2
|
+
import { writeFile as n } from "node:fs/promises";
|
|
3
|
+
import { createAnnotator as r } from "@ingcreators/annot-annotator";
|
|
4
|
+
import { captureScreen as i, test as a } from "@ingcreators/annot-product-docs";
|
|
5
|
+
import { expect as o } from "@playwright/test";
|
|
6
|
+
import { writePngWithTagsOnly as s } from "@ingcreators/annot-core/xmp-bytes";
|
|
7
|
+
//#region src/playwright/rebase.ts
|
|
8
|
+
function c(e, t) {
|
|
9
|
+
let n = [], r = [];
|
|
10
|
+
for (let i of e) {
|
|
11
|
+
let e = l(i, t);
|
|
12
|
+
e ? n.push(e) : r.push(i);
|
|
13
|
+
}
|
|
14
|
+
return {
|
|
15
|
+
kept: n,
|
|
16
|
+
dropped: r
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function l(e, t) {
|
|
20
|
+
switch (e.type) {
|
|
21
|
+
case "rect": return u(e, t);
|
|
22
|
+
case "numberedBadge": return d(e, t);
|
|
23
|
+
case "callout": return f(e, t);
|
|
24
|
+
case "circle": return p(e, t);
|
|
25
|
+
case "arrow": return m(e, t);
|
|
26
|
+
case "text": return h(e, t);
|
|
27
|
+
case "raw": return g(e);
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function u(e, t) {
|
|
31
|
+
return y(e.bbox, t) ? {
|
|
32
|
+
...e,
|
|
33
|
+
bbox: _(e.bbox, t)
|
|
34
|
+
} : null;
|
|
35
|
+
}
|
|
36
|
+
function d(e, t) {
|
|
37
|
+
return y(e.bbox, t) ? {
|
|
38
|
+
...e,
|
|
39
|
+
bbox: _(e.bbox, t),
|
|
40
|
+
imageWidth: t.width,
|
|
41
|
+
imageHeight: t.height
|
|
42
|
+
} : null;
|
|
43
|
+
}
|
|
44
|
+
function f(e, t) {
|
|
45
|
+
return !y(e.targetBbox, t) || !b(e.at, t) ? null : {
|
|
46
|
+
...e,
|
|
47
|
+
at: v(e.at, t),
|
|
48
|
+
targetBbox: _(e.targetBbox, t)
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function p(e, t) {
|
|
52
|
+
return y({
|
|
53
|
+
x: e.center.x - e.radius,
|
|
54
|
+
y: e.center.y - e.radius,
|
|
55
|
+
width: e.radius * 2,
|
|
56
|
+
height: e.radius * 2
|
|
57
|
+
}, t) ? {
|
|
58
|
+
...e,
|
|
59
|
+
center: v(e.center, t)
|
|
60
|
+
} : null;
|
|
61
|
+
}
|
|
62
|
+
function m(e, t) {
|
|
63
|
+
return !b(e.from, t) || !b(e.to, t) ? null : {
|
|
64
|
+
...e,
|
|
65
|
+
from: v(e.from, t),
|
|
66
|
+
to: v(e.to, t)
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
function h(e, t) {
|
|
70
|
+
return b(e.at, t) ? {
|
|
71
|
+
...e,
|
|
72
|
+
at: v(e.at, t)
|
|
73
|
+
} : null;
|
|
74
|
+
}
|
|
75
|
+
function g(e) {
|
|
76
|
+
return e;
|
|
77
|
+
}
|
|
78
|
+
function _(e, t) {
|
|
79
|
+
return {
|
|
80
|
+
x: e.x - t.x,
|
|
81
|
+
y: e.y - t.y,
|
|
82
|
+
width: e.width,
|
|
83
|
+
height: e.height
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
function v(e, t) {
|
|
87
|
+
return {
|
|
88
|
+
x: e.x - t.x,
|
|
89
|
+
y: e.y - t.y
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
function y(e, t) {
|
|
93
|
+
return e.x >= t.x && e.y >= t.y && e.x + e.width <= t.x + t.width && e.y + e.height <= t.y + t.height;
|
|
94
|
+
}
|
|
95
|
+
function b(e, t) {
|
|
96
|
+
return e.x >= t.x && e.y >= t.y && e.x <= t.x + t.width && e.y <= t.y + t.height;
|
|
97
|
+
}
|
|
98
|
+
function x(e) {
|
|
99
|
+
switch (e.type) {
|
|
100
|
+
case "rect":
|
|
101
|
+
case "numberedBadge": return `${e.type}@(${e.bbox.x},${e.bbox.y},${e.bbox.width},${e.bbox.height})`;
|
|
102
|
+
case "callout": return `callout@(${e.targetBbox.x},${e.targetBbox.y},${e.targetBbox.width},${e.targetBbox.height})`;
|
|
103
|
+
case "circle": return `circle@(${e.center.x},${e.center.y},r=${e.radius})`;
|
|
104
|
+
case "arrow": return `arrow@(${e.from.x},${e.from.y})→(${e.to.x},${e.to.y})`;
|
|
105
|
+
case "text": return `text@(${e.at.x},${e.at.y})`;
|
|
106
|
+
case "raw": return "raw[<svg fragment>]";
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//#endregion
|
|
110
|
+
//#region src/playwright/fixture.ts
|
|
111
|
+
var S = Symbol.for("@ingcreators/annot:screenshot-patched");
|
|
112
|
+
function C(e) {
|
|
113
|
+
let t = e;
|
|
114
|
+
if (t[S]) return;
|
|
115
|
+
let n = e.screenshot;
|
|
116
|
+
e.screenshot = async function(e = {}) {
|
|
117
|
+
let t = e?.annot;
|
|
118
|
+
return w(t) ? D.call(this, n, e) : n.call(this, e);
|
|
119
|
+
}, t[S] = !0;
|
|
120
|
+
}
|
|
121
|
+
function w(e) {
|
|
122
|
+
return !e || e === !0 ? !1 : !!(e.mdx || e.overlays && e.overlays.length > 0 || e.tags);
|
|
123
|
+
}
|
|
124
|
+
function T(e) {
|
|
125
|
+
return typeof e.boundingBox == "function";
|
|
126
|
+
}
|
|
127
|
+
function E(e) {
|
|
128
|
+
return T(e) ? e.page() : e;
|
|
129
|
+
}
|
|
130
|
+
async function D(e, t) {
|
|
131
|
+
let { annot: r, path: a, ...o } = t, s = o, c = r.editable ?? !0;
|
|
132
|
+
r.mdx && await i(E(this), {
|
|
133
|
+
id: r.mdx.id,
|
|
134
|
+
mdxPath: r.mdx.path
|
|
135
|
+
});
|
|
136
|
+
let l = await O(this, t.clip), u = await A({
|
|
137
|
+
rawBytes: k(await e.call(this, {
|
|
138
|
+
...s,
|
|
139
|
+
path: void 0
|
|
140
|
+
})),
|
|
141
|
+
annot: r,
|
|
142
|
+
editable: c,
|
|
143
|
+
clip: l
|
|
144
|
+
});
|
|
145
|
+
return a && await n(a, u), Buffer.from(u);
|
|
146
|
+
}
|
|
147
|
+
async function O(e, t) {
|
|
148
|
+
if (T(e)) {
|
|
149
|
+
let t = await e.boundingBox();
|
|
150
|
+
if (!t) throw Error("locator.screenshot({ annot }): locator has no bounding box (probably not visible). Re-test with a stable selector / waitFor().");
|
|
151
|
+
return t;
|
|
152
|
+
}
|
|
153
|
+
return t ?? null;
|
|
154
|
+
}
|
|
155
|
+
function k(e) {
|
|
156
|
+
return e instanceof Uint8Array && !(e instanceof Buffer) ? e : new Uint8Array(e.buffer, e.byteOffset, e.byteLength);
|
|
157
|
+
}
|
|
158
|
+
async function A(n) {
|
|
159
|
+
let { rawBytes: i, annot: a, editable: o, clip: l } = n, u = N(i), d = [];
|
|
160
|
+
if (a.mdx) {
|
|
161
|
+
let e = l ? {
|
|
162
|
+
width: l.x + l.width,
|
|
163
|
+
height: l.y + l.height
|
|
164
|
+
} : u, n = await t({
|
|
165
|
+
mdxPath: a.mdx.path,
|
|
166
|
+
screenId: a.mdx.id,
|
|
167
|
+
dims: e
|
|
168
|
+
});
|
|
169
|
+
d.push(...n);
|
|
170
|
+
}
|
|
171
|
+
a.overlays && d.push(...a.overlays);
|
|
172
|
+
let f;
|
|
173
|
+
if (l) {
|
|
174
|
+
let { kept: e, dropped: t } = c(d, l);
|
|
175
|
+
f = e, t.length > 0 && j(t);
|
|
176
|
+
} else f = d;
|
|
177
|
+
let p = !!(a.mdx || a.overlays);
|
|
178
|
+
if (p && !o) {
|
|
179
|
+
let t = e(f), n = `data:image/png;base64,${Buffer.from(i).toString("base64")}`, o = r({ loadSystemFonts: !0 }).toPng({
|
|
180
|
+
originalDataUrl: n,
|
|
181
|
+
annotationsSvg: t,
|
|
182
|
+
width: u.width,
|
|
183
|
+
height: u.height
|
|
184
|
+
});
|
|
185
|
+
return a.tags ? s(o, a.tags) : o;
|
|
186
|
+
}
|
|
187
|
+
if (p) {
|
|
188
|
+
let t = e(f), n = `data:image/png;base64,${Buffer.from(i).toString("base64")}`;
|
|
189
|
+
return r({ loadSystemFonts: !0 }).toEditablePng({
|
|
190
|
+
originalDataUrl: n,
|
|
191
|
+
annotationsSvg: t,
|
|
192
|
+
width: u.width,
|
|
193
|
+
height: u.height,
|
|
194
|
+
tags: a.tags
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
return a.tags ? s(i, a.tags) : i;
|
|
198
|
+
}
|
|
199
|
+
function j(e) {
|
|
200
|
+
let t = e.map(x).join(", "), n = `annot fixture: dropped ${e.length} overlay(s) outside the screenshot clip — ${t}`;
|
|
201
|
+
console.warn(n), M(n, e);
|
|
202
|
+
}
|
|
203
|
+
function M(e, t) {
|
|
204
|
+
try {
|
|
205
|
+
let n = a.info?.();
|
|
206
|
+
if (!n?.annotations) return;
|
|
207
|
+
n.annotations.push({
|
|
208
|
+
type: "warning",
|
|
209
|
+
description: `${e} (${t.length} dropped)`
|
|
210
|
+
});
|
|
211
|
+
} catch {}
|
|
212
|
+
}
|
|
213
|
+
function N(e) {
|
|
214
|
+
if (e.length < 24) throw Error("Playwright annot fixture: raw screenshot too short to contain PNG IHDR.");
|
|
215
|
+
let t = new DataView(e.buffer, e.byteOffset, e.byteLength);
|
|
216
|
+
return {
|
|
217
|
+
width: t.getUint32(16, !1),
|
|
218
|
+
height: t.getUint32(20, !1)
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
var P = a.extend({ page: async ({ page: e }, t) => {
|
|
222
|
+
C(Object.getPrototypeOf(e)), C(Object.getPrototypeOf(e.locator("html"))), await t(e);
|
|
223
|
+
} });
|
|
224
|
+
//#endregion
|
|
225
|
+
export { x as describeAnnotation, o as expect, C as patchScreenshot, c as rebaseAnnotations, P as test };
|
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { createHash as e } from "node:crypto";
|
|
2
|
+
import { mkdir as t, readFile as n, writeFile as r } from "node:fs/promises";
|
|
3
|
+
import { dirname as i, isAbsolute as a, join as o, resolve as s } from "node:path";
|
|
4
|
+
import { bboxAnnotationsToSvg as c, createAnnotator as l } from "@ingcreators/annot-annotator";
|
|
5
|
+
import { parseMdxFile as u } from "@ingcreators/annot-product-docs";
|
|
6
|
+
//#region src/cache.ts
|
|
7
|
+
var d = 1;
|
|
8
|
+
function f(t) {
|
|
9
|
+
let n = e("sha256");
|
|
10
|
+
return n.update("v1\n"), n.update(t.mdxSource), n.update("\0"), n.update(t.screenId), t.editable && n.update("\0editable"), n.digest("hex");
|
|
11
|
+
}
|
|
12
|
+
function p(e) {
|
|
13
|
+
return {
|
|
14
|
+
dir: e,
|
|
15
|
+
async get(t) {
|
|
16
|
+
try {
|
|
17
|
+
let r = await n(o(e, `${t}.png`));
|
|
18
|
+
return new Uint8Array(r.buffer, r.byteOffset, r.byteLength);
|
|
19
|
+
} catch (e) {
|
|
20
|
+
if (e.code === "ENOENT") return null;
|
|
21
|
+
throw e;
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
async set(n, a) {
|
|
25
|
+
let s = o(e, `${n}.png`);
|
|
26
|
+
await t(i(s), { recursive: !0 }), await r(s, a);
|
|
27
|
+
}
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
function m() {
|
|
31
|
+
let e = /* @__PURE__ */ new Map();
|
|
32
|
+
return {
|
|
33
|
+
dir: ":memory:",
|
|
34
|
+
async get(t) {
|
|
35
|
+
return e.get(t) ?? null;
|
|
36
|
+
},
|
|
37
|
+
async set(t, n) {
|
|
38
|
+
e.set(t, n);
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
//#endregion
|
|
43
|
+
//#region src/render.ts
|
|
44
|
+
async function h(e) {
|
|
45
|
+
let t = e.cwd ?? process.cwd(), n = a(e.mdxPath) ? e.mdxPath : s(t, e.mdxPath), r = await u(n);
|
|
46
|
+
if (!r) throw Error(`renderAnnotatedScreen: ${e.mdxPath} has no \`annot:\` frontmatter — cannot render.`);
|
|
47
|
+
let o = r.screens.find((t) => t.id === e.screenId);
|
|
48
|
+
if (!o) throw Error(`renderAnnotatedScreen: ${e.mdxPath} has no <Screen id="${e.screenId}"> block.`);
|
|
49
|
+
let c = g(e.editable), d = f({
|
|
50
|
+
mdxSource: r.source,
|
|
51
|
+
screenId: e.screenId,
|
|
52
|
+
editable: c !== null
|
|
53
|
+
});
|
|
54
|
+
if (e.cache) {
|
|
55
|
+
let t = await e.cache.get(d);
|
|
56
|
+
if (t) return {
|
|
57
|
+
bytes: t,
|
|
58
|
+
fromCache: !0,
|
|
59
|
+
hadBoundingBoxes: !0
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
let p = e.basePngBytes ?? await C(r, o.src, i(n)), m = w(p), h = v(r.commentBlocks.snapshot ?? ""), y = b(o.overlays, h, m), S, T;
|
|
63
|
+
if (y.length === 0) if (T = !1, c !== null) {
|
|
64
|
+
let e = `data:image/png;base64,${Buffer.from(p).toString("base64")}`;
|
|
65
|
+
S = l({ loadSystemFonts: !0 }).toEditablePng({
|
|
66
|
+
originalDataUrl: e,
|
|
67
|
+
annotationsSvg: _(),
|
|
68
|
+
width: m.width,
|
|
69
|
+
height: m.height,
|
|
70
|
+
tags: c.tags
|
|
71
|
+
});
|
|
72
|
+
} else S = p;
|
|
73
|
+
else {
|
|
74
|
+
let e = `data:image/png;base64,${Buffer.from(p).toString("base64")}`, t = x(y), n = l({ loadSystemFonts: !0 }), r = {
|
|
75
|
+
originalDataUrl: e,
|
|
76
|
+
annotationsSvg: t,
|
|
77
|
+
width: m.width,
|
|
78
|
+
height: m.height
|
|
79
|
+
};
|
|
80
|
+
S = c === null ? n.toPng(r) : n.toEditablePng({
|
|
81
|
+
...r,
|
|
82
|
+
tags: c.tags
|
|
83
|
+
}), T = !0;
|
|
84
|
+
}
|
|
85
|
+
return e.cache && await e.cache.set(d, S), {
|
|
86
|
+
bytes: S,
|
|
87
|
+
fromCache: !1,
|
|
88
|
+
hadBoundingBoxes: T
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
function g(e) {
|
|
92
|
+
return e ? e === !0 ? {} : e : null;
|
|
93
|
+
}
|
|
94
|
+
function _() {
|
|
95
|
+
return "<svg xmlns=\"http://www.w3.org/2000/svg\"></svg>";
|
|
96
|
+
}
|
|
97
|
+
function v(e) {
|
|
98
|
+
let t = [];
|
|
99
|
+
for (let n of e.split(/\r?\n/)) {
|
|
100
|
+
if (!n.trim()) continue;
|
|
101
|
+
let e = n.match(/^\s*-\s+([a-z]+)(?:\s+"([^"]*?)")?/);
|
|
102
|
+
if (!e) continue;
|
|
103
|
+
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+)?)\]/);
|
|
104
|
+
!a || !o || t.push({
|
|
105
|
+
role: r,
|
|
106
|
+
name: i,
|
|
107
|
+
ref: a,
|
|
108
|
+
box: {
|
|
109
|
+
x: Number.parseFloat(o[1]),
|
|
110
|
+
y: Number.parseFloat(o[2]),
|
|
111
|
+
width: Number.parseFloat(o[3]),
|
|
112
|
+
height: Number.parseFloat(o[4])
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
return t;
|
|
117
|
+
}
|
|
118
|
+
async function y(e) {
|
|
119
|
+
let t = e.cwd ?? process.cwd(), n = await u(a(e.mdxPath) ? e.mdxPath : s(t, e.mdxPath));
|
|
120
|
+
if (!n) throw Error(`resolveMdxAnnotations: ${e.mdxPath} has no \`annot:\` frontmatter — cannot resolve.`);
|
|
121
|
+
let r = n.screens.find((t) => t.id === e.screenId);
|
|
122
|
+
if (!r) throw Error(`resolveMdxAnnotations: ${e.mdxPath} has no <Screen id="${e.screenId}"> block.`);
|
|
123
|
+
let i = v(n.commentBlocks.snapshot ?? "");
|
|
124
|
+
return b(r.overlays, i, e.dims);
|
|
125
|
+
}
|
|
126
|
+
function b(e, t, n) {
|
|
127
|
+
let r = [], i = 1;
|
|
128
|
+
for (let a of e) {
|
|
129
|
+
let e = t.find((e) => e.role === a.match.role && e.name === a.match.name);
|
|
130
|
+
if (!e) continue;
|
|
131
|
+
let o = a.number ?? i++;
|
|
132
|
+
r.push({
|
|
133
|
+
type: "numberedBadge",
|
|
134
|
+
bbox: e.box,
|
|
135
|
+
number: o,
|
|
136
|
+
placement: "auto",
|
|
137
|
+
imageWidth: n.width,
|
|
138
|
+
imageHeight: n.height,
|
|
139
|
+
intent: a.intent === "action" ? "warning" : a.intent === "required" ? "error" : "info"
|
|
140
|
+
});
|
|
141
|
+
}
|
|
142
|
+
return r;
|
|
143
|
+
}
|
|
144
|
+
function x(e) {
|
|
145
|
+
return `<svg xmlns="http://www.w3.org/2000/svg">${c(e)}</svg>`;
|
|
146
|
+
}
|
|
147
|
+
function S(e) {
|
|
148
|
+
return e.length === 0 ? "<svg xmlns=\"http://www.w3.org/2000/svg\"></svg>" : `<svg xmlns="http://www.w3.org/2000/svg">${c(e)}</svg>`;
|
|
149
|
+
}
|
|
150
|
+
async function C(e, t, r) {
|
|
151
|
+
if (!t) throw Error("renderAnnotatedScreen: <Screen src=...> is required — cannot render without a base image.");
|
|
152
|
+
let i = await n(a(t) ? t : s(r, t));
|
|
153
|
+
return new Uint8Array(i.buffer, i.byteOffset, i.byteLength);
|
|
154
|
+
}
|
|
155
|
+
function w(e) {
|
|
156
|
+
if (e.length < 24) throw Error("renderAnnotatedScreen: base PNG too short to contain IHDR.");
|
|
157
|
+
let t = new DataView(e.buffer, e.byteOffset, e.byteLength);
|
|
158
|
+
return {
|
|
159
|
+
width: t.getUint32(16, !1),
|
|
160
|
+
height: t.getUint32(20, !1)
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
//#endregion
|
|
164
|
+
export { d as a, m as c, S as i, h as n, f as o, y as r, p as s, v as t };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ingcreators/annot-product-docs-astro",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.1",
|
|
4
4
|
"description": "Astro integration for `@ingcreators/annot-product-docs`. Wires the MDX components (`<Screen>` / `<Overlay>` / `<Transition>` / `<HistoryEntry>` / `<ScreenList>` / `<TransitionGraph>`) into an Astro site and supplies the Image Service that renders annotated PNGs from `<Screen>` blocks at build time. Phase 2 of docs/plans/living-product-docs.md.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"author": "ingcreators",
|
|
@@ -61,9 +61,9 @@
|
|
|
61
61
|
"vite-plugin-dts": "^5.0.1"
|
|
62
62
|
},
|
|
63
63
|
"dependencies": {
|
|
64
|
-
"@ingcreators/annot-
|
|
64
|
+
"@ingcreators/annot-core": "0.2.0",
|
|
65
65
|
"@ingcreators/annot-annotator": "0.5.0",
|
|
66
|
-
"@ingcreators/annot-
|
|
66
|
+
"@ingcreators/annot-product-docs": "0.2.0"
|
|
67
67
|
},
|
|
68
68
|
"peerDependencies": {
|
|
69
69
|
"@playwright/test": "^1.42.0",
|