@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,36 +1,30 @@
|
|
|
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
|
-
var project_tsconfig_paths = require('./project_tsconfig_paths-
|
|
13
|
-
var project_paths = require('./project_paths-
|
|
10
|
+
var project_tsconfig_paths = require('./project_tsconfig_paths-CDVxT6Ov.js');
|
|
11
|
+
var project_paths = require('./project_paths-Jtbi76Bs.js');
|
|
14
12
|
require('os');
|
|
15
13
|
var ts = require('typescript');
|
|
16
|
-
var checker = require('./checker-
|
|
17
|
-
var program = require('./program-
|
|
14
|
+
var checker = require('./checker-DF8ZaFW5.js');
|
|
15
|
+
var program = require('./program-BZk27Ndu.js');
|
|
18
16
|
require('path');
|
|
19
|
-
require('./index-
|
|
20
|
-
var apply_import_manager = require('./apply_import_manager-
|
|
17
|
+
require('./index-vGJcp5M7.js');
|
|
18
|
+
var apply_import_manager = require('./apply_import_manager-CyRT0UvU.js');
|
|
21
19
|
require('@angular-devkit/core');
|
|
22
20
|
require('node:path/posix');
|
|
23
21
|
require('fs');
|
|
24
22
|
require('module');
|
|
25
23
|
require('url');
|
|
26
24
|
|
|
27
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
28
|
-
|
|
29
|
-
var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts);
|
|
30
|
-
|
|
31
25
|
/** Migration that cleans up unused imports from a project. */
|
|
32
26
|
class UnusedImportsMigration extends project_paths.TsurgeFunnelMigration {
|
|
33
|
-
printer =
|
|
27
|
+
printer = ts.createPrinter();
|
|
34
28
|
createProgram(tsconfigAbsPath, fs) {
|
|
35
29
|
return super.createProgram(tsconfigAbsPath, fs, {
|
|
36
30
|
extendedDiagnostics: {
|
|
@@ -133,7 +127,7 @@ class UnusedImportsMigration extends project_paths.TsurgeFunnelMigration {
|
|
|
133
127
|
allRemovedIdentifiers: new Set(),
|
|
134
128
|
};
|
|
135
129
|
const walk = (node) => {
|
|
136
|
-
if (!
|
|
130
|
+
if (!ts.isIdentifier(node)) {
|
|
137
131
|
node.forEachChild(walk);
|
|
138
132
|
return;
|
|
139
133
|
}
|
|
@@ -145,17 +139,17 @@ class UnusedImportsMigration extends project_paths.TsurgeFunnelMigration {
|
|
|
145
139
|
if (locations.has(this.getNodeID(node.getStart(), node.getWidth()))) {
|
|
146
140
|
// When the entire array needs to be cleared, the diagnostic is
|
|
147
141
|
// reported on the property assignment, rather than an array element.
|
|
148
|
-
if (
|
|
142
|
+
if (ts.isPropertyAssignment(parent) &&
|
|
149
143
|
parent.name === node &&
|
|
150
|
-
|
|
144
|
+
ts.isArrayLiteralExpression(parent.initializer)) {
|
|
151
145
|
result.fullRemovals.add(parent.initializer);
|
|
152
146
|
parent.initializer.elements.forEach((element) => {
|
|
153
|
-
if (
|
|
147
|
+
if (ts.isIdentifier(element)) {
|
|
154
148
|
result.allRemovedIdentifiers.add(element);
|
|
155
149
|
}
|
|
156
150
|
});
|
|
157
151
|
}
|
|
158
|
-
else if (
|
|
152
|
+
else if (ts.isArrayLiteralExpression(parent)) {
|
|
159
153
|
if (!result.partialRemovals.has(parent)) {
|
|
160
154
|
result.partialRemovals.set(parent, new Set());
|
|
161
155
|
}
|
|
@@ -179,24 +173,24 @@ class UnusedImportsMigration extends project_paths.TsurgeFunnelMigration {
|
|
|
179
173
|
identifierCounts: new Map(),
|
|
180
174
|
};
|
|
181
175
|
const walk = (node) => {
|
|
182
|
-
if (
|
|
176
|
+
if (ts.isIdentifier(node) &&
|
|
183
177
|
node.parent &&
|
|
184
178
|
// Don't track individual identifiers marked for removal.
|
|
185
|
-
(!
|
|
179
|
+
(!ts.isArrayLiteralExpression(node.parent) ||
|
|
186
180
|
!partialRemovals.has(node.parent) ||
|
|
187
181
|
!partialRemovals.get(node.parent).has(node))) {
|
|
188
182
|
result.identifierCounts.set(node.text, (result.identifierCounts.get(node.text) ?? 0) + 1);
|
|
189
183
|
}
|
|
190
184
|
// Don't track identifiers in array literals that are about to be removed.
|
|
191
|
-
if (
|
|
185
|
+
if (ts.isArrayLiteralExpression(node) && fullRemovals.has(node)) {
|
|
192
186
|
return;
|
|
193
187
|
}
|
|
194
|
-
if (
|
|
188
|
+
if (ts.isImportDeclaration(node)) {
|
|
195
189
|
const namedBindings = node.importClause?.namedBindings;
|
|
196
|
-
const moduleName =
|
|
190
|
+
const moduleName = ts.isStringLiteral(node.moduleSpecifier)
|
|
197
191
|
? node.moduleSpecifier.text
|
|
198
192
|
: null;
|
|
199
|
-
if (namedBindings &&
|
|
193
|
+
if (namedBindings && ts.isNamedImports(namedBindings) && moduleName !== null) {
|
|
200
194
|
namedBindings.elements.forEach((imp) => {
|
|
201
195
|
if (!result.importedSymbols.has(moduleName)) {
|
|
202
196
|
result.importedSymbols.set(moduleName, new Map());
|
|
@@ -237,11 +231,11 @@ class UnusedImportsMigration extends project_paths.TsurgeFunnelMigration {
|
|
|
237
231
|
});
|
|
238
232
|
// Filter out the unused identifiers from an array.
|
|
239
233
|
partialRemovals.forEach((toRemove, node) => {
|
|
240
|
-
const newNode =
|
|
234
|
+
const newNode = ts.factory.updateArrayLiteralExpression(node, node.elements.filter((el) => !toRemove.has(el)));
|
|
241
235
|
replacements.push(new project_paths.Replacement(project_paths.projectFile(sourceFile, info), new project_paths.TextUpdate({
|
|
242
236
|
position: node.getStart(),
|
|
243
237
|
end: node.getEnd(),
|
|
244
|
-
toInsert: this.printer.printNode(
|
|
238
|
+
toInsert: this.printer.printNode(ts.EmitHint.Unspecified, newNode, sourceFile),
|
|
245
239
|
})));
|
|
246
240
|
});
|
|
247
241
|
// Attempt to clean up unused import declarations. Note that this isn't foolproof, because we
|
|
@@ -1,20 +1,17 @@
|
|
|
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
9
|
var ts = require('typescript');
|
|
10
|
-
var checker = require('./checker-
|
|
10
|
+
var checker = require('./checker-DF8ZaFW5.js');
|
|
11
11
|
require('os');
|
|
12
12
|
var p = require('path');
|
|
13
13
|
|
|
14
|
-
function
|
|
15
|
-
|
|
16
|
-
function _interopNamespace(e) {
|
|
17
|
-
if (e && e.__esModule) return e;
|
|
14
|
+
function _interopNamespaceDefault(e) {
|
|
18
15
|
var n = Object.create(null);
|
|
19
16
|
if (e) {
|
|
20
17
|
Object.keys(e).forEach(function (k) {
|
|
@@ -27,12 +24,11 @@ function _interopNamespace(e) {
|
|
|
27
24
|
}
|
|
28
25
|
});
|
|
29
26
|
}
|
|
30
|
-
n
|
|
27
|
+
n.default = e;
|
|
31
28
|
return Object.freeze(n);
|
|
32
29
|
}
|
|
33
30
|
|
|
34
|
-
var
|
|
35
|
-
var p__namespace = /*#__PURE__*/_interopNamespace(p);
|
|
31
|
+
var p__namespace = /*#__PURE__*/_interopNamespaceDefault(p);
|
|
36
32
|
|
|
37
33
|
/** Tracks changes that have to be made for specific files. */
|
|
38
34
|
class ChangeTracker {
|
|
@@ -76,7 +72,7 @@ class ChangeTracker {
|
|
|
76
72
|
* when copying nodes from one file to another, because TypeScript might not output literal nodes
|
|
77
73
|
* without it.
|
|
78
74
|
*/
|
|
79
|
-
replaceNode(oldNode, newNode, emitHint =
|
|
75
|
+
replaceNode(oldNode, newNode, emitHint = ts.EmitHint.Unspecified, sourceFileWhenPrinting) {
|
|
80
76
|
const sourceFile = oldNode.getSourceFile();
|
|
81
77
|
this.replaceText(sourceFile, oldNode.getStart(), oldNode.getWidth(), this._printer.printNode(emitHint, newNode, sourceFileWhenPrinting || sourceFile));
|
|
82
78
|
}
|
|
@@ -179,7 +175,7 @@ class ChangeTracker {
|
|
|
179
175
|
}
|
|
180
176
|
let kind = 0 /* QuoteKind.SINGLE */;
|
|
181
177
|
for (const statement of sourceFile.statements) {
|
|
182
|
-
if (
|
|
178
|
+
if (ts.isImportDeclaration(statement) && ts.isStringLiteral(statement.moduleSpecifier)) {
|
|
183
179
|
kind = statement.moduleSpecifier.getText()[0] === '"' ? 1 /* QuoteKind.DOUBLE */ : 0 /* QuoteKind.SINGLE */;
|
|
184
180
|
this._quotesCache.set(sourceFile, kind);
|
|
185
181
|
break;
|
|
@@ -204,12 +200,12 @@ class ChangeTracker {
|
|
|
204
200
|
const importLines = [];
|
|
205
201
|
let lastImport = null;
|
|
206
202
|
for (const statement of sourceFile.statements) {
|
|
207
|
-
if (
|
|
203
|
+
if (ts.isImportDeclaration(statement)) {
|
|
208
204
|
lastImport = statement;
|
|
209
205
|
}
|
|
210
206
|
}
|
|
211
207
|
for (const decl of importsToAdd) {
|
|
212
|
-
importLines.push(this._printer.printNode(
|
|
208
|
+
importLines.push(this._printer.printNode(ts.EmitHint.Unspecified, decl, sourceFile));
|
|
213
209
|
}
|
|
214
210
|
this.insertText(sourceFile, lastImport ? lastImport.getEnd() : 0, (lastImport ? '\n' : '') + importLines.join('\n'));
|
|
215
211
|
}
|
|
@@ -221,12 +217,12 @@ function normalizePath(path) {
|
|
|
221
217
|
}
|
|
222
218
|
|
|
223
219
|
function parseTsconfigFile(tsconfigPath, basePath) {
|
|
224
|
-
const { config } =
|
|
220
|
+
const { config } = ts.readConfigFile(tsconfigPath, ts.sys.readFile);
|
|
225
221
|
const parseConfigHost = {
|
|
226
|
-
useCaseSensitiveFileNames:
|
|
227
|
-
fileExists:
|
|
228
|
-
readDirectory:
|
|
229
|
-
readFile:
|
|
222
|
+
useCaseSensitiveFileNames: ts.sys.useCaseSensitiveFileNames,
|
|
223
|
+
fileExists: ts.sys.fileExists,
|
|
224
|
+
readDirectory: ts.sys.readDirectory,
|
|
225
|
+
readFile: ts.sys.readFile,
|
|
230
226
|
};
|
|
231
227
|
// Throw if incorrect arguments are passed to this function. Passing relative base paths
|
|
232
228
|
// results in root directories not being resolved and in later type checking runtime errors.
|
|
@@ -234,7 +230,7 @@ function parseTsconfigFile(tsconfigPath, basePath) {
|
|
|
234
230
|
if (!p__namespace.isAbsolute(basePath)) {
|
|
235
231
|
throw Error('Unexpected relative base path has been specified.');
|
|
236
232
|
}
|
|
237
|
-
return
|
|
233
|
+
return ts.parseJsonConfigFileContent(config, parseConfigHost, basePath, {});
|
|
238
234
|
}
|
|
239
235
|
|
|
240
236
|
/**
|
|
@@ -248,8 +244,8 @@ function parseTsconfigFile(tsconfigPath, basePath) {
|
|
|
248
244
|
* @param additionalFiles Additional file paths that should be added to the program.
|
|
249
245
|
*/
|
|
250
246
|
function createMigrationProgram(tree, tsconfigPath, basePath, fakeFileRead, additionalFiles) {
|
|
251
|
-
const { rootNames, options, host } = createProgramOptions(tree, tsconfigPath, basePath, fakeFileRead
|
|
252
|
-
return
|
|
247
|
+
const { rootNames, options, host } = createProgramOptions(tree, tsconfigPath, basePath, fakeFileRead);
|
|
248
|
+
return ts.createProgram(rootNames, options, host);
|
|
253
249
|
}
|
|
254
250
|
/**
|
|
255
251
|
* Creates the options necessary to instantiate a TypeScript program.
|
|
@@ -269,10 +265,10 @@ function createProgramOptions(tree, tsconfigPath, basePath, fakeFileRead, additi
|
|
|
269
265
|
const parsed = parseTsconfigFile(tsconfigPath, p.dirname(tsconfigPath));
|
|
270
266
|
const options = optionOverrides ? { ...parsed.options, ...optionOverrides } : parsed.options;
|
|
271
267
|
const host = createMigrationCompilerHost(tree, options, basePath, fakeFileRead);
|
|
272
|
-
return { rootNames: parsed.fileNames.concat(
|
|
268
|
+
return { rootNames: parsed.fileNames.concat([]), options, host };
|
|
273
269
|
}
|
|
274
270
|
function createMigrationCompilerHost(tree, options, basePath, fakeRead) {
|
|
275
|
-
const host =
|
|
271
|
+
const host = ts.createCompilerHost(options, true);
|
|
276
272
|
const defaultReadFile = host.readFile;
|
|
277
273
|
// We need to overwrite the host "readFile" method, as we want the TypeScript
|
|
278
274
|
// program to be based on the file contents in the virtual file tree. Otherwise
|
|
@@ -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
10
|
var p = require('path');
|
|
13
|
-
var compiler_host = require('./compiler_host-
|
|
14
|
-
var checker = require('./checker-
|
|
11
|
+
var compiler_host = require('./compiler_host-Da636uJ8.js');
|
|
12
|
+
var checker = require('./checker-DF8ZaFW5.js');
|
|
15
13
|
var ts = require('typescript');
|
|
16
14
|
require('os');
|
|
17
15
|
require('fs');
|
|
18
16
|
require('module');
|
|
19
17
|
require('url');
|
|
20
18
|
|
|
21
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
22
|
-
|
|
23
|
-
var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts);
|
|
24
|
-
|
|
25
19
|
function lookupIdentifiersInSourceFile(sourceFile, names) {
|
|
26
20
|
const results = new Set();
|
|
27
21
|
const visit = (node) => {
|
|
28
|
-
if (
|
|
22
|
+
if (ts.isIdentifier(node) && names.includes(node.text)) {
|
|
29
23
|
results.add(node);
|
|
30
24
|
}
|
|
31
|
-
|
|
25
|
+
ts.forEachChild(node, visit);
|
|
32
26
|
};
|
|
33
27
|
visit(sourceFile);
|
|
34
28
|
return results;
|
|
@@ -421,7 +415,7 @@ const replaceMarkerRegex = new RegExp(`${startMarker}|${endMarker}`, 'gm');
|
|
|
421
415
|
*/
|
|
422
416
|
function analyze(sourceFile, analyzedFiles) {
|
|
423
417
|
forEachClass(sourceFile, (node) => {
|
|
424
|
-
if (
|
|
418
|
+
if (ts.isClassDeclaration(node)) {
|
|
425
419
|
analyzeDecorators(node, sourceFile, analyzedFiles);
|
|
426
420
|
}
|
|
427
421
|
else {
|
|
@@ -440,7 +434,7 @@ function checkIfShouldChange(decl, file) {
|
|
|
440
434
|
const clause = decl.getChildAt(1);
|
|
441
435
|
return !(!file.removeCommonModule &&
|
|
442
436
|
clause.namedBindings &&
|
|
443
|
-
|
|
437
|
+
ts.isNamedImports(clause.namedBindings) &&
|
|
444
438
|
clause.namedBindings.elements.length === 1 &&
|
|
445
439
|
clause.namedBindings.elements[0].getText() === 'CommonModule');
|
|
446
440
|
}
|
|
@@ -454,46 +448,46 @@ function updateImportDeclaration(decl, removeCommonModule) {
|
|
|
454
448
|
// when the import declaration is at the top of the file, but right after a comment
|
|
455
449
|
// without this, the comment gets duplicated when the declaration is updated.
|
|
456
450
|
// the typescript AST includes that preceding comment as part of the import declaration full text.
|
|
457
|
-
const printer =
|
|
451
|
+
const printer = ts.createPrinter({
|
|
458
452
|
removeComments: true,
|
|
459
453
|
});
|
|
460
|
-
const updated =
|
|
461
|
-
return printer.printNode(
|
|
454
|
+
const updated = ts.factory.updateImportDeclaration(decl, decl.modifiers, updatedClause, decl.moduleSpecifier, undefined);
|
|
455
|
+
return printer.printNode(ts.EmitHint.Unspecified, updated, clause.getSourceFile());
|
|
462
456
|
}
|
|
463
457
|
function updateImportClause(clause, removeCommonModule) {
|
|
464
|
-
if (clause.namedBindings &&
|
|
458
|
+
if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
|
|
465
459
|
const removals = removeCommonModule ? importWithCommonRemovals : importRemovals;
|
|
466
460
|
const elements = clause.namedBindings.elements.filter((el) => !removals.includes(el.getText()));
|
|
467
461
|
if (elements.length === 0) {
|
|
468
462
|
return null;
|
|
469
463
|
}
|
|
470
|
-
clause =
|
|
464
|
+
clause = ts.factory.updateImportClause(clause, clause.isTypeOnly, clause.name, ts.factory.createNamedImports(elements));
|
|
471
465
|
}
|
|
472
466
|
return clause;
|
|
473
467
|
}
|
|
474
468
|
function updateClassImports(propAssignment, removeCommonModule) {
|
|
475
|
-
const printer =
|
|
469
|
+
const printer = ts.createPrinter();
|
|
476
470
|
const importList = propAssignment.initializer;
|
|
477
471
|
// Can't change non-array literals.
|
|
478
|
-
if (!
|
|
472
|
+
if (!ts.isArrayLiteralExpression(importList)) {
|
|
479
473
|
return null;
|
|
480
474
|
}
|
|
481
475
|
const removals = removeCommonModule ? importWithCommonRemovals : importRemovals;
|
|
482
|
-
const elements = importList.elements.filter((el) => !
|
|
476
|
+
const elements = importList.elements.filter((el) => !ts.isIdentifier(el) || !removals.includes(el.text));
|
|
483
477
|
if (elements.length === importList.elements.length) {
|
|
484
478
|
// nothing changed
|
|
485
479
|
return null;
|
|
486
480
|
}
|
|
487
|
-
const updatedElements =
|
|
488
|
-
const updatedAssignment =
|
|
489
|
-
return printer.printNode(
|
|
481
|
+
const updatedElements = ts.factory.updateArrayLiteralExpression(importList, elements);
|
|
482
|
+
const updatedAssignment = ts.factory.updatePropertyAssignment(propAssignment, propAssignment.name, updatedElements);
|
|
483
|
+
return printer.printNode(ts.EmitHint.Unspecified, updatedAssignment, updatedAssignment.getSourceFile());
|
|
490
484
|
}
|
|
491
485
|
function analyzeImportDeclarations(node, sourceFile, analyzedFiles) {
|
|
492
486
|
if (node.getText().indexOf('@angular/common') === -1) {
|
|
493
487
|
return;
|
|
494
488
|
}
|
|
495
489
|
const clause = node.getChildAt(1);
|
|
496
|
-
if (clause.namedBindings &&
|
|
490
|
+
if (clause.namedBindings && ts.isNamedImports(clause.namedBindings)) {
|
|
497
491
|
const elements = clause.namedBindings.elements.filter((el) => importWithCommonRemovals.includes(el.getText()));
|
|
498
492
|
if (elements.length > 0) {
|
|
499
493
|
AnalyzedFile.addRange(sourceFile.fileName, sourceFile, analyzedFiles, {
|
|
@@ -510,14 +504,14 @@ function analyzeDecorators(node, sourceFile, analyzedFiles) {
|
|
|
510
504
|
// Note: we have a utility to resolve the Angular decorators from a class declaration already.
|
|
511
505
|
// We don't use it here, because it requires access to the type checker which makes it more
|
|
512
506
|
// time-consuming to run internally.
|
|
513
|
-
const decorator =
|
|
514
|
-
return (
|
|
515
|
-
|
|
507
|
+
const decorator = ts.getDecorators(node)?.find((dec) => {
|
|
508
|
+
return (ts.isCallExpression(dec.expression) &&
|
|
509
|
+
ts.isIdentifier(dec.expression.expression) &&
|
|
516
510
|
dec.expression.expression.text === 'Component');
|
|
517
511
|
});
|
|
518
512
|
const metadata = decorator &&
|
|
519
513
|
decorator.expression.arguments.length > 0 &&
|
|
520
|
-
|
|
514
|
+
ts.isObjectLiteralExpression(decorator.expression.arguments[0])
|
|
521
515
|
? decorator.expression.arguments[0]
|
|
522
516
|
: null;
|
|
523
517
|
if (!metadata) {
|
|
@@ -526,8 +520,8 @@ function analyzeDecorators(node, sourceFile, analyzedFiles) {
|
|
|
526
520
|
for (const prop of metadata.properties) {
|
|
527
521
|
// All the properties we care about should have static
|
|
528
522
|
// names and be initialized to a static string.
|
|
529
|
-
if (!
|
|
530
|
-
(!
|
|
523
|
+
if (!ts.isPropertyAssignment(prop) ||
|
|
524
|
+
(!ts.isIdentifier(prop.name) && !ts.isStringLiteralLike(prop.name))) {
|
|
531
525
|
continue;
|
|
532
526
|
}
|
|
533
527
|
switch (prop.name.text) {
|
|
@@ -552,7 +546,7 @@ function analyzeDecorators(node, sourceFile, analyzedFiles) {
|
|
|
552
546
|
break;
|
|
553
547
|
case 'templateUrl':
|
|
554
548
|
// Leave the end as undefined which means that the range is until the end of the file.
|
|
555
|
-
if (
|
|
549
|
+
if (ts.isStringLiteralLike(prop.initializer)) {
|
|
556
550
|
const path = p.join(p.dirname(sourceFile.fileName), prop.initializer.text);
|
|
557
551
|
AnalyzedFile.addRange(path, sourceFile, analyzedFiles, {
|
|
558
552
|
start: 0,
|
|
@@ -747,7 +741,7 @@ function generatei18nContainer(i18nAttr, middle) {
|
|
|
747
741
|
/**
|
|
748
742
|
* Counts, replaces, and removes any necessary ng-templates post control flow migration
|
|
749
743
|
*/
|
|
750
|
-
function processNgTemplates(template) {
|
|
744
|
+
function processNgTemplates(template, sourceFile) {
|
|
751
745
|
// count usage
|
|
752
746
|
try {
|
|
753
747
|
const templates = getTemplates(template);
|
|
@@ -780,7 +774,18 @@ function processNgTemplates(template) {
|
|
|
780
774
|
}
|
|
781
775
|
// the +1 accounts for the t.count's counting of the original template
|
|
782
776
|
if (t.count === matches.length + 1 && safeToRemove) {
|
|
783
|
-
|
|
777
|
+
const refsInComponentFile = getViewChildOrViewChildrenNames(sourceFile);
|
|
778
|
+
if (refsInComponentFile?.length > 0) {
|
|
779
|
+
const templateRefs = getTemplateReferences(template);
|
|
780
|
+
for (const ref of refsInComponentFile) {
|
|
781
|
+
if (!templateRefs.includes(ref)) {
|
|
782
|
+
template = template.replace(t.contents, `${startMarker}${endMarker}`);
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
else {
|
|
787
|
+
template = template.replace(t.contents, `${startMarker}${endMarker}`);
|
|
788
|
+
}
|
|
784
789
|
}
|
|
785
790
|
// templates may have changed structure from nested replaced templates
|
|
786
791
|
// so we need to reprocess them before the next loop.
|
|
@@ -798,6 +803,44 @@ function processNgTemplates(template) {
|
|
|
798
803
|
return { migrated: template, err: err };
|
|
799
804
|
}
|
|
800
805
|
}
|
|
806
|
+
function getViewChildOrViewChildrenNames(sourceFile) {
|
|
807
|
+
const names = [];
|
|
808
|
+
function visit(node) {
|
|
809
|
+
if (ts.isDecorator(node) && ts.isCallExpression(node.expression)) {
|
|
810
|
+
const expr = node.expression;
|
|
811
|
+
if (ts.isIdentifier(expr.expression) &&
|
|
812
|
+
(expr.expression.text === 'ViewChild' || expr.expression.text === 'ViewChildren')) {
|
|
813
|
+
const firstArg = expr.arguments[0];
|
|
814
|
+
if (firstArg && ts.isStringLiteral(firstArg)) {
|
|
815
|
+
names.push(firstArg.text);
|
|
816
|
+
}
|
|
817
|
+
return;
|
|
818
|
+
}
|
|
819
|
+
}
|
|
820
|
+
ts.forEachChild(node, visit);
|
|
821
|
+
}
|
|
822
|
+
visit(sourceFile);
|
|
823
|
+
return names;
|
|
824
|
+
}
|
|
825
|
+
function getTemplateReferences(template) {
|
|
826
|
+
const parsed = parseTemplate(template);
|
|
827
|
+
if (parsed.tree === undefined) {
|
|
828
|
+
return [];
|
|
829
|
+
}
|
|
830
|
+
const references = [];
|
|
831
|
+
function visitNodes(nodes) {
|
|
832
|
+
for (const node of nodes) {
|
|
833
|
+
if (node?.name === 'ng-template') {
|
|
834
|
+
references.push(...node.attrs?.map((ref) => ref?.name?.slice(1)));
|
|
835
|
+
}
|
|
836
|
+
if (node.children) {
|
|
837
|
+
visitNodes(node.children);
|
|
838
|
+
}
|
|
839
|
+
}
|
|
840
|
+
}
|
|
841
|
+
visitNodes(parsed.tree.rootNodes);
|
|
842
|
+
return references;
|
|
843
|
+
}
|
|
801
844
|
function replaceRemainingPlaceholders(template) {
|
|
802
845
|
const pattern = '.*';
|
|
803
846
|
const placeholderPattern = getPlaceholder(pattern);
|
|
@@ -828,11 +871,11 @@ function canRemoveCommonModule(template) {
|
|
|
828
871
|
* removes imports from template imports and import declarations
|
|
829
872
|
*/
|
|
830
873
|
function removeImports(template, node, file) {
|
|
831
|
-
if (template.startsWith('imports') &&
|
|
874
|
+
if (template.startsWith('imports') && ts.isPropertyAssignment(node)) {
|
|
832
875
|
const updatedImport = updateClassImports(node, file.removeCommonModule);
|
|
833
876
|
return updatedImport ?? template;
|
|
834
877
|
}
|
|
835
|
-
else if (
|
|
878
|
+
else if (ts.isImportDeclaration(node) && checkIfShouldChange(node, file)) {
|
|
836
879
|
return updateImportDeclaration(node, file.removeCommonModule);
|
|
837
880
|
}
|
|
838
881
|
return template;
|
|
@@ -1119,7 +1162,7 @@ function formatTemplate(tmpl, templateType) {
|
|
|
1119
1162
|
/** Executes a callback on each class declaration in a file. */
|
|
1120
1163
|
function forEachClass(sourceFile, callback) {
|
|
1121
1164
|
sourceFile.forEachChild(function walk(node) {
|
|
1122
|
-
if (
|
|
1165
|
+
if (ts.isClassDeclaration(node) || ts.isImportDeclaration(node)) {
|
|
1123
1166
|
callback(node);
|
|
1124
1167
|
}
|
|
1125
1168
|
node.forEachChild(walk);
|
|
@@ -1719,7 +1762,7 @@ function migrateTemplate(template, templateType, node, file, format = true, anal
|
|
|
1719
1762
|
return { migrated: template, errors: switchResult.errors };
|
|
1720
1763
|
}
|
|
1721
1764
|
const caseResult = migrateCase(switchResult.migrated);
|
|
1722
|
-
const templateResult = processNgTemplates(caseResult.migrated);
|
|
1765
|
+
const templateResult = processNgTemplates(caseResult.migrated, file.sourceFile);
|
|
1723
1766
|
if (templateResult.err !== undefined) {
|
|
1724
1767
|
return { migrated: template, errors: [{ type: 'template', error: templateResult.err }] };
|
|
1725
1768
|
}
|
|
@@ -1,17 +1,13 @@
|
|
|
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
9
|
var ts = require('typescript');
|
|
10
10
|
|
|
11
|
-
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
12
|
-
|
|
13
|
-
var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts);
|
|
14
|
-
|
|
15
11
|
/** Gets import information about the specified identifier by using the Type checker. */
|
|
16
12
|
function getImportOfIdentifier(typeChecker, node) {
|
|
17
13
|
const symbol = typeChecker.getSymbolAtLocation(node);
|
|
@@ -19,11 +15,11 @@ function getImportOfIdentifier(typeChecker, node) {
|
|
|
19
15
|
return null;
|
|
20
16
|
}
|
|
21
17
|
const decl = symbol.declarations[0];
|
|
22
|
-
if (!
|
|
18
|
+
if (!ts.isImportSpecifier(decl)) {
|
|
23
19
|
return null;
|
|
24
20
|
}
|
|
25
21
|
const importDecl = decl.parent.parent.parent;
|
|
26
|
-
if (!
|
|
22
|
+
if (!ts.isImportDeclaration(importDecl) || !ts.isStringLiteral(importDecl.moduleSpecifier)) {
|
|
27
23
|
return null;
|
|
28
24
|
}
|
|
29
25
|
return {
|
|
@@ -56,14 +52,14 @@ function getImportSpecifier(sourceFile, moduleName, specifierName) {
|
|
|
56
52
|
function getImportSpecifiers(sourceFile, moduleName, specifierOrSpecifiers) {
|
|
57
53
|
const matches = [];
|
|
58
54
|
for (const node of sourceFile.statements) {
|
|
59
|
-
if (!
|
|
55
|
+
if (!ts.isImportDeclaration(node) || !ts.isStringLiteral(node.moduleSpecifier)) {
|
|
60
56
|
continue;
|
|
61
57
|
}
|
|
62
58
|
const namedBindings = node.importClause?.namedBindings;
|
|
63
59
|
const isMatch = typeof moduleName === 'string'
|
|
64
60
|
? node.moduleSpecifier.text === moduleName
|
|
65
61
|
: moduleName.test(node.moduleSpecifier.text);
|
|
66
|
-
if (!isMatch || !namedBindings || !
|
|
62
|
+
if (!isMatch || !namedBindings || !ts.isNamedImports(namedBindings)) {
|
|
67
63
|
continue;
|
|
68
64
|
}
|
|
69
65
|
if (typeof specifierOrSpecifiers === 'string') {
|
|
@@ -85,12 +81,11 @@ function getImportSpecifiers(sourceFile, moduleName, specifierOrSpecifiers) {
|
|
|
85
81
|
}
|
|
86
82
|
function getNamedImports(sourceFile, moduleName) {
|
|
87
83
|
for (const node of sourceFile.statements) {
|
|
88
|
-
if (
|
|
89
|
-
const isMatch =
|
|
90
|
-
|
|
91
|
-
: moduleName.test(node.moduleSpecifier.text);
|
|
84
|
+
if (ts.isImportDeclaration(node) && ts.isStringLiteral(node.moduleSpecifier)) {
|
|
85
|
+
const isMatch = node.moduleSpecifier.text === moduleName
|
|
86
|
+
;
|
|
92
87
|
const namedBindings = node.importClause?.namedBindings;
|
|
93
|
-
if (isMatch && namedBindings &&
|
|
88
|
+
if (isMatch && namedBindings && ts.isNamedImports(namedBindings)) {
|
|
94
89
|
return namedBindings;
|
|
95
90
|
}
|
|
96
91
|
}
|