@monimesl/dot-cli 0.1.0-alpha.7 → 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 +158 -71
- 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;
|
|
@@ -601,11 +610,9 @@ async function dev({ port, device, ...options }) {
|
|
|
601
610
|
};
|
|
602
611
|
}
|
|
603
612
|
function printDeviceLink(link) {
|
|
604
|
-
console.log(" Scan this in Dash
|
|
613
|
+
console.log(" Scan this in Dash: turn on Enable Dot Debugging in Developer Settings, then tap Live Test on\n the Dots tab.\n");
|
|
605
614
|
console.log(renderUnicodeCompact(link, { border: 1 }).replace(/^/gm, " "));
|
|
606
|
-
console.log(`\n
|
|
607
|
-
console.log(` Android emulator: adb shell am start -a android.intent.action.VIEW -d '${link}'`);
|
|
608
|
-
console.log(` iOS Simulator: xcrun simctl openurl booted '${link}'\n`);
|
|
615
|
+
console.log(`\n ${link}\n`);
|
|
609
616
|
}
|
|
610
617
|
var RebuildQueue = class {
|
|
611
618
|
#rebuild;
|
|
@@ -639,6 +646,99 @@ function isIgnored(file) {
|
|
|
639
646
|
});
|
|
640
647
|
}
|
|
641
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
|
|
642
742
|
//#region src/cli.ts
|
|
643
743
|
const USAGE = `Usage:
|
|
644
744
|
dotctl create [dir] [--name <name>] [--template <starter|showcase>]
|
|
@@ -650,6 +750,8 @@ const USAGE = `Usage:
|
|
|
650
750
|
view.dml, state.ts and controller.ts
|
|
651
751
|
dotctl build [root] [options] Build the minified bundles the host app runs
|
|
652
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
|
|
653
755
|
dotctl keys show Show the public key and key ID of this computer's
|
|
654
756
|
developer key, which signs the links \`dev --device\`
|
|
655
757
|
shows, for Dash to open
|
|
@@ -659,8 +761,8 @@ const USAGE = `Usage:
|
|
|
659
761
|
Options:
|
|
660
762
|
--out-dir <dir> Output directory (default: <root>/dist)
|
|
661
763
|
--conditions <list> Extra export conditions, comma separated
|
|
662
|
-
--port <port> Simulator port for \`dev\`; the next free one is used
|
|
663
|
-
(default: ${DEFAULT_PORT})
|
|
764
|
+
--port <port> Simulator port for \`dev\` and \`preview\`; the next free one is used
|
|
765
|
+
if taken (default: ${DEFAULT_PORT})
|
|
664
766
|
--device With \`dev\`, also serve the dot to the Dot example apps on phones on
|
|
665
767
|
the local network, through a link and QR code; they reload on each build
|
|
666
768
|
-h, --help Show this message`;
|
|
@@ -685,14 +787,14 @@ async function main(argv) {
|
|
|
685
787
|
});
|
|
686
788
|
const [command, target, pagePath] = positionals;
|
|
687
789
|
if (command === "lsp" && !values.help) {
|
|
688
|
-
const { serveStdio } = await import("./server-
|
|
790
|
+
const { serveStdio } = await import("./server-BfPAnsSf.js");
|
|
689
791
|
serveStdio();
|
|
690
792
|
return new Promise(() => {});
|
|
691
793
|
}
|
|
692
794
|
if (command === "keys" && !values.help) return keys(target);
|
|
693
795
|
if (command === "create" && target === "page" && !values.help) return addPage(pagePath);
|
|
694
796
|
if (command === "create" && !values.help) return createApp(target, values.name, values.template, values.pm);
|
|
695
|
-
if (values.help || command !== "build" && command !== "dev") {
|
|
797
|
+
if (values.help || command !== "build" && command !== "dev" && command !== "preview") {
|
|
696
798
|
console.log(USAGE);
|
|
697
799
|
return values.help ? 0 : 1;
|
|
698
800
|
}
|
|
@@ -714,6 +816,19 @@ async function main(argv) {
|
|
|
714
816
|
await stop();
|
|
715
817
|
return 0;
|
|
716
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
|
+
}
|
|
717
832
|
const started = performance.now();
|
|
718
833
|
const result = await build(options);
|
|
719
834
|
for (const file of result.files.filter((file) => !file.endsWith(".map"))) console.log(` ${relative(process.cwd(), file)}`);
|
|
@@ -757,7 +872,7 @@ async function createApp(dir, name, templateFlag, packageManagerFlag) {
|
|
|
757
872
|
console.error(`--pm must be one of ${PACKAGE_MANAGERS.join(", ")}`);
|
|
758
873
|
return 1;
|
|
759
874
|
}
|
|
760
|
-
name ??= await ask("Dot name
|
|
875
|
+
name ??= await ask("Dot name", dir ? toDisplayName(dir) : "Dot");
|
|
761
876
|
if (!name) {
|
|
762
877
|
console.error("A dot needs a name: dotctl create [dir] --name \"My Dot\"");
|
|
763
878
|
return 1;
|
|
@@ -772,7 +887,8 @@ async function createApp(dir, name, templateFlag, packageManagerFlag) {
|
|
|
772
887
|
console.log(`\nCreated ${name} in ${path}`);
|
|
773
888
|
if (workspace) console.log("It is inside the Dot repository, so it uses the workspace packages.");
|
|
774
889
|
let packageManager = workspace ? "pnpm" : packageManagerFlag ?? launchedBy();
|
|
775
|
-
|
|
890
|
+
console.log();
|
|
891
|
+
if (await confirm("Install and start it now?", true)) {
|
|
776
892
|
if (!workspace && !packageManagerFlag) packageManager = await choosePackageManager(packageManager);
|
|
777
893
|
if (await run(packageManager, ["install"], root) === 0) return run(packageManager, ["run", "dev"], root);
|
|
778
894
|
console.error(`\n${packageManager} install failed.`);
|
|
@@ -791,53 +907,24 @@ function run(command, args, cwd) {
|
|
|
791
907
|
child.on("exit", (code) => resolvePromise(code ?? 1));
|
|
792
908
|
});
|
|
793
909
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
return readAnswer(`${question}${fallback ? ` (${fallback})` : ""}`, fallback);
|
|
801
|
-
}
|
|
802
|
-
async function readAnswer(prompt, fallback) {
|
|
803
|
-
if (!process.stdin.isTTY) return fallback;
|
|
804
|
-
const readline = createInterface({
|
|
805
|
-
input: process.stdin,
|
|
806
|
-
output: process.stdout
|
|
807
|
-
});
|
|
808
|
-
try {
|
|
809
|
-
return (await readline.question(`${prompt} `)).trim() || fallback;
|
|
810
|
-
} catch (error) {
|
|
811
|
-
if (error.name === "AbortError") return;
|
|
812
|
-
throw error;
|
|
813
|
-
} finally {
|
|
814
|
-
readline.close();
|
|
815
|
-
}
|
|
816
|
-
}
|
|
817
|
-
async function chooseTemplate() {
|
|
818
|
-
if (!process.stdin.isTTY) return "starter";
|
|
819
|
-
console.log("\nTemplates:\n starter one page to build on\n showcase a page for each feature, to read");
|
|
820
|
-
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");
|
|
821
916
|
}
|
|
822
917
|
async function choosePackageManager(suggested) {
|
|
823
918
|
const installed = installedManagers();
|
|
824
919
|
if (installed.length < 2) return installed[0] ?? suggested;
|
|
825
|
-
|
|
826
|
-
}
|
|
827
|
-
async function chooseOne(question, options, fallback) {
|
|
828
|
-
while (true) {
|
|
829
|
-
const answer = await ask(`${question} ${options.join(" / ")}`, fallback);
|
|
830
|
-
if (answer === void 0) return fallback;
|
|
831
|
-
const chosen = options.find((option) => option === answer);
|
|
832
|
-
if (chosen) return chosen;
|
|
833
|
-
console.log(`Choose one of ${options.join(", ")}.`);
|
|
834
|
-
}
|
|
920
|
+
const fallback = installed.includes(suggested) ? suggested : installed[0];
|
|
921
|
+
return select("Package manager?", installed.map((manager) => ({ value: manager })), fallback);
|
|
835
922
|
}
|
|
836
923
|
main(process.argv.slice(2)).then((code) => process.exit(code), (error) => {
|
|
837
924
|
console.error(`error: ${describeError(error)}`);
|
|
838
925
|
process.exit(1);
|
|
839
926
|
});
|
|
840
927
|
//#endregion
|
|
841
|
-
export {};
|
|
928
|
+
export { findDotRoot as t };
|
|
842
929
|
|
|
843
930
|
//# sourceMappingURL=cli.js.map
|