diff --git a/.changeset/angry-swans-fry.md b/.changeset/angry-swans-fry.md deleted file mode 100644 index ce5c513d5fc3..000000000000 --- a/.changeset/angry-swans-fry.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Redesign Dev Overlay main screen to show more information, such as the coolest integrations, your current Astro version and more. diff --git a/.changeset/beige-jokes-report.md b/.changeset/beige-jokes-report.md deleted file mode 100644 index ecb97328b6c1..000000000000 --- a/.changeset/beige-jokes-report.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'@astrojs/mdx': major -'@astrojs/markdown-remark': major -'astro': major ---- - -Updates the unified, remark, and rehype dependencies to latest. Make sure to update your custom remark and rehype plugins as well to be compatible with the latest versions. - -**Potentially breaking change:** The default value of `markdown.remarkRehype.footnoteBackLabel` is changed from `"Back to content"` to `"Back to reference 1"`. See the `mdast-util-to-hast` [commit](https://github.com/syntax-tree/mdast-util-to-hast/commit/56c88e45690be138fad9f0bf367b939d09816863) for more information. diff --git a/.changeset/big-cooks-notice.md b/.changeset/big-cooks-notice.md deleted file mode 100644 index 9a0586c73ad4..000000000000 --- a/.changeset/big-cooks-notice.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'@astrojs/vercel': major -'@astrojs/node': major ---- - -The internals of the integration have been updated to support Astro 4.0. Make sure to upgrade your Astro version as Astro 3.0 is no longer supported. diff --git a/.changeset/brown-jars-lick.md b/.changeset/brown-jars-lick.md deleted file mode 100644 index 0d824e445f47..000000000000 --- a/.changeset/brown-jars-lick.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Fixes an issue where links with the same pathname as the current page, but different search params, were not prefetched. diff --git a/.changeset/calm-baboons-watch.md b/.changeset/calm-baboons-watch.md deleted file mode 100644 index a0e8259e965e..000000000000 --- a/.changeset/calm-baboons-watch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': minor ---- - -Update CLI logging experience diff --git a/.changeset/clever-beds-notice.md b/.changeset/clever-beds-notice.md deleted file mode 100644 index 6be65bde1157..000000000000 --- a/.changeset/clever-beds-notice.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'astro': major ---- - -Removes support for returning simple objects from endpoints (deprecated since Astro 3.0). You should return a `Response` instead. - -`ResponseWithEncoding` is also removed. You can refactor the code to return a response with an array buffer instead, which is encoding agnostic. - -The types for middlewares have also been revised. To type a middleware function, you should now use `MiddlewareHandler` instead of `MiddlewareResponseHandler`. If you used `defineMiddleware()` to type the function, no changes are needed. diff --git a/.changeset/curvy-sheep-lick.md b/.changeset/curvy-sheep-lick.md deleted file mode 100644 index d369d129d41f..000000000000 --- a/.changeset/curvy-sheep-lick.md +++ /dev/null @@ -1,6 +0,0 @@ ---- -'astro': patch ---- - -Consistently emit fallback routes in the correct folders, and emit routes that -consider `trailingSlash` diff --git a/.changeset/famous-eels-trade.md b/.changeset/famous-eels-trade.md deleted file mode 100644 index 2c3d24898746..000000000000 --- a/.changeset/famous-eels-trade.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Ensure the dev-overlay-window is anchored to the bottom diff --git a/.changeset/fluffy-dolls-sleep.md b/.changeset/fluffy-dolls-sleep.md deleted file mode 100644 index 02b698f1e492..000000000000 --- a/.changeset/fluffy-dolls-sleep.md +++ /dev/null @@ -1,26 +0,0 @@ ---- -'astro': minor ---- - -Adds a new way to configure the `i18n.locales` array. - -Developers can now assign a custom URL path prefix that can span multiple language codes: - -```js -// astro.config.mjs -export default defineConfig({ - experimental: { - i18n: { - defaultLocale: "english", - locales: [ - "de", - { path: "english", codes: ["en", "en-US"]}, - "fr", - ], - routingStrategy: "prefix-always" - } - } -}) -``` - -With the above configuration, the URL prefix of the default locale will be `/english/`. When computing `Astro.preferredLocale`, Astro will use the `codes`. diff --git a/.changeset/gentle-cobras-wash.md b/.changeset/gentle-cobras-wash.md deleted file mode 100644 index 1a9245524aae..000000000000 --- a/.changeset/gentle-cobras-wash.md +++ /dev/null @@ -1,17 +0,0 @@ ---- -'astro': minor ---- - -Adds the `astro preferences` command to manage user preferences. User preferences are specific to individual Astro users, unlike the `astro.config.mjs` file which changes behavior for everyone working on a project. - -User preferences are scoped to the current project by default, stored in a local `.astro/settings.json` file. Using the `--global` flag, user preferences can also be applied to every Astro project on the current machine. Global user preferences are stored in an operating system-specific location. - -```sh -# Disable the dev overlay for the current user in the current project -npm run astro preferences disable devOverlay -# Disable the dev overlay for the current user in all Astro projects on this machine -npm run astro preferences --global disable devOverlay - -# Check if the dev overlay is enabled for the current user -npm run astro preferences list devOverlay -``` diff --git a/.changeset/giant-snails-perform.md b/.changeset/giant-snails-perform.md deleted file mode 100644 index e44a0b73060b..000000000000 --- a/.changeset/giant-snails-perform.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@astrojs/vercel': major ---- - -Removes deprecated `analytics` option. Use the `webAnalytics` option instead. diff --git a/.changeset/gold-grapes-jump.md b/.changeset/gold-grapes-jump.md deleted file mode 100644 index d3da8b72e9eb..000000000000 --- a/.changeset/gold-grapes-jump.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': minor ---- - -Reworks Vite's logger to use Astro's logger to correctly log HMR messages diff --git a/.changeset/green-impalas-fetch.md b/.changeset/green-impalas-fetch.md deleted file mode 100644 index 02b77375fd40..000000000000 --- a/.changeset/green-impalas-fetch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Fix SVG icons not showing properly in the extended dropdown menu of the dev overlay diff --git a/.changeset/green-parrots-brake.md b/.changeset/green-parrots-brake.md deleted file mode 100644 index f2d9db4be5bc..000000000000 --- a/.changeset/green-parrots-brake.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -'astro': major ---- - -Removes additional deprecated APIs: - -- The Astro preview server now returns a 404 status instead of a 301 redirect when requesting assets from the public directory without a base. -- Removes special handling when referencing the `astro/client-image` type. You should use the `astro/client` type instead. -- Removes deprecated built-in `rss` support in `getStaticPaths`. You should use `@astrojs/rss` instead. -- Removes deprecated `Astro.request.params` support. You should use `Astro.params` instead. diff --git a/.changeset/grumpy-seas-switch.md b/.changeset/grumpy-seas-switch.md deleted file mode 100644 index 85cf0e22fe56..000000000000 --- a/.changeset/grumpy-seas-switch.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Improve high contrast mode with the Dev Overlay diff --git a/.changeset/grumpy-turtles-tickle.md b/.changeset/grumpy-turtles-tickle.md deleted file mode 100644 index 75f8f0eec333..000000000000 --- a/.changeset/grumpy-turtles-tickle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Improve highlight/tooltip positioning when in fixed positions diff --git a/.changeset/khaki-fans-sell.md b/.changeset/khaki-fans-sell.md deleted file mode 100644 index f6d84bdaedac..000000000000 --- a/.changeset/khaki-fans-sell.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@astrojs/markdown-remark': patch ---- - -Fixes `RemarkRehype` type's `handler` and `handlers` properties diff --git a/.changeset/lemon-crews-juggle.md b/.changeset/lemon-crews-juggle.md deleted file mode 100644 index d838bdbaadd5..000000000000 --- a/.changeset/lemon-crews-juggle.md +++ /dev/null @@ -1,9 +0,0 @@ ---- -'astro': major ---- - -Renames Dev Overlay to Dev Toolbar - -The previously named experimental Dev Overlay is now known as the Astro Dev Toolbar. Plugins have been renamed as Toolbar Apps. This updates our references to reflect. - -To not break existing APIs, aliases for the Toolbar-based names have been created. The previous API names will continue to function but will be deprecated in the future. All documentation has been updated to reflect Toolbar-based names. diff --git a/.changeset/light-ties-poke.md b/.changeset/light-ties-poke.md deleted file mode 100644 index 97eceace43e9..000000000000 --- a/.changeset/light-ties-poke.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -'@astrojs/svelte': major -'@astrojs/react': patch -'@astrojs/vue': patch -'astro': major ---- - -Adds Vite 5 support. There are no breaking changes from Astro. Check the [Vite migration guide](https://vitejs.dev/guide/migration.html) for details of the breaking changes from Vite instead. diff --git a/.changeset/little-beers-sit.md b/.changeset/little-beers-sit.md deleted file mode 100644 index 97dd63873884..000000000000 --- a/.changeset/little-beers-sit.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@astrojs/markdoc': minor ---- - -Removes internal `propagators` handling for Astro 3 diff --git a/.changeset/mighty-rats-flow.md b/.changeset/mighty-rats-flow.md deleted file mode 100644 index 8fbec88bafc3..000000000000 --- a/.changeset/mighty-rats-flow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Update the look and feel of the dev overlay diff --git a/.changeset/modern-candles-sip.md b/.changeset/modern-candles-sip.md deleted file mode 100644 index 31e75c412551..000000000000 --- a/.changeset/modern-candles-sip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'create-astro': patch ---- - -Stop clearing the console on start diff --git a/.changeset/ninety-weeks-juggle.md b/.changeset/ninety-weeks-juggle.md deleted file mode 100644 index a78fda8467d1..000000000000 --- a/.changeset/ninety-weeks-juggle.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Adds properties of the submit button (name, value) to the form data of a view transition diff --git a/.changeset/odd-rivers-happen.md b/.changeset/odd-rivers-happen.md deleted file mode 100644 index 2490084bc234..000000000000 --- a/.changeset/odd-rivers-happen.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': major ---- - -Removes the opt-in `handleForms` property for ``. Form submissions are now handled by default and can be disabled by setting `data-astro-reload` on relevant `
` elements. diff --git a/.changeset/plenty-candles-help.md b/.changeset/plenty-candles-help.md deleted file mode 100644 index e7ddf8cb4fcb..000000000000 --- a/.changeset/plenty-candles-help.md +++ /dev/null @@ -1,21 +0,0 @@ ---- -'astro': major ---- - -Removes support for Shiki custom language's `path` property. The language JSON file should be imported and passed to the option instead. - -```diff -// astro.config.js -+ import customLang from './custom.tmLanguage.json' - -export default defineConfig({ - markdown: { - shikiConfig: { - langs: [ -- { path: './custom.tmLanguage.json' }, -+ customLang, - ], - }, - }, -}) -``` diff --git a/.changeset/pre.json b/.changeset/pre.json deleted file mode 100644 index 6f386be808ce..000000000000 --- a/.changeset/pre.json +++ /dev/null @@ -1,74 +0,0 @@ -{ - "mode": "pre", - "tag": "beta", - "initialVersions": { - "astro": "3.5.5", - "@astrojs/prism": "3.0.0", - "@astrojs/rss": "3.0.0", - "create-astro": "4.5.1", - "@astrojs/alpinejs": "0.3.1", - "@astrojs/cloudflare": "0.0.0", - "@astrojs/lit": "3.0.3", - "@astrojs/markdoc": "0.7.2", - "@astrojs/mdx": "1.1.5", - "@astrojs/netlify": "0.0.0", - "@astrojs/node": "6.0.4", - "@astrojs/partytown": "2.0.2", - "@astrojs/preact": "3.0.1", - "@astrojs/react": "3.0.5", - "@astrojs/sitemap": "3.0.3", - "@astrojs/solid-js": "3.0.2", - "@astrojs/svelte": "4.0.4", - "@astrojs/tailwind": "5.0.2", - "@astrojs/vercel": "5.2.0", - "@astrojs/vue": "3.0.4", - "@astrojs/internal-helpers": "0.2.1", - "@astrojs/markdown-remark": "3.5.0", - "@astrojs/telemetry": "3.0.4", - "@astrojs/underscore-redirects": "0.3.3", - "@astrojs/upgrade": "0.0.1" - }, - "changesets": [ - "angry-swans-fry", - "beige-jokes-report", - "big-cooks-notice", - "brown-jars-lick", - "calm-baboons-watch", - "clever-beds-notice", - "curvy-sheep-lick", - "famous-eels-trade", - "fluffy-dolls-sleep", - "gentle-cobras-wash", - "giant-snails-perform", - "gold-grapes-jump", - "green-impalas-fetch", - "green-parrots-brake", - "grumpy-seas-switch", - "grumpy-turtles-tickle", - "khaki-fans-sell", - "lemon-crews-juggle", - "light-ties-poke", - "little-beers-sit", - "mighty-rats-flow", - "modern-candles-sip", - "ninety-weeks-juggle", - "odd-rivers-happen", - "plenty-candles-help", - "rude-hairs-whisper", - "sharp-starfishes-compete", - "shiny-trees-sip", - "short-deers-whisper", - "slimy-jeans-peel", - "slow-hornets-try", - "sour-games-burn", - "spicy-starfishes-shake", - "tasty-dryers-bathe", - "tasty-parents-own", - "three-chairs-sip", - "tricky-dragons-explain", - "weak-wolves-bow", - "wicked-sloths-develop", - "wild-apricots-rescue", - "wild-boats-wait" - ] -} diff --git a/.changeset/rude-hairs-whisper.md b/.changeset/rude-hairs-whisper.md deleted file mode 100644 index a9d7baa4d445..000000000000 --- a/.changeset/rude-hairs-whisper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': minor ---- - -Renames the `entryPoint` property of the `injectRoute` integrations API to `entrypoint` for consistency. A warning will be shown prompting you to update your code when using the old name. diff --git a/.changeset/sharp-starfishes-compete.md b/.changeset/sharp-starfishes-compete.md deleted file mode 100644 index 0eb4f413bcda..000000000000 --- a/.changeset/sharp-starfishes-compete.md +++ /dev/null @@ -1,20 +0,0 @@ ---- -'astro': major ---- - -This change only affects maintainers of third-party adapters. In the Integration API, the `app.render()` method of the `App` class has been simplified. - -Instead of two optional arguments, it now takes a single optional argument that is an object with two optional properties: `routeData` and `locals`. -```diff - app.render(request) - -- app.render(request, routeData) -+ app.render(request, { routeData }) - -- app.render(request, routeData, locals) -+ app.render(request, { routeData, locals }) - -- app.render(request, undefined, locals) -+ app.render(request, { locals }) -``` -The current signature is deprecated but will continue to function until next major version. diff --git a/.changeset/shiny-trees-sip.md b/.changeset/shiny-trees-sip.md deleted file mode 100644 index 991c7aa92825..000000000000 --- a/.changeset/shiny-trees-sip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@astrojs/markdown-remark': major ---- - -Removes deprecated APIs. All Astro packages had been refactored to not use these APIs. diff --git a/.changeset/short-deers-whisper.md b/.changeset/short-deers-whisper.md deleted file mode 100644 index 03e0f4480676..000000000000 --- a/.changeset/short-deers-whisper.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Removes vendored Vite's `importMeta.d.ts` file in favour of Vite 5's new `vite/types/import-meta.d.ts` export diff --git a/.changeset/slimy-jeans-peel.md b/.changeset/slimy-jeans-peel.md deleted file mode 100644 index c4ba769e3060..000000000000 --- a/.changeset/slimy-jeans-peel.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@astrojs/vercel': major ---- - -Removes the deprecated `@astrojs/vercel/edge` export. You should use `@astrojs/vercel/serverless` instead with the `edgeMiddleware` option. diff --git a/.changeset/slow-hornets-try.md b/.changeset/slow-hornets-try.md deleted file mode 100644 index 970e7f49105b..000000000000 --- a/.changeset/slow-hornets-try.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@astrojs/rss': major ---- - -Removes the `drafts` option as the feature is deprecated in Astro 3.0 diff --git a/.changeset/smart-cats-camp.md b/.changeset/smart-cats-camp.md deleted file mode 100644 index 96f290362b79..000000000000 --- a/.changeset/smart-cats-camp.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Fix routing prefixes when `prefixDefaultLocale` is `true` diff --git a/.changeset/sour-games-burn.md b/.changeset/sour-games-burn.md deleted file mode 100644 index f0d596603ddd..000000000000 --- a/.changeset/sour-games-burn.md +++ /dev/null @@ -1,13 +0,0 @@ ---- -"astro": patch ---- - -Refactors virtual modules exports. This should not break your project unless you import Astro's internal modules, including: - -- `astro/middleware/namespace` -- `astro/transitions` -- `astro/transitions/router` -- `astro/transitions/events` -- `astro/transitions/types` -- `astro/prefetch` -- `astro/i18n` diff --git a/.changeset/spicy-starfishes-shake.md b/.changeset/spicy-starfishes-shake.md deleted file mode 100644 index a283f4d37911..000000000000 --- a/.changeset/spicy-starfishes-shake.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Ensure overlay x-ray z-index is higher than the island diff --git a/.changeset/tasty-dryers-bathe.md b/.changeset/tasty-dryers-bathe.md deleted file mode 100644 index 438597e13b04..000000000000 --- a/.changeset/tasty-dryers-bathe.md +++ /dev/null @@ -1,27 +0,0 @@ ---- -'@astrojs/upgrade': minor ---- - -Initial release! - -`@astrojs/upgrade` is an automated command-line tool for upgrading Astro and your official Astro integrations together. - -Inside of your existing `astro` project, run the following command to install the `latest` version of your integrations. - -**With NPM:** - -```bash -npx @astrojs/upgrade -``` - -**With Yarn:** - -```bash -yarn dlx @astrojs/upgrade -``` - -**With PNPM:** - -```bash -pnpm dlx @astrojs/upgrade -``` diff --git a/.changeset/tasty-parents-own.md b/.changeset/tasty-parents-own.md deleted file mode 100644 index 3ab6ca510b4e..000000000000 --- a/.changeset/tasty-parents-own.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Adds instructions on how to hide the dev overlay diff --git a/.changeset/three-chairs-sip.md b/.changeset/three-chairs-sip.md deleted file mode 100644 index 68bdc0a61426..000000000000 --- a/.changeset/three-chairs-sip.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': minor ---- - -Update error log formatting diff --git a/.changeset/tricky-dragons-explain.md b/.changeset/tricky-dragons-explain.md deleted file mode 100644 index 78ecb1e95752..000000000000 --- a/.changeset/tricky-dragons-explain.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Fixes a number of small user experience bugs with the dev overlay diff --git a/.changeset/weak-wolves-bow.md b/.changeset/weak-wolves-bow.md deleted file mode 100644 index 484544cd12b7..000000000000 --- a/.changeset/weak-wolves-bow.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': major ---- - -Removes deprecated `app.match()` option, `matchNotFound` diff --git a/.changeset/wicked-sloths-develop.md b/.changeset/wicked-sloths-develop.md deleted file mode 100644 index 806e0270728f..000000000000 --- a/.changeset/wicked-sloths-develop.md +++ /dev/null @@ -1,11 +0,0 @@ ---- -'astro': major ---- - -Removes deprecated features from Astro 3.0 - -- Adapters are now required to pass `supportedAstroFeatures` to specify a list of features they support. -- The `build.split` and `build.excludeMiddleware` options are removed. Use `functionPerRoute` and `edgeMiddleware` from adapters instead. -- The `markdown.drafts` option and draft feature is removed. Use content collections instead. -- Lowercase endpoint names are no longer supported. Use uppercase endpoint names instead. -- `getHeaders()` exported from markdown files is removed. Use `getHeadings()` instead. diff --git a/.changeset/wild-apricots-rescue.md b/.changeset/wild-apricots-rescue.md deleted file mode 100644 index c4a7deea3eb3..000000000000 --- a/.changeset/wild-apricots-rescue.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'@astrojs/svelte': major ---- - -Drops support for Svelte 3 as `@sveltejs/vite-plugin-svelte` is updated to `3.0.0` which does not support Svelte 3 diff --git a/.changeset/wild-boats-wait.md b/.changeset/wild-boats-wait.md deleted file mode 100644 index 6300e839ea5d..000000000000 --- a/.changeset/wild-boats-wait.md +++ /dev/null @@ -1,5 +0,0 @@ ---- -'astro': patch ---- - -Returns the updated config in the integration `astro:config:setup` hook's `updateConfig()` API diff --git a/.eslintrc.cjs b/.eslintrc.cjs index e6085ac647f6..95f00b476289 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -58,6 +58,16 @@ module.exports = { '@typescript-eslint/unbound-method': 'off', '@typescript-eslint/no-explicit-any': 'off', + // Enforce separate type imports for type-only imports to avoid bundling unneeded code + '@typescript-eslint/consistent-type-imports': [ + 'error', + { + prefer: 'type-imports', + fixStyle: 'separate-type-imports', + disallowTypeAnnotations: false, + }, + ], + // These rules enabled by the preset configs don't work well for us '@typescript-eslint/await-thenable': 'off', 'prefer-const': 'off', diff --git a/LICENSE b/LICENSE index 1f0bcaa7dcef..b3cd0c0f0e01 100644 --- a/LICENSE +++ b/LICENSE @@ -20,7 +20,6 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - """ This license applies to parts of the `packages/create-astro` and `packages/astro` subdirectories originating from the https://github.com/sveltejs/kit repository: @@ -33,7 +32,6 @@ The above copyright notice and this permission notice shall be included in all c THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. """ - """ This license applies to parts of the `packages/create-astro` and `packages/astro` subdirectories originating from the https://github.com/vitejs/vite repository: diff --git a/examples/basics/package.json b/examples/basics/package.json index 7abdfe6a1293..d33671b1fb9f 100644 --- a/examples/basics/package.json +++ b/examples/basics/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^4.0.0-beta.4" + "astro": "^4.0.3" } } diff --git a/examples/blog/package.json b/examples/blog/package.json index 39563bd0c119..0c42df70d5fb 100644 --- a/examples/blog/package.json +++ b/examples/blog/package.json @@ -11,9 +11,9 @@ "astro": "astro" }, "dependencies": { - "@astrojs/mdx": "^2.0.0-beta.0", - "@astrojs/rss": "^4.0.0-beta.0", + "@astrojs/mdx": "^2.0.0", + "@astrojs/rss": "^4.0.1", "@astrojs/sitemap": "^3.0.3", - "astro": "^4.0.0-beta.4" + "astro": "^4.0.3" } } diff --git a/examples/component/package.json b/examples/component/package.json index 9b40573f38b1..3a72bb72e0bb 100644 --- a/examples/component/package.json +++ b/examples/component/package.json @@ -15,7 +15,7 @@ ], "scripts": {}, "devDependencies": { - "astro": "^4.0.0-beta.4" + "astro": "^4.0.3" }, "peerDependencies": { "astro": "^3.0.0" diff --git a/examples/framework-alpine/package.json b/examples/framework-alpine/package.json index 43157492725f..d37a79bc0e55 100644 --- a/examples/framework-alpine/package.json +++ b/examples/framework-alpine/package.json @@ -14,6 +14,6 @@ "@astrojs/alpinejs": "^0.3.1", "@types/alpinejs": "^3.13.5", "alpinejs": "^3.13.3", - "astro": "^4.0.0-beta.4" + "astro": "^4.0.3" } } diff --git a/examples/framework-lit/package.json b/examples/framework-lit/package.json index 9003183a9d76..96593eb37f47 100644 --- a/examples/framework-lit/package.json +++ b/examples/framework-lit/package.json @@ -13,7 +13,7 @@ "dependencies": { "@astrojs/lit": "^3.0.3", "@webcomponents/template-shadowroot": "^0.2.1", - "astro": "^4.0.0-beta.4", + "astro": "^4.0.3", "lit": "^2.8.0" } } diff --git a/examples/framework-multiple/package.json b/examples/framework-multiple/package.json index 5cb403a878b3..498b56f78207 100644 --- a/examples/framework-multiple/package.json +++ b/examples/framework-multiple/package.json @@ -12,11 +12,11 @@ }, "dependencies": { "@astrojs/preact": "^3.0.1", - "@astrojs/react": "^3.0.7-beta.0", + "@astrojs/react": "^3.0.7", "@astrojs/solid-js": "^3.0.2", - "@astrojs/svelte": "^5.0.0-beta.0", - "@astrojs/vue": "^4.0.0-beta.0", - "astro": "^4.0.0-beta.4", + "@astrojs/svelte": "^5.0.0", + "@astrojs/vue": "^4.0.2", + "astro": "^4.0.3", "preact": "^10.19.2", "react": "^18.2.0", "react-dom": "^18.2.0", diff --git a/examples/framework-preact/package.json b/examples/framework-preact/package.json index 5d7d53870fd5..5ed6833731ec 100644 --- a/examples/framework-preact/package.json +++ b/examples/framework-preact/package.json @@ -13,7 +13,7 @@ "dependencies": { "@astrojs/preact": "^3.0.1", "@preact/signals": "^1.2.1", - "astro": "^4.0.0-beta.4", + "astro": "^4.0.3", "preact": "^10.19.2" } } diff --git a/examples/framework-react/package.json b/examples/framework-react/package.json index 42a380a470b6..1732ec7906c4 100644 --- a/examples/framework-react/package.json +++ b/examples/framework-react/package.json @@ -11,10 +11,10 @@ "astro": "astro" }, "dependencies": { - "@astrojs/react": "^3.0.7-beta.0", + "@astrojs/react": "^3.0.7", "@types/react": "^18.2.37", "@types/react-dom": "^18.2.15", - "astro": "^4.0.0-beta.4", + "astro": "^4.0.3", "react": "^18.2.0", "react-dom": "^18.2.0" } diff --git a/examples/framework-solid/package.json b/examples/framework-solid/package.json index c7b542dd1479..709d10f81572 100644 --- a/examples/framework-solid/package.json +++ b/examples/framework-solid/package.json @@ -12,7 +12,7 @@ }, "dependencies": { "@astrojs/solid-js": "^3.0.2", - "astro": "^4.0.0-beta.4", + "astro": "^4.0.3", "solid-js": "^1.8.5" } } diff --git a/examples/framework-svelte/package.json b/examples/framework-svelte/package.json index a7df437f655a..c99ea913456f 100644 --- a/examples/framework-svelte/package.json +++ b/examples/framework-svelte/package.json @@ -11,8 +11,8 @@ "astro": "astro" }, "dependencies": { - "@astrojs/svelte": "^5.0.0-beta.0", - "astro": "^4.0.0-beta.4", + "@astrojs/svelte": "^5.0.0", + "astro": "^4.0.3", "svelte": "^4.2.5" } } diff --git a/examples/framework-vue/package.json b/examples/framework-vue/package.json index 1f1b3c8dfbf2..3a4480862d1b 100644 --- a/examples/framework-vue/package.json +++ b/examples/framework-vue/package.json @@ -11,8 +11,8 @@ "astro": "astro" }, "dependencies": { - "@astrojs/vue": "^4.0.0-beta.0", - "astro": "^4.0.0-beta.4", + "@astrojs/vue": "^4.0.2", + "astro": "^4.0.3", "vue": "^3.3.8" } } diff --git a/examples/hackernews/package.json b/examples/hackernews/package.json index dcc31e68d837..28a3310acbcf 100644 --- a/examples/hackernews/package.json +++ b/examples/hackernews/package.json @@ -11,7 +11,7 @@ "astro": "astro" }, "dependencies": { - "@astrojs/node": "^7.0.0-beta.1", - "astro": "^4.0.0-beta.4" + "@astrojs/node": "^7.0.0", + "astro": "^4.0.3" } } diff --git a/examples/integration/package.json b/examples/integration/package.json index 56d3da06015e..a92a888b46e6 100644 --- a/examples/integration/package.json +++ b/examples/integration/package.json @@ -15,7 +15,7 @@ ], "scripts": {}, "devDependencies": { - "astro": "^4.0.0-beta.4" + "astro": "^4.0.3" }, "peerDependencies": { "astro": "^3.0.0" diff --git a/examples/middleware/package.json b/examples/middleware/package.json index 48f890b43136..9af03a263845 100644 --- a/examples/middleware/package.json +++ b/examples/middleware/package.json @@ -12,8 +12,8 @@ "server": "node dist/server/entry.mjs" }, "dependencies": { - "@astrojs/node": "^7.0.0-beta.1", - "astro": "^4.0.0-beta.4", + "@astrojs/node": "^7.0.0", + "astro": "^4.0.3", "html-minifier": "^4.0.0" } } diff --git a/examples/minimal/package.json b/examples/minimal/package.json index 816dcad775cf..4e4fb33d36ea 100644 --- a/examples/minimal/package.json +++ b/examples/minimal/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^4.0.0-beta.4" + "astro": "^4.0.3" } } diff --git a/examples/non-html-pages/package.json b/examples/non-html-pages/package.json index 7b0fd18d48cd..52b4c9fc71e2 100644 --- a/examples/non-html-pages/package.json +++ b/examples/non-html-pages/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^4.0.0-beta.4" + "astro": "^4.0.3" } } diff --git a/examples/portfolio/package.json b/examples/portfolio/package.json index c80d64b0b463..01d5effb6220 100644 --- a/examples/portfolio/package.json +++ b/examples/portfolio/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^4.0.0-beta.4" + "astro": "^4.0.3" } } diff --git a/examples/ssr/package.json b/examples/ssr/package.json index a2e206bf14e1..5c6c5c20f62d 100644 --- a/examples/ssr/package.json +++ b/examples/ssr/package.json @@ -12,9 +12,9 @@ "server": "node dist/server/entry.mjs" }, "dependencies": { - "@astrojs/node": "^7.0.0-beta.1", - "@astrojs/svelte": "^5.0.0-beta.0", - "astro": "^4.0.0-beta.4", + "@astrojs/node": "^7.0.0", + "@astrojs/svelte": "^5.0.0", + "astro": "^4.0.3", "svelte": "^4.2.5" } } diff --git a/examples/view-transitions/package.json b/examples/view-transitions/package.json index 7408bec60c88..bb19a4f032a8 100644 --- a/examples/view-transitions/package.json +++ b/examples/view-transitions/package.json @@ -10,8 +10,8 @@ "astro": "astro" }, "devDependencies": { - "@astrojs/tailwind": "^6.0.0-beta.0", - "@astrojs/node": "^7.0.0-beta.1", - "astro": "^4.0.0-beta.4" + "@astrojs/tailwind": "^5.0.3", + "@astrojs/node": "^7.0.0", + "astro": "^4.0.3" } } diff --git a/examples/with-markdoc/package.json b/examples/with-markdoc/package.json index f2fe1301beb0..4d63d789ce6b 100644 --- a/examples/with-markdoc/package.json +++ b/examples/with-markdoc/package.json @@ -11,7 +11,7 @@ "astro": "astro" }, "dependencies": { - "@astrojs/markdoc": "^1.0.0-beta.1", - "astro": "^4.0.0-beta.4" + "@astrojs/markdoc": "^0.8.0", + "astro": "^4.0.3" } } diff --git a/examples/with-markdown-plugins/package.json b/examples/with-markdown-plugins/package.json index 5155dee67fcb..bd86abdde00d 100644 --- a/examples/with-markdown-plugins/package.json +++ b/examples/with-markdown-plugins/package.json @@ -11,8 +11,8 @@ "astro": "astro" }, "dependencies": { - "@astrojs/markdown-remark": "^4.0.0-beta.0", - "astro": "^4.0.0-beta.4", + "@astrojs/markdown-remark": "^4.0.0", + "astro": "^4.0.3", "hast-util-select": "^6.0.2", "rehype-autolink-headings": "^7.1.0", "rehype-slug": "^6.0.0", diff --git a/examples/with-markdown-shiki/package.json b/examples/with-markdown-shiki/package.json index 23147377488e..56de8c8716ef 100644 --- a/examples/with-markdown-shiki/package.json +++ b/examples/with-markdown-shiki/package.json @@ -11,6 +11,6 @@ "astro": "astro" }, "dependencies": { - "astro": "^4.0.0-beta.4" + "astro": "^4.0.3" } } diff --git a/examples/with-mdx/package.json b/examples/with-mdx/package.json index f6a9fed87b0b..b0e08746819f 100644 --- a/examples/with-mdx/package.json +++ b/examples/with-mdx/package.json @@ -11,9 +11,9 @@ "astro": "astro" }, "dependencies": { - "@astrojs/mdx": "^2.0.0-beta.0", + "@astrojs/mdx": "^2.0.0", "@astrojs/preact": "^3.0.1", - "astro": "^4.0.0-beta.4", + "astro": "^4.0.3", "preact": "^10.19.2" } } diff --git a/examples/with-nanostores/package.json b/examples/with-nanostores/package.json index 46fa70d1499a..66bd31e66dff 100644 --- a/examples/with-nanostores/package.json +++ b/examples/with-nanostores/package.json @@ -13,7 +13,7 @@ "dependencies": { "@astrojs/preact": "^3.0.1", "@nanostores/preact": "^0.5.0", - "astro": "^4.0.0-beta.4", + "astro": "^4.0.3", "nanostores": "^0.9.5", "preact": "^10.19.2" } diff --git a/examples/with-tailwindcss/package.json b/examples/with-tailwindcss/package.json index 9cdd53045903..c62ad3343514 100644 --- a/examples/with-tailwindcss/package.json +++ b/examples/with-tailwindcss/package.json @@ -11,10 +11,10 @@ "astro": "astro" }, "dependencies": { - "@astrojs/mdx": "^2.0.0-beta.0", - "@astrojs/tailwind": "^6.0.0-beta.0", + "@astrojs/mdx": "^2.0.0", + "@astrojs/tailwind": "^5.0.3", "@types/canvas-confetti": "^1.6.3", - "astro": "^4.0.0-beta.4", + "astro": "^4.0.3", "autoprefixer": "^10.4.15", "canvas-confetti": "^1.9.1", "postcss": "^8.4.28", diff --git a/examples/with-vitest/package.json b/examples/with-vitest/package.json index 4936a5894838..54f7fdf99720 100644 --- a/examples/with-vitest/package.json +++ b/examples/with-vitest/package.json @@ -12,7 +12,7 @@ "test": "vitest" }, "dependencies": { - "astro": "^4.0.0-beta.4", + "astro": "^4.0.3", "vitest": "^0.34.2" } } diff --git a/packages/astro-rss/CHANGELOG.md b/packages/astro-rss/CHANGELOG.md index 60327a088ea0..df205874890d 100644 --- a/packages/astro-rss/CHANGELOG.md +++ b/packages/astro-rss/CHANGELOG.md @@ -1,5 +1,17 @@ # @astrojs/rss +## 4.0.1 + +### Patch Changes + +- [#9299](https://github.com/withastro/astro/pull/9299) [`edfae50e6`](https://github.com/withastro/astro/commit/edfae50e6ea494f49c6d4fbf4bd4481870f994b1) Thanks [@cdvillard](https://github.com/cdvillard)! - Improves the `@astrojs/rss` error message thrown when the object passed to the `items` property is missing any of the three required keys or if one of those keys is mistyped. + +## 4.0.0 + +### Major Changes + +- [#9168](https://github.com/withastro/astro/pull/9168) [`153a5abb9`](https://github.com/withastro/astro/commit/153a5abb905042ac68b712514dc9ec387d3e6b17) Thanks [@bluwy](https://github.com/bluwy)! - Removes the deprecated (in v3.0) `drafts` option as the feature is deprecated in Astro 3.0 + ## 4.0.0-beta.0 ### Major Changes diff --git a/packages/astro-rss/package.json b/packages/astro-rss/package.json index 86df612b7707..c262452daf0b 100644 --- a/packages/astro-rss/package.json +++ b/packages/astro-rss/package.json @@ -1,7 +1,7 @@ { "name": "@astrojs/rss", "description": "Add RSS feeds to your Astro projects", - "version": "4.0.0-beta.0", + "version": "4.0.1", "type": "module", "types": "./dist/index.d.ts", "author": "withastro", diff --git a/packages/astro-rss/src/index.ts b/packages/astro-rss/src/index.ts index 48c5defe855c..c8cf19d6022e 100644 --- a/packages/astro-rss/src/index.ts +++ b/packages/astro-rss/src/index.ts @@ -109,9 +109,21 @@ async function validateRssOptions(rssOptions: RSSOptions) { const formattedError = new Error( [ `[RSS] Invalid or missing options:`, - ...parsedResult.error.errors.map( - (zodError) => `${zodError.message} (${zodError.path.join('.')})` - ), + ...parsedResult.error.errors.map((zodError) => { + const path = zodError.path.join('.'); + const message = `${zodError.message} (${path})`; + const code = zodError.code; + + if (path === 'items' && code === 'invalid_union') { + return [ + message, + `The \`items\` property requires properly typed \`title\`, \`pubDate\`, and \`link\` keys.`, + `Check your collection's schema, and visit https://docs.astro.build/en/guides/rss/#generating-items for more info.`, + ].join('\n'); + } + + return message; + }), ].join('\n') ); throw formattedError; diff --git a/packages/astro-rss/test/rss.test.js b/packages/astro-rss/test/rss.test.js index cc7bff82b2ed..e6f68a272f5f 100644 --- a/packages/astro-rss/test/rss.test.js +++ b/packages/astro-rss/test/rss.test.js @@ -1,18 +1,18 @@ -import rss, { getRssString } from '../dist/index.js'; -import { rssSchema } from '../dist/schema.js'; import chai from 'chai'; import chaiPromises from 'chai-as-promised'; import chaiXml from 'chai-xml'; +import rss, { getRssString } from '../dist/index.js'; +import { rssSchema } from '../dist/schema.js'; import { - title, description, - site, phpFeedItem, phpFeedItemWithContent, phpFeedItemWithCustomData, + site, + title, web1FeedItem, - web1FeedItemWithContent, web1FeedItemWithAllData, + web1FeedItemWithContent, } from './test-utils.js'; chai.use(chaiPromises); diff --git a/packages/astro/CHANGELOG.md b/packages/astro/CHANGELOG.md index 4b4c03b9844f..da96a03cb6be 100644 --- a/packages/astro/CHANGELOG.md +++ b/packages/astro/CHANGELOG.md @@ -1,5 +1,256 @@ # astro +## 4.0.3 + +### Patch Changes + +- [#9342](https://github.com/withastro/astro/pull/9342) [`eb942942d`](https://github.com/withastro/astro/commit/eb942942d67508c07d7efaa859a7840f7c0223da) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Fix missing `is:inline` type for the `` element + +- [#9343](https://github.com/withastro/astro/pull/9343) [`ab0281aee`](https://github.com/withastro/astro/commit/ab0281aee419e58c6079ca393987fe1ff0541dd5) Thanks [@martrapp](https://github.com/martrapp)! - Adds source file properties to HTML elements only if devToolbar is enabled + +- [#9336](https://github.com/withastro/astro/pull/9336) [`c76901065`](https://github.com/withastro/astro/commit/c76901065545f6a8d3de3e44d1c8ee5456a8a77a) Thanks [@FredKSchott](https://github.com/FredKSchott)! - dev: fix issue where 404 and 500 responses were logged as 200 + +- [#9339](https://github.com/withastro/astro/pull/9339) [`0bb3d5322`](https://github.com/withastro/astro/commit/0bb3d532219fb90fc08bfb472fc981fab6543d16) Thanks [@morinokami](https://github.com/morinokami)! - Fixed the log message to correctly display 'enabled' and 'disabled' when toggling 'Disable notifications' in the Toolbar. + +## 4.0.2 + +### Patch Changes + +- [#9331](https://github.com/withastro/astro/pull/9331) [`cfb20550d`](https://github.com/withastro/astro/commit/cfb20550d346a33e76e23453d5dcd084e5065c4d) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Updates an internal dependency ([`vitefu`](https://github.com/svitejs/vitefu)) to avoid a common `peerDependency` warning + +- [#9327](https://github.com/withastro/astro/pull/9327) [`3878a91be`](https://github.com/withastro/astro/commit/3878a91be4879988c7235f433e50a6dc82e32288) Thanks [@doseofted](https://github.com/doseofted)! - Fixes an edge case for `` when using View Transitions. Forms with `method="dialog"` no longer require an additional `data-astro-reload` attribute. + +## 4.0.1 + +### Patch Changes + +- [#9315](https://github.com/withastro/astro/pull/9315) [`631e5d01b`](https://github.com/withastro/astro/commit/631e5d01b00efee6970466c38201cb0e67ec74cf) Thanks [@ematipico](https://github.com/ematipico)! - Fixes an issue where logs that weren't grouped together by route when building the app. + +## 4.0.0 + +### Major Changes + +- [#9138](https://github.com/withastro/astro/pull/9138) [`abf601233`](https://github.com/withastro/astro/commit/abf601233f8188d118a8cb063c777478d8d9f1a3) Thanks [@bluwy](https://github.com/bluwy)! - Updates the unified, remark, and rehype dependencies to latest. Make sure to update your custom remark and rehype plugins as well to be compatible with the latest versions. + + **Potentially breaking change:** The default value of `markdown.remarkRehype.footnoteBackLabel` is changed from `"Back to content"` to `"Back to reference 1"`. See the `mdast-util-to-hast` [commit](https://github.com/syntax-tree/mdast-util-to-hast/commit/56c88e45690be138fad9f0bf367b939d09816863) for more information. + +- [#9181](https://github.com/withastro/astro/pull/9181) [`cdabf6ef0`](https://github.com/withastro/astro/commit/cdabf6ef02be7220fd2b6bdcef924ceca089381e) Thanks [@bluwy](https://github.com/bluwy)! - Removes support for returning simple objects from endpoints (deprecated since Astro 3.0). You should return a `Response` instead. + + `ResponseWithEncoding` is also removed. You can refactor the code to return a response with an array buffer instead, which is encoding agnostic. + + The types for middlewares have also been revised. To type a middleware function, you should now use `MiddlewareHandler` instead of `MiddlewareResponseHandler`. If you used `defineMiddleware()` to type the function, no changes are needed. + +- [#9263](https://github.com/withastro/astro/pull/9263) [`3cbd8ea75`](https://github.com/withastro/astro/commit/3cbd8ea7534910e3beae396dcfa93ce87dcdd91f) Thanks [@bluwy](https://github.com/bluwy)! - Removes additional deprecated APIs: + + - The Astro preview server now returns a 404 status instead of a 301 redirect when requesting assets from the public directory without a base. + - Removes special handling when referencing the `astro/client-image` type. You should use the `astro/client` type instead. + - Removes deprecated built-in `rss` support in `getStaticPaths`. You should use `@astrojs/rss` instead. + - Removes deprecated `Astro.request.params` support. You should use `Astro.params` instead. + +- [#9271](https://github.com/withastro/astro/pull/9271) [`47604bd5b`](https://github.com/withastro/astro/commit/47604bd5b5bb2ea63922b657bac104c010575c20) Thanks [@matthewp](https://github.com/matthewp)! - Renames Dev Overlay to Dev Toolbar + + The previously named experimental Dev Overlay is now known as the Astro Dev Toolbar. Overlay plugins have been renamed as Toolbar Apps. All APIs have been updated to reflect this name change. + + To not break existing APIs, aliases for the Toolbar-based names have been created. The previous API names will continue to function but will be deprecated in the future. All documentation has been updated to reflect Toolbar-based names. + +- [#9122](https://github.com/withastro/astro/pull/9122) [`1c48ed286`](https://github.com/withastro/astro/commit/1c48ed286538ab9e354eca4e4dcd7c6385c96721) Thanks [@bluwy](https://github.com/bluwy)! - Adds Vite 5 support. There are no breaking changes from Astro. Check the [Vite migration guide](https://vitejs.dev/guide/migration.html) for details of the breaking changes from Vite instead. + +- [#9225](https://github.com/withastro/astro/pull/9225) [`c421a3d17`](https://github.com/withastro/astro/commit/c421a3d17911aeda29b5204f6d568ae87e329eaf) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Removes the opt-in `handleForms` property for ``. Form submissions are now handled by default and this property is no longer necessary. This default behavior can be disabled by setting `data-astro-reload` on relevant `` elements. + +- [#9196](https://github.com/withastro/astro/pull/9196) [`37697a2c5`](https://github.com/withastro/astro/commit/37697a2c5511572dc29c0a4ea46f90c2f62be8e6) Thanks [@bluwy](https://github.com/bluwy)! - Removes support for Shiki custom language's `path` property. The language JSON file should be imported and passed to the option instead. + + ```diff + // astro.config.js + + import customLang from './custom.tmLanguage.json' + + export default defineConfig({ + markdown: { + shikiConfig: { + langs: [ + - { path: './custom.tmLanguage.json' }, + + customLang, + ], + }, + }, + }) + ``` + +- [#9199](https://github.com/withastro/astro/pull/9199) [`49aa215a0`](https://github.com/withastro/astro/commit/49aa215a01ee1c4805316c85bb0aea6cfbc25a31) Thanks [@lilnasy](https://github.com/lilnasy)! - This change only affects maintainers of third-party adapters. In the Integration API, the `app.render()` method of the `App` class has been simplified. + + Instead of two optional arguments, it now takes a single optional argument that is an object with two optional properties: `routeData` and `locals`. + + ```diff + app.render(request) + + - app.render(request, routeData) + + app.render(request, { routeData }) + + - app.render(request, routeData, locals) + + app.render(request, { routeData, locals }) + + - app.render(request, undefined, locals) + + app.render(request, { locals }) + ``` + + The current signature is deprecated but will continue to function until next major version. + +- [#9212](https://github.com/withastro/astro/pull/9212) [`c0383ea0c`](https://github.com/withastro/astro/commit/c0383ea0c102cb62b7235823c706a090ba08715f) Thanks [@alexanderniebuhr](https://github.com/alexanderniebuhr)! - Removes deprecated `app.match()` option, `matchNotFound` + +- [#9168](https://github.com/withastro/astro/pull/9168) [`153a5abb9`](https://github.com/withastro/astro/commit/153a5abb905042ac68b712514dc9ec387d3e6b17) Thanks [@bluwy](https://github.com/bluwy)! - Removes deprecated features from Astro 3.0 + + - Adapters are now required to pass `supportedAstroFeatures` to specify a list of features they support. + - The `build.split` and `build.excludeMiddleware` options are removed. Use `functionPerRoute` and `edgeMiddleware` from adapters instead. + - The `markdown.drafts` option and draft feature is removed. Use content collections instead. + - Lowercase endpoint names are no longer supported. Use uppercase endpoint names instead. + - `getHeaders()` exported from markdown files is removed. Use `getHeadings()` instead. + +### Minor Changes + +- [#9105](https://github.com/withastro/astro/pull/9105) [`6201bbe96`](https://github.com/withastro/astro/commit/6201bbe96c2a083fb201e4a43a9bd88499821a3e) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Update CLI logging experience + +- [#9200](https://github.com/withastro/astro/pull/9200) [`b4b851f5a`](https://github.com/withastro/astro/commit/b4b851f5a46b32ee531db5dc39ccd2aa7af7bcfd) Thanks [@ematipico](https://github.com/ematipico)! - Adds a new way to configure the `i18n.locales` array. + + Developers can now assign a custom URL path prefix that can span multiple language codes: + + ```js + // astro.config.mjs + export default defineConfig({ + experimental: { + i18n: { + defaultLocale: 'english', + locales: ['de', { path: 'english', codes: ['en', 'en-US'] }, 'fr'], + }, + }, + }); + ``` + + With the above configuration, the URL prefix of the default locale will be `/english/`. When computing `Astro.preferredLocale`, Astro will use the `codes`. + +- [#9115](https://github.com/withastro/astro/pull/9115) [`3b77889b4`](https://github.com/withastro/astro/commit/3b77889b47750ed6e17c7858780dc4aae9201b58) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Adds the `astro preferences` command to manage user preferences. User preferences are specific to individual Astro users, unlike the `astro.config.mjs` file which changes behavior for everyone working on a project. + + User preferences are scoped to the current project by default, stored in a local `.astro/settings.json` file. Using the `--global` flag, user preferences can also be applied to every Astro project on the current machine. Global user preferences are stored in an operating system-specific location. + + ```sh + # Disable the dev overlay for the current user in the current project + npm run astro preferences disable devOverlay + # Disable the dev overlay for the current user in all Astro projects on this machine + npm run astro preferences --global disable devOverlay + + # Check if the dev overlay is enabled for the current user + npm run astro preferences list devOverlay + ``` + +- [#9139](https://github.com/withastro/astro/pull/9139) [`459b26436`](https://github.com/withastro/astro/commit/459b2643666db08dbd29a100ce3d8697b451d3fe) Thanks [@bluwy](https://github.com/bluwy)! - Reworks Vite's logger to use Astro's logger to correctly log HMR messages + +- [#9279](https://github.com/withastro/astro/pull/9279) [`6a9669b81`](https://github.com/withastro/astro/commit/6a9669b810ddfcae6c537165a438190ea1e7a4bc) Thanks [@martrapp](https://github.com/martrapp)! - Improves consistency between navigations with and without ``. See [#9279](https://github.com/withastro/astro/pull/9279) for more details. + +- [#9161](https://github.com/withastro/astro/pull/9161) [`bd0c2e9ae`](https://github.com/withastro/astro/commit/bd0c2e9ae3389a9d3085050c1e8134ae98dff299) Thanks [@bluwy](https://github.com/bluwy)! - Renames the `entryPoint` property of the `injectRoute` integrations API to `entrypoint` for consistency. A warning will be shown prompting you to update your code when using the old name. + +- [#9129](https://github.com/withastro/astro/pull/9129) [`8bfc20511`](https://github.com/withastro/astro/commit/8bfc20511918d675202cdc100d4efab293e5cbac) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Update error log formatting + +### Patch Changes + +- [#9118](https://github.com/withastro/astro/pull/9118) [`000e8f465`](https://github.com/withastro/astro/commit/000e8f4654cae9982e21e0a858366c4844139db6) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Redesign Dev Overlay main screen to show more information, such as the coolest integrations, your current Astro version and more. + +- [#9118](https://github.com/withastro/astro/pull/9118) [`000e8f465`](https://github.com/withastro/astro/commit/000e8f4654cae9982e21e0a858366c4844139db6) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Fixes an issue where links with the same pathname as the current page, but different search params, were not prefetched. + +- [#9275](https://github.com/withastro/astro/pull/9275) [`0968cb1a3`](https://github.com/withastro/astro/commit/0968cb1a373b1101a649035d2ea2210d3d6412dc) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixes an issue where html annotations relevant only to the dev server were included in the production build. + +- [#9252](https://github.com/withastro/astro/pull/9252) [`7b74ec4ba`](https://github.com/withastro/astro/commit/7b74ec4ba48e363a19d20e322212d0d264927f1b) Thanks [@ematipico](https://github.com/ematipico)! - Consistently emit fallback routes in the correct folders, and emit routes that consider `trailingSlash` + +- [#9222](https://github.com/withastro/astro/pull/9222) [`279e3c1b3`](https://github.com/withastro/astro/commit/279e3c1b3d06e7b48f01c0ef8285c3719ac74ace) Thanks [@matthewp](https://github.com/matthewp)! - Ensure the dev-overlay-window is anchored to the bottom + +- [#9292](https://github.com/withastro/astro/pull/9292) [`5428b3da0`](https://github.com/withastro/astro/commit/5428b3da08493d933981c4646d5d132fb31f0d25) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Improves display for `astro preferences list` command + +- [#9235](https://github.com/withastro/astro/pull/9235) [`9c2342c32`](https://github.com/withastro/astro/commit/9c2342c327a13d2f7d1eb387b743e81f431b9813) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Fix SVG icons not showing properly in the extended dropdown menu of the dev overlay + +- [#9218](https://github.com/withastro/astro/pull/9218) [`f4401c8c1`](https://github.com/withastro/astro/commit/f4401c8c1fa203431b4e7b2e89381a91b4ef1ac6) Thanks [@matthewp](https://github.com/matthewp)! - Improve high contrast mode with the Dev Overlay + +- [#9254](https://github.com/withastro/astro/pull/9254) [`b750a161e`](https://github.com/withastro/astro/commit/b750a161e0e059de9cf814ce271d5891e4e97cbe) Thanks [@matthewp](https://github.com/matthewp)! - Improve highlight/tooltip positioning when in fixed positions + +- [#9230](https://github.com/withastro/astro/pull/9230) [`60cfa49e4`](https://github.com/withastro/astro/commit/60cfa49e445c926288612a6b1a30113ab988011c) Thanks [@FredKSchott](https://github.com/FredKSchott)! - Update the look and feel of the dev overlay + +- [#9248](https://github.com/withastro/astro/pull/9248) [`43ddb5217`](https://github.com/withastro/astro/commit/43ddb5217691dc4112d8d98ae07511a8be6d4b94) Thanks [@martrapp](https://github.com/martrapp)! - Adds properties of the submit button (name, value) to the form data of a view transition + +- [#9170](https://github.com/withastro/astro/pull/9170) [`8a228fce0`](https://github.com/withastro/astro/commit/8a228fce0114daeea2100e50ddc5cf2ea0a03b5d) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Adds new accessibility audits to the Dev Toolbar's built-in Audits app. + + The audits Astro performs are non-exhaustive and only capable of detecting a handful of common accessibility issues. Please take care to perform a thorough, **manual** audit of your site to ensure compliance with the [Web Content Accessibility Guidelines (WCAG) international standard](https://www.w3.org/WAI/standards-guidelines/wcag/) _before_ publishing your site. + + 🧡 Huge thanks to the [Svelte](https://github.com/sveltejs/svelte) team for providing the basis of these accessibility audits! + +- [#9149](https://github.com/withastro/astro/pull/9149) [`0fe3a7ed5`](https://github.com/withastro/astro/commit/0fe3a7ed5d7bb1a9fce1623e84ba14104b51223c) Thanks [@bluwy](https://github.com/bluwy)! - Removes vendored Vite's `importMeta.d.ts` file in favour of Vite 5's new `vite/types/import-meta.d.ts` export + +- [#9295](https://github.com/withastro/astro/pull/9295) [`3d2dbb0e5`](https://github.com/withastro/astro/commit/3d2dbb0e5d2bf67b38ff8533d4dd938c94433812) Thanks [@matthewp](https://github.com/matthewp)! - Remove aria-query package + + This is another CJS-only package that breaks usage. + +- [#9274](https://github.com/withastro/astro/pull/9274) [`feaba2c7f`](https://github.com/withastro/astro/commit/feaba2c7fc0a48d3af7dd98e6b750ec1e8274e33) Thanks [@TheOtterlord](https://github.com/TheOtterlord)! - Fix routing prefixes when `prefixDefaultLocale` is `true` + +- [#9273](https://github.com/withastro/astro/pull/9273) [`9887f2412`](https://github.com/withastro/astro/commit/9887f241241f800e2907afe7079db070f3bfcfab) Thanks [@alexanderniebuhr](https://github.com/alexanderniebuhr)! - Exports type for Dev Toolbar App under correct name + +- [#9150](https://github.com/withastro/astro/pull/9150) [`710be505c`](https://github.com/withastro/astro/commit/710be505c9ddf416e77a75343d8cae9c497d72c6) Thanks [@bluwy](https://github.com/bluwy)! - Refactors virtual modules exports. This should not break your project unless you import Astro's internal modules, including: + + - `astro/middleware/namespace` + - `astro/transitions` + - `astro/transitions/router` + - `astro/transitions/events` + - `astro/transitions/types` + - `astro/prefetch` + - `astro/i18n` + +- [#9227](https://github.com/withastro/astro/pull/9227) [`4b8a42406`](https://github.com/withastro/astro/commit/4b8a42406bbdcc68604ea4ecc2a926721fbc4d52) Thanks [@matthewp](https://github.com/matthewp)! - Ensure overlay x-ray z-index is higher than the island + +- [#9255](https://github.com/withastro/astro/pull/9255) [`9ea3e0b94`](https://github.com/withastro/astro/commit/9ea3e0b94f7c4813c52bffd78043f90fd87dffda) Thanks [@matthewp](https://github.com/matthewp)! - Adds instructions on how to hide the dev overlay + +- [#9293](https://github.com/withastro/astro/pull/9293) [`cf5fa4376`](https://github.com/withastro/astro/commit/cf5fa437627ca6978ae3ff33c7894f278dfe75cd) Thanks [@matthewp](https://github.com/matthewp)! - Removes the 'a11y-role-has-required-aria-props' audit rule + + This audit rule depends on a CommonJS module. To prevent blocking the 4.0 release the rule is being removed temporarily. + +- [#9214](https://github.com/withastro/astro/pull/9214) [`4fe523b00`](https://github.com/withastro/astro/commit/4fe523b0064b323ee46b2574339d96ea8bdb7b2d) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Fixes a number of small user experience bugs with the dev overlay + +- [#9013](https://github.com/withastro/astro/pull/9013) [`ff8eadb95`](https://github.com/withastro/astro/commit/ff8eadb95d34833baaf3ec7575bf4f293eae97da) Thanks [@bayssmekanique](https://github.com/bayssmekanique)! - Returns the updated config in the integration `astro:config:setup` hook's `updateConfig()` API + +- Updated dependencies [[`abf601233`](https://github.com/withastro/astro/commit/abf601233f8188d118a8cb063c777478d8d9f1a3), [`addb57c8e`](https://github.com/withastro/astro/commit/addb57c8e80b7b67ec61224666f3a1db5c44410c), [`c7953645e`](https://github.com/withastro/astro/commit/c7953645eeaaf9e87c6db4494b0023d2c1878ff0)]: + - @astrojs/markdown-remark@4.0.0 + +## 4.0.0-beta.7 + +### Patch Changes + +- [#9295](https://github.com/withastro/astro/pull/9295) [`3d2dbb0e5`](https://github.com/withastro/astro/commit/3d2dbb0e5d2bf67b38ff8533d4dd938c94433812) Thanks [@matthewp](https://github.com/matthewp)! - Remove aria-query package + + This is another CJS-only package that breaks usage. + +## 4.0.0-beta.6 + +### Patch Changes + +- [#9275](https://github.com/withastro/astro/pull/9275) [`0968cb1a3`](https://github.com/withastro/astro/commit/0968cb1a373b1101a649035d2ea2210d3d6412dc) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixes an issue where html annotations relevant only to the dev server were included in the production build. + +- [#9292](https://github.com/withastro/astro/pull/9292) [`5428b3da0`](https://github.com/withastro/astro/commit/5428b3da08493d933981c4646d5d132fb31f0d25) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Improves display for `astro preferences list` command + +- [#9293](https://github.com/withastro/astro/pull/9293) [`cf5fa4376`](https://github.com/withastro/astro/commit/cf5fa437627ca6978ae3ff33c7894f278dfe75cd) Thanks [@matthewp](https://github.com/matthewp)! - Removes the 'a11y-role-has-required-aria-props' audit rule + + This audit rule depends on a CommonJS module. To prevent blocking the 4.0 release the rule is being removed temporarily. + +## 4.0.0-beta.5 + +### Minor Changes + +- [#9279](https://github.com/withastro/astro/pull/9279) [`6a9669b81`](https://github.com/withastro/astro/commit/6a9669b810ddfcae6c537165a438190ea1e7a4bc) Thanks [@martrapp](https://github.com/martrapp)! - Improves consistency between navigations with and without ``. See [#9279](https://github.com/withastro/astro/pull/9279) for more details. + +### Patch Changes + +- [#9170](https://github.com/withastro/astro/pull/9170) [`8a228fce0`](https://github.com/withastro/astro/commit/8a228fce0114daeea2100e50ddc5cf2ea0a03b5d) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Adds new accessibility audits to the Dev Toolbar's built-in Audits app. + + The audits Astro performs are non-exhaustive and only capable of detecting a handful of common accessibility issues. Please take care to perform a thorough, **manual** audit of your site to ensure compliance with the [Web Content Accessibility Guidelines (WCAG) international standard](https://www.w3.org/WAI/standards-guidelines/wcag/) _before_ publishing your site. + + 🧡 Huge thanks to the [Svelte](https://github.com/sveltejs/svelte) team for providing the basis of these accessibility audits! + +- [#9274](https://github.com/withastro/astro/pull/9274) [`feaba2c7f`](https://github.com/withastro/astro/commit/feaba2c7fc0a48d3af7dd98e6b750ec1e8274e33) Thanks [@TheOtterlord](https://github.com/TheOtterlord)! - Fix routing prefixes when `prefixDefaultLocale` is `true` + +- [#9273](https://github.com/withastro/astro/pull/9273) [`9887f2412`](https://github.com/withastro/astro/commit/9887f241241f800e2907afe7079db070f3bfcfab) Thanks [@alexanderniebuhr](https://github.com/alexanderniebuhr)! - Exports type for Dev Toolbar App under correct name + ## 4.0.0-beta.4 ### Major Changes diff --git a/packages/astro/astro-jsx.d.ts b/packages/astro/astro-jsx.d.ts index 3e8a86889282..3f73bcc613ee 100644 --- a/packages/astro/astro-jsx.d.ts +++ b/packages/astro/astro-jsx.d.ts @@ -36,6 +36,7 @@ declare namespace astroHTML.JSX { AstroDefineVarsAttribute; type AstroStyleAttributes = import('./dist/@types/astro.js').AstroStyleAttributes & AstroDefineVarsAttribute; + type AstroSlotAttributes = import('./dist/@types/astro.js').AstroSlotAttributes; // This is an unfortunate use of `any`, but unfortunately we can't make a type that works for every framework // without importing every single framework's types (which comes with its own set of problems). @@ -1415,7 +1416,7 @@ declare namespace astroHTML.JSX { ruby: HTMLAttributes; s: HTMLAttributes; samp: HTMLAttributes; - slot: SlotHTMLAttributes; + slot: SlotHTMLAttributes & AstroSlotAttributes; script: ScriptHTMLAttributes & AstroScriptAttributes; section: HTMLAttributes; select: SelectHTMLAttributes; diff --git a/packages/astro/components/ViewTransitions.astro b/packages/astro/components/ViewTransitions.astro index 6ce08cec9556..310f1865a92c 100644 --- a/packages/astro/components/ViewTransitions.astro +++ b/packages/astro/components/ViewTransitions.astro @@ -104,6 +104,12 @@ const { fallback = 'animate' } = Astro.props; let action = submitter?.getAttribute('formaction') ?? form.action ?? location.pathname; const method = submitter?.getAttribute('formmethod') ?? form.method; + // the "dialog" method is a special keyword used within elements + // https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#attr-fs-method + if (method === 'dialog') { + return; + } + const options: Options = { sourceElement: submitter ?? form }; if (method === 'get') { const params = new URLSearchParams(formData as any); @@ -113,6 +119,7 @@ const { fallback = 'animate' } = Astro.props; } else { options.formData = formData; } + ev.preventDefault(); navigate(action, options); }); diff --git a/packages/astro/e2e/astro-envs.test.js b/packages/astro/e2e/astro-envs.test.js index 6cffc2d828de..cf8a1d304259 100644 --- a/packages/astro/e2e/astro-envs.test.js +++ b/packages/astro/e2e/astro-envs.test.js @@ -3,7 +3,7 @@ import { testFactory } from './test-utils.js'; const test = testFactory({ root: './fixtures/astro-envs/', - devOverlay: { + devToolbar: { enabled: false, }, }); diff --git a/packages/astro/e2e/css.test.js b/packages/astro/e2e/css.test.js index df50ee35d064..fff197a39246 100644 --- a/packages/astro/e2e/css.test.js +++ b/packages/astro/e2e/css.test.js @@ -3,7 +3,7 @@ import { testFactory } from './test-utils.js'; const test = testFactory({ root: './fixtures/css/', - devOverlay: { + devToolbar: { enabled: false, }, }); diff --git a/packages/astro/e2e/dev-overlay.test.js b/packages/astro/e2e/dev-overlay.test.js index a5e3560e905a..b61a3e10e756 100644 --- a/packages/astro/e2e/dev-overlay.test.js +++ b/packages/astro/e2e/dev-overlay.test.js @@ -19,8 +19,8 @@ test.describe('Dev Overlay', () => { test('dev overlay exists in the page', async ({ page, astro }) => { await page.goto(astro.resolveUrl('/')); - const devOVerlay = page.locator('astro-dev-toolbar'); - await expect(devOVerlay).toHaveCount(1); + const devToolbar = page.locator('astro-dev-toolbar'); + await expect(devToolbar).toHaveCount(1); }); test('shows plugin name on hover', async ({ page, astro }) => { @@ -200,7 +200,7 @@ test.describe('Dev Overlay', () => { await expect(settingsWindow).toHaveCount(1); await expect(settingsWindow).toBeVisible(); - const hideOverlay = settingsWindow.getByRole('heading', { name: 'Hide overlay' }); + const hideOverlay = settingsWindow.getByRole('heading', { name: 'Hide toolbar' }); await expect(hideOverlay).toBeVisible(); }); }); diff --git a/packages/astro/e2e/fixtures/astro-component/astro.config.mjs b/packages/astro/e2e/fixtures/astro-component/astro.config.mjs index 6ffc82a088f9..58b3ebc4bf9c 100644 --- a/packages/astro/e2e/fixtures/astro-component/astro.config.mjs +++ b/packages/astro/e2e/fixtures/astro-component/astro.config.mjs @@ -4,7 +4,7 @@ import preact from '@astrojs/preact' // https://astro.build/config export default defineConfig({ integrations: [preact()], - devOverlay: { + devToolbar: { enabled: false, } }); diff --git a/packages/astro/e2e/fixtures/astro-envs/astro.config.mjs b/packages/astro/e2e/fixtures/astro-envs/astro.config.mjs index 28bce59c7a47..48d49eccd204 100644 --- a/packages/astro/e2e/fixtures/astro-envs/astro.config.mjs +++ b/packages/astro/e2e/fixtures/astro-envs/astro.config.mjs @@ -5,7 +5,7 @@ import vue from '@astrojs/vue'; export default defineConfig({ site: 'http://example.com', base: '/blog', - devOverlay: { + devToolbar: { enabled: false, }, integrations: [vue()], diff --git a/packages/astro/e2e/fixtures/lit-component/astro.config.mjs b/packages/astro/e2e/fixtures/lit-component/astro.config.mjs index 19da6f609088..8df6f42a1165 100644 --- a/packages/astro/e2e/fixtures/lit-component/astro.config.mjs +++ b/packages/astro/e2e/fixtures/lit-component/astro.config.mjs @@ -4,7 +4,7 @@ import lit from '@astrojs/lit'; // https://astro.build/config export default defineConfig({ integrations: [lit()], - devOverlay: { + devToolbar: { enabled: false, } }); diff --git a/packages/astro/e2e/fixtures/prefetch/astro.config.mjs b/packages/astro/e2e/fixtures/prefetch/astro.config.mjs index 745817a28dc5..a29c83f4250c 100644 --- a/packages/astro/e2e/fixtures/prefetch/astro.config.mjs +++ b/packages/astro/e2e/fixtures/prefetch/astro.config.mjs @@ -2,7 +2,7 @@ import { defineConfig } from 'astro/config'; // https://astro.build/config export default defineConfig({ - devOverlay: { + devToolbar: { enabled: false, }, prefetch: true diff --git a/packages/astro/e2e/fixtures/tailwindcss/astro.config.mjs b/packages/astro/e2e/fixtures/tailwindcss/astro.config.mjs index 4c808ac5db5d..aa1ca234a34b 100644 --- a/packages/astro/e2e/fixtures/tailwindcss/astro.config.mjs +++ b/packages/astro/e2e/fixtures/tailwindcss/astro.config.mjs @@ -9,7 +9,7 @@ export default defineConfig({ configFile: fileURLToPath(new URL('./tailwind.config.js', import.meta.url)), }), ], - devOverlay: { + devToolbar: { enabled: false, }, vite: { diff --git a/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs b/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs index 9ca3631ee0f2..4b682d215785 100644 --- a/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs +++ b/packages/astro/e2e/fixtures/view-transitions/astro.config.mjs @@ -13,7 +13,7 @@ export default defineConfig({ '/redirect-two': '/two', '/redirect-external': 'http://example.com/', }, - devOverlay: { + devToolbar: { enabled: false, }, vite: { diff --git a/packages/astro/e2e/fixtures/view-transitions/src/pages/dialog.astro b/packages/astro/e2e/fixtures/view-transitions/src/pages/dialog.astro new file mode 100644 index 000000000000..07d4b0f00b39 --- /dev/null +++ b/packages/astro/e2e/fixtures/view-transitions/src/pages/dialog.astro @@ -0,0 +1,16 @@ +--- +import { ViewTransitions } from "astro:transitions"; +--- + + + + + + + + + + + + + diff --git a/packages/astro/e2e/fixtures/view-transitions/src/pages/long-page.astro b/packages/astro/e2e/fixtures/view-transitions/src/pages/long-page.astro index ebe918c680af..aa7c8b5e59c7 100644 --- a/packages/astro/e2e/fixtures/view-transitions/src/pages/long-page.astro +++ b/packages/astro/e2e/fixtures/view-transitions/src/pages/long-page.astro @@ -51,3 +51,9 @@ import Layout from '../components/Layout.astro'; Libero id faucibus nisl tincidunt eget nullam non. Faucibus a pellentesque sit amet porttitor eget dolor. Posuere urna nec tincidunt praesent semper feugiat nibh sed. Suspendisse ultrices gravida dictum fusce. Porttitor eget dolor morbi non arcu. Neque egestas congue quisque egestas diam in. Suscipit tellus mauris a diam maecenas sed enim ut sem. Luctus accumsan tortor posuere ac. Tortor posuere ac ut consequat semper viverra. Egestas tellus rutrum tellus pellentesque eu tincidunt tortor aliquam nulla. Senectus et netus et malesuada fames ac turpis egestas. Sed libero enim sed faucibus turpis in eu mi bibendum. Sollicitudin tempor id eu nisl nunc mi. + diff --git a/packages/astro/e2e/hmr.test.js b/packages/astro/e2e/hmr.test.js index 94aa68140c40..5e7e232af96f 100644 --- a/packages/astro/e2e/hmr.test.js +++ b/packages/astro/e2e/hmr.test.js @@ -3,7 +3,7 @@ import { testFactory } from './test-utils.js'; const test = testFactory({ root: './fixtures/hmr/', - devOverlay: { + devToolbar: { enabled: false, }, }); diff --git a/packages/astro/e2e/view-transitions.test.js b/packages/astro/e2e/view-transitions.test.js index fafea3e697fa..222c9dfdf2aa 100644 --- a/packages/astro/e2e/view-transitions.test.js +++ b/packages/astro/e2e/view-transitions.test.js @@ -394,7 +394,10 @@ test.describe('View Transitions', () => { await expect(locator).toBeInViewport(); // Scroll back to top + // back returns immediately, but we need to wait for navigate() to complete + const waitForReady = page.waitForEvent('console'); await page.goBack(); + await waitForReady; locator = page.locator('#longpage'); await expect(locator).toBeInViewport(); @@ -1071,4 +1074,21 @@ test.describe('View Transitions', () => { await page.click('#three'); await expect(page).toHaveURL(expected); }); + + test('Dialog using form with method of "dialog" should not trigger navigation', async ({ + page, + astro, + }) => { + await page.goto(astro.resolveUrl('/dialog')); + + let requests = []; + page.on('request', (request) => requests.push(`${request.method()} ${request.url()}`)); + + await page.click('#open'); + await expect(page.locator('dialog')).toHaveAttribute('open'); + await page.click('#close'); + await expect(page.locator('dialog')).not.toHaveAttribute('open'); + + expect(requests).toHaveLength(0); + }); }); diff --git a/packages/astro/package.json b/packages/astro/package.json index 23b2d68b08dd..c7dd43ae3d1f 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -1,6 +1,6 @@ { "name": "astro", - "version": "4.0.0-beta.4", + "version": "4.0.3", "description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.", "type": "module", "author": "withastro", @@ -169,7 +169,7 @@ "unist-util-visit": "^5.0.0", "vfile": "^6.0.1", "vite": "^5.0.0", - "vitefu": "^0.2.4", + "vitefu": "^0.2.5", "which-pm": "^2.1.1", "yargs-parser": "^21.1.1", "zod": "^3.22.4" diff --git a/packages/astro/src/@types/astro.ts b/packages/astro/src/@types/astro.ts index a689c0479e5e..fa8c33920ac0 100644 --- a/packages/astro/src/@types/astro.ts +++ b/packages/astro/src/@types/astro.ts @@ -132,6 +132,10 @@ export interface AstroScriptAttributes { 'is:inline'?: boolean; } +export interface AstroSlotAttributes { + 'is:inline'?: boolean; +} + export interface AstroComponentMetadata { displayName: string; hydrate?: 'load' | 'idle' | 'visible' | 'media' | 'only'; @@ -1155,35 +1159,6 @@ export interface AstroUserConfig { remotePatterns?: Partial[]; }; - /** - * @docs - * @kind heading - * @name Dev Overlay Options - * @deprecated Use `devToolbar` instead. - */ - devOverlay?: { - /** - * @docs - * @name devOverlay.enabled - * @type {boolean} - * @default `true` - * @description - * Whether to enable the dev overlay. This overlay allows you to inspect your page islands, see helpful audits on performance and accessibility, and more. - * - * This option is scoped to the entire project, to only disable the overlay for yourself, run `npm run astro preferences disable devOverlay`. To disable the overlay for all your Astro projects, run `npm run astro preferences disable devOverlay --global`. - */ - enabled: boolean; - /** - * @docs - * @name devOverlay.defaultState - * @type {'minimized' | 'expanded'} - * @default `minimized` - * @description - * Whether the dev overlay should be expanded or minimized by default. - */ - defaultState: 'minimized' | 'expanded'; - }; - /** * @docs * @kind heading @@ -1201,15 +1176,6 @@ export interface AstroUserConfig { * This option is scoped to the entire project, to only disable the toolbar for yourself, run `npm run astro preferences disable devToolbar`. To disable the toolbar for all your Astro projects, run `npm run astro preferences disable devToolbar --global`. */ enabled: boolean; - /** - * @docs - * @name devToolbar.defaultState - * @type {'minimized' | 'expanded'} - * @default `minimized` - * @description - * Whether the Dev Toolbar should be expanded or minimized by default. - */ - defaultState: 'minimized' | 'expanded'; }; /** @@ -1395,6 +1361,119 @@ export interface AstroUserConfig { */ vite?: ViteUserConfig; + /** + * @docs + * @kind heading + * @name i18n + * @type {object} + * @version 3.5.0 + * @type {object} + * @description + * + * Configures i18n routing and allows you to specify some customization options. + * + * See our guide for more information on [internationalization in Astro](/en/guides/internationalization/) + */ + i18n?: { + /** + * @docs + * @name i18n.defaultLocale + * @type {string} + * @version 3.5.0 + * @description + * + * The default locale of your website/application. This is a required field. + * + * No particular language format or syntax is enforced, but we suggest using lower-case and hyphens as needed (e.g. "es", "pt-br") for greatest compatibility. + */ + defaultLocale: string; + /** + * @docs + * @name i18n.locales + * @type {Locales} + * @version 3.5.0 + * @description + * + * A list of all locales supported by the website, including the `defaultLocale`. This is a required field. + * + * Languages can be listed either as individual codes (e.g. `['en', 'es', 'pt-br']`) or mapped to a shared `path` of codes (e.g. `{ path: "english", codes: ["en", "en-US"]}`). These codes will be used to determine the URL structure of your deployed site. + * + * No particular language code format or syntax is enforced, but your project folders containing your content files must match exactly the `locales` items in the list. In the case of multiple `codes` pointing to a custom URL path prefix, store your content files in a folder with the same name as the `path` configured. + */ + locales: Locales; + + /** + * @docs + * @name i18n.fallback + * @type {Record} + * @version 3.5.0 + * @description + * + * The fallback strategy when navigating to pages that do not exist (e.g. a translated page has not been created). + * + * Use this object to declare a fallback `locale` route for each language you support. If no fallback is specified, then unavailable pages will return a 404. + * + * ##### Example + * + * The following example configures your content fallback strategy to redirect unavailable pages in `/pt-br/` to their `es` version, and unavailable pages in `/fr/` to their `en` version. Unavailable `/es/` pages will return a 404. + * + * ```js + * export default defineConfig({ + * i18n: { + * defaultLocale: "en", + * locales: ["en", "fr", "pt-br", "es"], + * fallback: { + * pt: "es", + * fr: "en" + * } + * } + * }) + * ``` + */ + fallback?: Record; + + /** + * @docs + * @name i18n.routing + * @type {Routing} + * @version 3.7.0 + * @description + * + * Controls the routing strategy to determine your site URLs. Set this based on your folder/URL path configuration for your default language. + */ + routing?: { + /** + * @docs + * @name i18n.routing.prefixDefaultLocale + * @kind h4 + * @type {boolean} + * @default `false` + * @version 3.7.0 + * @description + * + * When `false`, only non-default languages will display a language prefix. + * The `defaultLocale` will not show a language prefix and content files do not exist in a localized folder. + * URLs will be of the form `example.com/[locale]/content/` for all non-default languages, but `example.com/content/` for the default locale. + * + * When `true`, all URLs will display a language prefix. + * URLs will be of the form `example.com/[locale]/content/` for every route, including the default language. + * Localized folders are used for every language, including the default. + */ + prefixDefaultLocale: boolean; + + /** + * @name i18n.routing.strategy + * @type {"pathname"} + * @default `"pathname"` + * @version 3.7.0 + * @description + * + * - `"pathanme": The strategy is applied to the pathname of the URLs + */ + strategy: 'pathname'; + }; + }; + /** * @docs * @kind heading @@ -1437,122 +1516,6 @@ export interface AstroUserConfig { */ optimizeHoistedScript?: boolean; - /** - * @docs - * @name experimental.i18n - * @type {object} - * @version 3.5.0 - * @type {object} - * @description - * - * Configures experimental i18n routing and allows you to specify some customization options. - * - * See our guide for more information on [internationalization in Astro](/en/guides/internationalization/) - */ - i18n?: { - /** - * @docs - * @kind h4 - * @name experimental.i18n.defaultLocale - * @type {string} - * @version 3.5.0 - * @description - * - * The default locale of your website/application. This is a required field. - * - * No particular language format or syntax is enforced, but we suggest using lower-case and hyphens as needed (e.g. "es", "pt-br") for greatest compatibility. - */ - defaultLocale: string; - /** - * @docs - * @kind h4 - * @name experimental.i18n.locales - * @type {Locales} - * @version 3.5.0 - * @description - * - * A list of all locales supported by the website, including the `defaultLocale`. This is a required field. - * - * Languages can be listed either as individual codes (e.g. `['en', 'es', 'pt-br']`) or mapped to a shared `path` of codes (e.g. `{ path: "english", codes: ["en", "en-US"]}`). These codes will be used to determine the URL structure of your deployed site. - * - * No particular language code format or syntax is enforced, but your project folders containing your content files must match exactly the `locales` items in the list. In the case of multiple `codes` pointing to a custom URL path prefix, store your content files in a folder with the same name as the `path` configured. - */ - locales: Locales; - - /** - * @docs - * @kind h4 - * @name experimental.i18n.fallback - * @type {Record} - * @version 3.5.0 - * @description - * - * The fallback strategy when navigating to pages that do not exist (e.g. a translated page has not been created). - * - * Use this object to declare a fallback `locale` route for each language you support. If no fallback is specified, then unavailable pages will return a 404. - * - * ##### Example - * - * The following example configures your content fallback strategy to redirect unavailable pages in `/pt-br/` to their `es` version, and unavailable pages in `/fr/` to their `en` version. Unavailable `/es/` pages will return a 404. - * - * ```js - * export default defineConfig({ - * experimental: { - * i18n: { - * defaultLocale: "en", - * locales: ["en", "fr", "pt-br", "es"], - * fallback: { - * pt: "es", - * fr: "en" - * } - * } - * } - * }) - * ``` - */ - fallback?: Record; - - /** - * @docs - * @kind h4 - * @name experimental.i18n.routing - * @type {Routing} - * @version 3.7.0 - * @description - * - * Controls the routing strategy to determine your site URLs. Set this based on your folder/URL path configuration for your default language. - */ - routing?: { - /** - * @docs - * @name experimental.i18n.routing.prefixDefaultLocale - * @type {boolean} - * @default `false` - * @version 3.7.0 - * @description - * - * When `false`, only non-default languages will display a language prefix. - * The `defaultLocale` will not show a language prefix and content files do not exist in a localized folder. - * URLs will be of the form `example.com/[locale]/content/` for all non-default languages, but `example.com/content/` for the default locale. - * - * When `true`, all URLs will display a language prefix. - * URLs will be of the form `example.com/[locale]/content/` for every route, including the default language. - * Localized folders are used for every language, including the default. - */ - prefixDefaultLocale: boolean; - - /** - * @name experimental.i18n.routing.strategy - * @type {"pathname"} - * @default `"pathname"` - * @version 3.7.0 - * @description - * - * - `"pathanme": The strategy is applied to the pathname of the URLs - */ - strategy: 'pathname'; - }; - }; /** * @docs * @name experimental.contentCollectionCache @@ -2228,7 +2191,7 @@ export interface APIContext< locals: App.Locals; /** - * Available only when `experimental.i18n` enabled and in SSR. + * Available only when `i18n` configured and in SSR. * * It represents the preferred locale of the user. It's computed by checking the supported locales in `i18n.locales` * and locales supported by the users's browser via the header `Accept-Language` @@ -2241,7 +2204,7 @@ export interface APIContext< preferredLocale: string | undefined; /** - * Available only when `experimental.i18n` enabled and in SSR. + * Available only when `i18n` configured and in SSR. * * It represents the list of the preferred locales that are supported by the application. The list is sorted via [quality value]. * @@ -2576,7 +2539,7 @@ export interface ClientDirectiveConfig { entrypoint: string; } -export interface DevOverlayPlugin { +export interface DevToolbarApp { id: string; name: string; icon: Icon; @@ -2584,10 +2547,11 @@ export interface DevOverlayPlugin { beforeTogglingOff?(canvas: ShadowRoot): boolean | Promise; } +export type DevOverlayPlugin = DevToolbarApp; + export type DevOverlayMetadata = Window & typeof globalThis & { __astro_dev_overlay__: { - defaultState: AstroConfig['devOverlay']['defaultState']; root: string; version: string; debugInfo: string; diff --git a/packages/astro/src/assets/build/generate.ts b/packages/astro/src/assets/build/generate.ts index c4109ea1edb1..1c55a93b9874 100644 --- a/packages/astro/src/assets/build/generate.ts +++ b/packages/astro/src/assets/build/generate.ts @@ -1,7 +1,7 @@ import { dim, green } from 'kleur/colors'; import fs, { readFileSync } from 'node:fs'; import { basename, join } from 'node:path/posix'; -import PQueue from 'p-queue'; +import type PQueue from 'p-queue'; import type { AstroConfig } from '../../@types/astro.js'; import type { BuildPipeline } from '../../core/build/buildPipeline.js'; import { getOutDirWithinCwd } from '../../core/build/common.js'; diff --git a/packages/astro/src/cli/preferences/index.ts b/packages/astro/src/cli/preferences/index.ts index 35de2ce04068..4fd29cdfea14 100644 --- a/packages/astro/src/cli/preferences/index.ts +++ b/packages/astro/src/cli/preferences/index.ts @@ -2,7 +2,7 @@ import type yargs from 'yargs-parser'; import type { AstroSettings } from '../../@types/astro.js'; -import { bold } from 'kleur/colors'; +import { bgGreen, black, bold, dim } from 'kleur/colors'; import { fileURLToPath } from 'node:url'; import dlv from 'dlv'; @@ -10,7 +10,12 @@ import { resolveConfig } from '../../core/config/config.js'; import { createSettings } from '../../core/config/settings.js'; import * as msg from '../../core/messages.js'; import { DEFAULT_PREFERENCES } from '../../preferences/defaults.js'; -import { coerce, isValidKey, type PreferenceKey } from '../../preferences/index.js'; +import { + coerce, + isValidKey, + type PreferenceKey, + type PreferenceLocation, +} from '../../preferences/index.js'; import { createLoggerFromFlags, flagsToAstroInlineConfig } from '../flags.js'; // @ts-expect-error flattie types are mispackaged import { flattie } from 'flattie'; @@ -211,12 +216,52 @@ async function resetPreference( } async function listPreferences(settings: AstroSettings, { location, json }: SubcommandOptions) { - const store = await settings.preferences.getAll({ location }); if (json) { - console.log(JSON.stringify(store, null, 2)); + const resolved = await settings.preferences.getAll(); + console.log(JSON.stringify(resolved, null, 2)); return 0; } - prettyPrint(store); + const { global, project, defaults } = await settings.preferences.list({ location }); + const flatProject = flattie(project); + const flatGlobal = flattie(global); + const flatUser = Object.assign({}, flatGlobal, flatProject); + for (let key of Object.keys(flatUser)) { + if (!isValidKey(key)) { + delete flatUser[key]; + continue; + } + } + + const flatDefault = flattie(defaults); + const userKeys = Object.keys(flatUser); + + if (userKeys.length > 0) { + const badge = bgGreen(black(` Your Preferences `)); + const table = formatTable(flatUser, ['Preference', 'Value']); + + console.log(['', badge, table].join('\n')); + } else { + const badge = bgGreen(black(` Your Preferences `)); + const message = dim('No preferences set'); + console.log(['', badge, '', message].join('\n')); + } + const flatUnset = Object.assign({}, flatDefault); + for (const key of userKeys) { + delete flatUnset[key]; + } + const unsetKeys = Object.keys(flatUnset); + + if (unsetKeys.length > 0) { + const badge = bgGreen(black(` Default Preferences `)); + const table = formatTable(flatUnset, ['Preference', 'Value']); + + console.log(['', badge, table].join('\n')); + } else { + const badge = bgGreen(black(` Default Preferences `)); + const message = dim('All preferences have been set'); + console.log(['', badge, '', message].join('\n')); + } + return 0; } @@ -256,19 +301,25 @@ function formatTable( b: string | number | boolean, style: (value: string | number | boolean) => string = (v) => v.toString() ): string { - return `${chars.v} ${style(a)} ${space(colALength - a.length - 2)} ${chars.v} ${style( + return `${dim(chars.v)} ${style(a)} ${space(colALength - a.length - 2)} ${dim(chars.v)} ${style( b - )} ${space(colBLength - b.toString().length - 3)} ${chars.v}`; + )} ${space(colBLength - b.toString().length - 3)} ${dim(chars.v)}`; } - const top = `${chars.topLeft}${chars.h.repeat(colALength + 1)}${chars.hBottom}${chars.h.repeat( - colBLength - )}${chars.topRight}`; - const bottom = `${chars.bottomLeft}${chars.h.repeat(colALength + 1)}${chars.hTop}${chars.h.repeat( - colBLength - )}${chars.bottomRight}`; - const divider = `${chars.vRightThick}${chars.hThick.repeat(colALength + 1)}${ - chars.hThickCross - }${chars.hThick.repeat(colBLength)}${chars.vLeftThick}`; + const top = dim( + `${chars.topLeft}${chars.h.repeat(colALength + 1)}${chars.hBottom}${chars.h.repeat( + colBLength + )}${chars.topRight}` + ); + const bottom = dim( + `${chars.bottomLeft}${chars.h.repeat(colALength + 1)}${chars.hTop}${chars.h.repeat( + colBLength + )}${chars.bottomRight}` + ); + const divider = dim( + `${chars.vRightThick}${chars.hThick.repeat(colALength + 1)}${ + chars.hThickCross + }${chars.hThick.repeat(colBLength)}${chars.vLeftThick}` + ); const rows: string[] = [top, formatRow(-1, colA, colB, bold), divider]; let i = 0; for (const [key, value] of Object.entries(object)) { diff --git a/packages/astro/src/core/build/buildPipeline.ts b/packages/astro/src/core/build/buildPipeline.ts index 87166b4f4a1b..623e89630fcf 100644 --- a/packages/astro/src/core/build/buildPipeline.ts +++ b/packages/astro/src/core/build/buildPipeline.ts @@ -2,7 +2,7 @@ import type { AstroConfig, AstroSettings, SSRLoadedRenderer } from '../../@types import { getOutputDirectory, isServerLikeOutput } from '../../prerender/utils.js'; import { BEFORE_HYDRATION_SCRIPT_ID } from '../../vite-plugin-scripts/index.js'; import type { SSRManifest } from '../app/types.js'; -import { Logger } from '../logger/core.js'; +import type { Logger } from '../logger/core.js'; import { Pipeline } from '../pipeline.js'; import { routeIsFallback, routeIsRedirect } from '../redirects/helpers.js'; import { createEnvironment } from '../render/index.js'; diff --git a/packages/astro/src/core/build/generate.ts b/packages/astro/src/core/build/generate.ts index 5fc439c154d4..99912ba27b66 100644 --- a/packages/astro/src/core/build/generate.ts +++ b/packages/astro/src/core/build/generate.ts @@ -10,7 +10,6 @@ import type { GetStaticPathsItem, RouteData, RouteType, - SSRElement, SSRError, SSRLoadedRenderer, SSRManifest, @@ -250,13 +249,11 @@ async function generatePage( // prepare information we need const logger = pipeline.getLogger(); const config = pipeline.getConfig(); - const manifest = pipeline.getManifest(); const pageModulePromise = ssrEntry.page; const onRequest = ssrEntry.onRequest; const pageInfo = getPageDataByComponent(pipeline.getInternals(), pageData.route.component); // Calculate information of the page, like scripts, links and styles - const hoistedScripts = pageInfo?.hoistedScript ?? null; const styles = pageData.styles .sort(cssOrder) .map(({ sheet }) => sheet) @@ -270,7 +267,7 @@ async function generatePage( pipeline.getManifest().base, pipeline.getManifest().trailingSlash ); - if (config.experimental.i18n && i18nMiddleware) { + if (config.i18n && i18nMiddleware) { if (onRequest) { pipeline.setMiddlewareFunction(sequence(i18nMiddleware, onRequest)); } else { @@ -295,6 +292,15 @@ async function generatePage( }; // Now we explode the routes. A route render itself, and it can render its fallbacks (i18n routing) for (const route of eachRouteInRouteData(pageData)) { + const icon = + route.type === 'page' || route.type === 'redirect' || route.type === 'fallback' + ? green('▶') + : magenta('λ'); + if (isRelativePath(route.component)) { + logger.info(null, `${icon} ${route.route}`); + } else { + logger.info(null, `${icon} ${route.component}`); + } // Get paths for the route, calling getStaticPaths if needed. const paths = await getPathsForRoute(route, pageModule, pipeline, builtPaths); let timeStart = performance.now(); @@ -516,16 +522,6 @@ async function generatePath( } } - const icon = - route.type === 'page' || route.type === 'redirect' || route.type === 'fallback' - ? green('▶') - : magenta('λ'); - if (isRelativePath(route.component)) { - logger.info(null, `${icon} ${route.route}`); - } else { - logger.info(null, `${icon} ${route.component}`); - } - // This adds the page name to the array so it can be shown as part of stats. if (route.type === 'page') { addPageName(pathname, pipeline.getStaticBuildOptions()); @@ -546,7 +542,7 @@ async function generatePath( logger: pipeline.getLogger(), ssr, }); - const i18n = pipeline.getConfig().experimental.i18n; + const i18n = pipeline.getConfig().i18n; const renderContext = await createRenderContext({ pathname, @@ -629,12 +625,12 @@ export function createBuildManifest( renderers: SSRLoadedRenderer[] ): SSRManifest { let i18nManifest: SSRManifestI18n | undefined = undefined; - if (settings.config.experimental.i18n) { + if (settings.config.i18n) { i18nManifest = { - fallback: settings.config.experimental.i18n.fallback, - routing: settings.config.experimental.i18n.routing, - defaultLocale: settings.config.experimental.i18n.defaultLocale, - locales: settings.config.experimental.i18n.locales, + fallback: settings.config.i18n.fallback, + routing: settings.config.i18n.routing, + defaultLocale: settings.config.i18n.defaultLocale, + locales: settings.config.i18n.locales, }; } return { diff --git a/packages/astro/src/core/build/index.ts b/packages/astro/src/core/build/index.ts index 0245e50c2ff1..fa45c9d6b6e3 100644 --- a/packages/astro/src/core/build/index.ts +++ b/packages/astro/src/core/build/index.ts @@ -24,7 +24,8 @@ import { resolveConfig } from '../config/config.js'; import { createNodeLogger } from '../config/logging.js'; import { createSettings } from '../config/settings.js'; import { createVite } from '../create-vite.js'; -import { Logger, levels, timerMessage } from '../logger/core.js'; +import type { Logger } from '../logger/core.js'; +import { levels, timerMessage } from '../logger/core.js'; import { apply as applyPolyfill } from '../polyfill.js'; import { RouteCache } from '../render/route-cache.js'; import { createRouteManifest } from '../routing/index.js'; diff --git a/packages/astro/src/core/build/plugins/plugin-manifest.ts b/packages/astro/src/core/build/plugins/plugin-manifest.ts index 6f9ec6326e07..1a313b6bbdb4 100644 --- a/packages/astro/src/core/build/plugins/plugin-manifest.ts +++ b/packages/astro/src/core/build/plugins/plugin-manifest.ts @@ -240,12 +240,12 @@ function buildManifest( entryModules[BEFORE_HYDRATION_SCRIPT_ID] = ''; } let i18nManifest: SSRManifestI18n | undefined = undefined; - if (settings.config.experimental.i18n) { + if (settings.config.i18n) { i18nManifest = { - fallback: settings.config.experimental.i18n.fallback, - routing: settings.config.experimental.i18n.routing, - locales: settings.config.experimental.i18n.locales, - defaultLocale: settings.config.experimental.i18n.defaultLocale, + fallback: settings.config.i18n.fallback, + routing: settings.config.i18n.routing, + locales: settings.config.i18n.locales, + defaultLocale: settings.config.i18n.defaultLocale, }; } diff --git a/packages/astro/src/core/build/util.ts b/packages/astro/src/core/build/util.ts index fc12b486f164..3d59cf45ce9a 100644 --- a/packages/astro/src/core/build/util.ts +++ b/packages/astro/src/core/build/util.ts @@ -29,9 +29,9 @@ export function shouldAppendForwardSlash( } export function i18nHasFallback(config: AstroConfig): boolean { - if (config.experimental.i18n && config.experimental.i18n.fallback) { + if (config.i18n && config.i18n.fallback) { // we have some fallback and the control is not none - return Object.keys(config.experimental.i18n.fallback).length > 0; + return Object.keys(config.i18n.fallback).length > 0; } return false; diff --git a/packages/astro/src/core/compile/compile.ts b/packages/astro/src/core/compile/compile.ts index 2985dcab963e..97625f021a55 100644 --- a/packages/astro/src/core/compile/compile.ts +++ b/packages/astro/src/core/compile/compile.ts @@ -5,14 +5,17 @@ import type { AstroConfig } from '../../@types/astro.js'; import { transform } from '@astrojs/compiler'; import { fileURLToPath } from 'node:url'; import { normalizePath } from 'vite'; -import { AggregateError, AstroError, CompilerError } from '../errors/errors.js'; +import type { AstroError } from '../errors/errors.js'; +import { AggregateError, CompilerError } from '../errors/errors.js'; import { AstroErrorData } from '../errors/index.js'; import { resolvePath } from '../util.js'; import { createStylePreprocessor } from './style.js'; +import type { AstroPreferences } from '../../preferences/index.js'; export interface CompileProps { astroConfig: AstroConfig; viteConfig: ResolvedConfig; + preferences: AstroPreferences; filename: string; source: string; } @@ -25,6 +28,7 @@ export interface CompileResult extends TransformResult { export async function compile({ astroConfig, viteConfig, + preferences, filename, source, }: CompileProps): Promise { @@ -47,7 +51,10 @@ export async function compile({ resultScopedSlot: true, transitionsAnimationURL: 'astro/components/viewtransitions.css', annotateSourceFile: - !viteConfig.isProduction && astroConfig.devOverlay && astroConfig.devOverlay.enabled, + viteConfig.command === 'serve' && + astroConfig.devToolbar && + astroConfig.devToolbar.enabled && + (await preferences.get('devToolbar.enabled')), preprocessStyle: createStylePreprocessor({ filename, viteConfig, diff --git a/packages/astro/src/core/config/schema.ts b/packages/astro/src/core/config/schema.ts index 95e3964b43f6..08910720a13e 100644 --- a/packages/astro/src/core/config/schema.ts +++ b/packages/astro/src/core/config/schema.ts @@ -41,13 +41,8 @@ const ASTRO_CONFIG_DEFAULTS = { image: { service: { entrypoint: 'astro/assets/services/sharp', config: {} }, }, - devOverlay: { - enabled: true, - defaultState: 'minimized', - }, devToolbar: { enabled: true, - defaultState: 'minimized', }, compressHTML: true, server: { @@ -232,20 +227,9 @@ export const AstroConfigSchema = z.object({ .default([]), }) .default(ASTRO_CONFIG_DEFAULTS.image), - devOverlay: z - .object({ - enabled: z.boolean().default(ASTRO_CONFIG_DEFAULTS.devOverlay.enabled), - defaultState: z - .enum(['minimized', 'expanded']) - .default(ASTRO_CONFIG_DEFAULTS.devOverlay.defaultState), - }) - .default(ASTRO_CONFIG_DEFAULTS.devOverlay), devToolbar: z .object({ enabled: z.boolean().default(ASTRO_CONFIG_DEFAULTS.devToolbar.enabled), - defaultState: z - .enum(['minimized', 'expanded']) - .default(ASTRO_CONFIG_DEFAULTS.devToolbar.defaultState), }) .default(ASTRO_CONFIG_DEFAULTS.devToolbar), markdown: z @@ -318,90 +302,90 @@ export const AstroConfigSchema = z.object({ vite: z .custom((data) => data instanceof Object && !Array.isArray(data)) .default(ASTRO_CONFIG_DEFAULTS.vite), - experimental: z - .object({ - optimizeHoistedScript: z - .boolean() - .optional() - .default(ASTRO_CONFIG_DEFAULTS.experimental.optimizeHoistedScript), - i18n: z.optional( - z + i18n: z.optional( + z + .object({ + defaultLocale: z.string(), + locales: z.array( + z.union([ + z.string(), + z.object({ + path: z.string(), + codes: z.string().array().nonempty(), + }), + ]) + ), + fallback: z.record(z.string(), z.string()).optional(), + routing: z .object({ - defaultLocale: z.string(), - locales: z.array( - z.union([ - z.string(), - z.object({ - path: z.string(), - codes: z.string().array().nonempty(), - }), - ]) - ), - fallback: z.record(z.string(), z.string()).optional(), - routing: z - .object({ - prefixDefaultLocale: z.boolean().default(false), - strategy: z.enum(['pathname']).default('pathname'), - }) - .default({}) - .transform((routing) => { - let strategy: RoutingStrategies; - switch (routing.strategy) { - case 'pathname': { - if (routing.prefixDefaultLocale === true) { - strategy = 'prefix-always'; - } else { - strategy = 'prefix-other-locales'; - } - } - } - return strategy; - }), + prefixDefaultLocale: z.boolean().default(false), + strategy: z.enum(['pathname']).default('pathname'), }) - .optional() - .superRefine((i18n, ctx) => { - if (i18n) { - const { defaultLocale, locales: _locales, fallback } = i18n; - const locales = _locales.map((locale) => { - if (typeof locale === 'string') { - return locale; + .default({}) + .transform((routing) => { + let strategy: RoutingStrategies; + switch (routing.strategy) { + case 'pathname': { + if (routing.prefixDefaultLocale === true) { + strategy = 'prefix-always'; } else { - return locale.path; + strategy = 'prefix-other-locales'; } - }); - if (!locales.includes(defaultLocale)) { + } + } + return strategy; + }), + }) + .optional() + .superRefine((i18n, ctx) => { + if (i18n) { + const { defaultLocale, locales: _locales, fallback } = i18n; + const locales = _locales.map((locale) => { + if (typeof locale === 'string') { + return locale; + } else { + return locale.path; + } + }); + if (!locales.includes(defaultLocale)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `The default locale \`${defaultLocale}\` is not present in the \`i18n.locales\` array.`, + }); + } + if (fallback) { + for (const [fallbackFrom, fallbackTo] of Object.entries(fallback)) { + if (!locales.includes(fallbackFrom)) { ctx.addIssue({ code: z.ZodIssueCode.custom, - message: `The default locale \`${defaultLocale}\` is not present in the \`i18n.locales\` array.`, + message: `The locale \`${fallbackFrom}\` key in the \`i18n.fallback\` record doesn't exist in the \`i18n.locales\` array.`, }); } - if (fallback) { - for (const [fallbackFrom, fallbackTo] of Object.entries(fallback)) { - if (!locales.includes(fallbackFrom)) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: `The locale \`${fallbackFrom}\` key in the \`i18n.fallback\` record doesn't exist in the \`i18n.locales\` array.`, - }); - } - if (fallbackFrom === defaultLocale) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: `You can't use the default locale as a key. The default locale can only be used as value.`, - }); - } + if (fallbackFrom === defaultLocale) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `You can't use the default locale as a key. The default locale can only be used as value.`, + }); + } - if (!locales.includes(fallbackTo)) { - ctx.addIssue({ - code: z.ZodIssueCode.custom, - message: `The locale \`${fallbackTo}\` value in the \`i18n.fallback\` record doesn't exist in the \`i18n.locales\` array.`, - }); - } - } + if (!locales.includes(fallbackTo)) { + ctx.addIssue({ + code: z.ZodIssueCode.custom, + message: `The locale \`${fallbackTo}\` value in the \`i18n.fallback\` record doesn't exist in the \`i18n.locales\` array.`, + }); } } - }) - ), + } + } + }) + ), + experimental: z + .object({ + optimizeHoistedScript: z + .boolean() + .optional() + .default(ASTRO_CONFIG_DEFAULTS.experimental.optimizeHoistedScript), contentCollectionCache: z .boolean() .optional() diff --git a/packages/astro/src/core/create-vite.ts b/packages/astro/src/core/create-vite.ts index 418e6387be14..bd3af4e292a5 100644 --- a/packages/astro/src/core/create-vite.ts +++ b/packages/astro/src/core/create-vite.ts @@ -141,7 +141,7 @@ export async function createVite( astroPrefetch({ settings }), astroTransitions({ settings }), astroDevOverlay({ settings, logger }), - !!settings.config.experimental.i18n && astroInternationalization({ settings }), + !!settings.config.i18n && astroInternationalization({ settings }), ], publicDir: fileURLToPath(settings.config.publicDir), root: fileURLToPath(settings.config.root), diff --git a/packages/astro/src/core/dev/restart.ts b/packages/astro/src/core/dev/restart.ts index b19eae4ac461..3d77ef0c0cc5 100644 --- a/packages/astro/src/core/dev/restart.ts +++ b/packages/astro/src/core/dev/restart.ts @@ -1,4 +1,4 @@ -import nodeFs from 'node:fs'; +import type nodeFs from 'node:fs'; import { fileURLToPath } from 'node:url'; import * as vite from 'vite'; import type { AstroInlineConfig, AstroSettings } from '../../@types/astro.js'; diff --git a/packages/astro/src/core/logger/node.ts b/packages/astro/src/core/logger/node.ts index 727cafd1b220..2c75968d2f85 100644 --- a/packages/astro/src/core/logger/node.ts +++ b/packages/astro/src/core/logger/node.ts @@ -1,5 +1,5 @@ import debugPackage from 'debug'; -import { Writable } from 'node:stream'; +import type { Writable } from 'node:stream'; import { getEventPrefix, levels, type LogMessage, type LogWritable } from './core.js'; type ConsoleStream = Writable & { diff --git a/packages/astro/src/core/messages.ts b/packages/astro/src/core/messages.ts index ebac2c51d611..b105e985cb05 100644 --- a/packages/astro/src/core/messages.ts +++ b/packages/astro/src/core/messages.ts @@ -37,7 +37,7 @@ export function req({ method?: string; reqTime?: number; }): string { - const color = statusCode >= 400 ? red : statusCode >= 300 ? yellow : blue; + const color = statusCode >= 500 ? red : statusCode >= 300 ? yellow : blue; return ( color(`[${statusCode}]`) + ` ` + diff --git a/packages/astro/src/core/render/params-and-props.ts b/packages/astro/src/core/render/params-and-props.ts index 0ad5df205f5b..3532c5f83726 100644 --- a/packages/astro/src/core/render/params-and-props.ts +++ b/packages/astro/src/core/render/params-and-props.ts @@ -4,7 +4,8 @@ import type { Logger } from '../logger/core.js'; import { routeIsFallback } from '../redirects/helpers.js'; import { routeIsRedirect } from '../redirects/index.js'; import { getParams } from '../routing/params.js'; -import { RouteCache, callGetStaticPaths, findPathItemByKey } from './route-cache.js'; +import type { RouteCache } from './route-cache.js'; +import { callGetStaticPaths, findPathItemByKey } from './route-cache.js'; interface GetParamsAndPropsOptions { mod: ComponentInstance | undefined; diff --git a/packages/astro/src/core/render/route-cache.ts b/packages/astro/src/core/render/route-cache.ts index 4db5b75fd494..8a4e821a523c 100644 --- a/packages/astro/src/core/render/route-cache.ts +++ b/packages/astro/src/core/render/route-cache.ts @@ -8,7 +8,6 @@ import type { RouteData, RuntimeMode, } from '../../@types/astro.js'; -import { AstroError, AstroErrorData } from '../errors/index.js'; import type { Logger } from '../logger/core.js'; import { stringifyParams } from '../routing/params.js'; diff --git a/packages/astro/src/core/routing/manifest/create.ts b/packages/astro/src/core/routing/manifest/create.ts index c582281ec323..c9c0bb071685 100644 --- a/packages/astro/src/core/routing/manifest/create.ts +++ b/packages/astro/src/core/routing/manifest/create.ts @@ -18,7 +18,6 @@ import { SUPPORTED_MARKDOWN_FILE_EXTENSIONS } from '../../constants.js'; import { removeLeadingForwardSlash, slash } from '../../path.js'; import { resolvePages } from '../../util.js'; import { getRouteGenerator } from './generator.js'; -import { getPathByLocale } from '../../../i18n/index.js'; const require = createRequire(import.meta.url); interface Item { @@ -491,7 +490,7 @@ export function createRouteManifest( // Didn't find a good place, insert last routes.push(routeData); }); - const i18n = settings.config.experimental.i18n; + const i18n = settings.config.i18n; if (i18n) { // In this block of code we group routes based on their locale diff --git a/packages/astro/src/i18n/vite-plugin-i18n.ts b/packages/astro/src/i18n/vite-plugin-i18n.ts index a28481cac513..cd4c3f854bd3 100644 --- a/packages/astro/src/i18n/vite-plugin-i18n.ts +++ b/packages/astro/src/i18n/vite-plugin-i18n.ts @@ -35,7 +35,7 @@ export default function astroInternationalization({ const trailingSlash = ${JSON.stringify(settings.config.trailingSlash)}; const format = ${JSON.stringify(settings.config.build.format)}; const site = ${JSON.stringify(settings.config.site)}; - const i18n = ${JSON.stringify(settings.config.experimental.i18n)}; + const i18n = ${JSON.stringify(settings.config.i18n)}; export const getRelativeLocaleUrl = (locale, path = "", opts) => _getLocaleRelativeUrl({ locale, diff --git a/packages/astro/src/integrations/index.ts b/packages/astro/src/integrations/index.ts index 9031eeb2dfe2..d082c438fbaa 100644 --- a/packages/astro/src/integrations/index.ts +++ b/packages/astro/src/integrations/index.ts @@ -18,7 +18,7 @@ import type { SerializedSSRManifest } from '../core/app/types.js'; import type { PageBuildData } from '../core/build/types.js'; import { buildClientDirectiveEntrypoint } from '../core/client-directive/index.js'; import { mergeConfig } from '../core/config/index.js'; -import { AstroIntegrationLogger, type Logger } from '../core/logger/core.js'; +import type { AstroIntegrationLogger, Logger } from '../core/logger/core.js'; import { isServerLikeOutput } from '../prerender/utils.js'; import { validateSupportedFeatures } from './astroFeaturesValidation.js'; diff --git a/packages/astro/src/preferences/index.ts b/packages/astro/src/preferences/index.ts index 00a46c573a91..ee50261158bc 100644 --- a/packages/astro/src/preferences/index.ts +++ b/packages/astro/src/preferences/index.ts @@ -22,11 +22,21 @@ export type GetDotKey< K extends string, > = K extends `${infer U}.${infer Rest}` ? GetDotKey : T[K]; +export type PreferenceLocation = 'global' | 'project'; export interface PreferenceOptions { - location?: 'global' | 'project'; + location?: PreferenceLocation; } +type DeepPartial = T extends object + ? { + [P in keyof T]?: DeepPartial; + } + : T; + export type PreferenceKey = DotKeys; +export interface PreferenceList extends Record> { + defaults: Preferences; +} export interface AstroPreferences { get( @@ -38,7 +48,8 @@ export interface AstroPreferences { value: GetDotKey, opts?: PreferenceOptions ): Promise; - getAll(opts?: PreferenceOptions): Promise>; + getAll(): Promise; + list(opts?: PreferenceOptions): Promise; } export function isValidKey(key: string): key is PreferenceKey { @@ -62,7 +73,7 @@ export function coerce(key: string, value: unknown) { export default function createPreferences(config: AstroConfig): AstroPreferences { const global = new PreferenceStore(getGlobalPreferenceDir()); const project = new PreferenceStore(fileURLToPath(new URL('./.astro/', config.root))); - const stores = { global, project }; + const stores: Record = { global, project }; return { async get(key, { location } = {}) { @@ -72,10 +83,20 @@ export default function createPreferences(config: AstroConfig): AstroPreferences async set(key, value, { location = 'project' } = {}) { stores[location].set(key, value); }, - async getAll({ location } = {}) { - if (!location) - return Object.assign({}, stores['global'].getAll(), stores['project'].getAll()); - return stores[location].getAll(); + async getAll() { + return Object.assign( + {}, + DEFAULT_PREFERENCES, + stores['global'].getAll(), + stores['project'].getAll() + ); + }, + async list() { + return { + global: stores['global'].getAll(), + project: stores['project'].getAll(), + defaults: DEFAULT_PREFERENCES, + }; }, }; } diff --git a/packages/astro/src/runtime/client/dev-overlay/entrypoint.ts b/packages/astro/src/runtime/client/dev-overlay/entrypoint.ts index 2124c21e07e0..fa3020b03c98 100644 --- a/packages/astro/src/runtime/client/dev-overlay/entrypoint.ts +++ b/packages/astro/src/runtime/client/dev-overlay/entrypoint.ts @@ -1,12 +1,14 @@ import type { DevOverlayPlugin as DevOverlayPluginDefinition } from '../../../@types/astro.js'; -import { type AstroDevOverlay, type DevOverlayPlugin } from './overlay.js'; +import type { AstroDevOverlay, DevOverlayPlugin } from './overlay.js'; import { settings } from './settings.js'; +// @ts-expect-error +import { loadDevOverlayPlugins } from 'astro:dev-overlay'; let overlay: AstroDevOverlay; document.addEventListener('DOMContentLoaded', async () => { const [ - { loadDevOverlayPlugins }, + customPluginsDefinitions, { default: astroDevToolPlugin }, { default: astroAuditPlugin }, { default: astroXrayPlugin }, @@ -23,10 +25,9 @@ document.addEventListener('DOMContentLoaded', async () => { DevOverlayIcon, }, ] = await Promise.all([ - // @ts-expect-error - import('astro:dev-overlay'), + loadDevOverlayPlugins() as DevOverlayPluginDefinition[], import('./plugins/astro.js'), - import('./plugins/audit.js'), + import('./plugins/audit/index.js'), import('./plugins/xray.js'), import('./plugins/settings.js'), import('./overlay.js'), @@ -126,7 +127,7 @@ document.addEventListener('DOMContentLoaded', async () => { box-shadow: 0px 0px 0px 0px rgba(19, 21, 26, 0.30), 0px 1px 2px 0px rgba(19, 21, 26, 0.29), 0px 4px 4px 0px rgba(19, 21, 26, 0.26), 0px 10px 6px 0px rgba(19, 21, 26, 0.15), 0px 17px 7px 0px rgba(19, 21, 26, 0.04), 0px 26px 7px 0px rgba(19, 21, 26, 0.01); width: 192px; padding: 8px; - z-index: 9999999999; + z-index: 2000000010; transform: translate(-50%, 0%); position: fixed; bottom: 72px; @@ -239,7 +240,6 @@ document.addEventListener('DOMContentLoaded', async () => { }, } satisfies DevOverlayPluginDefinition; - const customPluginsDefinitions = (await loadDevOverlayPlugins()) as DevOverlayPluginDefinition[]; const plugins: DevOverlayPlugin[] = [ ...[ astroDevToolPlugin, diff --git a/packages/astro/src/runtime/client/dev-overlay/overlay.ts b/packages/astro/src/runtime/client/dev-overlay/overlay.ts index 2def988020ac..48241ded9f77 100644 --- a/packages/astro/src/runtime/client/dev-overlay/overlay.ts +++ b/packages/astro/src/runtime/client/dev-overlay/overlay.ts @@ -58,7 +58,7 @@ export class AstroDevOverlay extends HTMLElement { bottom: 0px; left: 50%; transform: translate(-50%, 0%); - z-index: 9999999999; + z-index: 2000000010; display: flex; flex-direction: column; align-items: center; @@ -71,7 +71,7 @@ export class AstroDevOverlay extends HTMLElement { } #dev-overlay[data-hidden] #dev-bar .item { - opacity: 0; + opacity: 0.2; } #dev-bar-hitbox-above, @@ -228,12 +228,9 @@ export class AstroDevOverlay extends HTMLElement { width: 1px; } -
+
@@ -282,9 +279,12 @@ export class AstroDevOverlay extends HTMLElement { // Init plugin lazily, so that the page can load faster. // Fallback to setTimeout for Safari (sad!) if ('requestIdleCallback' in window) { - window.requestIdleCallback(async () => { - this.plugins.map((plugin) => this.initPlugin(plugin)); - }); + window.requestIdleCallback( + async () => { + this.plugins.map((plugin) => this.initPlugin(plugin)); + }, + { timeout: 300 } + ); } else { setTimeout(async () => { this.plugins.map((plugin) => this.initPlugin(plugin)); @@ -310,13 +310,14 @@ export class AstroDevOverlay extends HTMLElement { attachEvents() { const items = this.shadowRoot.querySelectorAll('.item'); items.forEach((item) => { - item.addEventListener('click', async (e) => { - const target = e.currentTarget; + item.addEventListener('click', async (event) => { + const target = event.currentTarget; if (!target || !(target instanceof HTMLElement)) return; const id = target.dataset.pluginId; if (!id) return; const plugin = this.getPluginById(id); if (!plugin) return; + event.stopPropagation(); await this.togglePluginStatus(plugin); }); }); @@ -340,37 +341,15 @@ export class AstroDevOverlay extends HTMLElement { }); }); - // On click, show the overlay if it's hidden, it's likely the user wants to interact with it - this.shadowRoot.addEventListener('click', () => { - if (!this.isHidden()) return; - this.setOverlayVisible(true); - }); - - this.devOverlay!.addEventListener('keyup', (event) => { - if (event.code === 'Space' || event.code === 'Enter') { - if (!this.isHidden()) return; - this.setOverlayVisible(true); - } - if (event.key === 'Escape') { - if (this.isHidden()) return; - if (this.getActivePlugin()) return; - this.setOverlayVisible(false); - } - }); - document.addEventListener('keyup', (event) => { - if (event.key !== 'Escape') { - return; - } - if (this.isHidden()) { - return; - } + if (event.key !== 'Escape') return; + if (this.isHidden()) return; const activePlugin = this.getActivePlugin(); if (activePlugin) { - this.setPluginStatus(activePlugin, false); - return; + this.togglePluginStatus(activePlugin); + } else { + this.setOverlayVisible(false); } - this.setOverlayVisible(false); }); } diff --git a/packages/astro/src/runtime/client/dev-overlay/plugins/audit/a11y.ts b/packages/astro/src/runtime/client/dev-overlay/plugins/audit/a11y.ts new file mode 100644 index 000000000000..a5e6e5073ad5 --- /dev/null +++ b/packages/astro/src/runtime/client/dev-overlay/plugins/audit/a11y.ts @@ -0,0 +1,481 @@ +/** + * https://github.com/sveltejs/svelte/blob/61e5e53eee82e895c1a5b4fd36efb87eafa1fc2d/LICENSE.md + * @license MIT + * + * Copyright (c) 2016-23 [these people](https://github.com/sveltejs/svelte/graphs/contributors) + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +import type { AuditRuleWithSelector } from './index.js'; + +const a11y_required_attributes = { + a: ['href'], + area: ['alt', 'aria-label', 'aria-labelledby'], + // html-has-lang + html: ['lang'], + // iframe-has-title + iframe: ['title'], + img: ['alt'], + object: ['title', 'aria-label', 'aria-labelledby'], +}; + +const interactiveElements = ['button', 'details', 'embed', 'iframe', 'label', 'select', 'textarea']; + +const aria_non_interactive_roles = [ + 'alert', + 'alertdialog', + 'application', + 'article', + 'banner', + 'button', + 'cell', + 'checkbox', + 'columnheader', + 'combobox', + 'complementary', + 'contentinfo', + 'definition', + 'dialog', + 'directory', + 'document', + 'feed', + 'figure', + 'form', + 'grid', + 'gridcell', + 'group', + 'heading', + 'img', + 'link', + 'list', + 'listbox', + 'listitem', + 'log', + 'main', + 'marquee', + 'math', + 'menu', + 'menubar', + 'menuitem', + 'menuitemcheckbox', + 'menuitemradio', + 'navigation', + 'none', + 'note', + 'option', + 'presentation', + 'progressbar', + 'radio', + 'radiogroup', + 'region', + 'row', + 'rowgroup', + 'rowheader', + 'scrollbar', + 'search', + 'searchbox', + 'separator', + 'slider', + 'spinbutton', + 'status', + 'switch', + 'tab', + 'tablist', + 'tabpanel', + 'term', + 'textbox', + 'timer', + 'toolbar', + 'tooltip', + 'tree', + 'treegrid', + 'treeitem', +]; + +const a11y_required_content = [ + // anchor-has-content + 'a', + // heading-has-content + 'h1', + 'h2', + 'h3', + 'h4', + 'h5', + 'h6', +]; + +const a11y_distracting_elements = ['blink', 'marquee']; + +const a11y_nested_implicit_semantics = new Map([ + ['header', 'banner'], + ['footer', 'contentinfo'], +]); +const a11y_implicit_semantics = new Map([ + ['a', 'link'], + ['area', 'link'], + ['article', 'article'], + ['aside', 'complementary'], + ['body', 'document'], + ['button', 'button'], + ['datalist', 'listbox'], + ['dd', 'definition'], + ['dfn', 'term'], + ['dialog', 'dialog'], + ['details', 'group'], + ['dt', 'term'], + ['fieldset', 'group'], + ['figure', 'figure'], + ['form', 'form'], + ['h1', 'heading'], + ['h2', 'heading'], + ['h3', 'heading'], + ['h4', 'heading'], + ['h5', 'heading'], + ['h6', 'heading'], + ['hr', 'separator'], + ['img', 'img'], + ['li', 'listitem'], + ['link', 'link'], + ['main', 'main'], + ['menu', 'list'], + ['meter', 'progressbar'], + ['nav', 'navigation'], + ['ol', 'list'], + ['option', 'option'], + ['optgroup', 'group'], + ['output', 'status'], + ['progress', 'progressbar'], + ['section', 'region'], + ['summary', 'button'], + ['table', 'table'], + ['tbody', 'rowgroup'], + ['textarea', 'textbox'], + ['tfoot', 'rowgroup'], + ['thead', 'rowgroup'], + ['tr', 'row'], + ['ul', 'list'], +]); +const menuitem_type_to_implicit_role = new Map([ + ['command', 'menuitem'], + ['checkbox', 'menuitemcheckbox'], + ['radio', 'menuitemradio'], +]); +const input_type_to_implicit_role = new Map([ + ['button', 'button'], + ['image', 'button'], + ['reset', 'button'], + ['submit', 'button'], + ['checkbox', 'checkbox'], + ['radio', 'radio'], + ['range', 'slider'], + ['number', 'spinbutton'], + ['email', 'textbox'], + ['search', 'searchbox'], + ['tel', 'textbox'], + ['text', 'textbox'], + ['url', 'textbox'], +]); + +const ariaAttributes = new Set( + 'activedescendant atomic autocomplete busy checked colcount colindex colspan controls current describedby description details disabled dropeffect errormessage expanded flowto grabbed haspopup hidden invalid keyshortcuts label labelledby level live modal multiline multiselectable orientation owns placeholder posinset pressed readonly relevant required roledescription rowcount rowindex rowspan selected setsize sort valuemax valuemin valuenow valuetext'.split( + ' ' + ) +); + +const ariaRoles = new Set( + 'alert alertdialog application article banner button cell checkbox columnheader combobox complementary contentinfo definition dialog directory document feed figure form grid gridcell group heading img link list listbox listitem log main marquee math menu menubar menuitem menuitemcheckbox menuitemradio navigation none note option presentation progressbar radio radiogroup region row rowgroup rowheader scrollbar search searchbox separator slider spinbutton status tab tablist tabpanel textbox timer toolbar tooltip tree treegrid treeitem'.split( + ' ' + ) +); + +export const a11y: AuditRuleWithSelector[] = [ + { + code: 'a11y-accesskey', + title: 'Avoid using `accesskey`', + message: + "The `accesskey` attribute can cause accessibility issues. The shortcuts can conflict with the browser's or operating system's shortcuts, and they are difficult for users to discover and use.", + selector: '[accesskey]', + }, + { + code: 'a11y-aria-activedescendant-has-tabindex', + title: 'Elements with attribute `aria-activedescendant` must be tabbable', + message: + 'This element must either have an inherent `tabindex` or declare `tabindex` as an attribute.', + selector: '[aria-activedescendant]', + match(element) { + if (!(element as HTMLElement).tabIndex && !element.hasAttribute('tabindex')) return true; + }, + }, + { + code: 'a11y-aria-attributes', + title: 'Element does not support ARIA roles.', + message: 'Elements like `meta`, `html`, `script`, `style` do not support having ARIA roles.', + selector: ':is(meta, html, script, style)[role]', + match(element) { + for (const attribute of element.attributes) { + if (attribute.name.startsWith('aria-')) return true; + } + }, + }, + { + code: 'a11y-autofocus', + title: 'Avoid using `autofocus`', + message: + 'The `autofocus` attribute can cause accessibility issues, as it can cause the focus to move around unexpectedly for screen reader users.', + selector: '[autofocus]', + }, + { + code: 'a11y-distracting-elements', + title: 'Distracting elements should not be used', + message: + 'Elements that can be visually distracting like `` or `` can cause accessibility issues for visually impaired users and should be avoided.', + selector: `:is(${a11y_distracting_elements.join(',')})`, + }, + { + code: 'a11y-hidden', + title: 'Certain DOM elements are useful for screen reader navigation and should not be hidden', + message: (element) => `${element.localName} element should not be hidden.`, + selector: '[aria-hidden]:is(h1,h2,h3,h4,h5,h6)', + }, + { + code: 'a11y-img-redundant-alt', + title: 'Redundant text in alt attribute', + message: + 'Screen readers already announce `img` elements as an image. There is no need to use words such as "image", "photo", and/or "picture".', + selector: 'img[alt]:not([aria-hidden])', + match: (img: HTMLImageElement) => /\b(image|picture|photo)\b/i.test(img.alt), + }, + { + code: 'a11y-incorrect-aria-attribute-type', + title: 'Incorrect value for ARIA attribute.', + message: '`aria-hidden` should only receive a boolean.', + selector: '[aria-hidden]', + match(element) { + const value = element.getAttribute('aria-hidden'); + if (!value) return true; + if (!['true', 'false'].includes(value)) return true; + }, + }, + { + code: 'a11y-invalid-attribute', + title: 'Attributes important for accessibility should have a valid value', + message: "`href` should not be empty, `'#'`, or `javascript:`.", + selector: 'a[href]:is([href=""], [href="#"], [href^="javascript:" i])', + }, + { + code: 'a11y-label-has-associated-control', + title: '`label` tag should have an associated control and a text content.', + message: + 'The `label` tag must be associated with a control using either `for` or having a nested input. Additionally, the `label` tag must have text content.', + selector: 'label:not([for])', + match(element) { + const inputChild = element.querySelector('input'); + if (!inputChild?.textContent) return true; + }, + }, + { + code: 'a11y-media-has-caption', + title: 'Unmuted video elements should have captions', + message: + 'Videos without captions can be difficult for deaf and hard-of-hearing users to follow along with. If the video does not need captions, add the `muted` attribute.', + selector: 'video:not([muted])', + match(element) { + const tracks = element.querySelectorAll('track'); + if (!tracks.length) return true; + + const hasCaptionTrack = Array.from(tracks).some( + (track) => track.getAttribute('kind') === 'captions' + ); + + return !hasCaptionTrack; + }, + }, + { + code: 'a11y-misplaced-scope', + title: 'The `scope` attribute should only be used on `` elements', + message: + 'The `scope` attribute tells the browser and screen readers how to navigate tables. In HTML5, it should only be used on `` elements.', + selector: ':not(th)[scope]', + }, + { + code: 'a11y-missing-attribute', + title: 'Required attributes missing.', + message: (element) => { + const requiredAttributes = + a11y_required_attributes[element.localName as keyof typeof a11y_required_attributes]; + + const missingAttributes = requiredAttributes.filter( + (attribute) => !element.hasAttribute(attribute) + ); + + return `${ + element.localName + } element is missing required attributes for accessibility: ${missingAttributes.join(', ')} `; + }, + selector: Object.keys(a11y_required_attributes).join(','), + match(element) { + const requiredAttributes = + a11y_required_attributes[element.localName as keyof typeof a11y_required_attributes]; + + if (!requiredAttributes) return true; + for (const attribute of requiredAttributes) { + if (!element.hasAttribute(attribute)) return true; + } + + return false; + }, + }, + { + code: 'a11y-missing-content', + title: 'Missing content on element important for accessibility', + message: 'Headings and anchors must have content to be accessible.', + selector: a11y_required_content.join(','), + match(element) { + if (!element.textContent) return true; + }, + }, + { + code: 'a11y-no-redundant-roles', + title: 'HTML element has redundant ARIA roles', + message: + 'Giving these elements an ARIA role that is already set by the browser has no effect and is redundant.', + selector: [...a11y_implicit_semantics.keys()].join(','), + match(element) { + const role = element.getAttribute('role'); + + if (element.localName === 'input') { + const type = element.getAttribute('type'); + if (!type) return true; + + const implicitRoleForType = input_type_to_implicit_role.get(type); + if (!implicitRoleForType) return true; + + if (role === implicitRoleForType) return false; + } + + // TODO: Handle menuitem and elements that inherit their role from their parent + + const implicitRole = a11y_implicit_semantics.get(element.localName); + if (!implicitRole) return true; + + if (role === implicitRole) return false; + }, + }, + { + code: 'a11y-no-interactive-element-to-noninteractive-role', + title: 'Non-interactive ARIA role used on interactive HTML element.', + message: + 'Interactive HTML elements like `` and `