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 +132 -0
- package/dist/client.d.ts +74 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +124 -0
- package/dist/client.js.map +1 -0
- package/dist/engine.d.ts +50 -0
- package/dist/engine.d.ts.map +1 -0
- package/dist/engine.js +163 -0
- package/dist/engine.js.map +1 -0
- package/dist/index.d.ts +22 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +22 -0
- package/dist/index.js.map +1 -0
- package/dist/preview.d.ts +193 -0
- package/dist/preview.d.ts.map +1 -0
- package/dist/preview.js +303 -0
- package/dist/preview.js.map +1 -0
- package/dist/protocol.d.ts +153 -0
- package/dist/protocol.d.ts.map +1 -0
- package/dist/protocol.js +19 -0
- package/dist/protocol.js.map +1 -0
- package/dist/svg.d.ts +57 -0
- package/dist/svg.d.ts.map +1 -0
- package/dist/svg.js +210 -0
- package/dist/svg.js.map +1 -0
- package/dist/version.d.ts +8 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +8 -0
- package/dist/version.js.map +1 -0
- package/dist/wire.d.ts +179 -0
- package/dist/wire.d.ts.map +1 -0
- package/dist/wire.js +174 -0
- package/dist/wire.js.map +1 -0
- package/dist/worker.d.ts +16 -0
- package/dist/worker.d.ts.map +1 -0
- package/dist/worker.js +23 -0
- package/dist/worker.js.map +1 -0
- package/package.json +45 -0
- package/wasm/fleuron.d.ts +221 -0
- package/wasm/fleuron.js +629 -0
- package/wasm/fleuron_bg.wasm +0 -0
- package/wasm/fleuron_bg.wasm.d.ts +30 -0
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.
|
package/dist/client.d.ts
ADDED
|
@@ -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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"}
|
package/dist/engine.d.ts
ADDED
|
@@ -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":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,IAAI,EAAE,EAAE,OAAO,EAAkB,MAAM,oBAAoB,CAAC;AAuBnE;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,UAAyB,EAAE;IAC5D,MAAM,IAAI,CAAC,OAAO,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;IACtF,OAAO,IAAI,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC,CAAC;AACnC,CAAC;AAED,0DAA0D;AAC1D,MAAM,OAAO,MAAM;IACA,OAAO,CAAU;IACjB,KAAK,GAAc,EAAE,CAAC;IAC/B,QAAQ,GAAG,KAAK,CAAC;IAEzB,YAAY,OAAgB;QAC1B,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IACzB,CAAC;IAED,iEAAiE;IACjE,MAAM,CAAC,OAAgB,EAAE,KAAY;QACnC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,CAAC,CAAC;QACpC,KAAK,IAAI,CAAC,KAAK,EAAE,CAAC;IACpB,CAAC;IAED,qCAAqC;IACrC,IAAI;QACF,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC;IACtB,CAAC;IAEO,KAAK,CAAC,KAAK;QACjB,IAAI,IAAI,CAAC,QAAQ,EAAE,CAAC;YAClB,OAAO;QACT,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC;QACrB,IAAI,CAAC;YACH,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBAC7B,0DAA0D;gBAC1D,4DAA4D;gBAC5D,6DAA6D;gBAC7D,eAAe;gBACf,MAAM,MAAM,EAAE,CAAC;gBACf,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;gBACnC,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;gBACnC,KAAK,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,KAAK,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,OAAO,EAAE,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC;YACzE,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,IAAI,CAAC,QAAQ,GAAG,KAAK,CAAC;QACxB,CAAC;IACH,CAAC;IAEO,GAAG,CAAC,OAAgB,EAAE,MAAe;QAC3C,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC;QACnC,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,GAAG,OAAO,CAAC;QACnC,IAAI,CAAC;YACH,0DAA0D;YAC1D,+DAA+D;YAC/D,8BAA8B;YAC9B,KAAK,MAAM,EAAE,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;gBAC7B,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACjB,CAAC;YACD,IAAI,OAAO,CAAC,IAAI,KAAK,SAAS,EAAE,CAAC;gBAC/B,KAAK,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;gBAC7C,OAAO;YACT,CAAC;YACD,IAAI,CAAC,MAAM,IAAI,OAAO,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;gBACvC,KAAK,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,UAAU,EAAE,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;gBAChD,OAAO;YACT,CAAC;YACD,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;YACpC,MAAM,MAAM,GAAG,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACrC,KAAK,CACH;gBACE,EAAE;gBACF,UAAU;gBACV,IAAI,EAAE,OAAO,CAAC,IAAI;gBAClB,KAAK;gBACL,MAAM,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;aACzE,EACD,CAAC,KAAK,CAAC,MAAqB,CAAC,CAC9B,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,KAAK,CAAC,EAAE,EAAE,EAAE,UAAU,EAAE,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACtD,CAAC;IACH,CAAC;IAEO,OAAO,CAAC,OAAgB;QAC9B,QAAQ,OAAO,CAAC,IAAI,EAAE,CAAC;YACrB,KAAK,KAAK;gBACR,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;YAClC,KAAK,MAAM;gBACT,OAAO,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,CAAC;YACnD;gBACE,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,EAAE,CAAC;QAClC,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,EAAM;QAClB,QAAQ,EAAE,CAAC,EAAE,EAAE,CAAC;YACd,KAAK,MAAM;gBACT,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;gBAC/B,MAAM;YACR,KAAK,OAAO;gBACV,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC;gBACxC,MAAM;YACR,KAAK,SAAS;gBACZ,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC;gBACpC,MAAM;YACR,KAAK,OAAO;gBACV,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC;gBAChC,MAAM;YACR,KAAK,UAAU;gBACb,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;gBAC3C,MAAM;YACR,KAAK,MAAM;gBACT,IAAI,CAAC,OAAO,CAAC,UAAU,CACrB,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EACvC,EAAE,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CACxC,CAAC;gBACF,MAAM;YACR,KAAK,QAAQ;gBACX,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;gBACrC,MAAM;YACR,KAAK,UAAU;gBACb,IAAI,CAAC,OAAO,CAAC,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC;gBACtD,MAAM;YACR,KAAK,MAAM;gBACT,IAAI,CAAC,OAAO,CAAC,cAAc,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,CAAC;gBAC9C,MAAM;YACR,KAAK,SAAS;gBACZ,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC;gBACjC,MAAM;YACR,KAAK,OAAO;gBACV,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC;gBAC9B,MAAM;QACV,CAAC;IACH,CAAC;CACF;AAED;;;;;GAKG;AACH,SAAS,YAAY,CAAC,KAAgB;IACpC,KAAK,IAAI,KAAK,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC,EAAE,CAAC;QAC1D,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,IAAI,CAAC;QACxC,IAAI,IAAI,KAAK,SAAS,IAAI,IAAI,KAAK,KAAK,EAAE,CAAC;YACzC,OAAO,KAAK,CAAC;QACf,CAAC;IACH,CAAC;IACD,OAAO,CAAC,CAAC,CAAC;AACZ,CAAC;AAED,oEAAoE;AACpE,SAAS,MAAM;IACb,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/index.d.ts
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, 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"}
|