astro 4.3.2 → 4.3.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.
Files changed (43) hide show
  1. package/client.d.ts +1 -0
  2. package/components/Picture.astro +3 -3
  3. package/content-types.template.d.ts +0 -49
  4. package/dist/@types/astro.d.ts +2 -2
  5. package/dist/assets/services/vendor/squoosh/codecs.js +4 -0
  6. package/dist/cli/add/index.js +1 -1
  7. package/dist/content/utils.js +1 -1
  8. package/dist/content/vite-plugin-content-assets.js +16 -6
  9. package/dist/core/build/css-asset-name.js +1 -1
  10. package/dist/core/build/plugins/plugin-manifest.js +1 -1
  11. package/dist/core/build/static-build.js +1 -1
  12. package/dist/core/constants.js +1 -1
  13. package/dist/core/create-vite.js +1 -1
  14. package/dist/core/dev/dev.js +1 -1
  15. package/dist/core/dev/restart.js +2 -2
  16. package/dist/core/errors/dev/utils.js +9 -9
  17. package/dist/core/errors/errors-data.js +1 -1
  18. package/dist/core/logger/vite.js +4 -5
  19. package/dist/core/messages.js +3 -3
  20. package/dist/core/module-loader/loader.d.ts +1 -0
  21. package/dist/core/preview/vite-plugin-astro-preview.js +1 -1
  22. package/dist/core/render/context.js +10 -1
  23. package/dist/core/routing/manifest/create.js +1 -1
  24. package/dist/events/error.js +2 -2
  25. package/dist/runtime/client/dev-toolbar/apps/audit/a11y.js +1 -1
  26. package/dist/runtime/server/index.js +1 -4
  27. package/dist/runtime/server/render/component.js +3 -3
  28. package/dist/runtime/server/render/util.js +5 -5
  29. package/dist/vite-plugin-astro/compile.js +2 -2
  30. package/dist/vite-plugin-astro/hmr.js +1 -1
  31. package/dist/vite-plugin-astro/utils.d.ts +1 -0
  32. package/dist/vite-plugin-astro/utils.js +4 -0
  33. package/dist/vite-plugin-astro-server/css.d.ts +1 -0
  34. package/dist/vite-plugin-astro-server/css.js +6 -1
  35. package/dist/vite-plugin-astro-server/route.js +4 -2
  36. package/dist/vite-plugin-astro-server/scripts.d.ts +4 -1
  37. package/dist/vite-plugin-astro-server/scripts.js +5 -1
  38. package/dist/vite-plugin-env/index.js +1 -1
  39. package/dist/vite-plugin-head/index.js +1 -1
  40. package/dist/vite-plugin-html/transform/utils.js +2 -2
  41. package/dist/vite-plugin-scanner/scan.js +1 -1
  42. package/dist/vite-plugin-utils/index.js +1 -1
  43. package/package.json +2 -2
package/client.d.ts CHANGED
@@ -1,4 +1,5 @@
1
1
  /// <reference types="vite/types/import-meta.d.ts" />
2
+ /// <reference path="./types/content.d.ts" />
2
3
 
3
4
  // eslint-disable-next-line @typescript-eslint/no-namespace
4
5
  declare namespace App {
@@ -51,11 +51,11 @@ const fallbackImage = await getImage({
51
51
  });
52
52
 
53
53
  const imgAdditionalAttributes: HTMLAttributes<'img'> = {};
54
- const sourceAdditionaAttributes: HTMLAttributes<'source'> = {};
54
+ const sourceAdditionalAttributes: HTMLAttributes<'source'> = {};
55
55
 
56
56
  // Propagate the `sizes` attribute to the `source` elements
57
57
  if (props.sizes) {
58
- sourceAdditionaAttributes.sizes = props.sizes;
58
+ sourceAdditionalAttributes.sizes = props.sizes;
59
59
  }
60
60
 
61
61
  if (fallbackImage.srcSet.values.length > 0) {
@@ -74,7 +74,7 @@ if (fallbackImage.srcSet.values.length > 0) {
74
74
  <source
75
75
  srcset={srcsetAttribute}
76
76
  type={'image/' + image.options.format}
77
- {...sourceAdditionaAttributes}
77
+ {...sourceAdditionalAttributes}
78
78
  />
79
79
  );
80
80
  })
@@ -9,8 +9,6 @@ declare module 'astro:content' {
9
9
  }
10
10
 
11
11
  declare module 'astro:content' {
12
- export { z } from 'astro/zod';
13
-
14
12
  type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
15
13
 
16
14
  export type CollectionKey = keyof AnyEntryMap;
@@ -19,53 +17,6 @@ declare module 'astro:content' {
19
17
  export type ContentCollectionKey = keyof ContentEntryMap;
20
18
  export type DataCollectionKey = keyof DataEntryMap;
21
19
 
22
- // This needs to be in sync with ImageMetadata
23
- export type ImageFunction = () => import('astro/zod').ZodObject<{
24
- src: import('astro/zod').ZodString;
25
- width: import('astro/zod').ZodNumber;
26
- height: import('astro/zod').ZodNumber;
27
- format: import('astro/zod').ZodUnion<
28
- [
29
- import('astro/zod').ZodLiteral<'png'>,
30
- import('astro/zod').ZodLiteral<'jpg'>,
31
- import('astro/zod').ZodLiteral<'jpeg'>,
32
- import('astro/zod').ZodLiteral<'tiff'>,
33
- import('astro/zod').ZodLiteral<'webp'>,
34
- import('astro/zod').ZodLiteral<'gif'>,
35
- import('astro/zod').ZodLiteral<'svg'>,
36
- import('astro/zod').ZodLiteral<'avif'>,
37
- ]
38
- >;
39
- }>;
40
-
41
- type BaseSchemaWithoutEffects =
42
- | import('astro/zod').AnyZodObject
43
- | import('astro/zod').ZodUnion<[BaseSchemaWithoutEffects, ...BaseSchemaWithoutEffects[]]>
44
- | import('astro/zod').ZodDiscriminatedUnion<string, import('astro/zod').AnyZodObject[]>
45
- | import('astro/zod').ZodIntersection<BaseSchemaWithoutEffects, BaseSchemaWithoutEffects>;
46
-
47
- type BaseSchema =
48
- | BaseSchemaWithoutEffects
49
- | import('astro/zod').ZodEffects<BaseSchemaWithoutEffects>;
50
-
51
- export type SchemaContext = { image: ImageFunction };
52
-
53
- type DataCollectionConfig<S extends BaseSchema> = {
54
- type: 'data';
55
- schema?: S | ((context: SchemaContext) => S);
56
- };
57
-
58
- type ContentCollectionConfig<S extends BaseSchema> = {
59
- type?: 'content';
60
- schema?: S | ((context: SchemaContext) => S);
61
- };
62
-
63
- type CollectionConfig<S> = ContentCollectionConfig<S> | DataCollectionConfig<S>;
64
-
65
- export function defineCollection<S extends BaseSchema>(
66
- input: CollectionConfig<S>
67
- ): CollectionConfig<S>;
68
-
69
20
  type AllValuesOf<T> = T extends any ? T[keyof T] : never;
70
21
  type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
71
22
  ContentEntryMap[C]
@@ -467,7 +467,7 @@ export interface AstroUserConfig {
467
467
  *
468
468
  * Specifies the output target for builds.
469
469
  *
470
- * - `'static'` - Building a static site to be deploy to any static host.
470
+ * - `'static'` - Building a static site to be deployed to any static host.
471
471
  * - `'server'` - Building an app to be deployed to a host supporting SSR (server-side rendering).
472
472
  * - `'hybrid'` - Building a static site with a few server-side rendered pages.
473
473
  *
@@ -1410,7 +1410,7 @@ export interface AstroUserConfig {
1410
1410
  * @version 3.7.0
1411
1411
  * @description
1412
1412
  *
1413
- * - `"pathanme": The strategy is applied to the pathname of the URLs
1413
+ * - `"pathname": The strategy is applied to the pathname of the URLs
1414
1414
  */
1415
1415
  strategy: 'pathname';
1416
1416
  /**
@@ -211,6 +211,8 @@ const codecs = {
211
211
  avif: {
212
212
  name: "AVIF",
213
213
  extension: "avif",
214
+ // Disable eslint rule to not touch the original code
215
+ // eslint-disable-next-line no-control-regex, regexp/control-character-escape
214
216
  detectors: [/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/],
215
217
  dec: () => instantiateEmscriptenWasm(avifDec, avifDecWasm),
216
218
  enc: async () => {
@@ -240,6 +242,8 @@ const codecs = {
240
242
  oxipng: {
241
243
  name: "OxiPNG",
242
244
  extension: "png",
245
+ // Disable eslint rule to not touch the original code
246
+ // eslint-disable-next-line no-control-regex, regexp/control-character-escape
243
247
  detectors: [/^\x89PNG\x0D\x0A\x1A\x0A/],
244
248
  dec: async () => {
245
249
  await pngEncDecInit();
@@ -316,7 +316,7 @@ async function parseAstroConfig(configURL) {
316
316
  return result;
317
317
  }
318
318
  const toIdent = (name) => {
319
- const ident = name.trim().replace(/[-_\.\/]?astro(?:js)?[-_\.]?/g, "").replace(/\.js/, "").replace(/(?:[\.\-\_\/]+)([a-zA-Z])/g, (_, w) => w.toUpperCase()).replace(/^[^a-zA-Z$_]+/, "");
319
+ const ident = name.trim().replace(/[-_./]?astro(?:js)?[-_.]?/g, "").replace(/\.js/, "").replace(/[.\-_/]+([a-zA-Z])/g, (_, w) => w.toUpperCase()).replace(/^[^a-zA-Z$_]+/, "");
320
320
  return `${ident[0].toLowerCase()}${ident.slice(1)}`;
321
321
  };
322
322
  function createPrettyError(err) {
@@ -71,7 +71,7 @@ async function getEntryData(entry, collectionConfig, pluginContext) {
71
71
  });
72
72
  }
73
73
  let formattedError;
74
- const parsed = await schema.safeParseAsync(entry.unvalidatedData, {
74
+ const parsed = await schema.safeParseAsync(data, {
75
75
  errorMap(error, ctx) {
76
76
  if (error.code === "custom" && error.params?.isHoistedAstroError) {
77
77
  formattedError = error.params?.astroError;
@@ -49,12 +49,22 @@ function astroContentAssetPropagationPlugin({
49
49
  if (!devModuleLoader.getModuleById(basePath)?.ssrModule) {
50
50
  await devModuleLoader.import(basePath);
51
51
  }
52
- const { styles, urls } = await getStylesForURL(pathToFileURL(basePath), devModuleLoader);
53
- const hoistedScripts = await getScriptsForURL(
54
- pathToFileURL(basePath),
55
- settings.config.root,
56
- devModuleLoader
57
- );
52
+ const {
53
+ styles,
54
+ urls,
55
+ crawledFiles: styleCrawledFiles
56
+ } = await getStylesForURL(pathToFileURL(basePath), devModuleLoader);
57
+ const { scripts: hoistedScripts, crawledFiles: scriptCrawledFiles } = await getScriptsForURL(pathToFileURL(basePath), settings.config.root, devModuleLoader);
58
+ for (const file of styleCrawledFiles) {
59
+ if (!file.includes("node_modules")) {
60
+ this.addWatchFile(file);
61
+ }
62
+ }
63
+ for (const file of scriptCrawledFiles) {
64
+ if (!file.includes("node_modules")) {
65
+ this.addWatchFile(file);
66
+ }
67
+ }
58
68
  stringifiedLinks = JSON.stringify([...urls]);
59
69
  stringifiedStyles = JSON.stringify(styles.map((s) => s.content));
60
70
  stringifiedScripts = JSON.stringify([...hoistedScripts]);
@@ -70,7 +70,7 @@ function getFirstParentId(parents) {
70
70
  }
71
71
  return parents[0]?.[0].id;
72
72
  }
73
- const charsToReplaceRe = /[.\[\]]/g;
73
+ const charsToReplaceRe = /[.[\]]/g;
74
74
  const underscoresRe = /_+/g;
75
75
  function prettifyBaseName(str) {
76
76
  return str.replace(charsToReplaceRe, "_").replace(underscoresRe, "_");
@@ -10,7 +10,7 @@ import { getOutFile, getOutFolder } from "../common.js";
10
10
  import { cssOrder, mergeInlineCss } from "../internal.js";
11
11
  import { normalizeTheLocale } from "../../../i18n/index.js";
12
12
  const manifestReplace = "@@ASTRO_MANIFEST_REPLACE@@";
13
- const replaceExp = new RegExp(`['"](${manifestReplace})['"]`, "g");
13
+ const replaceExp = new RegExp(`['"]${manifestReplace}['"]`, "g");
14
14
  const SSR_MANIFEST_VIRTUAL_MODULE_ID = "@astrojs-manifest";
15
15
  const RESOLVED_SSR_MANIFEST_VIRTUAL_MODULE_ID = "\0" + SSR_MANIFEST_VIRTUAL_MODULE_ID;
16
16
  function vitePluginManifest(options, internals) {
@@ -382,7 +382,7 @@ function makeAstroPageEntryPointFileName(prefix, facadeModuleId, routes) {
382
382
  const pageModuleId = facadeModuleId.replace(prefix, "").replace(ASTRO_PAGE_EXTENSION_POST_PATTERN, ".");
383
383
  const route = routes.find((routeData) => routeData.component === pageModuleId);
384
384
  const name = route?.route ?? pageModuleId;
385
- return `pages${name.replace(/\/$/, "/index").replaceAll(/[\[\]]/g, "_").replaceAll("...", "---")}.astro.mjs`;
385
+ return `pages${name.replace(/\/$/, "/index").replaceAll(/[[\]]/g, "_").replaceAll("...", "---")}.astro.mjs`;
386
386
  }
387
387
  function makeSplitEntryPointFileName(facadeModuleId, routes) {
388
388
  const filePath = `${makeAstroPageEntryPointFileName(
@@ -1,4 +1,4 @@
1
- const ASTRO_VERSION = "4.3.2";
1
+ const ASTRO_VERSION = "4.3.4";
2
2
  const SUPPORTED_MARKDOWN_FILE_EXTENSIONS = [
3
3
  ".markdown",
4
4
  ".mdown",
@@ -62,7 +62,7 @@ async function createVite(commandConfig, { settings, logger, mode, command, fs =
62
62
  // Attempt: package relies on `astro`. ✅ Definitely an Astro package
63
63
  pkgJson.peerDependencies?.astro || pkgJson.dependencies?.astro || // Attempt: package is tagged with `astro` or `astro-component`. ✅ Likely a community package
64
64
  pkgJson.keywords?.includes("astro") || pkgJson.keywords?.includes("astro-component") || // Attempt: package is named `astro-something` or `@scope/astro-something`. ✅ Likely a community package
65
- /^(@[^\/]+\/)?astro\-/.test(pkgJson.name)
65
+ /^(?:@[^/]+\/)?astro-/.test(pkgJson.name)
66
66
  );
67
67
  },
68
68
  isFrameworkPkgByName(pkgName) {
@@ -23,7 +23,7 @@ async function dev(inlineConfig) {
23
23
  base: restart.container.settings.config.base
24
24
  })
25
25
  );
26
- const currentVersion = "4.3.2";
26
+ const currentVersion = "4.3.4";
27
27
  if (currentVersion.includes("-")) {
28
28
  logger.warn("SKIP_FORMAT", msg.prerelease({ currentVersion }));
29
29
  }
@@ -19,8 +19,8 @@ async function createRestartedContainer(container, settings) {
19
19
  await startContainer(newContainer);
20
20
  return newContainer;
21
21
  }
22
- const configRE = new RegExp(`.*astro.config.((mjs)|(cjs)|(js)|(ts))$`);
23
- const preferencesRE = new RegExp(`.*.astro/settings.json$`);
22
+ const configRE = /.*astro.config.(?:mjs|cjs|js|ts)$/;
23
+ const preferencesRE = /.*\.astro\/settings.json$/;
24
24
  function shouldRestartContainer({ settings, inlineConfig, restartInFlight }, changedFile) {
25
25
  if (restartInFlight)
26
26
  return false;
@@ -81,7 +81,7 @@ function collectErrorMetadata(e, rootFolder) {
81
81
  }
82
82
  function generateHint(err) {
83
83
  const commonBrowserAPIs = ["document", "window"];
84
- if (/Unknown file extension \"\.(jsx|vue|svelte|astro|css)\" for /.test(err.message)) {
84
+ if (/Unknown file extension "\.(?:jsx|vue|svelte|astro|css)" for /.test(err.message)) {
85
85
  return "You likely need to add this package to `vite.ssr.noExternal` in your astro config file.";
86
86
  } else if (commonBrowserAPIs.some((api) => err.toString().includes(api))) {
87
87
  const hint = `Browser APIs are not available on the server.
@@ -107,8 +107,8 @@ function collectInfoFromStacktrace(error) {
107
107
  const possibleFilePath = error.loc?.file || error.pluginCode || error.id || // TODO: this could be better, `src` might be something else
108
108
  stackText.split("\n").find((ln) => ln.includes("src") || ln.includes("node_modules"));
109
109
  const source = possibleFilePath?.replace(/^[^(]+\(([^)]+).*$/, "$1").replace(/^\s+at\s+/, "");
110
- let file = source?.replace(/(:[0-9]+)/g, "");
111
- const location = /:([0-9]+):([0-9]+)/g.exec(source) ?? [];
110
+ let file = source?.replace(/:\d+/g, "");
111
+ const location = /:(\d+):(\d+)/.exec(source) ?? [];
112
112
  const line = location[1];
113
113
  const column = location[2];
114
114
  if (file && line && column) {
@@ -124,13 +124,13 @@ function collectInfoFromStacktrace(error) {
124
124
  }
125
125
  }
126
126
  if (!stackInfo.plugin) {
127
- stackInfo.plugin = /withastro\/astro\/packages\/integrations\/([\w-]+)/gim.exec(stackText)?.at(1) || /(@astrojs\/[\w-]+)\/(server|client|index)/gim.exec(stackText)?.at(1) || void 0;
127
+ stackInfo.plugin = /withastro\/astro\/packages\/integrations\/([\w-]+)/i.exec(stackText)?.at(1) || /(@astrojs\/[\w-]+)\/(server|client|index)/i.exec(stackText)?.at(1) || void 0;
128
128
  }
129
129
  stackInfo.stack = cleanErrorStack(error.stack);
130
130
  return stackInfo;
131
131
  }
132
132
  function cleanErrorStack(stack) {
133
- return stack.split(/\n/g).map((l) => l.replace(/\/@fs\//g, "/")).join("\n");
133
+ return stack.split(/\n/).map((l) => l.replace(/\/@fs\//g, "/")).join("\n");
134
134
  }
135
135
  function getDocsForError(err) {
136
136
  if (err.name !== "UnknownError" && err.name in AstroErrorData) {
@@ -142,10 +142,10 @@ function getDocsForError(err) {
142
142
  }
143
143
  }
144
144
  function renderErrorMarkdown(markdown, target) {
145
- const linkRegex = /\[([^\[]+)\]\((.*)\)/gm;
146
- const boldRegex = /\*\*(.+)\*\*/gm;
147
- const urlRegex = / (\b(https?|ftp):\/\/[-A-Z0-9+&@#\\/%?=~_|!:,.;]*[-A-Z0-9+&@#\\/%=~_|])/gim;
148
- const codeRegex = /`([^`]+)`/gim;
145
+ const linkRegex = /\[([^[]+)\]\((.*)\)/g;
146
+ const boldRegex = /\*\*(.+)\*\*/g;
147
+ const urlRegex = / ((?:https?|ftp):\/\/[-\w+&@#\\/%?=~|!:,.;]*[-\w+&@#\\/%=~|])/gi;
148
+ const codeRegex = /`([^`]+)`/g;
149
149
  if (target === "html") {
150
150
  return escape(markdown).replace(linkRegex, `<a href="$2" target="_blank">$1</a>`).replace(boldRegex, "<b>$1</b>").replace(urlRegex, ' <a href="$1" target="_blank">$1</a>').replace(codeRegex, "<code>$1</code>");
151
151
  } else {
@@ -184,7 +184,7 @@ const PrerenderDynamicEndpointPathCollide = {
184
184
  name: "PrerenderDynamicEndpointPathCollide",
185
185
  title: "Prerendered dynamic endpoint has path collision.",
186
186
  message: (pathname) => `Could not render \`${pathname}\` with an \`undefined\` param as the generated path will collide during prerendering. Prevent passing \`undefined\` as \`params\` for the endpoint's \`getStaticPaths()\` function, or add an additional extension to the endpoint's filename.`,
187
- hint: (filename) => `Rename \`${filename}\` to \`${filename.replace(/\.(js|ts)/, (m) => `.json` + m)}\``
187
+ hint: (filename) => `Rename \`${filename}\` to \`${filename.replace(/\.(?:js|ts)/, (m) => `.json` + m)}\``
188
188
  };
189
189
  const ExpectedImage = {
190
190
  name: "ExpectedImage",
@@ -8,11 +8,11 @@ const E2E_PREFIX = fileURLToPath(new URL("../../../e2e", import.meta.url));
8
8
  function isAstroSrcFile(id) {
9
9
  return id?.startsWith(PKG_PREFIX) && !id.startsWith(E2E_PREFIX);
10
10
  }
11
- const vitePageReloadMsg = /page reload (.*)( \(.*\))?/;
11
+ const vitePageReloadMsg = /page reload (.*)/;
12
12
  const viteHmrUpdateMsg = /hmr update (.*)/;
13
13
  const viteBuildMsg = /vite.*building.*for production/;
14
- const viteShortcutTitleMsg = /^\s*Shortcuts\s*$/s;
15
- const viteShortcutHelpMsg = /press\s+(.*?)\s+to\s+(.*)$/s;
14
+ const viteShortcutTitleMsg = /^\s*Shortcuts\s*$/;
15
+ const viteShortcutHelpMsg = /press (.+?) to (.+)$/s;
16
16
  function createViteLogger(astroLogger, viteLogLevel = "info") {
17
17
  const warnedMessages = /* @__PURE__ */ new Set();
18
18
  const loggedErrors = /* @__PURE__ */ new WeakSet();
@@ -26,8 +26,7 @@ function createViteLogger(astroLogger, viteLogLevel = "info") {
26
26
  if (m = vitePageReloadMsg.exec(stripped)) {
27
27
  if (isAstroSrcFile(m[1]))
28
28
  return;
29
- const extra = m[2] ?? "";
30
- astroLogger.info("watch", m[1] + extra);
29
+ astroLogger.info("watch", m[1]);
31
30
  } else if (m = viteHmrUpdateMsg.exec(stripped)) {
32
31
  if (isAstroSrcFile(m[1]))
33
32
  return;
@@ -36,7 +36,7 @@ function serverStart({
36
36
  host,
37
37
  base
38
38
  }) {
39
- const version = "4.3.2";
39
+ const version = "4.3.4";
40
40
  const localPrefix = `${dim("\u2503")} Local `;
41
41
  const networkPrefix = `${dim("\u2503")} Network `;
42
42
  const emptyPrefix = " ".repeat(11);
@@ -180,7 +180,7 @@ ${errorList.join(
180
180
  )}`;
181
181
  }
182
182
  const STACK_LINE_REGEXP = /^\s+at /g;
183
- const IRRELEVANT_STACK_REGEXP = /(node_modules|astro[\/\\]dist)/g;
183
+ const IRRELEVANT_STACK_REGEXP = /node_modules|astro[/\\]dist/g;
184
184
  function formatErrorStackTrace(err, showFullStacktrace) {
185
185
  const stackLines = (err.stack || "").split("\n").filter((line) => STACK_LINE_REGEXP.test(line));
186
186
  if (showFullStacktrace) {
@@ -261,7 +261,7 @@ function printHelp({
261
261
  message.push(
262
262
  linebreak(),
263
263
  ` ${bgGreen(black(` ${commandName} `))} ${green(
264
- `v${"4.3.2"}`
264
+ `v${"4.3.4"}`
265
265
  )} ${headline}`
266
266
  );
267
267
  }
@@ -31,6 +31,7 @@ export interface ModuleLoader {
31
31
  export interface ModuleNode {
32
32
  id: string | null;
33
33
  url: string;
34
+ file: string | null;
34
35
  ssrModule: Record<string, any> | null;
35
36
  ssrTransformResult: {
36
37
  deps?: string[];
@@ -3,7 +3,7 @@ import { fileURLToPath } from "node:url";
3
3
  import { notFoundTemplate, subpathNotUsedTemplate } from "../../template/4xx.js";
4
4
  import { cleanUrl } from "../../vite-plugin-utils/index.js";
5
5
  import { stripBase } from "./util.js";
6
- const HAS_FILE_EXTENSION_REGEXP = /^.*\.[^\\]+$/;
6
+ const HAS_FILE_EXTENSION_REGEXP = /\.[^/]+$/;
7
7
  function vitePluginAstroPreview(settings) {
8
8
  const { base, outDir, trailingSlash } = settings.config;
9
9
  function handle404(req, res) {
@@ -154,15 +154,24 @@ function computeCurrentLocale(request, locales, routingStrategy, defaultLocale)
154
154
  if (!routeData) {
155
155
  return defaultLocale;
156
156
  }
157
- for (const segment of routeData.route.split("/")) {
157
+ const pathname = routeData.pathname ?? new URL(request.url).pathname;
158
+ for (const segment of pathname.split("/").filter(Boolean)) {
158
159
  for (const locale of locales) {
159
160
  if (typeof locale === "string") {
161
+ if (!segment.includes(locale))
162
+ continue;
160
163
  if (normalizeTheLocale(locale) === normalizeTheLocale(segment)) {
161
164
  return locale;
162
165
  }
163
166
  } else {
164
167
  if (locale.path === segment) {
165
168
  return locale.codes.at(0);
169
+ } else {
170
+ for (const code of locale.codes) {
171
+ if (normalizeTheLocale(code) === normalizeTheLocale(segment)) {
172
+ return code;
173
+ }
174
+ }
166
175
  }
167
176
  }
168
177
  }
@@ -26,7 +26,7 @@ function getParts(part, file) {
26
26
  return;
27
27
  const dynamic = i % 2 === 1;
28
28
  const [, content] = dynamic ? /([^(]+)$/.exec(str) || [null, null] : [null, str];
29
- if (!content || dynamic && !/^(\.\.\.)?[a-zA-Z0-9_$]+$/.test(content)) {
29
+ if (!content || dynamic && !/^(?:\.\.\.)?[\w$]+$/.test(content)) {
30
30
  throw new Error(`Invalid route ${file} \u2014 parameter name must match /^[a-zA-Z0-9_$]+$/`);
31
31
  }
32
32
  result.push({
@@ -1,6 +1,6 @@
1
1
  import { AstroError, AstroErrorData } from "../core/errors/index.js";
2
2
  const EVENT_ERROR = "ASTRO_CLI_ERROR";
3
- const ANONYMIZE_MESSAGE_REGEX = /^(\w| )+/;
3
+ const ANONYMIZE_MESSAGE_REGEX = /^(?:\w| )+/;
4
4
  function anonymizeErrorMessage(msg) {
5
5
  const matchedMessage = msg.match(ANONYMIZE_MESSAGE_REGEX);
6
6
  if (!matchedMessage?.[0]) {
@@ -48,7 +48,7 @@ function getSafeErrorMessage(message) {
48
48
  function extractStringFromFunction(func) {
49
49
  const arrowIndex = func.indexOf("=>") + "=>".length;
50
50
  return func.slice(arrowIndex).trim().slice(1, -1).replace(
51
- /\${([^}]+)}/gm,
51
+ /\$\{([^}]+)\}/g,
52
52
  (str, match1) => `${match1.split(/\.?(?=[A-Z])/).join("_").toUpperCase()}`
53
53
  ).replace(/\\`/g, "`");
54
54
  }
@@ -221,7 +221,7 @@ const a11y = [
221
221
  title: "Redundant text in alt attribute",
222
222
  message: 'Screen readers already announce `img` elements as an image. There is no need to use words such as "image", "photo", and/or "picture".',
223
223
  selector: "img[alt]:not([aria-hidden])",
224
- match: (img) => /\b(image|picture|photo)\b/i.test(img.alt)
224
+ match: (img) => /\b(?:image|picture|photo)\b/i.test(img.alt)
225
225
  },
226
226
  {
227
227
  code: "a11y-incorrect-aria-attribute-type",
@@ -35,12 +35,9 @@ import { markHTMLString as markHTMLString2 } from "./escape.js";
35
35
  import { addAttribute as addAttribute2, Renderer as Renderer2 } from "./render/index.js";
36
36
  function mergeSlots(...slotted) {
37
37
  const slots = {};
38
- for (let slot of slotted) {
38
+ for (const slot of slotted) {
39
39
  if (!slot)
40
40
  continue;
41
- if (Array.isArray(slot)) {
42
- slot = mergeSlots(...slot);
43
- }
44
41
  if (typeof slot === "object") {
45
42
  Object.assign(slots, slot);
46
43
  } else if (typeof slot === "function") {
@@ -47,8 +47,8 @@ function isFragmentComponent(Component) {
47
47
  function isHTMLComponent(Component) {
48
48
  return Component && Component["astro:html"] === true;
49
49
  }
50
- const ASTRO_SLOT_EXP = /\<\/?astro-slot\b[^>]*>/g;
51
- const ASTRO_STATIC_SLOT_EXP = /\<\/?astro-static-slot\b[^>]*>/g;
50
+ const ASTRO_SLOT_EXP = /<\/?astro-slot\b[^>]*>/g;
51
+ const ASTRO_STATIC_SLOT_EXP = /<\/?astro-static-slot\b[^>]*>/g;
52
52
  function removeStaticAstroSlot(html, supportsAstroStaticSlot) {
53
53
  const exp = supportsAstroStaticSlot ? ASTRO_STATIC_SLOT_EXP : ASTRO_SLOT_EXP;
54
54
  return html.replace(exp, "");
@@ -305,7 +305,7 @@ ${serializeProps(
305
305
  };
306
306
  }
307
307
  function sanitizeElementName(tag) {
308
- const unsafe = /[&<>'"\s]+/g;
308
+ const unsafe = /[&<>'"\s]+/;
309
309
  if (!unsafe.test(tag))
310
310
  return tag;
311
311
  return tag.trim().split(unsafe)[0].trim();
@@ -1,12 +1,12 @@
1
1
  import { clsx } from "clsx";
2
2
  import { HTMLString, markHTMLString } from "../escape.js";
3
3
  const voidElementNames = /^(area|base|br|col|command|embed|hr|img|input|keygen|link|meta|param|source|track|wbr)$/i;
4
- const htmlBooleanAttributes = /^(allowfullscreen|async|autofocus|autoplay|controls|default|defer|disabled|disablepictureinpicture|disableremoteplayback|formnovalidate|hidden|loop|nomodule|novalidate|open|playsinline|readonly|required|reversed|scoped|seamless|itemscope)$/i;
5
- const htmlEnumAttributes = /^(contenteditable|draggable|spellcheck|value)$/i;
6
- const svgEnumAttributes = /^(autoReverse|externalResourcesRequired|focusable|preserveAlpha)$/i;
4
+ const htmlBooleanAttributes = /^(?:allowfullscreen|async|autofocus|autoplay|controls|default|defer|disabled|disablepictureinpicture|disableremoteplayback|formnovalidate|hidden|loop|nomodule|novalidate|open|playsinline|readonly|required|reversed|scoped|seamless|itemscope)$/i;
5
+ const htmlEnumAttributes = /^(?:contenteditable|draggable|spellcheck|value)$/i;
6
+ const svgEnumAttributes = /^(?:autoReverse|externalResourcesRequired|focusable|preserveAlpha)$/i;
7
7
  const STATIC_DIRECTIVES = /* @__PURE__ */ new Set(["set:html", "set:text"]);
8
- const toIdent = (k) => k.trim().replace(/(?:(?!^)\b\w|\s+|[^\w]+)/g, (match, index) => {
9
- if (/[^\w]|\s/.test(match))
8
+ const toIdent = (k) => k.trim().replace(/(?!^)\b\w|\s+|\W+/g, (match, index) => {
9
+ if (/\W/.test(match))
10
10
  return "";
11
11
  return index === 0 ? match : match.toUpperCase();
12
12
  });
@@ -1,7 +1,7 @@
1
1
  import { transformWithEsbuild } from "vite";
2
2
  import { compile } from "../core/compile/index.js";
3
3
  import { getFileInfo } from "../vite-plugin-utils/index.js";
4
- const FRONTMATTER_PARSE_REGEXP = /^\-\-\-(.*)^\-\-\-/ms;
4
+ import { frontmatterRE } from "./utils.js";
5
5
  async function compileAstro({
6
6
  compileProps,
7
7
  astroFileToCompileMetadata,
@@ -68,7 +68,7 @@ async function enhanceCompileError({
68
68
  source
69
69
  }) {
70
70
  const lineText = err.loc?.lineText;
71
- const scannedFrontmatter = FRONTMATTER_PARSE_REGEXP.exec(source);
71
+ const scannedFrontmatter = frontmatterRE.exec(source);
72
72
  if (scannedFrontmatter) {
73
73
  const frontmatter = scannedFrontmatter[1].replace(/\breturn\b/g, "throw");
74
74
  if (lineText && !frontmatter.includes(lineText))
@@ -1,5 +1,6 @@
1
1
  import path from "node:path";
2
2
  import { appendForwardSlash } from "@astrojs/internal-helpers/path";
3
+ import { frontmatterRE } from "./utils.js";
3
4
  async function handleHotUpdate(ctx, { logger, compile, astroFileToCssAstroDeps, astroFileToCompileMetadata }) {
4
5
  const oldCode = astroFileToCompileMetadata.get(ctx.file)?.originalCode;
5
6
  const newCode = await ctx.read();
@@ -21,7 +22,6 @@ async function handleHotUpdate(ctx, { logger, compile, astroFileToCssAstroDeps,
21
22
  }
22
23
  }
23
24
  }
24
- const frontmatterRE = /^\-\-\-.*?^\-\-\-/ms;
25
25
  const scriptRE = /<script(?:\s.*?)?>.*?<\/script>/gs;
26
26
  const styleRE = /<style(?:\s.*?)?>.*?<\/style>/gs;
27
27
  function isStyleOnlyChanged(oldCode, newCode) {
@@ -0,0 +1 @@
1
+ export declare const frontmatterRE: RegExp;
@@ -0,0 +1,4 @@
1
+ const frontmatterRE = /^---(.*?)^---/ms;
2
+ export {
3
+ frontmatterRE
4
+ };
@@ -8,5 +8,6 @@ interface ImportedStyle {
8
8
  export declare function getStylesForURL(filePath: URL, loader: ModuleLoader): Promise<{
9
9
  urls: Set<string>;
10
10
  styles: ImportedStyle[];
11
+ crawledFiles: Set<string>;
11
12
  }>;
12
13
  export {};
@@ -4,7 +4,11 @@ import { crawlGraph } from "./vite.js";
4
4
  async function getStylesForURL(filePath, loader) {
5
5
  const importedCssUrls = /* @__PURE__ */ new Set();
6
6
  const importedStylesMap = /* @__PURE__ */ new Map();
7
+ const crawledFiles = /* @__PURE__ */ new Set();
7
8
  for await (const importedModule of crawlGraph(loader, viteID(filePath), true)) {
9
+ if (importedModule.file) {
10
+ crawledFiles.add(importedModule.file);
11
+ }
8
12
  if (isBuildableCSSRequest(importedModule.url)) {
9
13
  let css = "";
10
14
  if (typeof importedModule.ssrModule?.default === "string") {
@@ -32,7 +36,8 @@ async function getStylesForURL(filePath, loader) {
32
36
  }
33
37
  return {
34
38
  urls: importedCssUrls,
35
- styles: [...importedStylesMap.values()]
39
+ styles: [...importedStylesMap.values()],
40
+ crawledFiles
36
41
  };
37
42
  }
38
43
  export {
@@ -64,7 +64,7 @@ async function matchRoute(pathname, manifestData, pipeline) {
64
64
  throw e;
65
65
  }
66
66
  }
67
- const altPathname = pathname.replace(/(index)?\.html$/, "");
67
+ const altPathname = pathname.replace(/(?:index)?\.html$/, "");
68
68
  if (altPathname !== pathname) {
69
69
  return await matchRoute(altPathname, manifestData, pipeline);
70
70
  }
@@ -159,6 +159,8 @@ async function handleRoute({
159
159
  return "";
160
160
  },
161
161
  params: [],
162
+ // Disable eslint as we only want to generate an empty RegExp
163
+ // eslint-disable-next-line prefer-regex-literals
162
164
  pattern: new RegExp(""),
163
165
  prerender: false,
164
166
  segments: [],
@@ -296,7 +298,7 @@ async function getScriptsAndStyles({ pipeline, filePath }) {
296
298
  const moduleLoader = pipeline.getModuleLoader();
297
299
  const settings = pipeline.getSettings();
298
300
  const mode = pipeline.getEnvironment().mode;
299
- const scripts = await getScriptsForURL(filePath, settings.config.root, moduleLoader);
301
+ const { scripts } = await getScriptsForURL(filePath, settings.config.root, moduleLoader);
300
302
  if (isPage(filePath, settings) && mode === "development") {
301
303
  scripts.add({
302
304
  props: { type: "module", src: "/@vite/client" },
@@ -1,3 +1,6 @@
1
1
  import type { SSRElement } from '../@types/astro.js';
2
2
  import type { ModuleLoader } from '../core/module-loader/index.js';
3
- export declare function getScriptsForURL(filePath: URL, root: URL, loader: ModuleLoader): Promise<Set<SSRElement>>;
3
+ export declare function getScriptsForURL(filePath: URL, root: URL, loader: ModuleLoader): Promise<{
4
+ scripts: Set<SSRElement>;
5
+ crawledFiles: Set<string>;
6
+ }>;
@@ -3,17 +3,21 @@ import { rootRelativePath, viteID } from "../core/util.js";
3
3
  import { crawlGraph } from "./vite.js";
4
4
  async function getScriptsForURL(filePath, root, loader) {
5
5
  const elements = /* @__PURE__ */ new Set();
6
+ const crawledFiles = /* @__PURE__ */ new Set();
6
7
  const rootID = viteID(filePath);
7
8
  const modInfo = loader.getModuleInfo(rootID);
8
9
  addHoistedScripts(elements, modInfo, root);
9
10
  for await (const moduleNode of crawlGraph(loader, rootID, true)) {
11
+ if (moduleNode.file) {
12
+ crawledFiles.add(moduleNode.file);
13
+ }
10
14
  const id = moduleNode.id;
11
15
  if (id) {
12
16
  const info = loader.getModuleInfo(id);
13
17
  addHoistedScripts(elements, info, root);
14
18
  }
15
19
  }
16
- return elements;
20
+ return { scripts: elements, crawledFiles };
17
21
  }
18
22
  function addHoistedScripts(set, info, root) {
19
23
  if (!info?.meta?.astro) {
@@ -3,7 +3,7 @@ import { loadEnv } from "vite";
3
3
  import { transform } from "esbuild";
4
4
  import MagicString from "magic-string";
5
5
  const importMetaEnvOnlyRe = /\bimport\.meta\.env\b(?!\.)/;
6
- const isValidIdentifierRe = /^[_$a-zA-Z][_$a-zA-Z0-9]*$/;
6
+ const isValidIdentifierRe = /^[_$a-zA-Z][\w$]*$/;
7
7
  const exportConstPrerenderRe = /\bexport\s+const\s+prerender\s*=\s*import\.meta\.env\.(.+?)\b/;
8
8
  function getPrivateEnv(viteConfig, astroConfig) {
9
9
  let envPrefixes = ["PUBLIC_"];
@@ -1,6 +1,6 @@
1
1
  import { getTopLevelPages, walkParentInfos } from "../core/build/graph.js";
2
2
  import { getAstroMetadata } from "../vite-plugin-astro/index.js";
3
- const injectExp = /(^\/\/|\/\/!)\s*astro-head-inject/;
3
+ const injectExp = /(?:^\/\/|\/\/!)\s*astro-head-inject/;
4
4
  function configHeadVitePlugin() {
5
5
  let server;
6
6
  function propagateMetadata(id, prop, value, seen = /* @__PURE__ */ new Set()) {
@@ -1,4 +1,4 @@
1
- const splitAttrsTokenizer = /([\$\{\}\@a-z0-9_\:\-]*)\s*?=\s*?(['"]?)(.*?)\2\s+/gim;
1
+ const splitAttrsTokenizer = /([${}@\w:\-]*)\s*=\s*?(['"]?)(.*?)\2\s+/g;
2
2
  function replaceAttribute(s, node, key, newValue) {
3
3
  splitAttrsTokenizer.lastIndex = 0;
4
4
  const text = s.original.slice(node.position?.start.offset ?? 0, node.position?.end.offset ?? 0).toString();
@@ -7,7 +7,7 @@ function replaceAttribute(s, node, key, newValue) {
7
7
  return;
8
8
  const start = node.position.start.offset + offset;
9
9
  const tokens = text.slice(offset).split(splitAttrsTokenizer);
10
- const token = tokens[0].replace(/([^>])(\>[\s\S]*$)/gim, "$1");
10
+ const token = tokens[0].replace(/([^>])>[\s\S]*$/gm, "$1");
11
11
  if (token.trim() === key) {
12
12
  const end = start + key.length;
13
13
  return s.overwrite(start, end, newValue, { contentOnly: true });
@@ -37,7 +37,7 @@ async function scan(code, id, settings) {
37
37
  const { n: name, le: endOfLocalName } = _export;
38
38
  if (BOOLEAN_EXPORTS.has(name)) {
39
39
  const prefix = code.slice(0, endOfLocalName).split("export").pop().trim().replace("prerender", "").trim();
40
- const suffix = code.slice(endOfLocalName).trim().replace(/\=/, "").trim().split(/[;\n]/)[0];
40
+ const suffix = code.slice(endOfLocalName).trim().replace(/=/, "").trim().split(/[;\n]/)[0];
41
41
  if (prefix !== "const" || !(isTruthy(suffix) || isFalsy(suffix))) {
42
42
  throw new AstroError({
43
43
  ...AstroErrorData.InvalidPrerenderExport,
@@ -11,7 +11,7 @@ function getFileInfo(id, config) {
11
11
  config.site ? new URL(config.base, config.site).pathname : config.base
12
12
  );
13
13
  const fileId = id.split("?")[0];
14
- let fileUrl = fileId.includes("/pages/") ? fileId.replace(/^.*?\/pages\//, sitePathname).replace(/(\/index)?\.(md|markdown|mdown|mkdn|mkd|mdwn|md|astro)$/, "") : void 0;
14
+ let fileUrl = fileId.includes("/pages/") ? fileId.replace(/^.*?\/pages\//, sitePathname).replace(/(?:\/index)?\.(?:md|markdown|mdown|mkdn|mkd|mdwn|astro)$/, "") : void 0;
15
15
  if (fileUrl && config.trailingSlash === "always") {
16
16
  fileUrl = appendForwardSlash(fileUrl);
17
17
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "astro",
3
- "version": "4.3.2",
3
+ "version": "4.3.4",
4
4
  "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
5
5
  "type": "module",
6
6
  "author": "withastro",
@@ -101,7 +101,7 @@
101
101
  "vendor"
102
102
  ],
103
103
  "dependencies": {
104
- "@astrojs/compiler": "^2.5.0",
104
+ "@astrojs/compiler": "^2.5.3",
105
105
  "@babel/core": "^7.23.3",
106
106
  "@babel/generator": "^7.23.3",
107
107
  "@babel/parser": "^7.23.3",