@contrail/util 1.1.14-alpha-2 → 1.1.14

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/lib/index.d.ts CHANGED
@@ -4,6 +4,7 @@ export * from './date-util/date-util';
4
4
  export * from './map-util/map-util';
5
5
  export * from './object-util/object-util';
6
6
  export * from './order-util/order-util';
7
+ export * from './performance-util/performance-util';
7
8
  export * from './promise-util/promise-util';
8
9
  export * from './retry-util/retry-util';
9
10
  export * from './string-util/string-util';
package/lib/index.js CHANGED
@@ -20,6 +20,7 @@ __exportStar(require("./date-util/date-util"), exports);
20
20
  __exportStar(require("./map-util/map-util"), exports);
21
21
  __exportStar(require("./object-util/object-util"), exports);
22
22
  __exportStar(require("./order-util/order-util"), exports);
23
+ __exportStar(require("./performance-util/performance-util"), exports);
23
24
  __exportStar(require("./promise-util/promise-util"), exports);
24
25
  __exportStar(require("./retry-util/retry-util"), exports);
25
26
  __exportStar(require("./string-util/string-util"), exports);
@@ -1,32 +1 @@
1
- type PerformanceComparisonEvent = {
2
- durationMsJson: number;
3
- durationMsRFDC: number;
4
- input: any;
5
- };
6
- type PerformanceSummary = {
7
- eventForWhichJsonWasMostFaster: PerformanceComparisonEvent | null;
8
- eventForWhichRFDCWasMostFaster: PerformanceComparisonEvent | null;
9
- totalDurationMsJson: number;
10
- totalDurationMsRFDC: number;
11
- invocationsInWhichJsonWasFaster: PerformanceComparisonEvent[];
12
- invocationsInWhichRFDCWasFaster: PerformanceComparisonEvent[];
13
- };
14
- type CloneMethods = {
15
- cloneRfdc: <T>(obj: T) => T;
16
- cloneJson: <T>(obj: T) => T;
17
- withTiming: (fn: () => any) => {
18
- result: any;
19
- durationMs: number;
20
- };
21
- };
22
- declare global {
23
- interface Window {
24
- performanceSummary: PerformanceSummary;
25
- performanceEvents: PerformanceComparisonEvent[];
26
- cloneMethods: CloneMethods;
27
- }
28
- }
29
- export declare function cloneDeep<T>(obj: T, options?: {
30
- shouldPreserveCircularReferences?: boolean;
31
- }): T;
32
- export {};
1
+ export declare function cloneDeep<T>(obj: T): T | null;
@@ -1,68 +1,15 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.cloneDeep = cloneDeep;
4
- const cloneDefault = require('rfdc')();
5
- const cloneWithCircles = require('rfdc')({ circles: true });
6
- function cloneRfdc(obj, options) {
7
- var _a;
8
- const shouldPreserveCircles = (_a = options === null || options === void 0 ? void 0 : options.shouldPreserveCircularReferences) !== null && _a !== void 0 ? _a : false;
9
- const clone = shouldPreserveCircles ? cloneWithCircles : cloneDefault;
10
- return clone(obj);
11
- }
12
- function withTiming(fn) {
13
- const start = performance.now();
14
- const result = fn();
15
- const durationMs = performance.now() - start;
16
- return { result, durationMs };
17
- }
18
- if (typeof window === 'undefined') {
19
- var window = {};
20
- }
21
- window.cloneMethods = {
22
- cloneRfdc,
23
- cloneJson: (obj) => JSON.parse(JSON.stringify(obj)),
24
- withTiming,
25
- };
26
- function cloneDeep(obj, options) {
27
- var _a;
28
- const shouldPreserveCircles = (_a = options === null || options === void 0 ? void 0 : options.shouldPreserveCircularReferences) !== null && _a !== void 0 ? _a : false;
29
- const clone = shouldPreserveCircles ? cloneWithCircles : cloneDefault;
30
- const { durationMs: durationMsJson } = withTiming(() => JSON.parse(JSON.stringify(obj)));
31
- const { durationMs: durationMsRFDC } = withTiming(() => clone(obj));
32
- const rfdcClone = clone(obj);
33
- if (!window.performanceEvents) {
34
- window.performanceEvents = [];
35
- }
36
- const performanceEvent = {
37
- durationMsJson,
38
- durationMsRFDC,
39
- input: obj,
40
- };
41
- window.performanceEvents.push(performanceEvent);
42
- window.performanceSummary = window.performanceSummary || {
43
- eventForWhichJsonWasMostFaster: null,
44
- eventForWhichRFDCWasMostFaster: null,
45
- totalDurationMsJson: 0,
46
- totalDurationMsRFDC: 0,
47
- invocationsInWhichJsonWasFaster: [],
48
- invocationsInWhichRFDCWasFaster: [],
49
- };
50
- window.performanceSummary.totalDurationMsJson += durationMsJson;
51
- window.performanceSummary.totalDurationMsRFDC += durationMsRFDC;
52
- const isJsonFaster = durationMsJson < durationMsRFDC;
53
- if (isJsonFaster) {
54
- window.performanceSummary.invocationsInWhichJsonWasFaster.push(performanceEvent);
55
- if (!window.performanceSummary.eventForWhichJsonWasMostFaster ||
56
- durationMsJson < window.performanceSummary.eventForWhichJsonWasMostFaster.durationMsJson) {
57
- window.performanceSummary.eventForWhichJsonWasMostFaster = performanceEvent;
58
- }
59
- }
60
- else {
61
- window.performanceSummary.invocationsInWhichRFDCWasFaster.push(performanceEvent);
62
- if (!window.performanceSummary.eventForWhichRFDCWasMostFaster ||
63
- durationMsRFDC < window.performanceSummary.eventForWhichRFDCWasMostFaster.durationMsRFDC) {
64
- window.performanceSummary.eventForWhichRFDCWasMostFaster = performanceEvent;
4
+ function cloneDeep(obj) {
5
+ if (obj === null || obj === undefined)
6
+ return null;
7
+ return JSON.parse(JSON.stringify(obj), (_key, value) => {
8
+ if (typeof value === 'string' && /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}.\d{3}Z$/.test(value)) {
9
+ const date = new Date(value);
10
+ if (!isNaN(date.getTime()))
11
+ return date;
65
12
  }
66
- }
67
- return rfdcClone;
13
+ return value;
14
+ });
68
15
  }
@@ -0,0 +1,298 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ const performance_util_1 = require("./performance-util");
13
+ function demonstrateStartEndSpan() {
14
+ console.log('--- Demonstrating startSpan/endSpan functionality ---\n');
15
+ (0, performance_util_1.clearDefaultTimingProfile)();
16
+ console.log('Example 1: Simple span');
17
+ (0, performance_util_1.startSpan)('Data Processing');
18
+ const start1 = performance.now();
19
+ while (performance.now() < start1 + 100) {
20
+ }
21
+ (0, performance_util_1.endSpan)('Data Processing');
22
+ (0, performance_util_1.displayTimingTree)();
23
+ console.log('\nExample 2: Nested spans');
24
+ (0, performance_util_1.clearDefaultTimingProfile)();
25
+ (0, performance_util_1.startSpan)('Complete Task');
26
+ (0, performance_util_1.startSpan)('Initialization');
27
+ const start2 = performance.now();
28
+ while (performance.now() < start2 + 50) {
29
+ }
30
+ (0, performance_util_1.endSpan)('Initialization');
31
+ (0, performance_util_1.startSpan)('Main Processing');
32
+ (0, performance_util_1.startSpan)('Sub-task 1');
33
+ const start3 = performance.now();
34
+ while (performance.now() < start3 + 30) {
35
+ }
36
+ (0, performance_util_1.endSpan)('Sub-task 1');
37
+ (0, performance_util_1.startSpan)('Sub-task 2');
38
+ const start4 = performance.now();
39
+ while (performance.now() < start4 + 40) {
40
+ }
41
+ (0, performance_util_1.endSpan)('Sub-task 2');
42
+ (0, performance_util_1.endSpan)('Main Processing');
43
+ (0, performance_util_1.startSpan)('Cleanup');
44
+ const start5 = performance.now();
45
+ while (performance.now() < start5 + 20) {
46
+ }
47
+ (0, performance_util_1.endSpan)('Cleanup');
48
+ (0, performance_util_1.endSpan)('Complete Task');
49
+ (0, performance_util_1.displayTimingTree)();
50
+ console.log('\nExample 3: Multiple sequential spans');
51
+ (0, performance_util_1.clearDefaultTimingProfile)();
52
+ (0, performance_util_1.startSpan)('Phase 1');
53
+ const start6 = performance.now();
54
+ while (performance.now() < start6 + 60) {
55
+ }
56
+ (0, performance_util_1.endSpan)('Phase 1');
57
+ (0, performance_util_1.startSpan)('Phase 2');
58
+ const start7 = performance.now();
59
+ while (performance.now() < start7 + 80) {
60
+ }
61
+ (0, performance_util_1.endSpan)('Phase 2');
62
+ (0, performance_util_1.startSpan)('Phase 3');
63
+ const start8 = performance.now();
64
+ while (performance.now() < start8 + 40) {
65
+ }
66
+ (0, performance_util_1.endSpan)('Phase 3');
67
+ (0, performance_util_1.displayTimingTree)();
68
+ }
69
+ function demonstrateWarningBehavior() {
70
+ console.log('\n--- Demonstrating Warning Behavior ---\n');
71
+ (0, performance_util_1.clearDefaultTimingProfile)();
72
+ console.log('Example 4: Warning behavior');
73
+ (0, performance_util_1.startSpan)('Test Span');
74
+ console.log('Started "Test Span"');
75
+ (0, performance_util_1.startSpan)('Test Span');
76
+ console.log('Attempted to start "Test Span" again (should see warning above)');
77
+ (0, performance_util_1.endSpan)('Test Span');
78
+ console.log('Ended "Test Span"');
79
+ (0, performance_util_1.endSpan)('Non-existent Span');
80
+ console.log('Attempted to end "Non-existent Span" (should see warning above)');
81
+ (0, performance_util_1.displayTimingTree)();
82
+ }
83
+ function demonstrateParentNodeId() {
84
+ return __awaiter(this, void 0, void 0, function* () {
85
+ console.log('\n--- Demonstrating parentNodeId Functionality ---\n');
86
+ (0, performance_util_1.clearDefaultTimingProfile)();
87
+ console.log('Example 5: Concurrent async operations with explicit parent');
88
+ yield (0, performance_util_1.withTimingAsync)('Main Operation', () => __awaiter(this, void 0, void 0, function* () {
89
+ const mainOpId = (0, performance_util_1.getCurrentParentNodeId)();
90
+ console.log(`Main Operation ID: ${String(mainOpId)}`);
91
+ console.log('Starting concurrent operations...');
92
+ const results = yield Promise.all([
93
+ (0, performance_util_1.withTimingAsync)('Fetch User Data', () => __awaiter(this, void 0, void 0, function* () {
94
+ yield new Promise((resolve) => setTimeout(resolve, 80));
95
+ console.log(' ✓ User data fetched');
96
+ return 'user-data';
97
+ }), { parentNodeId: mainOpId }),
98
+ (0, performance_util_1.withTimingAsync)('Fetch Permissions', () => __awaiter(this, void 0, void 0, function* () {
99
+ yield new Promise((resolve) => setTimeout(resolve, 60));
100
+ console.log(' ✓ Permissions fetched');
101
+ return 'permissions-data';
102
+ }), { parentNodeId: mainOpId }),
103
+ (0, performance_util_1.withTimingAsync)('Fetch Preferences', () => __awaiter(this, void 0, void 0, function* () {
104
+ yield new Promise((resolve) => setTimeout(resolve, 100));
105
+ console.log(' ✓ Preferences fetched');
106
+ return 'preferences-data';
107
+ }), { parentNodeId: mainOpId }),
108
+ ]);
109
+ console.log('All concurrent operations completed:', results);
110
+ yield (0, performance_util_1.withTimingAsync)('Process Results', () => __awaiter(this, void 0, void 0, function* () {
111
+ yield new Promise((resolve) => setTimeout(resolve, 30));
112
+ console.log(' ✓ Results processed');
113
+ }));
114
+ }));
115
+ (0, performance_util_1.displayTimingTree)();
116
+ });
117
+ }
118
+ function demonstrateMixedNesting() {
119
+ return __awaiter(this, void 0, void 0, function* () {
120
+ console.log('\n--- Demonstrating Mixed Natural and Explicit Nesting ---\n');
121
+ (0, performance_util_1.clearDefaultTimingProfile)();
122
+ console.log('Example 6: Mixed natural and explicit nesting');
123
+ yield (0, performance_util_1.withTimingAsync)('Application Startup', () => __awaiter(this, void 0, void 0, function* () {
124
+ yield (0, performance_util_1.withTimingAsync)('Load Configuration', () => __awaiter(this, void 0, void 0, function* () {
125
+ yield new Promise((resolve) => setTimeout(resolve, 50));
126
+ console.log(' ✓ Configuration loaded');
127
+ yield (0, performance_util_1.withTimingAsync)('Validate Config', () => __awaiter(this, void 0, void 0, function* () {
128
+ yield new Promise((resolve) => setTimeout(resolve, 20));
129
+ console.log(' ✓ Configuration validated');
130
+ }));
131
+ }));
132
+ console.log('Starting parallel initialization...');
133
+ (0, performance_util_1.startSpan)('Initialization');
134
+ const ininitializeId = (0, performance_util_1.getCurrentParentNodeId)();
135
+ (0, performance_util_1.withTimingSync)('Do something before initialization', () => {
136
+ const start = performance.now();
137
+ while (performance.now() < start + 20) {
138
+ }
139
+ console.log(' ✓ Pre-initialization task completed');
140
+ });
141
+ yield Promise.all([
142
+ (0, performance_util_1.withTimingAsync)('Initialize Database', () => __awaiter(this, void 0, void 0, function* () {
143
+ yield new Promise((resolve) => setTimeout(resolve, 120));
144
+ console.log(' ✓ Database initialized');
145
+ }), { parentNodeId: ininitializeId }),
146
+ (0, performance_util_1.withTimingAsync)('Initialize Cache', () => __awaiter(this, void 0, void 0, function* () {
147
+ yield new Promise((resolve) => setTimeout(resolve, 90));
148
+ console.log(' ✓ Cache initialized');
149
+ }), { parentNodeId: ininitializeId }),
150
+ (0, performance_util_1.withTimingAsync)('Initialize Logging', () => __awaiter(this, void 0, void 0, function* () {
151
+ yield new Promise((resolve) => setTimeout(resolve, 40));
152
+ console.log(' ✓ Logging initialized');
153
+ }), { parentNodeId: ininitializeId }),
154
+ ]);
155
+ (0, performance_util_1.withTimingSync)('Do something after initialization', () => {
156
+ const start = performance.now();
157
+ while (performance.now() < start + 20) {
158
+ }
159
+ console.log(' ✓ Post-initialization task completed');
160
+ });
161
+ (0, performance_util_1.endSpan)('Initialization');
162
+ yield (0, performance_util_1.withTimingAsync)('Final Setup', () => __awaiter(this, void 0, void 0, function* () {
163
+ yield new Promise((resolve) => setTimeout(resolve, 30));
164
+ console.log(' ✓ Final setup completed');
165
+ }));
166
+ }));
167
+ (0, performance_util_1.displayTimingTree)();
168
+ });
169
+ }
170
+ function demonstrateSyncWithParentId() {
171
+ console.log('\n--- Demonstrating Sync Functions with parentNodeId ---\n');
172
+ (0, performance_util_1.clearDefaultTimingProfile)();
173
+ console.log('Example 7: Sync functions with explicit parent');
174
+ (0, performance_util_1.withTimingSync)('Data Processing Pipeline', () => {
175
+ const pipelineId = (0, performance_util_1.getCurrentParentNodeId)();
176
+ console.log(`Pipeline ID: ${String(pipelineId)}`);
177
+ (0, performance_util_1.withTimingSync)('Load Input Data', () => {
178
+ const start = performance.now();
179
+ while (performance.now() < start + 50) {
180
+ }
181
+ console.log(' ✓ Input data loaded');
182
+ });
183
+ (0, performance_util_1.withTimingSync)('Process Batch 1', () => {
184
+ const start = performance.now();
185
+ while (performance.now() < start + 80) {
186
+ }
187
+ console.log(' ✓ Batch 1 processed');
188
+ }, { parentNodeId: pipelineId });
189
+ (0, performance_util_1.withTimingSync)('Process Batch 2', () => {
190
+ const start = performance.now();
191
+ while (performance.now() < start + 70) {
192
+ }
193
+ console.log(' ✓ Batch 2 processed');
194
+ }, { parentNodeId: pipelineId });
195
+ (0, performance_util_1.withTimingSync)('Process Batch 3', () => {
196
+ const start = performance.now();
197
+ while (performance.now() < start + 90) {
198
+ }
199
+ console.log(' ✓ Batch 3 processed');
200
+ }, { parentNodeId: pipelineId });
201
+ (0, performance_util_1.withTimingSync)('Save Results', () => {
202
+ const start = performance.now();
203
+ while (performance.now() < start + 40) {
204
+ }
205
+ console.log(' ✓ Results saved');
206
+ });
207
+ });
208
+ (0, performance_util_1.displayTimingTree)();
209
+ }
210
+ function demonstrateManualSpansWithParentId() {
211
+ console.log('\n--- Demonstrating Manual Spans with parentNodeId ---\n');
212
+ (0, performance_util_1.clearDefaultTimingProfile)();
213
+ console.log('Example 8: Manual spans with explicit parent');
214
+ (0, performance_util_1.startSpan)('Service Request');
215
+ const serviceId = (0, performance_util_1.getCurrentParentNodeId)();
216
+ console.log(`Service Request ID: ${String(serviceId)}`);
217
+ (0, performance_util_1.startSpan)('Authenticate User');
218
+ const start1 = performance.now();
219
+ while (performance.now() < start1 + 30) {
220
+ }
221
+ (0, performance_util_1.endSpan)('Authenticate User');
222
+ console.log(' ✓ User authenticated');
223
+ (0, performance_util_1.startSpan)('Validate Input', { parentNodeId: serviceId });
224
+ const start2 = performance.now();
225
+ while (performance.now() < start2 + 20) {
226
+ }
227
+ (0, performance_util_1.endSpan)('Validate Input');
228
+ console.log(' ✓ Input validated');
229
+ (0, performance_util_1.startSpan)('Check Rate Limits', { parentNodeId: serviceId });
230
+ const start3 = performance.now();
231
+ while (performance.now() < start3 + 15) {
232
+ }
233
+ (0, performance_util_1.endSpan)('Check Rate Limits');
234
+ console.log(' ✓ Rate limits checked');
235
+ (0, performance_util_1.startSpan)('Log Request', { parentNodeId: serviceId });
236
+ const start4 = performance.now();
237
+ while (performance.now() < start4 + 10) {
238
+ }
239
+ (0, performance_util_1.endSpan)('Log Request');
240
+ console.log(' ✓ Request logged');
241
+ (0, performance_util_1.startSpan)('Process Request');
242
+ const start5 = performance.now();
243
+ while (performance.now() < start5 + 60) {
244
+ }
245
+ (0, performance_util_1.endSpan)('Process Request');
246
+ console.log(' ✓ Request processed');
247
+ (0, performance_util_1.endSpan)('Service Request');
248
+ (0, performance_util_1.displayTimingTree)();
249
+ }
250
+ function demonstrateNestingComparison() {
251
+ return __awaiter(this, void 0, void 0, function* () {
252
+ console.log('\n--- Demonstrating Natural vs Explicit Nesting ---\n');
253
+ console.log('Natural Nesting (call stack based):');
254
+ (0, performance_util_1.clearDefaultTimingProfile)();
255
+ yield (0, performance_util_1.withTimingAsync)('Sequential Operations', () => __awaiter(this, void 0, void 0, function* () {
256
+ yield (0, performance_util_1.withTimingAsync)('Operation 1', () => __awaiter(this, void 0, void 0, function* () {
257
+ yield new Promise((resolve) => setTimeout(resolve, 30));
258
+ }));
259
+ yield (0, performance_util_1.withTimingAsync)('Operation 2', () => __awaiter(this, void 0, void 0, function* () {
260
+ yield new Promise((resolve) => setTimeout(resolve, 40));
261
+ }));
262
+ yield (0, performance_util_1.withTimingAsync)('Operation 3', () => __awaiter(this, void 0, void 0, function* () {
263
+ yield new Promise((resolve) => setTimeout(resolve, 35));
264
+ }));
265
+ }));
266
+ (0, performance_util_1.displayTimingTree)();
267
+ console.log('\nExplicit Parent Assignment (logical grouping):');
268
+ (0, performance_util_1.clearDefaultTimingProfile)();
269
+ yield (0, performance_util_1.withTimingAsync)('Parallel Operations', () => __awaiter(this, void 0, void 0, function* () {
270
+ const parentId = (0, performance_util_1.getCurrentParentNodeId)();
271
+ yield Promise.all([
272
+ (0, performance_util_1.withTimingAsync)('Operation 1', () => __awaiter(this, void 0, void 0, function* () {
273
+ yield new Promise((resolve) => setTimeout(resolve, 30));
274
+ }), { parentNodeId: parentId }),
275
+ (0, performance_util_1.withTimingAsync)('Operation 2', () => __awaiter(this, void 0, void 0, function* () {
276
+ yield new Promise((resolve) => setTimeout(resolve, 40));
277
+ }), { parentNodeId: parentId }),
278
+ (0, performance_util_1.withTimingAsync)('Operation 3', () => __awaiter(this, void 0, void 0, function* () {
279
+ yield new Promise((resolve) => setTimeout(resolve, 35));
280
+ }), { parentNodeId: parentId }),
281
+ ]);
282
+ }));
283
+ (0, performance_util_1.displayTimingTree)();
284
+ });
285
+ }
286
+ function runAllExamples() {
287
+ return __awaiter(this, void 0, void 0, function* () {
288
+ demonstrateStartEndSpan();
289
+ demonstrateWarningBehavior();
290
+ yield demonstrateParentNodeId();
291
+ yield demonstrateMixedNesting();
292
+ demonstrateSyncWithParentId();
293
+ demonstrateManualSpansWithParentId();
294
+ yield demonstrateNestingComparison();
295
+ console.log('\nAll examples completed. ');
296
+ });
297
+ }
298
+ runAllExamples().catch(console.error);
@@ -0,0 +1,35 @@
1
+ type TimingSpans = TimingNode[];
2
+ type TimingStack = TimingNode[];
3
+ export type TimingNode = {
4
+ label: string;
5
+ id: string;
6
+ durationMs: number;
7
+ children: TimingNode[];
8
+ startTime: number;
9
+ };
10
+ type ActiveSpan = {
11
+ node: TimingNode;
12
+ startTime: number;
13
+ wasAddedToStack: boolean;
14
+ };
15
+ type TimingProfile = {
16
+ activeSpans: Map<string, ActiveSpan>;
17
+ spansById: Map<string, TimingNode>;
18
+ timingSpans: TimingSpans;
19
+ timingStack: TimingStack;
20
+ };
21
+ export declare function getDefaultTimingProfile(): TimingProfile;
22
+ export declare function clearDefaultTimingProfile(): void;
23
+ export declare function getCurrentParentNodeId(): string | null;
24
+ export declare function withTimingAsync<T>(label: string, fn: () => Promise<T>, options?: {
25
+ parentNodeId?: string | null;
26
+ }): Promise<T>;
27
+ export declare function withTimingSync<T>(label: string, fn: () => T, options?: {
28
+ parentNodeId?: string | null;
29
+ }): T;
30
+ export declare function displayTimingTree(nodes?: TimingSpans, depth?: number, prefix?: string): string;
31
+ export declare function startSpan(spanName: string, options?: {
32
+ parentNodeId?: string | null;
33
+ }): void;
34
+ export declare function endSpan(spanName: string): void;
35
+ export {};
@@ -0,0 +1,257 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.getDefaultTimingProfile = getDefaultTimingProfile;
13
+ exports.clearDefaultTimingProfile = clearDefaultTimingProfile;
14
+ exports.getCurrentParentNodeId = getCurrentParentNodeId;
15
+ exports.withTimingAsync = withTimingAsync;
16
+ exports.withTimingSync = withTimingSync;
17
+ exports.displayTimingTree = displayTimingTree;
18
+ exports.startSpan = startSpan;
19
+ exports.endSpan = endSpan;
20
+ const DEFAULT_TIMING_PROFILE = {
21
+ activeSpans: new Map(),
22
+ spansById: new Map(),
23
+ timingSpans: [],
24
+ timingStack: [],
25
+ };
26
+ function getDefaultTimingProfile() {
27
+ return DEFAULT_TIMING_PROFILE;
28
+ }
29
+ function getTimingStack() {
30
+ return DEFAULT_TIMING_PROFILE.timingStack;
31
+ }
32
+ function getTimingSpans() {
33
+ return DEFAULT_TIMING_PROFILE.timingSpans;
34
+ }
35
+ function getNodeById(id) {
36
+ return DEFAULT_TIMING_PROFILE.spansById.get(id);
37
+ }
38
+ function setSpanId(id, node) {
39
+ DEFAULT_TIMING_PROFILE.spansById.set(id, node);
40
+ }
41
+ function clearDefaultTimingProfile() {
42
+ DEFAULT_TIMING_PROFILE.timingSpans = [];
43
+ DEFAULT_TIMING_PROFILE.timingStack = [];
44
+ DEFAULT_TIMING_PROFILE.activeSpans.clear();
45
+ DEFAULT_TIMING_PROFILE.spansById.clear();
46
+ }
47
+ function getParentNode() {
48
+ const stack = getTimingStack();
49
+ return stack.length > 0 ? stack[stack.length - 1] : null;
50
+ }
51
+ function getCurrentParentNodeId() {
52
+ const parentNode = getParentNode();
53
+ return parentNode ? parentNode.id : null;
54
+ }
55
+ function withTimingAsync(label, fn, options) {
56
+ return __awaiter(this, void 0, void 0, function* () {
57
+ const start = performance.now();
58
+ const chosenId = options === null || options === void 0 ? void 0 : options.parentNodeId;
59
+ const uniqueId = generateUUID();
60
+ const timingNode = {
61
+ label,
62
+ durationMs: 0,
63
+ children: [],
64
+ id: uniqueId,
65
+ startTime: start,
66
+ };
67
+ setSpanId(uniqueId, timingNode);
68
+ const parent = chosenId ? getNodeById(chosenId) : getParentNode();
69
+ if (parent) {
70
+ parent.children.push(timingNode);
71
+ }
72
+ else {
73
+ getTimingSpans().push(timingNode);
74
+ }
75
+ const isRunningConcurrently = !!chosenId;
76
+ if (!isRunningConcurrently) {
77
+ getTimingStack().push(timingNode);
78
+ }
79
+ return fn().finally(() => {
80
+ const end = performance.now();
81
+ timingNode.durationMs = end - start;
82
+ if (!isRunningConcurrently) {
83
+ getTimingStack().pop();
84
+ }
85
+ });
86
+ });
87
+ }
88
+ function withTimingSync(label, fn, options) {
89
+ const start = performance.now();
90
+ const chosenId = options === null || options === void 0 ? void 0 : options.parentNodeId;
91
+ const uniqueId = generateUUID();
92
+ const timingNode = {
93
+ label,
94
+ durationMs: 0,
95
+ children: [],
96
+ id: uniqueId,
97
+ startTime: start,
98
+ };
99
+ setSpanId(uniqueId, timingNode);
100
+ const parent = chosenId ? getNodeById(chosenId) : getParentNode();
101
+ if (parent) {
102
+ parent.children.push(timingNode);
103
+ }
104
+ else {
105
+ getTimingSpans().push(timingNode);
106
+ }
107
+ const isRunningConcurrently = !!chosenId;
108
+ if (!isRunningConcurrently) {
109
+ getTimingStack().push(timingNode);
110
+ }
111
+ try {
112
+ return fn();
113
+ }
114
+ finally {
115
+ const end = performance.now();
116
+ timingNode.durationMs = end - start;
117
+ if (!isRunningConcurrently) {
118
+ getTimingStack().pop();
119
+ }
120
+ }
121
+ }
122
+ function displayTimingTree(nodes = DEFAULT_TIMING_PROFILE.timingSpans, depth = 0, prefix = '') {
123
+ const lines = [];
124
+ const totalWidth = 120;
125
+ const timeWidth = 10;
126
+ const sortedNodes = [...nodes].sort((a, b) => a.startTime - b.startTime);
127
+ const groups = [];
128
+ let currentGroup = [];
129
+ for (let i = 0; i < sortedNodes.length; i++) {
130
+ const node = sortedNodes[i];
131
+ if (currentGroup.length === 0) {
132
+ currentGroup = [node];
133
+ }
134
+ else {
135
+ const hasOverlap = currentGroup.some((groupNode) => {
136
+ const nodeEnd = node.startTime + node.durationMs;
137
+ const groupNodeEnd = groupNode.startTime + groupNode.durationMs;
138
+ return node.startTime < groupNodeEnd && nodeEnd > groupNode.startTime;
139
+ });
140
+ if (hasOverlap) {
141
+ currentGroup.push(node);
142
+ }
143
+ else {
144
+ groups.push(currentGroup);
145
+ currentGroup = [node];
146
+ }
147
+ }
148
+ }
149
+ if (currentGroup.length > 0) {
150
+ groups.push(currentGroup);
151
+ }
152
+ groups.forEach((group, groupIndex) => {
153
+ const isLastGroup = groupIndex === groups.length - 1;
154
+ if (group.length === 1) {
155
+ const node = group[0];
156
+ const timeStr = `${node.durationMs.toFixed(2)}ms`;
157
+ const connector = depth === 0 ? '' : isLastGroup ? '└── ' : '├── ';
158
+ const labelWithPrefix = `${prefix}${connector}${node.label}`;
159
+ const availableWidth = totalWidth - timeWidth - labelWithPrefix.length;
160
+ const dots = '.'.repeat(Math.max(2, availableWidth));
161
+ lines.push(`${labelWithPrefix}${dots}${timeStr.padStart(timeWidth)}`);
162
+ if (node.children && node.children.length > 0) {
163
+ const childPrefix = prefix + (depth === 0 ? '' : isLastGroup ? ' ' : '│ ');
164
+ lines.push(displayTimingTree(node.children, depth + 1, childPrefix));
165
+ }
166
+ }
167
+ else {
168
+ const connector = depth === 0 ? '' : isLastGroup ? '└── ' : '├── ';
169
+ const parallelHeader = `${prefix}${connector}∥ Parallel Operations (${group.length})`;
170
+ lines.push(parallelHeader);
171
+ group.forEach((node, nodeIndex) => {
172
+ const isLastNode = nodeIndex === group.length - 1;
173
+ const timeStr = `${node.durationMs.toFixed(2)}ms`;
174
+ const parallelIndicator = '∥ ';
175
+ const nodeConnector = isLastNode ? '└── ' : '├── ';
176
+ const nodePrefix = prefix + (depth === 0 ? '' : isLastGroup ? ' ' : '│ ');
177
+ const labelWithPrefix = `${nodePrefix}${nodeConnector}${parallelIndicator}${node.label}`;
178
+ const availableWidth = totalWidth - timeWidth - labelWithPrefix.length;
179
+ const dots = '.'.repeat(Math.max(2, availableWidth));
180
+ lines.push(`${labelWithPrefix}${dots}${timeStr.padStart(timeWidth)}`);
181
+ if (node.children && node.children.length > 0) {
182
+ const childPrefix = nodePrefix + (isLastNode ? ' ' : '│ ');
183
+ lines.push(displayTimingTree(node.children, depth + 1, childPrefix));
184
+ }
185
+ });
186
+ }
187
+ });
188
+ const result = lines.join('\n');
189
+ if (depth === 0) {
190
+ console.log('\n--- Performance Timing Tree ---');
191
+ console.log(result);
192
+ console.log('\n--- End Timing ---\n');
193
+ }
194
+ return result;
195
+ }
196
+ function startSpan(spanName, options) {
197
+ if (DEFAULT_TIMING_PROFILE.activeSpans.has(spanName)) {
198
+ console.warn(`Span "${spanName}" is already active. Please end it before starting a new one with the same name.`);
199
+ return;
200
+ }
201
+ const startTime = performance.now();
202
+ const chosenId = options === null || options === void 0 ? void 0 : options.parentNodeId;
203
+ const uniqueId = generateUUID();
204
+ const timingNode = {
205
+ label: spanName,
206
+ durationMs: 0,
207
+ children: [],
208
+ id: uniqueId,
209
+ startTime: startTime,
210
+ };
211
+ setSpanId(uniqueId, timingNode);
212
+ const parent = chosenId ? getNodeById(chosenId) : getParentNode();
213
+ if (parent) {
214
+ parent.children.push(timingNode);
215
+ }
216
+ else {
217
+ getTimingSpans().push(timingNode);
218
+ }
219
+ const isRunningConcurrently = !!chosenId;
220
+ if (!isRunningConcurrently) {
221
+ getTimingStack().push(timingNode);
222
+ }
223
+ DEFAULT_TIMING_PROFILE.activeSpans.set(spanName, {
224
+ node: timingNode,
225
+ startTime: startTime,
226
+ wasAddedToStack: !isRunningConcurrently,
227
+ });
228
+ }
229
+ function endSpan(spanName) {
230
+ const activeSpan = DEFAULT_TIMING_PROFILE.activeSpans.get(spanName);
231
+ if (!activeSpan) {
232
+ console.warn(`No active span found with name "${spanName}". Make sure to call startSpan() first.`);
233
+ return;
234
+ }
235
+ const endTime = performance.now();
236
+ activeSpan.node.durationMs = endTime - activeSpan.startTime;
237
+ if (activeSpan.wasAddedToStack) {
238
+ const currentTop = getTimingStack()[getTimingStack().length - 1];
239
+ if (currentTop === activeSpan.node) {
240
+ getTimingStack().pop();
241
+ }
242
+ else {
243
+ const stackIndex = getTimingStack().findIndex((node) => node === activeSpan.node);
244
+ if (stackIndex !== -1) {
245
+ getTimingStack().splice(stackIndex, 1);
246
+ }
247
+ }
248
+ }
249
+ DEFAULT_TIMING_PROFILE.activeSpans.delete(spanName);
250
+ }
251
+ function generateUUID() {
252
+ return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
253
+ const r = (Math.random() * 16) | 0;
254
+ const v = c === 'x' ? r : (r & 0x3) | 0x8;
255
+ return v.toString(16);
256
+ });
257
+ }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@contrail/util",
3
- "version": "1.1.14-alpha-2",
4
- "description": "General javascript utilities",
3
+ "version": "1.1.14",
4
+ "description": "General JavaScript utilities",
5
5
  "main": "lib/index.js",
6
6
  "types": "lib/index.d.ts",
7
7
  "scripts": {
@@ -41,7 +41,6 @@
41
41
  "dependencies": {
42
42
  "@contrail/types": "^3.0.95",
43
43
  "fflate": "^0.8.2",
44
- "lodash": "^4.17.21",
45
- "rfdc": "^1.4.1"
44
+ "lodash": "^4.17.21"
46
45
  }
47
46
  }
@@ -1,106 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const lodash_1 = require("lodash");
4
- const cloneDeep_1 = require("./cloneDeep");
5
- function jsonClone(obj) {
6
- return JSON.parse(JSON.stringify(obj));
7
- }
8
- console.log('Performance test for small objects:');
9
- let smallObject = {
10
- sub1: {
11
- val: 1,
12
- },
13
- sub3: {
14
- val: 2,
15
- valX: '3',
16
- },
17
- };
18
- console.time('cloneDeepSmallRFDC');
19
- Array.from({ length: 10000 }).forEach(() => {
20
- (0, cloneDeep_1.cloneDeep)(smallObject);
21
- });
22
- console.timeEnd('cloneDeepSmallRFDC');
23
- console.time('cloneDeepSmallLodash');
24
- Array.from({ length: 10000 }).forEach(() => {
25
- (0, lodash_1.cloneDeep)(smallObject);
26
- });
27
- console.timeEnd('cloneDeepSmallLodash');
28
- console.time('cloneDeepSmallJson');
29
- Array.from({ length: 10000 }).forEach(() => {
30
- jsonClone(smallObject);
31
- });
32
- console.timeEnd('cloneDeepSmallJson');
33
- console.time('structuredCloneSmall');
34
- Array.from({ length: 10000 }).forEach(() => {
35
- structuredClone(smallObject);
36
- });
37
- console.timeEnd('structuredCloneSmall');
38
- console.log('\n\nPerformance test for very large objects:');
39
- let veryLargeObject = {};
40
- for (let i = 0; i < 100000; i++) {
41
- veryLargeObject[`key${i}`] = {
42
- sub1: {
43
- val: i,
44
- },
45
- sub2: new Date('2023-10-01T12:00:00.000Z'),
46
- sub3: {
47
- val: i + 1,
48
- valX: i + 2,
49
- },
50
- };
51
- }
52
- console.time('cloneDeepRFDC');
53
- (0, cloneDeep_1.cloneDeep)(veryLargeObject);
54
- console.timeEnd('cloneDeepRFDC');
55
- console.time('cloneDeepLodash');
56
- (0, lodash_1.cloneDeep)(veryLargeObject);
57
- console.timeEnd('cloneDeepLodash');
58
- console.time('cloneDeepJson');
59
- jsonClone(veryLargeObject);
60
- console.timeEnd('cloneDeepJson');
61
- console.time('structuredClone');
62
- structuredClone(veryLargeObject);
63
- console.timeEnd('structuredClone');
64
- console.log('\n\nPerformance test for very large arrays:');
65
- let veryLargeArray = [];
66
- for (let i = 0; i < 100000; i++) {
67
- veryLargeArray.push({
68
- sub1: {
69
- val: i,
70
- },
71
- sub2: new Date('2023-10-01T12:00:00.000Z'),
72
- sub3: {
73
- val: i + 1,
74
- valX: i + 2,
75
- },
76
- });
77
- }
78
- console.time('cloneDeepArrayRFDC');
79
- (0, cloneDeep_1.cloneDeep)(veryLargeArray);
80
- console.timeEnd('cloneDeepArrayRFDC');
81
- console.time('cloneDeepArrayLodash');
82
- (0, lodash_1.cloneDeep)(veryLargeArray);
83
- console.timeEnd('cloneDeepArrayLodash');
84
- console.time('cloneDeepArrayJson');
85
- jsonClone(veryLargeArray);
86
- console.timeEnd('cloneDeepArrayJson');
87
- console.time('structuredCloneArray');
88
- structuredClone(veryLargeArray);
89
- console.timeEnd('structuredCloneArray');
90
- console.log('\n\nPerformance test for assortment.json:');
91
- const fs = require("fs");
92
- const path = require("path");
93
- const assortmentFilePath = path.join(__dirname, 'assortment.json');
94
- const assortmentData = JSON.parse(fs.readFileSync(assortmentFilePath, 'utf8'));
95
- console.time('cloneDeepAssortment25kRFDC');
96
- (0, cloneDeep_1.cloneDeep)(assortmentData);
97
- console.timeEnd('cloneDeepAssortment25kRFDC');
98
- console.time('cloneDeepAssortment25kLodash');
99
- (0, lodash_1.cloneDeep)(assortmentData);
100
- console.timeEnd('cloneDeepAssortment25kLodash');
101
- console.time('cloneDeepAssortment25kJson');
102
- jsonClone(assortmentData);
103
- console.timeEnd('cloneDeepAssortment25kJson');
104
- console.time('structuredCloneAssortment25k');
105
- structuredClone(assortmentData);
106
- console.timeEnd('structuredCloneAssortment25k');