@angular/core 19.1.0-next.4 → 19.1.0-rc.0

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 (39) hide show
  1. package/LICENSE +1 -1
  2. package/fesm2022/core.mjs +190 -162
  3. package/fesm2022/core.mjs.map +1 -1
  4. package/fesm2022/primitives/event-dispatch.mjs +1 -24
  5. package/fesm2022/primitives/event-dispatch.mjs.map +1 -1
  6. package/fesm2022/primitives/signals.mjs +1 -1
  7. package/fesm2022/rxjs-interop.mjs +1 -1
  8. package/fesm2022/testing.mjs +5 -5
  9. package/index.d.ts +17 -11
  10. package/package.json +1 -1
  11. package/primitives/event-dispatch/index.d.ts +1 -1
  12. package/primitives/signals/index.d.ts +1 -1
  13. package/rxjs-interop/index.d.ts +1 -1
  14. package/schematics/bundles/apply_import_manager-6508401d.js +732 -0
  15. package/schematics/bundles/{checker-884633eb.js → checker-24b68d23.js} +33 -9
  16. package/schematics/bundles/cleanup-unused-imports.js +295 -0
  17. package/schematics/bundles/{compiler_host-22f6513d.js → compiler_host-5f693799.js} +2 -2
  18. package/schematics/bundles/control-flow-migration.js +3 -3
  19. package/schematics/bundles/explicit-standalone-flag.js +3 -3
  20. package/schematics/bundles/imports-abe29092.js +1 -1
  21. package/schematics/bundles/{combine_units-4a95b1b9.js → index-767e341d.js} +10 -723
  22. package/schematics/bundles/index-b1033cf0.js +30 -0
  23. package/schematics/bundles/inject-migration.js +3 -3
  24. package/schematics/bundles/leading_space-d190b83b.js +1 -1
  25. package/schematics/bundles/{migrate_ts_type_references-4b11f3f2.js → migrate_ts_type_references-bc7d8784.js} +29 -28
  26. package/schematics/bundles/nodes-a9f0b985.js +1 -1
  27. package/schematics/bundles/output-migration.js +26 -25
  28. package/schematics/bundles/pending-tasks.js +3 -3
  29. package/schematics/bundles/{program-094352ba.js → program-c810a4c2.js} +81 -40
  30. package/schematics/bundles/project_tsconfig_paths-e9ccccbf.js +1 -1
  31. package/schematics/bundles/provide-initializer.js +3 -3
  32. package/schematics/bundles/route-lazy-loading.js +3 -3
  33. package/schematics/bundles/signal-input-migration.js +31 -30
  34. package/schematics/bundles/signal-queries-migration.js +48 -47
  35. package/schematics/bundles/signals.js +6 -5
  36. package/schematics/bundles/standalone-migration.js +9 -25
  37. package/schematics/collection.json +5 -0
  38. package/schematics/ng-generate/cleanup-unused-imports/schema.json +7 -0
  39. package/testing/index.d.ts +1 -1
@@ -1,702 +1,22 @@
1
1
  'use strict';
2
2
  /**
3
- * @license Angular v19.1.0-next.4
3
+ * @license Angular v19.1.0-rc.0
4
4
  * (c) 2010-2024 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
- var os = require('os');
12
9
  var ts = require('typescript');
13
- var checker = require('./checker-884633eb.js');
14
- var program = require('./program-094352ba.js');
10
+ require('os');
11
+ var checker = require('./checker-24b68d23.js');
12
+ var program = require('./program-c810a4c2.js');
15
13
  require('path');
14
+ var apply_import_manager = require('./apply_import_manager-6508401d.js');
16
15
 
17
16
  function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
18
17
 
19
- function _interopNamespace(e) {
20
- if (e && e.__esModule) return e;
21
- var n = Object.create(null);
22
- if (e) {
23
- Object.keys(e).forEach(function (k) {
24
- if (k !== 'default') {
25
- var d = Object.getOwnPropertyDescriptor(e, k);
26
- Object.defineProperty(n, k, d.get ? d : {
27
- enumerable: true,
28
- get: function () { return e[k]; }
29
- });
30
- }
31
- });
32
- }
33
- n["default"] = e;
34
- return Object.freeze(n);
35
- }
36
-
37
- var posixPath__namespace = /*#__PURE__*/_interopNamespace(posixPath);
38
- var os__namespace = /*#__PURE__*/_interopNamespace(os);
39
18
  var ts__default = /*#__PURE__*/_interopDefaultLegacy(ts);
40
19
 
41
- /// <reference types="node" />
42
- class NgtscCompilerHost {
43
- fs;
44
- options;
45
- constructor(fs, options = {}) {
46
- this.fs = fs;
47
- this.options = options;
48
- }
49
- getSourceFile(fileName, languageVersion) {
50
- const text = this.readFile(fileName);
51
- return text !== undefined
52
- ? ts__default["default"].createSourceFile(fileName, text, languageVersion, true)
53
- : undefined;
54
- }
55
- getDefaultLibFileName(options) {
56
- return this.fs.join(this.getDefaultLibLocation(), ts__default["default"].getDefaultLibFileName(options));
57
- }
58
- getDefaultLibLocation() {
59
- return this.fs.getDefaultLibLocation();
60
- }
61
- writeFile(fileName, data, writeByteOrderMark, onError, sourceFiles) {
62
- const path = checker.absoluteFrom(fileName);
63
- this.fs.ensureDir(this.fs.dirname(path));
64
- this.fs.writeFile(path, data);
65
- }
66
- getCurrentDirectory() {
67
- return this.fs.pwd();
68
- }
69
- getCanonicalFileName(fileName) {
70
- return this.useCaseSensitiveFileNames() ? fileName : fileName.toLowerCase();
71
- }
72
- useCaseSensitiveFileNames() {
73
- return this.fs.isCaseSensitive();
74
- }
75
- getNewLine() {
76
- switch (this.options.newLine) {
77
- case ts__default["default"].NewLineKind.CarriageReturnLineFeed:
78
- return '\r\n';
79
- case ts__default["default"].NewLineKind.LineFeed:
80
- return '\n';
81
- default:
82
- return os__namespace.EOL;
83
- }
84
- }
85
- fileExists(fileName) {
86
- const absPath = this.fs.resolve(fileName);
87
- return this.fs.exists(absPath) && this.fs.stat(absPath).isFile();
88
- }
89
- readFile(fileName) {
90
- const absPath = this.fs.resolve(fileName);
91
- if (!this.fileExists(absPath)) {
92
- return undefined;
93
- }
94
- return this.fs.readFile(absPath);
95
- }
96
- realpath(path) {
97
- return this.fs.realpath(this.fs.resolve(path));
98
- }
99
- }
100
-
101
- // We use TypeScript's native `ts.matchFiles` utility for the virtual file systems
102
- /**
103
- * Creates a {@link ts.CompilerHost#readDirectory} implementation function,
104
- * that leverages the specified file system (that may be e.g. virtual).
105
- */
106
- function createFileSystemTsReadDirectoryFn(fs) {
107
- if (ts__default["default"].matchFiles === undefined) {
108
- throw Error('Unable to read directory in configured file system. This means that ' +
109
- 'TypeScript changed its file matching internals.\n\nPlease consider downgrading your ' +
110
- 'TypeScript version, and report an issue in the Angular framework repository.');
111
- }
112
- const matchFilesFn = ts__default["default"].matchFiles.bind(ts__default["default"]);
113
- return (rootDir, extensions, excludes, includes, depth) => {
114
- const directoryExists = (p) => {
115
- const resolvedPath = fs.resolve(p);
116
- return fs.exists(resolvedPath) && fs.stat(resolvedPath).isDirectory();
117
- };
118
- return matchFilesFn(rootDir, extensions, excludes, includes, fs.isCaseSensitive(), fs.pwd(), depth, (p) => {
119
- const resolvedPath = fs.resolve(p);
120
- // TS also gracefully returns an empty file set.
121
- if (!directoryExists(resolvedPath)) {
122
- return { directories: [], files: [] };
123
- }
124
- const children = fs.readdir(resolvedPath);
125
- const files = [];
126
- const directories = [];
127
- for (const child of children) {
128
- if (fs.stat(fs.join(resolvedPath, child))?.isDirectory()) {
129
- directories.push(child);
130
- }
131
- else {
132
- files.push(child);
133
- }
134
- }
135
- return { files, directories };
136
- }, (p) => fs.resolve(p), (p) => directoryExists(p));
137
- };
138
- }
139
-
140
- function calcProjectFileAndBasePath(project, host = checker.getFileSystem()) {
141
- const absProject = host.resolve(project);
142
- const projectIsDir = host.lstat(absProject).isDirectory();
143
- const projectFile = projectIsDir ? host.join(absProject, 'tsconfig.json') : absProject;
144
- const projectDir = projectIsDir ? absProject : host.dirname(absProject);
145
- const basePath = host.resolve(projectDir);
146
- return { projectFile, basePath };
147
- }
148
- function readConfiguration(project, existingOptions, host = checker.getFileSystem()) {
149
- try {
150
- const fs = checker.getFileSystem();
151
- const readConfigFile = (configFile) => ts__default["default"].readConfigFile(configFile, (file) => host.readFile(host.resolve(file)));
152
- const readAngularCompilerOptions = (configFile, parentOptions = {}) => {
153
- const { config, error } = readConfigFile(configFile);
154
- if (error) {
155
- // Errors are handled later on by 'parseJsonConfigFileContent'
156
- return parentOptions;
157
- }
158
- // Note: In Google, `angularCompilerOptions` are stored in `bazelOptions`.
159
- // This function typically doesn't run for actual Angular compilations, but
160
- // tooling like Tsurge, or schematics may leverage this helper, so we account
161
- // for this here.
162
- const angularCompilerOptions = config.angularCompilerOptions ?? config.bazelOptions?.angularCompilerOptions;
163
- // we are only interested into merging 'angularCompilerOptions' as
164
- // other options like 'compilerOptions' are merged by TS
165
- let existingNgCompilerOptions = { ...angularCompilerOptions, ...parentOptions };
166
- if (!config.extends) {
167
- return existingNgCompilerOptions;
168
- }
169
- const extendsPaths = typeof config.extends === 'string' ? [config.extends] : config.extends;
170
- // Call readAngularCompilerOptions recursively to merge NG Compiler options
171
- // Reverse the array so the overrides happen from right to left.
172
- return [...extendsPaths].reverse().reduce((prevOptions, extendsPath) => {
173
- const extendedConfigPath = getExtendedConfigPath(configFile, extendsPath, host, fs);
174
- return extendedConfigPath === null
175
- ? prevOptions
176
- : readAngularCompilerOptions(extendedConfigPath, prevOptions);
177
- }, existingNgCompilerOptions);
178
- };
179
- const { projectFile, basePath } = calcProjectFileAndBasePath(project, host);
180
- const configFileName = host.resolve(host.pwd(), projectFile);
181
- const { config, error } = readConfigFile(projectFile);
182
- if (error) {
183
- return {
184
- project,
185
- errors: [error],
186
- rootNames: [],
187
- options: {},
188
- emitFlags: program.EmitFlags.Default,
189
- };
190
- }
191
- const existingCompilerOptions = {
192
- genDir: basePath,
193
- basePath,
194
- ...readAngularCompilerOptions(configFileName),
195
- ...existingOptions,
196
- };
197
- 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;
200
- if (!(options['skipMetadataEmit'] || options['flatModuleOutFile'])) {
201
- emitFlags |= program.EmitFlags.Metadata;
202
- }
203
- if (options['skipTemplateCodegen']) {
204
- emitFlags = emitFlags & ~program.EmitFlags.Codegen;
205
- }
206
- return { project: projectFile, rootNames, projectReferences, options, errors, emitFlags };
207
- }
208
- catch (e) {
209
- const errors = [
210
- {
211
- category: ts__default["default"].DiagnosticCategory.Error,
212
- messageText: e.stack ?? e.message,
213
- file: undefined,
214
- start: undefined,
215
- length: undefined,
216
- source: 'angular',
217
- code: program.UNKNOWN_ERROR_CODE,
218
- },
219
- ];
220
- return { project: '', errors, rootNames: [], options: {}, emitFlags: program.EmitFlags.Default };
221
- }
222
- }
223
- function createParseConfigHost(host, fs = checker.getFileSystem()) {
224
- return {
225
- fileExists: host.exists.bind(host),
226
- readDirectory: createFileSystemTsReadDirectoryFn(fs),
227
- readFile: host.readFile.bind(host),
228
- useCaseSensitiveFileNames: fs.isCaseSensitive(),
229
- };
230
- }
231
- function getExtendedConfigPath(configFile, extendsValue, host, fs) {
232
- const result = getExtendedConfigPathWorker(configFile, extendsValue, host, fs);
233
- if (result !== null) {
234
- return result;
235
- }
236
- // Try to resolve the paths with a json extension append a json extension to the file in case if
237
- // it is missing and the resolution failed. This is to replicate TypeScript behaviour, see:
238
- // https://github.com/microsoft/TypeScript/blob/294a5a7d784a5a95a8048ee990400979a6bc3a1c/src/compiler/commandLineParser.ts#L2806
239
- return getExtendedConfigPathWorker(configFile, `${extendsValue}.json`, host, fs);
240
- }
241
- function getExtendedConfigPathWorker(configFile, extendsValue, host, fs) {
242
- if (extendsValue.startsWith('.') || fs.isRooted(extendsValue)) {
243
- const extendedConfigPath = host.resolve(host.dirname(configFile), extendsValue);
244
- if (host.exists(extendedConfigPath)) {
245
- return extendedConfigPath;
246
- }
247
- }
248
- else {
249
- const parseConfigHost = createParseConfigHost(host, fs);
250
- // 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);
252
- if (resolvedModule) {
253
- return checker.absoluteFrom(resolvedModule.resolvedFileName);
254
- }
255
- }
256
- return null;
257
- }
258
-
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
- * By default, Tsurge will always create an Angular compiler program
420
- * for projects analyzed and migrated. This works perfectly fine in
421
- * third-party where Tsurge migrations run in Angular CLI projects.
422
- *
423
- * In first party, when running against full Google3, creating an Angular
424
- * program for e.g. plain `ts_library` targets is overly expensive and
425
- * can result in out of memory issues for large TS targets. In 1P we can
426
- * reliably distinguish between TS and Angular targets via the `angularCompilerOptions`.
427
- */
428
- function google3UsePlainTsProgramIfNoKnownAngularOption() {
429
- return process.env['GOOGLE3_TSURGE'] === '1';
430
- }
431
-
432
- /** Options that are good defaults for Tsurge migrations. */
433
- const defaultMigrationTsOptions = {
434
- // Avoid checking libraries to speed up migrations.
435
- skipLibCheck: true,
436
- skipDefaultLibCheck: true,
437
- noEmit: true,
438
- // Does not apply to g3 and externally is enforced when the app is built by the compiler.
439
- disableTypeScriptVersionCheck: true,
440
- };
441
- /**
442
- * Creates an instance of a TypeScript program for the given project.
443
- */
444
- function createPlainTsProgram(tsHost, tsconfig, optionOverrides) {
445
- const program = ts__default["default"].createProgram({
446
- rootNames: tsconfig.rootNames,
447
- options: {
448
- ...tsconfig.options,
449
- ...defaultMigrationTsOptions,
450
- ...optionOverrides,
451
- },
452
- });
453
- return {
454
- ngCompiler: null,
455
- program,
456
- userOptions: tsconfig.options,
457
- programAbsoluteRootFileNames: tsconfig.rootNames,
458
- host: tsHost,
459
- };
460
- }
461
-
462
- /**
463
- * Parses the configuration of the given TypeScript project and creates
464
- * an instance of the Angular compiler for the project.
465
- */
466
- function createNgtscProgram(tsHost, tsconfig, optionOverrides) {
467
- const ngtscProgram = new program.NgtscProgram(tsconfig.rootNames, {
468
- ...tsconfig.options,
469
- ...defaultMigrationTsOptions,
470
- ...optionOverrides,
471
- }, tsHost);
472
- // Expose an easy way to debug-print ng semantic diagnostics.
473
- if (process.env['DEBUG_NG_SEMANTIC_DIAGNOSTICS'] === '1') {
474
- console.error(ts__default["default"].formatDiagnosticsWithColorAndContext(ngtscProgram.getNgSemanticDiagnostics(), tsHost));
475
- }
476
- return {
477
- ngCompiler: ngtscProgram.compiler,
478
- program: ngtscProgram.getTsProgram(),
479
- userOptions: tsconfig.options,
480
- programAbsoluteRootFileNames: tsconfig.rootNames,
481
- host: tsHost,
482
- };
483
- }
484
-
485
- /** Code of the error raised by TypeScript when a tsconfig doesn't match any files. */
486
- const NO_INPUTS_ERROR_CODE = 18003;
487
- /** Parses the given tsconfig file, supporting Angular compiler options. */
488
- function parseTsconfigOrDie(absoluteTsconfigPath, fs) {
489
- const tsconfig = readConfiguration(absoluteTsconfigPath, {}, fs);
490
- // Skip the "No inputs found..." error since we don't want to interrupt the migration if a
491
- // tsconfig doesn't match a file. This will result in an empty `Program` which is still valid.
492
- const errors = tsconfig.errors.filter((diag) => diag.code !== NO_INPUTS_ERROR_CODE);
493
- if (errors.length) {
494
- throw new Error(`Tsconfig could not be parsed or is invalid:\n\n` + `${errors.map((e) => e.messageText)}`);
495
- }
496
- return tsconfig;
497
- }
498
-
499
- /** Creates the base program info for the given tsconfig path. */
500
- function createBaseProgramInfo(absoluteTsconfigPath, fs, optionOverrides = {}) {
501
- if (fs === undefined) {
502
- fs = new checker.NodeJSFileSystem();
503
- checker.setFileSystem(fs);
504
- }
505
- const tsconfig = parseTsconfigOrDie(absoluteTsconfigPath, fs);
506
- const tsHost = new NgtscCompilerHost(fs, tsconfig.options);
507
- // When enabled, use a plain TS program if we are sure it's not
508
- // an Angular project based on the `tsconfig.json`.
509
- if (google3UsePlainTsProgramIfNoKnownAngularOption() &&
510
- tsconfig.options['_useHostForImportGeneration'] === undefined) {
511
- return createPlainTsProgram(tsHost, tsconfig, optionOverrides);
512
- }
513
- return createNgtscProgram(tsHost, tsconfig, optionOverrides);
514
- }
515
-
516
- /**
517
- * @private
518
- *
519
- * Base class for the possible Tsurge migration variants.
520
- *
521
- * For example, this class exposes methods to conveniently create
522
- * TypeScript programs, while also allowing migration authors to override.
523
- */
524
- class TsurgeBaseMigration {
525
- /**
526
- * Advanced Tsurge users can override this method, but most of the time,
527
- * overriding {@link prepareProgram} is more desirable.
528
- *
529
- * By default:
530
- * - In 3P: Ngtsc programs are being created.
531
- * - In 1P: Ngtsc or TS programs are created based on the Blaze target.
532
- */
533
- createProgram(tsconfigAbsPath, fs) {
534
- return createBaseProgramInfo(tsconfigAbsPath, fs);
535
- }
536
- // Optional function to prepare the base `ProgramInfo` even further,
537
- // for the analyze and migrate phases. E.g. determining source files.
538
- prepareProgram(info) {
539
- const fullProgramSourceFiles = [...info.program.getSourceFiles()];
540
- const sourceFiles = fullProgramSourceFiles.filter((f) => !f.isDeclarationFile &&
541
- // Note `isShim` will work for the initial program, but for TCB programs, the shims are no longer annotated.
542
- !checker.isShim(f) &&
543
- !f.fileName.endsWith('.ngtypecheck.ts'));
544
- // Sort it by length in reverse order (longest first). This speeds up lookups,
545
- // since there's no need to keep going through the array once a match is found.
546
- const sortedRootDirs = checker.getRootDirs(info.host, info.userOptions).sort((a, b) => b.length - a.length);
547
- // TODO: Consider also following TS's logic here, finding the common source root.
548
- // See: Program#getCommonSourceDirectory.
549
- const primaryRoot = checker.absoluteFrom(info.userOptions.rootDir ?? sortedRootDirs.at(-1) ?? info.program.getCurrentDirectory());
550
- return {
551
- ...info,
552
- sourceFiles,
553
- fullProgramSourceFiles,
554
- sortedRootDirs,
555
- projectRoot: primaryRoot,
556
- };
557
- }
558
- }
559
-
560
- /**
561
- * A simpler variant of a {@link TsurgeComplexMigration} that does not
562
- * fan-out into multiple workers per compilation unit to compute
563
- * the final migration replacements.
564
- *
565
- * This is faster and less resource intensive as workers and TS programs
566
- * are only ever created once.
567
- *
568
- * This is commonly the case when migrations are refactored to eagerly
569
- * compute replacements in the analyze stage, and then leverage the
570
- * global unit data to filter replacements that turned out to be "invalid".
571
- */
572
- class TsurgeFunnelMigration extends TsurgeBaseMigration {
573
- }
574
- /**
575
- * Complex variant of a `Tsurge` migration.
576
- *
577
- * For example, every analyze worker may contribute to a list of TS
578
- * references that are later combined. The migrate phase can then compute actual
579
- * file updates for all individual compilation units, leveraging the global metadata
580
- * to e.g. see if there are any references from other compilation units that may be
581
- * problematic and prevent migration of a given file.
582
- */
583
- class TsurgeComplexMigration extends TsurgeBaseMigration {
584
- }
585
-
586
- /** A text replacement for the given file. */
587
- class Replacement {
588
- projectFile;
589
- update;
590
- constructor(projectFile, update) {
591
- this.projectFile = projectFile;
592
- this.update = update;
593
- }
594
- }
595
- /** An isolated text update that may be applied to a file. */
596
- class TextUpdate {
597
- data;
598
- constructor(data) {
599
- this.data = data;
600
- }
601
- }
602
-
603
- /** Confirms that the given data `T` is serializable. */
604
- function confirmAsSerializable(data) {
605
- return data;
606
- }
607
-
608
- /**
609
- * Gets a project file instance for the given file.
610
- *
611
- * Use this helper for dealing with project paths throughout your
612
- * migration. The return type is serializable.
613
- *
614
- * See {@link ProjectFile}.
615
- */
616
- function projectFile(file, { sortedRootDirs, projectRoot }) {
617
- const fs = checker.getFileSystem();
618
- const filePath = fs.resolve(typeof file === 'string' ? file : file.fileName);
619
- // Sorted root directories are sorted longest to shortest. First match
620
- // is the appropriate root directory for ID computation.
621
- for (const rootDir of sortedRootDirs) {
622
- if (!isWithinBasePath(fs, rootDir, filePath)) {
623
- continue;
624
- }
625
- return {
626
- id: fs.relative(rootDir, filePath),
627
- rootRelativePath: fs.relative(projectRoot, filePath),
628
- };
629
- }
630
- // E.g. project directory may be `src/`, but files may be looked up
631
- // from `node_modules/`. This is fine, but in those cases, no root
632
- // directory matches.
633
- const rootRelativePath = fs.relative(projectRoot, filePath);
634
- return {
635
- id: rootRelativePath,
636
- rootRelativePath: rootRelativePath,
637
- };
638
- }
639
- /**
640
- * Whether `path` is a descendant of the `base`?
641
- * E.g. `a/b/c` is within `a/b` but not within `a/x`.
642
- */
643
- function isWithinBasePath(fs, base, path) {
644
- return checker.isLocalRelativePath(fs.relative(base, path));
645
- }
646
-
647
- /**
648
- * Applies import manager changes, and writes them as replacements the
649
- * given result array.
650
- */
651
- function applyImportManagerChanges(importManager, replacements, sourceFiles, info) {
652
- const { newImports, updatedImports, deletedImports } = importManager.finalize();
653
- const printer = ts__default["default"].createPrinter({});
654
- const pathToFile = new Map(sourceFiles.map((s) => [s.fileName, s]));
655
- // Capture new imports
656
- newImports.forEach((newImports, fileName) => {
657
- newImports.forEach((newImport) => {
658
- const printedImport = printer.printNode(ts__default["default"].EmitHint.Unspecified, newImport, pathToFile.get(fileName));
659
- replacements.push(new Replacement(projectFile(checker.absoluteFrom(fileName), info), new TextUpdate({ position: 0, end: 0, toInsert: `${printedImport}\n` })));
660
- });
661
- });
662
- // Capture updated imports
663
- for (const [oldBindings, newBindings] of updatedImports.entries()) {
664
- // The import will be generated as multi-line if it already is multi-line,
665
- // or if the number of elements significantly increased and it previously
666
- // consisted of very few specifiers.
667
- const isMultiline = oldBindings.getText().includes('\n') ||
668
- (newBindings.elements.length >= 6 && oldBindings.elements.length <= 3);
669
- const hasSpaceBetweenBraces = oldBindings.getText().startsWith('{ ');
670
- let formatFlags = ts__default["default"].ListFormat.NamedImportsOrExportsElements |
671
- ts__default["default"].ListFormat.Indented |
672
- ts__default["default"].ListFormat.Braces |
673
- ts__default["default"].ListFormat.PreserveLines |
674
- (isMultiline ? ts__default["default"].ListFormat.MultiLine : ts__default["default"].ListFormat.SingleLine);
675
- if (hasSpaceBetweenBraces) {
676
- formatFlags |= ts__default["default"].ListFormat.SpaceBetweenBraces;
677
- }
678
- else {
679
- formatFlags &= ~ts__default["default"].ListFormat.SpaceBetweenBraces;
680
- }
681
- const printedBindings = printer.printList(formatFlags, newBindings.elements, oldBindings.getSourceFile());
682
- replacements.push(new Replacement(projectFile(oldBindings.getSourceFile(), info), new TextUpdate({
683
- position: oldBindings.getStart(),
684
- end: oldBindings.getEnd(),
685
- // TS uses four spaces as indent. We migrate to two spaces as we
686
- // assume this to be more common.
687
- toInsert: printedBindings.replace(/^ {4}/gm, ' '),
688
- })));
689
- }
690
- // Update removed imports
691
- for (const removedImport of deletedImports) {
692
- replacements.push(new Replacement(projectFile(removedImport.getSourceFile(), info), new TextUpdate({
693
- position: removedImport.getStart(),
694
- end: removedImport.getEnd(),
695
- toInsert: '',
696
- })));
697
- }
698
- }
699
-
700
20
  function getMemberName(member) {
701
21
  if (member.name === undefined) {
702
22
  return null;
@@ -1295,7 +615,7 @@ function identifyHostBindingReferences(node, programInfo, checker$1, reflector,
1295
615
  readAstPath: ref.readAstPath,
1296
616
  isObjectShorthandExpression: ref.isObjectShorthandExpression,
1297
617
  isWrite: ref.isWrite,
1298
- file: projectFile(ref.context.getSourceFile(), programInfo),
618
+ file: apply_import_manager.projectFile(ref.context.getSourceFile(), programInfo),
1299
619
  hostPropertyNode: ref.context,
1300
620
  },
1301
621
  target: ref.targetField,
@@ -1395,8 +715,8 @@ function identifyTemplateReferences(programInfo, node, reflector, checker$1, eva
1395
715
  readAstPath: res.readAstPath,
1396
716
  node: res.context,
1397
717
  isObjectShorthandExpression: res.isObjectShorthandExpression,
1398
- originatingTsFile: projectFile(node.getSourceFile(), programInfo),
1399
- templateFile: projectFile(checker.absoluteFrom(templateFilePath), programInfo),
718
+ originatingTsFile: apply_import_manager.projectFile(node.getSourceFile(), programInfo),
719
+ templateFile: apply_import_manager.projectFile(checker.absoluteFrom(templateFilePath), programInfo),
1400
720
  isLikelyPartOfNarrowing: res.isLikelyNarrowed,
1401
721
  isWrite: res.isWrite,
1402
722
  },
@@ -1578,7 +898,7 @@ function identifyPotentialTypeScriptReference(node, programInfo, checker, knownF
1578
898
  kind: exports.ReferenceKind.TsReference,
1579
899
  from: {
1580
900
  node,
1581
- file: projectFile(node.getSourceFile(), programInfo),
901
+ file: apply_import_manager.projectFile(node.getSourceFile(), programInfo),
1582
902
  isWrite: isWriteReference,
1583
903
  isPartOfElementBinding: ts__default["default"].isBindingElement(node.parent),
1584
904
  },
@@ -1642,7 +962,7 @@ function createFindAllSourceFileReferencesVisitor(programInfo, checker, reflecto
1642
962
  result.references.push({
1643
963
  kind: exports.ReferenceKind.TsClassTypeReference,
1644
964
  from: {
1645
- file: projectFile(partialDirectiveInCatalyst.referenceNode.getSourceFile(), programInfo),
965
+ file: apply_import_manager.projectFile(partialDirectiveInCatalyst.referenceNode.getSourceFile(), programInfo),
1646
966
  node: partialDirectiveInCatalyst.referenceNode,
1647
967
  },
1648
968
  isPartialReference: true,
@@ -1660,46 +980,13 @@ function createFindAllSourceFileReferencesVisitor(programInfo, checker, reflecto
1660
980
  };
1661
981
  }
1662
982
 
1663
- /**
1664
- * Synchronously combines unit data for the given migration.
1665
- *
1666
- * Note: This helper is useful for testing and execution of
1667
- * Tsurge migrations in non-batchable environments. In general,
1668
- * prefer parallel execution of combining via e.g. Beam combiners.
1669
- */
1670
- async function synchronouslyCombineUnitData(migration, unitDatas) {
1671
- if (unitDatas.length === 0) {
1672
- return null;
1673
- }
1674
- if (unitDatas.length === 1) {
1675
- return unitDatas[0];
1676
- }
1677
- let combined = unitDatas[0];
1678
- for (let i = 1; i < unitDatas.length; i++) {
1679
- const other = unitDatas[i];
1680
- combined = await migration.combine(combined, other);
1681
- }
1682
- return combined;
1683
- }
1684
-
1685
- exports.DevkitMigrationFilesystem = DevkitMigrationFilesystem;
1686
- exports.Replacement = Replacement;
1687
- exports.TextUpdate = TextUpdate;
1688
- exports.TsurgeComplexMigration = TsurgeComplexMigration;
1689
- exports.TsurgeFunnelMigration = TsurgeFunnelMigration;
1690
- exports.applyImportManagerChanges = applyImportManagerChanges;
1691
- exports.confirmAsSerializable = confirmAsSerializable;
1692
- exports.createBaseProgramInfo = createBaseProgramInfo;
1693
983
  exports.createFindAllSourceFileReferencesVisitor = createFindAllSourceFileReferencesVisitor;
1694
984
  exports.getBindingElementDeclaration = getBindingElementDeclaration;
1695
985
  exports.getMemberName = getMemberName;
1696
- exports.groupReplacementsByFile = groupReplacementsByFile;
1697
986
  exports.isHostBindingReference = isHostBindingReference;
1698
987
  exports.isInputContainerNode = isInputContainerNode;
1699
988
  exports.isTemplateReference = isTemplateReference;
1700
989
  exports.isTsClassTypeReference = isTsClassTypeReference;
1701
990
  exports.isTsReference = isTsReference;
1702
- exports.projectFile = projectFile;
1703
- exports.synchronouslyCombineUnitData = synchronouslyCombineUnitData;
1704
991
  exports.traverseAccess = traverseAccess;
1705
992
  exports.unwrapParent = unwrapParent;