@angular/core 20.0.0-next.0 → 20.0.0-next.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/fesm2022/core.mjs +3307 -4479
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/di.mjs +45 -0
- package/fesm2022/primitives/di.mjs.map +1 -0
- package/fesm2022/primitives/event-dispatch.mjs +3 -590
- package/fesm2022/primitives/event-dispatch.mjs.map +1 -1
- package/fesm2022/primitives/signals.mjs +19 -9
- package/fesm2022/primitives/signals.mjs.map +1 -1
- package/fesm2022/rxjs-interop.mjs +8 -33
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +392 -250
- 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 +14339 -15134
- package/navigation_types.d-u4EOrrdZ.d.ts +121 -0
- package/package.json +11 -1
- package/primitives/di/index.d.ts +91 -0
- package/primitives/event-dispatch/index.d.ts +206 -310
- package/primitives/signals/index.d.ts +159 -196
- package/rxjs-interop/index.d.ts +72 -92
- package/schematics/bundles/{apply_import_manager-0959b78c.js → apply_import_manager-CyRT0UvU.js} +13 -17
- package/schematics/bundles/{checker-cf6f7980.js → checker-DF8ZaFW5.js} +3363 -1289
- package/schematics/bundles/cleanup-unused-imports.js +22 -28
- package/schematics/bundles/{compiler_host-cc1379e9.js → compiler_host-Da636uJ8.js} +20 -24
- package/schematics/bundles/control-flow-migration.js +82 -39
- package/schematics/bundles/{imports-31a38653.js → imports-CIX-JgAN.js} +10 -15
- package/schematics/bundles/{index-42d84d69.js → index-DnkWgagp.js} +56 -60
- package/schematics/bundles/{index-6675d6bc.js → index-vGJcp5M7.js} +5 -5
- package/schematics/bundles/inject-flags.js +181 -0
- package/schematics/bundles/inject-migration.js +122 -128
- package/schematics/bundles/{leading_space-6e7a8ec6.js → leading_space-D9nQ8UQC.js} +2 -2
- package/schematics/bundles/{migrate_ts_type_references-5089e4ef.js → migrate_ts_type_references-DtkOnnv0.js} +113 -120
- package/schematics/bundles/{ng_decorators-6878e227.js → ng_decorators-DznZ5jMl.js} +5 -9
- package/schematics/bundles/{nodes-ffdce442.js → nodes-B16H9JUd.js} +3 -7
- package/schematics/bundles/output-migration.js +40 -46
- package/schematics/bundles/{program-362689f0.js → program-BZk27Ndu.js} +846 -2653
- package/schematics/bundles/{project_paths-7d2daa1e.js → project_paths-Jtbi76Bs.js} +26 -24
- package/schematics/bundles/{project_tsconfig_paths-6c9cde78.js → project_tsconfig_paths-CDVxT6Ov.js} +2 -2
- package/schematics/bundles/{property_name-42030525.js → property_name-BBwFuqMe.js} +4 -8
- package/schematics/bundles/route-lazy-loading.js +36 -42
- package/schematics/bundles/self-closing-tags-migration.js +55 -45
- package/schematics/bundles/signal-input-migration.js +61 -68
- package/schematics/bundles/signal-queries-migration.js +48 -55
- package/schematics/bundles/signals.js +10 -12
- package/schematics/bundles/standalone-migration.js +179 -185
- package/schematics/migrations.json +4 -15
- package/testing/index.d.ts +309 -478
- package/weak_ref.d-ttyj86RV.d.ts +9 -0
- package/schematics/bundles/explicit-standalone-flag.js +0 -184
- package/schematics/bundles/pending-tasks.js +0 -103
- package/schematics/bundles/provide-initializer.js +0 -186
|
@@ -1,34 +1,28 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
/**
|
|
3
|
-
* @license Angular v20.0.0-next.
|
|
4
|
-
* (c) 2010-
|
|
3
|
+
* @license Angular v20.0.0-next.2
|
|
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
|
+
require('./index-vGJcp5M7.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 imports = require('./imports-
|
|
21
|
-
var checker = require('./checker-
|
|
14
|
+
var compiler_host = require('./compiler_host-Da636uJ8.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 imports = require('./imports-CIX-JgAN.js');
|
|
19
|
+
var checker = require('./checker-DF8ZaFW5.js');
|
|
22
20
|
require('os');
|
|
23
|
-
var program = require('./program-
|
|
21
|
+
var program = require('./program-BZk27Ndu.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
27
|
return new program.NgtscProgram(rootNames, options, host, oldProgram);
|
|
34
28
|
}
|
|
@@ -38,7 +32,7 @@ function isReferenceToImport(typeChecker, node, importSpecifier) {
|
|
|
38
32
|
// If this function is called on an identifier (should be most cases), we can quickly rule out
|
|
39
33
|
// non-matches by comparing the identifier's string and the local name of the import specifier
|
|
40
34
|
// which saves us some calls to the type checker.
|
|
41
|
-
if (
|
|
35
|
+
if (ts.isIdentifier(node) && node.text !== importSpecifier.name.text) {
|
|
42
36
|
return false;
|
|
43
37
|
}
|
|
44
38
|
const nodeSymbol = typeChecker.getTypeAtLocation(node).getSymbol();
|
|
@@ -114,7 +108,7 @@ class ReferenceResolver {
|
|
|
114
108
|
const results = new Map();
|
|
115
109
|
for (const symbol of referencedSymbols) {
|
|
116
110
|
for (const ref of symbol.references) {
|
|
117
|
-
if (!ref.isDefinition || symbol.definition.kind ===
|
|
111
|
+
if (!ref.isDefinition || symbol.definition.kind === ts.ScriptElementKind.alias) {
|
|
118
112
|
if (!results.has(ref.fileName)) {
|
|
119
113
|
results.set(ref.fileName, []);
|
|
120
114
|
}
|
|
@@ -152,7 +146,7 @@ class ReferenceResolver {
|
|
|
152
146
|
// the only one being passed in `getDocumentHighlight`, but we check here just in case.
|
|
153
147
|
if (file.fileName === fileName) {
|
|
154
148
|
for (const { textSpan: { start, length }, kind, } of file.highlightSpans) {
|
|
155
|
-
if (kind !==
|
|
149
|
+
if (kind !== ts.HighlightSpanKind.none) {
|
|
156
150
|
results.push([start, start + length]);
|
|
157
151
|
}
|
|
158
152
|
}
|
|
@@ -183,20 +177,20 @@ class ReferenceResolver {
|
|
|
183
177
|
rootFileNames.push(fileName);
|
|
184
178
|
}
|
|
185
179
|
});
|
|
186
|
-
this._languageService =
|
|
180
|
+
this._languageService = ts.createLanguageService({
|
|
187
181
|
getCompilationSettings: () => this._program.getTsProgram().getCompilerOptions(),
|
|
188
182
|
getScriptFileNames: () => rootFileNames,
|
|
189
183
|
// The files won't change so we can return the same version.
|
|
190
184
|
getScriptVersion: () => '0',
|
|
191
185
|
getScriptSnapshot: (path) => {
|
|
192
186
|
const content = this._readFile(path);
|
|
193
|
-
return content ?
|
|
187
|
+
return content ? ts.ScriptSnapshot.fromString(content) : undefined;
|
|
194
188
|
},
|
|
195
189
|
getCurrentDirectory: () => this._basePath,
|
|
196
|
-
getDefaultLibFileName: (options) =>
|
|
190
|
+
getDefaultLibFileName: (options) => ts.getDefaultLibFilePath(options),
|
|
197
191
|
readFile: (path) => this._readFile(path),
|
|
198
192
|
fileExists: (path) => this._host.fileExists(path),
|
|
199
|
-
},
|
|
193
|
+
}, ts.createDocumentRegistry(), ts.LanguageServiceMode.PartialSemantic);
|
|
200
194
|
}
|
|
201
195
|
return this._languageService;
|
|
202
196
|
}
|
|
@@ -240,11 +234,11 @@ function findClassDeclaration(reference, typeChecker) {
|
|
|
240
234
|
return (typeChecker
|
|
241
235
|
.getTypeAtLocation(reference)
|
|
242
236
|
.getSymbol()
|
|
243
|
-
?.declarations?.find(
|
|
237
|
+
?.declarations?.find(ts.isClassDeclaration) || null);
|
|
244
238
|
}
|
|
245
239
|
/** Finds a property with a specific name in an object literal expression. */
|
|
246
240
|
function findLiteralProperty(literal, name) {
|
|
247
|
-
return literal.properties.find((prop) => prop.name &&
|
|
241
|
+
return literal.properties.find((prop) => prop.name && ts.isIdentifier(prop.name) && prop.name.text === name);
|
|
248
242
|
}
|
|
249
243
|
/** Gets a relative path between two files that can be used inside a TypeScript import. */
|
|
250
244
|
function getRelativeImportPath(fromFile, toFile) {
|
|
@@ -282,12 +276,12 @@ function isClassReferenceInAngularModule(node, className, moduleName, typeChecke
|
|
|
282
276
|
const externalName = `@angular/${moduleName}`;
|
|
283
277
|
const internalName = `angular2/rc/packages/${moduleName}`;
|
|
284
278
|
return !!symbol?.declarations?.some((decl) => {
|
|
285
|
-
const closestClass = closestOrSelf(decl,
|
|
279
|
+
const closestClass = closestOrSelf(decl, ts.isClassDeclaration);
|
|
286
280
|
const closestClassFileName = closestClass?.getSourceFile().fileName;
|
|
287
281
|
if (!closestClass ||
|
|
288
282
|
!closestClassFileName ||
|
|
289
283
|
!closestClass.name ||
|
|
290
|
-
!
|
|
284
|
+
!ts.isIdentifier(closestClass.name) ||
|
|
291
285
|
(!closestClassFileName.includes(externalName) && !closestClassFileName.includes(internalName))) {
|
|
292
286
|
return false;
|
|
293
287
|
}
|
|
@@ -313,18 +307,18 @@ function getTestingImports(sourceFile) {
|
|
|
313
307
|
* @param catalystImport Import of Catalyst within the file.
|
|
314
308
|
*/
|
|
315
309
|
function isTestCall(typeChecker, node, testBedImport, catalystImport) {
|
|
316
|
-
const isObjectLiteralCall =
|
|
310
|
+
const isObjectLiteralCall = ts.isCallExpression(node) &&
|
|
317
311
|
node.arguments.length > 0 &&
|
|
318
312
|
// `arguments[0]` is the testing module config.
|
|
319
|
-
|
|
313
|
+
ts.isObjectLiteralExpression(node.arguments[0]);
|
|
320
314
|
const isTestBedCall = isObjectLiteralCall &&
|
|
321
315
|
testBedImport &&
|
|
322
|
-
|
|
316
|
+
ts.isPropertyAccessExpression(node.expression) &&
|
|
323
317
|
node.expression.name.text === 'configureTestingModule' &&
|
|
324
318
|
isReferenceToImport(typeChecker, node.expression.expression, testBedImport);
|
|
325
319
|
const isCatalystCall = isObjectLiteralCall &&
|
|
326
320
|
catalystImport &&
|
|
327
|
-
|
|
321
|
+
ts.isIdentifier(node.expression) &&
|
|
328
322
|
isReferenceToImport(typeChecker, node.expression, catalystImport);
|
|
329
323
|
return !!(isTestBedCall || isCatalystCall);
|
|
330
324
|
}
|
|
@@ -391,9 +385,9 @@ function convertNgModuleDeclarationToStandalone(decl, allDeclarations, tracker,
|
|
|
391
385
|
if (importsToAdd.length > 0) {
|
|
392
386
|
const hasTrailingComma = importsToAdd.length > 2 &&
|
|
393
387
|
!!extractMetadataLiteral(directiveMeta.decorator)?.properties.hasTrailingComma;
|
|
394
|
-
decorator = setPropertyOnAngularDecorator(decorator, 'imports',
|
|
388
|
+
decorator = setPropertyOnAngularDecorator(decorator, 'imports', ts.factory.createArrayLiteralExpression(
|
|
395
389
|
// Create a multi-line array when it has a trailing comma.
|
|
396
|
-
|
|
390
|
+
ts.factory.createNodeArray(importsToAdd, hasTrailingComma), hasTrailingComma));
|
|
397
391
|
}
|
|
398
392
|
}
|
|
399
393
|
tracker.replaceNode(directiveMeta.decorator, decorator);
|
|
@@ -446,13 +440,13 @@ function potentialImportsToExpressions(potentialImports, toFile, tracker, import
|
|
|
446
440
|
if (importLocation.moduleSpecifier) {
|
|
447
441
|
return tracker.addImport(toFile, importLocation.symbolName, importLocation.moduleSpecifier);
|
|
448
442
|
}
|
|
449
|
-
const identifier =
|
|
443
|
+
const identifier = ts.factory.createIdentifier(importLocation.symbolName);
|
|
450
444
|
if (!importLocation.isForwardReference) {
|
|
451
445
|
return identifier;
|
|
452
446
|
}
|
|
453
447
|
const forwardRefExpression = tracker.addImport(toFile, 'forwardRef', '@angular/core');
|
|
454
|
-
const arrowFunction =
|
|
455
|
-
return
|
|
448
|
+
const arrowFunction = ts.factory.createArrowFunction(undefined, undefined, [], undefined, undefined, identifier);
|
|
449
|
+
return ts.factory.createCallExpression(forwardRefExpression, undefined, [arrowFunction]);
|
|
456
450
|
});
|
|
457
451
|
}
|
|
458
452
|
/**
|
|
@@ -487,16 +481,16 @@ function moveDeclarationsToImports(literal, allDeclarations, typeChecker, templa
|
|
|
487
481
|
const declarationsToCopy = [];
|
|
488
482
|
const properties = [];
|
|
489
483
|
const importsProp = findLiteralProperty(literal, 'imports');
|
|
490
|
-
const hasAnyArrayTrailingComma = literal.properties.some((prop) =>
|
|
491
|
-
|
|
484
|
+
const hasAnyArrayTrailingComma = literal.properties.some((prop) => ts.isPropertyAssignment(prop) &&
|
|
485
|
+
ts.isArrayLiteralExpression(prop.initializer) &&
|
|
492
486
|
prop.initializer.elements.hasTrailingComma);
|
|
493
487
|
// Separate the declarations that we want to keep and ones we need to copy into the `imports`.
|
|
494
|
-
if (
|
|
488
|
+
if (ts.isPropertyAssignment(declarationsProp)) {
|
|
495
489
|
// If the declarations are an array, we can analyze it to
|
|
496
490
|
// find any classes from the current migration.
|
|
497
|
-
if (
|
|
491
|
+
if (ts.isArrayLiteralExpression(declarationsProp.initializer)) {
|
|
498
492
|
for (const el of declarationsProp.initializer.elements) {
|
|
499
|
-
if (
|
|
493
|
+
if (ts.isIdentifier(el)) {
|
|
500
494
|
const correspondingClass = findClassDeclaration(el, typeChecker);
|
|
501
495
|
if (!correspondingClass ||
|
|
502
496
|
// Check whether the declaration is either standalone already or is being converted
|
|
@@ -517,12 +511,12 @@ function moveDeclarationsToImports(literal, allDeclarations, typeChecker, templa
|
|
|
517
511
|
}
|
|
518
512
|
else {
|
|
519
513
|
// Otherwise create a spread that will be copied into the `imports`.
|
|
520
|
-
declarationsToCopy.push(
|
|
514
|
+
declarationsToCopy.push(ts.factory.createSpreadElement(declarationsProp.initializer));
|
|
521
515
|
}
|
|
522
516
|
}
|
|
523
517
|
// If there are no `imports`, create them with the declarations we want to copy.
|
|
524
518
|
if (!importsProp && declarationsToCopy.length > 0) {
|
|
525
|
-
properties.push(
|
|
519
|
+
properties.push(ts.factory.createPropertyAssignment('imports', ts.factory.createArrayLiteralExpression(ts.factory.createNodeArray(declarationsToCopy, hasAnyArrayTrailingComma && declarationsToCopy.length > 2))));
|
|
526
520
|
}
|
|
527
521
|
for (const prop of literal.properties) {
|
|
528
522
|
if (!isNamedPropertyAssignment(prop)) {
|
|
@@ -532,10 +526,10 @@ function moveDeclarationsToImports(literal, allDeclarations, typeChecker, templa
|
|
|
532
526
|
// If we have declarations to preserve, update the existing property, otherwise drop it.
|
|
533
527
|
if (prop === declarationsProp) {
|
|
534
528
|
if (declarationsToPreserve.length > 0) {
|
|
535
|
-
const hasTrailingComma =
|
|
529
|
+
const hasTrailingComma = ts.isArrayLiteralExpression(prop.initializer)
|
|
536
530
|
? prop.initializer.elements.hasTrailingComma
|
|
537
531
|
: hasAnyArrayTrailingComma;
|
|
538
|
-
properties.push(
|
|
532
|
+
properties.push(ts.factory.updatePropertyAssignment(prop, prop.name, ts.factory.createArrayLiteralExpression(ts.factory.createNodeArray(declarationsToPreserve, hasTrailingComma && declarationsToPreserve.length > 2))));
|
|
539
533
|
}
|
|
540
534
|
continue;
|
|
541
535
|
}
|
|
@@ -543,27 +537,27 @@ function moveDeclarationsToImports(literal, allDeclarations, typeChecker, templa
|
|
|
543
537
|
// that should be copied, we merge the two arrays.
|
|
544
538
|
if (prop === importsProp && declarationsToCopy.length > 0) {
|
|
545
539
|
let initializer;
|
|
546
|
-
if (
|
|
547
|
-
initializer =
|
|
540
|
+
if (ts.isArrayLiteralExpression(prop.initializer)) {
|
|
541
|
+
initializer = ts.factory.updateArrayLiteralExpression(prop.initializer, ts.factory.createNodeArray([...prop.initializer.elements, ...declarationsToCopy], prop.initializer.elements.hasTrailingComma));
|
|
548
542
|
}
|
|
549
543
|
else {
|
|
550
|
-
initializer =
|
|
544
|
+
initializer = ts.factory.createArrayLiteralExpression(ts.factory.createNodeArray([ts.factory.createSpreadElement(prop.initializer), ...declarationsToCopy],
|
|
551
545
|
// Expect the declarations to be greater than 1 since
|
|
552
546
|
// we have the pre-existing initializer already.
|
|
553
547
|
hasAnyArrayTrailingComma && declarationsToCopy.length > 1));
|
|
554
548
|
}
|
|
555
|
-
properties.push(
|
|
549
|
+
properties.push(ts.factory.updatePropertyAssignment(prop, prop.name, initializer));
|
|
556
550
|
continue;
|
|
557
551
|
}
|
|
558
552
|
// Retain any remaining properties.
|
|
559
553
|
properties.push(prop);
|
|
560
554
|
}
|
|
561
|
-
tracker.replaceNode(literal,
|
|
555
|
+
tracker.replaceNode(literal, ts.factory.updateObjectLiteralExpression(literal, ts.factory.createNodeArray(properties, literal.properties.hasTrailingComma)), ts.EmitHint.Expression);
|
|
562
556
|
}
|
|
563
557
|
/** Sets a decorator node to be standalone. */
|
|
564
558
|
function markDecoratorAsStandalone(node) {
|
|
565
559
|
const metadata = extractMetadataLiteral(node);
|
|
566
|
-
if (metadata === null || !
|
|
560
|
+
if (metadata === null || !ts.isCallExpression(node.expression)) {
|
|
567
561
|
return node;
|
|
568
562
|
}
|
|
569
563
|
const standaloneProp = metadata.properties.find((prop) => {
|
|
@@ -571,14 +565,14 @@ function markDecoratorAsStandalone(node) {
|
|
|
571
565
|
});
|
|
572
566
|
// In v19 standalone is the default so don't do anything if there's no `standalone`
|
|
573
567
|
// property or it's initialized to anything other than `false`.
|
|
574
|
-
if (!standaloneProp || standaloneProp.initializer.kind !==
|
|
568
|
+
if (!standaloneProp || standaloneProp.initializer.kind !== ts.SyntaxKind.FalseKeyword) {
|
|
575
569
|
return node;
|
|
576
570
|
}
|
|
577
571
|
const newProperties = metadata.properties.filter((element) => element !== standaloneProp);
|
|
578
572
|
// Use `createDecorator` instead of `updateDecorator`, because
|
|
579
573
|
// the latter ends up duplicating the node's leading comment.
|
|
580
|
-
return
|
|
581
|
-
|
|
574
|
+
return ts.factory.createDecorator(ts.factory.createCallExpression(node.expression.expression, node.expression.typeArguments, [
|
|
575
|
+
ts.factory.createObjectLiteralExpression(ts.factory.createNodeArray(newProperties, metadata.properties.hasTrailingComma), newProperties.length > 1),
|
|
582
576
|
]));
|
|
583
577
|
}
|
|
584
578
|
/**
|
|
@@ -590,27 +584,27 @@ function markDecoratorAsStandalone(node) {
|
|
|
590
584
|
*/
|
|
591
585
|
function setPropertyOnAngularDecorator(node, name, initializer) {
|
|
592
586
|
// Invalid decorator.
|
|
593
|
-
if (!
|
|
587
|
+
if (!ts.isCallExpression(node.expression) || node.expression.arguments.length > 1) {
|
|
594
588
|
return node;
|
|
595
589
|
}
|
|
596
590
|
let literalProperties;
|
|
597
591
|
let hasTrailingComma = false;
|
|
598
592
|
if (node.expression.arguments.length === 0) {
|
|
599
|
-
literalProperties = [
|
|
593
|
+
literalProperties = [ts.factory.createPropertyAssignment(name, initializer)];
|
|
600
594
|
}
|
|
601
|
-
else if (
|
|
595
|
+
else if (ts.isObjectLiteralExpression(node.expression.arguments[0])) {
|
|
602
596
|
const literal = node.expression.arguments[0];
|
|
603
597
|
const existingProperty = findLiteralProperty(literal, name);
|
|
604
598
|
hasTrailingComma = literal.properties.hasTrailingComma;
|
|
605
|
-
if (existingProperty &&
|
|
599
|
+
if (existingProperty && ts.isPropertyAssignment(existingProperty)) {
|
|
606
600
|
literalProperties = literal.properties.slice();
|
|
607
601
|
literalProperties[literalProperties.indexOf(existingProperty)] =
|
|
608
|
-
|
|
602
|
+
ts.factory.updatePropertyAssignment(existingProperty, existingProperty.name, initializer);
|
|
609
603
|
}
|
|
610
604
|
else {
|
|
611
605
|
literalProperties = [
|
|
612
606
|
...literal.properties,
|
|
613
|
-
|
|
607
|
+
ts.factory.createPropertyAssignment(name, initializer),
|
|
614
608
|
];
|
|
615
609
|
}
|
|
616
610
|
}
|
|
@@ -620,13 +614,13 @@ function setPropertyOnAngularDecorator(node, name, initializer) {
|
|
|
620
614
|
}
|
|
621
615
|
// Use `createDecorator` instead of `updateDecorator`, because
|
|
622
616
|
// the latter ends up duplicating the node's leading comment.
|
|
623
|
-
return
|
|
624
|
-
|
|
617
|
+
return ts.factory.createDecorator(ts.factory.createCallExpression(node.expression.expression, node.expression.typeArguments, [
|
|
618
|
+
ts.factory.createObjectLiteralExpression(ts.factory.createNodeArray(literalProperties, hasTrailingComma), literalProperties.length > 1),
|
|
625
619
|
]));
|
|
626
620
|
}
|
|
627
621
|
/** Checks if a node is a `PropertyAssignment` with a name. */
|
|
628
622
|
function isNamedPropertyAssignment(node) {
|
|
629
|
-
return
|
|
623
|
+
return ts.isPropertyAssignment(node) && node.name && ts.isIdentifier(node.name);
|
|
630
624
|
}
|
|
631
625
|
/**
|
|
632
626
|
* Finds the import from which to bring in a template dependency of a component.
|
|
@@ -663,16 +657,16 @@ function findImportLocation(target, inContext, importMode, typeChecker) {
|
|
|
663
657
|
* but not `declarations: []`.
|
|
664
658
|
*/
|
|
665
659
|
function hasNgModuleMetadataElements(node) {
|
|
666
|
-
return (
|
|
667
|
-
(!
|
|
660
|
+
return (ts.isPropertyAssignment(node) &&
|
|
661
|
+
(!ts.isArrayLiteralExpression(node.initializer) || node.initializer.elements.length > 0));
|
|
668
662
|
}
|
|
669
663
|
/** Finds all modules whose declarations can be migrated. */
|
|
670
664
|
function findNgModuleClassesToMigrate(sourceFile, typeChecker) {
|
|
671
665
|
const modules = [];
|
|
672
666
|
if (imports.getImportSpecifier(sourceFile, '@angular/core', 'NgModule')) {
|
|
673
667
|
sourceFile.forEachChild(function walk(node) {
|
|
674
|
-
if (
|
|
675
|
-
const decorator = ng_decorators.getAngularDecorators(typeChecker,
|
|
668
|
+
if (ts.isClassDeclaration(node)) {
|
|
669
|
+
const decorator = ng_decorators.getAngularDecorators(typeChecker, ts.getDecorators(node) || []).find((current) => current.name === 'NgModule');
|
|
676
670
|
const metadata = decorator ? extractMetadataLiteral(decorator.node) : null;
|
|
677
671
|
if (metadata) {
|
|
678
672
|
const declarations = findLiteralProperty(metadata, 'declarations');
|
|
@@ -696,8 +690,8 @@ function findTestObjectsToMigrate(sourceFile, typeChecker) {
|
|
|
696
690
|
const config = node.arguments[0];
|
|
697
691
|
const declarations = findLiteralProperty(config, 'declarations');
|
|
698
692
|
if (declarations &&
|
|
699
|
-
|
|
700
|
-
|
|
693
|
+
ts.isPropertyAssignment(declarations) &&
|
|
694
|
+
ts.isArrayLiteralExpression(declarations.initializer) &&
|
|
701
695
|
declarations.initializer.elements.length > 0) {
|
|
702
696
|
testObjects.push(config);
|
|
703
697
|
}
|
|
@@ -718,7 +712,7 @@ function findTemplateDependencies(decl, typeChecker) {
|
|
|
718
712
|
const usedPipes = typeChecker.getUsedPipes(decl);
|
|
719
713
|
if (usedDirectives !== null) {
|
|
720
714
|
for (const dir of usedDirectives) {
|
|
721
|
-
if (
|
|
715
|
+
if (ts.isClassDeclaration(dir.ref.node)) {
|
|
722
716
|
results.push(dir.ref);
|
|
723
717
|
}
|
|
724
718
|
}
|
|
@@ -726,7 +720,7 @@ function findTemplateDependencies(decl, typeChecker) {
|
|
|
726
720
|
if (usedPipes !== null) {
|
|
727
721
|
const potentialPipes = typeChecker.getPotentialPipes(decl);
|
|
728
722
|
for (const pipe of potentialPipes) {
|
|
729
|
-
if (
|
|
723
|
+
if (ts.isClassDeclaration(pipe.ref.node) &&
|
|
730
724
|
usedPipes.some((current) => pipe.name === current)) {
|
|
731
725
|
results.push(pipe.ref);
|
|
732
726
|
}
|
|
@@ -752,13 +746,13 @@ function filterNonBootstrappedDeclarations(declarations, ngModule, templateTypeC
|
|
|
752
746
|
}
|
|
753
747
|
// If we can't analyze the `bootstrap` property, we can't safely determine which
|
|
754
748
|
// declarations aren't bootstrapped so we assume that all of them are.
|
|
755
|
-
if (!
|
|
756
|
-
!
|
|
749
|
+
if (!ts.isPropertyAssignment(bootstrapProp) ||
|
|
750
|
+
!ts.isArrayLiteralExpression(bootstrapProp.initializer)) {
|
|
757
751
|
return [];
|
|
758
752
|
}
|
|
759
753
|
const bootstrappedClasses = new Set();
|
|
760
754
|
for (const el of bootstrapProp.initializer.elements) {
|
|
761
|
-
const referencedClass =
|
|
755
|
+
const referencedClass = ts.isIdentifier(el) ? findClassDeclaration(el, typeChecker) : null;
|
|
762
756
|
// If we can resolve an element to a class, we can filter it out,
|
|
763
757
|
// otherwise assume that the array isn't static.
|
|
764
758
|
if (referencedClass) {
|
|
@@ -779,7 +773,7 @@ function extractDeclarationsFromModule(ngModule, templateTypeChecker) {
|
|
|
779
773
|
const metadata = templateTypeChecker.getNgModuleMetadata(ngModule);
|
|
780
774
|
return metadata
|
|
781
775
|
? metadata.declarations
|
|
782
|
-
.filter((decl) =>
|
|
776
|
+
.filter((decl) => ts.isClassDeclaration(decl.node))
|
|
783
777
|
.map((decl) => decl.node)
|
|
784
778
|
: [];
|
|
785
779
|
}
|
|
@@ -795,7 +789,7 @@ function migrateTestDeclarations(testObjects, declarationsOutsideOfTestFiles, tr
|
|
|
795
789
|
const { decorators, componentImports } = analyzeTestingModules(testObjects, typeChecker);
|
|
796
790
|
const allDeclarations = new Set(declarationsOutsideOfTestFiles);
|
|
797
791
|
for (const decorator of decorators) {
|
|
798
|
-
const closestClass = nodes.closestNode(decorator.node,
|
|
792
|
+
const closestClass = nodes.closestNode(decorator.node, ts.isClassDeclaration);
|
|
799
793
|
if (decorator.name === 'Pipe' || decorator.name === 'Directive') {
|
|
800
794
|
tracker.replaceNode(decorator.node, markDecoratorAsStandalone(decorator.node));
|
|
801
795
|
if (closestClass) {
|
|
@@ -811,8 +805,8 @@ function migrateTestDeclarations(testObjects, declarationsOutsideOfTestFiles, tr
|
|
|
811
805
|
if (importsToAdd && importsToAdd.size > 0) {
|
|
812
806
|
const hasTrailingComma = importsToAdd.size > 2 &&
|
|
813
807
|
!!extractMetadataLiteral(decorator.node)?.properties.hasTrailingComma;
|
|
814
|
-
const importsArray =
|
|
815
|
-
tracker.replaceNode(decorator.node, setPropertyOnAngularDecorator(newDecorator, 'imports',
|
|
808
|
+
const importsArray = ts.factory.createNodeArray(Array.from(importsToAdd), hasTrailingComma);
|
|
809
|
+
tracker.replaceNode(decorator.node, setPropertyOnAngularDecorator(newDecorator, 'imports', ts.factory.createArrayLiteralExpression(importsArray)));
|
|
816
810
|
}
|
|
817
811
|
else {
|
|
818
812
|
tracker.replaceNode(decorator.node, newDecorator);
|
|
@@ -841,10 +835,10 @@ function analyzeTestingModules(testObjects, typeChecker) {
|
|
|
841
835
|
const importsProp = findLiteralProperty(obj, 'imports');
|
|
842
836
|
const importElements = importsProp &&
|
|
843
837
|
hasNgModuleMetadataElements(importsProp) &&
|
|
844
|
-
|
|
838
|
+
ts.isArrayLiteralExpression(importsProp.initializer)
|
|
845
839
|
? importsProp.initializer.elements.filter((el) => {
|
|
846
840
|
// Filter out calls since they may be a `ModuleWithProviders`.
|
|
847
|
-
return (!
|
|
841
|
+
return (!ts.isCallExpression(el) &&
|
|
848
842
|
// Also filter out the animations modules since they throw errors if they're imported
|
|
849
843
|
// multiple times and it's common for apps to use the `NoopAnimationsModule` to
|
|
850
844
|
// disable animations in screenshot tests.
|
|
@@ -855,7 +849,7 @@ function analyzeTestingModules(testObjects, typeChecker) {
|
|
|
855
849
|
if (seenDeclarations.has(decl)) {
|
|
856
850
|
continue;
|
|
857
851
|
}
|
|
858
|
-
const [decorator] = ng_decorators.getAngularDecorators(typeChecker,
|
|
852
|
+
const [decorator] = ng_decorators.getAngularDecorators(typeChecker, ts.getDecorators(decl) || []);
|
|
859
853
|
if (decorator) {
|
|
860
854
|
seenDeclarations.add(decl);
|
|
861
855
|
decorators.push(decorator);
|
|
@@ -885,7 +879,7 @@ function extractDeclarationsFromTestObject(obj, typeChecker) {
|
|
|
885
879
|
const declarations = findLiteralProperty(obj, 'declarations');
|
|
886
880
|
if (declarations &&
|
|
887
881
|
hasNgModuleMetadataElements(declarations) &&
|
|
888
|
-
|
|
882
|
+
ts.isArrayLiteralExpression(declarations.initializer)) {
|
|
889
883
|
for (const element of declarations.initializer.elements) {
|
|
890
884
|
const declaration = findClassDeclaration(element, typeChecker);
|
|
891
885
|
// Note that we only migrate classes that are in the same file as the testing module,
|
|
@@ -901,9 +895,9 @@ function extractDeclarationsFromTestObject(obj, typeChecker) {
|
|
|
901
895
|
/** Extracts the metadata object literal from an Angular decorator. */
|
|
902
896
|
function extractMetadataLiteral(decorator) {
|
|
903
897
|
// `arguments[0]` is the metadata object literal.
|
|
904
|
-
return
|
|
898
|
+
return ts.isCallExpression(decorator.expression) &&
|
|
905
899
|
decorator.expression.arguments.length === 1 &&
|
|
906
|
-
|
|
900
|
+
ts.isObjectLiteralExpression(decorator.expression.arguments[0])
|
|
907
901
|
? decorator.expression.arguments[0]
|
|
908
902
|
: null;
|
|
909
903
|
}
|
|
@@ -947,14 +941,14 @@ function pruneNgModules(program, host, basePath, rootFileNames, sourceFiles, pri
|
|
|
947
941
|
const testArrays = new UniqueItemTracker();
|
|
948
942
|
const nodesToRemove = new Set();
|
|
949
943
|
sourceFiles.forEach(function walk(node) {
|
|
950
|
-
if (
|
|
944
|
+
if (ts.isClassDeclaration(node) && canRemoveClass(node, typeChecker)) {
|
|
951
945
|
collectChangeLocations(node, removalLocations, componentImportArrays, testArrays, templateTypeChecker, referenceResolver, program);
|
|
952
946
|
classesToRemove.add(node);
|
|
953
947
|
}
|
|
954
|
-
else if (
|
|
948
|
+
else if (ts.isExportDeclaration(node) &&
|
|
955
949
|
!node.exportClause &&
|
|
956
950
|
node.moduleSpecifier &&
|
|
957
|
-
|
|
951
|
+
ts.isStringLiteralLike(node.moduleSpecifier) &&
|
|
958
952
|
node.moduleSpecifier.text.startsWith('.')) {
|
|
959
953
|
const exportedSourceFile = typeChecker
|
|
960
954
|
.getSymbolAtLocation(node.moduleSpecifier)
|
|
@@ -1021,15 +1015,15 @@ function collectChangeLocations(ngModule, removalLocations, componentImportArray
|
|
|
1021
1015
|
}
|
|
1022
1016
|
}
|
|
1023
1017
|
for (const node of nodes$1) {
|
|
1024
|
-
const closestArray = nodes.closestNode(node,
|
|
1018
|
+
const closestArray = nodes.closestNode(node, ts.isArrayLiteralExpression);
|
|
1025
1019
|
if (closestArray) {
|
|
1026
|
-
const closestAssignment = nodes.closestNode(closestArray,
|
|
1020
|
+
const closestAssignment = nodes.closestNode(closestArray, ts.isPropertyAssignment);
|
|
1027
1021
|
if (closestAssignment && isInImportsArray(closestAssignment, closestArray)) {
|
|
1028
|
-
const closestCall = nodes.closestNode(closestAssignment,
|
|
1022
|
+
const closestCall = nodes.closestNode(closestAssignment, ts.isCallExpression);
|
|
1029
1023
|
if (closestCall) {
|
|
1030
|
-
const closestDecorator = nodes.closestNode(closestCall,
|
|
1024
|
+
const closestDecorator = nodes.closestNode(closestCall, ts.isDecorator);
|
|
1031
1025
|
const closestClass = closestDecorator
|
|
1032
|
-
? nodes.closestNode(closestDecorator,
|
|
1026
|
+
? nodes.closestNode(closestDecorator, ts.isClassDeclaration)
|
|
1033
1027
|
: null;
|
|
1034
1028
|
const directiveMeta = closestClass
|
|
1035
1029
|
? templateTypeChecker.getDirectiveMetadata(closestClass)
|
|
@@ -1054,12 +1048,12 @@ function collectChangeLocations(ngModule, removalLocations, componentImportArray
|
|
|
1054
1048
|
removalLocations.arrays.track(closestArray, node);
|
|
1055
1049
|
continue;
|
|
1056
1050
|
}
|
|
1057
|
-
const closestImport = nodes.closestNode(node,
|
|
1051
|
+
const closestImport = nodes.closestNode(node, ts.isNamedImports);
|
|
1058
1052
|
if (closestImport) {
|
|
1059
1053
|
removalLocations.imports.track(closestImport, node);
|
|
1060
1054
|
continue;
|
|
1061
1055
|
}
|
|
1062
|
-
const closestExport = nodes.closestNode(node,
|
|
1056
|
+
const closestExport = nodes.closestNode(node, ts.isNamedExports);
|
|
1063
1057
|
if (closestExport) {
|
|
1064
1058
|
removalLocations.exports.track(closestExport, node);
|
|
1065
1059
|
continue;
|
|
@@ -1078,7 +1072,7 @@ function collectChangeLocations(ngModule, removalLocations, componentImportArray
|
|
|
1078
1072
|
*/
|
|
1079
1073
|
function replaceInComponentImportsArray(componentImportArrays, classesToRemove, tracker, typeChecker, templateTypeChecker, importRemapper) {
|
|
1080
1074
|
for (const [array, toReplace] of componentImportArrays.getEntries()) {
|
|
1081
|
-
const closestClass = nodes.closestNode(array,
|
|
1075
|
+
const closestClass = nodes.closestNode(array, ts.isClassDeclaration);
|
|
1082
1076
|
if (!closestClass) {
|
|
1083
1077
|
continue;
|
|
1084
1078
|
}
|
|
@@ -1157,7 +1151,7 @@ function replaceModulesInImportsArray(array, replacements, tracker, templateType
|
|
|
1157
1151
|
const newElements = [];
|
|
1158
1152
|
const identifiers = new Set();
|
|
1159
1153
|
for (const element of array.elements) {
|
|
1160
|
-
if (
|
|
1154
|
+
if (ts.isIdentifier(element)) {
|
|
1161
1155
|
identifiers.add(element.text);
|
|
1162
1156
|
}
|
|
1163
1157
|
}
|
|
@@ -1175,12 +1169,12 @@ function replaceModulesInImportsArray(array, replacements, tracker, templateType
|
|
|
1175
1169
|
}
|
|
1176
1170
|
}
|
|
1177
1171
|
potentialImportsToExpressions(potentialImports, array.getSourceFile(), tracker, importRemapper).forEach((expr) => {
|
|
1178
|
-
if (!
|
|
1172
|
+
if (!ts.isIdentifier(expr) || !identifiers.has(expr.text)) {
|
|
1179
1173
|
newElements.push(expr);
|
|
1180
1174
|
}
|
|
1181
1175
|
});
|
|
1182
1176
|
}
|
|
1183
|
-
tracker.replaceNode(array,
|
|
1177
|
+
tracker.replaceNode(array, ts.factory.updateArrayLiteralExpression(array, newElements));
|
|
1184
1178
|
}
|
|
1185
1179
|
/**
|
|
1186
1180
|
* Removes all tracked array references.
|
|
@@ -1190,7 +1184,7 @@ function replaceModulesInImportsArray(array, replacements, tracker, templateType
|
|
|
1190
1184
|
function removeArrayReferences(locations, tracker) {
|
|
1191
1185
|
for (const [array, toRemove] of locations.getEntries()) {
|
|
1192
1186
|
const newElements = filterRemovedElements(array.elements, toRemove);
|
|
1193
|
-
tracker.replaceNode(array,
|
|
1187
|
+
tracker.replaceNode(array, ts.factory.updateArrayLiteralExpression(array, ts.factory.createNodeArray(newElements, array.elements.hasTrailingComma)));
|
|
1194
1188
|
}
|
|
1195
1189
|
}
|
|
1196
1190
|
/**
|
|
@@ -1203,15 +1197,15 @@ function removeImportReferences(locations, tracker) {
|
|
|
1203
1197
|
const newElements = filterRemovedElements(namedImports.elements, toRemove);
|
|
1204
1198
|
// If no imports are left, we can try to drop the entire import.
|
|
1205
1199
|
if (newElements.length === 0) {
|
|
1206
|
-
const importClause = nodes.closestNode(namedImports,
|
|
1200
|
+
const importClause = nodes.closestNode(namedImports, ts.isImportClause);
|
|
1207
1201
|
// If the import clause has a name we can only drop then named imports.
|
|
1208
1202
|
// e.g. `import Foo, {ModuleToRemove} from './foo';` becomes `import Foo from './foo';`.
|
|
1209
1203
|
if (importClause && importClause.name) {
|
|
1210
|
-
tracker.replaceNode(importClause,
|
|
1204
|
+
tracker.replaceNode(importClause, ts.factory.updateImportClause(importClause, importClause.isTypeOnly, importClause.name, undefined));
|
|
1211
1205
|
}
|
|
1212
1206
|
else {
|
|
1213
1207
|
// Otherwise we can drop the entire declaration.
|
|
1214
|
-
const declaration = nodes.closestNode(namedImports,
|
|
1208
|
+
const declaration = nodes.closestNode(namedImports, ts.isImportDeclaration);
|
|
1215
1209
|
if (declaration) {
|
|
1216
1210
|
tracker.removeNode(declaration);
|
|
1217
1211
|
}
|
|
@@ -1219,7 +1213,7 @@ function removeImportReferences(locations, tracker) {
|
|
|
1219
1213
|
}
|
|
1220
1214
|
else {
|
|
1221
1215
|
// Otherwise we just drop the imported symbols and keep the declaration intact.
|
|
1222
|
-
tracker.replaceNode(namedImports,
|
|
1216
|
+
tracker.replaceNode(namedImports, ts.factory.updateNamedImports(namedImports, newElements));
|
|
1223
1217
|
}
|
|
1224
1218
|
}
|
|
1225
1219
|
}
|
|
@@ -1233,14 +1227,14 @@ function removeExportReferences(locations, tracker) {
|
|
|
1233
1227
|
const newElements = filterRemovedElements(namedExports.elements, toRemove);
|
|
1234
1228
|
// If no exports are left, we can drop the entire declaration.
|
|
1235
1229
|
if (newElements.length === 0) {
|
|
1236
|
-
const declaration = nodes.closestNode(namedExports,
|
|
1230
|
+
const declaration = nodes.closestNode(namedExports, ts.isExportDeclaration);
|
|
1237
1231
|
if (declaration) {
|
|
1238
1232
|
tracker.removeNode(declaration);
|
|
1239
1233
|
}
|
|
1240
1234
|
}
|
|
1241
1235
|
else {
|
|
1242
1236
|
// Otherwise we just drop the exported symbols and keep the declaration intact.
|
|
1243
|
-
tracker.replaceNode(namedExports,
|
|
1237
|
+
tracker.replaceNode(namedExports, ts.factory.updateNamedExports(namedExports, newElements));
|
|
1244
1238
|
}
|
|
1245
1239
|
}
|
|
1246
1240
|
}
|
|
@@ -1257,12 +1251,12 @@ function removeExportReferences(locations, tracker) {
|
|
|
1257
1251
|
function canRemoveClass(node, typeChecker) {
|
|
1258
1252
|
const decorator = findNgModuleDecorator(node, typeChecker)?.node;
|
|
1259
1253
|
// We can't remove a declaration if it's not a valid `NgModule`.
|
|
1260
|
-
if (!decorator || !
|
|
1254
|
+
if (!decorator || !ts.isCallExpression(decorator.expression)) {
|
|
1261
1255
|
return false;
|
|
1262
1256
|
}
|
|
1263
1257
|
// Unsupported case, e.g. `@NgModule(SOME_VALUE)`.
|
|
1264
1258
|
if (decorator.expression.arguments.length > 0 &&
|
|
1265
|
-
!
|
|
1259
|
+
!ts.isObjectLiteralExpression(decorator.expression.arguments[0])) {
|
|
1266
1260
|
return false;
|
|
1267
1261
|
}
|
|
1268
1262
|
// We can't remove modules that have class members. We make an exception for an
|
|
@@ -1280,7 +1274,7 @@ function canRemoveClass(node, typeChecker) {
|
|
|
1280
1274
|
// We can't remove the class if at least one import isn't identifier, because it may be a
|
|
1281
1275
|
// `ModuleWithProviders` which is the equivalent of having something in the `providers` array.
|
|
1282
1276
|
for (const dep of imports.initializer.elements) {
|
|
1283
|
-
if (!
|
|
1277
|
+
if (!ts.isIdentifier(dep)) {
|
|
1284
1278
|
return false;
|
|
1285
1279
|
}
|
|
1286
1280
|
const depDeclaration = findClassDeclaration(dep, typeChecker);
|
|
@@ -1316,9 +1310,9 @@ function canRemoveClass(node, typeChecker) {
|
|
|
1316
1310
|
* @param node Node to be checked.
|
|
1317
1311
|
*/
|
|
1318
1312
|
function isNonEmptyNgModuleProperty(node) {
|
|
1319
|
-
return (
|
|
1320
|
-
|
|
1321
|
-
|
|
1313
|
+
return (ts.isPropertyAssignment(node) &&
|
|
1314
|
+
ts.isIdentifier(node.name) &&
|
|
1315
|
+
ts.isArrayLiteralExpression(node.initializer) &&
|
|
1322
1316
|
node.initializer.elements.length > 0);
|
|
1323
1317
|
}
|
|
1324
1318
|
/**
|
|
@@ -1329,12 +1323,12 @@ function isNonEmptyNgModuleProperty(node) {
|
|
|
1329
1323
|
*/
|
|
1330
1324
|
function canRemoveFile(sourceFile, nodesToBeRemoved) {
|
|
1331
1325
|
for (const node of sourceFile.statements) {
|
|
1332
|
-
if (
|
|
1326
|
+
if (ts.isImportDeclaration(node) || nodesToBeRemoved.has(node)) {
|
|
1333
1327
|
continue;
|
|
1334
1328
|
}
|
|
1335
|
-
if (
|
|
1336
|
-
(
|
|
1337
|
-
|
|
1329
|
+
if (ts.isExportDeclaration(node) ||
|
|
1330
|
+
(ts.canHaveModifiers(node) &&
|
|
1331
|
+
ts.getModifiers(node)?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword))) {
|
|
1338
1332
|
return false;
|
|
1339
1333
|
}
|
|
1340
1334
|
}
|
|
@@ -1371,7 +1365,7 @@ function filterRemovedElements(elements, toRemove) {
|
|
|
1371
1365
|
}
|
|
1372
1366
|
/** Returns whether a node as an empty constructor. */
|
|
1373
1367
|
function isEmptyConstructor(node) {
|
|
1374
|
-
return (
|
|
1368
|
+
return (ts.isConstructorDeclaration(node) &&
|
|
1375
1369
|
node.parameters.length === 0 &&
|
|
1376
1370
|
(node.body == null || node.body.statements.length === 0));
|
|
1377
1371
|
}
|
|
@@ -1392,7 +1386,7 @@ function addRemovalTodos(nodes, tracker) {
|
|
|
1392
1386
|
}
|
|
1393
1387
|
/** Finds the `NgModule` decorator in a class, if it exists. */
|
|
1394
1388
|
function findNgModuleDecorator(node, typeChecker) {
|
|
1395
|
-
const decorators = ng_decorators.getAngularDecorators(typeChecker,
|
|
1389
|
+
const decorators = ng_decorators.getAngularDecorators(typeChecker, ts.getDecorators(node) || []);
|
|
1396
1390
|
return decorators.find((decorator) => decorator.name === 'NgModule') || null;
|
|
1397
1391
|
}
|
|
1398
1392
|
/**
|
|
@@ -1402,7 +1396,7 @@ function findNgModuleDecorator(node, typeChecker) {
|
|
|
1402
1396
|
*/
|
|
1403
1397
|
function isInImportsArray(closestAssignment, closestArray) {
|
|
1404
1398
|
return (closestAssignment.initializer === closestArray &&
|
|
1405
|
-
(
|
|
1399
|
+
(ts.isIdentifier(closestAssignment.name) || ts.isStringLiteralLike(closestAssignment.name)) &&
|
|
1406
1400
|
closestAssignment.name.text === 'imports');
|
|
1407
1401
|
}
|
|
1408
1402
|
|
|
@@ -1428,8 +1422,8 @@ function toStandaloneBootstrap(program, host, basePath, rootFileNames, sourceFil
|
|
|
1428
1422
|
: null;
|
|
1429
1423
|
for (const sourceFile of sourceFiles) {
|
|
1430
1424
|
sourceFile.forEachChild(function walk(node) {
|
|
1431
|
-
if (
|
|
1432
|
-
|
|
1425
|
+
if (ts.isCallExpression(node) &&
|
|
1426
|
+
ts.isPropertyAccessExpression(node.expression) &&
|
|
1433
1427
|
node.expression.name.text === 'bootstrapModule' &&
|
|
1434
1428
|
isClassReferenceInAngularModule(node.expression, 'PlatformRef', 'core', typeChecker)) {
|
|
1435
1429
|
const call = analyzeBootstrapCall(node, typeChecker, templateTypeChecker);
|
|
@@ -1461,30 +1455,30 @@ function toStandaloneBootstrap(program, host, basePath, rootFileNames, sourceFil
|
|
|
1461
1455
|
* @param templateTypeChecker
|
|
1462
1456
|
*/
|
|
1463
1457
|
function analyzeBootstrapCall(call, typeChecker, templateTypeChecker) {
|
|
1464
|
-
if (call.arguments.length === 0 || !
|
|
1458
|
+
if (call.arguments.length === 0 || !ts.isIdentifier(call.arguments[0])) {
|
|
1465
1459
|
return null;
|
|
1466
1460
|
}
|
|
1467
1461
|
const declaration = findClassDeclaration(call.arguments[0], typeChecker);
|
|
1468
1462
|
if (!declaration) {
|
|
1469
1463
|
return null;
|
|
1470
1464
|
}
|
|
1471
|
-
const decorator = ng_decorators.getAngularDecorators(typeChecker,
|
|
1465
|
+
const decorator = ng_decorators.getAngularDecorators(typeChecker, ts.getDecorators(declaration) || []).find((decorator) => decorator.name === 'NgModule');
|
|
1472
1466
|
if (!decorator ||
|
|
1473
1467
|
decorator.node.expression.arguments.length === 0 ||
|
|
1474
|
-
!
|
|
1468
|
+
!ts.isObjectLiteralExpression(decorator.node.expression.arguments[0])) {
|
|
1475
1469
|
return null;
|
|
1476
1470
|
}
|
|
1477
1471
|
const metadata = decorator.node.expression.arguments[0];
|
|
1478
1472
|
const bootstrapProp = findLiteralProperty(metadata, 'bootstrap');
|
|
1479
1473
|
if (!bootstrapProp ||
|
|
1480
|
-
!
|
|
1481
|
-
!
|
|
1474
|
+
!ts.isPropertyAssignment(bootstrapProp) ||
|
|
1475
|
+
!ts.isArrayLiteralExpression(bootstrapProp.initializer) ||
|
|
1482
1476
|
bootstrapProp.initializer.elements.length === 0 ||
|
|
1483
|
-
!
|
|
1477
|
+
!ts.isIdentifier(bootstrapProp.initializer.elements[0])) {
|
|
1484
1478
|
return null;
|
|
1485
1479
|
}
|
|
1486
1480
|
const component = findClassDeclaration(bootstrapProp.initializer.elements[0], typeChecker);
|
|
1487
|
-
if (component && component.name &&
|
|
1481
|
+
if (component && component.name && ts.isIdentifier(component.name)) {
|
|
1488
1482
|
return {
|
|
1489
1483
|
module: declaration,
|
|
1490
1484
|
metadata,
|
|
@@ -1518,23 +1512,23 @@ function migrateBootstrapCall(analysis, tracker, additionalProviders, referenceR
|
|
|
1518
1512
|
// If the pruning is left for some reason, the user will still have an actionable TODO.
|
|
1519
1513
|
tracker.insertText(moduleSourceFile, analysis.metadata.getStart(), '/* TODO(standalone-migration): clean up removed NgModule class manually. \n');
|
|
1520
1514
|
tracker.insertText(moduleSourceFile, analysis.metadata.getEnd(), ' */');
|
|
1521
|
-
if (providers &&
|
|
1515
|
+
if (providers && ts.isPropertyAssignment(providers)) {
|
|
1522
1516
|
nodeLookup = nodeLookup || getNodeLookup(moduleSourceFile);
|
|
1523
|
-
if (
|
|
1517
|
+
if (ts.isArrayLiteralExpression(providers.initializer)) {
|
|
1524
1518
|
providersInNewCall.push(...providers.initializer.elements);
|
|
1525
1519
|
}
|
|
1526
1520
|
else {
|
|
1527
|
-
providersInNewCall.push(
|
|
1521
|
+
providersInNewCall.push(ts.factory.createSpreadElement(providers.initializer));
|
|
1528
1522
|
}
|
|
1529
1523
|
addNodesToCopy(sourceFile, providers, nodeLookup, tracker, nodesToCopy, referenceResolver);
|
|
1530
1524
|
}
|
|
1531
|
-
if (imports &&
|
|
1525
|
+
if (imports && ts.isPropertyAssignment(imports)) {
|
|
1532
1526
|
nodeLookup = nodeLookup || getNodeLookup(moduleSourceFile);
|
|
1533
1527
|
migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, moduleImportsInNewCall, providersInNewCall, tracker, nodesToCopy, referenceResolver, typeChecker);
|
|
1534
1528
|
}
|
|
1535
1529
|
if (additionalProviders) {
|
|
1536
1530
|
additionalProviders.forEach((moduleSpecifier, name) => {
|
|
1537
|
-
providersInNewCall.push(
|
|
1531
|
+
providersInNewCall.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, name, moduleSpecifier), undefined, undefined));
|
|
1538
1532
|
});
|
|
1539
1533
|
}
|
|
1540
1534
|
if (nodesToCopy.size > 0) {
|
|
@@ -1547,7 +1541,7 @@ function migrateBootstrapCall(analysis, tracker, additionalProviders, referenceR
|
|
|
1547
1541
|
text += transformedNode.getText() + '\n';
|
|
1548
1542
|
}
|
|
1549
1543
|
else {
|
|
1550
|
-
text += printer.printNode(
|
|
1544
|
+
text += printer.printNode(ts.EmitHint.Unspecified, transformedNode, node.getSourceFile());
|
|
1551
1545
|
}
|
|
1552
1546
|
});
|
|
1553
1547
|
text += '\n';
|
|
@@ -1571,15 +1565,15 @@ function replaceBootstrapCallExpression(analysis, providers, modules, tracker) {
|
|
|
1571
1565
|
const combinedProviders = [];
|
|
1572
1566
|
if (modules.length > 0) {
|
|
1573
1567
|
const importProvidersExpression = tracker.addImport(sourceFile, 'importProvidersFrom', '@angular/core');
|
|
1574
|
-
combinedProviders.push(
|
|
1568
|
+
combinedProviders.push(ts.factory.createCallExpression(importProvidersExpression, [], modules));
|
|
1575
1569
|
}
|
|
1576
1570
|
// Push the providers after `importProvidersFrom` call for better readability.
|
|
1577
1571
|
combinedProviders.push(...providers);
|
|
1578
|
-
const providersArray =
|
|
1579
|
-
const initializer = remapDynamicImports(sourceFile.fileName,
|
|
1580
|
-
args.push(
|
|
1572
|
+
const providersArray = ts.factory.createNodeArray(combinedProviders, analysis.metadata.properties.hasTrailingComma && combinedProviders.length > 2);
|
|
1573
|
+
const initializer = remapDynamicImports(sourceFile.fileName, ts.factory.createArrayLiteralExpression(providersArray, combinedProviders.length > 1));
|
|
1574
|
+
args.push(ts.factory.createObjectLiteralExpression([ts.factory.createPropertyAssignment('providers', initializer)], true));
|
|
1581
1575
|
}
|
|
1582
|
-
tracker.replaceNode(analysis.call,
|
|
1576
|
+
tracker.replaceNode(analysis.call, ts.factory.createCallExpression(bootstrapExpression, [], args),
|
|
1583
1577
|
// Note: it's important to pass in the source file that the nodes originated from!
|
|
1584
1578
|
// Otherwise TS won't print out literals inside of the providers that we're copying
|
|
1585
1579
|
// over from the module file.
|
|
@@ -1599,14 +1593,14 @@ function replaceBootstrapCallExpression(analysis, providers, modules, tracker) {
|
|
|
1599
1593
|
* @param typeChecker
|
|
1600
1594
|
*/
|
|
1601
1595
|
function migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, importsForNewCall, providersInNewCall, tracker, nodesToCopy, referenceResolver, typeChecker) {
|
|
1602
|
-
if (!
|
|
1596
|
+
if (!ts.isArrayLiteralExpression(imports.initializer)) {
|
|
1603
1597
|
importsForNewCall.push(imports.initializer);
|
|
1604
1598
|
return;
|
|
1605
1599
|
}
|
|
1606
1600
|
for (const element of imports.initializer.elements) {
|
|
1607
1601
|
// If the reference is to a `RouterModule.forRoot` call, we can try to migrate it.
|
|
1608
|
-
if (
|
|
1609
|
-
|
|
1602
|
+
if (ts.isCallExpression(element) &&
|
|
1603
|
+
ts.isPropertyAccessExpression(element.expression) &&
|
|
1610
1604
|
element.arguments.length > 0 &&
|
|
1611
1605
|
element.expression.name.text === 'forRoot' &&
|
|
1612
1606
|
isClassReferenceInAngularModule(element.expression.expression, 'RouterModule', 'router', typeChecker)) {
|
|
@@ -1615,7 +1609,7 @@ function migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, imports
|
|
|
1615
1609
|
// If the features come back as null, it means that the router
|
|
1616
1610
|
// has a configuration that can't be migrated automatically.
|
|
1617
1611
|
if (features !== null) {
|
|
1618
|
-
providersInNewCall.push(
|
|
1612
|
+
providersInNewCall.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, 'provideRouter', '@angular/router'), [], [element.arguments[0], ...features]));
|
|
1619
1613
|
addNodesToCopy(sourceFile, element.arguments[0], nodeLookup, tracker, nodesToCopy, referenceResolver);
|
|
1620
1614
|
if (options) {
|
|
1621
1615
|
addNodesToCopy(sourceFile, options, nodeLookup, tracker, nodesToCopy, referenceResolver);
|
|
@@ -1623,17 +1617,17 @@ function migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, imports
|
|
|
1623
1617
|
continue;
|
|
1624
1618
|
}
|
|
1625
1619
|
}
|
|
1626
|
-
if (
|
|
1620
|
+
if (ts.isIdentifier(element)) {
|
|
1627
1621
|
// `BrowserAnimationsModule` can be replaced with `provideAnimations`.
|
|
1628
1622
|
const animationsModule = 'platform-browser/animations';
|
|
1629
1623
|
const animationsImport = `@angular/${animationsModule}`;
|
|
1630
1624
|
if (isClassReferenceInAngularModule(element, 'BrowserAnimationsModule', animationsModule, typeChecker)) {
|
|
1631
|
-
providersInNewCall.push(
|
|
1625
|
+
providersInNewCall.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, 'provideAnimations', animationsImport), [], []));
|
|
1632
1626
|
continue;
|
|
1633
1627
|
}
|
|
1634
1628
|
// `NoopAnimationsModule` can be replaced with `provideNoopAnimations`.
|
|
1635
1629
|
if (isClassReferenceInAngularModule(element, 'NoopAnimationsModule', animationsModule, typeChecker)) {
|
|
1636
|
-
providersInNewCall.push(
|
|
1630
|
+
providersInNewCall.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, 'provideNoopAnimations', animationsImport), [], []));
|
|
1637
1631
|
continue;
|
|
1638
1632
|
}
|
|
1639
1633
|
// `HttpClientModule` can be replaced with `provideHttpClient()`.
|
|
@@ -1643,21 +1637,21 @@ function migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, imports
|
|
|
1643
1637
|
const callArgs = [
|
|
1644
1638
|
// we add `withInterceptorsFromDi()` to the call to ensure that class-based interceptors
|
|
1645
1639
|
// still work
|
|
1646
|
-
|
|
1640
|
+
ts.factory.createCallExpression(tracker.addImport(sourceFile, 'withInterceptorsFromDi', httpClientImport), [], []),
|
|
1647
1641
|
];
|
|
1648
|
-
providersInNewCall.push(
|
|
1642
|
+
providersInNewCall.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, 'provideHttpClient', httpClientImport), [], callArgs));
|
|
1649
1643
|
continue;
|
|
1650
1644
|
}
|
|
1651
1645
|
}
|
|
1652
1646
|
const target =
|
|
1653
1647
|
// If it's a call, it'll likely be a `ModuleWithProviders`
|
|
1654
1648
|
// expression so the target is going to be call's expression.
|
|
1655
|
-
|
|
1649
|
+
ts.isCallExpression(element) && ts.isPropertyAccessExpression(element.expression)
|
|
1656
1650
|
? element.expression.expression
|
|
1657
1651
|
: element;
|
|
1658
1652
|
const classDeclaration = findClassDeclaration(target, typeChecker);
|
|
1659
1653
|
const decorators = classDeclaration
|
|
1660
|
-
? ng_decorators.getAngularDecorators(typeChecker,
|
|
1654
|
+
? ng_decorators.getAngularDecorators(typeChecker, ts.getDecorators(classDeclaration) || [])
|
|
1661
1655
|
: undefined;
|
|
1662
1656
|
if (!decorators ||
|
|
1663
1657
|
decorators.length === 0 ||
|
|
@@ -1677,7 +1671,7 @@ function migrateImportsForBootstrapCall(sourceFile, imports, nodeLookup, imports
|
|
|
1677
1671
|
*/
|
|
1678
1672
|
function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
1679
1673
|
// Options that aren't a static object literal can't be migrated.
|
|
1680
|
-
if (!
|
|
1674
|
+
if (!ts.isObjectLiteralExpression(options)) {
|
|
1681
1675
|
return null;
|
|
1682
1676
|
}
|
|
1683
1677
|
const featureExpressions = [];
|
|
@@ -1686,8 +1680,8 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1686
1680
|
const features = new UniqueItemTracker();
|
|
1687
1681
|
for (const prop of options.properties) {
|
|
1688
1682
|
// We can't migrate options that we can't easily analyze.
|
|
1689
|
-
if (!
|
|
1690
|
-
(!
|
|
1683
|
+
if (!ts.isPropertyAssignment(prop) ||
|
|
1684
|
+
(!ts.isIdentifier(prop.name) && !ts.isStringLiteralLike(prop.name))) {
|
|
1691
1685
|
return null;
|
|
1692
1686
|
}
|
|
1693
1687
|
switch (prop.name.text) {
|
|
@@ -1697,7 +1691,7 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1697
1691
|
break;
|
|
1698
1692
|
// `enableTracing: true` maps to the `withDebugTracing` feature.
|
|
1699
1693
|
case 'enableTracing':
|
|
1700
|
-
if (prop.initializer.kind ===
|
|
1694
|
+
if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) {
|
|
1701
1695
|
features.track('withDebugTracing', null);
|
|
1702
1696
|
}
|
|
1703
1697
|
break;
|
|
@@ -1705,7 +1699,7 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1705
1699
|
// `withEnabledBlockingInitialNavigation` feature, while `initialNavigation: 'disabled'` maps
|
|
1706
1700
|
// to the `withDisabledInitialNavigation` feature.
|
|
1707
1701
|
case 'initialNavigation':
|
|
1708
|
-
if (!
|
|
1702
|
+
if (!ts.isStringLiteralLike(prop.initializer)) {
|
|
1709
1703
|
return null;
|
|
1710
1704
|
}
|
|
1711
1705
|
if (prop.initializer.text === 'enabledBlocking' || prop.initializer.text === 'enabled') {
|
|
@@ -1717,7 +1711,7 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1717
1711
|
break;
|
|
1718
1712
|
// `useHash: true` maps to the `withHashLocation` feature.
|
|
1719
1713
|
case 'useHash':
|
|
1720
|
-
if (prop.initializer.kind ===
|
|
1714
|
+
if (prop.initializer.kind === ts.SyntaxKind.TrueKeyword) {
|
|
1721
1715
|
features.track('withHashLocation', null);
|
|
1722
1716
|
}
|
|
1723
1717
|
break;
|
|
@@ -1738,10 +1732,10 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1738
1732
|
}
|
|
1739
1733
|
}
|
|
1740
1734
|
if (inMemoryScrollingOptions.length > 0) {
|
|
1741
|
-
features.track('withInMemoryScrolling',
|
|
1735
|
+
features.track('withInMemoryScrolling', ts.factory.createObjectLiteralExpression(inMemoryScrollingOptions));
|
|
1742
1736
|
}
|
|
1743
1737
|
if (configOptions.length > 0) {
|
|
1744
|
-
features.track('withRouterConfig',
|
|
1738
|
+
features.track('withRouterConfig', ts.factory.createObjectLiteralExpression(configOptions));
|
|
1745
1739
|
}
|
|
1746
1740
|
for (const [feature, featureArgs] of features.getEntries()) {
|
|
1747
1741
|
const callArgs = [];
|
|
@@ -1750,7 +1744,7 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1750
1744
|
callArgs.push(arg);
|
|
1751
1745
|
}
|
|
1752
1746
|
});
|
|
1753
|
-
featureExpressions.push(
|
|
1747
|
+
featureExpressions.push(ts.factory.createCallExpression(tracker.addImport(sourceFile, feature, '@angular/router'), [], callArgs));
|
|
1754
1748
|
}
|
|
1755
1749
|
return featureExpressions;
|
|
1756
1750
|
}
|
|
@@ -1767,14 +1761,14 @@ function getRouterModuleForRootFeatures(sourceFile, options, tracker) {
|
|
|
1767
1761
|
function addNodesToCopy(targetFile, rootNode, nodeLookup, tracker, nodesToCopy, referenceResolver) {
|
|
1768
1762
|
const refs = findAllSameFileReferences(rootNode, nodeLookup, referenceResolver);
|
|
1769
1763
|
for (const ref of refs) {
|
|
1770
|
-
const importSpecifier = closestOrSelf(ref,
|
|
1764
|
+
const importSpecifier = closestOrSelf(ref, ts.isImportSpecifier);
|
|
1771
1765
|
const importDeclaration = importSpecifier
|
|
1772
|
-
? nodes.closestNode(importSpecifier,
|
|
1766
|
+
? nodes.closestNode(importSpecifier, ts.isImportDeclaration)
|
|
1773
1767
|
: null;
|
|
1774
1768
|
// If the reference is in an import, we need to add an import to the main file.
|
|
1775
1769
|
if (importDeclaration &&
|
|
1776
1770
|
importSpecifier &&
|
|
1777
|
-
|
|
1771
|
+
ts.isStringLiteralLike(importDeclaration.moduleSpecifier)) {
|
|
1778
1772
|
const moduleName = importDeclaration.moduleSpecifier.text.startsWith('.')
|
|
1779
1773
|
? remapRelativeImport(targetFile.fileName, importDeclaration.moduleSpecifier)
|
|
1780
1774
|
: importDeclaration.moduleSpecifier.text;
|
|
@@ -1785,12 +1779,12 @@ function addNodesToCopy(targetFile, rootNode, nodeLookup, tracker, nodesToCopy,
|
|
|
1785
1779
|
tracker.addImport(targetFile, symbolName, moduleName, alias);
|
|
1786
1780
|
continue;
|
|
1787
1781
|
}
|
|
1788
|
-
const variableDeclaration = closestOrSelf(ref,
|
|
1782
|
+
const variableDeclaration = closestOrSelf(ref, ts.isVariableDeclaration);
|
|
1789
1783
|
const variableStatement = variableDeclaration
|
|
1790
|
-
? nodes.closestNode(variableDeclaration,
|
|
1784
|
+
? nodes.closestNode(variableDeclaration, ts.isVariableStatement)
|
|
1791
1785
|
: null;
|
|
1792
1786
|
// If the reference is a variable, we can attempt to import it or copy it over.
|
|
1793
|
-
if (variableDeclaration && variableStatement &&
|
|
1787
|
+
if (variableDeclaration && variableStatement && ts.isIdentifier(variableDeclaration.name)) {
|
|
1794
1788
|
if (isExported(variableStatement)) {
|
|
1795
1789
|
tracker.addImport(targetFile, variableDeclaration.name.text, getRelativeImportPath(targetFile.fileName, ref.getSourceFile().fileName));
|
|
1796
1790
|
}
|
|
@@ -1844,7 +1838,7 @@ function findAllSameFileReferences(rootNode, nodeLookup, referenceResolver) {
|
|
|
1844
1838
|
}
|
|
1845
1839
|
// Keep searching, starting from the closest top-level node. We skip import declarations,
|
|
1846
1840
|
// because we already know about them and they may put the search into an infinite loop.
|
|
1847
|
-
if (!
|
|
1841
|
+
if (!ts.isImportDeclaration(closestTopLevel) &&
|
|
1848
1842
|
isOutsideRange(excludeStart, excludeEnd, closestTopLevel.getStart(), closestTopLevel.getEnd())) {
|
|
1849
1843
|
traversedTopLevelNodes.add(closestTopLevel);
|
|
1850
1844
|
walk(closestTopLevel);
|
|
@@ -1883,11 +1877,11 @@ function referencesToNodeWithinSameFile(node, nodeLookup, excludeStart, excludeE
|
|
|
1883
1877
|
function remapDynamicImports(targetFileName, rootNode) {
|
|
1884
1878
|
let hasChanged = false;
|
|
1885
1879
|
const transformer = (context) => {
|
|
1886
|
-
return (sourceFile) =>
|
|
1887
|
-
if (
|
|
1888
|
-
node.expression.kind ===
|
|
1880
|
+
return (sourceFile) => ts.visitNode(sourceFile, function walk(node) {
|
|
1881
|
+
if (ts.isCallExpression(node) &&
|
|
1882
|
+
node.expression.kind === ts.SyntaxKind.ImportKeyword &&
|
|
1889
1883
|
node.arguments.length > 0 &&
|
|
1890
|
-
|
|
1884
|
+
ts.isStringLiteralLike(node.arguments[0]) &&
|
|
1891
1885
|
node.arguments[0].text.startsWith('.')) {
|
|
1892
1886
|
hasChanged = true;
|
|
1893
1887
|
return context.factory.updateCallExpression(node, node.expression, node.typeArguments, [
|
|
@@ -1895,10 +1889,10 @@ function remapDynamicImports(targetFileName, rootNode) {
|
|
|
1895
1889
|
...node.arguments.slice(1),
|
|
1896
1890
|
]);
|
|
1897
1891
|
}
|
|
1898
|
-
return
|
|
1892
|
+
return ts.visitEachChild(node, walk, context);
|
|
1899
1893
|
});
|
|
1900
1894
|
};
|
|
1901
|
-
const result =
|
|
1895
|
+
const result = ts.transform(rootNode, [transformer]).transformed[0];
|
|
1902
1896
|
return hasChanged ? result : rootNode;
|
|
1903
1897
|
}
|
|
1904
1898
|
/**
|
|
@@ -1906,7 +1900,7 @@ function remapDynamicImports(targetFileName, rootNode) {
|
|
|
1906
1900
|
* @param node Node to be checked.
|
|
1907
1901
|
*/
|
|
1908
1902
|
function isTopLevelStatement(node) {
|
|
1909
|
-
return node.parent != null &&
|
|
1903
|
+
return node.parent != null && ts.isSourceFile(node.parent);
|
|
1910
1904
|
}
|
|
1911
1905
|
/**
|
|
1912
1906
|
* Asserts that a node is an identifier that might be referring to a symbol. This excludes
|
|
@@ -1914,8 +1908,8 @@ function isTopLevelStatement(node) {
|
|
|
1914
1908
|
* @param node Node to be checked.
|
|
1915
1909
|
*/
|
|
1916
1910
|
function isReferenceIdentifier(node) {
|
|
1917
|
-
return (
|
|
1918
|
-
((!
|
|
1911
|
+
return (ts.isIdentifier(node) &&
|
|
1912
|
+
((!ts.isPropertyAssignment(node.parent) && !ts.isParameter(node.parent)) ||
|
|
1919
1913
|
node.parent.name !== node));
|
|
1920
1914
|
}
|
|
1921
1915
|
/**
|
|
@@ -1941,8 +1935,8 @@ function remapRelativeImport(targetFileName, specifier) {
|
|
|
1941
1935
|
* @param node Node to be checked.
|
|
1942
1936
|
*/
|
|
1943
1937
|
function isExported(node) {
|
|
1944
|
-
return
|
|
1945
|
-
? node.modifiers.some((modifier) => modifier.kind ===
|
|
1938
|
+
return ts.canHaveModifiers(node) && node.modifiers
|
|
1939
|
+
? node.modifiers.some((modifier) => modifier.kind === ts.SyntaxKind.ExportKeyword)
|
|
1946
1940
|
: false;
|
|
1947
1941
|
}
|
|
1948
1942
|
/**
|
|
@@ -1951,11 +1945,11 @@ function isExported(node) {
|
|
|
1951
1945
|
* @param node Node to be checked.
|
|
1952
1946
|
*/
|
|
1953
1947
|
function isExportableDeclaration(node) {
|
|
1954
|
-
return (
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1948
|
+
return (ts.isEnumDeclaration(node) ||
|
|
1949
|
+
ts.isClassDeclaration(node) ||
|
|
1950
|
+
ts.isFunctionDeclaration(node) ||
|
|
1951
|
+
ts.isInterfaceDeclaration(node) ||
|
|
1952
|
+
ts.isTypeAliasDeclaration(node));
|
|
1959
1953
|
}
|
|
1960
1954
|
/**
|
|
1961
1955
|
* Gets the index after the last import in a file. Can be used to insert new code into the file.
|
|
@@ -1964,7 +1958,7 @@ function isExportableDeclaration(node) {
|
|
|
1964
1958
|
function getLastImportEnd(sourceFile) {
|
|
1965
1959
|
let index = 0;
|
|
1966
1960
|
for (const statement of sourceFile.statements) {
|
|
1967
|
-
if (
|
|
1961
|
+
if (ts.isImportDeclaration(statement)) {
|
|
1968
1962
|
index = Math.max(index, statement.getEnd());
|
|
1969
1963
|
}
|
|
1970
1964
|
else {
|
|
@@ -1983,8 +1977,8 @@ function hasImport(program, rootFileNames, moduleName) {
|
|
|
1983
1977
|
continue;
|
|
1984
1978
|
}
|
|
1985
1979
|
for (const statement of sourceFile.statements) {
|
|
1986
|
-
if (
|
|
1987
|
-
|
|
1980
|
+
if (ts.isImportDeclaration(statement) &&
|
|
1981
|
+
ts.isStringLiteralLike(statement.moduleSpecifier) &&
|
|
1988
1982
|
(statement.moduleSpecifier.text === moduleName ||
|
|
1989
1983
|
statement.moduleSpecifier.text.startsWith(deepImportStart))) {
|
|
1990
1984
|
return true;
|
|
@@ -2036,7 +2030,7 @@ function standaloneMigration(tree, tsconfigPath, basePath, pathToMigrate, schema
|
|
|
2036
2030
|
});
|
|
2037
2031
|
const referenceLookupExcludedFiles = /node_modules|\.ngtypecheck\.ts/;
|
|
2038
2032
|
const program = createProgram({ rootNames, host, options, oldProgram });
|
|
2039
|
-
const printer =
|
|
2033
|
+
const printer = ts.createPrinter();
|
|
2040
2034
|
if (fs.existsSync(pathToMigrate) && !fs.statSync(pathToMigrate).isDirectory()) {
|
|
2041
2035
|
throw new schematics.SchematicsException(`Migration path ${pathToMigrate} has to be a directory. Cannot run the standalone migration.`);
|
|
2042
2036
|
}
|