@faasjs/dev 8.0.0-beta.5 → 8.0.0-beta.6
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/README.md +15 -5
- package/dist/chunk-3FXFWIBW.mjs +221 -0
- package/dist/cli.cjs +335 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.mjs +136 -0
- package/dist/index.cjs +276 -26
- package/dist/index.d.ts +19 -21
- package/dist/index.mjs +78 -43
- package/faas-types.mjs +7 -0
- package/package.json +27 -17
package/README.md
CHANGED
|
@@ -60,19 +60,19 @@ expect(response.data).toEqual({ message: 'Hello, FaasJS' })
|
|
|
60
60
|
|
|
61
61
|
## API
|
|
62
62
|
|
|
63
|
-
- Vite: [viteFaasJsServer](functions/viteFaasJsServer.md)
|
|
64
|
-
- PGlite: [createPgliteKnex](functions/createPgliteKnex.md), [mountFaasKnex](functions/mountFaasKnex.md), [
|
|
63
|
+
- Vite: [viteFaasJsServer](functions/viteFaasJsServer.md)
|
|
64
|
+
- PGlite: [createPgliteKnex](functions/createPgliteKnex.md), [mountFaasKnex](functions/mountFaasKnex.md), [unmountFaasKnex](functions/unmountFaasKnex.md), [MountFaasKnexOptions](type-aliases/MountFaasKnexOptions.md)
|
|
65
65
|
- Test: [test](functions/test.md), [FuncWarper](classes/FuncWarper.md), [streamToString](functions/streamToString.md)
|
|
66
66
|
|
|
67
67
|
## Functions
|
|
68
68
|
|
|
69
69
|
- [createPgliteKnex](functions/createPgliteKnex.md)
|
|
70
70
|
- [defineFunc](functions/defineFunc.md)
|
|
71
|
+
- [generateFaasTypes](functions/generateFaasTypes.md)
|
|
72
|
+
- [isTypegenSourceFile](functions/isTypegenSourceFile.md)
|
|
71
73
|
- [mountFaasKnex](functions/mountFaasKnex.md)
|
|
72
74
|
- [nameFunc](functions/nameFunc.md)
|
|
73
75
|
- [parseFuncFilenameFromStack](functions/parseFuncFilenameFromStack.md)
|
|
74
|
-
- [runPgliteSql](functions/runPgliteSql.md)
|
|
75
|
-
- [runPgliteSqlFile](functions/runPgliteSqlFile.md)
|
|
76
76
|
- [streamToString](functions/streamToString.md)
|
|
77
77
|
- [test](functions/test.md)
|
|
78
78
|
- [unmountFaasKnex](functions/unmountFaasKnex.md)
|
|
@@ -85,6 +85,10 @@ expect(response.data).toEqual({ message: 'Hello, FaasJS' })
|
|
|
85
85
|
- [Func](classes/Func.md)
|
|
86
86
|
- [FuncWarper](classes/FuncWarper.md)
|
|
87
87
|
|
|
88
|
+
## Interfaces
|
|
89
|
+
|
|
90
|
+
- [FaasPluginEventMap](interfaces/FaasPluginEventMap.md)
|
|
91
|
+
|
|
88
92
|
## Type Aliases
|
|
89
93
|
|
|
90
94
|
- [Config](type-aliases/Config.md)
|
|
@@ -92,12 +96,18 @@ expect(response.data).toEqual({ message: 'Hello, FaasJS' })
|
|
|
92
96
|
- [FuncConfig](type-aliases/FuncConfig.md)
|
|
93
97
|
- [FuncEventType](type-aliases/FuncEventType.md)
|
|
94
98
|
- [FuncReturnType](type-aliases/FuncReturnType.md)
|
|
99
|
+
- [GenerateFaasTypesOptions](type-aliases/GenerateFaasTypesOptions.md)
|
|
100
|
+
- [GenerateFaasTypesResult](type-aliases/GenerateFaasTypesResult.md)
|
|
95
101
|
- [Handler](type-aliases/Handler.md)
|
|
102
|
+
- [InferPluginEvent](type-aliases/InferPluginEvent.md)
|
|
96
103
|
- [InvokeData](type-aliases/InvokeData.md)
|
|
97
104
|
- [LifeCycleKey](type-aliases/LifeCycleKey.md)
|
|
98
105
|
- [MountData](type-aliases/MountData.md)
|
|
99
106
|
- [MountFaasKnexOptions](type-aliases/MountFaasKnexOptions.md)
|
|
100
107
|
- [Next](type-aliases/Next.md)
|
|
108
|
+
- [NormalizePluginType](type-aliases/NormalizePluginType.md)
|
|
101
109
|
- [Plugin](type-aliases/Plugin.md)
|
|
110
|
+
- [ResolvePluginEvent](type-aliases/ResolvePluginEvent.md)
|
|
111
|
+
- [Simplify](type-aliases/Simplify.md)
|
|
112
|
+
- [UnionToIntersection](type-aliases/UnionToIntersection.md)
|
|
102
113
|
- [UseifyPlugin](type-aliases/UseifyPlugin.md)
|
|
103
|
-
- [ViteFaasJsServerOptions](type-aliases/ViteFaasJsServerOptions.md)
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { existsSync } from 'fs';
|
|
2
|
+
import { readFile, mkdir, writeFile, readdir } from 'fs/promises';
|
|
3
|
+
import { resolve, join, dirname, relative } from 'path';
|
|
4
|
+
import { loadConfig } from '@faasjs/load';
|
|
5
|
+
import { Logger } from '@faasjs/logger';
|
|
6
|
+
|
|
7
|
+
var __defProp = Object.defineProperty;
|
|
8
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
9
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
10
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
11
|
+
var __export = (target, all) => {
|
|
12
|
+
for (var name in all)
|
|
13
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
14
|
+
};
|
|
15
|
+
var __copyProps = (to, from, except, desc) => {
|
|
16
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
17
|
+
for (let key of __getOwnPropNames(from))
|
|
18
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
19
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
20
|
+
}
|
|
21
|
+
return to;
|
|
22
|
+
};
|
|
23
|
+
var __reExport = (target, mod, secondTarget) => (__copyProps(target, mod, "default"), secondTarget && __copyProps(secondTarget, mod, "default"));
|
|
24
|
+
function resolveFaasStaging() {
|
|
25
|
+
return process.env.FaasEnv || "development";
|
|
26
|
+
}
|
|
27
|
+
function resolveServerConfig(root, logger, defaultBase = "/") {
|
|
28
|
+
const projectRoot = resolve(root);
|
|
29
|
+
const staging = resolveFaasStaging();
|
|
30
|
+
const srcRoot = join(projectRoot, "src");
|
|
31
|
+
const config = loadConfig(
|
|
32
|
+
srcRoot,
|
|
33
|
+
join(srcRoot, "index.func.ts"),
|
|
34
|
+
staging,
|
|
35
|
+
logger
|
|
36
|
+
);
|
|
37
|
+
const server = config && typeof config === "object" ? config.server : void 0;
|
|
38
|
+
const resolvedRoot = server && typeof server.root === "string" && server.root.length ? resolve(projectRoot, server.root) : projectRoot;
|
|
39
|
+
const resolvedBase = server && typeof server.base === "string" && server.base.length ? server.base : defaultBase;
|
|
40
|
+
return {
|
|
41
|
+
root: resolvedRoot,
|
|
42
|
+
base: resolvedBase,
|
|
43
|
+
staging
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/typegen.ts
|
|
48
|
+
function normalizeSlashes(path) {
|
|
49
|
+
return path.replace(/\\/g, "/");
|
|
50
|
+
}
|
|
51
|
+
function normalizeRoute(path) {
|
|
52
|
+
const normalized = path.replace(/\/+/g, "/");
|
|
53
|
+
if (!normalized.length || normalized === "/") return "/";
|
|
54
|
+
return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
55
|
+
}
|
|
56
|
+
function toRoute(srcRoot, file) {
|
|
57
|
+
const relativePath = normalizeSlashes(relative(srcRoot, file));
|
|
58
|
+
const noTsPath = relativePath.replace(/\.ts$/, "");
|
|
59
|
+
if (noTsPath === "index.func") return { route: "/", priority: 2 };
|
|
60
|
+
if (noTsPath === "default.func") return { route: "/*", priority: 1 };
|
|
61
|
+
if (noTsPath.endsWith("/index.func"))
|
|
62
|
+
return {
|
|
63
|
+
route: normalizeRoute(`/${noTsPath.slice(0, -"/index.func".length)}`),
|
|
64
|
+
priority: 2
|
|
65
|
+
};
|
|
66
|
+
if (noTsPath.endsWith("/default.func"))
|
|
67
|
+
return {
|
|
68
|
+
route: normalizeRoute(`/${noTsPath.slice(0, -"/default.func".length)}/*`),
|
|
69
|
+
priority: 1
|
|
70
|
+
};
|
|
71
|
+
if (noTsPath.endsWith(".func"))
|
|
72
|
+
return {
|
|
73
|
+
route: normalizeRoute(`/${noTsPath.slice(0, -".func".length)}`),
|
|
74
|
+
priority: 3
|
|
75
|
+
};
|
|
76
|
+
throw Error(`[faas-types] Invalid func filename: ${file}`);
|
|
77
|
+
}
|
|
78
|
+
function toImportPath(fromFile, targetFile) {
|
|
79
|
+
const fromDir = dirname(fromFile);
|
|
80
|
+
const importPath = normalizeSlashes(relative(fromDir, targetFile)).replace(
|
|
81
|
+
/\.ts$/,
|
|
82
|
+
""
|
|
83
|
+
);
|
|
84
|
+
if (importPath.startsWith(".")) return importPath;
|
|
85
|
+
return `./${importPath}`;
|
|
86
|
+
}
|
|
87
|
+
function parsePluginTypes(config) {
|
|
88
|
+
const pluginConfig = config.plugins;
|
|
89
|
+
if (!pluginConfig || typeof pluginConfig !== "object") return [];
|
|
90
|
+
const pluginTypes = /* @__PURE__ */ new Set();
|
|
91
|
+
for (const key in pluginConfig) {
|
|
92
|
+
const data = pluginConfig[key];
|
|
93
|
+
if (typeof data === "string" && data.length) {
|
|
94
|
+
pluginTypes.add(data);
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
if (data && typeof data === "object") {
|
|
98
|
+
if (typeof data.type === "string" && data.type.length)
|
|
99
|
+
pluginTypes.add(data.type);
|
|
100
|
+
else pluginTypes.add(key);
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
pluginTypes.add(key);
|
|
104
|
+
}
|
|
105
|
+
return Array.from(pluginTypes).sort((a, b) => a.localeCompare(b));
|
|
106
|
+
}
|
|
107
|
+
async function readFuncFiles(dir) {
|
|
108
|
+
const result = [];
|
|
109
|
+
async function walk(currentDir) {
|
|
110
|
+
const entries = await readdir(currentDir, {
|
|
111
|
+
withFileTypes: true
|
|
112
|
+
});
|
|
113
|
+
for (const entry of entries) {
|
|
114
|
+
if (entry.name === ".faasjs" || entry.name === "node_modules") continue;
|
|
115
|
+
const filePath = join(currentDir, entry.name);
|
|
116
|
+
if (entry.isDirectory()) {
|
|
117
|
+
await walk(filePath);
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
if (entry.isFile() && entry.name.endsWith(".func.ts"))
|
|
121
|
+
result.push(filePath);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
await walk(dir);
|
|
125
|
+
return result.sort((a, b) => a.localeCompare(b));
|
|
126
|
+
}
|
|
127
|
+
function formatTypes(items) {
|
|
128
|
+
const actionLines = items.map((item) => {
|
|
129
|
+
return ` ${JSON.stringify(item.route)}: __FaasFuncAction<__FaasModuleFunc<typeof import(${JSON.stringify(item.importPath)})>>`;
|
|
130
|
+
});
|
|
131
|
+
const eventLines = items.map((item) => {
|
|
132
|
+
const plugins = item.pluginTypes.length ? `[${item.pluginTypes.map((type) => JSON.stringify(type)).join(", ")}]` : "[]";
|
|
133
|
+
return ` ${JSON.stringify(item.route)}: InferPluginEvent<${plugins}>`;
|
|
134
|
+
});
|
|
135
|
+
return `/**
|
|
136
|
+
* Generated by @faasjs/dev.
|
|
137
|
+
*
|
|
138
|
+
* Do not edit this file manually.
|
|
139
|
+
*/
|
|
140
|
+
import type { Func, InferPluginEvent } from '@faasjs/func'
|
|
141
|
+
|
|
142
|
+
type __FaasModuleFunc<TModule> = TModule extends { func: infer TFunc }
|
|
143
|
+
? TFunc extends Func
|
|
144
|
+
? TFunc
|
|
145
|
+
: never
|
|
146
|
+
: TModule extends { default: infer TFunc }
|
|
147
|
+
? TFunc extends Func
|
|
148
|
+
? TFunc
|
|
149
|
+
: never
|
|
150
|
+
: never
|
|
151
|
+
|
|
152
|
+
type __FaasFuncAction<TFunc extends Func> = {
|
|
153
|
+
Params: Parameters<ReturnType<TFunc['export']>['handler']>[0]['params']
|
|
154
|
+
Data: Awaited<ReturnType<ReturnType<TFunc['export']>['handler']>>
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
declare module '@faasjs/types' {
|
|
158
|
+
interface FaasActions {
|
|
159
|
+
${actionLines.length ? `${actionLines.join("\n")}
|
|
160
|
+
` : ""} }
|
|
161
|
+
|
|
162
|
+
interface FaasEvents {
|
|
163
|
+
${eventLines.length ? `${eventLines.join("\n")}
|
|
164
|
+
` : ""} }
|
|
165
|
+
}
|
|
166
|
+
`;
|
|
167
|
+
}
|
|
168
|
+
function isTypegenSourceFile(filePath) {
|
|
169
|
+
return /\.func\.ts$/.test(filePath) || /(^|[\\/])faas\.ya?ml$/.test(filePath);
|
|
170
|
+
}
|
|
171
|
+
async function generateFaasTypes(options = {}) {
|
|
172
|
+
const logger = options.logger || new Logger("FaasJs:Typegen");
|
|
173
|
+
const { root: projectRoot, staging } = resolveServerConfig(
|
|
174
|
+
options.root || process.cwd(),
|
|
175
|
+
logger
|
|
176
|
+
);
|
|
177
|
+
const srcRoot = join(projectRoot, "src");
|
|
178
|
+
const output = join(srcRoot, ".faasjs", "types.d.ts");
|
|
179
|
+
if (!existsSync(srcRoot))
|
|
180
|
+
throw Error(`[faas-types] Source directory not found: ${srcRoot}`);
|
|
181
|
+
const files = await readFuncFiles(srcRoot);
|
|
182
|
+
const routeMap = /* @__PURE__ */ new Map();
|
|
183
|
+
for (const file of files) {
|
|
184
|
+
const { route, priority } = toRoute(srcRoot, file);
|
|
185
|
+
const config = loadConfig(srcRoot, file, staging, logger);
|
|
186
|
+
const pluginTypes = parsePluginTypes(config);
|
|
187
|
+
const importPath = toImportPath(output, file);
|
|
188
|
+
const prev = routeMap.get(route);
|
|
189
|
+
if (!prev || priority > prev.priority)
|
|
190
|
+
routeMap.set(route, {
|
|
191
|
+
route,
|
|
192
|
+
importPath,
|
|
193
|
+
pluginTypes,
|
|
194
|
+
priority
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
const items = Array.from(routeMap.values()).sort(
|
|
198
|
+
(a, b) => a.route.localeCompare(b.route)
|
|
199
|
+
);
|
|
200
|
+
const content = formatTypes(items);
|
|
201
|
+
let changed = true;
|
|
202
|
+
try {
|
|
203
|
+
const previous = await readFile(output, "utf8");
|
|
204
|
+
if (previous === content) changed = false;
|
|
205
|
+
} catch (_error) {
|
|
206
|
+
}
|
|
207
|
+
if (changed) {
|
|
208
|
+
await mkdir(dirname(output), {
|
|
209
|
+
recursive: true
|
|
210
|
+
});
|
|
211
|
+
await writeFile(output, content);
|
|
212
|
+
}
|
|
213
|
+
return {
|
|
214
|
+
output,
|
|
215
|
+
changed,
|
|
216
|
+
fileCount: files.length,
|
|
217
|
+
routeCount: items.length
|
|
218
|
+
};
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
export { __export, __reExport, generateFaasTypes, isTypegenSourceFile, resolveServerConfig };
|
package/dist/cli.cjs
ADDED
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var fs = require('fs');
|
|
4
|
+
var promises = require('fs/promises');
|
|
5
|
+
var path = require('path');
|
|
6
|
+
var load = require('@faasjs/load');
|
|
7
|
+
var logger = require('@faasjs/logger');
|
|
8
|
+
|
|
9
|
+
// package.json
|
|
10
|
+
var package_default = {
|
|
11
|
+
name: "@faasjs/dev",
|
|
12
|
+
version: "v8.0.0-beta.5",
|
|
13
|
+
license: "MIT",
|
|
14
|
+
type: "module",
|
|
15
|
+
main: "dist/index.cjs",
|
|
16
|
+
module: "dist/index.mjs",
|
|
17
|
+
types: "dist/index.d.ts",
|
|
18
|
+
bin: {
|
|
19
|
+
"faas-types": "faas-types.mjs"
|
|
20
|
+
},
|
|
21
|
+
exports: {
|
|
22
|
+
".": {
|
|
23
|
+
types: "./dist/index.d.ts",
|
|
24
|
+
import: "./dist/index.mjs",
|
|
25
|
+
require: "./dist/index.cjs"
|
|
26
|
+
}
|
|
27
|
+
},
|
|
28
|
+
homepage: "https://faasjs.com/doc/dev",
|
|
29
|
+
repository: {
|
|
30
|
+
type: "git",
|
|
31
|
+
url: "git+https://github.com/faasjs/faasjs.git",
|
|
32
|
+
directory: "packages/dev"
|
|
33
|
+
},
|
|
34
|
+
bugs: {
|
|
35
|
+
url: "https://github.com/faasjs/faasjs/issues"
|
|
36
|
+
},
|
|
37
|
+
funding: "https://github.com/sponsors/faasjs",
|
|
38
|
+
scripts: {
|
|
39
|
+
build: "tsup-node --entry src/index.ts --entry src/cli.ts --config ../../tsup.config.ts"
|
|
40
|
+
},
|
|
41
|
+
files: [
|
|
42
|
+
"dist",
|
|
43
|
+
"faas-types.mjs"
|
|
44
|
+
],
|
|
45
|
+
peerDependencies: {
|
|
46
|
+
"@electric-sql/pglite": "*",
|
|
47
|
+
"@faasjs/deep_merge": ">=v8.0.0-beta.5",
|
|
48
|
+
"@faasjs/func": ">=v8.0.0-beta.5",
|
|
49
|
+
"@faasjs/http": ">=v8.0.0-beta.5",
|
|
50
|
+
"@faasjs/server": ">=v8.0.0-beta.5",
|
|
51
|
+
"@faasjs/knex": ">=v8.0.0-beta.5",
|
|
52
|
+
"@faasjs/load": ">=v8.0.0-beta.5",
|
|
53
|
+
"@faasjs/logger": ">=v8.0.0-beta.5",
|
|
54
|
+
"@types/node": "*",
|
|
55
|
+
knex: "*",
|
|
56
|
+
vite: "*",
|
|
57
|
+
vitest: "*",
|
|
58
|
+
"knex-pglite": "*"
|
|
59
|
+
},
|
|
60
|
+
devDependencies: {
|
|
61
|
+
"@electric-sql/pglite": "*",
|
|
62
|
+
"@faasjs/deep_merge": ">=v8.0.0-beta.5",
|
|
63
|
+
"@faasjs/func": ">=v8.0.0-beta.5",
|
|
64
|
+
"@faasjs/http": ">=v8.0.0-beta.5",
|
|
65
|
+
"@faasjs/server": ">=v8.0.0-beta.5",
|
|
66
|
+
"@faasjs/knex": ">=v8.0.0-beta.5",
|
|
67
|
+
"@faasjs/load": ">=v8.0.0-beta.5",
|
|
68
|
+
"@faasjs/logger": ">=v8.0.0-beta.5",
|
|
69
|
+
"@types/node": "*",
|
|
70
|
+
knex: "*",
|
|
71
|
+
vite: "*",
|
|
72
|
+
vitest: "*",
|
|
73
|
+
"knex-pglite": "*"
|
|
74
|
+
},
|
|
75
|
+
engines: {
|
|
76
|
+
node: ">=24.0.0",
|
|
77
|
+
npm: ">=11.0.0"
|
|
78
|
+
}
|
|
79
|
+
};
|
|
80
|
+
function resolveFaasStaging() {
|
|
81
|
+
return process.env.FaasEnv || "development";
|
|
82
|
+
}
|
|
83
|
+
function resolveServerConfig(root, logger, defaultBase = "/") {
|
|
84
|
+
const projectRoot = path.resolve(root);
|
|
85
|
+
const staging = resolveFaasStaging();
|
|
86
|
+
const srcRoot = path.join(projectRoot, "src");
|
|
87
|
+
const config = load.loadConfig(
|
|
88
|
+
srcRoot,
|
|
89
|
+
path.join(srcRoot, "index.func.ts"),
|
|
90
|
+
staging,
|
|
91
|
+
logger
|
|
92
|
+
);
|
|
93
|
+
const server = config && typeof config === "object" ? config.server : void 0;
|
|
94
|
+
const resolvedRoot = server && typeof server.root === "string" && server.root.length ? path.resolve(projectRoot, server.root) : projectRoot;
|
|
95
|
+
const resolvedBase = server && typeof server.base === "string" && server.base.length ? server.base : defaultBase;
|
|
96
|
+
return {
|
|
97
|
+
root: resolvedRoot,
|
|
98
|
+
base: resolvedBase,
|
|
99
|
+
staging
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
// src/typegen.ts
|
|
104
|
+
function normalizeSlashes(path) {
|
|
105
|
+
return path.replace(/\\/g, "/");
|
|
106
|
+
}
|
|
107
|
+
function normalizeRoute(path) {
|
|
108
|
+
const normalized = path.replace(/\/+/g, "/");
|
|
109
|
+
if (!normalized.length || normalized === "/") return "/";
|
|
110
|
+
return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
|
|
111
|
+
}
|
|
112
|
+
function toRoute(srcRoot, file) {
|
|
113
|
+
const relativePath = normalizeSlashes(path.relative(srcRoot, file));
|
|
114
|
+
const noTsPath = relativePath.replace(/\.ts$/, "");
|
|
115
|
+
if (noTsPath === "index.func") return { route: "/", priority: 2 };
|
|
116
|
+
if (noTsPath === "default.func") return { route: "/*", priority: 1 };
|
|
117
|
+
if (noTsPath.endsWith("/index.func"))
|
|
118
|
+
return {
|
|
119
|
+
route: normalizeRoute(`/${noTsPath.slice(0, -"/index.func".length)}`),
|
|
120
|
+
priority: 2
|
|
121
|
+
};
|
|
122
|
+
if (noTsPath.endsWith("/default.func"))
|
|
123
|
+
return {
|
|
124
|
+
route: normalizeRoute(`/${noTsPath.slice(0, -"/default.func".length)}/*`),
|
|
125
|
+
priority: 1
|
|
126
|
+
};
|
|
127
|
+
if (noTsPath.endsWith(".func"))
|
|
128
|
+
return {
|
|
129
|
+
route: normalizeRoute(`/${noTsPath.slice(0, -".func".length)}`),
|
|
130
|
+
priority: 3
|
|
131
|
+
};
|
|
132
|
+
throw Error(`[faas-types] Invalid func filename: ${file}`);
|
|
133
|
+
}
|
|
134
|
+
function toImportPath(fromFile, targetFile) {
|
|
135
|
+
const fromDir = path.dirname(fromFile);
|
|
136
|
+
const importPath = normalizeSlashes(path.relative(fromDir, targetFile)).replace(
|
|
137
|
+
/\.ts$/,
|
|
138
|
+
""
|
|
139
|
+
);
|
|
140
|
+
if (importPath.startsWith(".")) return importPath;
|
|
141
|
+
return `./${importPath}`;
|
|
142
|
+
}
|
|
143
|
+
function parsePluginTypes(config) {
|
|
144
|
+
const pluginConfig = config.plugins;
|
|
145
|
+
if (!pluginConfig || typeof pluginConfig !== "object") return [];
|
|
146
|
+
const pluginTypes = /* @__PURE__ */ new Set();
|
|
147
|
+
for (const key in pluginConfig) {
|
|
148
|
+
const data = pluginConfig[key];
|
|
149
|
+
if (typeof data === "string" && data.length) {
|
|
150
|
+
pluginTypes.add(data);
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
if (data && typeof data === "object") {
|
|
154
|
+
if (typeof data.type === "string" && data.type.length)
|
|
155
|
+
pluginTypes.add(data.type);
|
|
156
|
+
else pluginTypes.add(key);
|
|
157
|
+
continue;
|
|
158
|
+
}
|
|
159
|
+
pluginTypes.add(key);
|
|
160
|
+
}
|
|
161
|
+
return Array.from(pluginTypes).sort((a, b) => a.localeCompare(b));
|
|
162
|
+
}
|
|
163
|
+
async function readFuncFiles(dir) {
|
|
164
|
+
const result = [];
|
|
165
|
+
async function walk(currentDir) {
|
|
166
|
+
const entries = await promises.readdir(currentDir, {
|
|
167
|
+
withFileTypes: true
|
|
168
|
+
});
|
|
169
|
+
for (const entry of entries) {
|
|
170
|
+
if (entry.name === ".faasjs" || entry.name === "node_modules") continue;
|
|
171
|
+
const filePath = path.join(currentDir, entry.name);
|
|
172
|
+
if (entry.isDirectory()) {
|
|
173
|
+
await walk(filePath);
|
|
174
|
+
continue;
|
|
175
|
+
}
|
|
176
|
+
if (entry.isFile() && entry.name.endsWith(".func.ts"))
|
|
177
|
+
result.push(filePath);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
await walk(dir);
|
|
181
|
+
return result.sort((a, b) => a.localeCompare(b));
|
|
182
|
+
}
|
|
183
|
+
function formatTypes(items) {
|
|
184
|
+
const actionLines = items.map((item) => {
|
|
185
|
+
return ` ${JSON.stringify(item.route)}: __FaasFuncAction<__FaasModuleFunc<typeof import(${JSON.stringify(item.importPath)})>>`;
|
|
186
|
+
});
|
|
187
|
+
const eventLines = items.map((item) => {
|
|
188
|
+
const plugins = item.pluginTypes.length ? `[${item.pluginTypes.map((type) => JSON.stringify(type)).join(", ")}]` : "[]";
|
|
189
|
+
return ` ${JSON.stringify(item.route)}: InferPluginEvent<${plugins}>`;
|
|
190
|
+
});
|
|
191
|
+
return `/**
|
|
192
|
+
* Generated by @faasjs/dev.
|
|
193
|
+
*
|
|
194
|
+
* Do not edit this file manually.
|
|
195
|
+
*/
|
|
196
|
+
import type { Func, InferPluginEvent } from '@faasjs/func'
|
|
197
|
+
|
|
198
|
+
type __FaasModuleFunc<TModule> = TModule extends { func: infer TFunc }
|
|
199
|
+
? TFunc extends Func
|
|
200
|
+
? TFunc
|
|
201
|
+
: never
|
|
202
|
+
: TModule extends { default: infer TFunc }
|
|
203
|
+
? TFunc extends Func
|
|
204
|
+
? TFunc
|
|
205
|
+
: never
|
|
206
|
+
: never
|
|
207
|
+
|
|
208
|
+
type __FaasFuncAction<TFunc extends Func> = {
|
|
209
|
+
Params: Parameters<ReturnType<TFunc['export']>['handler']>[0]['params']
|
|
210
|
+
Data: Awaited<ReturnType<ReturnType<TFunc['export']>['handler']>>
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
declare module '@faasjs/types' {
|
|
214
|
+
interface FaasActions {
|
|
215
|
+
${actionLines.length ? `${actionLines.join("\n")}
|
|
216
|
+
` : ""} }
|
|
217
|
+
|
|
218
|
+
interface FaasEvents {
|
|
219
|
+
${eventLines.length ? `${eventLines.join("\n")}
|
|
220
|
+
` : ""} }
|
|
221
|
+
}
|
|
222
|
+
`;
|
|
223
|
+
}
|
|
224
|
+
async function generateFaasTypes(options = {}) {
|
|
225
|
+
const logger$1 = options.logger || new logger.Logger("FaasJs:Typegen");
|
|
226
|
+
const { root: projectRoot, staging } = resolveServerConfig(
|
|
227
|
+
options.root || process.cwd(),
|
|
228
|
+
logger$1
|
|
229
|
+
);
|
|
230
|
+
const srcRoot = path.join(projectRoot, "src");
|
|
231
|
+
const output = path.join(srcRoot, ".faasjs", "types.d.ts");
|
|
232
|
+
if (!fs.existsSync(srcRoot))
|
|
233
|
+
throw Error(`[faas-types] Source directory not found: ${srcRoot}`);
|
|
234
|
+
const files = await readFuncFiles(srcRoot);
|
|
235
|
+
const routeMap = /* @__PURE__ */ new Map();
|
|
236
|
+
for (const file of files) {
|
|
237
|
+
const { route, priority } = toRoute(srcRoot, file);
|
|
238
|
+
const config = load.loadConfig(srcRoot, file, staging, logger$1);
|
|
239
|
+
const pluginTypes = parsePluginTypes(config);
|
|
240
|
+
const importPath = toImportPath(output, file);
|
|
241
|
+
const prev = routeMap.get(route);
|
|
242
|
+
if (!prev || priority > prev.priority)
|
|
243
|
+
routeMap.set(route, {
|
|
244
|
+
route,
|
|
245
|
+
importPath,
|
|
246
|
+
pluginTypes,
|
|
247
|
+
priority
|
|
248
|
+
});
|
|
249
|
+
}
|
|
250
|
+
const items = Array.from(routeMap.values()).sort(
|
|
251
|
+
(a, b) => a.route.localeCompare(b.route)
|
|
252
|
+
);
|
|
253
|
+
const content = formatTypes(items);
|
|
254
|
+
let changed = true;
|
|
255
|
+
try {
|
|
256
|
+
const previous = await promises.readFile(output, "utf8");
|
|
257
|
+
if (previous === content) changed = false;
|
|
258
|
+
} catch (_error) {
|
|
259
|
+
}
|
|
260
|
+
if (changed) {
|
|
261
|
+
await promises.mkdir(path.dirname(output), {
|
|
262
|
+
recursive: true
|
|
263
|
+
});
|
|
264
|
+
await promises.writeFile(output, content);
|
|
265
|
+
}
|
|
266
|
+
return {
|
|
267
|
+
output,
|
|
268
|
+
changed,
|
|
269
|
+
fileCount: files.length,
|
|
270
|
+
routeCount: items.length
|
|
271
|
+
};
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
// src/cli.ts
|
|
275
|
+
var HelpText = `Generate FaasJS API/event type declarations.
|
|
276
|
+
|
|
277
|
+
Usage:
|
|
278
|
+
faas-types [options]
|
|
279
|
+
|
|
280
|
+
Options:
|
|
281
|
+
--root <path> Project root path (default: process.cwd())
|
|
282
|
+
-h, --help Show help
|
|
283
|
+
-v, --version Show version
|
|
284
|
+
`;
|
|
285
|
+
function parseCliArgs(argv) {
|
|
286
|
+
const args = argv.slice(2);
|
|
287
|
+
const options = {};
|
|
288
|
+
const readValue = (index, name) => {
|
|
289
|
+
const value = args[index + 1];
|
|
290
|
+
if (!value || value.startsWith("-"))
|
|
291
|
+
throw Error(`[faas-types] Missing value for ${name}`);
|
|
292
|
+
return value;
|
|
293
|
+
};
|
|
294
|
+
for (let i = 0; i < args.length; i++) {
|
|
295
|
+
const arg = args[i];
|
|
296
|
+
if (arg === "-h" || arg === "--help") return { showHelp: true, options };
|
|
297
|
+
if (arg === "-v" || arg === "--version")
|
|
298
|
+
return {
|
|
299
|
+
showVersion: true,
|
|
300
|
+
options
|
|
301
|
+
};
|
|
302
|
+
if (arg === "--root") {
|
|
303
|
+
options.root = readValue(i, arg);
|
|
304
|
+
i++;
|
|
305
|
+
continue;
|
|
306
|
+
}
|
|
307
|
+
throw Error(`[faas-types] Unknown option: ${arg}`);
|
|
308
|
+
}
|
|
309
|
+
return {
|
|
310
|
+
options
|
|
311
|
+
};
|
|
312
|
+
}
|
|
313
|
+
async function main(argv = process.argv) {
|
|
314
|
+
try {
|
|
315
|
+
const parsed = parseCliArgs(argv);
|
|
316
|
+
if (parsed.showHelp) {
|
|
317
|
+
console.log(HelpText);
|
|
318
|
+
return 0;
|
|
319
|
+
}
|
|
320
|
+
if (parsed.showVersion) {
|
|
321
|
+
console.log(package_default.version);
|
|
322
|
+
return 0;
|
|
323
|
+
}
|
|
324
|
+
const result = await generateFaasTypes(parsed.options);
|
|
325
|
+
console.log(
|
|
326
|
+
`[faas-types] ${result.changed ? "Generated" : "Up to date"} ${result.output} (${result.routeCount} routes from ${result.fileCount} files)`
|
|
327
|
+
);
|
|
328
|
+
return 0;
|
|
329
|
+
} catch (error) {
|
|
330
|
+
console.error(error?.message || error);
|
|
331
|
+
return 1;
|
|
332
|
+
}
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
exports.main = main;
|
package/dist/cli.d.ts
ADDED