fix(DirectiveResolver): throw on duplicate Input & Output names
This commit is contained in:
parent
93d0a01d3d
commit
d1a3e3aff1
|
@ -7,11 +7,13 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import {ComponentMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, Injectable, InputMetadata, OutputMetadata, QueryMetadata, resolveForwardRef} from '@angular/core';
|
import {ComponentMetadata, DirectiveMetadata, HostBindingMetadata, HostListenerMetadata, Injectable, InputMetadata, OutputMetadata, QueryMetadata, resolveForwardRef} from '@angular/core';
|
||||||
import {ReflectorReader, reflector} from '../core_private';
|
|
||||||
import {ListWrapper, StringMapWrapper} from '../src/facade/collection';
|
|
||||||
import {BaseException} from '../src/facade/exceptions';
|
|
||||||
import {Type, isPresent, stringify} from '../src/facade/lang';
|
|
||||||
|
|
||||||
|
import {ReflectorReader, reflector} from '../core_private';
|
||||||
|
|
||||||
|
import {StringMapWrapper} from './facade/collection';
|
||||||
|
import {BaseException} from './facade/exceptions';
|
||||||
|
import {Type, isPresent, stringify} from './facade/lang';
|
||||||
|
import {splitAtColon} from './util';
|
||||||
|
|
||||||
function _isDirectiveMetadata(type: any): type is DirectiveMetadata {
|
function _isDirectiveMetadata(type: any): type is DirectiveMetadata {
|
||||||
return type instanceof DirectiveMetadata;
|
return type instanceof DirectiveMetadata;
|
||||||
|
@ -91,20 +93,42 @@ export class DirectiveResolver {
|
||||||
return this._merge(dm, inputs, outputs, host, queries, directiveType);
|
return this._merge(dm, inputs, outputs, host, queries, directiveType);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private _extractPublicName(def: string) { return splitAtColon(def, [null, def])[1].trim(); }
|
||||||
|
|
||||||
private _merge(
|
private _merge(
|
||||||
dm: DirectiveMetadata, inputs: string[], outputs: string[], host: {[key: string]: string},
|
dm: DirectiveMetadata, inputs: string[], outputs: string[], host: {[key: string]: string},
|
||||||
queries: {[key: string]: any}, directiveType: Type): DirectiveMetadata {
|
queries: {[key: string]: any}, directiveType: Type): DirectiveMetadata {
|
||||||
var mergedInputs = isPresent(dm.inputs) ? ListWrapper.concat(dm.inputs, inputs) : inputs;
|
let mergedInputs: string[];
|
||||||
|
|
||||||
var mergedOutputs: string[];
|
if (isPresent(dm.inputs)) {
|
||||||
if (isPresent(dm.outputs)) {
|
const inputNames: string[] =
|
||||||
dm.outputs.forEach((propName: string) => {
|
dm.inputs.map((def: string): string => this._extractPublicName(def));
|
||||||
if (ListWrapper.contains(outputs, propName)) {
|
inputs.forEach((inputDef: string) => {
|
||||||
|
const publicName = this._extractPublicName(inputDef);
|
||||||
|
if (inputNames.indexOf(publicName) > -1) {
|
||||||
throw new BaseException(
|
throw new BaseException(
|
||||||
`Output event '${propName}' defined multiple times in '${stringify(directiveType)}'`);
|
`Input '${publicName}' defined multiple times in '${stringify(directiveType)}'`);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
mergedOutputs = ListWrapper.concat(dm.outputs, outputs);
|
mergedInputs = dm.inputs.concat(inputs);
|
||||||
|
} else {
|
||||||
|
mergedInputs = inputs;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mergedOutputs: string[];
|
||||||
|
|
||||||
|
if (isPresent(dm.outputs)) {
|
||||||
|
const outputNames: string[] =
|
||||||
|
dm.outputs.map((def: string): string => this._extractPublicName(def));
|
||||||
|
|
||||||
|
outputs.forEach((outputDef: string) => {
|
||||||
|
const publicName = this._extractPublicName(outputDef);
|
||||||
|
if (outputNames.indexOf(publicName) > -1) {
|
||||||
|
throw new BaseException(
|
||||||
|
`Output event '${publicName}' defined multiple times in '${stringify(directiveType)}'`);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mergedOutputs = dm.outputs.concat(outputs);
|
||||||
} else {
|
} else {
|
||||||
mergedOutputs = outputs;
|
mergedOutputs = outputs;
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,7 +31,6 @@ class SomeDirectiveWithOutputs {
|
||||||
c: any;
|
c: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Directive({selector: 'someDirective', outputs: ['a']})
|
@Directive({selector: 'someDirective', outputs: ['a']})
|
||||||
class SomeDirectiveWithDuplicateOutputs {
|
class SomeDirectiveWithDuplicateOutputs {
|
||||||
@Output() a: any;
|
@Output() a: any;
|
||||||
|
@ -43,6 +42,17 @@ class SomeDirectiveWithDuplicateRenamedOutputs {
|
||||||
localA: any;
|
localA: any;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Directive({selector: 'someDirective', inputs: ['a']})
|
||||||
|
class SomeDirectiveWithDuplicateInputs {
|
||||||
|
@Input() a: any;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Directive({selector: 'someDirective', inputs: ['localA: a']})
|
||||||
|
class SomeDirectiveWithDuplicateRenamedInputs {
|
||||||
|
@Input() a: any;
|
||||||
|
localA: any;
|
||||||
|
}
|
||||||
|
|
||||||
@Directive({selector: 'someDirective'})
|
@Directive({selector: 'someDirective'})
|
||||||
class SomeDirectiveWithSetterProps {
|
class SomeDirectiveWithSetterProps {
|
||||||
@Input('renamed')
|
@Input('renamed')
|
||||||
|
@ -133,6 +143,17 @@ export function main() {
|
||||||
expect(directiveMetadata.inputs).toEqual(['a: renamed']);
|
expect(directiveMetadata.inputs).toEqual(['a: renamed']);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw if duplicate inputs', () => {
|
||||||
|
expect(() => {
|
||||||
|
resolver.resolve(SomeDirectiveWithDuplicateInputs);
|
||||||
|
}).toThrowError(`Input 'a' defined multiple times in 'SomeDirectiveWithDuplicateInputs'`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw if duplicate inputs (with rename)', () => {
|
||||||
|
expect(() => { resolver.resolve(SomeDirectiveWithDuplicateRenamedInputs); })
|
||||||
|
.toThrowError(
|
||||||
|
`Input 'a' defined multiple times in 'SomeDirectiveWithDuplicateRenamedInputs'`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('outputs', () => {
|
describe('outputs', () => {
|
||||||
|
@ -151,6 +172,12 @@ export function main() {
|
||||||
.toThrowError(
|
.toThrowError(
|
||||||
`Output event 'a' defined multiple times in 'SomeDirectiveWithDuplicateOutputs'`);
|
`Output event 'a' defined multiple times in 'SomeDirectiveWithDuplicateOutputs'`);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('should throw if duplicate outputs (with rename)', () => {
|
||||||
|
expect(() => { resolver.resolve(SomeDirectiveWithDuplicateRenamedOutputs); })
|
||||||
|
.toThrowError(
|
||||||
|
`Output event 'a' defined multiple times in 'SomeDirectiveWithDuplicateRenamedOutputs'`);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
describe('host', () => {
|
describe('host', () => {
|
||||||
|
|
Loading…
Reference in New Issue