fix(compiler): support css stylesheets in offline compiler

This commit is contained in:
Tobias Bosch
2016-05-02 09:38:46 -07:00
parent c386fc8379
commit 00d3b6083c
38 changed files with 436 additions and 388 deletions

View File

@ -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');

View File

@ -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;
}

View File

@ -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');

View File

@ -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:<package-name>/<realm>/<path-to-module>
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;
}

View File

@ -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');