@kosmojs/dev 0.0.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/package.json +57 -0
- package/pkg/base-plugin/routes.js +618 -0
- package/pkg/base-plugin/routes.js.map +7 -0
- package/pkg/base-plugin/worker.js +810 -0
- package/pkg/base-plugin/worker.js.map +7 -0
- package/pkg/index.js +1004 -0
- package/pkg/index.js.map +7 -0
- package/pkg/src/alias-plugin/index.d.ts +5 -0
- package/pkg/src/base-plugin/api-handler.d.ts +10 -0
- package/pkg/src/base-plugin/ast.d.ts +49 -0
- package/pkg/src/base-plugin/cache.d.ts +20 -0
- package/pkg/src/base-plugin/index.d.ts +4 -0
- package/pkg/src/base-plugin/routes.d.ts +13 -0
- package/pkg/src/base-plugin/spinner.d.ts +8 -0
- package/pkg/src/base-plugin/worker.d.ts +17 -0
- package/pkg/src/define-plugin/index.d.ts +9 -0
- package/pkg/src/index.d.ts +6 -0
- package/pkg/src/stub-generator/index.d.ts +8 -0
- package/pkg/stub-generator/index.js +51 -0
- package/pkg/stub-generator/index.js.map +7 -0
- package/pkg/test/@fixtures/app/@src/api/articles/[...path]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/@src/api/books/[category]/[[author]]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/@src/api/books/[category]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/@src/api/books/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/@src/api/files/[[folder]]/[[id]].json/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/@src/api/files/[[folder]]/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/@src/api/index/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/@src/api/pages/[...path].html/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/@src/api/users/[id].json/index.d.ts +0 -0
- package/pkg/test/@fixtures/app/lib/@src/{api}/articles/[...path]/types.d.ts +3 -0
- package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/[[author]]/types.d.ts +4 -0
- package/pkg/test/@fixtures/app/lib/@src/{api}/books/[category]/types.d.ts +3 -0
- package/pkg/test/@fixtures/app/lib/@src/{api}/books/types.d.ts +1 -0
- package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/[[id]].json/types.d.ts +4 -0
- package/pkg/test/@fixtures/app/lib/@src/{api}/files/[[folder]]/types.d.ts +3 -0
- package/pkg/test/@fixtures/app/lib/@src/{api}/index/types.d.ts +1 -0
- package/pkg/test/@fixtures/app/lib/@src/{api}/pages/[...path].html/types.d.ts +3 -0
- package/pkg/test/@fixtures/app/lib/@src/{api}/users/[id].json/types.d.ts +3 -0
- package/pkg/test/@fixtures/ast/extractTypeDeclarations/exports/with-referenced-files.d.ts +1 -0
- package/pkg/test/@fixtures/ast/extractTypeDeclarations/imports/with-referenced-files.d.ts +1 -0
- package/pkg/test/ast/extractParamsRefinements.test.d.ts +1 -0
- package/pkg/test/ast/extractRouteMethods.test.d.ts +1 -0
- package/pkg/test/ast/extractTypeDeclarations.test.d.ts +1 -0
- package/pkg/test/routes/resolver.test.d.ts +1 -0
package/pkg/index.js
ADDED
|
@@ -0,0 +1,1004 @@
|
|
|
1
|
+
// src/index.ts
|
|
2
|
+
import { default as default2 } from "@kosmojs/api-generator";
|
|
3
|
+
import { default as default3 } from "@kosmojs/fetch-generator";
|
|
4
|
+
|
|
5
|
+
// src/alias-plugin/index.ts
|
|
6
|
+
import { glob } from "tinyglobby";
|
|
7
|
+
var alias_plugin_default = (appRoot, opt) => {
|
|
8
|
+
return {
|
|
9
|
+
name: "@kosmojs:aliasPlugin",
|
|
10
|
+
async config() {
|
|
11
|
+
const compilerOptions = await import(`${appRoot}/tsconfig.json`, {
|
|
12
|
+
with: { type: "json" }
|
|
13
|
+
}).then((e) => e.default.compilerOptions);
|
|
14
|
+
const aliasmap = [];
|
|
15
|
+
const pathEntries = Object.entries({ ...compilerOptions?.paths });
|
|
16
|
+
for (const [aliasPattern, pathPatterns] of pathEntries) {
|
|
17
|
+
const alias = aliasPattern.replace("/*", "");
|
|
18
|
+
const paths = pathPatterns.map((e) => e.replace("/*", "")).sort((a, b) => a.split(/\/+/).length - b.split(/\/+/).length);
|
|
19
|
+
if (paths.length === 1) {
|
|
20
|
+
aliasmap.push({
|
|
21
|
+
find: new RegExp(`^${alias}/`),
|
|
22
|
+
replacement: `${appRoot}/${paths[0]}/`
|
|
23
|
+
});
|
|
24
|
+
} else if (paths.length > 1) {
|
|
25
|
+
aliasmap.push({
|
|
26
|
+
find: new RegExp(`^${alias}/`),
|
|
27
|
+
replacement: "",
|
|
28
|
+
async customResolver(_src) {
|
|
29
|
+
const src = _src.replace(/(\$|\^|\+|\(|\)|\[|\])/g, "\\$1");
|
|
30
|
+
const patterns = paths.flatMap((path) => [
|
|
31
|
+
// Case 1: Extension is explicitly provided
|
|
32
|
+
// e.g. import styles from "@admin/{solid}/styles.module.css"
|
|
33
|
+
`${path}/${src}*`,
|
|
34
|
+
// Case 2: No extension provided
|
|
35
|
+
// Match any extension and return the first match
|
|
36
|
+
`${path}/${src}.*`,
|
|
37
|
+
// Case 3: Folder containing an index file of any extension
|
|
38
|
+
`${path}/${src}/index.*`
|
|
39
|
+
]);
|
|
40
|
+
const [file] = await glob(patterns, {
|
|
41
|
+
cwd: appRoot,
|
|
42
|
+
onlyFiles: true,
|
|
43
|
+
absolute: true,
|
|
44
|
+
dot: true,
|
|
45
|
+
followSymbolicLinks: false,
|
|
46
|
+
braceExpansion: false,
|
|
47
|
+
globstar: false,
|
|
48
|
+
ignore: opt?.ignore || [
|
|
49
|
+
"**/.git/**",
|
|
50
|
+
"**/node_modules/**",
|
|
51
|
+
"**/public/**",
|
|
52
|
+
"**/var/**"
|
|
53
|
+
]
|
|
54
|
+
});
|
|
55
|
+
return file;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return {
|
|
61
|
+
resolve: {
|
|
62
|
+
alias: aliasmap
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
// src/base-plugin/index.ts
|
|
70
|
+
import { basename, join as join3, resolve as resolve5 } from "node:path";
|
|
71
|
+
import { styleText as styleText2 } from "node:util";
|
|
72
|
+
import { Worker } from "node:worker_threads";
|
|
73
|
+
import apiGenerator from "@kosmojs/api-generator";
|
|
74
|
+
import stubGenerator from "@kosmojs/dev/stub-generator";
|
|
75
|
+
import fetchGenerator from "@kosmojs/fetch-generator";
|
|
76
|
+
|
|
77
|
+
// src/base-plugin/api-handler.ts
|
|
78
|
+
import { join, resolve } from "node:path";
|
|
79
|
+
import { styleText } from "node:util";
|
|
80
|
+
import { context } from "esbuild";
|
|
81
|
+
import { defaults } from "@kosmojs/devlib";
|
|
82
|
+
var api_handler_default = async (options) => {
|
|
83
|
+
const { appRoot, sourceFolder, baseurl, apiurl } = options;
|
|
84
|
+
const apiDir = join(sourceFolder, defaults.apiDir);
|
|
85
|
+
const outDir = join(options.outDir, defaults.apiDir);
|
|
86
|
+
const esbuildOptions = await import(resolve(appRoot, "esbuild.json"), { with: { type: "json" } }).then((e) => e.default);
|
|
87
|
+
let app;
|
|
88
|
+
let devMiddlewareFactory;
|
|
89
|
+
let teardownHandler;
|
|
90
|
+
const watcher = async () => {
|
|
91
|
+
const outfile = join(outDir, "dev.js");
|
|
92
|
+
const rebuildPlugin = {
|
|
93
|
+
name: "rebuild",
|
|
94
|
+
setup(build) {
|
|
95
|
+
build.onEnd(async () => {
|
|
96
|
+
if (app) {
|
|
97
|
+
await teardownHandler?.(app);
|
|
98
|
+
}
|
|
99
|
+
try {
|
|
100
|
+
const exports = await import([outfile, Date.now()].join("?"));
|
|
101
|
+
devMiddlewareFactory = exports.devMiddlewareFactory;
|
|
102
|
+
teardownHandler = exports.teardownHandler;
|
|
103
|
+
app = await exports.default();
|
|
104
|
+
console.debug(`${styleText("green", "\u279C")} Api handler ready`);
|
|
105
|
+
} catch (error) {
|
|
106
|
+
console.error(`${styleText("red", "\u2717")} Api handler error`);
|
|
107
|
+
console.error(error);
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
const ctx = await context({
|
|
113
|
+
...esbuildOptions,
|
|
114
|
+
logLevel: "error",
|
|
115
|
+
bundle: true,
|
|
116
|
+
entryPoints: [join(apiDir, "app.ts")],
|
|
117
|
+
plugins: [rebuildPlugin],
|
|
118
|
+
outfile
|
|
119
|
+
});
|
|
120
|
+
return {
|
|
121
|
+
async start() {
|
|
122
|
+
await ctx.watch({
|
|
123
|
+
// waits this many milliseconds before rebuilding after a change is detected
|
|
124
|
+
delay: options.watcher.delay
|
|
125
|
+
});
|
|
126
|
+
},
|
|
127
|
+
async stop() {
|
|
128
|
+
await ctx.dispose();
|
|
129
|
+
}
|
|
130
|
+
};
|
|
131
|
+
};
|
|
132
|
+
const devMiddleware = async (req, res, viteHandler) => {
|
|
133
|
+
const next = () => {
|
|
134
|
+
return viteHandler();
|
|
135
|
+
};
|
|
136
|
+
if (devMiddlewareFactory) {
|
|
137
|
+
const handler = devMiddlewareFactory(app);
|
|
138
|
+
await handler(req, res, next);
|
|
139
|
+
} else {
|
|
140
|
+
!req?.url || !new RegExp(`^${join(baseurl, apiurl)}($|/)`).test(req.url) ? next() : await app?.callback()(req, res);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
return {
|
|
144
|
+
watcher,
|
|
145
|
+
devMiddleware
|
|
146
|
+
};
|
|
147
|
+
};
|
|
148
|
+
|
|
149
|
+
// src/base-plugin/routes.ts
|
|
150
|
+
import { dirname, join as join2, resolve as resolve4 } from "node:path";
|
|
151
|
+
import crc3 from "crc/crc32";
|
|
152
|
+
import picomatch from "picomatch";
|
|
153
|
+
import { glob as glob2 } from "tinyglobby";
|
|
154
|
+
import {
|
|
155
|
+
defaults as defaults2,
|
|
156
|
+
pathResolver as pathResolver2,
|
|
157
|
+
pathTokensFactory,
|
|
158
|
+
render,
|
|
159
|
+
renderToFile
|
|
160
|
+
} from "@kosmojs/devlib";
|
|
161
|
+
|
|
162
|
+
// src/base-plugin/ast.ts
|
|
163
|
+
import { resolve as resolve2 } from "node:path";
|
|
164
|
+
import crc from "crc/crc32";
|
|
165
|
+
import { flattener } from "tfusion";
|
|
166
|
+
import {
|
|
167
|
+
Project,
|
|
168
|
+
SyntaxKind
|
|
169
|
+
} from "ts-morph";
|
|
170
|
+
import { HTTPMethods } from "@kosmojs/api";
|
|
171
|
+
var createProject = (opts) => new Project(opts);
|
|
172
|
+
var resolveRouteSignature = async (route, opts) => {
|
|
173
|
+
const {
|
|
174
|
+
sourceFile = createProject().addSourceFileAtPath(route.fileFullpath)
|
|
175
|
+
} = { ...opts };
|
|
176
|
+
const [typeDeclarations, referencedFiles] = extractTypeDeclarations(
|
|
177
|
+
sourceFile,
|
|
178
|
+
opts
|
|
179
|
+
);
|
|
180
|
+
const defaultExport = extractDefaultExport(sourceFile);
|
|
181
|
+
const paramsRefinements = defaultExport ? extractParamsRefinements(defaultExport) : void 0;
|
|
182
|
+
const methods = defaultExport ? extractRouteMethods(defaultExport, route) : [];
|
|
183
|
+
const payloadTypes = methods.flatMap((e) => {
|
|
184
|
+
return e.payloadType ? [e.payloadType] : [];
|
|
185
|
+
});
|
|
186
|
+
const responseTypes = methods.flatMap((e) => {
|
|
187
|
+
return e.responseType ? [e.responseType] : [];
|
|
188
|
+
});
|
|
189
|
+
return {
|
|
190
|
+
typeDeclarations,
|
|
191
|
+
paramsRefinements,
|
|
192
|
+
methods: methods.map((e) => e.method),
|
|
193
|
+
payloadTypes,
|
|
194
|
+
responseTypes,
|
|
195
|
+
referencedFiles
|
|
196
|
+
};
|
|
197
|
+
};
|
|
198
|
+
var extractDefaultExport = (sourceFile) => {
|
|
199
|
+
const [defaultExport] = sourceFile.getExportAssignments().flatMap((exportAssignment) => {
|
|
200
|
+
if (exportAssignment.isExportEquals()) {
|
|
201
|
+
return [];
|
|
202
|
+
}
|
|
203
|
+
const callExpression = exportAssignment.getExpression();
|
|
204
|
+
return callExpression.isKind(SyntaxKind.CallExpression) ? [callExpression] : [];
|
|
205
|
+
});
|
|
206
|
+
return defaultExport;
|
|
207
|
+
};
|
|
208
|
+
var extractParamsRefinements = (callExpression) => {
|
|
209
|
+
const [firstGeneric] = extractGenerics(callExpression);
|
|
210
|
+
if (!firstGeneric?.node.isKind(SyntaxKind.TupleType)) {
|
|
211
|
+
return;
|
|
212
|
+
}
|
|
213
|
+
const tupleElements = firstGeneric.node.getElements();
|
|
214
|
+
if (!tupleElements?.length) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
return tupleElements.map((node, index) => {
|
|
218
|
+
return {
|
|
219
|
+
index,
|
|
220
|
+
text: node.getText()
|
|
221
|
+
};
|
|
222
|
+
});
|
|
223
|
+
};
|
|
224
|
+
var extractRouteMethods = (callExpression, route) => {
|
|
225
|
+
const funcDeclaration = callExpression.getFirstChildByKind(SyntaxKind.ArrowFunction) || callExpression.getFirstChildByKind(SyntaxKind.FunctionExpression);
|
|
226
|
+
if (!funcDeclaration) {
|
|
227
|
+
return [];
|
|
228
|
+
}
|
|
229
|
+
const arrayLiteralExpression = funcDeclaration.getFirstChildByKind(
|
|
230
|
+
SyntaxKind.ArrayLiteralExpression
|
|
231
|
+
);
|
|
232
|
+
if (!arrayLiteralExpression) {
|
|
233
|
+
return [];
|
|
234
|
+
}
|
|
235
|
+
const callExpressions = [];
|
|
236
|
+
for (const e of arrayLiteralExpression.getChildrenOfKind(
|
|
237
|
+
SyntaxKind.CallExpression
|
|
238
|
+
)) {
|
|
239
|
+
const name = e.getExpression().getText();
|
|
240
|
+
if (HTTPMethods[name]) {
|
|
241
|
+
callExpressions.push([e, name]);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
const methods = [];
|
|
245
|
+
const skipValidationFilter = (e) => /@skip-validation/.test(e);
|
|
246
|
+
for (const [callExpression2, method] of callExpressions) {
|
|
247
|
+
const [payloadGeneric, responseGeneric] = extractGenerics(callExpression2);
|
|
248
|
+
const payloadText = payloadGeneric?.node ? payloadGeneric.node.getChildren().length === 0 ? "{}" : payloadGeneric.node.getFullText() : void 0;
|
|
249
|
+
const responseText = responseGeneric?.node.getText();
|
|
250
|
+
const responseType = responseText ? {
|
|
251
|
+
id: ["ResponseT", crc(route.importName + method)].join(""),
|
|
252
|
+
method,
|
|
253
|
+
skipValidation: responseGeneric?.comments ? responseGeneric.comments.some(skipValidationFilter) : false,
|
|
254
|
+
text: ["never", "object"].includes(responseText) ? "{}" : responseText,
|
|
255
|
+
resolvedType: void 0
|
|
256
|
+
} : void 0;
|
|
257
|
+
const payloadType = payloadText ? {
|
|
258
|
+
id: ["PayloadT", crc(route.importName + method)].join(""),
|
|
259
|
+
responseTypeId: responseType?.id,
|
|
260
|
+
method,
|
|
261
|
+
skipValidation: payloadGeneric?.comments ? payloadGeneric.comments.some(skipValidationFilter) : false,
|
|
262
|
+
isOptional: payloadText ? payloadText === "{}" || route.optionalParams : true,
|
|
263
|
+
text: payloadText,
|
|
264
|
+
resolvedType: void 0
|
|
265
|
+
} : void 0;
|
|
266
|
+
methods.push({
|
|
267
|
+
method,
|
|
268
|
+
payloadType,
|
|
269
|
+
responseType
|
|
270
|
+
});
|
|
271
|
+
}
|
|
272
|
+
return methods;
|
|
273
|
+
};
|
|
274
|
+
var extractTypeDeclarations = (sourceFile, opts) => {
|
|
275
|
+
const declarations = [];
|
|
276
|
+
const referencedFiles = opts?.withReferencedFiles ? [] : void 0;
|
|
277
|
+
for (const declaration of sourceFile.getImportDeclarations()) {
|
|
278
|
+
const modulePath = declaration.getModuleSpecifierValue();
|
|
279
|
+
const path = /^\.\.?\/?/.test(modulePath) ? opts?.relpathResolver ? opts.relpathResolver(modulePath) : modulePath : modulePath;
|
|
280
|
+
const typeOnlyDeclaration = declaration.isTypeOnly();
|
|
281
|
+
const defaultImport = typeOnlyDeclaration ? declaration.getDefaultImport() : void 0;
|
|
282
|
+
if (defaultImport) {
|
|
283
|
+
const name = defaultImport.getText();
|
|
284
|
+
const text = `import type ${name} from "${path}";`;
|
|
285
|
+
declarations.push({
|
|
286
|
+
importDeclaration: {
|
|
287
|
+
name,
|
|
288
|
+
path
|
|
289
|
+
},
|
|
290
|
+
text
|
|
291
|
+
});
|
|
292
|
+
if (referencedFiles) {
|
|
293
|
+
referencedFiles.push(...getReferencedFiles(defaultImport));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
for (const namedImport of declaration.getNamedImports()) {
|
|
297
|
+
if (namedImport.isTypeOnly() || typeOnlyDeclaration) {
|
|
298
|
+
const nameNode = namedImport.getNameNode();
|
|
299
|
+
const name = nameNode.getText();
|
|
300
|
+
const alias = namedImport.getAliasNode()?.getText();
|
|
301
|
+
const nameText = alias ? `${name} as ${alias}` : name;
|
|
302
|
+
declarations.push({
|
|
303
|
+
importDeclaration: {
|
|
304
|
+
name,
|
|
305
|
+
alias,
|
|
306
|
+
path
|
|
307
|
+
},
|
|
308
|
+
text: `import type { ${nameText} } from "${path}";`
|
|
309
|
+
});
|
|
310
|
+
if (referencedFiles) {
|
|
311
|
+
if (nameNode.isKind(SyntaxKind.Identifier)) {
|
|
312
|
+
referencedFiles.push(...getReferencedFiles(nameNode));
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
for (const declaration of sourceFile.getTypeAliases()) {
|
|
319
|
+
const name = declaration.getName();
|
|
320
|
+
const text = declaration.getFullText().trim();
|
|
321
|
+
declarations.push({
|
|
322
|
+
typeAliasDeclaration: { name },
|
|
323
|
+
text
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
for (const declaration of sourceFile.getInterfaces()) {
|
|
327
|
+
const name = declaration.getName();
|
|
328
|
+
const text = declaration.getFullText().trim();
|
|
329
|
+
declarations.push({
|
|
330
|
+
interfaceDeclaration: { name },
|
|
331
|
+
text
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
for (const declaration of sourceFile.getEnums()) {
|
|
335
|
+
const name = declaration.getName();
|
|
336
|
+
const text = declaration.getFullText().trim();
|
|
337
|
+
declarations.push({
|
|
338
|
+
enumDeclaration: { name },
|
|
339
|
+
text
|
|
340
|
+
});
|
|
341
|
+
}
|
|
342
|
+
for (const declaration of sourceFile.getExportDeclarations()) {
|
|
343
|
+
const typeOnlyDeclaration = declaration.isTypeOnly();
|
|
344
|
+
const modulePath = declaration.getModuleSpecifierValue();
|
|
345
|
+
const path = modulePath ? /^\.\.?\/?/.test(modulePath) ? opts?.relpathResolver ? opts.relpathResolver(modulePath) : modulePath : modulePath : void 0;
|
|
346
|
+
for (const namedExport of declaration.getNamedExports()) {
|
|
347
|
+
if (namedExport.isTypeOnly() || typeOnlyDeclaration) {
|
|
348
|
+
const nameNode = namedExport.getNameNode();
|
|
349
|
+
const name = nameNode.getText();
|
|
350
|
+
const alias = namedExport.getAliasNode()?.getText();
|
|
351
|
+
const nameText = alias ? `${name} as ${alias}` : name;
|
|
352
|
+
declarations.push({
|
|
353
|
+
exportDeclaration: {
|
|
354
|
+
name,
|
|
355
|
+
alias: alias ?? name,
|
|
356
|
+
path
|
|
357
|
+
},
|
|
358
|
+
text: path ? `export type { ${nameText} } from "${path}";` : `export type { ${nameText} };`
|
|
359
|
+
});
|
|
360
|
+
if (referencedFiles) {
|
|
361
|
+
if (nameNode.isKind(SyntaxKind.Identifier)) {
|
|
362
|
+
referencedFiles.push(...getReferencedFiles(nameNode));
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
}
|
|
368
|
+
return referencedFiles ? [declarations, [...new Set(referencedFiles)]] : [declarations];
|
|
369
|
+
};
|
|
370
|
+
var getReferencedFiles = (importIdentifier) => {
|
|
371
|
+
const declarations = importIdentifier?.getSymbol()?.getAliasedSymbol()?.getDeclarations() || [];
|
|
372
|
+
return declarations.flatMap((e) => {
|
|
373
|
+
const sourceFile = e.getSourceFile();
|
|
374
|
+
return sourceFile ? [sourceFile.getFilePath()] : [];
|
|
375
|
+
});
|
|
376
|
+
};
|
|
377
|
+
var extractGenerics = (callExpression) => {
|
|
378
|
+
return callExpression.getTypeArguments().map((node) => {
|
|
379
|
+
return {
|
|
380
|
+
node,
|
|
381
|
+
comments: node.getLeadingCommentRanges().map((range) => range.getText().trim())
|
|
382
|
+
};
|
|
383
|
+
});
|
|
384
|
+
};
|
|
385
|
+
var typeResolverFactory = ({ appRoot }) => {
|
|
386
|
+
const project = createProject({
|
|
387
|
+
tsConfigFilePath: resolve2(appRoot, "tsconfig.json"),
|
|
388
|
+
skipAddingFilesFromTsConfig: true
|
|
389
|
+
});
|
|
390
|
+
const literalTypesResolver = (literalTypes, options) => {
|
|
391
|
+
const sourceFile = project.createSourceFile(
|
|
392
|
+
`${crc(literalTypes)}-${Date.now()}.ts`,
|
|
393
|
+
literalTypes,
|
|
394
|
+
{ overwrite: true }
|
|
395
|
+
);
|
|
396
|
+
const resolvedTypes = flattener(project, sourceFile, {
|
|
397
|
+
...options,
|
|
398
|
+
stripComments: true
|
|
399
|
+
});
|
|
400
|
+
project.removeSourceFile(sourceFile);
|
|
401
|
+
return resolvedTypes;
|
|
402
|
+
};
|
|
403
|
+
return {
|
|
404
|
+
getSourceFile: (fileFullpath) => {
|
|
405
|
+
return project.getSourceFile(fileFullpath) || project.addSourceFileAtPath(fileFullpath);
|
|
406
|
+
},
|
|
407
|
+
refreshSourceFile: async (fileFullpath) => {
|
|
408
|
+
const sourceFile = project.getSourceFile(fileFullpath);
|
|
409
|
+
if (sourceFile) {
|
|
410
|
+
await sourceFile.refreshFromFileSystem();
|
|
411
|
+
}
|
|
412
|
+
},
|
|
413
|
+
literalTypesResolver
|
|
414
|
+
};
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
// src/base-plugin/cache.ts
|
|
418
|
+
import { resolve as resolve3 } from "node:path";
|
|
419
|
+
import crc2 from "crc/crc32";
|
|
420
|
+
import fsx from "fs-extra";
|
|
421
|
+
import pkg from "@kosmojs/dev/package.json" with { type: "json" };
|
|
422
|
+
import { pathResolver } from "@kosmojs/devlib";
|
|
423
|
+
var cacheFactory = (route, {
|
|
424
|
+
appRoot,
|
|
425
|
+
sourceFolder,
|
|
426
|
+
extraContext
|
|
427
|
+
}) => {
|
|
428
|
+
const cacheFile = pathResolver({
|
|
429
|
+
appRoot,
|
|
430
|
+
sourceFolder
|
|
431
|
+
}).resolve("apiLibDir", route.importPath, "cache.json");
|
|
432
|
+
const getCache = async (opt) => {
|
|
433
|
+
if (await fsx.exists(cacheFile)) {
|
|
434
|
+
try {
|
|
435
|
+
const cache = JSON.parse(await fsx.readFile(cacheFile, "utf8"));
|
|
436
|
+
return opt?.validate ? validateCache(cache) : cache;
|
|
437
|
+
} catch (_e) {
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
return void 0;
|
|
441
|
+
};
|
|
442
|
+
const persistCache = async ({
|
|
443
|
+
referencedFiles: _referencedFiles,
|
|
444
|
+
...rest
|
|
445
|
+
}) => {
|
|
446
|
+
const hash = await generateFileHash(route.fileFullpath, {
|
|
447
|
+
...extraContext
|
|
448
|
+
});
|
|
449
|
+
const referencedFiles = {};
|
|
450
|
+
for (const file of _referencedFiles) {
|
|
451
|
+
referencedFiles[
|
|
452
|
+
// Strip project root to ensure cached paths are relative
|
|
453
|
+
// and portable across environments (CI, local, etc.)
|
|
454
|
+
file.replace(`${appRoot}/`, "")
|
|
455
|
+
] = await generateFileHash(file);
|
|
456
|
+
}
|
|
457
|
+
const cache = { ...rest, hash, referencedFiles };
|
|
458
|
+
await fsx.outputJson(cacheFile, cache, { spaces: 2 });
|
|
459
|
+
return cache;
|
|
460
|
+
};
|
|
461
|
+
const validateCache = async (cache) => {
|
|
462
|
+
if (!cache?.hash) {
|
|
463
|
+
return;
|
|
464
|
+
}
|
|
465
|
+
if (!cache.typeDeclarations || !cache.referencedFiles) {
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const hash = await generateFileHash(route.fileFullpath, {
|
|
469
|
+
...extraContext
|
|
470
|
+
});
|
|
471
|
+
if (!identicalHashSum(cache.hash, hash)) {
|
|
472
|
+
return;
|
|
473
|
+
}
|
|
474
|
+
for (const [file, hash2] of Object.entries(cache.referencedFiles)) {
|
|
475
|
+
if (!identicalHashSum(hash2, await generateFileHash(resolve3(appRoot, file)))) {
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
478
|
+
}
|
|
479
|
+
return cache;
|
|
480
|
+
};
|
|
481
|
+
return {
|
|
482
|
+
getCache,
|
|
483
|
+
validateCache,
|
|
484
|
+
persistCache
|
|
485
|
+
};
|
|
486
|
+
};
|
|
487
|
+
var generateFileHash = async (file, extraContext) => {
|
|
488
|
+
let fileContent;
|
|
489
|
+
try {
|
|
490
|
+
fileContent = await fsx.readFile(file, "utf8");
|
|
491
|
+
} catch (_e) {
|
|
492
|
+
return 0;
|
|
493
|
+
}
|
|
494
|
+
return fileContent ? crc2(
|
|
495
|
+
JSON.stringify({
|
|
496
|
+
...extraContext,
|
|
497
|
+
[pkg.cacheVersion]: fileContent
|
|
498
|
+
})
|
|
499
|
+
) : 0;
|
|
500
|
+
};
|
|
501
|
+
var identicalHashSum = (a, b) => {
|
|
502
|
+
return a === b;
|
|
503
|
+
};
|
|
504
|
+
|
|
505
|
+
// src/base-plugin/templates/resolved-types.hbs
|
|
506
|
+
var resolved_types_default = "{{#each resolvedTypes}}\nexport type {{name}} = {{text}};\n{{/each}}\n";
|
|
507
|
+
|
|
508
|
+
// src/base-plugin/templates/types.hbs
|
|
509
|
+
var types_default = '{{#each typeDeclarations}}{{text}}\n{{/each}}\n\nexport type {{params.id}} = {\n {{#each paramsSchema}}\n "{{name}}"{{#unless isRequired}}?{{/unless}}:{{#if isRest}} Array<{{/if}}\n {{#if refinement}}{{refinement.text}}{{else}}string{{/if}}\n {{#if isRest}}>{{/if}}\n {{/each}}\n};\n\n{{#each payloadTypes}}\nexport type {{id}} = {{text}};\n{{/each}}\n\n{{#each responseTypes}}\nexport type {{id}} = {{text}};\n{{/each}}\n';
|
|
510
|
+
|
|
511
|
+
// src/base-plugin/routes.ts
|
|
512
|
+
var routes_default = async (pluginOptions) => {
|
|
513
|
+
const {
|
|
514
|
+
appRoot,
|
|
515
|
+
sourceFolder,
|
|
516
|
+
generators = [],
|
|
517
|
+
formatters = [],
|
|
518
|
+
refineTypeName
|
|
519
|
+
} = pluginOptions;
|
|
520
|
+
let resolveTypes = false;
|
|
521
|
+
for (const { options } of generators) {
|
|
522
|
+
if (options?.resolveTypes) {
|
|
523
|
+
resolveTypes = true;
|
|
524
|
+
}
|
|
525
|
+
}
|
|
526
|
+
const {
|
|
527
|
+
//
|
|
528
|
+
literalTypesResolver,
|
|
529
|
+
getSourceFile,
|
|
530
|
+
refreshSourceFile
|
|
531
|
+
} = typeResolverFactory(pluginOptions);
|
|
532
|
+
const routeFilePatterns = [
|
|
533
|
+
`${defaults2.apiDir}/**/index.ts`,
|
|
534
|
+
`${defaults2.pagesDir}/**/index.{ts,tsx,vue,svelte}`
|
|
535
|
+
];
|
|
536
|
+
const resolveRouteFile = (file) => {
|
|
537
|
+
const [_sourceFolder, folder, ...rest] = resolve4(appRoot, file).replace(`${appRoot}/`, "").split("/");
|
|
538
|
+
if (!folder || _sourceFolder !== sourceFolder || rest.length < 2) {
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
return picomatch.isMatch(join2(folder, ...rest), routeFilePatterns) ? [folder, rest.join("/")] : void 0;
|
|
542
|
+
};
|
|
543
|
+
const resolversFactory = (routeFiles2) => {
|
|
544
|
+
const resolvers = /* @__PURE__ */ new Map();
|
|
545
|
+
const entries = routeFiles2.flatMap((_file) => {
|
|
546
|
+
const resolvedPaths = resolveRouteFile(_file);
|
|
547
|
+
if (!resolvedPaths) {
|
|
548
|
+
return [];
|
|
549
|
+
}
|
|
550
|
+
const [folder, file] = resolvedPaths;
|
|
551
|
+
const fileFullpath = join2(appRoot, sourceFolder, folder, file);
|
|
552
|
+
const pathTokens = pathTokensFactory(dirname(file));
|
|
553
|
+
const name = pathTokens.map((e) => e.orig).join("/");
|
|
554
|
+
const importPath = dirname(file);
|
|
555
|
+
const importName = [
|
|
556
|
+
importPath.split(/\[/)[0].replace(/^\W+|\W+$/g, "").replace(/\W+/g, "_"),
|
|
557
|
+
crc3(importPath)
|
|
558
|
+
].join("_");
|
|
559
|
+
return [
|
|
560
|
+
{
|
|
561
|
+
name,
|
|
562
|
+
folder,
|
|
563
|
+
file,
|
|
564
|
+
fileFullpath,
|
|
565
|
+
pathTokens,
|
|
566
|
+
importPath,
|
|
567
|
+
importName
|
|
568
|
+
}
|
|
569
|
+
];
|
|
570
|
+
});
|
|
571
|
+
for (const entry of entries.filter((e) => e.folder === defaults2.apiDir)) {
|
|
572
|
+
const {
|
|
573
|
+
name,
|
|
574
|
+
file,
|
|
575
|
+
folder,
|
|
576
|
+
fileFullpath,
|
|
577
|
+
pathTokens,
|
|
578
|
+
importPath,
|
|
579
|
+
importName
|
|
580
|
+
} = entry;
|
|
581
|
+
const handler = async (updatedFile) => {
|
|
582
|
+
const paramsSchema = pathTokens.flatMap((e) => {
|
|
583
|
+
return e.param ? [e.param] : [];
|
|
584
|
+
});
|
|
585
|
+
const optionalParams = paramsSchema.length ? !paramsSchema.some((e) => e.isRequired) : true;
|
|
586
|
+
const { getCache, persistCache } = cacheFactory(
|
|
587
|
+
{ file, fileFullpath, importName, importPath },
|
|
588
|
+
{
|
|
589
|
+
appRoot,
|
|
590
|
+
sourceFolder,
|
|
591
|
+
extraContext: { resolveTypes }
|
|
592
|
+
}
|
|
593
|
+
);
|
|
594
|
+
let cache = await getCache({ validate: true });
|
|
595
|
+
if (!cache) {
|
|
596
|
+
if (updatedFile === fileFullpath) {
|
|
597
|
+
await refreshSourceFile(fileFullpath);
|
|
598
|
+
}
|
|
599
|
+
const {
|
|
600
|
+
typeDeclarations,
|
|
601
|
+
paramsRefinements,
|
|
602
|
+
methods,
|
|
603
|
+
payloadTypes,
|
|
604
|
+
responseTypes,
|
|
605
|
+
referencedFiles = []
|
|
606
|
+
} = await resolveRouteSignature(
|
|
607
|
+
{ importName, fileFullpath, optionalParams },
|
|
608
|
+
{
|
|
609
|
+
withReferencedFiles: true,
|
|
610
|
+
sourceFile: getSourceFile(fileFullpath),
|
|
611
|
+
relpathResolver(path) {
|
|
612
|
+
return join2(sourceFolder, defaults2.apiDir, dirname(file), path);
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
);
|
|
616
|
+
const numericParams = paramsRefinements ? paramsRefinements.flatMap(({ text, index }) => {
|
|
617
|
+
if (text === "number") {
|
|
618
|
+
const param = paramsSchema.at(index);
|
|
619
|
+
return param ? [param.name] : [];
|
|
620
|
+
}
|
|
621
|
+
return [];
|
|
622
|
+
}) : [];
|
|
623
|
+
const typesFile = pathResolver2({ appRoot, sourceFolder }).resolve(
|
|
624
|
+
"apiLibDir",
|
|
625
|
+
importPath,
|
|
626
|
+
"types.ts"
|
|
627
|
+
);
|
|
628
|
+
const params = {
|
|
629
|
+
id: ["ParamsT", crc3(name)].join(""),
|
|
630
|
+
schema: paramsSchema,
|
|
631
|
+
resolvedType: void 0
|
|
632
|
+
};
|
|
633
|
+
const typesFileContent = render(types_default, {
|
|
634
|
+
params,
|
|
635
|
+
paramsSchema: paramsSchema.map((param, index) => {
|
|
636
|
+
return {
|
|
637
|
+
...param,
|
|
638
|
+
refinement: paramsRefinements?.at(index)
|
|
639
|
+
};
|
|
640
|
+
}),
|
|
641
|
+
typeDeclarations,
|
|
642
|
+
payloadTypes,
|
|
643
|
+
responseTypes
|
|
644
|
+
});
|
|
645
|
+
const resolvedTypes = resolveTypes ? literalTypesResolver(typesFileContent, {
|
|
646
|
+
overrides: [...payloadTypes, ...responseTypes].reduce(
|
|
647
|
+
(map, { id, skipValidation }) => {
|
|
648
|
+
if (skipValidation) {
|
|
649
|
+
map[id] = "never";
|
|
650
|
+
}
|
|
651
|
+
return map;
|
|
652
|
+
},
|
|
653
|
+
{ [refineTypeName]: refineTypeName }
|
|
654
|
+
),
|
|
655
|
+
withProperties: [params.id, ...payloadTypes.map((e) => e.id)],
|
|
656
|
+
formatters
|
|
657
|
+
}) : void 0;
|
|
658
|
+
await renderToFile(
|
|
659
|
+
typesFile,
|
|
660
|
+
resolvedTypes ? resolved_types_default : typesFileContent,
|
|
661
|
+
{ resolvedTypes }
|
|
662
|
+
);
|
|
663
|
+
params.resolvedType = resolvedTypes?.find(
|
|
664
|
+
(e) => e.name === params.id
|
|
665
|
+
);
|
|
666
|
+
cache = await persistCache({
|
|
667
|
+
params,
|
|
668
|
+
methods,
|
|
669
|
+
typeDeclarations,
|
|
670
|
+
numericParams,
|
|
671
|
+
// text was needed at writing types.ts file, dropping from cache
|
|
672
|
+
payloadTypes: payloadTypes.map(({ text, ...rest }) => {
|
|
673
|
+
return {
|
|
674
|
+
...rest,
|
|
675
|
+
resolvedType: resolvedTypes?.find((e) => e.name === rest.id)
|
|
676
|
+
};
|
|
677
|
+
}),
|
|
678
|
+
responseTypes: responseTypes.map(({ text, ...rest }) => {
|
|
679
|
+
return {
|
|
680
|
+
...rest,
|
|
681
|
+
resolvedType: resolvedTypes?.find((e) => e.name === rest.id)
|
|
682
|
+
};
|
|
683
|
+
}),
|
|
684
|
+
referencedFiles
|
|
685
|
+
});
|
|
686
|
+
}
|
|
687
|
+
const route = {
|
|
688
|
+
name,
|
|
689
|
+
pathTokens,
|
|
690
|
+
params: cache.params,
|
|
691
|
+
numericParams: cache.numericParams,
|
|
692
|
+
optionalParams,
|
|
693
|
+
importName,
|
|
694
|
+
importPath,
|
|
695
|
+
folder,
|
|
696
|
+
file,
|
|
697
|
+
fileFullpath,
|
|
698
|
+
methods: cache.methods,
|
|
699
|
+
typeDeclarations: cache.typeDeclarations,
|
|
700
|
+
payloadTypes: cache.payloadTypes,
|
|
701
|
+
responseTypes: cache.responseTypes,
|
|
702
|
+
referencedFiles: Object.keys(cache.referencedFiles).map(
|
|
703
|
+
// expand referenced files path,
|
|
704
|
+
// they are stored as relative in cache
|
|
705
|
+
(e) => resolve4(appRoot, e)
|
|
706
|
+
)
|
|
707
|
+
};
|
|
708
|
+
return {
|
|
709
|
+
kind: "api",
|
|
710
|
+
route
|
|
711
|
+
};
|
|
712
|
+
};
|
|
713
|
+
resolvers.set(fileFullpath, { name, handler });
|
|
714
|
+
}
|
|
715
|
+
for (const entry of entries.filter((e) => e.folder === defaults2.pagesDir)) {
|
|
716
|
+
const {
|
|
717
|
+
//
|
|
718
|
+
name,
|
|
719
|
+
folder,
|
|
720
|
+
file,
|
|
721
|
+
fileFullpath,
|
|
722
|
+
pathTokens,
|
|
723
|
+
importPath,
|
|
724
|
+
importName
|
|
725
|
+
} = entry;
|
|
726
|
+
const handler = async () => {
|
|
727
|
+
const route = {
|
|
728
|
+
name,
|
|
729
|
+
pathTokens,
|
|
730
|
+
params: {
|
|
731
|
+
schema: pathTokens.flatMap((e) => e.param ? [e.param] : [])
|
|
732
|
+
},
|
|
733
|
+
folder,
|
|
734
|
+
file,
|
|
735
|
+
fileFullpath,
|
|
736
|
+
importPath,
|
|
737
|
+
importName
|
|
738
|
+
};
|
|
739
|
+
return {
|
|
740
|
+
kind: "page",
|
|
741
|
+
route
|
|
742
|
+
};
|
|
743
|
+
};
|
|
744
|
+
resolvers.set(fileFullpath, { name, handler });
|
|
745
|
+
}
|
|
746
|
+
return resolvers;
|
|
747
|
+
};
|
|
748
|
+
const routeFiles = await glob2(routeFilePatterns, {
|
|
749
|
+
cwd: resolve4(appRoot, sourceFolder),
|
|
750
|
+
absolute: true,
|
|
751
|
+
onlyFiles: true,
|
|
752
|
+
ignore: [
|
|
753
|
+
`${defaults2.apiDir}/index.ts`,
|
|
754
|
+
`${defaults2.pagesDir}/index.ts{x,}`
|
|
755
|
+
]
|
|
756
|
+
});
|
|
757
|
+
return {
|
|
758
|
+
resolvers: resolversFactory(routeFiles),
|
|
759
|
+
resolversFactory,
|
|
760
|
+
resolveRouteFile
|
|
761
|
+
};
|
|
762
|
+
};
|
|
763
|
+
|
|
764
|
+
// src/base-plugin/spinner.ts
|
|
765
|
+
import ora from "ora";
|
|
766
|
+
var spinnerFactory = (startText) => {
|
|
767
|
+
const spinner = ora().start(startText);
|
|
768
|
+
let _text = startText;
|
|
769
|
+
return {
|
|
770
|
+
text(text) {
|
|
771
|
+
_text = text;
|
|
772
|
+
spinner.text = text;
|
|
773
|
+
},
|
|
774
|
+
append(text) {
|
|
775
|
+
spinner.text = `${_text} \u203A ${text}`;
|
|
776
|
+
},
|
|
777
|
+
succeed(text) {
|
|
778
|
+
if (text) {
|
|
779
|
+
this.append(text);
|
|
780
|
+
} else {
|
|
781
|
+
this.text(_text);
|
|
782
|
+
}
|
|
783
|
+
spinner.succeed();
|
|
784
|
+
},
|
|
785
|
+
failed(text) {
|
|
786
|
+
if (text) {
|
|
787
|
+
this.text([_text, text].join("\n"));
|
|
788
|
+
}
|
|
789
|
+
spinner.fail();
|
|
790
|
+
}
|
|
791
|
+
};
|
|
792
|
+
};
|
|
793
|
+
var withSpinner = (text, pipe, spinner) => pipe(spinner || spinnerFactory(text));
|
|
794
|
+
|
|
795
|
+
// src/base-plugin/index.ts
|
|
796
|
+
var base_plugin_default = (apiurl, pluginOptions) => {
|
|
797
|
+
const outDirSuffix = "client";
|
|
798
|
+
const store = {};
|
|
799
|
+
const createWorker = () => {
|
|
800
|
+
const {
|
|
801
|
+
generators = [],
|
|
802
|
+
formatters = [],
|
|
803
|
+
...restOptions
|
|
804
|
+
} = store.resolvedOptions;
|
|
805
|
+
const generatorModules = generators.map(
|
|
806
|
+
(e) => [e.moduleImport, e.moduleConfig]
|
|
807
|
+
);
|
|
808
|
+
const formatterModules = pluginOptions?.formatters ? pluginOptions.formatters.map((e) => [e.moduleImport, e.moduleConfig]) : [];
|
|
809
|
+
const workerData = {
|
|
810
|
+
...restOptions,
|
|
811
|
+
generatorModules,
|
|
812
|
+
formatterModules
|
|
813
|
+
};
|
|
814
|
+
return new Worker(resolve5(import.meta.dirname, "base-plugin/worker.js"), {
|
|
815
|
+
workerData,
|
|
816
|
+
env: {
|
|
817
|
+
...process.env,
|
|
818
|
+
FORCE_COLOR: "1"
|
|
819
|
+
}
|
|
820
|
+
});
|
|
821
|
+
};
|
|
822
|
+
const workerHandler = (onReady, onExit) => {
|
|
823
|
+
const worker = createWorker();
|
|
824
|
+
const spinnerMap = /* @__PURE__ */ new Map();
|
|
825
|
+
worker.on("error", async (error) => {
|
|
826
|
+
console.error(error);
|
|
827
|
+
});
|
|
828
|
+
worker.on("exit", async () => {
|
|
829
|
+
await onExit?.();
|
|
830
|
+
});
|
|
831
|
+
worker.on(
|
|
832
|
+
"message",
|
|
833
|
+
async (msg) => {
|
|
834
|
+
if (msg?.spinner) {
|
|
835
|
+
const { id, startText, method, text } = msg.spinner;
|
|
836
|
+
withSpinner(
|
|
837
|
+
startText,
|
|
838
|
+
(spinner) => {
|
|
839
|
+
spinnerMap.set(id, spinner);
|
|
840
|
+
spinner[method](text || "");
|
|
841
|
+
if (method === "succeed" || method === "failed") {
|
|
842
|
+
spinnerMap.delete(id);
|
|
843
|
+
}
|
|
844
|
+
},
|
|
845
|
+
spinnerMap.get(id)
|
|
846
|
+
);
|
|
847
|
+
} else if (msg?.error) {
|
|
848
|
+
const { error } = msg;
|
|
849
|
+
if (error.stack) {
|
|
850
|
+
const [message, ...stack] = error.stack.split("\n");
|
|
851
|
+
console.error(styleText2("red", message));
|
|
852
|
+
console.error(stack.join("\n"));
|
|
853
|
+
} else if (error?.message) {
|
|
854
|
+
console.error(`${styleText2("red", error?.name)}: ${error.message}`);
|
|
855
|
+
} else {
|
|
856
|
+
console.error(error);
|
|
857
|
+
}
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
);
|
|
861
|
+
const readyHandler = async (msg) => {
|
|
862
|
+
if (msg === "ready") {
|
|
863
|
+
worker.off("message", readyHandler);
|
|
864
|
+
await onReady?.();
|
|
865
|
+
}
|
|
866
|
+
};
|
|
867
|
+
worker.on("message", readyHandler);
|
|
868
|
+
return async () => {
|
|
869
|
+
await worker.terminate();
|
|
870
|
+
};
|
|
871
|
+
};
|
|
872
|
+
return {
|
|
873
|
+
name: "@kosmojs:basePlugin",
|
|
874
|
+
config(config) {
|
|
875
|
+
if (!config.build?.outDir) {
|
|
876
|
+
throw new Error("Incomplete config, missing build.outDir");
|
|
877
|
+
}
|
|
878
|
+
return {
|
|
879
|
+
build: {
|
|
880
|
+
outDir: join3(config.build.outDir, outDirSuffix),
|
|
881
|
+
manifest: true
|
|
882
|
+
}
|
|
883
|
+
};
|
|
884
|
+
},
|
|
885
|
+
async configResolved(_config) {
|
|
886
|
+
store.config = _config;
|
|
887
|
+
const appRoot = resolve5(store.config.root, "..");
|
|
888
|
+
const sourceFolder = basename(store.config.root);
|
|
889
|
+
const outDir = resolve5(appRoot, resolve5(store.config.build.outDir, ".."));
|
|
890
|
+
const { stabilityThreshold = 1e3 } = typeof store.config.server.watch?.awaitWriteFinish === "object" ? store.config.server.watch.awaitWriteFinish : {};
|
|
891
|
+
const watcher = {
|
|
892
|
+
delay: stabilityThreshold,
|
|
893
|
+
...store.config.server.watch ? { options: store.config.server.watch } : {}
|
|
894
|
+
};
|
|
895
|
+
{
|
|
896
|
+
const {
|
|
897
|
+
generators = [],
|
|
898
|
+
formatters = [],
|
|
899
|
+
refineTypeName = "TRefine"
|
|
900
|
+
} = { ...pluginOptions };
|
|
901
|
+
const _apiGenerator = generators.find((e) => e.kind === "api");
|
|
902
|
+
const _fetchGenerator = generators.find((e) => e.kind === "fetch");
|
|
903
|
+
const _ssrGenerator = generators.find((e) => e.kind === "ssr");
|
|
904
|
+
store.resolvedOptions = {
|
|
905
|
+
...pluginOptions,
|
|
906
|
+
command: store.config.command,
|
|
907
|
+
watcher,
|
|
908
|
+
generators: [
|
|
909
|
+
// 1. stub generator should run first
|
|
910
|
+
stubGenerator(),
|
|
911
|
+
// 2. then api generator
|
|
912
|
+
_apiGenerator || apiGenerator(),
|
|
913
|
+
// 3. then fetch generator
|
|
914
|
+
_fetchGenerator || fetchGenerator(),
|
|
915
|
+
// 4. user generators in the order they were added
|
|
916
|
+
...generators.filter((e) => {
|
|
917
|
+
return e.kind ? !["api", "fetch", "ssr"].includes(e.kind) : true;
|
|
918
|
+
}),
|
|
919
|
+
// 5. ssr generator should run last
|
|
920
|
+
..._ssrGenerator ? [_ssrGenerator] : []
|
|
921
|
+
],
|
|
922
|
+
formatters: formatters.map((e) => e.formatter),
|
|
923
|
+
refineTypeName,
|
|
924
|
+
baseurl: store.config.base,
|
|
925
|
+
apiurl,
|
|
926
|
+
appRoot,
|
|
927
|
+
sourceFolder,
|
|
928
|
+
outDir
|
|
929
|
+
};
|
|
930
|
+
}
|
|
931
|
+
if (store.config.command === "build") {
|
|
932
|
+
const { resolvers } = await routes_default(store.resolvedOptions);
|
|
933
|
+
const resolvedRoutes = [];
|
|
934
|
+
{
|
|
935
|
+
const spinner = spinnerFactory("Resolving Routes");
|
|
936
|
+
for (const { name, handler } of resolvers.values()) {
|
|
937
|
+
spinner.append(
|
|
938
|
+
`[ ${resolvedRoutes.length + 1} of ${resolvers.size} ] ${name}`
|
|
939
|
+
);
|
|
940
|
+
resolvedRoutes.push(await handler());
|
|
941
|
+
}
|
|
942
|
+
spinner.succeed();
|
|
943
|
+
}
|
|
944
|
+
{
|
|
945
|
+
const spinner = spinnerFactory("Running Generators");
|
|
946
|
+
for (const { name, factory } of store.resolvedOptions.generators) {
|
|
947
|
+
spinner.append(name);
|
|
948
|
+
const { watchHandler } = await factory(store.resolvedOptions);
|
|
949
|
+
await watchHandler(resolvedRoutes);
|
|
950
|
+
}
|
|
951
|
+
spinner.succeed();
|
|
952
|
+
}
|
|
953
|
+
}
|
|
954
|
+
},
|
|
955
|
+
async configureServer(server) {
|
|
956
|
+
if (store.config.command !== "serve") {
|
|
957
|
+
return;
|
|
958
|
+
}
|
|
959
|
+
const apiHandler = await api_handler_default(store.resolvedOptions);
|
|
960
|
+
const apiWatcher = await apiHandler.watcher();
|
|
961
|
+
const stopWorker = workerHandler(
|
|
962
|
+
async () => {
|
|
963
|
+
await apiWatcher.start();
|
|
964
|
+
},
|
|
965
|
+
async () => {
|
|
966
|
+
await apiWatcher.stop();
|
|
967
|
+
}
|
|
968
|
+
);
|
|
969
|
+
server.middlewares.use(apiHandler.devMiddleware);
|
|
970
|
+
server.httpServer?.on("close", stopWorker);
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
};
|
|
974
|
+
|
|
975
|
+
// src/define-plugin/index.ts
|
|
976
|
+
import { parse as dotenv } from "dotenv";
|
|
977
|
+
import fsx2 from "fs-extra";
|
|
978
|
+
var define_plugin_default = (entries) => {
|
|
979
|
+
return {
|
|
980
|
+
name: "@kosmojs:definePlugin",
|
|
981
|
+
async config() {
|
|
982
|
+
const define = {};
|
|
983
|
+
for (const { keys, file, defineOn = "process.env", use } of entries) {
|
|
984
|
+
define[defineOn] = {};
|
|
985
|
+
const env = file && await fsx2.pathExists(file) ? dotenv(await fsx2.readFile(file, "utf8")) : process.env;
|
|
986
|
+
for (const [key, val] of Object.entries(env)) {
|
|
987
|
+
if (keys.includes(key)) {
|
|
988
|
+
define[`${defineOn}.${key}`] = JSON.stringify(val);
|
|
989
|
+
}
|
|
990
|
+
use?.(key, val);
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
return { define };
|
|
994
|
+
}
|
|
995
|
+
};
|
|
996
|
+
};
|
|
997
|
+
export {
|
|
998
|
+
alias_plugin_default as aliasPlugin,
|
|
999
|
+
default2 as apiGenerator,
|
|
1000
|
+
base_plugin_default as default,
|
|
1001
|
+
define_plugin_default as definePlugin,
|
|
1002
|
+
default3 as fetchGenerator
|
|
1003
|
+
};
|
|
1004
|
+
//# sourceMappingURL=index.js.map
|