@vedivad/typst-web-service 0.9.0 → 0.9.3
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/dist/index.d.ts +26 -13
- package/dist/index.js +109 -78
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -312,17 +312,24 @@ interface TypstProjectOptions {
|
|
|
312
312
|
*/
|
|
313
313
|
analyzerUriRoot?: string;
|
|
314
314
|
/**
|
|
315
|
-
*
|
|
315
|
+
* Scheduling for auto-compiles after VFS mutations. Mutations debounce by
|
|
316
|
+
* `debounceMs`; `maxWaitMs` caps how long the debounce can keep deferring
|
|
317
|
+
* during sustained edits so the user still sees progress.
|
|
318
|
+
*/
|
|
319
|
+
autoCompile?: AutoCompileOptions;
|
|
320
|
+
}
|
|
321
|
+
interface AutoCompileOptions {
|
|
322
|
+
/**
|
|
323
|
+
* Idle time (ms) after the last VFS mutation before a compile fires.
|
|
316
324
|
* Default: 0 — compile fires on the next macrotask. Set higher (e.g. 150) to
|
|
317
325
|
* coalesce rapid edits.
|
|
318
326
|
*/
|
|
319
|
-
|
|
327
|
+
debounceMs?: number;
|
|
320
328
|
/**
|
|
321
|
-
* Maximum time (ms)
|
|
322
|
-
*
|
|
323
|
-
* throttle — only debounce applies).
|
|
329
|
+
* Maximum time (ms) the debounce is allowed to defer a compile during
|
|
330
|
+
* sustained mutation bursts. Default: 0 (no cap — pure debounce).
|
|
324
331
|
*/
|
|
325
|
-
|
|
332
|
+
maxWaitMs?: number;
|
|
326
333
|
}
|
|
327
334
|
/**
|
|
328
335
|
* Coordinates a compiler + analyzer pair for multi-file Typst projects.
|
|
@@ -354,6 +361,7 @@ declare class TypstProject {
|
|
|
354
361
|
private _lastResult;
|
|
355
362
|
private _entry;
|
|
356
363
|
private destroyed;
|
|
364
|
+
private invokeListener;
|
|
357
365
|
constructor(options: TypstProjectOptions);
|
|
358
366
|
/**
|
|
359
367
|
* Schedule an auto-compile after VFS mutations. Coalesces rapid calls via
|
|
@@ -393,11 +401,16 @@ declare class TypstProject {
|
|
|
393
401
|
*/
|
|
394
402
|
setText(path: Path, content: string): Promise<void>;
|
|
395
403
|
/**
|
|
396
|
-
* Add or overwrite a JSON file.
|
|
397
|
-
*
|
|
404
|
+
* Add or overwrite a JSON file. The analyzer does not track data files, but
|
|
405
|
+
* if `path` was previously tracked as text the analyzer document is closed
|
|
406
|
+
* and the text entry retired so the three views stay consistent.
|
|
398
407
|
*/
|
|
399
408
|
setJson(path: Path, value: unknown): Promise<void>;
|
|
400
|
-
/**
|
|
409
|
+
/**
|
|
410
|
+
* Add or overwrite a binary file. If `path` was previously tracked as text,
|
|
411
|
+
* the analyzer document is closed and the text entry retired in the same
|
|
412
|
+
* call so the compiler / analyzer / project views stay consistent.
|
|
413
|
+
*/
|
|
401
414
|
setBinary(path: Path, content: ArrayBuffer | ArrayBufferView): Promise<void>;
|
|
402
415
|
/**
|
|
403
416
|
* Batch set multiple files. Strings route to both compiler and analyzer;
|
|
@@ -438,15 +451,15 @@ declare class TypstProject {
|
|
|
438
451
|
private requireAnalyzer;
|
|
439
452
|
/**
|
|
440
453
|
* Request completion for `path` at `position`, using `source` as the
|
|
441
|
-
* current document state.
|
|
442
|
-
*
|
|
454
|
+
* current document state. Pure analyzer query — neither the compiler VFS
|
|
455
|
+
* nor project tracking (`files`/`getText`) is touched. Throws when no
|
|
443
456
|
* analyzer is attached.
|
|
444
457
|
*/
|
|
445
458
|
completion(path: Path, source: string, position: LspPosition): Promise<LspCompletionResponse>;
|
|
446
459
|
/**
|
|
447
460
|
* Request hover for `path` at `position`, using `source` as the current
|
|
448
|
-
* document state.
|
|
449
|
-
* when no analyzer is attached.
|
|
461
|
+
* document state. Pure analyzer query — neither the compiler VFS nor
|
|
462
|
+
* project tracking is touched. Throws when no analyzer is attached.
|
|
450
463
|
*/
|
|
451
464
|
hover(path: Path, source: string, position: LspPosition): Promise<LspHover | null>;
|
|
452
465
|
/**
|
package/dist/index.js
CHANGED
|
@@ -43,12 +43,13 @@ var TypstAnalyzer = class _TypstAnalyzer {
|
|
|
43
43
|
return analyzer;
|
|
44
44
|
}
|
|
45
45
|
async didOpen(uri, content) {
|
|
46
|
-
this.content.set(uri, content);
|
|
47
46
|
await this.proxy.didOpen(uri, content);
|
|
47
|
+
this.content.set(uri, content);
|
|
48
48
|
}
|
|
49
49
|
async didClose(uri) {
|
|
50
|
-
if (!this.content.
|
|
50
|
+
if (!this.content.has(uri)) return;
|
|
51
51
|
await this.proxy.didClose(uri);
|
|
52
|
+
this.content.delete(uri);
|
|
52
53
|
}
|
|
53
54
|
/**
|
|
54
55
|
* Notify the analyzer that a document has changed. Skips the RPC when the
|
|
@@ -60,9 +61,9 @@ var TypstAnalyzer = class _TypstAnalyzer {
|
|
|
60
61
|
return;
|
|
61
62
|
}
|
|
62
63
|
if (this.content.get(uri) === content) return;
|
|
63
|
-
this.content.set(uri, content);
|
|
64
64
|
const version = ++this.versionCounter;
|
|
65
65
|
await this.proxy.didChange(uri, version, content);
|
|
66
|
+
this.content.set(uri, content);
|
|
66
67
|
}
|
|
67
68
|
/**
|
|
68
69
|
* Batch document changes. Splits inputs into opens (first-time URIs) and
|
|
@@ -72,17 +73,19 @@ var TypstAnalyzer = class _TypstAnalyzer {
|
|
|
72
73
|
async didChangeMany(docs) {
|
|
73
74
|
const opens = [];
|
|
74
75
|
const changes = [];
|
|
76
|
+
const updates = [];
|
|
75
77
|
for (const [uri, content] of Object.entries(docs)) {
|
|
76
78
|
if (!this.content.has(uri)) {
|
|
77
79
|
opens.push({ uri, content });
|
|
78
|
-
|
|
80
|
+
updates.push([uri, content]);
|
|
79
81
|
} else if (this.content.get(uri) !== content) {
|
|
80
82
|
changes.push({ uri, version: ++this.versionCounter, content });
|
|
81
|
-
|
|
83
|
+
updates.push([uri, content]);
|
|
82
84
|
}
|
|
83
85
|
}
|
|
84
86
|
if (opens.length === 0 && changes.length === 0) return;
|
|
85
87
|
await this.proxy.didChangeMany(opens, changes);
|
|
88
|
+
for (const [uri, content] of updates) this.content.set(uri, content);
|
|
86
89
|
}
|
|
87
90
|
/**
|
|
88
91
|
* Batch document closes. Filters to currently-open URIs and sends the set
|
|
@@ -91,10 +94,11 @@ var TypstAnalyzer = class _TypstAnalyzer {
|
|
|
91
94
|
async didCloseMany(uris) {
|
|
92
95
|
const toClose = [];
|
|
93
96
|
for (const uri of uris) {
|
|
94
|
-
if (this.content.
|
|
97
|
+
if (this.content.has(uri)) toClose.push(uri);
|
|
95
98
|
}
|
|
96
99
|
if (toClose.length === 0) return;
|
|
97
100
|
await this.proxy.didCloseMany(toClose);
|
|
101
|
+
for (const uri of toClose) this.content.delete(uri);
|
|
98
102
|
}
|
|
99
103
|
/**
|
|
100
104
|
* Request completion at `position` for `uri`, with `content` as the current
|
|
@@ -107,15 +111,16 @@ var TypstAnalyzer = class _TypstAnalyzer {
|
|
|
107
111
|
return this.proxy.completion(uri, position);
|
|
108
112
|
}
|
|
109
113
|
const isOpen = this.content.has(uri);
|
|
110
|
-
this.content.set(uri, content);
|
|
111
114
|
const version = ++this.versionCounter;
|
|
112
|
-
|
|
115
|
+
const result = await this.proxy.completionWithDoc(
|
|
113
116
|
uri,
|
|
114
117
|
version,
|
|
115
118
|
content,
|
|
116
119
|
position,
|
|
117
120
|
isOpen ? "change" : "open"
|
|
118
121
|
);
|
|
122
|
+
this.content.set(uri, content);
|
|
123
|
+
return result;
|
|
119
124
|
}
|
|
120
125
|
/**
|
|
121
126
|
* Request hover at `position` for `uri`, with `content` as the current
|
|
@@ -128,15 +133,16 @@ var TypstAnalyzer = class _TypstAnalyzer {
|
|
|
128
133
|
return this.proxy.hover(uri, position);
|
|
129
134
|
}
|
|
130
135
|
const isOpen = this.content.has(uri);
|
|
131
|
-
this.content.set(uri, content);
|
|
132
136
|
const version = ++this.versionCounter;
|
|
133
|
-
|
|
137
|
+
const result = await this.proxy.hoverWithDoc(
|
|
134
138
|
uri,
|
|
135
139
|
version,
|
|
136
140
|
content,
|
|
137
141
|
position,
|
|
138
142
|
isOpen ? "change" : "open"
|
|
139
143
|
);
|
|
144
|
+
this.content.set(uri, content);
|
|
145
|
+
return result;
|
|
140
146
|
}
|
|
141
147
|
destroy() {
|
|
142
148
|
this.proxy[Comlink.releaseProxy]();
|
|
@@ -162,7 +168,7 @@ import * as Comlink2 from "comlink";
|
|
|
162
168
|
var DEFAULT_FONTS = [
|
|
163
169
|
"https://cdn.jsdelivr.net/npm/roboto-font@0.1.0/fonts/Roboto/roboto-regular-webfont.ttf"
|
|
164
170
|
];
|
|
165
|
-
var
|
|
171
|
+
var defaultWasmUrl = () => `https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-web-compiler@${"0.7.0-rc2"}/pkg/typst_ts_web_compiler_bg.wasm`;
|
|
166
172
|
var TypstCompiler = class _TypstCompiler {
|
|
167
173
|
proxy;
|
|
168
174
|
worker;
|
|
@@ -177,7 +183,7 @@ var TypstCompiler = class _TypstCompiler {
|
|
|
177
183
|
const worker = options.worker ?? createWorker();
|
|
178
184
|
const proxy = Comlink2.wrap(worker);
|
|
179
185
|
await proxy.init(
|
|
180
|
-
options.wasmUrl ??
|
|
186
|
+
options.wasmUrl ?? defaultWasmUrl(),
|
|
181
187
|
options.fonts ?? DEFAULT_FONTS,
|
|
182
188
|
options.packages ?? true
|
|
183
189
|
);
|
|
@@ -205,8 +211,8 @@ var TypstCompiler = class _TypstCompiler {
|
|
|
205
211
|
*/
|
|
206
212
|
async setText(path, source) {
|
|
207
213
|
if (this.content.get(path) === source) return;
|
|
214
|
+
await this.proxy.mapShadow(path, this.encoder.encode(source));
|
|
208
215
|
this.content.set(path, source);
|
|
209
|
-
return this.proxy.mapShadow(path, this.encoder.encode(source));
|
|
210
216
|
}
|
|
211
217
|
/** Add or overwrite a JSON file in the virtual compiler filesystem. */
|
|
212
218
|
setJson(path, value, replacer, space) {
|
|
@@ -220,38 +226,42 @@ var TypstCompiler = class _TypstCompiler {
|
|
|
220
226
|
*/
|
|
221
227
|
async setMany(files) {
|
|
222
228
|
const encoded = {};
|
|
229
|
+
const textUpdates = [];
|
|
230
|
+
const binaryInvalidations = [];
|
|
223
231
|
for (const [path, content] of Object.entries(files)) {
|
|
224
232
|
if (typeof content === "string") {
|
|
225
233
|
if (this.content.get(path) === content) continue;
|
|
226
|
-
|
|
234
|
+
textUpdates.push([path, content]);
|
|
227
235
|
encoded[path] = this.encoder.encode(content);
|
|
228
236
|
} else {
|
|
229
|
-
|
|
237
|
+
binaryInvalidations.push(path);
|
|
230
238
|
encoded[path] = content;
|
|
231
239
|
}
|
|
232
240
|
}
|
|
233
241
|
if (Object.keys(encoded).length === 0) return;
|
|
234
|
-
|
|
242
|
+
await this.proxy.mapShadowMany(encoded);
|
|
243
|
+
for (const [path, content] of textUpdates) this.content.set(path, content);
|
|
244
|
+
for (const path of binaryInvalidations) this.content.delete(path);
|
|
235
245
|
}
|
|
236
246
|
/** Add or overwrite a binary file in the virtual compiler filesystem. */
|
|
237
|
-
setBinary(path, content) {
|
|
238
|
-
this.content.delete(path);
|
|
247
|
+
async setBinary(path, content) {
|
|
239
248
|
const bytes = content instanceof ArrayBuffer ? new Uint8Array(content) : new Uint8Array(
|
|
240
249
|
content.buffer,
|
|
241
250
|
content.byteOffset,
|
|
242
251
|
content.byteLength
|
|
243
252
|
);
|
|
244
|
-
|
|
253
|
+
await this.proxy.mapShadow(path, bytes);
|
|
254
|
+
this.content.delete(path);
|
|
245
255
|
}
|
|
246
256
|
/** Remove a file from the virtual compiler filesystem. */
|
|
247
|
-
remove(path) {
|
|
257
|
+
async remove(path) {
|
|
258
|
+
await this.proxy.unmapShadow(path);
|
|
248
259
|
this.content.delete(path);
|
|
249
|
-
return this.proxy.unmapShadow(path);
|
|
250
260
|
}
|
|
251
261
|
/** Clear all virtual files from the compiler filesystem. */
|
|
252
|
-
clear() {
|
|
262
|
+
async clear() {
|
|
263
|
+
await this.proxy.resetShadow();
|
|
253
264
|
this.content.clear();
|
|
254
|
-
return this.proxy.resetShadow();
|
|
255
265
|
}
|
|
256
266
|
destroy() {
|
|
257
267
|
this.proxy[Comlink2.releaseProxy]();
|
|
@@ -299,32 +309,28 @@ var CompileScheduler = class {
|
|
|
299
309
|
this.options = options;
|
|
300
310
|
}
|
|
301
311
|
debounceTimer = null;
|
|
302
|
-
|
|
303
|
-
lastFireTime = 0;
|
|
312
|
+
maxWaitTimer = null;
|
|
304
313
|
schedule(callback) {
|
|
305
314
|
if (this.debounceTimer) {
|
|
306
315
|
clearTimeout(this.debounceTimer);
|
|
307
316
|
this.debounceTimer = null;
|
|
308
317
|
}
|
|
309
|
-
const delay = Math.max(0, this.options.
|
|
318
|
+
const delay = Math.max(0, this.options.debounceMs ?? 0);
|
|
310
319
|
this.debounceTimer = setTimeout(() => {
|
|
311
320
|
this.debounceTimer = null;
|
|
312
|
-
this.
|
|
321
|
+
this.clearMaxWait();
|
|
322
|
+
callback();
|
|
313
323
|
}, delay);
|
|
314
|
-
const
|
|
315
|
-
if (
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
throttle - (performance.now() - this.lastFireTime)
|
|
319
|
-
);
|
|
320
|
-
this.throttleTimer = setTimeout(() => {
|
|
321
|
-
this.throttleTimer = null;
|
|
324
|
+
const maxWait = this.options.maxWaitMs;
|
|
325
|
+
if (maxWait != null && maxWait > 0 && !this.maxWaitTimer) {
|
|
326
|
+
this.maxWaitTimer = setTimeout(() => {
|
|
327
|
+
this.maxWaitTimer = null;
|
|
322
328
|
if (this.debounceTimer) {
|
|
323
329
|
clearTimeout(this.debounceTimer);
|
|
324
330
|
this.debounceTimer = null;
|
|
325
|
-
|
|
331
|
+
callback();
|
|
326
332
|
}
|
|
327
|
-
},
|
|
333
|
+
}, maxWait);
|
|
328
334
|
}
|
|
329
335
|
}
|
|
330
336
|
/** Cancel any pending scheduled fire without calling the callback. */
|
|
@@ -333,14 +339,13 @@ var CompileScheduler = class {
|
|
|
333
339
|
clearTimeout(this.debounceTimer);
|
|
334
340
|
this.debounceTimer = null;
|
|
335
341
|
}
|
|
336
|
-
|
|
337
|
-
clearTimeout(this.throttleTimer);
|
|
338
|
-
this.throttleTimer = null;
|
|
339
|
-
}
|
|
342
|
+
this.clearMaxWait();
|
|
340
343
|
}
|
|
341
|
-
|
|
342
|
-
this.
|
|
343
|
-
|
|
344
|
+
clearMaxWait() {
|
|
345
|
+
if (this.maxWaitTimer) {
|
|
346
|
+
clearTimeout(this.maxWaitTimer);
|
|
347
|
+
this.maxWaitTimer = null;
|
|
348
|
+
}
|
|
344
349
|
}
|
|
345
350
|
};
|
|
346
351
|
|
|
@@ -376,6 +381,13 @@ var TypstProject = class {
|
|
|
376
381
|
_lastResult;
|
|
377
382
|
_entry;
|
|
378
383
|
destroyed = false;
|
|
384
|
+
invokeListener(listener, result) {
|
|
385
|
+
try {
|
|
386
|
+
listener(result);
|
|
387
|
+
} catch (err) {
|
|
388
|
+
console.error("[typst] compile listener threw:", err);
|
|
389
|
+
}
|
|
390
|
+
}
|
|
379
391
|
constructor(options) {
|
|
380
392
|
this.compiler = options.compiler;
|
|
381
393
|
this.analyzer = options.analyzer;
|
|
@@ -384,8 +396,8 @@ var TypstProject = class {
|
|
|
384
396
|
);
|
|
385
397
|
this._entry = normalizePath(options.entry ?? DEFAULT_ENTRY);
|
|
386
398
|
this.scheduler = new CompileScheduler({
|
|
387
|
-
|
|
388
|
-
|
|
399
|
+
debounceMs: options.autoCompile?.debounceMs,
|
|
400
|
+
maxWaitMs: options.autoCompile?.maxWaitMs
|
|
389
401
|
});
|
|
390
402
|
}
|
|
391
403
|
/**
|
|
@@ -447,7 +459,6 @@ var TypstProject = class {
|
|
|
447
459
|
async setText(path, content) {
|
|
448
460
|
const p = normalizePath(path);
|
|
449
461
|
if (this.contentByPath.get(p) === content) return;
|
|
450
|
-
this.contentByPath.set(p, content);
|
|
451
462
|
await Promise.all([
|
|
452
463
|
this.compiler.setText(p, content),
|
|
453
464
|
this.analyzer?.didChange(
|
|
@@ -455,19 +466,37 @@ var TypstProject = class {
|
|
|
455
466
|
content
|
|
456
467
|
) ?? Promise.resolve()
|
|
457
468
|
]);
|
|
469
|
+
this.contentByPath.set(p, content);
|
|
458
470
|
this.scheduleCompile();
|
|
459
471
|
}
|
|
460
472
|
/**
|
|
461
|
-
* Add or overwrite a JSON file.
|
|
462
|
-
*
|
|
473
|
+
* Add or overwrite a JSON file. The analyzer does not track data files, but
|
|
474
|
+
* if `path` was previously tracked as text the analyzer document is closed
|
|
475
|
+
* and the text entry retired so the three views stay consistent.
|
|
463
476
|
*/
|
|
464
477
|
async setJson(path, value) {
|
|
465
|
-
|
|
478
|
+
const p = normalizePath(path);
|
|
479
|
+
const wasText = this.contentByPath.has(p);
|
|
480
|
+
await Promise.all([
|
|
481
|
+
this.compiler.setJson(p, value),
|
|
482
|
+
wasText ? this.analyzer?.didClose(pathToAnalyzerUri(p, this.analyzerUriRoot)) : void 0
|
|
483
|
+
]);
|
|
484
|
+
this.contentByPath.delete(p);
|
|
466
485
|
this.scheduleCompile();
|
|
467
486
|
}
|
|
468
|
-
/**
|
|
487
|
+
/**
|
|
488
|
+
* Add or overwrite a binary file. If `path` was previously tracked as text,
|
|
489
|
+
* the analyzer document is closed and the text entry retired in the same
|
|
490
|
+
* call so the compiler / analyzer / project views stay consistent.
|
|
491
|
+
*/
|
|
469
492
|
async setBinary(path, content) {
|
|
470
|
-
|
|
493
|
+
const p = normalizePath(path);
|
|
494
|
+
const wasText = this.contentByPath.has(p);
|
|
495
|
+
await Promise.all([
|
|
496
|
+
this.compiler.setBinary(p, content),
|
|
497
|
+
wasText ? this.analyzer?.didClose(pathToAnalyzerUri(p, this.analyzerUriRoot)) : void 0
|
|
498
|
+
]);
|
|
499
|
+
this.contentByPath.delete(p);
|
|
471
500
|
this.scheduleCompile();
|
|
472
501
|
}
|
|
473
502
|
/**
|
|
@@ -477,24 +506,37 @@ var TypstProject = class {
|
|
|
477
506
|
* always go through (no content cache, so no dedup).
|
|
478
507
|
*/
|
|
479
508
|
async setMany(files) {
|
|
509
|
+
const canonical = /* @__PURE__ */ new Map();
|
|
510
|
+
for (const [path, content] of Object.entries(files)) {
|
|
511
|
+
canonical.set(normalizePath(path), content);
|
|
512
|
+
}
|
|
480
513
|
const normalized = {};
|
|
481
514
|
const analyzerDocs = {};
|
|
482
|
-
|
|
483
|
-
|
|
515
|
+
const textUpdates = [];
|
|
516
|
+
const analyzerCloses = [];
|
|
517
|
+
const binaryRetirements = [];
|
|
518
|
+
for (const [p, content] of canonical) {
|
|
484
519
|
if (typeof content !== "string") {
|
|
485
520
|
normalized[p] = content;
|
|
521
|
+
if (this.contentByPath.has(p)) {
|
|
522
|
+
analyzerCloses.push(pathToAnalyzerUri(p, this.analyzerUriRoot));
|
|
523
|
+
binaryRetirements.push(p);
|
|
524
|
+
}
|
|
486
525
|
continue;
|
|
487
526
|
}
|
|
488
527
|
if (this.contentByPath.get(p) === content) continue;
|
|
489
|
-
|
|
528
|
+
textUpdates.push([p, content]);
|
|
490
529
|
normalized[p] = content;
|
|
491
530
|
analyzerDocs[pathToAnalyzerUri(p, this.analyzerUriRoot)] = content;
|
|
492
531
|
}
|
|
493
532
|
if (Object.keys(normalized).length === 0) return;
|
|
494
533
|
await Promise.all([
|
|
495
534
|
this.compiler.setMany(normalized),
|
|
496
|
-
this.analyzer?.didChangeMany(analyzerDocs) ?? Promise.resolve()
|
|
535
|
+
this.analyzer?.didChangeMany(analyzerDocs) ?? Promise.resolve(),
|
|
536
|
+
analyzerCloses.length > 0 ? this.analyzer?.didCloseMany(analyzerCloses) ?? Promise.resolve() : Promise.resolve()
|
|
497
537
|
]);
|
|
538
|
+
for (const [p, content] of textUpdates) this.contentByPath.set(p, content);
|
|
539
|
+
for (const p of binaryRetirements) this.contentByPath.delete(p);
|
|
498
540
|
this.scheduleCompile();
|
|
499
541
|
}
|
|
500
542
|
/**
|
|
@@ -503,11 +545,12 @@ var TypstProject = class {
|
|
|
503
545
|
*/
|
|
504
546
|
async remove(path) {
|
|
505
547
|
const p = normalizePath(path);
|
|
506
|
-
const wasText = this.contentByPath.
|
|
548
|
+
const wasText = this.contentByPath.has(p);
|
|
507
549
|
await Promise.all([
|
|
508
550
|
this.compiler.remove(p),
|
|
509
551
|
wasText ? this.analyzer?.didClose(pathToAnalyzerUri(p, this.analyzerUriRoot)) : void 0
|
|
510
552
|
]);
|
|
553
|
+
this.contentByPath.delete(p);
|
|
511
554
|
this.scheduleCompile();
|
|
512
555
|
}
|
|
513
556
|
/** Clear all files from both compiler VFS and analyzer document set. */
|
|
@@ -516,11 +559,11 @@ var TypstProject = class {
|
|
|
516
559
|
this.contentByPath.keys(),
|
|
517
560
|
(p) => pathToAnalyzerUri(p, this.analyzerUriRoot)
|
|
518
561
|
);
|
|
519
|
-
this.contentByPath.clear();
|
|
520
562
|
await Promise.all([
|
|
521
563
|
this.compiler.clear(),
|
|
522
564
|
uris.length > 0 ? this.analyzer?.didCloseMany(uris) : void 0
|
|
523
565
|
]);
|
|
566
|
+
this.contentByPath.clear();
|
|
524
567
|
this.scheduleCompile();
|
|
525
568
|
}
|
|
526
569
|
/**
|
|
@@ -533,11 +576,7 @@ var TypstProject = class {
|
|
|
533
576
|
onCompile(listener) {
|
|
534
577
|
this.compileListeners.add(listener);
|
|
535
578
|
if (this._lastResult !== void 0) {
|
|
536
|
-
|
|
537
|
-
listener(this._lastResult);
|
|
538
|
-
} catch (err) {
|
|
539
|
-
console.error("[typst] compile listener threw:", err);
|
|
540
|
-
}
|
|
579
|
+
this.invokeListener(listener, this._lastResult);
|
|
541
580
|
}
|
|
542
581
|
return () => {
|
|
543
582
|
this.compileListeners.delete(listener);
|
|
@@ -567,11 +606,7 @@ var TypstProject = class {
|
|
|
567
606
|
if (version === this.compileVersion) {
|
|
568
607
|
this._lastResult = result;
|
|
569
608
|
for (const listener of this.compileListeners) {
|
|
570
|
-
|
|
571
|
-
listener(result);
|
|
572
|
-
} catch (err) {
|
|
573
|
-
console.error("[typst] compile listener threw:", err);
|
|
574
|
-
}
|
|
609
|
+
this.invokeListener(listener, result);
|
|
575
610
|
}
|
|
576
611
|
}
|
|
577
612
|
return result;
|
|
@@ -588,31 +623,27 @@ var TypstProject = class {
|
|
|
588
623
|
}
|
|
589
624
|
/**
|
|
590
625
|
* Request completion for `path` at `position`, using `source` as the
|
|
591
|
-
* current document state.
|
|
592
|
-
*
|
|
626
|
+
* current document state. Pure analyzer query — neither the compiler VFS
|
|
627
|
+
* nor project tracking (`files`/`getText`) is touched. Throws when no
|
|
593
628
|
* analyzer is attached.
|
|
594
629
|
*/
|
|
595
630
|
completion(path, source, position) {
|
|
596
631
|
const analyzer = this.requireAnalyzer("completion");
|
|
597
|
-
const p = normalizePath(path);
|
|
598
|
-
this.contentByPath.set(p, source);
|
|
599
632
|
return analyzer.completion(
|
|
600
|
-
pathToAnalyzerUri(
|
|
633
|
+
pathToAnalyzerUri(normalizePath(path), this.analyzerUriRoot),
|
|
601
634
|
source,
|
|
602
635
|
position
|
|
603
636
|
);
|
|
604
637
|
}
|
|
605
638
|
/**
|
|
606
639
|
* Request hover for `path` at `position`, using `source` as the current
|
|
607
|
-
* document state.
|
|
608
|
-
* when no analyzer is attached.
|
|
640
|
+
* document state. Pure analyzer query — neither the compiler VFS nor
|
|
641
|
+
* project tracking is touched. Throws when no analyzer is attached.
|
|
609
642
|
*/
|
|
610
643
|
hover(path, source, position) {
|
|
611
644
|
const analyzer = this.requireAnalyzer("hover");
|
|
612
|
-
const p = normalizePath(path);
|
|
613
|
-
this.contentByPath.set(p, source);
|
|
614
645
|
return analyzer.hover(
|
|
615
|
-
pathToAnalyzerUri(
|
|
646
|
+
pathToAnalyzerUri(normalizePath(path), this.analyzerUriRoot),
|
|
616
647
|
source,
|
|
617
648
|
position
|
|
618
649
|
);
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/analyzer.ts","../src/rpc.ts","../src/identifiers.ts","../src/compiler.ts","../src/formatter.ts","../src/compile-scheduler.ts","../src/project.ts","../src/renderer.ts"],"sourcesContent":["import * as Comlink from \"comlink\";\nimport type {\n LspCompletionResponse,\n LspHover,\n LspPosition,\n} from \"./analyzer-types.js\";\nimport type { AnalyzerWorker } from \"./analyzer-worker.js\";\nimport { createAnalyzerWorker } from \"./rpc.js\";\n\nexport interface TypstAnalyzerOptions {\n /**\n * Explicit Worker instance. When omitted, an inlined blob worker is created automatically.\n * Use this for Vite apps:\n * `await TypstAnalyzer.create({ worker: new Worker(new URL('typst-web-service/analyzer-worker', import.meta.url), { type: 'module' }) })`\n */\n worker?: Worker;\n /**\n * URL to the tinymist WASM binary.\n * Required — there is no default CDN URL for tinymist-web.\n */\n wasmUrl: string;\n}\n\n/**\n * Manages a tinymist language server in a Web Worker. Provides LSP-based\n * completion and hover for Typst documents.\n *\n * const analyzer = await TypstAnalyzer.create({ wasmUrl: '...' });\n */\nexport class TypstAnalyzer {\n private readonly proxy: Comlink.Remote<AnalyzerWorker>;\n private readonly worker: Worker;\n private versionCounter = 0;\n /**\n * Last content pushed to the worker per URI. Presence is the source of\n * truth for \"is this URI opened on the worker?\"; value drives own-RPC dedup.\n */\n private readonly content = new Map<string, string>();\n\n private constructor(\n worker: Worker,\n proxy: Comlink.Remote<AnalyzerWorker>,\n ) {\n this.worker = worker;\n this.proxy = proxy;\n }\n\n static async create(options: TypstAnalyzerOptions): Promise<TypstAnalyzer> {\n const worker = options.worker ?? createAnalyzerWorker();\n const proxy = Comlink.wrap<AnalyzerWorker>(worker);\n const absoluteWasmUrl = new URL(options.wasmUrl, globalThis.location?.href)\n .href;\n\n const analyzer = new TypstAnalyzer(worker, proxy);\n\n await proxy.init(absoluteWasmUrl);\n\n return analyzer;\n }\n\n async didOpen(uri: string, content: string): Promise<void> {\n this.content.set(uri, content);\n await this.proxy.didOpen(uri, content);\n }\n\n async didClose(uri: string): Promise<void> {\n if (!this.content.delete(uri)) return;\n await this.proxy.didClose(uri);\n }\n\n /**\n * Notify the analyzer that a document has changed. Skips the RPC when the\n * content matches what the worker last saw.\n */\n async didChange(uri: string, content: string): Promise<void> {\n if (!this.content.has(uri)) {\n await this.didOpen(uri, content);\n return;\n }\n if (this.content.get(uri) === content) return;\n this.content.set(uri, content);\n const version = ++this.versionCounter;\n await this.proxy.didChange(uri, version, content);\n }\n\n /**\n * Batch document changes. Splits inputs into opens (first-time URIs) and\n * changes (already-open URIs) and sends them in a single worker roundtrip.\n * Skips unchanged documents; returns without an RPC if nothing is pending.\n */\n async didChangeMany(docs: Record<string, string>): Promise<void> {\n const opens: Array<{ uri: string; content: string }> = [];\n const changes: Array<{ uri: string; version: number; content: string }> =\n [];\n for (const [uri, content] of Object.entries(docs)) {\n if (!this.content.has(uri)) {\n opens.push({ uri, content });\n this.content.set(uri, content);\n } else if (this.content.get(uri) !== content) {\n changes.push({ uri, version: ++this.versionCounter, content });\n this.content.set(uri, content);\n }\n }\n if (opens.length === 0 && changes.length === 0) return;\n await this.proxy.didChangeMany(opens, changes);\n }\n\n /**\n * Batch document closes. Filters to currently-open URIs and sends the set\n * in a single worker roundtrip.\n */\n async didCloseMany(uris: string[]): Promise<void> {\n const toClose: string[] = [];\n for (const uri of uris) {\n if (this.content.delete(uri)) toClose.push(uri);\n }\n if (toClose.length === 0) return;\n await this.proxy.didCloseMany(toClose);\n }\n\n /**\n * Request completion at `position` for `uri`, with `content` as the current\n * document state. Bundles the didChange notification with the request in one\n * worker roundtrip; degrades to a plain completion request when the worker\n * already has this exact content.\n */\n async completion(\n uri: string,\n content: string,\n position: LspPosition,\n ): Promise<LspCompletionResponse> {\n if (this.content.get(uri) === content) {\n return this.proxy.completion(uri, position);\n }\n const isOpen = this.content.has(uri);\n this.content.set(uri, content);\n const version = ++this.versionCounter;\n return this.proxy.completionWithDoc(\n uri,\n version,\n content,\n position,\n isOpen ? \"change\" : \"open\",\n );\n }\n\n /**\n * Request hover at `position` for `uri`, with `content` as the current\n * document state. Bundles the didChange notification with the request in one\n * worker roundtrip; degrades to a plain hover request when the worker\n * already has this exact content.\n */\n async hover(\n uri: string,\n content: string,\n position: LspPosition,\n ): Promise<LspHover | null> {\n if (this.content.get(uri) === content) {\n return this.proxy.hover(uri, position);\n }\n const isOpen = this.content.has(uri);\n this.content.set(uri, content);\n const version = ++this.versionCounter;\n return this.proxy.hoverWithDoc(\n uri,\n version,\n content,\n position,\n isOpen ? \"change\" : \"open\",\n );\n }\n\n destroy(): void {\n this.proxy[Comlink.releaseProxy]();\n this.worker.terminate();\n }\n}\n","// Injected at build time by tsup (see tsup.config.ts)\ndeclare const __WORKER_CODE__: string;\ndeclare const __ANALYZER_WORKER_CODE__: string;\n\n/** Create a Worker from an inlined code string, auto-revoking the blob URL on terminate. */\nexport function createBlobWorker(code: string): Worker {\n const blob = new Blob([code], { type: \"application/javascript\" });\n const url = URL.createObjectURL(blob);\n const worker = new Worker(url);\n const origTerminate = worker.terminate.bind(worker);\n worker.terminate = () => {\n origTerminate();\n URL.revokeObjectURL(url);\n };\n return worker;\n}\n\n/** Create a blob Worker from the inlined compiler worker code. */\nexport function createWorker(): Worker {\n return createBlobWorker(__WORKER_CODE__);\n}\n\n/** Create a blob Worker from the inlined analyzer worker code. */\nexport function createAnalyzerWorker(): Worker {\n return createBlobWorker(__ANALYZER_WORKER_CODE__);\n}\n","/**\n * Two addressing schemes live in this codebase. This file is the only place\n * that knows how they relate. Keeping the vocabulary and conversions colocated\n * means a new contributor can read one file and understand the model.\n *\n * 1. Path — \"/main.typ\". Always leading-slash, always forward slashes.\n * Used by the compiler VFS, the `TypstProject` public API,\n * and the `typstFilePath` facet. Addresses a file within\n * the project.\n *\n * 2. AnalyzerUri — \"untitled:project/main.typ\". What tinymist's LSP expects.\n * Derived from a Path plus the analyzer URI root.\n *\n * The types below are type aliases, not branded/opaque types. That's\n * deliberate: callers can pass string literals where a Path is expected\n * without wrapping, and the aliases only serve as self-documenting\n * signatures. Ingress points still need to call `normalizePath` to defend\n * against un-normalized input — the alias does not imply the string has\n * been normalized.\n */\n\n/** `/path/to/file.typ` — leading-slash, forward slashes only. */\nexport type Path = string;\n\n/** `untitled:project/path/to/file.typ` — what tinymist's LSP consumes. */\nexport type AnalyzerUri = string;\n\n/** Ensure a path starts with a leading slash. Idempotent. */\nexport function normalizePath(path: string): Path {\n return path.startsWith(\"/\") ? path : `/${path}`;\n}\n\n/**\n * Normalize an analyzer URI root. Ensures leading slash, strips trailing\n * slashes. Special-cases \"/\" → \"\" so URIs don't end up with a leading\n * `untitled://`.\n */\nexport function normalizeRoot(rootPath: string): string {\n const root = normalizePath(rootPath);\n return root === \"/\" ? \"\" : root.replace(/\\/+$/, \"\");\n}\n\n/**\n * Build the analyzer URI for a given project path. `root` is expected to\n * already be normalized (see `normalizeRoot`).\n *\n * pathToAnalyzerUri(\"/main.typ\", \"/project\") -> \"untitled:project/main.typ\"\n */\nexport function pathToAnalyzerUri(path: Path, root: string): AnalyzerUri {\n const bare = root.replace(/^\\//, \"\");\n return `untitled:${bare}${normalizePath(path)}`;\n}\n","import * as Comlink from \"comlink\";\nimport { createWorker } from \"./rpc.js\";\nimport type { DiagnosticMessage } from \"./types.js\";\nimport type { CompilerWorker } from \"./compiler-worker.js\";\n\ndeclare const __TYPST_TS_WEB_COMPILER_VERSION__: string;\n\nexport interface CompileResult {\n diagnostics: DiagnosticMessage[];\n /** Vector artifact bytes from the compiler, usable with TypstRenderer for SVG rendering. */\n vector?: Uint8Array;\n}\n\nexport interface TypstCompilerOptions {\n /**\n * Explicit Worker instance. When omitted, an inlined blob worker is created automatically.\n * Use this for Vite apps to get proper source maps:\n * `await TypstCompiler.create({ worker: new Worker(new URL('typst-web-service/compiler-worker', import.meta.url)) })`\n */\n worker?: Worker;\n /**\n * URL to the typst-ts-web-compiler WASM binary.\n * Defaults to the matching version on jsDelivr CDN.\n * Override with a local asset URL for offline support or faster load:\n * `new URL('@myriaddreamin/typst-ts-web-compiler/pkg/typst_ts_web_compiler_bg.wasm', import.meta.url).href`\n */\n wasmUrl?: string;\n /** Font URLs to load into the Typst compiler. Defaults to Roboto from jsDelivr. */\n fonts?: string[];\n /**\n * Enable fetching @preview/ packages from packages.typst.org on demand.\n * Default: true.\n */\n packages?: boolean;\n}\n\nconst DEFAULT_FONTS = [\n \"https://cdn.jsdelivr.net/npm/roboto-font@0.1.0/fonts/Roboto/roboto-regular-webfont.ttf\",\n];\n\nconst DEFAULT_WASM_URL = `https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-web-compiler@${__TYPST_TS_WEB_COMPILER_VERSION__}/pkg/typst_ts_web_compiler_bg.wasm`;\n\n/**\n * Manages a Typst compiler worker. Create one instance and share it across\n * all extensions (linter, autocomplete, preview, etc.).\n *\n * await TypstCompiler.create() // blob worker, defaults\n * await TypstCompiler.create({ wasmUrl: '...' }) // blob worker, custom WASM\n * await TypstCompiler.create({ worker: myWorker }) // explicit Worker (Vite)\n * await TypstCompiler.create({ worker: myWorker, fonts: [...] }) // explicit Worker + options\n */\nexport class TypstCompiler {\n private readonly proxy: Comlink.Remote<CompilerWorker>;\n private readonly worker: Worker;\n private readonly encoder = new TextEncoder();\n /** Last text content pushed per path. Drives own-RPC dedup. Invalidated by binary writes. */\n private readonly content = new Map<string, string>();\n\n private constructor(\n worker: Worker,\n proxy: Comlink.Remote<CompilerWorker>,\n ) {\n this.worker = worker;\n this.proxy = proxy;\n }\n\n static async create(\n options: TypstCompilerOptions = {},\n ): Promise<TypstCompiler> {\n const worker = options.worker ?? createWorker();\n const proxy = Comlink.wrap<CompilerWorker>(worker);\n\n await proxy.init(\n options.wasmUrl ?? DEFAULT_WASM_URL,\n options.fonts ?? DEFAULT_FONTS,\n options.packages ?? true,\n );\n\n return new TypstCompiler(worker, proxy);\n }\n\n /**\n * Compile whatever is currently in the VFS (populated via\n * setText/setBinary/setJson/setMany). Defaults to compiling \"/main.typ\";\n * override with `entry`.\n */\n compile(entry?: string): Promise<CompileResult> {\n return this.proxy.compile(entry);\n }\n\n /**\n * Compile to PDF. Operates on whatever is currently in the VFS (populated\n * via setText/setBinary/setJson/setMany). Defaults to compiling \"/main.typ\";\n * override with `entry`.\n */\n compilePdf(entry?: string): Promise<Uint8Array> {\n return this.proxy.compilePdf(entry);\n }\n\n /**\n * Add or overwrite a text file in the virtual compiler filesystem. Skips\n * the worker RPC when `source` matches the last value pushed for `path`.\n */\n async setText(path: string, source: string): Promise<void> {\n if (this.content.get(path) === source) return;\n this.content.set(path, source);\n return this.proxy.mapShadow(path, this.encoder.encode(source));\n }\n\n /** Add or overwrite a JSON file in the virtual compiler filesystem. */\n setJson(\n path: string,\n value: unknown,\n replacer?: (this: unknown, key: string, value: unknown) => unknown,\n space?: string | number,\n ): Promise<void> {\n return this.setText(path, JSON.stringify(value, replacer, space));\n }\n\n /**\n * Add or overwrite multiple files in the virtual compiler filesystem in a\n * single worker roundtrip. Strings are UTF-8 encoded; Uint8Arrays are\n * passed through. Text entries unchanged since their last push are skipped;\n * binary entries always push and invalidate the text cache for their path.\n */\n async setMany(files: Record<string, string | Uint8Array>): Promise<void> {\n const encoded: Record<string, Uint8Array> = {};\n for (const [path, content] of Object.entries(files)) {\n if (typeof content === \"string\") {\n if (this.content.get(path) === content) continue;\n this.content.set(path, content);\n encoded[path] = this.encoder.encode(content);\n } else {\n this.content.delete(path);\n encoded[path] = content;\n }\n }\n if (Object.keys(encoded).length === 0) return;\n return this.proxy.mapShadowMany(encoded);\n }\n\n /** Add or overwrite a binary file in the virtual compiler filesystem. */\n setBinary(\n path: string,\n content: ArrayBuffer | ArrayBufferView,\n ): Promise<void> {\n this.content.delete(path);\n const bytes =\n content instanceof ArrayBuffer\n ? new Uint8Array(content)\n : new Uint8Array(\n content.buffer,\n content.byteOffset,\n content.byteLength,\n );\n return this.proxy.mapShadow(path, bytes);\n }\n\n /** Remove a file from the virtual compiler filesystem. */\n remove(path: string): Promise<void> {\n this.content.delete(path);\n return this.proxy.unmapShadow(path);\n }\n\n /** Clear all virtual files from the compiler filesystem. */\n clear(): Promise<void> {\n this.content.clear();\n return this.proxy.resetShadow();\n }\n\n destroy(): void {\n this.proxy[Comlink.releaseProxy]();\n this.worker.terminate();\n }\n}\n","export interface FormatConfig {\n /** Number of spaces per indentation level. Default: 2 */\n tab_spaces?: number;\n /** Maximum line width. Default: 80 */\n max_width?: number;\n /** Maximum consecutive blank lines allowed. */\n blank_lines_upper_bound?: number;\n /** Collapse consecutive whitespace in markup to a single space. */\n collapse_markup_spaces?: boolean;\n /** Sort import items alphabetically. */\n reorder_import_items?: boolean;\n /** Wrap text in markup to fit within max_width. Implies collapse_markup_spaces. */\n wrap_text?: boolean;\n}\n\nexport interface FormatRangeResult {\n /** Start index (UTF-16) of the actual formatted range. */\n start: number;\n /** End index (UTF-16) of the actual formatted range. */\n end: number;\n /** The formatted text for the range. */\n text: string;\n}\n\ntype TypstyleModule = typeof import(\"@typstyle/typstyle-wasm-bundler\");\n\nlet typstylePromise: Promise<TypstyleModule> | null = null;\n\nfunction getTypstyle(): Promise<TypstyleModule> {\n if (!typstylePromise) {\n typstylePromise = import(\"@typstyle/typstyle-wasm-bundler\").catch((err) => {\n typstylePromise = null;\n throw err;\n });\n }\n return typstylePromise;\n}\n\n/**\n * Typst code formatter powered by typstyle.\n *\n * Runs on the main thread — typstyle is lightweight and fast.\n * The WASM module is loaded lazily on first format call.\n * Requires a bundler that supports WASM imports (e.g. Vite, webpack).\n *\n * const formatter = TypstFormatter.create({ tab_spaces: 2, max_width: 80 });\n * const formatted = await formatter.format(source);\n */\nexport class TypstFormatter {\n private config: FormatConfig;\n\n private constructor(config: FormatConfig = {}) {\n this.config = config;\n // Eagerly start loading WASM so it's ready by first use.\n // Swallow preload errors — they'll surface on first format() call.\n getTypstyle().catch(() => {});\n }\n\n static create(config: FormatConfig = {}): TypstFormatter {\n return new TypstFormatter(config);\n }\n\n /** Format an entire Typst source string. */\n async format(source: string): Promise<string> {\n const typstyle = await getTypstyle();\n return typstyle.format(source, this.config);\n }\n\n /** Format a range within a Typst source string. Indices are UTF-16 code units. */\n async formatRange(\n source: string,\n start: number,\n end: number,\n ): Promise<FormatRangeResult> {\n const typstyle = await getTypstyle();\n const result = typstyle.format_range(source, start, end, this.config);\n return { start: result.start, end: result.end, text: result.text };\n }\n}\n","export interface CompileSchedulerOptions {\n /** Minimum idle time (ms) after the last request before firing. Default: 0. */\n debounceDelay?: number;\n /**\n * Maximum time (ms) between fires during continuous requests. Guarantees\n * a run at least this often so users see progress while typing. Default: 0\n * (no throttle).\n */\n throttleDelay?: number;\n}\n\n/**\n * Debounce + throttle helper for coalescing compile requests. A burst of\n * `schedule(cb)` calls within `debounceDelay` collapses into one fire; during\n * sustained bursts, `throttleDelay` guarantees a fire no less often than that.\n */\nexport class CompileScheduler {\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private throttleTimer: ReturnType<typeof setTimeout> | null = null;\n private lastFireTime = 0;\n\n constructor(private readonly options: CompileSchedulerOptions = {}) {}\n\n schedule(callback: () => void): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n\n const delay = Math.max(0, this.options.debounceDelay ?? 0);\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null;\n this.fire(callback);\n }, delay);\n\n const throttle = this.options.throttleDelay;\n if (throttle != null && throttle > 0 && !this.throttleTimer) {\n const wait = Math.max(\n 0,\n throttle - (performance.now() - this.lastFireTime),\n );\n this.throttleTimer = setTimeout(() => {\n this.throttleTimer = null;\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n this.fire(callback);\n }\n }, wait);\n }\n }\n\n /** Cancel any pending scheduled fire without calling the callback. */\n cancel(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n if (this.throttleTimer) {\n clearTimeout(this.throttleTimer);\n this.throttleTimer = null;\n }\n }\n\n private fire(callback: () => void): void {\n this.lastFireTime = performance.now();\n callback();\n }\n}\n","import type { TypstAnalyzer } from \"./analyzer.js\";\nimport type {\n LspCompletionResponse,\n LspHover,\n LspPosition,\n} from \"./analyzer-types.js\";\nimport { CompileScheduler } from \"./compile-scheduler.js\";\nimport type { CompileResult, TypstCompiler } from \"./compiler.js\";\nimport {\n normalizePath,\n normalizeRoot,\n type Path,\n pathToAnalyzerUri,\n} from \"./identifiers.js\";\n\nexport interface TypstProjectOptions {\n compiler: TypstCompiler;\n /**\n * Optional analyzer. When provided, text file operations also sync with the\n * analyzer so completions / hover reflect the current state.\n */\n analyzer?: TypstAnalyzer;\n /** Default entry file path. Default: \"/main.typ\". */\n entry?: string;\n /**\n * Prefix used to build the `untitled:` URIs handed to the analyzer.\n * Default: \"/project\". A path of `/main.typ` becomes\n * `untitled:project/main.typ`. Only affects URI construction — the compiler\n * and project VFS use the raw paths unchanged.\n */\n analyzerUriRoot?: string;\n /**\n * Idle time (ms) after the last VFS mutation before an auto-compile fires.\n * Default: 0 — compile fires on the next macrotask. Set higher (e.g. 150) to\n * coalesce rapid edits.\n */\n compileDebounceMs?: number;\n /**\n * Maximum time (ms) between auto-compiles during sustained mutation bursts.\n * Guarantees progress while the user is actively typing. Default: 0 (no\n * throttle — only debounce applies).\n */\n compileThrottleMs?: number;\n}\n\nconst DEFAULT_ENTRY = \"/main.typ\";\nconst DEFAULT_ROOT = \"/project\";\n\n/**\n * Coordinates a compiler + analyzer pair for multi-file Typst projects.\n *\n * Owns the project's virtual filesystem state. Editors push incremental\n * `setText` updates as the user types; the project mirrors those edits to\n * both the compiler's shadow VFS and the analyzer's open-document set, then\n * compiles or services LSP requests against the current state.\n *\n * const project = new TypstProject({ compiler, analyzer });\n * await project.setMany({ \"/main.typ\": \"...\", \"/utils.typ\": \"...\" });\n * const result = await project.compile();\n */\nexport type CompileListener = (result: CompileResult) => void;\n\nfunction errorAsCompileResult(\n err: unknown,\n paths: readonly string[],\n): CompileResult {\n const message = err instanceof Error ? err.message : String(err);\n return {\n diagnostics: paths.map((path) => ({\n package: \"\",\n path,\n severity: \"Error\",\n range: { startLine: 0, startCol: 0, endLine: 0, endCol: 1 },\n message,\n })),\n };\n}\n\nexport class TypstProject {\n private readonly compiler: TypstCompiler;\n private readonly analyzer?: TypstAnalyzer;\n private readonly analyzerUriRoot: string;\n /**\n * Tracked text files: path → latest content observed. Presence in this map\n * is the source of truth for \"is this a tracked text file?\"; insertion\n * order drives the `files` getter. Per-sink dedup lives in the compiler and\n * analyzer.\n */\n private readonly contentByPath = new Map<Path, string>();\n private readonly compileListeners = new Set<CompileListener>();\n private readonly scheduler: CompileScheduler;\n private compileVersion = 0;\n private _lastResult: CompileResult | undefined;\n private _entry: Path;\n private destroyed = false;\n\n constructor(options: TypstProjectOptions) {\n this.compiler = options.compiler;\n this.analyzer = options.analyzer;\n this.analyzerUriRoot = normalizeRoot(\n options.analyzerUriRoot ?? DEFAULT_ROOT,\n );\n this._entry = normalizePath(options.entry ?? DEFAULT_ENTRY);\n this.scheduler = new CompileScheduler({\n debounceDelay: options.compileDebounceMs,\n throttleDelay: options.compileThrottleMs,\n });\n }\n\n /**\n * Schedule an auto-compile after VFS mutations. Coalesces rapid calls via\n * the configured debounce/throttle. Errors surface through `onCompile`\n * listeners via a synthetic diagnostic; callers awaiting a specific compile\n * should call `compile()` directly.\n */\n private scheduleCompile(): void {\n if (this.destroyed) return;\n this.scheduler.schedule(() => {\n this.compile().catch((err) => console.error(\"[typst]\", err));\n });\n }\n\n /** Current entry file path. Assign to change the sticky entry used by subsequent `compile()` calls. */\n get entry(): Path {\n return this._entry;\n }\n\n set entry(path: Path) {\n const next = normalizePath(path);\n if (next === this._entry) return;\n this._entry = next;\n this.scheduleCompile();\n }\n\n /** Whether an analyzer is attached. */\n get hasAnalyzer(): boolean {\n return this.analyzer !== undefined;\n }\n\n /**\n * Most recent compile result, or `undefined` before the first compile has\n * settled. Useful for lazy-mounted UI that subscribes after boot and needs\n * an initial value.\n */\n get lastResult(): CompileResult | undefined {\n return this._lastResult;\n }\n\n /**\n * Snapshot of tracked text file paths, in insertion order. Updated by\n * `setText`, `setMany`, `remove`, and `clear`. Returns a fresh array — mutate\n * freely without affecting project state.\n */\n get files(): Path[] {\n return [...this.contentByPath.keys()];\n }\n\n /**\n * Current text content for a tracked file, or `undefined` if the path was\n * never written via `setText`/`setMany` (or was removed). Read-through to the\n * project's sync cache — lets consumers avoid shadowing the VFS themselves.\n */\n getText(path: Path): string | undefined {\n return this.contentByPath.get(normalizePath(path));\n }\n\n /**\n * Add or overwrite a text file. Goes to the compiler's VFS and, when an\n * analyzer is attached, to the analyzer as a document change. No-op when\n * the tracked path already has this exact content — skips both worker RPCs\n * and the auto-scheduled compile.\n */\n async setText(path: Path, content: string): Promise<void> {\n const p = normalizePath(path);\n if (this.contentByPath.get(p) === content) return;\n this.contentByPath.set(p, content);\n await Promise.all([\n this.compiler.setText(p, content),\n this.analyzer?.didChange(\n pathToAnalyzerUri(p, this.analyzerUriRoot),\n content,\n ) ?? Promise.resolve(),\n ]);\n this.scheduleCompile();\n }\n\n /**\n * Add or overwrite a JSON file. Compiler-only — the analyzer does not track\n * data files.\n */\n async setJson(path: Path, value: unknown): Promise<void> {\n await this.compiler.setJson(normalizePath(path), value);\n this.scheduleCompile();\n }\n\n /** Add or overwrite a binary file. Compiler-only. */\n async setBinary(\n path: Path,\n content: ArrayBuffer | ArrayBufferView,\n ): Promise<void> {\n await this.compiler.setBinary(normalizePath(path), content);\n this.scheduleCompile();\n }\n\n /**\n * Batch set multiple files. Strings route to both compiler and analyzer;\n * Uint8Array entries go to the compiler only. Strings matching the last\n * tracked content for their path are skipped on both sinks. Binary entries\n * always go through (no content cache, so no dedup).\n */\n async setMany(files: Record<Path, string | Uint8Array>): Promise<void> {\n const normalized: Record<Path, string | Uint8Array> = {};\n const analyzerDocs: Record<string, string> = {};\n for (const [path, content] of Object.entries(files)) {\n const p = normalizePath(path);\n if (typeof content !== \"string\") {\n normalized[p] = content;\n continue;\n }\n if (this.contentByPath.get(p) === content) continue;\n this.contentByPath.set(p, content);\n normalized[p] = content;\n analyzerDocs[pathToAnalyzerUri(p, this.analyzerUriRoot)] = content;\n }\n if (Object.keys(normalized).length === 0) return;\n await Promise.all([\n this.compiler.setMany(normalized),\n this.analyzer?.didChangeMany(analyzerDocs) ?? Promise.resolve(),\n ]);\n this.scheduleCompile();\n }\n\n /**\n * Remove a file. Always removed from the compiler's VFS; also closed on the\n * analyzer when it was previously tracked as text.\n */\n async remove(path: Path): Promise<void> {\n const p = normalizePath(path);\n const wasText = this.contentByPath.delete(p);\n await Promise.all([\n this.compiler.remove(p),\n wasText\n ? this.analyzer?.didClose(pathToAnalyzerUri(p, this.analyzerUriRoot))\n : undefined,\n ]);\n this.scheduleCompile();\n }\n\n /** Clear all files from both compiler VFS and analyzer document set. */\n async clear(): Promise<void> {\n const uris = Array.from(this.contentByPath.keys(), (p) =>\n pathToAnalyzerUri(p, this.analyzerUriRoot),\n );\n this.contentByPath.clear();\n await Promise.all([\n this.compiler.clear(),\n uris.length > 0 ? this.analyzer?.didCloseMany(uris) : undefined,\n ]);\n this.scheduleCompile();\n }\n\n /**\n * Subscribe to compile results. Fires after every `compile()` whose result is\n * still current (stale results from out-of-order concurrent compiles are\n * dropped). If a compile has already settled, the most recent result is\n * delivered synchronously so late-mounted listeners aren't stuck blank until\n * the next compile. Returns an unsubscribe function.\n */\n onCompile(listener: CompileListener): () => void {\n this.compileListeners.add(listener);\n if (this._lastResult !== undefined) {\n try {\n listener(this._lastResult);\n } catch (err) {\n console.error(\"[typst] compile listener threw:\", err);\n }\n }\n return () => {\n this.compileListeners.delete(listener);\n };\n }\n\n /**\n * Compile the current VFS state using the sticky entry. Errors from the\n * underlying compiler are converted into a synthetic error diagnostic so\n * callers and listeners always receive a `CompileResult`. Listeners are\n * notified only for the most recent compile — results from an earlier call\n * that resolves after a later one are suppressed.\n *\n * VFS mutations (`setText`, `remove`, etc.) auto-schedule a debounced\n * compile; call this directly only when you need an awaitable handle on the\n * result (e.g., to flush before rendering to PDF).\n */\n async compile(): Promise<CompileResult> {\n this.scheduler.cancel();\n const version = ++this.compileVersion;\n let result: CompileResult;\n try {\n result = await this.compiler.compile(this._entry);\n } catch (err) {\n // Spread the synthetic error across every tracked text path so the\n // diagnostic is visible no matter which file the user is viewing.\n // Falls back to the entry if nothing is tracked yet.\n const paths =\n this.contentByPath.size > 0\n ? [...this.contentByPath.keys()]\n : [this._entry];\n result = errorAsCompileResult(err, paths);\n }\n if (version === this.compileVersion) {\n this._lastResult = result;\n for (const listener of this.compileListeners) {\n try {\n listener(result);\n } catch (err) {\n console.error(\"[typst] compile listener threw:\", err);\n }\n }\n }\n return result;\n }\n\n /** Compile the current VFS state to PDF using the sticky entry. */\n compilePdf(): Promise<Uint8Array> {\n return this.compiler.compilePdf(this._entry);\n }\n\n private requireAnalyzer(operation: string): TypstAnalyzer {\n if (!this.analyzer) {\n throw new Error(`TypstProject: ${operation} requires an analyzer`);\n }\n return this.analyzer;\n }\n\n /**\n * Request completion for `path` at `position`, using `source` as the\n * current document state. One analyzer roundtrip; compiler is not touched —\n * the compile sync path writes to the compiler separately. Throws when no\n * analyzer is attached.\n */\n completion(\n path: Path,\n source: string,\n position: LspPosition,\n ): Promise<LspCompletionResponse> {\n const analyzer = this.requireAnalyzer(\"completion\");\n const p = normalizePath(path);\n this.contentByPath.set(p, source);\n return analyzer.completion(\n pathToAnalyzerUri(p, this.analyzerUriRoot),\n source,\n position,\n );\n }\n\n /**\n * Request hover for `path` at `position`, using `source` as the current\n * document state. One analyzer roundtrip; compiler is not touched. Throws\n * when no analyzer is attached.\n */\n hover(\n path: Path,\n source: string,\n position: LspPosition,\n ): Promise<LspHover | null> {\n const analyzer = this.requireAnalyzer(\"hover\");\n const p = normalizePath(path);\n this.contentByPath.set(p, source);\n return analyzer.hover(\n pathToAnalyzerUri(p, this.analyzerUriRoot),\n source,\n position,\n );\n }\n\n /**\n * Tear down the project and the services it owns. Destroys the attached\n * compiler and analyzer, drops all listeners, and clears VFS tracking state.\n * Idempotent — calling twice is a no-op. After destruction, further calls on\n * the project are not supported; construct a new one.\n *\n * If you need to share a compiler or analyzer across projects, destroy them\n * yourself and don't call this method — the project does not provide an\n * ownership toggle.\n */\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.scheduler.cancel();\n this.compileListeners.clear();\n this.contentByPath.clear();\n this._lastResult = undefined;\n this.compiler.destroy();\n this.analyzer?.destroy();\n }\n}\n","/** Minimal interface for the built TypstRenderer instance. */\nexport interface RendererInstance {\n free(): void;\n create_session(): RendererSession;\n manipulate_data(\n session: RendererSession,\n action: string,\n data: Uint8Array,\n ): void;\n svg_data(session: RendererSession): string;\n}\n\n/** Minimal interface for a TypstRenderer session. */\nexport interface RendererSession {\n free(): void;\n}\n\ntype RendererWasmModule = typeof import(\"@myriaddreamin/typst-ts-renderer\");\n\ndeclare const __TYPST_TS_RENDERER_VERSION__: string;\n\nconst DEFAULT_RENDERER_WASM_URL = `https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-renderer@${__TYPST_TS_RENDERER_VERSION__}/pkg/typst_ts_renderer_bg.wasm`;\n\nlet rendererModulePromise: Promise<RendererWasmModule> | null = null;\n\nfunction getRendererModule(): Promise<RendererWasmModule> {\n if (!rendererModulePromise) {\n rendererModulePromise = import(\"@myriaddreamin/typst-ts-renderer\").catch(\n (err) => {\n rendererModulePromise = null;\n throw err;\n },\n );\n }\n return rendererModulePromise;\n}\n\nexport interface TypstRendererOptions {\n /** URL to the typst-ts-renderer WASM binary. Defaults to jsDelivr CDN. */\n wasmUrl?: string;\n}\n\nexport interface RenderedSvgPage {\n /** Zero-based page index within the document. */\n index: number;\n /** Page width in typographic points. */\n width: number;\n /** Page height in typographic points. */\n height: number;\n /** Standalone SVG string for just this page. */\n svg: string;\n}\n\n/**\n * Converts Typst vector artifacts to SVG strings.\n *\n * The renderer WASM module is loaded lazily on first use.\n *\n * const renderer = TypstRenderer.create();\n * const svg = await renderer.renderSvg(vector);\n */\nexport class TypstRenderer {\n private wasmUrl: string;\n private instance: Promise<RendererInstance> | null = null;\n\n private constructor(options: TypstRendererOptions = {}) {\n this.wasmUrl = options.wasmUrl ?? DEFAULT_RENDERER_WASM_URL;\n // Eagerly start loading the WASM module so it's ready by first use.\n getRendererModule().catch(() => {});\n }\n\n static create(options: TypstRendererOptions = {}): TypstRenderer {\n return new TypstRenderer(options);\n }\n\n private getInstance(): Promise<RendererInstance> {\n if (!this.instance) {\n this.instance = this.#init().catch((err) => {\n this.instance = null;\n throw err;\n });\n }\n return this.instance;\n }\n\n async #init(): Promise<RendererInstance> {\n const mod = await getRendererModule();\n await mod.default({ module_or_path: this.wasmUrl });\n return new mod.TypstRendererBuilder().build();\n }\n\n /** Free the underlying WASM renderer instance. */\n async destroy(): Promise<void> {\n const instance = this.instance;\n this.instance = null;\n if (instance) {\n (await instance).free();\n }\n }\n\n /** Render a Typst vector artifact to an SVG string. */\n async renderSvg(vector: Uint8Array): Promise<string> {\n const renderer = await this.getInstance();\n const session = renderer.create_session();\n try {\n renderer.manipulate_data(session, \"reset\", vector);\n return renderer.svg_data(session);\n } finally {\n session.free();\n }\n }\n\n /**\n * Render a Typst vector artifact into one self-contained SVG string per\n * physical page. The merged SVG is split by `<g class=\"typst-page\">`\n * children; each group's `data-page-width` / `data-page-height` give the\n * page-local viewBox. Shared `<defs>` / `<style>` are duplicated into each\n * page so the output SVGs render independently. Returns an empty array if\n * the document has no page groups.\n */\n async renderSvgPages(vector: Uint8Array): Promise<RenderedSvgPage[]> {\n return splitMergedSvgPages(await this.renderSvg(vector));\n }\n}\n\n// Parsing must use \"text/html\", not \"image/svg+xml\": Typst's merged SVG\n// output has repeatedly failed XML-strict parsing. HTML mode tolerates it\n// and still produces real SVGSVGElement nodes for inline SVG.\nfunction splitMergedSvgPages(svg: string): RenderedSvgPage[] {\n const doc = new DOMParser().parseFromString(svg, \"text/html\");\n const root = doc.querySelector(\"svg\");\n if (!root) return [];\n\n const children = Array.from(root.children);\n const pageGroups = children.filter(\n (el) =>\n el.tagName.toLowerCase() === \"g\" && el.classList.contains(\"typst-page\"),\n );\n if (pageGroups.length === 0) return [];\n\n const sharedHtml = children\n .filter((el) => !el.classList.contains(\"typst-page\"))\n .map((el) => el.outerHTML)\n .join(\"\");\n\n const namespaceAttrs = Array.from(root.attributes)\n .filter((attr) => attr.name === \"xmlns\" || attr.name.startsWith(\"xmlns:\"))\n .map((attr) => `${attr.name}=\"${attr.value}\"`)\n .join(\" \");\n\n return pageGroups.flatMap((group, index) => {\n const width = Number(group.getAttribute(\"data-page-width\")) || 0;\n const height = Number(group.getAttribute(\"data-page-height\")) || 0;\n if (width <= 0 || height <= 0) return [];\n\n const clone = group.cloneNode(true) as Element;\n clone.removeAttribute(\"transform\");\n\n return [\n {\n index,\n width,\n height,\n svg:\n `<svg ${namespaceAttrs} viewBox=\"0 0 ${width} ${height}\" ` +\n `width=\"${width}\" height=\"${height}\">` +\n `${sharedHtml}${clone.outerHTML}</svg>`,\n },\n ];\n });\n}\n"],"mappings":"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","names":["Comlink"]}
|
|
1
|
+
{"version":3,"sources":["../src/analyzer.ts","../src/rpc.ts","../src/identifiers.ts","../src/compiler.ts","../src/formatter.ts","../src/compile-scheduler.ts","../src/project.ts","../src/renderer.ts"],"sourcesContent":["import * as Comlink from \"comlink\";\nimport type {\n LspCompletionResponse,\n LspHover,\n LspPosition,\n} from \"./analyzer-types.js\";\nimport type { AnalyzerWorker } from \"./analyzer-worker.js\";\nimport { createAnalyzerWorker } from \"./rpc.js\";\n\nexport interface TypstAnalyzerOptions {\n /**\n * Explicit Worker instance. When omitted, an inlined blob worker is created automatically.\n * Use this for Vite apps:\n * `await TypstAnalyzer.create({ worker: new Worker(new URL('typst-web-service/analyzer-worker', import.meta.url), { type: 'module' }) })`\n */\n worker?: Worker;\n /**\n * URL to the tinymist WASM binary.\n * Required — there is no default CDN URL for tinymist-web.\n */\n wasmUrl: string;\n}\n\n/**\n * Manages a tinymist language server in a Web Worker. Provides LSP-based\n * completion and hover for Typst documents.\n *\n * const analyzer = await TypstAnalyzer.create({ wasmUrl: '...' });\n */\nexport class TypstAnalyzer {\n private readonly proxy: Comlink.Remote<AnalyzerWorker>;\n private readonly worker: Worker;\n private versionCounter = 0;\n /**\n * Last content pushed to the worker per URI. Presence is the source of\n * truth for \"is this URI opened on the worker?\"; value drives own-RPC dedup.\n */\n private readonly content = new Map<string, string>();\n\n private constructor(worker: Worker, proxy: Comlink.Remote<AnalyzerWorker>) {\n this.worker = worker;\n this.proxy = proxy;\n }\n\n static async create(options: TypstAnalyzerOptions): Promise<TypstAnalyzer> {\n const worker = options.worker ?? createAnalyzerWorker();\n const proxy = Comlink.wrap<AnalyzerWorker>(worker);\n const absoluteWasmUrl = new URL(options.wasmUrl, globalThis.location?.href)\n .href;\n\n const analyzer = new TypstAnalyzer(worker, proxy);\n\n await proxy.init(absoluteWasmUrl);\n\n return analyzer;\n }\n\n async didOpen(uri: string, content: string): Promise<void> {\n await this.proxy.didOpen(uri, content);\n this.content.set(uri, content);\n }\n\n async didClose(uri: string): Promise<void> {\n if (!this.content.has(uri)) return;\n await this.proxy.didClose(uri);\n this.content.delete(uri);\n }\n\n /**\n * Notify the analyzer that a document has changed. Skips the RPC when the\n * content matches what the worker last saw.\n */\n async didChange(uri: string, content: string): Promise<void> {\n if (!this.content.has(uri)) {\n await this.didOpen(uri, content);\n return;\n }\n if (this.content.get(uri) === content) return;\n const version = ++this.versionCounter;\n await this.proxy.didChange(uri, version, content);\n this.content.set(uri, content);\n }\n\n /**\n * Batch document changes. Splits inputs into opens (first-time URIs) and\n * changes (already-open URIs) and sends them in a single worker roundtrip.\n * Skips unchanged documents; returns without an RPC if nothing is pending.\n */\n async didChangeMany(docs: Record<string, string>): Promise<void> {\n const opens: Array<{ uri: string; content: string }> = [];\n const changes: Array<{ uri: string; version: number; content: string }> =\n [];\n const updates: Array<[string, string]> = [];\n for (const [uri, content] of Object.entries(docs)) {\n if (!this.content.has(uri)) {\n opens.push({ uri, content });\n updates.push([uri, content]);\n } else if (this.content.get(uri) !== content) {\n changes.push({ uri, version: ++this.versionCounter, content });\n updates.push([uri, content]);\n }\n }\n if (opens.length === 0 && changes.length === 0) return;\n await this.proxy.didChangeMany(opens, changes);\n for (const [uri, content] of updates) this.content.set(uri, content);\n }\n\n /**\n * Batch document closes. Filters to currently-open URIs and sends the set\n * in a single worker roundtrip.\n */\n async didCloseMany(uris: string[]): Promise<void> {\n const toClose: string[] = [];\n for (const uri of uris) {\n if (this.content.has(uri)) toClose.push(uri);\n }\n if (toClose.length === 0) return;\n await this.proxy.didCloseMany(toClose);\n for (const uri of toClose) this.content.delete(uri);\n }\n\n /**\n * Request completion at `position` for `uri`, with `content` as the current\n * document state. Bundles the didChange notification with the request in one\n * worker roundtrip; degrades to a plain completion request when the worker\n * already has this exact content.\n */\n async completion(\n uri: string,\n content: string,\n position: LspPosition,\n ): Promise<LspCompletionResponse> {\n if (this.content.get(uri) === content) {\n return this.proxy.completion(uri, position);\n }\n const isOpen = this.content.has(uri);\n const version = ++this.versionCounter;\n const result = await this.proxy.completionWithDoc(\n uri,\n version,\n content,\n position,\n isOpen ? \"change\" : \"open\",\n );\n this.content.set(uri, content);\n return result;\n }\n\n /**\n * Request hover at `position` for `uri`, with `content` as the current\n * document state. Bundles the didChange notification with the request in one\n * worker roundtrip; degrades to a plain hover request when the worker\n * already has this exact content.\n */\n async hover(\n uri: string,\n content: string,\n position: LspPosition,\n ): Promise<LspHover | null> {\n if (this.content.get(uri) === content) {\n return this.proxy.hover(uri, position);\n }\n const isOpen = this.content.has(uri);\n const version = ++this.versionCounter;\n const result = await this.proxy.hoverWithDoc(\n uri,\n version,\n content,\n position,\n isOpen ? \"change\" : \"open\",\n );\n this.content.set(uri, content);\n return result;\n }\n\n destroy(): void {\n this.proxy[Comlink.releaseProxy]();\n this.worker.terminate();\n }\n}\n","// Injected at build time by tsup (see tsup.config.ts)\ndeclare const __WORKER_CODE__: string;\ndeclare const __ANALYZER_WORKER_CODE__: string;\n\n/** Create a Worker from an inlined code string, auto-revoking the blob URL on terminate. */\nfunction createBlobWorker(code: string): Worker {\n const blob = new Blob([code], { type: \"application/javascript\" });\n const url = URL.createObjectURL(blob);\n const worker = new Worker(url);\n const origTerminate = worker.terminate.bind(worker);\n worker.terminate = () => {\n origTerminate();\n URL.revokeObjectURL(url);\n };\n return worker;\n}\n\n/** Create a blob Worker from the inlined compiler worker code. */\nexport function createWorker(): Worker {\n return createBlobWorker(__WORKER_CODE__);\n}\n\n/** Create a blob Worker from the inlined analyzer worker code. */\nexport function createAnalyzerWorker(): Worker {\n return createBlobWorker(__ANALYZER_WORKER_CODE__);\n}\n","/**\n * Two addressing schemes live in this codebase. This file is the only place\n * that knows how they relate. Keeping the vocabulary and conversions colocated\n * means a new contributor can read one file and understand the model.\n *\n * 1. Path — \"/main.typ\". Always leading-slash, always forward slashes.\n * Used by the compiler VFS, the `TypstProject` public API,\n * and the `typstFilePath` facet. Addresses a file within\n * the project.\n *\n * 2. AnalyzerUri — \"untitled:project/main.typ\". What tinymist's LSP expects.\n * Derived from a Path plus the analyzer URI root.\n *\n * The types below are type aliases, not branded/opaque types. That's\n * deliberate: callers can pass string literals where a Path is expected\n * without wrapping, and the aliases only serve as self-documenting\n * signatures. Ingress points still need to call `normalizePath` to defend\n * against un-normalized input — the alias does not imply the string has\n * been normalized.\n */\n\n/** `/path/to/file.typ` — leading-slash, forward slashes only. */\nexport type Path = string;\n\n/** `untitled:project/path/to/file.typ` — what tinymist's LSP consumes. */\nexport type AnalyzerUri = string;\n\n/** Ensure a path starts with a leading slash. Idempotent. */\nexport function normalizePath(path: string): Path {\n return path.startsWith(\"/\") ? path : `/${path}`;\n}\n\n/**\n * Normalize an analyzer URI root. Ensures leading slash, strips trailing\n * slashes. Special-cases \"/\" → \"\" so URIs don't end up with a leading\n * `untitled://`.\n */\nexport function normalizeRoot(rootPath: string): string {\n const root = normalizePath(rootPath);\n return root === \"/\" ? \"\" : root.replace(/\\/+$/, \"\");\n}\n\n/**\n * Build the analyzer URI for a given project path. `root` is expected to\n * already be normalized (see `normalizeRoot`).\n *\n * pathToAnalyzerUri(\"/main.typ\", \"/project\") -> \"untitled:project/main.typ\"\n */\nexport function pathToAnalyzerUri(path: Path, root: string): AnalyzerUri {\n const bare = root.replace(/^\\//, \"\");\n return `untitled:${bare}${normalizePath(path)}`;\n}\n","import * as Comlink from \"comlink\";\nimport { createWorker } from \"./rpc.js\";\nimport type { DiagnosticMessage } from \"./types.js\";\nimport type { CompilerWorker } from \"./compiler-worker.js\";\n\ndeclare const __TYPST_TS_WEB_COMPILER_VERSION__: string;\n\nexport interface CompileResult {\n diagnostics: DiagnosticMessage[];\n /** Vector artifact bytes from the compiler, usable with TypstRenderer for SVG rendering. */\n vector?: Uint8Array;\n}\n\nexport interface TypstCompilerOptions {\n /**\n * Explicit Worker instance. When omitted, an inlined blob worker is created automatically.\n * Use this for Vite apps to get proper source maps:\n * `await TypstCompiler.create({ worker: new Worker(new URL('typst-web-service/compiler-worker', import.meta.url)) })`\n */\n worker?: Worker;\n /**\n * URL to the typst-ts-web-compiler WASM binary.\n * Defaults to the matching version on jsDelivr CDN.\n * Override with a local asset URL for offline support or faster load:\n * `new URL('@myriaddreamin/typst-ts-web-compiler/pkg/typst_ts_web_compiler_bg.wasm', import.meta.url).href`\n */\n wasmUrl?: string;\n /** Font URLs to load into the Typst compiler. Defaults to Roboto from jsDelivr. */\n fonts?: string[];\n /**\n * Enable fetching @preview/ packages from packages.typst.org on demand.\n * Default: true.\n */\n packages?: boolean;\n}\n\nconst DEFAULT_FONTS = [\n \"https://cdn.jsdelivr.net/npm/roboto-font@0.1.0/fonts/Roboto/roboto-regular-webfont.ttf\",\n];\n\nconst defaultWasmUrl = () =>\n `https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-web-compiler@${__TYPST_TS_WEB_COMPILER_VERSION__}/pkg/typst_ts_web_compiler_bg.wasm`;\n\n/**\n * Manages a Typst compiler worker. Create one instance and share it across\n * all extensions (linter, autocomplete, preview, etc.).\n *\n * await TypstCompiler.create() // blob worker, defaults\n * await TypstCompiler.create({ wasmUrl: '...' }) // blob worker, custom WASM\n * await TypstCompiler.create({ worker: myWorker }) // explicit Worker (Vite)\n * await TypstCompiler.create({ worker: myWorker, fonts: [...] }) // explicit Worker + options\n */\nexport class TypstCompiler {\n private readonly proxy: Comlink.Remote<CompilerWorker>;\n private readonly worker: Worker;\n private readonly encoder = new TextEncoder();\n /** Last text content pushed per path. Drives own-RPC dedup. Invalidated by binary writes. */\n private readonly content = new Map<string, string>();\n\n private constructor(worker: Worker, proxy: Comlink.Remote<CompilerWorker>) {\n this.worker = worker;\n this.proxy = proxy;\n }\n\n static async create(\n options: TypstCompilerOptions = {},\n ): Promise<TypstCompiler> {\n const worker = options.worker ?? createWorker();\n const proxy = Comlink.wrap<CompilerWorker>(worker);\n\n await proxy.init(\n options.wasmUrl ?? defaultWasmUrl(),\n options.fonts ?? DEFAULT_FONTS,\n options.packages ?? true,\n );\n\n return new TypstCompiler(worker, proxy);\n }\n\n /**\n * Compile whatever is currently in the VFS (populated via\n * setText/setBinary/setJson/setMany). Defaults to compiling \"/main.typ\";\n * override with `entry`.\n */\n compile(entry?: string): Promise<CompileResult> {\n return this.proxy.compile(entry);\n }\n\n /**\n * Compile to PDF. Operates on whatever is currently in the VFS (populated\n * via setText/setBinary/setJson/setMany). Defaults to compiling \"/main.typ\";\n * override with `entry`.\n */\n compilePdf(entry?: string): Promise<Uint8Array> {\n return this.proxy.compilePdf(entry);\n }\n\n /**\n * Add or overwrite a text file in the virtual compiler filesystem. Skips\n * the worker RPC when `source` matches the last value pushed for `path`.\n */\n async setText(path: string, source: string): Promise<void> {\n if (this.content.get(path) === source) return;\n await this.proxy.mapShadow(path, this.encoder.encode(source));\n this.content.set(path, source);\n }\n\n /** Add or overwrite a JSON file in the virtual compiler filesystem. */\n setJson(\n path: string,\n value: unknown,\n replacer?: (this: unknown, key: string, value: unknown) => unknown,\n space?: string | number,\n ): Promise<void> {\n return this.setText(path, JSON.stringify(value, replacer, space));\n }\n\n /**\n * Add or overwrite multiple files in the virtual compiler filesystem in a\n * single worker roundtrip. Strings are UTF-8 encoded; Uint8Arrays are\n * passed through. Text entries unchanged since their last push are skipped;\n * binary entries always push and invalidate the text cache for their path.\n */\n async setMany(files: Record<string, string | Uint8Array>): Promise<void> {\n const encoded: Record<string, Uint8Array> = {};\n const textUpdates: Array<[string, string]> = [];\n const binaryInvalidations: string[] = [];\n for (const [path, content] of Object.entries(files)) {\n if (typeof content === \"string\") {\n if (this.content.get(path) === content) continue;\n textUpdates.push([path, content]);\n encoded[path] = this.encoder.encode(content);\n } else {\n binaryInvalidations.push(path);\n encoded[path] = content;\n }\n }\n if (Object.keys(encoded).length === 0) return;\n await this.proxy.mapShadowMany(encoded);\n for (const [path, content] of textUpdates) this.content.set(path, content);\n for (const path of binaryInvalidations) this.content.delete(path);\n }\n\n /** Add or overwrite a binary file in the virtual compiler filesystem. */\n async setBinary(\n path: string,\n content: ArrayBuffer | ArrayBufferView,\n ): Promise<void> {\n const bytes =\n content instanceof ArrayBuffer\n ? new Uint8Array(content)\n : new Uint8Array(\n content.buffer,\n content.byteOffset,\n content.byteLength,\n );\n await this.proxy.mapShadow(path, bytes);\n this.content.delete(path);\n }\n\n /** Remove a file from the virtual compiler filesystem. */\n async remove(path: string): Promise<void> {\n await this.proxy.unmapShadow(path);\n this.content.delete(path);\n }\n\n /** Clear all virtual files from the compiler filesystem. */\n async clear(): Promise<void> {\n await this.proxy.resetShadow();\n this.content.clear();\n }\n\n destroy(): void {\n this.proxy[Comlink.releaseProxy]();\n this.worker.terminate();\n }\n}\n","export interface FormatConfig {\n /** Number of spaces per indentation level. Default: 2 */\n tab_spaces?: number;\n /** Maximum line width. Default: 80 */\n max_width?: number;\n /** Maximum consecutive blank lines allowed. */\n blank_lines_upper_bound?: number;\n /** Collapse consecutive whitespace in markup to a single space. */\n collapse_markup_spaces?: boolean;\n /** Sort import items alphabetically. */\n reorder_import_items?: boolean;\n /** Wrap text in markup to fit within max_width. Implies collapse_markup_spaces. */\n wrap_text?: boolean;\n}\n\nexport interface FormatRangeResult {\n /** Start index (UTF-16) of the actual formatted range. */\n start: number;\n /** End index (UTF-16) of the actual formatted range. */\n end: number;\n /** The formatted text for the range. */\n text: string;\n}\n\ntype TypstyleModule = typeof import(\"@typstyle/typstyle-wasm-bundler\");\n\nlet typstylePromise: Promise<TypstyleModule> | null = null;\n\nfunction getTypstyle(): Promise<TypstyleModule> {\n if (!typstylePromise) {\n typstylePromise = import(\"@typstyle/typstyle-wasm-bundler\").catch((err) => {\n typstylePromise = null;\n throw err;\n });\n }\n return typstylePromise;\n}\n\n/**\n * Typst code formatter powered by typstyle.\n *\n * Runs on the main thread — typstyle is lightweight and fast.\n * The WASM module is loaded lazily on first format call.\n * Requires a bundler that supports WASM imports (e.g. Vite, webpack).\n *\n * const formatter = TypstFormatter.create({ tab_spaces: 2, max_width: 80 });\n * const formatted = await formatter.format(source);\n */\nexport class TypstFormatter {\n private config: FormatConfig;\n\n private constructor(config: FormatConfig = {}) {\n this.config = config;\n // Eagerly start loading WASM so it's ready by first use.\n // Swallow preload errors — they'll surface on first format() call.\n getTypstyle().catch(() => {});\n }\n\n static create(config: FormatConfig = {}): TypstFormatter {\n return new TypstFormatter(config);\n }\n\n /** Format an entire Typst source string. */\n async format(source: string): Promise<string> {\n const typstyle = await getTypstyle();\n return typstyle.format(source, this.config);\n }\n\n /** Format a range within a Typst source string. Indices are UTF-16 code units. */\n async formatRange(\n source: string,\n start: number,\n end: number,\n ): Promise<FormatRangeResult> {\n const typstyle = await getTypstyle();\n const result = typstyle.format_range(source, start, end, this.config);\n return { start: result.start, end: result.end, text: result.text };\n }\n}\n","interface CompileSchedulerOptions {\n /** Minimum idle time (ms) after the last request before firing. Default: 0. */\n debounceMs?: number;\n /**\n * Maximum time (ms) the debounce may keep deferring during continuous\n * requests. Guarantees a fire at least this often so users see progress\n * while typing. Default: 0 (no cap).\n */\n maxWaitMs?: number;\n}\n\n/**\n * Debounce helper with a max-wait ceiling for coalescing compile requests. A\n * burst of `schedule(cb)` calls within `debounceMs` collapses into one fire;\n * during sustained bursts, `maxWaitMs` caps how long the debounce may keep\n * deferring.\n */\nexport class CompileScheduler {\n private debounceTimer: ReturnType<typeof setTimeout> | null = null;\n private maxWaitTimer: ReturnType<typeof setTimeout> | null = null;\n\n constructor(private readonly options: CompileSchedulerOptions = {}) {}\n\n schedule(callback: () => void): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n\n const delay = Math.max(0, this.options.debounceMs ?? 0);\n this.debounceTimer = setTimeout(() => {\n this.debounceTimer = null;\n this.clearMaxWait();\n callback();\n }, delay);\n\n const maxWait = this.options.maxWaitMs;\n if (maxWait != null && maxWait > 0 && !this.maxWaitTimer) {\n this.maxWaitTimer = setTimeout(() => {\n this.maxWaitTimer = null;\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n callback();\n }\n }, maxWait);\n }\n }\n\n /** Cancel any pending scheduled fire without calling the callback. */\n cancel(): void {\n if (this.debounceTimer) {\n clearTimeout(this.debounceTimer);\n this.debounceTimer = null;\n }\n this.clearMaxWait();\n }\n\n private clearMaxWait(): void {\n if (this.maxWaitTimer) {\n clearTimeout(this.maxWaitTimer);\n this.maxWaitTimer = null;\n }\n }\n}\n","import type { TypstAnalyzer } from \"./analyzer.js\";\nimport type {\n LspCompletionResponse,\n LspHover,\n LspPosition,\n} from \"./analyzer-types.js\";\nimport { CompileScheduler } from \"./compile-scheduler.js\";\nimport type { CompileResult, TypstCompiler } from \"./compiler.js\";\nimport {\n normalizePath,\n normalizeRoot,\n type Path,\n pathToAnalyzerUri,\n} from \"./identifiers.js\";\n\nexport interface TypstProjectOptions {\n compiler: TypstCompiler;\n /**\n * Optional analyzer. When provided, text file operations also sync with the\n * analyzer so completions / hover reflect the current state.\n */\n analyzer?: TypstAnalyzer;\n /** Default entry file path. Default: \"/main.typ\". */\n entry?: string;\n /**\n * Prefix used to build the `untitled:` URIs handed to the analyzer.\n * Default: \"/project\". A path of `/main.typ` becomes\n * `untitled:project/main.typ`. Only affects URI construction — the compiler\n * and project VFS use the raw paths unchanged.\n */\n analyzerUriRoot?: string;\n /**\n * Scheduling for auto-compiles after VFS mutations. Mutations debounce by\n * `debounceMs`; `maxWaitMs` caps how long the debounce can keep deferring\n * during sustained edits so the user still sees progress.\n */\n autoCompile?: AutoCompileOptions;\n}\n\nexport interface AutoCompileOptions {\n /**\n * Idle time (ms) after the last VFS mutation before a compile fires.\n * Default: 0 — compile fires on the next macrotask. Set higher (e.g. 150) to\n * coalesce rapid edits.\n */\n debounceMs?: number;\n /**\n * Maximum time (ms) the debounce is allowed to defer a compile during\n * sustained mutation bursts. Default: 0 (no cap — pure debounce).\n */\n maxWaitMs?: number;\n}\n\nconst DEFAULT_ENTRY = \"/main.typ\";\nconst DEFAULT_ROOT = \"/project\";\n\n/**\n * Coordinates a compiler + analyzer pair for multi-file Typst projects.\n *\n * Owns the project's virtual filesystem state. Editors push incremental\n * `setText` updates as the user types; the project mirrors those edits to\n * both the compiler's shadow VFS and the analyzer's open-document set, then\n * compiles or services LSP requests against the current state.\n *\n * const project = new TypstProject({ compiler, analyzer });\n * await project.setMany({ \"/main.typ\": \"...\", \"/utils.typ\": \"...\" });\n * const result = await project.compile();\n */\nexport type CompileListener = (result: CompileResult) => void;\n\nfunction errorAsCompileResult(\n err: unknown,\n paths: readonly string[],\n): CompileResult {\n const message = err instanceof Error ? err.message : String(err);\n return {\n diagnostics: paths.map((path) => ({\n package: \"\",\n path,\n severity: \"Error\",\n range: { startLine: 0, startCol: 0, endLine: 0, endCol: 1 },\n message,\n })),\n };\n}\n\nexport class TypstProject {\n private readonly compiler: TypstCompiler;\n private readonly analyzer?: TypstAnalyzer;\n private readonly analyzerUriRoot: string;\n /**\n * Tracked text files: path → latest content observed. Presence in this map\n * is the source of truth for \"is this a tracked text file?\"; insertion\n * order drives the `files` getter. Per-sink dedup lives in the compiler and\n * analyzer.\n */\n private readonly contentByPath = new Map<Path, string>();\n private readonly compileListeners = new Set<CompileListener>();\n private readonly scheduler: CompileScheduler;\n private compileVersion = 0;\n private _lastResult: CompileResult | undefined;\n private _entry: Path;\n private destroyed = false;\n\n private invokeListener(\n listener: CompileListener,\n result: CompileResult,\n ): void {\n try {\n listener(result);\n } catch (err) {\n console.error(\"[typst] compile listener threw:\", err);\n }\n }\n\n constructor(options: TypstProjectOptions) {\n this.compiler = options.compiler;\n this.analyzer = options.analyzer;\n this.analyzerUriRoot = normalizeRoot(\n options.analyzerUriRoot ?? DEFAULT_ROOT,\n );\n this._entry = normalizePath(options.entry ?? DEFAULT_ENTRY);\n this.scheduler = new CompileScheduler({\n debounceMs: options.autoCompile?.debounceMs,\n maxWaitMs: options.autoCompile?.maxWaitMs,\n });\n }\n\n /**\n * Schedule an auto-compile after VFS mutations. Coalesces rapid calls via\n * the configured debounce/throttle. Errors surface through `onCompile`\n * listeners via a synthetic diagnostic; callers awaiting a specific compile\n * should call `compile()` directly.\n */\n private scheduleCompile(): void {\n if (this.destroyed) return;\n this.scheduler.schedule(() => {\n this.compile().catch((err) => console.error(\"[typst]\", err));\n });\n }\n\n /** Current entry file path. Assign to change the sticky entry used by subsequent `compile()` calls. */\n get entry(): Path {\n return this._entry;\n }\n\n set entry(path: Path) {\n const next = normalizePath(path);\n if (next === this._entry) return;\n this._entry = next;\n this.scheduleCompile();\n }\n\n /** Whether an analyzer is attached. */\n get hasAnalyzer(): boolean {\n return this.analyzer !== undefined;\n }\n\n /**\n * Most recent compile result, or `undefined` before the first compile has\n * settled. Useful for lazy-mounted UI that subscribes after boot and needs\n * an initial value.\n */\n get lastResult(): CompileResult | undefined {\n return this._lastResult;\n }\n\n /**\n * Snapshot of tracked text file paths, in insertion order. Updated by\n * `setText`, `setMany`, `remove`, and `clear`. Returns a fresh array — mutate\n * freely without affecting project state.\n */\n get files(): Path[] {\n return [...this.contentByPath.keys()];\n }\n\n /**\n * Current text content for a tracked file, or `undefined` if the path was\n * never written via `setText`/`setMany` (or was removed). Read-through to the\n * project's sync cache — lets consumers avoid shadowing the VFS themselves.\n */\n getText(path: Path): string | undefined {\n return this.contentByPath.get(normalizePath(path));\n }\n\n /**\n * Add or overwrite a text file. Goes to the compiler's VFS and, when an\n * analyzer is attached, to the analyzer as a document change. No-op when\n * the tracked path already has this exact content — skips both worker RPCs\n * and the auto-scheduled compile.\n */\n async setText(path: Path, content: string): Promise<void> {\n const p = normalizePath(path);\n if (this.contentByPath.get(p) === content) return;\n await Promise.all([\n this.compiler.setText(p, content),\n this.analyzer?.didChange(\n pathToAnalyzerUri(p, this.analyzerUriRoot),\n content,\n ) ?? Promise.resolve(),\n ]);\n this.contentByPath.set(p, content);\n this.scheduleCompile();\n }\n\n /**\n * Add or overwrite a JSON file. The analyzer does not track data files, but\n * if `path` was previously tracked as text the analyzer document is closed\n * and the text entry retired so the three views stay consistent.\n */\n async setJson(path: Path, value: unknown): Promise<void> {\n const p = normalizePath(path);\n const wasText = this.contentByPath.has(p);\n await Promise.all([\n this.compiler.setJson(p, value),\n wasText\n ? this.analyzer?.didClose(pathToAnalyzerUri(p, this.analyzerUriRoot))\n : undefined,\n ]);\n this.contentByPath.delete(p);\n this.scheduleCompile();\n }\n\n /**\n * Add or overwrite a binary file. If `path` was previously tracked as text,\n * the analyzer document is closed and the text entry retired in the same\n * call so the compiler / analyzer / project views stay consistent.\n */\n async setBinary(\n path: Path,\n content: ArrayBuffer | ArrayBufferView,\n ): Promise<void> {\n const p = normalizePath(path);\n const wasText = this.contentByPath.has(p);\n await Promise.all([\n this.compiler.setBinary(p, content),\n wasText\n ? this.analyzer?.didClose(pathToAnalyzerUri(p, this.analyzerUriRoot))\n : undefined,\n ]);\n this.contentByPath.delete(p);\n this.scheduleCompile();\n }\n\n /**\n * Batch set multiple files. Strings route to both compiler and analyzer;\n * Uint8Array entries go to the compiler only. Strings matching the last\n * tracked content for their path are skipped on both sinks. Binary entries\n * always go through (no content cache, so no dedup).\n */\n async setMany(files: Record<Path, string | Uint8Array>): Promise<void> {\n const canonical = new Map<Path, string | Uint8Array>();\n for (const [path, content] of Object.entries(files)) {\n canonical.set(normalizePath(path), content);\n }\n\n const normalized: Record<Path, string | Uint8Array> = {};\n const analyzerDocs: Record<string, string> = {};\n const textUpdates: Array<[Path, string]> = [];\n const analyzerCloses: string[] = [];\n const binaryRetirements: Path[] = [];\n for (const [p, content] of canonical) {\n if (typeof content !== \"string\") {\n normalized[p] = content;\n if (this.contentByPath.has(p)) {\n analyzerCloses.push(pathToAnalyzerUri(p, this.analyzerUriRoot));\n binaryRetirements.push(p);\n }\n continue;\n }\n if (this.contentByPath.get(p) === content) continue;\n textUpdates.push([p, content]);\n normalized[p] = content;\n analyzerDocs[pathToAnalyzerUri(p, this.analyzerUriRoot)] = content;\n }\n if (Object.keys(normalized).length === 0) return;\n await Promise.all([\n this.compiler.setMany(normalized),\n this.analyzer?.didChangeMany(analyzerDocs) ?? Promise.resolve(),\n analyzerCloses.length > 0\n ? (this.analyzer?.didCloseMany(analyzerCloses) ?? Promise.resolve())\n : Promise.resolve(),\n ]);\n for (const [p, content] of textUpdates) this.contentByPath.set(p, content);\n for (const p of binaryRetirements) this.contentByPath.delete(p);\n this.scheduleCompile();\n }\n\n /**\n * Remove a file. Always removed from the compiler's VFS; also closed on the\n * analyzer when it was previously tracked as text.\n */\n async remove(path: Path): Promise<void> {\n const p = normalizePath(path);\n const wasText = this.contentByPath.has(p);\n await Promise.all([\n this.compiler.remove(p),\n wasText\n ? this.analyzer?.didClose(pathToAnalyzerUri(p, this.analyzerUriRoot))\n : undefined,\n ]);\n this.contentByPath.delete(p);\n this.scheduleCompile();\n }\n\n /** Clear all files from both compiler VFS and analyzer document set. */\n async clear(): Promise<void> {\n const uris = Array.from(this.contentByPath.keys(), (p) =>\n pathToAnalyzerUri(p, this.analyzerUriRoot),\n );\n await Promise.all([\n this.compiler.clear(),\n uris.length > 0 ? this.analyzer?.didCloseMany(uris) : undefined,\n ]);\n this.contentByPath.clear();\n this.scheduleCompile();\n }\n\n /**\n * Subscribe to compile results. Fires after every `compile()` whose result is\n * still current (stale results from out-of-order concurrent compiles are\n * dropped). If a compile has already settled, the most recent result is\n * delivered synchronously so late-mounted listeners aren't stuck blank until\n * the next compile. Returns an unsubscribe function.\n */\n onCompile(listener: CompileListener): () => void {\n this.compileListeners.add(listener);\n if (this._lastResult !== undefined) {\n this.invokeListener(listener, this._lastResult);\n }\n return () => {\n this.compileListeners.delete(listener);\n };\n }\n\n /**\n * Compile the current VFS state using the sticky entry. Errors from the\n * underlying compiler are converted into a synthetic error diagnostic so\n * callers and listeners always receive a `CompileResult`. Listeners are\n * notified only for the most recent compile — results from an earlier call\n * that resolves after a later one are suppressed.\n *\n * VFS mutations (`setText`, `remove`, etc.) auto-schedule a debounced\n * compile; call this directly only when you need an awaitable handle on the\n * result (e.g., to flush before rendering to PDF).\n */\n async compile(): Promise<CompileResult> {\n this.scheduler.cancel();\n const version = ++this.compileVersion;\n let result: CompileResult;\n try {\n result = await this.compiler.compile(this._entry);\n } catch (err) {\n // Spread the synthetic error across every tracked text path so the\n // diagnostic is visible no matter which file the user is viewing.\n // Falls back to the entry if nothing is tracked yet.\n const paths =\n this.contentByPath.size > 0\n ? [...this.contentByPath.keys()]\n : [this._entry];\n result = errorAsCompileResult(err, paths);\n }\n if (version === this.compileVersion) {\n this._lastResult = result;\n for (const listener of this.compileListeners) {\n this.invokeListener(listener, result);\n }\n }\n return result;\n }\n\n /** Compile the current VFS state to PDF using the sticky entry. */\n compilePdf(): Promise<Uint8Array> {\n return this.compiler.compilePdf(this._entry);\n }\n\n private requireAnalyzer(operation: string): TypstAnalyzer {\n if (!this.analyzer) {\n throw new Error(`TypstProject: ${operation} requires an analyzer`);\n }\n return this.analyzer;\n }\n\n /**\n * Request completion for `path` at `position`, using `source` as the\n * current document state. Pure analyzer query — neither the compiler VFS\n * nor project tracking (`files`/`getText`) is touched. Throws when no\n * analyzer is attached.\n */\n completion(\n path: Path,\n source: string,\n position: LspPosition,\n ): Promise<LspCompletionResponse> {\n const analyzer = this.requireAnalyzer(\"completion\");\n return analyzer.completion(\n pathToAnalyzerUri(normalizePath(path), this.analyzerUriRoot),\n source,\n position,\n );\n }\n\n /**\n * Request hover for `path` at `position`, using `source` as the current\n * document state. Pure analyzer query — neither the compiler VFS nor\n * project tracking is touched. Throws when no analyzer is attached.\n */\n hover(\n path: Path,\n source: string,\n position: LspPosition,\n ): Promise<LspHover | null> {\n const analyzer = this.requireAnalyzer(\"hover\");\n return analyzer.hover(\n pathToAnalyzerUri(normalizePath(path), this.analyzerUriRoot),\n source,\n position,\n );\n }\n\n /**\n * Tear down the project and the services it owns. Destroys the attached\n * compiler and analyzer, drops all listeners, and clears VFS tracking state.\n * Idempotent — calling twice is a no-op. After destruction, further calls on\n * the project are not supported; construct a new one.\n *\n * If you need to share a compiler or analyzer across projects, destroy them\n * yourself and don't call this method — the project does not provide an\n * ownership toggle.\n */\n destroy(): void {\n if (this.destroyed) return;\n this.destroyed = true;\n this.scheduler.cancel();\n this.compileListeners.clear();\n this.contentByPath.clear();\n this._lastResult = undefined;\n this.compiler.destroy();\n this.analyzer?.destroy();\n }\n}\n","/** Minimal interface for the built TypstRenderer instance. */\nexport interface RendererInstance {\n free(): void;\n create_session(): RendererSession;\n manipulate_data(\n session: RendererSession,\n action: string,\n data: Uint8Array,\n ): void;\n svg_data(session: RendererSession): string;\n}\n\n/** Minimal interface for a TypstRenderer session. */\nexport interface RendererSession {\n free(): void;\n}\n\ntype RendererWasmModule = typeof import(\"@myriaddreamin/typst-ts-renderer\");\n\ndeclare const __TYPST_TS_RENDERER_VERSION__: string;\n\nconst DEFAULT_RENDERER_WASM_URL = `https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-renderer@${__TYPST_TS_RENDERER_VERSION__}/pkg/typst_ts_renderer_bg.wasm`;\n\nlet rendererModulePromise: Promise<RendererWasmModule> | null = null;\n\nfunction getRendererModule(): Promise<RendererWasmModule> {\n if (!rendererModulePromise) {\n rendererModulePromise = import(\"@myriaddreamin/typst-ts-renderer\").catch(\n (err) => {\n rendererModulePromise = null;\n throw err;\n },\n );\n }\n return rendererModulePromise;\n}\n\nexport interface TypstRendererOptions {\n /** URL to the typst-ts-renderer WASM binary. Defaults to jsDelivr CDN. */\n wasmUrl?: string;\n}\n\nexport interface RenderedSvgPage {\n /** Zero-based page index within the document. */\n index: number;\n /** Page width in typographic points. */\n width: number;\n /** Page height in typographic points. */\n height: number;\n /** Standalone SVG string for just this page. */\n svg: string;\n}\n\n/**\n * Converts Typst vector artifacts to SVG strings.\n *\n * The renderer WASM module is loaded lazily on first use.\n *\n * const renderer = TypstRenderer.create();\n * const svg = await renderer.renderSvg(vector);\n */\nexport class TypstRenderer {\n private wasmUrl: string;\n private instance: Promise<RendererInstance> | null = null;\n\n private constructor(options: TypstRendererOptions = {}) {\n this.wasmUrl = options.wasmUrl ?? DEFAULT_RENDERER_WASM_URL;\n // Eagerly start loading the WASM module so it's ready by first use.\n getRendererModule().catch(() => {});\n }\n\n static create(options: TypstRendererOptions = {}): TypstRenderer {\n return new TypstRenderer(options);\n }\n\n private getInstance(): Promise<RendererInstance> {\n if (!this.instance) {\n this.instance = this.#init().catch((err) => {\n this.instance = null;\n throw err;\n });\n }\n return this.instance;\n }\n\n async #init(): Promise<RendererInstance> {\n const mod = await getRendererModule();\n await mod.default({ module_or_path: this.wasmUrl });\n return new mod.TypstRendererBuilder().build();\n }\n\n /** Free the underlying WASM renderer instance. */\n async destroy(): Promise<void> {\n const instance = this.instance;\n this.instance = null;\n if (instance) {\n (await instance).free();\n }\n }\n\n /** Render a Typst vector artifact to an SVG string. */\n async renderSvg(vector: Uint8Array): Promise<string> {\n const renderer = await this.getInstance();\n const session = renderer.create_session();\n try {\n renderer.manipulate_data(session, \"reset\", vector);\n return renderer.svg_data(session);\n } finally {\n session.free();\n }\n }\n\n /**\n * Render a Typst vector artifact into one self-contained SVG string per\n * physical page. The merged SVG is split by `<g class=\"typst-page\">`\n * children; each group's `data-page-width` / `data-page-height` give the\n * page-local viewBox. Shared `<defs>` / `<style>` are duplicated into each\n * page so the output SVGs render independently. Returns an empty array if\n * the document has no page groups.\n */\n async renderSvgPages(vector: Uint8Array): Promise<RenderedSvgPage[]> {\n return splitMergedSvgPages(await this.renderSvg(vector));\n }\n}\n\n// Parsing must use \"text/html\", not \"image/svg+xml\": Typst's merged SVG\n// output has repeatedly failed XML-strict parsing. HTML mode tolerates it\n// and still produces real SVGSVGElement nodes for inline SVG.\nfunction splitMergedSvgPages(svg: string): RenderedSvgPage[] {\n const doc = new DOMParser().parseFromString(svg, \"text/html\");\n const root = doc.querySelector(\"svg\");\n if (!root) return [];\n\n const children = Array.from(root.children);\n const pageGroups = children.filter(\n (el) =>\n el.tagName.toLowerCase() === \"g\" && el.classList.contains(\"typst-page\"),\n );\n if (pageGroups.length === 0) return [];\n\n const sharedHtml = children\n .filter((el) => !el.classList.contains(\"typst-page\"))\n .map((el) => el.outerHTML)\n .join(\"\");\n\n const namespaceAttrs = Array.from(root.attributes)\n .filter((attr) => attr.name === \"xmlns\" || attr.name.startsWith(\"xmlns:\"))\n .map((attr) => `${attr.name}=\"${attr.value}\"`)\n .join(\" \");\n\n return pageGroups.flatMap((group, index) => {\n const width = Number(group.getAttribute(\"data-page-width\")) || 0;\n const height = Number(group.getAttribute(\"data-page-height\")) || 0;\n if (width <= 0 || height <= 0) return [];\n\n const clone = group.cloneNode(true) as Element;\n clone.removeAttribute(\"transform\");\n\n return [\n {\n index,\n width,\n height,\n svg:\n `<svg ${namespaceAttrs} viewBox=\"0 0 ${width} ${height}\" ` +\n `width=\"${width}\" height=\"${height}\">` +\n `${sharedHtml}${clone.outerHTML}</svg>`,\n },\n ];\n });\n}\n"],"mappings":"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","names":["Comlink"]}
|