resolveObjectValuesToArray.js 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586
  1. import resolveToValue from './resolveToValue.js';
  2. function isObjectValuesCall(path) {
  3. if (!path.isCallExpression() || path.node.arguments.length !== 1) {
  4. return false;
  5. }
  6. const callee = path.get('callee');
  7. if (!callee.isMemberExpression()) {
  8. return false;
  9. }
  10. const object = callee.get('object');
  11. const property = callee.get('property');
  12. return (object.isIdentifier({ name: 'Object' }) &&
  13. property.isIdentifier({ name: 'values' }));
  14. }
  15. // Resolves an ObjectExpression or an ObjectTypeAnnotation
  16. function resolveObjectToPropMap(object) {
  17. if (object.isObjectExpression()) {
  18. const values = new Map();
  19. let error = false;
  20. object.get('properties').forEach((propPath) => {
  21. if (error || propPath.isObjectMethod())
  22. return;
  23. if (propPath.isObjectProperty()) {
  24. const key = propPath.get('key');
  25. let name;
  26. // Key is either Identifier or Literal
  27. if (key.isIdentifier()) {
  28. name = key.node.name;
  29. }
  30. else if (key.isNumericLiteral() || key.isStringLiteral()) {
  31. name = `${key.node.value}`;
  32. }
  33. else {
  34. error = true;
  35. return;
  36. }
  37. const valuePath = resolveToValue(propPath.get('value'));
  38. const value = valuePath.isStringLiteral()
  39. ? `"${valuePath.node.value}"`
  40. : valuePath.isNumericLiteral()
  41. ? `${valuePath.node.value}`
  42. : // we return null here because there are a lot of cases and we don't know yet what we need to handle
  43. 'null';
  44. values.set(name, value);
  45. }
  46. else if (propPath.isSpreadElement()) {
  47. const spreadObject = resolveToValue(propPath.get('argument'));
  48. const spreadValues = resolveObjectToPropMap(spreadObject);
  49. if (!spreadValues) {
  50. error = true;
  51. return;
  52. }
  53. for (const entry of spreadValues.entries()) {
  54. const [key, value] = entry;
  55. values.set(key, value);
  56. }
  57. }
  58. });
  59. if (!error) {
  60. return values;
  61. }
  62. }
  63. return null;
  64. }
  65. /**
  66. * Returns an ArrayExpression which contains all the values resolved from an object
  67. *
  68. * Ignores setters in objects
  69. *
  70. * Returns null in case of
  71. * unresolvable spreads
  72. * computed identifier values
  73. */
  74. export default function resolveObjectValuesToArray(path) {
  75. if (isObjectValuesCall(path)) {
  76. const argument = path.get('arguments')[0];
  77. const objectExpression = resolveToValue(
  78. // isObjectValuesCall already asserts that there is at least one argument, hence the non-null-assertion
  79. argument);
  80. const values = resolveObjectToPropMap(objectExpression);
  81. if (values) {
  82. return Array.from(values.values());
  83. }
  84. }
  85. return null;
  86. }