@sis-cc/dotstatsuite-components 16.3.0 → 16.5.0

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.
@@ -39,7 +39,14 @@ var parseAttributesValues = function parseAttributesValues(obs, attributes, inde
39
39
  if (R.isNil(attribute) || !R.prop('series', attribute)) {
40
40
  return acc;
41
41
  }
42
- var value = R.nth(valueIndex, attribute.values || []);
42
+ var _value = R.nth(valueIndex, attribute.values || []);
43
+ var value = R.isNil(_value) ? _value : R.over(R.lensProp('display'), function () {
44
+ var display = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true;
45
+ return display && !R.includes(_value.id, _constants.REJECTED_VALUE_IDS);
46
+ })(_value);
47
+ if ((!R.propOr(true, 'display', attribute) || !R.propOr(true, 'display', value)) && !R.prop('combined', attribute)) {
48
+ value = null;
49
+ }
43
50
  var relationship = R.propOr([], 'relationship', attribute);
44
51
  var coordinates = {};
45
52
  var serieKey = R.pipe(function (dims) {
@@ -51,7 +58,7 @@ var parseAttributesValues = function parseAttributesValues(obs, attributes, inde
51
58
  return dim.id + '=' + valueId;
52
59
  }), R.ifElse(R.isEmpty, R.always(null), R.join(':')))(indexedDimensions);
53
60
 
54
- return R.assoc(attribute.id, (0, _extends3.default)({}, R.pick(['id', 'name', 'relationship'], attribute), { value: value, serieKey: serieKey, coordinates: coordinates, isObs: R.isEmpty(relationship) }), acc);
61
+ return R.assoc(attribute.id, (0, _extends3.default)({}, R.pick(['id', 'name', 'relationship', 'display'], attribute), { value: value, serieKey: serieKey, coordinates: coordinates, isObs: R.isEmpty(relationship) }), acc);
55
62
  }, {}, attrValuesIndexes);
56
63
  };
57
64
 
@@ -0,0 +1,18 @@
1
+ 'use strict';
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getHeaderCoordinates = undefined;
7
+
8
+ var _ramda = require('ramda');
9
+
10
+ var R = _interopRequireWildcard(_ramda);
11
+
12
+ function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
13
+
14
+ var getHeaderCoordinates = exports.getHeaderCoordinates = function getHeaderCoordinates(oneValueDimensions) {
15
+ return R.reduce(function (acc, dim) {
16
+ return R.assoc(dim.id, R.path(['values', 0, 'id'], dim), acc);
17
+ }, {}, oneValueDimensions);
18
+ };
@@ -265,6 +265,15 @@ Object.defineProperty(exports, 'getHeaderCombinations', {
265
265
  }
266
266
  });
267
267
 
268
+ var _getHeaderCoordinates = require('./getHeaderCoordinates');
269
+
270
+ Object.defineProperty(exports, 'getHeaderCoordinates', {
271
+ enumerable: true,
272
+ get: function get() {
273
+ return _getHeaderCoordinates.getHeaderCoordinates;
274
+ }
275
+ });
276
+
268
277
  var _getLayout = require('./table/getLayout');
269
278
 
270
279
  Object.defineProperty(exports, 'getLayout', {
@@ -43,6 +43,8 @@ var _getHeaderSubtitle = require('./getHeaderSubtitle');
43
43
 
44
44
  var _getHeaderCombinations = require('./getHeaderCombinations');
45
45
 
46
+ var _getHeaderCoordinates = require('./getHeaderCoordinates');
47
+
46
48
  function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
47
49
 
48
50
  var prepareData = exports.prepareData = function prepareData(sdmxJson, _ref) {
@@ -75,6 +77,7 @@ var prepareData = exports.prepareData = function prepareData(sdmxJson, _ref) {
75
77
  var attributesSeries = (0, _getAttributesSeries.getAttributesSeries)(enhancedObservations);
76
78
  var manyValuesDimensions = (0, _getManyValuesDimensions.getManyValuesDimensions)(dimensions, attributesSeries, customAttributes, seriesCombinations);
77
79
  var oneValueDimensions = (0, _getOneValueDimensions.getOneValueDimensions)(dimensions, parsedAttributes);
80
+ var headerCoordinates = (0, _getHeaderCoordinates.getHeaderCoordinates)(oneValueDimensions);
78
81
  var hierarchisedDimensions = R.map(function (dim) {
79
82
  if (R.isEmpty(R.propOr({}, dim.id, hierarchies))) {
80
83
  return (0, _hierarchiseDimensionWithNativeHierarchy.hierarchiseDimensionWithNativeHierarchy)(dim);
@@ -99,7 +102,8 @@ var prepareData = exports.prepareData = function prepareData(sdmxJson, _ref) {
99
102
  header: {
100
103
  title: headerTitle,
101
104
  subtitle: headerSubtitle,
102
- combinations: headerCombinations
105
+ combinations: headerCombinations,
106
+ coordinates: headerCoordinates
103
107
  }
104
108
  };
105
109
  };
@@ -25,7 +25,7 @@ var refineAttributes = exports.refineAttributes = function refineAttributes(pars
25
25
  }, {}, seriesCombinations);
26
26
  return R.map(function (attr) {
27
27
  if (R.has(attr.id, indexedRelationships)) {
28
- return (0, _extends3.default)({}, attr, { series: true, relationship: R.prop(attr.id, indexedRelationships) });
28
+ return (0, _extends3.default)({}, attr, { series: true, relationship: R.prop(attr.id, indexedRelationships), combined: true });
29
29
  }
30
30
  return attr;
31
31
  }, parsedAttributes);
@@ -21,7 +21,7 @@ var getFlagsAndNotes = exports.getFlagsAndNotes = function getFlagsAndNotes(attr
21
21
  if (!R.has(id, attributesValues)) {
22
22
  return acc;
23
23
  }
24
- var attr = R.prop(id, attributesValues);
24
+ var attr = R.pick(['id', 'name', 'value', 'display'], R.prop(id, attributesValues));
25
25
  if (R.isNil(attr.value) || !R.pathOr(true, ['value', 'display'], attr) || !R.propOr(true, 'display', attr) || R.includes(R.path(['value', 'id'], attr), _constants.REJECTED_VALUE_IDS)) {
26
26
  return acc;
27
27
  }
@@ -5,14 +5,14 @@ Object.defineProperty(exports, "__esModule", {
5
5
  });
6
6
  exports.getLayoutData = undefined;
7
7
 
8
- var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties');
9
-
10
- var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2);
11
-
12
8
  var _slicedToArray2 = require('babel-runtime/helpers/slicedToArray');
13
9
 
14
10
  var _slicedToArray3 = _interopRequireDefault(_slicedToArray2);
15
11
 
12
+ var _objectWithoutProperties2 = require('babel-runtime/helpers/objectWithoutProperties');
13
+
14
+ var _objectWithoutProperties3 = _interopRequireDefault(_objectWithoutProperties2);
15
+
16
16
  var _extends2 = require('babel-runtime/helpers/extends');
17
17
 
18
18
  var _extends3 = _interopRequireDefault(_extends2);
@@ -23,13 +23,11 @@ var R = _interopRequireWildcard(_ramda);
23
23
 
24
24
  var _getFlagsAndNotes = require('./getFlagsAndNotes');
25
25
 
26
- var _hasCellMetadata = require('../hasCellMetadata');
27
-
28
26
  var _getCombinationDimensionsData = require('./getCombinationDimensionsData');
29
27
 
30
28
  var _parseValueHierarchy = require('./parseValueHierarchy');
31
29
 
32
- var _constants = require('../constants');
30
+ var _utils = require('../utils');
33
31
 
34
32
  function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } }
35
33
 
@@ -117,18 +115,16 @@ var getSubLayoutData = function getSubLayoutData(series, _definition, _ref) {
117
115
  i++;
118
116
  }
119
117
 
120
- var attributesValues = R.reduce(function (acc, key) {
121
- var splitKey = R.split(':', key);
122
- var isValid = R.all(function (entry) {
123
- var _R$split = R.split('=', entry),
124
- _R$split2 = (0, _slicedToArray3.default)(_R$split, 2),
125
- d = _R$split2[0],
126
- v = _R$split2[1];
127
-
128
- return R.propEq(d, v, coordinates);
129
- }, splitKey);
130
- return isValid ? (0, _extends3.default)({}, acc, R.length(splitKey) === 1 ? R.pick(combinationConceptIds, R.prop(key, attributesSeries)) : R.prop(key, attributesSeries)) : acc;
131
- }, {}, R.keys(attributesSeries));
118
+ var coordinatesValidator = (0, _utils.getLayoutCoordinatesValidator)(coordinates, topCoordinates);
119
+ var attributesValues = R.reduce(function (acc, serie) {
120
+ var coordinates = R.path([0, 'coordinates'], R.values(serie));
121
+ var isValid = coordinatesValidator(coordinates);
122
+ if (!isValid) {
123
+ return acc;
124
+ }
125
+ var isSingleBounded = R.length(R.keys(coordinates)) === 1;
126
+ return (0, _extends3.default)({}, acc, isSingleBounded ? R.pick(combinationConceptIds, serie) : serie);
127
+ }, {}, R.values(attributesSeries));
132
128
 
133
129
  data = R.addIndex(R.reduce)(function (acc, entry, ind) {
134
130
  if (!R.has('dimValues', entry)) {
@@ -158,10 +154,10 @@ var getSubLayoutData = function getSubLayoutData(series, _definition, _ref) {
158
154
  return R.append({ dimension: dimension, values: values }, acc);
159
155
  }, [], data);
160
156
 
161
- var layoutAttrValues = R.pipe(R.omit(combinationConceptIds), R.reject(R.prop('isObs')))(attributesValues);
157
+ var layoutAttrValues = R.reject(R.prop('isObs'), R.omit(combinationConceptIds, attributesValues));
162
158
 
163
159
  var flags = (0, _getFlagsAndNotes.getFlagsAndNotes)(layoutAttrValues, customAttributes);
164
- var hasMetadata = (0, _hasCellMetadata.hasCellMetadata)(metadataCoordinates, coordinates);
160
+ var hasMetadata = !R.isNil(R.find(coordinatesValidator, metadataCoordinates));
165
161
 
166
162
  if (!hasAdvancedAttributes) {
167
163
  hasAdvancedAttributes = getHasAdvancedAttributes(layoutAttrValues);
@@ -182,12 +178,14 @@ var getSubLayoutData = function getSubLayoutData(series, _definition, _ref) {
182
178
  var getLayoutData = function getLayoutData(layoutIndexes, layout, _ref2) {
183
179
  var metadataCoordinates = _ref2.metadataCoordinates,
184
180
  attributesSeries = _ref2.attributesSeries,
185
- customAttributes = _ref2.customAttributes;
181
+ customAttributes = _ref2.customAttributes,
182
+ _ref2$topCoordinates = _ref2.topCoordinates,
183
+ topCoordinates = _ref2$topCoordinates === undefined ? {} : _ref2$topCoordinates;
186
184
  var header = layoutIndexes.header,
187
185
  sections = layoutIndexes.sections,
188
186
  rest = (0, _objectWithoutProperties3.default)(layoutIndexes, ['header', 'sections']);
189
187
 
190
- var opts = { metadataCoordinates: metadataCoordinates, attributesSeries: attributesSeries, customAttributes: customAttributes };
188
+ var opts = { metadataCoordinates: metadataCoordinates, attributesSeries: attributesSeries, customAttributes: customAttributes, topCoordinates: topCoordinates };
191
189
  var headerData = getSubLayoutData(header, layout.header, opts);
192
190
  var sectionsData = R.pipe(R.transpose, function (_ref3) {
193
191
  var _ref4 = (0, _slicedToArray3.default)(_ref3, 2),
@@ -47,14 +47,15 @@ var getTableProps = exports.getTableProps = function getTableProps(_ref) {
47
47
  oneValueDimensions = data.oneValueDimensions,
48
48
  attributesSeries = data.attributesSeries,
49
49
  metadataCoordinates = data.metadataCoordinates,
50
- attributes = data.attributes;
50
+ attributes = data.attributes,
51
+ header = data.header;
51
52
 
52
53
 
53
54
  var seriesCombinations = (0, _getSeriesCombinations.getSeriesCombinations)(combinations, oneValueDimensions);
54
55
  var layout = (0, _getLayout.getLayout)(layoutIds, dimensions, seriesCombinations, isTimeInverted);
55
56
  var layoutIndexes = (0, _getSortedLayoutIndexes.getSortedLayoutIndexes)(layout, observations);
56
57
  var refinedLayoutIndexes = (0, _refineLayoutSize.refineLayoutSize)({ layout: layout, observations: observations, limit: limit })(layoutIndexes);
57
- var layoutData = (0, _getLayoutData.getLayoutData)(refinedLayoutIndexes, layout, { metadataCoordinates: metadataCoordinates, attributesSeries: attributesSeries, customAttributes: customAttributes });
58
+ var layoutData = (0, _getLayoutData.getLayoutData)(refinedLayoutIndexes, layout, { metadataCoordinates: metadataCoordinates, attributesSeries: attributesSeries, customAttributes: customAttributes, topCoordinates: header.coordinates });
58
59
 
59
60
  var cellsAttributesIds = (0, _getCellsAttributesIds.getCellsAttributesIds)(layoutIds, attributes);
60
61
  var indexedCombinations = (0, _getIndexedCombinationsByDisplay.getIndexedCombinationsByDisplay)(layout, seriesCombinations);
@@ -3,7 +3,7 @@
3
3
  Object.defineProperty(exports, "__esModule", {
4
4
  value: true
5
5
  });
6
- exports.trimedProps = undefined;
6
+ exports.getLayoutCoordinatesValidator = exports.trimedProps = undefined;
7
7
 
8
8
  var _ramda = require('ramda');
9
9
 
@@ -18,4 +18,25 @@ var trimedProps = exports.trimedProps = function trimedProps(properties, obj) {
18
18
  }
19
19
  return R.append(obj[prop], acc);
20
20
  }, [], properties);
21
+ };
22
+
23
+ var getLayoutCoordinatesValidator = exports.getLayoutCoordinatesValidator = function getLayoutCoordinatesValidator(layoutCoordinates) {
24
+ var topCoordinates = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {};
25
+ return function (coordinates) {
26
+ if (R.isEmpty(coordinates)) {
27
+ return false;
28
+ }
29
+ var keys = R.keys(coordinates);
30
+ var res = true;
31
+ var notInTop = {};
32
+ R.forEach(function (key) {
33
+ if (R.prop(key, layoutCoordinates) !== R.prop(key, coordinates)) {
34
+ res = false;
35
+ }
36
+ if (!R.has(key, topCoordinates)) {
37
+ notInTop[key] = key;
38
+ }
39
+ }, keys);
40
+ return res && !R.isEmpty(notInTop);
41
+ };
21
42
  };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@sis-cc/dotstatsuite-components",
3
3
  "description": "Set components based on React.",
4
- "version": "16.3.0",
4
+ "version": "16.5.0",
5
5
  "main": "lib/index.js",
6
6
  "author": "OECD",
7
7
  "license": "MIT",
@@ -19,7 +19,13 @@ const parseAttributesValues = (obs, attributes, indexedDimensions) => {
19
19
  if (R.isNil(attribute) || !R.prop('series', attribute)) {
20
20
  return acc;
21
21
  }
22
- let value = R.nth(valueIndex, attribute.values || []);
22
+ const _value = R.nth(valueIndex, attribute.values || []);
23
+ let value = R.isNil(_value)
24
+ ? _value
25
+ : R.over(R.lensProp('display'), (display=true) => display && !R.includes(_value.id, REJECTED_VALUE_IDS))(_value);
26
+ if ((!R.propOr(true, 'display', attribute) || !R.propOr(true, 'display', value)) && !R.prop('combined', attribute)) {
27
+ value = null;
28
+ }
23
29
  const relationship = R.propOr([], 'relationship', attribute);
24
30
  let coordinates = {};
25
31
  const serieKey = R.pipe(
@@ -33,7 +39,7 @@ const parseAttributesValues = (obs, attributes, indexedDimensions) => {
33
39
  R.ifElse(R.isEmpty, R.always(null), R.join(':'))
34
40
  )(indexedDimensions);
35
41
 
36
- return R.assoc(attribute.id, { ...R.pick(['id', 'name', 'relationship'], attribute), value, serieKey, coordinates, isObs: R.isEmpty(relationship) }, acc);
42
+ return R.assoc(attribute.id, { ...R.pick(['id', 'name', 'relationship', 'display'], attribute), value, serieKey, coordinates, isObs: R.isEmpty(relationship) }, acc);
37
43
  },
38
44
  {},
39
45
  attrValuesIndexes
@@ -0,0 +1,7 @@
1
+ import * as R from 'ramda';
2
+
3
+ export const getHeaderCoordinates = (oneValueDimensions) => R.reduce(
4
+ (acc, dim) => R.assoc(dim.id, R.path(['values', 0, 'id'], dim), acc),
5
+ {},
6
+ oneValueDimensions
7
+ );
@@ -30,6 +30,7 @@ export { getHeaderTitle } from './getHeaderTitle';
30
30
  export { getHeaderSubtitle } from './getHeaderSubtitle';
31
31
  export { getSeriesCombinations } from './getSeriesCombinations';
32
32
  export { getHeaderCombinations } from './getHeaderCombinations';
33
+ export { getHeaderCoordinates } from './getHeaderCoordinates';
33
34
  export { getLayout } from './table/getLayout';
34
35
  export { getSortedLayoutIndexes } from './table/getSortedLayoutIndexes';
35
36
  export { refineLayoutSize } from './table/refineLayoutSize';
@@ -16,6 +16,7 @@ import { getDataflowAttributes } from './getDataflowAttributes';
16
16
  import { getHeaderTitle } from './getHeaderTitle';
17
17
  import { getHeaderSubtitle } from './getHeaderSubtitle';
18
18
  import { getHeaderCombinations } from './getHeaderCombinations';
19
+ import { getHeaderCoordinates } from './getHeaderCoordinates';
19
20
 
20
21
  export const prepareData = (sdmxJson, { customAttributes, locale, hierarchies, dataflow, display, defaultCombinations }) => {
21
22
  const dimensions = R.pathOr([], ['data', 'structure', 'dimensions', 'observation'], sdmxJson);
@@ -38,6 +39,7 @@ export const prepareData = (sdmxJson, { customAttributes, locale, hierarchies, d
38
39
  const attributesSeries = getAttributesSeries(enhancedObservations);
39
40
  const manyValuesDimensions = getManyValuesDimensions(dimensions, attributesSeries, customAttributes, seriesCombinations);
40
41
  const oneValueDimensions = getOneValueDimensions(dimensions, parsedAttributes);
42
+ const headerCoordinates = getHeaderCoordinates(oneValueDimensions);
41
43
  const hierarchisedDimensions = R.map(dim => {
42
44
  if (R.isEmpty(R.propOr({}, dim.id, hierarchies))) {
43
45
  return hierarchiseDimensionWithNativeHierarchy(dim);
@@ -62,7 +64,8 @@ export const prepareData = (sdmxJson, { customAttributes, locale, hierarchies, d
62
64
  header: {
63
65
  title: headerTitle,
64
66
  subtitle: headerSubtitle,
65
- combinations: headerCombinations
67
+ combinations: headerCombinations,
68
+ coordinates: headerCoordinates
66
69
  }
67
70
  });
68
71
  };
@@ -9,7 +9,7 @@ export const refineAttributes = (parsedAttributes, seriesCombinations) => {
9
9
  );
10
10
  return R.map(attr => {
11
11
  if (R.has(attr.id, indexedRelationships)) {
12
- return { ...attr, series: true, relationship: R.prop(attr.id, indexedRelationships) };
12
+ return { ...attr, series: true, relationship: R.prop(attr.id, indexedRelationships), combined: true };
13
13
  }
14
14
  return attr;
15
15
  }, parsedAttributes);
@@ -10,7 +10,7 @@ export const getFlagsAndNotes = (attributesValues, customAttributes) => {
10
10
  if (!R.has(id, attributesValues)) {
11
11
  return acc;
12
12
  }
13
- const attr = R.prop(id, attributesValues);
13
+ const attr = R.pick(['id', 'name', 'value', 'display'], R.prop(id, attributesValues));
14
14
  if (R.isNil(attr.value) || !R.pathOr(true, ['value', 'display'], attr) || !R.propOr(true, 'display', attr)
15
15
  || R.includes(R.path(['value', 'id'], attr), REJECTED_VALUE_IDS)) {
16
16
  return acc;
@@ -1,9 +1,8 @@
1
1
  import * as R from 'ramda';
2
2
  import { getFlagsAndNotes } from './getFlagsAndNotes';
3
- import { hasCellMetadata } from '../hasCellMetadata';
4
3
  import { getCombinationDimensionsData } from './getCombinationDimensionsData';
5
4
  import { parseValueHierarchy } from './parseValueHierarchy';
6
- import { REJECTED_VALUE_IDS } from '../constants';
5
+ import { getLayoutCoordinatesValidator } from '../utils';
7
6
 
8
7
  const getSubLayoutData = (series, _definition, { metadataCoordinates, attributesSeries, customAttributes, topCoordinates={} }) => {
9
8
  const getHasAdvancedAttributes = (attrValues) => R.pipe(
@@ -94,17 +93,19 @@ const getSubLayoutData = (series, _definition, { metadataCoordinates, attributes
94
93
  i++;
95
94
  }
96
95
 
96
+ const coordinatesValidator = getLayoutCoordinatesValidator(coordinates, topCoordinates);
97
97
  const attributesValues = R.reduce(
98
- (acc, key) => {
99
- const splitKey = R.split(':', key);
100
- const isValid = R.all(entry => {
101
- const [d, v] = R.split('=', entry);
102
- return R.propEq(d, v, coordinates);
103
- }, splitKey);
104
- return isValid ? { ...acc, ...(R.length(splitKey) === 1 ? R.pick(combinationConceptIds, R.prop(key, attributesSeries)) : R.prop(key, attributesSeries)) } : acc;
98
+ (acc, serie) => {
99
+ const coordinates = R.path([0, 'coordinates'], R.values(serie));
100
+ const isValid = coordinatesValidator(coordinates);
101
+ if (!isValid) {
102
+ return acc;
103
+ }
104
+ const isSingleBounded = R.length(R.keys(coordinates)) === 1;
105
+ return ({ ...acc, ...(isSingleBounded ? R.pick(combinationConceptIds, serie) : serie) });
105
106
  },
106
107
  {},
107
- R.keys(attributesSeries)
108
+ R.values(attributesSeries)
108
109
  );
109
110
 
110
111
  data = R.addIndex(R.reduce)(
@@ -141,13 +142,13 @@ const getSubLayoutData = (series, _definition, { metadataCoordinates, attributes
141
142
  data
142
143
  );
143
144
 
144
- const layoutAttrValues = R.pipe(
145
- R.omit(combinationConceptIds),
146
- R.reject(R.prop('isObs'))
147
- )(attributesValues);
145
+ const layoutAttrValues = R.reject(
146
+ R.prop('isObs'),
147
+ R.omit(combinationConceptIds, attributesValues)
148
+ );
148
149
 
149
150
  const flags = getFlagsAndNotes(layoutAttrValues, customAttributes);
150
- const hasMetadata = hasCellMetadata(metadataCoordinates, coordinates);
151
+ const hasMetadata = !R.isNil(R.find(coordinatesValidator, metadataCoordinates));
151
152
 
152
153
  if (!hasAdvancedAttributes) {
153
154
  hasAdvancedAttributes = getHasAdvancedAttributes(layoutAttrValues);
@@ -168,9 +169,9 @@ const getSubLayoutData = (series, _definition, { metadataCoordinates, attributes
168
169
  return res;
169
170
  };
170
171
 
171
- export const getLayoutData = (layoutIndexes, layout, { metadataCoordinates, attributesSeries, customAttributes }) => {
172
+ export const getLayoutData = (layoutIndexes, layout, { metadataCoordinates, attributesSeries, customAttributes, topCoordinates={} }) => {
172
173
  const { header, sections, ...rest } = layoutIndexes;
173
- const opts = { metadataCoordinates, attributesSeries, customAttributes };
174
+ const opts = { metadataCoordinates, attributesSeries, customAttributes, topCoordinates };
174
175
  const headerData = getSubLayoutData(header, layout.header, opts);
175
176
  const sectionsData = R.pipe(
176
177
  R.transpose,
@@ -17,14 +17,15 @@ export const getTableProps = ({ data, layoutIds, customAttributes, limit, isTime
17
17
  oneValueDimensions,
18
18
  attributesSeries,
19
19
  metadataCoordinates,
20
- attributes
20
+ attributes,
21
+ header
21
22
  } = data;
22
23
 
23
24
  const seriesCombinations = getSeriesCombinations(combinations, oneValueDimensions);
24
25
  const layout = getLayout(layoutIds, dimensions, seriesCombinations, isTimeInverted);
25
26
  const layoutIndexes = getSortedLayoutIndexes(layout, observations);
26
27
  const refinedLayoutIndexes = refineLayoutSize({ layout, observations, limit })(layoutIndexes);
27
- const layoutData = getLayoutData(refinedLayoutIndexes, layout, { metadataCoordinates, attributesSeries, customAttributes });
28
+ const layoutData = getLayoutData(refinedLayoutIndexes, layout, { metadataCoordinates, attributesSeries, customAttributes, topCoordinates: header.coordinates });
28
29
 
29
30
  const cellsAttributesIds = getCellsAttributesIds(layoutIds, attributes);
30
31
  const indexedCombinations = getIndexedCombinationsByDisplay(layout, seriesCombinations);
@@ -10,3 +10,21 @@ export const trimedProps = (properties, obj) => R.reduce(
10
10
  [],
11
11
  properties,
12
12
  );
13
+
14
+ export const getLayoutCoordinatesValidator = (layoutCoordinates, topCoordinates={}) => (coordinates) => {
15
+ if (R.isEmpty(coordinates)) {
16
+ return false;
17
+ }
18
+ const keys = R.keys(coordinates);
19
+ let res = true;
20
+ let notInTop = {};
21
+ R.forEach(key => {
22
+ if (R.prop(key, layoutCoordinates) !== R.prop(key, coordinates)) {
23
+ res = false;
24
+ }
25
+ if (!R.has(key, topCoordinates)) {
26
+ notInTop[key] = key;
27
+ }
28
+ }, keys);
29
+ return res && !R.isEmpty(notInTop);
30
+ };
@@ -74,7 +74,7 @@ describe('enhanceObservations tests', () => {
74
74
  },
75
75
  {
76
76
  id: 'a4',
77
- values: [{ id: 'v0' }, { id: 'v1', display: false }],
77
+ values: [{ id: 'v0' }, { id: 'v1' }],
78
78
  relationship: ['d4'],
79
79
  series: true
80
80
  },
@@ -159,9 +159,9 @@ describe('enhanceObservations tests', () => {
159
159
  value: 22,
160
160
  formattedValue: '22',
161
161
  attributes: {
162
- a0: { id: 'a0', relationship: ['d0', 'd1'], value: { id: 'v0' }, serieKey: 'd0=v0:d1=v0', coordinates: { d0: 'v0', d1: 'v0' }, isObs: false },
163
- a3: { id: 'a3', relationship: ['d2', 'd3'], value: { id: 'v0' }, serieKey: 'd2=v0:d3=v0', coordinates: { d2: 'v0', d3: 'v0' }, isObs: false },
164
- a4: { id: 'a4', relationship: ['d4'], value: { id: 'v0' }, serieKey: 'd4=v0', coordinates: { d4: 'v0' }, isObs: false },
162
+ a0: { id: 'a0', relationship: ['d0', 'd1'], value: { id: 'v0', display: true }, serieKey: 'd0=v0:d1=v0', coordinates: { d0: 'v0', d1: 'v0' }, isObs: false },
163
+ a3: { id: 'a3', relationship: ['d2', 'd3'], value: { id: 'v0', display: true }, serieKey: 'd2=v0:d3=v0', coordinates: { d2: 'v0', d3: 'v0' }, isObs: false },
164
+ a4: { id: 'a4', relationship: ['d4'], value: { id: 'v0', display: true }, serieKey: 'd4=v0', coordinates: { d4: 'v0' }, isObs: false },
165
165
  },
166
166
  indexedDimValIds: { d0: 'v0', d1: 'v0', d2: 'v0', d3: 'v0', d4: 'v0' }
167
167
  },
@@ -171,9 +171,9 @@ describe('enhanceObservations tests', () => {
171
171
  value: 17,
172
172
  formattedValue: '17',
173
173
  attributes: {
174
- a0: { id: 'a0', relationship: ['d0', 'd1'], value: { id: 'v1' }, serieKey: 'd0=v0:d1=v0', coordinates: { d0: 'v0', d1: 'v0' }, isObs: false },
175
- a3: { id: 'a3', relationship: ['d2', 'd3'], value: { id: 'v1' }, serieKey: 'd2=v0:d3=v1', coordinates: { d2: 'v0', d3: 'v1' }, isObs: false },
176
- a4: { id: 'a4', relationship: ['d4'], value: { id: 'v0' }, serieKey: 'd4=v0', coordinates: { d4: 'v0' }, isObs: false },
174
+ a0: { id: 'a0', relationship: ['d0', 'd1'], value: { id: 'v1', display: true }, serieKey: 'd0=v0:d1=v0', coordinates: { d0: 'v0', d1: 'v0' }, isObs: false },
175
+ a3: { id: 'a3', relationship: ['d2', 'd3'], value: { id: 'v1', display: true }, serieKey: 'd2=v0:d3=v1', coordinates: { d2: 'v0', d3: 'v1' }, isObs: false },
176
+ a4: { id: 'a4', relationship: ['d4'], value: { id: 'v0', display: true }, serieKey: 'd4=v0', coordinates: { d4: 'v0' }, isObs: false },
177
177
  },
178
178
  indexedDimValIds: { d0: 'v0', d1: 'v0', d2: 'v0', d3: 'v1', d4: 'v0' }
179
179
  },
@@ -183,9 +183,9 @@ describe('enhanceObservations tests', () => {
183
183
  value: 55,
184
184
  formattedValue: '55',
185
185
  attributes: {
186
- a0: { id: 'a0', relationship: ['d0', 'd1'], value: { id: 'v2' }, serieKey: 'd0=v1:d1=v0', coordinates: { d0: 'v1', d1: 'v0' }, isObs: false },
186
+ a0: { id: 'a0', relationship: ['d0', 'd1'], value: { id: 'v2', display: true }, serieKey: 'd0=v1:d1=v0', coordinates: { d0: 'v1', d1: 'v0' }, isObs: false },
187
187
  a3: { id: 'a3', relationship: ['d2', 'd3'], value: undefined, serieKey: 'd2=v0:d3=v0', coordinates: { d2: 'v0', d3: 'v0' }, isObs: false },
188
- a4: { id: 'a4', relationship: ['d4'], value: { id: 'v0' }, serieKey: 'd4=v0', coordinates: { d4: 'v0' }, isObs: false },
188
+ a4: { id: 'a4', relationship: ['d4'], value: { id: 'v0', display: true }, serieKey: 'd4=v0', coordinates: { d4: 'v0' }, isObs: false },
189
189
  },
190
190
  indexedDimValIds: { d0: 'v1', d1: 'v0', d2: 'v0', d3: 'v0', d4: 'v0' }
191
191
  },
@@ -195,7 +195,7 @@ describe('enhanceObservations tests', () => {
195
195
  value: 35,
196
196
  formattedValue: '35',
197
197
  attributes: {
198
- a0: { id: 'a0', relationship: ['d0', 'd1'], value: { id: 'v2' }, serieKey: 'd0=v2:d1=v0', coordinates: { d0: 'v2', d1: 'v0' }, isObs: false },
198
+ a0: { id: 'a0', relationship: ['d0', 'd1'], value: { id: 'v2', display: true }, serieKey: 'd0=v2:d1=v0', coordinates: { d0: 'v2', d1: 'v0' }, isObs: false },
199
199
  a3: { id: 'a3', relationship: ['d2', 'd3'], value: undefined, serieKey: 'd2=v0:d3=v0', coordinates: { d2: 'v0', d3: 'v0' }, isObs: false },
200
200
  a4: { id: 'a4', relationship: ['d4'], value: undefined, serieKey: 'd4=v0', coordinates: { d4: 'v0' }, isObs: false },
201
201
  },
@@ -207,7 +207,7 @@ describe('enhanceObservations tests', () => {
207
207
  value: 35,
208
208
  formattedValue: '35',
209
209
  attributes: {
210
- a0: { id: 'a0', relationship: ['d0', 'd1'], value: { id: 'v2' }, serieKey: 'd0=v3:d1=v0', coordinates: { d0: 'v3', d1: 'v0' }, isObs: false },
210
+ a0: { id: 'a0', relationship: ['d0', 'd1'], value: { id: 'v2', display: true }, serieKey: 'd0=v3:d1=v0', coordinates: { d0: 'v3', d1: 'v0' }, isObs: false },
211
211
  a3: { id: 'a3', relationship: ['d2', 'd3'], value: undefined, serieKey: 'd2=v0:d3=v0', coordinates: { d2: 'v0', d3: 'v0' }, isObs: false },
212
212
  a4: { id: 'a4', relationship: ['d4'], value: undefined, serieKey: 'd4=v0', coordinates: { d4: 'v0' }, isObs: false },
213
213
  },
@@ -215,5 +215,43 @@ describe('enhanceObservations tests', () => {
215
215
  }
216
216
  });
217
217
  });
218
+ it('not displayed attributes and combinations', () => {
219
+ const attributes = [
220
+ { id: 'A1', display: false, series: true, values: [{ id: 'A1v' }], relationship: [] },
221
+ { id: 'A2', series: true, values: [{ id: 'A2v', display: false }], relationship: [] },
222
+ { id: 'A3', series: true, values: [{ id: '_T', display: true }], relationship: [] },
223
+ { id: 'A4', display: false, series: true, values: [{ id: 'A4v' }], relationship: [], combined: true },
224
+ { id: 'A5', series: true, values: [{ id: 'A5v', display: false }], relationship: [], combined: true },
225
+ { id: 'A6', series: true, values: [{ id: '_T', display: true }], relationship: [], combined: true },
226
+ ];
227
+
228
+ const dimensions = [];
229
+
230
+ const observations = {
231
+ obs: {
232
+ attrValuesIndexes: [0, 0, 0, 0, 0, 0],
233
+ dimValuesIndexes: [],
234
+ value: 22,
235
+ }
236
+ };
237
+
238
+ expect(enhanceObservations(dimensions, observations, attributes, {})).to.deep.equal({
239
+ obs: {
240
+ attrValuesIndexes: [0, 0, 0, 0, 0, 0],
241
+ dimValuesIndexes: [],
242
+ value: 22,
243
+ formattedValue: '22',
244
+ attributes: {
245
+ A1: { id: 'A1', display: false, value: null, relationship: [], serieKey: null, coordinates: {}, isObs: true },
246
+ A2: { id: 'A2', value: null, relationship: [], serieKey: null, coordinates: {}, isObs: true },
247
+ A3: { id: 'A3', value: null, relationship: [], serieKey: null, coordinates: {}, isObs: true },
248
+ A4: { id: 'A4', display: false, value: { id: 'A4v', display: true }, relationship: [], serieKey: null, coordinates: {}, isObs: true },
249
+ A5: { id: 'A5', value: { id: 'A5v', display: false }, relationship: [], serieKey: null, coordinates: {}, isObs: true },
250
+ A6: { id: 'A6', value: { id: '_T', display: false }, relationship: [], serieKey: null, coordinates: {}, isObs: true },
251
+ },
252
+ indexedDimValIds: {}
253
+ }
254
+ })
255
+ });
218
256
  });
219
257
 
@@ -72,7 +72,7 @@ describe('getCells tests', () => {
72
72
  flags: [
73
73
  { code: 'A', id: 'FL1', value: { id: 'A' } }, // regular flag
74
74
  { id: 'FT1', value: { id: 'V' } }, // regular foot note
75
- { id: 'A3', value: { id: 'A3V' }, serieKey: 'D3=v0' }, // rejected layout combination value displayed as a footnote
75
+ { id: 'A3', value: { id: 'A3V' } }, // rejected layout combination value displayed as a footnote
76
76
  { id: 'CELLS_COMB', values: [{ id: 'D1V' }, { id: 'A1V' }] } // cell level combination with fixed dim value
77
77
  ]
78
78
  }
@@ -182,4 +182,103 @@ describe('getLayoutData tests', () => {
182
182
  ]
183
183
  });
184
184
  });
185
+ it('flags, advanced attributes and metadata availability', () => {
186
+ const customAttributes = { flags: ['FL'], notes: ['FT'] };
187
+ const topCoordinates = { FREQ: 'A' };
188
+ const layout = {
189
+ header: [
190
+ { id: 'TIME_PERIOD', values: [{ id: '2020' }, { id: '2021' }] }
191
+ ],
192
+ sections: [
193
+ { id: 'TRANSACT', values: [{ id: 'TRANSACT1' }, { id: 'TRANSACT2' }] }
194
+ ],
195
+ rows: [
196
+ { id: 'REF_AREA', values: [{ id: 'US' }, { id: 'AUS' }, { id: 'FRA' }] },
197
+ { id: 'COMB_UNIT', concepts: ['TRANSACT', "MEASURE", 'UNIT_MULT'], dimensions: [{ id: 'MEASURE', values: [{ id: 'USD' }, { id: 'AUSD' }, { id: 'EUR' }] }] }
198
+ ]
199
+ };
200
+
201
+ const metadataCoordinates = [
202
+ {},
203
+ { TIME_PERIOD: '2021', FREQ: 'A' },
204
+ { TRANSACT: 'TRANSACT1' },
205
+ { TRANSACT: 'TRANSACT2', REF_AREA: 'AUS', FREQ: 'A' }
206
+ ];
207
+
208
+ const attributesSeries = {
209
+ 'TIME_PERIOD=2020:FREQ=A': {
210
+ FL: { id: 'FL', serieKey: 'TIME_PERIOD=2020:FREQ=A', coordinates: { TIME_PERIOD: '2020', FREQ: 'A' }, value: { id: 'FL_V' } },
211
+ FT: { id: 'FT', serieKey: 'TIME_PERIOD=2020:FREQ=A', coordinates: { TIME_PERIOD: '2020', FREQ: 'A' }, value: { id: 'FT_V0' } }
212
+ },
213
+ 'TRANSACT=TRANSACT1:MEASURE=USD': {
214
+ UNIT_MULT: { id: 'UNIT_MULT', serieKey: 'TRANSACT=TRANSACT1:MEASURE=USD', coordinates: { TRANSACT: 'TRANSACT1', MEASURE: 'USD' }, value: { id: 'BILL' } }
215
+ },
216
+ 'TRANSACT=TRANSACT1:MEASURE=AUSD': {
217
+ UNIT_MULT: { id: 'UNIT_MULT', serieKey: 'TRANSACT=TRANSACT1:MEASURE=AUSD', coordinates: { TRANSACT: 'TRANSACT1', MEASURE: 'AUSD' }, value: { id: '0' } }
218
+ },
219
+ 'TRANSACT=TRANSACT1:MEASURE=EUR': {
220
+ UNIT_MULT: { id: 'UNIT_MULT', serieKey: 'TRANSACT=TRANSACT1:MEASURE=EUR', coordinates: { TRANSACT: 'TRANSACT1', MEASURE: 'EUR' }, value: { id: 'MILL' } }
221
+ },
222
+ 'TRANSACT=TRANSACT2:MEASURE=USD': {
223
+ UNIT_MULT: { id: 'UNIT_MULT', serieKey: 'TRANSACT=TRANSACT2:MEASURE=USD', coordinates: { TRANSACT: 'TRANSACT2', MEASURE: 'USD' }, value: { id: 'BILL' } }
224
+ },
225
+ 'TRANSACT=TRANSACT2:MEASURE=AUSD': {
226
+ UNIT_MULT: { id: 'UNIT_MULT', serieKey: 'TRANSACT=TRANSACT2:MEASURE=AUSD', coordinates: { TRANSACT: 'TRANSACT2', MEASURE: 'AUSD' }, value: { id: '0' } }
227
+ },
228
+ 'TRANSACT=TRANSACT2:MEASURE=EUR': {
229
+ UNIT_MULT: { id: 'UNIT_MULT', serieKey: 'TRANSACT=TRANSACT2:MEASURE=EUR', coordinates: { TRANSACT: 'TRANSACT2', MEASURE: 'EUR' }, value: { id: 'MILL' } }
230
+ },
231
+ 'TRANSACT=TRANSACT1:FREQ=A': {
232
+ FT: { id: 'FT', serieKey: 'TRANSACT=TRANSACT1:FREQ=A', coordinates: { TRANSACT: 'TRANSACT1', FREQ: 'A' }, value: { id: 'FT_V1' } },
233
+ ADV: { id: 'ADV', serieKey: 'TRANSACT=TRANSACT1:FREQ=A', coordinates: { TRANSACT: 'TRANSACT1', FREQ: 'A' }, value: { id: 'ADV_V0' } }
234
+ },
235
+ 'TRANSACT=TRANSACT2:REF_AREA=FRA': {
236
+ FT: { id: 'FT', serieKey: 'TRANSACT=TRANSACT2:REF_AREA=FRA', coordinates: { TRANSACT: 'TRANSACT2', REF_AREA: 'FRA' }, value: { id: 'FT_V2' } }
237
+ },
238
+ 'TRANSACT=TRANSACT2:MEASURE=USD:FREQ=A': {
239
+ ADV: { id: 'ADV', serieKey: 'TRANSACT=TRANSACT2:MEASURE=USD:FREQ=A', coordinates: { TRANSACT: 'TRANSACT2', MEASURE: 'USD', FREQ: 'A' }, value: { id: 'ADV_V1' } }
240
+ },
241
+ };
242
+
243
+ const layoutIndexes = {
244
+ header: [[0], [1]],
245
+ sections: [
246
+ [
247
+ [0],
248
+ [[0, [0]], [1, [1]], [2, [2]]],
249
+ ],
250
+ [
251
+ [1],
252
+ [[0, [0]], [1, [1]], [2, [2]]],
253
+ ]
254
+ ]
255
+ };
256
+
257
+ const layoutData = {
258
+ headerData: [
259
+ { data: [{ dimension: { id: 'TIME_PERIOD' }, value: { id: '2020' } }], flags: [{ id: 'FL', code: 'FL_V', value: { id: 'FL_V' } }, { id: 'FT', value: { id: 'FT_V0' } }], key: 'TIME_PERIOD=2020', sideProps: null, coordinates: { TIME_PERIOD: '2020', FREQ: 'A' } },
260
+ { data: [{ dimension: { id: 'TIME_PERIOD' }, value: { id: '2021' } }], flags: [], key: 'TIME_PERIOD=2021', sideProps: { hasMetadata: true, hasAdvancedAttributes: false, coordinates: { TIME_PERIOD: '2021', FREQ: 'A' } }, coordinates: { TIME_PERIOD: '2021', FREQ: 'A' } },
261
+ ],
262
+ sectionsData: [
263
+ [
264
+ { data: [{ dimension: { id: 'TRANSACT' }, value: { id: 'TRANSACT1' } }], flags: [{ id: 'FT', value: { id: 'FT_V1' } }], key: 'TRANSACT=TRANSACT1', sideProps: { hasAdvancedAttributes: true, hasMetadata: true, coordinates: { TRANSACT: 'TRANSACT1', FREQ: 'A' } }, coordinates: { TRANSACT: 'TRANSACT1', FREQ: 'A' } },
265
+ [
266
+ { data: [{ dimension: { id: 'REF_AREA' }, value: { id: 'US' } }, { dimension: { id: 'COMB_UNIT' }, values: [{ id: 'USD', display: true }, { id: 'BILL' }] }], flags: [], key: 'REF_AREA=US:MEASURE=USD', sideProps: null, coordinates: { TRANSACT: 'TRANSACT1', REF_AREA: 'US', MEASURE: 'USD', FREQ: 'A' } },
267
+ { data: [{ dimension: { id: 'REF_AREA' }, value: { id: 'AUS' } }, { dimension: { id: 'COMB_UNIT' }, values: [{ id: 'AUSD', display: true }, { id: '0' }] }], flags: [], key: 'REF_AREA=AUS:MEASURE=AUSD', sideProps: null, coordinates: { TRANSACT: 'TRANSACT1', REF_AREA: 'AUS', MEASURE: 'AUSD', FREQ: 'A' } },
268
+ { data: [{ dimension: { id: 'REF_AREA' }, value: { id: 'FRA' } }, { dimension: { id: 'COMB_UNIT' }, values: [{ id: 'EUR', display: true }, { id: 'MILL' }] }], flags: [], key: 'REF_AREA=FRA:MEASURE=EUR', sideProps: null, coordinates: { TRANSACT: 'TRANSACT1', REF_AREA: 'FRA', MEASURE: 'EUR', FREQ: 'A' } },
269
+ ]
270
+ ],
271
+ [
272
+ { data: [{ dimension: { id: 'TRANSACT' }, value: { id: 'TRANSACT2' } }], flags: [], key: 'TRANSACT=TRANSACT2', sideProps: null, coordinates: { TRANSACT: 'TRANSACT2', FREQ: 'A' } },
273
+ [
274
+ { data: [{ dimension: { id: 'REF_AREA' }, value: { id: 'US' } }, { dimension: { id: 'COMB_UNIT' }, values: [{ id: 'USD', display: true }, { id: 'BILL' }] }], flags: [], key: 'REF_AREA=US:MEASURE=USD', sideProps: { hasAdvancedAttributes: true, hasMetadata: false, coordinates: { TRANSACT: 'TRANSACT2', REF_AREA: 'US', MEASURE: 'USD', FREQ: 'A' } }, coordinates: { TRANSACT: 'TRANSACT2', REF_AREA: 'US', MEASURE: 'USD', FREQ: 'A' } },
275
+ { data: [{ dimension: { id: 'REF_AREA' }, value: { id: 'AUS' } }, { dimension: { id: 'COMB_UNIT' }, values: [{ id: 'AUSD', display: true }, { id: '0' }] }], flags: [], key: 'REF_AREA=AUS:MEASURE=AUSD', sideProps: { hasAdvancedAttributes: false, hasMetadata: true, coordinates: { TRANSACT: 'TRANSACT2', REF_AREA: 'AUS', MEASURE: 'AUSD', FREQ: 'A' } }, coordinates: { TRANSACT: 'TRANSACT2', REF_AREA: 'AUS', MEASURE: 'AUSD', FREQ: 'A' } },
276
+ { data: [{ dimension: { id: 'REF_AREA' }, value: { id: 'FRA' } }, { dimension: { id: 'COMB_UNIT' }, values: [{ id: 'EUR', display: true }, { id: 'MILL' }] }], flags: [{ id: 'FT', value: { id: 'FT_V2' } }], key: 'REF_AREA=FRA:MEASURE=EUR', sideProps: null, coordinates: { TRANSACT: 'TRANSACT2', REF_AREA: 'FRA', MEASURE: 'EUR', FREQ: 'A' } },
277
+ ]
278
+ ],
279
+ ]
280
+ };
281
+
282
+ expect(getLayoutData(layoutIndexes, layout, { attributesSeries, metadataCoordinates, customAttributes, topCoordinates })).to.deep.equal(layoutData);
283
+ });
185
284
  });
@@ -0,0 +1,29 @@
1
+ import { expect } from 'chai';
2
+ import { refineAttributes } from '../src/rules2/src';
3
+
4
+ describe('refineAttributes tests', () => {
5
+ it('basic test', () => {
6
+ const attributes = [
7
+ { id: 'A1', relationship: [] },
8
+ { id: 'A2', relationship: ['D1', 'D2'] },
9
+ { id: 'A3', series: true, relationship: [] },
10
+ { id: 'A4', series: true, relationship: ['D3', 'D4'] },
11
+ { id: 'A5', header: true, relationship: [] },
12
+ { id: 'A6', series: true, relationship: ['D3', 'D4'] },
13
+ ];
14
+
15
+ const combinations = [
16
+ { id: 'COMB1', concepts: ['A1', 'A3', 'A4'], relationship: ['D5', 'D6'] },
17
+ { id: 'COMB2', concepts: ['A2'], relationship: [] },
18
+ ];
19
+
20
+ expect(refineAttributes(attributes, combinations)).to.deep.equal([
21
+ { id: 'A1', series: true, relationship: ['D5', 'D6'], combined: true },
22
+ { id: 'A2', series: true, relationship: [], combined: true },
23
+ { id: 'A3', series: true, relationship: ['D5', 'D6'], combined: true },
24
+ { id: 'A4', series: true, relationship: ['D5', 'D6'], combined: true },
25
+ { id: 'A5', header: true, relationship: [] },
26
+ { id: 'A6', series: true, relationship: ['D3', 'D4'] },
27
+ ]);
28
+ });
29
+ });