UNPKG

mic-inspector

Version:

A react inspector which a most similar of Chorme DevTools inspector

157 lines (156 loc) 6.2 kB
import { DescriptorNameType, DescriptorValueType } from './types'; import { NamedDescriptor } from '.'; const PROTO = '__proto__'; const { Number } = window; const { get: prototypeGetter } = Object.getOwnPropertyDescriptor(Object.prototype, PROTO) || {}; /** * Get the name type of the property * @param name Property name */ export const getNameType = (name) => { // if the name type is 'symbol' if (typeof name === 'symbol') { return DescriptorNameType.Symbol; } const number = Number.parseInt(name); // if the name type is not 'number' if (Number.isNaN(number)) { return DescriptorNameType.String; } return ( // if the names are same that represents the type of number is int number.toString() === name ? DescriptorNameType.Int : DescriptorNameType.Float) | ( // if the number is 0 number === 0 ? DescriptorNameType.Zero : ( // if the number is greater than 0 number > 0 ? DescriptorNameType.Positive : DescriptorNameType.Negative)); }; /** * A method to sort the descriptors * @param descriptor1 Property descriptor * @param descriptor2 Another property descriptor */ export const sortNamedDescriptors = (descriptor1, descriptor2) => { const { name: n1, valueType: v1, nameType: nt1 } = descriptor1; const { name: n2, valueType: v2, nameType: nt2 } = descriptor2; // if the name of the first one is index if ((nt1 & DescriptorNameType.Index) === DescriptorNameType.Index) { // if the name of the second one is index too if ((nt2 & DescriptorNameType.Index) === DescriptorNameType.Index) { return n1 - n2 < 0 ? -1 : 1; } // insert the descriptor1 before descriptor2 return -1; } // if the name of the second one is index else if ((nt2 & DescriptorNameType.Index) === DescriptorNameType.Index) { // insert the descriptor2 before descriptor1 return 1; } // if the first one is __proto__ if (n1 === PROTO) { // insert the descriptor2 before descriptor1 return 1; } // if the second one is __proto__ else if (n2 === PROTO) { // insert the descriptor1 before descriptor2 return -1; } // if the first one is enumerable if (descriptor1.enumerable) { // if the second one is 'not' enumerable if (!descriptor2.enumerable) { // insert the descriptor1 before descriptor2 return -1; } } // if the second one is enumerable else if (descriptor2.enumerable) { // insert the descriptor2 before descriptor1 return 1; } // if the first one is an accessor if ((v1 & DescriptorValueType.Accessor) === DescriptorValueType.Accessor) { // if the second one is 'not' an accessor if ((v2 & DescriptorValueType.Accessor) !== DescriptorValueType.Accessor) { // insert the descriptor2 before descriptor1 return 1; } // if the names are same if (n1 === n2) { // if the first one is a getter, then insert the descriptor1 before descriptor2 return (v1 & DescriptorValueType.Getter) === DescriptorValueType.Getter ? -1 : 1; } } // if the second one is an accessor else if ((v2 & DescriptorValueType.Accessor) === DescriptorValueType.Accessor) { // insert the descriptor1 before descriptor2 return -1; } // sorted by name return n1 > n2 ? 1 : -1; }; /** * Get the sorted named descriptors of the specific property value * @param propertyValue Property value * @param owner An object as the owner that has these descriptors */ export const getNamedDescriptors = (propertyValue, owner = propertyValue) => { const prototype = Object.getPrototypeOf(propertyValue); const names = Object.getOwnPropertyNames(propertyValue); const descriptors = []; // for each names for (const name of names) { const descriptor = Object.getOwnPropertyDescriptor(propertyValue, name); // if no descriptor if (!descriptor) { continue; } const { value, get, set, enumerable, configurable } = descriptor; // if accessor existed if (get || set) { // if getter existed if (get) { try { // if the name is not '__proto__' or the getter is not the getter of object prototype if (name !== PROTO || get !== prototypeGetter) { descriptors.push(new NamedDescriptor(owner, name, get.call(owner), DescriptorValueType.Result, enumerable, configurable)); } } catch (e) { descriptors.push(new NamedDescriptor(owner, name, get, set, enumerable, configurable)); } descriptors.push(new NamedDescriptor(owner, name, get, DescriptorValueType.Getter, false, true)); } if (set) { descriptors.push(new NamedDescriptor(owner, name, set, DescriptorValueType.Setter, false, true)); } continue; } descriptors.push(new NamedDescriptor(owner, name, value, DescriptorValueType.Normal, enumerable, configurable)); } // if prototype is existed if (prototype) { // for each descriptors of the prototype for (const descriptor of getNamedDescriptors(prototype, owner)) { const { name, valueType } = descriptor; // if the name included by names or the name is '__proto__' if (names.includes(name) || name === PROTO) { continue; } // if the value type is not DescriptorValueType.Result if ((valueType & DescriptorValueType.Result) !== DescriptorValueType.Result) { continue; } descriptors.push(descriptor); } descriptors.push(new NamedDescriptor(propertyValue, PROTO, prototype, DescriptorValueType.Normal, false)); } // return a list after sort these descriptors return descriptors.sort(sortNamedDescriptors); };