@vedivad/typst-web-service 0.15.4 → 0.17.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/README.md +68 -74
- package/dist/index.d.ts +176 -458
- package/dist/index.js +298 -635
- package/dist/index.js.map +1 -1
- package/dist/typsten-worker.js +509 -0
- package/dist/typsten-worker.js.map +1 -0
- package/dist/typsten_bg.wasm +0 -0
- package/package.json +5 -17
- package/dist/analyzer-worker.js +0 -1045
- package/dist/analyzer-worker.js.map +0 -1
- package/dist/compiler-worker.js +0 -2207
- package/dist/compiler-worker.js.map +0 -1
- package/dist/renderer-worker.js +0 -5261
- package/dist/renderer-worker.js.map +0 -1
package/README.md
CHANGED
|
@@ -1,14 +1,8 @@
|
|
|
1
1
|
# @vedivad/typst-web-service
|
|
2
2
|
|
|
3
|
-
Editor-agnostic Typst
|
|
4
|
-
format via WASM.
|
|
3
|
+
Editor-agnostic Typst engine for the web: compile, render, format, autocomplete, hover, and syntax-highlight, all from a single Typst engine compiled to WebAssembly and run in a Web Worker.
|
|
5
4
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
`TypstCompiler.create()` and `TypstAnalyzer.create()` are async because they
|
|
9
|
-
initialize worker-backed WASM services up front. `TypstRenderer.create()` and
|
|
10
|
-
`TypstFormatter.create()` are sync wrappers; their WASM work is awaited by
|
|
11
|
-
methods like `renderSvgPages()` and `format()`.
|
|
5
|
+
Everything goes through one class, `TypstProject`. It owns an in-memory file system, mirrors your files into the worker, schedules compiles, and forwards engine queries.
|
|
12
6
|
|
|
13
7
|
## Install
|
|
14
8
|
|
|
@@ -16,98 +10,98 @@ methods like `renderSvgPages()` and `format()`.
|
|
|
16
10
|
npm install @vedivad/typst-web-service
|
|
17
11
|
```
|
|
18
12
|
|
|
19
|
-
> Most users should install `@vedivad/codemirror-typst` instead, which re-exports everything
|
|
13
|
+
> Most users should install `@vedivad/codemirror-typst` instead, which re-exports everything here and adds CodeMirror 6 integration.
|
|
14
|
+
|
|
15
|
+
## Prerequisites
|
|
16
|
+
|
|
17
|
+
A bundler with WebAssembly support (e.g. [Vite](https://vite.dev) with [`vite-plugin-wasm`](https://github.com/nicolo-ribaudo/vite-plugin-wasm)). The engine wasm ships inside this package and is loaded into a worker at runtime; there are no separate binaries to wire up.
|
|
20
18
|
|
|
21
|
-
##
|
|
19
|
+
## Compile and render
|
|
22
20
|
|
|
23
21
|
```ts
|
|
24
|
-
import {
|
|
25
|
-
|
|
26
|
-
const compiler = await TypstCompiler.create();
|
|
27
|
-
const renderer = TypstRenderer.create();
|
|
28
|
-
|
|
29
|
-
// Populate the VFS, then compile
|
|
30
|
-
await compiler.setText("/main.typ", "= Hello, Typst");
|
|
31
|
-
const firstResult = await compiler.compile();
|
|
32
|
-
if (firstResult.vector) {
|
|
33
|
-
const pages = await renderer.renderSvgPages(firstResult.vector);
|
|
34
|
-
document.querySelector("#preview")!.innerHTML = pages
|
|
35
|
-
.map((page) => `<div class="page">${page.svg}</div>`)
|
|
36
|
-
.join("");
|
|
37
|
-
}
|
|
22
|
+
import { TypstProject } from "@vedivad/typst-web-service";
|
|
38
23
|
|
|
39
|
-
|
|
40
|
-
// (path, start position, end position, message)
|
|
24
|
+
const project = await TypstProject.create();
|
|
41
25
|
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
"/main.typ": '#import "template.typ": greet\n#greet("World")',
|
|
26
|
+
await project.setMany({
|
|
27
|
+
"/main.typ": '#import "/template.typ": greet\n#greet("World")',
|
|
45
28
|
"/template.typ": "#let greet(name) = [Hello, #name!]",
|
|
46
29
|
});
|
|
47
|
-
const multiFileResult = await compiler.compile();
|
|
48
30
|
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
31
|
+
const result = await project.compile();
|
|
32
|
+
// result.diagnostics: errors/warnings (deterministic order)
|
|
33
|
+
// result.pages: per-page dimensions (compile lays out; SVG is rendered on demand)
|
|
34
|
+
|
|
35
|
+
const pages = await project.renderedPages(0, result.pages.length);
|
|
36
|
+
document.querySelector("#preview")!.innerHTML = pages
|
|
37
|
+
.map((page) => `<div class="page">${page.svg}</div>`)
|
|
38
|
+
.join("");
|
|
39
|
+
|
|
40
|
+
// Export the last compile to PDF
|
|
41
|
+
const pdf = await project.exportPdf();
|
|
42
|
+
if (pdf) {
|
|
43
|
+
const blob = new Blob([pdf.slice()], { type: "application/pdf" });
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
project.destroy();
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
`compile()` returns the fresh result and also fires `onCompile` listeners; subscribe for reactive updates:
|
|
52
50
|
|
|
53
|
-
|
|
51
|
+
```ts
|
|
52
|
+
const unsubscribe = project.onCompile((result) => {
|
|
53
|
+
/* result.pages, result.diagnostics */
|
|
54
|
+
});
|
|
54
55
|
```
|
|
55
56
|
|
|
56
|
-
|
|
57
|
+
Rendering is on demand so a viewer can virtualize: `renderPage(index)` returns one page's SVG, `renderedPages(start, end)` returns `{ index, width, height, svg }` for a range.
|
|
58
|
+
|
|
59
|
+
## Fonts
|
|
57
60
|
|
|
58
|
-
|
|
61
|
+
The engine bundles Typst's default fonts (Libertinus Serif for body, New Computer Modern Math for equations, DejaVu Sans Mono for raw/code), so documents render out of the box. Use `addFont` to register families the engine does not ship, such as other scripts (CJK) or a brand font:
|
|
59
62
|
|
|
60
63
|
```ts
|
|
61
|
-
|
|
64
|
+
const bytes = new Uint8Array(await (await fetch(fontUrl)).arrayBuffer());
|
|
65
|
+
await project.addFont(bytes); // TTF/OTF or a TTC collection
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
Added fonts persist for the project's lifetime, and adding one schedules a recompile.
|
|
62
69
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
70
|
+
## Compile scheduling
|
|
71
|
+
|
|
72
|
+
VFS mutations (`setText`, `setMany`, `setBinary`, `remove`, `clear`, entry change) auto-schedule a debounced compile. Configure it per project; call `compile()` to flush immediately.
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
const project = await TypstProject.create({
|
|
76
|
+
entry: "/main.typ", // default compile entry (default: "/main.typ")
|
|
77
|
+
autoCompile: { debounceMs: 300, maxWaitMs: 2000 },
|
|
78
|
+
});
|
|
66
79
|
```
|
|
67
80
|
|
|
68
|
-
|
|
81
|
+
| Option | Default | Behavior |
|
|
82
|
+
| ------------------------ | ------- | ------------------------------------------------------------------------------------ |
|
|
83
|
+
| `autoCompile.debounceMs` | `0` | Coalesce a burst of mutations into one compile, firing once they pause. |
|
|
84
|
+
| `autoCompile.maxWaitMs` | `0` | Force a compile at least this often during sustained mutation. Needs `debounceMs`>0. |
|
|
69
85
|
|
|
70
|
-
|
|
71
|
-
| ------------------------- | --------- | ------- | ----------------------------------- |
|
|
72
|
-
| `tab_spaces` | `number` | `2` | Spaces per indentation level |
|
|
73
|
-
| `max_width` | `number` | `80` | Maximum line width |
|
|
74
|
-
| `blank_lines_upper_bound` | `number` | -- | Max consecutive blank lines |
|
|
75
|
-
| `collapse_markup_spaces` | `boolean` | -- | Collapse whitespace in markup |
|
|
76
|
-
| `reorder_import_items` | `boolean` | -- | Sort import items alphabetically |
|
|
77
|
-
| `wrap_text` | `boolean` | -- | Wrap text to fit within `max_width` |
|
|
86
|
+
`@preview` packages are fetched over HTTP on demand: when a source imports `@preview/...`, the referenced package is downloaded and pushed into the VFS before the compile runs. Sources with no such imports never hit the network.
|
|
78
87
|
|
|
79
|
-
##
|
|
88
|
+
## Editor intelligence
|
|
80
89
|
|
|
81
|
-
`
|
|
90
|
+
Completions, hover, formatting, and highlighting come from the engine's own `typst-ide` and `typst-syntax`; there is no separate language server. The IDE methods take the live editor buffer (`source`) so they work whether or not the project's VFS is already current. Offsets are CodeMirror (UTF-16) positions.
|
|
82
91
|
|
|
83
92
|
```ts
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
const analyzer = await TypstAnalyzer.create({ wasmUrl: tinymistWasmUrl });
|
|
88
|
-
|
|
89
|
-
await analyzer.didChange("untitled:project/main.typ", source);
|
|
90
|
-
const completions = await analyzer.completion(
|
|
91
|
-
"untitled:project/main.typ",
|
|
92
|
-
source,
|
|
93
|
-
{ line, character },
|
|
94
|
-
);
|
|
95
|
-
const hover = await analyzer.hover("untitled:project/main.typ", source, {
|
|
96
|
-
line,
|
|
97
|
-
character,
|
|
98
|
-
});
|
|
93
|
+
const completions = await project.completion("/main.typ", source, offset);
|
|
94
|
+
const hover = await project.hover("/main.typ", source, offset);
|
|
95
|
+
const formatted = await project.format("/main.typ", source);
|
|
99
96
|
|
|
100
|
-
|
|
97
|
+
// Syntax highlighting: spans for a viewport, or ready HTML for a snippet.
|
|
98
|
+
const spans = await project.highlight(source, viewportFrom, viewportTo);
|
|
99
|
+
const html = await project.highlightHtml(codeSnippet);
|
|
101
100
|
```
|
|
102
101
|
|
|
103
|
-
##
|
|
102
|
+
## Offsets
|
|
104
103
|
|
|
105
|
-
|
|
106
|
-
| ---------------- | ----------- | ----------------------- | ---------------------------------------------------------- |
|
|
107
|
-
| `TypstCompiler` | Web Worker | CDN (automatic) | `compile()` -> diagnostics + vector, `compilePdf()` -> PDF |
|
|
108
|
-
| `TypstRenderer` | Main thread | CDN (automatic) | `renderSvg(vector)` or `renderSvgPages(vector)` |
|
|
109
|
-
| `TypstFormatter` | Main thread | Bundler (static import) | `format(source)`, `formatRange(source, start, end)` |
|
|
110
|
-
| `TypstAnalyzer` | Web Worker | User-provided `wasmUrl` | Completion + hover via tinymist |
|
|
104
|
+
The engine speaks UTF-8 byte offsets; editors speak UTF-16. `cmOffsetToByte` and `byteToCmOffset` convert a single position; the project's own methods accept and return CodeMirror offsets, so you only need these if you work with raw engine offsets directly.
|
|
111
105
|
|
|
112
106
|
## License
|
|
113
107
|
|