@vedivad/typst-web-service 0.4.5 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +74 -54
- package/dist/index.js +122 -65
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -68,59 +68,6 @@ declare class TypstAnalyzer {
|
|
|
68
68
|
destroy(): void;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
-
interface AnalyzerSessionOptions {
|
|
72
|
-
analyzer: Pick<TypstAnalyzer, "ready" | "didOpen" | "didChange" | "completion" | "hover">;
|
|
73
|
-
/** Project root used to build stable in-memory analyzer URIs. Default: "/project". */
|
|
74
|
-
rootPath?: string;
|
|
75
|
-
/** Entry file path within the project. Synced last to ensure dependencies load first. Default: "/main.typ". */
|
|
76
|
-
entryPath?: string;
|
|
77
|
-
}
|
|
78
|
-
/**
|
|
79
|
-
* Synchronizes an in-memory Typst project with a TypstAnalyzer.
|
|
80
|
-
* Handles multi-file ordering and avoids cross-file race conditions.
|
|
81
|
-
*
|
|
82
|
-
* Diagnostics are not returned — they arrive via the analyzer's `onDiagnostics` callback.
|
|
83
|
-
*
|
|
84
|
-
* const session = new AnalyzerSession({ analyzer });
|
|
85
|
-
* await session.sync("/main.typ", source, files);
|
|
86
|
-
*/
|
|
87
|
-
declare class AnalyzerSession {
|
|
88
|
-
readonly ready: Promise<void>;
|
|
89
|
-
private readonly analyzer;
|
|
90
|
-
private readonly rootPath;
|
|
91
|
-
private readonly entryPath;
|
|
92
|
-
private readonly syncedFiles;
|
|
93
|
-
private queue;
|
|
94
|
-
private syncRevision;
|
|
95
|
-
constructor(options: AnalyzerSessionOptions);
|
|
96
|
-
/** Build a tinymist URI from a project-relative path. */
|
|
97
|
-
toUri(path: string): string;
|
|
98
|
-
/**
|
|
99
|
-
* Sync all project files with the analyzer, then notify it of the active file change.
|
|
100
|
-
* Diagnostics will arrive asynchronously via the analyzer's `onDiagnostics` callback.
|
|
101
|
-
*/
|
|
102
|
-
sync(path: string, content: string, files: Record<string, string>): Promise<void>;
|
|
103
|
-
private syncForRequest;
|
|
104
|
-
private syncActive;
|
|
105
|
-
private orderedPaths;
|
|
106
|
-
private syncFiles;
|
|
107
|
-
/**
|
|
108
|
-
* Sync files and request completions at the given position.
|
|
109
|
-
* Returns the raw LSP CompletionList/CompletionItem[] from tinymist.
|
|
110
|
-
*/
|
|
111
|
-
completion(path: string, content: string, files: Record<string, string>, line: number, character: number): Promise<unknown>;
|
|
112
|
-
/**
|
|
113
|
-
* Sync files and request hover info at the given position.
|
|
114
|
-
* Returns the raw LSP Hover result from tinymist.
|
|
115
|
-
*/
|
|
116
|
-
hover(path: string, content: string, files: Record<string, string>, line: number, character: number): Promise<unknown>;
|
|
117
|
-
private enqueue;
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
declare function normalizeUntitledUri(uri: string): string;
|
|
121
|
-
declare function normalizePath(path: string): string;
|
|
122
|
-
declare function normalizeRoot(rootPath: string): string;
|
|
123
|
-
|
|
124
71
|
/** Source range for a diagnostic. All values are 0-indexed. */
|
|
125
72
|
interface DiagnosticRange {
|
|
126
73
|
startLine: number;
|
|
@@ -186,6 +133,79 @@ declare class TypstCompiler {
|
|
|
186
133
|
destroy(): void;
|
|
187
134
|
}
|
|
188
135
|
|
|
136
|
+
type DiagnosticsSubscriber = (diagnostics: LspDiagnostic[]) => void;
|
|
137
|
+
interface AnalyzerSessionOptions {
|
|
138
|
+
analyzer: Pick<TypstAnalyzer, "ready" | "didOpen" | "didChange" | "completion" | "hover" | "onDiagnostics">;
|
|
139
|
+
/** Project root used to build stable in-memory analyzer URIs. Default: "/project". */
|
|
140
|
+
rootPath?: string;
|
|
141
|
+
/** Entry file path within the project. Synced last to ensure dependencies load first. Default: "/main.typ". */
|
|
142
|
+
entryPath?: string;
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Synchronizes an in-memory Typst project with a TypstAnalyzer.
|
|
146
|
+
* Handles multi-file ordering, request queueing, and diagnostic subscriptions.
|
|
147
|
+
*
|
|
148
|
+
* Diagnostics arrive via the analyzer's push mechanism and are forwarded
|
|
149
|
+
* to subscribers registered with `subscribe()`.
|
|
150
|
+
*
|
|
151
|
+
* const session = new AnalyzerSession({ analyzer });
|
|
152
|
+
* session.subscribe("/main.typ", (diags) => { ... });
|
|
153
|
+
* await session.sync("/main.typ", source, files);
|
|
154
|
+
*/
|
|
155
|
+
declare class AnalyzerSession {
|
|
156
|
+
readonly ready: Promise<void>;
|
|
157
|
+
private readonly analyzer;
|
|
158
|
+
private readonly rootPath;
|
|
159
|
+
private readonly entryPath;
|
|
160
|
+
private readonly syncedFiles;
|
|
161
|
+
private queue;
|
|
162
|
+
private syncRevision;
|
|
163
|
+
private readonly listenersByUri;
|
|
164
|
+
private readonly diagnosticsByUri;
|
|
165
|
+
private readonly diagnosticsHashByUri;
|
|
166
|
+
private readonly unsubscribeAnalyzer;
|
|
167
|
+
constructor(options: AnalyzerSessionOptions);
|
|
168
|
+
/** Build a tinymist URI from a project-relative path. */
|
|
169
|
+
toUri(path: string): string;
|
|
170
|
+
/**
|
|
171
|
+
* Subscribe to push-based diagnostics for a file path.
|
|
172
|
+
* Returns an unsubscribe function. Replays cached diagnostics immediately.
|
|
173
|
+
*/
|
|
174
|
+
subscribe(path: string, listener: DiagnosticsSubscriber): () => void;
|
|
175
|
+
/**
|
|
176
|
+
* Sync all project files with the analyzer, then notify it of the active file change.
|
|
177
|
+
* Diagnostics will arrive asynchronously via subscribers registered with `subscribe()`.
|
|
178
|
+
*/
|
|
179
|
+
sync(path: string, content: string, files: Record<string, string>): Promise<void>;
|
|
180
|
+
/**
|
|
181
|
+
* Sync files, then compile with the provided compiler.
|
|
182
|
+
* Diagnostics come from the analyzer (push-based); the compiler provides preview artifacts.
|
|
183
|
+
*/
|
|
184
|
+
syncAndCompile(path: string, content: string, files: Record<string, string>, compiler: TypstCompiler, onCompile?: (result: CompileResult) => void, signal?: AbortSignal): Promise<void>;
|
|
185
|
+
/**
|
|
186
|
+
* Sync files and request completions at the given position.
|
|
187
|
+
* Returns the raw LSP CompletionList/CompletionItem[] from tinymist.
|
|
188
|
+
*/
|
|
189
|
+
completion(path: string, content: string, files: Record<string, string>, line: number, character: number): Promise<unknown>;
|
|
190
|
+
/**
|
|
191
|
+
* Sync files and request hover info at the given position.
|
|
192
|
+
* Returns the raw LSP Hover result from tinymist.
|
|
193
|
+
*/
|
|
194
|
+
hover(path: string, content: string, files: Record<string, string>, line: number, character: number): Promise<unknown>;
|
|
195
|
+
destroy(): void;
|
|
196
|
+
/**
|
|
197
|
+
* Sync a single file with the analyzer.
|
|
198
|
+
* @param forceOpen - Always use didOpen (triggers tinymist diagnostics for the active file).
|
|
199
|
+
*/
|
|
200
|
+
private syncFile;
|
|
201
|
+
private orderedPaths;
|
|
202
|
+
private enqueue;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
declare function normalizeUntitledUri(uri: string): string;
|
|
206
|
+
declare function normalizePath(path: string): string;
|
|
207
|
+
declare function normalizeRoot(rootPath: string): string;
|
|
208
|
+
|
|
189
209
|
interface FormatConfig {
|
|
190
210
|
/** Number of spaces per indentation level. Default: 2 */
|
|
191
211
|
tab_spaces?: number;
|
|
@@ -248,4 +268,4 @@ declare class TypstRenderer {
|
|
|
248
268
|
renderSvg(vector: Uint8Array): Promise<string>;
|
|
249
269
|
}
|
|
250
270
|
|
|
251
|
-
export { AnalyzerSession, type AnalyzerSessionOptions, type CompileResult, type DiagnosticMessage, type DiagnosticRange, type FormatConfig, type FormatRangeResult, type LspDiagnostic, TypstAnalyzer, type TypstAnalyzerOptions, TypstCompiler, type TypstCompilerOptions, TypstFormatter, TypstRenderer, type TypstRendererOptions, normalizePath, normalizeRoot, normalizeUntitledUri };
|
|
271
|
+
export { AnalyzerSession, type AnalyzerSessionOptions, type CompileResult, type DiagnosticMessage, type DiagnosticRange, type DiagnosticsSubscriber, type FormatConfig, type FormatRangeResult, type LspDiagnostic, TypstAnalyzer, type TypstAnalyzerOptions, TypstCompiler, type TypstCompilerOptions, TypstFormatter, TypstRenderer, type TypstRendererOptions, normalizePath, normalizeRoot, normalizeUntitledUri };
|
package/dist/index.js
CHANGED
|
@@ -176,81 +176,86 @@ var AnalyzerSession = class {
|
|
|
176
176
|
syncedFiles = /* @__PURE__ */ new Map();
|
|
177
177
|
queue = Promise.resolve();
|
|
178
178
|
syncRevision = 0;
|
|
179
|
+
// Diagnostic subscription state
|
|
180
|
+
listenersByUri = /* @__PURE__ */ new Map();
|
|
181
|
+
diagnosticsByUri = /* @__PURE__ */ new Map();
|
|
182
|
+
diagnosticsHashByUri = /* @__PURE__ */ new Map();
|
|
183
|
+
unsubscribeAnalyzer;
|
|
179
184
|
constructor(options) {
|
|
180
185
|
this.analyzer = options.analyzer;
|
|
181
186
|
this.rootPath = normalizeRoot(options.rootPath ?? "/project");
|
|
182
187
|
this.entryPath = normalizePath(options.entryPath ?? "/main.typ");
|
|
183
188
|
this.ready = this.analyzer.ready;
|
|
189
|
+
this.unsubscribeAnalyzer = this.analyzer.onDiagnostics((uri, diagnostics) => {
|
|
190
|
+
const nextHash = diagnosticsHash(diagnostics);
|
|
191
|
+
if (this.diagnosticsHashByUri.get(uri) === nextHash) return;
|
|
192
|
+
this.diagnosticsByUri.set(uri, diagnostics);
|
|
193
|
+
this.diagnosticsHashByUri.set(uri, nextHash);
|
|
194
|
+
const listeners = this.listenersByUri.get(uri);
|
|
195
|
+
if (!listeners) return;
|
|
196
|
+
for (const listener of listeners) listener(diagnostics);
|
|
197
|
+
});
|
|
184
198
|
}
|
|
185
199
|
/** Build a tinymist URI from a project-relative path. */
|
|
186
200
|
toUri(path) {
|
|
187
201
|
const root = this.rootPath.replace(/^\//, "");
|
|
188
202
|
return `untitled:${root}${normalizePath(path)}`;
|
|
189
203
|
}
|
|
204
|
+
/**
|
|
205
|
+
* Subscribe to push-based diagnostics for a file path.
|
|
206
|
+
* Returns an unsubscribe function. Replays cached diagnostics immediately.
|
|
207
|
+
*/
|
|
208
|
+
subscribe(path, listener) {
|
|
209
|
+
const uri = this.toUri(path);
|
|
210
|
+
let listeners = this.listenersByUri.get(uri);
|
|
211
|
+
if (!listeners) {
|
|
212
|
+
listeners = /* @__PURE__ */ new Set();
|
|
213
|
+
this.listenersByUri.set(uri, listeners);
|
|
214
|
+
}
|
|
215
|
+
listeners.add(listener);
|
|
216
|
+
const cached = this.diagnosticsByUri.get(uri);
|
|
217
|
+
if (cached) listener(cached);
|
|
218
|
+
return () => {
|
|
219
|
+
const current = this.listenersByUri.get(uri);
|
|
220
|
+
if (!current) return;
|
|
221
|
+
current.delete(listener);
|
|
222
|
+
if (current.size === 0) this.listenersByUri.delete(uri);
|
|
223
|
+
};
|
|
224
|
+
}
|
|
190
225
|
/**
|
|
191
226
|
* Sync all project files with the analyzer, then notify it of the active file change.
|
|
192
|
-
* Diagnostics will arrive asynchronously via
|
|
227
|
+
* Diagnostics will arrive asynchronously via subscribers registered with `subscribe()`.
|
|
193
228
|
*/
|
|
194
229
|
async sync(path, content, files) {
|
|
195
|
-
|
|
196
|
-
const
|
|
197
|
-
const mergedFiles = { ...files, [
|
|
230
|
+
++this.syncRevision;
|
|
231
|
+
const activePath = normalizePath(path);
|
|
232
|
+
const mergedFiles = { ...files, [activePath]: content };
|
|
198
233
|
await this.enqueue(async () => {
|
|
199
|
-
await this.
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
await this.ready;
|
|
204
|
-
await this.syncFiles(mergedFiles, normalizedPath);
|
|
205
|
-
await this.syncActive(
|
|
206
|
-
normalizedPath,
|
|
207
|
-
mergedFiles[normalizedPath],
|
|
208
|
-
forceDidChange
|
|
209
|
-
);
|
|
210
|
-
}
|
|
211
|
-
async syncActive(path, content, forceDidChange) {
|
|
212
|
-
if (forceDidChange) {
|
|
213
|
-
await this.analyzer.didOpen(this.toUri(path), content);
|
|
214
|
-
this.syncedFiles.set(path, content);
|
|
215
|
-
return;
|
|
216
|
-
}
|
|
217
|
-
const prev = this.syncedFiles.get(path);
|
|
218
|
-
if (prev == null) {
|
|
219
|
-
await this.analyzer.didOpen(this.toUri(path), content);
|
|
220
|
-
this.syncedFiles.set(path, content);
|
|
221
|
-
return;
|
|
222
|
-
}
|
|
223
|
-
if (forceDidChange || prev !== content) {
|
|
224
|
-
await this.analyzer.didChange(this.toUri(path), content);
|
|
225
|
-
this.syncedFiles.set(path, content);
|
|
226
|
-
}
|
|
227
|
-
}
|
|
228
|
-
orderedPaths(files) {
|
|
229
|
-
return Object.keys(files).map((path) => normalizePath(path)).sort((a, b) => {
|
|
230
|
-
if (a === this.entryPath) return 1;
|
|
231
|
-
if (b === this.entryPath) return -1;
|
|
232
|
-
return a.localeCompare(b);
|
|
233
|
-
});
|
|
234
|
-
}
|
|
235
|
-
async syncFiles(files, activePath) {
|
|
236
|
-
for (const path of this.orderedPaths(files)) {
|
|
237
|
-
if (path === activePath) continue;
|
|
238
|
-
const next = files[path];
|
|
239
|
-
const prev = this.syncedFiles.get(path);
|
|
240
|
-
if (prev == null) {
|
|
241
|
-
await this.analyzer.didOpen(this.toUri(path), next);
|
|
242
|
-
this.syncedFiles.set(path, next);
|
|
243
|
-
continue;
|
|
234
|
+
await this.ready;
|
|
235
|
+
for (const filePath of this.orderedPaths(mergedFiles)) {
|
|
236
|
+
if (filePath === activePath) continue;
|
|
237
|
+
await this.syncFile(filePath, mergedFiles[filePath], false);
|
|
244
238
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
for (const path of Array.from(this.syncedFiles.keys())) {
|
|
251
|
-
if (!Object.hasOwn(files, path)) {
|
|
252
|
-
this.syncedFiles.delete(path);
|
|
239
|
+
await this.syncFile(activePath, mergedFiles[activePath], true);
|
|
240
|
+
for (const filePath of this.syncedFiles.keys()) {
|
|
241
|
+
if (!Object.hasOwn(mergedFiles, filePath)) {
|
|
242
|
+
this.syncedFiles.delete(filePath);
|
|
243
|
+
}
|
|
253
244
|
}
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Sync files, then compile with the provided compiler.
|
|
249
|
+
* Diagnostics come from the analyzer (push-based); the compiler provides preview artifacts.
|
|
250
|
+
*/
|
|
251
|
+
async syncAndCompile(path, content, files, compiler, onCompile, signal) {
|
|
252
|
+
await this.sync(path, content, files);
|
|
253
|
+
if (signal?.aborted) return;
|
|
254
|
+
try {
|
|
255
|
+
const result = await compiler.compile(files);
|
|
256
|
+
if (signal?.aborted) return;
|
|
257
|
+
onCompile?.(result);
|
|
258
|
+
} catch {
|
|
254
259
|
}
|
|
255
260
|
}
|
|
256
261
|
/**
|
|
@@ -259,13 +264,18 @@ var AnalyzerSession = class {
|
|
|
259
264
|
*/
|
|
260
265
|
async completion(path, content, files, line, character) {
|
|
261
266
|
const enqueuedRevision = this.syncRevision;
|
|
262
|
-
const
|
|
263
|
-
const mergedFiles = { ...files, [
|
|
267
|
+
const activePath = normalizePath(path);
|
|
268
|
+
const mergedFiles = { ...files, [activePath]: content };
|
|
264
269
|
return this.enqueue(async () => {
|
|
265
270
|
if (enqueuedRevision !== this.syncRevision) return null;
|
|
266
|
-
await this.
|
|
271
|
+
await this.ready;
|
|
272
|
+
for (const filePath of this.orderedPaths(mergedFiles)) {
|
|
273
|
+
if (filePath === activePath) continue;
|
|
274
|
+
await this.syncFile(filePath, mergedFiles[filePath], false);
|
|
275
|
+
}
|
|
276
|
+
await this.syncFile(activePath, mergedFiles[activePath], false);
|
|
267
277
|
return this.analyzer.completion(
|
|
268
|
-
this.toUri(
|
|
278
|
+
this.toUri(activePath),
|
|
269
279
|
line,
|
|
270
280
|
character
|
|
271
281
|
);
|
|
@@ -277,12 +287,46 @@ var AnalyzerSession = class {
|
|
|
277
287
|
*/
|
|
278
288
|
async hover(path, content, files, line, character) {
|
|
279
289
|
const enqueuedRevision = this.syncRevision;
|
|
280
|
-
const
|
|
281
|
-
const mergedFiles = { ...files, [
|
|
290
|
+
const activePath = normalizePath(path);
|
|
291
|
+
const mergedFiles = { ...files, [activePath]: content };
|
|
282
292
|
return this.enqueue(async () => {
|
|
283
293
|
if (enqueuedRevision !== this.syncRevision) return null;
|
|
284
|
-
await this.
|
|
285
|
-
|
|
294
|
+
await this.ready;
|
|
295
|
+
for (const filePath of this.orderedPaths(mergedFiles)) {
|
|
296
|
+
if (filePath === activePath) continue;
|
|
297
|
+
await this.syncFile(filePath, mergedFiles[filePath], false);
|
|
298
|
+
}
|
|
299
|
+
await this.syncFile(activePath, mergedFiles[activePath], false);
|
|
300
|
+
return this.analyzer.hover(this.toUri(activePath), line, character);
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
destroy() {
|
|
304
|
+
this.unsubscribeAnalyzer();
|
|
305
|
+
this.listenersByUri.clear();
|
|
306
|
+
this.diagnosticsByUri.clear();
|
|
307
|
+
this.diagnosticsHashByUri.clear();
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Sync a single file with the analyzer.
|
|
311
|
+
* @param forceOpen - Always use didOpen (triggers tinymist diagnostics for the active file).
|
|
312
|
+
*/
|
|
313
|
+
async syncFile(path, content, forceOpen) {
|
|
314
|
+
const prev = this.syncedFiles.get(path);
|
|
315
|
+
if (forceOpen || prev == null) {
|
|
316
|
+
await this.analyzer.didOpen(this.toUri(path), content);
|
|
317
|
+
this.syncedFiles.set(path, content);
|
|
318
|
+
return;
|
|
319
|
+
}
|
|
320
|
+
if (prev !== content) {
|
|
321
|
+
await this.analyzer.didChange(this.toUri(path), content);
|
|
322
|
+
this.syncedFiles.set(path, content);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
orderedPaths(files) {
|
|
326
|
+
return Object.keys(files).map((p) => normalizePath(p)).sort((a, b) => {
|
|
327
|
+
if (a === this.entryPath) return 1;
|
|
328
|
+
if (b === this.entryPath) return -1;
|
|
329
|
+
return a.localeCompare(b);
|
|
286
330
|
});
|
|
287
331
|
}
|
|
288
332
|
enqueue(task) {
|
|
@@ -294,6 +338,19 @@ var AnalyzerSession = class {
|
|
|
294
338
|
return run;
|
|
295
339
|
}
|
|
296
340
|
};
|
|
341
|
+
function diagnosticsHash(diagnostics) {
|
|
342
|
+
return JSON.stringify(
|
|
343
|
+
diagnostics.map((d) => [
|
|
344
|
+
d.range.start.line,
|
|
345
|
+
d.range.start.character,
|
|
346
|
+
d.range.end.line,
|
|
347
|
+
d.range.end.character,
|
|
348
|
+
d.severity ?? 1,
|
|
349
|
+
d.message,
|
|
350
|
+
d.source ?? ""
|
|
351
|
+
])
|
|
352
|
+
);
|
|
353
|
+
}
|
|
297
354
|
|
|
298
355
|
// src/compiler.ts
|
|
299
356
|
var DEFAULT_FONTS = [
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/rpc.ts","../src/uri.ts","../src/analyzer.ts","../src/analyzer-session.ts","../src/compiler.ts","../src/formatter.ts","../src/renderer.ts"],"sourcesContent":["// 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/** Generic RPC helper: post a message to a worker and await a response matched by id. */\nexport function workerRpc<\n TReq extends { id: number },\n TRes extends { id: number },\n>(\n worker: Worker,\n request: TReq,\n timeoutMs: number = 30_000,\n transfer?: Transferable[],\n): Promise<TRes> {\n return new Promise((resolve, reject) => {\n const handler = (e: MessageEvent<TRes>) => {\n if (e.data.id !== request.id) return;\n clearTimeout(timer);\n worker.removeEventListener(\"message\", handler);\n resolve(e.data);\n };\n const timer = setTimeout(() => {\n worker.removeEventListener(\"message\", handler);\n reject(new Error(`worker timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n worker.addEventListener(\"message\", handler);\n worker.postMessage(request, transfer ?? []);\n });\n}\n\n/** Convenience: send a destroy RPC and terminate the worker. */\nexport function destroyWorker<TReq extends { id: number }>(\n worker: Worker,\n request: TReq,\n timeoutMs: number,\n label: string,\n): void {\n workerRpc(worker, request, timeoutMs)\n .catch((err) => console.error(`${label} destroy failed:`, err))\n .finally(() => worker.terminate());\n}\n","export function normalizeUntitledUri(uri: string): string {\n if (!uri.startsWith(\"untitled:\")) return uri;\n return `untitled:${uri.slice(\"untitled:\".length).replace(/^\\/+/, \"\")}`;\n}\n\nexport function normalizePath(path: string): string {\n return path.startsWith(\"/\") ? path : `/${path}`;\n}\n\nexport function normalizeRoot(rootPath: string): string {\n const root = normalizePath(rootPath);\n return root === \"/\" ? \"\" : root.replace(/\\/+$/, \"\");\n}","import type {\n AnalyzerDiagnosticEvent,\n AnalyzerMessage,\n AnalyzerRequest,\n AnalyzerResponse,\n LspDiagnostic,\n} from \"./analyzer-types.js\";\nimport { createAnalyzerWorker, destroyWorker, workerRpc } from \"./rpc.js\";\nimport { normalizeUntitledUri } from \"./uri.js\";\n\nexport type { LspDiagnostic };\n\nexport type DiagnosticsListener = (\n uri: string,\n diagnostics: LspDiagnostic[],\n) => void;\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 * `new TypstAnalyzer({ 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\nconst TIMEOUT = { INIT: 120_000, REQUEST: 30_000, DESTROY: 5_000 } as const;\n\n/**\n * Manages a tinymist language server in a Web Worker. Provides LSP-based\n * diagnostics, completion, and hover for Typst documents.\n *\n * Diagnostics are push-based: call `didChange()` to notify the analyzer of\n * content changes, and receive diagnostics via `onDiagnostics()` listeners\n * whenever tinymist publishes them.\n *\n * const analyzer = new TypstAnalyzer({ wasmUrl: '...' });\n * analyzer.onDiagnostics((uri, diags) => { ... });\n */\nexport class TypstAnalyzer {\n readonly ready: Promise<void>;\n private idCounter = 0;\n private versionCounter = 0;\n private worker: Worker;\n private openedUris = new Set<string>();\n private diagnosticsListeners = new Set<DiagnosticsListener>();\n private latestDiagnosticsByUri = new Map<string, LspDiagnostic[]>();\n\n constructor(options: TypstAnalyzerOptions) {\n this.worker = options.worker ?? createAnalyzerWorker();\n const absoluteWasmUrl = new URL(options.wasmUrl, globalThis.location?.href)\n .href;\n\n // Listen for unsolicited diagnostic push notifications from the worker.\n this.worker.addEventListener(\n \"message\",\n (e: MessageEvent<AnalyzerMessage>) => {\n if (e.data.type === \"diagnostics\" && !(\"id\" in e.data)) {\n const event = e.data as AnalyzerDiagnosticEvent;\n const normalizedUri = normalizeUntitledUri(event.uri);\n this.latestDiagnosticsByUri.set(normalizedUri, event.diagnostics);\n for (const listener of this.diagnosticsListeners) {\n listener(normalizedUri, event.diagnostics);\n }\n }\n },\n );\n\n this.ready = this.rpc(\n { type: \"init\", id: ++this.idCounter, wasmUrl: absoluteWasmUrl },\n TIMEOUT.INIT,\n ).then((res) => {\n if (res.type === \"error\")\n throw new Error(`TypstAnalyzer init failed: ${res.message}`);\n });\n }\n\n /**\n * Register a listener for push-based diagnostics.\n * Returns an unsubscribe function.\n */\n onDiagnostics(listener: DiagnosticsListener): () => void {\n this.diagnosticsListeners.add(listener);\n return () => this.diagnosticsListeners.delete(listener);\n }\n\n /** Returns the latest pushed diagnostics for a URI, if available. */\n getLatestDiagnostics(uri: string): LspDiagnostic[] | undefined {\n return this.latestDiagnosticsByUri.get(normalizeUntitledUri(uri));\n }\n\n private rpc(\n request: AnalyzerRequest,\n timeoutMs: number = TIMEOUT.REQUEST,\n ): Promise<AnalyzerResponse> {\n return workerRpc(this.worker, request, timeoutMs);\n }\n\n async didOpen(uri: string, content: string): Promise<void> {\n await this.ready;\n const res = await this.rpc({\n type: \"didOpen\",\n id: ++this.idCounter,\n uri,\n content,\n });\n if (res.type === \"error\") throw new Error(res.message);\n this.openedUris.add(uri);\n }\n\n /**\n * Notify the analyzer that a document has changed.\n * Diagnostics will arrive asynchronously via `onDiagnostics()` listeners.\n */\n async didChange(uri: string, content: string): Promise<void> {\n await this.ready;\n if (!this.openedUris.has(uri)) {\n await this.didOpen(uri, content);\n return;\n }\n\n const version = ++this.versionCounter;\n const res = await this.rpc({\n type: \"didChange\",\n id: ++this.idCounter,\n uri,\n version,\n content,\n });\n if (res.type === \"error\") throw new Error(res.message);\n }\n\n async completion(\n uri: string,\n line: number,\n character: number,\n ): Promise<unknown> {\n await this.ready;\n const res = await this.rpc({\n type: \"completion\",\n id: ++this.idCounter,\n uri,\n line,\n character,\n });\n if (res.type === \"error\") throw new Error(res.message);\n if (res.type === \"completionResult\") return res.result;\n return null;\n }\n\n async hover(uri: string, line: number, character: number): Promise<unknown> {\n await this.ready;\n const res = await this.rpc({\n type: \"hover\",\n id: ++this.idCounter,\n uri,\n line,\n character,\n });\n if (res.type === \"error\") throw new Error(res.message);\n if (res.type === \"hoverResult\") return res.result;\n return null;\n }\n\n destroy(): void {\n this.diagnosticsListeners.clear();\n this.latestDiagnosticsByUri.clear();\n destroyWorker(\n this.worker,\n { type: \"destroy\" as const, id: ++this.idCounter },\n TIMEOUT.DESTROY,\n \"TypstAnalyzer\",\n );\n }\n}\n","import type { TypstAnalyzer } from \"./analyzer.js\";\n\nexport interface AnalyzerSessionOptions {\n analyzer: Pick<\n TypstAnalyzer,\n \"ready\" | \"didOpen\" | \"didChange\" | \"completion\" | \"hover\"\n >;\n /** Project root used to build stable in-memory analyzer URIs. Default: \"/project\". */\n rootPath?: string;\n /** Entry file path within the project. Synced last to ensure dependencies load first. Default: \"/main.typ\". */\n entryPath?: string;\n}\n\n\nimport { normalizePath, normalizeRoot } from \"./uri.js\";\n\n/**\n * Synchronizes an in-memory Typst project with a TypstAnalyzer.\n * Handles multi-file ordering and avoids cross-file race conditions.\n *\n * Diagnostics are not returned — they arrive via the analyzer's `onDiagnostics` callback.\n *\n * const session = new AnalyzerSession({ analyzer });\n * await session.sync(\"/main.typ\", source, files);\n */\nexport class AnalyzerSession {\n readonly ready: Promise<void>;\n\n private readonly analyzer: Pick<\n TypstAnalyzer,\n \"ready\" | \"didOpen\" | \"didChange\" | \"completion\" | \"hover\"\n >;\n private readonly rootPath: string;\n private readonly entryPath: string;\n private readonly syncedFiles = new Map<string, string>();\n private queue: Promise<void> = Promise.resolve();\n private syncRevision = 0;\n\n constructor(options: AnalyzerSessionOptions) {\n this.analyzer = options.analyzer;\n this.rootPath = normalizeRoot(options.rootPath ?? \"/project\");\n this.entryPath = normalizePath(options.entryPath ?? \"/main.typ\");\n this.ready = this.analyzer.ready;\n }\n\n /** Build a tinymist URI from a project-relative path. */\n toUri(path: string): string {\n // Tinymist publishes untitled URIs without a leading slash after the scheme.\n const root = this.rootPath.replace(/^\\//, \"\");\n return `untitled:${root}${normalizePath(path)}`;\n }\n\n /**\n * Sync all project files with the analyzer, then notify it of the active file change.\n * Diagnostics will arrive asynchronously via the analyzer's `onDiagnostics` callback.\n */\n async sync(\n path: string,\n content: string,\n files: Record<string, string>,\n ): Promise<void> {\n const revision = ++this.syncRevision;\n const normalizedPath = normalizePath(path);\n const mergedFiles = { ...files, [normalizedPath]: content };\n\n await this.enqueue(async () => {\n // Notify the active file last — tinymist will publish diagnostics for it.\n await this.syncForRequest(normalizedPath, mergedFiles, true);\n });\n }\n\n private async syncForRequest(\n normalizedPath: string,\n mergedFiles: Record<string, string>,\n forceDidChange: boolean,\n ): Promise<void> {\n await this.ready;\n await this.syncFiles(mergedFiles, normalizedPath);\n await this.syncActive(\n normalizedPath,\n mergedFiles[normalizedPath],\n forceDidChange,\n );\n }\n\n private async syncActive(\n path: string,\n content: string,\n forceDidChange: boolean,\n ): Promise<void> {\n if (forceDidChange) {\n await this.analyzer.didOpen(this.toUri(path), content);\n this.syncedFiles.set(path, content);\n return;\n }\n\n const prev = this.syncedFiles.get(path);\n\n if (prev == null) {\n await this.analyzer.didOpen(this.toUri(path), content);\n this.syncedFiles.set(path, content);\n return;\n }\n\n if (forceDidChange || prev !== content) {\n await this.analyzer.didChange(this.toUri(path), content);\n this.syncedFiles.set(path, content);\n }\n }\n\n private orderedPaths(files: Record<string, string>): string[] {\n return Object.keys(files)\n .map((path) => normalizePath(path))\n .sort((a, b) => {\n if (a === this.entryPath) return 1;\n if (b === this.entryPath) return -1;\n return a.localeCompare(b);\n });\n }\n\n private async syncFiles(\n files: Record<string, string>,\n activePath: string,\n ): Promise<void> {\n for (const path of this.orderedPaths(files)) {\n if (path === activePath) continue;\n\n const next = files[path];\n const prev = this.syncedFiles.get(path);\n\n if (prev == null) {\n await this.analyzer.didOpen(this.toUri(path), next);\n this.syncedFiles.set(path, next);\n continue;\n }\n\n if (prev !== next) {\n await this.analyzer.didChange(this.toUri(path), next);\n this.syncedFiles.set(path, next);\n }\n }\n\n for (const path of Array.from(this.syncedFiles.keys())) {\n if (!Object.hasOwn(files, path)) {\n this.syncedFiles.delete(path);\n }\n }\n }\n\n /**\n * Sync files and request completions at the given position.\n * Returns the raw LSP CompletionList/CompletionItem[] from tinymist.\n */\n async completion(\n path: string,\n content: string,\n files: Record<string, string>,\n line: number,\n character: number,\n ): Promise<unknown> {\n const enqueuedRevision = this.syncRevision;\n const normalizedPath = normalizePath(path);\n const mergedFiles = { ...files, [normalizedPath]: content };\n\n return this.enqueue(async () => {\n if (enqueuedRevision !== this.syncRevision) return null;\n\n await this.syncForRequest(normalizedPath, mergedFiles, false);\n return this.analyzer.completion(\n this.toUri(normalizedPath),\n line,\n character,\n );\n });\n }\n\n /**\n * Sync files and request hover info at the given position.\n * Returns the raw LSP Hover result from tinymist.\n */\n async hover(\n path: string,\n content: string,\n files: Record<string, string>,\n line: number,\n character: number,\n ): Promise<unknown> {\n const enqueuedRevision = this.syncRevision;\n const normalizedPath = normalizePath(path);\n const mergedFiles = { ...files, [normalizedPath]: content };\n\n return this.enqueue(async () => {\n if (enqueuedRevision !== this.syncRevision) return null;\n\n await this.syncForRequest(normalizedPath, mergedFiles, false);\n return this.analyzer.hover(this.toUri(normalizedPath), line, character);\n });\n }\n\n private enqueue<T>(task: () => Promise<T>): Promise<T> {\n const run = this.queue.then(task, task);\n this.queue = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n }\n}\n","import { createWorker, destroyWorker, workerRpc } from \"./rpc.js\";\nimport type {\n DiagnosticMessage,\n WorkerRequest,\n WorkerResponse,\n} from \"./types.js\";\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 * `new TypstCompiler({ worker: new Worker(new URL('typst-web-service/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 =\n \"https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-web-compiler@0.7.0-rc2/pkg/typst_ts_web_compiler_bg.wasm\";\n\nconst TIMEOUT = { INIT: 60_000, RENDER: 60_000, DESTROY: 5_000 } as const;\n\nfunction toFiles(\n source: string | Record<string, string>,\n): Record<string, string> {\n return typeof source === \"string\" ? { \"/main.typ\": source } : source;\n}\n\n/**\n * Manages a Typst compiler worker. Create one instance and share it across\n * all extensions (linter, autocomplete, preview, etc.).\n *\n * new TypstCompiler() // blob worker, defaults\n * new TypstCompiler({ wasmUrl: '...' }) // blob worker, custom WASM\n * new TypstCompiler({ worker: myWorker }) // explicit Worker (Vite)\n * new TypstCompiler({ worker: myWorker, fonts: [...] }) // explicit Worker + options\n */\nexport class TypstCompiler {\n readonly ready: Promise<void>;\n private idCounter = 0;\n private worker: Worker;\n\n /** The most recent vector artifact from a compile, if any. */\n lastVector?: Uint8Array;\n\n constructor(options: TypstCompilerOptions = {}) {\n this.worker = options.worker ?? createWorker();\n\n this.ready = workerRpc<WorkerRequest, WorkerResponse>(\n this.worker,\n {\n type: \"init\",\n id: ++this.idCounter,\n wasmUrl: options.wasmUrl ?? DEFAULT_WASM_URL,\n fonts: options.fonts ?? DEFAULT_FONTS,\n packages: options.packages ?? true,\n },\n TIMEOUT.INIT,\n ).then((res) => {\n if (res.type === \"error\")\n throw new Error(`TypstCompiler init failed: ${res.message}`);\n });\n }\n\n /** Compile a single source string (treated as /main.typ) or a map of files. */\n async compile(\n source: string | Record<string, string>,\n ): Promise<CompileResult> {\n await this.ready;\n const id = ++this.idCounter;\n const files = toFiles(source);\n const response = await workerRpc<WorkerRequest, WorkerResponse>(\n this.worker,\n {\n type: \"compile\",\n id,\n files,\n },\n );\n if (response.type === \"cancelled\") return { diagnostics: [] };\n if (response.type === \"result\") {\n const vector = response.vector\n ? new Uint8Array(response.vector)\n : undefined;\n if (vector) this.lastVector = vector;\n return { diagnostics: response.diagnostics, vector };\n }\n if (response.type === \"error\") throw new Error(response.message);\n return { diagnostics: [] };\n }\n\n /** Compile to PDF from a single source string (treated as /main.typ) or a map of files. */\n async compilePdf(\n source: string | Record<string, string>,\n ): Promise<Uint8Array> {\n await this.ready;\n const id = ++this.idCounter;\n const files = toFiles(source);\n const response = await workerRpc<WorkerRequest, WorkerResponse>(\n this.worker,\n { type: \"render\", id, files },\n TIMEOUT.RENDER,\n );\n if (response.type === \"cancelled\") throw new Error(\"Render cancelled\");\n if (response.type === \"pdf\") return new Uint8Array(response.data);\n if (response.type === \"error\") throw new Error(response.message);\n throw new Error(\"Unexpected response type\");\n }\n\n destroy(): void {\n const id = ++this.idCounter;\n destroyWorker(\n this.worker,\n { type: \"destroy\" as const, id },\n TIMEOUT.DESTROY,\n \"TypstCompiler\",\n );\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 // Reset so subsequent calls can retry\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 *\n * const formatter = new TypstFormatter({ tab_spaces: 2, max_width: 80 });\n * const formatted = await formatter.format(source);\n */\nexport class TypstFormatter {\n private config: FormatConfig;\n\n 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 /** 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","/** Minimal interface for the built TypstRenderer instance. */\nexport interface RendererInstance {\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\nconst DEFAULT_RENDERER_WASM_URL =\n \"https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-renderer@0.7.0-rc2/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\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 = new TypstRenderer();\n * const svg = await renderer.renderSvg(vector);\n */\nexport class TypstRenderer {\n private wasmUrl: string;\n private instance: Promise<RendererInstance> | null = null;\n\n 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 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(this.wasmUrl);\n return new mod.TypstRendererBuilder().build();\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"],"mappings":"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","names":["TIMEOUT"]}
|
|
1
|
+
{"version":3,"sources":["../src/rpc.ts","../src/uri.ts","../src/analyzer.ts","../src/analyzer-session.ts","../src/compiler.ts","../src/formatter.ts","../src/renderer.ts"],"sourcesContent":["// 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/** Generic RPC helper: post a message to a worker and await a response matched by id. */\nexport function workerRpc<\n TReq extends { id: number },\n TRes extends { id: number },\n>(\n worker: Worker,\n request: TReq,\n timeoutMs: number = 30_000,\n transfer?: Transferable[],\n): Promise<TRes> {\n return new Promise((resolve, reject) => {\n const handler = (e: MessageEvent<TRes>) => {\n if (e.data.id !== request.id) return;\n clearTimeout(timer);\n worker.removeEventListener(\"message\", handler);\n resolve(e.data);\n };\n const timer = setTimeout(() => {\n worker.removeEventListener(\"message\", handler);\n reject(new Error(`worker timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n worker.addEventListener(\"message\", handler);\n worker.postMessage(request, transfer ?? []);\n });\n}\n\n/** Convenience: send a destroy RPC and terminate the worker. */\nexport function destroyWorker<TReq extends { id: number }>(\n worker: Worker,\n request: TReq,\n timeoutMs: number,\n label: string,\n): void {\n workerRpc(worker, request, timeoutMs)\n .catch((err) => console.error(`${label} destroy failed:`, err))\n .finally(() => worker.terminate());\n}\n","export function normalizeUntitledUri(uri: string): string {\n if (!uri.startsWith(\"untitled:\")) return uri;\n return `untitled:${uri.slice(\"untitled:\".length).replace(/^\\/+/, \"\")}`;\n}\n\nexport function normalizePath(path: string): string {\n return path.startsWith(\"/\") ? path : `/${path}`;\n}\n\nexport function normalizeRoot(rootPath: string): string {\n const root = normalizePath(rootPath);\n return root === \"/\" ? \"\" : root.replace(/\\/+$/, \"\");\n}","import type {\n AnalyzerDiagnosticEvent,\n AnalyzerMessage,\n AnalyzerRequest,\n AnalyzerResponse,\n LspDiagnostic,\n} from \"./analyzer-types.js\";\nimport { createAnalyzerWorker, destroyWorker, workerRpc } from \"./rpc.js\";\nimport { normalizeUntitledUri } from \"./uri.js\";\n\nexport type { LspDiagnostic };\n\nexport type DiagnosticsListener = (\n uri: string,\n diagnostics: LspDiagnostic[],\n) => void;\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 * `new TypstAnalyzer({ 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\nconst TIMEOUT = { INIT: 120_000, REQUEST: 30_000, DESTROY: 5_000 } as const;\n\n/**\n * Manages a tinymist language server in a Web Worker. Provides LSP-based\n * diagnostics, completion, and hover for Typst documents.\n *\n * Diagnostics are push-based: call `didChange()` to notify the analyzer of\n * content changes, and receive diagnostics via `onDiagnostics()` listeners\n * whenever tinymist publishes them.\n *\n * const analyzer = new TypstAnalyzer({ wasmUrl: '...' });\n * analyzer.onDiagnostics((uri, diags) => { ... });\n */\nexport class TypstAnalyzer {\n readonly ready: Promise<void>;\n private idCounter = 0;\n private versionCounter = 0;\n private worker: Worker;\n private openedUris = new Set<string>();\n private diagnosticsListeners = new Set<DiagnosticsListener>();\n private latestDiagnosticsByUri = new Map<string, LspDiagnostic[]>();\n\n constructor(options: TypstAnalyzerOptions) {\n this.worker = options.worker ?? createAnalyzerWorker();\n const absoluteWasmUrl = new URL(options.wasmUrl, globalThis.location?.href)\n .href;\n\n // Listen for unsolicited diagnostic push notifications from the worker.\n this.worker.addEventListener(\n \"message\",\n (e: MessageEvent<AnalyzerMessage>) => {\n if (e.data.type === \"diagnostics\" && !(\"id\" in e.data)) {\n const event = e.data as AnalyzerDiagnosticEvent;\n const normalizedUri = normalizeUntitledUri(event.uri);\n this.latestDiagnosticsByUri.set(normalizedUri, event.diagnostics);\n for (const listener of this.diagnosticsListeners) {\n listener(normalizedUri, event.diagnostics);\n }\n }\n },\n );\n\n this.ready = this.rpc(\n { type: \"init\", id: ++this.idCounter, wasmUrl: absoluteWasmUrl },\n TIMEOUT.INIT,\n ).then((res) => {\n if (res.type === \"error\")\n throw new Error(`TypstAnalyzer init failed: ${res.message}`);\n });\n }\n\n /**\n * Register a listener for push-based diagnostics.\n * Returns an unsubscribe function.\n */\n onDiagnostics(listener: DiagnosticsListener): () => void {\n this.diagnosticsListeners.add(listener);\n return () => this.diagnosticsListeners.delete(listener);\n }\n\n /** Returns the latest pushed diagnostics for a URI, if available. */\n getLatestDiagnostics(uri: string): LspDiagnostic[] | undefined {\n return this.latestDiagnosticsByUri.get(normalizeUntitledUri(uri));\n }\n\n private rpc(\n request: AnalyzerRequest,\n timeoutMs: number = TIMEOUT.REQUEST,\n ): Promise<AnalyzerResponse> {\n return workerRpc(this.worker, request, timeoutMs);\n }\n\n async didOpen(uri: string, content: string): Promise<void> {\n await this.ready;\n const res = await this.rpc({\n type: \"didOpen\",\n id: ++this.idCounter,\n uri,\n content,\n });\n if (res.type === \"error\") throw new Error(res.message);\n this.openedUris.add(uri);\n }\n\n /**\n * Notify the analyzer that a document has changed.\n * Diagnostics will arrive asynchronously via `onDiagnostics()` listeners.\n */\n async didChange(uri: string, content: string): Promise<void> {\n await this.ready;\n if (!this.openedUris.has(uri)) {\n await this.didOpen(uri, content);\n return;\n }\n\n const version = ++this.versionCounter;\n const res = await this.rpc({\n type: \"didChange\",\n id: ++this.idCounter,\n uri,\n version,\n content,\n });\n if (res.type === \"error\") throw new Error(res.message);\n }\n\n async completion(\n uri: string,\n line: number,\n character: number,\n ): Promise<unknown> {\n await this.ready;\n const res = await this.rpc({\n type: \"completion\",\n id: ++this.idCounter,\n uri,\n line,\n character,\n });\n if (res.type === \"error\") throw new Error(res.message);\n if (res.type === \"completionResult\") return res.result;\n return null;\n }\n\n async hover(uri: string, line: number, character: number): Promise<unknown> {\n await this.ready;\n const res = await this.rpc({\n type: \"hover\",\n id: ++this.idCounter,\n uri,\n line,\n character,\n });\n if (res.type === \"error\") throw new Error(res.message);\n if (res.type === \"hoverResult\") return res.result;\n return null;\n }\n\n destroy(): void {\n this.diagnosticsListeners.clear();\n this.latestDiagnosticsByUri.clear();\n destroyWorker(\n this.worker,\n { type: \"destroy\" as const, id: ++this.idCounter },\n TIMEOUT.DESTROY,\n \"TypstAnalyzer\",\n );\n }\n}\n","import type { LspDiagnostic } from \"./analyzer-types.js\";\nimport type { TypstAnalyzer } from \"./analyzer.js\";\nimport type { CompileResult, TypstCompiler } from \"./compiler.js\";\nimport { normalizePath, normalizeRoot } from \"./uri.js\";\n\nexport type DiagnosticsSubscriber = (diagnostics: LspDiagnostic[]) => void;\n\nexport interface AnalyzerSessionOptions {\n analyzer: Pick<\n TypstAnalyzer,\n \"ready\" | \"didOpen\" | \"didChange\" | \"completion\" | \"hover\" | \"onDiagnostics\"\n >;\n /** Project root used to build stable in-memory analyzer URIs. Default: \"/project\". */\n rootPath?: string;\n /** Entry file path within the project. Synced last to ensure dependencies load first. Default: \"/main.typ\". */\n entryPath?: string;\n}\n\n/**\n * Synchronizes an in-memory Typst project with a TypstAnalyzer.\n * Handles multi-file ordering, request queueing, and diagnostic subscriptions.\n *\n * Diagnostics arrive via the analyzer's push mechanism and are forwarded\n * to subscribers registered with `subscribe()`.\n *\n * const session = new AnalyzerSession({ analyzer });\n * session.subscribe(\"/main.typ\", (diags) => { ... });\n * await session.sync(\"/main.typ\", source, files);\n */\nexport class AnalyzerSession {\n readonly ready: Promise<void>;\n\n private readonly analyzer: AnalyzerSessionOptions[\"analyzer\"];\n private readonly rootPath: string;\n private readonly entryPath: string;\n private readonly syncedFiles = new Map<string, string>();\n private queue: Promise<void> = Promise.resolve();\n private syncRevision = 0;\n\n // Diagnostic subscription state\n private readonly listenersByUri = new Map<string, Set<DiagnosticsSubscriber>>();\n private readonly diagnosticsByUri = new Map<string, LspDiagnostic[]>();\n private readonly diagnosticsHashByUri = new Map<string, string>();\n private readonly unsubscribeAnalyzer: () => void;\n\n constructor(options: AnalyzerSessionOptions) {\n this.analyzer = options.analyzer;\n this.rootPath = normalizeRoot(options.rootPath ?? \"/project\");\n this.entryPath = normalizePath(options.entryPath ?? \"/main.typ\");\n this.ready = this.analyzer.ready;\n\n this.unsubscribeAnalyzer = this.analyzer.onDiagnostics((uri, diagnostics) => {\n const nextHash = diagnosticsHash(diagnostics);\n if (this.diagnosticsHashByUri.get(uri) === nextHash) return;\n\n this.diagnosticsByUri.set(uri, diagnostics);\n this.diagnosticsHashByUri.set(uri, nextHash);\n\n const listeners = this.listenersByUri.get(uri);\n if (!listeners) return;\n for (const listener of listeners) listener(diagnostics);\n });\n }\n\n /** Build a tinymist URI from a project-relative path. */\n toUri(path: string): string {\n const root = this.rootPath.replace(/^\\//, \"\");\n return `untitled:${root}${normalizePath(path)}`;\n }\n\n /**\n * Subscribe to push-based diagnostics for a file path.\n * Returns an unsubscribe function. Replays cached diagnostics immediately.\n */\n subscribe(path: string, listener: DiagnosticsSubscriber): () => void {\n const uri = this.toUri(path);\n\n let listeners = this.listenersByUri.get(uri);\n if (!listeners) {\n listeners = new Set();\n this.listenersByUri.set(uri, listeners);\n }\n listeners.add(listener);\n\n const cached = this.diagnosticsByUri.get(uri);\n if (cached) listener(cached);\n\n return () => {\n const current = this.listenersByUri.get(uri);\n if (!current) return;\n current.delete(listener);\n if (current.size === 0) this.listenersByUri.delete(uri);\n };\n }\n\n /**\n * Sync all project files with the analyzer, then notify it of the active file change.\n * Diagnostics will arrive asynchronously via subscribers registered with `subscribe()`.\n */\n async sync(\n path: string,\n content: string,\n files: Record<string, string>,\n ): Promise<void> {\n ++this.syncRevision;\n const activePath = normalizePath(path);\n const mergedFiles = { ...files, [activePath]: content };\n\n await this.enqueue(async () => {\n await this.ready;\n\n // Sync non-active files first (dependencies), then the active file last\n // to trigger tinymist diagnostics.\n for (const filePath of this.orderedPaths(mergedFiles)) {\n if (filePath === activePath) continue;\n await this.syncFile(filePath, mergedFiles[filePath], false);\n }\n\n // Active file always uses didOpen to trigger tinymist compilation.\n await this.syncFile(activePath, mergedFiles[activePath], true);\n\n // Clean up files that were removed from the project.\n for (const filePath of this.syncedFiles.keys()) {\n if (!Object.hasOwn(mergedFiles, filePath)) {\n this.syncedFiles.delete(filePath);\n }\n }\n });\n }\n\n /**\n * Sync files, then compile with the provided compiler.\n * Diagnostics come from the analyzer (push-based); the compiler provides preview artifacts.\n */\n async syncAndCompile(\n path: string,\n content: string,\n files: Record<string, string>,\n compiler: TypstCompiler,\n onCompile?: (result: CompileResult) => void,\n signal?: AbortSignal,\n ): Promise<void> {\n await this.sync(path, content, files);\n if (signal?.aborted) return;\n\n try {\n const result = await compiler.compile(files);\n if (signal?.aborted) return;\n onCompile?.(result);\n } catch {\n // Analyzer push diagnostics are authoritative; compiler errors are non-fatal.\n }\n }\n\n /**\n * Sync files and request completions at the given position.\n * Returns the raw LSP CompletionList/CompletionItem[] from tinymist.\n */\n async completion(\n path: string,\n content: string,\n files: Record<string, string>,\n line: number,\n character: number,\n ): Promise<unknown> {\n const enqueuedRevision = this.syncRevision;\n const activePath = normalizePath(path);\n const mergedFiles = { ...files, [activePath]: content };\n\n return this.enqueue(async () => {\n if (enqueuedRevision !== this.syncRevision) return null;\n\n await this.ready;\n for (const filePath of this.orderedPaths(mergedFiles)) {\n if (filePath === activePath) continue;\n await this.syncFile(filePath, mergedFiles[filePath], false);\n }\n await this.syncFile(activePath, mergedFiles[activePath], false);\n\n return this.analyzer.completion(\n this.toUri(activePath),\n line,\n character,\n );\n });\n }\n\n /**\n * Sync files and request hover info at the given position.\n * Returns the raw LSP Hover result from tinymist.\n */\n async hover(\n path: string,\n content: string,\n files: Record<string, string>,\n line: number,\n character: number,\n ): Promise<unknown> {\n const enqueuedRevision = this.syncRevision;\n const activePath = normalizePath(path);\n const mergedFiles = { ...files, [activePath]: content };\n\n return this.enqueue(async () => {\n if (enqueuedRevision !== this.syncRevision) return null;\n\n await this.ready;\n for (const filePath of this.orderedPaths(mergedFiles)) {\n if (filePath === activePath) continue;\n await this.syncFile(filePath, mergedFiles[filePath], false);\n }\n await this.syncFile(activePath, mergedFiles[activePath], false);\n\n return this.analyzer.hover(this.toUri(activePath), line, character);\n });\n }\n\n destroy(): void {\n this.unsubscribeAnalyzer();\n this.listenersByUri.clear();\n this.diagnosticsByUri.clear();\n this.diagnosticsHashByUri.clear();\n }\n\n /**\n * Sync a single file with the analyzer.\n * @param forceOpen - Always use didOpen (triggers tinymist diagnostics for the active file).\n */\n private async syncFile(\n path: string,\n content: string,\n forceOpen: boolean,\n ): Promise<void> {\n const prev = this.syncedFiles.get(path);\n\n if (forceOpen || prev == null) {\n await this.analyzer.didOpen(this.toUri(path), content);\n this.syncedFiles.set(path, content);\n return;\n }\n\n if (prev !== content) {\n await this.analyzer.didChange(this.toUri(path), content);\n this.syncedFiles.set(path, content);\n }\n }\n\n private orderedPaths(files: Record<string, string>): string[] {\n return Object.keys(files)\n .map((p) => normalizePath(p))\n .sort((a, b) => {\n if (a === this.entryPath) return 1;\n if (b === this.entryPath) return -1;\n return a.localeCompare(b);\n });\n }\n\n private enqueue<T>(task: () => Promise<T>): Promise<T> {\n const run = this.queue.then(task, task);\n this.queue = run.then(\n () => undefined,\n () => undefined,\n );\n return run;\n }\n}\n\nfunction diagnosticsHash(diagnostics: LspDiagnostic[]): string {\n return JSON.stringify(\n diagnostics.map((d) => [\n d.range.start.line,\n d.range.start.character,\n d.range.end.line,\n d.range.end.character,\n d.severity ?? 1,\n d.message,\n d.source ?? \"\",\n ]),\n );\n}\n","import { createWorker, destroyWorker, workerRpc } from \"./rpc.js\";\nimport type {\n DiagnosticMessage,\n WorkerRequest,\n WorkerResponse,\n} from \"./types.js\";\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 * `new TypstCompiler({ worker: new Worker(new URL('typst-web-service/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 =\n \"https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-web-compiler@0.7.0-rc2/pkg/typst_ts_web_compiler_bg.wasm\";\n\nconst TIMEOUT = { INIT: 60_000, RENDER: 60_000, DESTROY: 5_000 } as const;\n\nfunction toFiles(\n source: string | Record<string, string>,\n): Record<string, string> {\n return typeof source === \"string\" ? { \"/main.typ\": source } : source;\n}\n\n/**\n * Manages a Typst compiler worker. Create one instance and share it across\n * all extensions (linter, autocomplete, preview, etc.).\n *\n * new TypstCompiler() // blob worker, defaults\n * new TypstCompiler({ wasmUrl: '...' }) // blob worker, custom WASM\n * new TypstCompiler({ worker: myWorker }) // explicit Worker (Vite)\n * new TypstCompiler({ worker: myWorker, fonts: [...] }) // explicit Worker + options\n */\nexport class TypstCompiler {\n readonly ready: Promise<void>;\n private idCounter = 0;\n private worker: Worker;\n\n /** The most recent vector artifact from a compile, if any. */\n lastVector?: Uint8Array;\n\n constructor(options: TypstCompilerOptions = {}) {\n this.worker = options.worker ?? createWorker();\n\n this.ready = workerRpc<WorkerRequest, WorkerResponse>(\n this.worker,\n {\n type: \"init\",\n id: ++this.idCounter,\n wasmUrl: options.wasmUrl ?? DEFAULT_WASM_URL,\n fonts: options.fonts ?? DEFAULT_FONTS,\n packages: options.packages ?? true,\n },\n TIMEOUT.INIT,\n ).then((res) => {\n if (res.type === \"error\")\n throw new Error(`TypstCompiler init failed: ${res.message}`);\n });\n }\n\n /** Compile a single source string (treated as /main.typ) or a map of files. */\n async compile(\n source: string | Record<string, string>,\n ): Promise<CompileResult> {\n await this.ready;\n const id = ++this.idCounter;\n const files = toFiles(source);\n const response = await workerRpc<WorkerRequest, WorkerResponse>(\n this.worker,\n {\n type: \"compile\",\n id,\n files,\n },\n );\n if (response.type === \"cancelled\") return { diagnostics: [] };\n if (response.type === \"result\") {\n const vector = response.vector\n ? new Uint8Array(response.vector)\n : undefined;\n if (vector) this.lastVector = vector;\n return { diagnostics: response.diagnostics, vector };\n }\n if (response.type === \"error\") throw new Error(response.message);\n return { diagnostics: [] };\n }\n\n /** Compile to PDF from a single source string (treated as /main.typ) or a map of files. */\n async compilePdf(\n source: string | Record<string, string>,\n ): Promise<Uint8Array> {\n await this.ready;\n const id = ++this.idCounter;\n const files = toFiles(source);\n const response = await workerRpc<WorkerRequest, WorkerResponse>(\n this.worker,\n { type: \"render\", id, files },\n TIMEOUT.RENDER,\n );\n if (response.type === \"cancelled\") throw new Error(\"Render cancelled\");\n if (response.type === \"pdf\") return new Uint8Array(response.data);\n if (response.type === \"error\") throw new Error(response.message);\n throw new Error(\"Unexpected response type\");\n }\n\n destroy(): void {\n const id = ++this.idCounter;\n destroyWorker(\n this.worker,\n { type: \"destroy\" as const, id },\n TIMEOUT.DESTROY,\n \"TypstCompiler\",\n );\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 // Reset so subsequent calls can retry\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 *\n * const formatter = new TypstFormatter({ tab_spaces: 2, max_width: 80 });\n * const formatted = await formatter.format(source);\n */\nexport class TypstFormatter {\n private config: FormatConfig;\n\n 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 /** 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","/** Minimal interface for the built TypstRenderer instance. */\nexport interface RendererInstance {\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\nconst DEFAULT_RENDERER_WASM_URL =\n \"https://cdn.jsdelivr.net/npm/@myriaddreamin/typst-ts-renderer@0.7.0-rc2/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\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 = new TypstRenderer();\n * const svg = await renderer.renderSvg(vector);\n */\nexport class TypstRenderer {\n private wasmUrl: string;\n private instance: Promise<RendererInstance> | null = null;\n\n 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 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(this.wasmUrl);\n return new mod.TypstRendererBuilder().build();\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"],"mappings":"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","names":["TIMEOUT"]}
|