@ng-formworks/core 17.2.7 → 18.0.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 +834 -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 +1158 -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 +10151 -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 +66 -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,788 +0,0 @@
1
- import cloneDeep from 'lodash/cloneDeep';
2
- import { JsonPointer } from './jsonpointer.functions';
3
- import { mergeSchemas } from './merge-schemas.function';
4
- import { forEach, hasOwn, mergeFilteredObject } from './utility.functions';
5
- import {
6
- getType,
7
- hasValue,
8
- inArray,
9
- isArray,
10
- isNumber,
11
- isObject,
12
- isString
13
- } from './validator.functions';
14
-
15
-
16
- /**
17
- * JSON Schema function library:
18
- *
19
- * buildSchemaFromLayout: TODO: Write this function
20
- *
21
- * buildSchemaFromData:
22
- *
23
- * getFromSchema:
24
- *
25
- * removeRecursiveReferences:
26
- *
27
- * getInputType:
28
- *
29
- * checkInlineType:
30
- *
31
- * isInputRequired:
32
- *
33
- * updateInputOptions:
34
- *
35
- * getTitleMapFromOneOf:
36
- *
37
- * getControlValidators:
38
- *
39
- * resolveSchemaReferences:
40
- *
41
- * getSubSchema:
42
- *
43
- * combineAllOf:
44
- *
45
- * fixRequiredArrayProperties:
46
- */
47
-
48
- /**
49
- * 'buildSchemaFromLayout' function
50
- *
51
- * TODO: Build a JSON Schema from a JSON Form layout
52
- *
53
- * // layout - The JSON Form layout
54
- * // - The new JSON Schema
55
- */
56
- export function buildSchemaFromLayout(layout) {
57
- return;
58
- // let newSchema: any = { };
59
- // const walkLayout = (layoutItems: any[], callback: Function): any[] => {
60
- // let returnArray: any[] = [];
61
- // for (let layoutItem of layoutItems) {
62
- // const returnItem: any = callback(layoutItem);
63
- // if (returnItem) { returnArray = returnArray.concat(callback(layoutItem)); }
64
- // if (layoutItem.items) {
65
- // returnArray = returnArray.concat(walkLayout(layoutItem.items, callback));
66
- // }
67
- // }
68
- // return returnArray;
69
- // };
70
- // walkLayout(layout, layoutItem => {
71
- // let itemKey: string;
72
- // if (typeof layoutItem === 'string') {
73
- // itemKey = layoutItem;
74
- // } else if (layoutItem.key) {
75
- // itemKey = layoutItem.key;
76
- // }
77
- // if (!itemKey) { return; }
78
- // //
79
- // });
80
- }
81
-
82
- /**
83
- * 'buildSchemaFromData' function
84
- *
85
- * Build a JSON Schema from a data object
86
- *
87
- * // data - The data object
88
- * // { boolean = false } requireAllFields - Require all fields?
89
- * // { boolean = true } isRoot - is root
90
- * // - The new JSON Schema
91
- */
92
- export function buildSchemaFromData(
93
- data, requireAllFields = false, isRoot = true
94
- ) {
95
- const newSchema: any = {};
96
- const getFieldType = (value: any): string => {
97
- const fieldType = getType(value, 'strict');
98
- return { integer: 'number', null: 'string' }[fieldType] || fieldType;
99
- };
100
- const buildSubSchema = (value) =>
101
- buildSchemaFromData(value, requireAllFields, false);
102
- if (isRoot) { newSchema.$schema = 'http://json-schema.org/draft-06/schema#'; }
103
- newSchema.type = getFieldType(data);
104
- if (newSchema.type === 'object') {
105
- newSchema.properties = {};
106
- if (requireAllFields) { newSchema.required = []; }
107
- for (const key of Object.keys(data)) {
108
- newSchema.properties[key] = buildSubSchema(data[key]);
109
- if (requireAllFields) { newSchema.required.push(key); }
110
- }
111
- } else if (newSchema.type === 'array') {
112
- newSchema.items = data.map(buildSubSchema);
113
- // If all items are the same type, use an object for items instead of an array
114
- if ((new Set(data.map(getFieldType))).size === 1) {
115
- newSchema.items = newSchema.items.reduce((a, b) => ({ ...a, ...b }), {});
116
- }
117
- if (requireAllFields) { newSchema.minItems = 1; }
118
- }
119
- return newSchema;
120
- }
121
-
122
- /**
123
- * 'getFromSchema' function
124
- *
125
- * Uses a JSON Pointer for a value within a data object to retrieve
126
- * the schema for that value within schema for the data object.
127
- *
128
- * The optional third parameter can also be set to return something else:
129
- * 'schema' (default): the schema for the value indicated by the data pointer
130
- * 'parentSchema': the schema for the value's parent object or array
131
- * 'schemaPointer': a pointer to the value's schema within the object's schema
132
- * 'parentSchemaPointer': a pointer to the schema for the value's parent object or array
133
- *
134
- * // schema - The schema to get the sub-schema from
135
- * // { Pointer } dataPointer - JSON Pointer (string or array)
136
- * // { string = 'schema' } returnType - what to return?
137
- * // - The located sub-schema
138
- */
139
- export function getFromSchema(schema, dataPointer, returnType = 'schema') {
140
- const dataPointerArray: any[] = JsonPointer.parse(dataPointer);
141
- if (dataPointerArray === null) {
142
- console.error(`getFromSchema error: Invalid JSON Pointer: ${dataPointer}`);
143
- return null;
144
- }
145
- let subSchema = schema;
146
- const schemaPointer = [];
147
- const length = dataPointerArray.length;
148
- if (returnType.slice(0, 6) === 'parent') { dataPointerArray.length--; }
149
- for (let i = 0; i < length; ++i) {
150
- const parentSchema = subSchema;
151
- const key = dataPointerArray[i];
152
- let subSchemaFound = false;
153
- if (typeof subSchema !== 'object') {
154
- console.error(`getFromSchema error: Unable to find "${key}" key in schema.`);
155
- console.error(schema);
156
- console.error(dataPointer);
157
- return null;
158
- }
159
- if (subSchema.type === 'array' && (!isNaN(key) || key === '-')) {
160
- if (hasOwn(subSchema, 'items')) {
161
- if (isObject(subSchema.items)) {
162
- subSchemaFound = true;
163
- subSchema = subSchema.items;
164
- schemaPointer.push('items');
165
- } else if (isArray(subSchema.items)) {
166
- if (!isNaN(key) && subSchema.items.length >= +key) {
167
- subSchemaFound = true;
168
- subSchema = subSchema.items[+key];
169
- schemaPointer.push('items', key);
170
- }
171
- }
172
- }
173
- if (!subSchemaFound && isObject(subSchema.additionalItems)) {
174
- subSchemaFound = true;
175
- subSchema = subSchema.additionalItems;
176
- schemaPointer.push('additionalItems');
177
- } else if (subSchema.additionalItems !== false) {
178
- subSchemaFound = true;
179
- subSchema = { };
180
- schemaPointer.push('additionalItems');
181
- }
182
- } else if (subSchema.type === 'object') {
183
- if (isObject(subSchema.properties) && hasOwn(subSchema.properties, key)) {
184
- subSchemaFound = true;
185
- subSchema = subSchema.properties[key];
186
- schemaPointer.push('properties', key);
187
- } else if (isObject(subSchema.additionalProperties)) {
188
- subSchemaFound = true;
189
- subSchema = subSchema.additionalProperties;
190
- schemaPointer.push('additionalProperties');
191
- } else if (subSchema.additionalProperties !== false) {
192
- subSchemaFound = true;
193
- subSchema = { };
194
- schemaPointer.push('additionalProperties');
195
- }
196
- }
197
- if (!subSchemaFound) {
198
- console.error(`getFromSchema error: Unable to find "${key}" item in schema.`);
199
- console.error(schema);
200
- console.error(dataPointer);
201
- return;
202
- }
203
- }
204
- return returnType.slice(-7) === 'Pointer' ? schemaPointer : subSchema;
205
- }
206
-
207
- /**
208
- * 'removeRecursiveReferences' function
209
- *
210
- * Checks a JSON Pointer against a map of recursive references and returns
211
- * a JSON Pointer to the shallowest equivalent location in the same object.
212
- *
213
- * Using this functions enables an object to be constructed with unlimited
214
- * recursion, while maintaing a fixed set of metadata, such as field data types.
215
- * The object can grow as large as it wants, and deeply recursed nodes can
216
- * just refer to the metadata for their shallow equivalents, instead of having
217
- * to add additional redundant metadata for each recursively added node.
218
- *
219
- * Example:
220
- *
221
- * pointer: '/stuff/and/more/and/more/and/more/and/more/stuff'
222
- * recursiveRefMap: [['/stuff/and/more/and/more', '/stuff/and/more/']]
223
- * returned: '/stuff/and/more/stuff'
224
- *
225
- * // { Pointer } pointer -
226
- * // { Map<string, string> } recursiveRefMap -
227
- * // { Map<string, number> = new Map() } arrayMap - optional
228
- * // { string } -
229
- */
230
- export function removeRecursiveReferences(
231
- pointer, recursiveRefMap, arrayMap = new Map()
232
- ) {
233
- if (!pointer) { return ''; }
234
- let genericPointer =
235
- JsonPointer.toGenericPointer(JsonPointer.compile(pointer), arrayMap);
236
- if (genericPointer.indexOf('/') === -1) { return genericPointer; }
237
- let possibleReferences = true;
238
- while (possibleReferences) {
239
- possibleReferences = false;
240
- recursiveRefMap.forEach((toPointer, fromPointer) => {
241
- if (JsonPointer.isSubPointer(toPointer, fromPointer)) {
242
- while (JsonPointer.isSubPointer(fromPointer, genericPointer, true)) {
243
- genericPointer = JsonPointer.toGenericPointer(
244
- toPointer + genericPointer.slice(fromPointer.length), arrayMap
245
- );
246
- possibleReferences = true;
247
- }
248
- }
249
- });
250
- }
251
- return genericPointer;
252
- }
253
-
254
- /**
255
- * 'getInputType' function
256
- *
257
- * // schema
258
- * // { any = null } layoutNode
259
- * // { string }
260
- */
261
- export function getInputType(schema, layoutNode: any = null) {
262
- // x-schema-form = Angular Schema Form compatibility
263
- // widget & component = React Jsonschema Form compatibility
264
- const controlType = JsonPointer.getFirst([
265
- [schema, '/x-schema-form/type'],
266
- [schema, '/x-schema-form/widget/component'],
267
- [schema, '/x-schema-form/widget'],
268
- [schema, '/widget/component'],
269
- [schema, '/widget']
270
- ]);
271
- if (isString(controlType)) { return checkInlineType(controlType, schema, layoutNode); }
272
- let schemaType = schema.type;
273
- if (schemaType) {
274
- if (isArray(schemaType)) { // If multiple types listed, use most inclusive type
275
- schemaType =
276
- inArray('object', schemaType) && hasOwn(schema, 'properties') ? 'object' :
277
- inArray('array', schemaType) && hasOwn(schema, 'items') ? 'array' :
278
- inArray('array', schemaType) && hasOwn(schema, 'additionalItems') ? 'array' :
279
- inArray('string', schemaType) ? 'string' :
280
- inArray('number', schemaType) ? 'number' :
281
- inArray('integer', schemaType) ? 'integer' :
282
- inArray('boolean', schemaType) ? 'boolean' : 'unknown';
283
- }
284
- if (schemaType === 'boolean') { return 'checkbox'; }
285
- if (schemaType === 'object') {
286
- if (hasOwn(schema, 'properties') || hasOwn(schema, 'additionalProperties')) {
287
- return 'section';
288
- }
289
- // TODO: Figure out how to handle additionalProperties
290
- if (hasOwn(schema, '$ref')) { return '$ref'; }
291
- }
292
- if (schemaType === 'array') {
293
- const itemsObject = JsonPointer.getFirst([
294
- [schema, '/items'],
295
- [schema, '/additionalItems']
296
- ]) || {};
297
- return hasOwn(itemsObject, 'enum') && schema.maxItems !== 1 ?
298
- checkInlineType('checkboxes', schema, layoutNode) : 'array';
299
- }
300
- if (schemaType === 'null') { return 'none'; }
301
- if (JsonPointer.has(layoutNode, '/options/titleMap') ||
302
- hasOwn(schema, 'enum') || getTitleMapFromOneOf(schema, null, true)
303
- ) { return 'select'; }
304
- if (schemaType === 'number' || schemaType === 'integer') {
305
- return (schemaType === 'integer' || hasOwn(schema, 'multipleOf')) &&
306
- hasOwn(schema, 'maximum') && hasOwn(schema, 'minimum') ? 'range' : schemaType;
307
- }
308
- if (schemaType === 'string') {
309
- return {
310
- 'color': 'color',
311
- 'date': 'date',
312
- 'date-time': 'datetime-local',
313
- 'email': 'email',
314
- 'uri': 'url',
315
- }[schema.format] || 'text';
316
- }
317
- }
318
- if (hasOwn(schema, '$ref')) { return '$ref'; }
319
- if (isArray(schema.oneOf) || isArray(schema.anyOf)) { return 'one-of'; }
320
- console.error(`getInputType error: Unable to determine input type for ${schemaType}`);
321
- console.error('schema', schema);
322
- if (layoutNode) { console.error('layoutNode', layoutNode); }
323
- return 'none';
324
- }
325
-
326
- /**
327
- * 'checkInlineType' function
328
- *
329
- * Checks layout and schema nodes for 'inline: true', and converts
330
- * 'radios' or 'checkboxes' to 'radios-inline' or 'checkboxes-inline'
331
- *
332
- * // { string } controlType -
333
- * // schema -
334
- * // { any = null } layoutNode -
335
- * // { string }
336
- */
337
- export function checkInlineType(controlType, schema, layoutNode: any = null) {
338
- if (!isString(controlType) || (
339
- controlType.slice(0, 8) !== 'checkbox' && controlType.slice(0, 5) !== 'radio'
340
- )) {
341
- return controlType;
342
- }
343
- if (
344
- JsonPointer.getFirst([
345
- [layoutNode, '/inline'],
346
- [layoutNode, '/options/inline'],
347
- [schema, '/inline'],
348
- [schema, '/x-schema-form/inline'],
349
- [schema, '/x-schema-form/options/inline'],
350
- [schema, '/x-schema-form/widget/inline'],
351
- [schema, '/x-schema-form/widget/component/inline'],
352
- [schema, '/x-schema-form/widget/component/options/inline'],
353
- [schema, '/widget/inline'],
354
- [schema, '/widget/component/inline'],
355
- [schema, '/widget/component/options/inline'],
356
- ]) === true
357
- ) {
358
- return controlType.slice(0, 5) === 'radio' ?
359
- 'radios-inline' : 'checkboxes-inline';
360
- } else {
361
- return controlType;
362
- }
363
- }
364
-
365
- /**
366
- * 'isInputRequired' function
367
- *
368
- * Checks a JSON Schema to see if an item is required
369
- *
370
- * // schema - the schema to check
371
- * // { string } schemaPointer - the pointer to the item to check
372
- * // { boolean } - true if the item is required, false if not
373
- */
374
- export function isInputRequired(schema, schemaPointer) {
375
- if (!isObject(schema)) {
376
- console.error('isInputRequired error: Input schema must be an object.');
377
- return false;
378
- }
379
- const listPointerArray = JsonPointer.parse(schemaPointer);
380
- if (isArray(listPointerArray)) {
381
- if (!listPointerArray.length) { return schema.required === true; }
382
- const keyName = listPointerArray.pop();
383
- const nextToLastKey = listPointerArray[listPointerArray.length - 1];
384
- if (['properties', 'additionalProperties', 'patternProperties', 'items', 'additionalItems']
385
- .includes(nextToLastKey)
386
- ) {
387
- listPointerArray.pop();
388
- }
389
- const parentSchema = JsonPointer.get(schema, listPointerArray) || {};
390
- if (isArray(parentSchema.required)) {
391
- return parentSchema.required.includes(keyName);
392
- }
393
- if (parentSchema.type === 'array') {
394
- return hasOwn(parentSchema, 'minItems') &&
395
- isNumber(keyName) &&
396
- +parentSchema.minItems > +keyName;
397
- }
398
- }
399
- return false;
400
- }
401
-
402
- /**
403
- * 'updateInputOptions' function
404
- *
405
- * // layoutNode
406
- * // schema
407
- * // jsf
408
- * // { void }
409
- */
410
- export function updateInputOptions(layoutNode, schema, jsf) {
411
- if (!isObject(layoutNode) || !isObject(layoutNode.options)) { return; }
412
-
413
- // Set all option values in layoutNode.options
414
- const newOptions: any = { };
415
- const fixUiKeys = key => key.slice(0, 3).toLowerCase() === 'ui:' ? key.slice(3) : key;
416
- mergeFilteredObject(newOptions, jsf.formOptions.defaultWidgetOptions, [], fixUiKeys);
417
- [ [ JsonPointer.get(schema, '/ui:widget/options'), [] ],
418
- [ JsonPointer.get(schema, '/ui:widget'), [] ],
419
- [ schema, [
420
- 'additionalProperties', 'additionalItems', 'properties', 'items',
421
- 'required', 'type', 'x-schema-form', '$ref'
422
- ] ],
423
- [ JsonPointer.get(schema, '/x-schema-form/options'), [] ],
424
- [ JsonPointer.get(schema, '/x-schema-form'), ['items', 'options'] ],
425
- [ layoutNode, [
426
- '_id', '$ref', 'arrayItem', 'arrayItemType', 'dataPointer', 'dataType',
427
- 'items', 'key', 'name', 'options', 'recursiveReference', 'type', 'widget'
428
- ] ],
429
- [ layoutNode.options, [] ],
430
- ].forEach(([ object, excludeKeys ]) =>
431
- mergeFilteredObject(newOptions, object, excludeKeys, fixUiKeys)
432
- );
433
- if (!hasOwn(newOptions, 'titleMap')) {
434
- let newTitleMap: any = null;
435
- newTitleMap = getTitleMapFromOneOf(schema, newOptions.flatList);
436
- if (newTitleMap) { newOptions.titleMap = newTitleMap; }
437
- if (!hasOwn(newOptions, 'titleMap') && !hasOwn(newOptions, 'enum') && hasOwn(schema, 'items')) {
438
- if (JsonPointer.has(schema, '/items/titleMap')) {
439
- newOptions.titleMap = schema.items.titleMap;
440
- } else if (JsonPointer.has(schema, '/items/enum')) {
441
- newOptions.enum = schema.items.enum;
442
- if (!hasOwn(newOptions, 'enumNames') && JsonPointer.has(schema, '/items/enumNames')) {
443
- newOptions.enumNames = schema.items.enumNames;
444
- }
445
- } else if (JsonPointer.has(schema, '/items/oneOf')) {
446
- newTitleMap = getTitleMapFromOneOf(schema.items, newOptions.flatList);
447
- if (newTitleMap) { newOptions.titleMap = newTitleMap; }
448
- }
449
- }
450
- }
451
-
452
- // If schema type is integer, enforce by setting multipleOf = 1
453
- if (schema.type === 'integer' && !hasValue(newOptions.multipleOf)) {
454
- newOptions.multipleOf = 1;
455
- }
456
-
457
- // Copy any typeahead word lists to options.typeahead.source
458
- if (JsonPointer.has(newOptions, '/autocomplete/source')) {
459
- newOptions.typeahead = newOptions.autocomplete;
460
- } else if (JsonPointer.has(newOptions, '/tagsinput/source')) {
461
- newOptions.typeahead = newOptions.tagsinput;
462
- } else if (JsonPointer.has(newOptions, '/tagsinput/typeahead/source')) {
463
- newOptions.typeahead = newOptions.tagsinput.typeahead;
464
- }
465
-
466
- layoutNode.options = newOptions;
467
- }
468
-
469
- /**
470
- * 'getTitleMapFromOneOf' function
471
- *
472
- * // { schema } schema
473
- * // { boolean = null } flatList
474
- * // { boolean = false } validateOnly
475
- * // { validators }
476
- */
477
- export function getTitleMapFromOneOf(
478
- schema: any = {}, flatList: boolean = null, validateOnly = false
479
- ) {
480
- let titleMap = null;
481
- const oneOf = schema.oneOf || schema.anyOf || null;
482
- if (isArray(oneOf) && oneOf.every(item => item.title)) {
483
- if (oneOf.every(item => isArray(item.enum) && item.enum.length === 1)) {
484
- if (validateOnly) { return true; }
485
- titleMap = oneOf.map(item => ({ name: item.title, value: item.enum[0] }));
486
- } else if (oneOf.every(item => item.const)) {
487
- if (validateOnly) { return true; }
488
- titleMap = oneOf.map(item => ({ name: item.title, value: item.const }));
489
- }
490
-
491
- // if flatList !== false and some items have colons, make grouped map
492
- if (flatList !== false && (titleMap || [])
493
- .filter(title => ((title || {}).name || '').indexOf(': ')).length > 1
494
- ) {
495
-
496
- // Split name on first colon to create grouped map (name -> group: name)
497
- const newTitleMap = titleMap.map(title => {
498
- const [group, name] = title.name.split(/: (.+)/);
499
- return group && name ? { ...title, group, name } : title;
500
- });
501
-
502
- // If flatList === true or at least one group has multiple items, use grouped map
503
- if (flatList === true || newTitleMap.some((title, index) => index &&
504
- hasOwn(title, 'group') && title.group === newTitleMap[index - 1].group
505
- )) {
506
- titleMap = newTitleMap;
507
- }
508
- }
509
- }
510
- return validateOnly ? false : titleMap;
511
- }
512
-
513
- /**
514
- * 'getControlValidators' function
515
- *
516
- * // schema
517
- * // { validators }
518
- */
519
- export function getControlValidators(schema) {
520
- if (!isObject(schema)) { return null; }
521
- const validators: any = { };
522
- if (hasOwn(schema, 'type')) {
523
- switch (schema.type) {
524
- case 'string':
525
- forEach(['pattern', 'format', 'minLength', 'maxLength'], (prop) => {
526
- if (hasOwn(schema, prop)) { validators[prop] = [schema[prop]]; }
527
- });
528
- break;
529
- case 'number': case 'integer':
530
- forEach(['Minimum', 'Maximum'], (ucLimit) => {
531
- const eLimit = 'exclusive' + ucLimit;
532
- const limit = ucLimit.toLowerCase();
533
- if (hasOwn(schema, limit)) {
534
- const exclusive = hasOwn(schema, eLimit) && schema[eLimit] === true;
535
- validators[limit] = [schema[limit], exclusive];
536
- }
537
- });
538
- forEach(['multipleOf', 'type'], (prop) => {
539
- if (hasOwn(schema, prop)) { validators[prop] = [schema[prop]]; }
540
- });
541
- break;
542
- case 'object':
543
- forEach(['minProperties', 'maxProperties', 'dependencies'], (prop) => {
544
- if (hasOwn(schema, prop)) { validators[prop] = [schema[prop]]; }
545
- });
546
- break;
547
- case 'array':
548
- forEach(['minItems', 'maxItems', 'uniqueItems'], (prop) => {
549
- if (hasOwn(schema, prop)) { validators[prop] = [schema[prop]]; }
550
- });
551
- break;
552
- }
553
- }
554
- if (hasOwn(schema, 'enum')) { validators.enum = [schema.enum]; }
555
- return validators;
556
- }
557
-
558
- /**
559
- * 'resolveSchemaReferences' function
560
- *
561
- * Find all $ref links in schema and save links and referenced schemas in
562
- * schemaRefLibrary, schemaRecursiveRefMap, and dataRecursiveRefMap
563
- *
564
- * // schema
565
- * // schemaRefLibrary
566
- * // { Map<string, string> } schemaRecursiveRefMap
567
- * // { Map<string, string> } dataRecursiveRefMap
568
- * // { Map<string, number> } arrayMap
569
- * //
570
- */
571
- export function resolveSchemaReferences(
572
- schema, schemaRefLibrary, schemaRecursiveRefMap, dataRecursiveRefMap, arrayMap
573
- ) {
574
- if (!isObject(schema)) {
575
- console.error('resolveSchemaReferences error: schema must be an object.');
576
- return;
577
- }
578
- const refLinks = new Set<string>();
579
- const refMapSet = new Set<string>();
580
- const refMap = new Map<string, string>();
581
- const recursiveRefMap = new Map<string, string>();
582
- const refLibrary: any = {};
583
-
584
- // Search schema for all $ref links, and build full refLibrary
585
- JsonPointer.forEachDeep(schema, (subSchema, subSchemaPointer) => {
586
- if (hasOwn(subSchema, '$ref') && isString(subSchema['$ref'])) {
587
- const refPointer = JsonPointer.compile(subSchema['$ref']);
588
- refLinks.add(refPointer);
589
- refMapSet.add(subSchemaPointer + '~~' + refPointer);
590
- refMap.set(subSchemaPointer, refPointer);
591
- }
592
- });
593
- refLinks.forEach(ref => refLibrary[ref] = getSubSchema(schema, ref));
594
-
595
- // Follow all ref links and save in refMapSet,
596
- // to find any multi-link recursive refernces
597
- let checkRefLinks = true;
598
- while (checkRefLinks) {
599
- checkRefLinks = false;
600
- Array.from(refMap).forEach(([fromRef1, toRef1]) => Array.from(refMap)
601
- .filter(([fromRef2, toRef2]) =>
602
- JsonPointer.isSubPointer(toRef1, fromRef2, true) &&
603
- !JsonPointer.isSubPointer(toRef2, toRef1, true) &&
604
- !refMapSet.has(fromRef1 + fromRef2.slice(toRef1.length) + '~~' + toRef2)
605
- )
606
- .forEach(([fromRef2, toRef2]) => {
607
- refMapSet.add(fromRef1 + fromRef2.slice(toRef1.length) + '~~' + toRef2);
608
- checkRefLinks = true;
609
- })
610
- );
611
- }
612
-
613
- // Build full recursiveRefMap
614
- // First pass - save all internally recursive refs from refMapSet
615
- Array.from(refMapSet)
616
- .map(refLink => refLink.split('~~'))
617
- .filter(([fromRef, toRef]) => JsonPointer.isSubPointer(toRef, fromRef))
618
- .forEach(([fromRef, toRef]) => recursiveRefMap.set(fromRef, toRef));
619
- // Second pass - create recursive versions of any other refs that link to recursive refs
620
- Array.from(refMap)
621
- .filter(([fromRef1, toRef1]) => Array.from(recursiveRefMap.keys())
622
- .every(fromRef2 => !JsonPointer.isSubPointer(fromRef1, fromRef2, true))
623
- )
624
- .forEach(([fromRef1, toRef1]) => Array.from(recursiveRefMap)
625
- .filter(([fromRef2, toRef2]) =>
626
- !recursiveRefMap.has(fromRef1 + fromRef2.slice(toRef1.length)) &&
627
- JsonPointer.isSubPointer(toRef1, fromRef2, true) &&
628
- !JsonPointer.isSubPointer(toRef1, fromRef1, true)
629
- )
630
- .forEach(([fromRef2, toRef2]) => recursiveRefMap.set(
631
- fromRef1 + fromRef2.slice(toRef1.length),
632
- fromRef1 + toRef2.slice(toRef1.length)
633
- ))
634
- );
635
-
636
- // Create compiled schema by replacing all non-recursive $ref links with
637
- // thieir linked schemas and, where possible, combining schemas in allOf arrays.
638
- let compiledSchema = { ...schema };
639
- delete compiledSchema.definitions;
640
- compiledSchema =
641
- getSubSchema(compiledSchema, '', refLibrary, recursiveRefMap);
642
-
643
- // Make sure all remaining schema $refs are recursive, and build final
644
- // schemaRefLibrary, schemaRecursiveRefMap, dataRecursiveRefMap, & arrayMap
645
- JsonPointer.forEachDeep(compiledSchema, (subSchema, subSchemaPointer) => {
646
- if (isString(subSchema['$ref'])) {
647
- let refPointer = JsonPointer.compile(subSchema['$ref']);
648
- if (!JsonPointer.isSubPointer(refPointer, subSchemaPointer, true)) {
649
- refPointer = removeRecursiveReferences(subSchemaPointer, recursiveRefMap);
650
- JsonPointer.set(compiledSchema, subSchemaPointer, { $ref: `#${refPointer}` });
651
- }
652
- if (!hasOwn(schemaRefLibrary, 'refPointer')) {
653
- schemaRefLibrary[refPointer] = !refPointer.length ? compiledSchema :
654
- getSubSchema(compiledSchema, refPointer, schemaRefLibrary, recursiveRefMap);
655
- }
656
- if (!schemaRecursiveRefMap.has(subSchemaPointer)) {
657
- schemaRecursiveRefMap.set(subSchemaPointer, refPointer);
658
- }
659
- const fromDataRef = JsonPointer.toDataPointer(subSchemaPointer, compiledSchema);
660
- if (!dataRecursiveRefMap.has(fromDataRef)) {
661
- const toDataRef = JsonPointer.toDataPointer(refPointer, compiledSchema);
662
- dataRecursiveRefMap.set(fromDataRef, toDataRef);
663
- }
664
- }
665
- if (subSchema.type === 'array' &&
666
- (hasOwn(subSchema, 'items') || hasOwn(subSchema, 'additionalItems'))
667
- ) {
668
- const dataPointer = JsonPointer.toDataPointer(subSchemaPointer, compiledSchema);
669
- if (!arrayMap.has(dataPointer)) {
670
- const tupleItems = isArray(subSchema.items) ? subSchema.items.length : 0;
671
- arrayMap.set(dataPointer, tupleItems);
672
- }
673
- }
674
- }, true);
675
- return compiledSchema;
676
- }
677
-
678
- /**
679
- * 'getSubSchema' function
680
- *
681
- * // schema
682
- * // { Pointer } pointer
683
- * // { object } schemaRefLibrary
684
- * // { Map<string, string> } schemaRecursiveRefMap
685
- * // { string[] = [] } usedPointers
686
- * //
687
- */
688
- export function getSubSchema(
689
- schema, pointer, schemaRefLibrary = null,
690
- schemaRecursiveRefMap: Map<string, string> = null, usedPointers: string[] = []
691
- ) {
692
- if (!schemaRefLibrary || !schemaRecursiveRefMap) {
693
- return JsonPointer.getCopy(schema, pointer);
694
- }
695
- if (typeof pointer !== 'string') { pointer = JsonPointer.compile(pointer); }
696
- usedPointers = [ ...usedPointers, pointer ];
697
- let newSchema: any = null;
698
- if (pointer === '') {
699
- newSchema = cloneDeep(schema);
700
- } else {
701
- const shortPointer = removeRecursiveReferences(pointer, schemaRecursiveRefMap);
702
- if (shortPointer !== pointer) { usedPointers = [ ...usedPointers, shortPointer ]; }
703
- newSchema = JsonPointer.getFirstCopy([
704
- [schemaRefLibrary, [shortPointer]],
705
- [schema, pointer],
706
- [schema, shortPointer]
707
- ]);
708
- }
709
- return JsonPointer.forEachDeepCopy(newSchema, (subSchema, subPointer) => {
710
- if (isObject(subSchema)) {
711
-
712
- // Replace non-recursive $ref links with referenced schemas
713
- if (isString(subSchema.$ref)) {
714
- const refPointer = JsonPointer.compile(subSchema.$ref);
715
- if (refPointer.length && usedPointers.every(ptr =>
716
- !JsonPointer.isSubPointer(refPointer, ptr, true)
717
- )) {
718
- const refSchema = getSubSchema(
719
- schema, refPointer, schemaRefLibrary, schemaRecursiveRefMap, usedPointers
720
- );
721
- if (Object.keys(subSchema).length === 1) {
722
- return refSchema;
723
- } else {
724
- const extraKeys = { ...subSchema };
725
- delete extraKeys.$ref;
726
- return mergeSchemas(refSchema, extraKeys);
727
- }
728
- }
729
- }
730
-
731
- // TODO: Convert schemas with 'type' arrays to 'oneOf'
732
-
733
- // Combine allOf subSchemas
734
- if (isArray(subSchema.allOf)) { return combineAllOf(subSchema); }
735
-
736
- // Fix incorrectly placed array object required lists
737
- if (subSchema.type === 'array' && isArray(subSchema.required)) {
738
- return fixRequiredArrayProperties(subSchema);
739
- }
740
- }
741
- return subSchema;
742
- }, true, <string>pointer);
743
- }
744
-
745
- /**
746
- * 'combineAllOf' function
747
- *
748
- * Attempt to convert an allOf schema object into
749
- * a non-allOf schema object with equivalent rules.
750
- *
751
- * // schema - allOf schema object
752
- * // - converted schema object
753
- */
754
- export function combineAllOf(schema) {
755
- if (!isObject(schema) || !isArray(schema.allOf)) { return schema; }
756
- let mergedSchema = mergeSchemas(...schema.allOf);
757
- if (Object.keys(schema).length > 1) {
758
- const extraKeys = { ...schema };
759
- delete extraKeys.allOf;
760
- mergedSchema = mergeSchemas(mergedSchema, extraKeys);
761
- }
762
- return mergedSchema;
763
- }
764
-
765
- /**
766
- * 'fixRequiredArrayProperties' function
767
- *
768
- * Fixes an incorrectly placed required list inside an array schema, by moving
769
- * it into items.properties or additionalItems.properties, where it belongs.
770
- *
771
- * // schema - allOf schema object
772
- * // - converted schema object
773
- */
774
- export function fixRequiredArrayProperties(schema) {
775
- if (schema.type === 'array' && isArray(schema.required)) {
776
- const itemsObject = hasOwn(schema.items, 'properties') ? 'items' :
777
- hasOwn(schema.additionalItems, 'properties') ? 'additionalItems' : null;
778
- if (itemsObject && !hasOwn(schema[itemsObject], 'required') && (
779
- hasOwn(schema[itemsObject], 'additionalProperties') ||
780
- schema.required.every(key => hasOwn(schema[itemsObject].properties, key))
781
- )) {
782
- schema = cloneDeep(schema);
783
- schema[itemsObject].required = schema.required;
784
- delete schema.required;
785
- }
786
- }
787
- return schema;
788
- }