@typeorm/codemod 1.0.0 → 1.0.2
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 +13 -10
- package/dist/cli/print-guide.js +2 -2
- package/dist/cli/print-summary.js +3 -2
- package/dist/cli/print-summary.js.map +1 -1
- package/dist/cli/print-usage.js +2 -1
- package/dist/cli/print-usage.js.map +1 -1
- package/dist/cli/run-transforms.js +181 -79
- package/dist/cli/run-transforms.js.map +1 -1
- package/dist/dependencies/v1.js +23 -9
- package/dist/dependencies/v1.js.map +1 -1
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -1
- package/dist/transforms/ast-helpers.js +779 -19
- package/dist/transforms/ast-helpers.js.map +1 -1
- package/dist/transforms/stats.js +11 -0
- package/dist/transforms/stats.js.map +1 -1
- package/dist/transforms/todo.js +42 -2
- package/dist/transforms/todo.js.map +1 -1
- package/dist/transforms/v1/column-readonly.js +28 -13
- package/dist/transforms/v1/column-readonly.js.map +1 -1
- package/dist/transforms/v1/column-unsigned-numeric.js +27 -26
- package/dist/transforms/v1/column-unsigned-numeric.js.map +1 -1
- package/dist/transforms/v1/column-width-zerofill.js +2 -1
- package/dist/transforms/v1/column-width-zerofill.js.map +1 -1
- package/dist/transforms/v1/connection-manager.js +82 -0
- package/dist/transforms/v1/connection-manager.js.map +1 -0
- package/dist/transforms/v1/connection-options-reader.js +214 -0
- package/dist/transforms/v1/connection-options-reader.js.map +1 -0
- package/dist/transforms/v1/connection-to-datasource.js +858 -93
- package/dist/transforms/v1/connection-to-datasource.js.map +1 -1
- package/dist/transforms/v1/datasource-expo.js +79 -0
- package/dist/transforms/v1/datasource-expo.js.map +1 -0
- package/dist/transforms/v1/datasource-mongodb.js +103 -64
- package/dist/transforms/v1/datasource-mongodb.js.map +1 -1
- package/dist/transforms/v1/datasource-mssql.js +88 -46
- package/dist/transforms/v1/datasource-mssql.js.map +1 -1
- package/dist/transforms/v1/datasource-mysql-connector.js +25 -6
- package/dist/transforms/v1/datasource-mysql-connector.js.map +1 -1
- package/dist/transforms/v1/datasource-name.js +19 -14
- package/dist/transforms/v1/datasource-name.js.map +1 -1
- package/dist/transforms/v1/datasource-sap.js +51 -26
- package/dist/transforms/v1/datasource-sap.js.map +1 -1
- package/dist/transforms/v1/datasource-sqlite-options.js +48 -13
- package/dist/transforms/v1/datasource-sqlite-options.js.map +1 -1
- package/dist/transforms/v1/datasource-sqlite-type.js +28 -7
- package/dist/transforms/v1/datasource-sqlite-type.js.map +1 -1
- package/dist/transforms/v1/file-logger.js +163 -0
- package/dist/transforms/v1/file-logger.js.map +1 -0
- package/dist/transforms/v1/find-options-join.js +84 -0
- package/dist/transforms/v1/find-options-join.js.map +1 -0
- package/dist/transforms/v1/find-options-lock-modes.js +26 -21
- package/dist/transforms/v1/find-options-lock-modes.js.map +1 -1
- package/dist/transforms/v1/find-options-string-relations.js +75 -9
- package/dist/transforms/v1/find-options-string-relations.js.map +1 -1
- package/dist/transforms/v1/find-options-string-select.js +75 -11
- package/dist/transforms/v1/find-options-string-select.js.map +1 -1
- package/dist/transforms/v1/global-functions.js +150 -64
- package/dist/transforms/v1/global-functions.js.map +1 -1
- package/dist/transforms/v1/index.js +16 -3
- package/dist/transforms/v1/index.js.map +1 -1
- package/dist/transforms/v1/migrations-get-all.js +25 -9
- package/dist/transforms/v1/migrations-get-all.js.map +1 -1
- package/dist/transforms/v1/mongodb-stats.js +21 -11
- package/dist/transforms/v1/mongodb-stats.js.map +1 -1
- package/dist/transforms/v1/mongodb-types.js +59 -2
- package/dist/transforms/v1/mongodb-types.js.map +1 -1
- package/dist/transforms/v1/query-builder-native-parameters.js +2 -0
- package/dist/transforms/v1/query-builder-native-parameters.js.map +1 -1
- package/dist/transforms/v1/query-builder-on-conflict.js +32 -18
- package/dist/transforms/v1/query-builder-on-conflict.js.map +1 -1
- package/dist/transforms/v1/query-builder-or-update.js +8 -4
- package/dist/transforms/v1/query-builder-or-update.js.map +1 -1
- package/dist/transforms/v1/query-builder-print-sql.js +18 -12
- package/dist/transforms/v1/query-builder-print-sql.js.map +1 -1
- package/dist/transforms/v1/query-builder-replace-property-names.js +16 -12
- package/dist/transforms/v1/query-builder-replace-property-names.js.map +1 -1
- package/dist/transforms/v1/query-builder-where-expression.js +29 -12
- package/dist/transforms/v1/query-builder-where-expression.js.map +1 -1
- package/dist/transforms/v1/query-runner-loaded-tables-views.js +1 -6
- package/dist/transforms/v1/query-runner-loaded-tables-views.js.map +1 -1
- package/dist/transforms/v1/relation-count.js +78 -12
- package/dist/transforms/v1/relation-count.js.map +1 -1
- package/dist/transforms/v1/repository-abstract.js +148 -34
- package/dist/transforms/v1/repository-abstract.js.map +1 -1
- package/dist/transforms/v1/repository-exist.js +20 -1
- package/dist/transforms/v1/repository-exist.js.map +1 -1
- package/dist/transforms/v1/repository-find-by-ids.js +67 -27
- package/dist/transforms/v1/repository-find-by-ids.js.map +1 -1
- package/dist/transforms/v1/repository-find-one-by-id.js +6 -0
- package/dist/transforms/v1/repository-find-one-by-id.js.map +1 -1
- package/dist/transforms/v1/use-container.js +65 -15
- package/dist/transforms/v1/use-container.js.map +1 -1
- package/package.json +3 -1
- package/dist/cli/colors.d.ts +0 -7
- package/dist/cli/colors.js +0 -12
- package/dist/cli/colors.js.map +0 -1
- package/dist/cli/error.d.ts +0 -1
- package/dist/cli/error.js +0 -11
- package/dist/cli/error.js.map +0 -1
- package/dist/cli/list-transforms.d.ts +0 -1
- package/dist/cli/parse-args.d.ts +0 -10
- package/dist/cli/print-guide.d.ts +0 -1
- package/dist/cli/print-summary.d.ts +0 -17
- package/dist/cli/print-todos.d.ts +0 -1
- package/dist/cli/print-usage.d.ts +0 -1
- package/dist/cli/run-dependencies.d.ts +0 -6
- package/dist/cli/run-transforms.d.ts +0 -21
- package/dist/cli/run.d.ts +0 -9
- package/dist/dependencies/config.d.ts +0 -24
- package/dist/dependencies/find-package-json.d.ts +0 -5
- package/dist/dependencies/index.d.ts +0 -5
- package/dist/dependencies/upgrade.d.ts +0 -11
- package/dist/dependencies/v1.d.ts +0 -2
- package/dist/index.d.ts +0 -2
- package/dist/lib/colors.d.ts +0 -9
- package/dist/lib/error.d.ts +0 -1
- package/dist/lib/format-time.d.ts +0 -1
- package/dist/lib/highlight.d.ts +0 -1
- package/dist/lib/spinner.d.ts +0 -5
- package/dist/transforms/ast-helpers.d.ts +0 -50
- package/dist/transforms/index.d.ts +0 -7
- package/dist/transforms/resolve.d.ts +0 -1
- package/dist/transforms/scan.d.ts +0 -4
- package/dist/transforms/scan.js +0 -33
- package/dist/transforms/scan.js.map +0 -1
- package/dist/transforms/stats.d.ts +0 -11
- package/dist/transforms/todo.d.ts +0 -2
- package/dist/transforms/transformer.d.ts +0 -8
- package/dist/transforms/v1/column-readonly.d.ts +0 -6
- package/dist/transforms/v1/column-unsigned-numeric.d.ts +0 -6
- package/dist/transforms/v1/column-width-zerofill.d.ts +0 -6
- package/dist/transforms/v1/connection-to-datasource.d.ts +0 -6
- package/dist/transforms/v1/datasource-mongodb.d.ts +0 -7
- package/dist/transforms/v1/datasource-mssql-domain.d.ts +0 -7
- package/dist/transforms/v1/datasource-mssql-domain.js +0 -35
- package/dist/transforms/v1/datasource-mssql-domain.js.map +0 -1
- package/dist/transforms/v1/datasource-mssql.d.ts +0 -7
- package/dist/transforms/v1/datasource-mysql-connector.d.ts +0 -6
- package/dist/transforms/v1/datasource-name.d.ts +0 -6
- package/dist/transforms/v1/datasource-sap.d.ts +0 -6
- package/dist/transforms/v1/datasource-sqlite-options.d.ts +0 -6
- package/dist/transforms/v1/datasource-sqlite-type.d.ts +0 -6
- package/dist/transforms/v1/find-options-lock-modes.d.ts +0 -6
- package/dist/transforms/v1/find-options-string-relations.d.ts +0 -6
- package/dist/transforms/v1/find-options-string-select.d.ts +0 -6
- package/dist/transforms/v1/global-functions.d.ts +0 -7
- package/dist/transforms/v1/index.d.ts +0 -40
- package/dist/transforms/v1/migrations-get-all.d.ts +0 -7
- package/dist/transforms/v1/mongodb-stats.d.ts +0 -7
- package/dist/transforms/v1/mongodb-types.d.ts +0 -6
- package/dist/transforms/v1/query-builder-native-parameters.d.ts +0 -6
- package/dist/transforms/v1/query-builder-on-conflict.d.ts +0 -7
- package/dist/transforms/v1/query-builder-or-update.d.ts +0 -6
- package/dist/transforms/v1/query-builder-print-sql.d.ts +0 -7
- package/dist/transforms/v1/query-builder-replace-property-names.d.ts +0 -7
- package/dist/transforms/v1/query-builder-where-expression.d.ts +0 -6
- package/dist/transforms/v1/query-runner-loaded-tables-views.d.ts +0 -7
- package/dist/transforms/v1/relation-count.d.ts +0 -7
- package/dist/transforms/v1/remove-abstract-repository.d.ts +0 -5
- package/dist/transforms/v1/remove-abstract-repository.js +0 -93
- package/dist/transforms/v1/remove-abstract-repository.js.map +0 -1
- package/dist/transforms/v1/remove-connector-package.d.ts +0 -4
- package/dist/transforms/v1/remove-connector-package.js +0 -19
- package/dist/transforms/v1/remove-connector-package.js.map +0 -1
- package/dist/transforms/v1/remove-datasource-name.d.ts +0 -4
- package/dist/transforms/v1/remove-datasource-name.js +0 -56
- package/dist/transforms/v1/remove-datasource-name.js.map +0 -1
- package/dist/transforms/v1/remove-mongodb-options.d.ts +0 -5
- package/dist/transforms/v1/remove-mongodb-options.js +0 -86
- package/dist/transforms/v1/remove-mongodb-options.js.map +0 -1
- package/dist/transforms/v1/remove-relation-count.d.ts +0 -5
- package/dist/transforms/v1/remove-relation-count.js +0 -49
- package/dist/transforms/v1/remove-relation-count.js.map +0 -1
- package/dist/transforms/v1/remove-replace-property-names.d.ts +0 -5
- package/dist/transforms/v1/remove-replace-property-names.js +0 -35
- package/dist/transforms/v1/remove-replace-property-names.js.map +0 -1
- package/dist/transforms/v1/remove-sap-options.d.ts +0 -4
- package/dist/transforms/v1/remove-sap-options.js +0 -54
- package/dist/transforms/v1/remove-sap-options.js.map +0 -1
- package/dist/transforms/v1/remove-unsigned-numeric.d.ts +0 -4
- package/dist/transforms/v1/remove-unsigned-numeric.js +0 -76
- package/dist/transforms/v1/remove-unsigned-numeric.js.map +0 -1
- package/dist/transforms/v1/remove-use-container.d.ts +0 -5
- package/dist/transforms/v1/remove-use-container.js +0 -63
- package/dist/transforms/v1/remove-use-container.js.map +0 -1
- package/dist/transforms/v1/remove-width-zerofill.d.ts +0 -4
- package/dist/transforms/v1/remove-width-zerofill.js +0 -29
- package/dist/transforms/v1/remove-width-zerofill.js.map +0 -1
- package/dist/transforms/v1/rename-connection-to-datasource.d.ts +0 -4
- package/dist/transforms/v1/rename-connection-to-datasource.js +0 -111
- package/dist/transforms/v1/rename-connection-to-datasource.js.map +0 -1
- package/dist/transforms/v1/rename-exist-to-exists.d.ts +0 -4
- package/dist/transforms/v1/rename-exist-to-exists.js +0 -25
- package/dist/transforms/v1/rename-exist-to-exists.js.map +0 -1
- package/dist/transforms/v1/rename-find-by-ids.d.ts +0 -4
- package/dist/transforms/v1/rename-find-by-ids.js +0 -64
- package/dist/transforms/v1/rename-find-by-ids.js.map +0 -1
- package/dist/transforms/v1/rename-get-all-migrations.d.ts +0 -5
- package/dist/transforms/v1/rename-get-all-migrations.js +0 -32
- package/dist/transforms/v1/rename-get-all-migrations.js.map +0 -1
- package/dist/transforms/v1/rename-loaded-tables-views.d.ts +0 -5
- package/dist/transforms/v1/rename-loaded-tables-views.js +0 -48
- package/dist/transforms/v1/rename-loaded-tables-views.js.map +0 -1
- package/dist/transforms/v1/rename-or-update-overload.d.ts +0 -4
- package/dist/transforms/v1/rename-or-update-overload.js +0 -46
- package/dist/transforms/v1/rename-or-update-overload.js.map +0 -1
- package/dist/transforms/v1/rename-print-sql-to-log-query.d.ts +0 -4
- package/dist/transforms/v1/rename-print-sql-to-log-query.js +0 -25
- package/dist/transforms/v1/rename-print-sql-to-log-query.js.map +0 -1
- package/dist/transforms/v1/replace-global-functions.d.ts +0 -5
- package/dist/transforms/v1/replace-global-functions.js +0 -92
- package/dist/transforms/v1/replace-global-functions.js.map +0 -1
- package/dist/transforms/v1/replace-lock-modes.d.ts +0 -4
- package/dist/transforms/v1/replace-lock-modes.js +0 -75
- package/dist/transforms/v1/replace-lock-modes.js.map +0 -1
- package/dist/transforms/v1/replace-mongodb-stats.d.ts +0 -5
- package/dist/transforms/v1/replace-mongodb-stats.js +0 -54
- package/dist/transforms/v1/replace-mongodb-stats.js.map +0 -1
- package/dist/transforms/v1/replace-mongodb-types.d.ts +0 -4
- package/dist/transforms/v1/replace-mongodb-types.js +0 -72
- package/dist/transforms/v1/replace-mongodb-types.js.map +0 -1
- package/dist/transforms/v1/replace-mssql-domain.d.ts +0 -5
- package/dist/transforms/v1/replace-mssql-domain.js +0 -25
- package/dist/transforms/v1/replace-mssql-domain.js.map +0 -1
- package/dist/transforms/v1/replace-on-conflict.d.ts +0 -5
- package/dist/transforms/v1/replace-on-conflict.js +0 -49
- package/dist/transforms/v1/replace-on-conflict.js.map +0 -1
- package/dist/transforms/v1/replace-readonly-column.d.ts +0 -4
- package/dist/transforms/v1/replace-readonly-column.js +0 -28
- package/dist/transforms/v1/replace-readonly-column.js.map +0 -1
- package/dist/transforms/v1/replace-set-native-parameters.d.ts +0 -4
- package/dist/transforms/v1/replace-set-native-parameters.js +0 -25
- package/dist/transforms/v1/replace-set-native-parameters.js.map +0 -1
- package/dist/transforms/v1/replace-sqlite-options.d.ts +0 -4
- package/dist/transforms/v1/replace-sqlite-options.js +0 -29
- package/dist/transforms/v1/replace-sqlite-options.js.map +0 -1
- package/dist/transforms/v1/replace-sqlite-type.d.ts +0 -4
- package/dist/transforms/v1/replace-sqlite-type.js +0 -22
- package/dist/transforms/v1/replace-sqlite-type.js.map +0 -1
- package/dist/transforms/v1/replace-where-expression-type.d.ts +0 -4
- package/dist/transforms/v1/replace-where-expression-type.js +0 -41
- package/dist/transforms/v1/replace-where-expression-type.js.map +0 -1
- package/dist/transforms/v1/repository-abstract.d.ts +0 -7
- package/dist/transforms/v1/repository-exist.d.ts +0 -6
- package/dist/transforms/v1/repository-find-by-ids.d.ts +0 -6
- package/dist/transforms/v1/repository-find-one-by-id.d.ts +0 -6
- package/dist/transforms/v1/upgrade-dependencies.d.ts +0 -15
- package/dist/transforms/v1/upgrade-dependencies.js +0 -163
- package/dist/transforms/v1/upgrade-dependencies.js.map +0 -1
- package/dist/transforms/v1/use-container.d.ts +0 -7
|
@@ -6,42 +6,237 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
6
6
|
exports.fn = exports.connectionToDataSource = exports.description = exports.name = void 0;
|
|
7
7
|
const node_path_1 = __importDefault(require("node:path"));
|
|
8
8
|
const ast_helpers_1 = require("../ast-helpers");
|
|
9
|
+
/**
|
|
10
|
+
* Unwraps common TypeScript expression wrappers around an identifier and
|
|
11
|
+
* returns the identifier's name. Handles `ds as DataSource`, `ds!`,
|
|
12
|
+
* `ds satisfies DataSource`, and the angle-bracket cast `<DataSource>ds`;
|
|
13
|
+
* identifiers reached through these wrappers are tracked alongside bare
|
|
14
|
+
* identifiers so accessor-chain transforms don't miss them.
|
|
15
|
+
*/
|
|
16
|
+
const unwrapIdentifierName = (node) => {
|
|
17
|
+
let current = node;
|
|
18
|
+
while (true) {
|
|
19
|
+
if (current.type === "Identifier")
|
|
20
|
+
return current.name;
|
|
21
|
+
if (current.type === "TSAsExpression" ||
|
|
22
|
+
current.type === "TSNonNullExpression" ||
|
|
23
|
+
current.type === "TSSatisfiesExpression" ||
|
|
24
|
+
current.type === "TSTypeAssertion") {
|
|
25
|
+
current = current.expression;
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
return null;
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
// Builds `Extract<DataSourceOptions, { type: "<literal>" }>` as a
|
|
32
|
+
// TSTypeReference node. Parses a synthetic type alias and pulls out its
|
|
33
|
+
// right-hand side so the returned node carries source-location info —
|
|
34
|
+
// recast otherwise splits builder-made nodes across lines because they
|
|
35
|
+
// have no `loc`, and Prettier preserves those line breaks verbatim.
|
|
36
|
+
// Drivers that share a literal with a sibling (mysql / mariadb both on
|
|
37
|
+
// MysqlDataSourceOptions) emit a union so `Extract` matches the
|
|
38
|
+
// declared union-typed `type` field.
|
|
39
|
+
const buildExtractDataSourceOptions = (j, literals) => {
|
|
40
|
+
const unionLiteral = literals.map((lit) => `"${lit}"`).join(" | ");
|
|
41
|
+
const source = `type __TypeormCodemodExtract = Extract<DataSourceOptions, { type: ${unionLiteral} }>`;
|
|
42
|
+
const aliasPath = j(source).find(j.TSTypeAliasDeclaration).paths()[0];
|
|
43
|
+
return aliasPath.node
|
|
44
|
+
.typeAnnotation;
|
|
45
|
+
};
|
|
46
|
+
// Ensures `import type { DataSourceOptions } from "typeorm"` is present.
|
|
47
|
+
// Augments an existing `import type` from `"typeorm"` when one exists, or
|
|
48
|
+
// emits a new line after the last import otherwise. Idempotent — a second
|
|
49
|
+
// run finds `DataSourceOptions` already imported and returns.
|
|
50
|
+
const ensureDataSourceOptionsTypeImport = (root, j) => {
|
|
51
|
+
const typeormImports = root.find(j.ImportDeclaration, {
|
|
52
|
+
source: { value: "typeorm" },
|
|
53
|
+
});
|
|
54
|
+
let hasIt = false;
|
|
55
|
+
typeormImports.forEach((p) => {
|
|
56
|
+
p.node.specifiers?.forEach((spec) => {
|
|
57
|
+
if (spec.type === "ImportSpecifier" &&
|
|
58
|
+
spec.imported.type === "Identifier" &&
|
|
59
|
+
spec.imported.name === "DataSourceOptions") {
|
|
60
|
+
hasIt = true;
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
if (hasIt)
|
|
65
|
+
return;
|
|
66
|
+
// Prefer augmenting an existing `import type { ... } from "typeorm"`
|
|
67
|
+
// — but only when that declaration is a pure named-specifier form.
|
|
68
|
+
// Pushing an `ImportSpecifier` into a namespace or default-only import
|
|
69
|
+
// (`import type * as ns` / `import type D`) produces invalid TS.
|
|
70
|
+
let augmented = false;
|
|
71
|
+
typeormImports.forEach((p) => {
|
|
72
|
+
if (augmented)
|
|
73
|
+
return;
|
|
74
|
+
if (p.node.importKind !== "type")
|
|
75
|
+
return;
|
|
76
|
+
const specifiers = p.node.specifiers ?? [];
|
|
77
|
+
const onlyNamed = specifiers.every((s) => s.type === "ImportSpecifier");
|
|
78
|
+
if (!onlyNamed)
|
|
79
|
+
return;
|
|
80
|
+
p.node.specifiers?.push(j.importSpecifier(j.identifier("DataSourceOptions")));
|
|
81
|
+
augmented = true;
|
|
82
|
+
});
|
|
83
|
+
if (augmented)
|
|
84
|
+
return;
|
|
85
|
+
const newImport = j.importDeclaration([j.importSpecifier(j.identifier("DataSourceOptions"))], j.literal("typeorm"));
|
|
86
|
+
newImport.importKind = "type";
|
|
87
|
+
const allImports = root.find(j.ImportDeclaration);
|
|
88
|
+
if (allImports.length > 0) {
|
|
89
|
+
allImports.at(-1).insertAfter(newImport);
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
root.find(j.Program).forEach((p) => {
|
|
93
|
+
p.node.body.unshift(newImport);
|
|
94
|
+
});
|
|
95
|
+
}
|
|
96
|
+
};
|
|
97
|
+
// Resolves the inner Identifier of a TSParameterProperty's `.parameter`,
|
|
98
|
+
// handling both the plain `Identifier` and default-valued `AssignmentPattern`
|
|
99
|
+
// forms. Returns null when neither shape applies.
|
|
100
|
+
const resolveTSParameterPropertyIdentifier = (inner) => {
|
|
101
|
+
if (inner.type === "Identifier")
|
|
102
|
+
return inner;
|
|
103
|
+
if (inner.type === "AssignmentPattern" &&
|
|
104
|
+
inner.left.type === "Identifier") {
|
|
105
|
+
return inner.left;
|
|
106
|
+
}
|
|
107
|
+
return null;
|
|
108
|
+
};
|
|
109
|
+
// Rename `connection` to `dataSource` on every ObjectProperty in `arg`.
|
|
110
|
+
// Returns true when at least one property was renamed. The shorthand
|
|
111
|
+
// `{ connection }` becomes `{ dataSource: connection }` — the variable
|
|
112
|
+
// reference stays intact and the object drops the shorthand flag.
|
|
113
|
+
const renameConnectionKeyToDataSource = (arg) => {
|
|
114
|
+
let changed = false;
|
|
115
|
+
for (const prop of arg.properties) {
|
|
116
|
+
if (prop.type !== "Property" && prop.type !== "ObjectProperty")
|
|
117
|
+
continue;
|
|
118
|
+
const p = prop;
|
|
119
|
+
if (p.key.type !== "Identifier" || p.key.name !== "connection")
|
|
120
|
+
continue;
|
|
121
|
+
p.key.name = "dataSource";
|
|
122
|
+
if (p.shorthand)
|
|
123
|
+
p.shorthand = false;
|
|
124
|
+
changed = true;
|
|
125
|
+
}
|
|
126
|
+
return changed;
|
|
127
|
+
};
|
|
128
|
+
// Remove every `connection` ObjectProperty from `arg`. Returns true when
|
|
129
|
+
// at least one property was dropped.
|
|
130
|
+
const dropConnectionKey = (arg) => {
|
|
131
|
+
const before = arg.properties.length;
|
|
132
|
+
arg.properties = arg.properties.filter((prop) => {
|
|
133
|
+
if (prop.type !== "Property" && prop.type !== "ObjectProperty") {
|
|
134
|
+
return true;
|
|
135
|
+
}
|
|
136
|
+
const p = prop;
|
|
137
|
+
return !(p.key.type === "Identifier" && p.key.name === "connection");
|
|
138
|
+
});
|
|
139
|
+
return arg.properties.length !== before;
|
|
140
|
+
};
|
|
141
|
+
// Walks every `new X(...)` whose callee is one of the tracked metadata
|
|
142
|
+
// constructors and rewrites the `connection` option key according to the
|
|
143
|
+
// constructor's v1 semantics (rename vs drop).
|
|
144
|
+
const rewriteMetadataConstructors = (root, j, entityMetadataLocalNames, indirectDataSourceLocalNames, hasChanges) => {
|
|
145
|
+
root.find(j.NewExpression).forEach((path) => {
|
|
146
|
+
const callee = path.node.callee;
|
|
147
|
+
if (callee.type !== "Identifier")
|
|
148
|
+
return;
|
|
149
|
+
const name = callee.name;
|
|
150
|
+
const isEntityMetadata = entityMetadataLocalNames.has(name);
|
|
151
|
+
const isIndirect = indirectDataSourceLocalNames.has(name);
|
|
152
|
+
if (!isEntityMetadata && !isIndirect)
|
|
153
|
+
return;
|
|
154
|
+
const [arg] = path.node.arguments;
|
|
155
|
+
if (arg?.type !== "ObjectExpression")
|
|
156
|
+
return;
|
|
157
|
+
const changed = isEntityMetadata
|
|
158
|
+
? renameConnectionKeyToDataSource(arg)
|
|
159
|
+
: dropConnectionKey(arg);
|
|
160
|
+
if (changed)
|
|
161
|
+
hasChanges = true;
|
|
162
|
+
});
|
|
163
|
+
return hasChanges;
|
|
164
|
+
};
|
|
9
165
|
exports.name = node_path_1.default.basename(__filename, node_path_1.default.extname(__filename));
|
|
10
166
|
exports.description = "migrate from `Connection` to `DataSource`";
|
|
11
167
|
const connectionToDataSource = (file, api) => {
|
|
12
168
|
const j = api.jscodeshift;
|
|
13
169
|
const root = j(file.source);
|
|
170
|
+
// File-level scope gate: without a typeorm import anywhere in the file,
|
|
171
|
+
// occurrences of `Connection` / `DataSource` must belong to an
|
|
172
|
+
// unrelated library (e.g. mongoose `new Connection().connect()`) and
|
|
173
|
+
// this transform must not touch them.
|
|
174
|
+
if (!(0, ast_helpers_1.fileImportsFrom)(root, j, "typeorm"))
|
|
175
|
+
return undefined;
|
|
14
176
|
let hasChanges = false;
|
|
15
|
-
//
|
|
177
|
+
// Generic type renames. Driver-specific *ConnectionOptions types are
|
|
178
|
+
// handled separately via the Extract rewrite below — they're not
|
|
179
|
+
// top-level exports from `"typeorm"`, so the codemod can't just rename
|
|
180
|
+
// the identifier and leave a broken import behind.
|
|
16
181
|
const typeRenames = {
|
|
17
182
|
Connection: "DataSource",
|
|
18
183
|
ConnectionOptions: "DataSourceOptions",
|
|
19
184
|
BaseConnectionOptions: "BaseDataSourceOptions",
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
185
|
+
};
|
|
186
|
+
// Maps every driver-specific options type name (both the v0 form ending
|
|
187
|
+
// in `ConnectionOptions` and the v1 form ending in `DataSourceOptions`)
|
|
188
|
+
// to the `type` literal(s) the driver carries. Used to rewrite type
|
|
189
|
+
// references to `Extract<DataSourceOptions, { type: "..." }>` so users
|
|
190
|
+
// don't need deep-path imports like `typeorm/driver/sap/...` for a
|
|
191
|
+
// single field annotation.
|
|
192
|
+
const driverOptionTypeLiterals = {
|
|
193
|
+
AuroraMysqlConnectionOptions: ["aurora-mysql"],
|
|
194
|
+
AuroraMysqlDataSourceOptions: ["aurora-mysql"],
|
|
195
|
+
AuroraPostgresConnectionOptions: ["aurora-postgres"],
|
|
196
|
+
AuroraPostgresDataSourceOptions: ["aurora-postgres"],
|
|
197
|
+
BetterSqlite3ConnectionOptions: ["better-sqlite3"],
|
|
198
|
+
BetterSqlite3DataSourceOptions: ["better-sqlite3"],
|
|
199
|
+
CapacitorConnectionOptions: ["capacitor"],
|
|
200
|
+
CapacitorDataSourceOptions: ["capacitor"],
|
|
201
|
+
CockroachConnectionOptions: ["cockroachdb"],
|
|
202
|
+
CockroachDataSourceOptions: ["cockroachdb"],
|
|
203
|
+
CordovaConnectionOptions: ["cordova"],
|
|
204
|
+
CordovaDataSourceOptions: ["cordova"],
|
|
205
|
+
ExpoConnectionOptions: ["expo"],
|
|
206
|
+
ExpoDataSourceOptions: ["expo"],
|
|
207
|
+
MongoConnectionOptions: ["mongodb"],
|
|
208
|
+
MongoDataSourceOptions: ["mongodb"],
|
|
209
|
+
// MySQL options cover both `type: "mysql"` and `type: "mariadb"`.
|
|
210
|
+
// Using a single literal would make `Extract` return `never`, so we
|
|
211
|
+
// emit a union `{ type: "mysql" | "mariadb" }` that matches.
|
|
212
|
+
MysqlConnectionOptions: ["mysql", "mariadb"],
|
|
213
|
+
MysqlDataSourceOptions: ["mysql", "mariadb"],
|
|
214
|
+
NativescriptConnectionOptions: ["nativescript"],
|
|
215
|
+
NativescriptDataSourceOptions: ["nativescript"],
|
|
216
|
+
OracleConnectionOptions: ["oracle"],
|
|
217
|
+
OracleDataSourceOptions: ["oracle"],
|
|
218
|
+
PostgresConnectionOptions: ["postgres"],
|
|
219
|
+
PostgresDataSourceOptions: ["postgres"],
|
|
220
|
+
ReactNativeConnectionOptions: ["react-native"],
|
|
221
|
+
ReactNativeDataSourceOptions: ["react-native"],
|
|
222
|
+
SapConnectionOptions: ["sap"],
|
|
223
|
+
SapDataSourceOptions: ["sap"],
|
|
224
|
+
// The v0 `sqlite` driver was removed; its options type maps to
|
|
225
|
+
// `better-sqlite3`'s `type` literal in v1.
|
|
226
|
+
SqliteConnectionOptions: ["better-sqlite3"],
|
|
227
|
+
SpannerConnectionOptions: ["spanner"],
|
|
228
|
+
SpannerDataSourceOptions: ["spanner"],
|
|
229
|
+
SqljsConnectionOptions: ["sqljs"],
|
|
230
|
+
SqljsDataSourceOptions: ["sqljs"],
|
|
231
|
+
SqlServerConnectionOptions: ["mssql"],
|
|
232
|
+
SqlServerDataSourceOptions: ["mssql"],
|
|
233
|
+
};
|
|
39
234
|
const methodRenames = {
|
|
40
235
|
connect: "initialize",
|
|
41
236
|
close: "destroy",
|
|
42
237
|
};
|
|
43
|
-
// TypeORM types whose instances
|
|
44
|
-
//
|
|
238
|
+
// TypeORM types whose instances had their `.connection` property renamed
|
|
239
|
+
// to `.dataSource` directly.
|
|
45
240
|
const typesWithConnectionProp = new Set([
|
|
46
241
|
"QueryRunner",
|
|
47
242
|
"EntityManager",
|
|
@@ -54,33 +249,292 @@ const connectionToDataSource = (file, api) => {
|
|
|
54
249
|
"DeleteQueryBuilder",
|
|
55
250
|
"SoftDeleteQueryBuilder",
|
|
56
251
|
"RelationQueryBuilder",
|
|
252
|
+
"EntityMetadata",
|
|
253
|
+
// Subscriber event types — all extend BaseEvent which deprecated
|
|
254
|
+
// `connection` in favor of `dataSource`. Covers the usual destructure
|
|
255
|
+
// pattern in subscriber handlers: `const { connection } = event`.
|
|
256
|
+
"BaseEvent",
|
|
257
|
+
"InsertEvent",
|
|
258
|
+
"UpdateEvent",
|
|
259
|
+
"RemoveEvent",
|
|
260
|
+
"SoftRemoveEvent",
|
|
261
|
+
"RecoverEvent",
|
|
262
|
+
"LoadEvent",
|
|
263
|
+
"QueryEvent",
|
|
264
|
+
"TransactionStartEvent",
|
|
265
|
+
"TransactionCommitEvent",
|
|
266
|
+
"TransactionRollbackEvent",
|
|
267
|
+
]);
|
|
268
|
+
// Metadata types whose v0.3 `.connection` getter was removed entirely in
|
|
269
|
+
// v1 (renamed in #12249). Access now goes through `.entityMetadata.dataSource`
|
|
270
|
+
// — a naive `.dataSource` rewrite would produce invalid code because these
|
|
271
|
+
// classes never exposed a top-level `.dataSource` field.
|
|
272
|
+
const typesWithIndirectDataSource = new Set([
|
|
273
|
+
"ColumnMetadata",
|
|
274
|
+
"IndexMetadata",
|
|
57
275
|
]);
|
|
58
|
-
// Collect local names imported from "typeorm" that need renaming
|
|
59
276
|
const localRenames = new Map();
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
277
|
+
const typeormPathPrefix = "typeorm/";
|
|
278
|
+
// Returns the rewritten module path for a `typeorm[/...]` import, or the
|
|
279
|
+
// original when no rewrite applies. Swaps the last path segment when
|
|
280
|
+
// that segment is an exact rename key (e.g. `.../Connection` →
|
|
281
|
+
// `.../DataSource`). Driver-specific options-type imports are handled
|
|
282
|
+
// by the Extract rewrite and never reach this helper.
|
|
283
|
+
const rewriteTypeormPath = (source) => {
|
|
284
|
+
if (!source.startsWith(typeormPathPrefix))
|
|
285
|
+
return source;
|
|
286
|
+
const lastSlash = source.lastIndexOf("/");
|
|
287
|
+
// No slash or trailing slash → no segment to rewrite
|
|
288
|
+
if (lastSlash === -1 || lastSlash === source.length - 1)
|
|
289
|
+
return source;
|
|
290
|
+
const lastSegment = source.slice(lastSlash + 1);
|
|
291
|
+
const renamedSegment = typeRenames[lastSegment];
|
|
292
|
+
if (!renamedSegment)
|
|
293
|
+
return source;
|
|
294
|
+
return source.slice(0, lastSlash + 1) + renamedSegment;
|
|
295
|
+
};
|
|
296
|
+
root.find(j.ImportDeclaration).forEach((path) => {
|
|
297
|
+
const source = path.node.source.value;
|
|
298
|
+
if (typeof source !== "string" ||
|
|
299
|
+
(source !== "typeorm" && !source.startsWith(typeormPathPrefix))) {
|
|
300
|
+
return;
|
|
301
|
+
}
|
|
63
302
|
path.node.specifiers?.forEach((spec) => {
|
|
64
|
-
if (spec.type
|
|
65
|
-
spec.imported.type
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
303
|
+
if (spec.type !== "ImportSpecifier" ||
|
|
304
|
+
spec.imported.type !== "Identifier") {
|
|
305
|
+
return;
|
|
306
|
+
}
|
|
307
|
+
const oldImported = spec.imported.name;
|
|
308
|
+
const newImported = typeRenames[oldImported];
|
|
309
|
+
if (!newImported)
|
|
310
|
+
return;
|
|
311
|
+
const hasAlias = spec.local?.type === "Identifier" &&
|
|
312
|
+
spec.local.name !== oldImported;
|
|
313
|
+
spec.imported.name = newImported;
|
|
314
|
+
// With an alias (`Connection as Foo`), the local binding already
|
|
315
|
+
// points to the renamed import — usages need no rewriting. Without
|
|
316
|
+
// one, propagate the rename to the local binding.
|
|
317
|
+
if (!hasAlias) {
|
|
318
|
+
const localName = spec.local?.type === "Identifier"
|
|
319
|
+
? spec.local.name
|
|
320
|
+
: oldImported;
|
|
321
|
+
localRenames.set(localName, newImported);
|
|
322
|
+
if (spec.local?.type === "Identifier") {
|
|
323
|
+
spec.local.name = newImported;
|
|
324
|
+
}
|
|
325
|
+
}
|
|
326
|
+
hasChanges = true;
|
|
327
|
+
});
|
|
328
|
+
// Dedupe specifiers that now share the same imported name after the
|
|
329
|
+
// rename — e.g. `import { Connection, DataSource }` would otherwise
|
|
330
|
+
// emit `import { DataSource, DataSource }`. Keep the first occurrence
|
|
331
|
+
// of each imported name and drop subsequent duplicates.
|
|
332
|
+
if (path.node.specifiers) {
|
|
333
|
+
const seen = new Set();
|
|
334
|
+
path.node.specifiers = path.node.specifiers.filter((spec) => {
|
|
335
|
+
if (spec.type !== "ImportSpecifier" ||
|
|
336
|
+
spec.imported.type !== "Identifier") {
|
|
337
|
+
return true;
|
|
338
|
+
}
|
|
339
|
+
const key = `${spec.imported.name}::${spec.local?.type === "Identifier" ? spec.local.name : ""}`;
|
|
340
|
+
if (seen.has(key)) {
|
|
78
341
|
hasChanges = true;
|
|
342
|
+
return false;
|
|
79
343
|
}
|
|
344
|
+
seen.add(key);
|
|
345
|
+
return true;
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
const rewritten = rewriteTypeormPath(source);
|
|
349
|
+
if (rewritten !== source) {
|
|
350
|
+
path.node.source.value = rewritten;
|
|
351
|
+
hasChanges = true;
|
|
352
|
+
}
|
|
353
|
+
});
|
|
354
|
+
// Driver-specific options types aren't top-level exports from "typeorm",
|
|
355
|
+
// and deep-path imports like `"typeorm/driver/sap/SapDataSourceOptions"`
|
|
356
|
+
// are brittle across refactors. Rewrite every reference to
|
|
357
|
+
// `Extract<DataSourceOptions, { type: "<driver>" }>` so users only need
|
|
358
|
+
// the union exported from the index. Handles both v0 (`SapConnectionOptions`)
|
|
359
|
+
// and v1 (`SapDataSourceOptions`) names, and aliased imports.
|
|
360
|
+
const driverOptionLocalBindings = new Map();
|
|
361
|
+
root.find(j.ImportDeclaration).forEach((importPath) => {
|
|
362
|
+
const importSource = importPath.node.source.value;
|
|
363
|
+
if (typeof importSource !== "string" ||
|
|
364
|
+
(importSource !== "typeorm" &&
|
|
365
|
+
!importSource.startsWith(typeormPathPrefix))) {
|
|
366
|
+
return;
|
|
367
|
+
}
|
|
368
|
+
const specifiers = importPath.node.specifiers ?? [];
|
|
369
|
+
const kept = specifiers.filter((spec) => {
|
|
370
|
+
if (spec.type !== "ImportSpecifier" ||
|
|
371
|
+
spec.imported.type !== "Identifier") {
|
|
372
|
+
return true;
|
|
80
373
|
}
|
|
374
|
+
const literals = driverOptionTypeLiterals[spec.imported.name];
|
|
375
|
+
if (!literals)
|
|
376
|
+
return true;
|
|
377
|
+
const localName = spec.local?.type === "Identifier"
|
|
378
|
+
? spec.local.name
|
|
379
|
+
: spec.imported.name;
|
|
380
|
+
driverOptionLocalBindings.set(localName, literals);
|
|
381
|
+
return false;
|
|
382
|
+
});
|
|
383
|
+
if (kept.length !== specifiers.length) {
|
|
384
|
+
importPath.node.specifiers = kept;
|
|
385
|
+
hasChanges = true;
|
|
386
|
+
if (kept.length === 0)
|
|
387
|
+
j(importPath).remove();
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
if (driverOptionLocalBindings.size > 0) {
|
|
391
|
+
// Walk every type reference in the file and replace tracked local
|
|
392
|
+
// bindings with an inline Extract<DataSourceOptions, { type: ... }>
|
|
393
|
+
// expression. TS narrowing via the `type` discriminator still picks
|
|
394
|
+
// the correct driver-specific fields.
|
|
395
|
+
root.find(j.TSTypeReference).forEach((refPath) => {
|
|
396
|
+
const typeName = refPath.node.typeName;
|
|
397
|
+
if (typeName.type !== "Identifier")
|
|
398
|
+
return;
|
|
399
|
+
const literals = driverOptionLocalBindings.get(typeName.name);
|
|
400
|
+
if (!literals)
|
|
401
|
+
return;
|
|
402
|
+
j(refPath).replaceWith(buildExtractDataSourceOptions(j, literals));
|
|
403
|
+
hasChanges = true;
|
|
81
404
|
});
|
|
405
|
+
// Emit / augment `import type { DataSourceOptions } from "typeorm"`
|
|
406
|
+
// so the Extract expressions resolve.
|
|
407
|
+
ensureDataSourceOptionsTypeImport(root, j);
|
|
408
|
+
}
|
|
409
|
+
// Re-export source paths (`export { X } from "typeorm/driver/..."` and
|
|
410
|
+
// `export * from "typeorm/driver/..."`) follow the same deep-path rewrite
|
|
411
|
+
// rules as import sources so barrel files that re-export renamed modules
|
|
412
|
+
// end up pointing at the v1 path.
|
|
413
|
+
root.find(j.ExportNamedDeclaration).forEach((exportPath) => {
|
|
414
|
+
const source = exportPath.node.source?.value;
|
|
415
|
+
if (typeof source !== "string")
|
|
416
|
+
return;
|
|
417
|
+
const rewritten = rewriteTypeormPath(source);
|
|
418
|
+
if (rewritten !== source) {
|
|
419
|
+
exportPath.node.source.value = rewritten;
|
|
420
|
+
hasChanges = true;
|
|
421
|
+
}
|
|
82
422
|
});
|
|
83
|
-
|
|
423
|
+
root.find(j.ExportAllDeclaration).forEach((exportPath) => {
|
|
424
|
+
const source = exportPath.node.source.value;
|
|
425
|
+
if (typeof source !== "string")
|
|
426
|
+
return;
|
|
427
|
+
const rewritten = rewriteTypeormPath(source);
|
|
428
|
+
if (rewritten !== source) {
|
|
429
|
+
exportPath.node.source.value = rewritten;
|
|
430
|
+
hasChanges = true;
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
// Cross-import dedup: the rewrites above can produce two ImportDeclarations
|
|
434
|
+
// that now target the same module with the same specifier (e.g. an
|
|
435
|
+
// existing `import type { BetterSqlite3DataSourceOptions }` plus a
|
|
436
|
+
// newly-renamed `import type { SqliteConnectionOptions }` from the old
|
|
437
|
+
// `sqlite/` path). Drop any later declaration whose (source, specifier
|
|
438
|
+
// set) tuple is already covered by an earlier one.
|
|
439
|
+
const seenImportKeys = new Map();
|
|
440
|
+
root.find(j.ImportDeclaration).forEach((importPath) => {
|
|
441
|
+
const source = importPath.node.source.value;
|
|
442
|
+
if (typeof source !== "string")
|
|
443
|
+
return;
|
|
444
|
+
const isTypeOnly = importPath.node.importKind === "type";
|
|
445
|
+
const specifiers = importPath.node.specifiers ?? [];
|
|
446
|
+
const specifierKey = specifiers
|
|
447
|
+
.map((spec) => {
|
|
448
|
+
const specType = spec.type;
|
|
449
|
+
if (specType === "ImportSpecifier") {
|
|
450
|
+
const s = spec;
|
|
451
|
+
const imported = s.imported.type === "Identifier"
|
|
452
|
+
? (s.imported.name ?? "")
|
|
453
|
+
: "";
|
|
454
|
+
const local = s.local?.type === "Identifier"
|
|
455
|
+
? (s.local.name ?? "")
|
|
456
|
+
: imported;
|
|
457
|
+
// Per-specifier importKind distinguishes
|
|
458
|
+
// `import { type X }` from `import { X }` — the two
|
|
459
|
+
// bindings have different runtime semantics and must
|
|
460
|
+
// not collapse into the same dedup key.
|
|
461
|
+
const kind = s.importKind === "type" ? "type:" : "";
|
|
462
|
+
return `named:${kind}${imported}->${local}`;
|
|
463
|
+
}
|
|
464
|
+
if (specType === "ImportDefaultSpecifier") {
|
|
465
|
+
const s = spec;
|
|
466
|
+
return `default:${s.local?.type === "Identifier" ? (s.local.name ?? "") : ""}`;
|
|
467
|
+
}
|
|
468
|
+
if (specType === "ImportNamespaceSpecifier") {
|
|
469
|
+
const s = spec;
|
|
470
|
+
return `namespace:${s.local?.type === "Identifier" ? (s.local.name ?? "") : ""}`;
|
|
471
|
+
}
|
|
472
|
+
return specType;
|
|
473
|
+
})
|
|
474
|
+
.sort()
|
|
475
|
+
.join("|");
|
|
476
|
+
const key = `${isTypeOnly ? "type:" : ""}${source}::${specifierKey}`;
|
|
477
|
+
if (seenImportKeys.has(key)) {
|
|
478
|
+
j(importPath).remove();
|
|
479
|
+
hasChanges = true;
|
|
480
|
+
return;
|
|
481
|
+
}
|
|
482
|
+
seenImportKeys.set(key, importPath.node);
|
|
483
|
+
});
|
|
484
|
+
// Rewrite a single `{ X [: Y] }` property in a destructured require of
|
|
485
|
+
// typeorm. Records the local binding in `localRenames` so the shared
|
|
486
|
+
// NewExpression/TSTypeReference rewrite loop below picks it up.
|
|
487
|
+
const rewriteRequireDestructuredProperty = (prop) => {
|
|
488
|
+
if (prop.type !== "Property" && prop.type !== "ObjectProperty") {
|
|
489
|
+
return false;
|
|
490
|
+
}
|
|
491
|
+
if (prop.key.type !== "Identifier")
|
|
492
|
+
return false;
|
|
493
|
+
const oldImported = prop.key.name;
|
|
494
|
+
const newName = typeRenames[oldImported];
|
|
495
|
+
if (!newName)
|
|
496
|
+
return false;
|
|
497
|
+
const localName = prop.value.type === "Identifier" ? prop.value.name : oldImported;
|
|
498
|
+
localRenames.set(localName, newName);
|
|
499
|
+
prop.key.name = newName;
|
|
500
|
+
if (prop.value.type === "Identifier" && prop.shorthand) {
|
|
501
|
+
prop.value.name = newName;
|
|
502
|
+
}
|
|
503
|
+
return true;
|
|
504
|
+
};
|
|
505
|
+
root.find(j.CallExpression, {
|
|
506
|
+
callee: { type: "Identifier", name: "require" },
|
|
507
|
+
}).forEach((callPath) => {
|
|
508
|
+
const [arg] = callPath.node.arguments;
|
|
509
|
+
if (!arg)
|
|
510
|
+
return;
|
|
511
|
+
const source = (0, ast_helpers_1.getStringValue)(arg);
|
|
512
|
+
if (typeof source !== "string" ||
|
|
513
|
+
(source !== "typeorm" && !source.startsWith(typeormPathPrefix))) {
|
|
514
|
+
return;
|
|
515
|
+
}
|
|
516
|
+
const rewrittenSource = rewriteTypeormPath(source);
|
|
517
|
+
if (rewrittenSource !== source) {
|
|
518
|
+
(0, ast_helpers_1.setStringValue)(arg, rewrittenSource);
|
|
519
|
+
hasChanges = true;
|
|
520
|
+
}
|
|
521
|
+
const parent = callPath.parent.node;
|
|
522
|
+
if (parent.type !== "VariableDeclarator")
|
|
523
|
+
return;
|
|
524
|
+
const id = parent.id;
|
|
525
|
+
if (id.type !== "ObjectPattern")
|
|
526
|
+
return;
|
|
527
|
+
const pattern = id;
|
|
528
|
+
for (const prop of pattern.properties) {
|
|
529
|
+
if (rewriteRequireDestructuredProperty(prop))
|
|
530
|
+
hasChanges = true;
|
|
531
|
+
}
|
|
532
|
+
});
|
|
533
|
+
// Rename re-exports from "typeorm" (e.g. barrel files that do
|
|
534
|
+
// `export { Connection } from "typeorm"`)
|
|
535
|
+
if ((0, ast_helpers_1.renameReExportSpecifiers)(root, j, "typeorm", typeRenames)) {
|
|
536
|
+
hasChanges = true;
|
|
537
|
+
}
|
|
84
538
|
for (const [oldName, newName] of localRenames) {
|
|
85
539
|
// TSTypeReference (e.g. const x: Connection = ...)
|
|
86
540
|
root.find(j.TSTypeReference, {
|
|
@@ -91,6 +545,15 @@ const connectionToDataSource = (file, api) => {
|
|
|
91
545
|
hasChanges = true;
|
|
92
546
|
}
|
|
93
547
|
});
|
|
548
|
+
// TSTypeQuery (e.g. const x: typeof Connection = ...)
|
|
549
|
+
root.find(j.TSTypeQuery, {
|
|
550
|
+
exprName: { name: oldName },
|
|
551
|
+
}).forEach((path) => {
|
|
552
|
+
if (path.node.exprName.type === "Identifier") {
|
|
553
|
+
path.node.exprName.name = newName;
|
|
554
|
+
hasChanges = true;
|
|
555
|
+
}
|
|
556
|
+
});
|
|
94
557
|
// NewExpression (e.g. new Connection(...))
|
|
95
558
|
root.find(j.NewExpression, {
|
|
96
559
|
callee: { type: "Identifier", name: oldName },
|
|
@@ -101,11 +564,26 @@ const connectionToDataSource = (file, api) => {
|
|
|
101
564
|
}
|
|
102
565
|
});
|
|
103
566
|
}
|
|
104
|
-
//
|
|
105
|
-
const
|
|
106
|
-
|
|
567
|
+
// DataSource-instance class names — used to recognize `new Connection()`
|
|
568
|
+
// / `const x: DataSource = ...` bindings. Must NOT include *Options types
|
|
569
|
+
// (e.g. `MysqlConnectionOptions`) because those are plain value-object
|
|
570
|
+
// shapes whose instances never carry `.connect()` / `.close()` methods,
|
|
571
|
+
// and treating them as DataSource-typed would incorrectly rename methods
|
|
572
|
+
// on parameters typed with those options.
|
|
573
|
+
//
|
|
574
|
+
// Expand to the set of LOCAL bindings — covers aliased ESM imports
|
|
575
|
+
// (`import { Connection as LegacyConn }`) and aliased CJS destructures
|
|
576
|
+
// (`const { Connection: LegacyConn } = require("typeorm")`) so code
|
|
577
|
+
// using the alias still gets `.connect()` → `.initialize()`. When no
|
|
578
|
+
// alias is in play the set simply contains `Connection` / `DataSource`
|
|
579
|
+
// from the plain imports.
|
|
580
|
+
const connectionTypeNames = (0, ast_helpers_1.expandLocalNamesForImports)(root, j, "typeorm", new Set(["Connection", "DataSource"]));
|
|
581
|
+
// Namespace-import locals for "typeorm" — used to gate qualified type
|
|
582
|
+
// references (`typeorm.Repository<T>`) inside `getTypeReferenceRootName`
|
|
583
|
+
// so array-element lookups don't mistake `Foo.Repository[]` from another
|
|
584
|
+
// library for a TypeORM receiver.
|
|
585
|
+
const typeormNamespaceNames = (0, ast_helpers_1.getNamespaceLocalNames)(root, j, "typeorm");
|
|
107
586
|
const connectionVarNames = new Set();
|
|
108
|
-
// Variables assigned from new Connection(...) / new DataSource(...)
|
|
109
587
|
root.find(j.VariableDeclarator).forEach((path) => {
|
|
110
588
|
const init = path.node.init;
|
|
111
589
|
if (init?.type === "NewExpression" &&
|
|
@@ -116,41 +594,78 @@ const connectionToDataSource = (file, api) => {
|
|
|
116
594
|
}
|
|
117
595
|
}
|
|
118
596
|
});
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
connectionTypeNames.has(ann.typeName.name)) {
|
|
128
|
-
connectionVarNames.add(id.name);
|
|
129
|
-
}
|
|
597
|
+
const collectDataSourceTyped = (id) => {
|
|
598
|
+
if (!id.name || id.typeAnnotation?.type !== "TSTypeAnnotation")
|
|
599
|
+
return;
|
|
600
|
+
const ann = id.typeAnnotation.typeAnnotation;
|
|
601
|
+
if (ann.type === "TSTypeReference" &&
|
|
602
|
+
ann.typeName.type === "Identifier" &&
|
|
603
|
+
connectionTypeNames.has(ann.typeName.name)) {
|
|
604
|
+
connectionVarNames.add(id.name);
|
|
130
605
|
}
|
|
606
|
+
};
|
|
607
|
+
root.find(j.VariableDeclarator).forEach((path) => {
|
|
608
|
+
if ((0, ast_helpers_1.isIdentifier)(path.node.id))
|
|
609
|
+
collectDataSourceTyped(path.node.id);
|
|
131
610
|
});
|
|
611
|
+
(0, ast_helpers_1.forEachIdentifierParam)(root, j, collectDataSourceTyped);
|
|
132
612
|
// Rename method calls: .connect() → .initialize(), .close() → .destroy()
|
|
133
|
-
// Only on
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
613
|
+
// Only on receivers known to be Connection/DataSource instances —
|
|
614
|
+
// covered after typed-var AND `this.<member>` collection below.
|
|
615
|
+
const renameDataSourceMethods = () => {
|
|
616
|
+
for (const [oldMethod, newMethod] of Object.entries(methodRenames)) {
|
|
617
|
+
root.find(j.CallExpression, {
|
|
618
|
+
callee: {
|
|
619
|
+
type: "MemberExpression",
|
|
620
|
+
property: { name: oldMethod },
|
|
621
|
+
},
|
|
622
|
+
}).forEach((path) => {
|
|
623
|
+
if (path.node.callee.type === "MemberExpression" &&
|
|
624
|
+
path.node.callee.property.type === "Identifier" &&
|
|
625
|
+
receiverIsIn(path.node.callee.object, connectionVarNames, thisConnectionMembers)) {
|
|
146
626
|
path.node.callee.property.name = newMethod;
|
|
147
627
|
hasChanges = true;
|
|
148
628
|
}
|
|
149
|
-
}
|
|
150
|
-
}
|
|
151
|
-
}
|
|
152
|
-
//
|
|
629
|
+
});
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
// Gate metadata type matches on the actual local bindings imported from
|
|
633
|
+
// typeorm — users sometimes have their own classes named `EntityMetadata`
|
|
634
|
+
// or `ColumnMetadata` and their `.connection` property access must not
|
|
635
|
+
// be rewritten.
|
|
636
|
+
const connectionPropLocalNames = (0, ast_helpers_1.expandLocalNamesForImports)(root, j, "typeorm", typesWithConnectionProp);
|
|
637
|
+
const indirectDataSourceLocalNames = (0, ast_helpers_1.expandLocalNamesForImports)(root, j, "typeorm", typesWithIndirectDataSource);
|
|
638
|
+
// Specifically the local names bound to typeorm's `EntityMetadata` —
|
|
639
|
+
// used to gate the constructor-option rewrite below. Alias-aware so
|
|
640
|
+
// `import { EntityMetadata as EM }` is still recognized.
|
|
641
|
+
const entityMetadataLocalNames = (0, ast_helpers_1.expandLocalNamesForImports)(root, j, "typeorm", new Set(["EntityMetadata"]));
|
|
153
642
|
const connectionPropVarNames = new Set();
|
|
643
|
+
const indirectDataSourceVarNames = new Set();
|
|
644
|
+
// Parallel sets for `this.X` member accesses — class properties and
|
|
645
|
+
// getters whose annotation is a tracked TypeORM type. Keyed by the
|
|
646
|
+
// member name (not prefixed) since the access shape (`this.X`) already
|
|
647
|
+
// signals the lookup side.
|
|
648
|
+
const thisConnectionMembers = new Set();
|
|
649
|
+
const thisConnectionPropMembers = new Set();
|
|
650
|
+
const thisIndirectMembers = new Set();
|
|
651
|
+
const classifyType = (typeName) => {
|
|
652
|
+
if (connectionTypeNames.has(typeName))
|
|
653
|
+
return connectionVarNames;
|
|
654
|
+
if (connectionPropLocalNames.has(typeName))
|
|
655
|
+
return connectionPropVarNames;
|
|
656
|
+
if (indirectDataSourceLocalNames.has(typeName))
|
|
657
|
+
return indirectDataSourceVarNames;
|
|
658
|
+
return null;
|
|
659
|
+
};
|
|
660
|
+
const classifyThisMemberType = (typeName) => {
|
|
661
|
+
if (connectionTypeNames.has(typeName))
|
|
662
|
+
return thisConnectionMembers;
|
|
663
|
+
if (connectionPropLocalNames.has(typeName))
|
|
664
|
+
return thisConnectionPropMembers;
|
|
665
|
+
if (indirectDataSourceLocalNames.has(typeName))
|
|
666
|
+
return thisIndirectMembers;
|
|
667
|
+
return null;
|
|
668
|
+
};
|
|
154
669
|
const collectTypedIdentifier = (id) => {
|
|
155
670
|
if (!id.name || !id.typeAnnotation)
|
|
156
671
|
return;
|
|
@@ -160,43 +675,293 @@ const connectionToDataSource = (file, api) => {
|
|
|
160
675
|
if (ann.typeAnnotation.type !== "TSTypeReference")
|
|
161
676
|
return;
|
|
162
677
|
const ref = ann.typeAnnotation;
|
|
163
|
-
if (ref.typeName.type
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
678
|
+
if (ref.typeName.type !== "Identifier")
|
|
679
|
+
return;
|
|
680
|
+
const bucket = classifyType(ref.typeName.name);
|
|
681
|
+
if (bucket)
|
|
682
|
+
bucket.add(id.name);
|
|
167
683
|
};
|
|
168
|
-
// Variable declarations with type annotations
|
|
169
684
|
root.find(j.VariableDeclarator).forEach((path) => {
|
|
170
685
|
if ((0, ast_helpers_1.isIdentifier)(path.node.id))
|
|
171
686
|
collectTypedIdentifier(path.node.id);
|
|
172
687
|
});
|
|
173
|
-
// Function/method/arrow parameters and constructor parameter properties
|
|
174
688
|
(0, ast_helpers_1.forEachIdentifierParam)(root, j, collectTypedIdentifier);
|
|
689
|
+
// Class properties with a TypeORM type annotation — e.g.
|
|
690
|
+
// private readonly tenantConnection: DataSource
|
|
691
|
+
// — register `this.tenantConnection` for rename-side lookup.
|
|
692
|
+
root.find(j.ClassProperty).forEach((path) => {
|
|
693
|
+
const keyNode = path.node.key;
|
|
694
|
+
if (keyNode.type !== "Identifier")
|
|
695
|
+
return;
|
|
696
|
+
const ann = path.node.typeAnnotation;
|
|
697
|
+
if (ann?.type !== "TSTypeAnnotation")
|
|
698
|
+
return;
|
|
699
|
+
const inner = ann.typeAnnotation;
|
|
700
|
+
if (inner.type !== "TSTypeReference")
|
|
701
|
+
return;
|
|
702
|
+
const typeName = inner.typeName;
|
|
703
|
+
if (typeName.type !== "Identifier")
|
|
704
|
+
return;
|
|
705
|
+
const bucket = classifyThisMemberType(typeName.name);
|
|
706
|
+
if (bucket)
|
|
707
|
+
bucket.add(keyNode.name);
|
|
708
|
+
});
|
|
709
|
+
// Constructor parameter properties — `constructor(private readonly x: DataSource)`
|
|
710
|
+
// is a TSParameterProperty whose inner `parameter` is the typed Identifier.
|
|
711
|
+
// These become class fields accessed via `this.x`.
|
|
712
|
+
root.find(j.TSParameterProperty).forEach((path) => {
|
|
713
|
+
const inner = path.node.parameter;
|
|
714
|
+
if (!inner)
|
|
715
|
+
return;
|
|
716
|
+
const id = resolveTSParameterPropertyIdentifier(inner);
|
|
717
|
+
if (!id)
|
|
718
|
+
return;
|
|
719
|
+
const ann = id.typeAnnotation;
|
|
720
|
+
if (ann?.type !== "TSTypeAnnotation")
|
|
721
|
+
return;
|
|
722
|
+
if (ann.typeAnnotation.type !== "TSTypeReference")
|
|
723
|
+
return;
|
|
724
|
+
const ref = ann.typeAnnotation;
|
|
725
|
+
if (ref.typeName.type !== "Identifier")
|
|
726
|
+
return;
|
|
727
|
+
const bucket = classifyThisMemberType(ref.typeName.name);
|
|
728
|
+
if (bucket)
|
|
729
|
+
bucket.add(id.name);
|
|
730
|
+
});
|
|
731
|
+
// Class getters with a return type annotation — e.g.
|
|
732
|
+
// private get entityManager(): EntityManager { ... }
|
|
733
|
+
// — same `this.X` lookup path.
|
|
734
|
+
root.find(j.ClassMethod).forEach((path) => {
|
|
735
|
+
if (path.node.kind !== "get")
|
|
736
|
+
return;
|
|
737
|
+
const keyNode = path.node.key;
|
|
738
|
+
if (keyNode.type !== "Identifier")
|
|
739
|
+
return;
|
|
740
|
+
const rt = path.node.returnType;
|
|
741
|
+
if (rt?.type !== "TSTypeAnnotation")
|
|
742
|
+
return;
|
|
743
|
+
const inner = rt.typeAnnotation;
|
|
744
|
+
if (inner.type !== "TSTypeReference")
|
|
745
|
+
return;
|
|
746
|
+
const typeName = inner.typeName;
|
|
747
|
+
if (typeName.type !== "Identifier")
|
|
748
|
+
return;
|
|
749
|
+
const bucket = classifyThisMemberType(typeName.name);
|
|
750
|
+
if (bucket)
|
|
751
|
+
bucket.add(keyNode.name);
|
|
752
|
+
});
|
|
753
|
+
// Resolves an object-access receiver to the set of known-type names it
|
|
754
|
+
// resolves against. Returns null for receivers we can't classify.
|
|
755
|
+
// x → { key: "x", isThisMember: false }
|
|
756
|
+
// this.x → { key: "x", isThisMember: true }
|
|
757
|
+
// (x as T) → same as x
|
|
758
|
+
// (this.x as T) → same as this.x
|
|
759
|
+
const resolveReceiver = (node) => {
|
|
760
|
+
const direct = unwrapIdentifierName(node);
|
|
761
|
+
if (direct)
|
|
762
|
+
return { key: direct, isThisMember: false };
|
|
763
|
+
const unwrapped = (0, ast_helpers_1.unwrapTsExpression)(node);
|
|
764
|
+
if ((unwrapped.type === "MemberExpression" ||
|
|
765
|
+
unwrapped.type === "OptionalMemberExpression") &&
|
|
766
|
+
unwrapped.object.type ===
|
|
767
|
+
"ThisExpression" &&
|
|
768
|
+
unwrapped.property.type === "Identifier") {
|
|
769
|
+
const prop = unwrapped.property;
|
|
770
|
+
return { key: prop.name, isThisMember: true };
|
|
771
|
+
}
|
|
772
|
+
return null;
|
|
773
|
+
};
|
|
774
|
+
const receiverIsIn = (node, bare, thisMember) => {
|
|
775
|
+
const r = resolveReceiver(node);
|
|
776
|
+
if (!r)
|
|
777
|
+
return false;
|
|
778
|
+
return r.isThisMember ? thisMember.has(r.key) : bare.has(r.key);
|
|
779
|
+
};
|
|
780
|
+
// Track variables assigned from DataSource accessors, so code like
|
|
781
|
+
// const manager = dataSource.manager
|
|
782
|
+
// manager.connection.getMetadata(...)
|
|
783
|
+
// gets rewritten without requiring an explicit `: EntityManager`
|
|
784
|
+
// annotation.
|
|
785
|
+
const dataSourceMemberAccessors = {
|
|
786
|
+
manager: "EntityManager",
|
|
787
|
+
mongoManager: "EntityManager",
|
|
788
|
+
};
|
|
789
|
+
const dataSourceCallAccessors = {
|
|
790
|
+
getRepository: "Repository",
|
|
791
|
+
getTreeRepository: "TreeRepository",
|
|
792
|
+
getMongoRepository: "MongoRepository",
|
|
793
|
+
createQueryRunner: "QueryRunner",
|
|
794
|
+
createQueryBuilder: "SelectQueryBuilder",
|
|
795
|
+
};
|
|
796
|
+
// Returns the TypeORM type that a DataSource accessor chain resolves to
|
|
797
|
+
// (`ds.manager` → "EntityManager", `ds.getRepository(X)` → "Repository"),
|
|
798
|
+
// or null when the initializer isn't a recognized accessor-chain pattern.
|
|
799
|
+
const resolveAccessorChainType = (init) => {
|
|
800
|
+
if (init.type === "MemberExpression") {
|
|
801
|
+
const baseName = unwrapIdentifierName(init.object);
|
|
802
|
+
if (!baseName ||
|
|
803
|
+
!connectionVarNames.has(baseName) ||
|
|
804
|
+
init.property.type !== "Identifier") {
|
|
805
|
+
return null;
|
|
806
|
+
}
|
|
807
|
+
return dataSourceMemberAccessors[init.property.name] ?? null;
|
|
808
|
+
}
|
|
809
|
+
if (init.type === "CallExpression" &&
|
|
810
|
+
init.callee.type === "MemberExpression" &&
|
|
811
|
+
init.callee.property.type === "Identifier") {
|
|
812
|
+
const baseName = unwrapIdentifierName(init.callee.object);
|
|
813
|
+
if (!baseName || !connectionVarNames.has(baseName))
|
|
814
|
+
return null;
|
|
815
|
+
return dataSourceCallAccessors[init.callee.property.name] ?? null;
|
|
816
|
+
}
|
|
817
|
+
return null;
|
|
818
|
+
};
|
|
819
|
+
root.find(j.VariableDeclarator).forEach((path) => {
|
|
820
|
+
if (path.node.id.type !== "Identifier")
|
|
821
|
+
return;
|
|
822
|
+
if (!path.node.init)
|
|
823
|
+
return;
|
|
824
|
+
const typeName = resolveAccessorChainType(path.node.init);
|
|
825
|
+
if (typeName && typesWithConnectionProp.has(typeName)) {
|
|
826
|
+
connectionPropVarNames.add(path.node.id.name);
|
|
827
|
+
}
|
|
828
|
+
});
|
|
829
|
+
renameDataSourceMethods();
|
|
175
830
|
// Rename .isConnected → .isInitialized on Connection/DataSource instances
|
|
176
831
|
root.find(j.MemberExpression, {
|
|
177
832
|
property: { name: "isConnected" },
|
|
178
833
|
}).forEach((path) => {
|
|
179
|
-
if (path.node.property.type
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
}
|
|
834
|
+
if (path.node.property.type !== "Identifier")
|
|
835
|
+
return;
|
|
836
|
+
if (receiverIsIn(path.node.object, connectionVarNames, thisConnectionMembers)) {
|
|
837
|
+
path.node.property.name = "isInitialized";
|
|
838
|
+
hasChanges = true;
|
|
185
839
|
}
|
|
186
840
|
});
|
|
187
|
-
// Rename .connection → .dataSource on known TypeORM instances
|
|
841
|
+
// Rename .connection → .dataSource on known TypeORM instances.
|
|
842
|
+
// For types without a direct `.dataSource` field (ColumnMetadata /
|
|
843
|
+
// IndexMetadata) the rename goes through `.entityMetadata.dataSource`.
|
|
188
844
|
root.find(j.MemberExpression, {
|
|
189
845
|
property: { name: "connection" },
|
|
190
846
|
}).forEach((path) => {
|
|
191
|
-
if (path.node.property.type
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
847
|
+
if (path.node.property.type !== "Identifier")
|
|
848
|
+
return;
|
|
849
|
+
if (receiverIsIn(path.node.object, connectionPropVarNames, thisConnectionPropMembers)) {
|
|
850
|
+
path.node.property.name = "dataSource";
|
|
851
|
+
hasChanges = true;
|
|
852
|
+
return;
|
|
853
|
+
}
|
|
854
|
+
if (receiverIsIn(path.node.object, indirectDataSourceVarNames, thisIndirectMembers)) {
|
|
855
|
+
// `col.connection` → `col.entityMetadata.dataSource`
|
|
856
|
+
path.node.object = j.memberExpression(path.node.object, j.identifier("entityMetadata"));
|
|
857
|
+
path.node.property.name = "dataSource";
|
|
858
|
+
hasChanges = true;
|
|
859
|
+
}
|
|
860
|
+
});
|
|
861
|
+
// Destructuring pattern: `const { connection } = event` / `for (const
|
|
862
|
+
// { connection } of events)` where `event`/`events[i]` is a tracked
|
|
863
|
+
// connectionProp receiver (subscriber event, EntityManager, QueryRunner,
|
|
864
|
+
// Repository, etc.). Rename the `connection` key to `dataSource` and
|
|
865
|
+
// preserve the local binding name.
|
|
866
|
+
const renameConnectionInObjectPattern = (id) => {
|
|
867
|
+
if (id.type !== "ObjectPattern")
|
|
868
|
+
return;
|
|
869
|
+
for (const prop of id.properties) {
|
|
870
|
+
if (prop.type !== "Property" && prop.type !== "ObjectProperty")
|
|
871
|
+
continue;
|
|
872
|
+
const typed = prop;
|
|
873
|
+
if (typed.key.type !== "Identifier")
|
|
874
|
+
continue;
|
|
875
|
+
if (typed.key.name !== "connection")
|
|
876
|
+
continue;
|
|
877
|
+
typed.key.name = "dataSource";
|
|
878
|
+
// Shorthand `{ connection }` expands to `{ dataSource: connection }`
|
|
879
|
+
// to keep the local variable name unchanged — the consumer code
|
|
880
|
+
// still references `connection`.
|
|
881
|
+
if (typed.shorthand)
|
|
882
|
+
typed.shorthand = false;
|
|
883
|
+
hasChanges = true;
|
|
198
884
|
}
|
|
885
|
+
};
|
|
886
|
+
root.find(j.VariableDeclarator).forEach((declPath) => {
|
|
887
|
+
const init = declPath.node.init;
|
|
888
|
+
if (!init)
|
|
889
|
+
return;
|
|
890
|
+
if (!receiverIsIn(init, connectionPropVarNames, thisConnectionPropMembers)) {
|
|
891
|
+
return;
|
|
892
|
+
}
|
|
893
|
+
renameConnectionInObjectPattern(declPath.node.id);
|
|
199
894
|
});
|
|
895
|
+
// `for (const { connection } of events)` — `ForOfStatement.left` is a
|
|
896
|
+
// `VariableDeclaration` whose declarators have no `init`, so the
|
|
897
|
+
// plain VariableDeclarator loop above skips them. Classify the loop
|
|
898
|
+
// variable's inferred type: either the iterable variable itself is a
|
|
899
|
+
// tracked receiver, or its declared annotation is `Tracked[]` /
|
|
900
|
+
// `Array<Tracked>`.
|
|
901
|
+
const elementTypeOf = (rhsNode) => {
|
|
902
|
+
if (rhsNode.type !== "Identifier")
|
|
903
|
+
return null;
|
|
904
|
+
const name = rhsNode.name;
|
|
905
|
+
let resolved = null;
|
|
906
|
+
root.find(j.VariableDeclarator).forEach((p) => {
|
|
907
|
+
if (resolved)
|
|
908
|
+
return;
|
|
909
|
+
if (p.node.id.type !== "Identifier")
|
|
910
|
+
return;
|
|
911
|
+
if (p.node.id.name !== name)
|
|
912
|
+
return;
|
|
913
|
+
const ann = p.node.id.typeAnnotation;
|
|
914
|
+
if (ann?.type !== "TSTypeAnnotation")
|
|
915
|
+
return;
|
|
916
|
+
const inner = ann.typeAnnotation;
|
|
917
|
+
if (inner.type === "TSArrayType") {
|
|
918
|
+
resolved =
|
|
919
|
+
(0, ast_helpers_1.getTypeReferenceRootName)(inner.elementType, typeormNamespaceNames) ?? null;
|
|
920
|
+
return;
|
|
921
|
+
}
|
|
922
|
+
if (inner.type === "TSTypeReference" &&
|
|
923
|
+
inner.typeName?.name ===
|
|
924
|
+
"Array") {
|
|
925
|
+
const params = inner.typeParameters?.params;
|
|
926
|
+
if (params && params.length > 0) {
|
|
927
|
+
resolved =
|
|
928
|
+
(0, ast_helpers_1.getTypeReferenceRootName)(params[0], typeormNamespaceNames) ?? null;
|
|
929
|
+
}
|
|
930
|
+
}
|
|
931
|
+
});
|
|
932
|
+
return resolved;
|
|
933
|
+
};
|
|
934
|
+
const visitForOf = (leftNode, rightNode) => {
|
|
935
|
+
if (!leftNode || !rightNode)
|
|
936
|
+
return;
|
|
937
|
+
if (leftNode.type !== "VariableDeclaration")
|
|
938
|
+
return;
|
|
939
|
+
// Either: the iterable itself is a tracked receiver (rare but valid
|
|
940
|
+
// — e.g. a generator that yields the receiver), OR its type is an
|
|
941
|
+
// array/`Array<T>` of a tracked type.
|
|
942
|
+
const directlyTracked = receiverIsIn(rightNode, connectionPropVarNames, thisConnectionPropMembers);
|
|
943
|
+
const elementType = elementTypeOf(rightNode);
|
|
944
|
+
const elementTracked = elementType !== null && connectionPropLocalNames.has(elementType);
|
|
945
|
+
if (!directlyTracked && !elementTracked)
|
|
946
|
+
return;
|
|
947
|
+
for (const d of leftNode
|
|
948
|
+
.declarations) {
|
|
949
|
+
if (d.type !== "VariableDeclarator")
|
|
950
|
+
continue;
|
|
951
|
+
renameConnectionInObjectPattern(d.id);
|
|
952
|
+
}
|
|
953
|
+
};
|
|
954
|
+
root.find(j.ForOfStatement).forEach((p) => visitForOf(p.node.left, p.node.right));
|
|
955
|
+
root.find(j.ForInStatement).forEach((p) => visitForOf(p.node.left, p.node.right));
|
|
956
|
+
// Rewrite the `connection` option passed to metadata-type constructors:
|
|
957
|
+
// - `new EntityMetadata({ connection: X, ... })` → rename key to
|
|
958
|
+
// `dataSource` (the option was just renamed in v1).
|
|
959
|
+
// - `new ColumnMetadata({ connection, ... })` / `IndexMetadata` →
|
|
960
|
+
// drop the `connection` key entirely. These constructors no longer
|
|
961
|
+
// accept `connection` in v1; the DataSource is reached through
|
|
962
|
+
// `entityMetadata.dataSource` and is set by the entity-metadata
|
|
963
|
+
// builder rather than the caller.
|
|
964
|
+
hasChanges = rewriteMetadataConstructors(root, j, entityMetadataLocalNames, indirectDataSourceLocalNames, hasChanges);
|
|
200
965
|
return hasChanges ? root.toSource() : undefined;
|
|
201
966
|
};
|
|
202
967
|
exports.connectionToDataSource = connectionToDataSource;
|