create-absolutejs 0.1.10 → 0.2.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.
package/dist/index.js CHANGED
@@ -1,4 +1,3 @@
1
- #!/usr/bin/env node
2
1
  var __create = Object.create;
3
2
  var __getProtoOf = Object.getPrototypeOf;
4
3
  var __defProp = Object.defineProperty;
@@ -146,8 +145,7 @@ var require_picocolors = __commonJS((exports, module) => {
146
145
  });
147
146
 
148
147
  // src/index.ts
149
- import { argv, exit as exit4 } from "node:process";
150
- import { parseArgs } from "node:util";
148
+ import { exit as exit5 } from "node:process";
151
149
 
152
150
  // node_modules/@clack/core/dist/index.mjs
153
151
  var import_sisteransi = __toESM(require_src(), 1);
@@ -837,21 +835,49 @@ var Y2 = ({ indicator: t = "dots" } = {}) => {
837
835
  } };
838
836
  };
839
837
 
840
- // src/constants.ts
841
- var UNFOUND_INDEX = -1;
842
- var DEFAULT_ARG_LENGTH = 2;
843
- var TWO_THIRDS = 2 / 3;
838
+ // src/messages.ts
839
+ var import_picocolors4 = __toESM(require_picocolors(), 1);
844
840
 
845
841
  // src/data.ts
846
842
  var import_picocolors3 = __toESM(require_picocolors(), 1);
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" }
843
+ var availableFrontends = [
844
+ "react",
845
+ "html",
846
+ "svelte",
847
+ "htmx"
848
+ ];
849
+ var availableAuthProviders = ["absoluteAuth", "none"];
850
+ var availableLanguages = ["ts", "js"];
851
+ var availableHTMLScriptOptions = ["js", "ts", "none"];
852
+ var availableDatabaseEngines = [
853
+ "postgresql",
854
+ "mysql",
855
+ "sqlite",
856
+ "mongodb",
857
+ "redis",
858
+ "singlestore",
859
+ "cockroachdb",
860
+ "mssql",
861
+ "none"
862
+ ];
863
+ var availableDirectoryConfigurations = ["default", "custom"];
864
+ var availableORMs = ["drizzle", "prisma", "none"];
865
+ var availableDatabaseHosts = [
866
+ "neon",
867
+ "planetscale",
868
+ "supabase",
869
+ "turso",
870
+ "vercel",
871
+ "upstash",
872
+ "atlas",
873
+ "none"
874
+ ];
875
+ var availableCodeQualityTools = ["eslint+prettier", "biome"];
876
+ var frontendLabels = {
877
+ react: import_picocolors3.cyan("React"),
878
+ html: "HTML",
879
+ svelte: import_picocolors3.magenta("Svelte"),
880
+ htmx: "HTMX"
855
881
  };
856
882
  var availablePlugins = [
857
883
  {
@@ -907,7 +933,7 @@ var defaultPlugins = [
907
933
  { isPlugin: false, packageName: "build" },
908
934
  { isPlugin: true, packageName: "networkingPlugin" }
909
935
  ],
910
- latestVersion: "0.6.0",
936
+ latestVersion: "0.8.14",
911
937
  value: "@absolutejs/absolute"
912
938
  },
913
939
  {
@@ -924,18 +950,43 @@ var defaultPlugins = [
924
950
  ];
925
951
 
926
952
  // src/messages.ts
927
- var import_picocolors4 = __toESM(require_picocolors(), 1);
928
953
  var helpMessage = `
929
- Usage: create-absolute [options] [dir]
954
+ Usage: create-absolute [options] [${import_picocolors4.magenta("project-name")}]
930
955
 
931
956
  Arguments:
932
- dir The name of the created application.
933
- If not specified, the user will be prompted during creation.
957
+ ${import_picocolors4.magenta("project-name")} Name of the application to create.
958
+ If omitted, you'll be prompted to enter one.
934
959
 
935
960
  Options:
936
- -h, --help Show this help message and exit
937
- -d, --debug Show a summary of the project configuration after creation
938
- -l, --latest Fetch and use the latest version of required packages
961
+ ${import_picocolors4.cyan("--help, -h")} Show this help message and exit
962
+ ${import_picocolors4.cyan("--debug, -d")} Display a summary of the project configuration after creation
963
+
964
+ ${import_picocolors4.cyan("--angular")} ${import_picocolors4.dim(import_picocolors4.cyan("<dir>"))} Directory name for an Angular frontend
965
+ ${import_picocolors4.cyan("--assets")} ${import_picocolors4.dim(import_picocolors4.cyan("<dir>"))} Directory name for your static assets
966
+ ${import_picocolors4.cyan("--auth")} ${import_picocolors4.dim(import_picocolors4.cyan("<plugin>"))} Preconfigured auth plugin (currently only "absolute-auth") or 'none' to skip auth setup
967
+ ${import_picocolors4.cyan("--build")} ${import_picocolors4.dim(import_picocolors4.cyan("<dir>"))} Output directory for build artifacts
968
+ ${import_picocolors4.cyan("--database")} ${import_picocolors4.dim(import_picocolors4.cyan("<dir>"))} Directory name for your database files
969
+ ${import_picocolors4.cyan("--directory")} ${import_picocolors4.dim(import_picocolors4.cyan("<mode>"))} Directory-naming strategy: "default" or "custom"
970
+ ${import_picocolors4.cyan("--engine")} ${import_picocolors4.dim(import_picocolors4.cyan("<engine>"))} Database engine (postgresql | mysql | sqlite | mongodb | redis | singlestore | cockroachdb | mssql) or 'none' to skip database setup
971
+ ${import_picocolors4.cyan("--frontend")} ${import_picocolors4.dim(import_picocolors4.cyan("<name>"))} Frontend framework(s) to include: one or more of "react", "svelte", "html", "htmx", "vue", "angular"
972
+ ${import_picocolors4.cyan("--git")} Initialize a Git repository
973
+ ${import_picocolors4.cyan("--host")} ${import_picocolors4.dim(import_picocolors4.cyan("<host>"))} Database host provider (neon | planetscale | supabase | turso | vercel | upstash | atlas) or 'none' to skip database host setup
974
+ ${import_picocolors4.cyan("--html")} ${import_picocolors4.dim(import_picocolors4.cyan("<dir>"))} Directory name for an HTML frontend
975
+ ${import_picocolors4.cyan("--htmx")} ${import_picocolors4.dim(import_picocolors4.cyan("<dir>"))} Directory name for an HTMX frontend
976
+ ${import_picocolors4.cyan("--lang")} ${import_picocolors4.dim(import_picocolors4.cyan("<lang>"))} Language: "ts" or "js"
977
+ ${import_picocolors4.cyan("--lts")} Use LTS versions of required packages
978
+ ${import_picocolors4.cyan("--npm")} Use the package manager that invoked this command to install dependencies
979
+ ${import_picocolors4.cyan("--orm")} ${import_picocolors4.dim(import_picocolors4.cyan("<orm>"))} ORM to configure: "drizzle" or "prisma" or 'none' to skip ORM setup
980
+ ${import_picocolors4.cyan("--plugin")} ${import_picocolors4.dim(import_picocolors4.cyan("<plugin>"))} Elysia plugin(s) to include (can be specified multiple times), passing 'none' will skip plugin setup and ignore any other plugin options
981
+ ${import_picocolors4.cyan("--quality")} ${import_picocolors4.dim(import_picocolors4.cyan("<tool>"))} Code quality tool: "eslint+prettier" or "biome"
982
+ ${import_picocolors4.cyan("--react")} ${import_picocolors4.dim(import_picocolors4.cyan("<dir>"))} Directory name for a React frontend
983
+ ${import_picocolors4.cyan("--script")} ${import_picocolors4.dim(import_picocolors4.cyan("<option>"))} HTML scripting option: "ts" or "js" or 'none' to skip HTML scripting setup
984
+ ${import_picocolors4.cyan("--skip")} Skips non required prompts and uses 'none' for all optional configurations
985
+ ${import_picocolors4.cyan("--svelte")} ${import_picocolors4.dim(import_picocolors4.cyan("<dir>"))} Directory name for a Svelte frontend
986
+ ${import_picocolors4.cyan("--tailwind")} Include Tailwind CSS setup
987
+ ${import_picocolors4.cyan("--tailwind-input")} ${import_picocolors4.dim(import_picocolors4.cyan("<file>"))} Path to your Tailwind CSS entry file
988
+ ${import_picocolors4.cyan("--tailwind-output")} ${import_picocolors4.dim(import_picocolors4.cyan("<file>"))} Path for the generated Tailwind CSS bundle
989
+ ${import_picocolors4.cyan("--vue")} ${import_picocolors4.dim(import_picocolors4.cyan("<dir>"))} Directory name for a Vue frontend
939
990
  `;
940
991
  var getOutroMessage = ({
941
992
  projectName,
@@ -944,19 +995,19 @@ var getOutroMessage = ({
944
995
  }) => `${import_picocolors4.green("Created successfully")}, you can now run:
945
996
 
946
997
  ` + `${import_picocolors4.cyan("cd")} ${projectName}
947
- ` + `${import_picocolors4.cyan(`${packageManager} dev`)}${installDependenciesNow ? "" : `
948
- ${import_picocolors4.cyan(`${packageManager} install`)}`}`;
998
+ ` + `${installDependenciesNow ? "" : `${import_picocolors4.cyan(`${packageManager} install`)}
999
+ `}` + `${import_picocolors4.cyan(`${packageManager} dev`)}`;
949
1000
  var getDebugMessage = ({
950
1001
  response: {
951
1002
  projectName,
952
1003
  language,
953
1004
  codeQualityTool,
954
- configType,
1005
+ directoryConfig,
955
1006
  useTailwind,
956
1007
  tailwind,
957
1008
  frontends,
958
1009
  htmlScriptOption,
959
- frontendConfigurations,
1010
+ frontendDirectories,
960
1011
  buildDirectory,
961
1012
  assetsDirectory,
962
1013
  databaseEngine,
@@ -968,51 +1019,49 @@ var getDebugMessage = ({
968
1019
  initializeGitNow,
969
1020
  installDependenciesNow
970
1021
  },
971
- packageManager,
972
- availableFrontends: availableFrontends2
1022
+ packageManager
973
1023
  }) => {
974
1024
  const htmlLabels = {
975
1025
  js: import_picocolors4.yellow("JavaScript"),
976
- "js+ssr": import_picocolors4.yellow("JavaScript + SSR"),
977
- ts: import_picocolors4.blueBright("TypeScript"),
978
- "ts+ssr": import_picocolors4.blueBright("TypeScript + SSR")
1026
+ none: import_picocolors4.dim("None"),
1027
+ ts: import_picocolors4.blueBright("TypeScript")
979
1028
  };
980
- const htmlScriptingValue = htmlScriptOption !== undefined ? htmlLabels[htmlScriptOption] : import_picocolors4.dim("None");
981
- const htmlScriptingLine = frontends.includes("html") ? `
982
- ${import_picocolors4.magenta("HTML Scripting")}: ${htmlScriptingValue}` : "";
983
- const frontendLabels = frontends.map((name) => availableFrontends2[name]?.label ?? name);
984
- const frontendHeading = frontends.length === 1 ? import_picocolors4.magenta("Frontend") : import_picocolors4.magenta("Frontends");
985
- const configString = frontendConfigurations.reduce((acc, { name, directory }, idx, arr) => {
986
- const label = availableFrontends2[name]?.label ?? name;
987
- const segment = `${label}: src/frontend/${directory}${idx < arr.length - 1 ? `
988
- ` : ""}`;
989
- return acc + segment;
990
- }, "");
991
- const tailwindSection = tailwind && useTailwind ? `
992
- ${import_picocolors4.cyan("Input")}: ${tailwind.input}
993
- ${import_picocolors4.cyan("Output")}: ${tailwind.output}` : import_picocolors4.dim("None");
994
- return `
995
- ${import_picocolors4.magenta("Project Name")}: ${projectName}
996
- ${import_picocolors4.magenta("Package Manager")}: ${packageManager}
997
- ${import_picocolors4.magenta("Config Type")}: ${configType === "custom" ? import_picocolors4.green("Custom") : import_picocolors4.dim("Default")}
998
- ${import_picocolors4.magenta("Language")}: ${language === "ts" ? import_picocolors4.blueBright("TypeScript") : import_picocolors4.yellow("JavaScript")}
999
- ${import_picocolors4.magenta("Linting")}: ${codeQualityTool === "eslint+prettier" ? "ESLint + Prettier" : "Biome"}
1000
- ${import_picocolors4.magenta("Tailwind Configuration")}: ${tailwindSection}
1001
- ${frontendHeading}: ${frontendLabels.join(", ")}${htmlScriptingLine}
1002
- ${import_picocolors4.magenta("Build Directory")}: ${buildDirectory}
1003
- ${import_picocolors4.magenta("Assets Directory")}: ${assetsDirectory}
1004
- ${import_picocolors4.magenta("Database Engine")}: ${databaseEngine ?? import_picocolors4.dim("None")}
1005
- ${import_picocolors4.magenta("Database Host")}: ${databaseHost ?? import_picocolors4.dim("None")}
1006
- ${import_picocolors4.magenta("Database Directory")}: ${databaseDirectory ?? import_picocolors4.dim("None")}
1007
- ${import_picocolors4.magenta("ORM")}: ${orm ?? import_picocolors4.dim("None")}
1008
- ${import_picocolors4.magenta("Authorization Provider")}: ${authProvider ?? import_picocolors4.dim("None")}
1009
- ${import_picocolors4.magenta("Plugins")}: ${plugins.length ? plugins.join(", ") : import_picocolors4.dim("None")}
1010
- ${import_picocolors4.magenta("Initialize Git")}: ${initializeGitNow ? import_picocolors4.green("Yes") : import_picocolors4.dim("No")}
1011
- ${import_picocolors4.magenta("Install Dependencies")}: ${installDependenciesNow ? import_picocolors4.green("Yes") : import_picocolors4.red("No")}
1012
- ${import_picocolors4.magenta("Framework Config")}:
1013
- ${configString}
1014
-
1015
- `;
1029
+ const htmlScriptingValue = htmlScriptOption ? htmlLabels[htmlScriptOption] : import_picocolors4.dim("None");
1030
+ const frameworkConfig = frontends.map((name) => `${frontendLabels[name]}: src/frontend/${frontendDirectories[name]}`).join(`
1031
+ `);
1032
+ const tailwindSection = useTailwind && tailwind ? `Input: ${tailwind.input}
1033
+ Output: ${tailwind.output}` : import_picocolors4.dim("None");
1034
+ const isCustomConfig = directoryConfig === "custom";
1035
+ const lines = [
1036
+ ["Project Name", projectName],
1037
+ ["Package Manager", packageManager],
1038
+ ["Config Type", isCustomConfig ? import_picocolors4.green("Custom") : import_picocolors4.dim("Default")],
1039
+ ["Language", language === "ts" ? import_picocolors4.blueBright("TypeScript") : import_picocolors4.yellow("JavaScript")],
1040
+ ["Linting", codeQualityTool === "eslint+prettier" ? "ESLint + Prettier" : "Biome"],
1041
+ ["Tailwind Configuration", tailwindSection],
1042
+ [frontends.length === 1 ? "Frontend" : "Frontends", frontends.map((name) => frontendLabels[name]).join(", ")],
1043
+ ["HTML Scripting", frontends.includes("html") ? htmlScriptingValue : import_picocolors4.dim("None")],
1044
+ ["Build Directory", buildDirectory],
1045
+ ["Assets Directory", assetsDirectory],
1046
+ ["Database Engine", databaseEngine && databaseEngine !== "none" ? databaseEngine : import_picocolors4.dim("None")],
1047
+ ["Database Host", databaseHost && databaseHost !== "none" ? databaseHost : import_picocolors4.dim("None")],
1048
+ ["Database Directory", databaseDirectory ?? import_picocolors4.dim("None")],
1049
+ ["ORM", orm ?? import_picocolors4.dim("None")],
1050
+ ["Auth Provider", authProvider && authProvider !== "none" ? authProvider : import_picocolors4.dim("None")],
1051
+ ["Plugins", plugins.length && !plugins.includes("none") ? plugins.join(", ") : import_picocolors4.dim("None")],
1052
+ ["Initialize Git", initializeGitNow ? import_picocolors4.green("Yes") : import_picocolors4.red("No")],
1053
+ ["Install Dependencies", installDependenciesNow ? import_picocolors4.green("Yes") : import_picocolors4.red("No")],
1054
+ ["Framework Config", frameworkConfig]
1055
+ ];
1056
+ const maxLabelLength = Math.max(...lines.map(([label]) => label.length));
1057
+ const body = `
1058
+
1059
+ ${lines.map(([label, value]) => {
1060
+ const gap = " ".repeat(maxLabelLength - label.length);
1061
+ return `${import_picocolors4.magenta(label)}:${gap} ${value}`;
1062
+ }).join(`
1063
+ `)}`;
1064
+ return body;
1016
1065
  };
1017
1066
 
1018
1067
  // src/questions/authProvider.ts
@@ -1060,16 +1109,16 @@ var getCodeQualityTool = async () => {
1060
1109
  // src/questions/configurationType.ts
1061
1110
  var import_picocolors7 = __toESM(require_picocolors(), 1);
1062
1111
  var getConfigurationType = async () => {
1063
- const configType = await ve({
1112
+ const directoryConfig = await ve({
1064
1113
  message: "Choose folder naming configuration:",
1065
1114
  options: [
1066
1115
  { label: import_picocolors7.blueBright("Default"), value: "default" },
1067
1116
  { label: import_picocolors7.yellow("Custom"), value: "custom" }
1068
1117
  ]
1069
1118
  });
1070
- if (pD(configType))
1119
+ if (pD(directoryConfig))
1071
1120
  abort();
1072
- return configType;
1121
+ return directoryConfig;
1073
1122
  };
1074
1123
 
1075
1124
  // src/questions/databaseEngine.ts
@@ -1147,28 +1196,29 @@ var getDatabaseHost = async (databaseEngine) => {
1147
1196
 
1148
1197
  // src/questions/directoryConfiguration.ts
1149
1198
  var getDirectoryConfiguration = async ({
1150
- configType,
1199
+ directoryConfig,
1151
1200
  useTailwind,
1152
- databaseEngine
1201
+ databaseEngine,
1202
+ argumentConfiguration
1153
1203
  }) => {
1154
- if (configType === "default") {
1204
+ if (directoryConfig === "default") {
1155
1205
  return {
1156
- assetsDirectory: "src/backend/assets",
1157
- buildDirectory: "build",
1158
- databaseDirectory: databaseEngine && "db",
1206
+ assetsDirectory: argumentConfiguration.assetsDirectory ?? "src/backend/assets",
1207
+ buildDirectory: argumentConfiguration.buildDirectory ?? "build",
1208
+ databaseDirectory: databaseEngine ? argumentConfiguration.databaseDirectory ?? "db" : undefined,
1159
1209
  tailwind: useTailwind ? {
1160
- input: "./src/frontend/styles/tailwind.css",
1161
- output: "/assets/css/tailwind.generated.css"
1210
+ input: argumentConfiguration.tailwind?.input ?? "./src/frontend/styles/tailwind.css",
1211
+ output: argumentConfiguration.tailwind?.output ?? "/assets/css/tailwind.generated.css"
1162
1212
  } : undefined
1163
1213
  };
1164
1214
  }
1165
- const buildDirectory = await he({
1215
+ const buildDirectory = argumentConfiguration.buildDirectory ?? await he({
1166
1216
  message: "Build directory:",
1167
1217
  placeholder: "build"
1168
1218
  });
1169
1219
  if (pD(buildDirectory))
1170
1220
  abort();
1171
- const assetsDirectory = await he({
1221
+ const assetsDirectory = argumentConfiguration.assetsDirectory ?? await he({
1172
1222
  message: "Assets directory:",
1173
1223
  placeholder: "src/backend/assets"
1174
1224
  });
@@ -1176,13 +1226,13 @@ var getDirectoryConfiguration = async ({
1176
1226
  abort();
1177
1227
  let tailwind;
1178
1228
  if (useTailwind) {
1179
- const input = await he({
1229
+ const input = argumentConfiguration.tailwind?.input ?? await he({
1180
1230
  message: "Tailwind input CSS file:",
1181
1231
  placeholder: "./src/frontend/styles/tailwind.css"
1182
1232
  });
1183
1233
  if (pD(input))
1184
1234
  abort();
1185
- const output = await he({
1235
+ const output = argumentConfiguration.tailwind?.output ?? await he({
1186
1236
  message: "Tailwind output CSS file:",
1187
1237
  placeholder: "/assets/css/tailwind.generated.css"
1188
1238
  });
@@ -1194,7 +1244,7 @@ var getDirectoryConfiguration = async ({
1194
1244
  }
1195
1245
  let databaseDirectory;
1196
1246
  if (databaseEngine !== undefined) {
1197
- databaseDirectory = await he({
1247
+ databaseDirectory = argumentConfiguration.databaseDirectory ?? await he({
1198
1248
  message: "Database directory:",
1199
1249
  placeholder: "db"
1200
1250
  });
@@ -1210,62 +1260,66 @@ var getDirectoryConfiguration = async ({
1210
1260
  };
1211
1261
 
1212
1262
  // src/questions/frontendDirectoryConfigurations.ts
1213
- var getFrontendDirectoryConfigurations = async (configType, frontends) => {
1214
- let frontendConfigurations;
1215
- const single = frontends.length === 1;
1216
- if (configType === "custom") {
1217
- frontendConfigurations = await frontends.reduce(async (prevP, frontend) => {
1218
- const prev = await prevP;
1219
- const pretty = availableFrontends[frontend]?.name ?? frontend;
1220
- const base = single ? "" : `${frontend}`;
1221
- const defDir = base;
1222
- const frontendDirectory = await he({
1223
- message: `${pretty} directory:`,
1224
- placeholder: defDir
1225
- });
1226
- if (pD(frontendDirectory))
1227
- abort();
1228
- return [
1229
- ...prev,
1230
- { directory: frontendDirectory, frontend, name: frontend }
1231
- ];
1232
- }, Promise.resolve([]));
1233
- } else {
1234
- frontendConfigurations = frontends.map((frontend) => ({
1235
- directory: single ? "" : frontend,
1236
- frontend,
1237
- name: frontend
1238
- }));
1239
- }
1240
- return frontendConfigurations;
1263
+ var getDirectoryForFrontend = async (directoryConfiguration, frontend, isSingleFrontend) => {
1264
+ if (directoryConfiguration !== "custom")
1265
+ return isSingleFrontend ? "" : frontend;
1266
+ const response = await he({
1267
+ message: `${frontendLabels[frontend]} directory:`,
1268
+ placeholder: isSingleFrontend ? "" : frontend
1269
+ });
1270
+ if (pD(response))
1271
+ abort();
1272
+ return response;
1241
1273
  };
1274
+ var getFrontendDirectoryConfigurations = async (directoryConfiguration, frontends, passedFrontendDirectories) => {
1275
+ const isSingleFrontend = frontends.length === 1;
1276
+ const frontendDirectories = {};
1277
+ const frontendsToPrompt = [];
1278
+ for (const frontend of frontends) {
1279
+ const prefilled = passedFrontendDirectories?.[frontend];
1280
+ if (prefilled === undefined)
1281
+ frontendsToPrompt.push(frontend);
1282
+ else
1283
+ frontendDirectories[frontend] = prefilled;
1284
+ }
1285
+ const promptedDirectories = await Promise.all(frontendsToPrompt.map((name) => getDirectoryForFrontend(directoryConfiguration, name, isSingleFrontend)));
1286
+ frontendsToPrompt.forEach((name, index) => frontendDirectories[name] = promptedDirectories[index]);
1287
+ return frontendDirectories;
1288
+ };
1289
+
1290
+ // src/typeGuards.ts
1291
+ var isLanguage = (value) => value === "ts" || value === "js";
1292
+ var isAuthProvider = (value) => value === "absoluteAuth" || value === "none" || value === undefined;
1293
+ var isDirectoryConfig = (value) => value === "default" || value === "custom";
1294
+ var isDatabaseEngine = (value) => value === "postgresql" || value === "mysql" || value === "sqlite" || value === "mongodb" || value === "redis" || value === "singlestore" || value === "cockroachdb" || value === "mssql" || value === "none" || value === undefined;
1295
+ var isDatabaseHost = (value) => value === "neon" || value === "planetscale" || value === "supabase" || value === "turso" || value === "vercel" || value === "upstash" || value === "atlas" || value === undefined;
1296
+ var isORM = (value) => value === "drizzle" || value === "prisma" || value === undefined;
1297
+ var isCodeQualityTool = (value) => value === "eslint+prettier" || value === "biome" || value === undefined;
1298
+ var isHTMLScriptOption = (value) => value === "ts" || value === "js" || value === "ts+ssr" || value === "js+ssr" || value === "none" || value === undefined;
1299
+ var isFrontend = (value) => value !== undefined && Object.keys(frontendLabels).includes(value);
1242
1300
 
1243
1301
  // src/questions/frontends.ts
1244
1302
  var getFrontends = async () => {
1245
1303
  const frontends = await fe({
1246
1304
  message: "Frontend(s) (space to select, enter to finish):",
1247
- options: Object.entries(availableFrontends).map(([value, { label }]) => ({ label, value }))
1305
+ options: Object.entries(frontendLabels).map(([value, label]) => ({
1306
+ label,
1307
+ value
1308
+ }))
1248
1309
  });
1249
1310
  if (pD(frontends))
1250
1311
  abort();
1251
- return frontends;
1312
+ return frontends.filter(isFrontend);
1252
1313
  };
1253
1314
 
1254
1315
  // src/questions/htmlScriptingOption.ts
1255
- var import_picocolors10 = __toESM(require_picocolors(), 1);
1256
1316
  var getHtmlScriptingOption = async (language) => {
1257
- const langLabel = language === "ts" ? import_picocolors10.blueBright("TypeScript") : import_picocolors10.yellow("JavaScript");
1258
- const htmlScriptOption = await ve({
1259
- message: `Add HTML scripting option (${langLabel}):`,
1260
- options: [
1261
- { label: `${langLabel} + SSR`, value: `${language}+ssr` },
1262
- { label: langLabel, value: language },
1263
- { label: "None", value: "none" }
1264
- ]
1317
+ const useScripts = await ye({
1318
+ message: "Would you like to use scripts for your HTML pages?"
1265
1319
  });
1266
- if (pD(htmlScriptOption))
1320
+ if (pD(useScripts))
1267
1321
  abort();
1268
- return htmlScriptOption === "none" ? undefined : htmlScriptOption;
1322
+ return useScripts ? language : undefined;
1269
1323
  };
1270
1324
 
1271
1325
  // src/questions/initializeGitNow.ts
@@ -1289,13 +1343,13 @@ var getInstallDependencies = async () => {
1289
1343
  };
1290
1344
 
1291
1345
  // src/questions/language.ts
1292
- var import_picocolors11 = __toESM(require_picocolors(), 1);
1346
+ var import_picocolors10 = __toESM(require_picocolors(), 1);
1293
1347
  var getLanguage = async () => {
1294
1348
  const language = await ve({
1295
1349
  message: "Language:",
1296
1350
  options: [
1297
- { label: import_picocolors11.blueBright("TypeScript"), value: "ts" },
1298
- { label: import_picocolors11.yellow("JavaScript"), value: "js" }
1351
+ { label: import_picocolors10.blueBright("TypeScript"), value: "ts" },
1352
+ { label: import_picocolors10.yellow("JavaScript"), value: "js" }
1299
1353
  ]
1300
1354
  });
1301
1355
  if (pD(language))
@@ -1304,14 +1358,14 @@ var getLanguage = async () => {
1304
1358
  };
1305
1359
 
1306
1360
  // src/questions/orm.ts
1307
- var import_picocolors12 = __toESM(require_picocolors(), 1);
1361
+ var import_picocolors11 = __toESM(require_picocolors(), 1);
1308
1362
  var getORM = async () => {
1309
1363
  const orm = await ve({
1310
1364
  message: "Choose an ORM (optional):",
1311
1365
  options: [
1312
1366
  { label: "None", value: "none" },
1313
- { label: import_picocolors12.cyan("Drizzle"), value: "drizzle" },
1314
- { label: import_picocolors12.magenta("Prisma"), value: "prisma" }
1367
+ { label: import_picocolors11.cyan("Drizzle"), value: "drizzle" },
1368
+ { label: import_picocolors11.magenta("Prisma"), value: "prisma" }
1315
1369
  ]
1316
1370
  });
1317
1371
  if (pD(orm))
@@ -1351,37 +1405,40 @@ var getUseTailwind = async () => {
1351
1405
  };
1352
1406
 
1353
1407
  // src/prompt.ts
1354
- var prompt = async () => {
1355
- const projectName = await getProjectName();
1356
- const language = await getLanguage();
1357
- const codeQualityTool = await getCodeQualityTool();
1358
- const useTailwind = await getUseTailwind();
1359
- const frontends = await getFrontends();
1360
- const htmlScriptOption = frontends.includes("html") ? await getHtmlScriptingOption(language) : undefined;
1361
- const databaseEngine = await getDatabaseEngine();
1362
- const databaseHost = await getDatabaseHost(databaseEngine);
1363
- const orm = databaseEngine !== undefined ? await getORM() : undefined;
1364
- const configType = await getConfigurationType();
1408
+ var prompt = async (argumentConfiguration) => {
1409
+ const projectName = argumentConfiguration.projectName ?? await getProjectName();
1410
+ const language = argumentConfiguration.language ?? await getLanguage();
1411
+ const codeQualityTool = argumentConfiguration.codeQualityTool ?? await getCodeQualityTool();
1412
+ const useTailwind = argumentConfiguration.useTailwind ?? await getUseTailwind();
1413
+ const frontends = argumentConfiguration.frontends?.filter((frontend) => frontend !== undefined) ?? await getFrontends();
1414
+ const htmlScriptOption = !frontends.includes("html") || argumentConfiguration.htmlScriptOption === "none" ? undefined : argumentConfiguration.htmlScriptOption ?? await getHtmlScriptingOption(language);
1415
+ const databaseEngine = argumentConfiguration.databaseEngine ?? await getDatabaseEngine();
1416
+ const databaseHost = argumentConfiguration.databaseHost ?? await getDatabaseHost(databaseEngine);
1417
+ const orm = databaseEngine !== undefined && databaseEngine !== "none" ? argumentConfiguration.orm ?? await getORM() : undefined;
1418
+ let directoryConfig = argumentConfiguration.directoryConfig ?? await getConfigurationType();
1365
1419
  const { buildDirectory, assetsDirectory, tailwind, databaseDirectory } = await getDirectoryConfiguration({
1366
- configType,
1420
+ argumentConfiguration,
1367
1421
  databaseEngine,
1422
+ directoryConfig,
1368
1423
  useTailwind
1369
1424
  });
1370
- const frontendConfigurations = await getFrontendDirectoryConfigurations(configType, frontends);
1371
- const authProvider = await getAuthProvider();
1372
- const plugins = await getPlugins();
1373
- const initializeGitNow = await getInitializeGit();
1374
- const installDependenciesNow = await getInstallDependencies();
1425
+ const frontendDirectories = await getFrontendDirectoryConfigurations(directoryConfig, frontends, argumentConfiguration.frontendDirectories);
1426
+ if (argumentConfiguration.frontendDirectories !== undefined)
1427
+ directoryConfig = "custom";
1428
+ const authProvider = argumentConfiguration.authProvider ?? await getAuthProvider();
1429
+ const plugins = argumentConfiguration.plugins?.filter((plugin) => plugin !== undefined) ?? await getPlugins();
1430
+ const initializeGitNow = argumentConfiguration.initializeGitNow ?? await getInitializeGit();
1431
+ const installDependenciesNow = argumentConfiguration.installDependenciesNow ?? await getInstallDependencies();
1375
1432
  const values = {
1376
1433
  assetsDirectory,
1377
1434
  authProvider,
1378
1435
  buildDirectory,
1379
1436
  codeQualityTool,
1380
- configType,
1381
1437
  databaseDirectory,
1382
1438
  databaseEngine,
1383
1439
  databaseHost,
1384
- frontendConfigurations,
1440
+ directoryConfig,
1441
+ frontendDirectories,
1385
1442
  frontends,
1386
1443
  htmlScriptOption,
1387
1444
  initializeGitNow,
@@ -1398,13 +1455,13 @@ var prompt = async () => {
1398
1455
 
1399
1456
  // src/scaffold.ts
1400
1457
  import { copyFileSync as copyFileSync4 } from "node:fs";
1401
- import { join as join9, dirname } from "node:path";
1458
+ import { join as join10, dirname } from "node:path";
1402
1459
  import { fileURLToPath } from "node:url";
1403
1460
 
1404
1461
  // src/commands/formatProject.ts
1405
1462
  import { execSync } from "child_process";
1406
1463
  import { exit as exit2 } from "process";
1407
- var import_picocolors13 = __toESM(require_picocolors(), 1);
1464
+ var import_picocolors12 = __toESM(require_picocolors(), 1);
1408
1465
 
1409
1466
  // src/utils/commandMaps.ts
1410
1467
  var formatCommands = {
@@ -1430,9 +1487,9 @@ var formatProject = ({
1430
1487
  const fmt = formatCommands[packageManager] ?? "bun run format";
1431
1488
  spin.start("Formatting files…");
1432
1489
  execSync(fmt, { cwd: projectName, stdio: "pipe" });
1433
- spin.stop(import_picocolors13.green("Files formatted"));
1490
+ spin.stop(import_picocolors12.green("Files formatted"));
1434
1491
  } catch (err) {
1435
- spin.stop(import_picocolors13.red("Failed to format files"), 1);
1492
+ spin.stop(import_picocolors12.red("Failed to format files"), 1);
1436
1493
  console.error("Error formatting:", err);
1437
1494
  exit2(1);
1438
1495
  }
@@ -1441,7 +1498,7 @@ var formatProject = ({
1441
1498
  // src/commands/installDependencies.ts
1442
1499
  import { execSync as execSync2 } from "child_process";
1443
1500
  import { exit as exit3 } from "process";
1444
- var import_picocolors14 = __toESM(require_picocolors(), 1);
1501
+ var import_picocolors13 = __toESM(require_picocolors(), 1);
1445
1502
  var installDependencies = async ({
1446
1503
  projectName,
1447
1504
  packageManager
@@ -1451,23 +1508,42 @@ var installDependencies = async ({
1451
1508
  try {
1452
1509
  spin.start("Installing dependencies…");
1453
1510
  execSync2(cmd, { cwd: projectName, stdio: "pipe" });
1454
- spin.stop(import_picocolors14.green("Dependencies installed"));
1511
+ spin.stop(import_picocolors13.green("Dependencies installed"));
1455
1512
  } catch (err) {
1456
- spin.stop(import_picocolors14.red("Installation failed"), 1);
1513
+ spin.stop(import_picocolors13.red("Installation failed"), 1);
1457
1514
  console.error("Error installing dependencies:", err);
1458
1515
  exit3(1);
1459
1516
  }
1460
1517
  };
1461
1518
 
1462
1519
  // src/generators/configurations/addConfigurationFiles.ts
1463
- var import_picocolors15 = __toESM(require_picocolors(), 1);
1464
- import { copyFileSync } from "fs";
1520
+ var import_picocolors14 = __toESM(require_picocolors(), 1);
1521
+ import { copyFileSync, writeFileSync } from "fs";
1465
1522
  import { join } from "path";
1523
+
1524
+ // src/generators/configurations/generatePrettierrc.ts
1525
+ var generatePrettierrc = (frontends) => {
1526
+ const usesSvelte = frontends.some((frontend) => frontend === "svelte");
1527
+ return `{
1528
+ "endOfLine": "auto",
1529
+ "printWidth": 80,
1530
+ "semi": true,
1531
+ "singleQuote": true,
1532
+ "tabWidth": 4,
1533
+ "trailingComma": "none",
1534
+ "useTabs": true
1535
+ ${usesSvelte ? `,"plugins": ["prettier-plugin-svelte"],
1536
+ "overrides": [{"files": "*.svelte", "options": {"parser": "svelte"}}]` : ""}
1537
+ }`;
1538
+ };
1539
+
1540
+ // src/generators/configurations/addConfigurationFiles.ts
1466
1541
  var addConfigurationFiles = ({
1467
1542
  tailwind,
1468
1543
  templatesDirectory,
1469
1544
  language,
1470
1545
  codeQualityTool,
1546
+ frontends,
1471
1547
  initializeGitNow,
1472
1548
  projectName
1473
1549
  }) => {
@@ -1482,16 +1558,17 @@ var addConfigurationFiles = ({
1482
1558
  if (codeQualityTool === "eslint+prettier") {
1483
1559
  copyFileSync(join(templatesDirectory, "configurations", "eslint.config.mjs"), join(projectName, "eslint.config.mjs"));
1484
1560
  copyFileSync(join(templatesDirectory, "configurations", ".prettierignore"), join(projectName, ".prettierignore"));
1485
- copyFileSync(join(templatesDirectory, "configurations", ".prettierrc.json"), join(projectName, ".prettierrc.json"));
1561
+ const prettierrc = generatePrettierrc(frontends);
1562
+ writeFileSync(join(projectName, ".prettierrc.json"), prettierrc);
1486
1563
  } else
1487
- console.warn(`${import_picocolors15.dim("│")}
1488
- ${import_picocolors15.yellow("▲")} Biome support not implemented yet`);
1564
+ console.warn(`${import_picocolors14.dim("│")}
1565
+ ${import_picocolors14.yellow("▲")} Biome support not implemented yet`);
1489
1566
  };
1490
1567
 
1491
- // src/generators/configurations/createPackageJson.ts
1492
- import { writeFileSync } from "fs";
1568
+ // src/generators/configurations/generatePackageJson.ts
1569
+ import { writeFileSync as writeFileSync2 } from "fs";
1493
1570
  import { join as join2 } from "path";
1494
- var import_picocolors16 = __toESM(require_picocolors(), 1);
1571
+ var import_picocolors15 = __toESM(require_picocolors(), 1);
1495
1572
 
1496
1573
  // src/utils/getPackageVersion.ts
1497
1574
  import { execSync as execSync3 } from "child_process";
@@ -1506,14 +1583,14 @@ var getPackageVersion = (packageName) => {
1506
1583
  }
1507
1584
  };
1508
1585
 
1509
- // src/generators/configurations/createPackageJson.ts
1586
+ // src/generators/configurations/generatePackageJson.ts
1510
1587
  var createPackageJson = ({
1511
1588
  projectName,
1512
1589
  authProvider,
1513
1590
  plugins,
1514
1591
  useTailwind,
1515
1592
  latest,
1516
- frontendConfigurations,
1593
+ frontendDirectories,
1517
1594
  codeQualityTool
1518
1595
  }) => {
1519
1596
  const s = Y2();
@@ -1521,6 +1598,8 @@ var createPackageJson = ({
1521
1598
  const resolveVersion = (name, listed) => latest ? getPackageVersion(name) ?? listed : listed;
1522
1599
  const dependencies = {};
1523
1600
  const devDependencies = {};
1601
+ const usesReact = frontendDirectories["react"] !== undefined;
1602
+ const usesSvelte = frontendDirectories["svelte"] !== undefined;
1524
1603
  for (const p2 of defaultPlugins) {
1525
1604
  dependencies[p2.value] = resolveVersion(p2.value, p2.latestVersion);
1526
1605
  }
@@ -1544,16 +1623,20 @@ var createPackageJson = ({
1544
1623
  devDependencies["tailwindcss"] = resolveVersion("tailwindcss", "4.1.7");
1545
1624
  devDependencies["@tailwindcss/cli"] = resolveVersion("@tailwindcss/cli", "4.1.7");
1546
1625
  }
1547
- if (frontendConfigurations.some((f) => f.name === "react")) {
1626
+ if (usesReact) {
1548
1627
  dependencies["react"] = resolveVersion("react", "19.1.0");
1549
1628
  dependencies["react-dom"] = resolveVersion("react-dom", "19.1.0");
1550
1629
  devDependencies["@types/react"] = resolveVersion("@types/react", "19.1.5");
1551
1630
  devDependencies["@types/react-dom"] = resolveVersion("@types/react-dom", "19.1.5");
1552
1631
  }
1553
- latest && s.stop(import_picocolors16.green("Package versions resolved"));
1632
+ if (usesSvelte) {
1633
+ dependencies["svelte"] = resolveVersion("svelte", "5.34.7");
1634
+ codeQualityTool === "eslint+prettier" && (devDependencies["prettier-plugin-svelte"] = resolveVersion("prettier-plugin-svelte", "3.4.0"));
1635
+ }
1636
+ latest && s.stop(import_picocolors15.green("Package versions resolved"));
1554
1637
  const scripts = {
1555
1638
  dev: "bun run src/backend/server.ts",
1556
- format: 'prettier --write "./**/*.{js,jsx,ts,tsx,css,json,mjs,md}"',
1639
+ format: `prettier --write "./**/*.{js,ts,css,json,mjs,md${usesReact ? ",jsx,tsx" : ""}${usesSvelte ? ",svelte" : ""}}"`,
1557
1640
  lint: "eslint ./src",
1558
1641
  test: 'echo "Error: no test specified" && exit 1',
1559
1642
  typecheck: "bun run tsc --noEmit"
@@ -1566,7 +1649,7 @@ var createPackageJson = ({
1566
1649
  type: "module",
1567
1650
  version: "0.1.0"
1568
1651
  };
1569
- writeFileSync(join2(projectName, "package.json"), JSON.stringify(packageJson));
1652
+ writeFileSync2(join2(projectName, "package.json"), JSON.stringify(packageJson));
1570
1653
  };
1571
1654
 
1572
1655
  // src/generators/configurations/initializeRoot.ts
@@ -1592,12 +1675,12 @@ var initalizeRoot = (projectName, templatesDirectory) => {
1592
1675
  };
1593
1676
 
1594
1677
  // src/generators/db/scaffoldDatabase.ts
1595
- var import_picocolors17 = __toESM(require_picocolors(), 1);
1678
+ var import_picocolors16 = __toESM(require_picocolors(), 1);
1596
1679
  import { mkdirSync as mkdirSync2 } from "fs";
1597
1680
  import { join as join5 } from "path";
1598
1681
 
1599
- // src/generators/configurations/createDrizzleConfig.ts
1600
- import { writeFileSync as writeFileSync2 } from "fs";
1682
+ // src/generators/configurations/generateDrizzleConfig.ts
1683
+ import { writeFileSync as writeFileSync3 } from "fs";
1601
1684
  import { join as join4 } from "path";
1602
1685
  var createDrizzleConfig = ({
1603
1686
  projectName,
@@ -1609,7 +1692,7 @@ var createDrizzleConfig = ({
1609
1692
  dialect: '${databaseEngine}'
1610
1693
  });
1611
1694
  `;
1612
- writeFileSync2(join4(projectName, "drizzle.config.ts"), drizzleConfig);
1695
+ writeFileSync3(join4(projectName, "drizzle.config.ts"), drizzleConfig);
1613
1696
  };
1614
1697
 
1615
1698
  // src/generators/db/scaffoldDatabase.ts
@@ -1620,20 +1703,31 @@ var scaffoldDatabase = ({
1620
1703
  orm
1621
1704
  }) => {
1622
1705
  mkdirSync2(join5(projectName, databaseDirectory), { recursive: true });
1623
- if (databaseEngine !== "postgresql") {
1624
- console.warn(`${import_picocolors17.dim("│")}
1625
- ${import_picocolors17.yellow("▲")} Only PostgreSQL support is implemented so far`);
1706
+ if (databaseEngine !== "postgresql" && databaseEngine !== "none") {
1707
+ console.warn(`${import_picocolors16.dim("│")}
1708
+ ${import_picocolors16.yellow("▲")} Only PostgreSQL support is implemented so far`);
1626
1709
  }
1627
1710
  if (orm === "drizzle") {
1628
1711
  createDrizzleConfig({ databaseEngine, projectName });
1629
1712
  }
1713
+ if (orm === "prisma") {
1714
+ console.warn(`${import_picocolors16.dim("│")}
1715
+ ${import_picocolors16.yellow("▲")} Prisma support is not implemented yet`);
1716
+ }
1630
1717
  };
1631
1718
 
1632
- // src/generators/project/createServer.ts
1633
- import { writeFileSync as writeFileSync3 } from "fs";
1719
+ // src/generators/project/generateServer.ts
1720
+ import { writeFileSync as writeFileSync4 } from "fs";
1721
+
1722
+ // src/constants.ts
1723
+ var UNFOUND_INDEX = -1;
1724
+ var DEFAULT_ARG_LENGTH = 2;
1725
+ var TWO_THIRDS = 2 / 3;
1726
+
1727
+ // src/generators/project/generateServer.ts
1634
1728
  var createServerFile = ({
1635
1729
  tailwind,
1636
- frontendConfigurations,
1730
+ frontendDirectories,
1637
1731
  serverFilePath,
1638
1732
  authProvider,
1639
1733
  availablePlugins: availablePlugins2,
@@ -1641,200 +1735,208 @@ var createServerFile = ({
1641
1735
  assetsDirectory,
1642
1736
  plugins
1643
1737
  }) => {
1644
- const requiresHtml = frontendConfigurations.some((configuration) => configuration.name === "html");
1645
- const requiresReact = frontendConfigurations.some((configuration) => configuration.name === "react");
1646
- const isSingleFrontend = frontendConfigurations.length === 1;
1647
- const selectedCustomPlugins = availablePlugins2.filter((plugin) => plugins.indexOf(plugin.value) !== UNFOUND_INDEX);
1648
- const authenticationPlugins = [];
1649
- if (authProvider === "absoluteAuth") {
1650
- authenticationPlugins.push(absoluteAuthPlugin);
1651
- }
1652
- const combinedDependencies = [
1738
+ const htmlDirectory = frontendDirectories["html"];
1739
+ const reactDirectory = frontendDirectories["react"];
1740
+ const svelteDirectory = frontendDirectories["svelte"];
1741
+ const requiresHtml = htmlDirectory !== undefined;
1742
+ const requiresReact = reactDirectory !== undefined;
1743
+ const requiresSvelte = svelteDirectory !== undefined;
1744
+ const selectedCustomPlugins = availablePlugins2.filter(({ value }) => plugins.indexOf(value) !== UNFOUND_INDEX);
1745
+ const authenticationPlugins = authProvider === "absoluteAuth" ? [absoluteAuthPlugin] : [];
1746
+ const allDependencies = [
1653
1747
  ...defaultDependencies,
1654
1748
  ...defaultPlugins,
1655
1749
  ...selectedCustomPlugins,
1656
1750
  ...authenticationPlugins
1657
1751
  ];
1658
- const uniqueDependencies = [];
1659
- combinedDependencies.forEach((dependency) => {
1660
- if (!uniqueDependencies.some((existingDependency) => existingDependency.value === dependency.value)) {
1661
- uniqueDependencies.push(dependency);
1662
- }
1663
- });
1664
- uniqueDependencies.sort((firstDependency, secondDependency) => firstDependency.value.localeCompare(secondDependency.value));
1665
- const importLines = uniqueDependencies.flatMap((dependency) => {
1666
- const importsArray = dependency.imports ?? [];
1667
- return importsArray.length > 0 ? [
1668
- `import { ${importsArray.map((importEntry) => importEntry.packageName).join(", ")} } from '${dependency.value}';`
1669
- ] : [];
1670
- });
1671
- const absoluteImportLineIndex = importLines.findIndex((importLine) => importLine.includes("from '@absolutejs/absolute'"));
1672
- if (absoluteImportLineIndex >= 0) {
1673
- const originalImportLine = importLines[absoluteImportLineIndex];
1674
- importLines[absoluteImportLineIndex] = originalImportLine.replace(/import\s*\{([\s\S]*?)\}\s*from '@absolutejs\/absolute';/, (_fullMatch, importList) => {
1675
- const importedItems = importList.split(",").map((item) => item.trim()).filter(Boolean);
1676
- if (requiresHtml && !importedItems.includes("handleHTMLPageRequest")) {
1677
- importedItems.push("handleHTMLPageRequest");
1678
- }
1679
- if (requiresReact && !importedItems.includes("handleReactPageRequest")) {
1680
- importedItems.push("handleReactPageRequest");
1681
- }
1682
- return `import { ${importedItems.join(", ")} } from '@absolutejs/absolute';`;
1683
- });
1684
- }
1685
- if (requiresReact) {
1686
- const reactImportSource = isSingleFrontend ? "../frontend/pages/ReactExample" : "../frontend/react/pages/ReactExample";
1752
+ const uniqueDependencies = Array.from(new Map(allDependencies.map((dependency) => [dependency.value, dependency])).values()).sort((a, b3) => a.value.localeCompare(b3.value));
1753
+ const importLines = uniqueDependencies.flatMap(({ value, imports }) => imports && imports.length > 0 ? [
1754
+ `import { ${imports.map(({ packageName }) => packageName).join(", ")} } from '${value}';`
1755
+ ] : []);
1756
+ const absoluteImportIdx = importLines.findIndex((line) => line.includes("from '@absolutejs/absolute'"));
1757
+ if (absoluteImportIdx !== UNFOUND_INDEX && importLines[absoluteImportIdx]) {
1758
+ const existingItems = importLines[absoluteImportIdx].replace(/import\s*\{\s*|\}\s*from.*$/g, "").split(",").map((item) => item.trim()).filter((value) => value.length > 0);
1759
+ const additionalItems = [
1760
+ requiresHtml && !existingItems.includes("handleHTMLPageRequest") && "handleHTMLPageRequest",
1761
+ requiresReact && !existingItems.includes("handleReactPageRequest") && "handleReactPageRequest",
1762
+ requiresSvelte && !existingItems.includes("handleSveltePageRequest") && "handleSveltePageRequest"
1763
+ ].filter((value) => typeof value === "string");
1764
+ importLines[absoluteImportIdx] = `import { ${[...existingItems, ...additionalItems].join(", ")} } from '@absolutejs/absolute';`;
1765
+ }
1766
+ if (reactDirectory !== undefined) {
1767
+ const reactImportSource = reactDirectory === "" ? "../frontend/pages/ReactExample" : `../frontend/${reactDirectory}/pages/ReactExample`;
1687
1768
  importLines.push(`import { ReactExample } from '${reactImportSource}';`);
1688
1769
  }
1689
- const useStatements = uniqueDependencies.flatMap((dependency) => dependency.imports).filter((importEntry) => importEntry?.isPlugin).map((importEntry) => {
1690
- if (importEntry?.config === undefined) {
1691
- return `.use(${importEntry?.packageName})`;
1692
- }
1693
- if (importEntry.config === null) {
1694
- return `.use(${importEntry.packageName}())`;
1695
- }
1696
- return `.use(${importEntry.packageName}(${JSON.stringify(importEntry.config)}))`;
1770
+ if (requiresSvelte) {
1771
+ const svelteImportSource = svelteDirectory === "" ? "../frontend/pages/SvelteExample" : `../frontend/${svelteDirectory}/pages/SvelteExample`;
1772
+ importLines.push(`import SvelteExample from '${svelteImportSource}.svelte';`);
1773
+ }
1774
+ const useStatements = uniqueDependencies.flatMap(({ imports }) => imports ?? []).filter((entry) => entry.isPlugin).map((entry) => {
1775
+ if (entry.config === undefined)
1776
+ return `.use(${entry.packageName})`;
1777
+ if (entry.config === null)
1778
+ return `.use(${entry.packageName}())`;
1779
+ return `.use(${entry.packageName}(${JSON.stringify(entry.config)}))`;
1697
1780
  });
1698
1781
  const manifestOptions = [
1699
- `buildDirectory: '${buildDirectory}'`,
1700
1782
  `assetsDirectory: '${assetsDirectory}'`,
1701
- ...frontendConfigurations.map((configuration) => configuration.directory ? `${configuration.name}Directory: './src/frontend/${configuration.directory}'` : `${configuration.name}Directory: './src/frontend/'`).filter((option) => option !== ""),
1783
+ `buildDirectory: '${buildDirectory}'`,
1784
+ ...Object.entries(frontendDirectories).map(([frameworkName, directory]) => `${frameworkName}Directory: './src/frontend/${directory}'`),
1702
1785
  tailwind ? `tailwind: ${JSON.stringify(tailwind)}` : ""
1703
- ];
1704
- const buildStatement = `const manifest = await build({
1786
+ ].filter(Boolean);
1787
+ const manifestDeclaration = `const manifest = await build({
1705
1788
  ${manifestOptions.join(`,
1706
1789
  `)}
1707
1790
  });`;
1708
- let guardStatements = `if (manifest === null) throw new Error('Manifest was not generated');`;
1709
- if (requiresReact) {
1710
- guardStatements += `
1711
- const { ReactExampleIndex } = manifest;
1712
- if (ReactExampleIndex === undefined) throw new Error('ReactExampleIndex was not generated');`;
1713
- }
1714
- let routeDefinitions = "";
1715
- frontendConfigurations.forEach((configuration, index) => {
1716
- const routePath = index === 0 ? "/" : `/${configuration.name}`;
1717
- if (configuration.name === "html") {
1718
- routeDefinitions += `
1719
- .get('${routePath}', () =>
1720
- handleHTMLPageRequest(\`${buildDirectory}/html/pages/HtmlExample.html\`)
1721
- )`;
1722
- } else if (configuration.name === "react") {
1723
- routeDefinitions += `
1724
- .get('${routePath}', () =>
1725
- handleReactPageRequest(ReactExample, ReactExampleIndex)
1726
- )`;
1791
+ const guardStatements = [
1792
+ `if (manifest === null) throw new Error('Manifest was not generated');`,
1793
+ requiresReact ? `const { ReactExampleIndex } = manifest;
1794
+ if (ReactExampleIndex === undefined) throw new Error('ReactExampleIndex was not generated');` : ""
1795
+ ].filter(Boolean).join(`
1796
+ `);
1797
+ const routes = Object.entries(frontendDirectories).map(([frameworkName, directory], index) => {
1798
+ const routePath = index === 0 ? "/" : `/${frameworkName}`;
1799
+ if (frameworkName === "html") {
1800
+ return `.get('${routePath}', () => handleHTMLPageRequest(\`${buildDirectory}/${directory}/pages/HTMLExample.html\`))`;
1727
1801
  }
1728
- });
1729
- let serverFileContent = `${importLines.join(`
1802
+ if (frameworkName === "react") {
1803
+ return `.get('${routePath}', () => handleReactPageRequest(ReactExample, ReactExampleIndex))`;
1804
+ }
1805
+ if (frameworkName === "svelte") {
1806
+ return `.get('${routePath}', () => handleSveltePageRequest(SvelteExample, manifest))`;
1807
+ }
1808
+ return "";
1809
+ }).filter(Boolean).join(`
1810
+ `);
1811
+ const serverFileContent = `${importLines.join(`
1730
1812
  `)}
1731
1813
 
1732
- ${buildStatement}
1814
+ ${manifestDeclaration}
1733
1815
 
1734
1816
  ${guardStatements}
1735
1817
 
1736
- new Elysia()${routeDefinitions}`;
1737
- useStatements.forEach((statement) => {
1738
- serverFileContent += `
1739
- ${statement}`;
1740
- });
1741
- serverFileContent += `
1742
- .on('error', (error) => {
1743
- const { request } = error;
1744
- console.error(\`Server error on \${request.method} \${request.url}: \${error.message}\`);
1818
+ new Elysia()${routes}
1819
+ ${useStatements.map((s) => ` ${s}`).join(`
1820
+ `)}
1821
+ .on('error', (err) => {
1822
+ const { request } = err;
1823
+ console.error(\`Server error on \${request.method} \${request.url}: \${err.message}\`);
1745
1824
  });
1746
1825
  `;
1747
- writeFileSync3(serverFilePath, serverFileContent);
1826
+ writeFileSync4(serverFilePath, serverFileContent);
1748
1827
  };
1749
1828
 
1750
1829
  // src/generators/project/scaffoldFrontends.ts
1751
- import { copyFileSync as copyFileSync3, mkdirSync as mkdirSync5 } from "node:fs";
1752
- import { join as join8 } from "node:path";
1830
+ import { copyFileSync as copyFileSync3, mkdirSync as mkdirSync6 } from "node:fs";
1831
+ import { join as join9 } from "node:path";
1753
1832
 
1754
1833
  // src/generators/html/scaffoldHTML.ts
1755
- import { cpSync as cpSync2, mkdirSync as mkdirSync3, writeFileSync as writeFileSync4 } from "fs";
1834
+ import { mkdirSync as mkdirSync3, writeFileSync as writeFileSync5 } from "fs";
1756
1835
  import { join as join6 } from "path";
1757
1836
 
1758
- // src/generators/html/getSSRScript.ts
1759
- var getSSRScript = (language, isSingle) => `import { HOURS_IN_DAY, TWO_THIRDS } from '${!isSingle ? "../" : ""}../../constants';
1760
-
1761
- document.addEventListener('DOMContentLoaded', () => {
1762
- const greeting = document.getElementById('greeting');
1763
- const date = new Date();
1764
- const hours = date.getHours();
1765
-
1766
- if (greeting === null) {
1767
- throw new Error('Greeting element not found');
1768
- }
1769
-
1770
- if (hours < HOURS_IN_DAY / 2) {
1771
- greeting.textContent = 'Good Morning, welcome to AbsoluteJS !';
1772
- } else if (hours < HOURS_IN_DAY * TWO_THIRDS) {
1773
- greeting.textContent = 'Good Afternoon, welcome to AbsoluteJS !';
1774
- } else {
1775
- greeting.textContent = 'Good Evening, welcome to AbsoluteJS !';
1776
- }
1777
-
1778
- const button = document.getElementById('counter-button');
1779
- const counter = document.getElementById('counter');
1780
- let count = 0;
1781
-
1782
- if (button === null || counter === null) {
1783
- throw new Error('Button or counter element not found');
1784
- }
1837
+ // src/generators/html/generateHTMLPage.ts
1838
+ var generateHTMLPage = (htmlScriptOption) => {
1839
+ let scriptTag = "";
1840
+ if (htmlScriptOption === "js") {
1841
+ scriptTag = `<script src="/html/scripts/javascriptExample.js"></script>`;
1842
+ } else if (htmlScriptOption === "ts") {
1843
+ scriptTag = `<script src="/html/scripts/typescriptExample.ts"></script>`;
1844
+ }
1845
+ return `<!DOCTYPE html>
1846
+ <html>
1847
+ <head>
1848
+ <title>Html Home</title>
1849
+ <link rel="stylesheet" type="text/css" href="/assets/css/HtmlHome.css">
1850
+ <link rel="icon" href="/assets/ico/favicon.ico" />
1851
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
1852
+ </head>
1853
+ <body>
1854
+ <header>
1855
+ <img id="logo" src="/assets/svg/brand_logo.svg" alt="AbsoluteJS Logo">
1856
+ <h1 id="greeting"></h1>
1857
+ </header>
1858
+ <main>
1859
+ <p>Welcome to AbsoluteJS, the next generation JavaScript framework. We're glad you're here.</p>
1860
+ <button id="counter-button">Click me!</button>
1861
+ <p id="counter">0</p>
1862
+ <nav id="links">
1863
+ <a href="/react" id="react-link">React</a>
1864
+ <a href="/vue" id="vue-link">Vue</a>
1865
+ <a href="/angular" id="angular-link">Angular</a>
1866
+ <a href="/svelte" id="svelte-link">Svelte</a>
1867
+ <a href="/ember" id="ember-link">Ember</a>
1868
+ <a href="/htmx" id="htmx-link">HTMX</a>
1869
+ </nav>
1870
+ </main>
1871
+ <footer>
1872
+ <p id="footer-text"></p>
1873
+ </footer>${scriptTag ? `
1874
+ ${scriptTag}` : ""}
1875
+ </body>
1876
+ </html>`;
1877
+ };
1785
1878
 
1786
- button.addEventListener('click', () => {
1787
- count++;
1788
- counter.textContent = count.toString();
1789
- });
1879
+ // src/generators/html/generateHTMLScript.ts
1880
+ var getHTMLScript = (htmlScriptOption, isSingleFrontend) => `import { HOURS_IN_DAY, TWO_THIRDS } from '${!isSingleFrontend ? "../" : ""}../../constants';
1790
1881
 
1791
- const links = document.querySelectorAll${language === "ts" && "<HTMLAnchorElement>"}('#links a');
1792
- links.forEach((link) => {
1793
- link.addEventListener('mouseover', () => {
1794
- link.style.transform = 'scale(1.2)';
1795
- });
1796
- link.addEventListener('mouseout', () => {
1797
- link.style.transform = 'scale(1)';
1798
- });
1799
- });
1882
+ const greeting = document.getElementById('greeting');
1883
+ const date = new Date();
1884
+ const hours = date.getHours();
1885
+ if (!greeting) throw new Error('Greeting element not found');
1800
1886
 
1801
- const footerText = document.getElementById('footer-text');
1887
+ if (hours < HOURS_IN_DAY / 2) {
1888
+ greeting.textContent = 'Good Morning, welcome to AbsoluteJS !';
1889
+ } else if (hours < HOURS_IN_DAY * TWO_THIRDS) {
1890
+ greeting.textContent = 'Good Afternoon, welcome to AbsoluteJS !';
1891
+ } else {
1892
+ greeting.textContent = 'Good Evening, welcome to AbsoluteJS !';
1893
+ }
1802
1894
 
1803
- if (footerText === null) {
1804
- throw new Error('Footer text element not found');
1805
- }
1895
+ const button = document.getElementById('counter-button');
1896
+ const counter = document.getElementById('counter');
1897
+ if (!button || !counter) throw new Error('Button or counter element not found');
1898
+ let count = 0;
1899
+ button.addEventListener('click', () => {
1900
+ count++;
1901
+ counter.textContent = count.toString();
1902
+ });
1806
1903
 
1807
- footerText.textContent = \`© ${new Date().getFullYear()} AbsoluteJS\`;
1904
+ const links = document.querySelectorAll${htmlScriptOption === "ts" ? "<HTMLAnchorElement>" : ""}('#links a');
1905
+ links.forEach((link) => {
1906
+ link.addEventListener('mouseover', () => link.style.transform = 'scale(1.2)');
1907
+ link.addEventListener('mouseout', () => link.style.transform = 'scale(1)');
1808
1908
  });
1909
+
1910
+ const footerText = document.getElementById('footer-text');
1911
+ if (!footerText) throw new Error('Footer text element not found');
1912
+ footerText.textContent = \`© ${new Date().getFullYear()} AbsoluteJS\`;
1809
1913
  `;
1810
1914
 
1811
1915
  // src/generators/html/scaffoldHTML.ts
1812
1916
  var scaffoldHTML = ({
1813
- templatesDirectory,
1814
- isSingle,
1917
+ isSingleFrontend,
1815
1918
  targetDirectory,
1816
- htmlScriptOption,
1817
- language
1919
+ htmlScriptOption
1818
1920
  }) => {
1819
- const htmlTemplates = join6(templatesDirectory, "html");
1820
- cpSync2(join6(htmlTemplates, "pages"), join6(targetDirectory, "pages"), {
1821
- recursive: true
1822
- });
1823
- const scriptsDir = join6(targetDirectory, "scripts");
1824
- mkdirSync3(scriptsDir);
1825
- if (htmlScriptOption?.includes("ssr")) {
1826
- const ssrScript = getSSRScript(language, isSingle);
1827
- const ssrFileName = language === "ts" ? "typescriptSSRExample.ts" : "javascriptSSRExample.js";
1828
- writeFileSync4(join6(scriptsDir, ssrFileName), ssrScript);
1921
+ const htmlPage = generateHTMLPage(htmlScriptOption);
1922
+ const htmlPagesDirectory = join6(targetDirectory, "pages");
1923
+ mkdirSync3(htmlPagesDirectory, { recursive: true });
1924
+ writeFileSync5(join6(htmlPagesDirectory, "HTMLExample.html"), htmlPage);
1925
+ if (htmlScriptOption !== undefined && htmlScriptOption !== "none") {
1926
+ const scriptsDir = join6(targetDirectory, "scripts");
1927
+ mkdirSync3(scriptsDir, { recursive: true });
1928
+ const script = getHTMLScript(htmlScriptOption, isSingleFrontend);
1929
+ const scriptFileName = htmlScriptOption === "ts" ? "typescriptExample.ts" : "javascriptExample.js";
1930
+ writeFileSync5(join6(scriptsDir, scriptFileName), script);
1829
1931
  }
1830
1932
  };
1831
1933
 
1832
1934
  // src/generators/react/scaffoldReact.ts
1833
- import { cpSync as cpSync3, mkdirSync as mkdirSync4, writeFileSync as writeFileSync5 } from "node:fs";
1935
+ import { cpSync as cpSync2, mkdirSync as mkdirSync4, writeFileSync as writeFileSync6 } from "node:fs";
1834
1936
  import { join as join7 } from "node:path";
1835
1937
 
1836
1938
  // src/generators/react/generateHeadComponent.ts
1837
- var generateHeadComponent = (isSingle) => `import { styleReset } from '${isSingle ? "../../styles" : "../../../styles/react"}/defaultStyles';
1939
+ var generateHeadComponent = (isSingleFrontend) => `import { styleReset } from '${isSingleFrontend ? "../../styles" : "../../../styles/react"}/defaultStyles';
1838
1940
 
1839
1941
  type HeadProps = {
1840
1942
  title?: string;
@@ -1869,13 +1971,13 @@ export const Head = ({
1869
1971
  `;
1870
1972
 
1871
1973
  // src/generators/react/generateReactPage.ts
1872
- var generateReactPage = (isSingle) => `import { useState } from 'react';
1974
+ var generateReactPage = (isSingleFrontend) => `import { useState } from 'react';
1873
1975
  import { Head } from '../components/utils/Head';
1874
1976
  import {
1875
1977
  bodyDefault,
1876
1978
  htmlDefault,
1877
1979
  mainDefault
1878
- } from '${isSingle ? "../styles" : "../../styles/react"}/defaultStyles';
1980
+ } from '${isSingleFrontend ? "../styles" : "../../styles/react"}/defaultStyles';
1879
1981
 
1880
1982
  export const ReactExample = () => {
1881
1983
  const [count, setCount] = useState(0);
@@ -1956,7 +2058,7 @@ export const ReactExample = () => {
1956
2058
  fontFamily: 'monospace'
1957
2059
  }}
1958
2060
  >
1959
- src/frontend/${isSingle ? "" : "react"}/pages/ReactExample.tsx
2061
+ src/frontend/${isSingleFrontend ? "" : "react"}/pages/ReactExample.tsx
1960
2062
  </code>{' '}
1961
2063
  to edit this page
1962
2064
  </p>
@@ -1972,77 +2074,136 @@ export const ReactExample = () => {
1972
2074
  var scaffoldReact = ({
1973
2075
  stylesDirectory,
1974
2076
  templatesDirectory,
1975
- isSingle,
2077
+ isSingleFrontend,
1976
2078
  targetDirectory
1977
2079
  }) => {
1978
2080
  const reactStylesSrc = join7(templatesDirectory, "react", "styles");
1979
2081
  const reactTemplates = join7(templatesDirectory, "react");
1980
2082
  const pagesDirectory = join7(targetDirectory, "pages");
1981
2083
  const componentsDirectory = join7(targetDirectory, "components");
1982
- const pageExample = generateReactPage(isSingle);
1983
- const headComponent = generateHeadComponent(isSingle);
1984
- mkdirSync4(pagesDirectory);
1985
- writeFileSync5(join7(pagesDirectory, "ReactExample.tsx"), pageExample);
2084
+ const pageExample = generateReactPage(isSingleFrontend);
2085
+ const headComponent = generateHeadComponent(isSingleFrontend);
2086
+ mkdirSync4(pagesDirectory, { recursive: true });
2087
+ writeFileSync6(join7(pagesDirectory, "ReactExample.tsx"), pageExample);
1986
2088
  mkdirSync4(join7(componentsDirectory, "utils"), { recursive: true });
1987
- writeFileSync5(join7(componentsDirectory, "utils", "Head.tsx"), headComponent);
1988
- cpSync3(join7(reactTemplates, "hooks"), join7(targetDirectory, "hooks"), {
2089
+ writeFileSync6(join7(componentsDirectory, "utils", "Head.tsx"), headComponent);
2090
+ cpSync2(join7(reactTemplates, "hooks"), join7(targetDirectory, "hooks"), {
1989
2091
  recursive: true
1990
2092
  });
1991
- if (isSingle) {
1992
- cpSync3(reactStylesSrc, stylesDirectory, {
2093
+ if (isSingleFrontend) {
2094
+ cpSync2(reactStylesSrc, stylesDirectory, {
1993
2095
  recursive: true
1994
2096
  });
1995
2097
  } else {
1996
2098
  const dest = join7(stylesDirectory, "react");
1997
- mkdirSync4(dest);
1998
- cpSync3(reactStylesSrc, dest, {
2099
+ mkdirSync4(dest, { recursive: true });
2100
+ cpSync2(reactStylesSrc, dest, {
1999
2101
  recursive: true
2000
2102
  });
2001
2103
  }
2002
2104
  };
2003
2105
 
2106
+ // src/generators/svelte/scaffoldSvelte.ts
2107
+ import { mkdirSync as mkdirSync5, writeFileSync as writeFileSync7 } from "node:fs";
2108
+ import { join as join8 } from "node:path";
2109
+
2110
+ // src/generators/svelte/generateSveltePage.ts
2111
+ var generateSveltePage = (language) => {
2112
+ const scriptTag = language === "ts" ? `<script lang="ts">` : `<script>`;
2113
+ return `${scriptTag}
2114
+ let count = $state(0);
2115
+
2116
+ const year = new Date().getFullYear();
2117
+ </script>
2118
+
2119
+ <svelte:head>
2120
+ <meta charset="utf-8" />
2121
+ <title>Svelte Home</title>
2122
+ <meta name="description" content="Welcome to AbsoluteJS" />
2123
+ <meta name="viewport" content="width=device-width, initial-scale=1" />
2124
+ <link rel="icon" href="/assets/ico/favicon.ico" />
2125
+ </svelte:head>
2126
+
2127
+ <main>
2128
+ <header><h1>This page was built with Svelte</h1></header>
2129
+
2130
+ <p>Welcome to the Svelte home page. This page was built using Svelte.</p>
2131
+
2132
+ <p>Counter: {count}</p>
2133
+ <button onclick={() => (count += 1)}>Increment</button>
2134
+
2135
+ <div id="links">
2136
+ <a href="/">Html</a>
2137
+ <a href="/vue">Vue</a>
2138
+ </div>
2139
+
2140
+ <footer><p>© {year} AbsoluteJS</p></footer>
2141
+ </main>
2142
+ `;
2143
+ };
2144
+
2145
+ // src/generators/svelte/scaffoldSvelte.ts
2146
+ var scaffoldSvelte = ({
2147
+ targetDirectory,
2148
+ language
2149
+ }) => {
2150
+ const pageExample = generateSveltePage(language);
2151
+ const pagesDirectory = join8(targetDirectory, "pages");
2152
+ const componentsDirectory = join8(targetDirectory, "components");
2153
+ mkdirSync5(pagesDirectory, { recursive: true });
2154
+ writeFileSync7(join8(pagesDirectory, "SvelteExample.svelte"), pageExample);
2155
+ mkdirSync5(join8(componentsDirectory), { recursive: true });
2156
+ };
2157
+
2004
2158
  // src/generators/project/scaffoldFrontends.ts
2005
2159
  var scaffoldFrontends = ({
2006
2160
  frontendDirectory,
2007
- language,
2008
2161
  templatesDirectory,
2009
- frontendConfigurations,
2162
+ frontendDirectories,
2163
+ language,
2010
2164
  tailwind,
2011
2165
  htmlScriptOption
2012
2166
  }) => {
2013
- const isSingle = frontendConfigurations.length === 1;
2014
- const stylesDirectory = join8(frontendDirectory, "styles");
2015
- mkdirSync5(stylesDirectory);
2016
- if (tailwind !== undefined) {
2017
- copyFileSync3(join8(templatesDirectory, "tailwind", "tailwind.css"), join8(stylesDirectory, "tailwind.css"));
2018
- }
2019
- const dirMap = new Map;
2020
- frontendConfigurations.forEach(({ name, directory }) => {
2021
- const dir = directory?.trim() ?? (isSingle ? "" : name);
2022
- if (dirMap.has(dir)) {
2023
- throw new Error(`Frontend directory collision: "${dir}" is assigned to both "${dirMap.get(dir)}" and "${name}". Please pick unique directories.`);
2167
+ const frontendEntries = Object.entries(frontendDirectories);
2168
+ const isSingleFrontend = frontendEntries.length === 1;
2169
+ const stylesDirectory = join9(frontendDirectory, "styles");
2170
+ const needsStylesDir = !(isSingleFrontend && frontendEntries[0]?.[0] === "svelte");
2171
+ if (needsStylesDir)
2172
+ mkdirSync6(stylesDirectory);
2173
+ if (needsStylesDir && tailwind !== undefined) {
2174
+ copyFileSync3(join9(templatesDirectory, "tailwind", "tailwind.css"), join9(stylesDirectory, "tailwind.css"));
2175
+ }
2176
+ const directoryMap = new Map;
2177
+ for (const [frontendName, rawDirectory] of frontendEntries) {
2178
+ const directory = rawDirectory?.trim() ?? (isSingleFrontend ? "" : frontendName);
2179
+ if (directoryMap.has(directory)) {
2180
+ throw new Error(`Frontend directory collision: "${directory}" is assigned to both "${directoryMap.get(directory)}" and "${frontendName}". Please pick unique directories.`);
2024
2181
  }
2025
- dirMap.set(dir, name);
2026
- const targetDirectory = join8(frontendDirectory, dir);
2027
- !isSingle && mkdirSync5(targetDirectory);
2028
- if (name === "react") {
2029
- scaffoldReact({
2030
- isSingle,
2031
- stylesDirectory,
2032
- targetDirectory,
2033
- templatesDirectory
2034
- });
2035
- }
2036
- if (name === "html") {
2037
- scaffoldHTML({
2038
- htmlScriptOption,
2039
- isSingle,
2040
- language,
2041
- targetDirectory,
2042
- templatesDirectory
2043
- });
2182
+ directoryMap.set(directory, frontendName);
2183
+ const targetDirectory = join9(frontendDirectory, directory);
2184
+ if (!isSingleFrontend)
2185
+ mkdirSync6(targetDirectory);
2186
+ switch (frontendName) {
2187
+ case "react":
2188
+ scaffoldReact({
2189
+ isSingleFrontend,
2190
+ stylesDirectory,
2191
+ targetDirectory,
2192
+ templatesDirectory
2193
+ });
2194
+ break;
2195
+ case "svelte":
2196
+ scaffoldSvelte({ language, targetDirectory });
2197
+ break;
2198
+ case "html":
2199
+ scaffoldHTML({
2200
+ htmlScriptOption,
2201
+ isSingleFrontend,
2202
+ targetDirectory
2203
+ });
2204
+ break;
2044
2205
  }
2045
- });
2206
+ }
2046
2207
  };
2047
2208
 
2048
2209
  // src/scaffold.ts
@@ -2053,28 +2214,29 @@ var scaffold = ({
2053
2214
  codeQualityTool,
2054
2215
  initializeGitNow,
2055
2216
  databaseEngine,
2056
- databaseHost,
2057
2217
  htmlScriptOption,
2058
2218
  useTailwind,
2059
2219
  databaseDirectory,
2060
2220
  orm,
2221
+ frontends,
2061
2222
  plugins,
2062
2223
  authProvider,
2063
2224
  buildDirectory,
2064
2225
  assetsDirectory,
2065
2226
  tailwind,
2066
2227
  installDependenciesNow,
2067
- frontendConfigurations
2228
+ frontendDirectories
2068
2229
  },
2069
2230
  latest,
2070
2231
  packageManager
2071
2232
  }) => {
2072
2233
  const __dirname2 = dirname(fileURLToPath(import.meta.url));
2073
- const templatesDirectory = join9(__dirname2, "/templates");
2234
+ const templatesDirectory = join10(__dirname2, "/templates");
2074
2235
  const { frontendDirectory, backendDirectory } = initalizeRoot(projectName, templatesDirectory);
2075
- copyFileSync4(join9(templatesDirectory, "README.md"), join9(projectName, "README.md"));
2236
+ copyFileSync4(join10(templatesDirectory, "README.md"), join10(projectName, "README.md"));
2076
2237
  addConfigurationFiles({
2077
2238
  codeQualityTool,
2239
+ frontends,
2078
2240
  initializeGitNow,
2079
2241
  language,
2080
2242
  projectName,
@@ -2084,19 +2246,19 @@ var scaffold = ({
2084
2246
  createPackageJson({
2085
2247
  authProvider,
2086
2248
  codeQualityTool,
2087
- frontendConfigurations,
2249
+ frontendDirectories,
2088
2250
  latest,
2089
2251
  plugins,
2090
2252
  projectName,
2091
2253
  useTailwind
2092
2254
  });
2093
- const serverFilePath = join9(backendDirectory, "server.ts");
2255
+ const serverFilePath = join10(backendDirectory, "server.ts");
2094
2256
  createServerFile({
2095
2257
  assetsDirectory,
2096
2258
  authProvider,
2097
2259
  availablePlugins,
2098
2260
  buildDirectory,
2099
- frontendConfigurations,
2261
+ frontendDirectories,
2100
2262
  plugins,
2101
2263
  serverFilePath,
2102
2264
  tailwind
@@ -2108,7 +2270,7 @@ var scaffold = ({
2108
2270
  projectName
2109
2271
  });
2110
2272
  scaffoldFrontends({
2111
- frontendConfigurations,
2273
+ frontendDirectories,
2112
2274
  frontendDirectory,
2113
2275
  htmlScriptOption,
2114
2276
  language,
@@ -2124,6 +2286,174 @@ var scaffold = ({
2124
2286
  });
2125
2287
  };
2126
2288
 
2289
+ // src/utils/parseCommandLineOptions.ts
2290
+ import { argv, exit as exit4 } from "node:process";
2291
+ import { parseArgs } from "node:util";
2292
+ var parseCommandLineOptions = () => {
2293
+ const { values, positionals } = parseArgs({
2294
+ allowNegative: true,
2295
+ allowPositionals: true,
2296
+ args: argv.slice(DEFAULT_ARG_LENGTH),
2297
+ options: {
2298
+ angular: { type: "string" },
2299
+ assets: { type: "string" },
2300
+ auth: { type: "string" },
2301
+ build: { type: "string" },
2302
+ database: { type: "string" },
2303
+ debug: { default: false, short: "d", type: "boolean" },
2304
+ directory: { type: "string" },
2305
+ engine: { type: "string" },
2306
+ frontend: { multiple: true, type: "string" },
2307
+ git: { type: "boolean" },
2308
+ help: { default: false, short: "h", type: "boolean" },
2309
+ host: { type: "string" },
2310
+ html: { type: "string" },
2311
+ htmx: { type: "string" },
2312
+ lang: { type: "string" },
2313
+ lts: { default: false, type: "boolean" },
2314
+ npm: { type: "boolean" },
2315
+ orm: { type: "string" },
2316
+ plugin: { multiple: true, type: "string" },
2317
+ quality: { type: "string" },
2318
+ react: { type: "string" },
2319
+ script: { type: "string" },
2320
+ skip: { type: "boolean" },
2321
+ svelte: { type: "string" },
2322
+ tailwind: { type: "boolean" },
2323
+ "tailwind-input": { type: "string" },
2324
+ "tailwind-output": { type: "string" },
2325
+ vue: { type: "string" }
2326
+ }
2327
+ });
2328
+ const errors = [];
2329
+ let authProvider;
2330
+ if (values.auth !== undefined && !isAuthProvider(values.auth)) {
2331
+ errors.push(`Invalid auth provider: "${values.auth}". Expected: [ ${availableAuthProviders.join(", ")} ]`);
2332
+ } else if (values.auth !== undefined) {
2333
+ authProvider = values.auth;
2334
+ } else if (values.skip) {
2335
+ authProvider = "none";
2336
+ }
2337
+ let databaseEngine;
2338
+ if (values.engine !== undefined && !isDatabaseEngine(values.engine)) {
2339
+ errors.push(`Invalid database engine: "${values.engine}". Expected: [ ${availableDatabaseEngines.join(", ")} ]`);
2340
+ } else if (values.engine !== undefined) {
2341
+ databaseEngine = values.engine;
2342
+ } else if (values.skip) {
2343
+ databaseEngine = "none";
2344
+ }
2345
+ let databaseHost;
2346
+ if (values.host !== undefined && !isDatabaseHost(values.host)) {
2347
+ errors.push(`Invalid database host: "${values.host}". Expected: [ ${availableDatabaseHosts.join(", ")} ]`);
2348
+ } else if (values.host !== undefined) {
2349
+ databaseHost = values.host;
2350
+ } else if (values.skip) {
2351
+ databaseHost = "none";
2352
+ }
2353
+ const { orm: ormValue } = values;
2354
+ let orm;
2355
+ if (ormValue !== undefined && !isORM(ormValue)) {
2356
+ errors.push(`Invalid ORM: "${values.orm}". Expected: [ ${availableORMs.join(", ")} ]`);
2357
+ } else if (ormValue !== undefined) {
2358
+ orm = ormValue;
2359
+ } else if (values.skip) {
2360
+ orm = "none";
2361
+ }
2362
+ const codeQualityTool = isCodeQualityTool(values.quality) ? values.quality : undefined;
2363
+ if (values.quality !== undefined && codeQualityTool === undefined) {
2364
+ errors.push(`Invalid code quality tool: "${values.quality}". Expected: [ ${availableCodeQualityTools.join(", ")} ]`);
2365
+ }
2366
+ let htmlScriptOption;
2367
+ if (values.script !== undefined && !isHTMLScriptOption(values.script)) {
2368
+ errors.push(`Invalid HTML script option: "${values.script}". Expected: [ ${availableHTMLScriptOptions.join(", ")} ]`);
2369
+ } else if (values.script !== undefined) {
2370
+ htmlScriptOption = values.script;
2371
+ } else if (values.skip) {
2372
+ htmlScriptOption = "none";
2373
+ }
2374
+ const language = values.lang !== undefined && isLanguage(values.lang) ? values.lang : undefined;
2375
+ if (values.lang !== undefined && language === undefined) {
2376
+ errors.push(`Invalid language: "${values.lang}". Expected: [ ${availableLanguages.join(", ")} ]`);
2377
+ }
2378
+ const directoryConfig = values.directory !== undefined && isDirectoryConfig(values.directory) ? values.directory : undefined;
2379
+ if (values.directory !== undefined && directoryConfig === undefined) {
2380
+ errors.push(`Invalid directory configuration: "${values.directory}". Expected: [ ${availableDirectoryConfigurations.join(", ")} ]`);
2381
+ }
2382
+ for (const f of values.frontend || []) {
2383
+ if (isFrontend(f))
2384
+ continue;
2385
+ errors.push(`Invalid frontend: "${f}". Expected: [ ${availableFrontends.join(", ")} ]`);
2386
+ }
2387
+ if (errors.length > 0) {
2388
+ console.error(errors.join(`
2389
+ `));
2390
+ exit4(1);
2391
+ }
2392
+ if (databaseEngine === "none" && databaseHost !== "none") {
2393
+ console.warn("Warning: Setting the database host without a database engine has no effect.");
2394
+ }
2395
+ if (databaseEngine === "none" && orm !== "none") {
2396
+ console.warn("Warning: Setting an ORM without a database engine has no effect.");
2397
+ }
2398
+ let databaseDirectory = values.database;
2399
+ if (databaseEngine === "none" && databaseDirectory !== undefined) {
2400
+ console.warn("Warning: Setting a database directory without a database engine has no effect.");
2401
+ databaseDirectory = undefined;
2402
+ }
2403
+ const frontendsWithDirectory = availableFrontends.filter((f) => values[f] !== undefined);
2404
+ const frontendDirectories = {};
2405
+ for (const frontend of frontendsWithDirectory) {
2406
+ frontendDirectories[frontend] = values[frontend];
2407
+ }
2408
+ const originalFrontends = values.frontend;
2409
+ const collector = new Set(originalFrontends ?? []);
2410
+ for (const frontend of frontendsWithDirectory) {
2411
+ collector.add(frontend);
2412
+ }
2413
+ values.frontend = collector.size > 0 ? Array.from(collector) : undefined;
2414
+ if (values.plugin === undefined && values.skip) {
2415
+ values.plugin = ["none"];
2416
+ }
2417
+ const plugins = values.plugin && values.plugin[0] === "none" ? [] : values.plugin;
2418
+ const hasTailwindFiles = values["tailwind-input"] !== undefined || values["tailwind-output"] !== undefined;
2419
+ let tailwind = hasTailwindFiles ? {
2420
+ input: values["tailwind-input"],
2421
+ output: values["tailwind-output"]
2422
+ } : undefined;
2423
+ const useTailwind = values.tailwind ?? (hasTailwindFiles ? true : undefined);
2424
+ if (useTailwind === false && hasTailwindFiles) {
2425
+ console.warn("Warning: Tailwind CSS input/output files are specified but Tailwind is disabled.");
2426
+ tailwind = undefined;
2427
+ }
2428
+ const argumentConfiguration = {
2429
+ assetsDirectory: values.assets,
2430
+ authProvider,
2431
+ buildDirectory: values.build,
2432
+ codeQualityTool,
2433
+ databaseDirectory,
2434
+ databaseEngine,
2435
+ databaseHost,
2436
+ directoryConfig,
2437
+ frontendDirectories,
2438
+ frontends: values.frontend?.filter(isFrontend),
2439
+ htmlScriptOption,
2440
+ initializeGitNow: values.git,
2441
+ installDependenciesNow: values.npm,
2442
+ language,
2443
+ orm,
2444
+ plugins,
2445
+ projectName: positionals[0],
2446
+ tailwind,
2447
+ useTailwind
2448
+ };
2449
+ return {
2450
+ argumentConfiguration,
2451
+ debug: values.debug,
2452
+ help: values.help,
2453
+ latest: values.lts
2454
+ };
2455
+ };
2456
+
2127
2457
  // src/utils/t3-utils.ts
2128
2458
  import { env } from "node:process";
2129
2459
  var getUserPackageManager = () => {
@@ -2142,24 +2472,15 @@ var getUserPackageManager = () => {
2142
2472
  };
2143
2473
 
2144
2474
  // src/index.ts
2145
- var { values } = parseArgs({
2146
- args: argv.slice(DEFAULT_ARG_LENGTH),
2147
- options: {
2148
- debug: { default: false, short: "d", type: "boolean" },
2149
- help: { default: false, short: "h", type: "boolean" },
2150
- latest: { default: false, short: "l", type: "boolean" }
2151
- },
2152
- strict: false
2153
- });
2154
2475
  var packageManager = getUserPackageManager();
2155
- if (values.help === true) {
2476
+ var { help, argumentConfiguration, latest, debug } = parseCommandLineOptions();
2477
+ if (help === true) {
2156
2478
  console.log(helpMessage);
2157
- exit4(0);
2479
+ exit5(0);
2158
2480
  }
2159
- var response = await prompt();
2160
- scaffold({ latest: values.latest === true, packageManager, response });
2161
- var debugMessage = values.debug !== false ? getDebugMessage({
2162
- availableFrontends,
2481
+ var response = await prompt(argumentConfiguration);
2482
+ scaffold({ latest, packageManager, response });
2483
+ var debugMessage = debug !== false ? getDebugMessage({
2163
2484
  packageManager,
2164
2485
  response
2165
2486
  }) : "";
@@ -2168,4 +2489,4 @@ var outroMessage = getOutroMessage({
2168
2489
  packageManager,
2169
2490
  projectName: response.projectName
2170
2491
  });
2171
- Se(debugMessage + outroMessage);
2492
+ Se(outroMessage + debugMessage);