@platforma-sdk/model 1.53.10 → 1.53.13
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/annotations/converter.cjs +11 -11
- package/dist/annotations/converter.cjs.map +1 -1
- package/dist/annotations/converter.d.ts +1 -1
- package/dist/annotations/converter.d.ts.map +1 -1
- package/dist/annotations/converter.js +11 -11
- package/dist/annotations/converter.js.map +1 -1
- package/dist/annotations/index.d.ts +2 -2
- package/dist/annotations/types.d.ts +4 -4
- package/dist/bconfig/index.d.ts +5 -5
- package/dist/bconfig/lambdas.d.ts +7 -7
- package/dist/bconfig/lambdas.d.ts.map +1 -1
- package/dist/bconfig/normalization.cjs.map +1 -1
- package/dist/bconfig/normalization.d.ts +3 -3
- package/dist/bconfig/normalization.js.map +1 -1
- package/dist/bconfig/types.cjs.map +1 -1
- package/dist/bconfig/types.d.ts +2 -2
- package/dist/bconfig/types.d.ts.map +1 -1
- package/dist/bconfig/types.js.map +1 -1
- package/dist/bconfig/util.d.ts +4 -4
- package/dist/bconfig/v3.d.ts +3 -3
- package/dist/block_api_v1.d.ts +2 -2
- package/dist/block_api_v1.d.ts.map +1 -1
- package/dist/block_api_v2.d.ts +2 -2
- package/dist/block_api_v2.d.ts.map +1 -1
- package/dist/block_api_v3.d.ts +3 -3
- package/dist/block_migrations.cjs +10 -10
- package/dist/block_migrations.cjs.map +1 -1
- package/dist/block_migrations.d.ts.map +1 -1
- package/dist/block_migrations.js +10 -10
- package/dist/block_migrations.js.map +1 -1
- package/dist/block_model.cjs +11 -11
- package/dist/block_model.cjs.map +1 -1
- package/dist/block_model.d.ts +8 -8
- package/dist/block_model.d.ts.map +1 -1
- package/dist/block_model.js +11 -11
- package/dist/block_model.js.map +1 -1
- package/dist/block_state_patch.d.ts +2 -2
- package/dist/block_state_util.cjs +1 -1
- package/dist/block_state_util.cjs.map +1 -1
- package/dist/block_state_util.d.ts +3 -3
- package/dist/block_state_util.js +1 -1
- package/dist/block_state_util.js.map +1 -1
- package/dist/block_storage.cjs +10 -10
- package/dist/block_storage.cjs.map +1 -1
- package/dist/block_storage.d.ts +2 -2
- package/dist/block_storage.d.ts.map +1 -1
- package/dist/block_storage.js +10 -10
- package/dist/block_storage.js.map +1 -1
- package/dist/block_storage_vm.cjs +22 -22
- package/dist/block_storage_vm.cjs.map +1 -1
- package/dist/block_storage_vm.d.ts +1 -1
- package/dist/block_storage_vm.d.ts.map +1 -1
- package/dist/block_storage_vm.js +22 -22
- package/dist/block_storage_vm.js.map +1 -1
- package/dist/builder.cjs +32 -23
- package/dist/builder.cjs.map +1 -1
- package/dist/builder.d.ts +7 -7
- package/dist/builder.d.ts.map +1 -1
- package/dist/builder.js +32 -23
- package/dist/builder.js.map +1 -1
- package/dist/components/PFrameForGraphs.cjs +7 -6
- package/dist/components/PFrameForGraphs.cjs.map +1 -1
- package/dist/components/PFrameForGraphs.d.ts +4 -4
- package/dist/components/PFrameForGraphs.d.ts.map +1 -1
- package/dist/components/PFrameForGraphs.js +7 -6
- package/dist/components/PFrameForGraphs.js.map +1 -1
- package/dist/components/PlAnnotations/filter.d.ts +14 -14
- package/dist/components/PlAnnotations/filter.d.ts.map +1 -1
- package/dist/components/PlAnnotations/filters_ui.cjs +46 -46
- package/dist/components/PlAnnotations/filters_ui.cjs.map +1 -1
- package/dist/components/PlAnnotations/filters_ui.d.ts +10 -34
- package/dist/components/PlAnnotations/filters_ui.d.ts.map +1 -1
- package/dist/components/PlAnnotations/filters_ui.js +46 -46
- package/dist/components/PlAnnotations/filters_ui.js.map +1 -1
- package/dist/components/PlAnnotations/index.d.ts +2 -2
- package/dist/components/PlAnnotations/types.d.ts +2 -2
- package/dist/components/PlDataTable.cjs +19 -20
- package/dist/components/PlDataTable.cjs.map +1 -1
- package/dist/components/PlDataTable.d.ts +27 -27
- package/dist/components/PlDataTable.d.ts.map +1 -1
- package/dist/components/PlDataTable.js +19 -20
- package/dist/components/PlDataTable.js.map +1 -1
- package/dist/components/PlMultiSequenceAlignment.cjs +2 -2
- package/dist/components/PlMultiSequenceAlignment.cjs.map +1 -1
- package/dist/components/PlMultiSequenceAlignment.d.ts +6 -6
- package/dist/components/PlMultiSequenceAlignment.d.ts.map +1 -1
- package/dist/components/PlMultiSequenceAlignment.js +2 -2
- package/dist/components/PlMultiSequenceAlignment.js.map +1 -1
- package/dist/components/PlSelectionModel.cjs.map +1 -1
- package/dist/components/PlSelectionModel.d.ts +1 -1
- package/dist/components/PlSelectionModel.js.map +1 -1
- package/dist/components/index.d.ts +5 -5
- package/dist/config/actions.cjs +39 -39
- package/dist/config/actions.cjs.map +1 -1
- package/dist/config/actions.d.ts +9 -9
- package/dist/config/actions.d.ts.map +1 -1
- package/dist/config/actions.js +39 -39
- package/dist/config/actions.js.map +1 -1
- package/dist/config/actions_kinds.d.ts +30 -30
- package/dist/config/actions_kinds.d.ts.map +1 -1
- package/dist/config/index.d.ts +6 -6
- package/dist/config/model.d.ts +28 -28
- package/dist/config/model_meta.d.ts +1 -1
- package/dist/config/type_engine.d.ts +3 -3
- package/dist/config/type_util.d.ts +2 -2
- package/dist/env_value.cjs +1 -1
- package/dist/env_value.cjs.map +1 -1
- package/dist/env_value.js +1 -1
- package/dist/env_value.js.map +1 -1
- package/dist/filters/converter.cjs +36 -32
- package/dist/filters/converter.cjs.map +1 -1
- package/dist/filters/converter.d.ts +2 -2
- package/dist/filters/converter.d.ts.map +1 -1
- package/dist/filters/converter.js +36 -32
- package/dist/filters/converter.js.map +1 -1
- package/dist/filters/index.d.ts +2 -2
- package/dist/filters/types.d.ts +33 -33
- package/dist/filters/types.d.ts.map +1 -1
- package/dist/index.d.ts +24 -24
- package/dist/internal.cjs +7 -7
- package/dist/internal.cjs.map +1 -1
- package/dist/internal.d.ts +4 -4
- package/dist/internal.d.ts.map +1 -1
- package/dist/internal.js +7 -7
- package/dist/internal.js.map +1 -1
- package/dist/package.json.cjs +1 -1
- package/dist/package.json.js +1 -1
- package/dist/pframe.cjs +1 -1
- package/dist/pframe.cjs.map +1 -1
- package/dist/pframe.d.ts +1 -1
- package/dist/pframe.js +1 -1
- package/dist/pframe.js.map +1 -1
- package/dist/pframe_utils/columns.cjs +23 -15
- package/dist/pframe_utils/columns.cjs.map +1 -1
- package/dist/pframe_utils/columns.d.ts +3 -3
- package/dist/pframe_utils/columns.d.ts.map +1 -1
- package/dist/pframe_utils/columns.js +23 -15
- package/dist/pframe_utils/columns.js.map +1 -1
- package/dist/pframe_utils/index.cjs +25 -25
- package/dist/pframe_utils/index.cjs.map +1 -1
- package/dist/pframe_utils/index.d.ts +3 -3
- package/dist/pframe_utils/index.d.ts.map +1 -1
- package/dist/pframe_utils/index.js +25 -25
- package/dist/pframe_utils/index.js.map +1 -1
- package/dist/platforma.d.ts +7 -7
- package/dist/platforma.d.ts.map +1 -1
- package/dist/raw_globals.cjs +4 -1
- package/dist/raw_globals.cjs.map +1 -1
- package/dist/raw_globals.d.ts +2 -2
- package/dist/raw_globals.d.ts.map +1 -1
- package/dist/raw_globals.js +4 -1
- package/dist/raw_globals.js.map +1 -1
- package/dist/ref_util.cjs +4 -4
- package/dist/ref_util.cjs.map +1 -1
- package/dist/ref_util.d.ts +1 -1
- package/dist/ref_util.js +4 -4
- package/dist/ref_util.js.map +1 -1
- package/dist/render/accessor.cjs +24 -24
- package/dist/render/accessor.cjs.map +1 -1
- package/dist/render/accessor.d.ts +10 -10
- package/dist/render/accessor.d.ts.map +1 -1
- package/dist/render/accessor.js +24 -24
- package/dist/render/accessor.js.map +1 -1
- package/dist/render/api.cjs +23 -23
- package/dist/render/api.cjs.map +1 -1
- package/dist/render/api.d.ts +11 -11
- package/dist/render/api.d.ts.map +1 -1
- package/dist/render/api.js +23 -23
- package/dist/render/api.js.map +1 -1
- package/dist/render/future.cjs.map +1 -1
- package/dist/render/future.d.ts +1 -1
- package/dist/render/future.js.map +1 -1
- package/dist/render/index.d.ts +6 -6
- package/dist/render/internal.cjs +4 -4
- package/dist/render/internal.cjs.map +1 -1
- package/dist/render/internal.d.ts +7 -7
- package/dist/render/internal.d.ts.map +1 -1
- package/dist/render/internal.js +4 -4
- package/dist/render/internal.js.map +1 -1
- package/dist/render/traversal_ops.d.ts +1 -1
- package/dist/render/util/axis_filtering.cjs +48 -44
- package/dist/render/util/axis_filtering.cjs.map +1 -1
- package/dist/render/util/axis_filtering.d.ts +2 -2
- package/dist/render/util/axis_filtering.js +48 -44
- package/dist/render/util/axis_filtering.js.map +1 -1
- package/dist/render/util/column_collection.cjs +42 -35
- package/dist/render/util/column_collection.cjs.map +1 -1
- package/dist/render/util/column_collection.d.ts +4 -4
- package/dist/render/util/column_collection.d.ts.map +1 -1
- package/dist/render/util/column_collection.js +42 -35
- package/dist/render/util/column_collection.js.map +1 -1
- package/dist/render/util/index.d.ts +4 -4
- package/dist/render/util/label.cjs +15 -21
- package/dist/render/util/label.cjs.map +1 -1
- package/dist/render/util/label.d.ts +2 -2
- package/dist/render/util/label.d.ts.map +1 -1
- package/dist/render/util/label.js +15 -21
- package/dist/render/util/label.js.map +1 -1
- package/dist/render/util/pcolumn_data.cjs +56 -54
- package/dist/render/util/pcolumn_data.cjs.map +1 -1
- package/dist/render/util/pcolumn_data.d.ts +5 -5
- package/dist/render/util/pcolumn_data.d.ts.map +1 -1
- package/dist/render/util/pcolumn_data.js +56 -54
- package/dist/render/util/pcolumn_data.js.map +1 -1
- package/dist/render/util/pframe_upgraders.cjs +6 -6
- package/dist/render/util/pframe_upgraders.cjs.map +1 -1
- package/dist/render/util/pframe_upgraders.d.ts +1 -1
- package/dist/render/util/pframe_upgraders.d.ts.map +1 -1
- package/dist/render/util/pframe_upgraders.js +6 -6
- package/dist/render/util/pframe_upgraders.js.map +1 -1
- package/dist/render/util/split_selectors.d.ts +1 -1
- package/dist/render/util/split_selectors.d.ts.map +1 -1
- package/dist/sdk_info.cjs.map +1 -1
- package/dist/sdk_info.js.map +1 -1
- package/dist/version.cjs.map +1 -1
- package/dist/version.js.map +1 -1
- package/package.json +23 -21
- package/src/annotations/converter.test.ts +98 -101
- package/src/annotations/converter.ts +21 -17
- package/src/annotations/index.ts +2 -2
- package/src/annotations/types.ts +4 -4
- package/src/bconfig/index.ts +5 -5
- package/src/bconfig/lambdas.ts +10 -12
- package/src/bconfig/normalization.ts +5 -5
- package/src/bconfig/types.ts +3 -5
- package/src/bconfig/util.ts +3 -3
- package/src/bconfig/v3.ts +3 -3
- package/src/block_api_v1.ts +7 -3
- package/src/block_api_v2.ts +7 -3
- package/src/block_api_v3.ts +3 -3
- package/src/block_migrations.test.ts +66 -67
- package/src/block_migrations.ts +16 -16
- package/src/block_model.ts +76 -140
- package/src/block_state_patch.ts +2 -2
- package/src/block_state_util.ts +4 -4
- package/src/block_storage.test.ts +106 -99
- package/src/block_storage.ts +22 -25
- package/src/block_storage_vm.ts +41 -35
- package/src/builder.ts +107 -95
- package/src/components/PFrameForGraphs.test.ts +261 -255
- package/src/components/PFrameForGraphs.ts +35 -22
- package/src/components/PlAnnotations/filter.ts +21 -15
- package/src/components/PlAnnotations/filters_ui.test.ts +230 -73
- package/src/components/PlAnnotations/filters_ui.ts +138 -105
- package/src/components/PlAnnotations/index.ts +2 -2
- package/src/components/PlAnnotations/types.ts +2 -2
- package/src/components/PlDataTable.ts +177 -164
- package/src/components/PlMultiSequenceAlignment.ts +11 -18
- package/src/components/PlSelectionModel.ts +1 -1
- package/src/components/index.ts +5 -5
- package/src/config/actions.ts +64 -59
- package/src/config/actions_kinds.ts +38 -34
- package/src/config/index.ts +6 -6
- package/src/config/model.ts +28 -28
- package/src/config/model_meta.ts +1 -1
- package/src/config/type_engine.ts +3 -3
- package/src/config/type_util.ts +2 -2
- package/src/env_value.ts +2 -2
- package/src/filters/converter.test.ts +185 -144
- package/src/filters/converter.ts +47 -35
- package/src/filters/index.ts +2 -2
- package/src/filters/types.ts +44 -39
- package/src/global.d.ts +1 -1
- package/src/index.ts +24 -24
- package/src/internal.ts +27 -17
- package/src/pframe.ts +3 -3
- package/src/pframe_utils/columns.ts +81 -31
- package/src/pframe_utils/index.ts +65 -43
- package/src/platforma.ts +44 -21
- package/src/raw_globals.ts +13 -7
- package/src/ref_util.ts +6 -6
- package/src/render/accessor.ts +43 -44
- package/src/render/api.ts +102 -78
- package/src/render/future.ts +2 -2
- package/src/render/index.ts +6 -6
- package/src/render/internal.ts +11 -12
- package/src/render/traversal_ops.ts +1 -1
- package/src/render/util/axis_filtering.ts +67 -52
- package/src/render/util/column_collection.ts +171 -91
- package/src/render/util/index.ts +4 -4
- package/src/render/util/label.test.ts +139 -139
- package/src/render/util/label.ts +42 -33
- package/src/render/util/pcolumn_data.ts +111 -75
- package/src/render/util/pframe_upgraders.ts +24 -13
- package/src/render/util/split_selectors.ts +6 -1
- package/src/sdk_info.ts +1 -1
- package/src/typing.test.ts +56 -56
- package/src/version.ts +1 -1
|
@@ -11,11 +11,11 @@ const TraceEntry = zod.z.object({
|
|
|
11
11
|
});
|
|
12
12
|
const Trace = zod.z.array(TraceEntry);
|
|
13
13
|
const DistancePenalty = 0.001;
|
|
14
|
-
const LabelType =
|
|
15
|
-
const LabelTypeFull =
|
|
14
|
+
const LabelType = "__LABEL__";
|
|
15
|
+
const LabelTypeFull = "__LABEL__@1";
|
|
16
16
|
function deriveLabels(values, specExtractor, ops = {}) {
|
|
17
17
|
const importances = new Map();
|
|
18
|
-
const forceTraceElements =
|
|
18
|
+
const forceTraceElements = ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0
|
|
19
19
|
? new Set(ops.forceTraceElements)
|
|
20
20
|
: undefined;
|
|
21
21
|
// number of times certain type occurred among all of the
|
|
@@ -26,7 +26,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
26
26
|
let prefixTrace;
|
|
27
27
|
let suffixTrace;
|
|
28
28
|
// Check if the result is the new structure or just PObjectSpec
|
|
29
|
-
if (
|
|
29
|
+
if ("spec" in extractorResult && typeof extractorResult.spec === "object") {
|
|
30
30
|
// It's the new structure { spec, prefixTrace?, suffixTrace? }
|
|
31
31
|
spec = extractorResult.spec;
|
|
32
32
|
prefixTrace = extractorResult.prefixTrace;
|
|
@@ -39,11 +39,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
39
39
|
const label = plModelCommon.readAnnotation(spec, plModelCommon.Annotation.Label);
|
|
40
40
|
const traceStr = plModelCommon.readAnnotation(spec, plModelCommon.Annotation.Trace);
|
|
41
41
|
const baseTrace = (traceStr ? Trace.safeParse(plModelCommon.parseJson(traceStr)).data : undefined) ?? [];
|
|
42
|
-
const trace = [
|
|
43
|
-
...(prefixTrace ?? []),
|
|
44
|
-
...baseTrace,
|
|
45
|
-
...(suffixTrace ?? []),
|
|
46
|
-
];
|
|
42
|
+
const trace = [...(prefixTrace ?? []), ...baseTrace, ...(suffixTrace ?? [])];
|
|
47
43
|
if (label !== undefined) {
|
|
48
44
|
const labelEntry = { label, type: LabelType, importance: -2 };
|
|
49
45
|
if (ops.addLabelAsSuffix)
|
|
@@ -79,7 +75,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
79
75
|
// sorting: most important types go first
|
|
80
76
|
allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);
|
|
81
77
|
for (const [typeName] of allTypeRecords) {
|
|
82
|
-
if (typeName.endsWith(
|
|
78
|
+
if (typeName.endsWith("@1") || numberOfRecordsWithType.get(typeName) === values.length)
|
|
83
79
|
mainTypes.push(typeName);
|
|
84
80
|
else
|
|
85
81
|
secondaryTypes.push(typeName);
|
|
@@ -88,21 +84,18 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
88
84
|
const result = [];
|
|
89
85
|
for (let i = 0; i < enrichedRecords.length; i++) {
|
|
90
86
|
const r = enrichedRecords[i];
|
|
91
|
-
const includedTrace = r.fullTrace
|
|
92
|
-
.filter((fm) => includedTypes.has(fm.fullType)
|
|
93
|
-
|| (forceTraceElements && forceTraceElements.has(fm.type)));
|
|
87
|
+
const includedTrace = r.fullTrace.filter((fm) => includedTypes.has(fm.fullType) || (forceTraceElements && forceTraceElements.has(fm.type)));
|
|
94
88
|
if (includedTrace.length === 0) {
|
|
95
89
|
if (force)
|
|
96
90
|
result.push({
|
|
97
|
-
label:
|
|
91
|
+
label: "Unlabeled",
|
|
98
92
|
value: r.value,
|
|
99
93
|
});
|
|
100
94
|
else
|
|
101
95
|
return undefined;
|
|
102
96
|
}
|
|
103
|
-
const labelSet = includedTrace
|
|
104
|
-
|
|
105
|
-
const sep = ops.separator ?? ' / ';
|
|
97
|
+
const labelSet = includedTrace.map((fm) => fm.label);
|
|
98
|
+
const sep = ops.separator ?? " / ";
|
|
106
99
|
result.push({
|
|
107
100
|
label: labelSet.join(sep),
|
|
108
101
|
value: r.value,
|
|
@@ -121,14 +114,15 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
121
114
|
const currentCardinality = countUniqueLabels(initialResult);
|
|
122
115
|
// Get types sorted by importance ascending (lowest first), excluding forced elements
|
|
123
116
|
const removableSorted = [...typeSet]
|
|
124
|
-
.filter((t) => !forceTraceElements?.has(t.split(
|
|
125
|
-
|
|
117
|
+
.filter((t) => !forceTraceElements?.has(t.split("@")[0]) &&
|
|
118
|
+
!(ops.includeNativeLabel && t === LabelTypeFull))
|
|
126
119
|
.sort((a, b) => (importances.get(a) ?? 0) - (importances.get(b) ?? 0));
|
|
127
120
|
for (const typeToRemove of removableSorted) {
|
|
128
121
|
const reducedSet = new Set(typeSet);
|
|
129
122
|
reducedSet.delete(typeToRemove);
|
|
130
123
|
const candidateResult = calculate(reducedSet);
|
|
131
|
-
if (candidateResult !== undefined &&
|
|
124
|
+
if (candidateResult !== undefined &&
|
|
125
|
+
countUniqueLabels(candidateResult) >= currentCardinality) {
|
|
132
126
|
typeSet.delete(typeToRemove);
|
|
133
127
|
}
|
|
134
128
|
}
|
|
@@ -136,7 +130,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
136
130
|
};
|
|
137
131
|
if (mainTypes.length === 0) {
|
|
138
132
|
if (secondaryTypes.length !== 0)
|
|
139
|
-
throw new Error(
|
|
133
|
+
throw new Error("Non-empty secondary types list while main types list is empty.");
|
|
140
134
|
return calculate(new Set(LabelTypeFull), true);
|
|
141
135
|
}
|
|
142
136
|
//
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"label.cjs","sources":["../../../src/render/util/label.ts"],"sourcesContent":["import { Annotation, parseJson, readAnnotation, type PObjectSpec } from '@milaboratories/pl-model-common';\nimport { z } from 'zod';\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult = PObjectSpec | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n};\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = '__LABEL__';\nconst LabelTypeFull = '__LABEL__@1';\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements = (ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0)\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if ('spec' in extractorResult && typeof extractorResult.spec === 'object') {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = readAnnotation(spec, Annotation.Label);\n const traceStr = readAnnotation(spec, Annotation.Trace);\n const baseTrace = (traceStr ? Trace.safeParse(parseJson(traceStr)).data : undefined) ?? [];\n\n const trace = [\n ...(prefixTrace ?? []),\n ...baseTrace,\n ...(suffixTrace ?? []),\n ];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith('@1') || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace\n .filter((fm) => includedTypes.has(fm.fullType)\n || (forceTraceElements && forceTraceElements.has(fm.type)));\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: 'Unlabeled',\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace\n .map((fm) => fm.label);\n const sep = ops.separator ?? ' / ';\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n const countUniqueLabels = (result: RecordsWithLabel<T>[] | undefined): number =>\n result === undefined ? 0 : new Set(result.map((c) => c.label)).size;\n\n // Post-processing: try removing types one by one (lowest importance first) to minimize the label set\n // Accepts removal if it doesn't decrease the number of unique labels (cardinality)\n const minimizeTypeSet = (typeSet: Set<string>): Set<string> => {\n const initialResult = calculate(typeSet);\n if (initialResult === undefined) {\n return typeSet;\n }\n const currentCardinality = countUniqueLabels(initialResult);\n\n // Get types sorted by importance ascending (lowest first), excluding forced elements\n const removableSorted = [...typeSet]\n .filter((t) =>\n !forceTraceElements?.has(t.split('@')[0])\n && !(ops.includeNativeLabel && t === LabelTypeFull))\n .sort((a, b) => (importances.get(a) ?? 0) - (importances.get(b) ?? 0));\n\n for (const typeToRemove of removableSorted) {\n const reducedSet = new Set(typeSet);\n reducedSet.delete(typeToRemove);\n const candidateResult = calculate(reducedSet);\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) >= currentCardinality) {\n typeSet.delete(typeToRemove);\n }\n }\n return typeSet;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0) throw new Error('Non-empty secondary types list while main types list is empty.');\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0)\n currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) === values.length) {\n minimizeTypeSet(currentSet);\n return calculate(currentSet)!;\n }\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n // Fallback: include all types, then try to minimize\n const fallbackSet = new Set([...mainTypes, ...secondaryTypes]);\n minimizeTypeSet(fallbackSet);\n return calculate(fallbackSet, true)!;\n}\n"],"names":["z","readAnnotation","Annotation","parseJson"],"mappings":";;;;;AAmBO,MAAM,UAAU,GAAGA,KAAC,CAAC,MAAM,CAAC;AACjC,IAAA,IAAI,EAAEA,KAAC,CAAC,MAAM,EAAE;AAChB,IAAA,UAAU,EAAEA,KAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;AACjC,IAAA,EAAE,EAAEA,KAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;AACzB,IAAA,KAAK,EAAEA,KAAC,CAAC,MAAM,EAAE;AAClB,CAAA;AAIM,MAAM,KAAK,GAAGA,KAAC,CAAC,KAAK,CAAC,UAAU;AAWvC,MAAM,eAAe,GAAG,KAAK;AAE7B,MAAM,SAAS,GAAG,WAAW;AAC7B,MAAM,aAAa,GAAG,aAAa;AAE7B,SAAU,YAAY,CAC1B,MAAW,EACX,aAA8C,EAC9C,MAA0B,EAAE,EAAA;AAE5B,IAAA,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB;AAE7C,IAAA,MAAM,kBAAkB,GAAG,CAAC,GAAG,CAAC,kBAAkB,KAAK,SAAS,IAAI,GAAG,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC;AACnG,UAAE,IAAI,GAAG,CAAC,GAAG,CAAC,kBAAkB;UAC9B,SAAS;;AAGb,IAAA,MAAM,uBAAuB,GAAG,IAAI,GAAG,EAAkB;IAEzD,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,KAAI;AAC3C,QAAA,MAAM,eAAe,GAAG,aAAa,CAAC,KAAK,CAAC;AAC5C,QAAA,IAAI,IAAiB;AACrB,QAAA,IAAI,WAAqC;AACzC,QAAA,IAAI,WAAqC;;QAGzC,IAAI,MAAM,IAAI,eAAe,IAAI,OAAO,eAAe,CAAC,IAAI,KAAK,QAAQ,EAAE;;AAEzE,YAAA,IAAI,GAAG,eAAe,CAAC,IAAI;AAC3B,YAAA,WAAW,GAAG,eAAe,CAAC,WAAW;AACzC,YAAA,WAAW,GAAG,eAAe,CAAC,WAAW;QAC3C;aAAO;;YAEL,IAAI,GAAG,eAA8B;QACvC;QAEA,MAAM,KAAK,GAAGC,4BAAc,CAAC,IAAI,EAAEC,wBAAU,CAAC,KAAK,CAAC;QACpD,MAAM,QAAQ,GAAGD,4BAAc,CAAC,IAAI,EAAEC,wBAAU,CAAC,KAAK,CAAC;QACvD,MAAM,SAAS,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC,SAAS,CAACC,uBAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,SAAS,KAAK,EAAE;AAE1F,QAAA,MAAM,KAAK,GAAG;AACZ,YAAA,IAAI,WAAW,IAAI,EAAE,CAAC;AACtB,YAAA,GAAG,SAAS;AACZ,YAAA,IAAI,WAAW,IAAI,EAAE,CAAC;SACvB;AAED,QAAA,IAAI,KAAK,KAAK,SAAS,EAAE;AACvB,YAAA,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE;YAC7D,IAAI,GAAG,CAAC,gBAAgB;AAAE,gBAAA,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;;gBAC3C,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC;QACrC;QAEA,MAAM,SAAS,GAAc,EAAE;AAE/B,QAAA,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB;AAC7C,QAAA,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE;YAC1C,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;YACnC,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC;AAC3C,YAAA,MAAM,eAAe,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5D,YAAA,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,eAAe,CAAC;AAC1C,YAAA,MAAM,QAAQ,GAAG,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,eAAe,EAAE;AACjD,YAAA,uBAAuB,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,uBAAuB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvF,YAAA,WAAW,CAAC,GAAG,CACb,QAAQ,EACR,IAAI,CAAC,GAAG,CACN,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,iBAAiB,EACrD,UAAU,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,eAAe,CAClD,CACF;AACD,YAAA,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,eAAe,EAAE,CAAC;QAC7E;QACA,SAAS,CAAC,OAAO,EAAE;QACnB,OAAO;YACL,KAAK;YACL,IAAI;YACJ,KAAK;YACL,SAAS;SACV;AACH,IAAA,CAAC,CAAC;;IAGF,MAAM,SAAS,GAAa,EAAE;;IAE9B,MAAM,cAAc,GAAa,EAAE;AAEnC,IAAA,MAAM,cAAc,GAAG,CAAC,GAAG,WAAW,CAAC;;IAEvC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;AAEhD,IAAA,KAAK,MAAM,CAAC,QAAQ,CAAC,IAAI,cAAc,EAAE;AACvC,QAAA,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,uBAAuB,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAC,MAAM;AACpF,YAAA,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;;AACrB,YAAA,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC;IACpC;IAEA,MAAM,SAAS,GAAG,CAAC,aAA0B,EAAE,KAAA,GAAiB,KAAK,KAAI;QACvE,MAAM,MAAM,GAA0B,EAAE;AACxC,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC/C,YAAA,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;AAC5B,YAAA,MAAM,aAAa,GAAG,CAAC,CAAC;AACrB,iBAAA,MAAM,CAAC,CAAC,EAAE,KAAK,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ;AACxC,oBAAC,kBAAkB,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC;AAC/D,YAAA,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE;AAC9B,gBAAA,IAAI,KAAK;oBACP,MAAM,CAAC,IAAI,CAAC;AACV,wBAAA,KAAK,EAAE,WAAW;wBAClB,KAAK,EAAE,CAAC,CAAC,KAAK;AACe,qBAAA,CAAC;;AAC7B,oBAAA,OAAO,SAAS;YACvB;YACA,MAAM,QAAQ,GAAG;iBACd,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC;AACxB,YAAA,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,IAAI,KAAK;YAClC,MAAM,CAAC,IAAI,CAAC;AACV,gBAAA,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;gBACzB,KAAK,EAAE,CAAC,CAAC,KAAK;AACe,aAAA,CAAC;QAClC;AACA,QAAA,OAAO,MAAM;AACf,IAAA,CAAC;AAED,IAAA,MAAM,iBAAiB,GAAG,CAAC,MAAyC,KAClE,MAAM,KAAK,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;;;AAIrE,IAAA,MAAM,eAAe,GAAG,CAAC,OAAoB,KAAiB;AAC5D,QAAA,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC;AACxC,QAAA,IAAI,aAAa,KAAK,SAAS,EAAE;AAC/B,YAAA,OAAO,OAAO;QAChB;AACA,QAAA,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,aAAa,CAAC;;AAG3D,QAAA,MAAM,eAAe,GAAG,CAAC,GAAG,OAAO;aAChC,MAAM,CAAC,CAAC,CAAC,KACR,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;eACrC,EAAE,GAAG,CAAC,kBAAkB,IAAI,CAAC,KAAK,aAAa,CAAC;AACpD,aAAA,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAExE,QAAA,KAAK,MAAM,YAAY,IAAI,eAAe,EAAE;AAC1C,YAAA,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;AACnC,YAAA,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC;AAC/B,YAAA,MAAM,eAAe,GAAG,SAAS,CAAC,UAAU,CAAC;YAC7C,IAAI,eAAe,KAAK,SAAS,IAAI,iBAAiB,CAAC,eAAe,CAAC,IAAI,kBAAkB,EAAE;AAC7F,gBAAA,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC;YAC9B;QACF;AACA,QAAA,OAAO,OAAO;AAChB,IAAA,CAAC;AAED,IAAA,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;AAC1B,QAAA,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;AAAE,YAAA,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC;QAClH,OAAO,SAAS,CAAC,IAAI,GAAG,CAAC,aAAa,CAAC,EAAE,IAAI,CAAE;IACjD;;;;;;;;;;IAWA,IAAI,aAAa,GAAG,CAAC;AACrB,IAAA,IAAI,cAAc,GAAG,EAAE;AACvB,IAAA,OAAO,aAAa,GAAG,SAAS,CAAC,MAAM,EAAE;AACvC,QAAA,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU;QACpC,IAAI,GAAG,CAAC,kBAAkB;AAAE,YAAA,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC;QACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,EAAE,CAAC;YAAE,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACpE,IAAI,cAAc,IAAI,CAAC;YACrB,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;AAE3C,QAAA,MAAM,eAAe,GAAG,SAAS,CAAC,UAAU,CAAC;AAE7C,QAAA,IAAI,eAAe,KAAK,SAAS,IAAI,iBAAiB,CAAC,eAAe,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE;YACzF,eAAe,CAAC,UAAU,CAAC;AAC3B,YAAA,OAAO,SAAS,CAAC,UAAU,CAAE;QAC/B;AAEA,QAAA,cAAc,EAAE;AAChB,QAAA,IAAI,cAAc,IAAI,SAAS,CAAC,MAAM,EAAE;AACtC,YAAA,aAAa,EAAE;YACf,cAAc,GAAG,aAAa;QAChC;IACF;;AAGA,IAAA,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,SAAS,EAAE,GAAG,cAAc,CAAC,CAAC;IAC9D,eAAe,CAAC,WAAW,CAAC;AAC5B,IAAA,OAAO,SAAS,CAAC,WAAW,EAAE,IAAI,CAAE;AACtC;;;;;;"}
|
|
1
|
+
{"version":3,"file":"label.cjs","sources":["../../../src/render/util/label.ts"],"sourcesContent":["import {\n Annotation,\n parseJson,\n readAnnotation,\n type PObjectSpec,\n} from \"@milaboratories/pl-model-common\";\nimport { z } from \"zod\";\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult =\n | PObjectSpec\n | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n };\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = \"__LABEL__\";\nconst LabelTypeFull = \"__LABEL__@1\";\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements =\n ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if (\"spec\" in extractorResult && typeof extractorResult.spec === \"object\") {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = readAnnotation(spec, Annotation.Label);\n const traceStr = readAnnotation(spec, Annotation.Trace);\n const baseTrace = (traceStr ? Trace.safeParse(parseJson(traceStr)).data : undefined) ?? [];\n\n const trace = [...(prefixTrace ?? []), ...baseTrace, ...(suffixTrace ?? [])];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith(\"@1\") || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace.filter(\n (fm) =>\n includedTypes.has(fm.fullType) || (forceTraceElements && forceTraceElements.has(fm.type)),\n );\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: \"Unlabeled\",\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace.map((fm) => fm.label);\n const sep = ops.separator ?? \" / \";\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n const countUniqueLabels = (result: RecordsWithLabel<T>[] | undefined): number =>\n result === undefined ? 0 : new Set(result.map((c) => c.label)).size;\n\n // Post-processing: try removing types one by one (lowest importance first) to minimize the label set\n // Accepts removal if it doesn't decrease the number of unique labels (cardinality)\n const minimizeTypeSet = (typeSet: Set<string>): Set<string> => {\n const initialResult = calculate(typeSet);\n if (initialResult === undefined) {\n return typeSet;\n }\n const currentCardinality = countUniqueLabels(initialResult);\n\n // Get types sorted by importance ascending (lowest first), excluding forced elements\n const removableSorted = [...typeSet]\n .filter(\n (t) =>\n !forceTraceElements?.has(t.split(\"@\")[0]) &&\n !(ops.includeNativeLabel && t === LabelTypeFull),\n )\n .sort((a, b) => (importances.get(a) ?? 0) - (importances.get(b) ?? 0));\n\n for (const typeToRemove of removableSorted) {\n const reducedSet = new Set(typeSet);\n reducedSet.delete(typeToRemove);\n const candidateResult = calculate(reducedSet);\n if (\n candidateResult !== undefined &&\n countUniqueLabels(candidateResult) >= currentCardinality\n ) {\n typeSet.delete(typeToRemove);\n }\n }\n return typeSet;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0)\n throw new Error(\"Non-empty secondary types list while main types list is empty.\");\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0) currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) === values.length) {\n minimizeTypeSet(currentSet);\n return calculate(currentSet)!;\n }\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n // Fallback: include all types, then try to minimize\n const fallbackSet = new Set([...mainTypes, ...secondaryTypes]);\n minimizeTypeSet(fallbackSet);\n return calculate(fallbackSet, true)!;\n}\n"],"names":["z","readAnnotation","Annotation","parseJson"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../src/render/util/label.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"label.d.ts","sourceRoot":"","sources":["../../../src/render/util/label.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,WAAW,EACjB,MAAM,iCAAiC,CAAC;AACzC,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,MAAM,gBAAgB,CAAC,CAAC,IAAI;IAChC,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,kBAAkB,GAAG;IAC/B,6CAA6C;IAC7C,kBAAkB,CAAC,EAAE,OAAO,CAAC;IAC7B,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sHAAsH;IACtH,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,2EAA2E;IAC3E,kBAAkB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B,CAAC;AAEF,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;EAKrB,CAAC;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,UAAU,CAAC,CAAC;AAGpD,eAAO,MAAM,KAAK;;;;;;;;;;;;;;;WAAsB,CAAC;AACzC,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,KAAK,CAAC,CAAC;AAI1C,KAAK,mBAAmB,GACpB,WAAW,GACX;IACE,IAAI,EAAE,WAAW,CAAC;IAClB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;CAC5B,CAAC;AAON,wBAAgB,YAAY,CAAC,CAAC,EAC5B,MAAM,EAAE,CAAC,EAAE,EACX,aAAa,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,mBAAmB,EAC9C,GAAG,GAAE,kBAAuB,GAC3B,gBAAgB,CAAC,CAAC,CAAC,EAAE,CAyLvB"}
|
|
@@ -9,11 +9,11 @@ const TraceEntry = z.object({
|
|
|
9
9
|
});
|
|
10
10
|
const Trace = z.array(TraceEntry);
|
|
11
11
|
const DistancePenalty = 0.001;
|
|
12
|
-
const LabelType =
|
|
13
|
-
const LabelTypeFull =
|
|
12
|
+
const LabelType = "__LABEL__";
|
|
13
|
+
const LabelTypeFull = "__LABEL__@1";
|
|
14
14
|
function deriveLabels(values, specExtractor, ops = {}) {
|
|
15
15
|
const importances = new Map();
|
|
16
|
-
const forceTraceElements =
|
|
16
|
+
const forceTraceElements = ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0
|
|
17
17
|
? new Set(ops.forceTraceElements)
|
|
18
18
|
: undefined;
|
|
19
19
|
// number of times certain type occurred among all of the
|
|
@@ -24,7 +24,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
24
24
|
let prefixTrace;
|
|
25
25
|
let suffixTrace;
|
|
26
26
|
// Check if the result is the new structure or just PObjectSpec
|
|
27
|
-
if (
|
|
27
|
+
if ("spec" in extractorResult && typeof extractorResult.spec === "object") {
|
|
28
28
|
// It's the new structure { spec, prefixTrace?, suffixTrace? }
|
|
29
29
|
spec = extractorResult.spec;
|
|
30
30
|
prefixTrace = extractorResult.prefixTrace;
|
|
@@ -37,11 +37,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
37
37
|
const label = readAnnotation(spec, Annotation.Label);
|
|
38
38
|
const traceStr = readAnnotation(spec, Annotation.Trace);
|
|
39
39
|
const baseTrace = (traceStr ? Trace.safeParse(parseJson(traceStr)).data : undefined) ?? [];
|
|
40
|
-
const trace = [
|
|
41
|
-
...(prefixTrace ?? []),
|
|
42
|
-
...baseTrace,
|
|
43
|
-
...(suffixTrace ?? []),
|
|
44
|
-
];
|
|
40
|
+
const trace = [...(prefixTrace ?? []), ...baseTrace, ...(suffixTrace ?? [])];
|
|
45
41
|
if (label !== undefined) {
|
|
46
42
|
const labelEntry = { label, type: LabelType, importance: -2 };
|
|
47
43
|
if (ops.addLabelAsSuffix)
|
|
@@ -77,7 +73,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
77
73
|
// sorting: most important types go first
|
|
78
74
|
allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);
|
|
79
75
|
for (const [typeName] of allTypeRecords) {
|
|
80
|
-
if (typeName.endsWith(
|
|
76
|
+
if (typeName.endsWith("@1") || numberOfRecordsWithType.get(typeName) === values.length)
|
|
81
77
|
mainTypes.push(typeName);
|
|
82
78
|
else
|
|
83
79
|
secondaryTypes.push(typeName);
|
|
@@ -86,21 +82,18 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
86
82
|
const result = [];
|
|
87
83
|
for (let i = 0; i < enrichedRecords.length; i++) {
|
|
88
84
|
const r = enrichedRecords[i];
|
|
89
|
-
const includedTrace = r.fullTrace
|
|
90
|
-
.filter((fm) => includedTypes.has(fm.fullType)
|
|
91
|
-
|| (forceTraceElements && forceTraceElements.has(fm.type)));
|
|
85
|
+
const includedTrace = r.fullTrace.filter((fm) => includedTypes.has(fm.fullType) || (forceTraceElements && forceTraceElements.has(fm.type)));
|
|
92
86
|
if (includedTrace.length === 0) {
|
|
93
87
|
if (force)
|
|
94
88
|
result.push({
|
|
95
|
-
label:
|
|
89
|
+
label: "Unlabeled",
|
|
96
90
|
value: r.value,
|
|
97
91
|
});
|
|
98
92
|
else
|
|
99
93
|
return undefined;
|
|
100
94
|
}
|
|
101
|
-
const labelSet = includedTrace
|
|
102
|
-
|
|
103
|
-
const sep = ops.separator ?? ' / ';
|
|
95
|
+
const labelSet = includedTrace.map((fm) => fm.label);
|
|
96
|
+
const sep = ops.separator ?? " / ";
|
|
104
97
|
result.push({
|
|
105
98
|
label: labelSet.join(sep),
|
|
106
99
|
value: r.value,
|
|
@@ -119,14 +112,15 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
119
112
|
const currentCardinality = countUniqueLabels(initialResult);
|
|
120
113
|
// Get types sorted by importance ascending (lowest first), excluding forced elements
|
|
121
114
|
const removableSorted = [...typeSet]
|
|
122
|
-
.filter((t) => !forceTraceElements?.has(t.split(
|
|
123
|
-
|
|
115
|
+
.filter((t) => !forceTraceElements?.has(t.split("@")[0]) &&
|
|
116
|
+
!(ops.includeNativeLabel && t === LabelTypeFull))
|
|
124
117
|
.sort((a, b) => (importances.get(a) ?? 0) - (importances.get(b) ?? 0));
|
|
125
118
|
for (const typeToRemove of removableSorted) {
|
|
126
119
|
const reducedSet = new Set(typeSet);
|
|
127
120
|
reducedSet.delete(typeToRemove);
|
|
128
121
|
const candidateResult = calculate(reducedSet);
|
|
129
|
-
if (candidateResult !== undefined &&
|
|
122
|
+
if (candidateResult !== undefined &&
|
|
123
|
+
countUniqueLabels(candidateResult) >= currentCardinality) {
|
|
130
124
|
typeSet.delete(typeToRemove);
|
|
131
125
|
}
|
|
132
126
|
}
|
|
@@ -134,7 +128,7 @@ function deriveLabels(values, specExtractor, ops = {}) {
|
|
|
134
128
|
};
|
|
135
129
|
if (mainTypes.length === 0) {
|
|
136
130
|
if (secondaryTypes.length !== 0)
|
|
137
|
-
throw new Error(
|
|
131
|
+
throw new Error("Non-empty secondary types list while main types list is empty.");
|
|
138
132
|
return calculate(new Set(LabelTypeFull), true);
|
|
139
133
|
}
|
|
140
134
|
//
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"label.js","sources":["../../../src/render/util/label.ts"],"sourcesContent":["import { Annotation, parseJson, readAnnotation, type PObjectSpec } from '@milaboratories/pl-model-common';\nimport { z } from 'zod';\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult = PObjectSpec | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n};\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = '__LABEL__';\nconst LabelTypeFull = '__LABEL__@1';\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements = (ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0)\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if ('spec' in extractorResult && typeof extractorResult.spec === 'object') {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = readAnnotation(spec, Annotation.Label);\n const traceStr = readAnnotation(spec, Annotation.Trace);\n const baseTrace = (traceStr ? Trace.safeParse(parseJson(traceStr)).data : undefined) ?? [];\n\n const trace = [\n ...(prefixTrace ?? []),\n ...baseTrace,\n ...(suffixTrace ?? []),\n ];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith('@1') || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace\n .filter((fm) => includedTypes.has(fm.fullType)\n || (forceTraceElements && forceTraceElements.has(fm.type)));\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: 'Unlabeled',\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace\n .map((fm) => fm.label);\n const sep = ops.separator ?? ' / ';\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n const countUniqueLabels = (result: RecordsWithLabel<T>[] | undefined): number =>\n result === undefined ? 0 : new Set(result.map((c) => c.label)).size;\n\n // Post-processing: try removing types one by one (lowest importance first) to minimize the label set\n // Accepts removal if it doesn't decrease the number of unique labels (cardinality)\n const minimizeTypeSet = (typeSet: Set<string>): Set<string> => {\n const initialResult = calculate(typeSet);\n if (initialResult === undefined) {\n return typeSet;\n }\n const currentCardinality = countUniqueLabels(initialResult);\n\n // Get types sorted by importance ascending (lowest first), excluding forced elements\n const removableSorted = [...typeSet]\n .filter((t) =>\n !forceTraceElements?.has(t.split('@')[0])\n && !(ops.includeNativeLabel && t === LabelTypeFull))\n .sort((a, b) => (importances.get(a) ?? 0) - (importances.get(b) ?? 0));\n\n for (const typeToRemove of removableSorted) {\n const reducedSet = new Set(typeSet);\n reducedSet.delete(typeToRemove);\n const candidateResult = calculate(reducedSet);\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) >= currentCardinality) {\n typeSet.delete(typeToRemove);\n }\n }\n return typeSet;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0) throw new Error('Non-empty secondary types list while main types list is empty.');\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0)\n currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) === values.length) {\n minimizeTypeSet(currentSet);\n return calculate(currentSet)!;\n }\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n // Fallback: include all types, then try to minimize\n const fallbackSet = new Set([...mainTypes, ...secondaryTypes]);\n minimizeTypeSet(fallbackSet);\n return calculate(fallbackSet, true)!;\n}\n"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"label.js","sources":["../../../src/render/util/label.ts"],"sourcesContent":["import {\n Annotation,\n parseJson,\n readAnnotation,\n type PObjectSpec,\n} from \"@milaboratories/pl-model-common\";\nimport { z } from \"zod\";\n\nexport type RecordsWithLabel<T> = {\n value: T;\n label: string;\n};\n\nexport type LabelDerivationOps = {\n /** Force inclusion of native column label */\n includeNativeLabel?: boolean;\n /** Separator to use between label parts (\" / \" by default) */\n separator?: string;\n /** If true, label will be added as suffix (at the end of the generated label). By default label added as a prefix. */\n addLabelAsSuffix?: boolean;\n /** Trace elements list that will be forced to be included in the label. */\n forceTraceElements?: string[];\n};\n\nexport const TraceEntry = z.object({\n type: z.string(),\n importance: z.number().optional(),\n id: z.string().optional(),\n label: z.string(),\n});\nexport type TraceEntry = z.infer<typeof TraceEntry>;\ntype FullTraceEntry = TraceEntry & { fullType: string; occurrenceIndex: number };\n\nexport const Trace = z.array(TraceEntry);\nexport type Trace = z.infer<typeof Trace>;\ntype FullTrace = FullTraceEntry[];\n\n// Define the possible return types for the specExtractor function\ntype SpecExtractorResult =\n | PObjectSpec\n | {\n spec: PObjectSpec;\n prefixTrace?: TraceEntry[];\n suffixTrace?: TraceEntry[];\n };\n\nconst DistancePenalty = 0.001;\n\nconst LabelType = \"__LABEL__\";\nconst LabelTypeFull = \"__LABEL__@1\";\n\nexport function deriveLabels<T>(\n values: T[],\n specExtractor: (obj: T) => SpecExtractorResult,\n ops: LabelDerivationOps = {},\n): RecordsWithLabel<T>[] {\n const importances = new Map<string, number>();\n\n const forceTraceElements =\n ops.forceTraceElements !== undefined && ops.forceTraceElements.length > 0\n ? new Set(ops.forceTraceElements)\n : undefined;\n\n // number of times certain type occurred among all of the\n const numberOfRecordsWithType = new Map<string, number>();\n\n const enrichedRecords = values.map((value) => {\n const extractorResult = specExtractor(value);\n let spec: PObjectSpec;\n let prefixTrace: TraceEntry[] | undefined;\n let suffixTrace: TraceEntry[] | undefined;\n\n // Check if the result is the new structure or just PObjectSpec\n if (\"spec\" in extractorResult && typeof extractorResult.spec === \"object\") {\n // It's the new structure { spec, prefixTrace?, suffixTrace? }\n spec = extractorResult.spec;\n prefixTrace = extractorResult.prefixTrace;\n suffixTrace = extractorResult.suffixTrace;\n } else {\n // It's just PObjectSpec\n spec = extractorResult as PObjectSpec;\n }\n\n const label = readAnnotation(spec, Annotation.Label);\n const traceStr = readAnnotation(spec, Annotation.Trace);\n const baseTrace = (traceStr ? Trace.safeParse(parseJson(traceStr)).data : undefined) ?? [];\n\n const trace = [...(prefixTrace ?? []), ...baseTrace, ...(suffixTrace ?? [])];\n\n if (label !== undefined) {\n const labelEntry = { label, type: LabelType, importance: -2 };\n if (ops.addLabelAsSuffix) trace.push(labelEntry);\n else trace.splice(0, 0, labelEntry);\n }\n\n const fullTrace: FullTrace = [];\n\n const occurrences = new Map<string, number>();\n for (let i = trace.length - 1; i >= 0; --i) {\n const { type: typeName } = trace[i];\n const importance = trace[i].importance ?? 0;\n const occurrenceIndex = (occurrences.get(typeName) ?? 0) + 1;\n occurrences.set(typeName, occurrenceIndex);\n const fullType = `${typeName}@${occurrenceIndex}`;\n numberOfRecordsWithType.set(fullType, (numberOfRecordsWithType.get(fullType) ?? 0) + 1);\n importances.set(\n fullType,\n Math.max(\n importances.get(fullType) ?? Number.NEGATIVE_INFINITY,\n importance - (trace.length - i) * DistancePenalty,\n ),\n );\n fullTrace.push({ ...trace[i], fullType, occurrenceIndex: occurrenceIndex });\n }\n fullTrace.reverse();\n return {\n value,\n spec,\n label,\n fullTrace,\n };\n });\n\n // excluding repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const mainTypes: string[] = [];\n // repeated types (i.e. ..@2, ..@3, etc.) not found in some records\n const secondaryTypes: string[] = [];\n\n const allTypeRecords = [...importances];\n // sorting: most important types go first\n allTypeRecords.sort(([, i1], [, i2]) => i2 - i1);\n\n for (const [typeName] of allTypeRecords) {\n if (typeName.endsWith(\"@1\") || numberOfRecordsWithType.get(typeName) === values.length)\n mainTypes.push(typeName);\n else secondaryTypes.push(typeName);\n }\n\n const calculate = (includedTypes: Set<string>, force: boolean = false) => {\n const result: RecordsWithLabel<T>[] = [];\n for (let i = 0; i < enrichedRecords.length; i++) {\n const r = enrichedRecords[i];\n const includedTrace = r.fullTrace.filter(\n (fm) =>\n includedTypes.has(fm.fullType) || (forceTraceElements && forceTraceElements.has(fm.type)),\n );\n if (includedTrace.length === 0) {\n if (force)\n result.push({\n label: \"Unlabeled\",\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n else return undefined;\n }\n const labelSet = includedTrace.map((fm) => fm.label);\n const sep = ops.separator ?? \" / \";\n result.push({\n label: labelSet.join(sep),\n value: r.value,\n } satisfies RecordsWithLabel<T>);\n }\n return result;\n };\n\n const countUniqueLabels = (result: RecordsWithLabel<T>[] | undefined): number =>\n result === undefined ? 0 : new Set(result.map((c) => c.label)).size;\n\n // Post-processing: try removing types one by one (lowest importance first) to minimize the label set\n // Accepts removal if it doesn't decrease the number of unique labels (cardinality)\n const minimizeTypeSet = (typeSet: Set<string>): Set<string> => {\n const initialResult = calculate(typeSet);\n if (initialResult === undefined) {\n return typeSet;\n }\n const currentCardinality = countUniqueLabels(initialResult);\n\n // Get types sorted by importance ascending (lowest first), excluding forced elements\n const removableSorted = [...typeSet]\n .filter(\n (t) =>\n !forceTraceElements?.has(t.split(\"@\")[0]) &&\n !(ops.includeNativeLabel && t === LabelTypeFull),\n )\n .sort((a, b) => (importances.get(a) ?? 0) - (importances.get(b) ?? 0));\n\n for (const typeToRemove of removableSorted) {\n const reducedSet = new Set(typeSet);\n reducedSet.delete(typeToRemove);\n const candidateResult = calculate(reducedSet);\n if (\n candidateResult !== undefined &&\n countUniqueLabels(candidateResult) >= currentCardinality\n ) {\n typeSet.delete(typeToRemove);\n }\n }\n return typeSet;\n };\n\n if (mainTypes.length === 0) {\n if (secondaryTypes.length !== 0)\n throw new Error(\"Non-empty secondary types list while main types list is empty.\");\n return calculate(new Set(LabelTypeFull), true)!;\n }\n\n //\n // includedTypes = 2\n // * *\n // T0 T1 T2 T3 T4 T5\n // *\n // additionalType = 3\n //\n // Resulting set: T0, T1, T3\n //\n let includedTypes = 0;\n let additionalType = -1;\n while (includedTypes < mainTypes.length) {\n const currentSet = new Set<string>();\n if (ops.includeNativeLabel) currentSet.add(LabelTypeFull);\n for (let i = 0; i < includedTypes; ++i) currentSet.add(mainTypes[i]);\n if (additionalType >= 0) currentSet.add(mainTypes[additionalType]);\n\n const candidateResult = calculate(currentSet);\n\n if (candidateResult !== undefined && countUniqueLabels(candidateResult) === values.length) {\n minimizeTypeSet(currentSet);\n return calculate(currentSet)!;\n }\n\n additionalType++;\n if (additionalType >= mainTypes.length) {\n includedTypes++;\n additionalType = includedTypes;\n }\n }\n\n // Fallback: include all types, then try to minimize\n const fallbackSet = new Set([...mainTypes, ...secondaryTypes]);\n minimizeTypeSet(fallbackSet);\n return calculate(fallbackSet, true)!;\n}\n"],"names":[],"mappings":";;;AAwBO,MAAM,UAAU,GAAG,CAAC,CAAC,MAAM,CAAC;AACjC,IAAA,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;AAChB,IAAA,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;AACjC,IAAA,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;AACzB,IAAA,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;AAClB,CAAA;AAIM,MAAM,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,UAAU;AAavC,MAAM,eAAe,GAAG,KAAK;AAE7B,MAAM,SAAS,GAAG,WAAW;AAC7B,MAAM,aAAa,GAAG,aAAa;AAE7B,SAAU,YAAY,CAC1B,MAAW,EACX,aAA8C,EAC9C,MAA0B,EAAE,EAAA;AAE5B,IAAA,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB;AAE7C,IAAA,MAAM,kBAAkB,GACtB,GAAG,CAAC,kBAAkB,KAAK,SAAS,IAAI,GAAG,CAAC,kBAAkB,CAAC,MAAM,GAAG;AACtE,UAAE,IAAI,GAAG,CAAC,GAAG,CAAC,kBAAkB;UAC9B,SAAS;;AAGf,IAAA,MAAM,uBAAuB,GAAG,IAAI,GAAG,EAAkB;IAEzD,MAAM,eAAe,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,KAAI;AAC3C,QAAA,MAAM,eAAe,GAAG,aAAa,CAAC,KAAK,CAAC;AAC5C,QAAA,IAAI,IAAiB;AACrB,QAAA,IAAI,WAAqC;AACzC,QAAA,IAAI,WAAqC;;QAGzC,IAAI,MAAM,IAAI,eAAe,IAAI,OAAO,eAAe,CAAC,IAAI,KAAK,QAAQ,EAAE;;AAEzE,YAAA,IAAI,GAAG,eAAe,CAAC,IAAI;AAC3B,YAAA,WAAW,GAAG,eAAe,CAAC,WAAW;AACzC,YAAA,WAAW,GAAG,eAAe,CAAC,WAAW;QAC3C;aAAO;;YAEL,IAAI,GAAG,eAA8B;QACvC;QAEA,MAAM,KAAK,GAAG,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC;QACpD,MAAM,QAAQ,GAAG,cAAc,CAAC,IAAI,EAAE,UAAU,CAAC,KAAK,CAAC;QACvD,MAAM,SAAS,GAAG,CAAC,QAAQ,GAAG,KAAK,CAAC,SAAS,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,GAAG,SAAS,KAAK,EAAE;QAE1F,MAAM,KAAK,GAAG,CAAC,IAAI,WAAW,IAAI,EAAE,CAAC,EAAE,GAAG,SAAS,EAAE,IAAI,WAAW,IAAI,EAAE,CAAC,CAAC;AAE5E,QAAA,IAAI,KAAK,KAAK,SAAS,EAAE;AACvB,YAAA,MAAM,UAAU,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,SAAS,EAAE,UAAU,EAAE,EAAE,EAAE;YAC7D,IAAI,GAAG,CAAC,gBAAgB;AAAE,gBAAA,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC;;gBAC3C,KAAK,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,EAAE,UAAU,CAAC;QACrC;QAEA,MAAM,SAAS,GAAc,EAAE;AAE/B,QAAA,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB;AAC7C,QAAA,KAAK,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,EAAE,CAAC,EAAE;YAC1C,MAAM,EAAE,IAAI,EAAE,QAAQ,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC;YACnC,MAAM,UAAU,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC;AAC3C,YAAA,MAAM,eAAe,GAAG,CAAC,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC;AAC5D,YAAA,WAAW,CAAC,GAAG,CAAC,QAAQ,EAAE,eAAe,CAAC;AAC1C,YAAA,MAAM,QAAQ,GAAG,CAAA,EAAG,QAAQ,CAAA,CAAA,EAAI,eAAe,EAAE;AACjD,YAAA,uBAAuB,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,uBAAuB,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACvF,YAAA,WAAW,CAAC,GAAG,CACb,QAAQ,EACR,IAAI,CAAC,GAAG,CACN,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,IAAI,MAAM,CAAC,iBAAiB,EACrD,UAAU,GAAG,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,eAAe,CAClD,CACF;AACD,YAAA,SAAS,CAAC,IAAI,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,eAAe,EAAE,eAAe,EAAE,CAAC;QAC7E;QACA,SAAS,CAAC,OAAO,EAAE;QACnB,OAAO;YACL,KAAK;YACL,IAAI;YACJ,KAAK;YACL,SAAS;SACV;AACH,IAAA,CAAC,CAAC;;IAGF,MAAM,SAAS,GAAa,EAAE;;IAE9B,MAAM,cAAc,GAAa,EAAE;AAEnC,IAAA,MAAM,cAAc,GAAG,CAAC,GAAG,WAAW,CAAC;;IAEvC,cAAc,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,CAAC,EAAE,GAAG,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;AAEhD,IAAA,KAAK,MAAM,CAAC,QAAQ,CAAC,IAAI,cAAc,EAAE;AACvC,QAAA,IAAI,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,uBAAuB,CAAC,GAAG,CAAC,QAAQ,CAAC,KAAK,MAAM,CAAC,MAAM;AACpF,YAAA,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC;;AACrB,YAAA,cAAc,CAAC,IAAI,CAAC,QAAQ,CAAC;IACpC;IAEA,MAAM,SAAS,GAAG,CAAC,aAA0B,EAAE,KAAA,GAAiB,KAAK,KAAI;QACvE,MAAM,MAAM,GAA0B,EAAE;AACxC,QAAA,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,eAAe,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;AAC/C,YAAA,MAAM,CAAC,GAAG,eAAe,CAAC,CAAC,CAAC;AAC5B,YAAA,MAAM,aAAa,GAAG,CAAC,CAAC,SAAS,CAAC,MAAM,CACtC,CAAC,EAAE,KACD,aAAa,CAAC,GAAG,CAAC,EAAE,CAAC,QAAQ,CAAC,KAAK,kBAAkB,IAAI,kBAAkB,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAC5F;AACD,YAAA,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC,EAAE;AAC9B,gBAAA,IAAI,KAAK;oBACP,MAAM,CAAC,IAAI,CAAC;AACV,wBAAA,KAAK,EAAE,WAAW;wBAClB,KAAK,EAAE,CAAC,CAAC,KAAK;AACe,qBAAA,CAAC;;AAC7B,oBAAA,OAAO,SAAS;YACvB;AACA,YAAA,MAAM,QAAQ,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,KAAK,CAAC;AACpD,YAAA,MAAM,GAAG,GAAG,GAAG,CAAC,SAAS,IAAI,KAAK;YAClC,MAAM,CAAC,IAAI,CAAC;AACV,gBAAA,KAAK,EAAE,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC;gBACzB,KAAK,EAAE,CAAC,CAAC,KAAK;AACe,aAAA,CAAC;QAClC;AACA,QAAA,OAAO,MAAM;AACf,IAAA,CAAC;AAED,IAAA,MAAM,iBAAiB,GAAG,CAAC,MAAyC,KAClE,MAAM,KAAK,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;;;AAIrE,IAAA,MAAM,eAAe,GAAG,CAAC,OAAoB,KAAiB;AAC5D,QAAA,MAAM,aAAa,GAAG,SAAS,CAAC,OAAO,CAAC;AACxC,QAAA,IAAI,aAAa,KAAK,SAAS,EAAE;AAC/B,YAAA,OAAO,OAAO;QAChB;AACA,QAAA,MAAM,kBAAkB,GAAG,iBAAiB,CAAC,aAAa,CAAC;;AAG3D,QAAA,MAAM,eAAe,GAAG,CAAC,GAAG,OAAO;aAChC,MAAM,CACL,CAAC,CAAC,KACA,CAAC,kBAAkB,EAAE,GAAG,CAAC,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YACzC,EAAE,GAAG,CAAC,kBAAkB,IAAI,CAAC,KAAK,aAAa,CAAC;AAEnD,aAAA,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,KAAK,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,WAAW,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;AAExE,QAAA,KAAK,MAAM,YAAY,IAAI,eAAe,EAAE;AAC1C,YAAA,MAAM,UAAU,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC;AACnC,YAAA,UAAU,CAAC,MAAM,CAAC,YAAY,CAAC;AAC/B,YAAA,MAAM,eAAe,GAAG,SAAS,CAAC,UAAU,CAAC;YAC7C,IACE,eAAe,KAAK,SAAS;AAC7B,gBAAA,iBAAiB,CAAC,eAAe,CAAC,IAAI,kBAAkB,EACxD;AACA,gBAAA,OAAO,CAAC,MAAM,CAAC,YAAY,CAAC;YAC9B;QACF;AACA,QAAA,OAAO,OAAO;AAChB,IAAA,CAAC;AAED,IAAA,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC,EAAE;AAC1B,QAAA,IAAI,cAAc,CAAC,MAAM,KAAK,CAAC;AAC7B,YAAA,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC;QACnF,OAAO,SAAS,CAAC,IAAI,GAAG,CAAC,aAAa,CAAC,EAAE,IAAI,CAAE;IACjD;;;;;;;;;;IAWA,IAAI,aAAa,GAAG,CAAC;AACrB,IAAA,IAAI,cAAc,GAAG,EAAE;AACvB,IAAA,OAAO,aAAa,GAAG,SAAS,CAAC,MAAM,EAAE;AACvC,QAAA,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU;QACpC,IAAI,GAAG,CAAC,kBAAkB;AAAE,YAAA,UAAU,CAAC,GAAG,CAAC,aAAa,CAAC;QACzD,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,aAAa,EAAE,EAAE,CAAC;YAAE,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC;QACpE,IAAI,cAAc,IAAI,CAAC;YAAE,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC;AAElE,QAAA,MAAM,eAAe,GAAG,SAAS,CAAC,UAAU,CAAC;AAE7C,QAAA,IAAI,eAAe,KAAK,SAAS,IAAI,iBAAiB,CAAC,eAAe,CAAC,KAAK,MAAM,CAAC,MAAM,EAAE;YACzF,eAAe,CAAC,UAAU,CAAC;AAC3B,YAAA,OAAO,SAAS,CAAC,UAAU,CAAE;QAC/B;AAEA,QAAA,cAAc,EAAE;AAChB,QAAA,IAAI,cAAc,IAAI,SAAS,CAAC,MAAM,EAAE;AACtC,YAAA,aAAa,EAAE;YACf,cAAc,GAAG,aAAa;QAChC;IACF;;AAGA,IAAA,MAAM,WAAW,GAAG,IAAI,GAAG,CAAC,CAAC,GAAG,SAAS,EAAE,GAAG,cAAc,CAAC,CAAC;IAC9D,eAAe,CAAC,WAAW,CAAC;AAC5B,IAAA,OAAO,SAAS,CAAC,WAAW,EAAE,IAAI,CAAE;AACtC;;;;"}
|