@lofcz/tikz 0.2.2 → 0.2.4
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/NOTICE.md +3 -1
- package/README.md +21 -2
- package/package.json +1 -1
- package/runtime/.build-key +1 -0
- package/runtime/dist/bundles/cm-tfm/chunks/0.br +0 -0
- package/runtime/dist/bundles/cm-tfm/chunks/1.br +0 -0
- package/runtime/dist/bundles/cm-tfm/chunks/2.br +0 -0
- package/runtime/dist/bundles/cm-tfm/chunks/3.br +0 -0
- package/runtime/dist/bundles/cm-tfm/chunks/4.br +0 -0
- package/runtime/dist/bundles/cm-tfm/chunks/5.br +0 -0
- package/runtime/dist/bundles/cm-tfm/chunks/6.br +0 -0
- package/runtime/dist/bundles/cm-tfm/chunks/7.br +0 -0
- package/runtime/dist/bundles/cm-tfm/files.index.json +1 -1
- package/runtime/dist/bundles/cm-type1/chunks/0.br +0 -0
- package/runtime/dist/bundles/cm-type1/chunks/1.br +0 -0
- package/runtime/dist/bundles/cm-type1/chunks/10.br +0 -0
- package/runtime/dist/bundles/cm-type1/chunks/11.br +0 -0
- package/runtime/dist/bundles/cm-type1/chunks/2.br +0 -0
- package/runtime/dist/bundles/cm-type1/chunks/3.br +0 -0
- package/runtime/dist/bundles/cm-type1/chunks/4.br +0 -0
- package/runtime/dist/bundles/cm-type1/chunks/5.br +0 -0
- package/runtime/dist/bundles/cm-type1/chunks/6.br +0 -0
- package/runtime/dist/bundles/cm-type1/chunks/7.br +0 -0
- package/runtime/dist/bundles/cm-type1/chunks/8.br +0 -0
- package/runtime/dist/bundles/cm-type1/chunks/9.br +0 -0
- package/runtime/dist/bundles/cm-type1/files.index.json +1 -1
- package/runtime/dist/bundles/core/chunks/0.br +0 -0
- package/runtime/dist/bundles/core/chunks/1.br +0 -0
- package/runtime/dist/bundles/core/chunks/2.br +0 -0
- package/runtime/dist/bundles/core/chunks/3.br +0 -0
- package/runtime/dist/bundles/core/files.index.json +1 -1
- package/runtime/dist/bundles/filesystem.json +1 -1
- package/runtime/dist/bundles/latex-core/chunks/0.br +0 -0
- package/runtime/dist/bundles/latex-core/chunks/1.br +0 -0
- package/runtime/dist/bundles/latex-core/chunks/10.br +0 -0
- package/runtime/dist/bundles/latex-core/chunks/2.br +0 -0
- package/runtime/dist/bundles/latex-core/chunks/3.br +0 -0
- package/runtime/dist/bundles/latex-core/chunks/4.br +0 -0
- package/runtime/dist/bundles/latex-core/chunks/5.br +0 -0
- package/runtime/dist/bundles/latex-core/chunks/6.br +0 -0
- package/runtime/dist/bundles/latex-core/chunks/7.br +0 -0
- package/runtime/dist/bundles/latex-core/chunks/8.br +0 -0
- package/runtime/dist/bundles/latex-core/chunks/9.br +0 -0
- package/runtime/dist/bundles/latex-core/files.index.json +1 -1
- package/runtime/dist/bundles/latex-extra/chunks/0.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/1.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/10.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/11.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/12.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/13.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/14.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/15.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/16.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/17.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/18.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/19.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/2.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/20.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/21.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/22.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/23.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/24.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/25.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/26.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/27.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/3.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/4.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/5.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/6.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/7.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/8.br +0 -0
- package/runtime/dist/bundles/latex-extra/chunks/9.br +0 -0
- package/runtime/dist/bundles/latex-extra/files.index.json +1 -1
- package/runtime/dist/bundles/lm-fonts/chunks/0.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/1.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/10.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/11.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/12.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/13.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/14.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/15.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/16.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/17.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/18.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/19.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/2.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/20.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/21.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/22.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/23.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/24.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/25.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/26.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/27.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/28.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/29.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/3.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/4.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/5.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/6.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/7.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/8.br +0 -0
- package/runtime/dist/bundles/lm-fonts/chunks/9.br +0 -0
- package/runtime/dist/bundles/lm-fonts/files.index.json +1 -1
- package/runtime/dist/bundles/luatex/chunks/0.br +0 -0
- package/runtime/dist/bundles/luatex/chunks/1.br +0 -0
- package/runtime/dist/bundles/luatex/files.index.json +1 -1
- package/runtime/dist/bundles/tex-plain/chunks/0.br +0 -0
- package/runtime/dist/bundles/tex-plain/chunks/1.br +0 -0
- package/runtime/dist/bundles/tex-plain/chunks/3.br +0 -0
- package/runtime/dist/bundles/tex-plain/chunks/4.br +0 -0
- package/runtime/dist/bundles/tex-plain/chunks/5.br +0 -0
- package/runtime/dist/bundles/tex-plain/chunks/6.br +0 -0
- package/runtime/dist/bundles/tex-plain/chunks/7.br +0 -0
- package/runtime/dist/bundles/tex-plain/files.index.json +1 -1
- package/runtime/dist/bundles/tikz-snapshot/chunks/1.br +0 -0
- package/runtime/dist/bundles/tikz-snapshot/files.index.json +1 -1
- package/runtime/dist/bundles/tikz-snapshot/manifest.json +1 -1
- package/runtime/dist/core.js +20 -13
- package/runtime/dist/texengine.d.ts +1 -0
- package/runtime/dist/types.d.ts +3 -3
- package/runtime/dist/vfs/lazyfs.d.ts +6 -1
- package/runtime/dist/vfs/lazyfs.js +17 -2
- package/src/browser-worker.js +3 -7
- package/src/deploy.js +1 -1
- package/src/index.js +3 -6
- package/src/source.js +97 -0
- package/src/worker.js +2 -1
package/runtime/dist/types.d.ts
CHANGED
|
@@ -101,9 +101,9 @@ export interface MetaPostOptions {
|
|
|
101
101
|
/** Defer engine glue and MetaPost WASM until used. MetaPost version fields in creation
|
|
102
102
|
* metadata remain empty in this mode. No cross-request cache is required. */
|
|
103
103
|
lazy?: boolean;
|
|
104
|
-
/** Default for latex()'s snapshot option
|
|
105
|
-
*
|
|
106
|
-
*
|
|
104
|
+
/** Default for latex()'s snapshot option: Node 'auto', browser 'none'. Browser hosts
|
|
105
|
+
* may enable 'auto' when shipping precompiled formats (the @lofcz/tikz browser entry does).
|
|
106
|
+
* Auto uses basic TikZ when available and the full format for explicit plotting packages. */
|
|
107
107
|
snapshot?: 'auto' | 'none';
|
|
108
108
|
}
|
|
109
109
|
export type OutputFormat = 'svg' | 'eps' | 'json' | 'none';
|
|
@@ -12,6 +12,7 @@ export interface EmscriptenFS {
|
|
|
12
12
|
mkdir(path: string, mode?: number): void;
|
|
13
13
|
writeFile(path: string, data: Uint8Array | string, opts?: {
|
|
14
14
|
encoding?: string;
|
|
15
|
+
canOwn?: boolean;
|
|
15
16
|
}): void;
|
|
16
17
|
readFile(path: string, opts?: {
|
|
17
18
|
encoding?: 'binary' | 'utf8';
|
|
@@ -50,7 +51,7 @@ export declare function isUnloadedLazy(FS: EmscriptenFS, path: string): boolean;
|
|
|
50
51
|
/** Force-load a lazy node (no-op for ordinary files). */
|
|
51
52
|
export declare function ensureLoaded(FS: EmscriptenFS, path: string): void;
|
|
52
53
|
/** Write a text or binary file, creating directories as needed. */
|
|
53
|
-
export declare function writeFileDeep(FS: EmscriptenFS, path: string, data: Uint8Array | string): void;
|
|
54
|
+
export declare function writeFileDeep(FS: EmscriptenFS, path: string, data: Uint8Array | string, canOwn?: boolean): void;
|
|
54
55
|
/**
|
|
55
56
|
* Record every file opened for writing from now on (absolute paths, into the
|
|
56
57
|
* returned set). The engine's open syscall reaches the filesystem through
|
|
@@ -60,3 +61,7 @@ export declare function writeFileDeep(FS: EmscriptenFS, path: string, data: Uint
|
|
|
60
61
|
export declare function trackWrites(FS: EmscriptenFS): Set<string>;
|
|
61
62
|
/** Recursively collect regular files under `dir` (used to harvest artifacts). */
|
|
62
63
|
export declare function listFiles(FS: EmscriptenFS, dir: string): string[];
|
|
64
|
+
/** Borrow a completed MEMFS file; never retain a view into a module's WASM heap. */
|
|
65
|
+
export declare function completedFileBytes(FS: EmscriptenFS, path: string, heap?: Uint8Array): Uint8Array;
|
|
66
|
+
/** Auxiliary inputs remain available, but are copied only if the consumer opens them. */
|
|
67
|
+
export declare function writeDeferredFile(FS: EmscriptenFS, path: string, size: number, load: () => Uint8Array): void;
|
|
@@ -82,7 +82,7 @@ export function ensureLoaded(FS, path) {
|
|
|
82
82
|
}
|
|
83
83
|
}
|
|
84
84
|
/** Write a text or binary file, creating directories as needed. */
|
|
85
|
-
export function writeFileDeep(FS, path, data) {
|
|
85
|
+
export function writeFileDeep(FS, path, data, canOwn = false) {
|
|
86
86
|
const i = path.lastIndexOf('/');
|
|
87
87
|
if (i > 0)
|
|
88
88
|
mkdirp(FS, path.slice(0, i));
|
|
@@ -92,7 +92,7 @@ export function writeFileDeep(FS, path, data) {
|
|
|
92
92
|
}
|
|
93
93
|
catch { /* ignore */ }
|
|
94
94
|
}
|
|
95
|
-
FS.writeFile(path, data);
|
|
95
|
+
FS.writeFile(path, data, { canOwn });
|
|
96
96
|
}
|
|
97
97
|
/**
|
|
98
98
|
* Record every file opened for writing from now on (absolute paths, into the
|
|
@@ -130,4 +130,19 @@ export function listFiles(FS, dir) {
|
|
|
130
130
|
walk(dir);
|
|
131
131
|
return out;
|
|
132
132
|
}
|
|
133
|
+
/** Borrow a completed MEMFS file; never retain a view into a module's WASM heap. */
|
|
134
|
+
export function completedFileBytes(FS, path, heap) {
|
|
135
|
+
const node = FS.lookupPath(path).node;
|
|
136
|
+
if (heap && node.contents instanceof Uint8Array && node.contents.buffer !== heap.buffer &&
|
|
137
|
+
Number.isSafeInteger(node.usedBytes) && node.usedBytes >= 0 && node.usedBytes <= node.contents.length)
|
|
138
|
+
return node.contents.subarray(0, node.usedBytes);
|
|
139
|
+
return FS.readFile(path, { encoding: 'binary' });
|
|
140
|
+
}
|
|
141
|
+
/** Auxiliary inputs remain available, but are copied only if the consumer opens them. */
|
|
142
|
+
export function writeDeferredFile(FS, path, size, load) {
|
|
143
|
+
mkdirp(FS, path.slice(0, path.lastIndexOf('/')) || '/');
|
|
144
|
+
if (FS.analyzePath(path).exists)
|
|
145
|
+
FS.unlink(path);
|
|
146
|
+
createLazyFile(FS, path, size, () => load().slice());
|
|
147
|
+
}
|
|
133
148
|
//# sourceMappingURL=lazyfs.js.map
|
package/src/browser-worker.js
CHANGED
|
@@ -1,15 +1,11 @@
|
|
|
1
1
|
import { MetaPost } from '../runtime/dist/index.js';
|
|
2
|
+
import { prepareTikzSource } from './source.js';
|
|
2
3
|
|
|
3
4
|
try {
|
|
4
|
-
const engine = await MetaPost.create({ worker: false, lazy: true, logLevel: 'silent' });
|
|
5
|
+
const engine = await MetaPost.create({ worker: false, lazy: true, snapshot: 'auto', logLevel: 'silent' });
|
|
5
6
|
self.onmessage = async ({ data: { source: code, maxOutputBytes } }) => {
|
|
6
7
|
try {
|
|
7
|
-
const
|
|
8
|
-
\usetikzlibrary{calc,intersections,angles,quotes,arrows.meta,positioning}
|
|
9
|
-
\begin{document}
|
|
10
|
-
${code}
|
|
11
|
-
\end{document}`;
|
|
12
|
-
const result = await engine.latex(source, { engine: 'auto', fonts: 'paths' });
|
|
8
|
+
const result = await engine.latex(prepareTikzSource(code), { engine: 'auto', fonts: 'paths' });
|
|
13
9
|
if (result.status === 'error' || result.status === 'fatal' || result.pages?.length !== 1)
|
|
14
10
|
throw new Error('TikZ requires one valid page. ' + JSON.stringify(result.diagnostics).slice(0, 2000));
|
|
15
11
|
const svg = result.pages[0], bytes = new TextEncoder().encode(svg);
|
package/src/deploy.js
CHANGED
|
@@ -28,7 +28,7 @@ export async function copyTikzBrowserAssets(directory) {
|
|
|
28
28
|
throw new Error('TikZ browser assets must be outside the installed package');
|
|
29
29
|
await mkdir(join(destination, 'src'), { recursive: true });
|
|
30
30
|
await cp(join(source, 'runtime'), join(destination, 'runtime'), { recursive: true });
|
|
31
|
-
for (const name of ['browser.js', 'browser-worker.js'])
|
|
31
|
+
for (const name of ['browser.js', 'browser-worker.js', 'source.js'])
|
|
32
32
|
await cp(join(source, 'src', name), join(destination, 'src', name));
|
|
33
33
|
for (const name of ['LICENSE', 'NOTICE.md', 'upstream.json'])
|
|
34
34
|
await cp(join(source, name), join(destination, name));
|
package/src/index.js
CHANGED
|
@@ -89,13 +89,10 @@ export function createTikzRenderer(options = {}) {
|
|
|
89
89
|
async render(code, { signal } = {}) {
|
|
90
90
|
if (typeof code !== 'string' || !code.trim() || code.length > settings.maxSourceLength)
|
|
91
91
|
throw new Error(`TikZ: use 1–${settings.maxSourceLength.toLocaleString('en-US')} characters.`);
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
\begin{document}
|
|
95
|
-
${code}
|
|
96
|
-
\end{document}`;
|
|
92
|
+
// The worker normalizes and wraps the picture (src/source.js), so this
|
|
93
|
+
// entry stays relocatable: it only needs the package directory.
|
|
97
94
|
await acquire(signal);
|
|
98
|
-
try { return await compile(
|
|
95
|
+
try { return await compile(code, signal); }
|
|
99
96
|
finally { release(); }
|
|
100
97
|
},
|
|
101
98
|
};
|
package/src/source.js
ADDED
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
// Source normalization shared by the Node worker and the browser worker.
|
|
2
|
+
//
|
|
3
|
+
// A bare picture is wrapped in a standalone document with the common
|
|
4
|
+
// libraries. `\color{…}` inside a `font=` key is rewritten into the node's
|
|
5
|
+
// `text=` key: in this DVI→SVG pipeline the colour special opened by a font
|
|
6
|
+
// switch is never popped inside the picture, and dvisvgm then rejects the page
|
|
7
|
+
// ("missing closing tag(s): </g>"). `text=` paints the same colour the TikZ way.
|
|
8
|
+
|
|
9
|
+
const PREAMBLE = String.raw`\documentclass[tikz,border=6pt]{standalone}
|
|
10
|
+
\usetikzlibrary{calc,intersections,angles,quotes,arrows.meta,positioning}
|
|
11
|
+
\begin{document}
|
|
12
|
+
`;
|
|
13
|
+
|
|
14
|
+
/** Wrap a bare picture into a complete standalone document. */
|
|
15
|
+
export function wrapStandalone(code) {
|
|
16
|
+
return /^\s*\\documentclass\b/m.test(code) ? code : `${PREAMBLE}${code}\n\\end{document}`;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/** Index just past the balanced group that opens at `start` (`{`/`[`), or -1. */
|
|
20
|
+
function groupEnd(text, start) {
|
|
21
|
+
const open = text[start], close = open === '{' ? '}' : ']';
|
|
22
|
+
let depth = 0;
|
|
23
|
+
for (let i = start; i < text.length; i++) {
|
|
24
|
+
const char = text[i];
|
|
25
|
+
if (char === '\\') { i++; continue; }
|
|
26
|
+
if (char === open) depth++;
|
|
27
|
+
else if (char === close && --depth === 0) return i + 1;
|
|
28
|
+
}
|
|
29
|
+
return -1;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
/** End of a pgfkeys value starting at `start`: the next top-level `,`, `]` or `}`. */
|
|
33
|
+
function valueEnd(text, start) {
|
|
34
|
+
for (let i = start; i < text.length; i++) {
|
|
35
|
+
const char = text[i];
|
|
36
|
+
if (char === '\\') { i++; continue; }
|
|
37
|
+
if (char === '{' || char === '[') { const end = groupEnd(text, i); if (end < 0) return -1; i = end - 1; continue; }
|
|
38
|
+
if (char === ',' || char === ']' || char === '}') return i;
|
|
39
|
+
}
|
|
40
|
+
return text.length;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
/** Position of the `]`/`}` that closes the option list containing `from`, or -1. */
|
|
44
|
+
function listEnd(text, from) {
|
|
45
|
+
let depth = 0;
|
|
46
|
+
for (let i = from; i < text.length; i++) {
|
|
47
|
+
const char = text[i];
|
|
48
|
+
if (char === '\\') { i++; continue; }
|
|
49
|
+
if (char === '{' || char === '[') depth++;
|
|
50
|
+
else if (char === '}' || char === ']') { if (depth === 0) return i; depth--; }
|
|
51
|
+
}
|
|
52
|
+
return -1;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
const COLOR = /\\color\s*\{([^{}]*)\}/g;
|
|
56
|
+
|
|
57
|
+
/** Move every `\color{name}` out of `font=` values into a trailing `text=name` key. */
|
|
58
|
+
export function hoistFontColors(source) {
|
|
59
|
+
let text = source;
|
|
60
|
+
const keyPattern = /(^|[\[{,])(\s*font\s*=\s*)/g;
|
|
61
|
+
for (let match = keyPattern.exec(text); match; match = keyPattern.exec(text)) {
|
|
62
|
+
const keyStart = match.index + match[1].length;
|
|
63
|
+
const valueStart = match.index + match[0].length;
|
|
64
|
+
const end = valueEnd(text, valueStart);
|
|
65
|
+
if (end < 0) break;
|
|
66
|
+
const value = text.slice(valueStart, end);
|
|
67
|
+
const colors = [...value.matchAll(COLOR)].map(m => m[1].trim()).filter(Boolean);
|
|
68
|
+
if (colors.length === 0) continue;
|
|
69
|
+
const braced = /^\{[\s\S]*\}$/.test(value.trim());
|
|
70
|
+
let cleaned = value.replace(COLOR, '').replace(/[ \t]+$/, '');
|
|
71
|
+
if (braced && !cleaned.replace(/^\{|\}$/g, '').trim()) cleaned = '';
|
|
72
|
+
else if (!braced && !cleaned.trim()) cleaned = '';
|
|
73
|
+
const close = listEnd(text, end);
|
|
74
|
+
if (close < 0) break;
|
|
75
|
+
const closer = text.slice(close);
|
|
76
|
+
let replaced;
|
|
77
|
+
if (cleaned) {
|
|
78
|
+
replaced = text.slice(0, valueStart) + cleaned + text.slice(end, close);
|
|
79
|
+
} else {
|
|
80
|
+
// Drop the whole `font=` key with the comma that separated it.
|
|
81
|
+
let keyRemoveStart = keyStart, keyRemoveEnd = end;
|
|
82
|
+
if (text[end] === ',') keyRemoveEnd = end + 1;
|
|
83
|
+
else if (match[1] === ',') keyRemoveStart = match.index;
|
|
84
|
+
replaced = text.slice(0, keyRemoveStart) + text.slice(keyRemoveEnd, close);
|
|
85
|
+
}
|
|
86
|
+
const replacedHead = replaced.replace(/[\s,]+$/, '');
|
|
87
|
+
const separator = /[[{]$/.test(replacedHead) ? '' : ', ';
|
|
88
|
+
text = `${replacedHead}${separator}text=${colors[colors.length - 1]}${closer}`;
|
|
89
|
+
keyPattern.lastIndex = Math.max(0, replacedHead.length - value.length);
|
|
90
|
+
}
|
|
91
|
+
return text;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** Everything the TeX engine receives: colour-safe keys inside a complete document. */
|
|
95
|
+
export function prepareTikzSource(code) {
|
|
96
|
+
return wrapStandalone(hoistFontColors(code));
|
|
97
|
+
}
|
package/src/worker.js
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
// filesystem is in-memory; no host texmf tree, shell or caller environment.
|
|
3
3
|
import { readFileSync } from 'node:fs';
|
|
4
4
|
import { MetaPost } from '../runtime/dist/index.js';
|
|
5
|
+
import { prepareTikzSource } from './source.js';
|
|
5
6
|
const { source } = JSON.parse(readFileSync(0, 'utf8'));
|
|
6
7
|
const engine = await MetaPost.create({ worker: false, lazy: true, logLevel: 'silent' });
|
|
7
8
|
try {
|
|
8
|
-
const result = await engine.latex(source, { engine: 'auto', fonts: 'paths' });
|
|
9
|
+
const result = await engine.latex(prepareTikzSource(source), { engine: 'auto', fonts: 'paths' });
|
|
9
10
|
if (result.status === 'error' || result.status === 'fatal' || result.pages?.length !== 1)
|
|
10
11
|
throw new Error('TikZ requires one valid page. ' + JSON.stringify(result.diagnostics).slice(0, 2000));
|
|
11
12
|
process.stdout.write(result.pages[0]);
|