From 5a269bba6940be8cf994ee9d4fe659c7c5ad5b16 Mon Sep 17 00:00:00 2001 From: Gal Schlezinger Date: Wed, 25 May 2022 11:17:07 +0300 Subject: [PATCH] Allow RegExp values --- .../build/analysis/extract-const-value.ts | 8 ++ .../build/analysis/get-page-static-info.ts | 4 +- packages/next/build/entries.ts | 9 +- .../index.test.ts | 86 +++++++++++++++---- 4 files changed, 82 insertions(+), 25 deletions(-) diff --git a/packages/next/build/analysis/extract-const-value.ts b/packages/next/build/analysis/extract-const-value.ts index 4d7190b7d773e..3af4cb247017b 100644 --- a/packages/next/build/analysis/extract-const-value.ts +++ b/packages/next/build/analysis/extract-const-value.ts @@ -9,6 +9,7 @@ import type { NullLiteral, NumericLiteral, ObjectExpression, + RegExpLiteral, StringLiteral, VariableDeclaration, } from '@swc/core' @@ -119,6 +120,10 @@ function isKeyValueProperty(node: Node): node is KeyValueProperty { return node.type === 'KeyValueProperty' } +function isRegExpLiteral(node: Node): node is RegExpLiteral { + return node.type === 'RegExpLiteral' +} + class UnsupportedValueError extends Error {} class NoSuchDeclarationError extends Error {} @@ -134,6 +139,9 @@ function extractValue(node: Node): any { } else if (isNumericLiteral(node)) { // e.g. 123 return node.value + } else if (isRegExpLiteral(node)) { + // e.g. /abc/i + return new RegExp(node.pattern, node.flags) } else if (isIdentifier(node)) { switch (node.value) { case 'undefined': diff --git a/packages/next/build/analysis/get-page-static-info.ts b/packages/next/build/analysis/get-page-static-info.ts index 10f5919f8a9ff..387cd4e212762 100644 --- a/packages/next/build/analysis/get-page-static-info.ts +++ b/packages/next/build/analysis/get-page-static-info.ts @@ -124,7 +124,9 @@ function getMiddlewareConfig(config: any): Partial { const result: Partial = {} const matcher = config.matcher - if (typeof matcher === 'string') { + if (matcher instanceof RegExp) { + result.pathMatcher = matcher + } else if (typeof matcher === 'string') { const parsed = tryToParsePath(matcher) if (parsed.regexStr) { result.pathMatcher = new RegExp(parsed.regexStr) diff --git a/packages/next/build/entries.ts b/packages/next/build/entries.ts index e215e4d508e9b..e86bbbaf1a7d4 100644 --- a/packages/next/build/entries.ts +++ b/packages/next/build/entries.ts @@ -154,13 +154,14 @@ export function getEdgeServerEntry(opts: { isServerComponent: boolean page: string pages: { [page: string]: string } - middleware?: { matcher?: RegExp } + middleware?: { pathMatcher?: RegExp } }) { if (opts.page === MIDDLEWARE_FILE) { const loaderParams: MiddlewareLoaderOptions = { absolutePagePath: opts.absolutePagePath, page: opts.page, - matcherRegexp: opts.middleware?.matcher && opts.middleware.matcher.source, + matcherRegexp: + opts.middleware?.pathMatcher && opts.middleware.pathMatcher.source, } return `next-middleware-loader?${stringify(loaderParams)}!` @@ -378,9 +379,7 @@ export async function createEntrypoints(params: CreateEntrypointsParams) { isDev: false, isServerComponent, page, - middleware: { - matcher: staticInfo?.middleware?.pathMatcher, - }, + middleware: staticInfo?.middleware, }) }, }) diff --git a/test/e2e/middleware-can-set-the-matcher-in-its-config/index.test.ts b/test/e2e/middleware-can-set-the-matcher-in-its-config/index.test.ts index 1fc13bc7c6aa3..3538ffba731cc 100644 --- a/test/e2e/middleware-can-set-the-matcher-in-its-config/index.test.ts +++ b/test/e2e/middleware-can-set-the-matcher-in-its-config/index.test.ts @@ -3,22 +3,23 @@ import { NextInstance } from 'test/lib/next-modes/base' import { fetchViaHTTP } from 'next-test-utils' describe('Middleware can set the matcher in its config', () => { - let next: NextInstance + describe('using a path pattern', () => { + let next: NextInstance - beforeAll(async () => { - next = await createNext({ - files: { - 'pages/index.js': ` + beforeAll(async () => { + next = await createNext({ + files: { + 'pages/index.js': ` export default function Page() { return

root page

} `, - 'pages/with-middleware/index.js': ` + 'pages/with-middleware/index.js': ` export default function Page() { return

This should run the middleware

} `, - 'middleware.js': ` + 'middleware.js': ` import { NextResponse } from 'next/server' export const config = { matcher: '/with-middleware/:path*' @@ -29,21 +30,68 @@ describe('Middleware can set the matcher in its config', () => { return res; } `, - }, - dependencies: {}, + }, + dependencies: {}, + }) + }) + afterAll(() => next.destroy()) + + it('does not add the header for root request', async () => { + const response = await fetchViaHTTP(next.url, '/') + expect(response.headers.get('X-From-Middleware')).toBeNull() + expect(await response.text()).toContain('root page') }) - }) - afterAll(() => next.destroy()) - it('does not add the header for root request', async () => { - const response = await fetchViaHTTP(next.url, '/') - expect(response.headers.get('X-From-Middleware')).toBeNull() - expect(await response.text()).toContain('root page') + it('adds the header for a matched path', async () => { + const response = await fetchViaHTTP(next.url, '/with-middleware') + expect(response.headers.get('X-From-Middleware')).toBe('true') + expect(await response.text()).toContain('This should run the middleware') + }) }) - it('adds the header for a matched path', async () => { - const response = await fetchViaHTTP(next.url, '/with-middleware') - expect(response.headers.get('X-From-Middleware')).toBe('true') - expect(await response.text()).toContain('This should run the middleware') + describe('using RegExp', () => { + let next: NextInstance + + beforeAll(async () => { + next = await createNext({ + files: { + 'pages/index.js': ` + export default function Page() { + return

root page

+ } + `, + 'pages/with-middleware/index.js': ` + export default function Page() { + return

This should run the middleware

+ } + `, + 'middleware.js': ` + import { NextResponse } from 'next/server' + export const config = { + matcher: /middleware/, + }; + export default (req) => { + const res = NextResponse.next(); + res.headers.set('X-From-Middleware', 'true'); + return res; + } + `, + }, + dependencies: {}, + }) + }) + afterAll(() => next.destroy()) + + it('does not add the header for root request', async () => { + const response = await fetchViaHTTP(next.url, '/') + expect(response.headers.get('X-From-Middleware')).toBeNull() + expect(await response.text()).toContain('root page') + }) + + it('adds the header for a matched path', async () => { + const response = await fetchViaHTTP(next.url, '/with-middleware') + expect(response.headers.get('X-From-Middleware')).toBe('true') + expect(await response.text()).toContain('This should run the middleware') + }) }) })