Skip to content

Commit 1fa6d3d

Browse files
author
John Doe
committed
refactor: add extensibility API helper
1 parent 9d4a223 commit 1fa6d3d

File tree

4 files changed

+618
-1
lines changed

4 files changed

+618
-1
lines changed

packages/utils/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@
2424
},
2525
"type": "module",
2626
"engines": {
27-
"node": ">=17.0.0"
27+
"node": ">=18.2.0"
2828
},
2929
"dependencies": {
3030
"@code-pushup/models": "0.101.1",
Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
import type {
2+
DevToolsColor,
3+
DevToolsProperties,
4+
EntryMeta,
5+
MarkOptionsWithDevtools,
6+
MarkerPayload,
7+
MeasureOptionsWithDevtools,
8+
TrackEntryPayload,
9+
} from './user-timing-extensibility-api.type.js';
10+
11+
const dataTypeTrackEntry = 'track-entry';
12+
13+
export function objToPropertiesPayload(
14+
object: Record<string, string | number | boolean | object | undefined>,
15+
): DevToolsProperties {
16+
return Object.entries(object);
17+
}
18+
19+
export function mergePropertiesWithOverwrite(
20+
baseProperties: DevToolsProperties | undefined,
21+
overrideProperties?: DevToolsProperties | undefined,
22+
): DevToolsProperties {
23+
return objToPropertiesPayload({
24+
...Object.fromEntries(
25+
(baseProperties ?? []).map(([key, value]) => [key, String(value)]),
26+
),
27+
...Object.fromEntries(
28+
(overrideProperties ?? []).map(([key, value]) => [key, String(value)]),
29+
),
30+
});
31+
}
32+
33+
export function markerPayload(
34+
options?: Omit<MarkerPayload, 'dataType'>,
35+
): MarkerPayload {
36+
return {
37+
dataType: 'marker',
38+
...options,
39+
};
40+
}
41+
42+
export function trackEntryPayload(
43+
options: Omit<TrackEntryPayload, 'dataType'>,
44+
): TrackEntryPayload {
45+
const { track, ...rest } = options;
46+
return {
47+
dataType: dataTypeTrackEntry,
48+
track,
49+
...rest,
50+
};
51+
}
52+
53+
export function markerErrorPayload<T extends DevToolsColor>(
54+
options?: Omit<MarkerPayload, 'dataType' | 'color'>,
55+
): MarkerPayload {
56+
return {
57+
dataType: 'marker',
58+
color: 'error' as T,
59+
...options,
60+
} satisfies MarkerPayload;
61+
}
62+
63+
export function trackEntryErrorPayload<
64+
T extends string,
65+
C extends DevToolsColor,
66+
>(
67+
options: Omit<TrackEntryPayload, 'color' | 'dataType'> & {
68+
track: T;
69+
color?: C;
70+
},
71+
): TrackEntryPayload {
72+
const { track, color = 'error', ...restOptions } = options;
73+
return {
74+
dataType: dataTypeTrackEntry,
75+
color,
76+
track,
77+
...restOptions,
78+
} satisfies TrackEntryPayload;
79+
}
80+
81+
export function errorToDevToolsProperties(e: unknown): DevToolsProperties {
82+
const name = e instanceof Error ? e.name : 'UnknownError';
83+
const message = e instanceof Error ? e.message : String(e);
84+
return [
85+
['Error Type', name],
86+
['Error Message', message],
87+
];
88+
}
89+
90+
export function errorToEntryMeta(
91+
e: unknown,
92+
options?: {
93+
tooltipText?: string;
94+
properties?: DevToolsProperties;
95+
},
96+
): EntryMeta {
97+
const { properties, tooltipText } = options ?? {};
98+
const props = mergePropertiesWithOverwrite(
99+
errorToDevToolsProperties(e),
100+
properties,
101+
);
102+
return {
103+
properties: props,
104+
...(tooltipText ? { tooltipText } : {}),
105+
};
106+
}
107+
108+
export function errorToTrackEntryPayload<T extends string>(
109+
error: unknown,
110+
detail: Omit<TrackEntryPayload, 'color' | 'dataType'> & {
111+
track: T;
112+
},
113+
) {
114+
const { properties, tooltipText, ...trackPayload } = detail;
115+
return {
116+
dataType: dataTypeTrackEntry,
117+
color: 'error' as const,
118+
...trackPayload,
119+
...errorToEntryMeta(error, {
120+
properties,
121+
tooltipText,
122+
}),
123+
} satisfies TrackEntryPayload;
124+
}
125+
126+
export function errorToMarkerPayload<T extends DevToolsColor>(
127+
error: unknown,
128+
detail?: Omit<MarkerPayload, 'color' | 'dataType'>,
129+
): MarkerPayload {
130+
const { properties, tooltipText } = detail ?? {};
131+
return {
132+
dataType: 'marker',
133+
color: 'error' as T,
134+
...errorToEntryMeta(error, {
135+
properties,
136+
tooltipText,
137+
}),
138+
} satisfies MarkerPayload;
139+
}
140+
141+
/**
142+
*
143+
* @example
144+
* profiler.mark('mark', asOptions({
145+
* properties: [
146+
* ['str', 'This is a detail property'],
147+
* ['num', 42],
148+
* ['object', { str: '42', num: 42 }],
149+
* ['array', [42, 42, 42]],
150+
* ],
151+
* }));
152+
*/
153+
export function asOptions(
154+
devtools: MarkerPayload,
155+
): Pick<MarkOptionsWithDevtools, 'detail'>;
156+
export function asOptions(
157+
devtools: TrackEntryPayload,
158+
): Pick<MeasureOptionsWithDevtools, 'detail'>;
159+
export function asOptions(
160+
devtools: MarkerPayload | TrackEntryPayload,
161+
):
162+
| Pick<MarkOptionsWithDevtools, 'detail'>
163+
| Pick<MeasureOptionsWithDevtools, 'detail'> {
164+
return devtools ? { detail: { devtools } } : { detail: {} };
165+
}

0 commit comments

Comments
 (0)