From 00d3b6083c8212ca74add314bd9b68ae02fa8f2d Mon Sep 17 00:00:00 2001 From: Tobias Bosch Date: Mon, 2 May 2016 09:38:46 -0700 Subject: [PATCH] fix(compiler): support css stylesheets in offline compiler --- .gitignore | 2 + modules/@angular/compiler/private_export.ts | 7 + .../@angular/compiler/src/compile_metadata.ts | 14 +- .../compiler/src/directive_normalizer.ts | 6 +- .../compiler/src/metadata_resolver.ts | 18 +- .../@angular/compiler/src/offline_compiler.ts | 64 ++++-- .../compiler/src/output/dart_emitter.ts | 6 +- .../compiler/src/output/dart_imports.ts | 52 +++++ .../compiler/src/output/js_emitter.ts | 9 +- .../@angular/compiler/src/output/path_util.ts | 65 +----- .../compiler/src/output/ts_emitter.ts | 6 +- .../@angular/compiler/src/runtime_compiler.ts | 8 +- .../@angular/compiler/src/style_compiler.ts | 2 +- .../compiler/test/compile_metadata_spec.ts | 3 +- .../test/directive_normalizer_spec.ts | 203 ++++++------------ .../compiler/test/metadata_resolver_spec.ts | 3 +- .../test/offline_compiler_codegen_typed.ts | 6 +- .../test/offline_compiler_codegen_untyped.ts | 4 +- .../compiler/test/offline_compiler_util.ts | 22 +- .../compiler/test/output/dart_emitter_spec.ts | 3 +- .../compiler/test/output/dart_imports_spec.ts | 64 ++++++ .../compiler/test/output/js_emitter_spec.ts | 10 +- .../output/output_emitter_codegen_typed.ts | 5 +- .../output/output_emitter_codegen_untyped.ts | 3 +- .../test/output/output_emitter_util.ts | 2 +- .../compiler/test/output/path_util_spec.ts | 69 ------ .../compiler/test/output/ts_emitter_spec.ts | 11 +- tools/compiler_cli/src/codegen.ts | 49 ++++- tools/compiler_cli/src/compiler_private.ts | 7 + tools/compiler_cli/src/reflector_host.ts | 51 +++-- tools/compiler_cli/src/static_reflector.ts | 13 +- .../compiler_cli/src/static_reflector_spec.ts | 18 +- tools/compiler_cli/test/src/basic.css | 3 + tools/compiler_cli/test/src/basic.html | 1 + tools/compiler_cli/test/src/basic.ts | 8 +- tools/compiler_cli/test/src/bootstrap.ts | 4 +- tools/compiler_cli/test/src/shared.css | 1 + tools/compiler_cli/test/tsconfig.json | 2 +- 38 files changed, 436 insertions(+), 388 deletions(-) create mode 100644 modules/@angular/compiler/src/output/dart_imports.ts create mode 100644 modules/@angular/compiler/test/output/dart_imports_spec.ts delete mode 100644 modules/@angular/compiler/test/output/path_util_spec.ts create mode 100644 tools/compiler_cli/src/compiler_private.ts create mode 100644 tools/compiler_cli/test/src/basic.css create mode 100644 tools/compiler_cli/test/src/shared.css diff --git a/.gitignore b/.gitignore index dcab35bb14..05a08bdc70 100644 --- a/.gitignore +++ b/.gitignore @@ -23,6 +23,8 @@ tmp # Files created by the template compiler **/*.ngfactory.ts +**/*.css.ts +**/*.css.shim.ts # Or type definitions we mirror from github # (NB: these lines are removed in publish-build-artifacts.sh) diff --git a/modules/@angular/compiler/private_export.ts b/modules/@angular/compiler/private_export.ts index 038b85026b..feec942e14 100644 --- a/modules/@angular/compiler/private_export.ts +++ b/modules/@angular/compiler/private_export.ts @@ -1,4 +1,5 @@ import * as selector from './src/selector'; +import * as pathUtil from './src/output/path_util'; export namespace __compiler_private__ { export type SelectorMatcher = selector.SelectorMatcher; @@ -6,4 +7,10 @@ export namespace __compiler_private__ { export type CssSelector = selector.CssSelector; export var CssSelector = selector.CssSelector; + + export type AssetUrl = pathUtil.AssetUrl; + export var AssetUrl = pathUtil.AssetUrl; + + export type ImportGenerator = pathUtil.ImportGenerator; + export var ImportGenerator = pathUtil.ImportGenerator; } diff --git a/modules/@angular/compiler/src/compile_metadata.ts b/modules/@angular/compiler/src/compile_metadata.ts index af74c35647..782bf0d7a4 100644 --- a/modules/@angular/compiler/src/compile_metadata.ts +++ b/modules/@angular/compiler/src/compile_metadata.ts @@ -466,16 +466,13 @@ export class CompileTemplateMetadata { styles: string[]; styleUrls: string[]; ngContentSelectors: string[]; - baseUrl: string; - constructor({encapsulation, template, templateUrl, styles, styleUrls, ngContentSelectors, - baseUrl}: { + constructor({encapsulation, template, templateUrl, styles, styleUrls, ngContentSelectors}: { encapsulation?: ViewEncapsulation, template?: string, templateUrl?: string, styles?: string[], styleUrls?: string[], - ngContentSelectors?: string[], - baseUrl?: string + ngContentSelectors?: string[] } = {}) { this.encapsulation = isPresent(encapsulation) ? encapsulation : ViewEncapsulation.Emulated; this.template = template; @@ -483,7 +480,6 @@ export class CompileTemplateMetadata { this.styles = isPresent(styles) ? styles : []; this.styleUrls = isPresent(styleUrls) ? styleUrls : []; this.ngContentSelectors = isPresent(ngContentSelectors) ? ngContentSelectors : []; - this.baseUrl = baseUrl; } static fromJson(data: {[key: string]: any}): CompileTemplateMetadata { @@ -495,8 +491,7 @@ export class CompileTemplateMetadata { templateUrl: data['templateUrl'], styles: data['styles'], styleUrls: data['styleUrls'], - ngContentSelectors: data['ngContentSelectors'], - baseUrl: data['baseUrl'] + ngContentSelectors: data['ngContentSelectors'] }); } @@ -508,8 +503,7 @@ export class CompileTemplateMetadata { 'templateUrl': this.templateUrl, 'styles': this.styles, 'styleUrls': this.styleUrls, - 'ngContentSelectors': this.ngContentSelectors, - 'baseUrl': this.baseUrl + 'ngContentSelectors': this.ngContentSelectors }; } } diff --git a/modules/@angular/compiler/src/directive_normalizer.ts b/modules/@angular/compiler/src/directive_normalizer.ts index 35c622c390..d6d1981b3d 100644 --- a/modules/@angular/compiler/src/directive_normalizer.ts +++ b/modules/@angular/compiler/src/directive_normalizer.ts @@ -63,9 +63,9 @@ export class DirectiveNormalizer { template: CompileTemplateMetadata): Promise { if (isPresent(template.template)) { return PromiseWrapper.resolve(this.normalizeLoadedTemplate( - directiveType, template, template.template, template.baseUrl)); + directiveType, template, template.template, directiveType.moduleUrl)); } else if (isPresent(template.templateUrl)) { - var sourceAbsUrl = this._urlResolver.resolve(template.baseUrl, template.templateUrl); + var sourceAbsUrl = this._urlResolver.resolve(directiveType.moduleUrl, template.templateUrl); return this._xhr.get(sourceAbsUrl) .then(templateContent => this.normalizeLoadedTemplate(directiveType, template, templateContent, sourceAbsUrl)); @@ -90,7 +90,7 @@ export class DirectiveNormalizer { visitor.styleUrls.filter(isStyleUrlResolvable) .map(url => this._urlResolver.resolve(templateAbsUrl, url)) .concat(templateMeta.styleUrls.filter(isStyleUrlResolvable) - .map(url => this._urlResolver.resolve(templateMeta.baseUrl, url))); + .map(url => this._urlResolver.resolve(directiveType.moduleUrl, url))); var allResolvedStyles = allStyles.map(style => { var styleWithImports = extractStyleUrls(this._urlResolver, templateAbsUrl, style); diff --git a/modules/@angular/compiler/src/metadata_resolver.ts b/modules/@angular/compiler/src/metadata_resolver.ts index 392e7ca8de..514ddafd6e 100644 --- a/modules/@angular/compiler/src/metadata_resolver.ts +++ b/modules/@angular/compiler/src/metadata_resolver.ts @@ -95,8 +95,7 @@ export class CompileMetadataResolver { template: viewMeta.template, templateUrl: viewMeta.templateUrl, styles: viewMeta.styles, - styleUrls: viewMeta.styleUrls, - baseUrl: calcTemplateBaseUrl(this._reflector, directiveType, cmpMeta) + styleUrls: viewMeta.styleUrls }); changeDetectionStrategy = cmpMeta.changeDetection; if (isPresent(dirMeta.viewProviders)) { @@ -118,7 +117,10 @@ export class CompileMetadataResolver { selector: dirMeta.selector, exportAs: dirMeta.exportAs, isComponent: isPresent(templateMeta), - type: this.getTypeMetadata(directiveType, staticTypeModuleUrl(directiveType)), + type: this.getTypeMetadata(directiveType, + isPresent(cmpMeta) ? + componentModuleUrl(this._reflector, directiveType, cmpMeta) : + staticTypeModuleUrl(dirMeta)), template: templateMeta, changeDetection: changeDetectionStrategy, inputs: dirMeta.inputs, @@ -392,7 +394,7 @@ function flattenArray(tree: any[], out: Array): void { } function isStaticType(value: any): boolean { - return isStringMap(value) && isPresent(value['name']) && isPresent(value['moduleId']); + return isStringMap(value) && isPresent(value['name']) && isPresent(value['filePath']); } function isValidType(value: any): boolean { @@ -400,13 +402,13 @@ function isValidType(value: any): boolean { } function staticTypeModuleUrl(value: any): string { - return isStaticType(value) ? value['moduleId'] : null; + return isStaticType(value) ? value['filePath'] : null; } -function calcTemplateBaseUrl(reflector: ReflectorReader, type: any, - cmpMetadata: ComponentMetadata): string { +function componentModuleUrl(reflector: ReflectorReader, type: any, + cmpMetadata: ComponentMetadata): string { if (isStaticType(type)) { - return type['filePath']; + return staticTypeModuleUrl(type); } if (isPresent(cmpMetadata.moduleId)) { diff --git a/modules/@angular/compiler/src/offline_compiler.ts b/modules/@angular/compiler/src/offline_compiler.ts index ad8e742105..234ab986c1 100644 --- a/modules/@angular/compiler/src/offline_compiler.ts +++ b/modules/@angular/compiler/src/offline_compiler.ts @@ -15,6 +15,7 @@ import {TemplateParser} from './template_parser'; import {DirectiveNormalizer} from './directive_normalizer'; import {OutputEmitter} from './output/abstract_emitter'; import * as o from './output/output_ast'; +import {XHR} from './xhr'; import { MODULE_SUFFIX, @@ -31,6 +32,10 @@ export class SourceModule { constructor(public moduleUrl: string, public source: string) {} } +export class StyleSheetSourceWithImports { + constructor(public source: SourceModule, public importedUrls: string[]) {} +} + export class NormalizedComponentWithViewDirectives { constructor(public component: CompileDirectiveMetadata, public directives: CompileDirectiveMetadata[], public pipes: CompilePipeMetadata[]) {} @@ -39,7 +44,8 @@ export class NormalizedComponentWithViewDirectives { export class OfflineCompiler { constructor(private _directiveNormalizer: DirectiveNormalizer, private _templateParser: TemplateParser, private _styleCompiler: StyleCompiler, - private _viewCompiler: ViewCompiler, private _outputEmitter: OutputEmitter) {} + private _viewCompiler: ViewCompiler, private _outputEmitter: OutputEmitter, + private _xhr: XHR) {} normalizeDirectiveMetadata(directive: CompileDirectiveMetadata): Promise { @@ -80,15 +86,19 @@ export class OfflineCompiler { return this._codegenSourceModule(moduleUrl, statements, exportedVars); } - compileStylesheet(stylesheetUrl: string, cssText: string): SourceModule[] { - var plainStyles = this._styleCompiler.compileStylesheet(stylesheetUrl, cssText, false); - var shimStyles = this._styleCompiler.compileStylesheet(stylesheetUrl, cssText, true); - return [ - this._codegenSourceModule(_stylesModuleUrl(stylesheetUrl, false), - _resolveStyleStatements(plainStyles), [plainStyles.stylesVar]), - this._codegenSourceModule(_stylesModuleUrl(stylesheetUrl, true), - _resolveStyleStatements(shimStyles), [shimStyles.stylesVar]) - ]; + loadAndCompileStylesheet(stylesheetUrl: string, shim: boolean, + suffix: string): Promise { + return this._xhr.get(stylesheetUrl) + .then((cssText) => { + var compileResult = this._styleCompiler.compileStylesheet(stylesheetUrl, cssText, shim); + var importedUrls = []; + compileResult.dependencies.forEach((dep) => { + importedUrls.push(dep.moduleUrl); + dep.valuePlaceholder.moduleUrl = _stylesModuleUrl(dep.moduleUrl, dep.isShimmed, suffix); + }); + return new StyleSheetSourceWithImports( + this._codgenStyles(stylesheetUrl, shim, suffix, compileResult), importedUrls); + }); } private _compileComponent(compMeta: CompileDirectiveMetadata, @@ -99,11 +109,18 @@ export class OfflineCompiler { directives, pipes, compMeta.type.name); var viewResult = this._viewCompiler.compileComponent(compMeta, parsedTemplate, o.variable(styleResult.stylesVar), pipes); - ListWrapper.addAll(targetStatements, _resolveStyleStatements(styleResult)); + ListWrapper.addAll(targetStatements, + _resolveStyleStatements(compMeta.type.moduleUrl, styleResult)); ListWrapper.addAll(targetStatements, _resolveViewStatements(viewResult)); return viewResult.viewFactoryVar; } + private _codgenStyles(inputUrl: string, shim: boolean, suffix: string, + stylesCompileResult: StylesCompileResult): SourceModule { + return this._codegenSourceModule(_stylesModuleUrl(inputUrl, shim, suffix), + stylesCompileResult.statements, + [stylesCompileResult.stylesVar]); + } private _codegenSourceModule(moduleUrl: string, statements: o.Statement[], exportedVars: string[]): SourceModule { @@ -119,21 +136,23 @@ function _resolveViewStatements(compileResult: ViewCompileResult): o.Statement[] } -function _resolveStyleStatements(compileResult: StylesCompileResult): o.Statement[] { +function _resolveStyleStatements(containingModuleUrl: string, + compileResult: StylesCompileResult): o.Statement[] { + var containingSuffix = _splitSuffix(containingModuleUrl)[1]; compileResult.dependencies.forEach((dep) => { - dep.valuePlaceholder.moduleUrl = _stylesModuleUrl(dep.sourceUrl, dep.isShimmed); + dep.valuePlaceholder.moduleUrl = + _stylesModuleUrl(dep.moduleUrl, dep.isShimmed, containingSuffix); }); return compileResult.statements; } function _templateModuleUrl(comp: CompileDirectiveMetadata): string { - var moduleUrl = comp.type.moduleUrl; - var urlWithoutSuffix = moduleUrl.substring(0, moduleUrl.length - MODULE_SUFFIX.length); - return `${urlWithoutSuffix}.ngfactory${MODULE_SUFFIX}`; + var urlWithSuffix = _splitSuffix(comp.type.moduleUrl); + return `${urlWithSuffix[0]}.ngfactory${urlWithSuffix[1]}`; } -function _stylesModuleUrl(stylesheetUrl: string, shim: boolean): string { - return shim ? `${stylesheetUrl}.shim${MODULE_SUFFIX}` : `${stylesheetUrl}${MODULE_SUFFIX}`; +function _stylesModuleUrl(stylesheetUrl: string, shim: boolean, suffix: string): string { + return shim ? `${stylesheetUrl}.shim${suffix}` : `${stylesheetUrl}${suffix}`; } function _assertComponent(meta: CompileDirectiveMetadata) { @@ -141,3 +160,12 @@ function _assertComponent(meta: CompileDirectiveMetadata) { throw new BaseException(`Could not compile '${meta.type.name}' because it is not a component.`); } } + +function _splitSuffix(path: string): string[] { + let lastDot = path.lastIndexOf('.'); + if (lastDot !== -1) { + return [path.substring(0, lastDot), path.substring(lastDot)]; + } else { + return [path, '']; + } +} \ No newline at end of file diff --git a/modules/@angular/compiler/src/output/dart_emitter.ts b/modules/@angular/compiler/src/output/dart_emitter.ts index f85dd5039a..a98dffe2dd 100644 --- a/modules/@angular/compiler/src/output/dart_emitter.ts +++ b/modules/@angular/compiler/src/output/dart_emitter.ts @@ -9,7 +9,7 @@ import { CATCH_ERROR_VAR, CATCH_STACK_VAR, } from './abstract_emitter'; -import {getImportModulePath, ImportEnv} from './path_util'; +import {ImportGenerator} from './path_util'; var _debugModuleUrl = 'asset://debug/lib'; @@ -37,7 +37,7 @@ export function debugOutputAstAsDart(ast: o.Statement | o.Expression | o.Type | } export class DartEmitter implements OutputEmitter { - constructor() {} + constructor(private _importGenerator: ImportGenerator) {} emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string { var srcParts = []; // Note: We are not creating a library here as Dart does not need it. @@ -49,7 +49,7 @@ export class DartEmitter implements OutputEmitter { converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => { srcParts.push( - `import '${getImportModulePath(moduleUrl, importedModuleUrl, ImportEnv.Dart)}' as ${prefix};`); + `import '${this._importGenerator.getImportPath(moduleUrl, importedModuleUrl)}' as ${prefix};`); }); srcParts.push(ctx.toSource()); return srcParts.join('\n'); diff --git a/modules/@angular/compiler/src/output/dart_imports.ts b/modules/@angular/compiler/src/output/dart_imports.ts new file mode 100644 index 0000000000..4981a1a003 --- /dev/null +++ b/modules/@angular/compiler/src/output/dart_imports.ts @@ -0,0 +1,52 @@ +import {BaseException} from '../../src/facade/exceptions'; +import {isPresent, isBlank, RegExpWrapper, Math} from '../../src/facade/lang'; +import {Injectable} from '@angular/core'; + +import {AssetUrl, ImportGenerator} from './path_util'; + +var _PATH_SEP = '/'; +var _PATH_SEP_RE = /\//g; + +@Injectable() +export class DartImportGenerator implements ImportGenerator { + getImportPath(moduleUrlStr: string, importedUrlStr: string): string { + var moduleUrl = AssetUrl.parse(moduleUrlStr, false); + var importedUrl = AssetUrl.parse(importedUrlStr, true); + if (isBlank(importedUrl)) { + return importedUrlStr; + } + // Try to create a relative path first + if (moduleUrl.firstLevelDir == importedUrl.firstLevelDir && + moduleUrl.packageName == importedUrl.packageName) { + return getRelativePath(moduleUrl.modulePath, importedUrl.modulePath); + } else if (importedUrl.firstLevelDir == 'lib') { + return `package:${importedUrl.packageName}/${importedUrl.modulePath}`; + } + throw new BaseException(`Can't import url ${importedUrlStr} from ${moduleUrlStr}`); + } +} + +export function getRelativePath(modulePath: string, importedPath: string): string { + var moduleParts = modulePath.split(_PATH_SEP_RE); + var importedParts = importedPath.split(_PATH_SEP_RE); + var longestPrefix = getLongestPathSegmentPrefix(moduleParts, importedParts); + + var resultParts = []; + var goParentCount = moduleParts.length - 1 - longestPrefix; + for (var i = 0; i < goParentCount; i++) { + resultParts.push('..'); + } + for (var i = longestPrefix; i < importedParts.length; i++) { + resultParts.push(importedParts[i]); + } + return resultParts.join(_PATH_SEP); +} + +export function getLongestPathSegmentPrefix(arr1: string[], arr2: string[]): number { + var prefixSize = 0; + var minLen = Math.min(arr1.length, arr2.length); + while (prefixSize < minLen && arr1[prefixSize] == arr2[prefixSize]) { + prefixSize++; + } + return prefixSize; +} \ No newline at end of file diff --git a/modules/@angular/compiler/src/output/js_emitter.ts b/modules/@angular/compiler/src/output/js_emitter.ts index b48d72d171..55bdb0d050 100644 --- a/modules/@angular/compiler/src/output/js_emitter.ts +++ b/modules/@angular/compiler/src/output/js_emitter.ts @@ -10,10 +10,10 @@ import { import {BaseException} from '@angular/core'; import {OutputEmitter, EmitterVisitorContext} from './abstract_emitter'; import {AbstractJsEmitterVisitor} from './abstract_js_emitter'; -import {getImportModulePath, ImportEnv} from './path_util'; +import {ImportGenerator} from './path_util'; export class JavaScriptEmitter implements OutputEmitter { - constructor() {} + constructor(private _importGenerator: ImportGenerator) {} emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string { var converter = new JsEmitterVisitor(moduleUrl); var ctx = EmitterVisitorContext.createRoot(exportedVars); @@ -21,8 +21,9 @@ export class JavaScriptEmitter implements OutputEmitter { var srcParts = []; converter.importsWithPrefixes.forEach((prefix, importedModuleUrl) => { // Note: can't write the real word for import as it screws up system.js auto detection... - srcParts.push(`var ${prefix} = req` + - `uire('${getImportModulePath(moduleUrl, importedModuleUrl, ImportEnv.JS)}');`); + srcParts.push( + `var ${prefix} = req` + + `uire('${this._importGenerator.getImportPath(moduleUrl, importedModuleUrl)}');`); }); srcParts.push(ctx.toSource()); return srcParts.join('\n'); diff --git a/modules/@angular/compiler/src/output/path_util.ts b/modules/@angular/compiler/src/output/path_util.ts index fbd9dc6fe3..9f4fd031ed 100644 --- a/modules/@angular/compiler/src/output/path_util.ts +++ b/modules/@angular/compiler/src/output/path_util.ts @@ -1,44 +1,24 @@ import {BaseException} from '../../src/facade/exceptions'; import {isPresent, isBlank, RegExpWrapper, Math} from '../../src/facade/lang'; +import {Injectable} from '@angular/core'; // asset:// var _ASSET_URL_RE = /asset:([^\/]+)\/([^\/]+)\/(.+)/g; -var _PATH_SEP = '/'; -var _PATH_SEP_RE = /\//g; - -export enum ImportEnv { - Dart, - JS -} - /** - * Returns the module path to use for an import. + * Interface that defines how import statements should be generated. */ -export function getImportModulePath(moduleUrlStr: string, importedUrlStr: string, - importEnv: ImportEnv): string { - var absolutePathPrefix: string = importEnv === ImportEnv.Dart ? `package:` : ''; - var moduleUrl = _AssetUrl.parse(moduleUrlStr, false); - var importedUrl = _AssetUrl.parse(importedUrlStr, true); - if (isBlank(importedUrl)) { - return importedUrlStr; - } +export abstract class ImportGenerator { + static parseAssetUrl(url: string): AssetUrl { return AssetUrl.parse(url); } - // Try to create a relative path first - if (moduleUrl.firstLevelDir == importedUrl.firstLevelDir && - moduleUrl.packageName == importedUrl.packageName) { - return getRelativePath(moduleUrl.modulePath, importedUrl.modulePath, importEnv); - } else if (importedUrl.firstLevelDir == 'lib') { - return `${absolutePathPrefix}${importedUrl.packageName}/${importedUrl.modulePath}`; - } - throw new BaseException(`Can't import url ${importedUrlStr} from ${moduleUrlStr}`); + abstract getImportPath(moduleUrlStr: string, importedUrlStr: string): string; } -class _AssetUrl { - static parse(url: string, allowNonMatching: boolean): _AssetUrl { +export class AssetUrl { + static parse(url: string, allowNonMatching: boolean = true): AssetUrl { var match = RegExpWrapper.firstMatch(_ASSET_URL_RE, url); if (isPresent(match)) { - return new _AssetUrl(match[1], match[2], match[3]); + return new AssetUrl(match[1], match[2], match[3]); } if (allowNonMatching) { return null; @@ -49,32 +29,3 @@ class _AssetUrl { constructor(public packageName: string, public firstLevelDir: string, public modulePath: string) { } } - -export function getRelativePath(modulePath: string, importedPath: string, - importEnv: ImportEnv): string { - var moduleParts = modulePath.split(_PATH_SEP_RE); - var importedParts = importedPath.split(_PATH_SEP_RE); - var longestPrefix = getLongestPathSegmentPrefix(moduleParts, importedParts); - - var resultParts = []; - var goParentCount = moduleParts.length - 1 - longestPrefix; - for (var i = 0; i < goParentCount; i++) { - resultParts.push('..'); - } - if (goParentCount <= 0 && importEnv === ImportEnv.JS) { - resultParts.push('.'); - } - for (var i = longestPrefix; i < importedParts.length; i++) { - resultParts.push(importedParts[i]); - } - return resultParts.join(_PATH_SEP); -} - -export function getLongestPathSegmentPrefix(arr1: string[], arr2: string[]): number { - var prefixSize = 0; - var minLen = Math.min(arr1.length, arr2.length); - while (prefixSize < minLen && arr1[prefixSize] == arr2[prefixSize]) { - prefixSize++; - } - return prefixSize; -} diff --git a/modules/@angular/compiler/src/output/ts_emitter.ts b/modules/@angular/compiler/src/output/ts_emitter.ts index 74256d5d89..041d8d328a 100644 --- a/modules/@angular/compiler/src/output/ts_emitter.ts +++ b/modules/@angular/compiler/src/output/ts_emitter.ts @@ -9,7 +9,7 @@ import { CATCH_ERROR_VAR, CATCH_STACK_VAR } from './abstract_emitter'; -import {getImportModulePath, ImportEnv} from './path_util'; +import {ImportGenerator} from './path_util'; var _debugModuleUrl = 'asset://debug/lib'; @@ -38,7 +38,7 @@ export function debugOutputAstAsTypeScript(ast: o.Statement | o.Expression | o.T } export class TypeScriptEmitter implements OutputEmitter { - constructor() {} + constructor(private _importGenerator: ImportGenerator) {} emitStatements(moduleUrl: string, stmts: o.Statement[], exportedVars: string[]): string { var converter = new _TsEmitterVisitor(moduleUrl); var ctx = EmitterVisitorContext.createRoot(exportedVars); @@ -48,7 +48,7 @@ export class TypeScriptEmitter implements OutputEmitter { // Note: can't write the real word for import as it screws up system.js auto detection... srcParts.push( `imp` + - `ort * as ${prefix} from '${getImportModulePath(moduleUrl, importedModuleUrl, ImportEnv.JS)}';`); + `ort * as ${prefix} from '${this._importGenerator.getImportPath(moduleUrl, importedModuleUrl)}';`); }); srcParts.push(ctx.toSource()); return srcParts.join('\n'); diff --git a/modules/@angular/compiler/src/runtime_compiler.ts b/modules/@angular/compiler/src/runtime_compiler.ts index 7c550e464b..850fcc7665 100644 --- a/modules/@angular/compiler/src/runtime_compiler.ts +++ b/modules/@angular/compiler/src/runtime_compiler.ts @@ -160,9 +160,9 @@ export class RuntimeCompiler implements ComponentResolver { var dep = result.dependencies[i]; var cssText = cssTexts[i]; var nestedCompileResult = - this._styleCompiler.compileStylesheet(dep.sourceUrl, cssText, dep.isShimmed); + this._styleCompiler.compileStylesheet(dep.moduleUrl, cssText, dep.isShimmed); nestedCompileResultPromises.push( - this._resolveStylesCompileResult(dep.sourceUrl, nestedCompileResult)); + this._resolveStylesCompileResult(dep.moduleUrl, nestedCompileResult)); } return PromiseWrapper.all(nestedCompileResultPromises); }) @@ -182,10 +182,10 @@ export class RuntimeCompiler implements ComponentResolver { } private _loadStylesheetDep(dep: StylesCompileDependency): Promise { - var cacheKey = `${dep.sourceUrl}${dep.isShimmed ? '.shim' : ''}`; + var cacheKey = `${dep.moduleUrl}${dep.isShimmed ? '.shim' : ''}`; var cssTextPromise = this._styleCache.get(cacheKey); if (isBlank(cssTextPromise)) { - cssTextPromise = this._xhr.get(dep.sourceUrl); + cssTextPromise = this._xhr.get(dep.moduleUrl); this._styleCache.set(cacheKey, cssTextPromise); } return cssTextPromise; diff --git a/modules/@angular/compiler/src/style_compiler.ts b/modules/@angular/compiler/src/style_compiler.ts index 0211c79793..36bb9a6459 100644 --- a/modules/@angular/compiler/src/style_compiler.ts +++ b/modules/@angular/compiler/src/style_compiler.ts @@ -11,7 +11,7 @@ const HOST_ATTR = /*@ts2dart_const*/ `_nghost-${COMPONENT_VARIABLE}`; const CONTENT_ATTR = /*@ts2dart_const*/ `_ngcontent-${COMPONENT_VARIABLE}`; export class StylesCompileDependency { - constructor(public sourceUrl: string, public isShimmed: boolean, + constructor(public moduleUrl: string, public isShimmed: boolean, public valuePlaceholder: CompileIdentifierMetadata) {} } diff --git a/modules/@angular/compiler/test/compile_metadata_spec.ts b/modules/@angular/compiler/test/compile_metadata_spec.ts index 68dce07d1f..f2715915c5 100644 --- a/modules/@angular/compiler/test/compile_metadata_spec.ts +++ b/modules/@angular/compiler/test/compile_metadata_spec.ts @@ -60,8 +60,7 @@ export function main() { templateUrl: 'someTemplateUrl', styles: ['someStyle'], styleUrls: ['someStyleUrl'], - ngContentSelectors: ['*'], - baseUrl: 'someBaseUrl' + ngContentSelectors: ['*'] }); fullDirectiveMeta = CompileDirectiveMetadata.create({ selector: 'someSelector', diff --git a/modules/@angular/compiler/test/directive_normalizer_spec.ts b/modules/@angular/compiler/test/directive_normalizer_spec.ts index 09404f3af0..ed75fd4f48 100644 --- a/modules/@angular/compiler/test/directive_normalizer_spec.ts +++ b/modules/@angular/compiler/test/directive_normalizer_spec.ts @@ -21,10 +21,15 @@ import {TEST_PROVIDERS} from './test_bindings'; export function main() { describe('DirectiveNormalizer', () => { var dirType: CompileTypeMetadata; + var dirTypeWithHttpUrl: CompileTypeMetadata; beforeEachProviders(() => TEST_PROVIDERS); - beforeEach(() => { dirType = new CompileTypeMetadata({name: 'SomeComp'}); }); + beforeEach(() => { + dirType = new CompileTypeMetadata({moduleUrl: 'package:some/module/a.js', name: 'SomeComp'}); + dirTypeWithHttpUrl = + new CompileTypeMetadata({moduleUrl: 'http://some/module/a.js', name: 'SomeComp'}); + }); describe('loadTemplate', () => { describe('inline template', () => { @@ -36,8 +41,7 @@ export function main() { template: 'a', templateUrl: null, styles: [], - styleUrls: ['test.css'], - baseUrl: 'package:some/module/a.js' + styleUrls: ['test.css'] })) .then((template: CompileTemplateMetadata) => { expect(template.template).toEqual('a'); @@ -46,7 +50,7 @@ export function main() { }); })); - it('should resolve styles on the annotation against the baseUrl', + it('should resolve styles on the annotation against the moduleUrl', inject([AsyncTestCompleter, DirectiveNormalizer], (async, normalizer: DirectiveNormalizer) => { normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({ @@ -54,8 +58,7 @@ export function main() { template: '', templateUrl: null, styles: [], - styleUrls: ['test.css'], - baseUrl: 'package:some/module/a.js' + styleUrls: ['test.css'] })) .then((template: CompileTemplateMetadata) => { expect(template.styleUrls).toEqual(['package:some/module/test.css']); @@ -63,7 +66,7 @@ export function main() { }); })); - it('should resolve styles in the template against the baseUrl', + it('should resolve styles in the template against the moduleUrl', inject([AsyncTestCompleter, DirectiveNormalizer], (async, normalizer: DirectiveNormalizer) => { normalizer.normalizeTemplate(dirType, new CompileTemplateMetadata({ @@ -71,8 +74,7 @@ export function main() { template: '', templateUrl: null, styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' + styleUrls: [] })) .then((template: CompileTemplateMetadata) => { expect(template.styleUrls).toEqual(['package:some/module/test.css']); @@ -83,7 +85,7 @@ export function main() { describe('templateUrl', () => { - it('should load a template from a url that is resolved against baseUrl', + it('should load a template from a url that is resolved against moduleUrl', inject([AsyncTestCompleter, DirectiveNormalizer, XHR], (async, normalizer: DirectiveNormalizer, xhr: MockXHR) => { xhr.expect('package:some/module/sometplurl.html', 'a'); @@ -92,8 +94,7 @@ export function main() { template: null, templateUrl: 'sometplurl.html', styles: [], - styleUrls: ['test.css'], - baseUrl: 'package:some/module/a.js' + styleUrls: ['test.css'] })) .then((template: CompileTemplateMetadata) => { expect(template.template).toEqual('a'); @@ -104,7 +105,7 @@ export function main() { xhr.flush(); })); - it('should resolve styles on the annotation against the baseUrl', + it('should resolve styles on the annotation against the moduleUrl', inject([AsyncTestCompleter, DirectiveNormalizer, XHR], (async, normalizer: DirectiveNormalizer, xhr: MockXHR) => { xhr.expect('package:some/module/tpl/sometplurl.html', ''); @@ -113,8 +114,7 @@ export function main() { template: null, templateUrl: 'tpl/sometplurl.html', styles: [], - styleUrls: ['test.css'], - baseUrl: 'package:some/module/a.js' + styleUrls: ['test.css'] })) .then((template: CompileTemplateMetadata) => { expect(template.styleUrls).toEqual(['package:some/module/test.css']); @@ -133,8 +133,7 @@ export function main() { template: null, templateUrl: 'tpl/sometplurl.html', styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' + styleUrls: [] })) .then((template: CompileTemplateMetadata) => { expect(template.styleUrls).toEqual(['package:some/module/tpl/test.css']); @@ -160,50 +159,36 @@ export function main() { inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var viewEncapsulation = ViewEncapsulation.Native; - var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ - encapsulation: viewEncapsulation, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), - '', 'package:some/module/'); + var template = normalizer.normalizeLoadedTemplate( + dirType, new CompileTemplateMetadata( + {encapsulation: viewEncapsulation, styles: [], styleUrls: []}), + '', 'package:some/module/'); expect(template.encapsulation).toBe(viewEncapsulation); })); it('should keep the template as html', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), - 'a', 'package:some/module/'); + var template = normalizer.normalizeLoadedTemplate( + dirType, + new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), 'a', + 'package:some/module/'); expect(template.template).toEqual('a') })); it('should collect ngContent', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), - '', - 'package:some/module/'); + var template = normalizer.normalizeLoadedTemplate( + dirType, + new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), + '', 'package:some/module/'); expect(template.ngContentSelectors).toEqual(['a']); })); it('should normalize ngContent wildcard selector', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate( - dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), + dirType, + new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), '', 'package:some/module/'); expect(template.ngContentSelectors).toEqual(['*', '*', '*']); @@ -211,91 +196,64 @@ export function main() { it('should collect top level styles in the template', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - var template = - normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), - '', 'package:some/module/'); + var template = normalizer.normalizeLoadedTemplate( + dirType, + new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), + '', 'package:some/module/'); expect(template.styles).toEqual(['a']); })); it('should collect styles inside in elements', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), - '
', - 'package:some/module/'); + var template = normalizer.normalizeLoadedTemplate( + dirType, + new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), + '
', 'package:some/module/'); expect(template.styles).toEqual(['a']); })); it('should collect styleUrls in the template', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), - '', - 'package:some/module/'); + var template = normalizer.normalizeLoadedTemplate( + dirType, + new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), + '', 'package:some/module/'); expect(template.styleUrls).toEqual(['package:some/module/aUrl']); })); it('should collect styleUrls in elements', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate( - dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), + dirType, + new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), '
', 'package:some/module/'); expect(template.styleUrls).toEqual(['package:some/module/aUrl']); })); it('should ignore link elements with non stylesheet rel attribute', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), - '', - 'package:some/module/'); + var template = normalizer.normalizeLoadedTemplate( + dirType, + new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), + '', 'package:some/module/'); expect(template.styleUrls).toEqual([]); })); it('should ignore link elements with absolute urls but non package: scheme', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate( - dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), + dirType, + new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), '', 'package:some/module/'); expect(template.styleUrls).toEqual([]); })); it('should extract @import style urls into styleAbsUrl', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: ['@import "test.css";'], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), - '', 'package:some/module/id'); + var template = normalizer.normalizeLoadedTemplate( + dirType, new CompileTemplateMetadata( + {encapsulation: null, styles: ['@import "test.css";'], styleUrls: []}), + '', 'package:some/module/id'); expect(template.styles).toEqual(['']); expect(template.styleUrls).toEqual(['package:some/module/test.css']); })); @@ -306,8 +264,7 @@ export function main() { dirType, new CompileTemplateMetadata({ encapsulation: null, styles: ['.foo{background-image: url(\'double.jpg\');'], - styleUrls: [], - baseUrl: 'package:some/module/a.js' + styleUrls: [] }), '', 'package:some/module/id'); expect(template.styles).toEqual(['.foo{background-image: url(\'double.jpg\');']); @@ -315,52 +272,38 @@ export function main() { it('should resolve relative style urls in styleUrls', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: ['test.css'], - baseUrl: 'package:some/module/a.js' - }), - '', 'package:some/module/id'); + var template = normalizer.normalizeLoadedTemplate( + dirType, new CompileTemplateMetadata( + {encapsulation: null, styles: [], styleUrls: ['test.css']}), + '', 'package:some/module/id'); expect(template.styles).toEqual([]); expect(template.styleUrls).toEqual(['package:some/module/test.css']); })); it('should resolve relative style urls in styleUrls with http directive url', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - var template = normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: ['test.css'], - baseUrl: 'http://some/module/a.js' - }), - '', 'http://some/module/id'); + var template = normalizer.normalizeLoadedTemplate( + dirTypeWithHttpUrl, new CompileTemplateMetadata( + {encapsulation: null, styles: [], styleUrls: ['test.css']}), + '', 'http://some/module/id'); expect(template.styles).toEqual([]); expect(template.styleUrls).toEqual(['http://some/module/test.css']); })); it('should normalize ViewEncapsulation.Emulated to ViewEncapsulation.None if there are no styles nor stylesheets', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { - var template = - normalizer.normalizeLoadedTemplate(dirType, new CompileTemplateMetadata({ - encapsulation: ViewEncapsulation.Emulated, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), - '', 'package:some/module/id'); + var template = normalizer.normalizeLoadedTemplate( + dirType, new CompileTemplateMetadata( + {encapsulation: ViewEncapsulation.Emulated, styles: [], styleUrls: []}), + '', 'package:some/module/id'); expect(template.encapsulation).toEqual(ViewEncapsulation.None); })); it('should ignore ng-content in elements with ngNonBindable', inject([DirectiveNormalizer], (normalizer: DirectiveNormalizer) => { var template = normalizer.normalizeLoadedTemplate( - dirType, new CompileTemplateMetadata({ - encapsulation: null, - styles: [], - styleUrls: [], - baseUrl: 'package:some/module/a.js' - }), + dirType, + new CompileTemplateMetadata({encapsulation: null, styles: [], styleUrls: []}), '
', 'package:some/module/'); expect(template.ngContentSelectors).toEqual([]); @@ -369,12 +312,8 @@ export function main() { it('should still collect ', 'package:some/module/'); expect(template.styles).toEqual(['div {color:red}']); })); diff --git a/modules/@angular/compiler/test/metadata_resolver_spec.ts b/modules/@angular/compiler/test/metadata_resolver_spec.ts index 076b6f1b1a..8aa02e7f22 100644 --- a/modules/@angular/compiler/test/metadata_resolver_spec.ts +++ b/modules/@angular/compiler/test/metadata_resolver_spec.ts @@ -62,13 +62,12 @@ export function main() { expect(meta.template.styleUrls).toEqual(['someStyleUrl']); expect(meta.template.template).toEqual('someTemplate'); expect(meta.template.templateUrl).toEqual('someTemplateUrl'); - expect(meta.template.baseUrl).toEqual(`package:someModuleId${MODULE_SUFFIX}`); })); it('should use the moduleUrl from the reflector if none is given', inject([CompileMetadataResolver], (resolver: CompileMetadataResolver) => { var value: string = - resolver.getDirectiveMetadata(ComponentWithoutModuleId).template.baseUrl; + resolver.getDirectiveMetadata(ComponentWithoutModuleId).type.moduleUrl; var expectedEndValue = IS_DART ? 'test/compiler/metadata_resolver_spec.dart' : './ComponentWithoutModuleId'; expect(value.endsWith(expectedEndValue)).toBe(true); diff --git a/modules/@angular/compiler/test/offline_compiler_codegen_typed.ts b/modules/@angular/compiler/test/offline_compiler_codegen_typed.ts index 15b2682388..bbb070f0c3 100644 --- a/modules/@angular/compiler/test/offline_compiler_codegen_typed.ts +++ b/modules/@angular/compiler/test/offline_compiler_codegen_typed.ts @@ -2,15 +2,17 @@ import {print, IS_DART} from '../src/facade/lang'; import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter'; import {DartEmitter} from '@angular/compiler/src/output/dart_emitter'; +import {DartImportGenerator} from '@angular/compiler/src/output/dart_imports'; import * as o from '@angular/compiler/src/output/output_ast'; import {compileComp, compAMetadata} from './offline_compiler_util'; import {ComponentFactory} from '@angular/core/src/linker/component_factory'; -import {CompA} from './offline_compiler_util'; +import {CompA, SimpleJsImportGenerator} from './offline_compiler_util'; export const CompANgFactory: ComponentFactory = null; export function emit(): Promise { - var emitter = IS_DART ? new DartEmitter() : new TypeScriptEmitter(); + var emitter = IS_DART ? new DartEmitter(new DartImportGenerator()) : + new TypeScriptEmitter(new SimpleJsImportGenerator()); return compileComp(emitter, compAMetadata); } diff --git a/modules/@angular/compiler/test/offline_compiler_codegen_untyped.ts b/modules/@angular/compiler/test/offline_compiler_codegen_untyped.ts index 8ffe3eeb09..383fc7a507 100644 --- a/modules/@angular/compiler/test/offline_compiler_codegen_untyped.ts +++ b/modules/@angular/compiler/test/offline_compiler_codegen_untyped.ts @@ -3,12 +3,12 @@ import {print} from '../src/facade/lang'; import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter'; import {compileComp, compAMetadata} from './offline_compiler_util'; import {ComponentFactory} from '@angular/core/src/linker/component_factory'; -import {CompA} from './offline_compiler_util'; +import {CompA, SimpleJsImportGenerator} from './offline_compiler_util'; export const CompANgFactory: ComponentFactory = null; export function emit() { - var emitter = new JavaScriptEmitter(); + var emitter = new JavaScriptEmitter(new SimpleJsImportGenerator()); return compileComp(emitter, compAMetadata); } diff --git a/modules/@angular/compiler/test/offline_compiler_util.ts b/modules/@angular/compiler/test/offline_compiler_util.ts index deb4d182c0..dd1fbc6847 100644 --- a/modules/@angular/compiler/test/offline_compiler_util.ts +++ b/modules/@angular/compiler/test/offline_compiler_util.ts @@ -1,4 +1,4 @@ -import {print, IS_DART} from '../src/facade/lang'; +import {print, isPresent, IS_DART} from '../src/facade/lang'; import {OutputEmitter} from '@angular/compiler/src/output/abstract_emitter'; import {Console} from '../core_private'; @@ -19,6 +19,7 @@ import {createOfflineCompileUrlResolver} from '@angular/compiler/src/url_resolve import {MockSchemaRegistry} from '../testing/schema_registry_mock'; import {MODULE_SUFFIX} from '@angular/compiler/src/util'; import {MockXHR} from '../testing/xhr_mock'; +import {ImportGenerator} from '@angular/compiler/src/output/path_util'; import { CompileDirectiveMetadata, @@ -29,7 +30,7 @@ import { export class CompA { user: string; } -var THIS_MODULE_PATH = `asset:angular2/test/compiler`; +var THIS_MODULE_PATH = `asset:@angular/lib/compiler/test`; var THIS_MODULE_URL = `${THIS_MODULE_PATH}/offline_compiler_util${MODULE_SUFFIX}`; export var compAMetadata = CompileDirectiveMetadata.create({ @@ -40,8 +41,7 @@ export var compAMetadata = CompileDirectiveMetadata.create({ template: new CompileTemplateMetadata({ templateUrl: './offline_compiler_compa.html', styles: ['.redStyle { color: red; }'], - styleUrls: ['./offline_compiler_compa.css'], - baseUrl: THIS_MODULE_URL, + styleUrls: ['./offline_compiler_compa.css'] }) }); @@ -54,7 +54,7 @@ function _createOfflineCompiler(xhr: MockXHR, emitter: OutputEmitter): OfflineCo normalizer, new TemplateParser(new Parser(new Lexer()), new MockSchemaRegistry({}, {}), htmlParser, new Console(), []), new StyleCompiler(urlResolver), new ViewCompiler(new CompilerConfig(true, true, true)), - emitter); + emitter, xhr); } export function compileComp(emitter: OutputEmitter, @@ -68,3 +68,15 @@ export function compileComp(emitter: OutputEmitter, xhr.flush(); return result; } + +export class SimpleJsImportGenerator implements ImportGenerator { + getImportPath(moduleUrlStr: string, importedUrlStr: string): string { + // var moduleAssetUrl = ImportGenerator.parseAssetUrl(moduleUrlStr); + var importedAssetUrl = ImportGenerator.parseAssetUrl(importedUrlStr); + if (isPresent(importedAssetUrl)) { + return `${importedAssetUrl.packageName}/${importedAssetUrl.modulePath}`; + } else { + return importedUrlStr; + } + } +} \ No newline at end of file diff --git a/modules/@angular/compiler/test/output/dart_emitter_spec.ts b/modules/@angular/compiler/test/output/dart_emitter_spec.ts index 7e5547e2e0..84e5a59eb6 100644 --- a/modules/@angular/compiler/test/output/dart_emitter_spec.ts +++ b/modules/@angular/compiler/test/output/dart_emitter_spec.ts @@ -13,6 +13,7 @@ import {isBlank} from '../../src/facade/lang'; import {DartEmitter} from '@angular/compiler/src/output/dart_emitter'; import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata'; import * as o from '@angular/compiler/src/output/output_ast'; +import {DartImportGenerator} from '@angular/compiler/src/output/dart_imports'; var someModuleUrl = 'asset:somePackage/lib/somePath'; var anotherModuleUrl = 'asset:somePackage/lib/someOtherPath'; @@ -36,7 +37,7 @@ export function main() { var someVar: o.ReadVarExpr; beforeEach(() => { - emitter = new DartEmitter(); + emitter = new DartEmitter(new DartImportGenerator()); someVar = o.variable('someVar'); }); diff --git a/modules/@angular/compiler/test/output/dart_imports_spec.ts b/modules/@angular/compiler/test/output/dart_imports_spec.ts new file mode 100644 index 0000000000..029be1bef2 --- /dev/null +++ b/modules/@angular/compiler/test/output/dart_imports_spec.ts @@ -0,0 +1,64 @@ +import { + beforeEach, + ddescribe, + describe, + expect, + iit, + inject, + it, + xit, +} from '@angular/core/testing/testing_internal'; + +import {DartImportGenerator} from '@angular/compiler/src/output/dart_imports'; + +export function main() { + describe('DartImportGenerator', () => { + describe('getImportPath', () => { + var generator: DartImportGenerator; + beforeEach(() => { generator = new DartImportGenerator(); }); + + it('should calculate relative paths Dart', () => { + expect(generator.getImportPath('asset:somePkg/lib/modPath', 'asset:somePkg/lib/impPath')) + .toEqual('impPath'); + }); + + it('should calculate relative paths for different constellations', () => { + expect(generator.getImportPath('asset:somePkg/test/modPath', 'asset:somePkg/test/impPath')) + .toEqual('impPath'); + expect( + generator.getImportPath('asset:somePkg/lib/modPath', 'asset:somePkg/lib/dir2/impPath')) + .toEqual('dir2/impPath'); + expect( + generator.getImportPath('asset:somePkg/lib/dir1/modPath', 'asset:somePkg/lib/impPath')) + .toEqual('../impPath'); + expect(generator.getImportPath('asset:somePkg/lib/dir1/modPath', + 'asset:somePkg/lib/dir2/impPath')) + .toEqual('../dir2/impPath'); + }); + + it('should calculate absolute paths', () => { + expect( + generator.getImportPath('asset:somePkg/lib/modPath', 'asset:someOtherPkg/lib/impPath')) + .toEqual('package:someOtherPkg/impPath'); + }); + + it('should not allow absolute imports of non lib modules', () => { + expect(() => generator.getImportPath('asset:somePkg/lib/modPath', + 'asset:somePkg/test/impPath')) + .toThrowError( + `Can't import url asset:somePkg/test/impPath from asset:somePkg/lib/modPath`); + }); + + it('should not allow non asset urls as base url', () => { + expect( + () => generator.getImportPath('http:somePkg/lib/modPath', 'asset:somePkg/test/impPath')) + .toThrowError(`Url http:somePkg/lib/modPath is not a valid asset: url`); + }); + + it('should allow non asset urls as import urls and pass them through', () => { + expect(generator.getImportPath('asset:somePkg/lib/modPath', 'dart:html')) + .toEqual('dart:html'); + }); + }); + }); +} diff --git a/modules/@angular/compiler/test/output/js_emitter_spec.ts b/modules/@angular/compiler/test/output/js_emitter_spec.ts index 3743ff67cc..89bd7751d3 100644 --- a/modules/@angular/compiler/test/output/js_emitter_spec.ts +++ b/modules/@angular/compiler/test/output/js_emitter_spec.ts @@ -13,6 +13,7 @@ import {isBlank} from '../../src/facade/lang'; import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter'; import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata'; import * as o from '@angular/compiler/src/output/output_ast'; +import {SimpleJsImportGenerator} from '../offline_compiler_util'; var someModuleUrl = 'asset:somePackage/lib/somePath'; var anotherModuleUrl = 'asset:somePackage/lib/someOtherPath'; @@ -33,7 +34,7 @@ export function main() { var someVar: o.ReadVarExpr; beforeEach(() => { - emitter = new JavaScriptEmitter(); + emitter = new JavaScriptEmitter(new SimpleJsImportGenerator()); someVar = o.variable('someVar'); }); @@ -111,9 +112,10 @@ export function main() { it('should support external identifiers', () => { expect(emitStmt(o.importExpr(sameModuleIdentifier).toStmt())).toEqual('someLocalId;'); expect(emitStmt(o.importExpr(externalModuleIdentifier).toStmt())) - .toEqual( - [`var import0 = re` + `quire('./someOtherPath');`, `import0.someExternalId;`].join( - '\n')); + .toEqual([ + `var import0 = re` + `quire('somePackage/someOtherPath');`, + `import0.someExternalId;` + ].join('\n')); }); it('should support operators', () => { diff --git a/modules/@angular/compiler/test/output/output_emitter_codegen_typed.ts b/modules/@angular/compiler/test/output/output_emitter_codegen_typed.ts index 4e1b9e5291..320ffa5c0e 100644 --- a/modules/@angular/compiler/test/output/output_emitter_codegen_typed.ts +++ b/modules/@angular/compiler/test/output/output_emitter_codegen_typed.ts @@ -4,8 +4,10 @@ import {unimplemented} from '../../src/facade/exceptions'; import {codegenExportsVars, codegenStmts} from './output_emitter_util'; import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter'; import {DartEmitter} from '@angular/compiler/src/output/dart_emitter'; +import {DartImportGenerator} from '@angular/compiler/src/output/dart_imports'; import * as o from '@angular/compiler/src/output/output_ast'; import {assetUrl} from '../../src/util'; +import {SimpleJsImportGenerator} from '../offline_compiler_util'; export function getExpressions(): any { return unimplemented(); @@ -13,7 +15,8 @@ export function getExpressions(): any { // Generator export function emit() { - var emitter = IS_DART ? new DartEmitter() : new TypeScriptEmitter(); + var emitter = IS_DART ? new DartEmitter(new DartImportGenerator()) : + new TypeScriptEmitter(new SimpleJsImportGenerator()); var emittedCode = emitter.emitStatements(assetUrl('compiler', 'output/output_emitter_codegen_typed', 'test'), codegenStmts, codegenExportsVars); diff --git a/modules/@angular/compiler/test/output/output_emitter_codegen_untyped.ts b/modules/@angular/compiler/test/output/output_emitter_codegen_untyped.ts index 5792e84c6f..f8f877a751 100644 --- a/modules/@angular/compiler/test/output/output_emitter_codegen_untyped.ts +++ b/modules/@angular/compiler/test/output/output_emitter_codegen_untyped.ts @@ -4,6 +4,7 @@ import {unimplemented} from '../../src/facade/exceptions'; import {codegenExportsVars, codegenStmts} from './output_emitter_util'; import {JavaScriptEmitter} from '@angular/compiler/src/output/js_emitter'; import {assetUrl} from '../../src/util'; +import {SimpleJsImportGenerator} from '../offline_compiler_util'; export function getExpressions(): any { return unimplemented(); @@ -11,7 +12,7 @@ export function getExpressions(): any { // Generator export function emit() { - var emitter = new JavaScriptEmitter(); + var emitter = new JavaScriptEmitter(new SimpleJsImportGenerator()); var emittedCode = emitter.emitStatements(assetUrl('compiler', 'output/output_emitter_codegen_untyped', 'test'), codegenStmts, codegenExportsVars); diff --git a/modules/@angular/compiler/test/output/output_emitter_util.ts b/modules/@angular/compiler/test/output/output_emitter_util.ts index 6cbe0f5f90..6dd8553882 100644 --- a/modules/@angular/compiler/test/output/output_emitter_util.ts +++ b/modules/@angular/compiler/test/output/output_emitter_util.ts @@ -15,7 +15,7 @@ export class ExternalClass { var testDataIdentifier = new CompileIdentifierMetadata({ name: 'ExternalClass', - moduleUrl: assetUrl('compiler', 'output/output_emitter_util'), + moduleUrl: `asset:@angular/lib/compiler/test/output/output_emitter_util`, runtime: ExternalClass }); diff --git a/modules/@angular/compiler/test/output/path_util_spec.ts b/modules/@angular/compiler/test/output/path_util_spec.ts deleted file mode 100644 index cd226b0e97..0000000000 --- a/modules/@angular/compiler/test/output/path_util_spec.ts +++ /dev/null @@ -1,69 +0,0 @@ -import { - beforeEach, - ddescribe, - describe, - expect, - iit, - inject, - it, - xit, -} from '@angular/core/testing/testing_internal'; - -import {getImportModulePath, ImportEnv} from '@angular/compiler/src/output/path_util'; - -export function main() { - describe('PathUtils', () => { - describe('getImportModulePath', () => { - it('should calculate relative paths for JS and Dart', () => { - expect(getImportModulePath('asset:somePkg/lib/modPath', 'asset:somePkg/lib/impPath', - ImportEnv.JS)) - .toEqual('./impPath'); - expect(getImportModulePath('asset:somePkg/lib/modPath', 'asset:somePkg/lib/impPath', - ImportEnv.Dart)) - .toEqual('impPath'); - }); - - it('should calculate relative paths for different constellations', () => { - expect(getImportModulePath('asset:somePkg/test/modPath', 'asset:somePkg/test/impPath', - ImportEnv.JS)) - .toEqual('./impPath'); - expect(getImportModulePath('asset:somePkg/lib/modPath', 'asset:somePkg/lib/dir2/impPath', - ImportEnv.JS)) - .toEqual('./dir2/impPath'); - expect(getImportModulePath('asset:somePkg/lib/dir1/modPath', 'asset:somePkg/lib/impPath', - ImportEnv.JS)) - .toEqual('../impPath'); - expect(getImportModulePath('asset:somePkg/lib/dir1/modPath', - 'asset:somePkg/lib/dir2/impPath', ImportEnv.JS)) - .toEqual('../dir2/impPath'); - }); - - it('should calculate absolute paths for JS and Dart', () => { - expect(getImportModulePath('asset:somePkg/lib/modPath', 'asset:someOtherPkg/lib/impPath', - ImportEnv.JS)) - .toEqual('someOtherPkg/impPath'); - expect(getImportModulePath('asset:somePkg/lib/modPath', 'asset:someOtherPkg/lib/impPath', - ImportEnv.Dart)) - .toEqual('package:someOtherPkg/impPath'); - }); - - it('should not allow absolute imports of non lib modules', () => { - expect(() => getImportModulePath('asset:somePkg/lib/modPath', 'asset:somePkg/test/impPath', - ImportEnv.Dart)) - .toThrowError( - `Can't import url asset:somePkg/test/impPath from asset:somePkg/lib/modPath`); - }); - - it('should not allow non asset urls as base url', () => { - expect(() => getImportModulePath('http:somePkg/lib/modPath', 'asset:somePkg/test/impPath', - ImportEnv.Dart)) - .toThrowError(`Url http:somePkg/lib/modPath is not a valid asset: url`); - }); - - it('should allow non asset urls as import urls and pass them through', () => { - expect(getImportModulePath('asset:somePkg/lib/modPath', 'dart:html', ImportEnv.Dart)) - .toEqual('dart:html'); - }); - }); - }); -} diff --git a/modules/@angular/compiler/test/output/ts_emitter_spec.ts b/modules/@angular/compiler/test/output/ts_emitter_spec.ts index a7cf3dab28..743f9e0fde 100644 --- a/modules/@angular/compiler/test/output/ts_emitter_spec.ts +++ b/modules/@angular/compiler/test/output/ts_emitter_spec.ts @@ -13,6 +13,7 @@ import {isBlank} from '../../src/facade/lang'; import {TypeScriptEmitter} from '@angular/compiler/src/output/ts_emitter'; import {CompileIdentifierMetadata} from '@angular/compiler/src/compile_metadata'; import * as o from '@angular/compiler/src/output/output_ast'; +import {SimpleJsImportGenerator} from '../offline_compiler_util'; var someModuleUrl = 'asset:somePackage/lib/somePath'; var anotherModuleUrl = 'asset:somePackage/lib/someOtherPath'; @@ -33,7 +34,7 @@ export function main() { var someVar: o.ReadVarExpr; beforeEach(() => { - emitter = new TypeScriptEmitter(); + emitter = new TypeScriptEmitter(new SimpleJsImportGenerator()); someVar = o.variable('someVar'); }); @@ -112,8 +113,10 @@ export function main() { it('should support external identifiers', () => { expect(emitStmt(o.importExpr(sameModuleIdentifier).toStmt())).toEqual('someLocalId;'); expect(emitStmt(o.importExpr(externalModuleIdentifier).toStmt())) - .toEqual([`import * as import0 from './someOtherPath';`, `import0.someExternalId;`].join( - '\n')); + .toEqual([ + `import * as import0 from 'somePackage/someOtherPath';`, + `import0.someExternalId;` + ].join('\n')); }); it('should support operators', () => { @@ -302,7 +305,7 @@ export function main() { .toEqual('var a:someLocalId = null;'); expect(emitStmt(writeVarExpr.toDeclStmt(o.importType(externalModuleIdentifier)))) .toEqual([ - `import * as import0 from './someOtherPath';`, + `import * as import0 from 'somePackage/someOtherPath';`, `var a:import0.someExternalId = null;` ].join('\n')); }); diff --git a/tools/compiler_cli/src/codegen.ts b/tools/compiler_cli/src/codegen.ts index d30e2864b4..135e3e1ef6 100644 --- a/tools/compiler_cli/src/codegen.ts +++ b/tools/compiler_cli/src/codegen.ts @@ -6,6 +6,7 @@ import * as ts from 'typescript'; import * as path from 'path'; import * as compiler from '@angular/compiler'; +import {ViewEncapsulation} from '@angular/core'; import {StaticReflector} from './static_reflector'; import {CompileMetadataResolver} from '@angular/compiler/src/metadata_resolver'; import {HtmlParser} from '@angular/compiler/src/html_parser'; @@ -22,7 +23,8 @@ import {Parse5DomAdapter} from '@angular/platform-server'; import {MetadataCollector} from 'ts-metadata-collector'; import {NodeReflectorHost} from './reflector_host'; -const SOURCE_EXTENSION = /\.[jt]s$/; +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. @@ -89,31 +91,55 @@ export class CodeGenerator { return result; } - codegen(): Promise { + // TODO(tbosch): add a cache for shared css files + // TODO(tbosch): detect cycles! + private generateStylesheet(filepath: string, shim: boolean): Promise { + return this.compiler.loadAndCompileStylesheet(filepath, shim, '.ts') + .then((sourceWithImports) => { + // Write codegen in a directory structure matching the sources. + // TODO(alexeagle): relativize paths by the rootDirs option + const emitPath = + path.join(this.ngOptions.genDir, + path.relative(this.basePath, sourceWithImports.source.moduleUrl)); + this.host.writeFile(emitPath, PREAMBLE + sourceWithImports.source.source, false); + return Promise.all( + sourceWithImports.importedUrls.map(url => this.generateStylesheet(url, shim))); + }); + } + + codegen(): Promise { Parse5DomAdapter.makeCurrent(); + const generateOneFile = (absSourcePath: string) => Promise.all(this.readComponents(absSourcePath)) .then((metadatas: compiler.CompileDirectiveMetadata[]) => { if (!metadatas || !metadatas.length) { return; } + let stylesheetPromises: Promise[] = []; + 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)); + }); + } + }); const generated = this.generateSource(metadatas); const sourceFile = this.program.getSourceFile(absSourcePath); // Write codegen in a directory structure matching the sources. - // TODO(alexeagle): maybe use generated.moduleUrl instead of hardcoded ".ngfactory.ts" // TODO(alexeagle): relativize paths by the rootDirs option - const emitPath = - path.join(this.ngOptions.genDir, path.relative(this.basePath, absSourcePath)) - .replace(SOURCE_EXTENSION, '.ngfactory.ts'); + const emitPath = path.join(this.ngOptions.genDir, + path.relative(this.basePath, generated.moduleUrl)); this.host.writeFile(emitPath, PREAMBLE + generated.source, false, () => {}, [sourceFile]); + return Promise.all(stylesheetPromises); }) .catch((e) => { console.error(e.stack); }); - - return Promise.all(this.program.getRootFileNames() - .filter(f => !/\.ngfactory\.ts$/.test(f)) - .map(generateOneFile)); + return Promise.all( + this.program.getRootFileNames().filter(f => !GENERATED_FILES.test(f)).map(generateOneFile)); } static create(ngOptions: AngularCompilerOptions, program: ts.Program, options: ts.CompilerOptions, @@ -129,7 +155,8 @@ export class CodeGenerator { /*console*/ null, []); const offlineCompiler = new compiler.OfflineCompiler( normalizer, tmplParser, new StyleCompiler(urlResolver), - new ViewCompiler(new compiler.CompilerConfig(true, true, true)), new TypeScriptEmitter()); + 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); diff --git a/tools/compiler_cli/src/compiler_private.ts b/tools/compiler_cli/src/compiler_private.ts new file mode 100644 index 0000000000..82c6bfeb97 --- /dev/null +++ b/tools/compiler_cli/src/compiler_private.ts @@ -0,0 +1,7 @@ +import {__compiler_private__ as _} from '@angular/compiler'; + +export var AssetUrl: typeof _.AssetUrl = _.AssetUrl; +export type AssetUrl = _.AssetUrl; + +export var ImportGenerator: typeof _.ImportGenerator = _.ImportGenerator; +export type ImportGenerator = _.ImportGenerator; diff --git a/tools/compiler_cli/src/reflector_host.ts b/tools/compiler_cli/src/reflector_host.ts index 6a81b9db6d..5eeb08bf2b 100644 --- a/tools/compiler_cli/src/reflector_host.ts +++ b/tools/compiler_cli/src/reflector_host.ts @@ -4,11 +4,12 @@ import {MetadataCollector, ModuleMetadata} from 'ts-metadata-collector'; import * as fs from 'fs'; import * as path from 'path'; import {AngularCompilerOptions} from './codegen'; +import {ImportGenerator, AssetUrl} from './compiler_private'; const EXT = /(\.ts|\.d\.ts|\.js|\.jsx|\.tsx)$/; const DTS = /\.d\.ts$/; -export class NodeReflectorHost implements StaticReflectorHost { +export class NodeReflectorHost implements StaticReflectorHost, ImportGenerator { private metadataCollector = new MetadataCollector(); constructor(private program: ts.Program, private compilerHost: ts.CompilerHost, private options: ts.CompilerOptions, private ngOptions: AngularCompilerOptions) {} @@ -33,34 +34,48 @@ export class NodeReflectorHost implements StaticReflectorHost { private resolve(m: string, containingFile: string) { const resolved = ts.resolveModuleName(m, containingFile, this.options, this.compilerHost).resolvedModule; - return resolved ? resolved.resolvedFileName : null + return resolved ? resolved.resolvedFileName : null; }; + + private resolveAssetUrl(url: string, containingFile: string): string { + let assetUrl = AssetUrl.parse(url); + if (assetUrl) { + return this.resolve(`${assetUrl.packageName}/${assetUrl.modulePath}`, 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. */ - private getModuleId(declarationFile: string, containingFile: string) { - const parts = declarationFile.replace(EXT, '').split(path.sep).filter(p => !!p); + getImportPath(containingFile: string, importedFile: string) { + importedFile = this.resolveAssetUrl(importedFile, ''); + 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)) { + 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(candidate, containingFile) === declarationFile) { - let pkg = parts[index]; - let pkgPath = parts.slice(index + 1, parts.length).join(path.sep); - return `asset:${pkg}/lib/${pkgPath}`; + if (this.resolve('.' + path.sep + candidate, containingFile) === importedFile) { + return `./${candidate}`; } - } - 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) === declarationFile) { - return `asset:./lib/${candidate}`; + if (this.resolve(candidate, containingFile) === importedFile) { + return candidate; } } throw new Error( - `Unable to find any resolvable import for ${declarationFile} relative to ${containingFile}`); + `Unable to find any resolvable import for ${importedFile} relative to ${containingFile}`); } findDeclaration(module: string, symbolName: string, containingFile: string, @@ -93,9 +108,8 @@ export class NodeReflectorHost implements StaticReflectorHost { } const declaration = symbol.getDeclarations()[0]; const declarationFile = declaration.getSourceFile().fileName; - const moduleId = this.getModuleId(declarationFile, containingFile); - return this.getStaticSymbol(moduleId, declarationFile, symbol.getName()); + return this.getStaticSymbol(declarationFile, symbol.getName()); } catch (e) { console.error(`can't resolve module ${module} from ${containingFile}`); throw e; @@ -108,15 +122,14 @@ export class NodeReflectorHost implements StaticReflectorHost { * 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 moduleId the module identifier as an absolute path. * @param declarationFile the absolute path of the file where the symbol is declared * @param name the name of the type. */ - getStaticSymbol(moduleId: string, declarationFile: string, name: string): StaticSymbol { + getStaticSymbol(declarationFile: string, name: string): StaticSymbol { let key = `"${declarationFile}".${name}`; let result = this.typeCache.get(key); if (!result) { - result = new StaticSymbol(moduleId, declarationFile, name); + result = new StaticSymbol(declarationFile, name); this.typeCache.set(key, result); } return result; diff --git a/tools/compiler_cli/src/static_reflector.ts b/tools/compiler_cli/src/static_reflector.ts index 2a89b93815..5ff06de381 100644 --- a/tools/compiler_cli/src/static_reflector.ts +++ b/tools/compiler_cli/src/static_reflector.ts @@ -43,9 +43,9 @@ import { */ export interface StaticReflectorHost { /** - * Return a ModuleMetadata for the given module. + * Return a ModuleMetadata for the given module. * - * @param moduleId 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. */ getMetadataFor(modulePath: string): {[key: string]: any}; @@ -57,7 +57,7 @@ export interface StaticReflectorHost { */ findDeclaration(modulePath: string, symbolName: string, containingFile?: string): StaticSymbol; - getStaticSymbol(moduleId: string, declarationFile: string, name: string): StaticSymbol; + getStaticSymbol(declarationFile: string, name: string): StaticSymbol; angularImportLocations(): {coreDecorators: string, diDecorators: string, diMetadata: string, provider: string}; @@ -66,10 +66,10 @@ export interface StaticReflectorHost { /** * A token representing the a reference to a static type. * - * This token is unique for a moduleId and name and can be used as a hash table key. + * This token is unique for a filePath and name and can be used as a hash table key. */ export class StaticSymbol { - constructor(public moduleId: string, public filePath: string, public name: string) {} + constructor(public filePath: string, public name: string) {} } /** @@ -324,8 +324,7 @@ export class StaticReflector implements ReflectorReader { staticSymbol = _this.host.findDeclaration(expression['module'], expression['name'], context.filePath); } else { - staticSymbol = _this.host.getStaticSymbol(context.moduleId, context.filePath, - expression['name']); + staticSymbol = _this.host.getStaticSymbol(context.filePath, expression['name']); } let result = staticSymbol; let moduleMetadata = _this.getModuleMetadata(staticSymbol.filePath); diff --git a/tools/compiler_cli/src/static_reflector_spec.ts b/tools/compiler_cli/src/static_reflector_spec.ts index 691de4f9ca..0b8e92fc34 100644 --- a/tools/compiler_cli/src/static_reflector_spec.ts +++ b/tools/compiler_cli/src/static_reflector_spec.ts @@ -14,7 +14,7 @@ import {ListWrapper} from '@angular/facade/src/collection'; import {StaticReflector, StaticReflectorHost, StaticSymbol} from './static_reflector'; describe('StaticReflector', () => { - let noContext = new StaticSymbol('', '', ''); + let noContext = new StaticSymbol('', ''); let host: StaticReflectorHost; let reflector: StaticReflector; @@ -34,7 +34,6 @@ describe('StaticReflector', () => { let annotation = annotations[0]; expect(annotation.selector).toEqual('[ngFor][ngForOf]'); expect(annotation.inputs).toEqual(['ngForTrackBy', 'ngForOf', 'ngForTemplate']); - }); it('should get constructor for NgFor', () => { @@ -226,15 +225,15 @@ describe('StaticReflector', () => { }); it('should simplify a module reference', () => { - expect(simplify(new StaticSymbol('', '/src/cases', ''), + 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', ''), + expect(simplify(new StaticSymbol('/src/cases', ''), ({__symbolic: "reference", module: "./extern", name: "nonExisting"}))) - .toEqual(host.getStaticSymbol('', '/src/extern.d.ts', 'nonExisting')); + .toEqual(host.getStaticSymbol('/src/extern.d.ts', 'nonExisting')); }); }); @@ -249,11 +248,11 @@ class MockReflectorHost implements StaticReflectorHost { provider: 'angular2/src/core/di/provider' }; } - getStaticSymbol(moduleId: string, declarationFile: string, name: string): StaticSymbol { + getStaticSymbol(declarationFile: string, name: string): StaticSymbol { var cacheKey = `${declarationFile}:${name}`; var result = this.staticTypeCache.get(cacheKey); if (isBlank(result)) { - result = new StaticSymbol(moduleId, declarationFile, name); + result = new StaticSymbol(declarationFile, name); this.staticTypeCache.set(cacheKey, result); } return result; @@ -292,10 +291,9 @@ class MockReflectorHost implements StaticReflectorHost { } if (modulePath.indexOf('.') === 0) { - return this.getStaticSymbol(`mod/${symbolName}`, pathTo(containingFile, modulePath) + '.d.ts', - symbolName); + return this.getStaticSymbol(pathTo(containingFile, modulePath) + '.d.ts', symbolName); } - return this.getStaticSymbol(`mod/${symbolName}`, '/tmp/' + modulePath + '.d.ts', symbolName); + return this.getStaticSymbol('/tmp/' + modulePath + '.d.ts', symbolName); } getMetadataFor(moduleId: string): any { diff --git a/tools/compiler_cli/test/src/basic.css b/tools/compiler_cli/test/src/basic.css new file mode 100644 index 0000000000..517161f74c --- /dev/null +++ b/tools/compiler_cli/test/src/basic.css @@ -0,0 +1,3 @@ +@import './shared.css'; + +.green { color: green } \ No newline at end of file diff --git a/tools/compiler_cli/test/src/basic.html b/tools/compiler_cli/test/src/basic.html index 1db443fdd6..a2e5268700 100644 --- a/tools/compiler_cli/test/src/basic.html +++ b/tools/compiler_cli/test/src/basic.html @@ -1,2 +1,3 @@
{{ctxProp}}
+ \ No newline at end of file diff --git a/tools/compiler_cli/test/src/basic.ts b/tools/compiler_cli/test/src/basic.ts index ed18ea481b..551e1b1ee2 100644 --- a/tools/compiler_cli/test/src/basic.ts +++ b/tools/compiler_cli/test/src/basic.ts @@ -2,7 +2,13 @@ import {Component, Inject} from '@angular/core'; import {FORM_DIRECTIVES} from '@angular/common'; import {MyComp} from './a/multiple_components'; -@Component({selector: 'basic', templateUrl: './basic.html', directives: [MyComp, FORM_DIRECTIVES]}) +@Component({ + selector: 'basic', + templateUrl: './basic.html', + styles: ['.red { color: red }'], + styleUrls: ['./basic.css'], + directives: [MyComp, FORM_DIRECTIVES] +}) export class Basic { ctxProp: string; constructor() { this.ctxProp = 'initiaValue'; } diff --git a/tools/compiler_cli/test/src/bootstrap.ts b/tools/compiler_cli/test/src/bootstrap.ts index 522cd14e23..145415c21c 100644 --- a/tools/compiler_cli/test/src/bootstrap.ts +++ b/tools/compiler_cli/test/src/bootstrap.ts @@ -1,8 +1,8 @@ import {coreBootstrap, ReflectiveInjector} from '@angular/core'; -import {browserPlatform, BROWSER_APP_PROVIDERS} from '@angular/platform-browser'; +import {browserPlatform, BROWSER_APP_STATIC_PROVIDERS} from '@angular/platform-browser'; import {BasicNgFactory} from './basic.ngfactory'; import {Basic} from './basic'; const appInjector = - ReflectiveInjector.resolveAndCreate(BROWSER_APP_PROVIDERS, browserPlatform().injector); + ReflectiveInjector.resolveAndCreate(BROWSER_APP_STATIC_PROVIDERS, browserPlatform().injector); coreBootstrap(appInjector, BasicNgFactory); diff --git a/tools/compiler_cli/test/src/shared.css b/tools/compiler_cli/test/src/shared.css new file mode 100644 index 0000000000..69ad252cce --- /dev/null +++ b/tools/compiler_cli/test/src/shared.css @@ -0,0 +1 @@ +.blue { color: blue } \ No newline at end of file diff --git a/tools/compiler_cli/test/tsconfig.json b/tools/compiler_cli/test/tsconfig.json index d9cee13591..1c404d285f 100644 --- a/tools/compiler_cli/test/tsconfig.json +++ b/tools/compiler_cli/test/tsconfig.json @@ -3,7 +3,7 @@ // For TypeScript 1.8, we have to lay out generated files // in the same source directory with your code. "genDir": ".", - "legacyPackageLayout": true + "legacyPackageLayout": false }, "compilerOptions": {