refactor(pipes): use Injector instead of pipe factories for pipe instantiation

BREAKING CHANGE
    - Pipe factories have been removed.
    - PIpe names to pipe implementations are 1-to-1  instead of 1-to-*

 Before:
     class DateFormatter {
         transform(date, args){}
     }

     class DateFormatterFactory {
       supporst(obj) { return true; }
       create(cdRef) { return new DateFormatter(); }
     }
     new Pipes({date: [new DateFormatterFactory()]})

After
    class DateFormatter {
      transform(date, args){}
    }
    new Pipes({date: DateFormatter})
This commit is contained in:
vsavkin
2015-08-06 10:39:02 -07:00
parent 06da60f4b7
commit 2dcf714d2b
28 changed files with 249 additions and 524 deletions

View File

@ -1,22 +1,20 @@
import {JitProtoChangeDetector} from './jit_proto_change_detector';
import {PregenProtoChangeDetector} from './pregen_proto_change_detector';
import {DynamicProtoChangeDetector} from './proto_change_detector';
import {PipeFactory, Pipe} from './pipes/pipe';
import {Pipes} from './pipes/pipes';
import {IterableDiffers, IterableDifferFactory} from './differs/iterable_differs';
import {DefaultIterableDifferFactory} from './differs/default_iterable_differ';
import {KeyValueDiffers, KeyValueDifferFactory} from './differs/keyvalue_differs';
import {DefaultKeyValueDifferFactory} from './differs/default_keyvalue_differ';
import {AsyncPipeFactory} from './pipes/async_pipe';
import {AsyncPipe} from './pipes/async_pipe';
import {UpperCasePipe} from './pipes/uppercase_pipe';
import {LowerCasePipe} from './pipes/lowercase_pipe';
import {JsonPipe} from './pipes/json_pipe';
import {LimitToPipeFactory} from './pipes/limit_to_pipe';
import {LimitToPipe} from './pipes/limit_to_pipe';
import {DatePipe} from './pipes/date_pipe';
import {DecimalPipe, PercentPipe, CurrencyPipe} from './pipes/number_pipe';
import {NullPipeFactory} from './pipes/null_pipe';
import {ChangeDetection, ProtoChangeDetector, ChangeDetectorDefinition} from './interfaces';
import {Inject, Injectable, OpaqueToken, Optional} from 'angular2/di';
import {Injector, Inject, Injectable, OpaqueToken, Optional, Binding} from 'angular2/di';
import {List, StringMap, StringMapWrapper} from 'angular2/src/facade/collection';
import {CONST, CONST_EXPR, isPresent, BaseException} from 'angular2/src/facade/lang';
@ -55,10 +53,28 @@ export {ChangeDetectorRef} from './change_detector_ref';
export {Pipes} from './pipes/pipes';
export {IterableDiffers, IterableDiffer, IterableDifferFactory} from './differs/iterable_differs';
export {KeyValueDiffers, KeyValueDiffer, KeyValueDifferFactory} from './differs/keyvalue_differs';
export {WrappedValue, Pipe, PipeFactory, BasePipe} from './pipes/pipe';
export {NullPipe, NullPipeFactory} from './pipes/null_pipe';
export {WrappedValue, Pipe, BasePipe} from './pipes/pipe';
function createPipes(inj: Injector): Pipes {
return new Pipes(
{
"async": AsyncPipe,
"uppercase": UpperCasePipe,
"lowercase": LowerCasePipe,
"json": JsonPipe,
"limitTo": LimitToPipe,
"number": DecimalPipe,
"percent": PercentPipe,
"currency": CurrencyPipe,
"date": DatePipe
},
inj);
}
export const defaultPipes: Binding =
CONST_EXPR(new Binding(Pipes, {toFactory: createPipes, deps: [Injector]}));
/**
* Structural diffing for `Object`s and `Map`s.
*/
@ -71,73 +87,6 @@ export const keyValDiff: KeyValueDifferFactory[] =
export const iterableDiff: IterableDifferFactory[] =
CONST_EXPR([CONST_EXPR(new DefaultIterableDifferFactory())]);
/**
* Async binding to such types as Observable.
*/
export const async: List<PipeFactory> =
CONST_EXPR([CONST_EXPR(new AsyncPipeFactory()), CONST_EXPR(new NullPipeFactory())]);
/**
* Uppercase text transform.
*/
export const uppercase: List<PipeFactory> =
CONST_EXPR([CONST_EXPR(new UpperCasePipe()), CONST_EXPR(new NullPipeFactory())]);
/**
* Lowercase text transform.
*/
export const lowercase: List<PipeFactory> =
CONST_EXPR([CONST_EXPR(new LowerCasePipe()), CONST_EXPR(new NullPipeFactory())]);
/**
* Json stringify transform.
*/
export const json: List<PipeFactory> =
CONST_EXPR([CONST_EXPR(new JsonPipe()), CONST_EXPR(new NullPipeFactory())]);
/**
* LimitTo text transform.
*/
export const limitTo: List<PipeFactory> =
CONST_EXPR([CONST_EXPR(new LimitToPipeFactory()), CONST_EXPR(new NullPipeFactory())]);
/**
* Number number transform.
*/
export const decimal: List<PipeFactory> =
CONST_EXPR([CONST_EXPR(new DecimalPipe()), CONST_EXPR(new NullPipeFactory())]);
/**
* Percent number transform.
*/
export const percent: List<PipeFactory> =
CONST_EXPR([CONST_EXPR(new PercentPipe()), CONST_EXPR(new NullPipeFactory())]);
/**
* Currency number transform.
*/
export const currency: List<PipeFactory> =
CONST_EXPR([CONST_EXPR(new CurrencyPipe()), CONST_EXPR(new NullPipeFactory())]);
/**
* Date/time formatter.
*/
export const date: List<PipeFactory> =
CONST_EXPR([CONST_EXPR(new DatePipe()), CONST_EXPR(new NullPipeFactory())]);
export const defaultPipes: Pipes = CONST_EXPR(new Pipes({
"async": async,
"uppercase": uppercase,
"lowercase": lowercase,
"json": json,
"limitTo": limitTo,
"number": decimal,
"percent": percent,
"currency": currency,
"date": date
}));
export const defaultIterableDiffers = CONST_EXPR(new IterableDiffers(iterableDiff));
export const defaultKeyValueDiffers = CONST_EXPR(new KeyValueDiffers(keyValDiff));

View File

@ -184,10 +184,7 @@ export class ChangeDetectorJITGenerator {
var read = `
if (${pipe} === ${UTIL}.uninitialized) {
${pipe} = ${this._names.getPipesAccessorName()}.get('${pipeType}', ${context}, ${cdRef});
} else if (!${pipe}.supports(${context})) {
${pipe}.onDestroy();
${pipe} = ${this._names.getPipesAccessorName()}.get('${pipeType}', ${context}, ${cdRef});
${pipe} = ${this._names.getPipesAccessorName()}.get('${pipeType}', ${cdRef});
}
${newValue} = ${pipe}.transform(${context}, [${argString}]);
`;

View File

@ -267,13 +267,9 @@ export class DynamicChangeDetector extends AbstractChangeDetector<any> {
_pipeFor(proto: ProtoRecord, context) {
var storedPipe = this._readPipe(proto);
if (isPresent(storedPipe) && storedPipe.supports(context)) {
return storedPipe;
}
if (isPresent(storedPipe)) {
storedPipe.onDestroy();
}
var pipe = this.pipes.get(proto.name, context, this.ref);
if (isPresent(storedPipe)) return storedPipe;
var pipe = this.pipes.get(proto.name, this.ref);
this._writePipe(proto, pipe);
return pipe;
}

View File

@ -1,6 +1,7 @@
import {isBlank, isPresent, isPromise, CONST, BaseException} from 'angular2/src/facade/lang';
import {Observable, Promise, ObservableWrapper} from 'angular2/src/facade/async';
import {Pipe, WrappedValue, PipeFactory} from './pipe';
import {Injectable} from 'angular2/di';
import {Pipe, WrappedValue, InvalidPipeArgumentException} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
@ -52,6 +53,7 @@ var _observableStrategy = new ObservableStrategy();
*
* ```
*/
@Injectable()
export class AsyncPipe implements Pipe {
_latestValue: Object = null;
_latestReturnedValue: Object = null;
@ -62,8 +64,6 @@ export class AsyncPipe implements Pipe {
constructor(public _ref: ChangeDetectorRef) {}
supports(obj: any): boolean { return true; }
onDestroy(): void {
if (isPresent(this._subscription)) {
this._dispose();
@ -98,13 +98,13 @@ export class AsyncPipe implements Pipe {
this._strategy.createSubscription(obj, value => this._updateLatestValue(obj, value));
}
_selectStrategy(obj: Observable | Promise<any>) {
_selectStrategy(obj: Observable | Promise<any>): any {
if (isPromise(obj)) {
return _promiseStrategy;
} else if (ObservableWrapper.isObservable(obj)) {
return _observableStrategy;
} else {
throw new BaseException(`Async pipe does not support object '${obj}'`);
throw new InvalidPipeArgumentException(AsyncPipe, obj);
}
}
@ -122,13 +122,4 @@ export class AsyncPipe implements Pipe {
this._ref.requestCheck();
}
}
}
/**
* Provides a factory for [AsyncPipe].
*/
@CONST()
export class AsyncPipeFactory implements PipeFactory {
supports(obj: any): boolean { return true; }
create(cdRef: ChangeDetectorRef): Pipe { return new AsyncPipe(cdRef); }
}
}

View File

@ -5,12 +5,13 @@ import {
Date,
DateWrapper,
CONST,
isBlank,
FunctionWrapper
} from 'angular2/src/facade/lang';
import {DateFormatter} from 'angular2/src/facade/intl';
import {Injectable} from 'angular2/di';
import {StringMapWrapper, ListWrapper} from 'angular2/src/facade/collection';
import {Pipe, BasePipe, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
import {Pipe, BasePipe, InvalidPipeArgumentException} from './pipe';
// TODO: move to a global configable location along with other i18n components.
var defaultLocale: string = 'en-US';
@ -70,7 +71,8 @@ var defaultLocale: string = 'en-US';
* {{ dateObj | date:'mmss' }} // output is '43:11'
*/
@CONST()
export class DatePipe extends BasePipe implements PipeFactory {
@Injectable()
export class DatePipe extends BasePipe {
static _ALIASES = {
'medium': 'yMMMdjms',
'short': 'yMdjm',
@ -84,6 +86,12 @@ export class DatePipe extends BasePipe implements PipeFactory {
transform(value: any, args: List<any>): string {
if (isBlank(value)) return null;
if (!this.supports(value)) {
throw new InvalidPipeArgumentException(DatePipe, value);
}
var pattern: string = isPresent(args) && args.length > 0 ? args[0] : 'mediumDate';
if (isNumber(value)) {
value = DateWrapper.fromMillis(value);
@ -95,6 +103,4 @@ export class DatePipe extends BasePipe implements PipeFactory {
}
supports(obj: any): boolean { return isDate(obj) || isNumber(obj); }
create(cdRef: ChangeDetectorRef): Pipe { return this; }
}

View File

@ -1,6 +1,6 @@
import {isBlank, isPresent, Json, CONST} from 'angular2/src/facade/lang';
import {Pipe, BasePipe, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
import {Injectable} from 'angular2/di';
import {Pipe, BasePipe} from './pipe';
/**
* Implements json transforms to any object.
@ -26,8 +26,7 @@ import {ChangeDetectorRef} from '../change_detector_ref';
* ```
*/
@CONST()
export class JsonPipe extends BasePipe implements PipeFactory {
@Injectable()
export class JsonPipe extends BasePipe {
transform(value: any, args: List<any> = null): string { return Json.stringify(value); }
create(cdRef: ChangeDetectorRef): Pipe { return this; }
}

View File

@ -8,8 +8,8 @@ import {
} from 'angular2/src/facade/lang';
import {ListWrapper} from 'angular2/src/facade/collection';
import {Math} from 'angular2/src/facade/math';
import {WrappedValue, Pipe, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
import {Injectable} from 'angular2/di';
import {WrappedValue, Pipe, InvalidPipeArgumentException} from './pipe';
/**
* Creates a new List or String containing only a prefix/suffix of the
@ -50,15 +50,18 @@ import {ChangeDetectorRef} from '../change_detector_ref';
* {{ 'abcdefghij' | limitTo: -4 }} // output is 'ghij'
* {{ 'abcdefghij' | limitTo: -100 }} // output is 'abcdefghij'
*/
@Injectable()
export class LimitToPipe implements Pipe {
static supportsObj(obj: any): boolean { return isString(obj) || isArray(obj); }
supports(obj: any): boolean { return LimitToPipe.supportsObj(obj); }
supports(obj: any): boolean { return isString(obj) || isArray(obj); }
transform(value: any, args: List<any> = null): any {
if (isBlank(args) || args.length == 0) {
throw new BaseException('limitTo pipe requires one argument');
}
if (!this.supports(value)) {
throw new InvalidPipeArgumentException(LimitToPipe, value);
}
if (isBlank(value)) return value;
var limit: int = args[0];
var left = 0, right = Math.min(limit, value.length);
if (limit < 0) {
@ -73,10 +76,3 @@ export class LimitToPipe implements Pipe {
onDestroy(): void {}
}
@CONST()
export class LimitToPipeFactory implements PipeFactory {
supports(obj: any): boolean { return LimitToPipe.supportsObj(obj); }
create(cdRef: ChangeDetectorRef): Pipe { return new LimitToPipe(); }
}

View File

@ -1,6 +1,6 @@
import {isString, StringWrapper, CONST} from 'angular2/src/facade/lang';
import {Pipe, BasePipe, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
import {isString, StringWrapper, CONST, isBlank} from 'angular2/src/facade/lang';
import {Injectable} from 'angular2/di';
import {Pipe, BasePipe, InvalidPipeArgumentException} from './pipe';
/**
* Implements lowercase transforms to text.
@ -23,12 +23,13 @@ import {ChangeDetectorRef} from '../change_detector_ref';
* ```
*/
@CONST()
export class LowerCasePipe extends BasePipe implements PipeFactory {
supports(str: any): boolean { return isString(str); }
@Injectable()
export class LowerCasePipe extends BasePipe {
transform(value: string, args: List<any> = null): string {
if (isBlank(value)) return value;
if (!isString(value)) {
throw new InvalidPipeArgumentException(LowerCasePipe, value);
}
return StringWrapper.toLowerCase(value);
}
create(cdRef: ChangeDetectorRef): Pipe { return this; }
}

View File

@ -1,27 +0,0 @@
import {isBlank, CONST} from 'angular2/src/facade/lang';
import {Pipe, BasePipe, WrappedValue, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
@CONST()
export class NullPipeFactory implements PipeFactory {
supports(obj: any): boolean { return NullPipe.supportsObj(obj); }
create(cdRef: ChangeDetectorRef): Pipe { return new NullPipe(); }
}
export class NullPipe extends BasePipe {
called: boolean = false;
static supportsObj(obj: any): boolean { return isBlank(obj); }
supports(obj: any): boolean { return NullPipe.supportsObj(obj); }
transform(value: any, args: List<any> = null): WrappedValue {
if (!this.called) {
this.called = true;
return WrappedValue.wrap(null);
} else {
return null;
}
}
}

View File

@ -10,17 +10,22 @@ import {
FunctionWrapper
} from 'angular2/src/facade/lang';
import {NumberFormatter, NumberFormatStyle} from 'angular2/src/facade/intl';
import {Injectable} from 'angular2/di';
import {ListWrapper} from 'angular2/src/facade/collection';
import {Pipe, BasePipe, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
import {Pipe, BasePipe, InvalidPipeArgumentException} from './pipe';
var defaultLocale: string = 'en-US';
var _re = RegExpWrapper.create('^(\\d+)?\\.((\\d+)(\\-(\\d+))?)?$');
@CONST()
export class NumberPipe extends BasePipe implements PipeFactory {
@Injectable()
export class NumberPipe extends BasePipe {
static _format(value: number, style: NumberFormatStyle, digits: string, currency: string = null,
currencyAsSymbol: boolean = false): string {
if (isBlank(value)) return null;
if (!isNumber(value)) {
throw new InvalidPipeArgumentException(NumberPipe, value);
}
var minInt = 1, minFraction = 0, maxFraction = 3;
if (isPresent(digits)) {
var parts = RegExpWrapper.firstMatch(_re, digits);
@ -45,10 +50,6 @@ export class NumberPipe extends BasePipe implements PipeFactory {
currencyAsSymbol: currencyAsSymbol
});
}
supports(obj: any): boolean { return isNumber(obj); }
create(cdRef: ChangeDetectorRef): Pipe { return this; }
}
/**

View File

@ -1,5 +1,4 @@
import {ABSTRACT, BaseException, CONST} from 'angular2/src/facade/lang';
import {ChangeDetectorRef} from '../change_detector_ref';
import {ABSTRACT, BaseException, CONST, Type} from 'angular2/src/facade/lang';
/**
* Indicates that the result of a {@link Pipe} transformation has changed even though the reference
@ -50,8 +49,6 @@ export interface Pipe {
/**
* Query if a pipe supports a particular object instance.
*/
supports(obj): boolean;
onDestroy(): void;
transform(value: any, args: List<any>): any;
@ -72,19 +69,16 @@ export interface Pipe {
*/
@CONST()
export class BasePipe implements Pipe {
supports(obj: any): boolean { return true; }
onDestroy(): void {}
transform(value: any, args: List<any>): any { return _abstract(); }
}
/**
*
*/
export interface PipeFactory {
supports(obs): boolean;
create(cdRef: ChangeDetectorRef): Pipe;
export class InvalidPipeArgumentException extends BaseException {
constructor(type: Type, value: Object) {
super(`Invalid argument '${value}' for pipe '${type}'`);
}
}
function _abstract() {
throw new BaseException('This method is abstract');
}
}

View File

@ -1,44 +1,42 @@
import {ListWrapper, isListLikeIterable, StringMapWrapper} from 'angular2/src/facade/collection';
import {isBlank, isPresent, BaseException, CONST} from 'angular2/src/facade/lang';
import {Pipe, PipeFactory} from './pipe';
import {Injectable, OptionalMetadata, SkipSelfMetadata} from 'angular2/di';
import {isBlank, isPresent, BaseException, CONST, Type} from 'angular2/src/facade/lang';
import {Pipe} from './pipe';
import {Injectable, OptionalMetadata, SkipSelfMetadata, Binding, Injector, bind} from 'angular2/di';
import {ChangeDetectorRef} from '../change_detector_ref';
import {Binding} from 'angular2/di';
@Injectable()
@CONST()
export class Pipes {
/**
* Map of {@link Pipe} names to {@link PipeFactory} lists used to configure the
* {@link Pipes} registry.
* Map of {@link Pipe} names to {@link Pipe} implementations.
*
* #Example
*
* ```
* var pipesConfig = {
* 'json': [jsonPipeFactory]
* 'json': JsonPipe
* }
* @Component({
* viewBindings: [
* bind(Pipes).toValue(new Pipes(pipesConfig))
* bind(Pipes).toFactory(inj => new Pipes(pipesConfig, in), [Injector])
* ]
* })
* ```
*/
config: StringMap<string, PipeFactory[]>;
config: StringMap<string, Type | Binding>;
constructor(config: StringMap<string, Type | Binding>, public injector: Injector) {
this.config = config;
}
constructor(config: StringMap<string, PipeFactory[]>) { this.config = config; }
get(type: string, obj: any, cdRef?: ChangeDetectorRef, existingPipe?: Pipe): Pipe {
if (isPresent(existingPipe) && existingPipe.supports(obj)) return existingPipe;
if (isPresent(existingPipe)) existingPipe.onDestroy();
var factories = this._getListOfFactories(type, obj);
var factory = this._getMatchingFactory(factories, type, obj);
return factory.create(cdRef);
get(type: string, cdRef: ChangeDetectorRef): Pipe {
var typeOrBinding = this.config[type];
if (isBlank(typeOrBinding)) {
throw new BaseException(`Cannot find pipe '${type}'.`);
}
// this is a temporary workaround and will be removed
return this.injector.resolveAndCreateChild([bind(ChangeDetectorRef).toValue(cdRef)])
.resolveAndInstantiate(typeOrBinding);
}
/**
@ -46,16 +44,7 @@ export class Pipes {
* inherited {@link Pipes} instance with the provided config and return a new
* {@link Pipes} instance.
*
* If the provided config contains a key that is not yet present in the
* inherited {@link Pipes}' config, a new {@link PipeFactory} list will be created
* for that key. Otherwise, the provided config will be merged with the inherited
* {@link Pipes} instance by prepending pipes to their respective keys, without mutating
* the inherited {@link Pipes}.
*
* The following example shows how to extend an existing list of `async` factories
* with a new {@link PipeFactory}, which will only be applied to the injector
* for this component and its children. This step is all that's required to make a new
* pipe available to this component's template.
* The provided config is merged with the {@link Pipes} instance.
*
* # Example
*
@ -63,55 +52,33 @@ export class Pipes {
* @Component({
* viewBindings: [
* Pipes.extend({
* async: [newAsyncPipe]
* 'bithdayFormat': BirthdayFormat
* })
* ]
* })
* ```
*/
static extend(config: StringMap<string, PipeFactory[]>): Binding {
static extend(config: StringMap<string, Type | Binding>): Binding {
return new Binding(Pipes, {
toFactory: (pipes: Pipes) => {
toFactory: (pipes: Pipes, injector: Injector) => {
if (isBlank(pipes)) {
// Typically would occur when calling Pipe.extend inside of dependencies passed to
// bootstrap(), which would override default pipes instead of extending them.
throw new BaseException('Cannot extend Pipes without a parent injector');
}
return Pipes.create(config, pipes);
return Pipes.create(config, injector, pipes);
},
// Dependency technically isn't optional, but we can provide a better error message this way.
deps: [[Pipes, new SkipSelfMetadata(), new OptionalMetadata()]]
deps: [[Pipes, new SkipSelfMetadata(), new OptionalMetadata()], Injector]
});
}
static create(config: StringMap<string, PipeFactory[]>, pipes: Pipes = null): Pipes {
static create(config: StringMap<string, Type | Binding>, injector: Injector,
pipes: Pipes = null): Pipes {
if (isPresent(pipes)) {
StringMapWrapper.forEach(pipes.config, (v: PipeFactory[], k: string) => {
if (StringMapWrapper.contains(config, k)) {
var configFactories: PipeFactory[] = config[k];
config[k] = configFactories.concat(v);
} else {
config[k] = ListWrapper.clone(v);
}
});
return new Pipes(StringMapWrapper.merge(pipes.config, config), injector);
} else {
return new Pipes(config, injector);
}
return new Pipes(config);
}
private _getListOfFactories(type: string, obj: any): PipeFactory[] {
var listOfFactories = this.config[type];
if (isBlank(listOfFactories)) {
throw new BaseException(`Cannot find '${type}' pipe supporting object '${obj}'`);
}
return listOfFactories;
}
private _getMatchingFactory(listOfFactories: PipeFactory[], type: string, obj: any): PipeFactory {
var matchingFactory =
ListWrapper.find(listOfFactories, pipeFactory => pipeFactory.supports(obj));
if (isBlank(matchingFactory)) {
throw new BaseException(`Cannot find '${type}' pipe supporting object '${obj}'`);
}
return matchingFactory;
}
}

View File

@ -1,6 +1,6 @@
import {isString, StringWrapper, CONST} from 'angular2/src/facade/lang';
import {Pipe, BasePipe, PipeFactory} from './pipe';
import {ChangeDetectorRef} from '../change_detector_ref';
import {isString, StringWrapper, CONST, isBlank} from 'angular2/src/facade/lang';
import {Injectable} from 'angular2/di';
import {Pipe, BasePipe, InvalidPipeArgumentException} from './pipe';
/**
* Implements uppercase transforms to text.
@ -23,12 +23,13 @@ import {ChangeDetectorRef} from '../change_detector_ref';
* ```
*/
@CONST()
export class UpperCasePipe extends BasePipe implements PipeFactory {
supports(str: any): boolean { return isString(str); }
@Injectable()
export class UpperCasePipe extends BasePipe {
transform(value: string, args: List<any> = null): string {
if (isBlank(value)) return value;
if (!isString(value)) {
throw new InvalidPipeArgumentException(UpperCasePipe, value);
}
return StringWrapper.toUpperCase(value);
}
create(cdRef: ChangeDetectorRef): Pipe { return this; }
}

View File

@ -137,7 +137,7 @@ function _injectorBindings(appComponentType): List<Type | Binding | List<any>> {
Compiler,
CompilerCache,
ViewResolver,
bind(Pipes).toValue(defaultPipes),
defaultPipes,
bind(IterableDiffers).toValue(defaultIterableDiffers),
bind(KeyValueDiffers).toValue(defaultKeyValueDiffers),
bind(ChangeDetection).toClass(bestChangeDetection),

View File

@ -558,7 +558,7 @@ export class Injector {
* @param `binding`: either a type or a binding.
* @returns an object created using binding.
*/
resolveAndInstantiate(binding: Type | Binding) {
resolveAndInstantiate(binding: Type | Binding): any {
return this.instantiateResolved(Injector.resolve([binding])[0]);
}

View File

@ -19,11 +19,6 @@ class SpyPipe extends SpyObject implements Pipe {
noSuchMethod(m) => super.noSuchMethod(m);
}
@proxy()
class SpyPipeFactory extends SpyObject implements PipeFactory {
noSuchMethod(m) => super.noSuchMethod(m);
}
@proxy()
class SpyDependencyProvider extends SpyObject implements DependencyProvider {
noSuchMethod(m) => super.noSuchMethod(m);
@ -39,3 +34,8 @@ class SpyIterableDifferFactory extends SpyObject
implements IterableDifferFactory {
noSuchMethod(m) => super.noSuchMethod(m);
}
@proxy
class SpyInjector extends SpyObject implements Injector {
noSuchMethod(m) => super.noSuchMethod(m);
}

View File

@ -22,12 +22,12 @@ export class SpyPipe extends SpyObject {
constructor() { super(BasePipe); }
}
export class SpyPipeFactory extends SpyObject {}
export class SpyDependencyProvider extends SpyObject {}
export class SpyIterableDifferFactory extends SpyObject {}
export class SpyInjector extends SpyObject {}
export class SpyChangeDetectorRef extends SpyObject {
constructor() { super(ChangeDetectorRef); }
}

View File

@ -122,7 +122,7 @@ function _getAppBindings() {
Compiler,
CompilerCache,
bind(ViewResolver).toClass(MockViewResolver),
bind(Pipes).toValue(defaultPipes),
defaultPipes,
bind(IterableDiffers).toValue(defaultIterableDiffers),
bind(KeyValueDiffers).toValue(defaultKeyValueDiffers),
bind(ChangeDetection).toClass(DynamicChangeDetection),

View File

@ -274,10 +274,7 @@ class _CodegenState {
var read = '''
if ($_IDENTICAL_CHECK_FN($pipe, $_UTIL.uninitialized)) {
$pipe = ${_names.getPipesAccessorName()}.get('$pipeType', $context, $cdRef);
} else if (!$pipe.supports($context)) {
$pipe.onDestroy();
$pipe = ${_names.getPipesAccessorName()}.get('$pipeType', $context, $cdRef);
$pipe = ${_names.getPipesAccessorName()}.get('$pipeType', $cdRef);
}
$newValue = $pipe.transform($context, [$argString]);
''';

View File

@ -118,7 +118,7 @@ function _injectorBindings(appComponentType, bus: WorkerMessageBus,
Compiler,
CompilerCache,
ViewResolver,
bind(Pipes).toValue(defaultPipes),
defaultPipes,
bind(ChangeDetection).toClass(bestChangeDetection),
DirectiveResolver,
Parser,