uql-codemod 0.43.0 → 0.45.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/dist/transform.js +78 -16
- package/package.json +1 -1
package/dist/transform.js
CHANGED
|
@@ -447,6 +447,37 @@ const BUILDER_INDEX_METHODS = new Map([
|
|
|
447
447
|
['addIndex', 1],
|
|
448
448
|
['createIndex', 2],
|
|
449
449
|
]);
|
|
450
|
+
/** The migration builder's `expr` helpers whose value an entity imports under the same name. */
|
|
451
|
+
const EXPR_VALUES = new Set(['currentDate', 'currentTime', 'uuid', 'uuidv7']);
|
|
452
|
+
/**
|
|
453
|
+
* Rewrites the migration builder's `expr.<helper>()` default as the value or `raw` an entity declares, or reports
|
|
454
|
+
* one with no rewrite. Called only where the file imports `expr` from uql, so a variable of its own is left alone.
|
|
455
|
+
*/
|
|
456
|
+
function rewriteExprCall(call, ctx) {
|
|
457
|
+
const callee = call.expression;
|
|
458
|
+
if (!ts.isPropertyAccessExpression(callee) ||
|
|
459
|
+
!ts.isIdentifier(callee.expression) ||
|
|
460
|
+
callee.expression.text !== 'expr') {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
const helper = callee.name.text;
|
|
464
|
+
// The one renamed: an entity's clock is `currentTimestamp`.
|
|
465
|
+
const value = helper === 'now' ? 'currentTimestamp' : EXPR_VALUES.has(helper) ? helper : undefined;
|
|
466
|
+
const [sql] = call.arguments;
|
|
467
|
+
if (value) {
|
|
468
|
+
ctx.edits.push(replaced(call, value));
|
|
469
|
+
ctx.imports.set(value, `the expr.${helper}()`);
|
|
470
|
+
}
|
|
471
|
+
else if (helper === 'raw' && sql && ts.isStringLiteralLike(sql)) {
|
|
472
|
+
ctx.edits.push(replaced(call, rawTag(sql.text)));
|
|
473
|
+
ctx.imports.set('raw', 'the raw`...`');
|
|
474
|
+
}
|
|
475
|
+
else {
|
|
476
|
+
ctx.unresolved.push(`${ctx.describe(call)}: expr.${helper}() is gone: declare the column with m.raw(...), or use a stamp on the entity`);
|
|
477
|
+
return;
|
|
478
|
+
}
|
|
479
|
+
ctx.rewritten.expr += 1;
|
|
480
|
+
}
|
|
450
481
|
/** Rewrites the `where` of the migration builder's `t.index()`, `t.unique()`, `t.addIndex()` and `m.createIndex()`. */
|
|
451
482
|
function rewriteBuilderCall(call, ctx) {
|
|
452
483
|
const at = ts.isPropertyAccessExpression(call.expression)
|
|
@@ -458,6 +489,31 @@ function rewriteBuilderCall(call, ctx) {
|
|
|
458
489
|
const options = call.arguments[at];
|
|
459
490
|
rewriteIndexWhere(options && ts.isObjectLiteralExpression(options) ? options : undefined, ctx);
|
|
460
491
|
}
|
|
492
|
+
const UPSERT_CALLS = new Set(['upsertOne', 'upsertMany', 'upsertInto']);
|
|
493
|
+
/**
|
|
494
|
+
* Rewrites an upsert's options holding `update` alone into that update, its fourth argument now. Read wherever it is
|
|
495
|
+
* called, since a querier is seldom imported from uql where it is used. Any other fourth argument is already an
|
|
496
|
+
* update, `{}` included, so a second run changes nothing.
|
|
497
|
+
*/
|
|
498
|
+
function rewriteUpsertCall(call, ctx) {
|
|
499
|
+
const callee = call.expression;
|
|
500
|
+
const name = ts.isPropertyAccessExpression(callee) ? callee.name : callee;
|
|
501
|
+
const options = call.arguments[3];
|
|
502
|
+
const update = options && upsertUpdate(options);
|
|
503
|
+
if (ts.isIdentifier(name) && UPSERT_CALLS.has(name.text) && options && update) {
|
|
504
|
+
ctx.edits.push(replaced(options, update.getText()));
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
/** The value of options holding `update` alone, `{ update: value }` or `{ update }`. */
|
|
508
|
+
function upsertUpdate(options) {
|
|
509
|
+
const [property] = ts.isObjectLiteralExpression(options) && options.properties.length === 1 ? options.properties : [];
|
|
510
|
+
if (property && ts.isPropertyAssignment(property) && propertyKey(property.name) === 'update') {
|
|
511
|
+
return property.initializer;
|
|
512
|
+
}
|
|
513
|
+
return property && ts.isShorthandPropertyAssignment(property) && property.name.text === 'update'
|
|
514
|
+
? property.name
|
|
515
|
+
: undefined;
|
|
516
|
+
}
|
|
461
517
|
/**
|
|
462
518
|
* `owner` is the declaring class's parameter and `target` the related one's, read off the `entity`
|
|
463
519
|
* getter unless the caller knows it from the property's type.
|
|
@@ -556,13 +612,7 @@ function unwrapRelationAlias(node, ctx) {
|
|
|
556
612
|
declared.typeName.text === 'Relation' &&
|
|
557
613
|
declared.typeArguments?.length === 1) {
|
|
558
614
|
ctx.edits.push(replaced(declared, declared.typeArguments[0].getText()));
|
|
559
|
-
ctx.
|
|
560
|
-
}
|
|
561
|
-
}
|
|
562
|
-
/** Counts `Relation<T>` wherever it appears, including the places this codemod does not rewrite. */
|
|
563
|
-
function countRelationAlias(node, ctx) {
|
|
564
|
-
if (ts.isTypeReferenceNode(node) && ts.isIdentifier(node.typeName) && node.typeName.text === 'Relation') {
|
|
565
|
-
ctx.relationAlias.seen += 1;
|
|
615
|
+
ctx.rewritten.Relation += 1;
|
|
566
616
|
}
|
|
567
617
|
}
|
|
568
618
|
/** Removes a statement together with the rest of its line, so nothing is left blank behind it. */
|
|
@@ -573,17 +623,25 @@ function removeStatement(node) {
|
|
|
573
623
|
return { start: node.getStart(), end: nextLineStart ?? node.getEnd(), text: '' };
|
|
574
624
|
}
|
|
575
625
|
/**
|
|
576
|
-
* Names `uql-orm` no longer exports and that the codemod does remove:
|
|
577
|
-
* every
|
|
626
|
+
* Names `uql-orm` no longer exports and that the codemod does remove: `Relation` once every usage was
|
|
627
|
+
* unwrapped, and `expr` once every default was rewritten. A removed *decorator* keeps its import on purpose (see
|
|
578
628
|
* {@link REMOVED_DECORATORS}).
|
|
579
629
|
*/
|
|
580
630
|
function deadImportNames(source, ctx) {
|
|
581
|
-
const
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
631
|
+
const imported = uqlImports(source, true);
|
|
632
|
+
// Every use of the name the file imports, the places no rewrite reaches included.
|
|
633
|
+
const uses = (name) => {
|
|
634
|
+
const element = imported.find((specifier) => importedName(specifier) === name);
|
|
635
|
+
return element ? usesOf(source, element.name, ctx.checker).length : 0;
|
|
636
|
+
};
|
|
637
|
+
const { rewritten } = ctx;
|
|
638
|
+
const relations = uses('Relation');
|
|
639
|
+
if (relations > rewritten.Relation) {
|
|
640
|
+
ctx.unresolved.push(`${source.fileName}: ${relations - rewritten.Relation} 'Relation<T>' reference(s) are somewhere this codemod ` +
|
|
641
|
+
'does not rewrite; unwrap them and drop the import by hand');
|
|
585
642
|
}
|
|
586
|
-
|
|
643
|
+
const names = ['Relation', 'expr'];
|
|
644
|
+
return new Set(names.filter((name) => rewritten[name] > 0 && rewritten[name] === uses(name)));
|
|
587
645
|
}
|
|
588
646
|
/**
|
|
589
647
|
* Removes `import 'reflect-metadata'`, since the polyfill only ever fed `design:type`, and each `dead` name
|
|
@@ -1037,16 +1095,16 @@ export function transformFile(source, checker) {
|
|
|
1037
1095
|
unresolved: [],
|
|
1038
1096
|
notes: [],
|
|
1039
1097
|
imports: new Map(),
|
|
1040
|
-
|
|
1098
|
+
rewritten: { Relation: 0, expr: 0 },
|
|
1041
1099
|
describe: (node) => `${source.fileName}:${lineOf(node) + 1}`,
|
|
1042
1100
|
};
|
|
1043
1101
|
const lineOf = (node) => source.getLineAndCharacterOfPosition(node.getStart()).line;
|
|
1044
1102
|
const rewritesRaw = uqlImports(source).some((element) => importedName(element) === 'raw');
|
|
1045
1103
|
// The builder's methods are known by name alone, so they are read only in a file that imports uql-orm.
|
|
1046
1104
|
const importsUql = uqlImportDeclarations(source, true).length > 0;
|
|
1105
|
+
const importsExpr = uqlImports(source, true).some((element) => importedName(element) === 'expr');
|
|
1047
1106
|
const visit = (node) => {
|
|
1048
1107
|
reportRemovedDecorators(node, ctx);
|
|
1049
|
-
countRelationAlias(node, ctx);
|
|
1050
1108
|
if (rewritesRaw) {
|
|
1051
1109
|
rewriteRawCall(node, ctx, source);
|
|
1052
1110
|
}
|
|
@@ -1059,9 +1117,13 @@ export function transformFile(source, checker) {
|
|
|
1059
1117
|
}
|
|
1060
1118
|
if (ts.isCallExpression(node)) {
|
|
1061
1119
|
rewriteDefineCall(node, ctx);
|
|
1120
|
+
rewriteUpsertCall(node, ctx);
|
|
1062
1121
|
if (importsUql) {
|
|
1063
1122
|
rewriteBuilderCall(node, ctx);
|
|
1064
1123
|
}
|
|
1124
|
+
if (importsExpr) {
|
|
1125
|
+
rewriteExprCall(node, ctx);
|
|
1126
|
+
}
|
|
1065
1127
|
}
|
|
1066
1128
|
if (ts.isPropertyAssignment(node)) {
|
|
1067
1129
|
rewriteStatementKeys(node, ctx);
|