@quillmark/quiver 0.7.0 → 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/PROGRAM.md +1 -1
- package/README.md +46 -5
- package/dist/engine-types.d.ts +3 -1
- package/dist/engine-types.js +1 -1
- package/dist/preview.d.ts +87 -0
- package/dist/preview.js +203 -0
- package/dist/testing.d.ts +6 -4
- package/dist/testing.js +12 -8
- package/package.json +13 -8
package/PROGRAM.md
CHANGED
|
@@ -465,7 +465,7 @@ const result = quill.render(doc, { format: "pdf" });
|
|
|
465
465
|
test runners wire their own loops against the main API.
|
|
466
466
|
|
|
467
467
|
**Dependencies:**
|
|
468
|
-
- Peer: `@quillmark/wasm@>=0.
|
|
468
|
+
- Peer: `@quillmark/wasm@>=0.71.0` with `Quillmark`, `Document.fromMarkdown`, `engine.quill(tree)`, and `quill.render(doc, opts?)` APIs.
|
|
469
469
|
- Runtime: `fflate ^0.8.2` for zip read/write (Node + browser)
|
|
470
470
|
- Dev-only: `node:crypto` (MD5 hashing in `build()` — never reached at runtime)
|
|
471
471
|
- No test-runner peer dependency; `/testing` uses `node:test` (built-in)
|
package/README.md
CHANGED
|
@@ -44,11 +44,52 @@ my-quiver/
|
|
|
44
44
|
```
|
|
45
45
|
|
|
46
46
|
Recommended CI: use the bundled `@quillmark/quiver/testing` harness — it
|
|
47
|
-
loads with `Quiver.fromDir
|
|
48
|
-
surface on publish, not on the consumer's
|
|
49
|
-
`node:test` (built into Node 18+); no extra
|
|
50
|
-
required. If you prefer vitest/jest/mocha, write a
|
|
51
|
-
the main API instead.
|
|
47
|
+
loads with `Quiver.fromDir`, compiles every quill, and renders each quill's
|
|
48
|
+
blueprint so validation errors surface on publish, not on the consumer's
|
|
49
|
+
build. The harness uses `node:test` (built into Node 18+); no extra
|
|
50
|
+
test-runner dependency required. If you prefer vitest/jest/mocha, write a
|
|
51
|
+
12-line loop against the main API instead.
|
|
52
|
+
|
|
53
|
+
## Manual validation (rendering samples)
|
|
54
|
+
|
|
55
|
+
The CI harness proves every quill _compiles_; it does not produce output a
|
|
56
|
+
human can look at. To eyeball real renders, run the
|
|
57
|
+
`@quillmark/quiver/preview` helper:
|
|
58
|
+
|
|
59
|
+
```ts
|
|
60
|
+
// scripts/preview.ts — run with: node --experimental-strip-types scripts/preview.ts
|
|
61
|
+
import { Quillmark, Document } from "@quillmark/wasm";
|
|
62
|
+
import { renderQuiverSamples } from "@quillmark/quiver/preview";
|
|
63
|
+
|
|
64
|
+
await renderQuiverSamples(import.meta.url, {
|
|
65
|
+
engine: new Quillmark(),
|
|
66
|
+
Document,
|
|
67
|
+
});
|
|
68
|
+
// → writes ./preview/<name>@<version>.<fmt> + index.html
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
It renders every quill's auto-generated blueprint (`quill.blueprint`), writes
|
|
72
|
+
the artifacts to `outDir` (default `preview/`), and emits an `index.html`
|
|
73
|
+
gallery. A `.gitignore` is written into `outDir` so the generated artifacts
|
|
74
|
+
are never accidentally committed. A quill that throws is recorded as failed —
|
|
75
|
+
with every diagnostic, not just the first — without aborting the run, so one
|
|
76
|
+
broken quill never hides the rest.
|
|
77
|
+
|
|
78
|
+
To iterate on a subset, pass `include` / `exclude` (each entry matches a
|
|
79
|
+
quill name or canonical ref):
|
|
80
|
+
|
|
81
|
+
```ts
|
|
82
|
+
await renderQuiverSamples(import.meta.url, {
|
|
83
|
+
engine: new Quillmark(),
|
|
84
|
+
Document,
|
|
85
|
+
exclude: ["broken-quill"], // or: include: ["memo@1.0.0"]
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
> **Linking the source repo?** `@quillmark/quiver/preview` resolves to
|
|
90
|
+
> `./dist/preview.js`, which only exists after `npm install && npm run build`
|
|
91
|
+
> in the `@quillmark/quiver` checkout. If you `npm link` it and see
|
|
92
|
+
> `Cannot find module './dist/preview.js'`, build the linked package first.
|
|
52
93
|
|
|
53
94
|
## Consuming a quiver (Node)
|
|
54
95
|
|
package/dist/engine-types.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Minimal structural types matching @quillmark/wasm >=0.
|
|
2
|
+
* Minimal structural types matching @quillmark/wasm >=0.79.0.
|
|
3
3
|
*
|
|
4
4
|
* Shape:
|
|
5
5
|
* class Quillmark { quill(tree: Map<string, Uint8Array>): Quill }
|
|
@@ -23,4 +23,6 @@ export interface QuillmarkLike {
|
|
|
23
23
|
export interface QuillLike {
|
|
24
24
|
render(doc: unknown, opts?: unknown): unknown;
|
|
25
25
|
open?: (doc: unknown) => unknown;
|
|
26
|
+
/** Auto-generated annotated Markdown blueprint — always present in @quillmark/wasm >=0.79.0. */
|
|
27
|
+
blueprint: string;
|
|
26
28
|
}
|
package/dist/engine-types.js
CHANGED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manual-validation helper for Quiver authors.
|
|
3
|
+
*
|
|
4
|
+
* `runQuiverTests` (`@quillmark/quiver/testing`) proves every quill *compiles*
|
|
5
|
+
* — it never produces a rendered artifact a human can look at. This module
|
|
6
|
+
* closes that gap: it renders each quill's blueprint, writes the artifacts to
|
|
7
|
+
* a directory, and emits an `index.html` gallery so an author can eyeball real
|
|
8
|
+
* output before publishing.
|
|
9
|
+
*
|
|
10
|
+
* Node-only: writes files and loads a source quiver from disk.
|
|
11
|
+
*
|
|
12
|
+
* Usage (place a script next to your Quiver.yaml):
|
|
13
|
+
*
|
|
14
|
+
* import { Quillmark, Document } from "@quillmark/wasm";
|
|
15
|
+
* import { renderQuiverSamples } from "@quillmark/quiver/preview";
|
|
16
|
+
*
|
|
17
|
+
* await renderQuiverSamples(import.meta.url, {
|
|
18
|
+
* engine: new Quillmark(),
|
|
19
|
+
* Document,
|
|
20
|
+
* });
|
|
21
|
+
* // → open ./preview/index.html
|
|
22
|
+
*
|
|
23
|
+
* The sample document is the auto-generated blueprint (`quill.blueprint`) for
|
|
24
|
+
* each quill version. Every quill always has a blueprint, so no quills are
|
|
25
|
+
* skipped for lack of a sample document.
|
|
26
|
+
*
|
|
27
|
+
* A `.gitignore` is written into `outDir` so the generated artifacts are not
|
|
28
|
+
* accidentally committed.
|
|
29
|
+
*/
|
|
30
|
+
import type { QuillmarkLike } from "./engine-types.js";
|
|
31
|
+
/**
|
|
32
|
+
* Structural shape of the `Document` class from `@quillmark/wasm`. Only the
|
|
33
|
+
* `fromMarkdown` factory is used; passing the real class satisfies this.
|
|
34
|
+
*/
|
|
35
|
+
export interface DocumentFactoryLike {
|
|
36
|
+
fromMarkdown(markdown: string): unknown;
|
|
37
|
+
}
|
|
38
|
+
export interface RenderQuiverSamplesOptions {
|
|
39
|
+
/** Quillmark engine instance (`new Quillmark()` from `@quillmark/wasm`). */
|
|
40
|
+
engine: QuillmarkLike;
|
|
41
|
+
/** The `Document` class from `@quillmark/wasm`. */
|
|
42
|
+
Document: DocumentFactoryLike;
|
|
43
|
+
/** Directory to write rendered artifacts into. Default: `preview`. */
|
|
44
|
+
outDir?: string;
|
|
45
|
+
/** Force an output format (`pdf`/`svg`/`png`/`txt`). Default: engine's choice. */
|
|
46
|
+
format?: string;
|
|
47
|
+
/** Suppress the console summary. Default: false. */
|
|
48
|
+
quiet?: boolean;
|
|
49
|
+
/**
|
|
50
|
+
* Render only these quills. Each entry matches a quill name (`"memo"`) or a
|
|
51
|
+
* canonical ref (`"memo@1.0.0"`). Omit to render all quills.
|
|
52
|
+
*/
|
|
53
|
+
include?: string[];
|
|
54
|
+
/**
|
|
55
|
+
* Skip these quills. Each entry matches a quill name (`"memo"`) or a
|
|
56
|
+
* canonical ref (`"memo@1.0.0"`). Applied after `include`.
|
|
57
|
+
*/
|
|
58
|
+
exclude?: string[];
|
|
59
|
+
}
|
|
60
|
+
/** Per-quill outcome returned by `renderQuiverSamples`. */
|
|
61
|
+
export interface RenderedSample {
|
|
62
|
+
/** Canonical ref, e.g. `"memo@1.0.0"`. */
|
|
63
|
+
ref: string;
|
|
64
|
+
/** `rendered` — artifacts written; `failed` — error. */
|
|
65
|
+
status: "rendered" | "failed";
|
|
66
|
+
/** Artifact filenames written under `outDir` (relative). */
|
|
67
|
+
files: string[];
|
|
68
|
+
/** Render warnings, formatted `"severity: message"`. */
|
|
69
|
+
warnings: string[];
|
|
70
|
+
/**
|
|
71
|
+
* Why the quill was skipped or failed. Empty when rendered. A failed render
|
|
72
|
+
* carries every diagnostic from the engine, not just the first.
|
|
73
|
+
*/
|
|
74
|
+
reasons: string[];
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Renders every quill's blueprint and writes the artifacts plus an
|
|
78
|
+
* `index.html` gallery to `outDir`.
|
|
79
|
+
*
|
|
80
|
+
* Does NOT fail fast: a quill that throws is recorded as `failed` and the
|
|
81
|
+
* run continues, so one broken quill never hides the others. Inspect the
|
|
82
|
+
* returned array (or `index.html`) for the full picture.
|
|
83
|
+
*
|
|
84
|
+
* @param metaUrlOrDir `import.meta.url` when called from the quiver root, or
|
|
85
|
+
* an absolute path to the source quiver directory.
|
|
86
|
+
*/
|
|
87
|
+
export declare function renderQuiverSamples(metaUrlOrDir: string, opts: RenderQuiverSamplesOptions): Promise<RenderedSample[]>;
|
package/dist/preview.js
ADDED
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Manual-validation helper for Quiver authors.
|
|
3
|
+
*
|
|
4
|
+
* `runQuiverTests` (`@quillmark/quiver/testing`) proves every quill *compiles*
|
|
5
|
+
* — it never produces a rendered artifact a human can look at. This module
|
|
6
|
+
* closes that gap: it renders each quill's blueprint, writes the artifacts to
|
|
7
|
+
* a directory, and emits an `index.html` gallery so an author can eyeball real
|
|
8
|
+
* output before publishing.
|
|
9
|
+
*
|
|
10
|
+
* Node-only: writes files and loads a source quiver from disk.
|
|
11
|
+
*
|
|
12
|
+
* Usage (place a script next to your Quiver.yaml):
|
|
13
|
+
*
|
|
14
|
+
* import { Quillmark, Document } from "@quillmark/wasm";
|
|
15
|
+
* import { renderQuiverSamples } from "@quillmark/quiver/preview";
|
|
16
|
+
*
|
|
17
|
+
* await renderQuiverSamples(import.meta.url, {
|
|
18
|
+
* engine: new Quillmark(),
|
|
19
|
+
* Document,
|
|
20
|
+
* });
|
|
21
|
+
* // → open ./preview/index.html
|
|
22
|
+
*
|
|
23
|
+
* The sample document is the auto-generated blueprint (`quill.blueprint`) for
|
|
24
|
+
* each quill version. Every quill always has a blueprint, so no quills are
|
|
25
|
+
* skipped for lack of a sample document.
|
|
26
|
+
*
|
|
27
|
+
* A `.gitignore` is written into `outDir` so the generated artifacts are not
|
|
28
|
+
* accidentally committed.
|
|
29
|
+
*/
|
|
30
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
31
|
+
import { join } from "node:path";
|
|
32
|
+
import { Quiver } from "./node.js";
|
|
33
|
+
/** Default directory rendered artifacts are written to. */
|
|
34
|
+
const DEFAULT_OUT_DIR = "preview";
|
|
35
|
+
/**
|
|
36
|
+
* Renders every quill's blueprint and writes the artifacts plus an
|
|
37
|
+
* `index.html` gallery to `outDir`.
|
|
38
|
+
*
|
|
39
|
+
* Does NOT fail fast: a quill that throws is recorded as `failed` and the
|
|
40
|
+
* run continues, so one broken quill never hides the others. Inspect the
|
|
41
|
+
* returned array (or `index.html`) for the full picture.
|
|
42
|
+
*
|
|
43
|
+
* @param metaUrlOrDir `import.meta.url` when called from the quiver root, or
|
|
44
|
+
* an absolute path to the source quiver directory.
|
|
45
|
+
*/
|
|
46
|
+
export async function renderQuiverSamples(metaUrlOrDir, opts) {
|
|
47
|
+
const outDir = opts.outDir ?? DEFAULT_OUT_DIR;
|
|
48
|
+
const quiver = await Quiver.fromDir(metaUrlOrDir);
|
|
49
|
+
await mkdir(outDir, { recursive: true });
|
|
50
|
+
const results = [];
|
|
51
|
+
for (const name of quiver.quillNames()) {
|
|
52
|
+
for (const version of quiver.versionsOf(name)) {
|
|
53
|
+
if (!isSelected(name, `${name}@${version}`, opts))
|
|
54
|
+
continue;
|
|
55
|
+
results.push(await renderOne(quiver, name, version, outDir, opts));
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
await writeFile(join(outDir, ".gitignore"), "*\n");
|
|
59
|
+
await writeFile(join(outDir, "index.html"), renderIndexHtml(quiver.name, results));
|
|
60
|
+
if (!opts.quiet)
|
|
61
|
+
printSummary(quiver.name, outDir, results);
|
|
62
|
+
return results;
|
|
63
|
+
}
|
|
64
|
+
/** Whether a quill passes the `include`/`exclude` filters. */
|
|
65
|
+
function isSelected(name, ref, opts) {
|
|
66
|
+
const matches = (list) => list.includes(name) || list.includes(ref);
|
|
67
|
+
if (opts.include && !matches(opts.include))
|
|
68
|
+
return false;
|
|
69
|
+
if (opts.exclude && matches(opts.exclude))
|
|
70
|
+
return false;
|
|
71
|
+
return true;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Formats a thrown render error into one string per diagnostic. `@quillmark/wasm`
|
|
75
|
+
* attaches a `diagnostics` array to its errors; fall back to the message when
|
|
76
|
+
* an error carries none.
|
|
77
|
+
*/
|
|
78
|
+
function failureReasons(err) {
|
|
79
|
+
const diagnostics = err.diagnostics;
|
|
80
|
+
if (Array.isArray(diagnostics) && diagnostics.length > 0) {
|
|
81
|
+
return diagnostics.map((d) => `${d.severity}: ${d.message}`);
|
|
82
|
+
}
|
|
83
|
+
return [err.message];
|
|
84
|
+
}
|
|
85
|
+
async function renderOne(quiver, name, version, outDir, opts) {
|
|
86
|
+
const ref = `${name}@${version}`;
|
|
87
|
+
let result;
|
|
88
|
+
try {
|
|
89
|
+
const quill = await quiver.getQuill(ref, { engine: opts.engine });
|
|
90
|
+
const markdown = quill.blueprint;
|
|
91
|
+
const doc = opts.Document.fromMarkdown(markdown);
|
|
92
|
+
result = quill.render(doc, opts.format ? { format: opts.format } : undefined);
|
|
93
|
+
}
|
|
94
|
+
catch (err) {
|
|
95
|
+
return {
|
|
96
|
+
ref,
|
|
97
|
+
status: "failed",
|
|
98
|
+
files: [],
|
|
99
|
+
warnings: [],
|
|
100
|
+
reasons: failureReasons(err),
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
const warnings = (result.warnings ?? []).map((w) => `${w.severity}: ${w.message}`);
|
|
104
|
+
const artifacts = result.artifacts ?? [];
|
|
105
|
+
if (artifacts.length === 0) {
|
|
106
|
+
return {
|
|
107
|
+
ref,
|
|
108
|
+
status: "failed",
|
|
109
|
+
files: [],
|
|
110
|
+
warnings,
|
|
111
|
+
reasons: ["render produced no artifacts"],
|
|
112
|
+
};
|
|
113
|
+
}
|
|
114
|
+
const files = [];
|
|
115
|
+
for (let i = 0; i < artifacts.length; i++) {
|
|
116
|
+
const artifact = artifacts[i];
|
|
117
|
+
const suffix = artifacts.length > 1 ? `.${i}` : "";
|
|
118
|
+
const fileName = `${ref}${suffix}.${artifact.format}`;
|
|
119
|
+
await writeFile(join(outDir, fileName), artifact.bytes);
|
|
120
|
+
files.push(fileName);
|
|
121
|
+
}
|
|
122
|
+
return { ref, status: "rendered", files, warnings, reasons: [] };
|
|
123
|
+
}
|
|
124
|
+
function printSummary(quiverName, outDir, results) {
|
|
125
|
+
const count = (s) => results.filter((r) => r.status === s).length;
|
|
126
|
+
console.log(`\nQuiver "${quiverName}" — sample render`);
|
|
127
|
+
for (const r of results) {
|
|
128
|
+
const detail = r.status === "rendered" ? r.files.join(", ") : (r.reasons[0] ?? "");
|
|
129
|
+
console.log(` [${r.status.padEnd(8)}] ${r.ref}${detail ? ` — ${detail}` : ""}`);
|
|
130
|
+
for (const extra of r.reasons.slice(1))
|
|
131
|
+
console.log(` ${extra}`);
|
|
132
|
+
for (const w of r.warnings)
|
|
133
|
+
console.log(` ⚠ ${w}`);
|
|
134
|
+
}
|
|
135
|
+
console.log(`\n${count("rendered")} rendered, ${count("failed")} failed`);
|
|
136
|
+
console.log(`Open ${join(outDir, "index.html")} to review.\n`);
|
|
137
|
+
}
|
|
138
|
+
function escapeHtml(text) {
|
|
139
|
+
return text
|
|
140
|
+
.replace(/&/g, "&")
|
|
141
|
+
.replace(/</g, "<")
|
|
142
|
+
.replace(/>/g, ">")
|
|
143
|
+
.replace(/"/g, """);
|
|
144
|
+
}
|
|
145
|
+
function embedArtifact(fileName) {
|
|
146
|
+
const ext = fileName.slice(fileName.lastIndexOf(".") + 1).toLowerCase();
|
|
147
|
+
const src = escapeHtml(fileName);
|
|
148
|
+
if (ext === "pdf") {
|
|
149
|
+
return `<iframe class="art" src="${src}" title="${src}"></iframe>`;
|
|
150
|
+
}
|
|
151
|
+
if (ext === "png" || ext === "svg") {
|
|
152
|
+
return `<img class="art" src="${src}" alt="${src}" />`;
|
|
153
|
+
}
|
|
154
|
+
return `<a href="${src}">${src}</a>`;
|
|
155
|
+
}
|
|
156
|
+
function renderIndexHtml(quiverName, results) {
|
|
157
|
+
const cards = results
|
|
158
|
+
.map((r) => {
|
|
159
|
+
const body = r.status === "rendered"
|
|
160
|
+
? r.files.map(embedArtifact).join("\n")
|
|
161
|
+
: `<ul class="reasons">${r.reasons
|
|
162
|
+
.map((reason) => `<li>${escapeHtml(reason)}</li>`)
|
|
163
|
+
.join("")}</ul>`;
|
|
164
|
+
const warnings = r.warnings.length
|
|
165
|
+
? `<ul class="warnings">${r.warnings
|
|
166
|
+
.map((w) => `<li>${escapeHtml(w)}</li>`)
|
|
167
|
+
.join("")}</ul>`
|
|
168
|
+
: "";
|
|
169
|
+
return `<section class="card ${r.status}">
|
|
170
|
+
<h2>${escapeHtml(r.ref)} <span class="badge">${r.status}</span></h2>
|
|
171
|
+
${warnings}
|
|
172
|
+
${body}
|
|
173
|
+
</section>`;
|
|
174
|
+
})
|
|
175
|
+
.join("\n");
|
|
176
|
+
return `<!doctype html>
|
|
177
|
+
<html lang="en">
|
|
178
|
+
<head>
|
|
179
|
+
<meta charset="utf-8" />
|
|
180
|
+
<title>Quiver preview — ${escapeHtml(quiverName)}</title>
|
|
181
|
+
<style>
|
|
182
|
+
body { font-family: system-ui, sans-serif; margin: 2rem; background: #fafafa; }
|
|
183
|
+
h1 { font-size: 1.4rem; }
|
|
184
|
+
.card { background: #fff; border: 1px solid #ddd; border-radius: 8px;
|
|
185
|
+
padding: 1rem; margin: 1rem 0; }
|
|
186
|
+
.card.failed { border-color: #e0b4b4; }
|
|
187
|
+
h2 { font-size: 1rem; margin: 0 0 0.5rem; }
|
|
188
|
+
.badge { font-size: 0.7rem; text-transform: uppercase; background: #eee;
|
|
189
|
+
border-radius: 4px; padding: 2px 6px; vertical-align: middle; }
|
|
190
|
+
.failed .badge { background: #f3d2d2; }
|
|
191
|
+
.art { width: 100%; height: 600px; border: 1px solid #eee; }
|
|
192
|
+
img.art { height: auto; }
|
|
193
|
+
.reasons { color: #a33; font-style: italic; }
|
|
194
|
+
.warnings { color: #96690a; font-size: 0.85rem; }
|
|
195
|
+
</style>
|
|
196
|
+
</head>
|
|
197
|
+
<body>
|
|
198
|
+
<h1>Quiver preview — ${escapeHtml(quiverName)}</h1>
|
|
199
|
+
${cards}
|
|
200
|
+
</body>
|
|
201
|
+
</html>
|
|
202
|
+
`;
|
|
203
|
+
}
|
package/dist/testing.d.ts
CHANGED
|
@@ -7,14 +7,15 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Usage (place this file next to your Quiver.yaml):
|
|
9
9
|
*
|
|
10
|
-
* import { Quillmark } from "@quillmark/wasm";
|
|
10
|
+
* import { Quillmark, Document } from "@quillmark/wasm";
|
|
11
11
|
* import { runQuiverTests } from "@quillmark/quiver/testing";
|
|
12
12
|
* const engine = new Quillmark();
|
|
13
|
-
* runQuiverTests(import.meta.url, engine);
|
|
13
|
+
* runQuiverTests(import.meta.url, engine, Document);
|
|
14
14
|
*
|
|
15
15
|
* Run with `node --test`.
|
|
16
16
|
*/
|
|
17
17
|
import type { QuillmarkLike } from "./engine-types.js";
|
|
18
|
+
import type { DocumentFactoryLike } from "./preview.js";
|
|
18
19
|
/**
|
|
19
20
|
* Registers a `node:test` describe block that validates every quill
|
|
20
21
|
* version in the quiver at `metaUrlOrDir` against the provided engine.
|
|
@@ -23,6 +24,7 @@ import type { QuillmarkLike } from "./engine-types.js";
|
|
|
23
24
|
* to Quiver.yaml). Pass an absolute directory path for any other layout.
|
|
24
25
|
*
|
|
25
26
|
* Validation covers the full loading pipeline: Quiver.yaml, Quill.yaml,
|
|
26
|
-
* all template files,
|
|
27
|
+
* all template files, engine compilation via engine.quill(tree), and a
|
|
28
|
+
* full render of each quill's blueprint document.
|
|
27
29
|
*/
|
|
28
|
-
export declare function runQuiverTests(metaUrlOrDir: string, engine: QuillmarkLike): void;
|
|
30
|
+
export declare function runQuiverTests(metaUrlOrDir: string, engine: QuillmarkLike, Document: DocumentFactoryLike): void;
|
package/dist/testing.js
CHANGED
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
*
|
|
8
8
|
* Usage (place this file next to your Quiver.yaml):
|
|
9
9
|
*
|
|
10
|
-
* import { Quillmark } from "@quillmark/wasm";
|
|
10
|
+
* import { Quillmark, Document } from "@quillmark/wasm";
|
|
11
11
|
* import { runQuiverTests } from "@quillmark/quiver/testing";
|
|
12
12
|
* const engine = new Quillmark();
|
|
13
|
-
* runQuiverTests(import.meta.url, engine);
|
|
13
|
+
* runQuiverTests(import.meta.url, engine, Document);
|
|
14
14
|
*
|
|
15
15
|
* Run with `node --test`.
|
|
16
16
|
*/
|
|
@@ -27,9 +27,10 @@ import { Quiver } from "./node.js";
|
|
|
27
27
|
* to Quiver.yaml). Pass an absolute directory path for any other layout.
|
|
28
28
|
*
|
|
29
29
|
* Validation covers the full loading pipeline: Quiver.yaml, Quill.yaml,
|
|
30
|
-
* all template files,
|
|
30
|
+
* all template files, engine compilation via engine.quill(tree), and a
|
|
31
|
+
* full render of each quill's blueprint document.
|
|
31
32
|
*/
|
|
32
|
-
export function runQuiverTests(metaUrlOrDir, engine) {
|
|
33
|
+
export function runQuiverTests(metaUrlOrDir, engine, Document) {
|
|
33
34
|
describe("Quiver", () => {
|
|
34
35
|
let quiver;
|
|
35
36
|
before(async () => {
|
|
@@ -40,12 +41,15 @@ export function runQuiverTests(metaUrlOrDir, engine) {
|
|
|
40
41
|
throw new Error("Quiver has no quills");
|
|
41
42
|
}
|
|
42
43
|
});
|
|
43
|
-
it("compiles every quill
|
|
44
|
+
it("compiles and renders every quill's blueprint without error", async () => {
|
|
44
45
|
for (const name of quiver.quillNames()) {
|
|
45
46
|
for (const version of quiver.versionsOf(name)) {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
const ref = `${name}@${version}`;
|
|
48
|
+
const quill = await quiver.getQuill(ref, { engine });
|
|
49
|
+
const doc = Document.fromMarkdown(quill.blueprint);
|
|
50
|
+
const result = quill.render(doc);
|
|
51
|
+
if (!Array.isArray(result.artifacts) || result.artifacts.length === 0) {
|
|
52
|
+
throw new Error(`${ref}: blueprint render produced no artifacts`);
|
|
49
53
|
}
|
|
50
54
|
}
|
|
51
55
|
}
|
package/package.json
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quillmark/quiver",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.9.0",
|
|
4
4
|
"description": "Quiver registry and build tooling for Quillmark",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"repository": {
|
|
8
8
|
"type": "git",
|
|
9
|
-
"url": "git+https://github.com/
|
|
9
|
+
"url": "git+https://github.com/quillmark-org/quiver.git"
|
|
10
10
|
},
|
|
11
11
|
"bugs": {
|
|
12
|
-
"url": "https://github.com/
|
|
12
|
+
"url": "https://github.com/quillmark-org/quiver/issues"
|
|
13
13
|
},
|
|
14
|
-
"homepage": "https://github.com/
|
|
14
|
+
"homepage": "https://github.com/quillmark-org/quiver#readme",
|
|
15
15
|
"keywords": [
|
|
16
16
|
"quillmark",
|
|
17
17
|
"quiver",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
],
|
|
21
21
|
"author": "Quillmark Contributors",
|
|
22
22
|
"engines": {
|
|
23
|
-
"node": ">=
|
|
23
|
+
"node": ">=24"
|
|
24
24
|
},
|
|
25
25
|
"exports": {
|
|
26
26
|
".": {
|
|
@@ -34,11 +34,16 @@
|
|
|
34
34
|
"./testing": {
|
|
35
35
|
"types": "./dist/testing.d.ts",
|
|
36
36
|
"import": "./dist/testing.js"
|
|
37
|
+
},
|
|
38
|
+
"./preview": {
|
|
39
|
+
"types": "./dist/preview.d.ts",
|
|
40
|
+
"import": "./dist/preview.js"
|
|
37
41
|
}
|
|
38
42
|
},
|
|
39
43
|
"sideEffects": [
|
|
40
44
|
"./dist/node.js",
|
|
41
|
-
"./dist/testing.js"
|
|
45
|
+
"./dist/testing.js",
|
|
46
|
+
"./dist/preview.js"
|
|
42
47
|
],
|
|
43
48
|
"files": [
|
|
44
49
|
"dist",
|
|
@@ -46,14 +51,14 @@
|
|
|
46
51
|
"README.md"
|
|
47
52
|
],
|
|
48
53
|
"peerDependencies": {
|
|
49
|
-
"@quillmark/wasm": ">=0.
|
|
54
|
+
"@quillmark/wasm": ">=0.79.0"
|
|
50
55
|
},
|
|
51
56
|
"dependencies": {
|
|
52
57
|
"fflate": "^0.8.2",
|
|
53
58
|
"yaml": "^2.8.3"
|
|
54
59
|
},
|
|
55
60
|
"devDependencies": {
|
|
56
|
-
"@quillmark/wasm": "0.
|
|
61
|
+
"@quillmark/wasm": "^0.79.0",
|
|
57
62
|
"@types/node": "^25.3.3",
|
|
58
63
|
"typescript": "^5.9.3",
|
|
59
64
|
"vitest": "^4.0.18"
|