@gadmin2n/cli 0.0.159 → 0.0.161
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/actions/prisma.action.js +66 -31
- package/package.json +2 -2
package/actions/prisma.action.js
CHANGED
|
@@ -51,36 +51,37 @@ function replaceFileContent(filePath, match, src, dest) {
|
|
|
51
51
|
}
|
|
52
52
|
class PrismaAction extends abstract_action_1.AbstractAction {
|
|
53
53
|
buildMergedSchema() {
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
54
|
+
// 读 generator 头
|
|
55
|
+
const generatorHead = fs.readFileSync('server/prisma/.generator.prisma', 'utf8');
|
|
56
|
+
// 读用户 schema 源
|
|
57
57
|
let schemaStr = '';
|
|
58
58
|
if (shell.test('-d', 'config/prisma')) {
|
|
59
|
-
schemaStr = shell.cat('config/prisma/*.prisma');
|
|
59
|
+
schemaStr = shell.cat('config/prisma/*.prisma').toString();
|
|
60
60
|
}
|
|
61
61
|
else {
|
|
62
|
-
schemaStr = shell.cat('config/schema.prisma');
|
|
62
|
+
schemaStr = shell.cat('config/schema.prisma').toString();
|
|
63
63
|
}
|
|
64
64
|
const schemaRegex = /([\s\S]*?model\s\w*\s*\{)([^\}]*)(\})/gim; // https://regex101.com/
|
|
65
|
-
let m,
|
|
65
|
+
let m, merged = '';
|
|
66
66
|
while ((m = schemaRegex.exec(schemaStr)) !== null) {
|
|
67
67
|
// This is necessary to avoid infinite loops with zero-width matches
|
|
68
68
|
if (m.index === schemaRegex.lastIndex) {
|
|
69
69
|
schemaRegex.lastIndex++;
|
|
70
70
|
}
|
|
71
71
|
let ignore = !!m[1].match(/\/\/\/\s*@IgnoreAutoField/);
|
|
72
|
-
|
|
72
|
+
merged += m[1];
|
|
73
73
|
if (!ignore) {
|
|
74
|
-
|
|
74
|
+
merged += '\n id BigInt @id @default(autoincrement())';
|
|
75
75
|
}
|
|
76
|
-
|
|
76
|
+
merged += m[2];
|
|
77
77
|
if (!ignore) {
|
|
78
|
-
|
|
78
|
+
merged +=
|
|
79
79
|
' creator String @db.VarChar(128) @map("creator")\n createdAt DateTime @default(now()) @map("created_at")\n updatedAt DateTime @updatedAt @default(now()) @map("updated_at")\n';
|
|
80
80
|
}
|
|
81
|
-
|
|
81
|
+
merged += m[3];
|
|
82
82
|
}
|
|
83
|
-
|
|
83
|
+
// 一次原子写 + diff:内容未变则完全不 touch 文件,避免任何 watcher 感知抖动。
|
|
84
|
+
return (0, sync_fs_1.writeFileIfChanged)('server/prisma/schema.prisma', generatorHead + merged);
|
|
84
85
|
}
|
|
85
86
|
handle(inputs, options) {
|
|
86
87
|
var _a, _b;
|
|
@@ -97,7 +98,10 @@ class PrismaAction extends abstract_action_1.AbstractAction {
|
|
|
97
98
|
const verbose = !!((_b = options.find((option) => option.name === 'verbose')) === null || _b === void 0 ? void 0 : _b.value);
|
|
98
99
|
// 分发过程按类别记账,收尾统一打摘要 / --verbose 打完整清单
|
|
99
100
|
const stats = {
|
|
100
|
-
|
|
101
|
+
serverGeneratedIndex: [],
|
|
102
|
+
serverGenerated: [],
|
|
103
|
+
serverGeneratedUnchanged: [],
|
|
104
|
+
serverGeneratedOrphans: [],
|
|
101
105
|
serverModulesNew: [],
|
|
102
106
|
serverModulesSkipped: [],
|
|
103
107
|
routesNew: [],
|
|
@@ -143,7 +147,8 @@ class PrismaAction extends abstract_action_1.AbstractAction {
|
|
|
143
147
|
// SERVER_STAGING/
|
|
144
148
|
// modules.index.ts → diff-copy 到 server/src/generated/modules.index.ts
|
|
145
149
|
// {model}/dto/{model}.form.validator.ts → diff-copy 到 web/src/generated/props/{model}/form.validator.ts(跨端)
|
|
146
|
-
// {model}
|
|
150
|
+
// {model}/dto/**(其余), {model}/entities/** → diff-copy 到 server/src/generated/{model}/**(权威、可被覆盖)
|
|
151
|
+
// {model}/**(其余:controller/service/module/spec) → 首次落地到 server/src/modules/{model}/**(保护用户编辑)
|
|
147
152
|
// 收集 server staging 里的 model 列表:凡有 dto/{name}.form.validator.ts 的一级子目录即视为 model
|
|
148
153
|
const stagingModels = fs.existsSync(SERVER_STAGING)
|
|
149
154
|
? fs
|
|
@@ -153,32 +158,55 @@ class PrismaAction extends abstract_action_1.AbstractAction {
|
|
|
153
158
|
.filter((name) => fs.existsSync((0, path_1.join)(SERVER_STAGING, name, 'dto', `${name}.form.validator.ts`)))
|
|
154
159
|
: [];
|
|
155
160
|
// ============ 阶段 1:server 集中写入 ============
|
|
161
|
+
const serverGeneratedKeep = new Set();
|
|
156
162
|
if (fs.existsSync(SERVER_STAGING)) {
|
|
157
|
-
// 1.1 modules.index.ts ——
|
|
163
|
+
// 1.1 modules.index.ts —— 顶层入口(放在 generated 下的顶级文件)
|
|
158
164
|
const modulesIndexSrc = (0, path_1.join)(SERVER_STAGING, 'modules.index.ts');
|
|
159
165
|
if (fs.existsSync(modulesIndexSrc)) {
|
|
160
|
-
const rel = '
|
|
161
|
-
|
|
162
|
-
|
|
166
|
+
const rel = 'modules.index.ts';
|
|
167
|
+
const dest = (0, path_1.join)('server/src/generated', rel);
|
|
168
|
+
if ((0, sync_fs_1.copyFileIfChanged)(modulesIndexSrc, dest)) {
|
|
169
|
+
stats.serverGeneratedIndex.push(dest);
|
|
163
170
|
}
|
|
171
|
+
serverGeneratedKeep.add(rel);
|
|
164
172
|
}
|
|
165
|
-
// 1.2 逐 model
|
|
173
|
+
// 1.2 逐 model 分发。dto/entities → generated(覆盖,权威),其余 → modules(首次落地)
|
|
166
174
|
for (const modelName of stagingModels) {
|
|
167
175
|
const modelStaging = (0, path_1.join)(SERVER_STAGING, modelName);
|
|
168
176
|
const validatorInStaging = (0, path_1.join)('dto', `${modelName}.form.validator.ts`);
|
|
169
177
|
for (const rel of (0, sync_fs_1.listFilesRecursive)(modelStaging)) {
|
|
170
178
|
if (rel === validatorInStaging)
|
|
171
|
-
continue;
|
|
172
|
-
const
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
179
|
+
continue; // 归 web 阶段处理
|
|
180
|
+
const isDto = rel.startsWith('dto' + path_1.sep) || rel.startsWith('dto/');
|
|
181
|
+
const isEntity = rel.startsWith('entities' + path_1.sep) ||
|
|
182
|
+
rel.startsWith('entities/');
|
|
183
|
+
if (isDto || isEntity) {
|
|
184
|
+
// 权威、每次覆盖到 server/src/generated/{model}/(controller 从这里 import)
|
|
185
|
+
const relInGenerated = (0, path_1.join)(modelName, rel);
|
|
186
|
+
const dest = (0, path_1.join)('server/src/generated', relInGenerated);
|
|
187
|
+
if ((0, sync_fs_1.copyFileIfChanged)((0, path_1.join)(modelStaging, rel), dest)) {
|
|
188
|
+
stats.serverGenerated.push(dest);
|
|
189
|
+
}
|
|
190
|
+
else {
|
|
191
|
+
stats.serverGeneratedUnchanged.push(dest);
|
|
192
|
+
}
|
|
193
|
+
serverGeneratedKeep.add(relInGenerated);
|
|
194
|
+
}
|
|
195
|
+
else {
|
|
196
|
+
// controller/service/module/spec —— 首次落地到 server/src/modules/{model}/
|
|
197
|
+
const dest = (0, path_1.join)('server/src/modules', modelName, rel);
|
|
198
|
+
if (fs.existsSync(dest)) {
|
|
199
|
+
stats.serverModulesSkipped.push(dest);
|
|
200
|
+
continue;
|
|
201
|
+
}
|
|
202
|
+
fs.mkdirSync((0, path_1.dirname)(dest), { recursive: true });
|
|
203
|
+
fs.copyFileSync((0, path_1.join)(modelStaging, rel), dest);
|
|
204
|
+
stats.serverModulesNew.push(dest);
|
|
176
205
|
}
|
|
177
|
-
fs.mkdirSync((0, path_1.dirname)(dest), { recursive: true });
|
|
178
|
-
fs.copyFileSync((0, path_1.join)(modelStaging, rel), dest);
|
|
179
|
-
stats.serverModulesNew.push(dest);
|
|
180
206
|
}
|
|
181
207
|
}
|
|
208
|
+
// 1.3 孤儿清理:删除 server/src/generated 下所有本轮未产出的文件(例如被删除的 model)
|
|
209
|
+
stats.serverGeneratedOrphans = (0, sync_fs_1.pruneOrphans)('server/src/generated', serverGeneratedKeep).map((r) => (0, path_1.join)('server/src/generated', r));
|
|
182
210
|
}
|
|
183
211
|
// ============ 阶段 2:web 集中写入 ============
|
|
184
212
|
const webKeep = new Set();
|
|
@@ -257,14 +285,18 @@ class PrismaAction extends abstract_action_1.AbstractAction {
|
|
|
257
285
|
});
|
|
258
286
|
}
|
|
259
287
|
printReport(stats, verbose) {
|
|
260
|
-
const serverWritten = stats.
|
|
288
|
+
const serverWritten = stats.serverGeneratedIndex.length +
|
|
289
|
+
stats.serverGenerated.length +
|
|
290
|
+
stats.serverModulesNew.length;
|
|
261
291
|
const webWritten = stats.generated.length + stats.routesNew.length;
|
|
262
292
|
console.log('');
|
|
263
293
|
console.log(chalk.bold('gadmin2 g prisma:'));
|
|
264
294
|
console.log(` ${chalk.cyan('server')}: ${serverWritten} written` +
|
|
265
|
-
` (index=${stats.
|
|
295
|
+
` (index=${stats.serverGeneratedIndex.length},` +
|
|
296
|
+
` generated=${stats.serverGenerated.length},` +
|
|
266
297
|
` modules-new=${stats.serverModulesNew.length}),` +
|
|
267
|
-
` ${stats.serverModulesSkipped.length}
|
|
298
|
+
` ${stats.serverGeneratedUnchanged.length + stats.serverModulesSkipped.length} unchanged,` +
|
|
299
|
+
` ${stats.serverGeneratedOrphans.length} orphan removed`);
|
|
268
300
|
console.log(` ${chalk.cyan('web')}: ${webWritten} written` +
|
|
269
301
|
` (routes-new=${stats.routesNew.length},` +
|
|
270
302
|
` generated=${stats.generated.length}),` +
|
|
@@ -281,7 +313,10 @@ class PrismaAction extends abstract_action_1.AbstractAction {
|
|
|
281
313
|
for (const p of list)
|
|
282
314
|
console.log(' ' + color(p));
|
|
283
315
|
};
|
|
284
|
-
printGroup('server modules.index (diff-write)', stats.
|
|
316
|
+
printGroup('server generated modules.index (diff-write)', stats.serverGeneratedIndex, chalk.green);
|
|
317
|
+
printGroup('server generated (written)', stats.serverGenerated, chalk.green);
|
|
318
|
+
printGroup('server generated (unchanged)', stats.serverGeneratedUnchanged, chalk.gray);
|
|
319
|
+
printGroup('server generated orphans removed', stats.serverGeneratedOrphans, chalk.red);
|
|
285
320
|
printGroup('server modules (new)', stats.serverModulesNew, chalk.green);
|
|
286
321
|
printGroup('server modules (skipped, exists)', stats.serverModulesSkipped, chalk.gray);
|
|
287
322
|
printGroup('web routes (new)', stats.routesNew, chalk.green);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gadmin2n/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.161",
|
|
4
4
|
"description": "Gadmin - modern, fast, powerful node.js web framework (@cli)",
|
|
5
5
|
"publishConfig": {
|
|
6
6
|
"access": "public"
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
"@angular-devkit/core": "13.3.2",
|
|
48
48
|
"@angular-devkit/schematics": "13.3.2",
|
|
49
49
|
"@angular-devkit/schematics-cli": "13.3.2",
|
|
50
|
-
"@gadmin2n/schematics": "^0.0.
|
|
50
|
+
"@gadmin2n/schematics": "^0.0.129",
|
|
51
51
|
"abc": "^0.6.1",
|
|
52
52
|
"chalk": "3.0.0",
|
|
53
53
|
"chokidar": "3.5.3",
|