starlight-cannoli-plugins 2.5.5 → 2.6.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/README.md +14 -5
- package/dist/{chunk-Z6DVEB7O.js → chunk-Q33KZ2RB.js} +22 -19
- package/dist/{chunk-2Z7KWWVF.js → chunk-TRGFYY3Y.js} +2 -6
- package/dist/index.js +2 -2
- package/dist/plugins/astro-latex-compile.d.ts +8 -1
- package/dist/plugins/astro-latex-compile.js +1 -1
- package/dist/plugins/expressive-code-emphasis.js +1 -1
- package/dist/styles/_starlight.scss +5 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -79,6 +79,14 @@ dvisvgm --version
|
|
|
79
79
|
|
|
80
80
|
- `svgOutputDir` (required): Directory where compiled SVG files are written. Must be inside `public/` so Astro serves them as static assets.
|
|
81
81
|
- `removeOrphanedSvgs` (optional, default: `false`): When `true`, SVG files that are no longer referenced by any `tex compile` block are deleted automatically. In dev mode, stale SVGs are removed immediately when a block is edited. On build, any remaining orphans are swept at the end.
|
|
82
|
+
- `texInputDirs` (optional): Directories added to the TeX input search path (`TEXINPUTS`), allowing `\input{}` and `\include{}` to resolve files from your project. Use a trailing `/` to search only that directory, or `//` to search it recursively. Multiple directories are supported.
|
|
83
|
+
|
|
84
|
+
```ts
|
|
85
|
+
astroLatexCompile({
|
|
86
|
+
svgOutputDir: "public/static/tex-svgs",
|
|
87
|
+
texInputDirs: ["src/latex//"], // search src/latex/ and all its subdirectories
|
|
88
|
+
});
|
|
89
|
+
```
|
|
82
90
|
|
|
83
91
|
**Usage:**
|
|
84
92
|
|
|
@@ -162,20 +170,21 @@ If your code block contains both `\documentclass` and `\begin{document}`, the pl
|
|
|
162
170
|
```
|
|
163
171
|
````
|
|
164
172
|
|
|
165
|
-
**
|
|
173
|
+
**Meta Attributes:**
|
|
174
|
+
|
|
175
|
+
The following attributes can be added to the opening fence:
|
|
166
176
|
|
|
167
|
-
|
|
177
|
+
- `class="..."`: CSS classes applied to the resulting `<img>` element (space-separated). The `tex-compiled` class is always included.
|
|
178
|
+
- `alt="..."`: Alt text for the resulting `<img>` element. Defaults to `"LaTeX diagram"` if omitted.
|
|
168
179
|
|
|
169
180
|
````markdown
|
|
170
|
-
```tex compile class="bg-white rounded-1"
|
|
181
|
+
```tex compile class="bg-white rounded-1" alt="A commutative diagram"
|
|
171
182
|
\begin{tikzpicture}
|
|
172
183
|
\node {Custom styled diagram};
|
|
173
184
|
\end{tikzpicture}
|
|
174
185
|
```
|
|
175
186
|
````
|
|
176
187
|
|
|
177
|
-
The img element will have classes: `tex-compiled bg-white rounded-1` (note: the `tex-compiled` class is always included by default).
|
|
178
|
-
|
|
179
188
|
### Remark LaTeX Compile (low-level)
|
|
180
189
|
|
|
181
190
|
The underlying remark plugin used by `astroLatexCompile`. Use this directly if you need to wire the transformer into a custom pipeline — most users should use `astroLatexCompile` instead.
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import { rm } from "fs/promises";
|
|
3
3
|
import { join as join2, resolve } from "path";
|
|
4
4
|
import { visit, SKIP } from "unist-util-visit";
|
|
5
|
+
import { MetaOptions } from "@expressive-code/core";
|
|
5
6
|
|
|
6
7
|
// src/plugins/astro-latex-compile/utils.ts
|
|
7
8
|
import { createHash } from "crypto";
|
|
@@ -165,11 +166,11 @@ ${formattedSource}
|
|
|
165
166
|
|
|
166
167
|
// src/plugins/utils/process-utils.ts
|
|
167
168
|
import { spawn } from "child_process";
|
|
168
|
-
function execProcess(command, args) {
|
|
169
|
+
function execProcess(command, args, options) {
|
|
169
170
|
return new Promise((resolve2, reject) => {
|
|
170
171
|
let stdout = "";
|
|
171
172
|
let stderr = "";
|
|
172
|
-
const proc = spawn(command, args);
|
|
173
|
+
const proc = spawn(command, args, { env: options?.env });
|
|
173
174
|
proc.stdout.on("data", (data) => {
|
|
174
175
|
stdout += data.toString();
|
|
175
176
|
});
|
|
@@ -211,7 +212,7 @@ function buildLatexSource(latexCode) {
|
|
|
211
212
|
"\\end{document}"
|
|
212
213
|
].join("\n");
|
|
213
214
|
}
|
|
214
|
-
async function compileLatexToSvg(latexCode, svgOutputDir) {
|
|
215
|
+
async function compileLatexToSvg(latexCode, svgOutputDir, texInputDirs = []) {
|
|
215
216
|
const hash = hashLatexCode(latexCode);
|
|
216
217
|
const svgPath = join(svgOutputDir, `${hash}.svg`);
|
|
217
218
|
if (existsSync(svgPath)) {
|
|
@@ -224,14 +225,17 @@ async function compileLatexToSvg(latexCode, svgOutputDir) {
|
|
|
224
225
|
const latexSource = buildLatexSource(latexCode);
|
|
225
226
|
try {
|
|
226
227
|
writeFileSync(texFile, latexSource, "utf-8");
|
|
228
|
+
const pdflatexEnv = texInputDirs.length > 0 ? {
|
|
229
|
+
...process.env,
|
|
230
|
+
TEXINPUTS: `${texInputDirs.join(":")}:${process.env.TEXINPUTS ?? ""}`
|
|
231
|
+
} : void 0;
|
|
227
232
|
let result;
|
|
228
233
|
try {
|
|
229
|
-
result = await execProcess(
|
|
230
|
-
"
|
|
231
|
-
"-output-directory",
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
]);
|
|
234
|
+
result = await execProcess(
|
|
235
|
+
"pdflatex",
|
|
236
|
+
["-interaction=nonstopmode", "-output-directory", workDir, texFile],
|
|
237
|
+
{ env: pdflatexEnv }
|
|
238
|
+
);
|
|
235
239
|
} catch (err) {
|
|
236
240
|
const code = err.code;
|
|
237
241
|
throw new Error(
|
|
@@ -280,13 +284,6 @@ Error: ${errorOutput}`
|
|
|
280
284
|
}
|
|
281
285
|
|
|
282
286
|
// src/plugins/astro-latex-compile/index.ts
|
|
283
|
-
function extractClassesFromMeta(meta) {
|
|
284
|
-
const classMatch = meta.match(/class="([^"]+)"/);
|
|
285
|
-
if (classMatch?.[1]) {
|
|
286
|
-
return classMatch[1].split(/\s+/).filter(Boolean);
|
|
287
|
-
}
|
|
288
|
-
return [];
|
|
289
|
-
}
|
|
290
287
|
function remarkLatexCompile(options) {
|
|
291
288
|
const svgOutputDir = resolve(options.svgOutputDir);
|
|
292
289
|
return async function transformer(tree, file) {
|
|
@@ -303,7 +300,11 @@ function remarkLatexCompile(options) {
|
|
|
303
300
|
nodes.map(async ({ node, index, parent }) => {
|
|
304
301
|
const lineNumber = node.position?.start.line ?? "?";
|
|
305
302
|
try {
|
|
306
|
-
const result = await compileLatexToSvg(
|
|
303
|
+
const result = await compileLatexToSvg(
|
|
304
|
+
node.value,
|
|
305
|
+
svgOutputDir,
|
|
306
|
+
options.texInputDirs ?? []
|
|
307
|
+
);
|
|
307
308
|
if (result.wasCompiled) {
|
|
308
309
|
console.log(
|
|
309
310
|
`[remark-latex-compile] ${filePath}:${lineNumber}: compiled ${result.hash}.svg`
|
|
@@ -345,11 +346,13 @@ ${details}`
|
|
|
345
346
|
const { index, parent, result } = results[i];
|
|
346
347
|
const { node } = nodes[i];
|
|
347
348
|
if (!result) continue;
|
|
348
|
-
const
|
|
349
|
+
const metaOptions = new MetaOptions(node.meta ?? "");
|
|
350
|
+
const customClasses = metaOptions.getString("class")?.split(/\s+/).filter(Boolean) ?? [];
|
|
351
|
+
const altText = metaOptions.getString("alt") ?? "LaTeX diagram";
|
|
349
352
|
const imageNode = {
|
|
350
353
|
type: "image",
|
|
351
354
|
url: `/static/tex-svgs/${result.hash}.svg`,
|
|
352
|
-
alt:
|
|
355
|
+
alt: altText,
|
|
353
356
|
data: {
|
|
354
357
|
hProperties: { className: ["tex-compiled", ...customClasses] }
|
|
355
358
|
}
|
|
@@ -12,17 +12,13 @@ var EmphasisAnnotation = class extends ExpressiveCodeAnnotation {
|
|
|
12
12
|
function escapeRegex(s) {
|
|
13
13
|
return s.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
14
14
|
}
|
|
15
|
-
function parseEmphTerms(meta) {
|
|
16
|
-
const match = meta.match(/\bemph="([^"]+)"/);
|
|
17
|
-
if (!match) return [];
|
|
18
|
-
return match[1].split(",").map((t) => t.trim()).filter(Boolean);
|
|
19
|
-
}
|
|
20
15
|
function expressiveCodeEmphasis() {
|
|
21
16
|
return definePlugin({
|
|
22
17
|
name: "expressiveCodeEmphasis",
|
|
23
18
|
hooks: {
|
|
24
19
|
preprocessCode: (context) => {
|
|
25
|
-
const
|
|
20
|
+
const emphValue = context.codeBlock.metaOptions.getString("emph");
|
|
21
|
+
const terms = emphValue ? emphValue.split(",").map((t) => t.trim()).filter(Boolean) : [];
|
|
26
22
|
if (terms.length === 0) return;
|
|
27
23
|
for (const line of context.codeBlock.getLines()) {
|
|
28
24
|
for (const term of terms) {
|
package/dist/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
expressiveCodeEmphasis
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-TRGFYY3Y.js";
|
|
4
4
|
import {
|
|
5
5
|
starlightIndexOnlySidebar
|
|
6
6
|
} from "./chunk-N2I2GJW3.js";
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
} from "./chunk-3UMY7T6G.js";
|
|
10
10
|
import {
|
|
11
11
|
remarkLatexCompile
|
|
12
|
-
} from "./chunk-
|
|
12
|
+
} from "./chunk-Q33KZ2RB.js";
|
|
13
13
|
import {
|
|
14
14
|
astroNormalizePaths
|
|
15
15
|
} from "./chunk-TLOFSB33.js";
|
|
@@ -14,7 +14,7 @@ interface CompilationResult {
|
|
|
14
14
|
* @returns Result object with hash, svgPath, and whether compilation occurred
|
|
15
15
|
* @throws Error if compilation fails
|
|
16
16
|
*/
|
|
17
|
-
declare function compileLatexToSvg(latexCode: string, svgOutputDir: string): Promise<CompilationResult>;
|
|
17
|
+
declare function compileLatexToSvg(latexCode: string, svgOutputDir: string, texInputDirs?: string[]): Promise<CompilationResult>;
|
|
18
18
|
|
|
19
19
|
interface RemarkLatexCompileOptions {
|
|
20
20
|
/**
|
|
@@ -22,6 +22,13 @@ interface RemarkLatexCompileOptions {
|
|
|
22
22
|
* Must be inside `public/` so Astro serves them as static assets.
|
|
23
23
|
*/
|
|
24
24
|
svgOutputDir: string;
|
|
25
|
+
/**
|
|
26
|
+
* Directories added to the TeX input search path via TEXINPUTS, allowing
|
|
27
|
+
* \input{} and \include{} to resolve files from your project. Use a trailing
|
|
28
|
+
* slash for the directory itself, or double trailing slash for recursive
|
|
29
|
+
* search (e.g. "src/latex/" or "src/latex//").
|
|
30
|
+
*/
|
|
31
|
+
texInputDirs?: string[];
|
|
25
32
|
/**
|
|
26
33
|
* @internal Populated by the Astro integration to track which hashes were
|
|
27
34
|
* referenced during a build, used for full orphan cleanup at build:done.
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
/********** Starlight Overrides **********/
|
|
2
2
|
|
|
3
|
+
$DARK_MODE_ROTATE: 178deg;
|
|
4
|
+
|
|
3
5
|
.sl-container:where(.astro-7nkwcw3z) {
|
|
4
6
|
max-width: 50rem;
|
|
5
7
|
}
|
|
@@ -127,7 +129,7 @@ div > div[class="page"] > svg {
|
|
|
127
129
|
html:not([data-theme="light"]) & {
|
|
128
130
|
stroke: white;
|
|
129
131
|
fill: white;
|
|
130
|
-
filter: invert(1) hue-rotate(
|
|
132
|
+
filter: invert(1) hue-rotate($DARK_MODE_ROTATE);
|
|
131
133
|
}
|
|
132
134
|
}
|
|
133
135
|
|
|
@@ -175,7 +177,7 @@ img.note-svg {
|
|
|
175
177
|
}
|
|
176
178
|
|
|
177
179
|
html:not([data-theme="light"]) & {
|
|
178
|
-
filter: invert(1) hue-rotate(
|
|
180
|
+
filter: invert(1) hue-rotate($DARK_MODE_ROTATE);
|
|
179
181
|
}
|
|
180
182
|
}
|
|
181
183
|
|
|
@@ -183,6 +185,6 @@ img.note-svg {
|
|
|
183
185
|
background-color: transparent;
|
|
184
186
|
|
|
185
187
|
html[data-theme="dark"] & {
|
|
186
|
-
filter: invert(1) hue-rotate(
|
|
188
|
+
filter: invert(1) hue-rotate($DARK_MODE_ROTATE);
|
|
187
189
|
}
|
|
188
190
|
}
|
package/package.json
CHANGED