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