@nu-appdev/northwestern-starlight-theme 1.6.0 → 1.6.1
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/CHANGELOG.md +14 -1
- package/config.ts +9 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/mermaid.d.ts +2 -2
- package/dist/mermaid.d.ts.map +1 -1
- package/dist/src/markdown-processor.d.ts +86 -0
- package/dist/src/markdown-processor.d.ts.map +1 -0
- package/index.ts +10 -17
- package/mermaid.ts +3 -29
- package/package.json +1 -1
- package/src/markdown-processor.ts +168 -0
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,18 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [1.6.1] - 2026-08-20
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- **Starlight plugins that extend the Markdown processor no longer stop working.** Astro 7 renders Markdown with the Sätteri processor and hands every integration the same live processor object. Plugins extend the pipeline by changing that object. The theme replaced it with a `unified()` processor from two `astro:config:setup` hooks, which run after Starlight has already set up its plugins, so everything those plugins had registered was thrown away.
|
|
15
|
+
|
|
16
|
+
The visible effect was `starlight-links-validator` 0.25 or newer: it validated zero links on every build and still printed "All internal links are valid", so broken internal links passed unnoticed. Any plugin that configures itself against the Sätteri processor was affected the same way.
|
|
17
|
+
|
|
18
|
+
`defineNorthwesternConfig()` now sets `markdown.processor` to `unified()` while `astro.config.*` is evaluated, before `starlight()` is created. No plugin ever sees Sätteri, and the theme only extends the processor it is given instead of replacing it. A processor you configure yourself is left alone.
|
|
19
|
+
|
|
20
|
+
- Mermaid no longer swaps the Markdown processor either. `astro-mermaid` 2.1 supports Sätteri on its own.
|
|
21
|
+
|
|
10
22
|
## [1.6.0] - 2026-07-28
|
|
11
23
|
|
|
12
24
|
### Added
|
|
@@ -191,7 +203,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
191
203
|
- OpenAPI plugin compatibility with method badge preservation
|
|
192
204
|
- Reduced motion support for transitions
|
|
193
205
|
|
|
194
|
-
[Unreleased]: https://github.com/NIT-Administrative-Systems/northwestern-starlight-theme/compare/v1.6.
|
|
206
|
+
[Unreleased]: https://github.com/NIT-Administrative-Systems/northwestern-starlight-theme/compare/v1.6.1...HEAD
|
|
207
|
+
[1.6.1]: https://github.com/NIT-Administrative-Systems/northwestern-starlight-theme/compare/v1.6.0...v1.6.1
|
|
195
208
|
[1.6.0]: https://github.com/NIT-Administrative-Systems/northwestern-starlight-theme/compare/v1.5.1...v1.6.0
|
|
196
209
|
[1.5.1]: https://github.com/NIT-Administrative-Systems/northwestern-starlight-theme/compare/v1.5.0...v1.5.1
|
|
197
210
|
[1.5.0]: https://github.com/NIT-Administrative-Systems/northwestern-starlight-theme/compare/v1.4.0...v1.5.0
|
package/config.ts
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from "./legacy-html-redirects";
|
|
16
16
|
import { type NorthwesternMermaidOptions, northwesternMermaid } from "./mermaid";
|
|
17
17
|
import { northwesternConfigOptionsSchema, validateSchema } from "./src/config-schema";
|
|
18
|
+
import { type MarkdownConfigLike, withUnifiedProcessor } from "./src/markdown-processor";
|
|
18
19
|
|
|
19
20
|
/**
|
|
20
21
|
* Vite plugin that enables `pluginLineNumbers` for both markdown code blocks
|
|
@@ -333,6 +334,14 @@ export function defineNorthwesternConfig(options: NorthwesternConfigOptions): As
|
|
|
333
334
|
return {
|
|
334
335
|
...astroConfig,
|
|
335
336
|
integrations,
|
|
337
|
+
// Pin the Markdown processor to `unified()` here, at `astro.config.*`
|
|
338
|
+
// evaluation time, so `starlight()` and every Starlight plugin observes it
|
|
339
|
+
// from the start. Doing this later from an `astro:config:setup` hook means
|
|
340
|
+
// replacing a processor plugins have already registered against — which
|
|
341
|
+
// silently drops those registrations (see `src/markdown-processor.ts`).
|
|
342
|
+
markdown: withUnifiedProcessor(
|
|
343
|
+
astroConfig.markdown as MarkdownConfigLike | undefined,
|
|
344
|
+
) as AstroUserConfig["markdown"],
|
|
336
345
|
...(mergedRedirects ? { redirects: mergedRedirects } : {}),
|
|
337
346
|
vite: {
|
|
338
347
|
...existingViteConfig,
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAErF,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAC/D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAEvD,OAAO,EAEH,KAAK,0BAA0B,EAElC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,0BAA0B,EAAuB,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,0BAA0B,CAAC;AAErF,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAC/D,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,SAAS,CAAC;AAEvD,OAAO,EAEH,KAAK,0BAA0B,EAElC,MAAM,yBAAyB,CAAC;AACjC,OAAO,EAAE,KAAK,0BAA0B,EAAuB,MAAM,WAAW,CAAC;AA4EjF;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CACjC,WAAW,EAAE,eAAe,EAC5B,gBAAgB,EAAE,eAAe,EAAE,EACnC,aAAa,EAAE,eAAe,EAAE,GACjC,eAAe,EAAE,CAmBnB;AAED;;;;;;;GAOG;AACH,MAAM,MAAM,yBAAyB,GAAG,IAAI,CAAC,eAAe,EAAE,cAAc,CAAC,GAAG;IAC5E,wFAAwF;IACxF,SAAS,EAAE,mBAAmB,CAAC;IAE/B;;;;OAIG;IACH,KAAK,CAAC,EAAE,uBAAuB,CAAC;IAEhC;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,0BAA0B,CAAC;IAE/C;;;;OAIG;IACH,OAAO,CAAC,EAAE,eAAe,EAAE,CAAC;IAE5B;;;;;;;;;;;;;;OAcG;IACH,mBAAmB,CAAC,EAAE,OAAO,GAAG,0BAA0B,CAAC;IAE3D;;;;;OAKG;IACH,YAAY,CAAC,EAAE;QACX,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;QAC5B,KAAK,CAAC,EAAE,gBAAgB,EAAE,CAAC;KAC9B,CAAC;CACL,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,GAAG,eAAe,CAyI5F"}
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAC;AAKhE;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,0BAA0B;IACvC;;;;;OAKG;IACH,MAAM,CAAC,EAAE,UAAU,GAAG,OAAO,CAAC;IAE9B;;;;;;OAMG;IACH,SAAS,CAAC,EAAE,OAAO,CAAC;IAEpB;;;;;;OAMG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,WAAW,uBAAuB;IACpC;;;;OAIG;IACH,QAAQ,CAAC,EAAE,0BAA0B,CAAC;IAEtC;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IAE5C;;;;;;;;;OASG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AA6BD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA8BG;AACH,MAAM,CAAC,OAAO,UAAU,iBAAiB,CAAC,MAAM,GAAE,uBAA4B,GAAG,eAAe,CAyP/F"}
|
package/dist/mermaid.d.ts
CHANGED
|
@@ -69,8 +69,8 @@ export declare const darkMermaidConfig: AstroMermaidOptions;
|
|
|
69
69
|
* This function is only needed for manual setups.
|
|
70
70
|
*
|
|
71
71
|
* **Must be added after `starlight()` in the `integrations` array.** This lets
|
|
72
|
-
* `astro-mermaid`
|
|
73
|
-
*
|
|
72
|
+
* `astro-mermaid` extend the active Markdown processor after Starlight and its
|
|
73
|
+
* plugins have configured it.
|
|
74
74
|
*
|
|
75
75
|
* @param options - Merged with Northwestern defaults. Set `toolbar: false` to
|
|
76
76
|
* disable the hover toolbar.
|
package/dist/mermaid.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../mermaid.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"mermaid.d.ts","sourceRoot":"","sources":["../mermaid.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,OAAO,CAAC;AAC9C,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC;AAIzD;;;;;;;GAOG;AACH,MAAM,WAAW,0BAA2B,SAAQ,mBAAmB;IACnE;;;;OAIG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,uBAAuB,GAAG,OAAO,GAAG,MAAM,CAAC;AAwUvD;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,+BAA+B,CAAC,IAAI,EAAE,uBAAuB,GAAG,mBAAmB,CAmBlG;AAED;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,EAAE,mBAA8D,CAAC;AAElG;;;;;GAKG;AACH,eAAO,MAAM,iBAAiB,EAAE,mBAA6D,CAAC;AAE9F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAgCG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,GAAE,0BAA+B,GAAG,gBAAgB,CAsD9F"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for Astro's `markdown.processor` API.
|
|
3
|
+
*
|
|
4
|
+
* Astro 6.4 introduced `markdown.processor`, and Astro 7 changed its default
|
|
5
|
+
* from `unified()` (`@astrojs/markdown-remark`) to `satteri()`
|
|
6
|
+
* (`@astrojs/markdown-satteri`). Both are *live objects*: integrations and
|
|
7
|
+
* Starlight plugins extend the Markdown pipeline by mutating the processor
|
|
8
|
+
* instance they are handed — pushing into `processor.options.*Plugins`, or
|
|
9
|
+
* wrapping `processor.createRenderer`.
|
|
10
|
+
*
|
|
11
|
+
* That makes processor **replacement** destructive. Anything registered on the
|
|
12
|
+
* outgoing object is dropped, and because most registrations are optional
|
|
13
|
+
* behaviour, the failure is silent: `starlight-links-validator` swapped for a
|
|
14
|
+
* fresh processor simply validates zero links and reports success.
|
|
15
|
+
*
|
|
16
|
+
* The theme therefore installs a `unified()` processor in
|
|
17
|
+
* `defineNorthwesternConfig()` — at `astro.config.*` evaluation time, before
|
|
18
|
+
* `starlight()` is constructed and before any plugin can observe the default —
|
|
19
|
+
* and from then on only ever *extends* the processor it is given.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* Structural shape of `markdown.processor`.
|
|
23
|
+
*
|
|
24
|
+
* Declared locally because `AstroUserConfig["markdown"]` only gained the
|
|
25
|
+
* `processor` key in Astro 6.4, and the theme supports Astro 5 and 6 as well.
|
|
26
|
+
*/
|
|
27
|
+
export interface MarkdownProcessorLike {
|
|
28
|
+
name: string;
|
|
29
|
+
options?: {
|
|
30
|
+
remarkPlugins?: unknown[];
|
|
31
|
+
rehypePlugins?: unknown[];
|
|
32
|
+
mdastPlugins?: unknown[];
|
|
33
|
+
hastPlugins?: unknown[];
|
|
34
|
+
[key: string]: unknown;
|
|
35
|
+
};
|
|
36
|
+
createRenderer?: unknown;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Structural shape of `markdown` in an Astro config, including the keys the
|
|
40
|
+
* installed Astro version may not know about yet.
|
|
41
|
+
*/
|
|
42
|
+
export interface MarkdownConfigLike {
|
|
43
|
+
processor?: MarkdownProcessorLike;
|
|
44
|
+
remarkPlugins?: unknown[];
|
|
45
|
+
rehypePlugins?: unknown[];
|
|
46
|
+
remarkRehype?: Record<string, unknown>;
|
|
47
|
+
gfm?: boolean;
|
|
48
|
+
smartypants?: unknown;
|
|
49
|
+
[key: string]: unknown;
|
|
50
|
+
}
|
|
51
|
+
/** A `unified()` processor from `@astrojs/markdown-remark`. */
|
|
52
|
+
export declare function isUnifiedProcessor(processor: MarkdownProcessorLike | undefined): processor is MarkdownProcessorLike & {
|
|
53
|
+
options: {
|
|
54
|
+
rehypePlugins: unknown[];
|
|
55
|
+
};
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Return a `markdown` config that is guaranteed to use a `unified()` processor.
|
|
59
|
+
*
|
|
60
|
+
* Call this while building the Astro config — before `starlight()` runs — so no
|
|
61
|
+
* plugin ever observes the Sätteri default. A processor the consumer supplied
|
|
62
|
+
* themselves is respected as-is (a non-`unified` one earns a warning, because
|
|
63
|
+
* several Starlight plugins the theme ships with only support `unified`).
|
|
64
|
+
*
|
|
65
|
+
* User-supplied `remarkPlugins` / `rehypePlugins` are deliberately *not* copied
|
|
66
|
+
* into the processor: Astro migrates those deprecated top-level arrays onto a
|
|
67
|
+
* `unified` processor itself (exactly once, tracked internally), and on Astro
|
|
68
|
+
* versions without `markdown.processor` they are the whole pipeline. Baking
|
|
69
|
+
* copies in here would run them twice.
|
|
70
|
+
*/
|
|
71
|
+
export declare function withUnifiedProcessor(markdown: MarkdownConfigLike | undefined, warn?: (message: string) => void): MarkdownConfigLike;
|
|
72
|
+
/**
|
|
73
|
+
* Register a rehype plugin on the active Markdown pipeline.
|
|
74
|
+
*
|
|
75
|
+
* Returns a `markdown` config patch to hand to `updateConfig()`, or `undefined`
|
|
76
|
+
* when the plugin was added to the live processor and no config update is
|
|
77
|
+
* needed. Mutating `processor.options` is how Astro itself extends a processor
|
|
78
|
+
* after config resolution — the object identity survives config validation
|
|
79
|
+
* precisely so that late registrations still apply.
|
|
80
|
+
*
|
|
81
|
+
* A non-`unified` processor is left alone. Replacing it here is what used to
|
|
82
|
+
* discard Sätteri-registered plugins from unrelated Starlight plugins, so the
|
|
83
|
+
* theme warns instead of swapping behind their back.
|
|
84
|
+
*/
|
|
85
|
+
export declare function addRehypePlugin(markdown: MarkdownConfigLike | undefined, plugin: unknown, warn?: (message: string) => void): MarkdownConfigLike | undefined;
|
|
86
|
+
//# sourceMappingURL=markdown-processor.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"markdown-processor.d.ts","sourceRoot":"","sources":["../../src/markdown-processor.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AAIH;;;;;GAKG;AACH,MAAM,WAAW,qBAAqB;IAClC,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE;QACN,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;QAC1B,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;QAC1B,YAAY,CAAC,EAAE,OAAO,EAAE,CAAC;QACzB,WAAW,CAAC,EAAE,OAAO,EAAE,CAAC;QACxB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;KAC1B,CAAC;IACF,cAAc,CAAC,EAAE,OAAO,CAAC;CAC5B;AAED;;;GAGG;AACH,MAAM,WAAW,kBAAkB;IAC/B,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;IAC1B,aAAa,CAAC,EAAE,OAAO,EAAE,CAAC;IAC1B,YAAY,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;IACvC,GAAG,CAAC,EAAE,OAAO,CAAC;IACd,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CAC1B;AAED,+DAA+D;AAC/D,wBAAgB,kBAAkB,CAC9B,SAAS,EAAE,qBAAqB,GAAG,SAAS,GAC7C,SAAS,IAAI,qBAAqB,GAAG;IAAE,OAAO,EAAE;QAAE,aAAa,EAAE,OAAO,EAAE,CAAA;KAAE,CAAA;CAAE,CAEhF;AAkBD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,oBAAoB,CAChC,QAAQ,EAAE,kBAAkB,GAAG,SAAS,EACxC,IAAI,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAmB,GAC/C,kBAAkB,CAwBpB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAC3B,QAAQ,EAAE,kBAAkB,GAAG,SAAS,EACxC,MAAM,EAAE,OAAO,EACf,IAAI,GAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAmB,GAC/C,kBAAkB,GAAG,SAAS,CA6BhC"}
|
package/index.ts
CHANGED
|
@@ -3,9 +3,9 @@ import type { IncomingMessage, ServerResponse } from "node:http";
|
|
|
3
3
|
import { createRequire } from "node:module";
|
|
4
4
|
import { dirname, join } from "node:path";
|
|
5
5
|
import { fileURLToPath } from "node:url";
|
|
6
|
-
import { unified } from "@astrojs/markdown-remark";
|
|
7
6
|
import type { StarlightPlugin } from "@astrojs/starlight/types";
|
|
8
7
|
import { nonEmptyStringSchema, northwesternThemeConfigSchema, validateSchema } from "./src/config-schema";
|
|
8
|
+
import { addRehypePlugin, type MarkdownConfigLike } from "./src/markdown-processor";
|
|
9
9
|
import rehypeTableScroll from "./src/rehype-table-scroll";
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -204,24 +204,17 @@ export default function northwesternTheme(config: NorthwesternThemeConfig = {}):
|
|
|
204
204
|
name: "northwestern-theme-config",
|
|
205
205
|
hooks: {
|
|
206
206
|
"astro:config:setup": ({ config: astroConfig, updateConfig: updateAstroConfig }) => {
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
gfm: markdown.gfm,
|
|
216
|
-
smartypants: markdown.smartypants,
|
|
217
|
-
}),
|
|
218
|
-
}
|
|
219
|
-
: {
|
|
220
|
-
rehypePlugins: [...(markdown.rehypePlugins ?? []), rehypeTableScroll],
|
|
221
|
-
};
|
|
207
|
+
// Extend whichever Markdown pipeline is active — never replace it.
|
|
208
|
+
// `defineNorthwesternConfig()` has already pinned a `unified()`
|
|
209
|
+
// processor before any plugin could register against it.
|
|
210
|
+
const markdownConfig = addRehypePlugin(
|
|
211
|
+
astroConfig.markdown as MarkdownConfigLike | undefined,
|
|
212
|
+
rehypeTableScroll,
|
|
213
|
+
(message) => logger.warn(message),
|
|
214
|
+
);
|
|
222
215
|
|
|
223
216
|
updateAstroConfig({
|
|
224
|
-
markdown: markdownConfig,
|
|
217
|
+
...(markdownConfig ? { markdown: markdownConfig } : {}),
|
|
225
218
|
vite: {
|
|
226
219
|
plugins: [
|
|
227
220
|
{
|
package/mermaid.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { unified } from "@astrojs/markdown-remark";
|
|
2
1
|
import type { AstroIntegration } from "astro";
|
|
3
2
|
import type { AstroMermaidOptions } from "astro-mermaid";
|
|
4
3
|
import { darken, isDark, lighten, mix, transparentize } from "khroma";
|
|
@@ -423,8 +422,8 @@ export const darkMermaidConfig: AstroMermaidOptions = createNorthwesternMermaidC
|
|
|
423
422
|
* This function is only needed for manual setups.
|
|
424
423
|
*
|
|
425
424
|
* **Must be added after `starlight()` in the `integrations` array.** This lets
|
|
426
|
-
* `astro-mermaid`
|
|
427
|
-
*
|
|
425
|
+
* `astro-mermaid` extend the active Markdown processor after Starlight and its
|
|
426
|
+
* plugins have configured it.
|
|
428
427
|
*
|
|
429
428
|
* @param options - Merged with Northwestern defaults. Set `toolbar: false` to
|
|
430
429
|
* disable the hover toolbar.
|
|
@@ -478,31 +477,6 @@ export function northwesternMermaid(options: NorthwesternMermaidOptions = {}): A
|
|
|
478
477
|
hooks: {
|
|
479
478
|
async "astro:config:setup"(params) {
|
|
480
479
|
const { default: mermaid } = await mermaidModulePromise;
|
|
481
|
-
let mermaidHookParams = params;
|
|
482
|
-
const markdown = params.config.markdown ?? {};
|
|
483
|
-
|
|
484
|
-
if (markdown.processor?.name === "satteri") {
|
|
485
|
-
const processor = unified({
|
|
486
|
-
remarkPlugins: markdown.remarkPlugins,
|
|
487
|
-
rehypePlugins: markdown.rehypePlugins,
|
|
488
|
-
remarkRehype: markdown.remarkRehype,
|
|
489
|
-
gfm: markdown.gfm,
|
|
490
|
-
smartypants: markdown.smartypants,
|
|
491
|
-
});
|
|
492
|
-
const unifiedMarkdown = {
|
|
493
|
-
...markdown,
|
|
494
|
-
processor,
|
|
495
|
-
};
|
|
496
|
-
|
|
497
|
-
params.updateConfig({ markdown: { processor } });
|
|
498
|
-
mermaidHookParams = {
|
|
499
|
-
...params,
|
|
500
|
-
config: {
|
|
501
|
-
...params.config,
|
|
502
|
-
markdown: unifiedMarkdown,
|
|
503
|
-
},
|
|
504
|
-
};
|
|
505
|
-
}
|
|
506
480
|
|
|
507
481
|
const mermaidIntegration = mermaid({
|
|
508
482
|
...lightConfig,
|
|
@@ -511,7 +485,7 @@ export function northwesternMermaid(options: NorthwesternMermaidOptions = {}): A
|
|
|
511
485
|
mermaidConfig: mergedLightMermaidConfig,
|
|
512
486
|
});
|
|
513
487
|
|
|
514
|
-
await mermaidIntegration.hooks["astro:config:setup"]?.(
|
|
488
|
+
await mermaidIntegration.hooks["astro:config:setup"]?.(params);
|
|
515
489
|
|
|
516
490
|
params.injectScript(
|
|
517
491
|
"page",
|
package/package.json
CHANGED
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helpers for Astro's `markdown.processor` API.
|
|
3
|
+
*
|
|
4
|
+
* Astro 6.4 introduced `markdown.processor`, and Astro 7 changed its default
|
|
5
|
+
* from `unified()` (`@astrojs/markdown-remark`) to `satteri()`
|
|
6
|
+
* (`@astrojs/markdown-satteri`). Both are *live objects*: integrations and
|
|
7
|
+
* Starlight plugins extend the Markdown pipeline by mutating the processor
|
|
8
|
+
* instance they are handed — pushing into `processor.options.*Plugins`, or
|
|
9
|
+
* wrapping `processor.createRenderer`.
|
|
10
|
+
*
|
|
11
|
+
* That makes processor **replacement** destructive. Anything registered on the
|
|
12
|
+
* outgoing object is dropped, and because most registrations are optional
|
|
13
|
+
* behaviour, the failure is silent: `starlight-links-validator` swapped for a
|
|
14
|
+
* fresh processor simply validates zero links and reports success.
|
|
15
|
+
*
|
|
16
|
+
* The theme therefore installs a `unified()` processor in
|
|
17
|
+
* `defineNorthwesternConfig()` — at `astro.config.*` evaluation time, before
|
|
18
|
+
* `starlight()` is constructed and before any plugin can observe the default —
|
|
19
|
+
* and from then on only ever *extends* the processor it is given.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
import { unified } from "@astrojs/markdown-remark";
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Structural shape of `markdown.processor`.
|
|
26
|
+
*
|
|
27
|
+
* Declared locally because `AstroUserConfig["markdown"]` only gained the
|
|
28
|
+
* `processor` key in Astro 6.4, and the theme supports Astro 5 and 6 as well.
|
|
29
|
+
*/
|
|
30
|
+
export interface MarkdownProcessorLike {
|
|
31
|
+
name: string;
|
|
32
|
+
options?: {
|
|
33
|
+
remarkPlugins?: unknown[];
|
|
34
|
+
rehypePlugins?: unknown[];
|
|
35
|
+
mdastPlugins?: unknown[];
|
|
36
|
+
hastPlugins?: unknown[];
|
|
37
|
+
[key: string]: unknown;
|
|
38
|
+
};
|
|
39
|
+
createRenderer?: unknown;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Structural shape of `markdown` in an Astro config, including the keys the
|
|
44
|
+
* installed Astro version may not know about yet.
|
|
45
|
+
*/
|
|
46
|
+
export interface MarkdownConfigLike {
|
|
47
|
+
processor?: MarkdownProcessorLike;
|
|
48
|
+
remarkPlugins?: unknown[];
|
|
49
|
+
rehypePlugins?: unknown[];
|
|
50
|
+
remarkRehype?: Record<string, unknown>;
|
|
51
|
+
gfm?: boolean;
|
|
52
|
+
smartypants?: unknown;
|
|
53
|
+
[key: string]: unknown;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
/** A `unified()` processor from `@astrojs/markdown-remark`. */
|
|
57
|
+
export function isUnifiedProcessor(
|
|
58
|
+
processor: MarkdownProcessorLike | undefined,
|
|
59
|
+
): processor is MarkdownProcessorLike & { options: { rehypePlugins: unknown[] } } {
|
|
60
|
+
return processor?.name === "unified" && Array.isArray(processor.options?.rehypePlugins);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* Plugins registered against a non-`unified` processor (Sätteri's `mdastPlugins`
|
|
65
|
+
* / `hastPlugins`).
|
|
66
|
+
*
|
|
67
|
+
* These use a different plugin system than remark/rehype — a visitor object from
|
|
68
|
+
* `defineHastPlugin()`, not a unified transformer — so they cannot be carried
|
|
69
|
+
* across when a processor is replaced. Counting them is how the theme detects
|
|
70
|
+
* that a replacement would silently drop somebody else's work.
|
|
71
|
+
*/
|
|
72
|
+
function countProcessorPlugins(processor: MarkdownProcessorLike): number {
|
|
73
|
+
const { mdastPlugins, hastPlugins } = processor.options ?? {};
|
|
74
|
+
return (
|
|
75
|
+
(Array.isArray(mdastPlugins) ? mdastPlugins.length : 0) + (Array.isArray(hastPlugins) ? hastPlugins.length : 0)
|
|
76
|
+
);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Return a `markdown` config that is guaranteed to use a `unified()` processor.
|
|
81
|
+
*
|
|
82
|
+
* Call this while building the Astro config — before `starlight()` runs — so no
|
|
83
|
+
* plugin ever observes the Sätteri default. A processor the consumer supplied
|
|
84
|
+
* themselves is respected as-is (a non-`unified` one earns a warning, because
|
|
85
|
+
* several Starlight plugins the theme ships with only support `unified`).
|
|
86
|
+
*
|
|
87
|
+
* User-supplied `remarkPlugins` / `rehypePlugins` are deliberately *not* copied
|
|
88
|
+
* into the processor: Astro migrates those deprecated top-level arrays onto a
|
|
89
|
+
* `unified` processor itself (exactly once, tracked internally), and on Astro
|
|
90
|
+
* versions without `markdown.processor` they are the whole pipeline. Baking
|
|
91
|
+
* copies in here would run them twice.
|
|
92
|
+
*/
|
|
93
|
+
export function withUnifiedProcessor(
|
|
94
|
+
markdown: MarkdownConfigLike | undefined,
|
|
95
|
+
warn: (message: string) => void = console.warn,
|
|
96
|
+
): MarkdownConfigLike {
|
|
97
|
+
const config = markdown ?? {};
|
|
98
|
+
|
|
99
|
+
if (config.processor) {
|
|
100
|
+
if (!isUnifiedProcessor(config.processor)) {
|
|
101
|
+
warn(
|
|
102
|
+
`[northwestern-starlight-theme] \`markdown.processor\` is set to \`${config.processor.name}()\`. ` +
|
|
103
|
+
"The theme's scrollable tables and Starlight plugins such as `starlight-image-zoom` require the " +
|
|
104
|
+
"`unified()` processor from `@astrojs/markdown-remark`. Remove `markdown.processor` to let the " +
|
|
105
|
+
"theme configure it, or set it to `unified({ ... })`.",
|
|
106
|
+
);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
return config;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return {
|
|
113
|
+
...config,
|
|
114
|
+
processor: unified({
|
|
115
|
+
remarkRehype: config.remarkRehype,
|
|
116
|
+
gfm: config.gfm,
|
|
117
|
+
smartypants: config.smartypants,
|
|
118
|
+
} as Parameters<typeof unified>[0]) as MarkdownProcessorLike,
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/**
|
|
123
|
+
* Register a rehype plugin on the active Markdown pipeline.
|
|
124
|
+
*
|
|
125
|
+
* Returns a `markdown` config patch to hand to `updateConfig()`, or `undefined`
|
|
126
|
+
* when the plugin was added to the live processor and no config update is
|
|
127
|
+
* needed. Mutating `processor.options` is how Astro itself extends a processor
|
|
128
|
+
* after config resolution — the object identity survives config validation
|
|
129
|
+
* precisely so that late registrations still apply.
|
|
130
|
+
*
|
|
131
|
+
* A non-`unified` processor is left alone. Replacing it here is what used to
|
|
132
|
+
* discard Sätteri-registered plugins from unrelated Starlight plugins, so the
|
|
133
|
+
* theme warns instead of swapping behind their back.
|
|
134
|
+
*/
|
|
135
|
+
export function addRehypePlugin(
|
|
136
|
+
markdown: MarkdownConfigLike | undefined,
|
|
137
|
+
plugin: unknown,
|
|
138
|
+
warn: (message: string) => void = console.warn,
|
|
139
|
+
): MarkdownConfigLike | undefined {
|
|
140
|
+
const config = markdown ?? {};
|
|
141
|
+
const processor = config.processor;
|
|
142
|
+
|
|
143
|
+
// Astro < 6.4: the top-level plugin arrays are the entire pipeline.
|
|
144
|
+
if (!processor) {
|
|
145
|
+
return { rehypePlugins: [...(config.rehypePlugins ?? []), plugin] };
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
if (isUnifiedProcessor(processor)) {
|
|
149
|
+
if (!processor.options.rehypePlugins.includes(plugin)) {
|
|
150
|
+
processor.options.rehypePlugins.push(plugin);
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return undefined;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const registered = countProcessorPlugins(processor);
|
|
157
|
+
warn(
|
|
158
|
+
`[northwestern-starlight-theme] Markdown is rendered by the \`${processor.name}()\` processor, which the theme ` +
|
|
159
|
+
"does not extend. Scrollable table wrappers are disabled for this build" +
|
|
160
|
+
(registered > 0
|
|
161
|
+
? `, and converting the processor would drop ${registered} plugin(s) other integrations registered on it. `
|
|
162
|
+
: ". ") +
|
|
163
|
+
"Use `defineNorthwesternConfig()` (it installs a `unified()` processor for you) or set " +
|
|
164
|
+
"`markdown.processor: unified({ ... })` from `@astrojs/markdown-remark`.",
|
|
165
|
+
);
|
|
166
|
+
|
|
167
|
+
return undefined;
|
|
168
|
+
}
|