mirror of
https://github.com/withastro/astro.git
synced 2025-03-17 23:11:29 -05:00
Merge branch 'main' into astro-dot-session
This commit is contained in:
commit
a6b59b9791
12 changed files with 74 additions and 27 deletions
5
.changeset/bright-gifts-prove.md
Normal file
5
.changeset/bright-gifts-prove.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
"astro": patch
|
||||
---
|
||||
|
||||
Updates a reference in an error message
|
5
.changeset/unlucky-wasps-refuse.md
Normal file
5
.changeset/unlucky-wasps-refuse.md
Normal file
|
@ -0,0 +1,5 @@
|
|||
---
|
||||
'@astrojs/markdown-remark': patch
|
||||
---
|
||||
|
||||
Fixes frontmatter parsing if file is encoded in UTF8 with BOM
|
|
@ -260,7 +260,6 @@ export class App {
|
|||
this.#logger.error(null, error.stack!);
|
||||
return this.#renderError(request, { status: 500, error, clientAddress });
|
||||
}
|
||||
Reflect.set(request, clientLocalsSymbol, locals);
|
||||
}
|
||||
if (!routeData) {
|
||||
routeData = this.match(request);
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { setGetEnv } from '../env/runtime.js';
|
||||
import { createI18nMiddleware } from '../i18n/middleware.js';
|
||||
import type { ComponentInstance } from '../types/astro.js';
|
||||
import type { MiddlewareHandler, RewritePayload } from '../types/public/common.js';
|
||||
|
@ -10,8 +9,6 @@ import type {
|
|||
SSRResult,
|
||||
} from '../types/public/internal.js';
|
||||
import { createOriginCheckMiddleware } from './app/middlewares.js';
|
||||
import { AstroError } from './errors/errors.js';
|
||||
import { AstroErrorData } from './errors/index.js';
|
||||
import type { Logger } from './logger/core.js';
|
||||
import { NOOP_MIDDLEWARE_FN } from './middleware/noop-middleware.js';
|
||||
import { sequence } from './middleware/sequence.js';
|
||||
|
|
|
@ -985,7 +985,7 @@ export const AstroGlobNoMatch = {
|
|||
/**
|
||||
* @docs
|
||||
* @see
|
||||
* - [Astro.redirect](https://docs.astro.build/en/reference/api-reference/#astroredirect)
|
||||
* - [Astro.redirect](https://docs.astro.build/en/reference/api-reference/#redirect)
|
||||
* @description
|
||||
* A redirect must be given a location with the `Location` header.
|
||||
*/
|
||||
|
|
|
@ -39,6 +39,11 @@ export type CreateContext = {
|
|||
* User defined default locale
|
||||
*/
|
||||
defaultLocale: string;
|
||||
|
||||
/**
|
||||
* Initial value of the locals
|
||||
*/
|
||||
locals: App.Locals;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -49,6 +54,7 @@ function createContext({
|
|||
params = {},
|
||||
userDefinedLocales = [],
|
||||
defaultLocale = '',
|
||||
locals,
|
||||
}: CreateContext): APIContext {
|
||||
let preferredLocale: string | undefined = undefined;
|
||||
let preferredLocaleList: string[] | undefined = undefined;
|
||||
|
@ -104,15 +110,15 @@ function createContext({
|
|||
return clientIpAddress;
|
||||
},
|
||||
get locals() {
|
||||
let locals = Reflect.get(request, clientLocalsSymbol);
|
||||
// TODO: deprecate this usage. This is used only by the edge middleware for now, so its usage should be basically none.
|
||||
let _locals = locals ?? Reflect.get(request, clientLocalsSymbol);
|
||||
if (locals === undefined) {
|
||||
locals = {};
|
||||
Reflect.set(request, clientLocalsSymbol, locals);
|
||||
_locals = {};
|
||||
}
|
||||
if (typeof locals !== 'object') {
|
||||
if (typeof _locals !== 'object') {
|
||||
throw new AstroError(AstroErrorData.LocalsNotAnObject);
|
||||
}
|
||||
return locals;
|
||||
return _locals;
|
||||
},
|
||||
set locals(_) {
|
||||
throw new AstroError(AstroErrorData.LocalsReassigned);
|
||||
|
|
|
@ -24,8 +24,6 @@ export interface CreateRequestOptions {
|
|||
routePattern: string;
|
||||
}
|
||||
|
||||
const clientLocalsSymbol = Symbol.for('astro.locals');
|
||||
|
||||
/**
|
||||
* Used by astro internals to create a web standard request object.
|
||||
*
|
||||
|
@ -39,7 +37,6 @@ export function createRequest({
|
|||
method = 'GET',
|
||||
body = undefined,
|
||||
logger,
|
||||
locals,
|
||||
isPrerendered = false,
|
||||
routePattern,
|
||||
}: CreateRequestOptions): Request {
|
||||
|
@ -93,7 +90,5 @@ export function createRequest({
|
|||
});
|
||||
}
|
||||
|
||||
Reflect.set(request, clientLocalsSymbol, locals ?? {});
|
||||
|
||||
return request;
|
||||
}
|
||||
|
|
|
@ -161,6 +161,7 @@ export async function handleRoute({
|
|||
let mod: ComponentInstance | undefined = undefined;
|
||||
let route: RouteData;
|
||||
const middleware = (await loadMiddleware(loader)).onRequest;
|
||||
// This is required for adapters to set locals in dev mode. They use a dev server middleware to inject locals to the `http.IncomingRequest` object.
|
||||
const locals = Reflect.get(incomingRequest, clientLocalsSymbol);
|
||||
|
||||
const { preloadedComponent } = matchedRoute;
|
||||
|
@ -245,7 +246,7 @@ export async function handleRoute({
|
|||
const fourOhFourRoute = await matchRoute('/404', manifestData, pipeline);
|
||||
if (fourOhFourRoute) {
|
||||
renderContext = await RenderContext.create({
|
||||
locals,
|
||||
locals: {},
|
||||
pipeline,
|
||||
pathname,
|
||||
middleware: isDefaultPrerendered404(fourOhFourRoute.route) ? undefined : middleware,
|
||||
|
|
|
@ -16,4 +16,21 @@ describe('createAPIContext', () => {
|
|||
|
||||
assert.equal(context.clientAddress, '192.0.2.43');
|
||||
});
|
||||
|
||||
it('should return the correct locals', () => {
|
||||
const request = new Request('http://example.com', {
|
||||
headers: {
|
||||
'x-forwarded-for': '192.0.2.43, 172.16.58.3',
|
||||
},
|
||||
});
|
||||
|
||||
const context = createContext({
|
||||
request,
|
||||
locals: {
|
||||
foo: 'bar',
|
||||
},
|
||||
});
|
||||
|
||||
assert.deepEqual(context.locals, { foo: 'bar' });
|
||||
});
|
||||
});
|
||||
|
|
|
@ -87,16 +87,17 @@ describe('endpoints', () => {
|
|||
url: '/streaming',
|
||||
});
|
||||
|
||||
const locals = { cancelledByTheServer: false };
|
||||
req[Symbol.for('astro.locals')] = locals;
|
||||
|
||||
container.handle(req, res);
|
||||
|
||||
await new Promise((resolve) => setTimeout(resolve, 500));
|
||||
res.emit('close');
|
||||
|
||||
await done;
|
||||
try {
|
||||
await done;
|
||||
|
||||
assert.equal(locals.cancelledByTheServer, true);
|
||||
assert.ok(true);
|
||||
} catch (err) {
|
||||
assert.fail(err);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
|
|
@ -11,9 +11,10 @@ export function isFrontmatterValid(frontmatter: Record<string, any>) {
|
|||
}
|
||||
|
||||
// Capture frontmatter wrapped with `---`, including any characters and new lines within it.
|
||||
// Only capture if it exists near the top of the file (whitespaces between the start of file and
|
||||
// the start of `---` are allowed)
|
||||
const frontmatterRE = /^\s*---([\s\S]*?\n)---/;
|
||||
// Only capture if `---` exists near the top of the file, including:
|
||||
// 1. Start of file (including if has BOM encoding)
|
||||
// 2. Start of file with any whitespace (but `---` must still start on a new line)
|
||||
const frontmatterRE = /(?:^\uFEFF?|^\s*\n)---([\s\S]*?\n)---/;
|
||||
export function extractFrontmatter(code: string): string | undefined {
|
||||
return frontmatterRE.exec(code)?.[1];
|
||||
}
|
||||
|
|
|
@ -2,16 +2,21 @@ import assert from 'node:assert/strict';
|
|||
import { describe, it } from 'node:test';
|
||||
import { extractFrontmatter, parseFrontmatter } from '../dist/index.js';
|
||||
|
||||
const bom = '\uFEFF';
|
||||
|
||||
describe('extractFrontmatter', () => {
|
||||
it('works', () => {
|
||||
const yaml = `\nfoo: bar\n`;
|
||||
assert.equal(extractFrontmatter(`---${yaml}---`), yaml);
|
||||
assert.equal(extractFrontmatter(` ---${yaml}---`), yaml);
|
||||
assert.equal(extractFrontmatter(`${bom}---${yaml}---`), yaml);
|
||||
assert.equal(extractFrontmatter(`\n---${yaml}---`), yaml);
|
||||
assert.equal(extractFrontmatter(`\n \n---${yaml}---`), yaml);
|
||||
assert.equal(extractFrontmatter(`---${yaml}---\ncontent`), yaml);
|
||||
assert.equal(extractFrontmatter(`${bom}---${yaml}---\ncontent`), yaml);
|
||||
assert.equal(extractFrontmatter(`\n\n---${yaml}---\n\ncontent`), yaml);
|
||||
assert.equal(extractFrontmatter(`\n \n---${yaml}---\n\ncontent`), yaml);
|
||||
assert.equal(extractFrontmatter(` ---${yaml}---`), undefined);
|
||||
assert.equal(extractFrontmatter(`---${yaml} ---`), undefined);
|
||||
assert.equal(extractFrontmatter(`text\n---${yaml}---\n\ncontent`), undefined);
|
||||
});
|
||||
});
|
||||
|
@ -24,10 +29,10 @@ describe('parseFrontmatter', () => {
|
|||
rawFrontmatter: yaml,
|
||||
content: '',
|
||||
});
|
||||
assert.deepEqual(parseFrontmatter(` ---${yaml}---`), {
|
||||
assert.deepEqual(parseFrontmatter(`${bom}---${yaml}---`), {
|
||||
frontmatter: { foo: 'bar' },
|
||||
rawFrontmatter: yaml,
|
||||
content: ' ',
|
||||
content: bom,
|
||||
});
|
||||
assert.deepEqual(parseFrontmatter(`\n---${yaml}---`), {
|
||||
frontmatter: { foo: 'bar' },
|
||||
|
@ -44,6 +49,11 @@ describe('parseFrontmatter', () => {
|
|||
rawFrontmatter: yaml,
|
||||
content: '\ncontent',
|
||||
});
|
||||
assert.deepEqual(parseFrontmatter(`${bom}---${yaml}---\ncontent`), {
|
||||
frontmatter: { foo: 'bar' },
|
||||
rawFrontmatter: yaml,
|
||||
content: `${bom}\ncontent`,
|
||||
});
|
||||
assert.deepEqual(parseFrontmatter(`\n\n---${yaml}---\n\ncontent`), {
|
||||
frontmatter: { foo: 'bar' },
|
||||
rawFrontmatter: yaml,
|
||||
|
@ -54,6 +64,16 @@ describe('parseFrontmatter', () => {
|
|||
rawFrontmatter: yaml,
|
||||
content: '\n \n\n\ncontent',
|
||||
});
|
||||
assert.deepEqual(parseFrontmatter(` ---${yaml}---`), {
|
||||
frontmatter: {},
|
||||
rawFrontmatter: '',
|
||||
content: ` ---${yaml}---`,
|
||||
});
|
||||
assert.deepEqual(parseFrontmatter(`---${yaml} ---`), {
|
||||
frontmatter: {},
|
||||
rawFrontmatter: '',
|
||||
content: `---${yaml} ---`,
|
||||
});
|
||||
assert.deepEqual(parseFrontmatter(`text\n---${yaml}---\n\ncontent`), {
|
||||
frontmatter: {},
|
||||
rawFrontmatter: '',
|
||||
|
|
Loading…
Add table
Reference in a new issue