summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChris Swithinbank2025-07-16 15:58:04 +0200
committerGitHub2025-07-16 15:58:04 +0200
commite7fe26720b7527c39e3aab42ea9fd0468f92167c (patch)
tree97d9f10826f04998fa6f3083885a3363160ac9fb
parent1161af0c2fe26485da6123f8fd7205c53b0e45e5 (diff)
downloadIT.starlight-e7fe26720b7527c39e3aab42ea9fd0468f92167c.tar.gz
IT.starlight-e7fe26720b7527c39e3aab42ea9fd0468f92167c.tar.bz2
IT.starlight-e7fe26720b7527c39e3aab42ea9fd0468f92167c.zip
Support passing `generateId` to `docsLoader()` (#3272)
Co-authored-by: HiDeoo <494699+HiDeoo@users.noreply.github.com>
-rw-r--r--.changeset/metal-trees-deny.md7
-rw-r--r--docs/src/content/docs/manual-setup.mdx2
-rw-r--r--docs/src/content/docs/reference/configuration.mdx115
-rw-r--r--packages/starlight/loaders.ts33
4 files changed, 151 insertions, 6 deletions
diff --git a/.changeset/metal-trees-deny.md b/.changeset/metal-trees-deny.md
new file mode 100644
index 00000000..86b2ab20
--- /dev/null
+++ b/.changeset/metal-trees-deny.md
@@ -0,0 +1,7 @@
+---
+'@astrojs/starlight': minor
+---
+
+Adds a new `generateId` option to Starlight’s `docsLoader()`
+
+This enables overriding the default sluggifier used to convert content filenames to URLs.
diff --git a/docs/src/content/docs/manual-setup.mdx b/docs/src/content/docs/manual-setup.mdx
index 7848438a..7b8fbe5d 100644
--- a/docs/src/content/docs/manual-setup.mdx
+++ b/docs/src/content/docs/manual-setup.mdx
@@ -64,7 +64,7 @@ Find all available options in the [Starlight configuration reference](/reference
Starlight is built on top of Astro’s [content collections](https://docs.astro.build/en/guides/content-collections/), which are configured in the `src/content.config.ts` file.
-Create or update the content config file, adding a `docs` collection that uses Starlight’s `docsLoader` and `docsSchema`:
+Create or update the content config file, adding a `docs` collection that uses Starlight’s [`docsLoader`](/reference/configuration/#docsloader) and [`docsSchema`](/reference/configuration/#docsschema):
```js ins={3-4,7}
// src/content.config.ts
diff --git a/docs/src/content/docs/reference/configuration.mdx b/docs/src/content/docs/reference/configuration.mdx
index 9d245531..e7e21955 100644
--- a/docs/src/content/docs/reference/configuration.mdx
+++ b/docs/src/content/docs/reference/configuration.mdx
@@ -677,3 +677,118 @@ starlight({
credits: true,
});
```
+
+## Configure content collections
+
+Starlight uses Astro [content collections](https://docs.astro.build/en/guides/content-collections/) to load your content.
+Starlight’s content loaders and schemas help configure collections as required.
+
+```js
+// src/content.config.ts
+import { defineCollection } from 'astro:content';
+import { docsLoader, i18nLoader } from '@astrojs/starlight/loaders';
+import { docsSchema, i18nSchema } from '@astrojs/starlight/schema';
+
+export const collections = {
+ docs: defineCollection({ loader: docsLoader(), schema: docsSchema() }),
+ // Optional: the i18n collection is used to translate UI in multilingual sites
+ i18n: defineCollection({ loader: i18nLoader(), schema: i18nSchema() }),
+};
+```
+
+### Loaders
+
+Starlight exports the following [Astro loaders](https://docs.astro.build/en/reference/content-loader-reference/) from the `@astrojs/starlight/loaders` module to simplify configuring content collections.
+
+#### `docsLoader()`
+
+The `docsLoader()` loads local Markdown, MDX, and Markdoc files from the `src/content/docs/` directory.
+File names starting with an underscore (`_`) are ignored.
+
+##### Import
+
+```js
+import { docsLoader } from '@astrojs/starlight/loaders';
+```
+
+##### Options
+
+###### `generateId()`
+
+**type:** `({ entry: string; base: URL; data: Record<string, unknown> }) => string`
+
+By default, pages generated using `docsLoader()` process your file names using a sluggifier, which removes special characters and lowercases the file name.
+If you want to override this default, provide your own custom `generateId()` function.
+
+For example, this can be useful to preserve special characters that would be removed.
+By default, `Example.File.md` would be served at `/examplefile`.
+If you wanted to serve it at `/Example.File`, you could do so by defining a custom `generateId()` function:
+
+```js
+docsLoader({
+ // Remove the `.md` or `.mdx` extension, but otherwise don’t process filenames.
+ generateId: ({ entry }) => entry.split('.').slice(0, -1).join('.'),
+}),
+```
+
+See [`generateId()` in the Astro docs](https://docs.astro.build/en/reference/content-loader-reference/#generateid) for more details.
+
+#### `i18nLoader()`
+
+The `i18nLoader()` loads local JSON and YAML files from the `src/content/i18n/` directory.
+File names starting with an underscore (`_`) are ignored.
+
+##### Import
+
+```js
+import { i18nLoader } from '@astrojs/starlight/loaders';
+```
+
+##### Options
+
+There are currently no options to configure `i18nLoader()`.
+
+### Schemas
+
+Starlight provides the following [content collection schemas](https://docs.astro.build/en/guides/content-collections/#defining-the-collection-schema) from the `@astrojs/starlight/schema` module.
+These schemas must be used for the `docs` and `i18n` collections Starlight depends on.
+
+#### `docsSchema()`
+
+The `docsSchema()` parses frontmatter for all your content in the `docs` collection.
+
+##### Import
+
+```js
+import { docsSchema } from '@astrojs/starlight/schema';
+```
+
+##### Options
+
+###### `extend`
+
+**type:** Zod schema or function that returns a Zod schema
+**default:** `z.object({})`
+
+Extend Starlight’s frontmatter schema with additional fields.
+See [“Customize frontmatter schema”](/reference/frontmatter/#customize-frontmatter-schema) for more details about using the `extend` option.
+
+#### `i18nSchema()`
+
+The `i18nSchema()` parses all data files in the `i18n` collection.
+
+##### Import
+
+```js
+import { i18nSchema } from '@astrojs/starlight/schema';
+```
+
+##### Options
+
+###### `extend`
+
+**type:** Zod object
+**default:** `z.object({})`
+
+Extend Starlight’s i18n schema with additional fields.
+See [“Extend translation schema”](/guides/i18n/#extend-translation-schema) for more details about using the `extend` option.
diff --git a/packages/starlight/loaders.ts b/packages/starlight/loaders.ts
index bb424d0e..ef2d6766 100644
--- a/packages/starlight/loaders.ts
+++ b/packages/starlight/loaders.ts
@@ -6,13 +6,30 @@ import { getCollectionPathFromRoot, type StarlightCollection } from './utils/col
const docsExtensions = ['markdown', 'mdown', 'mkdn', 'mkd', 'mdwn', 'md', 'mdx'];
const i18nExtensions = ['json', 'yml', 'yaml'];
-export function docsLoader(): Loader {
+type GlobOptions = Parameters<typeof glob>[0];
+type GenerateIdFunction = NonNullable<GlobOptions['generateId']>;
+
+/**
+ * Loads content files from the `src/content/docs/` directory, ignoring filenames starting with `_`.
+ */
+export function docsLoader({
+ generateId,
+}: {
+ /**
+ * Function that generates an ID for an entry. Default implementation generates a slug from the entry path.
+ * @returns The ID of the entry. Must be unique per collection.
+ **/
+ generateId?: GenerateIdFunction;
+} = {}): Loader {
return {
name: 'starlight-docs-loader',
- load: createGlobLoadFn('docs'),
+ load: createGlobLoadFn('docs', generateId),
};
}
+/**
+ * Loads data files from the `src/content/i18n/` directory, ignoring filenames starting with `_`.
+ */
export function i18nLoader(): Loader {
return {
name: 'starlight-i18n-loader',
@@ -20,7 +37,10 @@ export function i18nLoader(): Loader {
};
}
-function createGlobLoadFn(collection: StarlightCollection): Loader['load'] {
+function createGlobLoadFn(
+ collection: StarlightCollection,
+ generateId?: GenerateIdFunction
+): Loader['load'] {
return (context: LoaderContext) => {
const extensions = collection === 'docs' ? docsExtensions : i18nExtensions;
@@ -32,9 +52,12 @@ function createGlobLoadFn(collection: StarlightCollection): Loader['load'] {
extensions.push('mdoc');
}
- return glob({
+ const options: GlobOptions = {
base: getCollectionPathFromRoot(collection, context.config),
pattern: `**/[^_]*.{${extensions.join(',')}}`,
- }).load(context);
+ };
+ if (generateId) options.generateId = generateId;
+
+ return glob(options).load(context);
};
}