Skip to content

Commit 4c8ea12

Browse files
committed
feat(pipes): changed .append to .extend
BREAKING CHANGE: Pipes.append has been renamed into Pipes.extend. Pipes.extend prepends pipe factories instead of appending them.
1 parent e942709 commit 4c8ea12

File tree

2 files changed

+82
-49
lines changed

2 files changed

+82
-49
lines changed

modules/angular2/src/change_detection/pipes/pipes.ts

Lines changed: 26 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,18 +40,18 @@ export class Pipes {
4040
}
4141

4242
/**
43-
* Takes a {@link Pipes} config object and returns a binding used to append the
44-
* provided config to an inherited {@link Pipes} instance and return a new
43+
* Takes a {@link Pipes} config object and returns a binding used to extend the
44+
* inherited {@link Pipes} instance with the provided config and return a new
4545
* {@link Pipes} instance.
4646
*
4747
* If the provided config contains a key that is not yet present in the
4848
* inherited {@link Pipes}' config, a new {@link PipeFactory} list will be created
4949
* for that key. Otherwise, the provided config will be merged with the inherited
50-
* {@link Pipes} instance by appending pipes to their respective keys, without mutating
50+
* {@link Pipes} instance by prepending pipes to their respective keys, without mutating
5151
* the inherited {@link Pipes}.
5252
*
53-
* The following example shows how to append a new {@link PipeFactory} to the
54-
* existing list of `async` factories, which will only be applied to the injector
53+
* The following example shows how to extend an existing list of `async` factories
54+
* with a new {@link PipeFactory}, which will only be applied to the injector
5555
* for this component and its children. This step is all that's required to make a new
5656
* pipe available to this component's template.
5757
*
@@ -60,44 +60,42 @@ export class Pipes {
6060
* ```
6161
* @Component({
6262
* viewInjector: [
63-
* Pipes.append({
63+
* Pipes.extend({
6464
* async: [newAsyncPipe]
6565
* })
6666
* ]
6767
* })
6868
* ```
6969
*/
70-
static append(config): Binding {
70+
static extend(config): Binding {
7171
return new Binding(Pipes, {
7272
toFactory: (pipes: Pipes) => {
73-
if (!isPresent(pipes)) {
74-
// Typically would occur when calling Pipe.append inside of dependencies passed to
75-
// bootstrap(), which would override default pipes instead of append.
76-
throw new BaseException('Cannot append to Pipes without a parent injector');
73+
if (isBlank(pipes)) {
74+
// Typically would occur when calling Pipe.extend inside of dependencies passed to
75+
// bootstrap(), which would override default pipes instead of extending them.
76+
throw new BaseException('Cannot extend Pipes without a parent injector');
7777
}
78-
var mergedConfig: StringMap<string, PipeFactory[]> = <StringMap<string, PipeFactory[]>>{};
79-
80-
// Manual deep copy of existing Pipes config,
81-
// so that lists of PipeFactories don't get mutated.
82-
StringMapWrapper.forEach(pipes.config, (v: PipeFactory[], k: string) => {
83-
var localPipeList: PipeFactory[] = mergedConfig[k] = [];
84-
v.forEach((p: PipeFactory) => { localPipeList.push(p); });
85-
});
86-
87-
StringMapWrapper.forEach(config, (v: PipeFactory[], k: string) => {
88-
if (isListLikeIterable(mergedConfig[k])) {
89-
mergedConfig[k] = ListWrapper.concat(mergedConfig[k], config[k]);
90-
} else {
91-
mergedConfig[k] = config[k];
92-
}
93-
});
94-
return new Pipes(mergedConfig);
78+
return Pipes.create(config, pipes);
9579
},
9680
// Dependency technically isn't optional, but we can provide a better error message this way.
9781
deps: [[Pipes, new UnboundedMetadata(), new OptionalMetadata()]]
9882
});
9983
}
10084

85+
static create(config, pipes: Pipes = null): Pipes {
86+
if (isPresent(pipes)) {
87+
StringMapWrapper.forEach(pipes.config, (v: PipeFactory[], k: string) => {
88+
if (StringMapWrapper.contains(config, k)) {
89+
var configFactories: PipeFactory[] = config[k];
90+
config[k] = configFactories.concat(v);
91+
} else {
92+
config[k] = ListWrapper.clone(v);
93+
}
94+
});
95+
}
96+
return new Pipes(config);
97+
}
98+
10199
private _getListOfFactories(type: string, obj: any): PipeFactory[] {
102100
var listOfFactories = this.config[type];
103101
if (isBlank(listOfFactories)) {

modules/angular2/test/change_detection/pipes/pipes_spec.ts

Lines changed: 56 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -76,47 +76,82 @@ export function main() {
7676
.toThrowError(`Cannot find 'type' pipe supporting object 'some object'`);
7777
});
7878

79-
describe('.append()', () => {
80-
it('should create a factory that appends new pipes to old', () => {
81-
firstPipeFactory.spy("supports").andReturn(false);
79+
describe('.create()', () => {
80+
it("should create a new Pipes object", () => {
81+
firstPipeFactory.spy("supports").andReturn(true);
82+
firstPipeFactory.spy("create").andReturn(firstPipe);
83+
84+
var pipes = Pipes.create({'async': [firstPipeFactory]});
85+
expect(pipes.get("async", "first")).toBe(firstPipe);
86+
});
87+
88+
it("should prepend passed it config in existing registry", () => {
89+
firstPipeFactory.spy("supports").andReturn(true);
8290
secondPipeFactory.spy("supports").andReturn(true);
8391
secondPipeFactory.spy("create").andReturn(secondPipe);
92+
93+
var pipes1 = Pipes.create({'async': [firstPipeFactory]});
94+
var pipes2 = Pipes.create({'async': [secondPipeFactory]}, pipes1);
95+
96+
expect(pipes2.get("async", "first")).toBe(secondPipe);
97+
});
98+
99+
it("should use inherited pipes when no overrides support the provided object", () => {
100+
firstPipeFactory.spy("supports").andReturn(true);
101+
firstPipeFactory.spy("create").andReturn(firstPipe);
102+
secondPipeFactory.spy("supports").andReturn(false);
103+
104+
var pipes1 = Pipes.create({'async': [firstPipeFactory], 'date': [firstPipeFactory]});
105+
var pipes2 = Pipes.create({'async': [secondPipeFactory]}, pipes1);
106+
107+
expect(pipes2.get("async", "first")).toBe(firstPipe);
108+
expect(pipes2.get("date", "first")).toBe(firstPipe);
109+
});
110+
});
111+
112+
describe(".extend()", () => {
113+
it('should create a factory that prepend new pipes to old', () => {
114+
firstPipeFactory.spy("supports").andReturn(true);
115+
secondPipeFactory.spy("supports").andReturn(true);
116+
secondPipeFactory.spy("create").andReturn(secondPipe);
117+
84118
var originalPipes = new Pipes({'async': [firstPipeFactory]});
85-
var binding = Pipes.append({'async':<PipeFactory[]>[secondPipeFactory]});
119+
var binding = Pipes.extend({'async':<PipeFactory[]>[secondPipeFactory]});
86120
var pipes: Pipes = binding.toFactory(originalPipes);
87121

88122
expect(pipes.config['async'].length).toBe(2);
89123
expect(originalPipes.config['async'].length).toBe(1);
90124
expect(pipes.get('async', 'second plz')).toBe(secondPipe);
91125
});
92126

93-
94-
it('should append to di-inherited pipes', () => {
95-
firstPipeFactory.spy("supports").andReturn(false);
127+
it('should throw if calling extend when creating root injector', () => {
96128
secondPipeFactory.spy("supports").andReturn(true);
97129
secondPipeFactory.spy("create").andReturn(secondPipe);
98130

131+
var injector: Injector =
132+
Injector.resolveAndCreate([Pipes.extend({'async': [secondPipeFactory]})]);
133+
134+
expect(() => injector.get(Pipes))
135+
.toThrowError(/Cannot extend Pipes without a parent injector/g);
136+
});
137+
138+
it('should extend di-inherited pipes', () => {
139+
firstPipeFactory.spy("supports").andReturn(true);
140+
firstPipeFactory.spy("create").andReturn(firstPipe);
141+
142+
secondPipeFactory.spy("supports").andReturn(false);
143+
99144
var originalPipes: Pipes = new Pipes({'async': [firstPipeFactory]});
100145
var injector: Injector = Injector.resolveAndCreate([bind(Pipes).toValue(originalPipes)]);
101146
var childInjector: Injector =
102-
injector.resolveAndCreateChild([Pipes.append({'async': [secondPipeFactory]})]);
147+
injector.resolveAndCreateChild([Pipes.extend({'async': [secondPipeFactory]})]);
148+
103149
var parentPipes: Pipes = injector.get(Pipes);
104150
var childPipes: Pipes = childInjector.get(Pipes);
151+
105152
expect(childPipes.config['async'].length).toBe(2);
106153
expect(parentPipes.config['async'].length).toBe(1);
107-
expect(childPipes.get('async', 'second plz')).toBe(secondPipe);
108-
});
109-
110-
111-
it('should throw if calling append when creating root injector', () => {
112-
secondPipeFactory.spy("supports").andReturn(true);
113-
secondPipeFactory.spy("create").andReturn(secondPipe);
114-
115-
var injector: Injector =
116-
Injector.resolveAndCreate([Pipes.append({'async': [secondPipeFactory]})]);
117-
118-
expect(() => injector.get(Pipes))
119-
.toThrowError(/Cannot append to Pipes without a parent injector/g);
154+
expect(childPipes.get('async', 'second plz')).toBe(firstPipe);
120155
});
121156
});
122157
});

0 commit comments

Comments
 (0)