-
-
Notifications
You must be signed in to change notification settings - Fork 418
/
routing.ts
130 lines (118 loc) · 3.97 KB
/
routing.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
import type { GetStaticPathsItem } from 'astro';
import { CollectionEntry, getCollection } from 'astro:content';
import config from 'virtual:starlight/user-config';
import {
LocaleData,
localizedSlug,
slugToLocaleData,
slugToParam,
} from './slugs';
export type StarlightDocsEntry = Omit<CollectionEntry<'docs'>, 'slug'> & {
slug: string;
};
export interface Route extends LocaleData {
entry: StarlightDocsEntry;
entryMeta: LocaleData;
slug: string;
isFallback?: true;
[key: string]: unknown;
}
interface Path extends GetStaticPathsItem {
params: { slug: string | undefined };
props: Route;
}
/**
* Astro is inconsistent in its `index.md` slug generation. In most cases,
* `index` is stripped, but in the root of a collection, we get a slug of `index`.
* We map that to an empty string for consistent behaviour.
*/
const normalizeIndexSlug = (slug: string) => (slug === 'index' ? '' : slug);
/** All entries in the docs content collection. */
const docs: StarlightDocsEntry[] = (await getCollection('docs')).map(
({ slug, ...entry }) => ({ ...entry, slug: normalizeIndexSlug(slug) })
);
function getRoutes(): Route[] {
const routes: Route[] = docs.map((entry) => ({
entry,
slug: entry.slug,
entryMeta: slugToLocaleData(entry.slug),
...slugToLocaleData(entry.slug),
}));
// In multilingual sites, add required fallback routes.
if (config.isMultilingual) {
/** Entries in the docs content collection for the default locale. */
const defaultLocaleDocs = getLocaleDocs(
config.defaultLocale?.locale === 'root'
? undefined
: config.defaultLocale?.locale
);
for (const key in config.locales) {
if (key === config.defaultLocale.locale) continue;
const localeConfig = config.locales[key];
if (!localeConfig) continue;
const locale = key === 'root' ? undefined : key;
const localeDocs = getLocaleDocs(locale);
for (const fallback of defaultLocaleDocs) {
const slug = localizedSlug(fallback.slug, locale);
const doesNotNeedFallback = localeDocs.some((doc) => doc.slug === slug);
if (doesNotNeedFallback) continue;
routes.push({
entry: fallback,
slug,
isFallback: true,
lang: localeConfig.lang || 'en',
locale,
dir: localeConfig.dir,
entryMeta: slugToLocaleData(fallback.slug),
});
}
}
}
// Sort alphabetically by page slug to guarantee order regardless of platform.
return routes.sort((a, b) =>
a.slug < b.slug ? -1 : a.slug > b.slug ? 1 : 0
);
}
export const routes = getRoutes();
function getPaths(): Path[] {
return routes.map((route) => ({
params: { slug: slugToParam(route.slug) },
props: route,
}));
}
export const paths = getPaths();
/**
* Get all routes for a specific locale.
* A locale of `undefined` is treated as the “root” locale, if configured.
*/
export function getLocaleRoutes(locale: string | undefined): Route[] {
return filterByLocale(routes, locale);
}
/**
* Get all entries in the docs content collection for a specific locale.
* A locale of `undefined` is treated as the “root” locale, if configured.
*/
function getLocaleDocs(locale: string | undefined): StarlightDocsEntry[] {
return filterByLocale(docs, locale);
}
/** Filter an array to find items whose slug matches the passed locale. */
function filterByLocale<T extends { slug: string }>(
items: T[],
locale: string | undefined
): T[] {
if (config.locales) {
if (locale && locale in config.locales) {
return items.filter(
(i) => i.slug === locale || i.slug.startsWith(locale + '/')
);
} else if (config.locales.root) {
const langKeys = Object.keys(config.locales).filter((k) => k !== 'root');
const isLangIndex = new RegExp(`^(${langKeys.join('|')})$`);
const isLangDir = new RegExp(`^(${langKeys.join('|')})/`);
return items.filter(
(i) => !isLangIndex.test(i.slug) && !isLangDir.test(i.slug)
);
}
}
return items;
}