fleuron 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,132 @@
1
+ # fleuron
2
+
3
+ Paged-media layout in a worker: markdown and CSS in, a display
4
+ structure or PDF bytes out.
5
+
6
+ [fleuron](https://fleuron.typeworks.dev/) is a layout engine for
7
+ book-shaped documents, compiled to WebAssembly. It shapes text, breaks
8
+ and hyphenates lines, fragments the result into pages, and paints the
9
+ preview and the PDF from the same numbers. It touches no DOM and opens
10
+ no files.
11
+
12
+ ```sh
13
+ npm install fleuron
14
+ ```
15
+
16
+ ## On screen
17
+
18
+ ```js
19
+ import { Preview } from 'fleuron';
20
+
21
+ const preview = await Preview.mount(document.querySelector('#book'));
22
+ await preview.setStyle(css);
23
+ await preview.setMarkdown(markdown);
24
+
25
+ preview.page = 12;
26
+ preview.zoom = 1.5;
27
+ ```
28
+
29
+ `Preview` starts the worker, loads the module into it, keeps the
30
+ session, fetches the fonts the book was set in, and paints a page as
31
+ SVG. The encoded buffer, the worker messages and the display structure
32
+ are handled internally, and all three stay exported.
33
+
34
+ `fleuron-react` is the same thing as a component, and holds no engine
35
+ logic of its own.
36
+
37
+ ## In a worker
38
+
39
+ ```js
40
+ // fleuron.worker.js
41
+ import { createEngine } from 'fleuron';
42
+
43
+ const engine = createEngine();
44
+ self.onmessage = ({ data }) => {
45
+ void engine.then((ready) =>
46
+ ready.submit(data, (response, transfer) => self.postMessage(response, transfer)),
47
+ );
48
+ };
49
+ ```
50
+
51
+ ```js
52
+ // the host
53
+ import { Client, paintPage } from 'fleuron';
54
+
55
+ const worker = new Worker(new URL('./fleuron.worker.js', import.meta.url), { type: 'module' });
56
+ const client = new Client({ post: (request, transfer) => worker.postMessage(request, transfer) });
57
+ worker.onmessage = ({ data }) => client.receive(data);
58
+
59
+ const output = await client.preview([
60
+ { op: 'markdown', name: 'manuscript.md', text: markdown },
61
+ { op: 'style', css },
62
+ ]);
63
+ if (output !== null) {
64
+ element.innerHTML = paintPage(output.pages[0], { fonts: output.fonts });
65
+ }
66
+ ```
67
+
68
+ `null` means a later render overtook this one, so there is nothing to
69
+ paint. Every render raises a generation, the worker echoes it back, and
70
+ a reply that arrives behind the current one is dropped.
71
+
72
+ The package ships the worker in the shape above, so a host that wants
73
+ no worker file of its own can point at `fleuron/worker`.
74
+
75
+ ## Sending what changed
76
+
77
+ The module keeps a session between calls: the content tree, the
78
+ styling, and every stage between them and the page. A second render
79
+ pays for the edit rather than for the book.
80
+
81
+ ```js
82
+ await client.preview([{ op: 'style', css: '@page { margin-bottom: 84pt }' }]);
83
+ await client.preview([{ op: 'edit', name: 'ch03.md', text }]);
84
+ await client.apply([{ op: 'font', bytes }]);
85
+ ```
86
+
87
+ A stylesheet that only moves the page box re-fragments over lines that
88
+ are already broken. A keystroke in one chapter reparses that file and
89
+ leaves every other section's lines alone. Font bytes cross once and
90
+ stay registered. `client.stages` reports how many times each stage has
91
+ run, which shows when a cache served.
92
+
93
+ ## Batch
94
+
95
+ ```js
96
+ import { decodeDisplayList, initWasm, render, renderPdf } from 'fleuron';
97
+
98
+ await initWasm();
99
+ const output = decodeDisplayList(render(markdown, css));
100
+ const pdf = renderPdf(markdown, css);
101
+ ```
102
+
103
+ ## The display structure
104
+
105
+ `client.preview` hands back pages of text runs, rules and images, in
106
+ points, origin top left. Each text run carries the string it was shaped
107
+ from and each glyph a byte range into it, which is what a painter needs
108
+ for selection and copy-and-paste.
109
+
110
+ `paintPage` draws one of them as SVG. Each run becomes one `<text>`
111
+ carrying an x for every character in it, so the browser places the
112
+ glyphs where the engine put them instead of working out positions of
113
+ its own. `exportPdf` writes the same pages as PDF.
114
+
115
+ The bytes underneath are postcard with a version in front of them.
116
+ `decodeDisplayList` reads them, exported for a host that moves them
117
+ around itself. Nothing about using the package requires touching them.
118
+
119
+ ## What the host owns
120
+
121
+ The engine reads no paths, so the host fetches the font bytes and sends
122
+ them once. `client.fontBytes(id)` hands back the file a face was
123
+ registered from, which is how a painter draws with the bundled one.
124
+
125
+ Layout never decodes an image. It places one from the size the host
126
+ gives it, and the host draws the pixels.
127
+
128
+ The host starts the worker. A book-scale manuscript is hundreds of
129
+ milliseconds of work, and that much time on the main thread drops
130
+ interactions.
131
+
132
+ MIT or Apache-2.0.
@@ -0,0 +1,74 @@
1
+ /**
2
+ * The host's side of the wall: send an edit, get a display structure, and
3
+ * never paint one the reader has already typed past.
4
+ */
5
+ import { type Op, type Request, type Response, type Want } from './protocol.js';
6
+ import { type LayoutOutput } from './wire.js';
7
+ /** How a request reaches the worker. */
8
+ export interface Transport {
9
+ /**
10
+ * Sends one request. `transfer` holds the buffers that should move
11
+ * rather than be copied: font and image bytes, which the host has
12
+ * no reason to keep a second copy of.
13
+ */
14
+ post(request: Request, transfer: ArrayBuffer[]): void;
15
+ }
16
+ /** A render that was overtaken: nothing came back, and nothing should be painted. */
17
+ export declare const SUPERSEDED: null;
18
+ /**
19
+ * A client over one worker.
20
+ *
21
+ * Every render raises the generation, so a reply that arrives behind
22
+ * the current one resolves to `null` instead of bytes. A caller that
23
+ * paints what it is given therefore cannot paint a stale page.
24
+ */
25
+ export declare class Client {
26
+ private readonly transport;
27
+ private readonly waiting;
28
+ private id;
29
+ private generation;
30
+ private counters;
31
+ constructor(transport: Transport);
32
+ /** Hands a reply from the worker to whoever is waiting for it. */
33
+ receive(response: Response): void;
34
+ /** The generation the next render will carry. */
35
+ get current(): number;
36
+ /**
37
+ * What the last painted render cost, counted in stage runs rather
38
+ * than milliseconds: a cache that served shows here, where a clock
39
+ * would only show a fast machine.
40
+ */
41
+ get stages(): {
42
+ style: number;
43
+ lines: number;
44
+ flow: number;
45
+ paint: number;
46
+ };
47
+ /**
48
+ * Applies inputs and asks for a display structure. Resolves to `null`
49
+ * when a later render overtook this one, or when its reply came
50
+ * back behind the current generation.
51
+ */
52
+ preview(ops?: Op[]): Promise<LayoutOutput | null>;
53
+ /** The same, as PDF bytes. */
54
+ exportPdf(ops?: Op[]): Promise<Uint8Array | null>;
55
+ /**
56
+ * The file a face was registered from, for a painter that has to
57
+ * draw with the bytes the engine shaped with.
58
+ *
59
+ * A question rather than a render: nothing overtakes it, and the
60
+ * answer does not go stale, since a face keeps its id for the
61
+ * session's life.
62
+ */
63
+ fontBytes(font: number): Promise<Uint8Array>;
64
+ /** Applies inputs and asks for nothing back. */
65
+ apply(ops: Op[]): Promise<void>;
66
+ /**
67
+ * Applies inputs and asks for bytes: the display structure as the
68
+ * engine encoded it, or a PDF. `null` when this render was
69
+ * overtaken.
70
+ */
71
+ render(ops: Op[], want: Want): Promise<Uint8Array | null>;
72
+ private send;
73
+ }
74
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAwB,KAAK,EAAE,EAAE,KAAK,OAAO,EAAE,KAAK,QAAQ,EAAE,KAAK,IAAI,EAAE,MAAM,eAAe,CAAC;AACtG,OAAO,EAAqB,KAAK,YAAY,EAAE,MAAM,WAAW,CAAC;AAEjE,wCAAwC;AACxC,MAAM,WAAW,SAAS;IACxB;;;;OAIG;IACH,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,GAAG,IAAI,CAAC;CACvD;AAED,qFAAqF;AACrF,eAAO,MAAM,UAAU,MAAO,CAAC;AAE/B;;;;;;GAMG;AACH,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmD;IAC3E,OAAO,CAAC,EAAE,CAAK;IACf,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,QAAQ,CAAkD;gBAEtD,SAAS,EAAE,SAAS;IAIhC,kEAAkE;IAClE,OAAO,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IASjC,iDAAiD;IACjD,IAAI,OAAO,IAAI,MAAM,CAEpB;IAED;;;;OAIG;IACH,IAAI,MAAM,IAAI;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAC;QAAC,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,CAG1E;IAED;;;;OAIG;IACG,OAAO,CAAC,GAAG,GAAE,EAAE,EAAO,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;IAK3D,8BAA8B;IACxB,SAAS,CAAC,GAAG,GAAE,EAAE,EAAO,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAI3D;;;;;;;OAOG;IACG,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,UAAU,CAAC;IAQlD,gDAAgD;IAC1C,KAAK,CAAC,GAAG,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC;IAIrC;;;;OAIG;IACG,MAAM,CAAC,GAAG,EAAE,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAgB/D,OAAO,CAAC,IAAI;CA4Bb"}
package/dist/client.js ADDED
@@ -0,0 +1,124 @@
1
+ /**
2
+ * The host's side of the wall: send an edit, get a display structure, and
3
+ * never paint one the reader has already typed past.
4
+ */
5
+ import { isFailed, isRendered } from './protocol.js';
6
+ import { decodeDisplayList } from './wire.js';
7
+ /** A render that was overtaken: nothing came back, and nothing should be painted. */
8
+ export const SUPERSEDED = null;
9
+ /**
10
+ * A client over one worker.
11
+ *
12
+ * Every render raises the generation, so a reply that arrives behind
13
+ * the current one resolves to `null` instead of bytes. A caller that
14
+ * paints what it is given therefore cannot paint a stale page.
15
+ */
16
+ export class Client {
17
+ transport;
18
+ waiting = new Map();
19
+ id = 0;
20
+ generation = 0;
21
+ counters = [0, 0, 0, 0];
22
+ constructor(transport) {
23
+ this.transport = transport;
24
+ }
25
+ /** Hands a reply from the worker to whoever is waiting for it. */
26
+ receive(response) {
27
+ const settle = this.waiting.get(response.id);
28
+ if (settle === undefined) {
29
+ return;
30
+ }
31
+ this.waiting.delete(response.id);
32
+ settle(response);
33
+ }
34
+ /** The generation the next render will carry. */
35
+ get current() {
36
+ return this.generation;
37
+ }
38
+ /**
39
+ * What the last painted render cost, counted in stage runs rather
40
+ * than milliseconds: a cache that served shows here, where a clock
41
+ * would only show a fast machine.
42
+ */
43
+ get stages() {
44
+ const [style, lines, flow, paint] = this.counters;
45
+ return { style, lines, flow, paint };
46
+ }
47
+ /**
48
+ * Applies inputs and asks for a display structure. Resolves to `null`
49
+ * when a later render overtook this one, or when its reply came
50
+ * back behind the current generation.
51
+ */
52
+ async preview(ops = []) {
53
+ const bytes = await this.render(ops, 'preview');
54
+ return bytes === SUPERSEDED ? SUPERSEDED : decodeDisplayList(bytes);
55
+ }
56
+ /** The same, as PDF bytes. */
57
+ async exportPdf(ops = []) {
58
+ return this.render(ops, 'pdf');
59
+ }
60
+ /**
61
+ * The file a face was registered from, for a painter that has to
62
+ * draw with the bytes the engine shaped with.
63
+ *
64
+ * A question rather than a render: nothing overtakes it, and the
65
+ * answer does not go stale, since a face keeps its id for the
66
+ * session's life.
67
+ */
68
+ async fontBytes(font) {
69
+ const response = await this.send({ ops: [], want: 'font', font });
70
+ if (!isRendered(response)) {
71
+ throw new Error(`the engine sent no bytes for font ${font}`);
72
+ }
73
+ return response.bytes;
74
+ }
75
+ /** Applies inputs and asks for nothing back. */
76
+ async apply(ops) {
77
+ await this.send({ ops });
78
+ }
79
+ /**
80
+ * Applies inputs and asks for bytes: the display structure as the
81
+ * engine encoded it, or a PDF. `null` when this render was
82
+ * overtaken.
83
+ */
84
+ async render(ops, want) {
85
+ this.generation += 1;
86
+ const response = await this.send({ ops, want, generation: this.generation });
87
+ if (!isRendered(response)) {
88
+ return SUPERSEDED;
89
+ }
90
+ // The worker only knows it was overtaken by a request it had in
91
+ // hand. A reply can also be outrun in flight, and the host is the
92
+ // one who can see that.
93
+ if (response.generation < this.generation) {
94
+ return SUPERSEDED;
95
+ }
96
+ this.counters = response.stages;
97
+ return response.bytes;
98
+ }
99
+ send(what) {
100
+ this.id += 1;
101
+ const request = {
102
+ id: this.id,
103
+ generation: what.generation ?? this.generation,
104
+ ops: what.ops,
105
+ ...(what.want === undefined ? {} : { want: what.want }),
106
+ ...(what.font === undefined ? {} : { font: what.font }),
107
+ };
108
+ const transfer = request.ops
109
+ .filter((op) => op.op === 'font' || op.op === 'image')
110
+ .map((op) => op.bytes.buffer);
111
+ return new Promise((resolve, reject) => {
112
+ this.waiting.set(request.id, (response) => {
113
+ if (isFailed(response)) {
114
+ reject(new Error(response.error));
115
+ }
116
+ else {
117
+ resolve(response);
118
+ }
119
+ });
120
+ this.transport.post(request, transfer);
121
+ });
122
+ }
123
+ }
124
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,50 @@
1
+ /**
2
+ * The worker's side of the wall: the module, the session it keeps,
3
+ * and the rule that only the newest render is worth running.
4
+ *
5
+ * Requests are applied in the order they arrive and renders are not.
6
+ * A render that a later request overtakes before it starts is
7
+ * dropped, and the inputs it carried are applied all the same. So a
8
+ * dropped render leaves no stage half-built, and the render that
9
+ * follows it produces exactly what it would have produced had nobody
10
+ * typed.
11
+ */
12
+ import { Session, type InitInput } from '../wasm/fleuron.js';
13
+ import type { Request, Response } from './protocol.js';
14
+ /** How the module is loaded. */
15
+ export interface EngineOptions {
16
+ /**
17
+ * The module itself, or where to fetch it. A browser that serves
18
+ * the package can leave this out and let the module find its own
19
+ * `.wasm` beside the glue. Anywhere without `fetch` over the
20
+ * package's own files (Node, an extension, a bundler that inlines
21
+ * the module) passes the bytes.
22
+ */
23
+ wasm?: InitInput;
24
+ }
25
+ /** Sends one reply, moving the bytes rather than copying them. */
26
+ export type Reply = (response: Response, transfer: ArrayBuffer[]) => void;
27
+ /**
28
+ * Loads the module and opens a session over it.
29
+ *
30
+ * One session per worker: it holds the manuscript, the styling and
31
+ * every stage between them, which is what makes the second render of
32
+ * a book cost what changed rather than the book.
33
+ */
34
+ export declare function createEngine(options?: EngineOptions): Promise<Engine>;
35
+ /** A session, and the queue of requests waiting on it. */
36
+ export declare class Engine {
37
+ private readonly session;
38
+ private readonly queue;
39
+ private draining;
40
+ constructor(session: Session);
41
+ /** Takes a request. Replies arrive through `reply`, in order. */
42
+ submit(request: Request, reply: Reply): void;
43
+ /** Releases the module's session. */
44
+ free(): void;
45
+ private drain;
46
+ private run;
47
+ private produce;
48
+ private apply;
49
+ }
50
+ //# sourceMappingURL=engine.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.d.ts","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAa,EAAE,OAAO,EAAE,KAAK,SAAS,EAAE,MAAM,oBAAoB,CAAC;AACnE,OAAO,KAAK,EAAM,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAE3D,gCAAgC;AAChC,MAAM,WAAW,aAAa;IAC5B;;;;;;OAMG;IACH,IAAI,CAAC,EAAE,SAAS,CAAC;CAClB;AAED,kEAAkE;AAClE,MAAM,MAAM,KAAK,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,QAAQ,EAAE,WAAW,EAAE,KAAK,IAAI,CAAC;AAO1E;;;;;;GAMG;AACH,wBAAsB,YAAY,CAAC,OAAO,GAAE,aAAkB,GAAG,OAAO,CAAC,MAAM,CAAC,CAG/E;AAED,0DAA0D;AAC1D,qBAAa,MAAM;IACjB,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAU;IAClC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiB;IACvC,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,EAAE,OAAO;IAI5B,iEAAiE;IACjE,MAAM,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,GAAG,IAAI;IAK5C,qCAAqC;IACrC,IAAI,IAAI,IAAI;YAIE,KAAK;IAqBnB,OAAO,CAAC,GAAG;IAmCX,OAAO,CAAC,OAAO;IAWf,OAAO,CAAC,KAAK;CAwCd"}
package/dist/engine.js ADDED
@@ -0,0 +1,163 @@
1
+ /**
2
+ * The worker's side of the wall: the module, the session it keeps,
3
+ * and the rule that only the newest render is worth running.
4
+ *
5
+ * Requests are applied in the order they arrive and renders are not.
6
+ * A render that a later request overtakes before it starts is
7
+ * dropped, and the inputs it carried are applied all the same. So a
8
+ * dropped render leaves no stage half-built, and the render that
9
+ * follows it produces exactly what it would have produced had nobody
10
+ * typed.
11
+ */
12
+ import init, { Session } from '../wasm/fleuron.js';
13
+ /**
14
+ * Loads the module and opens a session over it.
15
+ *
16
+ * One session per worker: it holds the manuscript, the styling and
17
+ * every stage between them, which is what makes the second render of
18
+ * a book cost what changed rather than the book.
19
+ */
20
+ export async function createEngine(options = {}) {
21
+ await init(options.wasm === undefined ? undefined : { module_or_path: options.wasm });
22
+ return new Engine(new Session());
23
+ }
24
+ /** A session, and the queue of requests waiting on it. */
25
+ export class Engine {
26
+ session;
27
+ queue = [];
28
+ draining = false;
29
+ constructor(session) {
30
+ this.session = session;
31
+ }
32
+ /** Takes a request. Replies arrive through `reply`, in order. */
33
+ submit(request, reply) {
34
+ this.queue.push({ request, reply });
35
+ void this.drain();
36
+ }
37
+ /** Releases the module's session. */
38
+ free() {
39
+ this.session.free();
40
+ }
41
+ async drain() {
42
+ if (this.draining) {
43
+ return;
44
+ }
45
+ this.draining = true;
46
+ try {
47
+ while (this.queue.length > 0) {
48
+ // Everything already sent is delivered before anything is
49
+ // rendered, which is what makes latest-wins mean the latest
50
+ // the host has actually asked for rather than the latest one
51
+ // request ago.
52
+ await settle();
53
+ const batch = this.queue.splice(0);
54
+ const newest = lastRenderIn(batch);
55
+ batch.forEach((pending, index) => this.run(pending, index === newest));
56
+ }
57
+ }
58
+ finally {
59
+ this.draining = false;
60
+ }
61
+ }
62
+ run(pending, render) {
63
+ const { request, reply } = pending;
64
+ const { id, generation } = request;
65
+ try {
66
+ // Inputs are applied whether or not this request's render
67
+ // survives: an edit that crossed the wall is not undone by the
68
+ // keystroke that followed it.
69
+ for (const op of request.ops) {
70
+ this.apply(op);
71
+ }
72
+ if (request.want === undefined) {
73
+ reply({ id, generation, applied: true }, []);
74
+ return;
75
+ }
76
+ if (!render && request.want !== 'font') {
77
+ reply({ id, generation, superseded: true }, []);
78
+ return;
79
+ }
80
+ const bytes = this.produce(request);
81
+ const stages = this.session.stages();
82
+ reply({
83
+ id,
84
+ generation,
85
+ kind: request.want,
86
+ bytes,
87
+ stages: [stages[0] ?? 0, stages[1] ?? 0, stages[2] ?? 0, stages[3] ?? 0],
88
+ }, [bytes.buffer]);
89
+ }
90
+ catch (error) {
91
+ reply({ id, generation, error: String(error) }, []);
92
+ }
93
+ }
94
+ produce(request) {
95
+ switch (request.want) {
96
+ case 'pdf':
97
+ return this.session.exportPdf();
98
+ case 'font':
99
+ return this.session.fontBytes(request.font ?? 0);
100
+ default:
101
+ return this.session.preview();
102
+ }
103
+ }
104
+ apply(op) {
105
+ switch (op.op) {
106
+ case 'font':
107
+ this.session.addFont(op.bytes);
108
+ break;
109
+ case 'image':
110
+ this.session.addImage(op.url, op.bytes);
111
+ break;
112
+ case 'dialect':
113
+ this.session.setDialect(op.dialect);
114
+ break;
115
+ case 'split':
116
+ this.session.setSplit(op.level);
117
+ break;
118
+ case 'markdown':
119
+ this.session.setMarkdown(op.name, op.text);
120
+ break;
121
+ case 'book':
122
+ this.session.setSources(op.sources.map((source) => source.name), op.sources.map((source) => source.text));
123
+ break;
124
+ case 'remove':
125
+ this.session.removeMarkdown(op.name);
126
+ break;
127
+ case 'metadata':
128
+ this.session.setMetadata(JSON.stringify(op.metadata));
129
+ break;
130
+ case 'edit':
131
+ this.session.updateMarkdown(op.name, op.text);
132
+ break;
133
+ case 'content':
134
+ this.session.setContent(op.json);
135
+ break;
136
+ case 'style':
137
+ this.session.setStyle(op.css);
138
+ break;
139
+ }
140
+ }
141
+ }
142
+ /**
143
+ * Which request in a batch is the one whose render still matters.
144
+ *
145
+ * A question is not a render: asking for a face's bytes neither
146
+ * overtakes a render nor is overtaken by one.
147
+ */
148
+ function lastRenderIn(batch) {
149
+ for (let index = batch.length - 1; index >= 0; index -= 1) {
150
+ const want = batch[index]?.request.want;
151
+ if (want === 'preview' || want === 'pdf') {
152
+ return index;
153
+ }
154
+ }
155
+ return -1;
156
+ }
157
+ /** Yields long enough for messages already sent to be delivered. */
158
+ function settle() {
159
+ return new Promise((resolve) => {
160
+ setTimeout(resolve, 0);
161
+ });
162
+ }
163
+ //# sourceMappingURL=engine.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"engine.js","sourceRoot":"","sources":["../src/engine.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,22 @@
1
+ /**
2
+ * fleuron in a worker: markdown and CSS in, a display structure or PDF
3
+ * bytes out.
4
+ *
5
+ * The host keeps a {@link Client}, the worker keeps an
6
+ * {@link Engine}, and between them the engine's session keeps every
7
+ * stage of the pipeline so that a second render pays for the edit
8
+ * rather than for the book.
9
+ *
10
+ * {@link Preview} is all of that behind one object: an element, a
11
+ * manuscript, and a page on screen.
12
+ */
13
+ export { Client, SUPERSEDED, type Transport } from './client.js';
14
+ export { Engine, createEngine, type EngineOptions, type Reply } from './engine.js';
15
+ export { isFailed, isRendered, type Applied, type Failed, type Metadata, type Op, type Rendered, type Request, type Response, type Source, type Superseded, type Want, } from './protocol.js';
16
+ export { Preview, type PreviewOptions } from './preview.js';
17
+ export { VERSION } from './version.js';
18
+ export { faceFamily, paintPage, type PaintOptions } from './svg.js';
19
+ export { WIRE_VERSION, WireError, decodeDisplayList, wireVersionOf, type Asset, type DrawItem, type AxisSetting, type FaceAttributes, type FontRefEntry, type Glyph, type ImageItem, type Intrinsic, type LayoutOutput, type Page, type RectItem, type Side, type TextItem, type Warning, } from './wire.js';
20
+ export { Session, render, renderPdf, wireVersion } from '../wasm/fleuron.js';
21
+ export { default as initWasm, initSync, type InitInput, type SyncInitInput } from '../wasm/fleuron.js';
22
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,SAAS,EAAE,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,KAAK,EAAE,MAAM,aAAa,CAAC;AACnF,OAAO,EACL,QAAQ,EACR,UAAU,EACV,KAAK,OAAO,EACZ,KAAK,MAAM,EACX,KAAK,QAAQ,EACb,KAAK,EAAE,EACP,KAAK,QAAQ,EACb,KAAK,OAAO,EACZ,KAAK,QAAQ,EACb,KAAK,MAAM,EACX,KAAK,UAAU,EACf,KAAK,IAAI,GACV,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,KAAK,YAAY,EAAE,MAAM,UAAU,CAAC;AACpE,OAAO,EACL,YAAY,EACZ,SAAS,EACT,iBAAiB,EACjB,aAAa,EACb,KAAK,KAAK,EACV,KAAK,QAAQ,EACb,KAAK,WAAW,EAChB,KAAK,cAAc,EACnB,KAAK,YAAY,EACjB,KAAK,KAAK,EACV,KAAK,SAAS,EACd,KAAK,SAAS,EACd,KAAK,YAAY,EACjB,KAAK,IAAI,EACT,KAAK,QAAQ,EACb,KAAK,IAAI,EACT,KAAK,QAAQ,EACb,KAAK,OAAO,GACb,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,QAAQ,EAAE,KAAK,SAAS,EAAE,KAAK,aAAa,EAAE,MAAM,oBAAoB,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,22 @@
1
+ /**
2
+ * fleuron in a worker: markdown and CSS in, a display structure or PDF
3
+ * bytes out.
4
+ *
5
+ * The host keeps a {@link Client}, the worker keeps an
6
+ * {@link Engine}, and between them the engine's session keeps every
7
+ * stage of the pipeline so that a second render pays for the edit
8
+ * rather than for the book.
9
+ *
10
+ * {@link Preview} is all of that behind one object: an element, a
11
+ * manuscript, and a page on screen.
12
+ */
13
+ export { Client, SUPERSEDED } from './client.js';
14
+ export { Engine, createEngine } from './engine.js';
15
+ export { isFailed, isRendered, } from './protocol.js';
16
+ export { Preview } from './preview.js';
17
+ export { VERSION } from './version.js';
18
+ export { faceFamily, paintPage } from './svg.js';
19
+ export { WIRE_VERSION, WireError, decodeDisplayList, wireVersionOf, } from './wire.js';
20
+ export { Session, render, renderPdf, wireVersion } from '../wasm/fleuron.js';
21
+ export { default as initWasm, initSync } from '../wasm/fleuron.js';
22
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,MAAM,EAAE,UAAU,EAAkB,MAAM,aAAa,CAAC;AACjE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAkC,MAAM,aAAa,CAAC;AACnF,OAAO,EACL,QAAQ,EACR,UAAU,GAWX,MAAM,eAAe,CAAC;AACvB,OAAO,EAAE,OAAO,EAAuB,MAAM,cAAc,CAAC;AAC5D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AACvC,OAAO,EAAE,UAAU,EAAE,SAAS,EAAqB,MAAM,UAAU,CAAC;AACpE,OAAO,EACL,YAAY,EACZ,SAAS,EACT,iBAAiB,EACjB,aAAa,GAed,MAAM,WAAW,CAAC;AACnB,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAC7E,OAAO,EAAE,OAAO,IAAI,QAAQ,EAAE,QAAQ,EAAsC,MAAM,oBAAoB,CAAC"}