|
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