starlight-versions 0.1.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/LICENSE +21 -0
- package/README.md +27 -0
- package/components/VersionBanner.astro +38 -0
- package/components/VersionNotice.astro +48 -0
- package/components/VersionPagination.astro +34 -0
- package/components/VersionSearch.astro +486 -0
- package/components/VersionSelect.astro +112 -0
- package/components/VersionSidebar.astro +15 -0
- package/env.d.ts +10 -0
- package/index.ts +70 -0
- package/libs/config.ts +34 -0
- package/libs/fs.ts +67 -0
- package/libs/markdown.ts +246 -0
- package/libs/path.ts +49 -0
- package/libs/plugin.ts +36 -0
- package/libs/starlight.ts +88 -0
- package/libs/versions.ts +355 -0
- package/libs/vite.ts +21 -0
- package/overrides/Banner.astro +9 -0
- package/overrides/PageTitle.astro +9 -0
- package/overrides/Pagination.astro +7 -0
- package/overrides/Search.astro +7 -0
- package/overrides/Sidebar.astro +7 -0
- package/overrides/ThemeSelect.astro +9 -0
- package/package.json +71 -0
- package/schema.ts +13 -0
- package/virtual.d.ts +23 -0
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import path from 'node:path'
|
|
2
|
+
import url from 'node:url'
|
|
3
|
+
|
|
4
|
+
import type { Props } from '@astrojs/starlight/props'
|
|
5
|
+
import type { docsSchema } from '@astrojs/starlight/schema'
|
|
6
|
+
import type { StarlightPlugin } from '@astrojs/starlight/types'
|
|
7
|
+
import type { z } from 'astro/zod'
|
|
8
|
+
import yaml from 'yaml'
|
|
9
|
+
|
|
10
|
+
import { isAbsoluteLink, slugifyPath } from './path'
|
|
11
|
+
|
|
12
|
+
export function parseFrontmatter(frontmatter: string) {
|
|
13
|
+
return yaml.parse(frontmatter) as StarlightFrontmatter
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function getFrontmatterNodeValue(frontmatter: StarlightFrontmatter) {
|
|
17
|
+
return yaml.stringify(frontmatter).trim()
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function getDocSlug(docsDir: URL, doc: URL) {
|
|
21
|
+
const docPath = path.relative(url.fileURLToPath(docsDir), url.fileURLToPath(doc))
|
|
22
|
+
const slug = slugifyPath(docPath)
|
|
23
|
+
|
|
24
|
+
return slug === 'index' ? '/' : slug.replace(/\/index$/, '')
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export function getDocLocale(slug: string, starlightConfig: StarlightUserConfig): string | undefined {
|
|
28
|
+
const locales = Object.keys(starlightConfig.locales ?? {})
|
|
29
|
+
|
|
30
|
+
if (locales.length === 0) return undefined
|
|
31
|
+
|
|
32
|
+
const localeSegment = slug.split('/')[0]
|
|
33
|
+
|
|
34
|
+
if (!localeSegment) return undefined
|
|
35
|
+
|
|
36
|
+
return locales.find((locale) => locale === localeSegment)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export function addPrefixToSidebarConfig(
|
|
40
|
+
prefix: string,
|
|
41
|
+
sidebar: NonNullable<StarlightSidebarUserConfig>,
|
|
42
|
+
): NonNullable<StarlightSidebarUserConfig> {
|
|
43
|
+
return sidebar.map((item) => {
|
|
44
|
+
if ('items' in item) {
|
|
45
|
+
return {
|
|
46
|
+
...item,
|
|
47
|
+
items: addPrefixToSidebarConfig(prefix, item.items),
|
|
48
|
+
}
|
|
49
|
+
} else if ('autogenerate' in item) {
|
|
50
|
+
return {
|
|
51
|
+
...item,
|
|
52
|
+
autogenerate: {
|
|
53
|
+
...item.autogenerate,
|
|
54
|
+
directory: path.posix.join(prefix, item.autogenerate.directory),
|
|
55
|
+
},
|
|
56
|
+
}
|
|
57
|
+
} else if (isAbsoluteLink(item.link)) {
|
|
58
|
+
return item
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
const segments = item.link.split('/')
|
|
62
|
+
segments.splice(1, 0, prefix)
|
|
63
|
+
|
|
64
|
+
return {
|
|
65
|
+
...item,
|
|
66
|
+
link: segments.join('/'),
|
|
67
|
+
}
|
|
68
|
+
})
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
type StarlightFrontmatter = z.input<ReturnType<ReturnType<typeof docsSchema>>> & {
|
|
72
|
+
slug?: string
|
|
73
|
+
hero?: StarlightFrontmatteHero
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// Just to simplify type checking when updating the frontmatter,
|
|
77
|
+
interface StarlightFrontmatteHero {
|
|
78
|
+
image?: {
|
|
79
|
+
file?: string
|
|
80
|
+
dark?: string
|
|
81
|
+
light?: string
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export type StarlightUserConfig = Parameters<StarlightPlugin['hooks']['setup']>['0']['config']
|
|
86
|
+
export type StarlightSidebarUserConfig = StarlightUserConfig['sidebar']
|
|
87
|
+
|
|
88
|
+
export type StarlightSidebar = Props['sidebar']
|
package/libs/versions.ts
ADDED
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import type { StarlightConfig } from '@astrojs/starlight/types'
|
|
2
|
+
import type { AstroIntegrationLogger } from 'astro'
|
|
3
|
+
import { z } from 'astro/zod'
|
|
4
|
+
|
|
5
|
+
import type { StarlightVersionsConfig } from '..'
|
|
6
|
+
import type { DocsVersionsConfig } from '../schema'
|
|
7
|
+
|
|
8
|
+
import { copyDirectory, copyFile, ensureDirectory, listDirectory, readJSONFile, writeJSONFile } from './fs'
|
|
9
|
+
import { transformMarkdown } from './markdown'
|
|
10
|
+
import { ensureTrailingSlash, getExtension, stripExtension, stripLeadingSlash, stripTrailingSlash } from './path'
|
|
11
|
+
import { throwPluginError } from './plugin'
|
|
12
|
+
import {
|
|
13
|
+
getDocSlug,
|
|
14
|
+
type StarlightSidebarUserConfig,
|
|
15
|
+
type StarlightUserConfig,
|
|
16
|
+
addPrefixToSidebarConfig,
|
|
17
|
+
type StarlightSidebar,
|
|
18
|
+
getDocLocale,
|
|
19
|
+
} from './starlight'
|
|
20
|
+
|
|
21
|
+
const currentVersionSidebarGroupLabel = Symbol('StarlightVersionsCurrentVersionSidebarGroupLabel')
|
|
22
|
+
|
|
23
|
+
export const VersionBaseSchema = z.object({
|
|
24
|
+
/**
|
|
25
|
+
* The version redirect strategy used when navigating to this version:
|
|
26
|
+
*
|
|
27
|
+
* - `same-page`: Redirect to the same page when navigating to this version.
|
|
28
|
+
* - `root`: Redirect to the root page of the documentation when to this version.
|
|
29
|
+
*
|
|
30
|
+
* @default 'same-page'
|
|
31
|
+
*/
|
|
32
|
+
redirect: z.union([z.literal('root'), z.literal('same-page')]).default('same-page'),
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
export const VersionSchema = z
|
|
36
|
+
.object({
|
|
37
|
+
/**
|
|
38
|
+
* An optional label used in the UI when displaying the version.
|
|
39
|
+
* If not provided, the version slug is used.
|
|
40
|
+
*
|
|
41
|
+
* @example 'v2.0'
|
|
42
|
+
* @example 'v3.1.2'
|
|
43
|
+
*/
|
|
44
|
+
label: z.string().optional(),
|
|
45
|
+
/**
|
|
46
|
+
* The version slug used in URLs to identify the version and its content.
|
|
47
|
+
*
|
|
48
|
+
* @example '2.0'
|
|
49
|
+
* @example '3-1-2'
|
|
50
|
+
*/
|
|
51
|
+
slug: z.string().refine((value) => stripLeadingSlash(stripTrailingSlash(value))),
|
|
52
|
+
})
|
|
53
|
+
.merge(VersionBaseSchema)
|
|
54
|
+
|
|
55
|
+
export async function ensureNewVersion(
|
|
56
|
+
config: StarlightVersionsConfig,
|
|
57
|
+
starlightConfig: StarlightUserConfig,
|
|
58
|
+
srcDir: URL,
|
|
59
|
+
logger: AstroIntegrationLogger,
|
|
60
|
+
) {
|
|
61
|
+
const docsDir = new URL('content/docs/', srcDir)
|
|
62
|
+
const newVersion = await checkForNewVersion(config, docsDir)
|
|
63
|
+
const locales = Object.keys(starlightConfig.locales ?? {})
|
|
64
|
+
|
|
65
|
+
if (!newVersion) return
|
|
66
|
+
|
|
67
|
+
const assets: VersionAsset[] = []
|
|
68
|
+
|
|
69
|
+
await copyDirectory(docsDir, new URL(ensureTrailingSlash(newVersion.slug), docsDir), async (entry) => {
|
|
70
|
+
if (entry.type === 'directory') {
|
|
71
|
+
if (!entry.isRoot) {
|
|
72
|
+
const segments = entry.source.pathname.split('/')
|
|
73
|
+
const lastSegment = segments.at(-2)
|
|
74
|
+
const secondLastSegment = segments.at(-3)
|
|
75
|
+
|
|
76
|
+
if (secondLastSegment && lastSegment === newVersion.slug && locales.includes(secondLastSegment)) {
|
|
77
|
+
// Skip version directories in a locale directory.
|
|
78
|
+
return true
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// Do not skip other non-root directories.
|
|
82
|
+
return false
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
// Skip root version directories.
|
|
86
|
+
if (entry.name in config.versionsBySlug) return true
|
|
87
|
+
|
|
88
|
+
const localeDir = locales.find((locale) => locale === entry.name)
|
|
89
|
+
|
|
90
|
+
// Copy root directories not matching any locale.
|
|
91
|
+
if (!localeDir) return false
|
|
92
|
+
|
|
93
|
+
// Otherwise, swap the locale and version directories.
|
|
94
|
+
return new URL(`../../${localeDir}/${newVersion.slug}/`, entry.dest)
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const slug = getDocSlug(docsDir, entry.url)
|
|
98
|
+
|
|
99
|
+
const md = await transformMarkdown(entry.content, {
|
|
100
|
+
assets: [],
|
|
101
|
+
locale: getDocLocale(slug, starlightConfig),
|
|
102
|
+
slug,
|
|
103
|
+
url: entry.url,
|
|
104
|
+
version: newVersion,
|
|
105
|
+
})
|
|
106
|
+
|
|
107
|
+
assets.push(...(md.assets ?? []))
|
|
108
|
+
|
|
109
|
+
return md.content
|
|
110
|
+
})
|
|
111
|
+
|
|
112
|
+
for (const asset of assets) {
|
|
113
|
+
await copyFile(asset.source, asset.dest)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
await makeVersionConfig(newVersion, starlightConfig, srcDir)
|
|
117
|
+
|
|
118
|
+
logger.info(`Created new version '${newVersion.slug}'.`)
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export async function getVersionedSidebar(
|
|
122
|
+
config: StarlightVersionsConfig,
|
|
123
|
+
currentSidebar: StarlightSidebarUserConfig,
|
|
124
|
+
srcDir: URL,
|
|
125
|
+
): Promise<NonNullable<StarlightSidebarUserConfig>> {
|
|
126
|
+
const sidebar: StarlightSidebarUserConfig = [
|
|
127
|
+
{
|
|
128
|
+
label: currentVersionSidebarGroupLabel.toString(),
|
|
129
|
+
items: currentSidebar ?? [],
|
|
130
|
+
},
|
|
131
|
+
]
|
|
132
|
+
|
|
133
|
+
for (const version of config.versions) {
|
|
134
|
+
const versionSidebar = await getSidebarVersionGroup(version, srcDir)
|
|
135
|
+
sidebar.push(versionSidebar)
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
return sidebar
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// A version is considered as the current version if it's undefined.
|
|
142
|
+
export function getVersionSidebar(version: Version | undefined, sidebar: StarlightSidebar): StarlightSidebar {
|
|
143
|
+
const sidebarVersionGroup = sidebar.find(
|
|
144
|
+
(item) => item.label === (version?.slug ?? currentVersionSidebarGroupLabel.toString()),
|
|
145
|
+
)
|
|
146
|
+
|
|
147
|
+
if (!sidebarVersionGroup || !('entries' in sidebarVersionGroup)) {
|
|
148
|
+
throwPluginError(
|
|
149
|
+
`Failed to find a sidebar group for the ${version ? `version '${version.slug}'` : 'current version'}.`,
|
|
150
|
+
)
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return sidebarVersionGroup.entries
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// An undefined version is valid and represents the current version.
|
|
157
|
+
// https://github.com/withastro/starlight/blob/64288fb0051310f7148afd13f65c578664f04eb2/packages/starlight/utils/localizedUrl.ts
|
|
158
|
+
export function getVersionURL(
|
|
159
|
+
config: StarlightVersionsConfig,
|
|
160
|
+
starlightConfig: StarlightConfig,
|
|
161
|
+
url: URL,
|
|
162
|
+
version: Version | undefined,
|
|
163
|
+
): URL {
|
|
164
|
+
const versionURL = new URL(url)
|
|
165
|
+
const versionSlug = version?.slug ?? ''
|
|
166
|
+
const versionRedirect = version?.redirect ?? config.current.redirect
|
|
167
|
+
|
|
168
|
+
const base = stripTrailingSlash(import.meta.env.BASE_URL)
|
|
169
|
+
const hasBase = versionURL.pathname.startsWith(base)
|
|
170
|
+
|
|
171
|
+
if (hasBase) {
|
|
172
|
+
versionURL.pathname = versionURL.pathname.replace(base, '')
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
let baseSegment: string | undefined
|
|
176
|
+
let localeSegment: string | undefined
|
|
177
|
+
|
|
178
|
+
const isHTML = getExtension(versionURL.pathname) === '.html'
|
|
179
|
+
const [, firstSegment, secondSegment] = versionURL.pathname.split('/')
|
|
180
|
+
|
|
181
|
+
if (starlightConfig.isMultilingual || starlightConfig.locales) {
|
|
182
|
+
const versionOrLocale = firstSegment?.replace('.html', '')
|
|
183
|
+
const isRootLocale = versionOrLocale && !Object.keys(starlightConfig.locales).includes(versionOrLocale)
|
|
184
|
+
baseSegment = isRootLocale ? firstSegment : secondSegment
|
|
185
|
+
|
|
186
|
+
if (!isRootLocale) {
|
|
187
|
+
localeSegment = versionOrLocale
|
|
188
|
+
versionURL.pathname = versionURL.pathname.replace(`/${firstSegment}`, '')
|
|
189
|
+
}
|
|
190
|
+
} else {
|
|
191
|
+
baseSegment = firstSegment
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
const isRootHTML = baseSegment && getExtension(baseSegment) === '.html'
|
|
195
|
+
const baseSlug = baseSegment && isRootHTML ? stripExtension(baseSegment) : baseSegment
|
|
196
|
+
|
|
197
|
+
if (baseSlug && baseSlug in config.versionsBySlug) {
|
|
198
|
+
if (versionSlug) {
|
|
199
|
+
versionURL.pathname =
|
|
200
|
+
versionRedirect === 'same-page'
|
|
201
|
+
? versionURL.pathname.replace(baseSlug, versionSlug)
|
|
202
|
+
: `${versionSlug}${isHTML ? '.html' : '/'}`
|
|
203
|
+
} else if (isRootHTML) {
|
|
204
|
+
versionURL.pathname = '/index.html'
|
|
205
|
+
} else {
|
|
206
|
+
versionURL.pathname =
|
|
207
|
+
versionRedirect === 'same-page' ? versionURL.pathname.replace(`/${baseSlug}`, '') : isHTML ? '/index.html' : '/'
|
|
208
|
+
}
|
|
209
|
+
} else if (versionSlug) {
|
|
210
|
+
versionURL.pathname =
|
|
211
|
+
baseSegment === 'index.html'
|
|
212
|
+
? `/${versionSlug}.html`
|
|
213
|
+
: versionRedirect === 'same-page'
|
|
214
|
+
? `/${versionSlug}${versionURL.pathname}`
|
|
215
|
+
: isHTML
|
|
216
|
+
? `${versionSlug}.html`
|
|
217
|
+
: `/${versionSlug}/`
|
|
218
|
+
} else if (versionRedirect === 'root' && !isRootHTML) {
|
|
219
|
+
versionURL.pathname = isHTML ? '/index.html' : versionSlug
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
if (localeSegment) {
|
|
223
|
+
versionURL.pathname = isHTML
|
|
224
|
+
? versionURL.pathname === '/index.html'
|
|
225
|
+
? `/${localeSegment}.html`
|
|
226
|
+
: `/${localeSegment}${versionURL.pathname.replace(/\/$/, '.html')}`
|
|
227
|
+
: `/${localeSegment}${versionURL.pathname}`
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
if (hasBase) {
|
|
231
|
+
versionURL.pathname = base + versionURL.pathname
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
return versionURL
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// An undefined version is valid and represents the current version.
|
|
238
|
+
export function getVersionFromSlug(
|
|
239
|
+
config: StarlightVersionsConfig,
|
|
240
|
+
starlightConfig: StarlightConfig,
|
|
241
|
+
slug: string,
|
|
242
|
+
): Version | undefined {
|
|
243
|
+
const segments = slug.split('/')
|
|
244
|
+
|
|
245
|
+
const versionOrLocaleSegment = segments[0]
|
|
246
|
+
|
|
247
|
+
if (!versionOrLocaleSegment) return undefined
|
|
248
|
+
|
|
249
|
+
const version = config.versions.find((version) => version.slug === versionOrLocaleSegment)
|
|
250
|
+
|
|
251
|
+
if (version) return version
|
|
252
|
+
|
|
253
|
+
const locales = Object.keys(starlightConfig.locales ?? {})
|
|
254
|
+
|
|
255
|
+
if (!locales.includes(versionOrLocaleSegment)) return undefined
|
|
256
|
+
|
|
257
|
+
const versionSegment = segments[1]
|
|
258
|
+
|
|
259
|
+
return config.versions.find((version) => version.slug === versionSegment)
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export function getVersionIdentifier(version: Version | undefined): string {
|
|
263
|
+
return version?.slug ?? 'current'
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
// An undefined version is valid and represents the current version.
|
|
267
|
+
export function getVersionFromPaginationLink(
|
|
268
|
+
config: StarlightVersionsConfig,
|
|
269
|
+
link: string,
|
|
270
|
+
locale: string | undefined,
|
|
271
|
+
): Version | undefined {
|
|
272
|
+
const [, ...segments] = link.split('/')
|
|
273
|
+
|
|
274
|
+
if (import.meta.env.BASE_URL !== '/') {
|
|
275
|
+
// Remove the base segment if configured.
|
|
276
|
+
segments.splice(0, 1)
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
if (locale) {
|
|
280
|
+
// Remove the locale segment if the current locale is not a root locale.
|
|
281
|
+
segments.splice(0, 1)
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
const versionSegment = segments[0]
|
|
285
|
+
|
|
286
|
+
if (!versionSegment) return undefined
|
|
287
|
+
|
|
288
|
+
return config.versions.find((version) => version.slug === versionSegment)
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
async function getSidebarVersionGroup(version: Version, srcDir: URL) {
|
|
292
|
+
const versionConfig = await getVersionConfig(version, srcDir)
|
|
293
|
+
|
|
294
|
+
if (!versionConfig.sidebar) {
|
|
295
|
+
return {
|
|
296
|
+
label: version.slug,
|
|
297
|
+
autogenerate: { directory: version.slug },
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
return {
|
|
302
|
+
label: version.slug,
|
|
303
|
+
items: addPrefixToSidebarConfig(version.slug, versionConfig.sidebar),
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
async function getVersionConfig(version: Version, srcDir: URL) {
|
|
308
|
+
try {
|
|
309
|
+
return await readJSONFile<DocsVersionsConfig>(getVersionConfigURL(version, srcDir))
|
|
310
|
+
} catch (error) {
|
|
311
|
+
throw new Error(`Failed to read the version '${version.slug}' configuration file.`, { cause: error })
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
async function checkForNewVersion(config: StarlightVersionsConfig, docsDir: URL): Promise<Version | undefined> {
|
|
316
|
+
let newVersion: Version | undefined
|
|
317
|
+
|
|
318
|
+
const docsDirEntries = await listDirectory(docsDir)
|
|
319
|
+
const docsDirDirectories = new Set(docsDirEntries.filter((entry) => entry.isDirectory()).map((dirent) => dirent.name))
|
|
320
|
+
|
|
321
|
+
for (const version of config.versions) {
|
|
322
|
+
if (!docsDirDirectories.has(version.slug)) {
|
|
323
|
+
if (newVersion) {
|
|
324
|
+
throw new Error('Only one new version can be configured at a time.')
|
|
325
|
+
}
|
|
326
|
+
newVersion = version
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
return newVersion
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
async function makeVersionConfig(version: Version, starlightConfig: StarlightUserConfig, srcDir: URL) {
|
|
334
|
+
const versionsDir = getVersionContentCollectionURL(srcDir)
|
|
335
|
+
|
|
336
|
+
await ensureDirectory(versionsDir)
|
|
337
|
+
await writeJSONFile(getVersionConfigURL(version, srcDir), {
|
|
338
|
+
sidebar: starlightConfig.sidebar,
|
|
339
|
+
} satisfies DocsVersionsConfig)
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
function getVersionContentCollectionURL(srcDir: URL) {
|
|
343
|
+
return new URL('content/versions/', srcDir)
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
function getVersionConfigURL(version: Version, srcDir: URL) {
|
|
347
|
+
return new URL(`${version.slug}.json`, getVersionContentCollectionURL(srcDir))
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export type Version = z.output<typeof VersionSchema>
|
|
351
|
+
|
|
352
|
+
export interface VersionAsset {
|
|
353
|
+
source: URL
|
|
354
|
+
dest: URL
|
|
355
|
+
}
|
package/libs/vite.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { ViteUserConfig } from 'astro'
|
|
2
|
+
|
|
3
|
+
import type { StarlightVersionsConfig } from '..'
|
|
4
|
+
|
|
5
|
+
export function vitePluginStarlightVersions(config: StarlightVersionsConfig): VitePlugin {
|
|
6
|
+
const moduleId = 'virtual:starlight-versions-config'
|
|
7
|
+
const resolvedModuleId = `\0${moduleId}`
|
|
8
|
+
const moduleContent = `export default ${JSON.stringify(config)}`
|
|
9
|
+
|
|
10
|
+
return {
|
|
11
|
+
name: 'vite-plugin-starlight-versions',
|
|
12
|
+
load(id) {
|
|
13
|
+
return id === resolvedModuleId ? moduleContent : undefined
|
|
14
|
+
},
|
|
15
|
+
resolveId(id) {
|
|
16
|
+
return id === moduleId ? resolvedModuleId : undefined
|
|
17
|
+
},
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type VitePlugin = NonNullable<ViteUserConfig['plugins']>[number]
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Default from '@astrojs/starlight/components/Banner.astro'
|
|
3
|
+
import type { Props } from '@astrojs/starlight/props'
|
|
4
|
+
|
|
5
|
+
import VersionBanner from '../components/VersionBanner.astro'
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<VersionBanner {...Astro.props} />
|
|
9
|
+
<Default {...Astro.props}><slot /></Default>
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Default from '@astrojs/starlight/components/PageTitle.astro'
|
|
3
|
+
import type { Props } from '@astrojs/starlight/props'
|
|
4
|
+
|
|
5
|
+
import VersionNotice from '../components/VersionNotice.astro'
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<Default {...Astro.props}><slot /></Default>
|
|
9
|
+
<VersionNotice {...Astro.props} />
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
---
|
|
2
|
+
import Default from '@astrojs/starlight/components/ThemeSelect.astro'
|
|
3
|
+
import type { Props } from '@astrojs/starlight/props'
|
|
4
|
+
|
|
5
|
+
import VersionSelect from '../components/VersionSelect.astro'
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
<VersionSelect {...Astro.props} />
|
|
9
|
+
<Default {...Astro.props}><slot /></Default>
|
package/package.json
ADDED
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "starlight-versions",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"license": "MIT",
|
|
5
|
+
"description": "Starlight plugin to version documentation pages.",
|
|
6
|
+
"author": "HiDeoo <github@hideoo.dev> (https://hideoo.dev)",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./index.ts",
|
|
10
|
+
"./schema": "./schema.ts",
|
|
11
|
+
"./components/VersionBanner.astro": "./components/VersionBanner.astro",
|
|
12
|
+
"./components/VersionNotice.astro": "./components/VersionNotice.astro",
|
|
13
|
+
"./components/VersionPagination.astro": "./components/VersionPagination.astro",
|
|
14
|
+
"./components/VersionSearch.astro": "./components/VersionSearch.astro",
|
|
15
|
+
"./components/VersionSelect.astro": "./components/VersionSelect.astro",
|
|
16
|
+
"./components/VersionSidebar.astro": "./components/VersionSidebar.astro",
|
|
17
|
+
"./overrides/Banner.astro": "./overrides/Banner.astro",
|
|
18
|
+
"./overrides/PageTitle.astro": "./overrides/PageTitle.astro",
|
|
19
|
+
"./overrides/Pagination.astro": "./overrides/Pagination.astro",
|
|
20
|
+
"./overrides/Search.astro": "./overrides/Search.astro",
|
|
21
|
+
"./overrides/Sidebar.astro": "./overrides/Sidebar.astro",
|
|
22
|
+
"./overrides/ThemeSelect.astro": "./overrides/ThemeSelect.astro",
|
|
23
|
+
"./package.json": "./package.json"
|
|
24
|
+
},
|
|
25
|
+
"dependencies": {
|
|
26
|
+
"@pagefind/default-ui": "^1.0.3",
|
|
27
|
+
"github-slugger": "^2.0.0",
|
|
28
|
+
"mdast-util-mdx-jsx": "^3.1.2",
|
|
29
|
+
"mdast-util-mdxjs-esm": "^2.0.1",
|
|
30
|
+
"remark": "^15.0.1",
|
|
31
|
+
"remark-frontmatter": "^5.0.0",
|
|
32
|
+
"remark-mdx": "^3.0.1",
|
|
33
|
+
"unist-util-visit": "^5.0.0",
|
|
34
|
+
"vfile": "^6.0.1",
|
|
35
|
+
"yaml": "^2.4.2"
|
|
36
|
+
},
|
|
37
|
+
"devDependencies": {
|
|
38
|
+
"@types/mdast": "^4.0.4",
|
|
39
|
+
"fast-glob": "^3.3.2",
|
|
40
|
+
"vitest": "^1.6.0"
|
|
41
|
+
},
|
|
42
|
+
"peerDependencies": {
|
|
43
|
+
"@astrojs/starlight": ">=0.23.0"
|
|
44
|
+
},
|
|
45
|
+
"engines": {
|
|
46
|
+
"node": ">=18"
|
|
47
|
+
},
|
|
48
|
+
"publishConfig": {
|
|
49
|
+
"access": "public"
|
|
50
|
+
},
|
|
51
|
+
"sideEffects": false,
|
|
52
|
+
"keywords": [
|
|
53
|
+
"starlight",
|
|
54
|
+
"plugin",
|
|
55
|
+
"versions",
|
|
56
|
+
"versioning",
|
|
57
|
+
"documentation",
|
|
58
|
+
"astro"
|
|
59
|
+
],
|
|
60
|
+
"homepage": "https://github.com/HiDeoo/starlight-versions",
|
|
61
|
+
"repository": {
|
|
62
|
+
"type": "git",
|
|
63
|
+
"url": "https://github.com/HiDeoo/starlight-versions.git",
|
|
64
|
+
"directory": "packages/starlight-versions"
|
|
65
|
+
},
|
|
66
|
+
"bugs": "https://github.com/HiDeoo/starlight-versions/issues",
|
|
67
|
+
"scripts": {
|
|
68
|
+
"test": "vitest",
|
|
69
|
+
"lint": "prettier -c --cache . && eslint . --cache --max-warnings=0"
|
|
70
|
+
}
|
|
71
|
+
}
|
package/schema.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { z } from 'astro/zod'
|
|
2
|
+
|
|
3
|
+
import type { StarlightSidebarUserConfig } from './libs/starlight'
|
|
4
|
+
|
|
5
|
+
export function docsVersionsSchema() {
|
|
6
|
+
return z.object({
|
|
7
|
+
sidebar: z.any().optional(),
|
|
8
|
+
})
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface DocsVersionsConfig {
|
|
12
|
+
sidebar?: StarlightSidebarUserConfig
|
|
13
|
+
}
|
package/virtual.d.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
declare module 'virtual:starlight-versions-config' {
|
|
2
|
+
const StarlightVersionsConfig: import('./index').StarlightVersionsConfig
|
|
3
|
+
|
|
4
|
+
export default StarlightVersionsConfig
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
declare module 'virtual:starlight/user-config' {
|
|
8
|
+
const StarlightConfig: import('@astrojs/starlight/types').StarlightConfig
|
|
9
|
+
|
|
10
|
+
export default StarlightConfig
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
declare module 'virtual:starlight/project-context' {
|
|
14
|
+
const ProjectContext: {
|
|
15
|
+
root: string
|
|
16
|
+
srcDir: string
|
|
17
|
+
trailingSlash: import('astro').AstroConfig['trailingSlash']
|
|
18
|
+
build: {
|
|
19
|
+
format: import('astro').AstroConfig['build']['format']
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export default ProjectContext
|
|
23
|
+
}
|