|
1 | 1 | import * as devalue from 'devalue';
|
2 | 2 | import type fsMod from 'node:fs';
|
| 3 | +import { extname } from 'node:path'; |
3 | 4 | import { pathToFileURL } from 'url';
|
4 | 5 | import type { Plugin } from 'vite';
|
5 |
| -import { AstroSettings } from '../@types/astro.js'; |
| 6 | +import { AstroSettings, ContentEntryType } from '../@types/astro.js'; |
6 | 7 | import { AstroErrorData } from '../core/errors/errors-data.js';
|
7 | 8 | import { AstroError } from '../core/errors/errors.js';
|
8 | 9 | import { escapeViteEnvReferences, getFileInfo } from '../vite-plugin-utils/index.js';
|
@@ -34,6 +35,13 @@ export function astroContentImportPlugin({
|
34 | 35 | const contentPaths = getContentPaths(settings.config, fs);
|
35 | 36 | const contentEntryExts = getContentEntryExts(settings);
|
36 | 37 |
|
| 38 | + const contentEntryExtToParser: Map<string, ContentEntryType> = new Map(); |
| 39 | + for (const entryType of settings.contentEntryTypes) { |
| 40 | + for (const ext of entryType.extensions) { |
| 41 | + contentEntryExtToParser.set(ext, entryType); |
| 42 | + } |
| 43 | + } |
| 44 | + |
37 | 45 | return {
|
38 | 46 | name: 'astro:content-imports',
|
39 | 47 | async load(id) {
|
@@ -71,55 +79,48 @@ export function astroContentImportPlugin({
|
71 | 79 | });
|
72 | 80 | }
|
73 | 81 | const rawContents = await fs.promises.readFile(fileId, 'utf-8');
|
74 |
| - const contentEntryType = settings.contentEntryTypes.find((entryType) => |
75 |
| - entryType.extensions.some((ext) => fileId.endsWith(ext)) |
76 |
| - ); |
77 |
| - let body: string, |
78 |
| - unvalidatedData: Record<string, unknown>, |
79 |
| - unvalidatedSlug: string, |
80 |
| - rawData: string; |
81 |
| - if (contentEntryType) { |
82 |
| - const info = await contentEntryType.getEntryInfo({ |
83 |
| - fileUrl: pathToFileURL(fileId), |
84 |
| - contents: rawContents, |
| 82 | + const fileExt = extname(fileId); |
| 83 | + if (!contentEntryExtToParser.has(fileExt)) { |
| 84 | + throw new AstroError({ |
| 85 | + ...AstroErrorData.UnknownContentCollectionError, |
| 86 | + message: `No parser found for content entry ${JSON.stringify( |
| 87 | + fileId |
| 88 | + )}. Did you apply an integration for this file type?`, |
85 | 89 | });
|
86 |
| - body = info.body; |
87 |
| - unvalidatedData = info.data; |
88 |
| - unvalidatedSlug = info.slug; |
89 |
| - rawData = info.rawData; |
90 |
| - } else { |
91 |
| - const parsed = parseFrontmatter(rawContents, fileId); |
92 |
| - body = parsed.content; |
93 |
| - unvalidatedData = parsed.data; |
94 |
| - unvalidatedSlug = parsed.data.slug; |
95 |
| - rawData = parsed.matter; |
96 | 90 | }
|
97 |
| - |
98 |
| - const entryInfo = getEntryInfo({ |
| 91 | + const contentEntryParser = contentEntryExtToParser.get(fileExt)!; |
| 92 | + const info = await contentEntryParser.getEntryInfo({ |
| 93 | + fileUrl: pathToFileURL(fileId), |
| 94 | + contents: rawContents, |
| 95 | + }); |
| 96 | + const generatedInfo = getEntryInfo({ |
99 | 97 | entry: pathToFileURL(fileId),
|
100 | 98 | contentDir: contentPaths.contentDir,
|
101 | 99 | });
|
102 |
| - if (entryInfo instanceof Error) return; |
| 100 | + if (generatedInfo instanceof Error) return; |
103 | 101 |
|
104 |
| - const _internal = { filePath: fileId, rawData }; |
| 102 | + const _internal = { filePath: fileId, rawData: info.rawData }; |
105 | 103 | // TODO: move slug calculation to the start of the build
|
106 | 104 | // to generate a performant lookup map for `getEntryBySlug`
|
107 |
| - const slug = getEntrySlug({ ...entryInfo, unvalidatedSlug }); |
| 105 | + const slug = getEntrySlug({ ...generatedInfo, unvalidatedSlug: info.slug }); |
108 | 106 |
|
109 |
| - const collectionConfig = contentConfig?.collections[entryInfo.collection]; |
| 107 | + const collectionConfig = contentConfig?.collections[generatedInfo.collection]; |
110 | 108 | const data = collectionConfig
|
111 |
| - ? await getEntryData({ ...entryInfo, _internal, unvalidatedData }, collectionConfig) |
112 |
| - : unvalidatedData; |
| 109 | + ? await getEntryData( |
| 110 | + { ...generatedInfo, _internal, unvalidatedData: info.data }, |
| 111 | + collectionConfig |
| 112 | + ) |
| 113 | + : info.data; |
113 | 114 |
|
114 | 115 | const code = escapeViteEnvReferences(`
|
115 |
| -export const id = ${JSON.stringify(entryInfo.id)}; |
116 |
| -export const collection = ${JSON.stringify(entryInfo.collection)}; |
| 116 | +export const id = ${JSON.stringify(generatedInfo.id)}; |
| 117 | +export const collection = ${JSON.stringify(generatedInfo.collection)}; |
117 | 118 | export const slug = ${JSON.stringify(slug)};
|
118 |
| -export const body = ${JSON.stringify(body)}; |
| 119 | +export const body = ${JSON.stringify(info.body)}; |
119 | 120 | export const data = ${devalue.uneval(data) /* TODO: reuse astro props serializer */};
|
120 | 121 | export const _internal = {
|
121 |
| - filePath: ${JSON.stringify(fileId)}, |
122 |
| - rawData: ${JSON.stringify(unvalidatedData)}, |
| 122 | + filePath: ${JSON.stringify(_internal.filePath)}, |
| 123 | + rawData: ${JSON.stringify(_internal.rawData)}, |
123 | 124 | };
|
124 | 125 | `);
|
125 | 126 | return { code };
|
|
0 commit comments