@asterflow/cli 2.0.1 → 2.0.2
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/cjs/index.cjs +307 -216
- package/dist/mjs/index.js +319 -228
- package/dist/types/generators/packageJson.d.ts +1 -1
- package/dist/types/helpers/npmVersion.d.ts +12 -0
- package/dist/types/registry/plugins.d.ts +0 -1
- package/package.json +2 -2
package/dist/mjs/index.js
CHANGED
|
@@ -1,19 +1,104 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
// packages/cli/src/index.ts
|
|
3
|
-
import
|
|
4
|
-
import { hideBin as
|
|
3
|
+
import Ze from "yargs";
|
|
4
|
+
import { hideBin as et } from "yargs/helpers";
|
|
5
5
|
// packages/cli/src/commands/add.ts
|
|
6
|
-
import { exec as
|
|
7
|
-
import { existsSync as
|
|
8
|
-
import { readFile as
|
|
9
|
-
import { join as
|
|
10
|
-
import { promisify as
|
|
6
|
+
import { exec as ke } from "child_process";
|
|
7
|
+
import { existsSync as xe } from "fs";
|
|
8
|
+
import { readFile as ve, writeFile as je } from "fs/promises";
|
|
9
|
+
import { join as Pe, resolve as $e } from "path";
|
|
10
|
+
import { promisify as Ie } from "util";
|
|
11
|
+
// packages/cli/package.json
|
|
12
|
+
var D = {
|
|
13
|
+
name: "@asterflow/cli",
|
|
14
|
+
version: "2.0.2",
|
|
15
|
+
description: "CLI for scaffolding AsterFlow projects, adding plugins, and generating the static fs-routing manifest.",
|
|
16
|
+
keywords: [
|
|
17
|
+
"asterflow",
|
|
18
|
+
"cli",
|
|
19
|
+
"scaffolding",
|
|
20
|
+
"generator"
|
|
21
|
+
],
|
|
22
|
+
main: "dist/cjs/index.cjs",
|
|
23
|
+
module: "dist/mjs/index.js",
|
|
24
|
+
types: "dist/types/index.d.ts",
|
|
25
|
+
typings: "dist/types/index.d.ts",
|
|
26
|
+
type: "module",
|
|
27
|
+
license: "MIT",
|
|
28
|
+
author: "Ashu11-A",
|
|
29
|
+
repository: {
|
|
30
|
+
type: "git",
|
|
31
|
+
url: "git+https://github.com/AsterFlow/AsterFlow.git"
|
|
32
|
+
},
|
|
33
|
+
bugs: {
|
|
34
|
+
url: "https://github.com/AsterFlow/AsterFlow/issues"
|
|
35
|
+
},
|
|
36
|
+
homepage: "https://github.com/AsterFlow/AsterFlow",
|
|
37
|
+
bin: {
|
|
38
|
+
asterflow: "dist/cjs/index.cjs"
|
|
39
|
+
},
|
|
40
|
+
exports: {
|
|
41
|
+
".": {
|
|
42
|
+
types: "./dist/types/index.d.ts",
|
|
43
|
+
import: "./dist/mjs/index.js",
|
|
44
|
+
require: "./dist/cjs/index.cjs"
|
|
45
|
+
}
|
|
46
|
+
},
|
|
47
|
+
engines: {
|
|
48
|
+
node: ">=20"
|
|
49
|
+
},
|
|
50
|
+
scripts: {
|
|
51
|
+
dev: "bun run src/index.ts"
|
|
52
|
+
},
|
|
53
|
+
dependencies: {
|
|
54
|
+
"@asterflow/fs": "workspace:../../plugins/fs",
|
|
55
|
+
"@clack/prompts": "^0.9.1",
|
|
56
|
+
chalk: "^4.1.2",
|
|
57
|
+
"ci-info": "^4.1.0",
|
|
58
|
+
"validate-npm-package-name": "^6.0.0",
|
|
59
|
+
yargs: "^18.0.0"
|
|
60
|
+
},
|
|
61
|
+
devDependencies: {
|
|
62
|
+
"@types/validate-npm-package-name": "^4.0.2",
|
|
63
|
+
"@types/yargs": "^17.0.33"
|
|
64
|
+
},
|
|
65
|
+
peerDependencies: {
|
|
66
|
+
typescript: "^5.8.3"
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
// packages/cli/src/helpers/npmVersion.ts
|
|
70
|
+
var ge = "https://registry.npmjs.org", fe = 5e3, [B, W] = D.version.split(".").map(Number);
|
|
71
|
+
async function ye(e) {
|
|
72
|
+
let t = new AbortController(), r = setTimeout(() => t.abort(), fe);
|
|
73
|
+
try {
|
|
74
|
+
let s = await fetch(`${ge}/${encodeURIComponent(e)}`, {
|
|
75
|
+
signal: t.signal,
|
|
76
|
+
headers: { Accept: "application/vnd.npm.install-v1+json" }
|
|
77
|
+
});
|
|
78
|
+
if (!s.ok) return [];
|
|
79
|
+
let l = await s.json();
|
|
80
|
+
return Object.keys(l.versions ?? {});
|
|
81
|
+
} catch {
|
|
82
|
+
return [];
|
|
83
|
+
} finally {
|
|
84
|
+
clearTimeout(r);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async function j(e) {
|
|
88
|
+
let t = await ye(e), r = -1;
|
|
89
|
+
for (let l of t) {
|
|
90
|
+
let f = /^(\d+)\.(\d+)\.(\d+)$/.exec(l);
|
|
91
|
+
if (!f) continue;
|
|
92
|
+
let [, d, c, p] = f;
|
|
93
|
+
Number(d) !== B || Number(c) !== W || (r = Math.max(r, Number(p)));
|
|
94
|
+
}
|
|
95
|
+
return `^${r >= 0 ? `${B}.${W}.${r}` : D.version}`;
|
|
96
|
+
}
|
|
11
97
|
// packages/cli/src/registry/plugins.ts
|
|
12
|
-
var
|
|
98
|
+
var b = {
|
|
13
99
|
fs: {
|
|
14
100
|
id: "fs",
|
|
15
101
|
packageName: "@asterflow/fs",
|
|
16
|
-
version: "^1.0.7",
|
|
17
102
|
description: "File system-based routing - routes are discovered from a routes/ directory.",
|
|
18
103
|
importName: "fsRoutingPlugin",
|
|
19
104
|
useSnippet: ".use(fsRoutingPlugin, { routes })",
|
|
@@ -22,44 +107,43 @@ var y = {
|
|
|
22
107
|
multipart: {
|
|
23
108
|
id: "multipart",
|
|
24
109
|
packageName: "@asterflow/multipart",
|
|
25
|
-
version: "^1.0.0",
|
|
26
110
|
description: "multipart/form-data parsing (file uploads), with per-route type-safe field criteria.",
|
|
27
111
|
importName: "multipartPlugin",
|
|
28
112
|
useSnippet: ".use(multipartPlugin, { limits: { fileSize: 10 * 1024 * 1024 } })",
|
|
29
113
|
usageNote: "Build upload routes with Method.create(Method.POST).multipart({...}).handler(...) - see src/routes/upload.ts for a working example."
|
|
30
114
|
}
|
|
31
|
-
},
|
|
115
|
+
}, st = Object.keys(b);
|
|
32
116
|
// packages/cli/src/utils/log.ts
|
|
33
|
-
import
|
|
34
|
-
var
|
|
35
|
-
info: (e) => console.log(
|
|
36
|
-
success: (e) => console.log(
|
|
37
|
-
warn: (e) => console.log(
|
|
38
|
-
error: (e) => console.error(
|
|
39
|
-
step: (e) => console.log(
|
|
117
|
+
import $ from "chalk";
|
|
118
|
+
var m = {
|
|
119
|
+
info: (e) => console.log($.cyan(e)),
|
|
120
|
+
success: (e) => console.log($.green(e)),
|
|
121
|
+
warn: (e) => console.log($.yellow(e)),
|
|
122
|
+
error: (e) => console.error($.red(e)),
|
|
123
|
+
step: (e) => console.log($.gray(` ${e}`))
|
|
40
124
|
};
|
|
41
125
|
// packages/cli/src/utils/packageManager.ts
|
|
42
|
-
import { existsSync as
|
|
43
|
-
import { join as
|
|
44
|
-
var
|
|
126
|
+
import { existsSync as he } from "fs";
|
|
127
|
+
import { join as be } from "path";
|
|
128
|
+
var we = {
|
|
45
129
|
"bun.lock": "bun",
|
|
46
130
|
"bun.lockb": "bun",
|
|
47
131
|
"pnpm-lock.yaml": "pnpm",
|
|
48
132
|
"yarn.lock": "yarn",
|
|
49
133
|
"package-lock.json": "npm"
|
|
50
134
|
};
|
|
51
|
-
function
|
|
52
|
-
for (let [t, r] of Object.entries(
|
|
53
|
-
if (
|
|
135
|
+
function O(e) {
|
|
136
|
+
for (let [t, r] of Object.entries(we))
|
|
137
|
+
if (he(be(e, t))) return r;
|
|
54
138
|
return "bun";
|
|
55
139
|
}
|
|
56
|
-
function
|
|
57
|
-
return e ??
|
|
140
|
+
function Y(e, t) {
|
|
141
|
+
return e ?? O(t);
|
|
58
142
|
}
|
|
59
|
-
function
|
|
143
|
+
function J(e) {
|
|
60
144
|
return e === "yarn" ? "yarn" : `${e} install`;
|
|
61
145
|
}
|
|
62
|
-
function
|
|
146
|
+
function q(e, t) {
|
|
63
147
|
let r = t.join(" ");
|
|
64
148
|
switch (e) {
|
|
65
149
|
case "bun":
|
|
@@ -73,78 +157,79 @@ function W(e, t) {
|
|
|
73
157
|
}
|
|
74
158
|
}
|
|
75
159
|
// packages/cli/src/commands/add.ts
|
|
76
|
-
var
|
|
77
|
-
async function
|
|
78
|
-
let r =
|
|
160
|
+
var Ae = Ie(ke);
|
|
161
|
+
async function z({ names: e, directory: t }) {
|
|
162
|
+
let r = $e(t ?? "."), s = Pe(r, "package.json"), l = e.split(",").map((o) => o.trim()).filter(Boolean);
|
|
79
163
|
if (l.length === 0) {
|
|
80
|
-
|
|
164
|
+
m.error("No plugin names given. Usage: asterflow add fs,multipart"), process.exitCode = 1;
|
|
81
165
|
return;
|
|
82
166
|
}
|
|
83
|
-
let
|
|
84
|
-
if (
|
|
85
|
-
|
|
167
|
+
let f = l.filter((o) => !b[o]);
|
|
168
|
+
if (f.length > 0) {
|
|
169
|
+
m.error(`Unknown plugin${f.length > 1 ? "s" : ""}: ${f.join(", ")}`), m.step(`Available plugins: ${Object.keys(b).join(", ")}`), process.exitCode = 1;
|
|
86
170
|
return;
|
|
87
171
|
}
|
|
88
|
-
if (!
|
|
89
|
-
|
|
172
|
+
if (!xe(s)) {
|
|
173
|
+
m.error(`No package.json found at ${s}. Run this from an AsterFlow project (or \`asterflow init\` first).`), process.exitCode = 1;
|
|
90
174
|
return;
|
|
91
175
|
}
|
|
92
|
-
let
|
|
93
|
-
|
|
94
|
-
let
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
176
|
+
let d = l.map((o) => b[o]), c = await ve(s, "utf-8"), p = JSON.parse(c);
|
|
177
|
+
p.dependencies ??= {};
|
|
178
|
+
let w = d.filter((o) => p.dependencies[o.packageName]), y = d.filter((o) => !p.dependencies[o.packageName]), k = await Promise.all(y.map((o) => j(o.packageName)));
|
|
179
|
+
if (y.forEach((o, u) => {
|
|
180
|
+
p.dependencies[o.packageName] = k[u];
|
|
181
|
+
}), p.dependencies = Object.fromEntries(Object.entries(p.dependencies).sort(([o], [u]) => o.localeCompare(u))), y.length > 0) {
|
|
182
|
+
await je(s, `${JSON.stringify(p, null, 2)}
|
|
183
|
+
`), m.success(`Added to package.json: ${y.map((g) => g.packageName).join(", ")}`);
|
|
184
|
+
let o = O(r), u = q(o, y.map((g) => g.packageName));
|
|
185
|
+
m.info(`Installing (${u})...`);
|
|
101
186
|
try {
|
|
102
|
-
await
|
|
103
|
-
} catch (
|
|
104
|
-
|
|
187
|
+
await Ae(u, { cwd: r }), m.success("Dependencies installed.");
|
|
188
|
+
} catch (g) {
|
|
189
|
+
m.error(`Install failed - run manually: ${u}`), m.step(g instanceof Error ? g.message : String(g));
|
|
105
190
|
}
|
|
106
191
|
}
|
|
107
|
-
|
|
108
|
-
for (let
|
|
109
|
-
|
|
192
|
+
w.length > 0 && m.warn(`Already present, skipped: ${w.map((o) => o.packageName).join(", ")}`), m.info("Wire it up:");
|
|
193
|
+
for (let o of d)
|
|
194
|
+
m.step(`import { ${o.importName} } from '${o.packageName}'`), m.step(`app${o.useSnippet}`), m.step(o.usageNote);
|
|
110
195
|
}
|
|
111
196
|
// packages/cli/src/commands/generate.ts
|
|
112
|
-
import { generateRouteManifest as
|
|
113
|
-
import { watch as
|
|
114
|
-
import { join as
|
|
115
|
-
var
|
|
116
|
-
async function
|
|
117
|
-
let s =
|
|
197
|
+
import { generateRouteManifest as Ee } from "@asterflow/fs";
|
|
198
|
+
import { watch as Re } from "fs";
|
|
199
|
+
import { join as Ne, resolve as H } from "path";
|
|
200
|
+
var Se = "src/routes", K = "src/routes.gen.ts";
|
|
201
|
+
async function Q({ directory: e, out: t, watch: r }) {
|
|
202
|
+
let s = H(e ?? Se), l = H(t ?? K), f = async () => {
|
|
118
203
|
try {
|
|
119
|
-
await
|
|
120
|
-
} catch (
|
|
121
|
-
|
|
204
|
+
await Ee({ routesDir: s, outFile: l }), m.success(`Generated ${Ne(t ?? K)}`);
|
|
205
|
+
} catch (c) {
|
|
206
|
+
m.error(c instanceof Error ? c.message : String(c)), r || (process.exitCode = 1);
|
|
122
207
|
}
|
|
123
208
|
};
|
|
124
|
-
if (await
|
|
125
|
-
|
|
126
|
-
let
|
|
127
|
-
|
|
128
|
-
clearTimeout(
|
|
209
|
+
if (await f(), !r) return;
|
|
210
|
+
m.info(`Watching ${s} for changes...`);
|
|
211
|
+
let d;
|
|
212
|
+
Re(s, { recursive: !0 }, () => {
|
|
213
|
+
clearTimeout(d), d = setTimeout(f, 100);
|
|
129
214
|
});
|
|
130
215
|
}
|
|
131
216
|
// packages/cli/src/commands/init.ts
|
|
132
217
|
import * as i from "@clack/prompts";
|
|
133
|
-
import
|
|
134
|
-
import { exec as
|
|
135
|
-
import { appendFile as
|
|
136
|
-
import { basename as
|
|
137
|
-
import { promisify as
|
|
218
|
+
import le from "ci-info";
|
|
219
|
+
import { exec as Je } from "child_process";
|
|
220
|
+
import { appendFile as qe, mkdir as N, writeFile as L } from "fs/promises";
|
|
221
|
+
import { basename as G, dirname as pe, join as v, resolve as ze } from "path";
|
|
222
|
+
import { promisify as He } from "util";
|
|
138
223
|
// packages/cli/src/generators/appEntry.ts
|
|
139
|
-
function
|
|
140
|
-
let s = t.some((
|
|
224
|
+
function X({ adapter: e, plugins: t, stub: r }) {
|
|
225
|
+
let s = t.some((c) => c.id === "fs"), l = [
|
|
141
226
|
"import { AsterFlow } from 'asterflow'",
|
|
142
227
|
"import { adapters } from '@asterflow/adapter'",
|
|
143
228
|
...e.imports,
|
|
144
|
-
...t.map((
|
|
229
|
+
...t.map((c) => `import { ${c.importName} } from '${c.packageName}'`),
|
|
145
230
|
...s ? ["import routes from './routes.gen'"] : []
|
|
146
|
-
],
|
|
147
|
-
...t.map((
|
|
231
|
+
], f = [
|
|
232
|
+
...t.map((c) => c.useSnippet.replace(/^\./, "")),
|
|
148
233
|
...!s && r ? [`method('get', {
|
|
149
234
|
path: '/',
|
|
150
235
|
handler({ response }) {
|
|
@@ -152,56 +237,62 @@ function q({ adapter: e, plugins: t, stub: r }) {
|
|
|
152
237
|
}
|
|
153
238
|
})`] : [],
|
|
154
239
|
`listen${e.listenCall}`
|
|
155
|
-
],
|
|
240
|
+
], d = e.preamble ? `${e.preamble}
|
|
156
241
|
` : "";
|
|
157
242
|
return `${l.join(`
|
|
158
243
|
`)}
|
|
159
|
-
${
|
|
160
|
-
.${
|
|
244
|
+
${d}export default new AsterFlow({ driver: ${e.driverExpression} })
|
|
245
|
+
.${f.join(`
|
|
161
246
|
.`)}
|
|
162
247
|
`;
|
|
163
248
|
}
|
|
164
249
|
// packages/cli/src/generators/packageJson.ts
|
|
165
|
-
function
|
|
166
|
-
let s = r.some((u) => u.id === "fs"), l =
|
|
167
|
-
asterflow
|
|
168
|
-
"@asterflow/adapter"
|
|
250
|
+
async function Z({ name: e, adapter: t, plugins: r }) {
|
|
251
|
+
let s = r.some((u) => u.id === "fs"), [l, f, d, c] = await Promise.all([
|
|
252
|
+
j("asterflow"),
|
|
253
|
+
j("@asterflow/adapter"),
|
|
254
|
+
s ? j("@asterflow/cli") : Promise.resolve(null),
|
|
255
|
+
Promise.all(r.map((u) => j(u.packageName)))
|
|
256
|
+
]), p = {
|
|
257
|
+
asterflow: l,
|
|
258
|
+
"@asterflow/adapter": f,
|
|
169
259
|
zod: "^3.25.67"
|
|
170
260
|
};
|
|
171
|
-
t.dependency && (
|
|
172
|
-
|
|
173
|
-
|
|
261
|
+
t.dependency && (p[t.dependency] = "latest"), r.forEach((u, g) => {
|
|
262
|
+
p[u.packageName] = c[g];
|
|
263
|
+
});
|
|
264
|
+
let w = Object.fromEntries(Object.entries(p).sort(([u], [g]) => u.localeCompare(g))), y = s ? {
|
|
174
265
|
predev: "asterflow generate",
|
|
175
266
|
dev: "bun run src/index.ts",
|
|
176
267
|
prebuild: "asterflow generate"
|
|
177
|
-
} : { dev: "bun run src/index.ts" },
|
|
268
|
+
} : { dev: "bun run src/index.ts" }, k = {
|
|
178
269
|
typescript: "^5.8.3",
|
|
179
270
|
"@types/bun": "latest"
|
|
180
271
|
};
|
|
181
|
-
return s && (
|
|
272
|
+
return s && d && (k["@asterflow/cli"] = d), `${JSON.stringify({
|
|
182
273
|
name: e,
|
|
183
274
|
version: "0.1.0",
|
|
184
275
|
type: "module",
|
|
185
276
|
private: !0,
|
|
186
|
-
scripts:
|
|
187
|
-
dependencies:
|
|
188
|
-
devDependencies:
|
|
277
|
+
scripts: y,
|
|
278
|
+
dependencies: w,
|
|
279
|
+
devDependencies: k
|
|
189
280
|
}, null, 2)}
|
|
190
281
|
`;
|
|
191
282
|
}
|
|
192
283
|
// packages/cli/src/helpers/copyTemplate.ts
|
|
193
|
-
import { readFile as
|
|
194
|
-
import { join as
|
|
195
|
-
var
|
|
196
|
-
async function
|
|
197
|
-
return
|
|
284
|
+
import { readFile as Te, writeFile as Ce } from "fs/promises";
|
|
285
|
+
import { join as ee } from "path";
|
|
286
|
+
var De = ee(__dirname, "..", "..", "templates");
|
|
287
|
+
async function F(e) {
|
|
288
|
+
return Te(ee(De, e), "utf-8");
|
|
198
289
|
}
|
|
199
|
-
async function
|
|
200
|
-
let r = await
|
|
201
|
-
await
|
|
290
|
+
async function M(e, t) {
|
|
291
|
+
let r = await F(e);
|
|
292
|
+
await Ce(t, r);
|
|
202
293
|
}
|
|
203
294
|
// packages/cli/src/registry/templates.ts
|
|
204
|
-
var
|
|
295
|
+
var te = {
|
|
205
296
|
hello: {
|
|
206
297
|
id: "hello",
|
|
207
298
|
path: "/",
|
|
@@ -215,60 +306,60 @@ var Q = {
|
|
|
215
306
|
plugin: "multipart",
|
|
216
307
|
summary: "File upload handled by @asterflow/multipart."
|
|
217
308
|
}
|
|
218
|
-
},
|
|
219
|
-
function
|
|
309
|
+
}, I = Object.keys(te);
|
|
310
|
+
function R(e) {
|
|
220
311
|
let t = new Set(e);
|
|
221
|
-
return
|
|
312
|
+
return I.map((r) => te[r]).filter((r) => !r.plugin || t.has(r.plugin));
|
|
222
313
|
}
|
|
223
|
-
function
|
|
314
|
+
function re(e) {
|
|
224
315
|
let t = e.path.replace(/^\/+|\/+$/g, "");
|
|
225
316
|
return t.length === 0 ? "index.ts" : `${t}/index.ts`;
|
|
226
317
|
}
|
|
227
318
|
// packages/cli/src/generators/routes.ts
|
|
228
|
-
async function
|
|
319
|
+
async function ne({ pluginIds: e, templateIds: t }) {
|
|
229
320
|
if (!e.includes("fs")) return [];
|
|
230
|
-
let r =
|
|
321
|
+
let r = R(e).filter((s) => t.includes(s.id));
|
|
231
322
|
return Promise.all(r.map(async (s) => ({
|
|
232
|
-
fileName:
|
|
233
|
-
content: await
|
|
323
|
+
fileName: re(s),
|
|
324
|
+
content: await F(s.source)
|
|
234
325
|
})));
|
|
235
326
|
}
|
|
236
327
|
// packages/cli/src/helpers/git.ts
|
|
237
|
-
import { execSync as
|
|
238
|
-
import { rmSync as
|
|
239
|
-
import { join as
|
|
240
|
-
function
|
|
328
|
+
import { execSync as P } from "child_process";
|
|
329
|
+
import { rmSync as Oe } from "fs";
|
|
330
|
+
import { join as Fe } from "path";
|
|
331
|
+
function Me(e) {
|
|
241
332
|
try {
|
|
242
|
-
return
|
|
333
|
+
return P("git rev-parse --is-inside-work-tree", { cwd: e, stdio: "ignore" }), !0;
|
|
243
334
|
} catch {
|
|
244
335
|
return !1;
|
|
245
336
|
}
|
|
246
337
|
}
|
|
247
|
-
function
|
|
338
|
+
function _e(e) {
|
|
248
339
|
try {
|
|
249
|
-
return
|
|
340
|
+
return P("git config init.defaultBranch", { cwd: e, stdio: "ignore" }), !0;
|
|
250
341
|
} catch {
|
|
251
342
|
return !1;
|
|
252
343
|
}
|
|
253
344
|
}
|
|
254
|
-
function
|
|
345
|
+
function ie(e) {
|
|
255
346
|
let t = !1;
|
|
256
347
|
try {
|
|
257
|
-
return
|
|
348
|
+
return P("git --version", { stdio: "ignore" }), Me(e) ? !1 : (P("git init", { cwd: e, stdio: "ignore" }), t = !0, _e(e) || P("git checkout -b main", { cwd: e, stdio: "ignore" }), P("git add -A", { cwd: e, stdio: "ignore" }), P('git commit -m "Initial commit from create-asterflow-app"', { cwd: e, stdio: "ignore" }), !0);
|
|
258
349
|
} catch {
|
|
259
350
|
if (t)
|
|
260
351
|
try {
|
|
261
|
-
|
|
352
|
+
Oe(Fe(e, ".git"), { recursive: !0, force: !0 });
|
|
262
353
|
} catch {
|
|
263
354
|
}
|
|
264
355
|
return !1;
|
|
265
356
|
}
|
|
266
357
|
}
|
|
267
358
|
// packages/cli/src/helpers/isFolderEmpty.ts
|
|
268
|
-
import { lstatSync as
|
|
269
|
-
import { join as
|
|
270
|
-
import
|
|
271
|
-
var
|
|
359
|
+
import { lstatSync as Le, readdirSync as Ge } from "fs";
|
|
360
|
+
import { join as Ue } from "path";
|
|
361
|
+
import se from "chalk";
|
|
362
|
+
var Ve = new Set([
|
|
272
363
|
".DS_Store",
|
|
273
364
|
".git",
|
|
274
365
|
".gitattributes",
|
|
@@ -283,37 +374,37 @@ var De = new Set([
|
|
|
283
374
|
"LICENSE",
|
|
284
375
|
"Thumbs.db"
|
|
285
376
|
]);
|
|
286
|
-
function
|
|
287
|
-
let r =
|
|
377
|
+
function oe(e, t) {
|
|
378
|
+
let r = Ge(e).filter((s) => !Ve.has(s) && !s.endsWith(".iml"));
|
|
288
379
|
if (r.length === 0) return !0;
|
|
289
|
-
console.log(`The directory ${
|
|
380
|
+
console.log(`The directory ${se.green(t)} contains files that could conflict:`), console.log();
|
|
290
381
|
for (let s of r) {
|
|
291
|
-
let l =
|
|
292
|
-
console.log(` ${
|
|
382
|
+
let l = Le(Ue(e, s)).isDirectory();
|
|
383
|
+
console.log(` ${se.cyan(s)}${l ? "/" : ""}`);
|
|
293
384
|
}
|
|
294
385
|
return console.log(), console.log("Either try using a new directory name, or remove the files listed above."), console.log(), !1;
|
|
295
386
|
}
|
|
296
387
|
// packages/cli/src/helpers/isWriteable.ts
|
|
297
|
-
import { constants as
|
|
298
|
-
import { access as
|
|
299
|
-
async function
|
|
388
|
+
import { constants as Be } from "fs";
|
|
389
|
+
import { access as We } from "fs/promises";
|
|
390
|
+
async function ae(e) {
|
|
300
391
|
try {
|
|
301
|
-
return await
|
|
392
|
+
return await We(e, Be.W_OK), !0;
|
|
302
393
|
} catch {
|
|
303
394
|
return !1;
|
|
304
395
|
}
|
|
305
396
|
}
|
|
306
397
|
// packages/cli/src/helpers/validateProjectName.ts
|
|
307
|
-
import
|
|
308
|
-
function
|
|
309
|
-
let t =
|
|
398
|
+
import Ye from "validate-npm-package-name";
|
|
399
|
+
function _(e) {
|
|
400
|
+
let t = Ye(e);
|
|
310
401
|
return t.validForNewPackages ? { valid: !0 } : {
|
|
311
402
|
valid: !1,
|
|
312
403
|
problems: [...t.errors ?? [], ...t.warnings ?? []]
|
|
313
404
|
};
|
|
314
405
|
}
|
|
315
406
|
// packages/cli/src/registry/adapters.ts
|
|
316
|
-
var
|
|
407
|
+
var A = {
|
|
317
408
|
bun: {
|
|
318
409
|
id: "bun",
|
|
319
410
|
label: "Bun (native Bun.serve)",
|
|
@@ -370,191 +461,191 @@ var j = {
|
|
|
370
461
|
console.log('Server listening on http://localhost:3333')
|
|
371
462
|
})`
|
|
372
463
|
}
|
|
373
|
-
},
|
|
464
|
+
}, E = Object.keys(A);
|
|
374
465
|
// packages/cli/src/commands/init.ts
|
|
375
|
-
var
|
|
466
|
+
var Ke = He(Je), x = {
|
|
376
467
|
adapter: "bun",
|
|
377
468
|
plugins: ["fs", "multipart"],
|
|
378
469
|
install: !0,
|
|
379
470
|
git: !0
|
|
380
471
|
};
|
|
381
|
-
async function
|
|
472
|
+
async function ce(e) {
|
|
382
473
|
i.intro("Create a new AsterFlow project");
|
|
383
|
-
let t =
|
|
384
|
-
if (!await
|
|
474
|
+
let t = ze(e.directory ?? "."), r = G(t) === "." ? "my-asterflow-app" : G(t);
|
|
475
|
+
if (!await ae(pe(t))) {
|
|
385
476
|
i.cancel(`The path ${t} is not writable. Check folder permissions and try again.`), process.exitCode = 1;
|
|
386
477
|
return;
|
|
387
478
|
}
|
|
388
|
-
if (await
|
|
479
|
+
if (await N(t, { recursive: !0 }), !oe(t, G(t))) {
|
|
389
480
|
process.exitCode = 1;
|
|
390
481
|
return;
|
|
391
482
|
}
|
|
392
|
-
let s = process.argv.some((n) => n.startsWith("--")), l =
|
|
483
|
+
let s = process.argv.some((n) => n.startsWith("--")), l = le.isCI || !!e.yes || s, f = s && !e.yes && !le.isCI;
|
|
393
484
|
if (e.name) {
|
|
394
|
-
let n =
|
|
485
|
+
let n = _(e.name);
|
|
395
486
|
if (!n.valid) {
|
|
396
487
|
i.cancel(`Invalid project name "${e.name}":
|
|
397
|
-
${n.problems.map((
|
|
488
|
+
${n.problems.map((a) => ` - ${a}`).join(`
|
|
398
489
|
`)}`), process.exitCode = 1;
|
|
399
490
|
return;
|
|
400
491
|
}
|
|
401
492
|
}
|
|
402
|
-
let
|
|
403
|
-
if (
|
|
493
|
+
let d = e.name;
|
|
494
|
+
if (d === void 0)
|
|
404
495
|
if (l)
|
|
405
|
-
|
|
496
|
+
d = r;
|
|
406
497
|
else {
|
|
407
498
|
let n = await i.text({
|
|
408
499
|
message: "Project name",
|
|
409
500
|
placeholder: r,
|
|
410
501
|
defaultValue: r,
|
|
411
|
-
validate: (
|
|
412
|
-
let
|
|
413
|
-
return
|
|
502
|
+
validate: (a) => {
|
|
503
|
+
let h = _(a || r);
|
|
504
|
+
return h.valid ? void 0 : `Invalid project name: ${h.problems[0]}`;
|
|
414
505
|
}
|
|
415
506
|
});
|
|
416
507
|
if (i.isCancel(n)) return i.cancel("Cancelled.");
|
|
417
|
-
|
|
508
|
+
d = n;
|
|
418
509
|
}
|
|
419
|
-
if (e.adapter && !
|
|
420
|
-
i.cancel(`Unknown adapter "${e.adapter}". Available: ${
|
|
510
|
+
if (e.adapter && !A[e.adapter]) {
|
|
511
|
+
i.cancel(`Unknown adapter "${e.adapter}". Available: ${E.join(", ")}`), process.exitCode = 1;
|
|
421
512
|
return;
|
|
422
513
|
}
|
|
423
|
-
let
|
|
424
|
-
if (!
|
|
514
|
+
let c = e.adapter;
|
|
515
|
+
if (!c)
|
|
425
516
|
if (l)
|
|
426
|
-
|
|
517
|
+
c = x.adapter;
|
|
427
518
|
else {
|
|
428
519
|
let n = await i.select({
|
|
429
520
|
message: "Which adapter do you want to use?",
|
|
430
|
-
options: Object.values(
|
|
431
|
-
initialValue:
|
|
521
|
+
options: Object.values(A).map((a) => ({ value: a.id, label: a.label })),
|
|
522
|
+
initialValue: x.adapter
|
|
432
523
|
});
|
|
433
524
|
if (i.isCancel(n)) return i.cancel("Cancelled.");
|
|
434
|
-
|
|
525
|
+
c = n;
|
|
435
526
|
}
|
|
436
|
-
let
|
|
527
|
+
let p;
|
|
437
528
|
if (e.plugins !== void 0) {
|
|
438
|
-
|
|
439
|
-
let n =
|
|
529
|
+
p = e.plugins.split(",").map((a) => a.trim()).filter(Boolean);
|
|
530
|
+
let n = p.filter((a) => !b[a]);
|
|
440
531
|
if (n.length > 0) {
|
|
441
|
-
i.cancel(`Unknown plugin${n.length > 1 ? "s" : ""}: ${n.join(", ")}. Available: ${Object.keys(
|
|
532
|
+
i.cancel(`Unknown plugin${n.length > 1 ? "s" : ""}: ${n.join(", ")}. Available: ${Object.keys(b).join(", ")}`), process.exitCode = 1;
|
|
442
533
|
return;
|
|
443
534
|
}
|
|
444
535
|
} else if (l)
|
|
445
|
-
|
|
536
|
+
p = x.plugins;
|
|
446
537
|
else {
|
|
447
538
|
let n = await i.multiselect({
|
|
448
539
|
message: "Which plugins do you want to install? (space to select, enter to confirm)",
|
|
449
|
-
options: Object.values(
|
|
450
|
-
initialValues:
|
|
540
|
+
options: Object.values(b).map((a) => ({ value: a.id, label: a.packageName, hint: a.description })),
|
|
541
|
+
initialValues: x.plugins,
|
|
451
542
|
required: !1
|
|
452
543
|
});
|
|
453
544
|
if (i.isCancel(n)) return i.cancel("Cancelled.");
|
|
454
|
-
|
|
545
|
+
p = n;
|
|
455
546
|
}
|
|
456
|
-
|
|
457
|
-
let
|
|
547
|
+
p.length === 0 && (p = x.plugins);
|
|
548
|
+
let w = R(p), y;
|
|
458
549
|
if (e.routes !== void 0) {
|
|
459
|
-
let n = e.routes.split(",").map((
|
|
460
|
-
|
|
461
|
-
let
|
|
462
|
-
if (
|
|
463
|
-
i.cancel(`Unknown route template${
|
|
550
|
+
let n = e.routes.split(",").map((h) => h.trim()).filter(Boolean);
|
|
551
|
+
y = n.includes("none") ? [] : n;
|
|
552
|
+
let a = y.filter((h) => !w.some((me) => me.id === h));
|
|
553
|
+
if (a.length > 0) {
|
|
554
|
+
i.cancel(`Unknown route template${a.length > 1 ? "s" : ""}: ${a.join(", ")}. Available: ${w.map((h) => h.id).join(", ")}`), process.exitCode = 1;
|
|
464
555
|
return;
|
|
465
556
|
}
|
|
466
557
|
} else if (l)
|
|
467
|
-
|
|
558
|
+
y = w.map((n) => n.id);
|
|
468
559
|
else {
|
|
469
560
|
let n = await i.multiselect({
|
|
470
561
|
message: "Which example routes do you want to scaffold? (space to select, enter to confirm)",
|
|
471
|
-
options:
|
|
472
|
-
initialValues:
|
|
562
|
+
options: w.map((a) => ({ value: a.id, label: a.path, hint: a.summary })),
|
|
563
|
+
initialValues: w.map((a) => a.id),
|
|
473
564
|
required: !1
|
|
474
565
|
});
|
|
475
566
|
if (i.isCancel(n)) return i.cancel("Cancelled.");
|
|
476
|
-
|
|
567
|
+
y = n;
|
|
477
568
|
}
|
|
478
|
-
let
|
|
479
|
-
if (
|
|
569
|
+
let k = e.install;
|
|
570
|
+
if (k === void 0)
|
|
480
571
|
if (l)
|
|
481
|
-
|
|
572
|
+
k = x.install;
|
|
482
573
|
else {
|
|
483
|
-
let n = await i.confirm({ message: "Install dependencies now?", initialValue:
|
|
574
|
+
let n = await i.confirm({ message: "Install dependencies now?", initialValue: x.install });
|
|
484
575
|
if (i.isCancel(n)) return i.cancel("Cancelled.");
|
|
485
|
-
|
|
576
|
+
k = n;
|
|
486
577
|
}
|
|
487
|
-
let
|
|
488
|
-
if (
|
|
578
|
+
let o = e.git;
|
|
579
|
+
if (o === void 0)
|
|
489
580
|
if (l)
|
|
490
|
-
|
|
581
|
+
o = x.git;
|
|
491
582
|
else {
|
|
492
|
-
let n = await i.confirm({ message: "Initialize a git repository?", initialValue:
|
|
583
|
+
let n = await i.confirm({ message: "Initialize a git repository?", initialValue: x.git });
|
|
493
584
|
if (i.isCancel(n)) return i.cancel("Cancelled.");
|
|
494
|
-
|
|
585
|
+
o = n;
|
|
495
586
|
}
|
|
496
|
-
|
|
587
|
+
f && Qe({
|
|
497
588
|
adapter: e.adapter === void 0,
|
|
498
589
|
plugins: e.plugins === void 0,
|
|
499
590
|
routes: e.routes === void 0,
|
|
500
591
|
install: e.install === void 0,
|
|
501
592
|
git: e.git === void 0
|
|
502
|
-
}, { adapterId:
|
|
503
|
-
let
|
|
504
|
-
|
|
505
|
-
let
|
|
506
|
-
await
|
|
593
|
+
}, { adapterId: c, pluginIds: p, templateIds: y, install: k, git: o });
|
|
594
|
+
let u = A[c], g = p.map((n) => b[n]), U = i.spinner();
|
|
595
|
+
U.start("Scaffolding project");
|
|
596
|
+
let T = v(t, "src");
|
|
597
|
+
await N(T, { recursive: !0 }), await L(v(t, "package.json"), await Z({ name: d, adapter: u, plugins: g })), await M("tsconfig.json", v(t, "tsconfig.json")), await L(v(T, "index.ts"), X({ adapter: u, plugins: g, stub: y.length > 0 })), await M("gitignore", v(t, ".gitignore")), g.some((n) => n.id === "fs") && await qe(v(t, ".gitignore"), `src/routes.gen.ts
|
|
507
598
|
`);
|
|
508
|
-
let
|
|
509
|
-
if (
|
|
510
|
-
let n =
|
|
511
|
-
await
|
|
512
|
-
for (let
|
|
513
|
-
let
|
|
514
|
-
await
|
|
599
|
+
let V = await ne({ pluginIds: p, templateIds: y });
|
|
600
|
+
if (V.length > 0) {
|
|
601
|
+
let n = v(T, "routes");
|
|
602
|
+
await N(n, { recursive: !0 });
|
|
603
|
+
for (let a of V) {
|
|
604
|
+
let h = v(n, a.fileName);
|
|
605
|
+
await N(pe(h), { recursive: !0 }), await L(h, a.content);
|
|
515
606
|
}
|
|
516
607
|
}
|
|
517
|
-
|
|
518
|
-
let
|
|
519
|
-
if (
|
|
520
|
-
let n =
|
|
521
|
-
|
|
608
|
+
U.stop("Project scaffolded");
|
|
609
|
+
let C = Y(e.packageManager, t);
|
|
610
|
+
if (k) {
|
|
611
|
+
let n = J(C), a = i.spinner();
|
|
612
|
+
a.start(`Installing dependencies (${n})`);
|
|
522
613
|
try {
|
|
523
|
-
await
|
|
524
|
-
} catch (
|
|
525
|
-
|
|
614
|
+
await Ke(n, { cwd: t }), a.stop("Dependencies installed");
|
|
615
|
+
} catch (h) {
|
|
616
|
+
a.stop("Failed to install dependencies"), i.log.error(h instanceof Error ? h.message : String(h));
|
|
526
617
|
}
|
|
527
618
|
}
|
|
528
|
-
|
|
529
|
-
for (let n of
|
|
619
|
+
o && ie(t) && i.log.success("Initialized a git repository.");
|
|
620
|
+
for (let n of g)
|
|
530
621
|
i.log.info(`${n.packageName}: ${n.usageNote}`);
|
|
531
|
-
|
|
622
|
+
Xe({ name: d, targetDir: t, packageManager: C, useYarn: C === "yarn" });
|
|
532
623
|
}
|
|
533
|
-
function
|
|
624
|
+
function Qe(e, t) {
|
|
534
625
|
let r = [];
|
|
535
|
-
e.adapter && r.push(` --adapter <id> ${t.adapterId} (available: ${
|
|
626
|
+
e.adapter && r.push(` --adapter <id> ${t.adapterId} (available: ${E.join(", ")})`), e.plugins && r.push(` --plugins <ids> ${t.pluginIds.length > 0 ? t.pluginIds.join(",") : "none"} (available: ${Object.keys(b).join(", ")})`), e.routes && r.push(` --routes <ids> ${t.templateIds.length > 0 ? t.templateIds.join(",") : "none"} (available: ${I.join(", ")})`), e.install && r.push(` --no-install skip installing dependencies (default: ${t.install ? "installs" : "skips"})`), e.git && r.push(` --no-git skip git init (default: ${t.git ? "inits" : "skips"})`), r.length !== 0 && i.note(r.join(`
|
|
536
627
|
`), "Using defaults for unprovided options");
|
|
537
628
|
}
|
|
538
|
-
function
|
|
629
|
+
function Xe({ name: e, targetDir: t, packageManager: r, useYarn: s }) {
|
|
539
630
|
let l = `${r} ${s ? "" : "run "}dev`;
|
|
540
631
|
i.note(`cd ${t}
|
|
541
632
|
${l}`, "Next steps"), i.outro(`Success! Created ${e} at ${t}`);
|
|
542
633
|
}
|
|
543
634
|
// packages/cli/src/commands/list.ts
|
|
544
|
-
import
|
|
545
|
-
function
|
|
546
|
-
console.log(
|
|
635
|
+
import S from "chalk";
|
|
636
|
+
function de() {
|
|
637
|
+
console.log(S.bold(`
|
|
547
638
|
Available AsterFlow plugins:
|
|
548
639
|
`));
|
|
549
|
-
for (let e of Object.values(
|
|
550
|
-
console.log(` ${
|
|
640
|
+
for (let e of Object.values(b))
|
|
641
|
+
console.log(` ${S.cyan(e.id.padEnd(12))} ${S.gray(e.packageName)}`), console.log(` ${" ".repeat(12)} ${e.description}
|
|
551
642
|
`);
|
|
552
|
-
console.log(
|
|
643
|
+
console.log(S.gray(`Install with: asterflow add <name>[,<name>...]
|
|
553
644
|
`));
|
|
554
645
|
}
|
|
555
646
|
// packages/cli/src/index.ts
|
|
556
647
|
(async () => {
|
|
557
|
-
await
|
|
648
|
+
await Ze(et(process.argv)).scriptName("asterflow").command(
|
|
558
649
|
"init [directory]",
|
|
559
650
|
"Scaffold a new AsterFlow project",
|
|
560
651
|
(e) => e.positional("directory", {
|
|
@@ -565,13 +656,13 @@ Available AsterFlow plugins:
|
|
|
565
656
|
describe: "Project name (defaults to the directory name)"
|
|
566
657
|
}).option("adapter", {
|
|
567
658
|
type: "string",
|
|
568
|
-
describe: `Adapter to use (${
|
|
659
|
+
describe: `Adapter to use (${E.join(", ")})`
|
|
569
660
|
}).option("plugins", {
|
|
570
661
|
type: "string",
|
|
571
662
|
describe: "Comma-separated plugin ids, e.g. fs,multipart"
|
|
572
663
|
}).option("routes", {
|
|
573
664
|
type: "string",
|
|
574
|
-
describe: `Comma-separated route template ids to scaffold, or "none" (${
|
|
665
|
+
describe: `Comma-separated route template ids to scaffold, or "none" (${I.join(", ")})`
|
|
575
666
|
}).option("install", {
|
|
576
667
|
type: "boolean",
|
|
577
668
|
describe: "Install dependencies (default: yes)"
|
|
@@ -587,7 +678,7 @@ Available AsterFlow plugins:
|
|
|
587
678
|
}),
|
|
588
679
|
async (e) => {
|
|
589
680
|
let t = e.useNpm ? "npm" : e.usePnpm ? "pnpm" : e.useYarn ? "yarn" : e.useBun ? "bun" : void 0;
|
|
590
|
-
await
|
|
681
|
+
await ce({
|
|
591
682
|
directory: e.directory,
|
|
592
683
|
name: e.name,
|
|
593
684
|
adapter: e.adapter,
|
|
@@ -612,14 +703,14 @@ Available AsterFlow plugins:
|
|
|
612
703
|
describe: "Project directory (defaults to the current directory)"
|
|
613
704
|
}),
|
|
614
705
|
async (e) => {
|
|
615
|
-
await
|
|
706
|
+
await z({ names: e.names, directory: e.directory });
|
|
616
707
|
}
|
|
617
708
|
).command(
|
|
618
709
|
"list",
|
|
619
710
|
"List available plugins",
|
|
620
711
|
() => {
|
|
621
712
|
},
|
|
622
|
-
() =>
|
|
713
|
+
() => de()
|
|
623
714
|
).command(
|
|
624
715
|
"generate [directory]",
|
|
625
716
|
"Generate the static route manifest consumed by @asterflow/fs (fs-routing)",
|
|
@@ -636,7 +727,7 @@ Available AsterFlow plugins:
|
|
|
636
727
|
describe: "Regenerate whenever a file under the routes directory changes"
|
|
637
728
|
}),
|
|
638
729
|
async (e) => {
|
|
639
|
-
await
|
|
730
|
+
await Q({ directory: e.directory, out: e.out, watch: e.watch });
|
|
640
731
|
}
|
|
641
732
|
).demandCommand(1, "Specify a command: init, add, list or generate").strict().help().alias("help", "h").parse();
|
|
642
733
|
})().catch((e) => {
|