@angular/core 20.0.0-next.5 → 20.0.0-next.6

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 (68) hide show
  1. package/{api.d-mxcXqDpA.d.ts → api.d-DQLNOR5l.d.ts} +4 -4
  2. package/{discovery.d-CyYpOJ7j.d.ts → discovery.d-CFs2MaLO.d.ts} +7 -17
  3. package/{event_dispatcher.d-PWnbqZDx.d.ts → event_dispatcher.d-DlbccpYq.d.ts} +3 -3
  4. package/fesm2022/{attribute-B17mgaqe.mjs → attribute-BWp59EjE.mjs} +3 -3
  5. package/fesm2022/{attribute-B17mgaqe.mjs.map → attribute-BWp59EjE.mjs.map} +1 -1
  6. package/fesm2022/core.mjs +20 -18
  7. package/fesm2022/core.mjs.map +1 -1
  8. package/fesm2022/{debug_node-xKpCIZm-.mjs → debug_node-z_3NG8qT.mjs} +77 -68
  9. package/fesm2022/{debug_node-xKpCIZm-.mjs.map → debug_node-z_3NG8qT.mjs.map} +1 -1
  10. package/fesm2022/primitives/di.mjs +1 -1
  11. package/fesm2022/primitives/event-dispatch.mjs +2 -2
  12. package/fesm2022/primitives/signals.mjs +5 -5
  13. package/fesm2022/{resource-BPpYEDic.mjs → resource-CPPwEcg7.mjs} +6 -8
  14. package/fesm2022/resource-CPPwEcg7.mjs.map +1 -0
  15. package/fesm2022/{root_effect_scheduler-D0_b1cf_.mjs → root_effect_scheduler-VSXfCzDX.mjs} +46 -15
  16. package/fesm2022/root_effect_scheduler-VSXfCzDX.mjs.map +1 -0
  17. package/fesm2022/rxjs-interop.mjs +7 -84
  18. package/fesm2022/rxjs-interop.mjs.map +1 -1
  19. package/fesm2022/{signal-DhRAAi7R.mjs → signal-B6pMq7KS.mjs} +3 -3
  20. package/fesm2022/{signal-DhRAAi7R.mjs.map → signal-B6pMq7KS.mjs.map} +1 -1
  21. package/fesm2022/testing.mjs +165 -103
  22. package/fesm2022/testing.mjs.map +1 -1
  23. package/fesm2022/{untracked-DaaW3JJm.mjs → untracked-Bz5WMeU1.mjs} +4 -4
  24. package/fesm2022/{untracked-DaaW3JJm.mjs.map → untracked-Bz5WMeU1.mjs.map} +1 -1
  25. package/fesm2022/{weak_ref-DrMdAIDh.mjs → weak_ref-BaIq-pgY.mjs} +3 -3
  26. package/fesm2022/{weak_ref-DrMdAIDh.mjs.map → weak_ref-BaIq-pgY.mjs.map} +1 -1
  27. package/{graph.d-StYigYp1.d.ts → graph.d-BcIOep_B.d.ts} +3 -3
  28. package/index.d.ts +18 -20
  29. package/{ng_i18n_closure_mode.d-DLxSUiDr.d.ts → ng_i18n_closure_mode.d-C9d2CaSt.d.ts} +5 -5
  30. package/package.json +2 -2
  31. package/primitives/di/index.d.ts +1 -1
  32. package/primitives/event-dispatch/index.d.ts +3 -3
  33. package/primitives/signals/index.d.ts +6 -6
  34. package/rxjs-interop/index.d.ts +8 -17
  35. package/schematics/bundles/{apply_import_manager-C-ysxahq.js → apply_import_manager-DnMqg1pY.js} +6 -6
  36. package/schematics/bundles/{change_tracker-0Ktek5Xl.js → change_tracker-UMPkv-eH.js} +3 -3
  37. package/schematics/bundles/{checker-DqUKCGda.js → checker-BFBQyesT.js} +20 -3
  38. package/schematics/bundles/cleanup-unused-imports.js +25 -20
  39. package/schematics/bundles/{compiler-CuoiHqkc.js → compiler-BQ7R7w2v.js} +962 -297
  40. package/schematics/bundles/compiler_host-CAfDJO3W.js +1 -1
  41. package/schematics/bundles/control-flow-migration.js +2 -2
  42. package/schematics/bundles/document-core.js +12 -12
  43. package/schematics/bundles/imports-CIX-JgAN.js +1 -1
  44. package/schematics/bundles/{index-WFXCe5Q0.js → index-Cv4Q415G.js} +127 -36
  45. package/schematics/bundles/{index-CwFQSYXZ.js → index-D8tMJPKa.js} +10 -10
  46. package/schematics/bundles/inject-flags.js +14 -14
  47. package/schematics/bundles/inject-migration.js +4 -4
  48. package/schematics/bundles/leading_space-D9nQ8UQC.js +1 -1
  49. package/schematics/bundles/{migrate_ts_type_references-BNuHufqZ.js → migrate_ts_type_references-Cq_ZBuT4.js} +21 -21
  50. package/schematics/bundles/ng_decorators-DznZ5jMl.js +1 -1
  51. package/schematics/bundles/nodes-B16H9JUd.js +1 -1
  52. package/schematics/bundles/output-migration.js +80 -22
  53. package/schematics/bundles/{run_in_devkit-CmHxABFr.js → project_paths-ql6qcf_c.js} +254 -244
  54. package/schematics/bundles/project_tsconfig_paths-CDVxT6Ov.js +1 -1
  55. package/schematics/bundles/property_name-BBwFuqMe.js +1 -1
  56. package/schematics/bundles/route-lazy-loading.js +4 -4
  57. package/schematics/bundles/self-closing-tags-migration.js +20 -15
  58. package/schematics/bundles/signal-input-migration.js +26 -21
  59. package/schematics/bundles/signal-queries-migration.js +32 -27
  60. package/schematics/bundles/signals.js +8 -8
  61. package/schematics/bundles/standalone-migration.js +5 -5
  62. package/schematics/bundles/symbol-VPWguRxr.js +1 -1
  63. package/schematics/bundles/test-bed-get.js +13 -13
  64. package/{signal.d-BeaTIeOE.d.ts → signal.d-E0e5nW1p.d.ts} +4 -4
  65. package/testing/index.d.ts +9 -25
  66. package/{weak_ref.d-ttyj86RV.d.ts → weak_ref.d-eGOEP9S1.d.ts} +2 -2
  67. package/fesm2022/resource-BPpYEDic.mjs.map +0 -1
  68. package/fesm2022/root_effect_scheduler-D0_b1cf_.mjs.map +0 -1
@@ -1,19 +1,19 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v20.0.0-next.5
3
+ * @license Angular v20.0.0-next.6
4
4
  * (c) 2010-2025 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
7
7
  'use strict';
8
8
 
9
- var os = require('os');
10
- var ts = require('typescript');
11
- var checker = require('./checker-DqUKCGda.js');
12
- var index = require('./index-WFXCe5Q0.js');
9
+ var index = require('./index-Cv4Q415G.js');
13
10
  var schematics = require('@angular-devkit/schematics');
14
11
  var core = require('@angular-devkit/core');
15
12
  var posixPath = require('node:path/posix');
16
- require('./compiler-CuoiHqkc.js');
13
+ var os = require('os');
14
+ var ts = require('typescript');
15
+ var checker = require('./checker-BFBQyesT.js');
16
+ require('./compiler-BQ7R7w2v.js');
17
17
  require('path');
18
18
  var project_tsconfig_paths = require('./project_tsconfig_paths-CDVxT6Ov.js');
19
19
 
@@ -34,8 +34,8 @@ function _interopNamespaceDefault(e) {
34
34
  return Object.freeze(n);
35
35
  }
36
36
 
37
- var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
38
37
  var posixPath__namespace = /*#__PURE__*/_interopNamespaceDefault(posixPath);
38
+ var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
39
39
 
40
40
  /// <reference types="node" />
41
41
  class NgtscCompilerHost {
@@ -261,235 +261,6 @@ function getExtendedConfigPathWorker(configFile, extendsValue, host, fs) {
261
261
  return null;
262
262
  }
263
263
 
264
- /**
265
- * By default, Tsurge will always create an Angular compiler program
266
- * for projects analyzed and migrated. This works perfectly fine in
267
- * third-party where Tsurge migrations run in Angular CLI projects.
268
- *
269
- * In first party, when running against full Google3, creating an Angular
270
- * program for e.g. plain `ts_library` targets is overly expensive and
271
- * can result in out of memory issues for large TS targets. In 1P we can
272
- * reliably distinguish between TS and Angular targets via the `angularCompilerOptions`.
273
- */
274
- function google3UsePlainTsProgramIfNoKnownAngularOption() {
275
- return process.env['GOOGLE3_TSURGE'] === '1';
276
- }
277
-
278
- /** Options that are good defaults for Tsurge migrations. */
279
- const defaultMigrationTsOptions = {
280
- // Avoid checking libraries to speed up migrations.
281
- skipLibCheck: true,
282
- skipDefaultLibCheck: true,
283
- noEmit: true,
284
- // Does not apply to g3 and externally is enforced when the app is built by the compiler.
285
- disableTypeScriptVersionCheck: true,
286
- };
287
- /**
288
- * Creates an instance of a TypeScript program for the given project.
289
- */
290
- function createPlainTsProgram(tsHost, tsconfig, optionOverrides) {
291
- const program = ts.createProgram({
292
- rootNames: tsconfig.rootNames,
293
- options: {
294
- ...tsconfig.options,
295
- ...defaultMigrationTsOptions,
296
- ...optionOverrides,
297
- },
298
- });
299
- return {
300
- ngCompiler: null,
301
- program,
302
- userOptions: tsconfig.options,
303
- programAbsoluteRootFileNames: tsconfig.rootNames,
304
- host: tsHost,
305
- };
306
- }
307
-
308
- /**
309
- * Parses the configuration of the given TypeScript project and creates
310
- * an instance of the Angular compiler for the project.
311
- */
312
- function createNgtscProgram(tsHost, tsconfig, optionOverrides) {
313
- const ngtscProgram = new index.NgtscProgram(tsconfig.rootNames, {
314
- ...tsconfig.options,
315
- ...defaultMigrationTsOptions,
316
- ...optionOverrides,
317
- }, tsHost);
318
- // Expose an easy way to debug-print ng semantic diagnostics.
319
- if (process.env['DEBUG_NG_SEMANTIC_DIAGNOSTICS'] === '1') {
320
- console.error(ts.formatDiagnosticsWithColorAndContext(ngtscProgram.getNgSemanticDiagnostics(), tsHost));
321
- }
322
- return {
323
- ngCompiler: ngtscProgram.compiler,
324
- program: ngtscProgram.getTsProgram(),
325
- userOptions: tsconfig.options,
326
- programAbsoluteRootFileNames: tsconfig.rootNames,
327
- host: tsHost,
328
- };
329
- }
330
-
331
- /** Code of the error raised by TypeScript when a tsconfig doesn't match any files. */
332
- const NO_INPUTS_ERROR_CODE = 18003;
333
- /** Parses the given tsconfig file, supporting Angular compiler options. */
334
- function parseTsconfigOrDie(absoluteTsconfigPath, fs) {
335
- const tsconfig = readConfiguration(absoluteTsconfigPath, {}, fs);
336
- // Skip the "No inputs found..." error since we don't want to interrupt the migration if a
337
- // tsconfig doesn't match a file. This will result in an empty `Program` which is still valid.
338
- const errors = tsconfig.errors.filter((diag) => diag.code !== NO_INPUTS_ERROR_CODE);
339
- if (errors.length) {
340
- throw new Error(`Tsconfig could not be parsed or is invalid:\n\n` + `${errors.map((e) => e.messageText)}`);
341
- }
342
- return tsconfig;
343
- }
344
-
345
- /** Creates the base program info for the given tsconfig path. */
346
- function createBaseProgramInfo(absoluteTsconfigPath, fs, optionOverrides = {}) {
347
- if (fs === undefined) {
348
- fs = new checker.NodeJSFileSystem();
349
- checker.setFileSystem(fs);
350
- }
351
- const tsconfig = parseTsconfigOrDie(absoluteTsconfigPath, fs);
352
- const tsHost = new NgtscCompilerHost(fs, tsconfig.options);
353
- // When enabled, use a plain TS program if we are sure it's not
354
- // an Angular project based on the `tsconfig.json`.
355
- if (google3UsePlainTsProgramIfNoKnownAngularOption() &&
356
- tsconfig.options['_useHostForImportGeneration'] === undefined) {
357
- return createPlainTsProgram(tsHost, tsconfig, optionOverrides);
358
- }
359
- return createNgtscProgram(tsHost, tsconfig, optionOverrides);
360
- }
361
-
362
- /**
363
- * @private
364
- *
365
- * Base class for the possible Tsurge migration variants.
366
- *
367
- * For example, this class exposes methods to conveniently create
368
- * TypeScript programs, while also allowing migration authors to override.
369
- */
370
- class TsurgeBaseMigration {
371
- /**
372
- * Advanced Tsurge users can override this method, but most of the time,
373
- * overriding {@link prepareProgram} is more desirable.
374
- *
375
- * By default:
376
- * - In 3P: Ngtsc programs are being created.
377
- * - In 1P: Ngtsc or TS programs are created based on the Blaze target.
378
- */
379
- createProgram(tsconfigAbsPath, fs, optionOverrides) {
380
- return createBaseProgramInfo(tsconfigAbsPath, fs, optionOverrides);
381
- }
382
- // Optional function to prepare the base `ProgramInfo` even further,
383
- // for the analyze and migrate phases. E.g. determining source files.
384
- prepareProgram(info) {
385
- const fullProgramSourceFiles = [...info.program.getSourceFiles()];
386
- const sourceFiles = fullProgramSourceFiles.filter((f) => !f.isDeclarationFile &&
387
- // Note `isShim` will work for the initial program, but for TCB programs, the shims are no longer annotated.
388
- !checker.isShim(f) &&
389
- !f.fileName.endsWith('.ngtypecheck.ts'));
390
- // Sort it by length in reverse order (longest first). This speeds up lookups,
391
- // since there's no need to keep going through the array once a match is found.
392
- const sortedRootDirs = checker.getRootDirs(info.host, info.userOptions).sort((a, b) => b.length - a.length);
393
- // TODO: Consider also following TS's logic here, finding the common source root.
394
- // See: Program#getCommonSourceDirectory.
395
- const primaryRoot = checker.absoluteFrom(info.userOptions.rootDir ?? sortedRootDirs.at(-1) ?? info.program.getCurrentDirectory());
396
- return {
397
- ...info,
398
- sourceFiles,
399
- fullProgramSourceFiles,
400
- sortedRootDirs,
401
- projectRoot: primaryRoot,
402
- };
403
- }
404
- }
405
-
406
- /**
407
- * A simpler variant of a {@link TsurgeComplexMigration} that does not
408
- * fan-out into multiple workers per compilation unit to compute
409
- * the final migration replacements.
410
- *
411
- * This is faster and less resource intensive as workers and TS programs
412
- * are only ever created once.
413
- *
414
- * This is commonly the case when migrations are refactored to eagerly
415
- * compute replacements in the analyze stage, and then leverage the
416
- * global unit data to filter replacements that turned out to be "invalid".
417
- */
418
- class TsurgeFunnelMigration extends TsurgeBaseMigration {
419
- }
420
- /**
421
- * Complex variant of a `Tsurge` migration.
422
- *
423
- * For example, every analyze worker may contribute to a list of TS
424
- * references that are later combined. The migrate phase can then compute actual
425
- * file updates for all individual compilation units, leveraging the global metadata
426
- * to e.g. see if there are any references from other compilation units that may be
427
- * problematic and prevent migration of a given file.
428
- */
429
- class TsurgeComplexMigration extends TsurgeBaseMigration {
430
- }
431
-
432
- /** A text replacement for the given file. */
433
- class Replacement {
434
- projectFile;
435
- update;
436
- constructor(projectFile, update) {
437
- this.projectFile = projectFile;
438
- this.update = update;
439
- }
440
- }
441
- /** An isolated text update that may be applied to a file. */
442
- class TextUpdate {
443
- data;
444
- constructor(data) {
445
- this.data = data;
446
- }
447
- }
448
-
449
- /** Confirms that the given data `T` is serializable. */
450
- function confirmAsSerializable(data) {
451
- return data;
452
- }
453
-
454
- /**
455
- * Gets a project file instance for the given file.
456
- *
457
- * Use this helper for dealing with project paths throughout your
458
- * migration. The return type is serializable.
459
- *
460
- * See {@link ProjectFile}.
461
- */
462
- function projectFile(file, { sortedRootDirs, projectRoot }) {
463
- const fs = checker.getFileSystem();
464
- const filePath = fs.resolve(typeof file === 'string' ? file : file.fileName);
465
- // Sorted root directories are sorted longest to shortest. First match
466
- // is the appropriate root directory for ID computation.
467
- for (const rootDir of sortedRootDirs) {
468
- if (!isWithinBasePath(fs, rootDir, filePath)) {
469
- continue;
470
- }
471
- return {
472
- id: fs.relative(rootDir, filePath),
473
- rootRelativePath: fs.relative(projectRoot, filePath),
474
- };
475
- }
476
- // E.g. project directory may be `src/`, but files may be looked up
477
- // from `node_modules/`. This is fine, but in those cases, no root
478
- // directory matches.
479
- const rootRelativePath = fs.relative(projectRoot, filePath);
480
- return {
481
- id: rootRelativePath,
482
- rootRelativePath: rootRelativePath,
483
- };
484
- }
485
- /**
486
- * Whether `path` is a descendant of the `base`?
487
- * E.g. `a/b/c` is within `a/b` but not within `a/x`.
488
- */
489
- function isWithinBasePath(fs, base, path) {
490
- return checker.isLocalRelativePath(fs.relative(base, path));
491
- }
492
-
493
264
  /**
494
265
  * Angular compiler file system implementation that leverages an
495
266
  * CLI schematic virtual file tree.
@@ -671,6 +442,174 @@ async function synchronouslyCombineUnitData(migration, unitDatas) {
671
442
  return combined;
672
443
  }
673
444
 
445
+ /**
446
+ * By default, Tsurge will always create an Angular compiler program
447
+ * for projects analyzed and migrated. This works perfectly fine in
448
+ * third-party where Tsurge migrations run in Angular CLI projects.
449
+ *
450
+ * In first party, when running against full Google3, creating an Angular
451
+ * program for e.g. plain `ts_library` targets is overly expensive and
452
+ * can result in out of memory issues for large TS targets. In 1P we can
453
+ * reliably distinguish between TS and Angular targets via the `angularCompilerOptions`.
454
+ */
455
+ function google3UsePlainTsProgramIfNoKnownAngularOption() {
456
+ return process.env['GOOGLE3_TSURGE'] === '1';
457
+ }
458
+
459
+ /** Options that are good defaults for Tsurge migrations. */
460
+ const defaultMigrationTsOptions = {
461
+ // Avoid checking libraries to speed up migrations.
462
+ skipLibCheck: true,
463
+ skipDefaultLibCheck: true,
464
+ noEmit: true,
465
+ // Does not apply to g3 and externally is enforced when the app is built by the compiler.
466
+ disableTypeScriptVersionCheck: true,
467
+ };
468
+ /**
469
+ * Creates an instance of a TypeScript program for the given project.
470
+ */
471
+ function createPlainTsProgram(tsHost, tsconfig, optionOverrides) {
472
+ const program = ts.createProgram({
473
+ rootNames: tsconfig.rootNames,
474
+ options: {
475
+ ...tsconfig.options,
476
+ ...defaultMigrationTsOptions,
477
+ ...optionOverrides,
478
+ },
479
+ });
480
+ return {
481
+ ngCompiler: null,
482
+ program,
483
+ userOptions: tsconfig.options,
484
+ programAbsoluteRootFileNames: tsconfig.rootNames,
485
+ host: tsHost,
486
+ };
487
+ }
488
+
489
+ /**
490
+ * Parses the configuration of the given TypeScript project and creates
491
+ * an instance of the Angular compiler for the project.
492
+ */
493
+ function createNgtscProgram(tsHost, tsconfig, optionOverrides) {
494
+ const ngtscProgram = new index.NgtscProgram(tsconfig.rootNames, {
495
+ ...tsconfig.options,
496
+ ...defaultMigrationTsOptions,
497
+ ...optionOverrides,
498
+ }, tsHost);
499
+ // Expose an easy way to debug-print ng semantic diagnostics.
500
+ if (process.env['DEBUG_NG_SEMANTIC_DIAGNOSTICS'] === '1') {
501
+ console.error(ts.formatDiagnosticsWithColorAndContext(ngtscProgram.getNgSemanticDiagnostics(), tsHost));
502
+ }
503
+ return {
504
+ ngCompiler: ngtscProgram.compiler,
505
+ program: ngtscProgram.getTsProgram(),
506
+ userOptions: tsconfig.options,
507
+ programAbsoluteRootFileNames: tsconfig.rootNames,
508
+ host: tsHost,
509
+ };
510
+ }
511
+
512
+ /** Code of the error raised by TypeScript when a tsconfig doesn't match any files. */
513
+ const NO_INPUTS_ERROR_CODE = 18003;
514
+ /** Parses the given tsconfig file, supporting Angular compiler options. */
515
+ function parseTsconfigOrDie(absoluteTsconfigPath, fs) {
516
+ const tsconfig = readConfiguration(absoluteTsconfigPath, {}, fs);
517
+ // Skip the "No inputs found..." error since we don't want to interrupt the migration if a
518
+ // tsconfig doesn't match a file. This will result in an empty `Program` which is still valid.
519
+ const errors = tsconfig.errors.filter((diag) => diag.code !== NO_INPUTS_ERROR_CODE);
520
+ if (errors.length) {
521
+ throw new Error(`Tsconfig could not be parsed or is invalid:\n\n` + `${errors.map((e) => e.messageText)}`);
522
+ }
523
+ return tsconfig;
524
+ }
525
+
526
+ /** Creates the base program info for the given tsconfig path. */
527
+ function createBaseProgramInfo(absoluteTsconfigPath, fs, optionOverrides = {}) {
528
+ if (fs === undefined) {
529
+ fs = new checker.NodeJSFileSystem();
530
+ checker.setFileSystem(fs);
531
+ }
532
+ const tsconfig = parseTsconfigOrDie(absoluteTsconfigPath, fs);
533
+ const tsHost = new NgtscCompilerHost(fs, tsconfig.options);
534
+ // When enabled, use a plain TS program if we are sure it's not
535
+ // an Angular project based on the `tsconfig.json`.
536
+ if (google3UsePlainTsProgramIfNoKnownAngularOption() &&
537
+ tsconfig.options['_useHostForImportGeneration'] === undefined) {
538
+ return createPlainTsProgram(tsHost, tsconfig, optionOverrides);
539
+ }
540
+ return createNgtscProgram(tsHost, tsconfig, optionOverrides);
541
+ }
542
+
543
+ /**
544
+ * @private
545
+ *
546
+ * Base class for the possible Tsurge migration variants.
547
+ *
548
+ * For example, this class exposes methods to conveniently create
549
+ * TypeScript programs, while also allowing migration authors to override.
550
+ */
551
+ class TsurgeBaseMigration {
552
+ /**
553
+ * Advanced Tsurge users can override this method, but most of the time,
554
+ * overriding {@link prepareProgram} is more desirable.
555
+ *
556
+ * By default:
557
+ * - In 3P: Ngtsc programs are being created.
558
+ * - In 1P: Ngtsc or TS programs are created based on the Blaze target.
559
+ */
560
+ createProgram(tsconfigAbsPath, fs, optionOverrides) {
561
+ return createBaseProgramInfo(tsconfigAbsPath, fs, optionOverrides);
562
+ }
563
+ // Optional function to prepare the base `ProgramInfo` even further,
564
+ // for the analyze and migrate phases. E.g. determining source files.
565
+ prepareProgram(info) {
566
+ const fullProgramSourceFiles = [...info.program.getSourceFiles()];
567
+ const sourceFiles = fullProgramSourceFiles.filter((f) => !f.isDeclarationFile &&
568
+ // Note `isShim` will work for the initial program, but for TCB programs, the shims are no longer annotated.
569
+ !checker.isShim(f) &&
570
+ !f.fileName.endsWith('.ngtypecheck.ts'));
571
+ // Sort it by length in reverse order (longest first). This speeds up lookups,
572
+ // since there's no need to keep going through the array once a match is found.
573
+ const sortedRootDirs = checker.getRootDirs(info.host, info.userOptions).sort((a, b) => b.length - a.length);
574
+ // TODO: Consider also following TS's logic here, finding the common source root.
575
+ // See: Program#getCommonSourceDirectory.
576
+ const primaryRoot = checker.absoluteFrom(info.userOptions.rootDir ?? sortedRootDirs.at(-1) ?? info.program.getCurrentDirectory());
577
+ return {
578
+ ...info,
579
+ sourceFiles,
580
+ fullProgramSourceFiles,
581
+ sortedRootDirs,
582
+ projectRoot: primaryRoot,
583
+ };
584
+ }
585
+ }
586
+
587
+ /**
588
+ * A simpler variant of a {@link TsurgeComplexMigration} that does not
589
+ * fan-out into multiple workers per compilation unit to compute
590
+ * the final migration replacements.
591
+ *
592
+ * This is faster and less resource intensive as workers and TS programs
593
+ * are only ever created once.
594
+ *
595
+ * This is commonly the case when migrations are refactored to eagerly
596
+ * compute replacements in the analyze stage, and then leverage the
597
+ * global unit data to filter replacements that turned out to be "invalid".
598
+ */
599
+ class TsurgeFunnelMigration extends TsurgeBaseMigration {
600
+ }
601
+ /**
602
+ * Complex variant of a `Tsurge` migration.
603
+ *
604
+ * For example, every analyze worker may contribute to a list of TS
605
+ * references that are later combined. The migrate phase can then compute actual
606
+ * file updates for all individual compilation units, leveraging the global metadata
607
+ * to e.g. see if there are any references from other compilation units that may be
608
+ * problematic and prevent migration of a given file.
609
+ */
610
+ class TsurgeComplexMigration extends TsurgeBaseMigration {
611
+ }
612
+
674
613
  /*!
675
614
  * @license
676
615
  * Copyright Google LLC All Rights Reserved.
@@ -678,24 +617,30 @@ async function synchronouslyCombineUnitData(migration, unitDatas) {
678
617
  * Use of this source code is governed by an MIT-style license that can be
679
618
  * found in the LICENSE file at https://angular.dev/license
680
619
  */
620
+ exports.MigrationStage = void 0;
621
+ (function (MigrationStage) {
622
+ /** The migration is analyzing an entrypoint */
623
+ MigrationStage[MigrationStage["Analysis"] = 0] = "Analysis";
624
+ /** The migration is about to migrate an entrypoint */
625
+ MigrationStage[MigrationStage["Migrate"] = 1] = "Migrate";
626
+ })(exports.MigrationStage || (exports.MigrationStage = {}));
681
627
  /** Runs a Tsurge within an Angular Devkit context. */
682
628
  async function runMigrationInDevkit(config) {
683
629
  const { buildPaths, testPaths } = await project_tsconfig_paths.getProjectTsConfigPaths(config.tree);
684
630
  if (!buildPaths.length && !testPaths.length) {
685
631
  throw new schematics.SchematicsException('Could not find any tsconfig file. Cannot run the migration.');
686
632
  }
633
+ const tsconfigPaths = [...buildPaths, ...testPaths];
687
634
  const fs = new DevkitMigrationFilesystem(config.tree);
688
635
  checker.setFileSystem(fs);
689
636
  const migration = config.getMigration(fs);
690
637
  const unitResults = [];
691
- const programInfos = [...buildPaths, ...testPaths].map((tsconfigPath) => {
692
- config.beforeProgramCreation?.(tsconfigPath);
638
+ const isFunnelMigration = migration instanceof TsurgeFunnelMigration;
639
+ for (const tsconfigPath of tsconfigPaths) {
640
+ config.beforeProgramCreation?.(tsconfigPath, exports.MigrationStage.Analysis);
693
641
  const baseInfo = migration.createProgram(tsconfigPath, fs);
694
642
  const info = migration.prepareProgram(baseInfo);
695
- config.afterProgramCreation?.(info, fs);
696
- return { info, tsconfigPath };
697
- });
698
- for (const { info, tsconfigPath } of programInfos) {
643
+ config.afterProgramCreation?.(info, fs, exports.MigrationStage.Analysis);
699
644
  config.beforeUnitAnalysis?.(tsconfigPath);
700
645
  unitResults.push(await migration.analyze(info));
701
646
  }
@@ -707,12 +652,16 @@ async function runMigrationInDevkit(config) {
707
652
  }
708
653
  const globalMeta = await migration.globalMeta(combined);
709
654
  let replacements;
710
- if (migration instanceof TsurgeFunnelMigration) {
655
+ if (isFunnelMigration) {
711
656
  replacements = (await migration.migrate(globalMeta)).replacements;
712
657
  }
713
658
  else {
714
659
  replacements = [];
715
- for (const { info } of programInfos) {
660
+ for (const tsconfigPath of tsconfigPaths) {
661
+ config.beforeProgramCreation?.(tsconfigPath, exports.MigrationStage.Migrate);
662
+ const baseInfo = migration.createProgram(tsconfigPath, fs);
663
+ const info = migration.prepareProgram(baseInfo);
664
+ config.afterProgramCreation?.(info, fs, exports.MigrationStage.Migrate);
716
665
  const result = await migration.migrate(globalMeta, info);
717
666
  replacements.push(...result.replacements);
718
667
  }
@@ -736,6 +685,67 @@ async function runMigrationInDevkit(config) {
736
685
  config.whenDone?.(await migration.stats(globalMeta));
737
686
  }
738
687
 
688
+ /** A text replacement for the given file. */
689
+ class Replacement {
690
+ projectFile;
691
+ update;
692
+ constructor(projectFile, update) {
693
+ this.projectFile = projectFile;
694
+ this.update = update;
695
+ }
696
+ }
697
+ /** An isolated text update that may be applied to a file. */
698
+ class TextUpdate {
699
+ data;
700
+ constructor(data) {
701
+ this.data = data;
702
+ }
703
+ }
704
+
705
+ /** Confirms that the given data `T` is serializable. */
706
+ function confirmAsSerializable(data) {
707
+ return data;
708
+ }
709
+
710
+ /**
711
+ * Gets a project file instance for the given file.
712
+ *
713
+ * Use this helper for dealing with project paths throughout your
714
+ * migration. The return type is serializable.
715
+ *
716
+ * See {@link ProjectFile}.
717
+ */
718
+ function projectFile(file, { sortedRootDirs, projectRoot }) {
719
+ const fs = checker.getFileSystem();
720
+ const filePath = fs.resolve(typeof file === 'string' ? file : file.fileName);
721
+ // Sorted root directories are sorted longest to shortest. First match
722
+ // is the appropriate root directory for ID computation.
723
+ for (const rootDir of sortedRootDirs) {
724
+ if (!isWithinBasePath(fs, rootDir, filePath)) {
725
+ continue;
726
+ }
727
+ return {
728
+ id: fs.relative(rootDir, filePath),
729
+ rootRelativePath: fs.relative(projectRoot, filePath),
730
+ };
731
+ }
732
+ // E.g. project directory may be `src/`, but files may be looked up
733
+ // from `node_modules/`. This is fine, but in those cases, no root
734
+ // directory matches.
735
+ const rootRelativePath = fs.relative(projectRoot, filePath);
736
+ return {
737
+ id: rootRelativePath,
738
+ rootRelativePath: rootRelativePath,
739
+ };
740
+ }
741
+ /**
742
+ * Whether `path` is a descendant of the `base`?
743
+ * E.g. `a/b/c` is within `a/b` but not within `a/x`.
744
+ */
745
+ function isWithinBasePath(fs, base, path) {
746
+ return checker.isLocalRelativePath(fs.relative(base, path));
747
+ }
748
+
739
749
  exports.Replacement = Replacement;
740
750
  exports.TextUpdate = TextUpdate;
741
751
  exports.TsurgeComplexMigration = TsurgeComplexMigration;
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v20.0.0-next.5
3
+ * @license Angular v20.0.0-next.6
4
4
  * (c) 2010-2025 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v20.0.0-next.5
3
+ * @license Angular v20.0.0-next.6
4
4
  * (c) 2010-2025 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v20.0.0-next.5
3
+ * @license Angular v20.0.0-next.6
4
4
  * (c) 2010-2025 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
@@ -9,13 +9,13 @@
9
9
  var schematics = require('@angular-devkit/schematics');
10
10
  var fs = require('fs');
11
11
  var p = require('path');
12
- var change_tracker = require('./change_tracker-0Ktek5Xl.js');
12
+ var change_tracker = require('./change_tracker-UMPkv-eH.js');
13
13
  var project_tsconfig_paths = require('./project_tsconfig_paths-CDVxT6Ov.js');
14
14
  var compiler_host = require('./compiler_host-CAfDJO3W.js');
15
15
  var ts = require('typescript');
16
- var checker = require('./checker-DqUKCGda.js');
16
+ var checker = require('./checker-BFBQyesT.js');
17
17
  var property_name = require('./property_name-BBwFuqMe.js');
18
- require('./compiler-CuoiHqkc.js');
18
+ require('./compiler-BQ7R7w2v.js');
19
19
  require('os');
20
20
  require('@angular-devkit/core');
21
21
  require('module');