create-absolutejs 0.10.3 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/constants.d.ts +2 -2
- package/dist/constants.js +2 -2
- package/dist/data.d.ts +10 -10
- package/dist/data.js +88 -95
- package/dist/generators/angular/generateAngularPage.d.ts +7 -0
- package/dist/generators/angular/generateAngularPage.js +175 -0
- package/dist/generators/angular/scaffoldAngular.d.ts +2 -0
- package/dist/generators/angular/scaffoldAngular.js +34 -0
- package/dist/generators/configurations/generatePackageJson.js +26 -3
- package/dist/generators/configurations/scaffoldConfigurationFiles.js +26 -2
- package/dist/generators/db/dockerInitTemplates.d.ts +9 -9
- package/dist/generators/db/dockerInitTemplates.js +9 -9
- package/dist/generators/db/generateDatabaseTypes.js +5 -0
- package/dist/generators/db/generateDockerContainer.js +4 -2
- package/dist/generators/db/generateDrizzleSchema.js +16 -6
- package/dist/generators/db/handlerTemplates.d.ts +5 -0
- package/dist/generators/db/handlerTemplates.js +6 -0
- package/dist/generators/db/scaffoldDocker.js +42 -30
- package/dist/generators/html/generateHTMLPage.d.ts +1 -1
- package/dist/generators/html/generateHTMLPage.js +2 -2
- package/dist/generators/html/scaffoldHTML.d.ts +1 -1
- package/dist/generators/html/scaffoldHTML.js +2 -2
- package/dist/generators/htmx/generateHTMXPage.d.ts +1 -1
- package/dist/generators/htmx/generateHTMXPage.js +2 -2
- package/dist/generators/htmx/scaffoldHTMX.d.ts +1 -1
- package/dist/generators/htmx/scaffoldHTMX.js +2 -2
- package/dist/generators/project/computeFlags.d.ts +1 -0
- package/dist/generators/project/computeFlags.js +1 -0
- package/dist/generators/project/generateBuildBlock.d.ts +2 -1
- package/dist/generators/project/generateBuildBlock.js +11 -7
- package/dist/generators/project/generateDBBlock.js +6 -0
- package/dist/generators/project/generateImportsBlock.js +39 -27
- package/dist/generators/project/generateMarkupCSS.js +4 -0
- package/dist/generators/project/generateRoutesBlock.d.ts +1 -2
- package/dist/generators/project/generateRoutesBlock.js +28 -17
- package/dist/generators/project/generateServer.js +5 -10
- package/dist/generators/project/scaffoldFrontends.js +20 -1
- package/dist/generators/react/generateReactComponents.d.ts +2 -2
- package/dist/generators/react/generateReactComponents.js +33 -33
- package/dist/generators/react/scaffoldReact.d.ts +1 -1
- package/dist/generators/react/scaffoldReact.js +2 -2
- package/dist/generators/svelte/generateSveltePage.d.ts +1 -1
- package/dist/generators/svelte/generateSveltePage.js +20 -2
- package/dist/generators/svelte/scaffoldSvelte.d.ts +1 -1
- package/dist/generators/svelte/scaffoldSvelte.js +2 -2
- package/dist/generators/vue/generateVuePage.d.ts +1 -1
- package/dist/generators/vue/generateVuePage.js +20 -2
- package/dist/generators/vue/scaffoldVue.d.ts +1 -1
- package/dist/generators/vue/scaffoldVue.js +2 -2
- package/dist/questions/databaseEngine.d.ts +1 -1
- package/dist/questions/frontendDirectoryConfigurations.d.ts +1 -1
- package/dist/questions/frontends.d.ts +1 -1
- package/dist/questions/frontends.js +3 -3
- package/dist/scaffold.js +14 -2
- package/dist/templates/assets/svg/angular.svg +18 -0
- package/dist/templates/configurations/tsconfig.example.json +12 -12
- package/dist/templates/react/components/App.tsx +2 -2
- package/dist/templates/react/components/Head.tsx +7 -7
- package/dist/templates/react/components/OAuthLink.tsx +2 -2
- package/dist/templates/styles/colors.ts +6 -8
- package/dist/templates/styles/reset.css +15 -0
- package/dist/templates/svelte/components/Counter.svelte +4 -0
- package/dist/templates/vue/components/CountButton.vue +1 -1
- package/dist/typeGuards.d.ts +6 -6
- package/dist/typeGuards.js +6 -6
- package/dist/types.d.ts +1 -0
- package/dist/utils/checkDockerInstalled.d.ts +4 -4
- package/dist/utils/checkDockerInstalled.js +78 -71
- package/dist/utils/parseCommandLineOptions.js +13 -16
- package/dist/versions.d.ts +37 -29
- package/dist/versions.js +48 -39
- package/package.json +10 -9
- /package/dist/templates/configurations/{eslint.config.mjs → eslint.config.example.mjs} +0 -0
|
@@ -104,6 +104,7 @@ const templates = {
|
|
|
104
104
|
test: 'singlestore -u root -ppassword -e "SELECT 1" >/dev/null 2>&1'
|
|
105
105
|
},
|
|
106
106
|
image: 'ghcr.io/singlestore-labs/singlestoredb-dev', // NOTE: No tag specified due to data persistence
|
|
107
|
+
platform: 'linux/amd64', // Required for ARM64 (Apple Silicon); no-op on amd64
|
|
107
108
|
port: '3306:3306',
|
|
108
109
|
volumePath: '/data'
|
|
109
110
|
}
|
|
@@ -114,14 +115,15 @@ export const generateDockerContainer = (databaseEngine) => {
|
|
|
114
115
|
databaseEngine === 'sqlite') {
|
|
115
116
|
throw new Error('Internal type error: Expected a valid local database engine');
|
|
116
117
|
}
|
|
117
|
-
const { command, env, healthcheck, image, port, volumePath } = templates[databaseEngine];
|
|
118
|
+
const { command, env, healthcheck, image, platform, port, volumePath } = templates[databaseEngine];
|
|
118
119
|
const commandLine = command ? `\n command: ${command}` : '';
|
|
120
|
+
const platformLine = platform ? `\n platform: ${platform}` : '';
|
|
119
121
|
const envLines = Object.entries(env)
|
|
120
122
|
.map(([key, value]) => ` ${key}: ${value}`)
|
|
121
123
|
.join('\n');
|
|
122
124
|
return `services:
|
|
123
125
|
db:
|
|
124
|
-
image: ${image}
|
|
126
|
+
image: ${image}${platformLine}
|
|
125
127
|
restart: always
|
|
126
128
|
environment:
|
|
127
129
|
${envLines}
|
|
@@ -15,6 +15,14 @@ const DIALECTS = {
|
|
|
15
15
|
table: 'mysqlTable',
|
|
16
16
|
time: 'timestamp()'
|
|
17
17
|
},
|
|
18
|
+
mssql: {
|
|
19
|
+
builders: ['datetime2', 'int', 'mssqlTable', 'nvarchar', 'json'],
|
|
20
|
+
json: "nvarchar({ length: 'max', mode: 'json' })",
|
|
21
|
+
pkg: 'mssql-core',
|
|
22
|
+
string: 'nvarchar({ length: 255 })',
|
|
23
|
+
table: 'mssqlTable',
|
|
24
|
+
time: 'datetime2()'
|
|
25
|
+
},
|
|
18
26
|
mysql: {
|
|
19
27
|
builders: ['json', 'mysqlTable', 'timestamp', 'varchar', 'int'],
|
|
20
28
|
json: 'json()',
|
|
@@ -51,9 +59,10 @@ const DIALECTS = {
|
|
|
51
59
|
const builder = (expr) => expr.split('(')[0];
|
|
52
60
|
export const generateDrizzleSchema = ({ databaseEngine, authOption }) => {
|
|
53
61
|
const cfg = DIALECTS[databaseEngine];
|
|
54
|
-
const intBuilder = databaseEngine === '
|
|
55
|
-
databaseEngine === '
|
|
56
|
-
databaseEngine === '
|
|
62
|
+
const intBuilder = databaseEngine === 'mariadb' ||
|
|
63
|
+
databaseEngine === 'mssql' ||
|
|
64
|
+
databaseEngine === 'mysql' ||
|
|
65
|
+
databaseEngine === 'singlestore'
|
|
57
66
|
? 'int'
|
|
58
67
|
: 'integer';
|
|
59
68
|
const timeBuilder = builder(cfg.time);
|
|
@@ -68,9 +77,10 @@ export const generateDrizzleSchema = ({ databaseEngine, authOption }) => {
|
|
|
68
77
|
? `import { sql } from 'drizzle-orm';\n`
|
|
69
78
|
: '';
|
|
70
79
|
let uidColumn;
|
|
71
|
-
if (databaseEngine === '
|
|
72
|
-
databaseEngine === '
|
|
73
|
-
databaseEngine === '
|
|
80
|
+
if (databaseEngine === 'mariadb' ||
|
|
81
|
+
databaseEngine === 'mssql' ||
|
|
82
|
+
databaseEngine === 'mysql' ||
|
|
83
|
+
databaseEngine === 'singlestore') {
|
|
74
84
|
uidColumn = `${intBuilder}('uid').primaryKey().autoincrement()`;
|
|
75
85
|
}
|
|
76
86
|
else if (databaseEngine === 'sqlite') {
|
|
@@ -35,6 +35,11 @@ declare const driverConfigurations: {
|
|
|
35
35
|
readonly importLines: "";
|
|
36
36
|
readonly queries: QueryOperations;
|
|
37
37
|
};
|
|
38
|
+
readonly 'mssql:drizzle:local': {
|
|
39
|
+
readonly dbType: "NodeMssqlDatabase<SchemaType>";
|
|
40
|
+
readonly importLines: "import { eq } from 'drizzle-orm'\nimport { schema } from '../../../db/schema'";
|
|
41
|
+
readonly queries: QueryOperations;
|
|
42
|
+
};
|
|
38
43
|
readonly 'mssql:sql:local': {
|
|
39
44
|
readonly dbType: "ConnectionPool";
|
|
40
45
|
readonly importLines: "";
|
|
@@ -353,6 +353,12 @@ import { schema } from '../../../db/schema'`,
|
|
|
353
353
|
importLines: ``,
|
|
354
354
|
queries: mongodbQueryOperations
|
|
355
355
|
},
|
|
356
|
+
'mssql:drizzle:local': {
|
|
357
|
+
dbType: 'NodeMssqlDatabase<SchemaType>',
|
|
358
|
+
importLines: `import { eq } from 'drizzle-orm'
|
|
359
|
+
import { schema } from '../../../db/schema'`,
|
|
360
|
+
queries: drizzleQueryOperations
|
|
361
|
+
},
|
|
356
362
|
'mssql:sql:local': {
|
|
357
363
|
dbType: 'ConnectionPool',
|
|
358
364
|
importLines: ``,
|
|
@@ -6,6 +6,33 @@ import { green, red } from 'picocolors';
|
|
|
6
6
|
import { checkDockerInstalled, ensureDockerDaemonRunning, resolveDockerExe, shutdownDockerDaemon } from '../../utils/checkDockerInstalled';
|
|
7
7
|
import { countHistoryTables, initTemplates, userTables } from './dockerInitTemplates';
|
|
8
8
|
import { generateDockerContainer } from './generateDockerContainer';
|
|
9
|
+
const initDockerSchema = async ({ authOption, databaseEngine, docker, projectName, spin }) => {
|
|
10
|
+
const dbKey = databaseEngine;
|
|
11
|
+
const { wait, cli } = initTemplates[dbKey];
|
|
12
|
+
const usesAuth = authOption !== undefined && authOption !== 'none';
|
|
13
|
+
const dbCommand = usesAuth ? userTables[dbKey] : countHistoryTables[dbKey];
|
|
14
|
+
await $ `${docker} compose -p ${databaseEngine} -f db/docker-compose.db.yml up -d db`
|
|
15
|
+
.cwd(projectName)
|
|
16
|
+
.quiet();
|
|
17
|
+
spin.message(`Initializing ${databaseEngine} schema`);
|
|
18
|
+
await $ `${docker} compose -p ${databaseEngine} -f db/docker-compose.db.yml exec -T db \
|
|
19
|
+
bash -lc '${wait} && ${cli} "${dbCommand}"'`
|
|
20
|
+
.cwd(projectName)
|
|
21
|
+
.quiet();
|
|
22
|
+
spin.message(`Stopping ${databaseEngine} container`);
|
|
23
|
+
await $ `${docker} compose -p ${databaseEngine} -f db/docker-compose.db.yml down`
|
|
24
|
+
.cwd(projectName)
|
|
25
|
+
.quiet();
|
|
26
|
+
};
|
|
27
|
+
const verifyDockerContainer = async ({ databaseEngine, docker, projectName, spin }) => {
|
|
28
|
+
await $ `${docker} compose -p ${databaseEngine} -f db/docker-compose.db.yml up -d --wait db`
|
|
29
|
+
.cwd(projectName)
|
|
30
|
+
.quiet();
|
|
31
|
+
spin.message(`Stopping ${databaseEngine} container`);
|
|
32
|
+
await $ `${docker} compose -p ${databaseEngine} -f db/docker-compose.db.yml down`
|
|
33
|
+
.cwd(projectName)
|
|
34
|
+
.quiet();
|
|
35
|
+
};
|
|
9
36
|
export const scaffoldDocker = async ({ databaseEngine, projectDatabaseDirectory, projectName, authOption }) => {
|
|
10
37
|
if (databaseEngine === undefined ||
|
|
11
38
|
databaseEngine === 'none' ||
|
|
@@ -19,37 +46,22 @@ export const scaffoldDocker = async ({ databaseEngine, projectDatabaseDirectory,
|
|
|
19
46
|
const docker = resolveDockerExe();
|
|
20
47
|
const spin = spinner();
|
|
21
48
|
spin.start(`Starting ${databaseEngine} container`);
|
|
49
|
+
const dockerAction = databaseEngine in userTables
|
|
50
|
+
? () => initDockerSchema({
|
|
51
|
+
authOption,
|
|
52
|
+
databaseEngine,
|
|
53
|
+
docker,
|
|
54
|
+
projectName,
|
|
55
|
+
spin
|
|
56
|
+
})
|
|
57
|
+
: () => verifyDockerContainer({
|
|
58
|
+
databaseEngine,
|
|
59
|
+
docker,
|
|
60
|
+
projectName,
|
|
61
|
+
spin
|
|
62
|
+
});
|
|
22
63
|
try {
|
|
23
|
-
|
|
24
|
-
if (hasSchemaInit) {
|
|
25
|
-
const dbKey = databaseEngine;
|
|
26
|
-
const { wait, cli } = initTemplates[dbKey];
|
|
27
|
-
const usesAuth = authOption !== undefined && authOption !== 'none';
|
|
28
|
-
const dbCommand = usesAuth
|
|
29
|
-
? userTables[dbKey]
|
|
30
|
-
: countHistoryTables[dbKey];
|
|
31
|
-
await $ `${docker} compose -p ${databaseEngine} -f db/docker-compose.db.yml up -d db`
|
|
32
|
-
.cwd(projectName)
|
|
33
|
-
.quiet();
|
|
34
|
-
spin.message(`Initializing ${databaseEngine} schema`);
|
|
35
|
-
await $ `${docker} compose -p ${databaseEngine} -f db/docker-compose.db.yml exec -T db \
|
|
36
|
-
bash -lc '${wait} && ${cli} "${dbCommand}"'`
|
|
37
|
-
.cwd(projectName)
|
|
38
|
-
.quiet();
|
|
39
|
-
spin.message(`Stopping ${databaseEngine} container`);
|
|
40
|
-
await $ `${docker} compose -p ${databaseEngine} -f db/docker-compose.db.yml down`
|
|
41
|
-
.cwd(projectName)
|
|
42
|
-
.quiet();
|
|
43
|
-
}
|
|
44
|
-
else {
|
|
45
|
-
await $ `${docker} compose -p ${databaseEngine} -f db/docker-compose.db.yml up -d --wait db`
|
|
46
|
-
.cwd(projectName)
|
|
47
|
-
.quiet();
|
|
48
|
-
spin.message(`Stopping ${databaseEngine} container`);
|
|
49
|
-
await $ `${docker} compose -p ${databaseEngine} -f db/docker-compose.db.yml down`
|
|
50
|
-
.cwd(projectName)
|
|
51
|
-
.quiet();
|
|
52
|
-
}
|
|
64
|
+
await dockerAction();
|
|
53
65
|
spin.stop(green('Docker container verified'));
|
|
54
66
|
}
|
|
55
67
|
catch (err) {
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { CreateConfiguration, Frontend } from '../../types';
|
|
2
|
-
export declare const generateHTMLPage: (frontends: Frontend[], useHTMLScripts: CreateConfiguration["useHTMLScripts"]) => string;
|
|
2
|
+
export declare const generateHTMLPage: (frontends: Frontend[], useHTMLScripts: CreateConfiguration["useHTMLScripts"], editBasePath: string) => string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { formatNavLink } from '../../utils/formatNavLink';
|
|
2
|
-
export const generateHTMLPage = (frontends, useHTMLScripts) => {
|
|
2
|
+
export const generateHTMLPage = (frontends, useHTMLScripts, editBasePath) => {
|
|
3
3
|
const navLinks = frontends.map(formatNavLink).join('\n\t\t\t');
|
|
4
4
|
const initialCount = useHTMLScripts ? '0' : 'disabled';
|
|
5
5
|
const scriptTagBlock = useHTMLScripts
|
|
@@ -54,7 +54,7 @@ export const generateHTMLPage = (frontends, useHTMLScripts) => {
|
|
|
54
54
|
count is <span id="counter">${initialCount}</span>
|
|
55
55
|
</button>
|
|
56
56
|
<p>
|
|
57
|
-
Edit <code
|
|
57
|
+
Edit <code>${editBasePath}/pages/HTMLExample.html</code> and save
|
|
58
58
|
to test HMR.
|
|
59
59
|
</p>
|
|
60
60
|
${frontends.length > 1
|
|
@@ -2,5 +2,5 @@ import { ScaffoldFrontendProps } from '../../types';
|
|
|
2
2
|
type ScaffoldHTMLProps = ScaffoldFrontendProps & {
|
|
3
3
|
useHTMLScripts: boolean;
|
|
4
4
|
};
|
|
5
|
-
export declare const scaffoldHTML: ({ isSingleFrontend, targetDirectory, frontends, useHTMLScripts, templatesDirectory, projectAssetsDirectory }: ScaffoldHTMLProps) => void;
|
|
5
|
+
export declare const scaffoldHTML: ({ editBasePath, isSingleFrontend, targetDirectory, frontends, useHTMLScripts, templatesDirectory, projectAssetsDirectory }: ScaffoldHTMLProps) => void;
|
|
6
6
|
export {};
|
|
@@ -2,9 +2,9 @@ import { copyFileSync, cpSync, mkdirSync, writeFileSync } from 'fs';
|
|
|
2
2
|
import { join } from 'path';
|
|
3
3
|
import { generateMarkupCSS } from '../project/generateMarkupCSS';
|
|
4
4
|
import { generateHTMLPage } from './generateHTMLPage';
|
|
5
|
-
export const scaffoldHTML = ({ isSingleFrontend, targetDirectory, frontends, useHTMLScripts, templatesDirectory, projectAssetsDirectory }) => {
|
|
5
|
+
export const scaffoldHTML = ({ editBasePath, isSingleFrontend, targetDirectory, frontends, useHTMLScripts, templatesDirectory, projectAssetsDirectory }) => {
|
|
6
6
|
copyFileSync(join(templatesDirectory, 'assets', 'svg', 'HTML5_Badge.svg'), join(projectAssetsDirectory, 'svg', 'HTML5_Badge.svg'));
|
|
7
|
-
const htmlPage = generateHTMLPage(frontends, useHTMLScripts);
|
|
7
|
+
const htmlPage = generateHTMLPage(frontends, useHTMLScripts, editBasePath);
|
|
8
8
|
const pagesDirectory = join(targetDirectory, 'pages');
|
|
9
9
|
mkdirSync(pagesDirectory, { recursive: true });
|
|
10
10
|
const htmlFilePath = join(pagesDirectory, 'HTMLExample.html');
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Frontend } from '../../types';
|
|
2
|
-
export declare const generateHTMXPage: (isSingle: boolean, frontends: Frontend[]) => string;
|
|
2
|
+
export declare const generateHTMXPage: (isSingle: boolean, frontends: Frontend[], editBasePath: string) => string;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { formatNavLink } from '../../utils/formatNavLink';
|
|
2
|
-
export const generateHTMXPage = (isSingle, frontends) => {
|
|
2
|
+
export const generateHTMXPage = (isSingle, frontends, editBasePath) => {
|
|
3
3
|
const navLinks = frontends.map(formatNavLink).join('\n\t\t\t');
|
|
4
4
|
return `<!doctype html>
|
|
5
5
|
<html>
|
|
@@ -73,7 +73,7 @@ export const generateHTMXPage = (isSingle, frontends) => {
|
|
|
73
73
|
>
|
|
74
74
|
</button>
|
|
75
75
|
<p>
|
|
76
|
-
Edit <code
|
|
76
|
+
Edit <code>${editBasePath}/pages/HTMXExample.html</code> and save
|
|
77
77
|
to test HMR.
|
|
78
78
|
</p>
|
|
79
79
|
${frontends.length > 1
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { ScaffoldFrontendProps } from '../../types';
|
|
2
|
-
export declare const scaffoldHTMX: ({ targetDirectory, templatesDirectory, projectAssetsDirectory, frontends, isSingleFrontend }: ScaffoldFrontendProps) => void;
|
|
2
|
+
export declare const scaffoldHTMX: ({ editBasePath, targetDirectory, templatesDirectory, projectAssetsDirectory, frontends, isSingleFrontend }: ScaffoldFrontendProps) => void;
|
|
@@ -3,7 +3,7 @@ import { join } from 'path';
|
|
|
3
3
|
import { Glob } from 'bun';
|
|
4
4
|
import { generateMarkupCSS } from '../project/generateMarkupCSS';
|
|
5
5
|
import { generateHTMXPage } from './generateHTMXPage';
|
|
6
|
-
export const scaffoldHTMX = ({ targetDirectory, templatesDirectory, projectAssetsDirectory, frontends, isSingleFrontend }) => {
|
|
6
|
+
export const scaffoldHTMX = ({ editBasePath, targetDirectory, templatesDirectory, projectAssetsDirectory, frontends, isSingleFrontend }) => {
|
|
7
7
|
copyFileSync(join(templatesDirectory, 'assets', 'svg', 'htmx-logo-black.svg'), join(projectAssetsDirectory, 'svg', 'htmx-logo-black.svg'));
|
|
8
8
|
copyFileSync(join(templatesDirectory, 'assets', 'svg', 'htmx-logo-white.svg'), join(projectAssetsDirectory, 'svg', 'htmx-logo-white.svg'));
|
|
9
9
|
const glob = new Glob('htmx*.min.js');
|
|
@@ -15,7 +15,7 @@ export const scaffoldHTMX = ({ targetDirectory, templatesDirectory, projectAsset
|
|
|
15
15
|
copyFileSync(src, dest);
|
|
16
16
|
break;
|
|
17
17
|
}
|
|
18
|
-
const htmxPage = generateHTMXPage(isSingleFrontend, frontends);
|
|
18
|
+
const htmxPage = generateHTMXPage(isSingleFrontend, frontends, editBasePath);
|
|
19
19
|
const pagesDirectory = join(targetDirectory, 'pages');
|
|
20
20
|
mkdirSync(pagesDirectory, { recursive: true });
|
|
21
21
|
const htmxFilePath = join(pagesDirectory, 'HTMXExample.html');
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { FrontendDirectories } from '../../types';
|
|
2
2
|
export type FrameworkFlags = ReturnType<typeof computeFlags>;
|
|
3
3
|
export declare const computeFlags: (dirs: FrontendDirectories) => {
|
|
4
|
+
requiresAngular: boolean;
|
|
4
5
|
requiresHtml: boolean;
|
|
5
6
|
requiresHtmx: boolean;
|
|
6
7
|
requiresReact: boolean;
|
|
@@ -1,10 +1,11 @@
|
|
|
1
1
|
import type { CreateConfiguration, FrontendDirectories } from '../../types';
|
|
2
2
|
type GenerateBuildBlockProps = {
|
|
3
3
|
assetsDirectory: string;
|
|
4
|
+
backendDirectory: string;
|
|
4
5
|
buildDirectory: string;
|
|
5
6
|
frontendDirectories: FrontendDirectories;
|
|
6
7
|
publicDirectory: string;
|
|
7
8
|
tailwind: CreateConfiguration['tailwind'];
|
|
8
9
|
};
|
|
9
|
-
export declare const generateBuildBlock: ({ assetsDirectory, buildDirectory, frontendDirectories, publicDirectory, tailwind }: GenerateBuildBlockProps) => string;
|
|
10
|
+
export declare const generateBuildBlock: ({ assetsDirectory, backendDirectory, buildDirectory, frontendDirectories, publicDirectory, tailwind }: GenerateBuildBlockProps) => string;
|
|
10
11
|
export {};
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
|
|
1
|
+
import { writeFileSync } from 'fs';
|
|
2
|
+
import { join } from 'path';
|
|
3
|
+
export const generateBuildBlock = ({ assetsDirectory, backendDirectory, buildDirectory, frontendDirectories, publicDirectory, tailwind }) => {
|
|
2
4
|
const configEntries = [
|
|
3
5
|
`assetsDirectory: '${assetsDirectory}'`,
|
|
4
6
|
`buildDirectory: '${buildDirectory}'`,
|
|
@@ -7,11 +9,13 @@ export const generateBuildBlock = ({ assetsDirectory, buildDirectory, frontendDi
|
|
|
7
9
|
tailwind ? `tailwind: ${JSON.stringify(tailwind)}` : ''
|
|
8
10
|
]
|
|
9
11
|
.filter(Boolean)
|
|
10
|
-
.join(',\n
|
|
11
|
-
|
|
12
|
-
${configEntries}
|
|
13
|
-
};
|
|
12
|
+
.join(',\n\t');
|
|
13
|
+
const configContent = `import { defineConfig } from '@absolutejs/absolute'
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
export default defineConfig({
|
|
16
|
+
\t${configEntries}
|
|
17
|
+
})
|
|
18
|
+
`;
|
|
19
|
+
writeFileSync(join(backendDirectory, '..', '..', 'absolute.config.ts'), configContent);
|
|
20
|
+
return `const { absolutejs, manifest } = await prepare()`;
|
|
17
21
|
};
|
|
@@ -64,6 +64,12 @@ export const generateDBBlock = ({ databaseEngine, orm, databaseHost }) => {
|
|
|
64
64
|
return `
|
|
65
65
|
const pool = createPool(getEnv("DATABASE_URL"))
|
|
66
66
|
const db = drizzle(pool, { schema, mode: 'default' })
|
|
67
|
+
`;
|
|
68
|
+
}
|
|
69
|
+
if (databaseEngine === 'mssql' && hostKey === 'none') {
|
|
70
|
+
return `
|
|
71
|
+
const pool = await connect(getEnv("DATABASE_URL"))
|
|
72
|
+
const db = drizzle({ client: pool }, { schema })
|
|
67
73
|
`;
|
|
68
74
|
}
|
|
69
75
|
if (databaseEngine === 'postgresql' && databaseHost === 'neon') {
|
|
@@ -4,6 +4,8 @@ import { isDrizzleDialect } from '../../typeGuards';
|
|
|
4
4
|
export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authOption, databaseEngine, databaseHost, frontendDirectories }) => {
|
|
5
5
|
const rawImports = [];
|
|
6
6
|
const pushHandler = (cond, name, pkg = '@absolutejs/absolute') => cond && rawImports.push(`import { ${name} } from '${pkg}'`);
|
|
7
|
+
pushHandler(flags.requiresAngular, 'handleAngularPageRequest', '@absolutejs/absolute/angular');
|
|
8
|
+
pushHandler(flags.requiresAngular, 'generateHeadElement');
|
|
7
9
|
pushHandler(flags.requiresHtml, 'handleHTMLPageRequest');
|
|
8
10
|
pushHandler(flags.requiresReact, 'handleReactPageRequest');
|
|
9
11
|
pushHandler(flags.requiresSvelte, 'handleSveltePageRequest', '@absolutejs/absolute/svelte');
|
|
@@ -11,6 +13,7 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
11
13
|
pushHandler(flags.requiresVue, 'generateHeadElement');
|
|
12
14
|
pushHandler(flags.requiresHtmx, 'handleHTMXPageRequest');
|
|
13
15
|
const nonFrameworkOnly = (flags.requiresHtml || flags.requiresHtmx) &&
|
|
16
|
+
!flags.requiresAngular &&
|
|
14
17
|
!flags.requiresReact &&
|
|
15
18
|
!flags.requiresSvelte &&
|
|
16
19
|
!flags.requiresVue;
|
|
@@ -26,7 +29,6 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
26
29
|
.sort()
|
|
27
30
|
.join(', ')} } from '${dependency.value}'`);
|
|
28
31
|
}
|
|
29
|
-
rawImports.push(`import { env } from 'bun'`);
|
|
30
32
|
const buildExamplePath = (dir, file) => `../frontend${dir ? `/${dir}` : ''}/pages/${file}`;
|
|
31
33
|
const reactDir = frontendDirectories.react;
|
|
32
34
|
const svelteDir = frontendDirectories.svelte;
|
|
@@ -63,6 +65,19 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
63
65
|
: [`import { schema } from '../../db/schema'`])
|
|
64
66
|
]
|
|
65
67
|
};
|
|
68
|
+
const getPostgresqlOrmDatabaseImports = () => {
|
|
69
|
+
if (!isRemoteHost)
|
|
70
|
+
return [
|
|
71
|
+
`import { SQL } from 'bun'`,
|
|
72
|
+
`import { drizzle } from 'drizzle-orm/bun-sql'`
|
|
73
|
+
];
|
|
74
|
+
if (databaseHost === 'planetscale')
|
|
75
|
+
return [
|
|
76
|
+
`import { drizzle } from 'drizzle-orm/node-postgres'`,
|
|
77
|
+
`import { Pool } from 'pg'`
|
|
78
|
+
];
|
|
79
|
+
return [];
|
|
80
|
+
};
|
|
66
81
|
const ormDatabaseImports = {
|
|
67
82
|
drizzle: {
|
|
68
83
|
gel: [
|
|
@@ -73,23 +88,17 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
73
88
|
`import { drizzle } from 'drizzle-orm/mysql2'`,
|
|
74
89
|
`import { createPool } from 'mysql2/promise'`
|
|
75
90
|
],
|
|
91
|
+
mssql: [
|
|
92
|
+
`import { connect } from 'mssql'`,
|
|
93
|
+
`import { drizzle } from 'drizzle-orm/node-mssql'`
|
|
94
|
+
],
|
|
76
95
|
mysql: !isRemoteHost
|
|
77
96
|
? [
|
|
78
97
|
`import { drizzle } from 'drizzle-orm/mysql2'`,
|
|
79
98
|
`import { createPool } from 'mysql2/promise'`
|
|
80
99
|
]
|
|
81
100
|
: [],
|
|
82
|
-
postgresql:
|
|
83
|
-
? [
|
|
84
|
-
`import { SQL } from 'bun'`,
|
|
85
|
-
`import { drizzle } from 'drizzle-orm/bun-sql'`
|
|
86
|
-
]
|
|
87
|
-
: isRemoteHost && databaseHost === 'planetscale'
|
|
88
|
-
? [
|
|
89
|
-
`import { drizzle } from 'drizzle-orm/node-postgres'`,
|
|
90
|
-
`import { Pool } from 'pg'`
|
|
91
|
-
]
|
|
92
|
-
: [],
|
|
101
|
+
postgresql: getPostgresqlOrmDatabaseImports(),
|
|
93
102
|
singlestore: [
|
|
94
103
|
`import { drizzle } from 'drizzle-orm/singlestore'`,
|
|
95
104
|
`import { createPool } from 'mysql2/promise'`
|
|
@@ -102,6 +111,22 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
102
111
|
: []
|
|
103
112
|
}
|
|
104
113
|
};
|
|
114
|
+
const getPostgresqlNoOrmImports = () => {
|
|
115
|
+
if (isRemoteHost && databaseHost === 'neon')
|
|
116
|
+
return [
|
|
117
|
+
...connectorImports[databaseHost],
|
|
118
|
+
`import { getEnv } from '@absolutejs/absolute'`
|
|
119
|
+
];
|
|
120
|
+
if (isRemoteHost && databaseHost === 'planetscale')
|
|
121
|
+
return [
|
|
122
|
+
`import { Pool } from 'pg'`,
|
|
123
|
+
`import { getEnv } from '@absolutejs/absolute'`
|
|
124
|
+
];
|
|
125
|
+
return [
|
|
126
|
+
`import { SQL } from 'bun'`,
|
|
127
|
+
`import { getEnv } from '@absolutejs/absolute'`
|
|
128
|
+
];
|
|
129
|
+
};
|
|
105
130
|
const noOrmImports = {
|
|
106
131
|
cockroachdb: [
|
|
107
132
|
`import { SQL } from 'bun'`,
|
|
@@ -132,20 +157,7 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
132
157
|
`import { SQL } from 'bun'`,
|
|
133
158
|
`import { getEnv } from '@absolutejs/absolute'`
|
|
134
159
|
],
|
|
135
|
-
postgresql:
|
|
136
|
-
? [
|
|
137
|
-
...connectorImports[databaseHost],
|
|
138
|
-
`import { getEnv } from '@absolutejs/absolute'`
|
|
139
|
-
]
|
|
140
|
-
: isRemoteHost && databaseHost === 'planetscale'
|
|
141
|
-
? [
|
|
142
|
-
`import { Pool } from 'pg'`,
|
|
143
|
-
`import { getEnv } from '@absolutejs/absolute'`
|
|
144
|
-
]
|
|
145
|
-
: [
|
|
146
|
-
`import { SQL } from 'bun'`,
|
|
147
|
-
`import { getEnv } from '@absolutejs/absolute'`
|
|
148
|
-
],
|
|
160
|
+
postgresql: getPostgresqlNoOrmImports(),
|
|
149
161
|
singlestore: [
|
|
150
162
|
`import { createPool } from 'mysql2/promise'`,
|
|
151
163
|
`import { getEnv } from '@absolutejs/absolute'`
|
|
@@ -160,7 +172,7 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
160
172
|
if (orm === 'drizzle') {
|
|
161
173
|
rawImports.push(...ormImports[orm]);
|
|
162
174
|
}
|
|
163
|
-
if (orm
|
|
175
|
+
if (orm === 'drizzle' &&
|
|
164
176
|
isRemoteHost &&
|
|
165
177
|
!(databaseEngine === 'postgresql' && databaseHost === 'planetscale')) {
|
|
166
178
|
rawImports.push(...connectorImports[databaseHost], ...dialectImports[databaseHost]);
|
|
@@ -5,7 +5,6 @@ type GenerateRoutesBlockProps = {
|
|
|
5
5
|
flags: FrameworkFlags;
|
|
6
6
|
frontendDirectories: FrontendDirectories;
|
|
7
7
|
authOption: AuthOption;
|
|
8
|
-
buildDirectory: string;
|
|
9
8
|
};
|
|
10
|
-
export declare const generateRoutesBlock: ({ databaseEngine, flags, frontendDirectories, authOption
|
|
9
|
+
export declare const generateRoutesBlock: ({ databaseEngine, flags, frontendDirectories, authOption }: GenerateRoutesBlockProps) => string;
|
|
11
10
|
export {};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { isFrontend } from '../../typeGuards';
|
|
2
|
-
export const generateRoutesBlock = ({ databaseEngine, flags, frontendDirectories, authOption
|
|
2
|
+
export const generateRoutesBlock = ({ databaseEngine, flags, frontendDirectories, authOption }) => {
|
|
3
3
|
const hasDatabase = databaseEngine !== undefined && databaseEngine !== 'none';
|
|
4
4
|
const routes = [];
|
|
5
|
-
const wrap = (handlerCall) => authOption === 'abs'
|
|
5
|
+
const wrap = (handlerCall, isAsync = false) => authOption === 'abs'
|
|
6
6
|
? `async ({ cookie: { auth_provider, user_session_id }, store: { session }, status }) => {
|
|
7
7
|
const { user, error } = await getStatus(session, user_session_id);
|
|
8
8
|
|
|
@@ -15,29 +15,39 @@ export const generateRoutesBlock = ({ databaseEngine, flags, frontendDirectories
|
|
|
15
15
|
|
|
16
16
|
return ${handlerCall};
|
|
17
17
|
}`
|
|
18
|
-
:
|
|
18
|
+
: `${isAsync ? 'async ' : ''}() => ${handlerCall}`;
|
|
19
19
|
const createHandlerCall = (frontend, directory) => {
|
|
20
|
-
|
|
20
|
+
if (frontend === 'angular')
|
|
21
|
+
return `handleAngularPageRequest(
|
|
22
|
+
() => import('../frontend${directory ? `/${directory}` : ''}/pages/angular-example'),
|
|
23
|
+
asset(manifest, 'AngularExample'),
|
|
24
|
+
asset(manifest, 'AngularExampleIndex'),
|
|
25
|
+
generateHeadElement({
|
|
26
|
+
cssPath: asset(manifest, 'AngularExampleCSS'),
|
|
27
|
+
title: 'AbsoluteJS + Angular'
|
|
28
|
+
}),
|
|
29
|
+
{ initialCount: 0 }
|
|
30
|
+
)`;
|
|
21
31
|
if (frontend === 'html')
|
|
22
|
-
return `handleHTMLPageRequest(
|
|
32
|
+
return `handleHTMLPageRequest(asset(manifest, 'HTMLExample'))`;
|
|
23
33
|
if (frontend === 'htmx')
|
|
24
|
-
return `handleHTMXPageRequest(
|
|
34
|
+
return `handleHTMXPageRequest(asset(manifest, 'HTMXExample'))`;
|
|
25
35
|
if (frontend === 'react') {
|
|
26
36
|
const reactProps = authOption === 'abs'
|
|
27
|
-
? `{ initialCount: 0, cssPath: asset(
|
|
28
|
-
: `{ initialCount: 0, cssPath: asset(
|
|
37
|
+
? `{ initialCount: 0, cssPath: asset(manifest, 'ReactExampleCSS'), user, providerConfiguration }`
|
|
38
|
+
: `{ initialCount: 0, cssPath: asset(manifest, 'ReactExampleCSS') }`;
|
|
29
39
|
return `handleReactPageRequest(
|
|
30
40
|
ReactExample,
|
|
31
|
-
asset(
|
|
41
|
+
asset(manifest, 'ReactExampleIndex'),
|
|
32
42
|
${reactProps}
|
|
33
43
|
)`;
|
|
34
44
|
}
|
|
35
45
|
if (frontend === 'svelte')
|
|
36
46
|
return `handleSveltePageRequest(
|
|
37
47
|
SvelteExample,
|
|
38
|
-
asset(
|
|
39
|
-
asset(
|
|
40
|
-
{ initialCount: 0, cssPath: asset(
|
|
48
|
+
asset(manifest, 'SvelteExample'),
|
|
49
|
+
asset(manifest, 'SvelteExampleIndex'),
|
|
50
|
+
{ initialCount: 0, cssPath: asset(manifest, 'SvelteExampleCSS') }
|
|
41
51
|
)`;
|
|
42
52
|
if (frontend === 'vue') {
|
|
43
53
|
const vueComponent = flags.requiresSvelte
|
|
@@ -45,10 +55,10 @@ export const generateRoutesBlock = ({ databaseEngine, flags, frontendDirectories
|
|
|
45
55
|
: 'VueExample';
|
|
46
56
|
return `handleVuePageRequest(
|
|
47
57
|
${vueComponent},
|
|
48
|
-
asset(
|
|
49
|
-
asset(
|
|
58
|
+
asset(manifest, 'VueExample'),
|
|
59
|
+
asset(manifest, 'VueExampleIndex'),
|
|
50
60
|
generateHeadElement({
|
|
51
|
-
cssPath: asset(
|
|
61
|
+
cssPath: asset(manifest, 'VueExampleCSS'),
|
|
52
62
|
title: 'AbsoluteJS + Vue',
|
|
53
63
|
description: 'A Vue.js example with AbsoluteJS'
|
|
54
64
|
}),
|
|
@@ -60,10 +70,11 @@ export const generateRoutesBlock = ({ databaseEngine, flags, frontendDirectories
|
|
|
60
70
|
Object.entries(frontendDirectories).forEach(([frontend, directory], entryIndex) => {
|
|
61
71
|
if (!isFrontend(frontend))
|
|
62
72
|
return;
|
|
63
|
-
const handlerCall = createHandlerCall(frontend, directory);
|
|
73
|
+
const handlerCall = createHandlerCall(frontend, directory ?? '');
|
|
64
74
|
if (!handlerCall)
|
|
65
75
|
return;
|
|
66
|
-
const
|
|
76
|
+
const isAsync = frontend === 'angular';
|
|
77
|
+
const handler = wrap(handlerCall, isAsync);
|
|
67
78
|
if (entryIndex === 0) {
|
|
68
79
|
routes.push(`.get('/', ${handler})`);
|
|
69
80
|
}
|
|
@@ -22,6 +22,7 @@ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirecto
|
|
|
22
22
|
});
|
|
23
23
|
const manifestBlock = generateBuildBlock({
|
|
24
24
|
assetsDirectory,
|
|
25
|
+
backendDirectory,
|
|
25
26
|
buildDirectory,
|
|
26
27
|
frontendDirectories,
|
|
27
28
|
publicDirectory,
|
|
@@ -59,31 +60,25 @@ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirecto
|
|
|
59
60
|
})`;
|
|
60
61
|
const routesBlock = generateRoutesBlock({
|
|
61
62
|
authOption,
|
|
62
|
-
buildDirectory,
|
|
63
63
|
databaseEngine,
|
|
64
64
|
flags,
|
|
65
65
|
frontendDirectories
|
|
66
66
|
});
|
|
67
|
-
const hmrBlock = `
|
|
68
|
-
if (
|
|
69
|
-
typeof result.hmrState !== 'string' &&
|
|
70
|
-
typeof result.manifest === 'object'
|
|
71
|
-
) {
|
|
72
|
-
server.use(hmr(result.hmrState, result.manifest));
|
|
73
|
-
}`;
|
|
74
67
|
const content = `${importsBlock}
|
|
75
68
|
|
|
76
69
|
${manifestBlock}
|
|
77
70
|
${dbBlock ? `${dbBlock}\n` : ''}
|
|
78
71
|
const server = new Elysia()
|
|
72
|
+
.use(absolutejs)
|
|
79
73
|
${useBlock}${authOption === 'abs' ? `\n${guardBlock}` : ''}
|
|
80
74
|
${routesBlock}
|
|
81
75
|
.use(networking)
|
|
82
76
|
.on('error', err => {
|
|
83
77
|
const { request } = err
|
|
84
78
|
console.error(\`Server error on \${request.method} \${request.url}: \${err.message}\`)
|
|
85
|
-
})
|
|
86
|
-
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
export type Server = typeof server
|
|
87
82
|
`;
|
|
88
83
|
writeFileSync(serverFilePath, content);
|
|
89
84
|
};
|