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 };