diff --git a/node/declaration.test.ts b/node/declaration.test.ts index d67e4332..3d833443 100644 --- a/node/declaration.test.ts +++ b/node/declaration.test.ts @@ -163,23 +163,23 @@ test('netlify.toml-defined excludedPath are respected', () => { test('Does not escape front slashes in a regex pattern if they are already escaped', () => { const regexPattern = '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))\\/shows(?:\\/(.*))(.json)?[\\/#\\?]?$' const expected = '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))\\/shows(?:\\/(.*))(.json)?[\\/#\\?]?$' - const actual = parsePattern(regexPattern) - expect(actual).toEqual(expected) + expect(parsePattern(regexPattern, false)).toEqual(expected) + expect(parsePattern(regexPattern, true)).toEqual(expected) }) test('Escapes front slashes in a regex pattern', () => { const regexPattern = '^(?:/(_next/data/[^/]{1,}))?(?:/([^/.]{1,}))/shows(?:/(.*))(.json)?[/#\\?]?$' const expected = '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))\\/shows(?:\\/(.*))(.json)?[/#\\?]?$' - const actual = parsePattern(regexPattern) - expect(actual).toEqual(expected) + expect(parsePattern(regexPattern, false)).toEqual(expected) + expect(parsePattern(regexPattern, true)).toEqual(expected) }) test('Ensures pattern match on the whole path', () => { const regexPattern = '/foo/.*/bar' const expected = '^\\/foo\\/.*\\/bar$' - const actual = parsePattern(regexPattern) - expect(actual).toEqual(expected) + expect(parsePattern(regexPattern, false)).toEqual(expected) + expect(parsePattern(regexPattern, true)).toEqual(expected) }) diff --git a/node/declaration.ts b/node/declaration.ts index 1b94a733..9addefde 100644 --- a/node/declaration.ts +++ b/node/declaration.ts @@ -116,14 +116,34 @@ const createDeclarationsFromFunctionConfigs = ( return declarations } -// Validates and normalizes a pattern so that it's a valid regular expression -// in Go, which is the engine used by our edge nodes. -export const parsePattern = (pattern: string) => { +/** + * Normalizes a regular expression, ensuring it has a leading `^` and trailing + * `$` characters. It also converts the regular expression from PCRE to RE2 if + * needed. + */ +export const parsePattern = (pattern: string, pcreRegexpEngine: boolean) => { let enclosedPattern = pattern - if (!pattern.startsWith('^')) enclosedPattern = `^${enclosedPattern}` - if (!pattern.endsWith('$')) enclosedPattern = `${enclosedPattern}$` + + if (!pattern.startsWith('^')) { + enclosedPattern = `^${enclosedPattern}` + } + + if (!pattern.endsWith('$')) { + enclosedPattern = `${enclosedPattern}$` + } const regexp = new RegExp(enclosedPattern) + const regexpString = pcreRegexpEngine ? regexp.toString() : transformPCRERegexp(regexp) + + // Strip leading and forward slashes. + return regexpString.slice(1, -1) +} + +/** + * Transforms a PCRE regular expression into a RE2 expression, compatible + * with the Go engine used in our edge nodes. + */ +const transformPCRERegexp = (regexp: RegExp) => { const newRegexp = regexpAST.transform(regexp, { Assertion(path) { // Lookaheads are not supported. If we find one, throw an error. @@ -146,6 +166,5 @@ export const parsePattern = (pattern: string) => { }, }) - // Strip leading and forward slashes. - return newRegexp.toString().slice(1, -1) + return newRegexp.toString() } diff --git a/node/manifest.ts b/node/manifest.ts index c1a968c8..d5213c6e 100644 --- a/node/manifest.ts +++ b/node/manifest.ts @@ -228,12 +228,8 @@ const pathToRegularExpression = (path: string) => { const getRegularExpression = (declaration: Declaration, pcreRegexpEngine: boolean) => { if ('pattern' in declaration) { - if (pcreRegexpEngine) { - return declaration.pattern - } - try { - return parsePattern(declaration.pattern) + return parsePattern(declaration.pattern, pcreRegexpEngine) } catch (error: unknown) { throw wrapBundleError( new Error( @@ -252,13 +248,9 @@ const getExcludedRegularExpressions = (declaration: Declaration, pcreRegexpEngin ? declaration.excludedPattern : [declaration.excludedPattern] - if (pcreRegexpEngine) { - return excludedPatterns - } - return excludedPatterns.map((excludedPattern) => { try { - return parsePattern(excludedPattern) + return parsePattern(excludedPattern, pcreRegexpEngine) } catch (error: unknown) { throw wrapBundleError( new Error(