@monimesl/dot-cli 0.1.0-alpha.8 → 0.1.0-alpha.9
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +17 -9
- package/dist/cli.js +156 -67
- package/dist/cli.js.map +1 -1
- package/dist/{server-DFOUQnLA.js → server-BfPAnsSf.js} +34 -81
- package/dist/{server-DFOUQnLA.js.map → server-BfPAnsSf.js.map} +1 -1
- package/dist/templates/showcase/.env +1 -1
- package/dist/templates/showcase/dot.ts +2 -0
- package/dist/templates/showcase/pages/cache/controller.ts +45 -0
- package/dist/templates/showcase/pages/cache/state.ts +17 -0
- package/dist/templates/showcase/pages/cache/view.dml +36 -0
- package/dist/templates/showcase/pages/carousel/controller.ts +33 -3
- package/dist/templates/showcase/pages/carousel/state.ts +61 -24
- package/dist/templates/showcase/pages/carousel/view.dml +18 -15
- package/dist/templates/showcase/pages/device/controller.ts +22 -12
- package/dist/templates/showcase/pages/device/state.ts +1 -1
- package/dist/templates/showcase/pages/device/view.dml +13 -8
- package/dist/templates/showcase/pages/feedback/controller.ts +6 -1
- package/dist/templates/showcase/pages/feedback/state.ts +1 -0
- package/dist/templates/showcase/pages/feedback/view.dml +23 -23
- package/dist/templates/showcase/pages/files/controller.ts +33 -14
- package/dist/templates/showcase/pages/files/state.ts +10 -2
- package/dist/templates/showcase/pages/files/view.dml +29 -14
- package/dist/templates/showcase/pages/filters/controller.ts +11 -12
- package/dist/templates/showcase/pages/filters/state.ts +107 -61
- package/dist/templates/showcase/pages/filters/view.dml +18 -17
- package/dist/templates/showcase/pages/forms/controller.ts +36 -12
- package/dist/templates/showcase/pages/forms/state.ts +25 -6
- package/dist/templates/showcase/pages/forms/view.dml +28 -18
- package/dist/templates/showcase/pages/images/controller.ts +26 -0
- package/dist/templates/showcase/pages/images/state.ts +3 -0
- package/dist/templates/showcase/pages/images/view.dml +18 -3
- package/dist/templates/showcase/pages/index/state.ts +26 -14
- package/dist/templates/showcase/pages/index/view.dml +2 -2
- package/dist/templates/showcase/pages/layout/controller.ts +36 -2
- package/dist/templates/showcase/pages/layout/state.ts +22 -2
- package/dist/templates/showcase/pages/layout/view.dml +45 -22
- package/dist/templates/showcase/pages/lists/controller.ts +12 -11
- package/dist/templates/showcase/pages/lists/state.ts +87 -66
- package/dist/templates/showcase/pages/lists/view.dml +15 -15
- package/dist/templates/showcase/pages/navigation/controller.ts +2 -1
- package/dist/templates/showcase/pages/navigation/view.dml +5 -5
- package/dist/templates/showcase/pages/network/controller.ts +68 -24
- package/dist/templates/showcase/pages/network/state.ts +13 -6
- package/dist/templates/showcase/pages/network/view.dml +29 -18
- package/dist/templates/showcase/pages/payments/controller.ts +16 -12
- package/dist/templates/showcase/pages/payments/state.ts +3 -0
- package/dist/templates/showcase/pages/payments/view.dml +22 -12
- package/dist/templates/showcase/pages/secrets/controller.ts +43 -0
- package/dist/templates/showcase/pages/secrets/state.ts +5 -0
- package/dist/templates/showcase/pages/secrets/view.dml +24 -0
- package/dist/templates/showcase/pages/state/state.ts +1 -1
- package/dist/templates/showcase/pages/state/view.dml +9 -9
- package/dist/templates/showcase/pages/text/controller.ts +3 -3
- package/dist/templates/showcase/pages/text/state.ts +6 -5
- package/dist/templates/showcase/pages/text/view.dml +22 -13
- package/dist/templates/showcase/statics/logo.png +0 -0
- package/package.json +6 -6
package/README.md
CHANGED
|
@@ -8,19 +8,20 @@ dotctl create [dir] # scaffold a dot (asks for its name and template)
|
|
|
8
8
|
dotctl create page <path> # add a page to the dot you are in
|
|
9
9
|
dotctl build [root] # compile the dot into dist/ui and dist/logic, minified
|
|
10
10
|
dotctl dev [root] # build, run it in the browser simulator, and reload it on each change
|
|
11
|
+
dotctl preview [root] # build it as `build` does, and run that build in the browser simulator
|
|
11
12
|
dotctl keys show # print this computer's developer key: its public key and key ID
|
|
12
13
|
dotctl lsp # the .dml language server, which editors start
|
|
13
14
|
```
|
|
14
15
|
|
|
15
|
-
| Option | Applies to
|
|
16
|
-
| --------------------- |
|
|
17
|
-
| `--out-dir <dir>` |
|
|
18
|
-
| `--conditions <list>` |
|
|
19
|
-
| `--port <port>` | `dev`
|
|
20
|
-
| `--device` | `dev`
|
|
21
|
-
| `--name <name>` | `create`
|
|
22
|
-
| `--template <name>` | `create`
|
|
23
|
-
| `--pm <name>` | `create`
|
|
16
|
+
| Option | Applies to | What it does |
|
|
17
|
+
| --------------------- | ------------------------- | ------------------------------------------------------------------------ |
|
|
18
|
+
| `--out-dir <dir>` | `build`, `dev`, `preview` | Output directory (default: `<root>/dist`) |
|
|
19
|
+
| `--conditions <list>` | `build`, `dev`, `preview` | Extra export conditions, such as `@monimesl/dot-source` |
|
|
20
|
+
| `--port <port>` | `dev`, `preview` | Simulator port (default: `3680`, or the next free one) |
|
|
21
|
+
| `--device` | `dev` | Also serve the dot to the Dot example apps on phones, through a QR code |
|
|
22
|
+
| `--name <name>` | `create` | The dot's name, instead of asking |
|
|
23
|
+
| `--template <name>` | `create` | `starter` (one page to build on, the default) or `showcase` (every page) |
|
|
24
|
+
| `--pm <name>` | `create` | The package manager to install with: npm, pnpm, yarn or bun |
|
|
24
25
|
|
|
25
26
|
## `dotctl create`
|
|
26
27
|
|
|
@@ -45,6 +46,13 @@ With `--device`, it also serves each build on the local network to the Dot examp
|
|
|
45
46
|
QR code to scan with one, which then follows the dot in the same way: see
|
|
46
47
|
[the example apps](../hosts/native/README.md#the-example-apps).
|
|
47
48
|
|
|
49
|
+
## `dotctl preview`
|
|
50
|
+
|
|
51
|
+
Builds the dot as `dotctl build` does, and runs that build in the browser simulator: minified, and
|
|
52
|
+
with only the components its pages use, as the host app gets it. Use it to check a build before
|
|
53
|
+
publishing it. It doesn't rebuild on change: run it again after editing. The dot keeps the files it
|
|
54
|
+
saved under `dotctl dev`.
|
|
55
|
+
|
|
48
56
|
## Developer keys
|
|
49
57
|
|
|
50
58
|
Dash opens only links that one of the signed-in developer's keys signed. `dotctl dev --device`
|
package/dist/cli.js
CHANGED
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
import { createRequire } from "node:module";
|
|
2
2
|
import { spawn, spawnSync } from "node:child_process";
|
|
3
3
|
import { basename, dirname, join, relative, resolve, sep } from "node:path";
|
|
4
|
-
import {
|
|
5
|
-
import { parseArgs } from "node:util";
|
|
4
|
+
import { parseArgs, styleText } from "node:util";
|
|
6
5
|
import { CompileError, PAGES_DIR, build, installedRuntime, loadProject } from "@monimesl/dot-compiler";
|
|
7
6
|
import { DEFAULT_PORT, startSimulator } from "@monimesl/dot-simulator";
|
|
8
7
|
import { existsSync, readFileSync, readdirSync, watch } from "node:fs";
|
|
@@ -14,6 +13,8 @@ import { renderUnicodeCompact } from "uqr";
|
|
|
14
13
|
import { createHash, createHmac, createPrivateKey, createPublicKey, randomBytes, sign, timingSafeEqual } from "node:crypto";
|
|
15
14
|
import { homedir, networkInterfaces } from "node:os";
|
|
16
15
|
import { createServer } from "node:http";
|
|
16
|
+
import { emitKeypressEvents } from "node:readline";
|
|
17
|
+
import { createInterface } from "node:readline/promises";
|
|
17
18
|
//#region src/report.ts
|
|
18
19
|
/** A mistake in how a command was used, which its message alone explains. */
|
|
19
20
|
var CommandError = class extends Error {
|
|
@@ -36,6 +37,10 @@ function printBuildTime(startedAt) {
|
|
|
36
37
|
//#endregion
|
|
37
38
|
//#region src/create/template.ts
|
|
38
39
|
const TEMPLATES = ["starter", "showcase"];
|
|
40
|
+
const TEMPLATE_HINTS = {
|
|
41
|
+
starter: "one page to build on",
|
|
42
|
+
showcase: "a page for each feature, to read"
|
|
43
|
+
};
|
|
39
44
|
function isTemplate(name) {
|
|
40
45
|
return TEMPLATES.includes(name);
|
|
41
46
|
}
|
|
@@ -75,6 +80,7 @@ function packageJson({ packageName, dotVersion, workspace }) {
|
|
|
75
80
|
scripts: {
|
|
76
81
|
dev: `dotctl dev${conditions}`,
|
|
77
82
|
build: `dotctl build${conditions}`,
|
|
83
|
+
preview: `dotctl preview${conditions}`,
|
|
78
84
|
typecheck: "tsc --noEmit"
|
|
79
85
|
},
|
|
80
86
|
dependencies: { "@monimesl/dot-runtime": dotVersion },
|
|
@@ -115,8 +121,8 @@ function dotJson({ name, packageName, template }) {
|
|
|
115
121
|
version: "0.1.0"
|
|
116
122
|
};
|
|
117
123
|
if (template === "showcase") dot.network = { hosts: [
|
|
118
|
-
"
|
|
119
|
-
"
|
|
124
|
+
"itunes.apple.com",
|
|
125
|
+
"*.mzstatic.com",
|
|
120
126
|
"httpbin.org"
|
|
121
127
|
] };
|
|
122
128
|
return json(dot);
|
|
@@ -218,11 +224,17 @@ function cliRoot() {
|
|
|
218
224
|
return dirname(createRequire(import.meta.url).resolve("@monimesl/dot-cli/package.json"));
|
|
219
225
|
}
|
|
220
226
|
//#endregion
|
|
227
|
+
//#region src/dot-root.ts
|
|
228
|
+
function findDotRoot(dir) {
|
|
229
|
+
while (true) {
|
|
230
|
+
if (existsSync(join(dir, "dot.json"))) return dir;
|
|
231
|
+
const parent = dirname(dir);
|
|
232
|
+
if (parent === dir) return;
|
|
233
|
+
dir = parent;
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
//#endregion
|
|
221
237
|
//#region src/create/page.ts
|
|
222
|
-
/**
|
|
223
|
-
* Adds a page to the dot around `cwd`: its folder under pages/, with its three files, listed last in
|
|
224
|
-
* dot.ts.
|
|
225
|
-
*/
|
|
226
238
|
async function createPage(path, cwd) {
|
|
227
239
|
if (!isPageId(path)) throw new CommandError(`"${path}" is not a page path: use letters, digits, "-" and "_", with "/" between folders, such as "cart/checkout"`);
|
|
228
240
|
const root = findDotRoot(resolve(cwd));
|
|
@@ -277,14 +289,6 @@ function listsPage(source, dotFile, path) {
|
|
|
277
289
|
return false;
|
|
278
290
|
}
|
|
279
291
|
}
|
|
280
|
-
function findDotRoot(dir) {
|
|
281
|
-
while (true) {
|
|
282
|
-
if (existsSync(join(dir, "dot.json"))) return dir;
|
|
283
|
-
const parent = dirname(dir);
|
|
284
|
-
if (parent === dir) return;
|
|
285
|
-
dir = parent;
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
292
|
//#endregion
|
|
289
293
|
//#region src/create/package-manager.ts
|
|
290
294
|
const PACKAGE_MANAGERS = [
|
|
@@ -520,6 +524,17 @@ async function readText(request) {
|
|
|
520
524
|
return Buffer.concat(chunks).toString("utf8");
|
|
521
525
|
}
|
|
522
526
|
//#endregion
|
|
527
|
+
//#region src/simulator.ts
|
|
528
|
+
function startDotSimulator(project, outDir, port) {
|
|
529
|
+
return startSimulator({
|
|
530
|
+
dotDir: outDir,
|
|
531
|
+
reactHostDir: installedRuntime(project.root).react.dir,
|
|
532
|
+
name: project.dotJson.name,
|
|
533
|
+
port,
|
|
534
|
+
storageDir: join(project.root, ".dot", "files")
|
|
535
|
+
});
|
|
536
|
+
}
|
|
537
|
+
//#endregion
|
|
523
538
|
//#region src/dev.ts
|
|
524
539
|
const CHANGE_DEBOUNCE_MS = 50;
|
|
525
540
|
async function dev({ port, device, ...options }) {
|
|
@@ -543,13 +558,7 @@ async function dev({ port, device, ...options }) {
|
|
|
543
558
|
}
|
|
544
559
|
};
|
|
545
560
|
const firstError = await buildApp();
|
|
546
|
-
const simulator = await
|
|
547
|
-
dotDir: outDir,
|
|
548
|
-
reactHostDir: installedRuntime(project.root).react.dir,
|
|
549
|
-
name: project.dotJson.name,
|
|
550
|
-
port,
|
|
551
|
-
storageDir: join(project.root, ".dot", "files")
|
|
552
|
-
});
|
|
561
|
+
const simulator = await startDotSimulator(project, outDir, port);
|
|
553
562
|
if (firstError) simulator.error(firstError);
|
|
554
563
|
console.log(`\n Simulator running at: ${simulator.url}\n`);
|
|
555
564
|
let devices;
|
|
@@ -637,6 +646,99 @@ function isIgnored(file) {
|
|
|
637
646
|
});
|
|
638
647
|
}
|
|
639
648
|
//#endregion
|
|
649
|
+
//#region src/preview.ts
|
|
650
|
+
async function preview({ port, ...options }) {
|
|
651
|
+
const project = await loadProject(options.root);
|
|
652
|
+
const outDir = resolve(project.root, options.outDir ?? "dist");
|
|
653
|
+
const started = performance.now();
|
|
654
|
+
printWarnings(await build({
|
|
655
|
+
...options,
|
|
656
|
+
outDir,
|
|
657
|
+
mode: "production"
|
|
658
|
+
}));
|
|
659
|
+
printBuildTime(started);
|
|
660
|
+
const simulator = await startDotSimulator(project, outDir, port);
|
|
661
|
+
console.log(`\n Simulator running at: ${simulator.url}\n`);
|
|
662
|
+
return simulator;
|
|
663
|
+
}
|
|
664
|
+
//#endregion
|
|
665
|
+
//#region src/prompts.ts
|
|
666
|
+
const TERMINAL = {
|
|
667
|
+
input: process.stdin,
|
|
668
|
+
output: process.stdout
|
|
669
|
+
};
|
|
670
|
+
const ERASE_BELOW = "\x1B[0J";
|
|
671
|
+
const HIDE_CURSOR = "\x1B[?25l";
|
|
672
|
+
const SHOW_CURSOR = "\x1B[?25h";
|
|
673
|
+
const cursorUp = (lines) => `\x1b[${lines}A`;
|
|
674
|
+
async function select(question, choices, fallback, { input, output } = TERMINAL) {
|
|
675
|
+
if (!input.isTTY) return fallback;
|
|
676
|
+
let current = Math.max(0, choices.findIndex((choice) => choice.value === fallback));
|
|
677
|
+
const width = choices.some((choice) => choice.hint) ? Math.max(...choices.map((choice) => choice.value.length)) : 0;
|
|
678
|
+
const row = (choice, index) => {
|
|
679
|
+
const name = choice.value.padEnd(width);
|
|
680
|
+
const hint = choice.hint ? styleText("dim", ` ${choice.hint}`) : "";
|
|
681
|
+
const defaultMark = choice.value === fallback ? styleText("green", " (default)") : "";
|
|
682
|
+
if (index === current) return `${styleText("cyan", "❯")} ${styleText(["cyan", "bold"], name)}${hint}${defaultMark}`;
|
|
683
|
+
return ` ${name}${hint}${defaultMark}`;
|
|
684
|
+
};
|
|
685
|
+
let drawnLines = 0;
|
|
686
|
+
const draw = (lines) => {
|
|
687
|
+
output.write(`${drawnLines ? cursorUp(drawnLines) : ""}${ERASE_BELOW}${lines.join("\n")}\n`);
|
|
688
|
+
drawnLines = lines.length;
|
|
689
|
+
};
|
|
690
|
+
const drawList = () => draw([`${styleText("bold", question)} ${styleText("dim", "↑/↓ to move, Enter to choose")}`, ...choices.map(row)]);
|
|
691
|
+
emitKeypressEvents(input);
|
|
692
|
+
input.setRawMode(true);
|
|
693
|
+
input.resume();
|
|
694
|
+
output.write(HIDE_CURSOR);
|
|
695
|
+
drawList();
|
|
696
|
+
return new Promise((resolve) => {
|
|
697
|
+
const onKeypress = (_text, key) => {
|
|
698
|
+
if (key.ctrl && key.name === "c") {
|
|
699
|
+
output.write(`${SHOW_CURSOR}\n`);
|
|
700
|
+
process.exit(130);
|
|
701
|
+
}
|
|
702
|
+
if (key.name === "up" || key.name === "k") {
|
|
703
|
+
current = (current - 1 + choices.length) % choices.length;
|
|
704
|
+
drawList();
|
|
705
|
+
} else if (key.name === "down" || key.name === "j") {
|
|
706
|
+
current = (current + 1) % choices.length;
|
|
707
|
+
drawList();
|
|
708
|
+
} else if (key.name === "return" || key.name === "enter") {
|
|
709
|
+
const { value } = choices[current];
|
|
710
|
+
input.off("keypress", onKeypress);
|
|
711
|
+
input.setRawMode(false);
|
|
712
|
+
input.pause();
|
|
713
|
+
draw([`${styleText("bold", question)} ${styleText("cyan", value)}`]);
|
|
714
|
+
output.write(SHOW_CURSOR);
|
|
715
|
+
resolve(value);
|
|
716
|
+
}
|
|
717
|
+
};
|
|
718
|
+
input.on("keypress", onKeypress);
|
|
719
|
+
});
|
|
720
|
+
}
|
|
721
|
+
async function confirm(question, fallback, terminal = TERMINAL) {
|
|
722
|
+
if (!terminal.input.isTTY) return false;
|
|
723
|
+
return await select(question, [{ value: "Yes" }, { value: "No" }], fallback ? "Yes" : "No", terminal) === "Yes";
|
|
724
|
+
}
|
|
725
|
+
async function ask(question, fallback, { input, output } = TERMINAL) {
|
|
726
|
+
if (!input.isTTY) return fallback;
|
|
727
|
+
const hint = fallback ? styleText("dim", ` (default: ${fallback})`) : "";
|
|
728
|
+
const readline = createInterface({
|
|
729
|
+
input,
|
|
730
|
+
output
|
|
731
|
+
});
|
|
732
|
+
try {
|
|
733
|
+
return (await readline.question(`${styleText("bold", question)}${hint}: `)).trim() || fallback;
|
|
734
|
+
} catch (error) {
|
|
735
|
+
if (error.name === "AbortError") return;
|
|
736
|
+
throw error;
|
|
737
|
+
} finally {
|
|
738
|
+
readline.close();
|
|
739
|
+
}
|
|
740
|
+
}
|
|
741
|
+
//#endregion
|
|
640
742
|
//#region src/cli.ts
|
|
641
743
|
const USAGE = `Usage:
|
|
642
744
|
dotctl create [dir] [--name <name>] [--template <starter|showcase>]
|
|
@@ -648,6 +750,8 @@ const USAGE = `Usage:
|
|
|
648
750
|
view.dml, state.ts and controller.ts
|
|
649
751
|
dotctl build [root] [options] Build the minified bundles the host app runs
|
|
650
752
|
dotctl dev [root] [options] Run in the browser simulator, rebuilding on change
|
|
753
|
+
dotctl preview [root] [options] Build as \`build\` does, and run that build in the browser
|
|
754
|
+
simulator, as the host app gets it
|
|
651
755
|
dotctl keys show Show the public key and key ID of this computer's
|
|
652
756
|
developer key, which signs the links \`dev --device\`
|
|
653
757
|
shows, for Dash to open
|
|
@@ -657,8 +761,8 @@ const USAGE = `Usage:
|
|
|
657
761
|
Options:
|
|
658
762
|
--out-dir <dir> Output directory (default: <root>/dist)
|
|
659
763
|
--conditions <list> Extra export conditions, comma separated
|
|
660
|
-
--port <port> Simulator port for \`dev\`; the next free one is used
|
|
661
|
-
(default: ${DEFAULT_PORT})
|
|
764
|
+
--port <port> Simulator port for \`dev\` and \`preview\`; the next free one is used
|
|
765
|
+
if taken (default: ${DEFAULT_PORT})
|
|
662
766
|
--device With \`dev\`, also serve the dot to the Dot example apps on phones on
|
|
663
767
|
the local network, through a link and QR code; they reload on each build
|
|
664
768
|
-h, --help Show this message`;
|
|
@@ -683,14 +787,14 @@ async function main(argv) {
|
|
|
683
787
|
});
|
|
684
788
|
const [command, target, pagePath] = positionals;
|
|
685
789
|
if (command === "lsp" && !values.help) {
|
|
686
|
-
const { serveStdio } = await import("./server-
|
|
790
|
+
const { serveStdio } = await import("./server-BfPAnsSf.js");
|
|
687
791
|
serveStdio();
|
|
688
792
|
return new Promise(() => {});
|
|
689
793
|
}
|
|
690
794
|
if (command === "keys" && !values.help) return keys(target);
|
|
691
795
|
if (command === "create" && target === "page" && !values.help) return addPage(pagePath);
|
|
692
796
|
if (command === "create" && !values.help) return createApp(target, values.name, values.template, values.pm);
|
|
693
|
-
if (values.help || command !== "build" && command !== "dev") {
|
|
797
|
+
if (values.help || command !== "build" && command !== "dev" && command !== "preview") {
|
|
694
798
|
console.log(USAGE);
|
|
695
799
|
return values.help ? 0 : 1;
|
|
696
800
|
}
|
|
@@ -712,6 +816,19 @@ async function main(argv) {
|
|
|
712
816
|
await stop();
|
|
713
817
|
return 0;
|
|
714
818
|
}
|
|
819
|
+
if (command === "preview") {
|
|
820
|
+
if (values.device) {
|
|
821
|
+
console.error("--device works only with dotctl dev");
|
|
822
|
+
return 1;
|
|
823
|
+
}
|
|
824
|
+
const simulator = await preview({
|
|
825
|
+
...options,
|
|
826
|
+
port
|
|
827
|
+
});
|
|
828
|
+
await new Promise((resolve) => process.once("SIGINT", resolve));
|
|
829
|
+
await simulator.close();
|
|
830
|
+
return 0;
|
|
831
|
+
}
|
|
715
832
|
const started = performance.now();
|
|
716
833
|
const result = await build(options);
|
|
717
834
|
for (const file of result.files.filter((file) => !file.endsWith(".map"))) console.log(` ${relative(process.cwd(), file)}`);
|
|
@@ -755,7 +872,7 @@ async function createApp(dir, name, templateFlag, packageManagerFlag) {
|
|
|
755
872
|
console.error(`--pm must be one of ${PACKAGE_MANAGERS.join(", ")}`);
|
|
756
873
|
return 1;
|
|
757
874
|
}
|
|
758
|
-
name ??= await ask("Dot name
|
|
875
|
+
name ??= await ask("Dot name", dir ? toDisplayName(dir) : "Dot");
|
|
759
876
|
if (!name) {
|
|
760
877
|
console.error("A dot needs a name: dotctl create [dir] --name \"My Dot\"");
|
|
761
878
|
return 1;
|
|
@@ -770,7 +887,8 @@ async function createApp(dir, name, templateFlag, packageManagerFlag) {
|
|
|
770
887
|
console.log(`\nCreated ${name} in ${path}`);
|
|
771
888
|
if (workspace) console.log("It is inside the Dot repository, so it uses the workspace packages.");
|
|
772
889
|
let packageManager = workspace ? "pnpm" : packageManagerFlag ?? launchedBy();
|
|
773
|
-
|
|
890
|
+
console.log();
|
|
891
|
+
if (await confirm("Install and start it now?", true)) {
|
|
774
892
|
if (!workspace && !packageManagerFlag) packageManager = await choosePackageManager(packageManager);
|
|
775
893
|
if (await run(packageManager, ["install"], root) === 0) return run(packageManager, ["run", "dev"], root);
|
|
776
894
|
console.error(`\n${packageManager} install failed.`);
|
|
@@ -789,53 +907,24 @@ function run(command, args, cwd) {
|
|
|
789
907
|
child.on("exit", (code) => resolvePromise(code ?? 1));
|
|
790
908
|
});
|
|
791
909
|
}
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
return readAnswer(`${question}${fallback ? ` (${fallback})` : ""}`, fallback);
|
|
799
|
-
}
|
|
800
|
-
async function readAnswer(prompt, fallback) {
|
|
801
|
-
if (!process.stdin.isTTY) return fallback;
|
|
802
|
-
const readline = createInterface({
|
|
803
|
-
input: process.stdin,
|
|
804
|
-
output: process.stdout
|
|
805
|
-
});
|
|
806
|
-
try {
|
|
807
|
-
return (await readline.question(`${prompt} `)).trim() || fallback;
|
|
808
|
-
} catch (error) {
|
|
809
|
-
if (error.name === "AbortError") return;
|
|
810
|
-
throw error;
|
|
811
|
-
} finally {
|
|
812
|
-
readline.close();
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
async function chooseTemplate() {
|
|
816
|
-
if (!process.stdin.isTTY) return "starter";
|
|
817
|
-
console.log("\nTemplates:\n starter one page to build on\n showcase a page for each feature, to read");
|
|
818
|
-
return chooseOne("Template?", TEMPLATES, "starter");
|
|
910
|
+
function chooseTemplate() {
|
|
911
|
+
console.log();
|
|
912
|
+
return select("Template?", TEMPLATES.map((template) => ({
|
|
913
|
+
value: template,
|
|
914
|
+
hint: TEMPLATE_HINTS[template]
|
|
915
|
+
})), "starter");
|
|
819
916
|
}
|
|
820
917
|
async function choosePackageManager(suggested) {
|
|
821
918
|
const installed = installedManagers();
|
|
822
919
|
if (installed.length < 2) return installed[0] ?? suggested;
|
|
823
|
-
|
|
824
|
-
}
|
|
825
|
-
async function chooseOne(question, options, fallback) {
|
|
826
|
-
while (true) {
|
|
827
|
-
const answer = await ask(`${question} ${options.join(" / ")}`, fallback);
|
|
828
|
-
if (answer === void 0) return fallback;
|
|
829
|
-
const chosen = options.find((option) => option === answer);
|
|
830
|
-
if (chosen) return chosen;
|
|
831
|
-
console.log(`Choose one of ${options.join(", ")}.`);
|
|
832
|
-
}
|
|
920
|
+
const fallback = installed.includes(suggested) ? suggested : installed[0];
|
|
921
|
+
return select("Package manager?", installed.map((manager) => ({ value: manager })), fallback);
|
|
833
922
|
}
|
|
834
923
|
main(process.argv.slice(2)).then((code) => process.exit(code), (error) => {
|
|
835
924
|
console.error(`error: ${describeError(error)}`);
|
|
836
925
|
process.exit(1);
|
|
837
926
|
});
|
|
838
927
|
//#endregion
|
|
839
|
-
export {};
|
|
928
|
+
export { findDotRoot as t };
|
|
840
929
|
|
|
841
930
|
//# sourceMappingURL=cli.js.map
|