data-restructor 3.3.4 → 3.4.1

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.
Files changed (49) hide show
  1. package/.auto-changelog +9 -0
  2. package/.auto-changelog-template.hbs +36 -0
  3. package/.github/workflows/codeql-analysis.yml +4 -4
  4. package/.github/workflows/continuous-integration.yaml +84 -0
  5. package/CHANGELOG.md +199 -94
  6. package/CONTRIBUTING.md +51 -43
  7. package/Commands.md +16 -15
  8. package/README.md +193 -137
  9. package/SECURITY.md +2 -2
  10. package/coverage/coverage-summary.json +3 -3
  11. package/coverage/datarestructor.js.html +133 -133
  12. package/coverage/describedfield.js.html +45 -45
  13. package/coverage/index.html +1 -1
  14. package/coverage/templateResolver.js.html +26 -26
  15. package/devdist/datarestructor-ie.js +1487 -1678
  16. package/devdist/datarestructor.js +1438 -1614
  17. package/devdist/describedfield-ie.js +260 -282
  18. package/devdist/describedfield.js +257 -279
  19. package/devdist/templateResolver-ie.js +221 -257
  20. package/devdist/templateResolver.js +192 -228
  21. package/dist/datarestructor-ie.js +1 -1
  22. package/dist/datarestructor-ie.js.map +1 -1
  23. package/dist/datarestructor.js +1 -1
  24. package/dist/datarestructor.js.map +1 -1
  25. package/dist/describedfield-ie.js +1 -1
  26. package/dist/describedfield-ie.js.map +1 -1
  27. package/dist/describedfield.js +1 -1
  28. package/dist/describedfield.js.map +1 -1
  29. package/dist/templateResolver-ie.js +1 -1
  30. package/dist/templateResolver-ie.js.map +1 -1
  31. package/dist/templateResolver.js +1 -1
  32. package/dist/templateResolver.js.map +1 -1
  33. package/docs/datarestructor.js.html +1 -1
  34. package/docs/describedfield.js.html +1 -1
  35. package/docs/index.html +54 -44
  36. package/docs/module-datarestructor.DescribedEntryCreator.html +94 -94
  37. package/docs/module-datarestructor.PropertyStructureDescriptionBuilder.html +1 -1
  38. package/docs/module-datarestructor.Restructor.html +1 -1
  39. package/docs/module-datarestructor.Transform.html +605 -605
  40. package/docs/module-datarestructor.html +959 -995
  41. package/docs/module-described_field.DescribedDataFieldBuilder.html +1 -1
  42. package/docs/module-described_field.DescribedDataFieldGroup.html +1 -1
  43. package/docs/module-described_field.html +1 -37
  44. package/docs/module-template_resolver.Resolver.html +167 -167
  45. package/docs/module-template_resolver.html +1 -37
  46. package/docs/templateResolver.js.html +1 -1
  47. package/package.json +20 -14
  48. package/renovate.json +14 -0
  49. package/.github/workflows/action.yaml +0 -44
@@ -6,7 +6,7 @@
6
6
  // anything defined in a previous bundle is accessed via the
7
7
  // orig method which is the require for previous bundles
8
8
 
9
- (function(modules, entry, mainEntry, parcelRequireName, globalName) {
9
+ (function (modules, entry, mainEntry, parcelRequireName, globalName) {
10
10
  /* eslint-disable no-undef */
11
11
  var globalObject =
12
12
  typeof globalThis !== 'undefined'
@@ -80,11 +80,13 @@
80
80
  return cache[name].exports;
81
81
 
82
82
  function localRequire(x) {
83
- return newRequire(localRequire.resolve(x));
83
+ var res = localRequire.resolve(x);
84
+ return res === false ? {} : newRequire(res);
84
85
  }
85
86
 
86
87
  function resolve(x) {
87
- return modules[name][1][x] || x;
88
+ var id = modules[name][1][x];
89
+ return id != null ? id : x;
88
90
  }
89
91
  }
90
92
 
@@ -99,9 +101,9 @@
99
101
  newRequire.modules = modules;
100
102
  newRequire.cache = cache;
101
103
  newRequire.parent = previousRequire;
102
- newRequire.register = function(id, exports) {
104
+ newRequire.register = function (id, exports) {
103
105
  modules[id] = [
104
- function(require, module) {
106
+ function (require, module) {
105
107
  module.exports = exports;
106
108
  },
107
109
  {},
@@ -109,7 +111,7 @@
109
111
  };
110
112
 
111
113
  Object.defineProperty(newRequire, 'root', {
112
- get: function() {
114
+ get: function () {
113
115
  return globalObject[parcelRequireName];
114
116
  },
115
117
  });
@@ -131,7 +133,7 @@
131
133
 
132
134
  // RequireJS
133
135
  } else if (typeof define === 'function' && define.amd) {
134
- define(function() {
136
+ define(function () {
135
137
  return mainExports;
136
138
  });
137
139
 
@@ -140,1686 +142,1508 @@
140
142
  this[globalName] = mainExports;
141
143
  }
142
144
  }
143
- })({"7h0AO":[function(require,module,exports) {
145
+ })({"jZ3Ya":[function(require,module,exports) {
144
146
  /**
145
- * @file datarestructor transforms parsed JSON objects into a uniform data structure
146
- * @version {@link https://github.com/JohT/data-restructor-js/releases/latest latest version}
147
- * @author JohT
148
- */
149
- "use strict";
150
- var module = datarestructorInternalCreateIfNotExists(module);
151
- // Fallback for vanilla js without modules
147
+ * @file datarestructor transforms parsed JSON objects into a uniform data structure
148
+ * @version {@link https://github.com/JohT/data-restructor-js/releases/latest latest version}
149
+ * @author JohT
150
+ */ "use strict";
151
+ var module = datarestructorInternalCreateIfNotExists(module); // Fallback for vanilla js without modules
152
152
  function datarestructorInternalCreateIfNotExists(objectToCheck) {
153
- return objectToCheck || ({});
153
+ return objectToCheck || {};
154
154
  }
155
155
  /**
156
- * datarestructor namespace and module declaration.
157
- * It contains all functions to convert an object (e.g. parsed JSON) into uniform enumerated list of described field entries.
158
- *
159
- * <b>Transformation steps:</b>
160
- * - JSON
161
- * - flatten
162
- * - mark and identify
163
- * - add array fields
164
- * - deduplicate
165
- * - group
166
- * - flatten again
167
- * @module datarestructor
168
- */
169
- var datarestructor = module.exports = {};
170
- // Export module for npm...
156
+ * datarestructor namespace and module declaration.
157
+ * It contains all functions to convert an object (e.g. parsed JSON) into uniform enumerated list of described field entries.
158
+ *
159
+ * <b>Transformation steps:</b>
160
+ * - JSON
161
+ * - flatten
162
+ * - mark and identify
163
+ * - add array fields
164
+ * - deduplicate
165
+ * - group
166
+ * - flatten again
167
+ * @module datarestructor
168
+ */ var datarestructor = module.exports = {}; // Export module for npm...
171
169
  datarestructor.internalCreateIfNotExists = datarestructorInternalCreateIfNotExists;
172
- var internal_object_tools = internal_object_tools || require("../../lib/js/flattenToArray");
173
- // supports vanilla js & npm
174
- var template_resolver = template_resolver || require("../../src/js/templateResolver");
175
- // supports vanilla js & npm
176
- var described_field = described_field || require("../../src/js/describedfield");
177
- // supports vanilla js & npm
178
- /**
179
- * Takes the full qualified original property name and extracts a simple name out of it.
180
- *
181
- * @callback module:datarestructor.propertyNameFunction
182
- * @param {string} propertyName full qualified, point separated property name
183
- * @return {String} extracted, simple name
184
- */
170
+ var internal_object_tools = internal_object_tools || require("403576eaef4c3d50"); // supports vanilla js & npm
171
+ var template_resolver = template_resolver || require("f62fb3394fa418f2"); // supports vanilla js & npm
172
+ var described_field = described_field || require("4388868734c1e0a7"); // supports vanilla js & npm
185
173
  /**
186
- * Describes a selected part of the incoming data structure and defines,
187
- * how the data should be transformed.
188
- *
189
- * @typedef {Object} module:datarestructor.PropertyStructureDescription
190
- * @property {string} type - ""(default). Some examples: "summary" for e.g. a list overview. "detail" e.g. when a summary is selected. "filter" e.g. for field/value pair results that can be selected as search parameters.
191
- * @property {string} category - name of the category. Default = "". Could contain a short domain name like "product" or "vendor".
192
- * @property {string} [abbreviation=""] - one optional character, a symbol character or a short abbreviation of the category
193
- * @property {string} [image=""] - one optional path to an image resource
194
- * @property {boolean} propertyPatternTemplateMode - "false"(default): property name needs to be equal to the pattern. "true" allows variables like "{{fieldName}}" inside the pattern.
195
- * @property {string} propertyPattern - property name pattern (without array indices) to match
196
- * @property {string} indexStartsWith - ""(default) matches all ids. String that needs to match the beginning of the id. E.g. "1." will match id="1.3.4" but not "0.1.2".
197
- * @property {module:datarestructor.propertyNameFunction} getDisplayNameForPropertyName - display name for the property. ""(default) last property name element with upper case first letter.
198
- * @property {module:datarestructor.propertyNameFunction} getFieldNameForPropertyName - field name for the property. "" (default) last property name element.
199
- * @property {string} groupName - name of the property, that contains grouped entries. Default="group".
200
- * @property {string} groupPattern - Pattern that describes how to group entries. "groupName" defines the name of this group. A pattern may contain variables in double curly brackets {{variable}}.
201
- * @property {string} groupDestinationPattern - Pattern that describes where the group should be moved to. Default=""=Group will not be moved. A pattern may contain variables in double curly brackets {{variable}}.
202
- * @property {string} groupDestinationName - (default=groupName) Name of the group when it had been moved to the destination.
203
- * @property {string} deduplicationPattern - Pattern to use to remove duplicate entries. A pattern may contain variables in double curly brackets {{variable}}.
204
- */
205
- datarestructor.PropertyStructureDescriptionBuilder = (function () {
206
- "use strict";
207
- /**
208
- * Builder for a {@link PropertyStructureDescription}.
209
- * @constructs PropertyStructureDescriptionBuilder
210
- * @alias module:datarestructor.PropertyStructureDescriptionBuilder
211
- */
212
- function PropertyStructureDescription() {
213
- /**
214
- * @type {module:datarestructor.PropertyStructureDescription}
215
- */
216
- this.description = {
217
- type: "",
218
- category: "",
219
- abbreviation: "",
220
- image: "",
221
- propertyPatternTemplateMode: false,
222
- propertyPattern: "",
223
- indexStartsWith: "",
224
- groupName: "group",
225
- groupPattern: "",
226
- groupDestinationPattern: "",
227
- groupDestinationName: null,
228
- deduplicationPattern: "",
229
- getDisplayNameForPropertyName: null,
230
- getFieldNameForPropertyName: null,
231
- matchesPropertyName: null
232
- };
233
- /**
234
- * Sets the type.
235
- *
236
- * Contains the type of the entry, for example:
237
- * - "summary" for e.g. a list overview.
238
- * - "detail" e.g. when a summary is selected.
239
- * - "filter" e.g. for field/value pair results that can be selected as search parameters.
240
- *
241
- * @function
242
- * @param {String} [value=""]
243
- * @returns {module:datarestructor.PropertyStructureDescription}
244
- * @example type("summary")
245
- */
246
- this.type = function (value) {
247
- this.description.type = withDefault(value, "");
248
- return this;
249
- };
250
- /**
251
- * Sets the category.
252
- *
253
- * Contains a short domain nam, for example:
254
- * - "product" for products
255
- * - "vendor" for vendors
256
- *
257
- * @function
258
- * @param {String} [value=""]
259
- * @returns {module:datarestructor.PropertyStructureDescription}
260
- * @example category("Product")
261
- */
262
- this.category = function (value) {
263
- this.description.category = withDefault(value, "");
264
- return this;
265
- };
266
- /**
267
- * Sets the optional abbreviation.
268
- *
269
- * Contains a symbol character or a very short abbreviation of the category.
270
- * - "P" for products
271
- * - "V" for vendors
272
- *
273
- * @function
274
- * @param {String} [value=""]
275
- * @returns {module:datarestructor.PropertyStructureDescription}
276
- * @example abbreviation("P")
277
- */
278
- this.abbreviation = function (value) {
279
- this.description.abbreviation = withDefault(value, "");
280
- return this;
281
- };
282
- /**
283
- * Sets the optional path to an image resource.
284
- *
285
- * @function
286
- * @param {String} [value=""]
287
- * @returns {module:datarestructor.PropertyStructureDescription}
288
- * @example image("img/product.png")
289
- */
290
- this.image = function (value) {
291
- this.description.image = withDefault(value, "");
292
- return this;
293
- };
294
- /**
295
- * Sets "equal mode" for the property pattern.
296
- *
297
- * "propertyPattern" need to match exactly if this mode is activated.
298
- * It clears propertyPatternTemplateMode which means "equal" mode.
299
- * @function
300
- * @returns {module:datarestructor.PropertyStructureDescription}
301
- */
302
- this.propertyPatternEqualMode = function () {
303
- this.description.propertyPatternTemplateMode = false;
304
- return this;
305
- };
306
- /**
307
- * Sets "template mode" for the property pattern.
308
- *
309
- * "propertyPattern" can contain variables like {{fieldName}} and
310
- * doesn't need to match the property name exactly. If the "propertyPattern"
311
- * is shorter than the property name, it also matches when the property name
312
- * starts with the "propertyPattern".
313
- *
314
- * @function
315
- * @returns {module:datarestructor.PropertyStructureDescription}
316
- */
317
- this.propertyPatternTemplateMode = function () {
318
- this.description.propertyPatternTemplateMode = true;
319
- return this;
320
- };
321
- /**
322
- * Sets the property name pattern.
323
- *
324
- * Contains single property names with sub types separated by "." without array indices.
325
- * May contain variables in double curly brackets.
326
- *
327
- * Example:
328
- * - responses.hits.hits._source.{{fieldName}}
329
- * @function
330
- * @param {String} [value=""]
331
- * @returns {module:datarestructor.PropertyStructureDescription}
332
- * @example propertyPattern("responses.hits.hits._source.{{fieldName}}")
333
- */
334
- this.propertyPattern = function (value) {
335
- this.description.propertyPattern = withDefault(value, "");
336
- return this;
337
- };
338
- /**
339
- * Sets the optional beginning of the id that needs to match.
340
- * Matches all indices if set to "" (or not called).
341
- *
342
- * For example:
343
- * - "1." will match id="1.3.4" but not "0.1.2".
344
- * @function
345
- * @param {String} [value=""]
346
- * @returns {module:datarestructor.PropertyStructureDescription}
347
- * @example indexStartsWith("1.")
348
- */
349
- this.indexStartsWith = function (value) {
350
- this.description.indexStartsWith = withDefault(value, "");
351
- return this;
352
- };
353
- /**
354
- * Overrides the display name of the property.
355
- *
356
- * If it is not set or set to "" then it will be derived from the
357
- * last part of original property name starting with an upper case character.
358
- *
359
- * For example:
360
- * - "Product"
361
- * @function
362
- * @param {String} [value=""]
363
- * @returns {module:datarestructor.PropertyStructureDescription}
364
- * @example displayPropertyName("Product")
365
- */
366
- this.displayPropertyName = function (value) {
367
- this.description.getDisplayNameForPropertyName = createNameExtractFunction(value, this.description);
368
- if (isSpecifiedString(value)) {
369
- return this;
370
- }
371
- this.description.getDisplayNameForPropertyName = removeArrayValuePropertyPostfixFunction(this.description.getDisplayNameForPropertyName);
372
- this.description.getDisplayNameForPropertyName = upperCaseFirstLetterForFunction(this.description.getDisplayNameForPropertyName);
373
- return this;
374
- };
174
+ * Takes the full qualified original property name and extracts a simple name out of it.
175
+ *
176
+ * @callback module:datarestructor.propertyNameFunction
177
+ * @param {string} propertyName full qualified, point separated property name
178
+ * @return {String} extracted, simple name
179
+ */ /**
180
+ * Describes a selected part of the incoming data structure and defines,
181
+ * how the data should be transformed.
182
+ *
183
+ * @typedef {Object} module:datarestructor.PropertyStructureDescription
184
+ * @property {string} type - ""(default). Some examples: "summary" for e.g. a list overview. "detail" e.g. when a summary is selected. "filter" e.g. for field/value pair results that can be selected as search parameters.
185
+ * @property {string} category - name of the category. Default = "". Could contain a short domain name like "product" or "vendor".
186
+ * @property {string} [abbreviation=""] - one optional character, a symbol character or a short abbreviation of the category
187
+ * @property {string} [image=""] - one optional path to an image resource
188
+ * @property {boolean} propertyPatternTemplateMode - "false"(default): property name needs to be equal to the pattern. "true" allows variables like "{{fieldName}}" inside the pattern.
189
+ * @property {string} propertyPattern - property name pattern (without array indices) to match
190
+ * @property {string} indexStartsWith - ""(default) matches all ids. String that needs to match the beginning of the id. E.g. "1." will match id="1.3.4" but not "0.1.2".
191
+ * @property {module:datarestructor.propertyNameFunction} getDisplayNameForPropertyName - display name for the property. ""(default) last property name element with upper case first letter.
192
+ * @property {module:datarestructor.propertyNameFunction} getFieldNameForPropertyName - field name for the property. "" (default) last property name element.
193
+ * @property {string} groupName - name of the property, that contains grouped entries. Default="group".
194
+ * @property {string} groupPattern - Pattern that describes how to group entries. "groupName" defines the name of this group. A pattern may contain variables in double curly brackets {{variable}}.
195
+ * @property {string} groupDestinationPattern - Pattern that describes where the group should be moved to. Default=""=Group will not be moved. A pattern may contain variables in double curly brackets {{variable}}.
196
+ * @property {string} groupDestinationName - (default=groupName) Name of the group when it had been moved to the destination.
197
+ * @property {string} deduplicationPattern - Pattern to use to remove duplicate entries. A pattern may contain variables in double curly brackets {{variable}}.
198
+ */ datarestructor.PropertyStructureDescriptionBuilder = function() {
199
+ "use strict";
375
200
  /**
376
- * Overrides the (technical) field name of the property.
377
- *
378
- * If it is not set or set to "" then it will be derived from the
379
- * last part of original property name.
380
- *
381
- * For example:
382
- * - "product"
383
- * @function
384
- * @param {String} [value=""]
385
- * @returns {module:datarestructor.PropertyStructureDescription}
386
- * @example fieldName("product")
387
- */
388
- this.fieldName = function (value) {
389
- this.description.getFieldNameForPropertyName = createNameExtractFunction(value, this.description);
390
- return this;
391
- };
392
- /**
393
- * Sets the name of the property, that contains grouped entries.
394
- *
395
- * @function
396
- * @param {String} [value=""]
397
- * @returns {module:datarestructor.PropertyStructureDescription}
398
- * @example groupName("details")
399
- */
400
- this.groupName = function (value) {
401
- this.description.groupName = withDefault(value, "");
402
- return this;
403
- };
404
- /**
405
- * Sets the pattern that describes how to group entries.
406
- *
407
- * "groupName" defines the name of this group.
408
- * A pattern may contain variables in double curly brackets {{variable}}.
409
- * @function
410
- * @param {String} [value=""]
411
- * @returns {module:datarestructor.PropertyStructureDescription}
412
- * @example groupPattern("{{type}}-{{category}}")
413
- */
414
- this.groupPattern = function (value) {
415
- this.description.groupPattern = withDefault(value, "");
416
- return this;
417
- };
418
- /**
419
- * Sets the pattern that describes where the group should be moved to.
420
- *
421
- * Default=""=Group will not be moved.
422
- * A pattern may contain variables in double curly brackets {{variable}}.
423
- * @function
424
- * @param {String} [value=""]
425
- * @returns {module:datarestructor.PropertyStructureDescription}
426
- * @example groupDestinationPattern("main-{{category}}")
427
- */
428
- this.groupDestinationPattern = function (value) {
429
- this.description.groupDestinationPattern = withDefault(value, "");
430
- return this;
431
- };
432
- /**
433
- * Sets the name of the group when it had been moved to the destination.
434
- *
435
- * The default value is the groupName, which will be used when the value is not valid (null or empty)
436
- * @function
437
- * @param {String} [value=""]
438
- * @returns {module:datarestructor.PropertyStructureDescription}
439
- * @example groupDestinationPattern("options")
440
- */
441
- this.groupDestinationName = function (value) {
442
- this.description.groupDestinationName = withDefault(value, this.description.groupName);
443
- return this;
444
- };
445
- /**
446
- * Sets the pattern to be used to remove duplicate entries.
447
- *
448
- * A pattern may contain variables in double curly brackets {{variable}}.
449
- * A pattern may contain variables in double curly brackets {{variable}}.
450
- * @function
451
- * @param {String} [value=""]
452
- * @returns {module:datarestructor.PropertyStructureDescription}
453
- * @example deduplicationPattern("{{category}}--{{type}}--{{index[0]}}--{{index[1]}}--{{fieldName}}")
454
- */
455
- this.deduplicationPattern = function (value) {
456
- this.description.deduplicationPattern = withDefault(value, "");
457
- return this;
458
- };
459
- /**
460
- * Finalizes the settings and builds the PropertyStructureDescription.
461
- * @function
462
- * @returns {module:datarestructor.PropertyStructureDescription}
463
- */
464
- this.build = function () {
465
- this.description.matchesPropertyName = createFunctionMatchesPropertyName(this.description);
466
- if (this.description.getDisplayNameForPropertyName == null) {
467
- this.displayPropertyName("");
468
- }
469
- if (this.description.getFieldNameForPropertyName == null) {
470
- this.fieldName("");
471
- }
472
- if (this.description.groupDestinationName == null) {
473
- this.groupDestinationName("");
474
- }
475
- return this.description;
476
- };
477
- }
478
- function createNameExtractFunction(value, description) {
479
- if (isSpecifiedString(value)) {
480
- return function () {
201
+ * Builder for a {@link PropertyStructureDescription}.
202
+ * @constructs PropertyStructureDescriptionBuilder
203
+ * @alias module:datarestructor.PropertyStructureDescriptionBuilder
204
+ */ function PropertyStructureDescription() {
205
+ /**
206
+ * @type {module:datarestructor.PropertyStructureDescription}
207
+ */ this.description = {
208
+ type: "",
209
+ category: "",
210
+ abbreviation: "",
211
+ image: "",
212
+ propertyPatternTemplateMode: false,
213
+ propertyPattern: "",
214
+ indexStartsWith: "",
215
+ groupName: "group",
216
+ groupPattern: "",
217
+ groupDestinationPattern: "",
218
+ groupDestinationName: null,
219
+ deduplicationPattern: "",
220
+ getDisplayNameForPropertyName: null,
221
+ getFieldNameForPropertyName: null,
222
+ matchesPropertyName: null
223
+ };
224
+ /**
225
+ * Sets the type.
226
+ *
227
+ * Contains the type of the entry, for example:
228
+ * - "summary" for e.g. a list overview.
229
+ * - "detail" e.g. when a summary is selected.
230
+ * - "filter" e.g. for field/value pair results that can be selected as search parameters.
231
+ *
232
+ * @function
233
+ * @param {String} [value=""]
234
+ * @returns {module:datarestructor.PropertyStructureDescription}
235
+ * @example type("summary")
236
+ */ this.type = function(value) {
237
+ this.description.type = withDefault(value, "");
238
+ return this;
239
+ };
240
+ /**
241
+ * Sets the category.
242
+ *
243
+ * Contains a short domain nam, for example:
244
+ * - "product" for products
245
+ * - "vendor" for vendors
246
+ *
247
+ * @function
248
+ * @param {String} [value=""]
249
+ * @returns {module:datarestructor.PropertyStructureDescription}
250
+ * @example category("Product")
251
+ */ this.category = function(value) {
252
+ this.description.category = withDefault(value, "");
253
+ return this;
254
+ };
255
+ /**
256
+ * Sets the optional abbreviation.
257
+ *
258
+ * Contains a symbol character or a very short abbreviation of the category.
259
+ * - "P" for products
260
+ * - "V" for vendors
261
+ *
262
+ * @function
263
+ * @param {String} [value=""]
264
+ * @returns {module:datarestructor.PropertyStructureDescription}
265
+ * @example abbreviation("P")
266
+ */ this.abbreviation = function(value) {
267
+ this.description.abbreviation = withDefault(value, "");
268
+ return this;
269
+ };
270
+ /**
271
+ * Sets the optional path to an image resource.
272
+ *
273
+ * @function
274
+ * @param {String} [value=""]
275
+ * @returns {module:datarestructor.PropertyStructureDescription}
276
+ * @example image("img/product.png")
277
+ */ this.image = function(value) {
278
+ this.description.image = withDefault(value, "");
279
+ return this;
280
+ };
281
+ /**
282
+ * Sets "equal mode" for the property pattern.
283
+ *
284
+ * "propertyPattern" need to match exactly if this mode is activated.
285
+ * It clears propertyPatternTemplateMode which means "equal" mode.
286
+ * @function
287
+ * @returns {module:datarestructor.PropertyStructureDescription}
288
+ */ this.propertyPatternEqualMode = function() {
289
+ this.description.propertyPatternTemplateMode = false;
290
+ return this;
291
+ };
292
+ /**
293
+ * Sets "template mode" for the property pattern.
294
+ *
295
+ * "propertyPattern" can contain variables like {{fieldName}} and
296
+ * doesn't need to match the property name exactly. If the "propertyPattern"
297
+ * is shorter than the property name, it also matches when the property name
298
+ * starts with the "propertyPattern".
299
+ *
300
+ * @function
301
+ * @returns {module:datarestructor.PropertyStructureDescription}
302
+ */ this.propertyPatternTemplateMode = function() {
303
+ this.description.propertyPatternTemplateMode = true;
304
+ return this;
305
+ };
306
+ /**
307
+ * Sets the property name pattern.
308
+ *
309
+ * Contains single property names with sub types separated by "." without array indices.
310
+ * May contain variables in double curly brackets.
311
+ *
312
+ * Example:
313
+ * - responses.hits.hits._source.{{fieldName}}
314
+ * @function
315
+ * @param {String} [value=""]
316
+ * @returns {module:datarestructor.PropertyStructureDescription}
317
+ * @example propertyPattern("responses.hits.hits._source.{{fieldName}}")
318
+ */ this.propertyPattern = function(value) {
319
+ this.description.propertyPattern = withDefault(value, "");
320
+ return this;
321
+ };
322
+ /**
323
+ * Sets the optional beginning of the id that needs to match.
324
+ * Matches all indices if set to "" (or not called).
325
+ *
326
+ * For example:
327
+ * - "1." will match id="1.3.4" but not "0.1.2".
328
+ * @function
329
+ * @param {String} [value=""]
330
+ * @returns {module:datarestructor.PropertyStructureDescription}
331
+ * @example indexStartsWith("1.")
332
+ */ this.indexStartsWith = function(value) {
333
+ this.description.indexStartsWith = withDefault(value, "");
334
+ return this;
335
+ };
336
+ /**
337
+ * Overrides the display name of the property.
338
+ *
339
+ * If it is not set or set to "" then it will be derived from the
340
+ * last part of original property name starting with an upper case character.
341
+ *
342
+ * For example:
343
+ * - "Product"
344
+ * @function
345
+ * @param {String} [value=""]
346
+ * @returns {module:datarestructor.PropertyStructureDescription}
347
+ * @example displayPropertyName("Product")
348
+ */ this.displayPropertyName = function(value) {
349
+ this.description.getDisplayNameForPropertyName = createNameExtractFunction(value, this.description);
350
+ if (isSpecifiedString(value)) return this;
351
+ this.description.getDisplayNameForPropertyName = removeArrayValuePropertyPostfixFunction(this.description.getDisplayNameForPropertyName);
352
+ this.description.getDisplayNameForPropertyName = upperCaseFirstLetterForFunction(this.description.getDisplayNameForPropertyName);
353
+ return this;
354
+ };
355
+ /**
356
+ * Overrides the (technical) field name of the property.
357
+ *
358
+ * If it is not set or set to "" then it will be derived from the
359
+ * last part of original property name.
360
+ *
361
+ * For example:
362
+ * - "product"
363
+ * @function
364
+ * @param {String} [value=""]
365
+ * @returns {module:datarestructor.PropertyStructureDescription}
366
+ * @example fieldName("product")
367
+ */ this.fieldName = function(value) {
368
+ this.description.getFieldNameForPropertyName = createNameExtractFunction(value, this.description);
369
+ return this;
370
+ };
371
+ /**
372
+ * Sets the name of the property, that contains grouped entries.
373
+ *
374
+ * @function
375
+ * @param {String} [value=""]
376
+ * @returns {module:datarestructor.PropertyStructureDescription}
377
+ * @example groupName("details")
378
+ */ this.groupName = function(value) {
379
+ this.description.groupName = withDefault(value, "");
380
+ return this;
381
+ };
382
+ /**
383
+ * Sets the pattern that describes how to group entries.
384
+ *
385
+ * "groupName" defines the name of this group.
386
+ * A pattern may contain variables in double curly brackets {{variable}}.
387
+ * @function
388
+ * @param {String} [value=""]
389
+ * @returns {module:datarestructor.PropertyStructureDescription}
390
+ * @example groupPattern("{{type}}-{{category}}")
391
+ */ this.groupPattern = function(value) {
392
+ this.description.groupPattern = withDefault(value, "");
393
+ return this;
394
+ };
395
+ /**
396
+ * Sets the pattern that describes where the group should be moved to.
397
+ *
398
+ * Default=""=Group will not be moved.
399
+ * A pattern may contain variables in double curly brackets {{variable}}.
400
+ * @function
401
+ * @param {String} [value=""]
402
+ * @returns {module:datarestructor.PropertyStructureDescription}
403
+ * @example groupDestinationPattern("main-{{category}}")
404
+ */ this.groupDestinationPattern = function(value) {
405
+ this.description.groupDestinationPattern = withDefault(value, "");
406
+ return this;
407
+ };
408
+ /**
409
+ * Sets the name of the group when it had been moved to the destination.
410
+ *
411
+ * The default value is the groupName, which will be used when the value is not valid (null or empty)
412
+ * @function
413
+ * @param {String} [value=""]
414
+ * @returns {module:datarestructor.PropertyStructureDescription}
415
+ * @example groupDestinationPattern("options")
416
+ */ this.groupDestinationName = function(value) {
417
+ this.description.groupDestinationName = withDefault(value, this.description.groupName);
418
+ return this;
419
+ };
420
+ /**
421
+ * Sets the pattern to be used to remove duplicate entries.
422
+ *
423
+ * A pattern may contain variables in double curly brackets {{variable}}.
424
+ * A pattern may contain variables in double curly brackets {{variable}}.
425
+ * @function
426
+ * @param {String} [value=""]
427
+ * @returns {module:datarestructor.PropertyStructureDescription}
428
+ * @example deduplicationPattern("{{category}}--{{type}}--{{index[0]}}--{{index[1]}}--{{fieldName}}")
429
+ */ this.deduplicationPattern = function(value) {
430
+ this.description.deduplicationPattern = withDefault(value, "");
431
+ return this;
432
+ };
433
+ /**
434
+ * Finalizes the settings and builds the PropertyStructureDescription.
435
+ * @function
436
+ * @returns {module:datarestructor.PropertyStructureDescription}
437
+ */ this.build = function() {
438
+ this.description.matchesPropertyName = createFunctionMatchesPropertyName(this.description);
439
+ if (this.description.getDisplayNameForPropertyName == null) this.displayPropertyName("");
440
+ if (this.description.getFieldNameForPropertyName == null) this.fieldName("");
441
+ if (this.description.groupDestinationName == null) this.groupDestinationName("");
442
+ return this.description;
443
+ };
444
+ }
445
+ function createNameExtractFunction(value, description) {
446
+ if (isSpecifiedString(value)) return function() {
447
+ return value;
448
+ };
449
+ if (description.propertyPatternTemplateMode) {
450
+ var patternToMatch = description.propertyPattern; // closure (closed over) parameter
451
+ return extractNameUsingTemplatePattern(patternToMatch);
452
+ }
453
+ return extractNameUsingRightMostPropertyNameElement();
454
+ }
455
+ function createFunctionMatchesPropertyName(description) {
456
+ var propertyPatternToMatch = description.propertyPattern; // closure (closed over) parameter
457
+ if (!isSpecifiedString(propertyPatternToMatch)) return function() {
458
+ return false; // Without a propertyPattern, no property will match (deactivated mark/identify).
459
+ };
460
+ if (description.propertyPatternTemplateMode) return function(propertyNameWithoutArrayIndices) {
461
+ return templateModePatternRegexForPattern(propertyPatternToMatch).exec(propertyNameWithoutArrayIndices) != null;
462
+ };
463
+ return function(propertyNameWithoutArrayIndices) {
464
+ return propertyNameWithoutArrayIndices === propertyPatternToMatch;
465
+ };
466
+ }
467
+ function rightMostPropertyNameElement(propertyName) {
468
+ var regularExpression = new RegExp("(\\w+)$", "gi");
469
+ var match = propertyName.match(regularExpression);
470
+ if (match != null) return match[0];
471
+ return propertyName;
472
+ }
473
+ function upperCaseFirstLetter(value) {
474
+ if (value.length > 1) return value.charAt(0).toUpperCase() + value.slice(1);
481
475
  return value;
482
- };
483
476
  }
484
- if (description.propertyPatternTemplateMode) {
485
- var patternToMatch = description.propertyPattern;
486
- // closure (closed over) parameter
487
- return extractNameUsingTemplatePattern(patternToMatch);
477
+ function upperCaseFirstLetterForFunction(nameExtractFunction) {
478
+ return function(propertyName) {
479
+ return upperCaseFirstLetter(nameExtractFunction(propertyName));
480
+ };
488
481
  }
489
- return extractNameUsingRightMostPropertyNameElement();
490
- }
491
- function createFunctionMatchesPropertyName(description) {
492
- var propertyPatternToMatch = description.propertyPattern;
493
- // closure (closed over) parameter
494
- if (!isSpecifiedString(propertyPatternToMatch)) {
495
- return function () {
496
- return false;
497
- };
482
+ function removeArrayValuePropertyPostfixFunction(nameExtractFunction) {
483
+ return function(propertyName) {
484
+ var name = nameExtractFunction(propertyName);
485
+ name = name != null ? name : "";
486
+ return name.replace("_comma_separated_values", "");
487
+ };
498
488
  }
499
- if (description.propertyPatternTemplateMode) {
500
- return function (propertyNameWithoutArrayIndices) {
501
- return templateModePatternRegexForPattern(propertyPatternToMatch).exec(propertyNameWithoutArrayIndices) != null;
502
- };
489
+ function extractNameUsingTemplatePattern(propertyPattern) {
490
+ return function(propertyName) {
491
+ var regex = templateModePatternRegexForPatternAndVariable(propertyPattern, "{{fieldName}}");
492
+ var match = regex.exec(propertyName);
493
+ if (match && match[1] != "") return match[1];
494
+ return rightMostPropertyNameElement(propertyName);
495
+ };
503
496
  }
504
- return function (propertyNameWithoutArrayIndices) {
505
- return propertyNameWithoutArrayIndices === propertyPatternToMatch;
506
- };
507
- }
508
- function rightMostPropertyNameElement(propertyName) {
509
- var regularExpression = new RegExp("(\\w+)$", "gi");
510
- var match = propertyName.match(regularExpression);
511
- if (match != null) {
512
- return match[0];
497
+ function extractNameUsingRightMostPropertyNameElement() {
498
+ return function(propertyName) {
499
+ return rightMostPropertyNameElement(propertyName);
500
+ };
513
501
  }
514
- return propertyName;
515
- }
516
- function upperCaseFirstLetter(value) {
517
- if (value.length > 1) {
518
- return value.charAt(0).toUpperCase() + value.slice(1);
502
+ function templateModePatternRegexForPattern(propertyPatternToUse) {
503
+ var placeholderInDoubleCurlyBracketsRegEx = new RegExp("\\\\\\{\\\\\\{[-\\w]+\\\\\\}\\\\\\}", "gi");
504
+ return templateModePatternRegexForPatternAndVariable(propertyPatternToUse, placeholderInDoubleCurlyBracketsRegEx);
519
505
  }
520
- return value;
521
- }
522
- function upperCaseFirstLetterForFunction(nameExtractFunction) {
523
- return function (propertyName) {
524
- return upperCaseFirstLetter(nameExtractFunction(propertyName));
525
- };
526
- }
527
- function removeArrayValuePropertyPostfixFunction(nameExtractFunction) {
528
- return function (propertyName) {
529
- var name = nameExtractFunction(propertyName);
530
- name = name != null ? name : "";
531
- return name.replace("_comma_separated_values", "");
532
- };
533
- }
534
- function extractNameUsingTemplatePattern(propertyPattern) {
535
- return function (propertyName) {
536
- var regex = templateModePatternRegexForPatternAndVariable(propertyPattern, "{{fieldName}}");
537
- var match = regex.exec(propertyName);
538
- if (match && match[1] != "") {
539
- return match[1];
540
- }
541
- return rightMostPropertyNameElement(propertyName);
542
- };
543
- }
544
- function extractNameUsingRightMostPropertyNameElement() {
545
- return function (propertyName) {
546
- return rightMostPropertyNameElement(propertyName);
547
- };
548
- }
549
- function templateModePatternRegexForPattern(propertyPatternToUse) {
550
- var placeholderInDoubleCurlyBracketsRegEx = new RegExp("\\\\\\{\\\\\\{[-\\w]+\\\\\\}\\\\\\}", "gi");
551
- return templateModePatternRegexForPatternAndVariable(propertyPatternToUse, placeholderInDoubleCurlyBracketsRegEx);
552
- }
553
- function templateModePatternRegexForPatternAndVariable(propertyPatternToUse, variablePattern) {
554
- var pattern = escapeCharsForRegEx(propertyPatternToUse);
555
- if (typeof variablePattern === "string") {
556
- variablePattern = escapeCharsForRegEx(variablePattern);
506
+ function templateModePatternRegexForPatternAndVariable(propertyPatternToUse, variablePattern) {
507
+ var pattern = escapeCharsForRegEx(propertyPatternToUse);
508
+ if (typeof variablePattern === "string") variablePattern = escapeCharsForRegEx(variablePattern);
509
+ pattern = pattern.replace(variablePattern, "([-\\w]+)");
510
+ pattern = "^" + pattern;
511
+ return new RegExp(pattern, "i");
557
512
  }
558
- pattern = pattern.replace(variablePattern, "([-\\w]+)");
559
- pattern = "^" + pattern;
560
- return new RegExp(pattern, "i");
561
- }
562
- function escapeCharsForRegEx(characters) {
563
- var nonWordCharactersRegEx = new RegExp("([^-\\w])", "gi");
564
- return characters.replace(nonWordCharactersRegEx, "\\$1");
565
- }
566
- function withDefault(value, defaultValue) {
567
- return isSpecifiedString(value) ? value : defaultValue;
568
- }
569
- function isSpecifiedString(value) {
570
- return typeof value === "string" && value != null && value != "";
571
- }
572
- return PropertyStructureDescription;
573
- })();
574
- /**
575
- * Adds a group item/entry to the {@link module:datarestructor.DescribedEntry}.
576
- *
577
- * @callback module:datarestructor.addGroupEntryFunction
578
- * @param {String} groupName name of the group that should be added
579
- * @param {module:datarestructor.DescribedEntry} describedEntry entry that should be added to the group
580
- */
581
- /**
582
- * Adds some group items/entries to the {@link module:datarestructor.DescribedEntry}.
583
- *
584
- * @callback module:datarestructor.addGroupEntriesFunction
585
- * @param {String} groupName name of the group that should be added
586
- * @param {module:datarestructor.DescribedEntry[]} describedEntry entries that should be added to the group
587
- */
588
- /**
589
- * @typedef {Object} module:datarestructor.DescribedEntry
590
- * @property {string} category - category of the result from the PropertyStructureDescription using a short name or e.g. a symbol character
591
- * @property {string} type - type of the result from PropertyStructureDescription
592
- * @property {string} [abbreviation=""] - one optional character, a symbol character or a short abbreviation of the category
593
- * @property {string} [image=""] - one optional path to an image resource
594
- * @property {string} index - array of numbers containing the split index. Example: "responses[2].hits.hits[4]._source.name" leads to an array with the two elements: [2,4]
595
- * @property {string} displayName - display name extracted from the point separated hierarchical property name, e.g. "Name"
596
- * @property {string} fieldName - field name extracted from the point separated hierarchical property name, e.g. "name"
597
- * @property {string} value - content of the field
598
- * @property {string[]} groupNames - array of names of all dynamically added properties representing groups
599
- * @property {module:datarestructor.addGroupEntryFunction} addGroupEntry - function, that adds an entry to the given group. If the group does not exist, it will be created.
600
- * @property {module:datarestructor.addGroupEntriesFunction} addGroupEntries - function, that adds entries to the given group. If the group does not exist, it will be created.
601
- * @property {boolean} _isMatchingIndex - true, when _identifier.index matches the described "indexStartsWith"
602
- * @property {Object} _identifier - internal structure for identifier. Avoid using it outside since it may change.
603
- * @property {string} _identifier.index - array indices in hierarchical order separated by points, e.g. "0.0"
604
- * @property {string} _identifier.value - the (single) value of the "flattened" property, e.g. "Smith"
605
- * @property {string} _identifier.propertyNameWithArrayIndices - the "original" flattened property name in hierarchical order separated by points, e.g. "responses[0].hits.hits[0]._source.name"
606
- * @property {string} _identifier.propertyNameWithoutArrayIndices - same as propertyNamesWithArrayIndices but without array indices, e.g. "responses.hits.hits._source.name"
607
- * @property {string} _identifier.groupId - Contains the resolved groupPattern from the PropertyStructureDescription. Entries with the same id will be grouped into the "groupName" of the PropertyStructureDescription.
608
- * @property {string} _identifier.groupDestinationId - Contains the resolved groupDestinationPattern from the PropertyStructureDescription. Entries with this id will be moved to the given destination group.
609
- * @property {string} _identifier.deduplicationId - Contains the resolved deduplicationPattern from the PropertyStructureDescription. Entries with the same id will be considered to be a duplicate and hence removed.
610
- * @property {Object} _description - PropertyStructureDescription for internal use. Avoid using it outside since it may change.
611
- */
513
+ function escapeCharsForRegEx(characters) {
514
+ var nonWordCharactersRegEx = new RegExp("([^-\\w])", "gi");
515
+ return characters.replace(nonWordCharactersRegEx, "\\$1");
516
+ }
517
+ function withDefault(value, defaultValue) {
518
+ return isSpecifiedString(value) ? value : defaultValue;
519
+ }
520
+ function isSpecifiedString(value) {
521
+ return typeof value === "string" && value != null && value != "";
522
+ }
523
+ return PropertyStructureDescription;
524
+ }();
612
525
  /**
613
- * Returns a field value of the given {@link module:datarestructor.DescribedEntry}.
614
- *
615
- * @callback module:datarestructor.stringFieldOfDescribedEntryFunction
616
- * @param {module:datarestructor.DescribedEntry} entry described entry that contains the field that should be returned
617
- * @returns {String} field value
618
- */
619
- datarestructor.DescribedEntryCreator = (function () {
620
- "use strict";
621
- var removeArrayBracketsRegEx = new RegExp("\\[\\d+\\]", "gi");
622
- /**
623
- * Creates a {@link module:datarestructor.DescribedEntry}.
624
- * @constructs DescribedEntryCreator
625
- * @alias module:datarestructor.DescribedEntryCreator
626
- */
627
- function DescribedEntry(entry, description) {
628
- var indices = indicesOf(entry.name);
629
- var propertyNameWithoutArrayIndices = entry.name.replace(removeArrayBracketsRegEx, "");
630
- var templateResolver = new template_resolver.Resolver(this);
631
- this.category = description.category;
632
- this.type = description.type;
633
- this.abbreviation = description.abbreviation;
634
- this.image = description.image;
526
+ * Adds a group item/entry to the {@link module:datarestructor.DescribedEntry}.
527
+ *
528
+ * @callback module:datarestructor.addGroupEntryFunction
529
+ * @param {String} groupName name of the group that should be added
530
+ * @param {module:datarestructor.DescribedEntry} describedEntry entry that should be added to the group
531
+ */ /**
532
+ * Adds some group items/entries to the {@link module:datarestructor.DescribedEntry}.
533
+ *
534
+ * @callback module:datarestructor.addGroupEntriesFunction
535
+ * @param {String} groupName name of the group that should be added
536
+ * @param {module:datarestructor.DescribedEntry[]} describedEntry entries that should be added to the group
537
+ */ /**
538
+ * @typedef {Object} module:datarestructor.DescribedEntry
539
+ * @property {string} category - category of the result from the PropertyStructureDescription using a short name or e.g. a symbol character
540
+ * @property {string} type - type of the result from PropertyStructureDescription
541
+ * @property {string} [abbreviation=""] - one optional character, a symbol character or a short abbreviation of the category
542
+ * @property {string} [image=""] - one optional path to an image resource
543
+ * @property {string} index - array of numbers containing the split index. Example: "responses[2].hits.hits[4]._source.name" leads to an array with the two elements: [2,4]
544
+ * @property {string} displayName - display name extracted from the point separated hierarchical property name, e.g. "Name"
545
+ * @property {string} fieldName - field name extracted from the point separated hierarchical property name, e.g. "name"
546
+ * @property {string} value - content of the field
547
+ * @property {string[]} groupNames - array of names of all dynamically added properties representing groups
548
+ * @property {module:datarestructor.addGroupEntryFunction} addGroupEntry - function, that adds an entry to the given group. If the group does not exist, it will be created.
549
+ * @property {module:datarestructor.addGroupEntriesFunction} addGroupEntries - function, that adds entries to the given group. If the group does not exist, it will be created.
550
+ * @property {boolean} _isMatchingIndex - true, when _identifier.index matches the described "indexStartsWith"
551
+ * @property {Object} _identifier - internal structure for identifier. Avoid using it outside since it may change.
552
+ * @property {string} _identifier.index - array indices in hierarchical order separated by points, e.g. "0.0"
553
+ * @property {string} _identifier.value - the (single) value of the "flattened" property, e.g. "Smith"
554
+ * @property {string} _identifier.propertyNameWithArrayIndices - the "original" flattened property name in hierarchical order separated by points, e.g. "responses[0].hits.hits[0]._source.name"
555
+ * @property {string} _identifier.propertyNameWithoutArrayIndices - same as propertyNamesWithArrayIndices but without array indices, e.g. "responses.hits.hits._source.name"
556
+ * @property {string} _identifier.groupId - Contains the resolved groupPattern from the PropertyStructureDescription. Entries with the same id will be grouped into the "groupName" of the PropertyStructureDescription.
557
+ * @property {string} _identifier.groupDestinationId - Contains the resolved groupDestinationPattern from the PropertyStructureDescription. Entries with this id will be moved to the given destination group.
558
+ * @property {string} _identifier.deduplicationId - Contains the resolved deduplicationPattern from the PropertyStructureDescription. Entries with the same id will be considered to be a duplicate and hence removed.
559
+ * @property {Object} _description - PropertyStructureDescription for internal use. Avoid using it outside since it may change.
560
+ */ /**
561
+ * Returns a field value of the given {@link module:datarestructor.DescribedEntry}.
562
+ *
563
+ * @callback module:datarestructor.stringFieldOfDescribedEntryFunction
564
+ * @param {module:datarestructor.DescribedEntry} entry described entry that contains the field that should be returned
565
+ * @returns {String} field value
566
+ */ datarestructor.DescribedEntryCreator = function() {
567
+ "use strict";
568
+ var removeArrayBracketsRegEx = new RegExp("\\[\\d+\\]", "gi");
635
569
  /**
636
- * Array of numbers containing the split index.
637
- * Example: "responses[2].hits.hits[4]._source.name" leads to an array with two elements: [2,4]
638
- * This is the public version of the internal variable _identifier.index, which contains in contrast all index elements in one point separated string (e.g. "2.4").
639
- * @type {number[]}
640
- */
641
- this.index = indices.numberArray;
642
- this.displayName = description.getDisplayNameForPropertyName(propertyNameWithoutArrayIndices);
643
- this.fieldName = description.getFieldNameForPropertyName(propertyNameWithoutArrayIndices);
644
- this.value = entry.value;
645
- this.groupNames = [];
646
- this._isMatchingIndex = indices.pointDelimited.indexOf(description.indexStartsWith) == 0;
647
- this._description = description;
648
- this._identifier = {
649
- index: indices.pointDelimited,
650
- propertyNameWithArrayIndices: entry.name,
651
- propertyNameWithoutArrayIndices: propertyNameWithoutArrayIndices,
652
- groupId: "",
653
- groupDestinationId: "",
654
- deduplicationId: ""
655
- };
656
- this._identifier.groupId = templateResolver.replaceResolvableFields(description.groupPattern, templateResolver.resolvableFieldsOfAll(this, this._description, this._identifier));
657
- this._identifier.groupDestinationId = templateResolver.replaceResolvableFields(description.groupDestinationPattern, templateResolver.resolvableFieldsOfAll(this, this._description, this._identifier));
658
- this._identifier.deduplicationId = templateResolver.replaceResolvableFields(description.deduplicationPattern, templateResolver.resolvableFieldsOfAll(this, this._description, this._identifier));
570
+ * Creates a {@link module:datarestructor.DescribedEntry}.
571
+ * @constructs DescribedEntryCreator
572
+ * @alias module:datarestructor.DescribedEntryCreator
573
+ */ function DescribedEntry(entry, description) {
574
+ var indices = indicesOf(entry.name);
575
+ var propertyNameWithoutArrayIndices = entry.name.replace(removeArrayBracketsRegEx, "");
576
+ var templateResolver = new template_resolver.Resolver(this);
577
+ this.category = description.category;
578
+ this.type = description.type;
579
+ this.abbreviation = description.abbreviation;
580
+ this.image = description.image;
581
+ /**
582
+ * Array of numbers containing the split index.
583
+ * Example: "responses[2].hits.hits[4]._source.name" leads to an array with two elements: [2,4]
584
+ * This is the public version of the internal variable _identifier.index, which contains in contrast all index elements in one point separated string (e.g. "2.4").
585
+ * @type {number[]}
586
+ */ this.index = indices.numberArray;
587
+ this.displayName = description.getDisplayNameForPropertyName(propertyNameWithoutArrayIndices);
588
+ this.fieldName = description.getFieldNameForPropertyName(propertyNameWithoutArrayIndices);
589
+ this.value = entry.value;
590
+ this.groupNames = [];
591
+ this._isMatchingIndex = indices.pointDelimited.indexOf(description.indexStartsWith) == 0;
592
+ this._description = description;
593
+ this._identifier = {
594
+ index: indices.pointDelimited,
595
+ propertyNameWithArrayIndices: entry.name,
596
+ propertyNameWithoutArrayIndices: propertyNameWithoutArrayIndices,
597
+ groupId: "",
598
+ groupDestinationId: "",
599
+ deduplicationId: ""
600
+ };
601
+ this._identifier.groupId = templateResolver.replaceResolvableFields(description.groupPattern, templateResolver.resolvableFieldsOfAll(this, this._description, this._identifier));
602
+ this._identifier.groupDestinationId = templateResolver.replaceResolvableFields(description.groupDestinationPattern, templateResolver.resolvableFieldsOfAll(this, this._description, this._identifier));
603
+ this._identifier.deduplicationId = templateResolver.replaceResolvableFields(description.deduplicationPattern, templateResolver.resolvableFieldsOfAll(this, this._description, this._identifier));
604
+ /**
605
+ * Adds an entry to the given group. If the group does not exist, it will be created.
606
+ * @param {String} groupName name of the group that should be added
607
+ * @param {module:datarestructor.DescribedEntry} describedEntry entry that should be added to the group
608
+ */ this.addGroupEntry = function(groupName, describedEntry) {
609
+ this.addGroupEntries(groupName, [
610
+ describedEntry
611
+ ]);
612
+ };
613
+ /**
614
+ * Adds entries to the given group. If the group does not exist, it will be created.
615
+ * @param {String} groupName
616
+ * @param {module:datarestructor.DescribedEntry[]} describedEntries
617
+ */ this.addGroupEntries = function(groupName, describedEntries) {
618
+ if (!this[groupName]) {
619
+ this.groupNames.push(groupName);
620
+ this[groupName] = [];
621
+ }
622
+ var index;
623
+ var describedEntry;
624
+ for(index = 0; index < describedEntries.length; index += 1){
625
+ describedEntry = describedEntries[index];
626
+ this[groupName].push(describedEntry);
627
+ }
628
+ };
629
+ }
659
630
  /**
660
- * Adds an entry to the given group. If the group does not exist, it will be created.
661
- * @param {String} groupName name of the group that should be added
662
- * @param {module:datarestructor.DescribedEntry} describedEntry entry that should be added to the group
663
- */
664
- this.addGroupEntry = function (groupName, describedEntry) {
665
- this.addGroupEntries(groupName, [describedEntry]);
666
- };
631
+ * @typedef {Object} module:datarestructor.ExtractedIndices
632
+ * @property {string} pointDelimited - bracket indices separated by points
633
+ * @property {number[]} numberArray as array of numbers
634
+ */ /**
635
+ * Returns "1.12.123" and [1,12,123] for "results[1].hits.hits[12].aggregates[123]".
636
+ *
637
+ * @param {String} fullPropertyName
638
+ * @return {module:datarestructor.ExtractedIndices} extracted indices in different representations
639
+ * @protected
640
+ * @memberof module:datarestructor.DescribedEntryCreator
641
+ */ function indicesOf(fullPropertyName) {
642
+ var arrayBracketsRegEx = new RegExp("\\[(\\d+)\\]", "gi");
643
+ return indicesOfWithRegex(fullPropertyName, arrayBracketsRegEx);
644
+ }
667
645
  /**
668
- * Adds entries to the given group. If the group does not exist, it will be created.
669
- * @param {String} groupName
670
- * @param {module:datarestructor.DescribedEntry[]} describedEntries
671
- */
672
- this.addGroupEntries = function (groupName, describedEntries) {
673
- if (!this[groupName]) {
674
- this.groupNames.push(groupName);
675
- this[groupName] = [];
676
- }
677
- var index;
678
- var describedEntry;
679
- for (index = 0; index < describedEntries.length; index += 1) {
680
- describedEntry = describedEntries[index];
681
- this[groupName].push(describedEntry);
682
- }
683
- };
684
- }
685
- /**
686
- * @typedef {Object} module:datarestructor.ExtractedIndices
687
- * @property {string} pointDelimited - bracket indices separated by points
688
- * @property {number[]} numberArray as array of numbers
689
- */
690
- /**
691
- * Returns "1.12.123" and [1,12,123] for "results[1].hits.hits[12].aggregates[123]".
692
- *
693
- * @param {String} fullPropertyName
694
- * @return {module:datarestructor.ExtractedIndices} extracted indices in different representations
695
- * @protected
696
- * @memberof module:datarestructor.DescribedEntryCreator
697
- */
698
- function indicesOf(fullPropertyName) {
699
- var arrayBracketsRegEx = new RegExp("\\[(\\d+)\\]", "gi");
700
- return indicesOfWithRegex(fullPropertyName, arrayBracketsRegEx);
701
- }
702
- /**
703
- * Returns "1.12.123" and [1,12,123] for "results[1].hits.hits[12].aggregates[123]".
704
- *
705
- * @param {string} fullPropertyName
706
- * @param {RegExp} regexWithOneNumberGroup
707
- * @return {module:datarestructor.ExtractedIndices} extracted indices in different representations
708
- * @protected
709
- * @memberof module:datarestructor.DescribedEntryCreator
710
- */
711
- function indicesOfWithRegex(fullPropertyName, regexWithOneNumberGroup) {
712
- var pointDelimited = "";
713
- var numberArray = [];
714
- var match;
715
- do {
716
- match = regexWithOneNumberGroup.exec(fullPropertyName);
717
- if (match) {
718
- if (pointDelimited.length > 0) {
719
- pointDelimited += ".";
720
- }
721
- pointDelimited += match[1];
722
- numberArray.push(parseInt(match[1]));
723
- }
724
- } while (match);
725
- return {
726
- pointDelimited: pointDelimited,
727
- numberArray: numberArray
728
- };
729
- }
730
- return DescribedEntry;
731
- })();
646
+ * Returns "1.12.123" and [1,12,123] for "results[1].hits.hits[12].aggregates[123]".
647
+ *
648
+ * @param {string} fullPropertyName
649
+ * @param {RegExp} regexWithOneNumberGroup
650
+ * @return {module:datarestructor.ExtractedIndices} extracted indices in different representations
651
+ * @protected
652
+ * @memberof module:datarestructor.DescribedEntryCreator
653
+ */ function indicesOfWithRegex(fullPropertyName, regexWithOneNumberGroup) {
654
+ var pointDelimited = "";
655
+ var numberArray = [];
656
+ var match;
657
+ do {
658
+ match = regexWithOneNumberGroup.exec(fullPropertyName);
659
+ if (match) {
660
+ if (pointDelimited.length > 0) pointDelimited += ".";
661
+ pointDelimited += match[1];
662
+ numberArray.push(parseInt(match[1]));
663
+ }
664
+ }while (match);
665
+ return {
666
+ pointDelimited: pointDelimited,
667
+ numberArray: numberArray
668
+ };
669
+ }
670
+ return DescribedEntry;
671
+ }();
732
672
  /**
733
- * @typedef {Object} module:datarestructor.TransformConfig
734
- * @property {boolean} debugMode enables/disables detailed logging
735
- * @property {number} [maxRecursionDepth=8] Maximum recursion depth
736
- * @property {number} [removeDuplicationAboveRecursionDepth=1] Duplications will be removed above the given recursion depth value and remain unchanged below it.
737
- */
738
- datarestructor.Transform = (function () {
739
- "use strict";
740
- /**
741
- * Main class for the data transformation.
742
- * @param {module:datarestructor.PropertyStructureDescription[]} descriptions
743
- * @constructs Transform
744
- * @alias module:datarestructor.Transform
745
- */
746
- function Transform(descriptions) {
747
- /**
748
- * Descriptions of the input data that define the behaviour of the transformation.
749
- * @type {module:datarestructor.DescribedEntry[]}
750
- */
751
- this.descriptions = descriptions;
752
- /**
753
- * Configuration for the transformation.
754
- * @protected
755
- * @type {module:datarestructor.TransformConfig}
756
- */
757
- this.config = {
758
- /**
759
- * Debug mode switch, that enables/disables detailed logging.
760
- * @protected
761
- * @type {boolean}
762
- */
763
- debugMode: false,
764
- /**
765
- * Maximum recursion depth. Defaults to 8.
766
- * @protected
767
- * @type {number}
768
- */
769
- maxRecursionDepth: 8,
770
- /**
771
- * Duplications will be removed above the given recursion depth and remain below it.
772
- * Defaults to 1.
773
- *
774
- * Since fields can contain groups of fields that can contain groups of fields..., cyclic
775
- * data structures are possible by nature and will lead to duplications. Some of them
776
- * might be intended e.g. to take one (sub-)field with all (duplicated) groups.
777
- * To restrict duplications and improve performance it is beneficial to define a
778
- * recursion depth, above which further duplication won't be used and should be removed/avoided.
779
- *
780
- * @protected
781
- * @type {number}
782
- */
783
- removeDuplicationAboveRecursionDepth: 1
784
- };
785
- /**
786
- * Enables debug mode. Logs additional information.
787
- * @returns {module:datarestructor.Transform}
788
- */
789
- this.enableDebugMode = function () {
790
- this.config.debugMode = true;
791
- return this;
792
- };
673
+ * @typedef {Object} module:datarestructor.TransformConfig
674
+ * @property {boolean} debugMode enables/disables detailed logging
675
+ * @property {number} [maxRecursionDepth=8] Maximum recursion depth
676
+ * @property {number} [removeDuplicationAboveRecursionDepth=1] Duplications will be removed above the given recursion depth value and remain unchanged below it.
677
+ */ datarestructor.Transform = function() {
678
+ "use strict";
793
679
  /**
794
- * Sets the maximum recursion depth. Defaults to 8 if not set.
795
- * @param {number} value non negative number.
796
- * @returns {module:datarestructor.Transform}
797
- */
798
- this.setMaxRecursionDepth = function (value) {
799
- if (typeof value !== "number" || value < 0) {
800
- throw "Invalid max recursion depth value: " + value;
801
- }
802
- this.config.maxRecursionDepth = value;
803
- return this;
804
- };
805
- /**
806
- * Sets the recursion depth above which duplication will be removed. Duplications below it remain unchanged.
807
- * Defaults to 1.
808
- *
809
- * Since fields can contain groups of fields that can contain groups of fields..., cyclic
810
- * data structures are possible by nature and will lead to duplications. Some of them
811
- * might be intended e.g. to take one (sub-)field with all (duplicated) groups.
812
- * To restrict duplications and improve performance it is beneficial to define a
813
- * recursion depth, above which further duplication won't be used and should be removed/avoided.
814
- *
815
- * @param {number} value non negative number.
816
- * @returns {module:datarestructor.Transform}
817
- */
818
- this.setRemoveDuplicationAboveRecursionDepth = function (value) {
819
- if (typeof value !== "number" || value < 0) {
820
- throw "Invalid remove duplications above recursion depth value: " + value;
821
- }
822
- this.config.removeDuplicationAboveRecursionDepth = value;
823
- return this;
824
- };
825
- /**
826
- * "Assembly line", that takes the (pared JSON) data and processes it using all given descriptions in their given order.
827
- * @param {object} data - parsed JSON data or any other data object
828
- * @returns {module:datarestructor.DescribedEntry[]}
829
- * @example
830
- * var allDescriptions = [];
831
- * allDescriptions.push(summariesDescription());
832
- * allDescriptions.push(detailsDescription());
833
- * var result = new datarestructor.Transform(allDescriptions).processJson(jsonData);
834
- */
835
- this.processJson = function (data) {
836
- return processJsonUsingDescriptions(data, this.descriptions, this.config);
837
- };
838
- }
839
- /**
840
- * "Assembly line", that takes the jsonData and processes it using all given descriptions in their given order.
841
- * @param {object} jsonData parsed JSON data or any other data object
842
- * @param {module:datarestructor.PropertyStructureDescription[]} descriptions - already grouped entries
843
- * @param {module:datarestructor.TransformConfig} config configuration for the data transformation
844
- * @returns {module:datarestructor.DescribedEntry[]}
845
- * @protected
846
- * @memberof module:datarestructor.Transform
847
- */
848
- function processJsonUsingDescriptions(jsonData, descriptions, config) {
849
- // "Flatten" the hierarchical input json to an array of property names (point separated "folders") and values.
850
- var processedData = internal_object_tools.flattenToArray(jsonData);
851
- // Fill in properties ending with the name "_comma_separated_values" for array values to make it easier to display them.
852
- processedData = fillInArrayValues(processedData);
853
- if (config.debugMode) {
854
- console.log("flattened data with array values:");
855
- console.log(processedData);
856
- }
857
- // Mark, identify and harmonize the flattened data by applying one description after another in their given order.
858
- var describedData = [];
859
- var descriptionIndex, description, dataWithDescription;
860
- for (descriptionIndex = 0; descriptionIndex < descriptions.length; descriptionIndex += 1) {
861
- description = descriptions[descriptionIndex];
862
- // Filter all entries that match the current description and enrich them with it
863
- dataWithDescription = extractEntriesByDescription(processedData, description);
864
- // Remove duplicate entries where a deduplicationPattern is described
865
- describedData = deduplicateFlattenedData(describedData, dataWithDescription);
680
+ * Main class for the data transformation.
681
+ * @param {module:datarestructor.PropertyStructureDescription[]} descriptions
682
+ * @constructs Transform
683
+ * @alias module:datarestructor.Transform
684
+ */ function Transform(descriptions) {
685
+ /**
686
+ * Descriptions of the input data that define the behaviour of the transformation.
687
+ * @type {module:datarestructor.DescribedEntry[]}
688
+ */ this.descriptions = descriptions;
689
+ /**
690
+ * Configuration for the transformation.
691
+ * @protected
692
+ * @type {module:datarestructor.TransformConfig}
693
+ */ this.config = {
694
+ /**
695
+ * Debug mode switch, that enables/disables detailed logging.
696
+ * @protected
697
+ * @type {boolean}
698
+ */ debugMode: false,
699
+ /**
700
+ * Maximum recursion depth. Defaults to 8.
701
+ * @protected
702
+ * @type {number}
703
+ */ maxRecursionDepth: 8,
704
+ /**
705
+ * Duplications will be removed above the given recursion depth and remain below it.
706
+ * Defaults to 1.
707
+ *
708
+ * Since fields can contain groups of fields that can contain groups of fields..., cyclic
709
+ * data structures are possible by nature and will lead to duplications. Some of them
710
+ * might be intended e.g. to take one (sub-)field with all (duplicated) groups.
711
+ * To restrict duplications and improve performance it is beneficial to define a
712
+ * recursion depth, above which further duplication won't be used and should be removed/avoided.
713
+ *
714
+ * @protected
715
+ * @type {number}
716
+ */ removeDuplicationAboveRecursionDepth: 1
717
+ };
718
+ /**
719
+ * Enables debug mode. Logs additional information.
720
+ * @returns {module:datarestructor.Transform}
721
+ */ this.enableDebugMode = function() {
722
+ this.config.debugMode = true;
723
+ return this;
724
+ };
725
+ /**
726
+ * Sets the maximum recursion depth. Defaults to 8 if not set.
727
+ * @param {number} value non negative number.
728
+ * @returns {module:datarestructor.Transform}
729
+ */ this.setMaxRecursionDepth = function(value) {
730
+ if (typeof value !== "number" || value < 0) throw "Invalid max recursion depth value: " + value;
731
+ this.config.maxRecursionDepth = value;
732
+ return this;
733
+ };
734
+ /**
735
+ * Sets the recursion depth above which duplication will be removed. Duplications below it remain unchanged.
736
+ * Defaults to 1.
737
+ *
738
+ * Since fields can contain groups of fields that can contain groups of fields..., cyclic
739
+ * data structures are possible by nature and will lead to duplications. Some of them
740
+ * might be intended e.g. to take one (sub-)field with all (duplicated) groups.
741
+ * To restrict duplications and improve performance it is beneficial to define a
742
+ * recursion depth, above which further duplication won't be used and should be removed/avoided.
743
+ *
744
+ * @param {number} value non negative number.
745
+ * @returns {module:datarestructor.Transform}
746
+ */ this.setRemoveDuplicationAboveRecursionDepth = function(value) {
747
+ if (typeof value !== "number" || value < 0) throw "Invalid remove duplications above recursion depth value: " + value;
748
+ this.config.removeDuplicationAboveRecursionDepth = value;
749
+ return this;
750
+ };
751
+ /**
752
+ * "Assembly line", that takes the (pared JSON) data and processes it using all given descriptions in their given order.
753
+ * @param {object} data - parsed JSON data or any other data object
754
+ * @returns {module:datarestructor.DescribedEntry[]}
755
+ * @example
756
+ * var allDescriptions = [];
757
+ * allDescriptions.push(summariesDescription());
758
+ * allDescriptions.push(detailsDescription());
759
+ * var result = new datarestructor.Transform(allDescriptions).processJson(jsonData);
760
+ */ this.processJson = function(data) {
761
+ return processJsonUsingDescriptions(data, this.descriptions, this.config);
762
+ };
866
763
  }
867
- processedData = describedData;
868
- if (config.debugMode) {
869
- console.log("describedData data:");
870
- console.log(processedData);
871
- }
872
- // Group entries where a groupPattern is described
873
- processedData = groupFlattenedData(processedData);
874
- if (config.debugMode) {
875
- console.log("grouped describedData data:");
876
- console.log(processedData);
877
- }
878
- // Move group entries where a groupDestinationPattern is described
879
- processedData = applyGroupDestinationPattern(processedData);
880
- if (config.debugMode) {
881
- console.log("moved grouped describedData data:");
882
- console.log(processedData);
764
+ /**
765
+ * "Assembly line", that takes the jsonData and processes it using all given descriptions in their given order.
766
+ * @param {object} jsonData parsed JSON data or any other data object
767
+ * @param {module:datarestructor.PropertyStructureDescription[]} descriptions - already grouped entries
768
+ * @param {module:datarestructor.TransformConfig} config configuration for the data transformation
769
+ * @returns {module:datarestructor.DescribedEntry[]}
770
+ * @protected
771
+ * @memberof module:datarestructor.Transform
772
+ */ function processJsonUsingDescriptions(jsonData, descriptions, config) {
773
+ // "Flatten" the hierarchical input json to an array of property names (point separated "folders") and values.
774
+ var processedData = internal_object_tools.flattenToArray(jsonData);
775
+ // Fill in properties ending with the name "_comma_separated_values" for array values to make it easier to display them.
776
+ processedData = fillInArrayValues(processedData);
777
+ if (config.debugMode) {
778
+ console.log("flattened data with array values:");
779
+ console.log(processedData);
780
+ }
781
+ // Mark, identify and harmonize the flattened data by applying one description after another in their given order.
782
+ var describedData = [];
783
+ var descriptionIndex, description, dataWithDescription;
784
+ for(descriptionIndex = 0; descriptionIndex < descriptions.length; descriptionIndex += 1){
785
+ description = descriptions[descriptionIndex];
786
+ // Filter all entries that match the current description and enrich them with it
787
+ dataWithDescription = extractEntriesByDescription(processedData, description);
788
+ // Remove duplicate entries where a deduplicationPattern is described
789
+ describedData = deduplicateFlattenedData(describedData, dataWithDescription);
790
+ }
791
+ processedData = describedData;
792
+ if (config.debugMode) {
793
+ console.log("describedData data:");
794
+ console.log(processedData);
795
+ }
796
+ // Group entries where a groupPattern is described
797
+ processedData = groupFlattenedData(processedData);
798
+ if (config.debugMode) {
799
+ console.log("grouped describedData data:");
800
+ console.log(processedData);
801
+ }
802
+ // Move group entries where a groupDestinationPattern is described
803
+ processedData = applyGroupDestinationPattern(processedData);
804
+ if (config.debugMode) {
805
+ console.log("moved grouped describedData data:");
806
+ console.log(processedData);
807
+ }
808
+ // Turns the grouped object back into an array of DescribedEntry-Objects
809
+ processedData = propertiesAsArray(processedData);
810
+ // Converts the internal described entries into described fields
811
+ processedData = toDescribedFields(processedData, config);
812
+ if (config.debugMode) {
813
+ console.log("transformed result:");
814
+ console.log(processedData);
815
+ }
816
+ return processedData;
883
817
  }
884
- // Turns the grouped object back into an array of DescribedEntry-Objects
885
- processedData = propertiesAsArray(processedData);
886
- // Converts the internal described entries into described fields
887
- processedData = toDescribedFields(processedData, config);
888
- if (config.debugMode) {
889
- console.log("transformed result:");
890
- console.log(processedData);
818
+ /**
819
+ * Takes two arrays of objects, e.g. [{id: B, value: 2},{id: C, value: 3}]
820
+ * and [{id: A, value: 1},{id: B, value: 4}] and merges them into one:
821
+ * [{id: C, value: 3},{id: A, value: 1},{id: B, value: 4}]
822
+ *
823
+ * Entries with the same id ("duplicates") will be overwritten.
824
+ * Only the last element with the same id remains. The order is
825
+ * determined by the order of the array elements, whereas the first
826
+ * array comes before the second one. This means, that entries with the
827
+ * same id in the second array overwrite entries in the first array,
828
+ * and entries that occur later in the array overwrite earlier ones,
829
+ * if they have the same id.
830
+ *
831
+ * The id is extracted from every element using the given function.
832
+ *
833
+ * @param {module:datarestructor.DescribedEntry[]} entries
834
+ * @param {module:datarestructor.DescribedEntry[]} entriesToMerge
835
+ * @param {module:datarestructor.stringFieldOfDescribedEntryFunction} idOfElementFunction returns the id of an DescribedEntry
836
+ * @protected
837
+ * @memberof module:datarestructor.Transform
838
+ */ function mergeFlattenedData(entries, entriesToMerge, idOfElementFunction) {
839
+ var entriesToMergeById = asIdBasedObject(entriesToMerge, idOfElementFunction);
840
+ var merged = [];
841
+ var index, entry, id;
842
+ for(index = 0; index < entries.length; index += 1){
843
+ entry = entries[index];
844
+ id = idOfElementFunction(entry);
845
+ if (id == null || id === "" || entriesToMergeById[id] == null) merged.push(entry);
846
+ }
847
+ for(index = 0; index < entriesToMerge.length; index += 1){
848
+ entry = entriesToMerge[index];
849
+ merged.push(entry);
850
+ }
851
+ return merged;
891
852
  }
892
- return processedData;
893
- }
894
- /**
895
- * Takes two arrays of objects, e.g. [{id: B, value: 2},{id: C, value: 3}]
896
- * and [{id: A, value: 1},{id: B, value: 4}] and merges them into one:
897
- * [{id: C, value: 3},{id: A, value: 1},{id: B, value: 4}]
898
- *
899
- * Entries with the same id ("duplicates") will be overwritten.
900
- * Only the last element with the same id remains. The order is
901
- * determined by the order of the array elements, whereas the first
902
- * array comes before the second one. This means, that entries with the
903
- * same id in the second array overwrite entries in the first array,
904
- * and entries that occur later in the array overwrite earlier ones,
905
- * if they have the same id.
906
- *
907
- * The id is extracted from every element using the given function.
908
- *
909
- * @param {module:datarestructor.DescribedEntry[]} entries
910
- * @param {module:datarestructor.DescribedEntry[]} entriesToMerge
911
- * @param {module:datarestructor.stringFieldOfDescribedEntryFunction} idOfElementFunction returns the id of an DescribedEntry
912
- * @protected
913
- * @memberof module:datarestructor.Transform
914
- */
915
- function mergeFlattenedData(entries, entriesToMerge, idOfElementFunction) {
916
- var entriesToMergeById = asIdBasedObject(entriesToMerge, idOfElementFunction);
917
- var merged = [];
918
- var index, entry, id;
919
- for (index = 0; index < entries.length; index += 1) {
920
- entry = entries[index];
921
- id = idOfElementFunction(entry);
922
- if (id == null || id === "" || entriesToMergeById[id] == null) {
923
- merged.push(entry);
924
- }
853
+ /**
854
+ * Takes two arrays of objects, e.g. [{id: B, value: 2},{id: C, value: 3}]
855
+ * and [{id: A, value: 1},{id: B, value: 4}] and merges them into one:
856
+ * [{id: C, value: 3},{id: A, value: 1},{id: B, value: 4}]
857
+ *
858
+ * Entries with the same id ("duplicates") will be overwritten.
859
+ * Only the last element with the same id remains. The order is
860
+ * determined by the order of the array elements, whereas the first
861
+ * array comes before the second one. This means, that entries with the
862
+ * same id in the second array overwrite entries in the first array,
863
+ * and entries occurring later in the array overwrite earlier ones,
864
+ * if they have the same id.
865
+ *
866
+ * "entriesToMerge" will be returned directly, if "entries" is null or empty.
867
+ *
868
+ * The id is extracted from every element using their deduplication pattern (if available).
869
+ *
870
+ * @param {module:datarestructor.DescribedEntry[]} entries
871
+ * @param {module:datarestructor.DescribedEntry[]} entriesToMerge
872
+ * @param {module:datarestructor.stringFieldOfDescribedEntryFunction} idOfElementFunction returns the id of an DescribedEntry
873
+ * @see mergeFlattenedData
874
+ * @protected
875
+ * @memberof module:datarestructor.Transform
876
+ */ function deduplicateFlattenedData(entries, entriesToMerge) {
877
+ if (entries == null || entries.length == 0) return entriesToMerge;
878
+ var idOfElementFunction = function(entry) {
879
+ return entry._identifier.deduplicationId;
880
+ };
881
+ return mergeFlattenedData(entries, entriesToMerge, idOfElementFunction);
925
882
  }
926
- for (index = 0; index < entriesToMerge.length; index += 1) {
927
- entry = entriesToMerge[index];
928
- merged.push(entry);
883
+ /**
884
+ * Converts the given elements to an object, that provides these
885
+ * entries by their id. For example, [{id: A, value: 1}] becomes
886
+ * result['A'] = 1.
887
+ * @param {module:datarestructor.DescribedEntry[]} elements of DescribedEntry elements
888
+ * @param {module:datarestructor.stringFieldOfDescribedEntryFunction} idOfElementFunction returns the id of an DescribedEntry
889
+ * @return {module:datarestructor.DescribedEntry[] entries indexed by id
890
+ * @protected
891
+ * @memberof module:datarestructor.Transform
892
+ */ function asIdBasedObject(elements, idOfElementFunction) {
893
+ var idIndexedObject = new Object();
894
+ for(var index = 0; index < elements.length; index++){
895
+ var element = elements[index];
896
+ idIndexedObject[idOfElementFunction(element)] = element;
897
+ }
898
+ return idIndexedObject;
929
899
  }
930
- return merged;
931
- }
932
- /**
933
- * Takes two arrays of objects, e.g. [{id: B, value: 2},{id: C, value: 3}]
934
- * and [{id: A, value: 1},{id: B, value: 4}] and merges them into one:
935
- * [{id: C, value: 3},{id: A, value: 1},{id: B, value: 4}]
936
- *
937
- * Entries with the same id ("duplicates") will be overwritten.
938
- * Only the last element with the same id remains. The order is
939
- * determined by the order of the array elements, whereas the first
940
- * array comes before the second one. This means, that entries with the
941
- * same id in the second array overwrite entries in the first array,
942
- * and entries occurring later in the array overwrite earlier ones,
943
- * if they have the same id.
944
- *
945
- * "entriesToMerge" will be returned directly, if "entries" is null or empty.
946
- *
947
- * The id is extracted from every element using their deduplication pattern (if available).
948
- *
949
- * @param {module:datarestructor.DescribedEntry[]} entries
950
- * @param {module:datarestructor.DescribedEntry[]} entriesToMerge
951
- * @param {module:datarestructor.stringFieldOfDescribedEntryFunction} idOfElementFunction returns the id of an DescribedEntry
952
- * @see mergeFlattenedData
953
- * @protected
954
- * @memberof module:datarestructor.Transform
955
- */
956
- function deduplicateFlattenedData(entries, entriesToMerge) {
957
- if (entries == null || entries.length == 0) {
958
- return entriesToMerge;
900
+ /**
901
+ * Converts the given elements into an object, that provides these
902
+ * entries by their id (determined by the entry's groupPattern).
903
+ * For example, [{id: A, value: 1}] becomes result['A'] = 1.
904
+ *
905
+ * Furthermore, this function creates a group property (determined by the entry's groupName)
906
+ * and collects all related elements (specified by their group pattern) in it.
907
+ *
908
+ * @param {module:datarestructor.DescribedEntry[]} elements of DescribedEntry elements
909
+ * @return {module:datarestructor.DescribedEntry[] entries indexed by id
910
+ * @protected
911
+ * @memberof module:datarestructor.Transform
912
+ */ function groupFlattenedData(flattenedData) {
913
+ return groupById(flattenedData, function(entry) {
914
+ return entry._identifier.groupId;
915
+ }, function(entry) {
916
+ return entry._description.groupName;
917
+ });
959
918
  }
960
- var idOfElementFunction = function (entry) {
961
- return entry._identifier.deduplicationId;
962
- };
963
- return mergeFlattenedData(entries, entriesToMerge, idOfElementFunction);
964
- }
965
- /**
966
- * Converts the given elements to an object, that provides these
967
- * entries by their id. For example, [{id: A, value: 1}] becomes
968
- * result['A'] = 1.
969
- * @param {module:datarestructor.DescribedEntry[]} elements of DescribedEntry elements
970
- * @param {module:datarestructor.stringFieldOfDescribedEntryFunction} idOfElementFunction returns the id of an DescribedEntry
971
- * @return {module:datarestructor.DescribedEntry[] entries indexed by id
972
- * @protected
973
- * @memberof module:datarestructor.Transform
974
- */
975
- function asIdBasedObject(elements, idOfElementFunction) {
976
- var idIndexedObject = new Object();
977
- for (var index = 0; index < elements.length; index++) {
978
- var element = elements[index];
979
- idIndexedObject[idOfElementFunction(element)] = element;
919
+ /**
920
+ * Converts the given elements into an object, that provides these
921
+ * entries by their id. For example, [{id: A, value: 1}] becomes
922
+ * result['A'] = 1. Furthermore, this function creates a group property (with the name )
923
+ * and collects all related elements (specified by their group pattern) in it.
924
+ *
925
+ * @param {module:datarestructor.DescribedEntry[]} elements of DescribedEntry elements
926
+ * @param {module:datarestructor.stringFieldOfDescribedEntryFunction} groupNameOfElementFunction function, that returns the name of the group property that will be created inside the "main" element.
927
+ * @param {module:datarestructor.stringFieldOfDescribedEntryFunction} groupIdOfElementFunction returns the group id of an DescribedEntry
928
+ * @return {module:datarestructor.DescribedEntry[] entries indexed by id
929
+ * @protected
930
+ * @memberof module:datarestructor.Transform
931
+ */ function groupById(elements, groupIdOfElementFunction, groupNameOfElementFunction) {
932
+ var groupedResult = new Object();
933
+ for(var index = 0; index < elements.length; index++){
934
+ var element = elements[index];
935
+ var groupId = groupIdOfElementFunction(element);
936
+ if (groupId === "") continue;
937
+ var groupName = groupNameOfElementFunction(element);
938
+ if (groupName == null || groupName === "") continue;
939
+ if (!groupedResult[groupId]) groupedResult[groupId] = element;
940
+ groupedResult[groupId].addGroupEntry(groupName, element);
941
+ }
942
+ return groupedResult;
980
943
  }
981
- return idIndexedObject;
982
- }
983
- /**
984
- * Converts the given elements into an object, that provides these
985
- * entries by their id (determined by the entry's groupPattern).
986
- * For example, [{id: A, value: 1}] becomes result['A'] = 1.
987
- *
988
- * Furthermore, this function creates a group property (determined by the entry's groupName)
989
- * and collects all related elements (specified by their group pattern) in it.
990
- *
991
- * @param {module:datarestructor.DescribedEntry[]} elements of DescribedEntry elements
992
- * @return {module:datarestructor.DescribedEntry[] entries indexed by id
993
- * @protected
994
- * @memberof module:datarestructor.Transform
995
- */
996
- function groupFlattenedData(flattenedData) {
997
- return groupById(flattenedData, function (entry) {
998
- return entry._identifier.groupId;
999
- }, function (entry) {
1000
- return entry._description.groupName;
1001
- });
1002
- }
1003
- /**
1004
- * Converts the given elements into an object, that provides these
1005
- * entries by their id. For example, [{id: A, value: 1}] becomes
1006
- * result['A'] = 1. Furthermore, this function creates a group property (with the name )
1007
- * and collects all related elements (specified by their group pattern) in it.
1008
- *
1009
- * @param {module:datarestructor.DescribedEntry[]} elements of DescribedEntry elements
1010
- * @param {module:datarestructor.stringFieldOfDescribedEntryFunction} groupNameOfElementFunction function, that returns the name of the group property that will be created inside the "main" element.
1011
- * @param {module:datarestructor.stringFieldOfDescribedEntryFunction} groupIdOfElementFunction returns the group id of an DescribedEntry
1012
- * @return {module:datarestructor.DescribedEntry[] entries indexed by id
1013
- * @protected
1014
- * @memberof module:datarestructor.Transform
1015
- */
1016
- function groupById(elements, groupIdOfElementFunction, groupNameOfElementFunction) {
1017
- var groupedResult = new Object();
1018
- for (var index = 0; index < elements.length; index++) {
1019
- var element = elements[index];
1020
- var groupId = groupIdOfElementFunction(element);
1021
- if (groupId === "") {
1022
- continue;
1023
- }
1024
- var groupName = groupNameOfElementFunction(element);
1025
- if (groupName == null || groupName === "") {
1026
- continue;
1027
- }
1028
- if (!groupedResult[groupId]) {
1029
- groupedResult[groupId] = element;
1030
- }
1031
- groupedResult[groupId].addGroupEntry(groupName, element);
944
+ /**
945
+ * Extracts entries out of "flattened" JSON data and provides an array of objects.
946
+ * @param {Object[]} flattenedData - flattened json from search query result
947
+ * @param {string} flattenedData[].name - name of the property in hierarchical order separated by points
948
+ * @param {string} flattenedData[].value - value of the property as string
949
+ * @param {module:datarestructor.PropertyStructureDescription} - description of structure of the entries that should be extracted
950
+ * @return {module:datarestructor.DescribedEntry[]}
951
+ * @protected
952
+ * @memberof module:datarestructor.Transform
953
+ */ function extractEntriesByDescription(flattenedData, description) {
954
+ var removeArrayBracketsRegEx = new RegExp("\\[\\d+\\]", "gi");
955
+ var filtered = [];
956
+ flattenedData.filter(function(entry) {
957
+ var propertyNameWithoutArrayIndices = entry.name.replace(removeArrayBracketsRegEx, "");
958
+ if (description.matchesPropertyName(propertyNameWithoutArrayIndices)) {
959
+ var describedEntry = new datarestructor.DescribedEntryCreator(entry, description);
960
+ if (describedEntry._isMatchingIndex) filtered.push(describedEntry);
961
+ }
962
+ });
963
+ return filtered;
1032
964
  }
1033
- return groupedResult;
1034
- }
1035
- /**
1036
- * Extracts entries out of "flattened" JSON data and provides an array of objects.
1037
- * @param {Object[]} flattenedData - flattened json from search query result
1038
- * @param {string} flattenedData[].name - name of the property in hierarchical order separated by points
1039
- * @param {string} flattenedData[].value - value of the property as string
1040
- * @param {module:datarestructor.PropertyStructureDescription} - description of structure of the entries that should be extracted
1041
- * @return {module:datarestructor.DescribedEntry[]}
1042
- * @protected
1043
- * @memberof module:datarestructor.Transform
1044
- */
1045
- function extractEntriesByDescription(flattenedData, description) {
1046
- var removeArrayBracketsRegEx = new RegExp("\\[\\d+\\]", "gi");
1047
- var filtered = [];
1048
- flattenedData.filter(function (entry) {
1049
- var propertyNameWithoutArrayIndices = entry.name.replace(removeArrayBracketsRegEx, "");
1050
- if (description.matchesPropertyName(propertyNameWithoutArrayIndices)) {
1051
- var describedEntry = new datarestructor.DescribedEntryCreator(entry, description);
1052
- if (describedEntry._isMatchingIndex) {
1053
- filtered.push(describedEntry);
965
+ /**
966
+ * Takes already grouped {@link module:datarestructor.DescribedEntry} objects and
967
+ * uses their "_identifier.groupDestinationId" (if exists)
968
+ * to move groups to the given destination.
969
+ *
970
+ * This is useful, if separately described groups like "summary" and "detail" should be put together,
971
+ * so that every summery contains a group with the regarding details.
972
+ *
973
+ * @param {module:datarestructor.DescribedEntry[]} groupedObject - already grouped entries
974
+ * @return {module:datarestructor.DescribedEntry[]}
975
+ * @protected
976
+ * @memberof module:datarestructor.Transform
977
+ */ function applyGroupDestinationPattern(groupedObject) {
978
+ var keys = Object.keys(groupedObject);
979
+ var keysToDelete = [];
980
+ for(var index = 0; index < keys.length; index++){
981
+ var key = keys[index];
982
+ var entry = groupedObject[key];
983
+ if (entry._description.groupDestinationPattern != "") {
984
+ var destinationKey = entry._identifier.groupDestinationId;
985
+ if (groupedObject[destinationKey] != null) {
986
+ var newGroup = entry[entry._description.groupName];
987
+ groupedObject[destinationKey].addGroupEntries(entry._description.groupDestinationName, newGroup);
988
+ keysToDelete.push(key);
989
+ }
990
+ }
1054
991
  }
1055
- }
1056
- });
1057
- return filtered;
1058
- }
1059
- /**
1060
- * Takes already grouped {@link module:datarestructor.DescribedEntry} objects and
1061
- * uses their "_identifier.groupDestinationId" (if exists)
1062
- * to move groups to the given destination.
1063
- *
1064
- * This is useful, if separately described groups like "summary" and "detail" should be put together,
1065
- * so that every summery contains a group with the regarding details.
1066
- *
1067
- * @param {module:datarestructor.DescribedEntry[]} groupedObject - already grouped entries
1068
- * @return {module:datarestructor.DescribedEntry[]}
1069
- * @protected
1070
- * @memberof module:datarestructor.Transform
1071
- */
1072
- function applyGroupDestinationPattern(groupedObject) {
1073
- var keys = Object.keys(groupedObject);
1074
- var keysToDelete = [];
1075
- for (var index = 0; index < keys.length; index++) {
1076
- var key = keys[index];
1077
- var entry = groupedObject[key];
1078
- if (entry._description.groupDestinationPattern != "") {
1079
- var destinationKey = entry._identifier.groupDestinationId;
1080
- if (groupedObject[destinationKey] != null) {
1081
- var newGroup = entry[entry._description.groupName];
1082
- groupedObject[destinationKey].addGroupEntries(entry._description.groupDestinationName, newGroup);
1083
- keysToDelete.push(key);
992
+ // delete all moved entries that had been collected by their key
993
+ for(index = 0; index < keysToDelete.length; index += 1){
994
+ var keyToDelete = keysToDelete[index];
995
+ delete groupedObject[keyToDelete];
1084
996
  }
1085
- }
997
+ return groupedObject;
1086
998
  }
1087
- // delete all moved entries that had been collected by their key
1088
- for (index = 0; index < keysToDelete.length; index += 1) {
1089
- var keyToDelete = keysToDelete[index];
1090
- delete groupedObject[keyToDelete];
999
+ /**
1000
+ * Fills in extra "_comma_separated_values" properties into the flattened data
1001
+ * for properties that end with an array. E.g. response.hits.hits.tags[0]="active" and response.hits.hits.tags[0]="ready"
1002
+ * will lead to the extra element "response.hits.hits.tags_comma_separated_values="active, ready".
1003
+ *
1004
+ * @return flattened data with filled in "_comma_separated_values" properties
1005
+ * @protected
1006
+ * @memberof module:datarestructor.Transform
1007
+ */ function fillInArrayValues(flattenedData) {
1008
+ var trailingArrayIndexRegEx = new RegExp("\\[\\d+\\]$", "gi");
1009
+ var result = [];
1010
+ var lastArrayProperty = "";
1011
+ var lastArrayPropertyValue = "";
1012
+ flattenedData.filter(function(entry) {
1013
+ if (!entry.name.match(trailingArrayIndexRegEx)) {
1014
+ if (lastArrayProperty !== "") {
1015
+ result.push({
1016
+ name: lastArrayProperty + "_comma_separated_values",
1017
+ value: lastArrayPropertyValue
1018
+ });
1019
+ lastArrayProperty = "";
1020
+ }
1021
+ result.push(entry);
1022
+ return;
1023
+ }
1024
+ var propertyNameWithoutTrailingArrayIndex = entry.name.replace(trailingArrayIndexRegEx, "");
1025
+ if (lastArrayProperty === propertyNameWithoutTrailingArrayIndex) lastArrayPropertyValue += ", " + entry.value;
1026
+ else {
1027
+ if (lastArrayProperty !== "") {
1028
+ result.push({
1029
+ name: lastArrayProperty + "_comma_separated_values",
1030
+ value: lastArrayPropertyValue
1031
+ });
1032
+ lastArrayProperty = "";
1033
+ }
1034
+ lastArrayProperty = propertyNameWithoutTrailingArrayIndex;
1035
+ lastArrayPropertyValue = entry.value;
1036
+ }
1037
+ result.push(entry);
1038
+ });
1039
+ return result;
1091
1040
  }
1092
- return groupedObject;
1093
- }
1094
- /**
1095
- * Fills in extra "_comma_separated_values" properties into the flattened data
1096
- * for properties that end with an array. E.g. response.hits.hits.tags[0]="active" and response.hits.hits.tags[0]="ready"
1097
- * will lead to the extra element "response.hits.hits.tags_comma_separated_values="active, ready".
1098
- *
1099
- * @return flattened data with filled in "_comma_separated_values" properties
1100
- * @protected
1101
- * @memberof module:datarestructor.Transform
1102
- */
1103
- function fillInArrayValues(flattenedData) {
1104
- var trailingArrayIndexRegEx = new RegExp("\\[\\d+\\]$", "gi");
1105
- var result = [];
1106
- var lastArrayProperty = "";
1107
- var lastArrayPropertyValue = "";
1108
- flattenedData.filter(function (entry) {
1109
- if (!entry.name.match(trailingArrayIndexRegEx)) {
1110
- if (lastArrayProperty !== "") {
1111
- result.push({
1112
- name: lastArrayProperty + "_comma_separated_values",
1113
- value: lastArrayPropertyValue
1114
- });
1115
- lastArrayProperty = "";
1041
+ function propertiesAsArray(groupedData) {
1042
+ var result = [];
1043
+ var propertyNames = Object.keys(groupedData);
1044
+ for(var propertyIndex = 0; propertyIndex < propertyNames.length; propertyIndex++){
1045
+ var propertyName = propertyNames[propertyIndex];
1046
+ var propertyValue = groupedData[propertyName];
1047
+ result.push(propertyValue);
1116
1048
  }
1117
- result.push(entry);
1118
- return;
1119
- }
1120
- var propertyNameWithoutTrailingArrayIndex = entry.name.replace(trailingArrayIndexRegEx, "");
1121
- if (lastArrayProperty === propertyNameWithoutTrailingArrayIndex) {
1122
- lastArrayPropertyValue += ", " + entry.value;
1123
- } else {
1124
- if (lastArrayProperty !== "") {
1125
- result.push({
1126
- name: lastArrayProperty + "_comma_separated_values",
1127
- value: lastArrayPropertyValue
1128
- });
1129
- lastArrayProperty = "";
1049
+ return result;
1050
+ }
1051
+ /**
1052
+ * Converts described entries (internal data structure) to described fields (external data structure).
1053
+ * Since the structure of a described field is hierarchical, every field needs to be converted
1054
+ * in a recursive manner. The maximum recursion depth is taken as the second parameter.
1055
+ * @param {module:datarestructor.DescribedEntry[]} describedEntries
1056
+ * @param {module:datarestructor.TransformConfig} config configuration for the data transformation
1057
+ * @returns {module:described_field.DescribedDataField[]}
1058
+ * @protected
1059
+ * @memberof module:datarestructor.Transform
1060
+ */ function toDescribedFields(describedEntries, config) {
1061
+ var result = [];
1062
+ var index;
1063
+ var describedEntity;
1064
+ for(index = 0; index < describedEntries.length; index += 1){
1065
+ describedEntity = describedEntries[index];
1066
+ result.push(toDescribedField(describedEntity, {
1067
+ recursionDepth: 0,
1068
+ config: config,
1069
+ groupToSkip: ""
1070
+ }));
1130
1071
  }
1131
- lastArrayProperty = propertyNameWithoutTrailingArrayIndex;
1132
- lastArrayPropertyValue = entry.value;
1133
- }
1134
- result.push(entry);
1135
- });
1136
- return result;
1137
- }
1138
- function propertiesAsArray(groupedData) {
1139
- var result = [];
1140
- var propertyNames = Object.keys(groupedData);
1141
- for (var propertyIndex = 0; propertyIndex < propertyNames.length; propertyIndex++) {
1142
- var propertyName = propertyNames[propertyIndex];
1143
- var propertyValue = groupedData[propertyName];
1144
- result.push(propertyValue);
1072
+ return result;
1145
1073
  }
1146
- return result;
1147
- }
1148
- /**
1149
- * Converts described entries (internal data structure) to described fields (external data structure).
1150
- * Since the structure of a described field is hierarchical, every field needs to be converted
1151
- * in a recursive manner. The maximum recursion depth is taken as the second parameter.
1152
- * @param {module:datarestructor.DescribedEntry[]} describedEntries
1153
- * @param {module:datarestructor.TransformConfig} config configuration for the data transformation
1154
- * @returns {module:described_field.DescribedDataField[]}
1155
- * @protected
1156
- * @memberof module:datarestructor.Transform
1157
- */
1158
- function toDescribedFields(describedEntries, config) {
1159
- var result = [];
1160
- var index;
1161
- var describedEntity;
1162
- for (index = 0; index < describedEntries.length; index += 1) {
1163
- describedEntity = describedEntries[index];
1164
- result.push(toDescribedField(describedEntity, {
1165
- recursionDepth: 0,
1166
- config: config,
1167
- groupToSkip: ""
1168
- }));
1074
+ /**
1075
+ * Describes the context type for the recursive DescribedDataField conversion,
1076
+ * that contains everything that needs to be accessible throughout recursion regardless of the
1077
+ * recursion depth.
1078
+ *
1079
+ * @typedef {Object} module:datarestructor.DescribedFieldRecursionContext
1080
+ * @param {number} recursionDepth current recursion depth
1081
+ * @param {String} groupToSkip name of a group to skip or "" when no group should be skipped.
1082
+ * @param {module:datarestructor.TransformConfig} config configuration for the data transformation
1083
+ */ /**
1084
+ * Converts a internal described entry to a newly created public described field.
1085
+ * Since the structure of a described field is hierarchical, this function is called recursively.
1086
+ * Because the internal described entries may very likely contain cyclic references, the depth of recursion
1087
+ * needs to be limited. Therefore, the current recursion depth is taken as second parameter
1088
+ * and the maximum recursion depth is taken as third parameter.
1089
+ * @param {module:datarestructor.DescribedEntry} entry the internal entry that will be converted
1090
+ * @param {module:datarestructor.DescribedFieldRecursionContext} recursionContext context contains everything that needs to be accessible throughout the recursion.
1091
+ * @returns {module:described_field.DescribedDataField}
1092
+ * @protected
1093
+ * @memberof module:datarestructor.Transform
1094
+ */ function toDescribedField(entry, recursionContext) {
1095
+ var field = new described_field.DescribedDataFieldBuilder().category(entry.category).type(entry.type).abbreviation(entry.abbreviation).image(entry.image).index(entry.index).displayName(entry.displayName).fieldName(entry.fieldName).value(entry.value).build();
1096
+ if (recursionContext.recursionDepth > recursionContext.config.maxRecursionDepth) return field;
1097
+ var nextRecursionContext = null;
1098
+ var duplicateGroupNameToSkip = "";
1099
+ var fieldGroups = new described_field.DescribedDataFieldGroup(field);
1100
+ forEachGroupEntry(entry, function(groupName, groupEntry, allGroupEntries) {
1101
+ if (recursionContext.groupToSkip === groupName) {
1102
+ if (recursionContext.config.debugMode) console.log("Removed duplicate group " + groupName + " at recursion depth " + recursionContext.recursionDepth);
1103
+ return;
1104
+ }
1105
+ duplicateGroupNameToSkip = "";
1106
+ if (recursionContext.recursionDepth >= recursionContext.config.removeDuplicationAboveRecursionDepth) duplicateGroupNameToSkip = arraysEqual(groupEntry[groupName], allGroupEntries, describedFieldEqual) ? groupName : "";
1107
+ nextRecursionContext = {
1108
+ recursionDepth: recursionContext.recursionDepth + 1,
1109
+ config: recursionContext.config,
1110
+ groupToSkip: duplicateGroupNameToSkip
1111
+ };
1112
+ fieldGroups.addGroupEntry(groupName, toDescribedField(groupEntry, nextRecursionContext));
1113
+ });
1114
+ return field;
1169
1115
  }
1170
- return result;
1171
- }
1172
- /**
1173
- * Describes the context type for the recursive DescribedDataField conversion,
1174
- * that contains everything that needs to be accessible throughout recursion regardless of the
1175
- * recursion depth.
1176
- *
1177
- * @typedef {Object} module:datarestructor.DescribedFieldRecursionContext
1178
- * @param {number} recursionDepth current recursion depth
1179
- * @param {String} groupToSkip name of a group to skip or "" when no group should be skipped.
1180
- * @param {module:datarestructor.TransformConfig} config configuration for the data transformation
1181
- */
1182
- /**
1183
- * Converts a internal described entry to a newly created public described field.
1184
- * Since the structure of a described field is hierarchical, this function is called recursively.
1185
- * Because the internal described entries may very likely contain cyclic references, the depth of recursion
1186
- * needs to be limited. Therefore, the current recursion depth is taken as second parameter
1187
- * and the maximum recursion depth is taken as third parameter.
1188
- * @param {module:datarestructor.DescribedEntry} entry the internal entry that will be converted
1189
- * @param {module:datarestructor.DescribedFieldRecursionContext} recursionContext context contains everything that needs to be accessible throughout the recursion.
1190
- * @returns {module:described_field.DescribedDataField}
1191
- * @protected
1192
- * @memberof module:datarestructor.Transform
1193
- */
1194
- function toDescribedField(entry, recursionContext) {
1195
- var field = new described_field.DescribedDataFieldBuilder().category(entry.category).type(entry.type).abbreviation(entry.abbreviation).image(entry.image).index(entry.index).displayName(entry.displayName).fieldName(entry.fieldName).value(entry.value).build();
1196
- if (recursionContext.recursionDepth > recursionContext.config.maxRecursionDepth) {
1197
- return field;
1116
+ function describedFieldEqual(a, b) {
1117
+ return defaultEmpty(a.category) === defaultEmpty(b.category) && defaultEmpty(a.type) === defaultEmpty(b.type) && a.fieldName === b.fieldName && a.value === b.value;
1198
1118
  }
1199
- var nextRecursionContext = null;
1200
- var duplicateGroupNameToSkip = "";
1201
- var fieldGroups = new described_field.DescribedDataFieldGroup(field);
1202
- forEachGroupEntry(entry, function (groupName, groupEntry, allGroupEntries) {
1203
- if (recursionContext.groupToSkip === groupName) {
1204
- if (recursionContext.config.debugMode) {
1205
- console.log("Removed duplicate group " + groupName + " at recursion depth " + recursionContext.recursionDepth);
1206
- }
1207
- return;
1208
- }
1209
- duplicateGroupNameToSkip = "";
1210
- if (recursionContext.recursionDepth >= recursionContext.config.removeDuplicationAboveRecursionDepth) {
1211
- duplicateGroupNameToSkip = arraysEqual(groupEntry[groupName], allGroupEntries, describedFieldEqual) ? groupName : "";
1212
- }
1213
- nextRecursionContext = {
1214
- recursionDepth: recursionContext.recursionDepth + 1,
1215
- config: recursionContext.config,
1216
- groupToSkip: duplicateGroupNameToSkip
1217
- };
1218
- fieldGroups.addGroupEntry(groupName, toDescribedField(groupEntry, nextRecursionContext));
1219
- });
1220
- return field;
1221
- }
1222
- function describedFieldEqual(a, b) {
1223
- return defaultEmpty(a.category) === defaultEmpty(b.category) && defaultEmpty(a.type) === defaultEmpty(b.type) && a.fieldName === b.fieldName && a.value === b.value;
1224
- }
1225
- function defaultEmpty(value) {
1226
- return defaultValue(value, "");
1227
- }
1228
- function defaultValue(value, valueAsDefault) {
1229
- if (typeof value === "undefined" || !value) {
1230
- return valueAsDefault;
1119
+ function defaultEmpty(value) {
1120
+ return defaultValue(value, "");
1231
1121
  }
1232
- return value;
1233
- }
1234
- // Reference: https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript/16430730
1235
- // Added "elementEqualFunction" to implement equal object detection.
1236
- // Arrays are assumed to be sorted. Differently ordered entries are treated as not equal.
1237
- function arraysEqual(a, b, elementEqualFunction) {
1238
- if (a === b) return true;
1239
- if (a == null || b == null) return false;
1240
- if (a.length !== b.length) return false;
1241
- for (var i = 0; i < a.length; ++i) {
1242
- if (!elementEqualFunction(a[i], b[i])) return false;
1122
+ function defaultValue(value, valueAsDefault) {
1123
+ if (typeof value === "undefined" || !value) return valueAsDefault;
1124
+ return value;
1243
1125
  }
1244
- return true;
1245
- }
1246
- /**
1247
- * Takes the full qualified original property name and extracts a simple name out of it.
1248
- *
1249
- * @callback module:datarestructor.onEntryFoundFunction
1250
- * @param {string} groupName name of the group where the entry had been found.
1251
- * @param {module:datarestructor.DescribedEntry} foundEntry the found entry itself.
1252
- * @param {module:datarestructor.DescribedEntry[]} allEntries the array of all entries where the found entry is an element of.
1253
- */
1254
- /**
1255
- * Traverses through all groups and their entries and calls the given function on every found entry
1256
- * with the group name and the entry itself as parameters.
1257
- * @param {module:datarestructor.DescribedEntry} rootEntry
1258
- * @param {module:datarestructor.onEntryFoundFunction} onFoundEntry
1259
- * @protected
1260
- * @memberof module:datarestructor.Transform
1261
- */
1262
- function forEachGroupEntry(rootEntry, onFoundEntry) {
1263
- var groupIndex, entryIndex;
1264
- var groupName, entry;
1265
- for (groupIndex = 0; groupIndex < rootEntry.groupNames.length; groupIndex += 1) {
1266
- groupName = rootEntry.groupNames[groupIndex];
1267
- for (entryIndex = 0; entryIndex < rootEntry[groupName].length; entryIndex += 1) {
1268
- entry = rootEntry[groupName][entryIndex];
1269
- onFoundEntry(groupName, entry, rootEntry[groupName]);
1270
- }
1126
+ // Reference: https://stackoverflow.com/questions/3115982/how-to-check-if-two-arrays-are-equal-with-javascript/16430730
1127
+ // Added "elementEqualFunction" to implement equal object detection.
1128
+ // Arrays are assumed to be sorted. Differently ordered entries are treated as not equal.
1129
+ function arraysEqual(a, b, elementEqualFunction) {
1130
+ if (a === b) return true;
1131
+ if (a == null || b == null) return false;
1132
+ if (a.length !== b.length) return false;
1133
+ for(var i = 0; i < a.length; ++i){
1134
+ if (!elementEqualFunction(a[i], b[i])) return false;
1135
+ }
1136
+ return true;
1271
1137
  }
1272
- }
1273
- return Transform;
1274
- })();
1138
+ /**
1139
+ * Takes the full qualified original property name and extracts a simple name out of it.
1140
+ *
1141
+ * @callback module:datarestructor.onEntryFoundFunction
1142
+ * @param {string} groupName name of the group where the entry had been found.
1143
+ * @param {module:datarestructor.DescribedEntry} foundEntry the found entry itself.
1144
+ * @param {module:datarestructor.DescribedEntry[]} allEntries the array of all entries where the found entry is an element of.
1145
+ */ /**
1146
+ * Traverses through all groups and their entries and calls the given function on every found entry
1147
+ * with the group name and the entry itself as parameters.
1148
+ * @param {module:datarestructor.DescribedEntry} rootEntry
1149
+ * @param {module:datarestructor.onEntryFoundFunction} onFoundEntry
1150
+ * @protected
1151
+ * @memberof module:datarestructor.Transform
1152
+ */ function forEachGroupEntry(rootEntry, onFoundEntry) {
1153
+ var groupIndex, entryIndex;
1154
+ var groupName, entry;
1155
+ for(groupIndex = 0; groupIndex < rootEntry.groupNames.length; groupIndex += 1){
1156
+ groupName = rootEntry.groupNames[groupIndex];
1157
+ for(entryIndex = 0; entryIndex < rootEntry[groupName].length; entryIndex += 1){
1158
+ entry = rootEntry[groupName][entryIndex];
1159
+ onFoundEntry(groupName, entry, rootEntry[groupName]);
1160
+ }
1161
+ }
1162
+ }
1163
+ return Transform;
1164
+ }();
1275
1165
  /**
1276
- * Main fassade for the data restructor as static function(s).
1277
- *
1278
- * @example
1279
- * var allDescriptions = [];
1280
- * allDescriptions.push(summariesDescription());
1281
- * allDescriptions.push(detailsDescription());
1282
- * var result = datarestructor.Restructor.processJsonUsingDescriptions(jsonData, allDescriptions);
1283
- * @namespace module:datarestructor.Restructor
1284
- */
1285
- datarestructor.Restructor = {};
1166
+ * Main fassade for the data restructor as static function(s).
1167
+ *
1168
+ * @example
1169
+ * var allDescriptions = [];
1170
+ * allDescriptions.push(summariesDescription());
1171
+ * allDescriptions.push(detailsDescription());
1172
+ * var result = datarestructor.Restructor.processJsonUsingDescriptions(jsonData, allDescriptions);
1173
+ * @namespace module:datarestructor.Restructor
1174
+ */ datarestructor.Restructor = {};
1286
1175
  /**
1287
- * Static fassade function for the "Assembly line", that takes the jsonData and processes it using all given descriptions in their given order.
1288
- * @param {object} jsonData - parsed JSON data or any other data object
1289
- * @param {module:datarestructor.PropertyStructureDescription[]} descriptions - already grouped entries
1290
- * @param {boolean} debugMode - false=default=off, true=write additional logs for detailed debugging
1291
- * @returns {module:datarestructor.DescribedEntry[]}
1292
- * @memberof module:datarestructor.Restructor
1293
- * @deprecated since v3.1.0, please use "new datarestructor.Transform(descriptions).processJson(jsonData)".
1294
- */
1295
- datarestructor.Restructor.processJsonUsingDescriptions = function (jsonData, descriptions, debugMode) {
1296
- var restructor = new datarestructor.Transform(descriptions);
1297
- if (debugMode) {
1298
- restructor.enableDebugMode();
1299
- }
1300
- return restructor.processJson(jsonData);
1176
+ * Static fassade function for the "Assembly line", that takes the jsonData and processes it using all given descriptions in their given order.
1177
+ * @param {object} jsonData - parsed JSON data or any other data object
1178
+ * @param {module:datarestructor.PropertyStructureDescription[]} descriptions - already grouped entries
1179
+ * @param {boolean} debugMode - false=default=off, true=write additional logs for detailed debugging
1180
+ * @returns {module:datarestructor.DescribedEntry[]}
1181
+ * @memberof module:datarestructor.Restructor
1182
+ * @deprecated since v3.1.0, please use "new datarestructor.Transform(descriptions).processJson(jsonData)".
1183
+ */ datarestructor.Restructor.processJsonUsingDescriptions = function(jsonData, descriptions, debugMode) {
1184
+ var restructor = new datarestructor.Transform(descriptions);
1185
+ if (debugMode) restructor.enableDebugMode();
1186
+ return restructor.processJson(jsonData);
1301
1187
  };
1302
1188
 
1303
- },{"../../lib/js/flattenToArray":"3Qsn4","../../src/js/templateResolver":"7hyUl","../../src/js/describedfield":"4X3T9"}],"3Qsn4":[function(require,module,exports) {
1189
+ },{"403576eaef4c3d50":"i4dBQ","f62fb3394fa418f2":"5qyN0","4388868734c1e0a7":"g0GVY"}],"i4dBQ":[function(require,module,exports) {
1304
1190
  "use strict";
1305
1191
  /**
1306
- * @fileOverview Modded (compatibility, recursion depth) version of: https://stackoverflow.com/questions/19098797/fastest-way-to-flatten-un-flatten-nested-json-objectss
1307
- * @version ${project.version}
1308
- * @see {@link https://stackoverflow.com/questions/19098797/fastest-way-to-flatten-un-flatten-nested-json-objectss|stackoverflow flatten nested json objects}
1309
- */
1310
- var module = module || ({});
1311
- // Fallback for vanilla js without modules
1192
+ * @fileOverview Modded (compatibility, recursion depth) version of: https://stackoverflow.com/questions/19098797/fastest-way-to-flatten-un-flatten-nested-json-objectss
1193
+ * @version ${project.version}
1194
+ * @see {@link https://stackoverflow.com/questions/19098797/fastest-way-to-flatten-un-flatten-nested-json-objectss|stackoverflow flatten nested json objects}
1195
+ */ var module = module || {}; // Fallback for vanilla js without modules
1312
1196
  /**
1313
- * internal_object_tools. Not meant to be used outside this repository.
1314
- * @default {}
1315
- */
1316
- var internal_object_tools = module.exports = {};
1317
- // Export module for npm...
1197
+ * internal_object_tools. Not meant to be used outside this repository.
1198
+ * @default {}
1199
+ */ var internal_object_tools = module.exports = {}; // Export module for npm...
1318
1200
  /**
1319
- * @typedef {Object} NameValuePair
1320
- * @property {string} name - point separated names of the flattened main and sub properties, e.g. "responses[2].hits.hits[4]._source.name".
1321
- * @property {string} value - value of the property
1322
- */
1323
- /**
1324
- * @param {object} data hierarchical object that may consist fo fields, subfields and arrays.
1325
- * @param {number} maxRecursionDepth
1326
- * @returns {NameValuePair[]} array of property name and value pairs
1327
- */
1328
- internal_object_tools.flattenToArray = function (data, maxRecursionDepth) {
1329
- var result = [];
1330
- if (typeof maxRecursionDepth !== "number" || maxRecursionDepth < 1) {
1331
- maxRecursionDepth = 20;
1332
- }
1333
- function recurse(cur, prop, depth) {
1334
- if (depth > maxRecursionDepth || typeof cur === "function") {
1335
- return;
1336
- }
1337
- if (Object(cur) !== cur) {
1338
- result.push({
1339
- name: prop,
1340
- value: cur
1341
- });
1342
- } else if (Array.isArray(cur)) {
1343
- var i;
1344
- var l = cur.length;
1345
- for (i = 0; i < l; i += 1) {
1346
- recurse(cur[i], prop + "[" + i + "]", depth + 1);
1347
- }
1348
- if (l === 0) {
1349
- result[prop] = [];
1350
- result.push({
1351
- name: prop,
1352
- value: ""
1353
- });
1354
- }
1355
- } else {
1356
- var isEmpty = true;
1357
- var p;
1358
- for (p in cur) {
1359
- isEmpty = false;
1360
- recurse(cur[p], prop ? prop + "." + p : p, depth + 1);
1361
- }
1362
- if (isEmpty && prop) {
1363
- result.push({
1364
- name: prop,
1365
- value: ""
1201
+ * @typedef {Object} NameValuePair
1202
+ * @property {string} name - point separated names of the flattened main and sub properties, e.g. "responses[2].hits.hits[4]._source.name".
1203
+ * @property {string} value - value of the property
1204
+ */ /**
1205
+ * @param {object} data hierarchical object that may consist fo fields, subfields and arrays.
1206
+ * @param {number} maxRecursionDepth
1207
+ * @returns {NameValuePair[]} array of property name and value pairs
1208
+ */ internal_object_tools.flattenToArray = function(data, maxRecursionDepth) {
1209
+ var result = [];
1210
+ if (typeof maxRecursionDepth !== "number" || maxRecursionDepth < 1) maxRecursionDepth = 20;
1211
+ function recurse(cur, prop, depth) {
1212
+ if (depth > maxRecursionDepth || typeof cur === "function") return;
1213
+ if (Object(cur) !== cur) result.push({
1214
+ name: prop,
1215
+ value: cur
1366
1216
  });
1367
- }
1217
+ else if (Array.isArray(cur)) {
1218
+ var i;
1219
+ var l = cur.length;
1220
+ for(i = 0; i < l; i += 1)recurse(cur[i], prop + "[" + i + "]", depth + 1);
1221
+ if (l === 0) {
1222
+ result[prop] = [];
1223
+ result.push({
1224
+ name: prop,
1225
+ value: ""
1226
+ });
1227
+ }
1228
+ } else {
1229
+ var isEmpty = true;
1230
+ var p;
1231
+ for(p in cur){
1232
+ isEmpty = false;
1233
+ recurse(cur[p], prop ? prop + "." + p : p, depth + 1);
1234
+ }
1235
+ if (isEmpty && prop) result.push({
1236
+ name: prop,
1237
+ value: ""
1238
+ });
1239
+ }
1368
1240
  }
1369
- }
1370
- recurse(data, "", 0);
1371
- return result;
1241
+ recurse(data, "", 0);
1242
+ return result;
1372
1243
  };
1373
1244
 
1374
- },{}],"7hyUl":[function(require,module,exports) {
1245
+ },{}],"5qyN0":[function(require,module,exports) {
1375
1246
  /**
1376
- * @file Provides a simple template resolver, that replaces variables in double curly brackets with the values of a given object.
1377
- * @version {@link https://github.com/JohT/data-restructor-js/releases/latest latest version}
1378
- * @author JohT
1379
- * @version ${project.version}
1380
- */
1381
- "use strict";
1382
- var module = templateResolverInternalCreateIfNotExists(module);
1383
- // Fallback for vanilla js without modules
1247
+ * @file Provides a simple template resolver, that replaces variables in double curly brackets with the values of a given object.
1248
+ * @version {@link https://github.com/JohT/data-restructor-js/releases/latest latest version}
1249
+ * @author JohT
1250
+ * @version ${project.version}
1251
+ */ "use strict";
1252
+ var module = templateResolverInternalCreateIfNotExists(module); // Fallback for vanilla js without modules
1384
1253
  function templateResolverInternalCreateIfNotExists(objectToCheck) {
1385
- return objectToCheck || ({});
1254
+ return objectToCheck || {};
1386
1255
  }
1387
1256
  /**
1388
- * Provides a simple template resolver, that replaces variables in double curly brackets with the values of a given object.
1389
- * @module template_resolver
1390
- */
1391
- var template_resolver = module.exports = {};
1392
- // Export module for npm...
1257
+ * Provides a simple template resolver, that replaces variables in double curly brackets with the values of a given object.
1258
+ * @module template_resolver
1259
+ */ var template_resolver = module.exports = {}; // Export module for npm...
1393
1260
  template_resolver.internalCreateIfNotExists = templateResolverInternalCreateIfNotExists;
1394
- var internal_object_tools = internal_object_tools || require("../../lib/js/flattenToArray");
1395
- // supports vanilla js & npm
1396
- template_resolver.Resolver = (function () {
1397
- var removeArrayBracketsRegEx = new RegExp("\\[\\d+\\]", "gi");
1398
- /**
1399
- * Resolver. Is used inside this repository. It could also be used outside.
1400
- * @param {*} sourceDataObject The properties of this object will be used to replace the placeholders in the template.
1401
- * @constructs Resolver
1402
- * @alias module:template_resolver.Resolver
1403
- */
1404
- function Resolver(sourceDataObject) {
1405
- /**
1406
- * The properties of this source data object will be used to replace the placeholders in the template.
1407
- */
1408
- this.sourceDataObject = sourceDataObject;
1409
- /**
1410
- * Resolves the given template.
1411
- *
1412
- * The template may contain variables in double curly brackets.
1413
- * Supported variables are all properties of this object, e.g. "{{fieldName}}", "{{displayName}}", "{{value}}".
1414
- * Since this object may also contains (described) groups of sub objects, they can also be used, e.g. "{{summaries[0].value}}"
1415
- * Parts of the index can be inserted by using e.g. "{{index[1]}}".
1416
- *
1417
- * @param {string} template
1418
- * @returns {string} resolved template
1419
- */
1420
- this.resolveTemplate = function (template) {
1421
- return this.replaceResolvableFields(template, addFieldsPerGroup(this.resolvableFieldsOfAll(this.sourceDataObject)));
1422
- };
1423
- /**
1424
- * Returns a map like object, that contains all resolvable fields and their values as properties.
1425
- * This function takes a variable count of input parameters,
1426
- * each containing an object that contains resolvable fields to extract from.
1427
- *
1428
- * The recursion depth is limited to 3, so that an object,
1429
- * that contains an object can contain another object (but not further).
1430
- *
1431
- * Properties beginning with an underscore in their name will be filtered out, since they are considered as internal fields.
1432
- *
1433
- * @param {...object} varArgs variable count of parameters. Each parameter contains an object that fields should be resolvable for variables.
1434
- * @returns {object} object with resolvable field names and their values.
1435
- * @public
1436
- */
1437
- this.resolvableFieldsOfAll = function () {
1438
- var map = {};
1439
- var ignoreInternalFields = function (propertyName) {
1440
- return propertyName.indexOf("_") !== 0 && propertyName.indexOf("._") < 0;
1441
- };
1442
- var index;
1443
- for (index = 0; index < arguments.length; index += 1) {
1444
- addToFilteredMapObject(internal_object_tools.flattenToArray(arguments[index], 3), map, ignoreInternalFields);
1445
- }
1446
- return map;
1447
- };
1261
+ var internal_object_tools = internal_object_tools || require("2bc8fdaaf35dfa57"); // supports vanilla js & npm
1262
+ template_resolver.Resolver = function() {
1263
+ var removeArrayBracketsRegEx = new RegExp("\\[\\d+\\]", "gi");
1448
1264
  /**
1449
- * Replaces all variables in double curly brackets, e.g. {{property}},
1450
- * with the value of that property from the resolvableProperties.
1451
- *
1452
- * Supported property types: string, number, boolean
1453
- * @param {string} stringContainingVariables
1454
- * @param {object[]} resolvableFields (name=value)
1455
- */
1456
- this.replaceResolvableFields = function (stringContainingVariables, resolvableFields) {
1457
- var replaced = stringContainingVariables;
1458
- var propertyNames = Object.keys(resolvableFields);
1459
- var propertyIndex = 0;
1460
- var propertyName = "";
1461
- var propertyValue = "";
1462
- for (propertyIndex = 0; propertyIndex < propertyNames.length; propertyIndex += 1) {
1463
- propertyName = propertyNames[propertyIndex];
1464
- propertyValue = resolvableFields[propertyName];
1465
- replaced = replaced.replace("{{" + propertyName + "}}", propertyValue);
1466
- }
1467
- return replaced;
1468
- };
1469
- }
1470
- /**
1471
- * Adds the value of the "fieldName" property (including its group prefix) and its associated "value" property content.
1472
- * For example: detail[2].fieldName="name", detail[2].value="Smith" lead to the additional property detail.name="Smith".
1473
- * @param {object} object with resolvable field names and their values.
1474
- * @returns {object} object with resolvable field names and their values.
1475
- * @protected
1476
- * @memberof module:template_resolver.Resolver
1477
- */
1478
- function addFieldsPerGroup(map) {
1479
- var propertyNames = Object.keys(map);
1480
- var i, fullPropertyName, propertyInfo, propertyValue;
1481
- for (i = 0; i < propertyNames.length; i += 1) {
1482
- fullPropertyName = propertyNames[i];
1483
- propertyValue = map[fullPropertyName];
1484
- propertyInfo = getPropertyNameInfos(fullPropertyName);
1485
- // Supports fields that are defined by a property named "fieldName" (containing the name)
1486
- // and a property named "value" inside the same sub object (containing its value).
1487
- // Ignore custom fields that are named "fieldName"(propertyValue), since this would lead to an unpredictable behavior.
1488
- // TODO could make "fieldName" and "value" configurable
1489
- if (propertyInfo.name === "fieldName" && propertyValue !== "fieldName") {
1490
- map[propertyInfo.groupWithoutArrayIndices + propertyValue] = map[propertyInfo.group + "value"];
1491
- }
1265
+ * Resolver. Is used inside this repository. It could also be used outside.
1266
+ * @param {*} sourceDataObject The properties of this object will be used to replace the placeholders in the template.
1267
+ * @constructs Resolver
1268
+ * @alias module:template_resolver.Resolver
1269
+ */ function Resolver(sourceDataObject) {
1270
+ /**
1271
+ * The properties of this source data object will be used to replace the placeholders in the template.
1272
+ */ this.sourceDataObject = sourceDataObject;
1273
+ /**
1274
+ * Resolves the given template.
1275
+ *
1276
+ * The template may contain variables in double curly brackets.
1277
+ * Supported variables are all properties of this object, e.g. "{{fieldName}}", "{{displayName}}", "{{value}}".
1278
+ * Since this object may also contains (described) groups of sub objects, they can also be used, e.g. "{{summaries[0].value}}"
1279
+ * Parts of the index can be inserted by using e.g. "{{index[1]}}".
1280
+ *
1281
+ * @param {string} template
1282
+ * @returns {string} resolved template
1283
+ */ this.resolveTemplate = function(template) {
1284
+ return this.replaceResolvableFields(template, addFieldsPerGroup(this.resolvableFieldsOfAll(this.sourceDataObject)));
1285
+ };
1286
+ /**
1287
+ * Returns a map like object, that contains all resolvable fields and their values as properties.
1288
+ * This function takes a variable count of input parameters,
1289
+ * each containing an object that contains resolvable fields to extract from.
1290
+ *
1291
+ * The recursion depth is limited to 3, so that an object,
1292
+ * that contains an object can contain another object (but not further).
1293
+ *
1294
+ * Properties beginning with an underscore in their name will be filtered out, since they are considered as internal fields.
1295
+ *
1296
+ * @param {...object} varArgs variable count of parameters. Each parameter contains an object that fields should be resolvable for variables.
1297
+ * @returns {object} object with resolvable field names and their values.
1298
+ * @public
1299
+ */ this.resolvableFieldsOfAll = function() {
1300
+ var map = {};
1301
+ var ignoreInternalFields = function(propertyName) {
1302
+ return propertyName.indexOf("_") !== 0 && propertyName.indexOf("._") < 0;
1303
+ };
1304
+ var index;
1305
+ for(index = 0; index < arguments.length; index += 1)addToFilteredMapObject(internal_object_tools.flattenToArray(arguments[index], 3), map, ignoreInternalFields);
1306
+ return map;
1307
+ };
1308
+ /**
1309
+ * Replaces all variables in double curly brackets, e.g. {{property}},
1310
+ * with the value of that property from the resolvableProperties.
1311
+ *
1312
+ * Supported property types: string, number, boolean
1313
+ * @param {string} stringContainingVariables
1314
+ * @param {object[]} resolvableFields (name=value)
1315
+ */ this.replaceResolvableFields = function(stringContainingVariables, resolvableFields) {
1316
+ var replaced = stringContainingVariables;
1317
+ var propertyNames = Object.keys(resolvableFields);
1318
+ var propertyIndex = 0;
1319
+ var propertyName = "";
1320
+ var propertyValue = "";
1321
+ for(propertyIndex = 0; propertyIndex < propertyNames.length; propertyIndex += 1){
1322
+ propertyName = propertyNames[propertyIndex];
1323
+ propertyValue = resolvableFields[propertyName];
1324
+ replaced = replaced.replace("{{" + propertyName + "}}", propertyValue);
1325
+ }
1326
+ return replaced;
1327
+ };
1492
1328
  }
1493
- return map;
1494
- }
1495
- /**
1496
- * Infos about the full property name including the name of the group (followed by the separator) and the name of the property itself.
1497
- * @param {String} fullPropertyName
1498
- * @returns {Object} Contains "group" (empty or group name including trailing separator "."), "groupWithoutArrayIndices" and "name" (property name).
1499
- * @protected
1500
- * @memberof module:template_resolver.Resolver
1501
- */
1502
- function getPropertyNameInfos(fullPropertyName) {
1503
- var positionOfRightMostSeparator = fullPropertyName.lastIndexOf(".");
1504
- var propertyName = fullPropertyName;
1505
- if (positionOfRightMostSeparator > 0) {
1506
- propertyName = fullPropertyName.substr(positionOfRightMostSeparator + 1);
1329
+ /**
1330
+ * Adds the value of the "fieldName" property (including its group prefix) and its associated "value" property content.
1331
+ * For example: detail[2].fieldName="name", detail[2].value="Smith" lead to the additional property detail.name="Smith".
1332
+ * @param {object} object with resolvable field names and their values.
1333
+ * @returns {object} object with resolvable field names and their values.
1334
+ * @protected
1335
+ * @memberof module:template_resolver.Resolver
1336
+ */ function addFieldsPerGroup(map) {
1337
+ var propertyNames = Object.keys(map);
1338
+ var i, fullPropertyName, propertyInfo, propertyValue;
1339
+ for(i = 0; i < propertyNames.length; i += 1){
1340
+ fullPropertyName = propertyNames[i];
1341
+ propertyValue = map[fullPropertyName];
1342
+ propertyInfo = getPropertyNameInfos(fullPropertyName);
1343
+ // Supports fields that are defined by a property named "fieldName" (containing the name)
1344
+ // and a property named "value" inside the same sub object (containing its value).
1345
+ // Ignore custom fields that are named "fieldName"(propertyValue), since this would lead to an unpredictable behavior.
1346
+ // TODO could make "fieldName" and "value" configurable
1347
+ if (propertyInfo.name === "fieldName" && propertyValue !== "fieldName") map[propertyInfo.groupWithoutArrayIndices + propertyValue] = map[propertyInfo.group + "value"];
1348
+ }
1349
+ return map;
1507
1350
  }
1508
- var propertyGroup = "";
1509
- if (positionOfRightMostSeparator > 0) {
1510
- propertyGroup = fullPropertyName.substr(0, positionOfRightMostSeparator + 1);
1351
+ /**
1352
+ * Infos about the full property name including the name of the group (followed by the separator) and the name of the property itself.
1353
+ * @param {String} fullPropertyName
1354
+ * @returns {Object} Contains "group" (empty or group name including trailing separator "."), "groupWithoutArrayIndices" and "name" (property name).
1355
+ * @protected
1356
+ * @memberof module:template_resolver.Resolver
1357
+ */ function getPropertyNameInfos(fullPropertyName) {
1358
+ var positionOfRightMostSeparator = fullPropertyName.lastIndexOf(".");
1359
+ var propertyName = fullPropertyName;
1360
+ if (positionOfRightMostSeparator > 0) propertyName = fullPropertyName.substr(positionOfRightMostSeparator + 1);
1361
+ var propertyGroup = "";
1362
+ if (positionOfRightMostSeparator > 0) propertyGroup = fullPropertyName.substr(0, positionOfRightMostSeparator + 1); //includes the trailing ".".
1363
+ var propertyGroupWithoutArrayIndices = propertyGroup.replace(removeArrayBracketsRegEx, "");
1364
+ return {
1365
+ group: propertyGroup,
1366
+ groupWithoutArrayIndices: propertyGroupWithoutArrayIndices,
1367
+ name: propertyName
1368
+ };
1511
1369
  }
1512
- var propertyGroupWithoutArrayIndices = propertyGroup.replace(removeArrayBracketsRegEx, "");
1513
- return {
1514
- group: propertyGroup,
1515
- groupWithoutArrayIndices: propertyGroupWithoutArrayIndices,
1516
- name: propertyName
1517
- };
1518
- }
1519
- /**
1520
- * Collects all flattened name-value-pairs into one object using the property names as keys and their values as values (map-like).
1521
- * Example: `{name: "accountNumber", value: "12345"}` becomes `mapObject["accountNumber"]="12345"`.
1522
- *
1523
- * @param {NameValuePair[]} elements flattened array of name-value-pairs
1524
- * @param {object} mapObject container to collect the results. Needs to be created before e.g. using `{}`.
1525
- * @param {function} filterMatchesFunction takes the property name as string argument and returns true (include) or false (exclude).
1526
- * @protected
1527
- * @memberof module:template_resolver.Resolver
1528
- */
1529
- function addToFilteredMapObject(elements, mapObject, filterMatchesFunction) {
1530
- var index, element;
1531
- for (index = 0; index < elements.length; index += 1) {
1532
- element = elements[index];
1533
- if (typeof filterMatchesFunction === "function" && filterMatchesFunction(element.name)) {
1534
- mapObject[element.name] = element.value;
1535
- }
1370
+ /**
1371
+ * Collects all flattened name-value-pairs into one object using the property names as keys and their values as values (map-like).
1372
+ * Example: `{name: "accountNumber", value: "12345"}` becomes `mapObject["accountNumber"]="12345"`.
1373
+ *
1374
+ * @param {NameValuePair[]} elements flattened array of name-value-pairs
1375
+ * @param {object} mapObject container to collect the results. Needs to be created before e.g. using `{}`.
1376
+ * @param {function} filterMatchesFunction takes the property name as string argument and returns true (include) or false (exclude).
1377
+ * @protected
1378
+ * @memberof module:template_resolver.Resolver
1379
+ */ function addToFilteredMapObject(elements, mapObject, filterMatchesFunction) {
1380
+ var index, element;
1381
+ for(index = 0; index < elements.length; index += 1){
1382
+ element = elements[index];
1383
+ if (typeof filterMatchesFunction === "function" && filterMatchesFunction(element.name)) mapObject[element.name] = element.value;
1384
+ }
1385
+ return mapObject;
1536
1386
  }
1537
- return mapObject;
1538
- }
1539
- return Resolver;
1540
- })();
1387
+ return Resolver;
1388
+ }();
1541
1389
 
1542
- },{"../../lib/js/flattenToArray":"3Qsn4"}],"4X3T9":[function(require,module,exports) {
1390
+ },{"2bc8fdaaf35dfa57":"i4dBQ"}],"g0GVY":[function(require,module,exports) {
1543
1391
  /**
1544
- * @file Describes a data field of the restructured data.
1545
- * @version {@link https://github.com/JohT/data-restructor-js/releases/latest latest version}
1546
- * @author JohT
1547
- * @version ${project.version}
1548
- */
1549
- "use strict";
1550
- var module = describedFieldInternalCreateIfNotExists(module);
1551
- // Fallback for vanilla js without modules
1392
+ * @file Describes a data field of the restructured data.
1393
+ * @version {@link https://github.com/JohT/data-restructor-js/releases/latest latest version}
1394
+ * @author JohT
1395
+ * @version ${project.version}
1396
+ */ "use strict";
1397
+ var module = describedFieldInternalCreateIfNotExists(module); // Fallback for vanilla js without modules
1552
1398
  function describedFieldInternalCreateIfNotExists(objectToCheck) {
1553
- return objectToCheck || ({});
1399
+ return objectToCheck || {};
1554
1400
  }
1555
1401
  /**
1556
- * Describes a data field of the restructured data.
1557
- * @module described_field
1558
- */
1559
- var described_field = module.exports = {};
1560
- // Export module for npm...
1402
+ * Describes a data field of the restructured data.
1403
+ * @module described_field
1404
+ */ var described_field = module.exports = {}; // Export module for npm...
1561
1405
  described_field.internalCreateIfNotExists = describedFieldInternalCreateIfNotExists;
1562
1406
  /**
1563
- * Describes a field of the restructured data.
1564
- * Dynamically added properties represent custom named groups containing DescribedDataField-Arrays.
1565
- *
1566
- * @typedef {Object} module:described_field.DescribedDataField
1567
- * @property {string} [category=""] - name of the category. Could contain a short domain name like "product" or "vendor".
1568
- * @property {string} [type=""] - type of the data element. Examples: "summary" for e.g. a list overview. "detail" e.g. when a summary is selected. "filter" e.g. for field/value pair results that can be selected as data filters.
1569
- * @property {string} [abbreviation=""] - one optional character, a symbol character or a short abbreviation of the category
1570
- * @property {string} [image=""] - one optional path to an image resource
1571
- * @property {string} index - array of numbers containing the splitted index. Example: "responses[2].hits.hits[4]._source.name" will have an index of [2,4]
1572
- * @property {string[]} groupNames - array of names of all dynamically added properties representing groups
1573
- * @property {string} displayName - display name of the field
1574
- * @property {string} fieldName - field name
1575
- * @property {{*}} value - content of the field
1576
- * @property {module:described_field.DescribedDataField[]} [couldBeAnyCustomGroupName] any number of groups attached to the field each containing multiple fields
1577
- */
1578
- described_field.DescribedDataFieldBuilder = (function () {
1579
- /**
1580
- * Builds a {@link module:described_field.DescribedDataField}.
1581
- * DescribedDataField is the main element of the restructured data and therefore considered "public".
1582
- * @constructs DescribedDataFieldBuilder
1583
- * @alias module:described_field.DescribedDataFieldBuilder
1584
- */
1585
- function DescribedDataFieldBuilder() {
1586
- /**
1587
- * @type {module:described_field.DescribedDataField}
1588
- */
1589
- this.describedField = {
1590
- category: "",
1591
- type: "",
1592
- abbreviation: "",
1593
- image: "",
1594
- index: [],
1595
- groupNames: [],
1596
- displayName: "",
1597
- fieldName: "",
1598
- value: ""
1599
- };
1600
- /**
1601
- * Takes over all values of the template {@link module:described_field.DescribedDataField}.
1602
- * @function
1603
- * @param {module:described_field.DescribedDataField} template
1604
- * @returns {DescribedDataFieldBuilder}
1605
- * @example fromDescribedDataField(sourceField)
1606
- */
1607
- this.fromDescribedDataField = function (template) {
1608
- this.category(template.category);
1609
- this.type(template.type);
1610
- this.abbreviation(template.abbreviation);
1611
- this.image(template.image);
1612
- this.index(template.index);
1613
- this.groupNames(template.groupNames);
1614
- this.displayName(template.displayName);
1615
- this.fieldName(template.fieldName);
1616
- this.value(template.value);
1617
- return this;
1618
- };
1407
+ * Describes a field of the restructured data.
1408
+ * Dynamically added properties represent custom named groups containing DescribedDataField-Arrays.
1409
+ *
1410
+ * @typedef {Object} module:described_field.DescribedDataField
1411
+ * @property {string} [category=""] - name of the category. Could contain a short domain name like "product" or "vendor".
1412
+ * @property {string} [type=""] - type of the data element. Examples: "summary" for e.g. a list overview. "detail" e.g. when a summary is selected. "filter" e.g. for field/value pair results that can be selected as data filters.
1413
+ * @property {string} [abbreviation=""] - one optional character, a symbol character or a short abbreviation of the category
1414
+ * @property {string} [image=""] - one optional path to an image resource
1415
+ * @property {string} index - array of numbers containing the splitted index. Example: "responses[2].hits.hits[4]._source.name" will have an index of [2,4]
1416
+ * @property {string[]} groupNames - array of names of all dynamically added properties representing groups
1417
+ * @property {string} displayName - display name of the field
1418
+ * @property {string} fieldName - field name
1419
+ * @property {{*}} value - content of the field
1420
+ * @property {module:described_field.DescribedDataField[]} [couldBeAnyCustomGroupName] any number of groups attached to the field each containing multiple fields
1421
+ */ described_field.DescribedDataFieldBuilder = function() {
1619
1422
  /**
1620
- * Sets the category.
1621
- *
1622
- * Contains a short domain nam, for example:
1623
- * - "product" for products
1624
- * - "vendor" for vendors
1625
- *
1626
- * @function
1627
- * @param {String} [value=""]
1628
- * @returns {DescribedDataFieldBuilder}
1629
- * @example category("Product")
1630
- */
1631
- this.category = function (value) {
1632
- this.describedField.category = withDefaultString(value, "");
1633
- return this;
1634
- };
1635
- /**
1636
- * Sets the type.
1637
- *
1638
- * Contains the type of the entry, for example:
1639
- * - "summary" for e.g. a list overview.
1640
- * - "detail" e.g. when a summary is selected.
1641
- * - "filter" e.g. for field/value pair results that can be selected as search parameters.
1642
- *
1643
- * @function
1644
- * @param {String} [value=""]
1645
- * @returns {DescribedDataFieldBuilder}
1646
- * @example type("summary")
1647
- */
1648
- this.type = function (value) {
1649
- this.describedField.type = withDefaultString(value, "");
1650
- return this;
1651
- };
1652
- /**
1653
- * Sets the optional abbreviation.
1654
- *
1655
- * Contains a symbol character or a very short abbreviation of the category.
1656
- * - "P" for products
1657
- * - "V" for vendors
1658
- *
1659
- * @function
1660
- * @param {String} [value=""]
1661
- * @returns {DescribedDataFieldBuilder}
1662
- * @example abbreviation("P")
1663
- */
1664
- this.abbreviation = function (value) {
1665
- this.describedField.abbreviation = withDefaultString(value, "");
1666
- return this;
1667
- };
1668
- /**
1669
- * Sets the optional path to an image resource.
1670
- *
1671
- * @function
1672
- * @param {String} [value=""]
1673
- * @returns {DescribedDataFieldBuilder}
1674
- * @example image("img/product.png")
1675
- */
1676
- this.image = function (value) {
1677
- this.describedField.image = withDefaultString(value, "");
1678
- return this;
1679
- };
1680
- /**
1681
- * Sets the index as an array of numbers containing the splitted array indexes of the source field.
1682
- * Example: "responses[2].hits.hits[4]._source.name" will have an index of [2,4].
1683
- *
1684
- * @function
1685
- * @param {number[]} [value=[]]
1686
- * @returns {DescribedDataFieldBuilder}
1687
- * @example index([2,4])
1688
- */
1689
- this.index = function (value) {
1690
- this.describedField.index = withDefaultArray(value, []);
1691
- return this;
1692
- };
1693
- /**
1694
- * Sets the group names as an array of strings containing the names of the dynamically added properties,
1695
- * that contain an array of {@link module:described_field.DescribedDataField}-Objects.
1696
- *
1697
- * @function
1698
- * @param {string[]} [value=[]]
1699
- * @returns {DescribedDataFieldBuilder}
1700
- * @example groupNames(["summaries","details","options"])
1701
- */
1702
- this.groupNames = function (value) {
1703
- this.describedField.groupNames = withDefaultArray(value, []);
1704
- return this;
1705
- };
1706
- /**
1707
- * Sets the display name.
1708
- *
1709
- * @function
1710
- * @param {String} [value=""]
1711
- * @returns {DescribedDataFieldBuilder}
1712
- * @example displayName("Color")
1713
- */
1714
- this.displayName = function (value) {
1715
- this.describedField.displayName = withDefaultString(value, "");
1716
- return this;
1717
- };
1718
- /**
1719
- * Sets the (technical) field name.
1720
- *
1721
- * @function
1722
- * @param {String} [value=""]
1723
- * @returns {DescribedDataFieldBuilder}
1724
- * @example fieldName("color")
1725
- */
1726
- this.fieldName = function (value) {
1727
- this.describedField.fieldName = withDefaultString(value, "");
1728
- return this;
1729
- };
1730
- /**
1731
- * Sets the value/content of the field.
1732
- *
1733
- * @function
1734
- * @param {*} value
1735
- * @returns {DescribedDataFieldBuilder}
1736
- * @example value("darkblue")
1737
- */
1738
- this.value = function (value) {
1739
- this.describedField.value = value;
1740
- return this;
1741
- };
1742
- /**
1743
- * Finalizes the settings and builds the {@link module:described_field.DescribedDataField}.
1744
- * @function
1745
- * @returns {module:described_field.DescribedDataField}
1746
- */
1747
- this.build = function () {
1748
- return this.describedField;
1749
- };
1750
- }
1751
- function isSpecifiedString(value) {
1752
- return typeof value === "string" && value !== null && value !== "";
1753
- }
1754
- function withDefaultString(value, defaultValue) {
1755
- return isSpecifiedString(value) ? value : defaultValue;
1756
- }
1757
- function withDefaultArray(value, defaultValue) {
1758
- return value === undefined || value === null ? defaultValue : value;
1759
- }
1760
- return DescribedDataFieldBuilder;
1761
- })();
1423
+ * Builds a {@link module:described_field.DescribedDataField}.
1424
+ * DescribedDataField is the main element of the restructured data and therefore considered "public".
1425
+ * @constructs DescribedDataFieldBuilder
1426
+ * @alias module:described_field.DescribedDataFieldBuilder
1427
+ */ function DescribedDataFieldBuilder() {
1428
+ /**
1429
+ * @type {module:described_field.DescribedDataField}
1430
+ */ this.describedField = {
1431
+ category: "",
1432
+ type: "",
1433
+ abbreviation: "",
1434
+ image: "",
1435
+ index: [],
1436
+ groupNames: [],
1437
+ displayName: "",
1438
+ fieldName: "",
1439
+ value: ""
1440
+ };
1441
+ /**
1442
+ * Takes over all values of the template {@link module:described_field.DescribedDataField}.
1443
+ * @function
1444
+ * @param {module:described_field.DescribedDataField} template
1445
+ * @returns {DescribedDataFieldBuilder}
1446
+ * @example fromDescribedDataField(sourceField)
1447
+ */ this.fromDescribedDataField = function(template) {
1448
+ this.category(template.category);
1449
+ this.type(template.type);
1450
+ this.abbreviation(template.abbreviation);
1451
+ this.image(template.image);
1452
+ this.index(template.index);
1453
+ this.groupNames(template.groupNames);
1454
+ this.displayName(template.displayName);
1455
+ this.fieldName(template.fieldName);
1456
+ this.value(template.value);
1457
+ return this;
1458
+ };
1459
+ /**
1460
+ * Sets the category.
1461
+ *
1462
+ * Contains a short domain nam, for example:
1463
+ * - "product" for products
1464
+ * - "vendor" for vendors
1465
+ *
1466
+ * @function
1467
+ * @param {String} [value=""]
1468
+ * @returns {DescribedDataFieldBuilder}
1469
+ * @example category("Product")
1470
+ */ this.category = function(value) {
1471
+ this.describedField.category = withDefaultString(value, "");
1472
+ return this;
1473
+ };
1474
+ /**
1475
+ * Sets the type.
1476
+ *
1477
+ * Contains the type of the entry, for example:
1478
+ * - "summary" for e.g. a list overview.
1479
+ * - "detail" e.g. when a summary is selected.
1480
+ * - "filter" e.g. for field/value pair results that can be selected as search parameters.
1481
+ *
1482
+ * @function
1483
+ * @param {String} [value=""]
1484
+ * @returns {DescribedDataFieldBuilder}
1485
+ * @example type("summary")
1486
+ */ this.type = function(value) {
1487
+ this.describedField.type = withDefaultString(value, "");
1488
+ return this;
1489
+ };
1490
+ /**
1491
+ * Sets the optional abbreviation.
1492
+ *
1493
+ * Contains a symbol character or a very short abbreviation of the category.
1494
+ * - "P" for products
1495
+ * - "V" for vendors
1496
+ *
1497
+ * @function
1498
+ * @param {String} [value=""]
1499
+ * @returns {DescribedDataFieldBuilder}
1500
+ * @example abbreviation("P")
1501
+ */ this.abbreviation = function(value) {
1502
+ this.describedField.abbreviation = withDefaultString(value, "");
1503
+ return this;
1504
+ };
1505
+ /**
1506
+ * Sets the optional path to an image resource.
1507
+ *
1508
+ * @function
1509
+ * @param {String} [value=""]
1510
+ * @returns {DescribedDataFieldBuilder}
1511
+ * @example image("img/product.png")
1512
+ */ this.image = function(value) {
1513
+ this.describedField.image = withDefaultString(value, "");
1514
+ return this;
1515
+ };
1516
+ /**
1517
+ * Sets the index as an array of numbers containing the splitted array indexes of the source field.
1518
+ * Example: "responses[2].hits.hits[4]._source.name" will have an index of [2,4].
1519
+ *
1520
+ * @function
1521
+ * @param {number[]} [value=[]]
1522
+ * @returns {DescribedDataFieldBuilder}
1523
+ * @example index([2,4])
1524
+ */ this.index = function(value) {
1525
+ this.describedField.index = withDefaultArray(value, []);
1526
+ return this;
1527
+ };
1528
+ /**
1529
+ * Sets the group names as an array of strings containing the names of the dynamically added properties,
1530
+ * that contain an array of {@link module:described_field.DescribedDataField}-Objects.
1531
+ *
1532
+ * @function
1533
+ * @param {string[]} [value=[]]
1534
+ * @returns {DescribedDataFieldBuilder}
1535
+ * @example groupNames(["summaries","details","options"])
1536
+ */ this.groupNames = function(value) {
1537
+ this.describedField.groupNames = withDefaultArray(value, []);
1538
+ return this;
1539
+ };
1540
+ /**
1541
+ * Sets the display name.
1542
+ *
1543
+ * @function
1544
+ * @param {String} [value=""]
1545
+ * @returns {DescribedDataFieldBuilder}
1546
+ * @example displayName("Color")
1547
+ */ this.displayName = function(value) {
1548
+ this.describedField.displayName = withDefaultString(value, "");
1549
+ return this;
1550
+ };
1551
+ /**
1552
+ * Sets the (technical) field name.
1553
+ *
1554
+ * @function
1555
+ * @param {String} [value=""]
1556
+ * @returns {DescribedDataFieldBuilder}
1557
+ * @example fieldName("color")
1558
+ */ this.fieldName = function(value) {
1559
+ this.describedField.fieldName = withDefaultString(value, "");
1560
+ return this;
1561
+ };
1562
+ /**
1563
+ * Sets the value/content of the field.
1564
+ *
1565
+ * @function
1566
+ * @param {*} value
1567
+ * @returns {DescribedDataFieldBuilder}
1568
+ * @example value("darkblue")
1569
+ */ this.value = function(value) {
1570
+ this.describedField.value = value;
1571
+ return this;
1572
+ };
1573
+ /**
1574
+ * Finalizes the settings and builds the {@link module:described_field.DescribedDataField}.
1575
+ * @function
1576
+ * @returns {module:described_field.DescribedDataField}
1577
+ */ this.build = function() {
1578
+ return this.describedField;
1579
+ };
1580
+ }
1581
+ function isSpecifiedString(value) {
1582
+ return typeof value === "string" && value !== null && value !== "";
1583
+ }
1584
+ function withDefaultString(value, defaultValue) {
1585
+ return isSpecifiedString(value) ? value : defaultValue;
1586
+ }
1587
+ function withDefaultArray(value, defaultValue) {
1588
+ return value === undefined || value === null ? defaultValue : value;
1589
+ }
1590
+ return DescribedDataFieldBuilder;
1591
+ }();
1762
1592
  /**
1763
- * Creates a new described data field with all properties of the original one except for dynamically added groups.
1764
- * @param {module:described_field.DescribedDataField} describedDataField
1765
- * @returns {module:described_field.DescribedDataField}
1766
- * @memberof module:described_field
1767
- */
1768
- described_field.copyWithoutGroups = function (describedDataField) {
1769
- return new described_field.DescribedDataFieldBuilder().fromDescribedDataField(describedDataField).groupNames([]).build();
1593
+ * Creates a new described data field with all properties of the original one except for dynamically added groups.
1594
+ * @param {module:described_field.DescribedDataField} describedDataField
1595
+ * @returns {module:described_field.DescribedDataField}
1596
+ * @memberof module:described_field
1597
+ */ described_field.copyWithoutGroups = function(describedDataField) {
1598
+ return new described_field.DescribedDataFieldBuilder().fromDescribedDataField(describedDataField).groupNames([]).build();
1770
1599
  };
1771
- described_field.DescribedDataFieldGroup = (function () {
1772
- /**
1773
- * Adds groups to {@link module:described_field.DescribedDataField}s. These groups are dynamically added properties
1774
- * that contain an array of sub fields of the same type {@link module:described_field.DescribedDataField}s.
1775
- *
1776
- * @param {module:described_field.DescribedDataField} dataField
1777
- * @constructs DescribedDataFieldGroup
1778
- * @alias module:described_field.DescribedDataFieldGroup
1779
- * @example new described_field.DescribedDataFieldGroup(field).addGroupEntry("details", detailField);
1780
- */
1781
- function DescribedDataFieldGroup(dataField) {
1782
- this.dataField = dataField;
1783
- /**
1784
- * Adds an entry to the given group. If the group does not exist, it will be created.
1785
- * @function
1786
- * @param {String} groupName name of the group to which the entry will be added
1787
- * @param {module:described_field.DescribedDataField} describedField sub field that is added to the group
1788
- * @returns {DescribedDataFieldGroup}
1789
- */
1790
- this.addGroupEntry = function (groupName, describedField) {
1791
- this.addGroupEntries(groupName, [describedField]);
1792
- return this;
1793
- };
1600
+ described_field.DescribedDataFieldGroup = function() {
1794
1601
  /**
1795
- * Adds entries to the given group. If the group does not exist, it will be created.
1796
- * @function
1797
- * @param {String} groupName name of the group to which the entries will be added
1798
- * @param {module:described_field.DescribedDataField[]} describedFields sub fields that are added to the group
1799
- * @returns {DescribedDataFieldGroup}
1800
- */
1801
- this.addGroupEntries = function (groupName, describedFields) {
1802
- if (!groupName || groupName.length === 0) {
1803
- return this;
1804
- }
1805
- if (!describedFields || describedFields.length === 0) {
1806
- return this;
1807
- }
1808
- if (this.dataField[groupName] === undefined) {
1809
- this.dataField.groupNames.push(groupName);
1810
- this.dataField[groupName] = [];
1811
- }
1812
- var index;
1813
- var describedField;
1814
- for (index = 0; index < describedFields.length; index += 1) {
1815
- describedField = describedFields[index];
1816
- this.dataField[groupName].push(describedField);
1817
- }
1818
- return this;
1819
- };
1820
- }
1821
- return DescribedDataFieldGroup;
1822
- })();
1602
+ * Adds groups to {@link module:described_field.DescribedDataField}s. These groups are dynamically added properties
1603
+ * that contain an array of sub fields of the same type {@link module:described_field.DescribedDataField}s.
1604
+ *
1605
+ * @param {module:described_field.DescribedDataField} dataField
1606
+ * @constructs DescribedDataFieldGroup
1607
+ * @alias module:described_field.DescribedDataFieldGroup
1608
+ * @example new described_field.DescribedDataFieldGroup(field).addGroupEntry("details", detailField);
1609
+ */ function DescribedDataFieldGroup(dataField) {
1610
+ this.dataField = dataField;
1611
+ /**
1612
+ * Adds an entry to the given group. If the group does not exist, it will be created.
1613
+ * @function
1614
+ * @param {String} groupName name of the group to which the entry will be added
1615
+ * @param {module:described_field.DescribedDataField} describedField sub field that is added to the group
1616
+ * @returns {DescribedDataFieldGroup}
1617
+ */ this.addGroupEntry = function(groupName, describedField) {
1618
+ this.addGroupEntries(groupName, [
1619
+ describedField
1620
+ ]);
1621
+ return this;
1622
+ };
1623
+ /**
1624
+ * Adds entries to the given group. If the group does not exist, it will be created.
1625
+ * @function
1626
+ * @param {String} groupName name of the group to which the entries will be added
1627
+ * @param {module:described_field.DescribedDataField[]} describedFields sub fields that are added to the group
1628
+ * @returns {DescribedDataFieldGroup}
1629
+ */ this.addGroupEntries = function(groupName, describedFields) {
1630
+ if (!groupName || groupName.length === 0) return this;
1631
+ if (!describedFields || describedFields.length === 0) return this;
1632
+ if (this.dataField[groupName] === undefined) {
1633
+ this.dataField.groupNames.push(groupName);
1634
+ this.dataField[groupName] = [];
1635
+ }
1636
+ var index;
1637
+ var describedField;
1638
+ for(index = 0; index < describedFields.length; index += 1){
1639
+ describedField = describedFields[index];
1640
+ this.dataField[groupName].push(describedField);
1641
+ }
1642
+ return this;
1643
+ };
1644
+ }
1645
+ return DescribedDataFieldGroup;
1646
+ }();
1823
1647
 
1824
- },{}]},["7h0AO"], "7h0AO", "parcelRequire9661")
1648
+ },{}]},["jZ3Ya"], "jZ3Ya", "parcelRequirec1f2")
1825
1649