uql-codemod 0.48.1 → 0.49.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +27 -16
  2. package/dist/builders.d.ts +18 -0
  3. package/dist/builders.js +588 -0
  4. package/dist/classOptions.d.ts +9 -0
  5. package/dist/classOptions.js +240 -0
  6. package/dist/columnMethods.d.ts +11 -0
  7. package/dist/columnMethods.js +6 -0
  8. package/dist/columnRefs.js +3 -10
  9. package/dist/context.d.ts +18 -5
  10. package/dist/context.js +22 -4
  11. package/dist/definers.d.ts +24 -0
  12. package/dist/definers.js +34 -0
  13. package/dist/edits.d.ts +43 -11
  14. package/dist/edits.js +105 -26
  15. package/dist/entitySql.d.ts +15 -16
  16. package/dist/entitySql.js +33 -31
  17. package/dist/imports.d.ts +33 -16
  18. package/dist/imports.js +213 -99
  19. package/dist/index.d.ts +3 -3
  20. package/dist/index.js +9 -12
  21. package/dist/jsonIndex.d.ts +11 -0
  22. package/dist/jsonIndex.js +78 -0
  23. package/dist/keyMaps.d.ts +3 -1
  24. package/dist/keyMaps.js +5 -1
  25. package/dist/migrationBuilders.d.ts +13 -0
  26. package/dist/migrationBuilders.js +182 -0
  27. package/dist/relationTarget.d.ts +6 -0
  28. package/dist/relationTarget.js +21 -0
  29. package/dist/schemaEntity.d.ts +12 -0
  30. package/dist/schemaEntity.js +518 -0
  31. package/dist/schemaOptions.d.ts +6 -0
  32. package/dist/schemaOptions.js +6 -0
  33. package/dist/statementSql.d.ts +2 -1
  34. package/dist/statementSql.js +10 -4
  35. package/dist/syntax.d.ts +54 -0
  36. package/dist/syntax.js +131 -1
  37. package/dist/transform.d.ts +11 -2
  38. package/dist/transform.js +174 -165
  39. package/dist/tsconfig.d.ts +3 -9
  40. package/dist/tsconfig.js +18 -22
  41. package/package.json +1 -1
  42. package/dist/fieldType.d.ts +0 -13
  43. package/dist/fieldType.js +0 -56
package/dist/syntax.js CHANGED
@@ -7,9 +7,91 @@ export function identifierText(node) {
7
7
  export function propertyKey(name) {
8
8
  return ts.isIdentifier(name) || ts.isStringLiteral(name) ? name.text : undefined;
9
9
  }
10
+ export function isNamedProperty(prop) {
11
+ return ts.isPropertyAssignment(prop) || ts.isShorthandPropertyAssignment(prop);
12
+ }
10
13
  /** The property `name` of an object literal, a shorthand included. */
11
14
  export function namedProperty(node, name) {
12
- return node.properties.find((prop) => (ts.isPropertyAssignment(prop) || ts.isShorthandPropertyAssignment(prop)) && propertyKey(prop.name) === name);
15
+ return node.properties.find((prop) => isNamedProperty(prop) && propertyKey(prop.name) === name);
16
+ }
17
+ /** The key a property is written under, a shorthand's included; nothing for a spread, a method or a computed key. */
18
+ export function keyOf(prop) {
19
+ return isNamedProperty(prop) ? propertyKey(prop.name) : undefined;
20
+ }
21
+ /** The options `value` writes: a literal to read and write into, or why it is not one. */
22
+ export function optionsOf(value) {
23
+ if (!ts.isObjectLiteralExpression(value)) {
24
+ return { kind: 'opaque', reason: `its options are passed as '${value.getText()}'` };
25
+ }
26
+ return value.properties.some(ts.isSpreadAssignment)
27
+ ? { kind: 'opaque', reason: 'its options object spreads another' }
28
+ : { kind: 'literal', node: value };
29
+ }
30
+ /**
31
+ * An object literal's named properties by key, each as its value (a shorthand's value is its name), or `undefined`
32
+ * where `node` is no literal or one of its properties is spread, computed or a method.
33
+ */
34
+ export function propertiesByKey(node) {
35
+ const literal = objectLiteral(node);
36
+ if (!literal) {
37
+ return undefined;
38
+ }
39
+ const props = new Map();
40
+ for (const prop of literal.properties) {
41
+ if (!isNamedProperty(prop)) {
42
+ return undefined;
43
+ }
44
+ const key = propertyKey(prop.name);
45
+ if (key === undefined) {
46
+ return undefined;
47
+ }
48
+ props.set(key, ts.isShorthandPropertyAssignment(prop) ? prop.name : prop.initializer);
49
+ }
50
+ return props;
51
+ }
52
+ /** The root a method chain starts from, and its methods in source order: `f.string().nullable()` is `f` and two. */
53
+ export function chainOf(node) {
54
+ const methods = [];
55
+ let root = node;
56
+ while (ts.isCallExpression(root) && ts.isPropertyAccessExpression(root.expression)) {
57
+ methods.unshift({ call: root, name: root.expression.name.text, receiver: root.expression.expression });
58
+ root = root.expression.expression;
59
+ }
60
+ return { root, methods };
61
+ }
62
+ export function hasModifier(node, kind) {
63
+ return ts.canHaveModifiers(node) && !!ts.getModifiers(node)?.some((modifier) => modifier.kind === kind);
64
+ }
65
+ /** `preferred`, or it numbered past every name `nodes` mention, so a parameter named so shadows nothing they read. */
66
+ export function freeName(preferred, nodes) {
67
+ const taken = (name) => nodes.some((node) => mentions(node, name));
68
+ let name = preferred;
69
+ for (let n = 2; taken(name); n++) {
70
+ name = `${preferred}${n}`;
71
+ }
72
+ return name;
73
+ }
74
+ /** Whether `node` is an identifier reading `name`, not a member named so. */
75
+ function readsName(node, name) {
76
+ return (ts.isIdentifier(node) &&
77
+ node.text === name &&
78
+ !(ts.isPropertyAccessExpression(node.parent) && node.parent.name === node));
79
+ }
80
+ /** Each identifier in `node` naming `name`, in source order, nested functions included, but none a member named so. */
81
+ export function identifierUses(node, name) {
82
+ const uses = [];
83
+ const visit = (child) => {
84
+ if (readsName(child, name)) {
85
+ uses.push(child);
86
+ }
87
+ ts.forEachChild(child, visit);
88
+ };
89
+ visit(node);
90
+ return uses;
91
+ }
92
+ /** Whether `node` reads a binding named `name`, which a callback parameter of that name would shadow: stops at the first. */
93
+ export function mentions(node, name) {
94
+ return readsName(node, name) || !!ts.forEachChild(node, (child) => mentions(child, name) || undefined);
13
95
  }
14
96
  /** The property `name` of an object literal that is written with a value. */
15
97
  export function propertyAssignment(node, name) {
@@ -22,6 +104,13 @@ export function propertyValue(node, name) {
22
104
  export function objectProperties(node) {
23
105
  return node && ts.isObjectLiteralExpression(node) ? node.properties.filter(ts.isPropertyAssignment) : [];
24
106
  }
107
+ /** The entries of a column list, written as an array or returned by its callback. */
108
+ export function columnListEntries(list) {
109
+ if (list && ts.isArrowFunction(list) && !ts.isBlock(list.body)) {
110
+ return arrayElements(list.body);
111
+ }
112
+ return arrayElements(list);
113
+ }
25
114
  /** The elements of an array literal, or none where `node` is not one. */
26
115
  export function arrayElements(node) {
27
116
  return node && ts.isArrayLiteralExpression(node) ? node.elements : [];
@@ -30,6 +119,35 @@ export function arrayElements(node) {
30
119
  export function objectLiteral(node) {
31
120
  return node && ts.isObjectLiteralExpression(node) ? node : undefined;
32
121
  }
122
+ const indentUnits = new WeakMap();
123
+ /** Whether `node` starts a line of code whose indent a file's unit is read from: a member, a property, a statement. */
124
+ const startsCodeLine = (node) => ts.isClassElement(node) ||
125
+ ts.isPropertyAssignment(node) ||
126
+ ts.isShorthandPropertyAssignment(node) ||
127
+ ts.isVariableStatement(node) ||
128
+ ts.isExpressionStatement(node) ||
129
+ ts.isClassDeclaration(node) ||
130
+ ts.isFunctionDeclaration(node) ||
131
+ ts.isImportDeclaration(node);
132
+ /** One level of indentation as the file writes it: the shallowest indent of its code, two spaces where it has none. */
133
+ export function indentUnit(source) {
134
+ const known = indentUnits.get(source);
135
+ if (known !== undefined) {
136
+ return known;
137
+ }
138
+ const indents = [];
139
+ const visit = (node) => {
140
+ const indent = startsCodeLine(node) ? indentOf(node) : '';
141
+ if (indent) {
142
+ indents.push(indent);
143
+ }
144
+ ts.forEachChild(node, visit);
145
+ };
146
+ visit(source);
147
+ const unit = indents.reduce((shallow, indent) => (indent.length < shallow.length ? indent : shallow), indents[0] ?? ' ');
148
+ indentUnits.set(source, unit);
149
+ return unit;
150
+ }
33
151
  /** A node's decorators, or none where it is a kind that cannot carry them. */
34
152
  export function decoratorsOf(node) {
35
153
  return ts.canHaveDecorators(node) ? (ts.getDecorators(node) ?? []) : [];
@@ -39,3 +157,15 @@ export function decoratorName(node) {
39
157
  const { expression } = node;
40
158
  return identifierText(ts.isCallExpression(expression) ? expression.expression : expression);
41
159
  }
160
+ /** The decorators declaring a field: `@Field`, and `@Id` for the key the class names. */
161
+ export const FIELD_DECORATORS = new Set(['Field', 'Id']);
162
+ /** Where the line holding offset `at` of `text` starts. */
163
+ export function lineStartOf(text, at) {
164
+ return text.lastIndexOf('\n', at - 1) + 1;
165
+ }
166
+ /** The whitespace the line holding `node` starts with. */
167
+ export function indentOf(node) {
168
+ const text = node.getSourceFile().text;
169
+ const line = text.slice(lineStartOf(text, node.getStart()), node.getStart());
170
+ return line.slice(0, line.length - line.trimStart().length);
171
+ }
@@ -1,4 +1,5 @@
1
1
  import ts from 'typescript';
2
+ import { type Pass } from './edits.js';
2
3
  export type FileResult = {
3
4
  readonly fileName: string;
4
5
  readonly text: string;
@@ -9,9 +10,17 @@ export type FileResult = {
9
10
  readonly notes: readonly string[];
10
11
  };
11
12
  /**
12
- * Rewrites one source file for the standard decorator spec. The builder's and querier's methods are known by
13
- * name, so they are read only in a file importing uql-orm, and `expr` only where it is uql's.
13
+ * Rewrites one file across every breaking change: the earlier ones off the checker, then column builders and schema
14
+ * chains off the text those produced, so neither pass edits what the other writes.
14
15
  */
15
16
  export declare function transformFile(source: ts.SourceFile, checker: ts.TypeChecker, options?: {
16
17
  readonly strictNullChecks: boolean;
17
18
  }): FileResult;
19
+ /**
20
+ * The rewrites the checker reads types for, up to the schema entities a class-form registration declares. The
21
+ * builder's and querier's methods are known by name, so they are read only in a file importing uql-orm, and `expr`
22
+ * only where it is uql's.
23
+ */
24
+ export declare function rewriteLegacy(source: ts.SourceFile, checker: ts.TypeChecker, options: {
25
+ readonly strictNullChecks: boolean;
26
+ }): FileResult & Pass;