alepha 0.11.10 → 0.11.11
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/README.md +6 -0
- package/dist/index.cjs +1692 -408
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1622 -338
- package/dist/index.js.map +1 -1
- package/package.json +12 -6
- package/src/assets/tsconfigJson.ts +1 -0
- package/src/commands/BiomeCommands.ts +5 -24
- package/src/commands/CoreCommands.ts +41 -138
- package/src/commands/DrizzleCommands.ts +18 -193
- package/src/commands/VerifyCommands.ts +2 -6
- package/src/commands/ViteCommands.ts +24 -57
- package/src/services/ProjectUtils.ts +508 -0
package/package.json
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "alepha",
|
|
3
|
-
"
|
|
3
|
+
"description": "Easy-to-use modern TypeScript framework for building many kind of applications.",
|
|
4
|
+
"version": "0.11.11",
|
|
4
5
|
"type": "module",
|
|
5
6
|
"engines": {
|
|
6
7
|
"node": ">=22.0.0"
|
|
@@ -15,7 +16,7 @@
|
|
|
15
16
|
],
|
|
16
17
|
"bin": "./dist/index.js",
|
|
17
18
|
"dependencies": {
|
|
18
|
-
"@alepha/
|
|
19
|
+
"@alepha/orm": "^0.11.11",
|
|
19
20
|
"@biomejs/biome": "^2.3.5",
|
|
20
21
|
"drizzle-kit": "^0.31.7",
|
|
21
22
|
"tar": "^7.5.2",
|
|
@@ -25,9 +26,9 @@
|
|
|
25
26
|
"vitest": "^4.0.9"
|
|
26
27
|
},
|
|
27
28
|
"devDependencies": {
|
|
28
|
-
"@alepha/command": "^0.11.
|
|
29
|
-
"@alepha/core": "^0.11.
|
|
30
|
-
"@alepha/logger": "^0.11.
|
|
29
|
+
"@alepha/command": "^0.11.11",
|
|
30
|
+
"@alepha/core": "^0.11.11",
|
|
31
|
+
"@alepha/logger": "^0.11.11"
|
|
31
32
|
},
|
|
32
33
|
"scripts": {
|
|
33
34
|
"lint": "biome check --fix",
|
|
@@ -40,7 +41,12 @@
|
|
|
40
41
|
"url": "git+https://github.com/feunard/alepha.git"
|
|
41
42
|
},
|
|
42
43
|
"keywords": [
|
|
43
|
-
"alepha"
|
|
44
|
+
"alepha",
|
|
45
|
+
"aleph",
|
|
46
|
+
"framework",
|
|
47
|
+
"serverless",
|
|
48
|
+
"react",
|
|
49
|
+
"api"
|
|
44
50
|
],
|
|
45
51
|
"module": "./dist/index.js",
|
|
46
52
|
"exports": {
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { access } from "node:fs/promises";
|
|
2
|
-
import { join } from "node:path";
|
|
3
1
|
import { $command } from "@alepha/command";
|
|
4
2
|
import { $inject, t } from "@alepha/core";
|
|
5
3
|
import { $logger } from "@alepha/logger";
|
|
6
|
-
import { biomeJson } from "../assets/biomeJson.ts";
|
|
7
4
|
import { ProcessRunner } from "../services/ProcessRunner.ts";
|
|
5
|
+
import { ProjectUtils } from "../services/ProjectUtils.ts";
|
|
8
6
|
|
|
9
7
|
export class BiomeCommands {
|
|
10
8
|
protected readonly log = $logger();
|
|
11
9
|
protected readonly runner = $inject(ProcessRunner);
|
|
10
|
+
protected readonly utils = $inject(ProjectUtils);
|
|
11
|
+
|
|
12
12
|
protected readonly biomeFlags = t.object({
|
|
13
13
|
config: t.optional(
|
|
14
14
|
t.text({
|
|
@@ -22,7 +22,7 @@ export class BiomeCommands {
|
|
|
22
22
|
description: "Format the codebase using Biome",
|
|
23
23
|
flags: this.biomeFlags,
|
|
24
24
|
handler: async ({ flags }) => {
|
|
25
|
-
const configPath = await this.
|
|
25
|
+
const configPath = await this.utils.getBiomeConfigPath(flags.config);
|
|
26
26
|
await this.runner.exec(`biome format --fix --config-path=${configPath}`);
|
|
27
27
|
},
|
|
28
28
|
});
|
|
@@ -32,29 +32,10 @@ export class BiomeCommands {
|
|
|
32
32
|
description: "Run linter across the codebase using Biome",
|
|
33
33
|
flags: this.biomeFlags,
|
|
34
34
|
handler: async ({ flags }) => {
|
|
35
|
-
const configPath = await this.
|
|
35
|
+
const configPath = await this.utils.getBiomeConfigPath(flags.config);
|
|
36
36
|
await this.runner.exec(
|
|
37
37
|
`biome check --formatter-enabled=false --fix --config-path=${configPath}`,
|
|
38
38
|
);
|
|
39
39
|
},
|
|
40
40
|
});
|
|
41
|
-
|
|
42
|
-
protected async configPath(maybePath?: string): Promise<string> {
|
|
43
|
-
const root = process.cwd();
|
|
44
|
-
if (maybePath) {
|
|
45
|
-
try {
|
|
46
|
-
const path = join(root, maybePath);
|
|
47
|
-
await access(path);
|
|
48
|
-
return path;
|
|
49
|
-
} catch {}
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
try {
|
|
53
|
-
const path = join(root, "biome.json");
|
|
54
|
-
await access(path);
|
|
55
|
-
return path;
|
|
56
|
-
} catch {
|
|
57
|
-
return await this.runner.writeConfigFile("biome.json", biomeJson);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
41
|
}
|
|
@@ -1,18 +1,19 @@
|
|
|
1
|
-
import { access, mkdir
|
|
1
|
+
import { access, mkdir } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
-
import { Readable } from "node:stream";
|
|
4
3
|
import { $command, CliProvider } from "@alepha/command";
|
|
5
|
-
import { $inject,
|
|
4
|
+
import { $inject, t } from "@alepha/core";
|
|
6
5
|
import { $logger } from "@alepha/logger";
|
|
7
|
-
import {
|
|
8
|
-
import * as tar from "tar";
|
|
9
|
-
import { tsconfigJson } from "../assets/tsconfigJson.ts";
|
|
6
|
+
import { ProjectUtils } from "../services/ProjectUtils.ts";
|
|
10
7
|
import { version } from "../version.ts";
|
|
11
8
|
|
|
12
9
|
export class CoreCommands {
|
|
13
10
|
protected readonly log = $logger();
|
|
14
11
|
protected readonly cli = $inject(CliProvider);
|
|
12
|
+
protected readonly utils = $inject(ProjectUtils);
|
|
15
13
|
|
|
14
|
+
/**
|
|
15
|
+
* Called when no command is provided
|
|
16
|
+
*/
|
|
16
17
|
public readonly root = $command({
|
|
17
18
|
root: true,
|
|
18
19
|
flags: t.object({
|
|
@@ -33,6 +34,9 @@ export class CoreCommands {
|
|
|
33
34
|
},
|
|
34
35
|
});
|
|
35
36
|
|
|
37
|
+
/**
|
|
38
|
+
* Create a new Alepha project based on one of the sample projects (for now, only one sample project is available)
|
|
39
|
+
*/
|
|
36
40
|
public readonly create = $command({
|
|
37
41
|
name: "create",
|
|
38
42
|
description: "Create a new Alepha project",
|
|
@@ -45,9 +49,8 @@ export class CoreCommands {
|
|
|
45
49
|
pnpm: t.optional(t.boolean({ description: "Use pnpm package manager" })),
|
|
46
50
|
}),
|
|
47
51
|
summary: false,
|
|
48
|
-
handler: async ({ run, args, flags }) => {
|
|
52
|
+
handler: async ({ run, args, flags, root }) => {
|
|
49
53
|
const name = args;
|
|
50
|
-
const root = process.cwd();
|
|
51
54
|
const dest = join(root, name);
|
|
52
55
|
|
|
53
56
|
try {
|
|
@@ -73,11 +76,11 @@ export class CoreCommands {
|
|
|
73
76
|
await mkdir(dest, { recursive: true }).catch(() => null);
|
|
74
77
|
|
|
75
78
|
await run("Downloading sample project", () =>
|
|
76
|
-
this.downloadSampleProject(dest),
|
|
79
|
+
this.utils.downloadSampleProject(dest),
|
|
77
80
|
);
|
|
78
81
|
|
|
79
82
|
if (flags.yarn) {
|
|
80
|
-
await this.ensureYarn(dest);
|
|
83
|
+
await this.utils.ensureYarn(dest);
|
|
81
84
|
await run(`cd ${name} && yarn set version stable`, {
|
|
82
85
|
alias: "Setting Yarn to stable version",
|
|
83
86
|
});
|
|
@@ -109,6 +112,9 @@ export class CoreCommands {
|
|
|
109
112
|
},
|
|
110
113
|
});
|
|
111
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Clean the project, removing the "dist" directory
|
|
117
|
+
*/
|
|
112
118
|
public readonly clean = $command({
|
|
113
119
|
name: "clean",
|
|
114
120
|
description: "Clean the project",
|
|
@@ -117,6 +123,10 @@ export class CoreCommands {
|
|
|
117
123
|
},
|
|
118
124
|
});
|
|
119
125
|
|
|
126
|
+
/**
|
|
127
|
+
* Ensure the project has the necessary Alepha configuration files.
|
|
128
|
+
* Add the correct dependencies to package.json and install them.
|
|
129
|
+
*/
|
|
120
130
|
public readonly init = $command({
|
|
121
131
|
name: "init",
|
|
122
132
|
description: "Add missing Alepha configuration files to the project",
|
|
@@ -125,18 +135,30 @@ export class CoreCommands {
|
|
|
125
135
|
// force: t.boolean({
|
|
126
136
|
// description: "If true, all config files will be overwritten",
|
|
127
137
|
// }),
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
138
|
+
// choose package manager
|
|
139
|
+
yarn: t.optional(t.boolean({ description: "Use Yarn package manager" })),
|
|
140
|
+
// choose which dependencies to add
|
|
141
|
+
api: t.optional(
|
|
142
|
+
t.boolean({ description: "Include Alepha Server dependencies" }),
|
|
143
|
+
),
|
|
144
|
+
react: t.optional(
|
|
145
|
+
t.boolean({ description: "Include Alepha React dependencies" }),
|
|
146
|
+
),
|
|
147
|
+
orm: t.optional(
|
|
148
|
+
t.boolean({ description: "Include Alepha ORM dependencies" }),
|
|
149
|
+
),
|
|
131
150
|
}),
|
|
132
|
-
handler: async ({ run, flags }) => {
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
151
|
+
handler: async ({ run, flags, root }) => {
|
|
152
|
+
await run("Ensuring Alepha configuration files", async () => {
|
|
153
|
+
await this.utils.ensureTsConfig(root);
|
|
154
|
+
await this.utils.ensurePackageJson(root, flags);
|
|
155
|
+
});
|
|
137
156
|
|
|
138
157
|
if (flags.yarn) {
|
|
139
|
-
await this.ensureYarn(root);
|
|
158
|
+
await this.utils.ensureYarn(root);
|
|
159
|
+
await run("yarn install", {
|
|
160
|
+
alias: "Installing dependencies with Yarn",
|
|
161
|
+
});
|
|
140
162
|
} else {
|
|
141
163
|
await run("npm install", {
|
|
142
164
|
alias: "Installing dependencies with npm",
|
|
@@ -144,123 +166,4 @@ export class CoreCommands {
|
|
|
144
166
|
}
|
|
145
167
|
},
|
|
146
168
|
});
|
|
147
|
-
|
|
148
|
-
public async ensureYarn(root: string) {
|
|
149
|
-
const tsconfigPath = join(root, ".yarnrc.yml");
|
|
150
|
-
try {
|
|
151
|
-
await access(tsconfigPath);
|
|
152
|
-
} catch {
|
|
153
|
-
await writeFile(tsconfigPath, "nodeLinker: node-modules");
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
|
|
157
|
-
public generatePackageJsonContent(modes: { api?: boolean; react?: boolean }) {
|
|
158
|
-
const dependencies: Record<string, string> = {
|
|
159
|
-
"@alepha/core": `^${version}`,
|
|
160
|
-
"@alepha/logger": `^${version}`,
|
|
161
|
-
"@alepha/datetime": `^${version}`,
|
|
162
|
-
};
|
|
163
|
-
|
|
164
|
-
const devDependencies: Record<string, string> = {
|
|
165
|
-
alepha: `^${version}`,
|
|
166
|
-
"@alepha/vite": `^${version}`,
|
|
167
|
-
};
|
|
168
|
-
|
|
169
|
-
if (modes.api) {
|
|
170
|
-
dependencies["@alepha/server"] = `^${version}`;
|
|
171
|
-
dependencies["@alepha/server-swagger"] = `^${version}`;
|
|
172
|
-
dependencies["@alepha/server-multipart"] = `^${version}`;
|
|
173
|
-
}
|
|
174
|
-
|
|
175
|
-
if (modes.react) {
|
|
176
|
-
dependencies["@alepha/server"] = `^${version}`;
|
|
177
|
-
dependencies["@alepha/server-links"] = `^${version}`;
|
|
178
|
-
dependencies["@alepha/react"] = `^${version}`;
|
|
179
|
-
dependencies.react = "^19.2.0";
|
|
180
|
-
devDependencies["@types/react"] = "^19.0.0";
|
|
181
|
-
}
|
|
182
|
-
|
|
183
|
-
return {
|
|
184
|
-
dependencies,
|
|
185
|
-
devDependencies,
|
|
186
|
-
scripts: {
|
|
187
|
-
dev: "alepha dev",
|
|
188
|
-
build: "alepha build",
|
|
189
|
-
},
|
|
190
|
-
};
|
|
191
|
-
}
|
|
192
|
-
|
|
193
|
-
public async ensurePackageJson(
|
|
194
|
-
root: string,
|
|
195
|
-
modes: { api?: boolean; react?: boolean },
|
|
196
|
-
) {
|
|
197
|
-
const packageJsonPath = join(root, "package.json");
|
|
198
|
-
try {
|
|
199
|
-
await access(packageJsonPath);
|
|
200
|
-
} catch (error) {
|
|
201
|
-
this.log.info("No package.json found. Creating one...");
|
|
202
|
-
await writeFile(
|
|
203
|
-
packageJsonPath,
|
|
204
|
-
JSON.stringify(this.generatePackageJsonContent(modes), null, 2),
|
|
205
|
-
);
|
|
206
|
-
return;
|
|
207
|
-
}
|
|
208
|
-
|
|
209
|
-
const content = await readFile(packageJsonPath, "utf8");
|
|
210
|
-
const packageJson = JSON.parse(content);
|
|
211
|
-
if (!packageJson.type || packageJson.type !== "module") {
|
|
212
|
-
packageJson.type = "module";
|
|
213
|
-
}
|
|
214
|
-
const newPackageJson = this.generatePackageJsonContent(modes);
|
|
215
|
-
|
|
216
|
-
packageJson.type = "module";
|
|
217
|
-
packageJson.dependencies ??= {};
|
|
218
|
-
packageJson.devDependencies ??= {};
|
|
219
|
-
packageJson.scripts ??= {};
|
|
220
|
-
|
|
221
|
-
Object.assign(packageJson.dependencies, newPackageJson.dependencies);
|
|
222
|
-
Object.assign(packageJson.devDependencies, newPackageJson.devDependencies);
|
|
223
|
-
Object.assign(packageJson.scripts, newPackageJson.scripts);
|
|
224
|
-
|
|
225
|
-
await writeFile(packageJsonPath, JSON.stringify(packageJson, null, 2));
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
public async ensureTsConfig(root = process.cwd()) {
|
|
229
|
-
const tsconfigPath = join(root, "tsconfig.json");
|
|
230
|
-
try {
|
|
231
|
-
await access(tsconfigPath);
|
|
232
|
-
} catch {
|
|
233
|
-
this.log.info("Missing tsconfig.json detected. Creating one...");
|
|
234
|
-
await writeFile(tsconfigPath, tsconfigJson);
|
|
235
|
-
}
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
public async downloadSampleProject(targetDir: string) {
|
|
239
|
-
const url = "https://api.github.com/repos/feunard/alepha/tarball/main";
|
|
240
|
-
const response = await fetch(url, {
|
|
241
|
-
headers: {
|
|
242
|
-
"User-Agent": "Alepha-CLI", // GitHub API requires User-Agent
|
|
243
|
-
},
|
|
244
|
-
});
|
|
245
|
-
|
|
246
|
-
if (!response.ok) {
|
|
247
|
-
throw new AlephaError(`Failed to download: ${response.statusText}`);
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const tarStream = Readable.fromWeb(response.body as any);
|
|
251
|
-
await pipeline(
|
|
252
|
-
tarStream,
|
|
253
|
-
tar.extract({
|
|
254
|
-
cwd: targetDir, // Extract to target directory
|
|
255
|
-
strip: 3, // Remove feunard-alepha-<hash>/apps/starter prefix
|
|
256
|
-
filter: (path) => {
|
|
257
|
-
// Only extract files from apps/starter/
|
|
258
|
-
const parts = path.split("/");
|
|
259
|
-
return (
|
|
260
|
-
parts.length >= 3 && parts[1] === "apps" && parts[2] === "starter"
|
|
261
|
-
);
|
|
262
|
-
},
|
|
263
|
-
}),
|
|
264
|
-
);
|
|
265
|
-
}
|
|
266
169
|
}
|
|
@@ -2,19 +2,15 @@ import { readFile } from "node:fs/promises";
|
|
|
2
2
|
import { createRequire } from "node:module";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { $command } from "@alepha/command";
|
|
5
|
-
import { $inject,
|
|
5
|
+
import { $inject, AlephaError, t } from "@alepha/core";
|
|
6
6
|
import { $logger } from "@alepha/logger";
|
|
7
|
-
import type { RepositoryProvider } from "@alepha/postgres";
|
|
8
|
-
import { tsImport } from "tsx/esm/api";
|
|
9
7
|
import { ProcessRunner } from "../services/ProcessRunner.ts";
|
|
8
|
+
import { ProjectUtils } from "../services/ProjectUtils.ts";
|
|
10
9
|
|
|
11
10
|
export class DrizzleCommands {
|
|
12
11
|
log = $logger();
|
|
13
12
|
runner = $inject(ProcessRunner);
|
|
14
|
-
|
|
15
|
-
flags = t.object({
|
|
16
|
-
root: t.text({ description: "Project root", default: "." }),
|
|
17
|
-
});
|
|
13
|
+
utils = $inject(ProjectUtils);
|
|
18
14
|
|
|
19
15
|
/**
|
|
20
16
|
* Check if database migrations are up to date
|
|
@@ -29,17 +25,16 @@ export class DrizzleCommands {
|
|
|
29
25
|
check = $command({
|
|
30
26
|
name: "db:check-migrations",
|
|
31
27
|
description: "Verify database migration files are up to date",
|
|
32
|
-
flags: this.flags,
|
|
33
28
|
args: t.optional(
|
|
34
29
|
t.text({
|
|
35
30
|
title: "path",
|
|
36
31
|
description: "Path to the Alepha server entry file",
|
|
37
32
|
}),
|
|
38
33
|
),
|
|
39
|
-
handler: async ({
|
|
40
|
-
const rootDir =
|
|
34
|
+
handler: async ({ args, root }) => {
|
|
35
|
+
const rootDir = root;
|
|
41
36
|
this.log.debug(`Using project root: ${rootDir}`);
|
|
42
|
-
const { alepha } = await this.loadAlephaFromServerEntryFile(
|
|
37
|
+
const { alepha } = await this.utils.loadAlephaFromServerEntryFile(
|
|
43
38
|
rootDir,
|
|
44
39
|
args,
|
|
45
40
|
);
|
|
@@ -127,16 +122,15 @@ export class DrizzleCommands {
|
|
|
127
122
|
name: "db:generate",
|
|
128
123
|
description: "Generate migration files based on current database schema",
|
|
129
124
|
summary: false,
|
|
130
|
-
flags: this.flags,
|
|
131
125
|
args: t.optional(
|
|
132
126
|
t.text({
|
|
133
127
|
title: "path",
|
|
134
128
|
description: "Path to the Alepha server entry file",
|
|
135
129
|
}),
|
|
136
130
|
),
|
|
137
|
-
handler: async ({
|
|
138
|
-
await this.runDrizzleKitCommand({
|
|
139
|
-
|
|
131
|
+
handler: async ({ args, root }) => {
|
|
132
|
+
await this.utils.runDrizzleKitCommand({
|
|
133
|
+
root,
|
|
140
134
|
args,
|
|
141
135
|
command: "generate",
|
|
142
136
|
logMessage: (providerName, dialect) =>
|
|
@@ -157,16 +151,15 @@ export class DrizzleCommands {
|
|
|
157
151
|
name: "db:push",
|
|
158
152
|
description: "Push database schema changes directly to the database",
|
|
159
153
|
summary: false,
|
|
160
|
-
flags: this.flags,
|
|
161
154
|
args: t.optional(
|
|
162
155
|
t.text({
|
|
163
156
|
title: "path",
|
|
164
157
|
description: "Path to the Alepha server entry file",
|
|
165
158
|
}),
|
|
166
159
|
),
|
|
167
|
-
handler: async ({
|
|
168
|
-
await this.runDrizzleKitCommand({
|
|
169
|
-
|
|
160
|
+
handler: async ({ root, args }) => {
|
|
161
|
+
await this.utils.runDrizzleKitCommand({
|
|
162
|
+
root,
|
|
170
163
|
args,
|
|
171
164
|
command: "push",
|
|
172
165
|
logMessage: (providerName, dialect) =>
|
|
@@ -187,16 +180,15 @@ export class DrizzleCommands {
|
|
|
187
180
|
name: "db:migrate",
|
|
188
181
|
description: "Apply pending database migrations",
|
|
189
182
|
summary: false,
|
|
190
|
-
flags: this.flags,
|
|
191
183
|
args: t.optional(
|
|
192
184
|
t.text({
|
|
193
185
|
title: "path",
|
|
194
186
|
description: "Path to the Alepha server entry file",
|
|
195
187
|
}),
|
|
196
188
|
),
|
|
197
|
-
handler: async ({
|
|
198
|
-
await this.runDrizzleKitCommand({
|
|
199
|
-
|
|
189
|
+
handler: async ({ root, args }) => {
|
|
190
|
+
await this.utils.runDrizzleKitCommand({
|
|
191
|
+
root,
|
|
200
192
|
args,
|
|
201
193
|
command: "migrate",
|
|
202
194
|
logMessage: (providerName, dialect) =>
|
|
@@ -217,16 +209,15 @@ export class DrizzleCommands {
|
|
|
217
209
|
name: "db:studio",
|
|
218
210
|
description: "Launch Drizzle Studio database browser",
|
|
219
211
|
summary: false,
|
|
220
|
-
flags: this.flags,
|
|
221
212
|
args: t.optional(
|
|
222
213
|
t.text({
|
|
223
214
|
title: "path",
|
|
224
215
|
description: "Path to the Alepha server entry file",
|
|
225
216
|
}),
|
|
226
217
|
),
|
|
227
|
-
handler: async ({
|
|
228
|
-
await this.runDrizzleKitCommand({
|
|
229
|
-
|
|
218
|
+
handler: async ({ root, args }) => {
|
|
219
|
+
await this.utils.runDrizzleKitCommand({
|
|
220
|
+
root,
|
|
230
221
|
args,
|
|
231
222
|
command: "studio",
|
|
232
223
|
logMessage: (providerName, dialect) =>
|
|
@@ -234,170 +225,4 @@ export class DrizzleCommands {
|
|
|
234
225
|
});
|
|
235
226
|
},
|
|
236
227
|
});
|
|
237
|
-
|
|
238
|
-
/**
|
|
239
|
-
* Run a drizzle-kit command for all database providers
|
|
240
|
-
*/
|
|
241
|
-
protected async runDrizzleKitCommand(options: {
|
|
242
|
-
flags: { root: string };
|
|
243
|
-
args?: string;
|
|
244
|
-
command: string;
|
|
245
|
-
logMessage: (providerName: string, dialect: string) => string;
|
|
246
|
-
}): Promise<void> {
|
|
247
|
-
const rootDir = join(process.cwd(), options.flags.root);
|
|
248
|
-
this.log.debug(`Using project root: ${rootDir}`);
|
|
249
|
-
|
|
250
|
-
const { alepha, entry } = await this.loadAlephaFromServerEntryFile(
|
|
251
|
-
rootDir,
|
|
252
|
-
options.args,
|
|
253
|
-
);
|
|
254
|
-
|
|
255
|
-
const kit = this.getKitFromAlepha(alepha);
|
|
256
|
-
const repositoryProvider =
|
|
257
|
-
alepha.inject<RepositoryProvider>("RepositoryProvider");
|
|
258
|
-
const accepted = new Set<string>([]);
|
|
259
|
-
|
|
260
|
-
for (const descriptor of repositoryProvider.getRepositories()) {
|
|
261
|
-
const provider = descriptor.provider;
|
|
262
|
-
const providerName = provider.name;
|
|
263
|
-
const dialect = provider.dialect;
|
|
264
|
-
|
|
265
|
-
if (accepted.has(providerName)) {
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
|
-
accepted.add(providerName);
|
|
269
|
-
|
|
270
|
-
this.log.info("");
|
|
271
|
-
this.log.info(options.logMessage(providerName, dialect));
|
|
272
|
-
|
|
273
|
-
const drizzleConfigJsPath = await this.prepareDrizzleConfig({
|
|
274
|
-
kit,
|
|
275
|
-
provider,
|
|
276
|
-
providerName,
|
|
277
|
-
providerUrl: provider.url,
|
|
278
|
-
dialect,
|
|
279
|
-
entry,
|
|
280
|
-
rootDir,
|
|
281
|
-
});
|
|
282
|
-
|
|
283
|
-
await this.runner.exec(
|
|
284
|
-
`drizzle-kit ${options.command} --config=${drizzleConfigJsPath}`,
|
|
285
|
-
);
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/**
|
|
290
|
-
* Prepare Drizzle configuration files for a provider
|
|
291
|
-
*/
|
|
292
|
-
protected async prepareDrizzleConfig(options: {
|
|
293
|
-
kit: any;
|
|
294
|
-
provider: any;
|
|
295
|
-
providerName: string;
|
|
296
|
-
providerUrl: string;
|
|
297
|
-
dialect: string;
|
|
298
|
-
entry: string;
|
|
299
|
-
rootDir: string;
|
|
300
|
-
}): Promise<string> {
|
|
301
|
-
const models = Object.keys(options.kit.getModels(options.provider));
|
|
302
|
-
const entitiesJs = this.generateEntitiesJs(
|
|
303
|
-
options.entry,
|
|
304
|
-
options.providerName,
|
|
305
|
-
models,
|
|
306
|
-
);
|
|
307
|
-
|
|
308
|
-
const entitiesJsPath = await this.runner.writeConfigFile(
|
|
309
|
-
"entities.js",
|
|
310
|
-
entitiesJs,
|
|
311
|
-
options.rootDir,
|
|
312
|
-
);
|
|
313
|
-
|
|
314
|
-
const config: Record<string, any> = {
|
|
315
|
-
schema: entitiesJsPath,
|
|
316
|
-
out: `./migrations/${options.providerName}`,
|
|
317
|
-
dialect: options.dialect,
|
|
318
|
-
dbCredentials: {
|
|
319
|
-
url: options.providerUrl,
|
|
320
|
-
},
|
|
321
|
-
};
|
|
322
|
-
|
|
323
|
-
if (options.providerName === "pglite") {
|
|
324
|
-
config.driver = "pglite";
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
const drizzleConfigJs = "export default " + JSON.stringify(config, null, 2);
|
|
328
|
-
|
|
329
|
-
return await this.runner.writeConfigFile(
|
|
330
|
-
"drizzle.config.js",
|
|
331
|
-
drizzleConfigJs,
|
|
332
|
-
options.rootDir,
|
|
333
|
-
);
|
|
334
|
-
}
|
|
335
|
-
|
|
336
|
-
/**
|
|
337
|
-
* Get DrizzleKitProvider from Alepha instance
|
|
338
|
-
*/
|
|
339
|
-
protected getKitFromAlepha(alepha: Alepha): any {
|
|
340
|
-
// biome-ignore lint/complexity/useLiteralKeys: private key
|
|
341
|
-
return alepha["registry"]
|
|
342
|
-
.values()
|
|
343
|
-
.find((it: any) => it.instance.constructor.name === "DrizzleKitProvider")
|
|
344
|
-
?.instance;
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
public async loadAlephaFromServerEntryFile(
|
|
348
|
-
rootDir?: string,
|
|
349
|
-
explicitEntry?: string,
|
|
350
|
-
): Promise<{
|
|
351
|
-
alepha: Alepha;
|
|
352
|
-
entry: string;
|
|
353
|
-
}> {
|
|
354
|
-
process.env.ALEPHA_SKIP_START = "true";
|
|
355
|
-
|
|
356
|
-
const entry = await boot.getServerEntry(rootDir, explicitEntry);
|
|
357
|
-
const mod = await tsImport(entry, {
|
|
358
|
-
parentURL: import.meta.url,
|
|
359
|
-
});
|
|
360
|
-
|
|
361
|
-
this.log.debug(`Load entry: ${entry}`);
|
|
362
|
-
|
|
363
|
-
// check if alepha is correctly exported
|
|
364
|
-
if (mod.default instanceof Alepha) {
|
|
365
|
-
return {
|
|
366
|
-
alepha: mod.default,
|
|
367
|
-
entry,
|
|
368
|
-
};
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
// else, try with global variable
|
|
372
|
-
const g: any = global;
|
|
373
|
-
if (g.__alepha) {
|
|
374
|
-
return {
|
|
375
|
-
alepha: g.__alepha,
|
|
376
|
-
entry,
|
|
377
|
-
};
|
|
378
|
-
}
|
|
379
|
-
|
|
380
|
-
throw new AlephaError(
|
|
381
|
-
`Could not find Alepha instance in entry file: ${entry}`,
|
|
382
|
-
);
|
|
383
|
-
}
|
|
384
|
-
|
|
385
|
-
protected generateEntitiesJs(
|
|
386
|
-
entry: string,
|
|
387
|
-
provider: string,
|
|
388
|
-
models: string[] = [],
|
|
389
|
-
) {
|
|
390
|
-
return `
|
|
391
|
-
import "${entry}";
|
|
392
|
-
import { DrizzleKitProvider, Repository } from "@alepha/postgres";
|
|
393
|
-
|
|
394
|
-
const alepha = globalThis.__alepha;
|
|
395
|
-
const kit = alepha.inject(DrizzleKitProvider);
|
|
396
|
-
const provider = alepha.services(Repository).find((it) => it.provider.name === "${provider}").provider;
|
|
397
|
-
const models = kit.getModels(provider);
|
|
398
|
-
|
|
399
|
-
${models.map((it: string) => `export const ${it} = models["${it}"];`).join("\n")}
|
|
400
|
-
|
|
401
|
-
`.trim();
|
|
402
|
-
}
|
|
403
228
|
}
|
|
@@ -3,7 +3,7 @@ import { $inject } from "@alepha/core";
|
|
|
3
3
|
import { ProcessRunner } from "../services/ProcessRunner.ts";
|
|
4
4
|
|
|
5
5
|
export class VerifyCommands {
|
|
6
|
-
|
|
6
|
+
protected readonly processRunner = $inject(ProcessRunner);
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Run a series of verification commands to ensure code quality and correctness.
|
|
@@ -26,10 +26,6 @@ export class VerifyCommands {
|
|
|
26
26
|
await run("alepha lint");
|
|
27
27
|
await run("alepha test");
|
|
28
28
|
await run("alepha typecheck");
|
|
29
|
-
|
|
30
|
-
// run only if migrations dir is present ?
|
|
31
|
-
//await run("alepha db:check-migrations");
|
|
32
|
-
|
|
33
29
|
await run("alepha build");
|
|
34
30
|
await run("alepha clean");
|
|
35
31
|
},
|
|
@@ -42,7 +38,7 @@ export class VerifyCommands {
|
|
|
42
38
|
name: "typecheck",
|
|
43
39
|
description: "Check TypeScript types across the codebase",
|
|
44
40
|
handler: async () => {
|
|
45
|
-
await this.
|
|
41
|
+
await this.processRunner.exec("tsc --noEmit");
|
|
46
42
|
},
|
|
47
43
|
});
|
|
48
44
|
}
|