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 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
- **Custom CSS Classes:**
173
+ **Meta Attributes:**
174
+
175
+ The following attributes can be added to the opening fence:
166
176
 
167
- Add custom CSS classes the `tex compile` code block to have them applied to the resulting `<img>` element:
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("pdflatex", [
230
- "-interaction=nonstopmode",
231
- "-output-directory",
232
- workDir,
233
- texFile
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(node.value, svgOutputDir);
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 customClasses = extractClassesFromMeta(node.meta ?? "");
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: "LaTeX diagram",
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 terms = parseEmphTerms(context.codeBlock.meta);
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-2Z7KWWVF.js";
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-Z6DVEB7O.js";
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,7 +1,7 @@
1
1
  import {
2
2
  compileLatexToSvg,
3
3
  remarkLatexCompile
4
- } from "../chunk-Z6DVEB7O.js";
4
+ } from "../chunk-Q33KZ2RB.js";
5
5
  import "../chunk-QGM4M3NI.js";
6
6
  export {
7
7
  compileLatexToSvg,
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  expressiveCodeEmphasis
3
- } from "../chunk-2Z7KWWVF.js";
3
+ } from "../chunk-TRGFYY3Y.js";
4
4
  import "../chunk-QGM4M3NI.js";
5
5
  export {
6
6
  expressiveCodeEmphasis
@@ -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(168deg);
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(168deg);
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(168deg);
188
+ filter: invert(1) hue-rotate($DARK_MODE_ROTATE);
187
189
  }
188
190
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "starlight-cannoli-plugins",
3
3
  "type": "module",
4
- "version": "2.5.5",
4
+ "version": "2.6.0",
5
5
  "description": "Starlight plugins for automatic sidebar generation and link validation",
6
6
  "license": "ISC",
7
7
  "main": "./dist/index.js",