Skip to content

Commit b07c549

Browse files
AndrewKushnirdylhunn
authored andcommitted
refactor(compiler): enable register and resolve phases for local compilation (#53901)
This commit update the logic to enable `register` and `resolve` phases for local compilation. Those phases will be useful for local compilation in certain cases (will be used in followup PRs). PR Close #53901
1 parent 6f6ad02 commit b07c549

File tree

8 files changed

+62
-32
lines changed

8 files changed

+62
-32
lines changed

packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,10 @@ export class ComponentDecoratorHandler implements
542542
}
543543

544544
register(node: ClassDeclaration, analysis: ComponentAnalysisData): void {
545+
if (this.compilationMode === CompilationMode.LOCAL) {
546+
return;
547+
}
548+
545549
// Register this component's information with the `MetadataRegistry`. This ensures that
546550
// the information about the component is available during the compile() phase.
547551
const ref = new Reference(node);
@@ -652,6 +656,10 @@ export class ComponentDecoratorHandler implements
652656
resolve(
653657
node: ClassDeclaration, analysis: Readonly<ComponentAnalysisData>,
654658
symbol: ComponentSymbol): ResolveResult<ComponentResolutionData> {
659+
if (this.compilationMode === CompilationMode.LOCAL) {
660+
return {};
661+
}
662+
655663
if (this.semanticDepGraphUpdater !== null && analysis.baseClass instanceof Reference) {
656664
symbol.baseClass = this.semanticDepGraphUpdater.getSymbol(analysis.baseClass.node);
657665
}
@@ -1100,7 +1108,7 @@ export class ComponentDecoratorHandler implements
11001108

11011109
compileLocal(
11021110
node: ClassDeclaration, analysis: Readonly<ComponentAnalysisData>,
1103-
pool: ConstantPool): CompileResult[] {
1111+
resolution: Readonly<Partial<ComponentResolutionData>>, pool: ConstantPool): CompileResult[] {
11041112
if (analysis.template.errors !== null && analysis.template.errors.length > 0) {
11051113
return [];
11061114
}

packages/compiler-cli/src/ngtsc/annotations/directive/src/handler.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,10 @@ export class DirectiveDecoratorHandler implements
145145
}
146146

147147
register(node: ClassDeclaration, analysis: Readonly<DirectiveHandlerData>): void {
148+
if (this.compilationMode === CompilationMode.LOCAL) {
149+
return;
150+
}
151+
148152
// Register this directive's information with the `MetadataRegistry`. This ensures that
149153
// the information about the directive is available during the compile() phase.
150154
const ref = new Reference(node);
@@ -186,6 +190,10 @@ export class DirectiveDecoratorHandler implements
186190

187191
resolve(node: ClassDeclaration, analysis: DirectiveHandlerData, symbol: DirectiveSymbol):
188192
ResolveResult<unknown> {
193+
if (this.compilationMode === CompilationMode.LOCAL) {
194+
return {};
195+
}
196+
189197
if (this.semanticDepGraphUpdater !== null && analysis.baseClass instanceof Reference) {
190198
symbol.baseClass = this.semanticDepGraphUpdater.getSymbol(analysis.baseClass.node);
191199
}
@@ -246,7 +254,7 @@ export class DirectiveDecoratorHandler implements
246254

247255
compileLocal(
248256
node: ClassDeclaration, analysis: Readonly<DirectiveHandlerData>,
249-
pool: ConstantPool): CompileResult[] {
257+
resolution: Readonly<unknown>, pool: ConstantPool): CompileResult[] {
250258
const fac = compileNgFactoryDefField(toFactoryMetadata(analysis.meta, FactoryTarget.Directive));
251259
const def = compileDirectiveFromMetadata(analysis.meta, pool, makeBindingParser());
252260
const inputTransformFields = compileInputTransformFields(analysis.inputs);

packages/compiler-cli/src/ngtsc/annotations/ng_module/src/handler.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -531,6 +531,10 @@ export class NgModuleDecoratorHandler implements
531531
}
532532

533533
register(node: ClassDeclaration, analysis: NgModuleAnalysis): void {
534+
if (this.compilationMode === CompilationMode.LOCAL) {
535+
return;
536+
}
537+
534538
// Register this module's information with the LocalModuleScopeRegistry. This ensures that
535539
// during the compile() phase, the module's metadata is available for selector scope
536540
// computation.
@@ -555,6 +559,10 @@ export class NgModuleDecoratorHandler implements
555559

556560
resolve(node: ClassDeclaration, analysis: Readonly<NgModuleAnalysis>):
557561
ResolveResult<NgModuleResolution> {
562+
if (this.compilationMode === CompilationMode.LOCAL) {
563+
return {};
564+
}
565+
558566
const scope = this.scopeRegistry.getScopeOfModule(node);
559567
const diagnostics: ts.Diagnostic[] = [];
560568

packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,13 +89,21 @@ export class InjectableDecoratorHandler implements
8989
}
9090

9191
register(node: ClassDeclaration, analysis: InjectableHandlerData): void {
92+
if (this.compilationMode === CompilationMode.LOCAL) {
93+
return;
94+
}
95+
9296
this.injectableRegistry.registerInjectable(node, {
9397
ctorDeps: analysis.ctorDeps,
9498
});
9599
}
96100

97-
resolve(node: ClassDeclaration, analysis: Readonly<InjectableHandlerData>, symbol: null):
101+
resolve(node: ClassDeclaration, analysis: Readonly<InjectableHandlerData>):
98102
ResolveResult<unknown> {
103+
if (this.compilationMode === CompilationMode.LOCAL) {
104+
return {};
105+
}
106+
99107
if (requiresValidCtor(analysis.meta)) {
100108
const diagnostic = checkInheritanceOfInjectable(
101109
node, this.injectableRegistry, this.reflector, this.evaluator, this.strictCtorDeps,

packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,10 @@ export class PipeDecoratorHandler implements
153153
}
154154

155155
register(node: ClassDeclaration, analysis: Readonly<PipeHandlerData>): void {
156+
if (this.compilationMode === CompilationMode.LOCAL) {
157+
return;
158+
}
159+
156160
const ref = new Reference(node);
157161
this.metaRegistry.registerPipeMetadata({
158162
kind: MetaKind.Pipe,
@@ -170,6 +174,10 @@ export class PipeDecoratorHandler implements
170174
}
171175

172176
resolve(node: ClassDeclaration): ResolveResult<unknown> {
177+
if (this.compilationMode === CompilationMode.LOCAL) {
178+
return {};
179+
}
180+
173181
const duplicateDeclData = this.scopeRegistry.getDuplicateDeclarations(node);
174182
if (duplicateDeclData !== null) {
175183
// This pipe was declared twice (or more).

packages/compiler-cli/src/ngtsc/transform/src/api.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,8 +202,9 @@ export interface DecoratorHandler<D, A, S extends SemanticSymbol|null, R> {
202202
* Generates code based on each individual source file without using its
203203
* dependencies (suitable for local dev edit/refresh workflow)
204204
*/
205-
compileLocal(node: ClassDeclaration, analysis: Readonly<A>, constantPool: ConstantPool):
206-
CompileResult|CompileResult[];
205+
compileLocal(
206+
node: ClassDeclaration, analysis: Readonly<A>, resolution: Readonly<Partial<R>>,
207+
constantPool: ConstantPool): CompileResult|CompileResult[];
207208
}
208209

209210
/**

packages/compiler-cli/src/ngtsc/transform/src/compilation.ts

Lines changed: 11 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -411,20 +411,13 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
411411
}
412412

413413
const symbol = this.makeSymbolForTrait(trait.handler, clazz, result.analysis ?? null);
414-
if (this.compilationMode !== CompilationMode.LOCAL && result.analysis !== undefined &&
415-
trait.handler.register !== undefined) {
414+
if (result.analysis !== undefined && trait.handler.register !== undefined) {
416415
trait.handler.register(clazz, result.analysis);
417416
}
418417
trait = trait.toAnalyzed(result.analysis ?? null, result.diagnostics ?? null, symbol);
419418
}
420419

421420
resolve(): void {
422-
// No resolving needed for local compilation (only analysis and compile will be done in this
423-
// mode)
424-
if (this.compilationMode === CompilationMode.LOCAL) {
425-
return;
426-
}
427-
428421
const classes = this.classes.keys();
429422
for (const clazz of classes) {
430423
const record = this.classes.get(clazz)!;
@@ -484,7 +477,7 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
484477
* `ts.SourceFile`.
485478
*/
486479
typeCheck(sf: ts.SourceFile, ctx: TypeCheckContext): void {
487-
if (!this.fileToClasses.has(sf)) {
480+
if (!this.fileToClasses.has(sf) || this.compilationMode === CompilationMode.LOCAL) {
488481
return;
489482
}
490483

@@ -596,24 +589,20 @@ export class TraitCompiler implements ProgramTypeCheckAdapter {
596589

597590
for (const trait of record.traits) {
598591
let compileRes: CompileResult|CompileResult[];
592+
593+
if (trait.state !== TraitState.Resolved || containsErrors(trait.analysisDiagnostics) ||
594+
containsErrors(trait.resolveDiagnostics)) {
595+
// Cannot compile a trait that is not resolved, or had any errors in its declaration.
596+
continue;
597+
}
598+
599599
if (this.compilationMode === CompilationMode.LOCAL) {
600-
if (trait.state !== TraitState.Analyzed || trait.analysis === null ||
601-
containsErrors(trait.analysisDiagnostics)) {
602-
// Cannot compile a trait in local mode that is not analyzed, or had any errors in its
603-
// declaration.
604-
continue;
605-
}
606600
// `trait.analysis` is non-null asserted here because TypeScript does not recognize that
607601
// `Readonly<unknown>` is nullable (as `unknown` itself is nullable) due to the way that
608602
// `Readonly` works.
609-
compileRes = trait.handler.compileLocal(clazz, trait.analysis!, constantPool);
603+
compileRes =
604+
trait.handler.compileLocal(clazz, trait.analysis!, trait.resolution!, constantPool);
610605
} else {
611-
if (trait.state !== TraitState.Resolved || containsErrors(trait.analysisDiagnostics) ||
612-
containsErrors(trait.resolveDiagnostics)) {
613-
// Cannot compile a trait in global mode that is not resolved, or had any errors in its
614-
// declaration.
615-
continue;
616-
}
617606
// `trait.resolution` is non-null asserted below because TypeScript does not recognize that
618607
// `Readonly<unknown>` is nullable (as `unknown` itself is nullable) due to the way that
619608
// `Readonly` works.

packages/compiler-cli/src/ngtsc/transform/test/compilation_spec.ts

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -340,21 +340,21 @@ runInEachFileSystem(() => {
340340
}
341341
}
342342

343-
it('should not run resolve phase', () => {
343+
it('should invoke `resolve` phase', () => {
344344
const contents = `
345345
export class Test {}
346346
`;
347347
const handler = new TestDecoratorHandler();
348-
spyOn(handler, 'resolve');
348+
spyOn(handler, 'resolve').and.callThrough();
349349
const {compiler, sourceFile} = setup(contents, [handler], CompilationMode.LOCAL);
350350

351351
compiler.analyzeSync(sourceFile);
352352
compiler.resolve();
353353

354-
expect(handler.resolve).not.toHaveBeenCalled();
354+
expect(handler.resolve).toHaveBeenCalled();
355355
});
356356

357-
it('should not register', () => {
357+
it('should invoke `register` phase', () => {
358358
const contents = `
359359
export class Test {}
360360
`;
@@ -365,7 +365,7 @@ runInEachFileSystem(() => {
365365
compiler.analyzeSync(sourceFile);
366366
compiler.resolve();
367367

368-
expect(handler.register).not.toHaveBeenCalled();
368+
expect(handler.register).toHaveBeenCalled();
369369
});
370370

371371
it('should not call extendedTemplateCheck', () => {

0 commit comments

Comments
 (0)