@angular/core 19.0.0-next.8 → 19.0.0-next.9

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.
Files changed (30) hide show
  1. package/fesm2022/core.mjs +93 -13
  2. package/fesm2022/core.mjs.map +1 -1
  3. package/fesm2022/primitives/event-dispatch.mjs +1 -1
  4. package/fesm2022/primitives/signals.mjs +1 -1
  5. package/fesm2022/primitives/signals.mjs.map +1 -1
  6. package/fesm2022/rxjs-interop.mjs +1 -1
  7. package/fesm2022/testing.mjs +6 -4
  8. package/fesm2022/testing.mjs.map +1 -1
  9. package/index.d.ts +41 -18
  10. package/package.json +1 -1
  11. package/primitives/event-dispatch/index.d.ts +1 -1
  12. package/primitives/signals/index.d.ts +5 -1
  13. package/rxjs-interop/index.d.ts +1 -1
  14. package/schematics/bundles/{checker-e68dd7ce.js → checker-3b2ea20f.js} +124 -76
  15. package/schematics/bundles/{compiler_host-9a4d0c2b.js → compiler_host-b4ba5a28.js} +2 -2
  16. package/schematics/bundles/control-flow-migration.js +3 -3
  17. package/schematics/bundles/explicit-standalone-flag.js +3 -3
  18. package/schematics/bundles/{group_replacements-472b2387.js → group_replacements-e1b5cbf8.js} +234 -108
  19. package/schematics/bundles/imports-4ac08251.js +1 -1
  20. package/schematics/bundles/inject-migration.js +3 -3
  21. package/schematics/bundles/leading_space-d190b83b.js +1 -1
  22. package/schematics/bundles/nodes-0e7d45ca.js +1 -1
  23. package/schematics/bundles/pending-tasks.js +3 -3
  24. package/schematics/bundles/{program-105283c5.js → program-6534a30a.js} +67 -21
  25. package/schematics/bundles/project_tsconfig_paths-e9ccccbf.js +1 -1
  26. package/schematics/bundles/route-lazy-loading.js +3 -3
  27. package/schematics/bundles/signal-input-migration.js +147 -171
  28. package/schematics/bundles/signal-queries-migration.js +93 -74
  29. package/schematics/bundles/standalone-migration.js +5 -5
  30. package/testing/index.d.ts +3 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v19.0.0-next.8
3
+ * @license Angular v19.0.0-next.9
4
4
  * (c) 2010-2024 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
@@ -9,17 +9,17 @@
9
9
  Object.defineProperty(exports, '__esModule', { value: true });
10
10
 
11
11
  var schematics = require('@angular-devkit/schematics');
12
- var group_replacements = require('./group_replacements-472b2387.js');
12
+ var group_replacements = require('./group_replacements-e1b5cbf8.js');
13
13
  var ts = require('typescript');
14
14
  require('os');
15
- var checker = require('./checker-e68dd7ce.js');
16
- var program = require('./program-105283c5.js');
15
+ var checker = require('./checker-3b2ea20f.js');
16
+ var program = require('./program-6534a30a.js');
17
17
  require('path');
18
18
  var assert = require('assert');
19
19
  var leading_space = require('./leading_space-d190b83b.js');
20
20
  var project_tsconfig_paths = require('./project_tsconfig_paths-e9ccccbf.js');
21
21
  require('@angular-devkit/core');
22
- require('node:path');
22
+ require('node:path/posix');
23
23
  require('fs');
24
24
  require('module');
25
25
  require('url');
@@ -29,100 +29,6 @@ function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'defau
29
29
  var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts);
30
30
  var assert__default = /*#__PURE__*/_interopDefaultLegacy(assert);
31
31
 
32
- /**
33
- * Gets human-readable message information for the given input incompatibility.
34
- * This text will be used by the language service, or CLI-based migration.
35
- */
36
- function getMessageForInputIncompatibility(reason) {
37
- switch (reason) {
38
- case group_replacements.InputIncompatibilityReason.Accessor:
39
- return {
40
- short: 'Accessor inputs cannot be migrated as they are too complex.',
41
- extra: 'The migration potentially requires usage of `effect` or `computed`, but ' +
42
- 'the intent is unclear. The migration cannot safely migrate.',
43
- };
44
- case group_replacements.InputIncompatibilityReason.OverriddenByDerivedClass:
45
- return {
46
- short: 'The input cannot be migrated because the field is overridden by a subclass.',
47
- extra: 'The field in the subclass is not an input, so migrating would break your build.',
48
- };
49
- case group_replacements.InputIncompatibilityReason.ParentIsIncompatible:
50
- return {
51
- short: 'This input is inherited from a superclass, but the parent cannot be migrated.',
52
- extra: 'Migrating this input would cause your build to fail.',
53
- };
54
- case group_replacements.InputIncompatibilityReason.PotentiallyNarrowedInTemplateButNoSupportYet:
55
- return {
56
- short: 'This input is used in a control flow expression (e.g. `@if` or `*ngIf`) and ' +
57
- 'migrating would break narrowing currently.',
58
- extra: `In the future, Angular intends to support narrowing of signals.`,
59
- };
60
- case group_replacements.InputIncompatibilityReason.RedeclaredViaDerivedClassInputsArray:
61
- return {
62
- short: 'The input is overridden by a subclass that cannot be migrated.',
63
- extra: 'The subclass re-declares this input via the `inputs` array in @Directive/@Component. ' +
64
- 'Migrating this input would break your build because the subclass input cannot be migrated.',
65
- };
66
- case group_replacements.InputIncompatibilityReason.RequiredInputButNoGoodExplicitTypeExtractable:
67
- return {
68
- short: `Input is required, but the migration cannot determine a good type for the input.`,
69
- extra: 'Consider adding an explicit type to make the migration possible.',
70
- };
71
- case group_replacements.InputIncompatibilityReason.InputWithQuestionMarkButNoGoodExplicitTypeExtractable:
72
- return {
73
- short: `Input is marked with a question mark. Migration could not determine a good type for the input.`,
74
- extra: 'The migration needs to be able to resolve a type, so that it can include `undefined` in your type. ' +
75
- 'Consider adding an explicit type to make the migration possible.',
76
- };
77
- case group_replacements.InputIncompatibilityReason.SkippedViaConfigFilter:
78
- return {
79
- short: `This input is not part of the current migration scope.`,
80
- extra: 'Skipped via migration config.',
81
- };
82
- case group_replacements.InputIncompatibilityReason.SpyOnThatOverwritesField:
83
- return {
84
- short: 'A jasmine `spyOn` call spies on this input. This breaks with signal inputs.',
85
- extra: `Migration cannot safely migrate as "spyOn" writes to the input. Signal inputs are readonly.`,
86
- };
87
- case group_replacements.InputIncompatibilityReason.TypeConflictWithBaseClass:
88
- return {
89
- short: 'This input overrides a field from a superclass, while the superclass field is not migrated.',
90
- extra: 'Migrating the input would break your build because of a type conflict then.',
91
- };
92
- case group_replacements.InputIncompatibilityReason.WriteAssignment:
93
- return {
94
- short: 'Your application code writes to the input. This prevents migration.',
95
- extra: 'Signal inputs are readonly, so migrating would break your build.',
96
- };
97
- case group_replacements.InputIncompatibilityReason.OutsideOfMigrationScope:
98
- return {
99
- short: 'This input is not part of any source files in your project.',
100
- extra: 'The migration excludes inputs if no source file declaring the input was seen.',
101
- };
102
- }
103
- }
104
- /**
105
- * Gets human-readable message information for the given input class incompatibility.
106
- * This text will be used by the language service, or CLI-based migration.
107
- */
108
- function getMessageForClassIncompatibility(reason) {
109
- switch (reason) {
110
- case group_replacements.ClassIncompatibilityReason.InputOwningClassReferencedInClassProperty:
111
- return {
112
- short: 'Class of this input is referenced in the signature of another class.',
113
- extra: 'The other class is likely typed to expect a non-migrated field, so ' +
114
- 'migration is skipped to not break your build.',
115
- };
116
- case group_replacements.ClassIncompatibilityReason.ClassManuallyInstantiated:
117
- return {
118
- short: 'Class of this input is manually instantiated. ' +
119
- 'This is discouraged and prevents migration',
120
- extra: 'Signal inputs require a DI injection context. Manually instantiating ' +
121
- 'breaks this requirement in some cases, so the migration is skipped.',
122
- };
123
- }
124
- }
125
-
126
32
  /**
127
33
  * Class that holds information about a given directive and its input fields.
128
34
  */
@@ -145,11 +51,13 @@ class DirectiveInfo {
145
51
  this.incompatible = null;
146
52
  }
147
53
  /**
148
- * Checks whether there are any incompatible inputs for the
54
+ * Checks whether there are any migrated inputs for the
149
55
  * given class.
56
+ *
57
+ * Returns `false` if all inputs are incompatible.
150
58
  */
151
- hasIncompatibleMembers() {
152
- return Array.from(this.inputFields.values()).some(({ descriptor }) => this.isInputMemberIncompatible(descriptor));
59
+ hasMigratedFields() {
60
+ return Array.from(this.inputFields.values()).some(({ descriptor }) => !this.isInputMemberIncompatible(descriptor));
153
61
  }
154
62
  /**
155
63
  * Whether the given input member is incompatible. If the class is incompatible,
@@ -300,8 +208,8 @@ class KnownInputs {
300
208
  const inputInfo = this.knownInputIds.get(input.key);
301
209
  const existingIncompatibility = inputInfo.container.getInputMemberIncompatibility(input);
302
210
  // Ensure an existing more significant incompatibility is not overridden.
303
- if (existingIncompatibility !== null && group_replacements.isInputMemberIncompatibility(existingIncompatibility)) {
304
- incompatibility = group_replacements.pickInputIncompatibility(existingIncompatibility, incompatibility);
211
+ if (existingIncompatibility !== null && group_replacements.isFieldIncompatibility(existingIncompatibility)) {
212
+ incompatibility = group_replacements.pickFieldIncompatibility(existingIncompatibility, incompatibility);
305
213
  }
306
214
  this.knownInputIds
307
215
  .get(input.key)
@@ -329,13 +237,13 @@ class KnownInputs {
329
237
  captureUnknownDerivedField(field) {
330
238
  this.markFieldIncompatible(field, {
331
239
  context: null,
332
- reason: group_replacements.InputIncompatibilityReason.OverriddenByDerivedClass,
240
+ reason: group_replacements.FieldIncompatibilityReason.OverriddenByDerivedClass,
333
241
  });
334
242
  }
335
243
  captureUnknownParentField(field) {
336
244
  this.markFieldIncompatible(field, {
337
245
  context: null,
338
- reason: group_replacements.InputIncompatibilityReason.TypeConflictWithBaseClass,
246
+ reason: group_replacements.FieldIncompatibilityReason.TypeConflictWithBaseClass,
339
247
  });
340
248
  }
341
249
  }
@@ -527,7 +435,7 @@ function prepareAndCheckForConversion(node, metadata, checker, options) {
527
435
  if (ts__default["default"].isAccessor(node)) {
528
436
  return {
529
437
  context: node,
530
- reason: group_replacements.InputIncompatibilityReason.Accessor,
438
+ reason: group_replacements.FieldIncompatibilityReason.Accessor,
531
439
  };
532
440
  }
533
441
  assert__default["default"](metadata.inputDecorator !== null, 'Expected an input decorator for inputs that are being migrated.');
@@ -566,7 +474,7 @@ function prepareAndCheckForConversion(node, metadata, checker, options) {
566
474
  if (typeToAdd === undefined) {
567
475
  return {
568
476
  context: node,
569
- reason: group_replacements.InputIncompatibilityReason.InputWithQuestionMarkButNoGoodExplicitTypeExtractable,
477
+ reason: group_replacements.FieldIncompatibilityReason.SignalInput__QuestionMarkButNoGoodExplicitTypeExtractable,
570
478
  };
571
479
  }
572
480
  if (!checker.isTypeAssignableTo(checker.getUndefinedType(), checker.getTypeFromTypeNode(typeToAdd))) {
@@ -607,7 +515,7 @@ function prepareAndCheckForConversion(node, metadata, checker, options) {
607
515
  // the generated type might depend on imports that we cannot add here (nor want).
608
516
  return {
609
517
  context: node,
610
- reason: group_replacements.InputIncompatibilityReason.RequiredInputButNoGoodExplicitTypeExtractable,
518
+ reason: group_replacements.FieldIncompatibilityReason.SignalInput__RequiredButNoGoodExplicitTypeExtractable,
611
519
  };
612
520
  }
613
521
  }
@@ -667,7 +575,7 @@ function pass1__IdentifySourceFileAndDeclarationInputs(sf, host, checker, reflec
667
575
  // these are then later migrated in the migration phase.
668
576
  if (decoratorInput.inSourceFile && host.isSourceFileForCurrentMigration(sf)) {
669
577
  const conversionPreparation = prepareAndCheckForConversion(node, decoratorInput, checker, host.compilerOptions);
670
- if (group_replacements.isInputMemberIncompatibility(conversionPreparation)) {
578
+ if (group_replacements.isFieldIncompatibility(conversionPreparation)) {
671
579
  knownDecoratorInputs.markFieldIncompatible(inputDescr, conversionPreparation);
672
580
  result.sourceInputs.set(inputDescr, null);
673
581
  }
@@ -761,14 +669,14 @@ function executeAnalysisPhase(host, knownInputs, result, { sourceFiles, fullProg
761
669
  for (const reference of result.references) {
762
670
  if (group_replacements.isTsReference(reference) && reference.from.isWrite) {
763
671
  knownInputs.markFieldIncompatible(reference.target, {
764
- reason: group_replacements.InputIncompatibilityReason.WriteAssignment,
672
+ reason: group_replacements.FieldIncompatibilityReason.WriteAssignment,
765
673
  context: reference.from.node,
766
674
  });
767
675
  }
768
676
  if (group_replacements.isTemplateReference(reference) || group_replacements.isHostBindingReference(reference)) {
769
677
  if (reference.from.isWrite) {
770
678
  knownInputs.markFieldIncompatible(reference.target, {
771
- reason: group_replacements.InputIncompatibilityReason.WriteAssignment,
679
+ reason: group_replacements.FieldIncompatibilityReason.WriteAssignment,
772
680
  // No TS node context available for template or host bindings.
773
681
  context: null,
774
682
  });
@@ -779,7 +687,7 @@ function executeAnalysisPhase(host, knownInputs, result, { sourceFiles, fullProg
779
687
  if (group_replacements.isTemplateReference(reference)) {
780
688
  if (reference.from.isLikelyPartOfNarrowing) {
781
689
  knownInputs.markFieldIncompatible(reference.target, {
782
- reason: group_replacements.InputIncompatibilityReason.PotentiallyNarrowedInTemplateButNoSupportYet,
690
+ reason: group_replacements.FieldIncompatibilityReason.PotentiallyNarrowedInTemplateButNoSupportYet,
783
691
  context: null,
784
692
  });
785
693
  }
@@ -921,7 +829,7 @@ function mergeCompilationUnitData(metadataFiles) {
921
829
  else {
922
830
  // Input might not be incompatible in one target, but others might invalidate it.
923
831
  // merge the incompatibility state.
924
- existing.memberIncompatibility = group_replacements.pickInputIncompatibility({ reason: info.memberIncompatibility, context: null }, { reason: existing.memberIncompatibility, context: null }).reason;
832
+ existing.memberIncompatibility = group_replacements.pickFieldIncompatibility({ reason: info.memberIncompatibility, context: null }, { reason: existing.memberIncompatibility, context: null }).reason;
925
833
  }
926
834
  }
927
835
  // Merge incompatibility of the class owning the input.
@@ -953,7 +861,7 @@ function mergeCompilationUnitData(metadataFiles) {
953
861
  // If parent is incompatible and not migrated, then this input
954
862
  // cannot be migrated either. Try propagating parent incompatibility then.
955
863
  if (isNodeIncompatible(parent.data)) {
956
- node.data.info.memberIncompatibility = group_replacements.pickInputIncompatibility({ reason: group_replacements.InputIncompatibilityReason.ParentIsIncompatible, context: null }, existingMemberIncompatibility).reason;
864
+ node.data.info.memberIncompatibility = group_replacements.pickFieldIncompatibility({ reason: group_replacements.FieldIncompatibilityReason.ParentIsIncompatible, context: null }, existingMemberIncompatibility).reason;
957
865
  break;
958
866
  }
959
867
  }
@@ -965,7 +873,7 @@ function mergeCompilationUnitData(metadataFiles) {
965
873
  const existingMemberIncompatibility = info.memberIncompatibility !== null
966
874
  ? { reason: info.memberIncompatibility, context: null }
967
875
  : null;
968
- info.memberIncompatibility = group_replacements.pickInputIncompatibility({ reason: group_replacements.InputIncompatibilityReason.OutsideOfMigrationScope, context: null }, existingMemberIncompatibility).reason;
876
+ info.memberIncompatibility = group_replacements.pickFieldIncompatibility({ reason: group_replacements.FieldIncompatibilityReason.OutsideOfMigrationScope, context: null }, existingMemberIncompatibility).reason;
969
877
  }
970
878
  }
971
879
  return result;
@@ -1154,6 +1062,102 @@ function extractTransformOfInput(transform, resolvedType, checker) {
1154
1062
  };
1155
1063
  }
1156
1064
 
1065
+ /**
1066
+ * Gets human-readable message information for the given field incompatibility.
1067
+ * This text will be used by the language service, or CLI-based migration.
1068
+ */
1069
+ function getMessageForFieldIncompatibility(reason, fieldName) {
1070
+ switch (reason) {
1071
+ case group_replacements.FieldIncompatibilityReason.Accessor:
1072
+ return {
1073
+ short: `Accessor ${fieldName.plural} cannot be migrated as they are too complex.`,
1074
+ extra: 'The migration potentially requires usage of `effect` or `computed`, but ' +
1075
+ 'the intent is unclear. The migration cannot safely migrate.',
1076
+ };
1077
+ case group_replacements.FieldIncompatibilityReason.OverriddenByDerivedClass:
1078
+ return {
1079
+ short: `The ${fieldName.single} cannot be migrated because the field is overridden by a subclass.`,
1080
+ extra: 'The field in the subclass is not a signal, so migrating would break your build.',
1081
+ };
1082
+ case group_replacements.FieldIncompatibilityReason.ParentIsIncompatible:
1083
+ return {
1084
+ short: `This ${fieldName.single} is inherited from a superclass, but the parent cannot be migrated.`,
1085
+ extra: 'Migrating this field would cause your build to fail.',
1086
+ };
1087
+ case group_replacements.FieldIncompatibilityReason.PotentiallyNarrowedInTemplateButNoSupportYet:
1088
+ return {
1089
+ short: `This ${fieldName.single} is used in a control flow expression (e.g. \`@if\` or \`*ngIf\`) and ` +
1090
+ 'migrating would break narrowing currently.',
1091
+ extra: `In the future, Angular intends to support narrowing of signals.`,
1092
+ };
1093
+ case group_replacements.FieldIncompatibilityReason.RedeclaredViaDerivedClassInputsArray:
1094
+ return {
1095
+ short: `The ${fieldName.single} is overridden by a subclass that cannot be migrated.`,
1096
+ extra: `The subclass overrides this ${fieldName.single} via the \`inputs\` array in @Directive/@Component. ` +
1097
+ 'Migrating the field would break your build because the subclass field cannot be a signal.',
1098
+ };
1099
+ case group_replacements.FieldIncompatibilityReason.SignalInput__RequiredButNoGoodExplicitTypeExtractable:
1100
+ return {
1101
+ short: `Input is required, but the migration cannot determine a good type for the input.`,
1102
+ extra: 'Consider adding an explicit type to make the migration possible.',
1103
+ };
1104
+ case group_replacements.FieldIncompatibilityReason.SignalInput__QuestionMarkButNoGoodExplicitTypeExtractable:
1105
+ return {
1106
+ short: `Input is marked with a question mark. Migration could not determine a good type for the input.`,
1107
+ extra: 'The migration needs to be able to resolve a type, so that it can include `undefined` in your type. ' +
1108
+ 'Consider adding an explicit type to make the migration possible.',
1109
+ };
1110
+ case group_replacements.FieldIncompatibilityReason.SkippedViaConfigFilter:
1111
+ return {
1112
+ short: `This ${fieldName.single} is not part of the current migration scope.`,
1113
+ extra: 'Skipped via migration config.',
1114
+ };
1115
+ case group_replacements.FieldIncompatibilityReason.SpyOnThatOverwritesField:
1116
+ return {
1117
+ short: 'A jasmine `spyOn` call spies on this field. This breaks with signals.',
1118
+ extra: `Migration cannot safely migrate as "spyOn" writes to the ${fieldName.single}. ` +
1119
+ `Signal ${fieldName.plural} are readonly.`,
1120
+ };
1121
+ case group_replacements.FieldIncompatibilityReason.TypeConflictWithBaseClass:
1122
+ return {
1123
+ short: `This ${fieldName.single} overrides a field from a superclass, while the superclass ` +
1124
+ `field is not migrated.`,
1125
+ extra: 'Migrating the field would break your build because of a type conflict.',
1126
+ };
1127
+ case group_replacements.FieldIncompatibilityReason.WriteAssignment:
1128
+ return {
1129
+ short: `Your application code writes to the ${fieldName.single}. This prevents migration.`,
1130
+ extra: `Signal ${fieldName.plural} are readonly, so migrating would break your build.`,
1131
+ };
1132
+ case group_replacements.FieldIncompatibilityReason.OutsideOfMigrationScope:
1133
+ return {
1134
+ short: `This ${fieldName.single} is not part of any source files in your project.`,
1135
+ extra: `The migration excludes ${fieldName.plural} if no source file declaring them was seen.`,
1136
+ };
1137
+ }
1138
+ }
1139
+ /**
1140
+ * Gets human-readable message information for the given class incompatibility.
1141
+ * This text will be used by the language service, or CLI-based migration.
1142
+ */
1143
+ function getMessageForClassIncompatibility(reason, fieldName) {
1144
+ switch (reason) {
1145
+ case group_replacements.ClassIncompatibilityReason.OwningClassReferencedInClassProperty:
1146
+ return {
1147
+ short: `Class of this ${fieldName.single} is referenced in the signature of another class.`,
1148
+ extra: 'The other class is likely typed to expect a non-migrated field, so ' +
1149
+ 'migration is skipped to not break your build.',
1150
+ };
1151
+ case group_replacements.ClassIncompatibilityReason.ClassManuallyInstantiated:
1152
+ return {
1153
+ short: `Class of this ${fieldName.single} is manually instantiated. ` +
1154
+ 'This is discouraged and prevents migration',
1155
+ extra: `Signal ${fieldName.plural} require a DI injection context. Manually instantiating ` +
1156
+ 'breaks this requirement in some cases, so the migration is skipped.',
1157
+ };
1158
+ }
1159
+ }
1160
+
1157
1161
  /**
1158
1162
  * Inserts a TODO for the incompatibility blocking the given node
1159
1163
  * from being migrated.
@@ -1165,14 +1169,15 @@ function insertTodoForIncompatibility(node, programInfo, input) {
1165
1169
  }
1166
1170
  // If an input is skipped via config filter or outside migration scope, do not
1167
1171
  // insert TODOs, as this could results in lots of unnecessary comments.
1168
- if (group_replacements.isInputMemberIncompatibility(incompatibility) &&
1169
- (incompatibility.reason === group_replacements.InputIncompatibilityReason.SkippedViaConfigFilter ||
1170
- incompatibility.reason === group_replacements.InputIncompatibilityReason.OutsideOfMigrationScope)) {
1172
+ if (group_replacements.isFieldIncompatibility(incompatibility) &&
1173
+ (incompatibility.reason === group_replacements.FieldIncompatibilityReason.SkippedViaConfigFilter ||
1174
+ incompatibility.reason === group_replacements.FieldIncompatibilityReason.OutsideOfMigrationScope)) {
1171
1175
  return [];
1172
1176
  }
1173
- const message = group_replacements.isInputMemberIncompatibility(incompatibility)
1174
- ? getMessageForInputIncompatibility(incompatibility.reason).short
1175
- : getMessageForClassIncompatibility(incompatibility).short;
1177
+ const message = group_replacements.isFieldIncompatibility(incompatibility)
1178
+ ? getMessageForFieldIncompatibility(incompatibility.reason, { single: 'input', plural: 'inputs' })
1179
+ .short
1180
+ : getMessageForClassIncompatibility(incompatibility, { single: 'input', plural: 'inputs' }).short;
1176
1181
  const lines = cutStringToLineLimit(message, 70);
1177
1182
  return [
1178
1183
  insertPrecedingLine(node, programInfo, `// TODO: Skipped for migration because:`),
@@ -1306,43 +1311,7 @@ function pass8__migrateHostBindings(host, references, info) {
1306
1311
  in Catalyst test files.
1307
1312
  */
1308
1313
  function pass9__migrateTypeScriptTypeReferences(host, references, importManager, info) {
1309
- const seenTypeNodes = new WeakSet();
1310
- for (const reference of references) {
1311
- // This pass only deals with TS input class type references.
1312
- if (!group_replacements.isTsClassTypeReference(reference)) {
1313
- continue;
1314
- }
1315
- // Skip references to classes that are not fully migrated.
1316
- if (!host.shouldMigrateReferencesToClass(reference.target)) {
1317
- continue;
1318
- }
1319
- // Skip duplicate references. E.g. in batching.
1320
- if (seenTypeNodes.has(reference.from.node)) {
1321
- continue;
1322
- }
1323
- seenTypeNodes.add(reference.from.node);
1324
- if (reference.isPartialReference && reference.isPartOfCatalystFile) {
1325
- assert__default["default"](reference.from.node.typeArguments, 'Expected type arguments for partial reference.');
1326
- assert__default["default"](reference.from.node.typeArguments.length === 1, 'Expected an argument for reference.');
1327
- const firstArg = reference.from.node.typeArguments[0];
1328
- const sf = firstArg.getSourceFile();
1329
- // Naive detection of the import. Sufficient for this test file migration.
1330
- const catalystImport = sf.text.includes('google3/javascript/angular2/testing/catalyst/fake_async')
1331
- ? 'google3/javascript/angular2/testing/catalyst/fake_async'
1332
- : 'google3/javascript/angular2/testing/catalyst/async';
1333
- const unwrapImportExpr = importManager.addImport({
1334
- exportModuleSpecifier: catalystImport,
1335
- exportSymbolName: 'UnwrapSignalInputs',
1336
- requestedFile: sf,
1337
- });
1338
- host.replacements.push(new group_replacements.Replacement(group_replacements.projectFile(sf, info), new group_replacements.TextUpdate({
1339
- position: firstArg.getStart(),
1340
- end: firstArg.getStart(),
1341
- toInsert: `${host.printer.printNode(ts__default["default"].EmitHint.Unspecified, unwrapImportExpr, sf)}<`,
1342
- })));
1343
- host.replacements.push(new group_replacements.Replacement(group_replacements.projectFile(sf, info), new group_replacements.TextUpdate({ position: firstArg.getEnd(), end: firstArg.getEnd(), toInsert: '>' })));
1344
- }
1345
- }
1314
+ group_replacements.migrateTypeScriptTypeReferences(host, references, importManager, info);
1346
1315
  }
1347
1316
 
1348
1317
  /**
@@ -1366,7 +1335,7 @@ function executeMigrationPhase(host, knownInputs, result, info) {
1366
1335
  replacements: result.replacements,
1367
1336
  shouldMigrateReferencesToField: (inputDescr) => knownInputs.has(inputDescr) && knownInputs.get(inputDescr).isIncompatible() === false,
1368
1337
  shouldMigrateReferencesToClass: (clazz) => knownInputs.getDirectiveInfoForClass(clazz) !== undefined &&
1369
- knownInputs.getDirectiveInfoForClass(clazz).hasIncompatibleMembers() === false,
1338
+ knownInputs.getDirectiveInfoForClass(clazz).hasMigratedFields(),
1370
1339
  };
1371
1340
  // Migrate passes.
1372
1341
  pass5__migrateTypeScriptReferences(referenceMigrationHost, result.references, typeChecker, info);
@@ -1380,13 +1349,14 @@ function executeMigrationPhase(host, knownInputs, result, info) {
1380
1349
  /** Input reasons that cannot be ignored. */
1381
1350
  const nonIgnorableInputIncompatibilities = [
1382
1351
  // Outside of scope inputs should not be migrated. E.g. references to inputs in `node_modules/`.
1383
- group_replacements.InputIncompatibilityReason.OutsideOfMigrationScope,
1352
+ group_replacements.FieldIncompatibilityReason.OutsideOfMigrationScope,
1384
1353
  // Explicitly filtered inputs cannot be skipped via best effort mode.
1385
- group_replacements.InputIncompatibilityReason.SkippedViaConfigFilter,
1354
+ group_replacements.FieldIncompatibilityReason.SkippedViaConfigFilter,
1386
1355
  // There is no good output for accessor inputs.
1387
- group_replacements.InputIncompatibilityReason.Accessor,
1356
+ group_replacements.FieldIncompatibilityReason.Accessor,
1388
1357
  // There is no good output for such inputs. We can't perform "conversion".
1389
- group_replacements.InputIncompatibilityReason.RequiredInputButNoGoodExplicitTypeExtractable,
1358
+ group_replacements.FieldIncompatibilityReason.SignalInput__RequiredButNoGoodExplicitTypeExtractable,
1359
+ group_replacements.FieldIncompatibilityReason.SignalInput__QuestionMarkButNoGoodExplicitTypeExtractable,
1390
1360
  ];
1391
1361
  /** Filters ignorable input incompatibilities when best effort mode is enabled. */
1392
1362
  function filterIncompatibilitiesForBestEffortMode(knownInputs) {
@@ -1472,7 +1442,7 @@ class SignalInputMigration extends group_replacements.TsurgeComplexMigration {
1472
1442
  // Non-batch mode!
1473
1443
  if (this.config.upgradeAnalysisPhaseToAvoidBatch) {
1474
1444
  const merged = await this.merge([unitData]);
1475
- const replacements = await this.migrate(merged, info, {
1445
+ const { replacements } = await this.migrate(merged, info, {
1476
1446
  knownInputs,
1477
1447
  result,
1478
1448
  host,
@@ -1507,7 +1477,7 @@ class SignalInputMigration extends group_replacements.TsurgeComplexMigration {
1507
1477
  }
1508
1478
  this.config.reportProgressFn?.(60, 'Collecting migration changes..');
1509
1479
  executeMigrationPhase(host, knownInputs, result, analysisDeps);
1510
- return result.replacements;
1480
+ return { replacements: result.replacements };
1511
1481
  }
1512
1482
  async stats(globalMetadata) {
1513
1483
  let fullCompilationInputs = 0;
@@ -1517,14 +1487,20 @@ class SignalInputMigration extends group_replacements.TsurgeComplexMigration {
1517
1487
  const classIncompatibleCounts = {};
1518
1488
  for (const [id, input] of Object.entries(globalMetadata.knownInputs)) {
1519
1489
  fullCompilationInputs++;
1520
- if (input.seenAsSourceInput) {
1521
- sourceInputs++;
1490
+ const isConsideredSourceInput = input.seenAsSourceInput &&
1491
+ input.memberIncompatibility !== group_replacements.FieldIncompatibilityReason.OutsideOfMigrationScope &&
1492
+ input.memberIncompatibility !== group_replacements.FieldIncompatibilityReason.SkippedViaConfigFilter;
1493
+ // We won't track incompatibilities to inputs that aren't considered source inputs.
1494
+ // Tracking their statistics wouldn't provide any value.
1495
+ if (!isConsideredSourceInput) {
1496
+ continue;
1522
1497
  }
1498
+ sourceInputs++;
1523
1499
  if (input.memberIncompatibility !== null || input.owningClassIncompatibility !== null) {
1524
1500
  incompatibleInputs++;
1525
1501
  }
1526
1502
  if (input.memberIncompatibility !== null) {
1527
- const reasonName = group_replacements.InputIncompatibilityReason[input.memberIncompatibility];
1503
+ const reasonName = group_replacements.FieldIncompatibilityReason[input.memberIncompatibility];
1528
1504
  const key = `input-field-incompatibility-${reasonName}`;
1529
1505
  fieldIncompatibleCounts[key] ??= 0;
1530
1506
  fieldIncompatibleCounts[key]++;
@@ -1562,7 +1538,7 @@ function filterInputsViaConfig(result, knownInputs, config) {
1562
1538
  skippedInputs.add(input.descriptor.key);
1563
1539
  knownInputs.markFieldIncompatible(input.descriptor, {
1564
1540
  context: null,
1565
- reason: group_replacements.InputIncompatibilityReason.SkippedViaConfigFilter,
1541
+ reason: group_replacements.FieldIncompatibilityReason.SkippedViaConfigFilter,
1566
1542
  });
1567
1543
  }
1568
1544
  }
@@ -1622,7 +1598,7 @@ function migrate(options) {
1622
1598
  const replacementsPerFile = new Map();
1623
1599
  for (const { info, tsconfigPath } of programInfos) {
1624
1600
  context.logger.info(`Migrating: ${tsconfigPath}..`);
1625
- const replacements = await migration.migrate(merged, info);
1601
+ const { replacements } = await migration.migrate(merged, info);
1626
1602
  const changesPerFile = group_replacements.groupReplacementsByFile(replacements);
1627
1603
  for (const [file, changes] of changesPerFile) {
1628
1604
  if (!replacementsPerFile.has(file)) {