tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

ObjectProvider.mjs (4616B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 /* eslint no-shadow: ["error", { "allow": ["name"] }] */
      6 
      7 import { JSON_NUMBER } from "resource://devtools/client/shared/components/reps/reps/constants.mjs";
      8 
      9 const MAX_NUMERICAL_PROPERTIES = 100;
     10 
     11 /**
     12 * Implementation of the default data provider. A provider is state less
     13 * object responsible for transformation data (usually a state) to
     14 * a structure that can be directly consumed by the tree-view component.
     15 */
     16 const ObjectProvider = {
     17  getChildren(object, options = {}) {
     18    const { bucketLargeArrays = false } = options;
     19    const children = [];
     20 
     21    if (bucketLargeArrays && object instanceof BucketProperty) {
     22      // Expand a bucket by returning its range of properties
     23      const actualObject = object.object;
     24      const { startIndex, endIndex } = object;
     25      const bucketSize = endIndex - startIndex + 1;
     26 
     27      // If this bucket is still too large (>100 elements), create nested buckets
     28      if (bucketSize > MAX_NUMERICAL_PROPERTIES) {
     29        return this.makeBuckets(actualObject, startIndex, endIndex);
     30      }
     31 
     32      // Otherwise, return the actual array elements
     33      for (let i = startIndex; i <= endIndex; i++) {
     34        children.push(new ObjectProperty(String(i), actualObject[i]));
     35      }
     36      return children;
     37    }
     38 
     39    if (object instanceof ObjectProperty) {
     40      object = object.value;
     41    }
     42 
     43    if (!object) {
     44      return [];
     45    }
     46 
     47    if (object?.type === JSON_NUMBER) {
     48      return [];
     49    }
     50 
     51    if (typeof object == "string") {
     52      return [];
     53    }
     54 
     55    // Check if bucketing is enabled and this is an array with many elements
     56    if (
     57      bucketLargeArrays &&
     58      Array.isArray(object) &&
     59      object.length > MAX_NUMERICAL_PROPERTIES
     60    ) {
     61      return this.makeBuckets(object);
     62    }
     63 
     64    for (const prop in object) {
     65      try {
     66        children.push(new ObjectProperty(prop, object[prop]));
     67      } catch (e) {
     68        console.error(e);
     69      }
     70    }
     71    return children;
     72  },
     73 
     74  makeBuckets(array, startIndex = 0, endIndex = array.length - 1) {
     75    const numProperties = endIndex - startIndex + 1;
     76    // We want to have at most a hundred slices.
     77    // This matches the bucketing algorithm in
     78    // devtools/client/shared/components/object-inspector/utils/node.js
     79    const bucketSize =
     80      10 ** Math.max(2, Math.ceil(Math.log10(numProperties)) - 2);
     81    const numBuckets = Math.ceil(numProperties / bucketSize);
     82 
     83    const buckets = [];
     84    for (let i = 1; i <= numBuckets; i++) {
     85      const minKey = (i - 1) * bucketSize;
     86      const maxKey = Math.min(i * bucketSize - 1, numProperties - 1);
     87      const minIndex = startIndex + minKey;
     88      const maxIndex = startIndex + maxKey;
     89      const bucketName = `[${minIndex}${maxIndex}]`;
     90 
     91      buckets.push(new BucketProperty(bucketName, array, minIndex, maxIndex));
     92    }
     93    return buckets;
     94  },
     95 
     96  hasChildren(object) {
     97    if (object instanceof BucketProperty) {
     98      // Buckets always have children (the range of properties they represent)
     99      return true;
    100    }
    101 
    102    if (object instanceof ObjectProperty) {
    103      object = object.value;
    104    }
    105 
    106    if (!object) {
    107      return false;
    108    }
    109 
    110    if (object.type === JSON_NUMBER) {
    111      return false;
    112    }
    113 
    114    if (typeof object == "string") {
    115      return false;
    116    }
    117 
    118    if (typeof object !== "object") {
    119      return false;
    120    }
    121 
    122    return !!Object.keys(object).length;
    123  },
    124 
    125  getLabel(object) {
    126    // Both BucketProperty and ObjectProperty have a .name property
    127    return object instanceof BucketProperty || object instanceof ObjectProperty
    128      ? object.name
    129      : null;
    130  },
    131 
    132  getValue(object) {
    133    return object instanceof ObjectProperty ? object.value : null;
    134  },
    135 
    136  getKey(object) {
    137    // Both BucketProperty and ObjectProperty use .name as their key
    138    return object instanceof BucketProperty || object instanceof ObjectProperty
    139      ? object.name
    140      : null;
    141  },
    142 
    143  getType(object) {
    144    if (object instanceof BucketProperty) {
    145      return "bucket";
    146    }
    147    return object instanceof ObjectProperty
    148      ? typeof object.value
    149      : typeof object;
    150  },
    151 };
    152 
    153 function ObjectProperty(name, value) {
    154  this.name = name;
    155  this.value = value;
    156 }
    157 
    158 function BucketProperty(name, object, startIndex, endIndex) {
    159  this.name = name;
    160  this.object = object;
    161  this.startIndex = startIndex;
    162  this.endIndex = endIndex;
    163 }
    164 
    165 // Exports from this module
    166 export { BucketProperty, ObjectProperty, ObjectProvider };