grips.js 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123
  1. /* -*- indent-tabs-mode: nil; js-indent-level: 2 -*- */
  2. /* This Source Code Form is subject to the terms of the Mozilla Public
  3. * License, v. 2.0. If a copy of the MPL was not distributed with this
  4. * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  5. "use strict";
  6. const constants = require("../constants");
  7. /**
  8. * Initial state definition
  9. */
  10. function getInitialState() {
  11. return new Map();
  12. }
  13. /**
  14. * Maintain a cache of received grip responses from the backend.
  15. */
  16. function grips(state = getInitialState(), action) {
  17. // This reducer supports only one action, fetching actor properties
  18. // from the backend so, bail out if we are dealing with any other
  19. // action.
  20. if (action.type != constants.FETCH_PROPERTIES) {
  21. return state;
  22. }
  23. switch (action.status) {
  24. case "start":
  25. return onRequestProperties(state, action);
  26. case "end":
  27. return onReceiveProperties(state, action);
  28. }
  29. return state;
  30. }
  31. /**
  32. * Handle requestProperties action
  33. */
  34. function onRequestProperties(state, action) {
  35. return state;
  36. }
  37. /**
  38. * Handle receiveProperties action
  39. */
  40. function onReceiveProperties(cache, action) {
  41. let response = action.response;
  42. let from = response.from;
  43. let className = action.grip.class;
  44. // Properly deal with getters.
  45. mergeProperties(response);
  46. // Compute list of requested children.
  47. let previewProps = response.preview ? response.preview.ownProperties : null;
  48. let ownProps = response.ownProperties || previewProps || [];
  49. let props = Object.keys(ownProps).map(key => {
  50. // Array indexes as a special case. We convert any keys that are string
  51. // representations of integers to integers.
  52. if (className === "Array" && isInteger(key)) {
  53. key = parseInt(key, 10);
  54. }
  55. return new Property(key, ownProps[key], key);
  56. });
  57. props.sort(sortName);
  58. // Return new state/map.
  59. let newCache = new Map(cache);
  60. newCache.set(from, props);
  61. return newCache;
  62. }
  63. // Helpers
  64. function mergeProperties(response) {
  65. let { ownProperties } = response;
  66. // 'safeGetterValues' is new and isn't necessary defined on old grips.
  67. let safeGetterValues = response.safeGetterValues || {};
  68. // Merge the safe getter values into one object such that we can use it
  69. // in variablesView.
  70. for (let name of Object.keys(safeGetterValues)) {
  71. if (name in ownProperties) {
  72. let { getterValue, getterPrototypeLevel } = safeGetterValues[name];
  73. ownProperties[name].getterValue = getterValue;
  74. ownProperties[name].getterPrototypeLevel = getterPrototypeLevel;
  75. } else {
  76. ownProperties[name] = safeGetterValues[name];
  77. }
  78. }
  79. }
  80. function sortName(a, b) {
  81. // Display non-enumerable properties at the end.
  82. if (!a.value.enumerable && b.value.enumerable) {
  83. return 1;
  84. }
  85. if (a.value.enumerable && !b.value.enumerable) {
  86. return -1;
  87. }
  88. return a.name > b.name ? 1 : -1;
  89. }
  90. function isInteger(n) {
  91. // We use parseInt(n, 10) == n to disregard scientific notation e.g. "3e24"
  92. return isFinite(n) && parseInt(n, 10) == n;
  93. }
  94. function Property(name, value, key) {
  95. this.name = name;
  96. this.value = value;
  97. this.key = key;
  98. }
  99. // Exports from this module
  100. exports.grips = grips;
  101. exports.Property = Property;