@astrojs/starlight 0.41.10 → 0.42.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/dist/_virtual/_rolldown/runtime.js +13 -0
- package/dist/components/MobileMenuToggle.astro +65 -0
- package/{components → dist/components}/PageFrame.astro +32 -8
- package/dist/components-internals/Icons.d.ts +415 -0
- package/dist/components-internals/Icons.js +140 -0
- package/dist/components-internals/SidebarPersistState.d.ts +1 -0
- package/dist/components-internals/SidebarPersistState.js +53 -0
- package/dist/components-internals/TableOfContents/starlight-toc.d.ts +18 -0
- package/dist/components-internals/TableOfContents/starlight-toc.js +88 -0
- package/dist/constants.d.ts +4 -0
- package/dist/constants.js +4 -0
- package/{expressive-code.d.ts → dist/expressive-code.d.ts} +6 -13
- package/dist/expressive-code.js +31 -0
- package/dist/global.d.ts +62 -0
- package/dist/global.js +2 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.js +109 -0
- package/dist/integrations/aside-utils.d.ts +9 -0
- package/dist/integrations/aside-utils.js +35 -0
- package/dist/integrations/expressive-code/hast.d.ts +1 -0
- package/dist/integrations/expressive-code/hast.js +2 -0
- package/dist/integrations/expressive-code/index.d.ts +60 -0
- package/dist/integrations/expressive-code/index.js +48 -0
- package/dist/integrations/expressive-code/preprocessor.d.ts +17 -0
- package/dist/integrations/expressive-code/preprocessor.js +76 -0
- package/dist/integrations/expressive-code/themes/night-owl-dark.js +4 -0
- package/dist/integrations/expressive-code/themes/night-owl-light.js +4 -0
- package/dist/integrations/expressive-code/theming.d.ts +16 -0
- package/dist/integrations/expressive-code/theming.js +71 -0
- package/dist/integrations/expressive-code/translations.d.ts +8 -0
- package/dist/integrations/expressive-code/translations.js +26 -0
- package/dist/integrations/markdown-icon.d.ts +8 -0
- package/dist/integrations/markdown-icon.js +14 -0
- package/dist/integrations/markdown-plugins.d.ts +18 -0
- package/dist/integrations/markdown-plugins.js +36 -0
- package/dist/integrations/markdown-processor.d.ts +29 -0
- package/dist/integrations/markdown-processor.js +44 -0
- package/dist/integrations/pagefind.d.ts +7 -0
- package/dist/integrations/pagefind.js +34 -0
- package/dist/integrations/rehype-code-rtl-support.d.ts +21 -0
- package/dist/integrations/rehype-code-rtl-support.js +36 -0
- package/dist/integrations/rehype-heading-links.d.ts +10 -0
- package/dist/integrations/rehype-heading-links.js +57 -0
- package/dist/integrations/remark-asides.d.ts +32 -0
- package/dist/integrations/remark-asides.js +166 -0
- package/dist/integrations/remark-rehype.d.ts +17 -0
- package/dist/integrations/remark-rehype.js +51 -0
- package/dist/integrations/satteri.d.ts +13 -0
- package/dist/integrations/satteri.js +209 -0
- package/dist/integrations/shared/absolutePathToLang.d.ts +10 -0
- package/dist/integrations/shared/absolutePathToLang.js +13 -0
- package/dist/integrations/shared/localeToLang.d.ts +10 -0
- package/dist/integrations/shared/localeToLang.js +13 -0
- package/dist/integrations/shared/slugToLocale.d.ts +12 -0
- package/dist/integrations/shared/slugToLocale.js +15 -0
- package/dist/integrations/sitemap.d.ts +12 -0
- package/dist/integrations/sitemap.js +19 -0
- package/dist/integrations/vite-layer-order.d.ts +15 -0
- package/dist/integrations/vite-layer-order.js +56 -0
- package/dist/integrations/vite-lazy-barrel-optimization.d.ts +12 -0
- package/dist/integrations/vite-lazy-barrel-optimization.js +33 -0
- package/dist/integrations/vite-virtual-modules.d.ts +14 -0
- package/dist/integrations/vite-virtual-modules.js +108 -0
- package/dist/internal.d.ts +3 -0
- package/dist/internal.js +3 -0
- package/dist/loaders.d.ts +20 -0
- package/dist/loaders.js +49 -0
- package/dist/locals.d.ts +15 -0
- package/dist/locals.js +33 -0
- package/dist/package.js +4 -0
- package/{props.ts → dist/props.d.ts} +6 -4
- package/dist/props.js +1 -0
- package/dist/route-data.d.ts +7 -0
- package/dist/route-data.js +6 -0
- package/dist/schema.d.ts +426 -0
- package/dist/schema.js +103 -0
- package/dist/schemas/badge.d.ts +86 -0
- package/dist/schemas/badge.js +39 -0
- package/dist/schemas/components.d.ts +236 -0
- package/dist/schemas/components.js +36 -0
- package/dist/schemas/expressiveCode.d.ts +7 -0
- package/dist/schemas/expressiveCode.js +5 -0
- package/dist/schemas/favicon.d.ts +9 -0
- package/dist/schemas/favicon.js +32 -0
- package/dist/schemas/head.d.ts +33 -0
- package/dist/schemas/head.js +41 -0
- package/dist/schemas/hero.d.ts +319 -0
- package/dist/schemas/hero.js +73 -0
- package/dist/schemas/i18n.d.ts +125 -0
- package/dist/schemas/i18n.js +76 -0
- package/dist/schemas/icon.d.ts +284 -0
- package/dist/schemas/icon.js +7 -0
- package/dist/schemas/locale.d.ts +20 -0
- package/dist/schemas/locale.js +11 -0
- package/dist/schemas/logo.d.ts +32 -0
- package/dist/schemas/logo.js +14 -0
- package/dist/schemas/pagefind.d.ts +166 -0
- package/dist/schemas/pagefind.js +31 -0
- package/dist/schemas/prevNextLink.d.ts +10 -0
- package/dist/schemas/prevNextLink.js +14 -0
- package/dist/schemas/sidebar.d.ts +205 -0
- package/dist/schemas/sidebar.js +71 -0
- package/dist/schemas/site-title.d.ts +7 -0
- package/dist/schemas/site-title.js +17 -0
- package/dist/schemas/social.d.ts +292 -0
- package/dist/schemas/social.js +18 -0
- package/dist/schemas/tableOfContents.d.ts +24 -0
- package/dist/schemas/tableOfContents.js +16 -0
- package/{style → dist/style}/anchor-links.css +13 -1
- package/dist/translations/ar.js +36 -0
- package/dist/translations/ca.js +46 -0
- package/dist/translations/cs.js +46 -0
- package/dist/translations/da.js +33 -0
- package/dist/translations/de.js +33 -0
- package/dist/translations/el.js +33 -0
- package/dist/translations/en.js +33 -0
- package/dist/translations/es.js +46 -0
- package/dist/translations/fa.js +33 -0
- package/dist/translations/fi.js +33 -0
- package/dist/translations/fr.js +36 -0
- package/dist/translations/gl.js +46 -0
- package/dist/translations/he.js +33 -0
- package/dist/translations/hi.js +36 -0
- package/dist/translations/hu.js +46 -0
- package/dist/translations/id.js +33 -0
- package/dist/translations/index.d.ts +48 -0
- package/dist/translations/index.js +75 -0
- package/dist/translations/it.js +36 -0
- package/dist/translations/ja.js +36 -0
- package/dist/translations/ko.js +36 -0
- package/dist/translations/lv.js +33 -0
- package/dist/translations/nb.js +33 -0
- package/dist/translations/nl.js +33 -0
- package/dist/translations/pl.js +36 -0
- package/dist/translations/pt.js +36 -0
- package/dist/translations/ro.js +33 -0
- package/dist/translations/ru.js +36 -0
- package/dist/translations/sk.js +33 -0
- package/dist/translations/sv.js +33 -0
- package/dist/translations/th.js +33 -0
- package/dist/translations/tr.js +33 -0
- package/dist/translations/uk.js +33 -0
- package/dist/translations/vi.js +33 -0
- package/dist/translations/zh-CN.js +36 -0
- package/dist/translations/zh-TW.js +36 -0
- package/dist/types.d.ts +4 -0
- package/dist/types.js +1 -0
- package/{user-components → dist/user-components}/FileTree.astro +1 -1
- package/{user-components → dist/user-components}/Steps.astro +1 -1
- package/{user-components → dist/user-components}/TabItem.astro +1 -1
- package/{user-components → dist/user-components}/Tabs.astro +1 -1
- package/dist/user-components/file-tree-icons.d.ts +178 -0
- package/dist/user-components/file-tree-icons.js +632 -0
- package/dist/user-components/file-tree-processor.d.ts +16 -0
- package/dist/user-components/file-tree-processor.js +132 -0
- package/dist/user-components/steps-processor.d.ts +10 -0
- package/dist/user-components/steps-processor.js +39 -0
- package/dist/user-components/tabs-processor.d.ts +23 -0
- package/dist/user-components/tabs-processor.js +70 -0
- package/dist/utils/base.d.ts +7 -0
- package/dist/utils/base.js +15 -0
- package/dist/utils/canonical.d.ts +10 -0
- package/dist/utils/canonical.js +14 -0
- package/dist/utils/collection-fs.d.ts +13 -0
- package/dist/utils/collection-fs.js +19 -0
- package/{utils/collection.ts → dist/utils/collection.d.ts} +9 -20
- package/dist/utils/collection.js +26 -0
- package/dist/utils/createPathFormatter.d.ts +9 -0
- package/dist/utils/createPathFormatter.js +35 -0
- package/dist/utils/createTranslationSystem.d.ts +23 -0
- package/dist/utils/createTranslationSystem.js +84 -0
- package/dist/utils/error-map.d.ts +23 -0
- package/dist/utils/error-map.js +125 -0
- package/dist/utils/format-path.d.ts +4 -0
- package/dist/utils/format-path.js +9 -0
- package/dist/utils/generateToC.d.ts +14 -0
- package/dist/utils/generateToC.js +25 -0
- package/dist/utils/git.d.ts +12 -0
- package/dist/utils/git.js +71 -0
- package/dist/utils/gitInlined.d.ts +6 -0
- package/dist/utils/gitInlined.js +11 -0
- package/dist/utils/head.d.ts +7 -0
- package/dist/utils/head.js +233 -0
- package/dist/utils/i18n.d.ts +50 -0
- package/dist/utils/i18n.js +141 -0
- package/dist/utils/localizedUrl.d.ts +8 -0
- package/dist/utils/localizedUrl.js +28 -0
- package/dist/utils/navigation.d.ts +19 -0
- package/dist/utils/navigation.js +353 -0
- package/dist/utils/path.d.ts +21 -0
- package/dist/utils/path.js +51 -0
- package/dist/utils/plugins.d.ts +721 -0
- package/dist/utils/plugins.js +174 -0
- package/dist/utils/routing/data.d.ts +20 -0
- package/dist/utils/routing/data.js +127 -0
- package/dist/utils/routing/index.d.ts +21 -0
- package/dist/utils/routing/index.js +106 -0
- package/dist/utils/routing/middleware.d.ts +11 -0
- package/dist/utils/routing/middleware.js +65 -0
- package/dist/utils/routing/types.d.ts +93 -0
- package/dist/utils/routing/types.js +1 -0
- package/dist/utils/slugs.d.ts +45 -0
- package/dist/utils/slugs.js +104 -0
- package/dist/utils/starlight-page.d.ts +36 -0
- package/dist/utils/starlight-page.js +120 -0
- package/dist/utils/translations-fs.d.ts +15 -0
- package/dist/utils/translations-fs.js +39 -0
- package/dist/utils/translations.d.ts +20 -0
- package/dist/utils/translations.js +29 -0
- package/dist/utils/types.d.ts +5 -0
- package/dist/utils/types.js +1 -0
- package/dist/utils/url.d.ts +7 -0
- package/{utils/url.ts → dist/utils/url.js} +5 -4
- package/dist/utils/user-config.d.ts +2055 -0
- package/dist/utils/user-config.js +136 -0
- package/dist/utils/validateLogoImports.d.ts +5 -0
- package/dist/utils/validateLogoImports.js +16 -0
- package/dist/utils/zodDeepMerge.d.ts +16 -0
- package/dist/utils/zodDeepMerge.js +53 -0
- package/package.json +62 -33
- package/CHANGELOG.md +0 -3043
- package/components/MobileMenuToggle.astro +0 -114
- package/components-internals/Icons.ts +0 -248
- package/components-internals/SidebarPersistState.ts +0 -71
- package/components-internals/TableOfContents/starlight-toc.ts +0 -127
- package/constants.ts +0 -4
- package/expressive-code.mjs +0 -23
- package/global.d.ts +0 -11
- package/i18n.d.ts +0 -18
- package/index.ts +0 -200
- package/integrations/aside-utils.ts +0 -41
- package/integrations/expressive-code/hast.d.ts +0 -5
- package/integrations/expressive-code/hast.mjs +0 -9
- package/integrations/expressive-code/index.ts +0 -125
- package/integrations/expressive-code/preprocessor.ts +0 -126
- package/integrations/expressive-code/themes/night-owl-dark.jsonc +0 -1796
- package/integrations/expressive-code/themes/night-owl-light.jsonc +0 -1695
- package/integrations/expressive-code/theming.ts +0 -105
- package/integrations/expressive-code/translations.ts +0 -36
- package/integrations/markdown-icon.ts +0 -13
- package/integrations/markdown-plugins.ts +0 -71
- package/integrations/markdown-processor.ts +0 -64
- package/integrations/pagefind.ts +0 -60
- package/integrations/rehype-code-rtl-support.ts +0 -37
- package/integrations/rehype-heading-links.ts +0 -79
- package/integrations/remark-asides.ts +0 -219
- package/integrations/remark-rehype.ts +0 -87
- package/integrations/satteri.ts +0 -265
- package/integrations/shared/absolutePathToLang.ts +0 -26
- package/integrations/shared/localeToLang.ts +0 -15
- package/integrations/shared/slugToLocale.ts +0 -18
- package/integrations/sitemap.ts +0 -23
- package/integrations/vite-layer-order.ts +0 -69
- package/integrations/vite-lazy-barrel-optimization.ts +0 -40
- package/integrations/vite-virtual-modules.ts +0 -175
- package/internal.ts +0 -6
- package/loaders.ts +0 -63
- package/locals.d.ts +0 -43
- package/locals.ts +0 -43
- package/route-data.ts +0 -11
- package/schema.ts +0 -167
- package/schemas/badge.ts +0 -40
- package/schemas/components.ts +0 -265
- package/schemas/expressiveCode.ts +0 -12
- package/schemas/favicon.ts +0 -40
- package/schemas/head.ts +0 -50
- package/schemas/hero.ts +0 -69
- package/schemas/i18n.ts +0 -244
- package/schemas/icon.ts +0 -7
- package/schemas/logo.ts +0 -28
- package/schemas/pagefind.ts +0 -128
- package/schemas/prevNextLink.ts +0 -18
- package/schemas/sidebar.ts +0 -163
- package/schemas/site-title.ts +0 -20
- package/schemas/social.ts +0 -23
- package/schemas/tableOfContents.ts +0 -21
- package/translations/README.md +0 -14
- package/translations/ar.json +0 -33
- package/translations/ca.json +0 -43
- package/translations/cs.json +0 -43
- package/translations/da.json +0 -30
- package/translations/de.json +0 -30
- package/translations/el.json +0 -30
- package/translations/en.json +0 -30
- package/translations/es.json +0 -43
- package/translations/fa.json +0 -30
- package/translations/fi.json +0 -30
- package/translations/fr.json +0 -33
- package/translations/gl.json +0 -43
- package/translations/he.json +0 -30
- package/translations/hi.json +0 -33
- package/translations/hu.json +0 -43
- package/translations/id.json +0 -30
- package/translations/index.ts +0 -76
- package/translations/it.json +0 -33
- package/translations/ja.json +0 -33
- package/translations/ko.json +0 -33
- package/translations/lv.json +0 -30
- package/translations/nb.json +0 -30
- package/translations/nl.json +0 -30
- package/translations/pl.json +0 -33
- package/translations/pt.json +0 -33
- package/translations/ro.json +0 -30
- package/translations/ru.json +0 -33
- package/translations/sk.json +0 -30
- package/translations/sv.json +0 -30
- package/translations/th.json +0 -30
- package/translations/tr.json +0 -30
- package/translations/uk.json +0 -30
- package/translations/vi.json +0 -30
- package/translations/zh-CN.json +0 -33
- package/translations/zh-TW.json +0 -33
- package/types.ts +0 -7
- package/user-components/file-tree-icons.ts +0 -782
- package/user-components/rehype-file-tree.ts +0 -251
- package/user-components/rehype-steps.ts +0 -85
- package/user-components/rehype-tabs.ts +0 -121
- package/utils/base.ts +0 -15
- package/utils/canonical.ts +0 -19
- package/utils/collection-fs.ts +0 -20
- package/utils/createPathFormatter.ts +0 -60
- package/utils/createTranslationSystem.ts +0 -137
- package/utils/error-map.ts +0 -222
- package/utils/format-path.ts +0 -7
- package/utils/generateToC.ts +0 -33
- package/utils/git.ts +0 -121
- package/utils/gitInlined.ts +0 -20
- package/utils/head.ts +0 -235
- package/utils/i18n.ts +0 -221
- package/utils/localizedUrl.ts +0 -51
- package/utils/navigation.ts +0 -566
- package/utils/path.ts +0 -58
- package/utils/plugins.ts +0 -498
- package/utils/routing/data.ts +0 -154
- package/utils/routing/index.ts +0 -135
- package/utils/routing/middleware.ts +0 -81
- package/utils/routing/types.ts +0 -101
- package/utils/slugs.ts +0 -119
- package/utils/starlight-page.ts +0 -205
- package/utils/translations-fs.ts +0 -54
- package/utils/translations.ts +0 -57
- package/utils/types.ts +0 -15
- package/utils/user-config.ts +0 -348
- package/utils/validateLogoImports.ts +0 -21
- package/utils/zodDeepMerge.ts +0 -144
- package/virtual-internal.d.ts +0 -149
- package/virtual.d.ts +0 -27
- /package/{components → dist/components}/AnchorHeading.astro +0 -0
- /package/{components → dist/components}/Banner.astro +0 -0
- /package/{components → dist/components}/ContentNotice.astro +0 -0
- /package/{components → dist/components}/ContentPanel.astro +0 -0
- /package/{components → dist/components}/DraftContentNotice.astro +0 -0
- /package/{components → dist/components}/EditLink.astro +0 -0
- /package/{components → dist/components}/FallbackContentNotice.astro +0 -0
- /package/{components → dist/components}/Footer.astro +0 -0
- /package/{components → dist/components}/Head.astro +0 -0
- /package/{components → dist/components}/Header.astro +0 -0
- /package/{components → dist/components}/Hero.astro +0 -0
- /package/{components → dist/components}/LanguageSelect.astro +0 -0
- /package/{components → dist/components}/LastUpdated.astro +0 -0
- /package/{components → dist/components}/MarkdownContent.astro +0 -0
- /package/{components → dist/components}/MobileMenuFooter.astro +0 -0
- /package/{components → dist/components}/MobileTableOfContents.astro +0 -0
- /package/{components → dist/components}/Page.astro +0 -0
- /package/{components → dist/components}/PageSidebar.astro +0 -0
- /package/{components → dist/components}/PageTitle.astro +0 -0
- /package/{components → dist/components}/Pagination.astro +0 -0
- /package/{components → dist/components}/Search.astro +0 -0
- /package/{components → dist/components}/Select.astro +0 -0
- /package/{components → dist/components}/Sidebar.astro +0 -0
- /package/{components → dist/components}/SidebarPersister.astro +0 -0
- /package/{components → dist/components}/SidebarRestorePoint.astro +0 -0
- /package/{components → dist/components}/SidebarSublist.astro +0 -0
- /package/{components → dist/components}/SiteTitle.astro +0 -0
- /package/{components → dist/components}/SkipLink.astro +0 -0
- /package/{components → dist/components}/SocialIcons.astro +0 -0
- /package/{components → dist/components}/StarlightPage.astro +0 -0
- /package/{components → dist/components}/TableOfContents.astro +0 -0
- /package/{components → dist/components}/ThemeProvider.astro +0 -0
- /package/{components → dist/components}/ThemeSelect.astro +0 -0
- /package/{components → dist/components}/TwoColumnContent.astro +0 -0
- /package/{components-internals → dist/components-internals}/TableOfContents/TableOfContentsList.astro +0 -0
- /package/{components.ts → dist/components.ts} +0 -0
- /package/{routes → dist/routes}/common.astro +0 -0
- /package/{routes → dist/routes}/ssr/404.astro +0 -0
- /package/{routes → dist/routes}/ssr/index.astro +0 -0
- /package/{routes → dist/routes}/static/404.astro +0 -0
- /package/{routes → dist/routes}/static/index.astro +0 -0
- /package/{style → dist/style}/asides.css +0 -0
- /package/{style → dist/style}/layers.css +0 -0
- /package/{style → dist/style}/markdown.css +0 -0
- /package/{style → dist/style}/print.css +0 -0
- /package/{style → dist/style}/props.css +0 -0
- /package/{style → dist/style}/reset.css +0 -0
- /package/{style → dist/style}/util.css +0 -0
- /package/{user-components → dist/user-components}/Aside.astro +0 -0
- /package/{user-components → dist/user-components}/Badge.astro +0 -0
- /package/{user-components → dist/user-components}/Card.astro +0 -0
- /package/{user-components → dist/user-components}/CardGrid.astro +0 -0
- /package/{user-components → dist/user-components}/Icon.astro +0 -0
- /package/{user-components → dist/user-components}/LinkButton.astro +0 -0
- /package/{user-components → dist/user-components}/LinkCard.astro +0 -0
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { AstroError } from "astro/errors";
|
|
2
|
+
//#region src/utils/i18n.ts
|
|
3
|
+
/**
|
|
4
|
+
* A list of well-known right-to-left languages used as a fallback when determining the text
|
|
5
|
+
* direction of a locale is not supported by the `Intl.Locale` API in the current environment.
|
|
6
|
+
*
|
|
7
|
+
* @see getLocaleDir()
|
|
8
|
+
* @see https://en.wikipedia.org/wiki/IETF_language_tag#List_of_common_primary_language_subtags
|
|
9
|
+
*/
|
|
10
|
+
const wellKnownRTL = [
|
|
11
|
+
"ar",
|
|
12
|
+
"fa",
|
|
13
|
+
"he",
|
|
14
|
+
"prs",
|
|
15
|
+
"ps",
|
|
16
|
+
"syc",
|
|
17
|
+
"ug",
|
|
18
|
+
"ur"
|
|
19
|
+
];
|
|
20
|
+
/** Information about the built-in default locale used as a fallback when no locales are defined. */
|
|
21
|
+
const BuiltInDefaultLocale = {
|
|
22
|
+
...getLocaleInfo("en"),
|
|
23
|
+
lang: "en"
|
|
24
|
+
};
|
|
25
|
+
/**
|
|
26
|
+
* Processes the Astro and Starlight i18n configurations to generate/update them accordingly:
|
|
27
|
+
*
|
|
28
|
+
* - If no Astro and Starlight i18n configurations are provided, the built-in default locale is
|
|
29
|
+
* used in Starlight and the generated Astro i18n configuration will match it.
|
|
30
|
+
* - If only a Starlight i18n configuration is provided, an equivalent Astro i18n configuration is
|
|
31
|
+
* generated.
|
|
32
|
+
* - If only an Astro i18n configuration is provided, an equivalent Starlight i18n configuration is
|
|
33
|
+
* used.
|
|
34
|
+
* - If both an Astro and Starlight i18n configurations are provided, an error is thrown.
|
|
35
|
+
*/
|
|
36
|
+
function processI18nConfig(starlightConfig, astroI18nConfig) {
|
|
37
|
+
if (astroI18nConfig && !starlightConfig.isUsingBuiltInDefaultLocale) throw new AstroError("Cannot provide both an Astro `i18n` configuration and a Starlight `locales` configuration.", "Remove one of the two configurations.\nSee more at https://starlight.astro.build/guides/i18n/");
|
|
38
|
+
else if (astroI18nConfig) return {
|
|
39
|
+
astroI18nConfig,
|
|
40
|
+
starlightConfig: {
|
|
41
|
+
...starlightConfig,
|
|
42
|
+
...getStarlightI18nConfig(astroI18nConfig)
|
|
43
|
+
}
|
|
44
|
+
};
|
|
45
|
+
return {
|
|
46
|
+
astroI18nConfig: getAstroI18nConfig(starlightConfig),
|
|
47
|
+
starlightConfig
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
/** Generate an Astro i18n configuration based on a Starlight configuration. */
|
|
51
|
+
function getAstroI18nConfig(config) {
|
|
52
|
+
return {
|
|
53
|
+
defaultLocale: (config.defaultLocale.locale === "root" ? config.defaultLocale.lang : config.defaultLocale.locale ?? config.defaultLocale.lang) ?? BuiltInDefaultLocale.lang,
|
|
54
|
+
locales: config.locales ? Object.entries(config.locales).map(([locale, localeConfig]) => {
|
|
55
|
+
return {
|
|
56
|
+
codes: [localeConfig?.lang ?? locale],
|
|
57
|
+
path: locale === "root" ? localeConfig?.lang ?? BuiltInDefaultLocale.lang : locale
|
|
58
|
+
};
|
|
59
|
+
}) : [config.defaultLocale.lang],
|
|
60
|
+
routing: {
|
|
61
|
+
prefixDefaultLocale: config.isMultilingual && config.locales?.root === void 0 || !config.isMultilingual && config.locales !== void 0,
|
|
62
|
+
redirectToDefaultLocale: false,
|
|
63
|
+
fallbackType: "redirect"
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
/** Generate a Starlight i18n configuration based on an Astro configuration. */
|
|
68
|
+
function getStarlightI18nConfig(astroI18nConfig) {
|
|
69
|
+
if (astroI18nConfig.routing === "manual") throw new AstroError("Starlight is not compatible with the `manual` routing option in the Astro i18n configuration.");
|
|
70
|
+
const prefixDefaultLocale = astroI18nConfig.routing.prefixDefaultLocale;
|
|
71
|
+
const isMultilingual = astroI18nConfig.locales.length > 1;
|
|
72
|
+
const isMonolingualWithRootLocale = !isMultilingual && !prefixDefaultLocale;
|
|
73
|
+
const locales = isMonolingualWithRootLocale ? void 0 : Object.fromEntries(astroI18nConfig.locales.map((locale) => [isDefaultAstroLocale(astroI18nConfig, locale) && !prefixDefaultLocale ? "root" : isAstroLocaleExtendedConfig(locale) ? locale.path : locale, inferStarlightLocaleFromAstroLocale(locale)]));
|
|
74
|
+
const defaultAstroLocale = astroI18nConfig.locales.find((locale) => isDefaultAstroLocale(astroI18nConfig, locale));
|
|
75
|
+
if (!defaultAstroLocale) throw new AstroError("Astro default locale not found.", "This should never happen. Please open a new issue: https://github.com/withastro/starlight/issues/new?template=---01-bug-report.yml");
|
|
76
|
+
return {
|
|
77
|
+
isMultilingual,
|
|
78
|
+
locales,
|
|
79
|
+
defaultLocale: {
|
|
80
|
+
...inferStarlightLocaleFromAstroLocale(defaultAstroLocale),
|
|
81
|
+
locale: isMonolingualWithRootLocale || isMultilingual && !prefixDefaultLocale ? void 0 : isAstroLocaleExtendedConfig(defaultAstroLocale) ? defaultAstroLocale.codes[0] : defaultAstroLocale
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
/** Infer Starlight locale information based on a locale from an Astro i18n configuration. */
|
|
86
|
+
function inferStarlightLocaleFromAstroLocale(astroLocale) {
|
|
87
|
+
const lang = isAstroLocaleExtendedConfig(astroLocale) ? astroLocale.codes[0] : astroLocale;
|
|
88
|
+
return {
|
|
89
|
+
...getLocaleInfo(lang),
|
|
90
|
+
lang
|
|
91
|
+
};
|
|
92
|
+
}
|
|
93
|
+
/** Check if the passed locale is the default locale in an Astro i18n configuration. */
|
|
94
|
+
function isDefaultAstroLocale(astroI18nConfig, locale) {
|
|
95
|
+
return (isAstroLocaleExtendedConfig(locale) ? locale.path : locale) === astroI18nConfig.defaultLocale;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Check if the passed Astro locale is using the object variant.
|
|
99
|
+
* @see AstroLocaleExtendedConfig
|
|
100
|
+
*/
|
|
101
|
+
function isAstroLocaleExtendedConfig(locale) {
|
|
102
|
+
return typeof locale !== "string";
|
|
103
|
+
}
|
|
104
|
+
/** Returns the locale information such as a label and a direction based on a BCP-47 tag. */
|
|
105
|
+
function getLocaleInfo(lang) {
|
|
106
|
+
try {
|
|
107
|
+
const locale = new Intl.Locale(lang);
|
|
108
|
+
const label = new Intl.DisplayNames(locale, { type: "language" }).of(lang);
|
|
109
|
+
if (!label || lang === label) throw new Error("Label not found.");
|
|
110
|
+
return {
|
|
111
|
+
label: label[0]?.toLocaleUpperCase(locale) + label.slice(1),
|
|
112
|
+
dir: getLocaleDir(locale)
|
|
113
|
+
};
|
|
114
|
+
} catch {
|
|
115
|
+
throw new AstroError(`Failed to get locale information for the '${lang}' locale.`, "Make sure to provide a valid BCP-47 tags (e.g. en, ar, or zh-CN).");
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Returns the direction of the passed locale.
|
|
120
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Intl/Locale/getTextInfo
|
|
121
|
+
*/
|
|
122
|
+
function getLocaleDir(locale) {
|
|
123
|
+
if ("textInfo" in locale) return locale.textInfo.direction;
|
|
124
|
+
else if ("getTextInfo" in locale) return locale.getTextInfo().direction;
|
|
125
|
+
return wellKnownRTL.includes(locale.language) ? "rtl" : "ltr";
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Get the string for the passed language from a dictionary object.
|
|
129
|
+
*
|
|
130
|
+
* TODO: Make this clever. Currently a simple key look-up, but should use
|
|
131
|
+
* BCP-47 mapping so that e.g. `en-US` returns `en` strings, and use the
|
|
132
|
+
* site’s default locale as a last resort.
|
|
133
|
+
*
|
|
134
|
+
* @example
|
|
135
|
+
* pickLang({ en: 'Hello', fr: 'Bonjour' }, 'en'); // => 'Hello'
|
|
136
|
+
*/
|
|
137
|
+
function pickLang(dictionary, lang) {
|
|
138
|
+
return dictionary[lang];
|
|
139
|
+
}
|
|
140
|
+
//#endregion
|
|
141
|
+
export { BuiltInDefaultLocale, pickLang, processI18nConfig };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { AstroConfig } from "astro";
|
|
2
|
+
//#region src/utils/localizedUrl.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Get the equivalent of the passed URL for the passed locale.
|
|
5
|
+
*/
|
|
6
|
+
declare function localizedUrl(url: URL, locale: string | undefined, trailingSlash: AstroConfig['trailingSlash']): URL;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { localizedUrl };
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { stripTrailingSlash } from "./path.js";
|
|
2
|
+
import config from "virtual:starlight/user-config";
|
|
3
|
+
//#region src/utils/localizedUrl.ts
|
|
4
|
+
/**
|
|
5
|
+
* Get the equivalent of the passed URL for the passed locale.
|
|
6
|
+
*/
|
|
7
|
+
function localizedUrl(url, locale, trailingSlash) {
|
|
8
|
+
url = new URL(url);
|
|
9
|
+
if (!config.locales) return url;
|
|
10
|
+
if (locale === "root") locale = "";
|
|
11
|
+
/** Base URL with trailing `/` stripped. */
|
|
12
|
+
const base = stripTrailingSlash(import.meta.env.BASE_URL);
|
|
13
|
+
const hasBase = url.pathname.startsWith(base);
|
|
14
|
+
if (hasBase) url.pathname = url.pathname.replace(base, "");
|
|
15
|
+
const [_leadingSlash, baseSegment] = url.pathname.split("/");
|
|
16
|
+
const isRootHtml = baseSegment?.endsWith(".html");
|
|
17
|
+
const baseSlug = isRootHtml ? baseSegment?.slice(0, -5) : baseSegment;
|
|
18
|
+
if (baseSlug && baseSlug in config.locales) if (locale) url.pathname = url.pathname.replace(baseSlug, locale);
|
|
19
|
+
else if (isRootHtml) url.pathname = "/index.html";
|
|
20
|
+
else url.pathname = url.pathname.replace("/" + baseSlug, "");
|
|
21
|
+
else if (locale) if (baseSegment === "index.html") url.pathname = "/" + locale + ".html";
|
|
22
|
+
else url.pathname = "/" + locale + url.pathname;
|
|
23
|
+
if (hasBase) url.pathname = base + url.pathname;
|
|
24
|
+
if (trailingSlash === "never") url.pathname = stripTrailingSlash(url.pathname);
|
|
25
|
+
return url;
|
|
26
|
+
}
|
|
27
|
+
//#endregion
|
|
28
|
+
export { localizedUrl };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { StarlightConfig } from "./user-config.js";
|
|
2
|
+
import { PaginationLinks, SidebarEntry, SidebarLink } from "./routing/types.js";
|
|
3
|
+
import { PrevNextLinkConfig } from "../schemas/prevNextLink.js";
|
|
4
|
+
//#region src/utils/navigation.d.ts
|
|
5
|
+
/** Get the sidebar for the current page using the global config. */
|
|
6
|
+
declare function getSidebar(pathname: string, locale: string | undefined): SidebarEntry[];
|
|
7
|
+
/** Get the sidebar for the current page using the specified sidebar config. */
|
|
8
|
+
declare function getSidebarFromConfig(sidebarConfig: StarlightConfig['sidebar'], pathname: string, locale: string | undefined): SidebarEntry[];
|
|
9
|
+
/** Generates a deterministic string based on the content of the passed sidebar. */
|
|
10
|
+
declare function getSidebarHash(sidebar: SidebarEntry[]): string;
|
|
11
|
+
/** Turn the nested tree structure of a sidebar into a flat list of all the links. */
|
|
12
|
+
declare function flattenSidebar(sidebar: SidebarEntry[]): SidebarLink[];
|
|
13
|
+
/** Get previous/next pages in the sidebar or the ones from the frontmatter if any. */
|
|
14
|
+
declare function getPrevNextLinks(sidebar: SidebarEntry[], paginationEnabled: boolean, config: {
|
|
15
|
+
prev?: PrevNextLinkConfig;
|
|
16
|
+
next?: PrevNextLinkConfig;
|
|
17
|
+
}): PaginationLinks;
|
|
18
|
+
//#endregion
|
|
19
|
+
export { flattenSidebar, getPrevNextLinks, getSidebar, getSidebarFromConfig, getSidebarHash };
|
|
@@ -0,0 +1,353 @@
|
|
|
1
|
+
import { getCollectionPathFromRoot } from "./collection.js";
|
|
2
|
+
import { ensureLeadingSlash, ensureTrailingSlash, stripExtension, stripLeadingAndTrailingSlashes } from "./path.js";
|
|
3
|
+
import { BuiltInDefaultLocale, pickLang } from "./i18n.js";
|
|
4
|
+
import { createPathFormatter } from "./createPathFormatter.js";
|
|
5
|
+
import { formatPath } from "./format-path.js";
|
|
6
|
+
import { hasProtocol } from "./url.js";
|
|
7
|
+
import { localeToLang, localizedFilePath, slugToPathname } from "./slugs.js";
|
|
8
|
+
import { getLocaleRoutes, getRouteById } from "./routing/index.js";
|
|
9
|
+
import { AstroError } from "astro/errors";
|
|
10
|
+
import config from "virtual:starlight/user-config";
|
|
11
|
+
import project from "virtual:starlight/project-context";
|
|
12
|
+
//#region src/utils/navigation.ts
|
|
13
|
+
const DirKey = Symbol("DirKey");
|
|
14
|
+
const SlugKey = Symbol("SlugKey");
|
|
15
|
+
const rootAutogenerate = { directory: "" };
|
|
16
|
+
const neverPathFormatter = createPathFormatter({ trailingSlash: "never" });
|
|
17
|
+
const sidebarCollator = new Intl.Collator(localeToLang(void 0));
|
|
18
|
+
const docsCollectionPathFromRoot = getCollectionPathFromRoot("docs", project);
|
|
19
|
+
/** Create a new directory object. */
|
|
20
|
+
function makeDir(slug) {
|
|
21
|
+
const dir = {};
|
|
22
|
+
Object.defineProperty(dir, DirKey, { enumerable: false });
|
|
23
|
+
Object.defineProperty(dir, SlugKey, {
|
|
24
|
+
value: slug,
|
|
25
|
+
enumerable: false
|
|
26
|
+
});
|
|
27
|
+
return dir;
|
|
28
|
+
}
|
|
29
|
+
/** Test if the passed object is a directory record. */
|
|
30
|
+
function isDir(data) {
|
|
31
|
+
return DirKey in data;
|
|
32
|
+
}
|
|
33
|
+
/** Convert an item in a user’s sidebar config to a sidebar entry. */
|
|
34
|
+
function configItemToEntry(item, locale, routes) {
|
|
35
|
+
if ("link" in item) return linkFromSidebarLinkItem(item, locale);
|
|
36
|
+
else if ("autogenerate" in item) return entriesFromAutogenerateConfig(item, locale, routes);
|
|
37
|
+
else if ("slug" in item) return linkFromInternalSidebarLinkItem(item, locale);
|
|
38
|
+
else {
|
|
39
|
+
const label = pickLang(item.translations, localeToLang(locale)) || item.label;
|
|
40
|
+
return {
|
|
41
|
+
type: "group",
|
|
42
|
+
label,
|
|
43
|
+
entries: item.items.flatMap((i) => configItemToEntry(i, locale, routes)),
|
|
44
|
+
collapsed: item.collapsed,
|
|
45
|
+
badge: getSidebarBadge(item.badge, locale, label)
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
/** Autogenerate links and groups from a user’s sidebar config. */
|
|
50
|
+
function entriesFromAutogenerateConfig(item, locale, routes) {
|
|
51
|
+
const { attrs, collapsed, directory } = item.autogenerate;
|
|
52
|
+
const localeDir = locale ? locale + "/" + directory : directory;
|
|
53
|
+
const autogenerate = { directory };
|
|
54
|
+
return sidebarFromDir(treeify(routes.filter((doc) => {
|
|
55
|
+
const filePathFromContentDir = getRoutePathRelativeToCollectionRoot(doc, locale);
|
|
56
|
+
return stripExtension(filePathFromContentDir) === localeDir || filePathFromContentDir.startsWith(localeDir + "/");
|
|
57
|
+
}), locale, localeDir), {
|
|
58
|
+
collapsed: collapsed ?? false,
|
|
59
|
+
attrs
|
|
60
|
+
}, autogenerate);
|
|
61
|
+
}
|
|
62
|
+
/** Create a link entry from a manual link item in user config. */
|
|
63
|
+
function linkFromSidebarLinkItem(item, locale) {
|
|
64
|
+
let href = item.link;
|
|
65
|
+
if (!hasProtocol(href)) {
|
|
66
|
+
href = ensureLeadingSlash(href);
|
|
67
|
+
if (locale) href = "/" + locale + href;
|
|
68
|
+
}
|
|
69
|
+
const label = pickLang(item.translations, localeToLang(locale)) || item.label;
|
|
70
|
+
return makeSidebarLink({
|
|
71
|
+
href,
|
|
72
|
+
label,
|
|
73
|
+
badge: getSidebarBadge(item.badge, locale, label),
|
|
74
|
+
attrs: item.attrs
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
/** Create a link entry from an automatic internal link item in user config. */
|
|
78
|
+
function linkFromInternalSidebarLinkItem(item, locale) {
|
|
79
|
+
const slug = item.slug === "index" ? "" : item.slug;
|
|
80
|
+
const localizedSlug = locale ? slug ? locale + "/" + slug : locale : slug;
|
|
81
|
+
const route = getRouteById(localizedSlug);
|
|
82
|
+
if (!route) if (item.slug.at(0) === "/" || item.slug.at(-1) === "/") throw new AstroError(`The slug \`"${item.slug}"\` specified in the Starlight sidebar config must not start or end with a slash.`, `Please try updating \`"${item.slug}"\` to \`"${stripLeadingAndTrailingSlashes(item.slug)}"\`.`);
|
|
83
|
+
else throw new AstroError(`The slug \`"${item.slug}"\` specified in the Starlight sidebar config does not exist.`, "Update the Starlight config to reference a valid entry slug in the docs content collection.\nLearn more about Astro content collection slugs at https://docs.astro.build/en/reference/modules/astro-content/#getentry");
|
|
84
|
+
const frontmatter = route.entry.data;
|
|
85
|
+
const label = pickLang(item.translations, localeToLang(locale)) || item.label || frontmatter.sidebar?.label || frontmatter.title;
|
|
86
|
+
const badge = item.badge ?? frontmatter.sidebar?.badge;
|
|
87
|
+
const attrs = {
|
|
88
|
+
...frontmatter.sidebar?.attrs,
|
|
89
|
+
...item.attrs
|
|
90
|
+
};
|
|
91
|
+
return makeSidebarLink({
|
|
92
|
+
href: slugToPathname(route.id),
|
|
93
|
+
label,
|
|
94
|
+
badge: getSidebarBadge(badge, locale, label),
|
|
95
|
+
attrs
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
function makeSidebarLink({ attrs, badge, href, label, autogenerate }) {
|
|
99
|
+
if (!hasProtocol(href)) href = formatPath(href);
|
|
100
|
+
return makeLink({
|
|
101
|
+
label,
|
|
102
|
+
href,
|
|
103
|
+
badge,
|
|
104
|
+
attrs,
|
|
105
|
+
autogenerate
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
/** Create a link entry */
|
|
109
|
+
function makeLink({ attrs = {}, badge, autogenerate, ...opts }) {
|
|
110
|
+
return {
|
|
111
|
+
type: "link",
|
|
112
|
+
...opts,
|
|
113
|
+
badge,
|
|
114
|
+
isCurrent: false,
|
|
115
|
+
attrs,
|
|
116
|
+
...autogenerate ? { autogenerate } : {}
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
/** Get the segments leading to a page. */
|
|
120
|
+
function getBreadcrumbs(path, baseDir) {
|
|
121
|
+
const pathWithoutExt = stripExtension(path);
|
|
122
|
+
if (pathWithoutExt === baseDir) return [];
|
|
123
|
+
baseDir = ensureTrailingSlash(baseDir);
|
|
124
|
+
return (pathWithoutExt.startsWith(baseDir) ? pathWithoutExt.replace(baseDir, "") : pathWithoutExt).split("/");
|
|
125
|
+
}
|
|
126
|
+
/** Return the path of a route relative to the root of the collection. */
|
|
127
|
+
function getRoutePathRelativeToCollectionRoot(route, locale) {
|
|
128
|
+
return localizedFilePath(route.entry.filePath.replace(`${docsCollectionPathFromRoot}/`, ""), locale);
|
|
129
|
+
}
|
|
130
|
+
/** Turn a flat array of routes into a tree structure. */
|
|
131
|
+
function treeify(routes, locale, baseDir) {
|
|
132
|
+
const treeRoot = makeDir(baseDir);
|
|
133
|
+
routes.filter((doc) => !doc.entry.data.sidebar.hidden).map((doc) => [getRoutePathRelativeToCollectionRoot(doc, locale), doc]).sort(([a], [b]) => b.split("/").length - a.split("/").length).forEach(([filePathFromContentDir, doc]) => {
|
|
134
|
+
const parts = getBreadcrumbs(filePathFromContentDir, baseDir);
|
|
135
|
+
let currentNode = treeRoot;
|
|
136
|
+
parts.forEach((part, index) => {
|
|
137
|
+
const isLeaf = index === parts.length - 1;
|
|
138
|
+
if (isLeaf && Object.hasOwn(currentNode, part)) {
|
|
139
|
+
currentNode = currentNode[part];
|
|
140
|
+
part = "index";
|
|
141
|
+
}
|
|
142
|
+
if (!isLeaf) {
|
|
143
|
+
const path = currentNode[SlugKey];
|
|
144
|
+
currentNode[part] ||= makeDir(stripLeadingAndTrailingSlashes(path + "/" + part));
|
|
145
|
+
currentNode = currentNode[part];
|
|
146
|
+
} else currentNode[part] = doc;
|
|
147
|
+
});
|
|
148
|
+
});
|
|
149
|
+
return treeRoot;
|
|
150
|
+
}
|
|
151
|
+
/** Create a link entry for a given content collection entry. */
|
|
152
|
+
function linkFromRoute(route, attrs, autogenerate) {
|
|
153
|
+
return makeSidebarLink({
|
|
154
|
+
href: slugToPathname(route.id),
|
|
155
|
+
label: route.entry.data.sidebar.label || route.entry.data.title,
|
|
156
|
+
badge: route.entry.data.sidebar.badge,
|
|
157
|
+
attrs: {
|
|
158
|
+
...attrs,
|
|
159
|
+
...route.entry.data.sidebar.attrs
|
|
160
|
+
},
|
|
161
|
+
autogenerate
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get the sort weight for a given route or directory. Lower numbers rank higher.
|
|
166
|
+
* Directories have the weight of the lowest weighted route they contain.
|
|
167
|
+
*/
|
|
168
|
+
function getOrder(routeOrDir) {
|
|
169
|
+
const cachedOrder = orderByEntry.get(routeOrDir);
|
|
170
|
+
if (cachedOrder !== void 0) return cachedOrder;
|
|
171
|
+
const order = isDir(routeOrDir) ? Math.min(...Object.values(routeOrDir).flatMap(getOrder)) : routeOrDir.entry.data.sidebar.order ?? Number.MAX_VALUE;
|
|
172
|
+
orderByEntry.set(routeOrDir, order);
|
|
173
|
+
return order;
|
|
174
|
+
}
|
|
175
|
+
const orderByEntry = /* @__PURE__ */ new WeakMap();
|
|
176
|
+
/** Sort a directory’s entries by user-specified order or alphabetically if no order specified. */
|
|
177
|
+
function sortDirEntries(dir) {
|
|
178
|
+
return dir.sort(([_keyA, a], [_keyB, b]) => {
|
|
179
|
+
const [aOrder, bOrder] = [getOrder(a), getOrder(b)];
|
|
180
|
+
if (aOrder !== bOrder) return aOrder < bOrder ? -1 : 1;
|
|
181
|
+
return sidebarCollator.compare(isDir(a) ? a[SlugKey] : a.id, isDir(b) ? b[SlugKey] : b.id);
|
|
182
|
+
});
|
|
183
|
+
}
|
|
184
|
+
/** Create a group entry for a given content collection directory. */
|
|
185
|
+
function groupFromDir(dir, context) {
|
|
186
|
+
const { fullPath, dirName, collapsed, autogenerate } = context;
|
|
187
|
+
return {
|
|
188
|
+
type: "group",
|
|
189
|
+
label: dirName,
|
|
190
|
+
entries: sortDirEntries(Object.entries(dir)).map(([key, dirOrRoute]) => dirToItem(dirOrRoute, {
|
|
191
|
+
...context,
|
|
192
|
+
fullPath: `${fullPath}/${key}`,
|
|
193
|
+
dirName: key
|
|
194
|
+
})),
|
|
195
|
+
collapsed,
|
|
196
|
+
badge: void 0,
|
|
197
|
+
autogenerate
|
|
198
|
+
};
|
|
199
|
+
}
|
|
200
|
+
/** Create a sidebar entry for a directory or content entry. */
|
|
201
|
+
function dirToItem(dirOrRoute, context) {
|
|
202
|
+
const { attrs, autogenerate } = context;
|
|
203
|
+
return isDir(dirOrRoute) ? groupFromDir(dirOrRoute, context) : linkFromRoute(dirOrRoute, attrs, autogenerate);
|
|
204
|
+
}
|
|
205
|
+
/** Create a sidebar entry for a given content directory. */
|
|
206
|
+
function sidebarFromDir(tree, options, autogenerate = rootAutogenerate) {
|
|
207
|
+
return sortDirEntries(Object.entries(tree)).map(([key, dirOrRoute]) => dirToItem(dirOrRoute, {
|
|
208
|
+
...options,
|
|
209
|
+
fullPath: key,
|
|
210
|
+
dirName: key,
|
|
211
|
+
autogenerate
|
|
212
|
+
}));
|
|
213
|
+
}
|
|
214
|
+
/**
|
|
215
|
+
* Intermediate sidebar represents sidebar entries generated from the user config for a specific
|
|
216
|
+
* locale. These representations are cached per locale to avoid regenerating them for each page.
|
|
217
|
+
* When generating the final sidebar for a page, the current page entry in the sidebar is marked
|
|
218
|
+
* with `isCurrent` and cached. Subsequent runs then reset the previous current entry before marking
|
|
219
|
+
* the new current page.
|
|
220
|
+
*
|
|
221
|
+
* Sidebars, like all route data, are deep cloned before the data is passed to users for mutation,
|
|
222
|
+
* so optimising with a single mutable object per locale is safe.
|
|
223
|
+
*
|
|
224
|
+
* @see getSidebarFromIntermediateSidebar
|
|
225
|
+
*/
|
|
226
|
+
const intermediateSidebars = /* @__PURE__ */ new Map();
|
|
227
|
+
const lastCurrentEntryByLocale = /* @__PURE__ */ new Map();
|
|
228
|
+
/** Get the sidebar for the current page using the global config. */
|
|
229
|
+
function getSidebar(pathname, locale) {
|
|
230
|
+
let intermediateSidebar = intermediateSidebars.get(locale);
|
|
231
|
+
if (!intermediateSidebar) {
|
|
232
|
+
intermediateSidebar = getIntermediateSidebarFromConfig(config.sidebar, locale);
|
|
233
|
+
intermediateSidebars.set(locale, intermediateSidebar);
|
|
234
|
+
}
|
|
235
|
+
setIntermediateSidebarCurrentEntry(intermediateSidebar, pathname, locale);
|
|
236
|
+
return intermediateSidebar;
|
|
237
|
+
}
|
|
238
|
+
/** Get the sidebar for the current page using the specified sidebar config. */
|
|
239
|
+
function getSidebarFromConfig(sidebarConfig, pathname, locale) {
|
|
240
|
+
const sidebar = getIntermediateSidebarFromConfig(sidebarConfig, locale);
|
|
241
|
+
const currentEntry = getSidebarCurrentEntry(sidebar, pathname);
|
|
242
|
+
if (currentEntry) currentEntry.isCurrent = true;
|
|
243
|
+
return sidebar;
|
|
244
|
+
}
|
|
245
|
+
/** Get the intermediate sidebar for a locale using the specified sidebar config. */
|
|
246
|
+
function getIntermediateSidebarFromConfig(sidebarConfig, locale) {
|
|
247
|
+
const routes = getLocaleRoutes(locale);
|
|
248
|
+
if (sidebarConfig) return sidebarConfig.flatMap((group) => configItemToEntry(group, locale, routes));
|
|
249
|
+
else return sidebarFromDir(treeify(routes, locale, locale || ""), {
|
|
250
|
+
collapsed: false,
|
|
251
|
+
attrs: void 0
|
|
252
|
+
});
|
|
253
|
+
}
|
|
254
|
+
/** Marks the current page in an intermediate sidebar. */
|
|
255
|
+
function setIntermediateSidebarCurrentEntry(intermediateSidebar, pathname, locale) {
|
|
256
|
+
const lastCurrentEntry = lastCurrentEntryByLocale.get(locale);
|
|
257
|
+
if (lastCurrentEntry) lastCurrentEntry.isCurrent = false;
|
|
258
|
+
const entry = getSidebarCurrentEntry(intermediateSidebar, pathname);
|
|
259
|
+
if (entry) {
|
|
260
|
+
entry.isCurrent = true;
|
|
261
|
+
lastCurrentEntryByLocale.set(locale, entry);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
/** Finds the current page in a sidebar. */
|
|
265
|
+
function getSidebarCurrentEntry(sidebar, pathname) {
|
|
266
|
+
let entriesByPath = sidebarEntriesByPath.get(sidebar);
|
|
267
|
+
if (!entriesByPath) {
|
|
268
|
+
entriesByPath = /* @__PURE__ */ new Map();
|
|
269
|
+
for (const entry of flattenSidebar(sidebar)) {
|
|
270
|
+
const path = neverPathFormatter(encodeURI(entry.href));
|
|
271
|
+
if (!entriesByPath.has(path)) entriesByPath.set(path, entry);
|
|
272
|
+
}
|
|
273
|
+
sidebarEntriesByPath.set(sidebar, entriesByPath);
|
|
274
|
+
}
|
|
275
|
+
return entriesByPath.get(neverPathFormatter(pathname)) ?? null;
|
|
276
|
+
}
|
|
277
|
+
const sidebarEntriesByPath = /* @__PURE__ */ new WeakMap();
|
|
278
|
+
/** Generates a deterministic string based on the content of the passed sidebar. */
|
|
279
|
+
function getSidebarHash(sidebar) {
|
|
280
|
+
let hash = 0;
|
|
281
|
+
const sidebarIdentity = recursivelyBuildSidebarIdentity(sidebar);
|
|
282
|
+
for (let i = 0; i < sidebarIdentity.length; i++) {
|
|
283
|
+
const char = sidebarIdentity.charCodeAt(i);
|
|
284
|
+
hash = (hash << 5) - hash + char;
|
|
285
|
+
}
|
|
286
|
+
return (hash >>> 0).toString(36).padStart(7, "0");
|
|
287
|
+
}
|
|
288
|
+
/** Recurses through a sidebar tree to generate a string concatenating labels and link hrefs. */
|
|
289
|
+
function recursivelyBuildSidebarIdentity(sidebar) {
|
|
290
|
+
return sidebar.flatMap((entry) => entry.type === "group" ? entry.label + recursivelyBuildSidebarIdentity(entry.entries) : entry.label + entry.href).join("");
|
|
291
|
+
}
|
|
292
|
+
/** Turn the nested tree structure of a sidebar into a flat list of all the links. */
|
|
293
|
+
function flattenSidebar(sidebar) {
|
|
294
|
+
const cachedSidebar = flattenedSidebars.get(sidebar);
|
|
295
|
+
if (cachedSidebar) return cachedSidebar;
|
|
296
|
+
const flattenedSidebar = sidebar.flatMap((entry) => entry.type === "group" ? flattenSidebar(entry.entries) : entry);
|
|
297
|
+
flattenedSidebars.set(sidebar, flattenedSidebar);
|
|
298
|
+
return flattenedSidebar;
|
|
299
|
+
}
|
|
300
|
+
const flattenedSidebars = /* @__PURE__ */ new WeakMap();
|
|
301
|
+
/** Get previous/next pages in the sidebar or the ones from the frontmatter if any. */
|
|
302
|
+
function getPrevNextLinks(sidebar, paginationEnabled, config) {
|
|
303
|
+
const entries = flattenSidebar(sidebar);
|
|
304
|
+
const currentIndex = entries.findIndex((entry) => entry.isCurrent);
|
|
305
|
+
return {
|
|
306
|
+
prev: applyPrevNextLinkConfig(entries[currentIndex - 1], paginationEnabled, config.prev),
|
|
307
|
+
next: applyPrevNextLinkConfig(currentIndex > -1 ? entries[currentIndex + 1] : void 0, paginationEnabled, config.next)
|
|
308
|
+
};
|
|
309
|
+
}
|
|
310
|
+
/** Apply a prev/next link config to a navigation link. */
|
|
311
|
+
function applyPrevNextLinkConfig(link, paginationEnabled, config) {
|
|
312
|
+
if (config === false) return void 0;
|
|
313
|
+
else if (config === true) return link;
|
|
314
|
+
else if (typeof config === "string" && link) return {
|
|
315
|
+
...link,
|
|
316
|
+
label: config
|
|
317
|
+
};
|
|
318
|
+
else if (typeof config === "object") {
|
|
319
|
+
if (link) return {
|
|
320
|
+
...link,
|
|
321
|
+
label: config.label ?? link.label,
|
|
322
|
+
href: config.link ?? link.href,
|
|
323
|
+
attrs: {}
|
|
324
|
+
};
|
|
325
|
+
else if (config.link && config.label) return makeLink({
|
|
326
|
+
href: config.link,
|
|
327
|
+
label: config.label
|
|
328
|
+
});
|
|
329
|
+
}
|
|
330
|
+
return paginationEnabled ? link : void 0;
|
|
331
|
+
}
|
|
332
|
+
/** Get a sidebar badge for a given item. */
|
|
333
|
+
function getSidebarBadge(config, locale, itemLabel) {
|
|
334
|
+
if (!config) return;
|
|
335
|
+
if (typeof config === "string") return {
|
|
336
|
+
variant: "default",
|
|
337
|
+
text: config
|
|
338
|
+
};
|
|
339
|
+
return {
|
|
340
|
+
...config,
|
|
341
|
+
text: getSidebarBadgeText(config.text, locale, itemLabel)
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
/** Get the badge text for a sidebar item. */
|
|
345
|
+
function getSidebarBadgeText(text, locale, itemLabel) {
|
|
346
|
+
if (typeof text === "string") return text;
|
|
347
|
+
const defaultLang = config.defaultLocale?.lang || config.defaultLocale?.locale || BuiltInDefaultLocale.lang;
|
|
348
|
+
const defaultText = text[defaultLang];
|
|
349
|
+
if (!defaultText) throw new AstroError(`The badge text for "${itemLabel}" must have a key for the default language "${defaultLang}".`, "Update the Starlight config to include a badge text for the default language.\nLearn more about sidebar badges internationalization at https://starlight.astro.build/guides/sidebar/#internationalization-with-badges");
|
|
350
|
+
return pickLang(text, localeToLang(locale)) || defaultText;
|
|
351
|
+
}
|
|
352
|
+
//#endregion
|
|
353
|
+
export { flattenSidebar, getPrevNextLinks, getSidebar, getSidebarFromConfig, getSidebarHash };
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
//#region src/utils/path.d.ts
|
|
2
|
+
/** Ensure the passed path starts with a leading slash. */
|
|
3
|
+
declare function ensureLeadingSlash(href: string): string;
|
|
4
|
+
/** Ensure the passed path ends with a trailing slash. */
|
|
5
|
+
declare function ensureTrailingSlash(href: string): string;
|
|
6
|
+
/** Ensure the passed path starts and ends with slashes. */
|
|
7
|
+
declare function ensureLeadingAndTrailingSlashes(href: string): string;
|
|
8
|
+
/** Ensure the passed path does not start with a leading slash. */
|
|
9
|
+
declare function stripLeadingSlash(href: string): string;
|
|
10
|
+
/** Ensure the passed path does not end with a trailing slash. */
|
|
11
|
+
declare function stripTrailingSlash(href: string): string;
|
|
12
|
+
/** Ensure the passed path does not start and end with slashes. */
|
|
13
|
+
declare function stripLeadingAndTrailingSlashes(href: string): string;
|
|
14
|
+
/** Remove the extension from a path. */
|
|
15
|
+
declare function stripHtmlExtension(path: string): string;
|
|
16
|
+
/** Add '.html' extension to a path. */
|
|
17
|
+
declare function ensureHtmlExtension(path: string): string;
|
|
18
|
+
/** Remove the extension from a path. */
|
|
19
|
+
declare function stripExtension(path: string): string;
|
|
20
|
+
//#endregion
|
|
21
|
+
export { ensureHtmlExtension, ensureLeadingAndTrailingSlashes, ensureLeadingSlash, ensureTrailingSlash, stripExtension, stripHtmlExtension, stripLeadingAndTrailingSlashes, stripLeadingSlash, stripTrailingSlash };
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
//#region src/utils/path.ts
|
|
2
|
+
/** Ensure the passed path starts with a leading slash. */
|
|
3
|
+
function ensureLeadingSlash(href) {
|
|
4
|
+
if (href[0] !== "/") href = "/" + href;
|
|
5
|
+
return href;
|
|
6
|
+
}
|
|
7
|
+
/** Ensure the passed path ends with a trailing slash. */
|
|
8
|
+
function ensureTrailingSlash(href) {
|
|
9
|
+
if (href[href.length - 1] !== "/") href += "/";
|
|
10
|
+
return href;
|
|
11
|
+
}
|
|
12
|
+
/** Ensure the passed path starts and ends with slashes. */
|
|
13
|
+
function ensureLeadingAndTrailingSlashes(href) {
|
|
14
|
+
href = ensureLeadingSlash(href);
|
|
15
|
+
href = ensureTrailingSlash(href);
|
|
16
|
+
return href;
|
|
17
|
+
}
|
|
18
|
+
/** Ensure the passed path does not start with a leading slash. */
|
|
19
|
+
function stripLeadingSlash(href) {
|
|
20
|
+
if (href[0] === "/") href = href.slice(1);
|
|
21
|
+
return href;
|
|
22
|
+
}
|
|
23
|
+
/** Ensure the passed path does not end with a trailing slash. */
|
|
24
|
+
function stripTrailingSlash(href) {
|
|
25
|
+
if (href[href.length - 1] === "/") href = href.slice(0, -1);
|
|
26
|
+
return href;
|
|
27
|
+
}
|
|
28
|
+
/** Ensure the passed path does not start and end with slashes. */
|
|
29
|
+
function stripLeadingAndTrailingSlashes(href) {
|
|
30
|
+
href = stripLeadingSlash(href);
|
|
31
|
+
href = stripTrailingSlash(href);
|
|
32
|
+
return href;
|
|
33
|
+
}
|
|
34
|
+
/** Remove the extension from a path. */
|
|
35
|
+
function stripHtmlExtension(path) {
|
|
36
|
+
const pathWithoutTrailingSlash = stripTrailingSlash(path);
|
|
37
|
+
return pathWithoutTrailingSlash.endsWith(".html") ? pathWithoutTrailingSlash.slice(0, -5) : path;
|
|
38
|
+
}
|
|
39
|
+
/** Add '.html' extension to a path. */
|
|
40
|
+
function ensureHtmlExtension(path) {
|
|
41
|
+
path = stripLeadingAndTrailingSlashes(path);
|
|
42
|
+
if (!path.endsWith(".html")) path = path ? path + ".html" : "/index.html";
|
|
43
|
+
return ensureLeadingSlash(path);
|
|
44
|
+
}
|
|
45
|
+
/** Remove the extension from a path. */
|
|
46
|
+
function stripExtension(path) {
|
|
47
|
+
const periodIndex = path.lastIndexOf(".");
|
|
48
|
+
return path.slice(0, periodIndex > -1 ? periodIndex : void 0);
|
|
49
|
+
}
|
|
50
|
+
//#endregion
|
|
51
|
+
export { ensureHtmlExtension, ensureLeadingAndTrailingSlashes, ensureLeadingSlash, ensureTrailingSlash, stripExtension, stripHtmlExtension, stripLeadingAndTrailingSlashes, stripLeadingSlash, stripTrailingSlash };
|