@rshono/create 1.0.0-rc.2 → 1.0.0-rc.21
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/LICENSE +21 -0
- package/README.md +94 -61
- package/bin/create-rshono.mjs +9 -7
- package/dist/api.mjs +297 -254
- package/dist/cli.mjs +588 -518
- package/package.json +12 -13
- package/templates/base/AGENTS.md +5 -0
- package/templates/base/CLAUDE.md +1 -0
- package/templates/base/README.md +11 -9
- package/templates/base/_env +1 -4
- package/templates/base/_gitignore +1 -0
- package/templates/base/public/favicon.svg +2 -1
- package/templates/base/rshono.config.ts +0 -30
- package/templates/base/src/components/404.tsx +0 -1
- package/templates/base/src/components/500.tsx +0 -6
- package/templates/base/src/components/home.tsx +6 -23
- package/templates/base/src/components/layout.tsx +4 -11
- package/templates/base/src/routes.ts +1 -26
- package/templates/base/src/server.ts +20 -35
- package/templates/base/src/styles.css +1 -64
- package/templates/biome/biome.json +2 -1
- package/templates/biome-tailwind/biome.json +1 -1
- package/templates/eslint/eslint.config.mjs +16 -16
- package/templates/oxfmt/_oxfmtrc.json +1 -1
- package/templates/tailwind/postcss.config.mjs +0 -4
- package/templates/tailwind/rshono.config.ts +1 -37
- package/templates/tailwind/src/components/home.tsx +6 -23
- package/templates/tailwind/src/components/layout.tsx +4 -11
- package/templates/tailwind/src/styles.css +0 -25
- package/templates/base/src/actions.ts +0 -22
- package/templates/base/src/components/greet-form.tsx +0 -27
- package/templates/base/src/lib/env.ts +0 -26
package/dist/cli.mjs
CHANGED
|
@@ -482,7 +482,7 @@ function main_wrapAnsi(string, columns, options) {
|
|
|
482
482
|
var src = __webpack_require__(347);
|
|
483
483
|
;// CONCATENATED MODULE: external "node:tty"
|
|
484
484
|
|
|
485
|
-
;// CONCATENATED MODULE: ../../node_modules/.pnpm/@clack+core@1.
|
|
485
|
+
;// CONCATENATED MODULE: ../../node_modules/.pnpm/@clack+core@1.5.1/node_modules/@clack/core/dist/index.mjs
|
|
486
486
|
|
|
487
487
|
|
|
488
488
|
|
|
@@ -548,6 +548,7 @@ const dist_settings = {
|
|
|
548
548
|
error: "Something went wrong"
|
|
549
549
|
},
|
|
550
550
|
withGuide: true,
|
|
551
|
+
accessible: void 0,
|
|
551
552
|
date: {
|
|
552
553
|
monthNames: [...dist_t],
|
|
553
554
|
messages: {
|
|
@@ -572,11 +573,17 @@ function updateSettings(n) {
|
|
|
572
573
|
const e = n.messages;
|
|
573
574
|
e.cancel !== void 0 && (dist_settings.messages.cancel = e.cancel), e.error !== void 0 && (dist_settings.messages.error = e.error);
|
|
574
575
|
}
|
|
575
|
-
if (n.withGuide !== void 0 && (dist_settings.withGuide = n.withGuide !== false), n.date !== void 0) {
|
|
576
|
+
if (n.withGuide !== void 0 && (dist_settings.withGuide = n.withGuide !== false), n.accessible !== void 0 && (dist_settings.accessible = n.accessible === true), n.date !== void 0) {
|
|
576
577
|
const e = n.date;
|
|
577
578
|
e.monthNames !== void 0 && (dist_settings.date.monthNames = [...e.monthNames]), e.messages !== void 0 && (e.messages.required !== void 0 && (dist_settings.date.messages.required = e.messages.required), e.messages.invalidMonth !== void 0 && (dist_settings.date.messages.invalidMonth = e.messages.invalidMonth), e.messages.invalidDay !== void 0 && (dist_settings.date.messages.invalidDay = e.messages.invalidDay), e.messages.afterMin !== void 0 && (dist_settings.date.messages.afterMin = e.messages.afterMin), e.messages.beforeMax !== void 0 && (dist_settings.date.messages.beforeMax = e.messages.beforeMax));
|
|
578
579
|
}
|
|
579
580
|
}
|
|
581
|
+
function isAccessible(n) {
|
|
582
|
+
if (n !== void 0) return n;
|
|
583
|
+
if (dist_settings.accessible !== void 0) return dist_settings.accessible;
|
|
584
|
+
const e = process.env.ACCESSIBLE;
|
|
585
|
+
return e !== void 0 && e !== "" && e !== "0" && e !== "false";
|
|
586
|
+
}
|
|
580
587
|
function isActionKey(n, e) {
|
|
581
588
|
if (typeof n == "string")
|
|
582
589
|
return dist_settings.aliases.get(n) === e;
|
|
@@ -614,7 +621,7 @@ function dist_block({
|
|
|
614
621
|
input: e = stdin,
|
|
615
622
|
output: r = stdout,
|
|
616
623
|
overwrite: o = true,
|
|
617
|
-
hideCursor:
|
|
624
|
+
hideCursor: n = true
|
|
618
625
|
} = {}) {
|
|
619
626
|
const s = l.createInterface({
|
|
620
627
|
input: e,
|
|
@@ -623,51 +630,47 @@ function dist_block({
|
|
|
623
630
|
tabSize: 1
|
|
624
631
|
});
|
|
625
632
|
l.emitKeypressEvents(e, s), e instanceof ReadStream && e.isTTY && e.setRawMode(true);
|
|
626
|
-
const
|
|
633
|
+
const t = (f, { name: a, sequence: w }) => {
|
|
627
634
|
const c = String(f);
|
|
628
|
-
if (isActionKey([c, a,
|
|
629
|
-
|
|
635
|
+
if (isActionKey([c, a, w], "cancel")) {
|
|
636
|
+
n && r.write(cursor.show), process.exit(0);
|
|
630
637
|
return;
|
|
631
638
|
}
|
|
632
639
|
if (!o) return;
|
|
633
640
|
const i = a === "return" ? 0 : -1, m = a === "return" ? -1 : 0;
|
|
634
641
|
l.moveCursor(r, i, m, () => {
|
|
635
642
|
l.clearLine(r, 1, () => {
|
|
636
|
-
e.once("keypress",
|
|
643
|
+
e.once("keypress", t);
|
|
637
644
|
});
|
|
638
645
|
});
|
|
639
646
|
};
|
|
640
|
-
return
|
|
641
|
-
e.off("keypress",
|
|
647
|
+
return n && r.write(cursor.hide), e.once("keypress", t), () => {
|
|
648
|
+
e.off("keypress", t), n && r.write(cursor.show), e instanceof ReadStream && e.isTTY && !dist_R && e.setRawMode(false), s.terminal = false, s.close();
|
|
642
649
|
};
|
|
643
650
|
}
|
|
644
651
|
const dist_getColumns = (e) => "columns" in e && typeof e.columns == "number" ? e.columns : 80, getRows = (e) => "rows" in e && typeof e.rows == "number" ? e.rows : 20;
|
|
645
|
-
function dist_wrapTextWithPrefix(e, r, o,
|
|
652
|
+
function dist_wrapTextWithPrefix(e, r, o, n = o, s = o, t) {
|
|
646
653
|
const f = dist_getColumns(e ?? external_node_process_stdout);
|
|
647
654
|
return main_wrapAnsi(r, f - o.length, {
|
|
648
655
|
hard: true,
|
|
649
656
|
trim: false
|
|
650
657
|
}).split(`
|
|
651
658
|
`).map((c, i, m) => {
|
|
652
|
-
const d =
|
|
653
|
-
return i === 0 ? `${
|
|
659
|
+
const d = t ? t(c, i) : c;
|
|
660
|
+
return i === 0 ? `${n}${d}` : i === m.length - 1 ? `${s}${d}` : `${o}${d}`;
|
|
654
661
|
}).join(`
|
|
655
662
|
`);
|
|
656
663
|
}
|
|
657
664
|
|
|
658
|
-
function dist_runValidation(e,
|
|
665
|
+
function dist_runValidation(e, a) {
|
|
659
666
|
if ("~standard" in e) {
|
|
660
|
-
const
|
|
661
|
-
|
|
662
|
-
throw new TypeError(
|
|
663
|
-
"Schema validation must be synchronous. Update `validate()` and remove any asynchronous logic."
|
|
664
|
-
);
|
|
665
|
-
return a.issues?.at(0)?.message;
|
|
667
|
+
const n = e["~standard"].validate(a);
|
|
668
|
+
return n instanceof Promise ? n.then((r) => r.issues?.at(0)?.message) : n.issues?.at(0)?.message;
|
|
666
669
|
}
|
|
667
|
-
return e(
|
|
670
|
+
return e(a);
|
|
668
671
|
}
|
|
669
672
|
|
|
670
|
-
class
|
|
673
|
+
class dist_y {
|
|
671
674
|
input;
|
|
672
675
|
output;
|
|
673
676
|
_abortSignal;
|
|
@@ -682,9 +685,17 @@ class dist_V {
|
|
|
682
685
|
error = "";
|
|
683
686
|
value;
|
|
684
687
|
userInput = "";
|
|
688
|
+
/**
|
|
689
|
+
* Whether accessible (static, screen-reader friendly) output is enabled for
|
|
690
|
+
* this prompt, resolved from the `accessible` option, the global setting,
|
|
691
|
+
* and the `ACCESSIBLE` env var.
|
|
692
|
+
*/
|
|
693
|
+
get accessible() {
|
|
694
|
+
return isAccessible(this.opts.accessible);
|
|
695
|
+
}
|
|
685
696
|
constructor(t, e = true) {
|
|
686
|
-
const { input: i = external_node_process_stdin, output:
|
|
687
|
-
this.opts = o, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render =
|
|
697
|
+
const { input: i = external_node_process_stdin, output: s = external_node_process_stdout, render: r, signal: n, ...o } = t;
|
|
698
|
+
this.opts = o, this.onKeypress = this.onKeypress.bind(this), this.close = this.close.bind(this), this.render = this.render.bind(this), this._render = r.bind(this), this._track = e, this._abortSignal = n, this.input = i, this.output = s;
|
|
688
699
|
}
|
|
689
700
|
/**
|
|
690
701
|
* Unsubscribe all listeners
|
|
@@ -722,11 +733,11 @@ class dist_V {
|
|
|
722
733
|
* @param data - The data to pass to the callback
|
|
723
734
|
*/
|
|
724
735
|
emit(t, ...e) {
|
|
725
|
-
const i = this._subscribers.get(t) ?? [],
|
|
726
|
-
for (const
|
|
727
|
-
|
|
728
|
-
for (const
|
|
729
|
-
|
|
736
|
+
const i = this._subscribers.get(t) ?? [], s = [];
|
|
737
|
+
for (const r of i)
|
|
738
|
+
r.cb(...e), r.once && s.push(() => i.splice(i.indexOf(r), 1));
|
|
739
|
+
for (const r of s)
|
|
740
|
+
r();
|
|
730
741
|
}
|
|
731
742
|
prompt() {
|
|
732
743
|
return new Promise((t) => {
|
|
@@ -769,15 +780,18 @@ class dist_V {
|
|
|
769
780
|
_clearUserInput() {
|
|
770
781
|
this.rl?.write(null, { ctrl: true, name: "u" }), this._setUserInput("");
|
|
771
782
|
}
|
|
772
|
-
onKeypress(t, e) {
|
|
773
|
-
if (this.
|
|
774
|
-
if (this.
|
|
775
|
-
|
|
776
|
-
|
|
783
|
+
async onKeypress(t, e) {
|
|
784
|
+
if (this.state !== "validating") {
|
|
785
|
+
if (this._track && e.name !== "return" && (e.name && this._isActionKey(t, e) && this.rl?.write(null, { ctrl: true, name: "h" }), this._cursor = this.rl?.cursor ?? 0, this._setUserInput(this.rl?.line)), this.state === "error" && (this.state = "active"), e?.name && (!this._track && dist_settings.aliases.has(e.name) && this.emit("cursor", dist_settings.aliases.get(e.name)), dist_settings.actions.has(e.name) && this.emit("cursor", e.name)), t && (t.toLowerCase() === "y" || t.toLowerCase() === "n") && this.emit("confirm", t.toLowerCase() === "y"), this.emit("key", t, e), e?.name === "return" && this._shouldSubmit(t, e)) {
|
|
786
|
+
if (this.opts.validate) {
|
|
787
|
+
const i = dist_runValidation(this.opts.validate, this.value);
|
|
788
|
+
let s;
|
|
789
|
+
i instanceof Promise ? (this.state = "validating", this.render(), s = await i) : s = i, s && (this.error = s instanceof Error ? s.message : s, this.state = "error", this.rl?.write(this.userInput));
|
|
790
|
+
}
|
|
791
|
+
this.state !== "error" && (this.state = "submit");
|
|
777
792
|
}
|
|
778
|
-
this.state
|
|
793
|
+
isActionKey([t, e?.name, e?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
|
|
779
794
|
}
|
|
780
|
-
isActionKey([t, e?.name, e?.sequence], "cancel") && (this.state = "cancel"), (this.state === "submit" || this.state === "cancel") && this.emit("finalize"), this.render(), (this.state === "submit" || this.state === "cancel") && this.close();
|
|
781
795
|
}
|
|
782
796
|
close() {
|
|
783
797
|
this.input.unpipe(), this.input.removeListener("keypress", this.onKeypress), this.output.write(`
|
|
@@ -799,28 +813,28 @@ class dist_V {
|
|
|
799
813
|
else {
|
|
800
814
|
const e = diffLines(this._prevFrame, t), i = getRows(this.output);
|
|
801
815
|
if (this.restoreCursor(), e) {
|
|
802
|
-
const
|
|
803
|
-
let
|
|
804
|
-
if (
|
|
816
|
+
const s = Math.max(0, e.numLinesAfter - i), r = Math.max(0, e.numLinesBefore - i);
|
|
817
|
+
let n = e.lines.find((o) => o >= s);
|
|
818
|
+
if (n === void 0) {
|
|
805
819
|
this._prevFrame = t;
|
|
806
820
|
return;
|
|
807
821
|
}
|
|
808
822
|
if (e.lines.length === 1) {
|
|
809
|
-
this.output.write(src.cursor.move(0,
|
|
823
|
+
this.output.write(src.cursor.move(0, n - r)), this.output.write(src.erase.lines(1));
|
|
810
824
|
const o = t.split(`
|
|
811
825
|
`);
|
|
812
|
-
this.output.write(o[
|
|
826
|
+
this.output.write(o[n]), this._prevFrame = t, this.output.write(src.cursor.move(0, o.length - n - 1));
|
|
813
827
|
return;
|
|
814
828
|
} else if (e.lines.length > 1) {
|
|
815
|
-
if (
|
|
816
|
-
|
|
829
|
+
if (s < r)
|
|
830
|
+
n = s;
|
|
817
831
|
else {
|
|
818
|
-
const h =
|
|
832
|
+
const h = n - r;
|
|
819
833
|
h > 0 && this.output.write(src.cursor.move(0, h));
|
|
820
834
|
}
|
|
821
835
|
this.output.write(src.erase.down());
|
|
822
836
|
const f = t.split(`
|
|
823
|
-
`).slice(
|
|
837
|
+
`).slice(n);
|
|
824
838
|
this.output.write(f.join(`
|
|
825
839
|
`)), this._prevFrame = t;
|
|
826
840
|
return;
|
|
@@ -839,14 +853,14 @@ function p$1(l, e) {
|
|
|
839
853
|
const i = e.findIndex((s) => s.value === l);
|
|
840
854
|
return i !== -1 ? i : 0;
|
|
841
855
|
}
|
|
842
|
-
function
|
|
856
|
+
function dist_m(l, e) {
|
|
843
857
|
return (e.label ?? String(e.value)).toLowerCase().includes(l.toLowerCase());
|
|
844
858
|
}
|
|
845
|
-
function
|
|
859
|
+
function dist_g(l, e) {
|
|
846
860
|
if (e)
|
|
847
861
|
return l ? e : e[0];
|
|
848
862
|
}
|
|
849
|
-
let T$1 = class T extends
|
|
863
|
+
let T$1 = class T extends dist_y {
|
|
850
864
|
filteredOptions;
|
|
851
865
|
multiple;
|
|
852
866
|
isNavigating = false;
|
|
@@ -857,44 +871,50 @@ let T$1 = class T extends (/* unused pure expression or super */ null && (dist_V
|
|
|
857
871
|
#t;
|
|
858
872
|
#i;
|
|
859
873
|
#n;
|
|
874
|
+
#l;
|
|
860
875
|
get cursor() {
|
|
861
876
|
return this.#e;
|
|
862
877
|
}
|
|
863
878
|
get userInputWithCursor() {
|
|
864
879
|
if (!this.userInput)
|
|
865
|
-
return
|
|
880
|
+
return external_node_util_styleText(["inverse", "hidden"], "_");
|
|
866
881
|
if (this._cursor >= this.userInput.length)
|
|
867
882
|
return `${this.userInput}\u2588`;
|
|
868
883
|
const e = this.userInput.slice(0, this.cursor), t = this.userInput.slice(this.cursor, this.cursor + 1), i = this.userInput.slice(this.cursor + 1);
|
|
869
|
-
return `${e}${
|
|
884
|
+
return `${e}${external_node_util_styleText("inverse", t)}${i}`;
|
|
870
885
|
}
|
|
871
886
|
get options() {
|
|
872
887
|
return typeof this.#i == "function" ? this.#i() : this.#i;
|
|
873
888
|
}
|
|
874
889
|
constructor(e) {
|
|
875
|
-
super(e), this.#i = e.options, this.#n = e.placeholder;
|
|
890
|
+
super(e), this.#i = e.options, this.#n = e.placeholder, this.#l = e.completeOnTab === true;
|
|
876
891
|
const t = this.options;
|
|
877
|
-
this.filteredOptions = [...t], this.multiple = e.multiple === true, this.#t = typeof e.options == "function" ? e.filter : e.filter ??
|
|
892
|
+
this.filteredOptions = [...t], this.multiple = e.multiple === true, this.#t = typeof e.options == "function" ? e.filter : e.filter ?? dist_m;
|
|
878
893
|
let i;
|
|
879
894
|
if (e.initialValue && Array.isArray(e.initialValue) ? this.multiple ? i = e.initialValue : i = e.initialValue.slice(0, 1) : !this.multiple && this.options.length > 0 && (i = [this.options[0]?.value]), i)
|
|
880
895
|
for (const s of i) {
|
|
881
|
-
const n = t.findIndex((
|
|
896
|
+
const n = t.findIndex((r) => r.value === s);
|
|
882
897
|
n !== -1 && (this.toggleSelected(s), this.#e = n);
|
|
883
898
|
}
|
|
884
|
-
this.focusedValue = this.options[this.#e]?.value, this.on("key", (s, n) => this.#
|
|
899
|
+
this.focusedValue = this.options[this.#e]?.value, this.on("key", (s, n) => this.#u(s, n)), this.on("userInput", (s) => this.#o(s));
|
|
885
900
|
}
|
|
886
901
|
_isActionKey(e, t) {
|
|
887
902
|
return e === " " || this.multiple && this.isNavigating && t.name === "space" && e !== void 0 && e !== "";
|
|
888
903
|
}
|
|
889
|
-
#
|
|
890
|
-
const i = t.name === "up", s = t.name === "down", n = t.name === "return",
|
|
891
|
-
(
|
|
904
|
+
#u(e, t) {
|
|
905
|
+
const i = t.name === "up", s = t.name === "down", n = t.name === "return", r = this.userInput === "" || this.userInput === " ", u = this.#n, d = this.options, c = u !== void 0 && u !== "" && d.some(
|
|
906
|
+
(o) => !o.disabled && (this.#t ? this.#t(u, o) : true)
|
|
892
907
|
);
|
|
893
|
-
if (t.name === "tab" &&
|
|
908
|
+
if (t.name === "tab" && r && c) {
|
|
894
909
|
this.userInput === " " && this._clearUserInput(), this._setUserInput(u, true), this.isNavigating = false;
|
|
895
910
|
return;
|
|
896
911
|
}
|
|
897
|
-
|
|
912
|
+
if (t.name === "tab" && this.#l && !this.multiple && this.focusedValue !== void 0) {
|
|
913
|
+
const o = String(this.focusedValue);
|
|
914
|
+
this._clearUserInput(), this._setUserInput(o, true), this.isNavigating = false;
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
i || s ? (this.#e = findCursor(this.#e, i ? -1 : 1, this.filteredOptions), this.focusedValue = this.filteredOptions[this.#e]?.value, this.multiple || (this.selectedValues = [this.focusedValue]), this.isNavigating = true) : n ? this.value = dist_g(this.multiple, this.selectedValues) : this.multiple ? this.focusedValue !== void 0 && (t.name === "tab" || this.isNavigating && t.name === "space") ? this.toggleSelected(this.focusedValue) : this.isNavigating = false : (this.focusedValue && (this.selectedValues = [this.focusedValue]), this.isNavigating = false);
|
|
898
918
|
}
|
|
899
919
|
deselectAll() {
|
|
900
920
|
this.selectedValues = [];
|
|
@@ -902,7 +922,7 @@ let T$1 = class T extends (/* unused pure expression or super */ null && (dist_V
|
|
|
902
922
|
toggleSelected(e) {
|
|
903
923
|
this.filteredOptions.length !== 0 && (this.multiple ? this.selectedValues.includes(e) ? this.selectedValues = this.selectedValues.filter((t) => t !== e) : this.selectedValues = [...this.selectedValues, e] : this.selectedValues = [e]);
|
|
904
924
|
}
|
|
905
|
-
#
|
|
925
|
+
#o(e) {
|
|
906
926
|
if (e !== this.#s) {
|
|
907
927
|
this.#s = e;
|
|
908
928
|
const t = this.options;
|
|
@@ -915,7 +935,7 @@ let T$1 = class T extends (/* unused pure expression or super */ null && (dist_V
|
|
|
915
935
|
}
|
|
916
936
|
};
|
|
917
937
|
|
|
918
|
-
class dist_r extends
|
|
938
|
+
class dist_r extends dist_y {
|
|
919
939
|
get cursor() {
|
|
920
940
|
return this.value ? 0 : 1;
|
|
921
941
|
}
|
|
@@ -994,7 +1014,7 @@ function dist_T(r, t, i, s) {
|
|
|
994
1014
|
max: e && t.year === e.year && t.month === e.month ? e.day : dist_c(t.year, t.month)
|
|
995
1015
|
};
|
|
996
1016
|
}
|
|
997
|
-
class U extends
|
|
1017
|
+
class U extends dist_y {
|
|
998
1018
|
#i;
|
|
999
1019
|
#o;
|
|
1000
1020
|
#t;
|
|
@@ -1160,7 +1180,7 @@ class U extends dist_V {
|
|
|
1160
1180
|
}
|
|
1161
1181
|
}
|
|
1162
1182
|
|
|
1163
|
-
let u$2 = class u extends
|
|
1183
|
+
let u$2 = class u extends dist_y {
|
|
1164
1184
|
options;
|
|
1165
1185
|
cursor = 0;
|
|
1166
1186
|
#t;
|
|
@@ -1218,7 +1238,7 @@ let u$2 = class u extends (/* unused pure expression or super */ null && (dist_V
|
|
|
1218
1238
|
};
|
|
1219
1239
|
|
|
1220
1240
|
const dist_o = /* @__PURE__ */ new Set(["up", "down", "left", "right"]);
|
|
1221
|
-
class dist_h extends
|
|
1241
|
+
class dist_h extends dist_y {
|
|
1222
1242
|
#t = false;
|
|
1223
1243
|
#s;
|
|
1224
1244
|
focused = "editor";
|
|
@@ -1313,7 +1333,7 @@ ${i}` : `${s}${external_node_util_styleText("inverse", r)}${i}`;
|
|
|
1313
1333
|
}
|
|
1314
1334
|
}
|
|
1315
1335
|
|
|
1316
|
-
class dist_a extends
|
|
1336
|
+
class dist_a extends dist_y {
|
|
1317
1337
|
options;
|
|
1318
1338
|
cursor = 0;
|
|
1319
1339
|
get _value() {
|
|
@@ -1364,7 +1384,7 @@ class dist_a extends dist_V {
|
|
|
1364
1384
|
}
|
|
1365
1385
|
}
|
|
1366
1386
|
|
|
1367
|
-
let u$1 = class u extends
|
|
1387
|
+
let u$1 = class u extends dist_y {
|
|
1368
1388
|
_mask = "\u2022";
|
|
1369
1389
|
get cursor() {
|
|
1370
1390
|
return this._cursor;
|
|
@@ -1377,9 +1397,9 @@ let u$1 = class u extends (/* unused pure expression or super */ null && (dist_V
|
|
|
1377
1397
|
return this.masked;
|
|
1378
1398
|
const t = this.userInput;
|
|
1379
1399
|
if (this.cursor >= t.length)
|
|
1380
|
-
return `${this.masked}${
|
|
1400
|
+
return `${this.masked}${external_node_util_styleText(["inverse", "hidden"], "_")}`;
|
|
1381
1401
|
const s = this.masked, r = s.slice(0, this.cursor), i = s.slice(this.cursor, this.cursor + 1), o = s.slice(this.cursor + 1);
|
|
1382
|
-
return `${r}${
|
|
1402
|
+
return `${r}${external_node_util_styleText("inverse", i)}${o}`;
|
|
1383
1403
|
}
|
|
1384
1404
|
clear() {
|
|
1385
1405
|
this._clearUserInput();
|
|
@@ -1393,7 +1413,7 @@ let u$1 = class u extends (/* unused pure expression or super */ null && (dist_V
|
|
|
1393
1413
|
}
|
|
1394
1414
|
};
|
|
1395
1415
|
|
|
1396
|
-
let n$1 = class n extends
|
|
1416
|
+
let n$1 = class n extends dist_y {
|
|
1397
1417
|
options;
|
|
1398
1418
|
cursor = 0;
|
|
1399
1419
|
get _selectedValue() {
|
|
@@ -1422,7 +1442,7 @@ let n$1 = class n extends dist_V {
|
|
|
1422
1442
|
}
|
|
1423
1443
|
};
|
|
1424
1444
|
|
|
1425
|
-
class dist_u extends
|
|
1445
|
+
class dist_u extends dist_y {
|
|
1426
1446
|
options;
|
|
1427
1447
|
cursor = 0;
|
|
1428
1448
|
constructor(t) {
|
|
@@ -1440,7 +1460,7 @@ class dist_u extends dist_V {
|
|
|
1440
1460
|
}
|
|
1441
1461
|
}
|
|
1442
1462
|
|
|
1443
|
-
class dist_n extends
|
|
1463
|
+
class dist_n extends dist_y {
|
|
1444
1464
|
get userInputWithCursor() {
|
|
1445
1465
|
if (this.state === "submit")
|
|
1446
1466
|
return this.userInput;
|
|
@@ -1471,7 +1491,7 @@ class dist_n extends dist_V {
|
|
|
1471
1491
|
|
|
1472
1492
|
;// CONCATENATED MODULE: external "node:path"
|
|
1473
1493
|
|
|
1474
|
-
;// CONCATENATED MODULE: ../../node_modules/.pnpm/@clack+prompts@1.
|
|
1494
|
+
;// CONCATENATED MODULE: ../../node_modules/.pnpm/@clack+prompts@1.8.1/node_modules/@clack/prompts/dist/index.mjs
|
|
1475
1495
|
|
|
1476
1496
|
|
|
1477
1497
|
|
|
@@ -1509,6 +1529,8 @@ const unicode = isUnicodeSupported(), isCI = () => process.env.CI === "true", is
|
|
|
1509
1529
|
return external_node_util_styleText("yellow", S_STEP_ERROR);
|
|
1510
1530
|
case "submit":
|
|
1511
1531
|
return external_node_util_styleText("green", S_STEP_SUBMIT);
|
|
1532
|
+
case "validating":
|
|
1533
|
+
return external_node_util_styleText("dim", S_STEP_ACTIVE);
|
|
1512
1534
|
}
|
|
1513
1535
|
}, symbolBar = (o) => {
|
|
1514
1536
|
switch (o) {
|
|
@@ -1595,16 +1617,16 @@ const limitOptions = ({
|
|
|
1595
1617
|
return c && x.push(M), x;
|
|
1596
1618
|
};
|
|
1597
1619
|
|
|
1598
|
-
function
|
|
1620
|
+
function dist_E(t) {
|
|
1599
1621
|
return t.label ?? String(t.value ?? "");
|
|
1600
1622
|
}
|
|
1601
|
-
function
|
|
1623
|
+
function prompts_dist_P(t, c) {
|
|
1602
1624
|
if (!t)
|
|
1603
1625
|
return true;
|
|
1604
|
-
const n = (c.label ?? String(c.value ?? "")).toLowerCase(), i = (c.hint ?? "").toLowerCase(),
|
|
1605
|
-
return n.includes(o) || i.includes(o) ||
|
|
1626
|
+
const n = (c.label ?? String(c.value ?? "")).toLowerCase(), i = (c.hint ?? "").toLowerCase(), r = String(c.value).toLowerCase(), o = t.toLowerCase();
|
|
1627
|
+
return n.includes(o) || i.includes(o) || r.includes(o);
|
|
1606
1628
|
}
|
|
1607
|
-
function
|
|
1629
|
+
function dist_j(t, c) {
|
|
1608
1630
|
const n = [];
|
|
1609
1631
|
for (const i of c)
|
|
1610
1632
|
t.includes(i.value) && n.push(i);
|
|
@@ -1615,14 +1637,15 @@ const autocomplete = (t) => new AutocompletePrompt({
|
|
|
1615
1637
|
initialValue: t.initialValue ? [t.initialValue] : void 0,
|
|
1616
1638
|
initialUserInput: t.initialUserInput,
|
|
1617
1639
|
placeholder: t.placeholder,
|
|
1618
|
-
|
|
1640
|
+
completeOnTab: t.completeOnTab,
|
|
1641
|
+
filter: t.filter ?? ((n, i) => prompts_dist_P(n, i)),
|
|
1619
1642
|
signal: t.signal,
|
|
1620
1643
|
input: t.input,
|
|
1621
1644
|
output: t.output,
|
|
1622
1645
|
validate: t.validate,
|
|
1623
1646
|
render() {
|
|
1624
|
-
const n = t.withGuide ?? settings.withGuide, i = n ? [`${styleText("gray", S_BAR)}`, `${symbol(this.state)} ${t.message}`] : [`${symbol(this.state)} ${t.message}`],
|
|
1625
|
-
const a =
|
|
1647
|
+
const n = t.withGuide ?? settings.withGuide, i = n ? [`${styleText("gray", S_BAR)}`, `${symbol(this.state)} ${t.message}`] : [`${symbol(this.state)} ${t.message}`], r = this.userInput, o = this.options, m = t.placeholder, p = r === "" && m !== void 0, $ = (l, s) => {
|
|
1648
|
+
const a = dist_E(l), u = l.hint && l.value === this.focusedValue ? styleText("dim", ` (${l.hint})`) : "";
|
|
1626
1649
|
switch (s) {
|
|
1627
1650
|
case "active":
|
|
1628
1651
|
return `${styleText("green", S_RADIO_ACTIVE)} ${a}${u}`;
|
|
@@ -1634,39 +1657,40 @@ const autocomplete = (t) => new AutocompletePrompt({
|
|
|
1634
1657
|
};
|
|
1635
1658
|
switch (this.state) {
|
|
1636
1659
|
case "submit": {
|
|
1637
|
-
const
|
|
1660
|
+
const l = dist_j(this.selectedValues, o), s = l.length > 0 ? ` ${styleText("dim", l.map(dist_E).join(", "))}` : "", a = n ? styleText("gray", S_BAR) : "";
|
|
1638
1661
|
return `${i.join(`
|
|
1639
1662
|
`)}
|
|
1640
1663
|
${a}${s}`;
|
|
1641
1664
|
}
|
|
1642
1665
|
case "cancel": {
|
|
1643
|
-
const
|
|
1666
|
+
const l = r ? ` ${styleText(["strikethrough", "dim"], r)}` : "", s = n ? styleText("gray", S_BAR) : "";
|
|
1644
1667
|
return `${i.join(`
|
|
1645
1668
|
`)}
|
|
1646
|
-
${s}${
|
|
1669
|
+
${s}${l}`;
|
|
1647
1670
|
}
|
|
1648
1671
|
default: {
|
|
1649
|
-
const
|
|
1672
|
+
const l = this.state === "error" ? "yellow" : "cyan", s = n ? `${styleText(l, S_BAR)} ` : "", a = n ? styleText(l, S_BAR_END) : "";
|
|
1650
1673
|
let u = "";
|
|
1651
1674
|
if (this.isNavigating || p) {
|
|
1652
|
-
const d = p ? m :
|
|
1675
|
+
const d = p ? m : r;
|
|
1653
1676
|
u = d !== "" ? ` ${styleText("dim", d)}` : "";
|
|
1654
1677
|
} else
|
|
1655
1678
|
u = ` ${this.userInputWithCursor}`;
|
|
1656
1679
|
const V = this.filteredOptions.length !== o.length ? styleText(
|
|
1657
1680
|
"dim",
|
|
1658
1681
|
` (${this.filteredOptions.length} match${this.filteredOptions.length === 1 ? "" : "es"})`
|
|
1659
|
-
) : "",
|
|
1682
|
+
) : "", b = this.filteredOptions.length === 0 && r ? [`${s}${styleText("yellow", "No matches found")}`] : [], y = this.state === "error" ? [`${s}${styleText("yellow", this.error)}`] : [];
|
|
1660
1683
|
n && i.push(`${s.trimEnd()}`), i.push(
|
|
1661
1684
|
`${s}${styleText("dim", "Search:")}${u}${V}`,
|
|
1662
|
-
...
|
|
1663
|
-
...
|
|
1685
|
+
...b,
|
|
1686
|
+
...y
|
|
1664
1687
|
);
|
|
1665
|
-
const
|
|
1688
|
+
const S = [
|
|
1666
1689
|
`${styleText("dim", "\u2191/\u2193")} to select`,
|
|
1690
|
+
...t.completeOnTab ? [`${styleText("dim", "Tab:")} complete`] : [],
|
|
1667
1691
|
`${styleText("dim", "Enter:")} confirm`,
|
|
1668
1692
|
`${styleText("dim", "Type:")} to search`
|
|
1669
|
-
], g = [`${s}${
|
|
1693
|
+
], g = [`${s}${S.join(" \u2022 ")}`, a], O = this.filteredOptions.length === 0 ? [] : limitOptions({
|
|
1670
1694
|
cursor: this.cursor,
|
|
1671
1695
|
options: this.filteredOptions,
|
|
1672
1696
|
columnPadding: n ? 3 : 0,
|
|
@@ -1689,14 +1713,14 @@ ${s}${r}`;
|
|
|
1689
1713
|
}
|
|
1690
1714
|
}
|
|
1691
1715
|
}).prompt(), autocompleteMultiselect = (t) => {
|
|
1692
|
-
const c = (i,
|
|
1693
|
-
const p = o.includes(i.value), $ = i.label ?? String(i.value ?? ""),
|
|
1694
|
-
return i.disabled ? `${styleText("gray", S_CHECKBOX_INACTIVE)} ${styleText(["strikethrough", "gray"], $)}` :
|
|
1716
|
+
const c = (i, r, o, m) => {
|
|
1717
|
+
const p = o.includes(i.value), $ = i.label ?? String(i.value ?? ""), l = i.hint && m !== void 0 && i.value === m ? styleText("dim", ` (${i.hint})`) : "", s = p ? styleText("green", S_CHECKBOX_SELECTED) : styleText("dim", S_CHECKBOX_INACTIVE);
|
|
1718
|
+
return i.disabled ? `${styleText("gray", S_CHECKBOX_INACTIVE)} ${styleText(["strikethrough", "gray"], $)}` : r ? `${s} ${$}${l}` : `${s} ${styleText("dim", $)}`;
|
|
1695
1719
|
}, n = new AutocompletePrompt({
|
|
1696
1720
|
options: t.options,
|
|
1697
1721
|
multiple: true,
|
|
1698
1722
|
placeholder: t.placeholder,
|
|
1699
|
-
filter: t.filter ?? ((i,
|
|
1723
|
+
filter: t.filter ?? ((i, r) => prompts_dist_P(i, r)),
|
|
1700
1724
|
validate: () => {
|
|
1701
1725
|
if (t.required && n.selectedValues.length === 0)
|
|
1702
1726
|
return "Please select at least one item";
|
|
@@ -1706,39 +1730,39 @@ ${s}${r}`;
|
|
|
1706
1730
|
input: t.input,
|
|
1707
1731
|
output: t.output,
|
|
1708
1732
|
render() {
|
|
1709
|
-
const i = t.withGuide ?? settings.withGuide,
|
|
1733
|
+
const i = t.withGuide ?? settings.withGuide, r = `${i ? `${styleText("gray", S_BAR)}
|
|
1710
1734
|
` : ""}${symbol(this.state)} ${t.message}
|
|
1711
|
-
`, o = this.userInput, m = t.placeholder, p = o === "" && m !== void 0, $ = this.isNavigating || p ? styleText("dim", p ? m : o) : this.userInputWithCursor,
|
|
1735
|
+
`, o = this.userInput, m = t.placeholder, p = o === "" && m !== void 0, $ = this.isNavigating || p ? styleText("dim", p ? m : o) : this.userInputWithCursor, l = this.options, s = this.filteredOptions.length !== l.length ? styleText(
|
|
1712
1736
|
"dim",
|
|
1713
1737
|
` (${this.filteredOptions.length} match${this.filteredOptions.length === 1 ? "" : "es"})`
|
|
1714
1738
|
) : "";
|
|
1715
1739
|
switch (this.state) {
|
|
1716
1740
|
case "submit":
|
|
1717
|
-
return `${
|
|
1741
|
+
return `${r}${i ? `${styleText("gray", S_BAR)} ` : ""}${styleText(
|
|
1718
1742
|
"dim",
|
|
1719
1743
|
`${this.selectedValues.length} items selected`
|
|
1720
1744
|
)}`;
|
|
1721
1745
|
case "cancel":
|
|
1722
|
-
return `${
|
|
1746
|
+
return `${r}${i ? `${styleText("gray", S_BAR)} ` : ""}${styleText(
|
|
1723
1747
|
["strikethrough", "dim"],
|
|
1724
1748
|
o
|
|
1725
1749
|
)}`;
|
|
1726
1750
|
default: {
|
|
1727
|
-
const a = this.state === "error" ? "yellow" : "cyan", u = i ? `${styleText(a, S_BAR)} ` : "", V = i ? styleText(a, S_BAR_END) : "",
|
|
1751
|
+
const a = this.state === "error" ? "yellow" : "cyan", u = i ? `${styleText(a, S_BAR)} ` : "", V = i ? styleText(a, S_BAR_END) : "", b = [
|
|
1728
1752
|
`${styleText("dim", "\u2191/\u2193")} to navigate`,
|
|
1729
1753
|
`${styleText("dim", this.isNavigating ? "Space/Tab:" : "Tab:")} select`,
|
|
1730
1754
|
`${styleText("dim", "Enter:")} confirm`,
|
|
1731
1755
|
`${styleText("dim", "Type:")} to search`
|
|
1732
|
-
],
|
|
1733
|
-
...`${
|
|
1756
|
+
], y = this.filteredOptions.length === 0 && o ? [`${u}${styleText("yellow", "No matches found")}`] : [], S = this.state === "error" ? [`${u}${styleText("yellow", this.error)}`] : [], g = [
|
|
1757
|
+
...`${r}${i ? styleText(a, S_BAR) : ""}`.split(`
|
|
1734
1758
|
`),
|
|
1735
1759
|
`${u}${styleText("dim", "Search:")} ${$}${s}`,
|
|
1736
|
-
...
|
|
1737
|
-
...
|
|
1738
|
-
], O = [`${u}${
|
|
1760
|
+
...y,
|
|
1761
|
+
...S
|
|
1762
|
+
], O = [`${u}${b.join(" \u2022 ")}`, V], d = limitOptions({
|
|
1739
1763
|
cursor: this.cursor,
|
|
1740
1764
|
options: this.filteredOptions,
|
|
1741
|
-
style: (f,
|
|
1765
|
+
style: (f, L) => c(f, L, this.selectedValues, this.focusedValue),
|
|
1742
1766
|
maxItems: t.maxItems,
|
|
1743
1767
|
output: t.output,
|
|
1744
1768
|
rowPadding: g.length + O.length
|
|
@@ -1756,24 +1780,24 @@ ${s}${r}`;
|
|
|
1756
1780
|
return n.prompt();
|
|
1757
1781
|
};
|
|
1758
1782
|
|
|
1759
|
-
const
|
|
1783
|
+
const K = (/* unused pure expression or super */ null && ([
|
|
1760
1784
|
S_CORNER_TOP_LEFT,
|
|
1761
1785
|
S_CORNER_TOP_RIGHT,
|
|
1762
1786
|
S_CORNER_BOTTOM_LEFT,
|
|
1763
1787
|
S_CORNER_BOTTOM_RIGHT
|
|
1764
|
-
])),
|
|
1788
|
+
])), Q = (/* unused pure expression or super */ null && ([S_BAR_START, S_BAR_START_RIGHT, S_BAR_END, S_BAR_END_RIGHT]));
|
|
1765
1789
|
function A$1(n, e, t, o) {
|
|
1766
1790
|
let i = t, f = t;
|
|
1767
1791
|
return o === "center" ? i = Math.floor((e - n) / 2) : o === "right" && (i = e - n - t), f = e - i - n, [i, f];
|
|
1768
1792
|
}
|
|
1769
|
-
const
|
|
1793
|
+
const dist_U = (n) => n;
|
|
1770
1794
|
const box = (n = "", e = "", t) => {
|
|
1771
|
-
const o = t?.output ?? process.stdout, i = getColumns(o), R = 1 * 2, u = t?.titlePadding ?? 1, h = t?.contentPadding ?? 2, w = t?.width === void 0 || t.width === "auto" ? 1 : Math.min(1, t.width), m = t?.withGuide ?? settings.withGuide ? `${S_BAR} ` : "", b = t?.formatBorder ??
|
|
1772
|
-
let r = Math.floor(i * w) -
|
|
1795
|
+
const o = t?.output ?? process.stdout, i = getColumns(o), R = 1 * 2, u = t?.titlePadding ?? 1, h = t?.contentPadding ?? 2, w = t?.width === void 0 || t.width === "auto" ? 1 : Math.min(1, t.width), m = t?.withGuide ?? settings.withGuide ? `${styleText("gray", S_BAR)} ` : "", b = t?.formatBorder ?? dist_U, a = (t?.rounded ? K : Q).map(b), _ = b(S_BAR_H), p = b(S_BAR), x = l(m), B = l(e), y = i - x;
|
|
1796
|
+
let r = Math.floor(i * w) - x;
|
|
1773
1797
|
if (t?.width === "auto") {
|
|
1774
1798
|
const c = n.split(`
|
|
1775
1799
|
`);
|
|
1776
|
-
let s =
|
|
1800
|
+
let s = B + u * 2;
|
|
1777
1801
|
for (const G of c) {
|
|
1778
1802
|
const P = l(G) + h * 2;
|
|
1779
1803
|
P > s && (s = P);
|
|
@@ -1781,9 +1805,9 @@ const box = (n = "", e = "", t) => {
|
|
|
1781
1805
|
const g = s + R;
|
|
1782
1806
|
g < r && (r = g);
|
|
1783
1807
|
}
|
|
1784
|
-
r % 2 !== 0 && (r <
|
|
1785
|
-
const d = r - R,
|
|
1786
|
-
l(
|
|
1808
|
+
r % 2 !== 0 && (r < y ? r++ : r--);
|
|
1809
|
+
const d = r - R, T = d - u * 2, S = B > T ? `${e.slice(0, T - 3)}...` : e, [O, W] = A$1(
|
|
1810
|
+
l(S),
|
|
1787
1811
|
d,
|
|
1788
1812
|
u,
|
|
1789
1813
|
t?.titleAlign
|
|
@@ -1792,7 +1816,7 @@ const box = (n = "", e = "", t) => {
|
|
|
1792
1816
|
trim: false
|
|
1793
1817
|
});
|
|
1794
1818
|
o.write(
|
|
1795
|
-
`${m}${a[0]}${_.repeat(
|
|
1819
|
+
`${m}${a[0]}${_.repeat(O)}${S}${_.repeat(W)}${a[1]}
|
|
1796
1820
|
`
|
|
1797
1821
|
);
|
|
1798
1822
|
const E = L.split(`
|
|
@@ -1805,7 +1829,7 @@ const box = (n = "", e = "", t) => {
|
|
|
1805
1829
|
t?.contentAlign
|
|
1806
1830
|
);
|
|
1807
1831
|
o.write(
|
|
1808
|
-
`${m}${
|
|
1832
|
+
`${m}${p}${" ".repeat(s)}${c}${" ".repeat(g)}${p}
|
|
1809
1833
|
`
|
|
1810
1834
|
);
|
|
1811
1835
|
}
|
|
@@ -1813,39 +1837,39 @@ const box = (n = "", e = "", t) => {
|
|
|
1813
1837
|
`);
|
|
1814
1838
|
};
|
|
1815
1839
|
|
|
1816
|
-
const dist_confirm = (
|
|
1817
|
-
const a =
|
|
1840
|
+
const dist_confirm = (e) => {
|
|
1841
|
+
const a = e.active ?? "Yes", o = e.inactive ?? "No";
|
|
1818
1842
|
return new dist_r({
|
|
1819
1843
|
active: a,
|
|
1820
|
-
inactive:
|
|
1821
|
-
signal:
|
|
1822
|
-
input:
|
|
1823
|
-
output:
|
|
1824
|
-
initialValue:
|
|
1844
|
+
inactive: o,
|
|
1845
|
+
signal: e.signal,
|
|
1846
|
+
input: e.input,
|
|
1847
|
+
output: e.output,
|
|
1848
|
+
initialValue: e.initialValue ?? true,
|
|
1825
1849
|
render() {
|
|
1826
|
-
const
|
|
1827
|
-
|
|
1828
|
-
|
|
1850
|
+
const i = e.withGuide ?? dist_settings.withGuide, u = `${symbol(this.state)} `, l = i ? `${external_node_util_styleText("gray", S_BAR)} ` : "", f = dist_wrapTextWithPrefix(
|
|
1851
|
+
e.output,
|
|
1852
|
+
e.message,
|
|
1829
1853
|
l,
|
|
1830
1854
|
u
|
|
1831
|
-
),
|
|
1855
|
+
), s = `${i ? `${external_node_util_styleText("gray", S_BAR)}
|
|
1832
1856
|
` : ""}${f}
|
|
1833
|
-
`, c = this.value ? a :
|
|
1857
|
+
`, c = this.value ? a : o;
|
|
1834
1858
|
switch (this.state) {
|
|
1835
1859
|
case "submit": {
|
|
1836
|
-
const r =
|
|
1837
|
-
return `${
|
|
1860
|
+
const r = i ? `${external_node_util_styleText("gray", S_BAR)} ` : "";
|
|
1861
|
+
return `${s}${r}${external_node_util_styleText("dim", c)}`;
|
|
1838
1862
|
}
|
|
1839
1863
|
case "cancel": {
|
|
1840
|
-
const r =
|
|
1841
|
-
return `${
|
|
1864
|
+
const r = i ? `${external_node_util_styleText("gray", S_BAR)} ` : "";
|
|
1865
|
+
return `${s}${r}${external_node_util_styleText(["strikethrough", "dim"], c)}${i ? `
|
|
1842
1866
|
${external_node_util_styleText("gray", S_BAR)}` : ""}`;
|
|
1843
1867
|
}
|
|
1844
1868
|
default: {
|
|
1845
|
-
const r =
|
|
1846
|
-
return `${
|
|
1869
|
+
const r = i ? `${external_node_util_styleText("cyan", S_BAR)} ` : "", g = i ? external_node_util_styleText("cyan", S_BAR_END) : "";
|
|
1870
|
+
return `${s}${r}${this.value ? `${external_node_util_styleText("green", S_RADIO_ACTIVE)} ${a}` : `${external_node_util_styleText("dim", S_RADIO_INACTIVE)} ${external_node_util_styleText("dim", a)}`}${e.vertical ? i ? `
|
|
1847
1871
|
${external_node_util_styleText("cyan", S_BAR)} ` : `
|
|
1848
|
-
` : ` ${external_node_util_styleText("dim", "/")} `}${this.value ? `${external_node_util_styleText("dim", S_RADIO_INACTIVE)} ${external_node_util_styleText("dim",
|
|
1872
|
+
` : ` ${external_node_util_styleText("dim", "/")} `}${this.value ? `${external_node_util_styleText("dim", S_RADIO_INACTIVE)} ${external_node_util_styleText("dim", o)}` : `${external_node_util_styleText("green", S_RADIO_ACTIVE)} ${o}`}
|
|
1849
1873
|
${g}
|
|
1850
1874
|
`;
|
|
1851
1875
|
}
|
|
@@ -1947,7 +1971,7 @@ const multiselect = (i) => {
|
|
|
1947
1971
|
const u = (t, a) => {
|
|
1948
1972
|
const r = t.label ?? String(t.value);
|
|
1949
1973
|
return a === "disabled" ? `${styleText("gray", S_CHECKBOX_INACTIVE)} ${prompts_dist_m(r, (o) => styleText(["strikethrough", "gray"], o))}${t.hint ? ` ${styleText("dim", `(${t.hint ?? "disabled"})`)}` : ""}` : a === "active" ? `${styleText("cyan", S_CHECKBOX_ACTIVE)} ${r}${t.hint ? ` ${styleText("dim", `(${t.hint})`)}` : ""}` : a === "selected" ? `${styleText("green", S_CHECKBOX_SELECTED)} ${prompts_dist_m(r, (o) => styleText("dim", o))}${t.hint ? ` ${styleText("dim", `(${t.hint})`)}` : ""}` : a === "cancelled" ? `${prompts_dist_m(r, (o) => styleText(["strikethrough", "dim"], o))}` : a === "active-selected" ? `${styleText("green", S_CHECKBOX_SELECTED)} ${r}${t.hint ? ` ${styleText("dim", `(${t.hint})`)}` : ""}` : a === "submitted" ? `${prompts_dist_m(r, (o) => styleText("dim", o))}` : `${styleText("dim", S_CHECKBOX_INACTIVE)} ${prompts_dist_m(r, (o) => styleText("dim", o))}`;
|
|
1950
|
-
}, d = i.required ?? true,
|
|
1974
|
+
}, d = i.required ?? true, x = i.showInstructions ?? true;
|
|
1951
1975
|
return new MultiSelectPrompt({
|
|
1952
1976
|
options: i.options,
|
|
1953
1977
|
signal: i.signal,
|
|
@@ -1978,7 +2002,7 @@ ${styleText(
|
|
|
1978
2002
|
`${symbol(this.state)} `
|
|
1979
2003
|
), r = `${t ? `${styleText("gray", S_BAR)}
|
|
1980
2004
|
` : ""}${a}
|
|
1981
|
-
`, o = this.value ?? [],
|
|
2005
|
+
`, o = this.value ?? [], g = (n, l) => {
|
|
1982
2006
|
if (n.disabled)
|
|
1983
2007
|
return u(n, "disabled");
|
|
1984
2008
|
const s = o.includes(n.value);
|
|
@@ -2008,7 +2032,7 @@ ${styleText("gray", S_BAR)}` : ""}`;
|
|
|
2008
2032
|
case "error": {
|
|
2009
2033
|
const n = t ? `${styleText("yellow", S_BAR)} ` : "", l = this.error.split(`
|
|
2010
2034
|
`).map(
|
|
2011
|
-
($,
|
|
2035
|
+
($, v) => v === 0 ? `${t ? `${styleText("yellow", S_BAR_END)} ` : ""}${styleText("yellow", $)}` : ` ${$}`
|
|
2012
2036
|
).join(`
|
|
2013
2037
|
`), s = r.split(`
|
|
2014
2038
|
`).length, h = l.split(`
|
|
@@ -2020,7 +2044,7 @@ ${styleText("gray", S_BAR)}` : ""}`;
|
|
|
2020
2044
|
maxItems: i.maxItems,
|
|
2021
2045
|
columnPadding: n.length,
|
|
2022
2046
|
rowPadding: s + h,
|
|
2023
|
-
style:
|
|
2047
|
+
style: g
|
|
2024
2048
|
}).join(`
|
|
2025
2049
|
${n}`)}
|
|
2026
2050
|
${l}
|
|
@@ -2028,7 +2052,7 @@ ${l}
|
|
|
2028
2052
|
}
|
|
2029
2053
|
default: {
|
|
2030
2054
|
const n = t ? `${styleText("cyan", S_BAR)} ` : "", l = r.split(`
|
|
2031
|
-
`).length, s =
|
|
2055
|
+
`).length, s = x ? formatInstructionFooter(MULTISELECT_INSTRUCTIONS, t) : t ? [styleText("cyan", S_BAR_END)] : [], h = s.join(`
|
|
2032
2056
|
`), $ = s.length + 1;
|
|
2033
2057
|
return `${r}${n}${limitOptions({
|
|
2034
2058
|
output: i.output,
|
|
@@ -2037,7 +2061,7 @@ ${l}
|
|
|
2037
2061
|
maxItems: i.maxItems,
|
|
2038
2062
|
columnPadding: n.length,
|
|
2039
2063
|
rowPadding: l + $,
|
|
2040
|
-
style:
|
|
2064
|
+
style: g
|
|
2041
2065
|
}).join(`
|
|
2042
2066
|
${n}`)}
|
|
2043
2067
|
${h}
|
|
@@ -2049,10 +2073,10 @@ ${h}
|
|
|
2049
2073
|
};
|
|
2050
2074
|
|
|
2051
2075
|
const groupMultiselect = (o) => {
|
|
2052
|
-
const { selectableGroups:
|
|
2053
|
-
const a = n.label ?? String(n.value), t = typeof n.group == "string", s = t && (
|
|
2076
|
+
const { selectableGroups: f = true, groupSpacing: x = 0 } = o, d = (n, l, p = []) => {
|
|
2077
|
+
const a = n.label ?? String(n.value), t = typeof n.group == "string", s = t && (p[p.indexOf(n) + 1] ?? { group: true }), u = t && s && s.group === true;
|
|
2054
2078
|
let r = "", c = "";
|
|
2055
|
-
t && (
|
|
2079
|
+
t && (f ? (r = u ? `${S_BAR_END} ` : `${S_BAR} `, c = u ? " " : `${S_BAR} `) : r = " ");
|
|
2056
2080
|
let i = "";
|
|
2057
2081
|
if (x > 0 && !t && (i = `
|
|
2058
2082
|
`.repeat(x)), l === "active")
|
|
@@ -2070,7 +2094,7 @@ const groupMultiselect = (o) => {
|
|
|
2070
2094
|
`${i}${r} `,
|
|
2071
2095
|
`${i}${r}${styleText("cyan", S_CHECKBOX_ACTIVE)} `,
|
|
2072
2096
|
`${i}${c} `,
|
|
2073
|
-
(
|
|
2097
|
+
(m) => styleText("dim", m)
|
|
2074
2098
|
);
|
|
2075
2099
|
if (l === "group-active-selected")
|
|
2076
2100
|
return wrapTextWithPrefix(
|
|
@@ -2079,17 +2103,17 @@ const groupMultiselect = (o) => {
|
|
|
2079
2103
|
`${i}${r} `,
|
|
2080
2104
|
`${i}${r}${styleText("green", S_CHECKBOX_SELECTED)} `,
|
|
2081
2105
|
`${i}${c} `,
|
|
2082
|
-
(
|
|
2106
|
+
(m) => styleText("dim", m)
|
|
2083
2107
|
);
|
|
2084
2108
|
if (l === "selected") {
|
|
2085
|
-
const
|
|
2109
|
+
const m = t || f ? styleText("green", S_CHECKBOX_SELECTED) : "";
|
|
2086
2110
|
return wrapTextWithPrefix(
|
|
2087
2111
|
o.output,
|
|
2088
2112
|
`${a}${n.hint ? ` (${n.hint})` : ""}`,
|
|
2089
2113
|
`${i}${styleText("dim", r)} `,
|
|
2090
|
-
`${i}${styleText("dim", r)}${
|
|
2114
|
+
`${i}${styleText("dim", r)}${m} `,
|
|
2091
2115
|
`${i}${styleText("dim", c)} `,
|
|
2092
|
-
(
|
|
2116
|
+
(I) => styleText("dim", I)
|
|
2093
2117
|
);
|
|
2094
2118
|
}
|
|
2095
2119
|
if (l === "cancelled")
|
|
@@ -2104,16 +2128,16 @@ const groupMultiselect = (o) => {
|
|
|
2104
2128
|
);
|
|
2105
2129
|
if (l === "submitted")
|
|
2106
2130
|
return `${styleText("dim", a)}`;
|
|
2107
|
-
const
|
|
2131
|
+
const h = t || f ? styleText("dim", S_CHECKBOX_INACTIVE) : "";
|
|
2108
2132
|
return wrapTextWithPrefix(
|
|
2109
2133
|
o.output,
|
|
2110
2134
|
a,
|
|
2111
2135
|
`${i}${styleText("dim", r)} `,
|
|
2112
|
-
`${i}${styleText("dim", r)}${
|
|
2136
|
+
`${i}${styleText("dim", r)}${h} `,
|
|
2113
2137
|
`${i}${styleText("dim", c)} `,
|
|
2114
|
-
(
|
|
2138
|
+
(m) => styleText("dim", m)
|
|
2115
2139
|
);
|
|
2116
|
-
}, y = o.required ?? true,
|
|
2140
|
+
}, y = o.required ?? true, S = o.showInstructions ?? true;
|
|
2117
2141
|
return new GroupMultiSelectPrompt({
|
|
2118
2142
|
options: o.options,
|
|
2119
2143
|
signal: o.signal,
|
|
@@ -2122,7 +2146,7 @@ const groupMultiselect = (o) => {
|
|
|
2122
2146
|
initialValues: o.initialValues,
|
|
2123
2147
|
required: y,
|
|
2124
2148
|
cursorAt: o.cursorAt,
|
|
2125
|
-
selectableGroups:
|
|
2149
|
+
selectableGroups: f,
|
|
2126
2150
|
validate(n) {
|
|
2127
2151
|
if (y && (n === void 0 || n.length === 0))
|
|
2128
2152
|
return `Please select at least one option.
|
|
@@ -2140,24 +2164,24 @@ ${styleText(
|
|
|
2140
2164
|
render() {
|
|
2141
2165
|
const n = o.withGuide ?? settings.withGuide, l = `${n ? `${styleText("gray", S_BAR)}
|
|
2142
2166
|
` : ""}${symbol(this.state)} ${o.message}
|
|
2143
|
-
`,
|
|
2144
|
-
const u = this.options, r =
|
|
2145
|
-
return !s && typeof t.group == "string" && this.options[this.cursor]?.value === t.group ?
|
|
2167
|
+
`, p = this.value ?? [], a = (t, s) => {
|
|
2168
|
+
const u = this.options, r = p.includes(t.value) || t.group === true && this.isGroupSelected(`${t.value}`);
|
|
2169
|
+
return !s && typeof t.group == "string" && this.options[this.cursor]?.value === t.group ? d(t, r ? "group-active-selected" : "group-active", u) : s && r ? d(t, "active-selected", u) : r ? d(t, "selected", u) : d(t, s ? "active" : "inactive", u);
|
|
2146
2170
|
};
|
|
2147
2171
|
switch (this.state) {
|
|
2148
2172
|
case "submit": {
|
|
2149
|
-
const t = this.options.filter(({ value: u }) =>
|
|
2173
|
+
const t = this.options.filter(({ value: u }) => p.includes(u)).map((u) => d(u, "submitted")), s = t.length === 0 ? "" : ` ${t.join(styleText("dim", ", "))}`;
|
|
2150
2174
|
return `${l}${n ? styleText("gray", S_BAR) : ""}${s}`;
|
|
2151
2175
|
}
|
|
2152
2176
|
case "cancel": {
|
|
2153
|
-
const t = this.options.filter(({ value: s }) =>
|
|
2177
|
+
const t = this.options.filter(({ value: s }) => p.includes(s)).map((s) => d(s, "cancelled")).join(styleText("dim", ", "));
|
|
2154
2178
|
return `${l}${n ? `${styleText("gray", S_BAR)} ` : ""}${t.trim() ? `${t}${n ? `
|
|
2155
2179
|
${styleText("gray", S_BAR)}` : ""}` : ""}`;
|
|
2156
2180
|
}
|
|
2157
2181
|
case "error": {
|
|
2158
2182
|
const t = n ? `${styleText("yellow", S_BAR)} ` : "", s = this.error.split(`
|
|
2159
2183
|
`).map(
|
|
2160
|
-
(i,
|
|
2184
|
+
(i, h) => h === 0 ? `${n ? `${styleText("yellow", S_BAR_END)} ` : ""}${styleText("yellow", i)}` : ` ${i}`
|
|
2161
2185
|
).join(`
|
|
2162
2186
|
`), u = l.split(`
|
|
2163
2187
|
`).length, r = s.split(`
|
|
@@ -2177,7 +2201,7 @@ ${s}
|
|
|
2177
2201
|
}
|
|
2178
2202
|
default: {
|
|
2179
2203
|
const t = n ? `${styleText("cyan", S_BAR)} ` : "", s = l.split(`
|
|
2180
|
-
`).length, u =
|
|
2204
|
+
`).length, u = S ? formatInstructionFooter(MULTISELECT_INSTRUCTIONS, n) : n ? [styleText("cyan", S_BAR_END)] : [], r = u.join(`
|
|
2181
2205
|
`), c = u.length + 1, i = limitOptions({
|
|
2182
2206
|
output: o.output,
|
|
2183
2207
|
options: this.options,
|
|
@@ -2270,16 +2294,16 @@ const multiline = (e) => new MultiLinePrompt({
|
|
|
2270
2294
|
render() {
|
|
2271
2295
|
const i = e?.withGuide ?? settings.withGuide, o = `${`${i ? `${styleText("gray", S_BAR)}
|
|
2272
2296
|
` : ""}${symbol(this.state)} `}${e.message}
|
|
2273
|
-
`,
|
|
2297
|
+
`, h = e.placeholder && e.placeholder.length > 0 ? (
|
|
2274
2298
|
// biome-ignore lint/style/noNonNullAssertion: guarded by placeholder.length > 0
|
|
2275
2299
|
styleText("inverse", e.placeholder[0]) + styleText("dim", e.placeholder.slice(1))
|
|
2276
|
-
) : styleText(["inverse", "hidden"], "_"), a = this.userInput ? this.userInputWithCursor :
|
|
2300
|
+
) : styleText(["inverse", "hidden"], "_"), a = this.userInput ? this.userInputWithCursor : h, l = this.value ?? "", d = e.showSubmit ? `
|
|
2277
2301
|
${styleText(this.focused === "submit" ? "cyan" : "dim", "[ submit ]")}` : "";
|
|
2278
2302
|
switch (this.state) {
|
|
2279
2303
|
case "error": {
|
|
2280
2304
|
const n = `${styleText("yellow", S_BAR)} `, r = i ? wrapTextWithPrefix(e.output, a, n, void 0) : a, u = styleText("yellow", S_BAR_END);
|
|
2281
2305
|
return `${o}${r}
|
|
2282
|
-
${u} ${styleText("yellow", this.error)}${
|
|
2306
|
+
${u} ${styleText("yellow", this.error)}${d}
|
|
2283
2307
|
`;
|
|
2284
2308
|
}
|
|
2285
2309
|
case "submit": {
|
|
@@ -2307,7 +2331,7 @@ ${u} ${styleText("yellow", this.error)}${c}
|
|
|
2307
2331
|
default: {
|
|
2308
2332
|
const n = i ? `${styleText("cyan", S_BAR)} ` : "", r = i ? styleText("cyan", S_BAR_END) : "", u = i ? wrapTextWithPrefix(e.output, a, n) : a;
|
|
2309
2333
|
return `${o}${u}
|
|
2310
|
-
${r}${
|
|
2334
|
+
${r}${d}
|
|
2311
2335
|
`;
|
|
2312
2336
|
}
|
|
2313
2337
|
}
|
|
@@ -2346,36 +2370,36 @@ ${external_node_util_styleText("gray", l$1 + S_BAR_H.repeat(t + 2) + S_CORNER_BO
|
|
|
2346
2370
|
);
|
|
2347
2371
|
};
|
|
2348
2372
|
|
|
2349
|
-
const dist_password = (
|
|
2350
|
-
validate:
|
|
2351
|
-
mask:
|
|
2352
|
-
signal:
|
|
2353
|
-
input:
|
|
2354
|
-
output:
|
|
2373
|
+
const dist_password = (e) => new PasswordPrompt({
|
|
2374
|
+
validate: e.validate,
|
|
2375
|
+
mask: e.mask ?? S_PASSWORD_MASK,
|
|
2376
|
+
signal: e.signal,
|
|
2377
|
+
input: e.input,
|
|
2378
|
+
output: e.output,
|
|
2355
2379
|
render() {
|
|
2356
|
-
const
|
|
2357
|
-
` : ""}${symbol(this.state)} ${
|
|
2358
|
-
`,
|
|
2380
|
+
const r = e.withGuide ?? settings.withGuide, o = `${r ? `${styleText("gray", S_BAR)}
|
|
2381
|
+
` : ""}${symbol(this.state)} ${e.message}
|
|
2382
|
+
`, m = this.userInputWithCursor, i = this.masked;
|
|
2359
2383
|
switch (this.state) {
|
|
2360
2384
|
case "error": {
|
|
2361
|
-
const s =
|
|
2362
|
-
return
|
|
2363
|
-
${s}${
|
|
2385
|
+
const s = r ? `${styleText("yellow", S_BAR)} ` : "", n = r ? `${styleText("yellow", S_BAR_END)} ` : "", d = i ?? "";
|
|
2386
|
+
return e.clearOnError && this.clear(), `${o.trim()}
|
|
2387
|
+
${s}${d}
|
|
2364
2388
|
${n}${styleText("yellow", this.error)}
|
|
2365
2389
|
`;
|
|
2366
2390
|
}
|
|
2367
2391
|
case "submit": {
|
|
2368
|
-
const s =
|
|
2392
|
+
const s = r ? `${styleText("gray", S_BAR)} ` : "", n = i ? styleText("dim", i) : "";
|
|
2369
2393
|
return `${o}${s}${n}`;
|
|
2370
2394
|
}
|
|
2371
2395
|
case "cancel": {
|
|
2372
|
-
const s =
|
|
2373
|
-
return `${o}${s}${n}${i &&
|
|
2396
|
+
const s = r ? `${styleText("gray", S_BAR)} ` : "", n = i ? styleText(["strikethrough", "dim"], i) : "";
|
|
2397
|
+
return `${o}${s}${n}${i && r ? `
|
|
2374
2398
|
${styleText("gray", S_BAR)}` : ""}`;
|
|
2375
2399
|
}
|
|
2376
2400
|
default: {
|
|
2377
|
-
const s =
|
|
2378
|
-
return `${o}${s}${
|
|
2401
|
+
const s = r ? `${styleText("cyan", S_BAR)} ` : "", n = r ? styleText("cyan", S_BAR_END) : "";
|
|
2402
|
+
return `${o}${s}${m}
|
|
2379
2403
|
${n}
|
|
2380
2404
|
`;
|
|
2381
2405
|
}
|
|
@@ -2389,6 +2413,7 @@ const dist_path = (e) => {
|
|
|
2389
2413
|
...e,
|
|
2390
2414
|
initialUserInput: e.initialValue ?? e.root ?? process.cwd(),
|
|
2391
2415
|
maxItems: 5,
|
|
2416
|
+
completeOnTab: true,
|
|
2392
2417
|
validate(t) {
|
|
2393
2418
|
if (!Array.isArray(t)) {
|
|
2394
2419
|
if (!t)
|
|
@@ -2612,19 +2637,19 @@ ${external_node_util_styleText("gray", S_BAR)}` : ""}`;
|
|
|
2612
2637
|
}
|
|
2613
2638
|
default: {
|
|
2614
2639
|
const r = n ? `${external_node_util_styleText("cyan", S_BAR)} ` : "", a = u.split(`
|
|
2615
|
-
`).length, p = d ? formatInstructionFooter(SELECT_INSTRUCTIONS, n) : n ? [external_node_util_styleText("cyan", S_BAR_END)] : [],
|
|
2616
|
-
`),
|
|
2640
|
+
`).length, p = d ? formatInstructionFooter(SELECT_INSTRUCTIONS, n) : n ? [external_node_util_styleText("cyan", S_BAR_END)] : [], f = p.join(`
|
|
2641
|
+
`), b = p.length + 1;
|
|
2617
2642
|
return `${u}${r}${limitOptions({
|
|
2618
2643
|
output: t.output,
|
|
2619
2644
|
cursor: this.cursor,
|
|
2620
2645
|
options: this.options,
|
|
2621
2646
|
maxItems: t.maxItems,
|
|
2622
2647
|
columnPadding: r.length,
|
|
2623
|
-
rowPadding: a +
|
|
2648
|
+
rowPadding: a + b,
|
|
2624
2649
|
style: (g, x) => o(g, g.disabled ? "disabled" : x ? "active" : "inactive")
|
|
2625
2650
|
}).join(`
|
|
2626
2651
|
${r}`)}
|
|
2627
|
-
${
|
|
2652
|
+
${f}
|
|
2628
2653
|
`;
|
|
2629
2654
|
}
|
|
2630
2655
|
}
|
|
@@ -2633,7 +2658,7 @@ ${b}
|
|
|
2633
2658
|
};
|
|
2634
2659
|
|
|
2635
2660
|
const selectKey = (t) => {
|
|
2636
|
-
const
|
|
2661
|
+
const c = (e, a = "inactive") => {
|
|
2637
2662
|
if (e === void 0)
|
|
2638
2663
|
return "";
|
|
2639
2664
|
const n = e.label ?? String(e.value);
|
|
@@ -2652,33 +2677,33 @@ const selectKey = (t) => {
|
|
|
2652
2677
|
`;
|
|
2653
2678
|
switch (this.state) {
|
|
2654
2679
|
case "submit": {
|
|
2655
|
-
const n = e ? `${styleText("gray", S_BAR)} ` : "",
|
|
2680
|
+
const n = e ? `${styleText("gray", S_BAR)} ` : "", r = this.options.find((u) => u.value === this.value) ?? t.options[0], l = wrapTextWithPrefix(
|
|
2656
2681
|
t.output,
|
|
2657
|
-
|
|
2682
|
+
c(r, "selected"),
|
|
2658
2683
|
n
|
|
2659
2684
|
);
|
|
2660
|
-
return `${a}${
|
|
2685
|
+
return `${a}${l}`;
|
|
2661
2686
|
}
|
|
2662
2687
|
case "cancel": {
|
|
2663
|
-
const n = e ? `${styleText("gray", S_BAR)} ` : "",
|
|
2688
|
+
const n = e ? `${styleText("gray", S_BAR)} ` : "", r = wrapTextWithPrefix(
|
|
2664
2689
|
t.output,
|
|
2665
|
-
|
|
2690
|
+
c(this.options[0], "cancelled"),
|
|
2666
2691
|
n
|
|
2667
2692
|
);
|
|
2668
|
-
return `${a}${
|
|
2693
|
+
return `${a}${r}${e ? `
|
|
2669
2694
|
${styleText("gray", S_BAR)}` : ""}`;
|
|
2670
2695
|
}
|
|
2671
2696
|
default: {
|
|
2672
|
-
const n = e ? `${styleText("cyan", S_BAR)} ` : "",
|
|
2697
|
+
const n = e ? `${styleText("cyan", S_BAR)} ` : "", r = e ? styleText("cyan", S_BAR_END) : "", l = this.options.map(
|
|
2673
2698
|
(u, d) => wrapTextWithPrefix(
|
|
2674
2699
|
t.output,
|
|
2675
|
-
|
|
2700
|
+
c(u, d === this.cursor ? "active" : "inactive"),
|
|
2676
2701
|
n
|
|
2677
2702
|
)
|
|
2678
2703
|
).join(`
|
|
2679
2704
|
`);
|
|
2680
|
-
return `${a}${
|
|
2681
|
-
${
|
|
2705
|
+
return `${a}${l}
|
|
2706
|
+
${r}
|
|
2682
2707
|
`;
|
|
2683
2708
|
}
|
|
2684
2709
|
}
|
|
@@ -2841,42 +2866,48 @@ ${e.value}` : e.value;
|
|
|
2841
2866
|
};
|
|
2842
2867
|
};
|
|
2843
2868
|
|
|
2844
|
-
const dist_text = (
|
|
2845
|
-
validate:
|
|
2846
|
-
placeholder:
|
|
2847
|
-
defaultValue:
|
|
2848
|
-
initialValue:
|
|
2849
|
-
output:
|
|
2850
|
-
signal:
|
|
2851
|
-
input:
|
|
2869
|
+
const dist_text = (t) => new dist_n({
|
|
2870
|
+
validate: t.validate,
|
|
2871
|
+
placeholder: t.placeholder,
|
|
2872
|
+
defaultValue: t.defaultValue,
|
|
2873
|
+
initialValue: t.initialValue,
|
|
2874
|
+
output: t.output,
|
|
2875
|
+
signal: t.signal,
|
|
2876
|
+
input: t.input,
|
|
2852
2877
|
render() {
|
|
2853
|
-
const
|
|
2854
|
-
` : ""}${symbol(this.state)} `}${
|
|
2855
|
-
`,
|
|
2878
|
+
const r = t?.withGuide ?? dist_settings.withGuide, l = `${`${r ? `${external_node_util_styleText("gray", S_BAR)}
|
|
2879
|
+
` : ""}${symbol(this.state)} `}${t.message}
|
|
2880
|
+
`, d = t.placeholder && t.placeholder.length > 0 ? (
|
|
2856
2881
|
// biome-ignore lint/style/noNonNullAssertion: guarded by placeholder.length > 0
|
|
2857
|
-
external_node_util_styleText("inverse",
|
|
2858
|
-
) : external_node_util_styleText(["inverse", "hidden"], "_"), o = this.userInput ? this.userInputWithCursor :
|
|
2882
|
+
external_node_util_styleText("inverse", t.placeholder[0]) + external_node_util_styleText("dim", t.placeholder.slice(1))
|
|
2883
|
+
) : external_node_util_styleText(["inverse", "hidden"], "_"), o = this.userInput ? this.userInputWithCursor : d, s = this.value ?? "";
|
|
2859
2884
|
switch (this.state) {
|
|
2885
|
+
case "validating": {
|
|
2886
|
+
const n = r ? `${external_node_util_styleText("cyan", S_BAR)} ` : "", i = r ? external_node_util_styleText("cyan", S_BAR_END) : "", c = external_node_util_styleText("dim", o), $ = external_node_util_styleText("dim", "Validating...");
|
|
2887
|
+
return `${l}${n}${c}
|
|
2888
|
+
${i} ${$}
|
|
2889
|
+
`;
|
|
2890
|
+
}
|
|
2860
2891
|
case "error": {
|
|
2861
|
-
const n = this.error ? ` ${external_node_util_styleText("yellow", this.error)}` : "",
|
|
2862
|
-
return `${
|
|
2863
|
-
${
|
|
2864
|
-
${
|
|
2892
|
+
const n = this.error ? ` ${external_node_util_styleText("yellow", this.error)}` : "", i = r ? `${external_node_util_styleText("yellow", S_BAR)} ` : "", c = r ? external_node_util_styleText("yellow", S_BAR_END) : "";
|
|
2893
|
+
return `${l.trim()}
|
|
2894
|
+
${i}${o}
|
|
2895
|
+
${c}${n}
|
|
2865
2896
|
`;
|
|
2866
2897
|
}
|
|
2867
2898
|
case "submit": {
|
|
2868
|
-
const n =
|
|
2869
|
-
return `${
|
|
2899
|
+
const n = s ? `${r ? " " : ""}${external_node_util_styleText("dim", s)}` : "", i = r ? external_node_util_styleText("gray", S_BAR) : "";
|
|
2900
|
+
return `${l}${i}${n}`;
|
|
2870
2901
|
}
|
|
2871
2902
|
case "cancel": {
|
|
2872
|
-
const n =
|
|
2873
|
-
return `${
|
|
2874
|
-
${
|
|
2903
|
+
const n = s ? ` ${external_node_util_styleText(["strikethrough", "dim"], s)}` : "", i = r ? external_node_util_styleText("gray", S_BAR) : "";
|
|
2904
|
+
return `${l}${i}${n}${s.trim() ? `
|
|
2905
|
+
${i}` : ""}`;
|
|
2875
2906
|
}
|
|
2876
2907
|
default: {
|
|
2877
|
-
const n =
|
|
2878
|
-
return `${
|
|
2879
|
-
${
|
|
2908
|
+
const n = r ? `${external_node_util_styleText("cyan", S_BAR)} ` : "", i = r ? external_node_util_styleText("cyan", S_BAR_END) : "";
|
|
2909
|
+
return `${l}${n}${o}
|
|
2910
|
+
${i}
|
|
2880
2911
|
`;
|
|
2881
2912
|
}
|
|
2882
2913
|
}
|
|
@@ -2906,8 +2937,8 @@ function hasGit(cwd) {
|
|
|
2906
2937
|
], cwd).ok;
|
|
2907
2938
|
}
|
|
2908
2939
|
/**
|
|
2909
|
-
* Whether the new project already sits inside somebody's repository —
|
|
2910
|
-
*
|
|
2940
|
+
* Whether the new project already sits inside somebody's repository — a monorepo or an existing checkout, where
|
|
2941
|
+
* a nested repo would be a surprise rather than a convenience.
|
|
2911
2942
|
*/ function isInsideRepo(cwd) {
|
|
2912
2943
|
const { ok, stdout } = git_git([
|
|
2913
2944
|
'rev-parse',
|
|
@@ -2916,11 +2947,9 @@ function hasGit(cwd) {
|
|
|
2916
2947
|
return ok && stdout === 'true';
|
|
2917
2948
|
}
|
|
2918
2949
|
/**
|
|
2919
|
-
* Initializes a repository and makes the first commit.
|
|
2920
|
-
*
|
|
2921
|
-
*
|
|
2922
|
-
* on a machine with no `user.email` configured. That is not a reason to fail the scaffold — the files
|
|
2923
|
-
* are all there and staged — so the caller reports it and moves on.
|
|
2950
|
+
* Initializes a repository and makes the first commit. `initialized` is the honest answer when the commit itself
|
|
2951
|
+
* fails, as it does with no `user.email` configured — the files are all there and staged, so the caller reports
|
|
2952
|
+
* it and moves on rather than failing the scaffold.
|
|
2924
2953
|
*/ function initRepo(cwd) {
|
|
2925
2954
|
const init = git_git([
|
|
2926
2955
|
'init',
|
|
@@ -2943,22 +2972,21 @@ function hasGit(cwd) {
|
|
|
2943
2972
|
|
|
2944
2973
|
;// CONCATENATED MODULE: ./src/generated/framework.ts
|
|
2945
2974
|
// GENERATED by scripts/codegen.mjs from packages/core — do not edit. Run `pnpm --filter @rshono/create codegen`.
|
|
2946
|
-
/** The framework release a scaffolded app is pinned to: this package and rshono ship together. */ const RSHONO_VERSION = '1.0.0-rc.
|
|
2975
|
+
/** The framework release a scaffolded app is pinned to: this package and rshono ship together. */ const RSHONO_VERSION = '1.0.0-rc.21';
|
|
2947
2976
|
/**
|
|
2948
|
-
* The Node range rshono
|
|
2949
|
-
*
|
|
2950
|
-
*/ const NODE_ENGINE = '>=22.
|
|
2977
|
+
* The Node range rshono declares, restated in every scaffolded app's `engines` — so a CI image or a contributor
|
|
2978
|
+
* on an older Node hears it from their package manager rather than from a stack trace.
|
|
2979
|
+
*/ const NODE_ENGINE = '>=22.18.0';
|
|
2951
2980
|
/**
|
|
2952
|
-
* The dependency versions rshono is tested against, copied from its own manifest. Exact where it is
|
|
2953
|
-
*
|
|
2954
|
-
* overrides to fall back on.
|
|
2981
|
+
* The dependency versions rshono is tested against, copied from its own manifest. Exact where it is exact:
|
|
2982
|
+
* React's RSC internals are coupled across builds, and a generated app has no workspace overrides.
|
|
2955
2983
|
*/ const FRAMEWORK_DEPS = {
|
|
2956
|
-
hono: '^4.
|
|
2984
|
+
hono: '^4.13.7',
|
|
2957
2985
|
react: '19.2.8',
|
|
2958
2986
|
'react-dom': '19.2.8',
|
|
2959
2987
|
typescript: '^7.0.2',
|
|
2960
|
-
'@types/node': '^26.
|
|
2961
|
-
'@types/react': '^19.2.
|
|
2988
|
+
'@types/node': '^26.5.1',
|
|
2989
|
+
'@types/react': '^19.2.18'
|
|
2962
2990
|
};
|
|
2963
2991
|
/** Every `deploy` target the installed framework knows, with the command that ships what it built. */ const DEPLOY_TARGETS = [
|
|
2964
2992
|
{
|
|
@@ -2969,22 +2997,10 @@ function hasGit(cwd) {
|
|
|
2969
2997
|
name: 'cloudflare',
|
|
2970
2998
|
hint: 'deploy with `wrangler deploy`'
|
|
2971
2999
|
},
|
|
2972
|
-
{
|
|
2973
|
-
name: 'bun',
|
|
2974
|
-
hint: 'run `bun dist/server/main.mjs`'
|
|
2975
|
-
},
|
|
2976
|
-
{
|
|
2977
|
-
name: 'deno',
|
|
2978
|
-
hint: 'run `deno serve -A dist/server/main.mjs`'
|
|
2979
|
-
},
|
|
2980
3000
|
{
|
|
2981
3001
|
name: 'vercel',
|
|
2982
3002
|
hint: 'deploy with `vercel deploy --prebuilt`'
|
|
2983
3003
|
},
|
|
2984
|
-
{
|
|
2985
|
-
name: 'netlify',
|
|
2986
|
-
hint: 'deploy with `netlify deploy --build=false --dir=.netlify/publish`'
|
|
2987
|
-
},
|
|
2988
3004
|
{
|
|
2989
3005
|
name: 'aws-lambda',
|
|
2990
3006
|
hint: 'zip dist/ with the handler at dist/server/main.mjs'
|
|
@@ -2994,9 +3010,8 @@ function hasGit(cwd) {
|
|
|
2994
3010
|
;// CONCATENATED MODULE: ./src/options.ts
|
|
2995
3011
|
|
|
2996
3012
|
/*
|
|
2997
|
-
* The names each option accepts, spelled once
|
|
2998
|
-
*
|
|
2999
|
-
* — so a name added here reaches all three without a second list to remember.
|
|
3013
|
+
* The names each option accepts, spelled once: the types below are derived from them, the CLI validates its
|
|
3014
|
+
* flags against them and prints them in `--help`, and `pm.ts` recognises a package manager by them.
|
|
3000
3015
|
*/ const FORMATTER_NAMES = [
|
|
3001
3016
|
'prettier',
|
|
3002
3017
|
'biome',
|
|
@@ -3057,20 +3072,26 @@ const QUALITY_PRESETS = [
|
|
|
3057
3072
|
}
|
|
3058
3073
|
];
|
|
3059
3074
|
/**
|
|
3060
|
-
* Turns whatever the user typed into a name npm will accept, or
|
|
3061
|
-
*
|
|
3062
|
-
*
|
|
3075
|
+
* Turns whatever the user typed into a name npm will accept, or `null` when nothing usable is left.
|
|
3076
|
+
* Lowercasing and replacing runs of invalid characters covers the ordinary cases (`My App`, `my_app`).
|
|
3077
|
+
*
|
|
3078
|
+
* The promise is checked rather than assumed: the result goes through {@link isValidPackageName} on the way
|
|
3079
|
+
* out. It used to be spelled as a rule per character class here and the check made again by the caller, which
|
|
3080
|
+
* left the exported function able to return a name npm refuses — `_leading` was one, because a leading
|
|
3081
|
+
* underscore is stripped by npm's rule and not by this one.
|
|
3063
3082
|
*/ function toPackageName(input) {
|
|
3064
3083
|
const trimmed = input.trim().replace(/^\.\/+/, '').replace(/\/+$/, '');
|
|
3065
3084
|
if (!trimmed || trimmed === '.') return null;
|
|
3066
|
-
// A scoped name is a name, not a path: `@scope/pkg` stays whole
|
|
3067
|
-
//
|
|
3085
|
+
// A scoped name is a name, not a path: `@scope/pkg` stays whole. Anything else is a path, whose last
|
|
3086
|
+
// segment names the project.
|
|
3068
3087
|
const scoped = /^@[^\\/]+[\\/][^\\/]+$/.test(trimmed);
|
|
3069
3088
|
const base = scoped ? trimmed : trimmed.split(/[\\/]/).filter(Boolean).pop() ?? '';
|
|
3070
3089
|
if (!base) return null;
|
|
3071
|
-
const name = base.toLowerCase().replace(/[\\/]/g, '/').replace(/[^a-z\d\-._~/@]+/g, '-')
|
|
3072
|
-
|
|
3073
|
-
|
|
3090
|
+
const name = base.toLowerCase().replace(/[\\/]/g, '/').replace(/[^a-z\d\-._~/@]+/g, '-')// `_` alongside `-`: npm refuses a leading underscore too, and it is what `My_App` and `_internal` leave
|
|
3091
|
+
// behind once the invalid runs are replaced.
|
|
3092
|
+
.replace(/^[-_]+/, '').replace(/-+$/, '');
|
|
3093
|
+
const trimmedName = name.slice(0, 214);
|
|
3094
|
+
return isValidPackageName(trimmedName) ? trimmedName : null;
|
|
3074
3095
|
}
|
|
3075
3096
|
/** npm's own rule, narrowed to what we ever generate: no uppercase, no leading dot or underscore. */ function isValidPackageName(name) {
|
|
3076
3097
|
return /^(?:@[a-z\d\-*~][a-z\d\-*._~]*\/)?[a-z\d\-~][a-z\d\-._~]*$/.test(name) && name.length <= 214;
|
|
@@ -3078,12 +3099,12 @@ const QUALITY_PRESETS = [
|
|
|
3078
3099
|
|
|
3079
3100
|
;// CONCATENATED MODULE: ./src/features/combinations.ts
|
|
3080
3101
|
/**
|
|
3081
|
-
* Biome's CSS parser rejects Tailwind's syntax — `@apply`
|
|
3082
|
-
*
|
|
3083
|
-
*
|
|
3102
|
+
* Biome's CSS parser rejects Tailwind's syntax — `@apply` is a parse error, not an unknown-at-rule warning — so
|
|
3103
|
+
* a project with both needs Biome pointed away from stylesheets. The overlay is a second `biome.json` listed
|
|
3104
|
+
* after the first.
|
|
3084
3105
|
*
|
|
3085
|
-
* Narrow on purpose:
|
|
3086
|
-
*
|
|
3106
|
+
* Narrow on purpose: excluding CSS for everybody would give up formatting the plain-CSS template that Biome
|
|
3107
|
+
* handles perfectly well.
|
|
3087
3108
|
*/ const BIOME_TAILWIND = {
|
|
3088
3109
|
id: 'biome-tailwind',
|
|
3089
3110
|
overlays: [
|
|
@@ -3103,19 +3124,85 @@ const QUALITY_PRESETS = [
|
|
|
3103
3124
|
] : [];
|
|
3104
3125
|
}
|
|
3105
3126
|
|
|
3127
|
+
;// CONCATENATED MODULE: ./src/scripts.ts
|
|
3128
|
+
// `features/types.js` rather than `features/index.js`: the deploy feature imports `invoke` from here, and
|
|
3129
|
+
// going through the barrel would make that a cycle — types.ts imports nothing.
|
|
3130
|
+
/**
|
|
3131
|
+
* The scripts every app gets, whatever it targets.
|
|
3132
|
+
*
|
|
3133
|
+
* `start`, `preview` and `deploy` are not here: each means something different per platform, so the deploy
|
|
3134
|
+
* target contributes its own. The three names are a contract the targets keep, which is what lets the README
|
|
3135
|
+
* describe an app it was not written for:
|
|
3136
|
+
*
|
|
3137
|
+
* - **`start`** runs a build that already exists and never makes one — what a host's own start command calls.
|
|
3138
|
+
* - **`preview`** builds, then runs the result here, so the production build is answerable without deploying.
|
|
3139
|
+
* - **`deploy`** builds, then ships it — where the platform has one command that does the shipping.
|
|
3140
|
+
*/ const BASE_SCRIPTS = {
|
|
3141
|
+
dev: 'rshono dev',
|
|
3142
|
+
build: 'rshono build',
|
|
3143
|
+
typecheck: 'tsc --noEmit'
|
|
3144
|
+
};
|
|
3145
|
+
/**
|
|
3146
|
+
* Every script the app gets, in the order they are written: the base ones, then each feature's. The manifest and
|
|
3147
|
+
* the README's command table are both this, so neither can document a script the other lacks.
|
|
3148
|
+
*/ function buildScripts(features) {
|
|
3149
|
+
const scripts = {
|
|
3150
|
+
...BASE_SCRIPTS
|
|
3151
|
+
};
|
|
3152
|
+
for (const feature of features)Object.assign(scripts, feature.scripts);
|
|
3153
|
+
return scripts;
|
|
3154
|
+
}
|
|
3155
|
+
/** The gloss for each base script, in the README's command table. `build` names the target it is for. */ function baseScriptHelp(deploy) {
|
|
3156
|
+
return {
|
|
3157
|
+
dev: 'dev server with HMR, http://localhost:3000',
|
|
3158
|
+
build: `production build for ${deploy}`,
|
|
3159
|
+
typecheck: 'tsc --noEmit'
|
|
3160
|
+
};
|
|
3161
|
+
}
|
|
3162
|
+
/**
|
|
3163
|
+
* Script names a package manager has a command of its own for: `pnpm deploy` runs pnpm's workspace-deploy and
|
|
3164
|
+
* never looks at the manifest. These get the explicit `run` form, which all four managers accept.
|
|
3165
|
+
*/ const SHADOWED = new Set([
|
|
3166
|
+
'deploy'
|
|
3167
|
+
]);
|
|
3168
|
+
/** How to type one of the app's scripts with this package manager — `pnpm dev`, but `npm run dev`. */ function invoke(pm, script) {
|
|
3169
|
+
return `${SHADOWED.has(script) ? `${pm.name} run` : pm.run} ${script}`;
|
|
3170
|
+
}
|
|
3171
|
+
/**
|
|
3172
|
+
* The README's command table: one line per script, with the command to type and a one-line gloss. A script whose
|
|
3173
|
+
* feature supplies no `scriptHelp` is left out — that is how `format:check` stays out of a table about running
|
|
3174
|
+
* the app — and covered by the line pointing at `package.json`.
|
|
3175
|
+
*/ function scriptTable(answers, features, pm) {
|
|
3176
|
+
const help = baseScriptHelp(answers.deploy);
|
|
3177
|
+
for (const feature of features)Object.assign(help, feature.scriptHelp);
|
|
3178
|
+
const documented = Object.keys(buildScripts(features)).filter((name)=>help[name]);
|
|
3179
|
+
const width = Math.max(...documented.map((name)=>invoke(pm, name).length));
|
|
3180
|
+
return documented.map((name)=>`${invoke(pm, name).padEnd(width)} # ${help[name]}`).join('\n');
|
|
3181
|
+
}
|
|
3182
|
+
/**
|
|
3183
|
+
* The command that gets this app into production, as a sentence — the README's deploy step and the closing
|
|
3184
|
+
* summary's, so the two cannot name different commands.
|
|
3185
|
+
*
|
|
3186
|
+
* Read off the scripts rather than the target, so a target that gains a `deploy` gains the sentence with it.
|
|
3187
|
+
*/ function deployStep(features, pm) {
|
|
3188
|
+
const scripts = buildScripts(features);
|
|
3189
|
+
if (scripts.deploy) return `\`${invoke(pm, 'deploy')}\` does the build and the upload in one step.`;
|
|
3190
|
+
if (scripts.start) return `\`${invoke(pm, 'start')}\` runs that build wherever you host it, and never makes one.`;
|
|
3191
|
+
if (scripts.preview) return `\`${invoke(pm, 'preview')}\` runs the build here, so you can check it first.`;
|
|
3192
|
+
return `\`${invoke(pm, 'build')}\` produces it; getting it there is yours to script.`;
|
|
3193
|
+
}
|
|
3194
|
+
|
|
3106
3195
|
;// CONCATENATED MODULE: ./src/versions.ts
|
|
3107
3196
|
|
|
3108
3197
|
/** Passed straight through, so everything generated from the framework reaches the rest of the package here. */
|
|
3109
3198
|
/** The framework range a scaffolded app gets. The two packages are released together, so this is ours. */ const RSHONO_RANGE = `^${RSHONO_VERSION}`;
|
|
3110
3199
|
/**
|
|
3111
|
-
* Versions for the optional tooling the features can add — the one place in this package where a
|
|
3112
|
-
*
|
|
3113
|
-
*
|
|
3114
|
-
* which is generated from rshono's own manifest and must not be edited here.
|
|
3200
|
+
* Versions for the optional tooling the features can add — the one place in this package where a range is typed
|
|
3201
|
+
* by hand, because the framework declares none of these. Everything a scaffolded app needs to *run* rshono comes
|
|
3202
|
+
* from {@link FRAMEWORK_DEPS}, generated from rshono's own manifest.
|
|
3115
3203
|
*
|
|
3116
|
-
*
|
|
3117
|
-
*
|
|
3118
|
-
* was last touched.
|
|
3204
|
+
* Caret ranges, not exact: these are the app's own dev tools, and a scaffold made six months from now should
|
|
3205
|
+
* pick up their patch releases.
|
|
3119
3206
|
*/ const TOOL_VERSIONS = {
|
|
3120
3207
|
tailwindcss: '^4.3.3',
|
|
3121
3208
|
'@tailwindcss/postcss': '^4.3.3',
|
|
@@ -3127,126 +3214,148 @@ const QUALITY_PRESETS = [
|
|
|
3127
3214
|
oxlint: '^1.76.0',
|
|
3128
3215
|
oxfmt: '^0.61.0',
|
|
3129
3216
|
eslint: '^10.8.0',
|
|
3130
|
-
// ESLint's
|
|
3131
|
-
//
|
|
3217
|
+
// ESLint's recommended JavaScript rules, which typescript-eslint layers on rather than replaces, and the rules
|
|
3218
|
+
// of hooks — the one class of React mistake no type checker sees.
|
|
3132
3219
|
'@eslint/js': '^10.0.1',
|
|
3133
3220
|
'typescript-eslint': '^8.65.0',
|
|
3134
3221
|
'eslint-plugin-react-hooks': '^7.1.1',
|
|
3135
3222
|
wrangler: '^4.115.0'
|
|
3136
3223
|
};
|
|
3137
3224
|
/**
|
|
3138
|
-
* The TypeScript an ESLint app pins
|
|
3139
|
-
* {@link FRAMEWORK_DEPS}
|
|
3140
|
-
*
|
|
3141
|
-
* typescript-eslint reads TypeScript's compiler API directly rather than through a stable interface, so
|
|
3142
|
-
* it accepts `typescript >=4.8.4 <6.1.0` and nothing above. `~6.0.3` is the newest that satisfies it:
|
|
3143
|
-
* patch releases of 6.0, no minor. The framework itself stays on the TypeScript it is tested against —
|
|
3144
|
-
* rshono's declarations compile the same under either, which is what makes this pin an app's business
|
|
3145
|
-
* and not the framework's.
|
|
3225
|
+
* The TypeScript an ESLint app pins in place of the framework's own — the one deliberate exception to
|
|
3226
|
+
* {@link FRAMEWORK_DEPS}.
|
|
3146
3227
|
*
|
|
3147
|
-
*
|
|
3228
|
+
* typescript-eslint reads TypeScript's compiler API directly, so it accepts `>=4.8.4 <6.1.0` and nothing above;
|
|
3229
|
+
* `~6.0.3` is the newest that satisfies it. rshono's declarations compile the same under either, which is what
|
|
3230
|
+
* makes this the app's business. When upstream widens its range, this constant is what to delete.
|
|
3148
3231
|
*/ const ESLINT_TYPESCRIPT = '~6.0.3';
|
|
3149
3232
|
|
|
3150
3233
|
;// CONCATENATED MODULE: ./src/features/deploy.ts
|
|
3151
3234
|
|
|
3235
|
+
|
|
3152
3236
|
/**
|
|
3153
|
-
* What a deploy target adds beyond the `deploy` line in `rshono.config.ts
|
|
3154
|
-
* to read, and the template's to carry.
|
|
3237
|
+
* What a deploy target adds beyond the `deploy` line in `rshono.config.ts`, which the template carries.
|
|
3155
3238
|
*
|
|
3156
|
-
*
|
|
3157
|
-
*
|
|
3158
|
-
*
|
|
3159
|
-
* be a copy that goes stale.
|
|
3239
|
+
* Thin on purpose: the framework arranges its own output for every platform, and `rshono build` writes the one
|
|
3240
|
+
* platform config that has to exist. So a target contributes the commands that run and ship the build, the CLI
|
|
3241
|
+
* they need, the directories to gitignore, and a note for the step no command covers.
|
|
3160
3242
|
*
|
|
3161
|
-
*
|
|
3162
|
-
*
|
|
3163
|
-
*
|
|
3164
|
-
*/
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
start: 'deno serve -A dist/server/main.mjs'
|
|
3185
|
-
}
|
|
3186
|
-
},
|
|
3187
|
-
cloudflare: {
|
|
3188
|
-
id: 'deploy-cloudflare',
|
|
3189
|
-
devDependencies: {
|
|
3190
|
-
wrangler: TOOL_VERSIONS.wrangler
|
|
3191
|
-
},
|
|
3192
|
-
// wrangler brings workerd, whose install script only picks the platform binary out of the optional
|
|
3193
|
-
// dependency that already carries it — `workerd --version` answers without it having run.
|
|
3194
|
-
allowBuilds: {
|
|
3195
|
-
workerd: false
|
|
3196
|
-
},
|
|
3197
|
-
scripts: {
|
|
3198
|
-
deploy: 'rshono build && wrangler deploy'
|
|
3243
|
+
* What the three script names promise is documented above `BASE_SCRIPTS` in `scripts.ts`. Only `node` has a
|
|
3244
|
+
* `start` — `rshono start` refuses a bundle built for anywhere else — and it needs no `preview`, since `build`
|
|
3245
|
+
* then `start` already is one.
|
|
3246
|
+
*/ function deployFeatures(pm) {
|
|
3247
|
+
const build = invoke(pm, 'build');
|
|
3248
|
+
return {
|
|
3249
|
+
// Where a Node build goes next is a Dockerfile or a process manager, neither of which this can guess.
|
|
3250
|
+
node: {
|
|
3251
|
+
id: 'deploy-node',
|
|
3252
|
+
scripts: {
|
|
3253
|
+
start: 'rshono start'
|
|
3254
|
+
},
|
|
3255
|
+
scriptHelp: {
|
|
3256
|
+
start: 'run the build that exists — what your host calls'
|
|
3257
|
+
},
|
|
3258
|
+
platformSetup: [
|
|
3259
|
+
'The two commands a host asks for:',
|
|
3260
|
+
'',
|
|
3261
|
+
`- **Build** — \`${pm.name} install && ${build}\``,
|
|
3262
|
+
`- **Start** — \`${invoke(pm, 'start')}\``,
|
|
3263
|
+
'',
|
|
3264
|
+
`In a Dockerfile, the same pair: \`RUN ${build}\`, then \`CMD ["${pm.name}", "start"]\`.`
|
|
3265
|
+
].join('\n')
|
|
3199
3266
|
},
|
|
3200
|
-
|
|
3201
|
-
'
|
|
3202
|
-
|
|
3203
|
-
|
|
3204
|
-
|
|
3205
|
-
|
|
3206
|
-
|
|
3207
|
-
|
|
3208
|
-
|
|
3209
|
-
|
|
3210
|
-
|
|
3267
|
+
cloudflare: {
|
|
3268
|
+
id: 'deploy-cloudflare',
|
|
3269
|
+
devDependencies: {
|
|
3270
|
+
wrangler: TOOL_VERSIONS.wrangler
|
|
3271
|
+
},
|
|
3272
|
+
// The only two install scripts a scaffolded app can end up with, and wrangler brings both. Each merely
|
|
3273
|
+
// picks the platform binary out of the optional dependency already carrying it, so neither needs to run.
|
|
3274
|
+
allowBuilds: {
|
|
3275
|
+
esbuild: false,
|
|
3276
|
+
workerd: false
|
|
3277
|
+
},
|
|
3278
|
+
// `wrangler dev` is the one preview that runs the code in workerd rather than Node. Both scripts read the
|
|
3279
|
+
// wrangler.jsonc the build wrote, so nothing here has to know where the bundle went.
|
|
3280
|
+
scripts: {
|
|
3281
|
+
preview: 'rshono build && wrangler dev',
|
|
3282
|
+
deploy: 'rshono build && wrangler deploy'
|
|
3283
|
+
},
|
|
3284
|
+
scriptHelp: {
|
|
3285
|
+
preview: 'build, then run it in workerd — port 8787',
|
|
3286
|
+
deploy: 'build, then ship it to Cloudflare'
|
|
3287
|
+
},
|
|
3288
|
+
gitignore: [
|
|
3289
|
+
'.wrangler/'
|
|
3290
|
+
],
|
|
3291
|
+
notes: [
|
|
3292
|
+
'The first build writes wrangler.jsonc — yours to edit after that.'
|
|
3293
|
+
],
|
|
3294
|
+
platformSetup: [
|
|
3295
|
+
`Building from a git repo instead: set Workers Builds' **Build command** to \`${build}\`.`,
|
|
3296
|
+
'Its deploy command already defaults to `npx wrangler deploy`, and it installs dependencies itself.'
|
|
3297
|
+
].join('\n')
|
|
3211
3298
|
},
|
|
3212
|
-
|
|
3213
|
-
'
|
|
3214
|
-
|
|
3215
|
-
|
|
3216
|
-
|
|
3217
|
-
|
|
3218
|
-
|
|
3219
|
-
|
|
3220
|
-
|
|
3221
|
-
|
|
3222
|
-
|
|
3299
|
+
vercel: {
|
|
3300
|
+
id: 'deploy-vercel',
|
|
3301
|
+
// `--prod` because the script is called `deploy`: without it the CLI uploads to a throwaway preview URL.
|
|
3302
|
+
// `preview` is a Node build run here — the platform cannot run its own prebuilt output on your machine.
|
|
3303
|
+
scripts: {
|
|
3304
|
+
preview: 'rshono build --deploy node && rshono start',
|
|
3305
|
+
deploy: `rshono build && ${pm.dlx} vercel deploy --prebuilt --prod`
|
|
3306
|
+
},
|
|
3307
|
+
scriptHelp: {
|
|
3308
|
+
preview: 'build for Node and run that here',
|
|
3309
|
+
deploy: 'build, then upload it to production'
|
|
3310
|
+
},
|
|
3311
|
+
gitignore: [
|
|
3312
|
+
'.vercel/'
|
|
3313
|
+
],
|
|
3314
|
+
notes: [
|
|
3315
|
+
'--prebuilt uploads what rshono build assembled; the platform must not rebuild it.',
|
|
3316
|
+
'Drop --prod from the deploy script for a preview URL instead.'
|
|
3317
|
+
],
|
|
3318
|
+
platformSetup: [
|
|
3319
|
+
`Deploying from CI instead: the same \`${invoke(pm, 'deploy')}\`, with \`VERCEL_ORG_ID\`, \`VERCEL_PROJECT_ID\``,
|
|
3320
|
+
'and a CLI token in the environment.',
|
|
3321
|
+
'',
|
|
3322
|
+
`If you let Vercel build the repo itself, set **Framework Preset** to Other — \`hono\` is otherwise`,
|
|
3323
|
+
`detected as the Hono preset — and **Build Command** to \`${build}\`.`
|
|
3324
|
+
].join('\n')
|
|
3223
3325
|
},
|
|
3224
|
-
|
|
3225
|
-
'
|
|
3226
|
-
|
|
3227
|
-
|
|
3228
|
-
|
|
3229
|
-
|
|
3230
|
-
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3326
|
+
'aws-lambda': {
|
|
3327
|
+
id: 'deploy-aws-lambda',
|
|
3328
|
+
// No CLI to wrap and no upload to guess at, but `preview` still applies: the bundle is a Node handler.
|
|
3329
|
+
scripts: {
|
|
3330
|
+
preview: 'rshono build --deploy node && rshono start'
|
|
3331
|
+
},
|
|
3332
|
+
scriptHelp: {
|
|
3333
|
+
preview: 'build for Node and run that here'
|
|
3334
|
+
},
|
|
3335
|
+
notes: [
|
|
3336
|
+
'Use a Function URL in RESPONSE_STREAM mode — a buffered invoke mode drops the streaming.'
|
|
3337
|
+
],
|
|
3338
|
+
platformSetup: [
|
|
3339
|
+
`There is no settings page here; the upload is yours to script. A job needs \`${pm.name} install && ${build}\`,`,
|
|
3340
|
+
'then the function package: `dist/` and nothing else, with the handler at `dist/server/main.mjs`. Your',
|
|
3341
|
+
'dependencies are compiled into the bundle for this target, so no `node_modules` is uploaded — which also',
|
|
3342
|
+
'means a native addon fails the build here rather than the deploy.'
|
|
3343
|
+
].join('\n')
|
|
3344
|
+
}
|
|
3345
|
+
};
|
|
3346
|
+
}
|
|
3347
|
+
function deployFeature(target, pm) {
|
|
3348
|
+
return deployFeatures(pm)[target];
|
|
3237
3349
|
}
|
|
3238
3350
|
|
|
3239
3351
|
;// CONCATENATED MODULE: ./src/features/quality.ts
|
|
3240
3352
|
|
|
3241
3353
|
/**
|
|
3242
|
-
* The formatter and linter features. Biome answers to both slots and appears once
|
|
3243
|
-
* deduplicates by `id
|
|
3244
|
-
* dependency and one pair of scripts.
|
|
3354
|
+
* The formatter and linter features. Biome answers to both slots and appears once, because `selectFeatures`
|
|
3355
|
+
* deduplicates by `id`.
|
|
3245
3356
|
*
|
|
3246
|
-
*
|
|
3247
|
-
*
|
|
3248
|
-
* `lint:fix` beside `lint`, for the same reason in the other direction — `lint` is already the failing
|
|
3249
|
-
* one. Biome adds a `check` of its own, which is the pair of them in a single pass.
|
|
3357
|
+
* Each brings a pair of scripts, since the writing half and the CI half want different exit codes: `format`
|
|
3358
|
+
* rewrites and `format:check` fails, `lint:fix` rewrites and `lint` fails. Biome's `check` is both in one pass.
|
|
3250
3359
|
*/ const PRETTIER = {
|
|
3251
3360
|
id: 'prettier',
|
|
3252
3361
|
overlays: [
|
|
@@ -3288,11 +3397,9 @@ const OXLINT = {
|
|
|
3288
3397
|
};
|
|
3289
3398
|
/**
|
|
3290
3399
|
* The one feature that changes a dependency the framework otherwise decides: typescript-eslint cannot be
|
|
3291
|
-
* installed alongside the TypeScript rshono is tested against, so an ESLint app pins the newest
|
|
3292
|
-
*
|
|
3293
|
-
*
|
|
3294
|
-
* The rules are type-aware, which is the reason to reach for ESLint over a syntax-only linter at all —
|
|
3295
|
-
* so the config it ships hands the whole program to the parser rather than linting file by file.
|
|
3400
|
+
* installed alongside the TypeScript rshono is tested against, so an ESLint app pins the newest its peer range
|
|
3401
|
+
* accepts (see {@link ESLINT_TYPESCRIPT}). Its rules are type-aware — the reason to reach for ESLint at all —
|
|
3402
|
+
* so the config it ships hands the parser the whole program.
|
|
3296
3403
|
*/ const ESLINT = {
|
|
3297
3404
|
id: 'eslint',
|
|
3298
3405
|
overlays: [
|
|
@@ -3308,6 +3415,12 @@ const OXLINT = {
|
|
|
3308
3415
|
scripts: {
|
|
3309
3416
|
lint: 'eslint .',
|
|
3310
3417
|
'lint:fix': 'eslint . --fix'
|
|
3418
|
+
},
|
|
3419
|
+
// The pin is invisible from the command line, and its consequence is not: the rules reason about the
|
|
3420
|
+
// program through an older compiler than the one that builds it, so a fix can produce code `tsc` rejects.
|
|
3421
|
+
// The generated eslint.config.mjs explains why; the README's table is where someone reads what to type.
|
|
3422
|
+
scriptHelp: {
|
|
3423
|
+
'lint:fix': 'apply what it can — then run typecheck, see eslint.config.mjs'
|
|
3311
3424
|
}
|
|
3312
3425
|
};
|
|
3313
3426
|
const BIOME = {
|
|
@@ -3348,14 +3461,12 @@ function linterFeature(linter) {
|
|
|
3348
3461
|
;// CONCATENATED MODULE: ./src/features/styling.ts
|
|
3349
3462
|
|
|
3350
3463
|
/**
|
|
3351
|
-
* Tailwind is a PostCSS plugin and nothing more, which is the whole of this feature: four packages,
|
|
3352
|
-
*
|
|
3353
|
-
*
|
|
3354
|
-
* written in utilities instead of classes of their own.
|
|
3464
|
+
* Tailwind is a PostCSS plugin and nothing more, which is the whole of this feature: four packages, plus an
|
|
3465
|
+
* overlay carrying `postcss.config.mjs`, an `rshono.config.ts` whose `rspack` hook puts postcss-loader in front
|
|
3466
|
+
* of the CSS parser, a Tailwind entry stylesheet, and the two views rewritten in utilities.
|
|
3355
3467
|
*
|
|
3356
|
-
* `postcss`
|
|
3357
|
-
*
|
|
3358
|
-
* install one.
|
|
3468
|
+
* `postcss` is the app's dependency rather than the framework's: rshono compiles CSS natively, so an app that
|
|
3469
|
+
* wants no plugin chain installs none.
|
|
3359
3470
|
*/ const TAILWIND = {
|
|
3360
3471
|
id: 'tailwind',
|
|
3361
3472
|
overlays: [
|
|
@@ -3378,12 +3489,14 @@ function stylingFeature(styling) {
|
|
|
3378
3489
|
|
|
3379
3490
|
|
|
3380
3491
|
/**
|
|
3381
|
-
* The features a set of answers selects, in application order — so an overlay listed later wins a file
|
|
3382
|
-
*
|
|
3383
|
-
*
|
|
3384
|
-
|
|
3492
|
+
* The features a set of answers selects, in application order — so an overlay listed later wins a file both
|
|
3493
|
+
* ship. Deduplicated by `id`, which is what lets one feature answer two questions (Biome is both formatter and
|
|
3494
|
+
* linter) without contributing twice.
|
|
3495
|
+
*
|
|
3496
|
+
* `pm` reaches the deploy target because one script has to name the runner that fetches an uninstalled CLI.
|
|
3497
|
+
*/ function selectFeatures(answers, pm) {
|
|
3385
3498
|
const selected = [
|
|
3386
|
-
deployFeature(answers.deploy),
|
|
3499
|
+
deployFeature(answers.deploy, pm),
|
|
3387
3500
|
stylingFeature(answers.styling),
|
|
3388
3501
|
formatterFeature(answers.formatter),
|
|
3389
3502
|
linterFeature(answers.linter),
|
|
@@ -3401,15 +3514,7 @@ function stylingFeature(styling) {
|
|
|
3401
3514
|
|
|
3402
3515
|
;// CONCATENATED MODULE: ./src/pkg.ts
|
|
3403
3516
|
|
|
3404
|
-
|
|
3405
|
-
* The scripts every app gets. `start` is not among them, because it means something different per
|
|
3406
|
-
* platform: the three targets that run the build themselves — node, bun, deno — each contribute their
|
|
3407
|
-
* own, and a platform target contributes a `deploy` instead, where its platform has one command to give.
|
|
3408
|
-
*/ const BASE_SCRIPTS = {
|
|
3409
|
-
dev: 'rshono dev',
|
|
3410
|
-
build: 'rshono build',
|
|
3411
|
-
typecheck: 'tsc --noEmit'
|
|
3412
|
-
};
|
|
3517
|
+
|
|
3413
3518
|
/** Field order in the emitted file — the conventional reading order, and stable so snapshots are too. */ const FIELD_ORDER = [
|
|
3414
3519
|
'name',
|
|
3415
3520
|
'version',
|
|
@@ -3425,48 +3530,29 @@ function sorted(record) {
|
|
|
3425
3530
|
return Object.fromEntries(Object.entries(record).sort(([a], [b])=>a < b ? -1 : 1));
|
|
3426
3531
|
}
|
|
3427
3532
|
/**
|
|
3428
|
-
*
|
|
3429
|
-
* reads `rshono.config.ts` through esbuild, and esbuild's script only picks the platform binary out of
|
|
3430
|
-
* the optional dependency that already carries it — rshono's own repo denies it for the same reason.
|
|
3431
|
-
*/ const BASE_ALLOW_BUILDS = {
|
|
3432
|
-
esbuild: false
|
|
3433
|
-
};
|
|
3434
|
-
/**
|
|
3435
|
-
* pnpm's settings for the new app — written for pnpm and for nobody else.
|
|
3436
|
-
*
|
|
3437
|
-
* It exists for one field. A dependency with an install script is a question pnpm will not answer on its
|
|
3438
|
-
* own: it fails the install, and fails every `pnpm dev` after it, until the project has said whether the
|
|
3439
|
-
* script should run. None of the ones an rshono app inherits need to (each is a native package whose
|
|
3440
|
-
* binary arrives as an optional dependency), so a fresh app carries the answer rather than meeting
|
|
3441
|
-
* `pnpm approve-builds` before it has rendered a page once.
|
|
3533
|
+
* pnpm's settings for the new app, or `null` when no feature has anything to put in them.
|
|
3442
3534
|
*
|
|
3443
|
-
*
|
|
3444
|
-
*
|
|
3445
|
-
*
|
|
3535
|
+
* It exists for one field, `allowBuilds`: pnpm fails an install until the project has said whether a
|
|
3536
|
+
* dependency's install script should run. Nothing rshono installs has one, so most apps get no file. A file
|
|
3537
|
+
* rather than a `pnpm` key in `package.json`, which pnpm 11 no longer reads.
|
|
3446
3538
|
*/ function buildPnpmSettings(features) {
|
|
3447
|
-
const allowBuilds = {
|
|
3448
|
-
...BASE_ALLOW_BUILDS
|
|
3449
|
-
};
|
|
3539
|
+
const allowBuilds = {};
|
|
3450
3540
|
for (const feature of features)Object.assign(allowBuilds, feature.allowBuilds);
|
|
3541
|
+
const entries = Object.entries(sorted(allowBuilds));
|
|
3542
|
+
if (entries.length === 0) return null;
|
|
3451
3543
|
return [
|
|
3452
3544
|
'# Which dependencies may run an install script. pnpm runs none it has not been told about, and',
|
|
3453
3545
|
'# fails the install rather than skip one quietly — so anything added later belongs here too.',
|
|
3454
3546
|
'# `false` means the script was looked at: these ship their real binary as an optional dependency.',
|
|
3455
3547
|
'allowBuilds:',
|
|
3456
|
-
...
|
|
3548
|
+
...entries.map(([name, allowed])=>` ${name}: ${allowed}`),
|
|
3457
3549
|
''
|
|
3458
3550
|
].join('\n');
|
|
3459
3551
|
}
|
|
3460
3552
|
/**
|
|
3461
|
-
* Assembles `package.json` from the answers and whatever the selected features contribute.
|
|
3462
|
-
*
|
|
3463
|
-
* Dependencies are sorted by name and scripts are left in contribution order (the base ones, then each
|
|
3464
|
-
* feature's, in the order features were selected) — so two runs with the same answers produce byte-
|
|
3465
|
-
* identical output, which is what makes the generated manifest snapshot-testable.
|
|
3553
|
+
* Assembles `package.json` from the answers and whatever the selected features contribute. Dependencies are
|
|
3554
|
+
* sorted and scripts keep {@link buildScripts}'s order, so two runs with the same answers are byte-identical.
|
|
3466
3555
|
*/ function buildPackageJson(answers, features, pm) {
|
|
3467
|
-
const scripts = {
|
|
3468
|
-
...BASE_SCRIPTS
|
|
3469
|
-
};
|
|
3470
3556
|
const dependencies = {
|
|
3471
3557
|
'@rshono/core': RSHONO_RANGE,
|
|
3472
3558
|
hono: FRAMEWORK_DEPS.hono,
|
|
@@ -3479,7 +3565,6 @@ function sorted(record) {
|
|
|
3479
3565
|
typescript: FRAMEWORK_DEPS.typescript
|
|
3480
3566
|
};
|
|
3481
3567
|
for (const feature of features){
|
|
3482
|
-
Object.assign(scripts, feature.scripts);
|
|
3483
3568
|
Object.assign(dependencies, feature.dependencies);
|
|
3484
3569
|
Object.assign(devDependencies, feature.devDependencies);
|
|
3485
3570
|
}
|
|
@@ -3492,12 +3577,12 @@ function sorted(record) {
|
|
|
3492
3577
|
engines: {
|
|
3493
3578
|
node: NODE_ENGINE
|
|
3494
3579
|
},
|
|
3495
|
-
scripts,
|
|
3580
|
+
scripts: buildScripts(features),
|
|
3496
3581
|
dependencies: sorted(dependencies),
|
|
3497
3582
|
devDependencies: sorted(devDependencies)
|
|
3498
3583
|
};
|
|
3499
|
-
// Only when the environment told us the exact version:
|
|
3500
|
-
//
|
|
3584
|
+
// Only when the environment told us the exact version: this field pins the tool for Corepack, and a guess is
|
|
3585
|
+
// worse than leaving it out.
|
|
3501
3586
|
if (pm.version) manifest.packageManager = `${pm.name}@${pm.version}`;
|
|
3502
3587
|
const ordered = Object.fromEntries(FIELD_ORDER.filter((field)=>field in manifest).map((field)=>[
|
|
3503
3588
|
field,
|
|
@@ -3509,23 +3594,22 @@ function sorted(record) {
|
|
|
3509
3594
|
;// CONCATENATED MODULE: ./src/render.ts
|
|
3510
3595
|
|
|
3511
3596
|
/**
|
|
3512
|
-
* `{{NAME}}`,
|
|
3513
|
-
*
|
|
3514
|
-
* turns a token into literal text that no substitution will ever match again. `{{…}}` means nothing to
|
|
3515
|
-
* any of the formats these templates are written in.
|
|
3597
|
+
* `{{NAME}}`, not `__NAME__`: in markdown the latter is strong emphasis, so Prettier rewrites it to `**NAME**`
|
|
3598
|
+
* and the token stops matching. `{{…}}` means nothing to any format these templates are written in.
|
|
3516
3599
|
*/ const TOKEN_PATTERN = /\{\{[A-Z][A-Z\d_]*\}\}/g;
|
|
3517
|
-
function tokensFor(answers, pm) {
|
|
3600
|
+
function tokensFor(answers, features, pm) {
|
|
3518
3601
|
return {
|
|
3519
3602
|
'{{PROJECT_NAME}}': answers.packageName,
|
|
3520
3603
|
'{{DEPLOY_TARGET}}': answers.deploy,
|
|
3521
|
-
|
|
3522
|
-
'{{
|
|
3604
|
+
// From the features rather than the answers, because all three are about the scripts the app actually got.
|
|
3605
|
+
'{{SCRIPT_TABLE}}': scriptTable(answers, features, pm),
|
|
3606
|
+
'{{DEPLOY_STEP}}': deployStep(features, pm),
|
|
3607
|
+
'{{PLATFORM_SETUP}}': features.map((feature)=>feature.platformSetup ?? '').join('')
|
|
3523
3608
|
};
|
|
3524
3609
|
}
|
|
3525
3610
|
/**
|
|
3526
|
-
* Substitutes tokens, and throws on one it
|
|
3527
|
-
*
|
|
3528
|
-
* catch.
|
|
3611
|
+
* Substitutes tokens, and throws on one it does not know — a typo in a template would otherwise ship a literal
|
|
3612
|
+
* `{{PORJECT_NAME}}` into somebody's new app, which no test of the generator's logic would catch.
|
|
3529
3613
|
*/ function render(contents, tokens, source) {
|
|
3530
3614
|
return contents.replace(TOKEN_PATTERN, (token)=>{
|
|
3531
3615
|
const value = tokens[token];
|
|
@@ -3555,12 +3639,9 @@ function readTemplateDir(dir) {
|
|
|
3555
3639
|
return files;
|
|
3556
3640
|
}
|
|
3557
3641
|
/**
|
|
3558
|
-
* `_gitignore` → `.gitignore`, and so on for every dotfile
|
|
3559
|
-
*
|
|
3560
|
-
*
|
|
3561
|
-
* one — the file would exist in the repo, pass every local test, and be missing from the package
|
|
3562
|
-
* everybody actually installs. Naming them with an underscore and renaming here is the long-standing
|
|
3563
|
-
* fix. It applies to the basename only, so `src/lib/_x.ts` is a dotfile but `templates/_x/y.ts` is not.
|
|
3642
|
+
* `_gitignore` → `.gitignore`, and so on for every dotfile: npm strips a literal `.gitignore` out of a
|
|
3643
|
+
* published tarball, so a template that contained one would pass every local test and be missing from the
|
|
3644
|
+
* package everybody installs. The basename only, so `templates/_x/y.ts` is left alone.
|
|
3564
3645
|
*/ function undotted(path) {
|
|
3565
3646
|
const segments = path.split(posix.sep);
|
|
3566
3647
|
const name = segments.pop();
|
|
@@ -3569,22 +3650,19 @@ function readTemplateDir(dir) {
|
|
|
3569
3650
|
name.startsWith('_') ? `.${name.slice(1)}` : name
|
|
3570
3651
|
].join(posix.sep);
|
|
3571
3652
|
}
|
|
3572
|
-
/**
|
|
3573
|
-
* A feature's `.gitignore` lines, appended under a heading naming it — so somebody reading the file six
|
|
3574
|
-
* months later can tell why `.wrangler/` is in there.
|
|
3575
|
-
*/ function appendGitignore(existing, features) {
|
|
3653
|
+
/** A feature's `.gitignore` lines, under a heading naming it — so a reader can tell why `.wrangler/` is there. */ function appendGitignore(existing, features) {
|
|
3576
3654
|
const additions = features.filter((feature)=>feature.gitignore?.length);
|
|
3577
3655
|
if (additions.length === 0) return existing;
|
|
3578
3656
|
const blocks = additions.map((feature)=>`\n# ${feature.id}\n${feature.gitignore.join('\n')}\n`);
|
|
3579
3657
|
return existing + blocks.join('');
|
|
3580
3658
|
}
|
|
3581
3659
|
/**
|
|
3582
|
-
* Turns answers into the exact set of files to write, without touching the target directory
|
|
3583
|
-
* decisions
|
|
3584
|
-
*
|
|
3660
|
+
* Turns answers into the exact set of files to write, without touching the target directory. Separating the
|
|
3661
|
+
* decisions from the I/O is what lets a test assert on the whole matrix of answers, and makes `--dry-run` the
|
|
3662
|
+
* same code path minus the last step.
|
|
3585
3663
|
*/ function plan_plan(answers, pm) {
|
|
3586
|
-
const features = selectFeatures(answers);
|
|
3587
|
-
const tokens = tokensFor(answers, pm);
|
|
3664
|
+
const features = selectFeatures(answers, pm);
|
|
3665
|
+
const tokens = tokensFor(answers, features, pm);
|
|
3588
3666
|
const raw = readTemplateDir(external_node_path_join(TEMPLATES_DIR, 'base'));
|
|
3589
3667
|
for (const feature of features){
|
|
3590
3668
|
for (const overlay of feature.overlays ?? []){
|
|
@@ -3600,7 +3678,9 @@ function readTemplateDir(dir) {
|
|
|
3600
3678
|
const gitignore = files.get('.gitignore');
|
|
3601
3679
|
if (gitignore) files.set('.gitignore', appendGitignore(gitignore, features));
|
|
3602
3680
|
files.set('package.json', buildPackageJson(answers, features, pm));
|
|
3603
|
-
|
|
3681
|
+
// Only for pnpm, and only when a feature brought an install script to answer for — see `buildPnpmSettings`.
|
|
3682
|
+
const pnpmSettings = pm.name === 'pnpm' ? buildPnpmSettings(features) : null;
|
|
3683
|
+
if (pnpmSettings) files.set('pnpm-workspace.yaml', pnpmSettings);
|
|
3604
3684
|
return {
|
|
3605
3685
|
// Sorted, so both the write order and a test's snapshot are stable.
|
|
3606
3686
|
files: new Map([
|
|
@@ -3632,6 +3712,12 @@ const RUN = {
|
|
|
3632
3712
|
yarn: 'yarn',
|
|
3633
3713
|
bun: 'bun'
|
|
3634
3714
|
};
|
|
3715
|
+
const DLX = {
|
|
3716
|
+
npm: 'npx',
|
|
3717
|
+
pnpm: 'pnpm dlx',
|
|
3718
|
+
yarn: 'yarn dlx',
|
|
3719
|
+
bun: 'bunx'
|
|
3720
|
+
};
|
|
3635
3721
|
function isKnown(name) {
|
|
3636
3722
|
return PACKAGE_MANAGERS.includes(name);
|
|
3637
3723
|
}
|
|
@@ -3640,15 +3726,14 @@ function packageManager(name, version) {
|
|
|
3640
3726
|
name,
|
|
3641
3727
|
version,
|
|
3642
3728
|
install: INSTALL[name],
|
|
3643
|
-
run: RUN[name]
|
|
3729
|
+
run: RUN[name],
|
|
3730
|
+
dlx: DLX[name]
|
|
3644
3731
|
};
|
|
3645
3732
|
}
|
|
3646
3733
|
/**
|
|
3647
|
-
* Which package manager invoked us.
|
|
3648
|
-
*
|
|
3649
|
-
*
|
|
3650
|
-
*
|
|
3651
|
-
* Falls back to npm, which is also what a bare `node bin/create-rshono.mjs` gets.
|
|
3734
|
+
* Which package manager invoked us. All four set `npm_config_user_agent` on the process they spawn — `pnpm/11.9.0
|
|
3735
|
+
* npm/? node/v22.14.0 darwin arm64` — so `pnx @rshono/create` scaffolds a pnpm project without asking, exact
|
|
3736
|
+
* version included. Falls back to npm, which is also what a bare `node bin/create-rshono.mjs` gets.
|
|
3652
3737
|
*/ function detectPackageManager(userAgent = process.env.npm_config_user_agent) {
|
|
3653
3738
|
const [spec] = (userAgent ?? '').split(' ');
|
|
3654
3739
|
const [name, version] = (spec ?? '').split('/');
|
|
@@ -3656,18 +3741,11 @@ function packageManager(name, version) {
|
|
|
3656
3741
|
return packageManager('npm');
|
|
3657
3742
|
}
|
|
3658
3743
|
/**
|
|
3659
|
-
* Runs the install, streaming its output. `shell: true` on Windows
|
|
3660
|
-
*
|
|
3661
|
-
* are all fixed strings from the tables above, never anything the user typed.
|
|
3744
|
+
* Runs the install, streaming its output. `shell: true` on Windows, where npm, pnpm and yarn are `.cmd` shims
|
|
3745
|
+
* `spawn` cannot execute directly — safe because every argument is a fixed string from the tables above.
|
|
3662
3746
|
*/ function runInstall(pm, cwd) {
|
|
3663
3747
|
return run(pm, pm.install, cwd);
|
|
3664
3748
|
}
|
|
3665
|
-
/** `<pm> run <script>` — the one form every package manager accepts, Yarn v1 included. */ function runScript(pm, script, cwd) {
|
|
3666
|
-
return run(pm, [
|
|
3667
|
-
'run',
|
|
3668
|
-
script
|
|
3669
|
-
], cwd);
|
|
3670
|
-
}
|
|
3671
3749
|
function run(pm, args, cwd) {
|
|
3672
3750
|
const result = spawnSync(pm.name, args, {
|
|
3673
3751
|
cwd,
|
|
@@ -3680,9 +3758,19 @@ function run(pm, args, cwd) {
|
|
|
3680
3758
|
;// CONCATENATED MODULE: ./src/ui.ts
|
|
3681
3759
|
|
|
3682
3760
|
|
|
3761
|
+
|
|
3762
|
+
/**
|
|
3763
|
+
* The two halves of the closing line, in the words of the app's own scripts: what produces something shippable,
|
|
3764
|
+
* and where it goes from there. A target with no command to give falls back to the framework's hint.
|
|
3765
|
+
*/ function productionSteps(answers, plan, pm) {
|
|
3766
|
+
const scripts = buildScripts(plan.features);
|
|
3767
|
+
const check = scripts.preview ? `${invoke(pm, 'preview')} to run the production build` : `${pm.run} build`;
|
|
3768
|
+
const ship = scripts.deploy ? `${invoke(pm, 'deploy')} to ship it` : scripts.start ? `${invoke(pm, 'start')} on the host that runs it` : deployHint(answers.deploy);
|
|
3769
|
+
return `${check}, and ${ship}`;
|
|
3770
|
+
}
|
|
3683
3771
|
/**
|
|
3684
|
-
* What to do next, in the order to do it — the last thing the user reads
|
|
3685
|
-
*
|
|
3772
|
+
* What to do next, in the order to do it — the last thing the user reads. `installed` decides whether the install
|
|
3773
|
+
* step is still theirs.
|
|
3686
3774
|
*/ function nextSteps(answers, plan, pm, options) {
|
|
3687
3775
|
const steps = [];
|
|
3688
3776
|
if (options.directory !== '.') steps.push(`cd ${options.directory}`);
|
|
@@ -3691,7 +3779,7 @@ function run(pm, args, cwd) {
|
|
|
3691
3779
|
const lines = [
|
|
3692
3780
|
steps.join('\n')
|
|
3693
3781
|
];
|
|
3694
|
-
lines.push(`\nThen ${
|
|
3782
|
+
lines.push(`\nThen ${productionSteps(answers, plan, pm)}.`);
|
|
3695
3783
|
if (plan.notes.length > 0) lines.push(`\n${plan.notes.join('\n')}`);
|
|
3696
3784
|
return lines.join('\n');
|
|
3697
3785
|
}
|
|
@@ -3717,10 +3805,7 @@ function run(pm, args, cwd) {
|
|
|
3717
3805
|
;// CONCATENATED MODULE: ./src/write.ts
|
|
3718
3806
|
|
|
3719
3807
|
|
|
3720
|
-
/**
|
|
3721
|
-
* Files that do not make a directory "occupied". A user who ran `git init` or opened the folder in an
|
|
3722
|
-
* editor before scaffolding has not put anything in it that we would overwrite.
|
|
3723
|
-
*/ const IGNORED_ENTRIES = new Set([
|
|
3808
|
+
/** Files that do not make a directory "occupied": a `git init` or an editor has put nothing there to overwrite. */ const IGNORED_ENTRIES = new Set([
|
|
3724
3809
|
'.git',
|
|
3725
3810
|
'.DS_Store',
|
|
3726
3811
|
'.idea',
|
|
@@ -3728,12 +3813,9 @@ function run(pm, args, cwd) {
|
|
|
3728
3813
|
'Thumbs.db'
|
|
3729
3814
|
]);
|
|
3730
3815
|
/**
|
|
3731
|
-
* What is already at the target path,
|
|
3732
|
-
*
|
|
3733
|
-
*
|
|
3734
|
-
* A path that does not exist yet is no conflict. A path that exists and is *not* a directory is not
|
|
3735
|
-
* something `--force` should be able to write into, so it throws rather than reporting an empty list —
|
|
3736
|
-
* otherwise `create-rshono README.md` gets as far as `mkdir` before failing on a raw ENOTDIR.
|
|
3816
|
+
* What is already at the target path, ignoring the entries a fresh clone or an editor leaves behind — which is
|
|
3817
|
+
* what decides whether scaffolding into it is safe. A path that does not exist yet is no conflict; one that
|
|
3818
|
+
* exists and is not a directory throws, since `--force` should not write into it either.
|
|
3737
3819
|
*/ function conflictingEntries(dir) {
|
|
3738
3820
|
const stats = statSync(dir, {
|
|
3739
3821
|
throwIfNoEntry: false
|
|
@@ -3743,8 +3825,8 @@ function run(pm, args, cwd) {
|
|
|
3743
3825
|
return external_node_fs_readdirSync(dir).filter((entry)=>!IGNORED_ENTRIES.has(entry));
|
|
3744
3826
|
}
|
|
3745
3827
|
/**
|
|
3746
|
-
* Writes the plan
|
|
3747
|
-
*
|
|
3828
|
+
* Writes the plan, creating directories as needed and keeping the plan's own ordering — so a failure part-way
|
|
3829
|
+
* through leaves something a person can make sense of.
|
|
3748
3830
|
*/ function writePlan(plan, targetDir) {
|
|
3749
3831
|
mkdirSync(targetDir, {
|
|
3750
3832
|
recursive: true
|
|
@@ -3773,7 +3855,7 @@ const DEFAULT_DIRECTORY = 'my-rshono-app';
|
|
|
3773
3855
|
/** Every accepted name comes from `options.ts`, so the help cannot promise one the validation refuses. */ const HELP = `create-rshono — scaffold a new rshono app
|
|
3774
3856
|
|
|
3775
3857
|
Usage:
|
|
3776
|
-
|
|
3858
|
+
npx @rshono/create@latest [directory] [options]
|
|
3777
3859
|
|
|
3778
3860
|
Options:
|
|
3779
3861
|
-y, --yes accept the default for every question not given as a flag
|
|
@@ -3793,7 +3875,7 @@ Options:
|
|
|
3793
3875
|
Every question can be answered by a flag, and a non-interactive terminal implies --yes — so one command
|
|
3794
3876
|
scaffolds without prompting:
|
|
3795
3877
|
|
|
3796
|
-
|
|
3878
|
+
npx @rshono/create@latest my-app -y --deploy cloudflare --tailwind --quality biome
|
|
3797
3879
|
`;
|
|
3798
3880
|
function fail(message) {
|
|
3799
3881
|
log.error(message);
|
|
@@ -3810,11 +3892,7 @@ function fail(message) {
|
|
|
3810
3892
|
if (off) return false;
|
|
3811
3893
|
return undefined;
|
|
3812
3894
|
}
|
|
3813
|
-
/**
|
|
3814
|
-
* `parseArgs` rejects an unknown flag with a message that names it but nothing else — so a mistyped
|
|
3815
|
-
* `--tailwnid` reads as a wall of text about positional arguments. Pointing at `--help` is the whole
|
|
3816
|
-
* addition.
|
|
3817
|
-
*/ function parse() {
|
|
3895
|
+
/** `parseArgs` names an unknown flag but says nothing about what to do next; this points at `--help`. */ function parse() {
|
|
3818
3896
|
try {
|
|
3819
3897
|
return parseArgs({
|
|
3820
3898
|
options: {
|
|
@@ -3880,12 +3958,10 @@ function fail(message) {
|
|
|
3880
3958
|
async function main() {
|
|
3881
3959
|
const { values, positionals } = parse();
|
|
3882
3960
|
if (values.help) return console.log(HELP);
|
|
3883
|
-
if (values.version) return console.log("1.0.0-rc.
|
|
3884
|
-
|
|
3885
|
-
|
|
3886
|
-
|
|
3887
|
-
* stdout still attached would otherwise ask a question with nothing behind the keyboard.
|
|
3888
|
-
*/ const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY) && !values.yes;
|
|
3961
|
+
if (values.version) return console.log("1.0.0-rc.21");
|
|
3962
|
+
// A pipe, a CI job or an agent gets the defaults rather than a prompt nothing can answer. Both streams have to
|
|
3963
|
+
// be a terminal: the prompts draw on stdout but read from stdin.
|
|
3964
|
+
const interactive = Boolean(process.stdin.isTTY && process.stdout.isTTY) && !values.yes;
|
|
3889
3965
|
const pmFlag = oneOf(values.pm, PACKAGE_MANAGERS, 'pm');
|
|
3890
3966
|
const pm = pmFlag ? packageManager(pmFlag) : detectPackageManager();
|
|
3891
3967
|
const deployFlag = oneOf(values.deploy, DEPLOY_TARGET_NAMES, 'deploy');
|
|
@@ -3895,8 +3971,7 @@ async function main() {
|
|
|
3895
3971
|
const tailwindFlag = tristate(values.tailwind, values['no-tailwind'], 'tailwind');
|
|
3896
3972
|
const installFlag = tristate(values.install, values['no-install'], 'install');
|
|
3897
3973
|
const gitFlag = tristate(values.git, values['no-git'], 'git');
|
|
3898
|
-
// The framework version, not this package's: it is the one the app
|
|
3899
|
-
// worth reading here. `--version` reports create-rshono's own.
|
|
3974
|
+
// The framework version, not this package's: it is the one the app gets pinned to. `--version` reports ours.
|
|
3900
3975
|
intro(`create-rshono · rshono ${RSHONO_VERSION}`);
|
|
3901
3976
|
// ── Where ───────────────────────────────────────────────────────────────────────────────────────
|
|
3902
3977
|
let directory = positionals[0];
|
|
@@ -3909,11 +3984,17 @@ async function main() {
|
|
|
3909
3984
|
})) : DEFAULT_DIRECTORY;
|
|
3910
3985
|
}
|
|
3911
3986
|
const targetDir = resolve(process.cwd(), directory);
|
|
3912
|
-
|
|
3913
|
-
|
|
3914
|
-
|
|
3987
|
+
// Resolved rather than compared as text: `.`, `./`, `foo/..` and the cwd's own absolute path all name this
|
|
3988
|
+
// directory, and its own basename is the only thing left to call the package. Matching the literal `'.'`
|
|
3989
|
+
// covered one spelling and left `./` failing on "does not give a usable npm package name".
|
|
3990
|
+
const intoCwd = targetDir === process.cwd();
|
|
3991
|
+
const packageName = toPackageName(intoCwd ? basename(targetDir) : directory);
|
|
3992
|
+
if (!packageName) fail(`"${directory}" does not give a usable npm package name.`);
|
|
3993
|
+
// Not under --dry-run: nothing is written, so there is nothing to conflict with, and the advice it would
|
|
3994
|
+
// give (`--force`) describes an action the user did not ask for.
|
|
3995
|
+
const conflicts = values['dry-run'] ? [] : conflictingEntries(targetDir);
|
|
3915
3996
|
if (conflicts.length > 0 && !values.force) {
|
|
3916
|
-
const where =
|
|
3997
|
+
const where = intoCwd ? 'this directory' : `"${directory}"`;
|
|
3917
3998
|
const listed = `${conflicts.slice(0, 3).join(', ')}${conflicts.length > 3 ? ', …' : ''}`;
|
|
3918
3999
|
if (!interactive) fail(`${where} is not empty (${listed}) — pass --force to scaffold into it anyway.`);
|
|
3919
4000
|
const proceed = unwrap(await dist_confirm({
|
|
@@ -3956,10 +4037,9 @@ async function main() {
|
|
|
3956
4037
|
]
|
|
3957
4038
|
}));
|
|
3958
4039
|
}
|
|
3959
|
-
|
|
3960
|
-
|
|
3961
|
-
|
|
3962
|
-
*/ let preset = QUALITY_PRESETS.find((candidate)=>candidate.id === qualityFlag);
|
|
4040
|
+
// One question instead of two; the axes stay independent underneath, and a `--formatter` or `--linter` flag
|
|
4041
|
+
// addresses either on its own.
|
|
4042
|
+
let preset = QUALITY_PRESETS.find((candidate)=>candidate.id === qualityFlag);
|
|
3963
4043
|
if (!preset && !formatterFlag && !linterFlag) {
|
|
3964
4044
|
const fallback = QUALITY_PRESETS["0"];
|
|
3965
4045
|
if (interactive) {
|
|
@@ -4020,16 +4100,6 @@ async function main() {
|
|
|
4020
4100
|
installed = runInstall(pm, targetDir);
|
|
4021
4101
|
if (!installed) log.warn(`${pm.name} install failed — the files are all written, so run it yourself in the project.`);
|
|
4022
4102
|
}
|
|
4023
|
-
/*
|
|
4024
|
-
* Format the scaffold with the tool it was scaffolded with, so a fresh project passes its own
|
|
4025
|
-
* `format:check` instead of reporting a diff nobody made. Needs the install, since the formatter is a
|
|
4026
|
-
* devDependency — hence the skip, rather than a failure, when there is none.
|
|
4027
|
-
*
|
|
4028
|
-
* Whether there is a `format` script is the plan's answer, not the formatter answer's: `--formatter
|
|
4029
|
-
* none --linter biome` has no formatter and a `format` script all the same, because Biome brings one.
|
|
4030
|
-
*/ if (installed && plan.features.some((feature)=>feature.scripts?.format)) {
|
|
4031
|
-
if (!runScript(pm, 'format', targetDir)) log.warn(`\`${pm.run} format\` failed — the scaffold is written, just not formatted.`);
|
|
4032
|
-
}
|
|
4033
4103
|
if (git) {
|
|
4034
4104
|
if (!hasGit(targetDir)) {
|
|
4035
4105
|
log.warn('git was not found on PATH — skipped.');
|