astro 2.4.4 → 2.5.0
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/astro-jsx.d.ts +5 -1
- package/dist/@types/astro.d.ts +130 -6
- package/dist/assets/generate.d.ts +22 -0
- package/dist/assets/generate.js +90 -0
- package/dist/assets/internal.d.ts +0 -21
- package/dist/assets/internal.js +0 -86
- package/dist/assets/vite-plugin-assets.js +13 -2
- package/dist/content/consts.d.ts +3 -1
- package/dist/content/consts.js +5 -1
- package/dist/content/runtime-assets.d.ts +1 -1
- package/dist/content/runtime.d.ts +61 -7
- package/dist/content/runtime.js +127 -4
- package/dist/content/template/virtual-mod.d.mts +4 -1
- package/dist/content/types-generator.js +155 -80
- package/dist/content/utils.d.ts +76 -23
- package/dist/content/utils.js +129 -65
- package/dist/content/vite-plugin-content-imports.js +110 -25
- package/dist/content/vite-plugin-content-virtual-mod.d.ts +4 -3
- package/dist/content/vite-plugin-content-virtual-mod.js +89 -45
- package/dist/core/app/common.js +2 -0
- package/dist/core/app/index.js +6 -4
- package/dist/core/app/types.d.ts +6 -1
- package/dist/core/build/generate.js +8 -9
- package/dist/core/build/index.d.ts +1 -1
- package/dist/core/build/plugins/plugin-pages.d.ts +0 -2
- package/dist/core/build/plugins/plugin-pages.js +3 -4
- package/dist/core/build/plugins/plugin-prerender.d.ts +0 -2
- package/dist/core/build/plugins/plugin-prerender.js +2 -2
- package/dist/core/build/plugins/plugin-ssr.d.ts +1 -4
- package/dist/core/build/plugins/plugin-ssr.js +4 -3
- package/dist/core/build/static-build.js +9 -7
- package/dist/core/client-directive/build.d.ts +4 -0
- package/dist/core/client-directive/build.js +28 -0
- package/dist/core/client-directive/default.d.ts +1 -0
- package/dist/core/client-directive/default.js +17 -0
- package/dist/core/client-directive/index.d.ts +2 -0
- package/dist/core/client-directive/index.js +6 -0
- package/dist/core/compile/compile.js +1 -0
- package/dist/core/config/config.js +6 -0
- package/dist/core/config/schema.d.ts +68 -12
- package/dist/core/config/schema.js +29 -3
- package/dist/core/config/settings.js +74 -2
- package/dist/core/config/vite-load.js +2 -1
- package/dist/core/constants.js +1 -1
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/endpoint/dev/index.js +1 -1
- package/dist/core/endpoint/index.d.ts +1 -1
- package/dist/core/endpoint/index.js +16 -16
- package/dist/core/errors/errors-data.d.ts +55 -4
- package/dist/core/errors/errors-data.js +67 -7
- package/dist/core/errors/errors.d.ts +1 -0
- package/dist/core/errors/errors.js +5 -1
- package/dist/core/errors/index.d.ts +1 -1
- package/dist/core/errors/index.js +9 -1
- package/dist/core/errors/utils.d.ts +5 -0
- package/dist/core/errors/utils.js +14 -0
- package/dist/core/messages.js +2 -2
- package/dist/core/middleware/callMiddleware.d.ts +2 -1
- package/dist/core/middleware/callMiddleware.js +13 -3
- package/dist/core/render/core.js +1 -0
- package/dist/core/render/dev/environment.js +3 -1
- package/dist/core/render/dev/index.js +1 -1
- package/dist/core/render/environment.d.ts +1 -0
- package/dist/core/render/environment.js +2 -0
- package/dist/core/render/result.d.ts +1 -0
- package/dist/core/render/result.js +3 -2
- package/dist/core/routing/manifest/create.js +9 -2
- package/dist/core/sync/index.js +11 -1
- package/dist/core/util.js +2 -1
- package/dist/integrations/index.js +29 -3
- package/dist/jsx/babel.js +1 -2
- package/dist/prerender/utils.d.ts +3 -0
- package/dist/prerender/utils.js +10 -0
- package/dist/runtime/client/idle.d.ts +3 -0
- package/dist/runtime/client/idle.js +6 -3
- package/dist/runtime/client/idle.prebuilt.d.ts +1 -1
- package/dist/runtime/client/idle.prebuilt.js +1 -1
- package/dist/runtime/client/load.d.ts +3 -0
- package/dist/runtime/client/load.js +7 -6
- package/dist/runtime/client/load.prebuilt.d.ts +1 -1
- package/dist/runtime/client/load.prebuilt.js +1 -1
- package/dist/runtime/client/media.d.ts +6 -0
- package/dist/runtime/client/media.js +6 -3
- package/dist/runtime/client/media.prebuilt.d.ts +1 -1
- package/dist/runtime/client/media.prebuilt.js +1 -1
- package/dist/runtime/client/only.d.ts +6 -0
- package/dist/runtime/client/only.js +7 -6
- package/dist/runtime/client/only.prebuilt.d.ts +1 -1
- package/dist/runtime/client/only.prebuilt.js +1 -1
- package/dist/runtime/client/visible.d.ts +8 -0
- package/dist/runtime/client/visible.js +9 -6
- package/dist/runtime/client/visible.prebuilt.d.ts +1 -1
- package/dist/runtime/client/visible.prebuilt.js +1 -1
- package/dist/runtime/server/astro-island.prebuilt.d.ts +1 -1
- package/dist/runtime/server/astro-island.prebuilt.js +1 -1
- package/dist/runtime/server/endpoint.js +1 -1
- package/dist/runtime/server/hydration.d.ts +1 -2
- package/dist/runtime/server/hydration.js +4 -9
- package/dist/runtime/server/render/astro/instance.js +1 -2
- package/dist/runtime/server/render/astro/render-template.d.ts +1 -1
- package/dist/runtime/server/render/astro/render-template.js +10 -2
- package/dist/runtime/server/render/common.js +1 -1
- package/dist/runtime/server/render/component.js +20 -6
- package/dist/runtime/server/render/page.js +5 -0
- package/dist/runtime/server/render/util.d.ts +12 -0
- package/dist/runtime/server/render/util.js +89 -1
- package/dist/runtime/server/scripts.d.ts +1 -2
- package/dist/runtime/server/scripts.js +13 -21
- package/dist/vite-plugin-astro-server/request.js +2 -1
- package/dist/vite-plugin-astro-server/route.js +4 -3
- package/dist/vite-plugin-config-alias/index.js +13 -11
- package/dist/vite-plugin-jsx/index.js +1 -1
- package/dist/vite-plugin-scanner/index.js +6 -1
- package/dist/vite-plugin-scanner/scan.d.ts +1 -1
- package/dist/vite-plugin-scanner/scan.js +2 -2
- package/package.json +5 -3
- package/src/content/template/types.d.ts +108 -15
- package/src/content/template/virtual-mod.mjs +40 -16
- package/types.d.ts +6 -3
package/dist/content/utils.d.ts
CHANGED
|
@@ -5,32 +5,78 @@ import type { PluginContext } from 'rollup';
|
|
|
5
5
|
import { type ViteDevServer } from 'vite';
|
|
6
6
|
import { z } from 'zod';
|
|
7
7
|
import type { AstroConfig, AstroSettings, ContentEntryType } from '../@types/astro.js';
|
|
8
|
-
|
|
8
|
+
import { CONTENT_FLAGS } from './consts.js';
|
|
9
|
+
/**
|
|
10
|
+
* Amap from a collection + slug to the local file path.
|
|
11
|
+
* This is used internally to resolve entry imports when using `getEntry()`.
|
|
12
|
+
* @see `src/content/virtual-mod.mjs`
|
|
13
|
+
*/
|
|
14
|
+
export type ContentLookupMap = {
|
|
15
|
+
[collectionName: string]: {
|
|
16
|
+
type: 'content' | 'data';
|
|
17
|
+
entries: {
|
|
18
|
+
[lookupId: string]: string;
|
|
19
|
+
};
|
|
20
|
+
};
|
|
21
|
+
};
|
|
22
|
+
export declare const collectionConfigParser: z.ZodUnion<[z.ZodObject<{
|
|
23
|
+
type: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"content">>>;
|
|
9
24
|
schema: z.ZodOptional<z.ZodAny>;
|
|
10
25
|
}, "strip", z.ZodTypeAny, {
|
|
11
26
|
schema?: any;
|
|
27
|
+
type: "content";
|
|
12
28
|
}, {
|
|
29
|
+
type?: "content" | undefined;
|
|
13
30
|
schema?: any;
|
|
14
|
-
}
|
|
31
|
+
}>, z.ZodObject<{
|
|
32
|
+
type: z.ZodLiteral<"data">;
|
|
33
|
+
schema: z.ZodOptional<z.ZodAny>;
|
|
34
|
+
}, "strip", z.ZodTypeAny, {
|
|
35
|
+
schema?: any;
|
|
36
|
+
type: "data";
|
|
37
|
+
}, {
|
|
38
|
+
schema?: any;
|
|
39
|
+
type: "data";
|
|
40
|
+
}>]>;
|
|
15
41
|
export declare function getDotAstroTypeReference({ root, srcDir }: {
|
|
16
42
|
root: URL;
|
|
17
43
|
srcDir: URL;
|
|
18
44
|
}): string;
|
|
19
45
|
export declare const contentConfigParser: z.ZodObject<{
|
|
20
|
-
collections: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
46
|
+
collections: z.ZodRecord<z.ZodString, z.ZodUnion<[z.ZodObject<{
|
|
47
|
+
type: z.ZodDefault<z.ZodOptional<z.ZodLiteral<"content">>>;
|
|
21
48
|
schema: z.ZodOptional<z.ZodAny>;
|
|
22
49
|
}, "strip", z.ZodTypeAny, {
|
|
23
50
|
schema?: any;
|
|
51
|
+
type: "content";
|
|
24
52
|
}, {
|
|
53
|
+
type?: "content" | undefined;
|
|
25
54
|
schema?: any;
|
|
26
|
-
}
|
|
55
|
+
}>, z.ZodObject<{
|
|
56
|
+
type: z.ZodLiteral<"data">;
|
|
57
|
+
schema: z.ZodOptional<z.ZodAny>;
|
|
58
|
+
}, "strip", z.ZodTypeAny, {
|
|
59
|
+
schema?: any;
|
|
60
|
+
type: "data";
|
|
61
|
+
}, {
|
|
62
|
+
schema?: any;
|
|
63
|
+
type: "data";
|
|
64
|
+
}>]>>;
|
|
27
65
|
}, "strip", z.ZodTypeAny, {
|
|
28
66
|
collections: Record<string, {
|
|
29
67
|
schema?: any;
|
|
68
|
+
type: "content";
|
|
69
|
+
} | {
|
|
70
|
+
schema?: any;
|
|
71
|
+
type: "data";
|
|
30
72
|
}>;
|
|
31
73
|
}, {
|
|
32
74
|
collections: Record<string, {
|
|
75
|
+
type?: "content" | undefined;
|
|
33
76
|
schema?: any;
|
|
77
|
+
} | {
|
|
78
|
+
schema?: any;
|
|
79
|
+
type: "data";
|
|
34
80
|
}>;
|
|
35
81
|
}>;
|
|
36
82
|
export type CollectionConfig = z.infer<typeof collectionConfigParser>;
|
|
@@ -39,11 +85,6 @@ type EntryInternal = {
|
|
|
39
85
|
rawData: string | undefined;
|
|
40
86
|
filePath: string;
|
|
41
87
|
};
|
|
42
|
-
export type EntryInfo = {
|
|
43
|
-
id: string;
|
|
44
|
-
slug: string;
|
|
45
|
-
collection: string;
|
|
46
|
-
};
|
|
47
88
|
export declare const msg: {
|
|
48
89
|
collectionConfigMissing: (collection: string) => string;
|
|
49
90
|
};
|
|
@@ -53,26 +94,31 @@ export declare function parseEntrySlug({ id, collection, generatedSlug, frontmat
|
|
|
53
94
|
generatedSlug: string;
|
|
54
95
|
frontmatterSlug?: unknown;
|
|
55
96
|
}): string;
|
|
56
|
-
export declare function getEntryData(entry:
|
|
97
|
+
export declare function getEntryData(entry: {
|
|
98
|
+
id: string;
|
|
99
|
+
collection: string;
|
|
57
100
|
unvalidatedData: Record<string, unknown>;
|
|
58
101
|
_internal: EntryInternal;
|
|
59
|
-
}, collectionConfig: CollectionConfig, pluginContext: PluginContext,
|
|
60
|
-
[x: string]: unknown;
|
|
61
|
-
}>;
|
|
102
|
+
}, collectionConfig: CollectionConfig, pluginContext: PluginContext, config: AstroConfig): Promise<any>;
|
|
62
103
|
export declare function getContentEntryExts(settings: Pick<AstroSettings, 'contentEntryTypes'>): string[];
|
|
104
|
+
export declare function getDataEntryExts(settings: Pick<AstroSettings, 'dataEntryTypes'>): string[];
|
|
63
105
|
export declare function getContentEntryConfigByExtMap(settings: Pick<AstroSettings, 'contentEntryTypes'>): Map<string, ContentEntryType>;
|
|
64
|
-
export declare
|
|
65
|
-
}
|
|
66
|
-
export declare function getEntryInfo(params: Pick<ContentPaths, 'contentDir'> & {
|
|
106
|
+
export declare function getEntryCollectionName({ contentDir, entry, }: Pick<ContentPaths, 'contentDir'> & {
|
|
67
107
|
entry: string | URL;
|
|
68
|
-
|
|
69
|
-
}
|
|
70
|
-
|
|
108
|
+
}): string | undefined;
|
|
109
|
+
export declare function getDataEntryId({ entry, contentDir, collection, }: Pick<ContentPaths, 'contentDir'> & {
|
|
110
|
+
entry: URL;
|
|
111
|
+
collection: string;
|
|
112
|
+
}): string;
|
|
113
|
+
export declare function getContentEntryIdAndSlug({ entry, contentDir, collection, }: Pick<ContentPaths, 'contentDir'> & {
|
|
114
|
+
entry: URL;
|
|
115
|
+
collection: string;
|
|
116
|
+
}): {
|
|
117
|
+
id: string;
|
|
118
|
+
slug: string;
|
|
119
|
+
};
|
|
120
|
+
export declare function getEntryType(entryPath: string, paths: Pick<ContentPaths, 'config' | 'contentDir'>, contentFileExts: string[], dataFileExts: string[], experimentalAssets?: boolean): 'content' | 'data' | 'config' | 'ignored' | 'unsupported';
|
|
71
121
|
export declare function hasUnderscoreBelowContentDirectoryPath(fileUrl: URL, contentDir: ContentPaths['contentDir']): boolean;
|
|
72
|
-
/**
|
|
73
|
-
* Match YAML exception handling from Astro core errors
|
|
74
|
-
* @see 'astro/src/core/errors.ts'
|
|
75
|
-
*/
|
|
76
122
|
export declare function parseFrontmatter(fileContents: string, filePath: string): matter.GrayMatterFile<string>;
|
|
77
123
|
/**
|
|
78
124
|
* The content config is loaded separately from other `src/` files.
|
|
@@ -80,11 +126,18 @@ export declare function parseFrontmatter(fileContents: string, filePath: string)
|
|
|
80
126
|
* subscribe to changes during dev server updates.
|
|
81
127
|
*/
|
|
82
128
|
export declare const globalContentConfigObserver: ContentObservable;
|
|
129
|
+
export declare function hasContentFlag(viteId: string, flag: (typeof CONTENT_FLAGS)[number]): boolean;
|
|
83
130
|
export declare function loadContentConfig({ fs, settings, viteServer, }: {
|
|
84
131
|
fs: typeof fsMod;
|
|
85
132
|
settings: AstroSettings;
|
|
86
133
|
viteServer: ViteDevServer;
|
|
87
134
|
}): Promise<ContentConfig | undefined>;
|
|
135
|
+
export declare function reloadContentConfigObserver({ observer, ...loadContentConfigOpts }: {
|
|
136
|
+
fs: typeof fsMod;
|
|
137
|
+
settings: AstroSettings;
|
|
138
|
+
viteServer: ViteDevServer;
|
|
139
|
+
observer?: ContentObservable;
|
|
140
|
+
}): Promise<void>;
|
|
88
141
|
type ContentCtx = {
|
|
89
142
|
status: 'init';
|
|
90
143
|
} | {
|
package/dist/content/utils.js
CHANGED
|
@@ -7,12 +7,20 @@ import { normalizePath } from "vite";
|
|
|
7
7
|
import { z } from "zod";
|
|
8
8
|
import { VALID_INPUT_FORMATS } from "../assets/consts.js";
|
|
9
9
|
import { AstroError, AstroErrorData } from "../core/errors/index.js";
|
|
10
|
+
import { formatYAMLException, isYAMLException } from "../core/errors/utils.js";
|
|
10
11
|
import { CONTENT_TYPES_FILE } from "./consts.js";
|
|
11
12
|
import { errorMap } from "./error-map.js";
|
|
12
13
|
import { createImage } from "./runtime-assets.js";
|
|
13
|
-
const collectionConfigParser = z.
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const collectionConfigParser = z.union([
|
|
15
|
+
z.object({
|
|
16
|
+
type: z.literal("content").optional().default("content"),
|
|
17
|
+
schema: z.any().optional()
|
|
18
|
+
}),
|
|
19
|
+
z.object({
|
|
20
|
+
type: z.literal("data"),
|
|
21
|
+
schema: z.any().optional()
|
|
22
|
+
})
|
|
23
|
+
]);
|
|
16
24
|
function getDotAstroTypeReference({ root, srcDir }) {
|
|
17
25
|
const { cacheDir } = getContentPaths({ root, srcDir });
|
|
18
26
|
const contentTypesRelativeToSrcDir = normalizePath(
|
|
@@ -41,48 +49,60 @@ function parseEntrySlug({
|
|
|
41
49
|
});
|
|
42
50
|
}
|
|
43
51
|
}
|
|
44
|
-
async function getEntryData(entry, collectionConfig, pluginContext,
|
|
45
|
-
let
|
|
52
|
+
async function getEntryData(entry, collectionConfig, pluginContext, config) {
|
|
53
|
+
let data;
|
|
54
|
+
if (collectionConfig.type === "data") {
|
|
55
|
+
data = entry.unvalidatedData;
|
|
56
|
+
} else {
|
|
57
|
+
const { slug, ...unvalidatedData } = entry.unvalidatedData;
|
|
58
|
+
data = unvalidatedData;
|
|
59
|
+
}
|
|
46
60
|
let schema = collectionConfig.schema;
|
|
47
61
|
if (typeof schema === "function") {
|
|
48
|
-
if (!
|
|
62
|
+
if (!config.experimental.assets) {
|
|
49
63
|
throw new Error(
|
|
50
64
|
"The function shape for schema can only be used when `experimental.assets` is enabled."
|
|
51
65
|
);
|
|
52
66
|
}
|
|
53
67
|
schema = schema({
|
|
54
|
-
image: createImage(
|
|
68
|
+
image: createImage({ config }, pluginContext, entry._internal.filePath)
|
|
55
69
|
});
|
|
56
70
|
}
|
|
57
71
|
if (schema) {
|
|
58
|
-
if (typeof schema === "object" && "shape" in schema && schema.shape.slug) {
|
|
72
|
+
if (collectionConfig.type === "content" && typeof schema === "object" && "shape" in schema && schema.shape.slug) {
|
|
59
73
|
throw new AstroError({
|
|
60
74
|
...AstroErrorData.ContentSchemaContainsSlugError,
|
|
61
75
|
message: AstroErrorData.ContentSchemaContainsSlugError.message(entry.collection)
|
|
62
76
|
});
|
|
63
77
|
}
|
|
78
|
+
let formattedError;
|
|
64
79
|
const parsed = await schema.safeParseAsync(entry.unvalidatedData, {
|
|
65
|
-
errorMap
|
|
80
|
+
errorMap(error, ctx) {
|
|
81
|
+
var _a, _b;
|
|
82
|
+
if (error.code === "custom" && ((_a = error.params) == null ? void 0 : _a.isHoistedAstroError)) {
|
|
83
|
+
formattedError = (_b = error.params) == null ? void 0 : _b.astroError;
|
|
84
|
+
}
|
|
85
|
+
return errorMap(error, ctx);
|
|
86
|
+
}
|
|
66
87
|
});
|
|
67
88
|
if (parsed.success) {
|
|
68
89
|
data = parsed.data;
|
|
69
90
|
} else {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
location: {
|
|
78
|
-
file: entry._internal.filePath,
|
|
79
|
-
line: getFrontmatterErrorLine(
|
|
80
|
-
entry._internal.rawData,
|
|
81
|
-
String(parsed.error.errors[0].path[0])
|
|
91
|
+
if (!formattedError) {
|
|
92
|
+
formattedError = new AstroError({
|
|
93
|
+
...AstroErrorData.InvalidContentEntryFrontmatterError,
|
|
94
|
+
message: AstroErrorData.InvalidContentEntryFrontmatterError.message(
|
|
95
|
+
entry.collection,
|
|
96
|
+
entry.id,
|
|
97
|
+
parsed.error
|
|
82
98
|
),
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
99
|
+
location: {
|
|
100
|
+
file: entry._internal.filePath,
|
|
101
|
+
line: getYAMLErrorLine(entry._internal.rawData, String(parsed.error.errors[0].path[0])),
|
|
102
|
+
column: 0
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
86
106
|
throw formattedError;
|
|
87
107
|
}
|
|
88
108
|
}
|
|
@@ -91,6 +111,9 @@ async function getEntryData(entry, collectionConfig, pluginContext, settings) {
|
|
|
91
111
|
function getContentEntryExts(settings) {
|
|
92
112
|
return settings.contentEntryTypes.map((t) => t.extensions).flat();
|
|
93
113
|
}
|
|
114
|
+
function getDataEntryExts(settings) {
|
|
115
|
+
return settings.dataEntryTypes.map((t) => t.extensions).flat();
|
|
116
|
+
}
|
|
94
117
|
function getContentEntryConfigByExtMap(settings) {
|
|
95
118
|
const map = /* @__PURE__ */ new Map();
|
|
96
119
|
for (const entryType of settings.contentEntryTypes) {
|
|
@@ -100,39 +123,57 @@ function getContentEntryConfigByExtMap(settings) {
|
|
|
100
123
|
}
|
|
101
124
|
return map;
|
|
102
125
|
}
|
|
103
|
-
|
|
126
|
+
function getEntryCollectionName({
|
|
127
|
+
contentDir,
|
|
128
|
+
entry
|
|
129
|
+
}) {
|
|
130
|
+
const entryPath = typeof entry === "string" ? entry : fileURLToPath(entry);
|
|
131
|
+
const rawRelativePath = path.relative(fileURLToPath(contentDir), entryPath);
|
|
132
|
+
const collectionName = path.dirname(rawRelativePath).split(path.sep)[0];
|
|
133
|
+
const isOutsideCollection = !collectionName || collectionName === "" || collectionName === ".." || collectionName === ".";
|
|
134
|
+
if (isOutsideCollection) {
|
|
135
|
+
return void 0;
|
|
136
|
+
}
|
|
137
|
+
return collectionName;
|
|
104
138
|
}
|
|
105
|
-
function
|
|
139
|
+
function getDataEntryId({
|
|
106
140
|
entry,
|
|
107
141
|
contentDir,
|
|
108
|
-
|
|
142
|
+
collection
|
|
109
143
|
}) {
|
|
110
|
-
const
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
const
|
|
120
|
-
const
|
|
144
|
+
const relativePath = getRelativeEntryPath(entry, collection, contentDir);
|
|
145
|
+
const withoutFileExt = relativePath.replace(new RegExp(path.extname(relativePath) + "$"), "");
|
|
146
|
+
return withoutFileExt;
|
|
147
|
+
}
|
|
148
|
+
function getContentEntryIdAndSlug({
|
|
149
|
+
entry,
|
|
150
|
+
contentDir,
|
|
151
|
+
collection
|
|
152
|
+
}) {
|
|
153
|
+
const relativePath = getRelativeEntryPath(entry, collection, contentDir);
|
|
154
|
+
const withoutFileExt = relativePath.replace(new RegExp(path.extname(relativePath) + "$"), "");
|
|
155
|
+
const rawSlugSegments = withoutFileExt.split(path.sep);
|
|
121
156
|
const slug = rawSlugSegments.map((segment) => githubSlug(segment)).join("/").replace(/\/index$/, "");
|
|
122
157
|
const res = {
|
|
123
|
-
id: normalizePath(
|
|
124
|
-
slug
|
|
125
|
-
collection: normalizePath(rawCollection)
|
|
158
|
+
id: normalizePath(relativePath),
|
|
159
|
+
slug
|
|
126
160
|
};
|
|
127
161
|
return res;
|
|
128
162
|
}
|
|
129
|
-
function
|
|
163
|
+
function getRelativeEntryPath(entry, collection, contentDir) {
|
|
164
|
+
const relativeToContent = path.relative(fileURLToPath(contentDir), fileURLToPath(entry));
|
|
165
|
+
const relativeToCollection = path.relative(collection, relativeToContent);
|
|
166
|
+
return relativeToCollection;
|
|
167
|
+
}
|
|
168
|
+
function getEntryType(entryPath, paths, contentFileExts, dataFileExts, experimentalAssets = false) {
|
|
130
169
|
const { ext, base } = path.parse(entryPath);
|
|
131
170
|
const fileUrl = pathToFileURL(entryPath);
|
|
132
171
|
if (hasUnderscoreBelowContentDirectoryPath(fileUrl, paths.contentDir) || isOnIgnoreList(base) || experimentalAssets && isImageAsset(ext)) {
|
|
133
172
|
return "ignored";
|
|
134
173
|
} else if (contentFileExts.includes(ext)) {
|
|
135
174
|
return "content";
|
|
175
|
+
} else if (dataFileExts.includes(ext)) {
|
|
176
|
+
return "data";
|
|
136
177
|
} else if (fileUrl.href === paths.config.url.href) {
|
|
137
178
|
return "config";
|
|
138
179
|
} else {
|
|
@@ -153,15 +194,19 @@ function hasUnderscoreBelowContentDirectoryPath(fileUrl, contentDir) {
|
|
|
153
194
|
}
|
|
154
195
|
return false;
|
|
155
196
|
}
|
|
156
|
-
function
|
|
157
|
-
if (!
|
|
197
|
+
function getYAMLErrorLine(rawData, objectKey) {
|
|
198
|
+
if (!rawData)
|
|
158
199
|
return 0;
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
200
|
+
const indexOfObjectKey = rawData.search(
|
|
201
|
+
// Match key either at the top of the file or after a newline
|
|
202
|
+
// Ensures matching on top-level object keys only
|
|
203
|
+
new RegExp(`(
|
|
204
|
+
|^)${objectKey}`)
|
|
205
|
+
);
|
|
206
|
+
if (indexOfObjectKey === -1)
|
|
162
207
|
return 0;
|
|
163
|
-
const
|
|
164
|
-
const numNewlinesBeforeKey =
|
|
208
|
+
const dataBeforeKey = rawData.substring(0, indexOfObjectKey + 1);
|
|
209
|
+
const numNewlinesBeforeKey = dataBeforeKey.split("\n").length;
|
|
165
210
|
return numNewlinesBeforeKey;
|
|
166
211
|
}
|
|
167
212
|
function parseFrontmatter(fileContents, filePath) {
|
|
@@ -169,18 +214,18 @@ function parseFrontmatter(fileContents, filePath) {
|
|
|
169
214
|
matter.clearCache();
|
|
170
215
|
return matter(fileContents);
|
|
171
216
|
} catch (e) {
|
|
172
|
-
if (e
|
|
173
|
-
|
|
174
|
-
err.id = filePath;
|
|
175
|
-
err.loc = { file: e.id, line: e.mark.line + 1, column: e.mark.column };
|
|
176
|
-
err.message = e.reason;
|
|
177
|
-
throw err;
|
|
217
|
+
if (isYAMLException(e)) {
|
|
218
|
+
throw formatYAMLException(e);
|
|
178
219
|
} else {
|
|
179
220
|
throw e;
|
|
180
221
|
}
|
|
181
222
|
}
|
|
182
223
|
}
|
|
183
224
|
const globalContentConfigObserver = contentObservable({ status: "init" });
|
|
225
|
+
function hasContentFlag(viteId, flag) {
|
|
226
|
+
const flags = new URLSearchParams(viteId.split("?")[1] ?? "");
|
|
227
|
+
return flags.has(flag);
|
|
228
|
+
}
|
|
184
229
|
async function loadContentConfig({
|
|
185
230
|
fs,
|
|
186
231
|
settings,
|
|
@@ -191,12 +236,8 @@ async function loadContentConfig({
|
|
|
191
236
|
if (!contentPaths.config.exists) {
|
|
192
237
|
return void 0;
|
|
193
238
|
}
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
unparsedConfig = await viteServer.ssrLoadModule(configPathname);
|
|
197
|
-
} catch (e) {
|
|
198
|
-
throw e;
|
|
199
|
-
}
|
|
239
|
+
const configPathname = fileURLToPath(contentPaths.config.url);
|
|
240
|
+
unparsedConfig = await viteServer.ssrLoadModule(configPathname);
|
|
200
241
|
const config = contentConfigParser.safeParse(unparsedConfig);
|
|
201
242
|
if (config.success) {
|
|
202
243
|
return config.data;
|
|
@@ -204,6 +245,25 @@ async function loadContentConfig({
|
|
|
204
245
|
return void 0;
|
|
205
246
|
}
|
|
206
247
|
}
|
|
248
|
+
async function reloadContentConfigObserver({
|
|
249
|
+
observer = globalContentConfigObserver,
|
|
250
|
+
...loadContentConfigOpts
|
|
251
|
+
}) {
|
|
252
|
+
observer.set({ status: "loading" });
|
|
253
|
+
try {
|
|
254
|
+
const config = await loadContentConfig(loadContentConfigOpts);
|
|
255
|
+
if (config) {
|
|
256
|
+
observer.set({ status: "loaded", config });
|
|
257
|
+
} else {
|
|
258
|
+
observer.set({ status: "does-not-exist" });
|
|
259
|
+
}
|
|
260
|
+
} catch (e) {
|
|
261
|
+
observer.set({
|
|
262
|
+
status: "error",
|
|
263
|
+
error: e instanceof Error ? e : new AstroError(AstroErrorData.UnknownContentCollectionError)
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
}
|
|
207
267
|
function contentObservable(initialCtx) {
|
|
208
268
|
const subscribers = /* @__PURE__ */ new Set();
|
|
209
269
|
let ctx = initialCtx;
|
|
@@ -266,7 +326,7 @@ async function getEntrySlug({
|
|
|
266
326
|
}
|
|
267
327
|
const { slug: frontmatterSlug } = await contentEntryType.getEntryInfo({
|
|
268
328
|
fileUrl,
|
|
269
|
-
contents
|
|
329
|
+
contents
|
|
270
330
|
});
|
|
271
331
|
return parseEntrySlug({ generatedSlug, frontmatterSlug, id, collection });
|
|
272
332
|
}
|
|
@@ -277,23 +337,27 @@ function getExtGlob(exts) {
|
|
|
277
337
|
) : `{${exts.join(",")}}`;
|
|
278
338
|
}
|
|
279
339
|
export {
|
|
280
|
-
NoCollectionError,
|
|
281
340
|
collectionConfigParser,
|
|
282
341
|
contentConfigParser,
|
|
283
342
|
contentObservable,
|
|
284
343
|
getContentEntryConfigByExtMap,
|
|
285
344
|
getContentEntryExts,
|
|
345
|
+
getContentEntryIdAndSlug,
|
|
286
346
|
getContentPaths,
|
|
347
|
+
getDataEntryExts,
|
|
348
|
+
getDataEntryId,
|
|
287
349
|
getDotAstroTypeReference,
|
|
350
|
+
getEntryCollectionName,
|
|
288
351
|
getEntryData,
|
|
289
|
-
getEntryInfo,
|
|
290
352
|
getEntrySlug,
|
|
291
353
|
getEntryType,
|
|
292
354
|
getExtGlob,
|
|
293
355
|
globalContentConfigObserver,
|
|
356
|
+
hasContentFlag,
|
|
294
357
|
hasUnderscoreBelowContentDirectoryPath,
|
|
295
358
|
loadContentConfig,
|
|
296
359
|
msg,
|
|
297
360
|
parseEntrySlug,
|
|
298
|
-
parseFrontmatter
|
|
361
|
+
parseFrontmatter,
|
|
362
|
+
reloadContentConfigObserver
|
|
299
363
|
};
|
|
@@ -4,22 +4,22 @@ import { pathToFileURL } from "url";
|
|
|
4
4
|
import { AstroErrorData } from "../core/errors/errors-data.js";
|
|
5
5
|
import { AstroError } from "../core/errors/errors.js";
|
|
6
6
|
import { escapeViteEnvReferences, getFileInfo } from "../vite-plugin-utils/index.js";
|
|
7
|
-
import { CONTENT_FLAG } from "./consts.js";
|
|
7
|
+
import { CONTENT_FLAG, DATA_FLAG } from "./consts.js";
|
|
8
8
|
import {
|
|
9
9
|
getContentEntryConfigByExtMap,
|
|
10
10
|
getContentEntryExts,
|
|
11
|
+
getContentEntryIdAndSlug,
|
|
11
12
|
getContentPaths,
|
|
13
|
+
getDataEntryExts,
|
|
14
|
+
getDataEntryId,
|
|
15
|
+
getEntryCollectionName,
|
|
12
16
|
getEntryData,
|
|
13
|
-
getEntryInfo,
|
|
14
17
|
getEntryType,
|
|
15
18
|
globalContentConfigObserver,
|
|
16
|
-
|
|
17
|
-
parseEntrySlug
|
|
19
|
+
hasContentFlag,
|
|
20
|
+
parseEntrySlug,
|
|
21
|
+
reloadContentConfigObserver
|
|
18
22
|
} from "./utils.js";
|
|
19
|
-
function isContentFlagImport(viteId) {
|
|
20
|
-
const flags = new URLSearchParams(viteId.split("?")[1]);
|
|
21
|
-
return flags.has(CONTENT_FLAG);
|
|
22
|
-
}
|
|
23
23
|
function getContentRendererByViteId(viteId, settings) {
|
|
24
24
|
let ext = viteId.split(".").pop();
|
|
25
25
|
if (!ext)
|
|
@@ -32,18 +32,47 @@ function getContentRendererByViteId(viteId, settings) {
|
|
|
32
32
|
return void 0;
|
|
33
33
|
}
|
|
34
34
|
const CHOKIDAR_MODIFIED_EVENTS = ["add", "unlink", "change"];
|
|
35
|
+
const COLLECTION_TYPES_TO_INVALIDATE_ON = ["data", "content", "config"];
|
|
35
36
|
function astroContentImportPlugin({
|
|
36
37
|
fs,
|
|
37
38
|
settings
|
|
38
39
|
}) {
|
|
39
40
|
const contentPaths = getContentPaths(settings.config, fs);
|
|
40
41
|
const contentEntryExts = getContentEntryExts(settings);
|
|
42
|
+
const dataEntryExts = getDataEntryExts(settings);
|
|
41
43
|
const contentEntryConfigByExt = getContentEntryConfigByExtMap(settings);
|
|
44
|
+
const dataEntryExtToParser = /* @__PURE__ */ new Map();
|
|
45
|
+
for (const entryType of settings.dataEntryTypes) {
|
|
46
|
+
for (const ext of entryType.extensions) {
|
|
47
|
+
dataEntryExtToParser.set(ext, entryType.getEntryInfo);
|
|
48
|
+
}
|
|
49
|
+
}
|
|
42
50
|
const plugins = [
|
|
43
51
|
{
|
|
44
52
|
name: "astro:content-imports",
|
|
45
53
|
async transform(_, viteId) {
|
|
46
|
-
if (
|
|
54
|
+
if (hasContentFlag(viteId, DATA_FLAG)) {
|
|
55
|
+
const fileId = viteId.split("?")[0] ?? viteId;
|
|
56
|
+
const { id, data, collection, _internal } = await getDataEntryModule({
|
|
57
|
+
fileId,
|
|
58
|
+
dataEntryExtToParser,
|
|
59
|
+
contentPaths,
|
|
60
|
+
settings,
|
|
61
|
+
fs,
|
|
62
|
+
pluginContext: this
|
|
63
|
+
});
|
|
64
|
+
const code = escapeViteEnvReferences(`
|
|
65
|
+
export const id = ${JSON.stringify(id)};
|
|
66
|
+
export const collection = ${JSON.stringify(collection)};
|
|
67
|
+
export const data = ${devalue.uneval(data)};
|
|
68
|
+
export const _internal = {
|
|
69
|
+
type: 'data',
|
|
70
|
+
filePath: ${JSON.stringify(_internal.filePath)},
|
|
71
|
+
rawData: ${JSON.stringify(_internal.rawData)},
|
|
72
|
+
};
|
|
73
|
+
`);
|
|
74
|
+
return code;
|
|
75
|
+
} else if (hasContentFlag(viteId, CONTENT_FLAG)) {
|
|
47
76
|
const fileId = viteId.split("?")[0];
|
|
48
77
|
const { id, slug, collection, body, data, _internal } = await setContentEntryModuleCache({
|
|
49
78
|
fileId,
|
|
@@ -56,6 +85,7 @@ function astroContentImportPlugin({
|
|
|
56
85
|
export const body = ${JSON.stringify(body)};
|
|
57
86
|
export const data = ${devalue.uneval(data)};
|
|
58
87
|
export const _internal = {
|
|
88
|
+
type: 'content',
|
|
59
89
|
filePath: ${JSON.stringify(_internal.filePath)},
|
|
60
90
|
rawData: ${JSON.stringify(_internal.rawData)},
|
|
61
91
|
};`);
|
|
@@ -64,14 +94,21 @@ function astroContentImportPlugin({
|
|
|
64
94
|
},
|
|
65
95
|
configureServer(viteServer) {
|
|
66
96
|
viteServer.watcher.on("all", async (event, entry) => {
|
|
67
|
-
if (CHOKIDAR_MODIFIED_EVENTS.includes(event)
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
97
|
+
if (CHOKIDAR_MODIFIED_EVENTS.includes(event)) {
|
|
98
|
+
const entryType = getEntryType(
|
|
99
|
+
entry,
|
|
100
|
+
contentPaths,
|
|
101
|
+
contentEntryExts,
|
|
102
|
+
dataEntryExts,
|
|
103
|
+
settings.config.experimental.assets
|
|
104
|
+
);
|
|
105
|
+
if (!COLLECTION_TYPES_TO_INVALIDATE_ON.includes(entryType))
|
|
106
|
+
return;
|
|
107
|
+
if (entryType === "content" || entryType === "data") {
|
|
108
|
+
await reloadContentConfigObserver({ fs, settings, viteServer });
|
|
109
|
+
}
|
|
73
110
|
for (const modUrl of viteServer.moduleGraph.urlToModuleMap.keys()) {
|
|
74
|
-
if (
|
|
111
|
+
if (hasContentFlag(modUrl, CONTENT_FLAG) || hasContentFlag(modUrl, DATA_FLAG) || Boolean(getContentRendererByViteId(modUrl, settings))) {
|
|
75
112
|
const mod = await viteServer.moduleGraph.getModuleByUrl(modUrl);
|
|
76
113
|
if (mod) {
|
|
77
114
|
viteServer.moduleGraph.invalidateModule(mod);
|
|
@@ -145,13 +182,12 @@ function astroContentImportPlugin({
|
|
|
145
182
|
fileUrl: pathToFileURL(fileId),
|
|
146
183
|
contents: rawContents
|
|
147
184
|
});
|
|
148
|
-
const
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
const { id, slug: generatedSlug, collection } = entryInfoResult;
|
|
185
|
+
const entry = pathToFileURL(fileId);
|
|
186
|
+
const { contentDir } = contentPaths;
|
|
187
|
+
const collection = getEntryCollectionName({ entry, contentDir });
|
|
188
|
+
if (collection === void 0)
|
|
189
|
+
throw new AstroError(AstroErrorData.UnknownContentCollectionError);
|
|
190
|
+
const { id, slug: generatedSlug } = getContentEntryIdAndSlug({ entry, contentDir, collection });
|
|
155
191
|
const _internal = { filePath: fileId, rawData };
|
|
156
192
|
const slug = parseEntrySlug({
|
|
157
193
|
id,
|
|
@@ -161,10 +197,10 @@ function astroContentImportPlugin({
|
|
|
161
197
|
});
|
|
162
198
|
const collectionConfig = contentConfig == null ? void 0 : contentConfig.collections[collection];
|
|
163
199
|
let data = collectionConfig ? await getEntryData(
|
|
164
|
-
{ id, collection,
|
|
200
|
+
{ id, collection, _internal, unvalidatedData },
|
|
165
201
|
collectionConfig,
|
|
166
202
|
pluginContext,
|
|
167
|
-
settings
|
|
203
|
+
settings.config
|
|
168
204
|
) : unvalidatedData;
|
|
169
205
|
const contentEntryModule = {
|
|
170
206
|
id,
|
|
@@ -213,6 +249,55 @@ async function getContentConfigFromGlobal() {
|
|
|
213
249
|
}
|
|
214
250
|
return contentConfig;
|
|
215
251
|
}
|
|
252
|
+
async function getDataEntryModule({
|
|
253
|
+
fileId,
|
|
254
|
+
dataEntryExtToParser,
|
|
255
|
+
contentPaths,
|
|
256
|
+
fs,
|
|
257
|
+
pluginContext,
|
|
258
|
+
settings
|
|
259
|
+
}) {
|
|
260
|
+
const contentConfig = await getContentConfigFromGlobal();
|
|
261
|
+
let rawContents;
|
|
262
|
+
try {
|
|
263
|
+
rawContents = await fs.promises.readFile(fileId, "utf-8");
|
|
264
|
+
} catch (e) {
|
|
265
|
+
throw new AstroError({
|
|
266
|
+
...AstroErrorData.UnknownContentCollectionError,
|
|
267
|
+
message: `Unexpected error reading entry ${JSON.stringify(fileId)}.`,
|
|
268
|
+
stack: e instanceof Error ? e.stack : void 0
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
const fileExt = extname(fileId);
|
|
272
|
+
const dataEntryParser = dataEntryExtToParser.get(fileExt);
|
|
273
|
+
if (!dataEntryParser) {
|
|
274
|
+
throw new AstroError({
|
|
275
|
+
...AstroErrorData.UnknownContentCollectionError,
|
|
276
|
+
message: `No parser found for data entry ${JSON.stringify(
|
|
277
|
+
fileId
|
|
278
|
+
)}. Did you apply an integration for this file type?`
|
|
279
|
+
});
|
|
280
|
+
}
|
|
281
|
+
const { data: unvalidatedData, rawData = "" } = await dataEntryParser({
|
|
282
|
+
fileUrl: pathToFileURL(fileId),
|
|
283
|
+
contents: rawContents
|
|
284
|
+
});
|
|
285
|
+
const entry = pathToFileURL(fileId);
|
|
286
|
+
const { contentDir } = contentPaths;
|
|
287
|
+
const collection = getEntryCollectionName({ entry, contentDir });
|
|
288
|
+
if (collection === void 0)
|
|
289
|
+
throw new AstroError(AstroErrorData.UnknownContentCollectionError);
|
|
290
|
+
const id = getDataEntryId({ entry, contentDir, collection });
|
|
291
|
+
const _internal = { filePath: fileId, rawData };
|
|
292
|
+
const collectionConfig = contentConfig == null ? void 0 : contentConfig.collections[collection];
|
|
293
|
+
const data = collectionConfig ? await getEntryData(
|
|
294
|
+
{ id, collection, _internal, unvalidatedData },
|
|
295
|
+
collectionConfig,
|
|
296
|
+
pluginContext,
|
|
297
|
+
settings.config
|
|
298
|
+
) : unvalidatedData;
|
|
299
|
+
return { id, collection, data, _internal };
|
|
300
|
+
}
|
|
216
301
|
export {
|
|
217
302
|
astroContentImportPlugin
|
|
218
303
|
};
|