geonetwork-ui 2.10.0-dev.b6696be21 → 2.10.0-dev.bfea85a63

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 (105) hide show
  1. package/fesm2022/geonetwork-ui.mjs +1016 -6093
  2. package/fesm2022/geonetwork-ui.mjs.map +1 -1
  3. package/index.d.ts +144 -149
  4. package/index.d.ts.map +1 -1
  5. package/package.json +23 -33
  6. package/src/libs/api/metadata-converter/src/lib/gn4/atomic-operations.ts +48 -7
  7. package/src/libs/api/metadata-converter/src/lib/gn4/gn4.field.mapper.ts +5 -4
  8. package/src/libs/api/metadata-converter/src/lib/gn4/metadata-url.service.ts +2 -2
  9. package/src/libs/api/metadata-converter/src/lib/gn4/types/metadata.model.ts +1 -0
  10. package/src/libs/api/repository/src/lib/gn4/auth/auth.service.ts +4 -4
  11. package/src/libs/api/repository/src/lib/gn4/elasticsearch/elasticsearch.service.ts +2 -2
  12. package/src/libs/api/repository/src/lib/gn4/gn4-repository.ts +5 -5
  13. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-groups.service.ts +1 -1
  14. package/src/libs/api/repository/src/lib/gn4/organizations/organizations-from-metadata.service.ts +1 -1
  15. package/src/libs/api/repository/src/lib/gn4/platform/gn4-platform.service.ts +2 -2
  16. package/src/libs/common/domain/src/lib/model/record/metadata.model.ts +2 -0
  17. package/src/libs/common/domain/src/lib/model/thesaurus/thesaurus.model.ts +2 -1
  18. package/src/libs/common/fixtures/src/lib/records.fixtures.ts +51 -0
  19. package/src/libs/feature/catalog/src/lib/sources/sources.service.ts +5 -2
  20. package/src/libs/feature/editor/src/lib/+state/editor.actions.ts +4 -1
  21. package/src/libs/feature/editor/src/lib/+state/editor.effects.ts +26 -19
  22. package/src/libs/feature/editor/src/lib/+state/editor.facade.ts +5 -1
  23. package/src/libs/feature/editor/src/lib/components/constraint-card/constraint-card.component.ts +0 -2
  24. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.html +5 -14
  25. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.ts +3 -28
  26. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.html +5 -5
  27. package/src/libs/feature/editor/src/lib/components/online-service-resource-input/online-service-resource-input.component.ts +2 -1
  28. package/src/libs/feature/editor/src/lib/components/record-form/form-field/field-focus.directive.ts +4 -1
  29. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-constraints-shortcuts/form-field-constraints-shortcuts.component.ts +7 -7
  30. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-online-resources/form-field-online-resources.component.ts +1 -1
  31. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-overviews/form-field-overviews.component.ts +12 -5
  32. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.html +4 -4
  33. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-rich/form-field-rich.component.ts +7 -0
  34. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.html +6 -2
  35. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field-update-frequency/form-field-update-frequency.component.ts +3 -1
  36. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.css +0 -34
  37. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.html +20 -16
  38. package/src/libs/feature/editor/src/lib/components/record-form/form-field/form-field.component.ts +9 -0
  39. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.css +35 -0
  40. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.html +18 -5
  41. package/src/libs/feature/editor/src/lib/components/record-form/record-form.component.ts +76 -19
  42. package/src/libs/feature/editor/src/lib/expressions.ts +380 -8
  43. package/src/libs/feature/editor/src/lib/fields.config.ts +251 -290
  44. package/src/libs/feature/editor/src/lib/models/editor-config.model.ts +2 -3
  45. package/src/libs/feature/editor/src/lib/services/editor.service.ts +8 -12
  46. package/src/libs/feature/map/src/lib/utils/map-utils.service.ts +33 -0
  47. package/src/libs/feature/record/src/lib/map-view/map-view.component.ts +9 -1
  48. package/src/libs/feature/search/src/lib/results-table/results-table-container.component.ts +10 -5
  49. package/src/libs/ui/catalog/src/lib/language-switcher/language-switcher.component.ts +2 -2
  50. package/src/libs/ui/dataviz/src/index.ts +0 -1
  51. package/src/libs/ui/elements/src/index.ts +1 -0
  52. package/src/libs/ui/elements/src/lib/contact-details/contact-details.component.html +48 -56
  53. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.html +2 -1
  54. package/src/libs/ui/elements/src/lib/external-link-card/external-link-card.component.ts +2 -2
  55. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.css +13 -0
  56. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.html +13 -3
  57. package/src/libs/ui/elements/src/lib/image-overlay-preview/image-overlay-preview.component.ts +43 -6
  58. package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.html +14 -0
  59. package/src/libs/ui/elements/src/lib/keyword-badge/keyword-badge.component.ts +85 -0
  60. package/src/libs/ui/elements/src/lib/markdown-parser/markdown-parser.component.ts +2 -2
  61. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.css +5 -0
  62. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.html +4 -7
  63. package/src/libs/ui/elements/src/lib/metadata-info/metadata-info.component.ts +2 -2
  64. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.html +4 -5
  65. package/src/libs/ui/elements/src/lib/record-api-form/record-api-form.component.ts +4 -0
  66. package/src/libs/ui/inputs/src/lib/badge/badge.component.html +33 -26
  67. package/src/libs/ui/inputs/src/lib/badge/badge.component.ts +9 -0
  68. package/src/libs/ui/inputs/src/lib/date-picker/date-picker.component.ts +2 -2
  69. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.html +1 -1
  70. package/src/libs/ui/inputs/src/lib/dropdown-multiselect/dropdown-multiselect.component.ts +3 -3
  71. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.html +5 -5
  72. package/src/libs/ui/layout/src/lib/form-field-wrapper/form-field-wrapper.component.ts +9 -1
  73. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.html +1 -1
  74. package/src/libs/ui/layout/src/lib/interactive-table/interactive-table.component.ts +3 -8
  75. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.html +7 -7
  76. package/src/libs/ui/layout/src/lib/sortable-list/sortable-list.component.ts +14 -1
  77. package/src/libs/ui/map/src/lib/components/spatial-extent/spatial-extent.component.ts +4 -54
  78. package/src/libs/ui/map/src/lib/map-utils.ts +48 -0
  79. package/src/libs/ui/search/src/lib/record-preview-feed/record-preview-feed.component.ts +1 -1
  80. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.html +12 -8
  81. package/src/libs/ui/search/src/lib/results-table/action-menu/action-menu.component.ts +3 -1
  82. package/src/libs/ui/search/src/lib/results-table/results-table.component.html +1 -0
  83. package/src/libs/ui/widgets/src/lib/popover/popover.component.ts +7 -1
  84. package/src/libs/util/app-config/src/lib/app-config.ts +21 -9
  85. package/src/libs/util/data-fetcher/src/lib/readers/base-file.ts +1 -2
  86. package/src/libs/util/data-fetcher/src/lib/readers/wfs.ts +6 -3
  87. package/src/libs/util/i18n/src/index.ts +0 -1
  88. package/src/libs/util/i18n/src/lib/i18n.constants.ts +17 -11
  89. package/src/libs/util/i18n/src/lib/i18n.interceptor.ts +2 -2
  90. package/src/libs/util/i18n/src/lib/i18n.providers.ts +14 -17
  91. package/src/libs/util/i18n/src/lib/test.translate.loader.ts +48 -0
  92. package/src/libs/util/shared/src/lib/links/link-utils.ts +22 -0
  93. package/src/libs/util/shared/src/lib/services/date.service.ts +3 -3
  94. package/src/libs/util/shared/src/lib/utils/geojson.ts +58 -1
  95. package/style.css +0 -1
  96. package/tailwind.base.css +9 -0
  97. package/translations/de.json +53 -29
  98. package/translations/en.json +58 -34
  99. package/translations/es.json +27 -3
  100. package/translations/fr.json +55 -31
  101. package/translations/it.json +53 -29
  102. package/translations/nl.json +26 -2
  103. package/translations/pt.json +27 -3
  104. package/translations/sk.json +27 -3
  105. package/src/libs/feature/editor/src/lib/components/generic-keywords/generic-keywords.component.css +0 -3
@@ -1,16 +1,388 @@
1
- import { EditorFieldState, EditorFieldValue } from './models/'
1
+ import { EditorFieldValue } from './models/'
2
2
 
3
- export type ExpressionEvaluator = (field: EditorFieldState) => EditorFieldValue
3
+ export interface EvaluationContext {
4
+ globals: Record<string, object>
5
+ }
6
+
7
+ export type ExpressionEvaluator = (
8
+ context: EvaluationContext
9
+ ) => EditorFieldValue
10
+
11
+ const TOKEN_FUNCTION_CALL_START = '('
12
+ const TOKEN_FUNCTION_CALL_END = ')'
13
+ const TOKEN_PROPERTY_ACCESS = '.'
14
+ const TOKEN_OPERATOR_TERNARY_FIRST = '?'
15
+ const TOKEN_OPERATOR_TERNARY_SECOND = ':'
16
+ const TOKEN_OPERATOR_LOGICAL = ['==', '!=']
17
+ const TOKEN_STRING_LITERAL = ["'", '"']
18
+ const TOKEN_GROUP_START = '('
19
+ const TOKEN_GROUP_END = ')'
20
+
21
+ // See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Operator_precedence
22
+ const OPERATORS_BY_PRECEDENCE: string[][] = [
23
+ [TOKEN_OPERATOR_TERNARY_FIRST, TOKEN_OPERATOR_TERNARY_SECOND],
24
+ TOKEN_OPERATOR_LOGICAL,
25
+ ]
26
+ const ALL_OPERATORS = OPERATORS_BY_PRECEDENCE.flat()
27
+
28
+ export interface CompilationContext {
29
+ errors: string[]
30
+ }
31
+
32
+ export function isExpression(input: unknown): boolean {
33
+ return typeof input === 'string' && /^\${.*}$/.test(input)
34
+ }
35
+
36
+ function readNext(input: string, start: number, length = 1): string {
37
+ return input.substring(start, start + length)
38
+ }
4
39
 
5
- export function evaluate(expression: string): ExpressionEvaluator {
6
- if (expression.match(/^\${.*}$/)) {
7
- return evaluate(expression.slice(2, -1))
40
+ /**
41
+ * Will continue looking until an operator is found at the same depth level
42
+ */
43
+ function readUntilNextOperator(
44
+ input: string,
45
+ start: number,
46
+ currentOperator: string
47
+ ): string {
48
+ let pos = start
49
+ let result = ''
50
+ let depth = 0
51
+ while (pos < input.length) {
52
+ const isOperator = ALL_OPERATORS.some(
53
+ (token) => readNext(input, pos, token.length) === token
54
+ )
55
+ if (isOperator && depth === 0) {
56
+ const operatorPrecedence = OPERATORS_BY_PRECEDENCE.findIndex((tokens) =>
57
+ tokens.some((token) => readNext(input, pos, token.length) === token)
58
+ )
59
+ const currentPrecedence =
60
+ OPERATORS_BY_PRECEDENCE.findIndex((tokens) =>
61
+ tokens.some((token) => currentOperator === token)
62
+ ) ?? -1
63
+ // the new operator has a lower precedence than the current one: we stop here
64
+ if (operatorPrecedence < currentPrecedence) {
65
+ return result
66
+ }
67
+ }
68
+ if (input[pos] === TOKEN_GROUP_START) {
69
+ depth++
70
+ } else if (input[pos] === TOKEN_GROUP_END) {
71
+ depth--
72
+ }
73
+ if (depth < 0) {
74
+ return result
75
+ }
76
+ result += input[pos]
77
+ pos++
8
78
  }
9
- const operator = expression.split('(')[0]
10
- switch (operator) {
79
+ return result
80
+ }
81
+
82
+ /**
83
+ * Will look for a specific character or string situated at the same depth level!
84
+ * Returns null if nothing found
85
+ */
86
+ function readUntil(input: string, start: number, char: string): string | null {
87
+ let pos = start
88
+ let result = ''
89
+ let depth = 0
90
+ while (pos < input.length) {
91
+ if (depth === 0 && readNext(input, pos, char.length) === char) {
92
+ return result
93
+ }
94
+ if (input[pos] === TOKEN_GROUP_START) {
95
+ depth++
96
+ } else if (input[pos] === TOKEN_GROUP_END) {
97
+ depth--
98
+ }
99
+ if (depth < 0) {
100
+ return null
101
+ }
102
+ result += input[pos]
103
+ pos++
104
+ }
105
+ return null
106
+ }
107
+
108
+ function getFunctionEvaluator(
109
+ functionName: string,
110
+ context: CompilationContext
111
+ ): ExpressionEvaluator {
112
+ switch (functionName) {
11
113
  case 'dateNow':
12
114
  return () => new Date()
13
115
  default:
14
- throw new Error(`Unknown operator: ${operator}`)
116
+ context.errors.push(`Unknown function: ${functionName}`)
117
+ return () => undefined
118
+ }
119
+ }
120
+
121
+ /**
122
+ * This evaluates an expression using a very light subset of Javascript.
123
+ *
124
+ * Things allowed in expressions are:
125
+ * - comparing values with == and !=
126
+ * - ternary comparisons with a ? b : c
127
+ * - grouping with (...)
128
+ * - functions: for now only dateNow() is supported and returns a timestamp
129
+ * - access to globals such as record.type
130
+ *
131
+ * Expressions are turned into an evaluator that can be called with a context containing the globals.
132
+ * Expressions can return any primitive Javascript type
133
+ * Valid expressions should always be enclosed in ${...}
134
+ */
135
+ export function evaluate(expression: string): {
136
+ evaluator: ExpressionEvaluator
137
+ errors: string[]
138
+ } {
139
+ if (!/^\${.*}$/.test(expression)) {
140
+ throw new Error('Malformed expression: missing ${} enclosure')
141
+ }
142
+ const context = {
143
+ errors: [],
144
+ }
145
+ const trimmedExpression = expression.slice(2, -1)
146
+ return evaluateInternal(trimmedExpression, context)
147
+ }
148
+
149
+ function evaluateInternal(
150
+ expression: string,
151
+ currentContext: CompilationContext
152
+ ): { evaluator: ExpressionEvaluator; errors: string[] } {
153
+ let pos = 0
154
+ let currentSymbol = null
155
+ let currentEvaluator: ExpressionEvaluator = () => undefined
156
+
157
+ while (pos < expression.length) {
158
+ const isWhitespace = /\s/.test(readNext(expression, pos))
159
+ if (isWhitespace) {
160
+ pos++
161
+ continue
162
+ }
163
+
164
+ // SYMBOL (NAME)
165
+ const isSymbol = /[a-zA-Z]/.test(readNext(expression, pos))
166
+ if (isSymbol) {
167
+ currentSymbol = ''
168
+ while (pos < expression.length) {
169
+ if (!/[a-zA-Z]/.test(readNext(expression, pos))) {
170
+ break
171
+ }
172
+ currentSymbol += readNext(expression, pos)
173
+ pos++
174
+ }
175
+ continue
176
+ }
177
+
178
+ // FUNCTION CALL
179
+ const isFunctionCall =
180
+ currentSymbol && readNext(expression, pos) === TOKEN_FUNCTION_CALL_START
181
+ if (isFunctionCall) {
182
+ pos++
183
+ // no support for arguments for now (not needed)
184
+ if (readNext(expression, pos) !== TOKEN_FUNCTION_CALL_END) {
185
+ currentContext.errors.push(
186
+ `Expected token '${TOKEN_FUNCTION_CALL_END}' at position ${pos}, got '${readNext(expression, pos)}' instead`
187
+ )
188
+ break
189
+ }
190
+ pos++
191
+ currentEvaluator = getFunctionEvaluator(currentSymbol, currentContext)
192
+ currentSymbol = null
193
+ continue
194
+ }
195
+
196
+ // PROPERTY ACCESS (single level)
197
+ const isPropertyAccess =
198
+ currentSymbol && readNext(expression, pos) === TOKEN_PROPERTY_ACCESS
199
+ if (isPropertyAccess) {
200
+ pos++
201
+ if (!/[a-zA-Z]/.test(readNext(expression, pos))) {
202
+ currentContext.errors.push(
203
+ `Expected a property name after '${TOKEN_PROPERTY_ACCESS}' at position ${pos}, got '${readNext(expression, pos)}' instead`
204
+ )
205
+ break
206
+ }
207
+ let propertyName = ''
208
+ while (pos < expression.length) {
209
+ if (!/[a-zA-Z]/.test(readNext(expression, pos))) {
210
+ break
211
+ }
212
+ propertyName += readNext(expression, pos)
213
+ pos++
214
+ }
215
+ const variableName = currentSymbol
216
+ currentEvaluator = (context) => {
217
+ if (
218
+ !Object.prototype.hasOwnProperty.call(context.globals, variableName)
219
+ ) {
220
+ return undefined
221
+ }
222
+ if (
223
+ !Object.prototype.hasOwnProperty.call(
224
+ context.globals[variableName],
225
+ propertyName
226
+ )
227
+ ) {
228
+ return undefined
229
+ }
230
+ return context.globals[variableName][propertyName]
231
+ }
232
+ currentSymbol = null
233
+ continue
234
+ }
235
+
236
+ // we have a symbol but did not do either function call or property access => error
237
+ if (currentSymbol) {
238
+ currentContext.errors.push(
239
+ `Expected a function call or property access after symbol '${currentSymbol}' at position ${pos}, got '${readNext(expression, pos)}' instead`
240
+ )
241
+ break
242
+ }
243
+
244
+ // GROUP OPERATOR
245
+ const isGroupStart = readNext(expression, pos) === TOKEN_GROUP_START
246
+ if (isGroupStart) {
247
+ pos++
248
+ const groupExpression = readUntil(expression, pos, TOKEN_GROUP_END)
249
+ if (groupExpression === null) {
250
+ currentContext.errors.push(
251
+ `Reached end of expression before finding expected token '${TOKEN_GROUP_END}'`
252
+ )
253
+ break
254
+ }
255
+ pos += groupExpression.length + 1
256
+ currentEvaluator = evaluateInternal(
257
+ groupExpression,
258
+ currentContext
259
+ ).evaluator
260
+ continue
261
+ }
262
+
263
+ // LOGICAL OPERATORS
264
+ const isLogicalOperator = TOKEN_OPERATOR_LOGICAL.some(
265
+ (token) => readNext(expression, pos, token.length) === token
266
+ )
267
+ if (isLogicalOperator) {
268
+ const matchingOperator = TOKEN_OPERATOR_LOGICAL.find(
269
+ (token) => readNext(expression, pos, token.length) === token
270
+ )
271
+ const isEqual = matchingOperator.startsWith('=')
272
+ pos += matchingOperator.length
273
+ const comparedEvaluator = currentEvaluator
274
+ const comparedToExpression = readUntilNextOperator(
275
+ expression,
276
+ pos,
277
+ matchingOperator
278
+ )
279
+ pos += comparedToExpression.length
280
+ const comparedToEvaluator = evaluateInternal(
281
+ comparedToExpression,
282
+ currentContext
283
+ ).evaluator
284
+
285
+ currentEvaluator = (context) => {
286
+ return (
287
+ (comparedEvaluator(context) == comparedToEvaluator(context)) ===
288
+ isEqual
289
+ )
290
+ }
291
+ continue
292
+ }
293
+
294
+ // TERNARY OPERATOR
295
+ const isTernary = readNext(expression, pos) === TOKEN_OPERATOR_TERNARY_FIRST
296
+ if (isTernary) {
297
+ if (!currentEvaluator) {
298
+ currentContext.errors.push(
299
+ `Expected an expression before '${TOKEN_OPERATOR_TERNARY_FIRST}' at position ${pos} but could not find any`
300
+ )
301
+ break
302
+ }
303
+ pos++
304
+ const ifTrueExpression = readUntil(
305
+ expression,
306
+ pos,
307
+ TOKEN_OPERATOR_TERNARY_SECOND
308
+ )
309
+ if (ifTrueExpression === null) {
310
+ currentContext.errors.push(
311
+ `Reached end of expression before finding expected token '${TOKEN_OPERATOR_TERNARY_SECOND}'`
312
+ )
313
+ break
314
+ }
315
+ pos += ifTrueExpression.length + 1
316
+
317
+ const ifFalseExpression = readUntilNextOperator(
318
+ expression,
319
+ pos,
320
+ TOKEN_OPERATOR_TERNARY_FIRST
321
+ )
322
+ pos += ifFalseExpression.length
323
+
324
+ const conditionEvaluator = currentEvaluator
325
+ const ifTrueEvaluator = evaluateInternal(
326
+ ifTrueExpression,
327
+ currentContext
328
+ ).evaluator
329
+ const ifFalseEvaluator = evaluateInternal(
330
+ ifFalseExpression,
331
+ currentContext
332
+ ).evaluator
333
+ currentEvaluator = (context) => {
334
+ if (conditionEvaluator(context)) {
335
+ return ifTrueEvaluator(context)
336
+ }
337
+ return ifFalseEvaluator(context)
338
+ }
339
+ continue
340
+ }
341
+
342
+ // STRING LITERAL
343
+ const isStringLiteral = TOKEN_STRING_LITERAL.some(
344
+ (token) => readNext(expression, pos) === token
345
+ )
346
+ if (isStringLiteral) {
347
+ const openingToken = readNext(expression, pos)
348
+ pos++
349
+ const literal = readUntil(expression, pos, openingToken)
350
+ if (literal === null) {
351
+ currentContext.errors.push(
352
+ `Reached end of expression before finding corresponding closing token ${openingToken} for string literal`
353
+ )
354
+ break
355
+ }
356
+ pos += literal.length + 1
357
+ currentEvaluator = () => literal
358
+ continue
359
+ }
360
+
361
+ // NUMBER LITERAL
362
+ const isNumberLiteral = /[0-9]/.test(readNext(expression, pos))
363
+ if (isNumberLiteral) {
364
+ let literal = ''
365
+ while (pos < expression.length) {
366
+ if (!/[0-9]/.test(readNext(expression, pos))) {
367
+ break
368
+ }
369
+ literal += readNext(expression, pos)
370
+ pos++
371
+ }
372
+ const numberLiteral = parseInt(literal, 10)
373
+ currentEvaluator = () => numberLiteral
374
+ continue
375
+ }
376
+
377
+ // could not figure out what that was: leave
378
+ currentContext.errors.push(
379
+ `Unexpected character '${readNext(expression, pos)}' at position ${pos}`
380
+ )
381
+ break
382
+ }
383
+
384
+ return {
385
+ evaluator: currentEvaluator,
386
+ errors: currentContext.errors,
15
387
  }
16
388
  }