• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1/*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15class stateMgmtDFX {
16  // enable profile
17  public static enableProfiler: boolean = false;
18  public static inRenderingElementId: Array<number> = new Array<number>();
19  private static readonly DUMP_MAX_PROPERTY_COUNT: number = 50;
20  private static readonly DUMP_MAX_LENGTH: number = 10;
21  private static readonly DUMP_LAST_LENGTH: number = 3;
22
23  public static getObservedPropertyInfo<T>(observedProp: ObservedPropertyAbstractPU<T>, isProfiler: boolean,
24    changedTrackPropertyName?: string): ObservedPropertyInfo<T> {
25    return {
26      decorator: observedProp.debugInfoDecorator(), propertyName: observedProp.info(), id: observedProp.id__(),
27      changedTrackPropertyName: changedTrackPropertyName,
28      value: stateMgmtDFX.getRawValue(observedProp),
29      inRenderingElementId: stateMgmtDFX.inRenderingElementId.length === 0 ?
30        -1 : stateMgmtDFX.inRenderingElementId[stateMgmtDFX.inRenderingElementId.length - 1],
31      dependentElementIds: observedProp.dumpDependentElmtIdsObj(typeof observedProp.getUnmonitored() === 'object' ?
32        !TrackedObject.isCompatibilityMode(observedProp.getUnmonitored()) : false, isProfiler),
33      owningView: observedProp.getOwningView(),
34      length: stateMgmtDFX.getRawValueLength(observedProp),
35      syncPeers: observedProp.dumpSyncPeers(isProfiler, changedTrackPropertyName)
36    };
37  }
38
39  private static getType(item: RawValue): string {
40    try {
41      return Object.prototype.toString.call(item);
42    } catch (e) {
43      stateMgmtConsole.warn(`Cannot get the type of current value, error message is: ${e.message}`);
44      return 'unknown type';
45    }
46  }
47
48  /**
49   * Dump 10 items at most.
50   * If length > 10, the output will be the first 7 and last 3 items.
51   * eg: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
52   * output: [0, 1, 2, 3, 4, 5, 6, '...', 9, 10, 11]
53   *
54   */
55  private static dumpItems(arr: Array<RawValue>): Array<DumpBuildInType> {
56    let dumpArr = arr.slice(0, stateMgmtDFX.DUMP_MAX_LENGTH);
57    if (arr.length > stateMgmtDFX.DUMP_MAX_LENGTH) {
58      dumpArr.splice(stateMgmtDFX.DUMP_MAX_LENGTH - stateMgmtDFX.DUMP_LAST_LENGTH, stateMgmtDFX.DUMP_LAST_LENGTH, '...', ...arr.slice(-stateMgmtDFX.DUMP_LAST_LENGTH));
59    }
60    return dumpArr.map(item => typeof item === 'object' ? this.getType(item) : item);
61  }
62
63  private static dumpMap(map: Map<RawValue, RawValue>): Array<DumpBuildInType> {
64    let dumpKey = this.dumpItems(Array.from(map.keys()));
65    let dumpValue = this.dumpItems(Array.from(map.values()));
66    return dumpKey.map((item: any, index: number) => [item, dumpValue[index]]);
67  }
68
69  private static dumpObjectProperty(value: any): DumpObjectType | string {
70    let tempObj: DumpObjectType = {};
71    try {
72      let properties: string[] = Object.getOwnPropertyNames(value);
73      properties
74        .slice(0, stateMgmtDFX.DUMP_MAX_PROPERTY_COUNT)
75        .forEach((varName: string) => {
76          const propertyValue = Reflect.get(value as Object, varName);
77          tempObj[varName] = typeof propertyValue === 'object' ? this.getType(propertyValue) : propertyValue;
78        });
79      if (properties.length > stateMgmtDFX.DUMP_MAX_PROPERTY_COUNT) {
80        tempObj['...'] = '...';
81      }
82    } catch (e) {
83      stateMgmtConsole.warn(`can not dump Obj, error msg ${e.message}`);
84      return 'unknown type';
85    }
86    return tempObj;
87  }
88
89  private static getRawValue<T>(observedProp: ObservedPropertyAbstractPU<T>): DumpObjectType | Array<DumpBuildInType> | T | string {
90    let wrappedValue: T = observedProp.getUnmonitored();
91    if (typeof wrappedValue !== 'object') {
92      return wrappedValue;
93    }
94    let rawObject: T = ObservedObject.GetRawObject(wrappedValue);
95    if (rawObject instanceof Map) {
96      return stateMgmtDFX.dumpMap(rawObject);
97    } else if (rawObject instanceof Set) {
98      return stateMgmtDFX.dumpItems(Array.from(rawObject.values()));
99    } else if (rawObject instanceof Array) {
100      return stateMgmtDFX.dumpItems(Array.from(rawObject));
101    } else if (rawObject instanceof Date) {
102      return rawObject;
103    } else {
104      return stateMgmtDFX.dumpObjectProperty(rawObject);
105    }
106  }
107
108  private static getRawValueLength<T>(observedProp: ObservedPropertyAbstractPU<T>): number {
109    let wrappedValue: T = observedProp.getUnmonitored();
110    if (typeof wrappedValue !== 'object') {
111      return -1;
112    }
113    let rawObject: T = ObservedObject.GetRawObject(wrappedValue);
114    if (rawObject instanceof Map || rawObject instanceof Set) {
115     return rawObject.size;
116    } else if (rawObject instanceof Array) {
117      return rawObject.length;
118    }
119    try {
120      return Object.getOwnPropertyNames(rawObject).length;
121    } catch (e) {
122      return -1;
123    }
124  }
125}
126
127function setProfilerStatus(profilerStatus: boolean): void {
128  stateMgmtConsole.warn(`${profilerStatus ? `start` : `stop`} stateMgmt Profiler`);
129  stateMgmtDFX.enableProfiler = profilerStatus;
130}
131type PropertyDependenciesInfo = {
132  mode: string,
133  trackPropertiesDependencies: MapItem<string, Array<ElementType | number | string>>[],
134  propertyDependencies: Array<ElementType>
135}
136
137type ElementType = {
138  elementId: number,
139  elementTag: string,
140  isCustomNode: boolean,
141}
142
143// Data struct send to profiler or Inspector
144type ViewPUInfo = { componentName: string, id: number };
145type ObservedPropertyInfo<T> = {
146  decorator: string, propertyName: string, value: any, id: number, changeId?: number, inRenderingElementId?: number,
147  changedTrackPropertyName?: string | undefined,
148  dependentElementIds: PropertyDependenciesInfo,
149  length?: number
150  owningView?: ViewPUInfo, syncPeers?: ObservedPropertyInfo<T>[]
151};
152
153type SimpleType = string | number | boolean;
154type DumpObjectType = Record<string, SimpleType>;
155type DumpBuildInType = Array<SimpleType> | Array<[SimpleType, SimpleType]>;
156type RawValue = any;
157
158class DumpInfo {
159  public viewInfo?: ViewPUInfo;
160  public observedPropertiesInfo: ObservedPropertyInfo<any>[] = []
161}
162
163// global function used to throw error in Promise
164declare function _arkUIUncaughtPromiseError(error: any);