create-vidra-app 0.1.4 → 0.1.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +561 -214
- package/dist/index.js +142 -54
- package/package.json +10 -1
- package/templates/react-vite/package.json +2 -2
package/dist/index.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
2
|
import prompts2 from "prompts";
|
|
3
|
-
import chalk3 from "chalk";
|
|
4
3
|
import fs2 from "fs-extra";
|
|
5
4
|
import path2 from "path";
|
|
6
5
|
import { randomUUID } from "crypto";
|
|
@@ -26,7 +25,17 @@ var parseArgs = (argv) => {
|
|
|
26
25
|
const arg = argv[i];
|
|
27
26
|
if (arg.startsWith("--")) {
|
|
28
27
|
const [key, val] = arg.slice(2).split("=");
|
|
29
|
-
|
|
28
|
+
if (val !== void 0) {
|
|
29
|
+
args[key] = val;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
const next = argv[i + 1];
|
|
33
|
+
if (next !== void 0 && !next.startsWith("--")) {
|
|
34
|
+
args[key] = next;
|
|
35
|
+
i++;
|
|
36
|
+
} else {
|
|
37
|
+
args[key] = true;
|
|
38
|
+
}
|
|
30
39
|
} else {
|
|
31
40
|
args._.push(arg);
|
|
32
41
|
}
|
|
@@ -36,14 +45,65 @@ var parseArgs = (argv) => {
|
|
|
36
45
|
|
|
37
46
|
// src/exec.ts
|
|
38
47
|
import { execSync } from "child_process";
|
|
48
|
+
|
|
49
|
+
// src/theme.ts
|
|
39
50
|
import chalk from "chalk";
|
|
51
|
+
var lime = chalk.hex("#c8f751");
|
|
52
|
+
var value = chalk.hex("#e8e8ec");
|
|
53
|
+
var dim = chalk.hex("#7a7a86");
|
|
54
|
+
var amber = chalk.hex("#ffcf5c");
|
|
55
|
+
var green = chalk.hex("#86d98f");
|
|
56
|
+
var red = chalk.hex("#ff8585");
|
|
57
|
+
var slate = chalk.hex("#a9b0bd");
|
|
58
|
+
var uiColor = chalk.hex("#6fd3e0");
|
|
59
|
+
var hostColor = chalk.hex("#a48ce8");
|
|
60
|
+
var GLYPH_CHAR = {
|
|
61
|
+
done: "\u2713",
|
|
62
|
+
active: "\u25B8",
|
|
63
|
+
error: "\u2717",
|
|
64
|
+
manual: "?",
|
|
65
|
+
plan: "\u25C6",
|
|
66
|
+
skip: "\u2298"
|
|
67
|
+
};
|
|
68
|
+
var GLYPH_COLOR = {
|
|
69
|
+
done: green,
|
|
70
|
+
active: lime,
|
|
71
|
+
error: red,
|
|
72
|
+
manual: amber,
|
|
73
|
+
plan: slate,
|
|
74
|
+
skip: slate
|
|
75
|
+
};
|
|
76
|
+
var glyph = (name) => GLYPH_COLOR[name](GLYPH_CHAR[name]);
|
|
77
|
+
var wordmark = () => lime("vidra");
|
|
78
|
+
var kv = (label, val, width = 9) => ` ${dim(label.padEnd(width))} ${value(val)}`;
|
|
79
|
+
var row = (opts) => {
|
|
80
|
+
const parts = [` ${glyph(opts.glyph)}`];
|
|
81
|
+
if (opts.label !== void 0) {
|
|
82
|
+
const padded = opts.labelWidth ? opts.label.padEnd(opts.labelWidth) : opts.label;
|
|
83
|
+
parts.push(value(padded));
|
|
84
|
+
}
|
|
85
|
+
if (opts.detail) parts.push(opts.detail);
|
|
86
|
+
return parts.join(" ");
|
|
87
|
+
};
|
|
88
|
+
var footer = (content) => ` ${content}`;
|
|
89
|
+
var fixLine = (cmd, label = "fix:") => ` ${amber(label)} ${lime(cmd)}`;
|
|
90
|
+
|
|
91
|
+
// src/exec.ts
|
|
92
|
+
var toText = (value2) => {
|
|
93
|
+
if (value2 == null) return "";
|
|
94
|
+
return Buffer.isBuffer(value2) ? value2.toString() : value2;
|
|
95
|
+
};
|
|
96
|
+
var formatProcessError = (error) => {
|
|
97
|
+
const err = error;
|
|
98
|
+
const combined = [toText(err.stderr), toText(err.stdout)].map((s) => s.trim()).filter((s) => s.length > 0).join("\n").trim();
|
|
99
|
+
return combined.length > 0 ? combined : err.message ?? String(error);
|
|
100
|
+
};
|
|
40
101
|
var exec = (cmd, cwd) => {
|
|
41
102
|
try {
|
|
42
103
|
execSync(cmd, { cwd, stdio: "pipe" });
|
|
43
104
|
} catch (e) {
|
|
44
|
-
|
|
45
|
-
console.error(
|
|
46
|
-
console.error(chalk.dim(err.stderr?.toString() || err.message));
|
|
105
|
+
console.error(row({ glyph: "error", detail: dim(`command failed: ${cmd}`) }));
|
|
106
|
+
console.error(dim(formatProcessError(e)));
|
|
47
107
|
process.exit(1);
|
|
48
108
|
}
|
|
49
109
|
};
|
|
@@ -115,7 +175,6 @@ var applyReplacements = (str, replacements) => {
|
|
|
115
175
|
// src/doctor.ts
|
|
116
176
|
import { execFileSync } from "child_process";
|
|
117
177
|
import prompts from "prompts";
|
|
118
|
-
import chalk2 from "chalk";
|
|
119
178
|
var DOTNET = process.platform === "win32" ? "dotnet.exe" : "dotnet";
|
|
120
179
|
var MAUI_DOCS = "https://learn.microsoft.com/dotnet/maui/get-started/installation";
|
|
121
180
|
var bufToStr = (v) => v == null ? "" : Buffer.isBuffer(v) ? v.toString() : v;
|
|
@@ -178,11 +237,16 @@ var isInteractive = () => Boolean(process.stdin.isTTY && process.stdout.isTTY);
|
|
|
178
237
|
var installWorkload = (csprojPath) => {
|
|
179
238
|
const args = csprojPath ? ["workload", "restore", csprojPath] : ["workload", "install", "maui"];
|
|
180
239
|
console.log();
|
|
181
|
-
console.log(` ${chalk2.dim(`Running: ${DOTNET} ${args.join(" ")}`)}`);
|
|
182
240
|
console.log(
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
241
|
+
row({
|
|
242
|
+
glyph: "active",
|
|
243
|
+
detail: `${dim("running")} ${value(`${DOTNET} ${args.join(" ")}`)}`
|
|
244
|
+
})
|
|
245
|
+
);
|
|
246
|
+
console.log(
|
|
247
|
+
footer(
|
|
248
|
+
dim("this can download several hundred MB and take a few minutes.")
|
|
249
|
+
)
|
|
186
250
|
);
|
|
187
251
|
console.log();
|
|
188
252
|
try {
|
|
@@ -190,13 +254,15 @@ var installWorkload = (csprojPath) => {
|
|
|
190
254
|
return true;
|
|
191
255
|
} catch {
|
|
192
256
|
console.error();
|
|
193
|
-
console.error(
|
|
257
|
+
console.error(row({ glyph: "error", label: "workload install failed" }));
|
|
194
258
|
console.error(
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
259
|
+
footer(
|
|
260
|
+
dim(
|
|
261
|
+
"if this is a permissions error, your SDK is in a system location and needs elevation:"
|
|
262
|
+
)
|
|
263
|
+
)
|
|
198
264
|
);
|
|
199
|
-
console.error(
|
|
265
|
+
console.error(fixLine("sudo dotnet workload install maui"));
|
|
200
266
|
console.error();
|
|
201
267
|
return false;
|
|
202
268
|
}
|
|
@@ -205,9 +271,15 @@ var ensureMauiWorkload = async (opts = {}) => {
|
|
|
205
271
|
const dotnet = checkDotnetSdk();
|
|
206
272
|
if (dotnet.status === "missing") {
|
|
207
273
|
console.log();
|
|
208
|
-
console.log(
|
|
274
|
+
console.log(
|
|
275
|
+
row({
|
|
276
|
+
glyph: "error",
|
|
277
|
+
label: dotnet.name,
|
|
278
|
+
detail: dotnet.detail ? dim(dotnet.detail) : void 0
|
|
279
|
+
})
|
|
280
|
+
);
|
|
209
281
|
if (dotnet.fix) {
|
|
210
|
-
console.log(
|
|
282
|
+
console.log(fixLine(dotnet.fix));
|
|
211
283
|
}
|
|
212
284
|
return false;
|
|
213
285
|
}
|
|
@@ -215,7 +287,11 @@ var ensureMauiWorkload = async (opts = {}) => {
|
|
|
215
287
|
if (isMauiWorkloadInstalled()) return true;
|
|
216
288
|
console.log();
|
|
217
289
|
console.log(
|
|
218
|
-
|
|
290
|
+
row({
|
|
291
|
+
glyph: "error",
|
|
292
|
+
label: ".NET MAUI workload",
|
|
293
|
+
detail: dim("required but not installed")
|
|
294
|
+
})
|
|
219
295
|
);
|
|
220
296
|
const interactive = opts.interactive ?? isInteractive();
|
|
221
297
|
if (interactive) {
|
|
@@ -233,20 +309,25 @@ var ensureMauiWorkload = async (opts = {}) => {
|
|
|
233
309
|
}
|
|
234
310
|
if (install) {
|
|
235
311
|
if (installWorkload(opts.csprojPath) && isMauiWorkloadInstalled()) {
|
|
236
|
-
console.log(
|
|
312
|
+
console.log(
|
|
313
|
+
row({
|
|
314
|
+
glyph: "done",
|
|
315
|
+
label: ".NET MAUI workload",
|
|
316
|
+
detail: dim("installed")
|
|
317
|
+
})
|
|
318
|
+
);
|
|
237
319
|
return true;
|
|
238
320
|
}
|
|
239
321
|
return false;
|
|
240
322
|
}
|
|
241
323
|
}
|
|
242
|
-
console.log(
|
|
243
|
-
|
|
244
|
-
);
|
|
245
|
-
console.log(` ${chalk2.dim("docs:")} ${chalk2.cyan(MAUI_DOCS)}`);
|
|
324
|
+
console.log(fixLine("dotnet workload install maui", "run:"));
|
|
325
|
+
console.log(fixLine(MAUI_DOCS, "docs:"));
|
|
246
326
|
return false;
|
|
247
327
|
};
|
|
248
328
|
|
|
249
329
|
// src/index.ts
|
|
330
|
+
var note = (label, body) => ` ${dim(label.padEnd(7))} ${body}`;
|
|
250
331
|
var __dirname = path2.dirname(fileURLToPath(import.meta.url));
|
|
251
332
|
var CLI_ROOT = path2.resolve(__dirname, "..");
|
|
252
333
|
var TEMPLATES_DIR = path2.join(CLI_ROOT, "templates");
|
|
@@ -258,8 +339,9 @@ var VIDRA_VERSION = "0.1.0";
|
|
|
258
339
|
var SDK_VERSION = "0.1.0";
|
|
259
340
|
var main = async () => {
|
|
260
341
|
console.log();
|
|
261
|
-
console.log(
|
|
262
|
-
console.log(
|
|
342
|
+
console.log(` create-${lime("vidra")}-app`);
|
|
343
|
+
console.log(footer(dim("scaffold a new vidra application")));
|
|
344
|
+
console.log();
|
|
263
345
|
const args = parseArgs(process.argv);
|
|
264
346
|
let projectDir = args._[0];
|
|
265
347
|
let appId = args["app-id"];
|
|
@@ -295,19 +377,20 @@ var main = async () => {
|
|
|
295
377
|
}
|
|
296
378
|
const root = path2.resolve(projectDir);
|
|
297
379
|
if (fs2.existsSync(root) && fs2.readdirSync(root).length > 0) {
|
|
380
|
+
console.error();
|
|
298
381
|
console.error(
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
)
|
|
382
|
+
row({
|
|
383
|
+
glyph: "error",
|
|
384
|
+
detail: dim(`directory "${projectDir}" already exists and is not empty`)
|
|
385
|
+
})
|
|
304
386
|
);
|
|
387
|
+
console.error();
|
|
305
388
|
process.exit(1);
|
|
306
389
|
}
|
|
307
390
|
console.log();
|
|
308
|
-
console.log(
|
|
309
|
-
console.log(
|
|
310
|
-
console.log(
|
|
391
|
+
console.log(kv("project", projectName));
|
|
392
|
+
console.log(kv("directory", root));
|
|
393
|
+
console.log(kv("app id", appId));
|
|
311
394
|
console.log();
|
|
312
395
|
const isMonorepo = fs2.existsSync(path2.join(LOCAL_SDK_DIR, "package.json"));
|
|
313
396
|
const localFeedExists = isMonorepo && fs2.existsSync(LOCAL_FEED_DIR);
|
|
@@ -327,42 +410,49 @@ var main = async () => {
|
|
|
327
410
|
};
|
|
328
411
|
const templateDir = path2.join(TEMPLATES_DIR, "react-vite");
|
|
329
412
|
await scaffoldDir(templateDir, root, replacements);
|
|
330
|
-
console.log(
|
|
413
|
+
console.log(row({ glyph: "active", detail: dim("creating solution\u2026") }));
|
|
331
414
|
exec(`dotnet new sln -n ${projectName} --force`, root);
|
|
332
415
|
const slnFile = fs2.existsSync(path2.join(root, `${projectName}.slnx`)) ? `${projectName}.slnx` : `${projectName}.sln`;
|
|
333
416
|
exec(
|
|
334
417
|
`dotnet sln ${slnFile} add src/${projectName}.Host/${projectName}.Host.csproj`,
|
|
335
418
|
root
|
|
336
419
|
);
|
|
337
|
-
console.log(
|
|
420
|
+
console.log(row({ glyph: "active", detail: dim("installing dependencies\u2026") }));
|
|
338
421
|
const uiDir = path2.join(root, "ui");
|
|
339
422
|
const rootNpmOk = tryExec("npm install", root);
|
|
340
423
|
const uiNpmOk = tryExec("npm install", uiDir);
|
|
341
424
|
const npmOk = rootNpmOk && uiNpmOk;
|
|
342
425
|
console.log();
|
|
343
|
-
console.log(
|
|
426
|
+
console.log(
|
|
427
|
+
row({
|
|
428
|
+
glyph: "done",
|
|
429
|
+
detail: `${dim("your")} ${wordmark()} ${dim("app is ready")}`
|
|
430
|
+
})
|
|
431
|
+
);
|
|
432
|
+
console.log();
|
|
344
433
|
if (localFeedExists) {
|
|
345
|
-
console.log(
|
|
346
|
-
chalk3.dim(" NuGet:") + " local feed \u2192 " + chalk3.cyan(LOCAL_FEED_DIR)
|
|
347
|
-
);
|
|
434
|
+
console.log(note("nuget", `${dim("local feed \u2192")} ${value(LOCAL_FEED_DIR)}`));
|
|
348
435
|
} else if (isMonorepo) {
|
|
349
436
|
console.log(
|
|
350
|
-
|
|
437
|
+
row({
|
|
438
|
+
glyph: "manual",
|
|
439
|
+
detail: `${dim("local NuGet feed not found. run")} ${lime("./pack-local.sh")} ${dim("in the vidra repo, then update NuGet.Config.")}`
|
|
440
|
+
})
|
|
351
441
|
);
|
|
352
442
|
}
|
|
353
443
|
if (isMonorepo) {
|
|
354
|
-
console.log(
|
|
355
|
-
|
|
356
|
-
);
|
|
357
|
-
console.log(
|
|
358
|
-
chalk3.dim(" npm: ") + " create-vidra-app \u2192 " + chalk3.cyan(LOCAL_CLI_DIR)
|
|
359
|
-
);
|
|
444
|
+
console.log(note("npm", `${dim("@vidra-dev/sdk \u2192")} ${value(LOCAL_SDK_DIR)}`));
|
|
445
|
+
console.log(note("npm", `${dim("create-vidra-app \u2192")} ${value(LOCAL_CLI_DIR)}`));
|
|
360
446
|
}
|
|
361
447
|
console.log();
|
|
362
448
|
if (!npmOk) {
|
|
363
449
|
console.log(
|
|
364
|
-
|
|
450
|
+
row({
|
|
451
|
+
glyph: "manual",
|
|
452
|
+
detail: `${dim("npm install had errors. re-run")} ${lime("npm install")} ${dim("in the project root and in")} ${value("ui/")} ${dim("to retry.")}`
|
|
453
|
+
})
|
|
365
454
|
);
|
|
455
|
+
console.log();
|
|
366
456
|
}
|
|
367
457
|
const hostCsproj = path2.join(
|
|
368
458
|
root,
|
|
@@ -371,21 +461,19 @@ var main = async () => {
|
|
|
371
461
|
`${projectName}.Host.csproj`
|
|
372
462
|
);
|
|
373
463
|
const prereqsReady = await ensureMauiWorkload({ csprojPath: hostCsproj });
|
|
374
|
-
console.log(
|
|
375
|
-
console.log(` cd ${projectDir}`);
|
|
464
|
+
console.log(footer(dim("next steps")));
|
|
465
|
+
console.log(` ${value(`cd ${projectDir}`)}`);
|
|
376
466
|
console.log(
|
|
377
|
-
` npm run dev ${
|
|
467
|
+
` ${value("npm run dev")} ${dim("# starts vite + the MAUI host together")}`
|
|
378
468
|
);
|
|
379
469
|
if (!prereqsReady) {
|
|
380
470
|
console.log(
|
|
381
|
-
` ${
|
|
382
|
-
"vidra doctor"
|
|
383
|
-
)} ${chalk3.dim("to verify your setup first")}`
|
|
471
|
+
` ${dim("tip: run")} ${lime("vidra doctor")} ${dim("to verify your setup first")}`
|
|
384
472
|
);
|
|
385
473
|
}
|
|
386
474
|
console.log();
|
|
387
475
|
};
|
|
388
476
|
main().catch((e) => {
|
|
389
|
-
console.error(
|
|
477
|
+
console.error(row({ glyph: "error", detail: dim(e.message) }));
|
|
390
478
|
process.exit(1);
|
|
391
479
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "create-vidra-app",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.6",
|
|
4
4
|
"description": "Scaffold a new Vidra application (React + .NET MAUI)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
|
@@ -21,9 +21,18 @@
|
|
|
21
21
|
},
|
|
22
22
|
"keywords": [
|
|
23
23
|
"vidra",
|
|
24
|
+
"create-vidra-app",
|
|
25
|
+
"dotnet",
|
|
26
|
+
"csharp",
|
|
27
|
+
"dotnet-maui",
|
|
24
28
|
"maui",
|
|
25
29
|
"react",
|
|
30
|
+
"vue",
|
|
31
|
+
"svelte",
|
|
26
32
|
"cross-platform",
|
|
33
|
+
"desktop",
|
|
34
|
+
"electron-alternative",
|
|
35
|
+
"tauri-alternative",
|
|
27
36
|
"scaffold",
|
|
28
37
|
"cli"
|
|
29
38
|
],
|
|
@@ -5,8 +5,8 @@
|
|
|
5
5
|
"build": "vidra build",
|
|
6
6
|
"dev": "vidra dev",
|
|
7
7
|
"dev:ui": "npm run dev --prefix ui",
|
|
8
|
-
"dev:host:macos": "
|
|
9
|
-
"dev:host:windows": "
|
|
8
|
+
"dev:host:macos": "vidra run --target macos",
|
|
9
|
+
"dev:host:windows": "vidra run --target windows"
|
|
10
10
|
},
|
|
11
11
|
"devDependencies": {
|
|
12
12
|
"create-vidra-app": "{{cliVersion}}"
|