@lark-apaas/fullstack-cli 1.1.16-alpha.8 → 1.1.16-beta.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.
- package/README.md +20 -0
- package/dist/config/drizzle.config.js +24 -1
- package/dist/index.js +1057 -509
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// src/index.ts
|
|
2
|
-
import
|
|
2
|
+
import fs21 from "fs";
|
|
3
3
|
import path17 from "path";
|
|
4
4
|
import { fileURLToPath as fileURLToPath4 } from "url";
|
|
5
5
|
import { config as dotenvConfig } from "dotenv";
|
|
@@ -63,9 +63,18 @@ var FullstackCLI = class {
|
|
|
63
63
|
constructor(version) {
|
|
64
64
|
this.program = new Command();
|
|
65
65
|
this.hooks = new HooksManager();
|
|
66
|
-
this.program.name("fullstack-cli").description("CLI tool for fullstack template management").version(version);
|
|
66
|
+
this.program.name("fullstack-cli").description("CLI tool for fullstack template management").version(version).option("--canary <env>", "Set canary environment (e.g., boe_canary)");
|
|
67
|
+
this.setupGlobalOptions();
|
|
67
68
|
this.setupDefaultHooks();
|
|
68
69
|
}
|
|
70
|
+
setupGlobalOptions() {
|
|
71
|
+
this.program.hook("preAction", (thisCommand) => {
|
|
72
|
+
const opts = thisCommand.opts();
|
|
73
|
+
if (opts.canary) {
|
|
74
|
+
process.env.FORCE_FRAMEWORK_CLI_CANARY_ENV = opts.canary;
|
|
75
|
+
}
|
|
76
|
+
});
|
|
77
|
+
}
|
|
69
78
|
setupDefaultHooks() {
|
|
70
79
|
this.hooks.afterRun((ctx, error) => {
|
|
71
80
|
if (error) {
|
|
@@ -117,104 +126,94 @@ Command "${ctx.commandName}" completed in ${elapsed}ms`);
|
|
|
117
126
|
|
|
118
127
|
// src/commands/db/schema.handler.ts
|
|
119
128
|
import path2 from "path";
|
|
120
|
-
import
|
|
129
|
+
import fs4 from "fs";
|
|
121
130
|
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
122
131
|
import { spawnSync } from "child_process";
|
|
123
132
|
import { createRequire } from "module";
|
|
124
133
|
import { config as loadEnv } from "dotenv";
|
|
125
134
|
|
|
135
|
+
// src/commands/db/gen-dbschema/index.ts
|
|
136
|
+
import fs3 from "fs";
|
|
137
|
+
import path from "path";
|
|
138
|
+
|
|
126
139
|
// src/commands/db/gen-dbschema/postprocess.ts
|
|
127
140
|
import fs2 from "fs";
|
|
128
|
-
import path from "path";
|
|
129
141
|
|
|
130
|
-
// src/commands/db/gen-dbschema/
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
142
|
+
// src/commands/db/gen-dbschema/transforms/core.ts
|
|
143
|
+
import { IndentationText, Project, QuoteKind } from "ts-morph";
|
|
144
|
+
|
|
145
|
+
// src/commands/db/gen-dbschema/transforms/types.ts
|
|
146
|
+
function createEmptyStats() {
|
|
147
|
+
return {
|
|
148
|
+
patchedDefects: 0,
|
|
149
|
+
removedPgSchemas: 0,
|
|
150
|
+
convertedSchemaCalls: 0,
|
|
151
|
+
renamedIdentifiers: [],
|
|
152
|
+
replacedUnknown: 0,
|
|
153
|
+
fallbackToText: 0,
|
|
154
|
+
unmatchedUnknown: [],
|
|
155
|
+
replacedTimestamp: 0,
|
|
156
|
+
replacedDefaultNow: 0,
|
|
157
|
+
removedSystemFields: 0,
|
|
158
|
+
addedImports: [],
|
|
159
|
+
removedImports: []
|
|
160
|
+
};
|
|
145
161
|
}
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
162
|
+
|
|
163
|
+
// src/commands/db/gen-dbschema/transforms/core.ts
|
|
164
|
+
var PROJECT_OPTIONS = {
|
|
165
|
+
skipAddingFilesFromTsConfig: true,
|
|
166
|
+
skipFileDependencyResolution: true,
|
|
167
|
+
manipulationSettings: {
|
|
168
|
+
indentationText: IndentationText.TwoSpaces,
|
|
169
|
+
quoteKind: QuoteKind.Single
|
|
150
170
|
}
|
|
151
|
-
|
|
171
|
+
};
|
|
172
|
+
function parseSource(source, fileName = "schema.ts") {
|
|
173
|
+
const project = new Project({
|
|
174
|
+
...PROJECT_OPTIONS,
|
|
175
|
+
useInMemoryFileSystem: true
|
|
176
|
+
});
|
|
177
|
+
const sourceFile = project.createSourceFile(fileName, source);
|
|
178
|
+
return { project, sourceFile };
|
|
152
179
|
}
|
|
153
|
-
function
|
|
154
|
-
|
|
180
|
+
function applyTransforms(sourceFile, transforms) {
|
|
181
|
+
const stats = createEmptyStats();
|
|
182
|
+
for (const transform of transforms) {
|
|
183
|
+
try {
|
|
184
|
+
transform.transform({ sourceFile, stats });
|
|
185
|
+
} catch (error) {
|
|
186
|
+
console.error(`[ast] Transform "${transform.name}" failed:`, error);
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
return stats;
|
|
155
191
|
}
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
}
|
|
161
|
-
function convertSchemaTableInvocations(source) {
|
|
162
|
-
let converted = 0;
|
|
163
|
-
let text = source.replace(/([A-Za-z0-9_]+)\.table\(/g, () => {
|
|
164
|
-
converted += 1;
|
|
165
|
-
return "pgTable(";
|
|
166
|
-
});
|
|
167
|
-
text = text.replace(/([A-Za-z0-9_]+)\.view\(/g, () => {
|
|
168
|
-
converted += 1;
|
|
169
|
-
return "pgView(";
|
|
170
|
-
});
|
|
171
|
-
text = text.replace(/([A-Za-z0-9_]+)\.materializedView\(/g, () => {
|
|
172
|
-
converted += 1;
|
|
173
|
-
return "pgMaterializedView(";
|
|
192
|
+
function formatSourceFile(sourceFile) {
|
|
193
|
+
sourceFile.formatText({
|
|
194
|
+
indentSize: 2,
|
|
195
|
+
convertTabsToSpaces: true
|
|
174
196
|
});
|
|
175
|
-
text = text.replace(/([A-Za-z0-9_]+)\.enum\(/g, () => {
|
|
176
|
-
converted += 1;
|
|
177
|
-
return "pgEnum(";
|
|
178
|
-
});
|
|
179
|
-
text = text.replace(/([A-Za-z0-9_]+)\.sequence\(/g, () => {
|
|
180
|
-
converted += 1;
|
|
181
|
-
return "pgSequence(";
|
|
182
|
-
});
|
|
183
|
-
return { text, converted };
|
|
184
197
|
}
|
|
198
|
+
function printSourceFile(sourceFile) {
|
|
199
|
+
return sourceFile.getFullText();
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
// src/commands/db/gen-dbschema/transforms/ast/rename-identifiers.ts
|
|
203
|
+
import { Node } from "ts-morph";
|
|
185
204
|
|
|
186
|
-
// src/commands/db/gen-dbschema/
|
|
205
|
+
// src/commands/db/gen-dbschema/utils/identifier.ts
|
|
187
206
|
import { pinyin } from "pinyin-pro";
|
|
188
|
-
function
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
const equalsIndex = match.indexOf("=");
|
|
198
|
-
const suffix = equalsIndex >= 0 ? match.slice(equalsIndex) : ` = ${factory}("${tableName}"`;
|
|
199
|
-
const normalizedSuffix = suffix.trimStart();
|
|
200
|
-
return `export const ${sanitized} ${normalizedSuffix}`;
|
|
201
|
-
});
|
|
202
|
-
return { text: updated, renames };
|
|
203
|
-
}
|
|
204
|
-
function updateTableReferenceIdentifiers(source, renames) {
|
|
205
|
-
if (renames.length === 0) {
|
|
206
|
-
return source;
|
|
207
|
+
function toAsciiName(name) {
|
|
208
|
+
if (!/[^\x00-\x7F]/.test(name)) {
|
|
209
|
+
return name;
|
|
210
|
+
}
|
|
211
|
+
try {
|
|
212
|
+
const transliterated = pinyin(name, { toneType: "none", type: "array" }).join("_");
|
|
213
|
+
return transliterated || name;
|
|
214
|
+
} catch {
|
|
215
|
+
return name;
|
|
207
216
|
}
|
|
208
|
-
return renames.reduce((acc, rename) => {
|
|
209
|
-
if (!rename.from || rename.from === rename.to) {
|
|
210
|
-
return acc;
|
|
211
|
-
}
|
|
212
|
-
const pattern = new RegExp(`\\b${escapeRegExp(rename.from)}(\\s*\\.)`, "g");
|
|
213
|
-
return acc.replace(pattern, `${rename.to}$1`);
|
|
214
|
-
}, source);
|
|
215
|
-
}
|
|
216
|
-
function escapeRegExp(value) {
|
|
217
|
-
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&").replace(/\//g, "\\/");
|
|
218
217
|
}
|
|
219
218
|
function toCamelCase(str) {
|
|
220
219
|
const words = str.split(/[_\-\s]+/).filter(Boolean);
|
|
@@ -242,120 +241,722 @@ function sanitizeIdentifier(name) {
|
|
|
242
241
|
}
|
|
243
242
|
return sanitized;
|
|
244
243
|
}
|
|
245
|
-
function
|
|
246
|
-
|
|
247
|
-
|
|
244
|
+
function getUniqueIdentifier(name, usedIdentifiers) {
|
|
245
|
+
const base = sanitizeIdentifier(name);
|
|
246
|
+
if (!usedIdentifiers.has(base)) {
|
|
247
|
+
usedIdentifiers.add(base);
|
|
248
|
+
return base;
|
|
248
249
|
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
} catch (error) {
|
|
253
|
-
return name;
|
|
250
|
+
let suffix = 2;
|
|
251
|
+
while (usedIdentifiers.has(`${base}${suffix}`)) {
|
|
252
|
+
suffix++;
|
|
254
253
|
}
|
|
254
|
+
const unique = `${base}${suffix}`;
|
|
255
|
+
usedIdentifiers.add(unique);
|
|
256
|
+
return unique;
|
|
255
257
|
}
|
|
256
258
|
|
|
257
|
-
// src/commands/db/gen-dbschema/
|
|
258
|
-
var
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
259
|
+
// src/commands/db/gen-dbschema/transforms/ast/rename-identifiers.ts
|
|
260
|
+
var PG_FACTORIES = [
|
|
261
|
+
"pgTable",
|
|
262
|
+
"pgView",
|
|
263
|
+
"pgMaterializedView",
|
|
264
|
+
"pgEnum",
|
|
265
|
+
"pgSequence",
|
|
266
|
+
// Also match schema.xxx() format (before conversion)
|
|
267
|
+
"table",
|
|
268
|
+
"view",
|
|
269
|
+
"materializedView",
|
|
270
|
+
"enum",
|
|
271
|
+
"sequence"
|
|
272
|
+
];
|
|
273
|
+
function extractFactoryName(initializer) {
|
|
274
|
+
if (!Node.isCallExpression(initializer)) {
|
|
275
|
+
return void 0;
|
|
276
|
+
}
|
|
277
|
+
const args = initializer.getArguments();
|
|
278
|
+
if (args.length === 0) {
|
|
279
|
+
return void 0;
|
|
280
|
+
}
|
|
281
|
+
const firstArg = args[0];
|
|
282
|
+
if (Node.isStringLiteral(firstArg)) {
|
|
283
|
+
return firstArg.getLiteralText();
|
|
284
|
+
}
|
|
285
|
+
return void 0;
|
|
286
|
+
}
|
|
287
|
+
function isPgFactoryCall(initializer) {
|
|
288
|
+
if (!Node.isCallExpression(initializer)) {
|
|
289
|
+
return false;
|
|
290
|
+
}
|
|
291
|
+
const expression = initializer.getExpression();
|
|
292
|
+
const exprText = expression.getText();
|
|
293
|
+
if (PG_FACTORIES.includes(exprText)) {
|
|
294
|
+
return true;
|
|
295
|
+
}
|
|
296
|
+
if (Node.isPropertyAccessExpression(expression)) {
|
|
297
|
+
const propName = expression.getName();
|
|
298
|
+
if (PG_FACTORIES.includes(propName)) {
|
|
299
|
+
return true;
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
return false;
|
|
303
|
+
}
|
|
304
|
+
function getCurrentName(decl) {
|
|
305
|
+
const name = decl.getName();
|
|
306
|
+
return name.replace(/^"|"$/g, "");
|
|
307
|
+
}
|
|
308
|
+
function collectExistingIdentifiers(ctx) {
|
|
309
|
+
const { sourceFile } = ctx;
|
|
310
|
+
const identifiers = /* @__PURE__ */ new Set();
|
|
311
|
+
for (const statement of sourceFile.getStatements()) {
|
|
312
|
+
if (!Node.isVariableStatement(statement)) {
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
for (const decl of statement.getDeclarations()) {
|
|
316
|
+
const name = getCurrentName(decl);
|
|
317
|
+
if (name) {
|
|
318
|
+
identifiers.add(name);
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
return identifiers;
|
|
323
|
+
}
|
|
324
|
+
var renameIdentifiersTransform = {
|
|
325
|
+
name: "rename-identifiers",
|
|
326
|
+
transform(ctx) {
|
|
327
|
+
const { sourceFile, stats } = ctx;
|
|
328
|
+
const usedIdentifiers = collectExistingIdentifiers(ctx);
|
|
329
|
+
const renames = [];
|
|
330
|
+
for (const statement of sourceFile.getStatements()) {
|
|
331
|
+
if (!Node.isVariableStatement(statement)) {
|
|
332
|
+
continue;
|
|
333
|
+
}
|
|
334
|
+
if (!statement.hasExportKeyword()) {
|
|
335
|
+
continue;
|
|
336
|
+
}
|
|
337
|
+
for (const decl of statement.getDeclarations()) {
|
|
338
|
+
const initializer = decl.getInitializer();
|
|
339
|
+
if (!initializer) {
|
|
340
|
+
continue;
|
|
341
|
+
}
|
|
342
|
+
if (!isPgFactoryCall(initializer)) {
|
|
343
|
+
continue;
|
|
344
|
+
}
|
|
345
|
+
const tableName = extractFactoryName(initializer);
|
|
346
|
+
if (!tableName) {
|
|
347
|
+
continue;
|
|
348
|
+
}
|
|
349
|
+
const currentName = getCurrentName(decl);
|
|
350
|
+
const baseSanitized = sanitizeIdentifier(tableName);
|
|
351
|
+
if (baseSanitized === currentName) {
|
|
352
|
+
continue;
|
|
353
|
+
}
|
|
354
|
+
usedIdentifiers.delete(currentName);
|
|
355
|
+
const sanitized = getUniqueIdentifier(tableName, usedIdentifiers);
|
|
356
|
+
renames.push({ decl, from: currentName, to: sanitized });
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
for (const { decl, from, to } of renames.reverse()) {
|
|
360
|
+
try {
|
|
361
|
+
decl.rename(to);
|
|
362
|
+
stats.renamedIdentifiers.push({ from, to });
|
|
363
|
+
} catch (error) {
|
|
364
|
+
console.warn(`[rename-identifiers] Failed to rename "${from}" to "${to}":`, error);
|
|
365
|
+
}
|
|
366
|
+
}
|
|
367
|
+
stats.renamedIdentifiers.reverse();
|
|
368
|
+
}
|
|
369
|
+
};
|
|
370
|
+
|
|
371
|
+
// src/commands/db/gen-dbschema/transforms/ast/remove-pg-schema.ts
|
|
372
|
+
import { Node as Node2 } from "ts-morph";
|
|
373
|
+
var removePgSchemaTransform = {
|
|
374
|
+
name: "remove-pg-schema",
|
|
375
|
+
transform(ctx) {
|
|
376
|
+
const { sourceFile, stats } = ctx;
|
|
377
|
+
const statementsToRemove = [];
|
|
378
|
+
for (const statement of sourceFile.getStatements()) {
|
|
379
|
+
if (!Node2.isVariableStatement(statement)) {
|
|
380
|
+
continue;
|
|
381
|
+
}
|
|
382
|
+
for (const decl of statement.getDeclarations()) {
|
|
383
|
+
const initializer = decl.getInitializer();
|
|
384
|
+
if (!initializer || !Node2.isCallExpression(initializer)) {
|
|
385
|
+
continue;
|
|
386
|
+
}
|
|
387
|
+
const calleeText = initializer.getExpression().getText();
|
|
388
|
+
if (calleeText === "pgSchema") {
|
|
389
|
+
statementsToRemove.push(statement);
|
|
390
|
+
stats.removedPgSchemas++;
|
|
391
|
+
break;
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
for (const statement of statementsToRemove.reverse()) {
|
|
396
|
+
statement.remove();
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
// src/commands/db/gen-dbschema/transforms/ast/convert-schema-calls.ts
|
|
402
|
+
import { Node as Node3 } from "ts-morph";
|
|
403
|
+
var SCHEMA_METHOD_TO_PG = {
|
|
404
|
+
table: "pgTable",
|
|
405
|
+
view: "pgView",
|
|
406
|
+
materializedView: "pgMaterializedView",
|
|
407
|
+
enum: "pgEnum",
|
|
408
|
+
sequence: "pgSequence"
|
|
409
|
+
};
|
|
410
|
+
var convertSchemaCallsTransform = {
|
|
411
|
+
name: "convert-schema-calls",
|
|
412
|
+
transform(ctx) {
|
|
413
|
+
const { sourceFile, stats } = ctx;
|
|
414
|
+
sourceFile.forEachDescendant((node) => {
|
|
415
|
+
if (!Node3.isCallExpression(node)) {
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
418
|
+
const expression = node.getExpression();
|
|
419
|
+
if (!Node3.isPropertyAccessExpression(expression)) {
|
|
420
|
+
return;
|
|
421
|
+
}
|
|
422
|
+
const objectExpr = expression.getExpression();
|
|
423
|
+
const methodName = expression.getName();
|
|
424
|
+
const pgFactoryName = SCHEMA_METHOD_TO_PG[methodName];
|
|
425
|
+
if (!pgFactoryName) {
|
|
426
|
+
return;
|
|
427
|
+
}
|
|
428
|
+
if (!Node3.isIdentifier(objectExpr)) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
expression.replaceWithText(pgFactoryName);
|
|
432
|
+
stats.convertedSchemaCalls++;
|
|
433
|
+
});
|
|
434
|
+
}
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
// src/commands/db/gen-dbschema/transforms/ast/patch-defects.ts
|
|
438
|
+
import { Node as Node4 } from "ts-morph";
|
|
439
|
+
var patchDefectsTransform = {
|
|
440
|
+
name: "patch-defects",
|
|
441
|
+
transform(ctx) {
|
|
442
|
+
const { sourceFile, stats } = ctx;
|
|
443
|
+
sourceFile.forEachDescendant((node) => {
|
|
444
|
+
if (!Node4.isCallExpression(node)) {
|
|
445
|
+
return;
|
|
446
|
+
}
|
|
447
|
+
const expr = node.getExpression();
|
|
448
|
+
if (!Node4.isPropertyAccessExpression(expr)) {
|
|
449
|
+
return;
|
|
450
|
+
}
|
|
451
|
+
if (expr.getName() !== "default") {
|
|
452
|
+
return;
|
|
453
|
+
}
|
|
454
|
+
const args = node.getArguments();
|
|
455
|
+
if (args.length !== 1) {
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
const arg = args[0];
|
|
459
|
+
if (Node4.isStringLiteral(arg)) {
|
|
460
|
+
const text = arg.getLiteralText();
|
|
461
|
+
if (text === "") {
|
|
462
|
+
stats.patchedDefects++;
|
|
463
|
+
}
|
|
464
|
+
}
|
|
465
|
+
});
|
|
466
|
+
}
|
|
467
|
+
};
|
|
468
|
+
|
|
469
|
+
// src/commands/db/gen-dbschema/transforms/ast/replace-unknown.ts
|
|
470
|
+
import { Node as Node5 } from "ts-morph";
|
|
471
|
+
var KNOWN_TYPE_FACTORIES = {
|
|
472
|
+
user_profile: "userProfile",
|
|
473
|
+
file_attachment: "fileAttachment"
|
|
474
|
+
};
|
|
475
|
+
var replaceUnknownTransform = {
|
|
476
|
+
name: "replace-unknown",
|
|
477
|
+
transform(ctx) {
|
|
478
|
+
const { sourceFile, stats } = ctx;
|
|
479
|
+
const fullText = sourceFile.getFullText();
|
|
480
|
+
sourceFile.forEachDescendant((node) => {
|
|
481
|
+
if (!Node5.isCallExpression(node)) {
|
|
482
|
+
return;
|
|
483
|
+
}
|
|
484
|
+
const expression = node.getExpression();
|
|
485
|
+
if (!Node5.isIdentifier(expression) || expression.getText() !== "unknown") {
|
|
486
|
+
return;
|
|
487
|
+
}
|
|
488
|
+
const nodeStart = node.getStart();
|
|
489
|
+
const textBefore = fullText.slice(Math.max(0, nodeStart - 500), nodeStart);
|
|
490
|
+
const lines = textBefore.split("\n");
|
|
491
|
+
let factoryName = "text";
|
|
492
|
+
let foundKnownType = false;
|
|
493
|
+
for (let i = lines.length - 1; i >= Math.max(0, lines.length - 5); i--) {
|
|
494
|
+
const line = lines[i];
|
|
495
|
+
const todoMatch = line.match(/\/\/ TODO: failed to parse database type '(?:\w+\.)?([\w_]+)(\[\])?'/);
|
|
496
|
+
if (todoMatch) {
|
|
497
|
+
const typeName = todoMatch[1];
|
|
498
|
+
if (KNOWN_TYPE_FACTORIES[typeName]) {
|
|
499
|
+
factoryName = KNOWN_TYPE_FACTORIES[typeName];
|
|
500
|
+
foundKnownType = true;
|
|
501
|
+
}
|
|
502
|
+
break;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
expression.replaceWithText(factoryName);
|
|
506
|
+
if (foundKnownType) {
|
|
507
|
+
stats.replacedUnknown++;
|
|
275
508
|
} else {
|
|
276
|
-
|
|
277
|
-
result.push(line);
|
|
509
|
+
stats.fallbackToText++;
|
|
278
510
|
}
|
|
511
|
+
});
|
|
512
|
+
const todoCommentRegex = /\/\/ TODO: failed to parse database type '[^']+'\s*\n/g;
|
|
513
|
+
const currentText = sourceFile.getFullText();
|
|
514
|
+
const cleanedText = currentText.replace(todoCommentRegex, "");
|
|
515
|
+
if (cleanedText !== currentText) {
|
|
516
|
+
sourceFile.replaceWithText(cleanedText);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
};
|
|
520
|
+
|
|
521
|
+
// src/commands/db/gen-dbschema/transforms/ast/replace-timestamp.ts
|
|
522
|
+
import { Node as Node6 } from "ts-morph";
|
|
523
|
+
function checkTimestampOptions(optionsArg) {
|
|
524
|
+
let hasWithTimezone = false;
|
|
525
|
+
let hasModeString = false;
|
|
526
|
+
for (const prop of optionsArg.getProperties()) {
|
|
527
|
+
if (!Node6.isPropertyAssignment(prop)) {
|
|
279
528
|
continue;
|
|
280
529
|
}
|
|
281
|
-
|
|
282
|
-
|
|
530
|
+
const propName = prop.getName();
|
|
531
|
+
const initializer = prop.getInitializer();
|
|
532
|
+
if (propName === "withTimezone") {
|
|
533
|
+
if (Node6.isTrueLiteral(initializer)) {
|
|
534
|
+
hasWithTimezone = true;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
if (propName === "mode") {
|
|
538
|
+
if (Node6.isStringLiteral(initializer) && initializer.getLiteralText() === "string") {
|
|
539
|
+
hasModeString = true;
|
|
540
|
+
}
|
|
283
541
|
}
|
|
284
|
-
result.push(line);
|
|
285
542
|
}
|
|
286
|
-
return
|
|
287
|
-
text: result.join("\n"),
|
|
288
|
-
replaced,
|
|
289
|
-
unmatched
|
|
290
|
-
};
|
|
543
|
+
return hasWithTimezone && hasModeString;
|
|
291
544
|
}
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
545
|
+
var replaceTimestampTransform = {
|
|
546
|
+
name: "replace-timestamp",
|
|
547
|
+
transform(ctx) {
|
|
548
|
+
const { sourceFile, stats } = ctx;
|
|
549
|
+
const replacements = [];
|
|
550
|
+
sourceFile.forEachDescendant((node) => {
|
|
551
|
+
if (!Node6.isCallExpression(node)) {
|
|
552
|
+
return;
|
|
553
|
+
}
|
|
554
|
+
const expression = node.getExpression();
|
|
555
|
+
if (!Node6.isIdentifier(expression) || expression.getText() !== "timestamp") {
|
|
556
|
+
return;
|
|
557
|
+
}
|
|
558
|
+
const args = node.getArguments();
|
|
559
|
+
if (args.length === 2) {
|
|
560
|
+
const [fieldArg, optionsArg] = args;
|
|
561
|
+
if (!Node6.isStringLiteral(fieldArg)) {
|
|
562
|
+
return;
|
|
563
|
+
}
|
|
564
|
+
if (!Node6.isObjectLiteralExpression(optionsArg)) {
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (checkTimestampOptions(optionsArg)) {
|
|
568
|
+
const quote = fieldArg.getQuoteKind() === 1 ? '"' : "'";
|
|
569
|
+
const fieldName = fieldArg.getLiteralText();
|
|
570
|
+
replacements.push({
|
|
571
|
+
node,
|
|
572
|
+
replacement: `customTimestamptz(${quote}${fieldName}${quote})`
|
|
573
|
+
});
|
|
574
|
+
}
|
|
575
|
+
return;
|
|
576
|
+
}
|
|
577
|
+
if (args.length === 1) {
|
|
578
|
+
const [optionsArg] = args;
|
|
579
|
+
if (!Node6.isObjectLiteralExpression(optionsArg)) {
|
|
580
|
+
return;
|
|
581
|
+
}
|
|
582
|
+
if (checkTimestampOptions(optionsArg)) {
|
|
583
|
+
replacements.push({
|
|
584
|
+
node,
|
|
585
|
+
replacement: "customTimestamptz()"
|
|
586
|
+
});
|
|
587
|
+
}
|
|
588
|
+
return;
|
|
589
|
+
}
|
|
590
|
+
});
|
|
591
|
+
for (const { node, replacement } of replacements.reverse()) {
|
|
592
|
+
node.replaceWithText(replacement);
|
|
593
|
+
stats.replacedTimestamp++;
|
|
594
|
+
}
|
|
295
595
|
}
|
|
296
|
-
|
|
297
|
-
}
|
|
596
|
+
};
|
|
298
597
|
|
|
299
|
-
// src/commands/db/gen-dbschema/
|
|
300
|
-
import
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
598
|
+
// src/commands/db/gen-dbschema/transforms/ast/replace-default-now.ts
|
|
599
|
+
import { Node as Node7 } from "ts-morph";
|
|
600
|
+
var replaceDefaultNowTransform = {
|
|
601
|
+
name: "replace-default-now",
|
|
602
|
+
transform(ctx) {
|
|
603
|
+
const { sourceFile, stats } = ctx;
|
|
604
|
+
sourceFile.forEachDescendant((node) => {
|
|
605
|
+
if (!Node7.isCallExpression(node)) {
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
const expression = node.getExpression();
|
|
609
|
+
if (!Node7.isPropertyAccessExpression(expression)) {
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
if (expression.getName() !== "defaultNow") {
|
|
613
|
+
return;
|
|
614
|
+
}
|
|
615
|
+
if (node.getArguments().length !== 0) {
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
const objectExpr = expression.getExpression();
|
|
619
|
+
const objectText = objectExpr.getText();
|
|
620
|
+
node.replaceWithText(`${objectText}.default(sql\`CURRENT_TIMESTAMP\`)`);
|
|
621
|
+
stats.replacedDefaultNow++;
|
|
622
|
+
});
|
|
307
623
|
}
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
624
|
+
};
|
|
625
|
+
|
|
626
|
+
// src/commands/db/gen-dbschema/transforms/ast/remove-system-fields.ts
|
|
627
|
+
import { Node as Node8 } from "ts-morph";
|
|
628
|
+
var SYSTEM_TO_BUSINESS = {
|
|
629
|
+
_created_at: ["created_at", "createdAt"],
|
|
630
|
+
_created_by: ["created_by", "createdBy"],
|
|
631
|
+
_updated_at: ["updated_at", "updatedAt"],
|
|
632
|
+
_updated_by: ["updated_by", "updatedBy"]
|
|
633
|
+
};
|
|
634
|
+
var SYSTEM_FIELD_COLUMNS = new Set(Object.keys(SYSTEM_TO_BUSINESS));
|
|
635
|
+
var TABLE_FACTORIES = ["pgTable", "pgView", "pgMaterializedView", "table", "view", "materializedView"];
|
|
636
|
+
function extractColumnName(prop) {
|
|
637
|
+
const initializer = prop.getInitializer();
|
|
638
|
+
if (!initializer) return void 0;
|
|
639
|
+
let callExpr = initializer;
|
|
640
|
+
while (Node8.isCallExpression(callExpr)) {
|
|
641
|
+
const expr = callExpr.getExpression();
|
|
642
|
+
if (Node8.isPropertyAccessExpression(expr)) {
|
|
643
|
+
const baseExpr = expr.getExpression();
|
|
644
|
+
if (Node8.isCallExpression(baseExpr)) {
|
|
645
|
+
callExpr = baseExpr;
|
|
646
|
+
continue;
|
|
647
|
+
}
|
|
313
648
|
}
|
|
314
|
-
|
|
315
|
-
});
|
|
316
|
-
if (source.includes("pgTable(") && !filteredIdentifiers.includes("pgTable")) {
|
|
317
|
-
filteredIdentifiers.push("pgTable");
|
|
649
|
+
break;
|
|
318
650
|
}
|
|
319
|
-
if (
|
|
320
|
-
|
|
651
|
+
if (!Node8.isCallExpression(callExpr)) return void 0;
|
|
652
|
+
const args = callExpr.getArguments();
|
|
653
|
+
if (args.length === 0) return void 0;
|
|
654
|
+
const firstArg = args[0];
|
|
655
|
+
if (Node8.isStringLiteral(firstArg)) {
|
|
656
|
+
return firstArg.getLiteralText();
|
|
321
657
|
}
|
|
322
|
-
|
|
323
|
-
|
|
658
|
+
return void 0;
|
|
659
|
+
}
|
|
660
|
+
function getPropertyName(prop) {
|
|
661
|
+
const nameNode = prop.getNameNode();
|
|
662
|
+
if (Node8.isStringLiteral(nameNode)) {
|
|
663
|
+
return nameNode.getLiteralText();
|
|
664
|
+
} else if (Node8.isIdentifier(nameNode)) {
|
|
665
|
+
return nameNode.getText();
|
|
666
|
+
}
|
|
667
|
+
return "";
|
|
668
|
+
}
|
|
669
|
+
var removeSystemFieldsTransform = {
|
|
670
|
+
name: "remove-system-fields",
|
|
671
|
+
transform(ctx) {
|
|
672
|
+
const { sourceFile, stats } = ctx;
|
|
673
|
+
sourceFile.forEachDescendant((node) => {
|
|
674
|
+
if (!Node8.isCallExpression(node)) {
|
|
675
|
+
return;
|
|
676
|
+
}
|
|
677
|
+
const expression = node.getExpression();
|
|
678
|
+
let factoryName = "";
|
|
679
|
+
if (Node8.isIdentifier(expression)) {
|
|
680
|
+
factoryName = expression.getText();
|
|
681
|
+
} else if (Node8.isPropertyAccessExpression(expression)) {
|
|
682
|
+
factoryName = expression.getName();
|
|
683
|
+
}
|
|
684
|
+
if (!TABLE_FACTORIES.includes(factoryName)) {
|
|
685
|
+
return;
|
|
686
|
+
}
|
|
687
|
+
const args = node.getArguments();
|
|
688
|
+
if (args.length < 2) {
|
|
689
|
+
return;
|
|
690
|
+
}
|
|
691
|
+
const columnsArg = args[1];
|
|
692
|
+
if (!Node8.isObjectLiteralExpression(columnsArg)) {
|
|
693
|
+
return;
|
|
694
|
+
}
|
|
695
|
+
const properties = columnsArg.getProperties();
|
|
696
|
+
const systemFieldProps = /* @__PURE__ */ new Map();
|
|
697
|
+
for (const prop of properties) {
|
|
698
|
+
if (!Node8.isPropertyAssignment(prop)) {
|
|
699
|
+
continue;
|
|
700
|
+
}
|
|
701
|
+
const propName = getPropertyName(prop);
|
|
702
|
+
const columnName = extractColumnName(prop);
|
|
703
|
+
const systemFieldKey = SYSTEM_FIELD_COLUMNS.has(propName) ? propName : columnName && SYSTEM_FIELD_COLUMNS.has(columnName) ? columnName : null;
|
|
704
|
+
if (systemFieldKey) {
|
|
705
|
+
systemFieldProps.set(prop, systemFieldKey);
|
|
706
|
+
}
|
|
707
|
+
}
|
|
708
|
+
const businessPropertyNames = /* @__PURE__ */ new Set();
|
|
709
|
+
const businessColumnNames = /* @__PURE__ */ new Set();
|
|
710
|
+
for (const prop of properties) {
|
|
711
|
+
if (!Node8.isPropertyAssignment(prop)) {
|
|
712
|
+
continue;
|
|
713
|
+
}
|
|
714
|
+
if (systemFieldProps.has(prop)) {
|
|
715
|
+
continue;
|
|
716
|
+
}
|
|
717
|
+
const propName = getPropertyName(prop);
|
|
718
|
+
if (propName) {
|
|
719
|
+
businessPropertyNames.add(propName);
|
|
720
|
+
}
|
|
721
|
+
const columnName = extractColumnName(prop);
|
|
722
|
+
if (columnName) {
|
|
723
|
+
businessColumnNames.add(columnName);
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
const propsToRemove = [];
|
|
727
|
+
for (const [prop, systemFieldKey] of systemFieldProps) {
|
|
728
|
+
const businessFields = SYSTEM_TO_BUSINESS[systemFieldKey];
|
|
729
|
+
if (!businessFields) {
|
|
730
|
+
continue;
|
|
731
|
+
}
|
|
732
|
+
const hasBusinessField = businessFields.some(
|
|
733
|
+
(bf) => businessPropertyNames.has(bf) || businessColumnNames.has(bf)
|
|
734
|
+
);
|
|
735
|
+
if (hasBusinessField) {
|
|
736
|
+
propsToRemove.push(prop);
|
|
737
|
+
}
|
|
738
|
+
}
|
|
739
|
+
for (const prop of propsToRemove) {
|
|
740
|
+
prop.remove();
|
|
741
|
+
stats.removedSystemFields++;
|
|
742
|
+
}
|
|
743
|
+
});
|
|
324
744
|
}
|
|
325
|
-
|
|
326
|
-
|
|
745
|
+
};
|
|
746
|
+
|
|
747
|
+
// src/commands/db/gen-dbschema/transforms/ast/tweak-imports.ts
|
|
748
|
+
var REMOVE_IMPORTS = ["pgSchema", "customType"];
|
|
749
|
+
var PG_FACTORIES2 = ["pgTable", "pgView", "pgMaterializedView", "pgEnum", "pgSequence"];
|
|
750
|
+
var tweakImportsTransform = {
|
|
751
|
+
name: "tweak-imports",
|
|
752
|
+
transform(ctx) {
|
|
753
|
+
const { sourceFile, stats } = ctx;
|
|
754
|
+
const fullText = sourceFile.getFullText();
|
|
755
|
+
const imports = sourceFile.getImportDeclarations();
|
|
756
|
+
const pgCoreImport = imports.find((imp) => {
|
|
757
|
+
const moduleSpec = imp.getModuleSpecifierValue();
|
|
758
|
+
return moduleSpec === "drizzle-orm/pg-core";
|
|
759
|
+
});
|
|
760
|
+
if (!pgCoreImport) {
|
|
761
|
+
return;
|
|
762
|
+
}
|
|
763
|
+
const namedImports = pgCoreImport.getNamedImports();
|
|
764
|
+
const currentImports = namedImports.map((ni) => ni.getName());
|
|
765
|
+
const toRemove = [];
|
|
766
|
+
const toAdd = [];
|
|
767
|
+
for (const identifier of REMOVE_IMPORTS) {
|
|
768
|
+
if (currentImports.includes(identifier)) {
|
|
769
|
+
toRemove.push(identifier);
|
|
770
|
+
stats.removedImports.push(identifier);
|
|
771
|
+
}
|
|
772
|
+
}
|
|
773
|
+
if (currentImports.includes("timestamp")) {
|
|
774
|
+
const timestampUsed = /timestamp\s*\(/.test(fullText);
|
|
775
|
+
if (!timestampUsed) {
|
|
776
|
+
toRemove.push("timestamp");
|
|
777
|
+
stats.removedImports.push("timestamp");
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
for (const factory of PG_FACTORIES2) {
|
|
781
|
+
if (!currentImports.includes(factory)) {
|
|
782
|
+
const pattern = new RegExp(`${factory}\\s*\\(`);
|
|
783
|
+
if (pattern.test(fullText)) {
|
|
784
|
+
toAdd.push(factory);
|
|
785
|
+
stats.addedImports.push(factory);
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
}
|
|
789
|
+
for (const identifier of toRemove) {
|
|
790
|
+
const freshNamedImports = pgCoreImport.getNamedImports();
|
|
791
|
+
const namedImport = freshNamedImports.find((ni) => ni.getName() === identifier);
|
|
792
|
+
if (namedImport) {
|
|
793
|
+
namedImport.remove();
|
|
794
|
+
}
|
|
795
|
+
}
|
|
796
|
+
for (const identifier of toAdd) {
|
|
797
|
+
pgCoreImport.addNamedImport(identifier);
|
|
798
|
+
}
|
|
799
|
+
if (fullText.includes("sql`CURRENT_TIMESTAMP`")) {
|
|
800
|
+
const drizzleOrmImport = imports.find((imp) => {
|
|
801
|
+
const moduleSpec = imp.getModuleSpecifierValue();
|
|
802
|
+
return moduleSpec === "drizzle-orm";
|
|
803
|
+
});
|
|
804
|
+
if (!drizzleOrmImport) {
|
|
805
|
+
sourceFile.addImportDeclaration({
|
|
806
|
+
moduleSpecifier: "drizzle-orm",
|
|
807
|
+
namedImports: ["sql"]
|
|
808
|
+
});
|
|
809
|
+
stats.addedImports.push("sql");
|
|
810
|
+
} else {
|
|
811
|
+
const hasSql = drizzleOrmImport.getNamedImports().some((ni) => ni.getName() === "sql");
|
|
812
|
+
if (!hasSql) {
|
|
813
|
+
drizzleOrmImport.addNamedImport("sql");
|
|
814
|
+
stats.addedImports.push("sql");
|
|
815
|
+
}
|
|
816
|
+
}
|
|
817
|
+
}
|
|
327
818
|
}
|
|
328
|
-
|
|
329
|
-
|
|
819
|
+
};
|
|
820
|
+
|
|
821
|
+
// src/commands/db/gen-dbschema/transforms/ast/index.ts
|
|
822
|
+
var defaultTransforms = [
|
|
823
|
+
patchDefectsTransform,
|
|
824
|
+
// #2 Fix syntax errors first
|
|
825
|
+
removePgSchemaTransform,
|
|
826
|
+
// #3 Remove pgSchema declarations
|
|
827
|
+
convertSchemaCallsTransform,
|
|
828
|
+
// #4 Convert schema.xxx() to pgXxx()
|
|
829
|
+
renameIdentifiersTransform,
|
|
830
|
+
// #5+#6 Rename identifiers (auto-updates refs)
|
|
831
|
+
replaceUnknownTransform,
|
|
832
|
+
// #7 Replace unknown types
|
|
833
|
+
replaceTimestampTransform,
|
|
834
|
+
// #8 Replace timestamp
|
|
835
|
+
replaceDefaultNowTransform,
|
|
836
|
+
// #9 Replace .defaultNow()
|
|
837
|
+
removeSystemFieldsTransform,
|
|
838
|
+
// #10 Remove conflicting system fields
|
|
839
|
+
tweakImportsTransform
|
|
840
|
+
// #12 Adjust imports
|
|
841
|
+
];
|
|
842
|
+
|
|
843
|
+
// src/commands/db/gen-dbschema/transforms/text/patch-defects.ts
|
|
844
|
+
function collectExistingIdentifiers2(source) {
|
|
845
|
+
const identifiers = /* @__PURE__ */ new Set();
|
|
846
|
+
const exportPattern = /export\s+const\s+([a-zA-Z_$][a-zA-Z0-9_$]*)\s*=/g;
|
|
847
|
+
let match;
|
|
848
|
+
while ((match = exportPattern.exec(source)) !== null) {
|
|
849
|
+
identifiers.add(match[1]);
|
|
330
850
|
}
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
851
|
+
return identifiers;
|
|
852
|
+
}
|
|
853
|
+
function patchDefects(source) {
|
|
854
|
+
let fixed = 0;
|
|
855
|
+
const renamedQuotedExports = [];
|
|
856
|
+
let text = source;
|
|
857
|
+
const usedIdentifiers = collectExistingIdentifiers2(source);
|
|
858
|
+
text = text.replace(/\.default\('\)/g, () => {
|
|
859
|
+
fixed += 1;
|
|
860
|
+
return `.default('')`;
|
|
861
|
+
});
|
|
862
|
+
const quotedExportPattern = /export const\s+"([^"]+)"\s*=/g;
|
|
863
|
+
text = text.replace(quotedExportPattern, (_match, quotedName) => {
|
|
864
|
+
const sanitized = getUniqueIdentifier(quotedName, usedIdentifiers);
|
|
865
|
+
renamedQuotedExports.push({ from: quotedName, to: sanitized });
|
|
866
|
+
fixed += 1;
|
|
867
|
+
return `export const ${sanitized} =`;
|
|
868
|
+
});
|
|
869
|
+
for (const { from, to } of renamedQuotedExports) {
|
|
870
|
+
const escaped = from.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
871
|
+
const callPattern = new RegExp(`"${escaped}"\\s*\\(`, "g");
|
|
872
|
+
text = text.replace(callPattern, `${to}(`);
|
|
873
|
+
const dotPattern = new RegExp(`"${escaped}"\\s*\\.`, "g");
|
|
874
|
+
text = text.replace(dotPattern, `${to}.`);
|
|
875
|
+
}
|
|
876
|
+
return { text, fixed, renamedQuotedExports };
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
// src/commands/db/gen-dbschema/transforms/text/header.ts
|
|
880
|
+
var ESLINT_DISABLE = "/* eslint-disable */";
|
|
881
|
+
var HEADER_COMMENT = "/** auto generated, do not edit */";
|
|
882
|
+
var FULL_HEADER = `${ESLINT_DISABLE}
|
|
883
|
+
${HEADER_COMMENT}`;
|
|
884
|
+
function ensureHeader(source) {
|
|
885
|
+
let trimmed = source;
|
|
886
|
+
const headerPatterns = [
|
|
887
|
+
/^\/\*\s*eslint-disable\s*\*\/\s*\n?/,
|
|
888
|
+
/^\/\*\*\s*auto generated[^*]*\*\/\s*\n?/
|
|
889
|
+
];
|
|
890
|
+
for (const pattern of headerPatterns) {
|
|
891
|
+
while (pattern.test(trimmed)) {
|
|
892
|
+
trimmed = trimmed.replace(pattern, "");
|
|
893
|
+
}
|
|
894
|
+
}
|
|
895
|
+
trimmed = trimmed.trimStart();
|
|
896
|
+
return `${FULL_HEADER}
|
|
897
|
+
${trimmed}`;
|
|
898
|
+
}
|
|
899
|
+
|
|
900
|
+
// src/commands/db/gen-dbschema/transforms/text/system-comments.ts
|
|
901
|
+
var SYSTEM_FIELD_COMMENTS = {
|
|
902
|
+
_created_at: "Creation time",
|
|
903
|
+
_created_by: "Creator",
|
|
904
|
+
_updated_at: "Update time",
|
|
905
|
+
_updated_by: "Updater"
|
|
906
|
+
};
|
|
907
|
+
function addSystemFieldComments(source) {
|
|
908
|
+
const lines = source.split("\n");
|
|
909
|
+
for (let i = 0; i < lines.length; i += 1) {
|
|
910
|
+
const line = lines[i];
|
|
911
|
+
const entry = Object.entries(SYSTEM_FIELD_COMMENTS).find(
|
|
912
|
+
([key]) => line.includes(`"${key}"`) || line.includes(`'${key}'`)
|
|
913
|
+
);
|
|
914
|
+
if (!entry) {
|
|
915
|
+
continue;
|
|
916
|
+
}
|
|
917
|
+
const [, description] = entry;
|
|
918
|
+
const previousLine = lines[i - 1]?.trim() ?? "";
|
|
919
|
+
if (previousLine.startsWith("//") && previousLine.includes("System field")) {
|
|
920
|
+
continue;
|
|
921
|
+
}
|
|
922
|
+
const indentMatch = line.match(/^\s*/);
|
|
923
|
+
const indent = indentMatch ? indentMatch[0] : "";
|
|
924
|
+
const comment = `${indent}// System field: ${description} (auto-filled, do not modify)`;
|
|
925
|
+
lines.splice(i, 0, comment);
|
|
926
|
+
i += 1;
|
|
927
|
+
}
|
|
928
|
+
return lines.join("\n");
|
|
334
929
|
}
|
|
930
|
+
|
|
931
|
+
// src/commands/db/gen-dbschema/transforms/text/inline-types.ts
|
|
932
|
+
import fs from "fs";
|
|
933
|
+
import { fileURLToPath } from "url";
|
|
335
934
|
function inlineCustomTypes(source) {
|
|
336
|
-
|
|
935
|
+
let text = source.replace(/import \{[^}]*\} from ["']\.\/types["'];?\n*/g, "");
|
|
337
936
|
const templatePath = resolveTemplateTypesPath();
|
|
338
937
|
if (!templatePath) {
|
|
339
|
-
console.warn("[
|
|
938
|
+
console.warn("[text/inline-types] Template types file not found.");
|
|
340
939
|
return text;
|
|
341
940
|
}
|
|
342
|
-
|
|
941
|
+
const templateContent = fs.readFileSync(templatePath, "utf8");
|
|
942
|
+
return inlineFromTemplate(text, templateContent);
|
|
343
943
|
}
|
|
344
|
-
function
|
|
944
|
+
function inlineFromTemplate(source, templateContent) {
|
|
345
945
|
const typeDefinitions = templateContent.replace(/^import\s+.*;\r?\n*/gm, "").trim();
|
|
946
|
+
let text = source;
|
|
346
947
|
const needsSql = typeDefinitions.includes("sql`") && !text.includes("from 'drizzle-orm'") && !text.includes('from "drizzle-orm"');
|
|
347
948
|
const needsCustomType = typeDefinitions.includes("customType<") && !text.includes("customType");
|
|
348
949
|
if (needsCustomType) {
|
|
349
950
|
text = ensureImportIdentifier(text, "drizzle-orm/pg-core", "customType");
|
|
350
951
|
}
|
|
351
|
-
if (needsSql
|
|
952
|
+
if (needsSql) {
|
|
352
953
|
const importMatch = text.match(/^import [\s\S]*?from ["']drizzle-orm\/pg-core["'];?\n/m);
|
|
353
954
|
if (importMatch) {
|
|
354
955
|
const insertPoint = text.indexOf(importMatch[0]) + importMatch[0].length;
|
|
355
956
|
text = text.slice(0, insertPoint) + "import { sql } from 'drizzle-orm';\n" + text.slice(insertPoint);
|
|
356
957
|
}
|
|
357
958
|
}
|
|
358
|
-
const headerPrefix = `${
|
|
959
|
+
const headerPrefix = `${FULL_HEADER}
|
|
359
960
|
`;
|
|
360
961
|
let insertionPoint = 0;
|
|
361
962
|
if (text.startsWith(headerPrefix)) {
|
|
@@ -389,7 +990,10 @@ function ensureImportIdentifier(source, packageName, identifier) {
|
|
|
389
990
|
}
|
|
390
991
|
function resolveTemplateTypesPath() {
|
|
391
992
|
const candidates = [
|
|
993
|
+
// Source code paths (relative to transforms/text/)
|
|
994
|
+
new URL("../../template/types.ts", import.meta.url),
|
|
392
995
|
new URL("../template/types.ts", import.meta.url),
|
|
996
|
+
// Bundled path (relative to dist/index.js)
|
|
393
997
|
new URL("./gen-dbschema-template/types.ts", import.meta.url)
|
|
394
998
|
];
|
|
395
999
|
for (const url of candidates) {
|
|
@@ -401,131 +1005,9 @@ function resolveTemplateTypesPath() {
|
|
|
401
1005
|
return void 0;
|
|
402
1006
|
}
|
|
403
1007
|
|
|
404
|
-
// src/commands/db/gen-dbschema/
|
|
405
|
-
function addSystemFieldComments(source) {
|
|
406
|
-
const commentMap = {
|
|
407
|
-
"_created_at": "Creation time",
|
|
408
|
-
"_created_by": "Creator",
|
|
409
|
-
"_updated_at": "Update time",
|
|
410
|
-
"_updated_by": "Updater"
|
|
411
|
-
};
|
|
412
|
-
const lines = source.split("\n");
|
|
413
|
-
for (let i = 0; i < lines.length; i += 1) {
|
|
414
|
-
const line = lines[i];
|
|
415
|
-
const entry = Object.entries(commentMap).find(([key]) => line.includes(`"${key}"`));
|
|
416
|
-
if (!entry) {
|
|
417
|
-
continue;
|
|
418
|
-
}
|
|
419
|
-
const [, description] = entry;
|
|
420
|
-
const previousLine = lines[i - 1]?.trim() ?? "";
|
|
421
|
-
if (previousLine.startsWith("//") && previousLine.includes("System field")) {
|
|
422
|
-
continue;
|
|
423
|
-
}
|
|
424
|
-
const indentMatch = line.match(/^\s*/);
|
|
425
|
-
const indent = indentMatch ? indentMatch[0] : "";
|
|
426
|
-
const comment = `${indent}// System field: ${description} (auto-filled, do not modify)`;
|
|
427
|
-
lines.splice(i, 0, comment);
|
|
428
|
-
i += 1;
|
|
429
|
-
}
|
|
430
|
-
return lines.join("\n");
|
|
431
|
-
}
|
|
432
|
-
function removeConflictingSystemFields(source) {
|
|
433
|
-
const systemFieldMap = {
|
|
434
|
-
"_created_at": "created_at",
|
|
435
|
-
"_created_by": "created_by",
|
|
436
|
-
"_updated_at": "updated_at",
|
|
437
|
-
"_updated_by": "updated_by"
|
|
438
|
-
};
|
|
439
|
-
const lines = source.split("\n");
|
|
440
|
-
const result = [];
|
|
441
|
-
let inTable = false;
|
|
442
|
-
let tableStartLine = -1;
|
|
443
|
-
const tableBusinessFields = /* @__PURE__ */ new Set();
|
|
444
|
-
let bracketDepth = 0;
|
|
445
|
-
for (let i = 0; i < lines.length; i += 1) {
|
|
446
|
-
const line = lines[i];
|
|
447
|
-
if (!inTable && /=\s*(pgTable|pgView|pgMaterializedView)\s*\(/.test(line)) {
|
|
448
|
-
inTable = true;
|
|
449
|
-
tableStartLine = result.length;
|
|
450
|
-
tableBusinessFields.clear();
|
|
451
|
-
bracketDepth = 0;
|
|
452
|
-
}
|
|
453
|
-
if (inTable) {
|
|
454
|
-
for (const char of line) {
|
|
455
|
-
if (char === "{") bracketDepth++;
|
|
456
|
-
if (char === "}") bracketDepth--;
|
|
457
|
-
}
|
|
458
|
-
for (const businessField of Object.values(systemFieldMap)) {
|
|
459
|
-
if (line.includes(`"${businessField}"`) || line.includes(`'${businessField}'`)) {
|
|
460
|
-
tableBusinessFields.add(businessField);
|
|
461
|
-
}
|
|
462
|
-
}
|
|
463
|
-
if (bracketDepth === 0 && line.includes(");")) {
|
|
464
|
-
inTable = false;
|
|
465
|
-
const tableEndLine = result.length;
|
|
466
|
-
for (let j = tableStartLine; j <= tableEndLine; j++) {
|
|
467
|
-
const tableLine = result[j] || "";
|
|
468
|
-
let shouldRemove = false;
|
|
469
|
-
for (const [systemField, businessField] of Object.entries(systemFieldMap)) {
|
|
470
|
-
if (tableBusinessFields.has(businessField)) {
|
|
471
|
-
if (tableLine.includes(`"${systemField}"`) || tableLine.includes(`'${systemField}'`)) {
|
|
472
|
-
shouldRemove = true;
|
|
473
|
-
if (j > 0 && result[j - 1]?.includes("// System field:")) {
|
|
474
|
-
result[j - 1] = null;
|
|
475
|
-
}
|
|
476
|
-
break;
|
|
477
|
-
}
|
|
478
|
-
}
|
|
479
|
-
}
|
|
480
|
-
if (shouldRemove) {
|
|
481
|
-
result[j] = null;
|
|
482
|
-
}
|
|
483
|
-
}
|
|
484
|
-
}
|
|
485
|
-
}
|
|
486
|
-
result.push(line);
|
|
487
|
-
}
|
|
488
|
-
return result.filter((line) => line !== null).join("\n");
|
|
489
|
-
}
|
|
490
|
-
|
|
491
|
-
// src/commands/db/gen-dbschema/helper/patch-helper.ts
|
|
492
|
-
function patchDrizzleKitDefects(source) {
|
|
493
|
-
let fixed = 0;
|
|
494
|
-
const text = source.replace(/\.default\('\)/g, () => {
|
|
495
|
-
fixed += 1;
|
|
496
|
-
return `.default('')`;
|
|
497
|
-
});
|
|
498
|
-
return { text, fixed };
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
// src/commands/db/gen-dbschema/helper/timestamp-replacement.ts
|
|
502
|
-
function replaceTimestampWithCustomTypes(source) {
|
|
503
|
-
let replaced = 0;
|
|
504
|
-
const pattern = /timestamp\((['"])(.*?)\1,\s*(\{[^}]*\})\)/g;
|
|
505
|
-
const text = source.replace(pattern, (match, quote, fieldName, options) => {
|
|
506
|
-
const hasWithTimezone = /withTimezone:\s*true/.test(options);
|
|
507
|
-
const hasModeString = /mode:\s*['"]string['"]/.test(options);
|
|
508
|
-
if (hasWithTimezone && hasModeString) {
|
|
509
|
-
replaced += 1;
|
|
510
|
-
return `customTimestamptz(${quote}${fieldName}${quote})`;
|
|
511
|
-
}
|
|
512
|
-
return match;
|
|
513
|
-
});
|
|
514
|
-
return { text, replaced };
|
|
515
|
-
}
|
|
516
|
-
function replaceDefaultNowWithSql(source) {
|
|
517
|
-
let replaced = 0;
|
|
518
|
-
const pattern = /\.defaultNow\(\)/g;
|
|
519
|
-
const text = source.replace(pattern, () => {
|
|
520
|
-
replaced += 1;
|
|
521
|
-
return ".default(sql`CURRENT_TIMESTAMP`)";
|
|
522
|
-
});
|
|
523
|
-
return { text, replaced };
|
|
524
|
-
}
|
|
525
|
-
|
|
526
|
-
// src/commands/db/gen-dbschema/helper/appendTableAliases.ts
|
|
1008
|
+
// src/commands/db/gen-dbschema/transforms/text/table-aliases.ts
|
|
527
1009
|
var TABLE_ALIAS_MARKER = "// table aliases";
|
|
528
|
-
function
|
|
1010
|
+
function generateTableAliases(source) {
|
|
529
1011
|
const markerIndex = source.indexOf(`
|
|
530
1012
|
${TABLE_ALIAS_MARKER}`);
|
|
531
1013
|
const base = markerIndex === -1 ? source : source.slice(0, markerIndex);
|
|
@@ -547,62 +1029,100 @@ ${aliasLines}
|
|
|
547
1029
|
`;
|
|
548
1030
|
}
|
|
549
1031
|
|
|
1032
|
+
// src/commands/db/gen-dbschema/transforms/text/format.ts
|
|
1033
|
+
function formatSource(source) {
|
|
1034
|
+
let text = source;
|
|
1035
|
+
text = text.replace(/\r\n/g, "\n");
|
|
1036
|
+
text = text.replace(/\n{3,}/g, "\n\n");
|
|
1037
|
+
if (!text.endsWith("\n")) {
|
|
1038
|
+
text += "\n";
|
|
1039
|
+
}
|
|
1040
|
+
return text;
|
|
1041
|
+
}
|
|
1042
|
+
|
|
550
1043
|
// src/commands/db/gen-dbschema/postprocess.ts
|
|
1044
|
+
function postprocessSchema(rawSource) {
|
|
1045
|
+
const patchResult = patchDefects(rawSource);
|
|
1046
|
+
let source = patchResult.text;
|
|
1047
|
+
const { sourceFile } = parseSource(source);
|
|
1048
|
+
const astStats = applyTransforms(sourceFile, defaultTransforms);
|
|
1049
|
+
formatSourceFile(sourceFile);
|
|
1050
|
+
source = printSourceFile(sourceFile);
|
|
1051
|
+
source = ensureHeader(source);
|
|
1052
|
+
source = addSystemFieldComments(source);
|
|
1053
|
+
source = inlineCustomTypes(source);
|
|
1054
|
+
source = generateTableAliases(source);
|
|
1055
|
+
source = formatSource(source);
|
|
1056
|
+
return {
|
|
1057
|
+
source,
|
|
1058
|
+
astStats,
|
|
1059
|
+
patchedDefects: patchResult.fixed
|
|
1060
|
+
};
|
|
1061
|
+
}
|
|
1062
|
+
function logStats(result, prefix = "[postprocess]") {
|
|
1063
|
+
const { astStats, patchedDefects } = result;
|
|
1064
|
+
if (patchedDefects > 0) {
|
|
1065
|
+
console.info(`${prefix} Patched ${patchedDefects} syntax defects`);
|
|
1066
|
+
}
|
|
1067
|
+
if (astStats.removedPgSchemas > 0) {
|
|
1068
|
+
console.info(`${prefix} Removed ${astStats.removedPgSchemas} pgSchema declarations`);
|
|
1069
|
+
}
|
|
1070
|
+
if (astStats.convertedSchemaCalls > 0) {
|
|
1071
|
+
console.info(`${prefix} Converted ${astStats.convertedSchemaCalls} schema.xxx() calls`);
|
|
1072
|
+
}
|
|
1073
|
+
if (astStats.renamedIdentifiers.length > 0) {
|
|
1074
|
+
console.info(`${prefix} Renamed ${astStats.renamedIdentifiers.length} identifiers:`);
|
|
1075
|
+
for (const { from, to } of astStats.renamedIdentifiers) {
|
|
1076
|
+
console.info(`${prefix} ${from} -> ${to}`);
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
if (astStats.replacedUnknown > 0) {
|
|
1080
|
+
console.info(`${prefix} Replaced ${astStats.replacedUnknown} unknown types with custom types`);
|
|
1081
|
+
}
|
|
1082
|
+
if (astStats.fallbackToText > 0) {
|
|
1083
|
+
console.info(`${prefix} Replaced ${astStats.fallbackToText} unknown types with text (fallback)`);
|
|
1084
|
+
}
|
|
1085
|
+
if (astStats.unmatchedUnknown.length > 0) {
|
|
1086
|
+
console.warn(`${prefix} Unmatched unknown types:`);
|
|
1087
|
+
for (const line of astStats.unmatchedUnknown) {
|
|
1088
|
+
console.warn(`${prefix} ${line}`);
|
|
1089
|
+
}
|
|
1090
|
+
}
|
|
1091
|
+
if (astStats.replacedTimestamp > 0) {
|
|
1092
|
+
console.info(`${prefix} Replaced ${astStats.replacedTimestamp} timestamp with customTimestamptz`);
|
|
1093
|
+
}
|
|
1094
|
+
if (astStats.replacedDefaultNow > 0) {
|
|
1095
|
+
console.info(`${prefix} Replaced ${astStats.replacedDefaultNow} .defaultNow() calls`);
|
|
1096
|
+
}
|
|
1097
|
+
if (astStats.removedSystemFields > 0) {
|
|
1098
|
+
console.info(`${prefix} Removed ${astStats.removedSystemFields} conflicting system fields`);
|
|
1099
|
+
}
|
|
1100
|
+
if (astStats.addedImports.length > 0) {
|
|
1101
|
+
console.info(`${prefix} Added imports: ${astStats.addedImports.join(", ")}`);
|
|
1102
|
+
}
|
|
1103
|
+
if (astStats.removedImports.length > 0) {
|
|
1104
|
+
console.info(`${prefix} Removed imports: ${astStats.removedImports.join(", ")}`);
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
// src/commands/db/gen-dbschema/index.ts
|
|
551
1109
|
function postprocessDrizzleSchema(targetPath) {
|
|
552
1110
|
const resolvedPath = path.resolve(targetPath);
|
|
553
|
-
if (!
|
|
1111
|
+
if (!fs3.existsSync(resolvedPath)) {
|
|
554
1112
|
console.warn(`[postprocess-drizzle-schema] File not found: ${resolvedPath}`);
|
|
555
1113
|
return void 0;
|
|
556
1114
|
}
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
text = removePgSchemaDeclarations(text);
|
|
562
|
-
const tableConversion = convertSchemaTableInvocations(text);
|
|
563
|
-
text = tableConversion.text;
|
|
564
|
-
const renameResult = renamePgTableConstants(text);
|
|
565
|
-
text = renameResult.text;
|
|
566
|
-
text = updateTableReferenceIdentifiers(text, renameResult.renames);
|
|
567
|
-
const replacement = replaceUnknownColumns(text);
|
|
568
|
-
text = replacement.text;
|
|
569
|
-
const timestampReplacement = replaceTimestampWithCustomTypes(text);
|
|
570
|
-
text = timestampReplacement.text;
|
|
571
|
-
const defaultNowReplacement = replaceDefaultNowWithSql(text);
|
|
572
|
-
text = defaultNowReplacement.text;
|
|
573
|
-
text = removeConflictingSystemFields(text);
|
|
574
|
-
text = addSystemFieldComments(text);
|
|
575
|
-
text = tweakImports(text);
|
|
576
|
-
text = inlineCustomTypes(text);
|
|
577
|
-
text = appendTableAliases(text);
|
|
578
|
-
text = text.replace(/\r?\n/g, "\n");
|
|
579
|
-
text = collapseExtraBlankLines(text);
|
|
580
|
-
fs2.writeFileSync(resolvedPath, text, "utf8");
|
|
581
|
-
if (patchResult.fixed > 0) {
|
|
582
|
-
console.info(`[postprocess-drizzle-schema] Patched ${patchResult.fixed} drizzle-kit defects (.default(') -> .default(''))`);
|
|
583
|
-
}
|
|
584
|
-
if (replacement.replaced > 0) {
|
|
585
|
-
console.info(`[postprocess-drizzle-schema] Replaced ${replacement.replaced} unknown columns`);
|
|
586
|
-
}
|
|
587
|
-
if (replacement.unmatched.length > 0) {
|
|
588
|
-
console.warn("[postprocess-drizzle-schema] Unmatched custom types:", replacement.unmatched.length);
|
|
589
|
-
replacement.unmatched.forEach((line) => console.warn(` ${line}`));
|
|
590
|
-
}
|
|
591
|
-
if (tableConversion.converted > 0) {
|
|
592
|
-
console.info(`[postprocess-drizzle-schema] Converted ${tableConversion.converted} schema.table invocations to pgTable`);
|
|
593
|
-
}
|
|
594
|
-
if (timestampReplacement.replaced > 0) {
|
|
595
|
-
console.info(`[postprocess-drizzle-schema] Replaced ${timestampReplacement.replaced} timestamp fields with customTimestamptz`);
|
|
596
|
-
}
|
|
597
|
-
if (defaultNowReplacement.replaced > 0) {
|
|
598
|
-
console.info(`[postprocess-drizzle-schema] Replaced ${defaultNowReplacement.replaced} .defaultNow() with .default(sql\`CURRENT_TIMESTAMP\`)`);
|
|
599
|
-
}
|
|
1115
|
+
const rawSource = fs3.readFileSync(resolvedPath, "utf8");
|
|
1116
|
+
const result = postprocessSchema(rawSource);
|
|
1117
|
+
fs3.writeFileSync(resolvedPath, result.source, "utf8");
|
|
1118
|
+
logStats(result, "[postprocess-drizzle-schema]");
|
|
600
1119
|
return {
|
|
601
|
-
replacedUnknown:
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
1120
|
+
replacedUnknown: result.astStats.replacedUnknown,
|
|
1121
|
+
fallbackToText: result.astStats.fallbackToText,
|
|
1122
|
+
unmatchedUnknown: result.astStats.unmatchedUnknown,
|
|
1123
|
+
patchedDefects: result.patchedDefects,
|
|
1124
|
+
replacedTimestamps: result.astStats.replacedTimestamp,
|
|
1125
|
+
replacedDefaultNow: result.astStats.replacedDefaultNow
|
|
606
1126
|
};
|
|
607
1127
|
}
|
|
608
1128
|
|
|
@@ -1024,10 +1544,10 @@ export class ${className}Module {}
|
|
|
1024
1544
|
}
|
|
1025
1545
|
|
|
1026
1546
|
// src/commands/db/gen-nest-resource/schema-parser.ts
|
|
1027
|
-
import { Project, Node } from "ts-morph";
|
|
1547
|
+
import { Project as Project2, Node as Node9 } from "ts-morph";
|
|
1028
1548
|
var DrizzleSchemaParser = class {
|
|
1029
1549
|
constructor(projectOptions) {
|
|
1030
|
-
this.project = new
|
|
1550
|
+
this.project = new Project2(projectOptions);
|
|
1031
1551
|
}
|
|
1032
1552
|
parseSchemaFile(filePath) {
|
|
1033
1553
|
const sourceFile = this.project.addSourceFileAtPath(filePath);
|
|
@@ -1037,7 +1557,7 @@ var DrizzleSchemaParser = class {
|
|
|
1037
1557
|
const declarations = statement.getDeclarations();
|
|
1038
1558
|
for (const declaration of declarations) {
|
|
1039
1559
|
const initializer = declaration.getInitializer();
|
|
1040
|
-
if (initializer &&
|
|
1560
|
+
if (initializer && Node9.isCallExpression(initializer)) {
|
|
1041
1561
|
const expression = initializer.getExpression();
|
|
1042
1562
|
if (expression.getText() === "pgTable") {
|
|
1043
1563
|
const tableInfo = this.parsePgTable(
|
|
@@ -1060,13 +1580,13 @@ var DrizzleSchemaParser = class {
|
|
|
1060
1580
|
}
|
|
1061
1581
|
const tableName = args[0].getText().replace(/['"]/g, "");
|
|
1062
1582
|
const fieldsArg = args[1];
|
|
1063
|
-
if (!
|
|
1583
|
+
if (!Node9.isObjectLiteralExpression(fieldsArg)) {
|
|
1064
1584
|
return null;
|
|
1065
1585
|
}
|
|
1066
1586
|
const fields = [];
|
|
1067
1587
|
const properties = fieldsArg.getProperties();
|
|
1068
1588
|
for (const prop of properties) {
|
|
1069
|
-
if (
|
|
1589
|
+
if (Node9.isPropertyAssignment(prop)) {
|
|
1070
1590
|
const fieldName = prop.getName();
|
|
1071
1591
|
const initializer = prop.getInitializer();
|
|
1072
1592
|
const leadingComments = prop.getLeadingCommentRanges();
|
|
@@ -1074,7 +1594,7 @@ var DrizzleSchemaParser = class {
|
|
|
1074
1594
|
if (leadingComments.length > 0) {
|
|
1075
1595
|
comment = leadingComments.map((c) => c.getText()).join("\n").replace(/\/\//g, "").trim();
|
|
1076
1596
|
}
|
|
1077
|
-
if (initializer &&
|
|
1597
|
+
if (initializer && Node9.isCallExpression(initializer)) {
|
|
1078
1598
|
const fieldInfo = this.parseField(fieldName, initializer, comment);
|
|
1079
1599
|
fields.push(fieldInfo);
|
|
1080
1600
|
}
|
|
@@ -1106,10 +1626,10 @@ var DrizzleSchemaParser = class {
|
|
|
1106
1626
|
parseBaseType(callExpr, fieldInfo) {
|
|
1107
1627
|
let current = callExpr;
|
|
1108
1628
|
let baseCall = null;
|
|
1109
|
-
while (
|
|
1629
|
+
while (Node9.isCallExpression(current)) {
|
|
1110
1630
|
baseCall = current;
|
|
1111
1631
|
const expression2 = current.getExpression();
|
|
1112
|
-
if (
|
|
1632
|
+
if (Node9.isPropertyAccessExpression(expression2)) {
|
|
1113
1633
|
current = expression2.getExpression();
|
|
1114
1634
|
} else {
|
|
1115
1635
|
break;
|
|
@@ -1120,7 +1640,7 @@ var DrizzleSchemaParser = class {
|
|
|
1120
1640
|
}
|
|
1121
1641
|
const expression = baseCall.getExpression();
|
|
1122
1642
|
let typeName = "";
|
|
1123
|
-
if (
|
|
1643
|
+
if (Node9.isPropertyAccessExpression(expression)) {
|
|
1124
1644
|
typeName = expression.getName();
|
|
1125
1645
|
} else {
|
|
1126
1646
|
typeName = expression.getText();
|
|
@@ -1129,25 +1649,25 @@ var DrizzleSchemaParser = class {
|
|
|
1129
1649
|
const args = baseCall.getArguments();
|
|
1130
1650
|
if (args.length > 0) {
|
|
1131
1651
|
const firstArg = args[0];
|
|
1132
|
-
if (
|
|
1652
|
+
if (Node9.isStringLiteral(firstArg)) {
|
|
1133
1653
|
fieldInfo.columnName = firstArg.getLiteralText();
|
|
1134
|
-
} else if (
|
|
1654
|
+
} else if (Node9.isObjectLiteralExpression(firstArg)) {
|
|
1135
1655
|
this.parseTypeConfig(firstArg, fieldInfo);
|
|
1136
|
-
} else if (
|
|
1656
|
+
} else if (Node9.isArrayLiteralExpression(firstArg)) {
|
|
1137
1657
|
fieldInfo.enumValues = firstArg.getElements().map((el) => el.getText().replace(/['"]/g, ""));
|
|
1138
1658
|
}
|
|
1139
1659
|
}
|
|
1140
|
-
if (args.length > 1 &&
|
|
1660
|
+
if (args.length > 1 && Node9.isObjectLiteralExpression(args[1])) {
|
|
1141
1661
|
this.parseTypeConfig(args[1], fieldInfo);
|
|
1142
1662
|
}
|
|
1143
1663
|
}
|
|
1144
1664
|
parseTypeConfig(objLiteral, fieldInfo) {
|
|
1145
|
-
if (!
|
|
1665
|
+
if (!Node9.isObjectLiteralExpression(objLiteral)) {
|
|
1146
1666
|
return;
|
|
1147
1667
|
}
|
|
1148
1668
|
const properties = objLiteral.getProperties();
|
|
1149
1669
|
for (const prop of properties) {
|
|
1150
|
-
if (
|
|
1670
|
+
if (Node9.isPropertyAssignment(prop)) {
|
|
1151
1671
|
const propName = prop.getName();
|
|
1152
1672
|
const value = prop.getInitializer()?.getText();
|
|
1153
1673
|
switch (propName) {
|
|
@@ -1179,9 +1699,9 @@ var DrizzleSchemaParser = class {
|
|
|
1179
1699
|
}
|
|
1180
1700
|
parseCallChain(callExpr, fieldInfo) {
|
|
1181
1701
|
let current = callExpr;
|
|
1182
|
-
while (
|
|
1702
|
+
while (Node9.isCallExpression(current)) {
|
|
1183
1703
|
const expression = current.getExpression();
|
|
1184
|
-
if (
|
|
1704
|
+
if (Node9.isPropertyAccessExpression(expression)) {
|
|
1185
1705
|
const methodName = expression.getName();
|
|
1186
1706
|
const args = current.getArguments();
|
|
1187
1707
|
switch (methodName) {
|
|
@@ -1278,7 +1798,7 @@ var require2 = createRequire(import.meta.url);
|
|
|
1278
1798
|
async function run(options = {}) {
|
|
1279
1799
|
let exitCode = 0;
|
|
1280
1800
|
const envPath2 = path2.resolve(process.cwd(), ".env");
|
|
1281
|
-
if (
|
|
1801
|
+
if (fs4.existsSync(envPath2)) {
|
|
1282
1802
|
loadEnv({ path: envPath2 });
|
|
1283
1803
|
console.log("[gen-db-schema] \u2713 Loaded .env file");
|
|
1284
1804
|
}
|
|
@@ -1298,7 +1818,7 @@ async function run(options = {}) {
|
|
|
1298
1818
|
path2.resolve(__dirname2, "../../config/drizzle.config.js"),
|
|
1299
1819
|
path2.resolve(__dirname2, "../../../dist/config/drizzle.config.js")
|
|
1300
1820
|
];
|
|
1301
|
-
const configPath = configPathCandidates.find((p) =>
|
|
1821
|
+
const configPath = configPathCandidates.find((p) => fs4.existsSync(p));
|
|
1302
1822
|
console.log("[gen-db-schema] Using drizzle config from:", configPath ?? "(not found)");
|
|
1303
1823
|
if (!configPath) {
|
|
1304
1824
|
console.error("[gen-db-schema] Error: drizzle config not found in CLI package");
|
|
@@ -1310,8 +1830,8 @@ async function run(options = {}) {
|
|
|
1310
1830
|
let lastDir = null;
|
|
1311
1831
|
while (currentDir !== lastDir) {
|
|
1312
1832
|
const pkgJsonPath = path2.join(currentDir, "package.json");
|
|
1313
|
-
if (
|
|
1314
|
-
const pkgJsonRaw =
|
|
1833
|
+
if (fs4.existsSync(pkgJsonPath)) {
|
|
1834
|
+
const pkgJsonRaw = fs4.readFileSync(pkgJsonPath, "utf8");
|
|
1315
1835
|
const pkgJson = JSON.parse(pkgJsonRaw);
|
|
1316
1836
|
if (pkgJson.name === "drizzle-kit") {
|
|
1317
1837
|
const binField = pkgJson.bin;
|
|
@@ -1346,7 +1866,7 @@ async function run(options = {}) {
|
|
|
1346
1866
|
throw new Error(`drizzle-kit introspect failed with status ${result.status}`);
|
|
1347
1867
|
}
|
|
1348
1868
|
const generatedSchema = path2.join(OUT_DIR, "schema.ts");
|
|
1349
|
-
if (!
|
|
1869
|
+
if (!fs4.existsSync(generatedSchema)) {
|
|
1350
1870
|
console.error("[gen-db-schema] schema.ts not generated");
|
|
1351
1871
|
throw new Error("drizzle-kit introspect failed to generate schema.ts");
|
|
1352
1872
|
}
|
|
@@ -1355,8 +1875,8 @@ async function run(options = {}) {
|
|
|
1355
1875
|
console.warn("[gen-db-schema] Unmatched custom types detected:", stats.unmatchedUnknown);
|
|
1356
1876
|
}
|
|
1357
1877
|
console.log("[gen-db-schema] \u2713 Postprocessed schema");
|
|
1358
|
-
|
|
1359
|
-
|
|
1878
|
+
fs4.mkdirSync(path2.dirname(SCHEMA_FILE), { recursive: true });
|
|
1879
|
+
fs4.copyFileSync(generatedSchema, SCHEMA_FILE);
|
|
1360
1880
|
console.log(`[gen-db-schema] \u2713 Copied to ${outputPath}`);
|
|
1361
1881
|
try {
|
|
1362
1882
|
if (options.enableNestModuleGenerate) {
|
|
@@ -1377,8 +1897,8 @@ async function run(options = {}) {
|
|
|
1377
1897
|
console.error("[gen-db-schema] Failed:", err instanceof Error ? err.message : String(err));
|
|
1378
1898
|
exitCode = 1;
|
|
1379
1899
|
} finally {
|
|
1380
|
-
if (
|
|
1381
|
-
|
|
1900
|
+
if (fs4.existsSync(OUT_DIR)) {
|
|
1901
|
+
fs4.rmSync(OUT_DIR, { recursive: true, force: true });
|
|
1382
1902
|
}
|
|
1383
1903
|
process.exit(exitCode);
|
|
1384
1904
|
}
|
|
@@ -1397,7 +1917,7 @@ var genDbSchemaCommand = {
|
|
|
1397
1917
|
|
|
1398
1918
|
// src/commands/sync/run.handler.ts
|
|
1399
1919
|
import path4 from "path";
|
|
1400
|
-
import
|
|
1920
|
+
import fs6 from "fs";
|
|
1401
1921
|
import { fileURLToPath as fileURLToPath3 } from "url";
|
|
1402
1922
|
|
|
1403
1923
|
// src/config/sync.ts
|
|
@@ -1461,14 +1981,14 @@ function genSyncConfig(perms = {}) {
|
|
|
1461
1981
|
}
|
|
1462
1982
|
|
|
1463
1983
|
// src/utils/file-ops.ts
|
|
1464
|
-
import
|
|
1984
|
+
import fs5 from "fs";
|
|
1465
1985
|
import path3 from "path";
|
|
1466
1986
|
function removeLineFromFile(filePath, pattern) {
|
|
1467
|
-
if (!
|
|
1987
|
+
if (!fs5.existsSync(filePath)) {
|
|
1468
1988
|
console.log(`[fullstack-cli] \u25CB ${path3.basename(filePath)} (not found)`);
|
|
1469
1989
|
return false;
|
|
1470
1990
|
}
|
|
1471
|
-
const content =
|
|
1991
|
+
const content = fs5.readFileSync(filePath, "utf-8");
|
|
1472
1992
|
const lines = content.split("\n");
|
|
1473
1993
|
const trimmedPattern = pattern.trim();
|
|
1474
1994
|
const filteredLines = lines.filter((line) => line.trim() !== trimmedPattern);
|
|
@@ -1476,7 +1996,7 @@ function removeLineFromFile(filePath, pattern) {
|
|
|
1476
1996
|
console.log(`[fullstack-cli] \u25CB ${path3.basename(filePath)} (pattern not found: ${pattern})`);
|
|
1477
1997
|
return false;
|
|
1478
1998
|
}
|
|
1479
|
-
|
|
1999
|
+
fs5.writeFileSync(filePath, filteredLines.join("\n"));
|
|
1480
2000
|
console.log(`[fullstack-cli] \u2713 ${path3.basename(filePath)} (removed: ${pattern})`);
|
|
1481
2001
|
return true;
|
|
1482
2002
|
}
|
|
@@ -1492,7 +2012,7 @@ async function run2(options) {
|
|
|
1492
2012
|
process.exit(0);
|
|
1493
2013
|
}
|
|
1494
2014
|
const userPackageJson = path4.join(userProjectRoot, "package.json");
|
|
1495
|
-
if (!
|
|
2015
|
+
if (!fs6.existsSync(userPackageJson)) {
|
|
1496
2016
|
console.log("[fullstack-cli] Skip syncing (not a valid npm project)");
|
|
1497
2017
|
process.exit(0);
|
|
1498
2018
|
}
|
|
@@ -1538,7 +2058,7 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
1538
2058
|
}
|
|
1539
2059
|
const srcPath = path4.join(pluginRoot, rule.from);
|
|
1540
2060
|
const destPath = path4.join(userProjectRoot, rule.to);
|
|
1541
|
-
if (!
|
|
2061
|
+
if (!fs6.existsSync(srcPath)) {
|
|
1542
2062
|
console.warn(`[fullstack-cli] Source not found: ${rule.from}`);
|
|
1543
2063
|
return;
|
|
1544
2064
|
}
|
|
@@ -1556,31 +2076,31 @@ async function syncRule(rule, pluginRoot, userProjectRoot) {
|
|
|
1556
2076
|
}
|
|
1557
2077
|
function syncFile(src, dest, overwrite = true) {
|
|
1558
2078
|
const destDir = path4.dirname(dest);
|
|
1559
|
-
if (!
|
|
1560
|
-
|
|
2079
|
+
if (!fs6.existsSync(destDir)) {
|
|
2080
|
+
fs6.mkdirSync(destDir, { recursive: true });
|
|
1561
2081
|
}
|
|
1562
|
-
if (
|
|
2082
|
+
if (fs6.existsSync(dest) && !overwrite) {
|
|
1563
2083
|
console.log(`[fullstack-cli] \u25CB ${path4.basename(dest)} (skipped, already exists)`);
|
|
1564
2084
|
return;
|
|
1565
2085
|
}
|
|
1566
|
-
|
|
2086
|
+
fs6.copyFileSync(src, dest);
|
|
1567
2087
|
console.log(`[fullstack-cli] \u2713 ${path4.basename(dest)}`);
|
|
1568
2088
|
}
|
|
1569
2089
|
function syncDirectory(src, dest, overwrite = true) {
|
|
1570
|
-
if (!
|
|
1571
|
-
|
|
2090
|
+
if (!fs6.existsSync(dest)) {
|
|
2091
|
+
fs6.mkdirSync(dest, { recursive: true });
|
|
1572
2092
|
}
|
|
1573
|
-
const files =
|
|
2093
|
+
const files = fs6.readdirSync(src);
|
|
1574
2094
|
let count = 0;
|
|
1575
2095
|
files.forEach((file) => {
|
|
1576
2096
|
const srcFile = path4.join(src, file);
|
|
1577
2097
|
const destFile = path4.join(dest, file);
|
|
1578
|
-
const stats =
|
|
2098
|
+
const stats = fs6.statSync(srcFile);
|
|
1579
2099
|
if (stats.isDirectory()) {
|
|
1580
2100
|
syncDirectory(srcFile, destFile, overwrite);
|
|
1581
2101
|
} else {
|
|
1582
|
-
if (overwrite || !
|
|
1583
|
-
|
|
2102
|
+
if (overwrite || !fs6.existsSync(destFile)) {
|
|
2103
|
+
fs6.copyFileSync(srcFile, destFile);
|
|
1584
2104
|
console.log(`[fullstack-cli] \u2713 ${path4.relative(dest, destFile)}`);
|
|
1585
2105
|
count++;
|
|
1586
2106
|
}
|
|
@@ -1591,28 +2111,28 @@ function syncDirectory(src, dest, overwrite = true) {
|
|
|
1591
2111
|
}
|
|
1592
2112
|
}
|
|
1593
2113
|
function appendToFile(src, dest) {
|
|
1594
|
-
const content =
|
|
2114
|
+
const content = fs6.readFileSync(src, "utf-8");
|
|
1595
2115
|
let existingContent = "";
|
|
1596
|
-
if (
|
|
1597
|
-
existingContent =
|
|
2116
|
+
if (fs6.existsSync(dest)) {
|
|
2117
|
+
existingContent = fs6.readFileSync(dest, "utf-8");
|
|
1598
2118
|
}
|
|
1599
2119
|
if (existingContent.includes(content.trim())) {
|
|
1600
2120
|
console.log(`[fullstack-cli] \u25CB ${path4.basename(dest)} (already contains content)`);
|
|
1601
2121
|
return;
|
|
1602
2122
|
}
|
|
1603
|
-
|
|
2123
|
+
fs6.appendFileSync(dest, content);
|
|
1604
2124
|
console.log(`[fullstack-cli] \u2713 ${path4.basename(dest)} (appended)`);
|
|
1605
2125
|
}
|
|
1606
2126
|
function setPermissions(permissions, projectRoot) {
|
|
1607
2127
|
for (const [pattern, mode] of Object.entries(permissions)) {
|
|
1608
2128
|
if (pattern === "**/*.sh") {
|
|
1609
2129
|
const scriptsDir = path4.join(projectRoot, "scripts");
|
|
1610
|
-
if (
|
|
1611
|
-
const files =
|
|
2130
|
+
if (fs6.existsSync(scriptsDir)) {
|
|
2131
|
+
const files = fs6.readdirSync(scriptsDir);
|
|
1612
2132
|
files.forEach((file) => {
|
|
1613
2133
|
if (file.endsWith(".sh")) {
|
|
1614
2134
|
const filePath = path4.join(scriptsDir, file);
|
|
1615
|
-
|
|
2135
|
+
fs6.chmodSync(filePath, mode);
|
|
1616
2136
|
}
|
|
1617
2137
|
});
|
|
1618
2138
|
}
|
|
@@ -1620,16 +2140,16 @@ function setPermissions(permissions, projectRoot) {
|
|
|
1620
2140
|
}
|
|
1621
2141
|
}
|
|
1622
2142
|
function deleteFile(filePath) {
|
|
1623
|
-
if (
|
|
1624
|
-
|
|
2143
|
+
if (fs6.existsSync(filePath)) {
|
|
2144
|
+
fs6.unlinkSync(filePath);
|
|
1625
2145
|
console.log(`[fullstack-cli] \u2713 ${path4.basename(filePath)} (deleted)`);
|
|
1626
2146
|
} else {
|
|
1627
2147
|
console.log(`[fullstack-cli] \u25CB ${path4.basename(filePath)} (not found)`);
|
|
1628
2148
|
}
|
|
1629
2149
|
}
|
|
1630
2150
|
function deleteDirectory(dirPath) {
|
|
1631
|
-
if (
|
|
1632
|
-
|
|
2151
|
+
if (fs6.existsSync(dirPath)) {
|
|
2152
|
+
fs6.rmSync(dirPath, { recursive: true });
|
|
1633
2153
|
console.log(`[fullstack-cli] \u2713 ${path4.basename(dirPath)} (deleted)`);
|
|
1634
2154
|
} else {
|
|
1635
2155
|
console.log(`[fullstack-cli] \u25CB ${path4.basename(dirPath)} (not found)`);
|
|
@@ -1648,7 +2168,7 @@ var syncCommand = {
|
|
|
1648
2168
|
};
|
|
1649
2169
|
|
|
1650
2170
|
// src/commands/action-plugin/utils.ts
|
|
1651
|
-
import
|
|
2171
|
+
import fs7 from "fs";
|
|
1652
2172
|
import path5 from "path";
|
|
1653
2173
|
import { spawnSync as spawnSync2, execSync } from "child_process";
|
|
1654
2174
|
function parsePluginName(input) {
|
|
@@ -1674,11 +2194,11 @@ function getPluginPath(pluginName) {
|
|
|
1674
2194
|
}
|
|
1675
2195
|
function readPackageJson() {
|
|
1676
2196
|
const pkgPath = getPackageJsonPath();
|
|
1677
|
-
if (!
|
|
2197
|
+
if (!fs7.existsSync(pkgPath)) {
|
|
1678
2198
|
throw new Error("package.json not found in current directory");
|
|
1679
2199
|
}
|
|
1680
2200
|
try {
|
|
1681
|
-
const content =
|
|
2201
|
+
const content = fs7.readFileSync(pkgPath, "utf-8");
|
|
1682
2202
|
return JSON.parse(content);
|
|
1683
2203
|
} catch {
|
|
1684
2204
|
throw new Error("Failed to parse package.json");
|
|
@@ -1686,7 +2206,7 @@ function readPackageJson() {
|
|
|
1686
2206
|
}
|
|
1687
2207
|
function writePackageJson(pkg2) {
|
|
1688
2208
|
const pkgPath = getPackageJsonPath();
|
|
1689
|
-
|
|
2209
|
+
fs7.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
|
|
1690
2210
|
}
|
|
1691
2211
|
function readActionPlugins() {
|
|
1692
2212
|
const pkg2 = readPackageJson();
|
|
@@ -1720,11 +2240,11 @@ function npmInstall(tgzPath) {
|
|
|
1720
2240
|
}
|
|
1721
2241
|
function getPackageVersion(pluginName) {
|
|
1722
2242
|
const pkgJsonPath = path5.join(getPluginPath(pluginName), "package.json");
|
|
1723
|
-
if (!
|
|
2243
|
+
if (!fs7.existsSync(pkgJsonPath)) {
|
|
1724
2244
|
return null;
|
|
1725
2245
|
}
|
|
1726
2246
|
try {
|
|
1727
|
-
const content =
|
|
2247
|
+
const content = fs7.readFileSync(pkgJsonPath, "utf-8");
|
|
1728
2248
|
const pkg2 = JSON.parse(content);
|
|
1729
2249
|
return pkg2.version || null;
|
|
1730
2250
|
} catch {
|
|
@@ -1733,11 +2253,11 @@ function getPackageVersion(pluginName) {
|
|
|
1733
2253
|
}
|
|
1734
2254
|
function readPluginPackageJson(pluginPath) {
|
|
1735
2255
|
const pkgJsonPath = path5.join(pluginPath, "package.json");
|
|
1736
|
-
if (!
|
|
2256
|
+
if (!fs7.existsSync(pkgJsonPath)) {
|
|
1737
2257
|
return null;
|
|
1738
2258
|
}
|
|
1739
2259
|
try {
|
|
1740
|
-
const content =
|
|
2260
|
+
const content = fs7.readFileSync(pkgJsonPath, "utf-8");
|
|
1741
2261
|
return JSON.parse(content);
|
|
1742
2262
|
} catch {
|
|
1743
2263
|
return null;
|
|
@@ -1747,34 +2267,34 @@ function extractTgzToNodeModules(tgzPath, pluginName) {
|
|
|
1747
2267
|
const nodeModulesPath = path5.join(getProjectRoot(), "node_modules");
|
|
1748
2268
|
const targetDir = path5.join(nodeModulesPath, pluginName);
|
|
1749
2269
|
const scopeDir = path5.dirname(targetDir);
|
|
1750
|
-
if (!
|
|
1751
|
-
|
|
2270
|
+
if (!fs7.existsSync(scopeDir)) {
|
|
2271
|
+
fs7.mkdirSync(scopeDir, { recursive: true });
|
|
1752
2272
|
}
|
|
1753
|
-
if (
|
|
1754
|
-
|
|
2273
|
+
if (fs7.existsSync(targetDir)) {
|
|
2274
|
+
fs7.rmSync(targetDir, { recursive: true });
|
|
1755
2275
|
}
|
|
1756
2276
|
const tempDir = path5.join(nodeModulesPath, ".cache", "fullstack-cli", "extract-temp");
|
|
1757
|
-
if (
|
|
1758
|
-
|
|
2277
|
+
if (fs7.existsSync(tempDir)) {
|
|
2278
|
+
fs7.rmSync(tempDir, { recursive: true });
|
|
1759
2279
|
}
|
|
1760
|
-
|
|
2280
|
+
fs7.mkdirSync(tempDir, { recursive: true });
|
|
1761
2281
|
try {
|
|
1762
2282
|
execSync(`tar -xzf "${tgzPath}" -C "${tempDir}"`, { stdio: "pipe" });
|
|
1763
2283
|
const extractedDir = path5.join(tempDir, "package");
|
|
1764
|
-
if (
|
|
1765
|
-
|
|
2284
|
+
if (fs7.existsSync(extractedDir)) {
|
|
2285
|
+
fs7.renameSync(extractedDir, targetDir);
|
|
1766
2286
|
} else {
|
|
1767
|
-
const files =
|
|
2287
|
+
const files = fs7.readdirSync(tempDir);
|
|
1768
2288
|
if (files.length === 1) {
|
|
1769
|
-
|
|
2289
|
+
fs7.renameSync(path5.join(tempDir, files[0]), targetDir);
|
|
1770
2290
|
} else {
|
|
1771
2291
|
throw new Error("Unexpected tgz structure");
|
|
1772
2292
|
}
|
|
1773
2293
|
}
|
|
1774
2294
|
return targetDir;
|
|
1775
2295
|
} finally {
|
|
1776
|
-
if (
|
|
1777
|
-
|
|
2296
|
+
if (fs7.existsSync(tempDir)) {
|
|
2297
|
+
fs7.rmSync(tempDir, { recursive: true });
|
|
1778
2298
|
}
|
|
1779
2299
|
}
|
|
1780
2300
|
}
|
|
@@ -1786,7 +2306,7 @@ function checkMissingPeerDeps(peerDeps) {
|
|
|
1786
2306
|
const nodeModulesPath = path5.join(getProjectRoot(), "node_modules");
|
|
1787
2307
|
for (const [depName, _version] of Object.entries(peerDeps)) {
|
|
1788
2308
|
const depPath = path5.join(nodeModulesPath, depName);
|
|
1789
|
-
if (!
|
|
2309
|
+
if (!fs7.existsSync(depPath)) {
|
|
1790
2310
|
missing.push(depName);
|
|
1791
2311
|
}
|
|
1792
2312
|
}
|
|
@@ -1810,15 +2330,15 @@ function installMissingDeps(deps) {
|
|
|
1810
2330
|
}
|
|
1811
2331
|
function removePluginDirectory(pluginName) {
|
|
1812
2332
|
const pluginPath = getPluginPath(pluginName);
|
|
1813
|
-
if (
|
|
1814
|
-
|
|
2333
|
+
if (fs7.existsSync(pluginPath)) {
|
|
2334
|
+
fs7.rmSync(pluginPath, { recursive: true });
|
|
1815
2335
|
console.log(`[action-plugin] Removed ${pluginName}`);
|
|
1816
2336
|
}
|
|
1817
2337
|
}
|
|
1818
2338
|
|
|
1819
2339
|
// src/commands/action-plugin/api-client.ts
|
|
1820
2340
|
import { HttpClient as HttpClient2 } from "@lark-apaas/http-client";
|
|
1821
|
-
import
|
|
2341
|
+
import fs8 from "fs";
|
|
1822
2342
|
import path6 from "path";
|
|
1823
2343
|
|
|
1824
2344
|
// src/utils/http-client.ts
|
|
@@ -1832,10 +2352,13 @@ function getHttpClient() {
|
|
|
1832
2352
|
enabled: true
|
|
1833
2353
|
}
|
|
1834
2354
|
});
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
2355
|
+
const canaryEnv = process.env.FORCE_FRAMEWORK_CLI_CANARY_ENV;
|
|
2356
|
+
if (canaryEnv) {
|
|
2357
|
+
clientInstance.interceptors.request.use((req) => {
|
|
2358
|
+
req.headers["x-tt-env"] = canaryEnv;
|
|
2359
|
+
return req;
|
|
2360
|
+
});
|
|
2361
|
+
}
|
|
1839
2362
|
}
|
|
1840
2363
|
return clientInstance;
|
|
1841
2364
|
}
|
|
@@ -1908,8 +2431,8 @@ function getPluginCacheDir() {
|
|
|
1908
2431
|
}
|
|
1909
2432
|
function ensureCacheDir() {
|
|
1910
2433
|
const cacheDir = getPluginCacheDir();
|
|
1911
|
-
if (!
|
|
1912
|
-
|
|
2434
|
+
if (!fs8.existsSync(cacheDir)) {
|
|
2435
|
+
fs8.mkdirSync(cacheDir, { recursive: true });
|
|
1913
2436
|
}
|
|
1914
2437
|
}
|
|
1915
2438
|
function getTempFilePath(pluginKey, version) {
|
|
@@ -1932,7 +2455,7 @@ async function downloadPlugin(pluginKey, requestedVersion) {
|
|
|
1932
2455
|
tgzBuffer = await downloadFromPublic(pluginInfo.downloadURL);
|
|
1933
2456
|
}
|
|
1934
2457
|
const tgzPath = getTempFilePath(pluginKey, pluginInfo.version);
|
|
1935
|
-
|
|
2458
|
+
fs8.writeFileSync(tgzPath, tgzBuffer);
|
|
1936
2459
|
console.log(`[action-plugin] Downloaded to ${tgzPath} (${(tgzBuffer.length / 1024).toFixed(2)} KB)`);
|
|
1937
2460
|
return {
|
|
1938
2461
|
tgzPath,
|
|
@@ -1942,8 +2465,8 @@ async function downloadPlugin(pluginKey, requestedVersion) {
|
|
|
1942
2465
|
}
|
|
1943
2466
|
function cleanupTempFile(tgzPath) {
|
|
1944
2467
|
try {
|
|
1945
|
-
if (
|
|
1946
|
-
|
|
2468
|
+
if (fs8.existsSync(tgzPath)) {
|
|
2469
|
+
fs8.unlinkSync(tgzPath);
|
|
1947
2470
|
}
|
|
1948
2471
|
} catch {
|
|
1949
2472
|
}
|
|
@@ -2279,7 +2802,7 @@ var actionPluginCommandGroup = {
|
|
|
2279
2802
|
};
|
|
2280
2803
|
|
|
2281
2804
|
// src/commands/capability/utils.ts
|
|
2282
|
-
import
|
|
2805
|
+
import fs9 from "fs";
|
|
2283
2806
|
import path7 from "path";
|
|
2284
2807
|
var CAPABILITIES_DIR = "server/capabilities";
|
|
2285
2808
|
function getProjectRoot2() {
|
|
@@ -2295,23 +2818,23 @@ function getPluginManifestPath(pluginKey) {
|
|
|
2295
2818
|
return path7.join(getProjectRoot2(), "node_modules", pluginKey, "manifest.json");
|
|
2296
2819
|
}
|
|
2297
2820
|
function capabilitiesDirExists() {
|
|
2298
|
-
return
|
|
2821
|
+
return fs9.existsSync(getCapabilitiesDir());
|
|
2299
2822
|
}
|
|
2300
2823
|
function listCapabilityIds() {
|
|
2301
2824
|
const dir = getCapabilitiesDir();
|
|
2302
|
-
if (!
|
|
2825
|
+
if (!fs9.existsSync(dir)) {
|
|
2303
2826
|
return [];
|
|
2304
2827
|
}
|
|
2305
|
-
const files =
|
|
2306
|
-
return files.filter((f) => f.endsWith(".json")).map((f) => f.replace(/\.json$/, ""));
|
|
2828
|
+
const files = fs9.readdirSync(dir);
|
|
2829
|
+
return files.filter((f) => f.endsWith(".json") && f !== "capabilities.json").map((f) => f.replace(/\.json$/, ""));
|
|
2307
2830
|
}
|
|
2308
2831
|
function readCapability(id) {
|
|
2309
2832
|
const filePath = getCapabilityPath(id);
|
|
2310
|
-
if (!
|
|
2833
|
+
if (!fs9.existsSync(filePath)) {
|
|
2311
2834
|
throw new Error(`Capability not found: ${id}`);
|
|
2312
2835
|
}
|
|
2313
2836
|
try {
|
|
2314
|
-
const content =
|
|
2837
|
+
const content = fs9.readFileSync(filePath, "utf-8");
|
|
2315
2838
|
return JSON.parse(content);
|
|
2316
2839
|
} catch (error) {
|
|
2317
2840
|
if (error instanceof SyntaxError) {
|
|
@@ -2322,15 +2845,27 @@ function readCapability(id) {
|
|
|
2322
2845
|
}
|
|
2323
2846
|
function readAllCapabilities() {
|
|
2324
2847
|
const ids = listCapabilityIds();
|
|
2325
|
-
|
|
2848
|
+
const capabilities = [];
|
|
2849
|
+
for (const id of ids) {
|
|
2850
|
+
try {
|
|
2851
|
+
const capability = readCapability(id);
|
|
2852
|
+
if (!capability.pluginKey) {
|
|
2853
|
+
continue;
|
|
2854
|
+
}
|
|
2855
|
+
capabilities.push(capability);
|
|
2856
|
+
} catch {
|
|
2857
|
+
continue;
|
|
2858
|
+
}
|
|
2859
|
+
}
|
|
2860
|
+
return capabilities;
|
|
2326
2861
|
}
|
|
2327
2862
|
function readPluginManifest(pluginKey) {
|
|
2328
2863
|
const manifestPath = getPluginManifestPath(pluginKey);
|
|
2329
|
-
if (!
|
|
2864
|
+
if (!fs9.existsSync(manifestPath)) {
|
|
2330
2865
|
throw new Error(`Plugin not installed: ${pluginKey} (manifest.json not found)`);
|
|
2331
2866
|
}
|
|
2332
2867
|
try {
|
|
2333
|
-
const content =
|
|
2868
|
+
const content = fs9.readFileSync(manifestPath, "utf-8");
|
|
2334
2869
|
return JSON.parse(content);
|
|
2335
2870
|
} catch (error) {
|
|
2336
2871
|
if (error instanceof SyntaxError) {
|
|
@@ -2504,7 +3039,7 @@ var capabilityCommandGroup = {
|
|
|
2504
3039
|
};
|
|
2505
3040
|
|
|
2506
3041
|
// src/commands/migration/version-manager.ts
|
|
2507
|
-
import
|
|
3042
|
+
import fs10 from "fs";
|
|
2508
3043
|
import path8 from "path";
|
|
2509
3044
|
var PACKAGE_JSON = "package.json";
|
|
2510
3045
|
var VERSION_FIELD = "migrationVersion";
|
|
@@ -2513,25 +3048,25 @@ function getPackageJsonPath2() {
|
|
|
2513
3048
|
}
|
|
2514
3049
|
function getCurrentVersion() {
|
|
2515
3050
|
const pkgPath = getPackageJsonPath2();
|
|
2516
|
-
if (!
|
|
3051
|
+
if (!fs10.existsSync(pkgPath)) {
|
|
2517
3052
|
throw new Error("package.json not found");
|
|
2518
3053
|
}
|
|
2519
|
-
const pkg2 = JSON.parse(
|
|
3054
|
+
const pkg2 = JSON.parse(fs10.readFileSync(pkgPath, "utf-8"));
|
|
2520
3055
|
return pkg2[VERSION_FIELD] ?? 0;
|
|
2521
3056
|
}
|
|
2522
3057
|
function setCurrentVersion(version) {
|
|
2523
3058
|
const pkgPath = getPackageJsonPath2();
|
|
2524
|
-
const pkg2 = JSON.parse(
|
|
3059
|
+
const pkg2 = JSON.parse(fs10.readFileSync(pkgPath, "utf-8"));
|
|
2525
3060
|
pkg2[VERSION_FIELD] = version;
|
|
2526
|
-
|
|
3061
|
+
fs10.writeFileSync(pkgPath, JSON.stringify(pkg2, null, 2) + "\n", "utf-8");
|
|
2527
3062
|
}
|
|
2528
3063
|
|
|
2529
3064
|
// src/commands/migration/versions/v001_capability/json-migrator/detector.ts
|
|
2530
|
-
import
|
|
3065
|
+
import fs12 from "fs";
|
|
2531
3066
|
import path10 from "path";
|
|
2532
3067
|
|
|
2533
3068
|
// src/commands/migration/versions/v001_capability/utils.ts
|
|
2534
|
-
import
|
|
3069
|
+
import fs11 from "fs";
|
|
2535
3070
|
import path9 from "path";
|
|
2536
3071
|
var CAPABILITIES_DIR2 = "server/capabilities";
|
|
2537
3072
|
function getProjectRoot3() {
|
|
@@ -2548,19 +3083,30 @@ function getPluginManifestPath2(pluginKey) {
|
|
|
2548
3083
|
function detectJsonMigration() {
|
|
2549
3084
|
const capabilitiesDir = getCapabilitiesDir2();
|
|
2550
3085
|
const oldFilePath = path10.join(capabilitiesDir, "capabilities.json");
|
|
2551
|
-
if (!
|
|
3086
|
+
if (!fs12.existsSync(oldFilePath)) {
|
|
2552
3087
|
return {
|
|
2553
3088
|
needsMigration: false,
|
|
2554
3089
|
reason: "capabilities.json not found"
|
|
2555
3090
|
};
|
|
2556
3091
|
}
|
|
2557
3092
|
try {
|
|
2558
|
-
const content =
|
|
3093
|
+
const content = fs12.readFileSync(oldFilePath, "utf-8");
|
|
2559
3094
|
const parsed = JSON.parse(content);
|
|
2560
|
-
|
|
3095
|
+
if (!Array.isArray(parsed)) {
|
|
3096
|
+
return {
|
|
3097
|
+
needsMigration: false,
|
|
3098
|
+
reason: "capabilities.json is not a valid array"
|
|
3099
|
+
};
|
|
3100
|
+
}
|
|
3101
|
+
if (parsed.length === 0) {
|
|
3102
|
+
return {
|
|
3103
|
+
needsMigration: false,
|
|
3104
|
+
reason: "capabilities.json is an empty array"
|
|
3105
|
+
};
|
|
3106
|
+
}
|
|
2561
3107
|
return {
|
|
2562
3108
|
needsMigration: true,
|
|
2563
|
-
oldCapabilities:
|
|
3109
|
+
oldCapabilities: parsed,
|
|
2564
3110
|
oldFilePath
|
|
2565
3111
|
};
|
|
2566
3112
|
} catch (error) {
|
|
@@ -2595,7 +3141,7 @@ async function check(options) {
|
|
|
2595
3141
|
}
|
|
2596
3142
|
|
|
2597
3143
|
// src/commands/migration/versions/v001_capability/json-migrator/index.ts
|
|
2598
|
-
import
|
|
3144
|
+
import fs13 from "fs";
|
|
2599
3145
|
import path11 from "path";
|
|
2600
3146
|
|
|
2601
3147
|
// src/commands/migration/versions/v001_capability/mapping.ts
|
|
@@ -2826,10 +3372,10 @@ function transformCapabilities(oldCapabilities) {
|
|
|
2826
3372
|
// src/commands/migration/versions/v001_capability/json-migrator/index.ts
|
|
2827
3373
|
function loadExistingCapabilities() {
|
|
2828
3374
|
const capabilitiesDir = getCapabilitiesDir2();
|
|
2829
|
-
if (!
|
|
3375
|
+
if (!fs13.existsSync(capabilitiesDir)) {
|
|
2830
3376
|
return [];
|
|
2831
3377
|
}
|
|
2832
|
-
const files =
|
|
3378
|
+
const files = fs13.readdirSync(capabilitiesDir);
|
|
2833
3379
|
const capabilities = [];
|
|
2834
3380
|
for (const file of files) {
|
|
2835
3381
|
if (file === "capabilities.json" || !file.endsWith(".json")) {
|
|
@@ -2837,7 +3383,7 @@ function loadExistingCapabilities() {
|
|
|
2837
3383
|
}
|
|
2838
3384
|
try {
|
|
2839
3385
|
const filePath = path11.join(capabilitiesDir, file);
|
|
2840
|
-
const content =
|
|
3386
|
+
const content = fs13.readFileSync(filePath, "utf-8");
|
|
2841
3387
|
const capability = JSON.parse(content);
|
|
2842
3388
|
if (capability.id && capability.pluginKey) {
|
|
2843
3389
|
capabilities.push(capability);
|
|
@@ -2897,7 +3443,7 @@ async function migrateJsonFiles(options) {
|
|
|
2897
3443
|
for (const cap of newCapabilities) {
|
|
2898
3444
|
const filePath = path11.join(capabilitiesDir, `${cap.id}.json`);
|
|
2899
3445
|
const content = JSON.stringify(cap, null, 2);
|
|
2900
|
-
|
|
3446
|
+
fs13.writeFileSync(filePath, content, "utf-8");
|
|
2901
3447
|
console.log(` \u2713 Created: ${cap.id}.json`);
|
|
2902
3448
|
}
|
|
2903
3449
|
return {
|
|
@@ -2909,11 +3455,11 @@ async function migrateJsonFiles(options) {
|
|
|
2909
3455
|
}
|
|
2910
3456
|
|
|
2911
3457
|
// src/commands/migration/versions/v001_capability/plugin-installer/detector.ts
|
|
2912
|
-
import
|
|
3458
|
+
import fs14 from "fs";
|
|
2913
3459
|
function isPluginInstalled2(pluginKey) {
|
|
2914
3460
|
const actionPlugins = readActionPlugins();
|
|
2915
3461
|
const manifestPath = getPluginManifestPath2(pluginKey);
|
|
2916
|
-
return
|
|
3462
|
+
return fs14.existsSync(manifestPath) && !!actionPlugins[pluginKey];
|
|
2917
3463
|
}
|
|
2918
3464
|
function detectPluginsToInstall(capabilities) {
|
|
2919
3465
|
const pluginKeys = /* @__PURE__ */ new Set();
|
|
@@ -2990,10 +3536,10 @@ async function installPlugins(capabilities, options) {
|
|
|
2990
3536
|
|
|
2991
3537
|
// src/commands/migration/versions/v001_capability/code-migrator/index.ts
|
|
2992
3538
|
import path13 from "path";
|
|
2993
|
-
import { Project as
|
|
3539
|
+
import { Project as Project3 } from "ts-morph";
|
|
2994
3540
|
|
|
2995
3541
|
// src/commands/migration/versions/v001_capability/code-migrator/scanner.ts
|
|
2996
|
-
import
|
|
3542
|
+
import fs15 from "fs";
|
|
2997
3543
|
import path12 from "path";
|
|
2998
3544
|
var EXCLUDED_DIRS = [
|
|
2999
3545
|
"node_modules",
|
|
@@ -3009,7 +3555,7 @@ var EXCLUDED_PATTERNS = [
|
|
|
3009
3555
|
/\.d\.ts$/
|
|
3010
3556
|
];
|
|
3011
3557
|
function scanDirectory(dir, files = []) {
|
|
3012
|
-
const entries =
|
|
3558
|
+
const entries = fs15.readdirSync(dir, { withFileTypes: true });
|
|
3013
3559
|
for (const entry of entries) {
|
|
3014
3560
|
const fullPath = path12.join(dir, entry.name);
|
|
3015
3561
|
if (entry.isDirectory()) {
|
|
@@ -3028,13 +3574,13 @@ function scanDirectory(dir, files = []) {
|
|
|
3028
3574
|
}
|
|
3029
3575
|
function scanServerFiles() {
|
|
3030
3576
|
const serverDir = path12.join(getProjectRoot3(), "server");
|
|
3031
|
-
if (!
|
|
3577
|
+
if (!fs15.existsSync(serverDir)) {
|
|
3032
3578
|
return [];
|
|
3033
3579
|
}
|
|
3034
3580
|
return scanDirectory(serverDir);
|
|
3035
3581
|
}
|
|
3036
3582
|
function hasCapabilityImport(filePath) {
|
|
3037
|
-
const content =
|
|
3583
|
+
const content = fs15.readFileSync(filePath, "utf-8");
|
|
3038
3584
|
return /import\s+.*from\s+['"][^'"]*capabilities[^'"]*['"]/.test(content);
|
|
3039
3585
|
}
|
|
3040
3586
|
function scanFilesToMigrate() {
|
|
@@ -3098,17 +3644,17 @@ function analyzeImports(sourceFile) {
|
|
|
3098
3644
|
}
|
|
3099
3645
|
|
|
3100
3646
|
// src/commands/migration/versions/v001_capability/code-migrator/analyzers/call-site-analyzer.ts
|
|
3101
|
-
import { SyntaxKind } from "ts-morph";
|
|
3647
|
+
import { SyntaxKind as SyntaxKind4 } from "ts-morph";
|
|
3102
3648
|
function analyzeCallSites(sourceFile, imports) {
|
|
3103
3649
|
const callSites = [];
|
|
3104
3650
|
const importMap = /* @__PURE__ */ new Map();
|
|
3105
3651
|
for (const imp of imports) {
|
|
3106
3652
|
importMap.set(imp.importName, imp.capabilityId);
|
|
3107
3653
|
}
|
|
3108
|
-
const callExpressions = sourceFile.getDescendantsOfKind(
|
|
3654
|
+
const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind4.CallExpression);
|
|
3109
3655
|
for (const callExpr of callExpressions) {
|
|
3110
3656
|
const expression = callExpr.getExpression();
|
|
3111
|
-
if (expression.getKind() ===
|
|
3657
|
+
if (expression.getKind() === SyntaxKind4.Identifier) {
|
|
3112
3658
|
const functionName = expression.getText();
|
|
3113
3659
|
const capabilityId = importMap.get(functionName);
|
|
3114
3660
|
if (capabilityId) {
|
|
@@ -3121,11 +3667,11 @@ function analyzeCallSites(sourceFile, imports) {
|
|
|
3121
3667
|
text: callExpr.getText()
|
|
3122
3668
|
});
|
|
3123
3669
|
}
|
|
3124
|
-
} else if (expression.getKind() ===
|
|
3125
|
-
const propAccess = expression.asKind(
|
|
3670
|
+
} else if (expression.getKind() === SyntaxKind4.PropertyAccessExpression) {
|
|
3671
|
+
const propAccess = expression.asKind(SyntaxKind4.PropertyAccessExpression);
|
|
3126
3672
|
if (propAccess) {
|
|
3127
3673
|
const objectExpr = propAccess.getExpression();
|
|
3128
|
-
if (objectExpr.getKind() ===
|
|
3674
|
+
if (objectExpr.getKind() === SyntaxKind4.Identifier) {
|
|
3129
3675
|
const objectName = objectExpr.getText();
|
|
3130
3676
|
const capabilityId = importMap.get(objectName);
|
|
3131
3677
|
if (capabilityId) {
|
|
@@ -3161,13 +3707,15 @@ function analyzeClass(sourceFile) {
|
|
|
3161
3707
|
if (!name) continue;
|
|
3162
3708
|
const isInjectable = hasDecorator(classDecl, "Injectable");
|
|
3163
3709
|
const isController = hasDecorator(classDecl, "Controller");
|
|
3164
|
-
|
|
3710
|
+
const isAutomation = hasDecorator(classDecl, "Automation");
|
|
3711
|
+
if (classInfo && classInfo.isInjectable && !isInjectable && !isController && !isAutomation) {
|
|
3165
3712
|
continue;
|
|
3166
3713
|
}
|
|
3167
3714
|
const info = {
|
|
3168
3715
|
name,
|
|
3169
3716
|
isInjectable,
|
|
3170
3717
|
isController,
|
|
3718
|
+
isAutomation,
|
|
3171
3719
|
constructorParamCount: 0
|
|
3172
3720
|
};
|
|
3173
3721
|
const classBody = classDecl.getChildSyntaxListOrThrow();
|
|
@@ -3186,7 +3734,7 @@ function analyzeClass(sourceFile) {
|
|
|
3186
3734
|
info.constructorParamsEnd = ctor.getStart();
|
|
3187
3735
|
}
|
|
3188
3736
|
}
|
|
3189
|
-
if (isInjectable || isController || !classInfo) {
|
|
3737
|
+
if (isInjectable || isController || isAutomation || !classInfo) {
|
|
3190
3738
|
classInfo = info;
|
|
3191
3739
|
}
|
|
3192
3740
|
}
|
|
@@ -3199,10 +3747,10 @@ function canAutoMigrate(classInfo) {
|
|
|
3199
3747
|
reason: "No class found in file"
|
|
3200
3748
|
};
|
|
3201
3749
|
}
|
|
3202
|
-
if (!classInfo.isInjectable && !classInfo.isController) {
|
|
3750
|
+
if (!classInfo.isInjectable && !classInfo.isController && !classInfo.isAutomation) {
|
|
3203
3751
|
return {
|
|
3204
3752
|
canMigrate: false,
|
|
3205
|
-
reason: `Class "${classInfo.name}" is not @Injectable or @
|
|
3753
|
+
reason: `Class "${classInfo.name}" is not @Injectable, @Controller or @Automation`
|
|
3206
3754
|
};
|
|
3207
3755
|
}
|
|
3208
3756
|
return { canMigrate: true };
|
|
@@ -3352,7 +3900,7 @@ function addInjection(sourceFile) {
|
|
|
3352
3900
|
}
|
|
3353
3901
|
|
|
3354
3902
|
// src/commands/migration/versions/v001_capability/code-migrator/transformers/call-site-transformer.ts
|
|
3355
|
-
import { SyntaxKind as
|
|
3903
|
+
import { SyntaxKind as SyntaxKind5 } from "ts-morph";
|
|
3356
3904
|
var DEFAULT_ACTION_NAME = "run";
|
|
3357
3905
|
function generateNewCallText(capabilityId, actionName, args) {
|
|
3358
3906
|
const argsText = args.trim() || "{}";
|
|
@@ -3367,19 +3915,19 @@ function transformCallSites(sourceFile, imports) {
|
|
|
3367
3915
|
});
|
|
3368
3916
|
}
|
|
3369
3917
|
let replacedCount = 0;
|
|
3370
|
-
const callExpressions = sourceFile.getDescendantsOfKind(
|
|
3918
|
+
const callExpressions = sourceFile.getDescendantsOfKind(SyntaxKind5.CallExpression);
|
|
3371
3919
|
const sortedCalls = [...callExpressions].sort((a, b) => b.getStart() - a.getStart());
|
|
3372
3920
|
for (const callExpr of sortedCalls) {
|
|
3373
3921
|
const expression = callExpr.getExpression();
|
|
3374
3922
|
let importInfo;
|
|
3375
|
-
if (expression.getKind() ===
|
|
3923
|
+
if (expression.getKind() === SyntaxKind5.Identifier) {
|
|
3376
3924
|
const functionName = expression.getText();
|
|
3377
3925
|
importInfo = importMap.get(functionName);
|
|
3378
|
-
} else if (expression.getKind() ===
|
|
3379
|
-
const propAccess = expression.asKind(
|
|
3926
|
+
} else if (expression.getKind() === SyntaxKind5.PropertyAccessExpression) {
|
|
3927
|
+
const propAccess = expression.asKind(SyntaxKind5.PropertyAccessExpression);
|
|
3380
3928
|
if (propAccess) {
|
|
3381
3929
|
const objectExpr = propAccess.getExpression();
|
|
3382
|
-
if (objectExpr.getKind() ===
|
|
3930
|
+
if (objectExpr.getKind() === SyntaxKind5.Identifier) {
|
|
3383
3931
|
const objectName = objectExpr.getText();
|
|
3384
3932
|
importInfo = importMap.get(objectName);
|
|
3385
3933
|
}
|
|
@@ -3480,7 +4028,7 @@ async function migrateCode(options, capabilities) {
|
|
|
3480
4028
|
console.log(" No files need code migration.\n");
|
|
3481
4029
|
return result;
|
|
3482
4030
|
}
|
|
3483
|
-
const project = new
|
|
4031
|
+
const project = new Project3({
|
|
3484
4032
|
skipAddingFilesFromTsConfig: true,
|
|
3485
4033
|
compilerOptions: {
|
|
3486
4034
|
allowJs: true
|
|
@@ -3523,17 +4071,17 @@ function getSuggestion(analysis) {
|
|
|
3523
4071
|
}
|
|
3524
4072
|
|
|
3525
4073
|
// src/commands/migration/versions/v001_capability/cleanup.ts
|
|
3526
|
-
import
|
|
4074
|
+
import fs16 from "fs";
|
|
3527
4075
|
import path14 from "path";
|
|
3528
4076
|
function cleanupOldFiles(capabilities, dryRun) {
|
|
3529
4077
|
const deletedFiles = [];
|
|
3530
4078
|
const errors = [];
|
|
3531
4079
|
const capabilitiesDir = getCapabilitiesDir2();
|
|
3532
4080
|
const oldJsonPath = path14.join(capabilitiesDir, "capabilities.json");
|
|
3533
|
-
if (
|
|
4081
|
+
if (fs16.existsSync(oldJsonPath)) {
|
|
3534
4082
|
try {
|
|
3535
4083
|
if (!dryRun) {
|
|
3536
|
-
|
|
4084
|
+
fs16.unlinkSync(oldJsonPath);
|
|
3537
4085
|
}
|
|
3538
4086
|
deletedFiles.push("capabilities.json");
|
|
3539
4087
|
} catch (error) {
|
|
@@ -3542,10 +4090,10 @@ function cleanupOldFiles(capabilities, dryRun) {
|
|
|
3542
4090
|
}
|
|
3543
4091
|
for (const cap of capabilities) {
|
|
3544
4092
|
const tsFilePath = path14.join(capabilitiesDir, `${cap.id}.ts`);
|
|
3545
|
-
if (
|
|
4093
|
+
if (fs16.existsSync(tsFilePath)) {
|
|
3546
4094
|
try {
|
|
3547
4095
|
if (!dryRun) {
|
|
3548
|
-
|
|
4096
|
+
fs16.unlinkSync(tsFilePath);
|
|
3549
4097
|
}
|
|
3550
4098
|
deletedFiles.push(`${cap.id}.ts`);
|
|
3551
4099
|
} catch (error) {
|
|
@@ -3561,7 +4109,7 @@ function cleanupOldFiles(capabilities, dryRun) {
|
|
|
3561
4109
|
}
|
|
3562
4110
|
|
|
3563
4111
|
// src/commands/migration/versions/v001_capability/report-generator.ts
|
|
3564
|
-
import
|
|
4112
|
+
import fs17 from "fs";
|
|
3565
4113
|
import path15 from "path";
|
|
3566
4114
|
var REPORT_FILE = "capability-migration-report.md";
|
|
3567
4115
|
function printSummary(result) {
|
|
@@ -3725,15 +4273,15 @@ async function generateReport(result) {
|
|
|
3725
4273
|
}
|
|
3726
4274
|
lines.push("");
|
|
3727
4275
|
const logDir = process.env.LOG_DIR || "logs";
|
|
3728
|
-
if (!
|
|
4276
|
+
if (!fs17.existsSync(logDir)) {
|
|
3729
4277
|
return;
|
|
3730
4278
|
}
|
|
3731
4279
|
const reportDir = path15.join(logDir, "migration");
|
|
3732
|
-
if (!
|
|
3733
|
-
|
|
4280
|
+
if (!fs17.existsSync(reportDir)) {
|
|
4281
|
+
fs17.mkdirSync(reportDir, { recursive: true });
|
|
3734
4282
|
}
|
|
3735
4283
|
const reportPath = path15.join(reportDir, REPORT_FILE);
|
|
3736
|
-
|
|
4284
|
+
fs17.writeFileSync(reportPath, lines.join("\n"), "utf-8");
|
|
3737
4285
|
console.log(`\u{1F4C4} Report generated: ${reportPath}`);
|
|
3738
4286
|
}
|
|
3739
4287
|
|
|
@@ -4268,7 +4816,7 @@ var migrationCommand = {
|
|
|
4268
4816
|
import path16 from "path";
|
|
4269
4817
|
|
|
4270
4818
|
// src/commands/read-logs/std-utils.ts
|
|
4271
|
-
import
|
|
4819
|
+
import fs18 from "fs";
|
|
4272
4820
|
function formatStdPrefixTime(localTime) {
|
|
4273
4821
|
const match = localTime.match(/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/);
|
|
4274
4822
|
if (!match) return localTime;
|
|
@@ -4298,11 +4846,11 @@ function stripPrefixFromStdLine(line) {
|
|
|
4298
4846
|
return `[${time}] ${content}`;
|
|
4299
4847
|
}
|
|
4300
4848
|
function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarker) {
|
|
4301
|
-
const stat =
|
|
4849
|
+
const stat = fs18.statSync(filePath);
|
|
4302
4850
|
if (stat.size === 0) {
|
|
4303
4851
|
return { lines: [], markerFound: false, totalLinesCount: 0 };
|
|
4304
4852
|
}
|
|
4305
|
-
const fd =
|
|
4853
|
+
const fd = fs18.openSync(filePath, "r");
|
|
4306
4854
|
const chunkSize = 64 * 1024;
|
|
4307
4855
|
let position = stat.size;
|
|
4308
4856
|
let remainder = "";
|
|
@@ -4316,7 +4864,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
|
|
|
4316
4864
|
const length = Math.min(chunkSize, position);
|
|
4317
4865
|
position -= length;
|
|
4318
4866
|
const buffer = Buffer.alloc(length);
|
|
4319
|
-
|
|
4867
|
+
fs18.readSync(fd, buffer, 0, length, position);
|
|
4320
4868
|
let chunk = buffer.toString("utf8");
|
|
4321
4869
|
if (remainder) {
|
|
4322
4870
|
chunk += remainder;
|
|
@@ -4358,7 +4906,7 @@ function readStdLinesTailFromLastMarkerPaged(filePath, maxLines, offset, isMarke
|
|
|
4358
4906
|
}
|
|
4359
4907
|
}
|
|
4360
4908
|
} finally {
|
|
4361
|
-
|
|
4909
|
+
fs18.closeSync(fd);
|
|
4362
4910
|
}
|
|
4363
4911
|
return { lines: collected.reverse(), markerFound, totalLinesCount };
|
|
4364
4912
|
}
|
|
@@ -4379,21 +4927,21 @@ function readServerStdSegment(filePath, maxLines, offset) {
|
|
|
4379
4927
|
}
|
|
4380
4928
|
|
|
4381
4929
|
// src/commands/read-logs/tail.ts
|
|
4382
|
-
import
|
|
4930
|
+
import fs19 from "fs";
|
|
4383
4931
|
function fileExists(filePath) {
|
|
4384
4932
|
try {
|
|
4385
|
-
|
|
4933
|
+
fs19.accessSync(filePath, fs19.constants.F_OK | fs19.constants.R_OK);
|
|
4386
4934
|
return true;
|
|
4387
4935
|
} catch {
|
|
4388
4936
|
return false;
|
|
4389
4937
|
}
|
|
4390
4938
|
}
|
|
4391
4939
|
function readFileTailLines(filePath, maxLines) {
|
|
4392
|
-
const stat =
|
|
4940
|
+
const stat = fs19.statSync(filePath);
|
|
4393
4941
|
if (stat.size === 0) {
|
|
4394
4942
|
return [];
|
|
4395
4943
|
}
|
|
4396
|
-
const fd =
|
|
4944
|
+
const fd = fs19.openSync(filePath, "r");
|
|
4397
4945
|
const chunkSize = 64 * 1024;
|
|
4398
4946
|
const chunks = [];
|
|
4399
4947
|
let position = stat.size;
|
|
@@ -4403,13 +4951,13 @@ function readFileTailLines(filePath, maxLines) {
|
|
|
4403
4951
|
const length = Math.min(chunkSize, position);
|
|
4404
4952
|
position -= length;
|
|
4405
4953
|
const buffer = Buffer.alloc(length);
|
|
4406
|
-
|
|
4954
|
+
fs19.readSync(fd, buffer, 0, length, position);
|
|
4407
4955
|
chunks.unshift(buffer.toString("utf8"));
|
|
4408
4956
|
const chunkLines = buffer.toString("utf8").split("\n").length - 1;
|
|
4409
4957
|
collectedLines += chunkLines;
|
|
4410
4958
|
}
|
|
4411
4959
|
} finally {
|
|
4412
|
-
|
|
4960
|
+
fs19.closeSync(fd);
|
|
4413
4961
|
}
|
|
4414
4962
|
const content = chunks.join("");
|
|
4415
4963
|
const allLines = content.split("\n");
|
|
@@ -4425,11 +4973,11 @@ function readFileTailLines(filePath, maxLines) {
|
|
|
4425
4973
|
return allLines.slice(allLines.length - maxLines);
|
|
4426
4974
|
}
|
|
4427
4975
|
function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
|
|
4428
|
-
const stat =
|
|
4976
|
+
const stat = fs19.statSync(filePath);
|
|
4429
4977
|
if (stat.size === 0) {
|
|
4430
4978
|
return { lines: [], totalLinesCount: 0 };
|
|
4431
4979
|
}
|
|
4432
|
-
const fd =
|
|
4980
|
+
const fd = fs19.openSync(filePath, "r");
|
|
4433
4981
|
const chunkSize = 64 * 1024;
|
|
4434
4982
|
let position = stat.size;
|
|
4435
4983
|
let remainder = "";
|
|
@@ -4441,7 +4989,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
|
|
|
4441
4989
|
const length = Math.min(chunkSize, position);
|
|
4442
4990
|
position -= length;
|
|
4443
4991
|
const buffer = Buffer.alloc(length);
|
|
4444
|
-
|
|
4992
|
+
fs19.readSync(fd, buffer, 0, length, position);
|
|
4445
4993
|
let chunk = buffer.toString("utf8");
|
|
4446
4994
|
if (remainder) {
|
|
4447
4995
|
chunk += remainder;
|
|
@@ -4472,7 +5020,7 @@ function readFileTailNonEmptyLinesWithOffset(filePath, maxLines, offset) {
|
|
|
4472
5020
|
}
|
|
4473
5021
|
}
|
|
4474
5022
|
} finally {
|
|
4475
|
-
|
|
5023
|
+
fs19.closeSync(fd);
|
|
4476
5024
|
}
|
|
4477
5025
|
return { lines: collected.reverse(), totalLinesCount };
|
|
4478
5026
|
}
|
|
@@ -4574,7 +5122,7 @@ function extractClientStdSegment(lines, maxLines, offset) {
|
|
|
4574
5122
|
}
|
|
4575
5123
|
|
|
4576
5124
|
// src/commands/read-logs/json-lines.ts
|
|
4577
|
-
import
|
|
5125
|
+
import fs20 from "fs";
|
|
4578
5126
|
function normalizePid(value) {
|
|
4579
5127
|
if (typeof value === "number") {
|
|
4580
5128
|
return String(value);
|
|
@@ -4625,11 +5173,11 @@ function buildWantedLevelSet(levels) {
|
|
|
4625
5173
|
return set.size > 0 ? set : null;
|
|
4626
5174
|
}
|
|
4627
5175
|
function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
|
|
4628
|
-
const stat =
|
|
5176
|
+
const stat = fs20.statSync(filePath);
|
|
4629
5177
|
if (stat.size === 0) {
|
|
4630
5178
|
return { lines: [], totalLinesCount: 0 };
|
|
4631
5179
|
}
|
|
4632
|
-
const fd =
|
|
5180
|
+
const fd = fs20.openSync(filePath, "r");
|
|
4633
5181
|
const chunkSize = 64 * 1024;
|
|
4634
5182
|
let position = stat.size;
|
|
4635
5183
|
let remainder = "";
|
|
@@ -4644,7 +5192,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
|
|
|
4644
5192
|
const length = Math.min(chunkSize, position);
|
|
4645
5193
|
position -= length;
|
|
4646
5194
|
const buffer = Buffer.alloc(length);
|
|
4647
|
-
|
|
5195
|
+
fs20.readSync(fd, buffer, 0, length, position);
|
|
4648
5196
|
let chunk = buffer.toString("utf8");
|
|
4649
5197
|
if (remainder) {
|
|
4650
5198
|
chunk += remainder;
|
|
@@ -4706,7 +5254,7 @@ function readJsonLinesLastPid(filePath, maxLines, offset, levels) {
|
|
|
4706
5254
|
}
|
|
4707
5255
|
}
|
|
4708
5256
|
} finally {
|
|
4709
|
-
|
|
5257
|
+
fs20.closeSync(fd);
|
|
4710
5258
|
}
|
|
4711
5259
|
return { lines: collected.reverse(), totalLinesCount };
|
|
4712
5260
|
}
|
|
@@ -4749,11 +5297,11 @@ function extractTraceId(obj) {
|
|
|
4749
5297
|
function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
|
|
4750
5298
|
const wanted = traceId.trim();
|
|
4751
5299
|
if (!wanted) return { lines: [], totalLinesCount: 0 };
|
|
4752
|
-
const stat =
|
|
5300
|
+
const stat = fs20.statSync(filePath);
|
|
4753
5301
|
if (stat.size === 0) {
|
|
4754
5302
|
return { lines: [], totalLinesCount: 0 };
|
|
4755
5303
|
}
|
|
4756
|
-
const fd =
|
|
5304
|
+
const fd = fs20.openSync(filePath, "r");
|
|
4757
5305
|
const chunkSize = 64 * 1024;
|
|
4758
5306
|
let position = stat.size;
|
|
4759
5307
|
let remainder = "";
|
|
@@ -4766,7 +5314,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
|
|
|
4766
5314
|
const length = Math.min(chunkSize, position);
|
|
4767
5315
|
position -= length;
|
|
4768
5316
|
const buffer = Buffer.alloc(length);
|
|
4769
|
-
|
|
5317
|
+
fs20.readSync(fd, buffer, 0, length, position);
|
|
4770
5318
|
let chunk = buffer.toString("utf8");
|
|
4771
5319
|
if (remainder) {
|
|
4772
5320
|
chunk += remainder;
|
|
@@ -4819,7 +5367,7 @@ function readJsonLinesByTraceId(filePath, traceId, maxLines, offset, levels) {
|
|
|
4819
5367
|
}
|
|
4820
5368
|
}
|
|
4821
5369
|
} finally {
|
|
4822
|
-
|
|
5370
|
+
fs20.closeSync(fd);
|
|
4823
5371
|
}
|
|
4824
5372
|
return { lines: collected.reverse(), totalLinesCount };
|
|
4825
5373
|
}
|
|
@@ -4828,11 +5376,11 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
|
|
|
4828
5376
|
if (!wantedLevelSet) {
|
|
4829
5377
|
return { lines: [], totalLinesCount: 0 };
|
|
4830
5378
|
}
|
|
4831
|
-
const stat =
|
|
5379
|
+
const stat = fs20.statSync(filePath);
|
|
4832
5380
|
if (stat.size === 0) {
|
|
4833
5381
|
return { lines: [], totalLinesCount: 0 };
|
|
4834
5382
|
}
|
|
4835
|
-
const fd =
|
|
5383
|
+
const fd = fs20.openSync(filePath, "r");
|
|
4836
5384
|
const chunkSize = 64 * 1024;
|
|
4837
5385
|
let position = stat.size;
|
|
4838
5386
|
let remainder = "";
|
|
@@ -4844,7 +5392,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
|
|
|
4844
5392
|
const length = Math.min(chunkSize, position);
|
|
4845
5393
|
position -= length;
|
|
4846
5394
|
const buffer = Buffer.alloc(length);
|
|
4847
|
-
|
|
5395
|
+
fs20.readSync(fd, buffer, 0, length, position);
|
|
4848
5396
|
let chunk = buffer.toString("utf8");
|
|
4849
5397
|
if (remainder) {
|
|
4850
5398
|
chunk += remainder;
|
|
@@ -4891,7 +5439,7 @@ function readJsonLinesTailByLevel(filePath, maxLines, offset, levels) {
|
|
|
4891
5439
|
}
|
|
4892
5440
|
}
|
|
4893
5441
|
} finally {
|
|
4894
|
-
|
|
5442
|
+
fs20.closeSync(fd);
|
|
4895
5443
|
}
|
|
4896
5444
|
return { lines: collected.reverse(), totalLinesCount };
|
|
4897
5445
|
}
|
|
@@ -5189,11 +5737,11 @@ var commands = [
|
|
|
5189
5737
|
|
|
5190
5738
|
// src/index.ts
|
|
5191
5739
|
var envPath = path17.join(process.cwd(), ".env");
|
|
5192
|
-
if (
|
|
5740
|
+
if (fs21.existsSync(envPath)) {
|
|
5193
5741
|
dotenvConfig({ path: envPath });
|
|
5194
5742
|
}
|
|
5195
5743
|
var __dirname = path17.dirname(fileURLToPath4(import.meta.url));
|
|
5196
|
-
var pkg = JSON.parse(
|
|
5744
|
+
var pkg = JSON.parse(fs21.readFileSync(path17.join(__dirname, "../package.json"), "utf-8"));
|
|
5197
5745
|
var cli = new FullstackCLI(pkg.version);
|
|
5198
5746
|
cli.useAll(commands);
|
|
5199
5747
|
cli.run();
|