From 1b43158af611f68569d13f15bea0a4e70702e364 Mon Sep 17 00:00:00 2001 From: Charles Lyding <19598772+clydin@users.noreply.github.com> Date: Tue, 13 Apr 2021 13:46:49 -0400 Subject: [PATCH] fix(compiler-cli): do not error with prepocessing if component has no inline styles (#41602) The asynchronous preprocessing check was not accounting for components that did not have any inline styles. In that case, the cache did not have an entry which then allowed the asynchronous check to run and fail the compilation. The caching during the asynchronous analysis phase now handles components without inline styles. PR Close #41602 --- .../src/ngtsc/annotations/src/component.ts | 2 + .../ngtsc/annotations/test/component_spec.ts | 68 +++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts index ba723a1cd5..553e4ca273 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/src/component.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/src/component.ts @@ -302,6 +302,8 @@ export class ComponentDecoratorHandler implements this.preanalyzeStylesCache.set(node, styles); }); } + } else { + this.preanalyzeStylesCache.set(node, null); } // Wait for both the template and all styleUrl resources to resolve. diff --git a/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts b/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts index 8fcfca7eb6..d94519770e 100644 --- a/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts +++ b/packages/compiler-cli/src/ngtsc/annotations/test/component_spec.ts @@ -302,6 +302,74 @@ runInEachFileSystem(() => { const {analysis} = handler.analyze(TestCmp, detected.metadata); expect(analysis?.inlineStyles).toEqual(jasmine.arrayWithExactContents(['.xyz {}'])); }); + + it('should error if canPreprocess is true and async analyze is not used', async () => { + const {program, options, host} = makeProgram([ + { + name: _('/node_modules/@angular/core/index.d.ts'), + contents: 'export const Component: any;', + }, + { + name: _('/entry.ts'), + contents: ` + import {Component} from '@angular/core'; + + @Component({ + template: '', + styles: ['.abc {}'] + }) class TestCmp {} + ` + }, + ]); + const {reflectionHost, handler, resourceLoader} = setup(program, options, host); + resourceLoader.canPreload = true; + resourceLoader.canPreprocess = true; + + const TestCmp = getDeclaration(program, _('/entry.ts'), 'TestCmp', isNamedClassDeclaration); + const detected = handler.detect(TestCmp, reflectionHost.getDecoratorsOfDeclaration(TestCmp)); + if (detected === undefined) { + return fail('Failed to recognize @Component'); + } + + expect(() => handler.analyze(TestCmp, detected.metadata)) + .toThrowError('Inline resource processing requires asynchronous preanalyze.'); + }); + + it('should not error if component has no inline styles and canPreprocess is true', async () => { + const {program, options, host} = makeProgram([ + { + name: _('/node_modules/@angular/core/index.d.ts'), + contents: 'export const Component: any;', + }, + { + name: _('/entry.ts'), + contents: ` + import {Component} from '@angular/core'; + + @Component({ + template: '', + }) class TestCmp {} + ` + }, + ]); + const {reflectionHost, handler, resourceLoader} = setup(program, options, host); + resourceLoader.canPreload = true; + resourceLoader.canPreprocess = true; + resourceLoader.preprocessInline = async function(data, context) { + fail('preprocessInline should not have been called.'); + return data; + }; + + const TestCmp = getDeclaration(program, _('/entry.ts'), 'TestCmp', isNamedClassDeclaration); + const detected = handler.detect(TestCmp, reflectionHost.getDecoratorsOfDeclaration(TestCmp)); + if (detected === undefined) { + return fail('Failed to recognize @Component'); + } + + await handler.preanalyze(TestCmp, detected.metadata); + + expect(() => handler.analyze(TestCmp, detected.metadata)).not.toThrow(); + }); }); function ivyCode(code: ErrorCode): number {