mirror of
https://github.com/angular/angular
synced 2026-05-24 09:28:37 +00:00
refactor(devtools): separate object creation concern from state serializer api (rangle/angular-devtools#69)
This commit is contained in:
parent
f06aedc28c
commit
ec1c95cbdb
9 changed files with 406 additions and 274 deletions
|
|
@ -8,8 +8,8 @@ import {
|
|||
prepareForestForSerialization,
|
||||
} from './component-tree';
|
||||
import { start as startProfiling, stop as stopProfiling } from './recording';
|
||||
import { serializeComponentState } from './state-serializer';
|
||||
import { ComponentInspector, ComponentInspectorOptions } from './component-inspector';
|
||||
import { serializeComponentState } from './state-serializer/state-serializer';
|
||||
import { ComponentInspector, ComponentInspectorOptions } from './component-inspector/component-inspector';
|
||||
import { setConsoleReference } from './selected-component';
|
||||
import { unHighlight } from './highlighter';
|
||||
import {
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import { unHighlight, highlight, findComponentAndHost } from './highlighter';
|
||||
import { unHighlight, highlight, findComponentAndHost } from '../highlighter';
|
||||
import { Type } from '@angular/core';
|
||||
import {
|
||||
getDirectiveForest,
|
||||
ComponentTreeNode,
|
||||
findNodeInForest,
|
||||
getIndexForNativeElementInForest,
|
||||
} from './component-tree';
|
||||
} from '../component-tree';
|
||||
import { ElementID } from 'protocol';
|
||||
import { indexForest, IndexedNode } from './recording/observer';
|
||||
import { indexForest, IndexedNode } from '../recording/observer';
|
||||
|
||||
export interface ComponentInspectorOptions {
|
||||
onComponentEnter: (id: ElementID) => void;
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
import { deeplySerializeSelectedProperties } from './state-serializer';
|
||||
import { deeplySerializeSelectedProperties } from './state-serializer/state-serializer';
|
||||
|
||||
declare const ng: any;
|
||||
|
||||
|
|
@ -36,6 +36,7 @@ export const getLatestComponentState = (query: ComponentExplorerViewQuery): Dire
|
|||
if (!node) {
|
||||
return undefined;
|
||||
}
|
||||
|
||||
result = {};
|
||||
node.directives.forEach(dir => {
|
||||
if (!query.expandedProperties[dir.name]) {
|
||||
|
|
@ -45,6 +46,7 @@ export const getLatestComponentState = (query: ComponentExplorerViewQuery): Dire
|
|||
props: deeplySerializeSelectedProperties(dir.instance, query.expandedProperties[dir.name]),
|
||||
};
|
||||
});
|
||||
|
||||
if (node.component) {
|
||||
if (!query.expandedProperties[node.component.name]) {
|
||||
return;
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
import { RecorderComponent } from './observer';
|
||||
import { AppRecord, ComponentEventType, LifeCycleEventType } from 'protocol';
|
||||
import { getComponentName } from '../highlighter';
|
||||
import { serializeComponentState } from '../state-serializer';
|
||||
import { serializeComponentState } from '../state-serializer/state-serializer';
|
||||
|
||||
export interface RecordFactoryOptions {
|
||||
eventType: ComponentEventType | LifeCycleEventType;
|
||||
|
|
|
|||
|
|
@ -1,267 +0,0 @@
|
|||
import { Descriptor, PropType, NestedProp } from 'protocol';
|
||||
|
||||
const ignoreList = new Set(['__ngContext__', '__ngSimpleChanges__']);
|
||||
|
||||
const commonTypes = {
|
||||
boolean: PropType.Boolean,
|
||||
bigint: PropType.BigInt,
|
||||
function: PropType.Function,
|
||||
number: PropType.Number,
|
||||
string: PropType.String,
|
||||
symbol: PropType.Symbol,
|
||||
};
|
||||
|
||||
const MAX_LEVEL = 1;
|
||||
|
||||
const getDescriptorPreview = (type: PropType, prop: any): string => {
|
||||
switch (type) {
|
||||
case PropType.Array:
|
||||
return `Array(${prop.length})`;
|
||||
case PropType.BigInt:
|
||||
case PropType.Boolean:
|
||||
return truncate(prop.toString());
|
||||
case PropType.String:
|
||||
return `"${prop}"`;
|
||||
case PropType.Function:
|
||||
return `${prop.name}(...)`;
|
||||
case PropType.HTMLElement:
|
||||
return prop.constructor.name;
|
||||
case PropType.Null:
|
||||
return 'null';
|
||||
case PropType.Number:
|
||||
return parseInt(prop, 10).toString();
|
||||
case PropType.Object:
|
||||
return Object.keys(prop).length > 0 ? '{...}' : '{}';
|
||||
case PropType.Symbol:
|
||||
return 'Symbol()';
|
||||
case PropType.Undefined:
|
||||
return 'undefined';
|
||||
case PropType.Unknown:
|
||||
return 'unknown';
|
||||
}
|
||||
return '';
|
||||
};
|
||||
|
||||
const getPropType = (prop: any): PropType => {
|
||||
if (prop === undefined) {
|
||||
return PropType.Undefined;
|
||||
}
|
||||
if (prop === null) {
|
||||
return PropType.Null;
|
||||
}
|
||||
if (prop instanceof HTMLElement) {
|
||||
return PropType.HTMLElement;
|
||||
}
|
||||
const type = typeof prop;
|
||||
if (commonTypes[type] !== undefined) {
|
||||
return commonTypes[type];
|
||||
}
|
||||
if (type === 'object') {
|
||||
if (Array.isArray(prop)) {
|
||||
return PropType.Array;
|
||||
} else if (Object.prototype.toString.call(prop) === '[object Date]') {
|
||||
return PropType.Date;
|
||||
} else {
|
||||
return PropType.Object;
|
||||
}
|
||||
}
|
||||
console.log(type, prop);
|
||||
return PropType.Unknown;
|
||||
};
|
||||
|
||||
const truncate = (str: string, max = 20): string => {
|
||||
if (str.length > max) {
|
||||
return str.substr(0, max) + '...';
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
||||
const serializeShallowProperty = (prop: any): Descriptor => {
|
||||
const type = getPropType(prop);
|
||||
switch (type) {
|
||||
case PropType.BigInt:
|
||||
return {
|
||||
type,
|
||||
value: truncate(prop.toString()),
|
||||
editable: false,
|
||||
expandable: false,
|
||||
preview: getDescriptorPreview(type, prop),
|
||||
};
|
||||
case PropType.String:
|
||||
return {
|
||||
type,
|
||||
value: truncate(prop.toString()),
|
||||
editable: true,
|
||||
expandable: false,
|
||||
preview: getDescriptorPreview(type, prop),
|
||||
};
|
||||
case PropType.Boolean:
|
||||
case PropType.Number:
|
||||
case PropType.Date:
|
||||
return {
|
||||
type,
|
||||
value: prop,
|
||||
editable: true,
|
||||
expandable: false,
|
||||
preview: getDescriptorPreview(type, prop),
|
||||
};
|
||||
case PropType.Null:
|
||||
case PropType.Undefined:
|
||||
return {
|
||||
type,
|
||||
editable: true,
|
||||
expandable: false,
|
||||
preview: getDescriptorPreview(type, prop),
|
||||
};
|
||||
case PropType.Symbol:
|
||||
case PropType.Function:
|
||||
case PropType.HTMLElement:
|
||||
case PropType.Unknown: {
|
||||
return {
|
||||
type,
|
||||
editable: false,
|
||||
expandable: false,
|
||||
preview: getDescriptorPreview(type, prop),
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const nestedSerializer = (
|
||||
serializableInstance: any,
|
||||
nodes: NestedProp[],
|
||||
currentLevel = 0,
|
||||
level = MAX_LEVEL
|
||||
): Descriptor => {
|
||||
const type: PropType = getPropType(serializableInstance);
|
||||
if (currentLevel < level) {
|
||||
return levelSerializer(
|
||||
serializableInstance,
|
||||
undefined,
|
||||
currentLevel,
|
||||
level,
|
||||
(nestedProp: any, propName: string | number | undefined, nestedLevel: number) => {
|
||||
const idx = nodes.findIndex(v => v.name === propName);
|
||||
if (idx < 0) {
|
||||
// The property is not specified in the query.
|
||||
return nestedSerializer(nestedProp, [], nestedLevel, level);
|
||||
}
|
||||
return nestedSerializer(nestedProp, nodes[idx].children, nestedLevel, level);
|
||||
}
|
||||
);
|
||||
} else {
|
||||
switch (type) {
|
||||
case PropType.Array:
|
||||
const arr: Descriptor = {
|
||||
type,
|
||||
editable: true,
|
||||
expandable: serializableInstance.length > 0,
|
||||
preview: getDescriptorPreview(type, serializableInstance),
|
||||
};
|
||||
if (nodes && nodes.length) {
|
||||
arr.value = nodes.map(c => nestedSerializer(serializableInstance[c.name], c.children, currentLevel + 1));
|
||||
}
|
||||
return arr;
|
||||
case PropType.Object:
|
||||
const obj: Descriptor = {
|
||||
type,
|
||||
editable: true,
|
||||
expandable: Object.keys(serializableInstance).length > 0,
|
||||
preview: getDescriptorPreview(type, serializableInstance),
|
||||
};
|
||||
if (nodes && nodes.length) {
|
||||
obj.value = nodes.reduce((accum, c) => {
|
||||
if (serializableInstance.hasOwnProperty(c.name) && typeof c.name === 'string' && !ignoreList.has(c.name)) {
|
||||
accum[c.name] = nestedSerializer(serializableInstance[c.name], c.children, currentLevel + 1);
|
||||
}
|
||||
return accum;
|
||||
}, {});
|
||||
}
|
||||
return obj;
|
||||
default:
|
||||
return serializeShallowProperty(serializableInstance);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export const levelSerializer = (
|
||||
serializableInstance: any,
|
||||
_: string | number | undefined = undefined,
|
||||
currentLevel = 0,
|
||||
level = MAX_LEVEL,
|
||||
continuation = levelSerializer
|
||||
): Descriptor => {
|
||||
const type = getPropType(serializableInstance);
|
||||
switch (type) {
|
||||
case PropType.Array:
|
||||
if (currentLevel < level) {
|
||||
return {
|
||||
type,
|
||||
value: serializableInstance.map((nested: any, idx: number) =>
|
||||
continuation(nested, idx, currentLevel + 1, level)
|
||||
),
|
||||
editable: true,
|
||||
expandable: serializableInstance.length > 0,
|
||||
preview: getDescriptorPreview(type, serializableInstance),
|
||||
};
|
||||
}
|
||||
return {
|
||||
type,
|
||||
editable: true,
|
||||
expandable: serializableInstance.length > 0,
|
||||
preview: getDescriptorPreview(type, serializableInstance),
|
||||
};
|
||||
case PropType.Object:
|
||||
if (currentLevel < level) {
|
||||
return {
|
||||
type,
|
||||
value: Object.keys(serializableInstance).reduce((prev, key) => {
|
||||
if (typeof key === 'string' && !ignoreList.has(key)) {
|
||||
prev[key] = continuation(serializableInstance[key], key, currentLevel + 1, level);
|
||||
}
|
||||
return prev;
|
||||
}, {}),
|
||||
editable: true,
|
||||
expandable: Object.keys(serializableInstance).length > 0,
|
||||
preview: getDescriptorPreview(type, serializableInstance),
|
||||
};
|
||||
}
|
||||
return {
|
||||
type,
|
||||
editable: true,
|
||||
expandable: Object.keys(serializableInstance).length > 0,
|
||||
preview: getDescriptorPreview(type, serializableInstance),
|
||||
};
|
||||
default:
|
||||
return serializeShallowProperty(serializableInstance);
|
||||
}
|
||||
};
|
||||
|
||||
export const serializeComponentState = (instance: object, levels = MAX_LEVEL): { [key: string]: Descriptor } => {
|
||||
const result = {};
|
||||
for (const prop in instance) {
|
||||
if (instance.hasOwnProperty(prop) && !ignoreList.has(prop)) {
|
||||
result[prop] = levelSerializer(instance[prop], null, 0, levels);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export const deeplySerializeSelectedProperties = (
|
||||
instance: any,
|
||||
props: NestedProp[]
|
||||
): { [name: string]: Descriptor } => {
|
||||
const result = {};
|
||||
Object.keys(instance).forEach(propName => {
|
||||
if (ignoreList.has(propName)) {
|
||||
return;
|
||||
}
|
||||
const idx = props.findIndex(v => v.name === propName);
|
||||
if (idx < 0) {
|
||||
result[propName] = levelSerializer(instance[propName]);
|
||||
} else {
|
||||
result[propName] = nestedSerializer(instance[propName], props[idx].children);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
|
@ -0,0 +1,265 @@
|
|||
import { Descriptor, NestedProp, PropType } from 'protocol';
|
||||
|
||||
interface PropData {
|
||||
type: PropType;
|
||||
prop: any;
|
||||
}
|
||||
|
||||
interface LevelOptions {
|
||||
currentLevel: number;
|
||||
level?: number;
|
||||
}
|
||||
|
||||
interface CommonTypeCases {
|
||||
arrayCase?: () => any;
|
||||
bigIntCase?: () => any;
|
||||
booleanCase?: () => any;
|
||||
stringCase?: () => any;
|
||||
dateCase?: () => any;
|
||||
functionCase?: () => any;
|
||||
htmlElementCase?: () => any;
|
||||
nullCase?: () => any;
|
||||
numberCase?: () => any;
|
||||
objectCase?: () => any;
|
||||
symbolCase?: () => any;
|
||||
undefinedCase?: () => any;
|
||||
unknownCase?: () => any;
|
||||
}
|
||||
|
||||
const ignoreList = new Set(['__ngContext__', '__ngSimpleChanges__']);
|
||||
|
||||
const shallowPropTypeToTreeMetaData = {
|
||||
[PropType.String]: {
|
||||
editable: true,
|
||||
expandable: false,
|
||||
},
|
||||
[PropType.BigInt]: {
|
||||
editable: false,
|
||||
expandable: false,
|
||||
},
|
||||
[PropType.Boolean]: {
|
||||
editable: true,
|
||||
expandable: false,
|
||||
},
|
||||
[PropType.Number]: {
|
||||
editable: true,
|
||||
expandable: false,
|
||||
},
|
||||
[PropType.Date]: {
|
||||
editable: true,
|
||||
expandable: false,
|
||||
},
|
||||
[PropType.Null]: {
|
||||
editable: true,
|
||||
expandable: false,
|
||||
},
|
||||
[PropType.Undefined]: {
|
||||
editable: true,
|
||||
expandable: false,
|
||||
},
|
||||
[PropType.Symbol]: {
|
||||
editable: false,
|
||||
expandable: false,
|
||||
},
|
||||
[PropType.Function]: {
|
||||
editable: false,
|
||||
expandable: false,
|
||||
},
|
||||
[PropType.HTMLElement]: {
|
||||
editable: false,
|
||||
expandable: false,
|
||||
},
|
||||
[PropType.Unknown]: {
|
||||
editable: false,
|
||||
expandable: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const createShallowSerializedDescriptor = (propData: PropData): Descriptor => {
|
||||
const { type } = propData;
|
||||
|
||||
const shallowSerializedDescriptor: Descriptor = {
|
||||
type,
|
||||
expandable: shallowPropTypeToTreeMetaData[type].expandable,
|
||||
editable: shallowPropTypeToTreeMetaData[type].editable,
|
||||
preview: getDescriptorPreview(propData),
|
||||
};
|
||||
|
||||
const value = getShallowDescriptorValue(propData);
|
||||
if (value !== undefined) {
|
||||
shallowSerializedDescriptor.value = value;
|
||||
}
|
||||
|
||||
return shallowSerializedDescriptor;
|
||||
};
|
||||
|
||||
export const createLevelSerializedDescriptor = (
|
||||
propData: PropData,
|
||||
levelOptions: LevelOptions,
|
||||
continuation: any
|
||||
): Descriptor => {
|
||||
const { type, prop } = propData;
|
||||
|
||||
const levelSerializedDescriptor: Descriptor = {
|
||||
type,
|
||||
editable: true,
|
||||
expandable: Object.keys(prop).length > 0,
|
||||
preview: getDescriptorPreview(propData),
|
||||
};
|
||||
|
||||
if (levelOptions.currentLevel < levelOptions.level) {
|
||||
const value = getLevelDescriptorValue(propData, levelOptions, continuation);
|
||||
if (value !== undefined) {
|
||||
levelSerializedDescriptor.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
return levelSerializedDescriptor;
|
||||
};
|
||||
|
||||
export const createNestedSerializedDescriptor = (
|
||||
propData: PropData,
|
||||
levelOptions: LevelOptions,
|
||||
nodes: NestedProp[],
|
||||
nestedSerializer: any
|
||||
): Descriptor => {
|
||||
const { type, prop } = propData;
|
||||
|
||||
const nestedSerializedDescriptor: Descriptor = {
|
||||
type,
|
||||
editable: true,
|
||||
expandable: Object.keys(prop).length > 0,
|
||||
preview: getDescriptorPreview(propData),
|
||||
};
|
||||
|
||||
if (nodes && nodes.length) {
|
||||
const value = getNestedDescriptorValue(propData, levelOptions, nodes, nestedSerializer);
|
||||
if (value !== undefined) {
|
||||
nestedSerializedDescriptor.value = value;
|
||||
}
|
||||
}
|
||||
return nestedSerializedDescriptor;
|
||||
};
|
||||
|
||||
const getDataByType = (type: PropType, valueByType: CommonTypeCases, defaultValue?: any) => {
|
||||
try {
|
||||
switch (type) {
|
||||
case PropType.Array:
|
||||
return valueByType.arrayCase();
|
||||
case PropType.BigInt:
|
||||
return valueByType.bigIntCase();
|
||||
case PropType.Boolean:
|
||||
return valueByType.booleanCase();
|
||||
case PropType.String:
|
||||
return valueByType.stringCase();
|
||||
case PropType.Function:
|
||||
return valueByType.functionCase();
|
||||
case PropType.Date:
|
||||
return valueByType.dateCase();
|
||||
case PropType.HTMLElement:
|
||||
return valueByType.htmlElementCase();
|
||||
case PropType.Null:
|
||||
return valueByType.nullCase();
|
||||
case PropType.Number:
|
||||
return valueByType.numberCase();
|
||||
case PropType.Object:
|
||||
return valueByType.objectCase();
|
||||
case PropType.Symbol:
|
||||
return valueByType.symbolCase();
|
||||
case PropType.Undefined:
|
||||
return valueByType.undefinedCase();
|
||||
case PropType.Unknown:
|
||||
return valueByType.unknownCase();
|
||||
}
|
||||
} catch {
|
||||
return defaultValue;
|
||||
}
|
||||
};
|
||||
|
||||
const getDescriptorPreview = (propData: PropData) => {
|
||||
const { type, prop } = propData;
|
||||
|
||||
return getDataByType(
|
||||
type,
|
||||
{
|
||||
arrayCase: () => `Array(${prop.length})`,
|
||||
bigIntCase: () => truncate(prop.toString()),
|
||||
booleanCase: () => truncate(prop.toString()),
|
||||
stringCase: () => `"${prop}"`,
|
||||
functionCase: () => `${prop.name}(...)`,
|
||||
htmlElementCase: () => prop.constructor.name,
|
||||
nullCase: () => 'null',
|
||||
numberCase: () => parseInt(prop, 10).toString(),
|
||||
objectCase: () => (Object.keys(prop).length > 0 ? '{...}' : '{}'),
|
||||
symbolCase: () => 'Symbol()',
|
||||
undefinedCase: () => 'undefined',
|
||||
unknownCase: () => 'unknown',
|
||||
},
|
||||
''
|
||||
);
|
||||
};
|
||||
|
||||
const getShallowDescriptorValue = (propData: PropData) => {
|
||||
const { type, prop } = propData;
|
||||
|
||||
return getDataByType(
|
||||
type,
|
||||
{
|
||||
bigIntCase: () => prop,
|
||||
booleanCase: () => prop,
|
||||
stringCase: () => prop,
|
||||
dateCase: () => prop,
|
||||
numberCase: () => prop,
|
||||
},
|
||||
undefined
|
||||
);
|
||||
};
|
||||
|
||||
const getNestedDescriptorValue = (
|
||||
propData: PropData,
|
||||
levelOptions: LevelOptions,
|
||||
nodes: NestedProp[],
|
||||
nestedSerializer: any
|
||||
) => {
|
||||
const { type, prop } = propData;
|
||||
const { currentLevel } = levelOptions;
|
||||
|
||||
return getDataByType(type, {
|
||||
arrayCase: () =>
|
||||
nodes.map(nestedProp => nestedSerializer(prop[nestedProp.name], nestedProp.children, currentLevel + 1)),
|
||||
objectCase: () =>
|
||||
nodes.reduce((accumulator, nestedProp) => {
|
||||
if (
|
||||
prop.hasOwnProperty(nestedProp.name) &&
|
||||
typeof nestedProp.name === 'string' &&
|
||||
!ignoreList.has(nestedProp.name)
|
||||
) {
|
||||
accumulator[nestedProp.name] = nestedSerializer(prop[nestedProp.name], nestedProp.children, currentLevel + 1);
|
||||
}
|
||||
return accumulator;
|
||||
}, {}),
|
||||
});
|
||||
};
|
||||
|
||||
const getLevelDescriptorValue = (propData: PropData, levelOptions: LevelOptions, continuation: any) => {
|
||||
const { type, prop } = propData;
|
||||
const { currentLevel, level } = levelOptions;
|
||||
|
||||
return getDataByType(type, {
|
||||
arrayCase: () => prop.map((nested: any, idx: number) => continuation(nested, idx, currentLevel + 1, level)),
|
||||
objectCase: () =>
|
||||
Object.keys(prop).reduce((accumulator, propName) => {
|
||||
if (typeof propName === 'string' && !ignoreList.has(propName)) {
|
||||
accumulator[propName] = continuation(prop[propName], propName, currentLevel + 1, level);
|
||||
}
|
||||
return accumulator;
|
||||
}, {}),
|
||||
});
|
||||
};
|
||||
|
||||
const truncate = (str: string, max = 20): string => {
|
||||
if (str.length > max) {
|
||||
return str.substr(0, max) + '...';
|
||||
}
|
||||
return str;
|
||||
};
|
||||
|
|
@ -0,0 +1,132 @@
|
|||
import { Descriptor, NestedProp, PropType } from 'protocol';
|
||||
import {
|
||||
createLevelSerializedDescriptor,
|
||||
createNestedSerializedDescriptor,
|
||||
createShallowSerializedDescriptor,
|
||||
} from './serialized-descriptor-factory';
|
||||
|
||||
const ignoreList = new Set(['__ngContext__', '__ngSimpleChanges__']);
|
||||
|
||||
const commonTypes = {
|
||||
boolean: PropType.Boolean,
|
||||
bigint: PropType.BigInt,
|
||||
function: PropType.Function,
|
||||
number: PropType.Number,
|
||||
string: PropType.String,
|
||||
symbol: PropType.Symbol,
|
||||
};
|
||||
|
||||
const MAX_LEVEL = 1;
|
||||
|
||||
const getPropType = (prop: any): PropType => {
|
||||
if (prop === undefined) {
|
||||
return PropType.Undefined;
|
||||
}
|
||||
if (prop === null) {
|
||||
return PropType.Null;
|
||||
}
|
||||
if (prop instanceof HTMLElement) {
|
||||
return PropType.HTMLElement;
|
||||
}
|
||||
const type = typeof prop;
|
||||
if (commonTypes[type] !== undefined) {
|
||||
return commonTypes[type];
|
||||
}
|
||||
if (type === 'object') {
|
||||
if (Array.isArray(prop)) {
|
||||
return PropType.Array;
|
||||
} else if (Object.prototype.toString.call(prop) === '[object Date]') {
|
||||
return PropType.Date;
|
||||
} else {
|
||||
return PropType.Object;
|
||||
}
|
||||
}
|
||||
return PropType.Unknown;
|
||||
};
|
||||
|
||||
export const nestedSerializer = (
|
||||
serializableInstance: any,
|
||||
nodes: NestedProp[],
|
||||
currentLevel = 0,
|
||||
level = MAX_LEVEL
|
||||
): Descriptor => {
|
||||
const type: PropType = getPropType(serializableInstance);
|
||||
const propData = { prop: serializableInstance, type };
|
||||
const levelOptions = { level, currentLevel };
|
||||
|
||||
if (currentLevel < level) {
|
||||
return levelSerializer(
|
||||
serializableInstance,
|
||||
undefined,
|
||||
currentLevel,
|
||||
level,
|
||||
nestedSerializerContinuation(nodes, level)
|
||||
);
|
||||
}
|
||||
|
||||
if (type === PropType.Array || type === PropType.Object) {
|
||||
return createNestedSerializedDescriptor(propData, levelOptions, nodes, nestedSerializer);
|
||||
}
|
||||
|
||||
return createShallowSerializedDescriptor(propData);
|
||||
};
|
||||
|
||||
const nestedSerializerContinuation = (nodes: NestedProp[], level: number) => (
|
||||
nestedProp: any,
|
||||
propName: string | number | undefined,
|
||||
nestedLevel: number
|
||||
) => {
|
||||
const idx = nodes.findIndex(v => v.name === propName);
|
||||
if (idx < 0) {
|
||||
// The property is not specified in the query.
|
||||
return nestedSerializer(nestedProp, [], nestedLevel, level);
|
||||
}
|
||||
return nestedSerializer(nestedProp, nodes[idx].children, nestedLevel, level);
|
||||
};
|
||||
|
||||
export const levelSerializer = (
|
||||
serializableInstance: any,
|
||||
_: string | number | undefined = undefined,
|
||||
currentLevel = 0,
|
||||
level = MAX_LEVEL,
|
||||
continuation = levelSerializer
|
||||
): Descriptor => {
|
||||
const type = getPropType(serializableInstance);
|
||||
const propData = { prop: serializableInstance, type };
|
||||
const levelOptions = { level, currentLevel };
|
||||
|
||||
if (type === PropType.Array || type === PropType.Object) {
|
||||
return createLevelSerializedDescriptor(propData, levelOptions, continuation);
|
||||
}
|
||||
|
||||
return createShallowSerializedDescriptor(propData);
|
||||
};
|
||||
|
||||
export const serializeComponentState = (instance: object, levels = MAX_LEVEL): { [key: string]: Descriptor } => {
|
||||
const result = {};
|
||||
for (const prop in instance) {
|
||||
if (instance.hasOwnProperty(prop) && !ignoreList.has(prop)) {
|
||||
result[prop] = levelSerializer(instance[prop], null, 0, levels);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
export const deeplySerializeSelectedProperties = (
|
||||
instance: any,
|
||||
props: NestedProp[]
|
||||
): { [name: string]: Descriptor } => {
|
||||
const result = {};
|
||||
Object.keys(instance).forEach(propName => {
|
||||
if (ignoreList.has(propName)) {
|
||||
return;
|
||||
}
|
||||
const idx = props.findIndex(v => v.name === propName);
|
||||
if (idx < 0) {
|
||||
result[propName] = levelSerializer(instance[propName]);
|
||||
} else {
|
||||
result[propName] = nestedSerializer(instance[propName], props[idx].children);
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
Loading…
Reference in a new issue