Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
380377139b | |||
9c7680ef69 | |||
69572ac2f1 | |||
76f53f929c | |||
ba52f2f252 | |||
e122f6bf0f | |||
453c758d1a | |||
015ca47336 | |||
f32e287812 | |||
9946ac5cc7 | |||
593e05dc97 | |||
da77b580c9 | |||
1733ea09bd | |||
1f4fa28fac | |||
c12e56ec0c | |||
4a5c8bd25f | |||
9c954740d1 |
@ -1,3 +1,12 @@
|
|||||||
|
<a name="2.2.3"></a>
|
||||||
|
## [2.2.3](https://github.com/angular/angular/compare/2.2.2...2.2.3) (2016-11-23)
|
||||||
|
|
||||||
|
### Bug Fixes
|
||||||
|
|
||||||
|
* **compiler:** Revert: fix versions of `@angular/tsc-wrapped` ([015ca47](https://github.com/angular/angular/commit/015ca47))
|
||||||
|
* **animations:** Revert: blend in all previously transitioned styles into next animation if interrupted ([c12e56e](https://github.com/angular/angular/commit/c12e56e))
|
||||||
|
|
||||||
|
|
||||||
<a name="2.2.2"></a>
|
<a name="2.2.2"></a>
|
||||||
## [2.2.2](https://github.com/angular/angular/compare/2.2.1...2.2.2) (2016-11-22)
|
## [2.2.2](https://github.com/angular/angular/compare/2.2.1...2.2.2) (2016-11-22)
|
||||||
|
|
||||||
|
@ -50,7 +50,6 @@ module.exports = function(config) {
|
|||||||
'dist/all/@angular/**/e2e_test/**',
|
'dist/all/@angular/**/e2e_test/**',
|
||||||
'dist/all/@angular/router/**',
|
'dist/all/@angular/router/**',
|
||||||
'dist/all/@angular/compiler-cli/**',
|
'dist/all/@angular/compiler-cli/**',
|
||||||
'dist/all/@angular/compiler/test/aot/**',
|
|
||||||
'dist/all/@angular/benchpress/**',
|
'dist/all/@angular/benchpress/**',
|
||||||
'dist/all/angular1_router.js',
|
'dist/all/angular1_router.js',
|
||||||
'dist/all/@angular/platform-browser/testing/e2e_util.js',
|
'dist/all/@angular/platform-browser/testing/e2e_util.js',
|
||||||
|
@ -6,9 +6,9 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export {AotCompilerHost, AotCompilerHost as StaticReflectorHost, StaticReflector, StaticSymbol} from '@angular/compiler';
|
|
||||||
export {CodeGenerator} from './src/codegen';
|
export {CodeGenerator} from './src/codegen';
|
||||||
export {CompilerHost, CompilerHostContext, NodeCompilerHostContext} from './src/compiler_host';
|
|
||||||
export {Extractor} from './src/extractor';
|
export {Extractor} from './src/extractor';
|
||||||
|
export {NodeReflectorHostContext, ReflectorHost, ReflectorHostContext} from './src/reflector_host';
|
||||||
|
export {StaticReflector, StaticReflectorHost, StaticSymbol} from './src/static_reflector';
|
||||||
|
|
||||||
export * from '@angular/tsc-wrapped';
|
export * from '@angular/tsc-wrapped';
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"ng-xi18n": "./src/extract_i18n.js"
|
"ng-xi18n": "./src/extract_i18n.js"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@angular/tsc-wrapped": "^0.4.0",
|
"@angular/tsc-wrapped": "^0.3.0",
|
||||||
"reflect-metadata": "^0.1.2",
|
"reflect-metadata": "^0.1.2",
|
||||||
"minimist": "^1.2.0"
|
"minimist": "^1.2.0"
|
||||||
},
|
},
|
||||||
|
@ -17,9 +17,11 @@ import {readFileSync} from 'fs';
|
|||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {CompilerHost, CompilerHostContext} from './compiler_host';
|
import {PathMappedReflectorHost} from './path_mapped_reflector_host';
|
||||||
import {PathMappedCompilerHost} from './path_mapped_compiler_host';
|
|
||||||
import {Console} from './private_import_core';
|
import {Console} from './private_import_core';
|
||||||
|
import {ReflectorHost, ReflectorHostContext} from './reflector_host';
|
||||||
|
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
||||||
|
import {StaticReflector, StaticReflectorHost, StaticSymbol} from './static_reflector';
|
||||||
|
|
||||||
const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
||||||
const GENERATED_OR_DTS_FILES = /\.d\.ts$|\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
const GENERATED_OR_DTS_FILES = /\.d\.ts$|\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
||||||
@ -36,8 +38,8 @@ const PREAMBLE = `/**
|
|||||||
export class CodeGenerator {
|
export class CodeGenerator {
|
||||||
constructor(
|
constructor(
|
||||||
private options: AngularCompilerOptions, private program: ts.Program,
|
private options: AngularCompilerOptions, private program: ts.Program,
|
||||||
public host: ts.CompilerHost, private compiler: compiler.AotCompiler,
|
public host: ts.CompilerHost, private staticReflector: StaticReflector,
|
||||||
private ngCompilerHost: CompilerHost) {}
|
private compiler: compiler.OfflineCompiler, private reflectorHost: StaticReflectorHost) {}
|
||||||
|
|
||||||
// Write codegen in a directory structure matching the sources.
|
// Write codegen in a directory structure matching the sources.
|
||||||
private calculateEmitPath(filePath: string): string {
|
private calculateEmitPath(filePath: string): string {
|
||||||
@ -62,11 +64,11 @@ export class CodeGenerator {
|
|||||||
return path.join(this.options.genDir, relativePath);
|
return path.join(this.options.genDir, relativePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
codegen(): Promise<any> {
|
codegen(options: {transitiveModules: boolean}): Promise<any> {
|
||||||
return this.compiler
|
const staticSymbols =
|
||||||
.compileAll(this.program.getSourceFiles().map(
|
extractProgramSymbols(this.program, this.staticReflector, this.reflectorHost, this.options);
|
||||||
sf => this.ngCompilerHost.getCanonicalFileName(sf.fileName)))
|
|
||||||
.then(generatedModules => {
|
return this.compiler.compileModules(staticSymbols, options).then(generatedModules => {
|
||||||
generatedModules.forEach(generatedModule => {
|
generatedModules.forEach(generatedModule => {
|
||||||
const sourceFile = this.program.getSourceFile(generatedModule.fileUrl);
|
const sourceFile = this.program.getSourceFile(generatedModule.fileUrl);
|
||||||
const emitPath = this.calculateEmitPath(generatedModule.moduleUrl);
|
const emitPath = this.calculateEmitPath(generatedModule.moduleUrl);
|
||||||
@ -78,14 +80,17 @@ export class CodeGenerator {
|
|||||||
|
|
||||||
static create(
|
static create(
|
||||||
options: AngularCompilerOptions, cliOptions: NgcCliOptions, program: ts.Program,
|
options: AngularCompilerOptions, cliOptions: NgcCliOptions, program: ts.Program,
|
||||||
tsCompilerHost: ts.CompilerHost, compilerHostContext?: CompilerHostContext,
|
compilerHost: ts.CompilerHost, reflectorHostContext?: ReflectorHostContext,
|
||||||
ngCompilerHost?: CompilerHost): CodeGenerator {
|
resourceLoader?: compiler.ResourceLoader, reflectorHost?: ReflectorHost): CodeGenerator {
|
||||||
if (!ngCompilerHost) {
|
resourceLoader = resourceLoader || {
|
||||||
const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0;
|
get: (s: string) => {
|
||||||
ngCompilerHost = usePathMapping ?
|
if (!compilerHost.fileExists(s)) {
|
||||||
new PathMappedCompilerHost(program, tsCompilerHost, options, compilerHostContext) :
|
// TODO: We should really have a test for error cases like this!
|
||||||
new CompilerHost(program, tsCompilerHost, options, compilerHostContext);
|
throw new Error(`Compilation failed. Resource file not found: ${s}`);
|
||||||
}
|
}
|
||||||
|
return Promise.resolve(compilerHost.readFile(s));
|
||||||
|
}
|
||||||
|
};
|
||||||
const transFile = cliOptions.i18nFile;
|
const transFile = cliOptions.i18nFile;
|
||||||
const locale = cliOptions.locale;
|
const locale = cliOptions.locale;
|
||||||
let transContent: string = '';
|
let transContent: string = '';
|
||||||
@ -96,18 +101,84 @@ export class CodeGenerator {
|
|||||||
}
|
}
|
||||||
transContent = readFileSync(transFile, 'utf8');
|
transContent = readFileSync(transFile, 'utf8');
|
||||||
}
|
}
|
||||||
const {compiler: aotCompiler} = compiler.createAotCompiler(ngCompilerHost, {
|
|
||||||
debug: options.debug === true,
|
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
|
||||||
translations: transContent,
|
if (!reflectorHost) {
|
||||||
i18nFormat: cliOptions.i18nFormat,
|
const usePathMapping = !!options.rootDirs && options.rootDirs.length > 0;
|
||||||
locale: cliOptions.locale,
|
reflectorHost = usePathMapping ?
|
||||||
excludeFilePattern: options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES :
|
new PathMappedReflectorHost(program, compilerHost, options, reflectorHostContext) :
|
||||||
GENERATED_FILES
|
new ReflectorHost(program, compilerHost, options, reflectorHostContext);
|
||||||
|
}
|
||||||
|
const staticReflector = new StaticReflector(reflectorHost);
|
||||||
|
StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
||||||
|
const htmlParser =
|
||||||
|
new compiler.I18NHtmlParser(new compiler.HtmlParser(), transContent, cliOptions.i18nFormat);
|
||||||
|
const config = new compiler.CompilerConfig({
|
||||||
|
genDebugInfo: options.debug === true,
|
||||||
|
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||||
|
logBindingUpdate: false,
|
||||||
|
useJit: false
|
||||||
});
|
});
|
||||||
return new CodeGenerator(options, program, tsCompilerHost, aotCompiler, ngCompilerHost);
|
const normalizer =
|
||||||
|
new compiler.DirectiveNormalizer(resourceLoader, urlResolver, htmlParser, config);
|
||||||
|
const expressionParser = new compiler.Parser(new compiler.Lexer());
|
||||||
|
const elementSchemaRegistry = new compiler.DomElementSchemaRegistry();
|
||||||
|
const console = new Console();
|
||||||
|
const tmplParser = new compiler.TemplateParser(
|
||||||
|
expressionParser, elementSchemaRegistry, htmlParser, console, []);
|
||||||
|
const resolver = new compiler.CompileMetadataResolver(
|
||||||
|
new compiler.NgModuleResolver(staticReflector),
|
||||||
|
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
|
||||||
|
elementSchemaRegistry, normalizer, staticReflector);
|
||||||
|
// TODO(vicb): do not pass cliOptions.i18nFormat here
|
||||||
|
const offlineCompiler = new compiler.OfflineCompiler(
|
||||||
|
resolver, tmplParser, new compiler.StyleCompiler(urlResolver),
|
||||||
|
new compiler.ViewCompiler(config, elementSchemaRegistry),
|
||||||
|
new compiler.DirectiveWrapperCompiler(
|
||||||
|
config, expressionParser, elementSchemaRegistry, console),
|
||||||
|
new compiler.NgModuleCompiler(), new compiler.TypeScriptEmitter(reflectorHost),
|
||||||
|
cliOptions.locale, cliOptions.i18nFormat,
|
||||||
|
new compiler.AnimationParser(elementSchemaRegistry));
|
||||||
|
|
||||||
|
return new CodeGenerator(
|
||||||
|
options, program, compilerHost, staticReflector, offlineCompiler, reflectorHost);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function excludeFilePattern(options: AngularCompilerOptions): RegExp {
|
export function extractProgramSymbols(
|
||||||
return options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : GENERATED_FILES;
|
program: ts.Program, staticReflector: StaticReflector, reflectorHost: StaticReflectorHost,
|
||||||
|
options: AngularCompilerOptions): StaticSymbol[] {
|
||||||
|
// Compare with false since the default should be true
|
||||||
|
const skipFileNames =
|
||||||
|
options.generateCodeForLibraries === false ? GENERATED_OR_DTS_FILES : GENERATED_FILES;
|
||||||
|
|
||||||
|
const staticSymbols: StaticSymbol[] = [];
|
||||||
|
|
||||||
|
program.getSourceFiles()
|
||||||
|
.filter(sourceFile => !skipFileNames.test(sourceFile.fileName))
|
||||||
|
.forEach(sourceFile => {
|
||||||
|
const absSrcPath = reflectorHost.getCanonicalFileName(sourceFile.fileName);
|
||||||
|
|
||||||
|
const moduleMetadata = staticReflector.getModuleMetadata(absSrcPath);
|
||||||
|
if (!moduleMetadata) {
|
||||||
|
console.log(`WARNING: no metadata found for ${absSrcPath}`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const metadata = moduleMetadata['metadata'];
|
||||||
|
|
||||||
|
if (!metadata) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const symbol of Object.keys(metadata)) {
|
||||||
|
if (metadata[symbol] && metadata[symbol].__symbolic == 'error') {
|
||||||
|
// Ignore symbols that are only included to record error information.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
staticSymbols.push(reflectorHost.findDeclaration(absSrcPath, symbol, absSrcPath));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return staticSymbols;
|
||||||
}
|
}
|
||||||
|
@ -1,247 +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 {AotCompilerHost, StaticSymbol} from '@angular/compiler';
|
|
||||||
import {AngularCompilerOptions, MetadataCollector, ModuleMetadata} from '@angular/tsc-wrapped';
|
|
||||||
import * as fs from 'fs';
|
|
||||||
import * as path from 'path';
|
|
||||||
import * as ts from 'typescript';
|
|
||||||
|
|
||||||
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
|
||||||
const DTS = /\.d\.ts$/;
|
|
||||||
const NODE_MODULES = '/node_modules/';
|
|
||||||
const IS_GENERATED = /\.(ngfactory|css(\.shim)?)$/;
|
|
||||||
|
|
||||||
export interface CompilerHostContext {
|
|
||||||
fileExists(fileName: string): boolean;
|
|
||||||
directoryExists(directoryName: string): boolean;
|
|
||||||
readFile(fileName: string): string;
|
|
||||||
readResource(fileName: string): Promise<string>;
|
|
||||||
assumeFileExists(fileName: string): void;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class CompilerHost implements AotCompilerHost {
|
|
||||||
protected metadataCollector = new MetadataCollector();
|
|
||||||
protected context: CompilerHostContext;
|
|
||||||
private isGenDirChildOfRootDir: boolean;
|
|
||||||
protected basePath: string;
|
|
||||||
private genDir: string;
|
|
||||||
private resolverCache = new Map<string, ModuleMetadata[]>();
|
|
||||||
|
|
||||||
constructor(
|
|
||||||
protected program: ts.Program, protected compilerHost: ts.CompilerHost,
|
|
||||||
protected options: AngularCompilerOptions, context?: CompilerHostContext) {
|
|
||||||
// normalize the path so that it never ends with '/'.
|
|
||||||
this.basePath = path.normalize(path.join(this.options.basePath, '.')).replace(/\\/g, '/');
|
|
||||||
this.genDir = path.normalize(path.join(this.options.genDir, '.')).replace(/\\/g, '/');
|
|
||||||
|
|
||||||
this.context = context || new NodeCompilerHostContext(compilerHost);
|
|
||||||
const genPath: string = path.relative(this.basePath, this.genDir);
|
|
||||||
this.isGenDirChildOfRootDir = genPath === '' || !genPath.startsWith('..');
|
|
||||||
}
|
|
||||||
|
|
||||||
// We use absolute paths on disk as canonical.
|
|
||||||
getCanonicalFileName(fileName: string): string { return fileName; }
|
|
||||||
|
|
||||||
moduleNameToFileName(m: string, containingFile: string) {
|
|
||||||
if (!containingFile || !containingFile.length) {
|
|
||||||
if (m.indexOf('.') === 0) {
|
|
||||||
throw new Error('Resolution of relative paths requires a containing file.');
|
|
||||||
}
|
|
||||||
// Any containing file gives the same result for absolute imports
|
|
||||||
containingFile = this.getCanonicalFileName(path.join(this.basePath, 'index.ts'));
|
|
||||||
}
|
|
||||||
m = m.replace(EXT, '');
|
|
||||||
const resolved =
|
|
||||||
ts.resolveModuleName(m, containingFile.replace(/\\/g, '/'), this.options, this.context)
|
|
||||||
.resolvedModule;
|
|
||||||
return resolved ? this.getCanonicalFileName(resolved.resolvedFileName) : null;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* We want a moduleId that will appear in import statements in the generated code.
|
|
||||||
* These need to be in a form that system.js can load, so absolute file paths don't work.
|
|
||||||
*
|
|
||||||
* The `containingFile` is always in the `genDir`, where as the `importedFile` can be in
|
|
||||||
* `genDir`, `node_module` or `basePath`. The `importedFile` is either a generated file or
|
|
||||||
* existing file.
|
|
||||||
*
|
|
||||||
* | genDir | node_module | rootDir
|
|
||||||
* --------------+----------+-------------+----------
|
|
||||||
* generated | relative | relative | n/a
|
|
||||||
* existing file | n/a | absolute | relative(*)
|
|
||||||
*
|
|
||||||
* NOTE: (*) the relative path is computed depending on `isGenDirChildOfRootDir`.
|
|
||||||
*/
|
|
||||||
fileNameToModuleName(importedFile: string, containingFile: string): string {
|
|
||||||
// If a file does not yet exist (because we compile it later), we still need to
|
|
||||||
// assume it exists it so that the `resolve` method works!
|
|
||||||
if (!this.compilerHost.fileExists(importedFile)) {
|
|
||||||
this.context.assumeFileExists(importedFile);
|
|
||||||
}
|
|
||||||
|
|
||||||
containingFile = this.rewriteGenDirPath(containingFile);
|
|
||||||
const containingDir = path.dirname(containingFile);
|
|
||||||
// drop extension
|
|
||||||
importedFile = importedFile.replace(EXT, '');
|
|
||||||
|
|
||||||
const nodeModulesIndex = importedFile.indexOf(NODE_MODULES);
|
|
||||||
const importModule = nodeModulesIndex === -1 ?
|
|
||||||
null :
|
|
||||||
importedFile.substring(nodeModulesIndex + NODE_MODULES.length);
|
|
||||||
const isGeneratedFile = IS_GENERATED.test(importedFile);
|
|
||||||
|
|
||||||
if (isGeneratedFile) {
|
|
||||||
// rewrite to genDir path
|
|
||||||
if (importModule) {
|
|
||||||
// it is generated, therefore we do a relative path to the factory
|
|
||||||
return this.dotRelative(containingDir, this.genDir + NODE_MODULES + importModule);
|
|
||||||
} else {
|
|
||||||
// assume that import is also in `genDir`
|
|
||||||
importedFile = this.rewriteGenDirPath(importedFile);
|
|
||||||
return this.dotRelative(containingDir, importedFile);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// user code import
|
|
||||||
if (importModule) {
|
|
||||||
return importModule;
|
|
||||||
} else {
|
|
||||||
if (!this.isGenDirChildOfRootDir) {
|
|
||||||
// assume that they are on top of each other.
|
|
||||||
importedFile = importedFile.replace(this.basePath, this.genDir);
|
|
||||||
}
|
|
||||||
return this.dotRelative(containingDir, importedFile);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private dotRelative(from: string, to: string): string {
|
|
||||||
const rPath: string = path.relative(from, to).replace(/\\/g, '/');
|
|
||||||
return rPath.startsWith('.') ? rPath : './' + rPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Moves the path into `genDir` folder while preserving the `node_modules` directory.
|
|
||||||
*/
|
|
||||||
private rewriteGenDirPath(filepath: string) {
|
|
||||||
const nodeModulesIndex = filepath.indexOf(NODE_MODULES);
|
|
||||||
if (nodeModulesIndex !== -1) {
|
|
||||||
// If we are in node_modulse, transplant them into `genDir`.
|
|
||||||
return path.join(this.genDir, filepath.substring(nodeModulesIndex));
|
|
||||||
} else {
|
|
||||||
// pretend that containing file is on top of the `genDir` to normalize the paths.
|
|
||||||
// we apply the `genDir` => `rootDir` delta through `rootDirPrefix` later.
|
|
||||||
return filepath.replace(this.basePath, this.genDir);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
protected getSourceFile(filePath: string): ts.SourceFile {
|
|
||||||
const sf = this.program.getSourceFile(filePath);
|
|
||||||
if (!sf) {
|
|
||||||
if (this.context.fileExists(filePath)) {
|
|
||||||
const sourceText = this.context.readFile(filePath);
|
|
||||||
return ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true);
|
|
||||||
}
|
|
||||||
throw new Error(`Source file ${filePath} not present in program.`);
|
|
||||||
}
|
|
||||||
return sf;
|
|
||||||
}
|
|
||||||
|
|
||||||
getMetadataFor(filePath: string): ModuleMetadata[] {
|
|
||||||
if (!this.context.fileExists(filePath)) {
|
|
||||||
// If the file doesn't exists then we cannot return metadata for the file.
|
|
||||||
// This will occur if the user refernced a declared module for which no file
|
|
||||||
// exists for the module (i.e. jQuery or angularjs).
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (DTS.test(filePath)) {
|
|
||||||
const metadataPath = filePath.replace(DTS, '.metadata.json');
|
|
||||||
if (this.context.fileExists(metadataPath)) {
|
|
||||||
return this.readMetadata(metadataPath, filePath);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const sf = this.getSourceFile(filePath);
|
|
||||||
const metadata = this.metadataCollector.getMetadata(sf);
|
|
||||||
return metadata ? [metadata] : [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readMetadata(filePath: string, dtsFilePath: string): ModuleMetadata[] {
|
|
||||||
let metadatas = this.resolverCache.get(filePath);
|
|
||||||
if (metadatas) {
|
|
||||||
return metadatas;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
const metadataOrMetadatas = JSON.parse(this.context.readFile(filePath));
|
|
||||||
const metadatas = metadataOrMetadatas ?
|
|
||||||
(Array.isArray(metadataOrMetadatas) ? metadataOrMetadatas : [metadataOrMetadatas]) :
|
|
||||||
[];
|
|
||||||
const v1Metadata = metadatas.find(m => m['version'] === 1);
|
|
||||||
let v2Metadata = metadatas.find(m => m['version'] === 2);
|
|
||||||
if (!v2Metadata && v1Metadata) {
|
|
||||||
// patch up v1 to v2 by merging the metadata with metadata collected from the d.ts file
|
|
||||||
// as the only difference between the versions is whether all exports are contained in
|
|
||||||
// the metadata
|
|
||||||
v2Metadata = {'__symbolic': 'module', 'version': 2, 'metadata': {}};
|
|
||||||
if (v1Metadata.exports) {
|
|
||||||
v2Metadata.exports = v1Metadata.exports;
|
|
||||||
}
|
|
||||||
for (let prop in v1Metadata.metadata) {
|
|
||||||
v2Metadata.metadata[prop] = v1Metadata.metadata[prop];
|
|
||||||
}
|
|
||||||
const sourceText = this.context.readFile(dtsFilePath);
|
|
||||||
const exports = this.metadataCollector.getMetadata(this.getSourceFile(dtsFilePath));
|
|
||||||
if (exports) {
|
|
||||||
for (let prop in exports.metadata) {
|
|
||||||
if (!v2Metadata.metadata[prop]) {
|
|
||||||
v2Metadata.metadata[prop] = exports.metadata[prop];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
metadatas.push(v2Metadata);
|
|
||||||
}
|
|
||||||
this.resolverCache.set(filePath, metadatas);
|
|
||||||
return metadatas;
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`Failed to read JSON file ${filePath}`);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
loadResource(filePath: string): Promise<string> { return this.context.readResource(filePath); }
|
|
||||||
}
|
|
||||||
|
|
||||||
export class NodeCompilerHostContext implements CompilerHostContext {
|
|
||||||
constructor(private host: ts.CompilerHost) {}
|
|
||||||
|
|
||||||
private assumedExists: {[fileName: string]: boolean} = {};
|
|
||||||
|
|
||||||
fileExists(fileName: string): boolean {
|
|
||||||
return this.assumedExists[fileName] || this.host.fileExists(fileName);
|
|
||||||
}
|
|
||||||
|
|
||||||
directoryExists(directoryName: string): boolean {
|
|
||||||
try {
|
|
||||||
return fs.statSync(directoryName).isDirectory();
|
|
||||||
} catch (e) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
readFile(fileName: string): string { return fs.readFileSync(fileName, 'utf8'); }
|
|
||||||
|
|
||||||
readResource(s: string) {
|
|
||||||
if (!this.host.fileExists(s)) {
|
|
||||||
// TODO: We should really have a test for error cases like this!
|
|
||||||
throw new Error(`Compilation failed. Resource file not found: ${s}`);
|
|
||||||
}
|
|
||||||
return Promise.resolve(this.host.readFile(s));
|
|
||||||
}
|
|
||||||
|
|
||||||
assumeFileExists(fileName: string): void { this.assumedExists[fileName] = true; }
|
|
||||||
}
|
|
@ -24,7 +24,17 @@ import {Extractor} from './extractor';
|
|||||||
function extract(
|
function extract(
|
||||||
ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.I18nExtractionCliOptions,
|
ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.I18nExtractionCliOptions,
|
||||||
program: ts.Program, host: ts.CompilerHost) {
|
program: ts.Program, host: ts.CompilerHost) {
|
||||||
const extractor = Extractor.create(ngOptions, cliOptions.i18nFormat, program, host);
|
const resourceLoader: compiler.ResourceLoader = {
|
||||||
|
get: (s: string) => {
|
||||||
|
if (!host.fileExists(s)) {
|
||||||
|
// TODO: We should really have a test for error cases like this!
|
||||||
|
throw new Error(`Compilation failed. Resource file not found: ${s}`);
|
||||||
|
}
|
||||||
|
return Promise.resolve(host.readFile(s));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
const extractor =
|
||||||
|
Extractor.create(ngOptions, cliOptions.i18nFormat, program, host, resourceLoader);
|
||||||
|
|
||||||
const bundlePromise: Promise<compiler.MessageBundle> = extractor.extract();
|
const bundlePromise: Promise<compiler.MessageBundle> = extractor.extract();
|
||||||
|
|
||||||
|
@ -14,28 +14,86 @@
|
|||||||
import 'reflect-metadata';
|
import 'reflect-metadata';
|
||||||
|
|
||||||
import * as compiler from '@angular/compiler';
|
import * as compiler from '@angular/compiler';
|
||||||
|
import {ViewEncapsulation} from '@angular/core';
|
||||||
import * as tsc from '@angular/tsc-wrapped';
|
import * as tsc from '@angular/tsc-wrapped';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {excludeFilePattern} from './codegen';
|
import {extractProgramSymbols} from './codegen';
|
||||||
import {CompilerHost} from './compiler_host';
|
import {ReflectorHost} from './reflector_host';
|
||||||
|
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
||||||
|
import {StaticReflector, StaticSymbol} from './static_reflector';
|
||||||
|
|
||||||
export class Extractor {
|
export class Extractor {
|
||||||
constructor(
|
constructor(
|
||||||
private ngExtractor: compiler.Extractor, private ngCompilerHost: CompilerHost,
|
private options: tsc.AngularCompilerOptions, private program: ts.Program,
|
||||||
private program: ts.Program) {}
|
public host: ts.CompilerHost, private staticReflector: StaticReflector,
|
||||||
|
private messageBundle: compiler.MessageBundle, private reflectorHost: ReflectorHost,
|
||||||
|
private metadataResolver: compiler.CompileMetadataResolver) {}
|
||||||
|
|
||||||
extract(): Promise<compiler.MessageBundle> {
|
extract(): Promise<compiler.MessageBundle> {
|
||||||
return this.ngExtractor.extract(this.program.getSourceFiles().map(
|
const programSymbols: StaticSymbol[] =
|
||||||
sf => this.ngCompilerHost.getCanonicalFileName(sf.fileName)));
|
extractProgramSymbols(this.program, this.staticReflector, this.reflectorHost, this.options);
|
||||||
|
|
||||||
|
const {ngModules, files} = compiler.analyzeAndValidateNgModules(
|
||||||
|
programSymbols, {transitiveModules: true}, this.metadataResolver);
|
||||||
|
return compiler.loadNgModuleDirectives(ngModules).then(() => {
|
||||||
|
const errors: compiler.ParseError[] = [];
|
||||||
|
|
||||||
|
files.forEach(file => {
|
||||||
|
const compMetas: compiler.CompileDirectiveMetadata[] = [];
|
||||||
|
file.directives.forEach(directiveType => {
|
||||||
|
const dirMeta = this.metadataResolver.getDirectiveMetadata(directiveType);
|
||||||
|
if (dirMeta && dirMeta.isComponent) {
|
||||||
|
compMetas.push(dirMeta);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
compMetas.forEach(compMeta => {
|
||||||
|
const html = compMeta.template.template;
|
||||||
|
const interpolationConfig =
|
||||||
|
compiler.InterpolationConfig.fromArray(compMeta.template.interpolation);
|
||||||
|
errors.push(
|
||||||
|
...this.messageBundle.updateFromTemplate(html, file.srcUrl, interpolationConfig));
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (errors.length) {
|
||||||
|
throw new Error(errors.map(e => e.toString()).join('\n'));
|
||||||
|
}
|
||||||
|
|
||||||
|
return this.messageBundle;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
static create(
|
static create(
|
||||||
options: tsc.AngularCompilerOptions, translationsFormat: string, program: ts.Program,
|
options: tsc.AngularCompilerOptions, translationsFormat: string, program: ts.Program,
|
||||||
tsCompilerHost: ts.CompilerHost, ngCompilerHost?: CompilerHost): Extractor {
|
compilerHost: ts.CompilerHost, resourceLoader: compiler.ResourceLoader,
|
||||||
if (!ngCompilerHost) ngCompilerHost = new CompilerHost(program, tsCompilerHost, options);
|
reflectorHost?: ReflectorHost): Extractor {
|
||||||
const {extractor: ngExtractor} = compiler.Extractor.create(
|
const htmlParser = new compiler.I18NHtmlParser(new compiler.HtmlParser());
|
||||||
ngCompilerHost, {excludeFilePattern: excludeFilePattern(options)});
|
|
||||||
return new Extractor(ngExtractor, ngCompilerHost, program);
|
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
|
||||||
|
if (!reflectorHost) reflectorHost = new ReflectorHost(program, compilerHost, options);
|
||||||
|
const staticReflector = new StaticReflector(reflectorHost);
|
||||||
|
StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
||||||
|
|
||||||
|
const config = new compiler.CompilerConfig({
|
||||||
|
genDebugInfo: options.debug === true,
|
||||||
|
defaultEncapsulation: ViewEncapsulation.Emulated,
|
||||||
|
logBindingUpdate: false,
|
||||||
|
useJit: false
|
||||||
|
});
|
||||||
|
|
||||||
|
const normalizer =
|
||||||
|
new compiler.DirectiveNormalizer(resourceLoader, urlResolver, htmlParser, config);
|
||||||
|
const elementSchemaRegistry = new compiler.DomElementSchemaRegistry();
|
||||||
|
const resolver = new compiler.CompileMetadataResolver(
|
||||||
|
new compiler.NgModuleResolver(staticReflector),
|
||||||
|
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
|
||||||
|
elementSchemaRegistry, normalizer, staticReflector);
|
||||||
|
|
||||||
|
// TODO(vicb): implicit tags & attributes
|
||||||
|
const messageBundle = new compiler.MessageBundle(htmlParser, [], {});
|
||||||
|
|
||||||
|
return new Extractor(
|
||||||
|
options, program, compilerHost, staticReflector, messageBundle, reflectorHost, resolver);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -19,7 +19,9 @@ import {CodeGenerator} from './codegen';
|
|||||||
function codegen(
|
function codegen(
|
||||||
ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.NgcCliOptions, program: ts.Program,
|
ngOptions: tsc.AngularCompilerOptions, cliOptions: tsc.NgcCliOptions, program: ts.Program,
|
||||||
host: ts.CompilerHost) {
|
host: ts.CompilerHost) {
|
||||||
return CodeGenerator.create(ngOptions, cliOptions, program, host).codegen();
|
return CodeGenerator.create(ngOptions, cliOptions, program, host).codegen({
|
||||||
|
transitiveModules: true
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// CLI entry point
|
// CLI entry point
|
||||||
|
@ -6,28 +6,28 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {StaticSymbol} from '@angular/compiler';
|
|
||||||
import {AngularCompilerOptions, ModuleMetadata} from '@angular/tsc-wrapped';
|
import {AngularCompilerOptions, ModuleMetadata} from '@angular/tsc-wrapped';
|
||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
import {CompilerHost, CompilerHostContext} from './compiler_host';
|
import {ReflectorHost, ReflectorHostContext} from './reflector_host';
|
||||||
|
import {StaticSymbol} from './static_reflector';
|
||||||
|
|
||||||
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||||
const DTS = /\.d\.ts$/;
|
const DTS = /\.d\.ts$/;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This version of the AotCompilerHost expects that the program will be compiled
|
* This version of the reflector host expects that the program will be compiled
|
||||||
* and executed with a "path mapped" directory structure, where generated files
|
* and executed with a "path mapped" directory structure, where generated files
|
||||||
* are in a parallel tree with the sources, and imported using a `./` relative
|
* are in a parallel tree with the sources, and imported using a `./` relative
|
||||||
* import. This requires using TS `rootDirs` option and also teaching the module
|
* import. This requires using TS `rootDirs` option and also teaching the module
|
||||||
* loader what to do.
|
* loader what to do.
|
||||||
*/
|
*/
|
||||||
export class PathMappedCompilerHost extends CompilerHost {
|
export class PathMappedReflectorHost extends ReflectorHost {
|
||||||
constructor(
|
constructor(
|
||||||
program: ts.Program, compilerHost: ts.CompilerHost, options: AngularCompilerOptions,
|
program: ts.Program, compilerHost: ts.CompilerHost, options: AngularCompilerOptions,
|
||||||
context?: CompilerHostContext) {
|
context?: ReflectorHostContext) {
|
||||||
super(program, compilerHost, options, context);
|
super(program, compilerHost, options, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,14 +42,7 @@ export class PathMappedCompilerHost extends CompilerHost {
|
|||||||
return fileName;
|
return fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
moduleNameToFileName(m: string, containingFile: string) {
|
protected resolve(m: string, containingFile: string) {
|
||||||
if (!containingFile || !containingFile.length) {
|
|
||||||
if (m.indexOf('.') === 0) {
|
|
||||||
throw new Error('Resolution of relative paths requires a containing file.');
|
|
||||||
}
|
|
||||||
// Any containing file gives the same result for absolute imports
|
|
||||||
containingFile = this.getCanonicalFileName(path.join(this.basePath, 'index.ts'));
|
|
||||||
}
|
|
||||||
for (const root of this.options.rootDirs || ['']) {
|
for (const root of this.options.rootDirs || ['']) {
|
||||||
const rootedContainingFile = path.join(root, containingFile);
|
const rootedContainingFile = path.join(root, containingFile);
|
||||||
const resolved =
|
const resolved =
|
||||||
@ -58,7 +51,7 @@ export class PathMappedCompilerHost extends CompilerHost {
|
|||||||
if (this.options.traceResolution) {
|
if (this.options.traceResolution) {
|
||||||
console.log('resolve', m, containingFile, '=>', resolved.resolvedFileName);
|
console.log('resolve', m, containingFile, '=>', resolved.resolvedFileName);
|
||||||
}
|
}
|
||||||
return this.getCanonicalFileName(resolved.resolvedFileName);
|
return resolved.resolvedFileName;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -69,7 +62,10 @@ export class PathMappedCompilerHost extends CompilerHost {
|
|||||||
* Relativize the paths by checking candidate prefixes of the absolute path, to see if
|
* Relativize the paths by checking candidate prefixes of the absolute path, to see if
|
||||||
* they are resolvable by the moduleResolution strategy from the CompilerHost.
|
* they are resolvable by the moduleResolution strategy from the CompilerHost.
|
||||||
*/
|
*/
|
||||||
fileNameToModuleName(importedFile: string, containingFile: string): string {
|
getImportPath(containingFile: string, importedFile: string): string {
|
||||||
|
importedFile = this.resolveAssetUrl(importedFile, containingFile);
|
||||||
|
containingFile = this.resolveAssetUrl(containingFile, '');
|
||||||
|
|
||||||
if (this.options.traceResolution) {
|
if (this.options.traceResolution) {
|
||||||
console.log(
|
console.log(
|
||||||
'getImportPath from containingFile', containingFile, 'to importedFile', importedFile);
|
'getImportPath from containingFile', containingFile, 'to importedFile', importedFile);
|
||||||
@ -86,7 +82,7 @@ export class PathMappedCompilerHost extends CompilerHost {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const resolvable = (candidate: string) => {
|
const resolvable = (candidate: string) => {
|
||||||
const resolved = this.moduleNameToFileName(candidate, importedFile);
|
const resolved = this.getCanonicalFileName(this.resolve(candidate, importedFile));
|
||||||
return resolved && resolved.replace(EXT, '') === importedFile.replace(EXT, '');
|
return resolved && resolved.replace(EXT, '') === importedFile.replace(EXT, '');
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -116,7 +112,7 @@ export class PathMappedCompilerHost extends CompilerHost {
|
|||||||
`Unable to find any resolvable import for ${importedFile} relative to ${containingFile}`);
|
`Unable to find any resolvable import for ${importedFile} relative to ${containingFile}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMetadataFor(filePath: string): ModuleMetadata[] {
|
getMetadataFor(filePath: string): ModuleMetadata {
|
||||||
for (const root of this.options.rootDirs || []) {
|
for (const root of this.options.rootDirs || []) {
|
||||||
const rootedPath = path.join(root, filePath);
|
const rootedPath = path.join(root, filePath);
|
||||||
if (!this.compilerHost.fileExists(rootedPath)) {
|
if (!this.compilerHost.fileExists(rootedPath)) {
|
||||||
@ -128,13 +124,16 @@ export class PathMappedCompilerHost extends CompilerHost {
|
|||||||
if (DTS.test(rootedPath)) {
|
if (DTS.test(rootedPath)) {
|
||||||
const metadataPath = rootedPath.replace(DTS, '.metadata.json');
|
const metadataPath = rootedPath.replace(DTS, '.metadata.json');
|
||||||
if (this.context.fileExists(metadataPath)) {
|
if (this.context.fileExists(metadataPath)) {
|
||||||
return this.readMetadata(metadataPath, rootedPath);
|
const metadata = this.readMetadata(metadataPath);
|
||||||
|
return (Array.isArray(metadata) && metadata.length == 0) ? undefined : metadata;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const sf = this.getSourceFile(rootedPath);
|
const sf = this.program.getSourceFile(rootedPath);
|
||||||
sf.fileName = sf.fileName;
|
if (!sf) {
|
||||||
const metadata = this.metadataCollector.getMetadata(sf);
|
throw new Error(`Source file ${rootedPath} not present in program.`);
|
||||||
return metadata ? [metadata] : [];
|
}
|
||||||
|
sf.fileName = this.getCanonicalFileName(sf.fileName);
|
||||||
|
return this.metadataCollector.getMetadata(sf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -16,3 +16,9 @@ export var ReflectionCapabilities: typeof r.ReflectionCapabilities = r.Reflectio
|
|||||||
|
|
||||||
export type Console = typeof r._Console;
|
export type Console = typeof r._Console;
|
||||||
export var Console: typeof r.Console = r.Console;
|
export var Console: typeof r.Console = r.Console;
|
||||||
|
|
||||||
|
export var reflector: typeof r.reflector = r.reflector;
|
||||||
|
|
||||||
|
export type SetterFn = typeof r._SetterFn;
|
||||||
|
export type GetterFn = typeof r._GetterFn;
|
||||||
|
export type MethodFn = typeof r._MethodFn;
|
||||||
|
354
modules/@angular/compiler-cli/src/reflector_host.ts
Normal file
354
modules/@angular/compiler-cli/src/reflector_host.ts
Normal file
@ -0,0 +1,354 @@
|
|||||||
|
/**
|
||||||
|
* @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 {AssetUrl, ImportGenerator} from '@angular/compiler';
|
||||||
|
import {AngularCompilerOptions, MetadataCollector, ModuleMetadata} from '@angular/tsc-wrapped';
|
||||||
|
import * as fs from 'fs';
|
||||||
|
import * as path from 'path';
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
|
import {StaticReflectorHost, StaticSymbol} from './static_reflector';
|
||||||
|
|
||||||
|
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||||
|
const DTS = /\.d\.ts$/;
|
||||||
|
const NODE_MODULES = '/node_modules/';
|
||||||
|
const IS_GENERATED = /\.(ngfactory|css(\.shim)?)$/;
|
||||||
|
|
||||||
|
export interface ReflectorHostContext {
|
||||||
|
fileExists(fileName: string): boolean;
|
||||||
|
directoryExists(directoryName: string): boolean;
|
||||||
|
readFile(fileName: string): string;
|
||||||
|
assumeFileExists(fileName: string): void;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class ReflectorHost implements StaticReflectorHost, ImportGenerator {
|
||||||
|
protected metadataCollector = new MetadataCollector();
|
||||||
|
protected context: ReflectorHostContext;
|
||||||
|
private isGenDirChildOfRootDir: boolean;
|
||||||
|
protected basePath: string;
|
||||||
|
private genDir: string;
|
||||||
|
constructor(
|
||||||
|
protected program: ts.Program, protected compilerHost: ts.CompilerHost,
|
||||||
|
protected options: AngularCompilerOptions, context?: ReflectorHostContext) {
|
||||||
|
// normalize the path so that it never ends with '/'.
|
||||||
|
this.basePath = path.normalize(path.join(this.options.basePath, '.')).replace(/\\/g, '/');
|
||||||
|
this.genDir = path.normalize(path.join(this.options.genDir, '.')).replace(/\\/g, '/');
|
||||||
|
|
||||||
|
this.context = context || new NodeReflectorHostContext(compilerHost);
|
||||||
|
const genPath: string = path.relative(this.basePath, this.genDir);
|
||||||
|
this.isGenDirChildOfRootDir = genPath === '' || !genPath.startsWith('..');
|
||||||
|
}
|
||||||
|
|
||||||
|
angularImportLocations() {
|
||||||
|
return {
|
||||||
|
coreDecorators: '@angular/core/src/metadata',
|
||||||
|
diDecorators: '@angular/core/src/di/metadata',
|
||||||
|
diMetadata: '@angular/core/src/di/metadata',
|
||||||
|
diOpaqueToken: '@angular/core/src/di/opaque_token',
|
||||||
|
animationMetadata: '@angular/core/src/animation/metadata',
|
||||||
|
provider: '@angular/core/src/di/provider'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// We use absolute paths on disk as canonical.
|
||||||
|
getCanonicalFileName(fileName: string): string { return fileName; }
|
||||||
|
|
||||||
|
protected resolve(m: string, containingFile: string) {
|
||||||
|
m = m.replace(EXT, '');
|
||||||
|
const resolved =
|
||||||
|
ts.resolveModuleName(m, containingFile.replace(/\\/g, '/'), this.options, this.context)
|
||||||
|
.resolvedModule;
|
||||||
|
return resolved ? resolved.resolvedFileName : null;
|
||||||
|
};
|
||||||
|
|
||||||
|
protected normalizeAssetUrl(url: string): string {
|
||||||
|
const assetUrl = AssetUrl.parse(url);
|
||||||
|
const path = assetUrl ? `${assetUrl.packageName}/${assetUrl.modulePath}` : null;
|
||||||
|
return this.getCanonicalFileName(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected resolveAssetUrl(url: string, containingFile: string): string {
|
||||||
|
const assetUrl = this.normalizeAssetUrl(url);
|
||||||
|
if (assetUrl) {
|
||||||
|
return this.getCanonicalFileName(this.resolve(assetUrl, containingFile));
|
||||||
|
}
|
||||||
|
return url;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* We want a moduleId that will appear in import statements in the generated code.
|
||||||
|
* These need to be in a form that system.js can load, so absolute file paths don't work.
|
||||||
|
*
|
||||||
|
* The `containingFile` is always in the `genDir`, where as the `importedFile` can be in
|
||||||
|
* `genDir`, `node_module` or `basePath`. The `importedFile` is either a generated file or
|
||||||
|
* existing file.
|
||||||
|
*
|
||||||
|
* | genDir | node_module | rootDir
|
||||||
|
* --------------+----------+-------------+----------
|
||||||
|
* generated | relative | relative | n/a
|
||||||
|
* existing file | n/a | absolute | relative(*)
|
||||||
|
*
|
||||||
|
* NOTE: (*) the relative path is computed depending on `isGenDirChildOfRootDir`.
|
||||||
|
*/
|
||||||
|
getImportPath(containingFile: string, importedFile: string): string {
|
||||||
|
importedFile = this.resolveAssetUrl(importedFile, containingFile);
|
||||||
|
containingFile = this.resolveAssetUrl(containingFile, '');
|
||||||
|
|
||||||
|
// If a file does not yet exist (because we compile it later), we still need to
|
||||||
|
// assume it exists it so that the `resolve` method works!
|
||||||
|
if (!this.compilerHost.fileExists(importedFile)) {
|
||||||
|
this.context.assumeFileExists(importedFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
containingFile = this.rewriteGenDirPath(containingFile);
|
||||||
|
const containingDir = path.dirname(containingFile);
|
||||||
|
// drop extension
|
||||||
|
importedFile = importedFile.replace(EXT, '');
|
||||||
|
|
||||||
|
const nodeModulesIndex = importedFile.indexOf(NODE_MODULES);
|
||||||
|
const importModule = nodeModulesIndex === -1 ?
|
||||||
|
null :
|
||||||
|
importedFile.substring(nodeModulesIndex + NODE_MODULES.length);
|
||||||
|
const isGeneratedFile = IS_GENERATED.test(importedFile);
|
||||||
|
|
||||||
|
if (isGeneratedFile) {
|
||||||
|
// rewrite to genDir path
|
||||||
|
if (importModule) {
|
||||||
|
// it is generated, therefore we do a relative path to the factory
|
||||||
|
return this.dotRelative(containingDir, this.genDir + NODE_MODULES + importModule);
|
||||||
|
} else {
|
||||||
|
// assume that import is also in `genDir`
|
||||||
|
importedFile = this.rewriteGenDirPath(importedFile);
|
||||||
|
return this.dotRelative(containingDir, importedFile);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// user code import
|
||||||
|
if (importModule) {
|
||||||
|
return importModule;
|
||||||
|
} else {
|
||||||
|
if (!this.isGenDirChildOfRootDir) {
|
||||||
|
// assume that they are on top of each other.
|
||||||
|
importedFile = importedFile.replace(this.basePath, this.genDir);
|
||||||
|
}
|
||||||
|
return this.dotRelative(containingDir, importedFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private dotRelative(from: string, to: string): string {
|
||||||
|
const rPath: string = path.relative(from, to).replace(/\\/g, '/');
|
||||||
|
return rPath.startsWith('.') ? rPath : './' + rPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Moves the path into `genDir` folder while preserving the `node_modules` directory.
|
||||||
|
*/
|
||||||
|
private rewriteGenDirPath(filepath: string) {
|
||||||
|
const nodeModulesIndex = filepath.indexOf(NODE_MODULES);
|
||||||
|
if (nodeModulesIndex !== -1) {
|
||||||
|
// If we are in node_modulse, transplant them into `genDir`.
|
||||||
|
return path.join(this.genDir, filepath.substring(nodeModulesIndex));
|
||||||
|
} else {
|
||||||
|
// pretend that containing file is on top of the `genDir` to normalize the paths.
|
||||||
|
// we apply the `genDir` => `rootDir` delta through `rootDirPrefix` later.
|
||||||
|
return filepath.replace(this.basePath, this.genDir);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
findDeclaration(
|
||||||
|
module: string, symbolName: string, containingFile: string,
|
||||||
|
containingModule?: string): StaticSymbol {
|
||||||
|
if (!containingFile || !containingFile.length) {
|
||||||
|
if (module.indexOf('.') === 0) {
|
||||||
|
throw new Error('Resolution of relative paths requires a containing file.');
|
||||||
|
}
|
||||||
|
// Any containing file gives the same result for absolute imports
|
||||||
|
containingFile = path.join(this.basePath, 'index.ts');
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
const assetUrl = this.normalizeAssetUrl(module);
|
||||||
|
if (assetUrl) {
|
||||||
|
module = assetUrl;
|
||||||
|
}
|
||||||
|
const filePath = this.resolve(module, containingFile);
|
||||||
|
|
||||||
|
if (!filePath) {
|
||||||
|
// If the file cannot be found the module is probably referencing a declared module
|
||||||
|
// for which there is no disambiguating file and we also don't need to track
|
||||||
|
// re-exports. Just use the module name.
|
||||||
|
return this.getStaticSymbol(module, symbolName);
|
||||||
|
}
|
||||||
|
|
||||||
|
const tc = this.program.getTypeChecker();
|
||||||
|
const sf = this.program.getSourceFile(filePath);
|
||||||
|
if (!sf || !(<any>sf).symbol) {
|
||||||
|
// The source file was not needed in the compile but we do need the values from
|
||||||
|
// the corresponding .ts files stored in the .metadata.json file. Check the file
|
||||||
|
// for exports to see if the file is exported.
|
||||||
|
return this.resolveExportedSymbol(filePath, symbolName) ||
|
||||||
|
this.getStaticSymbol(filePath, symbolName);
|
||||||
|
}
|
||||||
|
|
||||||
|
let symbol = tc.getExportsOfModule((<any>sf).symbol).find(m => m.name === symbolName);
|
||||||
|
if (!symbol) {
|
||||||
|
throw new Error(`can't find symbol ${symbolName} exported from module ${filePath}`);
|
||||||
|
}
|
||||||
|
if (symbol &&
|
||||||
|
symbol.flags & ts.SymbolFlags.Alias) { // This is an alias, follow what it aliases
|
||||||
|
symbol = tc.getAliasedSymbol(symbol);
|
||||||
|
}
|
||||||
|
const declaration = symbol.getDeclarations()[0];
|
||||||
|
const declarationFile = this.getCanonicalFileName(declaration.getSourceFile().fileName);
|
||||||
|
|
||||||
|
return this.getStaticSymbol(declarationFile, symbol.getName());
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`can't resolve module ${module} from ${containingFile}`);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private typeCache = new Map<string, StaticSymbol>();
|
||||||
|
private resolverCache = new Map<string, ModuleMetadata>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
|
||||||
|
* All types passed to the StaticResolver should be pseudo-types returned by this method.
|
||||||
|
*
|
||||||
|
* @param declarationFile the absolute path of the file where the symbol is declared
|
||||||
|
* @param name the name of the type.
|
||||||
|
*/
|
||||||
|
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
||||||
|
const memberSuffix = members ? `.${ members.join('.')}` : '';
|
||||||
|
const key = `"${declarationFile}".${name}${memberSuffix}`;
|
||||||
|
let result = this.typeCache.get(key);
|
||||||
|
if (!result) {
|
||||||
|
result = new StaticSymbol(declarationFile, name, members);
|
||||||
|
this.typeCache.set(key, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
getMetadataFor(filePath: string): ModuleMetadata {
|
||||||
|
if (!this.context.fileExists(filePath)) {
|
||||||
|
// If the file doesn't exists then we cannot return metadata for the file.
|
||||||
|
// This will occur if the user refernced a declared module for which no file
|
||||||
|
// exists for the module (i.e. jQuery or angularjs).
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (DTS.test(filePath)) {
|
||||||
|
const metadataPath = filePath.replace(DTS, '.metadata.json');
|
||||||
|
if (this.context.fileExists(metadataPath)) {
|
||||||
|
const metadata = this.readMetadata(metadataPath);
|
||||||
|
return (Array.isArray(metadata) && metadata.length == 0) ? undefined : metadata;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const sf = this.program.getSourceFile(filePath);
|
||||||
|
if (!sf) {
|
||||||
|
if (this.context.fileExists(filePath)) {
|
||||||
|
const sourceText = this.context.readFile(filePath);
|
||||||
|
return this.metadataCollector.getMetadata(
|
||||||
|
ts.createSourceFile(filePath, sourceText, ts.ScriptTarget.Latest, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new Error(`Source file ${filePath} not present in program.`);
|
||||||
|
}
|
||||||
|
return this.metadataCollector.getMetadata(sf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readMetadata(filePath: string) {
|
||||||
|
try {
|
||||||
|
return this.resolverCache.get(filePath) || JSON.parse(this.context.readFile(filePath));
|
||||||
|
} catch (e) {
|
||||||
|
console.error(`Failed to read JSON file ${filePath}`);
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private getResolverMetadata(filePath: string): ModuleMetadata {
|
||||||
|
let metadata = this.resolverCache.get(filePath);
|
||||||
|
if (!metadata) {
|
||||||
|
metadata = this.getMetadataFor(filePath);
|
||||||
|
this.resolverCache.set(filePath, metadata);
|
||||||
|
}
|
||||||
|
return metadata;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected resolveExportedSymbol(filePath: string, symbolName: string): StaticSymbol {
|
||||||
|
const resolveModule = (moduleName: string): string => {
|
||||||
|
const resolvedModulePath = this.getCanonicalFileName(this.resolve(moduleName, filePath));
|
||||||
|
if (!resolvedModulePath) {
|
||||||
|
throw new Error(`Could not resolve module '${moduleName}' relative to file ${filePath}`);
|
||||||
|
}
|
||||||
|
return resolvedModulePath;
|
||||||
|
};
|
||||||
|
const metadata = this.getResolverMetadata(filePath);
|
||||||
|
if (metadata) {
|
||||||
|
// If we have metadata for the symbol, this is the original exporting location.
|
||||||
|
if (metadata.metadata[symbolName]) {
|
||||||
|
return this.getStaticSymbol(filePath, symbolName);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If no, try to find the symbol in one of the re-export location
|
||||||
|
if (metadata.exports) {
|
||||||
|
// Try and find the symbol in the list of explicitly re-exported symbols.
|
||||||
|
for (const moduleExport of metadata.exports) {
|
||||||
|
if (moduleExport.export) {
|
||||||
|
const exportSymbol = moduleExport.export.find(symbol => {
|
||||||
|
if (typeof symbol === 'string') {
|
||||||
|
return symbol == symbolName;
|
||||||
|
} else {
|
||||||
|
return symbol.as == symbolName;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (exportSymbol) {
|
||||||
|
let symName = symbolName;
|
||||||
|
if (typeof exportSymbol !== 'string') {
|
||||||
|
symName = exportSymbol.name;
|
||||||
|
}
|
||||||
|
return this.resolveExportedSymbol(resolveModule(moduleExport.from), symName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to find the symbol via export * directives.
|
||||||
|
for (const moduleExport of metadata.exports) {
|
||||||
|
if (!moduleExport.export) {
|
||||||
|
const resolvedModule = resolveModule(moduleExport.from);
|
||||||
|
const candidateSymbol = this.resolveExportedSymbol(resolvedModule, symbolName);
|
||||||
|
if (candidateSymbol) return candidateSymbol;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export class NodeReflectorHostContext implements ReflectorHostContext {
|
||||||
|
constructor(private host: ts.CompilerHost) {}
|
||||||
|
|
||||||
|
private assumedExists: {[fileName: string]: boolean} = {};
|
||||||
|
|
||||||
|
fileExists(fileName: string): boolean {
|
||||||
|
return this.assumedExists[fileName] || this.host.fileExists(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
directoryExists(directoryName: string): boolean {
|
||||||
|
try {
|
||||||
|
return fs.statSync(directoryName).isDirectory();
|
||||||
|
} catch (e) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
readFile(fileName: string): string { return fs.readFileSync(fileName, 'utf8'); }
|
||||||
|
|
||||||
|
assumeFileExists(fileName: string): void { this.assumedExists[fileName] = true; }
|
||||||
|
}
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {GetterFn, MethodFn, ReflectionCapabilities, SetterFn, reflector} from '../private_import_core';
|
import {GetterFn, MethodFn, ReflectionCapabilities, SetterFn, reflector} from './private_import_core';
|
||||||
import {StaticReflector} from './static_reflector';
|
import {StaticReflector} from './static_reflector';
|
||||||
|
|
||||||
export class StaticAndDynamicReflectionCapabilities {
|
export class StaticAndDynamicReflectionCapabilities {
|
@ -7,60 +7,54 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
import {Attribute, Component, ContentChild, ContentChildren, Directive, Host, HostBinding, HostListener, Inject, Injectable, Input, NgModule, Optional, Output, Pipe, Self, SkipSelf, ViewChild, ViewChildren, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
import {Attribute, Component, ContentChild, ContentChildren, Directive, Host, HostBinding, HostListener, Inject, Injectable, Input, NgModule, Optional, Output, Pipe, Self, SkipSelf, ViewChild, ViewChildren, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
||||||
import {ReflectorReader} from '../private_import_core';
|
|
||||||
import {StaticSymbol} from './static_symbol';
|
|
||||||
|
|
||||||
const SUPPORTED_SCHEMA_VERSION = 2;
|
import {ReflectorReader} from './private_import_core';
|
||||||
const ANGULAR_IMPORT_LOCATIONS = {
|
|
||||||
coreDecorators: '@angular/core/src/metadata',
|
const SUPPORTED_SCHEMA_VERSION = 1;
|
||||||
diDecorators: '@angular/core/src/di/metadata',
|
|
||||||
diMetadata: '@angular/core/src/di/metadata',
|
|
||||||
diOpaqueToken: '@angular/core/src/di/opaque_token',
|
|
||||||
animationMetadata: '@angular/core/src/animation/metadata',
|
|
||||||
provider: '@angular/core/src/di/provider'
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The host of the StaticReflector disconnects the implementation from TypeScript / other language
|
* The host of the static resolver is expected to be able to provide module metadata in the form of
|
||||||
* services and from underlying file systems.
|
* ModuleMetadata. Angular 2 CLI will produce this metadata for a module whenever a .d.ts files is
|
||||||
|
* produced and the module has exported variables or classes with decorators. Module metadata can
|
||||||
|
* also be produced directly from TypeScript sources by using MetadataCollector in tools/metadata.
|
||||||
*/
|
*/
|
||||||
export interface StaticReflectorHost {
|
export interface StaticReflectorHost {
|
||||||
/**
|
/**
|
||||||
* Return a ModuleMetadata for the given module.
|
* Return a ModuleMetadata for the given module.
|
||||||
* Angular 2 CLI will produce this metadata for a module whenever a .d.ts files is
|
|
||||||
* produced and the module has exported variables or classes with decorators. Module metadata can
|
|
||||||
* also be produced directly from TypeScript sources by using MetadataCollector in tools/metadata.
|
|
||||||
*
|
*
|
||||||
* @param modulePath is a string identifier for a module as an absolute path.
|
* @param modulePath is a string identifier for a module as an absolute path.
|
||||||
* @returns the metadata for the given module.
|
* @returns the metadata for the given module.
|
||||||
*/
|
*/
|
||||||
getMetadataFor(modulePath: string): {[key: string]: any}[];
|
getMetadataFor(modulePath: string): {[key: string]: any}|{[key: string]: any}[];
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Converts a module name that is used in an `import` to a file path.
|
* Resolve a symbol from an import statement form, to the file where it is declared.
|
||||||
* I.e.
|
* @param module the location imported from
|
||||||
* `path/to/containingFile.ts` containing `import {...} from 'module-name'`.
|
* @param containingFile for relative imports, the path of the file containing the import
|
||||||
*/
|
*/
|
||||||
moduleNameToFileName(moduleName: string, containingFile: string): string;
|
findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol;
|
||||||
|
|
||||||
|
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol;
|
||||||
|
|
||||||
|
angularImportLocations(): {
|
||||||
|
coreDecorators: string,
|
||||||
|
diDecorators: string,
|
||||||
|
diMetadata: string,
|
||||||
|
diOpaqueToken: string,
|
||||||
|
animationMetadata: string,
|
||||||
|
provider: string
|
||||||
|
};
|
||||||
|
|
||||||
|
getCanonicalFileName(fileName: string): string;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A cache of static symbol used by the StaticReflector to return the same symbol for the
|
* A token representing the a reference to a static type.
|
||||||
* same symbol values.
|
*
|
||||||
|
* This token is unique for a filePath and name and can be used as a hash table key.
|
||||||
*/
|
*/
|
||||||
export class StaticSymbolCache {
|
export class StaticSymbol {
|
||||||
private cache = new Map<string, StaticSymbol>();
|
constructor(public filePath: string, public name: string, public members?: string[]) {}
|
||||||
|
|
||||||
get(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
|
||||||
const memberSuffix = members ? `.${ members.join('.')}` : '';
|
|
||||||
const key = `"${declarationFile}".${name}${memberSuffix}`;
|
|
||||||
let result = this.cache.get(key);
|
|
||||||
if (!result) {
|
|
||||||
result = new StaticSymbol(declarationFile, name, members);
|
|
||||||
this.cache.set(key, result);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -68,7 +62,6 @@ export class StaticSymbolCache {
|
|||||||
* templates statically.
|
* templates statically.
|
||||||
*/
|
*/
|
||||||
export class StaticReflector implements ReflectorReader {
|
export class StaticReflector implements ReflectorReader {
|
||||||
private declarationCache = new Map<string, StaticSymbol>();
|
|
||||||
private annotationCache = new Map<StaticSymbol, any[]>();
|
private annotationCache = new Map<StaticSymbol, any[]>();
|
||||||
private propertyCache = new Map<StaticSymbol, {[key: string]: any}>();
|
private propertyCache = new Map<StaticSymbol, {[key: string]: any}>();
|
||||||
private parameterCache = new Map<StaticSymbol, any[]>();
|
private parameterCache = new Map<StaticSymbol, any[]>();
|
||||||
@ -76,24 +69,20 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
|
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
|
||||||
private opaqueToken: StaticSymbol;
|
private opaqueToken: StaticSymbol;
|
||||||
|
|
||||||
constructor(
|
constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); }
|
||||||
private host: StaticReflectorHost,
|
|
||||||
private staticSymbolCache: StaticSymbolCache = new StaticSymbolCache()) {
|
|
||||||
this.initializeConversionMap();
|
|
||||||
}
|
|
||||||
|
|
||||||
importUri(typeOrFunc: StaticSymbol): string {
|
importUri(typeOrFunc: StaticSymbol): string {
|
||||||
const staticSymbol = this.findDeclaration(typeOrFunc.filePath, typeOrFunc.name, '');
|
const staticSymbol = this.host.findDeclaration(typeOrFunc.filePath, typeOrFunc.name, '');
|
||||||
return staticSymbol ? staticSymbol.filePath : null;
|
return staticSymbol ? staticSymbol.filePath : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveIdentifier(name: string, moduleUrl: string, runtime: any): any {
|
resolveIdentifier(name: string, moduleUrl: string, runtime: any): any {
|
||||||
return this.findDeclaration(moduleUrl, name, '');
|
return this.host.findDeclaration(moduleUrl, name, '');
|
||||||
}
|
}
|
||||||
|
|
||||||
resolveEnum(enumIdentifier: any, name: string): any {
|
resolveEnum(enumIdentifier: any, name: string): any {
|
||||||
const staticSymbol: StaticSymbol = enumIdentifier;
|
const staticSymbol: StaticSymbol = enumIdentifier;
|
||||||
return this.getStaticSymbol(staticSymbol.filePath, staticSymbol.name, [name]);
|
return this.host.getStaticSymbol(staticSymbol.filePath, staticSymbol.name, [name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public annotations(type: StaticSymbol): any[] {
|
public annotations(type: StaticSymbol): any[] {
|
||||||
@ -190,145 +179,59 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
|
|
||||||
private initializeConversionMap(): void {
|
private initializeConversionMap(): void {
|
||||||
const {coreDecorators, diDecorators, diMetadata, diOpaqueToken, animationMetadata, provider} =
|
const {coreDecorators, diDecorators, diMetadata, diOpaqueToken, animationMetadata, provider} =
|
||||||
ANGULAR_IMPORT_LOCATIONS;
|
this.host.angularImportLocations();
|
||||||
this.opaqueToken = this.findDeclaration(diOpaqueToken, 'OpaqueToken');
|
this.opaqueToken = this.host.findDeclaration(diOpaqueToken, 'OpaqueToken');
|
||||||
|
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Host'), Host);
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Host'), Host);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.findDeclaration(diDecorators, 'Injectable'), Injectable);
|
this.host.findDeclaration(diDecorators, 'Injectable'), Injectable);
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Self'), Self);
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Self'), Self);
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'SkipSelf'), SkipSelf);
|
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Inject'), Inject);
|
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(diDecorators, 'Optional'), Optional);
|
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.findDeclaration(coreDecorators, 'Attribute'), Attribute);
|
this.host.findDeclaration(diDecorators, 'SkipSelf'), SkipSelf);
|
||||||
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Inject'), Inject);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.findDeclaration(coreDecorators, 'ContentChild'), ContentChild);
|
this.host.findDeclaration(diDecorators, 'Optional'), Optional);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.findDeclaration(coreDecorators, 'ContentChildren'), ContentChildren);
|
this.host.findDeclaration(coreDecorators, 'Attribute'), Attribute);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.findDeclaration(coreDecorators, 'ViewChild'), ViewChild);
|
this.host.findDeclaration(coreDecorators, 'ContentChild'), ContentChild);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.findDeclaration(coreDecorators, 'ViewChildren'), ViewChildren);
|
this.host.findDeclaration(coreDecorators, 'ContentChildren'), ContentChildren);
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(coreDecorators, 'Input'), Input);
|
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(coreDecorators, 'Output'), Output);
|
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(coreDecorators, 'Pipe'), Pipe);
|
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.findDeclaration(coreDecorators, 'HostBinding'), HostBinding);
|
this.host.findDeclaration(coreDecorators, 'ViewChild'), ViewChild);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.findDeclaration(coreDecorators, 'HostListener'), HostListener);
|
this.host.findDeclaration(coreDecorators, 'ViewChildren'), ViewChildren);
|
||||||
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Input'), Input);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.findDeclaration(coreDecorators, 'Directive'), Directive);
|
this.host.findDeclaration(coreDecorators, 'Output'), Output);
|
||||||
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Pipe'), Pipe);
|
||||||
this.registerDecoratorOrConstructor(
|
this.registerDecoratorOrConstructor(
|
||||||
this.findDeclaration(coreDecorators, 'Component'), Component);
|
this.host.findDeclaration(coreDecorators, 'HostBinding'), HostBinding);
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(coreDecorators, 'NgModule'), NgModule);
|
this.registerDecoratorOrConstructor(
|
||||||
|
this.host.findDeclaration(coreDecorators, 'HostListener'), HostListener);
|
||||||
|
this.registerDecoratorOrConstructor(
|
||||||
|
this.host.findDeclaration(coreDecorators, 'Directive'), Directive);
|
||||||
|
this.registerDecoratorOrConstructor(
|
||||||
|
this.host.findDeclaration(coreDecorators, 'Component'), Component);
|
||||||
|
this.registerDecoratorOrConstructor(
|
||||||
|
this.host.findDeclaration(coreDecorators, 'NgModule'), NgModule);
|
||||||
|
|
||||||
// Note: Some metadata classes can be used directly with Provider.deps.
|
// Note: Some metadata classes can be used directly with Provider.deps.
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'Host'), Host);
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'Host'), Host);
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'Self'), Self);
|
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'Self'), Self);
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'SkipSelf'), SkipSelf);
|
this.registerDecoratorOrConstructor(
|
||||||
this.registerDecoratorOrConstructor(this.findDeclaration(diMetadata, 'Optional'), Optional);
|
this.host.findDeclaration(diMetadata, 'SkipSelf'), SkipSelf);
|
||||||
|
this.registerDecoratorOrConstructor(
|
||||||
|
this.host.findDeclaration(diMetadata, 'Optional'), Optional);
|
||||||
|
|
||||||
this.registerFunction(this.findDeclaration(animationMetadata, 'trigger'), trigger);
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'trigger'), trigger);
|
||||||
this.registerFunction(this.findDeclaration(animationMetadata, 'state'), state);
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'state'), state);
|
||||||
this.registerFunction(this.findDeclaration(animationMetadata, 'transition'), transition);
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'transition'), transition);
|
||||||
this.registerFunction(this.findDeclaration(animationMetadata, 'style'), style);
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'style'), style);
|
||||||
this.registerFunction(this.findDeclaration(animationMetadata, 'animate'), animate);
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'animate'), animate);
|
||||||
this.registerFunction(this.findDeclaration(animationMetadata, 'keyframes'), keyframes);
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'keyframes'), keyframes);
|
||||||
this.registerFunction(this.findDeclaration(animationMetadata, 'sequence'), sequence);
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'sequence'), sequence);
|
||||||
this.registerFunction(this.findDeclaration(animationMetadata, 'group'), group);
|
this.registerFunction(this.host.findDeclaration(animationMetadata, 'group'), group);
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* getStaticSymbol produces a Type whose metadata is known but whose implementation is not loaded.
|
|
||||||
* All types passed to the StaticResolver should be pseudo-types returned by this method.
|
|
||||||
*
|
|
||||||
* @param declarationFile the absolute path of the file where the symbol is declared
|
|
||||||
* @param name the name of the type.
|
|
||||||
*/
|
|
||||||
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
|
||||||
return this.staticSymbolCache.get(declarationFile, name, members);
|
|
||||||
}
|
|
||||||
|
|
||||||
private resolveExportedSymbol(filePath: string, symbolName: string): StaticSymbol {
|
|
||||||
const resolveModule = (moduleName: string): string => {
|
|
||||||
const resolvedModulePath = this.host.moduleNameToFileName(moduleName, filePath);
|
|
||||||
if (!resolvedModulePath) {
|
|
||||||
throw new Error(`Could not resolve module '${moduleName}' relative to file ${filePath}`);
|
|
||||||
}
|
|
||||||
return resolvedModulePath;
|
|
||||||
};
|
|
||||||
const cacheKey = `${filePath}|${symbolName}`;
|
|
||||||
let staticSymbol = this.declarationCache.get(cacheKey);
|
|
||||||
if (staticSymbol) {
|
|
||||||
return staticSymbol;
|
|
||||||
}
|
|
||||||
const metadata = this.getModuleMetadata(filePath);
|
|
||||||
if (metadata) {
|
|
||||||
// If we have metadata for the symbol, this is the original exporting location.
|
|
||||||
if (metadata['metadata'][symbolName]) {
|
|
||||||
staticSymbol = this.getStaticSymbol(filePath, symbolName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// If no, try to find the symbol in one of the re-export location
|
|
||||||
if (!staticSymbol && metadata['exports']) {
|
|
||||||
// Try and find the symbol in the list of explicitly re-exported symbols.
|
|
||||||
for (const moduleExport of metadata['exports']) {
|
|
||||||
if (moduleExport.export) {
|
|
||||||
const exportSymbol = moduleExport.export.find((symbol: any) => {
|
|
||||||
if (typeof symbol === 'string') {
|
|
||||||
return symbol == symbolName;
|
|
||||||
} else {
|
|
||||||
return symbol.as == symbolName;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
if (exportSymbol) {
|
|
||||||
let symName = symbolName;
|
|
||||||
if (typeof exportSymbol !== 'string') {
|
|
||||||
symName = exportSymbol.name;
|
|
||||||
}
|
|
||||||
staticSymbol = this.resolveExportedSymbol(resolveModule(moduleExport.from), symName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!staticSymbol) {
|
|
||||||
// Try to find the symbol via export * directives.
|
|
||||||
for (const moduleExport of metadata['exports']) {
|
|
||||||
if (!moduleExport.export) {
|
|
||||||
const resolvedModule = resolveModule(moduleExport.from);
|
|
||||||
const candidateSymbol = this.resolveExportedSymbol(resolvedModule, symbolName);
|
|
||||||
if (candidateSymbol) {
|
|
||||||
staticSymbol = candidateSymbol;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
this.declarationCache.set(cacheKey, staticSymbol);
|
|
||||||
return staticSymbol;
|
|
||||||
}
|
|
||||||
|
|
||||||
findDeclaration(module: string, symbolName: string, containingFile?: string): StaticSymbol {
|
|
||||||
try {
|
|
||||||
const filePath = this.host.moduleNameToFileName(module, containingFile);
|
|
||||||
let symbol: StaticSymbol;
|
|
||||||
if (!filePath) {
|
|
||||||
// If the file cannot be found the module is probably referencing a declared module
|
|
||||||
// for which there is no disambiguating file and we also don't need to track
|
|
||||||
// re-exports. Just use the module name.
|
|
||||||
symbol = this.getStaticSymbol(module, symbolName);
|
|
||||||
} else {
|
|
||||||
symbol = this.resolveExportedSymbol(filePath, symbolName) ||
|
|
||||||
this.getStaticSymbol(filePath, symbolName);
|
|
||||||
}
|
|
||||||
return symbol;
|
|
||||||
} catch (e) {
|
|
||||||
console.error(`can't resolve module ${module} from ${containingFile}`);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @internal */
|
/** @internal */
|
||||||
@ -341,10 +244,10 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
function resolveReference(context: StaticSymbol, expression: any): StaticSymbol {
|
function resolveReference(context: StaticSymbol, expression: any): StaticSymbol {
|
||||||
let staticSymbol: StaticSymbol;
|
let staticSymbol: StaticSymbol;
|
||||||
if (expression['module']) {
|
if (expression['module']) {
|
||||||
staticSymbol =
|
staticSymbol = _this.host.findDeclaration(
|
||||||
_this.findDeclaration(expression['module'], expression['name'], context.filePath);
|
expression['module'], expression['name'], context.filePath);
|
||||||
} else {
|
} else {
|
||||||
staticSymbol = _this.getStaticSymbol(context.filePath, expression['name']);
|
staticSymbol = _this.host.getStaticSymbol(context.filePath, expression['name']);
|
||||||
}
|
}
|
||||||
return staticSymbol;
|
return staticSymbol;
|
||||||
}
|
}
|
||||||
@ -553,7 +456,8 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
const members = selectTarget.members ?
|
const members = selectTarget.members ?
|
||||||
(selectTarget.members as string[]).concat(member) :
|
(selectTarget.members as string[]).concat(member) :
|
||||||
[member];
|
[member];
|
||||||
return _this.getStaticSymbol(selectTarget.filePath, selectTarget.name, members);
|
return _this.host.getStaticSymbol(
|
||||||
|
selectTarget.filePath, selectTarget.name, members);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const member = simplify(expression['member']);
|
const member = simplify(expression['member']);
|
||||||
@ -588,10 +492,10 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
// Determine if the function is a built-in conversion
|
// Determine if the function is a built-in conversion
|
||||||
let target = expression['expression'];
|
let target = expression['expression'];
|
||||||
if (target['module']) {
|
if (target['module']) {
|
||||||
staticSymbol =
|
staticSymbol = _this.host.findDeclaration(
|
||||||
_this.findDeclaration(target['module'], target['name'], context.filePath);
|
target['module'], target['name'], context.filePath);
|
||||||
} else {
|
} else {
|
||||||
staticSymbol = _this.getStaticSymbol(context.filePath, target['name']);
|
staticSymbol = _this.host.getStaticSymbol(context.filePath, target['name']);
|
||||||
}
|
}
|
||||||
let converter = _this.conversionMap.get(staticSymbol);
|
let converter = _this.conversionMap.get(staticSymbol);
|
||||||
if (converter) {
|
if (converter) {
|
||||||
@ -647,15 +551,10 @@ export class StaticReflector implements ReflectorReader {
|
|||||||
public getModuleMetadata(module: string): {[key: string]: any} {
|
public getModuleMetadata(module: string): {[key: string]: any} {
|
||||||
let moduleMetadata = this.metadataCache.get(module);
|
let moduleMetadata = this.metadataCache.get(module);
|
||||||
if (!moduleMetadata) {
|
if (!moduleMetadata) {
|
||||||
const moduleMetadatas = this.host.getMetadataFor(module);
|
moduleMetadata = this.host.getMetadataFor(module);
|
||||||
if (moduleMetadatas) {
|
if (Array.isArray(moduleMetadata)) {
|
||||||
let maxVersion = -1;
|
moduleMetadata = moduleMetadata.find(md => md['version'] === SUPPORTED_SCHEMA_VERSION) ||
|
||||||
moduleMetadatas.forEach((md) => {
|
moduleMetadata[0];
|
||||||
if (md['version'] > maxVersion) {
|
|
||||||
maxVersion = md['version'];
|
|
||||||
moduleMetadata = md;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
if (!moduleMetadata) {
|
if (!moduleMetadata) {
|
||||||
moduleMetadata =
|
moduleMetadata =
|
||||||
@ -701,7 +600,6 @@ function expandedMessage(error: any): string {
|
|||||||
if (error.context && error.context.name) {
|
if (error.context && error.context.name) {
|
||||||
return `Reference to a local (non-exported) symbol '${error.context.name}'. Consider exporting the symbol`;
|
return `Reference to a local (non-exported) symbol '${error.context.name}'. Consider exporting the symbol`;
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
return error.message;
|
return error.message;
|
||||||
}
|
}
|
@ -1,219 +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';
|
|
||||||
|
|
||||||
import {CompilerHost} from '../src/compiler_host';
|
|
||||||
|
|
||||||
import {Directory, Entry, MockAotContext, MockCompilerHost} from './mocks';
|
|
||||||
|
|
||||||
describe('CompilerHost', () => {
|
|
||||||
let context: MockAotContext;
|
|
||||||
let host: ts.CompilerHost;
|
|
||||||
let program: ts.Program;
|
|
||||||
let hostNestedGenDir: CompilerHost;
|
|
||||||
let hostSiblingGenDir: CompilerHost;
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
context = new MockAotContext('/tmp/src', clone(FILES));
|
|
||||||
host = new MockCompilerHost(context);
|
|
||||||
program = ts.createProgram(
|
|
||||||
['main.ts'], {
|
|
||||||
module: ts.ModuleKind.CommonJS,
|
|
||||||
},
|
|
||||||
host);
|
|
||||||
// Force a typecheck
|
|
||||||
const errors = program.getSemanticDiagnostics();
|
|
||||||
if (errors && errors.length) {
|
|
||||||
throw new Error('Expected no errors');
|
|
||||||
}
|
|
||||||
hostNestedGenDir = new CompilerHost(
|
|
||||||
program, host, {
|
|
||||||
genDir: '/tmp/project/src/gen/',
|
|
||||||
basePath: '/tmp/project/src',
|
|
||||||
skipMetadataEmit: false,
|
|
||||||
strictMetadataEmit: false,
|
|
||||||
skipTemplateCodegen: false,
|
|
||||||
trace: false
|
|
||||||
},
|
|
||||||
context);
|
|
||||||
hostSiblingGenDir = new CompilerHost(
|
|
||||||
program, host, {
|
|
||||||
genDir: '/tmp/project/gen',
|
|
||||||
basePath: '/tmp/project/src/',
|
|
||||||
skipMetadataEmit: false,
|
|
||||||
strictMetadataEmit: false,
|
|
||||||
skipTemplateCodegen: false,
|
|
||||||
trace: false
|
|
||||||
},
|
|
||||||
context);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('nestedGenDir', () => {
|
|
||||||
it('should import node_module from factory', () => {
|
|
||||||
expect(hostNestedGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/node_modules/@angular/core.d.ts',
|
|
||||||
'/tmp/project/src/gen/my.ngfactory.ts', ))
|
|
||||||
.toEqual('@angular/core');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should import factory from factory', () => {
|
|
||||||
expect(hostNestedGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/my.other.ngfactory.ts', '/tmp/project/src/my.ngfactory.ts'))
|
|
||||||
.toEqual('./my.other.ngfactory');
|
|
||||||
expect(hostNestedGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/my.other.css.ts', '/tmp/project/src/a/my.ngfactory.ts'))
|
|
||||||
.toEqual('../my.other.css');
|
|
||||||
expect(hostNestedGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/a/my.other.css.shim.ts', '/tmp/project/src/my.ngfactory.ts'))
|
|
||||||
.toEqual('./a/my.other.css.shim');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should import application from factory', () => {
|
|
||||||
expect(hostNestedGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/my.other.ts', '/tmp/project/src/my.ngfactory.ts'))
|
|
||||||
.toEqual('../my.other');
|
|
||||||
expect(hostNestedGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/my.other.ts', '/tmp/project/src/a/my.ngfactory.ts'))
|
|
||||||
.toEqual('../../my.other');
|
|
||||||
expect(hostNestedGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/a/my.other.ts', '/tmp/project/src/my.ngfactory.ts'))
|
|
||||||
.toEqual('../a/my.other');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('siblingGenDir', () => {
|
|
||||||
it('should import node_module from factory', () => {
|
|
||||||
expect(hostSiblingGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/node_modules/@angular/core.d.ts',
|
|
||||||
'/tmp/project/src/gen/my.ngfactory.ts'))
|
|
||||||
.toEqual('@angular/core');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should import factory from factory', () => {
|
|
||||||
expect(hostSiblingGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/my.other.ngfactory.ts', '/tmp/project/src/my.ngfactory.ts'))
|
|
||||||
.toEqual('./my.other.ngfactory');
|
|
||||||
expect(hostSiblingGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/my.other.css.ts', '/tmp/project/src/a/my.ngfactory.ts'))
|
|
||||||
.toEqual('../my.other.css');
|
|
||||||
expect(hostSiblingGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/a/my.other.css.shim.ts', '/tmp/project/src/my.ngfactory.ts'))
|
|
||||||
.toEqual('./a/my.other.css.shim');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should import application from factory', () => {
|
|
||||||
expect(hostSiblingGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/my.other.ts', '/tmp/project/src/my.ngfactory.ts'))
|
|
||||||
.toEqual('./my.other');
|
|
||||||
expect(hostSiblingGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/my.other.ts', '/tmp/project/src/a/my.ngfactory.ts'))
|
|
||||||
.toEqual('../my.other');
|
|
||||||
expect(hostSiblingGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/src/a/my.other.ts', '/tmp/project/src/my.ngfactory.ts'))
|
|
||||||
.toEqual('./a/my.other');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce an import from main @angular/core', () => {
|
|
||||||
expect(hostNestedGenDir.fileNameToModuleName(
|
|
||||||
'/tmp/project/node_modules/@angular/core.d.ts', '/tmp/project/src/main.ts'))
|
|
||||||
.toEqual('@angular/core');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce an import from main to a sub-directory', () => {
|
|
||||||
expect(hostNestedGenDir.fileNameToModuleName('lib/utils.ts', 'main.ts')).toEqual('./lib/utils');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce an import from to a peer file', () => {
|
|
||||||
expect(hostNestedGenDir.fileNameToModuleName('lib/collections.ts', 'lib/utils.ts'))
|
|
||||||
.toEqual('./collections');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce an import from to a sibling directory', () => {
|
|
||||||
expect(hostNestedGenDir.fileNameToModuleName('lib/utils.ts', 'lib2/utils2.ts'))
|
|
||||||
.toEqual('../lib/utils');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to read a metadata file', () => {
|
|
||||||
expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/core.d.ts')).toEqual([
|
|
||||||
{__symbolic: 'module', version: 2, metadata: {foo: {__symbolic: 'class'}}}
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to read metadata from an otherwise unused .d.ts file ', () => {
|
|
||||||
expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/unused.d.ts')).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to read empty metadata ', () => {
|
|
||||||
expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/empty.d.ts')).toEqual([]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should return undefined for missing modules', () => {
|
|
||||||
expect(hostNestedGenDir.getMetadataFor('node_modules/@angular/missing.d.ts')).toBeUndefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should add missing v2 metadata from v1 metadata and .d.ts files', () => {
|
|
||||||
expect(hostNestedGenDir.getMetadataFor('metadata_versions/v1.d.ts')).toEqual([
|
|
||||||
{__symbolic: 'module', version: 1, metadata: {foo: {__symbolic: 'class'}}}, {
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 2,
|
|
||||||
metadata: {foo: {__symbolic: 'class'}, bar: {__symbolic: 'class'}}
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const dummyModule = 'export let foo: any[];';
|
|
||||||
|
|
||||||
const FILES: Entry = {
|
|
||||||
'tmp': {
|
|
||||||
'src': {
|
|
||||||
'main.ts': `
|
|
||||||
import * as c from '@angular/core';
|
|
||||||
import * as r from '@angular/router';
|
|
||||||
import * as u from './lib/utils';
|
|
||||||
import * as cs from './lib/collections';
|
|
||||||
import * as u2 from './lib2/utils2';
|
|
||||||
`,
|
|
||||||
'lib': {
|
|
||||||
'utils.ts': dummyModule,
|
|
||||||
'collections.ts': dummyModule,
|
|
||||||
},
|
|
||||||
'lib2': {'utils2.ts': dummyModule},
|
|
||||||
'node_modules': {
|
|
||||||
'@angular': {
|
|
||||||
'core.d.ts': dummyModule,
|
|
||||||
'core.metadata.json':
|
|
||||||
`{"__symbolic":"module", "version": 2, "metadata": {"foo": {"__symbolic": "class"}}}`,
|
|
||||||
'router': {'index.d.ts': dummyModule, 'src': {'providers.d.ts': dummyModule}},
|
|
||||||
'unused.d.ts': dummyModule,
|
|
||||||
'empty.d.ts': 'export declare var a: string;',
|
|
||||||
'empty.metadata.json': '[]',
|
|
||||||
}
|
|
||||||
},
|
|
||||||
'metadata_versions': {
|
|
||||||
'v1.d.ts': 'export declare class bar {}',
|
|
||||||
'v1.metadata.json':
|
|
||||||
`{"__symbolic":"module", "version": 1, "metadata": {"foo": {"__symbolic": "class"}}}`,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
function clone(entry: Entry): Entry {
|
|
||||||
if (typeof entry === 'string') {
|
|
||||||
return entry;
|
|
||||||
} else {
|
|
||||||
const result: Directory = {};
|
|
||||||
for (const name in entry) {
|
|
||||||
result[name] = clone(entry[name]);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,14 +6,14 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {CompilerHostContext} from '@angular/compiler-cli/src/compiler_host';
|
import {ReflectorHostContext} from '@angular/compiler-cli/src/reflector_host';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
export type Entry = string | Directory;
|
export type Entry = string | Directory;
|
||||||
|
|
||||||
export interface Directory { [name: string]: Entry; }
|
export interface Directory { [name: string]: Entry; }
|
||||||
|
|
||||||
export class MockAotContext implements CompilerHostContext {
|
export class MockContext implements ReflectorHostContext {
|
||||||
constructor(public currentDirectory: string, private files: Entry) {}
|
constructor(public currentDirectory: string, private files: Entry) {}
|
||||||
|
|
||||||
fileExists(fileName: string): boolean { return typeof this.getEntry(fileName) === 'string'; }
|
fileExists(fileName: string): boolean { return typeof this.getEntry(fileName) === 'string'; }
|
||||||
@ -28,14 +28,6 @@ export class MockAotContext implements CompilerHostContext {
|
|||||||
return undefined;
|
return undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
readResource(fileName: string): Promise<string> {
|
|
||||||
const result = this.readFile(fileName);
|
|
||||||
if (result == null) {
|
|
||||||
return Promise.reject(new Error(`Resource not found: ${fileName}`));
|
|
||||||
}
|
|
||||||
return Promise.resolve(result);
|
|
||||||
}
|
|
||||||
|
|
||||||
writeFile(fileName: string, data: string): void {
|
writeFile(fileName: string, data: string): void {
|
||||||
const parts = fileName.split('/');
|
const parts = fileName.split('/');
|
||||||
const name = parts.pop();
|
const name = parts.pop();
|
||||||
@ -97,7 +89,7 @@ function normalize(parts: string[]): string[] {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class MockCompilerHost implements ts.CompilerHost {
|
export class MockCompilerHost implements ts.CompilerHost {
|
||||||
constructor(private context: MockAotContext) {}
|
constructor(private context: MockContext) {}
|
||||||
|
|
||||||
fileExists(fileName: string): boolean { return this.context.fileExists(fileName); }
|
fileExists(fileName: string): boolean { return this.context.fileExists(fileName); }
|
||||||
|
|
||||||
|
329
modules/@angular/compiler-cli/test/reflector_host_spec.ts
Normal file
329
modules/@angular/compiler-cli/test/reflector_host_spec.ts
Normal file
@ -0,0 +1,329 @@
|
|||||||
|
/**
|
||||||
|
* @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 {beforeEach, describe, expect, it} from '@angular/core/testing/testing_internal';
|
||||||
|
import * as ts from 'typescript';
|
||||||
|
|
||||||
|
import {ReflectorHost} from '../src/reflector_host';
|
||||||
|
|
||||||
|
import {Directory, Entry, MockCompilerHost, MockContext} from './mocks';
|
||||||
|
|
||||||
|
describe('reflector_host', () => {
|
||||||
|
let context: MockContext;
|
||||||
|
let host: ts.CompilerHost;
|
||||||
|
let program: ts.Program;
|
||||||
|
let reflectorNestedGenDir: ReflectorHost;
|
||||||
|
let reflectorSiblingGenDir: ReflectorHost;
|
||||||
|
|
||||||
|
beforeEach(() => {
|
||||||
|
context = new MockContext('/tmp/src', clone(FILES));
|
||||||
|
host = new MockCompilerHost(context);
|
||||||
|
program = ts.createProgram(
|
||||||
|
['main.ts'], {
|
||||||
|
module: ts.ModuleKind.CommonJS,
|
||||||
|
},
|
||||||
|
host);
|
||||||
|
// Force a typecheck
|
||||||
|
const errors = program.getSemanticDiagnostics();
|
||||||
|
if (errors && errors.length) {
|
||||||
|
throw new Error('Expected no errors');
|
||||||
|
}
|
||||||
|
reflectorNestedGenDir = new ReflectorHost(
|
||||||
|
program, host, {
|
||||||
|
genDir: '/tmp/project/src/gen/',
|
||||||
|
basePath: '/tmp/project/src',
|
||||||
|
skipMetadataEmit: false,
|
||||||
|
strictMetadataEmit: false,
|
||||||
|
skipTemplateCodegen: false,
|
||||||
|
trace: false
|
||||||
|
},
|
||||||
|
context);
|
||||||
|
reflectorSiblingGenDir = new ReflectorHost(
|
||||||
|
program, host, {
|
||||||
|
genDir: '/tmp/project/gen',
|
||||||
|
basePath: '/tmp/project/src/',
|
||||||
|
skipMetadataEmit: false,
|
||||||
|
strictMetadataEmit: false,
|
||||||
|
skipTemplateCodegen: false,
|
||||||
|
trace: false
|
||||||
|
},
|
||||||
|
context);
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('nestedGenDir', () => {
|
||||||
|
it('should import node_module from factory', () => {
|
||||||
|
expect(reflectorNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/gen/my.ngfactory.ts',
|
||||||
|
'/tmp/project/node_modules/@angular/core.d.ts'))
|
||||||
|
.toEqual('@angular/core');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should import factory from factory', () => {
|
||||||
|
expect(reflectorNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ngfactory.ts'))
|
||||||
|
.toEqual('./my.other.ngfactory');
|
||||||
|
expect(reflectorNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.css.ts'))
|
||||||
|
.toEqual('../my.other.css');
|
||||||
|
expect(reflectorNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.css.shim.ts'))
|
||||||
|
.toEqual('./a/my.other.css.shim');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should import application from factory', () => {
|
||||||
|
expect(reflectorNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
||||||
|
.toEqual('../my.other');
|
||||||
|
expect(reflectorNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
||||||
|
.toEqual('../../my.other');
|
||||||
|
expect(reflectorNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.ts'))
|
||||||
|
.toEqual('../a/my.other');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('nestedGenDir', () => {
|
||||||
|
it('should import node_module from factory', () => {
|
||||||
|
expect(reflectorSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/gen/my.ngfactory.ts',
|
||||||
|
'/tmp/project/node_modules/@angular/core.d.ts'))
|
||||||
|
.toEqual('@angular/core');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should import factory from factory', () => {
|
||||||
|
expect(reflectorSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ngfactory.ts'))
|
||||||
|
.toEqual('./my.other.ngfactory');
|
||||||
|
expect(reflectorSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.css.ts'))
|
||||||
|
.toEqual('../my.other.css');
|
||||||
|
expect(reflectorSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.css.shim.ts'))
|
||||||
|
.toEqual('./a/my.other.css.shim');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should import application from factory', () => {
|
||||||
|
expect(reflectorSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
||||||
|
.toEqual('./my.other');
|
||||||
|
expect(reflectorSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/a/my.ngfactory.ts', '/tmp/project/src/my.other.ts'))
|
||||||
|
.toEqual('../my.other');
|
||||||
|
expect(reflectorSiblingGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/my.ngfactory.ts', '/tmp/project/src/a/my.other.ts'))
|
||||||
|
.toEqual('./a/my.other');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should provide the import locations for angular', () => {
|
||||||
|
const {coreDecorators, diDecorators, diMetadata, animationMetadata, provider} =
|
||||||
|
reflectorNestedGenDir.angularImportLocations();
|
||||||
|
expect(coreDecorators).toEqual('@angular/core/src/metadata');
|
||||||
|
expect(diDecorators).toEqual('@angular/core/src/di/metadata');
|
||||||
|
expect(diMetadata).toEqual('@angular/core/src/di/metadata');
|
||||||
|
expect(animationMetadata).toEqual('@angular/core/src/animation/metadata');
|
||||||
|
expect(provider).toEqual('@angular/core/src/di/provider');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce an import from main @angular/core', () => {
|
||||||
|
expect(reflectorNestedGenDir.getImportPath(
|
||||||
|
'/tmp/project/src/main.ts', '/tmp/project/node_modules/@angular/core.d.ts'))
|
||||||
|
.toEqual('@angular/core');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce an import from main to a sub-directory', () => {
|
||||||
|
expect(reflectorNestedGenDir.getImportPath('main.ts', 'lib/utils.ts')).toEqual('./lib/utils');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce an import from to a peer file', () => {
|
||||||
|
expect(reflectorNestedGenDir.getImportPath('lib/utils.ts', 'lib/collections.ts'))
|
||||||
|
.toEqual('./collections');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce an import from to a sibling directory', () => {
|
||||||
|
expect(reflectorNestedGenDir.getImportPath('lib2/utils2.ts', 'lib/utils.ts'))
|
||||||
|
.toEqual('../lib/utils');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce a symbol for an exported symbol', () => {
|
||||||
|
expect(reflectorNestedGenDir.findDeclaration('@angular/router', 'foo', 'main.ts'))
|
||||||
|
.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce a symbol for values space only reference', () => {
|
||||||
|
expect(reflectorNestedGenDir.findDeclaration('@angular/router/src/providers', 'foo', 'main.ts'))
|
||||||
|
.toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it('should be produce the same symbol if asked twice', () => {
|
||||||
|
const foo1 = reflectorNestedGenDir.getStaticSymbol('main.ts', 'foo');
|
||||||
|
const foo2 = reflectorNestedGenDir.getStaticSymbol('main.ts', 'foo');
|
||||||
|
expect(foo1).toBe(foo2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to produce a symbol for a module with no file', () => {
|
||||||
|
expect(reflectorNestedGenDir.getStaticSymbol('angularjs', 'SomeAngularSymbol')).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to read a metadata file', () => {
|
||||||
|
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/core.d.ts'))
|
||||||
|
.toEqual({__symbolic: 'module', version: 1, metadata: {foo: {__symbolic: 'class'}}});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to read metadata from an otherwise unused .d.ts file ', () => {
|
||||||
|
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/unused.d.ts'))
|
||||||
|
.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to read empty metadata ', () => {
|
||||||
|
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/empty.d.ts'))
|
||||||
|
.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return undefined for missing modules', () => {
|
||||||
|
expect(reflectorNestedGenDir.getMetadataFor('node_modules/@angular/missing.d.ts'))
|
||||||
|
.toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to trace a named export', () => {
|
||||||
|
const symbol = reflectorNestedGenDir.findDeclaration(
|
||||||
|
'./reexport/reexport.d.ts', 'One', '/tmp/src/main.ts');
|
||||||
|
expect(symbol.name).toEqual('One');
|
||||||
|
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to trace a renamed export', () => {
|
||||||
|
const symbol = reflectorNestedGenDir.findDeclaration(
|
||||||
|
'./reexport/reexport.d.ts', 'Four', '/tmp/src/main.ts');
|
||||||
|
expect(symbol.name).toEqual('Three');
|
||||||
|
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to trace an export * export', () => {
|
||||||
|
const symbol = reflectorNestedGenDir.findDeclaration(
|
||||||
|
'./reexport/reexport.d.ts', 'Five', '/tmp/src/main.ts');
|
||||||
|
expect(symbol.name).toEqual('Five');
|
||||||
|
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin5.d.ts');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be able to trace a multi-level re-export', () => {
|
||||||
|
const symbol = reflectorNestedGenDir.findDeclaration(
|
||||||
|
'./reexport/reexport.d.ts', 'Thirty', '/tmp/src/main.ts');
|
||||||
|
expect(symbol.name).toEqual('Thirty');
|
||||||
|
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin30.d.ts');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const dummyModule = 'export let foo: any[];';
|
||||||
|
|
||||||
|
const FILES: Entry = {
|
||||||
|
'tmp': {
|
||||||
|
'src': {
|
||||||
|
'main.ts': `
|
||||||
|
import * as c from '@angular/core';
|
||||||
|
import * as r from '@angular/router';
|
||||||
|
import * as u from './lib/utils';
|
||||||
|
import * as cs from './lib/collections';
|
||||||
|
import * as u2 from './lib2/utils2';
|
||||||
|
`,
|
||||||
|
'lib': {
|
||||||
|
'utils.ts': dummyModule,
|
||||||
|
'collections.ts': dummyModule,
|
||||||
|
},
|
||||||
|
'lib2': {'utils2.ts': dummyModule},
|
||||||
|
'reexport': {
|
||||||
|
'reexport.d.ts': `
|
||||||
|
import * as c from '@angular/core';
|
||||||
|
`,
|
||||||
|
'reexport.metadata.json': JSON.stringify({
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {},
|
||||||
|
exports: [
|
||||||
|
{from: './src/origin1', export: ['One', 'Two', {name: 'Three', as: 'Four'}]},
|
||||||
|
{from: './src/origin5'}, {from: './src/reexport2'}
|
||||||
|
]
|
||||||
|
}),
|
||||||
|
'src': {
|
||||||
|
'origin1.d.ts': `
|
||||||
|
export class One {}
|
||||||
|
export class Two {}
|
||||||
|
export class Three {}
|
||||||
|
`,
|
||||||
|
'origin1.metadata.json': JSON.stringify({
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {
|
||||||
|
One: {__symbolic: 'class'},
|
||||||
|
Two: {__symbolic: 'class'},
|
||||||
|
Three: {__symbolic: 'class'},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
'origin5.d.ts': `
|
||||||
|
export class Five {}
|
||||||
|
`,
|
||||||
|
'origin5.metadata.json': JSON.stringify({
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {
|
||||||
|
Five: {__symbolic: 'class'},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
'origin30.d.ts': `
|
||||||
|
export class Thirty {}
|
||||||
|
`,
|
||||||
|
'origin30.metadata.json': JSON.stringify({
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {
|
||||||
|
Thirty: {__symbolic: 'class'},
|
||||||
|
},
|
||||||
|
}),
|
||||||
|
'originNone.d.ts': dummyModule,
|
||||||
|
'originNone.metadata.json': JSON.stringify({
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {},
|
||||||
|
}),
|
||||||
|
'reexport2.d.ts': dummyModule,
|
||||||
|
'reexport2.metadata.json': JSON.stringify({
|
||||||
|
__symbolic: 'module',
|
||||||
|
version: 1,
|
||||||
|
metadata: {},
|
||||||
|
exports: [{from: './originNone'}, {from: './origin30'}]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
},
|
||||||
|
'node_modules': {
|
||||||
|
'@angular': {
|
||||||
|
'core.d.ts': dummyModule,
|
||||||
|
'core.metadata.json':
|
||||||
|
`{"__symbolic":"module", "version": 1, "metadata": {"foo": {"__symbolic": "class"}}}`,
|
||||||
|
'router': {'index.d.ts': dummyModule, 'src': {'providers.d.ts': dummyModule}},
|
||||||
|
'unused.d.ts': dummyModule,
|
||||||
|
'empty.d.ts': 'export declare var a: string;',
|
||||||
|
'empty.metadata.json': '[]',
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
function clone(entry: Entry): Entry {
|
||||||
|
if (typeof entry === 'string') {
|
||||||
|
return entry;
|
||||||
|
} else {
|
||||||
|
const result: Directory = {};
|
||||||
|
for (const name in entry) {
|
||||||
|
result[name] = clone(entry[name]);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
@ -6,7 +6,7 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {StaticReflector, StaticReflectorHost, StaticSymbol} from '@angular/compiler';
|
import {StaticReflector, StaticReflectorHost, StaticSymbol} from '@angular/compiler-cli/src/static_reflector';
|
||||||
import {HostListener, Inject, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
import {HostListener, Inject, animate, group, keyframes, sequence, state, style, transition, trigger} from '@angular/core';
|
||||||
import {MetadataCollector} from '@angular/tsc-wrapped';
|
import {MetadataCollector} from '@angular/tsc-wrapped';
|
||||||
import * as ts from 'typescript';
|
import * as ts from 'typescript';
|
||||||
@ -22,7 +22,7 @@ describe('StaticReflector', () => {
|
|||||||
let reflector: StaticReflector;
|
let reflector: StaticReflector;
|
||||||
|
|
||||||
beforeEach(() => {
|
beforeEach(() => {
|
||||||
host = new MockStaticReflectorHost();
|
host = new MockReflectorHost();
|
||||||
reflector = new StaticReflector(host);
|
reflector = new StaticReflector(host);
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ describe('StaticReflector', () => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
it('should get annotations for NgFor', () => {
|
it('should get annotations for NgFor', () => {
|
||||||
const NgFor = reflector.findDeclaration('@angular/common/src/directives/ng_for', 'NgFor');
|
const NgFor = host.findDeclaration('angular2/src/common/directives/ng_for', 'NgFor');
|
||||||
const annotations = reflector.annotations(NgFor);
|
const annotations = reflector.annotations(NgFor);
|
||||||
expect(annotations.length).toEqual(1);
|
expect(annotations.length).toEqual(1);
|
||||||
const annotation = annotations[0];
|
const annotation = annotations[0];
|
||||||
@ -40,15 +40,15 @@ describe('StaticReflector', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should get constructor for NgFor', () => {
|
it('should get constructor for NgFor', () => {
|
||||||
const NgFor = reflector.findDeclaration('@angular/common/src/directives/ng_for', 'NgFor');
|
const NgFor = host.findDeclaration('angular2/src/common/directives/ng_for', 'NgFor');
|
||||||
const ViewContainerRef = reflector.findDeclaration(
|
const ViewContainerRef =
|
||||||
'@angular/core/src/linker/view_container_ref', 'ViewContainerRef');
|
host.findDeclaration('angular2/src/core/linker/view_container_ref', 'ViewContainerRef');
|
||||||
const TemplateRef =
|
const TemplateRef =
|
||||||
reflector.findDeclaration('@angular/core/src/linker/template_ref', 'TemplateRef');
|
host.findDeclaration('angular2/src/core/linker/template_ref', 'TemplateRef');
|
||||||
const IterableDiffers = reflector.findDeclaration(
|
const IterableDiffers = host.findDeclaration(
|
||||||
'@angular/core/src/change_detection/differs/iterable_differs', 'IterableDiffers');
|
'angular2/src/core/change_detection/differs/iterable_differs', 'IterableDiffers');
|
||||||
const ChangeDetectorRef = reflector.findDeclaration(
|
const ChangeDetectorRef = host.findDeclaration(
|
||||||
'@angular/core/src/change_detection/change_detector_ref', 'ChangeDetectorRef');
|
'angular2/src/core/change_detection/change_detector_ref', 'ChangeDetectorRef');
|
||||||
|
|
||||||
const parameters = reflector.parameters(NgFor);
|
const parameters = reflector.parameters(NgFor);
|
||||||
expect(parameters).toEqual([
|
expect(parameters).toEqual([
|
||||||
@ -58,7 +58,7 @@ describe('StaticReflector', () => {
|
|||||||
|
|
||||||
it('should get annotations for HeroDetailComponent', () => {
|
it('should get annotations for HeroDetailComponent', () => {
|
||||||
const HeroDetailComponent =
|
const HeroDetailComponent =
|
||||||
reflector.findDeclaration('src/app/hero-detail.component', 'HeroDetailComponent');
|
host.findDeclaration('src/app/hero-detail.component', 'HeroDetailComponent');
|
||||||
const annotations = reflector.annotations(HeroDetailComponent);
|
const annotations = reflector.annotations(HeroDetailComponent);
|
||||||
expect(annotations.length).toEqual(1);
|
expect(annotations.length).toEqual(1);
|
||||||
const annotation = annotations[0];
|
const annotation = annotations[0];
|
||||||
@ -73,40 +73,41 @@ describe('StaticReflector', () => {
|
|||||||
])]);
|
])]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should throw an exception for unsupported metadata versions', () => {
|
it('should throw and exception for unsupported metadata versions', () => {
|
||||||
expect(() => reflector.findDeclaration('src/version-error', 'e'))
|
const e = host.findDeclaration('src/version-error', 'e');
|
||||||
|
expect(() => reflector.annotations(e))
|
||||||
.toThrow(new Error(
|
.toThrow(new Error(
|
||||||
'Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected 2'));
|
'Metadata version mismatch for module /tmp/src/version-error.d.ts, found version 100, expected 1'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get and empty annotation list for an unknown class', () => {
|
it('should get and empty annotation list for an unknown class', () => {
|
||||||
const UnknownClass = reflector.findDeclaration('src/app/app.component', 'UnknownClass');
|
const UnknownClass = host.findDeclaration('src/app/app.component', 'UnknownClass');
|
||||||
const annotations = reflector.annotations(UnknownClass);
|
const annotations = reflector.annotations(UnknownClass);
|
||||||
expect(annotations).toEqual([]);
|
expect(annotations).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get propMetadata for HeroDetailComponent', () => {
|
it('should get propMetadata for HeroDetailComponent', () => {
|
||||||
const HeroDetailComponent =
|
const HeroDetailComponent =
|
||||||
reflector.findDeclaration('src/app/hero-detail.component', 'HeroDetailComponent');
|
host.findDeclaration('src/app/hero-detail.component', 'HeroDetailComponent');
|
||||||
const props = reflector.propMetadata(HeroDetailComponent);
|
const props = reflector.propMetadata(HeroDetailComponent);
|
||||||
expect(props['hero']).toBeTruthy();
|
expect(props['hero']).toBeTruthy();
|
||||||
expect(props['onMouseOver']).toEqual([new HostListener('mouseover', ['$event'])]);
|
expect(props['onMouseOver']).toEqual([new HostListener('mouseover', ['$event'])]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get an empty object from propMetadata for an unknown class', () => {
|
it('should get an empty object from propMetadata for an unknown class', () => {
|
||||||
const UnknownClass = reflector.findDeclaration('src/app/app.component', 'UnknownClass');
|
const UnknownClass = host.findDeclaration('src/app/app.component', 'UnknownClass');
|
||||||
const properties = reflector.propMetadata(UnknownClass);
|
const properties = reflector.propMetadata(UnknownClass);
|
||||||
expect(properties).toEqual({});
|
expect(properties).toEqual({});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should get empty parameters list for an unknown class ', () => {
|
it('should get empty parameters list for an unknown class ', () => {
|
||||||
const UnknownClass = reflector.findDeclaration('src/app/app.component', 'UnknownClass');
|
const UnknownClass = host.findDeclaration('src/app/app.component', 'UnknownClass');
|
||||||
const parameters = reflector.parameters(UnknownClass);
|
const parameters = reflector.parameters(UnknownClass);
|
||||||
expect(parameters).toEqual([]);
|
expect(parameters).toEqual([]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should provide context for errors reported by the collector', () => {
|
it('should provide context for errors reported by the collector', () => {
|
||||||
const SomeClass = reflector.findDeclaration('src/error-reporting', 'SomeClass');
|
const SomeClass = host.findDeclaration('src/error-reporting', 'SomeClass');
|
||||||
expect(() => reflector.annotations(SomeClass))
|
expect(() => reflector.annotations(SomeClass))
|
||||||
.toThrow(new Error(
|
.toThrow(new Error(
|
||||||
'Error encountered resolving symbol values statically. A reasonable error message (position 13:34 in the original .ts file), resolving symbol ErrorSym in /tmp/src/error-references.d.ts, resolving symbol Link2 in /tmp/src/error-references.d.ts, resolving symbol Link1 in /tmp/src/error-references.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts'));
|
'Error encountered resolving symbol values statically. A reasonable error message (position 13:34 in the original .ts file), resolving symbol ErrorSym in /tmp/src/error-references.d.ts, resolving symbol Link2 in /tmp/src/error-references.d.ts, resolving symbol Link1 in /tmp/src/error-references.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts, resolving symbol SomeClass in /tmp/src/error-reporting.d.ts'));
|
||||||
@ -307,14 +308,14 @@ describe('StaticReflector', () => {
|
|||||||
expect(simplify(
|
expect(simplify(
|
||||||
new StaticSymbol('/src/cases', ''),
|
new StaticSymbol('/src/cases', ''),
|
||||||
({__symbolic: 'reference', module: './extern', name: 'nonExisting'})))
|
({__symbolic: 'reference', module: './extern', name: 'nonExisting'})))
|
||||||
.toEqual(reflector.getStaticSymbol('/src/extern.d.ts', 'nonExisting'));
|
.toEqual(host.getStaticSymbol('/src/extern.d.ts', 'nonExisting'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should simplify a function reference as a static symbol', () => {
|
it('should simplify a function reference as a static symbol', () => {
|
||||||
expect(simplify(
|
expect(simplify(
|
||||||
new StaticSymbol('/src/cases', 'myFunction'),
|
new StaticSymbol('/src/cases', 'myFunction'),
|
||||||
({__symbolic: 'function', parameters: ['a'], value: []})))
|
({__symbolic: 'function', parameters: ['a'], value: []})))
|
||||||
.toEqual(reflector.getStaticSymbol('/src/cases', 'myFunction'));
|
.toEqual(host.getStaticSymbol('/src/cases', 'myFunction'));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should simplify values initialized with a function call', () => {
|
it('should simplify values initialized with a function call', () => {
|
||||||
@ -342,11 +343,13 @@ describe('StaticReflector', () => {
|
|||||||
try {
|
try {
|
||||||
const metadata = host.getMetadataFor('/tmp/src/invalid-metadata.ts');
|
const metadata = host.getMetadataFor('/tmp/src/invalid-metadata.ts');
|
||||||
expect(metadata).toBeDefined();
|
expect(metadata).toBeDefined();
|
||||||
const moduleMetadata: any = metadata[0]['metadata'];
|
if (!Array.isArray(metadata)) {
|
||||||
|
const moduleMetadata: any = metadata['metadata'];
|
||||||
expect(moduleMetadata).toBeDefined();
|
expect(moduleMetadata).toBeDefined();
|
||||||
const classData: any = moduleMetadata['InvalidMetadata'];
|
const classData: any = moduleMetadata['InvalidMetadata'];
|
||||||
expect(classData).toBeDefined();
|
expect(classData).toBeDefined();
|
||||||
simplify(new StaticSymbol('/tmp/src/invalid-metadata.ts', ''), classData.decorators[0]);
|
simplify(new StaticSymbol('/tmp/src/invalid-metadata.ts', ''), classData.decorators[0]);
|
||||||
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
expect(e.fileName).toBe('/tmp/src/invalid-metadata.ts');
|
expect(e.fileName).toBe('/tmp/src/invalid-metadata.ts');
|
||||||
threw = true;
|
threw = true;
|
||||||
@ -374,7 +377,7 @@ describe('StaticReflector', () => {
|
|||||||
const metadata = reflector.getModuleMetadata('/tmp/src/custom-decorator-reference.ts');
|
const metadata = reflector.getModuleMetadata('/tmp/src/custom-decorator-reference.ts');
|
||||||
expect(metadata).toEqual({
|
expect(metadata).toEqual({
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
Foo: {
|
Foo: {
|
||||||
__symbolic: 'class',
|
__symbolic: 'class',
|
||||||
@ -403,35 +406,35 @@ describe('StaticReflector', () => {
|
|||||||
|
|
||||||
it('should be able to get metadata for a class containing a custom decorator', () => {
|
it('should be able to get metadata for a class containing a custom decorator', () => {
|
||||||
const props = reflector.propMetadata(
|
const props = reflector.propMetadata(
|
||||||
reflector.getStaticSymbol('/tmp/src/custom-decorator-reference.ts', 'Foo'));
|
host.getStaticSymbol('/tmp/src/custom-decorator-reference.ts', 'Foo'));
|
||||||
expect(props).toEqual({foo: []});
|
expect(props).toEqual({foo: []});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should read ctor parameters with forwardRef', () => {
|
it('should read ctor parameters with forwardRef', () => {
|
||||||
const src = '/tmp/src/forward-ref.ts';
|
const src = '/tmp/src/forward-ref.ts';
|
||||||
const dep = reflector.getStaticSymbol(src, 'Dep');
|
const dep = host.getStaticSymbol(src, 'Dep');
|
||||||
const props = reflector.parameters(reflector.getStaticSymbol(src, 'Forward'));
|
const props = reflector.parameters(host.getStaticSymbol(src, 'Forward'));
|
||||||
expect(props).toEqual([[dep, new Inject(dep)]]);
|
expect(props).toEqual([[dep, new Inject(dep)]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should report an error for invalid function calls', () => {
|
it('should report an error for invalid function calls', () => {
|
||||||
expect(
|
expect(
|
||||||
() => reflector.annotations(
|
() =>
|
||||||
reflector.getStaticSymbol('/tmp/src/invalid-calls.ts', 'MyComponent')))
|
reflector.annotations(host.getStaticSymbol('/tmp/src/invalid-calls.ts', 'MyComponent')))
|
||||||
.toThrow(new Error(
|
.toThrow(new Error(
|
||||||
`Error encountered resolving symbol values statically. Calling function 'someFunction', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol MyComponent in /tmp/src/invalid-calls.ts, resolving symbol MyComponent in /tmp/src/invalid-calls.ts`));
|
`Error encountered resolving symbol values statically. Calling function 'someFunction', function calls are not supported. Consider replacing the function or lambda with a reference to an exported function, resolving symbol MyComponent in /tmp/src/invalid-calls.ts, resolving symbol MyComponent in /tmp/src/invalid-calls.ts`));
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get metadata for a class containing a static method call', () => {
|
it('should be able to get metadata for a class containing a static method call', () => {
|
||||||
const annotations = reflector.annotations(
|
const annotations = reflector.annotations(
|
||||||
reflector.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyComponent'));
|
host.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyComponent'));
|
||||||
expect(annotations.length).toBe(1);
|
expect(annotations.length).toBe(1);
|
||||||
expect(annotations[0].providers).toEqual({provider: 'a', useValue: 100});
|
expect(annotations[0].providers).toEqual({provider: 'a', useValue: 100});
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get metadata for a class containing a static field reference', () => {
|
it('should be able to get metadata for a class containing a static field reference', () => {
|
||||||
const annotations = reflector.annotations(
|
const annotations =
|
||||||
reflector.getStaticSymbol('/tmp/src/static-field-reference.ts', 'Foo'));
|
reflector.annotations(host.getStaticSymbol('/tmp/src/static-field-reference.ts', 'Foo'));
|
||||||
expect(annotations.length).toBe(1);
|
expect(annotations.length).toBe(1);
|
||||||
expect(annotations[0].providers).toEqual([{provider: 'a', useValue: 'Some string'}]);
|
expect(annotations[0].providers).toEqual([{provider: 'a', useValue: 'Some string'}]);
|
||||||
});
|
});
|
||||||
@ -439,7 +442,7 @@ describe('StaticReflector', () => {
|
|||||||
it('should be able to get the metadata for a class calling a method with a conditional expression',
|
it('should be able to get the metadata for a class calling a method with a conditional expression',
|
||||||
() => {
|
() => {
|
||||||
const annotations = reflector.annotations(
|
const annotations = reflector.annotations(
|
||||||
reflector.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyCondComponent'));
|
host.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyCondComponent'));
|
||||||
expect(annotations.length).toBe(1);
|
expect(annotations.length).toBe(1);
|
||||||
expect(annotations[0].providers).toEqual([
|
expect(annotations[0].providers).toEqual([
|
||||||
[{provider: 'a', useValue: '1'}], [{provider: 'a', useValue: '2'}]
|
[{provider: 'a', useValue: '1'}], [{provider: 'a', useValue: '2'}]
|
||||||
@ -449,81 +452,50 @@ describe('StaticReflector', () => {
|
|||||||
it('should be able to get the metadata for a class calling a method with default parameters',
|
it('should be able to get the metadata for a class calling a method with default parameters',
|
||||||
() => {
|
() => {
|
||||||
const annotations = reflector.annotations(
|
const annotations = reflector.annotations(
|
||||||
reflector.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyDefaultsComponent'));
|
host.getStaticSymbol('/tmp/src/static-method-call.ts', 'MyDefaultsComponent'));
|
||||||
expect(annotations.length).toBe(1);
|
expect(annotations.length).toBe(1);
|
||||||
expect(annotations[0].providers).toEqual([['a', true, false]]);
|
expect(annotations[0].providers).toEqual([['a', true, false]]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to get metadata with a reference to a static method', () => {
|
it('should be able to get metadata with a reference to a static method', () => {
|
||||||
const annotations = reflector.annotations(
|
const annotations = reflector.annotations(
|
||||||
reflector.getStaticSymbol('/tmp/src/static-method-ref.ts', 'MethodReference'));
|
host.getStaticSymbol('/tmp/src/static-method-ref.ts', 'MethodReference'));
|
||||||
expect(annotations.length).toBe(1);
|
expect(annotations.length).toBe(1);
|
||||||
expect(annotations[0].providers[0].useValue.members[0]).toEqual('staticMethod');
|
expect(annotations[0].providers[0].useValue.members[0]).toEqual('staticMethod');
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to produce a symbol for an exported symbol', () => {
|
|
||||||
expect(reflector.findDeclaration('@angular/router', 'foo', 'main.ts')).toBeDefined();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should be able to produce a symbol for values space only reference', () => {
|
class MockReflectorHost implements StaticReflectorHost {
|
||||||
expect(reflector.findDeclaration('@angular/router/src/providers', 'foo', 'main.ts'))
|
private staticTypeCache = new Map<string, StaticSymbol>();
|
||||||
.toBeDefined();
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be produce the same symbol if asked twice', () => {
|
|
||||||
const foo1 = reflector.getStaticSymbol('main.ts', 'foo');
|
|
||||||
const foo2 = reflector.getStaticSymbol('main.ts', 'foo');
|
|
||||||
expect(foo1).toBe(foo2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to produce a symbol for a module with no file',
|
|
||||||
() => { expect(reflector.getStaticSymbol('angularjs', 'SomeAngularSymbol')).toBeDefined(); });
|
|
||||||
|
|
||||||
it('should be able to trace a named export', () => {
|
|
||||||
const symbol = reflector.findDeclaration('./reexport/reexport', 'One', '/tmp/src/main.ts');
|
|
||||||
expect(symbol.name).toEqual('One');
|
|
||||||
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to trace a renamed export', () => {
|
|
||||||
const symbol = reflector.findDeclaration('./reexport/reexport', 'Four', '/tmp/src/main.ts');
|
|
||||||
expect(symbol.name).toEqual('Three');
|
|
||||||
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to trace an export * export', () => {
|
|
||||||
const symbol = reflector.findDeclaration('./reexport/reexport', 'Five', '/tmp/src/main.ts');
|
|
||||||
expect(symbol.name).toEqual('Five');
|
|
||||||
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin5.d.ts');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to trace a multi-level re-export', () => {
|
|
||||||
const symbol = reflector.findDeclaration('./reexport/reexport', 'Thirty', '/tmp/src/main.ts');
|
|
||||||
expect(symbol.name).toEqual('Thirty');
|
|
||||||
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin30.d.ts');
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should cache tracing a named export', () => {
|
|
||||||
const moduleNameToFileNameSpy = spyOn(host, 'moduleNameToFileName').and.callThrough();
|
|
||||||
const getMetadataForSpy = spyOn(host, 'getMetadataFor').and.callThrough();
|
|
||||||
reflector.findDeclaration('./reexport/reexport', 'One', '/tmp/src/main.ts');
|
|
||||||
moduleNameToFileNameSpy.calls.reset();
|
|
||||||
getMetadataForSpy.calls.reset();
|
|
||||||
|
|
||||||
const symbol = reflector.findDeclaration('./reexport/reexport', 'One', '/tmp/src/main.ts');
|
|
||||||
expect(moduleNameToFileNameSpy.calls.count()).toBe(1);
|
|
||||||
expect(getMetadataForSpy.calls.count()).toBe(0);
|
|
||||||
expect(symbol.name).toEqual('One');
|
|
||||||
expect(symbol.filePath).toEqual('/tmp/src/reexport/src/origin1.d.ts');
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
class MockStaticReflectorHost implements StaticReflectorHost {
|
|
||||||
private collector = new MetadataCollector();
|
private collector = new MetadataCollector();
|
||||||
|
|
||||||
|
constructor() {}
|
||||||
|
|
||||||
|
angularImportLocations() {
|
||||||
|
return {
|
||||||
|
coreDecorators: 'angular2/src/core/metadata',
|
||||||
|
diDecorators: 'angular2/src/core/di/metadata',
|
||||||
|
diMetadata: 'angular2/src/core/di/metadata',
|
||||||
|
diOpaqueToken: 'angular2/src/core/di/opaque_token',
|
||||||
|
animationMetadata: 'angular2/src/core/animation/metadata',
|
||||||
|
provider: 'angular2/src/core/di/provider'
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
getCanonicalFileName(fileName: string): string { return fileName; }
|
||||||
|
|
||||||
|
getStaticSymbol(declarationFile: string, name: string, members?: string[]): StaticSymbol {
|
||||||
|
const cacheKey = `${declarationFile}:${name}${members?'.'+members.join('.'):''}`;
|
||||||
|
let result = this.staticTypeCache.get(cacheKey);
|
||||||
|
if (!result) {
|
||||||
|
result = new StaticSymbol(declarationFile, name, members);
|
||||||
|
this.staticTypeCache.set(cacheKey, result);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
// In tests, assume that symbols are not re-exported
|
// In tests, assume that symbols are not re-exported
|
||||||
moduleNameToFileName(modulePath: string, containingFile?: string): string {
|
findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol {
|
||||||
function splitPath(path: string): string[] { return path.split(/\/|\\/g); }
|
function splitPath(path: string): string[] { return path.split(/\/|\\/g); }
|
||||||
|
|
||||||
function resolvePath(pathParts: string[]): string {
|
function resolvePath(pathParts: string[]): string {
|
||||||
@ -557,34 +529,32 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
if (modulePath.indexOf('.') === 0) {
|
if (modulePath.indexOf('.') === 0) {
|
||||||
const baseName = pathTo(containingFile, modulePath);
|
const baseName = pathTo(containingFile, modulePath);
|
||||||
const tsName = baseName + '.ts';
|
const tsName = baseName + '.ts';
|
||||||
if (this._getMetadataFor(tsName)) {
|
if (this.getMetadataFor(tsName)) {
|
||||||
return tsName;
|
return this.getStaticSymbol(tsName, symbolName);
|
||||||
}
|
}
|
||||||
return baseName + '.d.ts';
|
return this.getStaticSymbol(baseName + '.d.ts', symbolName);
|
||||||
}
|
}
|
||||||
return '/tmp/' + modulePath + '.d.ts';
|
return this.getStaticSymbol('/tmp/' + modulePath + '.d.ts', symbolName);
|
||||||
}
|
}
|
||||||
|
|
||||||
getMetadataFor(moduleId: string): any { return this._getMetadataFor(moduleId); }
|
getMetadataFor(moduleId: string): any {
|
||||||
|
|
||||||
private _getMetadataFor(moduleId: string): any {
|
|
||||||
const data: {[key: string]: any} = {
|
const data: {[key: string]: any} = {
|
||||||
'/tmp/@angular/common/src/forms-deprecated/directives.d.ts': [{
|
'/tmp/angular2/src/common/forms-deprecated/directives.d.ts': [{
|
||||||
'__symbolic': 'module',
|
'__symbolic': 'module',
|
||||||
'version': 2,
|
'version': 1,
|
||||||
'metadata': {
|
'metadata': {
|
||||||
'FORM_DIRECTIVES': [
|
'FORM_DIRECTIVES': [
|
||||||
{
|
{
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'NgFor',
|
'name': 'NgFor',
|
||||||
'module': '@angular/common/src/directives/ng_for'
|
'module': 'angular2/src/common/directives/ng_for'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}],
|
}],
|
||||||
'/tmp/@angular/common/src/directives/ng_for.d.ts': {
|
'/tmp/angular2/src/common/directives/ng_for.d.ts': {
|
||||||
'__symbolic': 'module',
|
'__symbolic': 'module',
|
||||||
'version': 2,
|
'version': 1,
|
||||||
'metadata': {
|
'metadata': {
|
||||||
'NgFor': {
|
'NgFor': {
|
||||||
'__symbolic': 'class',
|
'__symbolic': 'class',
|
||||||
@ -594,7 +564,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'Directive',
|
'name': 'Directive',
|
||||||
'module': '@angular/core/src/metadata'
|
'module': '../../core/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
{
|
{
|
||||||
@ -611,22 +581,22 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'parameters': [
|
'parameters': [
|
||||||
{
|
{
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'module': '@angular/core/src/linker/view_container_ref',
|
'module': '../../core/linker/view_container_ref',
|
||||||
'name': 'ViewContainerRef'
|
'name': 'ViewContainerRef'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'module': '@angular/core/src/linker/template_ref',
|
'module': '../../core/linker/template_ref',
|
||||||
'name': 'TemplateRef'
|
'name': 'TemplateRef'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'module': '@angular/core/src/change_detection/differs/iterable_differs',
|
'module': '../../core/change_detection/differs/iterable_differs',
|
||||||
'name': 'IterableDiffers'
|
'name': 'IterableDiffers'
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'module': '@angular/core/src/change_detection/change_detector_ref',
|
'module': '../../core/change_detection/change_detector_ref',
|
||||||
'name': 'ChangeDetectorRef'
|
'name': 'ChangeDetectorRef'
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -636,17 +606,17 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'/tmp/@angular/core/src/linker/view_container_ref.d.ts':
|
'/tmp/angular2/src/core/linker/view_container_ref.d.ts':
|
||||||
{version: 2, 'metadata': {'ViewContainerRef': {'__symbolic': 'class'}}},
|
{version: 1, 'metadata': {'ViewContainerRef': {'__symbolic': 'class'}}},
|
||||||
'/tmp/@angular/core/src/linker/template_ref.d.ts':
|
'/tmp/angular2/src/core/linker/template_ref.d.ts':
|
||||||
{version: 2, 'module': './template_ref', 'metadata': {'TemplateRef': {'__symbolic': 'class'}}},
|
{version: 1, 'module': './template_ref', 'metadata': {'TemplateRef': {'__symbolic': 'class'}}},
|
||||||
'/tmp/@angular/core/src/change_detection/differs/iterable_differs.d.ts':
|
'/tmp/angular2/src/core/change_detection/differs/iterable_differs.d.ts':
|
||||||
{version: 2, 'metadata': {'IterableDiffers': {'__symbolic': 'class'}}},
|
{version: 1, 'metadata': {'IterableDiffers': {'__symbolic': 'class'}}},
|
||||||
'/tmp/@angular/core/src/change_detection/change_detector_ref.d.ts':
|
'/tmp/angular2/src/core/change_detection/change_detector_ref.d.ts':
|
||||||
{version: 2, 'metadata': {'ChangeDetectorRef': {'__symbolic': 'class'}}},
|
{version: 1, 'metadata': {'ChangeDetectorRef': {'__symbolic': 'class'}}},
|
||||||
'/tmp/src/app/hero-detail.component.d.ts': {
|
'/tmp/src/app/hero-detail.component.d.ts': {
|
||||||
'__symbolic': 'module',
|
'__symbolic': 'module',
|
||||||
'version': 2,
|
'version': 1,
|
||||||
'metadata': {
|
'metadata': {
|
||||||
'HeroDetailComponent': {
|
'HeroDetailComponent': {
|
||||||
'__symbolic': 'class',
|
'__symbolic': 'class',
|
||||||
@ -656,7 +626,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'Component',
|
'name': 'Component',
|
||||||
'module': '@angular/core/src/metadata'
|
'module': 'angular2/src/core/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
{
|
{
|
||||||
@ -668,7 +638,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'trigger',
|
'name': 'trigger',
|
||||||
'module': '@angular/core/src/animation/metadata'
|
'module': 'angular2/src/core/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
'myAnimation',
|
'myAnimation',
|
||||||
@ -676,7 +646,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'state',
|
'name': 'state',
|
||||||
'module': '@angular/core/src/animation/metadata'
|
'module': 'angular2/src/core/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
'state1',
|
'state1',
|
||||||
@ -684,7 +654,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'style',
|
'name': 'style',
|
||||||
'module': '@angular/core/src/animation/metadata'
|
'module': 'angular2/src/core/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
{ 'background':'white' }
|
{ 'background':'white' }
|
||||||
@ -696,7 +666,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'transition',
|
'name':'transition',
|
||||||
'module': '@angular/core/src/animation/metadata'
|
'module': 'angular2/src/core/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
'* => *',
|
'* => *',
|
||||||
@ -705,20 +675,20 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'expression':{
|
'expression':{
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'sequence',
|
'name':'sequence',
|
||||||
'module': '@angular/core/src/animation/metadata'
|
'module': 'angular2/src/core/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[[{ '__symbolic': 'call',
|
'arguments':[[{ '__symbolic': 'call',
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'group',
|
'name':'group',
|
||||||
'module': '@angular/core/src/animation/metadata'
|
'module': 'angular2/src/core/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[[{
|
'arguments':[[{
|
||||||
'__symbolic': 'call',
|
'__symbolic': 'call',
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'animate',
|
'name':'animate',
|
||||||
'module': '@angular/core/src/animation/metadata'
|
'module': 'angular2/src/core/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[
|
'arguments':[
|
||||||
'1s 0.5s',
|
'1s 0.5s',
|
||||||
@ -726,13 +696,13 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'keyframes',
|
'name':'keyframes',
|
||||||
'module': '@angular/core/src/animation/metadata'
|
'module': 'angular2/src/core/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[[{ '__symbolic': 'call',
|
'arguments':[[{ '__symbolic': 'call',
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'style',
|
'name':'style',
|
||||||
'module': '@angular/core/src/animation/metadata'
|
'module': 'angular2/src/core/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[ { 'background': 'blue'} ]
|
'arguments':[ { 'background': 'blue'} ]
|
||||||
}, {
|
}, {
|
||||||
@ -740,7 +710,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic':'reference',
|
'__symbolic':'reference',
|
||||||
'name':'style',
|
'name':'style',
|
||||||
'module': '@angular/core/src/animation/metadata'
|
'module': 'angular2/src/core/animation/metadata'
|
||||||
},
|
},
|
||||||
'arguments':[ { 'background': 'red'} ]
|
'arguments':[ { 'background': 'red'} ]
|
||||||
}]]
|
}]]
|
||||||
@ -766,7 +736,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'name': 'Input',
|
'name': 'Input',
|
||||||
'module': '@angular/core/src/metadata'
|
'module': 'angular2/src/core/metadata'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
@ -780,7 +750,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
'__symbolic': 'call',
|
'__symbolic': 'call',
|
||||||
'expression': {
|
'expression': {
|
||||||
'__symbolic': 'reference',
|
'__symbolic': 'reference',
|
||||||
'module': '@angular/core/src/metadata',
|
'module': 'angular2/src/core/metadata',
|
||||||
'name': 'HostListener'
|
'name': 'HostListener'
|
||||||
},
|
},
|
||||||
'arguments': [
|
'arguments': [
|
||||||
@ -797,11 +767,11 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
'/src/extern.d.ts': {'__symbolic': 'module', 'version': 2, metadata: {s: 's'}},
|
'/src/extern.d.ts': {'__symbolic': 'module', 'version': 1, metadata: {s: 's'}},
|
||||||
'/tmp/src/version-error.d.ts': {'__symbolic': 'module', 'version': 100, metadata: {e: 's'}},
|
'/tmp/src/version-error.d.ts': {'__symbolic': 'module', 'version': 100, metadata: {e: 's'}},
|
||||||
'/tmp/src/error-reporting.d.ts': {
|
'/tmp/src/error-reporting.d.ts': {
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
SomeClass: {
|
SomeClass: {
|
||||||
__symbolic: 'class',
|
__symbolic: 'class',
|
||||||
@ -811,7 +781,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
expression: {
|
expression: {
|
||||||
__symbolic: 'reference',
|
__symbolic: 'reference',
|
||||||
name: 'Component',
|
name: 'Component',
|
||||||
module: '@angular/core/src/metadata'
|
module: 'angular2/src/core/metadata'
|
||||||
},
|
},
|
||||||
arguments: [
|
arguments: [
|
||||||
{
|
{
|
||||||
@ -831,7 +801,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
},
|
},
|
||||||
'/tmp/src/error-references.d.ts': {
|
'/tmp/src/error-references.d.ts': {
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
Link1: {
|
Link1: {
|
||||||
__symbolic: 'reference',
|
__symbolic: 'reference',
|
||||||
@ -853,7 +823,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
},
|
},
|
||||||
'/tmp/src/function-declaration.d.ts': {
|
'/tmp/src/function-declaration.d.ts': {
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
one: {
|
one: {
|
||||||
__symbolic: 'function',
|
__symbolic: 'function',
|
||||||
@ -882,7 +852,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
},
|
},
|
||||||
'/tmp/src/function-reference.ts': {
|
'/tmp/src/function-reference.ts': {
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
one: {
|
one: {
|
||||||
__symbolic: 'call',
|
__symbolic: 'call',
|
||||||
@ -924,7 +894,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
},
|
},
|
||||||
'/tmp/src/function-recursive.d.ts': {
|
'/tmp/src/function-recursive.d.ts': {
|
||||||
__symbolic: 'modules',
|
__symbolic: 'modules',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
recursive: {
|
recursive: {
|
||||||
__symbolic: 'function',
|
__symbolic: 'function',
|
||||||
@ -984,7 +954,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
},
|
},
|
||||||
'/tmp/src/spread.ts': {
|
'/tmp/src/spread.ts': {
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
spread: [0, {__symbolic: 'spread', expression: [1, 2, 3, 4]}, 5]
|
spread: [0, {__symbolic: 'spread', expression: [1, 2, 3, 4]}, 5]
|
||||||
}
|
}
|
||||||
@ -1012,8 +982,8 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
`,
|
`,
|
||||||
'/tmp/src/invalid-calls.ts': `
|
'/tmp/src/invalid-calls.ts': `
|
||||||
import {someFunction} from './nvalid-calll-definitions.ts';
|
import {someFunction} from './nvalid-calll-definitions.ts';
|
||||||
import {Component} from '@angular/core/src/metadata';
|
import {Component} from 'angular2/src/core/metadata';
|
||||||
import {NgIf} from '@angular/common';
|
import {NgIf} from 'angular2/common';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'my-component',
|
selector: 'my-component',
|
||||||
@ -1029,7 +999,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
export class MyOtherComponent { }
|
export class MyOtherComponent { }
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-method.ts': `
|
'/tmp/src/static-method.ts': `
|
||||||
import {Component} from '@angular/core/src/metadata';
|
import {Component} from 'angular2/src/core/metadata';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'stub'
|
selector: 'stub'
|
||||||
@ -1047,7 +1017,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-method-call.ts': `
|
'/tmp/src/static-method-call.ts': `
|
||||||
import {Component} from '@angular/core/src/metadata';
|
import {Component} from 'angular2/src/core/metadata';
|
||||||
import {MyModule} from './static-method';
|
import {MyModule} from './static-method';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -1066,7 +1036,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
export class MyDefaultsComponent { }
|
export class MyDefaultsComponent { }
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-field.ts': `
|
'/tmp/src/static-field.ts': `
|
||||||
import {Injectable} from '@angular/core';
|
import {Injectable} from 'angular2/core';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class MyModule {
|
export class MyModule {
|
||||||
@ -1074,7 +1044,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-field-reference.ts': `
|
'/tmp/src/static-field-reference.ts': `
|
||||||
import {Component} from '@angular/core/src/metadata';
|
import {Component} from 'angular2/src/core/metadata';
|
||||||
import {MyModule} from './static-field';
|
import {MyModule} from './static-field';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -1088,7 +1058,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
'/tmp/src/static-method-ref.ts': `
|
'/tmp/src/static-method-ref.ts': `
|
||||||
import {Component} from '@angular/core/src/metadata';
|
import {Component} from 'angular2/src/core/metadata';
|
||||||
import {ClassWithStatics} from './static-method-def';
|
import {ClassWithStatics} from './static-method-def';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
@ -1099,7 +1069,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
'/tmp/src/invalid-metadata.ts': `
|
'/tmp/src/invalid-metadata.ts': `
|
||||||
import {Component} from '@angular/core/src/metadata';
|
import {Component} from 'angular2/src/core/metadata';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
providers: [ { provider: 'a', useValue: (() => 1)() }]
|
providers: [ { provider: 'a', useValue: (() => 1)() }]
|
||||||
@ -1107,9 +1077,9 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
export class InvalidMetadata {}
|
export class InvalidMetadata {}
|
||||||
`,
|
`,
|
||||||
'/tmp/src/forward-ref.ts': `
|
'/tmp/src/forward-ref.ts': `
|
||||||
import {forwardRef} from '@angular/core';
|
import {forwardRef} from 'angular2/core';
|
||||||
import {Component} from '@angular/core/src/metadata';
|
import {Component} from 'angular2/src/core/metadata';
|
||||||
import {Inject} from '@angular/core/src/di/metadata';
|
import {Inject} from 'angular2/src/core/di/metadata';
|
||||||
@Component({})
|
@Component({})
|
||||||
export class Forward {
|
export class Forward {
|
||||||
constructor(@Inject(forwardRef(() => Dep)) d: Dep) {}
|
constructor(@Inject(forwardRef(() => Dep)) d: Dep) {}
|
||||||
@ -1117,50 +1087,7 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
export class Dep {
|
export class Dep {
|
||||||
@Input f: Forward;
|
@Input f: Forward;
|
||||||
}
|
}
|
||||||
`,
|
`
|
||||||
'/tmp/src/reexport/reexport.d.ts': {
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 2,
|
|
||||||
metadata: {},
|
|
||||||
exports: [
|
|
||||||
{from: './src/origin1', export: ['One', 'Two', {name: 'Three', as: 'Four'}]},
|
|
||||||
{from: './src/origin5'}, {from: './src/reexport2'}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
'/tmp/src/reexport/src/origin1.d.ts': {
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 2,
|
|
||||||
metadata: {
|
|
||||||
One: {__symbolic: 'class'},
|
|
||||||
Two: {__symbolic: 'class'},
|
|
||||||
Three: {__symbolic: 'class'},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'/tmp/src/reexport/src/origin5.d.ts': {
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 2,
|
|
||||||
metadata: {
|
|
||||||
Five: {__symbolic: 'class'},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'/tmp/src/reexport/src/origin30.d.ts': {
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 2,
|
|
||||||
metadata: {
|
|
||||||
Thirty: {__symbolic: 'class'},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
'/tmp/src/reexport/src/originNone.d.ts': {
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 2,
|
|
||||||
metadata: {},
|
|
||||||
},
|
|
||||||
'/tmp/src/reexport/src/reexport2.d.ts': {
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 2,
|
|
||||||
metadata: {},
|
|
||||||
exports: [{from: './originNone'}, {from: './origin30'}]
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -1173,14 +1100,9 @@ class MockStaticReflectorHost implements StaticReflectorHost {
|
|||||||
if (diagnostics && diagnostics.length) {
|
if (diagnostics && diagnostics.length) {
|
||||||
throw Error(`Error encountered during parse of file ${moduleId}`);
|
throw Error(`Error encountered during parse of file ${moduleId}`);
|
||||||
}
|
}
|
||||||
return [this.collector.getMetadata(sf)];
|
return this.collector.getMetadata(sf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const result = data[moduleId];
|
return data[moduleId];
|
||||||
if (result) {
|
|
||||||
return Array.isArray(result) ? result : [result];
|
|
||||||
} else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -25,16 +25,11 @@ export * from './src/template_parser/template_ast';
|
|||||||
export {TEMPLATE_TRANSFORMS} from './src/template_parser/template_parser';
|
export {TEMPLATE_TRANSFORMS} from './src/template_parser/template_parser';
|
||||||
export {CompilerConfig, RenderTypes} from './src/config';
|
export {CompilerConfig, RenderTypes} from './src/config';
|
||||||
export * from './src/compile_metadata';
|
export * from './src/compile_metadata';
|
||||||
export * from './src/aot/compiler_factory';
|
export * from './src/offline_compiler';
|
||||||
export * from './src/aot/compiler';
|
export {RuntimeCompiler} from './src/runtime_compiler';
|
||||||
export * from './src/aot/compiler_host';
|
|
||||||
export * from './src/aot/static_reflector';
|
|
||||||
export * from './src/aot/static_reflection_capabilities';
|
|
||||||
export * from './src/aot/static_symbol';
|
|
||||||
export {JitCompiler} from './src/jit/compiler';
|
|
||||||
export * from './src/jit/compiler_factory';
|
|
||||||
export * from './src/url_resolver';
|
export * from './src/url_resolver';
|
||||||
export * from './src/resource_loader';
|
export * from './src/resource_loader';
|
||||||
|
export * from './src/compiler';
|
||||||
export {DirectiveResolver} from './src/directive_resolver';
|
export {DirectiveResolver} from './src/directive_resolver';
|
||||||
export {PipeResolver} from './src/pipe_resolver';
|
export {PipeResolver} from './src/pipe_resolver';
|
||||||
export {NgModuleResolver} from './src/ng_module_resolver';
|
export {NgModuleResolver} from './src/ng_module_resolver';
|
||||||
|
@ -1,75 +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 {ViewEncapsulation} from '@angular/core';
|
|
||||||
|
|
||||||
import {AnimationParser} from '../animation/animation_parser';
|
|
||||||
import {CompilerConfig} from '../config';
|
|
||||||
import {DirectiveNormalizer} from '../directive_normalizer';
|
|
||||||
import {DirectiveResolver} from '../directive_resolver';
|
|
||||||
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
|
||||||
import {Lexer} from '../expression_parser/lexer';
|
|
||||||
import {Parser} from '../expression_parser/parser';
|
|
||||||
import {I18NHtmlParser} from '../i18n/i18n_html_parser';
|
|
||||||
import {CompileMetadataResolver} from '../metadata_resolver';
|
|
||||||
import {HtmlParser} from '../ml_parser/html_parser';
|
|
||||||
import {NgModuleCompiler} from '../ng_module_compiler';
|
|
||||||
import {NgModuleResolver} from '../ng_module_resolver';
|
|
||||||
import {TypeScriptEmitter} from '../output/ts_emitter';
|
|
||||||
import {PipeResolver} from '../pipe_resolver';
|
|
||||||
import {Console} from '../private_import_core';
|
|
||||||
import {DomElementSchemaRegistry} from '../schema/dom_element_schema_registry';
|
|
||||||
import {StyleCompiler} from '../style_compiler';
|
|
||||||
import {TemplateParser} from '../template_parser/template_parser';
|
|
||||||
import {createOfflineCompileUrlResolver} from '../url_resolver';
|
|
||||||
import {ViewCompiler} from '../view_compiler/view_compiler';
|
|
||||||
|
|
||||||
import {AotCompiler} from './compiler';
|
|
||||||
import {AotCompilerHost} from './compiler_host';
|
|
||||||
import {AotCompilerOptions} from './compiler_options';
|
|
||||||
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
|
||||||
import {StaticReflector} from './static_reflector';
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Creates a new AotCompiler based on options and a host.
|
|
||||||
*/
|
|
||||||
export function createAotCompiler(compilerHost: AotCompilerHost, options: AotCompilerOptions):
|
|
||||||
{compiler: AotCompiler, reflector: StaticReflector} {
|
|
||||||
let translations: string = options.translations || '';
|
|
||||||
|
|
||||||
const urlResolver = createOfflineCompileUrlResolver();
|
|
||||||
const staticReflector = new StaticReflector(compilerHost);
|
|
||||||
StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
|
||||||
const htmlParser = new I18NHtmlParser(new HtmlParser(), translations, options.i18nFormat);
|
|
||||||
const config = new CompilerConfig({
|
|
||||||
genDebugInfo: options.debug === true,
|
|
||||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
|
||||||
logBindingUpdate: false,
|
|
||||||
useJit: false
|
|
||||||
});
|
|
||||||
const normalizer = new DirectiveNormalizer(
|
|
||||||
{get: (url: string) => compilerHost.loadResource(url)}, urlResolver, htmlParser, config);
|
|
||||||
const expressionParser = new Parser(new Lexer());
|
|
||||||
const elementSchemaRegistry = new DomElementSchemaRegistry();
|
|
||||||
const console = new Console();
|
|
||||||
const tmplParser =
|
|
||||||
new TemplateParser(expressionParser, elementSchemaRegistry, htmlParser, console, []);
|
|
||||||
const resolver = new CompileMetadataResolver(
|
|
||||||
new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
|
||||||
new PipeResolver(staticReflector), elementSchemaRegistry, normalizer, staticReflector);
|
|
||||||
// TODO(vicb): do not pass options.i18nFormat here
|
|
||||||
const compiler = new AotCompiler(
|
|
||||||
resolver, tmplParser, new StyleCompiler(urlResolver),
|
|
||||||
new ViewCompiler(config, elementSchemaRegistry),
|
|
||||||
new DirectiveWrapperCompiler(config, expressionParser, elementSchemaRegistry, console),
|
|
||||||
new NgModuleCompiler(), new TypeScriptEmitter(compilerHost), options.locale,
|
|
||||||
options.i18nFormat, new AnimationParser(elementSchemaRegistry), staticReflector, options);
|
|
||||||
return {compiler, reflector: staticReflector};
|
|
||||||
}
|
|
@ -1,24 +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 {ImportResolver} from '../output/path_util';
|
|
||||||
|
|
||||||
import {StaticReflectorHost} from './static_reflector';
|
|
||||||
import {StaticSymbol} from './static_symbol';
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The host of the AotCompiler disconnects the implementation from TypeScript / other language
|
|
||||||
* services and from underlying file systems.
|
|
||||||
*/
|
|
||||||
export interface AotCompilerHost extends StaticReflectorHost, ImportResolver {
|
|
||||||
/**
|
|
||||||
* Loads a resource (e.g. html / css)
|
|
||||||
*/
|
|
||||||
loadResource(path: string): Promise<string>;
|
|
||||||
}
|
|
@ -1,16 +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
|
|
||||||
*/
|
|
||||||
|
|
||||||
export interface AotCompilerOptions {
|
|
||||||
debug?: boolean;
|
|
||||||
locale?: string;
|
|
||||||
i18nFormat?: string;
|
|
||||||
translations?: string;
|
|
||||||
includeFilePattern?: RegExp;
|
|
||||||
excludeFilePattern?: RegExp;
|
|
||||||
}
|
|
@ -1,20 +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
|
|
||||||
*/
|
|
||||||
|
|
||||||
export function isStaticSymbol(value: any): value is StaticSymbol {
|
|
||||||
return typeof value === 'object' && value !== null && value['name'] && value['filePath'];
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A token representing the a reference to a static type.
|
|
||||||
*
|
|
||||||
* This token is unique for a filePath and name and can be used as a hash table key.
|
|
||||||
*/
|
|
||||||
export class StaticSymbol {
|
|
||||||
constructor(public filePath: string, public name: string, public members?: string[]) {}
|
|
||||||
}
|
|
@ -718,6 +718,15 @@ function _normalizeArray(obj: any[]): any[] {
|
|||||||
return obj || [];
|
return obj || [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export function isStaticSymbol(value: any): value is StaticSymbol {
|
||||||
|
return typeof value === 'object' && value !== null && value['name'] && value['filePath'];
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface StaticSymbol {
|
||||||
|
name: string;
|
||||||
|
filePath: string;
|
||||||
|
}
|
||||||
|
|
||||||
export class ProviderMeta {
|
export class ProviderMeta {
|
||||||
token: any;
|
token: any;
|
||||||
useClass: Type<any>;
|
useClass: Type<any>;
|
||||||
|
@ -8,29 +8,28 @@
|
|||||||
|
|
||||||
import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Inject, Injectable, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore} from '@angular/core';
|
import {COMPILER_OPTIONS, Compiler, CompilerFactory, CompilerOptions, Inject, Injectable, Optional, PLATFORM_INITIALIZER, PlatformRef, Provider, ReflectiveInjector, TRANSLATIONS, TRANSLATIONS_FORMAT, Type, ViewEncapsulation, createPlatformFactory, isDevMode, platformCore} from '@angular/core';
|
||||||
|
|
||||||
import {AnimationParser} from '../animation/animation_parser';
|
import {AnimationParser} from './animation/animation_parser';
|
||||||
import {CompilerConfig} from '../config';
|
import {CompilerConfig} from './config';
|
||||||
import {DirectiveNormalizer} from '../directive_normalizer';
|
import {DirectiveNormalizer} from './directive_normalizer';
|
||||||
import {DirectiveResolver} from '../directive_resolver';
|
import {DirectiveResolver} from './directive_resolver';
|
||||||
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
import {DirectiveWrapperCompiler} from './directive_wrapper_compiler';
|
||||||
import {Lexer} from '../expression_parser/lexer';
|
import {Lexer} from './expression_parser/lexer';
|
||||||
import {Parser} from '../expression_parser/parser';
|
import {Parser} from './expression_parser/parser';
|
||||||
import * as i18n from '../i18n/index';
|
import * as i18n from './i18n/index';
|
||||||
import {CompileMetadataResolver} from '../metadata_resolver';
|
import {CompileMetadataResolver} from './metadata_resolver';
|
||||||
import {HtmlParser} from '../ml_parser/html_parser';
|
import {HtmlParser} from './ml_parser/html_parser';
|
||||||
import {NgModuleCompiler} from '../ng_module_compiler';
|
import {NgModuleCompiler} from './ng_module_compiler';
|
||||||
import {NgModuleResolver} from '../ng_module_resolver';
|
import {NgModuleResolver} from './ng_module_resolver';
|
||||||
import {PipeResolver} from '../pipe_resolver';
|
import {PipeResolver} from './pipe_resolver';
|
||||||
import {Console, ReflectionCapabilities, Reflector, ReflectorReader, reflector} from '../private_import_core';
|
import {Console, ReflectionCapabilities, Reflector, ReflectorReader, reflector} from './private_import_core';
|
||||||
import {ResourceLoader} from '../resource_loader';
|
import {ResourceLoader} from './resource_loader';
|
||||||
import {DomElementSchemaRegistry} from '../schema/dom_element_schema_registry';
|
import {RuntimeCompiler} from './runtime_compiler';
|
||||||
import {ElementSchemaRegistry} from '../schema/element_schema_registry';
|
import {DomElementSchemaRegistry} from './schema/dom_element_schema_registry';
|
||||||
import {StyleCompiler} from '../style_compiler';
|
import {ElementSchemaRegistry} from './schema/element_schema_registry';
|
||||||
import {TemplateParser} from '../template_parser/template_parser';
|
import {StyleCompiler} from './style_compiler';
|
||||||
import {DEFAULT_PACKAGE_URL_PROVIDER, UrlResolver} from '../url_resolver';
|
import {TemplateParser} from './template_parser/template_parser';
|
||||||
import {ViewCompiler} from '../view_compiler/view_compiler';
|
import {DEFAULT_PACKAGE_URL_PROVIDER, UrlResolver} from './url_resolver';
|
||||||
|
import {ViewCompiler} from './view_compiler/view_compiler';
|
||||||
import {JitCompiler} from './compiler';
|
|
||||||
|
|
||||||
const _NO_RESOURCE_LOADER: ResourceLoader = {
|
const _NO_RESOURCE_LOADER: ResourceLoader = {
|
||||||
get(url: string): Promise<string>{
|
get(url: string): Promise<string>{
|
||||||
@ -39,7 +38,7 @@ const _NO_RESOURCE_LOADER: ResourceLoader = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A set of providers that provide `JitCompiler` and its dependencies to use for
|
* A set of providers that provide `RuntimeCompiler` and its dependencies to use for
|
||||||
* template compilation.
|
* template compilation.
|
||||||
*/
|
*/
|
||||||
export const COMPILER_PROVIDERS: Array<any|Type<any>|{[k: string]: any}|any[]> = [
|
export const COMPILER_PROVIDERS: Array<any|Type<any>|{[k: string]: any}|any[]> = [
|
||||||
@ -69,8 +68,8 @@ export const COMPILER_PROVIDERS: Array<any|Type<any>|{[k: string]: any}|any[]> =
|
|||||||
NgModuleCompiler,
|
NgModuleCompiler,
|
||||||
DirectiveWrapperCompiler,
|
DirectiveWrapperCompiler,
|
||||||
{provide: CompilerConfig, useValue: new CompilerConfig()},
|
{provide: CompilerConfig, useValue: new CompilerConfig()},
|
||||||
JitCompiler,
|
RuntimeCompiler,
|
||||||
{provide: Compiler, useExisting: JitCompiler},
|
{provide: Compiler, useExisting: RuntimeCompiler},
|
||||||
DomElementSchemaRegistry,
|
DomElementSchemaRegistry,
|
||||||
{provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry},
|
{provide: ElementSchemaRegistry, useExisting: DomElementSchemaRegistry},
|
||||||
UrlResolver,
|
UrlResolver,
|
||||||
@ -82,7 +81,7 @@ export const COMPILER_PROVIDERS: Array<any|Type<any>|{[k: string]: any}|any[]> =
|
|||||||
|
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class JitCompilerFactory implements CompilerFactory {
|
export class RuntimeCompilerFactory implements CompilerFactory {
|
||||||
private _defaultOptions: CompilerOptions[];
|
private _defaultOptions: CompilerOptions[];
|
||||||
constructor(@Inject(COMPILER_OPTIONS) defaultOptions: CompilerOptions[]) {
|
constructor(@Inject(COMPILER_OPTIONS) defaultOptions: CompilerOptions[]) {
|
||||||
this._defaultOptions = [<CompilerOptions>{
|
this._defaultOptions = [<CompilerOptions>{
|
||||||
@ -129,7 +128,7 @@ function _initReflector() {
|
|||||||
*/
|
*/
|
||||||
export const platformCoreDynamic = createPlatformFactory(platformCore, 'coreDynamic', [
|
export const platformCoreDynamic = createPlatformFactory(platformCore, 'coreDynamic', [
|
||||||
{provide: COMPILER_OPTIONS, useValue: {}, multi: true},
|
{provide: COMPILER_OPTIONS, useValue: {}, multi: true},
|
||||||
{provide: CompilerFactory, useClass: JitCompilerFactory},
|
{provide: CompilerFactory, useClass: RuntimeCompilerFactory},
|
||||||
{provide: PLATFORM_INITIALIZER, useValue: _initReflector, multi: true},
|
{provide: PLATFORM_INITIALIZER, useValue: _initReflector, multi: true},
|
||||||
]);
|
]);
|
||||||
|
|
@ -1,117 +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
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Extract i18n messages from source code
|
|
||||||
*/
|
|
||||||
import {ViewEncapsulation} from '@angular/core';
|
|
||||||
|
|
||||||
import {analyzeAndValidateNgModules, extractProgramSymbols, loadNgModuleDirectives} from '../aot/compiler';
|
|
||||||
import {StaticAndDynamicReflectionCapabilities} from '../aot/static_reflection_capabilities';
|
|
||||||
import {StaticReflector, StaticReflectorHost} from '../aot/static_reflector';
|
|
||||||
import {CompileDirectiveMetadata} from '../compile_metadata';
|
|
||||||
import {CompilerConfig} from '../config';
|
|
||||||
import {DirectiveNormalizer} from '../directive_normalizer';
|
|
||||||
import {DirectiveResolver} from '../directive_resolver';
|
|
||||||
import {CompileMetadataResolver} from '../metadata_resolver';
|
|
||||||
import {HtmlParser} from '../ml_parser/html_parser';
|
|
||||||
import {InterpolationConfig} from '../ml_parser/interpolation_config';
|
|
||||||
import {NgModuleResolver} from '../ng_module_resolver';
|
|
||||||
import {ParseError} from '../parse_util';
|
|
||||||
import {PipeResolver} from '../pipe_resolver';
|
|
||||||
import {Console} from '../private_import_core';
|
|
||||||
import {DomElementSchemaRegistry} from '../schema/dom_element_schema_registry';
|
|
||||||
import {createOfflineCompileUrlResolver} from '../url_resolver';
|
|
||||||
|
|
||||||
import {I18NHtmlParser} from './i18n_html_parser';
|
|
||||||
import {MessageBundle} from './message_bundle';
|
|
||||||
|
|
||||||
export interface ExtractorOptions {
|
|
||||||
includeFilePattern?: RegExp;
|
|
||||||
excludeFilePattern?: RegExp;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The host of the Extractor disconnects the implementation from TypeScript / other language
|
|
||||||
* services and from underlying file systems.
|
|
||||||
*/
|
|
||||||
export interface ExtractorHost extends StaticReflectorHost {
|
|
||||||
/**
|
|
||||||
* Loads a resource (e.g. html / css)
|
|
||||||
*/
|
|
||||||
loadResource(path: string): Promise<string>;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class Extractor {
|
|
||||||
constructor(
|
|
||||||
private options: ExtractorOptions, public host: ExtractorHost,
|
|
||||||
private staticReflector: StaticReflector, private messageBundle: MessageBundle,
|
|
||||||
private metadataResolver: CompileMetadataResolver) {}
|
|
||||||
|
|
||||||
extract(rootFiles: string[]): Promise<MessageBundle> {
|
|
||||||
const programSymbols = extractProgramSymbols(this.staticReflector, rootFiles, this.options);
|
|
||||||
const {ngModuleByPipeOrDirective, files, ngModules} =
|
|
||||||
analyzeAndValidateNgModules(programSymbols, this.options, this.metadataResolver);
|
|
||||||
return loadNgModuleDirectives(ngModules).then(() => {
|
|
||||||
const errors: ParseError[] = [];
|
|
||||||
|
|
||||||
files.forEach(file => {
|
|
||||||
const compMetas: CompileDirectiveMetadata[] = [];
|
|
||||||
file.directives.forEach(directiveType => {
|
|
||||||
const dirMeta = this.metadataResolver.getDirectiveMetadata(directiveType);
|
|
||||||
if (dirMeta && dirMeta.isComponent) {
|
|
||||||
compMetas.push(dirMeta);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
compMetas.forEach(compMeta => {
|
|
||||||
const html = compMeta.template.template;
|
|
||||||
const interpolationConfig =
|
|
||||||
InterpolationConfig.fromArray(compMeta.template.interpolation);
|
|
||||||
errors.push(
|
|
||||||
...this.messageBundle.updateFromTemplate(html, file.srcUrl, interpolationConfig));
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
if (errors.length) {
|
|
||||||
throw new Error(errors.map(e => e.toString()).join('\n'));
|
|
||||||
}
|
|
||||||
|
|
||||||
return this.messageBundle;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
static create(host: ExtractorHost, options: ExtractorOptions):
|
|
||||||
{extractor: Extractor, staticReflector: StaticReflector} {
|
|
||||||
const htmlParser = new I18NHtmlParser(new HtmlParser());
|
|
||||||
|
|
||||||
const urlResolver = createOfflineCompileUrlResolver();
|
|
||||||
const staticReflector = new StaticReflector(host);
|
|
||||||
StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
|
||||||
|
|
||||||
const config = new CompilerConfig({
|
|
||||||
genDebugInfo: false,
|
|
||||||
defaultEncapsulation: ViewEncapsulation.Emulated,
|
|
||||||
logBindingUpdate: false,
|
|
||||||
useJit: false
|
|
||||||
});
|
|
||||||
|
|
||||||
const normalizer = new DirectiveNormalizer(
|
|
||||||
{get: (url: string) => host.loadResource(url)}, urlResolver, htmlParser, config);
|
|
||||||
const elementSchemaRegistry = new DomElementSchemaRegistry();
|
|
||||||
const resolver = new CompileMetadataResolver(
|
|
||||||
new NgModuleResolver(staticReflector), new DirectiveResolver(staticReflector),
|
|
||||||
new PipeResolver(staticReflector), elementSchemaRegistry, normalizer, staticReflector);
|
|
||||||
|
|
||||||
// TODO(vicb): implicit tags & attributes
|
|
||||||
const messageBundle = new MessageBundle(htmlParser, [], {});
|
|
||||||
|
|
||||||
const extractor = new Extractor(options, host, staticReflector, messageBundle, resolver);
|
|
||||||
return {extractor, staticReflector};
|
|
||||||
}
|
|
||||||
}
|
|
@ -6,7 +6,6 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
export {Extractor, ExtractorHost, ExtractorOptions} from './extractor';
|
|
||||||
export {I18NHtmlParser} from './i18n_html_parser';
|
export {I18NHtmlParser} from './i18n_html_parser';
|
||||||
export {MessageBundle} from './message_bundle';
|
export {MessageBundle} from './message_bundle';
|
||||||
export {Serializer} from './serializers/serializer';
|
export {Serializer} from './serializers/serializer';
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import {ANALYZE_FOR_ENTRY_COMPONENTS, AnimationTransitionEvent, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
import {ANALYZE_FOR_ENTRY_COMPONENTS, AnimationTransitionEvent, ChangeDetectionStrategy, ChangeDetectorRef, ComponentFactory, ComponentFactoryResolver, ComponentRef, ElementRef, Injector, LOCALE_ID, NgModuleFactory, QueryList, RenderComponentType, Renderer, SecurityContext, SimpleChange, TRANSLATIONS_FORMAT, TemplateRef, ViewContainerRef, ViewEncapsulation} from '@angular/core';
|
||||||
|
|
||||||
import {StaticSymbol, isStaticSymbol} from './aot/static_symbol';
|
|
||||||
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
|
import {CompileIdentifierMetadata, CompileTokenMetadata} from './compile_metadata';
|
||||||
import {AnimationGroupPlayer, AnimationKeyframe, AnimationSequencePlayer, AnimationStyles, AnimationTransition, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, ComponentRef_, DebugAppView, DebugContext, NgModuleInjector, NoOpAnimationPlayer, StaticNodeDebugInfo, TemplateRef_, UNINITIALIZED, ValueUnwrapper, ViewContainer, ViewType, balanceAnimationKeyframes, clearStyles, collectAndResolveStyles, devModeEqual, prepareFinalAnimationStyles, reflector, registerModuleFactory, renderStyles, view_utils} from './private_import_core';
|
import {AnimationGroupPlayer, AnimationKeyframe, AnimationSequencePlayer, AnimationStyles, AnimationTransition, AppView, ChangeDetectorStatus, CodegenComponentFactoryResolver, ComponentRef_, DebugAppView, DebugContext, NgModuleInjector, NoOpAnimationPlayer, StaticNodeDebugInfo, TemplateRef_, UNINITIALIZED, ValueUnwrapper, ViewContainer, ViewType, balanceAnimationKeyframes, clearStyles, collectAndResolveStyles, devModeEqual, prepareFinalAnimationStyles, reflector, registerModuleFactory, renderStyles, view_utils} from './private_import_core';
|
||||||
|
|
||||||
@ -340,21 +339,19 @@ export class Identifiers {
|
|||||||
|
|
||||||
export function assetUrl(pkg: string, path: string = null, type: string = 'src'): string {
|
export function assetUrl(pkg: string, path: string = null, type: string = 'src'): string {
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
return `@angular/${pkg}/index`;
|
return `asset:@angular/lib/${pkg}/index`;
|
||||||
} else {
|
} else {
|
||||||
return `@angular/${pkg}/${type}/${path}`;
|
return `asset:@angular/lib/${pkg}/src/${path}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function resolveIdentifier(identifier: IdentifierSpec) {
|
export function resolveIdentifier(identifier: IdentifierSpec) {
|
||||||
let moduleUrl = identifier.moduleUrl;
|
return new CompileIdentifierMetadata({
|
||||||
const reference =
|
name: identifier.name,
|
||||||
reflector.resolveIdentifier(identifier.name, identifier.moduleUrl, identifier.runtime);
|
moduleUrl: identifier.moduleUrl,
|
||||||
if (isStaticSymbol(reference)) {
|
reference:
|
||||||
moduleUrl = reference.filePath;
|
reflector.resolveIdentifier(identifier.name, identifier.moduleUrl, identifier.runtime)
|
||||||
}
|
});
|
||||||
return new CompileIdentifierMetadata(
|
|
||||||
{name: identifier.name, moduleUrl: moduleUrl, reference: reference});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function identifierToken(identifier: CompileIdentifierMetadata): CompileTokenMetadata {
|
export function identifierToken(identifier: CompileIdentifierMetadata): CompileTokenMetadata {
|
||||||
|
@ -8,7 +8,6 @@
|
|||||||
|
|
||||||
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, Attribute, ChangeDetectionStrategy, Component, Host, Inject, Injectable, ModuleWithProviders, Optional, Provider, Query, SchemaMetadata, Self, SkipSelf, Type, resolveForwardRef} from '@angular/core';
|
import {AnimationAnimateMetadata, AnimationEntryMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationStateDeclarationMetadata, AnimationStateMetadata, AnimationStateTransitionMetadata, AnimationStyleMetadata, AnimationWithStepsMetadata, Attribute, ChangeDetectionStrategy, Component, Host, Inject, Injectable, ModuleWithProviders, Optional, Provider, Query, SchemaMetadata, Self, SkipSelf, Type, resolveForwardRef} from '@angular/core';
|
||||||
|
|
||||||
import {isStaticSymbol} from './aot/static_symbol';
|
|
||||||
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
import {assertArrayOfStrings, assertInterpolationSymbols} from './assertions';
|
||||||
import * as cpl from './compile_metadata';
|
import * as cpl from './compile_metadata';
|
||||||
import {DirectiveNormalizer} from './directive_normalizer';
|
import {DirectiveNormalizer} from './directive_normalizer';
|
||||||
@ -922,16 +921,16 @@ function flattenAndDedupeArray(tree: any[]): Array<any> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function isValidType(value: any): boolean {
|
function isValidType(value: any): boolean {
|
||||||
return isStaticSymbol(value) || (value instanceof Type);
|
return cpl.isStaticSymbol(value) || (value instanceof Type);
|
||||||
}
|
}
|
||||||
|
|
||||||
function staticTypeModuleUrl(value: any): string {
|
function staticTypeModuleUrl(value: any): string {
|
||||||
return isStaticSymbol(value) ? value.filePath : null;
|
return cpl.isStaticSymbol(value) ? value.filePath : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
function componentModuleUrl(
|
function componentModuleUrl(
|
||||||
reflector: ReflectorReader, type: Type<any>, cmpMetadata: Component): string {
|
reflector: ReflectorReader, type: Type<any>, cmpMetadata: Component): string {
|
||||||
if (isStaticSymbol(type)) {
|
if (cpl.isStaticSymbol(type)) {
|
||||||
return staticTypeModuleUrl(type);
|
return staticTypeModuleUrl(type);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -957,7 +956,7 @@ function convertToCompileValue(
|
|||||||
class _CompileValueConverter extends ValueTransformer {
|
class _CompileValueConverter extends ValueTransformer {
|
||||||
visitOther(value: any, targetIdentifiers: cpl.CompileIdentifierMetadata[]): any {
|
visitOther(value: any, targetIdentifiers: cpl.CompileIdentifierMetadata[]): any {
|
||||||
let identifier: cpl.CompileIdentifierMetadata;
|
let identifier: cpl.CompileIdentifierMetadata;
|
||||||
if (isStaticSymbol(value)) {
|
if (cpl.isStaticSymbol(value)) {
|
||||||
identifier = new cpl.CompileIdentifierMetadata(
|
identifier = new cpl.CompileIdentifierMetadata(
|
||||||
{name: value.name, moduleUrl: value.filePath, reference: value});
|
{name: value.name, moduleUrl: value.filePath, reference: value});
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,30 +8,114 @@
|
|||||||
|
|
||||||
import {SchemaMetadata} from '@angular/core';
|
import {SchemaMetadata} from '@angular/core';
|
||||||
|
|
||||||
import {AnimationCompiler} from '../animation/animation_compiler';
|
import {AnimationCompiler} from './animation/animation_compiler';
|
||||||
import {AnimationParser} from '../animation/animation_parser';
|
import {AnimationParser} from './animation/animation_parser';
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, createHostComponentMeta} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, CompileProviderMetadata, StaticSymbol, createHostComponentMeta} from './compile_metadata';
|
||||||
import {DirectiveNormalizer} from '../directive_normalizer';
|
import {DirectiveNormalizer} from './directive_normalizer';
|
||||||
import {DirectiveWrapperCompileResult, DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
import {DirectiveWrapperCompileResult, DirectiveWrapperCompiler} from './directive_wrapper_compiler';
|
||||||
import {ListWrapper} from '../facade/collection';
|
import {ListWrapper} from './facade/collection';
|
||||||
import {Identifiers, resolveIdentifier, resolveIdentifierToken} from '../identifiers';
|
import {Identifiers, resolveIdentifier, resolveIdentifierToken} from './identifiers';
|
||||||
import {CompileMetadataResolver} from '../metadata_resolver';
|
import {CompileMetadataResolver} from './metadata_resolver';
|
||||||
import {NgModuleCompiler} from '../ng_module_compiler';
|
import {NgModuleCompiler} from './ng_module_compiler';
|
||||||
import {OutputEmitter} from '../output/abstract_emitter';
|
import {OutputEmitter} from './output/abstract_emitter';
|
||||||
import * as o from '../output/output_ast';
|
import * as o from './output/output_ast';
|
||||||
import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
|
import {CompiledStylesheet, StyleCompiler} from './style_compiler';
|
||||||
import {TemplateParser} from '../template_parser/template_parser';
|
import {TemplateParser} from './template_parser/template_parser';
|
||||||
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency, ViewCompileResult, ViewCompiler} from '../view_compiler/view_compiler';
|
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency, ViewCompileResult, ViewCompiler} from './view_compiler/view_compiler';
|
||||||
|
|
||||||
import {AotCompilerOptions} from './compiler_options';
|
|
||||||
import {StaticReflector} from './static_reflector';
|
|
||||||
import {StaticSymbol} from './static_symbol';
|
|
||||||
|
|
||||||
export class SourceModule {
|
export class SourceModule {
|
||||||
constructor(public fileUrl: string, public moduleUrl: string, public source: string) {}
|
constructor(public fileUrl: string, public moduleUrl: string, public source: string) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class AotCompiler {
|
export interface NgAnalyzedModules {
|
||||||
|
ngModules: CompileNgModuleMetadata[];
|
||||||
|
ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>;
|
||||||
|
files: Array<{srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}>;
|
||||||
|
symbolsMissingModule?: StaticSymbol[];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns all the source files and a mapping from modules to directives
|
||||||
|
export function analyzeNgModules(
|
||||||
|
programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean},
|
||||||
|
metadataResolver: CompileMetadataResolver): NgAnalyzedModules {
|
||||||
|
const {ngModules, symbolsMissingModule} =
|
||||||
|
_createNgModules(programStaticSymbols, options, metadataResolver);
|
||||||
|
return _analyzeNgModules(ngModules, symbolsMissingModule);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
export function analyzeAndValidateNgModules(
|
||||||
|
programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean},
|
||||||
|
metadataResolver: CompileMetadataResolver): NgAnalyzedModules {
|
||||||
|
const result = analyzeNgModules(programStaticSymbols, options, metadataResolver);
|
||||||
|
if (result.symbolsMissingModule && result.symbolsMissingModule.length) {
|
||||||
|
const messages = result.symbolsMissingModule.map(
|
||||||
|
s => `Cannot determine the module for class ${s.name} in ${s.filePath}!`);
|
||||||
|
throw new Error(messages.join('\n'));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Wait for the directives in the given modules have been loaded
|
||||||
|
export function loadNgModuleDirectives(ngModules: CompileNgModuleMetadata[]) {
|
||||||
|
return Promise
|
||||||
|
.all(ListWrapper.flatten(ngModules.map(
|
||||||
|
(ngModule) => ngModule.transitiveModule.directiveLoaders.map(loader => loader()))))
|
||||||
|
.then(() => {});
|
||||||
|
}
|
||||||
|
|
||||||
|
function _analyzeNgModules(
|
||||||
|
ngModuleMetas: CompileNgModuleMetadata[],
|
||||||
|
symbolsMissingModule: StaticSymbol[]): NgAnalyzedModules {
|
||||||
|
const moduleMetasByRef = new Map<any, CompileNgModuleMetadata>();
|
||||||
|
ngModuleMetas.forEach((ngModule) => moduleMetasByRef.set(ngModule.type.reference, ngModule));
|
||||||
|
const ngModuleByPipeOrDirective = new Map<StaticSymbol, CompileNgModuleMetadata>();
|
||||||
|
const ngModulesByFile = new Map<string, StaticSymbol[]>();
|
||||||
|
const ngDirectivesByFile = new Map<string, StaticSymbol[]>();
|
||||||
|
const filePaths = new Set<string>();
|
||||||
|
|
||||||
|
// Looping over all modules to construct:
|
||||||
|
// - a map from file to modules `ngModulesByFile`,
|
||||||
|
// - a map from file to directives `ngDirectivesByFile`,
|
||||||
|
// - a map from directive/pipe to module `ngModuleByPipeOrDirective`.
|
||||||
|
ngModuleMetas.forEach((ngModuleMeta) => {
|
||||||
|
const srcFileUrl = ngModuleMeta.type.reference.filePath;
|
||||||
|
filePaths.add(srcFileUrl);
|
||||||
|
ngModulesByFile.set(
|
||||||
|
srcFileUrl, (ngModulesByFile.get(srcFileUrl) || []).concat(ngModuleMeta.type.reference));
|
||||||
|
|
||||||
|
ngModuleMeta.declaredDirectives.forEach((dirIdentifier) => {
|
||||||
|
const fileUrl = dirIdentifier.reference.filePath;
|
||||||
|
filePaths.add(fileUrl);
|
||||||
|
ngDirectivesByFile.set(
|
||||||
|
fileUrl, (ngDirectivesByFile.get(fileUrl) || []).concat(dirIdentifier.reference));
|
||||||
|
ngModuleByPipeOrDirective.set(dirIdentifier.reference, ngModuleMeta);
|
||||||
|
});
|
||||||
|
ngModuleMeta.declaredPipes.forEach((pipeIdentifier) => {
|
||||||
|
const fileUrl = pipeIdentifier.reference.filePath;
|
||||||
|
filePaths.add(fileUrl);
|
||||||
|
ngModuleByPipeOrDirective.set(pipeIdentifier.reference, ngModuleMeta);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
const files: {srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}[] = [];
|
||||||
|
|
||||||
|
filePaths.forEach((srcUrl) => {
|
||||||
|
const directives = ngDirectivesByFile.get(srcUrl) || [];
|
||||||
|
const ngModules = ngModulesByFile.get(srcUrl) || [];
|
||||||
|
files.push({srcUrl, directives, ngModules});
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
// map directive/pipe to module
|
||||||
|
ngModuleByPipeOrDirective,
|
||||||
|
// list modules and directives for every source file
|
||||||
|
files,
|
||||||
|
ngModules: ngModuleMetas, symbolsMissingModule
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class OfflineCompiler {
|
||||||
private _animationCompiler = new AnimationCompiler();
|
private _animationCompiler = new AnimationCompiler();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@ -40,15 +124,14 @@ export class AotCompiler {
|
|||||||
private _dirWrapperCompiler: DirectiveWrapperCompiler,
|
private _dirWrapperCompiler: DirectiveWrapperCompiler,
|
||||||
private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter,
|
private _ngModuleCompiler: NgModuleCompiler, private _outputEmitter: OutputEmitter,
|
||||||
private _localeId: string, private _translationFormat: string,
|
private _localeId: string, private _translationFormat: string,
|
||||||
private _animationParser: AnimationParser, private _staticReflector: StaticReflector,
|
private _animationParser: AnimationParser) {}
|
||||||
private _options: AotCompilerOptions) {}
|
|
||||||
|
|
||||||
clearCache() { this._metadataResolver.clearCache(); }
|
clearCache() { this._metadataResolver.clearCache(); }
|
||||||
|
|
||||||
compileAll(rootFiles: string[]): Promise<SourceModule[]> {
|
compileModules(staticSymbols: StaticSymbol[], options: {transitiveModules: boolean}):
|
||||||
const programSymbols = extractProgramSymbols(this._staticReflector, rootFiles, this._options);
|
Promise<SourceModule[]> {
|
||||||
const {ngModuleByPipeOrDirective, files, ngModules} =
|
const {ngModuleByPipeOrDirective, files, ngModules} =
|
||||||
analyzeAndValidateNgModules(programSymbols, this._options, this._metadataResolver);
|
analyzeAndValidateNgModules(staticSymbols, options, this._metadataResolver);
|
||||||
return loadNgModuleDirectives(ngModules).then(() => {
|
return loadNgModuleDirectives(ngModules).then(() => {
|
||||||
const sourceModules = files.map(
|
const sourceModules = files.map(
|
||||||
file => this._compileSrcFile(
|
file => this._compileSrcFile(
|
||||||
@ -273,130 +356,11 @@ function _splitTypescriptSuffix(path: string): string[] {
|
|||||||
return [path, ''];
|
return [path, ''];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface NgAnalyzedModules {
|
|
||||||
ngModules: CompileNgModuleMetadata[];
|
|
||||||
ngModuleByPipeOrDirective: Map<StaticSymbol, CompileNgModuleMetadata>;
|
|
||||||
files: Array<{srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}>;
|
|
||||||
symbolsMissingModule?: StaticSymbol[];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Returns all the source files and a mapping from modules to directives
|
|
||||||
export function analyzeNgModules(
|
|
||||||
programStaticSymbols: StaticSymbol[],
|
|
||||||
options: {includeFilePattern?: RegExp, excludeFilePattern?: RegExp},
|
|
||||||
metadataResolver: CompileMetadataResolver): NgAnalyzedModules {
|
|
||||||
const {ngModules, symbolsMissingModule} =
|
|
||||||
_createNgModules(programStaticSymbols, options, metadataResolver);
|
|
||||||
return _analyzeNgModules(ngModules, symbolsMissingModule);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function analyzeAndValidateNgModules(
|
|
||||||
programStaticSymbols: StaticSymbol[],
|
|
||||||
options: {includeFilePattern?: RegExp, excludeFilePattern?: RegExp},
|
|
||||||
metadataResolver: CompileMetadataResolver): NgAnalyzedModules {
|
|
||||||
const result = analyzeNgModules(programStaticSymbols, options, metadataResolver);
|
|
||||||
if (result.symbolsMissingModule && result.symbolsMissingModule.length) {
|
|
||||||
const messages = result.symbolsMissingModule.map(
|
|
||||||
s => `Cannot determine the module for class ${s.name} in ${s.filePath}!`);
|
|
||||||
throw new Error(messages.join('\n'));
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for the directives in the given modules have been loaded
|
|
||||||
export function loadNgModuleDirectives(ngModules: CompileNgModuleMetadata[]) {
|
|
||||||
return Promise
|
|
||||||
.all(ListWrapper.flatten(ngModules.map(
|
|
||||||
(ngModule) => ngModule.transitiveModule.directiveLoaders.map(loader => loader()))))
|
|
||||||
.then(() => {});
|
|
||||||
}
|
|
||||||
|
|
||||||
function _analyzeNgModules(
|
|
||||||
ngModuleMetas: CompileNgModuleMetadata[],
|
|
||||||
symbolsMissingModule: StaticSymbol[]): NgAnalyzedModules {
|
|
||||||
const moduleMetasByRef = new Map<any, CompileNgModuleMetadata>();
|
|
||||||
ngModuleMetas.forEach((ngModule) => moduleMetasByRef.set(ngModule.type.reference, ngModule));
|
|
||||||
const ngModuleByPipeOrDirective = new Map<StaticSymbol, CompileNgModuleMetadata>();
|
|
||||||
const ngModulesByFile = new Map<string, StaticSymbol[]>();
|
|
||||||
const ngDirectivesByFile = new Map<string, StaticSymbol[]>();
|
|
||||||
const filePaths = new Set<string>();
|
|
||||||
|
|
||||||
// Looping over all modules to construct:
|
|
||||||
// - a map from file to modules `ngModulesByFile`,
|
|
||||||
// - a map from file to directives `ngDirectivesByFile`,
|
|
||||||
// - a map from directive/pipe to module `ngModuleByPipeOrDirective`.
|
|
||||||
ngModuleMetas.forEach((ngModuleMeta) => {
|
|
||||||
const srcFileUrl = ngModuleMeta.type.reference.filePath;
|
|
||||||
filePaths.add(srcFileUrl);
|
|
||||||
ngModulesByFile.set(
|
|
||||||
srcFileUrl, (ngModulesByFile.get(srcFileUrl) || []).concat(ngModuleMeta.type.reference));
|
|
||||||
|
|
||||||
ngModuleMeta.declaredDirectives.forEach((dirIdentifier) => {
|
|
||||||
const fileUrl = dirIdentifier.reference.filePath;
|
|
||||||
filePaths.add(fileUrl);
|
|
||||||
ngDirectivesByFile.set(
|
|
||||||
fileUrl, (ngDirectivesByFile.get(fileUrl) || []).concat(dirIdentifier.reference));
|
|
||||||
ngModuleByPipeOrDirective.set(dirIdentifier.reference, ngModuleMeta);
|
|
||||||
});
|
|
||||||
ngModuleMeta.declaredPipes.forEach((pipeIdentifier) => {
|
|
||||||
const fileUrl = pipeIdentifier.reference.filePath;
|
|
||||||
filePaths.add(fileUrl);
|
|
||||||
ngModuleByPipeOrDirective.set(pipeIdentifier.reference, ngModuleMeta);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
const files: {srcUrl: string, directives: StaticSymbol[], ngModules: StaticSymbol[]}[] = [];
|
|
||||||
|
|
||||||
filePaths.forEach((srcUrl) => {
|
|
||||||
const directives = ngDirectivesByFile.get(srcUrl) || [];
|
|
||||||
const ngModules = ngModulesByFile.get(srcUrl) || [];
|
|
||||||
files.push({srcUrl, directives, ngModules});
|
|
||||||
});
|
|
||||||
|
|
||||||
return {
|
|
||||||
// map directive/pipe to module
|
|
||||||
ngModuleByPipeOrDirective,
|
|
||||||
// list modules and directives for every source file
|
|
||||||
files,
|
|
||||||
ngModules: ngModuleMetas, symbolsMissingModule
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function extractProgramSymbols(
|
|
||||||
staticReflector: StaticReflector, files: string[],
|
|
||||||
options: {includeFilePattern?: RegExp, excludeFilePattern?: RegExp} = {}): StaticSymbol[] {
|
|
||||||
const staticSymbols: StaticSymbol[] = [];
|
|
||||||
files.filter(fileName => _filterFileByPatterns(fileName, options)).forEach(sourceFile => {
|
|
||||||
const moduleMetadata = staticReflector.getModuleMetadata(sourceFile);
|
|
||||||
if (!moduleMetadata) {
|
|
||||||
console.log(`WARNING: no metadata found for ${sourceFile}`);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const metadata = moduleMetadata['metadata'];
|
|
||||||
|
|
||||||
if (!metadata) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const symbol of Object.keys(metadata)) {
|
|
||||||
if (metadata[symbol] && metadata[symbol].__symbolic == 'error') {
|
|
||||||
// Ignore symbols that are only included to record error information.
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
staticSymbols.push(staticReflector.getStaticSymbol(sourceFile, symbol));
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
return staticSymbols;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the NgModules and check
|
// Load the NgModules and check
|
||||||
// that all directives / pipes that are present in the program
|
// that all directives / pipes that are present in the program
|
||||||
// are also declared by a module.
|
// are also declared by a module.
|
||||||
function _createNgModules(
|
function _createNgModules(
|
||||||
programStaticSymbols: StaticSymbol[],
|
programStaticSymbols: StaticSymbol[], options: {transitiveModules: boolean},
|
||||||
options: {includeFilePattern?: RegExp, excludeFilePattern?: RegExp},
|
|
||||||
metadataResolver: CompileMetadataResolver):
|
metadataResolver: CompileMetadataResolver):
|
||||||
{ngModules: CompileNgModuleMetadata[], symbolsMissingModule: StaticSymbol[]} {
|
{ngModules: CompileNgModuleMetadata[], symbolsMissingModule: StaticSymbol[]} {
|
||||||
const ngModules = new Map<any, CompileNgModuleMetadata>();
|
const ngModules = new Map<any, CompileNgModuleMetadata>();
|
||||||
@ -404,7 +368,7 @@ function _createNgModules(
|
|||||||
const ngModulePipesAndDirective = new Set<StaticSymbol>();
|
const ngModulePipesAndDirective = new Set<StaticSymbol>();
|
||||||
|
|
||||||
const addNgModule = (staticSymbol: any) => {
|
const addNgModule = (staticSymbol: any) => {
|
||||||
if (ngModules.has(staticSymbol) || !_filterFileByPatterns(staticSymbol.filePath, options)) {
|
if (ngModules.has(staticSymbol)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
const ngModule = metadataResolver.getUnloadedNgModuleMetadata(staticSymbol, false, false);
|
const ngModule = metadataResolver.getUnloadedNgModuleMetadata(staticSymbol, false, false);
|
||||||
@ -412,9 +376,11 @@ function _createNgModules(
|
|||||||
ngModules.set(ngModule.type.reference, ngModule);
|
ngModules.set(ngModule.type.reference, ngModule);
|
||||||
ngModule.declaredDirectives.forEach((dir) => ngModulePipesAndDirective.add(dir.reference));
|
ngModule.declaredDirectives.forEach((dir) => ngModulePipesAndDirective.add(dir.reference));
|
||||||
ngModule.declaredPipes.forEach((pipe) => ngModulePipesAndDirective.add(pipe.reference));
|
ngModule.declaredPipes.forEach((pipe) => ngModulePipesAndDirective.add(pipe.reference));
|
||||||
// For every input module add the list of transitively included modules
|
if (options.transitiveModules) {
|
||||||
|
// For every input modules add the list of transitively included modules
|
||||||
ngModule.transitiveModule.modules.forEach(modMeta => addNgModule(modMeta.type.reference));
|
ngModule.transitiveModule.modules.forEach(modMeta => addNgModule(modMeta.type.reference));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return !!ngModule;
|
return !!ngModule;
|
||||||
};
|
};
|
||||||
programStaticSymbols.forEach((staticSymbol) => {
|
programStaticSymbols.forEach((staticSymbol) => {
|
||||||
@ -430,15 +396,3 @@ function _createNgModules(
|
|||||||
|
|
||||||
return {ngModules: Array.from(ngModules.values()), symbolsMissingModule};
|
return {ngModules: Array.from(ngModules.values()), symbolsMissingModule};
|
||||||
}
|
}
|
||||||
|
|
||||||
function _filterFileByPatterns(
|
|
||||||
fileName: string, options: {includeFilePattern?: RegExp, excludeFilePattern?: RegExp} = {}) {
|
|
||||||
let match = true;
|
|
||||||
if (options.includeFilePattern) {
|
|
||||||
match = match && !!options.includeFilePattern.exec(fileName);
|
|
||||||
}
|
|
||||||
if (options.excludeFilePattern) {
|
|
||||||
match = match && !options.excludeFilePattern.exec(fileName);
|
|
||||||
}
|
|
||||||
return match;
|
|
||||||
}
|
|
@ -12,10 +12,10 @@ import {isBlank, isPresent} from '../facade/lang';
|
|||||||
import {EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
import {EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
||||||
import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
|
import {AbstractJsEmitterVisitor} from './abstract_js_emitter';
|
||||||
import * as o from './output_ast';
|
import * as o from './output_ast';
|
||||||
import {ImportResolver} from './path_util';
|
import {ImportGenerator} from './path_util';
|
||||||
|
|
||||||
export class JavaScriptEmitter implements OutputEmitter {
|
export class JavaScriptEmitter implements OutputEmitter {
|
||||||
constructor(private _importGenerator: ImportResolver) {}
|
constructor(private _importGenerator: ImportGenerator) {}
|
||||||
emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string {
|
emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string {
|
||||||
const converter = new JsEmitterVisitor(moduleUrl);
|
const converter = new JsEmitterVisitor(moduleUrl);
|
||||||
const ctx = EmitterVisitorContext.createRoot(exportedVars);
|
const ctx = EmitterVisitorContext.createRoot(exportedVars);
|
||||||
@ -25,7 +25,7 @@ export class JavaScriptEmitter implements OutputEmitter {
|
|||||||
// Note: can't write the real word for import as it screws up system.js auto detection...
|
// Note: can't write the real word for import as it screws up system.js auto detection...
|
||||||
srcParts.push(
|
srcParts.push(
|
||||||
`var ${prefix} = req` +
|
`var ${prefix} = req` +
|
||||||
`uire('${this._importGenerator.fileNameToModuleName(importedModuleUrl, moduleUrl)}');`);
|
`uire('${this._importGenerator.getImportPath(moduleUrl, importedModuleUrl)}');`);
|
||||||
});
|
});
|
||||||
srcParts.push(ctx.toSource());
|
srcParts.push(ctx.toSource());
|
||||||
return srcParts.join('\n');
|
return srcParts.join('\n');
|
||||||
|
@ -6,13 +6,30 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// asset:<package-name>/<realm>/<path-to-module>
|
||||||
|
const _ASSET_URL_RE = /asset:([^\/]+)\/([^\/]+)\/(.+)/;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface that defines how import statements should be generated.
|
* Interface that defines how import statements should be generated.
|
||||||
*/
|
*/
|
||||||
export abstract class ImportResolver {
|
export abstract class ImportGenerator {
|
||||||
/**
|
static parseAssetUrl(url: string): AssetUrl { return AssetUrl.parse(url); }
|
||||||
* Converts a file path to a module name that can be used as an `import.
|
|
||||||
* I.e. `path/to/importedFile.ts` should be imported by `path/to/containingFile.ts`.
|
abstract getImportPath(moduleUrlStr: string, importedUrlStr: string): string;
|
||||||
*/
|
}
|
||||||
abstract fileNameToModuleName(importedFilePath: string, containingFilePath: string): string;
|
|
||||||
|
export class AssetUrl {
|
||||||
|
static parse(url: string, allowNonMatching: boolean = true): AssetUrl {
|
||||||
|
const match = url.match(_ASSET_URL_RE);
|
||||||
|
if (match !== null) {
|
||||||
|
return new AssetUrl(match[1], match[2], match[3]);
|
||||||
|
}
|
||||||
|
if (allowNonMatching) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
throw new Error(`Url ${url} is not a valid asset: url`);
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor(public packageName: string, public firstLevelDir: string, public modulePath: string) {
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -12,9 +12,9 @@ import {isBlank, isPresent} from '../facade/lang';
|
|||||||
|
|
||||||
import {AbstractEmitterVisitor, CATCH_ERROR_VAR, CATCH_STACK_VAR, EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
import {AbstractEmitterVisitor, CATCH_ERROR_VAR, CATCH_STACK_VAR, EmitterVisitorContext, OutputEmitter} from './abstract_emitter';
|
||||||
import * as o from './output_ast';
|
import * as o from './output_ast';
|
||||||
import {ImportResolver} from './path_util';
|
import {ImportGenerator} from './path_util';
|
||||||
|
|
||||||
const _debugModuleUrl = '/debug/lib';
|
const _debugModuleUrl = 'asset://debug/lib';
|
||||||
|
|
||||||
export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]):
|
export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.Type | any[]):
|
||||||
string {
|
string {
|
||||||
@ -37,7 +37,7 @@ export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.T
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class TypeScriptEmitter implements OutputEmitter {
|
export class TypeScriptEmitter implements OutputEmitter {
|
||||||
constructor(private _importGenerator: ImportResolver) {}
|
constructor(private _importGenerator: ImportGenerator) {}
|
||||||
emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string {
|
emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string {
|
||||||
const converter = new _TsEmitterVisitor(moduleUrl);
|
const converter = new _TsEmitterVisitor(moduleUrl);
|
||||||
const ctx = EmitterVisitorContext.createRoot(exportedVars);
|
const ctx = EmitterVisitorContext.createRoot(exportedVars);
|
||||||
@ -47,7 +47,7 @@ export class TypeScriptEmitter implements OutputEmitter {
|
|||||||
// Note: can't write the real word for import as it screws up system.js auto detection...
|
// Note: can't write the real word for import as it screws up system.js auto detection...
|
||||||
srcParts.push(
|
srcParts.push(
|
||||||
`imp` +
|
`imp` +
|
||||||
`ort * as ${prefix} from '${this._importGenerator.fileNameToModuleName(importedModuleUrl, moduleUrl)}';`);
|
`ort * as ${prefix} from '${this._importGenerator.getImportPath(moduleUrl, importedModuleUrl)}';`);
|
||||||
});
|
});
|
||||||
srcParts.push(ctx.toSource());
|
srcParts.push(ctx.toSource());
|
||||||
return srcParts.join('\n');
|
return srcParts.join('\n');
|
||||||
|
@ -73,6 +73,3 @@ export type ComponentStillLoadingError = typeof r._ComponentStillLoadingError;
|
|||||||
export const ComponentStillLoadingError: typeof r.ComponentStillLoadingError =
|
export const ComponentStillLoadingError: typeof r.ComponentStillLoadingError =
|
||||||
r.ComponentStillLoadingError;
|
r.ComponentStillLoadingError;
|
||||||
export const AnimationTransition: typeof r.AnimationTransition = r.AnimationTransition;
|
export const AnimationTransition: typeof r.AnimationTransition = r.AnimationTransition;
|
||||||
export type SetterFn = typeof r._SetterFn;
|
|
||||||
export type GetterFn = typeof r._GetterFn;
|
|
||||||
export type MethodFn = typeof r._MethodFn;
|
|
||||||
|
@ -8,22 +8,22 @@
|
|||||||
|
|
||||||
import {Compiler, ComponentFactory, Injectable, Injector, ModuleWithComponentFactories, NgModuleFactory, SchemaMetadata, Type} from '@angular/core';
|
import {Compiler, ComponentFactory, Injectable, Injector, ModuleWithComponentFactories, NgModuleFactory, SchemaMetadata, Type} from '@angular/core';
|
||||||
|
|
||||||
import {AnimationCompiler} from '../animation/animation_compiler';
|
import {AnimationCompiler} from './animation/animation_compiler';
|
||||||
import {AnimationParser} from '../animation/animation_parser';
|
import {AnimationParser} from './animation/animation_parser';
|
||||||
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, ProviderMeta, createHostComponentMeta} from '../compile_metadata';
|
import {CompileDirectiveMetadata, CompileIdentifierMetadata, CompileNgModuleMetadata, CompilePipeMetadata, ProviderMeta, createHostComponentMeta} from './compile_metadata';
|
||||||
import {CompilerConfig} from '../config';
|
import {CompilerConfig} from './config';
|
||||||
import {DirectiveNormalizer} from '../directive_normalizer';
|
import {DirectiveNormalizer} from './directive_normalizer';
|
||||||
import {DirectiveWrapperCompiler} from '../directive_wrapper_compiler';
|
import {DirectiveWrapperCompiler} from './directive_wrapper_compiler';
|
||||||
import {stringify} from '../facade/lang';
|
import {stringify} from './facade/lang';
|
||||||
import {CompileMetadataResolver} from '../metadata_resolver';
|
import {CompileMetadataResolver} from './metadata_resolver';
|
||||||
import {NgModuleCompiler} from '../ng_module_compiler';
|
import {NgModuleCompiler} from './ng_module_compiler';
|
||||||
import * as ir from '../output/output_ast';
|
import * as ir from './output/output_ast';
|
||||||
import {interpretStatements} from '../output/output_interpreter';
|
import {interpretStatements} from './output/output_interpreter';
|
||||||
import {jitStatements} from '../output/output_jit';
|
import {jitStatements} from './output/output_jit';
|
||||||
import {CompiledStylesheet, StyleCompiler} from '../style_compiler';
|
import {CompiledStylesheet, StyleCompiler} from './style_compiler';
|
||||||
import {TemplateParser} from '../template_parser/template_parser';
|
import {TemplateParser} from './template_parser/template_parser';
|
||||||
import {SyncAsyncResult} from '../util';
|
import {SyncAsyncResult} from './util';
|
||||||
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency, ViewCompiler} from '../view_compiler/view_compiler';
|
import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDependency, ViewCompiler} from './view_compiler/view_compiler';
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -37,7 +37,7 @@ import {ComponentFactoryDependency, DirectiveWrapperDependency, ViewClassDepende
|
|||||||
* application to XSS risks. For more detail, see the [Security Guide](http://g.co/ng/security).
|
* application to XSS risks. For more detail, see the [Security Guide](http://g.co/ng/security).
|
||||||
*/
|
*/
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class JitCompiler implements Compiler {
|
export class RuntimeCompiler implements Compiler {
|
||||||
private _compiledTemplateCache = new Map<Type<any>, CompiledTemplate>();
|
private _compiledTemplateCache = new Map<Type<any>, CompiledTemplate>();
|
||||||
private _compiledHostTemplateCache = new Map<Type<any>, CompiledTemplate>();
|
private _compiledHostTemplateCache = new Map<Type<any>, CompiledTemplate>();
|
||||||
private _compiledDirectiveWrapperCache = new Map<Type<any>, Type<any>>();
|
private _compiledDirectiveWrapperCache = new Map<Type<any>, Type<any>>();
|
||||||
@ -385,10 +385,10 @@ function assertComponent(meta: CompileDirectiveMetadata) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Implements `Compiler` by delegating to the JitCompiler using a known module.
|
* Implements `Compiler` by delegating to the RuntimeCompiler using a known module.
|
||||||
*/
|
*/
|
||||||
class ModuleBoundCompiler implements Compiler {
|
class ModuleBoundCompiler implements Compiler {
|
||||||
constructor(private _delegate: JitCompiler, private _ngModule: Type<any>) {}
|
constructor(private _delegate: RuntimeCompiler, private _ngModule: Type<any>) {}
|
||||||
|
|
||||||
get _injector(): Injector { return this._delegate.injector; }
|
get _injector(): Injector { return this._delegate.injector; }
|
||||||
|
|
@ -10,6 +10,9 @@ import {Inject, Injectable, PACKAGE_ROOT_URL} from '@angular/core';
|
|||||||
|
|
||||||
import {isBlank, isPresent} from './facade/lang';
|
import {isBlank, isPresent} from './facade/lang';
|
||||||
|
|
||||||
|
|
||||||
|
const _ASSET_SCHEME = 'asset:';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a {@link UrlResolver} with no package prefix.
|
* Create a {@link UrlResolver} with no package prefix.
|
||||||
*/
|
*/
|
||||||
@ -18,7 +21,7 @@ export function createUrlResolverWithoutPackagePrefix(): UrlResolver {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function createOfflineCompileUrlResolver(): UrlResolver {
|
export function createOfflineCompileUrlResolver(): UrlResolver {
|
||||||
return new UrlResolver('.');
|
return new UrlResolver(_ASSET_SCHEME);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -67,10 +70,15 @@ export class UrlResolver {
|
|||||||
if (isPresent(prefix) && isPresent(resolvedParts) &&
|
if (isPresent(prefix) && isPresent(resolvedParts) &&
|
||||||
resolvedParts[_ComponentIndex.Scheme] == 'package') {
|
resolvedParts[_ComponentIndex.Scheme] == 'package') {
|
||||||
let path = resolvedParts[_ComponentIndex.Path];
|
let path = resolvedParts[_ComponentIndex.Path];
|
||||||
|
if (this._packagePrefix === _ASSET_SCHEME) {
|
||||||
|
const pathSegements = path.split(/\//);
|
||||||
|
resolvedUrl = `asset:${pathSegements[0]}/lib/${pathSegements.slice(1).join('/')}`;
|
||||||
|
} else {
|
||||||
prefix = prefix.replace(/\/+$/, '');
|
prefix = prefix.replace(/\/+$/, '');
|
||||||
path = path.replace(/^\/+/, '');
|
path = path.replace(/^\/+/, '');
|
||||||
return `${prefix}/${path}`;
|
return `${prefix}/${path}`;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return resolvedUrl;
|
return resolvedUrl;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_in
|
|||||||
|
|
||||||
import {SimpleJsImportGenerator} from './output_emitter_util';
|
import {SimpleJsImportGenerator} from './output_emitter_util';
|
||||||
|
|
||||||
const someModuleUrl = 'somePackage/somePath';
|
const someModuleUrl = 'asset:somePackage/lib/somePath';
|
||||||
const anotherModuleUrl = 'somePackage/someOtherPath';
|
const anotherModuleUrl = 'asset:somePackage/lib/someOtherPath';
|
||||||
|
|
||||||
const sameModuleIdentifier =
|
const sameModuleIdentifier =
|
||||||
new CompileIdentifierMetadata({name: 'someLocalId', moduleUrl: someModuleUrl});
|
new CompileIdentifierMetadata({name: 'someLocalId', moduleUrl: someModuleUrl});
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
|
import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata';
|
||||||
import {assetUrl} from '@angular/compiler/src/identifiers';
|
import {assetUrl} from '@angular/compiler/src/identifiers';
|
||||||
import * as o from '@angular/compiler/src/output/output_ast';
|
import * as o from '@angular/compiler/src/output/output_ast';
|
||||||
import {ImportResolver} from '@angular/compiler/src/output/path_util';
|
import {ImportGenerator} from '@angular/compiler/src/output/path_util';
|
||||||
import {EventEmitter} from '@angular/core';
|
import {EventEmitter} from '@angular/core';
|
||||||
import {BaseError} from '@angular/core/src/facade/errors';
|
import {BaseError} from '@angular/core/src/facade/errors';
|
||||||
import {ViewType} from '@angular/core/src/linker/view_type';
|
import {ViewType} from '@angular/core/src/linker/view_type';
|
||||||
@ -22,7 +22,7 @@ export class ExternalClass {
|
|||||||
|
|
||||||
const testDataIdentifier = new CompileIdentifierMetadata({
|
const testDataIdentifier = new CompileIdentifierMetadata({
|
||||||
name: 'ExternalClass',
|
name: 'ExternalClass',
|
||||||
moduleUrl: `@angular/compiler/test/output/output_emitter_util`,
|
moduleUrl: `asset:@angular/lib/compiler/test/output/output_emitter_util`,
|
||||||
reference: ExternalClass
|
reference: ExternalClass
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -252,8 +252,13 @@ function createOperatorFn(op: o.BinaryOperator) {
|
|||||||
o.DYNAMIC_TYPE);
|
o.DYNAMIC_TYPE);
|
||||||
}
|
}
|
||||||
|
|
||||||
export class SimpleJsImportGenerator implements ImportResolver {
|
export class SimpleJsImportGenerator implements ImportGenerator {
|
||||||
fileNameToModuleName(importedUrlStr: string, moduleUrlStr: string): string {
|
getImportPath(moduleUrlStr: string, importedUrlStr: string): string {
|
||||||
|
const importedAssetUrl = ImportGenerator.parseAssetUrl(importedUrlStr);
|
||||||
|
if (importedAssetUrl) {
|
||||||
|
return `${importedAssetUrl.packageName}/${importedAssetUrl.modulePath}`;
|
||||||
|
} else {
|
||||||
return importedUrlStr;
|
return importedUrlStr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
@ -13,8 +13,8 @@ import {beforeEach, describe, expect, it} from '@angular/core/testing/testing_in
|
|||||||
|
|
||||||
import {SimpleJsImportGenerator} from './output_emitter_util';
|
import {SimpleJsImportGenerator} from './output_emitter_util';
|
||||||
|
|
||||||
const someModuleUrl = 'somePackage/somePath';
|
const someModuleUrl = 'asset:somePackage/lib/somePath';
|
||||||
const anotherModuleUrl = 'somePackage/someOtherPath';
|
const anotherModuleUrl = 'asset:somePackage/lib/someOtherPath';
|
||||||
|
|
||||||
const sameModuleIdentifier =
|
const sameModuleIdentifier =
|
||||||
new CompileIdentifierMetadata({name: 'someLocalId', moduleUrl: someModuleUrl});
|
new CompileIdentifierMetadata({name: 'someLocalId', moduleUrl: someModuleUrl});
|
||||||
|
@ -91,6 +91,9 @@ export function main() {
|
|||||||
it('should resolve package: urls',
|
it('should resolve package: urls',
|
||||||
() => { expect(isStyleUrlResolvable('package:someUrl.css')).toBe(true); });
|
() => { expect(isStyleUrlResolvable('package:someUrl.css')).toBe(true); });
|
||||||
|
|
||||||
|
it('should resolve asset: urls',
|
||||||
|
() => { expect(isStyleUrlResolvable('asset:someUrl.css')).toBe(true); });
|
||||||
|
|
||||||
it('should not resolve empty urls', () => {
|
it('should not resolve empty urls', () => {
|
||||||
expect(isStyleUrlResolvable(null)).toBe(false);
|
expect(isStyleUrlResolvable(null)).toBe(false);
|
||||||
expect(isStyleUrlResolvable('')).toBe(false);
|
expect(isStyleUrlResolvable('')).toBe(false);
|
||||||
|
@ -106,6 +106,16 @@ export function main() {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('asset urls', () => {
|
||||||
|
let resolver: UrlResolver;
|
||||||
|
beforeEach(() => { resolver = createOfflineCompileUrlResolver(); });
|
||||||
|
|
||||||
|
it('should resolve package: urls into asset: urls', () => {
|
||||||
|
expect(resolver.resolve(null, 'package:somePkg/somePath'))
|
||||||
|
.toEqual('asset:somePkg/lib/somePath');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('corner and error cases', () => {
|
describe('corner and error cases', () => {
|
||||||
it('should encode URLs before resolving',
|
it('should encode URLs before resolving',
|
||||||
() => {
|
() => {
|
||||||
|
@ -29,7 +29,7 @@ export * from './pipe_resolver_mock';
|
|||||||
import {createPlatformFactory, ModuleWithComponentFactories, Injectable, CompilerOptions, COMPILER_OPTIONS, CompilerFactory, NgModuleFactory, Injector, NgModule, Component, Directive, Pipe, Type, PlatformRef} from '@angular/core';
|
import {createPlatformFactory, ModuleWithComponentFactories, Injectable, CompilerOptions, COMPILER_OPTIONS, CompilerFactory, NgModuleFactory, Injector, NgModule, Component, Directive, Pipe, Type, PlatformRef} from '@angular/core';
|
||||||
import {MetadataOverride} from '@angular/core/testing';
|
import {MetadataOverride} from '@angular/core/testing';
|
||||||
import {TestingCompilerFactory, TestingCompiler} from './private_import_core';
|
import {TestingCompilerFactory, TestingCompiler} from './private_import_core';
|
||||||
import {platformCoreDynamic, JitCompiler, DirectiveResolver, NgModuleResolver, PipeResolver} from '@angular/compiler';
|
import {platformCoreDynamic, RuntimeCompiler, DirectiveResolver, NgModuleResolver, PipeResolver} from '@angular/compiler';
|
||||||
import {MockDirectiveResolver} from './directive_resolver_mock';
|
import {MockDirectiveResolver} from './directive_resolver_mock';
|
||||||
import {MockNgModuleResolver} from './ng_module_resolver_mock';
|
import {MockNgModuleResolver} from './ng_module_resolver_mock';
|
||||||
import {MockPipeResolver} from './pipe_resolver_mock';
|
import {MockPipeResolver} from './pipe_resolver_mock';
|
||||||
@ -40,7 +40,7 @@ export class TestingCompilerFactoryImpl implements TestingCompilerFactory {
|
|||||||
constructor(private _compilerFactory: CompilerFactory) {}
|
constructor(private _compilerFactory: CompilerFactory) {}
|
||||||
|
|
||||||
createTestingCompiler(options: CompilerOptions[]): TestingCompiler {
|
createTestingCompiler(options: CompilerOptions[]): TestingCompiler {
|
||||||
const compiler = <JitCompiler>this._compilerFactory.createCompiler(options);
|
const compiler = <RuntimeCompiler>this._compilerFactory.createCompiler(options);
|
||||||
return new TestingCompilerImpl(
|
return new TestingCompilerImpl(
|
||||||
compiler, compiler.injector.get(MockDirectiveResolver),
|
compiler, compiler.injector.get(MockDirectiveResolver),
|
||||||
compiler.injector.get(MockPipeResolver), compiler.injector.get(MockNgModuleResolver));
|
compiler.injector.get(MockPipeResolver), compiler.injector.get(MockNgModuleResolver));
|
||||||
@ -50,7 +50,7 @@ export class TestingCompilerFactoryImpl implements TestingCompilerFactory {
|
|||||||
export class TestingCompilerImpl implements TestingCompiler {
|
export class TestingCompilerImpl implements TestingCompiler {
|
||||||
private _overrider = new MetadataOverrider();
|
private _overrider = new MetadataOverrider();
|
||||||
constructor(
|
constructor(
|
||||||
private _compiler: JitCompiler, private _directiveResolver: MockDirectiveResolver,
|
private _compiler: RuntimeCompiler, private _directiveResolver: MockDirectiveResolver,
|
||||||
private _pipeResolver: MockPipeResolver, private _moduleResolver: MockNgModuleResolver) {}
|
private _pipeResolver: MockPipeResolver, private _moduleResolver: MockNgModuleResolver) {}
|
||||||
get injector(): Injector { return this._compiler.injector; }
|
get injector(): Injector { return this._compiler.injector; }
|
||||||
|
|
||||||
|
@ -20,8 +20,10 @@ export class WebAnimationsDriver implements AnimationDriver {
|
|||||||
previousPlayers: AnimationPlayer[] = []): WebAnimationsPlayer {
|
previousPlayers: AnimationPlayer[] = []): WebAnimationsPlayer {
|
||||||
let formattedSteps: {[key: string]: string | number}[] = [];
|
let formattedSteps: {[key: string]: string | number}[] = [];
|
||||||
let startingStyleLookup: {[key: string]: string | number} = {};
|
let startingStyleLookup: {[key: string]: string | number} = {};
|
||||||
if (isPresent(startingStyles)) {
|
if (isPresent(startingStyles) && startingStyles.styles.length > 0) {
|
||||||
startingStyleLookup = _populateStyles(startingStyles, {});
|
startingStyleLookup = _populateStyles(startingStyles, {});
|
||||||
|
startingStyleLookup['offset'] = 0;
|
||||||
|
formattedSteps.push(startingStyleLookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
keyframes.forEach((keyframe: AnimationKeyframe) => {
|
keyframes.forEach((keyframe: AnimationKeyframe) => {
|
||||||
|
@ -69,21 +69,12 @@ export class WebAnimationsPlayer implements AnimationPlayer {
|
|||||||
|
|
||||||
const previousStyleProps = Object.keys(this.previousStyles);
|
const previousStyleProps = Object.keys(this.previousStyles);
|
||||||
if (previousStyleProps.length) {
|
if (previousStyleProps.length) {
|
||||||
let startingKeyframe = keyframes[0];
|
let startingKeyframe = findStartingKeyframe(keyframes);
|
||||||
let missingStyleProps: string[] = [];
|
|
||||||
previousStyleProps.forEach(prop => {
|
previousStyleProps.forEach(prop => {
|
||||||
if (!isPresent(startingKeyframe[prop])) {
|
if (isPresent(startingKeyframe[prop])) {
|
||||||
missingStyleProps.push(prop);
|
|
||||||
}
|
|
||||||
startingKeyframe[prop] = this.previousStyles[prop];
|
startingKeyframe[prop] = this.previousStyles[prop];
|
||||||
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
if (missingStyleProps.length) {
|
|
||||||
for (let i = 1; i < keyframes.length; i++) {
|
|
||||||
let kf = keyframes[i];
|
|
||||||
missingStyleProps.forEach(prop => { kf[prop] = _computeStyle(this.element, prop); });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this._player = this._triggerWebAnimation(this.element, keyframes, this.options);
|
this._player = this._triggerWebAnimation(this.element, keyframes, this.options);
|
||||||
@ -185,3 +176,17 @@ function _copyKeyframeStyles(styles: {[style: string]: string | number}):
|
|||||||
});
|
});
|
||||||
return newStyles;
|
return newStyles;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function findStartingKeyframe(keyframes: {[prop: string]: string | number}[]):
|
||||||
|
{[prop: string]: string | number} {
|
||||||
|
let startingKeyframe = keyframes[0];
|
||||||
|
// it's important that we find the LAST keyframe
|
||||||
|
// to ensure that style overidding is final.
|
||||||
|
for (let i = 1; i < keyframes.length; i++) {
|
||||||
|
const kf = keyframes[i];
|
||||||
|
const offset = kf['offset'];
|
||||||
|
if (offset !== 0) break;
|
||||||
|
startingKeyframe = kf;
|
||||||
|
}
|
||||||
|
return startingKeyframe;
|
||||||
|
}
|
||||||
|
@ -202,32 +202,6 @@ export function main() {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should allow previous styles to be merged into the starting keyframe of the animation that were not apart of the animation to begin with',
|
|
||||||
() => {
|
|
||||||
if (!getDOM().supportsWebAnimation()) return;
|
|
||||||
|
|
||||||
const elm = el('<div></div>');
|
|
||||||
document.body.appendChild(elm);
|
|
||||||
elm.style.color = 'rgb(0,0,0)';
|
|
||||||
|
|
||||||
const previousStyles = {color: 'red'};
|
|
||||||
const previousPlayer =
|
|
||||||
new ExtendedWebAnimationsPlayer(elm, [previousStyles, previousStyles], {}, []);
|
|
||||||
previousPlayer.play();
|
|
||||||
previousPlayer.finish();
|
|
||||||
|
|
||||||
const player = new ExtendedWebAnimationsPlayer(
|
|
||||||
elm, [{opacity: '0'}, {opacity: '1'}], {duration: 1000}, [previousPlayer]);
|
|
||||||
|
|
||||||
player.init();
|
|
||||||
|
|
||||||
const data = player.domPlayer.captures['trigger'][0];
|
|
||||||
expect(data['keyframes']).toEqual([
|
|
||||||
{opacity: '0', color: 'red'},
|
|
||||||
{opacity: '1', color: 'rgb(0, 0, 0)'},
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should properly calculate the previous styles for the player even when its currently playing',
|
it('should properly calculate the previous styles for the player even when its currently playing',
|
||||||
() => {
|
() => {
|
||||||
if (!getDOM().supportsWebAnimation()) return;
|
if (!getDOM().supportsWebAnimation()) return;
|
||||||
|
@ -6,8 +6,8 @@
|
|||||||
* found in the LICENSE file at https://angular.io/license
|
* found in the LICENSE file at https://angular.io/license
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ChangeDetectorRef, Class, Component, EventEmitter, NO_ERRORS_SCHEMA, NgModule, SimpleChanges, Testability, destroyPlatform, forwardRef} from '@angular/core';
|
import {Class, Component, EventEmitter, NO_ERRORS_SCHEMA, NgModule, SimpleChanges, Testability, destroyPlatform, forwardRef} from '@angular/core';
|
||||||
import {async, fakeAsync, flushMicrotasks, tick} from '@angular/core/testing';
|
import {async, fakeAsync, flushMicrotasks} from '@angular/core/testing';
|
||||||
import {BrowserModule} from '@angular/platform-browser';
|
import {BrowserModule} from '@angular/platform-browser';
|
||||||
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
import {platformBrowserDynamic} from '@angular/platform-browser-dynamic';
|
||||||
import {UpgradeAdapter} from '@angular/upgrade';
|
import {UpgradeAdapter} from '@angular/upgrade';
|
||||||
@ -96,6 +96,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function Ng2Module() {}});
|
}).Class({constructor: function Ng2Module() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng1', () => {
|
ng1Module.directive('ng1', () => {
|
||||||
@ -169,6 +170,7 @@ export function main() {
|
|||||||
adapter.upgradeNg1Component('ng1a'), adapter.upgradeNg1Component('ng1b'), Ng2
|
adapter.upgradeNg1Component('ng1a'), adapter.upgradeNg1Component('ng1b'), Ng2
|
||||||
],
|
],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -274,6 +276,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [Ng2],
|
declarations: [Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
const element = html(`<div>
|
const element = html(`<div>
|
||||||
@ -317,6 +320,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [Ng2],
|
declarations: [Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -350,6 +354,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [Ng2],
|
declarations: [Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -404,6 +409,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -447,6 +453,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -494,6 +501,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -539,6 +547,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -571,6 +580,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -598,6 +608,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -622,6 +633,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -646,6 +658,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -671,6 +684,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -714,6 +728,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -746,6 +761,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -778,6 +794,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -817,6 +834,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -861,6 +879,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -873,156 +892,154 @@ export function main() {
|
|||||||
|
|
||||||
it('should call $onInit of components', async(() => {
|
it('should call $onInit of components', async(() => {
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
const $onInitSpy = jasmine.createSpy('$onInit');
|
const ng1Module = angular.module('ng1', []);
|
||||||
|
const valueToFind = '$onInit';
|
||||||
|
|
||||||
@Component({selector: 'ng2', template: '<ng1></ng1>'})
|
const ng1 = {
|
||||||
class Ng2Component {
|
|
||||||
}
|
|
||||||
|
|
||||||
angular.module('ng1', [])
|
|
||||||
.component('ng1', {
|
|
||||||
bindings: {},
|
bindings: {},
|
||||||
template: '',
|
template: '{{$ctrl.value}}',
|
||||||
controller: function() { this.$onInit = $onInitSpy; }
|
controller: Class(
|
||||||
})
|
{constructor: function() {}, $onInit: function() { this.value = valueToFind; }})
|
||||||
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
};
|
||||||
|
ng1Module.component('ng1', ng1);
|
||||||
|
|
||||||
@NgModule({
|
const Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component],
|
constructor: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Ng2Module = NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
})
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
class Ng2Module {
|
}).Class({constructor: function() {}});
|
||||||
}
|
|
||||||
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
|
|
||||||
const element = html(`<div><ng2></ng2></div>`);
|
const element = html(`<div><ng2></ng2></div>`);
|
||||||
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
expect($onInitSpy).toHaveBeenCalled();
|
expect(multiTrim(document.body.textContent)).toEqual(valueToFind);
|
||||||
ref.dispose();
|
ref.dispose();
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should call $doCheck of components', async(() => {
|
it('should call $doCheck of components', async(() => {
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
const $doCheckSpy = jasmine.createSpy('$doCheck');
|
const ng1Module = angular.module('ng1', []);
|
||||||
let changeDetector: ChangeDetectorRef;
|
const valueToFind = '$doCheck';
|
||||||
|
|
||||||
@Component({selector: 'ng2', template: '<ng1></ng1>'})
|
let spy = jasmine.createSpy('doCheck');
|
||||||
class Ng2Component {
|
|
||||||
constructor(cd: ChangeDetectorRef) { changeDetector = cd; }
|
|
||||||
}
|
|
||||||
|
|
||||||
angular.module('ng1', [])
|
const ng1 = {
|
||||||
.component('ng1', {
|
|
||||||
bindings: {},
|
bindings: {},
|
||||||
template: '{{$ctrl.value}}',
|
template: '{{$ctrl.value}}',
|
||||||
controller: function() { this.$doCheck = $doCheckSpy; }
|
controller: Class({
|
||||||
})
|
constructor: function() {},
|
||||||
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
$doCheck: function() {
|
||||||
|
this.value = valueToFind;
|
||||||
|
spy();
|
||||||
@NgModule({
|
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component],
|
|
||||||
imports: [BrowserModule],
|
|
||||||
})
|
|
||||||
class Ng2Module {
|
|
||||||
}
|
}
|
||||||
|
})
|
||||||
|
};
|
||||||
|
ng1Module.component('ng1', ng1);
|
||||||
|
|
||||||
|
const Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
|
||||||
|
constructor: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
|
const Ng2Module = NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
|
|
||||||
const element = html(`<div><ng2></ng2></div>`);
|
const element = html(`<div><ng2></ng2></div>`);
|
||||||
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
expect($doCheckSpy).toHaveBeenCalled();
|
expect(multiTrim(document.body.textContent)).toEqual(valueToFind);
|
||||||
|
expect(spy).toHaveBeenCalled();
|
||||||
$doCheckSpy.calls.reset();
|
let count = spy.calls.count();
|
||||||
changeDetector.detectChanges();
|
setTimeout(() => {
|
||||||
|
expect(spy.calls.count()).toBeGreaterThan(count);
|
||||||
expect($doCheckSpy).toHaveBeenCalled();
|
|
||||||
|
|
||||||
ref.dispose();
|
ref.dispose();
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should call $onChanges of components', fakeAsync(() => {
|
it('should call $onChanges of components', async(() => {
|
||||||
const EXPECTED_VALUE = '$onChanges called';
|
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
const $onChangesSpy = jasmine.createSpy('$onChanges');
|
const ng1Module = angular.module('ng1', []);
|
||||||
let ng2Instance: any;
|
const valueToFind = '$onChanges init';
|
||||||
|
const valueToChange = '$onChanges changed';
|
||||||
|
|
||||||
@Component({selector: 'ng2', template: '<ng1 [val]="val"></ng1>'})
|
const ng1 = {
|
||||||
class Ng2Component {
|
|
||||||
constructor() { ng2Instance = this; }
|
|
||||||
}
|
|
||||||
|
|
||||||
angular.module('ng1Module', [])
|
|
||||||
.component('ng1', {
|
|
||||||
bindings: {val: '<'},
|
bindings: {val: '<'},
|
||||||
template: '',
|
template: '{{$ctrl.value}}',
|
||||||
controller: function() { this.$onChanges = $onChangesSpy; }
|
controller: Class({
|
||||||
|
constructor: function() {},
|
||||||
|
$onChanges: function(changes: any) { this.value = changes.val.currentValue; }
|
||||||
})
|
})
|
||||||
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
};
|
||||||
|
ng1Module.component('ng1', ng1);
|
||||||
|
|
||||||
@NgModule({
|
const Ng2 = Component({selector: 'ng2', template: '<ng1 [val]="val"></ng1>'}).Class({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component],
|
constructor: function() { this.val = valueToFind; },
|
||||||
|
ngOnInit: function() { setTimeout(() => { this.val = valueToChange; }, 100); }
|
||||||
|
});
|
||||||
|
|
||||||
|
const Ng2Module = NgModule({
|
||||||
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
})
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
class Ng2Module {
|
}).Class({constructor: function() {}});
|
||||||
}
|
|
||||||
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
|
|
||||||
const element = html(`<div><ng2></ng2></div>`);
|
const element = html(`<div><ng2></ng2></div>`);
|
||||||
adapter.bootstrap(element, ['ng1Module']).ready((ref) => {
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
|
expect(multiTrim(document.body.textContent)).toEqual(valueToFind);
|
||||||
ng2Instance.val = EXPECTED_VALUE;
|
setTimeout(() => {
|
||||||
tick();
|
expect(multiTrim(document.body.textContent)).toEqual(valueToChange);
|
||||||
ref.ng1RootScope.$digest();
|
|
||||||
|
|
||||||
expect($onChangesSpy).toHaveBeenCalled();
|
|
||||||
const changes = $onChangesSpy.calls.mostRecent().args[0] as SimpleChanges;
|
|
||||||
expect(changes['val'].currentValue).toEqual(EXPECTED_VALUE);
|
|
||||||
|
|
||||||
ref.dispose();
|
ref.dispose();
|
||||||
|
}, 200);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
it('should call $onDestroy of components', fakeAsync(() => {
|
it('should call $onDestroy of components', async(() => {
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
const adapter: UpgradeAdapter = new UpgradeAdapter(forwardRef(() => Ng2Module));
|
||||||
const $onDestroySpy = jasmine.createSpy('$onDestroy');
|
const ng1Module = angular.module('ng1', []);
|
||||||
|
|
||||||
@Component({selector: 'ng2', template: '<ng1></ng1>'})
|
let spy = jasmine.createSpy('$onDestroy');
|
||||||
class Ng2Component {
|
|
||||||
}
|
|
||||||
|
|
||||||
angular.module('ng1', [])
|
const ng1 = {
|
||||||
.component('ng1', {
|
|
||||||
bindings: {},
|
bindings: {},
|
||||||
template: '<div>ng1</div>',
|
template: '<div>ng1</div>',
|
||||||
controller: function() { this.$onDestroy = $onDestroySpy; }
|
controller: function($rootScope: any) { this.$onDestroy = function() { spy(); }; }
|
||||||
})
|
};
|
||||||
.directive('ng2', adapter.downgradeNg2Component(Ng2Component));
|
ng1Module.component('ng1', ng1);
|
||||||
|
|
||||||
|
const Ng2 = Component({selector: 'ng2', template: '<ng1></ng1>'}).Class({
|
||||||
|
constructor: function() {}
|
||||||
|
});
|
||||||
|
|
||||||
@NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2Component],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
})
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
class Ng2Module {
|
}).Class({constructor: function() {}});
|
||||||
}
|
|
||||||
|
|
||||||
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
|
|
||||||
const element = html(`<div ng-if="!destroy"><ng2></ng2></div>`);
|
const element = html(`<div ng-if="!destroy"><ng2></ng2></div>`);
|
||||||
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
adapter.bootstrap(element, ['ng1']).ready((ref) => {
|
||||||
const $rootScope = ref.ng1RootScope as any;
|
(<any>ref.ng1RootScope).destroy = false;
|
||||||
|
setTimeout(() => {
|
||||||
$rootScope.destroy = false;
|
(<any>ref.ng1RootScope).destroy = true;
|
||||||
tick();
|
setTimeout(() => {
|
||||||
$rootScope.$digest();
|
expect(spy).toHaveBeenCalled();
|
||||||
|
|
||||||
expect($onDestroySpy).not.toHaveBeenCalled();
|
|
||||||
|
|
||||||
$rootScope.destroy = true;
|
|
||||||
tick();
|
|
||||||
$rootScope.$digest();
|
|
||||||
|
|
||||||
expect($onDestroySpy).toHaveBeenCalled();
|
|
||||||
|
|
||||||
ref.dispose();
|
ref.dispose();
|
||||||
|
}, 100);
|
||||||
|
}, 100);
|
||||||
});
|
});
|
||||||
}));
|
}));
|
||||||
|
|
||||||
@ -1045,6 +1062,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
ng1Module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
@ -1077,6 +1095,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2a, Ng2b],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2a, Ng2b],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
const element = html(`<div><ng2a></ng2a></div>`);
|
const element = html(`<div><ng2a></ng2a></div>`);
|
||||||
@ -1093,6 +1112,7 @@ export function main() {
|
|||||||
const MyNg2Module = NgModule({
|
const MyNg2Module = NgModule({
|
||||||
providers: [{provide: SomeToken, useValue: 'correct_value'}],
|
providers: [{provide: SomeToken, useValue: 'correct_value'}],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
const adapter: UpgradeAdapter = new UpgradeAdapter(MyNg2Module);
|
const adapter: UpgradeAdapter = new UpgradeAdapter(MyNg2Module);
|
||||||
@ -1220,6 +1240,7 @@ export function main() {
|
|||||||
const Ng2Module = NgModule({
|
const Ng2Module = NgModule({
|
||||||
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
declarations: [adapter.upgradeNg1Component('ng1'), Ng2],
|
||||||
imports: [BrowserModule],
|
imports: [BrowserModule],
|
||||||
|
schemas: [NO_ERRORS_SCHEMA],
|
||||||
}).Class({constructor: function() {}});
|
}).Class({constructor: function() {}});
|
||||||
|
|
||||||
module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
module.directive('ng2', adapter.downgradeNg2Component(Ng2));
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "angular-srcs",
|
"name": "angular-srcs",
|
||||||
"version": "2.2.2",
|
"version": "2.2.3",
|
||||||
"private": true,
|
"private": true,
|
||||||
"branchPattern": "2.0.*",
|
"branchPattern": "2.0.*",
|
||||||
"description": "Angular 2 - a web framework for modern web apps",
|
"description": "Angular 2 - a web framework for modern web apps",
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@angular/tsc-wrapped",
|
"name": "@angular/tsc-wrapped",
|
||||||
"version": "0.4.0",
|
"version": "0.2.2",
|
||||||
"description": "Wraps the tsc CLI, allowing extensions.",
|
"description": "Wraps the tsc CLI, allowing extensions.",
|
||||||
"homepage": "https://github.com/angular/angular/tree/master/tools/tsc-wrapped",
|
"homepage": "https://github.com/angular/angular/tree/master/tools/tsc-wrapped",
|
||||||
"bugs": "https://github.com/angular/angular/issues",
|
"bugs": "https://github.com/angular/angular/issues",
|
||||||
|
@ -256,11 +256,9 @@ export class MetadataCollector {
|
|||||||
if (classDeclaration.name) {
|
if (classDeclaration.name) {
|
||||||
const className = classDeclaration.name.text;
|
const className = classDeclaration.name.text;
|
||||||
if (node.flags & ts.NodeFlags.Export) {
|
if (node.flags & ts.NodeFlags.Export) {
|
||||||
if (!metadata) metadata = {};
|
|
||||||
if (classDeclaration.decorators) {
|
if (classDeclaration.decorators) {
|
||||||
|
if (!metadata) metadata = {};
|
||||||
metadata[className] = classMetadataOf(classDeclaration);
|
metadata[className] = classMetadataOf(classDeclaration);
|
||||||
} else {
|
|
||||||
metadata[className] = {__symbolic: 'class'};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -271,14 +269,10 @@ export class MetadataCollector {
|
|||||||
// names substitution will be performed by the StaticReflector.
|
// names substitution will be performed by the StaticReflector.
|
||||||
const functionDeclaration = <ts.FunctionDeclaration>node;
|
const functionDeclaration = <ts.FunctionDeclaration>node;
|
||||||
if (node.flags & ts.NodeFlags.Export) {
|
if (node.flags & ts.NodeFlags.Export) {
|
||||||
if (!metadata) metadata = {};
|
|
||||||
const maybeFunc = maybeGetSimpleFunction(functionDeclaration);
|
const maybeFunc = maybeGetSimpleFunction(functionDeclaration);
|
||||||
if (maybeFunc) {
|
if (maybeFunc) {
|
||||||
|
if (!metadata) metadata = {};
|
||||||
metadata[maybeFunc.name] = recordEntry(maybeFunc.func, node);
|
metadata[maybeFunc.name] = recordEntry(maybeFunc.func, node);
|
||||||
} else if (functionDeclaration.name.kind == ts.SyntaxKind.Identifier) {
|
|
||||||
const nameNode = <ts.Identifier>functionDeclaration.name;
|
|
||||||
const functionName = nameNode.text;
|
|
||||||
metadata[functionName] = {__symbolic: 'function'};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -15,7 +15,7 @@
|
|||||||
// semantics of the file in an array. For example, when generating a version 2 file, if version 1
|
// semantics of the file in an array. For example, when generating a version 2 file, if version 1
|
||||||
// can accurately represent the metadata, generate both version 1 and version 2 in an array.
|
// can accurately represent the metadata, generate both version 1 and version 2 in an array.
|
||||||
|
|
||||||
export const VERSION = 2;
|
export const VERSION = 1;
|
||||||
|
|
||||||
export type MetadataEntry = ClassMetadata | FunctionMetadata | MetadataValue;
|
export type MetadataEntry = ClassMetadata | FunctionMetadata | MetadataValue;
|
||||||
|
|
||||||
|
@ -29,7 +29,6 @@ describe('Collector', () => {
|
|||||||
'/unsupported-1.ts',
|
'/unsupported-1.ts',
|
||||||
'/unsupported-2.ts',
|
'/unsupported-2.ts',
|
||||||
'import-star.ts',
|
'import-star.ts',
|
||||||
'exported-classes.ts',
|
|
||||||
'exported-functions.ts',
|
'exported-functions.ts',
|
||||||
'exported-enum.ts',
|
'exported-enum.ts',
|
||||||
'exported-consts.ts',
|
'exported-consts.ts',
|
||||||
@ -63,7 +62,7 @@ describe('Collector', () => {
|
|||||||
const metadata = collector.getMetadata(sourceFile);
|
const metadata = collector.getMetadata(sourceFile);
|
||||||
expect(metadata).toEqual({
|
expect(metadata).toEqual({
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
HeroDetailComponent: {
|
HeroDetailComponent: {
|
||||||
__symbolic: 'class',
|
__symbolic: 'class',
|
||||||
@ -104,7 +103,7 @@ describe('Collector', () => {
|
|||||||
const metadata = collector.getMetadata(sourceFile);
|
const metadata = collector.getMetadata(sourceFile);
|
||||||
expect(metadata).toEqual({
|
expect(metadata).toEqual({
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
AppComponent: {
|
AppComponent: {
|
||||||
__symbolic: 'class',
|
__symbolic: 'class',
|
||||||
@ -158,7 +157,7 @@ describe('Collector', () => {
|
|||||||
const metadata = collector.getMetadata(sourceFile);
|
const metadata = collector.getMetadata(sourceFile);
|
||||||
expect(metadata).toEqual({
|
expect(metadata).toEqual({
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
HEROES: [
|
HEROES: [
|
||||||
{'id': 11, 'name': 'Mr. Nice'}, {'id': 12, 'name': 'Narco'},
|
{'id': 11, 'name': 'Mr. Nice'}, {'id': 12, 'name': 'Narco'},
|
||||||
@ -171,6 +170,13 @@ describe('Collector', () => {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should return undefined for modules that have no metadata', () => {
|
||||||
|
const sourceFile = program.getSourceFile('/app/error-cases.ts');
|
||||||
|
expect(sourceFile).toBeTruthy(sourceFile);
|
||||||
|
const metadata = collector.getMetadata(sourceFile);
|
||||||
|
expect(metadata).toBeUndefined();
|
||||||
|
});
|
||||||
|
|
||||||
let casesFile: ts.SourceFile;
|
let casesFile: ts.SourceFile;
|
||||||
let casesMetadata: ModuleMetadata;
|
let casesMetadata: ModuleMetadata;
|
||||||
|
|
||||||
@ -232,7 +238,7 @@ describe('Collector', () => {
|
|||||||
const metadata = collector.getMetadata(unsupported1);
|
const metadata = collector.getMetadata(unsupported1);
|
||||||
expect(metadata).toEqual({
|
expect(metadata).toEqual({
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
a: {__symbolic: 'error', message: 'Destructuring not supported', line: 1, character: 16},
|
a: {__symbolic: 'error', message: 'Destructuring not supported', line: 1, character: 16},
|
||||||
b: {__symbolic: 'error', message: 'Destructuring not supported', line: 1, character: 19},
|
b: {__symbolic: 'error', message: 'Destructuring not supported', line: 1, character: 19},
|
||||||
@ -269,26 +275,12 @@ describe('Collector', () => {
|
|||||||
]);
|
]);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should record all exported classes', () => {
|
|
||||||
const sourceFile = program.getSourceFile('/exported-classes.ts');
|
|
||||||
const metadata = collector.getMetadata(sourceFile);
|
|
||||||
expect(metadata).toEqual({
|
|
||||||
__symbolic: 'module',
|
|
||||||
version: 2,
|
|
||||||
metadata: {
|
|
||||||
SimpleClass: {__symbolic: 'class'},
|
|
||||||
AbstractClass: {__symbolic: 'class'},
|
|
||||||
DeclaredClass: {__symbolic: 'class'}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
it('should be able to record functions', () => {
|
it('should be able to record functions', () => {
|
||||||
const exportedFunctions = program.getSourceFile('/exported-functions.ts');
|
const exportedFunctions = program.getSourceFile('/exported-functions.ts');
|
||||||
const metadata = collector.getMetadata(exportedFunctions);
|
const metadata = collector.getMetadata(exportedFunctions);
|
||||||
expect(metadata).toEqual({
|
expect(metadata).toEqual({
|
||||||
__symbolic: 'module',
|
__symbolic: 'module',
|
||||||
version: 2,
|
version: 1,
|
||||||
metadata: {
|
metadata: {
|
||||||
one: {
|
one: {
|
||||||
__symbolic: 'function',
|
__symbolic: 'function',
|
||||||
@ -336,9 +328,7 @@ describe('Collector', () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
complexFn: {__symbolic: 'function'},
|
|
||||||
declaredFn: {__symbolic: 'function'}
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
@ -839,11 +829,6 @@ const FILES: Directory = {
|
|||||||
constructor(private f: common.NgFor) {}
|
constructor(private f: common.NgFor) {}
|
||||||
}
|
}
|
||||||
`,
|
`,
|
||||||
'exported-classes.ts': `
|
|
||||||
export class SimpleClass {}
|
|
||||||
export abstract class AbstractClass {}
|
|
||||||
export declare class DeclaredClass {}
|
|
||||||
`,
|
|
||||||
'exported-functions.ts': `
|
'exported-functions.ts': `
|
||||||
export function one(a: string, b: string, c: string) {
|
export function one(a: string, b: string, c: string) {
|
||||||
return {a: a, b: b, c: c};
|
return {a: a, b: b, c: c};
|
||||||
@ -857,14 +842,6 @@ const FILES: Directory = {
|
|||||||
export function supportsState(): boolean {
|
export function supportsState(): boolean {
|
||||||
return !!window.history.pushState;
|
return !!window.history.pushState;
|
||||||
}
|
}
|
||||||
export function complexFn(x: any): boolean {
|
|
||||||
if (x) {
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
export declare function declaredFn();
|
|
||||||
`,
|
`,
|
||||||
'exported-enum.ts': `
|
'exported-enum.ts': `
|
||||||
import {constValue} from './exported-consts';
|
import {constValue} from './exported-consts';
|
||||||
|
Reference in New Issue
Block a user