@vutex/vutex 0.0.14 → 0.0.17
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/licenses/NotoSansMono.OFL.md +93 -0
- package/licenses/NotoSerifSC.OFL.md +94 -0
- package/licenses/Tinos.OFL.md +93 -0
- package/locales/en-US/cli.json +5 -4
- package/package.json +8 -7
- package/readme.md +29 -3
- package/src/cli/commands/package.ts +41 -12
- package/src/cli/commands/render.ts +5 -1
- package/src/index.ts +3 -0
- package/src/node/load.ts +18 -22
- package/src/packages/builtin.ts +129 -0
- package/src/packages/lockfile.ts +33 -1
- package/src/packages/manager.ts +1125 -64
- package/src/packages/manifest.ts +45 -0
- package/src/packages/math_font.ts +63 -0
- package/src/packages/registry.ts +405 -0
- package/src/packages/template.ts +352 -0
- package/src/runtime.ts +387 -37
- package/src/types.ts +173 -15
package/src/runtime.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { dirname, extname, resolve } from "node:path";
|
|
3
|
+
|
|
1
4
|
import type {
|
|
5
|
+
ActivatedPackage,
|
|
2
6
|
CreateVuTeXOptions,
|
|
3
7
|
FormulaRender,
|
|
4
8
|
FormulaRenderOptions,
|
|
@@ -6,12 +10,22 @@ import type {
|
|
|
6
10
|
InspectDocumentResult,
|
|
7
11
|
RenderDocumentOptions,
|
|
8
12
|
RenderDocumentResult,
|
|
13
|
+
TemplateGeometry,
|
|
9
14
|
VuTeXBindings,
|
|
10
15
|
VuTeXDiagnostic,
|
|
11
16
|
VuTeXRuntime,
|
|
12
17
|
} from "./types.js";
|
|
13
18
|
import { PackageManager } from "./packages/manager.js";
|
|
14
19
|
import { readManifest } from "./packages/manifest.js";
|
|
20
|
+
import { readMathFontFace } from "./packages/math_font.js";
|
|
21
|
+
import { readTemplateGeometry } from "./packages/template.js";
|
|
22
|
+
|
|
23
|
+
type ParsedPayload = {
|
|
24
|
+
ok: boolean;
|
|
25
|
+
format: string;
|
|
26
|
+
graph?: unknown;
|
|
27
|
+
diagnostics?: VuTeXDiagnostic[];
|
|
28
|
+
};
|
|
15
29
|
|
|
16
30
|
function encodeFormulaOptions(options?: FormulaRenderOptions): string | undefined {
|
|
17
31
|
if (!options) {
|
|
@@ -32,58 +46,394 @@ function normalizeOutputFormat(value: string | undefined): string {
|
|
|
32
46
|
return typeof value === "string" && value.length > 0 ? value : "svg";
|
|
33
47
|
}
|
|
34
48
|
|
|
35
|
-
function
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
49
|
+
function formatFromPath(inputPath: string): string {
|
|
50
|
+
const extension = extname(inputPath).slice(1).toLowerCase();
|
|
51
|
+
switch (extension) {
|
|
52
|
+
case "md":
|
|
53
|
+
case "markdown":
|
|
54
|
+
return "markdown";
|
|
55
|
+
case "nd":
|
|
56
|
+
case "notedown":
|
|
57
|
+
return "notedown";
|
|
58
|
+
case "html":
|
|
59
|
+
case "htm":
|
|
60
|
+
return "html";
|
|
61
|
+
case "tex":
|
|
62
|
+
case "latex":
|
|
63
|
+
case "ltx":
|
|
64
|
+
return "tex";
|
|
65
|
+
case "typ":
|
|
66
|
+
case "typst":
|
|
67
|
+
return "typst";
|
|
68
|
+
case "docx":
|
|
69
|
+
return "docx";
|
|
70
|
+
case "epub":
|
|
71
|
+
return "epub";
|
|
72
|
+
default:
|
|
73
|
+
return "unknown";
|
|
43
74
|
}
|
|
44
75
|
}
|
|
45
76
|
|
|
77
|
+
function diagnostic(code: string, message: string, stage: string, path?: string): VuTeXDiagnostic {
|
|
78
|
+
return { code, severity: "error", message, stage, path };
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function byteLength(value: string): number {
|
|
82
|
+
return new TextEncoder().encode(value).length;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function readBytes(inputPath: string): Promise<Uint8Array> {
|
|
86
|
+
return readFile(resolve(inputPath)).then((buffer) => new Uint8Array(buffer));
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** Theme presets the native scene knows how to lay out. */
|
|
90
|
+
const NATIVE_THEMES = new Set(["baseline", "traditional", "editorial", "classic"]);
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Built-in math packages that install one OpenType MATH family.
|
|
94
|
+
*
|
|
95
|
+
* The native binding owns the same mapping, so an id outside this set fails
|
|
96
|
+
* closed instead of painting a face the document never declared.
|
|
97
|
+
*/
|
|
98
|
+
const NATIVE_MATH_FONTS = new Set(["latin-modern-math", "xits-math"]);
|
|
99
|
+
|
|
100
|
+
function activatedSlot(activation: ActivatedPackage[], slot: string): ActivatedPackage | undefined {
|
|
101
|
+
return activation.find((item) => item.slot === slot);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Compose the native primitives into one render call.
|
|
106
|
+
*
|
|
107
|
+
* The runtime owns orchestration only: it reads the input bytes, selects the
|
|
108
|
+
* format, chains parse -> lower -> build -> emit, and assembles the report.
|
|
109
|
+
* Font embedding happens inside the emission primitives, so this file never
|
|
110
|
+
* names a face.
|
|
111
|
+
*/
|
|
46
112
|
export function createVuTeXRuntime(
|
|
47
113
|
bindings: VuTeXBindings,
|
|
48
114
|
options: CreateVuTeXOptions = {},
|
|
49
115
|
): VuTeXRuntime {
|
|
50
116
|
const projectRoot = options.projectRoot ?? process.cwd();
|
|
51
117
|
const packages = new PackageManager(projectRoot);
|
|
118
|
+
const defaults = options.defaults ?? {};
|
|
52
119
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
120
|
+
async function render(inputPath: string, renderOptions: RenderDocumentOptions = {}): Promise<RenderDocumentResult> {
|
|
121
|
+
const manifest = await readManifest(projectRoot);
|
|
122
|
+
const outputFormat = normalizeOutputFormat(renderOptions.output ?? manifest?.document?.output);
|
|
123
|
+
const inputFormat = renderOptions.input ?? manifest?.document?.input ?? defaults.input ?? formatFromPath(inputPath);
|
|
124
|
+
const explicitTheme = typeof renderOptions.theme === "string" && renderOptions.theme.length > 0
|
|
125
|
+
? renderOptions.theme
|
|
126
|
+
: undefined;
|
|
127
|
+
const inputs = JSON.stringify([{ path: inputPath, format: inputFormat }]);
|
|
128
|
+
const activation = await packages.activation();
|
|
129
|
+
const activationErrors = activation.diagnostics.filter((item) => item.severity === "error");
|
|
130
|
+
if (activationErrors.length > 0) {
|
|
63
131
|
return {
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
pdf: response.pdf,
|
|
69
|
-
reportJson: response.reportJson,
|
|
70
|
-
diagnostics: diagnosticsFromReport(response.reportJson),
|
|
132
|
+
outputFormat,
|
|
133
|
+
reportJson: bindings.assembleReport("render", inputs, JSON.stringify(activation.diagnostics)),
|
|
134
|
+
diagnostics: activation.diagnostics,
|
|
135
|
+
packages: [],
|
|
71
136
|
};
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
const fail = (item: VuTeXDiagnostic): RenderDocumentResult => {
|
|
140
|
+
const items = [...activation.diagnostics, item];
|
|
75
141
|
return {
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
142
|
+
outputFormat,
|
|
143
|
+
reportJson: bindings.assembleReport("render", inputs, JSON.stringify(items)),
|
|
144
|
+
diagnostics: items,
|
|
145
|
+
packages: activation.packages,
|
|
80
146
|
};
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// A declared slot must change what the renderer does. `theme` and
|
|
150
|
+
// `math-font` have native consumers, so an unusable value fails the
|
|
151
|
+
// render instead of silently painting the built-in baseline.
|
|
152
|
+
const themePackage = activatedSlot(activation.packages, "theme");
|
|
153
|
+
const theme = explicitTheme ?? themePackage?.name ?? defaults.theme;
|
|
154
|
+
if (theme !== undefined && !NATIVE_THEMES.has(theme)) {
|
|
155
|
+
return fail(
|
|
156
|
+
diagnostic(
|
|
157
|
+
"VUTEX_PACKAGE_THEME_UNSUPPORTED",
|
|
158
|
+
`theme package has no native preset: ${theme}`,
|
|
159
|
+
"package",
|
|
160
|
+
inputPath,
|
|
161
|
+
),
|
|
162
|
+
);
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
const mathPackage = activatedSlot(activation.packages, "math-font");
|
|
166
|
+
const bundledMath = mathPackage !== undefined
|
|
167
|
+
&& mathPackage.source === "builtin"
|
|
168
|
+
&& NATIVE_MATH_FONTS.has(mathPackage.name);
|
|
169
|
+
if (mathPackage !== undefined && !bundledMath) {
|
|
170
|
+
if (mathPackage.path === undefined) {
|
|
171
|
+
return fail(
|
|
172
|
+
diagnostic(
|
|
173
|
+
"VUTEX_PACKAGE_MATH_FONT_UNSUPPORTED",
|
|
174
|
+
`math font package has no resource directory: ${mathPackage.name}`,
|
|
175
|
+
"package",
|
|
176
|
+
inputPath,
|
|
177
|
+
),
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
// Reflowed html keeps formulas as markup, so the warning below is
|
|
181
|
+
// the whole record for that format and the face is never installed.
|
|
182
|
+
if (outputFormat !== "html") {
|
|
183
|
+
const face = await readMathFontFace(mathPackage.path);
|
|
184
|
+
if (face.diagnostic !== undefined) {
|
|
185
|
+
return fail(face.diagnostic);
|
|
186
|
+
}
|
|
187
|
+
if (face.file === undefined) {
|
|
188
|
+
return fail(
|
|
189
|
+
diagnostic(
|
|
190
|
+
"VUTEX_PACKAGE_MATH_FONT_INVALID",
|
|
191
|
+
`math font package ${mathPackage.name} names no font file`,
|
|
192
|
+
"package",
|
|
193
|
+
inputPath,
|
|
194
|
+
),
|
|
195
|
+
);
|
|
196
|
+
}
|
|
197
|
+
let faceBytes: Uint8Array;
|
|
198
|
+
try {
|
|
199
|
+
faceBytes = await readBytes(face.file);
|
|
200
|
+
} catch {
|
|
201
|
+
return fail(
|
|
202
|
+
diagnostic(
|
|
203
|
+
"VUTEX_PACKAGE_MATH_FONT_INVALID",
|
|
204
|
+
`math font package ${mathPackage.name} has no readable font file`,
|
|
205
|
+
"package",
|
|
206
|
+
inputPath,
|
|
207
|
+
),
|
|
208
|
+
);
|
|
209
|
+
}
|
|
210
|
+
if (
|
|
211
|
+
face.texParameters !== undefined
|
|
212
|
+
&& !bindings.mathFontTexParameterFamilies().includes(face.texParameters)
|
|
213
|
+
) {
|
|
214
|
+
return fail(
|
|
215
|
+
diagnostic(
|
|
216
|
+
"VUTEX_PACKAGE_MATH_FONT_SEMANTICS_UNKNOWN",
|
|
217
|
+
`math font package ${mathPackage.name} declares unknown TeX parameter family: ${face.texParameters}`,
|
|
218
|
+
"package",
|
|
219
|
+
inputPath,
|
|
220
|
+
),
|
|
221
|
+
);
|
|
222
|
+
}
|
|
223
|
+
try {
|
|
224
|
+
bindings.installMathFontFace(
|
|
225
|
+
mathPackage.name,
|
|
226
|
+
mathPackage.artifactHash ?? "",
|
|
227
|
+
faceBytes,
|
|
228
|
+
face.texParameters,
|
|
229
|
+
);
|
|
230
|
+
} catch (failure) {
|
|
231
|
+
return fail(
|
|
232
|
+
diagnostic(
|
|
233
|
+
"VUTEX_PACKAGE_MATH_FONT_INVALID",
|
|
234
|
+
failure instanceof Error ? failure.message : String(failure),
|
|
235
|
+
"package",
|
|
236
|
+
inputPath,
|
|
237
|
+
),
|
|
238
|
+
);
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
const mathFont = mathPackage?.name ?? defaults.mathFont;
|
|
243
|
+
|
|
244
|
+
let bytes: Uint8Array;
|
|
245
|
+
try {
|
|
246
|
+
bytes = await readBytes(inputPath);
|
|
247
|
+
} catch {
|
|
248
|
+
return fail(diagnostic("VUTEX_INPUT_NOT_FOUND", `input path does not exist: ${inputPath}`, "read", inputPath));
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
let parsed: ParsedPayload;
|
|
252
|
+
try {
|
|
253
|
+
parsed = JSON.parse(bindings.parseDocument(inputPath, inputFormat, bytes)) as ParsedPayload;
|
|
254
|
+
} catch (failure) {
|
|
255
|
+
const message = failure instanceof Error ? failure.message : String(failure);
|
|
256
|
+
return fail(diagnostic("VUTEX_IMPORT_FAILED", message, "import", inputPath));
|
|
257
|
+
}
|
|
258
|
+
if (!parsed.ok || parsed.graph === undefined) {
|
|
259
|
+
const items = parsed.diagnostics ?? [];
|
|
260
|
+
const first = items[0] ?? diagnostic("VUTEX_IMPORT_FAILED", "import produced no graph", "import", inputPath);
|
|
261
|
+
return {
|
|
262
|
+
outputFormat,
|
|
263
|
+
reportJson: bindings.assembleReport("render", inputs, JSON.stringify(items)),
|
|
264
|
+
diagnostics: items.length > 0 ? items : [first],
|
|
265
|
+
packages: activation.packages,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
if (!["svg", "html", "snapshot", "pdf"].includes(outputFormat)) {
|
|
270
|
+
return fail(
|
|
271
|
+
diagnostic("VUTEX_OUTPUT_FORMAT_UNSUPPORTED", `unsupported output format: ${outputFormat}`, "render", inputPath),
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const graphJson = JSON.stringify(parsed.graph);
|
|
276
|
+
const diagnostics: VuTeXDiagnostic[] = [
|
|
277
|
+
...(parsed.diagnostics ?? []),
|
|
278
|
+
...activation.diagnostics,
|
|
279
|
+
];
|
|
280
|
+
const templatePackage = activatedSlot(activation.packages, "template");
|
|
281
|
+
let templateApplied: string | undefined;
|
|
282
|
+
let templateGeometry: TemplateGeometry | undefined;
|
|
283
|
+
if (templatePackage !== undefined) {
|
|
284
|
+
// Reflowed html has no fixed pages, so a page template has nothing
|
|
285
|
+
// to act on and only the warning records the gap.
|
|
286
|
+
if (outputFormat === "html") {
|
|
287
|
+
diagnostics.push({
|
|
288
|
+
code: "VUTEX_PACKAGE_TEMPLATE_INACTIVE",
|
|
289
|
+
severity: "warning",
|
|
290
|
+
message: `reflowed html has no fixed pages, so template ${templatePackage.name} does not apply`,
|
|
291
|
+
stage: "package",
|
|
292
|
+
args: { slot: "template", package: templatePackage.name },
|
|
293
|
+
});
|
|
294
|
+
} else {
|
|
295
|
+
if (templatePackage.path === undefined) {
|
|
296
|
+
return fail(
|
|
297
|
+
diagnostic(
|
|
298
|
+
"VUTEX_PACKAGE_TEMPLATE_UNSUPPORTED",
|
|
299
|
+
`template package has no resource directory: ${templatePackage.name}`,
|
|
300
|
+
"package",
|
|
301
|
+
inputPath,
|
|
302
|
+
),
|
|
303
|
+
);
|
|
304
|
+
}
|
|
305
|
+
const read = await readTemplateGeometry(templatePackage.path);
|
|
306
|
+
if (read.diagnostic !== undefined) {
|
|
307
|
+
return fail(read.diagnostic);
|
|
308
|
+
}
|
|
309
|
+
templateGeometry = read.geometry;
|
|
310
|
+
templateApplied = templatePackage.name;
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
let mathFontApplied: string | undefined;
|
|
314
|
+
try {
|
|
315
|
+
const lowered = bindings.lowerDocument(graphJson, inputPath);
|
|
316
|
+
const footnotes = JSON.parse(lowered.footnotesJson()) as Record<string, number>;
|
|
317
|
+
diagnostics.push(...(JSON.parse(lowered.diagnosticsJson()) as VuTeXDiagnostic[]));
|
|
318
|
+
|
|
319
|
+
let svg: string | undefined;
|
|
320
|
+
let html: string | undefined;
|
|
321
|
+
let pdf: Uint8Array | undefined;
|
|
322
|
+
let outputFormatLabel = outputFormat;
|
|
323
|
+
let pages: number | undefined;
|
|
324
|
+
let items: number | undefined;
|
|
325
|
+
|
|
326
|
+
if (outputFormat === "html") {
|
|
327
|
+
const flow = bindings.buildFlow(lowered.graphJson(), theme);
|
|
328
|
+
html = flow.html();
|
|
329
|
+
if (mathPackage !== undefined && mathFont !== undefined) {
|
|
330
|
+
diagnostics.push({
|
|
331
|
+
code: "VUTEX_PACKAGE_MATH_FONT_INACTIVE",
|
|
332
|
+
severity: "warning",
|
|
333
|
+
message: `reflowed html keeps formulas as markup, so ${mathFont} does not apply`,
|
|
334
|
+
stage: "package",
|
|
335
|
+
args: { slot: "math-font", package: mathFont },
|
|
336
|
+
});
|
|
337
|
+
}
|
|
338
|
+
} else {
|
|
339
|
+
const scene = bindings.buildDisplay(lowered, theme, mathFont, templateGeometry);
|
|
340
|
+
mathFontApplied = scene.mathFontId();
|
|
341
|
+
pages = scene.pageCount();
|
|
342
|
+
items = scene.itemCount();
|
|
343
|
+
diagnostics.push(...(JSON.parse(scene.diagnosticsJson()) as VuTeXDiagnostic[]));
|
|
344
|
+
if (outputFormat === "svg") {
|
|
345
|
+
svg = scene.svg();
|
|
346
|
+
} else if (outputFormat === "snapshot") {
|
|
347
|
+
html = scene.snapshotHtml();
|
|
348
|
+
} else {
|
|
349
|
+
const rendered = scene.pdf(JSON.stringify({
|
|
350
|
+
base_dir: renderOptions.baseDir ?? dirname(resolve(inputPath)),
|
|
351
|
+
resources: renderOptions.resources,
|
|
352
|
+
}));
|
|
353
|
+
pdf = new Uint8Array(rendered.pdf);
|
|
354
|
+
diagnostics.push(...(JSON.parse(rendered.diagnosticsJson) as VuTeXDiagnostic[]));
|
|
355
|
+
}
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
const bodyBytes = outputFormat === "pdf" ? (pdf?.byteLength ?? 0) : byteLength(svg ?? html ?? "");
|
|
359
|
+
const reportJson = bindings.assembleReport(
|
|
360
|
+
"render",
|
|
361
|
+
inputs,
|
|
362
|
+
JSON.stringify(diagnostics),
|
|
363
|
+
JSON.stringify({
|
|
364
|
+
format: outputFormatLabel,
|
|
365
|
+
bytes: bodyBytes,
|
|
366
|
+
...(pages === undefined ? {} : { pages, items }),
|
|
367
|
+
}),
|
|
368
|
+
JSON.stringify({
|
|
369
|
+
footnotes,
|
|
370
|
+
theme: theme ?? "baseline",
|
|
371
|
+
mathFont: mathFontApplied,
|
|
372
|
+
template: templateApplied,
|
|
373
|
+
packages: activation.packages,
|
|
374
|
+
}),
|
|
375
|
+
);
|
|
376
|
+
|
|
377
|
+
return {
|
|
378
|
+
outputFormat: outputFormatLabel,
|
|
379
|
+
svg,
|
|
380
|
+
html,
|
|
381
|
+
pdf,
|
|
382
|
+
reportJson,
|
|
383
|
+
diagnostics,
|
|
384
|
+
packages: activation.packages,
|
|
385
|
+
};
|
|
386
|
+
} catch (failure) {
|
|
387
|
+
const message = failure instanceof Error ? failure.message : String(failure);
|
|
388
|
+
const item = diagnostic("VUTEX_RENDER_FAILED", message, "render", inputPath);
|
|
389
|
+
diagnostics.push(item);
|
|
390
|
+
return {
|
|
391
|
+
outputFormat,
|
|
392
|
+
reportJson: bindings.assembleReport("render", inputs, JSON.stringify(diagnostics)),
|
|
393
|
+
diagnostics,
|
|
394
|
+
packages: activation.packages,
|
|
395
|
+
};
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
async function inspect(inputPath: string, _options: InspectDocumentOptions = {}): Promise<InspectDocumentResult> {
|
|
400
|
+
const inputFormat = formatFromPath(inputPath);
|
|
401
|
+
const inputs = JSON.stringify([{ path: inputPath, format: inputFormat }]);
|
|
402
|
+
let bytes: Uint8Array;
|
|
403
|
+
try {
|
|
404
|
+
bytes = await readBytes(inputPath);
|
|
405
|
+
} catch {
|
|
406
|
+
const item = diagnostic("VUTEX_INPUT_NOT_FOUND", `input path does not exist: ${inputPath}`, "inspect", inputPath);
|
|
407
|
+
return {
|
|
408
|
+
inputFormat,
|
|
409
|
+
path: inputPath,
|
|
410
|
+
reportJson: bindings.assembleReport("inspect", inputs, JSON.stringify([item])),
|
|
411
|
+
diagnostics: [item],
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
const parsed = JSON.parse(bindings.parseDocument(inputPath, inputFormat, bytes)) as ParsedPayload;
|
|
416
|
+
const diagnostics = parsed.diagnostics ?? [];
|
|
417
|
+
const extra = parsed.ok && parsed.graph !== undefined
|
|
418
|
+
? bindings.summarizeDocument(JSON.stringify(parsed.graph))
|
|
419
|
+
: undefined;
|
|
420
|
+
return {
|
|
421
|
+
inputFormat: parsed.format,
|
|
422
|
+
path: inputPath,
|
|
423
|
+
reportJson: bindings.assembleReport("inspect", inputs, JSON.stringify(diagnostics), undefined, extra),
|
|
424
|
+
diagnostics,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
return {
|
|
429
|
+
version: () => bindings.vutexVersion(),
|
|
430
|
+
render,
|
|
431
|
+
inspect,
|
|
432
|
+
measureFormula(source, formulaOptions) {
|
|
433
|
+
return decodeFormulaRender(bindings.measureFormula(source, encodeFormulaOptions(formulaOptions)));
|
|
81
434
|
},
|
|
82
|
-
|
|
83
|
-
return decodeFormulaRender(bindings.
|
|
84
|
-
},
|
|
85
|
-
renderFormula(source, options) {
|
|
86
|
-
return decodeFormulaRender(bindings.renderFormula(source, encodeFormulaOptions(options)));
|
|
435
|
+
renderFormula(source, formulaOptions) {
|
|
436
|
+
return decodeFormulaRender(bindings.renderFormula(source, encodeFormulaOptions(formulaOptions)));
|
|
87
437
|
},
|
|
88
438
|
packages: {
|
|
89
439
|
list: () => packages.list(),
|