refactor(compiler): rename /compiler_cli to /compiler-cli
This commit is contained in:
93
modules/@angular/compiler-cli/README.md
Normal file
93
modules/@angular/compiler-cli/README.md
Normal file
@ -0,0 +1,93 @@
|
||||
# Angular Template Compiler
|
||||
|
||||
Angular applications are built with templates, which may be `.html` or `.css` files,
|
||||
or may be inline `template` attributes on Decorators like `@Component`.
|
||||
|
||||
These templates are compiled into executable JS at application runtime (except in `interpretation` mode).
|
||||
This compilation can occur on the client, but it results in slower bootstrap time, and also
|
||||
requires that the compiler be included in the code downloaded to the client.
|
||||
|
||||
You can produce smaller, faster applications by running Angular's compiler as a build step,
|
||||
and then downloading only the executable JS to the client.
|
||||
|
||||
## Install and use
|
||||
|
||||
```
|
||||
# First install angular, see https://github.com/angular/angular/blob/master/CHANGELOG.md#200-rc0-2016-05-02
|
||||
$ npm install @angular/compiler-cli typescript@next @angular/platform-server @angular/compiler
|
||||
# Optional sanity check, make sure TypeScript can compile.
|
||||
$ ./node_modules/.bin/tsc -p path/to/project
|
||||
# ngc is a drop-in replacement for tsc.
|
||||
$ ./node_modules/.bin/ngc -p path/to/project
|
||||
```
|
||||
|
||||
In order to write a `bootstrap` that imports the generated code, you should first write your
|
||||
top-level component, and run `ngc` once to produce a generated `.ngfactory.ts` file.
|
||||
Then you can add an import statement in the `bootstrap` allowing you to bootstrap off the
|
||||
generated code.
|
||||
|
||||
## Configuration
|
||||
|
||||
The `tsconfig.json` file may contain an additional configuration block:
|
||||
```
|
||||
"angularCompilerOptions": {
|
||||
"genDir": "."
|
||||
}
|
||||
```
|
||||
the `genDir` option controls the path (relative to `tsconfig.json`) where the generated file tree
|
||||
will be written. If `genDir` is not set, then the code will be generated in the source tree, next
|
||||
to your original sources. More options may be added as we implement more features.
|
||||
|
||||
We recommend you avoid checking generated files into version control. This permits a state where
|
||||
the generated files in the repository were created from sources that were never checked in,
|
||||
making it impossible to reproduce the current state. Also, your changes will effectively appear
|
||||
twice in code reviews, with the generated version inscrutible by the reviewer.
|
||||
|
||||
In TypeScript 1.8, the generated sources will have to be written alongside your originals,
|
||||
so set `genDir` to the same location as your files (typicially the same as `rootDir`).
|
||||
Add `**/*.ngfactory.ts` to your `.gitignore` or other mechanism for your version control system.
|
||||
|
||||
In TypeScript 1.9 and above, you can add a generated folder into your application,
|
||||
such as `codegen`. Using the `rootDirs` option, you can allow relative imports like
|
||||
`import {} from './foo.ngfactory'` even though the `src` and `codegen` trees are distinct.
|
||||
Add `**/codegen` to your `.gitignore` or similar.
|
||||
|
||||
Note that in the second option, TypeScript will emit the code into two parallel directories
|
||||
as well. This is by design, see https://github.com/Microsoft/TypeScript/issues/8245.
|
||||
This makes the configuration of your runtime module loader more complex, so we don't recommend
|
||||
this option yet.
|
||||
|
||||
See the example in the `test/` directory for a working example.
|
||||
|
||||
## Compiler CLI
|
||||
|
||||
This program mimics the TypeScript tsc command line. It accepts a `-p` flag which points to a
|
||||
`tsconfig.json` file, or a directory containing one.
|
||||
|
||||
This CLI is intended for demos, prototyping, or for users with simple build systems
|
||||
that run bare `tsc`.
|
||||
|
||||
Users with a build system should expect an Angular 2 template plugin. Such a plugin would be
|
||||
based on the `index.ts` in this directory, but should share the TypeScript compiler instance
|
||||
with the one already used in the plugin for TypeScript typechecking and emit.
|
||||
|
||||
## Design
|
||||
At a high level, this program
|
||||
- collects static metadata about the sources using the `tsc-wrapped` package in angular2
|
||||
- uses the `OfflineCompiler` from `angular2/src/compiler/compiler` to codegen additional `.ts` files
|
||||
- these `.ts` files are written to the `genDir` path, then compiled together with the application.
|
||||
|
||||
## For developers
|
||||
```
|
||||
# Build angular2 and the compiler
|
||||
./build.sh
|
||||
# Run the test once
|
||||
# (First edit the LINKABLE_PKGS to use npm link instead of npm install)
|
||||
$ ./scripts/ci-lite/offline_compiler_test.sh
|
||||
# Keep a package fresh in watch mode
|
||||
./node_modules/.bin/tsc -p modules/@angular/compiler/tsconfig-es5.json -w
|
||||
# Iterate on the test
|
||||
cd /tmp/wherever/e2e_test.1464388257/
|
||||
./node_modules/.bin/ngc
|
||||
./node_modules/.bin/jasmine test/*_spec.js
|
||||
```
|
4
modules/@angular/compiler-cli/index.ts
Normal file
4
modules/@angular/compiler-cli/index.ts
Normal file
@ -0,0 +1,4 @@
|
||||
export {CodeGenerator} from './src/codegen';
|
||||
export {NodeReflectorHost} from './src/reflector_host';
|
||||
export {StaticReflector, StaticReflectorHost, StaticSymbol} from './src/static_reflector';
|
||||
export * from '@angular/tsc-wrapped';
|
@ -0,0 +1 @@
|
||||
<div></div>
|
@ -0,0 +1,27 @@
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'my-comp',
|
||||
template: '<div></div>',
|
||||
})
|
||||
export class MyComp {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'next-comp',
|
||||
templateUrl: './multiple_components.html',
|
||||
})
|
||||
export class NextComp {
|
||||
}
|
||||
|
||||
// Verify that exceptions from DirectiveResolver don't propagate
|
||||
export function NotADirective(c: any): void {}
|
||||
@NotADirective
|
||||
export class HasCustomDecorator {
|
||||
}
|
||||
|
||||
// Verify that custom decorators have metadata collected, eg Ionic
|
||||
export function Page(c: any): (f: Function) => void {return c;}
|
||||
|
||||
@Page({template: 'Ionic template'})
|
||||
export class AnIonicPage {}
|
@ -0,0 +1,3 @@
|
||||
@import './shared.css';
|
||||
|
||||
.green { color: green }
|
@ -0,0 +1,4 @@
|
||||
<div [attr.array]="[0]" [attr.map]="{a:1}">{{ctxProp}}</div>
|
||||
<form><input type="button" [(ngModel)]="ctxProp"/></form>
|
||||
<my-comp *ngIf="ctxBool"></my-comp>
|
||||
<div *ngFor="let x of ctxArr" [attr.value]="x"></div>
|
17
modules/@angular/compiler-cli/integrationtest/src/basic.ts
Normal file
17
modules/@angular/compiler-cli/integrationtest/src/basic.ts
Normal file
@ -0,0 +1,17 @@
|
||||
import {Component, Inject} from '@angular/core';
|
||||
import {FORM_DIRECTIVES, NgIf, NgFor} from '@angular/common';
|
||||
import {MyComp} from './a/multiple_components';
|
||||
|
||||
@Component({
|
||||
selector: 'basic',
|
||||
templateUrl: './basic.html',
|
||||
styles: ['.red { color: red }'],
|
||||
styleUrls: ['./basic.css'],
|
||||
directives: [MyComp, FORM_DIRECTIVES, NgIf, NgFor]
|
||||
})
|
||||
export class Basic {
|
||||
ctxProp: string;
|
||||
ctxBool: boolean;
|
||||
ctxArr: any[] = [];
|
||||
constructor() { this.ctxProp = 'initialValue'; }
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
import {coreBootstrap, ReflectiveInjector} from '@angular/core';
|
||||
import {browserPlatform, BROWSER_APP_PROVIDERS} from '@angular/platform-browser';
|
||||
import {BasicNgFactory} from './basic.ngfactory';
|
||||
import {Basic} from './basic';
|
||||
|
||||
const appInjector =
|
||||
ReflectiveInjector.resolveAndCreate(BROWSER_APP_PROVIDERS, browserPlatform().injector);
|
||||
coreBootstrap(BasicNgFactory, appInjector);
|
2
modules/@angular/compiler-cli/integrationtest/src/dep.d.ts
vendored
Normal file
2
modules/@angular/compiler-cli/integrationtest/src/dep.d.ts
vendored
Normal file
@ -0,0 +1,2 @@
|
||||
// Verify we don't try to extract metadata for .d.ts files
|
||||
export declare var a: string;
|
@ -0,0 +1,29 @@
|
||||
import {Component, Inject, OpaqueToken} from '@angular/core';
|
||||
import {NgIf} from '@angular/common';
|
||||
|
||||
export const SOME_OPAQUE_TOKEN = new OpaqueToken('opaqueToken');
|
||||
|
||||
@Component({
|
||||
selector: 'comp-providers',
|
||||
template: '',
|
||||
providers: [
|
||||
{provide: 'strToken', useValue: 'strValue'},
|
||||
{provide: SOME_OPAQUE_TOKEN, useValue: 10},
|
||||
{provide: 'reference', useValue: NgIf},
|
||||
{provide: 'complexToken', useValue: {a: 1, b: ['test', SOME_OPAQUE_TOKEN]}},
|
||||
]
|
||||
})
|
||||
export class CompWithProviders {
|
||||
constructor(@Inject('strToken') public ctxProp: string) {}
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'cmp-reference',
|
||||
template: `
|
||||
<input #a>{{a.value}}
|
||||
<div *ngIf="true">{{a.value}}</div>
|
||||
`,
|
||||
directives: [NgIf]
|
||||
})
|
||||
export class CompWithReferences {
|
||||
}
|
@ -0,0 +1,15 @@
|
||||
import {Component} from '@angular/core';
|
||||
|
||||
@Component({
|
||||
selector: 'comp-with-proj',
|
||||
template: '<ng-content></ng-content>'
|
||||
})
|
||||
export class CompWithProjection {
|
||||
}
|
||||
|
||||
@Component({
|
||||
selector: 'main',
|
||||
template: '<comp-with-proj><span greeting="Hello world!"></span></comp-with-proj>',
|
||||
directives: [CompWithProjection]
|
||||
})
|
||||
export class MainComp {}
|
@ -0,0 +1 @@
|
||||
.blue { color: blue }
|
@ -0,0 +1,73 @@
|
||||
// Only needed to satisfy the check in core/src/util/decorators.ts
|
||||
// TODO(alexeagle): maybe remove that check?
|
||||
require('reflect-metadata');
|
||||
|
||||
require('@angular/platform-server/src/parse5_adapter.js').Parse5DomAdapter.makeCurrent();
|
||||
require('zone.js/dist/zone-node.js');
|
||||
require('zone.js/dist/long-stack-trace-zone.js');
|
||||
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import {BasicNgFactory} from '../src/basic.ngfactory';
|
||||
import {MyComp} from '../src/a/multiple_components';
|
||||
import {ReflectiveInjector, DebugElement, getDebugNode} from '@angular/core';
|
||||
import {browserPlatform, BROWSER_APP_PROVIDERS} from '@angular/platform-browser';
|
||||
|
||||
describe("template codegen output", () => {
|
||||
const outDir = 'src';
|
||||
|
||||
it("should lower Decorators without reflect-metadata", () => {
|
||||
const jsOutput = path.join(outDir, 'basic.js');
|
||||
expect(fs.existsSync(jsOutput)).toBeTruthy();
|
||||
expect(fs.readFileSync(jsOutput, {encoding: 'utf-8'})).not.toContain('Reflect.decorate');
|
||||
});
|
||||
|
||||
it("should produce metadata.json outputs", () => {
|
||||
const metadataOutput = path.join(outDir, 'basic.metadata.json');
|
||||
expect(fs.existsSync(metadataOutput)).toBeTruthy();
|
||||
const output = fs.readFileSync(metadataOutput, {encoding: 'utf-8'});
|
||||
expect(output).toContain('"decorators":');
|
||||
expect(output).toContain('"module":"@angular/core","name":"Component"');
|
||||
});
|
||||
|
||||
it("should write .d.ts files", () => {
|
||||
const dtsOutput = path.join(outDir, 'basic.d.ts');
|
||||
expect(fs.existsSync(dtsOutput)).toBeTruthy();
|
||||
expect(fs.readFileSync(dtsOutput, {encoding: 'utf-8'})).toContain('Basic');
|
||||
});
|
||||
|
||||
it("should be able to create the basic component", () => {
|
||||
const appInjector = ReflectiveInjector.resolveAndCreate(BROWSER_APP_PROVIDERS,
|
||||
browserPlatform().injector);
|
||||
var comp = BasicNgFactory.create(appInjector);
|
||||
expect(comp.instance).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should support ngIf", () => {
|
||||
const appInjector = ReflectiveInjector.resolveAndCreate(BROWSER_APP_PROVIDERS,
|
||||
browserPlatform().injector);
|
||||
var comp = BasicNgFactory.create(appInjector);
|
||||
var debugElement = <DebugElement>getDebugNode(comp.location.nativeElement);
|
||||
expect(debugElement.children.length).toBe(2);
|
||||
|
||||
comp.instance.ctxBool = true;
|
||||
comp.changeDetectorRef.detectChanges();
|
||||
expect(debugElement.children.length).toBe(3);
|
||||
expect(debugElement.children[2].injector.get(MyComp)).toBeTruthy();
|
||||
});
|
||||
|
||||
it("should support ngFor", () => {
|
||||
const appInjector = ReflectiveInjector.resolveAndCreate(BROWSER_APP_PROVIDERS,
|
||||
browserPlatform().injector);
|
||||
var comp = BasicNgFactory.create(appInjector);
|
||||
var debugElement = <DebugElement>getDebugNode(comp.location.nativeElement);
|
||||
expect(debugElement.children.length).toBe(2);
|
||||
|
||||
// test NgFor
|
||||
comp.instance.ctxArr = [1, 2];
|
||||
comp.changeDetectorRef.detectChanges();
|
||||
expect(debugElement.children.length).toBe(4);
|
||||
expect(debugElement.children[2].attributes['value']).toBe('1');
|
||||
expect(debugElement.children[3].attributes['value']).toBe('2');
|
||||
});
|
||||
});
|
@ -0,0 +1,16 @@
|
||||
import {MainCompNgFactory} from '../src/projection.ngfactory';
|
||||
import {CompWithProjection} from '../src/projection';
|
||||
import {ReflectiveInjector, DebugElement, getDebugNode} from '@angular/core';
|
||||
import {browserPlatform, BROWSER_APP_PROVIDERS, By} from '@angular/platform-browser';
|
||||
|
||||
describe("content projection", () => {
|
||||
it("should support basic content projection", () => {
|
||||
const appInjector = ReflectiveInjector.resolveAndCreate(BROWSER_APP_PROVIDERS, browserPlatform().injector);
|
||||
var mainComp = MainCompNgFactory.create(appInjector);
|
||||
|
||||
var debugElement = <DebugElement>getDebugNode(mainComp.location.nativeElement);
|
||||
var compWithProjection = debugElement.query(By.directive(CompWithProjection));
|
||||
expect(compWithProjection.children.length).toBe(1);
|
||||
expect(compWithProjection.children[0].attributes['greeting']).toEqual('Hello world!');
|
||||
});
|
||||
});
|
18
modules/@angular/compiler-cli/integrationtest/tsconfig.json
Normal file
18
modules/@angular/compiler-cli/integrationtest/tsconfig.json
Normal file
@ -0,0 +1,18 @@
|
||||
{
|
||||
"angularCompilerOptions": {
|
||||
// For TypeScript 1.8, we have to lay out generated files
|
||||
// in the same source directory with your code.
|
||||
"genDir": "."
|
||||
},
|
||||
|
||||
"compilerOptions": {
|
||||
"target": "es5",
|
||||
"experimentalDecorators": true,
|
||||
"noImplicitAny": true,
|
||||
"moduleResolution": "node",
|
||||
"rootDir": "",
|
||||
"declaration": true,
|
||||
"lib": ["es6", "dom"],
|
||||
"baseUrl": "."
|
||||
}
|
||||
}
|
38
modules/@angular/compiler-cli/package.json
Normal file
38
modules/@angular/compiler-cli/package.json
Normal file
@ -0,0 +1,38 @@
|
||||
{
|
||||
"name": "@angular/compiler-cli",
|
||||
"version": "0.0.0-PLACEHOLDER",
|
||||
"description": "Execute angular2 template compiler in nodejs.",
|
||||
"main": "index.js",
|
||||
"typings": "index.d.ts",
|
||||
"bin": {
|
||||
"ngc": "./src/main.js"
|
||||
},
|
||||
"dependencies": {
|
||||
"@angular/tsc-wrapped": "^0.1.0",
|
||||
"reflect-metadata": "^0.1.2",
|
||||
"parse5": "1.3.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": "^1.9.0-dev",
|
||||
"@angular/compiler": "0.0.0-PLACEHOLDER",
|
||||
"@angular/platform-server": "0.0.0-PLACEHOLDER",
|
||||
"@angular/core": "0.0.0-PLACEHOLDER"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/angular/angular.git"
|
||||
},
|
||||
"keywords": [
|
||||
"angular",
|
||||
"compiler"
|
||||
],
|
||||
"contributors": [
|
||||
"Tobias Bosch <tbosch@google.com> (https://angular.io/)",
|
||||
"Alex Eagle <alexeagle@google.com> (https://angular.io/)"
|
||||
],
|
||||
"license": "MIT",
|
||||
"bugs": {
|
||||
"url": "https://github.com/angular/angular/issues"
|
||||
},
|
||||
"homepage": "https://github.com/angular/angular/tree/master/tools/compiler-cli"
|
||||
}
|
181
modules/@angular/compiler-cli/src/codegen.ts
Normal file
181
modules/@angular/compiler-cli/src/codegen.ts
Normal file
@ -0,0 +1,181 @@
|
||||
/**
|
||||
* Transform template html and css into executable code.
|
||||
* Intended to be used in a build step.
|
||||
*/
|
||||
import * as ts from 'typescript';
|
||||
import * as path from 'path';
|
||||
import {AngularCompilerOptions} from '@angular/tsc-wrapped';
|
||||
|
||||
import * as compiler from '@angular/compiler';
|
||||
import {ViewEncapsulation} from '@angular/core';
|
||||
import {StaticReflector} from './static_reflector';
|
||||
import {
|
||||
CompileMetadataResolver,
|
||||
HtmlParser,
|
||||
DirectiveNormalizer,
|
||||
Lexer,
|
||||
Parser,
|
||||
TemplateParser,
|
||||
DomElementSchemaRegistry,
|
||||
StyleCompiler,
|
||||
ViewCompiler,
|
||||
TypeScriptEmitter
|
||||
} from './compiler_private';
|
||||
|
||||
import {Parse5DomAdapter} from '@angular/platform-server';
|
||||
|
||||
import {NodeReflectorHost} from './reflector_host';
|
||||
import {StaticAndDynamicReflectionCapabilities} from './static_reflection_capabilities';
|
||||
|
||||
const GENERATED_FILES = /\.ngfactory\.ts$|\.css\.ts$|\.css\.shim\.ts$/;
|
||||
|
||||
const PREAMBLE = `/**
|
||||
* This file is generated by the Angular 2 template compiler.
|
||||
* Do not edit.
|
||||
*/
|
||||
/* tslint:disable */
|
||||
|
||||
`;
|
||||
|
||||
export class CodeGenerator {
|
||||
constructor(private options: AngularCompilerOptions,
|
||||
private program: ts.Program, public host: ts.CompilerHost,
|
||||
private staticReflector: StaticReflector, private resolver: CompileMetadataResolver,
|
||||
private compiler: compiler.OfflineCompiler,
|
||||
private reflectorHost: NodeReflectorHost) {}
|
||||
|
||||
private generateSource(metadatas: compiler.CompileDirectiveMetadata[]) {
|
||||
const normalize = (metadata: compiler.CompileDirectiveMetadata) => {
|
||||
const directiveType = metadata.type.runtime;
|
||||
const directives = this.resolver.getViewDirectivesMetadata(directiveType);
|
||||
return Promise.all(directives.map(d => this.compiler.normalizeDirectiveMetadata(d)))
|
||||
.then(normalizedDirectives => {
|
||||
const pipes = this.resolver.getViewPipesMetadata(directiveType);
|
||||
return new compiler.NormalizedComponentWithViewDirectives(metadata,
|
||||
normalizedDirectives, pipes);
|
||||
});
|
||||
};
|
||||
return Promise.all(metadatas.map(normalize))
|
||||
.then(normalizedCompWithDirectives =>
|
||||
this.compiler.compileTemplates(normalizedCompWithDirectives));
|
||||
}
|
||||
|
||||
private readComponents(absSourcePath: string) {
|
||||
const result: Promise<compiler.CompileDirectiveMetadata>[] = [];
|
||||
const moduleMetadata = this.staticReflector.getModuleMetadata(absSourcePath);
|
||||
if (!moduleMetadata) {
|
||||
console.log(`WARNING: no metadata found for ${absSourcePath}`);
|
||||
return result;
|
||||
}
|
||||
const metadata = moduleMetadata['metadata'];
|
||||
const symbols = metadata && Object.keys(metadata);
|
||||
if (!symbols || !symbols.length) {
|
||||
return result;
|
||||
}
|
||||
for (const symbol of symbols) {
|
||||
if (metadata[symbol] && metadata[symbol].__symbolic == 'error') {
|
||||
// Ignore symbols that are only included to record error information.
|
||||
continue;
|
||||
}
|
||||
const staticType = this.reflectorHost.findDeclaration(absSourcePath, symbol, absSourcePath);
|
||||
let directive: compiler.CompileDirectiveMetadata;
|
||||
directive = this.resolver.maybeGetDirectiveMetadata(<any>staticType);
|
||||
|
||||
if (!directive || !directive.isComponent) {
|
||||
continue;
|
||||
}
|
||||
result.push(this.compiler.normalizeDirectiveMetadata(directive));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Write codegen in a directory structure matching the sources.
|
||||
private calculateEmitPath(filePath: string) {
|
||||
let root = this.options.basePath;
|
||||
for (let eachRootDir of this.options.rootDirs || []) {
|
||||
if (this.options.trace) {
|
||||
console.log(`Check if ${filePath} is under rootDirs element ${eachRootDir}`);
|
||||
}
|
||||
if (path.relative(eachRootDir, filePath).indexOf('.') !== 0) {
|
||||
root = eachRootDir;
|
||||
}
|
||||
}
|
||||
|
||||
return path.join(this.options.genDir, path.relative(root, filePath));
|
||||
}
|
||||
|
||||
// TODO(tbosch): add a cache for shared css files
|
||||
// TODO(tbosch): detect cycles!
|
||||
private generateStylesheet(filepath: string, shim: boolean): Promise<any> {
|
||||
return this.compiler.loadAndCompileStylesheet(filepath, shim, '.ts')
|
||||
.then((sourceWithImports) => {
|
||||
const emitPath = this.calculateEmitPath(sourceWithImports.source.moduleUrl);
|
||||
// TODO(alexeagle): should include the sourceFile to the WriteFileCallback
|
||||
this.host.writeFile(emitPath, PREAMBLE + sourceWithImports.source.source, false);
|
||||
return Promise.all(
|
||||
sourceWithImports.importedUrls.map(url => this.generateStylesheet(url, shim)));
|
||||
});
|
||||
}
|
||||
|
||||
codegen(): Promise<any> {
|
||||
Parse5DomAdapter.makeCurrent();
|
||||
|
||||
let stylesheetPromises: Promise<any>[] = [];
|
||||
const generateOneFile = (absSourcePath: string) =>
|
||||
Promise.all(this.readComponents(absSourcePath))
|
||||
.then((metadatas: compiler.CompileDirectiveMetadata[]) => {
|
||||
if (!metadatas || !metadatas.length) {
|
||||
return;
|
||||
}
|
||||
metadatas.forEach((metadata) => {
|
||||
let stylesheetPaths = metadata && metadata.template && metadata.template.styleUrls;
|
||||
if (stylesheetPaths) {
|
||||
stylesheetPaths.forEach((path) => {
|
||||
stylesheetPromises.push(this.generateStylesheet(
|
||||
path, metadata.template.encapsulation === ViewEncapsulation.Emulated));
|
||||
});
|
||||
}
|
||||
});
|
||||
return this.generateSource(metadatas);
|
||||
})
|
||||
.then(generated => {
|
||||
if (generated) {
|
||||
const sourceFile = this.program.getSourceFile(absSourcePath);
|
||||
const emitPath = this.calculateEmitPath(generated.moduleUrl);
|
||||
this.host.writeFile(emitPath, PREAMBLE + generated.source, false, () => {},
|
||||
[sourceFile]);
|
||||
}
|
||||
})
|
||||
.catch((e) => { console.error(e.stack); });
|
||||
var compPromises = this.program.getSourceFiles()
|
||||
.map(sf => sf.fileName)
|
||||
.filter(f => !GENERATED_FILES.test(f))
|
||||
.map(generateOneFile);
|
||||
return Promise.all(stylesheetPromises.concat(compPromises));
|
||||
}
|
||||
|
||||
static create(options: AngularCompilerOptions, program: ts.Program,
|
||||
compilerHost: ts.CompilerHost): CodeGenerator {
|
||||
const xhr: compiler.XHR = {get: (s: string) => Promise.resolve(compilerHost.readFile(s))};
|
||||
const urlResolver: compiler.UrlResolver = compiler.createOfflineCompileUrlResolver();
|
||||
const reflectorHost = new NodeReflectorHost(program, compilerHost, options);
|
||||
const staticReflector = new StaticReflector(reflectorHost);
|
||||
StaticAndDynamicReflectionCapabilities.install(staticReflector);
|
||||
const htmlParser = new HtmlParser();
|
||||
const config = new compiler.CompilerConfig(true, true, true);
|
||||
const normalizer = new DirectiveNormalizer(xhr, urlResolver, htmlParser, config);
|
||||
const parser = new Parser(new Lexer());
|
||||
const tmplParser = new TemplateParser(parser, new DomElementSchemaRegistry(), htmlParser,
|
||||
/*console*/ null, []);
|
||||
const offlineCompiler = new compiler.OfflineCompiler(
|
||||
normalizer, tmplParser, new StyleCompiler(urlResolver),
|
||||
new ViewCompiler(new compiler.CompilerConfig(true, true, true)),
|
||||
new TypeScriptEmitter(reflectorHost), xhr);
|
||||
const resolver = new CompileMetadataResolver(
|
||||
new compiler.DirectiveResolver(staticReflector), new compiler.PipeResolver(staticReflector),
|
||||
new compiler.ViewResolver(staticReflector), null, null, staticReflector);
|
||||
|
||||
return new CodeGenerator(options, program, compilerHost, staticReflector, resolver,
|
||||
offlineCompiler, reflectorHost);
|
||||
}
|
||||
}
|
38
modules/@angular/compiler-cli/src/compiler_private.ts
Normal file
38
modules/@angular/compiler-cli/src/compiler_private.ts
Normal file
@ -0,0 +1,38 @@
|
||||
import {__compiler_private__ as _c} from '@angular/compiler';
|
||||
|
||||
export var AssetUrl: typeof _c.AssetUrl = _c.AssetUrl;
|
||||
export type AssetUrl = _c.AssetUrl;
|
||||
|
||||
export var ImportGenerator: typeof _c.ImportGenerator = _c.ImportGenerator;
|
||||
export type ImportGenerator = _c.ImportGenerator;
|
||||
|
||||
export type CompileMetadataResolver = _c.CompileMetadataResolver;
|
||||
export var CompileMetadataResolver: typeof _c.CompileMetadataResolver = _c.CompileMetadataResolver;
|
||||
|
||||
export type HtmlParser = _c.HtmlParser;
|
||||
export var HtmlParser: typeof _c.HtmlParser = _c.HtmlParser;
|
||||
|
||||
export type DirectiveNormalizer = _c.DirectiveNormalizer;
|
||||
export var DirectiveNormalizer: typeof _c.DirectiveNormalizer = _c.DirectiveNormalizer;
|
||||
|
||||
export type Lexer = _c.Lexer;
|
||||
export var Lexer: typeof _c.Lexer = _c.Lexer;
|
||||
|
||||
export type Parser = _c.Parser;
|
||||
export var Parser: typeof _c.Parser = _c.Parser;
|
||||
|
||||
export type TemplateParser = _c.TemplateParser;
|
||||
export var TemplateParser: typeof _c.TemplateParser = _c.TemplateParser;
|
||||
|
||||
export type DomElementSchemaRegistry = _c.DomElementSchemaRegistry;
|
||||
export var DomElementSchemaRegistry: typeof _c.DomElementSchemaRegistry =
|
||||
_c.DomElementSchemaRegistry;
|
||||
|
||||
export type StyleCompiler = _c.StyleCompiler;
|
||||
export var StyleCompiler: typeof _c.StyleCompiler = _c.StyleCompiler;
|
||||
|
||||
export type ViewCompiler = _c.ViewCompiler;
|
||||
export var ViewCompiler: typeof _c.ViewCompiler = _c.ViewCompiler;
|
||||
|
||||
export type TypeScriptEmitter = _c.TypeScriptEmitter;
|
||||
export var TypeScriptEmitter: typeof _c.TypeScriptEmitter = _c.TypeScriptEmitter;
|
9
modules/@angular/compiler-cli/src/core_private.ts
Normal file
9
modules/@angular/compiler-cli/src/core_private.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import {__core_private__ as r, __core_private_types__ as t} from '@angular/core';
|
||||
|
||||
export type ReflectorReader = t.ReflectorReader;
|
||||
export var ReflectorReader: typeof t.ReflectorReader = r.ReflectorReader;
|
||||
|
||||
export type ReflectionCapabilities = t.ReflectionCapabilities;
|
||||
export var ReflectionCapabilities: typeof t.ReflectionCapabilities = r.ReflectionCapabilities;
|
||||
|
||||
export var reflector: typeof t.reflector = r.reflector;
|
25
modules/@angular/compiler-cli/src/main.ts
Normal file
25
modules/@angular/compiler-cli/src/main.ts
Normal file
@ -0,0 +1,25 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
// Must be imported first, because angular2 decorators throws on load.
|
||||
import 'reflect-metadata';
|
||||
|
||||
import * as ts from 'typescript';
|
||||
import * as tsc from '@angular/tsc-wrapped';
|
||||
|
||||
import {CodeGenerator} from './codegen';
|
||||
|
||||
function codegen(ngOptions: tsc.AngularCompilerOptions, program: ts.Program, host: ts.CompilerHost) {
|
||||
return CodeGenerator.create(ngOptions, program, host).codegen();
|
||||
}
|
||||
|
||||
// CLI entry point
|
||||
if (require.main === module) {
|
||||
const args = require('minimist')(process.argv.slice(2));
|
||||
tsc.main(args.p || args.project || '.', args.basePath, codegen)
|
||||
.then(exitCode => process.exit(exitCode))
|
||||
.catch(e => {
|
||||
console.error(e.stack);
|
||||
console.error("Compilation failed");
|
||||
process.exit(1);
|
||||
});
|
||||
}
|
169
modules/@angular/compiler-cli/src/reflector_host.ts
Normal file
169
modules/@angular/compiler-cli/src/reflector_host.ts
Normal file
@ -0,0 +1,169 @@
|
||||
import {StaticReflectorHost, StaticSymbol} from './static_reflector';
|
||||
import * as ts from 'typescript';
|
||||
import {AngularCompilerOptions, MetadataCollector, ModuleMetadata} from '@angular/tsc-wrapped';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import {ImportGenerator, AssetUrl} from './compiler_private';
|
||||
|
||||
|
||||
const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/;
|
||||
const DTS = /\.d\.ts$/;
|
||||
|
||||
export class NodeReflectorHost implements StaticReflectorHost, ImportGenerator {
|
||||
private metadataCollector = new MetadataCollector();
|
||||
constructor(private program: ts.Program, private compilerHost: ts.CompilerHost,
|
||||
private options: AngularCompilerOptions) {}
|
||||
|
||||
angularImportLocations() {
|
||||
return {
|
||||
coreDecorators: '@angular/core/src/metadata',
|
||||
diDecorators: '@angular/core/src/di/decorators',
|
||||
diMetadata: '@angular/core/src/di/metadata',
|
||||
provider: '@angular/core/src/di/provider'
|
||||
};
|
||||
}
|
||||
private resolve(m: string, containingFile: string) {
|
||||
const resolved =
|
||||
ts.resolveModuleName(m, containingFile, this.options, this.compilerHost).resolvedModule;
|
||||
return resolved ? resolved.resolvedFileName : null;
|
||||
};
|
||||
|
||||
private normalizeAssetUrl(url: string): string {
|
||||
let assetUrl = AssetUrl.parse(url);
|
||||
return assetUrl ? `${assetUrl.packageName}/${assetUrl.modulePath}` : null;
|
||||
}
|
||||
|
||||
private resolveAssetUrl(url: string, containingFile: string): string {
|
||||
let assetUrl = this.normalizeAssetUrl(url);
|
||||
if (assetUrl) {
|
||||
return 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.
|
||||
* Relativize the paths by checking candidate prefixes of the absolute path, to see if
|
||||
* they are resolvable by the moduleResolution strategy from the CompilerHost.
|
||||
*/
|
||||
getImportPath(containingFile: string, importedFile: string) {
|
||||
importedFile = this.resolveAssetUrl(importedFile, containingFile);
|
||||
containingFile = this.resolveAssetUrl(containingFile, '');
|
||||
|
||||
// TODO(tbosch): if a file does not yet exist (because we compile it later),
|
||||
// we still need to create it so that the `resolve` method works!
|
||||
if (!this.compilerHost.fileExists(importedFile)) {
|
||||
if (this.options.trace) {
|
||||
console.log(`Generating empty file ${importedFile} to allow resolution of import`);
|
||||
}
|
||||
this.compilerHost.writeFile(importedFile, '', false);
|
||||
fs.writeFileSync(importedFile, '');
|
||||
}
|
||||
|
||||
const parts = importedFile.replace(EXT, '').split(path.sep).filter(p => !!p);
|
||||
|
||||
for (let index = parts.length - 1; index >= 0; index--) {
|
||||
let candidate = parts.slice(index, parts.length).join(path.sep);
|
||||
if (this.resolve('.' + path.sep + candidate, containingFile) === importedFile) {
|
||||
return `./${candidate}`;
|
||||
}
|
||||
if (this.resolve(candidate, containingFile) === importedFile) {
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
throw new Error(
|
||||
`Unable to find any resolvable import for ${importedFile} relative to ${containingFile}`);
|
||||
}
|
||||
|
||||
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.options.basePath, 'index.ts');
|
||||
}
|
||||
|
||||
try {
|
||||
let assetUrl = this.normalizeAssetUrl(module);
|
||||
if (assetUrl) {
|
||||
module = assetUrl;
|
||||
}
|
||||
const filePath = this.resolve(module, containingFile);
|
||||
|
||||
if (!filePath) {
|
||||
throw new Error(`Could not resolve module ${module} relative to ${containingFile}`);
|
||||
}
|
||||
|
||||
const tc = this.program.getTypeChecker();
|
||||
const sf = this.program.getSourceFile(filePath);
|
||||
|
||||
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 = 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>();
|
||||
|
||||
/**
|
||||
* 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): StaticSymbol {
|
||||
let key = `"${declarationFile}".${name}`;
|
||||
let result = this.typeCache.get(key);
|
||||
if (!result) {
|
||||
result = new StaticSymbol(declarationFile, name);
|
||||
this.typeCache.set(key, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// TODO(alexeagle): take a statictype
|
||||
getMetadataFor(filePath: string): ModuleMetadata {
|
||||
if (!fs.existsSync(filePath)) {
|
||||
throw new Error(`No such file '${filePath}'`);
|
||||
}
|
||||
if (DTS.test(filePath)) {
|
||||
const metadataPath = filePath.replace(DTS, '.metadata.json');
|
||||
if (fs.existsSync(metadataPath)) {
|
||||
return this.readMetadata(metadataPath);
|
||||
}
|
||||
}
|
||||
|
||||
let sf = this.program.getSourceFile(filePath);
|
||||
if (!sf) {
|
||||
throw new Error(`Source file ${filePath} not present in program.`);
|
||||
}
|
||||
const metadata = this.metadataCollector.getMetadata(sf);
|
||||
return metadata;
|
||||
}
|
||||
|
||||
readMetadata(filePath: string) {
|
||||
try {
|
||||
const result = JSON.parse(fs.readFileSync(filePath, {encoding: 'utf-8'}));
|
||||
return result;
|
||||
} catch (e) {
|
||||
console.error(`Failed to read JSON file ${filePath}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,41 @@
|
||||
import {ReflectionCapabilities, reflector} from './core_private';
|
||||
import {StaticReflector} from './static_reflector';
|
||||
|
||||
export class StaticAndDynamicReflectionCapabilities {
|
||||
static install(staticDelegate: StaticReflector) {
|
||||
reflector.updateCapabilities(new StaticAndDynamicReflectionCapabilities(staticDelegate));
|
||||
}
|
||||
|
||||
private dynamicDelegate = new ReflectionCapabilities();
|
||||
|
||||
constructor(private staticDelegate: StaticReflector) {}
|
||||
|
||||
isReflectionEnabled(): boolean { return true; }
|
||||
factory(type: any): Function { return this.dynamicDelegate.factory(type); }
|
||||
interfaces(type: any): any[] { return this.dynamicDelegate.interfaces(type); }
|
||||
hasLifecycleHook(type: any, lcInterface: /*Type*/ any, lcProperty: string): boolean {
|
||||
return isStaticType(type) ?
|
||||
this.staticDelegate.hasLifecycleHook(type, lcInterface, lcProperty) :
|
||||
this.dynamicDelegate.hasLifecycleHook(type, lcInterface, lcProperty);
|
||||
}
|
||||
parameters(type: any): any[][] {
|
||||
return isStaticType(type) ? this.staticDelegate.parameters(type) :
|
||||
this.dynamicDelegate.parameters(type);
|
||||
}
|
||||
annotations(type: any): any[] {
|
||||
return isStaticType(type) ? this.staticDelegate.annotations(type) :
|
||||
this.dynamicDelegate.annotations(type);
|
||||
}
|
||||
propMetadata(typeOrFunc: any): {[key: string]: any[]} {
|
||||
return isStaticType(typeOrFunc) ? this.staticDelegate.propMetadata(typeOrFunc) :
|
||||
this.dynamicDelegate.propMetadata(typeOrFunc);
|
||||
}
|
||||
getter(name: string) { return this.dynamicDelegate.getter(name); }
|
||||
setter(name: string) { return this.dynamicDelegate.setter(name); }
|
||||
method(name: string) { return this.dynamicDelegate.method(name); }
|
||||
importUri(type: any): string { return this.staticDelegate.importUri(type); }
|
||||
}
|
||||
|
||||
function isStaticType(type: any): boolean {
|
||||
return typeof type === 'object' && type.name && type.filePath;
|
||||
}
|
410
modules/@angular/compiler-cli/src/static_reflector.ts
Normal file
410
modules/@angular/compiler-cli/src/static_reflector.ts
Normal file
@ -0,0 +1,410 @@
|
||||
import {
|
||||
AttributeMetadata,
|
||||
DirectiveMetadata,
|
||||
ComponentMetadata,
|
||||
ContentChildrenMetadata,
|
||||
ContentChildMetadata,
|
||||
InputMetadata,
|
||||
HostBindingMetadata,
|
||||
HostListenerMetadata,
|
||||
OutputMetadata,
|
||||
PipeMetadata,
|
||||
ViewChildMetadata,
|
||||
ViewChildrenMetadata,
|
||||
ViewQueryMetadata,
|
||||
QueryMetadata,
|
||||
Provider,
|
||||
HostMetadata,
|
||||
OptionalMetadata,
|
||||
InjectableMetadata,
|
||||
SelfMetadata,
|
||||
SkipSelfMetadata,
|
||||
InjectMetadata,
|
||||
} from "@angular/core";
|
||||
import {ReflectorReader} from "./core_private";
|
||||
|
||||
/**
|
||||
* The host of the static resolver is expected to be able to provide module metadata in the form of
|
||||
* 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 {
|
||||
/**
|
||||
* Return a ModuleMetadata for the given module.
|
||||
*
|
||||
* @param modulePath is a string identifier for a module as an absolute path.
|
||||
* @returns the metadata for the given module.
|
||||
*/
|
||||
getMetadataFor(modulePath: string): {[key: string]: any};
|
||||
|
||||
/**
|
||||
* Resolve a symbol from an import statement form, to the file where it is declared.
|
||||
* @param module the location imported from
|
||||
* @param containingFile for relative imports, the path of the file containing the import
|
||||
*/
|
||||
findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol;
|
||||
|
||||
getStaticSymbol(declarationFile: string, name: string): StaticSymbol;
|
||||
|
||||
angularImportLocations():
|
||||
{coreDecorators: string, diDecorators: string, diMetadata: string, provider: string};
|
||||
}
|
||||
|
||||
/**
|
||||
* 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) {}
|
||||
}
|
||||
|
||||
/**
|
||||
* A static reflector implements enough of the Reflector API that is necessary to compile
|
||||
* templates statically.
|
||||
*/
|
||||
export class StaticReflector implements ReflectorReader {
|
||||
private annotationCache = new Map<StaticSymbol, any[]>();
|
||||
private propertyCache = new Map<StaticSymbol, {[key: string]: any}>();
|
||||
private parameterCache = new Map<StaticSymbol, any[]>();
|
||||
private metadataCache = new Map<string, {[key: string]: any}>();
|
||||
private conversionMap = new Map<StaticSymbol, (context: StaticSymbol, args: any[]) => any>();
|
||||
|
||||
constructor(private host: StaticReflectorHost) { this.initializeConversionMap(); }
|
||||
|
||||
importUri(typeOrFunc: StaticSymbol): string {
|
||||
var staticSymbol = this.host.findDeclaration(typeOrFunc.filePath, typeOrFunc.name, '');
|
||||
return staticSymbol ? staticSymbol.filePath : null;
|
||||
}
|
||||
|
||||
public annotations(type: StaticSymbol): any[] {
|
||||
let annotations = this.annotationCache.get(type);
|
||||
if (!annotations) {
|
||||
let classMetadata = this.getTypeMetadata(type);
|
||||
if (classMetadata['decorators']) {
|
||||
annotations = this.simplify(type, classMetadata['decorators']);
|
||||
} else {
|
||||
annotations = [];
|
||||
}
|
||||
this.annotationCache.set(type, annotations.filter(ann => !!ann));
|
||||
}
|
||||
return annotations;
|
||||
}
|
||||
|
||||
public propMetadata(type: StaticSymbol): {[key: string]: any} {
|
||||
let propMetadata = this.propertyCache.get(type);
|
||||
if (!propMetadata) {
|
||||
let classMetadata = this.getTypeMetadata(type);
|
||||
let members = classMetadata ? classMetadata['members'] : {};
|
||||
propMetadata = mapStringMap(members, (propData, propName) => {
|
||||
let prop = (<any[]>propData).find(a => a['__symbolic'] == 'property');
|
||||
if (prop && prop['decorators']) {
|
||||
return this.simplify(type, prop['decorators']);
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
});
|
||||
this.propertyCache.set(type, propMetadata);
|
||||
}
|
||||
return propMetadata;
|
||||
}
|
||||
|
||||
public parameters(type: StaticSymbol): any[] {
|
||||
if (!(type instanceof StaticSymbol)) {
|
||||
throw new Error(`parameters received ${JSON.stringify(type)} which is not a StaticSymbol`);
|
||||
}
|
||||
try {
|
||||
let parameters = this.parameterCache.get(type);
|
||||
if (!parameters) {
|
||||
let classMetadata = this.getTypeMetadata(type);
|
||||
let members = classMetadata ? classMetadata['members'] : null;
|
||||
let ctorData = members ? members['__ctor__'] : null;
|
||||
if (ctorData) {
|
||||
let ctor = (<any[]>ctorData).find(a => a['__symbolic'] == 'constructor');
|
||||
let parameterTypes = <any[]>this.simplify(type, ctor['parameters'] || []);
|
||||
let parameterDecorators = <any[]>this.simplify(type, ctor['parameterDecorators'] || []);
|
||||
|
||||
parameters = [];
|
||||
parameterTypes.forEach((paramType, index) => {
|
||||
let nestedResult: any[] = [];
|
||||
if (paramType) {
|
||||
nestedResult.push(paramType);
|
||||
}
|
||||
let decorators = parameterDecorators ? parameterDecorators[index] : null;
|
||||
if (decorators) {
|
||||
nestedResult.push(...decorators);
|
||||
}
|
||||
parameters.push(nestedResult);
|
||||
});
|
||||
}
|
||||
if (!parameters) {
|
||||
parameters = [];
|
||||
}
|
||||
this.parameterCache.set(type, parameters);
|
||||
}
|
||||
return parameters;
|
||||
} catch (e) {
|
||||
console.log(`Failed on type ${JSON.stringify(type)} with error ${e}`);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
hasLifecycleHook(type: any, lcInterface: /*Type*/ any, lcProperty: string): boolean {
|
||||
if (!(type instanceof StaticSymbol)) {
|
||||
throw new Error(
|
||||
`hasLifecycleHook received ${JSON.stringify(type)} which is not a StaticSymbol`);
|
||||
}
|
||||
let classMetadata = this.getTypeMetadata(type);
|
||||
let members = classMetadata ? classMetadata['members'] : null;
|
||||
let member:any[] = members ? members[lcProperty] : null;
|
||||
return member ? member.some(a => a['__symbolic'] == 'method') : false;
|
||||
}
|
||||
|
||||
private registerDecoratorOrConstructor(type: StaticSymbol, ctor: any): void {
|
||||
this.conversionMap.set(type, (context: StaticSymbol, args: any[]) => {
|
||||
let argValues: any[] = [];
|
||||
args.forEach((arg, index) => {
|
||||
let argValue: any;
|
||||
if (typeof arg === 'object' && !arg['__symbolic']) {
|
||||
argValue = mapStringMap(arg, (value, key) => this.simplify(context, value));
|
||||
} else {
|
||||
argValue = this.simplify(context, arg);
|
||||
}
|
||||
argValues.push(argValue);
|
||||
});
|
||||
var metadata = Object.create(ctor.prototype);
|
||||
ctor.apply(metadata, argValues);
|
||||
return metadata;
|
||||
});
|
||||
}
|
||||
|
||||
private initializeConversionMap(): void {
|
||||
const {coreDecorators, diDecorators, diMetadata, provider} = this.host.angularImportLocations();
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(provider, 'Provider'), Provider);
|
||||
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Host'),
|
||||
HostMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Injectable'),
|
||||
InjectableMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Self'),
|
||||
SelfMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'SkipSelf'),
|
||||
SkipSelfMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Inject'),
|
||||
InjectMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diDecorators, 'Optional'),
|
||||
OptionalMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Attribute'),
|
||||
AttributeMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Query'),
|
||||
QueryMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ViewQuery'),
|
||||
ViewQueryMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ContentChild'),
|
||||
ContentChildMetadata);
|
||||
this.registerDecoratorOrConstructor(
|
||||
this.host.findDeclaration(coreDecorators, 'ContentChildren'), ContentChildrenMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ViewChild'),
|
||||
ViewChildMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'ViewChildren'),
|
||||
ViewChildrenMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Input'),
|
||||
InputMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Output'),
|
||||
OutputMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Pipe'),
|
||||
PipeMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'HostBinding'),
|
||||
HostBindingMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'HostListener'),
|
||||
HostListenerMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Directive'),
|
||||
DirectiveMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(coreDecorators, 'Component'),
|
||||
ComponentMetadata);
|
||||
|
||||
// Note: Some metadata classes can be used directly with Provider.deps.
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'HostMetadata'),
|
||||
HostMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'SelfMetadata'),
|
||||
SelfMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'SkipSelfMetadata'),
|
||||
SkipSelfMetadata);
|
||||
this.registerDecoratorOrConstructor(this.host.findDeclaration(diMetadata, 'OptionalMetadata'),
|
||||
OptionalMetadata);
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
public simplify(context: StaticSymbol, value: any): any {
|
||||
let _this = this;
|
||||
|
||||
function simplify(expression: any): any {
|
||||
if (isPrimitive(expression)) {
|
||||
return expression;
|
||||
}
|
||||
if (expression instanceof Array) {
|
||||
let result: any[] = [];
|
||||
for (let item of(<any>expression)) {
|
||||
result.push(simplify(item));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
if (expression) {
|
||||
if (expression['__symbolic']) {
|
||||
let staticSymbol: StaticSymbol;
|
||||
switch (expression['__symbolic']) {
|
||||
case "binop":
|
||||
let left = simplify(expression['left']);
|
||||
let right = simplify(expression['right']);
|
||||
switch (expression['operator']) {
|
||||
case '&&':
|
||||
return left && right;
|
||||
case '||':
|
||||
return left || right;
|
||||
case '|':
|
||||
return left | right;
|
||||
case '^':
|
||||
return left ^ right;
|
||||
case '&':
|
||||
return left & right;
|
||||
case '==':
|
||||
return left == right;
|
||||
case '!=':
|
||||
return left != right;
|
||||
case '===':
|
||||
return left === right;
|
||||
case '!==':
|
||||
return left !== right;
|
||||
case '<':
|
||||
return left < right;
|
||||
case '>':
|
||||
return left > right;
|
||||
case '<=':
|
||||
return left <= right;
|
||||
case '>=':
|
||||
return left >= right;
|
||||
case '<<':
|
||||
return left << right;
|
||||
case '>>':
|
||||
return left >> right;
|
||||
case '+':
|
||||
return left + right;
|
||||
case '-':
|
||||
return left - right;
|
||||
case '*':
|
||||
return left * right;
|
||||
case '/':
|
||||
return left / right;
|
||||
case '%':
|
||||
return left % right;
|
||||
}
|
||||
return null;
|
||||
case "pre":
|
||||
let operand = simplify(expression['operand']);
|
||||
switch (expression['operator']) {
|
||||
case '+':
|
||||
return operand;
|
||||
case '-':
|
||||
return -operand;
|
||||
case '!':
|
||||
return !operand;
|
||||
case '~':
|
||||
return ~operand;
|
||||
}
|
||||
return null;
|
||||
case "index":
|
||||
let indexTarget = simplify(expression['expression']);
|
||||
let index = simplify(expression['index']);
|
||||
if (indexTarget && isPrimitive(index)) return indexTarget[index];
|
||||
return null;
|
||||
case "select":
|
||||
let selectTarget = simplify(expression['expression']);
|
||||
let member = simplify(expression['member']);
|
||||
if (selectTarget && isPrimitive(member)) return selectTarget[member];
|
||||
return null;
|
||||
case "reference":
|
||||
if (expression['module']) {
|
||||
staticSymbol = _this.host.findDeclaration(expression['module'], expression['name'],
|
||||
context.filePath);
|
||||
} else {
|
||||
staticSymbol = _this.host.getStaticSymbol(context.filePath, expression['name']);
|
||||
}
|
||||
let result = staticSymbol;
|
||||
let moduleMetadata = _this.getModuleMetadata(staticSymbol.filePath);
|
||||
let declarationValue =
|
||||
moduleMetadata ? moduleMetadata['metadata'][staticSymbol.name] : null;
|
||||
if (declarationValue) {
|
||||
result = _this.simplify(staticSymbol, declarationValue);
|
||||
}
|
||||
return result;
|
||||
case "class":
|
||||
return context;
|
||||
case "new":
|
||||
case "call":
|
||||
let target = expression['expression'];
|
||||
if (target['module']) {
|
||||
staticSymbol =
|
||||
_this.host.findDeclaration(target['module'], target['name'], context.filePath);
|
||||
} else {
|
||||
staticSymbol = _this.host.getStaticSymbol(context.filePath, target['name']);
|
||||
}
|
||||
let converter = _this.conversionMap.get(staticSymbol);
|
||||
if (converter) {
|
||||
let args = expression['arguments'];
|
||||
if (!args) {
|
||||
args = [];
|
||||
}
|
||||
return converter(context, args);
|
||||
} else {
|
||||
return context;
|
||||
}
|
||||
case "error":
|
||||
throw new Error(expression['message']);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
return mapStringMap(expression, (value, name) => simplify(value));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
return simplify(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param module an absolute path to a module file.
|
||||
*/
|
||||
public getModuleMetadata(module: string): {[key: string]: any} {
|
||||
let moduleMetadata = this.metadataCache.get(module);
|
||||
if (!moduleMetadata) {
|
||||
moduleMetadata = this.host.getMetadataFor(module);
|
||||
if (!moduleMetadata) {
|
||||
moduleMetadata = {__symbolic: "module", module: module, metadata: {}};
|
||||
}
|
||||
this.metadataCache.set(module, moduleMetadata);
|
||||
}
|
||||
return moduleMetadata;
|
||||
}
|
||||
|
||||
private getTypeMetadata(type: StaticSymbol): {[key: string]: any} {
|
||||
let moduleMetadata = this.getModuleMetadata(type.filePath);
|
||||
let result = moduleMetadata['metadata'][type.name];
|
||||
if (!result) {
|
||||
result = {__symbolic: "class"};
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function mapStringMap(input: {[key: string]: any},
|
||||
transform: (value: any, key: string) => any): {[key: string]: any} {
|
||||
if (!input) return {};
|
||||
var result: {[key: string]: any} = {};
|
||||
Object.keys(input).forEach((key) => { result[key] = transform(input[key], key); });
|
||||
return result;
|
||||
}
|
||||
|
||||
function isPrimitive(o: any): boolean {
|
||||
return o === null || (typeof o !== "function" && typeof o !== "object");
|
||||
}
|
429
modules/@angular/compiler-cli/test/static_reflector_spec.ts
Normal file
429
modules/@angular/compiler-cli/test/static_reflector_spec.ts
Normal file
@ -0,0 +1,429 @@
|
||||
import {
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
expect,
|
||||
ddescribe,
|
||||
beforeEach
|
||||
} from '@angular/core/testing/testing_internal';
|
||||
import {isBlank} from '@angular/facade/src/lang';
|
||||
import {ListWrapper} from '@angular/facade/src/collection';
|
||||
|
||||
import {
|
||||
StaticReflector,
|
||||
StaticReflectorHost,
|
||||
StaticSymbol
|
||||
} from '@angular/compiler-cli/src/static_reflector';
|
||||
|
||||
describe('StaticReflector', () => {
|
||||
let noContext = new StaticSymbol('', '');
|
||||
let host: StaticReflectorHost;
|
||||
let reflector: StaticReflector;
|
||||
|
||||
beforeEach(() => {
|
||||
host = new MockReflectorHost();
|
||||
reflector = new StaticReflector(host);
|
||||
});
|
||||
|
||||
function simplify(context: StaticSymbol, value: any) {
|
||||
return reflector.simplify(context, value);
|
||||
}
|
||||
|
||||
it('should get annotations for NgFor', () => {
|
||||
let NgFor = host.findDeclaration('angular2/src/common/directives/ng_for', 'NgFor');
|
||||
let annotations = reflector.annotations(NgFor);
|
||||
expect(annotations.length).toEqual(1);
|
||||
let annotation = annotations[0];
|
||||
expect(annotation.selector).toEqual('[ngFor][ngForOf]');
|
||||
expect(annotation.inputs).toEqual(['ngForTrackBy', 'ngForOf', 'ngForTemplate']);
|
||||
});
|
||||
|
||||
it('should get constructor for NgFor', () => {
|
||||
let NgFor = host.findDeclaration('angular2/src/common/directives/ng_for', 'NgFor');
|
||||
let ViewContainerRef =
|
||||
host.findDeclaration('angular2/src/core/linker/view_container_ref', 'ViewContainerRef');
|
||||
let TemplateRef = host.findDeclaration('angular2/src/core/linker/template_ref', 'TemplateRef');
|
||||
let IterableDiffers = host.findDeclaration(
|
||||
'angular2/src/core/change_detection/differs/iterable_differs', 'IterableDiffers');
|
||||
let ChangeDetectorRef = host.findDeclaration(
|
||||
'angular2/src/core/change_detection/change_detector_ref', 'ChangeDetectorRef');
|
||||
|
||||
let parameters = reflector.parameters(NgFor);
|
||||
expect(parameters)
|
||||
.toEqual([[ViewContainerRef], [TemplateRef], [IterableDiffers], [ChangeDetectorRef]]);
|
||||
});
|
||||
|
||||
it('should get annotations for HeroDetailComponent', () => {
|
||||
let HeroDetailComponent =
|
||||
host.findDeclaration('src/app/hero-detail.component', 'HeroDetailComponent');
|
||||
let annotations = reflector.annotations(HeroDetailComponent);
|
||||
expect(annotations.length).toEqual(1);
|
||||
let annotation = annotations[0];
|
||||
expect(annotation.selector).toEqual('my-hero-detail');
|
||||
expect(annotation.directives)
|
||||
.toEqual([[host.findDeclaration('angular2/src/common/directives/ng_for', 'NgFor')]]);
|
||||
});
|
||||
|
||||
it('should get and empty annotation list for an unknown class', () => {
|
||||
let UnknownClass = host.findDeclaration('src/app/app.component', 'UnknownClass');
|
||||
let annotations = reflector.annotations(UnknownClass);
|
||||
expect(annotations).toEqual([]);
|
||||
});
|
||||
|
||||
it('should get propMetadata for HeroDetailComponent', () => {
|
||||
let HeroDetailComponent =
|
||||
host.findDeclaration('src/app/hero-detail.component', 'HeroDetailComponent');
|
||||
let props = reflector.propMetadata(HeroDetailComponent);
|
||||
expect(props['hero']).toBeTruthy();
|
||||
});
|
||||
|
||||
it('should get an empty object from propMetadata for an unknown class', () => {
|
||||
let UnknownClass = host.findDeclaration('src/app/app.component', 'UnknownClass');
|
||||
let properties = reflector.propMetadata(UnknownClass);
|
||||
expect(properties).toEqual({});
|
||||
});
|
||||
|
||||
it('should get empty parameters list for an unknown class ', () => {
|
||||
let UnknownClass = host.findDeclaration('src/app/app.component', 'UnknownClass');
|
||||
let parameters = reflector.parameters(UnknownClass);
|
||||
expect(parameters).toEqual([]);
|
||||
});
|
||||
|
||||
it('should simplify primitive into itself', () => {
|
||||
expect(simplify(noContext, 1)).toBe(1);
|
||||
expect(simplify(noContext, true)).toBe(true);
|
||||
expect(simplify(noContext, "some value")).toBe("some value");
|
||||
});
|
||||
|
||||
it('should simplify an array into a copy of the array',
|
||||
() => { expect(simplify(noContext, [1, 2, 3])).toEqual([1, 2, 3]); });
|
||||
|
||||
it('should simplify an object to a copy of the object', () => {
|
||||
let expr = {a: 1, b: 2, c: 3};
|
||||
expect(simplify(noContext, expr)).toEqual(expr);
|
||||
});
|
||||
|
||||
it('should simplify &&', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '&&', left: true, right: true}))).toBe(true);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '&&', left: true, right: false}))).toBe(false);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '&&', left: false, right: true}))).toBe(false);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '&&', left: false, right: false}))).toBe(false);
|
||||
});
|
||||
|
||||
it('should simplify ||', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '||', left: true, right: true}))).toBe(true);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '||', left: true, right: false}))).toBe(true);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '||', left: false, right: true}))).toBe(true);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '||', left: false, right: false}))).toBe(false);
|
||||
});
|
||||
|
||||
it('should simplify &', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '&', left: 0x22, right: 0x0F}))).toBe(0x22 & 0x0F);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '&', left: 0x22, right: 0xF0}))).toBe(0x22 & 0xF0);
|
||||
});
|
||||
|
||||
it('should simplify |', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0x0F}))).toBe(0x22 | 0x0F);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0xF0}))).toBe(0x22 | 0xF0);
|
||||
});
|
||||
|
||||
it('should simplify ^', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0x0F}))).toBe(0x22 | 0x0F);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '|', left: 0x22, right: 0xF0}))).toBe(0x22 | 0xF0);
|
||||
});
|
||||
|
||||
it('should simplify ==', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '==', left: 0x22, right: 0x22}))).toBe(0x22 == 0x22);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '==', left: 0x22, right: 0xF0}))).toBe(0x22 == 0xF0);
|
||||
});
|
||||
|
||||
it('should simplify !=', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '!=', left: 0x22, right: 0x22}))).toBe(0x22 != 0x22);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '!=', left: 0x22, right: 0xF0}))).toBe(0x22 != 0xF0);
|
||||
});
|
||||
|
||||
it('should simplify ===', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '===', left: 0x22, right: 0x22}))).toBe(0x22 === 0x22);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '===', left: 0x22, right: 0xF0}))).toBe(0x22 === 0xF0);
|
||||
});
|
||||
|
||||
it('should simplify !==', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '!==', left: 0x22, right: 0x22}))).toBe(0x22 !== 0x22);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '!==', left: 0x22, right: 0xF0}))).toBe(0x22 !== 0xF0);
|
||||
});
|
||||
|
||||
it('should simplify >', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '>', left: 1, right: 1}))).toBe(1 > 1);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '>', left: 1, right: 0}))).toBe(1 > 0);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '>', left: 0, right: 1}))).toBe(0 > 1);
|
||||
});
|
||||
|
||||
it('should simplify >=', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '>=', left: 1, right: 1}))).toBe(1 >= 1);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '>=', left: 1, right: 0}))).toBe(1 >= 0);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '>=', left: 0, right: 1}))).toBe(0 >= 1);
|
||||
});
|
||||
|
||||
it('should simplify <=', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '<=', left: 1, right: 1}))).toBe(1 <= 1);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '<=', left: 1, right: 0}))).toBe(1 <= 0);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '<=', left: 0, right: 1}))).toBe(0 <= 1);
|
||||
});
|
||||
|
||||
it('should simplify <', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '<', left: 1, right: 1}))).toBe(1 < 1);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '<', left: 1, right: 0}))).toBe(1 < 0);
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '<', left: 0, right: 1}))).toBe(0 < 1);
|
||||
});
|
||||
|
||||
it('should simplify <<', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '<<', left: 0x55, right: 2}))).toBe(0x55 << 2);
|
||||
});
|
||||
|
||||
it('should simplify >>', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '>>', left: 0x55, right: 2}))).toBe(0x55 >> 2);
|
||||
});
|
||||
|
||||
it('should simplify +', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '+', left: 0x55, right: 2}))).toBe(0x55 + 2);
|
||||
});
|
||||
|
||||
it('should simplify -', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '-', left: 0x55, right: 2}))).toBe(0x55 - 2);
|
||||
});
|
||||
|
||||
it('should simplify *', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '*', left: 0x55, right: 2}))).toBe(0x55 * 2);
|
||||
});
|
||||
|
||||
it('should simplify /', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '/', left: 0x55, right: 2}))).toBe(0x55 / 2);
|
||||
});
|
||||
|
||||
it('should simplify %', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'binop', operator: '%', left: 0x55, right: 2}))).toBe(0x55 % 2);
|
||||
});
|
||||
|
||||
it('should simplify prefix -', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'pre', operator: '-', operand: 2}))).toBe(-2);
|
||||
});
|
||||
|
||||
it('should simplify prefix ~', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'pre', operator: '~', operand: 2}))).toBe(~2);
|
||||
});
|
||||
|
||||
it('should simplify prefix !', () => {
|
||||
expect(simplify(noContext, ({ __symbolic: 'pre', operator: '!', operand: true}))).toBe(!true);
|
||||
expect(simplify(noContext, ({ __symbolic: 'pre', operator: '!', operand: false}))).toBe(!false);
|
||||
});
|
||||
|
||||
it('should simplify an array index', () => {
|
||||
expect(simplify(noContext, ({__symbolic: "index", expression: [1, 2, 3], index: 2}))).toBe(3);
|
||||
});
|
||||
|
||||
it('should simplify an object index', () => {
|
||||
let expr = {__symbolic: "select", expression: {a: 1, b: 2, c: 3}, member: "b"};
|
||||
expect(simplify(noContext, expr)).toBe(2);
|
||||
});
|
||||
|
||||
it('should simplify a module reference', () => {
|
||||
expect(simplify(new StaticSymbol('/src/cases', ''),
|
||||
({__symbolic: "reference", module: "./extern", name: "s"})))
|
||||
.toEqual("s");
|
||||
});
|
||||
|
||||
it('should simplify a non existing reference as a static symbol', () => {
|
||||
expect(simplify(new StaticSymbol('/src/cases', ''),
|
||||
({__symbolic: "reference", module: "./extern", name: "nonExisting"})))
|
||||
.toEqual(host.getStaticSymbol('/src/extern.d.ts', 'nonExisting'));
|
||||
});
|
||||
});
|
||||
|
||||
class MockReflectorHost implements StaticReflectorHost {
|
||||
private staticTypeCache = new Map<string, StaticSymbol>();
|
||||
|
||||
angularImportLocations() {
|
||||
return {
|
||||
coreDecorators: 'angular2/src/core/metadata',
|
||||
diDecorators: 'angular2/src/core/di/decorators',
|
||||
diMetadata: 'angular2/src/core/di/metadata',
|
||||
provider: 'angular2/src/core/di/provider'
|
||||
};
|
||||
}
|
||||
getStaticSymbol(declarationFile: string, name: string): StaticSymbol {
|
||||
var cacheKey = `${declarationFile}:${name}`;
|
||||
var result = this.staticTypeCache.get(cacheKey);
|
||||
if (isBlank(result)) {
|
||||
result = new StaticSymbol(declarationFile, name);
|
||||
this.staticTypeCache.set(cacheKey, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// In tests, assume that symbols are not re-exported
|
||||
findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol {
|
||||
function splitPath(path: string): string[] { return path.split(/\/|\\/g); }
|
||||
|
||||
function resolvePath(pathParts: string[]): string {
|
||||
let result: string[] = [];
|
||||
ListWrapper.forEachWithIndex(pathParts, (part, index) => {
|
||||
switch (part) {
|
||||
case '':
|
||||
case '.':
|
||||
if (index > 0) return;
|
||||
break;
|
||||
case '..':
|
||||
if (index > 0 && result.length != 0) result.pop();
|
||||
return;
|
||||
}
|
||||
result.push(part);
|
||||
});
|
||||
return result.join('/');
|
||||
}
|
||||
|
||||
function pathTo(from: string, to: string): string {
|
||||
let result = to;
|
||||
if (to.startsWith('.')) {
|
||||
let fromParts = splitPath(from);
|
||||
fromParts.pop(); // remove the file name.
|
||||
let toParts = splitPath(to);
|
||||
result = resolvePath(fromParts.concat(toParts));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
if (modulePath.indexOf('.') === 0) {
|
||||
return this.getStaticSymbol(pathTo(containingFile, modulePath) + '.d.ts', symbolName);
|
||||
}
|
||||
return this.getStaticSymbol('/tmp/' + modulePath + '.d.ts', symbolName);
|
||||
}
|
||||
|
||||
getMetadataFor(moduleId: string): any {
|
||||
let data: {[key: string]: any} = {
|
||||
'/tmp/angular2/src/common/forms/directives.d.ts': {
|
||||
"__symbolic": "module",
|
||||
"metadata": {
|
||||
"FORM_DIRECTIVES": [
|
||||
{
|
||||
"__symbolic": "reference",
|
||||
"name": "NgFor",
|
||||
"module": "angular2/src/common/directives/ng_for"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
'/tmp/angular2/src/common/directives/ng_for.d.ts': {
|
||||
"__symbolic": "module",
|
||||
"metadata": {
|
||||
"NgFor": {
|
||||
"__symbolic": "class",
|
||||
"decorators": [
|
||||
{
|
||||
"__symbolic": "call",
|
||||
"expression": {
|
||||
"__symbolic": "reference",
|
||||
"name": "Directive",
|
||||
"module": "../../core/metadata"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"selector": "[ngFor][ngForOf]",
|
||||
"inputs": ["ngForTrackBy", "ngForOf", "ngForTemplate"]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"members": {
|
||||
"__ctor__": [
|
||||
{
|
||||
"__symbolic": "constructor",
|
||||
"parameters": [
|
||||
{
|
||||
"__symbolic": "reference",
|
||||
"module": "../../core/linker/view_container_ref",
|
||||
"name": "ViewContainerRef"
|
||||
},
|
||||
{
|
||||
"__symbolic": "reference",
|
||||
"module": "../../core/linker/template_ref",
|
||||
"name": "TemplateRef"
|
||||
},
|
||||
{
|
||||
"__symbolic": "reference",
|
||||
"module": "../../core/change_detection/differs/iterable_differs",
|
||||
"name": "IterableDiffers"
|
||||
},
|
||||
{
|
||||
"__symbolic": "reference",
|
||||
"module": "../../core/change_detection/change_detector_ref",
|
||||
"name": "ChangeDetectorRef"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/tmp/angular2/src/core/linker/view_container_ref.d.ts':
|
||||
{"metadata": {"ViewContainerRef": {"__symbolic": "class"}}},
|
||||
'/tmp/angular2/src/core/linker/template_ref.d.ts':
|
||||
{"module": "./template_ref", "metadata": {"TemplateRef": {"__symbolic": "class"}}},
|
||||
'/tmp/angular2/src/core/change_detection/differs/iterable_differs.d.ts':
|
||||
{"metadata": {"IterableDiffers": {"__symbolic": "class"}}},
|
||||
'/tmp/angular2/src/core/change_detection/change_detector_ref.d.ts':
|
||||
{"metadata": {"ChangeDetectorRef": {"__symbolic": "class"}}},
|
||||
'/tmp/src/app/hero-detail.component.d.ts': {
|
||||
"__symbolic": "module",
|
||||
"metadata": {
|
||||
"HeroDetailComponent": {
|
||||
"__symbolic": "class",
|
||||
"decorators": [
|
||||
{
|
||||
"__symbolic": "call",
|
||||
"expression": {
|
||||
"__symbolic": "reference",
|
||||
"name": "Component",
|
||||
"module": "angular2/src/core/metadata"
|
||||
},
|
||||
"arguments": [
|
||||
{
|
||||
"selector": "my-hero-detail",
|
||||
"template":
|
||||
"\n <div *ngIf=\"hero\">\n <h2>{{hero.name}} details!</h2>\n <div><label>id: </label>{{hero.id}}</div>\n <div>\n <label>name: </label>\n <input [(ngModel)]=\"hero.name\" placeholder=\"name\"/>\n </div>\n </div>\n",
|
||||
"directives": [
|
||||
{
|
||||
"__symbolic": "reference",
|
||||
"name": "FORM_DIRECTIVES",
|
||||
"module": "angular2/src/common/forms/directives"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"members": {
|
||||
"hero": [
|
||||
{
|
||||
"__symbolic": "property",
|
||||
"decorators": [
|
||||
{
|
||||
"__symbolic": "call",
|
||||
"expression": {
|
||||
"__symbolic": "reference",
|
||||
"name": "Input",
|
||||
"module": "angular2/src/core/metadata"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
'/src/extern.d.ts': {"__symbolic": "module", metadata: {s: "s"}}
|
||||
};
|
||||
return data[moduleId];
|
||||
}
|
||||
}
|
34
modules/@angular/compiler-cli/tsconfig-es5.json
Normal file
34
modules/@angular/compiler-cli/tsconfig-es5.json
Normal file
@ -0,0 +1,34 @@
|
||||
{
|
||||
"angularCompilerOptions": {
|
||||
"skipTemplateCodegen": true
|
||||
},
|
||||
"compilerOptions": {
|
||||
"module": "commonjs",
|
||||
"target": "es5",
|
||||
"lib": ["es6", "dom"],
|
||||
"noImplicitAny": true,
|
||||
"sourceMap": true,
|
||||
"baseUrl": ".",
|
||||
"paths": {
|
||||
"@angular/core": ["../../../dist/packages-dist/core"],
|
||||
"@angular/common": ["../../../dist/packages-dist/common"],
|
||||
"@angular/compiler": ["../../../dist/packages-dist/compiler"],
|
||||
"@angular/platform-server": ["../../../dist/packages-dist/platform-server"],
|
||||
"@angular/platform-browser": ["../../../dist/packages-dist/platform-browser"],
|
||||
"@angular/tsc-wrapped": ["../../../dist/tools/@angular/tsc-wrapped"]
|
||||
},
|
||||
"experimentalDecorators": true,
|
||||
"rootDir": ".",
|
||||
"sourceRoot": ".",
|
||||
"outDir": "../../../dist/packages-dist/compiler-cli",
|
||||
"declaration": true
|
||||
},
|
||||
"exclude": ["integrationtest"],
|
||||
"files": [
|
||||
"index.ts",
|
||||
"src/main.ts",
|
||||
"../../../node_modules/@types/node/index.d.ts",
|
||||
"../../../node_modules/@types/jasmine/index.d.ts",
|
||||
"../../../node_modules/zone.js/dist/zone.js.d.ts"
|
||||
]
|
||||
}
|
Reference in New Issue
Block a user