Skip to content

Commit b74fd6a

Browse files
committed
feat: support .md overrides for content collections
1 parent bdcc18a commit b74fd6a

File tree

7 files changed

+35
-3
lines changed

7 files changed

+35
-3
lines changed

packages/astro/src/@types/astro.ts

+1
Original file line numberDiff line numberDiff line change
@@ -978,6 +978,7 @@ export interface AstroConfig extends z.output<typeof AstroConfigSchema> {
978978
}
979979

980980
export interface ContentEntryType {
981+
name: string;
981982
extensions: string[];
982983
getEntryInfo(params: { fileUrl: URL; contents: string }): Promise<{
983984
data: Record<string, unknown>;

packages/astro/src/content/index.ts

+6-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,11 @@
11
export { attachContentServerListeners } from './server-listeners.js';
22
export { createContentTypesGenerator } from './types-generator.js';
3-
export { contentObservable, getContentPaths, getDotAstroTypeReference } from './utils.js';
3+
export {
4+
contentObservable,
5+
getContentPaths,
6+
getDotAstroTypeReference,
7+
hasMdContentEntryTypeOverride,
8+
} from './utils.js';
49
export { astroContentAssetPropagationPlugin } from './vite-plugin-content-assets.js';
510
export { astroContentImportPlugin } from './vite-plugin-content-imports.js';
611
export { astroContentVirtualModPlugin } from './vite-plugin-content-virtual-mod.js';

packages/astro/src/content/utils.ts

+9
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import { ErrorPayload as ViteErrorPayload, normalizePath, ViteDevServer } from '
77
import { z } from 'zod';
88
import { AstroConfig, AstroSettings } from '../@types/astro.js';
99
import { AstroError, AstroErrorData } from '../core/errors/index.js';
10+
import { MARKDOWN_CONTENT_ENTRY_TYPE_NAME } from '../vite-plugin-markdown/content-entry-type.js';
1011
import { CONTENT_TYPES_FILE } from './consts.js';
1112

1213
export const collectionConfigParser = z.object({
@@ -347,3 +348,11 @@ function search(fs: typeof fsMod, srcDir: URL) {
347348
}
348349
return { exists: false, url: paths[0] };
349350
}
351+
352+
export function hasMdContentEntryTypeOverride(settings: Pick<AstroSettings, 'contentEntryTypes'>) {
353+
return settings.contentEntryTypes.some(
354+
(contentEntryType) =>
355+
contentEntryType.name !== MARKDOWN_CONTENT_ENTRY_TYPE_NAME &&
356+
contentEntryType.extensions.includes('.md')
357+
);
358+
}

packages/astro/src/vite-plugin-markdown/content-entry-type.ts

+3
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@ import { fileURLToPath } from 'node:url';
22
import { ContentEntryType } from '../@types/astro.js';
33
import { parseFrontmatter } from '../content/utils.js';
44

5+
export const MARKDOWN_CONTENT_ENTRY_TYPE_NAME = 'astro:markdown';
6+
57
export const markdownContentEntryType: ContentEntryType = {
8+
name: MARKDOWN_CONTENT_ENTRY_TYPE_NAME,
69
extensions: ['.md'],
710
async getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) {
811
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));

packages/astro/src/vite-plugin-markdown/index.ts

+10
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import type { Plugin } from 'vite';
1010
import { normalizePath } from 'vite';
1111
import type { AstroSettings } from '../@types/astro';
1212
import { getContentPaths } from '../content/index.js';
13+
import { hasMdContentEntryTypeOverride } from '../content/index.js';
1314
import { AstroError, AstroErrorData, MarkdownError } from '../core/errors/index.js';
1415
import type { LogOptions } from '../core/logger/core.js';
1516
import { warn } from '../core/logger/core.js';
@@ -66,6 +67,15 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu
6667
async load(id) {
6768
if (isMarkdownFile(id)) {
6869
const { fileId, fileUrl } = getFileInfo(id, settings.config);
70+
if (
71+
// Integrations can override the Markdown parser for content collections.
72+
// If an override is present, skip this file.
73+
fileId.startsWith(getContentPaths(settings.config).contentDir.pathname) &&
74+
hasMdContentEntryTypeOverride(settings)
75+
) {
76+
return;
77+
}
78+
6979
const rawFile = await fs.promises.readFile(fileId, 'utf-8');
7080
const raw = safeMatter(rawFile, id);
7181
const renderResult = await renderMarkdown(raw.content, {

packages/integrations/markdoc/src/index.ts

+5-2
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,16 @@ import { parseFrontmatter } from './utils.js';
66
import { fileURLToPath } from 'node:url';
77
import fs from 'node:fs';
88

9+
const DEFAULT_MARKDOC_EXTS = ['.mdoc', '.md'];
10+
911
export default function markdoc(): AstroIntegration {
1012
return {
1113
name: '@astrojs/markdoc',
1214
hooks: {
1315
'astro:config:setup': async ({ updateConfig, config, addContentEntryType, command }: any) => {
1416
const contentEntryType = {
15-
extensions: ['.mdoc'],
17+
name: 'astro:markdoc',
18+
extensions: DEFAULT_MARKDOC_EXTS,
1619
async getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) {
1720
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));
1821
return {
@@ -34,7 +37,7 @@ export default function markdoc(): AstroIntegration {
3437
{
3538
name: '@astrojs/markdoc',
3639
async transform(code, id) {
37-
if (!id.endsWith('.mdoc')) return;
40+
if (!DEFAULT_MARKDOC_EXTS.some((ext) => id.endsWith(ext))) return;
3841
return `import { jsx as h } from 'astro/jsx-runtime';\nimport { Markdoc } from '@astrojs/markdoc';\nimport { Renderer } from '@astrojs/markdoc/components';\nexport const body = ${JSON.stringify(
3942
code
4043
)};\nexport function getParsed() { return Markdoc.parse(body); }\nexport function getTransformed(inlineConfig) { return Markdoc.transform(getParsed(), inlineConfig) }\nexport async function Content ({ config, components }) { return h(Renderer, { content: getTransformed(config), components }); }\nContent[Symbol.for('astro.needsHeadRendering')] = true;`;

packages/integrations/mdx/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ export default function mdx(partialMdxOptions: Partial<MdxOptions> = {}): AstroI
3535
command,
3636
}: any) => {
3737
const contentEntryType = {
38+
name: 'astro:mdx',
3839
extensions: ['.mdx'],
3940
async getEntryInfo({ fileUrl, contents }: { fileUrl: URL; contents: string }) {
4041
const parsed = parseFrontmatter(contents, fileURLToPath(fileUrl));

0 commit comments

Comments
 (0)