From 636ceada70418e57d50330d6fcdcac13ddab1745 Mon Sep 17 00:00:00 2001 From: Paul Brousseau Date: Tue, 21 Mar 2017 09:41:08 -0600 Subject: [PATCH] fix: no-dupe-keys with legal duplicated keys (#148) --- src/rules/noDupeKeys.js | 57 ++++++++++++++++- tests/rules/assertions/noDupeKeys.js | 91 +++++++++++++++++++++++++++- 2 files changed, 144 insertions(+), 4 deletions(-) diff --git a/src/rules/noDupeKeys.js b/src/rules/noDupeKeys.js index d419b2fb..90132ef2 100644 --- a/src/rules/noDupeKeys.js +++ b/src/rules/noDupeKeys.js @@ -12,13 +12,66 @@ export default (context) => { }); }; + const analizeElement = (element) => { + const {type} = element; + let value; + + switch (type) { + case 'GenericTypeAnnotation': + value = element.id.name; + break; + case 'ObjectTypeAnnotation': + // eslint-disable-next-line no-use-before-define + value = builObjectStructure(element.properties); + break; + case 'TupleTypeAnnotation': + // eslint-disable-next-line no-use-before-define + value = buildArrayStructure(element.types); + break; + default: + value = element.value; + break; + } + + return { + type, + value + }; + }; + + const buildArrayStructure = (elements) => { + return _.map(elements, (element) => { + return analizeElement(element); + }); + }; + + const builObjectStructure = (properties) => { + return _.map(properties, (property) => { + const element = analizeElement(property.value); + + return Object.assign(element, { + name: getParameterName(property, context) + }); + }); + }; + const checkForDuplicates = (node) => { const haystack = []; _.forEach(node.properties, (identifierNode) => { - const needle = getParameterName(identifierNode, context); + const needle = {name: getParameterName(identifierNode, context)}; + + if (identifierNode.value.type === 'FunctionTypeAnnotation') { + needle.args = _.map(identifierNode.value.params, (param) => { + return analizeElement(param.typeAnnotation); + }); + } + + const match = _.some(haystack, (existingNeedle) => { + return _.isEqual(existingNeedle, needle); + }); - if (_.includes(haystack, needle)) { + if (match) { report(identifierNode); } else { haystack.push(needle); diff --git a/tests/rules/assertions/noDupeKeys.js b/tests/rules/assertions/noDupeKeys.js index cecf60ff..c7f0d32b 100644 --- a/tests/rules/assertions/noDupeKeys.js +++ b/tests/rules/assertions/noDupeKeys.js @@ -1,11 +1,59 @@ export default { invalid: [ { - code: 'type FooType = { a: number, b: string, a: number }', + code: 'type f = { a: number, b: string, a: number }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'type f = { a: number, b: string, a: string }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'type f = { get(key: "a"): string, get(key: "a"): string }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'type f = { get(key: 1): string, get(key: 1): string }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'type f = { get(key: 1.1): string, get(key: 1.1): string }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'type f = { get(key: true): string, get(key: true): string }', errors: [{message: 'Duplicate property.'}] }, { - code: 'type FooType = { a: number, b: string, a: string }', + code: 'type f = { get(key: {a: 1}): string, get(key: {a: 1}):string }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'var a = "a"; type f = { get(key: a): string, get(key: a): string }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'var b = 1; type f = { get(key: b): string, get(key: b): string }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'var c = true; type f = { get(key: c): string, get(key: c): string }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'var d = {}; type f = { get(key: d): string, get(key: d): string }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'var e = []; type f = { get(key: e): string, get(key: e): string }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'var e = [1, "a"]; type f = { get(key: e): string, get(key: e): string }', + errors: [{message: 'Duplicate property.'}] + }, + { + code: 'function fn() {}; type f = { get(key: fn): string, get(key: fn): string }', errors: [{message: 'Duplicate property.'}] } ], @@ -20,6 +68,45 @@ export default { onlyFilesWithFlowAnnotation: true } } + }, + { + code: 'type f = { get(key: "a"): string, get(key: "b"): string }' + }, + { + code: 'type f = { get(key: 1): string, get(key: 2): string }' + }, + { + code: 'type f = { get(key: 1.1): string, get(key: 1.2): string }' + }, + { + code: 'type f = { get(key: true): string, get(key: false): string }' + }, + { + code: 'type f = { get(key: ["a", 1]): string, get(key: ["a", 2]): string }' + }, + { + code: 'type f = { get(key: ["a", ["b", 1]]): string, get(key: ["a", ["b", 2]]): string }' + }, + { + code: 'type f = { a: number, b: string, c: number }' + }, + { + code: 'type f = { get(key: "a"): string, get(key: "b"): string }' + }, + { + code: 'type f = { get(key: "a"): string, get(key: "a", key2: "b"): string }' + }, + { + code: 'type f = { get(key: "a"): string, get(key: 1): string }' + }, + { + code: 'type f = { get(key: { a: 1 }): string, get(key: { a: 2 }): string}' + }, + { + code: 'var a = {}; var b = {}; type f = { get(key: a): string, get(key: b): string }' + }, + { + code: 'var a = 1; var b = 1; type f = { get(key: a): string, get(key: b): string }' } ] };