@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,16 @@
|
|
|
1
|
+
//#region src/user-components/file-tree-processor.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Process the HTML for a file tree to create the necessary markup for each file and directory
|
|
4
|
+
* including icons.
|
|
5
|
+
* @param html Inner HTML passed to the `<FileTree>` component.
|
|
6
|
+
* @param directoryLabel The localized label for a directory.
|
|
7
|
+
* @returns The processed HTML for the file tree.
|
|
8
|
+
*/
|
|
9
|
+
declare function processFileTree(html: string, directoryLabel: string): string;
|
|
10
|
+
interface Definitions {
|
|
11
|
+
files: Record<string, string>;
|
|
12
|
+
extensions: Record<string, string>;
|
|
13
|
+
partials: Record<string, string>;
|
|
14
|
+
}
|
|
15
|
+
//#endregion
|
|
16
|
+
export { Definitions, processFileTree };
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { definitions } from "./file-tree-icons.js";
|
|
2
|
+
import { Icons } from "../components-internals/Icons.js";
|
|
3
|
+
import { AstroError } from "astro/errors";
|
|
4
|
+
import { htmlToHast } from "satteri";
|
|
5
|
+
import { CONTINUE, SKIP, visit } from "unist-util-visit";
|
|
6
|
+
import { toString } from "hast-util-to-string";
|
|
7
|
+
import { h, s } from "hastscript";
|
|
8
|
+
import { select } from "hast-util-select";
|
|
9
|
+
import { toHtml } from "hast-util-to-html";
|
|
10
|
+
//#region src/user-components/file-tree-processor.ts
|
|
11
|
+
const folderIcon = makeSVGIcon(Icons["seti:folder"]);
|
|
12
|
+
const defaultFileIcon = makeSVGIcon(Icons["seti:default"]);
|
|
13
|
+
/**
|
|
14
|
+
* Process the HTML for a file tree to create the necessary markup for each file and directory
|
|
15
|
+
* including icons.
|
|
16
|
+
* @param html Inner HTML passed to the `<FileTree>` component.
|
|
17
|
+
* @param directoryLabel The localized label for a directory.
|
|
18
|
+
* @returns The processed HTML for the file tree.
|
|
19
|
+
*/
|
|
20
|
+
function processFileTree(html, directoryLabel) {
|
|
21
|
+
const tree = htmlToHast(html, { fragment: true });
|
|
22
|
+
validateFileTree(tree);
|
|
23
|
+
visit(tree, "element", (node) => {
|
|
24
|
+
node.children = node.children.filter((child) => child.type === "comment" || child.type !== "text" || !/^\n+$/.test(child.value));
|
|
25
|
+
if (node.tagName !== "li") return CONTINUE;
|
|
26
|
+
const [firstChild, ...otherChildren] = node.children;
|
|
27
|
+
const comment = [];
|
|
28
|
+
if (firstChild?.type === "text") {
|
|
29
|
+
const [filename, ...fragments] = firstChild.value.split(" ");
|
|
30
|
+
firstChild.value = filename || "";
|
|
31
|
+
if (fragments.join(" ").trim().length > 0) comment.push(fragments.join(" "));
|
|
32
|
+
}
|
|
33
|
+
const subTreeIndex = otherChildren.findIndex((child) => child.type === "element" && child.tagName === "ul");
|
|
34
|
+
const commentNodes = subTreeIndex > -1 ? otherChildren.slice(0, subTreeIndex) : [...otherChildren];
|
|
35
|
+
otherChildren.splice(0, subTreeIndex > -1 ? subTreeIndex : otherChildren.length);
|
|
36
|
+
comment.push(...commentNodes);
|
|
37
|
+
const firstChildTextContent = firstChild ? toString(firstChild) : "";
|
|
38
|
+
const isDirectory = /\/\s*$/.test(firstChildTextContent) || otherChildren.some((child) => child.type === "element" && child.tagName === "ul");
|
|
39
|
+
const isPlaceholder = /^\s*(\.{3}|…)\s*$/.test(firstChildTextContent);
|
|
40
|
+
const isHighlighted = firstChild?.type === "element" && firstChild.tagName === "strong";
|
|
41
|
+
const icon = h("span", isDirectory ? folderIcon : getFileIcon(firstChildTextContent));
|
|
42
|
+
if (isDirectory) icon.children.unshift(h("span", { class: "sr-only" }, directoryLabel));
|
|
43
|
+
node.properties.class = isDirectory ? "directory" : "file";
|
|
44
|
+
if (isPlaceholder) node.properties.class += " empty";
|
|
45
|
+
const treeEntryChildren = [h("span", { class: isHighlighted ? "highlight" : "" }, [isPlaceholder ? null : icon, firstChild])];
|
|
46
|
+
if (comment.length > 0) treeEntryChildren.push(makeText(" "), h("span", { class: "comment" }, ...comment));
|
|
47
|
+
const treeEntry = h("span", { class: "tree-entry" }, ...treeEntryChildren);
|
|
48
|
+
if (isDirectory) {
|
|
49
|
+
const hasContents = otherChildren.length > 0;
|
|
50
|
+
node.children = [h("details", { open: hasContents }, [h("summary", treeEntry), ...hasContents ? otherChildren : [h("ul", h("li", "…"))]])];
|
|
51
|
+
return CONTINUE;
|
|
52
|
+
}
|
|
53
|
+
node.children = [treeEntry, ...otherChildren];
|
|
54
|
+
return SKIP;
|
|
55
|
+
});
|
|
56
|
+
return toHtml(tree);
|
|
57
|
+
}
|
|
58
|
+
/** Make a text node with the pass string as its contents. */
|
|
59
|
+
function makeText(value = "") {
|
|
60
|
+
return {
|
|
61
|
+
type: "text",
|
|
62
|
+
value
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
/** Make a node containing an SVG icon from the passed HTML string. */
|
|
66
|
+
function makeSVGIcon(svgString) {
|
|
67
|
+
return s("svg", {
|
|
68
|
+
width: 16,
|
|
69
|
+
height: 16,
|
|
70
|
+
class: "tree-icon",
|
|
71
|
+
"aria-hidden": "true",
|
|
72
|
+
viewBox: "0 0 24 24"
|
|
73
|
+
}, htmlToHast(svgString, {
|
|
74
|
+
fragment: true,
|
|
75
|
+
space: "svg"
|
|
76
|
+
}).children);
|
|
77
|
+
}
|
|
78
|
+
/** Return the icon for a file based on its file name. */
|
|
79
|
+
function getFileIcon(fileName) {
|
|
80
|
+
const name = getFileIconName(fileName);
|
|
81
|
+
if (!name) return defaultFileIcon;
|
|
82
|
+
if (name in Icons) {
|
|
83
|
+
const path = Icons[name];
|
|
84
|
+
return makeSVGIcon(path);
|
|
85
|
+
}
|
|
86
|
+
return defaultFileIcon;
|
|
87
|
+
}
|
|
88
|
+
/** Return the icon name for a file based on its file name. */
|
|
89
|
+
function getFileIconName(fileName) {
|
|
90
|
+
let icon = definitions.files[fileName];
|
|
91
|
+
if (icon) return icon;
|
|
92
|
+
icon = getFileIconTypeFromExtension(fileName);
|
|
93
|
+
if (icon) return icon;
|
|
94
|
+
for (const [partial, partialIcon] of Object.entries(definitions.partials)) if (fileName.includes(partial)) return partialIcon;
|
|
95
|
+
return icon;
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Get an icon from a file name based on its extension.
|
|
99
|
+
* Note that an extension in Seti is everything after a dot, so `README.md` would be `.md` and
|
|
100
|
+
* `name.with.dots` will try to look for an icon for `.with.dots` and then `.dots` if the first one
|
|
101
|
+
* is not found.
|
|
102
|
+
*/
|
|
103
|
+
function getFileIconTypeFromExtension(fileName) {
|
|
104
|
+
const firstDotIndex = fileName.indexOf(".");
|
|
105
|
+
if (firstDotIndex === -1) return;
|
|
106
|
+
let extension = fileName.slice(firstDotIndex);
|
|
107
|
+
while (extension !== "") {
|
|
108
|
+
const icon = definitions.extensions[extension];
|
|
109
|
+
if (icon) return icon;
|
|
110
|
+
const nextDotIndex = extension.indexOf(".", 1);
|
|
111
|
+
if (nextDotIndex === -1) return;
|
|
112
|
+
extension = extension.slice(nextDotIndex);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
/** Validate that the user provided HTML for a file tree is valid. */
|
|
116
|
+
function validateFileTree(tree) {
|
|
117
|
+
const rootElements = tree.children.filter(isElementNode);
|
|
118
|
+
const [rootElement] = rootElements;
|
|
119
|
+
if (rootElements.length === 0) throwFileTreeValidationError("The `<FileTree>` component expects its content to be a single unordered list but found no child elements.");
|
|
120
|
+
if (rootElements.length !== 1) throwFileTreeValidationError(`The \`<FileTree>\` component expects its content to be a single unordered list but found multiple child elements: ${rootElements.map((element) => `\`<${element.tagName}>\``).join(" - ")}.`);
|
|
121
|
+
if (!rootElement || rootElement.tagName !== "ul") throwFileTreeValidationError(`The \`<FileTree>\` component expects its content to be an unordered list but found the following element: \`<${rootElement?.tagName}>\`.`);
|
|
122
|
+
if (!select("li", rootElement)) throwFileTreeValidationError("The `<FileTree>` component expects its content to be an unordered list with at least one list item.");
|
|
123
|
+
}
|
|
124
|
+
function isElementNode(node) {
|
|
125
|
+
return node.type === "element";
|
|
126
|
+
}
|
|
127
|
+
/** Throw a validation error for a file tree linking to the documentation. */
|
|
128
|
+
function throwFileTreeValidationError(message) {
|
|
129
|
+
throw new AstroError(message, "To learn more about the `<FileTree>` component, see https://starlight.astro.build/components/file-tree/");
|
|
130
|
+
}
|
|
131
|
+
//#endregion
|
|
132
|
+
export { processFileTree };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
//#region src/user-components/steps-processor.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* Process steps children: validates the HTML and adds `role="list"` to the ordered list.
|
|
4
|
+
* @param html Inner HTML passed to the `<Steps>` component.
|
|
5
|
+
*/
|
|
6
|
+
declare const processSteps: (html: string | undefined) => {
|
|
7
|
+
html: string;
|
|
8
|
+
};
|
|
9
|
+
//#endregion
|
|
10
|
+
export { processSteps };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { AstroError } from "astro/errors";
|
|
2
|
+
import { htmlToHast } from "satteri";
|
|
3
|
+
import { toHtml } from "hast-util-to-html";
|
|
4
|
+
import { format } from "hast-util-format";
|
|
5
|
+
//#region src/user-components/steps-processor.ts
|
|
6
|
+
const prettyPrintHtml = (tree) => {
|
|
7
|
+
format(tree);
|
|
8
|
+
return toHtml(tree);
|
|
9
|
+
};
|
|
10
|
+
/**
|
|
11
|
+
* Process steps children: validates the HTML and adds `role="list"` to the ordered list.
|
|
12
|
+
* @param html Inner HTML passed to the `<Steps>` component.
|
|
13
|
+
*/
|
|
14
|
+
const processSteps = (html) => {
|
|
15
|
+
const tree = htmlToHast(html ?? "", { fragment: true });
|
|
16
|
+
const rootElements = tree.children.filter((item) => item.type === "element" && item.tagName !== "script");
|
|
17
|
+
const [rootElement] = rootElements;
|
|
18
|
+
if (!rootElement) throw new StepsError("The `<Steps>` component expects its content to be a single ordered list (`<ol>`) but found no child elements.");
|
|
19
|
+
else if (rootElements.length > 1) throw new StepsError("The `<Steps>` component expects its content to be a single ordered list (`<ol>`) but found multiple child elements: " + rootElements.map((element) => `\`<${element.tagName}>\``).join(", ") + ".", tree);
|
|
20
|
+
else if (rootElement.tagName !== "ol") throw new StepsError(`The \`<Steps>\` component expects its content to be a single ordered list (\`<ol>\`) but found the following element: \`<${rootElement.tagName}>\`.`, tree);
|
|
21
|
+
rootElement.properties.role = "list";
|
|
22
|
+
if (!Array.isArray(rootElement.properties.className)) rootElement.properties.className = ["sl-steps"];
|
|
23
|
+
else rootElement.properties.className.push("sl-steps");
|
|
24
|
+
if (typeof rootElement.properties.start === "number") {
|
|
25
|
+
const styles = [`--sl-steps-start: ${rootElement.properties.start - 1}`];
|
|
26
|
+
if (rootElement.properties.style) styles.push(String(rootElement.properties.style));
|
|
27
|
+
rootElement.properties.style = styles.join(";");
|
|
28
|
+
}
|
|
29
|
+
return { html: toHtml(tree) };
|
|
30
|
+
};
|
|
31
|
+
var StepsError = class extends AstroError {
|
|
32
|
+
constructor(message, tree) {
|
|
33
|
+
let hint = "To learn more about the `<Steps>` component, see https://starlight.astro.build/components/steps/";
|
|
34
|
+
if (tree) hint += "\n\nFull HTML passed to `<Steps>`:\n" + prettyPrintHtml(tree);
|
|
35
|
+
super(message, hint);
|
|
36
|
+
}
|
|
37
|
+
};
|
|
38
|
+
//#endregion
|
|
39
|
+
export { processSteps };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { StarlightIcon } from "../components-internals/Icons.js";
|
|
2
|
+
//#region src/user-components/tabs-processor.d.ts
|
|
3
|
+
interface Panel {
|
|
4
|
+
panelId: string;
|
|
5
|
+
tabId: string;
|
|
6
|
+
label: string;
|
|
7
|
+
icon?: StarlightIcon;
|
|
8
|
+
}
|
|
9
|
+
declare const TabItemTagname = "starlight-tab-item";
|
|
10
|
+
/**
|
|
11
|
+
* Process tab panel items to extract data for the tab links and format
|
|
12
|
+
* each tab panel correctly.
|
|
13
|
+
* @param html Inner HTML passed to the `<Tabs>` component.
|
|
14
|
+
* @param index The index of the `<Tabs>` component on the page.
|
|
15
|
+
*/
|
|
16
|
+
declare const processPanels: (html: string, index: number) => {
|
|
17
|
+
/** Data for each tab panel. */
|
|
18
|
+
panels: Panel[];
|
|
19
|
+
/** Processed HTML for the tab panels. */
|
|
20
|
+
html: string;
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { TabItemTagname, processPanels };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { htmlToHast } from "satteri";
|
|
2
|
+
import { CONTINUE, SKIP, visit } from "unist-util-visit";
|
|
3
|
+
import { select } from "hast-util-select";
|
|
4
|
+
import { toHtml } from "hast-util-to-html";
|
|
5
|
+
//#region src/user-components/tabs-processor.ts
|
|
6
|
+
const TabItemTagname = "starlight-tab-item";
|
|
7
|
+
const focusableElementSelectors = [
|
|
8
|
+
"input:not([disabled]):not([type=hidden])",
|
|
9
|
+
"select:not([disabled])",
|
|
10
|
+
"textarea:not([disabled])",
|
|
11
|
+
"button:not([disabled])",
|
|
12
|
+
"a[href]",
|
|
13
|
+
"area[href]",
|
|
14
|
+
"summary",
|
|
15
|
+
"iframe",
|
|
16
|
+
"object",
|
|
17
|
+
"embed",
|
|
18
|
+
"audio[controls]",
|
|
19
|
+
"video[controls]",
|
|
20
|
+
"[contenteditable]",
|
|
21
|
+
"[tabindex]:not([disabled])"
|
|
22
|
+
].map((selector) => `${selector}:not([hidden]):not([tabindex="-1"])`).join(",");
|
|
23
|
+
/**
|
|
24
|
+
* Process tab panel items to extract data for the tab links and format
|
|
25
|
+
* each tab panel correctly.
|
|
26
|
+
* @param html Inner HTML passed to the `<Tabs>` component.
|
|
27
|
+
* @param index The index of the `<Tabs>` component on the page.
|
|
28
|
+
*/
|
|
29
|
+
const processPanels = (html, index) => {
|
|
30
|
+
const tree = htmlToHast(html, { fragment: true });
|
|
31
|
+
const panels = [];
|
|
32
|
+
let isFirst = true;
|
|
33
|
+
let count = 0;
|
|
34
|
+
const getIDs = () => {
|
|
35
|
+
const id = count++;
|
|
36
|
+
return {
|
|
37
|
+
panelId: `tab-panel-${index}-${id}`,
|
|
38
|
+
tabId: `tab-${index}-${id}`
|
|
39
|
+
};
|
|
40
|
+
};
|
|
41
|
+
visit(tree, "element", (node) => {
|
|
42
|
+
if (node.tagName !== "starlight-tab-item" || !node.properties) return CONTINUE;
|
|
43
|
+
const { dataLabel, dataIcon } = node.properties;
|
|
44
|
+
const ids = getIDs();
|
|
45
|
+
const panel = {
|
|
46
|
+
...ids,
|
|
47
|
+
label: String(dataLabel)
|
|
48
|
+
};
|
|
49
|
+
if (dataIcon) panel.icon = String(dataIcon);
|
|
50
|
+
panels.push(panel);
|
|
51
|
+
delete node.properties.dataLabel;
|
|
52
|
+
delete node.properties.dataIcon;
|
|
53
|
+
node.tagName = "div";
|
|
54
|
+
node.properties.id = ids.panelId;
|
|
55
|
+
node.properties["aria-labelledby"] = ids.tabId;
|
|
56
|
+
node.properties.role = "tabpanel";
|
|
57
|
+
if (!select(focusableElementSelectors, node)) node.properties.tabindex = 0;
|
|
58
|
+
if (isFirst) isFirst = false;
|
|
59
|
+
else node.properties.hidden = true;
|
|
60
|
+
return SKIP;
|
|
61
|
+
});
|
|
62
|
+
return {
|
|
63
|
+
/** Data for each tab panel. */
|
|
64
|
+
panels,
|
|
65
|
+
/** Processed HTML for the tab panels. */
|
|
66
|
+
html: toHtml(tree)
|
|
67
|
+
};
|
|
68
|
+
};
|
|
69
|
+
//#endregion
|
|
70
|
+
export { TabItemTagname, processPanels };
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
//#region src/utils/base.d.ts
|
|
2
|
+
/** Get the a root-relative URL path with the site’s `base` prefixed. */
|
|
3
|
+
declare function pathWithBase(path: string): string;
|
|
4
|
+
/** Get the a root-relative file URL path with the site’s `base` prefixed. */
|
|
5
|
+
declare function fileWithBase(path: string): string;
|
|
6
|
+
//#endregion
|
|
7
|
+
export { fileWithBase, pathWithBase };
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { stripLeadingSlash, stripTrailingSlash } from "./path.js";
|
|
2
|
+
//#region src/utils/base.ts
|
|
3
|
+
const base = stripTrailingSlash(import.meta.env.BASE_URL);
|
|
4
|
+
/** Get the a root-relative URL path with the site’s `base` prefixed. */
|
|
5
|
+
function pathWithBase(path) {
|
|
6
|
+
path = stripLeadingSlash(path);
|
|
7
|
+
return path ? base + "/" + path : base + "/";
|
|
8
|
+
}
|
|
9
|
+
/** Get the a root-relative file URL path with the site’s `base` prefixed. */
|
|
10
|
+
function fileWithBase(path) {
|
|
11
|
+
path = stripLeadingSlash(path);
|
|
12
|
+
return path ? base + "/" + path : base;
|
|
13
|
+
}
|
|
14
|
+
//#endregion
|
|
15
|
+
export { fileWithBase, pathWithBase };
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { AstroConfig } from "astro";
|
|
2
|
+
//#region src/utils/canonical.d.ts
|
|
3
|
+
interface FormatCanonicalOptions {
|
|
4
|
+
format: AstroConfig['build']['format'];
|
|
5
|
+
trailingSlash: AstroConfig['trailingSlash'];
|
|
6
|
+
}
|
|
7
|
+
/** Format a canonical link based on the project config. */
|
|
8
|
+
declare function formatCanonical(href: string, opts: FormatCanonicalOptions): string;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { FormatCanonicalOptions, formatCanonical };
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { ensureTrailingSlash, stripTrailingSlash } from "./path.js";
|
|
2
|
+
//#region src/utils/canonical.ts
|
|
3
|
+
const canonicalTrailingSlashStrategies = {
|
|
4
|
+
always: ensureTrailingSlash,
|
|
5
|
+
never: stripTrailingSlash,
|
|
6
|
+
ignore: ensureTrailingSlash
|
|
7
|
+
};
|
|
8
|
+
/** Format a canonical link based on the project config. */
|
|
9
|
+
function formatCanonical(href, opts) {
|
|
10
|
+
if (opts.format === "file") return href;
|
|
11
|
+
return canonicalTrailingSlashStrategies[opts.trailingSlash](href);
|
|
12
|
+
}
|
|
13
|
+
//#endregion
|
|
14
|
+
export { formatCanonical };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { StarlightCollection } from "./collection.js";
|
|
2
|
+
//#region src/utils/collection-fs.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* @see {@link file://./collection.ts} for more context about this file.
|
|
5
|
+
*
|
|
6
|
+
* Below are various functions to easily get paths to collections used in Starlight that rely on
|
|
7
|
+
* Node.js builtins. They exist in a separate file from {@link file://./collection.ts} to avoid
|
|
8
|
+
* potentially importing Node.js builtins in the final bundle.
|
|
9
|
+
*/
|
|
10
|
+
declare function resolveCollectionPath(collection: StarlightCollection, srcDir: URL): string;
|
|
11
|
+
declare function getCollectionPosixPath(collection: StarlightCollection, srcDir: URL): string;
|
|
12
|
+
//#endregion
|
|
13
|
+
export { getCollectionPosixPath, resolveCollectionPath };
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { getCollectionUrl } from "./collection.js";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
//#region src/utils/collection-fs.ts
|
|
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
|
+
function resolveCollectionPath(collection, srcDir) {
|
|
13
|
+
return resolve(fileURLToPath(srcDir), `content/${collection}`);
|
|
14
|
+
}
|
|
15
|
+
function getCollectionPosixPath(collection, srcDir) {
|
|
16
|
+
return fileURLToPath(getCollectionUrl(collection, srcDir), { windows: false });
|
|
17
|
+
}
|
|
18
|
+
//#endregion
|
|
19
|
+
export { getCollectionPosixPath, resolveCollectionPath };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
//#region src/utils/collection.d.ts
|
|
2
|
+
type StarlightCollection = 'docs' | 'i18n';
|
|
3
3
|
/**
|
|
4
4
|
* We still rely on the content collection folder structure to be fixed for now:
|
|
5
5
|
*
|
|
@@ -17,21 +17,10 @@ export type StarlightCollection = 'docs' | 'i18n';
|
|
|
17
17
|
* hardcode them throughout the codebase. When user-defined content folder locations are supported,
|
|
18
18
|
* these helper functions should be updated to reflect that in one place.
|
|
19
19
|
*/
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
{ root, srcDir }: { root: URL | string; srcDir: URL | string }
|
|
28
|
-
) {
|
|
29
|
-
return (
|
|
30
|
-
(typeof srcDir === 'string' ? srcDir : srcDir.pathname).replace(
|
|
31
|
-
typeof root === 'string' ? root : root.pathname,
|
|
32
|
-
''
|
|
33
|
-
) +
|
|
34
|
-
'content/' +
|
|
35
|
-
collection
|
|
36
|
-
);
|
|
37
|
-
}
|
|
20
|
+
declare function getCollectionUrl(collection: StarlightCollection, srcDir: URL): URL;
|
|
21
|
+
declare function getCollectionPathFromRoot(collection: StarlightCollection, { root, srcDir }: {
|
|
22
|
+
root: URL | string;
|
|
23
|
+
srcDir: URL | string;
|
|
24
|
+
}): string;
|
|
25
|
+
//#endregion
|
|
26
|
+
export { StarlightCollection, getCollectionPathFromRoot, getCollectionUrl };
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
//#region src/utils/collection.ts
|
|
2
|
+
/**
|
|
3
|
+
* We still rely on the content collection folder structure to be fixed for now:
|
|
4
|
+
*
|
|
5
|
+
* - At build time, if the feature is enabled, we get all the last commit dates for each file in
|
|
6
|
+
* the docs folder ahead of time. In the current approach, we cannot know at this time the
|
|
7
|
+
* user-defined content folder path in the integration context as this would only be available
|
|
8
|
+
* from the loader. A potential solution could be to do that from a custom loader re-implementing
|
|
9
|
+
* the glob loader or built on top of it. Although, we don't have access to the Starlight
|
|
10
|
+
* configuration from the loader to even know we should do that.
|
|
11
|
+
* - Remark plugins get passed down an absolute path to a content file and we need to figure out
|
|
12
|
+
* the language from that path. Without knowing the content folder path, we cannot reliably do
|
|
13
|
+
* so.
|
|
14
|
+
*
|
|
15
|
+
* Below are various functions to easily get paths to these collections and avoid having to
|
|
16
|
+
* hardcode them throughout the codebase. When user-defined content folder locations are supported,
|
|
17
|
+
* these helper functions should be updated to reflect that in one place.
|
|
18
|
+
*/
|
|
19
|
+
function getCollectionUrl(collection, srcDir) {
|
|
20
|
+
return new URL(`content/${collection}/`, srcDir);
|
|
21
|
+
}
|
|
22
|
+
function getCollectionPathFromRoot(collection, { root, srcDir }) {
|
|
23
|
+
return (typeof srcDir === "string" ? srcDir : srcDir.pathname).replace(typeof root === "string" ? root : root.pathname, "") + "content/" + collection;
|
|
24
|
+
}
|
|
25
|
+
//#endregion
|
|
26
|
+
export { getCollectionPathFromRoot, getCollectionUrl };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { AstroConfig } from "astro";
|
|
2
|
+
//#region src/utils/createPathFormatter.d.ts
|
|
3
|
+
interface FormatPathOptions {
|
|
4
|
+
format?: AstroConfig['build']['format'];
|
|
5
|
+
trailingSlash?: AstroConfig['trailingSlash'];
|
|
6
|
+
}
|
|
7
|
+
declare function createPathFormatter(opts: FormatPathOptions): (href: string) => string;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { createPathFormatter };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { ensureHtmlExtension, ensureTrailingSlash, stripHtmlExtension, stripTrailingSlash } from "./path.js";
|
|
2
|
+
import { fileWithBase, pathWithBase } from "./base.js";
|
|
3
|
+
//#region src/utils/createPathFormatter.ts
|
|
4
|
+
const defaultFormatStrategy = {
|
|
5
|
+
addBase: pathWithBase,
|
|
6
|
+
handleExtension: (href) => stripHtmlExtension(href)
|
|
7
|
+
};
|
|
8
|
+
const formatStrategies = {
|
|
9
|
+
file: {
|
|
10
|
+
addBase: fileWithBase,
|
|
11
|
+
handleExtension: (href) => ensureHtmlExtension(href)
|
|
12
|
+
},
|
|
13
|
+
directory: defaultFormatStrategy,
|
|
14
|
+
preserve: defaultFormatStrategy
|
|
15
|
+
};
|
|
16
|
+
const trailingSlashStrategies = {
|
|
17
|
+
always: ensureTrailingSlash,
|
|
18
|
+
never: stripTrailingSlash,
|
|
19
|
+
ignore: (href) => href
|
|
20
|
+
};
|
|
21
|
+
/** Format a path based on the project config. */
|
|
22
|
+
function formatPath(href, { format = "directory", trailingSlash = "ignore" }) {
|
|
23
|
+
const formatStrategy = formatStrategies[format];
|
|
24
|
+
const trailingSlashStrategy = trailingSlashStrategies[trailingSlash];
|
|
25
|
+
href = formatStrategy.handleExtension(href);
|
|
26
|
+
href = formatStrategy.addBase(href);
|
|
27
|
+
if (format === "file") return href;
|
|
28
|
+
href = href === "/" ? href : trailingSlashStrategy(href);
|
|
29
|
+
return href;
|
|
30
|
+
}
|
|
31
|
+
function createPathFormatter(opts) {
|
|
32
|
+
return (href) => formatPath(href, opts);
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { createPathFormatter };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { StarlightConfig } from "./user-config.js";
|
|
2
|
+
import { i18nSchemaOutput } from "../schemas/i18n.js";
|
|
3
|
+
import _default from "../translations/index.js";
|
|
4
|
+
import { UserI18nKeys, UserI18nSchema } from "./translations.js";
|
|
5
|
+
import { ExistsFunction, TFunction } from "i18next";
|
|
6
|
+
//#region src/utils/createTranslationSystem.d.ts
|
|
7
|
+
/**
|
|
8
|
+
* The namespace for i18next resources used by Starlight.
|
|
9
|
+
* All translations handled by Starlight are stored in the same namespace and Starlight always use
|
|
10
|
+
* a new instance of i18next configured for this namespace.
|
|
11
|
+
*/
|
|
12
|
+
declare const i18nextNamespace: "starlight";
|
|
13
|
+
type I18nextNamespace = typeof i18nextNamespace;
|
|
14
|
+
declare function createTranslationSystem<T extends i18nSchemaOutput>(config: Pick<StarlightConfig, 'defaultLocale' | 'locales'>, userTranslations: Record<string, T>, pluginTranslations?: Record<string, T>): Promise<(lang: string | undefined) => I18nT>;
|
|
15
|
+
type BuiltInStrings = (typeof _default)['en'];
|
|
16
|
+
type I18nKeys = keyof BuiltInStrings | UserI18nKeys | keyof StarlightApp.I18n;
|
|
17
|
+
type I18nT = TFunction<'starlight', undefined> & {
|
|
18
|
+
all: () => UserI18nSchema;
|
|
19
|
+
exists: ExistsFunction;
|
|
20
|
+
dir: (lang?: string) => 'ltr' | 'rtl';
|
|
21
|
+
};
|
|
22
|
+
//#endregion
|
|
23
|
+
export { I18nKeys, I18nT, I18nextNamespace, createTranslationSystem };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { BuiltInDefaultLocale } from "./i18n.js";
|
|
2
|
+
import translations_default from "../translations/index.js";
|
|
3
|
+
import i18next from "i18next";
|
|
4
|
+
//#region src/utils/createTranslationSystem.ts
|
|
5
|
+
/**
|
|
6
|
+
* The namespace for i18next resources used by Starlight.
|
|
7
|
+
* All translations handled by Starlight are stored in the same namespace and Starlight always use
|
|
8
|
+
* a new instance of i18next configured for this namespace.
|
|
9
|
+
*/
|
|
10
|
+
const i18nextNamespace = "starlight";
|
|
11
|
+
async function createTranslationSystem(config, userTranslations, pluginTranslations = {}) {
|
|
12
|
+
const defaultLocale = config.defaultLocale.lang || config.defaultLocale?.locale || BuiltInDefaultLocale.lang;
|
|
13
|
+
const translations = { [defaultLocale]: buildResources(translations_default[defaultLocale] || translations_default[stripLangRegion(defaultLocale)], pluginTranslations[defaultLocale], userTranslations[defaultLocale]) };
|
|
14
|
+
if (config.locales) for (const locale in config.locales) {
|
|
15
|
+
const lang = localeToLang(locale, config.locales, config.defaultLocale);
|
|
16
|
+
translations[lang] = buildResources(translations_default[lang] || translations_default[stripLangRegion(lang)], pluginTranslations[lang], userTranslations[lang]);
|
|
17
|
+
}
|
|
18
|
+
const i18n = i18next.createInstance();
|
|
19
|
+
await i18n.init({
|
|
20
|
+
resources: translations,
|
|
21
|
+
fallbackLng: config.defaultLocale.lang || config.defaultLocale?.locale || BuiltInDefaultLocale.lang
|
|
22
|
+
});
|
|
23
|
+
/**
|
|
24
|
+
* Generate a utility function that returns UI strings for the given language.
|
|
25
|
+
*
|
|
26
|
+
* Also includes a few utility methods:
|
|
27
|
+
* - `all()` method for getting the entire dictionary.
|
|
28
|
+
* - `exists()` method for checking if a key exists in the dictionary.
|
|
29
|
+
* - `dir()` method for getting the text direction of the locale.
|
|
30
|
+
*
|
|
31
|
+
* @param {string | undefined} [lang]
|
|
32
|
+
* @example
|
|
33
|
+
* const t = useTranslations('en');
|
|
34
|
+
* const label = t('search.label');
|
|
35
|
+
* // => 'Search'
|
|
36
|
+
* const dictionary = t.all();
|
|
37
|
+
* // => { 'skipLink.label': 'Skip to content', 'search.label': 'Search', ... }
|
|
38
|
+
* const exists = t.exists('search.label');
|
|
39
|
+
* // => true
|
|
40
|
+
* const dir = t.dir();
|
|
41
|
+
* // => 'ltr'
|
|
42
|
+
*/
|
|
43
|
+
return (lang) => {
|
|
44
|
+
lang ??= config.defaultLocale?.lang || BuiltInDefaultLocale.lang;
|
|
45
|
+
const t = i18n.getFixedT(lang, i18nextNamespace);
|
|
46
|
+
t.all = () => i18n.getResourceBundle(lang, i18nextNamespace);
|
|
47
|
+
t.exists = ((key, options) => i18n.exists(key, {
|
|
48
|
+
lng: lang,
|
|
49
|
+
ns: i18nextNamespace,
|
|
50
|
+
...options
|
|
51
|
+
}));
|
|
52
|
+
t.dir = (dirLang = lang) => i18n.dir(dirLang);
|
|
53
|
+
return t;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Strips the region subtag from a BCP-47 lang string.
|
|
58
|
+
* @param {string} [lang]
|
|
59
|
+
* @example
|
|
60
|
+
* const lang = stripLangRegion('en-GB'); // => 'en'
|
|
61
|
+
*/
|
|
62
|
+
function stripLangRegion(lang) {
|
|
63
|
+
return lang.replace(/-[a-zA-Z]{2}/, "");
|
|
64
|
+
}
|
|
65
|
+
/**
|
|
66
|
+
* Get the BCP-47 language tag for the given locale.
|
|
67
|
+
* @param locale Locale string or `undefined` for the root locale.
|
|
68
|
+
*/
|
|
69
|
+
function localeToLang(locale, locales, defaultLocale) {
|
|
70
|
+
const lang = locale ? locales?.[locale]?.lang : locales?.root?.lang;
|
|
71
|
+
const defaultLang = defaultLocale?.lang || defaultLocale?.locale;
|
|
72
|
+
return lang || defaultLang || BuiltInDefaultLocale.lang;
|
|
73
|
+
}
|
|
74
|
+
/** Build an i18next resources dictionary by layering preferred translation sources. */
|
|
75
|
+
function buildResources(...dictionaries) {
|
|
76
|
+
const dictionary = {};
|
|
77
|
+
for (const dict of dictionaries) for (const key in dict) {
|
|
78
|
+
const value = dict[key];
|
|
79
|
+
if (value) dictionary[key] = value;
|
|
80
|
+
}
|
|
81
|
+
return { [i18nextNamespace]: dictionary };
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { createTranslationSystem };
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { z } from "astro/zod";
|
|
2
|
+
//#region src/utils/error-map.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Parse data with a Zod schema and throw a nicely formatted error if it is invalid.
|
|
5
|
+
*
|
|
6
|
+
* @param schema The Zod schema to use to parse the input.
|
|
7
|
+
* @param input Input data that should match the schema.
|
|
8
|
+
* @param message Error message preamble to use if the input fails to parse.
|
|
9
|
+
* @returns Validated data parsed by Zod.
|
|
10
|
+
*/
|
|
11
|
+
declare function parseWithFriendlyErrors<T extends z.ZodType>(schema: T, input: z.input<T>, message: string): z.output<T>;
|
|
12
|
+
/**
|
|
13
|
+
* Asynchronously parse data with a Zod schema that contains asynchronous refinements or transforms
|
|
14
|
+
* and throw a nicely formatted error if it is invalid.
|
|
15
|
+
*
|
|
16
|
+
* @param schema The Zod schema to use to parse the input.
|
|
17
|
+
* @param input Input data that should match the schema.
|
|
18
|
+
* @param message Error message preamble to use if the input fails to parse.
|
|
19
|
+
* @returns Validated data parsed by Zod.
|
|
20
|
+
*/
|
|
21
|
+
declare function parseAsyncWithFriendlyErrors<T extends z.ZodType>(schema: T, input: z.input<T>, message: string): Promise<z.output<T>>;
|
|
22
|
+
//#endregion
|
|
23
|
+
export { parseAsyncWithFriendlyErrors, parseWithFriendlyErrors };
|