astro 7.0.3 → 7.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/services/sharp.js +1 -1
- package/dist/cli/dev/background.js +4 -2
- package/dist/cli/infra/build-time-astro-version-provider.js +1 -1
- package/dist/content/content-layer.js +3 -3
- package/dist/content/vite-plugin-content-virtual-mod.js +5 -1
- package/dist/core/app/node.js +7 -2
- package/dist/core/build/plugins/index.js +2 -0
- package/dist/core/build/plugins/plugin-css-target-lowering.d.ts +14 -0
- package/dist/core/build/plugins/plugin-css-target-lowering.js +82 -0
- package/dist/core/constants.js +1 -1
- package/dist/core/create-vite.js +2 -0
- package/dist/core/dev/dev.js +1 -1
- package/dist/core/fetch/fetch-state.js +2 -0
- package/dist/core/head-propagation/buffer.d.ts +14 -3
- package/dist/core/head-propagation/buffer.js +17 -7
- package/dist/core/messages/runtime.js +1 -1
- package/dist/core/render/route-cache.d.ts +7 -2
- package/dist/core/routing/create-manifest.js +9 -7
- package/dist/prefetch/index.js +10 -0
- package/dist/runtime/client/dev-toolbar/apps/audit/rules/a11y.js +49 -9
- package/dist/runtime/server/hydration.js +1 -1
- package/dist/runtime/server/render/astro/instance.js +3 -0
- package/dist/runtime/server/render/page.js +7 -2
- package/dist/runtime/server/render/server-islands-shared.d.ts +1 -0
- package/dist/runtime/server/render/server-islands-shared.js +4 -0
- package/dist/runtime/server/render/server-islands.js +3 -2
- package/dist/template/4xx.js +1 -1
- package/dist/transitions/swap-functions.js +9 -2
- package/dist/types/public/internal.d.ts +14 -0
- package/dist/vite-plugin-astro/index.js +3 -1
- package/dist/vite-plugin-config-alias/index.d.ts +19 -1
- package/dist/vite-plugin-config-alias/index.js +6 -5
- package/dist/vite-plugin-html/transform/index.js +16 -7
- package/dist/vite-plugin-html/transform/slots.d.ts +10 -7
- package/dist/vite-plugin-html/transform/slots.js +19 -26
- package/dist/vite-plugin-html/transform/utils.d.ts +0 -3
- package/dist/vite-plugin-html/transform/utils.js +1 -20
- package/package.json +4 -26
- package/dist/vite-plugin-html/transform/escape.d.ts +0 -7
- package/dist/vite-plugin-html/transform/escape.js +0 -30
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
2
|
import { existsSync, mkdirSync, openSync } from "node:fs";
|
|
3
|
-
import {
|
|
3
|
+
import { createRequire } from "node:module";
|
|
4
|
+
import { dirname, resolve } from "node:path";
|
|
4
5
|
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
5
6
|
import {
|
|
6
7
|
checkExistingServer,
|
|
@@ -11,6 +12,7 @@ import {
|
|
|
11
12
|
GRACEFUL_SHUTDOWN_TIMEOUT
|
|
12
13
|
} from "../../core/dev/lockfile.js";
|
|
13
14
|
import { resolveRoot } from "../../core/config/config.js";
|
|
15
|
+
const require2 = createRequire(import.meta.url);
|
|
14
16
|
function formatBackgroundOutput(result) {
|
|
15
17
|
return JSON.stringify(result);
|
|
16
18
|
}
|
|
@@ -76,7 +78,7 @@ async function background({
|
|
|
76
78
|
}
|
|
77
79
|
const logFd = openSync(logFilePath, "w");
|
|
78
80
|
const rootPath = fileURLToPath(root);
|
|
79
|
-
const astroBin = resolve(
|
|
81
|
+
const astroBin = resolve(dirname(require2.resolve("astro/package.json")), "bin", "astro.mjs");
|
|
80
82
|
const child = spawn(process.execPath, [astroBin, ...args], {
|
|
81
83
|
detached: true,
|
|
82
84
|
stdio: ["ignore", logFd, logFd],
|
|
@@ -197,7 +197,7 @@ ${contentConfig.error.message}`
|
|
|
197
197
|
logger.info("Content config changed");
|
|
198
198
|
shouldClear = true;
|
|
199
199
|
}
|
|
200
|
-
if (previousAstroVersion && previousAstroVersion !== "7.0.
|
|
200
|
+
if (previousAstroVersion && previousAstroVersion !== "7.0.5") {
|
|
201
201
|
logger.info("Astro version changed");
|
|
202
202
|
shouldClear = true;
|
|
203
203
|
}
|
|
@@ -205,8 +205,8 @@ ${contentConfig.error.message}`
|
|
|
205
205
|
logger.info("Clearing content store");
|
|
206
206
|
this.#store.clearAll();
|
|
207
207
|
}
|
|
208
|
-
if ("7.0.
|
|
209
|
-
this.#store.metaStore().set("astro-version", "7.0.
|
|
208
|
+
if ("7.0.5") {
|
|
209
|
+
this.#store.metaStore().set("astro-version", "7.0.5");
|
|
210
210
|
}
|
|
211
211
|
if (currentConfigDigest) {
|
|
212
212
|
this.#store.metaStore().set("content-config-digest", currentConfigDigest);
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
} from "./consts.js";
|
|
24
24
|
import { getDataStoreFile } from "./content-layer.js";
|
|
25
25
|
import { getContentPaths, isDeferredModule } from "./utils.js";
|
|
26
|
+
const LARGE_DATA_STORE_THRESHOLD = 5 * 1024 * 1024;
|
|
26
27
|
function invalidateAssetImports(viteServer, filePath) {
|
|
27
28
|
const timestamp = Date.now();
|
|
28
29
|
for (const environment of Object.values(viteServer.environments)) {
|
|
@@ -70,10 +71,12 @@ function astroContentVirtualModPlugin({
|
|
|
70
71
|
let dataStoreFile;
|
|
71
72
|
let devServer;
|
|
72
73
|
let liveConfig;
|
|
74
|
+
let isDev = false;
|
|
73
75
|
return {
|
|
74
76
|
name: "astro-content-virtual-mod-plugin",
|
|
75
77
|
enforce: "pre",
|
|
76
78
|
config(_, env) {
|
|
79
|
+
isDev = env.command === "serve";
|
|
77
80
|
dataStoreFile = getDataStoreFile(settings, env.command === "serve");
|
|
78
81
|
const contentPaths = getContentPaths(
|
|
79
82
|
settings.config,
|
|
@@ -169,8 +172,9 @@ function astroContentVirtualModPlugin({
|
|
|
169
172
|
const jsonData = await fs.promises.readFile(dataStoreFile, "utf-8");
|
|
170
173
|
try {
|
|
171
174
|
const parsed = JSON.parse(jsonData);
|
|
175
|
+
const useRuntimeJsonParse = isDev && Buffer.byteLength(jsonData) > LARGE_DATA_STORE_THRESHOLD;
|
|
172
176
|
return {
|
|
173
|
-
code: dataToEsm(parsed, {
|
|
177
|
+
code: useRuntimeJsonParse ? `export default JSON.parse(${JSON.stringify(jsonData)})` : dataToEsm(parsed, {
|
|
174
178
|
compact: true
|
|
175
179
|
}),
|
|
176
180
|
map: { mappings: "" }
|
package/dist/core/app/node.js
CHANGED
|
@@ -42,8 +42,13 @@ function createRequestFromNodeRequest(req, {
|
|
|
42
42
|
protocol,
|
|
43
43
|
allowedDomains
|
|
44
44
|
);
|
|
45
|
-
const
|
|
46
|
-
|
|
45
|
+
const validatedForwardedHost = validateForwardedHeaders(
|
|
46
|
+
void 0,
|
|
47
|
+
getFirstForwardedValue(req.headers["x-forwarded-host"]),
|
|
48
|
+
void 0,
|
|
49
|
+
allowedDomains
|
|
50
|
+
).host;
|
|
51
|
+
const hostValidated = validatedHostname !== void 0 || validatedForwardedHost !== void 0;
|
|
47
52
|
const forwardedClientIp = hostValidated ? getFirstForwardedValue(req.headers["x-forwarded-for"]) : void 0;
|
|
48
53
|
const clientIp = forwardedClientIp || req.socket?.remoteAddress;
|
|
49
54
|
if (clientIp) {
|
|
@@ -3,6 +3,7 @@ import { astroHeadBuildPlugin } from "../../../vite-plugin-head/index.js";
|
|
|
3
3
|
import { pluginAnalyzer } from "./plugin-analyzer.js";
|
|
4
4
|
import { pluginComponentEntry } from "./plugin-component-entry.js";
|
|
5
5
|
import { pluginCSS } from "./plugin-css.js";
|
|
6
|
+
import { pluginCssTargetLowering } from "./plugin-css-target-lowering.js";
|
|
6
7
|
import { pluginInternals } from "./plugin-internals.js";
|
|
7
8
|
import { pluginMiddleware } from "./plugin-middleware.js";
|
|
8
9
|
import { pluginPrerender } from "./plugin-prerender.js";
|
|
@@ -18,6 +19,7 @@ function getAllBuildPlugins(internals, options) {
|
|
|
18
19
|
pluginInternals(options, internals),
|
|
19
20
|
pluginMiddleware(options, internals),
|
|
20
21
|
vitePluginActionsBuild(options, internals),
|
|
22
|
+
pluginCssTargetLowering(),
|
|
21
23
|
...pluginCSS(options, internals),
|
|
22
24
|
astroHeadBuildPlugin(internals),
|
|
23
25
|
pluginPrerender(options, internals),
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import type { Plugin as VitePlugin } from 'vite';
|
|
2
|
+
/**
|
|
3
|
+
* Vite plugin that applies CSS target lowering without minification.
|
|
4
|
+
*
|
|
5
|
+
* Vite's `finalizeCss` only applies CSS target lowering (via lightningcss) when
|
|
6
|
+
* `config.build.cssMinify` is truthy, because target lowering and minification
|
|
7
|
+
* are coupled in `minifyCSS`. When users set `minify: false`, Astro forces
|
|
8
|
+
* `cssMinify: false`, which disables target lowering for all CSS.
|
|
9
|
+
*
|
|
10
|
+
* This plugin fills that gap: when `cssMinify` is falsy and a CSS target is
|
|
11
|
+
* configured, it runs lightningcss with `minify: false` on all CSS assets in
|
|
12
|
+
* `generateBundle`, applying target lowering without minification.
|
|
13
|
+
*/
|
|
14
|
+
export declare function pluginCssTargetLowering(): VitePlugin;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { createRequire } from "node:module";
|
|
2
|
+
const BROWSER_MAP = {
|
|
3
|
+
chrome: "chrome",
|
|
4
|
+
edge: "edge",
|
|
5
|
+
firefox: "firefox",
|
|
6
|
+
hermes: false,
|
|
7
|
+
ie: "ie",
|
|
8
|
+
ios: "ios_saf",
|
|
9
|
+
node: false,
|
|
10
|
+
opera: "opera",
|
|
11
|
+
rhino: false,
|
|
12
|
+
safari: "safari"
|
|
13
|
+
};
|
|
14
|
+
const VERSION_RE = /\d/;
|
|
15
|
+
function convertTargets(esbuildTarget) {
|
|
16
|
+
if (!esbuildTarget) return {};
|
|
17
|
+
const targets = {};
|
|
18
|
+
const entries = Array.isArray(esbuildTarget) ? esbuildTarget : [esbuildTarget];
|
|
19
|
+
for (const entry of entries) {
|
|
20
|
+
if (entry === "esnext") continue;
|
|
21
|
+
const index = entry.search(VERSION_RE);
|
|
22
|
+
if (index >= 0) {
|
|
23
|
+
const browserName = entry.slice(0, index);
|
|
24
|
+
const browser = BROWSER_MAP[browserName];
|
|
25
|
+
if (browser === false) continue;
|
|
26
|
+
if (browser) {
|
|
27
|
+
const [major, minor = 0] = entry.slice(index).split(".").map((v) => Number.parseInt(v, 10));
|
|
28
|
+
if (!isNaN(major) && !isNaN(minor)) {
|
|
29
|
+
const version = major << 16 | minor << 8;
|
|
30
|
+
if (!targets[browser] || version < targets[browser]) {
|
|
31
|
+
targets[browser] = version;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return targets;
|
|
38
|
+
}
|
|
39
|
+
function pluginCssTargetLowering() {
|
|
40
|
+
let resolvedConfig;
|
|
41
|
+
return {
|
|
42
|
+
name: "astro:css-target-lowering",
|
|
43
|
+
enforce: "post",
|
|
44
|
+
configResolved(config) {
|
|
45
|
+
resolvedConfig = config;
|
|
46
|
+
},
|
|
47
|
+
async generateBundle(_outputOptions, bundle) {
|
|
48
|
+
if (resolvedConfig.build.cssMinify) return;
|
|
49
|
+
const cssTarget = resolvedConfig.build.cssTarget;
|
|
50
|
+
if (!cssTarget) return;
|
|
51
|
+
const targets = convertTargets(cssTarget);
|
|
52
|
+
if (Object.keys(targets).length === 0) return;
|
|
53
|
+
let lcssTransform;
|
|
54
|
+
try {
|
|
55
|
+
const requireFromVite = createRequire(import.meta.resolve("vite"));
|
|
56
|
+
lcssTransform = requireFromVite("lightningcss").transform;
|
|
57
|
+
} catch {
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
for (const [, asset] of Object.entries(bundle)) {
|
|
61
|
+
if (asset.type !== "asset") continue;
|
|
62
|
+
if (!asset.fileName.endsWith(".css")) continue;
|
|
63
|
+
if (typeof asset.source !== "string") continue;
|
|
64
|
+
try {
|
|
65
|
+
const result = lcssTransform({
|
|
66
|
+
...resolvedConfig.css?.lightningcss,
|
|
67
|
+
targets,
|
|
68
|
+
cssModules: void 0,
|
|
69
|
+
filename: asset.fileName,
|
|
70
|
+
code: Buffer.from(asset.source),
|
|
71
|
+
minify: false
|
|
72
|
+
});
|
|
73
|
+
asset.source = new TextDecoder().decode(result.code);
|
|
74
|
+
} catch {
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
}
|
|
80
|
+
export {
|
|
81
|
+
pluginCssTargetLowering
|
|
82
|
+
};
|
package/dist/core/constants.js
CHANGED
package/dist/core/create-vite.js
CHANGED
|
@@ -201,6 +201,8 @@ async function createVite(commandConfig, { settings, logger, mode, command, fs =
|
|
|
201
201
|
}
|
|
202
202
|
},
|
|
203
203
|
resolve: {
|
|
204
|
+
// Vite's native tsconfig path resolution; see configAliasVitePlugin for the deprecated fallback.
|
|
205
|
+
tsconfigPaths: true,
|
|
204
206
|
alias: [
|
|
205
207
|
{
|
|
206
208
|
// This is needed for Deno compatibility, as the non-browser version
|
package/dist/core/dev/dev.js
CHANGED
|
@@ -26,7 +26,7 @@ async function dev(inlineConfig) {
|
|
|
26
26
|
await telemetry.record([]);
|
|
27
27
|
const restart = await createContainerWithAutomaticRestart({ inlineConfig, fs });
|
|
28
28
|
const logger = restart.container.logger;
|
|
29
|
-
const currentVersion = "7.0.
|
|
29
|
+
const currentVersion = "7.0.5";
|
|
30
30
|
const isPrerelease = currentVersion.includes("-");
|
|
31
31
|
if (!isPrerelease) {
|
|
32
32
|
try {
|
|
@@ -297,6 +297,8 @@ class FetchState {
|
|
|
297
297
|
extraStyleHashes,
|
|
298
298
|
extraScriptHashes,
|
|
299
299
|
propagators: /* @__PURE__ */ new Set(),
|
|
300
|
+
routeHasPropagation: false,
|
|
301
|
+
pendingSlotEvaluations: [],
|
|
300
302
|
templateDepth: 0
|
|
301
303
|
},
|
|
302
304
|
cspDestination: manifest.csp?.cspDestination ?? (routeData.prerender ? "meta" : "header"),
|
|
@@ -3,10 +3,21 @@ export interface HeadPropagator {
|
|
|
3
3
|
init(result: SSRResult): unknown | Promise<unknown>;
|
|
4
4
|
}
|
|
5
5
|
/**
|
|
6
|
-
* Runs all registered propagators and collects
|
|
6
|
+
* Runs all registered propagators and collects the head HTML they emit.
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Components with head content are discovered as we go. Initializing one
|
|
9
|
+
* propagator can register more of them: a component marked `in-tree` renders
|
|
10
|
+
* its children, and one of those children may be a `self` component that emits
|
|
11
|
+
* styles. Slots add a second way to find them — a slot whose markup contains an
|
|
12
|
+
* `await` only reaches the components after that `await` once it resolves, so
|
|
13
|
+
* we also wait for those pending slot pre-renders. We keep initializing
|
|
14
|
+
* propagators and waiting on slots until no new ones appear.
|
|
15
|
+
*
|
|
16
|
+
* Propagators are tracked in a `seen` set rather than read through a single
|
|
17
|
+
* live `Set` iterator. A propagator can be registered after we have already
|
|
18
|
+
* iterated to the end of the set (e.g. once a slot's `await` resolves), and a
|
|
19
|
+
* `Set` iterator that has reported `done` would never report those late
|
|
20
|
+
* additions.
|
|
10
21
|
*
|
|
11
22
|
* @example
|
|
12
23
|
* If a layout initializes and discovers a nested component that also emits
|
|
@@ -1,15 +1,25 @@
|
|
|
1
1
|
async function collectPropagatedHeadParts(input) {
|
|
2
2
|
const collectedHeadParts = [];
|
|
3
|
-
const
|
|
3
|
+
const seen = /* @__PURE__ */ new Set();
|
|
4
|
+
const pendingSlotEvaluations = input.result._metadata?.pendingSlotEvaluations ?? [];
|
|
4
5
|
while (true) {
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
if (pendingSlotEvaluations.length > 0) {
|
|
7
|
+
const batch = pendingSlotEvaluations.splice(0, pendingSlotEvaluations.length);
|
|
8
|
+
await Promise.all(batch);
|
|
9
|
+
continue;
|
|
8
10
|
}
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
let progressed = false;
|
|
12
|
+
for (const propagator of input.propagators) {
|
|
13
|
+
if (seen.has(propagator)) continue;
|
|
14
|
+
seen.add(propagator);
|
|
15
|
+
progressed = true;
|
|
16
|
+
const returnValue = await propagator.init(input.result);
|
|
17
|
+
if (input.isHeadAndContent(returnValue) && returnValue.head) {
|
|
18
|
+
collectedHeadParts.push(returnValue.head);
|
|
19
|
+
}
|
|
20
|
+
break;
|
|
12
21
|
}
|
|
22
|
+
if (!progressed) break;
|
|
13
23
|
}
|
|
14
24
|
return collectedHeadParts;
|
|
15
25
|
}
|
|
@@ -18,8 +18,13 @@ interface RouteCacheEntry {
|
|
|
18
18
|
}
|
|
19
19
|
/**
|
|
20
20
|
* Manage the route cache, responsible for caching data related to each route,
|
|
21
|
-
* including the result of calling
|
|
22
|
-
*
|
|
21
|
+
* including the result of calling getStaticPaths(). This gives route matching,
|
|
22
|
+
* params/props resolution, and prerender generation a shared static-path table.
|
|
23
|
+
*
|
|
24
|
+
* In dev, this cache intentionally survives requests. It is invalidated by route
|
|
25
|
+
* module identity changes after HMR or by explicit cache clears from content data
|
|
26
|
+
* changes, not by each request. Dev route matching can call getStaticPaths()
|
|
27
|
+
* before rendering, and render-time props resolution may ask for it again.
|
|
23
28
|
*/
|
|
24
29
|
export declare class RouteCache {
|
|
25
30
|
private logger;
|
|
@@ -158,13 +158,14 @@ function createFileBasedRoutes({ settings, cwd, fsMod }, logger) {
|
|
|
158
158
|
} else {
|
|
159
159
|
const component = item.file;
|
|
160
160
|
const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
|
|
161
|
+
const route = joinSegments(segments);
|
|
161
162
|
const trailingSlash = trailingSlashForPath(
|
|
162
163
|
pathname,
|
|
163
164
|
settings.config,
|
|
164
|
-
item.isPage ? "page" : "endpoint"
|
|
165
|
+
item.isPage ? "page" : "endpoint",
|
|
166
|
+
route
|
|
165
167
|
);
|
|
166
168
|
const pattern = getPattern(segments, settings.config.base, trailingSlash);
|
|
167
|
-
const route = joinSegments(segments);
|
|
168
169
|
routes.push({
|
|
169
170
|
route,
|
|
170
171
|
isIndex: item.isIndex,
|
|
@@ -277,13 +278,14 @@ function createRoutesFromEntriesByDir(entriesByDir, settings, logger, pagesDirRe
|
|
|
277
278
|
} else {
|
|
278
279
|
const component = item.file;
|
|
279
280
|
const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
|
|
281
|
+
const route = joinSegments(segments);
|
|
280
282
|
const trailingSlash = trailingSlashForPath(
|
|
281
283
|
pathname,
|
|
282
284
|
settings.config,
|
|
283
|
-
item.isPage ? "page" : "endpoint"
|
|
285
|
+
item.isPage ? "page" : "endpoint",
|
|
286
|
+
route
|
|
284
287
|
);
|
|
285
288
|
const pattern = getPattern(segments, settings.config.base, trailingSlash);
|
|
286
|
-
const route = joinSegments(segments);
|
|
287
289
|
routes.push({
|
|
288
290
|
route,
|
|
289
291
|
isIndex: item.isIndex,
|
|
@@ -320,7 +322,7 @@ function groupEntriesByDir(entries) {
|
|
|
320
322
|
}
|
|
321
323
|
return entriesByDir;
|
|
322
324
|
}
|
|
323
|
-
const trailingSlashForPath = (pathname, config, type) => type === "endpoint" && pathname
|
|
325
|
+
const trailingSlashForPath = (pathname, config, type, route) => type === "endpoint" && hasFileExtension(pathname ?? route ?? "") ? "never" : config.trailingSlash;
|
|
324
326
|
function createInjectedRoutes({ settings, cwd }) {
|
|
325
327
|
const { config } = settings;
|
|
326
328
|
const prerender = getPrerenderDefault(config);
|
|
@@ -334,10 +336,10 @@ function createInjectedRoutes({ settings, cwd }) {
|
|
|
334
336
|
});
|
|
335
337
|
const type = resolved.endsWith(".astro") ? "page" : "endpoint";
|
|
336
338
|
const pathname = segments.every((segment) => segment.length === 1 && !segment[0].dynamic) ? `/${segments.map((segment) => segment[0].content).join("/")}` : null;
|
|
337
|
-
const
|
|
339
|
+
const route = joinSegments(segments);
|
|
340
|
+
const trailingSlash = trailingSlashForPath(pathname, config, type, route);
|
|
338
341
|
const pattern = getPattern(segments, settings.config.base, trailingSlash);
|
|
339
342
|
const params = segments.flat().filter((p) => p.dynamic).map((p) => p.content);
|
|
340
|
-
const route = joinSegments(segments);
|
|
341
343
|
routes.push({
|
|
342
344
|
type,
|
|
343
345
|
// For backwards compatibility, an injected route is never considered an index route.
|
package/dist/prefetch/index.js
CHANGED
|
@@ -191,6 +191,16 @@ function onPageLoad(cb) {
|
|
|
191
191
|
}
|
|
192
192
|
cb();
|
|
193
193
|
});
|
|
194
|
+
new MutationObserver((mutations) => {
|
|
195
|
+
for (const mutation of mutations) {
|
|
196
|
+
for (const node of mutation.addedNodes) {
|
|
197
|
+
if (node instanceof Element && (node.tagName === "A" || node.querySelector?.("a"))) {
|
|
198
|
+
cb();
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}).observe(document.body, { childList: true, subtree: true });
|
|
194
204
|
}
|
|
195
205
|
function appendSpeculationRules(url, eagerness) {
|
|
196
206
|
const script = document.createElement("script");
|
|
@@ -200,6 +200,32 @@ function isInteractive(element) {
|
|
|
200
200
|
}
|
|
201
201
|
return true;
|
|
202
202
|
}
|
|
203
|
+
function hasAccessibleName(element) {
|
|
204
|
+
return element.hasAttribute("aria-label") || element.hasAttribute("aria-labelledby");
|
|
205
|
+
}
|
|
206
|
+
const conditional_implicit_roles = /* @__PURE__ */ new Map([
|
|
207
|
+
["a", (el) => el.hasAttribute("href") ? "link" : null],
|
|
208
|
+
[
|
|
209
|
+
"aside",
|
|
210
|
+
(el) => {
|
|
211
|
+
const isNested = !!el.parentElement?.closest("article, aside, nav, section");
|
|
212
|
+
return !isNested || hasAccessibleName(el) ? "complementary" : null;
|
|
213
|
+
}
|
|
214
|
+
],
|
|
215
|
+
[
|
|
216
|
+
"img",
|
|
217
|
+
(el) => {
|
|
218
|
+
if (el.getAttribute("alt") === "") return null;
|
|
219
|
+
return "image";
|
|
220
|
+
}
|
|
221
|
+
],
|
|
222
|
+
[
|
|
223
|
+
"section",
|
|
224
|
+
(el) => {
|
|
225
|
+
return hasAccessibleName(el) ? "region" : null;
|
|
226
|
+
}
|
|
227
|
+
]
|
|
228
|
+
]);
|
|
203
229
|
const a11y = [
|
|
204
230
|
{
|
|
205
231
|
code: "a11y-accesskey",
|
|
@@ -378,19 +404,33 @@ const a11y = [
|
|
|
378
404
|
code: "a11y-no-redundant-roles",
|
|
379
405
|
title: "HTML element has redundant ARIA roles",
|
|
380
406
|
message: "Giving these elements an ARIA role that is already set by the browser has no effect and is redundant.",
|
|
381
|
-
selector
|
|
407
|
+
// The selector is all elements that have an implicit role, as well as input elements since their implicit role can change based on their attributes
|
|
408
|
+
selector: `[role]:is(${[...a11y_implicit_semantics.keys()].join(",")},input)`,
|
|
382
409
|
match(element) {
|
|
383
410
|
const role = element.getAttribute("role");
|
|
384
|
-
if (
|
|
385
|
-
|
|
386
|
-
|
|
411
|
+
if (!role) return false;
|
|
412
|
+
const localName = element.localName;
|
|
413
|
+
if (
|
|
414
|
+
// <ul>, <ol>, and <li> are legitimate workarounds to restore list semantics
|
|
415
|
+
// that some browsers (e.g., Safari) strip when CSS `list-style: none` is applied.
|
|
416
|
+
// Reference: https://bugs.webkit.org/show_bug.cgi?id=170179
|
|
417
|
+
localName === "ul" && role === "list" || localName === "ol" && role === "list" || localName === "li" && role === "listitem"
|
|
418
|
+
) {
|
|
419
|
+
return false;
|
|
420
|
+
}
|
|
421
|
+
if (localName === "input") {
|
|
422
|
+
const type = element.getAttribute("type") || "text";
|
|
387
423
|
const implicitRoleForType = input_type_to_implicit_role.get(type);
|
|
388
|
-
|
|
389
|
-
|
|
424
|
+
return role === implicitRoleForType;
|
|
425
|
+
}
|
|
426
|
+
const getConditionalRole = conditional_implicit_roles.get(localName);
|
|
427
|
+
if (getConditionalRole) {
|
|
428
|
+
const effectiveRole = getConditionalRole(element);
|
|
429
|
+
return effectiveRole ? role === effectiveRole : false;
|
|
390
430
|
}
|
|
391
|
-
const implicitRole = a11y_implicit_semantics.get(
|
|
392
|
-
if (!implicitRole) return
|
|
393
|
-
|
|
431
|
+
const implicitRole = a11y_implicit_semantics.get(localName);
|
|
432
|
+
if (!implicitRole) return false;
|
|
433
|
+
return role === implicitRole;
|
|
394
434
|
}
|
|
395
435
|
},
|
|
396
436
|
{
|
|
@@ -116,7 +116,7 @@ async function generateHydrateScript(scriptOptions, metadata) {
|
|
|
116
116
|
);
|
|
117
117
|
transitionDirectivesToCopyOnIsland.forEach((name) => {
|
|
118
118
|
if (typeof props[name] !== "undefined") {
|
|
119
|
-
island.props[name] = props[name];
|
|
119
|
+
island.props[name] = escapeHTML(String(props[name]));
|
|
120
120
|
}
|
|
121
121
|
});
|
|
122
122
|
return island;
|
|
@@ -18,6 +18,9 @@ class AstroComponentInstance {
|
|
|
18
18
|
for (const name in slots) {
|
|
19
19
|
let didRender = false;
|
|
20
20
|
let value = slots[name](result);
|
|
21
|
+
if (result._metadata.routeHasPropagation && isPromise(value)) {
|
|
22
|
+
result._metadata.pendingSlotEvaluations.push(value);
|
|
23
|
+
}
|
|
21
24
|
this.slotValues[name] = () => {
|
|
22
25
|
if (!didRender) {
|
|
23
26
|
didRender = true;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { isRoute404, isRoute500 } from "../../../core/routing/internal/route-errors.js";
|
|
2
|
+
import { isPropagatingHint } from "../../../core/head-propagation/resolver.js";
|
|
2
3
|
import { renderToAsyncIterable, renderToReadableStream, renderToString } from "./astro/render.js";
|
|
3
4
|
import { encoder } from "./common.js";
|
|
4
5
|
import { renderComponentToString } from "./component.js";
|
|
@@ -7,7 +8,9 @@ import { isDeno, isNode } from "./util.js";
|
|
|
7
8
|
import { isAstroComponentFactory } from "./astro/factory.js";
|
|
8
9
|
async function renderPage(result, componentFactory, props, children, streaming, route) {
|
|
9
10
|
if (!isAstroComponentFactory(componentFactory)) {
|
|
10
|
-
|
|
11
|
+
const nonAstroMeta = result.componentMetadata.get(componentFactory.moduleId);
|
|
12
|
+
result._metadata.headInTree = nonAstroMeta?.containsHead ?? false;
|
|
13
|
+
result._metadata.routeHasPropagation = isPropagatingHint(nonAstroMeta?.propagation ?? "none");
|
|
11
14
|
const pageProps = { ...props ?? {}, "server:root": true };
|
|
12
15
|
const str = await renderComponentToString(
|
|
13
16
|
result,
|
|
@@ -31,7 +34,9 @@ async function renderPage(result, componentFactory, props, children, streaming,
|
|
|
31
34
|
status: result.response.status
|
|
32
35
|
});
|
|
33
36
|
}
|
|
34
|
-
|
|
37
|
+
const pageMeta = result.componentMetadata.get(componentFactory.moduleId);
|
|
38
|
+
result._metadata.headInTree = pageMeta?.containsHead ?? false;
|
|
39
|
+
result._metadata.routeHasPropagation = isPropagatingHint(pageMeta?.propagation ?? "none");
|
|
35
40
|
let body;
|
|
36
41
|
if (streaming) {
|
|
37
42
|
if (isNode && !isDeno) {
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const SERVER_ISLAND_START = "[if astro]>server-island-start<![endif]";
|
|
@@ -3,6 +3,7 @@ import { markHTMLString, stringifyForScript } from "../escape.js";
|
|
|
3
3
|
import { renderChild } from "./any.js";
|
|
4
4
|
import { createThinHead } from "./astro/head-and-content.js";
|
|
5
5
|
import { createRenderInstruction } from "./instruction.js";
|
|
6
|
+
import { SERVER_ISLAND_START } from "./server-islands-shared.js";
|
|
6
7
|
import { renderSlotToString } from "./slot.js";
|
|
7
8
|
const internalProps = /* @__PURE__ */ new Set([
|
|
8
9
|
"server:component-path",
|
|
@@ -56,7 +57,7 @@ class ServerIslandComponent {
|
|
|
56
57
|
const hostId = await this.getHostId();
|
|
57
58
|
const islandContent = await this.getIslandContent();
|
|
58
59
|
destination.write(createRenderInstruction({ type: "server-island-runtime" }));
|
|
59
|
-
destination.write(
|
|
60
|
+
destination.write(`<!--${SERVER_ISLAND_START}-->`);
|
|
60
61
|
for (const name in this.slots) {
|
|
61
62
|
if (name === "fallback") {
|
|
62
63
|
await renderChild(destination, this.slots.fallback(this.result));
|
|
@@ -186,7 +187,7 @@ const SERVER_ISLAND_REPLACER = markHTMLString(
|
|
|
186
187
|
// Load the HTML before modifying the DOM in case of errors
|
|
187
188
|
let html = await r.text();
|
|
188
189
|
// Remove any placeholder content before the island script
|
|
189
|
-
while (s.previousSibling && s.previousSibling.nodeType !== 8 && s.previousSibling.data !== '
|
|
190
|
+
while (s.previousSibling && s.previousSibling.nodeType !== 8 && s.previousSibling.data !== '${SERVER_ISLAND_START}')
|
|
190
191
|
s.previousSibling.remove();
|
|
191
192
|
s.previousSibling?.remove();
|
|
192
193
|
// Insert the new HTML
|
package/dist/template/4xx.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { SERVER_ISLAND_START } from "../runtime/server/render/server-islands-shared.js";
|
|
1
2
|
const PERSIST_ATTR = "data-astro-transition-persist";
|
|
2
3
|
const NON_OVERRIDABLE_ASTRO_ATTRS = ["data-astro-transition", "data-astro-transition-fallback"];
|
|
3
4
|
const knownVueScopedStyles = /* @__PURE__ */ new Map();
|
|
@@ -29,6 +30,11 @@ function swapRootAttributes(newDoc) {
|
|
|
29
30
|
);
|
|
30
31
|
}
|
|
31
32
|
function swapHeadElements(doc) {
|
|
33
|
+
const relevantNodes = (parent, what = "both") => [
|
|
34
|
+
...[...parent.childNodes].filter(
|
|
35
|
+
(child) => child.nodeType === 8 && child.textContent === SERVER_ISLAND_START || what === "both" && child.nodeType === 1
|
|
36
|
+
)
|
|
37
|
+
];
|
|
32
38
|
for (const el of Array.from(document.head.children)) {
|
|
33
39
|
const newEl = persistedHeadElement(el, doc);
|
|
34
40
|
if (newEl) {
|
|
@@ -41,12 +47,13 @@ function swapHeadElements(doc) {
|
|
|
41
47
|
el.remove();
|
|
42
48
|
}
|
|
43
49
|
}
|
|
50
|
+
relevantNodes(document.head, "commentsOnly").forEach((node) => node.remove());
|
|
44
51
|
if (import.meta.env.DEV) {
|
|
45
|
-
|
|
52
|
+
relevantNodes(doc.head).forEach((child) => {
|
|
46
53
|
document.head.append(knownVueScopedStyles.get(child.dataset?.viteDevId) || child);
|
|
47
54
|
});
|
|
48
55
|
} else {
|
|
49
|
-
document.head.append(...doc.head
|
|
56
|
+
document.head.append(...relevantNodes(doc.head));
|
|
50
57
|
}
|
|
51
58
|
}
|
|
52
59
|
function swapBodyElement(newElement, oldElement) {
|
|
@@ -280,6 +280,20 @@ export interface SSRMetadata {
|
|
|
280
280
|
extraStyleHashes: string[];
|
|
281
281
|
extraScriptHashes: string[];
|
|
282
282
|
propagators: Set<AstroComponentInstance | ServerIslandComponent>;
|
|
283
|
+
/**
|
|
284
|
+
* `true` when the page being rendered is on a head-propagation path (its
|
|
285
|
+
* component metadata hint is `in-tree`/`self`). Only then do we await async
|
|
286
|
+
* slot pre-renders before collecting head content, so that propagating
|
|
287
|
+
* components hidden behind an `await` in slot markup are discovered in time.
|
|
288
|
+
* Pages with no propagation keep streaming without paying that cost.
|
|
289
|
+
*/
|
|
290
|
+
routeHasPropagation: boolean;
|
|
291
|
+
/**
|
|
292
|
+
* Promises from async slot pre-renders that may still need to register
|
|
293
|
+
* propagating components. Drained by `collectPropagatedHeadParts` before
|
|
294
|
+
* head content is flushed. Only populated when `routeHasPropagation` is true.
|
|
295
|
+
*/
|
|
296
|
+
pendingSlotEvaluations: Promise<unknown>[];
|
|
283
297
|
/**
|
|
284
298
|
* Tracks nesting depth of HTML `<template>` elements during rendering.
|
|
285
299
|
* Scripts rendered inside `<template>` tags should not be deduplicated,
|
|
@@ -55,7 +55,9 @@ function astro({ settings, logger }) {
|
|
|
55
55
|
viteConfig.resolve.conditions = [...defaultServerConditions];
|
|
56
56
|
}
|
|
57
57
|
}
|
|
58
|
-
viteConfig.resolve.conditions.
|
|
58
|
+
if (!viteConfig.resolve.conditions.includes("astro")) {
|
|
59
|
+
viteConfig.resolve.conditions.push("astro");
|
|
60
|
+
}
|
|
59
61
|
},
|
|
60
62
|
async configResolved(viteConfig) {
|
|
61
63
|
const toolbarEnabled = await settings.preferences.get("devToolbar.enabled");
|
|
@@ -1,6 +1,24 @@
|
|
|
1
1
|
import { type Plugin as VitePlugin } from 'vite';
|
|
2
2
|
import type { AstroSettings } from '../types/astro.js';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Fallback for tsconfig path aliases that Vite's `resolve.tsconfigPaths` does
|
|
5
|
+
* not currently handle in Astro's pipeline.
|
|
6
|
+
*
|
|
7
|
+
* This plugin is intentionally limited to the syntax Astro already supported
|
|
8
|
+
* before enabling `resolve.tsconfigPaths`:
|
|
9
|
+
* - CSS: `@import "..."`
|
|
10
|
+
* - CSS: `@import url("...")`
|
|
11
|
+
* - CSS: quoted `url("...")` references
|
|
12
|
+
* - Modules: JS, TS, and Astro import specifiers handled by `resolveId`
|
|
13
|
+
*
|
|
14
|
+
* Do not expand this fallback to new CSS at-rules or preprocessor syntax. It
|
|
15
|
+
* does not support `@use`, `@forward`, `@reference`, `@config`, unquoted
|
|
16
|
+
* `url(...)`, or every place a CSS tool might accept a file path. Those should
|
|
17
|
+
* be handled by Vite's native resolver instead.
|
|
18
|
+
*
|
|
19
|
+
* @deprecated This fallback will be removed in a future Astro version once Vite
|
|
20
|
+
* handles these remaining alias paths.
|
|
21
|
+
*/
|
|
4
22
|
export default function configAliasVitePlugin({ settings, }: {
|
|
5
23
|
settings: AstroSettings;
|
|
6
24
|
}): VitePlugin[] | null;
|
|
@@ -51,10 +51,10 @@ function configAliasVitePlugin({
|
|
|
51
51
|
const configAlias = getConfigAlias(settings);
|
|
52
52
|
if (!configAlias) return null;
|
|
53
53
|
return [
|
|
54
|
-
//
|
|
55
|
-
//
|
|
56
|
-
//
|
|
57
|
-
//
|
|
54
|
+
// Deprecated CSS fallback for Vite's transform pipeline. Only supports
|
|
55
|
+
// `@import "..."`, `@import url("...")`, and quoted `url("...")`.
|
|
56
|
+
// Do not add support here for `@use`, `@forward`, `@reference`, `@config`,
|
|
57
|
+
// or other CSS/preprocessor file-reference syntax.
|
|
58
58
|
{
|
|
59
59
|
name: "astro:tsconfig-alias-css",
|
|
60
60
|
enforce: "pre",
|
|
@@ -88,7 +88,8 @@ function configAliasVitePlugin({
|
|
|
88
88
|
}
|
|
89
89
|
}
|
|
90
90
|
},
|
|
91
|
-
//
|
|
91
|
+
// Deprecated module fallback for JS, TS, and Astro import specifiers that
|
|
92
|
+
// Vite's native tsconfig path resolution does not currently resolve.
|
|
92
93
|
{
|
|
93
94
|
name: "astro:tsconfig-alias",
|
|
94
95
|
// use post to only resolve ids that all other plugins before it can't
|
|
@@ -1,13 +1,15 @@
|
|
|
1
1
|
import MagicString from "magic-string";
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import escape from "./escape.js";
|
|
5
|
-
import slots, { SLOT_PREFIX } from "./slots.js";
|
|
2
|
+
import { collectSlots, SLOT_PREFIX } from "./slots.js";
|
|
3
|
+
import { escapeTemplateLiteralCharacters, needsEscape } from "./utils.js";
|
|
6
4
|
async function transform(code, id) {
|
|
7
5
|
const s = new MagicString(code, { filename: id });
|
|
8
|
-
|
|
9
|
-
const
|
|
10
|
-
|
|
6
|
+
let cursor = 0;
|
|
7
|
+
for (const slot of collectSlots(code)) {
|
|
8
|
+
escapeRange(s, code, cursor, slot.start);
|
|
9
|
+
s.overwrite(slot.start, slot.end, slot.value);
|
|
10
|
+
cursor = slot.end;
|
|
11
|
+
}
|
|
12
|
+
escapeRange(s, code, cursor, code.length);
|
|
11
13
|
s.prepend(`function render({ slots: ${SLOT_PREFIX} }) {
|
|
12
14
|
return \``);
|
|
13
15
|
s.append('`\n }\nrender["astro:html"] = true;\nexport default render;');
|
|
@@ -16,6 +18,13 @@ async function transform(code, id) {
|
|
|
16
18
|
map: s.generateMap({ hires: "boundary" })
|
|
17
19
|
};
|
|
18
20
|
}
|
|
21
|
+
function escapeRange(s, code, start, end) {
|
|
22
|
+
if (start >= end) return;
|
|
23
|
+
const segment = code.slice(start, end);
|
|
24
|
+
if (needsEscape(segment)) {
|
|
25
|
+
s.overwrite(start, end, escapeTemplateLiteralCharacters(segment));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
19
28
|
export {
|
|
20
29
|
transform
|
|
21
30
|
};
|
|
@@ -1,8 +1,11 @@
|
|
|
1
|
-
import type { Root } from 'hast';
|
|
2
|
-
import type MagicString from 'magic-string';
|
|
3
|
-
import type { Plugin } from 'unified';
|
|
4
|
-
declare const rehypeSlots: Plugin<[{
|
|
5
|
-
s: MagicString;
|
|
6
|
-
}], Root>;
|
|
7
|
-
export default rehypeSlots;
|
|
8
1
|
export declare const SLOT_PREFIX = "___SLOTS___";
|
|
2
|
+
export interface SlotReplacement {
|
|
3
|
+
start: number;
|
|
4
|
+
end: number;
|
|
5
|
+
value: string;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Find every `<slot>` (excluding `is:inline` ones) and describe how to replace it
|
|
9
|
+
* with a `${___SLOTS___[name] ?? `fallback`}` template literal expression.
|
|
10
|
+
*/
|
|
11
|
+
export declare function collectSlots(code: string): SlotReplacement[];
|
|
@@ -1,31 +1,24 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ELEMENT_NODE, parse, walkSync } from "ultrahtml";
|
|
2
2
|
import { escapeTemplateLiteralCharacters } from "./utils.js";
|
|
3
|
-
const rehypeSlots = ({ s }) => {
|
|
4
|
-
return (tree, file) => {
|
|
5
|
-
visit(tree, (node) => {
|
|
6
|
-
if (node.type === "element" && node.tagName === "slot") {
|
|
7
|
-
if (typeof node.properties?.["is:inline"] !== "undefined") return;
|
|
8
|
-
const name = node.properties?.["name"] ?? "default";
|
|
9
|
-
const start = node.position?.start.offset ?? 0;
|
|
10
|
-
const end = node.position?.end.offset ?? 0;
|
|
11
|
-
const first = node.children.at(0) ?? node;
|
|
12
|
-
const last = node.children.at(-1) ?? node;
|
|
13
|
-
const text = file.value.slice(
|
|
14
|
-
first.position?.start.offset ?? 0,
|
|
15
|
-
last.position?.end.offset ?? 0
|
|
16
|
-
).toString();
|
|
17
|
-
s.overwrite(
|
|
18
|
-
start,
|
|
19
|
-
end,
|
|
20
|
-
`\${${SLOT_PREFIX}["${name}"] ?? \`${escapeTemplateLiteralCharacters(text).trim()}\`}`
|
|
21
|
-
);
|
|
22
|
-
}
|
|
23
|
-
});
|
|
24
|
-
};
|
|
25
|
-
};
|
|
26
|
-
var slots_default = rehypeSlots;
|
|
27
3
|
const SLOT_PREFIX = `___SLOTS___`;
|
|
4
|
+
function collectSlots(code) {
|
|
5
|
+
const slots = [];
|
|
6
|
+
walkSync(parse(code), (node) => {
|
|
7
|
+
if (node.type !== ELEMENT_NODE || node.name !== "slot") return;
|
|
8
|
+
if ("is:inline" in node.attributes) return;
|
|
9
|
+
const [open, close] = node.loc;
|
|
10
|
+
if (!close) return;
|
|
11
|
+
const name = node.attributes.name ?? "default";
|
|
12
|
+
const fallback = open.end < close.start ? code.slice(open.end, close.start) : code.slice(open.start, close.end);
|
|
13
|
+
slots.push({
|
|
14
|
+
start: open.start,
|
|
15
|
+
end: close.end,
|
|
16
|
+
value: `\${${SLOT_PREFIX}["${name}"] ?? \`${escapeTemplateLiteralCharacters(fallback).trim()}\`}`
|
|
17
|
+
});
|
|
18
|
+
});
|
|
19
|
+
return slots;
|
|
20
|
+
}
|
|
28
21
|
export {
|
|
29
22
|
SLOT_PREFIX,
|
|
30
|
-
|
|
23
|
+
collectSlots
|
|
31
24
|
};
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
import type { Element } from 'hast';
|
|
2
|
-
import type MagicString from 'magic-string';
|
|
3
|
-
export declare function replaceAttribute(s: MagicString, node: Element, key: string, newValue: string): MagicString | undefined;
|
|
4
1
|
export declare function needsEscape(value: any): value is string;
|
|
5
2
|
export declare function escapeTemplateLiteralCharacters(value: string): string;
|
|
@@ -1,21 +1,3 @@
|
|
|
1
|
-
const splitAttrsTokenizer = /([${}@\w:\-]*)\s*=\s*?(['"]?)(.*?)\2\s+/g;
|
|
2
|
-
function replaceAttribute(s, node, key, newValue) {
|
|
3
|
-
splitAttrsTokenizer.lastIndex = 0;
|
|
4
|
-
const text = s.original.slice(node.position?.start.offset ?? 0, node.position?.end.offset ?? 0).toString();
|
|
5
|
-
const offset = text.indexOf(key);
|
|
6
|
-
if (offset === -1) return;
|
|
7
|
-
const start = node.position.start.offset + offset;
|
|
8
|
-
const tokens = text.slice(offset).split(splitAttrsTokenizer);
|
|
9
|
-
const token = tokens[0].replace(/([^>])>[\s\S]*$/gm, "$1");
|
|
10
|
-
if (token.trim() === key) {
|
|
11
|
-
const end = start + key.length;
|
|
12
|
-
return s.overwrite(start, end, newValue, { contentOnly: true });
|
|
13
|
-
} else {
|
|
14
|
-
const length = token.length;
|
|
15
|
-
const end = start + length;
|
|
16
|
-
return s.overwrite(start, end, newValue, { contentOnly: true });
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
1
|
const NEEDS_ESCAPE_RE = /[`\\]|\$\{/g;
|
|
20
2
|
function needsEscape(value) {
|
|
21
3
|
NEEDS_ESCAPE_RE.lastIndex = 0;
|
|
@@ -42,6 +24,5 @@ function escapeTemplateLiteralCharacters(value) {
|
|
|
42
24
|
}
|
|
43
25
|
export {
|
|
44
26
|
escapeTemplateLiteralCharacters,
|
|
45
|
-
needsEscape
|
|
46
|
-
replaceAttribute
|
|
27
|
+
needsEscape
|
|
47
28
|
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "astro",
|
|
3
|
-
"version": "7.0.
|
|
3
|
+
"version": "7.0.5",
|
|
4
4
|
"description": "Astro is a modern site builder with web best practices, performance, and DX front-of-mind.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"author": "withastro",
|
|
@@ -12,23 +12,6 @@
|
|
|
12
12
|
},
|
|
13
13
|
"bugs": "https://github.com/withastro/astro/issues",
|
|
14
14
|
"homepage": "https://astro.build",
|
|
15
|
-
"types": "./dist/index.d.ts",
|
|
16
|
-
"typesVersions": {
|
|
17
|
-
"*": {
|
|
18
|
-
"app": [
|
|
19
|
-
"./dist/core/app/index"
|
|
20
|
-
],
|
|
21
|
-
"app/*": [
|
|
22
|
-
"./dist/core/app/*"
|
|
23
|
-
],
|
|
24
|
-
"hono": [
|
|
25
|
-
"./dist/core/hono/index"
|
|
26
|
-
],
|
|
27
|
-
"middleware": [
|
|
28
|
-
"./dist/virtual-modules/middleware.d.ts"
|
|
29
|
-
]
|
|
30
|
-
}
|
|
31
|
-
},
|
|
32
15
|
"exports": {
|
|
33
16
|
".": "./dist/index.js",
|
|
34
17
|
"./env": "./env.d.ts",
|
|
@@ -113,7 +96,7 @@
|
|
|
113
96
|
"README.md"
|
|
114
97
|
],
|
|
115
98
|
"dependencies": {
|
|
116
|
-
"@astrojs/compiler-rs": "^0.
|
|
99
|
+
"@astrojs/compiler-rs": "^0.3.0",
|
|
117
100
|
"@capsizecss/unpack": "^4.0.0",
|
|
118
101
|
"@clack/prompts": "^1.1.0",
|
|
119
102
|
"@oslojs/encoding": "^1.1.0",
|
|
@@ -148,7 +131,6 @@
|
|
|
148
131
|
"package-manager-detector": "^1.6.0",
|
|
149
132
|
"piccolore": "^0.1.3",
|
|
150
133
|
"picomatch": "^4.0.4",
|
|
151
|
-
"rehype": "^13.0.2",
|
|
152
134
|
"semver": "^7.7.4",
|
|
153
135
|
"shiki": "^4.0.2",
|
|
154
136
|
"smol-toml": "^1.6.0",
|
|
@@ -158,20 +140,18 @@
|
|
|
158
140
|
"tinyglobby": "^0.2.15",
|
|
159
141
|
"ultrahtml": "^1.6.0",
|
|
160
142
|
"unifont": "~0.7.4",
|
|
161
|
-
"unist-util-visit": "^5.1.0",
|
|
162
143
|
"unstorage": "^1.17.5",
|
|
163
|
-
"vfile": "^6.0.3",
|
|
164
144
|
"vite": "^8.0.13",
|
|
165
145
|
"vitefu": "^1.1.2",
|
|
166
146
|
"xxhash-wasm": "^1.1.0",
|
|
167
147
|
"yargs-parser": "^22.0.0",
|
|
168
148
|
"zod": "^4.3.6",
|
|
169
|
-
"@astrojs/markdown-satteri": "0.3.2",
|
|
170
149
|
"@astrojs/internal-helpers": "0.10.0",
|
|
150
|
+
"@astrojs/markdown-satteri": "0.3.2",
|
|
171
151
|
"@astrojs/telemetry": "3.3.2"
|
|
172
152
|
},
|
|
173
153
|
"optionalDependencies": {
|
|
174
|
-
"sharp": "^0.34.0"
|
|
154
|
+
"sharp": "^0.34.0 || ^0.35.0"
|
|
175
155
|
},
|
|
176
156
|
"peerDependencies": {
|
|
177
157
|
"@astrojs/markdown-remark": "7.2.0"
|
|
@@ -184,7 +164,6 @@
|
|
|
184
164
|
"devDependencies": {
|
|
185
165
|
"@playwright/test": "1.58.2",
|
|
186
166
|
"@types/aria-query": "^5.0.4",
|
|
187
|
-
"@types/hast": "^3.0.4",
|
|
188
167
|
"@types/html-escaper": "3.0.4",
|
|
189
168
|
"@types/http-cache-semantics": "^4.2.0",
|
|
190
169
|
"@types/js-yaml": "^4.0.9",
|
|
@@ -206,7 +185,6 @@
|
|
|
206
185
|
"sass": "^1.98.0",
|
|
207
186
|
"typescript": "^6.0.3",
|
|
208
187
|
"undici": "^7.22.0",
|
|
209
|
-
"unified": "^11.0.5",
|
|
210
188
|
"vitest": "^4.1.0",
|
|
211
189
|
"@astrojs/check": "0.9.9",
|
|
212
190
|
"@astrojs/markdown-remark": "7.2.0",
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import { visit } from "unist-util-visit";
|
|
2
|
-
import { escapeTemplateLiteralCharacters, needsEscape, replaceAttribute } from "./utils.js";
|
|
3
|
-
const rehypeEscape = ({ s }) => {
|
|
4
|
-
return (tree) => {
|
|
5
|
-
visit(tree, (node) => {
|
|
6
|
-
if (node.type === "text" || node.type === "comment") {
|
|
7
|
-
if (needsEscape(node.value)) {
|
|
8
|
-
s.overwrite(
|
|
9
|
-
node.position.start.offset,
|
|
10
|
-
node.position.end.offset,
|
|
11
|
-
escapeTemplateLiteralCharacters(node.value)
|
|
12
|
-
);
|
|
13
|
-
}
|
|
14
|
-
} else if (node.type === "element") {
|
|
15
|
-
if (!node.properties) return;
|
|
16
|
-
for (let [key, value] of Object.entries(node.properties)) {
|
|
17
|
-
key = key.replace(/([A-Z])/g, "-$1").toLowerCase();
|
|
18
|
-
const newKey = needsEscape(key) ? escapeTemplateLiteralCharacters(key) : key;
|
|
19
|
-
const newValue = needsEscape(value) ? escapeTemplateLiteralCharacters(value) : value;
|
|
20
|
-
if (newKey === key && newValue === value) continue;
|
|
21
|
-
replaceAttribute(s, node, key, value === "" ? newKey : `${newKey}="${newValue}"`);
|
|
22
|
-
}
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
var escape_default = rehypeEscape;
|
|
28
|
-
export {
|
|
29
|
-
escape_default as default
|
|
30
|
-
};
|