astro 5.0.0-beta.2 → 5.0.0-beta.4
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/client.d.ts +1 -1
- package/components/viewtransitions.css +10 -0
- package/dist/actions/consts.d.ts +1 -1
- package/dist/actions/consts.js +1 -1
- package/dist/actions/runtime/virtual/get-action.js +1 -1
- package/dist/assets/utils/transformToPath.js +5 -1
- package/dist/cli/add/index.js +12 -14
- package/dist/cli/install-package.js +4 -4
- package/dist/content/consts.d.ts +5 -3
- package/dist/content/consts.js +7 -3
- package/dist/content/content-layer.js +20 -8
- package/dist/content/data-store.d.ts +2 -0
- package/dist/content/loaders/file.d.ts +9 -2
- package/dist/content/loaders/file.js +30 -14
- package/dist/content/loaders/glob.d.ts +5 -0
- package/dist/content/loaders/glob.js +29 -8
- package/dist/content/mutable-data-store.d.ts +2 -19
- package/dist/content/mutable-data-store.js +14 -1
- package/dist/content/runtime.d.ts +16 -10
- package/dist/content/runtime.js +40 -19
- package/dist/content/types-generator.js +18 -14
- package/dist/content/utils.d.ts +45 -30
- package/dist/content/utils.js +98 -5
- package/dist/content/vite-plugin-content-virtual-mod.d.ts +1 -3
- package/dist/content/vite-plugin-content-virtual-mod.js +8 -72
- package/dist/core/app/index.d.ts +1 -1
- package/dist/core/app/node.js +2 -1
- package/dist/core/app/types.d.ts +1 -1
- package/dist/core/base-pipeline.d.ts +2 -2
- package/dist/core/base-pipeline.js +4 -1
- package/dist/core/build/generate.js +7 -6
- package/dist/core/build/index.js +1 -10
- package/dist/core/build/internal.d.ts +0 -2
- package/dist/core/build/internal.js +0 -2
- package/dist/core/build/plugins/index.js +0 -2
- package/dist/core/build/plugins/plugin-manifest.js +1 -1
- package/dist/core/build/static-build.d.ts +1 -1
- package/dist/core/build/static-build.js +8 -44
- package/dist/core/config/schema.d.ts +167 -150
- package/dist/core/config/schema.js +6 -4
- package/dist/core/constants.js +1 -1
- package/dist/core/create-vite.js +3 -1
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/dev/restart.js +7 -3
- package/dist/core/errors/dev/utils.d.ts +1 -1
- package/dist/core/errors/dev/utils.js +5 -5
- package/dist/core/errors/errors-data.d.ts +12 -2
- package/dist/core/errors/errors-data.js +7 -1
- package/dist/core/fs/index.d.ts +1 -1
- package/dist/core/fs/index.js +2 -5
- package/dist/core/logger/vite.js +2 -2
- package/dist/core/messages.js +2 -2
- package/dist/core/render/params-and-props.js +1 -1
- package/dist/core/render-context.js +1 -1
- package/dist/core/util.d.ts +0 -1
- package/dist/core/util.js +1 -6
- package/dist/env/constants.d.ts +1 -1
- package/dist/env/constants.js +1 -1
- package/dist/integrations/hooks.d.ts +2 -2
- package/dist/integrations/hooks.js +12 -10
- package/dist/jsx/rehype.js +6 -2
- package/dist/preferences/constants.d.ts +1 -0
- package/dist/preferences/constants.js +4 -0
- package/dist/preferences/store.js +2 -1
- package/dist/runtime/server/astro-island.js +2 -1
- package/dist/runtime/server/astro-island.prebuilt-dev.d.ts +1 -1
- package/dist/runtime/server/astro-island.prebuilt-dev.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 +11 -2
- package/dist/runtime/server/render/server-islands.js +2 -2
- package/dist/runtime/server/serialize.js +11 -4
- package/dist/transitions/router.js +4 -3
- package/dist/types/public/config.d.ts +44 -20
- package/dist/types/public/integrations.d.ts +1 -1
- package/dist/vite-plugin-astro/index.js +8 -5
- package/dist/vite-plugin-astro-server/plugin.js +2 -1
- package/dist/vite-plugin-astro-server/response.js +2 -1
- package/dist/vite-plugin-hmr-reload/index.d.ts +7 -0
- package/dist/vite-plugin-hmr-reload/index.js +28 -0
- package/dist/vite-plugin-markdown/content-entry-type.js +4 -4
- package/dist/vite-plugin-markdown/index.js +1 -1
- package/package.json +22 -25
- package/templates/actions.mjs +5 -1
- package/templates/content/module.mjs +8 -6
- package/dist/core/build/plugins/plugin-content.d.ts +0 -5
- package/dist/core/build/plugins/plugin-content.js +0 -394
package/client.d.ts
CHANGED
|
@@ -19,7 +19,7 @@ interface ImportMeta {
|
|
|
19
19
|
* Astro and Vite expose environment variables through `import.meta.env`. For a complete list of the environment variables available, see the two references below.
|
|
20
20
|
*
|
|
21
21
|
* - [Astro reference](https://docs.astro.build/en/guides/environment-variables/#default-environment-variables)
|
|
22
|
-
* - [Vite reference](https://
|
|
22
|
+
* - [Vite reference](https://vite.dev/guide/env-and-mode.html#env-variables)
|
|
23
23
|
*/
|
|
24
24
|
readonly env: ImportMetaEnv;
|
|
25
25
|
}
|
|
@@ -10,12 +10,22 @@
|
|
|
10
10
|
@keyframes astroFadeIn {
|
|
11
11
|
from {
|
|
12
12
|
opacity: 0;
|
|
13
|
+
mix-blend-mode: plus-lighter;
|
|
14
|
+
}
|
|
15
|
+
to {
|
|
16
|
+
opacity: 1;
|
|
17
|
+
mix-blend-mode: plus-lighter;
|
|
13
18
|
}
|
|
14
19
|
}
|
|
15
20
|
|
|
16
21
|
@keyframes astroFadeOut {
|
|
22
|
+
from {
|
|
23
|
+
opacity: 1;
|
|
24
|
+
mix-blend-mode: plus-lighter;
|
|
25
|
+
}
|
|
17
26
|
to {
|
|
18
27
|
opacity: 0;
|
|
28
|
+
mix-blend-mode: plus-lighter;
|
|
19
29
|
}
|
|
20
30
|
}
|
|
21
31
|
|
package/dist/actions/consts.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export declare const VIRTUAL_MODULE_ID = "astro:actions";
|
|
2
2
|
export declare const RESOLVED_VIRTUAL_MODULE_ID: string;
|
|
3
|
-
export declare const ACTIONS_TYPES_FILE = "
|
|
3
|
+
export declare const ACTIONS_TYPES_FILE = "actions.d.ts";
|
|
4
4
|
export declare const VIRTUAL_INTERNAL_MODULE_ID = "astro:internal-actions";
|
|
5
5
|
export declare const RESOLVED_VIRTUAL_INTERNAL_MODULE_ID = "\0astro:internal-actions";
|
|
6
6
|
export declare const NOOP_ACTIONS = "\0noop-actions";
|
package/dist/actions/consts.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
const VIRTUAL_MODULE_ID = "astro:actions";
|
|
2
2
|
const RESOLVED_VIRTUAL_MODULE_ID = "\0" + VIRTUAL_MODULE_ID;
|
|
3
|
-
const ACTIONS_TYPES_FILE = "
|
|
3
|
+
const ACTIONS_TYPES_FILE = "actions.d.ts";
|
|
4
4
|
const VIRTUAL_INTERNAL_MODULE_ID = "astro:internal-actions";
|
|
5
5
|
const RESOLVED_VIRTUAL_INTERNAL_MODULE_ID = "\0astro:internal-actions";
|
|
6
6
|
const NOOP_ACTIONS = "\0noop-actions";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ActionNotFoundError } from "../../../core/errors/errors-data.js";
|
|
2
2
|
import { AstroError } from "../../../core/errors/errors.js";
|
|
3
3
|
async function getAction(path) {
|
|
4
|
-
const pathKeys = path.replace("/_actions/", "").split(".");
|
|
4
|
+
const pathKeys = path.replace("/_actions/", "").split(".").map((key) => decodeURIComponent(key));
|
|
5
5
|
let { server: actionLookup } = await import("astro:internal-actions");
|
|
6
6
|
if (actionLookup == null || !(typeof actionLookup === "object")) {
|
|
7
7
|
throw new TypeError(
|
|
@@ -6,7 +6,11 @@ import { isESMImportedImage } from "./imageKind.js";
|
|
|
6
6
|
function propsToFilename(filePath, transform, hash) {
|
|
7
7
|
let filename = decodeURIComponent(removeQueryString(filePath));
|
|
8
8
|
const ext = extname(filename);
|
|
9
|
-
|
|
9
|
+
if (filePath.startsWith("data:")) {
|
|
10
|
+
filename = shorthash(filePath);
|
|
11
|
+
} else {
|
|
12
|
+
filename = basename(filename, ext);
|
|
13
|
+
}
|
|
10
14
|
const prefixDirname = isESMImportedImage(transform.src) ? dirname(filePath) : "";
|
|
11
15
|
let outputExt = transform.format ? `.${transform.format}` : ext;
|
|
12
16
|
return decodeURIComponent(`${prefixDirname}/${filename}_${hash}${outputExt}`);
|
package/dist/cli/add/index.js
CHANGED
|
@@ -6,11 +6,11 @@ import { diffWords } from "diff";
|
|
|
6
6
|
import { bold, cyan, dim, green, magenta, red, yellow } from "kleur/colors";
|
|
7
7
|
import { builders, generateCode, loadFile } from "magicast";
|
|
8
8
|
import { getDefaultExportOptions } from "magicast/helpers";
|
|
9
|
-
import ora from "ora";
|
|
10
9
|
import preferredPM from "preferred-pm";
|
|
11
10
|
import prompts from "prompts";
|
|
12
11
|
import maxSatisfying from "semver/ranges/max-satisfying.js";
|
|
13
12
|
import { exec } from "tinyexec";
|
|
13
|
+
import yoctoSpinner from "yocto-spinner";
|
|
14
14
|
import {
|
|
15
15
|
loadTSConfig,
|
|
16
16
|
resolveConfig,
|
|
@@ -381,9 +381,6 @@ function setAdapter(mod, adapter, exportName) {
|
|
|
381
381
|
from: exportName
|
|
382
382
|
});
|
|
383
383
|
}
|
|
384
|
-
if (!config.output) {
|
|
385
|
-
config.output = "server";
|
|
386
|
-
}
|
|
387
384
|
switch (adapter.id) {
|
|
388
385
|
case "node":
|
|
389
386
|
config.adapter = builders.functionCall(adapterId, { mode: "standalone" });
|
|
@@ -494,7 +491,8 @@ async function resolveRangeToInstallSpecifier(name, range) {
|
|
|
494
491
|
const versions = await fetchPackageVersions(name);
|
|
495
492
|
if (versions instanceof Error) return name;
|
|
496
493
|
const stableVersions = versions.filter((v) => !v.includes("-"));
|
|
497
|
-
const maxStable = maxSatisfying(stableVersions
|
|
494
|
+
const maxStable = maxSatisfying(stableVersions, range) ?? maxSatisfying(versions, range);
|
|
495
|
+
if (!maxStable) return name;
|
|
498
496
|
return `${name}@^${maxStable}`;
|
|
499
497
|
}
|
|
500
498
|
const INHERITED_FLAGS = /* @__PURE__ */ new Set([
|
|
@@ -545,7 +543,7 @@ ${boxen(coloredOutput, {
|
|
|
545
543
|
${message}`
|
|
546
544
|
);
|
|
547
545
|
if (await askToContinue({ flags })) {
|
|
548
|
-
const spinner =
|
|
546
|
+
const spinner = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
549
547
|
try {
|
|
550
548
|
await exec(
|
|
551
549
|
installCommand.pm,
|
|
@@ -563,10 +561,10 @@ ${message}`
|
|
|
563
561
|
}
|
|
564
562
|
}
|
|
565
563
|
);
|
|
566
|
-
spinner.
|
|
564
|
+
spinner.success();
|
|
567
565
|
return 1 /* updated */;
|
|
568
566
|
} catch (err) {
|
|
569
|
-
spinner.
|
|
567
|
+
spinner.error();
|
|
570
568
|
logger.debug("add", "Error installing dependencies", err);
|
|
571
569
|
console.error("\n", err.stdout || err.message, "\n");
|
|
572
570
|
return 3 /* failure */;
|
|
@@ -577,7 +575,7 @@ ${message}`
|
|
|
577
575
|
}
|
|
578
576
|
}
|
|
579
577
|
async function validateIntegrations(integrations) {
|
|
580
|
-
const spinner =
|
|
578
|
+
const spinner = yoctoSpinner({ text: "Resolving packages..." }).start();
|
|
581
579
|
try {
|
|
582
580
|
const integrationEntries = await Promise.all(
|
|
583
581
|
integrations.map(async (integration) => {
|
|
@@ -594,9 +592,9 @@ async function validateIntegrations(integrations) {
|
|
|
594
592
|
const firstPartyPkgCheck = await fetchPackageJson("@astrojs", name, tag);
|
|
595
593
|
if (firstPartyPkgCheck instanceof Error) {
|
|
596
594
|
if (firstPartyPkgCheck.message) {
|
|
597
|
-
spinner.
|
|
595
|
+
spinner.warning(yellow(firstPartyPkgCheck.message));
|
|
598
596
|
}
|
|
599
|
-
spinner.
|
|
597
|
+
spinner.warning(yellow(`${bold(integration)} is not an official Astro package.`));
|
|
600
598
|
const response = await prompts({
|
|
601
599
|
type: "confirm",
|
|
602
600
|
name: "askToContinue",
|
|
@@ -621,7 +619,7 @@ async function validateIntegrations(integrations) {
|
|
|
621
619
|
const thirdPartyPkgCheck = await fetchPackageJson(scope, name, tag);
|
|
622
620
|
if (thirdPartyPkgCheck instanceof Error) {
|
|
623
621
|
if (thirdPartyPkgCheck.message) {
|
|
624
|
-
spinner.
|
|
622
|
+
spinner.warning(yellow(thirdPartyPkgCheck.message));
|
|
625
623
|
}
|
|
626
624
|
throw new Error(`Unable to fetch ${bold(integration)}. Does the package exist?`);
|
|
627
625
|
} else {
|
|
@@ -661,11 +659,11 @@ async function validateIntegrations(integrations) {
|
|
|
661
659
|
return { id: integration, packageName, dependencies, type: integrationType };
|
|
662
660
|
})
|
|
663
661
|
);
|
|
664
|
-
spinner.
|
|
662
|
+
spinner.success();
|
|
665
663
|
return integrationEntries;
|
|
666
664
|
} catch (e) {
|
|
667
665
|
if (e instanceof Error) {
|
|
668
|
-
spinner.
|
|
666
|
+
spinner.error(e.message);
|
|
669
667
|
process.exit(1);
|
|
670
668
|
} else {
|
|
671
669
|
throw e;
|
|
@@ -2,11 +2,11 @@ import { createRequire } from "node:module";
|
|
|
2
2
|
import boxen from "boxen";
|
|
3
3
|
import ci from "ci-info";
|
|
4
4
|
import { bold, cyan, dim, magenta } from "kleur/colors";
|
|
5
|
-
import ora from "ora";
|
|
6
5
|
import preferredPM from "preferred-pm";
|
|
7
6
|
import prompts from "prompts";
|
|
8
7
|
import { exec } from "tinyexec";
|
|
9
8
|
import whichPm from "which-pm";
|
|
9
|
+
import yoctoSpinner from "yocto-spinner";
|
|
10
10
|
const require2 = createRequire(import.meta.url);
|
|
11
11
|
async function getPackage(packageName, logger, options, otherDeps = []) {
|
|
12
12
|
try {
|
|
@@ -104,18 +104,18 @@ ${message}`
|
|
|
104
104
|
})).askToContinue;
|
|
105
105
|
}
|
|
106
106
|
if (Boolean(response)) {
|
|
107
|
-
const spinner =
|
|
107
|
+
const spinner = yoctoSpinner({ text: "Installing dependencies..." }).start();
|
|
108
108
|
try {
|
|
109
109
|
await exec(
|
|
110
110
|
installCommand.pm,
|
|
111
111
|
[installCommand.command, ...installCommand.flags, ...installCommand.dependencies],
|
|
112
112
|
{ nodeOptions: { cwd } }
|
|
113
113
|
);
|
|
114
|
-
spinner.
|
|
114
|
+
spinner.success();
|
|
115
115
|
return true;
|
|
116
116
|
} catch (err) {
|
|
117
117
|
logger.debug("add", "Error installing dependencies", err);
|
|
118
|
-
spinner.
|
|
118
|
+
spinner.error();
|
|
119
119
|
return false;
|
|
120
120
|
}
|
|
121
121
|
} else {
|
package/dist/content/consts.d.ts
CHANGED
|
@@ -17,8 +17,10 @@ export declare const LINKS_PLACEHOLDER = "@@ASTRO-LINKS@@";
|
|
|
17
17
|
export declare const STYLES_PLACEHOLDER = "@@ASTRO-STYLES@@";
|
|
18
18
|
export declare const IMAGE_IMPORT_PREFIX = "__ASTRO_IMAGE_";
|
|
19
19
|
export declare const CONTENT_FLAGS: readonly ["astroContentCollectionEntry", "astroRenderContent", "astroDataCollectionEntry", "astroPropagatedAssets", "astroContentImageFlag", "astroContentModuleFlag"];
|
|
20
|
-
export declare const CONTENT_TYPES_FILE = "
|
|
20
|
+
export declare const CONTENT_TYPES_FILE = "content.d.ts";
|
|
21
21
|
export declare const DATA_STORE_FILE = "data-store.json";
|
|
22
|
-
export declare const ASSET_IMPORTS_FILE = "assets.mjs";
|
|
23
|
-
export declare const MODULES_IMPORTS_FILE = "modules.mjs";
|
|
22
|
+
export declare const ASSET_IMPORTS_FILE = "content-assets.mjs";
|
|
23
|
+
export declare const MODULES_IMPORTS_FILE = "content-modules.mjs";
|
|
24
|
+
export declare const COLLECTIONS_MANIFEST_FILE = "collections/collections.json";
|
|
25
|
+
export declare const COLLECTIONS_DIR = "collections/";
|
|
24
26
|
export declare const CONTENT_LAYER_TYPE = "content_layer";
|
package/dist/content/consts.js
CHANGED
|
@@ -24,15 +24,19 @@ const CONTENT_FLAGS = [
|
|
|
24
24
|
CONTENT_IMAGE_FLAG,
|
|
25
25
|
CONTENT_MODULE_FLAG
|
|
26
26
|
];
|
|
27
|
-
const CONTENT_TYPES_FILE = "
|
|
27
|
+
const CONTENT_TYPES_FILE = "content.d.ts";
|
|
28
28
|
const DATA_STORE_FILE = "data-store.json";
|
|
29
|
-
const ASSET_IMPORTS_FILE = "assets.mjs";
|
|
30
|
-
const MODULES_IMPORTS_FILE = "modules.mjs";
|
|
29
|
+
const ASSET_IMPORTS_FILE = "content-assets.mjs";
|
|
30
|
+
const MODULES_IMPORTS_FILE = "content-modules.mjs";
|
|
31
|
+
const COLLECTIONS_MANIFEST_FILE = "collections/collections.json";
|
|
32
|
+
const COLLECTIONS_DIR = "collections/";
|
|
31
33
|
const CONTENT_LAYER_TYPE = "content_layer";
|
|
32
34
|
export {
|
|
33
35
|
ASSET_IMPORTS_FILE,
|
|
34
36
|
ASSET_IMPORTS_RESOLVED_STUB_ID,
|
|
35
37
|
ASSET_IMPORTS_VIRTUAL_ID,
|
|
38
|
+
COLLECTIONS_DIR,
|
|
39
|
+
COLLECTIONS_MANIFEST_FILE,
|
|
36
40
|
CONTENT_FLAG,
|
|
37
41
|
CONTENT_FLAGS,
|
|
38
42
|
CONTENT_IMAGE_FLAG,
|
|
@@ -4,6 +4,7 @@ import xxhash from "xxhash-wasm";
|
|
|
4
4
|
import { AstroError, AstroErrorData } from "../core/errors/index.js";
|
|
5
5
|
import {
|
|
6
6
|
ASSET_IMPORTS_FILE,
|
|
7
|
+
COLLECTIONS_MANIFEST_FILE,
|
|
7
8
|
CONTENT_LAYER_TYPE,
|
|
8
9
|
DATA_STORE_FILE,
|
|
9
10
|
MODULES_IMPORTS_FILE
|
|
@@ -106,10 +107,25 @@ class ContentLayer {
|
|
|
106
107
|
logger.info("Syncing content");
|
|
107
108
|
const { digest: currentConfigDigest } = contentConfig.config;
|
|
108
109
|
this.#lastConfigDigest = currentConfigDigest;
|
|
110
|
+
let shouldClear = false;
|
|
109
111
|
const previousConfigDigest = await this.#store.metaStore().get("config-digest");
|
|
112
|
+
const previousAstroVersion = await this.#store.metaStore().get("astro-version");
|
|
110
113
|
if (currentConfigDigest && previousConfigDigest !== currentConfigDigest) {
|
|
111
|
-
logger.info("Content config changed
|
|
114
|
+
logger.info("Content config changed");
|
|
115
|
+
shouldClear = true;
|
|
116
|
+
}
|
|
117
|
+
if (previousAstroVersion !== "5.0.0-beta.4") {
|
|
118
|
+
logger.info("Astro version changed");
|
|
119
|
+
shouldClear = true;
|
|
120
|
+
}
|
|
121
|
+
if (shouldClear) {
|
|
122
|
+
logger.info("Clearing content store");
|
|
112
123
|
this.#store.clearAll();
|
|
124
|
+
}
|
|
125
|
+
if ("5.0.0-beta.4") {
|
|
126
|
+
await this.#store.metaStore().set("astro-version", "5.0.0-beta.4");
|
|
127
|
+
}
|
|
128
|
+
if (currentConfigDigest) {
|
|
113
129
|
await this.#store.metaStore().set("config-digest", currentConfigDigest);
|
|
114
130
|
}
|
|
115
131
|
await Promise.all(
|
|
@@ -159,14 +175,10 @@ class ContentLayer {
|
|
|
159
175
|
return collection.loader.load(context);
|
|
160
176
|
})
|
|
161
177
|
);
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
}
|
|
178
|
+
await fs.mkdir(this.#settings.config.cacheDir, { recursive: true });
|
|
179
|
+
await fs.mkdir(this.#settings.dotAstroDir, { recursive: true });
|
|
165
180
|
const cacheFile = getDataStoreFile(this.#settings);
|
|
166
181
|
await this.#store.writeToDisk(cacheFile);
|
|
167
|
-
if (!existsSync(this.#settings.dotAstroDir)) {
|
|
168
|
-
await fs.mkdir(this.#settings.dotAstroDir, { recursive: true });
|
|
169
|
-
}
|
|
170
182
|
const assetImportsFile = new URL(ASSET_IMPORTS_FILE, this.#settings.dotAstroDir);
|
|
171
183
|
await this.#store.writeAssetImports(assetImportsFile);
|
|
172
184
|
const modulesImportsFile = new URL(MODULES_IMPORTS_FILE, this.#settings.dotAstroDir);
|
|
@@ -177,7 +189,7 @@ class ContentLayer {
|
|
|
177
189
|
}
|
|
178
190
|
}
|
|
179
191
|
async regenerateCollectionFileManifest() {
|
|
180
|
-
const collectionsManifest = new URL(
|
|
192
|
+
const collectionsManifest = new URL(COLLECTIONS_MANIFEST_FILE, this.#settings.dotAstroDir);
|
|
181
193
|
this.#logger.debug("content", "Regenerating collection file manifest");
|
|
182
194
|
if (existsSync(collectionsManifest)) {
|
|
183
195
|
try {
|
|
@@ -31,6 +31,8 @@ export interface DataEntry<TData extends Record<string, unknown> = Record<string
|
|
|
31
31
|
*/
|
|
32
32
|
deferredRender?: boolean;
|
|
33
33
|
assetImports?: Array<string>;
|
|
34
|
+
/** @deprecated */
|
|
35
|
+
legacyId?: string;
|
|
34
36
|
}
|
|
35
37
|
/**
|
|
36
38
|
* A read-only data store for content collections. This is used to retrieve data from the content layer at runtime.
|
|
@@ -1,7 +1,14 @@
|
|
|
1
1
|
import type { Loader } from './types.js';
|
|
2
|
+
export interface FileOptions {
|
|
3
|
+
/**
|
|
4
|
+
* the parsing function to use for this data
|
|
5
|
+
* @default JSON.parse or yaml.load, depending on the extension of the file
|
|
6
|
+
* */
|
|
7
|
+
parser?: (text: string) => Record<string, Record<string, unknown>> | Array<Record<string, unknown>>;
|
|
8
|
+
}
|
|
2
9
|
/**
|
|
3
10
|
* Loads entries from a JSON file. The file must contain an array of objects that contain unique `id` fields, or an object with string keys.
|
|
4
|
-
* @todo Add support for other file types, such as YAML, CSV etc.
|
|
5
11
|
* @param fileName The path to the JSON file to load, relative to the content directory.
|
|
12
|
+
* @param options Additional options for the file loader
|
|
6
13
|
*/
|
|
7
|
-
export declare function file(fileName: string): Loader;
|
|
14
|
+
export declare function file(fileName: string, options?: FileOptions): Loader;
|
|
@@ -1,43 +1,59 @@
|
|
|
1
1
|
import { promises as fs, existsSync } from "node:fs";
|
|
2
2
|
import { fileURLToPath } from "node:url";
|
|
3
|
+
import yaml from "js-yaml";
|
|
3
4
|
import { posixRelative } from "../utils.js";
|
|
4
|
-
function file(fileName) {
|
|
5
|
+
function file(fileName, options) {
|
|
5
6
|
if (fileName.includes("*")) {
|
|
6
7
|
throw new Error("Glob patterns are not supported in `file` loader. Use `glob` loader instead.");
|
|
7
8
|
}
|
|
9
|
+
let parse = null;
|
|
10
|
+
const ext = fileName.split(".").at(-1);
|
|
11
|
+
if (ext === "json") {
|
|
12
|
+
parse = JSON.parse;
|
|
13
|
+
} else if (ext === "yml" || ext === "yaml") {
|
|
14
|
+
parse = (text) => yaml.load(text, {
|
|
15
|
+
filename: fileName
|
|
16
|
+
});
|
|
17
|
+
}
|
|
18
|
+
if (options?.parser) parse = options.parser;
|
|
19
|
+
if (parse === null) {
|
|
20
|
+
throw new Error(
|
|
21
|
+
`No parser found for file '${fileName}'. Try passing a parser to the \`file\` loader.`
|
|
22
|
+
);
|
|
23
|
+
}
|
|
8
24
|
async function syncData(filePath, { logger, parseData, store, config }) {
|
|
9
|
-
let
|
|
25
|
+
let data;
|
|
10
26
|
try {
|
|
11
|
-
const
|
|
12
|
-
|
|
27
|
+
const contents = await fs.readFile(filePath, "utf-8");
|
|
28
|
+
data = parse(contents);
|
|
13
29
|
} catch (error) {
|
|
14
30
|
logger.error(`Error reading data from ${fileName}`);
|
|
15
31
|
logger.debug(error.message);
|
|
16
32
|
return;
|
|
17
33
|
}
|
|
18
34
|
const normalizedFilePath = posixRelative(fileURLToPath(config.root), filePath);
|
|
19
|
-
if (Array.isArray(
|
|
20
|
-
if (
|
|
35
|
+
if (Array.isArray(data)) {
|
|
36
|
+
if (data.length === 0) {
|
|
21
37
|
logger.warn(`No items found in ${fileName}`);
|
|
22
38
|
}
|
|
23
|
-
logger.debug(`Found ${
|
|
39
|
+
logger.debug(`Found ${data.length} item array in ${fileName}`);
|
|
24
40
|
store.clear();
|
|
25
|
-
for (const rawItem of
|
|
41
|
+
for (const rawItem of data) {
|
|
26
42
|
const id = (rawItem.id ?? rawItem.slug)?.toString();
|
|
27
43
|
if (!id) {
|
|
28
44
|
logger.error(`Item in ${fileName} is missing an id or slug field.`);
|
|
29
45
|
continue;
|
|
30
46
|
}
|
|
31
|
-
const
|
|
32
|
-
store.set({ id, data, filePath: normalizedFilePath });
|
|
47
|
+
const parsedData = await parseData({ id, data: rawItem, filePath });
|
|
48
|
+
store.set({ id, data: parsedData, filePath: normalizedFilePath });
|
|
33
49
|
}
|
|
34
|
-
} else if (typeof
|
|
35
|
-
const entries = Object.entries(
|
|
50
|
+
} else if (typeof data === "object") {
|
|
51
|
+
const entries = Object.entries(data);
|
|
36
52
|
logger.debug(`Found object with ${entries.length} entries in ${fileName}`);
|
|
37
53
|
store.clear();
|
|
38
54
|
for (const [id, rawItem] of entries) {
|
|
39
|
-
const
|
|
40
|
-
store.set({ id, data, filePath: normalizedFilePath });
|
|
55
|
+
const parsedData = await parseData({ id, data: rawItem, filePath });
|
|
56
|
+
store.set({ id, data: parsedData, filePath: normalizedFilePath });
|
|
41
57
|
}
|
|
42
58
|
} else {
|
|
43
59
|
logger.error(`Invalid data in ${fileName}. Must be an array or object.`);
|
|
@@ -23,3 +23,8 @@ export interface GlobOptions {
|
|
|
23
23
|
* @param pattern A glob pattern to match files, relative to the content directory.
|
|
24
24
|
*/
|
|
25
25
|
export declare function glob(globOptions: GlobOptions): Loader;
|
|
26
|
+
/** @private */
|
|
27
|
+
export declare function glob(globOptions: GlobOptions & {
|
|
28
|
+
/** @deprecated */
|
|
29
|
+
_legacy?: true;
|
|
30
|
+
}): Loader;
|
|
@@ -9,7 +9,7 @@ function generateIdDefault({ entry, base, data }) {
|
|
|
9
9
|
if (data.slug) {
|
|
10
10
|
return data.slug;
|
|
11
11
|
}
|
|
12
|
-
const entryURL = new URL(entry, base);
|
|
12
|
+
const entryURL = new URL(encodeURI(entry), base);
|
|
13
13
|
const { slug } = getContentEntryIdAndSlug({
|
|
14
14
|
entry: entryURL,
|
|
15
15
|
contentDir: base,
|
|
@@ -41,17 +41,19 @@ function glob(globOptions) {
|
|
|
41
41
|
load: async ({ config, logger, watcher, parseData, store, generateDigest, entryTypes }) => {
|
|
42
42
|
const renderFunctionByContentType = /* @__PURE__ */ new WeakMap();
|
|
43
43
|
const untouchedEntries = new Set(store.keys());
|
|
44
|
+
const isLegacy = globOptions._legacy;
|
|
45
|
+
const emulateLegacyCollections = !config.legacy.collections;
|
|
44
46
|
async function syncData(entry, base, entryType) {
|
|
45
47
|
if (!entryType) {
|
|
46
48
|
logger.warn(`No entry type found for ${entry}`);
|
|
47
49
|
return;
|
|
48
50
|
}
|
|
49
|
-
const fileUrl = new URL(entry, base);
|
|
51
|
+
const fileUrl = new URL(encodeURI(entry), base);
|
|
50
52
|
const contents = await fs.readFile(fileUrl, "utf-8").catch((err) => {
|
|
51
53
|
logger.error(`Error reading ${entry}: ${err.message}`);
|
|
52
54
|
return;
|
|
53
55
|
});
|
|
54
|
-
if (!contents) {
|
|
56
|
+
if (!contents && contents !== "") {
|
|
55
57
|
logger.warn(`No contents found for ${entry}`);
|
|
56
58
|
return;
|
|
57
59
|
}
|
|
@@ -60,6 +62,16 @@ function glob(globOptions) {
|
|
|
60
62
|
fileUrl
|
|
61
63
|
});
|
|
62
64
|
const id = generateId({ entry, base, data });
|
|
65
|
+
let legacyId;
|
|
66
|
+
if (isLegacy) {
|
|
67
|
+
const entryURL = new URL(encodeURI(entry), base);
|
|
68
|
+
const legacyOptions = getContentEntryIdAndSlug({
|
|
69
|
+
entry: entryURL,
|
|
70
|
+
contentDir: base,
|
|
71
|
+
collection: ""
|
|
72
|
+
});
|
|
73
|
+
legacyId = legacyOptions.id;
|
|
74
|
+
}
|
|
63
75
|
untouchedEntries.delete(id);
|
|
64
76
|
const existingEntry = store.get(id);
|
|
65
77
|
const digest = generateDigest(contents);
|
|
@@ -80,6 +92,11 @@ function glob(globOptions) {
|
|
|
80
92
|
filePath
|
|
81
93
|
});
|
|
82
94
|
if (entryType.getRenderFunction) {
|
|
95
|
+
if (isLegacy && data.layout) {
|
|
96
|
+
logger.error(
|
|
97
|
+
`The Markdown "layout" field is not supported in content collections in Astro 5. Ignoring layout for ${JSON.stringify(entry)}. Enable "legacy.collections" if you need to use the layout field.`
|
|
98
|
+
);
|
|
99
|
+
}
|
|
83
100
|
let render = renderFunctionByContentType.get(entryType);
|
|
84
101
|
if (!render) {
|
|
85
102
|
render = await entryType.getRenderFunction(config);
|
|
@@ -104,7 +121,8 @@ function glob(globOptions) {
|
|
|
104
121
|
filePath: relativePath,
|
|
105
122
|
digest,
|
|
106
123
|
rendered,
|
|
107
|
-
assetImports: rendered?.metadata?.imagePaths
|
|
124
|
+
assetImports: rendered?.metadata?.imagePaths,
|
|
125
|
+
legacyId
|
|
108
126
|
});
|
|
109
127
|
} else if ("contentModuleTypes" in entryType) {
|
|
110
128
|
store.set({
|
|
@@ -113,10 +131,11 @@ function glob(globOptions) {
|
|
|
113
131
|
body,
|
|
114
132
|
filePath: relativePath,
|
|
115
133
|
digest,
|
|
116
|
-
deferredRender: true
|
|
134
|
+
deferredRender: true,
|
|
135
|
+
legacyId
|
|
117
136
|
});
|
|
118
137
|
} else {
|
|
119
|
-
store.set({ id, data: parsedData, body, filePath: relativePath, digest });
|
|
138
|
+
store.set({ id, data: parsedData, body, filePath: relativePath, digest, legacyId });
|
|
120
139
|
}
|
|
121
140
|
fileToIdMap.set(filePath, id);
|
|
122
141
|
}
|
|
@@ -154,7 +173,7 @@ function glob(globOptions) {
|
|
|
154
173
|
if (isConfigFile(entry)) {
|
|
155
174
|
return;
|
|
156
175
|
}
|
|
157
|
-
if (isInContentDir(entry)) {
|
|
176
|
+
if (!emulateLegacyCollections && isInContentDir(entry)) {
|
|
158
177
|
skippedFiles.push(entry);
|
|
159
178
|
return;
|
|
160
179
|
}
|
|
@@ -167,7 +186,9 @@ function glob(globOptions) {
|
|
|
167
186
|
const skipCount = skippedFiles.length;
|
|
168
187
|
if (skipCount > 0) {
|
|
169
188
|
const patternList = Array.isArray(globOptions.pattern) ? globOptions.pattern.join(", ") : globOptions.pattern;
|
|
170
|
-
logger.warn(
|
|
189
|
+
logger.warn(
|
|
190
|
+
`The glob() loader cannot be used for files in ${bold("src/content")} when legacy mode is enabled.`
|
|
191
|
+
);
|
|
171
192
|
if (skipCount > 10) {
|
|
172
193
|
logger.warn(
|
|
173
194
|
`Skipped ${green(skippedFiles.length)} files that matched ${green(patternList)}.`
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type PathLike } from 'node:fs';
|
|
2
|
-
import { type DataEntry, ImmutableDataStore
|
|
2
|
+
import { type DataEntry, ImmutableDataStore } from './data-store.js';
|
|
3
3
|
/**
|
|
4
4
|
* Extends the DataStore with the ability to change entries and write them to disk.
|
|
5
5
|
* This is kept as a separate class to avoid needing node builtins at runtime, when read-only access is all that is needed.
|
|
@@ -34,24 +34,7 @@ export declare class MutableDataStore extends ImmutableDataStore {
|
|
|
34
34
|
export interface DataStore {
|
|
35
35
|
get: <TData extends Record<string, unknown> = Record<string, unknown>>(key: string) => DataEntry<TData> | undefined;
|
|
36
36
|
entries: () => Array<[id: string, DataEntry]>;
|
|
37
|
-
set: <TData extends Record<string, unknown>>(opts:
|
|
38
|
-
/** The ID of the entry. Must be unique per collection. */
|
|
39
|
-
id: string;
|
|
40
|
-
/** The data to store. */
|
|
41
|
-
data: TData;
|
|
42
|
-
/** The raw body of the content, if applicable. */
|
|
43
|
-
body?: string;
|
|
44
|
-
/** The file path of the content, if applicable. Relative to the site root. */
|
|
45
|
-
filePath?: string;
|
|
46
|
-
/** A content digest, to check if the content has changed. */
|
|
47
|
-
digest?: number | string;
|
|
48
|
-
/** The rendered content, if applicable. */
|
|
49
|
-
rendered?: RenderedContent;
|
|
50
|
-
/**
|
|
51
|
-
* If an entry is a deferred, its rendering phase is delegated to a virtual module during the runtime phase.
|
|
52
|
-
*/
|
|
53
|
-
deferredRender?: boolean;
|
|
54
|
-
}) => boolean;
|
|
37
|
+
set: <TData extends Record<string, unknown>>(opts: DataEntry<TData>) => boolean;
|
|
55
38
|
values: () => Array<DataEntry>;
|
|
56
39
|
keys: () => Array<string>;
|
|
57
40
|
delete: (key: string) => void;
|
|
@@ -159,7 +159,17 @@ ${lines.join(",\n")}]);
|
|
|
159
159
|
entries: () => this.entries(collectionName),
|
|
160
160
|
values: () => this.values(collectionName),
|
|
161
161
|
keys: () => this.keys(collectionName),
|
|
162
|
-
set: ({
|
|
162
|
+
set: ({
|
|
163
|
+
id: key,
|
|
164
|
+
data,
|
|
165
|
+
body,
|
|
166
|
+
filePath,
|
|
167
|
+
deferredRender,
|
|
168
|
+
digest,
|
|
169
|
+
rendered,
|
|
170
|
+
assetImports,
|
|
171
|
+
legacyId
|
|
172
|
+
}) => {
|
|
163
173
|
if (!key) {
|
|
164
174
|
throw new Error(`ID must be a non-empty string`);
|
|
165
175
|
}
|
|
@@ -200,6 +210,9 @@ ${lines.join(",\n")}]);
|
|
|
200
210
|
if (rendered) {
|
|
201
211
|
entry.rendered = rendered;
|
|
202
212
|
}
|
|
213
|
+
if (legacyId) {
|
|
214
|
+
entry.legacyId = legacyId;
|
|
215
|
+
}
|
|
203
216
|
if (deferredRender) {
|
|
204
217
|
entry.deferredRender = deferredRender;
|
|
205
218
|
if (filePath) {
|
|
@@ -18,10 +18,11 @@ export declare function createGetCollection({ contentCollectionToEntryMap, dataC
|
|
|
18
18
|
getRenderEntryImport: GetEntryImport;
|
|
19
19
|
cacheEntriesByCollection: Map<string, any[]>;
|
|
20
20
|
}): (collection: string, filter?: (entry: any) => unknown) => Promise<any[]>;
|
|
21
|
-
export declare function createGetEntryBySlug({ getEntryImport, getRenderEntryImport, collectionNames, }: {
|
|
21
|
+
export declare function createGetEntryBySlug({ getEntryImport, getRenderEntryImport, collectionNames, getEntry, }: {
|
|
22
22
|
getEntryImport: GetEntryImport;
|
|
23
23
|
getRenderEntryImport: GetEntryImport;
|
|
24
24
|
collectionNames: Set<string>;
|
|
25
|
+
getEntry: ReturnType<typeof createGetEntry>;
|
|
25
26
|
}): (collection: string, slug: string) => Promise<{
|
|
26
27
|
id: any;
|
|
27
28
|
slug: any;
|
|
@@ -30,10 +31,11 @@ export declare function createGetEntryBySlug({ getEntryImport, getRenderEntryImp
|
|
|
30
31
|
data: any;
|
|
31
32
|
render(): Promise<RenderResult>;
|
|
32
33
|
} | undefined>;
|
|
33
|
-
export declare function createGetDataEntryById({ getEntryImport, collectionNames, }: {
|
|
34
|
+
export declare function createGetDataEntryById({ getEntryImport, collectionNames, getEntry, }: {
|
|
34
35
|
getEntryImport: GetEntryImport;
|
|
35
36
|
collectionNames: Set<string>;
|
|
36
|
-
|
|
37
|
+
getEntry: ReturnType<typeof createGetEntry>;
|
|
38
|
+
}): (collection: string, id: string) => Promise<ContentEntryResult | {
|
|
37
39
|
id: any;
|
|
38
40
|
collection: any;
|
|
39
41
|
data: any;
|
|
@@ -79,7 +81,11 @@ export declare function renderEntry(entry: DataEntry | {
|
|
|
79
81
|
render: () => Promise<{
|
|
80
82
|
Content: AstroComponentFactory;
|
|
81
83
|
}>;
|
|
82
|
-
}
|
|
84
|
+
} | (DataEntry & {
|
|
85
|
+
render: () => Promise<{
|
|
86
|
+
Content: AstroComponentFactory;
|
|
87
|
+
}>;
|
|
88
|
+
})): Promise<{
|
|
83
89
|
Content: AstroComponentFactory;
|
|
84
90
|
}>;
|
|
85
91
|
export declare function createReference({ lookupMap }: {
|
|
@@ -88,20 +94,20 @@ export declare function createReference({ lookupMap }: {
|
|
|
88
94
|
id: z.ZodString;
|
|
89
95
|
collection: z.ZodString;
|
|
90
96
|
}, "strip", z.ZodTypeAny, {
|
|
91
|
-
id: string;
|
|
92
97
|
collection: string;
|
|
93
|
-
}, {
|
|
94
98
|
id: string;
|
|
99
|
+
}, {
|
|
95
100
|
collection: string;
|
|
101
|
+
id: string;
|
|
96
102
|
}>, z.ZodObject<{
|
|
97
103
|
slug: z.ZodString;
|
|
98
104
|
collection: z.ZodString;
|
|
99
105
|
}, "strip", z.ZodTypeAny, {
|
|
100
|
-
collection: string;
|
|
101
106
|
slug: string;
|
|
102
|
-
}, {
|
|
103
107
|
collection: string;
|
|
108
|
+
}, {
|
|
104
109
|
slug: string;
|
|
110
|
+
collection: string;
|
|
105
111
|
}>]>, {
|
|
106
112
|
id: string;
|
|
107
113
|
collection: string;
|
|
@@ -109,10 +115,10 @@ export declare function createReference({ lookupMap }: {
|
|
|
109
115
|
slug: string;
|
|
110
116
|
collection: string;
|
|
111
117
|
} | undefined, string | {
|
|
112
|
-
id: string;
|
|
113
118
|
collection: string;
|
|
119
|
+
id: string;
|
|
114
120
|
} | {
|
|
115
|
-
collection: string;
|
|
116
121
|
slug: string;
|
|
122
|
+
collection: string;
|
|
117
123
|
}>;
|
|
118
124
|
export {};
|