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.
Files changed (73) hide show
  1. package/dist/constants.d.ts +2 -2
  2. package/dist/constants.js +2 -2
  3. package/dist/data.d.ts +10 -10
  4. package/dist/data.js +88 -95
  5. package/dist/generators/angular/generateAngularPage.d.ts +7 -0
  6. package/dist/generators/angular/generateAngularPage.js +175 -0
  7. package/dist/generators/angular/scaffoldAngular.d.ts +2 -0
  8. package/dist/generators/angular/scaffoldAngular.js +34 -0
  9. package/dist/generators/configurations/generatePackageJson.js +26 -3
  10. package/dist/generators/configurations/scaffoldConfigurationFiles.js +26 -2
  11. package/dist/generators/db/dockerInitTemplates.d.ts +9 -9
  12. package/dist/generators/db/dockerInitTemplates.js +9 -9
  13. package/dist/generators/db/generateDatabaseTypes.js +5 -0
  14. package/dist/generators/db/generateDockerContainer.js +4 -2
  15. package/dist/generators/db/generateDrizzleSchema.js +16 -6
  16. package/dist/generators/db/handlerTemplates.d.ts +5 -0
  17. package/dist/generators/db/handlerTemplates.js +6 -0
  18. package/dist/generators/db/scaffoldDocker.js +42 -30
  19. package/dist/generators/html/generateHTMLPage.d.ts +1 -1
  20. package/dist/generators/html/generateHTMLPage.js +2 -2
  21. package/dist/generators/html/scaffoldHTML.d.ts +1 -1
  22. package/dist/generators/html/scaffoldHTML.js +2 -2
  23. package/dist/generators/htmx/generateHTMXPage.d.ts +1 -1
  24. package/dist/generators/htmx/generateHTMXPage.js +2 -2
  25. package/dist/generators/htmx/scaffoldHTMX.d.ts +1 -1
  26. package/dist/generators/htmx/scaffoldHTMX.js +2 -2
  27. package/dist/generators/project/computeFlags.d.ts +1 -0
  28. package/dist/generators/project/computeFlags.js +1 -0
  29. package/dist/generators/project/generateBuildBlock.d.ts +2 -1
  30. package/dist/generators/project/generateBuildBlock.js +11 -7
  31. package/dist/generators/project/generateDBBlock.js +6 -0
  32. package/dist/generators/project/generateImportsBlock.js +39 -27
  33. package/dist/generators/project/generateMarkupCSS.js +4 -0
  34. package/dist/generators/project/generateRoutesBlock.d.ts +1 -2
  35. package/dist/generators/project/generateRoutesBlock.js +28 -17
  36. package/dist/generators/project/generateServer.js +5 -10
  37. package/dist/generators/project/scaffoldFrontends.js +20 -1
  38. package/dist/generators/react/generateReactComponents.d.ts +2 -2
  39. package/dist/generators/react/generateReactComponents.js +33 -33
  40. package/dist/generators/react/scaffoldReact.d.ts +1 -1
  41. package/dist/generators/react/scaffoldReact.js +2 -2
  42. package/dist/generators/svelte/generateSveltePage.d.ts +1 -1
  43. package/dist/generators/svelte/generateSveltePage.js +20 -2
  44. package/dist/generators/svelte/scaffoldSvelte.d.ts +1 -1
  45. package/dist/generators/svelte/scaffoldSvelte.js +2 -2
  46. package/dist/generators/vue/generateVuePage.d.ts +1 -1
  47. package/dist/generators/vue/generateVuePage.js +20 -2
  48. package/dist/generators/vue/scaffoldVue.d.ts +1 -1
  49. package/dist/generators/vue/scaffoldVue.js +2 -2
  50. package/dist/questions/databaseEngine.d.ts +1 -1
  51. package/dist/questions/frontendDirectoryConfigurations.d.ts +1 -1
  52. package/dist/questions/frontends.d.ts +1 -1
  53. package/dist/questions/frontends.js +3 -3
  54. package/dist/scaffold.js +14 -2
  55. package/dist/templates/assets/svg/angular.svg +18 -0
  56. package/dist/templates/configurations/tsconfig.example.json +12 -12
  57. package/dist/templates/react/components/App.tsx +2 -2
  58. package/dist/templates/react/components/Head.tsx +7 -7
  59. package/dist/templates/react/components/OAuthLink.tsx +2 -2
  60. package/dist/templates/styles/colors.ts +6 -8
  61. package/dist/templates/styles/reset.css +15 -0
  62. package/dist/templates/svelte/components/Counter.svelte +4 -0
  63. package/dist/templates/vue/components/CountButton.vue +1 -1
  64. package/dist/typeGuards.d.ts +6 -6
  65. package/dist/typeGuards.js +6 -6
  66. package/dist/types.d.ts +1 -0
  67. package/dist/utils/checkDockerInstalled.d.ts +4 -4
  68. package/dist/utils/checkDockerInstalled.js +78 -71
  69. package/dist/utils/parseCommandLineOptions.js +13 -16
  70. package/dist/versions.d.ts +37 -29
  71. package/dist/versions.js +48 -39
  72. package/package.json +10 -9
  73. /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 === 'mysql' ||
55
- databaseEngine === 'singlestore' ||
56
- databaseEngine === 'mariadb'
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 === 'mysql' ||
72
- databaseEngine === 'singlestore' ||
73
- databaseEngine === 'mariadb') {
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
- const hasSchemaInit = databaseEngine in userTables;
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>example/html/pages/HtmlExample.html</code> and save
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>example/htmx/pages/HtmxHome.html</code> and save
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,4 +1,5 @@
1
1
  export const computeFlags = (dirs) => ({
2
+ requiresAngular: dirs.angular !== undefined,
2
3
  requiresHtml: dirs.html !== undefined,
3
4
  requiresHtmx: dirs.htmx !== undefined,
4
5
  requiresReact: dirs.react !== undefined,
@@ -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
- export const generateBuildBlock = ({ assetsDirectory, buildDirectory, frontendDirectories, publicDirectory, tailwind }) => {
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
- return `const buildConfig: BuildConfig = {
12
- ${configEntries}
13
- };
12
+ .join(',\n\t');
13
+ const configContent = `import { defineConfig } from '@absolutejs/absolute'
14
14
 
15
- const isDev = env.NODE_ENV === 'development';
16
- const result = isDev ? await devBuild(buildConfig) : await build(buildConfig);`;
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: !isRemoteHost
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: isRemoteHost && databaseHost === 'neon'
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 == 'drizzle' &&
175
+ if (orm === 'drizzle' &&
164
176
  isRemoteHost &&
165
177
  !(databaseEngine === 'postgresql' && databaseHost === 'planetscale')) {
166
178
  rawImports.push(...connectorImports[databaseHost], ...dialectImports[databaseHost]);
@@ -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;
@@ -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, buildDirectory }: GenerateRoutesBlockProps) => string;
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, buildDirectory }) => {
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
- : `() => ${handlerCall}`;
18
+ : `${isAsync ? 'async ' : ''}() => ${handlerCall}`;
19
19
  const createHandlerCall = (frontend, directory) => {
20
- const base = `${buildDirectory}${directory ? `/${directory}` : ''}/pages`;
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(\`${base}/HTMLExample.html\`)`;
32
+ return `handleHTMLPageRequest(asset(manifest, 'HTMLExample'))`;
23
33
  if (frontend === 'htmx')
24
- return `handleHTMXPageRequest(\`${base}/HTMXExample.html\`)`;
34
+ return `handleHTMXPageRequest(asset(manifest, 'HTMXExample'))`;
25
35
  if (frontend === 'react') {
26
36
  const reactProps = authOption === 'abs'
27
- ? `{ initialCount: 0, cssPath: asset(result, 'ReactExampleCSS'), user, providerConfiguration }`
28
- : `{ initialCount: 0, cssPath: asset(result, 'ReactExampleCSS') }`;
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(result, 'ReactExampleIndex'),
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(result, 'SvelteExample'),
39
- asset(result, 'SvelteExampleIndex'),
40
- { initialCount: 0, cssPath: asset(result, 'SvelteExampleCSS') }
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(result, 'VueExample'),
49
- asset(result, 'VueExampleIndex'),
58
+ asset(manifest, 'VueExample'),
59
+ asset(manifest, 'VueExampleIndex'),
50
60
  generateHeadElement({
51
- cssPath: asset(result, 'VueExampleCSS'),
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 handler = wrap(handlerCall);
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
- ${hmrBlock}
79
+ })
80
+
81
+ export type Server = typeof server
87
82
  `;
88
83
  writeFileSync(serverFilePath, content);
89
84
  };