@angular/core 20.0.0-next.1 → 20.0.0-next.3
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/fesm2022/core.mjs +770 -2144
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/di.mjs +3 -2
- package/fesm2022/primitives/di.mjs.map +1 -1
- package/fesm2022/primitives/event-dispatch.mjs +2 -589
- package/fesm2022/primitives/event-dispatch.mjs.map +1 -1
- package/fesm2022/primitives/signals.mjs +44 -13
- package/fesm2022/primitives/signals.mjs.map +1 -1
- package/fesm2022/rxjs-interop.mjs +7 -39
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +116 -143
- package/fesm2022/testing.mjs.map +1 -1
- package/fesm2022/weak_ref-DrMdAIDh.mjs +12 -0
- package/fesm2022/weak_ref-DrMdAIDh.mjs.map +1 -0
- package/index.d.ts +14366 -15214
- package/navigation_types.d-u4EOrrdZ.d.ts +121 -0
- package/package.json +2 -2
- package/primitives/di/index.d.ts +66 -59
- package/primitives/event-dispatch/index.d.ts +205 -309
- package/primitives/signals/index.d.ts +161 -195
- package/rxjs-interop/index.d.ts +71 -100
- package/schematics/bundles/{apply_import_manager-e2a7fe5b.js → apply_import_manager-BXQEjo09.js} +15 -19
- package/schematics/bundles/{checker-af521da6.js → checker-BHb19MHt.js} +3695 -1175
- package/schematics/bundles/cleanup-unused-imports.js +56 -89
- package/schematics/bundles/{compiler_host-5a29293c.js → compiler_host-Bk3repE2.js} +19 -23
- package/schematics/bundles/control-flow-migration.js +81 -38
- package/schematics/bundles/{imports-047fbbc8.js → imports-CIX-JgAN.js} +9 -14
- package/schematics/bundles/{index-1bef3025.js → index-BL9kAIe5.js} +62 -66
- package/schematics/bundles/{program-a449f9bf.js → index-I8VbxQcO.js} +1508 -3178
- package/schematics/bundles/inject-flags.js +147 -0
- package/schematics/bundles/inject-migration.js +121 -127
- package/schematics/bundles/{leading_space-f8944434.js → leading_space-D9nQ8UQC.js} +1 -1
- package/schematics/bundles/{migrate_ts_type_references-2a3e9e6b.js → migrate_ts_type_references-KlOTWeDl.js} +121 -126
- package/schematics/bundles/{ng_decorators-b0d8b324.js → ng_decorators-DznZ5jMl.js} +4 -8
- package/schematics/bundles/{nodes-7758dbf6.js → nodes-B16H9JUd.js} +2 -6
- package/schematics/bundles/output-migration.js +94 -128
- package/schematics/bundles/{project_tsconfig_paths-b558633b.js → project_tsconfig_paths-CDVxT6Ov.js} +1 -1
- package/schematics/bundles/{property_name-ac18447e.js → property_name-BBwFuqMe.js} +3 -7
- package/schematics/bundles/route-lazy-loading.js +35 -41
- package/schematics/bundles/{project_paths-17dc204d.js → run_in_devkit-C0JPtK2u.js} +283 -216
- package/schematics/bundles/self-closing-tags-migration.js +55 -91
- package/schematics/bundles/signal-input-migration.js +121 -156
- package/schematics/bundles/signal-queries-migration.js +119 -154
- package/schematics/bundles/signals.js +12 -14
- package/schematics/bundles/standalone-migration.js +180 -200
- package/schematics/bundles/symbol-VPWguRxr.js +25 -0
- package/schematics/bundles/test-bed-get.js +98 -0
- package/schematics/migrations.json +8 -14
- package/testing/index.d.ts +289 -471
- package/weak_ref.d-ttyj86RV.d.ts +9 -0
- package/schematics/bundles/explicit-standalone-flag.js +0 -184
- package/schematics/bundles/index-ef1bffbb.js +0 -30
- package/schematics/bundles/pending-tasks.js +0 -103
- package/schematics/bundles/provide-initializer.js +0 -186
|
@@ -1,50 +1,30 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
/**
|
|
3
|
-
* @license Angular v20.0.0-next.
|
|
3
|
+
* @license Angular v20.0.0-next.3
|
|
4
4
|
* (c) 2010-2025 Google LLC. https://angular.io/
|
|
5
5
|
* License: MIT
|
|
6
6
|
*/
|
|
7
7
|
'use strict';
|
|
8
8
|
|
|
9
|
-
Object.defineProperty(exports, '__esModule', { value: true });
|
|
10
|
-
|
|
11
9
|
var schematics = require('@angular-devkit/schematics');
|
|
12
|
-
require('./index-
|
|
10
|
+
var index = require('./index-I8VbxQcO.js');
|
|
13
11
|
var fs = require('fs');
|
|
14
12
|
var p = require('path');
|
|
15
13
|
var ts = require('typescript');
|
|
16
|
-
var compiler_host = require('./compiler_host-
|
|
17
|
-
var project_tsconfig_paths = require('./project_tsconfig_paths-
|
|
18
|
-
var ng_decorators = require('./ng_decorators-
|
|
19
|
-
var nodes = require('./nodes-
|
|
20
|
-
var
|
|
21
|
-
var
|
|
14
|
+
var compiler_host = require('./compiler_host-Bk3repE2.js');
|
|
15
|
+
var project_tsconfig_paths = require('./project_tsconfig_paths-CDVxT6Ov.js');
|
|
16
|
+
var ng_decorators = require('./ng_decorators-DznZ5jMl.js');
|
|
17
|
+
var nodes = require('./nodes-B16H9JUd.js');
|
|
18
|
+
var symbol = require('./symbol-VPWguRxr.js');
|
|
19
|
+
var imports = require('./imports-CIX-JgAN.js');
|
|
20
|
+
var checker = require('./checker-BHb19MHt.js');
|
|
22
21
|
require('os');
|
|
23
|
-
var program = require('./program-a449f9bf.js');
|
|
24
22
|
require('@angular-devkit/core');
|
|
25
23
|
require('module');
|
|
26
24
|
require('url');
|
|
27
25
|
|
|
28
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
29
|
-
|
|
30
|
-
var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts);
|
|
31
|
-
|
|
32
26
|
function createProgram({ rootNames, options, host, oldProgram, }) {
|
|
33
|
-
return new
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
/** Checks whether a node is referring to a specific import specifier. */
|
|
37
|
-
function isReferenceToImport(typeChecker, node, importSpecifier) {
|
|
38
|
-
// If this function is called on an identifier (should be most cases), we can quickly rule out
|
|
39
|
-
// non-matches by comparing the identifier's string and the local name of the import specifier
|
|
40
|
-
// which saves us some calls to the type checker.
|
|
41
|
-
if (ts__default["default"].isIdentifier(node) && node.text !== importSpecifier.name.text) {
|
|
42
|
-
return false;
|
|
43
|
-
}
|
|
44
|
-
const nodeSymbol = typeChecker.getTypeAtLocation(node).getSymbol();
|
|
45
|
-
const importSymbol = typeChecker.getTypeAtLocation(importSpecifier).getSymbol();
|
|
46
|
-
return (!!(nodeSymbol?.declarations?.[0] && importSymbol?.declarations?.[0]) &&
|
|
47
|
-
nodeSymbol.declarations[0] === importSymbol.declarations[0]);
|
|
27
|
+
return new index.NgtscProgram(rootNames, options, host, oldProgram);
|
|
48
28
|
}
|
|
49
29
|
|
|
50
30
|
/*!
|
|
@@ -114,7 +94,7 @@ class ReferenceResolver {
|
|
|
114
94
|
const results = new Map();
|
|
115
95
|
for (const symbol of referencedSymbols) {
|
|
116
96
|
for (const ref of symbol.references) {
|
|
117
|
-
if (!ref.isDefinition || symbol.definition.kind ===
|
|
97
|
+
if (!ref.isDefinition || symbol.definition.kind === ts.ScriptElementKind.alias) {
|
|
118
98
|
if (!results.has(ref.fileName)) {
|
|
119
99
|
results.set(ref.fileName, []);
|
|
120
100
|
}
|
|
@@ -152,7 +132,7 @@ class ReferenceResolver {
|
|
|
152
132
|
// the only one being passed in `getDocumentHighlight`, but we check here just in case.
|
|
153
133
|
if (file.fileName === fileName) {
|
|
154
134
|
for (const { textSpan: { start, length }, kind, } of file.highlightSpans) {
|
|
155
|
-
if (kind !==
|
|
135
|
+
if (kind !== ts.HighlightSpanKind.none) {
|
|
156
136
|
results.push([start, start + length]);
|
|
157
137
|
}
|
|
158
138
|
}
|
|
@@ -183,20 +163,20 @@ class ReferenceResolver {
|
|
|
183
163
|
rootFileNames.push(fileName);
|
|
184
164
|
}
|
|
185
165
|
});
|
|
186
|
-
this._languageService =
|
|
166
|
+
this._languageService = ts.createLanguageService({
|
|
187
167
|
getCompilationSettings: () => this._program.getTsProgram().getCompilerOptions(),
|
|
188
168
|
getScriptFileNames: () => rootFileNames,
|
|
189
169
|
// The files won't change so we can return the same version.
|
|
190
170
|
getScriptVersion: () => '0',
|
|
191
171
|
getScriptSnapshot: (path) => {
|
|
192
172
|
const content = this._readFile(path);
|
|
193
|
-
return content ?
|
|
173
|
+
return content ? ts.ScriptSnapshot.fromString(content) : undefined;
|
|
194
174
|
},
|
|
195
175
|
getCurrentDirectory: () => this._basePath,
|
|
196
|
-
getDefaultLibFileName: (options) =>
|
|
176
|
+
getDefaultLibFileName: (options) => ts.getDefaultLibFilePath(options),
|
|
197
177
|
readFile: (path) => this._readFile(path),
|
|
198
178
|
fileExists: (path) => this._host.fileExists(path),
|
|
199
|
-
},
|
|
179
|
+
}, ts.createDocumentRegistry(), ts.LanguageServiceMode.PartialSemantic);
|
|
200
180
|
}
|
|
201
181
|
return this._languageService;
|
|
202
182
|
}
|
|
@@ -240,11 +220,11 @@ function findClassDeclaration(reference, typeChecker) {
|
|
|
240
220
|
return (typeChecker
|
|
241
221
|
.getTypeAtLocation(reference)
|
|
242
222
|
.getSymbol()
|
|
243
|
-
?.declarations?.find(
|
|
223
|
+
?.declarations?.find(ts.isClassDeclaration) || null);
|
|
244
224
|
}
|
|
245
225
|
/** Finds a property with a specific name in an object literal expression. */
|
|
246
226
|
function findLiteralProperty(literal, name) {
|
|
247
|
-
return literal.properties.find((prop) => prop.name &&
|
|
227
|
+
return literal.properties.find((prop) => prop.name && ts.isIdentifier(prop.name) && prop.name.text === name);
|
|
248
228
|
}
|
|
249
229
|
/** Gets a relative path between two files that can be used inside a TypeScript import. */
|
|
250
230
|
function getRelativeImportPath(fromFile, toFile) {
|
|
@@ -282,12 +262,12 @@ function isClassReferenceInAngularModule(node, className, moduleName, typeChecke
|
|
|
282
262
|
const externalName = `@angular/${moduleName}`;
|
|
283
263
|
const internalName = `angular2/rc/packages/${moduleName}`;
|
|
284
264
|
return !!symbol?.declarations?.some((decl) => {
|
|
285
|
-
const closestClass = closestOrSelf(decl,
|
|
265
|
+
const closestClass = closestOrSelf(decl, ts.isClassDeclaration);
|
|
286
266
|
const closestClassFileName = closestClass?.getSourceFile().fileName;
|
|
287
267
|
if (!closestClass ||
|
|
288
268
|
!closestClassFileName ||
|
|
289
269
|
!closestClass.name ||
|
|
290
|
-
!
|
|
270
|
+
!ts.isIdentifier(closestClass.name) ||
|
|
291
271
|
(!closestClassFileName.includes(externalName) && !closestClassFileName.includes(internalName))) {
|
|
292
272
|
return false;
|
|
293
273
|
}
|
|
@@ -313,19 +293,19 @@ function getTestingImports(sourceFile) {
|
|
|
313
293
|
* @param catalystImport Import of Catalyst within the file.
|
|
314
294
|
*/
|
|
315
295
|
function isTestCall(typeChecker, node, testBedImport, catalystImport) {
|
|
316
|
-
const isObjectLiteralCall =
|
|
296
|
+
const isObjectLiteralCall = ts.isCallExpression(node) &&
|
|
317
297
|
node.arguments.length > 0 &&
|
|
318
298
|
// `arguments[0]` is the testing module config.
|
|
319
|
-
|
|
299
|
+
ts.isObjectLiteralExpression(node.arguments[0]);
|
|
320
300
|
const isTestBedCall = isObjectLiteralCall &&
|
|
321
301
|
testBedImport &&
|
|
322
|
-
|
|
302
|
+
ts.isPropertyAccessExpression(node.expression) &&
|
|
323
303
|
node.expression.name.text === 'configureTestingModule' &&
|
|
324
|
-
isReferenceToImport(typeChecker, node.expression.expression, testBedImport);
|
|
304
|
+
symbol.isReferenceToImport(typeChecker, node.expression.expression, testBedImport);
|
|
325
305
|
const isCatalystCall = isObjectLiteralCall &&
|
|
326
306
|
catalystImport &&
|
|
327
|
-
|
|
328
|
-
isReferenceToImport(typeChecker, node.expression, catalystImport);
|
|
307
|
+
ts.isIdentifier(node.expression) &&
|
|
308
|
+
symbol.isReferenceToImport(typeChecker, node.expression, catalystImport);
|
|
329
309
|
return !!(isTestBedCall || isCatalystCall);
|
|
330
310
|
}
|
|
331
311
|
|
|
@@ -391,9 +371,9 @@ function convertNgModuleDeclarationToStandalone(decl, allDeclarations, tracker,
|
|
|
391
371
|
if (importsToAdd.length > 0) {
|
|
392
372
|
const hasTrailingComma = importsToAdd.length > 2 &&
|
|
393
373
|
!!extractMetadataLiteral(directiveMeta.decorator)?.properties.hasTrailingComma;
|
|
394
|
-
decorator = setPropertyOnAngularDecorator(decorator, 'imports',
|
|
374
|
+
decorator = setPropertyOnAngularDecorator(decorator, 'imports', ts.factory.createArrayLiteralExpression(
|
|
395
375
|
// Create a multi-line array when it has a trailing comma.
|
|
396
|
-
|
|
376
|
+
ts.factory.createNodeArray(importsToAdd, hasTrailingComma), hasTrailingComma));
|
|
397
377
|
}
|
|
398
378
|
}
|
|
399
379
|
tracker.replaceNode(directiveMeta.decorator, decorator);
|
|
@@ -446,13 +426,13 @@ function potentialImportsToExpressions(potentialImports, toFile, tracker, import
|
|
|
446
426
|
if (importLocation.moduleSpecifier) {
|
|
447
427
|
return tracker.addImport(toFile, importLocation.symbolName, importLocation.moduleSpecifier);
|
|
448
428
|
}
|
|
449
|
-
const identifier =
|
|
429
|
+
const identifier = ts.factory.createIdentifier(importLocation.symbolName);
|
|
450
430
|
if (!importLocation.isForwardReference) {
|
|
451
431
|
return identifier;
|
|
452
432
|
}
|
|
453
433
|
const forwardRefExpression = tracker.addImport(toFile, 'forwardRef', '@angular/core');
|
|
454
|
-
const arrowFunction =
|
|
455
|
-
return
|
|
434
|
+
const arrowFunction = ts.factory.createArrowFunction(undefined, undefined, [], undefined, undefined, identifier);
|
|
435
|
+
return ts.factory.createCallExpression(forwardRefExpression, undefined, [arrowFunction]);
|
|
456
436
|
});
|
|
457
437
|
}
|
|
458
438
|
/**
|
|
@@ -487,16 +467,16 @@ function moveDeclarationsToImports(literal, allDeclarations, typeChecker, templa
|
|
|
487
467
|
const declarationsToCopy = [];
|
|
488
468
|
const properties = [];
|
|
489
469
|
const importsProp = findLiteralProperty(literal, 'imports');
|
|
490
|
-
const hasAnyArrayTrailingComma = literal.properties.some((prop) =>
|
|
491
|
-
|
|
470
|
+
const hasAnyArrayTrailingComma = literal.properties.some((prop) => ts.isPropertyAssignment(prop) &&
|
|
471
|
+
ts.isArrayLiteralExpression(prop.initializer) &&
|
|
492
472
|
prop.initializer.elements.hasTrailingComma);
|
|
493
473
|
// Separate the declarations that we want to keep and ones we need to copy into the `imports`.
|
|
494
|
-
if (
|
|
474
|
+
if (ts.isPropertyAssignment(declarationsProp)) {
|
|
495
475
|
// If the declarations are an array, we can analyze it to
|
|
496
476
|
// find any classes from the current migration.
|
|
497
|
-
if (
|
|
477
|
+
if (ts.isArrayLiteralExpression(declarationsProp.initializer)) {
|
|
498
478
|
for (const el of declarationsProp.initializer.elements) {
|
|
499
|
-
if (
|
|
479
|
+
if (ts.isIdentifier(el)) {
|
|
500
480
|
const correspondingClass = findClassDeclaration(el, typeChecker);
|
|
501
481
|
if (!correspondingClass ||
|
|
502
482
|
// Check whether the declaration is either standalone already or is being converted
|
|
@@ -517,12 +497,12 @@ function moveDeclarationsToImports(literal, allDeclarations, typeChecker, templa
|
|
|
517
497
|
}
|
|
518
498
|
else {
|
|
519
499
|
// Otherwise create a spread that will be copied into the `imports`.
|
|
520
|
-
declarationsToCopy.push(
|
|
500
|
+
declarationsToCopy.push(ts.factory.createSpreadElement(declarationsProp.initializer));
|
|
521
501
|
}
|
|
522
502
|
}
|
|
523
503
|
// If there are no `imports`, create them with the declarations we want to copy.
|
|
524
504
|
if (!importsProp && declarationsToCopy.length > 0) {
|
|
525
|
-
properties.push(
|
|
505
|
+
properties.push(ts.factory.createPropertyAssignment('imports', ts.factory.createArrayLiteralExpression(ts.factory.createNodeArray(declarationsToCopy, hasAnyArrayTrailingComma && declarationsToCopy.length > 2))));
|
|
526
506
|
}
|
|
527
507
|
for (const prop of literal.properties) {
|
|
528
508
|
if (!isNamedPropertyAssignment(prop)) {
|
|
@@ -532,10 +512,10 @@ function moveDeclarationsToImports(literal, allDeclarations, typeChecker, templa
|
|
|
532
512
|
// If we have declarations to preserve, update the existing property, otherwise drop it.
|
|
533
513
|
if (prop === declarationsProp) {
|
|
534
514
|
if (declarationsToPreserve.length > 0) {
|
|
535
|
-
const hasTrailingComma =
|
|
515
|
+
const hasTrailingComma = ts.isArrayLiteralExpression(prop.initializer)
|
|
536
516
|
? prop.initializer.elements.hasTrailingComma
|
|
537
517
|
: hasAnyArrayTrailingComma;
|
|
538
|
-
properties.push(
|
|
518
|
+
properties.push(ts.factory.updatePropertyAssignment(prop, prop.name, ts.factory.createArrayLiteralExpression(ts.factory.createNodeArray(declarationsToPreserve, hasTrailingComma && declarationsToPreserve.length > 2))));
|
|
539
519
|
}
|
|
540
520
|
continue;
|
|
541
521
|
}
|
|
@@ -543,27 +523,27 @@ function moveDeclarationsToImports(literal, allDeclarations, typeChecker, templa
|
|
|
543
523
|
// that should be copied, we merge the two arrays.
|
|
544
524
|
if (prop === importsProp && declarationsToCopy.length > 0) {
|
|
545
525
|
let initializer;
|
|
546
|
-
if (
|
|
547
|
-
initializer =
|
|
526
|
+
if (ts.isArrayLiteralExpression(prop.initializer)) {
|
|
527
|
+
initializer = ts.factory.updateArrayLiteralExpression(prop.initializer, ts.factory.createNodeArray([...prop.initializer.elements, ...declarationsToCopy], prop.initializer.elements.hasTrailingComma));
|
|
548
528
|
}
|
|
549
529
|
else {
|
|
550
|
-
initializer =
|
|
530
|
+
initializer = ts.factory.createArrayLiteralExpression(ts.factory.createNodeArray([ts.factory.createSpreadElement(prop.initializer), ...declarationsToCopy],
|
|
551
531
|
// Expect the declarations to be greater than 1 since
|
|
552
532
|
// we have the pre-existing initializer already.
|
|
553
533
|
hasAnyArrayTrailingComma && declarationsToCopy.length > 1));
|
|
554
534
|
}
|
|
555
|
-
properties.push(
|
|
535
|
+
properties.push(ts.factory.updatePropertyAssignment(prop, prop.name, initializer));
|
|
556
536
|
continue;
|
|
557
537
|
}
|
|
558
538
|
// Retain any remaining properties.
|
|
559
539
|
properties.push(prop);
|
|
560
540
|
}
|
|
561
|
-
tracker.replaceNode(literal,
|
|
541
|
+
tracker.replaceNode(literal, ts.factory.updateObjectLiteralExpression(literal, ts.factory.createNodeArray(properties, literal.properties.hasTrailingComma)), ts.EmitHint.Expression);
|
|
562
542
|
}
|
|
563
543
|
/** Sets a decorator node to be standalone. */
|
|
564
544
|
function markDecoratorAsStandalone(node) {
|
|
565
545
|
const metadata = extractMetadataLiteral(node);
|
|
566
|
-
if (metadata === null || !
|
|
546
|
+
if (metadata === null || !ts.isCallExpression(node.expression)) {
|
|
567
547
|
return node;
|
|
568
548
|
}
|
|
569
549
|
const standaloneProp = metadata.properties.find((prop) => {
|
|
@@ -571,14 +551,14 @@ function markDecoratorAsStandalone(node) {
|
|
|
571
551
|
});
|
|
572
552
|
// In v19 standalone is the default so don't do anything if there's no `standalone`
|
|
573
553
|
// property or it's initialized to anything other than `false`.
|
|
574
|
-
if (!standaloneProp || standaloneProp.initializer.kind !==
|
|
554
|
+
if (!standaloneProp || standaloneProp.initializer.kind !== ts.SyntaxKind.FalseKeyword) {
|
|
575
555
|
return node;
|
|
576
556
|
}
|
|
577
557
|
const newProperties = metadata.properties.filter((element) => element !== standaloneProp);
|
|
578
558
|
// Use `createDecorator` instead of `updateDecorator`, because
|
|
579
559
|
// the latter ends up duplicating the node's leading comment.
|
|
580
|
-
return
|
|
581
|
-
|
|
560
|
+
return ts.factory.createDecorator(ts.factory.createCallExpression(node.expression.expression, node.expression.typeArguments, [
|
|
561
|
+
ts.factory.createObjectLiteralExpression(ts.factory.createNodeArray(newProperties, metadata.properties.hasTrailingComma), newProperties.length > 1),
|
|
582
562
|
]));
|
|
583
563
|
}
|
|
584
564
|
/**
|
|
@@ -590,27 +570,27 @@ function markDecoratorAsStandalone(node) {
|
|
|
590
570
|
*/
|
|
591
571
|
function setPropertyOnAngularDecorator(node, name, initializer) {
|
|
592
572
|
// Invalid decorator.
|
|
593
|
-
if (!
|
|
573
|
+
if (!ts.isCallExpression(node.expression) || node.expression.arguments.length > 1) {
|
|
594
574
|
return node;
|
|
595
575
|
}
|
|
596
576
|
let literalProperties;
|
|
597
577
|
let hasTrailingComma = false;
|
|
598
578
|
if (node.expression.arguments.length === 0) {
|
|
599
|
-
literalProperties = [
|
|
579
|
+
literalProperties = [ts.factory.createPropertyAssignment(name, initializer)];
|
|
600
580
|
}
|
|
601
|
-
else if (
|
|
581
|
+
else if (ts.isObjectLiteralExpression(node.expression.arguments[0])) {
|
|
602
582
|
const literal = node.expression.arguments[0];
|
|
603
583
|
const existingProperty = findLiteralProperty(literal, name);
|
|
604
584
|
hasTrailingComma = literal.properties.hasTrailingComma;
|
|
605
|
-
if (existingProperty &&
|
|
585
|
+
if (existingProperty && ts.isPropertyAssignment(existingProperty)) {
|
|
606
586
|
literalProperties = literal.properties.slice();
|
|
607
587
|
literalProperties[literalProperties.indexOf(existingProperty)] =
|
|
608
|
-
|
|
588
|
+
ts.factory.updatePropertyAssignment(existingProperty, existingProperty.name, initializer);
|
|
609
589
|
}
|
|
610
590
|
else {
|
|
611
591
|
literalProperties = [
|
|
612
592
|
...literal.properties,
|
|
613
|
-
|
|
593
|
+
ts.factory.createPropertyAssignment(name, initializer),
|
|
614
594
|
];
|
|
615
595
|
}
|
|
616
596
|
}
|
|
@@ -620,13 +600,13 @@ function setPropertyOnAngularDecorator(node, name, initializer) {
|
|
|
620
600
|
}
|
|
621
601
|
// Use `createDecorator` instead of `updateDecorator`, because
|
|
622
602
|
// the latter ends up duplicating the node's leading comment.
|
|
623
|
-
return
|
|
624
|
-
|
|
603
|
+
return ts.factory.createDecorator(ts.factory.createCallExpression(node.expression.expression, node.expression.typeArguments, [
|
|
604
|
+
ts.factory.createObjectLiteralExpression(ts.factory.createNodeArray(literalProperties, hasTrailingComma), literalProperties.length > 1),
|
|
625
605
|
]));
|
|
626
606
|
}
|
|
627
607
|
/** Checks if a node is a `PropertyAssignment` with a name. */
|
|
628
608
|
function isNamedPropertyAssignment(node) {
|
|
629
|
-
return
|
|
609
|
+
return ts.isPropertyAssignment(node) && node.name && ts.isIdentifier(node.name);
|
|
630
610
|
}
|
|
631
611
|
/**
|
|
632
612
|
* Finds the import from which to bring in a template dependency of a component.
|
|
@@ -663,16 +643,16 @@ function findImportLocation(target, inContext, importMode, typeChecker) {
|
|
|
663
643
|
* but not `declarations: []`.
|
|
664
644
|
*/
|
|
665
645
|
function hasNgModuleMetadataElements(node) {
|
|
666
|
-
return (
|
|
667
|
-
(!
|
|
646
|
+
return (ts.isPropertyAssignment(node) &&
|
|
647
|
+
(!ts.isArrayLiteralExpression(node.initializer) || node.initializer.elements.length > 0));
|
|
668
648
|
}
|
|
669
649
|
/** Finds all modules whose declarations can be migrated. */
|
|
670
650
|
function findNgModuleClassesToMigrate(sourceFile, typeChecker) {
|
|
671
651
|
const modules = [];
|
|
672
652
|
if (imports.getImportSpecifier(sourceFile, '@angular/core', 'NgModule')) {
|
|
673
653
|
sourceFile.forEachChild(function walk(node) {
|
|
674
|
-
if (
|
|
675
|
-
const decorator = ng_decorators.getAngularDecorators(typeChecker,
|
|
654
|
+
if (ts.isClassDeclaration(node)) {
|
|
655
|
+
const decorator = ng_decorators.getAngularDecorators(typeChecker, ts.getDecorators(node) || []).find((current) => current.name === 'NgModule');
|
|
676
656
|
const metadata = decorator ? extractMetadataLiteral(decorator.node) : null;
|
|
677
657
|
if (metadata) {
|
|
678
658
|
const declarations = findLiteralProperty(metadata, 'declarations');
|
|
@@ -696,8 +676,8 @@ function findTestObjectsToMigrate(sourceFile, typeChecker) {
|
|
|
696
676
|
const config = node.arguments[0];
|
|
697
677
|
const declarations = findLiteralProperty(config, 'declarations');
|
|
698
678
|
if (declarations &&
|
|
699
|
-
|
|
700
|
-
|
|
679
|
+
ts.isPropertyAssignment(declarations) &&
|
|
680
|
+
ts.isArrayLiteralExpression(declarations.initializer) &&
|
|
701
681
|
declarations.initializer.elements.length > 0) {
|
|
702
682
|
testObjects.push(config);
|
|
703
683
|
}
|
|
@@ -718,7 +698,7 @@ function findTemplateDependencies(decl, typeChecker) {
|
|
|
718
698
|
const usedPipes = typeChecker.getUsedPipes(decl);
|
|
719
699
|
if (usedDirectives !== null) {
|
|
720
700
|
for (const dir of usedDirectives) {
|
|
721
|
-
if (
|
|
701
|
+
if (ts.isClassDeclaration(dir.ref.node)) {
|
|
722
702
|
results.push(dir.ref);
|
|
723
703
|
}
|
|
724
704
|
}
|
|
@@ -726,7 +706,7 @@ function findTemplateDependencies(decl, typeChecker) {
|
|
|
726
706
|
if (usedPipes !== null) {
|
|
727
707
|
const potentialPipes = typeChecker.getPotentialPipes(decl);
|
|
728
708
|
for (const pipe of potentialPipes) {
|
|
729
|
-
if (
|
|
709
|
+
if (ts.isClassDeclaration(pipe.ref.node) &&
|
|
730
710
|
usedPipes.some((current) => pipe.name === current)) {
|
|
731
711
|
results.push(pipe.ref);
|
|
732
712
|
}
|
|
@@ -752,13 +732,13 @@ function filterNonBootstrappedDeclarations(declarations, ngModule, templateTypeC
|
|
|
752
732
|
}
|
|
753
733
|
// If we can't analyze the `bootstrap` property, we can't safely determine which
|
|
754
734
|
// declarations aren't bootstrapped so we assume that all of them are.
|
|
755
|
-
if (!
|
|
756
|
-
!
|
|
735
|
+
if (!ts.isPropertyAssignment(bootstrapProp) ||
|
|
736
|
+
!ts.isArrayLiteralExpression(bootstrapProp.initializer)) {
|
|
757
737
|
return [];
|
|
758
738
|
}
|
|
759
739
|
const bootstrappedClasses = new Set();
|
|
760
740
|
for (const el of bootstrapProp.initializer.elements) {
|
|
761
|
-
const referencedClass =
|
|
741
|
+
const referencedClass = ts.isIdentifier(el) ? findClassDeclaration(el, typeChecker) : null;
|
|
762
742
|
// If we can resolve an element to a class, we can filter it out,
|
|
763
743
|
// otherwise assume that the array isn't static.
|
|
764
744
|
if (referencedClass) {
|
|
@@ -779,7 +759,7 @@ function extractDeclarationsFromModule(ngModule, templateTypeChecker) {
|
|
|
779
759
|
const metadata = templateTypeChecker.getNgModuleMetadata(ngModule);
|
|
780
760
|
return metadata
|
|
781
761
|
? metadata.declarations
|
|
782
|
-
.filter((decl) =>
|
|
762
|
+
.filter((decl) => ts.isClassDeclaration(decl.node))
|
|
783
763
|
.map((decl) => decl.node)
|
|
784
764
|
: [];
|
|
785
765
|
}
|
|
@@ -795,7 +775,7 @@ function migrateTestDeclarations(testObjects, declarationsOutsideOfTestFiles, tr
|
|
|
795
775
|
const { decorators, componentImports } = analyzeTestingModules(testObjects, typeChecker);
|
|
796
776
|
const allDeclarations = new Set(declarationsOutsideOfTestFiles);
|
|
797
777
|
for (const decorator of decorators) {
|
|
798
|
-
const closestClass = nodes.closestNode(decorator.node,
|
|
778
|
+
const closestClass = nodes.closestNode(decorator.node, ts.isClassDeclaration);
|
|
799
779
|
if (decorator.name === 'Pipe' || decorator.name === 'Directive') {
|
|
800
780
|
tracker.replaceNode(decorator.node, markDecoratorAsStandalone(decorator.node));
|
|
801
781
|
if (closestClass) {
|
|
@@ -811,8 +791,8 @@ function migrateTestDeclarations(testObjects, declarationsOutsideOfTestFiles, tr
|
|
|
811
791
|
if (importsToAdd && importsToAdd.size > 0) {
|
|
812
792
|
const hasTrailingComma = importsToAdd.size > 2 &&
|
|
813
793
|
!!extractMetadataLiteral(decorator.node)?.properties.hasTrailingComma;
|
|
814
|
-
const importsArray =
|
|
815
|
-
tracker.replaceNode(decorator.node, setPropertyOnAngularDecorator(newDecorator, 'imports',
|
|
794
|
+
const importsArray = ts.factory.createNodeArray(Array.from(importsToAdd), hasTrailingComma);
|
|
795
|
+
tracker.replaceNode(decorator.node, setPropertyOnAngularDecorator(newDecorator, 'imports', ts.factory.createArrayLiteralExpression(importsArray)));
|
|
816
796
|
}
|
|
817
797
|
else {
|
|
818
798
|
tracker.replaceNode(decorator.node, newDecorator);
|
|
@@ -841,10 +821,10 @@ function analyzeTestingModules(testObjects, typeChecker) {
|
|
|
841
821
|
const importsProp = findLiteralProperty(obj, 'imports');
|
|
842
822
|
const importElements = importsProp &&
|
|
843
823
|
hasNgModuleMetadataElements(importsProp) &&
|
|
844
|
-
|
|
824
|
+
ts.isArrayLiteralExpression(importsProp.initializer)
|
|
845
825
|
? importsProp.initializer.elements.filter((el) => {
|
|
846
826
|
// Filter out calls since they may be a `ModuleWithProviders`.
|
|
847
|
-
return (!
|
|
827
|
+
return (!ts.isCallExpression(el) &&
|
|
848
828
|
// Also filter out the animations modules since they throw errors if they're imported
|
|
849
829
|
// multiple times and it's common for apps to use the `NoopAnimationsModule` to
|
|
850
830
|
// disable animations in screenshot tests.
|
|
@@ -855,7 +835,7 @@ function analyzeTestingModules(testObjects, typeChecker) {
|
|
|
855
835
|
if (seenDeclarations.has(decl)) {
|
|
856
836
|
continue;
|
|
857
837
|
}
|
|
858
|
-
const [decorator] = ng_decorators.getAngularDecorators(typeChecker,
|
|
838
|
+
const [decorator] = ng_decorators.getAngularDecorators(typeChecker, ts.getDecorators(decl) || []);
|
|
859
839
|
if (decorator) {
|
|
860
840
|
seenDeclarations.add(decl);
|
|
861
841
|
decorators.push(decorator);
|
|
@@ -885,7 +865,7 @@ function extractDeclarationsFromTestObject(obj, typeChecker) {
|
|
|
885
865
|
const declarations = findLiteralProperty(obj, 'declarations');
|
|
886
866
|
if (declarations &&
|
|
887
867
|
hasNgModuleMetadataElements(declarations) &&
|
|
888
|
-
|
|
868
|
+
ts.isArrayLiteralExpression(declarations.initializer)) {
|
|
889
869
|
for (const element of declarations.initializer.elements) {
|
|
890
870
|
const declaration = findClassDeclaration(element, typeChecker);
|
|
891
871
|
// Note that we only migrate classes that are in the same file as the testing module,
|
|
@@ -901,9 +881,9 @@ function extractDeclarationsFromTestObject(obj, typeChecker) {
|
|
|
901
881
|
/** Extracts the metadata object literal from an Angular decorator. */
|
|
902
882
|
function extractMetadataLiteral(decorator) {
|
|
903
883
|
// `arguments[0]` is the metadata object literal.
|
|
904
|
-
return
|
|
884
|
+
return ts.isCallExpression(decorator.expression) &&
|
|
905
885
|
decorator.expression.arguments.length === 1 &&
|
|
906
|
-
|
|
886
|
+
ts.isObjectLiteralExpression(decorator.expression.arguments[0])
|
|
907
887
|
? decorator.expression.arguments[0]
|
|
908
888
|
: null;
|
|
909
889
|
}
|
|
@@ -947,14 +927,14 @@ function pruneNgModules(program, host, basePath, rootFileNames, sourceFiles, pri
|
|
|
947
927
|
const testArrays = new UniqueItemTracker();
|
|
948
928
|
const nodesToRemove = new Set();
|
|
949
929
|
sourceFiles.forEach(function walk(node) {
|
|
950
|
-
if (
|
|
930
|
+
if (ts.isClassDeclaration(node) && canRemoveClass(node, typeChecker)) {
|
|
951
931
|
collectChangeLocations(node, removalLocations, componentImportArrays, testArrays, templateTypeChecker, referenceResolver, program);
|
|
952
932
|
classesToRemove.add(node);
|
|
953
933
|
}
|
|
954
|
-
else if (
|
|
934
|
+
else if (ts.isExportDeclaration(node) &&
|
|
955
935
|
!node.exportClause &&
|
|
956
936
|
node.moduleSpecifier &&
|
|
957
|
-
|
|
937
|
+
ts.isStringLiteralLike(node.moduleSpecifier) &&
|
|
958
938
|
node.moduleSpecifier.text.startsWith('.')) {
|
|
959
939
|
const exportedSourceFile = typeChecker
|
|
960
940
|
.getSymbolAtLocation(node.moduleSpecifier)
|
|
@@ -1021,15 +1001,15 @@ function collectChangeLocations(ngModule, removalLocations, componentImportArray
|
|
|
1021
1001
|
}
|
|
1022
1002
|
}
|
|
1023
1003
|
for (const node of nodes$1) {
|
|
1024
|
-
const closestArray = nodes.closestNode(node,
|
|
1004
|
+
const closestArray = nodes.closestNode(node, ts.isArrayLiteralExpression);
|
|
1025
1005
|
if (closestArray) {
|
|
1026
|
-
const closestAssignment = nodes.closestNode(closestArray,
|
|
1006
|
+
const closestAssignment = nodes.closestNode(closestArray, ts.isPropertyAssignment);
|
|
1027
1007
|
if (closestAssignment && isInImportsArray(closestAssignment, closestArray)) {
|
|
1028
|
-
const closestCall = nodes.closestNode(closestAssignment,
|
|
1008
|
+
const closestCall = nodes.closestNode(closestAssignment, ts.isCallExpression);
|
|
1029
1009
|
if (closestCall) {
|
|
1030
|
-
const closestDecorator = nodes.closestNode(closestCall,
|
|
1010
|
+
const closestDecorator = nodes.closestNode(closestCall, ts.isDecorator);
|
|
1031
1011
|
const closestClass = closestDecorator
|
|
1032
|
-
? nodes.closestNode(closestDecorator,
|
|
1012
|
+
? nodes.closestNode(closestDecorator, ts.isClassDeclaration)
|
|
1033
1013
|
: null;
|
|
1034
1014
|
const directiveMeta = closestClass
|
|
1035
1015
|
? templateTypeChecker.getDirectiveMetadata(closestClass)
|
|
@@ -1054,12 +1034,12 @@ function collectChangeLocations(ngModule, removalLocations, componentImportArray
|
|
|
1054
1034
|
removalLocations.arrays.track(closestArray, node);
|
|
1055
1035
|
continue;
|
|
1056
1036
|
}
|
|
1057
|
-
const closestImport = nodes.closestNode(node,
|
|
1037
|
+
const closestImport = nodes.closestNode(node, ts.isNamedImports);
|
|
1058
1038
|
if (closestImport) {
|
|
1059
1039
|
removalLocations.imports.track(closestImport, node);
|
|
1060
1040
|
continue;
|
|
1061
1041
|
}
|
|
1062
|
-
const closestExport = nodes.closestNode(node,
|
|
1042
|
+
const closestExport = nodes.closestNode(node, ts.isNamedExports);
|
|
1063
1043
|
if (closestExport) {
|
|
1064
1044
|
removalLocations.exports.track(closestExport, node);
|
|
1065
1045
|
continue;
|
|
@@ -1078,7 +1058,7 @@ function collectChangeLocations(ngModule, removalLocations, componentImportArray
|
|
|
1078
1058
|
*/
|
|
1079
1059
|
function replaceInComponentImportsArray(componentImportArrays, classesToRemove, tracker, typeChecker, templateTypeChecker, importRemapper) {
|
|
1080
1060
|
for (const [array, toReplace] of componentImportArrays.getEntries()) {
|
|
1081
|
-
const closestClass = nodes.closestNode(array,
|
|
1061
|
+
const closestClass = nodes.closestNode(array, ts.isClassDeclaration);
|
|
1082
1062
|
if (!closestClass) {
|
|
1083
1063
|
continue;
|
|
1084
1064
|
}
|
|
@@ -1157,7 +1137,7 @@ function replaceModulesInImportsArray(array, replacements, tracker, templateType
|
|
|
1157
1137
|
const newElements = [];
|
|
1158
1138
|
const identifiers = new Set();
|
|
1159
1139
|
for (const element of array.elements) {
|
|
1160
|
-
if (
|
|
1140
|
+
if (ts.isIdentifier(element)) {
|
|
1161
1141
|
identifiers.add(element.text);
|
|
1162
1142
|
}
|
|
1163
1143
|
}
|
|
@@ -1175,12 +1155,12 @@ function replaceModulesInImportsArray(array, replacements, tracker, templateType
|
|
|
1175
1155
|
}
|
|
1176
1156
|
}
|
|
1177
1157
|
potentialImportsToExpressions(potentialImports, array.getSourceFile(), tracker, importRemapper).forEach((expr) => {
|
|
1178
|
-
if (!
|
|
1158
|
+
if (!ts.isIdentifier(expr) || !identifiers.has(expr.text)) {
|
|
1179
1159
|
newElements.push(expr);
|
|
1180
1160
|
}
|
|
1181
1161
|
});
|
|
1182
1162
|
}
|
|
1183
|
-
tracker.replaceNode(array,
|
|
1163
|
+
tracker.replaceNode(array, ts.factory.updateArrayLiteralExpression(array, newElements));
|
|
1184
1164
|
}
|
|
1185
1165
|
/**
|
|
1186
1166
|
* Removes all tracked array references.
|
|
@@ -1190,7 +1170,7 @@ function replaceModulesInImportsArray(array, replacements, tracker, templateType
|
|
|
1190
1170
|
function removeArrayReferences(locations, tracker) {
|
|
1191
1171
|
for (const [array, toRemove] of locations.getEntries()) {
|
|
1192
1172
|
const newElements = filterRemovedElements(array.elements, toRemove);
|
|
1193
|
-
tracker.replaceNode(array,
|
|
1173
|
+
tracker.replaceNode(array, ts.factory.updateArrayLiteralExpression(array, ts.factory.createNodeArray(newElements, array.elements.hasTrailingComma)));
|
|
1194
1174
|
}
|
|
1195
1175
|
}
|
|
1196
1176
|
/**
|
|
@@ -1203,15 +1183,15 @@ function removeImportReferences(locations, tracker) {
|
|
|
1203
1183
|
const newElements = filterRemovedElements(namedImports.elements, toRemove);
|
|
1204
1184
|
// If no imports are left, we can try to drop the entire import.
|
|
1205
1185
|
if (newElements.length === 0) {
|
|
1206
|
-
const importClause = nodes.closestNode(namedImports,
|
|
1186
|
+
const importClause = nodes.closestNode(namedImports, ts.isImportClause);
|
|
1207
1187
|
// If the import clause has a name we can only drop then named imports.
|
|
1208
1188
|
// e.g. `import Foo, {ModuleToRemove} from './foo';` becomes `import Foo from './foo';`.
|
|
1209
1189
|
if (importClause && importClause.name) {
|
|
1210
|
-
tracker.replaceNode(importClause,
|
|
1190
|
+
tracker.replaceNode(importClause, ts.factory.updateImportClause(importClause, importClause.isTypeOnly, importClause.name, undefined));
|
|
1211
1191
|
}
|
|
1212
1192
|
else {
|
|
1213
1193
|
// Otherwise we can drop the entire declaration.
|
|
1214
|
-
const declaration = nodes.closestNode(namedImports,
|
|
1194
|
+
const declaration = nodes.closestNode(namedImports, ts.isImportDeclaration);
|
|
1215
1195
|
if (declaration) {
|
|
1216
1196
|
tracker.removeNode(declaration);
|
|
1217
1197
|
}
|
|
@@ -1219,7 +1199,7 @@ function removeImportReferences(locations, tracker) {
|
|
|
1219
1199
|
}
|
|
1220
1200
|
else {
|
|
1221
1201
|
// Otherwise we just drop the imported symbols and keep the declaration intact.
|
|
1222
|
-
tracker.replaceNode(namedImports,
|
|
1202
|
+
tracker.replaceNode(namedImports, ts.factory.updateNamedImports(namedImports, newElements));
|
|
1223
1203
|
}
|
|
1224
1204
|
}
|
|
1225
1205
|
}
|
|
@@ -1233,14 +1213,14 @@ function removeExportReferences(locations, tracker) {
|
|
|
1233
1213
|
const newElements = filterRemovedElements(namedExports.elements, toRemove);
|
|
1234
1214
|
// If no exports are left, we can drop the entire declaration.
|
|
1235
1215
|
if (newElements.length === 0) {
|
|
1236
|
-
const declaration = nodes.closestNode(namedExports,
|
|
1216
|
+
const declaration = nodes.closestNode(namedExports, ts.isExportDeclaration);
|
|
1237
1217
|
if (declaration) {
|
|
1238
1218
|
tracker.removeNode(declaration);
|
|
1239
1219
|
}
|
|
1240
1220
|
}
|
|
1241
1221
|
else {
|
|
1242
1222
|
// Otherwise we just drop the exported symbols and keep the declaration intact.
|
|
1243
|
-
tracker.replaceNode(namedExports,
|
|
1223
|
+
tracker.replaceNode(namedExports, ts.factory.updateNamedExports(namedExports, newElements));
|
|
1244
1224
|
}
|
|
1245
1225
|
}
|
|
1246
1226
|
}
|
|
@@ -1257,12 +1237,12 @@ function removeExportReferences(locations, tracker) {
|
|
|
1257
1237
|
function canRemoveClass(node, typeChecker) {
|
|
1258
1238
|
const decorator = findNgModuleDecorator(node, typeChecker)?.node;
|
|
1259
1239
|
// We can't remove a declaration if it's not a valid `NgModule`.
|
|
1260
|
-
if (!decorator || !
|
|
1240
|
+
if (!decorator || !ts.isCallExpression(decorator.expression)) {
|
|
1261
1241
|
return false;
|
|
1262
1242
|
}
|
|
1263
1243
|
// Unsupported case, e.g. `@NgModule(SOME_VALUE)`.
|
|
1264
1244
|
if (decorator.expression.arguments.length > 0 &&
|
|
1265
|
-
!
|
|
1245
|
+
!ts.isObjectLiteralExpression(decorator.expression.arguments[0])) {
|
|
1266
1246
|
return false;
|
|
1267
1247
|
}
|
|
1268
1248
|
// We can't remove modules that have class members. We make an exception for an
|
|
@@ -1280,7 +1260,7 @@ function canRemoveClass(node, typeChecker) {
|
|
|
1280
1260
|
// We can't remove the class if at least one import isn't identifier, because it may be a
|
|
1281
1261
|
// `ModuleWithProviders` which is the equivalent of having something in the `providers` array.
|
|
1282
1262
|
for (const dep of imports.initializer.elements) {
|
|
1283
|
-
if (!
|
|
1263
|
+
if (!ts.isIdentifier(dep)) {
|
|
1284
1264
|
return false;
|
|
1285
1265
|
}
|
|
1286
1266
|
const depDeclaration = findClassDeclaration(dep, typeChecker);
|
|
@@ -1316,9 +1296,9 @@ function canRemoveClass(node, typeChecker) {
|
|
|
1316
1296
|
* @param node Node to be checked.
|
|
1317
1297
|
*/
|
|
1318
1298
|
function isNonEmptyNgModuleProperty(node) {
|
|
1319
|
-
return (
|
|
1320
|
-
|
|
1321
|
-
|
|
1299
|
+
return (ts.isPropertyAssignment(node) &&
|
|
1300
|
+
ts.isIdentifier(node.name) &&
|
|
1301
|
+
ts.isArrayLiteralExpression(node.initializer) &&
|
|
1322
1302
|
node.initializer.elements.length > 0);
|
|
1323
1303
|
}
|
|
1324
1304
|
/**
|
|
@@ -1329,12 +1309,12 @@ function isNonEmptyNgModuleProperty(node) {
|
|
|
1329
1309
|
*/
|
|
1330
1310
|
function canRemoveFile(sourceFile, nodesToBeRemoved) {
|
|
1331
1311
|
for (const node of sourceFile.statements) {
|
|
1332
|
-
if (
|
|
1312
|
+
if (ts.isImportDeclaration(node) || nodesToBeRemoved.has(node)) {
|
|
1333
1313
|
continue;
|
|
1334
1314
|
}
|
|
1335
|
-
if (
|
|
1336
|
-
(
|
|
1337
|
-
|
|
1315
|
+
if (ts.isExportDeclaration(node) ||
|
|
1316
|
+
(ts.canHaveModifiers(node) &&
|
|
1317
|
+
ts.getModifiers(node)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword))) {
|
|
1338
1318
|
return false;
|
|
1339
1319
|
}
|
|
1340
1320
|
}
|
|
@@ -1371,7 +1351,7 @@ function filterRemovedElements(elements, toRemove) {
|
|
|
1371
1351
|
}
|
|
1372
1352
|
/** Returns whether a node as an empty constructor. */
|
|
1373
1353
|
function isEmptyConstructor(node) {
|
|
1374
|
-
return (
|
|
1354
|
+
return (ts.isConstructorDeclaration(node) &&
|
|
1375
1355
|
node.parameters.length === 0 &&
|
|
1376
1356
|
(node.body == null || node.body.statements.length === 0));
|
|
1377
1357
|
}
|
|
@@ -1392,7 +1372,7 @@ function addRemovalTodos(nodes, tracker) {
|
|
|
1392
1372
|
}
|
|
1393
1373
|
/** Finds the `NgModule` decorator in a class, if it exists. */
|
|
1394
1374
|
function findNgModuleDecorator(node, typeChecker) {
|
|
1395
|
-
const decorators = ng_decorators.getAngularDecorators(typeChecker,
|
|
1375
|
+
const decorators = ng_decorators.getAngularDecorators(typeChecker, ts.getDecorators(node) || []);
|
|
1396
1376
|
return decorators.find((decorator) => decorator.name === 'NgModule') || null;
|
|
1397
1377
|
}
|
|
1398
1378
|
/**
|
|
@@ -1402,7 +1382,7 @@ function findNgModuleDecorator(node, typeChecker) {
|
|
|
1402
1382
|
*/
|
|
1403
1383
|
function isInImportsArray(closestAssignment, closestArray) {
|
|
1404
1384
|
return (closestAssignment.initializer === closestArray &&
|
|
1405
|
-
(
|
|
1385
|
+
(ts.isIdentifier(closestAssignment.name) || ts.isStringLiteralLike(closestAssignment.name)) &&
|
|
1406
1386
|
closestAssignment.name.text === 'imports');
|
|
1407
1387
|
}
|
|
1408
1388
|
|
|
@@ -1428,8 +1408,8 @@ function toStandaloneBootstrap(program, host, basePath, rootFileNames, sourceFil
|
|
|
1428
1408
|
: null;
|
|
1429
1409
|
for (const sourceFile of sourceFiles) {
|
|
1430
1410
|
sourceFile.forEachChild(function walk(node) {
|
|
1431
|
-
if (
|
|
1432
|
-
|
|
1411
|
+
if (ts.isCallExpression(node) &&
|
|
1412
|
+
ts.isPropertyAccessExpression(node.expression) &&
|
|
1433
1413
|
node.expression.name.text === 'bootstrapModule' &&
|
|
1434
1414
|
isClassReferenceInAngularModule(node.expression, 'PlatformRef', 'core', typeChecker)) {
|
|
1435
1415
|
const call = analyzeBootstrapCall(node, typeChecker, templateTypeChecker);
|
|
@@ -1461,30 +1441,30 @@ function toStandaloneBootstrap(program, host, basePath, rootFileNames, sourceFil
|
|
|
1461
1441
|
* @param templateTypeChecker
|
|
1462
1442
|
*/
|
|
1463
1443
|
function analyzeBootstrapCall(call, typeChecker, templateTypeChecker) {
|
|
1464
|
-
if (call.arguments.length === 0 || !
|
|
1444
|
+
if (call.arguments.length === 0 || !ts.isIdentifier(call.arguments[0])) {
|
|
1465
1445
|
return null;
|
|
1466
1446
|
}
|
|
1467
1447
|
const declaration = findClassDeclaration(call.arguments[0], typeChecker);
|
|
1468
1448
|
if (!declaration) {
|
|
1469
1449
|
return null;
|
|
1470
1450
|
}
|
|
1471
|
-
const decorator = ng_decorators.getAngularDecorators(typeChecker,
|
|
1451
|
+
const decorator = ng_decorators.getAngularDecorators(typeChecker, ts.getDecorators(declaration) || []).find((decorator) => decorator.name === 'NgModule');
|
|
1472
1452
|
if (!decorator ||
|
|
1473
1453
|
decorator.node.expression.arguments.length === 0 ||
|
|
1474
|
-
!
|
|
1454
|
+
!ts.isObjectLiteralExpression(decorator.node.expression.arguments[0])) {
|
|
1475
1455
|
return null;
|
|
1476
1456
|
}
|
|
1477
1457
|
const metadata = decorator.node.expression.arguments[0];
|
|
1478
1458
|
const bootstrapProp = findLiteralProperty(metadata, 'bootstrap');
|
|
1479
1459
|
if (!bootstrapProp ||
|
|
1480
|
-
!
|
|
1481
|
-
!
|
|
1460
|
+
!ts.isPropertyAssignment(bootstrapProp) ||
|
|
1461
|
+
!ts.isArrayLiteralExpression(bootstrapProp.initializer) ||
|
|
1482
1462
|
bootstrapProp.initializer.elements.length === 0 ||
|
|
1483
|
-
!
|
|
1463
|
+
!ts.isIdentifier(bootstrapProp.initializer.elements[0])) {
|
|
1484
1464
|
return null;
|
|
1485
1465
|
}
|
|
1486
1466
|
const component = findClassDeclaration(bootstrapProp.initializer.elements[0], typeChecker);
|
|
1487
|
-
if (component && component.name &&
|
|
1467
|
+
if (component && component.name && ts.isIdentifier(component.name)) {
|
|
1488
1468
|
return {
|
|
1489
1469
|
module: declaration,
|
|
1490
1470
|
metadata,
|
|
@@ -1518,23 +1498,23 @@ function migrateBootstrapCall(analysis, tracker, additionalProviders, referenceR
|
|
|
1518
1498
|
// If the pruning is left for some reason, the user will still have an actionable TODO.
|
|
1519
1499
|
tracker.insertText(moduleSourceFile, analysis.metadata.getStart(), '/* TODO(standalone-migration): clean up removed NgModule class manually. \n');
|
|
1520
1500
|
tracker.insertText(moduleSourceFile, analysis.metadata.getEnd(), ' */');
|
|
1521
|
-
if (providers &&
|
|
1501
|
+
if (providers && ts.isPropertyAssignment(providers)) {
|
|
1522
1502
|
nodeLookup = nodeLookup || getNodeLookup(moduleSourceFile);
|
|
1523
|
-
if (
|
|
1503
|
+
if (ts.isArrayLiteralExpression(providers.initializer)) {
|
|
1524
1504
|
providersInNewCall.push(...providers.initializer.elements);
|
|
1525
1505
|
}
|
|
1526
1506
|
else {
|
|
1527
|
-
providersInNewCall.push(
|
|
1507
|
+
providersInNewCall.push(ts.factory.createSpreadElement(providers.initializer));
|
|
1528
1508
|
}
|
|
1529
1509
|
addNodesToCopy(sourceFile, providers, nodeLookup, tracker, nodesToCopy, referenceResolver);
|
|
1530
1510
|
}
|
|
1531
|
-
if (imports &&
|
|
1511
|
+
if (imports && ts.isPropertyAssignment(imports)) {
|
|
1532
1512
|
nodeLookup = nodeLookup || getNodeLookup(moduleSourceFile);
|
|
1533
1513
|
migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, moduleImportsInNewCall, providersInNewCall, tracker, nodesToCopy, referenceResolver, typeChecker);
|
|
1534
1514
|
}
|
|
1535
1515
|
if (additionalProviders) {
|
|
1536
1516
|
additionalProviders.forEach((moduleSpecifier, name) => {
|
|
1537
|
-
providersInNewCall.push(
|
|
1517
|
+
providersInNewCall.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, name, moduleSpecifier), undefined, undefined));
|
|
1538
1518
|
});
|
|
1539
1519
|
}
|
|
1540
1520
|
if (nodesToCopy.size > 0) {
|
|
@@ -1547,7 +1527,7 @@ function migrateBootstrapCall(analysis, tracker, additionalProviders, referenceR
|
|
|
1547
1527
|
text += transformedNode.getText() + '\n';
|
|
1548
1528
|
}
|
|
1549
1529
|
else {
|
|
1550
|
-
text += printer.printNode(
|
|
1530
|
+
text += printer.printNode(ts.EmitHint.Unspecified, transformedNode, node.getSourceFile());
|
|
1551
1531
|
}
|
|
1552
1532
|
});
|
|
1553
1533
|
text += '\n';
|
|
@@ -1571,15 +1551,15 @@ function replaceBootstrapCallExpression(analysis, providers, modules, tracker) {
|
|
|
1571
1551
|
const combinedProviders = [];
|
|
1572
1552
|
if (modules.length > 0) {
|
|
1573
1553
|
const importProvidersExpression = tracker.addImport(sourceFile, 'importProvidersFrom', '@angular/core');
|
|
1574
|
-
combinedProviders.push(
|
|
1554
|
+
combinedProviders.push(ts.factory.createCallExpression(importProvidersExpression, [], modules));
|
|
1575
1555
|
}
|
|
1576
1556
|
// Push the providers after `importProvidersFrom` call for better readability.
|
|
1577
1557
|
combinedProviders.push(...providers);
|
|
1578
|
-
const providersArray =
|
|
1579
|
-
const initializer = remapDynamicImports(sourceFile.fileName,
|
|
1580
|
-
args.push(
|
|
1558
|
+
const providersArray = ts.factory.createNodeArray(combinedProviders, analysis.metadata.properties.hasTrailingComma && combinedProviders.length > 2);
|
|
1559
|
+
const initializer = remapDynamicImports(sourceFile.fileName, ts.factory.createArrayLiteralExpression(providersArray, combinedProviders.length > 1));
|
|
1560
|
+
args.push(ts.factory.createObjectLiteralExpression([ts.factory.createPropertyAssignment('providers', initializer)], true));
|
|
1581
1561
|
}
|
|
1582
|
-
tracker.replaceNode(analysis.call,
|
|
1562
|
+
tracker.replaceNode(analysis.call, ts.factory.createCallExpression(bootstrapExpression, [], args),
|
|
1583
1563
|
// Note: it's important to pass in the source file that the nodes originated from!
|
|
1584
1564
|
// Otherwise TS won't print out literals inside of the providers that we're copying
|
|
1585
1565
|
// over from the module file.
|
|
@@ -1599,14 +1579,14 @@ function replaceBootstrapCallExpression(analysis, providers, modules, tracker) {
|
|
|
1599
1579
|
* @param typeChecker
|
|
1600
1580
|
*/
|
|
1601
1581
|
function migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, importsForNewCall, providersInNewCall, tracker, nodesToCopy, referenceResolver, typeChecker) {
|
|
1602
|
-
if (!
|
|
1582
|
+
if (!ts.isArrayLiteralExpression(imports.initializer)) {
|
|
1603
1583
|
importsForNewCall.push(imports.initializer);
|
|
1604
1584
|
return;
|
|
1605
1585
|
}
|
|
1606
1586
|
for (const element of imports.initializer.elements) {
|
|
1607
1587
|
// If the reference is to a `RouterModule.forRoot` call, we can try to migrate it.
|
|
1608
|
-
if (
|
|
1609
|
-
|
|
1588
|
+
if (ts.isCallExpression(element) &&
|
|
1589
|
+
ts.isPropertyAccessExpression(element.expression) &&
|
|
1610
1590
|
element.arguments.length > 0 &&
|
|
1611
1591
|
element.expression.name.text === 'forRoot' &&
|
|
1612
1592
|
isClassReferenceInAngularModule(element.expression.expression, 'RouterModule', 'router', typeChecker)) {
|
|
@@ -1615,7 +1595,7 @@ function migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, imports
|
|
|
1615
1595
|
// If the features come back as null, it means that the router
|
|
1616
1596
|
// has a configuration that can't be migrated automatically.
|
|
1617
1597
|
if (features !== null) {
|
|
1618
|
-
providersInNewCall.push(
|
|
1598
|
+
providersInNewCall.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, 'provideRouter', '@angular/router'), [], [element.arguments[0], ...features]));
|
|
1619
1599
|
addNodesToCopy(sourceFile, element.arguments[0], nodeLookup, tracker, nodesToCopy, referenceResolver);
|
|
1620
1600
|
if (options) {
|
|
1621
1601
|
addNodesToCopy(sourceFile, options, nodeLookup, tracker, nodesToCopy, referenceResolver);
|
|
@@ -1623,17 +1603,17 @@ function migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, imports
|
|
|
1623
1603
|
continue;
|
|
1624
1604
|
}
|
|
1625
1605
|
}
|
|
1626
|
-
if (
|
|
1606
|
+
if (ts.isIdentifier(element)) {
|
|
1627
1607
|
// `BrowserAnimationsModule` can be replaced with `provideAnimations`.
|
|
1628
1608
|
const animationsModule = 'platform-browser/animations';
|
|
1629
1609
|
const animationsImport = `@angular/${animationsModule}`;
|
|
1630
1610
|
if (isClassReferenceInAngularModule(element, 'BrowserAnimationsModule', animationsModule, typeChecker)) {
|
|
1631
|
-
providersInNewCall.push(
|
|
1611
|
+
providersInNewCall.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, 'provideAnimations', animationsImport), [], []));
|
|
1632
1612
|
continue;
|
|
1633
1613
|
}
|
|
1634
1614
|
// `NoopAnimationsModule` can be replaced with `provideNoopAnimations`.
|
|
1635
1615
|
if (isClassReferenceInAngularModule(element, 'NoopAnimationsModule', animationsModule, typeChecker)) {
|
|
1636
|
-
providersInNewCall.push(
|
|
1616
|
+
providersInNewCall.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, 'provideNoopAnimations', animationsImport), [], []));
|
|
1637
1617
|
continue;
|
|
1638
1618
|
}
|
|
1639
1619
|
// `HttpClientModule` can be replaced with `provideHttpClient()`.
|
|
@@ -1643,21 +1623,21 @@ function migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, imports
|
|
|
1643
1623
|
const callArgs = [
|
|
1644
1624
|
// we add `withInterceptorsFromDi()` to the call to ensure that class-based interceptors
|
|
1645
1625
|
// still work
|
|
1646
|
-
|
|
1626
|
+
ts.factory.createCallExpression(tracker.addImport(sourceFile, 'withInterceptorsFromDi', httpClientImport), [], []),
|
|
1647
1627
|
];
|
|
1648
|
-
providersInNewCall.push(
|
|
1628
|
+
providersInNewCall.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, 'provideHttpClient', httpClientImport), [], callArgs));
|
|
1649
1629
|
continue;
|
|
1650
1630
|
}
|
|
1651
1631
|
}
|
|
1652
1632
|
const target =
|
|
1653
1633
|
// If it's a call, it'll likely be a `ModuleWithProviders`
|
|
1654
1634
|
// expression so the target is going to be call's expression.
|
|
1655
|
-
|
|
1635
|
+
ts.isCallExpression(element) && ts.isPropertyAccessExpression(element.expression)
|
|
1656
1636
|
? element.expression.expression
|
|
1657
1637
|
: element;
|
|
1658
1638
|
const classDeclaration = findClassDeclaration(target, typeChecker);
|
|
1659
1639
|
const decorators = classDeclaration
|
|
1660
|
-
? ng_decorators.getAngularDecorators(typeChecker,
|
|
1640
|
+
? ng_decorators.getAngularDecorators(typeChecker, ts.getDecorators(classDeclaration) || [])
|
|
1661
1641
|
: undefined;
|
|
1662
1642
|
if (!decorators ||
|
|
1663
1643
|
decorators.length === 0 ||
|
|
@@ -1677,7 +1657,7 @@ function migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, imports
|
|
|
1677
1657
|
*/
|
|
1678
1658
|
function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
1679
1659
|
// Options that aren't a static object literal can't be migrated.
|
|
1680
|
-
if (!
|
|
1660
|
+
if (!ts.isObjectLiteralExpression(options)) {
|
|
1681
1661
|
return null;
|
|
1682
1662
|
}
|
|
1683
1663
|
const featureExpressions = [];
|
|
@@ -1686,8 +1666,8 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1686
1666
|
const features = new UniqueItemTracker();
|
|
1687
1667
|
for (const prop of options.properties) {
|
|
1688
1668
|
// We can't migrate options that we can't easily analyze.
|
|
1689
|
-
if (!
|
|
1690
|
-
(!
|
|
1669
|
+
if (!ts.isPropertyAssignment(prop) ||
|
|
1670
|
+
(!ts.isIdentifier(prop.name) && !ts.isStringLiteralLike(prop.name))) {
|
|
1691
1671
|
return null;
|
|
1692
1672
|
}
|
|
1693
1673
|
switch (prop.name.text) {
|
|
@@ -1697,7 +1677,7 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1697
1677
|
break;
|
|
1698
1678
|
// `enableTracing: true` maps to the `withDebugTracing` feature.
|
|
1699
1679
|
case 'enableTracing':
|
|
1700
|
-
if (prop.initializer.kind ===
|
|
1680
|
+
if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) {
|
|
1701
1681
|
features.track('withDebugTracing', null);
|
|
1702
1682
|
}
|
|
1703
1683
|
break;
|
|
@@ -1705,7 +1685,7 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1705
1685
|
// `withEnabledBlockingInitialNavigation` feature, while `initialNavigation: 'disabled'` maps
|
|
1706
1686
|
// to the `withDisabledInitialNavigation` feature.
|
|
1707
1687
|
case 'initialNavigation':
|
|
1708
|
-
if (!
|
|
1688
|
+
if (!ts.isStringLiteralLike(prop.initializer)) {
|
|
1709
1689
|
return null;
|
|
1710
1690
|
}
|
|
1711
1691
|
if (prop.initializer.text === 'enabledBlocking' || prop.initializer.text === 'enabled') {
|
|
@@ -1717,7 +1697,7 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1717
1697
|
break;
|
|
1718
1698
|
// `useHash: true` maps to the `withHashLocation` feature.
|
|
1719
1699
|
case 'useHash':
|
|
1720
|
-
if (prop.initializer.kind ===
|
|
1700
|
+
if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) {
|
|
1721
1701
|
features.track('withHashLocation', null);
|
|
1722
1702
|
}
|
|
1723
1703
|
break;
|
|
@@ -1738,10 +1718,10 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1738
1718
|
}
|
|
1739
1719
|
}
|
|
1740
1720
|
if (inMemoryScrollingOptions.length > 0) {
|
|
1741
|
-
features.track('withInMemoryScrolling',
|
|
1721
|
+
features.track('withInMemoryScrolling', ts.factory.createObjectLiteralExpression(inMemoryScrollingOptions));
|
|
1742
1722
|
}
|
|
1743
1723
|
if (configOptions.length > 0) {
|
|
1744
|
-
features.track('withRouterConfig',
|
|
1724
|
+
features.track('withRouterConfig', ts.factory.createObjectLiteralExpression(configOptions));
|
|
1745
1725
|
}
|
|
1746
1726
|
for (const [feature, featureArgs] of features.getEntries()) {
|
|
1747
1727
|
const callArgs = [];
|
|
@@ -1750,7 +1730,7 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1750
1730
|
callArgs.push(arg);
|
|
1751
1731
|
}
|
|
1752
1732
|
});
|
|
1753
|
-
featureExpressions.push(
|
|
1733
|
+
featureExpressions.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, feature, '@angular/router'), [], callArgs));
|
|
1754
1734
|
}
|
|
1755
1735
|
return featureExpressions;
|
|
1756
1736
|
}
|
|
@@ -1767,14 +1747,14 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1767
1747
|
function addNodesToCopy(targetFile, rootNode, nodeLookup, tracker, nodesToCopy, referenceResolver) {
|
|
1768
1748
|
const refs = findAllSameFileReferences(rootNode, nodeLookup, referenceResolver);
|
|
1769
1749
|
for (const ref of refs) {
|
|
1770
|
-
const importSpecifier = closestOrSelf(ref,
|
|
1750
|
+
const importSpecifier = closestOrSelf(ref, ts.isImportSpecifier);
|
|
1771
1751
|
const importDeclaration = importSpecifier
|
|
1772
|
-
? nodes.closestNode(importSpecifier,
|
|
1752
|
+
? nodes.closestNode(importSpecifier, ts.isImportDeclaration)
|
|
1773
1753
|
: null;
|
|
1774
1754
|
// If the reference is in an import, we need to add an import to the main file.
|
|
1775
1755
|
if (importDeclaration &&
|
|
1776
1756
|
importSpecifier &&
|
|
1777
|
-
|
|
1757
|
+
ts.isStringLiteralLike(importDeclaration.moduleSpecifier)) {
|
|
1778
1758
|
const moduleName = importDeclaration.moduleSpecifier.text.startsWith('.')
|
|
1779
1759
|
? remapRelativeImport(targetFile.fileName, importDeclaration.moduleSpecifier)
|
|
1780
1760
|
: importDeclaration.moduleSpecifier.text;
|
|
@@ -1785,12 +1765,12 @@ function addNodesToCopy(targetFile, rootNode, nodeLookup, tracker, nodesToCopy,
|
|
|
1785
1765
|
tracker.addImport(targetFile, symbolName, moduleName, alias);
|
|
1786
1766
|
continue;
|
|
1787
1767
|
}
|
|
1788
|
-
const variableDeclaration = closestOrSelf(ref,
|
|
1768
|
+
const variableDeclaration = closestOrSelf(ref, ts.isVariableDeclaration);
|
|
1789
1769
|
const variableStatement = variableDeclaration
|
|
1790
|
-
? nodes.closestNode(variableDeclaration,
|
|
1770
|
+
? nodes.closestNode(variableDeclaration, ts.isVariableStatement)
|
|
1791
1771
|
: null;
|
|
1792
1772
|
// If the reference is a variable, we can attempt to import it or copy it over.
|
|
1793
|
-
if (variableDeclaration && variableStatement &&
|
|
1773
|
+
if (variableDeclaration && variableStatement && ts.isIdentifier(variableDeclaration.name)) {
|
|
1794
1774
|
if (isExported(variableStatement)) {
|
|
1795
1775
|
tracker.addImport(targetFile, variableDeclaration.name.text, getRelativeImportPath(targetFile.fileName, ref.getSourceFile().fileName));
|
|
1796
1776
|
}
|
|
@@ -1844,7 +1824,7 @@ function findAllSameFileReferences(rootNode, nodeLookup, referenceResolver) {
|
|
|
1844
1824
|
}
|
|
1845
1825
|
// Keep searching, starting from the closest top-level node. We skip import declarations,
|
|
1846
1826
|
// because we already know about them and they may put the search into an infinite loop.
|
|
1847
|
-
if (!
|
|
1827
|
+
if (!ts.isImportDeclaration(closestTopLevel) &&
|
|
1848
1828
|
isOutsideRange(excludeStart, excludeEnd, closestTopLevel.getStart(), closestTopLevel.getEnd())) {
|
|
1849
1829
|
traversedTopLevelNodes.add(closestTopLevel);
|
|
1850
1830
|
walk(closestTopLevel);
|
|
@@ -1883,11 +1863,11 @@ function referencesToNodeWithinSameFile(node, nodeLookup, excludeStart, excludeE
|
|
|
1883
1863
|
function remapDynamicImports(targetFileName, rootNode) {
|
|
1884
1864
|
let hasChanged = false;
|
|
1885
1865
|
const transformer = (context) => {
|
|
1886
|
-
return (sourceFile) =>
|
|
1887
|
-
if (
|
|
1888
|
-
node.expression.kind ===
|
|
1866
|
+
return (sourceFile) => ts.visitNode(sourceFile, function walk(node) {
|
|
1867
|
+
if (ts.isCallExpression(node) &&
|
|
1868
|
+
node.expression.kind === ts.SyntaxKind.ImportKeyword &&
|
|
1889
1869
|
node.arguments.length > 0 &&
|
|
1890
|
-
|
|
1870
|
+
ts.isStringLiteralLike(node.arguments[0]) &&
|
|
1891
1871
|
node.arguments[0].text.startsWith('.')) {
|
|
1892
1872
|
hasChanged = true;
|
|
1893
1873
|
return context.factory.updateCallExpression(node, node.expression, node.typeArguments, [
|
|
@@ -1895,10 +1875,10 @@ function remapDynamicImports(targetFileName, rootNode) {
|
|
|
1895
1875
|
...node.arguments.slice(1),
|
|
1896
1876
|
]);
|
|
1897
1877
|
}
|
|
1898
|
-
return
|
|
1878
|
+
return ts.visitEachChild(node, walk, context);
|
|
1899
1879
|
});
|
|
1900
1880
|
};
|
|
1901
|
-
const result =
|
|
1881
|
+
const result = ts.transform(rootNode, [transformer]).transformed[0];
|
|
1902
1882
|
return hasChanged ? result : rootNode;
|
|
1903
1883
|
}
|
|
1904
1884
|
/**
|
|
@@ -1906,7 +1886,7 @@ function remapDynamicImports(targetFileName, rootNode) {
|
|
|
1906
1886
|
* @param node Node to be checked.
|
|
1907
1887
|
*/
|
|
1908
1888
|
function isTopLevelStatement(node) {
|
|
1909
|
-
return node.parent != null &&
|
|
1889
|
+
return node.parent != null && ts.isSourceFile(node.parent);
|
|
1910
1890
|
}
|
|
1911
1891
|
/**
|
|
1912
1892
|
* Asserts that a node is an identifier that might be referring to a symbol. This excludes
|
|
@@ -1914,8 +1894,8 @@ function isTopLevelStatement(node) {
|
|
|
1914
1894
|
* @param node Node to be checked.
|
|
1915
1895
|
*/
|
|
1916
1896
|
function isReferenceIdentifier(node) {
|
|
1917
|
-
return (
|
|
1918
|
-
((!
|
|
1897
|
+
return (ts.isIdentifier(node) &&
|
|
1898
|
+
((!ts.isPropertyAssignment(node.parent) && !ts.isParameter(node.parent)) ||
|
|
1919
1899
|
node.parent.name !== node));
|
|
1920
1900
|
}
|
|
1921
1901
|
/**
|
|
@@ -1941,8 +1921,8 @@ function remapRelativeImport(targetFileName, specifier) {
|
|
|
1941
1921
|
* @param node Node to be checked.
|
|
1942
1922
|
*/
|
|
1943
1923
|
function isExported(node) {
|
|
1944
|
-
return
|
|
1945
|
-
? node.modifiers.some((modifier) => modifier.kind ===
|
|
1924
|
+
return ts.canHaveModifiers(node) && node.modifiers
|
|
1925
|
+
? node.modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)
|
|
1946
1926
|
: false;
|
|
1947
1927
|
}
|
|
1948
1928
|
/**
|
|
@@ -1951,11 +1931,11 @@ function isExported(node) {
|
|
|
1951
1931
|
* @param node Node to be checked.
|
|
1952
1932
|
*/
|
|
1953
1933
|
function isExportableDeclaration(node) {
|
|
1954
|
-
return (
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1934
|
+
return (ts.isEnumDeclaration(node) ||
|
|
1935
|
+
ts.isClassDeclaration(node) ||
|
|
1936
|
+
ts.isFunctionDeclaration(node) ||
|
|
1937
|
+
ts.isInterfaceDeclaration(node) ||
|
|
1938
|
+
ts.isTypeAliasDeclaration(node));
|
|
1959
1939
|
}
|
|
1960
1940
|
/**
|
|
1961
1941
|
* Gets the index after the last import in a file. Can be used to insert new code into the file.
|
|
@@ -1964,7 +1944,7 @@ function isExportableDeclaration(node) {
|
|
|
1964
1944
|
function getLastImportEnd(sourceFile) {
|
|
1965
1945
|
let index = 0;
|
|
1966
1946
|
for (const statement of sourceFile.statements) {
|
|
1967
|
-
if (
|
|
1947
|
+
if (ts.isImportDeclaration(statement)) {
|
|
1968
1948
|
index = Math.max(index, statement.getEnd());
|
|
1969
1949
|
}
|
|
1970
1950
|
else {
|
|
@@ -1983,8 +1963,8 @@ function hasImport(program, rootFileNames, moduleName) {
|
|
|
1983
1963
|
continue;
|
|
1984
1964
|
}
|
|
1985
1965
|
for (const statement of sourceFile.statements) {
|
|
1986
|
-
if (
|
|
1987
|
-
|
|
1966
|
+
if (ts.isImportDeclaration(statement) &&
|
|
1967
|
+
ts.isStringLiteralLike(statement.moduleSpecifier) &&
|
|
1988
1968
|
(statement.moduleSpecifier.text === moduleName ||
|
|
1989
1969
|
statement.moduleSpecifier.text.startsWith(deepImportStart))) {
|
|
1990
1970
|
return true;
|
|
@@ -2036,7 +2016,7 @@ function standaloneMigration(tree, tsconfigPath, basePath, pathToMigrate, schema
|
|
|
2036
2016
|
});
|
|
2037
2017
|
const referenceLookupExcludedFiles = /node_modules|\.ngtypecheck\.ts/;
|
|
2038
2018
|
const program = createProgram({ rootNames, host, options, oldProgram });
|
|
2039
|
-
const printer =
|
|
2019
|
+
const printer = ts.createPrinter();
|
|
2040
2020
|
if (fs.existsSync(pathToMigrate) && !fs.statSync(pathToMigrate).isDirectory()) {
|
|
2041
2021
|
throw new schematics.SchematicsException(`Migration path ${pathToMigrate} has to be a directory. Cannot run the standalone migration.`);
|
|
2042
2022
|
}
|