create-absolutejs 0.8.2 → 0.9.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 (61) hide show
  1. package/LICENSE +24 -24
  2. package/README.md +179 -179
  3. package/dist/data.js +3 -0
  4. package/dist/generators/configurations/generateDrizzleConfig.js +15 -15
  5. package/dist/generators/configurations/generatePrettierrc.js +9 -9
  6. package/dist/generators/configurations/initializeRoot.js +2 -0
  7. package/dist/generators/db/dockerInitTemplates.js +79 -79
  8. package/dist/generators/db/generateDatabaseTypes.js +6 -6
  9. package/dist/generators/db/generateDockerContainer.js +19 -19
  10. package/dist/generators/db/generateDrizzleSchema.js +17 -17
  11. package/dist/generators/db/generateSqliteSchema.js +8 -8
  12. package/dist/generators/db/handlerTemplates.js +259 -259
  13. package/dist/generators/db/scaffoldDocker.js +1 -1
  14. package/dist/generators/html/generateHTMLPage.js +60 -60
  15. package/dist/generators/htmx/generateHTMXPage.js +86 -86
  16. package/dist/generators/project/generateAbsoluteAuthConfig.js +96 -96
  17. package/dist/generators/project/generateBuildBlock.d.ts +2 -1
  18. package/dist/generators/project/generateBuildBlock.js +9 -5
  19. package/dist/generators/project/generateDBBlock.js +9 -9
  20. package/dist/generators/project/generateImportsBlock.js +1 -0
  21. package/dist/generators/project/generateMarkupCSS.js +145 -145
  22. package/dist/generators/project/generateRoutesBlock.js +36 -36
  23. package/dist/generators/project/generateServer.d.ts +2 -1
  24. package/dist/generators/project/generateServer.js +29 -19
  25. package/dist/generators/project/scaffoldBackend.d.ts +2 -1
  26. package/dist/generators/project/scaffoldBackend.js +2 -1
  27. package/dist/generators/react/generateReactComponents.js +95 -95
  28. package/dist/generators/svelte/generateSveltePage.js +210 -210
  29. package/dist/generators/vue/generateVuePage.js +261 -261
  30. package/dist/messages.js +43 -43
  31. package/dist/scaffold.js +1 -0
  32. package/dist/templates/README.md +35 -35
  33. package/dist/templates/assets/svg/google-logo.svg +7 -7
  34. package/dist/templates/assets/svg/htmx-logo-black.svg +9 -9
  35. package/dist/templates/assets/svg/htmx-logo-white.svg +9 -9
  36. package/dist/templates/assets/svg/vue-logo.svg +4 -4
  37. package/dist/templates/configurations/.prettierignore +3 -3
  38. package/dist/templates/configurations/.prettierrc.json +9 -9
  39. package/dist/templates/configurations/drizzle.config.ts +13 -13
  40. package/dist/templates/configurations/eslint.config.mjs +243 -243
  41. package/dist/templates/configurations/tsconfig.example.json +98 -98
  42. package/dist/templates/constants.ts +2 -2
  43. package/dist/templates/db/docker-compose.db.yml +15 -15
  44. package/dist/templates/git/gitignore +51 -51
  45. package/dist/templates/html/scripts/typescript-example.ts +21 -21
  46. package/dist/templates/react/components/App.tsx +52 -52
  47. package/dist/templates/react/components/Head.tsx +34 -34
  48. package/dist/templates/react/components/OAuthLink.tsx +39 -39
  49. package/dist/templates/react/components/ProfilePicture.tsx +56 -56
  50. package/dist/templates/styles/colors.ts +11 -11
  51. package/dist/templates/styles/reset.css +84 -84
  52. package/dist/templates/svelte/components/Counter.svelte +19 -19
  53. package/dist/templates/svelte/composables/counter.svelte.ts +14 -14
  54. package/dist/templates/tailwind/postcss.config.ts +8 -8
  55. package/dist/templates/tailwind/tailwind.config.ts +7 -7
  56. package/dist/templates/tailwind/tailwind.css +1 -1
  57. package/dist/templates/vue/components/CountButton.vue +39 -39
  58. package/dist/templates/vue/composables/useCount.ts +14 -14
  59. package/dist/versions.d.ts +1 -1
  60. package/dist/versions.js +1 -1
  61. package/package.json +1 -1
@@ -1,148 +1,148 @@
1
- export const generateMarkupCSS = (frontend, color, isSingleFrontend) => `@import url('${isSingleFrontend ? '../styles/reset.css' : '../../styles/reset.css'}');
2
-
3
- header {
4
- align-items: center;
5
- background-color: #1a1a1a;
6
- box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
7
- display: flex;
8
- justify-content: space-between;
9
- padding: 2rem;
10
- text-align: center;
11
- }
12
-
13
- header a {
14
- position: relative;
15
- color: #5fbeeb;
16
- text-decoration: none;
17
- }
18
-
19
- header a::after {
20
- content: '';
21
- position: absolute;
22
- left: 0;
23
- bottom: 0;
24
- width: 100%;
25
- height: 2px;
26
- background: linear-gradient(90deg, #5fbeeb 0%, #35d5a2 50%, #ff4b91 100%);
27
- transform: scaleX(0);
28
- transform-origin: left;
29
- transition: transform 0.25s ease-in-out;
30
- }
31
-
32
- header a:hover::after {
33
- transform: scaleX(1);
34
- }
35
-
36
- h1 {
37
- font-size: 2.5rem;
38
- margin-top: 2rem;
39
- }
40
-
41
- .logo {
42
- height: 8rem;
43
- width: 8rem;
44
- will-change: filter;
45
- transition: filter 300ms;
46
- }
47
-
48
- .logo:hover {
49
- filter: drop-shadow(0 0 2rem #5fbeeb);
50
- }
51
-
52
- .logo.${frontend}:hover {
53
- filter: drop-shadow(0 0 2rem ${color});
54
- }
55
-
56
- nav {
57
- display: flex;
58
- gap: 4rem;
59
- justify-content: center;
60
- }
61
-
62
- header details {
63
- position: relative;
64
- }
65
-
66
- header details summary {
67
- list-style: none;
68
- appearance: none;
69
- -webkit-appearance: none;
70
- cursor: pointer;
71
- user-select: none;
72
- color: #5fbeeb;
73
- font-size: 1.5rem;
74
- font-weight: 500;
75
- padding: 0.5rem 1rem;
76
- }
77
-
78
- header summary::after {
79
- content: '▼';
80
- display: inline-block;
81
- margin-left: 0.5rem;
82
- font-size: 0.75rem;
83
- transition: transform 0.3s ease;
84
- }
85
-
86
- header details[open] summary::after {
87
- transform: rotate(180deg);
88
- }
89
-
90
- header details nav {
91
- position: absolute;
92
- top: 100%;
93
- right: -0.5rem;
94
- display: flex;
95
- flex-direction: column;
96
- gap: 0.75rem;
97
- background: rgba(185, 185, 185, 0.1);
98
- backdrop-filter: blur(4px);
99
- border: 1px solid #5fbeeb;
100
- border-radius: 1rem;
101
- padding: 1rem 1.5rem;
102
- box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
103
- opacity: 0;
104
- transform: translateY(-8px);
105
- pointer-events: none;
106
- transition:
107
- opacity 0.3s ease,
108
- transform 0.3s ease;
109
- z-index: 1000;
110
- }
111
-
112
- header details[open] nav {
113
- opacity: 1;
114
- transform: translateY(0);
115
- pointer-events: auto;
116
- }
117
-
118
- header details nav a {
119
- font-size: 1.1rem;
120
- padding: 0.25rem 0;
121
- white-space: nowrap;
122
- }
123
-
124
- @media (prefers-color-scheme: light) {
125
- header {
126
- background-color: #ffffff;
127
- }
128
-
129
- button {
130
- background-color: #ffffff;
131
- }
132
- }
1
+ export const generateMarkupCSS = (frontend, color, isSingleFrontend) => `@import url('${isSingleFrontend ? '../styles/reset.css' : '../../styles/reset.css'}');
2
+
3
+ header {
4
+ align-items: center;
5
+ background-color: #1a1a1a;
6
+ box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
7
+ display: flex;
8
+ justify-content: space-between;
9
+ padding: 2rem;
10
+ text-align: center;
11
+ }
12
+
13
+ header a {
14
+ position: relative;
15
+ color: #5fbeeb;
16
+ text-decoration: none;
17
+ }
18
+
19
+ header a::after {
20
+ content: '';
21
+ position: absolute;
22
+ left: 0;
23
+ bottom: 0;
24
+ width: 100%;
25
+ height: 2px;
26
+ background: linear-gradient(90deg, #5fbeeb 0%, #35d5a2 50%, #ff4b91 100%);
27
+ transform: scaleX(0);
28
+ transform-origin: left;
29
+ transition: transform 0.25s ease-in-out;
30
+ }
31
+
32
+ header a:hover::after {
33
+ transform: scaleX(1);
34
+ }
35
+
36
+ h1 {
37
+ font-size: 2.5rem;
38
+ margin-top: 2rem;
39
+ }
40
+
41
+ .logo {
42
+ height: 8rem;
43
+ width: 8rem;
44
+ will-change: filter;
45
+ transition: filter 300ms;
46
+ }
47
+
48
+ .logo:hover {
49
+ filter: drop-shadow(0 0 2rem #5fbeeb);
50
+ }
51
+
52
+ .logo.${frontend}:hover {
53
+ filter: drop-shadow(0 0 2rem ${color});
54
+ }
55
+
56
+ nav {
57
+ display: flex;
58
+ gap: 4rem;
59
+ justify-content: center;
60
+ }
61
+
62
+ header details {
63
+ position: relative;
64
+ }
65
+
66
+ header details summary {
67
+ list-style: none;
68
+ appearance: none;
69
+ -webkit-appearance: none;
70
+ cursor: pointer;
71
+ user-select: none;
72
+ color: #5fbeeb;
73
+ font-size: 1.5rem;
74
+ font-weight: 500;
75
+ padding: 0.5rem 1rem;
76
+ }
77
+
78
+ header summary::after {
79
+ content: '▼';
80
+ display: inline-block;
81
+ margin-left: 0.5rem;
82
+ font-size: 0.75rem;
83
+ transition: transform 0.3s ease;
84
+ }
85
+
86
+ header details[open] summary::after {
87
+ transform: rotate(180deg);
88
+ }
89
+
90
+ header details nav {
91
+ position: absolute;
92
+ top: 100%;
93
+ right: -0.5rem;
94
+ display: flex;
95
+ flex-direction: column;
96
+ gap: 0.75rem;
97
+ background: rgba(185, 185, 185, 0.1);
98
+ backdrop-filter: blur(4px);
99
+ border: 1px solid #5fbeeb;
100
+ border-radius: 1rem;
101
+ padding: 1rem 1.5rem;
102
+ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.25);
103
+ opacity: 0;
104
+ transform: translateY(-8px);
105
+ pointer-events: none;
106
+ transition:
107
+ opacity 0.3s ease,
108
+ transform 0.3s ease;
109
+ z-index: 1000;
110
+ }
111
+
112
+ header details[open] nav {
113
+ opacity: 1;
114
+ transform: translateY(0);
115
+ pointer-events: auto;
116
+ }
117
+
118
+ header details nav a {
119
+ font-size: 1.1rem;
120
+ padding: 0.25rem 0;
121
+ white-space: nowrap;
122
+ }
123
+
124
+ @media (prefers-color-scheme: light) {
125
+ header {
126
+ background-color: #ffffff;
127
+ }
128
+
129
+ button {
130
+ background-color: #ffffff;
131
+ }
132
+ }
133
133
  ${frontend === 'react'
134
- ? `\n@keyframes logo-spin {
135
- from {
136
- transform: rotate(0deg);
137
- }
138
- to {
139
- transform: rotate(360deg);
140
- }
141
- }
142
-
143
- @media (prefers-reduced-motion: no-preference) {
144
- a:nth-of-type(2) .logo {
145
- animation: logo-spin infinite 20s linear;
146
- }
134
+ ? `\n@keyframes logo-spin {
135
+ from {
136
+ transform: rotate(0deg);
137
+ }
138
+ to {
139
+ transform: rotate(360deg);
140
+ }
141
+ }
142
+
143
+ @media (prefers-reduced-motion: no-preference) {
144
+ a:nth-of-type(2) .logo {
145
+ animation: logo-spin infinite 20s linear;
146
+ }
147
147
  }`
148
148
  : ''}`;
@@ -3,17 +3,17 @@ export const generateRoutesBlock = ({ databaseEngine, flags, frontendDirectories
3
3
  const hasDatabase = databaseEngine !== undefined && databaseEngine !== 'none';
4
4
  const routes = [];
5
5
  const wrap = (handlerCall) => authOption === 'abs'
6
- ? `async ({ cookie: { auth_provider, user_session_id }, store: { session }, status }) => {
7
- const { user, error } = await getStatus(session, user_session_id);
8
-
9
- if (error) {
10
- return status(error.code, error.message);
11
- }
12
-
13
- const providerConfiguration =
14
- auth_provider.value && providers[auth_provider.value];
15
-
16
- return ${handlerCall};
6
+ ? `async ({ cookie: { auth_provider, user_session_id }, store: { session }, status }) => {
7
+ const { user, error } = await getStatus(session, user_session_id);
8
+
9
+ if (error) {
10
+ return status(error.code, error.message);
11
+ }
12
+
13
+ const providerConfiguration =
14
+ auth_provider.value && providers[auth_provider.value];
15
+
16
+ return ${handlerCall};
17
17
  }`
18
18
  : `() => ${handlerCall}`;
19
19
  const createHandlerCall = (frontend, directory) => {
@@ -24,35 +24,35 @@ export const generateRoutesBlock = ({ databaseEngine, flags, frontendDirectories
24
24
  return `handleHTMXPageRequest(\`${base}/HTMXExample.html\`)`;
25
25
  if (frontend === 'react') {
26
26
  const reactProps = authOption === 'abs'
27
- ? `{ initialCount: 0, cssPath: asset(manifest, 'ReactExampleCSS'), user, providerConfiguration }`
28
- : `{ initialCount: 0, cssPath: asset(manifest, 'ReactExampleCSS') }`;
29
- return `handleReactPageRequest(
30
- ReactExample,
31
- asset(manifest, 'ReactExampleIndex'),
32
- ${reactProps}
27
+ ? `{ initialCount: 0, cssPath: asset(result, 'ReactExampleCSS'), user, providerConfiguration }`
28
+ : `{ initialCount: 0, cssPath: asset(result, 'ReactExampleCSS') }`;
29
+ return `handleReactPageRequest(
30
+ ReactExample,
31
+ asset(result, 'ReactExampleIndex'),
32
+ ${reactProps}
33
33
  )`;
34
34
  }
35
35
  if (frontend === 'svelte')
36
- return `handleSveltePageRequest(
37
- SvelteExample,
38
- asset(manifest, 'SvelteExample'),
39
- asset(manifest, 'SvelteExampleIndex'),
40
- { initialCount: 0, cssPath: asset(manifest, 'SvelteExampleCSS') }
36
+ return `handleSveltePageRequest(
37
+ SvelteExample,
38
+ asset(result, 'SvelteExample'),
39
+ asset(result, 'SvelteExampleIndex'),
40
+ { initialCount: 0, cssPath: asset(result, 'SvelteExampleCSS') }
41
41
  )`;
42
42
  if (frontend === 'vue') {
43
43
  const vueComponent = flags.requiresSvelte
44
44
  ? 'vueImports.VueExample'
45
45
  : 'VueExample';
46
- return `handleVuePageRequest(
47
- ${vueComponent},
48
- asset(manifest, 'VueExample'),
49
- asset(manifest, 'VueExampleIndex'),
50
- generateHeadElement({
51
- cssPath: asset(manifest, 'VueExampleCSS'),
52
- title: 'AbsoluteJS + Vue',
53
- description: 'A Vue.js example with AbsoluteJS'
54
- }),
55
- { initialCount: 0 }
46
+ return `handleVuePageRequest(
47
+ ${vueComponent},
48
+ asset(result, 'VueExample'),
49
+ asset(result, 'VueExampleIndex'),
50
+ generateHeadElement({
51
+ cssPath: asset(result, 'VueExampleCSS'),
52
+ title: 'AbsoluteJS + Vue',
53
+ description: 'A Vue.js example with AbsoluteJS'
54
+ }),
55
+ { initialCount: 0 }
56
56
  )`;
57
57
  }
58
58
  return '';
@@ -76,10 +76,10 @@ export const generateRoutesBlock = ({ databaseEngine, flags, frontendDirectories
76
76
  }
77
77
  });
78
78
  if (hasDatabase && (authOption === undefined || authOption === 'none')) {
79
- routes.push(`.get('/count/:uid', ({ params: { uid } }) => getCountHistory(db, uid), {
80
- params: t.Object({ uid: t.Number() })
81
- })`, `.post('/count', ({ body: { count } }) => createCountHistory(db, count), {
82
- body: t.Object({ count: t.Number() })
79
+ routes.push(`.get('/count/:uid', ({ params: { uid } }) => getCountHistory(db, uid), {
80
+ params: t.Object({ uid: t.Number() })
81
+ })`, `.post('/count', ({ body: { count } }) => createCountHistory(db, count), {
82
+ body: t.Object({ count: t.Number() })
83
83
  })`);
84
84
  }
85
85
  return routes.join('\n ');
@@ -1,6 +1,7 @@
1
1
  import type { CreateConfiguration } from '../../types';
2
2
  type CreateServerFileProps = Pick<CreateConfiguration, 'tailwind' | 'authOption' | 'databaseEngine' | 'plugins' | 'buildDirectory' | 'databaseHost' | 'orm' | 'assetsDirectory' | 'frontendDirectories'> & {
3
3
  backendDirectory: string;
4
+ publicDirectory: string;
4
5
  };
5
- export declare const generateServerFile: ({ tailwind, authOption, plugins, buildDirectory, databaseEngine, databaseHost, orm, assetsDirectory, frontendDirectories, backendDirectory }: CreateServerFileProps) => void;
6
+ export declare const generateServerFile: ({ tailwind, authOption, plugins, buildDirectory, databaseEngine, databaseHost, orm, assetsDirectory, frontendDirectories, backendDirectory, publicDirectory }: CreateServerFileProps) => void;
6
7
  export {};
@@ -6,7 +6,7 @@ import { generateBuildBlock } from './generateBuildBlock';
6
6
  import { generateDBBlock } from './generateDBBlock';
7
7
  import { generateImportsBlock } from './generateImportsBlock';
8
8
  import { generateRoutesBlock } from './generateRoutesBlock';
9
- export const generateServerFile = ({ tailwind, authOption, plugins, buildDirectory, databaseEngine, databaseHost, orm, assetsDirectory, frontendDirectories, backendDirectory }) => {
9
+ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirectory, databaseEngine, databaseHost, orm, assetsDirectory, frontendDirectories, backendDirectory, publicDirectory }) => {
10
10
  const serverFilePath = join(backendDirectory, 'server.ts');
11
11
  const flags = computeFlags(frontendDirectories);
12
12
  const deps = collectDependencies({ authOption, flags, plugins });
@@ -24,6 +24,7 @@ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirecto
24
24
  assetsDirectory,
25
25
  buildDirectory,
26
26
  frontendDirectories,
27
+ publicDirectory,
27
28
  tailwind
28
29
  });
29
30
  let dbBlock = '';
@@ -32,7 +33,8 @@ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirecto
32
33
  }
33
34
  const useBlock = deps
34
35
  .flatMap((dependency) => dependency.imports ?? [])
35
- .filter((pluginImport) => pluginImport.isPlugin)
36
+ .filter((pluginImport) => pluginImport.isPlugin &&
37
+ pluginImport.packageName !== 'networking')
36
38
  .map((pluginImport) => {
37
39
  if (pluginImport.packageName === 'absoluteAuth') {
38
40
  const hasDatabase = databaseEngine !== undefined && databaseEngine !== 'none';
@@ -49,11 +51,11 @@ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirecto
49
51
  return `.use(${pluginImport.packageName}(${JSON.stringify(pluginImport.config)}))`;
50
52
  })
51
53
  .join('\n');
52
- const guardBlock = `.guard({
53
- cookie: t.Cookie({
54
- auth_provider: t.Optional(authProviderOption),
55
- user_session_id: userSessionIdTypebox
56
- })
54
+ const guardBlock = `.guard({
55
+ cookie: t.Cookie({
56
+ auth_provider: t.Optional(authProviderOption),
57
+ user_session_id: userSessionIdTypebox
58
+ })
57
59
  })`;
58
60
  const routesBlock = generateRoutesBlock({
59
61
  authOption,
@@ -62,18 +64,26 @@ export const generateServerFile = ({ tailwind, authOption, plugins, buildDirecto
62
64
  flags,
63
65
  frontendDirectories
64
66
  });
65
- const content = `${importsBlock}
66
-
67
- ${manifestBlock}
68
- ${dbBlock}
69
- new Elysia()
70
- ${useBlock}
71
- ${authOption === 'abs' ? guardBlock : ''}
72
- ${routesBlock}
73
- .on('error', err => {
74
- const { request } = err
75
- console.error(\`Server error on \${request.method} \${request.url}: \${err.message}\`)
76
- });
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
+ const content = `${importsBlock}
75
+
76
+ ${manifestBlock}
77
+ ${dbBlock ? `${dbBlock}\n` : ''}
78
+ const server = new Elysia()
79
+ ${useBlock}${authOption === 'abs' ? `\n${guardBlock}` : ''}
80
+ ${routesBlock}
81
+ .use(networking)
82
+ .on('error', err => {
83
+ const { request } = err
84
+ console.error(\`Server error on \${request.method} \${request.url}: \${err.message}\`)
85
+ });
86
+ ${hmrBlock}
77
87
  `;
78
88
  writeFileSync(serverFilePath, content);
79
89
  };
@@ -1,6 +1,7 @@
1
1
  import { CreateConfiguration } from '../../types';
2
2
  type ScaffoldBackendProps = Pick<CreateConfiguration, 'assetsDirectory' | 'absProviders' | 'authOption' | 'buildDirectory' | 'databaseEngine' | 'databaseHost' | 'frontendDirectories' | 'orm' | 'plugins' | 'tailwind'> & {
3
3
  backendDirectory: string;
4
+ publicDirectory: string;
4
5
  };
5
- export declare const scaffoldBackend: ({ assetsDirectory, authOption, absProviders, backendDirectory, buildDirectory, databaseEngine, databaseHost, frontendDirectories, orm, plugins, tailwind }: ScaffoldBackendProps) => void;
6
+ export declare const scaffoldBackend: ({ assetsDirectory, authOption, absProviders, backendDirectory, buildDirectory, databaseEngine, databaseHost, frontendDirectories, orm, plugins, publicDirectory, tailwind }: ScaffoldBackendProps) => void;
6
7
  export {};
@@ -2,7 +2,7 @@ import { mkdirSync, writeFileSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { generateAbsoluteAuthConfig } from './generateAbsoluteAuthConfig';
4
4
  import { generateServerFile } from './generateServer';
5
- export const scaffoldBackend = ({ assetsDirectory, authOption, absProviders, backendDirectory, buildDirectory, databaseEngine, databaseHost, frontendDirectories, orm, plugins, tailwind }) => {
5
+ export const scaffoldBackend = ({ assetsDirectory, authOption, absProviders, backendDirectory, buildDirectory, databaseEngine, databaseHost, frontendDirectories, orm, plugins, publicDirectory, tailwind }) => {
6
6
  generateServerFile({
7
7
  assetsDirectory,
8
8
  authOption,
@@ -13,6 +13,7 @@ export const scaffoldBackend = ({ assetsDirectory, authOption, absProviders, bac
13
13
  frontendDirectories,
14
14
  orm,
15
15
  plugins,
16
+ publicDirectory,
16
17
  tailwind
17
18
  });
18
19
  if (authOption === 'abs') {