astro 4.13.4 → 4.14.1
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/components/Code.astro +9 -0
- package/dist/@types/astro.d.ts +249 -1
- package/dist/actions/consts.d.ts +1 -1
- package/dist/actions/consts.js +1 -1
- package/dist/actions/index.js +12 -21
- package/dist/assets/endpoint/node.js +1 -1
- package/dist/assets/utils/resolveImports.d.ts +9 -0
- package/dist/assets/utils/resolveImports.js +22 -0
- package/dist/cli/add/index.d.ts +2 -2
- package/dist/cli/add/index.js +2 -2
- package/dist/cli/build/index.d.ts +2 -2
- package/dist/cli/build/index.js +5 -1
- package/dist/cli/check/index.d.ts +2 -2
- package/dist/cli/check/index.js +5 -2
- package/dist/cli/db/index.d.ts +4 -3
- package/dist/cli/db/index.js +10 -3
- package/dist/cli/dev/index.d.ts +2 -2
- package/dist/cli/dev/index.js +1 -0
- package/dist/cli/docs/index.d.ts +2 -2
- package/dist/cli/flags.d.ts +3 -1
- package/dist/cli/flags.js +2 -1
- package/dist/cli/index.d.ts +1 -1
- package/dist/cli/index.js +26 -13
- package/dist/cli/info/index.d.ts +2 -2
- package/dist/cli/preferences/index.d.ts +2 -2
- package/dist/cli/preferences/index.js +1 -1
- package/dist/cli/preview/index.d.ts +2 -2
- package/dist/cli/sync/index.d.ts +2 -2
- package/dist/cli/sync/index.js +5 -2
- package/dist/cli/telemetry/index.d.ts +2 -2
- package/dist/content/consts.d.ts +16 -2
- package/dist/content/consts.js +32 -2
- package/dist/content/content-layer.d.ts +40 -0
- package/dist/content/content-layer.js +253 -0
- package/dist/content/data-store.d.ts +54 -0
- package/dist/content/data-store.js +72 -0
- package/dist/content/loaders/file.d.ts +7 -0
- package/dist/content/loaders/file.js +72 -0
- package/dist/content/loaders/glob.d.ts +25 -0
- package/dist/content/loaders/glob.js +218 -0
- package/dist/content/loaders/index.d.ts +3 -0
- package/dist/content/loaders/index.js +7 -0
- package/dist/content/loaders/types.d.ts +36 -0
- package/dist/content/loaders/types.js +0 -0
- package/dist/content/mutable-data-store.d.ts +77 -0
- package/dist/content/mutable-data-store.js +269 -0
- package/dist/content/runtime.d.ts +46 -8
- package/dist/content/runtime.js +225 -31
- package/dist/content/types-generator.js +123 -35
- package/dist/content/utils.d.ts +307 -2
- package/dist/content/utils.js +101 -7
- package/dist/content/vite-plugin-content-assets.js +9 -1
- package/dist/content/vite-plugin-content-virtual-mod.js +94 -2
- package/dist/core/build/index.js +14 -7
- package/dist/core/build/plugins/plugin-ssr.js +32 -4
- package/dist/core/config/config.d.ts +2 -5
- package/dist/core/config/config.js +0 -12
- package/dist/core/config/index.d.ts +1 -1
- package/dist/core/config/index.js +0 -2
- package/dist/core/config/schema.d.ts +34 -0
- package/dist/core/config/schema.js +6 -2
- package/dist/core/config/settings.js +5 -3
- package/dist/core/constants.js +1 -1
- package/dist/core/create-vite.js +1 -1
- package/dist/core/dev/container.js +2 -1
- package/dist/core/dev/dev.js +33 -3
- package/dist/core/dev/restart.js +25 -10
- package/dist/core/errors/errors-data.d.ts +21 -0
- package/dist/core/errors/errors-data.js +13 -0
- package/dist/core/index.js +1 -1
- package/dist/core/logger/vite.js +1 -1
- package/dist/core/messages.js +2 -2
- package/dist/core/preview/static-preview-server.js +1 -1
- package/dist/core/routing/manifest/create.js +1 -1
- package/dist/core/sync/constants.d.ts +1 -0
- package/dist/core/sync/constants.js +4 -0
- package/dist/core/sync/index.d.ts +12 -4
- package/dist/core/sync/index.js +54 -24
- package/dist/core/sync/write-files.d.ts +4 -0
- package/dist/core/sync/write-files.js +69 -0
- package/dist/core/util.js +1 -1
- package/dist/env/sync.js +6 -4
- package/dist/integrations/hooks.d.ts +7 -1
- package/dist/integrations/hooks.js +54 -0
- package/dist/preferences/index.d.ts +1 -1
- package/dist/preferences/index.js +2 -2
- package/dist/runtime/server/render/server-islands.js +6 -4
- package/dist/vite-plugin-astro-server/response.js +1 -1
- package/dist/vite-plugin-env/index.d.ts +3 -1
- package/dist/vite-plugin-env/index.js +11 -1
- package/dist/vite-plugin-markdown/content-entry-type.js +25 -2
- package/dist/vite-plugin-scanner/index.js +15 -5
- package/package.json +10 -5
- package/templates/content/module.mjs +6 -1
- package/templates/content/types.d.ts +18 -5
- package/types/content.d.ts +34 -1
- package/dist/core/sync/setup-env-ts.d.ts +0 -8
- package/dist/core/sync/setup-env-ts.js +0 -79
package/dist/content/runtime.js
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
+
import { Traverse } from "neotraverse/modern";
|
|
1
2
|
import pLimit from "p-limit";
|
|
2
|
-
import { ZodIssueCode,
|
|
3
|
-
import {
|
|
3
|
+
import { ZodIssueCode, z } from "zod";
|
|
4
|
+
import { imageSrcToImportId } from "../assets/utils/resolveImports.js";
|
|
5
|
+
import { AstroError, AstroErrorData, AstroUserError } from "../core/errors/index.js";
|
|
4
6
|
import { prependForwardSlash } from "../core/path.js";
|
|
5
7
|
import {
|
|
6
8
|
createComponent,
|
|
@@ -9,9 +11,21 @@ import {
|
|
|
9
11
|
renderScriptElement,
|
|
10
12
|
renderTemplate,
|
|
11
13
|
renderUniqueStylesheet,
|
|
14
|
+
render as serverRender,
|
|
12
15
|
unescapeHTML
|
|
13
16
|
} from "../runtime/server/index.js";
|
|
17
|
+
import { CONTENT_LAYER_TYPE, IMAGE_IMPORT_PREFIX } from "./consts.js";
|
|
18
|
+
import { globalDataStore } from "./data-store.js";
|
|
14
19
|
function defineCollection(config) {
|
|
20
|
+
if ("loader" in config) {
|
|
21
|
+
if (config.type && config.type !== CONTENT_LAYER_TYPE) {
|
|
22
|
+
throw new AstroUserError(
|
|
23
|
+
"Collections that use the Content Layer API must have a `loader` defined and no `type` set.",
|
|
24
|
+
"Check your collection definitions in `src/content/config.*`.'"
|
|
25
|
+
);
|
|
26
|
+
}
|
|
27
|
+
config.type = CONTENT_LAYER_TYPE;
|
|
28
|
+
}
|
|
15
29
|
if (!config.type) config.type = "content";
|
|
16
30
|
return config;
|
|
17
31
|
}
|
|
@@ -37,11 +51,29 @@ function createGetCollection({
|
|
|
37
51
|
cacheEntriesByCollection
|
|
38
52
|
}) {
|
|
39
53
|
return async function getCollection(collection, filter) {
|
|
54
|
+
const hasFilter = typeof filter === "function";
|
|
55
|
+
const store = await globalDataStore.get();
|
|
40
56
|
let type;
|
|
41
57
|
if (collection in contentCollectionToEntryMap) {
|
|
42
58
|
type = "content";
|
|
43
59
|
} else if (collection in dataCollectionToEntryMap) {
|
|
44
60
|
type = "data";
|
|
61
|
+
} else if (store.hasCollection(collection)) {
|
|
62
|
+
const { default: imageAssetMap } = await import("astro:asset-imports");
|
|
63
|
+
const result = [];
|
|
64
|
+
for (const rawEntry of store.values(collection)) {
|
|
65
|
+
const data = rawEntry.filePath ? updateImageReferencesInData(rawEntry.data, rawEntry.filePath, imageAssetMap) : rawEntry.data;
|
|
66
|
+
const entry = {
|
|
67
|
+
...rawEntry,
|
|
68
|
+
data,
|
|
69
|
+
collection
|
|
70
|
+
};
|
|
71
|
+
if (hasFilter && !filter(entry)) {
|
|
72
|
+
continue;
|
|
73
|
+
}
|
|
74
|
+
result.push(entry);
|
|
75
|
+
}
|
|
76
|
+
return result;
|
|
45
77
|
} else {
|
|
46
78
|
console.warn(
|
|
47
79
|
`The collection ${JSON.stringify(
|
|
@@ -85,7 +117,7 @@ function createGetCollection({
|
|
|
85
117
|
);
|
|
86
118
|
cacheEntriesByCollection.set(collection, entries);
|
|
87
119
|
}
|
|
88
|
-
if (
|
|
120
|
+
if (hasFilter) {
|
|
89
121
|
return entries.filter(filter);
|
|
90
122
|
} else {
|
|
91
123
|
return entries.slice();
|
|
@@ -94,9 +126,21 @@ function createGetCollection({
|
|
|
94
126
|
}
|
|
95
127
|
function createGetEntryBySlug({
|
|
96
128
|
getEntryImport,
|
|
97
|
-
getRenderEntryImport
|
|
129
|
+
getRenderEntryImport,
|
|
130
|
+
collectionNames
|
|
98
131
|
}) {
|
|
99
132
|
return async function getEntryBySlug(collection, slug) {
|
|
133
|
+
const store = await globalDataStore.get();
|
|
134
|
+
if (!collectionNames.has(collection)) {
|
|
135
|
+
if (store.hasCollection(collection)) {
|
|
136
|
+
throw new AstroError({
|
|
137
|
+
...AstroErrorData.GetEntryDeprecationError,
|
|
138
|
+
message: AstroErrorData.GetEntryDeprecationError.message(collection, "getEntryBySlug")
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
console.warn(`The collection ${JSON.stringify(collection)} does not exist.`);
|
|
142
|
+
return void 0;
|
|
143
|
+
}
|
|
100
144
|
const entryImport = await getEntryImport(collection, slug);
|
|
101
145
|
if (typeof entryImport !== "function") return void 0;
|
|
102
146
|
const entry = await entryImport();
|
|
@@ -116,8 +160,22 @@ function createGetEntryBySlug({
|
|
|
116
160
|
};
|
|
117
161
|
};
|
|
118
162
|
}
|
|
119
|
-
function createGetDataEntryById({
|
|
163
|
+
function createGetDataEntryById({
|
|
164
|
+
getEntryImport,
|
|
165
|
+
collectionNames
|
|
166
|
+
}) {
|
|
120
167
|
return async function getDataEntryById(collection, id) {
|
|
168
|
+
const store = await globalDataStore.get();
|
|
169
|
+
if (!collectionNames.has(collection)) {
|
|
170
|
+
if (store.hasCollection(collection)) {
|
|
171
|
+
throw new AstroError({
|
|
172
|
+
...AstroErrorData.GetEntryDeprecationError,
|
|
173
|
+
message: AstroErrorData.GetEntryDeprecationError.message(collection, "getDataEntryById")
|
|
174
|
+
});
|
|
175
|
+
}
|
|
176
|
+
console.warn(`The collection ${JSON.stringify(collection)} does not exist.`);
|
|
177
|
+
return void 0;
|
|
178
|
+
}
|
|
121
179
|
const lazyImport = await getEntryImport(collection, id);
|
|
122
180
|
if (!lazyImport) throw new Error(`Entry ${collection} \u2192 ${id} was not found.`);
|
|
123
181
|
const entry = await lazyImport();
|
|
@@ -130,7 +188,8 @@ function createGetDataEntryById({ getEntryImport }) {
|
|
|
130
188
|
}
|
|
131
189
|
function createGetEntry({
|
|
132
190
|
getEntryImport,
|
|
133
|
-
getRenderEntryImport
|
|
191
|
+
getRenderEntryImport,
|
|
192
|
+
collectionNames
|
|
134
193
|
}) {
|
|
135
194
|
return async function getEntry(collectionOrLookupObject, _lookupId) {
|
|
136
195
|
let collection, lookupId;
|
|
@@ -146,6 +205,26 @@ function createGetEntry({
|
|
|
146
205
|
collection = collectionOrLookupObject.collection;
|
|
147
206
|
lookupId = "id" in collectionOrLookupObject ? collectionOrLookupObject.id : collectionOrLookupObject.slug;
|
|
148
207
|
}
|
|
208
|
+
const store = await globalDataStore.get();
|
|
209
|
+
if (store.hasCollection(collection)) {
|
|
210
|
+
const entry2 = store.get(collection, lookupId);
|
|
211
|
+
if (!entry2) {
|
|
212
|
+
console.warn(`Entry ${collection} \u2192 ${lookupId} was not found.`);
|
|
213
|
+
return;
|
|
214
|
+
}
|
|
215
|
+
if (entry2.filePath) {
|
|
216
|
+
const { default: imageAssetMap } = await import("astro:asset-imports");
|
|
217
|
+
entry2.data = updateImageReferencesInData(entry2.data, entry2.filePath, imageAssetMap);
|
|
218
|
+
}
|
|
219
|
+
return {
|
|
220
|
+
...entry2,
|
|
221
|
+
collection
|
|
222
|
+
};
|
|
223
|
+
}
|
|
224
|
+
if (!collectionNames.has(collection)) {
|
|
225
|
+
console.warn(`The collection ${JSON.stringify(collection)} does not exist.`);
|
|
226
|
+
return void 0;
|
|
227
|
+
}
|
|
149
228
|
const entryImport = await getEntryImport(collection, lookupId);
|
|
150
229
|
if (typeof entryImport !== "function") return void 0;
|
|
151
230
|
const entry = await entryImport();
|
|
@@ -179,6 +258,82 @@ function createGetEntries(getEntry) {
|
|
|
179
258
|
return Promise.all(entries.map((e) => getEntry(e)));
|
|
180
259
|
};
|
|
181
260
|
}
|
|
261
|
+
const CONTENT_LAYER_IMAGE_REGEX = /__ASTRO_IMAGE_="([^"]+)"/g;
|
|
262
|
+
async function updateImageReferencesInBody(html, fileName) {
|
|
263
|
+
const { default: imageAssetMap } = await import("astro:asset-imports");
|
|
264
|
+
const imageObjects = /* @__PURE__ */ new Map();
|
|
265
|
+
const { getImage } = await import("astro:assets");
|
|
266
|
+
for (const [_full, imagePath] of html.matchAll(CONTENT_LAYER_IMAGE_REGEX)) {
|
|
267
|
+
try {
|
|
268
|
+
const decodedImagePath = JSON.parse(imagePath.replaceAll(""", '"'));
|
|
269
|
+
const id = imageSrcToImportId(decodedImagePath.src, fileName);
|
|
270
|
+
const imported = imageAssetMap.get(id);
|
|
271
|
+
if (!id || imageObjects.has(id) || !imported) {
|
|
272
|
+
continue;
|
|
273
|
+
}
|
|
274
|
+
const image = await getImage({ ...decodedImagePath, src: imported });
|
|
275
|
+
imageObjects.set(imagePath, image);
|
|
276
|
+
} catch {
|
|
277
|
+
throw new Error(`Failed to parse image reference: ${imagePath}`);
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
return html.replaceAll(CONTENT_LAYER_IMAGE_REGEX, (full, imagePath) => {
|
|
281
|
+
const image = imageObjects.get(imagePath);
|
|
282
|
+
if (!image) {
|
|
283
|
+
return full;
|
|
284
|
+
}
|
|
285
|
+
const { index, ...attributes } = image.attributes;
|
|
286
|
+
return Object.entries({
|
|
287
|
+
...attributes,
|
|
288
|
+
src: image.src,
|
|
289
|
+
srcset: image.srcSet.attribute
|
|
290
|
+
}).map(([key, value]) => value ? `${key}=${JSON.stringify(String(value))}` : "").join(" ");
|
|
291
|
+
});
|
|
292
|
+
}
|
|
293
|
+
function updateImageReferencesInData(data, fileName, imageAssetMap) {
|
|
294
|
+
return new Traverse(data).map(function(ctx, val) {
|
|
295
|
+
if (typeof val === "string" && val.startsWith(IMAGE_IMPORT_PREFIX)) {
|
|
296
|
+
const src = val.replace(IMAGE_IMPORT_PREFIX, "");
|
|
297
|
+
const id = imageSrcToImportId(src, fileName);
|
|
298
|
+
if (!id) {
|
|
299
|
+
ctx.update(src);
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
302
|
+
const imported = imageAssetMap.get(id);
|
|
303
|
+
if (imported) {
|
|
304
|
+
ctx.update(imported);
|
|
305
|
+
} else {
|
|
306
|
+
ctx.update(src);
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
});
|
|
310
|
+
}
|
|
311
|
+
async function renderEntry(entry) {
|
|
312
|
+
if (entry && "render" in entry) {
|
|
313
|
+
return entry.render();
|
|
314
|
+
}
|
|
315
|
+
if (entry.deferredRender) {
|
|
316
|
+
try {
|
|
317
|
+
const { default: contentModules } = await import("astro:content-module-imports");
|
|
318
|
+
const module = contentModules.get(entry.filePath);
|
|
319
|
+
const deferredMod = await module();
|
|
320
|
+
return {
|
|
321
|
+
Content: deferredMod.Content,
|
|
322
|
+
headings: deferredMod.getHeadings?.() ?? [],
|
|
323
|
+
remarkPluginFrontmatter: deferredMod.frontmatter ?? {}
|
|
324
|
+
};
|
|
325
|
+
} catch (e) {
|
|
326
|
+
console.error(e);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
const html = entry?.rendered?.metadata?.imagePaths?.length && entry.filePath ? await updateImageReferencesInBody(entry.rendered.html, entry.filePath) : entry?.rendered?.html;
|
|
330
|
+
const Content = createComponent(() => serverRender`${unescapeHTML(html)}`);
|
|
331
|
+
return {
|
|
332
|
+
Content,
|
|
333
|
+
headings: entry?.rendered?.metadata?.headings ?? [],
|
|
334
|
+
remarkPluginFrontmatter: entry?.rendered?.metadata?.frontmatter ?? {}
|
|
335
|
+
};
|
|
336
|
+
}
|
|
182
337
|
async function render({
|
|
183
338
|
collection,
|
|
184
339
|
id,
|
|
@@ -256,31 +411,69 @@ async function render({
|
|
|
256
411
|
}
|
|
257
412
|
function createReference({ lookupMap }) {
|
|
258
413
|
return function reference(collection) {
|
|
259
|
-
return
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
ctx.
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
414
|
+
return z.union([
|
|
415
|
+
z.string(),
|
|
416
|
+
z.object({
|
|
417
|
+
id: z.string(),
|
|
418
|
+
collection: z.string()
|
|
419
|
+
}),
|
|
420
|
+
z.object({
|
|
421
|
+
slug: z.string(),
|
|
422
|
+
collection: z.string()
|
|
423
|
+
})
|
|
424
|
+
]).transform(
|
|
425
|
+
async (lookup, ctx) => {
|
|
426
|
+
const flattenedErrorPath = ctx.path.join(".");
|
|
427
|
+
const store = await globalDataStore.get();
|
|
428
|
+
const collectionIsInStore = store.hasCollection(collection);
|
|
429
|
+
if (typeof lookup === "object") {
|
|
430
|
+
if (lookup.collection !== collection) {
|
|
431
|
+
ctx.addIssue({
|
|
432
|
+
code: ZodIssueCode.custom,
|
|
433
|
+
message: `**${flattenedErrorPath}**: Reference to ${collection} invalid. Expected ${collection}. Received ${lookup.collection}.`
|
|
434
|
+
});
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
if (!lookupMap[collection] && !collectionIsInStore) {
|
|
438
|
+
ctx.addIssue({
|
|
439
|
+
code: ZodIssueCode.custom,
|
|
440
|
+
message: `**${flattenedErrorPath}:** Reference to ${collection} invalid. Collection does not exist or is empty.`
|
|
441
|
+
});
|
|
442
|
+
return;
|
|
443
|
+
}
|
|
444
|
+
return lookup;
|
|
445
|
+
}
|
|
446
|
+
if (collectionIsInStore) {
|
|
447
|
+
const entry2 = store.get(collection, lookup);
|
|
448
|
+
if (!entry2) {
|
|
449
|
+
ctx.addIssue({
|
|
450
|
+
code: ZodIssueCode.custom,
|
|
451
|
+
message: `**${flattenedErrorPath}**: Reference to ${collection} invalid. Entry ${lookup} does not exist.`
|
|
452
|
+
});
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
return { id: lookup, collection };
|
|
456
|
+
}
|
|
457
|
+
if (!lookupMap[collection] && store.collections().size === 0) {
|
|
458
|
+
return { id: lookup, collection };
|
|
459
|
+
}
|
|
460
|
+
const { type, entries } = lookupMap[collection];
|
|
461
|
+
const entry = entries[lookup];
|
|
462
|
+
if (!entry) {
|
|
463
|
+
ctx.addIssue({
|
|
464
|
+
code: ZodIssueCode.custom,
|
|
465
|
+
message: `**${flattenedErrorPath}**: Reference to ${collection} invalid. Expected ${Object.keys(
|
|
466
|
+
entries
|
|
467
|
+
).map((c) => JSON.stringify(c)).join(" | ")}. Received ${JSON.stringify(lookup)}.`
|
|
468
|
+
});
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
if (type === "content") {
|
|
472
|
+
return { slug: lookup, collection };
|
|
473
|
+
}
|
|
474
|
+
return { id: lookup, collection };
|
|
281
475
|
}
|
|
282
|
-
|
|
283
|
-
});
|
|
476
|
+
);
|
|
284
477
|
};
|
|
285
478
|
}
|
|
286
479
|
function isPropagatedAssetsModule(module) {
|
|
@@ -294,5 +487,6 @@ export {
|
|
|
294
487
|
createGetEntry,
|
|
295
488
|
createGetEntryBySlug,
|
|
296
489
|
createReference,
|
|
297
|
-
defineCollection
|
|
490
|
+
defineCollection,
|
|
491
|
+
renderEntry
|
|
298
492
|
};
|
|
@@ -5,10 +5,11 @@ import { bold, cyan } from "kleur/colors";
|
|
|
5
5
|
import { normalizePath } from "vite";
|
|
6
6
|
import { z } from "zod";
|
|
7
7
|
import { zodToJsonSchema } from "zod-to-json-schema";
|
|
8
|
+
import { printNode, zodToTs } from "zod-to-ts";
|
|
8
9
|
import { AstroError } from "../core/errors/errors.js";
|
|
9
10
|
import { AstroErrorData } from "../core/errors/index.js";
|
|
10
11
|
import { isRelativePath } from "../core/path.js";
|
|
11
|
-
import { CONTENT_TYPES_FILE, VIRTUAL_MODULE_ID } from "./consts.js";
|
|
12
|
+
import { CONTENT_LAYER_TYPE, CONTENT_TYPES_FILE, VIRTUAL_MODULE_ID } from "./consts.js";
|
|
12
13
|
import {
|
|
13
14
|
getContentEntryIdAndSlug,
|
|
14
15
|
getContentPaths,
|
|
@@ -269,6 +270,36 @@ function normalizeConfigPath(from, to) {
|
|
|
269
270
|
const normalizedPath = configPath.replaceAll("\\", "/");
|
|
270
271
|
return `"${isRelativePath(configPath) ? "" : "./"}${normalizedPath}"`;
|
|
271
272
|
}
|
|
273
|
+
const schemaCache = /* @__PURE__ */ new Map();
|
|
274
|
+
async function getContentLayerSchema(collection, collectionKey) {
|
|
275
|
+
const cached = schemaCache.get(collectionKey);
|
|
276
|
+
if (cached) {
|
|
277
|
+
return cached;
|
|
278
|
+
}
|
|
279
|
+
if (collection?.type === CONTENT_LAYER_TYPE && typeof collection.loader === "object" && collection.loader.schema) {
|
|
280
|
+
let schema = collection.loader.schema;
|
|
281
|
+
if (typeof schema === "function") {
|
|
282
|
+
schema = await schema();
|
|
283
|
+
}
|
|
284
|
+
if (schema) {
|
|
285
|
+
schemaCache.set(collectionKey, await schema);
|
|
286
|
+
return schema;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
async function typeForCollection(collection, collectionKey) {
|
|
291
|
+
if (collection?.schema) {
|
|
292
|
+
return `InferEntrySchema<${collectionKey}>`;
|
|
293
|
+
}
|
|
294
|
+
if (collection?.type === CONTENT_LAYER_TYPE) {
|
|
295
|
+
const schema = await getContentLayerSchema(collection, collectionKey);
|
|
296
|
+
if (schema) {
|
|
297
|
+
const ast = zodToTs(schema);
|
|
298
|
+
return printNode(ast.node);
|
|
299
|
+
}
|
|
300
|
+
}
|
|
301
|
+
return "any";
|
|
302
|
+
}
|
|
272
303
|
async function writeContentFiles({
|
|
273
304
|
fs,
|
|
274
305
|
contentPaths,
|
|
@@ -292,10 +323,11 @@ async function writeContentFiles({
|
|
|
292
323
|
entries: {}
|
|
293
324
|
};
|
|
294
325
|
}
|
|
326
|
+
let contentCollectionsMap = {};
|
|
295
327
|
for (const collectionKey of Object.keys(collectionEntryMap).sort()) {
|
|
296
328
|
const collectionConfig = contentConfig?.collections[JSON.parse(collectionKey)];
|
|
297
329
|
const collection = collectionEntryMap[collectionKey];
|
|
298
|
-
if (collectionConfig?.type && collection.type !== "unknown" && collection.type !== collectionConfig.type) {
|
|
330
|
+
if (collectionConfig?.type && collection.type !== "unknown" && collectionConfig.type !== CONTENT_LAYER_TYPE && collection.type !== collectionConfig.type) {
|
|
299
331
|
viteServer.hot.send({
|
|
300
332
|
type: "error",
|
|
301
333
|
err: new AstroError({
|
|
@@ -319,7 +351,7 @@ async function writeContentFiles({
|
|
|
319
351
|
collectionConfig?.type ?? "data"
|
|
320
352
|
) : collection.type;
|
|
321
353
|
const collectionEntryKeys = Object.keys(collection.entries).sort();
|
|
322
|
-
const dataType = collectionConfig
|
|
354
|
+
const dataType = await typeForCollection(collectionConfig, collectionKey);
|
|
323
355
|
switch (resolvedType) {
|
|
324
356
|
case "content":
|
|
325
357
|
if (collectionEntryKeys.length === 0) {
|
|
@@ -352,6 +384,15 @@ async function writeContentFiles({
|
|
|
352
384
|
`;
|
|
353
385
|
}
|
|
354
386
|
contentTypesStr += `};
|
|
387
|
+
`;
|
|
388
|
+
break;
|
|
389
|
+
case CONTENT_LAYER_TYPE:
|
|
390
|
+
dataTypesStr += `${collectionKey}: Record<string, {
|
|
391
|
+
id: string;
|
|
392
|
+
collection: ${collectionKey};
|
|
393
|
+
data: ${dataType};
|
|
394
|
+
rendered?: RenderedContent
|
|
395
|
+
}>;
|
|
355
396
|
`;
|
|
356
397
|
break;
|
|
357
398
|
case "data":
|
|
@@ -377,42 +418,51 @@ async function writeContentFiles({
|
|
|
377
418
|
`;
|
|
378
419
|
}
|
|
379
420
|
if (collectionConfig?.schema) {
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
await fs.promises.writeFile(
|
|
388
|
-
new URL(`./${collectionKey.replace(/"/g, "")}.schema.json`, collectionSchemasDir),
|
|
389
|
-
JSON.stringify(
|
|
390
|
-
zodToJsonSchema(zodSchemaForJson, {
|
|
391
|
-
name: collectionKey.replace(/"/g, ""),
|
|
392
|
-
markdownDescription: true,
|
|
393
|
-
errorMessages: true,
|
|
394
|
-
// Fix for https://github.com/StefanTerdell/zod-to-json-schema/issues/110
|
|
395
|
-
dateStrategy: ["format:date-time", "format:date", "integer"]
|
|
396
|
-
}),
|
|
397
|
-
null,
|
|
398
|
-
2
|
|
399
|
-
)
|
|
400
|
-
);
|
|
401
|
-
} catch (err) {
|
|
402
|
-
logger.warn(
|
|
403
|
-
"content",
|
|
404
|
-
`An error was encountered while creating the JSON schema for the ${collectionKey} collection. Proceeding without it. Error: ${err}`
|
|
405
|
-
);
|
|
406
|
-
}
|
|
421
|
+
await generateJSONSchema(
|
|
422
|
+
fs,
|
|
423
|
+
collectionConfig,
|
|
424
|
+
collectionKey,
|
|
425
|
+
collectionSchemasDir,
|
|
426
|
+
logger
|
|
427
|
+
);
|
|
407
428
|
}
|
|
408
429
|
break;
|
|
409
430
|
}
|
|
431
|
+
if (settings.config.experimental.contentIntellisense && collectionConfig && (collectionConfig.schema || await getContentLayerSchema(collectionConfig, collectionKey))) {
|
|
432
|
+
await generateJSONSchema(fs, collectionConfig, collectionKey, collectionSchemasDir, logger);
|
|
433
|
+
contentCollectionsMap[collectionKey] = collection;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
if (settings.config.experimental.contentIntellisense) {
|
|
437
|
+
let contentCollectionManifest = {
|
|
438
|
+
collections: [],
|
|
439
|
+
entries: {}
|
|
440
|
+
};
|
|
441
|
+
Object.entries(contentCollectionsMap).forEach(([collectionKey, collection]) => {
|
|
442
|
+
const collectionConfig = contentConfig?.collections[JSON.parse(collectionKey)];
|
|
443
|
+
const key = JSON.parse(collectionKey);
|
|
444
|
+
contentCollectionManifest.collections.push({
|
|
445
|
+
hasSchema: Boolean(collectionConfig?.schema || schemaCache.has(collectionKey)),
|
|
446
|
+
name: key
|
|
447
|
+
});
|
|
448
|
+
Object.keys(collection.entries).forEach((entryKey) => {
|
|
449
|
+
const entryPath = new URL(
|
|
450
|
+
JSON.parse(entryKey),
|
|
451
|
+
contentPaths.contentDir + `${key}/`
|
|
452
|
+
).toString();
|
|
453
|
+
contentCollectionManifest.entries[entryPath.toLowerCase()] = key;
|
|
454
|
+
});
|
|
455
|
+
});
|
|
456
|
+
await fs.promises.writeFile(
|
|
457
|
+
new URL("./collections.json", collectionSchemasDir),
|
|
458
|
+
JSON.stringify(contentCollectionManifest, null, 2)
|
|
459
|
+
);
|
|
410
460
|
}
|
|
411
461
|
if (!fs.existsSync(settings.dotAstroDir)) {
|
|
412
462
|
fs.mkdirSync(settings.dotAstroDir, { recursive: true });
|
|
413
463
|
}
|
|
414
464
|
const configPathRelativeToCacheDir = normalizeConfigPath(
|
|
415
|
-
settings.dotAstroDir.pathname,
|
|
465
|
+
new URL("astro", settings.dotAstroDir).pathname,
|
|
416
466
|
contentPaths.config.url.pathname
|
|
417
467
|
);
|
|
418
468
|
for (const contentEntryType of contentEntryTypes) {
|
|
@@ -426,10 +476,48 @@ async function writeContentFiles({
|
|
|
426
476
|
"'@@CONTENT_CONFIG_TYPE@@'",
|
|
427
477
|
contentConfig ? `typeof import(${configPathRelativeToCacheDir})` : "never"
|
|
428
478
|
);
|
|
429
|
-
|
|
430
|
-
new URL(CONTENT_TYPES_FILE, settings.dotAstroDir)
|
|
431
|
-
|
|
432
|
-
|
|
479
|
+
if (settings.injectedTypes.some((t) => t.filename === CONTENT_TYPES_FILE)) {
|
|
480
|
+
const filePath = fileURLToPath(new URL(CONTENT_TYPES_FILE, settings.dotAstroDir));
|
|
481
|
+
await fs.promises.mkdir(path.dirname(filePath), { recursive: true });
|
|
482
|
+
await fs.promises.writeFile(filePath, typeTemplateContent, "utf-8");
|
|
483
|
+
} else {
|
|
484
|
+
settings.injectedTypes.push({
|
|
485
|
+
filename: CONTENT_TYPES_FILE,
|
|
486
|
+
content: typeTemplateContent
|
|
487
|
+
});
|
|
488
|
+
}
|
|
489
|
+
}
|
|
490
|
+
async function generateJSONSchema(fsMod, collectionConfig, collectionKey, collectionSchemasDir, logger) {
|
|
491
|
+
let zodSchemaForJson = typeof collectionConfig.schema === "function" ? collectionConfig.schema({ image: () => z.string() }) : collectionConfig.schema;
|
|
492
|
+
if (!zodSchemaForJson && collectionConfig.type === CONTENT_LAYER_TYPE) {
|
|
493
|
+
zodSchemaForJson = await getContentLayerSchema(collectionConfig, collectionKey);
|
|
494
|
+
}
|
|
495
|
+
if (zodSchemaForJson instanceof z.ZodObject) {
|
|
496
|
+
zodSchemaForJson = zodSchemaForJson.extend({
|
|
497
|
+
$schema: z.string().optional()
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
try {
|
|
501
|
+
await fsMod.promises.writeFile(
|
|
502
|
+
new URL(`./${collectionKey.replace(/"/g, "")}.schema.json`, collectionSchemasDir),
|
|
503
|
+
JSON.stringify(
|
|
504
|
+
zodToJsonSchema(zodSchemaForJson, {
|
|
505
|
+
name: collectionKey.replace(/"/g, ""),
|
|
506
|
+
markdownDescription: true,
|
|
507
|
+
errorMessages: true,
|
|
508
|
+
// Fix for https://github.com/StefanTerdell/zod-to-json-schema/issues/110
|
|
509
|
+
dateStrategy: ["format:date-time", "format:date", "integer"]
|
|
510
|
+
}),
|
|
511
|
+
null,
|
|
512
|
+
2
|
|
513
|
+
)
|
|
514
|
+
);
|
|
515
|
+
} catch (err) {
|
|
516
|
+
logger.warn(
|
|
517
|
+
"content",
|
|
518
|
+
`An error was encountered while creating the JSON schema for the ${collectionKey} collection. Proceeding without it. Error: ${err}`
|
|
519
|
+
);
|
|
520
|
+
}
|
|
433
521
|
}
|
|
434
522
|
export {
|
|
435
523
|
createContentTypesGenerator
|