@gooddata/sdk-code-convertors 11.51.0-alpha.2 → 11.51.0-alpha.4

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.
@@ -1,6 +1,6 @@
1
1
  // (C) 2023-2026 GoodData Corporation
2
2
  import { Document, Pair, YAMLMap, YAMLSeq } from "yaml";
3
- import { filterAttributeElements, filterLocalIdentifier, filterObjRef, getAttributeElementsItems, isAbsoluteDateFilter, isArbitraryAttributeFilter, isArithmeticMeasureDefinition, isAttribute, isAttributeElementsByValue, isAttributeLocator, isAttributeSort, isBucket, isComparisonCondition, isDateFilter, isFilter, isInlineMeasureDefinition, isInsight, isLocalIdRef, isMatchAttributeFilter, isMeasure, isMeasureDefinition, isMeasureLocator, isMeasureSort, isMeasureValueFilter, isNegativeAttributeFilter, isPoPMeasureDefinition, isPositiveAttributeFilter, isPreviousPeriodMeasureDefinition, isRangeCondition, isRankingFilter, isRelativeDateFilter, isTotalLocator, serializeObjRef, } from "@gooddata/sdk-model";
3
+ import { filterLocalIdentifier, isArithmeticMeasureDefinition, isAttribute, isAttributeLocator, isAttributeSort, isBucket, isFilter, isInlineMeasureDefinition, isInsight, isMeasure, isMeasureDefinition, isMeasureLocator, isMeasureSort, isPoPMeasureDefinition, isPreviousPeriodMeasureDefinition, isTotalLocator, } from "@gooddata/sdk-model";
4
4
  import { areaChart } from "../configs/areaChart.js";
5
5
  import { barChart } from "../configs/barChart.js";
6
6
  import { bubbleChart } from "../configs/bubbleChart.js";
@@ -26,12 +26,11 @@ import { treemapChart } from "../configs/treemapChart.js";
26
26
  import { waterfallChart } from "../configs/waterfallChart.js";
27
27
  import { BucketsType } from "../types.js";
28
28
  import { CoreErrorCode, newError, updateErrorContext } from "../utils/errors.js";
29
- import { matchConditionToYaml, parseDateValues } from "../utils/filterUtils.js";
30
- import { parseGranularity } from "../utils/granularityUtils.js";
31
29
  import { remapLocationAttribute } from "../utils/locationUtils.js";
32
30
  import { VISUALISATION_COMMENT } from "../utils/texts.js";
33
31
  import { visualizationUrlToYamlVisType } from "../utils/visualisationTypeMap.js";
34
- import { cleanUpItems, createFilterItemKeyName, entryWithSpace, fillOptionalMetaFields, getIdentifier, } from "../utils/yamlUtils.js";
32
+ import { cleanUpItems, entryWithSpace, fillOptionalMetaFields, getIdentifier } from "../utils/yamlUtils.js";
33
+ import { declarativeFiltersToYaml } from "./filtersToYaml.js";
35
34
  /** @public */
36
35
  export function declarativeVisualisationToYaml(entities, visualisation, context) {
37
36
  const errorContext = updateErrorContext(context, {
@@ -71,6 +70,12 @@ export function declarativeVisualisationToYaml(entities, visualisation, context)
71
70
  declarativeVisToYaml(doc, insight.insight, report, entities, updateErrorContext(errorContext, {
72
71
  path: ["insight"],
73
72
  }));
73
+ report.buckets.assertAllConsumed(errorContext);
74
+ // Only a type whose grammar has `layers:` writes them; any other drops the list whole, and its fields
75
+ // are already merged into `query.fields` by then, left declared and unreferenced.
76
+ if ((insight.insight.layers ?? []).length > 0 && doc.get("layers") === undefined) {
77
+ throw newError(CoreErrorCode.ItemNotSupported, ["layers"], updateErrorContext(errorContext, { path: ["layers"] }));
78
+ }
74
79
  return {
75
80
  content: doc.toString({
76
81
  lineWidth: 0,
@@ -78,6 +83,30 @@ export function declarativeVisualisationToYaml(entities, visualisation, context)
78
83
  json: doc.toJSON(),
79
84
  };
80
85
  }
86
+ /**
87
+ * Every type reads the buckets it writes by looking them up, so one it never looks up is dropped whole,
88
+ * taking its items with it.
89
+ */
90
+ function bucketRegistry(groups) {
91
+ // Recorded per group, since two groups may share a type and one lookup reaches only the first.
92
+ const consumed = new Set();
93
+ return {
94
+ consume(type) {
95
+ const found = groups.find((group) => group.type === type);
96
+ if (found) {
97
+ consumed.add(found);
98
+ }
99
+ return found;
100
+ },
101
+ // An empty bucket carries nothing to lose, so only one holding items is refused.
102
+ assertAllConsumed(errorContext) {
103
+ const dropped = groups.find((group) => group.items.length > 0 && !consumed.has(group));
104
+ if (dropped) {
105
+ throw newError(CoreErrorCode.ItemNotSupported, [`bucket "${dropped.type}"`], updateErrorContext(errorContext, { path: ["buckets", dropped.type] }));
106
+ }
107
+ },
108
+ };
109
+ }
81
110
  function declarativeReportToYaml(entities, def, errorContext) {
82
111
  const report = new YAMLMap();
83
112
  const { fieldsMap, postProcessors, groups: derivedBuckets, } = declarativeBucketsToYaml(entities, def.buckets, updateErrorContext(errorContext, {
@@ -117,7 +146,7 @@ function declarativeReportToYaml(entities, def, errorContext) {
117
146
  });
118
147
  return {
119
148
  report,
120
- derivedBuckets,
149
+ buckets: bucketRegistry(derivedBuckets),
121
150
  };
122
151
  }
123
152
  function appendLayerFieldsToReport(fieldsMap, postProcessors, entities, layers, errorContext) {
@@ -283,6 +312,9 @@ export function declarativeBucketsToYaml(entities, buckets, errorContext) {
283
312
  filters: [],
284
313
  };
285
314
  const addField = (local, def, group, { format, axis } = {}) => {
315
+ if (fullFieldsMap.has(local)) {
316
+ throw newError(CoreErrorCode.DuplicateFieldName, [local], errorContext);
317
+ }
286
318
  fullFieldsMap.add(new Pair(local, def));
287
319
  group.items.push(createBucketGroupItem(local, format, axis));
288
320
  };
@@ -497,481 +529,6 @@ function getShortenedBucket(def) {
497
529
  }
498
530
  return false;
499
531
  }
500
- function detectEmptyValuesFilterType(filter) {
501
- const attributeElements = filterAttributeElements(filter);
502
- const items = attributeElements ? getAttributeElementsItems(attributeElements) : [];
503
- if (items.length !== 1 || items[0] !== "") {
504
- return undefined;
505
- }
506
- return isPositiveAttributeFilter(filter) ? "only" : "exclude";
507
- }
508
- function getObjRefGroupingKey(objRef) {
509
- if (!objRef || typeof objRef !== "object") {
510
- return undefined;
511
- }
512
- if ("identifier" in objRef) {
513
- const identifier = objRef.identifier;
514
- if (typeof identifier === "string") {
515
- return identifier;
516
- }
517
- if (identifier && typeof identifier === "object" && "id" in identifier) {
518
- const id = identifier.id;
519
- if (typeof id === "string") {
520
- return id;
521
- }
522
- }
523
- }
524
- if ("uri" in objRef) {
525
- const uri = objRef.uri;
526
- if (typeof uri === "string") {
527
- return uri;
528
- }
529
- }
530
- if ("localIdentifier" in objRef) {
531
- const localIdentifier = objRef.localIdentifier;
532
- if (typeof localIdentifier === "string") {
533
- return localIdentifier;
534
- }
535
- }
536
- return serializeObjRef(objRef);
537
- }
538
- /**
539
- * Groups date filters with their associated attribute filters. Leaves the rest alone.
540
- * @param filters
541
- */
542
- function groupFiltersByDateFilter(filters) {
543
- const dateFilters = [...filters].filter(isDateFilter);
544
- const nonDateFilters = [...filters].filter((f) => !isDateFilter(f));
545
- const result = { grouped: {}, rest: [] };
546
- const getFilterRefDetails = (filter) => {
547
- const objRef = filterObjRef(filter);
548
- if (!objRef) {
549
- return {
550
- objRef: undefined,
551
- filterRef: undefined,
552
- };
553
- }
554
- return {
555
- objRef,
556
- filterRef: getObjRefGroupingKey(objRef),
557
- };
558
- };
559
- dateFilters.forEach((dateFilter) => {
560
- const { filterRef: datasetId } = getFilterRefDetails(dateFilter);
561
- const fi = filters.indexOf(dateFilter);
562
- if (datasetId === undefined) {
563
- result.rest.push([dateFilter, fi]);
564
- return;
565
- }
566
- if (result.grouped[datasetId]) {
567
- result.rest.push([dateFilter, fi]);
568
- }
569
- else {
570
- result.grouped[datasetId] = { dateFilter: [dateFilter, fi], attributeFilters: [] };
571
- }
572
- });
573
- nonDateFilters.forEach((filter) => {
574
- const { filterRef: filterId } = getFilterRefDetails(filter);
575
- const fi = filters.indexOf(filter);
576
- if (filterId === undefined) {
577
- result.rest.push([filter, fi]);
578
- return;
579
- }
580
- const datasetId = filterId.split(".")[0];
581
- const group = result.grouped[datasetId];
582
- if (group) {
583
- group.attributeFilters.push([filter, fi]);
584
- }
585
- else {
586
- result.rest.push([filter, fi]);
587
- }
588
- });
589
- return result;
590
- }
591
- /** @internal */
592
- export function declarativeFiltersToYaml(entities, filters, errorContext) {
593
- const filtersArray = [];
594
- const filtersMap = {};
595
- const usedKeys = new Set();
596
- const getUniqueKey = (baseKey) => {
597
- let key = baseKey;
598
- let suffix = 2;
599
- while (usedKeys.has(key)) {
600
- key = `${baseKey}_${suffix}`;
601
- suffix += 1;
602
- }
603
- usedKeys.add(key);
604
- return key;
605
- };
606
- const filtersGroupedByDateFilter = groupFiltersByDateFilter(filters);
607
- filtersGroupedByDateFilter.rest.forEach(([filter, fi]) => {
608
- const result = declarativeFilterToYaml(entities, filter, getUniqueKey, undefined, updateErrorContext(errorContext, {
609
- path: [fi.toString()],
610
- }));
611
- if (!result) {
612
- return;
613
- }
614
- const { key, yaml, filter: originalFilter } = result;
615
- filtersArray.push(new Pair(key, yaml));
616
- filtersMap[key] = {
617
- yaml,
618
- filter: originalFilter,
619
- };
620
- });
621
- Object.values(filtersGroupedByDateFilter.grouped).forEach(({ dateFilter, attributeFilters }) => {
622
- const result = declarativeFilterToYaml(entities, dateFilter[0], getUniqueKey, attributeFilters.map(([f]) => f), updateErrorContext(errorContext, {
623
- path: [dateFilter[1].toString()],
624
- }));
625
- if (!result) {
626
- return;
627
- }
628
- const { key, yaml, filter: originalFilter } = result;
629
- filtersArray.push(new Pair(key, yaml));
630
- filtersMap[key] = {
631
- yaml,
632
- filter: originalFilter,
633
- };
634
- });
635
- return {
636
- filtersMap,
637
- filtersArray: filtersArray.reduce((map, filter) => {
638
- map.add(filter);
639
- return map;
640
- }, new YAMLMap()),
641
- };
642
- }
643
- function declarativeFilterToYaml(entities, filter, getUniqueKey, connectedAttributeFilters, errorContext) {
644
- if (!isFilter(filter)) {
645
- return null;
646
- }
647
- const key = getUniqueKey(createFilterItemKeyName(filter, "date", updateErrorContext(errorContext, {
648
- path: ["date"],
649
- })));
650
- if (isAbsoluteDateFilter(filter)) {
651
- return {
652
- key,
653
- yaml: declarativeAbsoluteDateFilterToYaml(filter.absoluteDateFilter, connectedAttributeFilters, entities, getUniqueKey, updateErrorContext(errorContext, {
654
- path: ["absoluteDateFilter"],
655
- })),
656
- filter,
657
- };
658
- }
659
- if (isRelativeDateFilter(filter)) {
660
- return {
661
- key,
662
- yaml: declarativeRelativeDateFilterToYaml(filter.relativeDateFilter, connectedAttributeFilters, entities, getUniqueKey, updateErrorContext(errorContext, {
663
- path: ["relativeDateFilter"],
664
- })),
665
- filter,
666
- };
667
- }
668
- if (isPositiveAttributeFilter(filter)) {
669
- return {
670
- key,
671
- yaml: declarativePositiveAttributeFilterToYaml(entities, filter.positiveAttributeFilter, updateErrorContext(errorContext, {
672
- path: ["positiveAttributeFilter"],
673
- })),
674
- filter,
675
- };
676
- }
677
- if (isNegativeAttributeFilter(filter)) {
678
- return {
679
- key,
680
- yaml: declarativeNegativeAttributeFilterToYaml(entities, filter.negativeAttributeFilter, updateErrorContext(errorContext, {
681
- path: ["negativeAttributeFilter"],
682
- })),
683
- filter,
684
- };
685
- }
686
- if (isArbitraryAttributeFilter(filter)) {
687
- return {
688
- key,
689
- yaml: declarativeArbitraryAttributeFilterToYaml(filter.arbitraryAttributeFilter, updateErrorContext(errorContext, {
690
- path: ["arbitraryAttributeFilter"],
691
- })),
692
- filter,
693
- };
694
- }
695
- if (isMatchAttributeFilter(filter)) {
696
- return {
697
- key,
698
- yaml: declarativeMatchAttributeFilterToYaml(filter.matchAttributeFilter, updateErrorContext(errorContext, {
699
- path: ["matchAttributeFilter"],
700
- })),
701
- filter,
702
- };
703
- }
704
- if (isMeasureValueFilter(filter)) {
705
- return {
706
- key,
707
- yaml: declarativeMeasureValueFilterToYaml(filter.measureValueFilter, updateErrorContext(errorContext, {
708
- path: ["measureValueFilter"],
709
- })),
710
- filter,
711
- };
712
- }
713
- if (isRankingFilter(filter)) {
714
- return {
715
- key,
716
- yaml: declarativeRankingFilterToYaml(filter.rankingFilter, updateErrorContext(errorContext, {
717
- path: ["rankingFilter"],
718
- })),
719
- filter,
720
- };
721
- }
722
- throw newError(CoreErrorCode.FilterItemTypeNotSupported, [JSON.stringify(filter)], errorContext);
723
- }
724
- /**
725
- * Modifies `map`, adding `empty_filters` and `with` keys, populated from connectedAttributeFilters.
726
- */
727
- function processConnectedAttributeFilters(map, connectedAttributeFilters, entities, getUniqueKey, errorContext) {
728
- // empty values filter
729
- const emptyValuesFilter = connectedAttributeFilters.find((filter) => detectEmptyValuesFilterType(filter));
730
- if (emptyValuesFilter) {
731
- map.add(new Pair("empty_values", detectEmptyValuesFilterType(emptyValuesFilter)));
732
- }
733
- // additional attribute filters
734
- const additionalAttributeFilters = connectedAttributeFilters.filter((filter) => filter !== emptyValuesFilter);
735
- if (additionalAttributeFilters.length === 0) {
736
- return;
737
- }
738
- const withMap = new YAMLMap();
739
- map.add(new Pair("with", withMap));
740
- additionalAttributeFilters?.forEach((filter) => {
741
- const converted = declarativeFilterToYaml(entities, filter, getUniqueKey, undefined, errorContext);
742
- if (!converted) {
743
- return;
744
- }
745
- withMap.add(new Pair(converted.key, converted.yaml));
746
- });
747
- }
748
- /** @internal */
749
- export function declarativeAbsoluteDateFilterToYaml(absoluteDateFilter, connectedAttributeFilters = [], entities, getUniqueKey, errorContext) {
750
- const map = new YAMLMap();
751
- // base date filter attributes
752
- map.add(new Pair("type", "date_filter"));
753
- map.add(new Pair("from", absoluteDateFilter.from));
754
- map.add(new Pair("to", absoluteDateFilter.to));
755
- const id = getIdentifier(absoluteDateFilter.dataSet, true, updateErrorContext(errorContext, {
756
- path: ["dateSet"],
757
- }));
758
- map.add(new Pair("using", id));
759
- // connected attribute filters
760
- processConnectedAttributeFilters(map, connectedAttributeFilters, entities, getUniqueKey, errorContext);
761
- return map;
762
- }
763
- function isRelativeDateFilterAllTime(relativeDateFilter) {
764
- const { granularity, from, to } = relativeDateFilter;
765
- // This should be enough to tell the type is IRelativeDateFilterAllTimeBody
766
- if (granularity === "ALL_TIME_GRANULARITY") {
767
- return true;
768
- }
769
- // But unfortunately AD emits granularity as GDC.time.year for an all time date filter, so we need this check as well
770
- return granularity === "GDC.time.year" && from === undefined && to === undefined;
771
- }
772
- /** @internal */
773
- export function declarativeRelativeDateFilterToYaml(relativeDateFilter, connectedAttributeFilters = [], entities, getUniqueKey, errorContext) {
774
- const map = new YAMLMap();
775
- map.add(new Pair("type", "date_filter"));
776
- if (isRelativeDateFilterAllTime(relativeDateFilter)) {
777
- // Do not add anything
778
- }
779
- else {
780
- // Add granularity
781
- if (relativeDateFilter.granularity) {
782
- map.add(new Pair("granularity", parseGranularity(relativeDateFilter.granularity)));
783
- }
784
- // Add from/to only if both are defined
785
- if (relativeDateFilter.from !== undefined && relativeDateFilter.to !== undefined) {
786
- map.add(new Pair("from", relativeDateFilter.from));
787
- map.add(new Pair("to", relativeDateFilter.to));
788
- }
789
- }
790
- const id = getIdentifier(relativeDateFilter.dataSet, true, updateErrorContext(errorContext, {
791
- path: ["dataSet"],
792
- }));
793
- map.add(new Pair("using", id));
794
- processConnectedAttributeFilters(map, connectedAttributeFilters, entities, getUniqueKey, errorContext);
795
- return map;
796
- }
797
- /** @internal */
798
- export function declarativePositiveAttributeFilterToYaml(entities, attributeFilter, errorContext) {
799
- const map = new YAMLMap();
800
- map.add(new Pair("type", "attribute_filter"));
801
- const id = getIdentifier(attributeFilter.displayForm, undefined, updateErrorContext(errorContext, {
802
- path: ["displayForm"],
803
- }));
804
- map.add(new Pair("using", id));
805
- if (isAttributeElementsByValue(attributeFilter.in)) {
806
- const ind = attributeFilter.in;
807
- // Filter out null/undefined but preserve empty strings which are valid attribute values
808
- const values = ind.values.filter((v) => v !== null && v !== undefined);
809
- map.add(new Pair("state", new Pair("include", parseDateValues(entities, id, values))));
810
- }
811
- return map;
812
- }
813
- /** @internal */
814
- export function declarativeNegativeAttributeFilterToYaml(entities, attributeFilter, errorContext) {
815
- const map = new YAMLMap();
816
- map.add(new Pair("type", "attribute_filter"));
817
- const id = getIdentifier(attributeFilter.displayForm, undefined, updateErrorContext(errorContext, {
818
- path: ["displayForm"],
819
- }));
820
- map.add(new Pair("using", id));
821
- if (isAttributeElementsByValue(attributeFilter.notIn)) {
822
- const ind = attributeFilter.notIn;
823
- // Filter out null/undefined but preserve empty strings which are valid attribute values
824
- const values = ind.values.filter((v) => v !== null && v !== undefined);
825
- if (values.length > 0) {
826
- map.add(new Pair("state", new Pair("exclude", parseDateValues(entities, id, values))));
827
- }
828
- }
829
- return map;
830
- }
831
- export function declarativeArbitraryAttributeFilterToYaml(attributeFilter, errorContext) {
832
- const map = new YAMLMap();
833
- map.add(new Pair("type", "text_filter"));
834
- map.add(new Pair("using", getIdentifier(attributeFilter.label, undefined, updateErrorContext(errorContext, {
835
- path: ["label"],
836
- }))));
837
- map.add(new Pair("condition", attributeFilter.negativeSelection ? "isNot" : "is"));
838
- map.add(new Pair("values", attributeFilter.values));
839
- return map;
840
- }
841
- export function declarativeMatchAttributeFilterToYaml(attributeFilter, errorContext) {
842
- const map = new YAMLMap();
843
- map.add(new Pair("type", "text_filter"));
844
- map.add(new Pair("using", getIdentifier(attributeFilter.label, undefined, updateErrorContext(errorContext, {
845
- path: ["label"],
846
- }))));
847
- map.add(new Pair("condition", matchConditionToYaml(attributeFilter.operator, attributeFilter.negativeSelection)));
848
- map.add(new Pair("value", attributeFilter.literal));
849
- if (attributeFilter.caseSensitive !== undefined) {
850
- map.add(new Pair("case_sensitive", attributeFilter.caseSensitive));
851
- }
852
- return map;
853
- }
854
- function addSingleConditionToYaml(map, condition) {
855
- if (isComparisonCondition(condition)) {
856
- const comp = condition.comparison;
857
- map.add(new Pair("condition", comp.operator.toUpperCase()));
858
- map.add(new Pair("value", comp.value));
859
- map.add(new Pair("null_values_as_zero", comp.treatNullValuesAs !== undefined));
860
- }
861
- else if (isRangeCondition(condition)) {
862
- const range = condition.range;
863
- map.add(new Pair("condition", range.operator.toUpperCase()));
864
- map.add(new Pair("from", range.from));
865
- map.add(new Pair("to", range.to));
866
- map.add(new Pair("null_values_as_zero", range.treatNullValuesAs !== undefined));
867
- }
868
- }
869
- function addConditionToYamlMap(conditionMap, condition) {
870
- let hasTreatNullValues = false;
871
- if (isComparisonCondition(condition)) {
872
- const comp = condition.comparison;
873
- conditionMap.add(new Pair("condition", comp.operator.toUpperCase()));
874
- conditionMap.add(new Pair("value", comp.value));
875
- if (comp.treatNullValuesAs !== undefined) {
876
- hasTreatNullValues = true;
877
- }
878
- }
879
- else if (isRangeCondition(condition)) {
880
- const range = condition.range;
881
- conditionMap.add(new Pair("condition", range.operator.toUpperCase()));
882
- conditionMap.add(new Pair("from", range.from));
883
- conditionMap.add(new Pair("to", range.to));
884
- if (range.treatNullValuesAs !== undefined) {
885
- hasTreatNullValues = true;
886
- }
887
- }
888
- return hasTreatNullValues;
889
- }
890
- /** @internal */
891
- export function declarativeMeasureValueFilterToYaml(measureValueFilter, errorContext) {
892
- const map = new YAMLMap();
893
- map.add(new Pair("type", "metric_value_filter"));
894
- if (isLocalIdRef(measureValueFilter.measure)) {
895
- map.add(new Pair("using", measureValueFilter.measure.localIdentifier));
896
- }
897
- else {
898
- map.add(new Pair("using", getIdentifier(measureValueFilter.measure, undefined, updateErrorContext(errorContext, {
899
- path: ["measure"],
900
- }))));
901
- }
902
- // Handle multiple conditions (new SDK model feature)
903
- if (measureValueFilter.conditions && measureValueFilter.conditions.length > 1) {
904
- // Multiple conditions: use conditions array
905
- const conditionsSeq = new YAMLSeq();
906
- let treatNullValuesAsZero = false;
907
- measureValueFilter.conditions.forEach((cond) => {
908
- const conditionMap = new YAMLMap();
909
- if (addConditionToYamlMap(conditionMap, cond)) {
910
- treatNullValuesAsZero = true;
911
- }
912
- conditionsSeq.add(conditionMap);
913
- });
914
- map.add(new Pair("conditions", conditionsSeq));
915
- if (treatNullValuesAsZero) {
916
- map.add(new Pair("null_values_as_zero", true));
917
- }
918
- }
919
- else if (measureValueFilter.conditions?.length === 1) {
920
- // Single condition in array: use old format for cleaner output
921
- addSingleConditionToYaml(map, measureValueFilter.conditions[0]);
922
- }
923
- else if (measureValueFilter.condition) {
924
- // Fallback to single condition field for backward compatibility
925
- addSingleConditionToYaml(map, measureValueFilter.condition);
926
- }
927
- // Handle dimensionality field
928
- if (measureValueFilter.dimensionality && Array.isArray(measureValueFilter.dimensionality)) {
929
- const dimensionalitySeq = new YAMLSeq();
930
- measureValueFilter.dimensionality.forEach((item) => {
931
- if (isLocalIdRef(item)) {
932
- dimensionalitySeq.add(item.localIdentifier);
933
- }
934
- else {
935
- dimensionalitySeq.add(getIdentifier(item));
936
- }
937
- });
938
- map.add(new Pair("dimensionality", dimensionalitySeq));
939
- }
940
- return map;
941
- }
942
- /** @internal */
943
- export function declarativeRankingFilterToYaml(rankingFilter, errorContext) {
944
- const map = new YAMLMap();
945
- map.add(new Pair("type", "ranking_filter"));
946
- if (isLocalIdRef(rankingFilter.measure)) {
947
- map.add(new Pair("using", rankingFilter.measure.localIdentifier));
948
- }
949
- else {
950
- map.add(new Pair("using", getIdentifier(rankingFilter.measure, undefined, updateErrorContext(errorContext, {
951
- path: ["measure"],
952
- }))));
953
- }
954
- if (rankingFilter.operator === "TOP") {
955
- map.add(new Pair("top", rankingFilter.value));
956
- }
957
- if (rankingFilter.operator === "BOTTOM") {
958
- map.add(new Pair("bottom", rankingFilter.value));
959
- }
960
- //NOTE: There can be array, but UI allows only 1 attr now
961
- if (rankingFilter.attributes?.[0]) {
962
- const first = rankingFilter.attributes[0];
963
- if (isLocalIdRef(first)) {
964
- map.add(new Pair("attribute", first.localIdentifier));
965
- }
966
- else {
967
- map.add(new Pair("attribute", getIdentifier(first)));
968
- }
969
- }
970
- if (rankingFilter.strictLimitOfRows !== undefined) {
971
- map.add(new Pair("strict_limit_of_rows", rankingFilter.strictLimitOfRows));
972
- }
973
- return map;
974
- }
975
532
  /** @internal */
976
533
  export function declarativeSortsToYaml(sorts, _errorContext) {
977
534
  const sortsArray = [];
@@ -1033,15 +590,15 @@ export function declarativeMeasureSortToYaml(sort) {
1033
590
  //visualisations
1034
591
  function declarativeVisTableToYaml(doc, def, report, _context) {
1035
592
  //buckets
1036
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
593
+ const metrics = report.buckets.consume(BucketsType.Measures);
1037
594
  if (metrics && metrics.items.length > 0) {
1038
595
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1039
596
  }
1040
- const attribute = report.derivedBuckets.find((item) => item.type === BucketsType.Attribute);
597
+ const attribute = report.buckets.consume(BucketsType.Attribute);
1041
598
  if (attribute && attribute.items.length > 0) {
1042
599
  doc.add(entryWithSpace("view_by", groupToYaml(attribute)));
1043
600
  }
1044
- const columns = report.derivedBuckets.find((item) => item.type === BucketsType.Columns);
601
+ const columns = report.buckets.consume(BucketsType.Columns);
1045
602
  if (columns && columns.items.length > 0) {
1046
603
  doc.add(entryWithSpace("segment_by", groupToYaml(columns)));
1047
604
  }
@@ -1052,15 +609,15 @@ function declarativeVisTableToYaml(doc, def, report, _context) {
1052
609
  }
1053
610
  function declarativeVisBarToYaml(doc, def, report, _errorContext) {
1054
611
  //buckets
1055
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
612
+ const metrics = report.buckets.consume(BucketsType.Measures);
1056
613
  if (metrics && metrics.items.length > 0) {
1057
614
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1058
615
  }
1059
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
616
+ const view = report.buckets.consume(BucketsType.View);
1060
617
  if (view && view.items.length > 0) {
1061
618
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1062
619
  }
1063
- const stack = report.derivedBuckets.find((item) => item.type === BucketsType.Stack);
620
+ const stack = report.buckets.consume(BucketsType.Stack);
1064
621
  if (stack && stack.items.length > 0) {
1065
622
  doc.add(entryWithSpace("segment_by", groupToYaml(stack)));
1066
623
  }
@@ -1071,15 +628,15 @@ function declarativeVisBarToYaml(doc, def, report, _errorContext) {
1071
628
  }
1072
629
  function declarativeVisColumnToYaml(doc, def, report, _errorContext) {
1073
630
  //buckets
1074
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
631
+ const metrics = report.buckets.consume(BucketsType.Measures);
1075
632
  if (metrics && metrics.items.length > 0) {
1076
633
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1077
634
  }
1078
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
635
+ const view = report.buckets.consume(BucketsType.View);
1079
636
  if (view && view.items.length > 0) {
1080
637
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1081
638
  }
1082
- const stack = report.derivedBuckets.find((item) => item.type === BucketsType.Stack);
639
+ const stack = report.buckets.consume(BucketsType.Stack);
1083
640
  if (stack && stack.items.length > 0) {
1084
641
  doc.add(entryWithSpace("segment_by", groupToYaml(stack)));
1085
642
  }
@@ -1090,15 +647,15 @@ function declarativeVisColumnToYaml(doc, def, report, _errorContext) {
1090
647
  }
1091
648
  function declarativeVisLineToYaml(doc, def, report, _errorContext) {
1092
649
  //buckets
1093
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
650
+ const metrics = report.buckets.consume(BucketsType.Measures);
1094
651
  if (metrics && metrics.items.length > 0) {
1095
652
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1096
653
  }
1097
- const trend = report.derivedBuckets.find((item) => item.type === BucketsType.Trend);
654
+ const trend = report.buckets.consume(BucketsType.Trend);
1098
655
  if (trend && trend.items.length > 0) {
1099
656
  doc.add(entryWithSpace("view_by", groupToYaml(trend)));
1100
657
  }
1101
- const segment = report.derivedBuckets.find((item) => item.type === BucketsType.Segment);
658
+ const segment = report.buckets.consume(BucketsType.Segment);
1102
659
  if (segment && segment.items.length > 0) {
1103
660
  doc.add(entryWithSpace("segment_by", groupToYaml(segment)));
1104
661
  }
@@ -1109,15 +666,15 @@ function declarativeVisLineToYaml(doc, def, report, _errorContext) {
1109
666
  }
1110
667
  function declarativeVisRadarToYaml(doc, def, report, _errorContext) {
1111
668
  //buckets
1112
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
669
+ const metrics = report.buckets.consume(BucketsType.Measures);
1113
670
  if (metrics && metrics.items.length > 0) {
1114
671
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1115
672
  }
1116
- const trend = report.derivedBuckets.find((item) => item.type === BucketsType.Trend);
673
+ const trend = report.buckets.consume(BucketsType.Trend);
1117
674
  if (trend && trend.items.length > 0) {
1118
675
  doc.add(entryWithSpace("view_by", groupToYaml(trend)));
1119
676
  }
1120
- const segment = report.derivedBuckets.find((item) => item.type === BucketsType.Segment);
677
+ const segment = report.buckets.consume(BucketsType.Segment);
1121
678
  if (segment && segment.items.length > 0) {
1122
679
  doc.add(entryWithSpace("segment_by", groupToYaml(segment)));
1123
680
  }
@@ -1128,15 +685,15 @@ function declarativeVisRadarToYaml(doc, def, report, _errorContext) {
1128
685
  }
1129
686
  function declarativeVisAreaToYaml(doc, def, report, _errorContext) {
1130
687
  //buckets
1131
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
688
+ const metrics = report.buckets.consume(BucketsType.Measures);
1132
689
  if (metrics && metrics.items.length > 0) {
1133
690
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1134
691
  }
1135
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
692
+ const view = report.buckets.consume(BucketsType.View);
1136
693
  if (view && view.items.length > 0) {
1137
694
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1138
695
  }
1139
- const stack = report.derivedBuckets.find((item) => item.type === BucketsType.Stack);
696
+ const stack = report.buckets.consume(BucketsType.Stack);
1140
697
  if (stack && stack.items.length > 0) {
1141
698
  doc.add(entryWithSpace("segment_by", groupToYaml(stack)));
1142
699
  }
@@ -1147,8 +704,8 @@ function declarativeVisAreaToYaml(doc, def, report, _errorContext) {
1147
704
  }
1148
705
  function declarativeVisScatterToYaml(doc, def, report, _errorContext) {
1149
706
  //buckets
1150
- const metrics1 = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
1151
- const metrics2 = report.derivedBuckets.find((item) => item.type === BucketsType.SecondaryMeasures);
707
+ const metrics1 = report.buckets.consume(BucketsType.Measures);
708
+ const metrics2 = report.buckets.consume(BucketsType.SecondaryMeasures);
1152
709
  const metrics = {
1153
710
  items: cleanUpItems([
1154
711
  ...(metrics1?.items.length ? metrics1.items : [null]),
@@ -1159,11 +716,11 @@ function declarativeVisScatterToYaml(doc, def, report, _errorContext) {
1159
716
  if (metrics.items.length > 0) {
1160
717
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1161
718
  }
1162
- const attributes = report.derivedBuckets.find((item) => item.type === BucketsType.Attribute);
719
+ const attributes = report.buckets.consume(BucketsType.Attribute);
1163
720
  if (attributes && attributes.items.length > 0) {
1164
721
  doc.add(entryWithSpace("view_by", groupToYaml(attributes)));
1165
722
  }
1166
- const segments = report.derivedBuckets.find((item) => item.type === BucketsType.Segment);
723
+ const segments = report.buckets.consume(BucketsType.Segment);
1167
724
  if (segments && segments.items.length > 0) {
1168
725
  doc.add(entryWithSpace("segment_by", groupToYaml(segments)));
1169
726
  }
@@ -1174,8 +731,8 @@ function declarativeVisScatterToYaml(doc, def, report, _errorContext) {
1174
731
  }
1175
732
  function declarativeVisBubbleToYaml(doc, def, report, _errorContext) {
1176
733
  //buckets
1177
- const metrics1 = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
1178
- const metrics2 = report.derivedBuckets.find((item) => item.type === BucketsType.SecondaryMeasures);
734
+ const metrics1 = report.buckets.consume(BucketsType.Measures);
735
+ const metrics2 = report.buckets.consume(BucketsType.SecondaryMeasures);
1179
736
  const metrics = {
1180
737
  items: cleanUpItems([
1181
738
  ...(metrics1?.items.length ? metrics1.items : [null]),
@@ -1186,11 +743,11 @@ function declarativeVisBubbleToYaml(doc, def, report, _errorContext) {
1186
743
  if (metrics.items.length > 0) {
1187
744
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1188
745
  }
1189
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
746
+ const view = report.buckets.consume(BucketsType.View);
1190
747
  if (view && view.items.length > 0) {
1191
748
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1192
749
  }
1193
- const tertiaryMetrics = report.derivedBuckets.find((item) => item.type === BucketsType.TertiaryMeasures);
750
+ const tertiaryMetrics = report.buckets.consume(BucketsType.TertiaryMeasures);
1194
751
  if (tertiaryMetrics && tertiaryMetrics.items.length > 0) {
1195
752
  doc.add(entryWithSpace("segment_by", groupToYaml(tertiaryMetrics)));
1196
753
  }
@@ -1201,11 +758,11 @@ function declarativeVisBubbleToYaml(doc, def, report, _errorContext) {
1201
758
  }
1202
759
  function declarativeVisPieToYaml(doc, def, report, _errorContext) {
1203
760
  //buckets
1204
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
761
+ const metrics = report.buckets.consume(BucketsType.Measures);
1205
762
  if (metrics && metrics.items.length > 0) {
1206
763
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1207
764
  }
1208
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
765
+ const view = report.buckets.consume(BucketsType.View);
1209
766
  if (view && view.items.length > 0) {
1210
767
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1211
768
  }
@@ -1216,11 +773,11 @@ function declarativeVisPieToYaml(doc, def, report, _errorContext) {
1216
773
  }
1217
774
  function declarativeVisDonutToYaml(doc, def, report, _errorContext) {
1218
775
  //buckets
1219
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
776
+ const metrics = report.buckets.consume(BucketsType.Measures);
1220
777
  if (metrics && metrics.items.length > 0) {
1221
778
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1222
779
  }
1223
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
780
+ const view = report.buckets.consume(BucketsType.View);
1224
781
  if (view && view.items.length > 0) {
1225
782
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1226
783
  }
@@ -1231,15 +788,15 @@ function declarativeVisDonutToYaml(doc, def, report, _errorContext) {
1231
788
  }
1232
789
  function declarativeVisTreemapToYaml(doc, def, report, _errorContext) {
1233
790
  //buckets
1234
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
791
+ const metrics = report.buckets.consume(BucketsType.Measures);
1235
792
  if (metrics && metrics.items.length > 0) {
1236
793
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1237
794
  }
1238
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
795
+ const view = report.buckets.consume(BucketsType.View);
1239
796
  if (view && view.items.length > 0) {
1240
797
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1241
798
  }
1242
- const segment = report.derivedBuckets.find((item) => item.type === BucketsType.Segment);
799
+ const segment = report.buckets.consume(BucketsType.Segment);
1243
800
  if (segment && segment.items.length > 0) {
1244
801
  doc.add(entryWithSpace("segment_by", groupToYaml(segment)));
1245
802
  }
@@ -1250,11 +807,11 @@ function declarativeVisTreemapToYaml(doc, def, report, _errorContext) {
1250
807
  }
1251
808
  function declarativeVisPyramidToYaml(doc, def, report, _errorContext) {
1252
809
  //buckets
1253
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
810
+ const metrics = report.buckets.consume(BucketsType.Measures);
1254
811
  if (metrics && metrics.items.length > 0) {
1255
812
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1256
813
  }
1257
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
814
+ const view = report.buckets.consume(BucketsType.View);
1258
815
  if (view && view.items.length > 0) {
1259
816
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1260
817
  }
@@ -1265,11 +822,11 @@ function declarativeVisPyramidToYaml(doc, def, report, _errorContext) {
1265
822
  }
1266
823
  function declarativeVisFunnelToYaml(doc, def, report, _errorContext) {
1267
824
  //buckets
1268
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
825
+ const metrics = report.buckets.consume(BucketsType.Measures);
1269
826
  if (metrics && metrics.items.length > 0) {
1270
827
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1271
828
  }
1272
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
829
+ const view = report.buckets.consume(BucketsType.View);
1273
830
  if (view && view.items.length > 0) {
1274
831
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1275
832
  }
@@ -1280,15 +837,15 @@ function declarativeVisFunnelToYaml(doc, def, report, _errorContext) {
1280
837
  }
1281
838
  function declarativeVisHeatmapToYaml(doc, def, report, _errorContext) {
1282
839
  //buckets
1283
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
840
+ const metrics = report.buckets.consume(BucketsType.Measures);
1284
841
  if (metrics && metrics.items.length > 0) {
1285
842
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1286
843
  }
1287
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
844
+ const view = report.buckets.consume(BucketsType.View);
1288
845
  if (view && view.items.length > 0) {
1289
846
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1290
847
  }
1291
- const stack = report.derivedBuckets.find((item) => item.type === BucketsType.Stack);
848
+ const stack = report.buckets.consume(BucketsType.Stack);
1292
849
  if (stack && stack.items.length > 0) {
1293
850
  doc.add(entryWithSpace("segment_by", groupToYaml(stack)));
1294
851
  }
@@ -1299,9 +856,9 @@ function declarativeVisHeatmapToYaml(doc, def, report, _errorContext) {
1299
856
  }
1300
857
  function declarativeVisBulletToYaml(doc, def, report, _errorContext) {
1301
858
  //buckets
1302
- const metrics1 = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
1303
- const metrics2 = report.derivedBuckets.find((item) => item.type === BucketsType.SecondaryMeasures);
1304
- const metrics3 = report.derivedBuckets.find((item) => item.type === BucketsType.TertiaryMeasures);
859
+ const metrics1 = report.buckets.consume(BucketsType.Measures);
860
+ const metrics2 = report.buckets.consume(BucketsType.SecondaryMeasures);
861
+ const metrics3 = report.buckets.consume(BucketsType.TertiaryMeasures);
1305
862
  const metrics = {
1306
863
  items: cleanUpItems([
1307
864
  ...(metrics1?.items.length ? metrics1.items : [null]),
@@ -1313,7 +870,7 @@ function declarativeVisBulletToYaml(doc, def, report, _errorContext) {
1313
870
  if (metrics.items.length > 0) {
1314
871
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1315
872
  }
1316
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
873
+ const view = report.buckets.consume(BucketsType.View);
1317
874
  if (view && view.items.length > 0) {
1318
875
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1319
876
  }
@@ -1324,11 +881,11 @@ function declarativeVisBulletToYaml(doc, def, report, _errorContext) {
1324
881
  }
1325
882
  function declarativeVisWaterfallToYaml(doc, def, report, _errorContext) {
1326
883
  //buckets
1327
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
884
+ const metrics = report.buckets.consume(BucketsType.Measures);
1328
885
  if (metrics && metrics.items.length > 0) {
1329
886
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1330
887
  }
1331
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
888
+ const view = report.buckets.consume(BucketsType.View);
1332
889
  if (view && view.items.length > 0) {
1333
890
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1334
891
  }
@@ -1339,12 +896,12 @@ function declarativeVisWaterfallToYaml(doc, def, report, _errorContext) {
1339
896
  }
1340
897
  function declarativeVisDependencyWheelToYaml(doc, def, report, _errorContext) {
1341
898
  //buckets
1342
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
899
+ const metrics = report.buckets.consume(BucketsType.Measures);
1343
900
  if (metrics && metrics.items.length > 0) {
1344
901
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1345
902
  }
1346
- const from = report.derivedBuckets.find((item) => item.type === BucketsType.AttributeFrom);
1347
- const to = report.derivedBuckets.find((item) => item.type === BucketsType.AttributeTo);
903
+ const from = report.buckets.consume(BucketsType.AttributeFrom);
904
+ const to = report.buckets.consume(BucketsType.AttributeTo);
1348
905
  const view = {
1349
906
  items: cleanUpItems([
1350
907
  ...(from?.items.length ? from.items : [null]),
@@ -1362,12 +919,12 @@ function declarativeVisDependencyWheelToYaml(doc, def, report, _errorContext) {
1362
919
  }
1363
920
  function declarativeVisSankeyToYaml(doc, def, report, _errorContext) {
1364
921
  //buckets
1365
- const metrics = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
922
+ const metrics = report.buckets.consume(BucketsType.Measures);
1366
923
  if (metrics && metrics.items.length > 0) {
1367
924
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1368
925
  }
1369
- const from = report.derivedBuckets.find((item) => item.type === BucketsType.AttributeFrom);
1370
- const to = report.derivedBuckets.find((item) => item.type === BucketsType.AttributeTo);
926
+ const from = report.buckets.consume(BucketsType.AttributeFrom);
927
+ const to = report.buckets.consume(BucketsType.AttributeTo);
1371
928
  const view = {
1372
929
  items: cleanUpItems([
1373
930
  ...(from?.items.length ? from.items : [null]),
@@ -1385,8 +942,8 @@ function declarativeVisSankeyToYaml(doc, def, report, _errorContext) {
1385
942
  }
1386
943
  function declarativeVisHeadlineToYaml(doc, def, report, _errorContext) {
1387
944
  //buckets
1388
- const metrics1 = report.derivedBuckets.find((item) => item.type === BucketsType.Measures);
1389
- const metrics2 = report.derivedBuckets.find((item) => item.type === BucketsType.SecondaryMeasures);
945
+ const metrics1 = report.buckets.consume(BucketsType.Measures);
946
+ const metrics2 = report.buckets.consume(BucketsType.SecondaryMeasures);
1390
947
  const metrics = {
1391
948
  items: [...(metrics1?.items ?? [null]), ...(metrics2?.items ?? [])],
1392
949
  type: BucketsType.Measures,
@@ -1401,8 +958,8 @@ function declarativeVisHeadlineToYaml(doc, def, report, _errorContext) {
1401
958
  }
1402
959
  function declarativeVisComboToYaml(doc, def, report, _errorContext) {
1403
960
  //buckets
1404
- const metrics1 = addAxisTypeToGroup(report.derivedBuckets.find((item) => item.type === BucketsType.Measures), "primary");
1405
- const metrics2 = addAxisTypeToGroup(report.derivedBuckets.find((item) => item.type === BucketsType.SecondaryMeasures), "secondary");
961
+ const metrics1 = addAxisTypeToGroup(report.buckets.consume(BucketsType.Measures), "primary");
962
+ const metrics2 = addAxisTypeToGroup(report.buckets.consume(BucketsType.SecondaryMeasures), "secondary");
1406
963
  const metrics = {
1407
964
  items: [...(metrics1?.items ?? []), ...(metrics2?.items ?? [])],
1408
965
  type: BucketsType.Measures,
@@ -1410,7 +967,7 @@ function declarativeVisComboToYaml(doc, def, report, _errorContext) {
1410
967
  if (metrics && metrics.items.length > 0) {
1411
968
  doc.add(entryWithSpace("metrics", groupToYaml(metrics)));
1412
969
  }
1413
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
970
+ const view = report.buckets.consume(BucketsType.View);
1414
971
  if (view && view.items.length > 0) {
1415
972
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1416
973
  }
@@ -1419,9 +976,9 @@ function declarativeVisComboToYaml(doc, def, report, _errorContext) {
1419
976
  doc.add(config);
1420
977
  }
1421
978
  }
1422
- function addPushpinBucketsToYaml(target, groups) {
1423
- const sizeBucket = groups.find((item) => item.type === BucketsType.Size);
1424
- const colorBucket = groups.find((item) => item.type === BucketsType.Color);
979
+ function addPushpinBucketsToYaml(target, buckets) {
980
+ const sizeBucket = buckets.consume(BucketsType.Size);
981
+ const colorBucket = buckets.consume(BucketsType.Color);
1425
982
  const metrics = {
1426
983
  items: cleanUpItems([
1427
984
  ...(sizeBucket?.items.length ? sizeBucket.items : [null]),
@@ -1432,17 +989,17 @@ function addPushpinBucketsToYaml(target, groups) {
1432
989
  if (metrics.items.length > 0) {
1433
990
  target.add(entryWithSpace("metrics", groupToYaml(metrics)));
1434
991
  }
1435
- const location = groups.find((item) => item.type === BucketsType.Location);
992
+ const location = buckets.consume(BucketsType.Location);
1436
993
  if (location && location.items.length > 0) {
1437
994
  target.add(entryWithSpace("view_by", groupToYaml(location)));
1438
995
  }
1439
- const segment = groups.find((item) => item.type === BucketsType.Segment);
996
+ const segment = buckets.consume(BucketsType.Segment);
1440
997
  if (segment && segment.items.length > 0) {
1441
998
  target.add(entryWithSpace("segment_by", groupToYaml(segment)));
1442
999
  }
1443
1000
  }
1444
- function addGeoAreaBucketsToYaml(target, groups) {
1445
- const colorBucket = groups.find((item) => item.type === BucketsType.Color);
1001
+ function addGeoAreaBucketsToYaml(target, buckets) {
1002
+ const colorBucket = buckets.consume(BucketsType.Color);
1446
1003
  const metrics = {
1447
1004
  items: cleanUpItems([...(colorBucket?.items.length ? colorBucket.items : [null])]),
1448
1005
  type: BucketsType.Measures,
@@ -1450,18 +1007,18 @@ function addGeoAreaBucketsToYaml(target, groups) {
1450
1007
  if (metrics.items.length > 0) {
1451
1008
  target.add(entryWithSpace("metrics", groupToYaml(metrics)));
1452
1009
  }
1453
- const area = groups.find((item) => item.type === BucketsType.Area);
1010
+ const area = buckets.consume(BucketsType.Area);
1454
1011
  if (area && area.items.length > 0) {
1455
1012
  target.add(entryWithSpace("view_by", groupToYaml(area)));
1456
1013
  }
1457
- const segment = groups.find((item) => item.type === BucketsType.Segment);
1014
+ const segment = buckets.consume(BucketsType.Segment);
1458
1015
  if (segment && segment.items.length > 0) {
1459
1016
  target.add(entryWithSpace("segment_by", groupToYaml(segment)));
1460
1017
  }
1461
1018
  }
1462
1019
  function declarativeVisGeoToYaml(doc, def, report, entities, errorContext) {
1463
1020
  //buckets
1464
- addPushpinBucketsToYaml(doc, report.derivedBuckets);
1021
+ addPushpinBucketsToYaml(doc, report.buckets);
1465
1022
  const config = geoChart.load(def.properties);
1466
1023
  if (config) {
1467
1024
  doc.add(config);
@@ -1470,7 +1027,7 @@ function declarativeVisGeoToYaml(doc, def, report, entities, errorContext) {
1470
1027
  }
1471
1028
  function declarativeVisGeoAreaToYaml(doc, def, report, entities, errorContext) {
1472
1029
  //buckets
1473
- addGeoAreaBucketsToYaml(doc, report.derivedBuckets);
1030
+ addGeoAreaBucketsToYaml(doc, report.buckets);
1474
1031
  const config = geoAreaChart.load(def.properties);
1475
1032
  if (config) {
1476
1033
  doc.add(config);
@@ -1488,16 +1045,16 @@ function appendLayers(doc, def, entities, errorContext) {
1488
1045
  }
1489
1046
  }
1490
1047
  function declarativeVisRepeaterToYaml(doc, def, report, _errorContext) {
1491
- const columns = report.derivedBuckets.find((item) => item.type === BucketsType.Columns);
1048
+ const columns = report.buckets.consume(BucketsType.Columns);
1492
1049
  const columnsMapped = addChartTypeToGroup(columns, def.properties);
1493
1050
  if (columnsMapped && columnsMapped.items.length > 0) {
1494
1051
  doc.add(entryWithSpace("metrics", groupToYaml(columnsMapped)));
1495
1052
  }
1496
- const view = report.derivedBuckets.find((item) => item.type === BucketsType.View);
1053
+ const view = report.buckets.consume(BucketsType.View);
1497
1054
  if (view && view.items.length > 0) {
1498
1055
  doc.add(entryWithSpace("view_by", groupToYaml(view)));
1499
1056
  }
1500
- const attribute = report.derivedBuckets.find((item) => item.type === BucketsType.Attribute);
1057
+ const attribute = report.buckets.consume(BucketsType.Attribute);
1501
1058
  if (attribute && attribute.items.length > 0) {
1502
1059
  doc.add(entryWithSpace("segment_by", groupToYaml(attribute)));
1503
1060
  }
@@ -1584,10 +1141,28 @@ function addChartTypeToGroup(group, config) {
1584
1141
  }),
1585
1142
  };
1586
1143
  }
1144
+ // Each check matches what the emitter would have written, so a value it would have ignored anyway (an
1145
+ // unrecognized filter, a config carrying no label) is not refused.
1146
+ function unrepresentableLayerField(layer) {
1147
+ if (layer.filters?.some(isFilter)) {
1148
+ return "filters";
1149
+ }
1150
+ if (layer.sorts?.length) {
1151
+ return "sorts";
1152
+ }
1153
+ const configs = Object.values(layer.attributeFilterConfigs ?? {});
1154
+ return configs.some((config) => config?.displayAsLabel) ? "attributeFilterConfigs" : null;
1155
+ }
1587
1156
  function declarativeLayersToYaml(entities, layersDefinition, errorContext) {
1588
1157
  const layers = new YAMLSeq();
1589
1158
  layersDefinition.forEach((layer, li) => {
1590
- const { groups } = declarativeBucketsToYaml(entities, layer.buckets ?? [], updateErrorContext(errorContext, { path: [li.toString(), "buckets"] }));
1159
+ // A layer's own filters and sorts would read back as the insight's, so they are refused.
1160
+ const unrepresentable = unrepresentableLayerField(layer);
1161
+ if (unrepresentable !== null) {
1162
+ throw newError(CoreErrorCode.ItemNotSupported, [`layer "${layer.id}" own ${unrepresentable}`], updateErrorContext(errorContext, { path: [li.toString(), unrepresentable] }));
1163
+ }
1164
+ const { groups: layerGroups } = declarativeBucketsToYaml(entities, layer.buckets ?? [], updateErrorContext(errorContext, { path: [li.toString(), "buckets"] }));
1165
+ const buckets = bucketRegistry(layerGroups);
1591
1166
  const layerKind = resolveLayerExportKind(layer.type, updateErrorContext(errorContext, { path: [li.toString(), "type"] }));
1592
1167
  const layerMap = new YAMLMap();
1593
1168
  layerMap.add(new Pair("id", layer.id));
@@ -1597,7 +1172,8 @@ function declarativeLayersToYaml(entities, layersDefinition, errorContext) {
1597
1172
  if (layer.type) {
1598
1173
  layerMap.add(new Pair("type", layer.type));
1599
1174
  }
1600
- appendLayerBucketsForKind(layerMap, groups, layerKind, updateErrorContext(errorContext, { path: [li.toString()] }));
1175
+ appendLayerBucketsForKind(layerMap, buckets, layerKind, updateErrorContext(errorContext, { path: [li.toString()] }));
1176
+ buckets.assertAllConsumed(updateErrorContext(errorContext, { path: [li.toString()] }));
1601
1177
  addLayerConfig(layerMap, layerKind, layer.properties);
1602
1178
  layers.add(layerMap);
1603
1179
  });
@@ -1612,13 +1188,13 @@ function resolveLayerExportKind(rawLayerType, errorContext) {
1612
1188
  }
1613
1189
  throw newError(CoreErrorCode.LayerTypeNotSupported, [rawLayerType ?? "<missing>"], errorContext);
1614
1190
  }
1615
- function appendLayerBucketsForKind(layerMap, groups, kind, errorContext) {
1191
+ function appendLayerBucketsForKind(layerMap, buckets, kind, errorContext) {
1616
1192
  if (kind === "pushpin") {
1617
- addPushpinBucketsToYaml(layerMap, groups);
1193
+ addPushpinBucketsToYaml(layerMap, buckets);
1618
1194
  return;
1619
1195
  }
1620
1196
  if (kind === "area") {
1621
- addGeoAreaBucketsToYaml(layerMap, groups);
1197
+ addGeoAreaBucketsToYaml(layerMap, buckets);
1622
1198
  return;
1623
1199
  }
1624
1200
  throw newError(CoreErrorCode.LayerTypeNotSupported, [kind], errorContext);