@angular/core 20.0.0-next.1 → 20.0.0-next.3

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 (54) hide show
  1. package/fesm2022/core.mjs +770 -2144
  2. package/fesm2022/core.mjs.map +1 -1
  3. package/fesm2022/primitives/di.mjs +3 -2
  4. package/fesm2022/primitives/di.mjs.map +1 -1
  5. package/fesm2022/primitives/event-dispatch.mjs +2 -589
  6. package/fesm2022/primitives/event-dispatch.mjs.map +1 -1
  7. package/fesm2022/primitives/signals.mjs +44 -13
  8. package/fesm2022/primitives/signals.mjs.map +1 -1
  9. package/fesm2022/rxjs-interop.mjs +7 -39
  10. package/fesm2022/rxjs-interop.mjs.map +1 -1
  11. package/fesm2022/testing.mjs +116 -143
  12. package/fesm2022/testing.mjs.map +1 -1
  13. package/fesm2022/weak_ref-DrMdAIDh.mjs +12 -0
  14. package/fesm2022/weak_ref-DrMdAIDh.mjs.map +1 -0
  15. package/index.d.ts +14366 -15214
  16. package/navigation_types.d-u4EOrrdZ.d.ts +121 -0
  17. package/package.json +2 -2
  18. package/primitives/di/index.d.ts +66 -59
  19. package/primitives/event-dispatch/index.d.ts +205 -309
  20. package/primitives/signals/index.d.ts +161 -195
  21. package/rxjs-interop/index.d.ts +71 -100
  22. package/schematics/bundles/{apply_import_manager-e2a7fe5b.js → apply_import_manager-BXQEjo09.js} +15 -19
  23. package/schematics/bundles/{checker-af521da6.js → checker-BHb19MHt.js} +3695 -1175
  24. package/schematics/bundles/cleanup-unused-imports.js +56 -89
  25. package/schematics/bundles/{compiler_host-5a29293c.js → compiler_host-Bk3repE2.js} +19 -23
  26. package/schematics/bundles/control-flow-migration.js +81 -38
  27. package/schematics/bundles/{imports-047fbbc8.js → imports-CIX-JgAN.js} +9 -14
  28. package/schematics/bundles/{index-1bef3025.js → index-BL9kAIe5.js} +62 -66
  29. package/schematics/bundles/{program-a449f9bf.js → index-I8VbxQcO.js} +1508 -3178
  30. package/schematics/bundles/inject-flags.js +147 -0
  31. package/schematics/bundles/inject-migration.js +121 -127
  32. package/schematics/bundles/{leading_space-f8944434.js → leading_space-D9nQ8UQC.js} +1 -1
  33. package/schematics/bundles/{migrate_ts_type_references-2a3e9e6b.js → migrate_ts_type_references-KlOTWeDl.js} +121 -126
  34. package/schematics/bundles/{ng_decorators-b0d8b324.js → ng_decorators-DznZ5jMl.js} +4 -8
  35. package/schematics/bundles/{nodes-7758dbf6.js → nodes-B16H9JUd.js} +2 -6
  36. package/schematics/bundles/output-migration.js +94 -128
  37. package/schematics/bundles/{project_tsconfig_paths-b558633b.js → project_tsconfig_paths-CDVxT6Ov.js} +1 -1
  38. package/schematics/bundles/{property_name-ac18447e.js → property_name-BBwFuqMe.js} +3 -7
  39. package/schematics/bundles/route-lazy-loading.js +35 -41
  40. package/schematics/bundles/{project_paths-17dc204d.js → run_in_devkit-C0JPtK2u.js} +283 -216
  41. package/schematics/bundles/self-closing-tags-migration.js +55 -91
  42. package/schematics/bundles/signal-input-migration.js +121 -156
  43. package/schematics/bundles/signal-queries-migration.js +119 -154
  44. package/schematics/bundles/signals.js +12 -14
  45. package/schematics/bundles/standalone-migration.js +180 -200
  46. package/schematics/bundles/symbol-VPWguRxr.js +25 -0
  47. package/schematics/bundles/test-bed-get.js +98 -0
  48. package/schematics/migrations.json +8 -14
  49. package/testing/index.d.ts +289 -471
  50. package/weak_ref.d-ttyj86RV.d.ts +9 -0
  51. package/schematics/bundles/explicit-standalone-flag.js +0 -184
  52. package/schematics/bundles/index-ef1bffbb.js +0 -30
  53. package/schematics/bundles/pending-tasks.js +0 -103
  54. package/schematics/bundles/provide-initializer.js +0 -186
@@ -1,23 +1,22 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v20.0.0-next.1
3
+ * @license Angular v20.0.0-next.3
4
4
  * (c) 2010-2025 Google LLC. https://angular.io/
5
5
  * License: MIT
6
6
  */
7
7
  'use strict';
8
8
 
9
- var core = require('@angular-devkit/core');
10
- var posixPath = require('node:path/posix');
11
9
  var os = require('os');
12
10
  var ts = require('typescript');
13
- var checker = require('./checker-af521da6.js');
14
- var program = require('./program-a449f9bf.js');
11
+ var checker = require('./checker-BHb19MHt.js');
12
+ var index = require('./index-I8VbxQcO.js');
13
+ var schematics = require('@angular-devkit/schematics');
14
+ var core = require('@angular-devkit/core');
15
+ var posixPath = require('node:path/posix');
15
16
  require('path');
17
+ var project_tsconfig_paths = require('./project_tsconfig_paths-CDVxT6Ov.js');
16
18
 
17
- function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
18
-
19
- function _interopNamespace(e) {
20
- if (e && e.__esModule) return e;
19
+ function _interopNamespaceDefault(e) {
21
20
  var n = Object.create(null);
22
21
  if (e) {
23
22
  Object.keys(e).forEach(function (k) {
@@ -30,13 +29,12 @@ function _interopNamespace(e) {
30
29
  }
31
30
  });
32
31
  }
33
- n["default"] = e;
32
+ n.default = e;
34
33
  return Object.freeze(n);
35
34
  }
36
35
 
37
- var posixPath__namespace = /*#__PURE__*/_interopNamespace(posixPath);
38
- var os__namespace = /*#__PURE__*/_interopNamespace(os);
39
- var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts);
36
+ var os__namespace = /*#__PURE__*/_interopNamespaceDefault(os);
37
+ var posixPath__namespace = /*#__PURE__*/_interopNamespaceDefault(posixPath);
40
38
 
41
39
  /// <reference types="node" />
42
40
  class NgtscCompilerHost {
@@ -49,11 +47,11 @@ class NgtscCompilerHost {
49
47
  getSourceFile(fileName, languageVersion) {
50
48
  const text = this.readFile(fileName);
51
49
  return text !== undefined
52
- ? ts__default["default"].createSourceFile(fileName, text, languageVersion, true)
50
+ ? ts.createSourceFile(fileName, text, languageVersion, true)
53
51
  : undefined;
54
52
  }
55
53
  getDefaultLibFileName(options) {
56
- return this.fs.join(this.getDefaultLibLocation(), ts__default["default"].getDefaultLibFileName(options));
54
+ return this.fs.join(this.getDefaultLibLocation(), ts.getDefaultLibFileName(options));
57
55
  }
58
56
  getDefaultLibLocation() {
59
57
  return this.fs.getDefaultLibLocation();
@@ -74,9 +72,9 @@ class NgtscCompilerHost {
74
72
  }
75
73
  getNewLine() {
76
74
  switch (this.options.newLine) {
77
- case ts__default["default"].NewLineKind.CarriageReturnLineFeed:
75
+ case ts.NewLineKind.CarriageReturnLineFeed:
78
76
  return '\r\n';
79
- case ts__default["default"].NewLineKind.LineFeed:
77
+ case ts.NewLineKind.LineFeed:
80
78
  return '\n';
81
79
  default:
82
80
  return os__namespace.EOL;
@@ -99,17 +97,23 @@ class NgtscCompilerHost {
99
97
  }
100
98
 
101
99
  // We use TypeScript's native `ts.matchFiles` utility for the virtual file systems
100
+ // and their TypeScript compiler host `readDirectory` implementation. TypeScript's
101
+ // function implements complex logic for matching files with respect to root
102
+ // directory, extensions, excludes, includes etc. The function is currently
103
+ // internal but we can use it as the API most likely will not change any time soon,
104
+ // nor does it seem like this is being made public any time soon.
105
+ // Related issue for tracking: https://github.com/microsoft/TypeScript/issues/13793.
102
106
  /**
103
107
  * Creates a {@link ts.CompilerHost#readDirectory} implementation function,
104
108
  * that leverages the specified file system (that may be e.g. virtual).
105
109
  */
106
110
  function createFileSystemTsReadDirectoryFn(fs) {
107
- if (ts__default["default"].matchFiles === undefined) {
111
+ if (ts.matchFiles === undefined) {
108
112
  throw Error('Unable to read directory in configured file system. This means that ' +
109
113
  'TypeScript changed its file matching internals.\n\nPlease consider downgrading your ' +
110
114
  'TypeScript version, and report an issue in the Angular framework repository.');
111
115
  }
112
- const matchFilesFn = ts__default["default"].matchFiles.bind(ts__default["default"]);
116
+ const matchFilesFn = ts.matchFiles.bind(ts);
113
117
  return (rootDir, extensions, excludes, includes, depth) => {
114
118
  const directoryExists = (p) => {
115
119
  const resolvedPath = fs.resolve(p);
@@ -148,7 +152,7 @@ function calcProjectFileAndBasePath(project, host = checker.getFileSystem()) {
148
152
  function readConfiguration(project, existingOptions, host = checker.getFileSystem()) {
149
153
  try {
150
154
  const fs = checker.getFileSystem();
151
- const readConfigFile = (configFile) => ts__default["default"].readConfigFile(configFile, (file) => host.readFile(host.resolve(file)));
155
+ const readConfigFile = (configFile) => ts.readConfigFile(configFile, (file) => host.readFile(host.resolve(file)));
152
156
  const readAngularCompilerOptions = (configFile, parentOptions = {}) => {
153
157
  const { config, error } = readConfigFile(configFile);
154
158
  if (error) {
@@ -185,7 +189,7 @@ function readConfiguration(project, existingOptions, host = checker.getFileSyste
185
189
  errors: [error],
186
190
  rootNames: [],
187
191
  options: {},
188
- emitFlags: program.EmitFlags.Default,
192
+ emitFlags: index.EmitFlags.Default,
189
193
  };
190
194
  }
191
195
  const existingCompilerOptions = {
@@ -195,29 +199,29 @@ function readConfiguration(project, existingOptions, host = checker.getFileSyste
195
199
  ...existingOptions,
196
200
  };
197
201
  const parseConfigHost = createParseConfigHost(host, fs);
198
- const { options, errors, fileNames: rootNames, projectReferences, } = ts__default["default"].parseJsonConfigFileContent(config, parseConfigHost, basePath, existingCompilerOptions, configFileName);
199
- let emitFlags = program.EmitFlags.Default;
202
+ const { options, errors, fileNames: rootNames, projectReferences, } = ts.parseJsonConfigFileContent(config, parseConfigHost, basePath, existingCompilerOptions, configFileName);
203
+ let emitFlags = index.EmitFlags.Default;
200
204
  if (!(options['skipMetadataEmit'] || options['flatModuleOutFile'])) {
201
- emitFlags |= program.EmitFlags.Metadata;
205
+ emitFlags |= index.EmitFlags.Metadata;
202
206
  }
203
207
  if (options['skipTemplateCodegen']) {
204
- emitFlags = emitFlags & ~program.EmitFlags.Codegen;
208
+ emitFlags = emitFlags & ~index.EmitFlags.Codegen;
205
209
  }
206
210
  return { project: projectFile, rootNames, projectReferences, options, errors, emitFlags };
207
211
  }
208
212
  catch (e) {
209
213
  const errors = [
210
214
  {
211
- category: ts__default["default"].DiagnosticCategory.Error,
215
+ category: ts.DiagnosticCategory.Error,
212
216
  messageText: e.stack ?? e.message,
213
217
  file: undefined,
214
218
  start: undefined,
215
219
  length: undefined,
216
220
  source: 'angular',
217
- code: program.UNKNOWN_ERROR_CODE,
221
+ code: index.UNKNOWN_ERROR_CODE,
218
222
  },
219
223
  ];
220
- return { project: '', errors, rootNames: [], options: {}, emitFlags: program.EmitFlags.Default };
224
+ return { project: '', errors, rootNames: [], options: {}, emitFlags: index.EmitFlags.Default };
221
225
  }
222
226
  }
223
227
  function createParseConfigHost(host, fs = checker.getFileSystem()) {
@@ -248,7 +252,7 @@ function getExtendedConfigPathWorker(configFile, extendsValue, host, fs) {
248
252
  else {
249
253
  const parseConfigHost = createParseConfigHost(host, fs);
250
254
  // Path isn't a rooted or relative path, resolve like a module.
251
- const { resolvedModule } = ts__default["default"].nodeModuleNameResolver(extendsValue, configFile, { moduleResolution: ts__default["default"].ModuleResolutionKind.Node10, resolveJsonModule: true }, parseConfigHost);
255
+ const { resolvedModule } = ts.nodeModuleNameResolver(extendsValue, configFile, { moduleResolution: ts.ModuleResolutionKind.Node10, resolveJsonModule: true }, parseConfigHost);
252
256
  if (resolvedModule) {
253
257
  return checker.absoluteFrom(resolvedModule.resolvedFileName);
254
258
  }
@@ -256,187 +260,6 @@ function getExtendedConfigPathWorker(configFile, extendsValue, host, fs) {
256
260
  return null;
257
261
  }
258
262
 
259
- /**
260
- * Angular compiler file system implementation that leverages an
261
- * CLI schematic virtual file tree.
262
- */
263
- class DevkitMigrationFilesystem {
264
- tree;
265
- constructor(tree) {
266
- this.tree = tree;
267
- }
268
- extname(path) {
269
- return core.extname(path);
270
- }
271
- isRoot(path) {
272
- return path === core.normalize('/');
273
- }
274
- isRooted(path) {
275
- return this.normalize(path).startsWith('/');
276
- }
277
- dirname(file) {
278
- return this.normalize(core.dirname(file));
279
- }
280
- join(basePath, ...paths) {
281
- return this.normalize(core.join(basePath, ...paths));
282
- }
283
- relative(from, to) {
284
- return this.normalize(core.relative(from, to));
285
- }
286
- basename(filePath, extension) {
287
- return posixPath__namespace.basename(filePath, extension);
288
- }
289
- normalize(path) {
290
- return core.normalize(path);
291
- }
292
- resolve(...paths) {
293
- const normalizedPaths = paths.map((p) => core.normalize(p));
294
- // In dev-kit, the NodeJS working directory should never be
295
- // considered, so `/` is the last resort over `cwd`.
296
- return this.normalize(posixPath__namespace.resolve(core.normalize('/'), ...normalizedPaths));
297
- }
298
- pwd() {
299
- return '/';
300
- }
301
- isCaseSensitive() {
302
- return true;
303
- }
304
- exists(path) {
305
- return statPath(this.tree, path) !== null;
306
- }
307
- readFile(path) {
308
- return this.tree.readText(path);
309
- }
310
- readFileBuffer(path) {
311
- const buffer = this.tree.read(path);
312
- if (buffer === null) {
313
- throw new Error(`File does not exist: ${path}`);
314
- }
315
- return buffer;
316
- }
317
- readdir(path) {
318
- const dir = this.tree.getDir(path);
319
- return [
320
- ...dir.subdirs,
321
- ...dir.subfiles,
322
- ];
323
- }
324
- lstat(path) {
325
- const stat = statPath(this.tree, path);
326
- if (stat === null) {
327
- throw new Error(`File does not exist for "lstat": ${path}`);
328
- }
329
- return stat;
330
- }
331
- stat(path) {
332
- const stat = statPath(this.tree, path);
333
- if (stat === null) {
334
- throw new Error(`File does not exist for "stat": ${path}`);
335
- }
336
- return stat;
337
- }
338
- realpath(filePath) {
339
- return filePath;
340
- }
341
- getDefaultLibLocation() {
342
- return 'node_modules/typescript/lib';
343
- }
344
- ensureDir(path) {
345
- // Migrations should compute replacements and not write directly.
346
- throw new Error('DevkitFilesystem#ensureDir is not supported.');
347
- }
348
- writeFile(path, data) {
349
- // Migrations should compute replacements and not write directly.
350
- throw new Error('DevkitFilesystem#writeFile is not supported.');
351
- }
352
- removeFile(path) {
353
- // Migrations should compute replacements and not write directly.
354
- throw new Error('DevkitFilesystem#removeFile is not supported.');
355
- }
356
- copyFile(from, to) {
357
- // Migrations should compute replacements and not write directly.
358
- throw new Error('DevkitFilesystem#copyFile is not supported.');
359
- }
360
- moveFile(from, to) {
361
- // Migrations should compute replacements and not write directly.
362
- throw new Error('DevkitFilesystem#moveFile is not supported.');
363
- }
364
- removeDeep(path) {
365
- // Migrations should compute replacements and not write directly.
366
- throw new Error('DevkitFilesystem#removeDeep is not supported.');
367
- }
368
- chdir(_path) {
369
- throw new Error('FileSystem#chdir is not supported.');
370
- }
371
- symlink() {
372
- throw new Error('FileSystem#symlink is not supported.');
373
- }
374
- }
375
- /** Stats the given path in the virtual tree. */
376
- function statPath(tree, path) {
377
- let fileInfo = null;
378
- let dirInfo = null;
379
- try {
380
- fileInfo = tree.get(path);
381
- }
382
- catch (e) {
383
- if (e.constructor.name === 'PathIsDirectoryException') {
384
- dirInfo = tree.getDir(path);
385
- }
386
- else {
387
- throw e;
388
- }
389
- }
390
- if (fileInfo !== null || dirInfo !== null) {
391
- return {
392
- isDirectory: () => dirInfo !== null,
393
- isFile: () => fileInfo !== null,
394
- isSymbolicLink: () => false,
395
- };
396
- }
397
- return null;
398
- }
399
-
400
- /**
401
- * Groups the given replacements per project relative
402
- * file path.
403
- *
404
- * This allows for simple execution of the replacements
405
- * against a given file. E.g. via {@link applyTextUpdates}.
406
- */
407
- function groupReplacementsByFile(replacements) {
408
- const result = new Map();
409
- for (const { projectFile, update } of replacements) {
410
- if (!result.has(projectFile.rootRelativePath)) {
411
- result.set(projectFile.rootRelativePath, []);
412
- }
413
- result.get(projectFile.rootRelativePath).push(update);
414
- }
415
- return result;
416
- }
417
-
418
- /**
419
- * Synchronously combines unit data for the given migration.
420
- *
421
- * Note: This helper is useful for testing and execution of
422
- * Tsurge migrations in non-batchable environments. In general,
423
- * prefer parallel execution of combining via e.g. Beam combiners.
424
- */
425
- async function synchronouslyCombineUnitData(migration, unitDatas) {
426
- if (unitDatas.length === 0) {
427
- return null;
428
- }
429
- if (unitDatas.length === 1) {
430
- return unitDatas[0];
431
- }
432
- let combined = unitDatas[0];
433
- for (let i = 1; i < unitDatas.length; i++) {
434
- const other = unitDatas[i];
435
- combined = await migration.combine(combined, other);
436
- }
437
- return combined;
438
- }
439
-
440
263
  /**
441
264
  * By default, Tsurge will always create an Angular compiler program
442
265
  * for projects analyzed and migrated. This works perfectly fine in
@@ -464,7 +287,7 @@ const defaultMigrationTsOptions = {
464
287
  * Creates an instance of a TypeScript program for the given project.
465
288
  */
466
289
  function createPlainTsProgram(tsHost, tsconfig, optionOverrides) {
467
- const program = ts__default["default"].createProgram({
290
+ const program = ts.createProgram({
468
291
  rootNames: tsconfig.rootNames,
469
292
  options: {
470
293
  ...tsconfig.options,
@@ -486,14 +309,14 @@ function createPlainTsProgram(tsHost, tsconfig, optionOverrides) {
486
309
  * an instance of the Angular compiler for the project.
487
310
  */
488
311
  function createNgtscProgram(tsHost, tsconfig, optionOverrides) {
489
- const ngtscProgram = new program.NgtscProgram(tsconfig.rootNames, {
312
+ const ngtscProgram = new index.NgtscProgram(tsconfig.rootNames, {
490
313
  ...tsconfig.options,
491
314
  ...defaultMigrationTsOptions,
492
315
  ...optionOverrides,
493
316
  }, tsHost);
494
317
  // Expose an easy way to debug-print ng semantic diagnostics.
495
318
  if (process.env['DEBUG_NG_SEMANTIC_DIAGNOSTICS'] === '1') {
496
- console.error(ts__default["default"].formatDiagnosticsWithColorAndContext(ngtscProgram.getNgSemanticDiagnostics(), tsHost));
319
+ console.error(ts.formatDiagnosticsWithColorAndContext(ngtscProgram.getNgSemanticDiagnostics(), tsHost));
497
320
  }
498
321
  return {
499
322
  ngCompiler: ngtscProgram.compiler,
@@ -666,13 +489,257 @@ function isWithinBasePath(fs, base, path) {
666
489
  return checker.isLocalRelativePath(fs.relative(base, path));
667
490
  }
668
491
 
669
- exports.DevkitMigrationFilesystem = DevkitMigrationFilesystem;
492
+ /**
493
+ * Angular compiler file system implementation that leverages an
494
+ * CLI schematic virtual file tree.
495
+ */
496
+ class DevkitMigrationFilesystem {
497
+ tree;
498
+ constructor(tree) {
499
+ this.tree = tree;
500
+ }
501
+ extname(path) {
502
+ return core.extname(path);
503
+ }
504
+ isRoot(path) {
505
+ return path === core.normalize('/');
506
+ }
507
+ isRooted(path) {
508
+ return this.normalize(path).startsWith('/');
509
+ }
510
+ dirname(file) {
511
+ return this.normalize(core.dirname(file));
512
+ }
513
+ join(basePath, ...paths) {
514
+ return this.normalize(core.join(basePath, ...paths));
515
+ }
516
+ relative(from, to) {
517
+ return this.normalize(core.relative(from, to));
518
+ }
519
+ basename(filePath, extension) {
520
+ return posixPath__namespace.basename(filePath, extension);
521
+ }
522
+ normalize(path) {
523
+ return core.normalize(path);
524
+ }
525
+ resolve(...paths) {
526
+ const normalizedPaths = paths.map((p) => core.normalize(p));
527
+ // In dev-kit, the NodeJS working directory should never be
528
+ // considered, so `/` is the last resort over `cwd`.
529
+ return this.normalize(posixPath__namespace.resolve(core.normalize('/'), ...normalizedPaths));
530
+ }
531
+ pwd() {
532
+ return '/';
533
+ }
534
+ isCaseSensitive() {
535
+ return true;
536
+ }
537
+ exists(path) {
538
+ return statPath(this.tree, path) !== null;
539
+ }
540
+ readFile(path) {
541
+ return this.tree.readText(path);
542
+ }
543
+ readFileBuffer(path) {
544
+ const buffer = this.tree.read(path);
545
+ if (buffer === null) {
546
+ throw new Error(`File does not exist: ${path}`);
547
+ }
548
+ return buffer;
549
+ }
550
+ readdir(path) {
551
+ const dir = this.tree.getDir(path);
552
+ return [
553
+ ...dir.subdirs,
554
+ ...dir.subfiles,
555
+ ];
556
+ }
557
+ lstat(path) {
558
+ const stat = statPath(this.tree, path);
559
+ if (stat === null) {
560
+ throw new Error(`File does not exist for "lstat": ${path}`);
561
+ }
562
+ return stat;
563
+ }
564
+ stat(path) {
565
+ const stat = statPath(this.tree, path);
566
+ if (stat === null) {
567
+ throw new Error(`File does not exist for "stat": ${path}`);
568
+ }
569
+ return stat;
570
+ }
571
+ realpath(filePath) {
572
+ return filePath;
573
+ }
574
+ getDefaultLibLocation() {
575
+ return 'node_modules/typescript/lib';
576
+ }
577
+ ensureDir(path) {
578
+ // Migrations should compute replacements and not write directly.
579
+ throw new Error('DevkitFilesystem#ensureDir is not supported.');
580
+ }
581
+ writeFile(path, data) {
582
+ // Migrations should compute replacements and not write directly.
583
+ throw new Error('DevkitFilesystem#writeFile is not supported.');
584
+ }
585
+ removeFile(path) {
586
+ // Migrations should compute replacements and not write directly.
587
+ throw new Error('DevkitFilesystem#removeFile is not supported.');
588
+ }
589
+ copyFile(from, to) {
590
+ // Migrations should compute replacements and not write directly.
591
+ throw new Error('DevkitFilesystem#copyFile is not supported.');
592
+ }
593
+ moveFile(from, to) {
594
+ // Migrations should compute replacements and not write directly.
595
+ throw new Error('DevkitFilesystem#moveFile is not supported.');
596
+ }
597
+ removeDeep(path) {
598
+ // Migrations should compute replacements and not write directly.
599
+ throw new Error('DevkitFilesystem#removeDeep is not supported.');
600
+ }
601
+ chdir(_path) {
602
+ throw new Error('FileSystem#chdir is not supported.');
603
+ }
604
+ symlink() {
605
+ throw new Error('FileSystem#symlink is not supported.');
606
+ }
607
+ }
608
+ /** Stats the given path in the virtual tree. */
609
+ function statPath(tree, path) {
610
+ let fileInfo = null;
611
+ let dirInfo = null;
612
+ try {
613
+ fileInfo = tree.get(path);
614
+ }
615
+ catch (e) {
616
+ if (e.constructor.name === 'PathIsDirectoryException') {
617
+ dirInfo = tree.getDir(path);
618
+ }
619
+ else {
620
+ throw e;
621
+ }
622
+ }
623
+ if (fileInfo !== null || dirInfo !== null) {
624
+ return {
625
+ isDirectory: () => dirInfo !== null,
626
+ isFile: () => fileInfo !== null,
627
+ isSymbolicLink: () => false,
628
+ };
629
+ }
630
+ return null;
631
+ }
632
+
633
+ /**
634
+ * Groups the given replacements per project relative
635
+ * file path.
636
+ *
637
+ * This allows for simple execution of the replacements
638
+ * against a given file. E.g. via {@link applyTextUpdates}.
639
+ */
640
+ function groupReplacementsByFile(replacements) {
641
+ const result = new Map();
642
+ for (const { projectFile, update } of replacements) {
643
+ if (!result.has(projectFile.rootRelativePath)) {
644
+ result.set(projectFile.rootRelativePath, []);
645
+ }
646
+ result.get(projectFile.rootRelativePath).push(update);
647
+ }
648
+ return result;
649
+ }
650
+
651
+ /**
652
+ * Synchronously combines unit data for the given migration.
653
+ *
654
+ * Note: This helper is useful for testing and execution of
655
+ * Tsurge migrations in non-batchable environments. In general,
656
+ * prefer parallel execution of combining via e.g. Beam combiners.
657
+ */
658
+ async function synchronouslyCombineUnitData(migration, unitDatas) {
659
+ if (unitDatas.length === 0) {
660
+ return null;
661
+ }
662
+ if (unitDatas.length === 1) {
663
+ return unitDatas[0];
664
+ }
665
+ let combined = unitDatas[0];
666
+ for (let i = 1; i < unitDatas.length; i++) {
667
+ const other = unitDatas[i];
668
+ combined = await migration.combine(combined, other);
669
+ }
670
+ return combined;
671
+ }
672
+
673
+ /*!
674
+ * @license
675
+ * Copyright Google LLC All Rights Reserved.
676
+ *
677
+ * Use of this source code is governed by an MIT-style license that can be
678
+ * found in the LICENSE file at https://angular.dev/license
679
+ */
680
+ /** Runs a Tsurge within an Angular Devkit context. */
681
+ async function runMigrationInDevkit(config) {
682
+ const { buildPaths, testPaths } = await project_tsconfig_paths.getProjectTsConfigPaths(config.tree);
683
+ if (!buildPaths.length && !testPaths.length) {
684
+ throw new schematics.SchematicsException('Could not find any tsconfig file. Cannot run the migration.');
685
+ }
686
+ const fs = new DevkitMigrationFilesystem(config.tree);
687
+ checker.setFileSystem(fs);
688
+ const migration = config.getMigration(fs);
689
+ const unitResults = [];
690
+ const programInfos = [...buildPaths, ...testPaths].map((tsconfigPath) => {
691
+ config.beforeProgramCreation?.(tsconfigPath);
692
+ const baseInfo = migration.createProgram(tsconfigPath, fs);
693
+ const info = migration.prepareProgram(baseInfo);
694
+ config.afterProgramCreation?.(info, fs);
695
+ return { info, tsconfigPath };
696
+ });
697
+ for (const { info, tsconfigPath } of programInfos) {
698
+ config.beforeUnitAnalysis?.(tsconfigPath);
699
+ unitResults.push(await migration.analyze(info));
700
+ }
701
+ config.afterAllAnalyzed?.();
702
+ const combined = await synchronouslyCombineUnitData(migration, unitResults);
703
+ if (combined === null) {
704
+ config.afterAnalysisFailure?.();
705
+ return;
706
+ }
707
+ const globalMeta = await migration.globalMeta(combined);
708
+ let replacements;
709
+ if (migration instanceof TsurgeFunnelMigration) {
710
+ replacements = (await migration.migrate(globalMeta)).replacements;
711
+ }
712
+ else {
713
+ replacements = [];
714
+ for (const { info } of programInfos) {
715
+ const result = await migration.migrate(globalMeta, info);
716
+ replacements.push(...result.replacements);
717
+ }
718
+ }
719
+ const replacementsPerFile = new Map();
720
+ const changesPerFile = groupReplacementsByFile(replacements);
721
+ for (const [file, changes] of changesPerFile) {
722
+ if (!replacementsPerFile.has(file)) {
723
+ replacementsPerFile.set(file, changes);
724
+ }
725
+ }
726
+ for (const [file, changes] of replacementsPerFile) {
727
+ const recorder = config.tree.beginUpdate(file);
728
+ for (const c of changes) {
729
+ recorder
730
+ .remove(c.data.position, c.data.end - c.data.position)
731
+ .insertRight(c.data.position, c.data.toInsert);
732
+ }
733
+ config.tree.commitUpdate(recorder);
734
+ }
735
+ config.whenDone?.(await migration.stats(globalMeta));
736
+ }
737
+
670
738
  exports.Replacement = Replacement;
671
739
  exports.TextUpdate = TextUpdate;
672
740
  exports.TsurgeComplexMigration = TsurgeComplexMigration;
673
741
  exports.TsurgeFunnelMigration = TsurgeFunnelMigration;
674
742
  exports.confirmAsSerializable = confirmAsSerializable;
675
743
  exports.createBaseProgramInfo = createBaseProgramInfo;
676
- exports.groupReplacementsByFile = groupReplacementsByFile;
677
744
  exports.projectFile = projectFile;
678
- exports.synchronouslyCombineUnitData = synchronouslyCombineUnitData;
745
+ exports.runMigrationInDevkit = runMigrationInDevkit;