create-absolutejs 0.3.1 → 0.3.3
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/commands/formatProject.d.ts +4 -2
- package/dist/commands/formatProject.js +21 -0
- package/dist/commands/installDependencies.js +19 -0
- package/dist/constants.js +4 -0
- package/dist/data.js +125 -0
- package/dist/generators/configurations/addConfigurationFiles.js +21 -0
- package/dist/generators/configurations/generateDrizzleConfig.js +11 -0
- package/dist/generators/configurations/generatePackageJson.js +74 -0
- package/dist/generators/configurations/generatePrettierrc.js +13 -0
- package/dist/generators/configurations/initializeRoot.js +26 -0
- package/dist/generators/db/scaffoldDatabase.js +16 -0
- package/dist/generators/html/scaffoldHTML.js +14 -0
- package/dist/generators/htmx/scaffoldHTMX.js +15 -0
- package/dist/generators/project/generateMarkupCSS.js +133 -0
- package/dist/generators/project/generateServer.js +159 -0
- package/dist/generators/project/scaffoldFrontends.js +71 -0
- package/dist/generators/react/scaffoldReact.js +14 -0
- package/dist/generators/svelte/scaffoldSvelte.js +13 -0
- package/dist/generators/vue/scaffoldVue.js +8 -0
- package/dist/index.js +23 -2464
- package/dist/messages.js +84 -0
- package/dist/prompt.js +84 -0
- package/dist/questions/authProvider.js +15 -0
- package/dist/questions/codeQualityTool.js +18 -0
- package/dist/questions/configurationType.js +15 -0
- package/dist/questions/databaseEngine.js +24 -0
- package/dist/questions/databaseHost.js +51 -0
- package/dist/questions/directoryConfiguration.js +77 -0
- package/dist/questions/frontendDirectoryConfigurations.js +29 -0
- package/dist/questions/frontends.js +16 -0
- package/dist/questions/htmlScriptingOption.js +10 -0
- package/dist/questions/initializeGitNow.js +10 -0
- package/dist/questions/installDependenciesNow.js +10 -0
- package/dist/questions/orm.js +16 -0
- package/dist/questions/plugins.js +13 -0
- package/dist/questions/projectName.js +11 -0
- package/dist/questions/useTailwind.js +8 -0
- package/dist/scaffold.js +70 -0
- package/dist/typeGuards.js +24 -0
- package/dist/types.js +1 -0
- package/dist/utils/abort.js +8 -0
- package/dist/utils/commandMaps.d.ts +3 -1
- package/dist/utils/commandMaps.js +18 -0
- package/dist/utils/getPackageVersion.js +12 -0
- package/dist/utils/parseCommandLineOptions.js +170 -0
- package/dist/utils/t3-utils.js +24 -0
- package/package.json +2 -2
package/dist/messages.js
ADDED
|
@@ -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
|
+
};
|
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
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
|
+
installDependenciesNow,
|
|
67
|
+
packageManager,
|
|
68
|
+
projectName
|
|
69
|
+
});
|
|
70
|
+
};
|
|
@@ -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 {};
|
|
@@ -1,2 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
import { PackageManager } from '../types';
|
|
2
|
+
export declare const formatCommands: Record<PackageManager, string>;
|
|
3
|
+
export declare const formatNoInstallCommands: Record<PackageManager, string>;
|
|
2
4
|
export declare const installCommands: Record<string, string>;
|
|
@@ -0,0 +1,18 @@
|
|
|
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 formatNoInstallCommands = {
|
|
8
|
+
bun: 'bunx prettier --write "./**/*.{js,ts,css,json,mjs,md,jsx,tsx,svelte,vue}"',
|
|
9
|
+
npm: 'npx prettier --write "./**/*.{js,ts,css,json,mjs,md,jsx,tsx,svelte,vue}"',
|
|
10
|
+
pnpm: 'pnpm dlx prettier --write "./**/*.{js,ts,css,json,mjs,md,jsx,tsx,svelte,vue}"',
|
|
11
|
+
yarn: 'yarn dlx prettier --write "./**/*.{js,ts,css,json,mjs,md,jsx,tsx,svelte,vue}"'
|
|
12
|
+
};
|
|
13
|
+
export const installCommands = {
|
|
14
|
+
bun: 'bun install',
|
|
15
|
+
npm: 'npm install',
|
|
16
|
+
pnpm: 'pnpm install',
|
|
17
|
+
yarn: 'yarn install'
|
|
18
|
+
};
|