@angular/core 21.0.0-next.3 → 21.0.0-next.5

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 (78) hide show
  1. package/api.d.d.ts +7 -4
  2. package/chrome_dev_tools_performance.d.d.ts +1 -1
  3. package/discovery.d.d.ts +48 -21
  4. package/effect.d.d.ts +1 -2
  5. package/event_dispatcher.d.d.ts +1 -1
  6. package/fesm2022/attribute.mjs +1 -1
  7. package/fesm2022/attribute.mjs.map +1 -1
  8. package/fesm2022/core.mjs +228 -72
  9. package/fesm2022/core.mjs.map +1 -1
  10. package/fesm2022/debug_node.mjs +564 -747
  11. package/fesm2022/debug_node.mjs.map +1 -1
  12. package/fesm2022/effect.mjs +3 -4
  13. package/fesm2022/effect.mjs.map +1 -1
  14. package/fesm2022/not_found.mjs +1 -1
  15. package/fesm2022/not_found.mjs.map +1 -1
  16. package/fesm2022/primitives/di.mjs +1 -1
  17. package/fesm2022/primitives/di.mjs.map +1 -1
  18. package/fesm2022/primitives/event-dispatch.mjs +1 -1
  19. package/fesm2022/primitives/event-dispatch.mjs.map +1 -1
  20. package/fesm2022/primitives/signals.mjs +4 -5
  21. package/fesm2022/primitives/signals.mjs.map +1 -1
  22. package/fesm2022/resource.mjs +5 -4
  23. package/fesm2022/resource.mjs.map +1 -1
  24. package/fesm2022/root_effect_scheduler.mjs +61 -45
  25. package/fesm2022/root_effect_scheduler.mjs.map +1 -1
  26. package/fesm2022/rxjs-interop.mjs +3 -1
  27. package/fesm2022/rxjs-interop.mjs.map +1 -1
  28. package/fesm2022/signal.mjs +32 -11
  29. package/fesm2022/signal.mjs.map +1 -1
  30. package/fesm2022/testing.mjs +4 -4
  31. package/fesm2022/testing.mjs.map +1 -1
  32. package/fesm2022/weak_ref.mjs +1 -1
  33. package/fesm2022/weak_ref.mjs.map +1 -1
  34. package/graph.d.d.ts +24 -4
  35. package/index.d.ts +19 -140
  36. package/package.json +2 -2
  37. package/primitives/di/index.d.ts +1 -1
  38. package/primitives/event-dispatch/index.d.ts +1 -1
  39. package/primitives/signals/index.d.ts +2 -3
  40. package/rxjs-interop/index.d.ts +3 -1
  41. package/schematics/bundles/add-bootstrap-context-to-server-main.cjs +5 -5
  42. package/schematics/bundles/application-config-core.cjs +6 -6
  43. package/schematics/bundles/{apply_import_manager-tNexl58m.cjs → apply_import_manager-Bx60Uquz.cjs} +3 -3
  44. package/schematics/bundles/bootstrap-options-migration.cjs +637 -0
  45. package/schematics/bundles/cleanup-unused-imports.cjs +5 -5
  46. package/schematics/bundles/{compiler_host-Df7s6Riz.cjs → compiler_host-Aouk-n4F.cjs} +2 -2
  47. package/schematics/bundles/control-flow-migration.cjs +71 -39
  48. package/schematics/bundles/{imports-26VeX8i-.cjs → imports-DwPXlGFl.cjs} +27 -1
  49. package/schematics/bundles/{index-Clvp4COX.cjs → index-BZQb51Qf.cjs} +4 -4
  50. package/schematics/bundles/{index-CBaykQBv.cjs → index-Bb6iejCd.cjs} +130 -41
  51. package/schematics/bundles/inject-migration.cjs +5 -5
  52. package/schematics/bundles/leading_space-D9nQ8UQC.cjs +1 -1
  53. package/schematics/bundles/{migrate_ts_type_references-C_gTvDtH.cjs → migrate_ts_type_references-By2ZtKls.cjs} +5 -5
  54. package/schematics/bundles/{ng_component_template-HYGPuVhy.cjs → ng_component_template-B4M8mTyv.cjs} +3 -3
  55. package/schematics/bundles/{ng_decorators-CtYwz9Lw.cjs → ng_decorators-BI0uV7KI.cjs} +2 -2
  56. package/schematics/bundles/ngclass-to-class-migration.cjs +110 -98
  57. package/schematics/bundles/ngstyle-to-style-migration.cjs +490 -0
  58. package/schematics/bundles/nodes-B16H9JUd.cjs +1 -1
  59. package/schematics/bundles/output-migration.cjs +6 -6
  60. package/schematics/bundles/parse_html-7Wl_HDnw.cjs +132 -0
  61. package/schematics/bundles/{project_paths-BJTqcWvC.cjs → project_paths-Dr2s3Pq3.cjs} +3 -3
  62. package/schematics/bundles/{project_tsconfig_paths-bRwOJEk9.cjs → project_tsconfig_paths-DX9KHLn9.cjs} +423 -236
  63. package/schematics/bundles/property_name-BBwFuqMe.cjs +1 -1
  64. package/schematics/bundles/route-lazy-loading.cjs +48 -4
  65. package/schematics/bundles/router-current-navigation.cjs +6 -6
  66. package/schematics/bundles/router-last-successful-navigation.cjs +6 -6
  67. package/schematics/bundles/self-closing-tags-migration.cjs +8 -8
  68. package/schematics/bundles/signal-input-migration.cjs +17 -9
  69. package/schematics/bundles/signal-queries-migration.cjs +7 -7
  70. package/schematics/bundles/signals.cjs +7 -7
  71. package/schematics/bundles/standalone-migration.cjs +17 -10
  72. package/schematics/bundles/{symbol-VPWguRxr.cjs → symbol-BObKoqes.cjs} +3 -2
  73. package/schematics/collection.json +6 -0
  74. package/schematics/migrations/ngstyle-to-style-migration/schema.json +20 -0
  75. package/schematics/migrations.json +5 -0
  76. package/testing/index.d.ts +1 -1
  77. package/weak_ref.d.d.ts +1 -1
  78. package/schematics/bundles/parse_html-CLFKoiOK.cjs +0 -41
@@ -1,16 +1,16 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v21.0.0-next.3
3
+ * @license Angular v21.0.0-next.5
4
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 ng_decorators = require('./ng_decorators-CtYwz9Lw.cjs');
10
+ var ng_decorators = require('./ng_decorators-BI0uV7KI.cjs');
11
11
  var property_name = require('./property_name-BBwFuqMe.cjs');
12
12
  require('os');
13
- var project_tsconfig_paths = require('./project_tsconfig_paths-bRwOJEk9.cjs');
13
+ var project_tsconfig_paths = require('./project_tsconfig_paths-DX9KHLn9.cjs');
14
14
 
15
15
  /**
16
16
  * Unwraps a given expression TypeScript node. Expressions can be wrapped within multiple
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v21.0.0-next.3
3
+ * @license Angular v21.0.0-next.5
4
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 imports = require('./imports-26VeX8i-.cjs');
10
+ var imports = require('./imports-DwPXlGFl.cjs');
11
11
 
12
12
  function getCallDecoratorImport(typeChecker, decorator) {
13
13
  // Note that this does not cover the edge case where decorators are called from
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v21.0.0-next.3
3
+ * @license Angular v21.0.0-next.5
4
4
  * (c) 2010-2025 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
@@ -8,22 +8,22 @@
8
8
 
9
9
  var ts = require('typescript');
10
10
  require('os');
11
- var project_tsconfig_paths = require('./project_tsconfig_paths-bRwOJEk9.cjs');
12
- var index = require('./index-CBaykQBv.cjs');
11
+ var project_tsconfig_paths = require('./project_tsconfig_paths-DX9KHLn9.cjs');
12
+ var index = require('./index-Bb6iejCd.cjs');
13
13
  require('path');
14
14
  require('node:path');
15
- var project_paths = require('./project_paths-BJTqcWvC.cjs');
16
- var apply_import_manager = require('./apply_import_manager-tNexl58m.cjs');
17
- var imports = require('./imports-26VeX8i-.cjs');
18
- var parse_html = require('./parse_html-CLFKoiOK.cjs');
19
- var ng_component_template = require('./ng_component_template-HYGPuVhy.cjs');
15
+ var project_paths = require('./project_paths-Dr2s3Pq3.cjs');
16
+ var apply_import_manager = require('./apply_import_manager-Bx60Uquz.cjs');
17
+ var imports = require('./imports-DwPXlGFl.cjs');
18
+ var parse_html = require('./parse_html-7Wl_HDnw.cjs');
19
+ var ng_component_template = require('./ng_component_template-B4M8mTyv.cjs');
20
20
  require('@angular-devkit/core');
21
21
  require('node:path/posix');
22
22
  require('fs');
23
23
  require('module');
24
24
  require('url');
25
25
  require('@angular-devkit/schematics');
26
- require('./ng_decorators-CtYwz9Lw.cjs');
26
+ require('./ng_decorators-BI0uV7KI.cjs');
27
27
  require('./property_name-BBwFuqMe.cjs');
28
28
 
29
29
  const ngClassStr = 'NgClass';
@@ -32,7 +32,7 @@ const commonModuleImportsStr = 'CommonModule';
32
32
  function migrateNgClassBindings(template, config, componentNode, typeChecker) {
33
33
  const parsed = parse_html.parseTemplate(template);
34
34
  if (!parsed.tree || !parsed.tree.rootNodes.length) {
35
- return { migrated: template, changed: false, replacementCount: 0 };
35
+ return { migrated: template, changed: false, replacementCount: 0, canRemoveCommonModule: false };
36
36
  }
37
37
  const visitor = new NgClassCollector(template, componentNode, typeChecker);
38
38
  project_tsconfig_paths.visitAll$1(visitor, parsed.tree.rootNodes, config);
@@ -45,13 +45,19 @@ function migrateNgClassBindings(template, config, componentNode, typeChecker) {
45
45
  changedOffset += newTemplate.length - currentLength;
46
46
  replacementCount++;
47
47
  }
48
- return { migrated: newTemplate, changed: newTemplate !== template, replacementCount };
48
+ const changed = newTemplate !== template;
49
+ return {
50
+ migrated: newTemplate,
51
+ changed,
52
+ replacementCount,
53
+ canRemoveCommonModule: changed ? parse_html.canRemoveCommonModule(newTemplate) : false,
54
+ };
49
55
  }
50
56
  /**
51
57
  * Creates a Replacement to remove `NgClass` from a component's `imports` array.
52
58
  * Uses ReflectionHost + PartialEvaluator for robust AST analysis.
53
59
  */
54
- function createNgClassImportsArrayRemoval(classNode, file, typeChecker) {
60
+ function createNgClassImportsArrayRemoval(classNode, file, typeChecker, removeCommonModule) {
55
61
  const reflector = new project_tsconfig_paths.TypeScriptReflectionHost(typeChecker);
56
62
  const evaluator = new index.PartialEvaluator(reflector, typeChecker, null);
57
63
  // Use ReflectionHost to get decorators instead of manual AST traversal
@@ -84,74 +90,66 @@ function createNgClassImportsArrayRemoval(classNode, file, typeChecker) {
84
90
  return null;
85
91
  }
86
92
  const importsArray = importsProperty.initializer;
87
- const ngClassIndex = importsArray.elements.findIndex((e) => ts.isIdentifier(e) && e.text === ngClassStr);
88
- if (ngClassIndex === -1) {
89
- return null;
90
- }
91
- const elements = importsArray.elements;
92
- const ngClassElement = elements[ngClassIndex];
93
- const range = getNgClassRemovalRange(importsProperty, importsArray, ngClassElement, classNode.getSourceFile());
94
- return new project_paths.Replacement(file, new project_paths.TextUpdate({ position: range.start, end: range.end, toInsert: '' }));
95
- }
96
- function getElementRemovalRange(elementNode, sourceFile) {
97
- const parent = elementNode.parent;
98
- // Check if in array context (imports: [..]) or object context (@Component({..}))
99
- const isArrayLiteralExpression = ts.isArrayLiteralExpression(parent);
100
- const isObjectLiteralExpression = ts.isObjectLiteralExpression(parent);
101
- let elements;
102
- if (isArrayLiteralExpression) {
103
- elements = parent.elements;
104
- }
105
- else if (isObjectLiteralExpression) {
106
- elements = parent.properties;
107
- }
108
- else {
109
- return { start: elementNode.getStart(sourceFile), end: elementNode.getEnd() };
110
- }
111
- const elementIndex = elements.indexOf(elementNode);
112
- const isLastElement = elementIndex === elements.length - 1;
113
- if (isLastElement) {
114
- // If this is the LAST element, the range is from the END of the previous element
115
- // to the END of this element. This captures the comma and space preceding it.
116
- // Ex: `[a, b]` -> remove `, b`
117
- const start = elementIndex > 0 ? elements[elementIndex - 1].getEnd() : elementNode.getStart(sourceFile); // If it is also the first (only) element, there is no comma before it.
118
- return { start: start, end: elementNode.getEnd() };
119
- }
120
- else {
121
- // If it's the FIRST or MIDDLE element, the range goes from the BEGINNING of this element
122
- // to the BEGINNING of the next one. This captures the element itself and the comma that FOLLOWS it.
123
- // Ex: `[a, b]` -> remove `a,`
124
- const nextElement = elements[elementIndex + 1];
125
- return {
126
- start: elementNode.getStart(sourceFile),
127
- end: nextElement.getStart(sourceFile),
128
- };
129
- }
93
+ const elementsToRemove = new Set([ngClassStr]);
94
+ if (removeCommonModule) {
95
+ elementsToRemove.add(commonModuleImportsStr);
96
+ }
97
+ const originalElements = importsArray.elements;
98
+ const filteredElements = originalElements.filter((el) => !ts.isIdentifier(el) || !elementsToRemove.has(el.text));
99
+ if (filteredElements.length === originalElements.length) {
100
+ return null; // No changes needed.
101
+ }
102
+ // If the array becomes empty, remove the entire `imports` property.
103
+ if (filteredElements.length === 0) {
104
+ const removalRange = getPropertyRemovalRange(importsProperty);
105
+ return new project_paths.Replacement(file, new project_paths.TextUpdate({
106
+ position: removalRange.start,
107
+ end: removalRange.end,
108
+ toInsert: '',
109
+ }));
110
+ }
111
+ const printer = ts.createPrinter();
112
+ const newArray = ts.factory.updateArrayLiteralExpression(importsArray, filteredElements);
113
+ const newText = printer.printNode(ts.EmitHint.Unspecified, newArray, classNode.getSourceFile());
114
+ return new project_paths.Replacement(file, new project_paths.TextUpdate({
115
+ position: importsArray.getStart(),
116
+ end: importsArray.getEnd(),
117
+ toInsert: newText,
118
+ }));
130
119
  }
131
- /**
132
- * If there is more than one import, it affects the NgClass element within the array.
133
- * Otherwise, `NgClass` is the only import. The removal affects the entire `imports: [...]` property.
134
- */
135
- function getNgClassRemovalRange(importsProperty, importsArray, ngClassElement, sourceFile) {
136
- if (importsArray.elements.length > 1) {
137
- return getElementRemovalRange(ngClassElement, sourceFile);
138
- }
139
- else {
140
- return getElementRemovalRange(importsProperty, sourceFile);
141
- }
120
+ function getPropertyRemovalRange(property) {
121
+ const parent = property.parent;
122
+ if (!ts.isObjectLiteralExpression(parent)) {
123
+ return { start: property.getStart(), end: property.getEnd() };
124
+ }
125
+ const properties = parent.properties;
126
+ const propertyIndex = properties.indexOf(property);
127
+ const end = property.getEnd();
128
+ if (propertyIndex < properties.length - 1) {
129
+ const nextProperty = properties[propertyIndex + 1];
130
+ return { start: property.getStart(), end: nextProperty.getStart() };
131
+ }
132
+ return { start: property.getStart(), end };
142
133
  }
143
- function calculateImportReplacements(info, sourceFiles) {
134
+ function calculateImportReplacements(info, sourceFiles, filesToRemoveCommonModule) {
144
135
  const importReplacements = {};
145
136
  const importManager = new project_tsconfig_paths.ImportManager();
146
137
  for (const sf of sourceFiles) {
147
138
  const file = project_paths.projectFile(sf, info);
139
+ // Always remove NgClass if it's imported directly.
148
140
  importManager.removeImport(sf, ngClassStr, commonModuleStr);
141
+ // Conditionally remove CommonModule if it's no longer needed.
142
+ if (filesToRemoveCommonModule.has(file.id)) {
143
+ importManager.removeImport(sf, commonModuleImportsStr, commonModuleStr);
144
+ }
149
145
  const addRemove = [];
150
146
  apply_import_manager.applyImportManagerChanges(importManager, addRemove, [sf], info);
151
- importReplacements[file.id] = {
152
- add: [],
153
- addAndRemove: addRemove,
154
- };
147
+ if (addRemove.length > 0) {
148
+ importReplacements[file.id] = {
149
+ add: [],
150
+ addAndRemove: addRemove,
151
+ };
152
+ }
155
153
  }
156
154
  return importReplacements;
157
155
  }
@@ -390,11 +388,27 @@ class NgClassMigration extends project_paths.TsurgeFunnelMigration {
390
388
  super();
391
389
  this.config = config;
392
390
  }
391
+ processTemplate(template, node, file, info, typeChecker) {
392
+ const { migrated, changed, replacementCount, canRemoveCommonModule } = migrateNgClassBindings(template.content, this.config, node, typeChecker);
393
+ if (!changed) {
394
+ return null;
395
+ }
396
+ const fileToMigrate = template.inline
397
+ ? file
398
+ : project_paths.projectFile(template.filePath, info);
399
+ const end = template.start + template.content.length;
400
+ return {
401
+ replacements: [prepareTextReplacement(fileToMigrate, migrated, template.start, end)],
402
+ replacementCount,
403
+ canRemoveCommonModule,
404
+ };
405
+ }
393
406
  async analyze(info) {
394
407
  const { sourceFiles, program } = info;
395
408
  const typeChecker = program.getTypeChecker();
396
409
  const ngClassReplacements = [];
397
410
  const filesWithNgClassDeclarations = new Set();
411
+ const filesToRemoveCommonModule = new Set();
398
412
  for (const sf of sourceFiles) {
399
413
  ts.forEachChild(sf, (node) => {
400
414
  if (!ts.isClassDeclaration(node)) {
@@ -408,42 +422,40 @@ class NgClassMigration extends project_paths.TsurgeFunnelMigration {
408
422
  templateVisitor.visitNode(node);
409
423
  const replacementsForClass = [];
410
424
  let replacementCountForClass = 0;
411
- templateVisitor.resolvedTemplates.forEach((template) => {
412
- const { migrated, changed, replacementCount } = migrateNgClassBindings(template.content, this.config, node, typeChecker);
413
- if (!changed) {
414
- return;
425
+ let canRemoveCommonModuleForFile = true;
426
+ for (const template of templateVisitor.resolvedTemplates) {
427
+ const result = this.processTemplate(template, node, file, info, typeChecker);
428
+ if (result) {
429
+ replacementsForClass.push(...result.replacements);
430
+ replacementCountForClass += result.replacementCount;
431
+ if (!result.canRemoveCommonModule) {
432
+ canRemoveCommonModuleForFile = false;
433
+ }
415
434
  }
416
- replacementCountForClass += replacementCount;
417
- const fileToMigrate = template.inline
418
- ? file
419
- : project_paths.projectFile(template.filePath, info);
420
- const end = template.start + template.content.length;
421
- replacementsForClass.push(prepareTextReplacement(fileToMigrate, migrated, template.start, end));
422
- });
423
- if (replacementCountForClass === 0) {
424
- return;
425
- }
426
- filesWithNgClassDeclarations.add(sf);
427
- const importArrayRemoval = createNgClassImportsArrayRemoval(node, file, typeChecker);
428
- if (importArrayRemoval) {
429
- replacementsForClass.push(importArrayRemoval);
430
- }
431
- const existing = ngClassReplacements.find((entry) => entry.file === file);
432
- if (existing) {
433
- existing.replacements.push(...replacementsForClass);
434
- existing.replacementCount += replacementCountForClass;
435
435
  }
436
- else {
436
+ if (replacementsForClass.length > 0) {
437
+ if (canRemoveCommonModuleForFile) {
438
+ filesToRemoveCommonModule.add(file.id);
439
+ }
440
+ // Handle the `@Component({ imports: [...] })` array.
441
+ const importsRemoval = createNgClassImportsArrayRemoval(node, file, typeChecker, canRemoveCommonModuleForFile);
442
+ if (importsRemoval) {
443
+ replacementsForClass.push(importsRemoval);
444
+ }
437
445
  ngClassReplacements.push({
438
446
  file,
439
- replacements: replacementsForClass,
440
447
  replacementCount: replacementCountForClass,
448
+ replacements: replacementsForClass,
441
449
  });
450
+ filesWithNgClassDeclarations.add(sf);
442
451
  }
443
452
  });
444
453
  }
445
- const importReplacements = calculateImportReplacements(info, filesWithNgClassDeclarations);
446
- return project_paths.confirmAsSerializable({ ngClassReplacements, importReplacements });
454
+ const importReplacements = calculateImportReplacements(info, filesWithNgClassDeclarations, filesToRemoveCommonModule);
455
+ return project_paths.confirmAsSerializable({
456
+ ngClassReplacements,
457
+ importReplacements,
458
+ });
447
459
  }
448
460
  async combine(unitA, unitB) {
449
461
  const importReplacements = {};