diff --git a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts index 343f04c578dac..865c347e85bb3 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/component/src/handler.ts @@ -542,6 +542,10 @@ export class ComponentDecoratorHandler implements } register(node: ClassDeclaration, analysis: ComponentAnalysisData): void { + if (this.compilationMode === CompilationMode.LOCAL) { + return; + } + // Register this component's information with the `MetadataRegistry`. This ensures that // the information about the component is available during the compile() phase. const ref = new Reference(node); @@ -652,6 +656,10 @@ export class ComponentDecoratorHandler implements resolve( node: ClassDeclaration, analysis: Readonly, symbol: ComponentSymbol): ResolveResult { + if (this.compilationMode === CompilationMode.LOCAL) { + return {}; + } + if (this.semanticDepGraphUpdater !== null && analysis.baseClass instanceof Reference) { symbol.baseClass = this.semanticDepGraphUpdater.getSymbol(analysis.baseClass.node); } @@ -1100,7 +1108,7 @@ export class ComponentDecoratorHandler implements compileLocal( node: ClassDeclaration, analysis: Readonly, - pool: ConstantPool): CompileResult[] { + resolution: Readonly>, pool: ConstantPool): CompileResult[] { if (analysis.template.errors !== null && analysis.template.errors.length > 0) { return []; } diff --git a/packages/compiler-cli/src/ngtsc/annotations/directive/src/handler.ts b/packages/compiler-cli/src/ngtsc/annotations/directive/src/handler.ts index c69d809547eae..694209d140116 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/directive/src/handler.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/directive/src/handler.ts @@ -145,6 +145,10 @@ export class DirectiveDecoratorHandler implements } register(node: ClassDeclaration, analysis: Readonly): void { + if (this.compilationMode === CompilationMode.LOCAL) { + return; + } + // Register this directive's information with the `MetadataRegistry`. This ensures that // the information about the directive is available during the compile() phase. const ref = new Reference(node); @@ -186,6 +190,10 @@ export class DirectiveDecoratorHandler implements resolve(node: ClassDeclaration, analysis: DirectiveHandlerData, symbol: DirectiveSymbol): ResolveResult { + if (this.compilationMode === CompilationMode.LOCAL) { + return {}; + } + if (this.semanticDepGraphUpdater !== null && analysis.baseClass instanceof Reference) { symbol.baseClass = this.semanticDepGraphUpdater.getSymbol(analysis.baseClass.node); } @@ -246,7 +254,7 @@ export class DirectiveDecoratorHandler implements compileLocal( node: ClassDeclaration, analysis: Readonly, - pool: ConstantPool): CompileResult[] { + resolution: Readonly, pool: ConstantPool): CompileResult[] { const fac = compileNgFactoryDefField(toFactoryMetadata(analysis.meta, FactoryTarget.Directive)); const def = compileDirectiveFromMetadata(analysis.meta, pool, makeBindingParser()); const inputTransformFields = compileInputTransformFields(analysis.inputs); diff --git a/packages/compiler-cli/src/ngtsc/annotations/ng_module/src/handler.ts b/packages/compiler-cli/src/ngtsc/annotations/ng_module/src/handler.ts index 6b846cbb6b793..1010b215f9d37 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/ng_module/src/handler.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/ng_module/src/handler.ts @@ -531,6 +531,10 @@ export class NgModuleDecoratorHandler implements } register(node: ClassDeclaration, analysis: NgModuleAnalysis): void { + if (this.compilationMode === CompilationMode.LOCAL) { + return; + } + // Register this module's information with the LocalModuleScopeRegistry. This ensures that // during the compile() phase, the module's metadata is available for selector scope // computation. @@ -555,6 +559,10 @@ export class NgModuleDecoratorHandler implements resolve(node: ClassDeclaration, analysis: Readonly): ResolveResult { + if (this.compilationMode === CompilationMode.LOCAL) { + return {}; + } + const scope = this.scopeRegistry.getScopeOfModule(node); const diagnostics: ts.Diagnostic[] = []; diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts index be7b3793bcc7a..174416fc8c8d6 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/injectable.ts @@ -89,13 +89,21 @@ export class InjectableDecoratorHandler implements } register(node: ClassDeclaration, analysis: InjectableHandlerData): void { + if (this.compilationMode === CompilationMode.LOCAL) { + return; + } + this.injectableRegistry.registerInjectable(node, { ctorDeps: analysis.ctorDeps, }); } - resolve(node: ClassDeclaration, analysis: Readonly, symbol: null): + resolve(node: ClassDeclaration, analysis: Readonly): ResolveResult { + if (this.compilationMode === CompilationMode.LOCAL) { + return {}; + } + if (requiresValidCtor(analysis.meta)) { const diagnostic = checkInheritanceOfInjectable( node, this.injectableRegistry, this.reflector, this.evaluator, this.strictCtorDeps, diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts index b0307fe8a9b98..155e23e9d2031 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/pipe.ts @@ -153,6 +153,10 @@ export class PipeDecoratorHandler implements } register(node: ClassDeclaration, analysis: Readonly): void { + if (this.compilationMode === CompilationMode.LOCAL) { + return; + } + const ref = new Reference(node); this.metaRegistry.registerPipeMetadata({ kind: MetaKind.Pipe, @@ -170,6 +174,10 @@ export class PipeDecoratorHandler implements } resolve(node: ClassDeclaration): ResolveResult { + if (this.compilationMode === CompilationMode.LOCAL) { + return {}; + } + const duplicateDeclData = this.scopeRegistry.getDuplicateDeclarations(node); if (duplicateDeclData !== null) { // This pipe was declared twice (or more). diff --git a/packages/compiler-cli/src/ngtsc/transform/src/api.ts b/packages/compiler-cli/src/ngtsc/transform/src/api.ts index 8bec70c4272ba..ea254e72271de 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/api.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/api.ts @@ -202,8 +202,9 @@ export interface DecoratorHandler { * Generates code based on each individual source file without using its * dependencies (suitable for local dev edit/refresh workflow) */ - compileLocal(node: ClassDeclaration, analysis: Readonly, constantPool: ConstantPool): - CompileResult|CompileResult[]; + compileLocal( + node: ClassDeclaration, analysis: Readonly, resolution: Readonly>, + constantPool: ConstantPool): CompileResult|CompileResult[]; } /** diff --git a/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts b/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts index 270dc7919b21a..e650ee5d545e2 100644 --- a/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts +++ b/packages/compiler-cli/src/ngtsc/transform/src/compilation.ts @@ -411,20 +411,13 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { } const symbol = this.makeSymbolForTrait(trait.handler, clazz, result.analysis ?? null); - if (this.compilationMode !== CompilationMode.LOCAL && result.analysis !== undefined && - trait.handler.register !== undefined) { + if (result.analysis !== undefined && trait.handler.register !== undefined) { trait.handler.register(clazz, result.analysis); } trait = trait.toAnalyzed(result.analysis ?? null, result.diagnostics ?? null, symbol); } resolve(): void { - // No resolving needed for local compilation (only analysis and compile will be done in this - // mode) - if (this.compilationMode === CompilationMode.LOCAL) { - return; - } - const classes = this.classes.keys(); for (const clazz of classes) { const record = this.classes.get(clazz)!; @@ -484,7 +477,7 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { * `ts.SourceFile`. */ typeCheck(sf: ts.SourceFile, ctx: TypeCheckContext): void { - if (!this.fileToClasses.has(sf)) { + if (!this.fileToClasses.has(sf) || this.compilationMode === CompilationMode.LOCAL) { return; } @@ -596,24 +589,20 @@ export class TraitCompiler implements ProgramTypeCheckAdapter { for (const trait of record.traits) { let compileRes: CompileResult|CompileResult[]; + + if (trait.state !== TraitState.Resolved || containsErrors(trait.analysisDiagnostics) || + containsErrors(trait.resolveDiagnostics)) { + // Cannot compile a trait that is not resolved, or had any errors in its declaration. + continue; + } + if (this.compilationMode === CompilationMode.LOCAL) { - if (trait.state !== TraitState.Analyzed || trait.analysis === null || - containsErrors(trait.analysisDiagnostics)) { - // Cannot compile a trait in local mode that is not analyzed, or had any errors in its - // declaration. - continue; - } // `trait.analysis` is non-null asserted here because TypeScript does not recognize that // `Readonly` is nullable (as `unknown` itself is nullable) due to the way that // `Readonly` works. - compileRes = trait.handler.compileLocal(clazz, trait.analysis!, constantPool); + compileRes = + trait.handler.compileLocal(clazz, trait.analysis!, trait.resolution!, constantPool); } else { - if (trait.state !== TraitState.Resolved || containsErrors(trait.analysisDiagnostics) || - containsErrors(trait.resolveDiagnostics)) { - // Cannot compile a trait in global mode that is not resolved, or had any errors in its - // declaration. - continue; - } // `trait.resolution` is non-null asserted below because TypeScript does not recognize that // `Readonly` is nullable (as `unknown` itself is nullable) due to the way that // `Readonly` works. diff --git a/packages/compiler-cli/src/ngtsc/transform/test/compilation_spec.ts b/packages/compiler-cli/src/ngtsc/transform/test/compilation_spec.ts index 7a0014d7e429f..ea67dc8eae061 100644 --- a/packages/compiler-cli/src/ngtsc/transform/test/compilation_spec.ts +++ b/packages/compiler-cli/src/ngtsc/transform/test/compilation_spec.ts @@ -340,21 +340,21 @@ runInEachFileSystem(() => { } } - it('should not run resolve phase', () => { + it('should invoke `resolve` phase', () => { const contents = ` export class Test {} `; const handler = new TestDecoratorHandler(); - spyOn(handler, 'resolve'); + spyOn(handler, 'resolve').and.callThrough(); const {compiler, sourceFile} = setup(contents, [handler], CompilationMode.LOCAL); compiler.analyzeSync(sourceFile); compiler.resolve(); - expect(handler.resolve).not.toHaveBeenCalled(); + expect(handler.resolve).toHaveBeenCalled(); }); - it('should not register', () => { + it('should invoke `register` phase', () => { const contents = ` export class Test {} `; @@ -365,7 +365,7 @@ runInEachFileSystem(() => { compiler.analyzeSync(sourceFile); compiler.resolve(); - expect(handler.register).not.toHaveBeenCalled(); + expect(handler.register).toHaveBeenCalled(); }); it('should not call extendedTemplateCheck', () => {