@angular/core 19.0.0-next.10 → 19.0.0-next.11
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 +13205 -11798
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives/event-dispatch.mjs +1 -1
- package/fesm2022/primitives/signals.mjs +8 -6
- package/fesm2022/primitives/signals.mjs.map +1 -1
- package/fesm2022/rxjs-interop.mjs +72 -4
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +4 -4
- package/index.d.ts +527 -51
- package/package.json +1 -1
- package/primitives/event-dispatch/index.d.ts +1 -1
- package/primitives/signals/index.d.ts +3 -1
- package/rxjs-interop/index.d.ts +32 -1
- package/schematics/bundles/{checker-77660732.js → checker-51c08a1b.js} +112 -97
- package/schematics/bundles/{compiler_host-81f430d9.js → compiler_host-d7f120f0.js} +2 -2
- package/schematics/bundles/control-flow-migration.js +3 -3
- package/schematics/bundles/explicit-standalone-flag.js +6 -4
- package/schematics/bundles/imports-4ac08251.js +1 -1
- package/schematics/bundles/{group_replacements-1f48eff7.js → index-f7b283e6.js} +247 -1649
- package/schematics/bundles/inject-migration.js +7 -6
- package/schematics/bundles/leading_space-d190b83b.js +1 -1
- package/schematics/bundles/migrate_ts_type_references-b2b55f62.js +1448 -0
- package/schematics/bundles/{nodes-0e7d45ca.js → ng_decorators-4579dec6.js} +1 -14
- package/schematics/bundles/nodes-a535b2be.js +27 -0
- package/schematics/bundles/output-migration.js +7295 -0
- package/schematics/bundles/pending-tasks.js +3 -3
- package/schematics/bundles/{program-1413936a.js → program-6e6520d8.js} +40 -18
- package/schematics/bundles/project_tsconfig_paths-e9ccccbf.js +1 -1
- package/schematics/bundles/provide-initializer.js +190 -0
- package/schematics/bundles/route-lazy-loading.js +3 -3
- package/schematics/bundles/signal-input-migration.js +73 -60
- package/schematics/bundles/signal-queries-migration.js +119 -90
- package/schematics/bundles/signals.js +54 -0
- package/schematics/bundles/standalone-migration.js +12 -11
- package/schematics/collection.json +11 -0
- package/schematics/migrations.json +7 -1
- package/schematics/ng-generate/output-migration/schema.json +19 -0
- package/schematics/ng-generate/signals/schema.json +65 -0
- package/testing/index.d.ts +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
/**
|
|
3
|
-
* @license Angular v19.0.0-next.
|
|
3
|
+
* @license Angular v19.0.0-next.11
|
|
4
4
|
* (c) 2010-2024 Google LLC. https://angular.io/
|
|
5
5
|
* License: MIT
|
|
6
6
|
*/
|
|
@@ -10,19 +10,20 @@ Object.defineProperty(exports, '__esModule', { value: true });
|
|
|
10
10
|
|
|
11
11
|
var schematics = require('@angular-devkit/schematics');
|
|
12
12
|
var project_tsconfig_paths = require('./project_tsconfig_paths-e9ccccbf.js');
|
|
13
|
-
var
|
|
13
|
+
var index = require('./index-f7b283e6.js');
|
|
14
14
|
require('os');
|
|
15
15
|
var ts = require('typescript');
|
|
16
|
-
var checker = require('./checker-
|
|
17
|
-
var program = require('./program-
|
|
16
|
+
var checker = require('./checker-51c08a1b.js');
|
|
17
|
+
var program = require('./program-6e6520d8.js');
|
|
18
18
|
var assert = require('assert');
|
|
19
19
|
require('path');
|
|
20
|
+
var migrate_ts_type_references = require('./migrate_ts_type_references-b2b55f62.js');
|
|
20
21
|
require('@angular-devkit/core');
|
|
21
|
-
require('./leading_space-d190b83b.js');
|
|
22
22
|
require('node:path/posix');
|
|
23
23
|
require('fs');
|
|
24
24
|
require('module');
|
|
25
25
|
require('url');
|
|
26
|
+
require('./leading_space-d190b83b.js');
|
|
26
27
|
|
|
27
28
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
28
29
|
|
|
@@ -37,7 +38,7 @@ function migrateHostBindings(host, references, info) {
|
|
|
37
38
|
const seenReferences = new WeakMap();
|
|
38
39
|
for (const reference of references) {
|
|
39
40
|
// This pass only deals with host binding references.
|
|
40
|
-
if (!
|
|
41
|
+
if (!index.isHostBindingReference(reference)) {
|
|
41
42
|
continue;
|
|
42
43
|
}
|
|
43
44
|
// Skip references to incompatible inputs.
|
|
@@ -61,7 +62,7 @@ function migrateHostBindings(host, references, info) {
|
|
|
61
62
|
const appendText = reference.from.isObjectShorthandExpression
|
|
62
63
|
? `: ${reference.from.read.name}()`
|
|
63
64
|
: `()`;
|
|
64
|
-
host.replacements.push(new
|
|
65
|
+
host.replacements.push(new index.Replacement(index.projectFile(bindingField.getSourceFile(), info), new index.TextUpdate({ position: readEndPos, end: readEndPos, toInsert: appendText })));
|
|
65
66
|
}
|
|
66
67
|
}
|
|
67
68
|
|
|
@@ -73,7 +74,7 @@ function migrateTemplateReferences(host, references) {
|
|
|
73
74
|
const seenFileReferences = new Set();
|
|
74
75
|
for (const reference of references) {
|
|
75
76
|
// This pass only deals with HTML template references.
|
|
76
|
-
if (!
|
|
77
|
+
if (!index.isTemplateReference(reference)) {
|
|
77
78
|
continue;
|
|
78
79
|
}
|
|
79
80
|
// Skip references to incompatible inputs.
|
|
@@ -90,7 +91,7 @@ function migrateTemplateReferences(host, references) {
|
|
|
90
91
|
const appendText = reference.from.isObjectShorthandExpression
|
|
91
92
|
? `: ${reference.from.read.name}()`
|
|
92
93
|
: `()`;
|
|
93
|
-
host.replacements.push(new
|
|
94
|
+
host.replacements.push(new index.Replacement(reference.from.templateFile, new index.TextUpdate({
|
|
94
95
|
position: reference.from.read.sourceSpan.end,
|
|
95
96
|
end: reference.from.read.sourceSpan.end,
|
|
96
97
|
toInsert: appendText,
|
|
@@ -138,7 +139,7 @@ function extractQueryListType(node) {
|
|
|
138
139
|
* --> read stays
|
|
139
140
|
* --> emitDistinctChangesOnly is gone!
|
|
140
141
|
*/
|
|
141
|
-
function computeReplacementsToMigrateQuery(node, metadata, importManager, info, printer) {
|
|
142
|
+
function computeReplacementsToMigrateQuery(node, metadata, importManager, info, printer, options, checker$1) {
|
|
142
143
|
const sf = node.getSourceFile();
|
|
143
144
|
let newQueryFn = importManager.addImport({
|
|
144
145
|
requestedFile: sf,
|
|
@@ -172,36 +173,56 @@ function computeReplacementsToMigrateQuery(node, metadata, importManager, info,
|
|
|
172
173
|
if (optionProperties.length > 0) {
|
|
173
174
|
args.push(ts__default["default"].factory.createObjectLiteralExpression(optionProperties));
|
|
174
175
|
}
|
|
175
|
-
|
|
176
|
-
const
|
|
177
|
-
|
|
178
|
-
//
|
|
179
|
-
|
|
176
|
+
const strictNullChecksEnabled = options.strict === true || options.strictNullChecks === true;
|
|
177
|
+
const strictPropertyInitialization = options.strict === true || options.strictPropertyInitialization === true;
|
|
178
|
+
let isRequired = node.exclamationToken !== undefined;
|
|
179
|
+
// If we come across an application with strict null checks enabled, but strict
|
|
180
|
+
// property initialization is disabled, there are two options:
|
|
181
|
+
// - Either the query is already typed to include `undefined` explicitly,
|
|
182
|
+
// in which case an option query makes sense.
|
|
183
|
+
// - OR, the query is not typed to include `undefined`. In which case, the query
|
|
184
|
+
// should be marked as required to not break the app. The user-code throughout
|
|
185
|
+
// the application (given strict null checks) already assumes non-nullable!
|
|
186
|
+
if (strictNullChecksEnabled &&
|
|
187
|
+
!strictPropertyInitialization &&
|
|
188
|
+
node.initializer === undefined &&
|
|
189
|
+
node.questionToken === undefined &&
|
|
190
|
+
type !== undefined &&
|
|
191
|
+
!checker$1.isTypeAssignableTo(checker$1.getUndefinedType(), checker$1.getTypeFromTypeNode(type))) {
|
|
192
|
+
isRequired = true;
|
|
193
|
+
}
|
|
194
|
+
if (isRequired && metadata.queryInfo.first) {
|
|
195
|
+
// If the query is required already via some indicators, and this is a "single"
|
|
196
|
+
// query, use the available `.required` method.
|
|
180
197
|
newQueryFn = ts__default["default"].factory.createPropertyAccessExpression(newQueryFn, 'required');
|
|
181
198
|
}
|
|
182
199
|
// If this query is still nullable (i.e. not required), attempt to remove
|
|
183
200
|
// explicit `undefined` types if possible.
|
|
184
|
-
if (!
|
|
185
|
-
type =
|
|
201
|
+
if (!isRequired && type !== undefined && ts__default["default"].isUnionTypeNode(type)) {
|
|
202
|
+
type = migrate_ts_type_references.removeFromUnionIfPossible(type, (v) => v.kind !== ts__default["default"].SyntaxKind.UndefinedKeyword);
|
|
186
203
|
}
|
|
187
|
-
|
|
204
|
+
let locatorType = Array.isArray(metadata.queryInfo.predicate)
|
|
188
205
|
? null
|
|
189
206
|
: metadata.queryInfo.predicate.expression;
|
|
190
|
-
|
|
191
|
-
// If the type and the read type are matching, we can rely
|
|
192
|
-
//
|
|
207
|
+
let resolvedReadType = metadata.queryInfo.read ?? locatorType;
|
|
208
|
+
// If the original property type and the read type are matching, we can rely
|
|
209
|
+
// on the TS inference, instead of repeating types, like in `viewChild<Button>(Button)`.
|
|
193
210
|
if (type !== undefined &&
|
|
194
|
-
|
|
195
|
-
ts__default["default"].isIdentifier(
|
|
211
|
+
resolvedReadType instanceof checker.WrappedNodeExpr &&
|
|
212
|
+
ts__default["default"].isIdentifier(resolvedReadType.node) &&
|
|
196
213
|
ts__default["default"].isTypeReferenceNode(type) &&
|
|
197
214
|
ts__default["default"].isIdentifier(type.typeName) &&
|
|
198
|
-
type.typeName.text ===
|
|
199
|
-
|
|
200
|
-
}
|
|
201
|
-
const call = ts__default["default"].factory.createCallExpression(newQueryFn,
|
|
215
|
+
type.typeName.text === resolvedReadType.node.text) {
|
|
216
|
+
locatorType = null;
|
|
217
|
+
}
|
|
218
|
+
const call = ts__default["default"].factory.createCallExpression(newQueryFn,
|
|
219
|
+
// If there is no resolved `ReadT` (e.g. string predicate), we use the
|
|
220
|
+
// original type explicitly as generic. Otherwise, query API is smart
|
|
221
|
+
// enough to always infer.
|
|
222
|
+
resolvedReadType === null && type !== undefined ? [type] : undefined, args);
|
|
202
223
|
const updated = ts__default["default"].factory.createPropertyDeclaration([ts__default["default"].factory.createModifier(ts__default["default"].SyntaxKind.ReadonlyKeyword)], node.name, undefined, undefined, call);
|
|
203
224
|
return [
|
|
204
|
-
new
|
|
225
|
+
new index.Replacement(index.projectFile(node.getSourceFile(), info), new index.TextUpdate({
|
|
205
226
|
position: node.getStart(),
|
|
206
227
|
end: node.getEnd(),
|
|
207
228
|
toInsert: printer.printNode(ts__default["default"].EmitHint.Unspecified, updated, sf),
|
|
@@ -242,7 +263,7 @@ function getUniqueIDForClassProperty(property, info) {
|
|
|
242
263
|
if (property.name === undefined) {
|
|
243
264
|
return null;
|
|
244
265
|
}
|
|
245
|
-
const id =
|
|
266
|
+
const id = index.projectFile(property.getSourceFile(), info).id.replace(/\.d\.ts$/, '.ts');
|
|
246
267
|
// Note: If a class is nested, there could be an ID clash.
|
|
247
268
|
// This is highly unlikely though, and this is not a problem because
|
|
248
269
|
// in such cases, there is even less chance there are any references to
|
|
@@ -305,6 +326,7 @@ function extractSourceQueryDefinition(node, reflector, evaluator, info) {
|
|
|
305
326
|
args: decorator.args ?? [],
|
|
306
327
|
queryInfo,
|
|
307
328
|
node: node,
|
|
329
|
+
fieldDecorators: decorators,
|
|
308
330
|
};
|
|
309
331
|
}
|
|
310
332
|
|
|
@@ -320,13 +342,13 @@ function markFieldIncompatibleInMetadata(data, id, reason) {
|
|
|
320
342
|
existing.fieldReason = reason;
|
|
321
343
|
}
|
|
322
344
|
else {
|
|
323
|
-
existing.fieldReason =
|
|
345
|
+
existing.fieldReason = migrate_ts_type_references.pickFieldIncompatibility({ reason, context: null }, { reason: existing.fieldReason, context: null }).reason;
|
|
324
346
|
}
|
|
325
347
|
}
|
|
326
348
|
function filterBestEffortIncompatibilities(knownQueries) {
|
|
327
349
|
for (const query of Object.values(knownQueries.globalMetadata.problematicQueries)) {
|
|
328
350
|
if (query.fieldReason !== null &&
|
|
329
|
-
!
|
|
351
|
+
!migrate_ts_type_references.nonIgnorableFieldIncompatibilities.includes(query.fieldReason)) {
|
|
330
352
|
query.fieldReason = null;
|
|
331
353
|
}
|
|
332
354
|
}
|
|
@@ -362,12 +384,12 @@ class KnownQueries {
|
|
|
362
384
|
});
|
|
363
385
|
this.knownQueryIDs.set(id, { key: id, node: queryField });
|
|
364
386
|
const descriptor = { key: id, node: queryField };
|
|
365
|
-
const file =
|
|
387
|
+
const file = index.projectFile(queryField.getSourceFile(), this.info);
|
|
366
388
|
if (this.config.shouldMigrateQuery !== undefined &&
|
|
367
389
|
!this.config.shouldMigrateQuery(descriptor, file)) {
|
|
368
390
|
this.markFieldIncompatible(descriptor, {
|
|
369
391
|
context: null,
|
|
370
|
-
reason:
|
|
392
|
+
reason: migrate_ts_type_references.FieldIncompatibilityReason.SkippedViaConfigFilter,
|
|
371
393
|
});
|
|
372
394
|
}
|
|
373
395
|
}
|
|
@@ -398,27 +420,27 @@ class KnownQueries {
|
|
|
398
420
|
if (this.isFieldIncompatible(parent) && !this.isFieldIncompatible(derived)) {
|
|
399
421
|
this.markFieldIncompatible(derived, {
|
|
400
422
|
context: null,
|
|
401
|
-
reason:
|
|
423
|
+
reason: migrate_ts_type_references.FieldIncompatibilityReason.ParentIsIncompatible,
|
|
402
424
|
});
|
|
403
425
|
return;
|
|
404
426
|
}
|
|
405
427
|
if (this.isFieldIncompatible(derived) && !this.isFieldIncompatible(parent)) {
|
|
406
428
|
this.markFieldIncompatible(parent, {
|
|
407
429
|
context: null,
|
|
408
|
-
reason:
|
|
430
|
+
reason: migrate_ts_type_references.FieldIncompatibilityReason.DerivedIsIncompatible,
|
|
409
431
|
});
|
|
410
432
|
}
|
|
411
433
|
}
|
|
412
434
|
captureUnknownDerivedField(field) {
|
|
413
435
|
this.markFieldIncompatible(field, {
|
|
414
436
|
context: null,
|
|
415
|
-
reason:
|
|
437
|
+
reason: migrate_ts_type_references.FieldIncompatibilityReason.OverriddenByDerivedClass,
|
|
416
438
|
});
|
|
417
439
|
}
|
|
418
440
|
captureUnknownParentField(field) {
|
|
419
441
|
this.markFieldIncompatible(field, {
|
|
420
442
|
context: null,
|
|
421
|
-
reason:
|
|
443
|
+
reason: migrate_ts_type_references.FieldIncompatibilityReason.TypeConflictWithBaseClass,
|
|
422
444
|
});
|
|
423
445
|
}
|
|
424
446
|
getIncompatibilityForField(descriptor) {
|
|
@@ -437,13 +459,13 @@ class KnownQueries {
|
|
|
437
459
|
getIncompatibilityTextForField(field) {
|
|
438
460
|
const incompatibilityInfo = this.globalMetadata.problematicQueries[field.key];
|
|
439
461
|
if (incompatibilityInfo.fieldReason !== null) {
|
|
440
|
-
return
|
|
462
|
+
return migrate_ts_type_references.getMessageForFieldIncompatibility(incompatibilityInfo.fieldReason, {
|
|
441
463
|
single: 'query',
|
|
442
464
|
plural: 'queries',
|
|
443
465
|
});
|
|
444
466
|
}
|
|
445
467
|
if (incompatibilityInfo.classReason !== null) {
|
|
446
|
-
return
|
|
468
|
+
return migrate_ts_type_references.getMessageForClassIncompatibility(incompatibilityInfo.classReason, {
|
|
447
469
|
single: 'query',
|
|
448
470
|
plural: 'queries',
|
|
449
471
|
});
|
|
@@ -476,7 +498,7 @@ function queryFunctionNameToDecorator(name) {
|
|
|
476
498
|
* E.g. whether `<my-read>.toArray` is detected.
|
|
477
499
|
*/
|
|
478
500
|
function checkTsReferenceAccessesField(ref, fieldName) {
|
|
479
|
-
const accessNode =
|
|
501
|
+
const accessNode = index.traverseAccess(ref.from.node);
|
|
480
502
|
// Check if the reference is part of a property access.
|
|
481
503
|
if (!ts__default["default"].isPropertyAccessExpression(accessNode.parent) ||
|
|
482
504
|
!ts__default["default"].isIdentifier(accessNode.parent.name)) {
|
|
@@ -545,7 +567,7 @@ function checkNonTsReferenceCallsField(ref, fieldName) {
|
|
|
545
567
|
}
|
|
546
568
|
|
|
547
569
|
function removeQueryListToArrayCall(ref, info, globalMetadata, knownQueries, replacements) {
|
|
548
|
-
if (!
|
|
570
|
+
if (!index.isHostBindingReference(ref) && !index.isTemplateReference(ref) && !index.isTsReference(ref)) {
|
|
549
571
|
return;
|
|
550
572
|
}
|
|
551
573
|
if (knownQueries.isFieldIncompatible(ref.target)) {
|
|
@@ -555,13 +577,13 @@ function removeQueryListToArrayCall(ref, info, globalMetadata, knownQueries, rep
|
|
|
555
577
|
return;
|
|
556
578
|
}
|
|
557
579
|
// TS references.
|
|
558
|
-
if (
|
|
580
|
+
if (index.isTsReference(ref)) {
|
|
559
581
|
const toArrayCallExpr = checkTsReferenceCallsField(ref, 'toArray');
|
|
560
582
|
if (toArrayCallExpr === null) {
|
|
561
583
|
return;
|
|
562
584
|
}
|
|
563
585
|
const toArrayExpr = toArrayCallExpr.expression;
|
|
564
|
-
replacements.push(new
|
|
586
|
+
replacements.push(new index.Replacement(index.projectFile(toArrayExpr.getSourceFile(), info), new index.TextUpdate({
|
|
565
587
|
// Delete from expression end to call end. E.g. `.toArray(<..>)`.
|
|
566
588
|
position: toArrayExpr.expression.getEnd(),
|
|
567
589
|
end: toArrayCallExpr.getEnd(),
|
|
@@ -574,9 +596,9 @@ function removeQueryListToArrayCall(ref, info, globalMetadata, knownQueries, rep
|
|
|
574
596
|
if (callExpr === null) {
|
|
575
597
|
return;
|
|
576
598
|
}
|
|
577
|
-
const file =
|
|
578
|
-
const offset =
|
|
579
|
-
replacements.push(new
|
|
599
|
+
const file = index.isHostBindingReference(ref) ? ref.from.file : ref.from.templateFile;
|
|
600
|
+
const offset = index.isHostBindingReference(ref) ? ref.from.hostPropertyNode.getStart() + 1 : 0;
|
|
601
|
+
replacements.push(new index.Replacement(file, new index.TextUpdate({
|
|
580
602
|
// Delete from expression end to call end. E.g. `.toArray(<..>)`.
|
|
581
603
|
position: offset + callExpr.receiver.receiver.sourceSpan.end,
|
|
582
604
|
end: offset + callExpr.sourceSpan.end,
|
|
@@ -585,7 +607,7 @@ function removeQueryListToArrayCall(ref, info, globalMetadata, knownQueries, rep
|
|
|
585
607
|
}
|
|
586
608
|
|
|
587
609
|
function replaceQueryListGetCall(ref, info, globalMetadata, knownQueries, replacements) {
|
|
588
|
-
if (!
|
|
610
|
+
if (!index.isHostBindingReference(ref) && !index.isTemplateReference(ref) && !index.isTsReference(ref)) {
|
|
589
611
|
return;
|
|
590
612
|
}
|
|
591
613
|
if (knownQueries.isFieldIncompatible(ref.target)) {
|
|
@@ -594,13 +616,13 @@ function replaceQueryListGetCall(ref, info, globalMetadata, knownQueries, replac
|
|
|
594
616
|
if (!globalMetadata.knownQueryFields[ref.target.key]?.isMulti) {
|
|
595
617
|
return;
|
|
596
618
|
}
|
|
597
|
-
if (
|
|
619
|
+
if (index.isTsReference(ref)) {
|
|
598
620
|
const getCallExpr = checkTsReferenceCallsField(ref, 'get');
|
|
599
621
|
if (getCallExpr === null) {
|
|
600
622
|
return;
|
|
601
623
|
}
|
|
602
624
|
const getExpr = getCallExpr.expression;
|
|
603
|
-
replacements.push(new
|
|
625
|
+
replacements.push(new index.Replacement(index.projectFile(getExpr.getSourceFile(), info), new index.TextUpdate({
|
|
604
626
|
position: getExpr.name.getStart(),
|
|
605
627
|
end: getExpr.name.getEnd(),
|
|
606
628
|
toInsert: 'at',
|
|
@@ -612,9 +634,9 @@ function replaceQueryListGetCall(ref, info, globalMetadata, knownQueries, replac
|
|
|
612
634
|
if (callExpr === null) {
|
|
613
635
|
return;
|
|
614
636
|
}
|
|
615
|
-
const file =
|
|
616
|
-
const offset =
|
|
617
|
-
replacements.push(new
|
|
637
|
+
const file = index.isHostBindingReference(ref) ? ref.from.file : ref.from.templateFile;
|
|
638
|
+
const offset = index.isHostBindingReference(ref) ? ref.from.hostPropertyNode.getStart() + 1 : 0;
|
|
639
|
+
replacements.push(new index.Replacement(file, new index.TextUpdate({
|
|
618
640
|
position: offset + callExpr.receiver.nameSpan.start,
|
|
619
641
|
end: offset + callExpr.receiver.nameSpan.end,
|
|
620
642
|
toInsert: 'at',
|
|
@@ -630,7 +652,7 @@ const problematicQueryListMethods = [
|
|
|
630
652
|
'destroy',
|
|
631
653
|
];
|
|
632
654
|
function checkForIncompatibleQueryListAccesses(ref, result) {
|
|
633
|
-
if (
|
|
655
|
+
if (index.isTsReference(ref)) {
|
|
634
656
|
for (const problematicFn of problematicQueryListMethods) {
|
|
635
657
|
const access = checkTsReferenceAccessesField(ref, problematicFn);
|
|
636
658
|
if (access !== null) {
|
|
@@ -639,7 +661,7 @@ function checkForIncompatibleQueryListAccesses(ref, result) {
|
|
|
639
661
|
}
|
|
640
662
|
}
|
|
641
663
|
}
|
|
642
|
-
if (
|
|
664
|
+
if (index.isHostBindingReference(ref) || index.isTemplateReference(ref)) {
|
|
643
665
|
for (const problematicFn of problematicQueryListMethods) {
|
|
644
666
|
const access = checkNonTsReferenceAccessesField(ref, problematicFn);
|
|
645
667
|
if (access !== null) {
|
|
@@ -655,7 +677,7 @@ const mapping = new Map([
|
|
|
655
677
|
['last', 'at(-1)!'],
|
|
656
678
|
]);
|
|
657
679
|
function replaceQueryListFirstAndLastReferences(ref, info, globalMetadata, knownQueries, replacements) {
|
|
658
|
-
if (!
|
|
680
|
+
if (!index.isHostBindingReference(ref) && !index.isTemplateReference(ref) && !index.isTsReference(ref)) {
|
|
659
681
|
return;
|
|
660
682
|
}
|
|
661
683
|
if (knownQueries.isFieldIncompatible(ref.target)) {
|
|
@@ -664,12 +686,12 @@ function replaceQueryListFirstAndLastReferences(ref, info, globalMetadata, known
|
|
|
664
686
|
if (!globalMetadata.knownQueryFields[ref.target.key]?.isMulti) {
|
|
665
687
|
return;
|
|
666
688
|
}
|
|
667
|
-
if (
|
|
689
|
+
if (index.isTsReference(ref)) {
|
|
668
690
|
const expr = checkTsReferenceAccessesField(ref, 'first') ?? checkTsReferenceAccessesField(ref, 'last');
|
|
669
691
|
if (expr === null) {
|
|
670
692
|
return;
|
|
671
693
|
}
|
|
672
|
-
replacements.push(new
|
|
694
|
+
replacements.push(new index.Replacement(index.projectFile(expr.getSourceFile(), info), new index.TextUpdate({
|
|
673
695
|
position: expr.name.getStart(),
|
|
674
696
|
end: expr.name.getEnd(),
|
|
675
697
|
toInsert: mapping.get(expr.name.text),
|
|
@@ -681,16 +703,16 @@ function replaceQueryListFirstAndLastReferences(ref, info, globalMetadata, known
|
|
|
681
703
|
if (expr === null) {
|
|
682
704
|
return;
|
|
683
705
|
}
|
|
684
|
-
const file =
|
|
685
|
-
const offset =
|
|
686
|
-
replacements.push(new
|
|
706
|
+
const file = index.isHostBindingReference(ref) ? ref.from.file : ref.from.templateFile;
|
|
707
|
+
const offset = index.isHostBindingReference(ref) ? ref.from.hostPropertyNode.getStart() + 1 : 0;
|
|
708
|
+
replacements.push(new index.Replacement(file, new index.TextUpdate({
|
|
687
709
|
position: offset + expr.nameSpan.start,
|
|
688
710
|
end: offset + expr.nameSpan.end,
|
|
689
711
|
toInsert: mapping.get(expr.name),
|
|
690
712
|
})));
|
|
691
713
|
}
|
|
692
714
|
|
|
693
|
-
class SignalQueriesMigration extends
|
|
715
|
+
class SignalQueriesMigration extends index.TsurgeComplexMigration {
|
|
694
716
|
constructor(config = {}) {
|
|
695
717
|
super();
|
|
696
718
|
this.config = config;
|
|
@@ -709,7 +731,7 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
709
731
|
potentialProblematicReferenceForMultiQueries: {},
|
|
710
732
|
reusableAnalysisReferences: null,
|
|
711
733
|
};
|
|
712
|
-
const groupedAstVisitor = new
|
|
734
|
+
const groupedAstVisitor = new migrate_ts_type_references.GroupedTsAstVisitor(sourceFiles);
|
|
713
735
|
const referenceResult = { references: [] };
|
|
714
736
|
const classesWithFilteredQueries = new Set();
|
|
715
737
|
const filteredQueriesForCompilationUnit = new Map();
|
|
@@ -721,7 +743,7 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
721
743
|
key: extractedQuery.id,
|
|
722
744
|
node: queryNode,
|
|
723
745
|
};
|
|
724
|
-
const containingFile =
|
|
746
|
+
const containingFile = index.projectFile(queryNode.getSourceFile(), info);
|
|
725
747
|
// If we have a config filter function, use it here for later
|
|
726
748
|
// perf-boosted reference lookups. Useful in non-batch mode.
|
|
727
749
|
if (this.config.shouldMigrateQuery === undefined ||
|
|
@@ -736,7 +758,7 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
736
758
|
isMulti: extractedQuery.queryInfo.first === false,
|
|
737
759
|
};
|
|
738
760
|
if (ts__default["default"].isAccessor(queryNode)) {
|
|
739
|
-
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, extractedQuery.id,
|
|
761
|
+
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, extractedQuery.id, migrate_ts_type_references.FieldIncompatibilityReason.Accessor);
|
|
740
762
|
}
|
|
741
763
|
// Detect queries with union types that are uncommon to be
|
|
742
764
|
// automatically migrate-able. E.g. `refs: ElementRef|null`,
|
|
@@ -746,7 +768,14 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
746
768
|
// Either too large union, or doesn't match `T|undefined`.
|
|
747
769
|
(queryNode.type.types.length > 2 ||
|
|
748
770
|
!queryNode.type.types.some((t) => t.kind === ts__default["default"].SyntaxKind.UndefinedKeyword))) {
|
|
749
|
-
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, extractedQuery.id,
|
|
771
|
+
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, extractedQuery.id, migrate_ts_type_references.FieldIncompatibilityReason.SignalQueries__IncompatibleMultiUnionType);
|
|
772
|
+
}
|
|
773
|
+
// Migrating fields with `@HostBinding` is incompatible as
|
|
774
|
+
// the host binding decorator does not invoke the signal.
|
|
775
|
+
const hostBindingDecorators = checker.getAngularDecorators(extractedQuery.fieldDecorators, ['HostBinding'],
|
|
776
|
+
/* isCore */ false);
|
|
777
|
+
if (hostBindingDecorators.length > 0) {
|
|
778
|
+
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, extractedQuery.id, migrate_ts_type_references.FieldIncompatibilityReason.SignalIncompatibleWithHostBinding);
|
|
750
779
|
}
|
|
751
780
|
}
|
|
752
781
|
};
|
|
@@ -774,15 +803,15 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
774
803
|
return descriptor;
|
|
775
804
|
},
|
|
776
805
|
};
|
|
777
|
-
groupedAstVisitor.register(
|
|
806
|
+
groupedAstVisitor.register(index.createFindAllSourceFileReferencesVisitor(info, checker$1, reflector, info.ngCompiler['resourceManager'], evaluator, templateTypeChecker, allFieldsOrKnownQueries,
|
|
778
807
|
// In non-batch mode, we know what inputs exist and can optimize the reference
|
|
779
808
|
// resolution significantly (for e.g. VSCode integration)— as we know what
|
|
780
809
|
// field names may be used to reference potential queries.
|
|
781
810
|
this.config.assumeNonBatch
|
|
782
811
|
? new Set(Array.from(filteredQueriesForCompilationUnit.values()).map((f) => f.fieldName))
|
|
783
812
|
: null, referenceResult).visitor);
|
|
784
|
-
const inheritanceGraph = new
|
|
785
|
-
|
|
813
|
+
const inheritanceGraph = new migrate_ts_type_references.InheritanceGraph(checker$1).expensivePopulate(info.sourceFiles);
|
|
814
|
+
migrate_ts_type_references.checkIncompatiblePatterns(inheritanceGraph, checker$1, groupedAstVisitor, {
|
|
786
815
|
...allFieldsOrKnownQueries,
|
|
787
816
|
isFieldIncompatible: (f) => res.potentialProblematicQueries[f.key]?.fieldReason !== null ||
|
|
788
817
|
res.potentialProblematicQueries[f.key]?.classReason !== null,
|
|
@@ -802,16 +831,16 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
802
831
|
// Determine incompatible queries based on problematic references
|
|
803
832
|
// we saw in TS code, templates or host bindings.
|
|
804
833
|
for (const ref of referenceResult.references) {
|
|
805
|
-
if (
|
|
806
|
-
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, ref.target.key,
|
|
834
|
+
if (index.isTsReference(ref) && ref.from.isWrite) {
|
|
835
|
+
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, ref.target.key, migrate_ts_type_references.FieldIncompatibilityReason.WriteAssignment);
|
|
807
836
|
}
|
|
808
|
-
if ((
|
|
809
|
-
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, ref.target.key,
|
|
837
|
+
if ((index.isTemplateReference(ref) || index.isHostBindingReference(ref)) && ref.from.isWrite) {
|
|
838
|
+
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, ref.target.key, migrate_ts_type_references.FieldIncompatibilityReason.WriteAssignment);
|
|
810
839
|
}
|
|
811
840
|
// TODO: Remove this when we support signal narrowing in templates.
|
|
812
841
|
// https://github.com/angular/angular/pull/55456.
|
|
813
|
-
if (
|
|
814
|
-
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, ref.target.key,
|
|
842
|
+
if (index.isTemplateReference(ref) && ref.from.isLikelyPartOfNarrowing) {
|
|
843
|
+
markFieldIncompatibleInMetadata(res.potentialProblematicQueries, ref.target.key, migrate_ts_type_references.FieldIncompatibilityReason.PotentiallyNarrowedInTemplateButNoSupportYet);
|
|
815
844
|
}
|
|
816
845
|
// Check for other incompatible query list accesses.
|
|
817
846
|
checkForIncompatibleQueryListAccesses(ref, res);
|
|
@@ -819,7 +848,7 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
819
848
|
if (this.config.assumeNonBatch) {
|
|
820
849
|
res.reusableAnalysisReferences = referenceResult.references;
|
|
821
850
|
}
|
|
822
|
-
return
|
|
851
|
+
return index.confirmAsSerializable(res);
|
|
823
852
|
}
|
|
824
853
|
async merge(units) {
|
|
825
854
|
const merged = {
|
|
@@ -851,11 +880,11 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
851
880
|
for (const unit of units) {
|
|
852
881
|
for (const id of Object.keys(unit.potentialProblematicReferenceForMultiQueries)) {
|
|
853
882
|
if (merged.knownQueryFields[id]?.isMulti) {
|
|
854
|
-
markFieldIncompatibleInMetadata(merged.problematicQueries, id,
|
|
883
|
+
markFieldIncompatibleInMetadata(merged.problematicQueries, id, migrate_ts_type_references.FieldIncompatibilityReason.SignalQueries__QueryListProblematicFieldAccessed);
|
|
855
884
|
}
|
|
856
885
|
}
|
|
857
886
|
}
|
|
858
|
-
return
|
|
887
|
+
return index.confirmAsSerializable(merged);
|
|
859
888
|
}
|
|
860
889
|
async migrate(globalMetadata, info) {
|
|
861
890
|
assert__default["default"](info.ngCompiler !== null, 'Expected queries migration to have an Angular program.');
|
|
@@ -909,21 +938,21 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
909
938
|
// lookups below.
|
|
910
939
|
const fieldNamesToConsiderForReferenceLookup = new Set(Object.values(globalMetadata.knownQueryFields).map((f) => f.fieldName));
|
|
911
940
|
// Find all references.
|
|
912
|
-
const groupedAstVisitor = new
|
|
941
|
+
const groupedAstVisitor = new migrate_ts_type_references.GroupedTsAstVisitor(sourceFiles);
|
|
913
942
|
// Re-use previous reference result if available, instead of
|
|
914
943
|
// looking for references which is quite expensive.
|
|
915
944
|
if (globalMetadata.reusableAnalysisReferences !== null) {
|
|
916
945
|
referenceResult.references = globalMetadata.reusableAnalysisReferences;
|
|
917
946
|
}
|
|
918
947
|
else {
|
|
919
|
-
groupedAstVisitor.register(
|
|
948
|
+
groupedAstVisitor.register(index.createFindAllSourceFileReferencesVisitor(info, checker$1, reflector, info.ngCompiler['resourceManager'], evaluator, templateTypeChecker, knownQueries, fieldNamesToConsiderForReferenceLookup, referenceResult).visitor);
|
|
920
949
|
}
|
|
921
950
|
// Check inheritance.
|
|
922
951
|
// NOTE: Inheritance is only checked in the migrate stage as we cannot reliably
|
|
923
952
|
// check during analyze— where we don't know what fields from foreign `.d.ts`
|
|
924
953
|
// files refer to queries or not.
|
|
925
|
-
const inheritanceGraph = new
|
|
926
|
-
|
|
954
|
+
const inheritanceGraph = new migrate_ts_type_references.InheritanceGraph(checker$1).expensivePopulate(info.sourceFiles);
|
|
955
|
+
migrate_ts_type_references.checkInheritanceOfKnownFields(inheritanceGraph, metaReader, knownQueries, {
|
|
927
956
|
getFieldsForClass: (n) => knownQueries.getQueryFieldsOfClass(n) ?? [],
|
|
928
957
|
isClassWithKnownFields: (clazz) => knownQueries.getQueryFieldsOfClass(clazz) !== undefined,
|
|
929
958
|
});
|
|
@@ -943,7 +972,7 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
943
972
|
if (incompatibility !== null) {
|
|
944
973
|
// Add a TODO for the incompatible query, if desired.
|
|
945
974
|
if (this.config.insertTodosForSkippedFields) {
|
|
946
|
-
replacements.push(...
|
|
975
|
+
replacements.push(...migrate_ts_type_references.insertTodoForIncompatibility(node, info, incompatibility, {
|
|
947
976
|
single: 'query',
|
|
948
977
|
plural: 'queries',
|
|
949
978
|
}));
|
|
@@ -951,7 +980,7 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
951
980
|
updateFileState(filesWithIncompleteMigration, sf, extractedQuery.kind);
|
|
952
981
|
continue;
|
|
953
982
|
}
|
|
954
|
-
replacements.push(...computeReplacementsToMigrateQuery(node, extractedQuery, importManager, info, printer));
|
|
983
|
+
replacements.push(...computeReplacementsToMigrateQuery(node, extractedQuery, importManager, info, printer, info.userOptions, checker$1));
|
|
955
984
|
}
|
|
956
985
|
// Migrate references.
|
|
957
986
|
const referenceMigrationHost = {
|
|
@@ -962,10 +991,10 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
962
991
|
.getQueryFieldsOfClass(clazz)
|
|
963
992
|
?.some((q) => !knownQueries.isFieldIncompatible(q)),
|
|
964
993
|
};
|
|
965
|
-
|
|
994
|
+
migrate_ts_type_references.migrateTypeScriptReferences(referenceMigrationHost, referenceResult.references, checker$1, info);
|
|
966
995
|
migrateTemplateReferences(referenceMigrationHost, referenceResult.references);
|
|
967
996
|
migrateHostBindings(referenceMigrationHost, referenceResult.references, info);
|
|
968
|
-
|
|
997
|
+
migrate_ts_type_references.migrateTypeScriptTypeReferences(referenceMigrationHost, referenceResult.references, importManager, info);
|
|
969
998
|
// Fix problematic calls, like `QueryList#toArray`, or `QueryList#get`.
|
|
970
999
|
for (const ref of referenceResult.references) {
|
|
971
1000
|
removeQueryListToArrayCall(ref, info, globalMetadata, knownQueries, replacements);
|
|
@@ -989,7 +1018,7 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
989
1018
|
importManager.removeImport(file, 'QueryList', '@angular/core');
|
|
990
1019
|
}
|
|
991
1020
|
}
|
|
992
|
-
|
|
1021
|
+
index.applyImportManagerChanges(importManager, replacements, sourceFiles, info);
|
|
993
1022
|
return { replacements, knownQueries };
|
|
994
1023
|
}
|
|
995
1024
|
async stats(globalMetadata) {
|
|
@@ -1010,13 +1039,13 @@ class SignalQueriesMigration extends group_replacements.TsurgeComplexMigration {
|
|
|
1010
1039
|
}
|
|
1011
1040
|
incompatibleQueries++;
|
|
1012
1041
|
if (info.classReason !== null) {
|
|
1013
|
-
const reasonName =
|
|
1042
|
+
const reasonName = migrate_ts_type_references.ClassIncompatibilityReason[info.classReason];
|
|
1014
1043
|
const key = `incompat-class-${reasonName}`;
|
|
1015
1044
|
classIncompatibleCounts[key] ??= 0;
|
|
1016
1045
|
classIncompatibleCounts[key]++;
|
|
1017
1046
|
}
|
|
1018
1047
|
if (info.fieldReason !== null) {
|
|
1019
|
-
const reasonName =
|
|
1048
|
+
const reasonName = migrate_ts_type_references.FieldIncompatibilityReason[info.fieldReason];
|
|
1020
1049
|
const key = `incompat-field-${reasonName}`;
|
|
1021
1050
|
fieldIncompatibleCounts[key] ??= 0;
|
|
1022
1051
|
fieldIncompatibleCounts[key]++;
|
|
@@ -1052,7 +1081,7 @@ function migrate(options) {
|
|
|
1052
1081
|
if (!buildPaths.length && !testPaths.length) {
|
|
1053
1082
|
throw new schematics.SchematicsException('Could not find any tsconfig file. Cannot run signal queries migration.');
|
|
1054
1083
|
}
|
|
1055
|
-
const fs = new
|
|
1084
|
+
const fs = new index.DevkitMigrationFilesystem(tree);
|
|
1056
1085
|
checker.setFileSystem(fs);
|
|
1057
1086
|
const migration = new SignalQueriesMigration({
|
|
1058
1087
|
bestEffortMode: options.bestEffortMode,
|
|
@@ -1089,7 +1118,7 @@ function migrate(options) {
|
|
|
1089
1118
|
for (const { info, tsconfigPath } of programInfos) {
|
|
1090
1119
|
context.logger.info(`Migrating: ${tsconfigPath}..`);
|
|
1091
1120
|
const { replacements } = await migration.migrate(merged, info);
|
|
1092
|
-
const changesPerFile =
|
|
1121
|
+
const changesPerFile = index.groupReplacementsByFile(replacements);
|
|
1093
1122
|
for (const [file, changes] of changesPerFile) {
|
|
1094
1123
|
if (!replacementsPerFile.has(file)) {
|
|
1095
1124
|
replacementsPerFile.set(file, changes);
|