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:
@ -768,7 +768,7 @@ export function main() {
|
||||
});
|
||||
|
||||
it('should destroy all active pipes during dehyration', () => {
|
||||
var pipe = new OncePipe();
|
||||
var pipe = new PipeWithOnDestroy();
|
||||
var registry = new FakePipes('pipe', () => pipe);
|
||||
var cd = _createChangeDetector('name | pipe', new Person('bob'), registry).changeDetector;
|
||||
|
||||
@ -810,36 +810,6 @@ export function main() {
|
||||
expect(val.dispatcher.log).toEqual(['propName=Megatron state:1']);
|
||||
});
|
||||
|
||||
it('should lookup pipes in the registry when the context is not supported', () => {
|
||||
var registry = new FakePipes('pipe', () => new OncePipe());
|
||||
var ctx = new Person('Megatron');
|
||||
|
||||
var cd = _createChangeDetector('name | pipe', ctx, registry).changeDetector;
|
||||
|
||||
cd.detectChanges();
|
||||
|
||||
expect(registry.numberOfLookups).toEqual(1);
|
||||
|
||||
ctx.name = 'Optimus Prime';
|
||||
cd.detectChanges();
|
||||
|
||||
expect(registry.numberOfLookups).toEqual(2);
|
||||
});
|
||||
|
||||
it('should invoke onDestroy on a pipe before switching to another one', () => {
|
||||
var pipe = new OncePipe();
|
||||
var registry = new FakePipes('pipe', () => pipe);
|
||||
var ctx = new Person('Megatron');
|
||||
|
||||
var cd = _createChangeDetector('name | pipe', ctx, registry).changeDetector;
|
||||
|
||||
cd.detectChanges();
|
||||
ctx.name = 'Optimus Prime';
|
||||
cd.detectChanges();
|
||||
|
||||
expect(pipe.destroyCalled).toEqual(true);
|
||||
});
|
||||
|
||||
it('should inject the ChangeDetectorRef ' +
|
||||
'of the encompassing component into a pipe',
|
||||
() => {
|
||||
@ -886,41 +856,24 @@ export function main() {
|
||||
|
||||
class CountingPipe implements Pipe {
|
||||
state: number = 0;
|
||||
|
||||
onDestroy() {}
|
||||
|
||||
supports(newValue) { return true; }
|
||||
|
||||
transform(value, args = null) { return `${value} state:${this.state ++}`; }
|
||||
}
|
||||
|
||||
class OncePipe implements Pipe {
|
||||
called: boolean = false;
|
||||
class PipeWithOnDestroy implements Pipe {
|
||||
destroyCalled: boolean = false;
|
||||
|
||||
supports(newValue) { return !this.called; }
|
||||
|
||||
onDestroy() { this.destroyCalled = true; }
|
||||
|
||||
transform(value, args = null) {
|
||||
this.called = true;
|
||||
return value;
|
||||
}
|
||||
transform(value, args = null) { return null; }
|
||||
}
|
||||
|
||||
class IdentityPipe implements Pipe {
|
||||
supports(obj): boolean { return true; }
|
||||
|
||||
onDestroy() {}
|
||||
|
||||
transform(value, args = null) { return value; }
|
||||
}
|
||||
|
||||
class WrappedPipe implements Pipe {
|
||||
supports(obj): boolean { return true; }
|
||||
|
||||
onDestroy() {}
|
||||
|
||||
transform(value, args = null) { return WrappedValue.wrap(value); }
|
||||
}
|
||||
|
||||
@ -931,24 +884,16 @@ class MultiArgPipe implements Pipe {
|
||||
var arg3 = args.length > 2 ? args[2] : 'default';
|
||||
return `${value} ${arg1} ${arg2} ${arg3}`;
|
||||
}
|
||||
supports(obj): boolean { return true; }
|
||||
onDestroy(): void {}
|
||||
}
|
||||
|
||||
class FakePipes extends Pipes {
|
||||
numberOfLookups: number;
|
||||
pipeType: string;
|
||||
factory: Function;
|
||||
numberOfLookups = 0;
|
||||
cdRef: any;
|
||||
|
||||
constructor(pipeType, factory) {
|
||||
super({});
|
||||
this.pipeType = pipeType;
|
||||
this.factory = factory;
|
||||
this.numberOfLookups = 0;
|
||||
}
|
||||
constructor(public pipeType: string, public factory: Function) { super(null, null); }
|
||||
|
||||
get(type: string, obj, cdRef?, existingPipe?) {
|
||||
get(type: string, cdRef?) {
|
||||
if (type != this.pipeType) return null;
|
||||
this.numberOfLookups++;
|
||||
this.cdRef = cdRef;
|
||||
|
@ -20,10 +20,8 @@ import {JsonPipe} from 'angular2/src/change_detection/pipes/json_pipe';
|
||||
export function main() {
|
||||
describe("JsonPipe", () => {
|
||||
var regNewLine = '\n';
|
||||
var canHasUndefined; // because Dart doesn't like undefined;
|
||||
var inceptionObj;
|
||||
var inceptionObjString;
|
||||
var catString;
|
||||
var pipe;
|
||||
var collection: number[];
|
||||
|
||||
@ -35,27 +33,10 @@ export function main() {
|
||||
" \"dream\": \"Limbo\"\n" + " }\n" + " }\n" + "}";
|
||||
|
||||
|
||||
catString = 'Inception Cat';
|
||||
pipe = new JsonPipe();
|
||||
collection = [];
|
||||
});
|
||||
|
||||
describe("supports", () => {
|
||||
it("should support objects", () => { expect(pipe.supports(inceptionObj)).toBe(true); });
|
||||
|
||||
it("should support strings", () => { expect(pipe.supports(catString)).toBe(true); });
|
||||
|
||||
it("should support null", () => { expect(pipe.supports(null)).toBe(true); });
|
||||
|
||||
it("should support NaN", () => { expect(pipe.supports(NumberWrapper.NaN)).toBe(true); });
|
||||
|
||||
if (!IS_DARTIUM) {
|
||||
it("should support undefined",
|
||||
() => { expect(pipe.supports(canHasUndefined)).toBe(true); });
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
it("should return JSON-formatted string",
|
||||
() => { expect(pipe.transform(inceptionObj)).toEqual(inceptionObjString); });
|
||||
|
@ -4,29 +4,17 @@ import {LowerCasePipe} from 'angular2/src/change_detection/pipes/lowercase_pipe'
|
||||
|
||||
export function main() {
|
||||
describe("LowerCasePipe", () => {
|
||||
var str;
|
||||
var upper;
|
||||
var lower;
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => {
|
||||
str = 'something';
|
||||
lower = 'something';
|
||||
upper = 'SOMETHING';
|
||||
pipe = new LowerCasePipe();
|
||||
});
|
||||
|
||||
describe("supports", () => {
|
||||
it("should support strings", () => { expect(pipe.supports(str)).toBe(true); });
|
||||
|
||||
it("should not support other objects", () => {
|
||||
expect(pipe.supports(new Object())).toBe(false);
|
||||
expect(pipe.supports(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
|
||||
it("should return lowercase", () => {
|
||||
var val = pipe.transform(upper);
|
||||
expect(val).toEqual(lower);
|
||||
@ -39,6 +27,8 @@ export function main() {
|
||||
expect(val2).toEqual('wat');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
|
||||
});
|
||||
|
||||
});
|
||||
|
@ -12,18 +12,8 @@ export function main() {
|
||||
|
||||
beforeEach(() => { pipe = new DecimalPipe(); });
|
||||
|
||||
describe("supports", () => {
|
||||
it("should support numbers", () => { expect(pipe.supports(123.0)).toBe(true); });
|
||||
|
||||
it("should not support other objects", () => {
|
||||
expect(pipe.supports(new Object())).toBe(false);
|
||||
expect(pipe.supports('str')).toBe(false);
|
||||
expect(pipe.supports(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
it('should return correct value', () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(pipe.transform(12345, [])).toEqual('12,345');
|
||||
expect(pipe.transform(123, ['.2'])).toEqual('123.00');
|
||||
expect(pipe.transform(1, ['3.'])).toEqual('001');
|
||||
@ -31,6 +21,9 @@ export function main() {
|
||||
expect(pipe.transform(1.123456, ['3.4-5'])).toEqual('001.12346');
|
||||
expect(pipe.transform(1.1234, [])).toEqual('1.123');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object(), [])).toThrowError(); });
|
||||
});
|
||||
});
|
||||
|
||||
@ -39,21 +32,14 @@ export function main() {
|
||||
|
||||
beforeEach(() => { pipe = new PercentPipe(); });
|
||||
|
||||
describe("supports", () => {
|
||||
it("should support numbers", () => { expect(pipe.supports(123.0)).toBe(true); });
|
||||
|
||||
it("should not support other objects", () => {
|
||||
expect(pipe.supports(new Object())).toBe(false);
|
||||
expect(pipe.supports('str')).toBe(false);
|
||||
expect(pipe.supports(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
it('should return correct value', () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(pipe.transform(1.23, [])).toEqual('123%');
|
||||
expect(pipe.transform(1.2, ['.2'])).toEqual('120.00%');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object(), [])).toThrowError(); });
|
||||
});
|
||||
});
|
||||
|
||||
@ -62,21 +48,14 @@ export function main() {
|
||||
|
||||
beforeEach(() => { pipe = new CurrencyPipe(); });
|
||||
|
||||
describe("supports", () => {
|
||||
it("should support numbers", () => { expect(pipe.supports(123.0)).toBe(true); });
|
||||
|
||||
it("should not support other objects", () => {
|
||||
expect(pipe.supports(new Object())).toBe(false);
|
||||
expect(pipe.supports('str')).toBe(false);
|
||||
expect(pipe.supports(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
it('should return correct value', () => {
|
||||
it('should return correct value for numbers', () => {
|
||||
expect(pipe.transform(123, [])).toEqual('USD123');
|
||||
expect(pipe.transform(12, ['EUR', false, '.2'])).toEqual('EUR12.00');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object(), [])).toThrowError(); });
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -1,158 +1,88 @@
|
||||
import {
|
||||
ddescribe,
|
||||
xdescribe,
|
||||
describe,
|
||||
it,
|
||||
iit,
|
||||
xit,
|
||||
expect,
|
||||
beforeEach,
|
||||
afterEach,
|
||||
SpyPipe,
|
||||
SpyPipeFactory
|
||||
afterEach
|
||||
} from 'angular2/test_lib';
|
||||
|
||||
import {Injector, bind} from 'angular2/di';
|
||||
import {Pipes} from 'angular2/src/change_detection/pipes/pipes';
|
||||
import {PipeFactory} from 'angular2/src/change_detection/pipes/pipe';
|
||||
import {Pipe} from 'angular2/src/change_detection/pipes/pipe';
|
||||
|
||||
class APipe implements Pipe {
|
||||
transform(a, b) {}
|
||||
onDestroy() {}
|
||||
}
|
||||
|
||||
class AnotherPipe implements Pipe {
|
||||
transform(a, b) {}
|
||||
onDestroy() {}
|
||||
}
|
||||
|
||||
export function main() {
|
||||
describe("pipe registry", () => {
|
||||
var firstPipe;
|
||||
var secondPipe;
|
||||
var injector;
|
||||
|
||||
var firstPipeFactory;
|
||||
var secondPipeFactory;
|
||||
beforeEach(() => { injector = Injector.resolveAndCreate([]); });
|
||||
|
||||
beforeEach(() => {
|
||||
firstPipe = <any>new SpyPipe();
|
||||
secondPipe = <any>new SpyPipe();
|
||||
|
||||
firstPipeFactory = <any>new SpyPipeFactory();
|
||||
secondPipeFactory = <any>new SpyPipeFactory();
|
||||
it("should instantiate a pipe", () => {
|
||||
var r = new Pipes({"type": APipe}, injector);
|
||||
expect(r.get("type", null)).toBeAnInstanceOf(APipe);
|
||||
});
|
||||
|
||||
it("should return an existing pipe if it can support the passed in object", () => {
|
||||
var r = new Pipes({"type": []});
|
||||
|
||||
firstPipe.spy("supports").andReturn(true);
|
||||
|
||||
expect(r.get("type", "some object", null, firstPipe)).toEqual(firstPipe);
|
||||
});
|
||||
|
||||
it("should call onDestroy on the provided pipe if it cannot support the provided object",
|
||||
() => {
|
||||
firstPipe.spy("supports").andReturn(false);
|
||||
firstPipeFactory.spy("supports").andReturn(true);
|
||||
firstPipeFactory.spy("create").andReturn(secondPipe);
|
||||
|
||||
var r = new Pipes({"type": [firstPipeFactory]});
|
||||
|
||||
expect(r.get("type", "some object", null, firstPipe)).toEqual(secondPipe);
|
||||
expect(firstPipe.spy("onDestroy")).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("should return the first pipe supporting the data type", () => {
|
||||
firstPipeFactory.spy("supports").andReturn(false);
|
||||
firstPipeFactory.spy("create").andReturn(firstPipe);
|
||||
|
||||
secondPipeFactory.spy("supports").andReturn(true);
|
||||
secondPipeFactory.spy("create").andReturn(secondPipe);
|
||||
|
||||
var r = new Pipes({"type": [firstPipeFactory, secondPipeFactory]});
|
||||
|
||||
expect(r.get("type", "some object")).toBe(secondPipe);
|
||||
it("should instantiate a new pipe every time", () => {
|
||||
var r = new Pipes({"type": APipe}, injector);
|
||||
var p1 = r.get("type", null);
|
||||
var p2 = r.get("type", null);
|
||||
expect(p1).not.toBe(p2);
|
||||
});
|
||||
|
||||
it("should throw when no matching type", () => {
|
||||
var r = new Pipes({});
|
||||
expect(() => r.get("unknown", "some object"))
|
||||
.toThrowError(`Cannot find 'unknown' pipe supporting object 'some object'`);
|
||||
});
|
||||
|
||||
it("should throw when no matching pipe", () => {
|
||||
var r = new Pipes({"type": []});
|
||||
|
||||
expect(() => r.get("type", "some object"))
|
||||
.toThrowError(`Cannot find 'type' pipe supporting object 'some object'`);
|
||||
var r = new Pipes({}, null);
|
||||
expect(() => r.get("unknown", null)).toThrowError(`Cannot find pipe 'unknown'.`);
|
||||
});
|
||||
|
||||
describe('.create()', () => {
|
||||
it("should create a new Pipes object", () => {
|
||||
firstPipeFactory.spy("supports").andReturn(true);
|
||||
firstPipeFactory.spy("create").andReturn(firstPipe);
|
||||
|
||||
var pipes = Pipes.create({'async': [firstPipeFactory]});
|
||||
expect(pipes.get("async", "first")).toBe(firstPipe);
|
||||
var pipes = Pipes.create({'pipe': APipe}, null);
|
||||
expect(pipes.config).toEqual({'pipe': APipe});
|
||||
});
|
||||
|
||||
it("should prepend passed it config in existing registry", () => {
|
||||
firstPipeFactory.spy("supports").andReturn(true);
|
||||
secondPipeFactory.spy("supports").andReturn(true);
|
||||
secondPipeFactory.spy("create").andReturn(secondPipe);
|
||||
it("should merge pipes config", () => {
|
||||
var pipes1 = Pipes.create({'pipe': APipe, 'pipe1': APipe}, null);
|
||||
var pipes2 = Pipes.create({'pipe': AnotherPipe, 'pipe2': AnotherPipe}, null, pipes1);
|
||||
|
||||
var pipes1 = Pipes.create({'async': [firstPipeFactory]});
|
||||
var pipes2 = Pipes.create({'async': [secondPipeFactory]}, pipes1);
|
||||
|
||||
expect(pipes2.get("async", "first")).toBe(secondPipe);
|
||||
expect(pipes2.config).toEqual({'pipe': AnotherPipe, 'pipe1': APipe, 'pipe2': AnotherPipe});
|
||||
});
|
||||
|
||||
it("should use inherited pipes when no overrides support the provided object", () => {
|
||||
firstPipeFactory.spy("supports").andReturn(true);
|
||||
firstPipeFactory.spy("create").andReturn(firstPipe);
|
||||
secondPipeFactory.spy("supports").andReturn(false);
|
||||
it("should not change parent's config", () => {
|
||||
var pipes1 = Pipes.create({'pipe': APipe, 'pipe1': APipe}, null);
|
||||
Pipes.create({'pipe': AnotherPipe, 'pipe2': AnotherPipe}, null, pipes1);
|
||||
|
||||
var pipes1 = Pipes.create({'async': [firstPipeFactory], 'date': [firstPipeFactory]});
|
||||
var pipes2 = Pipes.create({'async': [secondPipeFactory]}, pipes1);
|
||||
|
||||
expect(pipes2.get("async", "first")).toBe(firstPipe);
|
||||
expect(pipes2.get("date", "first")).toBe(firstPipe);
|
||||
expect(pipes1.config).toEqual({'pipe': APipe, 'pipe1': APipe});
|
||||
});
|
||||
});
|
||||
|
||||
describe(".extend()", () => {
|
||||
it('should create a factory that prepend new pipes to old', () => {
|
||||
firstPipeFactory.spy("supports").andReturn(true);
|
||||
secondPipeFactory.spy("supports").andReturn(true);
|
||||
secondPipeFactory.spy("create").andReturn(secondPipe);
|
||||
var pipes1 = Pipes.create({'pipe': APipe, 'pipe1': APipe}, null);
|
||||
var binding = Pipes.extend({'pipe': AnotherPipe, 'pipe2': AnotherPipe});
|
||||
var pipes: Pipes = binding.toFactory(pipes1, injector);
|
||||
|
||||
var originalPipes = new Pipes({'async': [firstPipeFactory]});
|
||||
var binding = Pipes.extend({'async':<PipeFactory[]>[secondPipeFactory]});
|
||||
var pipes: Pipes = binding.toFactory(originalPipes);
|
||||
|
||||
expect(pipes.config['async'].length).toBe(2);
|
||||
expect(originalPipes.config['async'].length).toBe(1);
|
||||
expect(pipes.get('async', 'second plz')).toBe(secondPipe);
|
||||
expect(pipes.config).toEqual({'pipe': AnotherPipe, 'pipe1': APipe, 'pipe2': AnotherPipe});
|
||||
});
|
||||
|
||||
it('should throw if calling extend when creating root injector', () => {
|
||||
secondPipeFactory.spy("supports").andReturn(true);
|
||||
secondPipeFactory.spy("create").andReturn(secondPipe);
|
||||
|
||||
var injector: Injector =
|
||||
Injector.resolveAndCreate([Pipes.extend({'async': [secondPipeFactory]})]);
|
||||
var injector = Injector.resolveAndCreate([Pipes.extend({'pipe': APipe})]);
|
||||
|
||||
expect(() => injector.get(Pipes))
|
||||
.toThrowErrorWith("Cannot extend Pipes without a parent injector");
|
||||
});
|
||||
|
||||
it('should extend di-inherited pipes', () => {
|
||||
firstPipeFactory.spy("supports").andReturn(true);
|
||||
firstPipeFactory.spy("create").andReturn(firstPipe);
|
||||
|
||||
secondPipeFactory.spy("supports").andReturn(false);
|
||||
|
||||
var originalPipes: Pipes = new Pipes({'async': [firstPipeFactory]});
|
||||
var injector: Injector = Injector.resolveAndCreate([bind(Pipes).toValue(originalPipes)]);
|
||||
var childInjector: Injector =
|
||||
injector.resolveAndCreateChild([Pipes.extend({'async': [secondPipeFactory]})]);
|
||||
|
||||
var parentPipes: Pipes = injector.get(Pipes);
|
||||
var childPipes: Pipes = childInjector.get(Pipes);
|
||||
|
||||
expect(childPipes.config['async'].length).toBe(2);
|
||||
expect(parentPipes.config['async'].length).toBe(1);
|
||||
expect(childPipes.get('async', 'second plz')).toBe(firstPipe);
|
||||
});
|
||||
});
|
||||
});
|
||||
}
|
||||
|
@ -4,27 +4,16 @@ import {UpperCasePipe} from 'angular2/src/change_detection/pipes/uppercase_pipe'
|
||||
|
||||
export function main() {
|
||||
describe("UpperCasePipe", () => {
|
||||
var str;
|
||||
var upper;
|
||||
var lower;
|
||||
var pipe;
|
||||
|
||||
beforeEach(() => {
|
||||
str = 'something';
|
||||
lower = 'something';
|
||||
upper = 'SOMETHING';
|
||||
pipe = new UpperCasePipe();
|
||||
});
|
||||
|
||||
describe("supports", () => {
|
||||
it("should support strings", () => { expect(pipe.supports(str)).toBe(true); });
|
||||
|
||||
it("should not support other objects", () => {
|
||||
expect(pipe.supports(new Object())).toBe(false);
|
||||
expect(pipe.supports(null)).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe("transform", () => {
|
||||
|
||||
it("should return uppercase", () => {
|
||||
@ -39,6 +28,8 @@ export function main() {
|
||||
expect(val2).toEqual('WAT');
|
||||
});
|
||||
|
||||
it("should not support other objects",
|
||||
() => { expect(() => pipe.transform(new Object())).toThrowError(); });
|
||||
});
|
||||
|
||||
});
|
||||
|
Reference in New Issue
Block a user