diff --git a/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts b/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts index a4c5f105f6..a8e02ccc3f 100644 --- a/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts +++ b/packages/compiler-cli/ngcc/src/analysis/decoration_analyzer.ts @@ -8,6 +8,7 @@ import {ConstantPool} from '@angular/compiler'; import * as ts from 'typescript'; +import {ParsedConfiguration} from '../../..'; import {ComponentDecoratorHandler, DirectiveDecoratorHandler, InjectableDecoratorHandler, NgModuleDecoratorHandler, PipeDecoratorHandler, ReferencesRegistry, ResourceLoader} from '../../../src/ngtsc/annotations'; import {CycleAnalyzer, ImportGraph} from '../../../src/ngtsc/cycles'; import {isFatalDiagnosticError} from '../../../src/ngtsc/diagnostics'; @@ -55,6 +56,7 @@ export class DecorationAnalyzer { private rootDirs = this.bundle.rootDirs; private packagePath = this.bundle.entryPoint.package; private isCore = this.bundle.isCore; + private compilerOptions = this.tsConfig !== null? this.tsConfig.options: {}; moduleResolver = new ModuleResolver(this.program, this.options, this.host, /* moduleResolutionCache */ null); @@ -87,7 +89,7 @@ export class DecorationAnalyzer { new ComponentDecoratorHandler( this.reflectionHost, this.evaluator, this.fullRegistry, this.fullMetaReader, this.scopeRegistry, this.scopeRegistry, this.isCore, this.resourceManager, this.rootDirs, - /* defaultPreserveWhitespaces */ false, + !!this.compilerOptions.preserveWhitespaces, /* i18nUseExternalIds */ true, this.bundle.enableI18nLegacyMessageIdFormat, this.moduleResolver, this.cycleAnalyzer, this.refEmitter, NOOP_DEFAULT_IMPORT_RECORDER, NOOP_DEPENDENCY_TRACKER, this.injectableRegistry, /* annotateForClosureCompiler */ false), @@ -123,7 +125,8 @@ export class DecorationAnalyzer { constructor( private fs: FileSystem, private bundle: EntryPointBundle, private reflectionHost: NgccReflectionHost, private referencesRegistry: ReferencesRegistry, - private diagnosticHandler: (error: ts.Diagnostic) => void = () => {}) {} + private diagnosticHandler: (error: ts.Diagnostic) => void = () => {}, + private tsConfig: ParsedConfiguration|null = null) {} /** * Analyze a program to find all the decorated files should be transformed. diff --git a/packages/compiler-cli/ngcc/src/main.ts b/packages/compiler-cli/ngcc/src/main.ts index 6a202be471..a069b8b03b 100644 --- a/packages/compiler-cli/ngcc/src/main.ts +++ b/packages/compiler-cli/ngcc/src/main.ts @@ -307,7 +307,7 @@ export function mainNgcc( const createCompileFn: CreateCompileFn = onTaskCompleted => { const fileWriter = getFileWriter( fileSystem, logger, pkgJsonUpdater, createNewEntryPointFormats, errorOnFailedEntryPoint); - const transformer = new Transformer(fileSystem, logger); + const transformer = new Transformer(fileSystem, logger, tsConfig); return (task: Task) => { const {entryPoint, formatProperty, formatPropertiesToMarkAsProcessed, processDts} = task; diff --git a/packages/compiler-cli/ngcc/src/packages/transformer.ts b/packages/compiler-cli/ngcc/src/packages/transformer.ts index 6ae9785929..f7a30944f7 100644 --- a/packages/compiler-cli/ngcc/src/packages/transformer.ts +++ b/packages/compiler-cli/ngcc/src/packages/transformer.ts @@ -7,6 +7,7 @@ */ import * as ts from 'typescript'; +import {ParsedConfiguration} from '../../..'; import {FileSystem} from '../../../src/ngtsc/file_system'; import {TypeScriptReflectionHost} from '../../../src/ngtsc/reflection'; import {DecorationAnalyzer} from '../analysis/decoration_analyzer'; @@ -63,7 +64,9 @@ export type TransformResult = { * - Some formats may contain multiple "modules" in a single file. */ export class Transformer { - constructor(private fs: FileSystem, private logger: Logger) {} + constructor( + private fs: FileSystem, private logger: Logger, + private tsConfig: ParsedConfiguration|null = null) {} /** * Transform the source (and typings) files of a bundle. @@ -146,7 +149,7 @@ export class Transformer { const diagnostics: ts.Diagnostic[] = []; const decorationAnalyzer = new DecorationAnalyzer( this.fs, bundle, reflectionHost, referencesRegistry, - diagnostic => diagnostics.push(diagnostic)); + diagnostic => diagnostics.push(diagnostic), this.tsConfig); const decorationAnalyses = decorationAnalyzer.analyzeProgram(); const moduleWithProvidersAnalyzer = diff --git a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts index 328ea2ee44..4cc67792d5 100644 --- a/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts +++ b/packages/compiler-cli/ngcc/test/integration/ngcc_spec.ts @@ -1373,6 +1373,44 @@ runInEachFileSystem(() => { }); }); + describe('whitespace preservation', () => { + it('should default not to preserve whitespace', () => { + mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015']}); + expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + expect(fs.readFile(_('/dist/local-package/index.js'))) + .toMatch(/ɵɵtext\(\d+, " Hello\\n"\);/); + }); + + it('should preserve whitespace if set in a loaded tsconfig.json', () => { + fs.writeFile( + _('/tsconfig.json'), + JSON.stringify({angularCompilerOptions: {preserveWhitespaces: true}})); + mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015']}); + expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + expect(fs.readFile(_('/dist/local-package/index.js'))) + .toMatch(/ɵɵtext\(\d+, "\\n Hello\\n"\);/); + }); + + it('should not preserve whitespace if set to false in a loaded tsconfig.json', () => { + fs.writeFile( + _('/tsconfig.json'), + JSON.stringify({angularCompilerOptions: {preserveWhitespaces: false}})); + mainNgcc({basePath: '/dist', propertiesToConsider: ['es2015']}); + expect(loadPackage('local-package', _('/dist')).__processed_by_ivy_ngcc__).toEqual({ + es2015: '0.0.0-PLACEHOLDER', + typings: '0.0.0-PLACEHOLDER', + }); + expect(fs.readFile(_('/dist/local-package/index.js'))) + .toMatch(/ɵɵtext\(\d+, " Hello\\n"\);/); + }); + }); + describe('with configuration files', () => { it('should process a configured deep-import as an entry-point', () => { loadTestFiles([ @@ -1883,7 +1921,7 @@ runInEachFileSystem(() => { { name: _('/dist/local-package/index.js'), contents: - `import {Component} from '@angular/core';\nexport class AppComponent {};\nAppComponent.decorators = [\n{ type: Component, args: [{selector: 'app', template: '

Hello

'}] }\n];` + `import {Component} from '@angular/core';\nexport class AppComponent {};\nAppComponent.decorators = [\n{ type: Component, args: [{selector: 'app', template: '

\\n Hello\\n

'}] }\n];` }, { name: _('/dist/local-package/index.d.ts'),