@astrojs/starlight 0.35.1 → 0.35.2
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 +8 -0
- package/index.ts +3 -1
- package/integrations/asides-error.ts +9 -0
- package/integrations/asides.ts +1 -9
- package/integrations/expressive-code/index.ts +12 -120
- package/integrations/expressive-code/preprocessor.ts +121 -0
- package/integrations/remark-rehype-utils.ts +1 -1
- package/integrations/shared/absolutePathToLang.ts +4 -8
- package/integrations/virtual-user-config.ts +1 -1
- package/internal.ts +1 -1
- package/package.json +1 -1
- package/user-components/Aside.astro +1 -1
- package/utils/collection-fs.ts +21 -0
- package/utils/collection.ts +2 -9
- package/utils/plugins.ts +5 -1
- package/utils/slugs.ts +9 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,13 @@
|
|
|
1
1
|
# @astrojs/starlight
|
|
2
2
|
|
|
3
|
+
## 0.35.2
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- [#3341](https://github.com/withastro/starlight/pull/3341) [`10f6fe2`](https://github.com/withastro/starlight/commit/10f6fe22a981247293ee4de106736f1a6ae24b6a) Thanks [@HiDeoo](https://github.com/HiDeoo)! - Prevents potential build issues with the Astro Cloudflare adapter due to the dependency on Node.js builtins.
|
|
8
|
+
|
|
9
|
+
- [#3327](https://github.com/withastro/starlight/pull/3327) [`bf58c60`](https://github.com/withastro/starlight/commit/bf58c60b9c3d5f5efdafbdba83cefa0566a367dc) Thanks [@delucis](https://github.com/delucis)! - Fixes a routing bug for docs pages with a slug authored with non-normalized composition. This could occur for filenames containing diacritics in some circumstances, causing 404s.
|
|
10
|
+
|
|
3
11
|
## 0.35.1
|
|
4
12
|
|
|
5
13
|
### Patch Changes
|
package/index.ts
CHANGED
|
@@ -92,7 +92,9 @@ export default function StarlightIntegration(
|
|
|
92
92
|
// config or by a plugin.
|
|
93
93
|
const allIntegrations = [...config.integrations, ...integrations];
|
|
94
94
|
if (!allIntegrations.find(({ name }) => name === 'astro-expressive-code')) {
|
|
95
|
-
integrations.push(
|
|
95
|
+
integrations.push(
|
|
96
|
+
...starlightExpressiveCode({ astroConfig: config, starlightConfig, useTranslations })
|
|
97
|
+
);
|
|
96
98
|
}
|
|
97
99
|
if (!allIntegrations.find(({ name }) => name === '@astrojs/sitemap')) {
|
|
98
100
|
integrations.push(starlightSitemap(starlightConfig));
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AstroError } from 'astro/errors';
|
|
2
|
+
|
|
3
|
+
export function throwInvalidAsideIconError(icon: string) {
|
|
4
|
+
throw new AstroError(
|
|
5
|
+
'Invalid aside icon',
|
|
6
|
+
`An aside custom icon must be set to the name of one of Starlight\’s built-in icons, but received \`${icon}\`.\n\n` +
|
|
7
|
+
'See https://starlight.astro.build/reference/icons/#all-icons for a list of available icons.'
|
|
8
|
+
);
|
|
9
|
+
}
|
package/integrations/asides.ts
CHANGED
|
@@ -19,7 +19,7 @@ import { getRemarkRehypeDocsCollectionPath, shouldTransformFile } from './remark
|
|
|
19
19
|
import { Icons } from '../components/Icons';
|
|
20
20
|
import { fromHtml } from 'hast-util-from-html';
|
|
21
21
|
import type { Element } from 'hast';
|
|
22
|
-
import {
|
|
22
|
+
import { throwInvalidAsideIconError } from './asides-error';
|
|
23
23
|
|
|
24
24
|
interface AsidesOptions {
|
|
25
25
|
starlightConfig: Pick<StarlightConfig, 'defaultLocale' | 'locales'>;
|
|
@@ -253,14 +253,6 @@ function remarkAsides(options: AsidesOptions): Plugin<[], Root> {
|
|
|
253
253
|
|
|
254
254
|
type RemarkPlugins = NonNullable<NonNullable<AstroUserConfig['markdown']>['remarkPlugins']>;
|
|
255
255
|
|
|
256
|
-
export function throwInvalidAsideIconError(icon: string) {
|
|
257
|
-
throw new AstroError(
|
|
258
|
-
'Invalid aside icon',
|
|
259
|
-
`An aside custom icon must be set to the name of one of Starlight\’s built-in icons, but received \`${icon}\`.\n\n` +
|
|
260
|
-
'See https://starlight.astro.build/reference/icons/#all-icons for a list of available icons.'
|
|
261
|
-
);
|
|
262
|
-
}
|
|
263
|
-
|
|
264
256
|
export function starlightAsides(options: AsidesOptions): RemarkPlugins {
|
|
265
257
|
return [remarkDirective, remarkAsides(options)];
|
|
266
258
|
}
|
|
@@ -1,20 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
type AstroExpressiveCodeOptions,
|
|
4
|
-
type CustomConfigPreprocessors,
|
|
5
|
-
} from 'astro-expressive-code';
|
|
6
|
-
import { addClassName } from 'astro-expressive-code/hast';
|
|
7
|
-
import type { AstroIntegration } from 'astro';
|
|
1
|
+
import { astroExpressiveCode, type AstroExpressiveCodeOptions } from 'astro-expressive-code';
|
|
2
|
+
import type { AstroConfig, AstroIntegration } from 'astro';
|
|
8
3
|
import type { HookParameters, StarlightConfig } from '../../types';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
applyStarlightUiThemeColors,
|
|
14
|
-
preprocessThemes,
|
|
15
|
-
type ThemeObjectOrBundledThemeName,
|
|
16
|
-
} from './theming';
|
|
17
|
-
import { addTranslations } from './translations';
|
|
4
|
+
import { getStarlightEcConfigPreprocessor } from './preprocessor';
|
|
5
|
+
import { type ThemeObjectOrBundledThemeName } from './theming';
|
|
6
|
+
import { getCollectionPosixPath } from '../../utils/collection-fs';
|
|
18
7
|
|
|
19
8
|
export type StarlightExpressiveCodeOptions = Omit<AstroExpressiveCodeOptions, 'themes'> & {
|
|
20
9
|
/**
|
|
@@ -63,114 +52,13 @@ export type StarlightExpressiveCodeOptions = Omit<AstroExpressiveCodeOptions, 't
|
|
|
63
52
|
};
|
|
64
53
|
|
|
65
54
|
type StarlightEcIntegrationOptions = {
|
|
55
|
+
astroConfig: AstroConfig;
|
|
66
56
|
starlightConfig: StarlightConfig;
|
|
67
57
|
useTranslations: HookParameters<'config:setup'>['useTranslations'];
|
|
68
58
|
};
|
|
69
59
|
|
|
70
|
-
/**
|
|
71
|
-
* Create an Expressive Code configuration preprocessor based on Starlight config.
|
|
72
|
-
* Used internally to set up Expressive Code and by the `<Code>` component.
|
|
73
|
-
*/
|
|
74
|
-
export function getStarlightEcConfigPreprocessor({
|
|
75
|
-
starlightConfig,
|
|
76
|
-
useTranslations,
|
|
77
|
-
}: StarlightEcIntegrationOptions): CustomConfigPreprocessors['preprocessAstroIntegrationConfig'] {
|
|
78
|
-
return (input): AstroExpressiveCodeOptions => {
|
|
79
|
-
const astroConfig = input.astroConfig;
|
|
80
|
-
const ecConfig = input.ecConfig as StarlightExpressiveCodeOptions;
|
|
81
|
-
|
|
82
|
-
const {
|
|
83
|
-
themes: themesInput,
|
|
84
|
-
cascadeLayer,
|
|
85
|
-
customizeTheme,
|
|
86
|
-
styleOverrides: { textMarkers: textMarkersStyleOverrides, ...otherStyleOverrides } = {},
|
|
87
|
-
useStarlightDarkModeSwitch,
|
|
88
|
-
useStarlightUiThemeColors = ecConfig.themes === undefined,
|
|
89
|
-
plugins = [],
|
|
90
|
-
...rest
|
|
91
|
-
} = ecConfig;
|
|
92
|
-
|
|
93
|
-
// Handle the `themes` option
|
|
94
|
-
const themes = preprocessThemes(themesInput);
|
|
95
|
-
if (useStarlightUiThemeColors === true && themes.length < 2) {
|
|
96
|
-
console.warn(
|
|
97
|
-
`*** Warning: Using the config option "useStarlightUiThemeColors: true" ` +
|
|
98
|
-
`with a single theme is not recommended. For better color contrast, ` +
|
|
99
|
-
`please provide at least one dark and one light theme.\n`
|
|
100
|
-
);
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
// Add the `not-content` class to all rendered blocks to prevent them from being affected
|
|
104
|
-
// by Starlight's default content styles
|
|
105
|
-
plugins.push({
|
|
106
|
-
name: 'Starlight Plugin',
|
|
107
|
-
hooks: {
|
|
108
|
-
postprocessRenderedBlock: ({ renderData }) => {
|
|
109
|
-
addClassName(renderData.blockAst, 'not-content');
|
|
110
|
-
},
|
|
111
|
-
},
|
|
112
|
-
});
|
|
113
|
-
|
|
114
|
-
// Add Expressive Code UI translations for all defined locales
|
|
115
|
-
addTranslations(starlightConfig, useTranslations);
|
|
116
|
-
|
|
117
|
-
return {
|
|
118
|
-
themes,
|
|
119
|
-
customizeTheme: (theme) => {
|
|
120
|
-
if (useStarlightUiThemeColors) {
|
|
121
|
-
applyStarlightUiThemeColors(theme);
|
|
122
|
-
}
|
|
123
|
-
if (customizeTheme) {
|
|
124
|
-
theme = customizeTheme(theme) ?? theme;
|
|
125
|
-
}
|
|
126
|
-
return theme;
|
|
127
|
-
},
|
|
128
|
-
defaultLocale: starlightConfig.defaultLocale?.lang ?? starlightConfig.defaultLocale?.locale,
|
|
129
|
-
themeCssSelector: (theme, { styleVariants }) => {
|
|
130
|
-
// If one dark and one light theme are available, and the user has not disabled it,
|
|
131
|
-
// generate theme CSS selectors compatible with Starlight's dark mode switch
|
|
132
|
-
if (useStarlightDarkModeSwitch !== false && styleVariants.length >= 2) {
|
|
133
|
-
const baseTheme = styleVariants[0]?.theme;
|
|
134
|
-
const altTheme = styleVariants.find((v) => v.theme.type !== baseTheme?.type)?.theme;
|
|
135
|
-
if (theme === baseTheme || theme === altTheme) return `[data-theme='${theme.type}']`;
|
|
136
|
-
}
|
|
137
|
-
// Return the default selector
|
|
138
|
-
return `[data-theme='${theme.name}']`;
|
|
139
|
-
},
|
|
140
|
-
cascadeLayer: cascadeLayer ?? 'starlight.components',
|
|
141
|
-
styleOverrides: {
|
|
142
|
-
borderRadius: '0px',
|
|
143
|
-
borderWidth: '1px',
|
|
144
|
-
codePaddingBlock: '0.75rem',
|
|
145
|
-
codePaddingInline: '1rem',
|
|
146
|
-
codeFontFamily: 'var(--__sl-font-mono)',
|
|
147
|
-
codeFontSize: 'var(--sl-text-code)',
|
|
148
|
-
codeLineHeight: 'var(--sl-line-height)',
|
|
149
|
-
uiFontFamily: 'var(--__sl-font)',
|
|
150
|
-
textMarkers: {
|
|
151
|
-
lineDiffIndicatorMarginLeft: '0.25rem',
|
|
152
|
-
defaultChroma: '45',
|
|
153
|
-
backgroundOpacity: '60%',
|
|
154
|
-
...textMarkersStyleOverrides,
|
|
155
|
-
},
|
|
156
|
-
...otherStyleOverrides,
|
|
157
|
-
},
|
|
158
|
-
getBlockLocale: ({ file }) => {
|
|
159
|
-
if (file.url) {
|
|
160
|
-
const locale = slugToLocale(file.url.pathname.slice(1), starlightConfig);
|
|
161
|
-
return localeToLang(starlightConfig, locale);
|
|
162
|
-
}
|
|
163
|
-
// Note that EC cannot use the `absolutePathToLang` helper passed down to plugins as this callback
|
|
164
|
-
// is also called in the context of the `<Code>` component.
|
|
165
|
-
return absolutePathToLang(file.path, { starlightConfig, astroConfig });
|
|
166
|
-
},
|
|
167
|
-
plugins,
|
|
168
|
-
...rest,
|
|
169
|
-
};
|
|
170
|
-
};
|
|
171
|
-
}
|
|
172
|
-
|
|
173
60
|
export const starlightExpressiveCode = ({
|
|
61
|
+
astroConfig,
|
|
174
62
|
starlightConfig,
|
|
175
63
|
useTranslations,
|
|
176
64
|
}: StarlightEcIntegrationOptions): AstroIntegration[] => {
|
|
@@ -213,11 +101,15 @@ export const starlightExpressiveCode = ({
|
|
|
213
101
|
typeof starlightConfig.expressiveCode === 'object'
|
|
214
102
|
? (starlightConfig.expressiveCode as AstroExpressiveCodeOptions)
|
|
215
103
|
: {};
|
|
104
|
+
|
|
105
|
+
let docsPath = getCollectionPosixPath('docs', astroConfig.srcDir);
|
|
106
|
+
|
|
216
107
|
return [
|
|
217
108
|
astroExpressiveCode({
|
|
218
109
|
...configArgs,
|
|
219
110
|
customConfigPreprocessors: {
|
|
220
111
|
preprocessAstroIntegrationConfig: getStarlightEcConfigPreprocessor({
|
|
112
|
+
docsPath,
|
|
221
113
|
starlightConfig,
|
|
222
114
|
useTranslations,
|
|
223
115
|
}),
|
|
@@ -225,7 +117,7 @@ export const starlightExpressiveCode = ({
|
|
|
225
117
|
import starlightConfig from 'virtual:starlight/user-config'
|
|
226
118
|
import { useTranslations, getStarlightEcConfigPreprocessor } from '@astrojs/starlight/internal'
|
|
227
119
|
|
|
228
|
-
export default getStarlightEcConfigPreprocessor({ starlightConfig, useTranslations })
|
|
120
|
+
export default getStarlightEcConfigPreprocessor({ docsPath: ${JSON.stringify(docsPath)}, starlightConfig, useTranslations })
|
|
229
121
|
`,
|
|
230
122
|
},
|
|
231
123
|
}),
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type AstroExpressiveCodeOptions,
|
|
3
|
+
type CustomConfigPreprocessors,
|
|
4
|
+
} from 'astro-expressive-code';
|
|
5
|
+
import { addClassName } from 'astro-expressive-code/hast';
|
|
6
|
+
import type { StarlightExpressiveCodeOptions } from './index';
|
|
7
|
+
import type { HookParameters, StarlightConfig } from '../../types';
|
|
8
|
+
import { applyStarlightUiThemeColors, preprocessThemes } from './theming';
|
|
9
|
+
import { addTranslations } from './translations';
|
|
10
|
+
import { slugToLocale } from '../shared/slugToLocale';
|
|
11
|
+
import { localeToLang } from '../shared/localeToLang';
|
|
12
|
+
import { absolutePathToLang } from '../shared/absolutePathToLang';
|
|
13
|
+
|
|
14
|
+
type StarlightEcConfigPreprocessorOptions = {
|
|
15
|
+
docsPath: string;
|
|
16
|
+
starlightConfig: StarlightConfig;
|
|
17
|
+
useTranslations: HookParameters<'config:setup'>['useTranslations'];
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Create an Expressive Code configuration preprocessor based on Starlight config.
|
|
22
|
+
* Used internally to set up Expressive Code and by the `<Code>` component.
|
|
23
|
+
*/
|
|
24
|
+
export function getStarlightEcConfigPreprocessor({
|
|
25
|
+
docsPath,
|
|
26
|
+
starlightConfig,
|
|
27
|
+
useTranslations,
|
|
28
|
+
}: StarlightEcConfigPreprocessorOptions): CustomConfigPreprocessors['preprocessAstroIntegrationConfig'] {
|
|
29
|
+
return (input): AstroExpressiveCodeOptions => {
|
|
30
|
+
const ecConfig = input.ecConfig as StarlightExpressiveCodeOptions;
|
|
31
|
+
|
|
32
|
+
const {
|
|
33
|
+
themes: themesInput,
|
|
34
|
+
cascadeLayer,
|
|
35
|
+
customizeTheme,
|
|
36
|
+
styleOverrides: { textMarkers: textMarkersStyleOverrides, ...otherStyleOverrides } = {},
|
|
37
|
+
useStarlightDarkModeSwitch,
|
|
38
|
+
useStarlightUiThemeColors = ecConfig.themes === undefined,
|
|
39
|
+
plugins = [],
|
|
40
|
+
...rest
|
|
41
|
+
} = ecConfig;
|
|
42
|
+
|
|
43
|
+
// Handle the `themes` option
|
|
44
|
+
const themes = preprocessThemes(themesInput);
|
|
45
|
+
if (useStarlightUiThemeColors === true && themes.length < 2) {
|
|
46
|
+
console.warn(
|
|
47
|
+
`*** Warning: Using the config option "useStarlightUiThemeColors: true" ` +
|
|
48
|
+
`with a single theme is not recommended. For better color contrast, ` +
|
|
49
|
+
`please provide at least one dark and one light theme.\n`
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
// Add the `not-content` class to all rendered blocks to prevent them from being affected
|
|
54
|
+
// by Starlight's default content styles
|
|
55
|
+
plugins.push({
|
|
56
|
+
name: 'Starlight Plugin',
|
|
57
|
+
hooks: {
|
|
58
|
+
postprocessRenderedBlock: ({ renderData }) => {
|
|
59
|
+
addClassName(renderData.blockAst, 'not-content');
|
|
60
|
+
},
|
|
61
|
+
},
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Add Expressive Code UI translations for all defined locales
|
|
65
|
+
addTranslations(starlightConfig, useTranslations);
|
|
66
|
+
|
|
67
|
+
return {
|
|
68
|
+
themes,
|
|
69
|
+
customizeTheme: (theme) => {
|
|
70
|
+
if (useStarlightUiThemeColors) {
|
|
71
|
+
applyStarlightUiThemeColors(theme);
|
|
72
|
+
}
|
|
73
|
+
if (customizeTheme) {
|
|
74
|
+
theme = customizeTheme(theme) ?? theme;
|
|
75
|
+
}
|
|
76
|
+
return theme;
|
|
77
|
+
},
|
|
78
|
+
defaultLocale: starlightConfig.defaultLocale?.lang ?? starlightConfig.defaultLocale?.locale,
|
|
79
|
+
themeCssSelector: (theme, { styleVariants }) => {
|
|
80
|
+
// If one dark and one light theme are available, and the user has not disabled it,
|
|
81
|
+
// generate theme CSS selectors compatible with Starlight's dark mode switch
|
|
82
|
+
if (useStarlightDarkModeSwitch !== false && styleVariants.length >= 2) {
|
|
83
|
+
const baseTheme = styleVariants[0]?.theme;
|
|
84
|
+
const altTheme = styleVariants.find((v) => v.theme.type !== baseTheme?.type)?.theme;
|
|
85
|
+
if (theme === baseTheme || theme === altTheme) return `[data-theme='${theme.type}']`;
|
|
86
|
+
}
|
|
87
|
+
// Return the default selector
|
|
88
|
+
return `[data-theme='${theme.name}']`;
|
|
89
|
+
},
|
|
90
|
+
cascadeLayer: cascadeLayer ?? 'starlight.components',
|
|
91
|
+
styleOverrides: {
|
|
92
|
+
borderRadius: '0px',
|
|
93
|
+
borderWidth: '1px',
|
|
94
|
+
codePaddingBlock: '0.75rem',
|
|
95
|
+
codePaddingInline: '1rem',
|
|
96
|
+
codeFontFamily: 'var(--__sl-font-mono)',
|
|
97
|
+
codeFontSize: 'var(--sl-text-code)',
|
|
98
|
+
codeLineHeight: 'var(--sl-line-height)',
|
|
99
|
+
uiFontFamily: 'var(--__sl-font)',
|
|
100
|
+
textMarkers: {
|
|
101
|
+
lineDiffIndicatorMarginLeft: '0.25rem',
|
|
102
|
+
defaultChroma: '45',
|
|
103
|
+
backgroundOpacity: '60%',
|
|
104
|
+
...textMarkersStyleOverrides,
|
|
105
|
+
},
|
|
106
|
+
...otherStyleOverrides,
|
|
107
|
+
},
|
|
108
|
+
getBlockLocale: ({ file }) => {
|
|
109
|
+
if (file.url) {
|
|
110
|
+
const locale = slugToLocale(file.url.pathname.slice(1), starlightConfig);
|
|
111
|
+
return localeToLang(starlightConfig, locale);
|
|
112
|
+
}
|
|
113
|
+
// Note that EC cannot use the `absolutePathToLang` helper passed down to plugins as this callback
|
|
114
|
+
// is also called in the context of the `<Code>` component.
|
|
115
|
+
return absolutePathToLang(file.path, { docsPath, starlightConfig });
|
|
116
|
+
},
|
|
117
|
+
plugins,
|
|
118
|
+
...rest,
|
|
119
|
+
};
|
|
120
|
+
};
|
|
121
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { AstroConfig } from 'astro';
|
|
2
2
|
import type { VFile } from 'vfile';
|
|
3
|
-
import { resolveCollectionPath } from '../utils/collection';
|
|
3
|
+
import { resolveCollectionPath } from '../utils/collection-fs';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Returns the path to the Starlight docs collection ready to be used in remark/rehype plugins,
|
|
@@ -1,24 +1,20 @@
|
|
|
1
|
-
import { pathToFileURL } from 'node:url';
|
|
2
|
-
import type { AstroConfig } from 'astro';
|
|
3
1
|
import type { StarlightConfig } from '../../types';
|
|
4
2
|
import { localeToLang } from './localeToLang';
|
|
5
|
-
import { getCollectionPath } from '../../utils/collection';
|
|
6
3
|
import { slugToLocale } from './slugToLocale';
|
|
7
4
|
|
|
8
5
|
/** Get current language from an absolute file path. */
|
|
9
6
|
export function absolutePathToLang(
|
|
10
7
|
path: string,
|
|
11
8
|
{
|
|
9
|
+
docsPath,
|
|
12
10
|
starlightConfig,
|
|
13
|
-
astroConfig,
|
|
14
11
|
}: {
|
|
12
|
+
docsPath: string;
|
|
15
13
|
starlightConfig: Pick<StarlightConfig, 'defaultLocale' | 'locales'>;
|
|
16
|
-
astroConfig: { root: AstroConfig['root']; srcDir: AstroConfig['srcDir'] };
|
|
17
14
|
}
|
|
18
15
|
): string {
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
path = pathToFileURL(path).pathname;
|
|
16
|
+
// Format path to unix style path.
|
|
17
|
+
path = path?.replace(/\\/g, '/');
|
|
22
18
|
// Ensure that the page path starts with a slash if the docs directory also does,
|
|
23
19
|
// which makes stripping the docs path in the next step work on Windows, too.
|
|
24
20
|
if (path && !path.startsWith('/') && docsPath.startsWith('/')) path = '/' + path;
|
|
@@ -2,7 +2,7 @@ import type { AstroConfig, HookParameters, ViteUserConfig } from 'astro';
|
|
|
2
2
|
import { existsSync } from 'node:fs';
|
|
3
3
|
import { resolve } from 'node:path';
|
|
4
4
|
import { fileURLToPath } from 'node:url';
|
|
5
|
-
import { resolveCollectionPath } from '../utils/collection';
|
|
5
|
+
import { resolveCollectionPath } from '../utils/collection-fs';
|
|
6
6
|
import type { StarlightConfig } from '../utils/user-config';
|
|
7
7
|
import { getAllNewestCommitDate } from '../utils/git';
|
|
8
8
|
import type { PluginTranslations } from '../utils/plugins';
|
package/internal.ts
CHANGED
package/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { AstroError } from 'astro/errors';
|
|
3
3
|
import Icon from './Icon.astro';
|
|
4
4
|
import { Icons, type StarlightIcon } from '../components/Icons';
|
|
5
|
-
import { throwInvalidAsideIconError } from '../integrations/asides';
|
|
5
|
+
import { throwInvalidAsideIconError } from '../integrations/asides-error';
|
|
6
6
|
|
|
7
7
|
const asideVariants = ['note', 'tip', 'caution', 'danger'] as const;
|
|
8
8
|
const icons = { note: 'information', tip: 'rocket', caution: 'warning', danger: 'error' } as const;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { resolve } from 'node:path';
|
|
2
|
+
import { fileURLToPath } from 'node:url';
|
|
3
|
+
import { getCollectionUrl, type StarlightCollection } from './collection';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* @see {@link file://./collection.ts} for more context about this file.
|
|
7
|
+
*
|
|
8
|
+
* Below are various functions to easily get paths to collections used in Starlight that rely on
|
|
9
|
+
* Node.js builtins. They exist in a separate file from {@link file://./collection.ts} to avoid
|
|
10
|
+
* potentially importing Node.js builtins in the final bundle.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
export function resolveCollectionPath(collection: StarlightCollection, srcDir: URL) {
|
|
14
|
+
return resolve(fileURLToPath(srcDir), `content/${collection}`);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export function getCollectionPosixPath(collection: StarlightCollection, srcDir: URL) {
|
|
18
|
+
// TODO: when Astro minimum Node.js version is >= 20.13.0, refactor to use the `fileURLToPath`
|
|
19
|
+
// second optional argument to enforce POSIX paths by setting `windows: false`.
|
|
20
|
+
return fileURLToPath(getCollectionUrl(collection, srcDir)).replace(/\\/g, '/');
|
|
21
|
+
}
|
package/utils/collection.ts
CHANGED
|
@@ -1,6 +1,3 @@
|
|
|
1
|
-
import { resolve } from 'node:path';
|
|
2
|
-
import { fileURLToPath } from 'node:url';
|
|
3
|
-
|
|
4
1
|
const collectionNames = ['docs', 'i18n'] as const;
|
|
5
2
|
export type StarlightCollection = (typeof collectionNames)[number];
|
|
6
3
|
|
|
@@ -22,12 +19,8 @@ export type StarlightCollection = (typeof collectionNames)[number];
|
|
|
22
19
|
* these helper functions should be updated to reflect that in one place.
|
|
23
20
|
*/
|
|
24
21
|
|
|
25
|
-
export function
|
|
26
|
-
return new URL(`content/${collection}/`, srcDir)
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
export function resolveCollectionPath(collection: StarlightCollection, srcDir: URL) {
|
|
30
|
-
return resolve(fileURLToPath(srcDir), `content/${collection}`);
|
|
22
|
+
export function getCollectionUrl(collection: StarlightCollection, srcDir: URL) {
|
|
23
|
+
return new URL(`content/${collection}/`, srcDir);
|
|
31
24
|
}
|
|
32
25
|
|
|
33
26
|
export function getCollectionPathFromRoot(
|
package/utils/plugins.ts
CHANGED
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
import type { UserI18nSchema } from './translations';
|
|
11
11
|
import { createTranslationSystemFromFs } from './translations-fs';
|
|
12
12
|
import { absolutePathToLang as getAbsolutePathFromLang } from '../integrations/shared/absolutePathToLang';
|
|
13
|
+
import { getCollectionPosixPath } from './collection-fs';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Runs Starlight plugins in the order that they are configured after validating the user-provided
|
|
@@ -65,7 +66,10 @@ export async function runPlugins(
|
|
|
65
66
|
);
|
|
66
67
|
|
|
67
68
|
function absolutePathToLang(path: string) {
|
|
68
|
-
return getAbsolutePathFromLang(path, {
|
|
69
|
+
return getAbsolutePathFromLang(path, {
|
|
70
|
+
docsPath: getCollectionPosixPath('docs', context.config.srcDir),
|
|
71
|
+
starlightConfig,
|
|
72
|
+
});
|
|
69
73
|
}
|
|
70
74
|
|
|
71
75
|
// A list of Astro integrations added by the various plugins.
|
package/utils/slugs.ts
CHANGED
|
@@ -39,12 +39,18 @@ function localeToDir(locale: string | undefined): 'ltr' | 'rtl' {
|
|
|
39
39
|
return dir || config.defaultLocale.dir;
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/**
|
|
43
|
+
* Convert a content collection slug to a param as expected by Astro’s router.
|
|
44
|
+
* This utility handles stripping `index` from file names and matches
|
|
45
|
+
* [Astro’s param sanitization logic](https://github.com/withastro/astro/blob/687d25365a41ff8a9e6da155d3527f841abb70dd/packages/astro/src/core/routing/manifest/generator.ts#L4-L18)
|
|
46
|
+
* by normalizing strings to their canonical representations.
|
|
47
|
+
* @param slug Content collection slug
|
|
48
|
+
* @returns Param compatible with Astro’s router
|
|
49
|
+
*/
|
|
42
50
|
export function slugToParam(slug: string): string | undefined {
|
|
43
51
|
return slug === 'index' || slug === '' || slug === '/'
|
|
44
52
|
? undefined
|
|
45
|
-
: slug.endsWith('/index')
|
|
46
|
-
? slug.slice(0, -6)
|
|
47
|
-
: slug;
|
|
53
|
+
: (slug.endsWith('/index') ? slug.slice(0, -6) : slug).normalize();
|
|
48
54
|
}
|
|
49
55
|
|
|
50
56
|
export function slugToPathname(slug: string): string {
|