Skip to content

Commit 270fb83

Browse files
devversiondylhunn
authored andcommitted
refactor(migrations): leverage tsurge for signal input migration (#57451)
This commit simplifies the batching support for the signal input migration by using the new tsurge framework we've built. This allows for consistent setup across all possible entry-points and also simplifies the 1P setup given that we can simply use the Tsurge macros, instead of having to maintain our own Go-based runner. PR Close #57451
1 parent d3c01ef commit 270fb83

24 files changed

+424
-321
lines changed

packages/core/schematics/migrations/signal-migration/src/BUILD.bazel

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ ts_library(
3333
"//packages/compiler-cli/src/ngtsc/typecheck",
3434
"//packages/compiler-cli/src/ngtsc/typecheck/api",
3535
"//packages/core/schematics/utils",
36+
"//packages/core/schematics/utils/tsurge",
3637
"@npm//@types/node",
3738
"@npm//magic-string",
3839
"@npm//typescript",
@@ -45,3 +46,10 @@ nodejs_binary(
4546
entry_point = ":index.ts",
4647
visibility = ["//packages/core/schematics/migrations/signal-migration/test:__pkg__"],
4748
)
49+
50+
nodejs_binary(
51+
name = "batch_test_bin",
52+
data = [":src"],
53+
entry_point = ":batch/test_bin.ts",
54+
visibility = ["//packages/core/schematics/migrations/signal-migration/test:__pkg__"],
55+
)

packages/core/schematics/migrations/signal-migration/src/create_program.ts renamed to packages/core/schematics/migrations/signal-migration/src/analysis_deps.ts

Lines changed: 10 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -6,33 +6,28 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import path from 'path';
109
import ts from 'typescript';
1110

12-
import {NodeJSFileSystem, setFileSystem} from '../../../../../compiler-cli/src/ngtsc/file_system';
1311
import {DtsMetadataReader, MetadataReader} from '../../../../../compiler-cli/src/ngtsc/metadata';
1412
import {PartialEvaluator} from '../../../../../compiler-cli/src/ngtsc/partial_evaluator';
1513
import {NgtscProgram} from '../../../../../compiler-cli/src/ngtsc/program';
1614
import {TypeScriptReflectionHost} from '../../../../../compiler-cli/src/ngtsc/reflection';
1715

1816
import assert from 'assert';
17+
import {ProgramInfo} from '../../../utils/tsurge/program_info';
1918
import {ResourceLoader} from '../../../../../compiler-cli/src/ngtsc/annotations';
2019
import {NgCompiler} from '../../../../../compiler-cli/src/ngtsc/core';
2120
import {ReferenceEmitter} from '../../../../../compiler-cli/src/ngtsc/imports';
2221
import {isShim} from '../../../../../compiler-cli/src/ngtsc/shims';
2322
import {TemplateTypeChecker} from '../../../../../compiler-cli/src/ngtsc/typecheck/api';
24-
import {
25-
ParsedConfiguration,
26-
readConfiguration,
27-
} from '../../../../../compiler-cli/src/perform_compile';
2823

2924
/**
3025
* Interface containing the analysis information
3126
* for an Angular program to be migrated.
3227
*/
33-
export interface AnalysisProgramInfo {
28+
export interface AnalysisProgramInfo extends ProgramInfo<NgtscProgram> {
3429
// List of source files in the program.
35-
sourceFiles: readonly ts.SourceFile[];
30+
sourceFiles: ts.SourceFile[];
3631
// List of all files in the program, including external `d.ts`.
3732
programFiles: readonly ts.SourceFile[];
3833
reflector: TypeScriptReflectionHost;
@@ -45,56 +40,6 @@ export interface AnalysisProgramInfo {
4540
resourceLoader: ResourceLoader;
4641
}
4742

48-
/** Creates and prepares analysis for the given TypeScript project. */
49-
export function createAndPrepareAnalysisProgram(
50-
absoluteTsconfigPath: string,
51-
): AnalysisProgramInfo & {
52-
tsHost: ts.CompilerHost;
53-
basePath: string;
54-
tsconfig: ParsedConfiguration;
55-
} {
56-
setFileSystem(new NodeJSFileSystem());
57-
58-
const basePath = path.dirname(absoluteTsconfigPath);
59-
const tsconfig = readConfiguration(absoluteTsconfigPath, {}, new NodeJSFileSystem());
60-
61-
if (tsconfig.errors.length > 0) {
62-
throw new Error(
63-
`Tsconfig could not be parsed or is invalid:\n\n` +
64-
`${tsconfig.errors.map((e) => e.messageText)}`,
65-
);
66-
}
67-
68-
const tsHost = ts.createCompilerHost(tsconfig.options, true);
69-
const ngtscProgram = new NgtscProgram(
70-
tsconfig.rootNames,
71-
{
72-
...tsconfig.options,
73-
_enableTemplateTypeChecker: true,
74-
_compilePoisonedComponents: true,
75-
// We want to migrate non-exported classes too.
76-
compileNonExportedClasses: true,
77-
// Avoid checking libraries to speed up the migration.
78-
skipLibCheck: true,
79-
skipDefaultLibCheck: true,
80-
// Always generate as much TCB code as possible.
81-
// This allows us to check references in templates as much as possible.
82-
// Note that this may yield more diagnostics, but we are not collecting these anyway.
83-
strictTemplates: true,
84-
},
85-
tsHost,
86-
);
87-
88-
const userProgram = ngtscProgram.getTsProgram();
89-
90-
return {
91-
...prepareAnalysisInfo(userProgram, ngtscProgram.compiler, tsconfig),
92-
tsconfig,
93-
basePath,
94-
tsHost,
95-
};
96-
}
97-
9843
/**
9944
* Prepares migration analysis for the given program.
10045
*
@@ -104,7 +49,7 @@ export function createAndPrepareAnalysisProgram(
10449
export function prepareAnalysisInfo(
10550
userProgram: ts.Program,
10651
compiler: NgCompiler,
107-
tsconfig?: ParsedConfiguration,
52+
programAbsoluteRootPaths?: string[],
10853
) {
10954
// Get template type checker & analyze sync.
11055
const templateTypeChecker = compiler.getTemplateTypeChecker();
@@ -120,11 +65,14 @@ export function prepareAnalysisInfo(
12065
const dtsMetadataReader = new DtsMetadataReader(typeChecker, reflector);
12166
const resourceLoader = compiler['resourceManager'];
12267

68+
// Optional filter for testing. Allows for simulation of parallel execution
69+
// even if some tsconfig's have overlap due to sharing of TS sources.
70+
// (this is commonly not the case in g3 where deps are `.d.ts` files).
12371
const limitToRootNamesOnly = process.env['LIMIT_TO_ROOT_NAMES_ONLY'] === '1';
12472
if (limitToRootNamesOnly) {
12573
assert(
126-
tsconfig !== undefined,
127-
'Expected a tsconfig to be specified when limiting to root names.',
74+
programAbsoluteRootPaths !== undefined,
75+
'Expected absolute root paths when limiting to root names.',
12876
);
12977
}
13078

@@ -138,7 +86,7 @@ export function prepareAnalysisInfo(
13886
// Optional replacement filter. Allows parallel execution in case
13987
// some tsconfig's have overlap due to sharing of TS sources.
14088
// (this is commonly not the case in g3 where deps are `.d.ts` files).
141-
(!limitToRootNamesOnly || tsconfig!.rootNames.includes(f.fileName)),
89+
(!limitToRootNamesOnly || programAbsoluteRootPaths!.includes(f.fileName)),
14290
);
14391

14492
return {

packages/core/schematics/migrations/signal-migration/src/batch/BUILD.bazel

Lines changed: 0 additions & 22 deletions
This file was deleted.

packages/core/schematics/migrations/signal-migration/src/batch/bin.ts

Lines changed: 0 additions & 30 deletions
This file was deleted.

packages/core/schematics/migrations/signal-migration/src/batch/extract.ts

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,42 +6,30 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {createAndPrepareAnalysisProgram} from '../create_program';
109
import {KnownInputs} from '../input_detection/known_inputs';
11-
import {MigrationHost} from '../migration_host';
12-
import {pass4__checkInheritanceOfInputs} from '../passes/4_check_inheritance';
13-
import {executeAnalysisPhase} from '../phase_analysis';
1410
import {MigrationResult} from '../result';
1511
import {InputUniqueKey} from '../utils/input_id';
1612
import {
1713
isHostBindingInputReference,
1814
isTsInputClassTypeReference,
1915
isTsInputReference,
2016
} from '../utils/input_reference';
21-
import {IncompatibilityType, MetadataFile} from './metadata_file';
17+
import {CompilationUnitData, IncompatibilityType} from './metadata_file';
2218

2319
/**
2420
* Batch mode.
2521
*
2622
* Analyzes and extracts metadata for the given TypeScript target. The
2723
* resolved metadata is returned and can be merged later.
24+
*
25+
* TODO: Remove when 1P code uses go/tsurge.
2826
*/
29-
export function extract(absoluteTsconfigPath: string) {
30-
const analysisDeps = createAndPrepareAnalysisProgram(absoluteTsconfigPath);
31-
const {tsconfig, basePath, metaRegistry, sourceFiles} = analysisDeps;
32-
const knownInputs = new KnownInputs();
33-
const result = new MigrationResult();
34-
const host = new MigrationHost(
35-
/* projectDir */ tsconfig.options.rootDir ?? basePath,
36-
/* isMigratingCore */ true,
37-
tsconfig.options,
38-
sourceFiles,
39-
);
40-
41-
const {inheritanceGraph} = executeAnalysisPhase(host, knownInputs, result, analysisDeps);
42-
pass4__checkInheritanceOfInputs(host, inheritanceGraph, metaRegistry, knownInputs);
27+
export function extract(_absoluteTsconfigPath: string): CompilationUnitData {
28+
return {knownInputs: {}, references: []};
29+
}
4330

44-
const struct: MetadataFile = {
31+
export function getCompilationUnitMetadata(knownInputs: KnownInputs, result: MigrationResult) {
32+
const struct: CompilationUnitData = {
4533
knownInputs: Array.from(knownInputs.knownInputIds.entries()).reduce(
4634
(res, [inputIdStr, info]) => {
4735
const classIncompatibility =
@@ -64,7 +52,7 @@ export function extract(absoluteTsconfigPath: string) {
6452
},
6553
};
6654
},
67-
{} as MetadataFile['knownInputs'],
55+
{} as CompilationUnitData['knownInputs'],
6856
),
6957
references: result.references.map((r) => {
7058
if (isTsInputReference(r)) {

packages/core/schematics/migrations/signal-migration/src/batch/merge_metadata.ts

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -7,24 +7,24 @@
77
*/
88

99
import fs from 'fs';
10-
import {MetadataFile, SerializableForBatching} from './metadata_file';
10+
import {CompilationUnitData, SerializableForBatching} from './metadata_file';
1111
import {InputReference, InputReferenceKind} from '../utils/input_reference';
1212

13-
/** Merges a list of metadata files into a combined global file. */
14-
export async function mergeMetadataFilesViaPath(absoluteMetadataFiles: string[]) {
15-
mergeMetadataFiles(
16-
await Promise.all(
17-
absoluteMetadataFiles.map(
18-
async (filePath) =>
19-
JSON.parse(await fs.promises.readFile(filePath, 'utf8')) as MetadataFile,
20-
),
21-
),
22-
);
13+
/**
14+
* Merges a list of metadata files into a combined global file.
15+
*
16+
* TODO: Remove when 1P code uses go/tsurge.
17+
*/
18+
export async function mergeMetadataFiles(metadataFiles: CompilationUnitData[]) {
19+
const result = mergeCompilationUnitData(metadataFiles);
20+
process.stdout.write(JSON.stringify(result));
2321
}
2422

25-
/** Merges a list of metadata files into a combined global file. */
26-
export function mergeMetadataFiles(metadataFiles: MetadataFile[]) {
27-
const result: MetadataFile = {
23+
/** Merges a list of compilation units into a combined unit. */
24+
export function mergeCompilationUnitData(
25+
metadataFiles: CompilationUnitData[],
26+
): CompilationUnitData {
27+
const result: CompilationUnitData = {
2828
knownInputs: {},
2929
references: [],
3030
};
@@ -53,7 +53,7 @@ export function mergeMetadataFiles(metadataFiles: MetadataFile[]) {
5353
}
5454
}
5555

56-
process.stdout.write(JSON.stringify(result));
56+
return result;
5757
}
5858

5959
/** Computes a unique ID for the given reference. */

packages/core/schematics/migrations/signal-migration/src/batch/metadata_file.ts

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,13 +33,13 @@ export enum IncompatibilityType {
3333
}
3434

3535
/**
36-
* Type describing a serializable metadata file.
36+
* Type describing a serializable compilation unit data.
3737
*
3838
* The metadata files are built for every compilation unit in batching
3939
* mode, and can be merged later, and then used as global analysis metadata
4040
* when migrating.
4141
*/
42-
export interface MetadataFile {
42+
export interface CompilationUnitData {
4343
knownInputs: {
4444
// Use `string` here so that it's a usable index key.
4545
[inputIdKey: string]: {
@@ -52,3 +52,6 @@ export interface MetadataFile {
5252

5353
references: SerializableForBatching<InputReference>[];
5454
}
55+
56+
// TODO: Remove when 1P code uses go/tsurge.
57+
export type {CompilationUnitData as MetadataFile};

packages/core/schematics/migrations/signal-migration/src/batch/migrate_target.ts

Lines changed: 13 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,39 +6,30 @@
66
* found in the LICENSE file at https://angular.io/license
77
*/
88

9-
import {createAndPrepareAnalysisProgram} from '../create_program';
109
import {KnownInputs} from '../input_detection/known_inputs';
11-
import {MigrationHost} from '../migration_host';
12-
import {pass4__checkInheritanceOfInputs} from '../passes/4_check_inheritance';
13-
import {executeAnalysisPhase} from '../phase_analysis';
14-
import {executeMigrationPhase} from '../phase_migrate';
15-
import {MigrationResult} from '../result';
1610
import {InputUniqueKey} from '../utils/input_id';
17-
import {writeMigrationReplacements} from '../write_replacements';
18-
import {IncompatibilityType, MetadataFile} from './metadata_file';
11+
import {CompilationUnitData, IncompatibilityType, MetadataFile} from './metadata_file';
1912

2013
/**
2114
* Batch mode.
2215
*
2316
* Migrates the given compilation unit, leveraging the global analysis metadata
2417
* that was created as the merge of all individual project units.
18+
*
19+
* TODO: Remove when 1P code uses go/tsurge.
2520
*/
26-
export function migrateTarget(absoluteTsconfigPath: string, mergedMetadata: MetadataFile) {
27-
const analysisDeps = createAndPrepareAnalysisProgram(absoluteTsconfigPath);
28-
const {tsHost, tsconfig, basePath, sourceFiles, metaRegistry} = analysisDeps;
29-
const knownInputs = new KnownInputs();
30-
const result = new MigrationResult();
31-
const host = new MigrationHost(
32-
/* projectDir */ tsconfig.options.rootDir ?? basePath,
33-
/* isMigratingCore */ true,
34-
tsconfig.options,
35-
sourceFiles,
36-
);
37-
38-
const {inheritanceGraph} = executeAnalysisPhase(host, knownInputs, result, analysisDeps);
21+
export function migrateTarget(_absoluteTsconfigPath: string, _mergedMetadata: MetadataFile) {
22+
return {
23+
replacements: new Map<string, Array<{pos: number; end: number; toInsert: string}>>(),
24+
};
25+
}
3926

27+
export function populateKnownInputsFromGlobalData(
28+
knownInputs: KnownInputs,
29+
globalData: CompilationUnitData,
30+
) {
4031
// Populate from batch metadata.
41-
for (const [_key, info] of Object.entries(mergedMetadata.knownInputs)) {
32+
for (const [_key, info] of Object.entries(globalData.knownInputs)) {
4233
const key = _key as unknown as InputUniqueKey;
4334

4435
// irrelevant for this compilation unit.
@@ -61,12 +52,4 @@ export function migrateTarget(absoluteTsconfigPath: string, mergedMetadata: Meta
6152
}
6253
}
6354
}
64-
65-
pass4__checkInheritanceOfInputs(host, inheritanceGraph, metaRegistry, knownInputs);
66-
executeMigrationPhase(host, knownInputs, result, analysisDeps);
67-
68-
return {
69-
replacements: result.replacements,
70-
apply: () => writeMigrationReplacements(tsHost, result),
71-
};
7255
}

0 commit comments

Comments
 (0)