refactor(ivy): ngcc - encapsulate variables into "bundles" (#26906)

There are a number of variables that need to be passed around
the program, in particular to the renderers, which benefit from being
stored in well defined objects.

The new `EntryPointBundle` structure is a specific format of an entry-point
and contains the compiled `BundleProgram` objects for the source and typings,
if appropriate.

This change helps with future refactoring, where we may need to add new
properties to this object. It allows us to maintain more stable APIs between
the constituent parts of ngcc, rather than passing lots of primitive values
around throughout the program.

PR Close #26906
This commit is contained in:
Pete Bacon Darwin 2018-11-25 21:40:25 +00:00 committed by Igor Minar
parent 64f6820660
commit b55e1c2ba9
19 changed files with 608 additions and 499 deletions

View File

@ -10,7 +10,8 @@ import * as ts from 'typescript';
import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import} from '../../../ngtsc/host'; import {ClassMember, ClassMemberKind, CtorParameter, Decorator, Import} from '../../../ngtsc/host';
import {TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/metadata'; import {TypeScriptReflectionHost, reflectObjectLiteral} from '../../../ngtsc/metadata';
import {findAll, getNameText, getOriginalSymbol, isDefined} from '../utils'; import {BundleProgram} from '../packages/bundle_program';
import {findAll, getNameText, isDefined} from '../utils';
import {DecoratedClass} from './decorated_class'; import {DecoratedClass} from './decorated_class';
import {NgccReflectionHost, PRE_R3_MARKER, SwitchableVariableDeclaration, isSwitchableVariableDeclaration} from './ngcc_host'; import {NgccReflectionHost, PRE_R3_MARKER, SwitchableVariableDeclaration, isSwitchableVariableDeclaration} from './ngcc_host';
@ -49,13 +50,9 @@ export const CONSTRUCTOR_PARAMS = 'ctorParameters' as ts.__String;
*/ */
export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements NgccReflectionHost { export class Esm2015ReflectionHost extends TypeScriptReflectionHost implements NgccReflectionHost {
protected dtsClassMap: Map<string, ts.ClassDeclaration>|null; protected dtsClassMap: Map<string, ts.ClassDeclaration>|null;
constructor( constructor(protected isCore: boolean, checker: ts.TypeChecker, dts?: BundleProgram|null) {
protected isCore: boolean, checker: ts.TypeChecker, dtsRootFileName?: string,
dtsProgram?: ts.Program|null) {
super(checker); super(checker);
this.dtsClassMap = (dtsRootFileName && dtsProgram) ? this.dtsClassMap = dts && this.computeDtsClassMap(dts.path, dts.program) || null;
this.computeDtsClassMap(dtsRootFileName, dtsProgram) :
null;
} }
/** /**

View File

@ -11,6 +11,7 @@ import * as yargs from 'yargs';
import {DependencyHost} from './packages/dependency_host'; import {DependencyHost} from './packages/dependency_host';
import {DependencyResolver} from './packages/dependency_resolver'; import {DependencyResolver} from './packages/dependency_resolver';
import {EntryPointFormat} from './packages/entry_point'; import {EntryPointFormat} from './packages/entry_point';
import {makeEntryPointBundle} from './packages/entry_point_bundle';
import {EntryPointFinder} from './packages/entry_point_finder'; import {EntryPointFinder} from './packages/entry_point_finder';
import {Transformer} from './packages/transformer'; import {Transformer} from './packages/transformer';
@ -48,12 +49,25 @@ export function mainNgcc(args: string[]): number {
try { try {
const {entryPoints} = finder.findEntryPoints(sourcePath); const {entryPoints} = finder.findEntryPoints(sourcePath);
entryPoints.forEach(entryPoint => { entryPoints.forEach(entryPoint => {
// Are we compiling the Angular core?
const isCore = entryPoint.name === '@angular/core';
// We transform the d.ts typings files while transforming one of the formats. // We transform the d.ts typings files while transforming one of the formats.
// This variable decides with which of the available formats to do this transform. // This variable decides with which of the available formats to do this transform.
// It is marginally faster to process via the flat file if available. // It is marginally faster to process via the flat file if available.
const dtsTranformFormat: EntryPointFormat = entryPoint.fesm2015 ? 'fesm2015' : 'esm2015'; const dtsTransformFormat: EntryPointFormat = entryPoint.fesm2015 ? 'fesm2015' : 'esm2015';
formats.forEach(
format => transformer.transform(entryPoint, format, format === dtsTranformFormat)); formats.forEach(format => {
const bundle =
makeEntryPointBundle(entryPoint, isCore, format, format === dtsTransformFormat);
if (bundle === null) {
console.warn(
`Skipping ${entryPoint.name} : ${format} (no entry point file for this format).`);
} else {
transformer.transform(entryPoint, isCore, bundle);
}
});
}); });
} catch (e) { } catch (e) {
console.error(e.stack); console.error(e.stack);

View File

@ -1,31 +0,0 @@
/**
* @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 {
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,
};
}

View File

@ -0,0 +1,72 @@
/**
* @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 {dirname, resolve} from 'canonical-path';
import {existsSync, lstatSync, readdirSync} from 'fs';
import * as ts from 'typescript';
/**
* An entry point bundle contains one or two programs, e.g. `src` and `dts`,
* that are compiled via TypeScript.
*
* To aid with processing the program, this interface exposes the program itself,
* as well as path and TS file of the entry-point to the program and the r3Symbols
* file, if appropriate.
*/
export interface BundleProgram {
program: ts.Program;
path: string;
file: ts.SourceFile;
r3SymbolsPath: string|null;
r3SymbolsFile: ts.SourceFile|null;
}
/**
* Create a bundle program.
*/
export function makeBundleProgram(
isCore: boolean, path: string, r3FileName: string, options: ts.CompilerOptions,
host: ts.CompilerHost): BundleProgram {
const r3SymbolsPath = isCore ? findR3SymbolsPath(dirname(path), r3FileName) : null;
const rootPaths = r3SymbolsPath ? [path, r3SymbolsPath] : [path];
const program = ts.createProgram(rootPaths, options, host);
const file = program.getSourceFile(path) !;
const r3SymbolsFile = r3SymbolsPath && program.getSourceFile(r3SymbolsPath) || null;
return {program, path, file, r3SymbolsPath, r3SymbolsFile};
}
/**
* Search the given directory hierarchy to find the path to the `r3_symbols` file.
*/
export function findR3SymbolsPath(directory: string, filename: string): string|null {
const r3SymbolsFilePath = resolve(directory, filename);
if (existsSync(r3SymbolsFilePath)) {
return r3SymbolsFilePath;
}
const subDirectories =
readdirSync(directory)
// Not interested in hidden files
.filter(p => !p.startsWith('.'))
// Ignore node_modules
.filter(p => p !== 'node_modules')
// Only interested in directories (and only those that are not symlinks)
.filter(p => {
const stat = lstatSync(resolve(directory, p));
return stat.isDirectory() && !stat.isSymbolicLink();
});
for (const subDirectory of subDirectories) {
const r3SymbolsFilePath = findR3SymbolsPath(resolve(directory, subDirectory, ), filename);
if (r3SymbolsFilePath) {
return r3SymbolsFilePath;
}
}
return null;
}

View File

@ -0,0 +1,58 @@
/**
* @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';
import {BundleProgram, makeBundleProgram} from './bundle_program';
import {EntryPoint, EntryPointFormat} from './entry_point';
/**
* A bundle of files and paths (and TS programs) that correspond to a particular
* format of a package entry-point.
*/
export interface EntryPointBundle {
format: EntryPointFormat;
isFlat: boolean;
rootDirs: string[];
src: BundleProgram;
dts: BundleProgram|null;
}
/**
* Get an object that describes a formatted bundle for an entry-point.
* @param entryPoint The entry-point that contains the bundle.
* @param format The format of the bundle.
* @param transformDts True if processing this bundle should also process its `.d.ts` files.
*/
export function makeEntryPointBundle(
entryPoint: EntryPoint, isCore: boolean, format: EntryPointFormat,
transformDts: boolean): EntryPointBundle|null {
// Bail out if the entry-point does not have this format.
const path = entryPoint[format];
if (!path) {
return null;
}
// Create the TS program and necessary helpers.
const options: ts.CompilerOptions = {
allowJs: true,
maxNodeModuleJsDepth: Infinity,
rootDir: entryPoint.path,
};
const host = ts.createCompilerHost(options);
const rootDirs = [entryPoint.path];
// Create the bundle programs, as necessary.
const src = makeBundleProgram(isCore, path, 'r3_symbols.js', options, host);
const dts = transformDts ?
makeBundleProgram(isCore, entryPoint.typings, 'r3_symbols.d.ts', options, host) :
null;
const isFlat = src.r3SymbolsFile === null;
return {format, rootDirs, isFlat, src, dts};
}

View File

@ -5,10 +5,9 @@
* Use of this source code is governed by an MIT-style license that can be * 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 * found in the LICENSE file at https://angular.io/license
*/ */
import {dirname, resolve} from 'canonical-path'; import {dirname} from 'canonical-path';
import {existsSync, lstatSync, readdirSync, writeFileSync} from 'fs'; import {existsSync, writeFileSync} from 'fs';
import {mkdir, mv} from 'shelljs'; import {mkdir, mv} from 'shelljs';
import * as ts from 'typescript';
import {DecorationAnalyzer} from '../analysis/decoration_analyzer'; import {DecorationAnalyzer} from '../analysis/decoration_analyzer';
import {NgccReferencesRegistry} from '../analysis/ngcc_references_registry'; import {NgccReferencesRegistry} from '../analysis/ngcc_references_registry';
@ -21,8 +20,8 @@ import {EsmRenderer} from '../rendering/esm_renderer';
import {FileInfo, Renderer} from '../rendering/renderer'; import {FileInfo, Renderer} from '../rendering/renderer';
import {checkMarkerFile, writeMarkerFile} from './build_marker'; import {checkMarkerFile, writeMarkerFile} from './build_marker';
import {BundleInfo, createBundleInfo} from './bundle'; import {EntryPoint} from './entry_point';
import {EntryPoint, EntryPointFormat} from './entry_point'; import {EntryPointBundle} from './entry_point_bundle';
/** /**
* A Package is stored in a directory on disk and that directory can contain one or more package * A Package is stored in a directory on disk and that directory can contain one or more package
@ -32,9 +31,11 @@ import {EntryPoint, EntryPointFormat} from './entry_point';
* parsed to identify the decorated exported classes that need to be analyzed and compiled by one or * parsed to identify the decorated exported classes that need to be analyzed and compiled by one or
* more `DecoratorHandler` objects. * more `DecoratorHandler` objects.
* *
* Each entry point to a package is identified by a `SourceFile` that can be parsed and analyzed to * Each entry point to a package is identified by a `package.json` which contains properties that
* indicate what formatted bundles are accessible via this end-point.
*
* Each bundle is identified by a root `SourceFile` that can be parsed and analyzed to
* identify classes that need to be transformed; and then finally rendered and written to disk. * identify classes that need to be transformed; and then finally rendered and written to disk.
* The actual file which needs to be transformed depends upon the package format.
* *
* Along with the source files, the corresponding source maps (either inline or external) and * Along with the source files, the corresponding source maps (either inline or external) and
* `.d.ts` files are transformed accordingly. * `.d.ts` files are transformed accordingly.
@ -46,126 +47,71 @@ import {EntryPoint, EntryPointFormat} from './entry_point';
export class Transformer { export class Transformer {
constructor(private sourcePath: string, private targetPath: string) {} constructor(private sourcePath: string, private targetPath: string) {}
transform(entryPoint: EntryPoint, format: EntryPointFormat, transformDts: boolean): void { /**
if (checkMarkerFile(entryPoint, format)) { * Transform the source (and typings) files of a bundle.
console.warn(`Skipping ${entryPoint.name} : ${format} (already built).`); * @param bundle the bundle to transform.
*/
transform(entryPoint: EntryPoint, isCore: boolean, bundle: EntryPointBundle): void {
if (checkMarkerFile(entryPoint, bundle.format)) {
console.warn(`Skipping ${entryPoint.name} : ${bundle.format} (already built).`);
return; return;
} }
const entryPointFilePath = entryPoint[format]; console.warn(`Compiling ${entryPoint.name} - ${bundle.format}`);
if (!entryPointFilePath) {
console.warn(
`Skipping ${entryPoint.name} : ${format} (no entry point file for this format).`);
return;
}
console.warn(`Compiling ${entryPoint.name} - ${format}`); const reflectionHost = this.getHost(isCore, bundle);
const options: ts.CompilerOptions = {
allowJs: true,
maxNodeModuleJsDepth: Infinity,
rootDir: entryPoint.path,
};
// Create the TS program and necessary helpers.
// TODO : create a custom compiler host that reads from .bak files if available.
const host = ts.createCompilerHost(options);
const rootDirs = this.getRootDirs(host, options);
const isCore = entryPoint.name === '@angular/core';
const r3SymbolsPath =
isCore ? this.findR3SymbolsPath(dirname(entryPointFilePath), 'r3_symbols.js') : null;
const rootPaths = r3SymbolsPath ? [entryPointFilePath, r3SymbolsPath] : [entryPointFilePath];
const packageProgram = ts.createProgram(rootPaths, options, host);
const r3SymbolsFile = r3SymbolsPath && packageProgram.getSourceFile(r3SymbolsPath) || null;
// Create the program for processing DTS files if enabled for this format.
const dtsFilePath = entryPoint.typings;
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);
// Parse and analyze the files. // Parse and analyze the files.
const {decorationAnalyses, switchMarkerAnalyses} = const {decorationAnalyses, switchMarkerAnalyses} =
this.analyzeProgram(packageProgram, reflectionHost, rootDirs, isCore); this.analyzeProgram(reflectionHost, isCore, bundle);
console.time(`${entryPoint.name} (rendering)`);
// Transform the source files and source maps. // Transform the source files and source maps.
const renderer = this.getRenderer(format, packageProgram, reflectionHost, bundle, transformDts); const renderer = this.getRenderer(reflectionHost, isCore, bundle);
const renderedFiles = const renderedFiles = renderer.renderProgram(decorationAnalyses, switchMarkerAnalyses);
renderer.renderProgram(packageProgram, decorationAnalyses, switchMarkerAnalyses);
console.timeEnd(`${entryPoint.name} (rendering)`);
// Write out all the transformed files. // Write out all the transformed files.
renderedFiles.forEach(file => this.writeFile(file)); renderedFiles.forEach(file => this.writeFile(file));
// Write the built-with-ngcc marker // Write the built-with-ngcc marker
writeMarkerFile(entryPoint, format); writeMarkerFile(entryPoint, bundle.format);
} }
getRootDirs(host: ts.CompilerHost, options: ts.CompilerOptions) { getHost(isCore: boolean, bundle: EntryPointBundle): NgccReflectionHost {
if (options.rootDirs !== undefined) { const typeChecker = bundle.src.program.getTypeChecker();
return options.rootDirs; switch (bundle.format) {
} else if (options.rootDir !== undefined) {
return [options.rootDir];
} else {
return [host.getCurrentDirectory()];
}
}
getHost(
isCore: boolean, format: string, program: ts.Program, dtsFilePath: string,
dtsProgram: ts.Program|null): NgccReflectionHost {
switch (format) {
case 'esm2015': case 'esm2015':
case 'fesm2015': case 'fesm2015':
return new Esm2015ReflectionHost(isCore, program.getTypeChecker(), dtsFilePath, dtsProgram); return new Esm2015ReflectionHost(isCore, typeChecker, bundle.dts);
case 'esm5': case 'esm5':
case 'fesm5': case 'fesm5':
return new Esm5ReflectionHost(isCore, program.getTypeChecker()); return new Esm5ReflectionHost(isCore, typeChecker);
default: default:
throw new Error(`Relection host for "${format}" not yet implemented.`); throw new Error(`Reflection host for "${bundle.format}" not yet implemented.`);
} }
} }
getRenderer( getRenderer(host: NgccReflectionHost, isCore: boolean, bundle: EntryPointBundle): Renderer {
format: string, program: ts.Program, host: NgccReflectionHost, bundle: BundleInfo, switch (bundle.format) {
transformDts: boolean): Renderer {
switch (format) {
case 'esm2015': case 'esm2015':
case 'fesm2015': case 'fesm2015':
return new EsmRenderer(host, bundle, this.sourcePath, this.targetPath, transformDts); return new EsmRenderer(host, isCore, bundle, this.sourcePath, this.targetPath);
case 'esm5': case 'esm5':
case 'fesm5': case 'fesm5':
return new Esm5Renderer(host, bundle, this.sourcePath, this.targetPath, transformDts); return new Esm5Renderer(host, isCore, bundle, this.sourcePath, this.targetPath);
default: default:
throw new Error(`Renderer for "${format}" not yet implemented.`); throw new Error(`Renderer for "${bundle.format}" not yet implemented.`);
} }
} }
analyzeProgram( analyzeProgram(reflectionHost: NgccReflectionHost, isCore: boolean, bundle: EntryPointBundle) {
program: ts.Program, reflectionHost: NgccReflectionHost, rootDirs: string[], const typeChecker = bundle.src.program.getTypeChecker();
isCore: boolean) {
const typeChecker = bundle.program.getTypeChecker();
const referencesRegistry = new NgccReferencesRegistry(reflectionHost); const referencesRegistry = new NgccReferencesRegistry(reflectionHost);
const decorationAnalyzer = const decorationAnalyzer = new DecorationAnalyzer(
new DecorationAnalyzer(typeChecker, reflectionHost, referencesRegistry, rootDirs, isCore); typeChecker, reflectionHost, referencesRegistry, bundle.rootDirs, isCore);
const switchMarkerAnalyzer = new SwitchMarkerAnalyzer(reflectionHost); const switchMarkerAnalyzer = new SwitchMarkerAnalyzer(reflectionHost);
return { const decorationAnalyses = decorationAnalyzer.analyzeProgram(bundle.src.program);
decorationAnalyses: decorationAnalyzer.analyzeProgram(program), const switchMarkerAnalyses = switchMarkerAnalyzer.analyzeProgram(bundle.src.program);
switchMarkerAnalyses: switchMarkerAnalyzer.analyzeProgram(program), return {decorationAnalyses, switchMarkerAnalyses};
};
} }
writeFile(file: FileInfo): void { writeFile(file: FileInfo): void {
@ -176,32 +122,4 @@ export class Transformer {
} }
writeFileSync(file.path, file.contents, 'utf8'); writeFileSync(file.path, file.contents, 'utf8');
} }
findR3SymbolsPath(directory: string, fileName: string): string|null {
const r3SymbolsFilePath = resolve(directory, fileName);
if (existsSync(r3SymbolsFilePath)) {
return r3SymbolsFilePath;
}
const subDirectories =
readdirSync(directory)
// Not interested in hidden files
.filter(p => !p.startsWith('.'))
// Ignore node_modules
.filter(p => p !== 'node_modules')
// Only interested in directories (and only those that are not symlinks)
.filter(p => {
const stat = lstatSync(resolve(directory, p));
return stat.isDirectory() && !stat.isSymbolicLink();
});
for (const subDirectory of subDirectories) {
const r3SymbolsFilePath = this.findR3SymbolsPath(resolve(directory, subDirectory), fileName);
if (r3SymbolsFilePath) {
return r3SymbolsFilePath;
}
}
return null;
}
} }

View File

@ -9,14 +9,14 @@ import * as ts from 'typescript';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import {NgccReflectionHost} from '../host/ngcc_host'; import {NgccReflectionHost} from '../host/ngcc_host';
import {CompiledClass} from '../analysis/decoration_analyzer'; import {CompiledClass} from '../analysis/decoration_analyzer';
import {BundleInfo} from '../packages/bundle';
import {EsmRenderer} from './esm_renderer'; import {EsmRenderer} from './esm_renderer';
import {EntryPointBundle} from '../packages/entry_point_bundle';
export class Esm5Renderer extends EsmRenderer { export class Esm5Renderer extends EsmRenderer {
constructor( constructor(
host: NgccReflectionHost, bundle: BundleInfo, sourcePath: string, targetPath: string, host: NgccReflectionHost, isCore: boolean, bundle: EntryPointBundle, sourcePath: string,
transformDts: boolean) { targetPath: string) {
super(host, bundle, sourcePath, targetPath, transformDts); super(host, isCore, bundle, sourcePath, targetPath);
} }
/** /**

View File

@ -9,14 +9,14 @@ import * as ts from 'typescript';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host'; import {NgccReflectionHost, POST_R3_MARKER, PRE_R3_MARKER, SwitchableVariableDeclaration} from '../host/ngcc_host';
import {CompiledClass} from '../analysis/decoration_analyzer'; import {CompiledClass} from '../analysis/decoration_analyzer';
import {BundleInfo} from '../packages/bundle'; import {Renderer, stripExtension} from './renderer';
import {Renderer} from './renderer'; import {EntryPointBundle} from '../packages/entry_point_bundle';
export class EsmRenderer extends Renderer { export class EsmRenderer extends Renderer {
constructor( constructor(
host: NgccReflectionHost, bundle: BundleInfo, sourcePath: string, targetPath: string, host: NgccReflectionHost, isCore: boolean, bundle: EntryPointBundle, sourcePath: string,
transformDts: boolean) { targetPath: string) {
super(host, bundle, sourcePath, targetPath, transformDts); super(host, isCore, bundle, sourcePath, targetPath);
} }
/** /**

View File

@ -19,9 +19,9 @@ import {translateStatement, translateType} from '../../../ngtsc/translator';
import {NgccImportManager} from './ngcc_import_manager'; import {NgccImportManager} from './ngcc_import_manager';
import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/decoration_analyzer'; import {CompiledClass, CompiledFile, DecorationAnalyses} from '../analysis/decoration_analyzer';
import {SwitchMarkerAnalyses, SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer'; import {SwitchMarkerAnalyses, SwitchMarkerAnalysis} from '../analysis/switch_marker_analyzer';
import {BundleInfo} from '../packages/bundle';
import {IMPORT_PREFIX} from '../constants'; import {IMPORT_PREFIX} from '../constants';
import {NgccReflectionHost, SwitchableVariableDeclaration} from '../host/ngcc_host'; import {NgccReflectionHost, SwitchableVariableDeclaration} from '../host/ngcc_host';
import {EntryPointBundle} from '../packages/entry_point_bundle';
interface SourceMapInfo { interface SourceMapInfo {
source: string; source: string;
@ -56,28 +56,33 @@ interface DtsClassInfo {
*/ */
export abstract class Renderer { export abstract class Renderer {
constructor( constructor(
protected host: NgccReflectionHost, protected bundle: BundleInfo, protected host: NgccReflectionHost, protected isCore: boolean,
protected sourcePath: string, protected targetPath: string, protected transformDts: boolean) { protected bundle: EntryPointBundle, protected sourcePath: string,
} protected targetPath: string) {}
renderProgram( renderProgram(decorationAnalyses: DecorationAnalyses, switchMarkerAnalyses: SwitchMarkerAnalyses):
program: ts.Program, decorationAnalyses: DecorationAnalyses, FileInfo[] {
switchMarkerAnalyses: SwitchMarkerAnalyses): FileInfo[] {
const renderedFiles: FileInfo[] = []; const renderedFiles: FileInfo[] = [];
// Transform the source files. // Transform the source files.
program.getSourceFiles().map(sourceFile => { this.bundle.src.program.getSourceFiles().map(sourceFile => {
const compiledFile = decorationAnalyses.get(sourceFile); const compiledFile = decorationAnalyses.get(sourceFile);
const switchMarkerAnalysis = switchMarkerAnalyses.get(sourceFile); const switchMarkerAnalysis = switchMarkerAnalyses.get(sourceFile);
if (compiledFile || switchMarkerAnalysis) { if (compiledFile || switchMarkerAnalysis || sourceFile === this.bundle.src.file) {
renderedFiles.push(...this.renderFile(sourceFile, compiledFile, switchMarkerAnalysis)); renderedFiles.push(...this.renderFile(sourceFile, compiledFile, switchMarkerAnalysis));
} }
}); });
if (this.transformDts) { // Transform the .d.ts files
// Transform the .d.ts files if (this.bundle.dts) {
const dtsFiles = this.getTypingsFilesToRender(decorationAnalyses); const dtsFiles = this.getTypingsFilesToRender(decorationAnalyses);
// If the dts entry-point is not already there (it did not have compiled classes)
// then add it now, to ensure it gets its extra exports rendered.
if (!dtsFiles.has(this.bundle.dts.file)) {
dtsFiles.set(this.bundle.dts.file, []);
}
dtsFiles.forEach((classes, file) => renderedFiles.push(...this.renderDtsFile(file, classes))); dtsFiles.forEach((classes, file) => renderedFiles.push(...this.renderDtsFile(file, classes)));
} }
@ -101,8 +106,7 @@ export abstract class Renderer {
} }
if (compiledFile) { if (compiledFile) {
const importManager = const importManager = new NgccImportManager(this.bundle.isFlat, this.isCore, IMPORT_PREFIX);
new NgccImportManager(this.bundle.isFlat, this.bundle.isCore, IMPORT_PREFIX);
const decoratorsToRemove = new Map<ts.Node, ts.Node[]>(); const decoratorsToRemove = new Map<ts.Node, ts.Node[]>();
compiledFile.compiledClasses.forEach(clazz => { compiledFile.compiledClasses.forEach(clazz => {
@ -118,9 +122,9 @@ export abstract class Renderer {
this.addImports( this.addImports(
outputText, importManager.getAllImports( outputText, importManager.getAllImports(
compiledFile.sourceFile.fileName, this.bundle.rewriteCoreImportsTo)); compiledFile.sourceFile.fileName, this.bundle.src.r3SymbolsFile));
// TODO: remove contructor param metadata and property decorators (we need info from the // TODO: remove constructor param metadata and property decorators (we need info from the
// handlers to do this) // handlers to do this)
this.removeDecorators(outputText, decoratorsToRemove); this.removeDecorators(outputText, decoratorsToRemove);
} }
@ -131,7 +135,7 @@ export abstract class Renderer {
renderDtsFile(dtsFile: ts.SourceFile, dtsClasses: DtsClassInfo[]): FileInfo[] { renderDtsFile(dtsFile: ts.SourceFile, dtsClasses: DtsClassInfo[]): FileInfo[] {
const input = this.extractSourceMap(dtsFile); const input = this.extractSourceMap(dtsFile);
const outputText = new MagicString(input.source); const outputText = new MagicString(input.source);
const importManager = new NgccImportManager(false, this.bundle.isCore, IMPORT_PREFIX); const importManager = new NgccImportManager(false, this.isCore, IMPORT_PREFIX);
dtsClasses.forEach(dtsClass => { dtsClasses.forEach(dtsClass => {
const endOfClass = dtsClass.dtsDeclaration.getEnd(); const endOfClass = dtsClass.dtsDeclaration.getEnd();
@ -143,8 +147,7 @@ export abstract class Renderer {
}); });
this.addImports( this.addImports(
outputText, outputText, importManager.getAllImports(dtsFile.fileName, this.bundle.dts !.r3SymbolsFile));
importManager.getAllImports(dtsFile.fileName, this.bundle.rewriteCoreDtsImportsTo));
return this.renderSourceAndMap(dtsFile, input, outputText); return this.renderSourceAndMap(dtsFile, input, outputText);
} }
@ -337,6 +340,10 @@ export function renderDefinitions(
return definitions; return definitions;
} }
export function stripExtension(filePath: string): string {
return filePath.replace(/\.(js|d\.ts$)/, '');
}
/** /**
* Create an Angular AST statement node that contains the assignment of the * Create an Angular AST statement node that contains the assignment of the
* compiled decorator to be applied to the class. * compiled decorator to be applied to the class.

View File

@ -13,7 +13,7 @@ import {DecorationAnalyses, DecorationAnalyzer} from '../../src/analysis/decorat
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {makeProgram} from '../helpers/utils'; import {makeTestProgram} from '../helpers/utils';
const TEST_PROGRAM = { const TEST_PROGRAM = {
name: 'test.js', name: 'test.js',
@ -84,7 +84,7 @@ describe('DecorationAnalyzer', () => {
let result: DecorationAnalyses; let result: DecorationAnalyses;
beforeEach(() => { beforeEach(() => {
program = makeProgram(TEST_PROGRAM); program = makeTestProgram(TEST_PROGRAM);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const referencesRegistry = new NgccReferencesRegistry(host); const referencesRegistry = new NgccReferencesRegistry(host);
const analyzer = const analyzer =
@ -127,7 +127,7 @@ describe('DecorationAnalyzer', () => {
// is not yet solved. // is not yet solved.
it('should analyze an internally imported component, which is not publicly exported from the entry-point', it('should analyze an internally imported component, which is not publicly exported from the entry-point',
() => { () => {
const program = makeProgram(...INTERNAL_COMPONENT_PROGRAM); const program = makeTestProgram(...INTERNAL_COMPONENT_PROGRAM);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const referencesRegistry = new NgccReferencesRegistry(host); const referencesRegistry = new NgccReferencesRegistry(host);
const analyzer = new DecorationAnalyzer( const analyzer = new DecorationAnalyzer(
@ -144,7 +144,7 @@ describe('DecorationAnalyzer', () => {
}); });
it('should analyze an internally defined component, which is not exported at all', () => { it('should analyze an internally defined component, which is not exported at all', () => {
const program = makeProgram(...INTERNAL_COMPONENT_PROGRAM); const program = makeTestProgram(...INTERNAL_COMPONENT_PROGRAM);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const referencesRegistry = new NgccReferencesRegistry(host); const referencesRegistry = new NgccReferencesRegistry(host);
const analyzer = const analyzer =

View File

@ -9,7 +9,7 @@ import * as ts from 'typescript';
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {makeProgram} from '../helpers/utils'; import {makeTestProgram} from '../helpers/utils';
const TEST_PROGRAM = [ const TEST_PROGRAM = [
{ {
@ -46,7 +46,7 @@ const TEST_PROGRAM = [
describe('SwitchMarkerAnalyzer', () => { describe('SwitchMarkerAnalyzer', () => {
describe('analyzeProgram()', () => { describe('analyzeProgram()', () => {
it('should check for switchable markers in all the files of the program', () => { it('should check for switchable markers in all the files of the program', () => {
const program = makeProgram(...TEST_PROGRAM); const program = makeTestProgram(...TEST_PROGRAM);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const analyzer = new SwitchMarkerAnalyzer(host); const analyzer = new SwitchMarkerAnalyzer(host);
const analysis = analyzer.analyzeProgram(program); const analysis = analyzer.analyzeProgram(program);

View File

@ -6,12 +6,48 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import * as ts from 'typescript'; import * as ts from 'typescript';
import {makeProgram as _makeProgram} from '../../../ngtsc/testing/in_memory_typescript';
import {makeProgram} from '../../../ngtsc/testing/in_memory_typescript';
import {BundleProgram} from '../../src/packages/bundle_program';
import {EntryPointFormat} from '../../src/packages/entry_point';
import {EntryPointBundle} from '../../src/packages/entry_point_bundle';
export {getDeclaration} from '../../../ngtsc/testing/in_memory_typescript'; export {getDeclaration} from '../../../ngtsc/testing/in_memory_typescript';
export function makeProgram(...files: {name: string, contents: string}[]): ts.Program {
return _makeProgram([getFakeCore(), getFakeTslib(), ...files], {allowJs: true, checkJs: false}) /**
*
* @param format The format of the bundle.
* @param files The source files to include in the bundle.
* @param dtsFiles The typings files to include the bundle.
*/
export function makeTestEntryPointBundle(
format: EntryPointFormat, files: {name: string, contents: string, isRoot?: boolean}[],
dtsFiles?: {name: string, contents: string, isRoot?: boolean}[]): EntryPointBundle {
const src = makeTestBundleProgram(files);
const dts = dtsFiles ? makeTestBundleProgram(dtsFiles) : null;
const isFlat = src.r3SymbolsFile === null;
return {format, rootDirs: ['/'], src, dts, isFlat};
}
/**
* Create a bundle program for testing.
* @param files The source files of the bundle program.
*/
export function makeTestBundleProgram(files: {name: string, contents: string}[]): BundleProgram {
const program = makeTestProgram(...files);
const path = files[0].name;
const file = program.getSourceFile(path) !;
const r3SymbolsInfo = files.find(file => file.name.indexOf('r3_symbols') !== -1) || null;
const r3SymbolsPath = r3SymbolsInfo && r3SymbolsInfo.name;
const r3SymbolsFile = r3SymbolsPath && program.getSourceFile(r3SymbolsPath) || null;
return {program, path, file, r3SymbolsPath, r3SymbolsFile};
}
export function makeTestProgram(
...files: {name: string, contents: string, isRoot?: boolean | undefined}[]): ts.Program {
return makeProgram([getFakeCore(), getFakeTslib(), ...files], {allowJs: true, checkJs: false})
.program; .program;
} }

View File

@ -10,7 +10,7 @@ import * as ts from 'typescript';
import {ClassMemberKind, Import} from '../../../ngtsc/host'; import {ClassMemberKind, Import} from '../../../ngtsc/host';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {convertToDirectTsLibImport, getDeclaration, makeProgram} from '../helpers/utils'; import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils';
const FILES = [ const FILES = [
{ {
@ -103,7 +103,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
describe('getDecoratorsOfDeclaration()', () => { describe('getDecoratorsOfDeclaration()', () => {
it('should find the decorators on a class', () => { it('should find the decorators on a class', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -127,7 +127,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
{from: '@angular/core', name: 'Directive'} : {from: '@angular/core', name: 'Directive'} :
{}); {});
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -142,7 +142,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
}); });
it('should support decorators being used inside @angular/core', () => { it('should support decorators being used inside @angular/core', () => {
const program = makeProgram(fileSystem.files[1]); const program = makeTestProgram(fileSystem.files[1]);
const host = new Esm2015ReflectionHost(true, program.getTypeChecker()); const host = new Esm2015ReflectionHost(true, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/node_modules/@angular/core/some_directive.js', 'SomeDirective', program, '/node_modules/@angular/core/some_directive.js', 'SomeDirective',
@ -163,7 +163,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
describe('getMembersOfClass()', () => { describe('getMembersOfClass()', () => {
it('should find decorated members on a class', () => { it('should find decorated members on a class', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -181,7 +181,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
}); });
it('should find non decorated properties on a class', () => { it('should find non decorated properties on a class', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -195,7 +195,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
}); });
it('should find static methods on a class', () => { it('should find static methods on a class', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -208,7 +208,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
}); });
it('should find static properties on a class', () => { it('should find static properties on a class', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -225,7 +225,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
const spy = const spy =
spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier').and.returnValue({}); spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier').and.returnValue({});
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -236,7 +236,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
}); });
it('should support decorators being used inside @angular/core', () => { it('should support decorators being used inside @angular/core', () => {
const program = makeProgram(fileSystem.files[1]); const program = makeTestProgram(fileSystem.files[1]);
const host = new Esm2015ReflectionHost(true, program.getTypeChecker()); const host = new Esm2015ReflectionHost(true, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/node_modules/@angular/core/some_directive.js', 'SomeDirective', program, '/node_modules/@angular/core/some_directive.js', 'SomeDirective',
@ -252,7 +252,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
describe('getConstructorParameters', () => { describe('getConstructorParameters', () => {
it('should find the decorated constructor parameters', () => { it('should find the decorated constructor parameters', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -273,7 +273,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
const spy = spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier') const spy = spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo); .and.returnValue(mockImportInfo);
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -291,7 +291,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
describe('getDeclarationOfIdentifier', () => { describe('getDeclarationOfIdentifier', () => {
it('should return the declaration of a locally defined identifier', () => { it('should return the declaration of a locally defined identifier', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -307,7 +307,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
}); });
it('should return the declaration of an externally defined identifier', () => { it('should return the declaration of an externally defined identifier', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -330,7 +330,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
describe('getVariableValue', () => { describe('getVariableValue', () => {
it('should find the "actual" declaration of an aliased variable identifier', () => { it('should find the "actual" declaration of an aliased variable identifier', () => {
const program = makeProgram(fileSystem.files[2]); const program = makeTestProgram(fileSystem.files[2]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const ngModuleRef = findVariableDeclaration( const ngModuleRef = findVariableDeclaration(
program.getSourceFile(fileSystem.files[2].name) !, 'HttpClientXsrfModule_1'); program.getSourceFile(fileSystem.files[2].name) !, 'HttpClientXsrfModule_1');
@ -345,7 +345,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
}); });
it('should return null if the variable has no assignment', () => { it('should return null if the variable has no assignment', () => {
const program = makeProgram(fileSystem.files[2]); const program = makeTestProgram(fileSystem.files[2]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const missingValue = findVariableDeclaration( const missingValue = findVariableDeclaration(
program.getSourceFile(fileSystem.files[2].name) !, 'missingValue'); program.getSourceFile(fileSystem.files[2].name) !, 'missingValue');
@ -354,7 +354,7 @@ describe('Fesm2015ReflectionHost [import helper style]', () => {
}); });
it('should return null if the variable is not assigned from a call to __decorate', () => { it('should return null if the variable is not assigned from a call to __decorate', () => {
const program = makeProgram(fileSystem.files[2]); const program = makeTestProgram(fileSystem.files[2]);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const nonDecoratedVar = findVariableDeclaration( const nonDecoratedVar = findVariableDeclaration(
program.getSourceFile(fileSystem.files[2].name) !, 'nonDecoratedVar'); program.getSourceFile(fileSystem.files[2].name) !, 'nonDecoratedVar');

View File

@ -7,9 +7,10 @@
*/ */
import * as ts from 'typescript'; import * as ts from 'typescript';
import {ClassMemberKind, Import} from '../../../ngtsc/host'; import {ClassMemberKind, Import} from '../../../ngtsc/host';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {getDeclaration, makeProgram} from '../helpers/utils'; import {getDeclaration, makeTestBundleProgram, makeTestProgram} from '../helpers/utils';
const SOME_DIRECTIVE_FILE = { const SOME_DIRECTIVE_FILE = {
name: '/some_directive.js', name: '/some_directive.js',
@ -486,7 +487,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('getDecoratorsOfDeclaration()', () => { describe('getDecoratorsOfDeclaration()', () => {
it('should find the decorators on a class', () => { it('should find the decorators on a class', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration); getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration);
@ -504,7 +505,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should return null if the symbol is not a class', () => { it('should return null if the symbol is not a class', () => {
const program = makeProgram(FOO_FUNCTION_FILE); const program = makeTestProgram(FOO_FUNCTION_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const functionNode = const functionNode =
getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration); getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration);
@ -513,7 +514,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should return null if there are no decorators', () => { it('should return null if there are no decorators', () => {
const program = makeProgram(SIMPLE_CLASS_FILE); const program = makeTestProgram(SIMPLE_CLASS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isClassDeclaration); getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isClassDeclaration);
@ -522,7 +523,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore `decorators` if it is not an array literal', () => { it('should ignore `decorators` if it is not an array literal', () => {
const program = makeProgram(INVALID_DECORATORS_FILE); const program = makeTestProgram(INVALID_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATORS_FILE.name, 'NotArrayLiteral', ts.isClassDeclaration); program, INVALID_DECORATORS_FILE.name, 'NotArrayLiteral', ts.isClassDeclaration);
@ -531,7 +532,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore decorator elements that are not object literals', () => { it('should ignore decorator elements that are not object literals', () => {
const program = makeProgram(INVALID_DECORATORS_FILE); const program = makeTestProgram(INVALID_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATORS_FILE.name, 'NotObjectLiteral', ts.isClassDeclaration); program, INVALID_DECORATORS_FILE.name, 'NotObjectLiteral', ts.isClassDeclaration);
@ -542,7 +543,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore decorator elements that have no `type` property', () => { it('should ignore decorator elements that have no `type` property', () => {
const program = makeProgram(INVALID_DECORATORS_FILE); const program = makeTestProgram(INVALID_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATORS_FILE.name, 'NoTypeProperty', ts.isClassDeclaration); program, INVALID_DECORATORS_FILE.name, 'NoTypeProperty', ts.isClassDeclaration);
@ -553,7 +554,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore decorator elements whose `type` value is not an identifier', () => { it('should ignore decorator elements whose `type` value is not an identifier', () => {
const program = makeProgram(INVALID_DECORATORS_FILE); const program = makeTestProgram(INVALID_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATORS_FILE.name, 'NotIdentifier', ts.isClassDeclaration); program, INVALID_DECORATORS_FILE.name, 'NotIdentifier', ts.isClassDeclaration);
@ -568,7 +569,7 @@ describe('Fesm2015ReflectionHost', () => {
const spy = spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier') const spy = spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo); .and.returnValue(mockImportInfo);
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration); getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration);
@ -583,7 +584,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('(returned decorators `args`)', () => { describe('(returned decorators `args`)', () => {
it('should be an empty array if decorator has no `args` property', () => { it('should be an empty array if decorator has no `args` property', () => {
const program = makeProgram(INVALID_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_DECORATOR_ARGS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', ts.isClassDeclaration); program, INVALID_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', ts.isClassDeclaration);
@ -595,7 +596,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should be an empty array if decorator\'s `args` has no property assignment', () => { it('should be an empty array if decorator\'s `args` has no property assignment', () => {
const program = makeProgram(INVALID_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_DECORATOR_ARGS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', program, INVALID_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment',
@ -608,7 +609,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should be an empty array if `args` property value is not an array literal', () => { it('should be an empty array if `args` property value is not an array literal', () => {
const program = makeProgram(INVALID_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_DECORATOR_ARGS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', ts.isClassDeclaration); program, INVALID_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', ts.isClassDeclaration);
@ -623,7 +624,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('getMembersOfClass()', () => { describe('getMembersOfClass()', () => {
it('should find decorated properties on a class', () => { it('should find decorated properties on a class', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration); getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration);
@ -641,7 +642,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should find non decorated properties on a class', () => { it('should find non decorated properties on a class', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration); getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration);
@ -655,7 +656,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should find static methods on a class', () => { it('should find static methods on a class', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration); getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration);
@ -668,7 +669,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should find static properties on a class', () => { it('should find static properties on a class', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration); getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration);
@ -682,7 +683,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should throw if the symbol is not a class', () => { it('should throw if the symbol is not a class', () => {
const program = makeProgram(FOO_FUNCTION_FILE); const program = makeTestProgram(FOO_FUNCTION_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const functionNode = const functionNode =
getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration); getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration);
@ -692,7 +693,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should return an empty array if there are no prop decorators', () => { it('should return an empty array if there are no prop decorators', () => {
const program = makeProgram(SIMPLE_CLASS_FILE); const program = makeTestProgram(SIMPLE_CLASS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isClassDeclaration); getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isClassDeclaration);
@ -703,7 +704,7 @@ describe('Fesm2015ReflectionHost', () => {
it('should not process decorated properties in `propDecorators` if it is not an object literal', it('should not process decorated properties in `propDecorators` if it is not an object literal',
() => { () => {
const program = makeProgram(INVALID_PROP_DECORATORS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteral', ts.isClassDeclaration); program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteral', ts.isClassDeclaration);
@ -713,7 +714,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore prop decorator elements that are not object literals', () => { it('should ignore prop decorator elements that are not object literals', () => {
const program = makeProgram(INVALID_PROP_DECORATORS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteralProp', program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteralProp',
@ -727,7 +728,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore prop decorator elements that have no `type` property', () => { it('should ignore prop decorator elements that have no `type` property', () => {
const program = makeProgram(INVALID_PROP_DECORATORS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATORS_FILE.name, 'NoTypeProperty', ts.isClassDeclaration); program, INVALID_PROP_DECORATORS_FILE.name, 'NoTypeProperty', ts.isClassDeclaration);
@ -740,7 +741,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore prop decorator elements whose `type` value is not an identifier', () => { it('should ignore prop decorator elements whose `type` value is not an identifier', () => {
const program = makeProgram(INVALID_PROP_DECORATORS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATORS_FILE.name, 'NotIdentifier', ts.isClassDeclaration); program, INVALID_PROP_DECORATORS_FILE.name, 'NotIdentifier', ts.isClassDeclaration);
@ -760,7 +761,7 @@ describe('Fesm2015ReflectionHost', () => {
return {name: `name${callCount}`, from: '@angular/core'}; return {name: `name${callCount}`, from: '@angular/core'};
}); });
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration); getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration);
@ -782,7 +783,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('(returned prop decorators `args`)', () => { describe('(returned prop decorators `args`)', () => {
it('should be an empty array if prop decorator has no `args` property', () => { it('should be an empty array if prop decorator has no `args` property', () => {
const program = makeProgram(INVALID_PROP_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATOR_ARGS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoArgsProperty',
@ -797,7 +798,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should be an empty array if prop decorator\'s `args` has no property assignment', () => { it('should be an empty array if prop decorator\'s `args` has no property assignment', () => {
const program = makeProgram(INVALID_PROP_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATOR_ARGS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment',
@ -812,7 +813,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should be an empty array if `args` property value is not an array literal', () => { it('should be an empty array if `args` property value is not an array literal', () => {
const program = makeProgram(INVALID_PROP_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATOR_ARGS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral',
@ -830,7 +831,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('getConstructorParameters()', () => { describe('getConstructorParameters()', () => {
it('should find the decorated constructor parameters', () => { it('should find the decorated constructor parameters', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration); getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration);
@ -846,7 +847,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should throw if the symbol is not a class', () => { it('should throw if the symbol is not a class', () => {
const program = makeProgram(FOO_FUNCTION_FILE); const program = makeTestProgram(FOO_FUNCTION_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const functionNode = const functionNode =
getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration); getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration);
@ -856,7 +857,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should return `null` if there is no constructor', () => { it('should return `null` if there is no constructor', () => {
const program = makeProgram(SIMPLE_CLASS_FILE); const program = makeTestProgram(SIMPLE_CLASS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isClassDeclaration); getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isClassDeclaration);
@ -865,7 +866,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should return an array even if there are no decorators', () => { it('should return an array even if there are no decorators', () => {
const program = makeProgram(SIMPLE_CLASS_FILE); const program = makeTestProgram(SIMPLE_CLASS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SIMPLE_CLASS_FILE.name, 'NoDecoratorConstructorClass', ts.isClassDeclaration); program, SIMPLE_CLASS_FILE.name, 'NoDecoratorConstructorClass', ts.isClassDeclaration);
@ -878,7 +879,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should return an empty array if there are no constructor parameters', () => { it('should return an empty array if there are no constructor parameters', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NoParameters', ts.isClassDeclaration); program, INVALID_CTOR_DECORATORS_FILE.name, 'NoParameters', ts.isClassDeclaration);
@ -888,7 +889,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore decorators that are not imported from core', () => { it('should ignore decorators that are not imported from core', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NotFromCore', ts.isClassDeclaration); program, INVALID_CTOR_DECORATORS_FILE.name, 'NotFromCore', ts.isClassDeclaration);
@ -902,7 +903,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore `ctorParameters` if it is not an arrow function', () => { it('should ignore `ctorParameters` if it is not an arrow function', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NotArrowFunction', ts.isClassDeclaration); program, INVALID_CTOR_DECORATORS_FILE.name, 'NotArrowFunction', ts.isClassDeclaration);
@ -916,7 +917,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore `ctorParameters` if it does not return an array literal', () => { it('should ignore `ctorParameters` if it does not return an array literal', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NotArrayLiteral', ts.isClassDeclaration); program, INVALID_CTOR_DECORATORS_FILE.name, 'NotArrayLiteral', ts.isClassDeclaration);
@ -931,7 +932,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('(returned parameters `decorators`)', () => { describe('(returned parameters `decorators`)', () => {
it('should ignore param decorator elements that are not object literals', () => { it('should ignore param decorator elements that are not object literals', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NotObjectLiteral', ts.isClassDeclaration); program, INVALID_CTOR_DECORATORS_FILE.name, 'NotObjectLiteral', ts.isClassDeclaration);
@ -949,7 +950,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore param decorator elements that have no `type` property', () => { it('should ignore param decorator elements that have no `type` property', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NoTypeProperty', ts.isClassDeclaration); program, INVALID_CTOR_DECORATORS_FILE.name, 'NoTypeProperty', ts.isClassDeclaration);
@ -961,7 +962,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should ignore param decorator elements whose `type` value is not an identifier', () => { it('should ignore param decorator elements whose `type` value is not an identifier', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NotIdentifier', ts.isClassDeclaration); program, INVALID_CTOR_DECORATORS_FILE.name, 'NotIdentifier', ts.isClassDeclaration);
@ -977,7 +978,7 @@ describe('Fesm2015ReflectionHost', () => {
const spy = spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier') const spy = spyOn(Esm2015ReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo); .and.returnValue(mockImportInfo);
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration);
@ -994,7 +995,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('(returned parameters `decorators.args`)', () => { describe('(returned parameters `decorators.args`)', () => {
it('should be an empty array if param decorator has no `args` property', () => { it('should be an empty array if param decorator has no `args` property', () => {
const program = makeProgram(INVALID_CTOR_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATOR_ARGS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoArgsProperty',
@ -1009,7 +1010,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should be an empty array if param decorator\'s `args` has no property assignment', () => { it('should be an empty array if param decorator\'s `args` has no property assignment', () => {
const program = makeProgram(INVALID_CTOR_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATOR_ARGS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment',
@ -1023,7 +1024,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should be an empty array if `args` property value is not an array literal', () => { it('should be an empty array if `args` property value is not an array literal', () => {
const program = makeProgram(INVALID_CTOR_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATOR_ARGS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral',
@ -1040,7 +1041,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('getDefinitionOfFunction()', () => { describe('getDefinitionOfFunction()', () => {
it('should return an object describing the function declaration passed as an argument', () => { it('should return an object describing the function declaration passed as an argument', () => {
const program = makeProgram(FUNCTION_BODY_FILE); const program = makeTestProgram(FUNCTION_BODY_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const fooNode = const fooNode =
@ -1102,7 +1103,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('getImportOfIdentifier()', () => { describe('getImportOfIdentifier()', () => {
it('should find the import of an identifier', () => { it('should find the import of an identifier', () => {
const program = makeProgram(...IMPORTS_FILES); const program = makeTestProgram(...IMPORTS_FILES);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const variableNode = const variableNode =
getDeclaration(program, IMPORTS_FILES[1].name, 'b', ts.isVariableDeclaration); getDeclaration(program, IMPORTS_FILES[1].name, 'b', ts.isVariableDeclaration);
@ -1112,7 +1113,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should find the name by which the identifier was exported, not imported', () => { it('should find the name by which the identifier was exported, not imported', () => {
const program = makeProgram(...IMPORTS_FILES); const program = makeTestProgram(...IMPORTS_FILES);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const variableNode = const variableNode =
getDeclaration(program, IMPORTS_FILES[1].name, 'c', ts.isVariableDeclaration); getDeclaration(program, IMPORTS_FILES[1].name, 'c', ts.isVariableDeclaration);
@ -1122,7 +1123,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should return null if the identifier was not imported', () => { it('should return null if the identifier was not imported', () => {
const program = makeProgram(...IMPORTS_FILES); const program = makeTestProgram(...IMPORTS_FILES);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const variableNode = const variableNode =
getDeclaration(program, IMPORTS_FILES[1].name, 'd', ts.isVariableDeclaration); getDeclaration(program, IMPORTS_FILES[1].name, 'd', ts.isVariableDeclaration);
@ -1134,7 +1135,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('getDeclarationOfIdentifier()', () => { describe('getDeclarationOfIdentifier()', () => {
it('should return the declaration of a locally defined identifier', () => { it('should return the declaration of a locally defined identifier', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration); getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration);
@ -1150,7 +1151,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should return the declaration of an externally defined identifier', () => { it('should return the declaration of an externally defined identifier', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration); getDeclaration(program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isClassDeclaration);
@ -1170,7 +1171,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('getExportsOfModule()', () => { describe('getExportsOfModule()', () => {
it('should return a map of all the exports from a given module', () => { it('should return a map of all the exports from a given module', () => {
const program = makeProgram(...EXPORTS_FILES); const program = makeTestProgram(...EXPORTS_FILES);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const file = program.getSourceFile(EXPORTS_FILES[1].name) !; const file = program.getSourceFile(EXPORTS_FILES[1].name) !;
const exportDeclarations = host.getExportsOfModule(file); const exportDeclarations = host.getExportsOfModule(file);
@ -1205,7 +1206,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('isClass()', () => { describe('isClass()', () => {
it('should return true if a given node is a TS class declaration', () => { it('should return true if a given node is a TS class declaration', () => {
const program = makeProgram(SIMPLE_CLASS_FILE); const program = makeTestProgram(SIMPLE_CLASS_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const node = const node =
getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isClassDeclaration); getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isClassDeclaration);
@ -1213,7 +1214,7 @@ describe('Fesm2015ReflectionHost', () => {
}); });
it('should return false if a given node is a TS function declaration', () => { it('should return false if a given node is a TS function declaration', () => {
const program = makeProgram(FOO_FUNCTION_FILE); const program = makeTestProgram(FOO_FUNCTION_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const node = getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration); const node = getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration);
expect(host.isClass(node)).toBe(false); expect(host.isClass(node)).toBe(false);
@ -1222,10 +1223,10 @@ describe('Fesm2015ReflectionHost', () => {
describe('getGenericArityOfClass()', () => { describe('getGenericArityOfClass()', () => {
it('should properly count type parameters', () => { it('should properly count type parameters', () => {
const dtsProgram = makeProgram(ARITY_CLASSES[1]); const program = makeTestProgram(ARITY_CLASSES[0]);
const program = makeProgram(ARITY_CLASSES[0]); const dtsProgram = makeTestProgram(ARITY_CLASSES[1]);
const host = new Esm2015ReflectionHost( const dts = makeTestBundleProgram([ARITY_CLASSES[1]]);
false, program.getTypeChecker(), ARITY_CLASSES[1].name, dtsProgram); const host = new Esm2015ReflectionHost(false, program.getTypeChecker(), dts);
const noTypeParamClass = const noTypeParamClass =
getDeclaration(program, '/src/class.js', 'NoTypeParam', ts.isClassDeclaration); getDeclaration(program, '/src/class.js', 'NoTypeParam', ts.isClassDeclaration);
expect(host.getGenericArityOfClass(noTypeParamClass)).toBe(0); expect(host.getGenericArityOfClass(noTypeParamClass)).toBe(0);
@ -1241,7 +1242,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('getSwitchableDeclarations()', () => { describe('getSwitchableDeclarations()', () => {
it('should return a collection of all the switchable variable declarations in the given module', it('should return a collection of all the switchable variable declarations in the given module',
() => { () => {
const program = makeProgram(MARKER_FILE); const program = makeTestProgram(MARKER_FILE);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const file = program.getSourceFile(MARKER_FILE.name) !; const file = program.getSourceFile(MARKER_FILE.name) !;
const declarations = host.getSwitchableDeclarations(file); const declarations = host.getSwitchableDeclarations(file);
@ -1253,7 +1254,7 @@ describe('Fesm2015ReflectionHost', () => {
describe('findDecoratedClasses()', () => { describe('findDecoratedClasses()', () => {
it('should return an array of all decorated classes in the given source file', () => { it('should return an array of all decorated classes in the given source file', () => {
const program = makeProgram(...DECORATED_FILES); const program = makeTestProgram(...DECORATED_FILES);
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, program.getTypeChecker());
const primaryFile = program.getSourceFile(DECORATED_FILES[0].name) !; const primaryFile = program.getSourceFile(DECORATED_FILES[0].name) !;
const secondaryFile = program.getSourceFile(DECORATED_FILES[1].name) !; const secondaryFile = program.getSourceFile(DECORATED_FILES[1].name) !;
@ -1280,58 +1281,53 @@ describe('Fesm2015ReflectionHost', () => {
describe('getDtsDeclarationsOfClass()', () => { describe('getDtsDeclarationsOfClass()', () => {
it('should find the dts declaration that has the same relative path to the source file', () => { it('should find the dts declaration that has the same relative path to the source file', () => {
const srcProgram = makeProgram(...TYPINGS_SRC_FILES); const srcProgram = makeTestProgram(...TYPINGS_SRC_FILES);
const dtsProgram = makeProgram(...TYPINGS_DTS_FILES); const dts = makeTestBundleProgram(TYPINGS_DTS_FILES);
const class1 = getDeclaration(srcProgram, '/src/class1.js', 'Class1', ts.isClassDeclaration); const class1 = getDeclaration(srcProgram, '/src/class1.js', 'Class1', ts.isClassDeclaration);
const host = new Esm2015ReflectionHost( const host = new Esm2015ReflectionHost(false, srcProgram.getTypeChecker(), dts);
false, srcProgram.getTypeChecker(), TYPINGS_DTS_FILES[0].name, dtsProgram);
const dtsDeclaration = host.getDtsDeclarationOfClass(class1); const dtsDeclaration = host.getDtsDeclarationOfClass(class1);
expect(dtsDeclaration !.getSourceFile().fileName).toEqual('/typings/class1.d.ts'); expect(dtsDeclaration !.getSourceFile().fileName).toEqual('/typings/class1.d.ts');
}); });
it('should return null if there is no matching class in the matching dts file', () => { it('should return null if there is no matching class in the matching dts file', () => {
const srcProgram = makeProgram(...TYPINGS_SRC_FILES); const srcProgram = makeTestProgram(...TYPINGS_SRC_FILES);
const dtsProgram = makeProgram(...TYPINGS_DTS_FILES); const dts = makeTestBundleProgram(TYPINGS_DTS_FILES);
const missingClass = const missingClass =
getDeclaration(srcProgram, '/src/class1.js', 'MissingClass1', ts.isClassDeclaration); getDeclaration(srcProgram, '/src/class1.js', 'MissingClass1', ts.isClassDeclaration);
const host = new Esm2015ReflectionHost( const host = new Esm2015ReflectionHost(false, srcProgram.getTypeChecker(), dts);
false, srcProgram.getTypeChecker(), TYPINGS_DTS_FILES[0].name, dtsProgram);
expect(host.getDtsDeclarationOfClass(missingClass)).toBe(null); expect(host.getDtsDeclarationOfClass(missingClass)).toBe(null);
}); });
it('should return null if there is no matching dts file', () => { it('should return null if there is no matching dts file', () => {
const srcProgram = makeProgram(...TYPINGS_SRC_FILES); const srcProgram = makeTestProgram(...TYPINGS_SRC_FILES);
const dtsProgram = makeProgram(...TYPINGS_DTS_FILES); const dts = makeTestBundleProgram(TYPINGS_DTS_FILES);
const missingClass = getDeclaration( const missingClass = getDeclaration(
srcProgram, '/src/missing-class.js', 'MissingClass2', ts.isClassDeclaration); srcProgram, '/src/missing-class.js', 'MissingClass2', ts.isClassDeclaration);
const host = new Esm2015ReflectionHost( const host = new Esm2015ReflectionHost(false, srcProgram.getTypeChecker(), dts);
false, srcProgram.getTypeChecker(), TYPINGS_DTS_FILES[0].name, dtsProgram);
expect(host.getDtsDeclarationOfClass(missingClass)).toBe(null); expect(host.getDtsDeclarationOfClass(missingClass)).toBe(null);
}); });
it('should find the dts file that contains a matching class declaration, even if the source files do not match', it('should find the dts file that contains a matching class declaration, even if the source files do not match',
() => { () => {
const srcProgram = makeProgram(...TYPINGS_SRC_FILES); const srcProgram = makeTestProgram(...TYPINGS_SRC_FILES);
const dtsProgram = makeProgram(...TYPINGS_DTS_FILES); const dts = makeTestBundleProgram(TYPINGS_DTS_FILES);
const class1 = const class1 =
getDeclaration(srcProgram, '/src/flat-file.js', 'Class1', ts.isClassDeclaration); getDeclaration(srcProgram, '/src/flat-file.js', 'Class1', ts.isClassDeclaration);
const host = new Esm2015ReflectionHost( const host = new Esm2015ReflectionHost(false, srcProgram.getTypeChecker(), dts);
false, srcProgram.getTypeChecker(), TYPINGS_DTS_FILES[0].name, dtsProgram);
const dtsDeclaration = host.getDtsDeclarationOfClass(class1); const dtsDeclaration = host.getDtsDeclarationOfClass(class1);
expect(dtsDeclaration !.getSourceFile().fileName).toEqual('/typings/class1.d.ts'); expect(dtsDeclaration !.getSourceFile().fileName).toEqual('/typings/class1.d.ts');
}); });
it('should find aliased exports', () => { it('should find aliased exports', () => {
const srcProgram = makeProgram(...TYPINGS_SRC_FILES); const srcProgram = makeTestProgram(...TYPINGS_SRC_FILES);
const dtsProgram = makeProgram(...TYPINGS_DTS_FILES); const dts = makeTestBundleProgram(TYPINGS_DTS_FILES);
const class3 = const class3 =
getDeclaration(srcProgram, '/src/flat-file.js', 'Class3', ts.isClassDeclaration); getDeclaration(srcProgram, '/src/flat-file.js', 'Class3', ts.isClassDeclaration);
const host = new Esm2015ReflectionHost( const host = new Esm2015ReflectionHost(false, srcProgram.getTypeChecker(), dts);
false, srcProgram.getTypeChecker(), TYPINGS_DTS_FILES[0].name, dtsProgram);
const dtsDeclaration = host.getDtsDeclarationOfClass(class3); const dtsDeclaration = host.getDtsDeclarationOfClass(class3);
expect(dtsDeclaration !.getSourceFile().fileName).toEqual('/typings/class3.d.ts'); expect(dtsDeclaration !.getSourceFile().fileName).toEqual('/typings/class3.d.ts');
@ -1339,12 +1335,11 @@ describe('Fesm2015ReflectionHost', () => {
it('should find the dts file that contains a matching class declaration, even if the class is not publicly exported', it('should find the dts file that contains a matching class declaration, even if the class is not publicly exported',
() => { () => {
const srcProgram = makeProgram(...TYPINGS_SRC_FILES); const srcProgram = makeTestProgram(...TYPINGS_SRC_FILES);
const dtsProgram = makeProgram(...TYPINGS_DTS_FILES); const dts = makeTestBundleProgram(TYPINGS_DTS_FILES);
const internalClass = const internalClass =
getDeclaration(srcProgram, '/src/internal.js', 'InternalClass', ts.isClassDeclaration); getDeclaration(srcProgram, '/src/internal.js', 'InternalClass', ts.isClassDeclaration);
const host = new Esm2015ReflectionHost( const host = new Esm2015ReflectionHost(false, srcProgram.getTypeChecker(), dts);
false, srcProgram.getTypeChecker(), TYPINGS_DTS_FILES[0].name, dtsProgram);
const dtsDeclaration = host.getDtsDeclarationOfClass(internalClass); const dtsDeclaration = host.getDtsDeclarationOfClass(internalClass);
expect(dtsDeclaration !.getSourceFile().fileName).toEqual('/typings/internal.d.ts'); expect(dtsDeclaration !.getSourceFile().fileName).toEqual('/typings/internal.d.ts');
@ -1352,14 +1347,13 @@ describe('Fesm2015ReflectionHost', () => {
it('should prefer the publicly exported class if there are multiple classes with the same name', it('should prefer the publicly exported class if there are multiple classes with the same name',
() => { () => {
const srcProgram = makeProgram(...TYPINGS_SRC_FILES); const srcProgram = makeTestProgram(...TYPINGS_SRC_FILES);
const dtsProgram = makeProgram(...TYPINGS_DTS_FILES); const dts = makeTestBundleProgram(TYPINGS_DTS_FILES);
const class2 = const class2 =
getDeclaration(srcProgram, '/src/class2.js', 'Class2', ts.isClassDeclaration); getDeclaration(srcProgram, '/src/class2.js', 'Class2', ts.isClassDeclaration);
const internalClass2 = const internalClass2 =
getDeclaration(srcProgram, '/src/internal.js', 'Class2', ts.isClassDeclaration); getDeclaration(srcProgram, '/src/internal.js', 'Class2', ts.isClassDeclaration);
const host = new Esm2015ReflectionHost( const host = new Esm2015ReflectionHost(false, srcProgram.getTypeChecker(), dts);
false, srcProgram.getTypeChecker(), TYPINGS_DTS_FILES[0].name, dtsProgram);
const class2DtsDeclaration = host.getDtsDeclarationOfClass(class2); const class2DtsDeclaration = host.getDtsDeclarationOfClass(class2);
expect(class2DtsDeclaration !.getSourceFile().fileName).toEqual('/typings/class2.d.ts'); expect(class2DtsDeclaration !.getSourceFile().fileName).toEqual('/typings/class2.d.ts');

View File

@ -10,7 +10,7 @@ import * as ts from 'typescript';
import {ClassMemberKind, Import} from '../../../ngtsc/host'; import {ClassMemberKind, Import} from '../../../ngtsc/host';
import {Esm5ReflectionHost} from '../../src/host/esm5_host'; import {Esm5ReflectionHost} from '../../src/host/esm5_host';
import {convertToDirectTsLibImport, getDeclaration, makeProgram} from '../helpers/utils'; import {convertToDirectTsLibImport, getDeclaration, makeTestProgram} from '../helpers/utils';
const FILES = [ const FILES = [
{ {
@ -118,7 +118,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
describe('getDecoratorsOfDeclaration()', () => { describe('getDecoratorsOfDeclaration()', () => {
it('should find the decorators on a class', () => { it('should find the decorators on a class', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -142,7 +142,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
{from: '@angular/core', name: 'Directive'} : {from: '@angular/core', name: 'Directive'} :
{}); {});
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -157,7 +157,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
}); });
it('should support decorators being used inside @angular/core', () => { it('should support decorators being used inside @angular/core', () => {
const program = makeProgram(fileSystem.files[1]); const program = makeTestProgram(fileSystem.files[1]);
const host = new Esm5ReflectionHost(true, program.getTypeChecker()); const host = new Esm5ReflectionHost(true, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/node_modules/@angular/core/some_directive.js', 'SomeDirective', program, '/node_modules/@angular/core/some_directive.js', 'SomeDirective',
@ -178,7 +178,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
describe('getMembersOfClass()', () => { describe('getMembersOfClass()', () => {
it('should find decorated members on a class', () => { it('should find decorated members on a class', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -196,7 +196,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
}); });
it('should find non decorated properties on a class', () => { it('should find non decorated properties on a class', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -210,7 +210,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
}); });
it('should find static methods on a class', () => { it('should find static methods on a class', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -223,7 +223,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
}); });
it('should find static properties on a class', () => { it('should find static properties on a class', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -240,7 +240,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
const spy = const spy =
spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier').and.returnValue({}); spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier').and.returnValue({});
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -251,7 +251,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
}); });
it('should support decorators being used inside @angular/core', () => { it('should support decorators being used inside @angular/core', () => {
const program = makeProgram(fileSystem.files[1]); const program = makeTestProgram(fileSystem.files[1]);
const host = new Esm5ReflectionHost(true, program.getTypeChecker()); const host = new Esm5ReflectionHost(true, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/node_modules/@angular/core/some_directive.js', 'SomeDirective', program, '/node_modules/@angular/core/some_directive.js', 'SomeDirective',
@ -267,7 +267,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
describe('getConstructorParameters', () => { describe('getConstructorParameters', () => {
it('should find the decorated constructor parameters', () => { it('should find the decorated constructor parameters', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -288,7 +288,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
const spy = spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier') const spy = spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo); .and.returnValue(mockImportInfo);
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -306,7 +306,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
describe('getDeclarationOfIdentifier', () => { describe('getDeclarationOfIdentifier', () => {
it('should return the declaration of a locally defined identifier', () => { it('should return the declaration of a locally defined identifier', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -322,7 +322,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
}); });
it('should return the declaration of an externally defined identifier', () => { it('should return the declaration of an externally defined identifier', () => {
const program = makeProgram(fileSystem.files[0]); const program = makeTestProgram(fileSystem.files[0]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration); program, '/some_directive.js', 'SomeDirective', ts.isVariableDeclaration);
@ -347,7 +347,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
describe('getVariableValue', () => { describe('getVariableValue', () => {
it('should find the "actual" declaration of an aliased variable identifier', () => { it('should find the "actual" declaration of an aliased variable identifier', () => {
const program = makeProgram(fileSystem.files[2]); const program = makeTestProgram(fileSystem.files[2]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const ngModuleRef = findVariableDeclaration( const ngModuleRef = findVariableDeclaration(
program.getSourceFile(fileSystem.files[2].name) !, 'HttpClientXsrfModule_1'); program.getSourceFile(fileSystem.files[2].name) !, 'HttpClientXsrfModule_1');
@ -362,7 +362,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
}); });
it('should return undefined if the variable has no assignment', () => { it('should return undefined if the variable has no assignment', () => {
const program = makeProgram(fileSystem.files[2]); const program = makeTestProgram(fileSystem.files[2]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const missingValue = findVariableDeclaration( const missingValue = findVariableDeclaration(
program.getSourceFile(fileSystem.files[2].name) !, 'missingValue'); program.getSourceFile(fileSystem.files[2].name) !, 'missingValue');
@ -371,7 +371,7 @@ describe('Esm5ReflectionHost [import helper style]', () => {
}); });
it('should return null if the variable is not assigned from a call to __decorate', () => { it('should return null if the variable is not assigned from a call to __decorate', () => {
const program = makeProgram(fileSystem.files[2]); const program = makeTestProgram(fileSystem.files[2]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const nonDecoratedVar = findVariableDeclaration( const nonDecoratedVar = findVariableDeclaration(
program.getSourceFile(fileSystem.files[2].name) !, 'nonDecoratedVar'); program.getSourceFile(fileSystem.files[2].name) !, 'nonDecoratedVar');

View File

@ -11,7 +11,7 @@ import * as ts from 'typescript';
import {ClassMemberKind, Import} from '../../../ngtsc/host'; import {ClassMemberKind, Import} from '../../../ngtsc/host';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {Esm5ReflectionHost} from '../../src/host/esm5_host'; import {Esm5ReflectionHost} from '../../src/host/esm5_host';
import {getDeclaration, makeProgram} from '../helpers/utils'; import {getDeclaration, makeTestProgram} from '../helpers/utils';
const SOME_DIRECTIVE_FILE = { const SOME_DIRECTIVE_FILE = {
name: '/some_directive.js', name: '/some_directive.js',
@ -476,7 +476,7 @@ describe('Esm5ReflectionHost', () => {
describe('getDecoratorsOfDeclaration()', () => { describe('getDecoratorsOfDeclaration()', () => {
it('should find the decorators on a class', () => { it('should find the decorators on a class', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration);
@ -494,7 +494,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should return null if the symbol is not a class', () => { it('should return null if the symbol is not a class', () => {
const program = makeProgram(FOO_FUNCTION_FILE); const program = makeTestProgram(FOO_FUNCTION_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const functionNode = const functionNode =
getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration); getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration);
@ -503,7 +503,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should return null if there are no decorators', () => { it('should return null if there are no decorators', () => {
const program = makeProgram(SIMPLE_CLASS_FILE); const program = makeTestProgram(SIMPLE_CLASS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration);
@ -512,7 +512,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should ignore `decorators` if it is not an array literal', () => { it('should ignore `decorators` if it is not an array literal', () => {
const program = makeProgram(INVALID_DECORATORS_FILE); const program = makeTestProgram(INVALID_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATORS_FILE.name, 'NotArrayLiteral', ts.isVariableDeclaration); program, INVALID_DECORATORS_FILE.name, 'NotArrayLiteral', ts.isVariableDeclaration);
@ -521,7 +521,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should ignore decorator elements that are not object literals', () => { it('should ignore decorator elements that are not object literals', () => {
const program = makeProgram(INVALID_DECORATORS_FILE); const program = makeTestProgram(INVALID_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATORS_FILE.name, 'NotObjectLiteral', ts.isVariableDeclaration); program, INVALID_DECORATORS_FILE.name, 'NotObjectLiteral', ts.isVariableDeclaration);
@ -532,7 +532,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should ignore decorator elements that have no `type` property', () => { it('should ignore decorator elements that have no `type` property', () => {
const program = makeProgram(INVALID_DECORATORS_FILE); const program = makeTestProgram(INVALID_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATORS_FILE.name, 'NoTypeProperty', ts.isVariableDeclaration); program, INVALID_DECORATORS_FILE.name, 'NoTypeProperty', ts.isVariableDeclaration);
@ -543,7 +543,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should ignore decorator elements whose `type` value is not an identifier', () => { it('should ignore decorator elements whose `type` value is not an identifier', () => {
const program = makeProgram(INVALID_DECORATORS_FILE); const program = makeTestProgram(INVALID_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATORS_FILE.name, 'NotIdentifier', ts.isVariableDeclaration); program, INVALID_DECORATORS_FILE.name, 'NotIdentifier', ts.isVariableDeclaration);
@ -558,7 +558,7 @@ describe('Esm5ReflectionHost', () => {
const spy = spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier') const spy = spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo); .and.returnValue(mockImportInfo);
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration);
@ -573,7 +573,7 @@ describe('Esm5ReflectionHost', () => {
describe('(returned decorators `args`)', () => { describe('(returned decorators `args`)', () => {
it('should be an empty array if decorator has no `args` property', () => { it('should be an empty array if decorator has no `args` property', () => {
const program = makeProgram(INVALID_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_DECORATOR_ARGS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', ts.isVariableDeclaration); program, INVALID_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', ts.isVariableDeclaration);
@ -585,7 +585,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should be an empty array if decorator\'s `args` has no property assignment', () => { it('should be an empty array if decorator\'s `args` has no property assignment', () => {
const program = makeProgram(INVALID_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_DECORATOR_ARGS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', program, INVALID_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment',
@ -598,7 +598,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should be an empty array if `args` property value is not an array literal', () => { it('should be an empty array if `args` property value is not an array literal', () => {
const program = makeProgram(INVALID_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_DECORATOR_ARGS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', ts.isVariableDeclaration); program, INVALID_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', ts.isVariableDeclaration);
@ -613,7 +613,7 @@ describe('Esm5ReflectionHost', () => {
describe('getMembersOfClass()', () => { describe('getMembersOfClass()', () => {
it('should find decorated members on a class', () => { it('should find decorated members on a class', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration);
@ -631,7 +631,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should find non decorated properties on a class', () => { it('should find non decorated properties on a class', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration);
@ -645,7 +645,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should find static methods on a class', () => { it('should find static methods on a class', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration);
@ -658,7 +658,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should find static properties on a class', () => { it('should find static properties on a class', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration);
@ -672,7 +672,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should throw if the symbol is not a class', () => { it('should throw if the symbol is not a class', () => {
const program = makeProgram(FOO_FUNCTION_FILE); const program = makeTestProgram(FOO_FUNCTION_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const functionNode = const functionNode =
getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration); getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration);
@ -682,7 +682,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should return an empty array if there are no prop decorators', () => { it('should return an empty array if there are no prop decorators', () => {
const program = makeProgram(SIMPLE_CLASS_FILE); const program = makeTestProgram(SIMPLE_CLASS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = const classNode =
getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration);
@ -693,7 +693,7 @@ describe('Esm5ReflectionHost', () => {
it('should not process decorated properties in `propDecorators` if it is not an object literal', it('should not process decorated properties in `propDecorators` if it is not an object literal',
() => { () => {
const program = makeProgram(INVALID_PROP_DECORATORS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteral', program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteral',
@ -704,7 +704,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should ignore prop decorator elements that are not object literals', () => { it('should ignore prop decorator elements that are not object literals', () => {
const program = makeProgram(INVALID_PROP_DECORATORS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteralProp', program, INVALID_PROP_DECORATORS_FILE.name, 'NotObjectLiteralProp',
@ -718,7 +718,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should ignore prop decorator elements that have no `type` property', () => { it('should ignore prop decorator elements that have no `type` property', () => {
const program = makeProgram(INVALID_PROP_DECORATORS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATORS_FILE.name, 'NoTypeProperty', ts.isVariableDeclaration); program, INVALID_PROP_DECORATORS_FILE.name, 'NoTypeProperty', ts.isVariableDeclaration);
@ -731,7 +731,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should ignore prop decorator elements whose `type` value is not an identifier', () => { it('should ignore prop decorator elements whose `type` value is not an identifier', () => {
const program = makeProgram(INVALID_PROP_DECORATORS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATORS_FILE.name, 'NotIdentifier', ts.isVariableDeclaration); program, INVALID_PROP_DECORATORS_FILE.name, 'NotIdentifier', ts.isVariableDeclaration);
@ -750,7 +750,7 @@ describe('Esm5ReflectionHost', () => {
return {name: `name${callCount}`, from: `@angular/core`}; return {name: `name${callCount}`, from: `@angular/core`};
}); });
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration);
@ -766,7 +766,7 @@ describe('Esm5ReflectionHost', () => {
describe('(returned prop decorators `args`)', () => { describe('(returned prop decorators `args`)', () => {
it('should be an empty array if prop decorator has no `args` property', () => { it('should be an empty array if prop decorator has no `args` property', () => {
const program = makeProgram(INVALID_PROP_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATOR_ARGS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoArgsProperty',
@ -781,7 +781,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should be an empty array if prop decorator\'s `args` has no property assignment', () => { it('should be an empty array if prop decorator\'s `args` has no property assignment', () => {
const program = makeProgram(INVALID_PROP_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATOR_ARGS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment',
@ -796,7 +796,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should be an empty array if `args` property value is not an array literal', () => { it('should be an empty array if `args` property value is not an array literal', () => {
const program = makeProgram(INVALID_PROP_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_PROP_DECORATOR_ARGS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', program, INVALID_PROP_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral',
@ -814,7 +814,7 @@ describe('Esm5ReflectionHost', () => {
describe('getConstructorParameters', () => { describe('getConstructorParameters', () => {
it('should find the decorated constructor parameters', () => { it('should find the decorated constructor parameters', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration);
@ -830,7 +830,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should throw if the symbol is not a class', () => { it('should throw if the symbol is not a class', () => {
const program = makeProgram(FOO_FUNCTION_FILE); const program = makeTestProgram(FOO_FUNCTION_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const functionNode = const functionNode =
getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration); getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration);
@ -843,7 +843,7 @@ describe('Esm5ReflectionHost', () => {
// it('should return `null` if there is no constructor', () => { }); // it('should return `null` if there is no constructor', () => { });
it('should return an array even if there are no decorators', () => { it('should return an array even if there are no decorators', () => {
const program = makeProgram(SIMPLE_CLASS_FILE); const program = makeTestProgram(SIMPLE_CLASS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SIMPLE_CLASS_FILE.name, 'NoDecoratorConstructorClass', ts.isVariableDeclaration); program, SIMPLE_CLASS_FILE.name, 'NoDecoratorConstructorClass', ts.isVariableDeclaration);
@ -856,7 +856,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should return an empty array if there are no constructor parameters', () => { it('should return an empty array if there are no constructor parameters', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NoParameters', ts.isVariableDeclaration); program, INVALID_CTOR_DECORATORS_FILE.name, 'NoParameters', ts.isVariableDeclaration);
@ -869,7 +869,7 @@ describe('Esm5ReflectionHost', () => {
// it('should ignore `ctorParameters` if it is an arrow function', () => { }); // it('should ignore `ctorParameters` if it is an arrow function', () => { });
it('should ignore `ctorParameters` if it does not return an array literal', () => { it('should ignore `ctorParameters` if it does not return an array literal', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NotArrayLiteral', ts.isVariableDeclaration); program, INVALID_CTOR_DECORATORS_FILE.name, 'NotArrayLiteral', ts.isVariableDeclaration);
@ -884,7 +884,7 @@ describe('Esm5ReflectionHost', () => {
describe('(returned parameters `decorators`)', () => { describe('(returned parameters `decorators`)', () => {
it('should ignore param decorator elements that are not object literals', () => { it('should ignore param decorator elements that are not object literals', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NotObjectLiteral', program, INVALID_CTOR_DECORATORS_FILE.name, 'NotObjectLiteral',
@ -903,7 +903,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should ignore param decorator elements that have no `type` property', () => { it('should ignore param decorator elements that have no `type` property', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NoTypeProperty', ts.isVariableDeclaration); program, INVALID_CTOR_DECORATORS_FILE.name, 'NoTypeProperty', ts.isVariableDeclaration);
@ -915,7 +915,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should ignore param decorator elements whose `type` value is not an identifier', () => { it('should ignore param decorator elements whose `type` value is not an identifier', () => {
const program = makeProgram(INVALID_CTOR_DECORATORS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATORS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATORS_FILE.name, 'NotIdentifier', ts.isVariableDeclaration); program, INVALID_CTOR_DECORATORS_FILE.name, 'NotIdentifier', ts.isVariableDeclaration);
@ -931,7 +931,7 @@ describe('Esm5ReflectionHost', () => {
const spy = spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier') const spy = spyOn(Esm5ReflectionHost.prototype, 'getImportOfIdentifier')
.and.returnValue(mockImportInfo); .and.returnValue(mockImportInfo);
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration);
@ -948,7 +948,7 @@ describe('Esm5ReflectionHost', () => {
describe('(returned parameters `decorators.args`)', () => { describe('(returned parameters `decorators.args`)', () => {
it('should be an empty array if param decorator has no `args` property', () => { it('should be an empty array if param decorator has no `args` property', () => {
const program = makeProgram(INVALID_CTOR_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATOR_ARGS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoArgsProperty', program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoArgsProperty',
@ -963,7 +963,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should be an empty array if param decorator\'s `args` has no property assignment', () => { it('should be an empty array if param decorator\'s `args` has no property assignment', () => {
const program = makeProgram(INVALID_CTOR_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATOR_ARGS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment', program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NoPropertyAssignment',
@ -977,7 +977,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should be an empty array if `args` property value is not an array literal', () => { it('should be an empty array if `args` property value is not an array literal', () => {
const program = makeProgram(INVALID_CTOR_DECORATOR_ARGS_FILE); const program = makeTestProgram(INVALID_CTOR_DECORATOR_ARGS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral', program, INVALID_CTOR_DECORATOR_ARGS_FILE.name, 'NotArrayLiteral',
@ -994,7 +994,7 @@ describe('Esm5ReflectionHost', () => {
describe('getDefinitionOfFunction()', () => { describe('getDefinitionOfFunction()', () => {
it('should return an object describing the function declaration passed as an argument', () => { it('should return an object describing the function declaration passed as an argument', () => {
const program = makeProgram(FUNCTION_BODY_FILE); const program = makeTestProgram(FUNCTION_BODY_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const fooNode = const fooNode =
@ -1042,7 +1042,7 @@ describe('Esm5ReflectionHost', () => {
describe('getImportOfIdentifier', () => { describe('getImportOfIdentifier', () => {
it('should find the import of an identifier', () => { it('should find the import of an identifier', () => {
const program = makeProgram(...IMPORTS_FILES); const program = makeTestProgram(...IMPORTS_FILES);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const variableNode = const variableNode =
getDeclaration(program, IMPORTS_FILES[1].name, 'b', ts.isVariableDeclaration); getDeclaration(program, IMPORTS_FILES[1].name, 'b', ts.isVariableDeclaration);
@ -1052,7 +1052,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should find the name by which the identifier was exported, not imported', () => { it('should find the name by which the identifier was exported, not imported', () => {
const program = makeProgram(...IMPORTS_FILES); const program = makeTestProgram(...IMPORTS_FILES);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const variableNode = const variableNode =
getDeclaration(program, IMPORTS_FILES[1].name, 'c', ts.isVariableDeclaration); getDeclaration(program, IMPORTS_FILES[1].name, 'c', ts.isVariableDeclaration);
@ -1062,7 +1062,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should return null if the identifier was not imported', () => { it('should return null if the identifier was not imported', () => {
const program = makeProgram(...IMPORTS_FILES); const program = makeTestProgram(...IMPORTS_FILES);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const variableNode = const variableNode =
getDeclaration(program, IMPORTS_FILES[1].name, 'd', ts.isVariableDeclaration); getDeclaration(program, IMPORTS_FILES[1].name, 'd', ts.isVariableDeclaration);
@ -1074,7 +1074,7 @@ describe('Esm5ReflectionHost', () => {
describe('getDeclarationOfIdentifier', () => { describe('getDeclarationOfIdentifier', () => {
it('should return the declaration of a locally defined identifier', () => { it('should return the declaration of a locally defined identifier', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration);
@ -1090,7 +1090,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should return the declaration of an externally defined identifier', () => { it('should return the declaration of an externally defined identifier', () => {
const program = makeProgram(SOME_DIRECTIVE_FILE); const program = makeTestProgram(SOME_DIRECTIVE_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const classNode = getDeclaration( const classNode = getDeclaration(
program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration); program, SOME_DIRECTIVE_FILE.name, 'SomeDirective', ts.isVariableDeclaration);
@ -1110,7 +1110,7 @@ describe('Esm5ReflectionHost', () => {
describe('getExportsOfModule()', () => { describe('getExportsOfModule()', () => {
it('should return a map of all the exports from a given module', () => { it('should return a map of all the exports from a given module', () => {
const program = makeProgram(...EXPORTS_FILES); const program = makeTestProgram(...EXPORTS_FILES);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const file = program.getSourceFile(EXPORTS_FILES[1].name) !; const file = program.getSourceFile(EXPORTS_FILES[1].name) !;
const exportDeclarations = host.getExportsOfModule(file); const exportDeclarations = host.getExportsOfModule(file);
@ -1168,7 +1168,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should return the class symbol for an ES5 class (outer variable declaration)', () => { it('should return the class symbol for an ES5 class (outer variable declaration)', () => {
const program = makeProgram(SIMPLE_CLASS_FILE); const program = makeTestProgram(SIMPLE_CLASS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const node = const node =
getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration);
@ -1176,7 +1176,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should return the class symbol for an ES5 class (inner function declaration)', () => { it('should return the class symbol for an ES5 class (inner function declaration)', () => {
const program = makeProgram(SIMPLE_CLASS_FILE); const program = makeTestProgram(SIMPLE_CLASS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const outerNode = const outerNode =
getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); getDeclaration(program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration);
@ -1190,7 +1190,7 @@ describe('Esm5ReflectionHost', () => {
it('should return the same class symbol (of the inner declaration) for outer and inner declarations', it('should return the same class symbol (of the inner declaration) for outer and inner declarations',
() => { () => {
const program = makeProgram(SIMPLE_CLASS_FILE); const program = makeTestProgram(SIMPLE_CLASS_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const outerNode = getDeclaration( const outerNode = getDeclaration(
program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration); program, SIMPLE_CLASS_FILE.name, 'EmptyClass', ts.isVariableDeclaration);
@ -1204,7 +1204,7 @@ describe('Esm5ReflectionHost', () => {
}); });
it('should return undefined if node is not an ES5 class', () => { it('should return undefined if node is not an ES5 class', () => {
const program = makeProgram(FOO_FUNCTION_FILE); const program = makeTestProgram(FOO_FUNCTION_FILE);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const node = getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration); const node = getDeclaration(program, FOO_FUNCTION_FILE.name, 'foo', ts.isFunctionDeclaration);
expect(host.getClassSymbol(node)).toBeUndefined(); expect(host.getClassSymbol(node)).toBeUndefined();
@ -1254,7 +1254,7 @@ describe('Esm5ReflectionHost', () => {
describe('findDecoratedClasses()', () => { describe('findDecoratedClasses()', () => {
it('should return an array of all decorated classes in the given source file', () => { it('should return an array of all decorated classes in the given source file', () => {
const program = makeProgram(...DECORATED_FILES); const program = makeTestProgram(...DECORATED_FILES);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const host = new Esm5ReflectionHost(false, program.getTypeChecker());
const primary = program.getSourceFile(DECORATED_FILES[0].name) !; const primary = program.getSourceFile(DECORATED_FILES[0].name) !;

View File

@ -7,30 +7,35 @@
*/ */
import {dirname} from 'canonical-path'; import {dirname} from 'canonical-path';
import * as ts from 'typescript'; import * as ts from 'typescript';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import {makeProgram} from '../helpers/utils';
import {makeTestEntryPointBundle} from '../helpers/utils';
import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
import {createBundleInfo} from '../../src/packages/bundle';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {EsmRenderer} from '../../src/rendering/esm_renderer'; import {EsmRenderer} from '../../src/rendering/esm_renderer';
function setup(file: {name: string, contents: string}, transformDts: boolean = false) { function setup(file: {name: string, contents: string}) {
const dir = dirname(file.name); const dir = dirname(file.name);
const program = makeProgram(file); const bundle = makeTestEntryPointBundle('esm2015', [file]) !;
const sourceFile = program.getSourceFile(file.name) !; const typeChecker = bundle.src.program.getTypeChecker();
const host = new Esm2015ReflectionHost(false, program.getTypeChecker()); const host = new Esm2015ReflectionHost(false, typeChecker);
const referencesRegistry = new NgccReferencesRegistry(host);
const decorationAnalyses = const decorationAnalyses =
new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program); new DecorationAnalyzer(typeChecker, host, referencesRegistry, [''], false)
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program); .analyzeProgram(bundle.src.program);
const bundle = createBundleInfo(false, null, null); const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program);
const renderer = new EsmRenderer(host, bundle, dir, dir, false); const renderer = new EsmRenderer(host, false, bundle, dir, dir);
return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses}; return {
host,
program: bundle.src.program,
sourceFile: bundle.src.file, renderer, decorationAnalyses, switchMarkerAnalyses
};
} }
const PROGRAM = { const PROGRAM = {
name: 'some/file.js', name: '/some/file.js',
contents: ` contents: `
/* A copyright notice */ /* A copyright notice */
import {Directive} from '@angular/core'; import {Directive} from '@angular/core';
@ -65,7 +70,7 @@ function compileNgModuleFactory__POST_R3__(injector, options, moduleType) {
}; };
const PROGRAM_DECORATE_HELPER = { const PROGRAM_DECORATE_HELPER = {
name: 'some/file.js', name: '/some/file.js',
contents: ` contents: `
import * as tslib_1 from "tslib"; import * as tslib_1 from "tslib";
var D_1; var D_1;

View File

@ -5,29 +5,37 @@
* Use of this source code is governed by an MIT-style license that can be * 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 * found in the LICENSE file at https://angular.io/license
*/ */
import * as ts from 'typescript'; import {dirname} from 'canonical-path';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import {makeProgram, getDeclaration} from '../helpers/utils'; import * as ts from 'typescript';
import {makeTestEntryPointBundle, getDeclaration} from '../helpers/utils';
import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
import {createBundleInfo} from '../../src/packages/bundle';
import {Esm5ReflectionHost} from '../../src/host/esm5_host'; import {Esm5ReflectionHost} from '../../src/host/esm5_host';
import {Esm5Renderer} from '../../src/rendering/esm5_renderer'; import {Esm5Renderer} from '../../src/rendering/esm5_renderer';
function setup(file: {name: string, contents: string}) { function setup(file: {name: string, contents: string}) {
const program = makeProgram(file); const dir = dirname(file.name);
const sourceFile = program.getSourceFile(file.name) !; const bundle = makeTestEntryPointBundle('esm5', [file]);
const host = new Esm5ReflectionHost(false, program.getTypeChecker()); const typeChecker = bundle.src.program.getTypeChecker();
const host = new Esm5ReflectionHost(false, typeChecker);
const referencesRegistry = new NgccReferencesRegistry(host);
const decorationAnalyses = const decorationAnalyses =
new DecorationAnalyzer(program.getTypeChecker(), host, [''], false).analyzeProgram(program); new DecorationAnalyzer(typeChecker, host, referencesRegistry, [''], false)
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program); .analyzeProgram(bundle.src.program);
const bundle = createBundleInfo(false, null, null); const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program);
const renderer = new Esm5Renderer(host, bundle, '', '', false); const renderer = new Esm5Renderer(host, false, bundle, dir, dir);
return {host, program, sourceFile, renderer, decorationAnalyses, switchMarkerAnalyses}; return {
host,
program: bundle.src.program,
sourceFile: bundle.src.file, renderer, decorationAnalyses, switchMarkerAnalyses
};
} }
const PROGRAM = { const PROGRAM = {
name: 'some/file.js', name: '/some/file.js',
contents: ` contents: `
/* A copyright notice */ /* A copyright notice */
import {Directive} from '@angular/core'; import {Directive} from '@angular/core';
@ -86,7 +94,7 @@ export {A, B, C, NoIife, BadIife};`
}; };
const PROGRAM_DECORATE_HELPER = { const PROGRAM_DECORATE_HELPER = {
name: 'some/file.js', name: '/some/file.js',
contents: ` contents: `
import * as tslib_1 from "tslib"; import * as tslib_1 from "tslib";
/* A copyright notice */ /* A copyright notice */

View File

@ -6,21 +6,21 @@
* found in the LICENSE file at https://angular.io/license * found in the LICENSE file at https://angular.io/license
*/ */
import * as fs from 'fs'; import * as fs from 'fs';
import * as ts from 'typescript';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import * as ts from 'typescript';
import {fromObject, generateMapFileComment} from 'convert-source-map'; import {fromObject, generateMapFileComment} from 'convert-source-map';
import {makeProgram} from '../helpers/utils';
import {CompiledClass, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer'; import {CompiledClass, DecorationAnalyzer} from '../../src/analysis/decoration_analyzer';
import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry'; import {NgccReferencesRegistry} from '../../src/analysis/ngcc_references_registry';
import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer'; import {SwitchMarkerAnalyzer} from '../../src/analysis/switch_marker_analyzer';
import {BundleInfo, createBundleInfo} from '../../src/packages/bundle';
import {Esm2015ReflectionHost} from '../../src/host/esm2015_host'; import {Esm2015ReflectionHost} from '../../src/host/esm2015_host';
import {Renderer} from '../../src/rendering/renderer'; import {Renderer} from '../../src/rendering/renderer';
import {EntryPoint} from '../../src/packages/entry_point';
import {EntryPointBundle} from '../../src/packages/entry_point_bundle';
import {makeTestEntryPointBundle} from '../helpers/utils';
class TestRenderer extends Renderer { class TestRenderer extends Renderer {
constructor(host: Esm2015ReflectionHost, bundle: BundleInfo) { constructor(host: Esm2015ReflectionHost, isCore: boolean, bundle: EntryPointBundle) {
super(host, bundle, '/src', '/dist', false); super(host, isCore, bundle, '/src', '/dist');
} }
addImports(output: MagicString, imports: {name: string, as: string}[]) { addImports(output: MagicString, imports: {name: string, as: string}[]) {
output.prepend('\n// ADD IMPORTS\n'); output.prepend('\n// ADD IMPORTS\n');
@ -40,25 +40,23 @@ class TestRenderer extends Renderer {
} }
function createTestRenderer( function createTestRenderer(
files: {name: string, contents: string}[], packageName: string, files: {name: string, contents: string}[],
options: {isCore?: boolean, rewriteCoreImportsTo?: string} = {}) { dtsFile?: {name: string, contents: string}) {
const program = makeProgram(...files); const isCore = packageName === '@angular/core';
const rewriteCoreImportsTo = const bundle = makeTestEntryPointBundle('esm2015', files, dtsFile && [dtsFile]);
options.rewriteCoreImportsTo ? program.getSourceFile(options.rewriteCoreImportsTo) ! : null; const typeChecker = bundle.src.program.getTypeChecker();
const bundle = createBundleInfo(options.isCore || false, rewriteCoreImportsTo, null); const host = new Esm2015ReflectionHost(isCore, typeChecker, bundle.dts);
const host = new Esm2015ReflectionHost(bundle.isCore, program.getTypeChecker());
const referencesRegistry = new NgccReferencesRegistry(host); const referencesRegistry = new NgccReferencesRegistry(host);
const decorationAnalyses = const decorationAnalyses =
new DecorationAnalyzer( new DecorationAnalyzer(typeChecker, host, referencesRegistry, bundle.rootDirs, isCore)
program.getTypeChecker(), host, referencesRegistry, [''], bundle.isCore) .analyzeProgram(bundle.src.program);
.analyzeProgram(program); const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(bundle.src.program);
const switchMarkerAnalyses = new SwitchMarkerAnalyzer(host).analyzeProgram(program); const renderer = new TestRenderer(host, isCore, bundle);
const renderer = new TestRenderer(host, bundle);
spyOn(renderer, 'addImports').and.callThrough(); spyOn(renderer, 'addImports').and.callThrough();
spyOn(renderer, 'addDefinitions').and.callThrough(); spyOn(renderer, 'addDefinitions').and.callThrough();
spyOn(renderer, 'removeDecorators').and.callThrough(); spyOn(renderer, 'removeDecorators').and.callThrough();
return {renderer, program, decorationAnalyses, switchMarkerAnalyses}; return {renderer, decorationAnalyses, switchMarkerAnalyses};
} }
@ -68,6 +66,10 @@ describe('Renderer', () => {
contents: contents:
`import { Directive } from '@angular/core';\nexport class A {\n foo(x) {\n return x;\n }\n}\nA.decorators = [\n { type: Directive, args: [{ selector: '[a]' }] }\n];\n` `import { Directive } from '@angular/core';\nexport class A {\n foo(x) {\n return x;\n }\n}\nA.decorators = [\n { type: Directive, args: [{ selector: '[a]' }] }\n];\n`
}; };
const INPUT_DTS_PROGRAM = {
name: '/typings/file.d.ts',
contents: `export declare class A {\nfoo(x: number): number;\n}\n`
};
const INPUT_PROGRAM_MAP = fromObject({ const INPUT_PROGRAM_MAP = fromObject({
'version': 3, 'version': 3,
@ -105,9 +107,9 @@ describe('Renderer', () => {
describe('renderProgram()', () => { describe('renderProgram()', () => {
it('should render the modified contents; and a new map file, if the original provided no map file.', it('should render the modified contents; and a new map file, if the original provided no map file.',
() => { () => {
const {renderer, program, decorationAnalyses, switchMarkerAnalyses} = const {renderer, decorationAnalyses, switchMarkerAnalyses} =
createTestRenderer([INPUT_PROGRAM]); createTestRenderer('test-package', [INPUT_PROGRAM]);
const result = renderer.renderProgram(program, decorationAnalyses, switchMarkerAnalyses); const result = renderer.renderProgram(decorationAnalyses, switchMarkerAnalyses);
expect(result[0].path).toEqual('/dist/file.js'); expect(result[0].path).toEqual('/dist/file.js');
expect(result[0].contents) expect(result[0].contents)
.toEqual(RENDERED_CONTENTS + '\n' + generateMapFileComment('/dist/file.js.map')); .toEqual(RENDERED_CONTENTS + '\n' + generateMapFileComment('/dist/file.js.map'));
@ -115,104 +117,111 @@ describe('Renderer', () => {
expect(result[1].contents).toEqual(OUTPUT_PROGRAM_MAP.toJSON()); expect(result[1].contents).toEqual(OUTPUT_PROGRAM_MAP.toJSON());
}); });
it('should call addImports with the source code and info about the core Angular library.', describe('calling abstract methods', () => {
() => { it('should call addImports with the source code and info about the core Angular library.',
const {decorationAnalyses, program, renderer, switchMarkerAnalyses} = () => {
createTestRenderer([INPUT_PROGRAM]); const {decorationAnalyses, renderer, switchMarkerAnalyses} =
renderer.renderProgram(program, decorationAnalyses, switchMarkerAnalyses); createTestRenderer('test-package', [INPUT_PROGRAM]);
const addImportsSpy = renderer.addImports as jasmine.Spy; renderer.renderProgram(decorationAnalyses, switchMarkerAnalyses);
expect(addImportsSpy.calls.first().args[0].toString()).toEqual(RENDERED_CONTENTS); const addImportsSpy = renderer.addImports as jasmine.Spy;
expect(addImportsSpy.calls.first().args[1]).toEqual([ expect(addImportsSpy.calls.first().args[0].toString()).toEqual(RENDERED_CONTENTS);
{name: '@angular/core', as: 'ɵngcc0'} expect(addImportsSpy.calls.first().args[1]).toEqual([
]); {name: '@angular/core', as: 'ɵngcc0'}
}); ]);
});
it('should call addDefinitions with the source code, the analyzed class and the renderered definitions.', it('should call addDefinitions with the source code, the analyzed class and the rendered definitions.',
() => { () => {
const {decorationAnalyses, program, renderer, switchMarkerAnalyses} = const {decorationAnalyses, renderer, switchMarkerAnalyses} =
createTestRenderer([INPUT_PROGRAM]); createTestRenderer('test-package', [INPUT_PROGRAM]);
renderer.renderProgram(program, decorationAnalyses, switchMarkerAnalyses); renderer.renderProgram(decorationAnalyses, switchMarkerAnalyses);
const addDefinitionsSpy = renderer.addDefinitions as jasmine.Spy; const addDefinitionsSpy = renderer.addDefinitions as jasmine.Spy;
expect(addDefinitionsSpy.calls.first().args[0].toString()).toEqual(RENDERED_CONTENTS); expect(addDefinitionsSpy.calls.first().args[0].toString()).toEqual(RENDERED_CONTENTS);
expect(addDefinitionsSpy.calls.first().args[1]).toEqual(jasmine.objectContaining({ expect(addDefinitionsSpy.calls.first().args[1]).toEqual(jasmine.objectContaining({
name: 'A', name: 'A',
decorators: [jasmine.objectContaining({name: 'Directive'})], decorators: [jasmine.objectContaining({name: 'Directive'})],
})); }));
expect(addDefinitionsSpy.calls.first().args[2]) expect(addDefinitionsSpy.calls.first().args[2])
.toEqual(`/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{ .toEqual(`/*@__PURE__*/ ɵngcc0.ɵsetClassMetadata(A, [{
type: Directive, type: Directive,
args: [{ selector: '[a]' }] args: [{ selector: '[a]' }]
}], null, { foo: [] }); }], null, { foo: [] });
A.ngDirectiveDef = ɵngcc0.ɵdefineDirective({ type: A, selectors: [["", "a", ""]], factory: function A_Factory(t) { return new (t || A)(); } });`); A.ngDirectiveDef = ɵngcc0.ɵdefineDirective({ type: A, selectors: [["", "a", ""]], factory: function A_Factory(t) { return new (t || A)(); } });`);
}); });
it('should call removeDecorators with the source code, a map of class decorators that have been analyzed', it('should call removeDecorators with the source code, a map of class decorators that have been analyzed',
() => { () => {
const {decorationAnalyses, program, renderer, switchMarkerAnalyses} = const {decorationAnalyses, renderer, switchMarkerAnalyses} =
createTestRenderer([INPUT_PROGRAM]); createTestRenderer('test-package', [INPUT_PROGRAM]);
renderer.renderProgram(program, decorationAnalyses, switchMarkerAnalyses); renderer.renderProgram(decorationAnalyses, switchMarkerAnalyses);
const removeDecoratorsSpy = renderer.removeDecorators as jasmine.Spy; const removeDecoratorsSpy = renderer.removeDecorators as jasmine.Spy;
expect(removeDecoratorsSpy.calls.first().args[0].toString()).toEqual(RENDERED_CONTENTS); expect(removeDecoratorsSpy.calls.first().args[0].toString()).toEqual(RENDERED_CONTENTS);
// Each map key is the TS node of the decorator container // Each map key is the TS node of the decorator container
// Each map value is an array of TS nodes that are the decorators to remove // Each map value is an array of TS nodes that are the decorators to remove
const map = removeDecoratorsSpy.calls.first().args[1] as Map<ts.Node, ts.Node[]>; const map = removeDecoratorsSpy.calls.first().args[1] as Map<ts.Node, ts.Node[]>;
const keys = Array.from(map.keys()); const keys = Array.from(map.keys());
expect(keys.length).toEqual(1); expect(keys.length).toEqual(1);
expect(keys[0].getText()) expect(keys[0].getText())
.toEqual(`[\n { type: Directive, args: [{ selector: '[a]' }] }\n]`); .toEqual(`[\n { type: Directive, args: [{ selector: '[a]' }] }\n]`);
const values = Array.from(map.values()); const values = Array.from(map.values());
expect(values.length).toEqual(1); expect(values.length).toEqual(1);
expect(values[0].length).toEqual(1); expect(values[0].length).toEqual(1);
expect(values[0][0].getText()).toEqual(`{ type: Directive, args: [{ selector: '[a]' }] }`); expect(values[0][0].getText())
}); .toEqual(`{ type: Directive, args: [{ selector: '[a]' }] }`);
});
});
it('should merge any inline source map from the original file and write the output as an inline source map', describe('source map merging', () => {
() => { it('should merge any inline source map from the original file and write the output as an inline source map',
const {decorationAnalyses, program, renderer, switchMarkerAnalyses} = createTestRenderer([{ () => {
...INPUT_PROGRAM, const {decorationAnalyses, renderer, switchMarkerAnalyses} = createTestRenderer(
contents: INPUT_PROGRAM.contents + '\n' + INPUT_PROGRAM_MAP.toComment() 'test-package', [{
}]); ...INPUT_PROGRAM,
const result = renderer.renderProgram(program, decorationAnalyses, switchMarkerAnalyses); contents: INPUT_PROGRAM.contents + '\n' + INPUT_PROGRAM_MAP.toComment()
expect(result[0].path).toEqual('/dist/file.js'); }]);
expect(result[0].contents) const result = renderer.renderProgram(decorationAnalyses, switchMarkerAnalyses);
.toEqual(RENDERED_CONTENTS + '\n' + MERGED_OUTPUT_PROGRAM_MAP.toComment()); expect(result[0].path).toEqual('/dist/file.js');
expect(result[1]).toBeUndefined(); expect(result[0].contents)
}); .toEqual(RENDERED_CONTENTS + '\n' + MERGED_OUTPUT_PROGRAM_MAP.toComment());
expect(result[1]).toBeUndefined();
});
it('should merge any external source map from the original file and write the output to an external source map', it('should merge any external source map from the original file and write the output to an external source map',
() => { () => {
// Mock out reading the map file from disk // Mock out reading the map file from disk
spyOn(fs, 'readFileSync').and.returnValue(INPUT_PROGRAM_MAP.toJSON()); spyOn(fs, 'readFileSync').and.returnValue(INPUT_PROGRAM_MAP.toJSON());
const {decorationAnalyses, program, renderer, switchMarkerAnalyses} = createTestRenderer([{ const {decorationAnalyses, renderer, switchMarkerAnalyses} = createTestRenderer(
...INPUT_PROGRAM, 'test-package', [{
contents: INPUT_PROGRAM.contents + '\n//# sourceMappingURL=file.js.map' ...INPUT_PROGRAM,
}]); contents: INPUT_PROGRAM.contents + '\n//# sourceMappingURL=file.js.map'
const result = renderer.renderProgram(program, decorationAnalyses, switchMarkerAnalyses); }]);
expect(result[0].path).toEqual('/dist/file.js'); const result = renderer.renderProgram(decorationAnalyses, switchMarkerAnalyses);
expect(result[0].contents) expect(result[0].path).toEqual('/dist/file.js');
.toEqual(RENDERED_CONTENTS + '\n' + generateMapFileComment('/dist/file.js.map')); expect(result[0].contents)
expect(result[1].path).toEqual('/dist/file.js.map'); .toEqual(RENDERED_CONTENTS + '\n' + generateMapFileComment('/dist/file.js.map'));
expect(result[1].contents).toEqual(MERGED_OUTPUT_PROGRAM_MAP.toJSON()); expect(result[1].path).toEqual('/dist/file.js.map');
}); expect(result[1].contents).toEqual(MERGED_OUTPUT_PROGRAM_MAP.toJSON());
});
});
describe('@angular/core support', () => { describe('@angular/core support', () => {
it('should render relative imports in ESM bundles', () => { it('should render relative imports in ESM bundles', () => {
const R3_SYMBOLS_FILE = {
name: '/src/r3_symbols.js',
contents: `export const NgModule = () => null;`
};
const CORE_FILE = { const CORE_FILE = {
name: '/src/core.js', name: '/src/core.js',
contents: contents:
`import { NgModule } from './ng_module';\nexport class MyModule {}\nMyModule.decorators = [\n { type: NgModule, args: [] }\n];\n` `import { NgModule } from './ng_module';\nexport class MyModule {}\nMyModule.decorators = [\n { type: NgModule, args: [] }\n];\n`
}; };
const R3_SYMBOLS_FILE = {
const {decorationAnalyses, program, renderer, switchMarkerAnalyses} = createTestRenderer( // r3_symbols in the file name indicates that this is the path to rewrite core imports to
[R3_SYMBOLS_FILE, CORE_FILE], name: '/src/r3_symbols.js',
{isCore: true, rewriteCoreImportsTo: R3_SYMBOLS_FILE.name}); contents: `export const NgModule = () => null;`
renderer.renderProgram(program, decorationAnalyses, switchMarkerAnalyses); };
// The package name of `@angular/core` indicates that we are compiling the core library.
const {decorationAnalyses, renderer, switchMarkerAnalyses, privateDeclarationsAnalyses} =
createTestRenderer('@angular/core', [CORE_FILE, R3_SYMBOLS_FILE]);
renderer.renderProgram(
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
const addDefinitionsSpy = renderer.addDefinitions as jasmine.Spy; const addDefinitionsSpy = renderer.addDefinitions as jasmine.Spy;
expect(addDefinitionsSpy.calls.first().args[2]) expect(addDefinitionsSpy.calls.first().args[2])
.toContain(`/*@__PURE__*/ ɵngcc0.setClassMetadata(`); .toContain(`/*@__PURE__*/ ɵngcc0.setClassMetadata(`);
@ -227,16 +236,38 @@ A.ngDirectiveDef = ɵngcc0.ɵdefineDirective({ type: A, selectors: [["", "a", ""
export class MyModule {}\nMyModule.decorators = [\n { type: NgModule, args: [] }\n];\n` export class MyModule {}\nMyModule.decorators = [\n { type: NgModule, args: [] }\n];\n`
}; };
const {decorationAnalyses, program, renderer, switchMarkerAnalyses} = const {decorationAnalyses, renderer, switchMarkerAnalyses, privateDeclarationsAnalyses} =
createTestRenderer([CORE_FILE], {isCore: true}); createTestRenderer('@angular/core', [CORE_FILE]);
renderer.renderProgram(program, decorationAnalyses, switchMarkerAnalyses); renderer.renderProgram(
decorationAnalyses, switchMarkerAnalyses, privateDeclarationsAnalyses);
const addDefinitionsSpy = renderer.addDefinitions as jasmine.Spy; const addDefinitionsSpy = renderer.addDefinitions as jasmine.Spy;
expect(addDefinitionsSpy.calls.first().args[2]) expect(addDefinitionsSpy.calls.first().args[2])
.toContain(`/*@__PURE__*/ setClassMetadata(`); .toContain(`/*@__PURE__*/ setClassMetadata(`);
const addImportsSpy = renderer.addImports as jasmine.Spy; const addImportsSpy = renderer.addImports as jasmine.Spy;
expect(addImportsSpy.calls.first().args[1]).toEqual([]); expect(addImportsSpy.calls.first().args[1]).toEqual([]);
}); });
});
describe('rendering typings', () => {
it('should render extract types into typings files', () => {
const {renderer, decorationAnalyses, switchMarkerAnalyses} =
createTestRenderer('test-package', [INPUT_PROGRAM], INPUT_DTS_PROGRAM);
const result = renderer.renderProgram(decorationAnalyses, switchMarkerAnalyses);
const typingsFile = result.find(f => f.path === '/typings/file.d.ts') !;
expect(typingsFile.contents)
.toContain(
'foo(x: number): number;\n static ngDirectiveDef: ɵngcc0.ɵDirectiveDefWithMeta');
});
it('should render imports into typings files', () => {
const {renderer, decorationAnalyses, switchMarkerAnalyses} =
createTestRenderer('test-package', [INPUT_PROGRAM], INPUT_DTS_PROGRAM);
const result = renderer.renderProgram(decorationAnalyses, switchMarkerAnalyses);
const typingsFile = result.find(f => f.path === '/typings/file.d.ts') !;
expect(typingsFile.contents).toContain(`// ADD IMPORTS\nexport declare class A`);
});
}); });
}); });
}); });