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.
Files changed (75) 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 +11 -0
  6. package/dist/generators/angular/generateAngularPage.js +174 -0
  7. package/dist/generators/angular/scaffoldAngular.d.ts +2 -0
  8. package/dist/generators/angular/scaffoldAngular.js +38 -0
  9. package/dist/generators/configurations/generatePackageJson.js +28 -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 +3 -3
  21. package/dist/generators/html/scaffoldHTML.d.ts +1 -1
  22. package/dist/generators/html/scaffoldHTML.js +4 -6
  23. package/dist/generators/htmx/generateHTMXPage.d.ts +1 -1
  24. package/dist/generators/htmx/generateHTMXPage.js +3 -3
  25. package/dist/generators/htmx/scaffoldHTMX.d.ts +1 -1
  26. package/dist/generators/htmx/scaffoldHTMX.js +4 -6
  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 +12 -7
  31. package/dist/generators/project/generateDBBlock.js +6 -0
  32. package/dist/generators/project/generateImportsBlock.d.ts +1 -2
  33. package/dist/generators/project/generateImportsBlock.js +48 -50
  34. package/dist/generators/project/generateMarkupCSS.d.ts +1 -1
  35. package/dist/generators/project/generateMarkupCSS.js +5 -1
  36. package/dist/generators/project/generateRoutesBlock.d.ts +1 -4
  37. package/dist/generators/project/generateRoutesBlock.js +44 -38
  38. package/dist/generators/project/generateServer.js +5 -12
  39. package/dist/generators/project/scaffoldFrontends.js +40 -4
  40. package/dist/generators/react/generateReactComponents.d.ts +2 -2
  41. package/dist/generators/react/generateReactComponents.js +33 -33
  42. package/dist/generators/react/scaffoldReact.d.ts +1 -1
  43. package/dist/generators/react/scaffoldReact.js +4 -6
  44. package/dist/generators/svelte/generateSveltePage.d.ts +1 -1
  45. package/dist/generators/svelte/generateSveltePage.js +20 -2
  46. package/dist/generators/svelte/scaffoldSvelte.d.ts +1 -1
  47. package/dist/generators/svelte/scaffoldSvelte.js +4 -6
  48. package/dist/generators/vue/generateVuePage.d.ts +1 -1
  49. package/dist/generators/vue/generateVuePage.js +2 -229
  50. package/dist/generators/vue/scaffoldVue.d.ts +1 -1
  51. package/dist/generators/vue/scaffoldVue.js +6 -2
  52. package/dist/questions/databaseEngine.d.ts +1 -1
  53. package/dist/questions/frontendDirectoryConfigurations.d.ts +1 -1
  54. package/dist/questions/frontends.d.ts +1 -1
  55. package/dist/questions/frontends.js +3 -3
  56. package/dist/scaffold.js +14 -2
  57. package/dist/templates/assets/svg/angular.svg +18 -0
  58. package/dist/templates/configurations/tsconfig.example.json +12 -12
  59. package/dist/templates/react/components/App.tsx +2 -2
  60. package/dist/templates/react/components/Head.tsx +7 -7
  61. package/dist/templates/react/components/OAuthLink.tsx +2 -2
  62. package/dist/templates/styles/colors.ts +6 -8
  63. package/dist/templates/styles/reset.css +15 -0
  64. package/dist/templates/svelte/components/Counter.svelte +4 -0
  65. package/dist/templates/vue/components/CountButton.vue +1 -1
  66. package/dist/typeGuards.d.ts +6 -6
  67. package/dist/typeGuards.js +6 -6
  68. package/dist/types.d.ts +3 -0
  69. package/dist/utils/checkDockerInstalled.d.ts +4 -4
  70. package/dist/utils/checkDockerInstalled.js +78 -71
  71. package/dist/utils/parseCommandLineOptions.js +13 -16
  72. package/dist/versions.d.ts +38 -29
  73. package/dist/versions.js +49 -39
  74. package/package.json +10 -9
  75. /package/dist/templates/configurations/{eslint.config.mjs → eslint.config.example.mjs} +0 -0
@@ -1,4 +1,4 @@
1
- export declare const UNFOUND_INDEX = -1;
2
1
  export declare const DEFAULT_ARG_LENGTH = 2;
3
- export declare const TWO_THIRDS: number;
4
2
  export declare const HOURS_IN_DAY = 24;
3
+ export declare const TWO_THIRDS: number;
4
+ export declare const UNFOUND_INDEX = -1;
package/dist/constants.js CHANGED
@@ -1,4 +1,4 @@
1
- export const UNFOUND_INDEX = -1;
2
1
  export const DEFAULT_ARG_LENGTH = 2;
3
- export const TWO_THIRDS = 2 / 3;
4
2
  export const HOURS_IN_DAY = 24;
3
+ export const TWO_THIRDS = 2 / 3;
4
+ export const UNFOUND_INDEX = -1;
package/dist/data.d.ts CHANGED
@@ -1,18 +1,18 @@
1
1
  import type { FrontendLabels, AvailableDependency } from './types';
2
- export declare const availableFrontends: readonly ["react", "html", "svelte", "vue", "htmx"];
2
+ export declare const absoluteAuthPlugin: AvailableDependency;
3
3
  export declare const availableAuthProviders: readonly ["abs", "none"];
4
- export declare const availableDrizzleDialects: readonly ["gel", "mysql", "postgresql", "sqlite", "singlestore", "mariadb"];
5
- export declare const availablePrismaDialects: readonly ["mysql", "postgresql", "sqlite", "mongodb", "mariadb", "cockroachdb", "mssql"];
4
+ export declare const availableCodeQualityTools: readonly ["eslint+prettier", "biome"];
6
5
  export declare const availableDatabaseEngines: readonly ["postgresql", "mysql", "sqlite", "mongodb", "mariadb", "gel", "singlestore", "cockroachdb", "mssql", "none"];
6
+ export declare const availableDatabaseHosts: readonly ["neon", "planetscale", "turso", "none"];
7
7
  export declare const availableDirectoryConfigurations: readonly ["default", "custom"];
8
+ export declare const availableDrizzleDialects: readonly ["gel", "mariadb", "mssql", "mysql", "postgresql", "singlestore", "sqlite"];
9
+ export declare const availableFrontends: readonly ["react", "html", "svelte", "vue", "htmx", "angular"];
8
10
  export declare const availableORMs: readonly ["drizzle", "prisma", "none"];
9
- export declare const availableDatabaseHosts: readonly ["neon", "planetscale", "turso", "none"];
10
- export declare const availableCodeQualityTools: readonly ["eslint+prettier", "biome"];
11
- export declare const frontendLabels: FrontendLabels;
12
11
  export declare const availablePlugins: AvailableDependency[];
13
- export declare const absoluteAuthPlugin: AvailableDependency;
14
- export declare const scopedStatePlugin: AvailableDependency;
15
- export declare const eslintAndPrettierDependencies: AvailableDependency[];
16
- export declare const eslintReactDependencies: AvailableDependency[];
12
+ export declare const availablePrismaDialects: readonly ["mysql", "postgresql", "sqlite", "mongodb", "mariadb", "cockroachdb", "mssql"];
17
13
  export declare const defaultDependencies: AvailableDependency[];
18
14
  export declare const defaultPlugins: AvailableDependency[];
15
+ export declare const eslintAndPrettierDependencies: AvailableDependency[];
16
+ export declare const eslintReactDependencies: AvailableDependency[];
17
+ export declare const frontendLabels: FrontendLabels;
18
+ export declare const scopedStatePlugin: AvailableDependency;
package/dist/data.js CHANGED
@@ -1,31 +1,20 @@
1
- import { cyan, green, magenta } from 'picocolors';
1
+ import { cyan, green, magenta, red } from 'picocolors';
2
2
  import { versions } from './versions';
3
- export const availableFrontends = [
4
- 'react',
5
- 'html',
6
- 'svelte',
7
- // 'angular',
8
- 'vue',
9
- 'htmx'
10
- ];
3
+ export const absoluteAuthPlugin = {
4
+ imports: [
5
+ {
6
+ config: {
7
+ providersConfiguration: {}
8
+ },
9
+ isPlugin: true,
10
+ packageName: 'absoluteAuth'
11
+ }
12
+ ],
13
+ latestVersion: versions['@absolutejs/auth'],
14
+ value: '@absolutejs/auth'
15
+ };
11
16
  export const availableAuthProviders = ['abs', 'none'];
12
- export const availableDrizzleDialects = [
13
- 'gel',
14
- 'mysql',
15
- 'postgresql',
16
- 'sqlite',
17
- 'singlestore',
18
- 'mariadb'
19
- ];
20
- export const availablePrismaDialects = [
21
- 'mysql',
22
- 'postgresql',
23
- 'sqlite',
24
- 'mongodb',
25
- 'mariadb',
26
- 'cockroachdb',
27
- 'mssql'
28
- ];
17
+ export const availableCodeQualityTools = ['eslint+prettier', 'biome'];
29
18
  export const availableDatabaseEngines = [
30
19
  'postgresql',
31
20
  'mysql',
@@ -38,25 +27,31 @@ export const availableDatabaseEngines = [
38
27
  'mssql',
39
28
  'none'
40
29
  ];
41
- export const availableDirectoryConfigurations = ['default', 'custom'];
42
- export const availableORMs = ['drizzle', 'prisma', 'none'];
43
30
  export const availableDatabaseHosts = [
44
31
  'neon',
45
32
  'planetscale',
46
33
  'turso',
47
34
  'none'
48
35
  ];
49
- export const availableCodeQualityTools = ['eslint+prettier', 'biome'];
50
- /* eslint-disable absolute/sort-keys-fixable */
51
- export const frontendLabels = {
52
- react: cyan('React'),
53
- html: 'HTML',
54
- htmx: 'HTMX',
55
- svelte: magenta('Svelte'),
56
- vue: green('Vue')
57
- // angular: red('Angular'),
58
- };
59
- /* eslint-enable absolute/sort-keys-fixable */
36
+ export const availableDirectoryConfigurations = ['default', 'custom'];
37
+ export const availableDrizzleDialects = [
38
+ 'gel',
39
+ 'mariadb',
40
+ 'mssql',
41
+ 'mysql',
42
+ 'postgresql',
43
+ 'singlestore',
44
+ 'sqlite'
45
+ ];
46
+ export const availableFrontends = [
47
+ 'react',
48
+ 'html',
49
+ 'svelte',
50
+ 'vue',
51
+ 'htmx',
52
+ 'angular'
53
+ ];
54
+ export const availableORMs = ['drizzle', 'prisma', 'none'];
60
55
  export const availablePlugins = [
61
56
  {
62
57
  imports: [{ config: null, isPlugin: true, packageName: 'cors' }],
@@ -77,30 +72,41 @@ export const availablePlugins = [
77
72
  value: 'elysia-rate-limit'
78
73
  }
79
74
  ];
80
- export const absoluteAuthPlugin = {
81
- imports: [
82
- {
83
- config: {
84
- providersConfiguration: {}
85
- },
86
- isPlugin: true,
87
- packageName: 'absoluteAuth'
88
- }
89
- ],
90
- latestVersion: versions['@absolutejs/auth'],
91
- value: '@absolutejs/auth'
92
- };
93
- export const scopedStatePlugin = {
94
- imports: [
95
- {
96
- config: { count: { value: 0 } },
97
- isPlugin: true,
98
- packageName: 'scopedState'
99
- }
100
- ],
101
- latestVersion: versions['elysia-scoped-state'],
102
- value: 'elysia-scoped-state'
103
- };
75
+ export const availablePrismaDialects = [
76
+ 'mysql',
77
+ 'postgresql',
78
+ 'sqlite',
79
+ 'mongodb',
80
+ 'mariadb',
81
+ 'cockroachdb',
82
+ 'mssql'
83
+ ];
84
+ export const defaultDependencies = [
85
+ {
86
+ imports: [{ isPlugin: false, packageName: 'Elysia' }],
87
+ latestVersion: versions['elysia'],
88
+ value: 'elysia'
89
+ }
90
+ ];
91
+ export const defaultPlugins = [
92
+ {
93
+ imports: [
94
+ { isPlugin: false, packageName: 'asset' },
95
+ { isPlugin: true, packageName: 'networking' },
96
+ { isPlugin: false, packageName: 'prepare' }
97
+ ],
98
+ latestVersion: versions['@absolutejs/absolute'],
99
+ value: '@absolutejs/absolute'
100
+ },
101
+ {
102
+ latestVersion: versions['@elysiajs/eden'],
103
+ value: '@elysiajs/eden'
104
+ },
105
+ {
106
+ latestVersion: versions['@elysiajs/static'],
107
+ value: '@elysiajs/static'
108
+ }
109
+ ];
104
110
  export const eslintAndPrettierDependencies = [
105
111
  {
106
112
  latestVersion: versions['@eslint/compat'],
@@ -173,35 +179,22 @@ export const eslintReactDependencies = [
173
179
  value: 'zod-validation-error'
174
180
  }
175
181
  ];
176
- export const defaultDependencies = [
177
- {
178
- imports: [{ isPlugin: false, packageName: 'Elysia' }],
179
- latestVersion: versions['elysia'],
180
- value: 'elysia'
181
- }
182
- ];
183
- export const defaultPlugins = [
184
- {
185
- imports: [
186
- { isPlugin: false, packageName: 'BuildConfig' },
187
- { isPlugin: false, packageName: 'asset' },
188
- { isPlugin: false, packageName: 'build' },
189
- { isPlugin: false, packageName: 'devBuild' },
190
- { isPlugin: false, packageName: 'hmr' },
191
- { isPlugin: true, packageName: 'networking' }
192
- ],
193
- latestVersion: versions['@absolutejs/absolute'],
194
- value: '@absolutejs/absolute'
195
- },
196
- {
197
- imports: [
198
- {
199
- config: { assets: './build', prefix: '' },
200
- isPlugin: true,
201
- packageName: 'staticPlugin'
202
- }
203
- ],
204
- latestVersion: versions['@elysiajs/static'],
205
- value: '@elysiajs/static'
206
- }
207
- ];
182
+ export const frontendLabels = {
183
+ angular: red('Angular'),
184
+ html: 'HTML',
185
+ htmx: 'HTMX',
186
+ react: cyan('React'),
187
+ svelte: magenta('Svelte'),
188
+ vue: green('Vue')
189
+ };
190
+ export const scopedStatePlugin = {
191
+ imports: [
192
+ {
193
+ config: { count: { value: 0 } },
194
+ isPlugin: true,
195
+ packageName: 'scopedState'
196
+ }
197
+ ],
198
+ latestVersion: versions['elysia-scoped-state'],
199
+ value: 'elysia-scoped-state'
200
+ };
@@ -0,0 +1,11 @@
1
+ import { Frontend } from '../../types';
2
+ export declare const generateAngularPage: (_frontends: Frontend[]) => string;
3
+ export declare const generateAngularPageHtml: () => string;
4
+ export declare const generateAppComponent: (isSingleFrontend: boolean) => string;
5
+ export declare const generateAppComponentCss: () => string;
6
+ export declare const generateAppComponentHtml: (frontends: Frontend[], editBasePath: string) => string;
7
+ export declare const generateCounterComponent: (isSingleFrontend: boolean) => string;
8
+ export declare const generateCounterComponentHtml: () => string;
9
+ export declare const generateCounterComponentCss: () => string;
10
+ export declare const generateDropdownComponent: (_frontends: Frontend[]) => string;
11
+ export declare const generateDropdownComponentHtml: (frontends: Frontend[]) => string;
@@ -0,0 +1,174 @@
1
+ import { formatNavLink } from '../../utils/formatNavLink';
2
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
3
+ export const generateAngularPage = (_frontends) => `import { Component, inject, InjectionToken } from '@angular/core';
4
+ import { CommonModule } from '@angular/common';
5
+ import { defineAngularPage } from '@absolutejs/absolute/angular';
6
+ import { DropdownComponent } from '../components/dropdown.component';
7
+ import { AppComponent } from '../components/app.component';
8
+
9
+ export const INITIAL_COUNT = new InjectionToken<number>('INITIAL_COUNT');
10
+
11
+ type AngularPageProps = {
12
+ initialCount: number;
13
+ };
14
+
15
+ @Component({
16
+ imports: [CommonModule, DropdownComponent, AppComponent],
17
+ selector: 'angular-page',
18
+ standalone: true,
19
+ templateUrl: '../templates/angular-example.html'
20
+ })
21
+ export class AngularExampleComponent {
22
+ initialCount: number = 0;
23
+
24
+ constructor() {
25
+ const initialCountToken = inject(INITIAL_COUNT, { optional: true });
26
+ this.initialCount = initialCountToken ?? 0;
27
+ }
28
+ }
29
+
30
+ export const page = defineAngularPage<AngularPageProps>({
31
+ component: AngularExampleComponent
32
+ });
33
+ `;
34
+ export const generateAngularPageHtml = () => `<header>
35
+ <a href="/">AbsoluteJS</a>
36
+ <app-dropdown></app-dropdown>
37
+ </header>
38
+ <app-root [initialCount]="initialCount"></app-root>
39
+ `;
40
+ export const generateAppComponent = (isSingleFrontend) => `import { Component, Input, ViewEncapsulation } from '@angular/core';
41
+ import { CommonModule } from '@angular/common';
42
+ import { CounterComponent } from './counter.component';
43
+
44
+ @Component({
45
+ selector: 'app-root',
46
+ standalone: true,
47
+ imports: [CommonModule, CounterComponent],
48
+ templateUrl: '../templates/app.component.html',
49
+ styleUrl: '${isSingleFrontend ? '../' : '../../'}styles/app.component.css',
50
+ encapsulation: ViewEncapsulation.None
51
+ })
52
+ export class AppComponent {
53
+ @Input() initialCount: number = 0;
54
+ }
55
+ `;
56
+ export const generateAppComponentCss = () => ``;
57
+ export const generateAppComponentHtml = (frontends, editBasePath) => {
58
+ const exploreBlock = frontends.length > 1
59
+ ? `\n\t<p style="margin-top: 2rem">\n\t\tExplore the other pages to see multiple frameworks running\n\t\ttogether.\n\t</p>`
60
+ : '';
61
+ return `<main>
62
+ <nav>
63
+ <a href="https://absolutejs.com" target="_blank">
64
+ <img
65
+ class="logo"
66
+ src="/assets/png/absolutejs-temp.png"
67
+ alt="AbsoluteJS Logo"
68
+ />
69
+ </a>
70
+ <a href="https://angular.dev/">
71
+ <img
72
+ class="logo angular"
73
+ src="/assets/svg/angular.svg"
74
+ alt="Angular Logo"
75
+ />
76
+ </a>
77
+ </nav>
78
+ <h1>AbsoluteJS + Angular</h1>
79
+ <app-counter [initialCount]="initialCount"></app-counter>
80
+ <p>
81
+ Edit <code>${editBasePath}/pages/angular-example.ts</code> and save to
82
+ test HMR.
83
+ </p>${exploreBlock}
84
+ <p style="color: #777; font-size: 1rem; margin-top: 2rem">
85
+ Click on the AbsoluteJS and Angular logos to learn more.
86
+ </p>
87
+ </main>
88
+ `;
89
+ };
90
+ export const generateCounterComponent = (isSingleFrontend) => `import { Component, Input } from '@angular/core';
91
+ import { CommonModule } from '@angular/common';
92
+
93
+ @Component({
94
+ selector: 'app-counter',
95
+ standalone: true,
96
+ imports: [CommonModule],
97
+ templateUrl: '../templates/counter.component.html',
98
+ styleUrl: '${isSingleFrontend ? '../' : '../../'}styles/counter.component.css'
99
+ })
100
+ export class CounterComponent {
101
+ @Input() initialCount: number = 0;
102
+ count: number = 0;
103
+
104
+ ngOnInit() {
105
+ this.count = this.initialCount;
106
+ }
107
+
108
+ increment() {
109
+ this.count++;
110
+ }
111
+ }
112
+ `;
113
+ export const generateCounterComponentHtml = () => `<button (click)="increment()">
114
+ count is <span class="counter-value">{{ count }}</span>
115
+ </button>
116
+ `;
117
+ export const generateCounterComponentCss = () => `button {
118
+ background-color: #1a1a1a;
119
+ border: 1px solid transparent;
120
+ border-radius: 0.5rem;
121
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
122
+ cursor: pointer;
123
+ font-family: inherit;
124
+ font-size: 1.1rem;
125
+ font-weight: 500;
126
+ margin: 2rem 0;
127
+ padding: 0.6rem 1.2rem;
128
+ transition: border-color 0.25s;
129
+ }
130
+ button:hover {
131
+ border-color: #dd0031;
132
+ }
133
+ button:focus,
134
+ button:focus-visible {
135
+ outline: 4px auto -webkit-focus-ring-color;
136
+ }
137
+
138
+ @media (prefers-color-scheme: light) {
139
+ button {
140
+ background-color: #ffffff;
141
+ }
142
+ }
143
+ `;
144
+ // eslint-disable-next-line @typescript-eslint/no-unused-vars
145
+ export const generateDropdownComponent = (_frontends) => {
146
+ return `import { Component } from '@angular/core';
147
+ import { CommonModule } from '@angular/common';
148
+
149
+ @Component({
150
+ selector: 'app-dropdown',
151
+ standalone: true,
152
+ imports: [CommonModule],
153
+ templateUrl: '../templates/dropdown.component.html'
154
+ })
155
+ export class DropdownComponent {
156
+ isOpen = false;
157
+ }
158
+ `;
159
+ };
160
+ export const generateDropdownComponentHtml = (frontends) => {
161
+ const navLinks = frontends.map(formatNavLink).join('\n\t\t');
162
+ return `<details
163
+ class="dropdown"
164
+ [attr.open]="isOpen ? '' : null"
165
+ (mouseenter)="isOpen = true"
166
+ (mouseleave)="isOpen = false"
167
+ >
168
+ <summary>Pages</summary>
169
+ <nav class="menu">
170
+ ${navLinks}
171
+ </nav>
172
+ </details>
173
+ `;
174
+ };
@@ -0,0 +1,2 @@
1
+ import { ScaffoldFrontendProps } from '../../types';
2
+ export declare const scaffoldAngular: ({ editBasePath, isSingleFrontend, targetDirectory, frontends, templatesDirectory, projectAssetsDirectory, stylesDirectory, stylesIndexesDirectory }: ScaffoldFrontendProps) => void;
@@ -0,0 +1,38 @@
1
+ import { copyFileSync, mkdirSync, writeFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { generateMarkupCSS } from '../project/generateMarkupCSS';
4
+ import { generateAngularPage, generateAngularPageHtml, generateAppComponent, generateAppComponentCss, generateAppComponentHtml, generateCounterComponent, generateCounterComponentCss, generateCounterComponentHtml, generateDropdownComponent, generateDropdownComponentHtml } from './generateAngularPage';
5
+ export const scaffoldAngular = ({ editBasePath, isSingleFrontend, targetDirectory, frontends, templatesDirectory, projectAssetsDirectory, stylesDirectory, stylesIndexesDirectory }) => {
6
+ copyFileSync(join(templatesDirectory, 'assets', 'svg', 'angular.svg'), join(projectAssetsDirectory, 'svg', 'angular.svg'));
7
+ const componentsDirectory = join(targetDirectory, 'components');
8
+ mkdirSync(componentsDirectory, { recursive: true });
9
+ const pagesDirectory = join(targetDirectory, 'pages');
10
+ mkdirSync(pagesDirectory, { recursive: true });
11
+ const templatesDir = join(targetDirectory, 'templates');
12
+ mkdirSync(templatesDir, { recursive: true });
13
+ writeFileSync(join(pagesDirectory, 'angular-example.ts'), generateAngularPage(frontends), 'utf-8');
14
+ writeFileSync(join(templatesDir, 'angular-example.html'), generateAngularPageHtml(), 'utf-8');
15
+ writeFileSync(join(componentsDirectory, 'dropdown.component.ts'), generateDropdownComponent(frontends), 'utf-8');
16
+ writeFileSync(join(templatesDir, 'dropdown.component.html'), generateDropdownComponentHtml(frontends), 'utf-8');
17
+ writeFileSync(join(componentsDirectory, 'app.component.ts'), generateAppComponent(isSingleFrontend), 'utf-8');
18
+ writeFileSync(join(templatesDir, 'app.component.html'), generateAppComponentHtml(frontends, editBasePath), 'utf-8');
19
+ writeFileSync(join(stylesDirectory, 'app.component.css'), generateAppComponentCss(), 'utf-8');
20
+ writeFileSync(join(componentsDirectory, 'counter.component.ts'), generateCounterComponent(isSingleFrontend), 'utf-8');
21
+ writeFileSync(join(templatesDir, 'counter.component.html'), generateCounterComponentHtml(), 'utf-8');
22
+ writeFileSync(join(stylesDirectory, 'counter.component.css'), generateCounterComponentCss(), 'utf-8');
23
+ const angularCSS = generateMarkupCSS('angular', '#dd0031');
24
+ const customElementCSS = `
25
+ /* Flex wrappers for Angular custom elements */
26
+ angular-page {
27
+ display: flex;
28
+ flex: 1;
29
+ flex-direction: column;
30
+ }
31
+
32
+ app-root {
33
+ display: flex;
34
+ flex: 1;
35
+ flex-direction: column;
36
+ }`;
37
+ writeFileSync(join(stylesIndexesDirectory, 'angular-example.css'), angularCSS + customElementCSS, 'utf-8');
38
+ };
@@ -46,12 +46,22 @@ export const createPackageJson = async ({ projectName, authOption, plugins, data
46
46
  if (flags.requiresReact) {
47
47
  packageNames.add('react');
48
48
  packageNames.add('react-dom');
49
+ packageNames.add('react-refresh');
49
50
  packageNames.add('@types/react');
50
51
  }
51
52
  if (flags.requiresReact && codeQualityTool === 'eslint+prettier') {
52
53
  for (const dep of eslintReactDependencies)
53
54
  packageNames.add(dep.value);
54
55
  }
56
+ if (flags.requiresAngular) {
57
+ packageNames.add('@angular/common');
58
+ packageNames.add('@angular/compiler');
59
+ packageNames.add('@angular/compiler-cli');
60
+ packageNames.add('@angular/core');
61
+ packageNames.add('@angular/platform-browser');
62
+ packageNames.add('@angular/platform-server');
63
+ packageNames.add('@angular/ssr');
64
+ }
55
65
  if (flags.requiresSvelte)
56
66
  packageNames.add('svelte');
57
67
  if (flags.requiresSvelte && codeQualityTool === 'eslint+prettier')
@@ -133,12 +143,27 @@ export const createPackageJson = async ({ projectName, authOption, plugins, data
133
143
  dependencies['react'] = resolveVersion('react', versions['react']);
134
144
  dependencies['react-dom'] = resolveVersion('react-dom', versions['react-dom']);
135
145
  devDependencies['@types/react'] = resolveVersion('@types/react', versions['@types/react']);
146
+ devDependencies['react-refresh'] = resolveVersion('react-refresh', versions['react-refresh']);
136
147
  }
137
148
  if (flags.requiresReact && codeQualityTool === 'eslint+prettier') {
138
149
  eslintReactDependencies.forEach((dep) => {
139
150
  devDependencies[dep.value] = resolveVersion(dep.value, dep.latestVersion);
140
151
  });
141
152
  }
153
+ if (flags.requiresAngular) {
154
+ const angularPackages = [
155
+ '@angular/common',
156
+ '@angular/compiler',
157
+ '@angular/compiler-cli',
158
+ '@angular/core',
159
+ '@angular/platform-browser',
160
+ '@angular/platform-server',
161
+ '@angular/ssr'
162
+ ];
163
+ angularPackages.forEach((pkg) => {
164
+ dependencies[pkg] = resolveVersion(pkg, versions[pkg]);
165
+ });
166
+ }
142
167
  if (flags.requiresSvelte) {
143
168
  dependencies['svelte'] = resolveVersion('svelte', versions['svelte']);
144
169
  }
@@ -168,9 +193,9 @@ export const createPackageJson = async ({ projectName, authOption, plugins, data
168
193
  if (latest)
169
194
  s.stop(green('Package versions resolved'));
170
195
  const scripts = {
171
- dev: 'absolutejs dev',
172
- format: `absolutejs prettier --write "./**/*.{js,ts,css,json,mjs,md${flags.requiresReact ? ',jsx,tsx' : ''}${flags.requiresSvelte ? ',svelte' : ''}${flags.requiresVue ? ',vue' : ''}${flags.requiresHtml || flags.requiresHtmx ? ',html' : ''}}"`,
173
- lint: 'absolutejs eslint',
196
+ dev: 'absolute dev',
197
+ format: `absolute prettier --write "./**/*.{js,ts,css,json,mjs,md${flags.requiresReact ? ',jsx,tsx' : ''}${flags.requiresSvelte ? ',svelte' : ''}${flags.requiresVue ? ',vue' : ''}${flags.requiresHtml || flags.requiresHtmx ? ',html' : ''}}"`,
198
+ lint: 'absolute eslint',
174
199
  test: 'echo "Error: no test specified" && exit 1',
175
200
  typecheck: 'bun run tsc --noEmit'
176
201
  };
@@ -1,11 +1,35 @@
1
- import { copyFileSync, writeFileSync } from 'fs';
1
+ import { copyFileSync, readFileSync, writeFileSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { dim, yellow } from 'picocolors';
4
4
  import { generateEnv } from './generateEnv';
5
5
  import { generateEslintConfig } from './generateEslintConfig';
6
6
  import { generatePrettierrc } from './generatePrettierrc';
7
7
  export const scaffoldConfigurationFiles = ({ tailwind, templatesDirectory, databaseEngine, envVariables, databaseHost, codeQualityTool, frontends, initializeGitNow, projectName }) => {
8
- copyFileSync(join(templatesDirectory, 'configurations', 'tsconfig.example.json'), join(projectName, 'tsconfig.json'));
8
+ const hasAngular = frontends.includes('angular');
9
+ if (hasAngular) {
10
+ const templatePath = join(templatesDirectory, 'configurations', 'tsconfig.example.json');
11
+ const raw = readFileSync(templatePath, 'utf-8');
12
+ const stripped = raw
13
+ .replace(/\/\*[\s\S]*?\*\//g, '')
14
+ .replace(/\/\/[^\n]*/g, '')
15
+ .replace(/,\s*([}\]])/g, '$1');
16
+ const tsconfig = JSON.parse(stripped);
17
+ tsconfig.compilerOptions['emitDecoratorMetadata'] = true;
18
+ tsconfig.compilerOptions['experimentalDecorators'] = true;
19
+ tsconfig.compilerOptions['useDefineForClassFields'] = false;
20
+ const withAngular = {
21
+ angularCompilerOptions: {
22
+ enableI18nLegacyMessageIdFormat: false,
23
+ strictInjectionParameters: true,
24
+ strictTemplates: true
25
+ },
26
+ ...tsconfig
27
+ };
28
+ writeFileSync(join(projectName, 'tsconfig.json'), JSON.stringify(withAngular, null, '\t'));
29
+ }
30
+ else {
31
+ copyFileSync(join(templatesDirectory, 'configurations', 'tsconfig.example.json'), join(projectName, 'tsconfig.json'));
32
+ }
9
33
  if (tailwind) {
10
34
  copyFileSync(join(templatesDirectory, 'tailwind', 'postcss.config.ts'), join(projectName, 'postcss.config.ts'));
11
35
  copyFileSync(join(templatesDirectory, 'tailwind', 'tailwind.config.ts'), join(projectName, 'tailwind.config.ts'));
@@ -1,12 +1,3 @@
1
- export declare const userTables: {
2
- readonly cockroachdb: "CREATE TABLE IF NOT EXISTS users (\n auth_sub VARCHAR(255) PRIMARY KEY,\n created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n metadata JSONB DEFAULT '{}'::jsonb\n);";
3
- readonly gel: "create type users {\n create required property auth_sub: str {\n create constraint exclusive;\n };\n\n create required property created_at: datetime {\n set default := datetime_current();\n };\n\n create required property metadata: json {\n set default := to_json('{}');\n };\n};";
4
- readonly mariadb: "CREATE TABLE IF NOT EXISTS users (\n auth_sub VARCHAR(255) PRIMARY KEY,\n created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n metadata JSON DEFAULT ('{}')\n);";
5
- readonly mssql: "IF OBJECT_ID('users','U') IS NULL\nBEGIN\n CREATE TABLE users (\n auth_sub NVARCHAR(255) PRIMARY KEY,\n created_at DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME(),\n metadata NVARCHAR(MAX) NULL\n );\nEND;";
6
- readonly mysql: "CREATE TABLE IF NOT EXISTS users (\n auth_sub VARCHAR(255) PRIMARY KEY,\n created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n metadata JSON DEFAULT (JSON_OBJECT())\n);";
7
- readonly postgresql: "CREATE TABLE IF NOT EXISTS users (\n auth_sub VARCHAR(255) PRIMARY KEY,\n created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n metadata JSONB DEFAULT '{}'::jsonb\n);";
8
- readonly singlestore: "CREATE TABLE IF NOT EXISTS users (\n auth_sub VARCHAR(255) PRIMARY KEY,\n created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n metadata JSON DEFAULT ('{}')\n);";
9
- };
10
1
  export declare const countHistoryTables: {
11
2
  readonly cockroachdb: "CREATE SEQUENCE IF NOT EXISTS count_history_uid_seq START WITH 1 INCREMENT BY 1;\nCREATE TABLE IF NOT EXISTS count_history (\n uid BIGINT PRIMARY KEY DEFAULT nextval('count_history_uid_seq'),\n count INT NOT NULL,\n created_at TIMESTAMP NOT NULL DEFAULT NOW()\n);";
12
3
  readonly gel: "create scalar type CountHistoryUid extending sequence;\ncreate type count_history {\n create required property uid: CountHistoryUid {\n create constraint exclusive;\n set default := sequence_next(introspect CountHistoryUid);\n };\n\n create required property count: int16;\n\n create required property created_at: datetime {\n set default := datetime_current();\n };\n};";
@@ -50,3 +41,12 @@ export declare const initTemplates: {
50
41
  readonly wait: "until singlestore -u root -ppassword -e \"SELECT 1\" >/dev/null 2>&1; do sleep 1; done";
51
42
  };
52
43
  };
44
+ export declare const userTables: {
45
+ readonly cockroachdb: "CREATE TABLE IF NOT EXISTS users (\n auth_sub VARCHAR(255) PRIMARY KEY,\n created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n metadata JSONB DEFAULT '{}'::jsonb\n);";
46
+ readonly gel: "create type users {\n create required property auth_sub: str {\n create constraint exclusive;\n };\n\n create required property created_at: datetime {\n set default := datetime_current();\n };\n\n create required property metadata: json {\n set default := to_json('{}');\n };\n};";
47
+ readonly mariadb: "CREATE TABLE IF NOT EXISTS users (\n auth_sub VARCHAR(255) PRIMARY KEY,\n created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n metadata JSON DEFAULT ('{}')\n);";
48
+ readonly mssql: "IF OBJECT_ID('users','U') IS NULL\nBEGIN\n CREATE TABLE users (\n auth_sub NVARCHAR(255) PRIMARY KEY,\n created_at DATETIME2 NOT NULL DEFAULT SYSUTCDATETIME(),\n metadata NVARCHAR(MAX) NULL\n );\nEND;";
49
+ readonly mysql: "CREATE TABLE IF NOT EXISTS users (\n auth_sub VARCHAR(255) PRIMARY KEY,\n created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n metadata JSON DEFAULT (JSON_OBJECT())\n);";
50
+ readonly postgresql: "CREATE TABLE IF NOT EXISTS users (\n auth_sub VARCHAR(255) PRIMARY KEY,\n created_at TIMESTAMP NOT NULL DEFAULT NOW(),\n metadata JSONB DEFAULT '{}'::jsonb\n);";
51
+ readonly singlestore: "CREATE TABLE IF NOT EXISTS users (\n auth_sub VARCHAR(255) PRIMARY KEY,\n created_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,\n metadata JSON DEFAULT ('{}')\n);";
52
+ };
@@ -91,15 +91,6 @@ create type count_history {
91
91
  set default := datetime_current();
92
92
  };
93
93
  };`;
94
- export const userTables = {
95
- cockroachdb: cockroachdbUsers,
96
- gel: gelUsers,
97
- mariadb: mariadbUsers,
98
- mssql: mssqlUsers,
99
- mysql: mysqlUsers,
100
- postgresql: postgresqlUsers,
101
- singlestore: singlestoreUsers
102
- };
103
94
  export const countHistoryTables = {
104
95
  cockroachdb: cockroachdbCountHistory,
105
96
  gel: gelCountHistory,
@@ -143,3 +134,12 @@ export const initTemplates = {
143
134
  wait: 'until singlestore -u root -ppassword -e "SELECT 1" >/dev/null 2>&1; do sleep 1; done'
144
135
  }
145
136
  };
137
+ export const userTables = {
138
+ cockroachdb: cockroachdbUsers,
139
+ gel: gelUsers,
140
+ mariadb: mariadbUsers,
141
+ mssql: mssqlUsers,
142
+ mysql: mysqlUsers,
143
+ postgresql: postgresqlUsers,
144
+ singlestore: singlestoreUsers
145
+ };