@angular/core 21.0.0-next.0 → 21.0.0-next.10
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/_attribute-chunk.mjs +12 -0
- package/fesm2022/_attribute-chunk.mjs.map +1 -0
- package/fesm2022/_debug_node-chunk.mjs +18469 -0
- package/fesm2022/_debug_node-chunk.mjs.map +1 -0
- package/fesm2022/_effect-chunk.mjs +423 -0
- package/fesm2022/_effect-chunk.mjs.map +1 -0
- package/fesm2022/_effect-chunk2.mjs +2951 -0
- package/fesm2022/_effect-chunk2.mjs.map +1 -0
- package/fesm2022/_not_found-chunk.mjs +39 -0
- package/fesm2022/_not_found-chunk.mjs.map +1 -0
- package/fesm2022/_resource-chunk.mjs +378 -0
- package/fesm2022/_resource-chunk.mjs.map +1 -0
- package/fesm2022/_untracked-chunk.mjs +96 -0
- package/fesm2022/_untracked-chunk.mjs.map +1 -0
- package/fesm2022/_weak_ref-chunk.mjs +10 -0
- package/fesm2022/_weak_ref-chunk.mjs.map +1 -0
- package/fesm2022/core.mjs +2499 -4185
- package/fesm2022/core.mjs.map +1 -1
- package/fesm2022/primitives-di.mjs +23 -0
- package/fesm2022/primitives-di.mjs.map +1 -0
- package/fesm2022/primitives-event-dispatch.mjs +788 -0
- package/fesm2022/primitives-event-dispatch.mjs.map +1 -0
- package/fesm2022/primitives-signals.mjs +187 -0
- package/fesm2022/primitives-signals.mjs.map +1 -0
- package/fesm2022/rxjs-interop.mjs +210 -308
- package/fesm2022/rxjs-interop.mjs.map +1 -1
- package/fesm2022/testing.mjs +2309 -3170
- package/fesm2022/testing.mjs.map +1 -1
- package/package.json +18 -12
- package/resources/best-practices.md +56 -0
- package/schematics/bundles/add-bootstrap-context-to-server-main.cjs +117 -0
- package/schematics/bundles/application-config-core.cjs +84 -0
- package/schematics/bundles/{apply_import_manager-DR9xXCle.cjs → apply_import_manager-1Zs_gpB6.cjs} +4 -5
- package/schematics/bundles/bootstrap-options-migration.cjs +598 -0
- package/schematics/bundles/cleanup-unused-imports.cjs +9 -13
- package/schematics/bundles/common-to-standalone-migration.cjs +381 -0
- package/schematics/bundles/{compiler_host-BXBP7CE2.cjs → compiler_host-DBwYMlTo.cjs} +10 -11
- package/schematics/bundles/control-flow-migration.cjs +122 -119
- package/schematics/bundles/{imports-CIX-JgAN.cjs → imports-DP72APSx.cjs} +6 -1
- package/schematics/bundles/{index-CfTQUOiz.cjs → index-B7I9sIUx.cjs} +36 -39
- package/schematics/bundles/inject-migration.cjs +148 -70
- package/schematics/bundles/leading_space-D9nQ8UQC.cjs +1 -1
- package/schematics/bundles/{migrate_ts_type_references-6NtAj-Wk.cjs → migrate_ts_type_references-UGIUl7En.cjs} +500 -24
- package/schematics/bundles/ng_component_template-Dsuq1Lw7.cjs +185 -0
- package/schematics/bundles/{ng_decorators-B5HCqr20.cjs → ng_decorators-DSFlWYQY.cjs} +2 -2
- package/schematics/bundles/ngclass-to-class-migration.cjs +542 -0
- package/schematics/bundles/ngstyle-to-style-migration.cjs +487 -0
- package/schematics/bundles/nodes-B16H9JUd.cjs +1 -1
- package/schematics/bundles/output-migration.cjs +16 -19
- package/schematics/bundles/parse_html-8VLCL37B.cjs +132 -0
- package/schematics/bundles/{project_paths-DcaODbky.cjs → project_paths-DvD50ouC.cjs} +14 -247
- package/schematics/bundles/project_tsconfig_paths-CDVxT6Ov.cjs +90 -0
- package/schematics/bundles/property_name-BBwFuqMe.cjs +1 -1
- package/schematics/bundles/route-lazy-loading.cjs +54 -26
- package/schematics/bundles/router-current-navigation.cjs +7 -18
- package/schematics/bundles/router-last-successful-navigation.cjs +7 -18
- package/schematics/bundles/router-testing-module-migration.cjs +502 -0
- package/schematics/bundles/self-closing-tags-migration.cjs +17 -216
- package/schematics/bundles/signal-input-migration.cjs +93 -29
- package/schematics/bundles/signal-queries-migration.cjs +22 -25
- package/schematics/bundles/signals.cjs +10 -13
- package/schematics/bundles/standalone-migration.cjs +135 -102
- package/schematics/bundles/{symbol-VPWguRxr.cjs → symbol-BObKoqes.cjs} +3 -2
- package/schematics/collection.json +23 -0
- package/schematics/migrations/common-to-standalone-migration/schema.json +14 -0
- package/schematics/migrations/ngclass-to-class-migration/schema.json +20 -0
- package/schematics/migrations/ngstyle-to-style-migration/schema.json +20 -0
- package/schematics/migrations/router-testing-module-migration/schema.json +14 -0
- package/schematics/migrations.json +16 -2
- package/{api.d.d.ts → types/_api-chunk.d.ts} +9 -6
- package/{chrome_dev_tools_performance.d.d.ts → types/_chrome_dev_tools_performance-chunk.d.ts} +26 -31
- package/{discovery.d.d.ts → types/_discovery-chunk.d.ts} +135 -98
- package/{signal.d.d.ts → types/_effect-chunk.d.ts} +14 -5
- package/{event_dispatcher.d.d.ts → types/_event_dispatcher-chunk.d.ts} +2 -2
- package/{graph.d.d.ts → types/_formatter-chunk.d.ts} +40 -7
- package/{weak_ref.d.d.ts → types/_weak_ref-chunk.d.ts} +2 -2
- package/{index.d.ts → types/core.d.ts} +233 -305
- package/{primitives/di/index.d.ts → types/primitives-di.d.ts} +2 -2
- package/{primitives/event-dispatch/index.d.ts → types/primitives-event-dispatch.d.ts} +4 -4
- package/{primitives/signals/index.d.ts → types/primitives-signals.d.ts} +7 -8
- package/{rxjs-interop/index.d.ts → types/rxjs-interop.d.ts} +8 -6
- package/{testing/index.d.ts → types/testing.d.ts} +7 -7
- package/fesm2022/attribute.mjs +0 -24
- package/fesm2022/attribute.mjs.map +0 -1
- package/fesm2022/debug_node.mjs +0 -31833
- package/fesm2022/debug_node.mjs.map +0 -1
- package/fesm2022/not_found.mjs +0 -56
- package/fesm2022/not_found.mjs.map +0 -1
- package/fesm2022/primitives/di.mjs +0 -23
- package/fesm2022/primitives/di.mjs.map +0 -1
- package/fesm2022/primitives/event-dispatch.mjs +0 -1622
- package/fesm2022/primitives/event-dispatch.mjs.map +0 -1
- package/fesm2022/primitives/signals.mjs +0 -89
- package/fesm2022/primitives/signals.mjs.map +0 -1
- package/fesm2022/resource.mjs +0 -633
- package/fesm2022/resource.mjs.map +0 -1
- package/fesm2022/root_effect_scheduler.mjs +0 -4007
- package/fesm2022/root_effect_scheduler.mjs.map +0 -1
- package/fesm2022/signal.mjs +0 -560
- package/fesm2022/signal.mjs.map +0 -1
- package/fesm2022/untracked.mjs +0 -117
- package/fesm2022/untracked.mjs.map +0 -1
- package/fesm2022/weak_ref.mjs +0 -12
- package/fesm2022/weak_ref.mjs.map +0 -1
- package/schematics/bundles/index-esqfDjNB.cjs +0 -22074
- package/schematics/bundles/project_tsconfig_paths-CS-eSeHC.cjs +0 -51062
|
@@ -1,20 +1,19 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
/**
|
|
3
|
-
* @license Angular v21.0.0-next.
|
|
3
|
+
* @license Angular v21.0.0-next.10
|
|
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 schematics = require('@angular-devkit/schematics');
|
|
10
|
-
var
|
|
11
|
-
var compiler_host = require('./compiler_host-
|
|
12
|
-
var
|
|
10
|
+
var path = require('path');
|
|
11
|
+
var compiler_host = require('./compiler_host-DBwYMlTo.cjs');
|
|
12
|
+
var compiler = require('@angular/compiler');
|
|
13
13
|
var ts = require('typescript');
|
|
14
|
-
require('
|
|
15
|
-
require('
|
|
16
|
-
require('
|
|
17
|
-
require('url');
|
|
14
|
+
var parse_html = require('./parse_html-8VLCL37B.cjs');
|
|
15
|
+
var project_tsconfig_paths = require('./project_tsconfig_paths-CDVxT6Ov.cjs');
|
|
16
|
+
require('@angular/compiler-cli/private/migrations');
|
|
18
17
|
require('@angular-devkit/core');
|
|
19
18
|
|
|
20
19
|
function lookupIdentifiersInSourceFile(sourceFile, names) {
|
|
@@ -274,7 +273,7 @@ class AnalyzedFile {
|
|
|
274
273
|
}
|
|
275
274
|
}
|
|
276
275
|
/** Finds all non-control flow elements from common module. */
|
|
277
|
-
class CommonCollector extends
|
|
276
|
+
class CommonCollector extends compiler.RecursiveVisitor {
|
|
278
277
|
count = 0;
|
|
279
278
|
visitElement(el) {
|
|
280
279
|
if (el.attrs.length > 0) {
|
|
@@ -313,7 +312,7 @@ class CommonCollector extends project_tsconfig_paths.RecursiveVisitor$1 {
|
|
|
313
312
|
}
|
|
314
313
|
}
|
|
315
314
|
/** Finds all elements that represent i18n blocks. */
|
|
316
|
-
class i18nCollector extends
|
|
315
|
+
class i18nCollector extends compiler.RecursiveVisitor {
|
|
317
316
|
elements = [];
|
|
318
317
|
visitElement(el) {
|
|
319
318
|
if (el.attrs.find((a) => a.name === 'i18n') !== undefined) {
|
|
@@ -323,7 +322,7 @@ class i18nCollector extends project_tsconfig_paths.RecursiveVisitor$1 {
|
|
|
323
322
|
}
|
|
324
323
|
}
|
|
325
324
|
/** Finds all elements with ngif structural directives. */
|
|
326
|
-
class ElementCollector extends
|
|
325
|
+
class ElementCollector extends compiler.RecursiveVisitor {
|
|
327
326
|
_attributes;
|
|
328
327
|
elements = [];
|
|
329
328
|
constructor(_attributes = []) {
|
|
@@ -376,7 +375,7 @@ class ElementCollector extends project_tsconfig_paths.RecursiveVisitor$1 {
|
|
|
376
375
|
}
|
|
377
376
|
}
|
|
378
377
|
/** Finds all elements with ngif structural directives. */
|
|
379
|
-
class TemplateCollector extends
|
|
378
|
+
class TemplateCollector extends compiler.RecursiveVisitor {
|
|
380
379
|
elements = [];
|
|
381
380
|
templates = new Map();
|
|
382
381
|
visitElement(el) {
|
|
@@ -409,6 +408,7 @@ const endMarkerRegex = new RegExp(endMarker, 'gm');
|
|
|
409
408
|
const startI18nMarkerRegex = new RegExp(startI18nMarker, 'gm');
|
|
410
409
|
const endI18nMarkerRegex = new RegExp(endI18nMarker, 'gm');
|
|
411
410
|
const replaceMarkerRegex = new RegExp(`${startMarker}|${endMarker}`, 'gm');
|
|
411
|
+
const PRIORITY_WEIGHT_TEMPLATE_REFERENCE_BY_OUTLET = 2;
|
|
412
412
|
/**
|
|
413
413
|
* Analyzes a source file to find file that need to be migrated and the text ranges within them.
|
|
414
414
|
* @param sourceFile File to be analyzed.
|
|
@@ -548,8 +548,8 @@ function analyzeDecorators(node, sourceFile, analyzedFiles) {
|
|
|
548
548
|
case 'templateUrl':
|
|
549
549
|
// Leave the end as undefined which means that the range is until the end of the file.
|
|
550
550
|
if (ts.isStringLiteralLike(prop.initializer)) {
|
|
551
|
-
const path =
|
|
552
|
-
AnalyzedFile.addRange(path, sourceFile, analyzedFiles, {
|
|
551
|
+
const path$1 = path.join(path.dirname(sourceFile.fileName), prop.initializer.text);
|
|
552
|
+
AnalyzedFile.addRange(path$1, sourceFile, analyzedFiles, {
|
|
553
553
|
start: 0,
|
|
554
554
|
node: prop,
|
|
555
555
|
type: 'templateUrl',
|
|
@@ -579,37 +579,8 @@ function getNestedCount(etm, aggregator) {
|
|
|
579
579
|
return getNestedCount(etm, aggregator);
|
|
580
580
|
}
|
|
581
581
|
}
|
|
582
|
-
/**
|
|
583
|
-
* parses the template string into the Html AST
|
|
584
|
-
*/
|
|
585
|
-
function parseTemplate(template) {
|
|
586
|
-
let parsed;
|
|
587
|
-
try {
|
|
588
|
-
// Note: we use the HtmlParser here, instead of the `parseTemplate` function, because the
|
|
589
|
-
// latter returns an Ivy AST, not an HTML AST. The HTML AST has the advantage of preserving
|
|
590
|
-
// interpolated text as text nodes containing a mixture of interpolation tokens and text tokens,
|
|
591
|
-
// rather than turning them into `BoundText` nodes like the Ivy AST does. This allows us to
|
|
592
|
-
// easily get the text-only ranges without having to reconstruct the original text.
|
|
593
|
-
parsed = new project_tsconfig_paths.HtmlParser().parse(template, '', {
|
|
594
|
-
// Allows for ICUs to be parsed.
|
|
595
|
-
tokenizeExpansionForms: true,
|
|
596
|
-
// Explicitly disable blocks so that their characters are treated as plain text.
|
|
597
|
-
tokenizeBlocks: true,
|
|
598
|
-
preserveLineEndings: true,
|
|
599
|
-
});
|
|
600
|
-
// Don't migrate invalid templates.
|
|
601
|
-
if (parsed.errors && parsed.errors.length > 0) {
|
|
602
|
-
const errors = parsed.errors.map((e) => ({ type: 'parse', error: e }));
|
|
603
|
-
return { tree: undefined, errors };
|
|
604
|
-
}
|
|
605
|
-
}
|
|
606
|
-
catch (e) {
|
|
607
|
-
return { tree: undefined, errors: [{ type: 'parse', error: e }] };
|
|
608
|
-
}
|
|
609
|
-
return { tree: parsed, errors: [] };
|
|
610
|
-
}
|
|
611
582
|
function validateMigratedTemplate(migrated, fileName) {
|
|
612
|
-
const parsed = parseTemplate(migrated);
|
|
583
|
+
const parsed = parse_html.parseTemplate(migrated);
|
|
613
584
|
let errors = [];
|
|
614
585
|
if (parsed.errors.length > 0) {
|
|
615
586
|
errors.push({
|
|
@@ -628,7 +599,7 @@ function validateMigratedTemplate(migrated, fileName) {
|
|
|
628
599
|
}
|
|
629
600
|
function validateI18nStructure(parsed, fileName) {
|
|
630
601
|
const visitor = new i18nCollector();
|
|
631
|
-
|
|
602
|
+
compiler.visitAll(visitor, parsed.rootNodes);
|
|
632
603
|
const parents = visitor.elements.filter((el) => el.children.length > 0);
|
|
633
604
|
for (const p of parents) {
|
|
634
605
|
for (const el of visitor.elements) {
|
|
@@ -705,10 +676,10 @@ function reduceNestingOffset(el, nestLevel, offset, postOffsets) {
|
|
|
705
676
|
* Returns null if the migration failed (e.g. there was a syntax error).
|
|
706
677
|
*/
|
|
707
678
|
function getTemplates(template) {
|
|
708
|
-
const parsed = parseTemplate(template);
|
|
679
|
+
const parsed = parse_html.parseTemplate(template);
|
|
709
680
|
if (parsed.tree !== undefined) {
|
|
710
681
|
const visitor = new TemplateCollector();
|
|
711
|
-
|
|
682
|
+
compiler.visitAll(visitor, parsed.tree.rootNodes);
|
|
712
683
|
for (let [key, tmpl] of visitor.templates) {
|
|
713
684
|
tmpl.count = countTemplateUsage(parsed.tree.rootNodes, key);
|
|
714
685
|
tmpl.generateContents(template);
|
|
@@ -717,34 +688,6 @@ function getTemplates(template) {
|
|
|
717
688
|
}
|
|
718
689
|
return new Map();
|
|
719
690
|
}
|
|
720
|
-
function countTemplateUsage(nodes, templateName) {
|
|
721
|
-
let count = 0;
|
|
722
|
-
let isReferencedInTemplateOutlet = false;
|
|
723
|
-
for (const node of nodes) {
|
|
724
|
-
if (node.attrs) {
|
|
725
|
-
for (const attr of node.attrs) {
|
|
726
|
-
if (attr.name === '*ngTemplateOutlet' && attr.value === templateName.slice(1)) {
|
|
727
|
-
isReferencedInTemplateOutlet = true;
|
|
728
|
-
break;
|
|
729
|
-
}
|
|
730
|
-
if (attr.name.trim() === templateName) {
|
|
731
|
-
count++;
|
|
732
|
-
}
|
|
733
|
-
}
|
|
734
|
-
}
|
|
735
|
-
if (node.children) {
|
|
736
|
-
if (node.name === 'for') {
|
|
737
|
-
for (const child of node.children) {
|
|
738
|
-
if (child.value?.includes(templateName.slice(1))) {
|
|
739
|
-
count++;
|
|
740
|
-
}
|
|
741
|
-
}
|
|
742
|
-
}
|
|
743
|
-
count += countTemplateUsage(node.children, templateName);
|
|
744
|
-
}
|
|
745
|
-
}
|
|
746
|
-
return isReferencedInTemplateOutlet ? count + 2 : count;
|
|
747
|
-
}
|
|
748
691
|
function updateTemplates(template, templates) {
|
|
749
692
|
const updatedTemplates = getTemplates(template);
|
|
750
693
|
for (let [key, tmpl] of updatedTemplates) {
|
|
@@ -768,9 +711,10 @@ function processNgTemplates(template, sourceFile) {
|
|
|
768
711
|
try {
|
|
769
712
|
const templates = getTemplates(template);
|
|
770
713
|
// swap placeholders and remove
|
|
771
|
-
for (const [
|
|
772
|
-
const
|
|
773
|
-
const
|
|
714
|
+
for (const [nameWithHash, t] of templates) {
|
|
715
|
+
const name = nameWithHash.slice(1);
|
|
716
|
+
const replaceRegex = new RegExp(getPlaceholder(name), 'g');
|
|
717
|
+
const forRegex = new RegExp(getPlaceholder(nameWithHash.slice(1), PlaceholderKind.Alternate), 'g');
|
|
774
718
|
const forMatches = [...template.matchAll(forRegex)];
|
|
775
719
|
const matches = [...forMatches, ...template.matchAll(replaceRegex)];
|
|
776
720
|
let safeToRemove = true;
|
|
@@ -795,7 +739,12 @@ function processNgTemplates(template, sourceFile) {
|
|
|
795
739
|
template = template.replace(replaceRegex, t.children);
|
|
796
740
|
}
|
|
797
741
|
const dist = matches.filter((obj, index, self) => index === self.findIndex((t) => t.input === obj.input));
|
|
798
|
-
|
|
742
|
+
// Check if template is used by ngTemplateOutlet in addition to control flow
|
|
743
|
+
const hasTemplateOutletUsage = checkForTemplateOutletUsage(template, nameWithHash.slice(1));
|
|
744
|
+
// Only remove template if it's safe to do so AND not used by ngTemplateOutlet
|
|
745
|
+
if ((t.count === dist.length || t.count - matches.length === 1) &&
|
|
746
|
+
safeToRemove &&
|
|
747
|
+
!hasTemplateOutletUsage) {
|
|
799
748
|
const refsInComponentFile = getViewChildOrViewChildrenNames(sourceFile);
|
|
800
749
|
if (refsInComponentFile?.length > 0) {
|
|
801
750
|
const templateRefs = getTemplateReferences(template);
|
|
@@ -825,6 +774,59 @@ function processNgTemplates(template, sourceFile) {
|
|
|
825
774
|
return { migrated: template, err: err };
|
|
826
775
|
}
|
|
827
776
|
}
|
|
777
|
+
function analyzeTemplateUsage(nodes, templateName) {
|
|
778
|
+
let count = 0;
|
|
779
|
+
let isReferencedInTemplateOutlet = false;
|
|
780
|
+
const templateNameWithHash = `#${templateName}`;
|
|
781
|
+
function traverseNodes(nodeList) {
|
|
782
|
+
for (const node of nodeList) {
|
|
783
|
+
if (node.attrs) {
|
|
784
|
+
for (const attr of node.attrs) {
|
|
785
|
+
if ((attr.name === '*ngTemplateOutlet' || attr.name === '[ngTemplateOutlet]') &&
|
|
786
|
+
attr.value?.split(';')[0] === templateName) {
|
|
787
|
+
isReferencedInTemplateOutlet = true;
|
|
788
|
+
}
|
|
789
|
+
if (attr.name.trim() === templateNameWithHash) {
|
|
790
|
+
count++;
|
|
791
|
+
}
|
|
792
|
+
}
|
|
793
|
+
}
|
|
794
|
+
if (node.children) {
|
|
795
|
+
if (node.name === 'for') {
|
|
796
|
+
for (const child of node.children) {
|
|
797
|
+
if (child.value?.includes(templateName)) {
|
|
798
|
+
count++;
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
}
|
|
802
|
+
traverseNodes(node.children);
|
|
803
|
+
}
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
traverseNodes(nodes);
|
|
807
|
+
return {
|
|
808
|
+
isReferencedInTemplateOutlet,
|
|
809
|
+
totalCount: isReferencedInTemplateOutlet
|
|
810
|
+
? count + PRIORITY_WEIGHT_TEMPLATE_REFERENCE_BY_OUTLET
|
|
811
|
+
: count,
|
|
812
|
+
};
|
|
813
|
+
}
|
|
814
|
+
/**
|
|
815
|
+
* Checks if a template is used by ngTemplateOutlet directive
|
|
816
|
+
*/
|
|
817
|
+
function checkForTemplateOutletUsage(template, templateName) {
|
|
818
|
+
const parsed = parse_html.parseTemplate(template);
|
|
819
|
+
if (parsed.tree === undefined) {
|
|
820
|
+
return false;
|
|
821
|
+
}
|
|
822
|
+
const result = analyzeTemplateUsage(parsed.tree.rootNodes, templateName);
|
|
823
|
+
return result.isReferencedInTemplateOutlet;
|
|
824
|
+
}
|
|
825
|
+
function countTemplateUsage(nodes, templateNameWithHash) {
|
|
826
|
+
const templateName = templateNameWithHash.slice(1);
|
|
827
|
+
const result = analyzeTemplateUsage(nodes, templateName);
|
|
828
|
+
return result.totalCount;
|
|
829
|
+
}
|
|
828
830
|
function getViewChildOrViewChildrenNames(sourceFile) {
|
|
829
831
|
const names = [];
|
|
830
832
|
function visit(node) {
|
|
@@ -845,15 +847,15 @@ function getViewChildOrViewChildrenNames(sourceFile) {
|
|
|
845
847
|
return names;
|
|
846
848
|
}
|
|
847
849
|
function getTemplateReferences(template) {
|
|
848
|
-
const parsed = parseTemplate(template);
|
|
850
|
+
const parsed = parse_html.parseTemplate(template);
|
|
849
851
|
if (parsed.tree === undefined) {
|
|
850
852
|
return [];
|
|
851
853
|
}
|
|
852
|
-
const
|
|
854
|
+
const templateNameRefWithoutHash = [];
|
|
853
855
|
function visitNodes(nodes) {
|
|
854
856
|
for (const node of nodes) {
|
|
855
857
|
if (node?.name === 'ng-template') {
|
|
856
|
-
|
|
858
|
+
templateNameRefWithoutHash.push(...node.attrs?.map((ref) => ref?.name?.slice(1)));
|
|
857
859
|
}
|
|
858
860
|
if (node.children) {
|
|
859
861
|
visitNodes(node.children);
|
|
@@ -861,7 +863,7 @@ function getTemplateReferences(template) {
|
|
|
861
863
|
}
|
|
862
864
|
}
|
|
863
865
|
visitNodes(parsed.tree.rootNodes);
|
|
864
|
-
return
|
|
866
|
+
return templateNameRefWithoutHash;
|
|
865
867
|
}
|
|
866
868
|
function replaceRemainingPlaceholders(template) {
|
|
867
869
|
const pattern = '.*';
|
|
@@ -880,11 +882,11 @@ function replaceRemainingPlaceholders(template) {
|
|
|
880
882
|
* determines if the CommonModule can be safely removed from imports
|
|
881
883
|
*/
|
|
882
884
|
function canRemoveCommonModule(template) {
|
|
883
|
-
const parsed = parseTemplate(template);
|
|
885
|
+
const parsed = parse_html.parseTemplate(template);
|
|
884
886
|
let removeCommonModule = false;
|
|
885
887
|
if (parsed.tree !== undefined) {
|
|
886
888
|
const visitor = new CommonCollector();
|
|
887
|
-
|
|
889
|
+
compiler.visitAll(visitor, parsed.tree.rootNodes);
|
|
888
890
|
removeCommonModule = visitor.count === 0;
|
|
889
891
|
}
|
|
890
892
|
return removeCommonModule;
|
|
@@ -1004,10 +1006,10 @@ function getMainBlock(etm, tmpl, offset) {
|
|
|
1004
1006
|
return { start, middle, end };
|
|
1005
1007
|
}
|
|
1006
1008
|
function generateI18nMarkers(tmpl) {
|
|
1007
|
-
let parsed = parseTemplate(tmpl);
|
|
1009
|
+
let parsed = parse_html.parseTemplate(tmpl);
|
|
1008
1010
|
if (parsed.tree !== undefined) {
|
|
1009
1011
|
const visitor = new i18nCollector();
|
|
1010
|
-
|
|
1012
|
+
compiler.visitAll(visitor, parsed.tree.rootNodes);
|
|
1011
1013
|
for (const [ix, el] of visitor.elements.entries()) {
|
|
1012
1014
|
// we only care about elements with children and i18n tags
|
|
1013
1015
|
// elements without children have nothing to translate
|
|
@@ -1203,13 +1205,13 @@ const cases = [boundcase, switchcase, nakedcase, switchdefault, nakeddefault];
|
|
|
1203
1205
|
*/
|
|
1204
1206
|
function migrateCase(template) {
|
|
1205
1207
|
let errors = [];
|
|
1206
|
-
let parsed = parseTemplate(template);
|
|
1208
|
+
let parsed = parse_html.parseTemplate(template);
|
|
1207
1209
|
if (parsed.tree === undefined) {
|
|
1208
1210
|
return { migrated: template, errors, changed: false };
|
|
1209
1211
|
}
|
|
1210
1212
|
let result = template;
|
|
1211
1213
|
const visitor = new ElementCollector(cases);
|
|
1212
|
-
|
|
1214
|
+
compiler.visitAll(visitor, parsed.tree.rootNodes);
|
|
1213
1215
|
calculateNesting(visitor, hasLineBreaks(template));
|
|
1214
1216
|
// this tracks the character shift from different lengths of blocks from
|
|
1215
1217
|
// the prior directives so as to adjust for nested block replacement during
|
|
@@ -1300,13 +1302,13 @@ const stringPairs = new Map([
|
|
|
1300
1302
|
*/
|
|
1301
1303
|
function migrateFor(template) {
|
|
1302
1304
|
let errors = [];
|
|
1303
|
-
let parsed = parseTemplate(template);
|
|
1305
|
+
let parsed = parse_html.parseTemplate(template);
|
|
1304
1306
|
if (parsed.tree === undefined) {
|
|
1305
1307
|
return { migrated: template, errors, changed: false };
|
|
1306
1308
|
}
|
|
1307
1309
|
let result = template;
|
|
1308
1310
|
const visitor = new ElementCollector(fors);
|
|
1309
|
-
|
|
1311
|
+
compiler.visitAll(visitor, parsed.tree.rootNodes);
|
|
1310
1312
|
calculateNesting(visitor, hasLineBreaks(template));
|
|
1311
1313
|
// this tracks the character shift from different lengths of blocks from
|
|
1312
1314
|
// the prior directives so as to adjust for nested block replacement during
|
|
@@ -1505,13 +1507,13 @@ const ifs = [ngif, nakedngif, boundngif];
|
|
|
1505
1507
|
*/
|
|
1506
1508
|
function migrateIf(template) {
|
|
1507
1509
|
let errors = [];
|
|
1508
|
-
let parsed = parseTemplate(template);
|
|
1510
|
+
let parsed = parse_html.parseTemplate(template);
|
|
1509
1511
|
if (parsed.tree === undefined) {
|
|
1510
1512
|
return { migrated: template, errors, changed: false };
|
|
1511
1513
|
}
|
|
1512
1514
|
let result = template;
|
|
1513
1515
|
const visitor = new ElementCollector(ifs);
|
|
1514
|
-
|
|
1516
|
+
compiler.visitAll(visitor, parsed.tree.rootNodes);
|
|
1515
1517
|
calculateNesting(visitor, hasLineBreaks(template));
|
|
1516
1518
|
// this tracks the character shift from different lengths of blocks from
|
|
1517
1519
|
// the prior directives so as to adjust for nested block replacement during
|
|
@@ -1698,13 +1700,13 @@ const switches = [ngswitch];
|
|
|
1698
1700
|
*/
|
|
1699
1701
|
function migrateSwitch(template) {
|
|
1700
1702
|
let errors = [];
|
|
1701
|
-
let parsed = parseTemplate(template);
|
|
1703
|
+
let parsed = parse_html.parseTemplate(template);
|
|
1702
1704
|
if (parsed.tree === undefined) {
|
|
1703
1705
|
return { migrated: template, errors, changed: false };
|
|
1704
1706
|
}
|
|
1705
1707
|
let result = template;
|
|
1706
1708
|
const visitor = new ElementCollector(switches);
|
|
1707
|
-
|
|
1709
|
+
compiler.visitAll(visitor, parsed.tree.rootNodes);
|
|
1708
1710
|
calculateNesting(visitor, hasLineBreaks(template));
|
|
1709
1711
|
// this tracks the character shift from different lengths of blocks from
|
|
1710
1712
|
// the prior directives so as to adjust for nested block replacement during
|
|
@@ -1735,11 +1737,11 @@ function migrateSwitch(template) {
|
|
|
1735
1737
|
}
|
|
1736
1738
|
function assertValidSwitchStructure(children) {
|
|
1737
1739
|
for (const child of children) {
|
|
1738
|
-
if (child instanceof
|
|
1740
|
+
if (child instanceof compiler.Text && child.value.trim() !== '') {
|
|
1739
1741
|
throw new Error(`Text node: "${child.value}" would result in invalid migrated @switch block structure. ` +
|
|
1740
1742
|
`@switch can only have @case or @default as children.`);
|
|
1741
1743
|
}
|
|
1742
|
-
else if (child instanceof
|
|
1744
|
+
else if (child instanceof compiler.Element) {
|
|
1743
1745
|
let hasCase = false;
|
|
1744
1746
|
for (const attr of child.attrs) {
|
|
1745
1747
|
if (cases.includes(attr.name)) {
|
|
@@ -1843,7 +1845,10 @@ function migrate(options) {
|
|
|
1843
1845
|
const basePath = process.cwd();
|
|
1844
1846
|
let pathToMigrate;
|
|
1845
1847
|
if (options.path) {
|
|
1846
|
-
|
|
1848
|
+
if (options.path.startsWith('..')) {
|
|
1849
|
+
throw new schematics.SchematicsException('Cannot run control flow migration outside of the current project.');
|
|
1850
|
+
}
|
|
1851
|
+
pathToMigrate = compiler_host.normalizePath(path.join(basePath, options.path));
|
|
1847
1852
|
if (pathToMigrate.trim() !== '') {
|
|
1848
1853
|
allPaths.push(pathToMigrate);
|
|
1849
1854
|
}
|
|
@@ -1853,33 +1858,31 @@ function migrate(options) {
|
|
|
1853
1858
|
allPaths = [...buildPaths, ...testPaths];
|
|
1854
1859
|
}
|
|
1855
1860
|
if (!allPaths.length) {
|
|
1856
|
-
|
|
1861
|
+
context.logger.warn('Could not find any tsconfig file. Cannot run the control flow migration.');
|
|
1862
|
+
return;
|
|
1857
1863
|
}
|
|
1858
1864
|
let errors = [];
|
|
1865
|
+
let sourceFilesCount = 0;
|
|
1859
1866
|
for (const tsconfigPath of allPaths) {
|
|
1860
|
-
const
|
|
1867
|
+
const program = compiler_host.createMigrationProgram(tree, tsconfigPath, basePath);
|
|
1868
|
+
const sourceFiles = program
|
|
1869
|
+
.getSourceFiles()
|
|
1870
|
+
.filter((sourceFile) => (pathToMigrate ? sourceFile.fileName.startsWith(pathToMigrate) : true) &&
|
|
1871
|
+
compiler_host.canMigrateFile(basePath, sourceFile, program));
|
|
1872
|
+
const migrateErrors = runControlFlowMigration(tree, sourceFiles, basePath, options);
|
|
1861
1873
|
errors = [...errors, ...migrateErrors];
|
|
1874
|
+
sourceFilesCount += sourceFiles.length;
|
|
1862
1875
|
}
|
|
1863
1876
|
if (errors.length > 0) {
|
|
1864
1877
|
context.logger.warn(`WARNING: ${errors.length} errors occurred during your migration:\n`);
|
|
1865
|
-
errors.forEach((err) =>
|
|
1866
|
-
|
|
1867
|
-
|
|
1878
|
+
errors.forEach((err) => context.logger.warn(err));
|
|
1879
|
+
}
|
|
1880
|
+
else if (sourceFilesCount === 0) {
|
|
1881
|
+
context.logger.warn('Control flow migration did not find any files to migrate');
|
|
1868
1882
|
}
|
|
1869
1883
|
};
|
|
1870
1884
|
}
|
|
1871
|
-
function runControlFlowMigration(tree,
|
|
1872
|
-
if (schematicOptions?.path?.startsWith('..')) {
|
|
1873
|
-
throw new schematics.SchematicsException('Cannot run control flow migration outside of the current project.');
|
|
1874
|
-
}
|
|
1875
|
-
const program = compiler_host.createMigrationProgram(tree, tsconfigPath, basePath);
|
|
1876
|
-
const sourceFiles = program
|
|
1877
|
-
.getSourceFiles()
|
|
1878
|
-
.filter((sourceFile) => (pathToMigrate ? sourceFile.fileName.startsWith(pathToMigrate) : true) &&
|
|
1879
|
-
compiler_host.canMigrateFile(basePath, sourceFile, program));
|
|
1880
|
-
if (sourceFiles.length === 0) {
|
|
1881
|
-
throw new schematics.SchematicsException(`Could not find any files to migrate under the path ${pathToMigrate}. Cannot run the control flow migration.`);
|
|
1882
|
-
}
|
|
1885
|
+
function runControlFlowMigration(tree, sourceFiles, basePath, schematicOptions) {
|
|
1883
1886
|
const analysis = new Map();
|
|
1884
1887
|
const migrateErrors = new Map();
|
|
1885
1888
|
for (const sourceFile of sourceFiles) {
|
|
@@ -1888,10 +1891,10 @@ function runControlFlowMigration(tree, tsconfigPath, basePath, pathToMigrate, sc
|
|
|
1888
1891
|
// sort files with .html files first
|
|
1889
1892
|
// this ensures class files know if it's safe to remove CommonModule
|
|
1890
1893
|
const paths = sortFilePaths([...analysis.keys()]);
|
|
1891
|
-
for (const path of paths) {
|
|
1892
|
-
const file = analysis.get(path);
|
|
1894
|
+
for (const path$1 of paths) {
|
|
1895
|
+
const file = analysis.get(path$1);
|
|
1893
1896
|
const ranges = file.getSortedRanges();
|
|
1894
|
-
const relativePath =
|
|
1897
|
+
const relativePath = path.relative(basePath, path$1);
|
|
1895
1898
|
const content = tree.readText(relativePath);
|
|
1896
1899
|
const update = tree.beginUpdate(relativePath);
|
|
1897
1900
|
for (const { start, end, node, type } of ranges) {
|
|
@@ -1903,7 +1906,7 @@ function runControlFlowMigration(tree, tsconfigPath, basePath, pathToMigrate, sc
|
|
|
1903
1906
|
update.insertLeft(start, migrated);
|
|
1904
1907
|
}
|
|
1905
1908
|
if (errors.length > 0) {
|
|
1906
|
-
migrateErrors.set(path, errors);
|
|
1909
|
+
migrateErrors.set(path$1, errors);
|
|
1907
1910
|
}
|
|
1908
1911
|
}
|
|
1909
1912
|
tree.commitUpdate(update);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
/**
|
|
3
|
-
* @license Angular v21.0.0-next.
|
|
3
|
+
* @license Angular v21.0.0-next.10
|
|
4
4
|
* (c) 2010-2025 Google LLC. https://angular.io/
|
|
5
5
|
* License: MIT
|
|
6
6
|
*/
|
|
@@ -49,6 +49,10 @@ function getImportOfIdentifier(typeChecker, node) {
|
|
|
49
49
|
function getImportSpecifier(sourceFile, moduleName, specifierName) {
|
|
50
50
|
return getImportSpecifiers(sourceFile, moduleName, specifierName)[0] ?? null;
|
|
51
51
|
}
|
|
52
|
+
/**
|
|
53
|
+
* Note: returns only matching imports specifiers,
|
|
54
|
+
* Unmatched imports will be ignored (you won't get undefined), but a shorter array.
|
|
55
|
+
*/
|
|
52
56
|
function getImportSpecifiers(sourceFile, moduleName, specifierOrSpecifiers) {
|
|
53
57
|
const matches = [];
|
|
54
58
|
for (const node of sourceFile.statements) {
|
|
@@ -102,4 +106,5 @@ function findImportSpecifier(nodes, specifierName) {
|
|
|
102
106
|
|
|
103
107
|
exports.getImportOfIdentifier = getImportOfIdentifier;
|
|
104
108
|
exports.getImportSpecifier = getImportSpecifier;
|
|
109
|
+
exports.getImportSpecifiers = getImportSpecifiers;
|
|
105
110
|
exports.getNamedImports = getNamedImports;
|