@ng-formworks/core 17.2.7 → 17.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +833 -0
  3. package/esm2022/lib/framework-library/framework-library.service.mjs +175 -0
  4. package/esm2022/lib/framework-library/framework.mjs +15 -0
  5. package/esm2022/lib/framework-library/no-framework.component.mjs +18 -0
  6. package/esm2022/lib/framework-library/no-framework.module.mjs +27 -0
  7. package/esm2022/lib/framework-library/no.framework.mjs +19 -0
  8. package/esm2022/lib/json-schema-form.component.mjs +765 -0
  9. package/esm2022/lib/json-schema-form.module.mjs +26 -0
  10. package/esm2022/lib/json-schema-form.service.mjs +676 -0
  11. package/esm2022/lib/locale/de-validation-messages.mjs +60 -0
  12. package/esm2022/lib/locale/en-validation-messages.mjs +60 -0
  13. package/esm2022/lib/locale/es-validation-messages.mjs +57 -0
  14. package/esm2022/lib/locale/fr-validation-messages.mjs +60 -0
  15. package/esm2022/lib/locale/index.mjs +8 -0
  16. package/esm2022/lib/locale/it-validation-messages.mjs +60 -0
  17. package/esm2022/lib/locale/pt-validation-messages.mjs +60 -0
  18. package/esm2022/lib/locale/zh-validation-messages.mjs +60 -0
  19. package/esm2022/lib/shared/convert-schema-to-draft6.function.mjs +300 -0
  20. package/esm2022/lib/shared/form-group.functions.mjs +442 -0
  21. package/esm2022/lib/shared/format-regex.constants.mjs +54 -0
  22. package/esm2022/lib/shared/index.mjs +12 -0
  23. package/esm2022/lib/shared/json-schema.functions.mjs +784 -0
  24. package/esm2022/lib/shared/json.validators.mjs +884 -0
  25. package/esm2022/lib/shared/jsonpointer.functions.mjs +1026 -0
  26. package/esm2022/lib/shared/layout.functions.mjs +1154 -0
  27. package/esm2022/lib/shared/merge-schemas.function.mjs +345 -0
  28. package/esm2022/lib/shared/utility.functions.mjs +380 -0
  29. package/esm2022/lib/shared/validator.functions.mjs +584 -0
  30. package/esm2022/lib/widget-library/add-reference.component.mjs +61 -0
  31. package/esm2022/lib/widget-library/button.component.mjs +72 -0
  32. package/esm2022/lib/widget-library/checkbox.component.mjs +105 -0
  33. package/esm2022/lib/widget-library/checkboxes.component.mjs +147 -0
  34. package/esm2022/lib/widget-library/file.component.mjs +35 -0
  35. package/esm2022/lib/widget-library/hidden.component.mjs +54 -0
  36. package/esm2022/lib/widget-library/index.mjs +55 -0
  37. package/esm2022/lib/widget-library/input.component.mjs +119 -0
  38. package/esm2022/lib/widget-library/message.component.mjs +38 -0
  39. package/esm2022/lib/widget-library/none.component.mjs +21 -0
  40. package/esm2022/lib/widget-library/number.component.mjs +123 -0
  41. package/esm2022/lib/widget-library/one-of.component.mjs +35 -0
  42. package/esm2022/lib/widget-library/orderable.directive.mjs +123 -0
  43. package/esm2022/lib/widget-library/radios.component.mjs +153 -0
  44. package/esm2022/lib/widget-library/root.component.mjs +79 -0
  45. package/esm2022/lib/widget-library/section.component.mjs +199 -0
  46. package/esm2022/lib/widget-library/select-framework.component.mjs +51 -0
  47. package/esm2022/lib/widget-library/select-widget.component.mjs +46 -0
  48. package/esm2022/lib/widget-library/select.component.mjs +150 -0
  49. package/esm2022/lib/widget-library/submit.component.mjs +82 -0
  50. package/esm2022/lib/widget-library/tab.component.mjs +41 -0
  51. package/esm2022/lib/widget-library/tabs.component.mjs +108 -0
  52. package/esm2022/lib/widget-library/template.component.mjs +46 -0
  53. package/esm2022/lib/widget-library/textarea.component.mjs +104 -0
  54. package/esm2022/lib/widget-library/widget-library.module.mjs +42 -0
  55. package/esm2022/lib/widget-library/widget-library.service.mjs +226 -0
  56. package/esm2022/ng-formworks-core.mjs +5 -0
  57. package/esm2022/public_api.mjs +13 -0
  58. package/fesm2022/ng-formworks-core.mjs +10147 -0
  59. package/fesm2022/ng-formworks-core.mjs.map +1 -0
  60. package/index.d.ts +5 -0
  61. package/lib/framework-library/framework-library.service.d.ts +55 -0
  62. package/lib/framework-library/framework.d.ts +13 -0
  63. package/lib/framework-library/no-framework.component.d.ts +8 -0
  64. package/lib/framework-library/no-framework.module.d.ts +9 -0
  65. package/lib/framework-library/no.framework.d.ts +10 -0
  66. package/lib/json-schema-form.component.d.ts +218 -0
  67. package/lib/json-schema-form.module.d.ts +11 -0
  68. package/lib/json-schema-form.service.d.ts +115 -0
  69. package/lib/locale/de-validation-messages.d.ts +1 -0
  70. package/lib/locale/en-validation-messages.d.ts +1 -0
  71. package/lib/locale/es-validation-messages.d.ts +1 -0
  72. package/lib/locale/fr-validation-messages.d.ts +1 -0
  73. package/{src/lib/locale/index.ts → lib/locale/index.d.ts} +7 -7
  74. package/lib/locale/it-validation-messages.d.ts +1 -0
  75. package/lib/locale/pt-validation-messages.d.ts +1 -0
  76. package/lib/locale/zh-validation-messages.d.ts +1 -0
  77. package/lib/shared/convert-schema-to-draft6.function.d.ts +21 -0
  78. package/lib/shared/form-group.functions.d.ts +100 -0
  79. package/lib/shared/format-regex.constants.d.ts +19 -0
  80. package/lib/shared/index.d.ts +9 -0
  81. package/lib/shared/json-schema.functions.d.ts +193 -0
  82. package/lib/shared/json.validators.d.ts +441 -0
  83. package/lib/shared/jsonpointer.functions.d.ts +416 -0
  84. package/lib/shared/layout.functions.d.ts +83 -0
  85. package/lib/shared/merge-schemas.function.d.ts +19 -0
  86. package/lib/shared/utility.functions.d.ts +165 -0
  87. package/{src/lib/shared/validator.functions.ts → lib/shared/validator.functions.d.ts} +364 -601
  88. package/lib/widget-library/add-reference.component.d.ts +20 -0
  89. package/lib/widget-library/button.component.d.ts +21 -0
  90. package/lib/widget-library/checkbox.component.d.ts +24 -0
  91. package/lib/widget-library/checkboxes.component.d.ts +24 -0
  92. package/lib/widget-library/file.component.d.ts +21 -0
  93. package/lib/widget-library/hidden.component.d.ts +19 -0
  94. package/{src/lib/widget-library/index.ts → lib/widget-library/index.d.ts} +47 -56
  95. package/lib/widget-library/input.component.d.ts +22 -0
  96. package/lib/widget-library/message.component.d.ts +15 -0
  97. package/lib/widget-library/none.component.d.ts +8 -0
  98. package/lib/widget-library/number.component.d.ts +25 -0
  99. package/lib/widget-library/one-of.component.d.ts +21 -0
  100. package/lib/widget-library/orderable.directive.d.ts +41 -0
  101. package/lib/widget-library/radios.component.d.ts +23 -0
  102. package/lib/widget-library/root.component.d.ts +17 -0
  103. package/lib/widget-library/section.component.d.ts +19 -0
  104. package/lib/widget-library/select-framework.component.d.ts +18 -0
  105. package/lib/widget-library/select-widget.component.d.ts +18 -0
  106. package/lib/widget-library/select.component.d.ts +24 -0
  107. package/lib/widget-library/submit.component.d.ts +24 -0
  108. package/lib/widget-library/tab.component.d.ts +14 -0
  109. package/lib/widget-library/tabs.component.d.ts +20 -0
  110. package/lib/widget-library/template.component.d.ts +18 -0
  111. package/lib/widget-library/textarea.component.d.ts +21 -0
  112. package/lib/widget-library/widget-library.module.d.ts +31 -0
  113. package/lib/widget-library/widget-library.service.d.ts +22 -0
  114. package/package.json +64 -53
  115. package/{src/public_api.ts → public_api.d.ts} +9 -21
  116. package/karma.conf.js +0 -46
  117. package/ng-package.json +0 -11
  118. package/src/lib/framework-library/framework-library.service.ts +0 -195
  119. package/src/lib/framework-library/framework.ts +0 -11
  120. package/src/lib/framework-library/no-framework.component.html +0 -2
  121. package/src/lib/framework-library/no-framework.component.ts +0 -11
  122. package/src/lib/framework-library/no-framework.module.ts +0 -18
  123. package/src/lib/framework-library/no.framework.ts +0 -11
  124. package/src/lib/json-schema-form.component.html +0 -7
  125. package/src/lib/json-schema-form.component.ts +0 -809
  126. package/src/lib/json-schema-form.module.ts +0 -17
  127. package/src/lib/json-schema-form.service.ts +0 -907
  128. package/src/lib/locale/de-validation-messages.ts +0 -58
  129. package/src/lib/locale/en-validation-messages.ts +0 -58
  130. package/src/lib/locale/es-validation-messages.ts +0 -55
  131. package/src/lib/locale/fr-validation-messages.ts +0 -58
  132. package/src/lib/locale/it-validation-messages.ts +0 -58
  133. package/src/lib/locale/pt-validation-messages.ts +0 -58
  134. package/src/lib/locale/zh-validation-messages.ts +0 -58
  135. package/src/lib/locale-dates/en-US.ts +0 -5
  136. package/src/lib/shared/convert-schema-to-draft6.function.ts +0 -321
  137. package/src/lib/shared/form-group.functions.ts +0 -522
  138. package/src/lib/shared/format-regex.constants.ts +0 -73
  139. package/src/lib/shared/index.ts +0 -40
  140. package/src/lib/shared/json-schema.functions.ts +0 -788
  141. package/src/lib/shared/json.validators.ts +0 -878
  142. package/src/lib/shared/jsonpointer.functions.ts +0 -1012
  143. package/src/lib/shared/jspointer.functions.json.spec.ts +0 -103
  144. package/src/lib/shared/layout.functions.ts +0 -1233
  145. package/src/lib/shared/merge-schemas.function.ts +0 -329
  146. package/src/lib/shared/utility.functions.ts +0 -373
  147. package/src/lib/shared/validator.functions.spec.ts +0 -55
  148. package/src/lib/widget-library/add-reference.component.ts +0 -59
  149. package/src/lib/widget-library/button.component.ts +0 -54
  150. package/src/lib/widget-library/checkbox.component.ts +0 -74
  151. package/src/lib/widget-library/checkboxes.component.ts +0 -104
  152. package/src/lib/widget-library/file.component.ts +0 -36
  153. package/src/lib/widget-library/hidden.component.ts +0 -39
  154. package/src/lib/widget-library/input.component.ts +0 -76
  155. package/src/lib/widget-library/message.component.ts +0 -29
  156. package/src/lib/widget-library/none.component.ts +0 -12
  157. package/src/lib/widget-library/number.component.ts +0 -79
  158. package/src/lib/widget-library/one-of.component.ts +0 -36
  159. package/src/lib/widget-library/orderable.directive.ts +0 -130
  160. package/src/lib/widget-library/radios.component.ts +0 -101
  161. package/src/lib/widget-library/root.component.ts +0 -78
  162. package/src/lib/widget-library/section.component.ts +0 -133
  163. package/src/lib/widget-library/select-framework.component.ts +0 -50
  164. package/src/lib/widget-library/select-widget.component.ts +0 -46
  165. package/src/lib/widget-library/select.component.ts +0 -96
  166. package/src/lib/widget-library/submit.component.ts +0 -68
  167. package/src/lib/widget-library/tab.component.ts +0 -29
  168. package/src/lib/widget-library/tabs.component.ts +0 -83
  169. package/src/lib/widget-library/template.component.ts +0 -52
  170. package/src/lib/widget-library/textarea.component.ts +0 -68
  171. package/src/lib/widget-library/widget-library.module.ts +0 -13
  172. package/src/lib/widget-library/widget-library.service.ts +0 -234
  173. package/src/test.ts +0 -18
  174. package/tsconfig.lib.json +0 -25
  175. package/tsconfig.lib.prod.json +0 -9
  176. package/tsconfig.spec.json +0 -17
  177. package/tslint.json +0 -11
@@ -1,1012 +0,0 @@
1
- import {
2
- cleanValueOfQuotes,
3
- copy,
4
- ExpressionType,
5
- getExpressionType,
6
- getKeyAndValueByExpressionType,
7
- hasOwn,
8
- isEqual,
9
- isNotEqual,
10
- isNotExpression
11
- } from './utility.functions';
12
- import {Injectable} from '@angular/core';
13
- import {isArray, isDefined, isEmpty, isMap, isNumber, isObject, isString} from './validator.functions';
14
-
15
- /**
16
- * 'JsonPointer' class
17
- *
18
- * Some utilities for using JSON Pointers with JSON objects
19
- * https://tools.ietf.org/html/rfc6901
20
- *
21
- * get, getCopy, getFirst, set, setCopy, insert, insertCopy, remove, has, dict,
22
- * forEachDeep, forEachDeepCopy, escape, unescape, parse, compile, toKey,
23
- * isJsonPointer, isSubPointer, toIndexedPointer, toGenericPointer,
24
- * toControlPointer, toSchemaPointer, toDataPointer, parseObjectPath
25
- *
26
- * Some functions based on manuelstofer's json-pointer utilities
27
- * https://github.com/manuelstofer/json-pointer
28
- */
29
- export type Pointer = string | string[];
30
-
31
- @Injectable()
32
- export class JsonPointer {
33
-
34
- /**
35
- * 'get' function
36
- *
37
- * Uses a JSON Pointer to retrieve a value from an object.
38
- *
39
- * // { object } object - Object to get value from
40
- * // { Pointer } pointer - JSON Pointer (string or array)
41
- * // { number = 0 } startSlice - Zero-based index of first Pointer key to use
42
- * // { number } endSlice - Zero-based index of last Pointer key to use
43
- * // { boolean = false } getBoolean - Return only true or false?
44
- * // { boolean = false } errors - Show error if not found?
45
- * // { object } - Located value (or true or false if getBoolean = true)
46
- */
47
- static get(
48
- object, pointer, startSlice = 0, endSlice: number = null,
49
- getBoolean = false, errors = false
50
- ) {
51
- if (object === null) { return getBoolean ? false : undefined; }
52
- let keyArray: any[] = this.parse(pointer, errors);
53
- if (typeof object === 'object' && keyArray !== null) {
54
- let subObject = object;
55
- if (startSlice >= keyArray.length || endSlice <= -keyArray.length) { return object; }
56
- if (startSlice <= -keyArray.length) { startSlice = 0; }
57
- if (!isDefined(endSlice) || endSlice >= keyArray.length) { endSlice = keyArray.length; }
58
- keyArray = keyArray.slice(startSlice, endSlice);
59
- for (let key of keyArray) {
60
- if (key === '-' && isArray(subObject) && subObject.length) {
61
- key = subObject.length - 1;
62
- }
63
- if (isMap(subObject) && subObject.has(key)) {
64
- subObject = subObject.get(key);
65
- } else if (typeof subObject === 'object' && subObject !== null &&
66
- hasOwn(subObject, key)
67
- ) {
68
- subObject = subObject[key];
69
- } else {
70
- const evaluatedExpression = JsonPointer.evaluateExpression(subObject, key);
71
- if (evaluatedExpression.passed) {
72
- subObject = evaluatedExpression.key ? subObject[evaluatedExpression.key] : subObject;
73
- } else {
74
- this.logErrors(errors, key, pointer, object);
75
- return getBoolean ? false : undefined;
76
- }
77
- }
78
- }
79
- return getBoolean ? true : subObject;
80
- }
81
- if (errors && keyArray === null) {
82
- console.error(`get error: Invalid JSON Pointer: ${pointer}`);
83
- }
84
- if (errors && typeof object !== 'object') {
85
- console.error('get error: Invalid object:');
86
- console.error(object);
87
- }
88
- return getBoolean ? false : undefined;
89
- }
90
-
91
- private static logErrors(errors, key, pointer, object) {
92
- if (errors) {
93
- console.error(`get error: "${key}" key not found in object.`);
94
- console.error(pointer);
95
- console.error(object);
96
- }
97
- }
98
-
99
- /**
100
- * Evaluates conditional expression in form of `model.<property>==<value>` or
101
- * `model.<property>!=<value>` where the first one means that the value must match to be
102
- * shown in a form, while the former shows the property only when the property value is not
103
- * set, or does not equal the given value.
104
- *
105
- * // { subObject } subObject - an object containing the data values of properties
106
- * // { key } key - the key from the for loop in a form of `<property>==<value>`
107
- *
108
- * Returns the object with two properties. The property passed informs whether
109
- * the expression evaluated successfully and the property key returns either the same
110
- * key if it is not contained inside the subObject or the key of the property if it is contained.
111
- */
112
- static evaluateExpression(subObject: Object, key: any) {
113
- const defaultResult = {passed: false, key: key};
114
- const keysAndExpression = this.parseKeysAndExpression(key, subObject);
115
- if (!keysAndExpression) {
116
- return defaultResult;
117
- }
118
-
119
- const ownCheckResult = this.doOwnCheckResult(subObject, keysAndExpression);
120
- if (ownCheckResult) {
121
- return ownCheckResult;
122
- }
123
-
124
- const cleanedValue = cleanValueOfQuotes(keysAndExpression.keyAndValue[1]);
125
-
126
- const evaluatedResult = this.performExpressionOnValue(keysAndExpression, cleanedValue, subObject);
127
- if (evaluatedResult) {
128
- return evaluatedResult;
129
- }
130
-
131
- return defaultResult;
132
- }
133
-
134
- /**
135
- * Performs the actual evaluation on the given expression with given values and keys.
136
- * // { cleanedValue } cleanedValue - the given valued cleaned of quotes if it had any
137
- * // { subObject } subObject - the object with properties values
138
- * // { keysAndExpression } keysAndExpression - an object holding the expressions with
139
- */
140
- private static performExpressionOnValue(keysAndExpression: any, cleanedValue: String, subObject: Object) {
141
- const propertyByKey = subObject[keysAndExpression.keyAndValue[0]];
142
- if (this.doComparisonByExpressionType(keysAndExpression.expressionType, propertyByKey, cleanedValue)) {
143
- return {passed: true, key: keysAndExpression.keyAndValue[0]};
144
- }
145
-
146
- return null;
147
- }
148
-
149
- private static doComparisonByExpressionType(expressionType: ExpressionType, propertyByKey, cleanedValue: String): Boolean {
150
- if (isEqual(expressionType)) {
151
- return propertyByKey === cleanedValue;
152
- }
153
- if (isNotEqual(expressionType)) {
154
- return propertyByKey !== cleanedValue;
155
- }
156
- return false;
157
- }
158
-
159
- /**
160
- * Does the checks when the parsed key is actually no a property inside subObject.
161
- * That would mean that the equal comparison makes no sense and thus the negative result
162
- * is returned, and the not equal comparison is not necessary because it doesn't equal
163
- * obviously. Returns null when the given key is a real property inside the subObject.
164
- * // { subObject } subObject - the object with properties values
165
- * // { keysAndExpression } keysAndExpression - an object holding the expressions with
166
- * the associated keys.
167
- */
168
- private static doOwnCheckResult(subObject: Object, keysAndExpression) {
169
- let ownCheckResult = null;
170
- if (!hasOwn(subObject, keysAndExpression.keyAndValue[0])) {
171
- if (isEqual(keysAndExpression.expressionType)) {
172
- ownCheckResult = {passed: false, key: null};
173
- }
174
- if (isNotEqual(keysAndExpression.expressionType)) {
175
- ownCheckResult = {passed: true, key: null};
176
- }
177
- }
178
- return ownCheckResult;
179
- }
180
-
181
- /**
182
- * Does the basic checks and tries to parse an expression and a pair
183
- * of key and value.
184
- * // { key } key - the original for loop created value containing key and value in one string
185
- * // { subObject } subObject - the object with properties values
186
- */
187
- private static parseKeysAndExpression(key: string, subObject) {
188
- if (this.keyOrSubObjEmpty(key, subObject)) {
189
- return null;
190
- }
191
- const expressionType = getExpressionType(key.toString());
192
- if (isNotExpression(expressionType)) {
193
- return null;
194
- }
195
- const keyAndValue = getKeyAndValueByExpressionType(expressionType, key);
196
- if (!keyAndValue || !keyAndValue[0] || !keyAndValue[1]) {
197
- return null;
198
- }
199
- return {expressionType: expressionType, keyAndValue: keyAndValue};
200
- }
201
-
202
- private static keyOrSubObjEmpty(key: any, subObject: Object) {
203
- return !key || !subObject;
204
- }
205
-
206
- /**
207
- * 'getCopy' function
208
- *
209
- * Uses a JSON Pointer to deeply clone a value from an object.
210
- *
211
- * // { object } object - Object to get value from
212
- * // { Pointer } pointer - JSON Pointer (string or array)
213
- * // { number = 0 } startSlice - Zero-based index of first Pointer key to use
214
- * // { number } endSlice - Zero-based index of last Pointer key to use
215
- * // { boolean = false } getBoolean - Return only true or false?
216
- * // { boolean = false } errors - Show error if not found?
217
- * // { object } - Located value (or true or false if getBoolean = true)
218
- */
219
- static getCopy(
220
- object, pointer, startSlice = 0, endSlice: number = null,
221
- getBoolean = false, errors = false
222
- ) {
223
- const objectToCopy =
224
- this.get(object, pointer, startSlice, endSlice, getBoolean, errors);
225
- return this.forEachDeepCopy(objectToCopy);
226
- }
227
-
228
- /**
229
- * 'getFirst' function
230
- *
231
- * Takes an array of JSON Pointers and objects,
232
- * checks each object for a value specified by the pointer,
233
- * and returns the first value found.
234
- *
235
- * // { [object, pointer][] } items - Array of objects and pointers to check
236
- * // { any = null } defaultValue - Value to return if nothing found
237
- * // { boolean = false } getCopy - Return a copy instead?
238
- * // - First value found
239
- */
240
- static getFirst(items, defaultValue: any = null, getCopy = false) {
241
- if (isEmpty(items)) { return; }
242
- if (isArray(items)) {
243
- for (const item of items) {
244
- if (isEmpty(item)) { continue; }
245
- if (isArray(item) && item.length >= 2) {
246
- if (isEmpty(item[0]) || isEmpty(item[1])) { continue; }
247
- const value = getCopy ?
248
- this.getCopy(item[0], item[1]) :
249
- this.get(item[0], item[1]);
250
- if (value) { return value; }
251
- continue;
252
- }
253
- console.error('getFirst error: Input not in correct format.\n' +
254
- 'Should be: [ [ object1, pointer1 ], [ object 2, pointer2 ], etc... ]');
255
- return;
256
- }
257
- return defaultValue;
258
- }
259
- if (isMap(items)) {
260
- for (const [object, pointer] of items) {
261
- if (object === null || !this.isJsonPointer(pointer)) { continue; }
262
- const value = getCopy ?
263
- this.getCopy(object, pointer) :
264
- this.get(object, pointer);
265
- if (value) { return value; }
266
- }
267
- return defaultValue;
268
- }
269
- console.error('getFirst error: Input not in correct format.\n' +
270
- 'Should be: [ [ object1, pointer1 ], [ object 2, pointer2 ], etc... ]');
271
- return defaultValue;
272
- }
273
-
274
- /**
275
- * 'getFirstCopy' function
276
- *
277
- * Similar to getFirst, but always returns a copy.
278
- *
279
- * // { [object, pointer][] } items - Array of objects and pointers to check
280
- * // { any = null } defaultValue - Value to return if nothing found
281
- * // - Copy of first value found
282
- */
283
- static getFirstCopy(items, defaultValue: any = null) {
284
- const firstCopy = this.getFirst(items, defaultValue, true);
285
- return firstCopy;
286
- }
287
-
288
- /**
289
- * 'set' function
290
- *
291
- * Uses a JSON Pointer to set a value on an object.
292
- * Also creates any missing sub objects or arrays to contain that value.
293
- *
294
- * If the optional fourth parameter is TRUE and the inner-most container
295
- * is an array, the function will insert the value as a new item at the
296
- * specified location in the array, rather than overwriting the existing
297
- * value (if any) at that location.
298
- *
299
- * So set([1, 2, 3], '/1', 4) => [1, 4, 3]
300
- * and
301
- * So set([1, 2, 3], '/1', 4, true) => [1, 4, 2, 3]
302
- *
303
- * // { object } object - The object to set value in
304
- * // { Pointer } pointer - The JSON Pointer (string or array)
305
- * // value - The new value to set
306
- * // { boolean } insert - insert value?
307
- * // { object } - The original object, modified with the set value
308
- */
309
- static set(object, pointer, value, insert = false) {
310
- const keyArray = this.parse(pointer);
311
- if (keyArray !== null && keyArray.length) {
312
- let subObject = object;
313
- for (let i = 0; i < keyArray.length - 1; ++i) {
314
- let key = keyArray[i];
315
- if (key === '-' && isArray(subObject)) {
316
- key = subObject.length;
317
- }
318
- if (isMap(subObject) && subObject.has(key)) {
319
- subObject = subObject.get(key);
320
- } else {
321
- if (!hasOwn(subObject, key)) {
322
- subObject[key] = (keyArray[i + 1].match(/^(\d+|-)$/)) ? [] : {};
323
- }
324
- subObject = subObject[key];
325
- }
326
- }
327
- const lastKey = keyArray[keyArray.length - 1];
328
- if (isArray(subObject) && lastKey === '-') {
329
- subObject.push(value);
330
- } else if (insert && isArray(subObject) && !isNaN(+lastKey)) {
331
- subObject.splice(lastKey, 0, value);
332
- } else if (isMap(subObject)) {
333
- subObject.set(lastKey, value);
334
- } else {
335
- subObject[lastKey] = value;
336
- }
337
- return object;
338
- }
339
- console.error(`set error: Invalid JSON Pointer: ${pointer}`);
340
- return object;
341
- }
342
-
343
- /**
344
- * 'setCopy' function
345
- *
346
- * Copies an object and uses a JSON Pointer to set a value on the copy.
347
- * Also creates any missing sub objects or arrays to contain that value.
348
- *
349
- * If the optional fourth parameter is TRUE and the inner-most container
350
- * is an array, the function will insert the value as a new item at the
351
- * specified location in the array, rather than overwriting the existing value.
352
- *
353
- * // { object } object - The object to copy and set value in
354
- * // { Pointer } pointer - The JSON Pointer (string or array)
355
- * // value - The value to set
356
- * // { boolean } insert - insert value?
357
- * // { object } - The new object with the set value
358
- */
359
- static setCopy(object, pointer, value, insert = false) {
360
- const keyArray = this.parse(pointer);
361
- if (keyArray !== null) {
362
- const newObject = copy(object);
363
- let subObject = newObject;
364
- for (let i = 0; i < keyArray.length - 1; ++i) {
365
- let key = keyArray[i];
366
- if (key === '-' && isArray(subObject)) {
367
- key = subObject.length;
368
- }
369
- if (isMap(subObject) && subObject.has(key)) {
370
- subObject.set(key, copy(subObject.get(key)));
371
- subObject = subObject.get(key);
372
- } else {
373
- if (!hasOwn(subObject, key)) {
374
- subObject[key] = (keyArray[i + 1].match(/^(\d+|-)$/)) ? [] : {};
375
- }
376
- subObject[key] = copy(subObject[key]);
377
- subObject = subObject[key];
378
- }
379
- }
380
- const lastKey = keyArray[keyArray.length - 1];
381
- if (isArray(subObject) && lastKey === '-') {
382
- subObject.push(value);
383
- } else if (insert && isArray(subObject) && !isNaN(+lastKey)) {
384
- subObject.splice(lastKey, 0, value);
385
- } else if (isMap(subObject)) {
386
- subObject.set(lastKey, value);
387
- } else {
388
- subObject[lastKey] = value;
389
- }
390
- return newObject;
391
- }
392
- console.error(`setCopy error: Invalid JSON Pointer: ${pointer}`);
393
- return object;
394
- }
395
-
396
- /**
397
- * 'insert' function
398
- *
399
- * Calls 'set' with insert = TRUE
400
- *
401
- * // { object } object - object to insert value in
402
- * // { Pointer } pointer - JSON Pointer (string or array)
403
- * // value - value to insert
404
- * // { object }
405
- */
406
- static insert(object, pointer, value) {
407
- const updatedObject = this.set(object, pointer, value, true);
408
- return updatedObject;
409
- }
410
-
411
- /**
412
- * 'insertCopy' function
413
- *
414
- * Calls 'setCopy' with insert = TRUE
415
- *
416
- * // { object } object - object to insert value in
417
- * // { Pointer } pointer - JSON Pointer (string or array)
418
- * // value - value to insert
419
- * // { object }
420
- */
421
- static insertCopy(object, pointer, value) {
422
- const updatedObject = this.setCopy(object, pointer, value, true);
423
- return updatedObject;
424
- }
425
-
426
- /**
427
- * 'remove' function
428
- *
429
- * Uses a JSON Pointer to remove a key and its attribute from an object
430
- *
431
- * // { object } object - object to delete attribute from
432
- * // { Pointer } pointer - JSON Pointer (string or array)
433
- * // { object }
434
- */
435
- static remove(object, pointer) {
436
- const keyArray = this.parse(pointer);
437
- if (keyArray !== null && keyArray.length) {
438
- let lastKey = keyArray.pop();
439
- const parentObject = this.get(object, keyArray);
440
- if (isArray(parentObject)) {
441
- if (lastKey === '-') { lastKey = parentObject.length - 1; }
442
- parentObject.splice(lastKey, 1);
443
- } else if (isObject(parentObject)) {
444
- delete parentObject[lastKey];
445
- }
446
- return object;
447
- }
448
- console.error(`remove error: Invalid JSON Pointer: ${pointer}`);
449
- return object;
450
- }
451
-
452
- /**
453
- * 'has' function
454
- *
455
- * Tests if an object has a value at the location specified by a JSON Pointer
456
- *
457
- * // { object } object - object to chek for value
458
- * // { Pointer } pointer - JSON Pointer (string or array)
459
- * // { boolean }
460
- */
461
- static has(object, pointer) {
462
- const hasValue = this.get(object, pointer, 0, null, true);
463
- return hasValue;
464
- }
465
-
466
- /**
467
- * 'dict' function
468
- *
469
- * Returns a (pointer -> value) dictionary for an object
470
- *
471
- * // { object } object - The object to create a dictionary from
472
- * // { object } - The resulting dictionary object
473
- */
474
- static dict(object) {
475
- const results: any = {};
476
- this.forEachDeep(object, (value, pointer) => {
477
- if (typeof value !== 'object') { results[pointer] = value; }
478
- });
479
- return results;
480
- }
481
-
482
- /**
483
- * 'forEachDeep' function
484
- *
485
- * Iterates over own enumerable properties of an object or items in an array
486
- * and invokes an iteratee function for each key/value or index/value pair.
487
- * By default, iterates over items within objects and arrays after calling
488
- * the iteratee function on the containing object or array itself.
489
- *
490
- * The iteratee is invoked with three arguments: (value, pointer, rootObject),
491
- * where pointer is a JSON pointer indicating the location of the current
492
- * value within the root object, and rootObject is the root object initially
493
- * submitted to th function.
494
- *
495
- * If a third optional parameter 'bottomUp' is set to TRUE, the iterator
496
- * function will be called on sub-objects and arrays after being
497
- * called on their contents, rather than before, which is the default.
498
- *
499
- * This function can also optionally be called directly on a sub-object by
500
- * including optional 4th and 5th parameterss to specify the initial
501
- * root object and pointer.
502
- *
503
- * // { object } object - the initial object or array
504
- * // { (v: any, p?: string, o?: any) => any } function - iteratee function
505
- * // { boolean = false } bottomUp - optional, set to TRUE to reverse direction
506
- * // { object = object } rootObject - optional, root object or array
507
- * // { string = '' } pointer - optional, JSON Pointer to object within rootObject
508
- * // { object } - The modified object
509
- */
510
- static forEachDeep(
511
- object, fn: (v: any, p?: string, o?: any) => any = (v) => v,
512
- bottomUp = false, pointer = '', rootObject = object
513
- ) {
514
- if (typeof fn !== 'function') {
515
- console.error(`forEachDeep error: Iterator is not a function:`, fn);
516
- return;
517
- }
518
- if (!bottomUp) { fn(object, pointer, rootObject); }
519
- if (isObject(object) || isArray(object)) {
520
- for (const key of Object.keys(object)) {
521
- const newPointer = pointer + '/' + this.escape(key);
522
- this.forEachDeep(object[key], fn, bottomUp, newPointer, rootObject);
523
- }
524
- }
525
- if (bottomUp) { fn(object, pointer, rootObject); }
526
- }
527
-
528
- /**
529
- * 'forEachDeepCopy' function
530
- *
531
- * Similar to forEachDeep, but returns a copy of the original object, with
532
- * the same keys and indexes, but with values replaced with the result of
533
- * the iteratee function.
534
- *
535
- * // { object } object - the initial object or array
536
- * // { (v: any, k?: string, o?: any, p?: any) => any } function - iteratee function
537
- * // { boolean = false } bottomUp - optional, set to TRUE to reverse direction
538
- * // { object = object } rootObject - optional, root object or array
539
- * // { string = '' } pointer - optional, JSON Pointer to object within rootObject
540
- * // { object } - The copied object
541
- */
542
- static forEachDeepCopy(
543
- object, fn: (v: any, p?: string, o?: any) => any = (v) => v,
544
- bottomUp = false, pointer = '', rootObject = object
545
- ) {
546
- if (typeof fn !== 'function') {
547
- console.error(`forEachDeepCopy error: Iterator is not a function:`, fn);
548
- return null;
549
- }
550
- if (isObject(object) || isArray(object)) {
551
- let newObject = isArray(object) ? [ ...object ] : { ...object };
552
- if (!bottomUp) { newObject = fn(newObject, pointer, rootObject); }
553
- for (const key of Object.keys(newObject)) {
554
- const newPointer = pointer + '/' + this.escape(key);
555
- newObject[key] = this.forEachDeepCopy(
556
- newObject[key], fn, bottomUp, newPointer, rootObject
557
- );
558
- }
559
- if (bottomUp) { newObject = fn(newObject, pointer, rootObject); }
560
- return newObject;
561
- } else {
562
- return fn(object, pointer, rootObject);
563
- }
564
- }
565
-
566
- /**
567
- * 'escape' function
568
- *
569
- * Escapes a string reference key
570
- *
571
- * // { string } key - string key to escape
572
- * // { string } - escaped key
573
- */
574
- static escape(key) {
575
- const escaped = key.toString().replace(/~/g, '~0').replace(/\//g, '~1');
576
- return escaped;
577
- }
578
-
579
- /**
580
- * 'unescape' function
581
- *
582
- * Unescapes a string reference key
583
- *
584
- * // { string } key - string key to unescape
585
- * // { string } - unescaped key
586
- */
587
- static unescape(key) {
588
- const unescaped = key.toString().replace(/~1/g, '/').replace(/~0/g, '~');
589
- return unescaped;
590
- }
591
-
592
- /**
593
- * 'parse' function
594
- *
595
- * Converts a string JSON Pointer into a array of keys
596
- * (if input is already an an array of keys, it is returned unchanged)
597
- *
598
- * // { Pointer } pointer - JSON Pointer (string or array)
599
- * // { boolean = false } errors - Show error if invalid pointer?
600
- * // { string[] } - JSON Pointer array of keys
601
- */
602
- static parse(pointer, errors = false) {
603
- if (!this.isJsonPointer(pointer)) {
604
- if (errors) { console.error(`parse error: Invalid JSON Pointer: ${pointer}`); }
605
- return null;
606
- }
607
- if (isArray(pointer)) { return <string[]>pointer; }
608
- if (typeof pointer === 'string') {
609
- if ((<string>pointer)[0] === '#') { pointer = pointer.slice(1); }
610
- if (<string>pointer === '' || <string>pointer === '/') { return []; }
611
- return (<string>pointer).slice(1).split('/').map(this.unescape);
612
- }
613
- }
614
-
615
- /**
616
- * 'compile' function
617
- *
618
- * Converts an array of keys into a JSON Pointer string
619
- * (if input is already a string, it is normalized and returned)
620
- *
621
- * The optional second parameter is a default which will replace any empty keys.
622
- *
623
- * // { Pointer } pointer - JSON Pointer (string or array)
624
- * // { string | number = '' } defaultValue - Default value
625
- * // { boolean = false } errors - Show error if invalid pointer?
626
- * // { string } - JSON Pointer string
627
- */
628
- static compile(pointer, defaultValue = '', errors = false) {
629
- if (pointer === '#') { return ''; }
630
- if (!this.isJsonPointer(pointer)) {
631
- if (errors) { console.error(`compile error: Invalid JSON Pointer: ${pointer}`); }
632
- return null;
633
- }
634
- if (isArray(pointer)) {
635
- if ((<string[]>pointer).length === 0) { return ''; }
636
- return '/' + (<string[]>pointer).map(
637
- key => key === '' ? defaultValue : this.escape(key)
638
- ).join('/');
639
- }
640
- if (typeof pointer === 'string') {
641
- if (pointer[0] === '#') { pointer = pointer.slice(1); }
642
- return pointer;
643
- }
644
- }
645
-
646
- /**
647
- * 'toKey' function
648
- *
649
- * Extracts name of the final key from a JSON Pointer.
650
- *
651
- * // { Pointer } pointer - JSON Pointer (string or array)
652
- * // { boolean = false } errors - Show error if invalid pointer?
653
- * // { string } - the extracted key
654
- */
655
- static toKey(pointer, errors = false) {
656
- const keyArray = this.parse(pointer, errors);
657
- if (keyArray === null) { return null; }
658
- if (!keyArray.length) { return ''; }
659
- return keyArray[keyArray.length - 1];
660
- }
661
-
662
- /**
663
- * 'isJsonPointer' function
664
- *
665
- * Checks a string or array value to determine if it is a valid JSON Pointer.
666
- * Returns true if a string is empty, or starts with '/' or '#/'.
667
- * Returns true if an array contains only string values.
668
- *
669
- * // value - value to check
670
- * // { boolean } - true if value is a valid JSON Pointer, otherwise false
671
- */
672
- static isJsonPointer(value) {
673
- if (isArray(value)) {
674
- return value.every(key => typeof key === 'string');
675
- } else if (isString(value)) {
676
- if (value === '' || value === '#') { return true; }
677
- if (value[0] === '/' || value.slice(0, 2) === '#/') {
678
- return !/(~[^01]|~$)/g.test(value);
679
- }
680
- }
681
- return false;
682
- }
683
-
684
- /**
685
- * 'isSubPointer' function
686
- *
687
- * Checks whether one JSON Pointer is a subset of another.
688
- *
689
- * // { Pointer } shortPointer - potential subset JSON Pointer
690
- * // { Pointer } longPointer - potential superset JSON Pointer
691
- * // { boolean = false } trueIfMatching - return true if pointers match?
692
- * // { boolean = false } errors - Show error if invalid pointer?
693
- * // { boolean } - true if shortPointer is a subset of longPointer, false if not
694
- */
695
- static isSubPointer(
696
- shortPointer, longPointer, trueIfMatching = false, errors = false
697
- ) {
698
- if (!this.isJsonPointer(shortPointer) || !this.isJsonPointer(longPointer)) {
699
- if (errors) {
700
- let invalid = '';
701
- if (!this.isJsonPointer(shortPointer)) { invalid += ` 1: ${shortPointer}`; }
702
- if (!this.isJsonPointer(longPointer)) { invalid += ` 2: ${longPointer}`; }
703
- console.error(`isSubPointer error: Invalid JSON Pointer ${invalid}`);
704
- }
705
- return;
706
- }
707
- shortPointer = this.compile(shortPointer, '', errors);
708
- longPointer = this.compile(longPointer, '', errors);
709
- return shortPointer === longPointer ? trueIfMatching :
710
- `${shortPointer}/` === longPointer.slice(0, shortPointer.length + 1);
711
- }
712
-
713
- /**
714
- * 'toIndexedPointer' function
715
- *
716
- * Merges an array of numeric indexes and a generic pointer to create an
717
- * indexed pointer for a specific item.
718
- *
719
- * For example, merging the generic pointer '/foo/-/bar/-/baz' and
720
- * the array [4, 2] would result in the indexed pointer '/foo/4/bar/2/baz'
721
- *
722
- *
723
- * // { Pointer } genericPointer - The generic pointer
724
- * // { number[] } indexArray - The array of numeric indexes
725
- * // { Map<string, number> } arrayMap - An optional array map
726
- * // { string } - The merged pointer with indexes
727
- */
728
- static toIndexedPointer(
729
- genericPointer, indexArray, arrayMap: Map<string, number> = null
730
- ) {
731
- if (this.isJsonPointer(genericPointer) && isArray(indexArray)) {
732
- let indexedPointer = this.compile(genericPointer);
733
- if (isMap(arrayMap)) {
734
- let arrayIndex = 0;
735
- return indexedPointer.replace(/\/\-(?=\/|$)/g, (key, stringIndex) =>
736
- arrayMap.has((<string>indexedPointer).slice(0, stringIndex)) ?
737
- '/' + indexArray[arrayIndex++] : key
738
- );
739
- } else {
740
- for (const pointerIndex of indexArray) {
741
- indexedPointer = indexedPointer.replace('/-', '/' + pointerIndex);
742
- }
743
- return indexedPointer;
744
- }
745
- }
746
- if (!this.isJsonPointer(genericPointer)) {
747
- console.error(`toIndexedPointer error: Invalid JSON Pointer: ${genericPointer}`);
748
- }
749
- if (!isArray(indexArray)) {
750
- console.error(`toIndexedPointer error: Invalid indexArray: ${indexArray}`);
751
- }
752
- }
753
-
754
- /**
755
- * 'toGenericPointer' function
756
- *
757
- * Compares an indexed pointer to an array map and removes list array
758
- * indexes (but leaves tuple arrray indexes and all object keys, including
759
- * numeric keys) to create a generic pointer.
760
- *
761
- * For example, using the indexed pointer '/foo/1/bar/2/baz/3' and
762
- * the arrayMap [['/foo', 0], ['/foo/-/bar', 3], ['/foo/-/bar/-/baz', 0]]
763
- * would result in the generic pointer '/foo/-/bar/2/baz/-'
764
- * Using the indexed pointer '/foo/1/bar/4/baz/3' and the same arrayMap
765
- * would result in the generic pointer '/foo/-/bar/-/baz/-'
766
- * (the bar array has 3 tuple items, so index 2 is retained, but 4 is removed)
767
- *
768
- * The structure of the arrayMap is: [['path to array', number of tuple items]...]
769
- *
770
- *
771
- * // { Pointer } indexedPointer - The indexed pointer (array or string)
772
- * // { Map<string, number> } arrayMap - The optional array map (for preserving tuple indexes)
773
- * // { string } - The generic pointer with indexes removed
774
- */
775
- static toGenericPointer(indexedPointer, arrayMap = new Map<string, number>()) {
776
- if (this.isJsonPointer(indexedPointer) && isMap(arrayMap)) {
777
- const pointerArray = this.parse(indexedPointer);
778
- for (let i = 1; i < pointerArray.length; i++) {
779
- const subPointer = this.compile(pointerArray.slice(0, i));
780
- if (arrayMap.has(subPointer) &&
781
- arrayMap.get(subPointer) <= +pointerArray[i]
782
- ) {
783
- pointerArray[i] = '-';
784
- }
785
- }
786
- return this.compile(pointerArray);
787
- }
788
- if (!this.isJsonPointer(indexedPointer)) {
789
- console.error(`toGenericPointer error: invalid JSON Pointer: ${indexedPointer}`);
790
- }
791
- if (!isMap(arrayMap)) {
792
- console.error(`toGenericPointer error: invalid arrayMap: ${arrayMap}`);
793
- }
794
- }
795
-
796
- /**
797
- * 'toControlPointer' function
798
- *
799
- * Accepts a JSON Pointer for a data object and returns a JSON Pointer for the
800
- * matching control in an Angular FormGroup.
801
- *
802
- * // { Pointer } dataPointer - JSON Pointer (string or array) to a data object
803
- * // { FormGroup } formGroup - Angular FormGroup to get value from
804
- * // { boolean = false } controlMustExist - Only return if control exists?
805
- * // { Pointer } - JSON Pointer (string) to the formGroup object
806
- */
807
- static toControlPointer(dataPointer, formGroup, controlMustExist = false) {
808
- const dataPointerArray = this.parse(dataPointer);
809
- const controlPointerArray: string[] = [];
810
- let subGroup = formGroup;
811
- if (dataPointerArray !== null) {
812
- for (const key of dataPointerArray) {
813
- if (hasOwn(subGroup, 'controls')) {
814
- controlPointerArray.push('controls');
815
- subGroup = subGroup.controls;
816
- }
817
- if (isArray(subGroup) && (key === '-')) {
818
- controlPointerArray.push((subGroup.length - 1).toString());
819
- subGroup = subGroup[subGroup.length - 1];
820
- } else if (hasOwn(subGroup, key)) {
821
- controlPointerArray.push(key);
822
- subGroup = subGroup[key];
823
- } else if (controlMustExist) {
824
- console.error(`toControlPointer error: Unable to find "${key}" item in FormGroup.`);
825
- console.error(dataPointer);
826
- console.error(formGroup);
827
- return;
828
- } else {
829
- controlPointerArray.push(key);
830
- subGroup = { controls: {} };
831
- }
832
- }
833
- return this.compile(controlPointerArray);
834
- }
835
- console.error(`toControlPointer error: Invalid JSON Pointer: ${dataPointer}`);
836
- }
837
-
838
- /**
839
- * 'toSchemaPointer' function
840
- *
841
- * Accepts a JSON Pointer to a value inside a data object and a JSON schema
842
- * for that object.
843
- *
844
- * Returns a Pointer to the sub-schema for the value inside the object's schema.
845
- *
846
- * // { Pointer } dataPointer - JSON Pointer (string or array) to an object
847
- * // schema - JSON schema for the object
848
- * // { Pointer } - JSON Pointer (string) to the object's schema
849
- */
850
- static toSchemaPointer(dataPointer, schema) {
851
- if (this.isJsonPointer(dataPointer) && typeof schema === 'object') {
852
- const pointerArray = this.parse(dataPointer);
853
- if (!pointerArray.length) { return ''; }
854
- const firstKey = pointerArray.shift();
855
- if (schema.type === 'object' || schema.properties || schema.additionalProperties) {
856
- if ((schema.properties || {})[firstKey]) {
857
- return `/properties/${this.escape(firstKey)}` +
858
- this.toSchemaPointer(pointerArray, schema.properties[firstKey]);
859
- } else if (schema.additionalProperties) {
860
- return '/additionalProperties' +
861
- this.toSchemaPointer(pointerArray, schema.additionalProperties);
862
- }
863
- }
864
- if ((schema.type === 'array' || schema.items) &&
865
- (isNumber(firstKey) || firstKey === '-' || firstKey === '')
866
- ) {
867
- const arrayItem = firstKey === '-' || firstKey === '' ? 0 : +firstKey;
868
- if (isArray(schema.items)) {
869
- if (arrayItem < schema.items.length) {
870
- return '/items/' + arrayItem +
871
- this.toSchemaPointer(pointerArray, schema.items[arrayItem]);
872
- } else if (schema.additionalItems) {
873
- return '/additionalItems' +
874
- this.toSchemaPointer(pointerArray, schema.additionalItems);
875
- }
876
- } else if (isObject(schema.items)) {
877
- return '/items' + this.toSchemaPointer(pointerArray, schema.items);
878
- } else if (isObject(schema.additionalItems)) {
879
- return '/additionalItems' +
880
- this.toSchemaPointer(pointerArray, schema.additionalItems);
881
- }
882
- }
883
- console.error(`toSchemaPointer error: Data pointer ${dataPointer} ` +
884
- `not compatible with schema ${schema}`);
885
- return null;
886
- }
887
- if (!this.isJsonPointer(dataPointer)) {
888
- console.error(`toSchemaPointer error: Invalid JSON Pointer: ${dataPointer}`);
889
- }
890
- if (typeof schema !== 'object') {
891
- console.error(`toSchemaPointer error: Invalid JSON Schema: ${schema}`);
892
- }
893
- return null;
894
- }
895
-
896
- /**
897
- * 'toDataPointer' function
898
- *
899
- * Accepts a JSON Pointer to a sub-schema inside a JSON schema and the schema.
900
- *
901
- * If possible, returns a generic Pointer to the corresponding value inside
902
- * the data object described by the JSON schema.
903
- *
904
- * Returns null if the sub-schema is in an ambiguous location (such as
905
- * definitions or additionalProperties) where the corresponding value
906
- * location cannot be determined.
907
- *
908
- * // { Pointer } schemaPointer - JSON Pointer (string or array) to a JSON schema
909
- * // schema - the JSON schema
910
- * // { boolean = false } errors - Show errors?
911
- * // { Pointer } - JSON Pointer (string) to the value in the data object
912
- */
913
- static toDataPointer(schemaPointer, schema, errors = false) {
914
- if (this.isJsonPointer(schemaPointer) && typeof schema === 'object' &&
915
- this.has(schema, schemaPointer)
916
- ) {
917
- const pointerArray = this.parse(schemaPointer);
918
- if (!pointerArray.length) { return ''; }
919
- const firstKey = pointerArray.shift();
920
- if (firstKey === 'properties' ||
921
- (firstKey === 'items' && isArray(schema.items))
922
- ) {
923
- const secondKey = pointerArray.shift();
924
- const pointerSuffix = this.toDataPointer(pointerArray, schema[firstKey][secondKey]);
925
- return pointerSuffix === null ? null : '/' + secondKey + pointerSuffix;
926
- } else if (firstKey === 'additionalItems' ||
927
- (firstKey === 'items' && isObject(schema.items))
928
- ) {
929
- const pointerSuffix = this.toDataPointer(pointerArray, schema[firstKey]);
930
- return pointerSuffix === null ? null : '/-' + pointerSuffix;
931
- } else if (['allOf', 'anyOf', 'oneOf'].includes(firstKey)) {
932
- const secondKey = pointerArray.shift();
933
- return this.toDataPointer(pointerArray, schema[firstKey][secondKey]);
934
- } else if (firstKey === 'not') {
935
- return this.toDataPointer(pointerArray, schema[firstKey]);
936
- } else if (['contains', 'definitions', 'dependencies', 'additionalItems',
937
- 'additionalProperties', 'patternProperties', 'propertyNames'].includes(firstKey)
938
- ) {
939
- if (errors) { console.error(`toDataPointer error: Ambiguous location`); }
940
- }
941
- return '';
942
- }
943
- if (errors) {
944
- if (!this.isJsonPointer(schemaPointer)) {
945
- console.error(`toDataPointer error: Invalid JSON Pointer: ${schemaPointer}`);
946
- }
947
- if (typeof schema !== 'object') {
948
- console.error(`toDataPointer error: Invalid JSON Schema: ${schema}`);
949
- }
950
- if (typeof schema !== 'object') {
951
- console.error(`toDataPointer error: Pointer ${schemaPointer} invalid for Schema: ${schema}`);
952
- }
953
- }
954
- return null;
955
- }
956
-
957
- /**
958
- * 'parseObjectPath' function
959
- *
960
- * Parses a JavaScript object path into an array of keys, which
961
- * can then be passed to compile() to convert into a string JSON Pointer.
962
- *
963
- * Based on mike-marcacci's excellent objectpath parse function:
964
- * https://github.com/mike-marcacci/objectpath
965
- *
966
- * // { Pointer } path - The object path to parse
967
- * // { string[] } - The resulting array of keys
968
- */
969
- static parseObjectPath(path) {
970
- if (isArray(path)) { return <string[]>path; }
971
- if (this.isJsonPointer(path)) { return this.parse(path); }
972
- if (typeof path === 'string') {
973
- let index = 0;
974
- const parts: string[] = [];
975
- while (index < path.length) {
976
- const nextDot = path.indexOf('.', index);
977
- const nextOB = path.indexOf('[', index); // next open bracket
978
- if (nextDot === -1 && nextOB === -1) { // last item
979
- parts.push(path.slice(index));
980
- index = path.length;
981
- } else if (nextDot !== -1 && (nextDot < nextOB || nextOB === -1)) { // dot notation
982
- parts.push(path.slice(index, nextDot));
983
- index = nextDot + 1;
984
- } else { // bracket notation
985
- if (nextOB > index) {
986
- parts.push(path.slice(index, nextOB));
987
- index = nextOB;
988
- }
989
- const quote = path.charAt(nextOB + 1);
990
- if (quote === '"' || quote === '\'') { // enclosing quotes
991
- let nextCB = path.indexOf(quote + ']', nextOB); // next close bracket
992
- while (nextCB !== -1 && path.charAt(nextCB - 1) === '\\') {
993
- nextCB = path.indexOf(quote + ']', nextCB + 2);
994
- }
995
- if (nextCB === -1) { nextCB = path.length; }
996
- parts.push(path.slice(index + 2, nextCB)
997
- .replace(new RegExp('\\' + quote, 'g'), quote));
998
- index = nextCB + 2;
999
- } else { // no enclosing quotes
1000
- let nextCB = path.indexOf(']', nextOB); // next close bracket
1001
- if (nextCB === -1) { nextCB = path.length; }
1002
- parts.push(path.slice(index + 1, nextCB));
1003
- index = nextCB + 1;
1004
- }
1005
- if (path.charAt(index) === '.') { index++; }
1006
- }
1007
- }
1008
- return parts;
1009
- }
1010
- console.error('parseObjectPath error: Input object path must be a string.');
1011
- }
1012
- }