refactor(pipes): removed pipes from properties
BREAKING CHANGE: This PR remove an ability to use pipes in the properties config. Instead, inject the pipe registry.
This commit is contained in:
@ -145,7 +145,7 @@ export class ChangeDetectorJITGenerator {
|
||||
_getNonNullPipeNames(): List<string> {
|
||||
var pipes = [];
|
||||
this.records.forEach((r) => {
|
||||
if (r.mode === RecordType.PIPE || r.mode === RecordType.BINDING_PIPE) {
|
||||
if (r.isPipeRecord()) {
|
||||
pipes.push(this._pipeNames[r.selfIndex]);
|
||||
}
|
||||
});
|
||||
@ -245,7 +245,7 @@ export class ChangeDetectorJITGenerator {
|
||||
var change = this._changeNames[r.selfIndex];
|
||||
|
||||
var pipe = this._pipeNames[r.selfIndex];
|
||||
var cdRef = r.mode === RecordType.BINDING_PIPE ? "this.ref" : "null";
|
||||
var cdRef = "this.ref";
|
||||
|
||||
var protoIndex = r.selfIndex - 1;
|
||||
var pipeType = r.name;
|
||||
|
@ -269,14 +269,7 @@ export class DynamicChangeDetector extends AbstractChangeDetector {
|
||||
if (isPresent(storedPipe)) {
|
||||
storedPipe.onDestroy();
|
||||
}
|
||||
|
||||
// Currently, only pipes that used in bindings in the template get
|
||||
// the changeDetectorRef of the encompassing component.
|
||||
//
|
||||
// In the future, pipes declared in the bind configuration should
|
||||
// be able to access the changeDetectorRef of that component.
|
||||
var cdr = proto.mode === RecordType.BINDING_PIPE ? this.ref : null;
|
||||
var pipe = this.pipeRegistry.get(proto.name, context, cdr);
|
||||
var pipe = this.pipeRegistry.get(proto.name, context, this.ref);
|
||||
this._writePipe(proto, pipe);
|
||||
return pipe;
|
||||
}
|
||||
|
@ -141,11 +141,8 @@ export class KeyedAccess extends AST {
|
||||
visit(visitor: AstVisitor) { return visitor.visitKeyedAccess(this); }
|
||||
}
|
||||
|
||||
export class Pipe extends AST {
|
||||
constructor(public exp: AST, public name: string, public args: List<any>,
|
||||
public inBinding: boolean) {
|
||||
super();
|
||||
}
|
||||
export class BindingPipe extends AST {
|
||||
constructor(public exp: AST, public name: string, public args: List<any>) { super(); }
|
||||
|
||||
visit(visitor: AstVisitor) { return visitor.visitPipe(this); }
|
||||
}
|
||||
@ -336,7 +333,7 @@ export interface AstVisitor {
|
||||
visitChain(ast: Chain): any;
|
||||
visitConditional(ast: Conditional): any;
|
||||
visitIf(ast: If): any;
|
||||
visitPipe(ast: Pipe): any;
|
||||
visitPipe(ast: BindingPipe): any;
|
||||
visitFunctionCall(ast: FunctionCall): any;
|
||||
visitImplicitReceiver(ast: ImplicitReceiver): any;
|
||||
visitInterpolation(ast: Interpolation): any;
|
||||
@ -394,8 +391,8 @@ export class AstTransformer implements AstVisitor {
|
||||
ast.falseExp.visit(this));
|
||||
}
|
||||
|
||||
visitPipe(ast: Pipe) {
|
||||
return new Pipe(ast.exp.visit(this), ast.name, this.visitAll(ast.args), ast.inBinding);
|
||||
visitPipe(ast: BindingPipe) {
|
||||
return new BindingPipe(ast.exp.visit(this), ast.name, this.visitAll(ast.args));
|
||||
}
|
||||
|
||||
visitKeyedAccess(ast: KeyedAccess) {
|
||||
|
@ -34,7 +34,7 @@ import {
|
||||
PrefixNot,
|
||||
Conditional,
|
||||
If,
|
||||
Pipe,
|
||||
BindingPipe,
|
||||
Assignment,
|
||||
Chain,
|
||||
KeyedAccess,
|
||||
@ -73,15 +73,6 @@ export class Parser {
|
||||
return new ASTWithSource(ast, input, location);
|
||||
}
|
||||
|
||||
addPipes(bindingAst: ASTWithSource, pipes: List<string>): ASTWithSource {
|
||||
if (ListWrapper.isEmpty(pipes)) return bindingAst;
|
||||
|
||||
var res: AST = ListWrapper.reduce(
|
||||
pipes, (result, currentPipeName) => new Pipe(result, currentPipeName, [], false),
|
||||
bindingAst.ast);
|
||||
return new ASTWithSource(res, bindingAst.source, bindingAst.location);
|
||||
}
|
||||
|
||||
parseTemplateBindings(input: string, location: any): List<TemplateBinding> {
|
||||
var tokens = this._lexer.tokenize(input);
|
||||
return new _ParseAST(input, location, tokens, this._reflector, false).parseTemplateBindings();
|
||||
@ -224,7 +215,7 @@ class _ParseAST {
|
||||
while (this.optionalCharacter($COLON)) {
|
||||
args.push(this.parsePipe());
|
||||
}
|
||||
result = new Pipe(result, name, args, true);
|
||||
result = new BindingPipe(result, name, args);
|
||||
} while (this.optionalOperator("|"));
|
||||
}
|
||||
|
||||
|
@ -15,12 +15,10 @@ import {
|
||||
isArray
|
||||
} from 'angular2/src/facade/lang';
|
||||
|
||||
import {WrappedValue, Pipe, PipeFactory} from './pipe';
|
||||
import {WrappedValue, Pipe, BasePipe, PipeFactory} from './pipe';
|
||||
|
||||
@CONST()
|
||||
export class IterableChangesFactory extends PipeFactory {
|
||||
constructor() { super(); }
|
||||
|
||||
export class IterableChangesFactory implements PipeFactory {
|
||||
supports(obj): boolean { return IterableChanges.supportsObj(obj); }
|
||||
|
||||
create(cdRef): Pipe { return new IterableChanges(); }
|
||||
@ -29,7 +27,7 @@ export class IterableChangesFactory extends PipeFactory {
|
||||
/**
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
export class IterableChanges extends Pipe {
|
||||
export class IterableChanges extends BasePipe {
|
||||
private _collection = null;
|
||||
private _length: int = null;
|
||||
// Keeps track of the used records at any point in time (during & across `_check()` calls)
|
||||
@ -95,7 +93,7 @@ export class IterableChanges extends Pipe {
|
||||
if (this.check(collection)) {
|
||||
return WrappedValue.wrap(this);
|
||||
} else {
|
||||
return this;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
import {isBlank, isPresent, Json} from 'angular2/src/facade/lang';
|
||||
import {Pipe, PipeFactory} from './pipe';
|
||||
import {Pipe, BasePipe, PipeFactory} from './pipe';
|
||||
|
||||
/**
|
||||
* Implements json transforms to any object.
|
||||
@ -26,9 +26,7 @@ import {Pipe, PipeFactory} from './pipe';
|
||||
*
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
export class JsonPipe extends Pipe {
|
||||
supports(obj): boolean { return true; }
|
||||
|
||||
export class JsonPipe extends BasePipe {
|
||||
transform(value): string { return Json.stringify(value); }
|
||||
|
||||
create(cdRef): Pipe { return this }
|
||||
|
@ -1,15 +1,13 @@
|
||||
import {ListWrapper, MapWrapper, StringMapWrapper} from 'angular2/src/facade/collection';
|
||||
import {stringify, looseIdentical, isJsObject, CONST} from 'angular2/src/facade/lang';
|
||||
|
||||
import {WrappedValue, Pipe, PipeFactory} from './pipe';
|
||||
import {WrappedValue, BasePipe, Pipe, PipeFactory} from './pipe';
|
||||
|
||||
/**
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
@CONST()
|
||||
export class KeyValueChangesFactory extends PipeFactory {
|
||||
constructor() { super(); }
|
||||
|
||||
export class KeyValueChangesFactory implements PipeFactory {
|
||||
supports(obj): boolean { return KeyValueChanges.supportsObj(obj); }
|
||||
|
||||
create(cdRef): Pipe { return new KeyValueChanges(); }
|
||||
@ -18,7 +16,7 @@ export class KeyValueChangesFactory extends PipeFactory {
|
||||
/**
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
export class KeyValueChanges extends Pipe {
|
||||
export class KeyValueChanges extends BasePipe {
|
||||
private _records: Map<any, any> = new Map();
|
||||
private _mapHead: KVChangeRecord = null;
|
||||
private _previousMapHead: KVChangeRecord = null;
|
||||
@ -37,7 +35,7 @@ export class KeyValueChanges extends Pipe {
|
||||
if (this.check(map)) {
|
||||
return WrappedValue.wrap(this);
|
||||
} else {
|
||||
return this;
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -23,7 +23,7 @@ import {Pipe} from './pipe';
|
||||
*
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
export class LowerCasePipe extends Pipe {
|
||||
export class LowerCasePipe implements Pipe {
|
||||
_latestValue: string = null;
|
||||
|
||||
supports(str): boolean { return isString(str); }
|
||||
|
@ -1,13 +1,11 @@
|
||||
import {isBlank, CONST} from 'angular2/src/facade/lang';
|
||||
import {Pipe, WrappedValue, PipeFactory} from './pipe';
|
||||
import {Pipe, BasePipe, WrappedValue, PipeFactory} from './pipe';
|
||||
|
||||
/**
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
@CONST()
|
||||
export class NullPipeFactory extends PipeFactory {
|
||||
constructor() { super(); }
|
||||
|
||||
export class NullPipeFactory implements PipeFactory {
|
||||
supports(obj): boolean { return NullPipe.supportsObj(obj); }
|
||||
|
||||
create(cdRef): Pipe { return new NullPipe(); }
|
||||
@ -16,7 +14,7 @@ export class NullPipeFactory extends PipeFactory {
|
||||
/**
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
export class NullPipe extends Pipe {
|
||||
export class NullPipe extends BasePipe {
|
||||
called: boolean = false;
|
||||
|
||||
static supportsObj(obj): boolean { return isBlank(obj); }
|
||||
|
@ -29,14 +29,14 @@ import {ChangeDetectorRef} from '../change_detector_ref';
|
||||
*
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
export class ObservablePipe extends Pipe {
|
||||
export class ObservablePipe implements Pipe {
|
||||
_latestValue: Object = null;
|
||||
_latestReturnedValue: Object = null;
|
||||
|
||||
_subscription: Object = null;
|
||||
_observable: Observable = null;
|
||||
|
||||
constructor(public _ref: ChangeDetectorRef) { super(); }
|
||||
constructor(public _ref: ChangeDetectorRef) {}
|
||||
|
||||
supports(obs): boolean { return ObservableWrapper.isObservable(obs); }
|
||||
|
||||
@ -91,9 +91,7 @@ export class ObservablePipe extends Pipe {
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
@CONST()
|
||||
export class ObservablePipeFactory extends PipeFactory {
|
||||
constructor() { super(); }
|
||||
|
||||
export class ObservablePipeFactory implements PipeFactory {
|
||||
supports(obs): boolean { return ObservableWrapper.isObservable(obs); }
|
||||
|
||||
create(cdRef): Pipe { return new ObservablePipe(cdRef); }
|
||||
|
@ -36,11 +36,13 @@ var _wrappedIndex = 0;
|
||||
* #Example
|
||||
*
|
||||
* ```
|
||||
* class DoublePipe extends Pipe {
|
||||
* class DoublePipe implements Pipe {
|
||||
* supports(obj) {
|
||||
* return true;
|
||||
* }
|
||||
*
|
||||
* onDestroy() {}
|
||||
*
|
||||
* transform(value) {
|
||||
* return `${value}${value}`;
|
||||
* }
|
||||
@ -49,24 +51,34 @@ var _wrappedIndex = 0;
|
||||
*
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
export class Pipe {
|
||||
supports(obj): boolean { return false; }
|
||||
onDestroy() {}
|
||||
transform(value: any): any { return null; }
|
||||
export interface Pipe {
|
||||
supports(obj): boolean;
|
||||
onDestroy(): void;
|
||||
transform(value: any): any;
|
||||
}
|
||||
|
||||
// TODO: vsavkin: make it an interface
|
||||
@CONST()
|
||||
export class PipeFactory {
|
||||
supports(obs): boolean {
|
||||
_abstract();
|
||||
return false;
|
||||
}
|
||||
/**
|
||||
* Provides default implementation of supports and onDestroy.
|
||||
*
|
||||
* #Example
|
||||
*
|
||||
* ```
|
||||
* class DoublePipe extends BasePipe {*
|
||||
* transform(value) {
|
||||
* return `${value}${value}`;
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
export class BasePipe implements Pipe {
|
||||
supports(obj): boolean { return true; }
|
||||
onDestroy(): void {}
|
||||
transform(value: any): any { return _abstract(); }
|
||||
}
|
||||
|
||||
create(cdRef): Pipe {
|
||||
_abstract();
|
||||
return null;
|
||||
}
|
||||
export interface PipeFactory {
|
||||
supports(obs): boolean;
|
||||
create(cdRef): Pipe;
|
||||
}
|
||||
|
||||
function _abstract() {
|
||||
|
@ -1,6 +1,6 @@
|
||||
import {List, ListWrapper} from 'angular2/src/facade/collection';
|
||||
import {isBlank, isPresent, BaseException, CONST} from 'angular2/src/facade/lang';
|
||||
import {Pipe} from './pipe';
|
||||
import {Pipe, PipeFactory} from './pipe';
|
||||
import {Injectable} from 'angular2/src/di/decorators';
|
||||
import {ChangeDetectorRef} from '../change_detector_ref';
|
||||
|
||||
@ -8,18 +8,31 @@ import {ChangeDetectorRef} from '../change_detector_ref';
|
||||
export class PipeRegistry {
|
||||
constructor(public config) {}
|
||||
|
||||
get(type: string, obj, cdRef: ChangeDetectorRef): Pipe {
|
||||
var listOfConfigs = this.config[type];
|
||||
if (isBlank(listOfConfigs)) {
|
||||
get(type: string, obj, 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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
var matchingConfig = ListWrapper.find(listOfConfigs, (pipeConfig) => pipeConfig.supports(obj));
|
||||
|
||||
if (isBlank(matchingConfig)) {
|
||||
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 matchingConfig.create(cdRef);
|
||||
return matchingFactory;
|
||||
}
|
||||
}
|
||||
|
@ -28,12 +28,12 @@ import {ChangeDetectorRef} from '../change_detector_ref';
|
||||
*
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
export class PromisePipe extends Pipe {
|
||||
export class PromisePipe implements Pipe {
|
||||
_latestValue: Object = null;
|
||||
_latestReturnedValue: Object = null;
|
||||
_sourcePromise: Promise<any>;
|
||||
|
||||
constructor(public _ref: ChangeDetectorRef) { super(); }
|
||||
constructor(public _ref: ChangeDetectorRef) {}
|
||||
|
||||
supports(promise): boolean { return isPromise(promise); }
|
||||
|
||||
|
@ -23,7 +23,7 @@ import {Pipe} from './pipe';
|
||||
*
|
||||
* @exportedAs angular2/pipes
|
||||
*/
|
||||
export class UpperCasePipe extends Pipe {
|
||||
export class UpperCasePipe implements Pipe {
|
||||
_latestValue: string = null;
|
||||
|
||||
supports(str): boolean { return isString(str); }
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
Chain,
|
||||
Conditional,
|
||||
If,
|
||||
Pipe,
|
||||
BindingPipe,
|
||||
FunctionCall,
|
||||
ImplicitReceiver,
|
||||
Interpolation,
|
||||
@ -179,10 +179,9 @@ class _ConvertAstIntoProtoRecords implements AstVisitor {
|
||||
null, 0);
|
||||
}
|
||||
|
||||
visitPipe(ast: Pipe) {
|
||||
visitPipe(ast: BindingPipe) {
|
||||
var value = ast.exp.visit(this);
|
||||
var type = ast.inBinding ? RecordType.BINDING_PIPE : RecordType.PIPE;
|
||||
return this._addRecord(type, ast.name, ast.name, [], null, value);
|
||||
return this._addRecord(RecordType.PIPE, ast.name, ast.name, [], null, value);
|
||||
}
|
||||
|
||||
visitKeyedAccess(ast: KeyedAccess) {
|
||||
|
@ -12,7 +12,6 @@ export enum RecordType {
|
||||
INVOKE_CLOSURE,
|
||||
KEYED_ACCESS,
|
||||
PIPE,
|
||||
BINDING_PIPE,
|
||||
INTERPOLATE,
|
||||
SAFE_PROPERTY,
|
||||
SAFE_INVOKE_METHOD,
|
||||
@ -30,9 +29,7 @@ export class ProtoRecord {
|
||||
return this.mode === RecordType.INTERPOLATE || this.mode === RecordType.PRIMITIVE_OP;
|
||||
}
|
||||
|
||||
isPipeRecord(): boolean {
|
||||
return this.mode === RecordType.PIPE || this.mode === RecordType.BINDING_PIPE;
|
||||
}
|
||||
isPipeRecord(): boolean { return this.mode === RecordType.PIPE; }
|
||||
|
||||
isLifeCycleRecord(): boolean { return this.mode === RecordType.DIRECTIVE_LIFECYCLE; }
|
||||
}
|
||||
|
Reference in New Issue
Block a user