noDupeKeys.js.flow 2.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394
  1. import _ from 'lodash/';
  2. import {
  3. getParameterName,
  4. } from '../utilities';
  5. const schema = [];
  6. const create = (context) => {
  7. const report = (node) => {
  8. context.report({
  9. loc: node.loc,
  10. message: 'Duplicate property.',
  11. node,
  12. });
  13. };
  14. const analyzeElement = (element) => {
  15. const { type } = element;
  16. let value;
  17. switch (type) {
  18. case 'GenericTypeAnnotation':
  19. value = element.id.name;
  20. break;
  21. case 'ObjectTypeAnnotation':
  22. // eslint-disable-next-line no-use-before-define
  23. value = buildObjectStructure(element.properties);
  24. break;
  25. case 'TupleTypeAnnotation':
  26. // eslint-disable-next-line no-use-before-define
  27. value = buildArrayStructure(element.types);
  28. break;
  29. default:
  30. value = element.value;
  31. break;
  32. }
  33. return {
  34. type,
  35. value,
  36. };
  37. };
  38. const buildArrayStructure = (elements) => _.map(elements, (element) => analyzeElement(element));
  39. const buildObjectStructure = (properties) => _.map(properties, (property) => {
  40. const element = analyzeElement(
  41. property.type === 'ObjectTypeSpreadProperty'
  42. ? property.argument
  43. : property.value,
  44. );
  45. return {
  46. ...element,
  47. name: getParameterName(property, context),
  48. };
  49. });
  50. const checkForDuplicates = (node) => {
  51. const haystack = [];
  52. // filter out complex object types, like ObjectTypeSpreadProperty
  53. const identifierNodes = _.filter(node.properties, { type: 'ObjectTypeProperty' });
  54. for (const identifierNode of identifierNodes) {
  55. const needle = { name: getParameterName(identifierNode, context) };
  56. if (identifierNode.value.type === 'FunctionTypeAnnotation') {
  57. needle.args = _.map(
  58. identifierNode.value.params,
  59. (param) => analyzeElement(param.typeAnnotation),
  60. );
  61. }
  62. const match = _.some(haystack, (existingNeedle) => _.isEqual(existingNeedle, needle));
  63. if (match) {
  64. report(identifierNode);
  65. } else {
  66. haystack.push(needle);
  67. }
  68. }
  69. };
  70. return {
  71. ObjectTypeAnnotation: checkForDuplicates,
  72. };
  73. };
  74. export default {
  75. create,
  76. schema,
  77. };