create-absolutejs 0.10.3 → 0.12.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 +11 -0
- package/dist/generators/angular/generateAngularPage.js +174 -0
- package/dist/generators/angular/scaffoldAngular.d.ts +2 -0
- package/dist/generators/angular/scaffoldAngular.js +38 -0
- package/dist/generators/configurations/generatePackageJson.js +28 -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 +3 -3
- package/dist/generators/html/scaffoldHTML.d.ts +1 -1
- package/dist/generators/html/scaffoldHTML.js +4 -6
- package/dist/generators/htmx/generateHTMXPage.d.ts +1 -1
- package/dist/generators/htmx/generateHTMXPage.js +3 -3
- package/dist/generators/htmx/scaffoldHTMX.d.ts +1 -1
- package/dist/generators/htmx/scaffoldHTMX.js +4 -6
- 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 +12 -7
- package/dist/generators/project/generateDBBlock.js +6 -0
- package/dist/generators/project/generateImportsBlock.d.ts +1 -2
- package/dist/generators/project/generateImportsBlock.js +48 -50
- package/dist/generators/project/generateMarkupCSS.d.ts +1 -1
- package/dist/generators/project/generateMarkupCSS.js +5 -1
- package/dist/generators/project/generateRoutesBlock.d.ts +1 -4
- package/dist/generators/project/generateRoutesBlock.js +44 -38
- package/dist/generators/project/generateServer.js +5 -12
- package/dist/generators/project/scaffoldFrontends.js +40 -4
- 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 +4 -6
- 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 +4 -6
- package/dist/generators/vue/generateVuePage.d.ts +1 -1
- package/dist/generators/vue/generateVuePage.js +2 -229
- package/dist/generators/vue/scaffoldVue.d.ts +1 -1
- package/dist/generators/vue/scaffoldVue.js +6 -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 +3 -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 +38 -29
- package/dist/versions.js +49 -39
- package/package.json +10 -9
- /package/dist/templates/configurations/{eslint.config.mjs → eslint.config.example.mjs} +0 -0
|
@@ -34,6 +34,11 @@ export const generateDatabaseTypes = ({ databaseEngine, databaseHost, authOption
|
|
|
34
34
|
dbTypeLine =
|
|
35
35
|
'export type DatabaseType = Mysql2Database<SchemaType>;';
|
|
36
36
|
break;
|
|
37
|
+
case 'mssql':
|
|
38
|
+
dbImport = `import { NodeMssqlDatabase } from 'drizzle-orm/node-mssql';`;
|
|
39
|
+
dbTypeLine =
|
|
40
|
+
'export type DatabaseType = NodeMssqlDatabase<SchemaType>;';
|
|
41
|
+
break;
|
|
37
42
|
case 'postgresql':
|
|
38
43
|
dbImport = `import { BunSQLDatabase } from 'drizzle-orm/bun-sql';`;
|
|
39
44
|
dbTypeLine =
|
|
@@ -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, isSingleFrontend: boolean) => 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, isSingleFrontend) => {
|
|
3
3
|
const navLinks = frontends.map(formatNavLink).join('\n\t\t\t');
|
|
4
4
|
const initialCount = useHTMLScripts ? '0' : 'disabled';
|
|
5
5
|
const scriptTagBlock = useHTMLScripts
|
|
@@ -15,7 +15,7 @@ export const generateHTMLPage = (frontends, useHTMLScripts) => {
|
|
|
15
15
|
<link
|
|
16
16
|
rel="stylesheet"
|
|
17
17
|
type="text/css"
|
|
18
|
-
href="
|
|
18
|
+
href="${isSingleFrontend ? '../../' : '../../../'}styles/indexes/html-example.css"
|
|
19
19
|
/>
|
|
20
20
|
<link rel="icon" href="/assets/ico/favicon.ico" />
|
|
21
21
|
</head>
|
|
@@ -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, stylesIndexesDirectory }: 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, stylesIndexesDirectory }) => {
|
|
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, isSingleFrontend);
|
|
8
8
|
const pagesDirectory = join(targetDirectory, 'pages');
|
|
9
9
|
mkdirSync(pagesDirectory, { recursive: true });
|
|
10
10
|
const htmlFilePath = join(pagesDirectory, 'HTMLExample.html');
|
|
@@ -13,9 +13,7 @@ export const scaffoldHTML = ({ isSingleFrontend, targetDirectory, frontends, use
|
|
|
13
13
|
cpSync(join(templatesDirectory, 'html', 'scripts'), scriptsDirectory, {
|
|
14
14
|
recursive: true
|
|
15
15
|
});
|
|
16
|
-
const
|
|
17
|
-
|
|
18
|
-
const cssOutputFile = join(cssOutputDir, 'html-example.css');
|
|
19
|
-
const htmlCSS = generateMarkupCSS('html', '#e34f26', isSingleFrontend);
|
|
16
|
+
const cssOutputFile = join(stylesIndexesDirectory, 'html-example.css');
|
|
17
|
+
const htmlCSS = generateMarkupCSS('html', '#e34f26');
|
|
20
18
|
writeFileSync(cssOutputFile, htmlCSS, 'utf-8');
|
|
21
19
|
};
|
|
@@ -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>
|
|
@@ -11,7 +11,7 @@ export const generateHTMXPage = (isSingle, frontends) => {
|
|
|
11
11
|
<link
|
|
12
12
|
rel="stylesheet"
|
|
13
13
|
type="text/css"
|
|
14
|
-
href="
|
|
14
|
+
href="${isSingle ? '../../' : '../../../'}styles/indexes/htmx-example.css"
|
|
15
15
|
/>
|
|
16
16
|
<link rel="icon" href="/assets/ico/favicon.ico" />
|
|
17
17
|
<script src="${isSingle ? '' : '/htmx'}/htmx.min.js"></script>
|
|
@@ -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, stylesIndexesDirectory }: 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, stylesIndexesDirectory }) => {
|
|
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,14 +15,12 @@ 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');
|
|
22
22
|
writeFileSync(htmxFilePath, htmxPage, 'utf-8');
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const cssOutputFile = join(cssOutputDir, 'htmx-example.css');
|
|
26
|
-
const htmxCSS = generateMarkupCSS('htmx', '#3465a4', isSingleFrontend);
|
|
23
|
+
const cssOutputFile = join(stylesIndexesDirectory, 'htmx-example.css');
|
|
24
|
+
const htmxCSS = generateMarkupCSS('htmx', '#3465a4');
|
|
27
25
|
writeFileSync(cssOutputFile, htmxCSS, 'utf-8');
|
|
28
26
|
};
|
|
@@ -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,17 +1,22 @@
|
|
|
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}'`,
|
|
5
7
|
...Object.entries(frontendDirectories).map(([f, dir]) => `${f}Directory: 'src/frontend${dir ? `/${dir}` : ''}'`),
|
|
6
8
|
`publicDirectory: '${publicDirectory}'`,
|
|
9
|
+
`stylesConfig: 'src/styles/indexes'`,
|
|
7
10
|
tailwind ? `tailwind: ${JSON.stringify(tailwind)}` : ''
|
|
8
11
|
]
|
|
9
12
|
.filter(Boolean)
|
|
10
|
-
.join(',\n
|
|
11
|
-
|
|
12
|
-
${configEntries}
|
|
13
|
-
};
|
|
13
|
+
.join(',\n\t');
|
|
14
|
+
const configContent = `import { defineConfig } from '@absolutejs/absolute'
|
|
14
15
|
|
|
15
|
-
|
|
16
|
-
|
|
16
|
+
export default defineConfig({
|
|
17
|
+
\t${configEntries}
|
|
18
|
+
})
|
|
19
|
+
`;
|
|
20
|
+
writeFileSync(join(backendDirectory, '..', '..', 'absolute.config.ts'), configContent);
|
|
21
|
+
return `const { absolutejs, manifest } = await prepare()`;
|
|
17
22
|
};
|
|
@@ -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') {
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { AvailableDependency, CreateConfiguration } from '../../types';
|
|
2
2
|
import type { FrameworkFlags } from './computeFlags';
|
|
3
3
|
type GenerateImportsBlockProps = {
|
|
4
|
-
backendDirectory: string;
|
|
5
4
|
deps: AvailableDependency[];
|
|
6
5
|
flags: FrameworkFlags;
|
|
7
6
|
orm: CreateConfiguration['orm'];
|
|
@@ -10,5 +9,5 @@ type GenerateImportsBlockProps = {
|
|
|
10
9
|
databaseHost: CreateConfiguration['databaseHost'];
|
|
11
10
|
frontendDirectories: CreateConfiguration['frontendDirectories'];
|
|
12
11
|
};
|
|
13
|
-
export declare const generateImportsBlock: ({
|
|
12
|
+
export declare const generateImportsBlock: ({ deps, flags, orm, authOption, databaseEngine, databaseHost, frontendDirectories }: GenerateImportsBlockProps) => string;
|
|
14
13
|
export {};
|
|
@@ -1,42 +1,37 @@
|
|
|
1
|
-
import { mkdirSync, writeFileSync } from 'fs';
|
|
2
|
-
import { join } from 'path';
|
|
3
1
|
import { isDrizzleDialect } from '../../typeGuards';
|
|
4
|
-
export const generateImportsBlock = ({
|
|
2
|
+
export const generateImportsBlock = ({ deps, flags, orm, authOption, databaseEngine, databaseHost, frontendDirectories }) => {
|
|
5
3
|
const rawImports = [];
|
|
6
4
|
const pushHandler = (cond, name, pkg = '@absolutejs/absolute') => cond && rawImports.push(`import { ${name} } from '${pkg}'`);
|
|
5
|
+
pushHandler(flags.requiresAngular, 'handleAngularPageRequest', '@absolutejs/absolute/angular');
|
|
6
|
+
pushHandler(flags.requiresAngular, 'generateHeadElement');
|
|
7
7
|
pushHandler(flags.requiresHtml, 'handleHTMLPageRequest');
|
|
8
|
-
pushHandler(flags.requiresReact, 'handleReactPageRequest');
|
|
8
|
+
pushHandler(flags.requiresReact, 'handleReactPageRequest', '@absolutejs/absolute/react');
|
|
9
9
|
pushHandler(flags.requiresSvelte, 'handleSveltePageRequest', '@absolutejs/absolute/svelte');
|
|
10
10
|
pushHandler(flags.requiresVue, 'handleVuePageRequest', '@absolutejs/absolute/vue');
|
|
11
11
|
pushHandler(flags.requiresVue, 'generateHeadElement');
|
|
12
12
|
pushHandler(flags.requiresHtmx, 'handleHTMXPageRequest');
|
|
13
|
-
const nonFrameworkOnly = (flags.requiresHtml || flags.requiresHtmx) &&
|
|
14
|
-
!flags.requiresReact &&
|
|
15
|
-
!flags.requiresSvelte &&
|
|
16
|
-
!flags.requiresVue;
|
|
17
13
|
for (const dependency of deps) {
|
|
18
14
|
const importsList = dependency.imports ?? [];
|
|
19
|
-
|
|
20
|
-
? importsList.filter((imp) => imp.packageName !== 'asset')
|
|
21
|
-
: importsList;
|
|
22
|
-
if (relevantImports.length === 0)
|
|
15
|
+
if (importsList.length === 0)
|
|
23
16
|
continue;
|
|
24
|
-
rawImports.push(`import { ${
|
|
17
|
+
rawImports.push(`import { ${importsList
|
|
25
18
|
.map((imp) => imp.packageName)
|
|
26
19
|
.sort()
|
|
27
20
|
.join(', ')} } from '${dependency.value}'`);
|
|
28
21
|
}
|
|
29
|
-
rawImports.push(`import { env } from 'bun'`);
|
|
30
22
|
const buildExamplePath = (dir, file) => `../frontend${dir ? `/${dir}` : ''}/pages/${file}`;
|
|
31
23
|
const reactDir = frontendDirectories.react;
|
|
32
24
|
const svelteDir = frontendDirectories.svelte;
|
|
33
25
|
const vueDir = frontendDirectories.vue;
|
|
26
|
+
const angularDir = frontendDirectories.angular;
|
|
34
27
|
if (flags.requiresReact && reactDir !== undefined)
|
|
35
28
|
rawImports.push(`import { ReactExample } from '${buildExamplePath(reactDir, 'ReactExample')}'`);
|
|
36
29
|
if (flags.requiresSvelte && svelteDir !== undefined)
|
|
37
|
-
rawImports.push(`import SvelteExample from '${buildExamplePath(svelteDir, 'SvelteExample.svelte')}'`);
|
|
38
|
-
if (flags.requiresVue &&
|
|
39
|
-
rawImports.push(`import VueExample from '${buildExamplePath(vueDir, 'VueExample.vue')}'`);
|
|
30
|
+
rawImports.push(`import type SvelteExample from '${buildExamplePath(svelteDir, 'SvelteExample.svelte')}'`);
|
|
31
|
+
if (flags.requiresVue && vueDir !== undefined)
|
|
32
|
+
rawImports.push(`import type VueExample from '${buildExamplePath(vueDir, 'VueExample.vue')}'`);
|
|
33
|
+
if (flags.requiresAngular && angularDir !== undefined)
|
|
34
|
+
rawImports.push(`import type * as AngularExamplePage from '${buildExamplePath(angularDir, 'angular-example')}'`);
|
|
40
35
|
const connectorImports = {
|
|
41
36
|
neon: [`import { neon } from '@neondatabase/serverless'`],
|
|
42
37
|
planetscale: [`import { Client } from '@planetscale/database'`],
|
|
@@ -63,6 +58,19 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
63
58
|
: [`import { schema } from '../../db/schema'`])
|
|
64
59
|
]
|
|
65
60
|
};
|
|
61
|
+
const getPostgresqlOrmDatabaseImports = () => {
|
|
62
|
+
if (!isRemoteHost)
|
|
63
|
+
return [
|
|
64
|
+
`import { SQL } from 'bun'`,
|
|
65
|
+
`import { drizzle } from 'drizzle-orm/bun-sql'`
|
|
66
|
+
];
|
|
67
|
+
if (databaseHost === 'planetscale')
|
|
68
|
+
return [
|
|
69
|
+
`import { drizzle } from 'drizzle-orm/node-postgres'`,
|
|
70
|
+
`import { Pool } from 'pg'`
|
|
71
|
+
];
|
|
72
|
+
return [];
|
|
73
|
+
};
|
|
66
74
|
const ormDatabaseImports = {
|
|
67
75
|
drizzle: {
|
|
68
76
|
gel: [
|
|
@@ -73,23 +81,17 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
73
81
|
`import { drizzle } from 'drizzle-orm/mysql2'`,
|
|
74
82
|
`import { createPool } from 'mysql2/promise'`
|
|
75
83
|
],
|
|
84
|
+
mssql: [
|
|
85
|
+
`import { connect } from 'mssql'`,
|
|
86
|
+
`import { drizzle } from 'drizzle-orm/node-mssql'`
|
|
87
|
+
],
|
|
76
88
|
mysql: !isRemoteHost
|
|
77
89
|
? [
|
|
78
90
|
`import { drizzle } from 'drizzle-orm/mysql2'`,
|
|
79
91
|
`import { createPool } from 'mysql2/promise'`
|
|
80
92
|
]
|
|
81
93
|
: [],
|
|
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
|
-
: [],
|
|
94
|
+
postgresql: getPostgresqlOrmDatabaseImports(),
|
|
93
95
|
singlestore: [
|
|
94
96
|
`import { drizzle } from 'drizzle-orm/singlestore'`,
|
|
95
97
|
`import { createPool } from 'mysql2/promise'`
|
|
@@ -102,6 +104,22 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
102
104
|
: []
|
|
103
105
|
}
|
|
104
106
|
};
|
|
107
|
+
const getPostgresqlNoOrmImports = () => {
|
|
108
|
+
if (isRemoteHost && databaseHost === 'neon')
|
|
109
|
+
return [
|
|
110
|
+
...connectorImports[databaseHost],
|
|
111
|
+
`import { getEnv } from '@absolutejs/absolute'`
|
|
112
|
+
];
|
|
113
|
+
if (isRemoteHost && databaseHost === 'planetscale')
|
|
114
|
+
return [
|
|
115
|
+
`import { Pool } from 'pg'`,
|
|
116
|
+
`import { getEnv } from '@absolutejs/absolute'`
|
|
117
|
+
];
|
|
118
|
+
return [
|
|
119
|
+
`import { SQL } from 'bun'`,
|
|
120
|
+
`import { getEnv } from '@absolutejs/absolute'`
|
|
121
|
+
];
|
|
122
|
+
};
|
|
105
123
|
const noOrmImports = {
|
|
106
124
|
cockroachdb: [
|
|
107
125
|
`import { SQL } from 'bun'`,
|
|
@@ -132,20 +150,7 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
132
150
|
`import { SQL } from 'bun'`,
|
|
133
151
|
`import { getEnv } from '@absolutejs/absolute'`
|
|
134
152
|
],
|
|
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
|
-
],
|
|
153
|
+
postgresql: getPostgresqlNoOrmImports(),
|
|
149
154
|
singlestore: [
|
|
150
155
|
`import { createPool } from 'mysql2/promise'`,
|
|
151
156
|
`import { getEnv } from '@absolutejs/absolute'`
|
|
@@ -160,7 +165,7 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
160
165
|
if (orm === 'drizzle') {
|
|
161
166
|
rawImports.push(...ormImports[orm]);
|
|
162
167
|
}
|
|
163
|
-
if (orm
|
|
168
|
+
if (orm === 'drizzle' &&
|
|
164
169
|
isRemoteHost &&
|
|
165
170
|
!(databaseEngine === 'postgresql' && databaseHost === 'planetscale')) {
|
|
166
171
|
rawImports.push(...connectorImports[databaseHost], ...dialectImports[databaseHost]);
|
|
@@ -175,13 +180,6 @@ export const generateImportsBlock = ({ backendDirectory, deps, flags, orm, authO
|
|
|
175
180
|
rawImports.push(`import { absoluteAuthConfig } from './utils/absoluteAuthConfig'`, `import { t } from 'elysia'`, `import { authProviderOption, providers, userSessionIdTypebox, getStatus } from '@absolutejs/auth'`);
|
|
176
181
|
if (hasDatabase && (authOption === undefined || authOption === 'none'))
|
|
177
182
|
rawImports.push(`import { getCountHistory, createCountHistory } from './handlers/countHistoryHandlers'`, `import { t } from 'elysia'`);
|
|
178
|
-
if (flags.requiresVue && flags.requiresSvelte) {
|
|
179
|
-
const utilsDir = join(backendDirectory, 'utils');
|
|
180
|
-
mkdirSync(utilsDir, { recursive: true });
|
|
181
|
-
const vuePathForUtils = `../../frontend${vueDir ? `/${vueDir}` : ''}/pages/VueExample.vue`;
|
|
182
|
-
writeFileSync(join(utilsDir, 'vueImporter.ts'), `import VueExample from "${vuePathForUtils}"\n\nexport const vueImports = { VueExample } as const\n`);
|
|
183
|
-
rawImports.push(`import { vueImports } from './utils/vueImporter'`);
|
|
184
|
-
}
|
|
185
183
|
const importMap = new Map();
|
|
186
184
|
for (const stmt of rawImports) {
|
|
187
185
|
const match = stmt.match(/^import\s+(.+)\s+from\s+['"](.+)['"];?/);
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import { Frontend } from '../../types';
|
|
2
|
-
export declare const generateMarkupCSS: (frontend: Frontend, color: string
|
|
2
|
+
export declare const generateMarkupCSS: (frontend: Frontend, color: string) => string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export const generateMarkupCSS = (frontend, color
|
|
1
|
+
export const generateMarkupCSS = (frontend, color) => `@import url('../reset.css');
|
|
2
2
|
|
|
3
3
|
header {
|
|
4
4
|
align-items: center;
|
|
@@ -53,6 +53,10 @@ h1 {
|
|
|
53
53
|
filter: drop-shadow(0 0 2rem ${color});
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
button:hover {
|
|
57
|
+
border-color: ${color};
|
|
58
|
+
}
|
|
59
|
+
|
|
56
60
|
nav {
|
|
57
61
|
display: flex;
|
|
58
62
|
gap: 4rem;
|
|
@@ -1,11 +1,8 @@
|
|
|
1
1
|
import type { AuthOption, CreateConfiguration, FrontendDirectories } from '../../types';
|
|
2
|
-
import type { FrameworkFlags } from './computeFlags';
|
|
3
2
|
type GenerateRoutesBlockProps = {
|
|
4
3
|
databaseEngine: CreateConfiguration['databaseEngine'];
|
|
5
|
-
flags: FrameworkFlags;
|
|
6
4
|
frontendDirectories: FrontendDirectories;
|
|
7
5
|
authOption: AuthOption;
|
|
8
|
-
buildDirectory: string;
|
|
9
6
|
};
|
|
10
|
-
export declare const generateRoutesBlock: ({ databaseEngine,
|
|
7
|
+
export declare const generateRoutesBlock: ({ databaseEngine, frontendDirectories, authOption }: GenerateRoutesBlockProps) => string;
|
|
11
8
|
export {};
|