1010 * then mapping to incremental values starting from mocked epoch clock base,
1111 * while preserving the original order of events in the output.
1212 *
13- * @param jsonlContent - JSONL string content (one JSON object per line)
13+ * @param jsonlContent - JSONL string content (one JSON object per line) or parsed JSON object/array
1414 * @param baseTimestampUs - Base timestamp in microseconds to start incrementing from (default: 1_700_000_005_000_000)
1515 * @returns Normalized JSONL string with deterministic pid, tid, and ts values
1616 */
1717export function omitTraceJson (
18- jsonlContent : string ,
18+ jsonlContent : string | object ,
1919 baseTimestampUs = 1_700_000_005_000_000 ,
2020) : string {
21- if ( ! jsonlContent . trim ( ) ) {
21+ if ( typeof jsonlContent !== 'string' ) {
22+ const eventsArray = Array . isArray ( jsonlContent )
23+ ? jsonlContent
24+ : [ jsonlContent ] ;
25+ if ( eventsArray . length === 0 ) {
26+ return '' ;
27+ }
28+ const events = eventsArray as TraceEvent [ ] ;
29+ return normalizeAndFormatEvents ( events , baseTimestampUs ) ;
30+ }
31+
32+ // Handle string input (JSONL format)
33+ const trimmedContent = jsonlContent . trim ( ) ;
34+ if ( ! trimmedContent ) {
2235 return jsonlContent ;
2336 }
2437
2538 // Parse all events from JSONL
26- const events = jsonlContent
27- . trim ( )
39+ const events = trimmedContent
2840 . split ( '\n' )
2941 . filter ( Boolean )
3042 . map ( line => JSON . parse ( line ) as TraceEvent ) ;
@@ -33,46 +45,85 @@ export function omitTraceJson(
3345 return jsonlContent ;
3446 }
3547
36- // Collect unique pid and tid values
37- const uniquePids = new Set < number > ( ) ;
38- const uniqueTids = new Set < number > ( ) ;
39- const timestamps : number [ ] = [ ] ;
40- const uniqueLocalIds = new Set < string > ( ) ;
41-
42- for ( const event of events ) {
43- if ( typeof event . pid === 'number' ) {
44- uniquePids . add ( event . pid ) ;
45- }
46- if ( typeof event . tid === 'number' ) {
47- uniqueTids . add ( event . tid ) ;
48- }
49- if ( typeof event . ts === 'number' ) {
50- timestamps . push ( event . ts ) ;
51- }
52- // Collect id2.local values
53- if (
54- event . id2 &&
55- typeof event . id2 === 'object' &&
56- 'local' in event . id2 &&
57- typeof event . id2 . local === 'string'
58- ) {
59- uniqueLocalIds . add ( event . id2 . local ) ;
60- }
48+ return normalizeAndFormatEvents ( events , baseTimestampUs ) ;
49+ }
50+
51+ /**
52+ * Normalizes trace events and formats them as JSONL.
53+ */
54+ function normalizeAndFormatEvents (
55+ events : TraceEvent [ ] ,
56+ baseTimestampUs : number ,
57+ ) : string {
58+ if ( events . length === 0 ) {
59+ return '' ;
6160 }
6261
62+ // Collect unique pid and tid values
63+ type Accumulator = {
64+ uniquePids : Set < number > ;
65+ uniqueTids : Set < number > ;
66+ timestamps : number [ ] ;
67+ uniqueLocalIds : Set < string > ;
68+ } ;
69+
70+ const { uniquePids, uniqueTids, timestamps, uniqueLocalIds } =
71+ events . reduce < Accumulator > (
72+ ( acc , event ) => {
73+ const newUniquePids = new Set ( acc . uniquePids ) ;
74+ const newUniqueTids = new Set ( acc . uniqueTids ) ;
75+ const newUniqueLocalIds = new Set ( acc . uniqueLocalIds ) ;
76+
77+ if ( typeof event . pid === 'number' ) {
78+ newUniquePids . add ( event . pid ) ;
79+ }
80+ if ( typeof event . tid === 'number' ) {
81+ newUniqueTids . add ( event . tid ) ;
82+ }
83+
84+ const newTimestamps =
85+ typeof event . ts === 'number'
86+ ? [ ...acc . timestamps , event . ts ]
87+ : acc . timestamps ;
88+
89+ // Collect id2.local values
90+ if (
91+ event . id2 &&
92+ typeof event . id2 === 'object' &&
93+ 'local' in event . id2 &&
94+ typeof event . id2 . local === 'string'
95+ ) {
96+ newUniqueLocalIds . add ( event . id2 . local ) ;
97+ }
98+
99+ return {
100+ uniquePids : newUniquePids ,
101+ uniqueTids : newUniqueTids ,
102+ timestamps : newTimestamps ,
103+ uniqueLocalIds : newUniqueLocalIds ,
104+ } ;
105+ } ,
106+ {
107+ uniquePids : new Set < number > ( ) ,
108+ uniqueTids : new Set < number > ( ) ,
109+ timestamps : [ ] as number [ ] ,
110+ uniqueLocalIds : new Set < string > ( ) ,
111+ } ,
112+ ) ;
113+
63114 // Create mappings: original value -> normalized incremental value
64115 const pidMap = new Map < number , number > ( ) ;
65116 const tidMap = new Map < number , number > ( ) ;
66117 const localIdMap = new Map < string , string > ( ) ;
67118
68119 // Sort unique values to ensure consistent mapping order
69- const sortedPids = Array . from ( uniquePids ) . sort ( ( a , b ) => a - b ) ;
70- const sortedTids = Array . from ( uniqueTids ) . sort ( ( a , b ) => a - b ) ;
71- const sortedLocalIds = Array . from ( uniqueLocalIds ) . sort ( ) ;
120+ const sortedPids = [ ... uniquePids ] . sort ( ( a , b ) => a - b ) ;
121+ const sortedTids = [ ... uniqueTids ] . sort ( ( a , b ) => a - b ) ;
122+ const sortedLocalIds = [ ... uniqueLocalIds ] . sort ( ) ;
72123
73124 // Map pids starting from 10001
74125 sortedPids . forEach ( ( pid , index ) => {
75- pidMap . set ( pid , 10001 + index ) ;
126+ pidMap . set ( pid , 10_001 + index ) ;
76127 } ) ;
77128
78129 // Map tids starting from 1
@@ -87,50 +138,58 @@ export function omitTraceJson(
87138
88139 // Sort timestamps to determine incremental order
89140 const sortedTimestamps = [ ...timestamps ] . sort ( ( a , b ) => a - b ) ;
90- const tsMap = new Map < number , number > ( ) ;
91141
92142 // Map timestamps incrementally starting from baseTimestampUs
93- sortedTimestamps . forEach ( ( ts , index ) => {
94- if ( ! tsMap . has ( ts ) ) {
95- tsMap . set ( ts , baseTimestampUs + index ) ;
143+ const tsMap = sortedTimestamps . reduce ( ( map , ts , index ) => {
144+ if ( ! map . has ( ts ) ) {
145+ return new Map ( map ) . set ( ts , baseTimestampUs + index ) ;
96146 }
97- } ) ;
147+ return map ;
148+ } , new Map < number , number > ( ) ) ;
98149
99150 // Normalize events while preserving original order
100151 const normalizedEvents = events . map ( event => {
101- const normalized : TraceEvent = { ...event } ;
152+ const pidUpdate =
153+ typeof event . pid === 'number' && pidMap . has ( event . pid )
154+ ? { pid : pidMap . get ( event . pid ) ! }
155+ : { } ;
102156
103- if ( typeof normalized . pid === 'number' && pidMap . has ( normalized . pid ) ) {
104- normalized . pid = pidMap . get ( normalized . pid ) ! ;
105- }
157+ const tidUpdate =
158+ typeof event . tid === 'number' && tidMap . has ( event . tid )
159+ ? { tid : tidMap . get ( event . tid ) ! }
160+ : { } ;
106161
107- if ( typeof normalized . tid === 'number' && tidMap . has ( normalized . tid ) ) {
108- normalized . tid = tidMap . get ( normalized . tid ) ! ;
109- }
110-
111- if ( typeof normalized . ts === 'number' && tsMap . has ( normalized . ts ) ) {
112- normalized . ts = tsMap . get ( normalized . ts ) ! ;
113- }
162+ const tsUpdate =
163+ typeof event . ts === 'number' && tsMap . has ( event . ts )
164+ ? { ts : tsMap . get ( event . ts ) ! }
165+ : { } ;
114166
115167 // Normalize id2.local if present
116- if (
117- normalized . id2 &&
118- typeof normalized . id2 === 'object' &&
119- 'local' in normalized . id2 &&
120- typeof normalized . id2 . local === 'string' &&
121- localIdMap . has ( normalized . id2 . local )
122- ) {
123- normalized . id2 = {
124- ...normalized . id2 ,
125- local : localIdMap . get ( normalized . id2 . local ) ! ,
126- } ;
127- }
128-
129- return normalized ;
168+ const id2Update =
169+ event . id2 &&
170+ typeof event . id2 === 'object' &&
171+ 'local' in event . id2 &&
172+ typeof event . id2 . local === 'string' &&
173+ localIdMap . has ( event . id2 . local )
174+ ? {
175+ id2 : {
176+ ...event . id2 ,
177+ local : localIdMap . get ( event . id2 . local ) ! ,
178+ } ,
179+ }
180+ : { } ;
181+
182+ return {
183+ ...event ,
184+ ...pidUpdate ,
185+ ...tidUpdate ,
186+ ...tsUpdate ,
187+ ...id2Update ,
188+ } ;
130189 } ) ;
131190
132191 // Convert back to JSONL format
133- return normalizedEvents . map ( event => JSON . stringify ( event ) ) . join ( '\n' ) + '\n' ;
192+ return ` ${ normalizedEvents . map ( event => JSON . stringify ( event ) ) . join ( '\n' ) } \n` ;
134193}
135194
136195/**
0 commit comments