@netlify/zip-it-and-ship-it 14.4.2 → 14.5.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/manifest.d.ts +1 -0
- package/dist/manifest.js +4 -1
- package/dist/runtimes/node/in_source_config/index.d.ts +1 -0
- package/dist/runtimes/node/in_source_config/index.js +37 -1
- package/dist/runtimes/node/parser/exports.d.ts +2 -1
- package/dist/runtimes/node/parser/exports.js +27 -6
- package/dist/utils/format_result.d.ts +1 -0
- package/dist/utils/format_result.js +1 -0
- package/package.json +3 -3
package/dist/manifest.d.ts
CHANGED
package/dist/manifest.js
CHANGED
|
@@ -12,7 +12,7 @@ export const createManifest = async ({ functions, path }) => {
|
|
|
12
12
|
};
|
|
13
13
|
await fs.writeFile(path, JSON.stringify(payload));
|
|
14
14
|
};
|
|
15
|
-
const formatFunctionForManifest = ({ bootstrapVersion, bundler, displayName, excludedRoutes, generator, invocationMode, mainFile, name, path, priority, trafficRules, routes, runtime, runtimeVersion, runtimeAPIVersion, schedule, timeout, }) => {
|
|
15
|
+
const formatFunctionForManifest = ({ bootstrapVersion, bundler, displayName, eventSubscriptions, excludedRoutes, generator, invocationMode, mainFile, name, path, priority, trafficRules, routes, runtime, runtimeVersion, runtimeAPIVersion, schedule, timeout, }) => {
|
|
16
16
|
const manifestFunction = {
|
|
17
17
|
bundler,
|
|
18
18
|
displayName,
|
|
@@ -29,6 +29,9 @@ const formatFunctionForManifest = ({ bootstrapVersion, bundler, displayName, exc
|
|
|
29
29
|
runtime,
|
|
30
30
|
schedule,
|
|
31
31
|
};
|
|
32
|
+
if (eventSubscriptions?.length) {
|
|
33
|
+
manifestFunction.eventSubscriptions = eventSubscriptions;
|
|
34
|
+
}
|
|
32
35
|
if (routes?.length !== 0) {
|
|
33
36
|
manifestFunction.routes = routes;
|
|
34
37
|
}
|
|
@@ -7,6 +7,7 @@ import type { ModuleFormat } from '../utils/module_format.js';
|
|
|
7
7
|
export declare const IN_SOURCE_CONFIG_MODULE = "@netlify/functions";
|
|
8
8
|
export interface StaticAnalysisResult {
|
|
9
9
|
config: InSourceConfig;
|
|
10
|
+
eventSubscriptions?: string[];
|
|
10
11
|
excludedRoutes?: Route[];
|
|
11
12
|
inputModuleFormat?: ModuleFormat;
|
|
12
13
|
invocationMode?: InvocationMode;
|
|
@@ -14,6 +14,7 @@ import { createBindingsMethod } from '../parser/bindings.js';
|
|
|
14
14
|
import { traverseNodes } from '../parser/exports.js';
|
|
15
15
|
import { getImports } from '../parser/imports.js';
|
|
16
16
|
import { safelyParseSource, safelyReadSource } from '../parser/index.js';
|
|
17
|
+
import { eventHandlers } from '@netlify/serverless-functions-api';
|
|
17
18
|
import { parse as parseSchedule } from './properties/schedule.js';
|
|
18
19
|
export const IN_SOURCE_CONFIG_MODULE = '@netlify/functions';
|
|
19
20
|
const httpMethod = z.enum(['GET', 'POST', 'PUT', 'PATCH', 'OPTIONS', 'DELETE', 'HEAD']);
|
|
@@ -49,6 +50,37 @@ export const inSourceConfig = functionConfig
|
|
|
49
50
|
preferStatic: z.boolean().optional().catch(undefined),
|
|
50
51
|
rateLimit: rateLimit.optional().catch(undefined),
|
|
51
52
|
});
|
|
53
|
+
/**
|
|
54
|
+
* Extracts event subscription slugs from the default export expression,
|
|
55
|
+
* if it's an object whose property names match known event handlers.
|
|
56
|
+
*/
|
|
57
|
+
const getEventSubscriptions = (expression, getAllBindings) => {
|
|
58
|
+
let objectExpression;
|
|
59
|
+
if (expression?.type === 'ObjectExpression') {
|
|
60
|
+
objectExpression = expression;
|
|
61
|
+
}
|
|
62
|
+
else if (expression?.type === 'Identifier') {
|
|
63
|
+
const binding = getAllBindings().get(expression.name);
|
|
64
|
+
if (binding?.type === 'ObjectExpression') {
|
|
65
|
+
objectExpression = binding;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (!objectExpression) {
|
|
69
|
+
return [];
|
|
70
|
+
}
|
|
71
|
+
const events = [];
|
|
72
|
+
for (const property of objectExpression.properties) {
|
|
73
|
+
let name;
|
|
74
|
+
if ((property.type === 'ObjectMethod' || property.type === 'ObjectProperty') &&
|
|
75
|
+
property.key.type === 'Identifier') {
|
|
76
|
+
name = property.key.name;
|
|
77
|
+
}
|
|
78
|
+
if (name && name in eventHandlers) {
|
|
79
|
+
events.push(eventHandlers[name]);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
return events;
|
|
83
|
+
};
|
|
52
84
|
const validateScheduleFunction = (functionFound, scheduleFound, functionName) => {
|
|
53
85
|
if (!functionFound) {
|
|
54
86
|
throw new FunctionBundlingUserError("The `schedule` helper was imported but we couldn't find any usages. If you meant to schedule a function, please check that `schedule` is invoked and `handler` correctly exported.", { functionName, runtime: RUNTIME.JAVASCRIPT });
|
|
@@ -87,7 +119,7 @@ export const parseSource = (source, { functionName }) => {
|
|
|
87
119
|
let scheduledFunctionFound = false;
|
|
88
120
|
let scheduleFound = false;
|
|
89
121
|
const getAllBindings = createBindingsMethod(ast.body);
|
|
90
|
-
const { configExport, handlerExports, hasDefaultExport, inputModuleFormat } = traverseNodes(ast.body, getAllBindings);
|
|
122
|
+
const { configExport, handlerExports, hasDefaultExport, defaultExportExpression, inputModuleFormat } = traverseNodes(ast.body, getAllBindings);
|
|
91
123
|
const isV2API = handlerExports.length === 0 && hasDefaultExport;
|
|
92
124
|
if (isV2API) {
|
|
93
125
|
const result = {
|
|
@@ -95,6 +127,10 @@ export const parseSource = (source, { functionName }) => {
|
|
|
95
127
|
inputModuleFormat,
|
|
96
128
|
runtimeAPIVersion: 2,
|
|
97
129
|
};
|
|
130
|
+
const eventSubscriptions = getEventSubscriptions(defaultExportExpression, getAllBindings);
|
|
131
|
+
if (eventSubscriptions.length > 0) {
|
|
132
|
+
result.eventSubscriptions = eventSubscriptions;
|
|
133
|
+
}
|
|
98
134
|
const { data, error, success } = inSourceConfig.safeParse(configExport);
|
|
99
135
|
if (success) {
|
|
100
136
|
result.config = data;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Statement } from '@babel/types';
|
|
1
|
+
import type { Declaration, Expression, Statement } from '@babel/types';
|
|
2
2
|
import type { ISCExport } from '../in_source_config/index.js';
|
|
3
3
|
import type { BindingMethod } from './bindings.js';
|
|
4
4
|
/**
|
|
@@ -14,5 +14,6 @@ export declare const traverseNodes: (nodes: Statement[], getAllBindings: Binding
|
|
|
14
14
|
configExport: Record<string, unknown>;
|
|
15
15
|
handlerExports: ISCExport[];
|
|
16
16
|
hasDefaultExport: boolean;
|
|
17
|
+
defaultExportExpression: Expression | Declaration | undefined;
|
|
17
18
|
inputModuleFormat: "cjs";
|
|
18
19
|
};
|
|
@@ -13,6 +13,7 @@ export const traverseNodes = (nodes, getAllBindings) => {
|
|
|
13
13
|
const handlerExports = [];
|
|
14
14
|
let configExport = {};
|
|
15
15
|
let hasDefaultExport = false;
|
|
16
|
+
let defaultExportExpression;
|
|
16
17
|
let inputModuleFormat = MODULE_FORMAT.COMMONJS;
|
|
17
18
|
nodes.forEach((node) => {
|
|
18
19
|
if (isESMImportExport(node)) {
|
|
@@ -39,10 +40,18 @@ export const traverseNodes = (nodes, getAllBindings) => {
|
|
|
39
40
|
const cjsDefaultExports = getCJSExports(node, 'default');
|
|
40
41
|
if (cjsDefaultExports.length !== 0) {
|
|
41
42
|
hasDefaultExport = true;
|
|
43
|
+
defaultExportExpression = getCJSDefaultExpression(node);
|
|
42
44
|
return;
|
|
43
45
|
}
|
|
44
|
-
if (
|
|
46
|
+
if (node.type === 'ExportDefaultDeclaration') {
|
|
45
47
|
hasDefaultExport = true;
|
|
48
|
+
defaultExportExpression = node.declaration;
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (node.type === 'ExportNamedDeclaration' &&
|
|
52
|
+
node.specifiers.some((exportSpecifier) => exportSpecifier.exported.type === 'Identifier' && exportSpecifier.exported.name === 'default')) {
|
|
53
|
+
hasDefaultExport = true;
|
|
54
|
+
defaultExportExpression = getESMReexportedDefaultExpression(node, getAllBindings);
|
|
46
55
|
}
|
|
47
56
|
const esmConfig = parseConfigESMExport(node);
|
|
48
57
|
if (esmConfig !== undefined) {
|
|
@@ -54,7 +63,7 @@ export const traverseNodes = (nodes, getAllBindings) => {
|
|
|
54
63
|
configExport = cjsConfigExports[0].object;
|
|
55
64
|
}
|
|
56
65
|
});
|
|
57
|
-
return { configExport, handlerExports, hasDefaultExport, inputModuleFormat };
|
|
66
|
+
return { configExport, handlerExports, hasDefaultExport, defaultExportExpression, inputModuleFormat };
|
|
58
67
|
};
|
|
59
68
|
// Finds the main handler export in a CJS AST.
|
|
60
69
|
const getCJSExports = (node, name) => {
|
|
@@ -112,10 +121,6 @@ const isNamedExport = (node, name) => {
|
|
|
112
121
|
((exported.type === 'Identifier' && exported.name === name) ||
|
|
113
122
|
(exported.type === 'StringLiteral' && exported.value === name)));
|
|
114
123
|
};
|
|
115
|
-
// Returns whether a given node is or contains a default export declaration.
|
|
116
|
-
const isESMDefaultExport = (node) => node.type === 'ExportDefaultDeclaration' ||
|
|
117
|
-
(node.type === 'ExportNamedDeclaration' &&
|
|
118
|
-
node.specifiers.some((exportSpecifier) => exportSpecifier.exported.type === 'Identifier' && exportSpecifier.exported.name === 'default'));
|
|
119
124
|
/**
|
|
120
125
|
* Finds a `config` named CJS export that maps to an object variable
|
|
121
126
|
* declaration, like:
|
|
@@ -213,6 +218,22 @@ const getExportsFromBindings = (specifiers, name, getAllBindings) => {
|
|
|
213
218
|
const exports = getExportsFromExpression(binding);
|
|
214
219
|
return exports;
|
|
215
220
|
};
|
|
221
|
+
// Extracts the right-hand side expression from a CJS default export
|
|
222
|
+
// (e.g. `exports.default = expr` or `module.exports.default = expr`).
|
|
223
|
+
const getCJSDefaultExpression = (node) => {
|
|
224
|
+
if (node.type === 'ExpressionStatement' && node.expression.type === 'AssignmentExpression' && node.expression.right) {
|
|
225
|
+
return node.expression.right;
|
|
226
|
+
}
|
|
227
|
+
return undefined;
|
|
228
|
+
};
|
|
229
|
+
// Resolves the expression for `export { x as default }` by looking up `x` in bindings.
|
|
230
|
+
const getESMReexportedDefaultExpression = (node, getAllBindings) => {
|
|
231
|
+
const defaultSpecifier = node.specifiers.find((spec) => spec.type === 'ExportSpecifier' && spec.exported.type === 'Identifier' && spec.exported.name === 'default');
|
|
232
|
+
if (defaultSpecifier && defaultSpecifier.type === 'ExportSpecifier') {
|
|
233
|
+
return getAllBindings().get(defaultSpecifier.local.name);
|
|
234
|
+
}
|
|
235
|
+
return undefined;
|
|
236
|
+
};
|
|
216
237
|
const getExportsFromExpression = (node) => {
|
|
217
238
|
switch (node?.type) {
|
|
218
239
|
case 'CallExpression': {
|
|
@@ -3,6 +3,7 @@ import { RuntimeName } from '../runtimes/runtime.js';
|
|
|
3
3
|
import type { ExtendedRoute, Route } from './routes.js';
|
|
4
4
|
export type FunctionResult = Omit<FunctionArchive, 'runtime'> & {
|
|
5
5
|
bootstrapVersion?: string;
|
|
6
|
+
eventSubscriptions?: string[];
|
|
6
7
|
routes?: ExtendedRoute[];
|
|
7
8
|
excludedRoutes?: Route[];
|
|
8
9
|
runtime: RuntimeName;
|
|
@@ -4,6 +4,7 @@ export const formatZipResult = (archive) => {
|
|
|
4
4
|
const functionResult = {
|
|
5
5
|
...archive,
|
|
6
6
|
staticAnalysisResult: undefined,
|
|
7
|
+
eventSubscriptions: archive.staticAnalysisResult?.eventSubscriptions,
|
|
7
8
|
routes: archive.staticAnalysisResult?.routes,
|
|
8
9
|
excludedRoutes: archive.staticAnalysisResult?.excludedRoutes,
|
|
9
10
|
runtime: archive.runtime.name,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@netlify/zip-it-and-ship-it",
|
|
3
|
-
"version": "14.
|
|
3
|
+
"version": "14.5.0",
|
|
4
4
|
"description": "Zip it and ship it",
|
|
5
5
|
"main": "./dist/main.js",
|
|
6
6
|
"type": "module",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"@babel/parser": "^7.22.5",
|
|
45
45
|
"@babel/types": "^7.28.5",
|
|
46
46
|
"@netlify/binary-info": "^1.0.0",
|
|
47
|
-
"@netlify/serverless-functions-api": "
|
|
47
|
+
"@netlify/serverless-functions-api": "2.11.1",
|
|
48
48
|
"@vercel/nft": "0.29.4",
|
|
49
49
|
"archiver": "^7.0.0",
|
|
50
50
|
"common-path-prefix": "^3.0.0",
|
|
@@ -99,5 +99,5 @@
|
|
|
99
99
|
"engines": {
|
|
100
100
|
"node": ">=18.14.0"
|
|
101
101
|
},
|
|
102
|
-
"gitHead": "
|
|
102
|
+
"gitHead": "5163296011af5d699885acf2c8bca82a4458ab31"
|
|
103
103
|
}
|