0
Fork 0
mirror of https://github.com/withastro/astro.git synced 2024-12-30 22:03:56 -05:00

Merge branch 'main' into db

This commit is contained in:
Matthew Phillips 2024-02-16 15:18:24 -05:00
commit 841e24ebb9
689 changed files with 15154 additions and 8798 deletions

View file

@ -1,5 +0,0 @@
---
"@astrojs/rss": patch
---
Restores `rssSchema` to a zod object

View file

@ -1,5 +0,0 @@
---
"astro": patch
---
Fixes types generation from Content Collections config file

View file

@ -1,31 +0,0 @@
---
"@astrojs/alpinejs": minor
---
Allows extending Alpine using the new `entrypoint` configuration
You can extend Alpine by setting the `entrypoint` option to a root-relative import specifier (for example, `entrypoint: "/src/entrypoint"`).
The default export of this file should be a function that accepts an Alpine instance prior to starting, allowing the use of custom directives, plugins and other customizations for advanced use cases.
```js
// astro.config.mjs
import { defineConfig } from 'astro/config';
import alpine from '@astrojs/alpinejs';
export default defineConfig({
// ...
integrations: [alpine({ entrypoint: '/src/entrypoint' })],
});
```
```js
// src/entrypoint.ts
import type { Alpine } from 'alpinejs'
export default (Alpine: Alpine) => {
Alpine.directive('foo', el => {
el.textContent = 'bar';
})
}
```

View file

@ -0,0 +1,5 @@
---
"astro": patch
---
Fixes an issue where some astro commands failed if the astro config file or an integration used the global `crypto` object.

View file

@ -0,0 +1,5 @@
---
"astro": patch
---
Simplifies internal Vite preview server teardown

View file

@ -1,5 +0,0 @@
---
"create-astro": patch
---
Fixes `@astrojs/check` and `typescript` addition to `package.json` dependencies when the user has decided not to auto-install dependencies

View file

@ -1,5 +0,0 @@
---
"astro": patch
---
Adds telemetry for when apps are toggled in the dev toolbar. This data is completely anonymous and only the names of built-in apps are shared with us. This data will help us monitor how much the dev toolbar is used and which apps are used more. For more information on how Astro collects telemetry, visit the following page: https://astro.build/telemetry/

View file

@ -1,5 +0,0 @@
---
"astro": patch
---
Fixes environment variables replacement for `export const prerender`

View file

@ -1,5 +0,0 @@
---
"astro": patch
---
Refactors internals of the `astro:i18n` module to be more maintainable.

View file

@ -1,5 +0,0 @@
---
"@astrojs/vercel": patch
---
Fixes an issue where the serverless function ignored cookies added using Astro.cookies.

View file

@ -7,15 +7,17 @@ module.exports = {
'plugin:@typescript-eslint/recommended-type-checked',
'plugin:@typescript-eslint/stylistic-type-checked',
'prettier',
'plugin:regexp/recommended',
],
parser: '@typescript-eslint/parser',
parserOptions: {
project: ['./packages/*/tsconfig.json', './tsconfig.eslint.json'],
tsconfigRootDir: __dirname,
},
plugins: ['@typescript-eslint', 'prettier', 'no-only-tests'],
plugins: ['@typescript-eslint', 'prettier', 'no-only-tests', 'regexp'],
rules: {
// These off/configured-differently-by-default rules fit well for us
'@typescript-eslint/switch-exhaustiveness-check': 'error',
'@typescript-eslint/array-type': ['error', { default: 'array-simple' }],
'@typescript-eslint/no-unused-vars': [
'warn',
@ -71,6 +73,9 @@ module.exports = {
// These rules enabled by the preset configs don't work well for us
'@typescript-eslint/await-thenable': 'off',
'prefer-const': 'off',
// In some cases, using explicit letter-casing is more performant than the `i` flag
'regexp/use-ignore-case': 'off',
},
overrides: [
{

View file

@ -132,7 +132,7 @@ async function generateMessage() {
}
if (message.length < 2000) {
console.log(message);
return message;
} else {
const { name, version, url } = packages.find((pkg) => pkg.name === 'astro') ?? packages[0];
message = `${emoji} Some ${descriptor} ${pluralize(verb)}\n\n`;
@ -158,11 +158,8 @@ async function generateMessage() {
}
async function run() {
if (!process.env.DISCORD_WEBHOOK) {
console.error('No DISCORD_WEBHOOK variable detected!');
process.exit(1);
}
const content = await generateMessage();
console.log(content);
setOutput('DISCORD_MESSAGE', content);
}

View file

@ -68,7 +68,7 @@ async function bundle(files) {
sourcemap: false,
target: ['es2018'],
outdir: 'out',
external: ['astro:*'],
external: ['astro:*', 'aria-query', 'axobject-query'],
metafile: true,
})

View file

@ -21,7 +21,7 @@ jobs:
MAIN-BENCH: ${{ steps.benchmark-main.outputs.BENCH_RESULT }}
steps:
# https://github.com/actions/checkout/issues/331#issuecomment-1438220926
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
persist-credentials: false
ref: refs/pull/${{ github.event.issue.number }}/head
@ -30,9 +30,9 @@ jobs:
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
node-version: 18
cache: "pnpm"
- name: Install dependencies
@ -63,7 +63,7 @@ jobs:
shell: bash
# main benchmark
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
persist-credentials: false
ref: "main"
@ -94,7 +94,7 @@ jobs:
pull-requests: write
steps:
- name: Comment PR
uses: peter-evans/create-or-update-comment@v2
uses: peter-evans/create-or-update-comment@v4
continue-on-error: true
with:
issue-number: ${{ github.event.issue.number }}

View file

@ -13,7 +13,7 @@ jobs:
steps:
- name: Check if there is already a block on this PR
id: blocked
uses: actions/github-script@v6
uses: actions/github-script@v7
env:
issue_number: ${{ github.event.number }}
with:
@ -32,14 +32,14 @@ jobs:
return 'false'
result-encoding: string
- uses: actions/checkout@v3
- uses: actions/checkout@v4
if: steps.blocked.outputs.result != 'true'
with:
fetch-depth: 0
- name: Get changed files in the .changeset folder
id: changed-files
uses: tj-actions/changed-files@v35
uses: tj-actions/changed-files@v42
if: steps.blocked.outputs.result != 'true'
with:
files: |
@ -63,7 +63,7 @@ jobs:
done
- name: Add label
uses: actions/github-script@v6
uses: actions/github-script@v7
if: steps.check.outputs.found == 'true'
env:
issue_number: ${{ github.event.number }}
@ -77,7 +77,7 @@ jobs:
});
- name: Change PR Status
uses: actions/github-script@v6
uses: actions/github-script@v7
if: steps.check.outputs.found == 'true'
env:
issue_number: ${{ github.event.number }}

View file

@ -26,13 +26,13 @@ jobs:
timeout-minutes: 7
steps:
- name: Check out repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18
cache: "pnpm"

View file

@ -47,13 +47,13 @@ jobs:
run: git config --global core.autocrlf false
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v2
- name: Setup node@${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.NODE_VERSION }}
cache: "pnpm"
@ -77,13 +77,13 @@ jobs:
run: git config --global core.autocrlf false
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18
cache: "pnpm"
@ -110,7 +110,7 @@ jobs:
OS: [ubuntu-latest]
NODE_VERSION: [18, 20.5.1]
include:
- os: macos-latest
- os: macos-14
NODE_VERSION: 18
- os: windows-latest
NODE_VERSION: 18.17.1
@ -122,13 +122,13 @@ jobs:
run: git config --global core.autocrlf false
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v2
- name: Setup node@${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.NODE_VERSION }}
cache: "pnpm"
@ -159,13 +159,13 @@ jobs:
run: git config --global core.autocrlf false
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v2
- name: Setup node@${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.NODE_VERSION }}
cache: "pnpm"
@ -195,19 +195,19 @@ jobs:
run: git config --global core.autocrlf false
- name: Checkout
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v2
- name: Setup node@${{ matrix.NODE_VERSION }}
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.NODE_VERSION }}
cache: "pnpm"
- name: Checkout docs
uses: actions/checkout@v3
uses: actions/checkout@v4
with:
repository: withastro/docs
path: smoke/docs
@ -227,7 +227,7 @@ jobs:
- name: Check if docs changed
id: changes
uses: dorny/paths-filter@v2
uses: dorny/paths-filter@v3
with:
filters: |
docs:

View file

@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out code
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Cleanup caches older than 5 days
if: github.event_name == 'schedule'

View file

@ -12,7 +12,7 @@ jobs:
permissions:
issues: write
steps:
- uses: actions/github-script@v6
- uses: actions/github-script@v7
with:
script: |
github.rest.issues.addLabels({

View file

@ -30,13 +30,13 @@ jobs:
outputs:
run_job: ${{ steps.check_files.outputs.run_job }}
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18
cache: "pnpm"
@ -66,7 +66,7 @@ jobs:
if: needs.check_for_update.outputs.run_job == 'true'
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
fetch-depth: 0

View file

@ -27,13 +27,13 @@ jobs:
contents: write
id-token: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18
cache: "pnpm"

View file

@ -23,10 +23,10 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v2
uses: actions/checkout@v4
- name: Checkout Main into tmp
uses: actions/checkout@v2
uses: actions/checkout@v4
with:
ref: main
path: main
@ -35,7 +35,7 @@ jobs:
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18
cache: "pnpm"
@ -44,7 +44,7 @@ jobs:
run: pnpm install
- name: Check Bundle Size
uses: actions/github-script@v6
uses: actions/github-script@v7
with:
script: |
const { default: script } = await import('${{ github.workspace }}/.github/scripts/bundle-size.mjs')

View file

@ -34,7 +34,7 @@ jobs:
- name: Extract the snapshot name from comment body
id: getSnapshotName
uses: actions/github-script@v6
uses: actions/github-script@v7
with:
script: |
const { body } = context.payload.comment;
@ -58,7 +58,7 @@ jobs:
with:
token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: ${{ steps.refs.outputs.head_ref }}
fetch-depth: 0
@ -69,7 +69,7 @@ jobs:
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18
registry-url: "https://registry.npmjs.org"
@ -124,7 +124,7 @@ jobs:
NO_COLOR: 1
- name: Pull Request Notification
uses: actions/github-script@v6
uses: actions/github-script@v7
env:
TAG: ${{ steps.getSnapshotName.outputs.result }}
STATUS_DATA: ${{ steps.changesets.outputs.status }}

View file

@ -2,7 +2,7 @@ name: Hosted tests
on:
schedule:
- cron: '0 0 * * 0'
- cron: '0 0 * * 0'
env:
ASTRO_TELEMETRY_DISABLED: true
@ -19,33 +19,30 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Check out repository
uses: actions/checkout@v3
uses: actions/checkout@v4
- name: Setup PNPM
uses: pnpm/action-setup@v2
- name: Setup Node
uses: actions/setup-node@v3
uses: actions/setup-node@v4
with:
node-version: 18
cache: "pnpm"
cache: 'pnpm'
- name: Install dependencies
run: pnpm install
- name: Build Astro
run: pnpm turbo build --filter astro --filter @astrojs/vercel
run: pnpm turbo build --filter astro --filter @astrojs/vercel
- name: Build test project
working-directory: ./packages/integrations/vercel/test/hosted/hosted-astro-project
run:
pnpm run build
run: pnpm run build
- name: Deploy to Vercel
working-directory: ./packages/integrations/vercel/test/hosted/hosted-astro-project
run:
pnpm dlx vercel --prod --prebuilt
run: pnpm dlx vercel --prod --prebuilt
- name: Test
run:
pnpm run test:e2e:hosts
run: pnpm run test:e2e:hosts

1
.gitignore vendored
View file

@ -22,6 +22,7 @@ package-lock.json
*.env
packages/astro/src/**/*.prebuilt.ts
packages/astro/src/**/*.prebuilt-dev.ts
!packages/astro/vendor/vite/dist
packages/integrations/**/.netlify/

View file

@ -6,7 +6,7 @@ import path from 'node:path';
import { fileURLToPath } from 'node:url';
import { waitUntilBusy } from 'port-authority';
import { calculateStat, astroBin } from './_util.js';
import { renderFiles } from '../make-project/render-default.js';
import { renderPages } from '../make-project/render-default.js';
const port = 4322;
@ -57,7 +57,7 @@ export async function run(projectDir, outputFile) {
async function benchmarkRenderTime() {
/** @type {Record<string, number[]>} */
const result = {};
for (const fileName of Object.keys(renderFiles)) {
for (const fileName of renderPages) {
// Render each file 100 times and push to an array
for (let i = 0; i < 100; i++) {
const pathname = '/' + fileName.slice(0, -path.extname(fileName).length);

View file

@ -3,31 +3,68 @@ import { loremIpsumHtml, loremIpsumMd } from './_util.js';
// Map of files to be generated and tested for rendering.
// Ideally each content should be similar for comparison.
export const renderFiles = {
'astro.astro': `\
const renderFiles = {
'components/ListItem.astro': `\
---
const { className, item, attrs } = Astro.props;
const nested = item !== 0;
---
<li class={className}>
<a
href={item}
aria-current={item === 0}
class:list={[{ large: !nested }, className]}
{...attrs}
>
<span>{item}</span>
</a>
</li>
`,
'components/Sublist.astro': `\
---
import ListItem from '../components/ListItem.astro';
const { items } = Astro.props;
const className = "text-red-500";
const style = { color: "red" };
---
<ul style={style}>
{items.map((item) => (
<ListItem className={className} item={item} attrs={{}} />
))}
</ul>
`,
'pages/astro.astro': `\
---
const className = "text-red-500";
const style = { color: "red" };
const items = Array.from({ length: 1000 }, (_, i) => i);
const items = Array.from({ length: 10000 }, (_, i) => ({i}));
---
<html>
<head>
<title>My Site</title>
</head>
<body>
<h1 class={className + ' text-lg'}>List</h1>
<ul style={style}>
{items.map((item) => (
<li class={className}>{item}</li>
))}
</ul>
<ul style={style}>
{items.map((item) => (
<li class={className}>
<a
href={item.i}
aria-current={item.i === 0}
class:list={[{ large: item.i === 0 }, className]}
{...({})}
>
<span>{item.i}</span>
</a>
</li>
))}
</ul>
${Array.from({ length: 1000 })
.map(() => `<p>${loremIpsumHtml}</p>`)
.join('\n')}
</body>
</html>`,
'md.md': `\
'pages/md.md': `\
# List
${Array.from({ length: 1000 }, (_, i) => i)
@ -38,7 +75,7 @@ ${Array.from({ length: 1000 })
.map(() => loremIpsumMd)
.join('\n\n')}
`,
'mdx.mdx': `\
'pages/mdx.mdx': `\
export const className = "text-red-500";
export const style = { color: "red" };
export const items = Array.from({ length: 1000 }, (_, i) => i);
@ -57,16 +94,24 @@ ${Array.from({ length: 1000 })
`,
};
export const renderPages = [];
for (const file of Object.keys(renderFiles)) {
if (file.startsWith('pages/')) {
renderPages.push(file.replace('pages/', ''));
}
}
/**
* @param {URL} projectDir
*/
export async function run(projectDir) {
await fs.rm(projectDir, { recursive: true, force: true });
await fs.mkdir(new URL('./src/pages', projectDir), { recursive: true });
await fs.mkdir(new URL('./src/components', projectDir), { recursive: true });
await Promise.all(
Object.entries(renderFiles).map(([name, content]) => {
return fs.writeFile(new URL(`./src/pages/${name}`, projectDir), content, 'utf-8');
return fs.writeFile(new URL(`./src/${name}`, projectDir), content, 'utf-8');
})
);

View file

@ -11,6 +11,6 @@
"astro": "astro"
},
"dependencies": {
"astro": "^4.2.4"
"astro": "^4.4.0"
}
}

View file

@ -11,9 +11,9 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "^2.1.0",
"@astrojs/rss": "^4.0.3",
"@astrojs/mdx": "^2.1.1",
"@astrojs/rss": "^4.0.5",
"@astrojs/sitemap": "^3.0.5",
"astro": "^4.2.4"
"astro": "^4.4.0"
}
}

View file

@ -6,7 +6,8 @@ type Props = HTMLAttributes<'a'>;
const { href, class: className, ...props } = Astro.props;
const { pathname } = Astro.url;
const isActive = href === pathname || href === pathname.replace(/\/$/, '');
const subpath = pathname.match(/[^\/]+/g);
const isActive = href === pathname || href === '/' + subpath?.[0];
---
<a href={href} class:list={[className, { active: isActive }]} {...props}>

View file

@ -11,7 +11,7 @@ import { SITE_TITLE, SITE_DESCRIPTION } from '../consts';
<BaseHead title={SITE_TITLE} description={SITE_DESCRIPTION} />
</head>
<body>
<Header title={SITE_TITLE} />
<Header />
<main>
<h1>🧑‍🚀 Hello, Astronaut!</h1>
<p>

View file

@ -15,7 +15,7 @@
],
"scripts": {},
"devDependencies": {
"astro": "^4.2.4"
"astro": "^4.4.0"
},
"peerDependencies": {
"astro": "^4.0.0"

View file

@ -11,9 +11,9 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/alpinejs": "^0.3.2",
"@astrojs/alpinejs": "^0.4.0",
"@types/alpinejs": "^3.13.5",
"alpinejs": "^3.13.3",
"astro": "^4.2.4"
"astro": "^4.4.0"
}
}

View file

@ -13,7 +13,7 @@
"dependencies": {
"@astrojs/lit": "^4.0.1",
"@webcomponents/template-shadowroot": "^0.2.1",
"astro": "^4.2.4",
"lit": "^2.8.0"
"astro": "^4.4.0",
"lit": "^3.1.2"
}
}

View file

@ -12,11 +12,11 @@
},
"dependencies": {
"@astrojs/preact": "^3.1.0",
"@astrojs/react": "^3.0.9",
"@astrojs/react": "^3.0.10",
"@astrojs/solid-js": "^4.0.1",
"@astrojs/svelte": "^5.0.3",
"@astrojs/vue": "^4.0.8",
"astro": "^4.2.4",
"astro": "^4.4.0",
"preact": "^10.19.2",
"react": "^18.2.0",
"react-dom": "^18.2.0",

View file

@ -13,7 +13,7 @@
"dependencies": {
"@astrojs/preact": "^3.1.0",
"@preact/signals": "^1.2.1",
"astro": "^4.2.4",
"astro": "^4.4.0",
"preact": "^10.19.2"
}
}

View file

@ -11,10 +11,10 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/react": "^3.0.9",
"@astrojs/react": "^3.0.10",
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"astro": "^4.2.4",
"astro": "^4.4.0",
"react": "^18.2.0",
"react-dom": "^18.2.0"
}

View file

@ -12,7 +12,7 @@
},
"dependencies": {
"@astrojs/solid-js": "^4.0.1",
"astro": "^4.2.4",
"astro": "^4.4.0",
"solid-js": "^1.8.5"
}
}

View file

@ -12,7 +12,7 @@
},
"dependencies": {
"@astrojs/svelte": "^5.0.3",
"astro": "^4.2.4",
"astro": "^4.4.0",
"svelte": "^4.2.5"
}
}

View file

@ -12,7 +12,7 @@
},
"dependencies": {
"@astrojs/vue": "^4.0.8",
"astro": "^4.2.4",
"astro": "^4.4.0",
"vue": "^3.3.8"
}
}

View file

@ -11,7 +11,7 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/node": "^8.0.0",
"astro": "^4.2.4"
"@astrojs/node": "^8.2.0",
"astro": "^4.4.0"
}
}

View file

@ -15,7 +15,7 @@
],
"scripts": {},
"devDependencies": {
"astro": "^4.2.4"
"astro": "^4.4.0"
},
"peerDependencies": {
"astro": "^4.0.0"

View file

@ -12,8 +12,8 @@
"server": "node dist/server/entry.mjs"
},
"dependencies": {
"@astrojs/node": "^8.0.0",
"astro": "^4.2.4",
"@astrojs/node": "^8.2.0",
"astro": "^4.4.0",
"html-minifier": "^4.0.0"
},
"devDependencies": {

View file

@ -11,6 +11,6 @@
"astro": "astro"
},
"dependencies": {
"astro": "^4.2.4"
"astro": "^4.4.0"
}
}

View file

@ -11,6 +11,6 @@
"astro": "astro"
},
"dependencies": {
"astro": "^4.2.4"
"astro": "^4.4.0"
}
}

View file

@ -11,6 +11,6 @@
"astro": "astro"
},
"dependencies": {
"astro": "^4.2.4"
"astro": "^4.4.0"
}
}

View file

@ -12,9 +12,9 @@
"server": "node dist/server/entry.mjs"
},
"dependencies": {
"@astrojs/node": "^8.0.0",
"@astrojs/node": "^8.2.0",
"@astrojs/svelte": "^5.0.3",
"astro": "^4.2.4",
"astro": "^4.4.0",
"svelte": "^4.2.5"
}
}

View file

@ -10,7 +10,7 @@
"astro": "astro"
},
"dependencies": {
"astro": "^4.2.4",
"astro": "^4.4.0",
"sass": "^1.69.5",
"sharp": "^0.32.6"
}

View file

@ -11,7 +11,7 @@
},
"devDependencies": {
"@astrojs/tailwind": "^5.1.0",
"@astrojs/node": "^8.0.0",
"astro": "^4.2.4"
"@astrojs/node": "^8.2.0",
"astro": "^4.4.0"
}
}

View file

@ -1,7 +1,5 @@
<nav class="nav border-b border-gray-800 sticky top-0 z-30 bg-gray-900">
<div
class="container mx-auto px-4 flex flex-col md:flex-row items-center justify-between px-4 py-6"
>
<div class="container mx-auto flex flex-col md:flex-row items-center justify-between px-4 py-6">
<ul class="flex flex-col md:flex-row items-center">
<li>
<a href="/" class="flex items-center font-bold text-xl">

View file

@ -11,7 +11,7 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/markdoc": "^0.8.3",
"astro": "^4.2.4"
"@astrojs/markdoc": "^0.9.0",
"astro": "^4.4.0"
}
}

View file

@ -1,6 +1,6 @@
---
// Inspired by the `Aside` component from docs.astro.build
// https://github.com/withastro/docs/blob/main/src/components/Aside.astro
// https://github.com/withastro/starlight/blob/main/packages/starlight/integrations/asides.ts
interface Props {
type?: 'note' | 'tip' | 'caution' | 'danger';

View file

@ -11,8 +11,8 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/markdown-remark": "^4.2.0",
"astro": "^4.2.4",
"@astrojs/markdown-remark": "^4.2.1",
"astro": "^4.4.0",
"hast-util-select": "^6.0.2",
"rehype-autolink-headings": "^7.1.0",
"rehype-slug": "^6.0.0",

View file

@ -11,6 +11,6 @@
"astro": "astro"
},
"dependencies": {
"astro": "^4.2.4"
"astro": "^4.4.0"
}
}

View file

@ -11,9 +11,9 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "^2.1.0",
"@astrojs/mdx": "^2.1.1",
"@astrojs/preact": "^3.1.0",
"astro": "^4.2.4",
"astro": "^4.4.0",
"preact": "^10.19.2"
}
}

View file

@ -13,7 +13,7 @@
"dependencies": {
"@astrojs/preact": "^3.1.0",
"@nanostores/preact": "^0.5.0",
"astro": "^4.2.4",
"astro": "^4.4.0",
"nanostores": "^0.9.5",
"preact": "^10.19.2"
}

View file

@ -11,10 +11,10 @@
"astro": "astro"
},
"dependencies": {
"@astrojs/mdx": "^2.1.0",
"@astrojs/mdx": "^2.1.1",
"@astrojs/tailwind": "^5.1.0",
"@types/canvas-confetti": "^1.6.3",
"astro": "^4.2.4",
"astro": "^4.4.0",
"autoprefixer": "^10.4.15",
"canvas-confetti": "^1.9.1",
"postcss": "^8.4.28",

View file

@ -12,7 +12,7 @@
"test": "vitest"
},
"dependencies": {
"astro": "^4.2.4",
"vitest": "^1.2.1"
"astro": "^4.4.0",
"vitest": "^1.2.2"
}
}

View file

@ -59,12 +59,13 @@
"eslint-config-prettier": "^9.0.0",
"eslint-plugin-no-only-tests": "^3.1.0",
"eslint-plugin-prettier": "^5.0.0",
"eslint-plugin-regexp": "^2.2.0",
"globby": "^14.0.0",
"only-allow": "^1.1.1",
"organize-imports-cli": "^0.10.0",
"prettier": "^3.1.0",
"prettier-plugin-astro": "^0.12.2",
"tiny-glob": "^0.2.9",
"globby": "^14.0.0",
"turbo": "^1.10.12",
"typescript": "~5.2.2"
},

View file

@ -16,6 +16,7 @@ export function addAstro(Prism: typeof import('prismjs')) {
let script = Prism.util.clone(Prism.languages[scriptLang]);
// eslint-disable-next-line regexp/no-useless-assertions
let space = /(?:\s|\/\/.*(?!.)|\/\*(?:[^*]|\*(?!\/))\*\/)/.source;
let braces = /(?:\{(?:\{(?:\{[^{}]*\}|[^{}])*\}|[^{}])*\})/.source;
let spread = /(?:\{<S>*\.{3}(?:[^{}]|<BRACES>)*\})/.source;
@ -39,13 +40,13 @@ export function addAstro(Prism: typeof import('prismjs')) {
Prism.languages.astro = Prism.languages.extend('markup', script);
(Prism.languages.astro as any).tag.pattern = re(
/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/
/<\/?(?:[\w.:-]+(?:<S>+(?:[\w.:$-]+(?:=(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s{'"/>=]+|<BRACES>))?|<SPREAD>))*<S>*\/?)?>/
.source
);
(Prism.languages.astro as any).tag.inside['tag'].pattern = /^<\/?[^\s>\/]*/i;
(Prism.languages.astro as any).tag.inside['tag'].pattern = /^<\/?[^\s>/]*/;
(Prism.languages.astro as any).tag.inside['attr-value'].pattern =
/=(?!\{)(?:"(?:\\[^]|[^\\"])*"|'(?:\\[^]|[^\\'])*'|[^\s'">]+)/i;
/=(?!\{)(?:"(?:\\[\s\S]|[^\\"])*"|'(?:\\[\s\S]|[^\\'])*'|[^\s'">]+)/;
(Prism.languages.astro as any).tag.inside['tag'].inside['class-name'] =
/^[A-Z]\w*(?:\.[A-Z]\w*)*$/;
(Prism.languages.astro as any).tag.inside['comment'] = script['comment'];
@ -71,7 +72,7 @@ export function addAstro(Prism: typeof import('prismjs')) {
pattern: re(/=<BRACES>/.source),
inside: {
'script-punctuation': {
pattern: /^=(?={)/,
pattern: /^=(?=\{)/,
alias: 'punctuation',
},
rest: Prism.languages.astro,

View file

@ -1,5 +1,17 @@
# @astrojs/rss
## 4.0.5
### Patch Changes
- [#9967](https://github.com/withastro/astro/pull/9967) [`8b8f26fdf2af2a769f4846bdaaf4cf6b30f9e37c`](https://github.com/withastro/astro/commit/8b8f26fdf2af2a769f4846bdaaf4cf6b30f9e37c) Thanks [@madcampos](https://github.com/madcampos)! - Allows `enclosure' to have a length of 0
## 4.0.4
### Patch Changes
- [#9797](https://github.com/withastro/astro/pull/9797) [`457e8b6422704ba23347c766a8bb9c101c2aba0b`](https://github.com/withastro/astro/commit/457e8b6422704ba23347c766a8bb9c101c2aba0b) Thanks [@wkillerud](https://github.com/wkillerud)! - Restores `rssSchema` to a zod object
## 4.0.3
### Patch Changes

View file

@ -1,7 +1,7 @@
{
"name": "@astrojs/rss",
"description": "Add RSS feeds to your Astro projects",
"version": "4.0.3",
"version": "4.0.5",
"type": "module",
"types": "./dist/index.d.ts",
"author": "withastro",
@ -24,18 +24,13 @@
"build": "astro-scripts build \"src/**/*.ts\" && tsc",
"build:ci": "astro-scripts build \"src/**/*.ts\"",
"dev": "astro-scripts dev \"src/**/*.ts\"",
"test": "mocha --exit --timeout 20000"
"test": "astro-scripts test \"test/**/*.test.js\""
},
"devDependencies": {
"@types/chai": "^4.3.10",
"@types/chai-as-promised": "^7.1.8",
"@types/mocha": "^10.0.4",
"@types/xml2js": "^0.4.14",
"astro": "workspace:*",
"astro-scripts": "workspace:*",
"chai": "^4.3.7",
"chai-as-promised": "^7.1.1",
"chai-xml": "^0.4.1",
"mocha": "^10.2.0"
"xml2js": "0.6.2"
},
"dependencies": {
"fast-xml-parser": "^4.2.7",

View file

@ -16,7 +16,7 @@ export const rssSchema = z.object({
enclosure: z
.object({
url: z.string(),
length: z.number().positive().int().finite(),
length: z.number().nonnegative().int().finite(),
type: z.string(),
})
.optional(),

View file

@ -10,10 +10,10 @@ export function createCanonicalURL(
let pathname = url.replace(/\/index.html$/, ''); // index.html is not canonical
if (trailingSlash === false) {
// remove the trailing slash
pathname = pathname.replace(/(\/+)?$/, '');
pathname = pathname.replace(/\/*$/, '');
} else if (!getUrlExtension(url)) {
// add trailing slash if theres no extension or `trailingSlash` is true
pathname = pathname.replace(/(\/+)?$/, '/');
pathname = pathname.replace(/\/*$/, '/');
}
pathname = pathname.replace(/\/+/g, '/'); // remove duplicate slashes (URL() wont)

View file

@ -1,10 +1,9 @@
import chai from 'chai';
import chaiPromises from 'chai-as-promised';
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import { phpFeedItem, web1FeedItem } from './test-utils.js';
import { pagesGlobToRssItems } from '../dist/index.js';
chai.use(chaiPromises);
describe('pagesGlobToRssItems', () => {
it('should generate on valid result', async () => {
const globResult = {
@ -33,8 +32,7 @@ describe('pagesGlobToRssItems', () => {
};
const items = await pagesGlobToRssItems(globResult);
chai.expect(items.sort((a, b) => a.pubDate - b.pubDate)).to.deep.equal([
const expected = [
{
title: phpFeedItem.title,
link: phpFeedItem.link,
@ -47,7 +45,12 @@ describe('pagesGlobToRssItems', () => {
pubDate: new Date(web1FeedItem.pubDate),
description: web1FeedItem.description,
},
]);
];
assert.deepEqual(
items.sort((a, b) => a.pubDate - b.pubDate),
expected
);
});
it('should fail on missing "url"', () => {
@ -63,7 +66,7 @@ describe('pagesGlobToRssItems', () => {
})
),
};
return chai.expect(pagesGlobToRssItems(globResult)).to.be.rejected;
return assert.rejects(pagesGlobToRssItems(globResult));
});
it('should fail on missing "title" key and "description"', () => {
@ -80,7 +83,7 @@ describe('pagesGlobToRssItems', () => {
})
),
};
return chai.expect(pagesGlobToRssItems(globResult)).to.be.rejected;
return assert.rejects(pagesGlobToRssItems(globResult));
});
it('should not fail on missing "title" key if "description" is present', () => {
@ -97,7 +100,7 @@ describe('pagesGlobToRssItems', () => {
})
),
};
return chai.expect(pagesGlobToRssItems(globResult)).to.not.be.rejected;
return assert.doesNotReject(pagesGlobToRssItems(globResult));
});
it('should not fail on missing "description" key if "title" is present', () => {
@ -114,6 +117,6 @@ describe('pagesGlobToRssItems', () => {
})
),
};
return chai.expect(pagesGlobToRssItems(globResult)).to.not.be.rejected;
return assert.doesNotReject(pagesGlobToRssItems(globResult));
});
});

View file

@ -1,6 +1,6 @@
import chai from 'chai';
import chaiPromises from 'chai-as-promised';
import chaiXml from 'chai-xml';
import assert from 'node:assert/strict';
import { describe, it } from 'node:test';
import { z } from 'astro/zod';
import rss, { getRssString } from '../dist/index.js';
import { rssSchema } from '../dist/schema.js';
@ -14,11 +14,9 @@ import {
web1FeedItem,
web1FeedItemWithAllData,
web1FeedItemWithContent,
parseXmlString,
} from './test-utils.js';
chai.use(chaiPromises);
chai.use(chaiXml);
// note: I spent 30 minutes looking for a nice node-based snapshot tool
// ...and I gave up. Enjoy big strings!
// prettier-ignore
@ -34,6 +32,15 @@ const validXmlWithStylesheet = `<?xml version="1.0" encoding="UTF-8"?><?xml-styl
// prettier-ignore
const validXmlWithXSLStylesheet = `<?xml version="1.0" encoding="UTF-8"?><?xml-stylesheet href="/feedstylesheet.xsl" type="text/xsl"?><rss version="2.0"><channel><title><![CDATA[${title}]]></title><description><![CDATA[${description}]]></description><link>${site}/</link></channel></rss>`;
function assertXmlDeepEqual(a, b) {
const parsedA = parseXmlString(a);
const parsedB = parseXmlString(b);
assert.equal(parsedA.err, null);
assert.equal(parsedB.err, null);
assert.deepEqual(parsedA.result, parsedB.result);
}
describe('rss', () => {
it('should return a response', async () => {
const response = await rss({
@ -44,10 +51,14 @@ describe('rss', () => {
});
const str = await response.text();
chai.expect(str).xml.to.equal(validXmlResult);
// NOTE: Chai used the below parser to perform the tests, but I have omitted it for now.
// parser = new xml2js.Parser({ trim: flag(this, 'deep') });
assertXmlDeepEqual(str, validXmlResult);
const contentType = response.headers.get('Content-Type');
chai.expect(contentType).to.equal('application/xml');
assert.equal(contentType, 'application/xml');
});
it('should be the same string as getRssString', async () => {
@ -62,7 +73,7 @@ describe('rss', () => {
const str1 = await response.text();
const str2 = await getRssString(options);
chai.expect(str1).to.equal(str2);
assert.equal(str1, str2);
});
});
@ -75,7 +86,7 @@ describe('getRssString', () => {
site,
});
chai.expect(str).xml.to.equal(validXmlResult);
assertXmlDeepEqual(str, validXmlResult);
});
it('should generate on valid RSSFeedItem array with HTML content included', async () => {
@ -86,7 +97,7 @@ describe('getRssString', () => {
site,
});
chai.expect(str).xml.to.equal(validXmlWithContentResult);
assertXmlDeepEqual(str, validXmlWithContentResult);
});
it('should generate on valid RSSFeedItem array with all RSS content included', async () => {
@ -97,7 +108,7 @@ describe('getRssString', () => {
site,
});
chai.expect(str).xml.to.equal(validXmlResultWithAllData);
assertXmlDeepEqual(str, validXmlResultWithAllData);
});
it('should generate on valid RSSFeedItem array with custom data included', async () => {
@ -111,7 +122,7 @@ describe('getRssString', () => {
site,
});
chai.expect(str).xml.to.equal(validXmlWithCustomDataResult);
assertXmlDeepEqual(str, validXmlWithCustomDataResult);
});
it('should include xml-stylesheet instruction when stylesheet is defined', async () => {
@ -123,7 +134,7 @@ describe('getRssString', () => {
stylesheet: '/feedstylesheet.css',
});
chai.expect(str).xml.to.equal(validXmlWithStylesheet);
assertXmlDeepEqual(str, validXmlWithStylesheet);
});
it('should include xml-stylesheet instruction with xsl type when stylesheet is set to xsl file', async () => {
@ -135,7 +146,7 @@ describe('getRssString', () => {
stylesheet: '/feedstylesheet.xsl',
});
chai.expect(str).xml.to.equal(validXmlWithXSLStylesheet);
assertXmlDeepEqual(str, validXmlWithXSLStylesheet);
});
it('should preserve self-closing tags on `customData`', async () => {
@ -152,7 +163,7 @@ describe('getRssString', () => {
customData,
});
chai.expect(str).to.contain(customData);
assert.ok(str.includes(customData));
});
it('should not append trailing slash to URLs with the given option', async () => {
@ -164,8 +175,8 @@ describe('getRssString', () => {
trailingSlash: false,
});
chai.expect(str).xml.to.contain('https://example.com/<');
chai.expect(str).xml.to.contain('https://example.com/php<');
assert.ok(str.includes('https://example.com/<'));
assert.ok(str.includes('https://example.com/php<'));
});
it('Deprecated import.meta.glob mapping still works', async () => {
@ -201,7 +212,7 @@ describe('getRssString', () => {
site,
});
chai.expect(str).xml.to.equal(validXmlResult);
assertXmlDeepEqual(str, validXmlResult);
});
it('should fail when an invalid date string is provided', async () => {
@ -212,8 +223,8 @@ describe('getRssString', () => {
link: phpFeedItem.link,
});
chai.expect(res.success).to.be.false;
chai.expect(res.error.issues[0].path[0]).to.equal('pubDate');
assert.equal(res.success, false);
assert.equal(res.error.issues[0].path[0], 'pubDate');
});
it('should be extendable', () => {
@ -225,6 +236,34 @@ describe('getRssString', () => {
} catch (e) {
error = e.message;
}
chai.expect(error).to.be.null;
assert.equal(error, null);
});
it('should not fail when an enclosure has a length of 0', async () => {
let error = null;
try {
await getRssString({
title,
description,
items: [
{
title: 'Title',
pubDate: new Date().toISOString(),
description: 'Description',
link: '/link',
enclosure: {
url: '/enclosure',
length: 0,
type: 'audio/mpeg',
},
},
],
site,
});
} catch (e) {
error = e.message;
}
assert.equal(error, null);
});
});

View file

@ -1,3 +1,5 @@
import xml2js from 'xml2js';
export const title = 'My RSS feed';
export const description = 'This sure is a nice RSS feed';
export const site = 'https://example.com';
@ -45,3 +47,20 @@ export const web1FeedItemWithAllData = {
type: 'audio/mpeg',
},
};
const parser = new xml2js.Parser({ trim: true });
/**
*
* Utility function to parse an XML string into an object using `xml2js`.
*
* @param {string} xmlString - Stringified XML to parse.
* @return {{ err: Error, result: any }} Represents an option containing the parsed XML string or an Error.
*/
export function parseXmlString(xmlString) {
let res;
parser.parseString(xmlString, (err, result) => {
res = { err, result };
});
return res;
}

View file

@ -1,5 +1,320 @@
# astro
## 4.4.0
### Minor Changes
- [#9614](https://github.com/withastro/astro/pull/9614) [`d469bebd7b45b060dc41d82ab1cf18ee6de7e051`](https://github.com/withastro/astro/commit/d469bebd7b45b060dc41d82ab1cf18ee6de7e051) Thanks [@matthewp](https://github.com/matthewp)! - Improves Node.js streaming performance.
This uses an `AsyncIterable` instead of a `ReadableStream` to do streaming in Node.js. This is a non-standard enhancement by Node, which is done only in that environment.
- [#10001](https://github.com/withastro/astro/pull/10001) [`748b2e87cd44d8bcc1ab9d7e504703057e2000cd`](https://github.com/withastro/astro/commit/748b2e87cd44d8bcc1ab9d7e504703057e2000cd) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Removes content collection warning when a configured collection does not have a matching directory name. This should resolve `i18n` collection warnings for Starlight users.
This also ensures configured collection names are always included in `getCollection()` and `getEntry()` types even when a matching directory is absent. We hope this allows users to discover typos during development by surfacing type information.
- [#10074](https://github.com/withastro/astro/pull/10074) [`7443929381b47db0639c49a4d32aec4177bd9102`](https://github.com/withastro/astro/commit/7443929381b47db0639c49a4d32aec4177bd9102) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Add a UI showing the list of found problems when using the audit app in the dev toolbar
- [#10099](https://github.com/withastro/astro/pull/10099) [`b340f8fe3aaa81e38c4f1aa41498b159dc733d86`](https://github.com/withastro/astro/commit/b340f8fe3aaa81e38c4f1aa41498b159dc733d86) Thanks [@martrapp](https://github.com/martrapp)! - Fixes a regression where view transition names containing special characters such as spaces or punctuation stopped working.
Regular use naming your transitions with `transition: name` is unaffected.
However, this fix may result in breaking changes if your project relies on the particular character encoding strategy Astro uses to translate `transition:name` directives into values of the underlying CSS `view-transition-name` property. For example, `Welcome to Astro` is now encoded as `Welcome_20to_20Astro_2e`.
This mainly affects spaces and punctuation marks but no Unicode characters with codes >= 128.
- [#9976](https://github.com/withastro/astro/pull/9976) [`91f75afbc642b6e73dd4ec18a1fe2c3128c68132`](https://github.com/withastro/astro/commit/91f75afbc642b6e73dd4ec18a1fe2c3128c68132) Thanks [@OliverSpeir](https://github.com/OliverSpeir)! - Adds a new optional `astro:assets` image attribute `inferSize` for use with remote images.
Remote images can now have their dimensions inferred just like local images. Setting `inferSize` to `true` allows you to use `getImage()` and the `<Image />` and `<Picture />` components without setting the `width` and `height` properties.
```astro
---
import { Image, Picture, getImage } from 'astro:assets';
const myPic = await getImage({ src: 'https://example.com/example.png', inferSize: true });
---
<Image src="https://example.com/example.png" inferSize alt="" />
<Picture src="https://example.com/example.png" inferSize alt="" />
```
Read more about [using `inferSize` with remote images](https://docs.astro.build/en/guides/images/#infersize) in our documentation.
- [#10015](https://github.com/withastro/astro/pull/10015) [`6884b103c8314a43e926c6acdf947cbf812a21f4`](https://github.com/withastro/astro/commit/6884b103c8314a43e926c6acdf947cbf812a21f4) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Adds initial support for performance audits to the dev toolbar
### Patch Changes
- [#10116](https://github.com/withastro/astro/pull/10116) [`4bcc249a9f34aaac59658ca626c828bd6dbb8046`](https://github.com/withastro/astro/commit/4bcc249a9f34aaac59658ca626c828bd6dbb8046) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixes an issue where the dev server froze when typescript aliases were used.
- [#10096](https://github.com/withastro/astro/pull/10096) [`227cd83a51bbd451dc223fd16f4cf1b87b8e44f8`](https://github.com/withastro/astro/commit/227cd83a51bbd451dc223fd16f4cf1b87b8e44f8) Thanks [@Fryuni](https://github.com/Fryuni)! - Fixes regression on routing priority for multi-layer index pages
The sorting algorithm positions more specific routes before less specific routes, and considers index pages to be more specific than a dynamic route with a rest parameter inside of it.
This means that `/blog` is considered more specific than `/blog/[...slug]`.
But this special case was being applied incorrectly to indexes, which could cause a problem in scenarios like the following:
- `/`
- `/blog`
- `/blog/[...slug]`
The algorithm would make the following comparisons:
- `/` is more specific than `/blog` (incorrect)
- `/blog/[...slug]` is more specific than `/` (correct)
- `/blog` is more specific than `/blog/[...slug]` (correct)
Although the incorrect first comparison is not a problem by itself, it could cause the algorithm to make the wrong decision.
Depending on the other routes in the project, the sorting could perform just the last two comparisons and by transitivity infer the inverse of the third (`/blog/[...slug` > `/` > `/blog`), which is incorrect.
Now the algorithm doesn't have a special case for index pages and instead does the comparison soleley for rest parameter segments and their immediate parents, which is consistent with the transitivity property.
- [#10120](https://github.com/withastro/astro/pull/10120) [`787e6f52470cf07fb50c865948b2bc8fe45a6d31`](https://github.com/withastro/astro/commit/787e6f52470cf07fb50c865948b2bc8fe45a6d31) Thanks [@bluwy](https://github.com/bluwy)! - Updates and supports Vite 5.1
- [#10096](https://github.com/withastro/astro/pull/10096) [`227cd83a51bbd451dc223fd16f4cf1b87b8e44f8`](https://github.com/withastro/astro/commit/227cd83a51bbd451dc223fd16f4cf1b87b8e44f8) Thanks [@Fryuni](https://github.com/Fryuni)! - Fixes edge case on i18n fallback routes
Previously index routes deeply nested in the default locale, like `/some/nested/index.astro` could be mistaked as the root index for the default locale, resulting in an incorrect redirect on `/`.
- [#10112](https://github.com/withastro/astro/pull/10112) [`476b79a61165d0aac5e98459a4ec90762050a14b`](https://github.com/withastro/astro/commit/476b79a61165d0aac5e98459a4ec90762050a14b) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Renames the home Astro Devoolbar App to `astro:home`
- [#10117](https://github.com/withastro/astro/pull/10117) [`51b6ff7403c1223b1c399e88373075972c82c24c`](https://github.com/withastro/astro/commit/51b6ff7403c1223b1c399e88373075972c82c24c) Thanks [@hippotastic](https://github.com/hippotastic)! - Fixes an issue where `create astro`, `astro add` and `@astrojs/upgrade` would fail due to unexpected package manager CLI output.
## 4.3.7
### Patch Changes
- [#9857](https://github.com/withastro/astro/pull/9857) [`73bd900754365b006ee730df9f379ba924e5b3fa`](https://github.com/withastro/astro/commit/73bd900754365b006ee730df9f379ba924e5b3fa) Thanks [@iamyunsin](https://github.com/iamyunsin)! - Fixes false positives in the dev overlay audit when multiple `role` values exist.
- [#10075](https://github.com/withastro/astro/pull/10075) [`71273edbb429b5afdba6f8ee14681b66e4c09ecc`](https://github.com/withastro/astro/commit/71273edbb429b5afdba6f8ee14681b66e4c09ecc) Thanks [@lilnasy](https://github.com/lilnasy)! - Improves error messages for island hydration.
- [#10072](https://github.com/withastro/astro/pull/10072) [`8106178043050d142bf385bed2990730518f28e2`](https://github.com/withastro/astro/commit/8106178043050d142bf385bed2990730518f28e2) Thanks [@lilnasy](https://github.com/lilnasy)! - Clarifies error messages in endpoint routing.
- [#9971](https://github.com/withastro/astro/pull/9971) [`d9266c4467ca0faa1213c1a5995164e5655ab375`](https://github.com/withastro/astro/commit/d9266c4467ca0faa1213c1a5995164e5655ab375) Thanks [@mingjunlu](https://github.com/mingjunlu)! - Fixes an issue where ReadableStream wasn't canceled in dev mode
## 4.3.6
### Patch Changes
- [#10063](https://github.com/withastro/astro/pull/10063) [`dac759798c111494e76affd2c2504d63944871fe`](https://github.com/withastro/astro/commit/dac759798c111494e76affd2c2504d63944871fe) Thanks [@marwan-mohamed12](https://github.com/marwan-mohamed12)! - Moves `shikiji-core` from `devDependencies` to `dependencies` to prevent type errors
- [#10067](https://github.com/withastro/astro/pull/10067) [`989ea63bb2a5a670021541198aa70b8dc7c4bd2f`](https://github.com/withastro/astro/commit/989ea63bb2a5a670021541198aa70b8dc7c4bd2f) Thanks [@ematipico](https://github.com/ematipico)! - Fixes a regression in the `astro:i18n` module, where the functions `getAbsoluteLocaleUrl` and `getAbsoluteLocaleUrlList` returned a URL with double slash with a certain combination of options.
- [#10060](https://github.com/withastro/astro/pull/10060) [`1810309e65c596266355c3b7bb36cdac70f3305e`](https://github.com/withastro/astro/commit/1810309e65c596266355c3b7bb36cdac70f3305e) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixes an issue where custom client directives added by integrations broke builds with a custom root.
- [#9991](https://github.com/withastro/astro/pull/9991) [`8fb67c81bb84530b39df4a1449c0862def0854af`](https://github.com/withastro/astro/commit/8fb67c81bb84530b39df4a1449c0862def0854af) Thanks [@ktym4a](https://github.com/ktym4a)! - Increases compatibility with standard browser behavior by changing where view transitions occur on browser back navigation.
## 4.3.5
### Patch Changes
- [#10022](https://github.com/withastro/astro/pull/10022) [`3fc76efb2a8faa47edf67562a1f0c84a19be1b33`](https://github.com/withastro/astro/commit/3fc76efb2a8faa47edf67562a1f0c84a19be1b33) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixes a regression where types for the `astro:content` module did not include required exports, leading to typescript errors.
- [#10016](https://github.com/withastro/astro/pull/10016) [`037e4f12dd2f460d66f72c9f2d992b95e74d2da9`](https://github.com/withastro/astro/commit/037e4f12dd2f460d66f72c9f2d992b95e74d2da9) Thanks [@ematipico](https://github.com/ematipico)! - Fixes a bug where routes with a name that start with the name of the `i18n.defaultLocale` were incorrectly returning a 404 response.
## 4.3.4
### Patch Changes
- [#10013](https://github.com/withastro/astro/pull/10013) [`e6b5306a7de779ce495d0ff076d302de0aa57eaf`](https://github.com/withastro/astro/commit/e6b5306a7de779ce495d0ff076d302de0aa57eaf) Thanks [@delucis](https://github.com/delucis)! - Fixes a regression in content collection types
- [#10003](https://github.com/withastro/astro/pull/10003) [`ce4283331f18c6178654dd705e3cf02efeef004a`](https://github.com/withastro/astro/commit/ce4283331f18c6178654dd705e3cf02efeef004a) Thanks [@bholmesdev](https://github.com/bholmesdev)! - Adds support for `.strict()` on content collection schemas when a custom `slug` is present.
## 4.3.3
### Patch Changes
- [#9998](https://github.com/withastro/astro/pull/9998) [`18ac0940ea1b49b6b0ddd9be1f96aef416e2d7ee`](https://github.com/withastro/astro/commit/18ac0940ea1b49b6b0ddd9be1f96aef416e2d7ee) Thanks [@ematipico](https://github.com/ematipico)! - Fixes a bug in `Astro.currentLocale` that wasn't returning the correct locale when a locale is configured via `path`
- [#9998](https://github.com/withastro/astro/pull/9998) [`18ac0940ea1b49b6b0ddd9be1f96aef416e2d7ee`](https://github.com/withastro/astro/commit/18ac0940ea1b49b6b0ddd9be1f96aef416e2d7ee) Thanks [@ematipico](https://github.com/ematipico)! - Fixes a regression in `Astro.currentLocale` where it stopped working properly with dynamic routes
- [#9956](https://github.com/withastro/astro/pull/9956) [`81acac24a3cac5a9143155c1d9f838ea84a70421`](https://github.com/withastro/astro/commit/81acac24a3cac5a9143155c1d9f838ea84a70421) Thanks [@matthewp](https://github.com/matthewp)! - Fixes HMR for MDX dependencies in Content Collections
- [#9999](https://github.com/withastro/astro/pull/9999) [`c53a31321a935e4be04809046d7e0ba3cc41b272`](https://github.com/withastro/astro/commit/c53a31321a935e4be04809046d7e0ba3cc41b272) Thanks [@MoustaphaDev](https://github.com/MoustaphaDev)! - Rollbacks the feature which allowed to dynamically generate slots with variable slot names due to unexpected regressions.
- [#9906](https://github.com/withastro/astro/pull/9906) [`3c0876cbed5033e6b5b42cc2b9d8b393d7e5a55e`](https://github.com/withastro/astro/commit/3c0876cbed5033e6b5b42cc2b9d8b393d7e5a55e) Thanks [@florian-lefebvre](https://github.com/florian-lefebvre)! - Improves the types for the `astro:content` module by making low fidelity types available before running `astro sync`
## 4.3.2
### Patch Changes
- [#9932](https://github.com/withastro/astro/pull/9932) [`9f0d89fa7e9e7c08c8600b0c49c2cce7489a7582`](https://github.com/withastro/astro/commit/9f0d89fa7e9e7c08c8600b0c49c2cce7489a7582) Thanks [@ematipico](https://github.com/ematipico)! - Fixes a case where a warning was logged even when the feature `i18nDomains` wasn't enabled
- [#9907](https://github.com/withastro/astro/pull/9907) [`6c894af5ab79f290f4ff7feb68617a66e91febc1`](https://github.com/withastro/astro/commit/6c894af5ab79f290f4ff7feb68617a66e91febc1) Thanks [@ktym4a](https://github.com/ktym4a)! - Load 404.html on all non-existent paths on astro preview.
## 4.3.1
### Patch Changes
- [#9841](https://github.com/withastro/astro/pull/9841) [`27ea080e24e2c5cdc59b63b1dfe0a83a0c696597`](https://github.com/withastro/astro/commit/27ea080e24e2c5cdc59b63b1dfe0a83a0c696597) Thanks [@kristianbinau](https://github.com/kristianbinau)! - Makes the warning clearer when having a custom `base` and requesting a public URL without it
- [#9888](https://github.com/withastro/astro/pull/9888) [`9d2fdb293d6a7323e10126cebad18ef9a2ea2800`](https://github.com/withastro/astro/commit/9d2fdb293d6a7323e10126cebad18ef9a2ea2800) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Improves error handling logic for the `astro sync` command.
- [#9918](https://github.com/withastro/astro/pull/9918) [`d52529e09450c84933dd15d6481edb32269f537b`](https://github.com/withastro/astro/commit/d52529e09450c84933dd15d6481edb32269f537b) Thanks [@LarryIVC](https://github.com/LarryIVC)! - Adds the `name` attribute to the `<details>` tag type
- [#9938](https://github.com/withastro/astro/pull/9938) [`1568afb78a163db63a4cde146dec87785a83db1d`](https://github.com/withastro/astro/commit/1568afb78a163db63a4cde146dec87785a83db1d) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixes a regression where middleware did not run for prerendered pages and endpoints.
- [#9931](https://github.com/withastro/astro/pull/9931) [`44674418965d658733d3602668a9354e18f8ef89`](https://github.com/withastro/astro/commit/44674418965d658733d3602668a9354e18f8ef89) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixes a regression where a response created with `Response.redirect` or containing `null` as the body never completed in node-based adapters.
## 4.3.0
### Minor Changes
- [#9839](https://github.com/withastro/astro/pull/9839) [`58f9e393a188702eef5329e41deff3dcb65a3230`](https://github.com/withastro/astro/commit/58f9e393a188702eef5329e41deff3dcb65a3230) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Adds a new `ComponentProps` type export from `astro/types` to get the props type of an Astro component.
```astro
---
import type { ComponentProps } from 'astro/types';
import Button from './Button.astro';
type myButtonProps = ComponentProps<typeof Button>;
---
```
- [#9159](https://github.com/withastro/astro/pull/9159) [`7d937c158959e76443a02f740b10e251d14dbd8c`](https://github.com/withastro/astro/commit/7d937c158959e76443a02f740b10e251d14dbd8c) Thanks [@bluwy](https://github.com/bluwy)! - Adds CLI shortcuts as an easter egg for the dev server:
- `o + enter`: opens the site in your browser
- `q + enter`: quits the dev server
- `h + enter`: prints all available shortcuts
- [#9764](https://github.com/withastro/astro/pull/9764) [`fad4f64aa149086feda2d1f3a0b655767034f1a8`](https://github.com/withastro/astro/commit/fad4f64aa149086feda2d1f3a0b655767034f1a8) Thanks [@matthewp](https://github.com/matthewp)! - Adds a new `build.format` configuration option: `'preserve'`. This option will preserve your source structure in the final build.
The existing configuration options, `file` and `directory`, either build all of your HTML pages as files matching the route name (e.g. `/about.html`) or build all your files as `index.html` within a nested directory structure (e.g. `/about/index.html`), respectively. It was not previously possible to control the HTML file built on a per-file basis.
One limitation of `build.format: 'file'` is that it cannot create `index.html` files for any individual routes (other than the base path of `/`) while otherwise building named files. Creating explicit index pages within your file structure still generates a file named for the page route (e.g. `src/pages/about/index.astro` builds `/about.html`) when using the `file` configuration option.
Rather than make a breaking change to allow `build.format: 'file'` to be more flexible, we decided to create a new `build.format: 'preserve'`.
The new format will preserve how the filesystem is structured and make sure that is mirrored over to production. Using this option:
- `about.astro` becomes `about.html`
- `about/index.astro` becomes `about/index.html`
See the [`build.format` configuration options reference](https://docs.astro.build/en/reference/configuration-reference/#buildformat) for more details.
- [#9143](https://github.com/withastro/astro/pull/9143) [`041fdd5c89920f7ccf944b095f29e451f78b0e28`](https://github.com/withastro/astro/commit/041fdd5c89920f7ccf944b095f29e451f78b0e28) Thanks [@ematipico](https://github.com/ematipico)! - Adds experimental support for a new i18n domain routing option (`"domains"`) that allows you to configure different domains for individual locales in entirely server-rendered projects.
To enable this in your project, first configure your `server`-rendered project's i18n routing with your preferences if you have not already done so. Then, set the `experimental.i18nDomains` flag to `true` and add `i18n.domains` to map any of your supported `locales` to custom URLs:
```js
//astro.config.mjs"
import { defineConfig } from 'astro/config';
export default defineConfig({
site: 'https://example.com',
output: 'server', // required, with no prerendered pages
adapter: node({
mode: 'standalone',
}),
i18n: {
defaultLocale: 'en',
locales: ['es', 'en', 'fr', 'ja'],
routing: {
prefixDefaultLocale: false,
},
domains: {
fr: 'https://fr.example.com',
es: 'https://example.es',
},
},
experimental: {
i18nDomains: true,
},
});
```
With `"domains"` configured, the URLs emitted by `getAbsoluteLocaleUrl()` and `getAbsoluteLocaleUrlList()` will use the options set in `i18n.domains`.
```js
import { getAbsoluteLocaleUrl } from 'astro:i18n';
getAbsoluteLocaleUrl('en', 'about'); // will return "https://example.com/about"
getAbsoluteLocaleUrl('fr', 'about'); // will return "https://fr.example.com/about"
getAbsoluteLocaleUrl('es', 'about'); // will return "https://example.es/about"
getAbsoluteLocaleUrl('ja', 'about'); // will return "https://example.com/ja/about"
```
Similarly, your localized files will create routes at corresponding URLs:
- The file `/en/about.astro` will be reachable at the URL `https://example.com/about`.
- The file `/fr/about.astro` will be reachable at the URL `https://fr.example.com/about`.
- The file `/es/about.astro` will be reachable at the URL `https://example.es/about`.
- The file `/ja/about.astro` will be reachable at the URL `https://example.com/ja/about`.
See our [Internationalization Guide](https://docs.astro.build/en/guides/internationalization/#domains-experimental) for more details and limitations on this experimental routing feature.
- [#9755](https://github.com/withastro/astro/pull/9755) [`d4b886141bb342ac71b1c060e67d66ca2ffbb8bd`](https://github.com/withastro/astro/commit/d4b886141bb342ac71b1c060e67d66ca2ffbb8bd) Thanks [@OliverSpeir](https://github.com/OliverSpeir)! - Fixes an issue where images in Markdown required a relative specifier (e.g. `./`)
Now, you can use the standard `![](img.png)` syntax in Markdown files for images colocated in the same folder: no relative specifier required!
There is no need to update your project; your existing images will still continue to work. However, you may wish to remove any relative specifiers from these Markdown images as they are no longer necessary:
```diff
- ![A cute dog](./dog.jpg)
+ ![A cute dog](dog.jpg)
<!-- This dog lives in the same folder as my article! -->
```
### Patch Changes
- [#9908](https://github.com/withastro/astro/pull/9908) [`2f6d1faa6f2d6de2d4ccd2a48adf5adadc82e593`](https://github.com/withastro/astro/commit/2f6d1faa6f2d6de2d4ccd2a48adf5adadc82e593) Thanks [@lilnasy](https://github.com/lilnasy)! - Improves http behavior relating to errors encountered while streaming a response.
- [#9877](https://github.com/withastro/astro/pull/9877) [`7be5f94dcfc73a78d0fb301eeff51614d987a165`](https://github.com/withastro/astro/commit/7be5f94dcfc73a78d0fb301eeff51614d987a165) Thanks [@fabiankachlock](https://github.com/fabiankachlock)! - Fixes the content config type path on windows
- [#9143](https://github.com/withastro/astro/pull/9143) [`041fdd5c89920f7ccf944b095f29e451f78b0e28`](https://github.com/withastro/astro/commit/041fdd5c89920f7ccf944b095f29e451f78b0e28) Thanks [@ematipico](https://github.com/ematipico)! - Fixes an issue where the function `getLocaleRelativeUrlList` wasn't normalising the paths by default
- [#9911](https://github.com/withastro/astro/pull/9911) [`aaedb848b1d6f683840035865528506a346ea659`](https://github.com/withastro/astro/commit/aaedb848b1d6f683840035865528506a346ea659) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Fixes an issue where some adapters that do not include a `start()` export would error rather than silently proceed
## 4.2.8
### Patch Changes
- [#9884](https://github.com/withastro/astro/pull/9884) [`37369550ab57ca529fd6c796e5b0e96e897ca6e5`](https://github.com/withastro/astro/commit/37369550ab57ca529fd6c796e5b0e96e897ca6e5) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixes an issue where multiple cookies were sent in a single Set-Cookie header in the dev mode.
- [#9876](https://github.com/withastro/astro/pull/9876) [`e9027f194b939ac5a4d795ee1a2c24e4a6fbefc0`](https://github.com/withastro/astro/commit/e9027f194b939ac5a4d795ee1a2c24e4a6fbefc0) Thanks [@friedemannsommer](https://github.com/friedemannsommer)! - Fixes an issue where using `Response.redirect` in an endpoint led to an error.
- [#9882](https://github.com/withastro/astro/pull/9882) [`13c3b712c7ba45d0081f459fc06f142216a4ec59`](https://github.com/withastro/astro/commit/13c3b712c7ba45d0081f459fc06f142216a4ec59) Thanks [@natemoo-re](https://github.com/natemoo-re)! - Improves handling of YAML parsing errors
- [#9878](https://github.com/withastro/astro/pull/9878) [`a40a0ff5883c7915dd55881dcebd052b9f94a0eb`](https://github.com/withastro/astro/commit/a40a0ff5883c7915dd55881dcebd052b9f94a0eb) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixes an issue where setting trailingSlash to "never" had no effect on `Astro.url`.
## 4.2.7
### Patch Changes
- [#9840](https://github.com/withastro/astro/pull/9840) [`70fdf1a5c660057152c1ca111dcc89ceda5c8840`](https://github.com/withastro/astro/commit/70fdf1a5c660057152c1ca111dcc89ceda5c8840) Thanks [@delucis](https://github.com/delucis)! - Expose `ContentConfig` type from `astro:content`
- [#9865](https://github.com/withastro/astro/pull/9865) [`00ba9f1947ca9016cd0ee4d8f6048027fab2ab9a`](https://github.com/withastro/astro/commit/00ba9f1947ca9016cd0ee4d8f6048027fab2ab9a) Thanks [@ematipico](https://github.com/ematipico)! - Fixes a bug in `Astro.currentLocale` where the value was incorrectly computed during the build.
- [#9838](https://github.com/withastro/astro/pull/9838) [`0a06d87a1e2b94be00a954f350c184222fa0594d`](https://github.com/withastro/astro/commit/0a06d87a1e2b94be00a954f350c184222fa0594d) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixes an issue where `astro:i18n` could not be used in framework components.
- Updated dependencies [[`44c957f893c6bf5f5b7c78301de7b21c5975584d`](https://github.com/withastro/astro/commit/44c957f893c6bf5f5b7c78301de7b21c5975584d)]:
- @astrojs/markdown-remark@4.2.1
## 4.2.6
### Patch Changes
- [#9825](https://github.com/withastro/astro/pull/9825) [`e4370e9e9dd862425eced25823c82e77d9516927`](https://github.com/withastro/astro/commit/e4370e9e9dd862425eced25823c82e77d9516927) Thanks [@tugrulates](https://github.com/tugrulates)! - Fixes false positive aria role errors on interactive elements
- [#9828](https://github.com/withastro/astro/pull/9828) [`a3df9d83ca92abb5f08f576631019c1604204bd9`](https://github.com/withastro/astro/commit/a3df9d83ca92abb5f08f576631019c1604204bd9) Thanks [@ematipico](https://github.com/ematipico)! - Fixes a case where shared modules among pages and middleware were transformed to a no-op after the build.
- [#9834](https://github.com/withastro/astro/pull/9834) [`1885cea308a62b173a50967cf5a0b174b3c3f3f1`](https://github.com/withastro/astro/commit/1885cea308a62b173a50967cf5a0b174b3c3f3f1) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Fixes third-party dev toolbar apps not loading correctly when using absolute paths on Windows
## 4.2.5
### Patch Changes
- [#9818](https://github.com/withastro/astro/pull/9818) [`d688954c5adba75b0d676694fbf5fb0da1c0af13`](https://github.com/withastro/astro/commit/d688954c5adba75b0d676694fbf5fb0da1c0af13) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Improves the wording of a few confusing error messages
- [#9680](https://github.com/withastro/astro/pull/9680) [`5d7db1dbb0ff06db98e08b0ca241ff09d0b8b44d`](https://github.com/withastro/astro/commit/5d7db1dbb0ff06db98e08b0ca241ff09d0b8b44d) Thanks [@loucyx](https://github.com/loucyx)! - Fixes types generation from Content Collections config file
- [#9822](https://github.com/withastro/astro/pull/9822) [`bd880e8437ea2df16f322f604865c1148a9fd4cf`](https://github.com/withastro/astro/commit/bd880e8437ea2df16f322f604865c1148a9fd4cf) Thanks [@liruifengv](https://github.com/liruifengv)! - Applies the correct escaping to identifiers used with `transition:name`.
- [#9830](https://github.com/withastro/astro/pull/9830) [`f3d22136e53fd902310024519fc4de83f0a58039`](https://github.com/withastro/astro/commit/f3d22136e53fd902310024519fc4de83f0a58039) Thanks [@lilnasy](https://github.com/lilnasy)! - Fixes an issue where 404 responses from endpoints were replaced with contents of 404.astro in dev mode.
- [#9816](https://github.com/withastro/astro/pull/9816) [`2a44c8f93201958fba2d1e83046eabcaef186b7c`](https://github.com/withastro/astro/commit/2a44c8f93201958fba2d1e83046eabcaef186b7c) Thanks [@Princesseuh](https://github.com/Princesseuh)! - Adds telemetry for when apps are toggled in the dev toolbar. This data is completely anonymous and only the names of built-in apps are shared with us. This data will help us monitor how much the dev toolbar is used and which apps are used more. For more information on how Astro collects telemetry, visit the following page: https://astro.build/telemetry/
- [#9807](https://github.com/withastro/astro/pull/9807) [`b3f313138bb314e2b416c29cda507383c2a9f816`](https://github.com/withastro/astro/commit/b3f313138bb314e2b416c29cda507383c2a9f816) Thanks [@bluwy](https://github.com/bluwy)! - Fixes environment variables replacement for `export const prerender`
- [#9790](https://github.com/withastro/astro/pull/9790) [`267c5aa2c7706f0ea3447f20a09d85aa560866ad`](https://github.com/withastro/astro/commit/267c5aa2c7706f0ea3447f20a09d85aa560866ad) Thanks [@lilnasy](https://github.com/lilnasy)! - Refactors internals of the `astro:i18n` module to be more maintainable.
- [#9776](https://github.com/withastro/astro/pull/9776) [`dc75180aa698b298264362bab7f00391af427798`](https://github.com/withastro/astro/commit/dc75180aa698b298264362bab7f00391af427798) Thanks [@lilnasy](https://github.com/lilnasy)! - Simplifies internals that handle middleware.
## 4.2.4
### Patch Changes

View file

@ -670,6 +670,7 @@ declare namespace astroHTML.JSX {
interface DetailsHTMLAttributes extends HTMLAttributes {
open?: boolean | string | undefined | null;
name?: string | undefined | null;
}
interface DelHTMLAttributes extends HTMLAttributes {

View file

@ -20,8 +20,8 @@ async function main() {
const version = process.versions.node;
// Fast-path for higher Node.js versions
if ((parseInt(version) || 0) <= skipSemverCheckIfAbove) {
const semver = await import('semver');
try {
const semver = await import('semver');
if (!semver.satisfies(version, engines)) {
await errorNodeUnsupported();
return;

View file

@ -1,4 +1,5 @@
/// <reference types="vite/types/import-meta.d.ts" />
/// <reference path="./types/content.d.ts" />
// eslint-disable-next-line @typescript-eslint/no-namespace
declare namespace App {

View file

@ -29,6 +29,10 @@ const additionalAttributes: HTMLAttributes<'img'> = {};
if (image.srcSet.values.length > 0) {
additionalAttributes.srcset = image.srcSet.attribute;
}
if (import.meta.env.DEV) {
additionalAttributes['data-image-component'] = 'true';
}
---
<img src={image.src} {...additionalAttributes} {...image.attributes} />

View file

@ -51,16 +51,20 @@ const fallbackImage = await getImage({
});
const imgAdditionalAttributes: HTMLAttributes<'img'> = {};
const sourceAdditionaAttributes: HTMLAttributes<'source'> = {};
const sourceAdditionalAttributes: HTMLAttributes<'source'> = {};
// Propagate the `sizes` attribute to the `source` elements
if (props.sizes) {
sourceAdditionaAttributes.sizes = props.sizes;
sourceAdditionalAttributes.sizes = props.sizes;
}
if (fallbackImage.srcSet.values.length > 0) {
imgAdditionalAttributes.srcset = fallbackImage.srcSet.attribute;
}
if (import.meta.env.DEV) {
imgAdditionalAttributes['data-image-component'] = 'true';
}
---
<picture {...pictureAttributes}>
@ -74,7 +78,7 @@ if (fallbackImage.srcSet.values.length > 0) {
<source
srcset={srcsetAttribute}
type={'image/' + image.options.format}
{...sourceAdditionaAttributes}
{...sourceAdditionalAttributes}
/>
);
})

View file

@ -9,8 +9,6 @@ declare module 'astro:content' {
}
declare module 'astro:content' {
export { z } from 'astro/zod';
type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
export type CollectionKey = keyof AnyEntryMap;
@ -19,53 +17,6 @@ declare module 'astro:content' {
export type ContentCollectionKey = keyof ContentEntryMap;
export type DataCollectionKey = keyof DataEntryMap;
// This needs to be in sync with ImageMetadata
export type ImageFunction = () => import('astro/zod').ZodObject<{
src: import('astro/zod').ZodString;
width: import('astro/zod').ZodNumber;
height: import('astro/zod').ZodNumber;
format: import('astro/zod').ZodUnion<
[
import('astro/zod').ZodLiteral<'png'>,
import('astro/zod').ZodLiteral<'jpg'>,
import('astro/zod').ZodLiteral<'jpeg'>,
import('astro/zod').ZodLiteral<'tiff'>,
import('astro/zod').ZodLiteral<'webp'>,
import('astro/zod').ZodLiteral<'gif'>,
import('astro/zod').ZodLiteral<'svg'>,
import('astro/zod').ZodLiteral<'avif'>,
]
>;
}>;
type BaseSchemaWithoutEffects =
| import('astro/zod').AnyZodObject
| import('astro/zod').ZodUnion<[BaseSchemaWithoutEffects, ...BaseSchemaWithoutEffects[]]>
| import('astro/zod').ZodDiscriminatedUnion<string, import('astro/zod').AnyZodObject[]>
| import('astro/zod').ZodIntersection<BaseSchemaWithoutEffects, BaseSchemaWithoutEffects>;
type BaseSchema =
| BaseSchemaWithoutEffects
| import('astro/zod').ZodEffects<BaseSchemaWithoutEffects>;
export type SchemaContext = { image: ImageFunction };
type DataCollectionConfig<S extends BaseSchema> = {
type: 'data';
schema?: S | ((context: SchemaContext) => S);
};
type ContentCollectionConfig<S extends BaseSchema> = {
type?: 'content';
schema?: S | ((context: SchemaContext) => S);
};
type CollectionConfig<S> = ContentCollectionConfig<S> | DataCollectionConfig<S>;
export function defineCollection<S extends BaseSchema>(
input: CollectionConfig<S>
): CollectionConfig<S>;
type AllValuesOf<T> = T extends any ? T[keyof T] : never;
type ValidContentEntrySlug<C extends keyof ContentEntryMap> = AllValuesOf<
ContentEntryMap[C]
@ -183,5 +134,5 @@ declare module 'astro:content' {
type AnyEntryMap = ContentEntryMap & DataEntryMap;
type ContentConfig = '@@CONTENT_CONFIG_TYPE@@';
export type ContentConfig = '@@CONTENT_CONFIG_TYPE@@';
}

View file

@ -0,0 +1,29 @@
import { expect } from '@playwright/test';
import { testFactory } from './test-utils.js';
const test = testFactory({ root: './fixtures/content-collections/' });
let devServer;
test.beforeAll(async ({ astro }) => {
devServer = await astro.startDevServer();
});
test.afterAll(async ({ astro }) => {
await devServer.stop();
astro.resetAllFiles();
});
test.describe('Content Collections', () => {
test('HMR', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/'));
await astro.editFile('./src/components/MyComponent.astro', (original) =>
original.replace('red', 'green')
);
const h1 = page.locator('#my-heading');
await expect(h1, 'should have green color').toHaveCSS('color', 'rgb(0, 128, 0)');
});
});

View file

@ -0,0 +1,46 @@
import { expect } from '@playwright/test';
import { testFactory } from './test-utils.js';
const test = testFactory({
root: './fixtures/dev-toolbar/',
});
let devServer;
test.beforeAll(async ({ astro }) => {
devServer = await astro.startDevServer();
});
test.afterAll(async () => {
await devServer.stop();
});
test.describe('Dev Toolbar - Audits', () => {
test('can warn about perf issues', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/audits-perf'));
const toolbar = page.locator('astro-dev-toolbar');
const appButton = toolbar.locator('button[data-app-id="astro:audit"]');
await appButton.click();
const auditCanvas = toolbar.locator('astro-dev-toolbar-app-canvas[data-app-id="astro:audit"]');
const auditHighlights = auditCanvas.locator('astro-dev-toolbar-highlight');
const count = await auditHighlights.count();
expect(count).toEqual(2);
for (const auditHighlight of await auditHighlights.all()) {
await expect(auditHighlight).toBeVisible();
const auditCode = await auditHighlight.getAttribute('data-audit-code');
expect(auditCode.startsWith('perf-')).toBe(true);
await auditHighlight.hover();
const auditHighlightTooltip = auditHighlight.locator('astro-dev-toolbar-tooltip');
await expect(auditHighlightTooltip).toBeVisible();
}
// Toggle app off
await appButton.click();
});
});

View file

@ -27,7 +27,7 @@ test.describe('Dev Toolbar', () => {
await page.goto(astro.resolveUrl('/'));
const toolbar = page.locator('astro-dev-toolbar');
const appButton = toolbar.locator('button[data-app-id="astro"]');
const appButton = toolbar.locator('button[data-app-id="astro:home"]');
const appButtonTooltip = appButton.locator('.item-tooltip');
await appButton.hover();
@ -38,10 +38,12 @@ test.describe('Dev Toolbar', () => {
await page.goto(astro.resolveUrl('/'));
const toolbar = page.locator('astro-dev-toolbar');
const appButton = toolbar.locator('button[data-app-id="astro"]');
const appButton = toolbar.locator('button[data-app-id="astro:home"]');
await appButton.click();
const astroAppCanvas = toolbar.locator('astro-dev-toolbar-app-canvas[data-app-id="astro"]');
const astroAppCanvas = toolbar.locator(
'astro-dev-toolbar-app-canvas[data-app-id="astro:home"]'
);
const astroWindow = astroAppCanvas.locator('astro-dev-toolbar-window');
await expect(astroWindow).toHaveCount(1);
await expect(astroWindow).toBeVisible();
@ -98,17 +100,18 @@ test.describe('Dev Toolbar', () => {
await appButton.click();
const auditCanvas = toolbar.locator('astro-dev-toolbar-app-canvas[data-app-id="astro:audit"]');
const auditHighlight = auditCanvas.locator('astro-dev-toolbar-highlight');
await expect(auditHighlight).toBeVisible();
const auditHighlights = auditCanvas.locator('astro-dev-toolbar-highlight');
await auditHighlight.hover();
const auditHighlightTooltip = auditHighlight.locator('astro-dev-toolbar-tooltip');
await expect(auditHighlightTooltip).toBeVisible();
for (const auditHighlight of await auditHighlights.all()) {
await expect(auditHighlight).toBeVisible();
await auditHighlight.hover();
const auditHighlightTooltip = auditHighlight.locator('astro-dev-toolbar-tooltip');
await expect(auditHighlightTooltip).toBeVisible();
}
// Toggle app off
await appButton.click();
await expect(auditHighlight).not.toBeVisible();
await expect(auditHighlightTooltip).not.toBeVisible();
});
test('audit shows no issues message when there are no issues', async ({ page, astro }) => {
@ -129,6 +132,23 @@ test.describe('Dev Toolbar', () => {
await expect(auditWindow.locator('astro-dev-toolbar-icon[icon=check-circle]')).toBeVisible();
});
test('audit shows a window with list of problems', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/'));
const toolbar = page.locator('astro-dev-toolbar');
const appButton = toolbar.locator('button[data-app-id="astro:audit"]');
await appButton.click();
const auditCanvas = toolbar.locator('astro-dev-toolbar-app-canvas[data-app-id="astro:audit"]');
const auditWindow = auditCanvas.locator('astro-dev-toolbar-window');
await expect(auditWindow).toHaveCount(1);
await expect(auditWindow).toBeVisible();
// Toggle app off
await appButton.click();
await expect(auditWindow).not.toBeVisible();
});
test('adjusts tooltip position if off-screen', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/tooltip-position'));
@ -187,10 +207,12 @@ test.describe('Dev Toolbar', () => {
await expect(settingsWindow).toBeVisible();
// Click the astro app
appButton = toolbar.locator('button[data-app-id="astro"]');
appButton = toolbar.locator('button[data-app-id="astro:home"]');
await appButton.click();
const astroAppCanvas = toolbar.locator('astro-dev-toolbar-app-canvas[data-app-id="astro"]');
const astroAppCanvas = toolbar.locator(
'astro-dev-toolbar-app-canvas[data-app-id="astro:home"]'
);
const astroWindow = astroAppCanvas.locator('astro-dev-toolbar-window');
await expect(astroWindow).toHaveCount(1);
await expect(astroWindow).toBeVisible();
@ -215,4 +237,35 @@ test.describe('Dev Toolbar', () => {
const hideToolbar = settingsWindow.getByRole('heading', { name: 'Hide toolbar' });
await expect(hideToolbar).toBeVisible();
});
test('supports third-party apps', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/'));
const toolbar = page.locator('astro-dev-toolbar');
const appButton = toolbar.locator('button[data-app-id="my-plugin"]');
await appButton.click();
const myAppCanvas = toolbar.locator('astro-dev-toolbar-app-canvas[data-app-id="my-plugin"]');
console.log(await myAppCanvas.innerHTML());
const myAppWindow = myAppCanvas.locator('astro-dev-toolbar-window');
await expect(myAppWindow).toHaveCount(1);
await expect(myAppWindow).toBeVisible();
// Toggle app off
await appButton.click();
await expect(myAppWindow).not.toBeVisible();
});
test('islands include their server and client render time', async ({ page, astro }) => {
await page.goto(astro.resolveUrl('/'));
const island = page.locator('astro-island');
await expect(island).toHaveCount(1);
const serverRenderTime = await island.getAttribute('server-render-time');
const clientRenderTime = await island.getAttribute('client-render-time');
expect(serverRenderTime).not.toBe(null);
expect(clientRenderTime).not.toBe(null);
});
});

View file

@ -0,0 +1,9 @@
import { defineConfig } from 'astro/config';
import mdx from '@astrojs/mdx';
// https://astro.build/config
export default defineConfig({
integrations: [
mdx(),
],
});

View file

@ -0,0 +1,9 @@
{
"name": "@e2e/content-collections",
"version": "0.0.0",
"private": true,
"dependencies": {
"@astrojs/mdx": "workspace:*",
"astro": "workspace:*"
}
}

View file

@ -0,0 +1,10 @@
<h1 id="my-heading">
Some text here
</h1>
<style>
h1 {
color: red;
}
</style>

View file

@ -0,0 +1,6 @@
---
---
import MyComponent from '../../components/MyComponent.astro';
<MyComponent />

View file

@ -0,0 +1,8 @@
---
import { getEntryBySlug } from 'astro:content'
const post = await getEntryBySlug('posts', 'post-1')
const { Content } = await post.render();
---
<Content/>

View file

@ -1,5 +1,6 @@
import preact from '@astrojs/preact';
import { myIntegration } from './custom-integration.js';
export default {
integrations: [preact()],
integrations: [preact(), myIntegration()],
};

View file

@ -0,0 +1,17 @@
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
/** @type {() => import('astro').AstroIntegration} */
export function myIntegration() {
return {
name: 'my-integration',
hooks: {
'astro:config:setup': ({ addDevToolbarApp }) => {
const importPath = dirname(fileURLToPath(import.meta.url));
const pluginPath = join(importPath, 'custom-plugin.js');
addDevToolbarApp(pluginPath);
},
},
};
}

View file

@ -0,0 +1,20 @@
export default {
id: 'my-plugin',
name: 'My Plugin',
icon: 'astro:logo',
init(canvas) {
const astroWindow = document.createElement('astro-dev-toolbar-window');
const myButton = document.createElement('astro-dev-toolbar-button');
myButton.size = 'medium';
myButton.buttonStyle = 'purple';
myButton.innerText = 'Click me!';
myButton.addEventListener('click', () => {
console.log('Clicked!');
});
astroWindow.appendChild(myButton);
canvas.appendChild(astroWindow);
},
};

View file

@ -2,4 +2,4 @@
---
<img src="https://astro.build/assets/press/astro-logo-dark.svg" alt="Astro logo" />
<div>Hey, there's no errors here!</div>

View file

@ -0,0 +1,10 @@
---
import { Image } from "astro:assets";
import walrus from "../light_walrus.avif";
---
<Image src={walrus} loading="lazy" alt="A walrus" />
<div style="height: 9000px;"></div>
<Image src={walrus} loading="eager" alt="A walrus" />

View file

@ -22,6 +22,7 @@ const { link } = Astro.props as Props;
<ViewTransitions handleForms />
<DarkMode />
<meta name="script-executions" content="0">
<meta charset="utf-8">
<script is:inline defer>
{
// Increment a global to see if this is running more than once

View file

@ -4,6 +4,7 @@ import Layout from '../components/Layout.astro';
<Layout>
<article id="longpage">
<div><a id="click-one" href="/one">go to 1</a></div>
<div><a id="click-self" href="/long-page">go to self</a></div>
<div><a id="click-scroll-down" href="#click-one-again">go further down</a></div>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Dictum varius duis at consectetur lorem donec massa sapien faucibus. Amet mauris commodo quis imperdiet massa. Sed pulvinar proin gravida hendrerit lectus a. Magna ac placerat vestibulum lectus. Blandit cursus risus at ultrices mi tempus. Luctus venenatis lectus magna fringilla urna porttitor. Auctor eu augue ut lectus arcu bibendum at varius vel. Tristique senectus et netus et. In fermentum et sollicitudin ac orci phasellus egestas tellus rutrum. Eget lorem dolor sed viverra ipsum nunc aliquet. Amet consectetur adipiscing elit ut aliquam purus. Accumsan lacus vel facilisis volutpat est velit egestas. Felis imperdiet proin fermentum leo vel. Ut tellus elementum sagittis vitae et leo duis ut diam. Nisl pretium fusce id velit. Lorem donec massa sapien faucibus et. Nibh sed pulvinar proin gravida hendrerit lectus a. In est ante in nibh mauris cursus mattis molestie.

View file

@ -0,0 +1,37 @@
---
import Layout from '../components/Layout.astro';
---
<Layout>
<div id="one" transition:name="front-end">front-end</div>
<div id="two" transition:name="开源">开源</div>
<div id="three" transition:name="开a源">开a源</div>
<div id="four" transition:name="c开a源c">c开a源c</div>
<div id="five" transition:name="オープンソース">オープンソース</div>
<div id="six" transition:name="开$源">开$源</div>
<div id="seven" transition:name="开.源">开.源</div>
<div id="eight" transition:name="🐎👱❤">🐎👱❤</div>
<div id="nine" transition:name="--9">--9</div>
<div id="ten" transition:name="10">10</div>
<div id="eleven" transition:name="-11">-11</div>
<div id="twelve" transition:name="#! /">#! /</div>
<div id="thirteen" transition:name="_01__02___">_01__02___</div>
<div id="batch0" transition:name="\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f">control chars</div>
<div id="batch1" transition:name="\x20\x21\x22\x23\x24\x25\x26\x27\x28\x29\x2a\x2b\x2c\x2d\x2e\x2f\x30\x31\x32\x33\x34\x35\x36\x37\x38\x39\x3a\x3b\x3c\x3d\x3e\x3f">punctation &amp; numbers</div>
<div id="batch2" transition:name="\x40\x41\x42\x43\x44\x45\x46\x47\x48\x49\x4a\x4b\x4c\x4d\x4e\x4f\x50\x51\x52\x53\x54\x55\x56\x57\x58\x59\x5a\x5b\x5c\x5d\x5e\x5f">upper case chars</div>
<div id="batch3" transition:name="\x60\x61\x62\x63\x64\x65\x66\x67\x68\x69\x6a\x6b\x6c\x6d\x6e\x6f\x70\x71\x72\x73\x74\x75\x76\x77\x78\x79\x7a\x7b\x7c\x7d\x7e\x7f">lower case chars</div>
<div id="batch4" transition:name="\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f">80-9f</div>
<div id="batch5" transition:name="\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf">a0-bf</div>
<div id="batch6" transition:name="\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf">c0-df</div>
<div id="batch7" transition:name="\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff">e0-ff</div>
<a id="navigate" href="">navigate</a>
</Layout>
<script>
document.addEventListener('animationstart', start);
function start(event:Event) {
if (event instanceof AnimationEvent) {
const name = event.animationName;
const match = name.match(/^-ua-view-transition-group-anim-(.*)$/)
if (match) console.log("anim:",match[1]);
}
}
</script>

View file

@ -413,10 +413,7 @@ 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();
@ -426,6 +423,85 @@ test.describe('View Transitions', () => {
await expect(locator).toBeInViewport();
});
test('View Transitions Rule', async ({ page, astro }) => {
let consoleCount = 0;
page.on('console', (msg) => {
// This count is used for transition events
if (msg.text() === 'ready') consoleCount++;
});
// Don't test back and forward '' to '', because They are not stored in the history.
// click '' to '' (transition)
await page.goto(astro.resolveUrl('/long-page'));
let locator = page.locator('#longpage');
await expect(locator).toBeInViewport();
let consolePromise = page.waitForEvent('console');
await page.click('#click-self');
await consolePromise;
locator = page.locator('#longpage');
await expect(locator).toBeInViewport();
expect(consoleCount).toEqual(1);
// click '' to 'hash' (no transition)
await page.click('#click-scroll-down');
locator = page.locator('#click-one-again');
await expect(locator).toBeInViewport();
expect(consoleCount).toEqual(1);
// back 'hash' to '' (no transition)
await page.goBack();
locator = page.locator('#longpage');
await expect(locator).toBeInViewport();
expect(consoleCount).toEqual(1);
// forward '' to 'hash' (no transition)
await page.goForward();
locator = page.locator('#click-one-again');
await expect(locator).toBeInViewport();
expect(consoleCount).toEqual(1);
// click 'hash' to 'hash' (no transition)
await page.click('#click-scroll-up');
locator = page.locator('#longpage');
await expect(locator).toBeInViewport();
expect(consoleCount).toEqual(1);
// back 'hash' to 'hash' (no transition)
await page.goBack();
locator = page.locator('#click-one-again');
await expect(locator).toBeInViewport();
expect(consoleCount).toEqual(1);
// forward 'hash' to 'hash' (no transition)
await page.goForward();
locator = page.locator('#longpage');
await expect(locator).toBeInViewport();
expect(consoleCount).toEqual(1);
// click 'hash' to '' (transition)
consolePromise = page.waitForEvent('console');
await page.click('#click-self');
await consolePromise;
locator = page.locator('#longpage');
await expect(locator).toBeInViewport();
expect(consoleCount).toEqual(2);
// back '' to 'hash' (transition)
consolePromise = page.waitForEvent('console');
await page.goBack();
await consolePromise;
locator = page.locator('#longpage');
await expect(locator).toBeInViewport();
expect(consoleCount).toEqual(3);
// forward 'hash' to '' (transition)
consolePromise = page.waitForEvent('console');
await page.goForward();
await consolePromise;
locator = page.locator('#longpage');
await expect(locator).toBeInViewport();
expect(consoleCount).toEqual(4);
});
test('<Image /> component forwards transitions to the <img>', async ({ page, astro }) => {
// Go to page 1
await page.goto(astro.resolveUrl('/image-one'));
@ -1227,4 +1303,71 @@ test.describe('View Transitions', () => {
expect(loads.length, 'There should only be 1 page load').toEqual(1);
});
test('transition:name should be escaped correctly', async ({ page, astro }) => {
const expectedAnimations = new Set();
const checkName = async (selector, name) => {
expectedAnimations.add(name);
expect(page.locator(selector), 'should be escaped correctly').toHaveCSS(
'view-transition-name',
name
);
};
page.on('console', (msg) => {
if (msg.text().startsWith('anim: ')) {
const split = msg.text().split(' ', 2);
expectedAnimations.delete(split[1]);
}
});
await page.goto(astro.resolveUrl('/transition-name'));
await checkName('#one', 'front-end');
await checkName('#two', '开源');
await checkName('#three', '开a源');
await checkName('#four', 'c开a源c');
await checkName('#five', 'オープンソース');
await checkName('#six', '开_24源');
await checkName('#seven', '开_2e源');
await checkName('#eight', '🐎👱❤');
await checkName('#nine', '_--9');
await checkName('#ten', '_10');
await checkName('#eleven', '_-11');
await checkName('#twelve', '__23_21_20_2f');
await checkName('#thirteen', '___01____02______');
await checkName(
'#batch0',
'__00_01_02_03_04_05_06_07_08_09_0a_0b_0c_0d_0e_0f_10_11_12_13_14_15_16_17_18_19_1a_1b_1c_1d_1e_1f'
);
await checkName(
'#batch1',
'__20_21_22_23_24_25_26_27_28_29_2a_2b_2c-_2e_2f0123456789_3a_3b_3c_3d_3e_3f'
);
await checkName('#batch2', '__40ABCDEFGHIJKLMNOPQRSTUVWXYZ_5b_5c_5d_5e__');
await checkName('#batch3', '__60abcdefghijklmnopqrstuvwxyz_7b_7c_7d_7e_7f');
await checkName(
'#batch4',
'\x80\x81\x82\x83\x84\x85\x86\x87\x88\x89\x8a\x8b\x8c\x8d\x8e\x8f\x90\x91\x92\x93\x94\x95\x96\x97\x98\x99\x9a\x9b\x9c\x9d\x9e\x9f'
);
await checkName(
'#batch5',
'\xa0\xa1\xa2\xa3\xa4\xa5\xa6\xa7\xa8\xa9\xaa\xab\xac\xad\xae\xaf\xb0\xb1\xb2\xb3\xb4\xb5\xb6\xb7\xb8\xb9\xba\xbb\xbc\xbd\xbe\xbf'
);
await checkName(
'#batch6',
'\xc0\xc1\xc2\xc3\xc4\xc5\xc6\xc7\xc8\xc9\xca\xcb\xcc\xcd\xce\xcf\xd0\xd1\xd2\xd3\xd4\xd5\xd6\xd7\xd8\xd9\xda\xdb\xdc\xdd\xde\xdf'
);
await checkName(
'#batch7',
'\xe0\xe1\xe2\xe3\xe4\xe5\xe6\xe7\xe8\xe9\xea\xeb\xec\xed\xee\xef\xf0\xf1\xf2\xf3\xf4\xf5\xf6\xf7\xf8\xf9\xfa\xfb\xfc\xfd\xfe\xff'
);
await page.click('#navigate');
await page.waitForTimeout(400); // yes, I dislike this, too. Might fix later.
expect(
expectedAnimations.size,
'all animations for transition:names should have been found'
).toEqual(0);
});
});

View file

@ -1,6 +1,6 @@
{
"name": "astro",
"version": "4.2.4",
"version": "4.4.0",
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
"type": "module",
"author": "withastro",
@ -96,6 +96,7 @@
"content-types.template.d.ts",
"content-module.template.mjs",
"astro-jsx.d.ts",
"types/content.d.ts",
"types.d.ts",
"README.md",
"vendor"
@ -106,15 +107,14 @@
"build:ci": "pnpm run prebuild && astro-scripts build \"src/**/*.{ts,js}\" && pnpm run postbuild",
"dev": "astro-scripts dev --copy-wasm --prebuild \"src/runtime/server/astro-island.ts\" --prebuild \"src/runtime/client/{idle,load,media,only,visible}.ts\" \"src/**/*.{ts,js}\"",
"postbuild": "astro-scripts copy \"src/**/*.astro\" && astro-scripts copy \"src/**/*.wasm\"",
"test:unit": "mocha --exit --timeout 30000 ./test/units/**/*.test.js",
"test:unit:match": "mocha --exit --timeout 30000 ./test/units/**/*.test.js -g",
"test": "pnpm run test:unit && mocha --exit --timeout 30000 --ignore **/lit-element.test.js && mocha --timeout 30000 **/lit-element.test.js",
"test:match": "mocha --timeout 30000 -g",
"test": "pnpm run test:node",
"test:match": "mocha ./test/*.test.js --timeout 30000 -g",
"test:e2e": "playwright test",
"test:e2e:match": "playwright test -g"
"test:e2e:match": "playwright test -g",
"test:node": "astro-scripts test \"test/**/*.nodetest.js\""
},
"dependencies": {
"@astrojs/compiler": "^2.5.0",
"@astrojs/compiler": "^2.5.3",
"@astrojs/internal-helpers": "workspace:*",
"@astrojs/markdown-remark": "workspace:*",
"@astrojs/telemetry": "workspace:*",
@ -124,6 +124,7 @@
"@babel/plugin-transform-react-jsx": "^7.22.5",
"@babel/traverse": "^7.23.3",
"@babel/types": "^7.23.3",
"@medv/finder": "^3.1.0",
"@types/babel__core": "^7.20.4",
"acorn": "^8.11.2",
"aria-query": "^5.3.0",
@ -134,6 +135,7 @@
"clsx": "^2.0.0",
"common-ancestor-path": "^1.0.1",
"cookie": "^0.6.0",
"cssesc": "^3.0.0",
"debug": "^4.3.4",
"deterministic-object-hash": "^2.0.1",
"devalue": "^4.3.2",
@ -160,19 +162,18 @@
"p-queue": "^8.0.1",
"path-to-regexp": "^6.2.1",
"preferred-pm": "^3.1.2",
"probe-image-size": "^7.2.3",
"prompts": "^2.4.2",
"rehype": "^13.0.1",
"resolve": "^1.22.4",
"semver": "^7.5.4",
"server-destroy": "^1.0.1",
"shikiji": "^0.9.18",
"shikiji": "^0.9.19",
"shikiji-core": "^0.9.19",
"string-width": "^7.0.0",
"strip-ansi": "^7.1.0",
"tsconfck": "^3.0.0",
"unist-util-visit": "^5.0.0",
"vfile": "^6.0.1",
"vite": "^5.0.12",
"vite": "^5.1.2",
"vitefu": "^0.2.5",
"which-pm": "^2.1.1",
"yargs-parser": "^21.1.1",
@ -191,6 +192,7 @@
"@types/common-ancestor-path": "^1.0.2",
"@types/connect": "^3.4.38",
"@types/cookie": "^0.5.4",
"@types/cssesc": "^3.0.2",
"@types/debug": "^4.1.12",
"@types/diff": "^5.0.8",
"@types/dlv": "^1.1.4",
@ -207,7 +209,6 @@
"@types/resolve": "^1.20.5",
"@types/semver": "^7.5.2",
"@types/send": "^0.17.4",
"@types/server-destroy": "^1.0.3",
"@types/unist": "^3.0.2",
"@types/yargs-parser": "^21.0.3",
"astro-scripts": "workspace:*",
@ -224,7 +225,6 @@
"remark-code-titles": "^0.1.2",
"rollup": "^4.5.0",
"sass": "^1.69.5",
"shikiji-core": "^0.9.18",
"srcset-parse": "^1.1.0",
"unified": "^11.0.4"
},

View file

@ -1,6 +1,6 @@
---
// Inspired by the `Aside` component from docs.astro.build
// https://github.com/withastro/docs/blob/main/src/components/Aside.astro
// https://github.com/withastro/starlight/blob/main/packages/starlight/integrations/asides.ts
interface Props {
type?: 'note' | 'tip' | 'caution' | 'danger';

View file

@ -206,7 +206,7 @@ export interface AstroGlobal<
* const { name } = Astro.props
* ```
*
* [Astro reference](https://docs.astro.build/en/core-concepts/astro-components/#component-props)
* [Astro reference](https://docs.astro.build/en/basics/astro-components/#component-props)
*/
props: AstroSharedContext<Props, Params>['props'];
/** Information about the current request. This is a standard [Request](https://developer.mozilla.org/en-US/docs/Web/API/Request) object
@ -553,7 +553,7 @@ export interface AstroUserConfig {
*
* Specifies the output target for builds.
*
* - `'static'` - Building a static site to be deploy to any static host.
* - `'static'` - Building a static site to be deployed to any static host.
* - `'server'` - Building an app to be deployed to a host supporting SSR (server-side rendering).
* - `'hybrid'` - Building a static site with a few server-side rendered pages.
*
@ -784,12 +784,13 @@ export interface AstroUserConfig {
/**
* @docs
* @name build.format
* @typeraw {('file' | 'directory')}
* @typeraw {('file' | 'directory' | 'preserve')}
* @default `'directory'`
* @description
* Control the output file format of each page. This value may be set by an adapter for you.
* - If `'file'`, Astro will generate an HTML file (ex: "/foo.html") for each page.
* - If `'directory'`, Astro will generate a directory with a nested `index.html` file (ex: "/foo/index.html") for each page.
* - `'file'`: Astro will generate an HTML file named for each page route. (e.g. `src/pages/about.astro` and `src/pages/about/index.astro` both build the file `/about.html`)
* - `'directory'`: Astro will generate a directory with a nested `index.html` file for each page. (e.g. `src/pages/about.astro` and `src/pages/about/index.astro` both build the file `/about/index.html`)
* - `'preserve'`: Astro will generate HTML files exactly as they appear in your source folder. (e.g. `src/pages/about.astro` builds `/about.html` and `src/pages/about/index.astro` builds the file `/about/index.html`)
*
* ```js
* {
@ -813,7 +814,7 @@ export interface AstroUserConfig {
* - `directory` - Set `trailingSlash: 'always'`
* - `file` - Set `trailingSlash: 'never'`
*/
format?: 'file' | 'directory';
format?: 'file' | 'directory' | 'preserve';
/**
* @docs
* @name build.client
@ -1529,9 +1530,49 @@ export interface AstroUserConfig {
* @version 3.7.0
* @description
*
* - `"pathanme": The strategy is applied to the pathname of the URLs
* - `"pathname": The strategy is applied to the pathname of the URLs
*/
strategy: 'pathname';
/**
* @name i18n.domains
* @type {Record<string, string> }
* @default '{}'
* @version 4.3.0
* @description
*
* Configures the URL pattern of one or more supported languages to use a custom domain (or sub-domain).
*
* When a locale is mapped to a domain, a `/[locale]/` path prefix will not be used.
* However, localized folders within `src/pages/` are still required, including for your configured `defaultLocale`.
*
* Any other locale not configured will default to a localized path-based URL according to your `prefixDefaultLocale` strategy (e.g. `https://example.com/[locale]/blog`).
*
* ```js
* //astro.config.mjs
* export default defineConfig({
* site: "https://example.com",
* output: "server", // required, with no prerendered pages
* adapter: node({
* mode: 'standalone',
* }),
* i18n: {
* defaultLocale: "en",
* locales: ["en", "fr", "pt-br", "es"],
* prefixDefaultLocale: false,
* domains: {
* fr: "https://fr.example.com",
* es: "https://example.es"
* }
* },
* })
* ```
*
* Both page routes built and URLs returned by the `astro:i18n` helper functions [`getAbsoluteLocaleUrl()`](https://docs.astro.build/en/guides/internationalization/#getabsolutelocaleurl) and [`getAbsoluteLocaleUrlList()`](https://docs.astro.build/en/guides/internationalization/#getabsolutelocaleurllist) will use the options set in `i18n.domains`.
*
* See the [Internationalization Guide](https://docs.astro.build/en/guides/internationalization/#domains) for more details, including the limitations of this feature.
*/
domains?: Record<string, string>;
};
};
@ -1643,7 +1684,7 @@ export interface AstroUserConfig {
* @version 4.2.0
* @description
*
* Prioritizes redirects and injected routes equally alongside file-based project routes, following the same [route priority order rules](https://docs.astro.build/en/core-concepts/routing/#route-priority-order) for all routes.
* Prioritizes redirects and injected routes equally alongside file-based project routes, following the same [route priority order rules](https://docs.astro.build/en/guides/routing/#route-priority-order) for all routes.
*
* This allows more control over routing in your project by not automatically prioritizing certain types of routes, and standardizes the route priority ordering for all routes.
*
@ -1664,6 +1705,49 @@ export interface AstroUserConfig {
* In the event of route collisions, where two routes of equal route priority attempt to build the same URL, Astro will log a warning identifying the conflicting routes.
*/
globalRoutePriority?: boolean;
/**
* @docs
* @name experimental.i18nDomains
* @type {boolean}
* @default `false`
* @version 4.3.0
* @description
*
* Enables domain support for the [experimental `domains` routing strategy](https://docs.astro.build/en/guides/internationalization/#domains-experimental) which allows you to configure the URL pattern of one or more supported languages to use a custom domain (or sub-domain).
*
* When a locale is mapped to a domain, a `/[locale]/` path prefix will not be used. However, localized folders within `src/pages/` are still required, including for your configured `defaultLocale`.
*
* Any other locale not configured will default to a localized path-based URL according to your `prefixDefaultLocale` strategy (e.g. `https://example.com/[locale]/blog`).
*
* ```js
* //astro.config.mjs
* export default defineConfig({
* site: "https://example.com",
* output: "server", // required, with no prerendered pages
* adapter: node({
* mode: 'standalone',
* }),
* i18n: {
* defaultLocale: "en",
* locales: ["en", "fr", "pt-br", "es"],
* prefixDefaultLocale: false,
* domains: {
* fr: "https://fr.example.com",
* es: "https://example.es",
* },
* },
* experimental: {
* i18nDomains: true,
* },
* });
* ```
*
* Both page routes built and URLs returned by the `astro:i18n` helper functions [`getAbsoluteLocaleUrl()`](https://docs.astro.build/en/guides/internationalization/#getabsolutelocaleurl) and [`getAbsoluteLocaleUrlList()`](https://docs.astro.build/en/guides/internationalization/#getabsolutelocaleurllist) will use the options set in `i18n.domains`.
*
* See the [Internationalization Guide](https://docs.astro.build/en/guides/internationalization/#domains-experimental) for more details, including the limitations of this experimental feature.
*/
i18nDomains?: boolean;
};
}
@ -1939,7 +2023,7 @@ export type GetStaticPathsResultKeyed = GetStaticPathsResult & {
};
/**
* Return an array of pages to generate for a [dynamic route](https://docs.astro.build/en/core-concepts/routing/#dynamic-routes). (**SSG Only**)
* Return an array of pages to generate for a [dynamic route](https://docs.astro.build/en/guides/routing/#dynamic-routes). (**SSG Only**)
*
* [Astro Reference](https://docs.astro.build/en/reference/api-reference/#getstaticpaths)
*/
@ -2133,7 +2217,7 @@ export type AstroFeatureMap = {
/**
* List of features that orbit around the i18n routing
*/
i18n?: AstroInternationalizationFeature;
i18nDomains?: SupportsKind;
};
export interface AstroAssetsFeature {
@ -2150,9 +2234,9 @@ export interface AstroAssetsFeature {
export interface AstroInternationalizationFeature {
/**
* Whether the adapter is able to detect the language of the browser, usually using the `Accept-Language` header.
* The adapter should be able to create the proper redirects
*/
detectBrowserLanguage?: SupportsKind;
domains?: SupportsKind;
}
export type Locales = (string | { codes: string[]; path: string })[];
@ -2556,6 +2640,7 @@ export interface RouteData {
redirect?: RedirectConfig;
redirectRoute?: RouteData;
fallbackRoutes: RouteData[];
isIndex: boolean;
}
export type RedirectRouteData = RouteData & {

View file

@ -9,6 +9,7 @@ import type {
UnresolvedImageTransform,
} from './types.js';
import { isESMImportedImage, isRemoteImage } from './utils/imageKind.js';
import { probe } from './utils/remoteProbe.js';
export async function getConfiguredImageService(): Promise<ImageService> {
if (!globalThis?.astroAsset?.imageService) {
@ -61,6 +62,21 @@ export async function getImage(
: options.src,
};
// Infer size for remote images if inferSize is true
if (options.inferSize && isRemoteImage(resolvedOptions.src)) {
try {
const result = await probe(resolvedOptions.src); // Directly probe the image URL
resolvedOptions.width ??= result.width;
resolvedOptions.height ??= result.height;
delete resolvedOptions.inferSize; // Delete so it doesn't end up in the attributes
} catch {
throw new AstroError({
...AstroErrorData.FailedToFetchRemoteImageDimensions,
message: AstroErrorData.FailedToFetchRemoteImageDimensions.message(resolvedOptions.src),
});
}
}
const originalPath = isESMImportedImage(resolvedOptions.src)
? resolvedOptions.src.fsPath
: resolvedOptions.src;

View file

@ -48,6 +48,8 @@ async function getRotationForEXIF(
case 7:
case 8:
return { type: 'rotate', numRotations: 3 };
default:
return undefined;
}
}

View file

@ -291,6 +291,8 @@ export const codecs = {
avif: {
name: 'AVIF',
extension: 'avif',
// Disable eslint rule to not touch the original code
// eslint-disable-next-line no-control-regex, regexp/control-character-escape
detectors: [/^\x00\x00\x00 ftypavif\x00\x00\x00\x00/],
dec: () =>
instantiateEmscriptenWasm(avifDec as DecodeModuleFactory, avifDecWasm),
@ -321,6 +323,8 @@ export const codecs = {
oxipng: {
name: 'OxiPNG',
extension: 'png',
// Disable eslint rule to not touch the original code
// eslint-disable-next-line no-control-regex, regexp/control-character-escape
detectors: [/^\x89PNG\x0D\x0A\x1A\x0A/],
dec: async () => {
await pngEncDecInit()

View file

@ -59,6 +59,7 @@ export type SrcSetValue = UnresolvedSrcSetValue & {
*/
export type UnresolvedImageTransform = Omit<ImageTransform, 'src'> & {
src: ImageMetadata | string | Promise<{ default: ImageMetadata }>;
inferSize?: boolean;
};
/**
@ -176,16 +177,38 @@ export type LocalImageProps<T> = ImageSharedProps<T> & {
quality?: ImageQuality;
};
export type RemoteImageProps<T> = WithRequired<ImageSharedProps<T>, 'width' | 'height'> & {
/**
* URL of a remote image. Can start with a protocol (ex: `https://`) or alternatively `/`, or `Astro.url`, for images in the `public` folder
*
* Remote images are not optimized, and require both `width` and `height` to be set.
*
* **Example**:
* ```
* <Image src="https://example.com/image.png" width={450} height={300} alt="..." />
* ```
*/
src: string;
};
export type RemoteImageProps<T> =
| (ImageSharedProps<T> & {
/**
* URL of a remote image. Can start with a protocol (ex: `https://`) or alternatively `/`, or `Astro.url`, for images in the `public` folder
*
* Remote images are not optimized, and require both `width` and `height` to be set.
*
* **Example**:
* ```
* <Image src="https://example.com/image.png" width={450} height={300} alt="..." />
* ```
*/
src: string;
/**
* When inferSize is true width and height are not required
*/
inferSize: true;
})
| (WithRequired<ImageSharedProps<T>, 'width' | 'height'> & {
/**
* URL of a remote image. Can start with a protocol (ex: `https://`) or alternatively `/`, or `Astro.url`, for images in the `public` folder
*
* Remote images are not optimized, and require both `width` and `height` to be set.
*
* **Example**:
* ```
* <Image src="https://example.com/image.png" width={450} height={300} alt="..." />
* ```
*/
src: string;
/**
* When inferSize is false or undefined width and height are required
*/
inferSize?: false | undefined;
});

Some files were not shown because too many files have changed in this diff Show more