@platforma-sdk/model 1.59.3 → 1.60.2
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/block_storage.cjs.map +1 -1
- package/dist/block_storage.d.ts +1 -11
- package/dist/block_storage.js.map +1 -1
- package/dist/block_storage_callbacks.cjs.map +1 -1
- package/dist/block_storage_callbacks.js.map +1 -1
- package/dist/columns/column_collection_builder.cjs +215 -0
- package/dist/columns/column_collection_builder.cjs.map +1 -0
- package/dist/columns/column_collection_builder.d.ts +112 -0
- package/dist/columns/column_collection_builder.js +214 -0
- package/dist/columns/column_collection_builder.js.map +1 -0
- package/dist/columns/column_selector.cjs +122 -0
- package/dist/columns/column_selector.cjs.map +1 -0
- package/dist/columns/column_selector.d.ts +41 -0
- package/dist/columns/column_selector.js +118 -0
- package/dist/columns/column_selector.js.map +1 -0
- package/dist/columns/column_snapshot.cjs +20 -0
- package/dist/columns/column_snapshot.cjs.map +1 -0
- package/dist/columns/column_snapshot.d.ts +39 -0
- package/dist/columns/column_snapshot.js +18 -0
- package/dist/columns/column_snapshot.js.map +1 -0
- package/dist/columns/column_snapshot_provider.cjs +112 -0
- package/dist/columns/column_snapshot_provider.cjs.map +1 -0
- package/dist/columns/column_snapshot_provider.d.ts +73 -0
- package/dist/columns/column_snapshot_provider.js +107 -0
- package/dist/columns/column_snapshot_provider.js.map +1 -0
- package/dist/columns/ctx_column_sources.cjs +84 -0
- package/dist/columns/ctx_column_sources.cjs.map +1 -0
- package/dist/columns/ctx_column_sources.d.ts +33 -0
- package/dist/columns/ctx_column_sources.js +82 -0
- package/dist/columns/ctx_column_sources.js.map +1 -0
- package/dist/columns/index.cjs +5 -0
- package/dist/columns/index.d.ts +5 -0
- package/dist/columns/index.js +5 -0
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs +111 -0
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.cjs.map +1 -0
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.d.ts +25 -0
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js +110 -0
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV2.js.map +1 -0
- package/dist/components/PlDataTable/{table.cjs → createPlDataTable/createPlDataTableV3.cjs} +54 -54
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.cjs.map +1 -0
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.d.ts +39 -0
- package/dist/components/PlDataTable/{table.js → createPlDataTable/createPlDataTableV3.js} +53 -53
- package/dist/components/PlDataTable/createPlDataTable/createPlDataTableV3.js.map +1 -0
- package/dist/components/PlDataTable/createPlDataTable/index.cjs +12 -0
- package/dist/components/PlDataTable/createPlDataTable/index.cjs.map +1 -0
- package/dist/components/PlDataTable/createPlDataTable/index.d.ts +15 -0
- package/dist/components/PlDataTable/createPlDataTable/index.js +12 -0
- package/dist/components/PlDataTable/createPlDataTable/index.js.map +1 -0
- package/dist/components/PlDataTable/createPlDataTableSheet.cjs +18 -0
- package/dist/components/PlDataTable/createPlDataTableSheet.cjs.map +1 -0
- package/dist/components/PlDataTable/createPlDataTableSheet.d.ts +11 -0
- package/dist/components/PlDataTable/createPlDataTableSheet.js +17 -0
- package/dist/components/PlDataTable/createPlDataTableSheet.js.map +1 -0
- package/dist/components/PlDataTable/index.cjs +4 -1
- package/dist/components/PlDataTable/index.d.ts +5 -2
- package/dist/components/PlDataTable/index.js +4 -1
- package/dist/components/PlDataTable/state-migration.cjs.map +1 -1
- package/dist/components/PlDataTable/state-migration.d.ts +2 -2
- package/dist/components/PlDataTable/state-migration.js.map +1 -1
- package/dist/components/PlDataTable/{v4.d.ts → typesV4.d.ts} +2 -2
- package/dist/components/PlDataTable/{v5.d.ts → typesV5.d.ts} +2 -2
- package/dist/components/index.cjs +4 -1
- package/dist/components/index.d.ts +5 -2
- package/dist/components/index.js +4 -1
- package/dist/index.cjs +44 -16
- package/dist/index.d.ts +17 -5
- package/dist/index.js +15 -3
- package/dist/labels/derive_distinct_labels.cjs +156 -0
- package/dist/labels/derive_distinct_labels.cjs.map +1 -0
- package/dist/labels/derive_distinct_labels.d.ts +29 -0
- package/dist/labels/derive_distinct_labels.js +155 -0
- package/dist/labels/derive_distinct_labels.js.map +1 -0
- package/dist/labels/index.cjs +2 -0
- package/dist/labels/index.d.ts +2 -0
- package/dist/labels/index.js +2 -0
- package/dist/labels/write_labels_to_specs.cjs +15 -0
- package/dist/labels/write_labels_to_specs.cjs.map +1 -0
- package/dist/labels/write_labels_to_specs.d.ts +9 -0
- package/dist/labels/write_labels_to_specs.js +14 -0
- package/dist/labels/write_labels_to_specs.js.map +1 -0
- package/dist/package.cjs +1 -1
- package/dist/package.js +1 -1
- package/dist/render/api.cjs +11 -2
- package/dist/render/api.cjs.map +1 -1
- package/dist/render/api.d.ts +9 -5
- package/dist/render/api.js +12 -3
- package/dist/render/api.js.map +1 -1
- package/dist/render/index.d.ts +2 -1
- package/dist/render/index.js +1 -1
- package/dist/render/internal.cjs.map +1 -1
- package/dist/render/internal.d.ts +5 -2
- package/dist/render/internal.js.map +1 -1
- package/dist/render/util/column_collection.cjs +3 -3
- package/dist/render/util/column_collection.cjs.map +1 -1
- package/dist/render/util/column_collection.d.ts +3 -2
- package/dist/render/util/column_collection.js +4 -4
- package/dist/render/util/column_collection.js.map +1 -1
- package/dist/render/util/index.d.ts +2 -1
- package/dist/render/util/index.js +1 -1
- package/dist/render/util/label.cjs +7 -134
- package/dist/render/util/label.cjs.map +1 -1
- package/dist/render/util/label.d.ts +5 -50
- package/dist/render/util/label.js +8 -132
- package/dist/render/util/label.js.map +1 -1
- package/dist/render/util/split_selectors.d.ts +2 -2
- package/package.json +9 -7
- package/src/block_storage.ts +0 -11
- package/src/block_storage_callbacks.ts +1 -1
- package/src/columns/column_collection_builder.test.ts +427 -0
- package/src/columns/column_collection_builder.ts +455 -0
- package/src/columns/column_selector.test.ts +472 -0
- package/src/columns/column_selector.ts +212 -0
- package/src/columns/column_snapshot.ts +55 -0
- package/src/columns/column_snapshot_provider.ts +177 -0
- package/src/columns/ctx_column_sources.ts +107 -0
- package/src/columns/expand_by_partition.test.ts +289 -0
- package/src/columns/expand_by_partition.ts +187 -0
- package/src/columns/index.ts +5 -0
- package/src/components/PlDataTable/createPlDataTable/createPlDataTableV2.ts +193 -0
- package/src/components/PlDataTable/{table.ts → createPlDataTable/createPlDataTableV3.ts} +134 -70
- package/src/components/PlDataTable/createPlDataTable/index.ts +27 -0
- package/src/components/PlDataTable/createPlDataTableSheet.ts +20 -0
- package/src/components/PlDataTable/index.ts +6 -4
- package/src/components/PlDataTable/state-migration.ts +2 -2
- package/src/index.ts +2 -1
- package/src/labels/derive_distinct_labels.test.ts +461 -0
- package/src/labels/derive_distinct_labels.ts +289 -0
- package/src/labels/index.ts +2 -0
- package/src/labels/write_labels_to_specs.ts +12 -0
- package/src/render/api.ts +25 -3
- package/src/render/internal.ts +20 -1
- package/src/render/util/column_collection.ts +9 -6
- package/src/render/util/label.test.ts +1 -1
- package/src/render/util/label.ts +19 -235
- package/src/render/util/split_selectors.ts +3 -3
- package/dist/components/PlDataTable/table.cjs.map +0 -1
- package/dist/components/PlDataTable/table.d.ts +0 -30
- package/dist/components/PlDataTable/table.js.map +0 -1
- /package/src/components/PlDataTable/{v4.ts → typesV4.ts} +0 -0
- /package/src/components/PlDataTable/{v5.ts → typesV5.ts} +0 -0
|
@@ -0,0 +1,461 @@
|
|
|
1
|
+
import { Annotation, type PColumnSpec } from "@milaboratories/pl-model-common";
|
|
2
|
+
import { expect, test } from "vitest";
|
|
3
|
+
import { deriveDistinctLabels, type Entry, type Trace } from "./derive_distinct_labels";
|
|
4
|
+
|
|
5
|
+
function tracesToSpecs(traces: Trace[]) {
|
|
6
|
+
return traces.map(
|
|
7
|
+
(t) =>
|
|
8
|
+
({
|
|
9
|
+
kind: "PColumn",
|
|
10
|
+
name: "name",
|
|
11
|
+
valueType: "Int",
|
|
12
|
+
annotations: {
|
|
13
|
+
[Annotation.Trace]: JSON.stringify(t),
|
|
14
|
+
[Annotation.Label]: "Label",
|
|
15
|
+
},
|
|
16
|
+
axesSpec: [],
|
|
17
|
+
}) satisfies PColumnSpec,
|
|
18
|
+
);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function createSpec(overrides: Partial<PColumnSpec> = {}): PColumnSpec {
|
|
22
|
+
return {
|
|
23
|
+
kind: "PColumn",
|
|
24
|
+
name: "name",
|
|
25
|
+
valueType: "Int",
|
|
26
|
+
annotations: {},
|
|
27
|
+
axesSpec: [],
|
|
28
|
+
...overrides,
|
|
29
|
+
} as PColumnSpec;
|
|
30
|
+
}
|
|
31
|
+
test.each<{ name: string; traces: Trace[]; labels: string[] }>([
|
|
32
|
+
{
|
|
33
|
+
name: "simple",
|
|
34
|
+
traces: [[{ type: "t1", label: "L1" }], [{ type: "t1", label: "L2" }]],
|
|
35
|
+
labels: ["L1", "L2"],
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
name: "later wins",
|
|
39
|
+
traces: [
|
|
40
|
+
[
|
|
41
|
+
{ type: "t1", label: "T1L1" },
|
|
42
|
+
{ type: "t2", label: "T2L1" },
|
|
43
|
+
],
|
|
44
|
+
[
|
|
45
|
+
{ type: "t1", label: "T1L2" },
|
|
46
|
+
{ type: "t2", label: "T2L2" },
|
|
47
|
+
],
|
|
48
|
+
],
|
|
49
|
+
labels: ["T2L1", "T2L2"],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: "importance wins",
|
|
53
|
+
traces: [
|
|
54
|
+
[
|
|
55
|
+
{ type: "t1", importance: 100, label: "T1L1" },
|
|
56
|
+
{ type: "t2", label: "T2L1" },
|
|
57
|
+
],
|
|
58
|
+
[
|
|
59
|
+
{ type: "t1", importance: 100, label: "T1L2" },
|
|
60
|
+
{ type: "t2", label: "T2L2" },
|
|
61
|
+
],
|
|
62
|
+
],
|
|
63
|
+
labels: ["T1L1", "T1L2"],
|
|
64
|
+
},
|
|
65
|
+
{
|
|
66
|
+
name: "uniqueness wins",
|
|
67
|
+
traces: [
|
|
68
|
+
[
|
|
69
|
+
{ type: "t1", label: "T1L1" },
|
|
70
|
+
{ type: "t2", label: "T2L1" },
|
|
71
|
+
],
|
|
72
|
+
[
|
|
73
|
+
{ type: "t1", label: "T1L2" },
|
|
74
|
+
{ type: "t2", label: "T2L1" },
|
|
75
|
+
],
|
|
76
|
+
],
|
|
77
|
+
labels: ["T1L1", "T1L2"],
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
name: "combinatoric solution",
|
|
81
|
+
traces: [
|
|
82
|
+
[
|
|
83
|
+
{ type: "t1", label: "T1L1" },
|
|
84
|
+
{ type: "t2", label: "T2L1" },
|
|
85
|
+
],
|
|
86
|
+
[
|
|
87
|
+
{ type: "t1", label: "T1L1" },
|
|
88
|
+
{ type: "t2", label: "T2L2" },
|
|
89
|
+
],
|
|
90
|
+
[
|
|
91
|
+
{ type: "t1", label: "T1L2" },
|
|
92
|
+
{ type: "t2", label: "T2L2" },
|
|
93
|
+
],
|
|
94
|
+
],
|
|
95
|
+
labels: ["T1L1 / T2L1", "T1L1 / T2L2", "T1L2 / T2L2"],
|
|
96
|
+
},
|
|
97
|
+
{
|
|
98
|
+
name: "different importance and id",
|
|
99
|
+
traces: [
|
|
100
|
+
[{ type: "sameType", importance: 10, id: "id1", label: "High importance" }],
|
|
101
|
+
[{ type: "sameType", importance: 5, id: "id2", label: "Low importance" }],
|
|
102
|
+
],
|
|
103
|
+
labels: ["High importance", "Low importance"],
|
|
104
|
+
},
|
|
105
|
+
{
|
|
106
|
+
name: "mixed common and different entries",
|
|
107
|
+
traces: [
|
|
108
|
+
[
|
|
109
|
+
{ type: "commonType", importance: 1, id: "common", label: "Common entry" },
|
|
110
|
+
{ type: "uniqueType", importance: 10, id: "id1", label: "Unique entry 1" },
|
|
111
|
+
],
|
|
112
|
+
[
|
|
113
|
+
{ type: "commonType", importance: 1, id: "common", label: "Common entry" },
|
|
114
|
+
{ type: "uniqueType", importance: 5, id: "id2", label: "Unique entry 2" },
|
|
115
|
+
],
|
|
116
|
+
],
|
|
117
|
+
labels: ["Unique entry 1", "Unique entry 2"],
|
|
118
|
+
},
|
|
119
|
+
])("test label derivation: $name", ({ traces, labels }) => {
|
|
120
|
+
expect(deriveDistinctLabels(tracesToSpecs(traces)).map((r) => r.label)).toEqual(labels);
|
|
121
|
+
expect(
|
|
122
|
+
deriveDistinctLabels(tracesToSpecs(traces), { includeNativeLabel: true }).map((r) => r.label),
|
|
123
|
+
).toEqual(labels.map((l) => "Label / " + l));
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
test("test fallback to native labels in label derivation", () => {
|
|
127
|
+
expect(deriveDistinctLabels(tracesToSpecs([[], []])).map((r) => r.label)).toEqual([
|
|
128
|
+
"Label",
|
|
129
|
+
"Label",
|
|
130
|
+
]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
test.each<{ name: string; traces: Trace[]; labels: string[] }>([
|
|
134
|
+
{
|
|
135
|
+
name: "removes redundant low-importance type when high-importance alone suffices",
|
|
136
|
+
traces: [
|
|
137
|
+
[
|
|
138
|
+
{ type: "t1", importance: 10, label: "High1" },
|
|
139
|
+
{ type: "t2", importance: 1, label: "Low1" },
|
|
140
|
+
],
|
|
141
|
+
[
|
|
142
|
+
{ type: "t1", importance: 10, label: "High2" },
|
|
143
|
+
{ type: "t2", importance: 1, label: "Low2" },
|
|
144
|
+
],
|
|
145
|
+
],
|
|
146
|
+
// Both t1 and t2 distinguish, but t2 (low importance) should be removed since t1 alone suffices
|
|
147
|
+
labels: ["High1", "High2"],
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
name: "keeps both types when both are needed for uniqueness",
|
|
151
|
+
traces: [
|
|
152
|
+
[
|
|
153
|
+
{ type: "t1", importance: 10, label: "A" },
|
|
154
|
+
{ type: "t2", importance: 1, label: "X" },
|
|
155
|
+
],
|
|
156
|
+
[
|
|
157
|
+
{ type: "t1", importance: 10, label: "A" },
|
|
158
|
+
{ type: "t2", importance: 1, label: "Y" },
|
|
159
|
+
],
|
|
160
|
+
[
|
|
161
|
+
{ type: "t1", importance: 10, label: "B" },
|
|
162
|
+
{ type: "t2", importance: 1, label: "Y" },
|
|
163
|
+
],
|
|
164
|
+
],
|
|
165
|
+
// Neither t1 nor t2 alone can distinguish all three, need both
|
|
166
|
+
labels: ["A / X", "A / Y", "B / Y"],
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
name: "removes multiple redundant types greedily",
|
|
170
|
+
traces: [
|
|
171
|
+
[
|
|
172
|
+
{ type: "t1", importance: 100, label: "Unique1" },
|
|
173
|
+
{ type: "t2", importance: 10, label: "Same" },
|
|
174
|
+
{ type: "t3", importance: 1, label: "Same" },
|
|
175
|
+
],
|
|
176
|
+
[
|
|
177
|
+
{ type: "t1", importance: 100, label: "Unique2" },
|
|
178
|
+
{ type: "t2", importance: 10, label: "Same" },
|
|
179
|
+
{ type: "t3", importance: 1, label: "Same" },
|
|
180
|
+
],
|
|
181
|
+
],
|
|
182
|
+
// t1 alone distinguishes; t2 and t3 are redundant and should be removed
|
|
183
|
+
labels: ["Unique1", "Unique2"],
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
name: "fallback case: removes types that do not reduce cardinality",
|
|
187
|
+
traces: [
|
|
188
|
+
// Two columns with identical traces - cannot be distinguished
|
|
189
|
+
[
|
|
190
|
+
{ type: "t1", importance: 100, label: "A" },
|
|
191
|
+
{ type: "t2", importance: 10, label: "X" },
|
|
192
|
+
{ type: "t3", importance: 1, label: "Same" },
|
|
193
|
+
],
|
|
194
|
+
[
|
|
195
|
+
{ type: "t1", importance: 100, label: "A" },
|
|
196
|
+
{ type: "t2", importance: 10, label: "X" },
|
|
197
|
+
{ type: "t3", importance: 1, label: "Same" },
|
|
198
|
+
],
|
|
199
|
+
// Third column is different
|
|
200
|
+
[
|
|
201
|
+
{ type: "t1", importance: 100, label: "B" },
|
|
202
|
+
{ type: "t2", importance: 10, label: "Y" },
|
|
203
|
+
{ type: "t3", importance: 1, label: "Same" },
|
|
204
|
+
],
|
|
205
|
+
],
|
|
206
|
+
// Cannot achieve full uniqueness (2 columns are identical), but t3 (Same) can be removed
|
|
207
|
+
// since it doesn't help distinguish anything. t1 alone gives cardinality 2.
|
|
208
|
+
labels: ["A", "A", "B"],
|
|
209
|
+
},
|
|
210
|
+
])("test label minimization: $name", ({ traces, labels }) => {
|
|
211
|
+
expect(deriveDistinctLabels(tracesToSpecs(traces)).map((r) => r.label)).toEqual(labels);
|
|
212
|
+
});
|
|
213
|
+
|
|
214
|
+
test.each<{ name: string; traces: Trace[]; labels: string[]; forceTraceElements: string[] }>([
|
|
215
|
+
{
|
|
216
|
+
name: "force one element",
|
|
217
|
+
traces: [
|
|
218
|
+
[
|
|
219
|
+
{ type: "t1", label: "T1L1" },
|
|
220
|
+
{ type: "t2", label: "T2L1" },
|
|
221
|
+
],
|
|
222
|
+
[
|
|
223
|
+
{ type: "t1", label: "T1L2" },
|
|
224
|
+
{ type: "t2", label: "T2L2" },
|
|
225
|
+
],
|
|
226
|
+
],
|
|
227
|
+
labels: ["T1L1", "T1L2"],
|
|
228
|
+
forceTraceElements: ["t1"],
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
name: "force multiple elements",
|
|
232
|
+
traces: [
|
|
233
|
+
[
|
|
234
|
+
{ type: "t1", label: "T1L1" },
|
|
235
|
+
{ type: "t2", label: "T2L1" },
|
|
236
|
+
{ type: "t3", label: "T3L1" },
|
|
237
|
+
],
|
|
238
|
+
[
|
|
239
|
+
{ type: "t1", label: "T1L2" },
|
|
240
|
+
{ type: "t2", label: "T2L2" },
|
|
241
|
+
{ type: "t3", label: "T3L2" },
|
|
242
|
+
],
|
|
243
|
+
],
|
|
244
|
+
labels: ["T1L1 / T3L1", "T1L2 / T3L2"],
|
|
245
|
+
forceTraceElements: ["t1", "t3"],
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
name: "force element not in all traces",
|
|
249
|
+
traces: [
|
|
250
|
+
[
|
|
251
|
+
{ type: "t1", label: "T1L1" },
|
|
252
|
+
{ type: "t2", label: "T2L1" },
|
|
253
|
+
],
|
|
254
|
+
[{ type: "t2", label: "T2L2" }],
|
|
255
|
+
],
|
|
256
|
+
labels: ["T1L1 / T2L1", "T2L2"],
|
|
257
|
+
forceTraceElements: ["t1"],
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
name: "force element with includeNativeLabel",
|
|
261
|
+
traces: [
|
|
262
|
+
[
|
|
263
|
+
{ type: "t1", label: "T1L1" },
|
|
264
|
+
{ type: "t2", label: "T2L1" },
|
|
265
|
+
],
|
|
266
|
+
[
|
|
267
|
+
{ type: "t1", label: "T1L2" },
|
|
268
|
+
{ type: "t2", label: "T2L2" },
|
|
269
|
+
],
|
|
270
|
+
],
|
|
271
|
+
labels: ["T1L1", "T1L2"],
|
|
272
|
+
forceTraceElements: ["t1"],
|
|
273
|
+
},
|
|
274
|
+
])(
|
|
275
|
+
"test label derivation with forceTraceElements: $name",
|
|
276
|
+
({ name, traces, labels, forceTraceElements }) => {
|
|
277
|
+
expect(
|
|
278
|
+
deriveDistinctLabels(tracesToSpecs(traces), { forceTraceElements }).map((r) => r.label),
|
|
279
|
+
).toEqual(labels);
|
|
280
|
+
|
|
281
|
+
if (name === "force element with includeNativeLabel") {
|
|
282
|
+
expect(
|
|
283
|
+
deriveDistinctLabels(tracesToSpecs(traces), {
|
|
284
|
+
forceTraceElements,
|
|
285
|
+
includeNativeLabel: true,
|
|
286
|
+
}).map((r) => r.label),
|
|
287
|
+
).toEqual(labels.map((l) => "Label / " + l));
|
|
288
|
+
}
|
|
289
|
+
},
|
|
290
|
+
);
|
|
291
|
+
|
|
292
|
+
// --- Entry with { spec, prefixTrace, suffixTrace } ---
|
|
293
|
+
|
|
294
|
+
test("Entry with prefixTrace prepends to labels", () => {
|
|
295
|
+
const spec = createSpec({
|
|
296
|
+
annotations: {
|
|
297
|
+
[Annotation.Trace]: JSON.stringify([{ type: "t1", label: "Base" }]),
|
|
298
|
+
},
|
|
299
|
+
});
|
|
300
|
+
const entries: Entry[] = [
|
|
301
|
+
{ spec, prefixTrace: [{ type: "prefix", label: "P1" }] },
|
|
302
|
+
{ spec, prefixTrace: [{ type: "prefix", label: "P2" }] },
|
|
303
|
+
];
|
|
304
|
+
const labels = deriveDistinctLabels(entries).map((r) => r.label);
|
|
305
|
+
expect(labels).toEqual(["P1", "P2"]);
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
test("Entry with suffixTrace appends to labels", () => {
|
|
309
|
+
const spec = createSpec({
|
|
310
|
+
annotations: {
|
|
311
|
+
[Annotation.Trace]: JSON.stringify([{ type: "t1", label: "Base" }]),
|
|
312
|
+
},
|
|
313
|
+
});
|
|
314
|
+
const entries: Entry[] = [
|
|
315
|
+
{ spec, suffixTrace: [{ type: "suffix", label: "S1" }] },
|
|
316
|
+
{ spec, suffixTrace: [{ type: "suffix", label: "S2" }] },
|
|
317
|
+
];
|
|
318
|
+
const labels = deriveDistinctLabels(entries).map((r) => r.label);
|
|
319
|
+
expect(labels).toEqual(["S1", "S2"]);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
test("Entry with both prefixTrace and suffixTrace", () => {
|
|
323
|
+
const spec1 = createSpec({
|
|
324
|
+
annotations: {
|
|
325
|
+
[Annotation.Trace]: JSON.stringify([{ type: "base", label: "Same" }]),
|
|
326
|
+
},
|
|
327
|
+
});
|
|
328
|
+
const entries: Entry[] = [
|
|
329
|
+
{
|
|
330
|
+
spec: spec1,
|
|
331
|
+
prefixTrace: [{ type: "pfx", label: "Pre1" }],
|
|
332
|
+
suffixTrace: [{ type: "sfx", label: "Suf1" }],
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
spec: spec1,
|
|
336
|
+
prefixTrace: [{ type: "pfx", label: "Pre2" }],
|
|
337
|
+
suffixTrace: [{ type: "sfx", label: "Suf2" }],
|
|
338
|
+
},
|
|
339
|
+
];
|
|
340
|
+
const labels = deriveDistinctLabels(entries).map((r) => r.label);
|
|
341
|
+
// suffix is later in the trace (higher positional importance), so it wins over prefix
|
|
342
|
+
expect(labels).toEqual(["Suf1", "Suf2"]);
|
|
343
|
+
});
|
|
344
|
+
|
|
345
|
+
// --- addLabelAsSuffix ---
|
|
346
|
+
|
|
347
|
+
test("addLabelAsSuffix places native label at the end", () => {
|
|
348
|
+
const specs = tracesToSpecs([[{ type: "t1", label: "L1" }], [{ type: "t1", label: "L2" }]]);
|
|
349
|
+
const labels = deriveDistinctLabels(specs, {
|
|
350
|
+
includeNativeLabel: true,
|
|
351
|
+
addLabelAsSuffix: true,
|
|
352
|
+
}).map((r) => r.label);
|
|
353
|
+
expect(labels).toEqual(["L1 / Label", "L2 / Label"]);
|
|
354
|
+
});
|
|
355
|
+
|
|
356
|
+
// --- separator ---
|
|
357
|
+
|
|
358
|
+
test("custom separator is used between label parts", () => {
|
|
359
|
+
const specs = tracesToSpecs([
|
|
360
|
+
[
|
|
361
|
+
{ type: "t1", label: "A" },
|
|
362
|
+
{ type: "t2", label: "X" },
|
|
363
|
+
],
|
|
364
|
+
[
|
|
365
|
+
{ type: "t1", label: "A" },
|
|
366
|
+
{ type: "t2", label: "Y" },
|
|
367
|
+
],
|
|
368
|
+
[
|
|
369
|
+
{ type: "t1", label: "B" },
|
|
370
|
+
{ type: "t2", label: "Y" },
|
|
371
|
+
],
|
|
372
|
+
]);
|
|
373
|
+
const labels = deriveDistinctLabels(specs, { separator: " - " }).map((r) => r.label);
|
|
374
|
+
expect(labels).toEqual(["A - X", "A - Y", "B - Y"]);
|
|
375
|
+
});
|
|
376
|
+
|
|
377
|
+
// --- single value ---
|
|
378
|
+
|
|
379
|
+
test("single value gets its trace label", () => {
|
|
380
|
+
const specs = tracesToSpecs([[{ type: "t1", label: "Only" }]]);
|
|
381
|
+
const labels = deriveDistinctLabels(specs).map((r) => r.label);
|
|
382
|
+
expect(labels).toEqual(["Only"]);
|
|
383
|
+
});
|
|
384
|
+
|
|
385
|
+
// --- Unlabeled fallback ---
|
|
386
|
+
|
|
387
|
+
test("Unlabeled fallback when no trace entries match", () => {
|
|
388
|
+
// Two identical specs with identical traces — fallback path
|
|
389
|
+
const spec = createSpec({
|
|
390
|
+
annotations: {
|
|
391
|
+
[Annotation.Trace]: JSON.stringify([{ type: "t1", label: "Same" }]),
|
|
392
|
+
},
|
|
393
|
+
});
|
|
394
|
+
// Remove native label so LABEL_TYPE is not added
|
|
395
|
+
delete spec.annotations![Annotation.Label];
|
|
396
|
+
|
|
397
|
+
const result = deriveDistinctLabels([spec, spec]);
|
|
398
|
+
expect(result.every((r) => r.label === "Same")).toBe(true);
|
|
399
|
+
});
|
|
400
|
+
|
|
401
|
+
test("Unlabeled when no traces and no label", () => {
|
|
402
|
+
const spec = createSpec();
|
|
403
|
+
const result = deriveDistinctLabels([spec, spec]);
|
|
404
|
+
expect(result.every((r) => r.label === "Unlabeled")).toBe(true);
|
|
405
|
+
});
|
|
406
|
+
|
|
407
|
+
// --- repeated type occurrences (secondaryTypes path) ---
|
|
408
|
+
|
|
409
|
+
test("repeated type occurrences are used as secondary types", () => {
|
|
410
|
+
// Two records where "t1" appears twice in each, with different labels on 2nd occurrence
|
|
411
|
+
const specs = tracesToSpecs([
|
|
412
|
+
[
|
|
413
|
+
{ type: "t1", label: "First" },
|
|
414
|
+
{ type: "t1", label: "A" },
|
|
415
|
+
],
|
|
416
|
+
[
|
|
417
|
+
{ type: "t1", label: "First" },
|
|
418
|
+
{ type: "t1", label: "B" },
|
|
419
|
+
],
|
|
420
|
+
]);
|
|
421
|
+
const labels = deriveDistinctLabels(specs).map((r) => r.label);
|
|
422
|
+
// t1@1 has label "First" for both (same), t1@2 has "A" vs "B" (distinguishing)
|
|
423
|
+
// t1@2 is secondary since it only appears when there are 2 occurrences
|
|
424
|
+
expect(labels).toEqual(["A", "B"]);
|
|
425
|
+
});
|
|
426
|
+
|
|
427
|
+
// --- spec without Annotation.Label (only Trace) ---
|
|
428
|
+
|
|
429
|
+
test("spec without native label uses only trace entries", () => {
|
|
430
|
+
const specs = [
|
|
431
|
+
createSpec({
|
|
432
|
+
annotations: {
|
|
433
|
+
[Annotation.Trace]: JSON.stringify([{ type: "t1", label: "X" }]),
|
|
434
|
+
},
|
|
435
|
+
}),
|
|
436
|
+
createSpec({
|
|
437
|
+
annotations: {
|
|
438
|
+
[Annotation.Trace]: JSON.stringify([{ type: "t1", label: "Y" }]),
|
|
439
|
+
},
|
|
440
|
+
}),
|
|
441
|
+
];
|
|
442
|
+
const labels = deriveDistinctLabels(specs).map((r) => r.label);
|
|
443
|
+
expect(labels).toEqual(["X", "Y"]);
|
|
444
|
+
});
|
|
445
|
+
|
|
446
|
+
test("includeNativeLabel with no native label does not break", () => {
|
|
447
|
+
const specs = [
|
|
448
|
+
createSpec({
|
|
449
|
+
annotations: {
|
|
450
|
+
[Annotation.Trace]: JSON.stringify([{ type: "t1", label: "X" }]),
|
|
451
|
+
},
|
|
452
|
+
}),
|
|
453
|
+
createSpec({
|
|
454
|
+
annotations: {
|
|
455
|
+
[Annotation.Trace]: JSON.stringify([{ type: "t1", label: "Y" }]),
|
|
456
|
+
},
|
|
457
|
+
}),
|
|
458
|
+
];
|
|
459
|
+
const labels = deriveDistinctLabels(specs, { includeNativeLabel: true }).map((r) => r.label);
|
|
460
|
+
expect(labels).toEqual(["X", "Y"]);
|
|
461
|
+
});
|