@astrojs/starlight 0.39.3 → 0.40.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/CHANGELOG.md +35 -0
- package/components/AnchorHeading.astro +2 -1
- package/index.ts +25 -19
- package/integrations/anchor-icon.ts +5 -0
- package/integrations/aside-icons.ts +39 -0
- package/integrations/asides.ts +8 -62
- package/integrations/code-rtl-support.ts +2 -2
- package/integrations/heading-links.ts +4 -6
- package/integrations/markdown-plugins.ts +68 -0
- package/integrations/markdown-process.ts +52 -0
- package/integrations/remark-rehype.ts +16 -51
- package/integrations/satteri.ts +292 -0
- package/package.json +14 -6
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,40 @@
|
|
|
1
1
|
# @astrojs/starlight
|
|
2
2
|
|
|
3
|
+
## 0.40.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#3923](https://github.com/withastro/starlight/pull/3923) [`edf2e6b`](https://github.com/withastro/starlight/commit/edf2e6bf46b2a0809eb4d5877eb817b224b50af4) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Adds support for Astro 6.4 and the new Sätteri Markdown processor.
|
|
8
|
+
|
|
9
|
+
It is now possible to opt into using [Astro's 6.4 Sätteri Markdown processor](https://astro.build/blog/astro-640/#faster-markdown-builds-with-s%C3%A4tteri) by installing the `@astrojs/markdown-satteri` package and configuring it in your `astro.config.mjs` file:
|
|
10
|
+
|
|
11
|
+
```js
|
|
12
|
+
// astro.config.mjs
|
|
13
|
+
|
|
14
|
+
import { defineConfig } from 'astro/config';
|
|
15
|
+
import { satteri } from '@astrojs/markdown-satteri';
|
|
16
|
+
|
|
17
|
+
export default defineConfig({
|
|
18
|
+
markdown: {
|
|
19
|
+
processor: satteri(),
|
|
20
|
+
},
|
|
21
|
+
});
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
⚠️ **BREAKING CHANGE:** The minimum supported version of Astro is now v6.4.5.
|
|
25
|
+
|
|
26
|
+
Please update Starlight and Astro together:
|
|
27
|
+
|
|
28
|
+
```sh
|
|
29
|
+
npx @astrojs/upgrade
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
_Community Starlight plugins and Astro integrations may also need to be manually updated to work with Sätteri. If you encounter any issues, please reach out to the plugin or integration author to see if it is a known issue or if an updated version is being worked on._
|
|
33
|
+
|
|
34
|
+
### Patch Changes
|
|
35
|
+
|
|
36
|
+
- [#3923](https://github.com/withastro/starlight/pull/3923) [`edf2e6b`](https://github.com/withastro/starlight/commit/edf2e6bf46b2a0809eb4d5877eb817b224b50af4) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Updates Expressive Code to version 0.43.1.
|
|
37
|
+
|
|
3
38
|
## 0.39.3
|
|
4
39
|
|
|
5
40
|
### Patch Changes
|
|
@@ -7,6 +7,7 @@ import sanitize from 'ultrahtml/transformers/sanitize';
|
|
|
7
7
|
// global Markdown option disabled.
|
|
8
8
|
import '../style/anchor-links.css';
|
|
9
9
|
import { AstroError } from 'astro/errors';
|
|
10
|
+
import { anchorLinkIconPath } from '../integrations/anchor-icon';
|
|
10
11
|
|
|
11
12
|
const headingLevels = [1, 2, 3, 4, 5, 6, '1', '2', '3', '4', '5', '6'] as const;
|
|
12
13
|
interface Props extends HTMLAttributes<'h1'> {
|
|
@@ -45,7 +46,7 @@ const accessibleLabel = Astro.locals.t('heading.anchorLabel', {
|
|
|
45
46
|
><svg width="16" height="16" viewBox="0 0 24 24"
|
|
46
47
|
><path
|
|
47
48
|
fill="currentcolor"
|
|
48
|
-
d=
|
|
49
|
+
d={anchorLinkIconPath}
|
|
49
50
|
></path></svg
|
|
50
51
|
></span
|
|
51
52
|
><span class="sr-only" data-pagefind-ignore="" set:text={accessibleLabel} /></a
|
package/index.ts
CHANGED
|
@@ -10,12 +10,12 @@
|
|
|
10
10
|
import mdx from '@astrojs/mdx';
|
|
11
11
|
import type { AstroIntegration } from 'astro';
|
|
12
12
|
import { AstroError } from 'astro/errors';
|
|
13
|
+
import type { MarkdownProcessorPluginOptions } from './integrations/markdown-process';
|
|
13
14
|
import {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
} from './integrations/
|
|
18
|
-
import { starlightDirectivesRestorationIntegration } from './integrations/asides';
|
|
15
|
+
applyStarlightMarkdownPlugins,
|
|
16
|
+
satteriIntegration,
|
|
17
|
+
starlightDirectivesRestorationIntegration,
|
|
18
|
+
} from './integrations/markdown-plugins';
|
|
19
19
|
import { starlightExpressiveCode } from './integrations/expressive-code/index';
|
|
20
20
|
import { starlightPagefind } from './integrations/pagefind';
|
|
21
21
|
import { starlightSitemap } from './integrations/sitemap';
|
|
@@ -90,6 +90,12 @@ export default function StarlightIntegration(
|
|
|
90
90
|
prerender: starlightConfig.prerender,
|
|
91
91
|
});
|
|
92
92
|
|
|
93
|
+
// Astro 6.4+ always sets `config.markdown.processor` (defaulting to `unified()`). Resolve
|
|
94
|
+
// it and the optional Sätteri integration up front so we can reject unsupported
|
|
95
|
+
// usage before wiring up the integrations below.
|
|
96
|
+
const processor = config.markdown.processor;
|
|
97
|
+
const satteri = await satteriIntegration;
|
|
98
|
+
|
|
93
99
|
// Add built-in integrations only if they are not already added by the user through the
|
|
94
100
|
// config or by a plugin.
|
|
95
101
|
const allIntegrations = [...config.integrations, ...integrations];
|
|
@@ -105,9 +111,20 @@ export default function StarlightIntegration(
|
|
|
105
111
|
integrations.push(mdx({ optimize: true }));
|
|
106
112
|
}
|
|
107
113
|
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
114
|
+
const markdownProcessorOptions: MarkdownProcessorPluginOptions = {
|
|
115
|
+
starlightConfig,
|
|
116
|
+
astroConfig: config,
|
|
117
|
+
useTranslations,
|
|
118
|
+
absolutePathToLang,
|
|
119
|
+
};
|
|
120
|
+
|
|
121
|
+
// We push our plugins onto the processor's options.
|
|
122
|
+
applyStarlightMarkdownPlugins(processor, markdownProcessorOptions, satteri, logger);
|
|
123
|
+
|
|
124
|
+
// Add Starlight directives restoration integration at the end of the list so that
|
|
125
|
+
// remark/mdast plugins injected by Starlight plugins through Astro integrations can
|
|
126
|
+
// handle text and leaf directives before they are transformed back to their original
|
|
127
|
+
// form.
|
|
111
128
|
integrations.push(starlightDirectivesRestorationIntegration());
|
|
112
129
|
|
|
113
130
|
// Add integrations immediately after Starlight in the config array.
|
|
@@ -117,13 +134,6 @@ export default function StarlightIntegration(
|
|
|
117
134
|
const selfIndex = config.integrations.findIndex((i) => i.name === '@astrojs/starlight');
|
|
118
135
|
config.integrations.splice(selfIndex + 1, 0, ...integrations);
|
|
119
136
|
|
|
120
|
-
const remarkRehypeOptions: RemarkRehypePluginOptions = {
|
|
121
|
-
starlightConfig,
|
|
122
|
-
astroConfig: config,
|
|
123
|
-
useTranslations,
|
|
124
|
-
absolutePathToLang,
|
|
125
|
-
};
|
|
126
|
-
|
|
127
137
|
// TODO: refactor once there is a reliable way to detect non-Node.js compatible
|
|
128
138
|
// environments, rather than relying on the presence of specific adapters/integrations.
|
|
129
139
|
const isCloudflareEnv =
|
|
@@ -169,10 +179,6 @@ export default function StarlightIntegration(
|
|
|
169
179
|
},
|
|
170
180
|
},
|
|
171
181
|
},
|
|
172
|
-
markdown: {
|
|
173
|
-
remarkPlugins: [...starlightRemarkPlugins(remarkRehypeOptions)],
|
|
174
|
-
rehypePlugins: [...starlightRehypePlugins(remarkRehypeOptions)],
|
|
175
|
-
},
|
|
176
182
|
scopedStyleStrategy: 'where',
|
|
177
183
|
// If not already configured, default to prefetching all links on hover.
|
|
178
184
|
prefetch: config.prefetch ?? { prefetchAll: true },
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// SVG `d` for the anchor-link icon rendered next to headings. Shared by the unified
|
|
2
|
+
// (`heading-links.ts`) and Sätteri (`satteri.ts`) autolink plugins and the `<AnchorHeading>`
|
|
3
|
+
// component so the three stay in sync.
|
|
4
|
+
export const anchorLinkIconPath =
|
|
5
|
+
'm12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z';
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const asideVariants = ['note', 'tip', 'caution', 'danger'] as const;
|
|
2
|
+
export type AsideVariant = (typeof asideVariants)[number];
|
|
3
|
+
|
|
4
|
+
const asideVariantSet = new Set<string>(asideVariants);
|
|
5
|
+
export function isAsideVariant(value: string): value is AsideVariant {
|
|
6
|
+
return asideVariantSet.has(value);
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export const asideIconPathAttrs = {
|
|
10
|
+
// Information icon
|
|
11
|
+
note: [
|
|
12
|
+
{
|
|
13
|
+
d: 'M12 11C11.7348 11 11.4804 11.1054 11.2929 11.2929C11.1054 11.4804 11 11.7348 11 12V16C11 16.2652 11.1054 16.5196 11.2929 16.7071C11.4804 16.8946 11.7348 17 12 17C12.2652 17 12.5196 16.8946 12.7071 16.7071C12.8946 16.5196 13 16.2652 13 16V12C13 11.7348 12.8946 11.4804 12.7071 11.2929C12.5196 11.1054 12.2652 11 12 11ZM12.38 7.08C12.1365 6.97998 11.8635 6.97998 11.62 7.08C11.4973 7.12759 11.3851 7.19896 11.29 7.29C11.2017 7.3872 11.1306 7.49882 11.08 7.62C11.024 7.73868 10.9966 7.86882 11 8C10.9992 8.13161 11.0245 8.26207 11.0742 8.38391C11.124 8.50574 11.1973 8.61656 11.29 8.71C11.3872 8.79833 11.4988 8.86936 11.62 8.92C11.7715 8.98224 11.936 9.00632 12.099 8.99011C12.2619 8.97391 12.4184 8.91792 12.5547 8.82707C12.691 8.73622 12.8029 8.61328 12.8805 8.46907C12.9582 8.32486 12.9992 8.16378 13 8C12.9963 7.73523 12.8927 7.48163 12.71 7.29C12.6149 7.19896 12.5028 7.12759 12.38 7.08ZM12 2C10.0222 2 8.08879 2.58649 6.4443 3.6853C4.79981 4.78412 3.51809 6.3459 2.76121 8.17317C2.00433 10.0004 1.8063 12.0111 2.19215 13.9509C2.578 15.8907 3.53041 17.6725 4.92894 19.0711C6.32746 20.4696 8.10929 21.422 10.0491 21.8079C11.9889 22.1937 13.9996 21.9957 15.8268 21.2388C17.6541 20.4819 19.2159 19.2002 20.3147 17.5557C21.4135 15.9112 22 13.9778 22 12C22 10.6868 21.7413 9.38642 21.2388 8.17317C20.7363 6.95991 19.9997 5.85752 19.0711 4.92893C18.1425 4.00035 17.0401 3.26375 15.8268 2.7612C14.6136 2.25866 13.3132 2 12 2ZM12 20C10.4178 20 8.87104 19.5308 7.55544 18.6518C6.23985 17.7727 5.21447 16.5233 4.60897 15.0615C4.00347 13.5997 3.84504 11.9911 4.15372 10.4393C4.4624 8.88743 5.22433 7.46197 6.34315 6.34315C7.46197 5.22433 8.88743 4.4624 10.4393 4.15372C11.9911 3.84504 13.5997 4.00346 15.0615 4.60896C16.5233 5.21447 17.7727 6.23984 18.6518 7.55544C19.5308 8.87103 20 10.4177 20 12C20 14.1217 19.1572 16.1566 17.6569 17.6569C16.1566 19.1571 14.1217 20 12 20Z',
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
// Rocket icon
|
|
17
|
+
tip: [
|
|
18
|
+
{
|
|
19
|
+
'fill-rule': 'evenodd',
|
|
20
|
+
'clip-rule': 'evenodd',
|
|
21
|
+
d: 'M1.43909 8.85483L1.44039 8.85354L4.96668 5.33815C5.30653 4.99386 5.7685 4.79662 6.2524 4.78972L6.26553 4.78963L12.9014 4.78962L13.8479 3.84308C16.9187 0.772319 20.0546 0.770617 21.4678 0.975145C21.8617 1.02914 22.2271 1.21053 22.5083 1.4917C22.7894 1.77284 22.9708 2.13821 23.0248 2.53199C23.2294 3.94517 23.2278 7.08119 20.1569 10.1521L19.2107 11.0983V17.7338L19.2106 17.7469C19.2037 18.2308 19.0067 18.6933 18.6624 19.0331L15.1456 22.5608C14.9095 22.7966 14.6137 22.964 14.29 23.0449C13.9663 23.1259 13.6267 23.1174 13.3074 23.0204C12.9881 22.9235 12.7011 22.7417 12.4771 22.4944C12.2533 22.2473 12.1006 21.9441 12.0355 21.6171L11.1783 17.3417L6.65869 12.822L4.34847 12.3589L2.38351 11.965C2.05664 11.8998 1.75272 11.747 1.50564 11.5232C1.25835 11.2992 1.07653 11.0122 0.979561 10.6929C0.882595 10.3736 0.874125 10.034 0.955057 9.7103C1.03599 9.38659 1.20328 9.09092 1.43909 8.85483ZM6.8186 10.8724L2.94619 10.096L6.32006 6.73268H10.9583L6.8186 10.8724ZM15.2219 5.21703C17.681 2.75787 20.0783 2.75376 21.1124 2.8876C21.2462 3.92172 21.2421 6.31895 18.783 8.77812L12.0728 15.4883L8.51172 11.9272L15.2219 5.21703ZM13.9042 21.0538L13.1279 17.1811L17.2676 13.0414V17.68L13.9042 21.0538Z',
|
|
22
|
+
},
|
|
23
|
+
{
|
|
24
|
+
d: 'M9.31827 18.3446C9.45046 17.8529 9.17864 17.3369 8.68945 17.1724C8.56178 17.1294 8.43145 17.1145 8.30512 17.1243C8.10513 17.1398 7.91519 17.2172 7.76181 17.3434C7.62613 17.455 7.51905 17.6048 7.45893 17.7835C6.97634 19.2186 5.77062 19.9878 4.52406 20.4029C4.08525 20.549 3.6605 20.644 3.29471 20.7053C3.35607 20.3395 3.45098 19.9148 3.59711 19.476C4.01221 18.2294 4.78141 17.0237 6.21648 16.5411C6.39528 16.481 6.54504 16.3739 6.65665 16.2382C6.85126 16.0016 6.92988 15.678 6.84417 15.3647C6.83922 15.3466 6.83373 15.3286 6.82767 15.3106C6.74106 15.053 6.55701 14.8557 6.33037 14.7459C6.10949 14.6389 5.84816 14.615 5.59715 14.6994C5.47743 14.7397 5.36103 14.7831 5.24786 14.8294C3.22626 15.6569 2.2347 17.4173 1.75357 18.8621C1.49662 19.6337 1.36993 20.3554 1.30679 20.8818C1.27505 21.1464 1.25893 21.3654 1.25072 21.5213C1.24662 21.5993 1.24448 21.6618 1.24337 21.7066L1.243 21.7226L1.24235 21.7605L1.2422 21.7771L1.24217 21.7827L1.24217 21.7856C1.24217 22.3221 1.67703 22.7579 2.2137 22.7579L2.2155 22.7579L2.22337 22.7578L2.23956 22.7577C2.25293 22.7575 2.27096 22.7572 2.29338 22.7567C2.33821 22.7555 2.40073 22.7534 2.47876 22.7493C2.63466 22.7411 2.85361 22.725 3.11822 22.6932C3.64462 22.6301 4.36636 22.5034 5.13797 22.2464C6.58274 21.7653 8.3431 20.7738 9.17063 18.7522C9.21696 18.639 9.26037 18.5226 9.30064 18.4029C9.30716 18.3835 9.31304 18.364 9.31827 18.3446Z',
|
|
25
|
+
},
|
|
26
|
+
],
|
|
27
|
+
// Warning triangle icon
|
|
28
|
+
caution: [
|
|
29
|
+
{
|
|
30
|
+
d: 'M12 16C11.8022 16 11.6089 16.0587 11.4444 16.1686C11.28 16.2784 11.1518 16.4346 11.0761 16.6173C11.0004 16.8001 10.9806 17.0011 11.0192 17.1951C11.0578 17.3891 11.153 17.5673 11.2929 17.7071C11.4327 17.847 11.6109 17.9422 11.8049 17.9808C11.9989 18.0194 12.2 17.9996 12.3827 17.9239C12.5654 17.8482 12.7216 17.72 12.8315 17.5556C12.9413 17.3911 13 17.1978 13 17C13 16.7348 12.8946 16.4805 12.7071 16.2929C12.5196 16.1054 12.2652 16 12 16ZM22.67 17.47L14.62 3.47003C14.3598 3.00354 13.9798 2.61498 13.5192 2.3445C13.0586 2.07401 12.5341 1.9314 12 1.9314C11.4659 1.9314 10.9414 2.07401 10.4808 2.3445C10.0202 2.61498 9.64019 3.00354 9.38 3.47003L1.38 17.47C1.11079 17.924 0.966141 18.441 0.960643 18.9688C0.955144 19.4966 1.089 20.0166 1.34868 20.4761C1.60837 20.9356 1.9847 21.3185 2.43968 21.5861C2.89466 21.8536 3.41218 21.9964 3.94 22H20.06C20.5921 22.0053 21.1159 21.8689 21.5779 21.6049C22.0399 21.341 22.4234 20.9589 22.689 20.4978C22.9546 20.0368 23.0928 19.5134 23.0895 18.9814C23.0862 18.4493 22.9414 17.9277 22.67 17.47ZM20.94 19.47C20.8523 19.626 20.7245 19.7556 20.5697 19.8453C20.4149 19.935 20.2389 19.9815 20.06 19.98H3.94C3.76111 19.9815 3.5851 19.935 3.43032 19.8453C3.27553 19.7556 3.14765 19.626 3.06 19.47C2.97223 19.318 2.92602 19.1456 2.92602 18.97C2.92602 18.7945 2.97223 18.622 3.06 18.47L11.06 4.47003C11.1439 4.30623 11.2714 4.16876 11.4284 4.07277C11.5855 3.97678 11.766 3.92599 11.95 3.92599C12.134 3.92599 12.3145 3.97678 12.4716 4.07277C12.6286 4.16876 12.7561 4.30623 12.84 4.47003L20.89 18.47C20.9892 18.6199 21.0462 18.7937 21.055 18.9732C21.0638 19.1527 21.0241 19.3312 20.94 19.49V19.47ZM12 8.00003C11.7348 8.00003 11.4804 8.10538 11.2929 8.29292C11.1054 8.48046 11 8.73481 11 9.00003V13C11 13.2652 11.1054 13.5196 11.2929 13.7071C11.4804 13.8947 11.7348 14 12 14C12.2652 14 12.5196 13.8947 12.7071 13.7071C12.8946 13.5196 13 13.2652 13 13V9.00003C13 8.73481 12.8946 8.48046 12.7071 8.29292C12.5196 8.10538 12.2652 8.00003 12 8.00003Z',
|
|
31
|
+
},
|
|
32
|
+
],
|
|
33
|
+
// Error shield icon
|
|
34
|
+
danger: [
|
|
35
|
+
{
|
|
36
|
+
d: 'M12 7C11.7348 7 11.4804 7.10536 11.2929 7.29289C11.1054 7.48043 11 7.73478 11 8V12C11 12.2652 11.1054 12.5196 11.2929 12.7071C11.4804 12.8946 11.7348 13 12 13C12.2652 13 12.5196 12.8946 12.7071 12.7071C12.8946 12.5196 13 12.2652 13 12V8C13 7.73478 12.8946 7.48043 12.7071 7.29289C12.5196 7.10536 12.2652 7 12 7ZM12 15C11.8022 15 11.6089 15.0586 11.4444 15.1685C11.28 15.2784 11.1518 15.4346 11.0761 15.6173C11.0004 15.8 10.9806 16.0011 11.0192 16.1951C11.0578 16.3891 11.153 16.5673 11.2929 16.7071C11.4327 16.847 11.6109 16.9422 11.8049 16.9808C11.9989 17.0194 12.2 16.9996 12.3827 16.9239C12.5654 16.8482 12.7216 16.72 12.8315 16.5556C12.9414 16.3911 13 16.1978 13 16C13 15.7348 12.8946 15.4804 12.7071 15.2929C12.5196 15.1054 12.2652 15 12 15ZM21.71 7.56L16.44 2.29C16.2484 2.10727 15.9948 2.00368 15.73 2H8.27C8.00523 2.00368 7.75163 2.10727 7.56 2.29L2.29 7.56C2.10727 7.75163 2.00368 8.00523 2 8.27V15.73C2.00368 15.9948 2.10727 16.2484 2.29 16.44L7.56 21.71C7.75163 21.8927 8.00523 21.9963 8.27 22H15.73C15.9948 21.9963 16.2484 21.8927 16.44 21.71L21.71 16.44C21.8927 16.2484 21.9963 15.9948 22 15.73V8.27C21.9963 8.00523 21.8927 7.75163 21.71 7.56ZM20 15.31L15.31 20H8.69L4 15.31V8.69L8.69 4H15.31L20 8.69V15.31Z',
|
|
37
|
+
},
|
|
38
|
+
],
|
|
39
|
+
} as const satisfies Record<AsideVariant, ReadonlyArray<Record<string, string>>>;
|
package/integrations/asides.ts
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
/// <reference types="mdast-util-directive" />
|
|
2
2
|
|
|
3
|
-
import type { AstroIntegration } from 'astro';
|
|
4
3
|
import { h as _h, s as _s, type Properties, type Result } from 'hastscript';
|
|
5
4
|
import type { Node, Paragraph as P, Parent, PhrasingContent, Root } from 'mdast';
|
|
6
5
|
import {
|
|
@@ -13,12 +12,13 @@ import { toMarkdown } from 'mdast-util-to-markdown';
|
|
|
13
12
|
import { toString } from 'mdast-util-to-string';
|
|
14
13
|
import type { Plugin, Transformer } from 'unified';
|
|
15
14
|
import { visit } from 'unist-util-visit';
|
|
16
|
-
import type {
|
|
15
|
+
import type { MarkdownProcessorPluginOptions } from './markdown-process';
|
|
17
16
|
import type { StarlightIcon } from '../types';
|
|
18
17
|
import { Icons } from '../components-internals/Icons';
|
|
19
18
|
import { fromHtml } from 'hast-util-from-html';
|
|
20
19
|
import type { Element } from 'hast';
|
|
21
20
|
import { throwInvalidAsideIconError } from './asides-error';
|
|
21
|
+
import { asideIconPathAttrs, isAsideVariant, type AsideVariant } from './aside-icons';
|
|
22
22
|
|
|
23
23
|
/** Hacky function that generates an mdast HTML tree ready for conversion to HTML by rehype. */
|
|
24
24
|
function h(el: string, attrs: Properties = {}, children: unknown[] = []): P {
|
|
@@ -124,41 +124,12 @@ function makeSvgChildNodes(children: Result['children']): P[] {
|
|
|
124
124
|
* </aside>
|
|
125
125
|
* ```
|
|
126
126
|
*/
|
|
127
|
-
export function remarkAsides(options:
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
// Information icon
|
|
134
|
-
note: [
|
|
135
|
-
s('path', {
|
|
136
|
-
d: 'M12 11C11.7348 11 11.4804 11.1054 11.2929 11.2929C11.1054 11.4804 11 11.7348 11 12V16C11 16.2652 11.1054 16.5196 11.2929 16.7071C11.4804 16.8946 11.7348 17 12 17C12.2652 17 12.5196 16.8946 12.7071 16.7071C12.8946 16.5196 13 16.2652 13 16V12C13 11.7348 12.8946 11.4804 12.7071 11.2929C12.5196 11.1054 12.2652 11 12 11ZM12.38 7.08C12.1365 6.97998 11.8635 6.97998 11.62 7.08C11.4973 7.12759 11.3851 7.19896 11.29 7.29C11.2017 7.3872 11.1306 7.49882 11.08 7.62C11.024 7.73868 10.9966 7.86882 11 8C10.9992 8.13161 11.0245 8.26207 11.0742 8.38391C11.124 8.50574 11.1973 8.61656 11.29 8.71C11.3872 8.79833 11.4988 8.86936 11.62 8.92C11.7715 8.98224 11.936 9.00632 12.099 8.99011C12.2619 8.97391 12.4184 8.91792 12.5547 8.82707C12.691 8.73622 12.8029 8.61328 12.8805 8.46907C12.9582 8.32486 12.9992 8.16378 13 8C12.9963 7.73523 12.8927 7.48163 12.71 7.29C12.6149 7.19896 12.5028 7.12759 12.38 7.08ZM12 2C10.0222 2 8.08879 2.58649 6.4443 3.6853C4.79981 4.78412 3.51809 6.3459 2.76121 8.17317C2.00433 10.0004 1.8063 12.0111 2.19215 13.9509C2.578 15.8907 3.53041 17.6725 4.92894 19.0711C6.32746 20.4696 8.10929 21.422 10.0491 21.8079C11.9889 22.1937 13.9996 21.9957 15.8268 21.2388C17.6541 20.4819 19.2159 19.2002 20.3147 17.5557C21.4135 15.9112 22 13.9778 22 12C22 10.6868 21.7413 9.38642 21.2388 8.17317C20.7363 6.95991 19.9997 5.85752 19.0711 4.92893C18.1425 4.00035 17.0401 3.26375 15.8268 2.7612C14.6136 2.25866 13.3132 2 12 2ZM12 20C10.4178 20 8.87104 19.5308 7.55544 18.6518C6.23985 17.7727 5.21447 16.5233 4.60897 15.0615C4.00347 13.5997 3.84504 11.9911 4.15372 10.4393C4.4624 8.88743 5.22433 7.46197 6.34315 6.34315C7.46197 5.22433 8.88743 4.4624 10.4393 4.15372C11.9911 3.84504 13.5997 4.00346 15.0615 4.60896C16.5233 5.21447 17.7727 6.23984 18.6518 7.55544C19.5308 8.87103 20 10.4177 20 12C20 14.1217 19.1572 16.1566 17.6569 17.6569C16.1566 19.1571 14.1217 20 12 20Z',
|
|
137
|
-
}),
|
|
138
|
-
],
|
|
139
|
-
// Rocket icon
|
|
140
|
-
tip: [
|
|
141
|
-
s('path', {
|
|
142
|
-
'fill-rule': 'evenodd',
|
|
143
|
-
'clip-rule': 'evenodd',
|
|
144
|
-
d: 'M1.43909 8.85483L1.44039 8.85354L4.96668 5.33815C5.30653 4.99386 5.7685 4.79662 6.2524 4.78972L6.26553 4.78963L12.9014 4.78962L13.8479 3.84308C16.9187 0.772319 20.0546 0.770617 21.4678 0.975145C21.8617 1.02914 22.2271 1.21053 22.5083 1.4917C22.7894 1.77284 22.9708 2.13821 23.0248 2.53199C23.2294 3.94517 23.2278 7.08119 20.1569 10.1521L19.2107 11.0983V17.7338L19.2106 17.7469C19.2037 18.2308 19.0067 18.6933 18.6624 19.0331L15.1456 22.5608C14.9095 22.7966 14.6137 22.964 14.29 23.0449C13.9663 23.1259 13.6267 23.1174 13.3074 23.0204C12.9881 22.9235 12.7011 22.7417 12.4771 22.4944C12.2533 22.2473 12.1006 21.9441 12.0355 21.6171L11.1783 17.3417L6.65869 12.822L4.34847 12.3589L2.38351 11.965C2.05664 11.8998 1.75272 11.747 1.50564 11.5232C1.25835 11.2992 1.07653 11.0122 0.979561 10.6929C0.882595 10.3736 0.874125 10.034 0.955057 9.7103C1.03599 9.38659 1.20328 9.09092 1.43909 8.85483ZM6.8186 10.8724L2.94619 10.096L6.32006 6.73268H10.9583L6.8186 10.8724ZM15.2219 5.21703C17.681 2.75787 20.0783 2.75376 21.1124 2.8876C21.2462 3.92172 21.2421 6.31895 18.783 8.77812L12.0728 15.4883L8.51172 11.9272L15.2219 5.21703ZM13.9042 21.0538L13.1279 17.1811L17.2676 13.0414V17.68L13.9042 21.0538Z',
|
|
145
|
-
}),
|
|
146
|
-
s('path', {
|
|
147
|
-
d: 'M9.31827 18.3446C9.45046 17.8529 9.17864 17.3369 8.68945 17.1724C8.56178 17.1294 8.43145 17.1145 8.30512 17.1243C8.10513 17.1398 7.91519 17.2172 7.76181 17.3434C7.62613 17.455 7.51905 17.6048 7.45893 17.7835C6.97634 19.2186 5.77062 19.9878 4.52406 20.4029C4.08525 20.549 3.6605 20.644 3.29471 20.7053C3.35607 20.3395 3.45098 19.9148 3.59711 19.476C4.01221 18.2294 4.78141 17.0237 6.21648 16.5411C6.39528 16.481 6.54504 16.3739 6.65665 16.2382C6.85126 16.0016 6.92988 15.678 6.84417 15.3647C6.83922 15.3466 6.83373 15.3286 6.82767 15.3106C6.74106 15.053 6.55701 14.8557 6.33037 14.7459C6.10949 14.6389 5.84816 14.615 5.59715 14.6994C5.47743 14.7397 5.36103 14.7831 5.24786 14.8294C3.22626 15.6569 2.2347 17.4173 1.75357 18.8621C1.49662 19.6337 1.36993 20.3554 1.30679 20.8818C1.27505 21.1464 1.25893 21.3654 1.25072 21.5213C1.24662 21.5993 1.24448 21.6618 1.24337 21.7066L1.243 21.7226L1.24235 21.7605L1.2422 21.7771L1.24217 21.7827L1.24217 21.7856C1.24217 22.3221 1.67703 22.7579 2.2137 22.7579L2.2155 22.7579L2.22337 22.7578L2.23956 22.7577C2.25293 22.7575 2.27096 22.7572 2.29338 22.7567C2.33821 22.7555 2.40073 22.7534 2.47876 22.7493C2.63466 22.7411 2.85361 22.725 3.11822 22.6932C3.64462 22.6301 4.36636 22.5034 5.13797 22.2464C6.58274 21.7653 8.3431 20.7738 9.17063 18.7522C9.21696 18.639 9.26037 18.5226 9.30064 18.4029C9.30716 18.3835 9.31304 18.364 9.31827 18.3446Z',
|
|
148
|
-
}),
|
|
149
|
-
],
|
|
150
|
-
// Warning triangle icon
|
|
151
|
-
caution: [
|
|
152
|
-
s('path', {
|
|
153
|
-
d: 'M12 16C11.8022 16 11.6089 16.0587 11.4444 16.1686C11.28 16.2784 11.1518 16.4346 11.0761 16.6173C11.0004 16.8001 10.9806 17.0011 11.0192 17.1951C11.0578 17.3891 11.153 17.5673 11.2929 17.7071C11.4327 17.847 11.6109 17.9422 11.8049 17.9808C11.9989 18.0194 12.2 17.9996 12.3827 17.9239C12.5654 17.8482 12.7216 17.72 12.8315 17.5556C12.9413 17.3911 13 17.1978 13 17C13 16.7348 12.8946 16.4805 12.7071 16.2929C12.5196 16.1054 12.2652 16 12 16ZM22.67 17.47L14.62 3.47003C14.3598 3.00354 13.9798 2.61498 13.5192 2.3445C13.0586 2.07401 12.5341 1.9314 12 1.9314C11.4659 1.9314 10.9414 2.07401 10.4808 2.3445C10.0202 2.61498 9.64019 3.00354 9.38 3.47003L1.38 17.47C1.11079 17.924 0.966141 18.441 0.960643 18.9688C0.955144 19.4966 1.089 20.0166 1.34868 20.4761C1.60837 20.9356 1.9847 21.3185 2.43968 21.5861C2.89466 21.8536 3.41218 21.9964 3.94 22H20.06C20.5921 22.0053 21.1159 21.8689 21.5779 21.6049C22.0399 21.341 22.4234 20.9589 22.689 20.4978C22.9546 20.0368 23.0928 19.5134 23.0895 18.9814C23.0862 18.4493 22.9414 17.9277 22.67 17.47ZM20.94 19.47C20.8523 19.626 20.7245 19.7556 20.5697 19.8453C20.4149 19.935 20.2389 19.9815 20.06 19.98H3.94C3.76111 19.9815 3.5851 19.935 3.43032 19.8453C3.27553 19.7556 3.14765 19.626 3.06 19.47C2.97223 19.318 2.92602 19.1456 2.92602 18.97C2.92602 18.7945 2.97223 18.622 3.06 18.47L11.06 4.47003C11.1439 4.30623 11.2714 4.16876 11.4284 4.07277C11.5855 3.97678 11.766 3.92599 11.95 3.92599C12.134 3.92599 12.3145 3.97678 12.4716 4.07277C12.6286 4.16876 12.7561 4.30623 12.84 4.47003L20.89 18.47C20.9892 18.6199 21.0462 18.7937 21.055 18.9732C21.0638 19.1527 21.0241 19.3312 20.94 19.49V19.47ZM12 8.00003C11.7348 8.00003 11.4804 8.10538 11.2929 8.29292C11.1054 8.48046 11 8.73481 11 9.00003V13C11 13.2652 11.1054 13.5196 11.2929 13.7071C11.4804 13.8947 11.7348 14 12 14C12.2652 14 12.5196 13.8947 12.7071 13.7071C12.8946 13.5196 13 13.2652 13 13V9.00003C13 8.73481 12.8946 8.48046 12.7071 8.29292C12.5196 8.10538 12.2652 8.00003 12 8.00003Z',
|
|
154
|
-
}),
|
|
155
|
-
],
|
|
156
|
-
// Error shield icon
|
|
157
|
-
danger: [
|
|
158
|
-
s('path', {
|
|
159
|
-
d: 'M12 7C11.7348 7 11.4804 7.10536 11.2929 7.29289C11.1054 7.48043 11 7.73478 11 8V12C11 12.2652 11.1054 12.5196 11.2929 12.7071C11.4804 12.8946 11.7348 13 12 13C12.2652 13 12.5196 12.8946 12.7071 12.7071C12.8946 12.5196 13 12.2652 13 12V8C13 7.73478 12.8946 7.48043 12.7071 7.29289C12.5196 7.10536 12.2652 7 12 7ZM12 15C11.8022 15 11.6089 15.0586 11.4444 15.1685C11.28 15.2784 11.1518 15.4346 11.0761 15.6173C11.0004 15.8 10.9806 16.0011 11.0192 16.1951C11.0578 16.3891 11.153 16.5673 11.2929 16.7071C11.4327 16.847 11.6109 16.9422 11.8049 16.9808C11.9989 17.0194 12.2 16.9996 12.3827 16.9239C12.5654 16.8482 12.7216 16.72 12.8315 16.5556C12.9414 16.3911 13 16.1978 13 16C13 15.7348 12.8946 15.4804 12.7071 15.2929C12.5196 15.1054 12.2652 15 12 15ZM21.71 7.56L16.44 2.29C16.2484 2.10727 15.9948 2.00368 15.73 2H8.27C8.00523 2.00368 7.75163 2.10727 7.56 2.29L2.29 7.56C2.10727 7.75163 2.00368 8.00523 2 8.27V15.73C2.00368 15.9948 2.10727 16.2484 2.29 16.44L7.56 21.71C7.75163 21.8927 8.00523 21.9963 8.27 22H15.73C15.9948 21.9963 16.2484 21.8927 16.44 21.71L21.71 16.44C21.8927 16.2484 21.9963 15.9948 22 15.73V8.27C21.9963 8.00523 21.8927 7.75163 21.71 7.56ZM20 15.31L15.31 20H8.69L4 15.31V8.69L8.69 4H15.31L20 8.69V15.31Z',
|
|
160
|
-
}),
|
|
161
|
-
],
|
|
127
|
+
export function remarkAsides(options: MarkdownProcessorPluginOptions): Plugin<[], Root> {
|
|
128
|
+
const iconPaths: Record<AsideVariant, ReturnType<typeof s>[]> = {
|
|
129
|
+
note: asideIconPathAttrs.note.map((attrs) => s('path', attrs)),
|
|
130
|
+
tip: asideIconPathAttrs.tip.map((attrs) => s('path', attrs)),
|
|
131
|
+
caution: asideIconPathAttrs.caution.map((attrs) => s('path', attrs)),
|
|
132
|
+
danger: asideIconPathAttrs.danger.map((attrs) => s('path', attrs)),
|
|
162
133
|
};
|
|
163
134
|
|
|
164
135
|
const transformer: Transformer<Root> = (tree, file) => {
|
|
@@ -256,28 +227,3 @@ export function remarkDirectivesRestoration() {
|
|
|
256
227
|
});
|
|
257
228
|
};
|
|
258
229
|
}
|
|
259
|
-
|
|
260
|
-
/**
|
|
261
|
-
* Directives not handled by Starlight are transformed back to their original form to avoid
|
|
262
|
-
* breaking user content.
|
|
263
|
-
* To allow remark plugins injected by Starlight plugins through Astro integrations to handle
|
|
264
|
-
* such directives, we need to restore unhandled text and leaf directives back to their original
|
|
265
|
-
* form only after all these other plugins have run.
|
|
266
|
-
* To do so, we run a remark plugin restoring these directives back to their original form from
|
|
267
|
-
* another Astro integration that runs after all the ones that may have been injected by Starlight
|
|
268
|
-
* plugins.
|
|
269
|
-
*/
|
|
270
|
-
export function starlightDirectivesRestorationIntegration(): AstroIntegration {
|
|
271
|
-
return {
|
|
272
|
-
name: 'starlight-directives-restoration',
|
|
273
|
-
hooks: {
|
|
274
|
-
'astro:config:setup': ({ updateConfig }) => {
|
|
275
|
-
updateConfig({
|
|
276
|
-
markdown: {
|
|
277
|
-
remarkPlugins: [remarkDirectivesRestoration],
|
|
278
|
-
},
|
|
279
|
-
});
|
|
280
|
-
},
|
|
281
|
-
},
|
|
282
|
-
};
|
|
283
|
-
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Root } from 'hast';
|
|
2
2
|
import { CONTINUE, SKIP, visit } from 'unist-util-visit';
|
|
3
3
|
import type { Transformer } from 'unified';
|
|
4
|
-
import type {
|
|
4
|
+
import type { MarkdownProcessorPluginOptions } from './markdown-process';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* rehype plugin that adds `dir` attributes to `<code>` and `<pre>`
|
|
@@ -17,7 +17,7 @@ import type { RemarkRehypePluginOptions } from './remark-rehype';
|
|
|
17
17
|
* - `<code>` is often LTR, but could also be RTL. `dir="auto"` ensures the bidirectional
|
|
18
18
|
* algorithm treats the contents of `<code>` in isolation and gives its best guess.
|
|
19
19
|
*/
|
|
20
|
-
export function rehypeRtlCodeSupport(_options:
|
|
20
|
+
export function rehypeRtlCodeSupport(_options: MarkdownProcessorPluginOptions) {
|
|
21
21
|
const transformer: Transformer<Root> = (tree) => {
|
|
22
22
|
visit(tree, 'element', (el) => {
|
|
23
23
|
if (el.tagName === 'pre' || el.tagName === 'code') {
|
|
@@ -3,7 +3,8 @@ import { toString } from 'hast-util-to-string';
|
|
|
3
3
|
import { h } from 'hastscript';
|
|
4
4
|
import type { Transformer } from 'unified';
|
|
5
5
|
import { SKIP, visit } from 'unist-util-visit';
|
|
6
|
-
import
|
|
6
|
+
import { anchorLinkIconPath } from './anchor-icon';
|
|
7
|
+
import type { MarkdownProcessorPluginOptions } from './markdown-process';
|
|
7
8
|
|
|
8
9
|
const AnchorLinkIcon = h(
|
|
9
10
|
'span',
|
|
@@ -11,10 +12,7 @@ const AnchorLinkIcon = h(
|
|
|
11
12
|
h(
|
|
12
13
|
'svg',
|
|
13
14
|
{ width: 16, height: 16, viewBox: '0 0 24 24' },
|
|
14
|
-
h('path', {
|
|
15
|
-
fill: 'currentcolor',
|
|
16
|
-
d: 'm12.11 15.39-3.88 3.88a2.52 2.52 0 0 1-3.5 0 2.47 2.47 0 0 1 0-3.5l3.88-3.88a1 1 0 0 0-1.42-1.42l-3.88 3.89a4.48 4.48 0 0 0 6.33 6.33l3.89-3.88a1 1 0 1 0-1.42-1.42Zm8.58-12.08a4.49 4.49 0 0 0-6.33 0l-3.89 3.88a1 1 0 0 0 1.42 1.42l3.88-3.88a2.52 2.52 0 0 1 3.5 0 2.47 2.47 0 0 1 0 3.5l-3.88 3.88a1 1 0 1 0 1.42 1.42l3.88-3.89a4.49 4.49 0 0 0 0-6.33ZM8.83 15.17a1 1 0 0 0 1.1.22 1 1 0 0 0 .32-.22l4.92-4.92a1 1 0 0 0-1.42-1.42l-4.92 4.92a1 1 0 0 0 0 1.42Z',
|
|
17
|
-
})
|
|
15
|
+
h('path', { fill: 'currentcolor', d: anchorLinkIconPath })
|
|
18
16
|
)
|
|
19
17
|
);
|
|
20
18
|
|
|
@@ -24,7 +22,7 @@ const AnchorLinkIcon = h(
|
|
|
24
22
|
export default function rehypeAutolinkHeadings({
|
|
25
23
|
absolutePathToLang,
|
|
26
24
|
useTranslations,
|
|
27
|
-
}:
|
|
25
|
+
}: MarkdownProcessorPluginOptions) {
|
|
28
26
|
const transformer: Transformer<Root> = (tree, file) => {
|
|
29
27
|
const pageLang = absolutePathToLang(file.path);
|
|
30
28
|
const t = useTranslations(pageLang);
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import { isUnifiedProcessor } from '@astrojs/markdown-remark';
|
|
2
|
+
import type { AstroConfig, AstroIntegration, AstroIntegrationLogger } from 'astro';
|
|
3
|
+
import { remarkDirectivesRestoration } from './asides';
|
|
4
|
+
import type { MarkdownProcessorPluginOptions } from './markdown-process';
|
|
5
|
+
import { starlightRehypePlugins, starlightRemarkPlugins } from './remark-rehype';
|
|
6
|
+
|
|
7
|
+
// For some reason, trying to `await import("./satteri")` in the integration module causes a Vite
|
|
8
|
+
// error about the module runner being closed. This shape works, not sure why!
|
|
9
|
+
export const satteriIntegration = import('./satteri').catch(() => null);
|
|
10
|
+
|
|
11
|
+
type SatteriIntegration = Awaited<typeof satteriIntegration>;
|
|
12
|
+
type MarkdownProcessor = NonNullable<AstroConfig['markdown']['processor']>;
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* Registers Starlight's Markdown transforms on the Astro 6.4+ `markdown.processor`, picking the
|
|
16
|
+
* plugin set for the configured engine.
|
|
17
|
+
*/
|
|
18
|
+
export function applyStarlightMarkdownPlugins(
|
|
19
|
+
processor: MarkdownProcessor,
|
|
20
|
+
options: MarkdownProcessorPluginOptions,
|
|
21
|
+
satteri: SatteriIntegration,
|
|
22
|
+
logger: Pick<AstroIntegrationLogger, 'warn'>
|
|
23
|
+
) {
|
|
24
|
+
if (satteri?.isSatteriProcessor(processor)) {
|
|
25
|
+
// Starlight's asides are built on container directives, which Sätteri disables by default.
|
|
26
|
+
processor.options.features.directive = true;
|
|
27
|
+
const { mdastPlugins, hastPlugins } = satteri.starlightSatteriPlugins(options);
|
|
28
|
+
processor.options.mdastPlugins.push(...mdastPlugins);
|
|
29
|
+
processor.options.hastPlugins.push(...hastPlugins);
|
|
30
|
+
} else if (isUnifiedProcessor(processor)) {
|
|
31
|
+
processor.options.remarkPlugins.push(...starlightRemarkPlugins(options));
|
|
32
|
+
processor.options.rehypePlugins.push(...starlightRehypePlugins(options));
|
|
33
|
+
} else {
|
|
34
|
+
logger.warn(
|
|
35
|
+
`The configured \`markdown.processor\` ("${processor.name}") is not supported by Starlight. ` +
|
|
36
|
+
"Starlight's Markdown transforms (asides, heading anchor links, RTL code support) won't run on your content. " +
|
|
37
|
+
'Switch to `unified()` from `@astrojs/markdown-remark` or `satteri()` from `@astrojs/markdown-satteri`.'
|
|
38
|
+
);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** Registers the directive-restoration plugin on the Astro 6.4+ `markdown.processor`. */
|
|
43
|
+
export function registerDirectivesRestoration(
|
|
44
|
+
processor: MarkdownProcessor,
|
|
45
|
+
satteri: SatteriIntegration
|
|
46
|
+
) {
|
|
47
|
+
if (satteri?.isSatteriProcessor(processor)) {
|
|
48
|
+
processor.options.mdastPlugins.push(satteri.satteriDirectivesRestoration());
|
|
49
|
+
} else if (isUnifiedProcessor(processor)) {
|
|
50
|
+
processor.options.remarkPlugins.push(remarkDirectivesRestoration);
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Run directive-restoration last so plugins added by Starlight plugins (via their own Astro
|
|
56
|
+
* integrations) get to handle text/leaf directives first.
|
|
57
|
+
*/
|
|
58
|
+
export function starlightDirectivesRestorationIntegration(): AstroIntegration {
|
|
59
|
+
return {
|
|
60
|
+
name: 'starlight-directives-restoration',
|
|
61
|
+
hooks: {
|
|
62
|
+
'astro:config:setup': async ({ config }) => {
|
|
63
|
+
const satteri = await satteriIntegration;
|
|
64
|
+
registerDirectivesRestoration(config.markdown?.processor, satteri);
|
|
65
|
+
},
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import type { AstroConfig } from 'astro';
|
|
4
|
+
import { resolveCollectionPath } from '../utils/collection-fs';
|
|
5
|
+
import type { HookParameters, StarlightConfig } from '../types';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Options shared by the plugin factories of both Markdown processors Starlight supports (the unified
|
|
9
|
+
* `remark`/`rehype` pipeline and Sätteri).
|
|
10
|
+
*/
|
|
11
|
+
export interface MarkdownProcessorPluginOptions {
|
|
12
|
+
starlightConfig: Pick<StarlightConfig, 'defaultLocale' | 'locales' | 'markdown'>;
|
|
13
|
+
astroConfig: Pick<AstroConfig, 'root' | 'srcDir'>;
|
|
14
|
+
useTranslations: HookParameters<'config:setup'>['useTranslations'];
|
|
15
|
+
absolutePathToLang: HookParameters<'config:setup'>['absolutePathToLang'];
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Returns the paths to the Starlight docs collection and any additional paths defined in the
|
|
20
|
+
* `starlightConfig.markdown.processedDirs` option that can be used with the {@link shouldTransformPath}
|
|
21
|
+
* utility to determine if a file should be transformed by a plugin or not.
|
|
22
|
+
*/
|
|
23
|
+
export function getMarkdownProcessorPaths(options: MarkdownProcessorPluginOptions): string[] {
|
|
24
|
+
const paths = [normalizePath(resolveCollectionPath('docs', options.astroConfig.srcDir))];
|
|
25
|
+
|
|
26
|
+
for (const processedDir of options.starlightConfig.markdown.processedDirs) {
|
|
27
|
+
paths.push(normalizePath(resolve(fileURLToPath(options.astroConfig.root), processedDir)));
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
return paths;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Determines if a file should be transformed by a Markdown plugin, e.g. files without a known path
|
|
35
|
+
* or files that are not part of the allowed paths are skipped. Accepts a path string (as the unified
|
|
36
|
+
* pipeline exposes via `VFile`) or a `URL` (as Sätteri exposes via `ctx.fileURL`).
|
|
37
|
+
*/
|
|
38
|
+
export function shouldTransformPath(path: string | URL | undefined, allowedPaths: string[]) {
|
|
39
|
+
if (!path) return false;
|
|
40
|
+
const normalizedPath = normalizePath(path instanceof URL ? fileURLToPath(path) : path);
|
|
41
|
+
return allowedPaths.some((p) => normalizedPath.startsWith(p));
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* File path separators seems to be inconsistent on Windows between remark/rehype plugins used on
|
|
46
|
+
* Markdown vs MDX files.
|
|
47
|
+
* For the time being, we normalize all paths to unix style paths.
|
|
48
|
+
*/
|
|
49
|
+
const backSlashRegex = /\\/g;
|
|
50
|
+
function normalizePath(path: string) {
|
|
51
|
+
return path.replace(backSlashRegex, '/');
|
|
52
|
+
}
|
|
@@ -1,25 +1,25 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
import type { AstroConfig } from 'astro';
|
|
4
1
|
import { rehypeHeadingIds } from '@astrojs/markdown-remark';
|
|
5
2
|
import type { Root as RehypeRoot } from 'hast';
|
|
6
3
|
import type { Root as RemarkRoot } from 'mdast';
|
|
7
4
|
import remarkDirective from 'remark-directive';
|
|
8
5
|
import type { Plugin } from 'unified';
|
|
9
6
|
import type { VFile } from 'vfile';
|
|
10
|
-
import { resolveCollectionPath } from '../utils/collection-fs';
|
|
11
|
-
import type { HookParameters, StarlightConfig } from '../types';
|
|
12
7
|
import { remarkAsides } from './asides';
|
|
13
8
|
import { rehypeRtlCodeSupport } from './code-rtl-support';
|
|
14
9
|
import rehypeAutolinkHeadings from './heading-links';
|
|
10
|
+
import {
|
|
11
|
+
getMarkdownProcessorPaths,
|
|
12
|
+
shouldTransformPath,
|
|
13
|
+
type MarkdownProcessorPluginOptions,
|
|
14
|
+
} from './markdown-process';
|
|
15
15
|
|
|
16
16
|
/** List of remark plugins to apply. */
|
|
17
|
-
export function starlightRemarkPlugins(options:
|
|
17
|
+
export function starlightRemarkPlugins(options: MarkdownProcessorPluginOptions): RemarkPlugin[] {
|
|
18
18
|
return [remarkDirective, remarkPlugins(options)];
|
|
19
19
|
}
|
|
20
20
|
|
|
21
21
|
/** List of rehype plugins to apply. */
|
|
22
|
-
export function starlightRehypePlugins(options:
|
|
22
|
+
export function starlightRehypePlugins(options: MarkdownProcessorPluginOptions): RehypePlugin[] {
|
|
23
23
|
return [
|
|
24
24
|
...(options.starlightConfig.markdown.headingLinks ? [[rehypeHeadingIds]] : []),
|
|
25
25
|
rehypePlugins(options),
|
|
@@ -27,8 +27,8 @@ export function starlightRehypePlugins(options: RemarkRehypePluginOptions): Rehy
|
|
|
27
27
|
}
|
|
28
28
|
|
|
29
29
|
/** Remark plugin applying other Starlight remark plugins if necessary. */
|
|
30
|
-
function remarkPlugins(options:
|
|
31
|
-
const
|
|
30
|
+
function remarkPlugins(options: MarkdownProcessorPluginOptions): RemarkPlugin {
|
|
31
|
+
const allowedPaths = getMarkdownProcessorPaths(options);
|
|
32
32
|
|
|
33
33
|
return function attacher(this) {
|
|
34
34
|
const remarkAsidesTransformer = remarkAsides(options).call(this)!;
|
|
@@ -36,7 +36,7 @@ function remarkPlugins(options: RemarkRehypePluginOptions): RemarkPlugin {
|
|
|
36
36
|
return async function transformer(...args) {
|
|
37
37
|
const [, file] = args;
|
|
38
38
|
|
|
39
|
-
if (!shouldTransformFile(file,
|
|
39
|
+
if (!shouldTransformFile(file, allowedPaths)) return;
|
|
40
40
|
|
|
41
41
|
await remarkAsidesTransformer(...args);
|
|
42
42
|
};
|
|
@@ -44,8 +44,8 @@ function remarkPlugins(options: RemarkRehypePluginOptions): RemarkPlugin {
|
|
|
44
44
|
}
|
|
45
45
|
|
|
46
46
|
/** Rehype plugin applying other Starlight rehype plugins if necessary. */
|
|
47
|
-
function rehypePlugins(options:
|
|
48
|
-
const
|
|
47
|
+
function rehypePlugins(options: MarkdownProcessorPluginOptions): RehypePlugin {
|
|
48
|
+
const allowedPaths = getMarkdownProcessorPaths(options);
|
|
49
49
|
|
|
50
50
|
return function attacher(this) {
|
|
51
51
|
const rehypeRtlCodeSupportTransformer = rehypeRtlCodeSupport(options).call(this);
|
|
@@ -54,7 +54,7 @@ function rehypePlugins(options: RemarkRehypePluginOptions): RehypePlugin {
|
|
|
54
54
|
return async function transformer(...args) {
|
|
55
55
|
const [, file] = args;
|
|
56
56
|
|
|
57
|
-
if (!shouldTransformFile(file,
|
|
57
|
+
if (!shouldTransformFile(file, allowedPaths)) return;
|
|
58
58
|
|
|
59
59
|
await rehypeRtlCodeSupportTransformer(...args);
|
|
60
60
|
|
|
@@ -65,52 +65,17 @@ function rehypePlugins(options: RemarkRehypePluginOptions): RehypePlugin {
|
|
|
65
65
|
};
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
/**
|
|
69
|
-
* Returns the paths to the Starlight docs collection and any additional paths defined in the
|
|
70
|
-
* `starlightConfig.markdown.processedDirs` option that can be used with the
|
|
71
|
-
* `shouldTransformFile()` utility to determine if a file should be transformed by a plugin or not.
|
|
72
|
-
*/
|
|
73
|
-
function getRemarkRehypePaths(options: RemarkRehypePluginOptions): string[] {
|
|
74
|
-
const paths = [normalizePath(resolveCollectionPath('docs', options.astroConfig.srcDir))];
|
|
75
|
-
|
|
76
|
-
for (const processedDir of options.starlightConfig.markdown.processedDirs) {
|
|
77
|
-
paths.push(normalizePath(resolve(fileURLToPath(options.astroConfig.root), processedDir)));
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
return paths;
|
|
81
|
-
}
|
|
82
|
-
|
|
83
68
|
/**
|
|
84
69
|
* Determines if a file should be transformed by a remark/rehype plugin, e.g. files without a known
|
|
85
|
-
* path or files that are not part of the allowed
|
|
70
|
+
* path or files that are not part of the allowed paths are skipped.
|
|
86
71
|
*/
|
|
87
|
-
function shouldTransformFile(file: VFile,
|
|
72
|
+
function shouldTransformFile(file: VFile, allowedPaths: string[]) {
|
|
88
73
|
// If the content is rendered using the content loader `renderMarkdown()` API, a file path
|
|
89
74
|
// is not provided.
|
|
90
75
|
// In that case, we skip the file.
|
|
91
76
|
if (!file?.path) return false;
|
|
92
77
|
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
// If the document is not part of the allowed remark/rehype paths, skip it.
|
|
96
|
-
return remarkRehypePaths.some((path) => normalizedPath.startsWith(path));
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
/**
|
|
100
|
-
* File path separators seems to be inconsistent on Windows between remark/rehype plugins used on
|
|
101
|
-
* Markdown vs MDX files.
|
|
102
|
-
* For the time being, we normalize all paths to unix style paths.
|
|
103
|
-
*/
|
|
104
|
-
const backSlashRegex = /\\/g;
|
|
105
|
-
function normalizePath(path: string) {
|
|
106
|
-
return path.replace(backSlashRegex, '/');
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
export interface RemarkRehypePluginOptions {
|
|
110
|
-
starlightConfig: Pick<StarlightConfig, 'defaultLocale' | 'locales' | 'markdown'>;
|
|
111
|
-
astroConfig: Pick<AstroConfig, 'root' | 'srcDir'>;
|
|
112
|
-
useTranslations: HookParameters<'config:setup'>['useTranslations'];
|
|
113
|
-
absolutePathToLang: HookParameters<'config:setup'>['absolutePathToLang'];
|
|
78
|
+
return shouldTransformPath(file.path, allowedPaths);
|
|
114
79
|
}
|
|
115
80
|
|
|
116
81
|
type RemarkPlugin = Plugin<[], RemarkRoot>;
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
import { fileURLToPath } from 'node:url';
|
|
2
|
+
import { isSatteriProcessor, satteriHeadingIdsPlugin } from '@astrojs/markdown-satteri';
|
|
3
|
+
import type { Element, Properties } from 'hast';
|
|
4
|
+
import type { Paragraph } from 'mdast';
|
|
5
|
+
import { directiveToMarkdown } from 'mdast-util-directive';
|
|
6
|
+
import { toMarkdown } from 'mdast-util-to-markdown';
|
|
7
|
+
import type {
|
|
8
|
+
HastPluginDefinition,
|
|
9
|
+
HastPluginInput,
|
|
10
|
+
MdastPluginInput,
|
|
11
|
+
MdastPluginDefinition,
|
|
12
|
+
} from 'satteri';
|
|
13
|
+
import { anchorLinkIconPath } from './anchor-icon';
|
|
14
|
+
import { asideIconPathAttrs, isAsideVariant } from './aside-icons';
|
|
15
|
+
import {
|
|
16
|
+
getMarkdownProcessorPaths,
|
|
17
|
+
shouldTransformPath,
|
|
18
|
+
type MarkdownProcessorPluginOptions,
|
|
19
|
+
} from './markdown-process';
|
|
20
|
+
import { Icons } from '../components-internals/Icons';
|
|
21
|
+
import { throwInvalidAsideIconError } from './asides-error';
|
|
22
|
+
import type { StarlightIcon } from '../types';
|
|
23
|
+
|
|
24
|
+
// Re-exported so callers can narrow `markdown.processor` to a Sätteri processor through the same
|
|
25
|
+
// lazy import that loads the optional `@astrojs/markdown-satteri` peer dependency.
|
|
26
|
+
export { isSatteriProcessor };
|
|
27
|
+
|
|
28
|
+
export function starlightSatteriPlugins(options: MarkdownProcessorPluginOptions): {
|
|
29
|
+
mdastPlugins: MdastPluginInput[];
|
|
30
|
+
hastPlugins: HastPluginInput[];
|
|
31
|
+
} {
|
|
32
|
+
const allowedPaths = getMarkdownProcessorPaths(options);
|
|
33
|
+
return {
|
|
34
|
+
mdastPlugins: [satteriAsidesPlugin(options, allowedPaths)],
|
|
35
|
+
hastPlugins: [
|
|
36
|
+
satteriRtlCodeSupportPlugin(allowedPaths),
|
|
37
|
+
...(options.starlightConfig.markdown.headingLinks
|
|
38
|
+
? [() => satteriHeadingIdsPlugin(), satteriAutolinkHeadingsPlugin(options, allowedPaths)]
|
|
39
|
+
: []),
|
|
40
|
+
],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Recover directives Starlight didn't claim so user content isn't dropped
|
|
46
|
+
*/
|
|
47
|
+
export function satteriDirectivesRestoration(): MdastPluginDefinition {
|
|
48
|
+
return {
|
|
49
|
+
name: 'starlight-directives-restoration',
|
|
50
|
+
textDirective(node) {
|
|
51
|
+
// Leave directives another plugin already handled (i.e. set `data` on) untouched.
|
|
52
|
+
if (node.data !== undefined) return;
|
|
53
|
+
return { type: 'text', value: serializeDirective(node) };
|
|
54
|
+
},
|
|
55
|
+
leafDirective(node) {
|
|
56
|
+
if (node.data !== undefined) return;
|
|
57
|
+
return {
|
|
58
|
+
type: 'paragraph',
|
|
59
|
+
children: [{ type: 'text', value: serializeDirective(node) }],
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
containerDirective(node) {
|
|
63
|
+
if (node.data !== undefined) return;
|
|
64
|
+
return paragraphElement('div', {}, [...node.children]);
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
function paragraphElement(
|
|
70
|
+
tagName: string,
|
|
71
|
+
properties: Properties,
|
|
72
|
+
children: unknown[] = []
|
|
73
|
+
): Paragraph {
|
|
74
|
+
return {
|
|
75
|
+
type: 'paragraph',
|
|
76
|
+
data: { hName: tagName, hProperties: properties },
|
|
77
|
+
children: children as Paragraph['children'],
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Convert `:::variant` directive blocks into styled asides. */
|
|
82
|
+
function satteriAsidesPlugin(
|
|
83
|
+
options: MarkdownProcessorPluginOptions,
|
|
84
|
+
allowedPaths: string[]
|
|
85
|
+
): MdastPluginDefinition {
|
|
86
|
+
return {
|
|
87
|
+
name: 'starlight-asides',
|
|
88
|
+
containerDirective(node, ctx) {
|
|
89
|
+
if (!shouldTransformPath(ctx.fileURL, allowedPaths)) return;
|
|
90
|
+
if (!isAsideVariant(node.name)) return;
|
|
91
|
+
|
|
92
|
+
const variant = node.name;
|
|
93
|
+
// `shouldTransformPath` above already returned for a missing `fileURL`.
|
|
94
|
+
const filename = fileURLToPath(ctx.fileURL!);
|
|
95
|
+
const t = options.useTranslations(options.absolutePathToLang(filename));
|
|
96
|
+
|
|
97
|
+
let title = t(`aside.${variant}`);
|
|
98
|
+
let titleNode: unknown[] = [{ type: 'text', value: title }];
|
|
99
|
+
const children = [...node.children];
|
|
100
|
+
const firstChild = children[0];
|
|
101
|
+
if (
|
|
102
|
+
firstChild?.type === 'paragraph' &&
|
|
103
|
+
firstChild.data?.directiveLabel &&
|
|
104
|
+
firstChild.children.length > 0
|
|
105
|
+
) {
|
|
106
|
+
titleNode = firstChild.children;
|
|
107
|
+
title = ctx.textContent(firstChild);
|
|
108
|
+
children.shift();
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
const customIconName = node.attributes?.['icon'];
|
|
112
|
+
let innerSvgHtml: string;
|
|
113
|
+
if (customIconName) {
|
|
114
|
+
const icon = Icons[customIconName as StarlightIcon];
|
|
115
|
+
if (!icon) throwInvalidAsideIconError(customIconName);
|
|
116
|
+
innerSvgHtml = icon;
|
|
117
|
+
} else {
|
|
118
|
+
innerSvgHtml = asideIconPathAttrs[variant]
|
|
119
|
+
.map((attrs) => `<path${attrsToHtml(attrs)}/>`)
|
|
120
|
+
.join('');
|
|
121
|
+
}
|
|
122
|
+
const iconSvg = `<svg viewBox="0 0 24 24" width="16" height="16" fill="currentColor" class="starlight-aside__icon">${innerSvgHtml}</svg>`;
|
|
123
|
+
|
|
124
|
+
return paragraphElement(
|
|
125
|
+
'aside',
|
|
126
|
+
{
|
|
127
|
+
'aria-label': title,
|
|
128
|
+
class: `starlight-aside starlight-aside--${variant}`,
|
|
129
|
+
},
|
|
130
|
+
[
|
|
131
|
+
paragraphElement('p', { class: 'starlight-aside__title', 'aria-hidden': 'true' }, [
|
|
132
|
+
{ type: 'html', value: iconSvg },
|
|
133
|
+
...titleNode,
|
|
134
|
+
]),
|
|
135
|
+
paragraphElement('div', { class: 'starlight-aside__content' }, children),
|
|
136
|
+
]
|
|
137
|
+
);
|
|
138
|
+
},
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
function attrsToHtml(attrs: Record<string, string>): string {
|
|
143
|
+
let out = '';
|
|
144
|
+
for (const [key, value] of Object.entries(attrs)) {
|
|
145
|
+
out += ` ${key}="${value.replace(/&/g, '&').replace(/"/g, '"')}"`;
|
|
146
|
+
}
|
|
147
|
+
return out;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
function serializeDirective(node: Parameters<typeof toMarkdown>[0]): string {
|
|
151
|
+
const md = toMarkdown(node, { extensions: [directiveToMarkdown()] });
|
|
152
|
+
return md.at(-1) === '\n' ? md.slice(0, -1) : md;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function satteriRtlCodeSupportPlugin(allowedPaths: string[]): () => HastPluginDefinition {
|
|
156
|
+
return () => {
|
|
157
|
+
// HACK: Sätteri currently does not expose a way to either know the parent of a node, or
|
|
158
|
+
// skipping a subtree visit. To work around this, we manually track the source spans of `<pre>`
|
|
159
|
+
// elements and skip applying `dir="auto"` to `<code>` elements inside those spans. This is:
|
|
160
|
+
// bad, because it means that it won't work for nodes without positions (e.g. generated nodes),
|
|
161
|
+
// but it's as good as it gets right now.
|
|
162
|
+
const preSpans: Array<[number, number]> = [];
|
|
163
|
+
return {
|
|
164
|
+
name: 'starlight-rtl-code-support',
|
|
165
|
+
element: [
|
|
166
|
+
{
|
|
167
|
+
filter: ['pre'],
|
|
168
|
+
visit(node, ctx) {
|
|
169
|
+
if (!shouldTransformPath(ctx.fileURL, allowedPaths)) return;
|
|
170
|
+
const span = nodeSpan(node);
|
|
171
|
+
if (span) preSpans.push(span);
|
|
172
|
+
if (node.properties && 'dir' in node.properties) return;
|
|
173
|
+
ctx.setProperty(node, 'dir', 'ltr');
|
|
174
|
+
},
|
|
175
|
+
},
|
|
176
|
+
{
|
|
177
|
+
filter: ['code'],
|
|
178
|
+
visit(node, ctx) {
|
|
179
|
+
if (!shouldTransformPath(ctx.fileURL, allowedPaths)) return;
|
|
180
|
+
if (isInsideSpan(nodeSpan(node), preSpans)) return;
|
|
181
|
+
if (node.properties && 'dir' in node.properties) return;
|
|
182
|
+
ctx.setProperty(node, 'dir', 'auto');
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
// Shiki runs ahead of us and replaces the highlighted `<pre>` element with a raw HTML
|
|
187
|
+
// node, so the `pre` element visitor above never sees it. Patch the raw markup instead.
|
|
188
|
+
raw(node, ctx) {
|
|
189
|
+
if (!shouldTransformPath(ctx.fileURL, allowedPaths)) return undefined;
|
|
190
|
+
const value = ltrRawPre(node.value);
|
|
191
|
+
if (value === null) return undefined;
|
|
192
|
+
return { type: 'raw', value };
|
|
193
|
+
},
|
|
194
|
+
};
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/** The source byte span of a node, or `null` when it carries no position (e.g. a generated node). */
|
|
199
|
+
function nodeSpan(node: { position?: Element['position'] }): [number, number] | null {
|
|
200
|
+
const start = node.position?.start.offset;
|
|
201
|
+
const end = node.position?.end.offset;
|
|
202
|
+
return typeof start === 'number' && typeof end === 'number' ? [start, end] : null;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
function isInsideSpan(span: [number, number] | null, spans: Array<[number, number]>): boolean {
|
|
206
|
+
if (!span) return false;
|
|
207
|
+
return spans.some(([start, end]) => span[0] >= start && span[1] <= end);
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
const rawPreOpenTag = /<pre(?=[\s>])[^>]*>/;
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Add `dir="ltr"` to the opening tag of a raw `<pre>` HTML string, unless it already declares a
|
|
214
|
+
* `dir`. Returns `null` when the value isn’t a `<pre>`, leaving unrelated raw HTML untouched.
|
|
215
|
+
*/
|
|
216
|
+
function ltrRawPre(value: string): string | null {
|
|
217
|
+
const openTag = value.match(rawPreOpenTag)?.[0];
|
|
218
|
+
if (!openTag || /\sdir\s*=/.test(openTag)) return null;
|
|
219
|
+
return value.replace(openTag, () => `<pre dir="ltr"${openTag.slice(4)}`);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function satteriAutolinkHeadingsPlugin(
|
|
223
|
+
options: MarkdownProcessorPluginOptions,
|
|
224
|
+
allowedPaths: string[]
|
|
225
|
+
): HastPluginDefinition {
|
|
226
|
+
return {
|
|
227
|
+
name: 'starlight-autolink-headings',
|
|
228
|
+
element: {
|
|
229
|
+
filter: ['h1', 'h2', 'h3', 'h4', 'h5', 'h6'],
|
|
230
|
+
visit(node, ctx) {
|
|
231
|
+
if (!shouldTransformPath(ctx.fileURL, allowedPaths)) return;
|
|
232
|
+
|
|
233
|
+
const id = node.properties?.['id'];
|
|
234
|
+
if (typeof id !== 'string' || !id) return;
|
|
235
|
+
|
|
236
|
+
const title = ctx.textContent(node);
|
|
237
|
+
// `shouldTransformPath` above already returned for a missing `fileURL`.
|
|
238
|
+
const filename = fileURLToPath(ctx.fileURL!);
|
|
239
|
+
const t = options.useTranslations(options.absolutePathToLang(filename));
|
|
240
|
+
const accessibleLabel = t('heading.anchorLabel', {
|
|
241
|
+
title,
|
|
242
|
+
interpolation: { escapeValue: false },
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
return {
|
|
246
|
+
type: 'element',
|
|
247
|
+
tagName: 'div',
|
|
248
|
+
properties: { class: `sl-heading-wrapper level-${node.tagName}` },
|
|
249
|
+
children: [
|
|
250
|
+
node,
|
|
251
|
+
{
|
|
252
|
+
type: 'element',
|
|
253
|
+
tagName: 'a',
|
|
254
|
+
properties: { class: 'sl-anchor-link', href: '#' + id },
|
|
255
|
+
children: [
|
|
256
|
+
{
|
|
257
|
+
type: 'element',
|
|
258
|
+
tagName: 'span',
|
|
259
|
+
properties: { 'aria-hidden': 'true', class: 'sl-anchor-icon' },
|
|
260
|
+
children: [
|
|
261
|
+
{
|
|
262
|
+
type: 'element',
|
|
263
|
+
tagName: 'svg',
|
|
264
|
+
properties: { width: '16', height: '16', viewBox: '0 0 24 24' },
|
|
265
|
+
children: [
|
|
266
|
+
{
|
|
267
|
+
type: 'element',
|
|
268
|
+
tagName: 'path',
|
|
269
|
+
properties: {
|
|
270
|
+
fill: 'currentcolor',
|
|
271
|
+
d: anchorLinkIconPath,
|
|
272
|
+
},
|
|
273
|
+
children: [],
|
|
274
|
+
},
|
|
275
|
+
],
|
|
276
|
+
},
|
|
277
|
+
],
|
|
278
|
+
},
|
|
279
|
+
{
|
|
280
|
+
type: 'element',
|
|
281
|
+
tagName: 'span',
|
|
282
|
+
properties: { class: 'sr-only', 'data-pagefind-ignore': true },
|
|
283
|
+
children: [{ type: 'text', value: accessibleLabel }],
|
|
284
|
+
},
|
|
285
|
+
],
|
|
286
|
+
},
|
|
287
|
+
],
|
|
288
|
+
};
|
|
289
|
+
},
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@astrojs/starlight",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.40.0",
|
|
4
4
|
"description": "Build beautiful, high-performance documentation websites with Astro",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"docs",
|
|
@@ -42,25 +42,33 @@
|
|
|
42
42
|
"./style/markdown.css": "./style/markdown.css"
|
|
43
43
|
},
|
|
44
44
|
"peerDependencies": {
|
|
45
|
-
"
|
|
45
|
+
"@astrojs/markdown-satteri": "^0.2.0",
|
|
46
|
+
"astro": "^6.4.5"
|
|
47
|
+
},
|
|
48
|
+
"peerDependenciesMeta": {
|
|
49
|
+
"@astrojs/markdown-satteri": {
|
|
50
|
+
"optional": true
|
|
51
|
+
}
|
|
46
52
|
},
|
|
47
53
|
"devDependencies": {
|
|
54
|
+
"@astrojs/markdown-satteri": "^0.2.2",
|
|
48
55
|
"@playwright/test": "^1.59.1",
|
|
49
56
|
"@types/node": "^22.19.17",
|
|
50
57
|
"@vitest/coverage-v8": "^4.1.5",
|
|
51
|
-
"astro": "^6.
|
|
58
|
+
"astro": "^6.4.5",
|
|
52
59
|
"linkedom": "^0.18.12",
|
|
60
|
+
"satteri": "^0.8.1",
|
|
53
61
|
"vitest": "^4.1.5"
|
|
54
62
|
},
|
|
55
63
|
"dependencies": {
|
|
56
|
-
"@astrojs/markdown-remark": "^7.
|
|
57
|
-
"@astrojs/mdx": "^
|
|
64
|
+
"@astrojs/markdown-remark": "^7.2.0",
|
|
65
|
+
"@astrojs/mdx": "^6.0.2",
|
|
58
66
|
"@astrojs/sitemap": "^3.7.2",
|
|
59
67
|
"@pagefind/default-ui": "^1.3.0",
|
|
60
68
|
"@types/hast": "^3.0.4",
|
|
61
69
|
"@types/js-yaml": "^4.0.9",
|
|
62
70
|
"@types/mdast": "^4.0.4",
|
|
63
|
-
"astro-expressive-code": "^0.
|
|
71
|
+
"astro-expressive-code": "^0.43.1",
|
|
64
72
|
"bcp-47": "^2.1.0",
|
|
65
73
|
"hast-util-from-html": "^2.0.3",
|
|
66
74
|
"hast-util-select": "^6.0.4",
|