create-absolutejs 0.0.6 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/index.js +1416 -168
  2. package/package.json +15 -9
package/dist/index.js CHANGED
@@ -145,14 +145,15 @@ var require_picocolors = __commonJS((exports, module) => {
145
145
  module.exports.createColors = createColors;
146
146
  });
147
147
 
148
- // index.ts
149
- import { argv, exit } from "node:process";
148
+ // src/index.ts
149
+ import { argv, exit as exit4 } from "node:process";
150
150
  import { parseArgs } from "node:util";
151
151
 
152
152
  // node_modules/@clack/core/dist/index.mjs
153
153
  var import_sisteransi = __toESM(require_src(), 1);
154
- import { stdin as j, stdout as M } from "node:process";
155
154
  var import_picocolors = __toESM(require_picocolors(), 1);
155
+ import { stdin as j, stdout as M } from "node:process";
156
+ import * as g from "node:readline";
156
157
  import O from "node:readline";
157
158
  import { Writable as X } from "node:stream";
158
159
  function DD({ onlyFirst: e = false } = {}) {
@@ -385,6 +386,28 @@ function m(e, u) {
385
386
  const t = e;
386
387
  t.isTTY && t.setRawMode(u);
387
388
  }
389
+ function fD({ input: e = j, output: u = M, overwrite: t = true, hideCursor: F = true } = {}) {
390
+ const s = g.createInterface({ input: e, output: u, prompt: "", tabSize: 1 });
391
+ g.emitKeypressEvents(e, s), e.isTTY && e.setRawMode(true);
392
+ const i = (D, { name: r, sequence: n }) => {
393
+ const E = String(D);
394
+ if ($([E, r, n], "cancel")) {
395
+ F && u.write(import_sisteransi.cursor.show), process.exit(0);
396
+ return;
397
+ }
398
+ if (!t)
399
+ return;
400
+ const a = r === "return" ? 0 : -1, o = r === "return" ? -1 : 0;
401
+ g.moveCursor(u, a, o, () => {
402
+ g.clearLine(u, 1, () => {
403
+ e.once("keypress", i);
404
+ });
405
+ });
406
+ };
407
+ return F && u.write(import_sisteransi.cursor.hide), e.once("keypress", i), () => {
408
+ e.off("keypress", i), F && u.write(import_sisteransi.cursor.show), e.isTTY && !AD && e.setRawMode(false), s.terminal = false, s.close();
409
+ };
410
+ }
388
411
  var gD = Object.defineProperty;
389
412
  var vD = (e, u, t) => (u in e) ? gD(e, u, { enumerable: true, configurable: true, writable: true, value: t }) : e[u] = t;
390
413
  var h = (e, u, t) => (vD(e, typeof u != "symbol" ? u + "" : u, t), t);
@@ -483,6 +506,24 @@ class x {
483
506
  }
484
507
  }
485
508
  }
509
+
510
+ class dD extends x {
511
+ get cursor() {
512
+ return this.value ? 0 : 1;
513
+ }
514
+ get _value() {
515
+ return this.cursor === 0;
516
+ }
517
+ constructor(u) {
518
+ super(u, false), this.value = !!u.initialValue, this.on("value", () => {
519
+ this.value = this._value;
520
+ }), this.on("confirm", (t) => {
521
+ this.output.write(import_sisteransi.cursor.move(0, -1)), this.value = t, this.state = "submit", this.close();
522
+ }), this.on("cursor", () => {
523
+ this.value = !this.value;
524
+ });
525
+ }
526
+ }
486
527
  var A;
487
528
  A = new WeakMap;
488
529
  var kD = Object.defineProperty;
@@ -613,9 +654,9 @@ var G2 = (t) => {
613
654
  const { cursor: n, options: r, style: i } = t, s = t.maxItems ?? Number.POSITIVE_INFINITY, c = Math.max(process.stdout.rows - 4, 0), a = Math.min(c, Math.max(s, 5));
614
655
  let l2 = 0;
615
656
  n >= l2 + a - 3 ? l2 = Math.max(Math.min(n - a + 3, r.length - a), 0) : n < l2 + 2 && (l2 = Math.max(n - 2, 0));
616
- const $2 = a < r.length && l2 > 0, g = a < r.length && l2 + a < r.length;
657
+ const $2 = a < r.length && l2 > 0, g2 = a < r.length && l2 + a < r.length;
617
658
  return r.slice(l2, l2 + a).map((p2, v2, f) => {
618
- const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g;
659
+ const j2 = v2 === 0 && $2, E = v2 === f.length - 1 && g2;
619
660
  return j2 || E ? import_picocolors2.default.dim("...") : i(p2, v2 + l2 === n);
620
661
  });
621
662
  };
@@ -640,6 +681,25 @@ ${import_picocolors2.default.cyan(d2)}
640
681
  `;
641
682
  }
642
683
  } }).prompt();
684
+ var ye = (t) => {
685
+ const n = t.active ?? "Yes", r = t.inactive ?? "No";
686
+ return new dD({ active: n, inactive: r, initialValue: t.initialValue ?? true, render() {
687
+ const i = `${import_picocolors2.default.gray(o)}
688
+ ${b2(this.state)} ${t.message}
689
+ `, s = this.value ? n : r;
690
+ switch (this.state) {
691
+ case "submit":
692
+ return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.dim(s)}`;
693
+ case "cancel":
694
+ return `${i}${import_picocolors2.default.gray(o)} ${import_picocolors2.default.strikethrough(import_picocolors2.default.dim(s))}
695
+ ${import_picocolors2.default.gray(o)}`;
696
+ default:
697
+ return `${i}${import_picocolors2.default.cyan(o)} ${this.value ? `${import_picocolors2.default.green(k2)} ${n}` : `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(n)}`} ${import_picocolors2.default.dim("/")} ${this.value ? `${import_picocolors2.default.dim(P2)} ${import_picocolors2.default.dim(r)}` : `${import_picocolors2.default.green(k2)} ${r}`}
698
+ ${import_picocolors2.default.cyan(d2)}
699
+ `;
700
+ }
701
+ } }).prompt();
702
+ };
643
703
  var ve = (t) => {
644
704
  const n = (r, i) => {
645
705
  const s = r.label ?? String(r.value);
@@ -725,189 +785,1377 @@ ${import_picocolors2.default.gray(d2)} ${t}
725
785
  `);
726
786
  };
727
787
  var J2 = `${import_picocolors2.default.gray(o)} `;
788
+ var Y2 = ({ indicator: t = "dots" } = {}) => {
789
+ const n = V2 ? ["◒", "◐", "◓", "◑"] : ["•", "o", "O", "0"], r = V2 ? 80 : 120, i = process.env.CI === "true";
790
+ let s, c, a = false, l2 = "", $2, g2 = performance.now();
791
+ const p2 = (m2) => {
792
+ const h2 = m2 > 1 ? "Something went wrong" : "Canceled";
793
+ a && N2(h2, m2);
794
+ }, v2 = () => p2(2), f = () => p2(1), j2 = () => {
795
+ process.on("uncaughtExceptionMonitor", v2), process.on("unhandledRejection", v2), process.on("SIGINT", f), process.on("SIGTERM", f), process.on("exit", p2);
796
+ }, E = () => {
797
+ process.removeListener("uncaughtExceptionMonitor", v2), process.removeListener("unhandledRejection", v2), process.removeListener("SIGINT", f), process.removeListener("SIGTERM", f), process.removeListener("exit", p2);
798
+ }, B2 = () => {
799
+ if ($2 === undefined)
800
+ return;
801
+ i && process.stdout.write(`
802
+ `);
803
+ const m2 = $2.split(`
804
+ `);
805
+ process.stdout.write(import_sisteransi2.cursor.move(-999, m2.length - 1)), process.stdout.write(import_sisteransi2.erase.down(m2.length));
806
+ }, R2 = (m2) => m2.replace(/\.+$/, ""), O2 = (m2) => {
807
+ const h2 = (performance.now() - m2) / 1000, w2 = Math.floor(h2 / 60), I2 = Math.floor(h2 % 60);
808
+ return w2 > 0 ? `[${w2}m ${I2}s]` : `[${I2}s]`;
809
+ }, H2 = (m2 = "") => {
810
+ a = true, s = fD(), l2 = R2(m2), g2 = performance.now(), process.stdout.write(`${import_picocolors2.default.gray(o)}
811
+ `);
812
+ let h2 = 0, w2 = 0;
813
+ j2(), c = setInterval(() => {
814
+ if (i && l2 === $2)
815
+ return;
816
+ B2(), $2 = l2;
817
+ const I2 = import_picocolors2.default.magenta(n[h2]);
818
+ if (i)
819
+ process.stdout.write(`${I2} ${l2}...`);
820
+ else if (t === "timer")
821
+ process.stdout.write(`${I2} ${l2} ${O2(g2)}`);
822
+ else {
823
+ const z2 = ".".repeat(Math.floor(w2)).slice(0, 3);
824
+ process.stdout.write(`${I2} ${l2}${z2}`);
825
+ }
826
+ h2 = h2 + 1 < n.length ? h2 + 1 : 0, w2 = w2 < n.length ? w2 + 0.125 : 0;
827
+ }, r);
828
+ }, N2 = (m2 = "", h2 = 0) => {
829
+ a = false, clearInterval(c), B2();
830
+ const w2 = h2 === 0 ? import_picocolors2.default.green(C2) : h2 === 1 ? import_picocolors2.default.red(L2) : import_picocolors2.default.red(W2);
831
+ l2 = R2(m2 ?? l2), t === "timer" ? process.stdout.write(`${w2} ${l2} ${O2(g2)}
832
+ `) : process.stdout.write(`${w2} ${l2}
833
+ `), E(), s();
834
+ };
835
+ return { start: H2, stop: N2, message: (m2 = "") => {
836
+ l2 = R2(m2 ?? l2);
837
+ } };
838
+ };
839
+
840
+ // src/constants.ts
841
+ var UNFOUND_INDEX = -1;
842
+ var DEFAULT_ARG_LENGTH = 2;
843
+ var TWO_THIRDS = 2 / 3;
728
844
 
729
- // index.ts
845
+ // src/data.ts
730
846
  var import_picocolors3 = __toESM(require_picocolors(), 1);
731
- var { blueBright, yellow, cyan, green, magenta, red, reset, white } = import_picocolors3.default;
732
- var frameworkNames = {
733
- angular: "Angular",
734
- html: "HTML",
735
- htmx: "HTMX",
736
- react: "React",
737
- solid: "Solid",
738
- svelte: "Svelte",
739
- vue: "Vue"
847
+ var availableFrontends = {
848
+ react: { label: import_picocolors3.cyan("React"), name: "React" },
849
+ html: { label: "HTML", name: "HTML" },
850
+ angular: { label: import_picocolors3.red("Angular"), name: "Angular" },
851
+ vue: { label: import_picocolors3.green("Vue"), name: "Vue" },
852
+ svelte: { label: import_picocolors3.magenta("Svelte"), name: "Svelte" },
853
+ htmx: { label: "HTMX", name: "HTMX" },
854
+ solid: { label: import_picocolors3.blueBright("Solid"), name: "Solid" }
740
855
  };
856
+ var availablePlugins = [
857
+ {
858
+ imports: [{ config: null, isPlugin: true, packageName: "cors" }],
859
+ label: import_picocolors3.cyan("⚙️ @elysiajs/cors"),
860
+ latestVersion: "1.3.3",
861
+ value: "@elysiajs/cors"
862
+ },
863
+ {
864
+ imports: [{ config: null, isPlugin: true, packageName: "swagger" }],
865
+ label: import_picocolors3.cyan("\uD83D\uDCD1 @elysiajs/swagger"),
866
+ latestVersion: "1.3.0",
867
+ value: "@elysiajs/swagger"
868
+ },
869
+ {
870
+ imports: [{ config: null, isPlugin: true, packageName: "rateLimit" }],
871
+ label: import_picocolors3.green("\uD83D\uDEE0️ elysia-rate-limit"),
872
+ latestVersion: "4.3.0",
873
+ value: "elysia-rate-limit"
874
+ }
875
+ ];
876
+ var absoluteAuthPlugin = {
877
+ imports: [
878
+ {
879
+ config: { providersConfiguration: {} },
880
+ isPlugin: true,
881
+ packageName: "absoluteAuth"
882
+ }
883
+ ],
884
+ latestVersion: "0.3.2",
885
+ value: "@absolutejs/auth"
886
+ };
887
+ var defaultDependencies = [
888
+ {
889
+ imports: [{ isPlugin: false, packageName: "Elysia" }],
890
+ latestVersion: "1.3.1",
891
+ value: "elysia"
892
+ }
893
+ ];
894
+ var defaultPlugins = [
895
+ {
896
+ imports: [
897
+ { isPlugin: false, packageName: "build" },
898
+ { isPlugin: true, packageName: "networkingPlugin" }
899
+ ],
900
+ latestVersion: "0.6.0",
901
+ value: "@absolutejs/absolute"
902
+ },
903
+ {
904
+ imports: [
905
+ {
906
+ config: { assets: "./build", prefix: "" },
907
+ isPlugin: true,
908
+ packageName: "staticPlugin"
909
+ }
910
+ ],
911
+ latestVersion: "1.3.0",
912
+ value: "@elysiajs/static"
913
+ }
914
+ ];
915
+
916
+ // src/messages.ts
917
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
918
+ var helpMessage = `
919
+ Usage: create-absolute [options] [dir]
920
+
921
+ Arguments:
922
+ dir The name of the created application.
923
+ If not specified, the user will be prompted during creation.
924
+
925
+ Options:
926
+ -h, --help Show this help message and exit
927
+ -d, --debug Show a summary of the project configuration after creation
928
+ -l, --latest Fetch and use the latest version of required packages
929
+ `;
930
+ var getOutroMessage = ({
931
+ projectName,
932
+ packageManager,
933
+ installDependenciesNow
934
+ }) => `${import_picocolors4.green("Created successfully")}, you can now run:
935
+
936
+ ` + `${import_picocolors4.cyan("cd")} ${projectName}
937
+ ` + `${import_picocolors4.cyan(`${packageManager} dev`)}${installDependenciesNow ? "" : `
938
+ ${import_picocolors4.cyan(`${packageManager} install`)}`}`;
939
+ var getDebugMessage = ({
940
+ response: {
941
+ projectName,
942
+ language,
943
+ codeQualityTool,
944
+ configType,
945
+ useTailwind,
946
+ tailwind,
947
+ frontends,
948
+ htmlScriptOption,
949
+ frontendConfigurations,
950
+ buildDirectory,
951
+ assetsDirectory,
952
+ databaseEngine,
953
+ databaseHost,
954
+ databaseDirectory,
955
+ orm,
956
+ authProvider,
957
+ plugins,
958
+ initializeGitNow,
959
+ installDependenciesNow
960
+ },
961
+ packageManager,
962
+ availableFrontends: availableFrontends2
963
+ }) => {
964
+ const htmlLabels = {
965
+ js: import_picocolors4.yellow("JavaScript"),
966
+ "js+ssr": import_picocolors4.yellow("JavaScript + SSR"),
967
+ ts: import_picocolors4.blueBright("TypeScript"),
968
+ "ts+ssr": import_picocolors4.blueBright("TypeScript + SSR")
969
+ };
970
+ const htmlScriptingValue = htmlScriptOption !== undefined ? htmlLabels[htmlScriptOption] : import_picocolors4.dim("None");
971
+ const htmlScriptingLine = frontends.includes("html") ? `
972
+ ${import_picocolors4.magenta("HTML Scripting")}: ${htmlScriptingValue}` : "";
973
+ const frontendLabels = frontends.map((name) => availableFrontends2[name]?.label ?? name);
974
+ const frontendHeading = frontends.length === 1 ? import_picocolors4.magenta("Frontend") : import_picocolors4.magenta("Frontends");
975
+ const configString = frontendConfigurations.reduce((acc, { name, directory }, idx, arr) => {
976
+ const label = availableFrontends2[name]?.label ?? name;
977
+ const segment = `${label}: src/frontend/${directory}${idx < arr.length - 1 ? `
978
+ ` : ""}`;
979
+ return acc + segment;
980
+ }, "");
981
+ const tailwindSection = tailwind && useTailwind ? `
982
+ ${import_picocolors4.cyan("Input")}: ${tailwind.input}
983
+ ${import_picocolors4.cyan("Output")}: ${tailwind.output}` : import_picocolors4.dim("None");
984
+ return `
985
+ ${import_picocolors4.magenta("Project Name")}: ${projectName}
986
+ ${import_picocolors4.magenta("Package Manager")}: ${packageManager}
987
+ ${import_picocolors4.magenta("Config Type")}: ${configType === "custom" ? import_picocolors4.green("Custom") : import_picocolors4.dim("Default")}
988
+ ${import_picocolors4.magenta("Language")}: ${language === "ts" ? import_picocolors4.blueBright("TypeScript") : import_picocolors4.yellow("JavaScript")}
989
+ ${import_picocolors4.magenta("Linting")}: ${codeQualityTool === "eslint+prettier" ? "ESLint + Prettier" : "Biome"}
990
+ ${import_picocolors4.magenta("Tailwind Configuration")}: ${tailwindSection}
991
+ ${frontendHeading}: ${frontendLabels.join(", ")}${htmlScriptingLine}
992
+ ${import_picocolors4.magenta("Build Directory")}: ${buildDirectory}
993
+ ${import_picocolors4.magenta("Assets Directory")}: ${assetsDirectory}
994
+ ${import_picocolors4.magenta("Database Engine")}: ${databaseEngine ?? import_picocolors4.dim("None")}
995
+ ${import_picocolors4.magenta("Database Host")}: ${databaseHost ?? import_picocolors4.dim("None")}
996
+ ${import_picocolors4.magenta("Database Directory")}: ${databaseDirectory ?? import_picocolors4.dim("None")}
997
+ ${import_picocolors4.magenta("ORM")}: ${orm ?? import_picocolors4.dim("None")}
998
+ ${import_picocolors4.magenta("Authorization Provider")}: ${authProvider ?? import_picocolors4.dim("None")}
999
+ ${import_picocolors4.magenta("Plugins")}: ${plugins.length ? plugins.join(", ") : import_picocolors4.dim("None")}
1000
+ ${import_picocolors4.magenta("Initialize Git")}: ${initializeGitNow ? import_picocolors4.green("Yes") : import_picocolors4.dim("No")}
1001
+ ${import_picocolors4.magenta("Install Dependencies")}: ${installDependenciesNow ? import_picocolors4.green("Yes") : import_picocolors4.red("No")}
1002
+ ${import_picocolors4.magenta("Framework Config")}:
1003
+ ${configString}
1004
+
1005
+ `;
1006
+ };
1007
+
1008
+ // src/questions/authProvider.ts
1009
+ var import_picocolors5 = __toESM(require_picocolors(), 1);
1010
+
1011
+ // src/utils/abort.ts
1012
+ import { exit } from "node:process";
741
1013
  function abort() {
742
1014
  xe("Operation cancelled");
743
1015
  exit(0);
744
1016
  }
745
- var DEFAULT_ARG_LENGTH = 2;
746
- var { values } = parseArgs({
747
- args: argv.slice(DEFAULT_ARG_LENGTH),
748
- options: {
749
- help: { default: false, short: "h", type: "boolean" }
750
- },
751
- strict: false
752
- });
753
- if (values.help) {
754
- console.log(`
755
- Usage: create-absolute [OPTION]...
756
1017
 
757
- Options:
758
- -h, --help Show this help message and exit
759
- `);
760
- exit(0);
761
- }
762
- var projectName = await he({
763
- message: "Project name:",
764
- placeholder: "absolutejs-project"
765
- });
766
- if (pD(projectName))
767
- abort();
768
- var language = await ve({
769
- message: "Language:",
770
- options: [
771
- { label: blueBright("TypeScript"), value: "ts" },
772
- { label: yellow("JavaScript"), value: "js" }
773
- ]
774
- });
775
- if (pD(language))
776
- abort();
777
- var useTailwind = await ve({
778
- message: "Add Tailwind support?",
779
- options: [
780
- { label: green("Yes"), value: true },
781
- { label: red("No"), value: false }
782
- ]
783
- });
784
- if (pD(useTailwind))
785
- abort();
786
- var tailwind;
787
- if (useTailwind) {
788
- const input = await he({
789
- message: "Tailwind input CSS file:",
790
- placeholder: "./example/styles/tailwind.css"
1018
+ // src/questions/authProvider.ts
1019
+ var getAuthProvider = async () => {
1020
+ const authProvider = await ve({
1021
+ message: "Auth provider:",
1022
+ options: [
1023
+ { label: "None", value: "none" },
1024
+ { label: import_picocolors5.cyan("Absolute Auth"), value: "absoluteAuth" }
1025
+ ]
1026
+ });
1027
+ if (pD(authProvider))
1028
+ abort();
1029
+ return authProvider === "none" ? undefined : authProvider;
1030
+ };
1031
+
1032
+ // src/questions/codeQualityTool.ts
1033
+ var import_picocolors6 = __toESM(require_picocolors(), 1);
1034
+ var getCodeQualityTool = async () => {
1035
+ const codeQualityTool = await ve({
1036
+ message: "Choose linting and formatting tool:",
1037
+ options: [
1038
+ {
1039
+ label: import_picocolors6.blueBright("ESLint + Prettier"),
1040
+ value: "eslint+prettier"
1041
+ },
1042
+ { label: import_picocolors6.yellow("Biome"), value: "biome" }
1043
+ ]
791
1044
  });
792
- if (pD(input))
1045
+ if (pD(codeQualityTool))
793
1046
  abort();
794
- const output = await he({
795
- message: "Tailwind output CSS file:",
796
- placeholder: "/assets/css/tailwind.generated.css"
1047
+ return codeQualityTool;
1048
+ };
1049
+
1050
+ // src/questions/configurationType.ts
1051
+ var import_picocolors7 = __toESM(require_picocolors(), 1);
1052
+ var getConfigurationType = async () => {
1053
+ const configType = await ve({
1054
+ message: "Choose folder naming configuration:",
1055
+ options: [
1056
+ { label: import_picocolors7.blueBright("Default"), value: "default" },
1057
+ { label: import_picocolors7.yellow("Custom"), value: "custom" }
1058
+ ]
797
1059
  });
798
- if (pD(output))
1060
+ if (pD(configType))
799
1061
  abort();
800
- tailwind = { input, output };
801
- }
802
- var frameworks = await fe({
803
- message: "Framework(s) (space to select, enter to finish):",
804
- options: [
805
- { label: cyan("React"), value: "react" },
806
- { label: green("Vue"), value: "vue" },
807
- { label: magenta("Svelte"), value: "svelte" },
808
- { label: red("Angular"), value: "angular" },
809
- { label: blueBright("Solid"), value: "solid" },
810
- { label: white("HTML"), value: "html" },
811
- { label: white("HTMX"), value: "htmx" }
812
- ]
813
- });
814
- if (pD(frameworks))
815
- abort();
816
- var buildDir = await he({
817
- message: "Build directory:",
818
- placeholder: "build"
819
- });
820
- if (pD(buildDir))
821
- abort();
822
- var assetsDir = await he({
823
- message: "Assets directory:",
824
- placeholder: "src/backend/assets"
825
- });
826
- if (pD(assetsDir))
827
- abort();
828
- var single = frameworks.length === 1;
829
- var configs = await frameworks.reduce(async (previousConfigsPromise, framework) => {
830
- const previousConfigs = await previousConfigsPromise;
831
- const prettyName = frameworkNames[framework] ?? framework;
832
- const baseDirectory = single ? "src/frontend" : `src/frontend/${framework}`;
833
- const defaultPagesDirectory = `${baseDirectory}/pages`;
834
- const defaultIndexDirectory = `${baseDirectory}/indexes`;
835
- const pagesDirectory = await he({
836
- message: `${prettyName} pages directory:`,
837
- placeholder: defaultPagesDirectory
1062
+ return configType;
1063
+ };
1064
+
1065
+ // src/questions/databaseEngine.ts
1066
+ var import_picocolors8 = __toESM(require_picocolors(), 1);
1067
+ var getDatabaseEngine = async () => {
1068
+ const databaseDialectResponse = await ve({
1069
+ message: "Database engine:",
1070
+ options: [
1071
+ { label: "None", value: "none" },
1072
+ { label: import_picocolors8.cyan("PostgreSQL"), value: "postgresql" },
1073
+ { label: import_picocolors8.magenta("SQLite"), value: "sqlite" },
1074
+ { label: import_picocolors8.green("MySQL"), value: "mysql" },
1075
+ { label: import_picocolors8.red("Redis"), value: "redis" },
1076
+ { label: import_picocolors8.green("MongoDB"), value: "mongodb" },
1077
+ { label: import_picocolors8.magenta("SingleStore"), value: "singlestore" },
1078
+ { label: import_picocolors8.yellow("SQL Server"), value: "mssql" },
1079
+ { label: import_picocolors8.cyan("CockroachDB"), value: "cockroachdb" }
1080
+ ]
1081
+ });
1082
+ if (pD(databaseDialectResponse))
1083
+ abort();
1084
+ return databaseDialectResponse === "none" ? undefined : databaseDialectResponse;
1085
+ };
1086
+
1087
+ // src/questions/databaseHost.ts
1088
+ var import_picocolors9 = __toESM(require_picocolors(), 1);
1089
+ var getDatabaseHost = async (databaseEngine) => {
1090
+ if (databaseEngine === "postgresql") {
1091
+ const databaseHost = await ve({
1092
+ message: "Select database host:",
1093
+ options: [
1094
+ { label: import_picocolors9.cyan("Neon"), value: "neon" },
1095
+ { label: import_picocolors9.cyan("Supabase"), value: "supabase" },
1096
+ { label: "None", value: "none" }
1097
+ ]
1098
+ });
1099
+ if (pD(databaseHost))
1100
+ abort();
1101
+ return databaseHost === "none" ? undefined : databaseHost;
1102
+ }
1103
+ if (databaseEngine === "mysql") {
1104
+ const databaseHost = await ye({
1105
+ message: "Are you using PlanetScale?"
1106
+ });
1107
+ if (pD(databaseHost))
1108
+ abort();
1109
+ return databaseHost ? "planetscale" : undefined;
1110
+ }
1111
+ if (databaseEngine === "sqlite") {
1112
+ const databaseHost = await ye({
1113
+ message: "Are you using Turso?"
1114
+ });
1115
+ if (pD(databaseHost))
1116
+ abort();
1117
+ return databaseHost ? "turso" : undefined;
1118
+ }
1119
+ if (databaseEngine === "mongodb") {
1120
+ const databaseHost = await ye({
1121
+ message: "Are you using Atlas?"
1122
+ });
1123
+ if (pD(databaseHost))
1124
+ abort();
1125
+ return databaseHost ? "atlas" : undefined;
1126
+ }
1127
+ if (databaseEngine === "redis") {
1128
+ const databaseHost = await ye({
1129
+ message: "Are you using Upstash?"
1130
+ });
1131
+ if (pD(databaseHost))
1132
+ abort();
1133
+ return databaseHost ? "upstash" : undefined;
1134
+ }
1135
+ return;
1136
+ };
1137
+
1138
+ // src/questions/directoryConfiguration.ts
1139
+ var getDirectoryConfiguration = async ({
1140
+ configType,
1141
+ useTailwind,
1142
+ databaseEngine
1143
+ }) => {
1144
+ if (configType === "default") {
1145
+ return {
1146
+ assetsDirectory: "src/backend/assets",
1147
+ buildDirectory: "build",
1148
+ databaseDirectory: databaseEngine && "db",
1149
+ tailwind: useTailwind ? {
1150
+ input: "./src/frontend/styles/tailwind.css",
1151
+ output: "/assets/css/tailwind.generated.css"
1152
+ } : undefined
1153
+ };
1154
+ }
1155
+ const buildDirectory = await he({
1156
+ message: "Build directory:",
1157
+ placeholder: "build"
838
1158
  });
839
- if (pD(pagesDirectory))
1159
+ if (pD(buildDirectory))
840
1160
  abort();
841
- const indexDirectory = await he({
842
- message: `${prettyName} index directory:`,
843
- placeholder: defaultIndexDirectory
1161
+ const assetsDirectory = await he({
1162
+ message: "Assets directory:",
1163
+ placeholder: "src/backend/assets"
844
1164
  });
845
- if (pD(indexDirectory))
1165
+ if (pD(assetsDirectory))
846
1166
  abort();
847
- return [
848
- ...previousConfigs,
849
- { framework, index: indexDirectory, pages: pagesDirectory }
850
- ];
851
- }, Promise.resolve([]));
852
- var dbProvider = await ve({
853
- message: "Database provider:",
854
- options: [
855
- { label: cyan("PostgreSQL"), value: "postgres" },
856
- { label: green("MySQL"), value: "mysql" },
857
- { label: reset("None"), value: "none" }
858
- ]
859
- });
860
- if (pD(dbProvider))
861
- abort();
862
- var orm;
863
- if (dbProvider !== "none") {
864
- const ormChoice = await ve({
1167
+ let tailwind;
1168
+ if (useTailwind) {
1169
+ const input = await he({
1170
+ message: "Tailwind input CSS file:",
1171
+ placeholder: "./src/frontend/styles/tailwind.css"
1172
+ });
1173
+ if (pD(input))
1174
+ abort();
1175
+ const output = await he({
1176
+ message: "Tailwind output CSS file:",
1177
+ placeholder: "/assets/css/tailwind.generated.css"
1178
+ });
1179
+ if (pD(output))
1180
+ abort();
1181
+ tailwind = { input, output };
1182
+ } else {
1183
+ tailwind = undefined;
1184
+ }
1185
+ let databaseDirectory;
1186
+ if (databaseEngine !== undefined) {
1187
+ databaseDirectory = await he({
1188
+ message: "Database directory:",
1189
+ placeholder: "db"
1190
+ });
1191
+ if (pD(databaseDirectory))
1192
+ abort();
1193
+ }
1194
+ return {
1195
+ assetsDirectory,
1196
+ buildDirectory,
1197
+ databaseDirectory,
1198
+ tailwind
1199
+ };
1200
+ };
1201
+
1202
+ // src/questions/frontendDirectoryConfigurations.ts
1203
+ var getFrontendDirectoryConfigurations = async (configType, frontends) => {
1204
+ let frontendConfigurations;
1205
+ const single = frontends.length === 1;
1206
+ if (configType === "custom") {
1207
+ frontendConfigurations = await frontends.reduce(async (prevP, frontend) => {
1208
+ const prev = await prevP;
1209
+ const pretty = availableFrontends[frontend]?.name ?? frontend;
1210
+ const base = single ? "" : `${frontend}`;
1211
+ const defDir = base;
1212
+ const frontendDirectory = await he({
1213
+ message: `${pretty} directory:`,
1214
+ placeholder: defDir
1215
+ });
1216
+ if (pD(frontendDirectory))
1217
+ abort();
1218
+ return [
1219
+ ...prev,
1220
+ { directory: frontendDirectory, frontend, name: frontend }
1221
+ ];
1222
+ }, Promise.resolve([]));
1223
+ } else {
1224
+ frontendConfigurations = frontends.map((frontend) => ({
1225
+ directory: single ? "" : frontend,
1226
+ frontend,
1227
+ name: frontend
1228
+ }));
1229
+ }
1230
+ return frontendConfigurations;
1231
+ };
1232
+
1233
+ // src/questions/frontends.ts
1234
+ var getFrontends = async () => {
1235
+ const frontends = await fe({
1236
+ message: "Frontend(s) (space to select, enter to finish):",
1237
+ options: Object.entries(availableFrontends).map(([value, { label }]) => ({ label, value }))
1238
+ });
1239
+ if (pD(frontends))
1240
+ abort();
1241
+ return frontends;
1242
+ };
1243
+
1244
+ // src/questions/htmlScriptingOption.ts
1245
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
1246
+ var getHtmlScriptingOption = async (language) => {
1247
+ const langLabel = language === "ts" ? import_picocolors10.blueBright("TypeScript") : import_picocolors10.yellow("JavaScript");
1248
+ const htmlScriptOption = await ve({
1249
+ message: `Add HTML scripting option (${langLabel}):`,
1250
+ options: [
1251
+ { label: `${langLabel} + SSR`, value: `${language}+ssr` },
1252
+ { label: langLabel, value: language },
1253
+ { label: "None", value: "none" }
1254
+ ]
1255
+ });
1256
+ if (pD(htmlScriptOption))
1257
+ abort();
1258
+ return htmlScriptOption === "none" ? undefined : htmlScriptOption;
1259
+ };
1260
+
1261
+ // src/questions/initializeGitNow.ts
1262
+ var getInitializeGit = async () => {
1263
+ const initializeGitNow = await ye({
1264
+ message: "Initialize a git repository?"
1265
+ });
1266
+ if (pD(initializeGitNow))
1267
+ abort();
1268
+ return initializeGitNow;
1269
+ };
1270
+
1271
+ // src/questions/installDependenciesNow.ts
1272
+ var getInstallDependencies = async () => {
1273
+ const installDependenciesNow = await ye({
1274
+ message: "Install dependencies now?"
1275
+ });
1276
+ if (pD(installDependenciesNow))
1277
+ abort();
1278
+ return installDependenciesNow;
1279
+ };
1280
+
1281
+ // src/questions/language.ts
1282
+ var import_picocolors11 = __toESM(require_picocolors(), 1);
1283
+ var getLanguage = async () => {
1284
+ const language = await ve({
1285
+ message: "Language:",
1286
+ options: [
1287
+ { label: import_picocolors11.blueBright("TypeScript"), value: "ts" },
1288
+ { label: import_picocolors11.yellow("JavaScript"), value: "js" }
1289
+ ]
1290
+ });
1291
+ if (pD(language))
1292
+ abort();
1293
+ return language;
1294
+ };
1295
+
1296
+ // src/questions/orm.ts
1297
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
1298
+ var getORM = async () => {
1299
+ const orm = await ve({
865
1300
  message: "Choose an ORM (optional):",
866
1301
  options: [
867
- { label: cyan("Drizzle"), value: "drizzle" },
868
- { label: magenta("Prisma"), value: "prisma" },
869
- { label: reset("None"), value: "none" }
1302
+ { label: "None", value: "none" },
1303
+ { label: import_picocolors12.cyan("Drizzle"), value: "drizzle" },
1304
+ { label: import_picocolors12.magenta("Prisma"), value: "prisma" }
870
1305
  ]
871
1306
  });
872
- if (pD(ormChoice))
1307
+ if (pD(orm))
873
1308
  abort();
874
- orm = ormChoice === "none" ? undefined : ormChoice;
875
- }
876
- var authProvider = await ve({
877
- message: "Auth provider:",
878
- options: [
879
- { label: cyan("Absolute Auth"), value: "absoluteAuth" },
880
- { label: yellow("JWT"), value: "jwt" },
881
- { label: reset("None"), value: "none" }
882
- ]
1309
+ return orm === "none" ? undefined : orm;
1310
+ };
1311
+
1312
+ // src/questions/plugins.ts
1313
+ var getPlugins = async () => {
1314
+ const plugins = await fe({
1315
+ message: "Select additional Elysia plugins (space to select, enter to submit):",
1316
+ options: availablePlugins,
1317
+ required: false
1318
+ });
1319
+ if (pD(plugins))
1320
+ abort();
1321
+ return plugins;
1322
+ };
1323
+
1324
+ // src/questions/projectName.ts
1325
+ var getProjectName = async () => {
1326
+ const projectName = await he({
1327
+ message: "Project name:",
1328
+ placeholder: "absolutejs-project"
1329
+ });
1330
+ if (pD(projectName))
1331
+ abort();
1332
+ return projectName;
1333
+ };
1334
+
1335
+ // src/questions/useTailwind.ts
1336
+ var getUseTailwind = async () => {
1337
+ const useTailwind = await ye({ message: "Add Tailwind support?" });
1338
+ if (pD(useTailwind))
1339
+ abort();
1340
+ return useTailwind;
1341
+ };
1342
+
1343
+ // src/prompt.ts
1344
+ var prompt = async () => {
1345
+ const projectName = await getProjectName();
1346
+ const language = await getLanguage();
1347
+ const codeQualityTool = await getCodeQualityTool();
1348
+ const useTailwind = await getUseTailwind();
1349
+ const frontends = await getFrontends();
1350
+ const htmlScriptOption = frontends.includes("html") ? await getHtmlScriptingOption(language) : undefined;
1351
+ const databaseEngine = await getDatabaseEngine();
1352
+ const databaseHost = await getDatabaseHost(databaseEngine);
1353
+ const orm = databaseEngine !== undefined ? await getORM() : undefined;
1354
+ const configType = await getConfigurationType();
1355
+ const { buildDirectory, assetsDirectory, tailwind, databaseDirectory } = await getDirectoryConfiguration({
1356
+ configType,
1357
+ databaseEngine,
1358
+ useTailwind
1359
+ });
1360
+ const frontendConfigurations = await getFrontendDirectoryConfigurations(configType, frontends);
1361
+ const authProvider = await getAuthProvider();
1362
+ const plugins = await getPlugins();
1363
+ const initializeGitNow = await getInitializeGit();
1364
+ const installDependenciesNow = await getInstallDependencies();
1365
+ const values = {
1366
+ assetsDirectory,
1367
+ authProvider,
1368
+ buildDirectory,
1369
+ codeQualityTool,
1370
+ configType,
1371
+ databaseDirectory,
1372
+ databaseEngine,
1373
+ databaseHost,
1374
+ frontendConfigurations,
1375
+ frontends,
1376
+ htmlScriptOption,
1377
+ initializeGitNow,
1378
+ installDependenciesNow,
1379
+ language,
1380
+ orm,
1381
+ plugins,
1382
+ projectName,
1383
+ tailwind,
1384
+ useTailwind
1385
+ };
1386
+ return values;
1387
+ };
1388
+
1389
+ // src/scaffold.ts
1390
+ import { copyFileSync as copyFileSync4 } from "node:fs";
1391
+ import { join as join9, dirname } from "node:path";
1392
+ import { fileURLToPath } from "node:url";
1393
+
1394
+ // src/commands/formatProject.ts
1395
+ import { execSync } from "child_process";
1396
+ import { exit as exit2 } from "process";
1397
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
1398
+
1399
+ // src/utils/commandMaps.ts
1400
+ var formatCommands = {
1401
+ bun: "bun run format",
1402
+ npm: "npm run format",
1403
+ pnpm: "pnpm run format",
1404
+ yarn: "yarn format"
1405
+ };
1406
+ var installCommands = {
1407
+ bun: "bun install",
1408
+ npm: "npm install",
1409
+ pnpm: "pnpm install",
1410
+ yarn: "yarn install"
1411
+ };
1412
+
1413
+ // src/commands/formatProject.ts
1414
+ var formatProject = ({
1415
+ projectName,
1416
+ packageManager
1417
+ }) => {
1418
+ const spin = Y2();
1419
+ try {
1420
+ const fmt = formatCommands[packageManager] ?? "bun run format";
1421
+ spin.start("Formatting files…");
1422
+ execSync(fmt, { cwd: projectName, stdio: "pipe" });
1423
+ spin.stop(import_picocolors13.green("Files formatted"));
1424
+ } catch (err) {
1425
+ spin.stop(import_picocolors13.red("Failed to format files"), 1);
1426
+ console.error("Error formatting:", err);
1427
+ exit2(1);
1428
+ }
1429
+ };
1430
+
1431
+ // src/commands/installDependencies.ts
1432
+ import { execSync as execSync2 } from "child_process";
1433
+ import { exit as exit3 } from "process";
1434
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
1435
+ var installDependencies = async ({
1436
+ projectName,
1437
+ packageManager
1438
+ }) => {
1439
+ const spin = Y2();
1440
+ const cmd = installCommands[packageManager] ?? "bun install";
1441
+ try {
1442
+ spin.start("Installing dependencies…");
1443
+ execSync2(cmd, { cwd: projectName, stdio: "pipe" });
1444
+ spin.stop(import_picocolors14.green("Dependencies installed"));
1445
+ } catch (err) {
1446
+ spin.stop(import_picocolors14.red("Installation failed"), 1);
1447
+ console.error("Error installing dependencies:", err);
1448
+ exit3(1);
1449
+ }
1450
+ };
1451
+
1452
+ // src/generators/configurations/addConfigurationFiles.ts
1453
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
1454
+ import { copyFileSync } from "fs";
1455
+ import { join } from "path";
1456
+ var addConfigurationFiles = ({
1457
+ tailwind,
1458
+ templatesDirectory,
1459
+ language,
1460
+ codeQualityTool,
1461
+ initializeGitNow,
1462
+ projectName
1463
+ }) => {
1464
+ if (tailwind) {
1465
+ copyFileSync(join(templatesDirectory, "tailwind", "postcss.config.ts"), join(projectName, "postcss.config.ts"));
1466
+ copyFileSync(join(templatesDirectory, "tailwind", "tailwind.config.ts"), join(projectName, "tailwind.config.ts"));
1467
+ }
1468
+ if (initializeGitNow)
1469
+ copyFileSync(join(templatesDirectory, "git", ".gitignore"), join(projectName, ".gitignore"));
1470
+ if (language === "ts")
1471
+ copyFileSync(join(templatesDirectory, "configurations", "tsconfig.example.json"), join(projectName, "tsconfig.json"));
1472
+ if (codeQualityTool === "eslint+prettier") {
1473
+ copyFileSync(join(templatesDirectory, "configurations", "eslint.config.mjs"), join(projectName, "eslint.config.mjs"));
1474
+ copyFileSync(join(templatesDirectory, "configurations", ".prettierignore"), join(projectName, ".prettierignore"));
1475
+ copyFileSync(join(templatesDirectory, "configurations", ".prettierrc.json"), join(projectName, ".prettierrc.json"));
1476
+ } else
1477
+ console.warn(`${import_picocolors15.dim("│")}
1478
+ ${import_picocolors15.yellow("▲")} Biome support not implemented yet`);
1479
+ };
1480
+
1481
+ // src/generators/configurations/createPackageJson.ts
1482
+ import { writeFileSync } from "fs";
1483
+ import { join as join2 } from "path";
1484
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
1485
+
1486
+ // src/utils/getPackageVersion.ts
1487
+ import { execSync as execSync3 } from "child_process";
1488
+ var getPackageVersion = (packageName) => {
1489
+ try {
1490
+ const raw = execSync3(`curl -s https://registry.npmjs.org/${packageName}/latest`);
1491
+ const { version } = JSON.parse(raw.toString());
1492
+ return version;
1493
+ } catch (err) {
1494
+ console.error(`Error fetching version for ${packageName}:`, err);
1495
+ return null;
1496
+ }
1497
+ };
1498
+
1499
+ // src/generators/configurations/createPackageJson.ts
1500
+ var createPackageJson = ({
1501
+ projectName,
1502
+ authProvider,
1503
+ plugins,
1504
+ useTailwind,
1505
+ latest,
1506
+ frontendConfigurations
1507
+ }) => {
1508
+ const s = Y2();
1509
+ latest && s.start("Resolving package versions…");
1510
+ const resolveVersion = (name, listed) => latest ? getPackageVersion(name) ?? listed : listed;
1511
+ const dependencies = {};
1512
+ const devDependencies = {};
1513
+ for (const p2 of defaultPlugins) {
1514
+ dependencies[p2.value] = resolveVersion(p2.value, p2.latestVersion);
1515
+ }
1516
+ if (authProvider === "absoluteAuth") {
1517
+ dependencies[absoluteAuthPlugin.value] = resolveVersion(absoluteAuthPlugin.value, absoluteAuthPlugin.latestVersion);
1518
+ }
1519
+ for (const pluginValue of plugins) {
1520
+ const meta = availablePlugins.find((p2) => p2.value === pluginValue);
1521
+ if (!meta)
1522
+ continue;
1523
+ dependencies[meta.value] = resolveVersion(meta.value, meta.latestVersion);
1524
+ }
1525
+ if (useTailwind) {
1526
+ devDependencies["autoprefixer"] = resolveVersion("autoprefixer", "10.4.21");
1527
+ devDependencies["postcss"] = resolveVersion("postcss", "8.5.3");
1528
+ devDependencies["tailwindcss"] = resolveVersion("tailwindcss", "4.1.7");
1529
+ devDependencies["@tailwindcss/cli"] = resolveVersion("@tailwindcss/cli", "4.1.7");
1530
+ }
1531
+ if (frontendConfigurations.some((f) => f.name === "react")) {
1532
+ dependencies["react"] = resolveVersion("react", "19.1.0");
1533
+ dependencies["react-dom"] = resolveVersion("react-dom", "19.1.0");
1534
+ devDependencies["@types/react"] = resolveVersion("@types/react", "19.1.5");
1535
+ devDependencies["@types/react-dom"] = resolveVersion("@types/react-dom", "19.1.5");
1536
+ }
1537
+ latest && s.stop(import_picocolors16.green("Package versions resolved"));
1538
+ const scripts = {
1539
+ dev: "bun run src/backend/server.ts",
1540
+ format: 'prettier --write "./**/*.{js,jsx,ts,tsx,css,json,mjs,md}"',
1541
+ lint: "eslint ./src",
1542
+ test: 'echo "Error: no test specified" && exit 1',
1543
+ typecheck: "bun run tsc --noEmit"
1544
+ };
1545
+ const packageJson = {
1546
+ dependencies,
1547
+ devDependencies,
1548
+ name: projectName,
1549
+ scripts,
1550
+ type: "module",
1551
+ version: "0.1.0"
1552
+ };
1553
+ writeFileSync(join2(projectName, "package.json"), JSON.stringify(packageJson));
1554
+ };
1555
+
1556
+ // src/generators/configurations/initializeRoot.ts
1557
+ import { copyFileSync as copyFileSync2, cpSync, existsSync, mkdirSync } from "node:fs";
1558
+ import { join as join3 } from "node:path";
1559
+ var initalizeRoot = (projectName, templatesDirectory) => {
1560
+ if (existsSync(projectName))
1561
+ throw new Error(`Cannot create project "${projectName}": directory already exists.`);
1562
+ mkdirSync(projectName);
1563
+ const srcDir = join3(projectName, "src");
1564
+ mkdirSync(srcDir);
1565
+ copyFileSync2(join3(templatesDirectory, "constants.ts"), join3(projectName, "src", "constants.ts"));
1566
+ const frontendDirectory = join3(srcDir, "frontend");
1567
+ const backendDirectory = join3(srcDir, "backend");
1568
+ mkdirSync(frontendDirectory);
1569
+ mkdirSync(backendDirectory);
1570
+ mkdirSync(join3(srcDir, "types"));
1571
+ cpSync(join3(templatesDirectory, "assets"), join3(backendDirectory, "assets"), { recursive: true });
1572
+ return {
1573
+ backendDirectory,
1574
+ frontendDirectory
1575
+ };
1576
+ };
1577
+
1578
+ // src/generators/db/scaffoldDatabase.ts
1579
+ var import_picocolors17 = __toESM(require_picocolors(), 1);
1580
+ import { mkdirSync as mkdirSync2 } from "fs";
1581
+ import { join as join5 } from "path";
1582
+
1583
+ // src/generators/configurations/createDrizzleConfig.ts
1584
+ import { writeFileSync as writeFileSync2 } from "fs";
1585
+ import { join as join4 } from "path";
1586
+ var createDrizzleConfig = ({
1587
+ projectName,
1588
+ databaseEngine
1589
+ }) => {
1590
+ const drizzleConfig = `import { defineConfig } from "drizzle-kit";
1591
+
1592
+ export default defineConfig({
1593
+ dialect: '${databaseEngine}'
1594
+ });
1595
+ `;
1596
+ writeFileSync2(join4(projectName, "drizzle.config.ts"), drizzleConfig);
1597
+ };
1598
+
1599
+ // src/generators/db/scaffoldDatabase.ts
1600
+ var scaffoldDatabase = ({
1601
+ projectName,
1602
+ databaseEngine,
1603
+ databaseDirectory,
1604
+ orm
1605
+ }) => {
1606
+ mkdirSync2(join5(projectName, databaseDirectory), { recursive: true });
1607
+ if (databaseEngine !== "postgresql") {
1608
+ console.warn(`${import_picocolors17.dim("│")}
1609
+ ${import_picocolors17.yellow("▲")} Only PostgreSQL support is implemented so far`);
1610
+ }
1611
+ if (orm === "drizzle") {
1612
+ createDrizzleConfig({ databaseEngine, projectName });
1613
+ }
1614
+ };
1615
+
1616
+ // src/generators/project/createServer.ts
1617
+ import { writeFileSync as writeFileSync3 } from "fs";
1618
+ var createServerFile = ({
1619
+ tailwind,
1620
+ frontendConfigurations,
1621
+ serverFilePath,
1622
+ authProvider,
1623
+ availablePlugins: availablePlugins2,
1624
+ buildDirectory,
1625
+ assetsDirectory,
1626
+ plugins
1627
+ }) => {
1628
+ const requiresHtml = frontendConfigurations.some((configuration) => configuration.name === "html");
1629
+ const requiresReact = frontendConfigurations.some((configuration) => configuration.name === "react");
1630
+ const isSingleFrontend = frontendConfigurations.length === 1;
1631
+ const selectedCustomPlugins = availablePlugins2.filter((plugin) => plugins.indexOf(plugin.value) !== UNFOUND_INDEX);
1632
+ const authenticationPlugins = [];
1633
+ if (authProvider === "absoluteAuth") {
1634
+ authenticationPlugins.push(absoluteAuthPlugin);
1635
+ }
1636
+ const combinedDependencies = [
1637
+ ...defaultDependencies,
1638
+ ...defaultPlugins,
1639
+ ...selectedCustomPlugins,
1640
+ ...authenticationPlugins
1641
+ ];
1642
+ const uniqueDependencies = [];
1643
+ combinedDependencies.forEach((dependency) => {
1644
+ if (!uniqueDependencies.some((existingDependency) => existingDependency.value === dependency.value)) {
1645
+ uniqueDependencies.push(dependency);
1646
+ }
1647
+ });
1648
+ uniqueDependencies.sort((firstDependency, secondDependency) => firstDependency.value.localeCompare(secondDependency.value));
1649
+ const importLines = uniqueDependencies.flatMap((dependency) => dependency.imports.length > 0 ? [
1650
+ `import { ${dependency.imports.map((importEntry) => importEntry.packageName).join(", ")} } from '${dependency.value}';`
1651
+ ] : []);
1652
+ const absoluteImportLineIndex = importLines.findIndex((importLine) => importLine.includes("from '@absolutejs/absolute'"));
1653
+ if (absoluteImportLineIndex >= 0) {
1654
+ const originalImportLine = importLines[absoluteImportLineIndex];
1655
+ importLines[absoluteImportLineIndex] = originalImportLine.replace(/import\s*\{([\s\S]*?)\}\s*from '@absolutejs\/absolute';/, (_fullMatch, importList) => {
1656
+ const importedItems = importList.split(",").map((item) => item.trim()).filter(Boolean);
1657
+ if (requiresHtml && !importedItems.includes("handleHTMLPageRequest")) {
1658
+ importedItems.push("handleHTMLPageRequest");
1659
+ }
1660
+ if (requiresReact && !importedItems.includes("handleReactPageRequest")) {
1661
+ importedItems.push("handleReactPageRequest");
1662
+ }
1663
+ return `import { ${importedItems.join(", ")} } from '@absolutejs/absolute';`;
1664
+ });
1665
+ }
1666
+ if (requiresReact) {
1667
+ const reactImportSource = isSingleFrontend ? "../frontend/pages/ReactExample" : "../frontend/react/pages/ReactExample";
1668
+ importLines.push(`import { ReactExample } from '${reactImportSource}';`);
1669
+ }
1670
+ const useStatements = uniqueDependencies.flatMap((dependency) => dependency.imports).filter((importEntry) => importEntry.isPlugin).map((importEntry) => {
1671
+ if (importEntry.config === undefined) {
1672
+ return `.use(${importEntry.packageName})`;
1673
+ }
1674
+ if (importEntry.config === null) {
1675
+ return `.use(${importEntry.packageName}())`;
1676
+ }
1677
+ return `.use(${importEntry.packageName}(${JSON.stringify(importEntry.config)}))`;
1678
+ });
1679
+ const manifestOptions = [
1680
+ `buildDirectory: '${buildDirectory}'`,
1681
+ `assetsDirectory: '${assetsDirectory}'`,
1682
+ ...frontendConfigurations.map((configuration) => configuration.directory ? `${configuration.name}Directory: './src/frontend/${configuration.directory}'` : "").filter((option) => option !== ""),
1683
+ tailwind ? `tailwind: ${JSON.stringify(tailwind)}` : ""
1684
+ ];
1685
+ const buildStatement = `const manifest = await build({
1686
+ ${manifestOptions.join(`,
1687
+ `)}
1688
+ });`;
1689
+ let guardStatements = `if (manifest === null) throw new Error('Manifest was not generated');`;
1690
+ if (requiresReact) {
1691
+ guardStatements += `
1692
+ const { ReactExampleIndex } = manifest;
1693
+ if (ReactExampleIndex === undefined) throw new Error('ReactExampleIndex was not generated');`;
1694
+ }
1695
+ let routeDefinitions = "";
1696
+ frontendConfigurations.forEach((configuration, index) => {
1697
+ const routePath = index === 0 ? "/" : `/${configuration.name}`;
1698
+ if (configuration.name === "html") {
1699
+ routeDefinitions += `
1700
+ .get('${routePath}', () =>
1701
+ handleHTMLPageRequest(\`${buildDirectory}/html/pages/HtmlExample.html\`)
1702
+ )`;
1703
+ } else if (configuration.name === "react") {
1704
+ routeDefinitions += `
1705
+ .get('${routePath}', () =>
1706
+ handleReactPageRequest(ReactExample, ReactExampleIndex)
1707
+ )`;
1708
+ }
1709
+ });
1710
+ let serverFileContent = `${importLines.join(`
1711
+ `)}
1712
+
1713
+ ${buildStatement}
1714
+
1715
+ ${guardStatements}
1716
+
1717
+ new Elysia()${routeDefinitions}`;
1718
+ useStatements.forEach((statement) => {
1719
+ serverFileContent += `
1720
+ ${statement}`;
1721
+ });
1722
+ serverFileContent += `
1723
+ .on('error', (error) => {
1724
+ const { request } = error;
1725
+ console.error(\`Server error on \${request.method} \${request.url}: \${error.message}\`);
1726
+ });
1727
+ `;
1728
+ writeFileSync3(serverFilePath, serverFileContent);
1729
+ };
1730
+
1731
+ // src/generators/project/scaffoldFrontends.ts
1732
+ import { copyFileSync as copyFileSync3, mkdirSync as mkdirSync5 } from "node:fs";
1733
+ import { join as join8 } from "node:path";
1734
+
1735
+ // src/generators/html/scaffoldHTML.ts
1736
+ import { cpSync as cpSync2, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
1737
+ import { join as join6 } from "path";
1738
+
1739
+ // src/generators/html/getSSRScript.ts
1740
+ var getSSRScript = (language, isSingle) => `import { HOURS_IN_DAY, TWO_THIRDS } from '${!isSingle ? "../" : ""}../../constants';
1741
+
1742
+ document.addEventListener('DOMContentLoaded', () => {
1743
+ const greeting = document.getElementById('greeting');
1744
+ const date = new Date();
1745
+ const hours = date.getHours();
1746
+
1747
+ if (greeting === null) {
1748
+ throw new Error('Greeting element not found');
1749
+ }
1750
+
1751
+ if (hours < HOURS_IN_DAY / 2) {
1752
+ greeting.textContent = 'Good Morning, welcome to AbsoluteJS !';
1753
+ } else if (hours < HOURS_IN_DAY * TWO_THIRDS) {
1754
+ greeting.textContent = 'Good Afternoon, welcome to AbsoluteJS !';
1755
+ } else {
1756
+ greeting.textContent = 'Good Evening, welcome to AbsoluteJS !';
1757
+ }
1758
+
1759
+ const button = document.getElementById('counter-button');
1760
+ const counter = document.getElementById('counter');
1761
+ let count = 0;
1762
+
1763
+ if (button === null || counter === null) {
1764
+ throw new Error('Button or counter element not found');
1765
+ }
1766
+
1767
+ button.addEventListener('click', () => {
1768
+ count++;
1769
+ counter.textContent = count.toString();
1770
+ });
1771
+
1772
+ const links = document.querySelectorAll${language === "ts" && "<HTMLAnchorElement>"}('#links a');
1773
+ links.forEach((link) => {
1774
+ link.addEventListener('mouseover', () => {
1775
+ link.style.transform = 'scale(1.2)';
1776
+ });
1777
+ link.addEventListener('mouseout', () => {
1778
+ link.style.transform = 'scale(1)';
1779
+ });
1780
+ });
1781
+
1782
+ const footerText = document.getElementById('footer-text');
1783
+
1784
+ if (footerText === null) {
1785
+ throw new Error('Footer text element not found');
1786
+ }
1787
+
1788
+ footerText.textContent = \`© ${new Date().getFullYear()} AbsoluteJS\`;
883
1789
  });
884
- if (pD(authProvider))
885
- abort();
886
- var plugins = await fe({
887
- message: "Select additional Elysia plugins (space to select, enter to submit):",
888
- options: [
889
- { label: cyan("⚙️ @elysia/cors"), value: "cors" },
890
- { label: cyan("\uD83D\uDCE6 @elysia/static"), value: "static" },
891
- { label: green("\uD83D\uDEE0️ elysia-rate-limit"), value: "rateLimit" },
892
- { label: green("\uD83D\uDCD1 elysia-swagger"), value: "swagger" }
893
- ],
894
- required: false
1790
+ `;
1791
+
1792
+ // src/generators/html/scaffoldHTML.ts
1793
+ var scaffoldHTML = ({
1794
+ templatesDirectory,
1795
+ isSingle,
1796
+ targetDirectory,
1797
+ stylesDirectory,
1798
+ htmlScriptOption,
1799
+ language
1800
+ }) => {
1801
+ const htmlTemplates = join6(templatesDirectory, "html");
1802
+ cpSync2(join6(htmlTemplates, "pages"), join6(targetDirectory, "pages"), {
1803
+ recursive: true
1804
+ });
1805
+ const scriptsDir = join6(targetDirectory, "scripts");
1806
+ mkdirSync3(scriptsDir);
1807
+ if (htmlScriptOption?.includes("ssr")) {
1808
+ const ssrScript = getSSRScript(language, isSingle);
1809
+ const ssrFileName = language === "ts" ? "typescriptSSRExample.ts" : "javascriptSSRExample.js";
1810
+ writeFileSync4(join6(scriptsDir, ssrFileName), ssrScript);
1811
+ }
1812
+ const htmlStylesSrc = join6(htmlTemplates, "styles");
1813
+ if (isSingle) {
1814
+ cpSync2(htmlStylesSrc, stylesDirectory, { recursive: true });
1815
+ } else {
1816
+ const dest = join6(stylesDirectory, "html");
1817
+ mkdirSync3(dest);
1818
+ cpSync2(htmlStylesSrc, dest, { recursive: true });
1819
+ }
1820
+ };
1821
+
1822
+ // src/generators/react/scaffoldReact.ts
1823
+ import { cpSync as cpSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "node:fs";
1824
+ import { join as join7 } from "node:path";
1825
+
1826
+ // src/generators/react/generateHeadComponent.ts
1827
+ var generateHeadComponent = (isSingle) => `import { styleReset } from '${isSingle ? "../../styles" : "../../../styles/react"}/defaultStyles';
1828
+
1829
+ type HeadProps = {
1830
+ title?: string;
1831
+ icon?: string;
1832
+ font?: string;
1833
+ };
1834
+
1835
+ export const Head = ({
1836
+ title = 'AbsoluteJS',
1837
+ icon = '/assets/ico/favicon.ico',
1838
+ font = 'Poppins'
1839
+ }: HeadProps) => (
1840
+ <head>
1841
+ <meta charSet="utf-8" />
1842
+ <title>{title}</title>
1843
+ <meta name="description" content="Bun, Elysia & React" />
1844
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1845
+ <link rel="icon" href={icon} />
1846
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
1847
+ <link
1848
+ rel="preconnect"
1849
+ href="https://fonts.gstatic.com"
1850
+ crossOrigin="anonymous"
1851
+ />
1852
+ <link
1853
+ href={\`https://fonts.googleapis.com/css2?family=\${font}:wght@100..900&display=swap\`}
1854
+ rel="stylesheet"
1855
+ />
1856
+ <style>{styleReset}</style>
1857
+ </head>
1858
+ );
1859
+ `;
1860
+
1861
+ // src/generators/react/generateReactPage.ts
1862
+ var generateReactPage = (isSingle) => `import { useState } from 'react';
1863
+ import { Head } from '../components/utils/Head';
1864
+ import {
1865
+ bodyDefault,
1866
+ htmlDefault,
1867
+ mainDefault
1868
+ } from '${isSingle ? "../styles" : "../../styles/react"}/defaultStyles';
1869
+
1870
+ export const ReactExample = () => {
1871
+ const [count, setCount] = useState(0);
1872
+
1873
+ return (
1874
+ <html lang="en" style={htmlDefault}>
1875
+ <Head />
1876
+ <body style={bodyDefault}>
1877
+ <main style={mainDefault}>
1878
+ <style>{\`
1879
+ @keyframes spin {
1880
+ from { transform: rotate(0deg); }
1881
+ to { transform: rotate(360deg); }
1882
+ }
1883
+ \`}</style>
1884
+ <div
1885
+ style={{
1886
+ flex: 1,
1887
+ display: 'flex',
1888
+ flexDirection: 'column',
1889
+ justifyContent: 'center',
1890
+ alignItems: 'center',
1891
+ padding: '1rem',
1892
+ gap: '1.5rem'
1893
+ }}
1894
+ >
1895
+ <a
1896
+ href="https://react.dev"
1897
+ target="_blank"
1898
+ rel="noreferrer"
1899
+ style={{
1900
+ textDecoration: 'none'
1901
+ }}
1902
+ >
1903
+ <img
1904
+ src="/assets/svg/react.svg"
1905
+ alt="React logo"
1906
+ style={{
1907
+ animation: 'spin 20s linear infinite',
1908
+ transformOrigin: 'center center',
1909
+ height: 145,
1910
+ display: 'block'
1911
+ }}
1912
+ />
1913
+ </a>
1914
+ <h1
1915
+ style={{
1916
+ fontSize: '2rem',
1917
+ fontWeight: 600,
1918
+ color: '#333',
1919
+ margin: 0
1920
+ }}
1921
+ >
1922
+ AbsoluteJS + React
1923
+ </h1>
1924
+ <button
1925
+ onClick={() => setCount(prev => prev + 1)}
1926
+ style={{
1927
+ padding: '0.75rem 1.5rem',
1928
+ fontSize: '1rem',
1929
+ fontWeight: 500,
1930
+ backgroundColor: '#0070f3',
1931
+ color: '#fff',
1932
+ border: 'none',
1933
+ borderRadius: '5px',
1934
+ cursor: 'pointer'
1935
+ }}
1936
+ >
1937
+ count is {count}
1938
+ </button>
1939
+ <p style={{ fontSize: '1rem', color: '#555', margin: 0 }}>
1940
+ Edit{' '}
1941
+ <code
1942
+ style={{
1943
+ backgroundColor: '#f5f5f5',
1944
+ padding: '0.2rem 0.4rem',
1945
+ borderRadius: '3px',
1946
+ fontFamily: 'monospace'
1947
+ }}
1948
+ >
1949
+ src/frontend/${isSingle ? "" : "react"}/pages/ReactExample.tsx
1950
+ </code>{' '}
1951
+ to edit this page
1952
+ </p>
1953
+ </div>
1954
+ </main>
1955
+ </body>
1956
+ </html>
1957
+ );
1958
+ };
1959
+ `;
1960
+
1961
+ // src/generators/react/scaffoldReact.ts
1962
+ var scaffoldReact = ({
1963
+ stylesDirectory,
1964
+ templatesDirectory,
1965
+ isSingle,
1966
+ targetDirectory
1967
+ }) => {
1968
+ const reactStylesSrc = join7(templatesDirectory, "react", "styles");
1969
+ const reactTemplates = join7(templatesDirectory, "react");
1970
+ const pagesDirectory = join7(targetDirectory, "pages");
1971
+ const componentsDirectory = join7(targetDirectory, "components");
1972
+ const pageExample = generateReactPage(isSingle);
1973
+ const headComponent = generateHeadComponent(isSingle);
1974
+ mkdirSync4(pagesDirectory);
1975
+ writeFileSync5(join7(pagesDirectory, "ReactExample.tsx"), pageExample);
1976
+ mkdirSync4(join7(componentsDirectory, "utils"), { recursive: true });
1977
+ writeFileSync5(join7(componentsDirectory, "utils", "Head.tsx"), headComponent);
1978
+ cpSync3(join7(reactTemplates, "hooks"), join7(targetDirectory, "hooks"), {
1979
+ recursive: true
1980
+ });
1981
+ if (isSingle) {
1982
+ cpSync3(reactStylesSrc, stylesDirectory, {
1983
+ recursive: true
1984
+ });
1985
+ } else {
1986
+ const dest = join7(stylesDirectory, "react");
1987
+ mkdirSync4(dest);
1988
+ cpSync3(reactStylesSrc, dest, {
1989
+ recursive: true
1990
+ });
1991
+ }
1992
+ };
1993
+
1994
+ // src/generators/project/scaffoldFrontends.ts
1995
+ var scaffoldFrontends = ({
1996
+ frontendDirectory,
1997
+ language,
1998
+ templatesDirectory,
1999
+ frontendConfigurations,
2000
+ tailwind,
2001
+ htmlScriptOption
2002
+ }) => {
2003
+ const isSingle = frontendConfigurations.length === 1;
2004
+ const stylesDirectory = join8(frontendDirectory, "styles");
2005
+ mkdirSync5(stylesDirectory);
2006
+ if (tailwind !== undefined) {
2007
+ copyFileSync3(join8(templatesDirectory, "tailwind", "tailwind.css"), join8(stylesDirectory, "tailwind.css"));
2008
+ }
2009
+ const dirMap = new Map;
2010
+ frontendConfigurations.forEach(({ name, directory }) => {
2011
+ const dir = directory?.trim() ?? (isSingle ? "" : name);
2012
+ if (dirMap.has(dir)) {
2013
+ throw new Error(`Frontend directory collision: "${dir}" is assigned to both "${dirMap.get(dir)}" and "${name}". Please pick unique directories.`);
2014
+ }
2015
+ dirMap.set(dir, name);
2016
+ const targetDirectory = join8(frontendDirectory, dir);
2017
+ !isSingle && mkdirSync5(targetDirectory);
2018
+ if (name === "react") {
2019
+ scaffoldReact({
2020
+ isSingle,
2021
+ stylesDirectory,
2022
+ targetDirectory,
2023
+ templatesDirectory
2024
+ });
2025
+ }
2026
+ if (name === "html") {
2027
+ scaffoldHTML({
2028
+ htmlScriptOption,
2029
+ isSingle,
2030
+ language,
2031
+ stylesDirectory,
2032
+ targetDirectory,
2033
+ templatesDirectory
2034
+ });
2035
+ }
2036
+ });
2037
+ };
2038
+
2039
+ // src/scaffold.ts
2040
+ var scaffold = ({
2041
+ response: {
2042
+ projectName,
2043
+ language,
2044
+ codeQualityTool,
2045
+ initializeGitNow,
2046
+ databaseEngine,
2047
+ databaseHost,
2048
+ htmlScriptOption,
2049
+ useTailwind,
2050
+ databaseDirectory,
2051
+ orm,
2052
+ plugins,
2053
+ authProvider,
2054
+ buildDirectory,
2055
+ assetsDirectory,
2056
+ tailwind,
2057
+ installDependenciesNow,
2058
+ frontendConfigurations
2059
+ },
2060
+ latest,
2061
+ packageManager
2062
+ }) => {
2063
+ const __dirname2 = dirname(fileURLToPath(import.meta.url));
2064
+ const templatesDirectory = join9(__dirname2, "/templates");
2065
+ const { frontendDirectory, backendDirectory } = initalizeRoot(projectName, templatesDirectory);
2066
+ copyFileSync4(join9(templatesDirectory, "README.md"), join9(projectName, "README.md"));
2067
+ addConfigurationFiles({
2068
+ codeQualityTool,
2069
+ initializeGitNow,
2070
+ language,
2071
+ projectName,
2072
+ tailwind,
2073
+ templatesDirectory
2074
+ });
2075
+ createPackageJson({
2076
+ authProvider,
2077
+ frontendConfigurations,
2078
+ latest,
2079
+ plugins,
2080
+ projectName,
2081
+ useTailwind
2082
+ });
2083
+ const serverFilePath = join9(backendDirectory, "server.ts");
2084
+ createServerFile({
2085
+ assetsDirectory,
2086
+ authProvider,
2087
+ availablePlugins,
2088
+ buildDirectory,
2089
+ frontendConfigurations,
2090
+ plugins,
2091
+ serverFilePath,
2092
+ tailwind
2093
+ });
2094
+ databaseDirectory !== undefined && scaffoldDatabase({
2095
+ databaseDirectory,
2096
+ databaseEngine,
2097
+ orm,
2098
+ projectName
2099
+ });
2100
+ scaffoldFrontends({
2101
+ frontendConfigurations,
2102
+ frontendDirectory,
2103
+ htmlScriptOption,
2104
+ language,
2105
+ tailwind,
2106
+ templatesDirectory
2107
+ });
2108
+ if (installDependenciesNow) {
2109
+ installDependencies({ packageManager, projectName });
2110
+ }
2111
+ formatProject({
2112
+ packageManager,
2113
+ projectName
2114
+ });
2115
+ };
2116
+
2117
+ // src/utils/t3-utils.ts
2118
+ import { env } from "node:process";
2119
+ var getUserPackageManager = () => {
2120
+ const userAgent = env.npm_config_user_agent;
2121
+ if (userAgent) {
2122
+ if (userAgent.startsWith("yarn")) {
2123
+ return "yarn";
2124
+ } else if (userAgent.startsWith("pnpm")) {
2125
+ return "pnpm";
2126
+ } else if (userAgent.startsWith("bun")) {
2127
+ return "bun";
2128
+ }
2129
+ return "npm";
2130
+ }
2131
+ return "npm";
2132
+ };
2133
+
2134
+ // src/index.ts
2135
+ var { values } = parseArgs({
2136
+ args: argv.slice(DEFAULT_ARG_LENGTH),
2137
+ options: {
2138
+ debug: { default: false, short: "d", type: "boolean" },
2139
+ help: { default: false, short: "h", type: "boolean" },
2140
+ latest: { default: false, short: "l", type: "boolean" }
2141
+ },
2142
+ strict: false
895
2143
  });
896
- if (pD(plugins))
897
- abort();
898
- Se(`
899
- Project Name: ${projectName}
900
- Language: ${language === "ts" ? "TypeScript" : "JavaScript"}
901
- Tailwind: ${tailwind ? `input: ${tailwind.input}, output: ${tailwind.output}` : "None"}
902
- Framework(s): ${frameworks.join(", ")}
903
- Build Directory: ${buildDir}
904
- Assets Directory: ${assetsDir}
905
- Database: ${dbProvider === "none" ? "None" : dbProvider}
906
- ORM: ${orm ?? "None"}
907
- Auth: ${authProvider === "none" ? "None" : authProvider}
908
- Plugins: ${plugins.length ? plugins.join(", ") : "None"}
909
-
910
- Framework Config:
911
- ${configs.map(({ framework, pages, index }) => `${frameworkNames[framework] ?? framework} ⇒ pages: ${pages}, index: ${index}`).join(`
912
- `)}
913
- `);
2144
+ var packageManager = getUserPackageManager();
2145
+ if (values.help === true) {
2146
+ console.log(helpMessage);
2147
+ exit4(0);
2148
+ }
2149
+ var response = await prompt();
2150
+ scaffold({ latest: values.latest === true, packageManager, response });
2151
+ var debugMessage = values.debug !== false ? getDebugMessage({
2152
+ availableFrontends,
2153
+ packageManager,
2154
+ response
2155
+ }) : "";
2156
+ var outroMessage = getOutroMessage({
2157
+ installDependenciesNow: response.installDependenciesNow,
2158
+ packageManager,
2159
+ projectName: response.projectName
2160
+ });
2161
+ Se(debugMessage + outroMessage);