Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion modules/angular2/angular2.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,4 @@ export * from './platform/browser';
export * from './src/platform/dom/dom_adapter';
export * from './src/platform/dom/events/event_manager';
export * from './upgrade';
export {UrlResolver, AppRootUrl} from './compiler';
export {UrlResolver, AppRootUrl, getUrlScheme, DEFAULT_PACKAGE_URL_PROVIDER} from './compiler';
3 changes: 2 additions & 1 deletion modules/angular2/core.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ export {
APP_ID,
APP_COMPONENT,
APP_INITIALIZER,
PACKAGE_ROOT_URL,
PLATFORM_INITIALIZER
} from './src/core/application_tokens';
export * from './src/core/zone';
Expand All @@ -29,4 +30,4 @@ export * from './src/core/change_detection';
export * from './src/core/platform_directives_and_pipes';
export * from './src/core/platform_common_providers';
export * from './src/core/application_common_providers';
export * from './src/core/reflection/reflection';
export * from './src/core/reflection/reflection';
3 changes: 2 additions & 1 deletion modules/angular2/src/compiler/compiler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {Compiler} from 'angular2/src/core/linker/compiler';
import {RuntimeCompiler} from 'angular2/src/compiler/runtime_compiler';
import {ElementSchemaRegistry} from 'angular2/src/compiler/schema/element_schema_registry';
import {DomElementSchemaRegistry} from 'angular2/src/compiler/schema/dom_element_schema_registry';
import {UrlResolver} from 'angular2/src/compiler/url_resolver';
import {UrlResolver, DEFAULT_PACKAGE_URL_PROVIDER} from 'angular2/src/compiler/url_resolver';
import {AppRootUrl} from 'angular2/src/compiler/app_root_url';
import {AnchorBasedAppRootUrl} from 'angular2/src/compiler/anchor_based_app_root_url';
import {Parser, Lexer} from 'angular2/src/core/change_detection/change_detection';
Expand All @@ -40,6 +40,7 @@ export const COMPILER_PROVIDERS: Array<Type | Provider | any[]> = CONST_EXPR([
TemplateParser,
TemplateNormalizer,
RuntimeMetadataResolver,
DEFAULT_PACKAGE_URL_PROVIDER,
StyleCompiler,
CommandCompiler,
ChangeDetectionCompiler,
Expand Down
8 changes: 6 additions & 2 deletions modules/angular2/src/compiler/runtime_metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {reflector} from 'angular2/src/core/reflection/reflection';
import {Injectable, Inject, Optional} from 'angular2/src/core/di';
import {PLATFORM_DIRECTIVES} from 'angular2/src/core/platform_directives_and_pipes';
import {MODULE_SUFFIX} from './util';
import {getUrlScheme} from 'angular2/src/compiler/url_resolver';

@Injectable()
export class RuntimeMetadataResolver {
Expand Down Expand Up @@ -107,8 +108,11 @@ function isValidDirective(value: Type): boolean {
}

function calcModuleUrl(type: Type, dirMeta: md.DirectiveMetadata): string {
if (isPresent(dirMeta.moduleId)) {
return `package:${dirMeta.moduleId}${MODULE_SUFFIX}`;
var moduleId = dirMeta.moduleId;
if (isPresent(moduleId)) {
var scheme = getUrlScheme(moduleId);
return isPresent(scheme) && scheme.length > 0 ? moduleId :
`package:${moduleId}${MODULE_SUFFIX}`;
} else {
return reflector.importUri(type);
}
Expand Down
21 changes: 16 additions & 5 deletions modules/angular2/src/compiler/url_resolver.dart
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
library angular2.src.services.url_resolver;

import 'package:angular2/src/core/di.dart' show Injectable, Provider;
import 'package:angular2/src/core/di.dart' show Injectable, Inject, Provider;
import 'package:angular2/src/facade/lang.dart' show isPresent, StringWrapper;
import 'package:angular2/src/core/application_tokens.dart' show PACKAGE_ROOT_URL;

UrlResolver createWithoutPackagePrefix() {
return new UrlResolver.withUrlPrefix(null);
}

const DEFAULT_PACKAGE_URL_PROVIDER = const Provider(PACKAGE_ROOT_URL, useValue: "/packages");

@Injectable()
class UrlResolver {
/// This will be the location where 'package:' Urls will resolve. Default is
/// '/packages'
final String _packagePrefix;

const UrlResolver() : _packagePrefix = '/packages';
UrlResolver([@Inject(PACKAGE_ROOT_URL) packagePrefix]) :
this._packagePrefix = isPresent(packagePrefix) ? StringWrapper.stripRight(packagePrefix, '/') : null;

/// Creates a UrlResolver that will resolve 'package:' Urls to a different
/// prefixed location.
const UrlResolver.withUrlPrefix(this._packagePrefix);
UrlResolver.withUrlPrefix(this._packagePrefix);

/**
* Resolves the `url` given the `baseUrl`:
Expand All @@ -32,15 +37,21 @@ class UrlResolver {
*/
String resolve(String baseUrl, String url) {
Uri uri = Uri.parse(url);
if (!uri.isAbsolute) {

if (isPresent(baseUrl) && baseUrl.length > 0) {
Uri baseUri = Uri.parse(baseUrl);
uri = baseUri.resolveUri(uri);
}

if (_packagePrefix != null && uri.scheme == 'package') {
return '$_packagePrefix/${uri.path}';
var path = StringWrapper.stripLeft(uri.path, '/');
return '$_packagePrefix/${path}';
} else {
return uri.toString();
}
}
}

String getUrlScheme(String url) {
return Uri.parse(url).scheme;
}
37 changes: 34 additions & 3 deletions modules/angular2/src/compiler/url_resolver.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,21 @@
import {Injectable} from 'angular2/src/core/di';
import {isPresent, isBlank, RegExpWrapper, normalizeBlank} from 'angular2/src/facade/lang';
import {Injectable, Inject} from 'angular2/src/core/di';
import {
StringWrapper,
isPresent,
isBlank,
RegExpWrapper,
normalizeBlank
} from 'angular2/src/facade/lang';
import {BaseException, WrappedException} from 'angular2/src/facade/exceptions';
import {ListWrapper} from 'angular2/src/facade/collection';
import {PACKAGE_ROOT_URL} from 'angular2/src/core/application_tokens';
import {Provider} from 'angular2/src/core/di';

export function createWithoutPackagePrefix(): UrlResolver {
return new UrlResolver();
}

export var DEFAULT_PACKAGE_URL_PROVIDER = new Provider(PACKAGE_ROOT_URL, {useValue: "/"});

/**
* Used by the {@link Compiler} when resolving HTML and CSS template URLs.
Expand All @@ -17,6 +26,14 @@ export function createWithoutPackagePrefix(): UrlResolver {
*/
@Injectable()
export class UrlResolver {
private _packagePrefix: string;

constructor(@Inject(PACKAGE_ROOT_URL) packagePrefix: string = null) {
if (isPresent(packagePrefix)) {
this._packagePrefix = StringWrapper.stripRight(packagePrefix, "/") + "/";
}
}

/**
* Resolves the `url` given the `baseUrl`:
* - when the `url` is null, the `baseUrl` is returned,
Expand All @@ -29,7 +46,21 @@ export class UrlResolver {
* @param {string} url
* @returns {string} the resolved URL
*/
resolve(baseUrl: string, url: string): string { return _resolveUrl(baseUrl, url); }
resolve(baseUrl: string, url: string): string {
var resolvedUrl = url;
if (isPresent(baseUrl) && baseUrl.length > 0) {
resolvedUrl = _resolveUrl(baseUrl, resolvedUrl);
}
if (isPresent(this._packagePrefix) && getUrlScheme(resolvedUrl) == "package") {
resolvedUrl = resolvedUrl.replace("package:", this._packagePrefix);
}
return resolvedUrl;
}
}

export function getUrlScheme(url: string): string {
var match = _split(url);
return (match && match[_ComponentIndex.Scheme]) || "";
}

// The code below is adapted from Traceur:
Expand Down
8 changes: 7 additions & 1 deletion modules/angular2/src/core/application_tokens.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,4 +58,10 @@ export const PLATFORM_INITIALIZER: OpaqueToken =
/**
* A function that will be executed when an application is initialized.
*/
export const APP_INITIALIZER: OpaqueToken = CONST_EXPR(new OpaqueToken("Application Initializer"));
export const APP_INITIALIZER: OpaqueToken = CONST_EXPR(new OpaqueToken("Application Initializer"));

/**
* A token which indicates the root directory of the application
*/
export const PACKAGE_ROOT_URL: OpaqueToken =
CONST_EXPR(new OpaqueToken("Application Packages Root URL"));
24 changes: 24 additions & 0 deletions modules/angular2/src/facade/lang.dart
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,30 @@ class StringWrapper {
return s == s2;
}

static String stripLeft(String s, String charVal) {
if (isPresent(s) && s.length > 0) {
var pos = 0;
for (var i = 0; i < s.length; i++) {
if (s[i] != charVal) break;
pos++;
}
s = s.substring(pos);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you just do one substring at the end of the function?

}
return s;
}

static String stripRight(String s, String charVal) {
if (isPresent(s) && s.length > 0) {
var pos = s.length;
for (var i = s.length - 1; i >= 0; i--) {
if (s[i] != charVal) break;
pos--;
}
s = s.substring(0, pos);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you just do one substring at the end of the function?

}
return s;
}

static String replace(String s, Pattern from, String replace) {
return s.replaceFirst(from, replace);
}
Expand Down
24 changes: 24 additions & 0 deletions modules/angular2/src/facade/lang.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,30 @@ export class StringWrapper {

static equals(s: string, s2: string): boolean { return s === s2; }

static stripLeft(s: string, charVal: string): string {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see above

if (s && s.length) {
var pos = 0;
for (var i = 0; i < s.length; i++) {
if (s[i] != charVal) break;
pos++;
}
s = s.substring(pos);
}
return s;
}

static stripRight(s: string, charVal: string): string {
if (s && s.length) {
var pos = s.length;
for (var i = s.length - 1; i >= 0; i--) {
if (s[i] != charVal) break;
pos--;
}
s = s.substring(0, pos);
}
return s;
}

static replace(s: string, from: string, replace: string): string {
return s.replace(from, replace);
}
Expand Down
61 changes: 54 additions & 7 deletions modules/angular2/test/compiler/url_resolver_spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,15 @@
import {describe, it, expect, beforeEach, ddescribe, iit, xit, el} from 'angular2/testing_internal';
import {
describe,
it,
expect,
beforeEach,
ddescribe,
iit,
xit,
el,
inject
} from 'angular2/testing_internal';
import {IS_DART} from 'angular2/src/facade/lang';
import {UrlResolver} from 'angular2/src/compiler/url_resolver';

export function main() {
Expand Down Expand Up @@ -69,14 +80,50 @@ export function main() {
expect(resolver.resolve('foo/baz', '/bar')).toEqual('/bar');
expect(resolver.resolve('foo/baz/', '/bar')).toEqual('/bar');
});
});

describe('corner and error cases', () => {
it('should encode URLs before resolving', () => {
expect(resolver.resolve('foo/baz', `<p #p>Hello
</p>`))
.toEqual('foo/%3Cp%20#p%3EHello%0A%20%20%20%20%20%20%20%20%3C/p%3E');
it('should not resolve urls against the baseUrl when the url contains a scheme', () => {
resolver = new UrlResolver('my_packages_dir');
expect(resolver.resolve("base/", 'package:file')).toEqual('my_packages_dir/file');
expect(resolver.resolve("base/", 'http:super_file')).toEqual('http:super_file');
expect(resolver.resolve("base/", './mega_file')).toEqual('base/mega_file');
});
});

describe('packages',
() => {
it('should resolve a url based on the application package', () => {
resolver = new UrlResolver('my_packages_dir');
expect(resolver.resolve(null, 'package:some/dir/file.txt'))

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add a test where the baseUrl contains package: and the second argument is a relative url. Then the package url should also be resolved.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this test is still missing...

.toEqual('my_packages_dir/some/dir/file.txt');
expect(resolver.resolve(null, 'some/dir/file.txt')).toEqual('some/dir/file.txt');
});

it('should contain a default value of "/packages" when nothing is provided for DART',
inject([UrlResolver], (resolver) => {
if (IS_DART) {
expect(resolver.resolve(null, 'package:file')).toEqual('/packages/file');
}
}));

it('should contain a default value of "/" when nothing is provided for TS/ESM',
inject([UrlResolver], (resolver) => {
if (!IS_DART) {
expect(resolver.resolve(null, 'package:file')).toEqual('/file');
}
}));

it('should resolve a package value when present within the baseurl', () => {
resolver = new UrlResolver('/my_special_dir');
expect(resolver.resolve('package:some_dir/', 'matias.html'))
.toEqual('/my_special_dir/some_dir/matias.html');
});
})

describe('corner and error cases', () => {
it('should encode URLs before resolving', () => {
expect(resolver.resolve('foo/baz', `<p #p>Hello
</p>`)).toEqual('foo/%3Cp%20#p%3EHello%0A%20%20%20%20%20%20%20%20%3C/p%3E');
});
});
});
}
54 changes: 54 additions & 0 deletions modules/angular2/test/facade/lang_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -65,5 +65,59 @@ export function main() {
});
});

describe('stripLeft', () => {
it('should strip the first character of the string if it matches the provided input', () => {
var input = "~angular2 is amazing";
var expectedOutput = "angular2 is amazing";

expect(StringWrapper.stripLeft(input, "~")).toEqual(expectedOutput);
});

it('should keep stripping characters from the start until the first unmatched character',
() => {
var input = "#####hello";
var expectedOutput = "hello";
expect(StringWrapper.stripLeft(input, "#")).toEqual(expectedOutput);
});

it('should not alter the provided input if the first charater does not match the provided input',
() => {
var input = "+angular2 is amazing";
expect(StringWrapper.stripLeft(input, "*")).toEqual(input);
});

it('should not do any alterations when an empty string or null value is passed in', () => {
expect(StringWrapper.stripLeft("", "S")).toEqual("");
expect(StringWrapper.stripLeft(null, "S")).toEqual(null);
});
});

describe('stripRight', () => {
it('should strip the first character of the string if it matches the provided input', () => {
var input = "angular2 is amazing!";
var expectedOutput = "angular2 is amazing";

expect(StringWrapper.stripRight(input, "!")).toEqual(expectedOutput);
});

it('should not alter the provided input if the first charater does not match the provided input',
() => {
var input = "angular2 is amazing+";

expect(StringWrapper.stripRight(input, "*")).toEqual(input);
});

it('should keep stripping characters from the end until the first unmatched character',
() => {
var input = "hi&!&&&&&";
var expectedOutput = "hi&!";
expect(StringWrapper.stripRight(input, "&")).toEqual(expectedOutput);
});

it('should not do any alterations when an empty string or null value is passed in', () => {
expect(StringWrapper.stripRight("", "S")).toEqual("");
expect(StringWrapper.stripRight(null, "S")).toEqual(null);
});
});
});
}
3 changes: 3 additions & 0 deletions modules/angular2/test/public_api_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1196,6 +1196,9 @@ var NG_ALL = [
'UpperCasePipe.transform()',
'UrlResolver',
'UrlResolver.resolve()',
'getUrlScheme()',
'PACKAGE_ROOT_URL',
'DEFAULT_PACKAGE_URL_PROVIDER',
'Validators#compose()',
'Validators#composeAsync()',
'Validators#nullValidator()',
Expand Down
3 changes: 3 additions & 0 deletions modules/playground/e2e_test/relative_assets/assets_spec.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
library playground.e2e_test.relative_assets.assets_spec;

main() {}
Loading