create-absolutejs 0.3.9 → 0.3.11
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/README.md +15 -15
- package/dist/data.d.ts +4 -2
- package/dist/data.js +23 -8
- package/dist/generators/configurations/generateDrizzleConfig.d.ts +2 -1
- package/dist/generators/configurations/generateDrizzleConfig.js +16 -6
- package/dist/generators/configurations/generatePackageJson.d.ts +2 -2
- package/dist/generators/configurations/generatePackageJson.js +42 -20
- package/dist/generators/db/generateDBHandlers.d.ts +6 -0
- package/dist/generators/db/generateDBHandlers.js +11 -0
- package/dist/generators/db/generateDrizzleSchema.d.ts +8 -0
- package/dist/generators/db/generateDrizzleSchema.js +122 -0
- package/dist/generators/db/handlerTemplates.d.ts +52 -0
- package/dist/generators/db/handlerTemplates.js +168 -0
- package/dist/generators/db/scaffoldDatabase.d.ts +5 -6
- package/dist/generators/db/scaffoldDatabase.js +37 -6
- package/dist/generators/html/generateHTMLPage.d.ts +2 -2
- package/dist/generators/html/generateHTMLPage.js +7 -4
- package/dist/generators/html/scaffoldHTML.js +1 -1
- package/dist/generators/project/collectDependencies.d.ts +9 -0
- package/dist/generators/project/collectDependencies.js +16 -0
- package/dist/generators/project/computeFlags.d.ts +9 -0
- package/dist/generators/project/computeFlags.js +7 -0
- package/dist/generators/project/generateBuildBlock.d.ts +9 -0
- package/dist/generators/project/generateBuildBlock.js +13 -0
- package/dist/generators/project/generateDBBlock.d.ts +4 -0
- package/dist/generators/project/generateDBBlock.js +69 -0
- package/dist/generators/project/generateImportsBlock.d.ts +13 -0
- package/dist/generators/project/generateImportsBlock.js +124 -0
- package/dist/generators/project/generateRoutesBlock.d.ts +10 -0
- package/dist/generators/project/generateRoutesBlock.js +74 -0
- package/dist/generators/project/generateServer.d.ts +3 -4
- package/dist/generators/project/generateServer.js +46 -170
- package/dist/generators/project/generateUseBlock.d.ts +6 -0
- package/dist/generators/project/generateUseBlock.js +28 -0
- package/dist/messages.js +13 -13
- package/dist/prompt.js +6 -7
- package/dist/questions/databaseEngine.d.ts +1 -1
- package/dist/questions/databaseEngine.js +2 -1
- package/dist/questions/databaseHost.d.ts +1 -1
- package/dist/questions/databaseHost.js +10 -30
- package/dist/questions/orm.d.ts +2 -1
- package/dist/questions/orm.js +13 -7
- package/dist/scaffold.d.ts +1 -1
- package/dist/scaffold.js +16 -8
- package/dist/templates/db/docker-compose.db.yml +15 -0
- package/dist/typeGuards.d.ts +3 -1
- package/dist/typeGuards.js +5 -19
- package/dist/types.d.ts +3 -1
- package/dist/utils/checkDockerInstalled.d.ts +2 -0
- package/dist/utils/checkDockerInstalled.js +179 -0
- package/dist/utils/parseCommandLineOptions.js +47 -15
- package/package.json +2 -2
- package/dist/templates/html/pages/HTMLExample.html +0 -66
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
type CreateServerFileProps = Pick<CreateConfiguration, 'tailwind' | 'authProvider' | 'plugins' | 'buildDirectory' | 'assetsDirectory' | 'frontendDirectories'> & {
|
|
3
|
-
availablePlugins: AvailableDependency[];
|
|
1
|
+
import type { CreateConfiguration } from '../../types';
|
|
2
|
+
type CreateServerFileProps = Pick<CreateConfiguration, 'tailwind' | 'authProvider' | 'databaseEngine' | 'plugins' | 'buildDirectory' | 'databaseHost' | 'orm' | 'assetsDirectory' | 'frontendDirectories'> & {
|
|
4
3
|
backendDirectory: string;
|
|
5
4
|
};
|
|
6
|
-
export declare const generateServerFile: ({ tailwind,
|
|
5
|
+
export declare const generateServerFile: ({ tailwind, authProvider, plugins, buildDirectory, databaseEngine, databaseHost, orm, assetsDirectory, frontendDirectories, backendDirectory }: CreateServerFileProps) => void;
|
|
7
6
|
export {};
|
|
@@ -1,179 +1,55 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { writeFileSync, mkdirSync } from 'fs';
|
|
2
2
|
import { join } from 'path';
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
|
|
3
|
+
import { collectDependencies } from './collectDependencies';
|
|
4
|
+
import { computeFlags } from './computeFlags';
|
|
5
|
+
import { generateBuildBlock } from './generateBuildBlock';
|
|
6
|
+
import { generateDBBlock } from './generateDBBlock';
|
|
7
|
+
import { generateImportsBlock } from './generateImportsBlock';
|
|
8
|
+
import { generateRoutesBlock } from './generateRoutesBlock';
|
|
9
|
+
import { generateUseBlock } from './generateUseBlock';
|
|
10
|
+
export const generateServerFile = ({ tailwind, authProvider, plugins, buildDirectory, databaseEngine, databaseHost, orm, assetsDirectory, frontendDirectories, backendDirectory }) => {
|
|
6
11
|
const serverFilePath = join(backendDirectory, 'server.ts');
|
|
7
|
-
const
|
|
8
|
-
const
|
|
9
|
-
const
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
const nonFrameworkOnly = (requiresHtml || requiresHtmx) &&
|
|
18
|
-
!requiresReact &&
|
|
19
|
-
!requiresSvelte &&
|
|
20
|
-
!requiresVue;
|
|
21
|
-
const selectedCustomPlugins = availablePlugins.filter(({ value }) => plugins.indexOf(value) !== UNFOUND_INDEX);
|
|
22
|
-
const authenticationPlugins = authProvider === 'absoluteAuth' ? [absoluteAuthPlugin] : [];
|
|
23
|
-
const htmxPlugins = requiresHtmx ? [scopedStatePlugin] : [];
|
|
24
|
-
const allDependencies = [
|
|
25
|
-
...defaultDependencies,
|
|
26
|
-
...defaultPlugins,
|
|
27
|
-
...selectedCustomPlugins,
|
|
28
|
-
...authenticationPlugins,
|
|
29
|
-
...htmxPlugins
|
|
30
|
-
];
|
|
31
|
-
const uniqueDependencies = Array.from(new Map(allDependencies.map((dependency) => [dependency.value, dependency])).values()).sort((a, b) => a.value.localeCompare(b.value));
|
|
32
|
-
const importLines = uniqueDependencies.flatMap(({ value, imports }) => {
|
|
33
|
-
const filteredImports = nonFrameworkOnly && imports
|
|
34
|
-
? imports.filter(({ packageName }) => packageName !== 'asset')
|
|
35
|
-
: imports;
|
|
36
|
-
return filteredImports && filteredImports.length > 0
|
|
37
|
-
? [
|
|
38
|
-
`import { ${filteredImports
|
|
39
|
-
.map(({ packageName }) => packageName)
|
|
40
|
-
.join(', ')} } from '${value}';`
|
|
41
|
-
]
|
|
42
|
-
: [];
|
|
12
|
+
const flags = computeFlags(frontendDirectories);
|
|
13
|
+
const deps = collectDependencies({ authProvider, flags, plugins });
|
|
14
|
+
const importsBlock = generateImportsBlock({
|
|
15
|
+
authProvider,
|
|
16
|
+
backendDirectory,
|
|
17
|
+
databaseEngine,
|
|
18
|
+
databaseHost,
|
|
19
|
+
deps,
|
|
20
|
+
flags,
|
|
21
|
+
orm
|
|
43
22
|
});
|
|
44
|
-
const
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
.map((item) => item.trim())
|
|
50
|
-
.filter((value) => value.length > 0);
|
|
51
|
-
const additionalItems = [
|
|
52
|
-
requiresHtml &&
|
|
53
|
-
!existingItems.includes('handleHTMLPageRequest') &&
|
|
54
|
-
'handleHTMLPageRequest',
|
|
55
|
-
requiresReact &&
|
|
56
|
-
!existingItems.includes('handleReactPageRequest') &&
|
|
57
|
-
'handleReactPageRequest',
|
|
58
|
-
requiresSvelte &&
|
|
59
|
-
!existingItems.includes('handleSveltePageRequest') &&
|
|
60
|
-
'handleSveltePageRequest',
|
|
61
|
-
requiresVue &&
|
|
62
|
-
!existingItems.includes('handleVuePageRequest') &&
|
|
63
|
-
'handleVuePageRequest',
|
|
64
|
-
requiresVue &&
|
|
65
|
-
!existingItems.includes('generateHeadElement') &&
|
|
66
|
-
'generateHeadElement',
|
|
67
|
-
requiresHtmx &&
|
|
68
|
-
!existingItems.includes('handleHTMXPageRequest') &&
|
|
69
|
-
'handleHTMXPageRequest'
|
|
70
|
-
].filter((value) => typeof value === 'string');
|
|
71
|
-
importLines[absoluteImportIdx] = `import { ${[
|
|
72
|
-
...existingItems,
|
|
73
|
-
...additionalItems
|
|
74
|
-
].join(', ')} } from '@absolutejs/absolute';`;
|
|
75
|
-
}
|
|
76
|
-
if (reactDirectory !== undefined) {
|
|
77
|
-
const reactImportSource = reactDirectory === ''
|
|
78
|
-
? '../frontend/pages/ReactExample'
|
|
79
|
-
: `../frontend/${reactDirectory}/pages/ReactExample`;
|
|
80
|
-
importLines.push(`import { ReactExample } from '${reactImportSource}';`);
|
|
81
|
-
}
|
|
82
|
-
if (requiresSvelte) {
|
|
83
|
-
const svelteImportSource = svelteDirectory === ''
|
|
84
|
-
? '../frontend/pages/SvelteExample'
|
|
85
|
-
: `../frontend/${svelteDirectory}/pages/SvelteExample`;
|
|
86
|
-
importLines.push(`import SvelteExample from '${svelteImportSource}.svelte';`);
|
|
87
|
-
}
|
|
88
|
-
if (requiresVue) {
|
|
89
|
-
const vueImportSource = vueDirectory === ''
|
|
90
|
-
? '../frontend/pages/VueExample'
|
|
91
|
-
: `../frontend/${vueDirectory}/pages/VueExample`;
|
|
92
|
-
const vueImportLine = requiresSvelte
|
|
93
|
-
? `import { vueImports } from './utils/vueImporter';\n\nconst { VueExample } = vueImports;`
|
|
94
|
-
: `import VueExample from '${vueImportSource}.vue';`;
|
|
95
|
-
importLines.push(vueImportLine);
|
|
96
|
-
}
|
|
97
|
-
if (requiresVue && requiresSvelte) {
|
|
98
|
-
const vueImporter = `// This file is auto-generated by the AbsoluteJS project generator.
|
|
99
|
-
// It is required to use Vue and Svelte together in the same project.
|
|
100
|
-
// This is due to how the Vue Official plugin handles non .ts files.
|
|
101
|
-
|
|
102
|
-
import VueExample from "../../frontend/vue/pages/VueExample.vue";
|
|
103
|
-
|
|
104
|
-
export const vueImports = {
|
|
105
|
-
VueExample
|
|
106
|
-
} as const;
|
|
107
|
-
`;
|
|
108
|
-
const backendUtilsDirectory = join(backendDirectory, 'utils');
|
|
109
|
-
mkdirSync(backendUtilsDirectory, { recursive: true });
|
|
110
|
-
writeFileSync(join(backendUtilsDirectory, 'vueImporter.ts'), vueImporter);
|
|
111
|
-
}
|
|
112
|
-
const useStatements = uniqueDependencies
|
|
113
|
-
.flatMap(({ imports }) => imports ?? [])
|
|
114
|
-
.filter((entry) => entry.isPlugin)
|
|
115
|
-
.map((entry) => {
|
|
116
|
-
if (entry.config === undefined)
|
|
117
|
-
return `.use(${entry.packageName})`;
|
|
118
|
-
if (entry.config === null)
|
|
119
|
-
return `.use(${entry.packageName}())`;
|
|
120
|
-
return `.use(${entry.packageName}(${JSON.stringify(entry.config)}))`;
|
|
23
|
+
const manifestBlock = generateBuildBlock({
|
|
24
|
+
assetsDirectory,
|
|
25
|
+
buildDirectory,
|
|
26
|
+
frontendDirectories,
|
|
27
|
+
tailwind
|
|
121
28
|
});
|
|
122
|
-
const
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
const
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
handler = `handleHTMLPageRequest(\`${buildDirectory}${directory ? `/${directory}` : ''}/pages/HTMLExample.html\`)`;
|
|
136
|
-
break;
|
|
137
|
-
case 'react':
|
|
138
|
-
handler = `handleReactPageRequest(ReactExample, asset(manifest, 'ReactExampleIndex'), { initialCount: 0, cssPath: asset(manifest, 'ReactExampleCSS') })`;
|
|
139
|
-
break;
|
|
140
|
-
case 'svelte':
|
|
141
|
-
handler = `handleSveltePageRequest(SvelteExample, asset(manifest, 'SvelteExample'), asset(manifest, 'SvelteExampleIndex'), { initialCount: 0, cssPath: asset(manifest, 'SvelteExampleCSS') })`;
|
|
142
|
-
break;
|
|
143
|
-
case 'vue':
|
|
144
|
-
handler = `handleVuePageRequest(VueExample, asset(manifest, 'VueExample'), asset(manifest, 'VueExampleIndex'), generateHeadElement({ cssPath: asset(manifest, 'VueExampleCSS'), title: 'AbsoluteJS + Vue' }), { initialCount: 0 })`;
|
|
145
|
-
break;
|
|
146
|
-
case 'htmx':
|
|
147
|
-
handler = `handleHTMXPageRequest(\`${buildDirectory}${directory ? `/${directory}` : ''}/pages/HTMXExample.html\`)`;
|
|
148
|
-
if (index === 0) {
|
|
149
|
-
acc.indexRoute = `.get('/', () => ${handler})`;
|
|
150
|
-
}
|
|
151
|
-
acc.otherRoutes.push(`.get('/htmx', () => ${handler})`, `.post('/htmx/reset', ({ resetScopedStore }) => resetScopedStore())`, `.get('/htmx/count', ({ scopedStore }) => scopedStore.count)`, `.post('/htmx/increment', ({ scopedStore }) => ++scopedStore.count)`);
|
|
152
|
-
return acc;
|
|
153
|
-
default:
|
|
154
|
-
return acc;
|
|
155
|
-
}
|
|
156
|
-
if (index === 0) {
|
|
157
|
-
acc.indexRoute = `.get('/', () => ${handler})`;
|
|
158
|
-
}
|
|
159
|
-
acc.otherRoutes.push(`.get('/${frameworkName}', () => ${handler})`);
|
|
160
|
-
return acc;
|
|
161
|
-
}, { indexRoute: null, otherRoutes: [] });
|
|
162
|
-
const routes = [routesData.indexRoute ?? '', ...routesData.otherRoutes]
|
|
163
|
-
.filter(Boolean)
|
|
164
|
-
.join('\n ');
|
|
165
|
-
const useLines = useStatements.map((s) => ` ${s}`).join('\n');
|
|
166
|
-
const serverFileContent = `${importLines.join('\n')}
|
|
167
|
-
|
|
168
|
-
${manifestDeclaration}
|
|
29
|
+
const dbBlock = generateDBBlock({ databaseEngine, databaseHost, orm });
|
|
30
|
+
const useBlock = generateUseBlock({
|
|
31
|
+
databaseEngine,
|
|
32
|
+
deps,
|
|
33
|
+
orm
|
|
34
|
+
});
|
|
35
|
+
const routesBlock = generateRoutesBlock({
|
|
36
|
+
authProvider,
|
|
37
|
+
buildDirectory,
|
|
38
|
+
flags,
|
|
39
|
+
frontendDirectories
|
|
40
|
+
});
|
|
41
|
+
const content = `${importsBlock}
|
|
169
42
|
|
|
43
|
+
${manifestBlock}
|
|
44
|
+
${dbBlock}
|
|
170
45
|
new Elysia()
|
|
171
|
-
${
|
|
172
|
-
${
|
|
173
|
-
.on('error',
|
|
174
|
-
const { request } = err
|
|
175
|
-
console.error(\`Server error on \${request.method} \${request.url}: \${err.message}\`)
|
|
46
|
+
${useBlock}
|
|
47
|
+
${routesBlock}
|
|
48
|
+
.on('error', err => {
|
|
49
|
+
const { request } = err
|
|
50
|
+
console.error(\`Server error on \${request.method} \${request.url}: \${err.message}\`)
|
|
176
51
|
});
|
|
177
52
|
`;
|
|
178
|
-
|
|
53
|
+
mkdirSync(backendDirectory, { recursive: true });
|
|
54
|
+
writeFileSync(serverFilePath, content);
|
|
179
55
|
};
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
export const generateUseBlock = ({ deps, databaseEngine, orm }) => deps
|
|
2
|
+
.flatMap((dependency) => dependency.imports ?? [])
|
|
3
|
+
.filter((pluginImport) => pluginImport.isPlugin)
|
|
4
|
+
.map((pluginImport) => {
|
|
5
|
+
const isAuth = pluginImport.packageName === 'absoluteAuth';
|
|
6
|
+
if (isAuth) {
|
|
7
|
+
const baseConfigString = pluginImport.config !== null
|
|
8
|
+
? JSON.stringify(pluginImport.config).slice(1, -1)
|
|
9
|
+
: '';
|
|
10
|
+
const hasDatabase = databaseEngine !== undefined && databaseEngine !== 'none';
|
|
11
|
+
const hasOrm = orm !== undefined && orm !== 'none';
|
|
12
|
+
const instantiate = 'instantiateUserSession';
|
|
13
|
+
const pluginGeneric = hasOrm ? '<User>' : '';
|
|
14
|
+
const callback = hasDatabase
|
|
15
|
+
? `async ({ authProvider, providerInstance, tokenResponse, userSessionId, session }) => ${instantiate}({ authProvider, providerInstance, session, tokenResponse, userSessionId, createUser: (userIdentity) => createUser({ authProvider, db, userIdentity }), getUser: (userIdentity) => getUser({ authProvider, db, userIdentity }) })`
|
|
16
|
+
: `({ authProvider, tokenResponse, userSessionId }) => { console.log(\`Successfully authorized OAuth2 with \${authProvider} (session: \${userSessionId})\`, tokenResponse); }`;
|
|
17
|
+
const mergedConfig = `{ ${baseConfigString}${baseConfigString ? ',' : ''} onCallbackSuccess: ${callback} }`;
|
|
18
|
+
return `.use(absoluteAuth${pluginGeneric}(${mergedConfig}))`;
|
|
19
|
+
}
|
|
20
|
+
if (pluginImport.config === undefined) {
|
|
21
|
+
return `.use(${pluginImport.packageName})`;
|
|
22
|
+
}
|
|
23
|
+
if (pluginImport.config === null) {
|
|
24
|
+
return `.use(${pluginImport.packageName}())`;
|
|
25
|
+
}
|
|
26
|
+
return `.use(${pluginImport.packageName}(${JSON.stringify(pluginImport.config)}))`;
|
|
27
|
+
})
|
|
28
|
+
.join('\n');
|
package/dist/messages.js
CHANGED
|
@@ -12,36 +12,36 @@ Options:
|
|
|
12
12
|
${cyan('--debug, -d')} Display a summary of the project configuration after creation
|
|
13
13
|
|
|
14
14
|
${cyan('--angular')} Include an Angular frontend
|
|
15
|
-
${cyan('--angular-dir')} ${dim(cyan('<
|
|
16
|
-
${cyan('--assets')} ${dim(cyan('<
|
|
15
|
+
${cyan('--angular-dir')} ${dim(cyan('<directory>'))} Specify the directory for and use the Angular frontend
|
|
16
|
+
${cyan('--assets')} ${dim(cyan('<directory>'))} Directory name for your static assets
|
|
17
17
|
${cyan('--auth')} ${dim(cyan('<plugin>'))} Pre-configured auth plugin (currently only "absolute-auth") or 'none'
|
|
18
18
|
${cyan('--biome')} Use Biome for code quality and formatting
|
|
19
|
-
${cyan('--build')} ${dim(cyan('<
|
|
20
|
-
${cyan('--
|
|
19
|
+
${cyan('--build')} ${dim(cyan('<directory>'))} Output directory for build artifacts
|
|
20
|
+
${cyan('--db')} ${dim(cyan('<engine>'))} Database engine (postgresql | mysql | sqlite | mongodb | mariadb | gel | singlestore | cockroachdb | mssql) or 'none'
|
|
21
|
+
${cyan('--db-dir')} ${dim(cyan('<directory>'))} Directory name for your database files
|
|
22
|
+
${cyan('--db-host')} ${dim(cyan('<host>'))} Database host provider (neon | planetscale) or 'none'
|
|
21
23
|
${cyan('--directory')} ${dim(cyan('<mode>'))} Directory-naming strategy: "default" or "custom"
|
|
22
|
-
${cyan('--
|
|
23
|
-
${cyan('--eslint+prettier')} Use ESLint + Prettier for code quality and formatting
|
|
24
|
+
${cyan('--eslint+prettier')} Use ESLint + Prettier for code quality and formatting
|
|
24
25
|
${cyan('--git')} Initialize a Git repository
|
|
25
|
-
${cyan('--host')} ${dim(cyan('<host>'))} Database host provider (neon | planetscale | supabase | turso | vercel | upstash | atlas) or 'none'
|
|
26
26
|
${cyan('--html')} Include a plain HTML frontend
|
|
27
|
-
${cyan('--html-dir')} ${dim(cyan('<
|
|
28
|
-
${cyan('--html-scripts')}
|
|
27
|
+
${cyan('--html-dir')} ${dim(cyan('<directory>'))} Specify the directory for and use the HTML frontend
|
|
28
|
+
${cyan('--html-scripts')} Enable HTML scripting with TypeScript
|
|
29
29
|
${cyan('--htmx')} Include an HTMX frontend
|
|
30
|
-
${cyan('--htmx-dir')} ${dim(cyan('<
|
|
30
|
+
${cyan('--htmx-dir')} ${dim(cyan('<directory>'))} Specify the directory for and use the HTMX frontend
|
|
31
31
|
${cyan('--install')} Use the same package manager to install dependencies
|
|
32
32
|
${cyan('--lts')} Use LTS versions of required packages
|
|
33
33
|
${cyan('--orm')} ${dim(cyan('<orm>'))} ORM to configure: "drizzle" | "prisma" | 'none'
|
|
34
34
|
${cyan('--plugin')} ${dim(cyan('<plugin>'))} Elysia plugin(s) to include (repeatable); 'none' skips plugin setup
|
|
35
35
|
${cyan('--react')} Include a React frontend
|
|
36
|
-
${cyan('--react-dir')} ${dim(cyan('<
|
|
36
|
+
${cyan('--react-dir')} ${dim(cyan('<directory>'))} Specify the directory for and use the React frontend
|
|
37
37
|
${cyan('--skip')} Skip non-required prompts; uses 'none' for all optional configs
|
|
38
38
|
${cyan('--svelte')} Include a Svelte frontend
|
|
39
|
-
${cyan('--svelte-dir')} ${dim(cyan('<
|
|
39
|
+
${cyan('--svelte-dir')} ${dim(cyan('<directory>'))} Specify the directory for and use the Svelte frontend
|
|
40
40
|
${cyan('--tailwind')} Include Tailwind CSS setup
|
|
41
41
|
${cyan('--tailwind-input')} ${dim(cyan('<file>'))} Path to your Tailwind CSS entry file
|
|
42
42
|
${cyan('--tailwind-output')} ${dim(cyan('<file>'))} Path for the generated Tailwind CSS bundle
|
|
43
43
|
${cyan('--vue')} Include a Vue frontend
|
|
44
|
-
${cyan('--vue-dir')} ${dim(cyan('<
|
|
44
|
+
${cyan('--vue-dir')} ${dim(cyan('<directory>'))} Specify the directory for and use the Vue frontend
|
|
45
45
|
`;
|
|
46
46
|
export const getOutroMessage = ({ projectName, packageManager, installDependenciesNow }) => `${green('Created successfully')}, you can now run:\n\n` +
|
|
47
47
|
`${cyan('cd')} ${projectName}\n` +
|
package/dist/prompt.js
CHANGED
|
@@ -23,11 +23,10 @@ export const prompt = async (argumentConfiguration) => {
|
|
|
23
23
|
// 4. Frontend(s)
|
|
24
24
|
const frontends = argumentConfiguration.frontends?.filter((frontend) => frontend !== undefined) ?? (await getFrontends());
|
|
25
25
|
// 5. HTML scripting option (if HTML was selected)
|
|
26
|
-
const useHTMLScripts =
|
|
27
|
-
argumentConfiguration.useHTMLScripts
|
|
28
|
-
|
|
29
|
-
:
|
|
30
|
-
(await getHtmlScriptingOption()));
|
|
26
|
+
const useHTMLScripts = frontends.includes('html')
|
|
27
|
+
? (argumentConfiguration.useHTMLScripts ??
|
|
28
|
+
(await getHtmlScriptingOption()))
|
|
29
|
+
: false;
|
|
31
30
|
// 6. Database engine
|
|
32
31
|
const databaseEngine = argumentConfiguration.databaseEngine ?? (await getDatabaseEngine());
|
|
33
32
|
// 7. Database host
|
|
@@ -35,7 +34,7 @@ export const prompt = async (argumentConfiguration) => {
|
|
|
35
34
|
(await getDatabaseHost(databaseEngine));
|
|
36
35
|
// 8. ORM choice
|
|
37
36
|
const orm = databaseEngine !== undefined && databaseEngine !== 'none'
|
|
38
|
-
? (argumentConfiguration.orm ?? (await getORM()))
|
|
37
|
+
? (argumentConfiguration.orm ?? (await getORM(databaseEngine)))
|
|
39
38
|
: undefined;
|
|
40
39
|
// 9. Configuration type
|
|
41
40
|
let directoryConfig = argumentConfiguration.directoryConfig ?? (await getConfigurationType());
|
|
@@ -46,7 +45,7 @@ export const prompt = async (argumentConfiguration) => {
|
|
|
46
45
|
directoryConfig,
|
|
47
46
|
useTailwind
|
|
48
47
|
});
|
|
49
|
-
// 11. Framework
|
|
48
|
+
// 11. Framework specific directories
|
|
50
49
|
const frontendDirectories = await getFrontendDirectoryConfigurations(directoryConfig, frontends, argumentConfiguration.frontendDirectories);
|
|
51
50
|
// If the user specified a custom directory configuration, we need to update the configuration type
|
|
52
51
|
if (argumentConfiguration.frontendDirectories !== undefined)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const getDatabaseEngine: () => Promise<"
|
|
1
|
+
export declare const getDatabaseEngine: () => Promise<"gel" | "mysql" | "postgresql" | "sqlite" | "singlestore" | "mongodb" | "mariadb" | "cockroachdb" | "mssql" | undefined>;
|
|
@@ -9,7 +9,8 @@ export const getDatabaseEngine = async () => {
|
|
|
9
9
|
{ label: cyan('PostgreSQL'), value: 'postgresql' },
|
|
10
10
|
{ label: magenta('SQLite'), value: 'sqlite' },
|
|
11
11
|
{ label: green('MySQL'), value: 'mysql' },
|
|
12
|
-
{ label: red('
|
|
12
|
+
{ label: red('MariaDB'), value: 'mariadb' },
|
|
13
|
+
{ label: cyan('Gel'), value: 'gel' },
|
|
13
14
|
{ label: green('MongoDB'), value: 'mongodb' },
|
|
14
15
|
{ label: magenta('SingleStore'), value: 'singlestore' },
|
|
15
16
|
{ label: yellow('SQL Server'), value: 'mssql' },
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { DatabaseEngine } from '../types';
|
|
2
|
-
export declare const getDatabaseHost: (databaseEngine: DatabaseEngine) => Promise<"neon" | "planetscale" | "
|
|
2
|
+
export declare const getDatabaseHost: (databaseEngine: DatabaseEngine) => Promise<"neon" | "planetscale" | "turso" | undefined>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { select, isCancel
|
|
1
|
+
import { select, isCancel } from '@clack/prompts';
|
|
2
2
|
import { cyan } from 'picocolors';
|
|
3
3
|
import { abort } from '../utils/abort';
|
|
4
4
|
export const getDatabaseHost = async (databaseEngine) => {
|
|
@@ -6,46 +6,26 @@ export const getDatabaseHost = async (databaseEngine) => {
|
|
|
6
6
|
const databaseHost = await select({
|
|
7
7
|
message: 'Select database host:',
|
|
8
8
|
options: [
|
|
9
|
+
{ label: 'None', value: 'none' },
|
|
9
10
|
{ label: cyan('Neon'), value: 'neon' },
|
|
10
|
-
{ label: cyan('
|
|
11
|
-
{ label: 'None', value: 'none' }
|
|
11
|
+
{ label: cyan('PlanetScale'), value: 'planetscale' }
|
|
12
12
|
]
|
|
13
13
|
});
|
|
14
14
|
if (isCancel(databaseHost))
|
|
15
15
|
abort();
|
|
16
16
|
return databaseHost === 'none' ? undefined : databaseHost;
|
|
17
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
18
|
if (databaseEngine === 'sqlite') {
|
|
27
|
-
const databaseHost = await
|
|
28
|
-
message: '
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
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?'
|
|
19
|
+
const databaseHost = await select({
|
|
20
|
+
message: 'Select database host:',
|
|
21
|
+
options: [
|
|
22
|
+
{ label: 'None', value: 'none' },
|
|
23
|
+
{ label: cyan('Turso'), value: 'turso' }
|
|
24
|
+
]
|
|
45
25
|
});
|
|
46
26
|
if (isCancel(databaseHost))
|
|
47
27
|
abort();
|
|
48
|
-
return databaseHost
|
|
28
|
+
return databaseHost === 'none' ? undefined : databaseHost;
|
|
49
29
|
}
|
|
50
30
|
return undefined;
|
|
51
31
|
};
|
package/dist/questions/orm.d.ts
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
import { DatabaseEngine } from '../types';
|
|
2
|
+
export declare const getORM: (databaseEngine: Exclude<DatabaseEngine, "none" | undefined>) => Promise<"drizzle" | "prisma" | undefined>;
|
package/dist/questions/orm.js
CHANGED
|
@@ -1,14 +1,20 @@
|
|
|
1
1
|
import { select, isCancel } from '@clack/prompts';
|
|
2
2
|
import { cyan, magenta } from 'picocolors';
|
|
3
|
+
import { isDrizzleDialect, isPrismaDialect } from '../typeGuards';
|
|
3
4
|
import { abort } from '../utils/abort';
|
|
4
|
-
export const getORM = async () => {
|
|
5
|
+
export const getORM = async (databaseEngine) => {
|
|
6
|
+
const options = [
|
|
7
|
+
{ label: 'None', value: 'none' }
|
|
8
|
+
];
|
|
9
|
+
if (isDrizzleDialect(databaseEngine)) {
|
|
10
|
+
options.push({ label: cyan('Drizzle'), value: 'drizzle' });
|
|
11
|
+
}
|
|
12
|
+
if (isPrismaDialect(databaseEngine)) {
|
|
13
|
+
options.push({ label: magenta('Prisma'), value: 'prisma' });
|
|
14
|
+
}
|
|
5
15
|
const orm = await select({
|
|
6
|
-
message: 'Choose an ORM
|
|
7
|
-
options
|
|
8
|
-
{ label: 'None', value: 'none' },
|
|
9
|
-
{ label: cyan('Drizzle'), value: 'drizzle' },
|
|
10
|
-
{ label: magenta('Prisma'), value: 'prisma' }
|
|
11
|
-
]
|
|
16
|
+
message: 'Choose an ORM for your database:',
|
|
17
|
+
options
|
|
12
18
|
});
|
|
13
19
|
if (isCancel(orm))
|
|
14
20
|
abort();
|
package/dist/scaffold.d.ts
CHANGED
|
@@ -4,5 +4,5 @@ type ScaffoldProps = {
|
|
|
4
4
|
packageManager: PackageManager;
|
|
5
5
|
latest: boolean;
|
|
6
6
|
};
|
|
7
|
-
export declare const scaffold: ({ response: { projectName, codeQualityTool, initializeGitNow, databaseEngine, useHTMLScripts, useTailwind, databaseDirectory, orm, frontends, plugins, authProvider, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, packageManager }: ScaffoldProps) => Promise<void>;
|
|
7
|
+
export declare const scaffold: ({ response: { projectName, codeQualityTool, initializeGitNow, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, orm, frontends, plugins, authProvider, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, packageManager }: ScaffoldProps) => Promise<void>;
|
|
8
8
|
export {};
|
package/dist/scaffold.js
CHANGED
|
@@ -4,16 +4,13 @@ import { fileURLToPath } from 'node:url';
|
|
|
4
4
|
import { formatProject } from './commands/formatProject';
|
|
5
5
|
import { initializeGit } from './commands/initializeGit';
|
|
6
6
|
import { installDependencies } from './commands/installDependencies';
|
|
7
|
-
import { availablePlugins } from './data';
|
|
8
7
|
import { addConfigurationFiles } from './generators/configurations/addConfigurationFiles';
|
|
9
8
|
import { createPackageJson } from './generators/configurations/generatePackageJson';
|
|
10
9
|
import { initalizeRoot } from './generators/configurations/initializeRoot';
|
|
11
10
|
import { scaffoldDatabase } from './generators/db/scaffoldDatabase';
|
|
12
11
|
import { generateServerFile } from './generators/project/generateServer';
|
|
13
12
|
import { scaffoldFrontends } from './generators/project/scaffoldFrontends';
|
|
14
|
-
export const scaffold = async ({ response: { projectName, codeQualityTool, initializeGitNow, databaseEngine,
|
|
15
|
-
// databaseHost,
|
|
16
|
-
useHTMLScripts, useTailwind, databaseDirectory, orm, frontends, plugins, authProvider, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, packageManager }) => {
|
|
13
|
+
export const scaffold = async ({ response: { projectName, codeQualityTool, initializeGitNow, databaseEngine, databaseHost, useHTMLScripts, useTailwind, databaseDirectory, orm, frontends, plugins, authProvider, buildDirectory, assetsDirectory, tailwind, installDependenciesNow, frontendDirectories }, latest, packageManager }) => {
|
|
17
14
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
18
15
|
const templatesDirectory = join(__dirname, '/templates');
|
|
19
16
|
const { frontendDirectory, backendDirectory, projectAssetsDirectory } = initalizeRoot(projectName, templatesDirectory);
|
|
@@ -29,8 +26,11 @@ useHTMLScripts, useTailwind, databaseDirectory, orm, frontends, plugins, authPro
|
|
|
29
26
|
createPackageJson({
|
|
30
27
|
authProvider,
|
|
31
28
|
codeQualityTool,
|
|
29
|
+
databaseEngine,
|
|
30
|
+
databaseHost,
|
|
32
31
|
frontendDirectories,
|
|
33
32
|
latest,
|
|
33
|
+
orm,
|
|
34
34
|
plugins,
|
|
35
35
|
projectName,
|
|
36
36
|
useTailwind
|
|
@@ -38,20 +38,28 @@ useHTMLScripts, useTailwind, databaseDirectory, orm, frontends, plugins, authPro
|
|
|
38
38
|
generateServerFile({
|
|
39
39
|
assetsDirectory,
|
|
40
40
|
authProvider,
|
|
41
|
-
availablePlugins,
|
|
42
41
|
backendDirectory,
|
|
43
42
|
buildDirectory,
|
|
43
|
+
databaseEngine,
|
|
44
|
+
databaseHost,
|
|
44
45
|
frontendDirectories,
|
|
46
|
+
orm,
|
|
45
47
|
plugins,
|
|
46
48
|
tailwind
|
|
47
49
|
});
|
|
48
50
|
void (databaseDirectory !== undefined &&
|
|
49
|
-
|
|
51
|
+
databaseEngine !== 'none' &&
|
|
52
|
+
databaseEngine !== undefined &&
|
|
53
|
+
(await scaffoldDatabase({
|
|
54
|
+
authProvider,
|
|
55
|
+
backendDirectory,
|
|
50
56
|
databaseDirectory,
|
|
51
57
|
databaseEngine,
|
|
58
|
+
databaseHost,
|
|
52
59
|
orm,
|
|
53
|
-
projectName
|
|
54
|
-
|
|
60
|
+
projectName,
|
|
61
|
+
templatesDirectory
|
|
62
|
+
})));
|
|
55
63
|
scaffoldFrontends({
|
|
56
64
|
frontendDirectories,
|
|
57
65
|
frontendDirectory,
|
package/dist/typeGuards.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
|
-
import type { AuthProvider, CodeQualityTool, DatabaseEngine, DatabaseHost, Frontend, ORM } from './types';
|
|
1
|
+
import type { AuthProvider, AvailableDrizzleDialect, CodeQualityTool, DatabaseEngine, DatabaseHost, Frontend, ORM } from './types';
|
|
2
2
|
export declare const isAuthProvider: (value: string | undefined) => value is AuthProvider;
|
|
3
3
|
export declare const isDirectoryConfig: (value: string) => value is "default" | "custom";
|
|
4
|
+
export declare const isDrizzleDialect: (value: string | undefined) => value is AvailableDrizzleDialect;
|
|
5
|
+
export declare const isPrismaDialect: (value: string | undefined) => value is string;
|
|
4
6
|
export declare const isDatabaseEngine: (value: string | undefined) => value is DatabaseEngine;
|
|
5
7
|
export declare const isDatabaseHost: (value: string | undefined) => value is DatabaseHost;
|
|
6
8
|
export declare const isORM: (value: string | undefined) => value is ORM;
|
package/dist/typeGuards.js
CHANGED
|
@@ -1,24 +1,10 @@
|
|
|
1
|
-
import { frontendLabels } from './data';
|
|
1
|
+
import { availableDatabaseEngines, availableDatabaseHosts, availableDrizzleDialects, availablePrismaDialects, frontendLabels } from './data';
|
|
2
2
|
export const isAuthProvider = (value) => value === 'absoluteAuth' || value === 'none' || value === undefined;
|
|
3
3
|
export const isDirectoryConfig = (value) => value === 'default' || value === 'custom';
|
|
4
|
-
export const
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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;
|
|
4
|
+
export const isDrizzleDialect = (value) => availableDrizzleDialects.some((dialect) => dialect === value);
|
|
5
|
+
export const isPrismaDialect = (value) => availablePrismaDialects.some((dialect) => dialect === value);
|
|
6
|
+
export const isDatabaseEngine = (value) => availableDatabaseEngines.some((engine) => engine === value);
|
|
7
|
+
export const isDatabaseHost = (value) => availableDatabaseHosts.some((host) => host === value);
|
|
22
8
|
export const isORM = (value) => value === 'drizzle' || value === 'prisma' || value === undefined;
|
|
23
9
|
export const isCodeQualityTool = (value) => value === 'eslint+prettier' || value === 'biome' || value === undefined;
|
|
24
10
|
export const isFrontend = (value) => value !== undefined && Object.keys(frontendLabels).includes(value);
|
package/dist/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { availableAuthProviders, availableCodeQualityTools, availableDatabaseEngines, availableDatabaseHosts, availableDirectoryConfigurations, availableFrontends, availableORMs } from './data';
|
|
1
|
+
import { availableAuthProviders, availableCodeQualityTools, availableDatabaseEngines, availableDatabaseHosts, availableDirectoryConfigurations, availableDrizzleDialects, availableFrontends, availableORMs, availablePrismaDialects } from './data';
|
|
2
2
|
export type ScaffoldFrontendProps = {
|
|
3
3
|
targetDirectory: string;
|
|
4
4
|
templatesDirectory: string;
|
|
@@ -22,6 +22,8 @@ export type AvailableDependency = {
|
|
|
22
22
|
};
|
|
23
23
|
export type PackageManager = 'npm' | 'pnpm' | 'yarn' | 'bun';
|
|
24
24
|
export type AuthProvider = (typeof availableAuthProviders)[number] | undefined;
|
|
25
|
+
export type AvailableDrizzleDialect = (typeof availableDrizzleDialects)[number];
|
|
26
|
+
export type AvailablePrismaDialect = (typeof availablePrismaDialects)[number];
|
|
25
27
|
export type DatabaseEngine = (typeof availableDatabaseEngines)[number] | undefined;
|
|
26
28
|
export type DatabaseHost = (typeof availableDatabaseHosts)[number] | undefined;
|
|
27
29
|
export type DirectoryConfiguration = (typeof availableDirectoryConfigurations)[number];
|