@routier/core 0.0.6 → 0.1.0-rc.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/capabilities/Capability.d.ts +6 -16
- package/dist/capabilities/PerformanceCapability.d.ts +4 -6
- package/dist/capabilities/TracingCapability.d.ts +3 -6
- package/dist/capabilities/index.js +399 -343
- package/dist/capabilities/index.js.map +1 -1
- package/dist/capabilities/types.d.ts +10 -19
- package/dist/codegen/blocks.d.ts +8 -0
- package/dist/codegen/handlers/CompareIdsHandlerBuilder.d.ts +4 -0
- package/dist/codegen/handlers/compare/CompareArrayHandler.d.ts +6 -0
- package/dist/codegen/handlers/compare/CompareDateHandler.d.ts +6 -0
- package/dist/codegen/handlers/compareIds/CompareIdsKeyHandler.d.ts +6 -0
- package/dist/codegen/handlers/index.d.ts +1 -0
- package/dist/codegen/handlers/serialize/SerializeDateHandler.d.ts +2 -1
- package/dist/codegen/handlers/serialize/SerializeFunctionHandler.d.ts +6 -0
- package/dist/codegen/index.js +39 -0
- package/dist/codegen/index.js.map +1 -1
- package/dist/collections/index.js +1 -1
- package/dist/collections/index.js.map +1 -1
- package/dist/expressions/index.js +203 -29
- package/dist/expressions/index.js.map +1 -1
- package/dist/index.js +1147 -507
- package/dist/index.js.map +1 -1
- package/dist/pipeline/TrampolinePipeline.d.ts +1 -0
- package/dist/pipeline/index.js +71 -47
- package/dist/pipeline/index.js.map +1 -1
- package/dist/plugins/EphemeralDataPlugin.d.ts +2 -2
- package/dist/plugins/index.js +252 -62
- package/dist/plugins/index.js.map +1 -1
- package/dist/plugins/query/types.d.ts +5 -0
- package/dist/plugins/replication/OptimisticReplicationDbPlugin.d.ts +2 -1
- package/dist/plugins/replication/ReplicationDbPlugin.d.ts +2 -1
- package/dist/plugins/translators/DataTranslator.d.ts +3 -1
- package/dist/plugins/translators/JsonTranslator.d.ts +1 -0
- package/dist/plugins/translators/SqlTranslator.d.ts +1 -0
- package/dist/plugins/translators/TranslatedArrayValue.d.ts +6 -0
- package/dist/plugins/translators/TranslatedGroupValue.d.ts +6 -0
- package/dist/plugins/translators/TranslatedSingleValue.d.ts +6 -0
- package/dist/plugins/translators/index.d.ts +4 -0
- package/dist/plugins/translators/types.d.ts +10 -0
- package/dist/plugins/types.d.ts +2 -1
- package/dist/schema/PropertyInfo.d.ts +7 -2
- package/dist/schema/SchemaDefinition.d.ts +1 -1
- package/dist/schema/communication/broadcast.d.ts +3 -3
- package/dist/schema/index.js +504 -73
- package/dist/schema/index.js.map +1 -1
- package/dist/schema/property/modifiers/SchemaTracked.d.ts +3 -1
- package/dist/schema/table/SchemaComputed.d.ts +1 -1
- package/dist/schema/testSchemas.test.d.ts +60 -36
- package/dist/schema/types.d.ts +16 -1
- package/dist/utilities/index.d.ts +1 -0
- package/dist/utilities/index.js +164 -2
- package/dist/utilities/index.js.map +1 -1
- package/dist/utilities/strings.d.ts +34 -0
- package/dist/utilities/strings.test.d.ts +1 -0
- package/dist/utilities/unsafeCast.d.ts +1 -0
- package/package.json +1 -1
- package/readme.md +1 -1
|
@@ -9,214 +9,103 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
9
9
|
Capability: () => (Capability)
|
|
10
10
|
});
|
|
11
11
|
class Capability {
|
|
12
|
+
excludedNames = new Set([
|
|
13
|
+
"Array",
|
|
14
|
+
"Set",
|
|
15
|
+
"Map",
|
|
16
|
+
"AbortController",
|
|
17
|
+
"AbortSignal",
|
|
18
|
+
"SchemaString",
|
|
19
|
+
"SchemaNumber",
|
|
20
|
+
"SchemaArray",
|
|
21
|
+
"SchemaBoolean",
|
|
22
|
+
"SchemaDate",
|
|
23
|
+
"SchemaObject",
|
|
24
|
+
"SchemaDefault",
|
|
25
|
+
"SchemaDeserialize",
|
|
26
|
+
"SchemaDistinct",
|
|
27
|
+
"SchemaFrom",
|
|
28
|
+
"SchemaIdentity",
|
|
29
|
+
"SchemaIndex",
|
|
30
|
+
"SchemaKey",
|
|
31
|
+
"SchemaNullable",
|
|
32
|
+
"SchemaOptional",
|
|
33
|
+
"SchemaReadonly",
|
|
34
|
+
"SchemaSerialize",
|
|
35
|
+
"SchemaTracked",
|
|
36
|
+
"SchemaComputed",
|
|
37
|
+
"SchemaFunction",
|
|
38
|
+
"SchemaBase",
|
|
39
|
+
"SchemaDefinition"
|
|
40
|
+
]);
|
|
12
41
|
isValidObject(obj) {
|
|
13
42
|
return typeof obj === "object" && obj !== null;
|
|
14
43
|
}
|
|
15
|
-
getObjectName(obj) {
|
|
16
|
-
return obj?.constructor?.name || 'root';
|
|
17
|
-
}
|
|
18
|
-
exploreObjectMethods(obj, callback, options = {}) {
|
|
19
|
-
if (!this.isValidObject(obj)) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const { maxDepth = 10, includeNonEnumerable = false, filter = () => true } = options;
|
|
23
|
-
const rootName = this.getObjectName(obj);
|
|
24
|
-
const visited = new Set();
|
|
25
|
-
// Explore root methods
|
|
26
|
-
this.exploreRootMethods(obj, callback, filter);
|
|
27
|
-
// Explore nested methods
|
|
28
|
-
this.exploreNestedMethods(obj, callback, filter, [rootName], visited, maxDepth, includeNonEnumerable);
|
|
29
|
-
}
|
|
30
|
-
exploreRootMethods(obj, callback, filter) {
|
|
31
|
-
const methodNames = this.extractMethodNames(obj);
|
|
32
|
-
for (const methodName of methodNames) {
|
|
33
|
-
const methodInfo = {
|
|
34
|
-
methodName,
|
|
35
|
-
instance: obj,
|
|
36
|
-
methodPath: [String(methodName)],
|
|
37
|
-
parent: null
|
|
38
|
-
};
|
|
39
|
-
if (filter(methodInfo)) {
|
|
40
|
-
callback(methodInfo);
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
}
|
|
44
|
-
extractMethodNames(obj) {
|
|
45
|
-
const methodNames = new Set();
|
|
46
|
-
let prototype = obj;
|
|
47
|
-
while (prototype && prototype !== Object.prototype) {
|
|
48
|
-
const allKeys = [
|
|
49
|
-
...Object.getOwnPropertyNames(prototype),
|
|
50
|
-
...Object.getOwnPropertySymbols(prototype),
|
|
51
|
-
];
|
|
52
|
-
for (const key of allKeys) {
|
|
53
|
-
const descriptor = Object.getOwnPropertyDescriptor(prototype, key);
|
|
54
|
-
if (this.isCallableMethod(descriptor, key)) {
|
|
55
|
-
methodNames.add(key);
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
prototype = Object.getPrototypeOf(prototype);
|
|
59
|
-
}
|
|
60
|
-
return Array.from(methodNames);
|
|
61
|
-
}
|
|
62
44
|
isCallableMethod(descriptor, key) {
|
|
63
45
|
return (descriptor?.value &&
|
|
64
46
|
typeof descriptor.value === 'function' &&
|
|
65
47
|
key !== 'constructor' &&
|
|
66
48
|
key !== 'undefined');
|
|
67
49
|
}
|
|
68
|
-
|
|
69
|
-
if (
|
|
50
|
+
canExplore(descriptor) {
|
|
51
|
+
if (typeof descriptor.value !== "object") {
|
|
70
52
|
return false;
|
|
71
53
|
}
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
// Caveat: Symbol.toStringTag can spoof this.
|
|
75
|
-
return objectTag === "[object Object]";
|
|
76
|
-
}
|
|
77
|
-
shouldProcessProperty(property) {
|
|
78
|
-
return (this.isCustomClassInstance(property) &&
|
|
79
|
-
property?.constructor.name !== "Object");
|
|
80
|
-
}
|
|
81
|
-
exploreNestedMethods(obj, callback, filter, initialPath, visited, maxDepth, includeNonEnumerable) {
|
|
82
|
-
if (visited.has(obj) || initialPath.length > maxDepth) {
|
|
83
|
-
return;
|
|
84
|
-
}
|
|
85
|
-
visited.add(obj);
|
|
86
|
-
if (!this.isValidObject(obj)) {
|
|
87
|
-
return;
|
|
54
|
+
if (descriptor.value == null) {
|
|
55
|
+
return false;
|
|
88
56
|
}
|
|
89
|
-
const
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
for (const propertyName of properties) {
|
|
93
|
-
const property = obj[propertyName];
|
|
94
|
-
if (!this.shouldProcessProperty(property)) {
|
|
95
|
-
continue;
|
|
96
|
-
}
|
|
97
|
-
const newPath = [...initialPath, propertyName];
|
|
98
|
-
// Explore methods on this property
|
|
99
|
-
this.explorePropertyMethods(property, callback, filter, newPath, obj);
|
|
100
|
-
// Recursively explore nested objects
|
|
101
|
-
this.exploreNestedMethods(property, callback, filter, newPath, visited, maxDepth, includeNonEnumerable);
|
|
57
|
+
const name = this.getName(descriptor.value);
|
|
58
|
+
if (name == null) {
|
|
59
|
+
return true;
|
|
102
60
|
}
|
|
61
|
+
return this.excludedNames.has(name) === false;
|
|
103
62
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
const fullMethodPath = [...methodPath, String(methodName)];
|
|
108
|
-
const methodInfo = {
|
|
109
|
-
methodName,
|
|
110
|
-
instance: property,
|
|
111
|
-
methodPath: fullMethodPath,
|
|
112
|
-
parent
|
|
113
|
-
};
|
|
114
|
-
if (filter(methodInfo)) {
|
|
115
|
-
callback(methodInfo);
|
|
116
|
-
}
|
|
63
|
+
getName(value) {
|
|
64
|
+
if (value.constructor != null) {
|
|
65
|
+
return value.constructor.name;
|
|
117
66
|
}
|
|
67
|
+
return null;
|
|
118
68
|
}
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
switch (type) {
|
|
126
|
-
case 'string':
|
|
127
|
-
return `"${value}"`;
|
|
128
|
-
case 'number':
|
|
129
|
-
case 'boolean':
|
|
130
|
-
return String(value);
|
|
131
|
-
case 'function':
|
|
132
|
-
return `[Function: ${this.getFunctionName(value)}]`;
|
|
133
|
-
case 'object':
|
|
134
|
-
if (currentDepth >= maxDepth) {
|
|
135
|
-
return '[Max Depth Reached]';
|
|
136
|
-
}
|
|
137
|
-
return this.stringifyObject(value, maxDepth, currentDepth);
|
|
138
|
-
default:
|
|
139
|
-
return `[${type}]`;
|
|
69
|
+
getPath(info, propertyName) {
|
|
70
|
+
let parent = info.parent;
|
|
71
|
+
const path = [info.propertyName, propertyName];
|
|
72
|
+
while (parent != null) {
|
|
73
|
+
path.unshift(parent.propertyName);
|
|
74
|
+
parent = parent.parent;
|
|
140
75
|
}
|
|
76
|
+
return path.join(".");
|
|
141
77
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
}
|
|
146
|
-
stringifyObject(obj, maxDepth, currentDepth) {
|
|
147
|
-
if (obj === null)
|
|
148
|
-
return 'null';
|
|
149
|
-
// Handle special object types
|
|
150
|
-
if (obj instanceof Date) {
|
|
151
|
-
return `Date(${obj.toISOString()})`;
|
|
152
|
-
}
|
|
153
|
-
if (obj instanceof Error) {
|
|
154
|
-
return `Error(${obj.message})`;
|
|
155
|
-
}
|
|
156
|
-
if (obj instanceof RegExp) {
|
|
157
|
-
return obj.toString();
|
|
158
|
-
}
|
|
159
|
-
if (Array.isArray(obj)) {
|
|
160
|
-
return this.stringifyArray(obj, maxDepth, currentDepth);
|
|
161
|
-
}
|
|
162
|
-
if (obj.constructor && obj.constructor.name !== 'Object') {
|
|
163
|
-
return this.stringifyClassInstance(obj, maxDepth, currentDepth);
|
|
164
|
-
}
|
|
165
|
-
return this.stringifyPlainObject(obj, maxDepth, currentDepth);
|
|
166
|
-
}
|
|
167
|
-
stringifyArray(arr, maxDepth, currentDepth) {
|
|
168
|
-
if (arr.length === 0)
|
|
169
|
-
return '[]';
|
|
170
|
-
const items = arr.slice(0, 5).map(item => this.stringifyValue(item, maxDepth, currentDepth + 1));
|
|
171
|
-
const suffix = arr.length > 5 ? `... (+${arr.length - 5} more)` : '';
|
|
172
|
-
return `[${items.join(', ')}${suffix}]`;
|
|
173
|
-
}
|
|
174
|
-
stringifyClassInstance(obj, maxDepth, currentDepth) {
|
|
175
|
-
const className = obj.constructor.name;
|
|
176
|
-
const properties = this.getObjectProperties(obj);
|
|
177
|
-
if (Object.keys(properties).length === 0) {
|
|
178
|
-
return `${className} {}`;
|
|
179
|
-
}
|
|
180
|
-
const props = Object.entries(properties)
|
|
181
|
-
.slice(0, 5)
|
|
182
|
-
.map(([key, value]) => {
|
|
183
|
-
// For primitive values, don't increase depth
|
|
184
|
-
const isPrimitive = value === null || value === undefined ||
|
|
185
|
-
(typeof value !== 'object' && typeof value !== 'function');
|
|
186
|
-
const depth = isPrimitive ? currentDepth : currentDepth + 1;
|
|
187
|
-
return `${key}: ${this.stringifyValue(value, maxDepth, depth)}`;
|
|
188
|
-
});
|
|
189
|
-
const suffix = Object.keys(properties).length > 5 ?
|
|
190
|
-
`... (+${Object.keys(properties).length - 5} more)` : '';
|
|
191
|
-
return `${className} { ${props.join(', ')}${suffix} }`;
|
|
192
|
-
}
|
|
193
|
-
stringifyPlainObject(obj, maxDepth, currentDepth) {
|
|
194
|
-
const properties = this.getObjectProperties(obj);
|
|
195
|
-
if (Object.keys(properties).length === 0) {
|
|
196
|
-
return '{}';
|
|
78
|
+
explore(instance, onDiscover) {
|
|
79
|
+
if (!this.isValidObject(instance)) {
|
|
80
|
+
return;
|
|
197
81
|
}
|
|
198
|
-
const
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
const
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
return `${key}: ${this.stringifyValue(value, maxDepth, depth)}`;
|
|
206
|
-
});
|
|
207
|
-
const suffix = Object.keys(properties).length > 5 ?
|
|
208
|
-
`... (+${Object.keys(properties).length - 5} more)` : '';
|
|
209
|
-
return `{ ${props.join(', ')}${suffix} }`;
|
|
210
|
-
}
|
|
211
|
-
getObjectProperties(obj) {
|
|
212
|
-
const properties = {};
|
|
213
|
-
// Get enumerable properties
|
|
214
|
-
for (const key in obj) {
|
|
215
|
-
if (obj.hasOwnProperty(key)) {
|
|
216
|
-
properties[key] = obj[key];
|
|
82
|
+
const explore = [{ instance, propertyName: this.getName(instance) }];
|
|
83
|
+
const visited = new Set();
|
|
84
|
+
for (let i = 0; i < explore.length; i++) {
|
|
85
|
+
const info = explore[i];
|
|
86
|
+
const item = info.instance;
|
|
87
|
+
if (visited.has(item)) {
|
|
88
|
+
continue;
|
|
217
89
|
}
|
|
90
|
+
const allKeys = [
|
|
91
|
+
...Object.getOwnPropertyNames(item),
|
|
92
|
+
...Object.getOwnPropertySymbols(item),
|
|
93
|
+
];
|
|
94
|
+
for (const key of allKeys) {
|
|
95
|
+
const descriptor = Object.getOwnPropertyDescriptor(item, key);
|
|
96
|
+
const isCallable = this.isCallableMethod(descriptor, key);
|
|
97
|
+
onDiscover(info, {
|
|
98
|
+
name: key,
|
|
99
|
+
isCallable
|
|
100
|
+
});
|
|
101
|
+
if (this.canExplore(descriptor) === false) {
|
|
102
|
+
continue;
|
|
103
|
+
}
|
|
104
|
+
const path = this.getPath(info, key);
|
|
105
|
+
explore.push({ instance: descriptor.value, parent: info, propertyName: key, path });
|
|
106
|
+
}
|
|
107
|
+
visited.add(item);
|
|
218
108
|
}
|
|
219
|
-
return properties;
|
|
220
109
|
}
|
|
221
110
|
}
|
|
222
111
|
|
|
@@ -231,99 +120,134 @@ __webpack_require__.r(__webpack_exports__);
|
|
|
231
120
|
__webpack_require__.d(__webpack_exports__, {
|
|
232
121
|
PerformanceCapability: () => (PerformanceCapability)
|
|
233
122
|
});
|
|
123
|
+
/* ESM import */var _utilities__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ../utilities */ "./src/utilities/strings.ts");
|
|
234
124
|
/* ESM import */var _Capability__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Capability */ "./src/capabilities/Capability.ts");
|
|
235
125
|
/* ESM import */var _performance_PerformanceTracker__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./performance/PerformanceTracker */ "./src/capabilities/performance/PerformanceTracker.ts");
|
|
236
126
|
/* ESM import */var _tracing_CallTraceManager__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tracing/CallTraceManager */ "./src/capabilities/tracing/CallTraceManager.ts");
|
|
237
127
|
|
|
238
128
|
|
|
239
129
|
|
|
130
|
+
|
|
240
131
|
class PerformanceCapability extends _Capability__WEBPACK_IMPORTED_MODULE_0__.Capability {
|
|
241
132
|
callTraceManager;
|
|
242
133
|
performanceTracker;
|
|
243
|
-
|
|
244
|
-
|
|
134
|
+
filter;
|
|
135
|
+
childDurations = new Map();
|
|
245
136
|
constructor(options) {
|
|
246
137
|
super();
|
|
247
|
-
this.
|
|
248
|
-
if (isCompleted) {
|
|
249
|
-
if (!performanceMetrics.duration)
|
|
250
|
-
return;
|
|
251
|
-
const deltaFromStart = this.performanceTracker.getDeltaFromOperationStart(operationId, performanceMetrics.endTime || performanceMetrics.startTime);
|
|
252
|
-
console.log(`[${type} ${operationId}] ${methodName} COMPLETED`, {
|
|
253
|
-
methodPath,
|
|
254
|
-
performance: {
|
|
255
|
-
deltaFromStart: this.performanceTracker.formatDuration(deltaFromStart),
|
|
256
|
-
executionTime: this.performanceTracker.formatDuration(performanceMetrics.duration),
|
|
257
|
-
timeToNextCall: performanceMetrics.timeToNextCall ?
|
|
258
|
-
this.performanceTracker.formatDuration(performanceMetrics.timeToNextCall) : 'N/A'
|
|
259
|
-
}
|
|
260
|
-
});
|
|
261
|
-
return;
|
|
262
|
-
}
|
|
263
|
-
const deltaFromStart = this.performanceTracker.getDeltaFromOperationStart(operationId, performanceMetrics.startTime);
|
|
264
|
-
console.log(`[${type} ${operationId}] ${methodName}`, {
|
|
265
|
-
methodPath,
|
|
266
|
-
performance: {
|
|
267
|
-
deltaFromStart: this.performanceTracker.formatDuration(deltaFromStart)
|
|
268
|
-
}
|
|
269
|
-
});
|
|
270
|
-
});
|
|
271
|
-
this.shouldLog = options?.shouldLog ?? (() => true);
|
|
138
|
+
this.filter = options?.filter ?? (() => true);
|
|
272
139
|
this.callTraceManager = new _tracing_CallTraceManager__WEBPACK_IMPORTED_MODULE_1__.CallTraceManager();
|
|
273
140
|
this.performanceTracker = new _performance_PerformanceTracker__WEBPACK_IMPORTED_MODULE_2__.PerformanceTracker();
|
|
274
141
|
}
|
|
275
|
-
createPerformanceInterceptor(originalMethod, methodName, methodPath, instance) {
|
|
276
|
-
return (...args) => {
|
|
277
|
-
const isNewOperation = this.callTraceManager.isNewOperation();
|
|
278
|
-
let operationId;
|
|
279
|
-
if (isNewOperation) {
|
|
280
|
-
operationId = this.callTraceManager.startNewOperation();
|
|
281
|
-
const startTime = this.performanceTracker.startMethodTiming(operationId, methodPath);
|
|
282
|
-
this.log('ORIGIN', operationId, methodName, methodPath, { startTime }, false);
|
|
283
|
-
}
|
|
284
|
-
else {
|
|
285
|
-
operationId = this.callTraceManager.getActiveOperationId();
|
|
286
|
-
// Record that the previous method is about to call this one
|
|
287
|
-
const callTrace = this.callTraceManager.getCurrentTrace();
|
|
288
|
-
const previousMethodPath = callTrace[callTrace.length - 2];
|
|
289
|
-
if (previousMethodPath) {
|
|
290
|
-
this.performanceTracker.recordNextMethodStart(operationId, previousMethodPath);
|
|
291
|
-
}
|
|
292
|
-
const startTime = this.performanceTracker.startMethodTiming(operationId, methodPath);
|
|
293
|
-
this.log('CHILD', operationId, methodName, methodPath, { startTime }, false);
|
|
294
|
-
}
|
|
295
|
-
try {
|
|
296
|
-
const result = originalMethod.apply(instance, args);
|
|
297
|
-
return result;
|
|
298
|
-
}
|
|
299
|
-
finally {
|
|
300
|
-
// End performance tracking
|
|
301
|
-
const performanceMetrics = this.performanceTracker.endMethodTiming(operationId, methodPath);
|
|
302
|
-
// Log completion with performance metrics
|
|
303
|
-
this.log(isNewOperation ? 'ORIGIN' : 'CHILD', operationId, methodName, methodPath, performanceMetrics, true);
|
|
304
|
-
if (isNewOperation) {
|
|
305
|
-
this.callTraceManager.endOperation();
|
|
306
|
-
this.performanceTracker.cleanupOperation(operationId);
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
};
|
|
310
|
-
}
|
|
311
142
|
apply(instance) {
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
143
|
+
this.explore(instance, (meta, info) => {
|
|
144
|
+
if (info.isCallable) {
|
|
145
|
+
const originalMethod = meta.instance[info.name].bind(meta.instance);
|
|
146
|
+
meta.instance[info.name] = (...args) => {
|
|
147
|
+
const path = `${meta.path}.${String(info.name)}()`;
|
|
148
|
+
if (this.filter(path, info, meta) === false) {
|
|
149
|
+
return originalMethod(...args);
|
|
150
|
+
}
|
|
151
|
+
const isNewOperation = this.callTraceManager.isNewOperation();
|
|
152
|
+
let operationId;
|
|
153
|
+
let callTrace;
|
|
154
|
+
let depth;
|
|
155
|
+
if (isNewOperation) {
|
|
156
|
+
operationId = this.callTraceManager.startNewOperation();
|
|
157
|
+
this.childDurations.set(operationId, []);
|
|
158
|
+
callTrace = this.callTraceManager.addMethodToTrace(path);
|
|
159
|
+
depth = callTrace.length - 1;
|
|
160
|
+
const formattedCallTrace = this.callTraceManager.formatMethodPaths(callTrace);
|
|
161
|
+
this.performanceTracker.startMethodTiming(operationId, path);
|
|
162
|
+
console.log(`\n${'═'.repeat(60)}`);
|
|
163
|
+
console.log(`▶ ORIGIN [${operationId}] ${path}`);
|
|
164
|
+
if (args.length > 0) {
|
|
165
|
+
console.log(` Args:`, (0,_utilities__WEBPACK_IMPORTED_MODULE_3__.stringifyObject)(args, 4, 0));
|
|
166
|
+
}
|
|
167
|
+
console.log(` Call Stack: ${formattedCallTrace.join(' → ')}`);
|
|
168
|
+
}
|
|
169
|
+
else {
|
|
170
|
+
operationId = this.callTraceManager.getActiveOperationId();
|
|
171
|
+
callTrace = this.callTraceManager.addMethodToTrace(path);
|
|
172
|
+
depth = callTrace.length - 1;
|
|
173
|
+
const indent = ' '.repeat(Math.min(depth, 4));
|
|
174
|
+
// Track children for this child method too
|
|
175
|
+
const childMethodKey = `${operationId}:${path}`;
|
|
176
|
+
this.childDurations.set(childMethodKey, []);
|
|
177
|
+
this.performanceTracker.startMethodTiming(operationId, path);
|
|
178
|
+
console.log(`${indent}└─ CHILD [${operationId}] ${path}`);
|
|
179
|
+
if (args.length > 0) {
|
|
180
|
+
console.log(`${indent} Args:`, (0,_utilities__WEBPACK_IMPORTED_MODULE_3__.stringifyObject)(args, 4, 0));
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
try {
|
|
184
|
+
return originalMethod(...args);
|
|
185
|
+
}
|
|
186
|
+
finally {
|
|
187
|
+
const metrics = this.performanceTracker.endMethodTiming(operationId, path);
|
|
188
|
+
const duration = metrics.duration ?? 0;
|
|
189
|
+
const formattedDuration = this.performanceTracker.formatDuration(duration);
|
|
190
|
+
if (isNewOperation) {
|
|
191
|
+
const childDurations = this.childDurations.get(operationId) ?? [];
|
|
192
|
+
const totalChildTime = childDurations.reduce((sum, d) => sum + d, 0);
|
|
193
|
+
const formattedTotalChildTime = this.performanceTracker.formatDuration(totalChildTime);
|
|
194
|
+
const overhead = duration - totalChildTime;
|
|
195
|
+
const formattedOverhead = this.performanceTracker.formatDuration(Math.max(0, overhead));
|
|
196
|
+
console.log(`\n${'═'.repeat(60)}`);
|
|
197
|
+
console.log(`◀ COMPLETE [${operationId}] ${path}`);
|
|
198
|
+
console.log(` Total Duration: ${formattedDuration}`);
|
|
199
|
+
if (childDurations.length > 0) {
|
|
200
|
+
console.log(` Children Duration: ${formattedTotalChildTime} (${childDurations.length} calls)`);
|
|
201
|
+
console.log(` Overhead: ${formattedOverhead}`);
|
|
202
|
+
}
|
|
203
|
+
console.log(`${'═'.repeat(60)}\n`);
|
|
204
|
+
this.childDurations.delete(operationId);
|
|
205
|
+
this.performanceTracker.cleanupOperation(operationId);
|
|
206
|
+
this.callTraceManager.endOperation();
|
|
207
|
+
}
|
|
208
|
+
else {
|
|
209
|
+
const indent = ' '.repeat(Math.min(depth, 4));
|
|
210
|
+
const childMethodKey = `${operationId}:${path}`;
|
|
211
|
+
const childDurations = this.childDurations.get(childMethodKey) ?? [];
|
|
212
|
+
const totalChildTime = childDurations.reduce((sum, d) => sum + d, 0);
|
|
213
|
+
const formattedTotalChildTime = this.performanceTracker.formatDuration(totalChildTime);
|
|
214
|
+
const overhead = duration - totalChildTime;
|
|
215
|
+
const formattedOverhead = this.performanceTracker.formatDuration(Math.max(0, overhead));
|
|
216
|
+
console.log(`${indent} ✓ ${formattedDuration}`);
|
|
217
|
+
if (childDurations.length > 0) {
|
|
218
|
+
console.log(`${indent} Children: ${formattedTotalChildTime} (${childDurations.length} calls), Overhead: ${formattedOverhead}`);
|
|
219
|
+
}
|
|
220
|
+
// Clean up child method tracking
|
|
221
|
+
this.childDurations.delete(childMethodKey);
|
|
222
|
+
// Find the parent method and add this duration to its children list
|
|
223
|
+
// The parent is the method one level up in the call trace
|
|
224
|
+
const currentTrace = this.callTraceManager.getCurrentTrace();
|
|
225
|
+
if (currentTrace.length > 1) {
|
|
226
|
+
// Parent is the second-to-last item in the trace (before we remove current)
|
|
227
|
+
const parentPath = currentTrace[currentTrace.length - 2];
|
|
228
|
+
// Check if parent is the root operation (trace length 2 means root + this child)
|
|
229
|
+
if (currentTrace.length === 2) {
|
|
230
|
+
// Direct child of root - add to root's children list
|
|
231
|
+
const rootChildDurations = this.childDurations.get(operationId);
|
|
232
|
+
if (rootChildDurations) {
|
|
233
|
+
rootChildDurations.push(duration);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
else {
|
|
237
|
+
// Nested child - add to parent method's children list
|
|
238
|
+
const parentMethodKey = `${operationId}:${parentPath}`;
|
|
239
|
+
const parentChildDurations = this.childDurations.get(parentMethodKey);
|
|
240
|
+
if (parentChildDurations) {
|
|
241
|
+
parentChildDurations.push(duration);
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
this.callTraceManager.removeMethodFromTrace();
|
|
247
|
+
}
|
|
248
|
+
};
|
|
319
249
|
}
|
|
320
|
-
};
|
|
321
|
-
// Use the generic interception utility
|
|
322
|
-
this.exploreObjectMethods(instance, (methodInfo) => {
|
|
323
|
-
const originalMethod = methodInfo.instance[methodInfo.methodName].bind(methodInfo.instance);
|
|
324
|
-
const wrappedMethod = wrapper.wrapMethod(originalMethod, methodInfo);
|
|
325
|
-
methodInfo.instance[methodInfo.methodName] = wrappedMethod;
|
|
326
|
-
}, {});
|
|
250
|
+
});
|
|
327
251
|
}
|
|
328
252
|
}
|
|
329
253
|
|
|
@@ -340,95 +264,61 @@ __webpack_require__.d(__webpack_exports__, {
|
|
|
340
264
|
});
|
|
341
265
|
/* ESM import */var _Capability__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./Capability */ "./src/capabilities/Capability.ts");
|
|
342
266
|
/* ESM import */var _tracing_CallTraceManager__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./tracing/CallTraceManager */ "./src/capabilities/tracing/CallTraceManager.ts");
|
|
267
|
+
/* ESM import */var _utilities_strings__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ../utilities/strings */ "./src/utilities/strings.ts");
|
|
268
|
+
|
|
343
269
|
|
|
344
270
|
|
|
345
271
|
class TracingCapability extends _Capability__WEBPACK_IMPORTED_MODULE_0__.Capability {
|
|
346
272
|
callTraceManager;
|
|
347
|
-
|
|
348
|
-
shouldLogMethod;
|
|
273
|
+
filter;
|
|
349
274
|
constructor(options) {
|
|
350
275
|
super();
|
|
351
|
-
this.
|
|
352
|
-
const stringifiedArgs = args.map(arg => this.stringifyValue(arg, 4));
|
|
353
|
-
const logData = {
|
|
354
|
-
methodPath,
|
|
355
|
-
callStack: formattedCallTrace,
|
|
356
|
-
args: stringifiedArgs
|
|
357
|
-
};
|
|
358
|
-
console.log(`[${type} ${operationId}] ${methodName}`, logData);
|
|
359
|
-
});
|
|
360
|
-
this.shouldLogMethod = options?.shouldLog ?? (() => true);
|
|
276
|
+
this.filter = options?.filter ?? (() => true);
|
|
361
277
|
this.callTraceManager = new _tracing_CallTraceManager__WEBPACK_IMPORTED_MODULE_1__.CallTraceManager();
|
|
362
278
|
}
|
|
363
|
-
createTracingInterceptor(originalMethod, methodName, methodPath, instance) {
|
|
364
|
-
return (...args) => {
|
|
365
|
-
const isNewOperation = this.callTraceManager.isNewOperation();
|
|
366
|
-
let operationId;
|
|
367
|
-
let callTrace;
|
|
368
|
-
if (isNewOperation) {
|
|
369
|
-
operationId = this.callTraceManager.startNewOperation();
|
|
370
|
-
callTrace = this.callTraceManager.addMethodToTrace(methodPath);
|
|
371
|
-
const formattedCallTrace = this.callTraceManager.formatMethodPaths(callTrace);
|
|
372
|
-
this.log('ORIGIN', operationId, methodName, methodPath, callTrace, formattedCallTrace, args);
|
|
373
|
-
}
|
|
374
|
-
else {
|
|
375
|
-
operationId = this.callTraceManager.getActiveOperationId();
|
|
376
|
-
callTrace = this.callTraceManager.addMethodToTrace(methodPath);
|
|
377
|
-
const formattedCallTrace = this.callTraceManager.formatMethodPaths(callTrace);
|
|
378
|
-
this.log('CHILD', operationId, methodName, methodPath, callTrace, formattedCallTrace, args);
|
|
379
|
-
}
|
|
380
|
-
try {
|
|
381
|
-
const result = originalMethod.apply(instance, args);
|
|
382
|
-
return result;
|
|
383
|
-
}
|
|
384
|
-
finally {
|
|
385
|
-
if (isNewOperation) {
|
|
386
|
-
this.callTraceManager.endOperation();
|
|
387
|
-
}
|
|
388
|
-
else {
|
|
389
|
-
this.callTraceManager.removeMethodFromTrace();
|
|
390
|
-
}
|
|
391
|
-
}
|
|
392
|
-
};
|
|
393
|
-
}
|
|
394
279
|
apply(instance) {
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
280
|
+
this.explore(instance, (meta, info) => {
|
|
281
|
+
if (info.isCallable) {
|
|
282
|
+
const originalMethod = meta.instance[info.name].bind(meta.instance);
|
|
283
|
+
meta.instance[info.name] = (...args) => {
|
|
284
|
+
const path = `${meta.path}.${String(info.name)}()`;
|
|
285
|
+
if (this.filter(path, info, meta) === false) {
|
|
286
|
+
return originalMethod(...args);
|
|
287
|
+
}
|
|
288
|
+
const isNewOperation = this.callTraceManager.isNewOperation();
|
|
289
|
+
let operationId;
|
|
290
|
+
if (isNewOperation) {
|
|
291
|
+
operationId = this.callTraceManager.startNewOperation();
|
|
292
|
+
const callTrace = this.callTraceManager.addMethodToTrace(path);
|
|
293
|
+
const formattedCallTrace = this.callTraceManager.formatMethodPaths(callTrace);
|
|
294
|
+
console.log(`\n${'═'.repeat(60)}`);
|
|
295
|
+
console.log(`▶ ORIGIN [${operationId}] ${path}`);
|
|
296
|
+
if (args.length > 0) {
|
|
297
|
+
console.log(` Args:`, (0,_utilities_strings__WEBPACK_IMPORTED_MODULE_2__.stringifyObject)(args, 4, 0));
|
|
298
|
+
}
|
|
299
|
+
console.log(` Call Stack: ${formattedCallTrace.join(' → ')}`);
|
|
300
|
+
}
|
|
301
|
+
else {
|
|
302
|
+
operationId = this.callTraceManager.getActiveOperationId();
|
|
303
|
+
const callTrace = this.callTraceManager.addMethodToTrace(path);
|
|
304
|
+
const indent = ' '.repeat(Math.min(callTrace.length - 1, 4));
|
|
305
|
+
console.log(`${indent}└─ CHILD [${operationId}] ${path}`);
|
|
306
|
+
if (args.length > 0) {
|
|
307
|
+
console.log(`${indent} Args:`, (0,_utilities_strings__WEBPACK_IMPORTED_MODULE_2__.stringifyObject)(args, 4, 0));
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
try {
|
|
311
|
+
return originalMethod(...args);
|
|
312
|
+
}
|
|
313
|
+
finally {
|
|
314
|
+
this.callTraceManager.removeMethodFromTrace();
|
|
315
|
+
if (isNewOperation) {
|
|
316
|
+
this.callTraceManager.endOperation();
|
|
317
|
+
}
|
|
318
|
+
}
|
|
418
319
|
};
|
|
419
|
-
const shouldLog = this.shouldLogMethod(methodInfo.methodName, metadata);
|
|
420
|
-
if (!shouldLog) {
|
|
421
|
-
return originalMethod; // Return unwrapped method if not logging
|
|
422
|
-
}
|
|
423
|
-
return this.createTracingInterceptor(originalMethod, String(methodInfo.methodName), methodInfo.methodPath.join(' → '), methodInfo.instance);
|
|
424
320
|
}
|
|
425
|
-
};
|
|
426
|
-
// Use the generic interception utility
|
|
427
|
-
this.exploreObjectMethods(instance, (methodInfo) => {
|
|
428
|
-
const originalMethod = methodInfo.instance[methodInfo.methodName].bind(methodInfo.instance);
|
|
429
|
-
const wrappedMethod = wrapper.wrapMethod(originalMethod, methodInfo);
|
|
430
|
-
methodInfo.instance[methodInfo.methodName] = wrappedMethod;
|
|
431
|
-
}, {});
|
|
321
|
+
});
|
|
432
322
|
}
|
|
433
323
|
}
|
|
434
324
|
|
|
@@ -520,7 +410,7 @@ class CallTraceManager {
|
|
|
520
410
|
activeOperationId = null;
|
|
521
411
|
activeCallStack = [];
|
|
522
412
|
startNewOperation() {
|
|
523
|
-
const operationId = (0,_utilities__WEBPACK_IMPORTED_MODULE_0__.uuid)();
|
|
413
|
+
const operationId = (0,_utilities__WEBPACK_IMPORTED_MODULE_0__.uuid)(8);
|
|
524
414
|
this.activeOperationId = operationId;
|
|
525
415
|
this.activeCallStack = [];
|
|
526
416
|
return operationId;
|
|
@@ -561,6 +451,172 @@ class CallTraceManager {
|
|
|
561
451
|
}
|
|
562
452
|
|
|
563
453
|
|
|
454
|
+
}),
|
|
455
|
+
"./src/utilities/strings.ts":
|
|
456
|
+
/*!**********************************!*\
|
|
457
|
+
!*** ./src/utilities/strings.ts ***!
|
|
458
|
+
\**********************************/
|
|
459
|
+
(function (__unused_webpack_module, __webpack_exports__, __webpack_require__) {
|
|
460
|
+
__webpack_require__.r(__webpack_exports__);
|
|
461
|
+
__webpack_require__.d(__webpack_exports__, {
|
|
462
|
+
fastHash: () => (fastHash),
|
|
463
|
+
hash: () => (hash),
|
|
464
|
+
stringifyObject: () => (stringifyObject)
|
|
465
|
+
});
|
|
466
|
+
const hash = (value, seed = 0) => {
|
|
467
|
+
// From Stack Overflow
|
|
468
|
+
// https://stackoverflow.com/a/52171480/3329760
|
|
469
|
+
let h1 = 0xdeadbeef ^ seed, h2 = 0x41c6ce57 ^ seed;
|
|
470
|
+
for (let i = 0, ch; i < value.length; i++) {
|
|
471
|
+
ch = value.charCodeAt(i);
|
|
472
|
+
h1 = Math.imul(h1 ^ ch, 2654435761);
|
|
473
|
+
h2 = Math.imul(h2 ^ ch, 1597334677);
|
|
474
|
+
}
|
|
475
|
+
h1 = Math.imul(h1 ^ (h1 >>> 16), 2246822507);
|
|
476
|
+
h1 ^= Math.imul(h2 ^ (h2 >>> 13), 3266489909);
|
|
477
|
+
h2 = Math.imul(h2 ^ (h2 >>> 16), 2246822507);
|
|
478
|
+
h2 ^= Math.imul(h1 ^ (h1 >>> 13), 3266489909);
|
|
479
|
+
return 4294967296 * (2097151 & h2) + (h1 >>> 0);
|
|
480
|
+
};
|
|
481
|
+
/**
|
|
482
|
+
* Fast string hash optimized for comparisons.
|
|
483
|
+
* Uses djb2 algorithm - very fast and good distribution for short to medium strings.
|
|
484
|
+
* Same input always produces same output (deterministic).
|
|
485
|
+
*
|
|
486
|
+
* @param value - The string to hash
|
|
487
|
+
* @param seed - Optional seed value (default: 5381)
|
|
488
|
+
* @returns A positive 32-bit integer hash value
|
|
489
|
+
*
|
|
490
|
+
* @example
|
|
491
|
+
* ```ts
|
|
492
|
+
* fastHash("test") === fastHash("test") // true
|
|
493
|
+
* fastHash("test") !== fastHash("test2") // true
|
|
494
|
+
* ```
|
|
495
|
+
*/
|
|
496
|
+
const fastHash = (value, seed = 5381) => {
|
|
497
|
+
let hash = seed;
|
|
498
|
+
for (let i = 0; i < value.length; i++) {
|
|
499
|
+
hash = ((hash << 5) + hash) + value.charCodeAt(i);
|
|
500
|
+
}
|
|
501
|
+
return hash >>> 0; // Convert to unsigned 32-bit integer
|
|
502
|
+
};
|
|
503
|
+
/**
|
|
504
|
+
* Converts any value to a readable string representation.
|
|
505
|
+
* Handles primitives, objects, arrays, classes, dates, errors, and functions.
|
|
506
|
+
* Supports depth limiting to prevent infinite recursion on circular references.
|
|
507
|
+
*
|
|
508
|
+
* @param obj - The value to stringify
|
|
509
|
+
* @param maxDepth - Maximum depth for nested objects (default: 3)
|
|
510
|
+
* @param currentDepth - Current recursion depth (default: 0)
|
|
511
|
+
* @returns String representation of the value
|
|
512
|
+
*
|
|
513
|
+
* @example
|
|
514
|
+
* ```ts
|
|
515
|
+
* stringifyObject({ name: "test", count: 5 }) // '{ name: "test", count: 5 }'
|
|
516
|
+
* stringifyObject([1, 2, 3]) // '[1, 2, 3]'
|
|
517
|
+
* stringifyObject(new Date()) // 'Date(2024-01-01T00:00:00.000Z)'
|
|
518
|
+
* ```
|
|
519
|
+
*/
|
|
520
|
+
function stringifyObject(obj, maxDepth = 3, currentDepth = 0) {
|
|
521
|
+
if (obj === null)
|
|
522
|
+
return 'null';
|
|
523
|
+
if (obj === undefined)
|
|
524
|
+
return 'undefined';
|
|
525
|
+
const type = typeof obj;
|
|
526
|
+
switch (type) {
|
|
527
|
+
case 'string':
|
|
528
|
+
return `"${obj}"`;
|
|
529
|
+
case 'number':
|
|
530
|
+
case 'boolean':
|
|
531
|
+
return String(obj);
|
|
532
|
+
case 'function':
|
|
533
|
+
return `[Function: ${getFunctionName(obj)}]`;
|
|
534
|
+
case 'object':
|
|
535
|
+
if (currentDepth >= maxDepth) {
|
|
536
|
+
return '[Max Depth Reached]';
|
|
537
|
+
}
|
|
538
|
+
return stringifyObjectValue(obj, maxDepth, currentDepth);
|
|
539
|
+
default:
|
|
540
|
+
return `[${type}]`;
|
|
541
|
+
}
|
|
542
|
+
}
|
|
543
|
+
function getFunctionName(fn) {
|
|
544
|
+
const name = fn.name;
|
|
545
|
+
return name || 'anonymous';
|
|
546
|
+
}
|
|
547
|
+
function getObjectProperties(obj) {
|
|
548
|
+
const properties = {};
|
|
549
|
+
for (const key in obj) {
|
|
550
|
+
if (obj.hasOwnProperty(key)) {
|
|
551
|
+
properties[key] = obj[key];
|
|
552
|
+
}
|
|
553
|
+
}
|
|
554
|
+
return properties;
|
|
555
|
+
}
|
|
556
|
+
function stringifyObjectValue(obj, maxDepth, currentDepth) {
|
|
557
|
+
if (obj === null)
|
|
558
|
+
return 'null';
|
|
559
|
+
if (obj instanceof Date) {
|
|
560
|
+
return `Date(${obj.toISOString()})`;
|
|
561
|
+
}
|
|
562
|
+
if (obj instanceof Error) {
|
|
563
|
+
return `Error(${obj.message})`;
|
|
564
|
+
}
|
|
565
|
+
if (obj instanceof RegExp) {
|
|
566
|
+
return obj.toString();
|
|
567
|
+
}
|
|
568
|
+
if (Array.isArray(obj)) {
|
|
569
|
+
return stringifyArray(obj, maxDepth, currentDepth);
|
|
570
|
+
}
|
|
571
|
+
if (obj.constructor && obj.constructor.name !== 'Object') {
|
|
572
|
+
return stringifyClassInstance(obj, maxDepth, currentDepth);
|
|
573
|
+
}
|
|
574
|
+
return stringifyPlainObject(obj, maxDepth, currentDepth);
|
|
575
|
+
}
|
|
576
|
+
function stringifyArray(arr, maxDepth, currentDepth) {
|
|
577
|
+
if (arr.length === 0)
|
|
578
|
+
return '[]';
|
|
579
|
+
const items = arr.slice(0, 5).map(item => stringifyObject(item, maxDepth, currentDepth + 1));
|
|
580
|
+
const suffix = arr.length > 5 ? `... (+${arr.length - 5} more)` : '';
|
|
581
|
+
return `[${items.join(', ')}${suffix}]`;
|
|
582
|
+
}
|
|
583
|
+
function stringifyClassInstance(obj, maxDepth, currentDepth) {
|
|
584
|
+
const className = obj.constructor.name;
|
|
585
|
+
const properties = getObjectProperties(obj);
|
|
586
|
+
if (Object.keys(properties).length === 0) {
|
|
587
|
+
return `${className} {}`;
|
|
588
|
+
}
|
|
589
|
+
const props = Object.entries(properties)
|
|
590
|
+
.slice(0, 5)
|
|
591
|
+
.map(([key, value]) => {
|
|
592
|
+
const isPrimitive = value === null || value === undefined ||
|
|
593
|
+
(typeof value !== 'object' && typeof value !== 'function');
|
|
594
|
+
const depth = isPrimitive ? currentDepth : currentDepth + 1;
|
|
595
|
+
return `${key}: ${stringifyObject(value, maxDepth, depth)}`;
|
|
596
|
+
});
|
|
597
|
+
const suffix = Object.keys(properties).length > 5 ?
|
|
598
|
+
`... (+${Object.keys(properties).length - 5} more)` : '';
|
|
599
|
+
return `${className} { ${props.join(', ')}${suffix} }`;
|
|
600
|
+
}
|
|
601
|
+
function stringifyPlainObject(obj, maxDepth, currentDepth) {
|
|
602
|
+
const properties = getObjectProperties(obj);
|
|
603
|
+
if (Object.keys(properties).length === 0) {
|
|
604
|
+
return '{}';
|
|
605
|
+
}
|
|
606
|
+
const props = Object.entries(properties)
|
|
607
|
+
.slice(0, 5)
|
|
608
|
+
.map(([key, value]) => {
|
|
609
|
+
const isPrimitive = value === null || value === undefined ||
|
|
610
|
+
(typeof value !== 'object' && typeof value !== 'function');
|
|
611
|
+
const depth = isPrimitive ? currentDepth : currentDepth + 1;
|
|
612
|
+
return `${key}: ${stringifyObject(value, maxDepth, depth)}`;
|
|
613
|
+
});
|
|
614
|
+
const suffix = Object.keys(properties).length > 5 ?
|
|
615
|
+
`... (+${Object.keys(properties).length - 5} more)` : '';
|
|
616
|
+
return `{ ${props.join(', ')}${suffix} }`;
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
|
|
564
620
|
}),
|
|
565
621
|
"./src/utilities/uuid.ts":
|
|
566
622
|
/*!*******************************!*\
|