Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 10 additions & 4 deletions integration/ngcc/test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,19 @@ ivy-ngcc
if [[ $? != 0 ]]; then exit 1; fi

# Did it compile @angular/core/ApplicationModule correctly?
grep "ApplicationModule.ngModuleDef = ɵdefineNgModule" node_modules/@angular/core/fesm2015/core.js
grep "ApplicationModule.ngModuleDef = defineNgModule" node_modules/@angular/core/fesm2015/core.js
if [[ $? != 0 ]]; then exit 1; fi
grep "ApplicationModule.ngModuleDef = ɵdefineNgModule" node_modules/@angular/core/fesm5/core.js
grep "ApplicationModule.ngModuleDef = defineNgModule" node_modules/@angular/core/fesm5/core.js
if [[ $? != 0 ]]; then exit 1; fi
grep "ApplicationModule.ngModuleDef = ɵngcc0.ɵdefineNgModule" node_modules/@angular/core/esm2015/src/application_module.js
grep "ApplicationModule.ngModuleDef = ɵngcc0.defineNgModule" node_modules/@angular/core/esm2015/src/application_module.js
if [[ $? != 0 ]]; then exit 1; fi
grep "ApplicationModule.ngModuleDef = ɵngcc0.ɵdefineNgModule" node_modules/@angular/core/esm5/src/application_module.js
grep "ApplicationModule.ngModuleDef = ɵngcc0.defineNgModule" node_modules/@angular/core/esm5/src/application_module.js
if [[ $? != 0 ]]; then exit 1; fi

# Did it transform @angular/core typing files correctly?
grep "import [*] as ɵngcc0 from './r3_symbols';" node_modules/@angular/core/src/application_module.d.ts
if [[ $? != 0 ]]; then exit 1; fi
grep "static ngInjectorDef: ɵngcc0.InjectorDef<ApplicationModule>;" node_modules/@angular/core/src/application_module.d.ts
if [[ $? != 0 ]]; then exit 1; fi

# Can it be safely run again (as a noop)?
Expand Down
31 changes: 31 additions & 0 deletions packages/compiler-cli/src/ngcc/src/packages/bundle.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
/**
* @license
* Copyright Google Inc. All Rights Reserved.
*
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/

import * as ts from 'typescript';

/**
* A bundle represents the currently compiled entry point format, containing
* information that is necessary for compiling @angular/core with ngcc.
*/
export interface BundleInfo {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the concept of an object to hold this stuff, I am not happy with the name though. Bundle is too generic.

Also I still switch back and forth between passing everything into the constructor versus passing everything to the renderProgram method versus (our current situation) of passing some things to each.

isCore: boolean;
isFlat: boolean;
rewriteCoreImportsTo: ts.SourceFile|null;
rewriteCoreDtsImportsTo: ts.SourceFile|null;
}

export function createBundleInfo(
isCore: boolean, rewriteCoreImportsTo: ts.SourceFile | null,
rewriteCoreDtsImportsTo: ts.SourceFile | null): BundleInfo {
return {
isCore,
isFlat: rewriteCoreImportsTo === null,
rewriteCoreImportsTo: rewriteCoreImportsTo,
rewriteCoreDtsImportsTo: rewriteCoreDtsImportsTo,
};
}
48 changes: 30 additions & 18 deletions packages/compiler-cli/src/ngcc/src/packages/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {EsmRenderer} from '../rendering/esm_renderer';
import {FileInfo, Renderer} from '../rendering/renderer';

import {checkMarkerFile, writeMarkerFile} from './build_marker';
import {BundleInfo, createBundleInfo} from './bundle';
import {EntryPoint, EntryPointFormat} from './entry_point';

/**
Expand Down Expand Up @@ -70,27 +71,40 @@ export class Transformer {
const host = ts.createCompilerHost(options);
const rootDirs = this.getRootDirs(host, options);
const isCore = entryPoint.name === '@angular/core';
const r3SymbolsPath = isCore ? this.findR3SymbolsPath(dirname(entryPointFilePath)) : null;
const r3SymbolsPath =
isCore ? this.findR3SymbolsPath(dirname(entryPointFilePath), 'r3_symbols.js') : null;
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work even if we're compiling a FESM entrypoint?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes. For FESMs, the NgccImportManager will prevent core imports from being generated if core itself is being compiled.

if (this.isFlat && this.isCore && moduleName === '@angular/core') {
return {moduleImport: null, symbol: this.rewriteSymbol(moduleName, symbol)};
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Glad that is sorted :-)

const rootPaths = r3SymbolsPath ? [entryPointFilePath, r3SymbolsPath] : [entryPointFilePath];
const packageProgram = ts.createProgram(rootPaths, options, host);
console.time(entryPoint.name + '(dtsmappper creation)');
const r3SymbolsFile = r3SymbolsPath && packageProgram.getSourceFile(r3SymbolsPath) || null;

// Create the program for processing DTS files if enabled for this format.
const dtsFilePath = entryPoint.typings;
const dtsProgram = transformDts ? ts.createProgram([entryPoint.typings], options, host) : null;
console.timeEnd(entryPoint.name + '(dtsmappper creation)');
let dtsProgram: ts.Program|null = null;
let r3SymbolsDtsFile: ts.SourceFile|null = null;
if (transformDts) {
console.time(`${entryPoint.name} (dtsMapper creation)`);
const r3SymbolsDtsPath =
isCore ? this.findR3SymbolsPath(dirname(dtsFilePath), 'r3_symbols.d.ts') : null;
const rootDtsPaths = r3SymbolsDtsPath ? [dtsFilePath, r3SymbolsDtsPath] : [dtsFilePath];

dtsProgram = ts.createProgram(rootDtsPaths, options, host);
r3SymbolsDtsFile = r3SymbolsDtsPath && dtsProgram.getSourceFile(r3SymbolsDtsPath) || null;
console.timeEnd(`${entryPoint.name} (dtsMapper creation)`);
}

const bundle = createBundleInfo(isCore, r3SymbolsFile, r3SymbolsDtsFile);
const reflectionHost = this.getHost(isCore, format, packageProgram, dtsFilePath, dtsProgram);
const r3SymbolsFile = r3SymbolsPath && packageProgram.getSourceFile(r3SymbolsPath) || null;

// Parse and analyze the files.
const {decorationAnalyses, switchMarkerAnalyses} =
this.analyzeProgram(packageProgram, reflectionHost, rootDirs, isCore);

console.time(entryPoint.name + '(rendering)');
console.time(`${entryPoint.name} (rendering)`);
// Transform the source files and source maps.
const renderer = this.getRenderer(
format, packageProgram, reflectionHost, isCore, r3SymbolsFile, transformDts);
const renderer = this.getRenderer(format, packageProgram, reflectionHost, bundle, transformDts);
const renderedFiles =
renderer.renderProgram(packageProgram, decorationAnalyses, switchMarkerAnalyses);
console.timeEnd(entryPoint.name + '(rendering)');
console.timeEnd(`${entryPoint.name} (rendering)`);

// Write out all the transformed files.
renderedFiles.forEach(file => this.writeFile(file));
Expand Down Expand Up @@ -125,17 +139,15 @@ export class Transformer {
}

getRenderer(
format: string, program: ts.Program, host: NgccReflectionHost, isCore: boolean,
rewriteCoreImportsTo: ts.SourceFile|null, transformDts: boolean): Renderer {
format: string, program: ts.Program, host: NgccReflectionHost, bundle: BundleInfo,
transformDts: boolean): Renderer {
switch (format) {
case 'esm2015':
case 'fesm2015':
return new EsmRenderer(
host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath, transformDts);
return new EsmRenderer(host, bundle, this.sourcePath, this.targetPath, transformDts);
case 'esm5':
case 'fesm5':
return new Esm5Renderer(
host, isCore, rewriteCoreImportsTo, this.sourcePath, this.targetPath, transformDts);
return new Esm5Renderer(host, bundle, this.sourcePath, this.targetPath, transformDts);
default:
throw new Error(`Renderer for "${format}" not yet implemented.`);
}
Expand All @@ -162,8 +174,8 @@ export class Transformer {
writeFileSync(file.path, file.contents, 'utf8');
}

findR3SymbolsPath(directory: string): string|null {
const r3SymbolsFilePath = resolve(directory, 'r3_symbols.js');
findR3SymbolsPath(directory: string, fileName: string): string|null {
const r3SymbolsFilePath = resolve(directory, fileName);
if (existsSync(r3SymbolsFilePath)) {
return r3SymbolsFilePath;
}
Expand All @@ -181,7 +193,7 @@ export class Transformer {
});

for (const subDirectory of subDirectories) {
const r3SymbolsFilePath = this.findR3SymbolsPath(resolve(directory, subDirectory));
const r3SymbolsFilePath = this.findR3SymbolsPath(resolve(directory, subDirectory), fileName);
if (r3SymbolsFilePath) {
return r3SymbolsFilePath;
}
Expand Down
8 changes: 4 additions & 4 deletions packages/compiler-cli/src/ngcc/src/rendering/esm5_renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import * as ts from 'typescript';
import MagicString from 'magic-string';
import {NgccReflectionHost} from '../host/ngcc_host';
import {CompiledClass} from '../analysis/decoration_analyzer';
import {BundleInfo} from '../packages/bundle';
import {EsmRenderer} from './esm_renderer';

export class Esm5Renderer extends EsmRenderer {
constructor(
protected host: NgccReflectionHost, protected isCore: boolean,
protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string,
protected targetPath: string, transformDts: boolean) {
super(host, isCore, rewriteCoreImportsTo, sourcePath, targetPath, transformDts);
protected host: NgccReflectionHost, protected bundle: BundleInfo,
protected sourcePath: string, protected targetPath: string, transformDts: boolean) {
super(host, bundle, sourcePath, targetPath, transformDts);
}

/**
Expand Down
8 changes: 4 additions & 4 deletions packages/compiler-cli/src/ngcc/src/rendering/esm_renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ import * as ts from 'typescript';
import MagicString from 'magic-string';
import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host';
import {CompiledClass} from '../analysis/decoration_analyzer';
import {BundleInfo} from '../packages/bundle';
import {Renderer} from './renderer';

export class EsmRenderer extends Renderer {
constructor(
protected host: NgccReflectionHost, protected isCore: boolean,
protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string,
protected targetPath: string, transformDts: boolean) {
super(host, isCore, rewriteCoreImportsTo, sourcePath, targetPath, transformDts);
protected host: NgccReflectionHost, protected bundle: BundleInfo,
protected sourcePath: string, protected targetPath: string, transformDts: boolean) {
super(host, bundle, sourcePath, targetPath, transformDts);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@ import {ImportManager} from '../../../ngtsc/translator';
export class NgccImportManager extends ImportManager {
constructor(private isFlat: boolean, isCore: boolean, prefix?: string) { super(isCore, prefix); }

generateNamedImport(moduleName: string, symbol: string): string|null {
generateNamedImport(moduleName: string, symbol: string):
{moduleImport: string | null, symbol: string} {
if (this.isFlat && this.isCore && moduleName === '@angular/core') {
return null;
return {moduleImport: null, symbol: this.rewriteSymbol(moduleName, symbol)};
}
return super.generateNamedImport(moduleName, symbol);
}
}
}
18 changes: 10 additions & 8 deletions packages/compiler-cli/src/ngcc/src/rendering/renderer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {translateStatement, translateType} from '../../../ngtsc/translator';
import {NgccImportManager} from './ngcc_import_manager';
import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/decoration_analyzer';
import {SwitchMarkerAnalyses, SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer';
import {BundleInfo} from '../packages/bundle';
import {IMPORT_PREFIX} from '../constants';
import {NgccReflectionHost, SwitchableVariableDeclaration} from '../host/ngcc_host';

Expand Down Expand Up @@ -55,9 +56,9 @@ interface DtsClassInfo {
*/
export abstract class Renderer {
constructor(
protected host: NgccReflectionHost, protected isCore: boolean,
protected rewriteCoreImportsTo: ts.SourceFile|null, protected sourcePath: string,
protected targetPath: string, protected transformDts: boolean) {}
protected host: NgccReflectionHost, protected bundle: BundleInfo,
protected sourcePath: string, protected targetPath: string, protected transformDts: boolean) {
}

renderProgram(
program: ts.Program, decorationAnalyses: DecorationAnalyses,
Expand Down Expand Up @@ -101,7 +102,7 @@ export abstract class Renderer {

if (compiledFile) {
const importManager =
new NgccImportManager(!this.rewriteCoreImportsTo, this.isCore, IMPORT_PREFIX);
new NgccImportManager(this.bundle.isFlat, this.bundle.isCore, IMPORT_PREFIX);
const decoratorsToRemove = new Map<ts.Node, ts.Node[]>();

compiledFile.compiledClasses.forEach(clazz => {
Expand All @@ -116,8 +117,8 @@ export abstract class Renderer {
compiledFile.sourceFile);

this.addImports(
outputText,
importManager.getAllImports(compiledFile.sourceFile.fileName, this.rewriteCoreImportsTo));
outputText, importManager.getAllImports(
compiledFile.sourceFile.fileName, this.bundle.rewriteCoreImportsTo));

// TODO: remove contructor param metadata and property decorators (we need info from the
// handlers to do this)
Expand All @@ -130,7 +131,7 @@ export abstract class Renderer {
renderDtsFile(dtsFile: ts.SourceFile, dtsClasses: DtsClassInfo[]): FileInfo[] {
const input = this.extractSourceMap(dtsFile);
const outputText = new MagicString(input.source);
const importManager = new NgccImportManager(false, this.isCore, IMPORT_PREFIX);
const importManager = new NgccImportManager(false, this.bundle.isCore, IMPORT_PREFIX);

dtsClasses.forEach(dtsClass => {
const endOfClass = dtsClass.dtsDeclaration.getEnd();
Expand All @@ -142,7 +143,8 @@ export abstract class Renderer {
});

this.addImports(
outputText, importManager.getAllImports(dtsFile.fileName, this.rewriteCoreImportsTo));
outputText,
importManager.getAllImports(dtsFile.fileName, this.bundle.rewriteCoreDtsImportsTo));

return this.renderSourceAndMap(dtsFile, input, outputText);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import MagicString from 'magic-string';
import {makeProgram} from '../helpers/utils';
import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
import {createBundleInfo} from '../../src/packages/bundle';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {EsmRenderer} from '../../src/rendering/esm_renderer';

Expand All @@ -23,7 +24,8 @@ function setup(file: {name: string, contents: string}, transformDts: boolean = f
const decorationAnalyses =
new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program);
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program);
const renderer = new EsmRenderer(host, false, null, dir, dir, false);
const bundle = createBundleInfo(false, null, null);
const renderer = new EsmRenderer(host, bundle, dir, dir, false);
return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses};
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import MagicString from 'magic-string';
import {makeProgram, getDeclaration} from '../helpers/utils';
import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
import {createBundleInfo} from '../../src/packages/bundle';
import {Esm5ReflectionHost} from '../../src/host/esm5_host';
import {Esm5Renderer} from '../../src/rendering/esm5_renderer';

Expand All @@ -20,7 +21,8 @@ function setup(file: {name: string, contents: string}) {
const decorationAnalyses =
new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program);
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program);
const renderer = new Esm5Renderer(host, false, null, '', '', false);
const bundle = createBundleInfo(false, null, null);
const renderer = new Esm5Renderer(host, bundle, '', '', false);
return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses};
}

Expand Down
Loading