create-absolutejs 0.3.1 → 0.3.2

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 (45) hide show
  1. package/dist/commands/formatProject.js +19 -0
  2. package/dist/commands/installDependencies.js +19 -0
  3. package/dist/constants.js +4 -0
  4. package/dist/data.js +125 -0
  5. package/dist/generators/configurations/addConfigurationFiles.js +21 -0
  6. package/dist/generators/configurations/generateDrizzleConfig.js +11 -0
  7. package/dist/generators/configurations/generatePackageJson.js +74 -0
  8. package/dist/generators/configurations/generatePrettierrc.js +13 -0
  9. package/dist/generators/configurations/initializeRoot.js +26 -0
  10. package/dist/generators/db/scaffoldDatabase.js +16 -0
  11. package/dist/generators/html/scaffoldHTML.js +14 -0
  12. package/dist/generators/htmx/scaffoldHTMX.js +15 -0
  13. package/dist/generators/project/generateMarkupCSS.js +133 -0
  14. package/dist/generators/project/generateServer.js +159 -0
  15. package/dist/generators/project/scaffoldFrontends.js +71 -0
  16. package/dist/generators/react/scaffoldReact.js +14 -0
  17. package/dist/generators/svelte/scaffoldSvelte.js +13 -0
  18. package/dist/generators/vue/scaffoldVue.js +8 -0
  19. package/dist/index.js +23 -2464
  20. package/dist/messages.js +84 -0
  21. package/dist/prompt.js +84 -0
  22. package/dist/questions/authProvider.js +15 -0
  23. package/dist/questions/codeQualityTool.js +18 -0
  24. package/dist/questions/configurationType.js +15 -0
  25. package/dist/questions/databaseEngine.js +24 -0
  26. package/dist/questions/databaseHost.js +51 -0
  27. package/dist/questions/directoryConfiguration.js +77 -0
  28. package/dist/questions/frontendDirectoryConfigurations.js +29 -0
  29. package/dist/questions/frontends.js +16 -0
  30. package/dist/questions/htmlScriptingOption.js +10 -0
  31. package/dist/questions/initializeGitNow.js +10 -0
  32. package/dist/questions/installDependenciesNow.js +10 -0
  33. package/dist/questions/orm.js +16 -0
  34. package/dist/questions/plugins.js +13 -0
  35. package/dist/questions/projectName.js +11 -0
  36. package/dist/questions/useTailwind.js +8 -0
  37. package/dist/scaffold.js +69 -0
  38. package/dist/typeGuards.js +24 -0
  39. package/dist/types.js +1 -0
  40. package/dist/utils/abort.js +8 -0
  41. package/dist/utils/commandMaps.js +12 -0
  42. package/dist/utils/getPackageVersion.js +12 -0
  43. package/dist/utils/parseCommandLineOptions.js +170 -0
  44. package/dist/utils/t3-utils.js +24 -0
  45. package/package.json +2 -2
@@ -0,0 +1,84 @@
1
+ import { blueBright, cyan, dim, green, magenta, red } from 'picocolors';
2
+ import { frontendLabels } from './data';
3
+ export const helpMessage = `
4
+ Usage: create-absolute [options] [${magenta('project-name')}]
5
+
6
+ Arguments:
7
+ ${magenta('project-name')} Name of the application to create.
8
+ If omitted, you'll be prompted to enter one.
9
+
10
+ Options:
11
+ ${cyan('--help, -h')} Show this help message and exit
12
+ ${cyan('--debug, -d')} Display a summary of the project configuration after creation
13
+
14
+ ${cyan('--angular')} ${dim(cyan('<dir>'))} Directory name for an Angular frontend
15
+ ${cyan('--assets')} ${dim(cyan('<dir>'))} Directory name for your static assets
16
+ ${cyan('--auth')} ${dim(cyan('<plugin>'))} Preconfigured auth plugin (currently only "absolute-auth") or 'none' to skip auth setup
17
+ ${cyan('--build')} ${dim(cyan('<dir>'))} Output directory for build artifacts
18
+ ${cyan('--database')} ${dim(cyan('<dir>'))} Directory name for your database files
19
+ ${cyan('--directory')} ${dim(cyan('<mode>'))} Directory-naming strategy: "default" or "custom"
20
+ ${cyan('--engine')} ${dim(cyan('<engine>'))} Database engine (postgresql | mysql | sqlite | mongodb | redis | singlestore | cockroachdb | mssql) or 'none' to skip database setup
21
+ ${cyan('--frontend')} ${dim(cyan('<name>'))} Frontend framework(s) to include: one or more of "react", "svelte", "html", "htmx", "vue", "angular"
22
+ ${cyan('--git')} Initialize a Git repository
23
+ ${cyan('--host')} ${dim(cyan('<host>'))} Database host provider (neon | planetscale | supabase | turso | vercel | upstash | atlas) or 'none' to skip database host setup
24
+ ${cyan('--html')} ${dim(cyan('<dir>'))} Directory name for an HTML frontend
25
+ ${cyan('--htmx')} ${dim(cyan('<dir>'))} Directory name for an HTMX frontend
26
+ ${cyan('--lts')} Use LTS versions of required packages
27
+ ${cyan('--npm')} Use the package manager that invoked this command to install dependencies
28
+ ${cyan('--orm')} ${dim(cyan('<orm>'))} ORM to configure: "drizzle" or "prisma" or 'none' to skip ORM setup
29
+ ${cyan('--plugin')} ${dim(cyan('<plugin>'))} Elysia plugin(s) to include (can be specified multiple times), passing 'none' will skip plugin setup and ignore any other plugin options
30
+ ${cyan('--quality')} ${dim(cyan('<tool>'))} Code quality tool: "eslint+prettier" or "biome"
31
+ ${cyan('--react')} ${dim(cyan('<dir>'))} Directory name for a React frontend
32
+ ${cyan('--html-script')} ${dim(cyan('<option>'))} Enable HTML scripting with TypeScript
33
+ ${cyan('--skip')} Skips non required prompts and uses 'none' for all optional configurations
34
+ ${cyan('--svelte')} ${dim(cyan('<dir>'))} Directory name for a Svelte frontend
35
+ ${cyan('--tailwind')} Include Tailwind CSS setup
36
+ ${cyan('--tailwind-input')} ${dim(cyan('<file>'))} Path to your Tailwind CSS entry file
37
+ ${cyan('--tailwind-output')} ${dim(cyan('<file>'))} Path for the generated Tailwind CSS bundle
38
+ ${cyan('--vue')} ${dim(cyan('<dir>'))} Directory name for a Vue frontend
39
+ `;
40
+ export const getOutroMessage = ({ projectName, packageManager, installDependenciesNow }) => `${green('Created successfully')}, you can now run:\n\n` +
41
+ `${cyan('cd')} ${projectName}\n` +
42
+ `${installDependenciesNow ? '' : `${cyan(`${packageManager} install`)}\n`}` +
43
+ `${cyan(`${packageManager} dev`)}`; // TODO: Some package managers need run
44
+ export const getDebugMessage = ({ response: { projectName, codeQualityTool, directoryConfig, useTailwind, tailwind, frontends, useHTMLScripts, frontendDirectories, buildDirectory, assetsDirectory, databaseEngine, databaseHost, databaseDirectory, orm, authProvider, plugins, initializeGitNow, installDependenciesNow }, packageManager }) => {
45
+ const htmlScriptingValue = useHTMLScripts
46
+ ? blueBright('TypeScript')
47
+ : dim('None');
48
+ const frameworkConfig = frontends
49
+ .map((name) => `${frontendLabels[name]}: src/frontend/${frontendDirectories[name]}`)
50
+ .join('\n ');
51
+ const tailwindSection = useTailwind && tailwind
52
+ ? `Input: ${tailwind.input}\nOutput: ${tailwind.output}`
53
+ : dim('None');
54
+ const isCustomConfig = directoryConfig === 'custom';
55
+ /* prettier-ignore */
56
+ const lines = [
57
+ ['Project Name', projectName],
58
+ ['Package Manager', packageManager],
59
+ ['Config Type', isCustomConfig ? green('Custom') : dim('Default')],
60
+ ['Linting', codeQualityTool === 'eslint+prettier' ? 'ESLint + Prettier' : 'Biome'],
61
+ ['Tailwind Configuration', tailwindSection],
62
+ [frontends.length === 1 ? 'Frontend' : 'Frontends', frontends.map((name) => frontendLabels[name]).join(', ')],
63
+ ['HTML Scripting', frontends.includes('html') ? htmlScriptingValue : dim('None')],
64
+ ['Build Directory', buildDirectory],
65
+ ['Assets Directory', assetsDirectory],
66
+ ['Database Engine', databaseEngine && databaseEngine !== 'none' ? databaseEngine : dim('None')],
67
+ ['Database Host', databaseHost && databaseHost !== 'none' ? databaseHost : dim('None')],
68
+ ['Database Directory', databaseDirectory ?? dim('None')],
69
+ ['ORM', orm ?? dim('None')],
70
+ ['Auth Provider', authProvider && authProvider !== 'none' ? authProvider : dim('None')],
71
+ ['Plugins', plugins.length && !plugins.includes('none') ? plugins.join(', ') : dim('None')],
72
+ ['Initialize Git', initializeGitNow ? green('Yes') : red('No')],
73
+ ['Install Dependencies', installDependenciesNow ? green('Yes') : red('No')],
74
+ ['Framework Config', frameworkConfig]
75
+ ];
76
+ const maxLabelLength = Math.max(...lines.map(([label]) => label.length));
77
+ const body = `\n\n${lines
78
+ .map(([label, value]) => {
79
+ const gap = ' '.repeat(maxLabelLength - label.length);
80
+ return `${magenta(label)}:${gap} ${value}`;
81
+ })
82
+ .join('\n')}`;
83
+ return body;
84
+ };
package/dist/prompt.js ADDED
@@ -0,0 +1,84 @@
1
+ import { getAuthProvider } from './questions/authProvider';
2
+ import { getCodeQualityTool } from './questions/codeQualityTool';
3
+ import { getConfigurationType } from './questions/configurationType';
4
+ import { getDatabaseEngine } from './questions/databaseEngine';
5
+ import { getDatabaseHost } from './questions/databaseHost';
6
+ import { getDirectoryConfiguration } from './questions/directoryConfiguration';
7
+ import { getFrontendDirectoryConfigurations } from './questions/frontendDirectoryConfigurations';
8
+ import { getFrontends } from './questions/frontends';
9
+ import { getHtmlScriptingOption } from './questions/htmlScriptingOption';
10
+ import { getInitializeGit } from './questions/initializeGitNow';
11
+ import { getInstallDependencies } from './questions/installDependenciesNow';
12
+ import { getORM } from './questions/orm';
13
+ import { getPlugins } from './questions/plugins';
14
+ import { getProjectName } from './questions/projectName';
15
+ import { getUseTailwind } from './questions/useTailwind';
16
+ export const prompt = async (argumentConfiguration) => {
17
+ // 1. Project name
18
+ const projectName = argumentConfiguration.projectName ?? (await getProjectName());
19
+ // 2. Linting/formatting tool
20
+ const codeQualityTool = argumentConfiguration.codeQualityTool ?? (await getCodeQualityTool());
21
+ // 3. Tailwind support?
22
+ const useTailwind = argumentConfiguration.useTailwind ?? (await getUseTailwind());
23
+ // 4. Frontend(s)
24
+ const frontends = argumentConfiguration.frontends?.filter((frontend) => frontend !== undefined) ?? (await getFrontends());
25
+ // 5. HTML scripting option (if HTML was selected)
26
+ const useHTMLScripts = !frontends.includes('html') ||
27
+ argumentConfiguration.useHTMLScripts === undefined
28
+ ? false
29
+ : (argumentConfiguration.useHTMLScripts ??
30
+ (await getHtmlScriptingOption()));
31
+ // 6. Database engine
32
+ const databaseEngine = argumentConfiguration.databaseEngine ?? (await getDatabaseEngine());
33
+ // 7. Database host
34
+ const databaseHost = argumentConfiguration.databaseHost ??
35
+ (await getDatabaseHost(databaseEngine));
36
+ // 8. ORM choice
37
+ const orm = databaseEngine !== undefined && databaseEngine !== 'none'
38
+ ? (argumentConfiguration.orm ?? (await getORM()))
39
+ : undefined;
40
+ // 9. Configuration type
41
+ let directoryConfig = argumentConfiguration.directoryConfig ?? (await getConfigurationType());
42
+ // 10. Directory configurations
43
+ const { buildDirectory, assetsDirectory, tailwind, databaseDirectory } = await getDirectoryConfiguration({
44
+ argumentConfiguration,
45
+ databaseEngine,
46
+ directoryConfig,
47
+ useTailwind
48
+ });
49
+ // 11. Framework-specific directories
50
+ const frontendDirectories = await getFrontendDirectoryConfigurations(directoryConfig, frontends, argumentConfiguration.frontendDirectories);
51
+ // If the user specified a custom directory configuration, we need to update the configuration type
52
+ if (argumentConfiguration.frontendDirectories !== undefined)
53
+ directoryConfig = 'custom';
54
+ // 12. Auth provider
55
+ const authProvider = argumentConfiguration.authProvider ?? (await getAuthProvider());
56
+ // 13. Additional plugins
57
+ const plugins = argumentConfiguration.plugins?.filter((plugin) => plugin !== undefined) ?? (await getPlugins());
58
+ // 14. Initialize Git repository
59
+ const initializeGitNow = argumentConfiguration.initializeGitNow ?? (await getInitializeGit());
60
+ // 15. Install dependencies
61
+ const installDependenciesNow = argumentConfiguration.installDependenciesNow ??
62
+ (await getInstallDependencies());
63
+ const values = {
64
+ assetsDirectory,
65
+ authProvider,
66
+ buildDirectory,
67
+ codeQualityTool,
68
+ databaseDirectory,
69
+ databaseEngine,
70
+ databaseHost,
71
+ directoryConfig,
72
+ frontendDirectories,
73
+ frontends,
74
+ initializeGitNow,
75
+ installDependenciesNow,
76
+ orm,
77
+ plugins,
78
+ projectName,
79
+ tailwind,
80
+ useHTMLScripts,
81
+ useTailwind
82
+ };
83
+ return values;
84
+ };
@@ -0,0 +1,15 @@
1
+ import { select, isCancel } from '@clack/prompts';
2
+ import { cyan } from 'picocolors';
3
+ import { abort } from '../utils/abort';
4
+ export const getAuthProvider = async () => {
5
+ const authProvider = await select({
6
+ message: 'Auth provider:',
7
+ options: [
8
+ { label: 'None', value: 'none' },
9
+ { label: cyan('Absolute Auth'), value: 'absoluteAuth' }
10
+ ]
11
+ });
12
+ if (isCancel(authProvider))
13
+ abort();
14
+ return authProvider === 'none' ? undefined : authProvider;
15
+ };
@@ -0,0 +1,18 @@
1
+ import { select, isCancel } from '@clack/prompts';
2
+ import { blueBright, yellow } from 'picocolors';
3
+ import { abort } from '../utils/abort';
4
+ export const getCodeQualityTool = async () => {
5
+ const codeQualityTool = await select({
6
+ message: 'Choose linting and formatting tool:',
7
+ options: [
8
+ {
9
+ label: blueBright('ESLint + Prettier'),
10
+ value: 'eslint+prettier'
11
+ },
12
+ { label: yellow('Biome'), value: 'biome' }
13
+ ]
14
+ });
15
+ if (isCancel(codeQualityTool))
16
+ abort();
17
+ return codeQualityTool;
18
+ };
@@ -0,0 +1,15 @@
1
+ import { select, isCancel } from '@clack/prompts';
2
+ import { blueBright, yellow } from 'picocolors';
3
+ import { abort } from '../utils/abort';
4
+ export const getConfigurationType = async () => {
5
+ const directoryConfig = await select({
6
+ message: 'Choose folder naming configuration:',
7
+ options: [
8
+ { label: blueBright('Default'), value: 'default' },
9
+ { label: yellow('Custom'), value: 'custom' }
10
+ ]
11
+ });
12
+ if (isCancel(directoryConfig))
13
+ abort();
14
+ return directoryConfig;
15
+ };
@@ -0,0 +1,24 @@
1
+ import { select, isCancel } from '@clack/prompts';
2
+ import { cyan, magenta, green, red, yellow } from 'picocolors';
3
+ import { abort } from '../utils/abort';
4
+ export const getDatabaseEngine = async () => {
5
+ const databaseDialectResponse = await select({
6
+ message: 'Database engine:',
7
+ options: [
8
+ { label: 'None', value: 'none' },
9
+ { label: cyan('PostgreSQL'), value: 'postgresql' },
10
+ { label: magenta('SQLite'), value: 'sqlite' },
11
+ { label: green('MySQL'), value: 'mysql' },
12
+ { label: red('Redis'), value: 'redis' },
13
+ { label: green('MongoDB'), value: 'mongodb' },
14
+ { label: magenta('SingleStore'), value: 'singlestore' },
15
+ { label: yellow('SQL Server'), value: 'mssql' },
16
+ { label: cyan('CockroachDB'), value: 'cockroachdb' }
17
+ ]
18
+ });
19
+ if (isCancel(databaseDialectResponse))
20
+ abort();
21
+ return databaseDialectResponse === 'none'
22
+ ? undefined
23
+ : databaseDialectResponse;
24
+ };
@@ -0,0 +1,51 @@
1
+ import { select, isCancel, confirm } from '@clack/prompts';
2
+ import { cyan } from 'picocolors';
3
+ import { abort } from '../utils/abort';
4
+ export const getDatabaseHost = async (databaseEngine) => {
5
+ if (databaseEngine === 'postgresql') {
6
+ const databaseHost = await select({
7
+ message: 'Select database host:',
8
+ options: [
9
+ { label: cyan('Neon'), value: 'neon' },
10
+ { label: cyan('Supabase'), value: 'supabase' },
11
+ { label: 'None', value: 'none' }
12
+ ]
13
+ });
14
+ if (isCancel(databaseHost))
15
+ abort();
16
+ return databaseHost === 'none' ? undefined : databaseHost;
17
+ }
18
+ if (databaseEngine === 'mysql') {
19
+ const databaseHost = await confirm({
20
+ message: 'Are you using PlanetScale?'
21
+ });
22
+ if (isCancel(databaseHost))
23
+ abort();
24
+ return databaseHost ? 'planetscale' : undefined;
25
+ }
26
+ if (databaseEngine === 'sqlite') {
27
+ const databaseHost = await confirm({
28
+ message: 'Are you using Turso?'
29
+ });
30
+ if (isCancel(databaseHost))
31
+ abort();
32
+ return databaseHost ? 'turso' : undefined;
33
+ }
34
+ if (databaseEngine === 'mongodb') {
35
+ const databaseHost = await confirm({
36
+ message: 'Are you using Atlas?'
37
+ });
38
+ if (isCancel(databaseHost))
39
+ abort();
40
+ return databaseHost ? 'atlas' : undefined;
41
+ }
42
+ if (databaseEngine === 'redis') {
43
+ const databaseHost = await confirm({
44
+ message: 'Are you using Upstash?'
45
+ });
46
+ if (isCancel(databaseHost))
47
+ abort();
48
+ return databaseHost ? 'upstash' : undefined;
49
+ }
50
+ return undefined;
51
+ };
@@ -0,0 +1,77 @@
1
+ import { text, isCancel } from '@clack/prompts';
2
+ import { abort } from '../utils/abort';
3
+ export const getDirectoryConfiguration = async ({ directoryConfig, useTailwind, databaseEngine, argumentConfiguration }) => {
4
+ if (directoryConfig === 'default') {
5
+ return {
6
+ assetsDirectory: argumentConfiguration.assetsDirectory ?? 'src/backend/assets',
7
+ buildDirectory: argumentConfiguration.buildDirectory ?? 'build',
8
+ databaseDirectory: databaseEngine
9
+ ? (argumentConfiguration.databaseDirectory ?? 'db')
10
+ : undefined,
11
+ tailwind: useTailwind
12
+ ? {
13
+ input: argumentConfiguration.tailwind?.input ??
14
+ './src/frontend/styles/tailwind.css',
15
+ output: argumentConfiguration.tailwind?.output ??
16
+ '/assets/css/tailwind.generated.css'
17
+ }
18
+ : undefined
19
+ };
20
+ }
21
+ // Build directory
22
+ const buildDirectory = argumentConfiguration.buildDirectory ??
23
+ (await text({
24
+ message: 'Build directory:',
25
+ placeholder: 'build'
26
+ }));
27
+ if (isCancel(buildDirectory))
28
+ abort();
29
+ // Assets directory
30
+ const assetsDirectory = argumentConfiguration.assetsDirectory ??
31
+ (await text({
32
+ message: 'Assets directory:',
33
+ placeholder: 'src/backend/assets'
34
+ }));
35
+ if (isCancel(assetsDirectory))
36
+ abort();
37
+ // Tailwind directory
38
+ let tailwind;
39
+ if (useTailwind) {
40
+ const input = argumentConfiguration.tailwind?.input ??
41
+ (await text({
42
+ message: 'Tailwind input CSS file:',
43
+ placeholder: './src/frontend/styles/tailwind.css'
44
+ }));
45
+ if (isCancel(input))
46
+ abort();
47
+ const output = argumentConfiguration.tailwind?.output ??
48
+ (await text({
49
+ message: 'Tailwind output CSS file:',
50
+ placeholder: '/assets/css/tailwind.generated.css'
51
+ }));
52
+ if (isCancel(output))
53
+ abort();
54
+ tailwind = { input, output };
55
+ }
56
+ else {
57
+ tailwind = undefined;
58
+ }
59
+ // Database
60
+ let databaseDirectory;
61
+ if (databaseEngine !== undefined) {
62
+ databaseDirectory =
63
+ argumentConfiguration.databaseDirectory ??
64
+ (await text({
65
+ message: 'Database directory:',
66
+ placeholder: 'db'
67
+ }));
68
+ if (isCancel(databaseDirectory))
69
+ abort();
70
+ }
71
+ return {
72
+ assetsDirectory,
73
+ buildDirectory,
74
+ databaseDirectory,
75
+ tailwind
76
+ };
77
+ };
@@ -0,0 +1,29 @@
1
+ import { text, isCancel } from '@clack/prompts';
2
+ import { frontendLabels } from '../data';
3
+ import { abort } from '../utils/abort';
4
+ const getDirectoryForFrontend = async (directoryConfiguration, frontend, isSingleFrontend) => {
5
+ if (directoryConfiguration !== 'custom')
6
+ return isSingleFrontend ? '' : frontend;
7
+ const response = await text({
8
+ message: `${frontendLabels[frontend]} directory:`,
9
+ placeholder: isSingleFrontend ? '' : frontend
10
+ });
11
+ if (isCancel(response))
12
+ abort();
13
+ return response;
14
+ };
15
+ export const getFrontendDirectoryConfigurations = async (directoryConfiguration, frontends, passedFrontendDirectories) => {
16
+ const isSingleFrontend = frontends.length === 1;
17
+ const frontendDirectories = {};
18
+ const frontendsToPrompt = [];
19
+ for (const frontend of frontends) {
20
+ const prefilled = passedFrontendDirectories?.[frontend];
21
+ if (prefilled === undefined)
22
+ frontendsToPrompt.push(frontend);
23
+ else
24
+ frontendDirectories[frontend] = prefilled;
25
+ }
26
+ const promptedDirectories = await Promise.all(frontendsToPrompt.map((name) => getDirectoryForFrontend(directoryConfiguration, name, isSingleFrontend)));
27
+ frontendsToPrompt.forEach((name, index) => (frontendDirectories[name] = promptedDirectories[index]));
28
+ return frontendDirectories;
29
+ };
@@ -0,0 +1,16 @@
1
+ import { multiselect, isCancel } from '@clack/prompts';
2
+ import { frontendLabels } from '../data';
3
+ import { isFrontend } from '../typeGuards';
4
+ import { abort } from '../utils/abort';
5
+ export const getFrontends = async () => {
6
+ const frontends = await multiselect({
7
+ message: 'Frontend(s) (space to select, enter to finish):',
8
+ options: Object.entries(frontendLabels).map(([value, label]) => ({
9
+ label,
10
+ value
11
+ }))
12
+ });
13
+ if (isCancel(frontends))
14
+ abort();
15
+ return frontends.filter(isFrontend);
16
+ };
@@ -0,0 +1,10 @@
1
+ import { confirm, isCancel } from '@clack/prompts';
2
+ import { abort } from '../utils/abort';
3
+ export const getHtmlScriptingOption = async () => {
4
+ const useScripts = await confirm({
5
+ message: 'Would you like to use scripts for your HTML pages?'
6
+ });
7
+ if (isCancel(useScripts))
8
+ abort();
9
+ return useScripts;
10
+ };
@@ -0,0 +1,10 @@
1
+ import { isCancel, confirm } from '@clack/prompts';
2
+ import { abort } from '../utils/abort';
3
+ export const getInitializeGit = async () => {
4
+ const initializeGitNow = await confirm({
5
+ message: 'Initialize a git repository?'
6
+ });
7
+ if (isCancel(initializeGitNow))
8
+ abort();
9
+ return initializeGitNow;
10
+ };
@@ -0,0 +1,10 @@
1
+ import { isCancel, confirm } from '@clack/prompts';
2
+ import { abort } from '../utils/abort';
3
+ export const getInstallDependencies = async () => {
4
+ const installDependenciesNow = await confirm({
5
+ message: 'Install dependencies now?'
6
+ });
7
+ if (isCancel(installDependenciesNow))
8
+ abort();
9
+ return installDependenciesNow;
10
+ };
@@ -0,0 +1,16 @@
1
+ import { select, isCancel } from '@clack/prompts';
2
+ import { cyan, magenta } from 'picocolors';
3
+ import { abort } from '../utils/abort';
4
+ export const getORM = async () => {
5
+ const orm = await select({
6
+ message: 'Choose an ORM (optional):',
7
+ options: [
8
+ { label: 'None', value: 'none' },
9
+ { label: cyan('Drizzle'), value: 'drizzle' },
10
+ { label: magenta('Prisma'), value: 'prisma' }
11
+ ]
12
+ });
13
+ if (isCancel(orm))
14
+ abort();
15
+ return orm === 'none' ? undefined : orm;
16
+ };
@@ -0,0 +1,13 @@
1
+ import { multiselect, isCancel } from '@clack/prompts';
2
+ import { availablePlugins } from '../data';
3
+ import { abort } from '../utils/abort';
4
+ export const getPlugins = async () => {
5
+ const plugins = await multiselect({
6
+ message: 'Select additional Elysia plugins (space to select, enter to submit):',
7
+ options: availablePlugins,
8
+ required: false
9
+ });
10
+ if (isCancel(plugins))
11
+ abort();
12
+ return plugins;
13
+ };
@@ -0,0 +1,11 @@
1
+ import { isCancel, text } from '@clack/prompts';
2
+ import { abort } from '../utils/abort';
3
+ export const getProjectName = async () => {
4
+ const projectName = await text({
5
+ message: 'Project name:',
6
+ placeholder: 'absolutejs-project'
7
+ });
8
+ if (isCancel(projectName))
9
+ abort();
10
+ return projectName ?? 'absolutejs-project';
11
+ };
@@ -0,0 +1,8 @@
1
+ import { isCancel, confirm } from '@clack/prompts';
2
+ import { abort } from '../utils/abort';
3
+ export const getUseTailwind = async () => {
4
+ const useTailwind = await confirm({ message: 'Add Tailwind support?' });
5
+ if (isCancel(useTailwind))
6
+ abort();
7
+ return useTailwind;
8
+ };
@@ -0,0 +1,69 @@
1
+ import { copyFileSync } from 'node:fs';
2
+ import { join, dirname } from 'node:path';
3
+ import { fileURLToPath } from 'node:url';
4
+ import { formatProject } from './commands/formatProject';
5
+ import { installDependencies } from './commands/installDependencies';
6
+ import { availablePlugins } from './data';
7
+ import { addConfigurationFiles } from './generators/configurations/addConfigurationFiles';
8
+ import { createPackageJson } from './generators/configurations/generatePackageJson';
9
+ import { initalizeRoot } from './generators/configurations/initializeRoot';
10
+ import { scaffoldDatabase } from './generators/db/scaffoldDatabase';
11
+ import { createServerFile } from './generators/project/generateServer';
12
+ import { scaffoldFrontends } from './generators/project/scaffoldFrontends';
13
+ export const scaffold = ({ response: { projectName, codeQualityTool, initializeGitNow, databaseEngine,
14
+ // databaseHost,
15
+ useHTMLScripts, useTailwind, databaseDirectory, orm, frontends, plugins, authProvider, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, packageManager }) => {
16
+ const __dirname = dirname(fileURLToPath(import.meta.url));
17
+ const templatesDirectory = join(__dirname, '/templates');
18
+ const { frontendDirectory, backendDirectory, projectAssetsDirectory } = initalizeRoot(projectName, templatesDirectory);
19
+ copyFileSync(join(templatesDirectory, 'README.md'), join(projectName, 'README.md'));
20
+ addConfigurationFiles({
21
+ codeQualityTool,
22
+ frontends,
23
+ initializeGitNow,
24
+ projectName,
25
+ tailwind,
26
+ templatesDirectory
27
+ });
28
+ createPackageJson({
29
+ authProvider,
30
+ codeQualityTool,
31
+ frontendDirectories,
32
+ latest,
33
+ plugins,
34
+ projectName,
35
+ useTailwind
36
+ });
37
+ const serverFilePath = join(backendDirectory, 'server.ts');
38
+ createServerFile({
39
+ assetsDirectory,
40
+ authProvider,
41
+ availablePlugins,
42
+ buildDirectory,
43
+ frontendDirectories,
44
+ plugins,
45
+ serverFilePath,
46
+ tailwind
47
+ });
48
+ void (databaseDirectory !== undefined &&
49
+ scaffoldDatabase({
50
+ databaseDirectory,
51
+ databaseEngine,
52
+ orm,
53
+ projectName
54
+ }));
55
+ scaffoldFrontends({
56
+ frontendDirectories,
57
+ frontendDirectory,
58
+ projectAssetsDirectory,
59
+ templatesDirectory,
60
+ useHTMLScripts
61
+ });
62
+ if (installDependenciesNow) {
63
+ installDependencies({ packageManager, projectName });
64
+ }
65
+ formatProject({
66
+ packageManager,
67
+ projectName
68
+ });
69
+ };
@@ -0,0 +1,24 @@
1
+ import { frontendLabels } from './data';
2
+ export const isAuthProvider = (value) => value === 'absoluteAuth' || value === 'none' || value === undefined;
3
+ export const isDirectoryConfig = (value) => value === 'default' || value === 'custom';
4
+ export const isDatabaseEngine = (value) => value === 'postgresql' ||
5
+ value === 'mysql' ||
6
+ value === 'sqlite' ||
7
+ value === 'mongodb' ||
8
+ value === 'redis' ||
9
+ value === 'singlestore' ||
10
+ value === 'cockroachdb' ||
11
+ value === 'mssql' ||
12
+ value === 'none' ||
13
+ value === undefined;
14
+ export const isDatabaseHost = (value) => value === 'neon' ||
15
+ value === 'planetscale' ||
16
+ value === 'supabase' ||
17
+ value === 'turso' ||
18
+ value === 'vercel' ||
19
+ value === 'upstash' ||
20
+ value === 'atlas' ||
21
+ value === undefined;
22
+ export const isORM = (value) => value === 'drizzle' || value === 'prisma' || value === undefined;
23
+ export const isCodeQualityTool = (value) => value === 'eslint+prettier' || value === 'biome' || value === undefined;
24
+ export const isFrontend = (value) => value !== undefined && Object.keys(frontendLabels).includes(value);
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,8 @@
1
+ import { exit } from 'node:process';
2
+ import { cancel } from '@clack/prompts';
3
+ /* eslint-disable */
4
+ export function abort() {
5
+ cancel('Operation cancelled');
6
+ exit(0);
7
+ }
8
+ /* eslint-enable */
@@ -0,0 +1,12 @@
1
+ export const formatCommands = {
2
+ bun: 'bun run format',
3
+ npm: 'npm run format',
4
+ pnpm: 'pnpm run format',
5
+ yarn: 'yarn format'
6
+ };
7
+ export const installCommands = {
8
+ bun: 'bun install',
9
+ npm: 'npm install',
10
+ pnpm: 'pnpm install',
11
+ yarn: 'yarn install'
12
+ };
@@ -0,0 +1,12 @@
1
+ import { execSync } from 'child_process';
2
+ export const getPackageVersion = (packageName) => {
3
+ try {
4
+ const raw = execSync(`curl -s https://registry.npmjs.org/${packageName}/latest`);
5
+ const { version } = JSON.parse(raw.toString());
6
+ return version;
7
+ }
8
+ catch (err) {
9
+ console.error(`Error fetching version for ${packageName}:`, err);
10
+ return null;
11
+ }
12
+ };