@netlify/edge-bundler 11.2.2 → 11.3.0
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/node/declaration.d.ts +2 -3
- package/dist/node/declaration.js +3 -33
- package/dist/node/declaration.test.js +4 -7
- package/dist/node/feature_flags.d.ts +2 -6
- package/dist/node/feature_flags.js +1 -3
- package/dist/node/manifest.d.ts +1 -1
- package/dist/node/manifest.js +8 -8
- package/dist/node/manifest.test.js +3 -13
- package/package.json +2 -3
|
@@ -19,8 +19,7 @@ export type Declaration = DeclarationWithPath | DeclarationWithPattern;
|
|
|
19
19
|
export declare const mergeDeclarations: (tomlDeclarations: Declaration[], userFunctionsConfig: Record<string, FunctionConfig>, internalFunctionsConfig: Record<string, FunctionConfig>, deployConfigDeclarations: Declaration[], _featureFlags?: FeatureFlags) => Declaration[];
|
|
20
20
|
/**
|
|
21
21
|
* Normalizes a regular expression, ensuring it has a leading `^` and trailing
|
|
22
|
-
* `$` characters.
|
|
23
|
-
* needed.
|
|
22
|
+
* `$` characters.
|
|
24
23
|
*/
|
|
25
|
-
export declare const
|
|
24
|
+
export declare const normalizePattern: (pattern: string) => string;
|
|
26
25
|
export {};
|
package/dist/node/declaration.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import regexpAST from 'regexp-tree';
|
|
2
1
|
export const mergeDeclarations = (tomlDeclarations, userFunctionsConfig, internalFunctionsConfig, deployConfigDeclarations,
|
|
3
2
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
|
4
3
|
_featureFlags = {}) => {
|
|
@@ -68,10 +67,9 @@ const createDeclarationsFromFunctionConfigs = (functionConfigs, functionsVisited
|
|
|
68
67
|
};
|
|
69
68
|
/**
|
|
70
69
|
* Normalizes a regular expression, ensuring it has a leading `^` and trailing
|
|
71
|
-
* `$` characters.
|
|
72
|
-
* needed.
|
|
70
|
+
* `$` characters.
|
|
73
71
|
*/
|
|
74
|
-
export const
|
|
72
|
+
export const normalizePattern = (pattern) => {
|
|
75
73
|
let enclosedPattern = pattern;
|
|
76
74
|
if (!pattern.startsWith('^')) {
|
|
77
75
|
enclosedPattern = `^${enclosedPattern}`;
|
|
@@ -80,34 +78,6 @@ export const parsePattern = (pattern, pcreRegexpEngine) => {
|
|
|
80
78
|
enclosedPattern = `${enclosedPattern}$`;
|
|
81
79
|
}
|
|
82
80
|
const regexp = new RegExp(enclosedPattern);
|
|
83
|
-
const regexpString = pcreRegexpEngine ? regexp.toString() : transformPCRERegexp(regexp);
|
|
84
81
|
// Strip leading and forward slashes.
|
|
85
|
-
return
|
|
86
|
-
};
|
|
87
|
-
/**
|
|
88
|
-
* Transforms a PCRE regular expression into a RE2 expression, compatible
|
|
89
|
-
* with the Go engine used in our edge nodes.
|
|
90
|
-
*/
|
|
91
|
-
const transformPCRERegexp = (regexp) => {
|
|
92
|
-
const newRegexp = regexpAST.transform(regexp, {
|
|
93
|
-
Assertion(path) {
|
|
94
|
-
// Lookaheads are not supported. If we find one, throw an error.
|
|
95
|
-
if (path.node.kind === 'Lookahead') {
|
|
96
|
-
throw new Error('Regular expressions with lookaheads are not supported');
|
|
97
|
-
}
|
|
98
|
-
},
|
|
99
|
-
Group(path) {
|
|
100
|
-
// Named captured groups in JavaScript use a different syntax than in Go.
|
|
101
|
-
// If we find one, convert it to an unnamed capture group, which is valid
|
|
102
|
-
// in both engines.
|
|
103
|
-
if ('name' in path.node && path.node.name !== undefined) {
|
|
104
|
-
path.replace({
|
|
105
|
-
...path.node,
|
|
106
|
-
name: undefined,
|
|
107
|
-
nameRaw: undefined,
|
|
108
|
-
});
|
|
109
|
-
}
|
|
110
|
-
},
|
|
111
|
-
});
|
|
112
|
-
return newRegexp.toString();
|
|
82
|
+
return regexp.toString().slice(1, -1);
|
|
113
83
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { test, expect } from 'vitest';
|
|
2
|
-
import { mergeDeclarations,
|
|
2
|
+
import { mergeDeclarations, normalizePattern } from './declaration.js';
|
|
3
3
|
const deployConfigDeclarations = [];
|
|
4
4
|
test('Ensure the order of edge functions with FF', () => {
|
|
5
5
|
const deployConfigDeclarations = [
|
|
@@ -117,18 +117,15 @@ test('netlify.toml-defined excludedPath are respected', () => {
|
|
|
117
117
|
test('Does not escape front slashes in a regex pattern if they are already escaped', () => {
|
|
118
118
|
const regexPattern = '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))\\/shows(?:\\/(.*))(.json)?[\\/#\\?]?$';
|
|
119
119
|
const expected = '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))\\/shows(?:\\/(.*))(.json)?[\\/#\\?]?$';
|
|
120
|
-
expect(
|
|
121
|
-
expect(parsePattern(regexPattern, true)).toEqual(expected);
|
|
120
|
+
expect(normalizePattern(regexPattern)).toEqual(expected);
|
|
122
121
|
});
|
|
123
122
|
test('Escapes front slashes in a regex pattern', () => {
|
|
124
123
|
const regexPattern = '^(?:/(_next/data/[^/]{1,}))?(?:/([^/.]{1,}))/shows(?:/(.*))(.json)?[/#\\?]?$';
|
|
125
124
|
const expected = '^(?:\\/(_next\\/data\\/[^/]{1,}))?(?:\\/([^/.]{1,}))\\/shows(?:\\/(.*))(.json)?[/#\\?]?$';
|
|
126
|
-
expect(
|
|
127
|
-
expect(parsePattern(regexPattern, true)).toEqual(expected);
|
|
125
|
+
expect(normalizePattern(regexPattern)).toEqual(expected);
|
|
128
126
|
});
|
|
129
127
|
test('Ensures pattern match on the whole path', () => {
|
|
130
128
|
const regexPattern = '/foo/.*/bar';
|
|
131
129
|
const expected = '^\\/foo\\/.*\\/bar$';
|
|
132
|
-
expect(
|
|
133
|
-
expect(parsePattern(regexPattern, true)).toEqual(expected);
|
|
130
|
+
expect(normalizePattern(regexPattern)).toEqual(expected);
|
|
134
131
|
});
|
|
@@ -1,10 +1,6 @@
|
|
|
1
|
-
declare const defaultFlags: {
|
|
2
|
-
edge_bundler_pcre_regexp: boolean;
|
|
3
|
-
};
|
|
1
|
+
declare const defaultFlags: {};
|
|
4
2
|
type FeatureFlag = keyof typeof defaultFlags;
|
|
5
3
|
type FeatureFlags = Partial<Record<FeatureFlag, boolean>>;
|
|
6
|
-
declare const getFlags: (input?: Record<string, boolean>, flags?: {
|
|
7
|
-
edge_bundler_pcre_regexp: boolean;
|
|
8
|
-
}) => FeatureFlags;
|
|
4
|
+
declare const getFlags: (input?: Record<string, boolean>, flags?: {}) => FeatureFlags;
|
|
9
5
|
export { defaultFlags, getFlags };
|
|
10
6
|
export type { FeatureFlag, FeatureFlags };
|
|
@@ -1,6 +1,4 @@
|
|
|
1
|
-
const defaultFlags = {
|
|
2
|
-
edge_bundler_pcre_regexp: false,
|
|
3
|
-
};
|
|
1
|
+
const defaultFlags = {};
|
|
4
2
|
const getFlags = (input = {}, flags = defaultFlags) => Object.entries(flags).reduce((result, [key, defaultValue]) => ({
|
|
5
3
|
...result,
|
|
6
4
|
[key]: input[key] === undefined ? defaultValue : input[key],
|
package/dist/node/manifest.d.ts
CHANGED
|
@@ -42,7 +42,7 @@ interface GenerateManifestOptions {
|
|
|
42
42
|
layers?: Layer[];
|
|
43
43
|
userFunctionConfig?: Record<string, FunctionConfig>;
|
|
44
44
|
}
|
|
45
|
-
declare const generateManifest: ({ bundles, declarations,
|
|
45
|
+
declare const generateManifest: ({ bundles, declarations, functions, userFunctionConfig, internalFunctionConfig, importMap, layers, }: GenerateManifestOptions) => {
|
|
46
46
|
declarationsWithoutFunction: string[];
|
|
47
47
|
manifest: Manifest;
|
|
48
48
|
unroutedFunctions: string[];
|
package/dist/node/manifest.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { promises as fs } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { wrapBundleError } from './bundle_error.js';
|
|
4
|
-
import {
|
|
4
|
+
import { normalizePattern } from './declaration.js';
|
|
5
5
|
import { getPackageVersion } from './package_json.js';
|
|
6
6
|
import { nonNullable } from './utils/non_nullable.js';
|
|
7
7
|
import { ExtendedURLPattern } from './utils/urlpattern.js';
|
|
@@ -46,7 +46,7 @@ const normalizeMethods = (method, name) => {
|
|
|
46
46
|
return method.toUpperCase();
|
|
47
47
|
});
|
|
48
48
|
};
|
|
49
|
-
const generateManifest = ({ bundles = [], declarations = [],
|
|
49
|
+
const generateManifest = ({ bundles = [], declarations = [], functions, userFunctionConfig = {}, internalFunctionConfig = {}, importMap, layers = [], }) => {
|
|
50
50
|
const preCacheRoutes = [];
|
|
51
51
|
const postCacheRoutes = [];
|
|
52
52
|
const manifestFunctionConfig = Object.fromEntries(functions.map(({ name }) => [name, { excluded_patterns: [] }]));
|
|
@@ -74,14 +74,14 @@ const generateManifest = ({ bundles = [], declarations = [], featureFlags, funct
|
|
|
74
74
|
declarationsWithoutFunction.add(declaration.function);
|
|
75
75
|
return;
|
|
76
76
|
}
|
|
77
|
-
const pattern = getRegularExpression(declaration
|
|
77
|
+
const pattern = getRegularExpression(declaration);
|
|
78
78
|
// If there is no `pattern`, the declaration will never be triggered, so we
|
|
79
79
|
// can discard it.
|
|
80
80
|
if (!pattern) {
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
83
83
|
routedFunctions.add(declaration.function);
|
|
84
|
-
const excludedPattern = getExcludedRegularExpressions(declaration
|
|
84
|
+
const excludedPattern = getExcludedRegularExpressions(declaration);
|
|
85
85
|
const route = {
|
|
86
86
|
function: func.name,
|
|
87
87
|
pattern: serializePattern(pattern),
|
|
@@ -135,10 +135,10 @@ const pathToRegularExpression = (path) => {
|
|
|
135
135
|
throw wrapBundleError(error);
|
|
136
136
|
}
|
|
137
137
|
};
|
|
138
|
-
const getRegularExpression = (declaration
|
|
138
|
+
const getRegularExpression = (declaration) => {
|
|
139
139
|
if ('pattern' in declaration) {
|
|
140
140
|
try {
|
|
141
|
-
return
|
|
141
|
+
return normalizePattern(declaration.pattern);
|
|
142
142
|
}
|
|
143
143
|
catch (error) {
|
|
144
144
|
throw wrapBundleError(new Error(`Could not parse path declaration of function '${declaration.function}': ${error.message}`));
|
|
@@ -146,14 +146,14 @@ const getRegularExpression = (declaration, pcreRegexpEngine) => {
|
|
|
146
146
|
}
|
|
147
147
|
return pathToRegularExpression(declaration.path);
|
|
148
148
|
};
|
|
149
|
-
const getExcludedRegularExpressions = (declaration
|
|
149
|
+
const getExcludedRegularExpressions = (declaration) => {
|
|
150
150
|
if ('excludedPattern' in declaration && declaration.excludedPattern) {
|
|
151
151
|
const excludedPatterns = Array.isArray(declaration.excludedPattern)
|
|
152
152
|
? declaration.excludedPattern
|
|
153
153
|
: [declaration.excludedPattern];
|
|
154
154
|
return excludedPatterns.map((excludedPattern) => {
|
|
155
155
|
try {
|
|
156
|
-
return
|
|
156
|
+
return normalizePattern(excludedPattern);
|
|
157
157
|
}
|
|
158
158
|
catch (error) {
|
|
159
159
|
throw wrapBundleError(new Error(`Could not parse path declaration of function '${declaration.function}': ${error.message}`));
|
|
@@ -386,22 +386,12 @@ test('Generates a manifest with layers', () => {
|
|
|
386
386
|
expect(manifest2.routes).toEqual(expectedRoutes);
|
|
387
387
|
expect(manifest2.layers).toEqual(layers);
|
|
388
388
|
});
|
|
389
|
-
test('
|
|
390
|
-
const functions = [{ name: 'func-1', path: '/path/to/func-1.ts' }];
|
|
391
|
-
const declarations = [{ function: 'func-1', pattern: '^\\/((?!api|_next\\/static|_next\\/image|favicon.ico).*)$' }];
|
|
392
|
-
expect(() => generateManifest({
|
|
393
|
-
bundles: [],
|
|
394
|
-
declarations,
|
|
395
|
-
functions,
|
|
396
|
-
})).toThrowError(/^Could not parse path declaration of function 'func-1': Regular expressions with lookaheads are not supported$/);
|
|
397
|
-
});
|
|
398
|
-
test('Accepts regular expressions with lookaheads if support for the PCRE engine is enabled', () => {
|
|
389
|
+
test('Accepts regular expressions with lookaheads', () => {
|
|
399
390
|
const functions = [{ name: 'func-1', path: '/path/to/func-1.ts' }];
|
|
400
391
|
const declarations = [{ function: 'func-1', pattern: '^\\/((?!api|_next\\/static|_next\\/image|favicon.ico).*)$' }];
|
|
401
392
|
const { manifest } = generateManifest({
|
|
402
393
|
bundles: [],
|
|
403
394
|
declarations,
|
|
404
|
-
featureFlags: { edge_bundler_pcre_regexp: true },
|
|
405
395
|
functions,
|
|
406
396
|
});
|
|
407
397
|
const [route] = manifest.routes;
|
|
@@ -409,11 +399,11 @@ test('Accepts regular expressions with lookaheads if support for the PCRE engine
|
|
|
409
399
|
expect(regexp.test('/foo')).toBeTruthy();
|
|
410
400
|
expect(regexp.test('/_next/static/foo')).toBeFalsy();
|
|
411
401
|
});
|
|
412
|
-
test('
|
|
402
|
+
test('Accepts regular expressions with named capture groups', () => {
|
|
413
403
|
const functions = [{ name: 'func-1', path: '/path/to/func-1.ts' }];
|
|
414
404
|
const declarations = [{ function: 'func-1', pattern: '^/(?<name>\\w+)$' }];
|
|
415
405
|
const { manifest } = generateManifest({ bundles: [], declarations, functions });
|
|
416
|
-
expect(manifest.routes).toEqual([{ function: 'func-1', pattern: '^/(
|
|
406
|
+
expect(manifest.routes).toEqual([{ function: 'func-1', pattern: '^/(?<name>\\w+)$', excluded_patterns: [] }]);
|
|
417
407
|
});
|
|
418
408
|
test('Returns functions without a declaration and unrouted functions', () => {
|
|
419
409
|
const bundle = {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/edge-bundler",
|
|
3
|
-
"version": "11.
|
|
3
|
+
"version": "11.3.0",
|
|
4
4
|
"description": "Intelligently prepare Netlify Edge Functions for deployment",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/node/index.js",
|
|
@@ -81,7 +81,7 @@
|
|
|
81
81
|
"better-ajv-errors": "^1.2.0",
|
|
82
82
|
"common-path-prefix": "^3.0.0",
|
|
83
83
|
"env-paths": "^3.0.0",
|
|
84
|
-
"esbuild": "0.
|
|
84
|
+
"esbuild": "0.20.0",
|
|
85
85
|
"execa": "^6.0.0",
|
|
86
86
|
"find-up": "^6.3.0",
|
|
87
87
|
"get-package-name": "^2.2.0",
|
|
@@ -93,7 +93,6 @@
|
|
|
93
93
|
"p-retry": "^5.1.1",
|
|
94
94
|
"p-wait-for": "^4.1.0",
|
|
95
95
|
"path-key": "^4.0.0",
|
|
96
|
-
"regexp-tree": "^0.1.24",
|
|
97
96
|
"semver": "^7.3.8",
|
|
98
97
|
"tmp-promise": "^3.0.3",
|
|
99
98
|
"urlpattern-polyfill": "8.0.2",
|