mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
refactor(migrations): allow tsurge migrations to run with just NgCompiler (#57562)
This is important so that migrations can easily be wired up in the language service where only `NgCompiler` is available. PR Close #57562
This commit is contained in:
parent
674aed5984
commit
389933f079
11 changed files with 52 additions and 100 deletions
|
|
@ -25,7 +25,7 @@ import {TemplateTypeChecker} from '../../../../../compiler-cli/src/ngtsc/typeche
|
|||
* Interface containing the analysis information
|
||||
* for an Angular program to be migrated.
|
||||
*/
|
||||
export interface AnalysisProgramInfo extends ProgramInfo<NgtscProgram> {
|
||||
export interface AnalysisProgramInfo extends ProgramInfo {
|
||||
// List of source files in the program.
|
||||
sourceFiles: ts.SourceFile[];
|
||||
// List of all files in the program, including external `d.ts`.
|
||||
|
|
|
|||
|
|
@ -6,7 +6,6 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import {NgtscProgram} from '../../../../../compiler-cli/src/ngtsc/program';
|
||||
import {FileSystem} from '../../../../../compiler-cli/src/ngtsc/file_system';
|
||||
import {confirmAsSerializable, Serializable} from '../../../utils/tsurge/helpers/serializable';
|
||||
import {BaseProgramInfo, ProgramInfo} from '../../../utils/tsurge/program_info';
|
||||
|
|
@ -26,6 +25,7 @@ import {InheritanceGraph} from './utils/inheritance_graph';
|
|||
import {executeMigrationPhase} from './phase_migrate';
|
||||
import {filterIncompatibilitiesForBestEffortMode} from './best_effort_mode';
|
||||
import {createNgtscProgram} from '../../../utils/tsurge/helpers/ngtsc_program';
|
||||
import assert from 'assert';
|
||||
|
||||
/**
|
||||
* Tsurge migration for migrating Angular `@Input()` declarations to
|
||||
|
|
@ -33,9 +33,7 @@ import {createNgtscProgram} from '../../../utils/tsurge/helpers/ngtsc_program';
|
|||
*/
|
||||
export class SignalInputMigration extends TsurgeComplexMigration<
|
||||
CompilationUnitData,
|
||||
CompilationUnitData,
|
||||
NgtscProgram,
|
||||
AnalysisProgramInfo
|
||||
CompilationUnitData
|
||||
> {
|
||||
upgradeAnalysisPhaseToAvoidBatch = false;
|
||||
upgradedAnalysisPhaseResults: Replacement[] | null = null;
|
||||
|
|
@ -43,7 +41,7 @@ export class SignalInputMigration extends TsurgeComplexMigration<
|
|||
bestEffortMode = false;
|
||||
|
||||
// Override the default ngtsc program creation, to add extra flags.
|
||||
override createProgram(tsconfigAbsPath: string, fs?: FileSystem): BaseProgramInfo<NgtscProgram> {
|
||||
override createProgram(tsconfigAbsPath: string, fs?: FileSystem): BaseProgramInfo {
|
||||
return createNgtscProgram(tsconfigAbsPath, fs, {
|
||||
_enableTemplateTypeChecker: true,
|
||||
_compilePoisonedComponents: true,
|
||||
|
|
@ -57,23 +55,20 @@ export class SignalInputMigration extends TsurgeComplexMigration<
|
|||
}
|
||||
|
||||
// Extend the program info with the analysis information we need in every phase.
|
||||
override prepareProgram(baseInfo: BaseProgramInfo<NgtscProgram>): AnalysisProgramInfo {
|
||||
const info = super.prepareProgram(baseInfo);
|
||||
prepareAnalysisDeps(info: ProgramInfo): AnalysisProgramInfo {
|
||||
assert(info.ngCompiler !== null, 'Expected `NgCompiler` to be configured.');
|
||||
return {
|
||||
...info,
|
||||
...prepareAnalysisInfo(
|
||||
info.program.getTsProgram(),
|
||||
info.program.compiler,
|
||||
info.programAbsoluteRootPaths,
|
||||
),
|
||||
...prepareAnalysisInfo(info.program, info.ngCompiler, info.programAbsoluteRootPaths),
|
||||
};
|
||||
}
|
||||
|
||||
override async analyze(analysisDeps: AnalysisProgramInfo) {
|
||||
override async analyze(info: ProgramInfo) {
|
||||
const analysisDeps = this.prepareAnalysisDeps(info);
|
||||
const {metaRegistry} = analysisDeps;
|
||||
const knownInputs = new KnownInputs();
|
||||
const result = new MigrationResult();
|
||||
const host = createMigrationHost(analysisDeps);
|
||||
const host = createMigrationHost(info);
|
||||
|
||||
const {inheritanceGraph} = executeAnalysisPhase(host, knownInputs, result, analysisDeps);
|
||||
pass4__checkInheritanceOfInputs(host, inheritanceGraph, metaRegistry, knownInputs);
|
||||
|
|
@ -86,11 +81,12 @@ export class SignalInputMigration extends TsurgeComplexMigration<
|
|||
// Non-batch mode!
|
||||
if (this.upgradeAnalysisPhaseToAvoidBatch) {
|
||||
const merged = await this.merge([unitData]);
|
||||
const replacements = await this.migrate(merged, analysisDeps, {
|
||||
const replacements = await this.migrate(merged, info, {
|
||||
knownInputs,
|
||||
result,
|
||||
host,
|
||||
inheritanceGraph,
|
||||
analysisDeps,
|
||||
});
|
||||
|
||||
// Expose the upgraded analysis stage results.
|
||||
|
|
@ -106,18 +102,19 @@ export class SignalInputMigration extends TsurgeComplexMigration<
|
|||
|
||||
override async migrate(
|
||||
globalMetadata: CompilationUnitData,
|
||||
analysisDeps: AnalysisProgramInfo,
|
||||
info: ProgramInfo,
|
||||
nonBatchData?: {
|
||||
knownInputs: KnownInputs;
|
||||
result: MigrationResult;
|
||||
host: MigrationHost;
|
||||
inheritanceGraph: InheritanceGraph;
|
||||
analysisDeps: AnalysisProgramInfo;
|
||||
},
|
||||
): Promise<Replacement[]> {
|
||||
const knownInputs = nonBatchData?.knownInputs ?? new KnownInputs();
|
||||
const result = nonBatchData?.result ?? new MigrationResult();
|
||||
const host = nonBatchData?.host ?? createMigrationHost(analysisDeps);
|
||||
const {metaRegistry} = analysisDeps;
|
||||
const host = nonBatchData?.host ?? createMigrationHost(info);
|
||||
const analysisDeps = nonBatchData?.analysisDeps ?? this.prepareAnalysisDeps(info);
|
||||
let inheritanceGraph: InheritanceGraph;
|
||||
|
||||
// Can't re-use analysis structures, so re-build them.
|
||||
|
|
@ -129,7 +126,7 @@ export class SignalInputMigration extends TsurgeComplexMigration<
|
|||
inheritanceGraph = nonBatchData.inheritanceGraph;
|
||||
}
|
||||
|
||||
pass4__checkInheritanceOfInputs(host, inheritanceGraph, metaRegistry, knownInputs);
|
||||
pass4__checkInheritanceOfInputs(host, inheritanceGraph, analysisDeps.metaRegistry, knownInputs);
|
||||
if (this.bestEffortMode) {
|
||||
filterIncompatibilitiesForBestEffortMode(knownInputs);
|
||||
}
|
||||
|
|
@ -140,7 +137,7 @@ export class SignalInputMigration extends TsurgeComplexMigration<
|
|||
}
|
||||
}
|
||||
|
||||
function createMigrationHost(info: ProgramInfo<NgtscProgram>): MigrationHost {
|
||||
function createMigrationHost(info: ProgramInfo): MigrationHost {
|
||||
return new MigrationHost(
|
||||
/* projectDir */ info.projectDirAbsPath,
|
||||
/* isMigratingCore */ false,
|
||||
|
|
|
|||
|
|
@ -6,11 +6,8 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import assert from 'assert';
|
||||
import path from 'path';
|
||||
import ts from 'typescript';
|
||||
import {FileSystem} from '../../../../compiler-cli/src/ngtsc/file_system';
|
||||
import {NgtscProgram} from '../../../../compiler-cli/src/ngtsc/program';
|
||||
import {isShim} from '../../../../compiler-cli/src/ngtsc/shims';
|
||||
import {createNgtscProgram} from './helpers/ngtsc_program';
|
||||
import {BaseProgramInfo, ProgramInfo} from './program_info';
|
||||
|
|
@ -21,22 +18,16 @@ import {BaseProgramInfo, ProgramInfo} from './program_info';
|
|||
* For example, this class exposes methods to conveniently create
|
||||
* TypeScript programs, while also allowing migration authors to override.
|
||||
*/
|
||||
export abstract class TsurgeBaseMigration<
|
||||
TsProgramType extends ts.Program | NgtscProgram = NgtscProgram,
|
||||
PreparationInfo = ProgramInfo<TsProgramType>,
|
||||
> {
|
||||
export abstract class TsurgeBaseMigration {
|
||||
// By default, ngtsc programs are being created.
|
||||
createProgram(tsconfigAbsPath: string, fs?: FileSystem): BaseProgramInfo<TsProgramType> {
|
||||
return createNgtscProgram(tsconfigAbsPath, fs) as BaseProgramInfo<TsProgramType>;
|
||||
createProgram(tsconfigAbsPath: string, fs?: FileSystem): BaseProgramInfo {
|
||||
return createNgtscProgram(tsconfigAbsPath, fs);
|
||||
}
|
||||
|
||||
// Optional function to prepare the base `ProgramInfo` even further,
|
||||
// for the analyze and migrate phases. E.g. determining source files.
|
||||
prepareProgram(info: BaseProgramInfo<TsProgramType>): PreparationInfo {
|
||||
assert(info.program instanceof NgtscProgram);
|
||||
|
||||
const userProgram = info.program.getTsProgram();
|
||||
const fullProgramSourceFiles = userProgram.getSourceFiles();
|
||||
prepareProgram(info: BaseProgramInfo): ProgramInfo {
|
||||
const fullProgramSourceFiles = [...info.program.getSourceFiles()];
|
||||
const sourceFiles = fullProgramSourceFiles.filter(
|
||||
(f) =>
|
||||
!f.isDeclarationFile &&
|
||||
|
|
@ -53,6 +44,6 @@ export abstract class TsurgeBaseMigration<
|
|||
sourceFiles,
|
||||
fullProgramSourceFiles,
|
||||
projectDirAbsPath,
|
||||
} as PreparationInfo;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
import {TsurgeMigration} from '../migration';
|
||||
import {Serializable} from '../helpers/serializable';
|
||||
import ts from 'typescript';
|
||||
import {NgtscProgram} from '../../../../../compiler-cli/src/ngtsc/program';
|
||||
|
||||
/**
|
||||
* Executes the analyze phase of the given migration against
|
||||
|
|
@ -17,12 +15,8 @@ import {NgtscProgram} from '../../../../../compiler-cli/src/ngtsc/program';
|
|||
*
|
||||
* @returns the serializable migration unit data.
|
||||
*/
|
||||
export async function executeAnalyzePhase<
|
||||
UnitData,
|
||||
GlobalData,
|
||||
TsProgramType extends ts.Program | NgtscProgram,
|
||||
>(
|
||||
migration: TsurgeMigration<UnitData, GlobalData, TsProgramType, unknown>,
|
||||
export async function executeAnalyzePhase<UnitData, GlobalData>(
|
||||
migration: TsurgeMigration<UnitData, GlobalData>,
|
||||
tsconfigAbsolutePath: string,
|
||||
): Promise<Serializable<UnitData>> {
|
||||
const baseInfo = migration.createProgram(tsconfigAbsolutePath);
|
||||
|
|
|
|||
|
|
@ -6,10 +6,8 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import ts from 'typescript';
|
||||
import {Serializable} from '../helpers/serializable';
|
||||
import {TsurgeMigration} from '../migration';
|
||||
import {NgtscProgram} from '../../../../../compiler-cli/src/ngtsc/program';
|
||||
|
||||
/**
|
||||
* Executes the merge phase for the given migration against
|
||||
|
|
@ -17,12 +15,8 @@ import {NgtscProgram} from '../../../../../compiler-cli/src/ngtsc/program';
|
|||
*
|
||||
* @returns the serializable migration global data.
|
||||
*/
|
||||
export async function executeMergePhase<
|
||||
UnitData,
|
||||
GlobalData,
|
||||
TsProgramType extends ts.Program | NgtscProgram,
|
||||
>(
|
||||
migration: TsurgeMigration<UnitData, GlobalData, TsProgramType, unknown>,
|
||||
export async function executeMergePhase<UnitData, GlobalData>(
|
||||
migration: TsurgeMigration<UnitData, GlobalData>,
|
||||
units: UnitData[],
|
||||
): Promise<Serializable<GlobalData>> {
|
||||
return await migration.merge(units);
|
||||
|
|
|
|||
|
|
@ -8,8 +8,6 @@
|
|||
|
||||
import {TsurgeMigration} from '../migration';
|
||||
import {Replacement} from '../replacement';
|
||||
import {NgtscProgram} from '../../../../../compiler-cli/src/ngtsc/program';
|
||||
import ts from 'typescript';
|
||||
|
||||
/**
|
||||
* Executes the migrate phase of the given migration against
|
||||
|
|
@ -20,12 +18,8 @@ import ts from 'typescript';
|
|||
*
|
||||
* @returns a list of text replacements to apply to disk.
|
||||
*/
|
||||
export async function executeMigratePhase<
|
||||
UnitData,
|
||||
GlobalData,
|
||||
TsProgramType extends ts.Program | NgtscProgram,
|
||||
>(
|
||||
migration: TsurgeMigration<UnitData, GlobalData, TsProgramType, unknown>,
|
||||
export async function executeMigratePhase<UnitData, GlobalData>(
|
||||
migration: TsurgeMigration<UnitData, GlobalData>,
|
||||
globalMetadata: GlobalData,
|
||||
tsconfigAbsolutePath: string,
|
||||
): Promise<Replacement[]> {
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@ export function createNgtscProgram(
|
|||
absoluteTsconfigPath: string,
|
||||
fs?: FileSystem,
|
||||
optionOverrides: NgCompilerOptions = {},
|
||||
): BaseProgramInfo<NgtscProgram> {
|
||||
): BaseProgramInfo {
|
||||
if (fs === undefined) {
|
||||
fs = new NodeJSFileSystem();
|
||||
setFileSystem(fs);
|
||||
|
|
@ -57,7 +57,8 @@ export function createNgtscProgram(
|
|||
);
|
||||
|
||||
return {
|
||||
program: ngtscProgram,
|
||||
ngCompiler: ngtscProgram.compiler,
|
||||
program: ngtscProgram.getTsProgram(),
|
||||
userOptions: tsconfig.options,
|
||||
programAbsoluteRootPaths: tsconfig.rootNames,
|
||||
tsconfigAbsolutePath: absoluteTsconfigPath,
|
||||
|
|
|
|||
|
|
@ -6,8 +6,6 @@
|
|||
* found in the LICENSE file at https://angular.io/license
|
||||
*/
|
||||
|
||||
import ts from 'typescript';
|
||||
import {NgtscProgram} from '../../../../compiler-cli/src/ngtsc/program';
|
||||
import {TsurgeBaseMigration} from './base_migration';
|
||||
import {Serializable} from './helpers/serializable';
|
||||
import {ProgramInfo} from './program_info';
|
||||
|
|
@ -37,24 +35,9 @@ import {Replacement} from './replacement';
|
|||
*
|
||||
* TODO: Link design doc
|
||||
*/
|
||||
export type TsurgeMigration<
|
||||
UnitAnalysisMetadata,
|
||||
CombinedGlobalMetadata,
|
||||
TsProgramType extends ts.Program | NgtscProgram = NgtscProgram,
|
||||
PreparationInfo = ProgramInfo<TsProgramType>,
|
||||
> =
|
||||
| TsurgeComplexMigration<
|
||||
UnitAnalysisMetadata,
|
||||
CombinedGlobalMetadata,
|
||||
TsProgramType,
|
||||
PreparationInfo
|
||||
>
|
||||
| TsurgeFunnelMigration<
|
||||
UnitAnalysisMetadata,
|
||||
CombinedGlobalMetadata,
|
||||
TsProgramType,
|
||||
PreparationInfo
|
||||
>;
|
||||
export type TsurgeMigration<UnitAnalysisMetadata, CombinedGlobalMetadata> =
|
||||
| TsurgeComplexMigration<UnitAnalysisMetadata, CombinedGlobalMetadata>
|
||||
| TsurgeFunnelMigration<UnitAnalysisMetadata, CombinedGlobalMetadata>;
|
||||
|
||||
/**
|
||||
* A simpler variant of a {@link TsurgeComplexMigration} that does not
|
||||
|
|
@ -71,9 +54,8 @@ export type TsurgeMigration<
|
|||
export abstract class TsurgeFunnelMigration<
|
||||
UnitAnalysisMetadata,
|
||||
CombinedGlobalMetadata,
|
||||
TsProgramType extends ts.Program | NgtscProgram = NgtscProgram,
|
||||
PreparationInfo = ProgramInfo<TsProgramType>,
|
||||
> extends TsurgeBaseMigration<TsProgramType, PreparationInfo> {
|
||||
PreparationInfo = ProgramInfo,
|
||||
> extends TsurgeBaseMigration {
|
||||
/** Analyzes the given TypeScript project and returns serializable compilation unit data. */
|
||||
abstract analyze(info: PreparationInfo): Promise<Serializable<UnitAnalysisMetadata>>;
|
||||
|
||||
|
|
@ -104,11 +86,9 @@ export abstract class TsurgeFunnelMigration<
|
|||
export abstract class TsurgeComplexMigration<
|
||||
UnitAnalysisMetadata,
|
||||
CombinedGlobalMetadata,
|
||||
TsProgramType extends ts.Program | NgtscProgram = NgtscProgram,
|
||||
PreparationInfo = ProgramInfo<TsProgramType>,
|
||||
> extends TsurgeBaseMigration<TsProgramType, PreparationInfo> {
|
||||
> extends TsurgeBaseMigration {
|
||||
/** Analyzes the given TypeScript project and returns serializable compilation unit data. */
|
||||
abstract analyze(info: PreparationInfo): Promise<Serializable<UnitAnalysisMetadata>>;
|
||||
abstract analyze(info: ProgramInfo): Promise<Serializable<UnitAnalysisMetadata>>;
|
||||
|
||||
/** Merges all compilation unit data from previous analysis phases into a global result. */
|
||||
abstract merge(units: UnitAnalysisMetadata[]): Promise<Serializable<CombinedGlobalMetadata>>;
|
||||
|
|
@ -122,6 +102,6 @@ export abstract class TsurgeComplexMigration<
|
|||
*/
|
||||
abstract migrate(
|
||||
globalMetadata: CombinedGlobalMetadata,
|
||||
info: PreparationInfo,
|
||||
info: ProgramInfo,
|
||||
): Promise<Replacement[]>;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,14 +10,16 @@ import {NgtscProgram} from '../../../../compiler-cli/src/ngtsc/program';
|
|||
import {NgCompilerOptions} from '../../../../compiler-cli/src/ngtsc/core/api';
|
||||
|
||||
import ts from 'typescript';
|
||||
import {NgCompiler} from '../../../../compiler-cli/src/ngtsc/core';
|
||||
|
||||
/**
|
||||
* Base information for a TypeScript project, including an instantiated
|
||||
* TypeScript program. Base information may be extended by user-overridden
|
||||
* migration preparation methods to extend the stages with more data.
|
||||
*/
|
||||
export interface BaseProgramInfo<T extends NgtscProgram | ts.Program> {
|
||||
program: T;
|
||||
export interface BaseProgramInfo {
|
||||
ngCompiler: NgCompiler | null;
|
||||
program: ts.Program;
|
||||
userOptions: NgCompilerOptions;
|
||||
programAbsoluteRootPaths: string[];
|
||||
tsconfigAbsolutePath: string;
|
||||
|
|
@ -30,8 +32,8 @@ export interface BaseProgramInfo<T extends NgtscProgram | ts.Program> {
|
|||
* A different interface may be used as full program information, configured via a
|
||||
* {@link TsurgeMigration.prepareProgram} override.
|
||||
*/
|
||||
export interface ProgramInfo<T extends NgtscProgram | ts.Program> extends BaseProgramInfo<T> {
|
||||
export interface ProgramInfo extends BaseProgramInfo {
|
||||
sourceFiles: ts.SourceFile[];
|
||||
fullProgramSourceFiles: ts.SourceFile[];
|
||||
fullProgramSourceFiles: readonly ts.SourceFile[];
|
||||
projectDirAbsPath: string;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ import path from 'path';
|
|||
import {UniqueID} from '../helpers/unique_id';
|
||||
import ts from 'typescript';
|
||||
import {ProgramInfo} from '../program_info';
|
||||
import {NgtscProgram} from '../../../../../compiler-cli/src/ngtsc/program';
|
||||
import {DtsMetadataReader} from '../../../../../compiler-cli/src/ngtsc/metadata';
|
||||
import {ClassDeclaration, ReflectionHost} from '../../../../../compiler-cli/src/ngtsc/reflection';
|
||||
import {Reference} from '../../../../../compiler-cli/src/ngtsc/imports';
|
||||
|
|
@ -24,7 +23,7 @@ export function getIdOfOutput(projectDirAbsPath: string, prop: ts.PropertyDeclar
|
|||
}
|
||||
|
||||
export function findOutputDeclarationsAndReferences(
|
||||
{sourceFiles, projectDirAbsPath}: ProgramInfo<NgtscProgram>,
|
||||
{sourceFiles, projectDirAbsPath}: ProgramInfo,
|
||||
checker: ts.TypeChecker,
|
||||
reflector: ReflectionHost,
|
||||
dtsReader: DtsMetadataReader,
|
||||
|
|
|
|||
|
|
@ -27,8 +27,8 @@ type GlobalMetadata = {[id: OutputID]: {canBeMigrated: boolean}};
|
|||
* framework works as expected. This is **not a full migration**, but rather an example.
|
||||
*/
|
||||
export class OutputMigration extends TsurgeComplexMigration<AnalysisUnit, GlobalMetadata> {
|
||||
override async analyze(info: ProgramInfo<NgtscProgram>) {
|
||||
const program = info.program.getTsProgram();
|
||||
override async analyze(info: ProgramInfo) {
|
||||
const program = info.program;
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const reflector = new TypeScriptReflectionHost(typeChecker, false);
|
||||
const dtsReader = new DtsMetadataReader(typeChecker, reflector);
|
||||
|
|
@ -74,8 +74,8 @@ export class OutputMigration extends TsurgeComplexMigration<AnalysisUnit, Global
|
|||
return confirmAsSerializable(merged);
|
||||
}
|
||||
|
||||
override async migrate(globalAnalysisData: GlobalMetadata, info: ProgramInfo<NgtscProgram>) {
|
||||
const program = info.program.getTsProgram();
|
||||
override async migrate(globalAnalysisData: GlobalMetadata, info: ProgramInfo) {
|
||||
const program = info.program;
|
||||
const typeChecker = program.getTypeChecker();
|
||||
const reflector = new TypeScriptReflectionHost(typeChecker, false);
|
||||
const dtsReader = new DtsMetadataReader(typeChecker, reflector);
|
||||
|
|
|
|||
Loading…
Reference in a new issue