@react-typed-forms/schemas 15.1.3 → 15.2.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.
- package/lib/controlBuilder.d.ts +1 -2
- package/lib/controlDefinition.d.ts +42 -36
- package/lib/controlRender.d.ts +36 -85
- package/lib/defaultSchemaInterface.d.ts +2 -6
- package/lib/hooks.d.ts +1 -2
- package/lib/index.cjs +669 -838
- package/lib/index.cjs.map +1 -1
- package/lib/index.d.ts +0 -4
- package/lib/index.js +580 -721
- package/lib/index.js.map +1 -1
- package/lib/renderers.d.ts +1 -0
- package/lib/schemaField.d.ts +133 -1
- package/lib/util.d.ts +11 -9
- package/package.json +1 -1
- package/src/controlBuilder.ts +2 -8
- package/src/controlDefinition.ts +243 -43
- package/src/controlRender.tsx +96 -157
- package/src/createFormRenderer.tsx +2 -1
- package/src/defaultSchemaInterface.ts +5 -15
- package/src/hooks.tsx +7 -7
- package/src/index.ts +0 -4
- package/src/renderers.tsx +1 -0
- package/src/schemaField.ts +400 -1
- package/src/util.ts +89 -116
- package/src/validators.ts +3 -3
- package/lib/formNode.d.ts +0 -46
- package/lib/schemaDataNode.d.ts +0 -31
- package/lib/schemaInterface.d.ts +0 -102
- package/lib/schemaNode.d.ts +0 -54
- package/src/formNode.ts +0 -253
- package/src/schemaDataNode.ts +0 -129
- package/src/schemaInterface.ts +0 -135
- package/src/schemaNode.ts +0 -279
package/src/hooks.tsx
CHANGED
|
@@ -31,6 +31,11 @@ import {
|
|
|
31
31
|
import jsonata from "jsonata";
|
|
32
32
|
import { v4 as uuidv4 } from "uuid";
|
|
33
33
|
import { DynamicHookGenerator, HookDep, toDepString } from "./dynamicHooks";
|
|
34
|
+
import {
|
|
35
|
+
schemaDataForFieldRef,
|
|
36
|
+
SchemaDataNode,
|
|
37
|
+
SchemaInterface,
|
|
38
|
+
} from "./schemaField";
|
|
34
39
|
import {
|
|
35
40
|
DataExpression,
|
|
36
41
|
DataMatchExpression,
|
|
@@ -39,8 +44,6 @@ import {
|
|
|
39
44
|
JsonataExpression,
|
|
40
45
|
NotEmptyExpression,
|
|
41
46
|
} from "./entityExpression";
|
|
42
|
-
import { SchemaInterface } from "./schemaInterface";
|
|
43
|
-
import { schemaDataForFieldRef, SchemaDataNode } from "./schemaDataNode";
|
|
44
47
|
|
|
45
48
|
export type EvalExpressionHook<A = any> = DynamicHookGenerator<
|
|
46
49
|
Control<A | undefined>,
|
|
@@ -330,10 +333,7 @@ export function matchesType(context: SchemaDataNode): boolean {
|
|
|
330
333
|
const typeNode = parent.schema
|
|
331
334
|
.getChildNodes()
|
|
332
335
|
.find((x) => x.field.isTypeField);
|
|
333
|
-
if (typeNode == null)
|
|
334
|
-
console.warn("No type field found for", parent.schema);
|
|
335
|
-
return false;
|
|
336
|
-
}
|
|
336
|
+
if (typeNode == null) return true;
|
|
337
337
|
const typeField = parent.getChild(typeNode).control as Control<string>;
|
|
338
338
|
return typeField && types.includes(typeField.value);
|
|
339
339
|
}
|
|
@@ -373,7 +373,7 @@ export function useJsonataExpression(
|
|
|
373
373
|
}
|
|
374
374
|
}, [fullExpr]);
|
|
375
375
|
const control = useControl();
|
|
376
|
-
const listenerRef = useRef<(
|
|
376
|
+
const listenerRef = useRef<() => void>();
|
|
377
377
|
const updateRef = useRef(0);
|
|
378
378
|
const [ref] = useRefState(
|
|
379
379
|
() =>
|
package/src/index.ts
CHANGED
|
@@ -12,7 +12,3 @@ export * from "./dynamicHooks";
|
|
|
12
12
|
export * from "./schemaValidator";
|
|
13
13
|
export * from "./schemaField";
|
|
14
14
|
export * from "./entityExpression";
|
|
15
|
-
export * from "./formNode";
|
|
16
|
-
export * from "./schemaInterface";
|
|
17
|
-
export * from "./schemaDataNode";
|
|
18
|
-
export * from "./schemaNode";
|
package/src/renderers.tsx
CHANGED
package/src/schemaField.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { SchemaValidator } from "./schemaValidator";
|
|
2
|
+
import { Control, ControlSetup, newControl } from "@react-typed-forms/core";
|
|
3
|
+
import { EntityExpression } from "./entityExpression";
|
|
2
4
|
|
|
3
5
|
export type EqualityFunc = (a: any, b: any) => boolean;
|
|
4
6
|
|
|
@@ -114,6 +116,146 @@ export enum ValidationMessageType {
|
|
|
114
116
|
NotBeforeDate = "NotBeforeDate",
|
|
115
117
|
}
|
|
116
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Interface for schema-related operations.
|
|
121
|
+
*/
|
|
122
|
+
export interface SchemaInterface {
|
|
123
|
+
/**
|
|
124
|
+
* Checks if the value of a field is empty.
|
|
125
|
+
* @param field The schema field.
|
|
126
|
+
* @param value The value to check.
|
|
127
|
+
* @returns True if the value is empty, false otherwise.
|
|
128
|
+
*/
|
|
129
|
+
isEmptyValue(field: SchemaField, value: any): boolean;
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* Gets the text representation of a field's value.
|
|
133
|
+
* @param field The schema field.
|
|
134
|
+
* @param value The value to convert.
|
|
135
|
+
* @param element Indicates if the value is an element, optional.
|
|
136
|
+
* @returns The text representation of the value.
|
|
137
|
+
*/
|
|
138
|
+
textValue(
|
|
139
|
+
field: SchemaField,
|
|
140
|
+
value: any,
|
|
141
|
+
element?: boolean,
|
|
142
|
+
): string | undefined;
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Gets the length of a control's value.
|
|
146
|
+
* @param field The schema field.
|
|
147
|
+
* @param control The control to check.
|
|
148
|
+
* @returns The length of the control's value.
|
|
149
|
+
*/
|
|
150
|
+
controlLength(field: SchemaField, control: Control<any>): number;
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* Gets the length of a field's value.
|
|
154
|
+
* @param field The schema field.
|
|
155
|
+
* @param value The value to check.
|
|
156
|
+
* @returns The length of the value.
|
|
157
|
+
*/
|
|
158
|
+
valueLength(field: SchemaField, value: any): number;
|
|
159
|
+
|
|
160
|
+
/**
|
|
161
|
+
* Gets the data options for a schema data node.
|
|
162
|
+
* @param node The schema data node.
|
|
163
|
+
* @returns The data options.
|
|
164
|
+
*/
|
|
165
|
+
getDataOptions(node: SchemaDataNode): FieldOption[] | null | undefined;
|
|
166
|
+
|
|
167
|
+
/**
|
|
168
|
+
* Gets the node options for a schema node.
|
|
169
|
+
* @param node The schema node.
|
|
170
|
+
* @returns The node options.
|
|
171
|
+
*/
|
|
172
|
+
getNodeOptions(node: SchemaNode): FieldOption[] | null | undefined;
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Gets the options for a schema field.
|
|
176
|
+
* @param field The schema field.
|
|
177
|
+
* @returns The field options.
|
|
178
|
+
*/
|
|
179
|
+
getOptions(field: SchemaField): FieldOption[] | undefined | null;
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Gets the filter options for a schema data node and field.
|
|
183
|
+
* @param array The schema data node.
|
|
184
|
+
* @param field The schema node.
|
|
185
|
+
* @returns The filter options.
|
|
186
|
+
*/
|
|
187
|
+
getFilterOptions(
|
|
188
|
+
array: SchemaDataNode,
|
|
189
|
+
field: SchemaNode,
|
|
190
|
+
): FieldOption[] | undefined | null;
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Parses a string value to milliseconds.
|
|
194
|
+
* @param field The schema field.
|
|
195
|
+
* @param v The string value to parse.
|
|
196
|
+
* @returns The parsed value in milliseconds.
|
|
197
|
+
*/
|
|
198
|
+
parseToMillis(field: SchemaField, v: string): number;
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Gets the validation message text for a field.
|
|
202
|
+
* @param field The schema field.
|
|
203
|
+
* @param messageType The type of validation message.
|
|
204
|
+
* @param actual The actual value.
|
|
205
|
+
* @param expected The expected value.
|
|
206
|
+
* @returns The validation message text.
|
|
207
|
+
*/
|
|
208
|
+
validationMessageText(
|
|
209
|
+
field: SchemaField,
|
|
210
|
+
messageType: ValidationMessageType,
|
|
211
|
+
actual: any,
|
|
212
|
+
expected: any,
|
|
213
|
+
): string;
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Compares two values of a field.
|
|
217
|
+
* @param field The schema field.
|
|
218
|
+
* @param v1 The first value.
|
|
219
|
+
* @param v2 The second value.
|
|
220
|
+
* @returns The comparison result.
|
|
221
|
+
*/
|
|
222
|
+
compareValue(field: SchemaField, v1: unknown, v2: unknown): number;
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Gets the search text for a field's value.
|
|
226
|
+
* @param field The schema field.
|
|
227
|
+
* @param value The value to search.
|
|
228
|
+
* @returns The search text.
|
|
229
|
+
*/
|
|
230
|
+
searchText(field: SchemaField, value: any): string;
|
|
231
|
+
|
|
232
|
+
makeEqualityFunc(field: SchemaNode, element?: boolean): EqualityFunc;
|
|
233
|
+
|
|
234
|
+
makeControlSetup(field: SchemaNode, element?: boolean): ControlSetup<any>;
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
export interface SchemaTreeLookup {
|
|
238
|
+
getSchema(schemaId: string): SchemaNode | undefined;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
export interface SchemaNode extends SchemaTreeLookup {
|
|
242
|
+
id: string;
|
|
243
|
+
field: SchemaField;
|
|
244
|
+
getChildNode(field: string): SchemaNode | undefined;
|
|
245
|
+
getChildNodes(noRecurse?: boolean, withParent?: SchemaNode): SchemaNode[];
|
|
246
|
+
parent?: SchemaNode;
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
export interface SchemaDataNode {
|
|
250
|
+
id: string;
|
|
251
|
+
schema: SchemaNode;
|
|
252
|
+
elementIndex?: number;
|
|
253
|
+
control: Control<any>;
|
|
254
|
+
parent?: SchemaDataNode;
|
|
255
|
+
getChild(schemaNode: SchemaNode): SchemaDataNode;
|
|
256
|
+
getChildElement(index: number): SchemaDataNode;
|
|
257
|
+
}
|
|
258
|
+
|
|
117
259
|
export function findField(
|
|
118
260
|
fields: SchemaField[],
|
|
119
261
|
field: string,
|
|
@@ -129,10 +271,267 @@ export function isCompoundField(sf: SchemaField): sf is CompoundField {
|
|
|
129
271
|
return sf.type === FieldType.Compound;
|
|
130
272
|
}
|
|
131
273
|
|
|
132
|
-
|
|
274
|
+
function missingField(field: string): SchemaField {
|
|
133
275
|
return { field: "__missing", type: FieldType.Any, displayName: field };
|
|
134
276
|
}
|
|
135
277
|
|
|
278
|
+
function nodeForSchema(
|
|
279
|
+
field: SchemaField,
|
|
280
|
+
lookup: SchemaTreeLookup,
|
|
281
|
+
parent: SchemaNode | undefined,
|
|
282
|
+
): SchemaNode {
|
|
283
|
+
const node = {
|
|
284
|
+
id: parent ? parent.id + "/" + field.field : field.field,
|
|
285
|
+
field,
|
|
286
|
+
getSchema: lookup.getSchema,
|
|
287
|
+
parent,
|
|
288
|
+
getChildNode,
|
|
289
|
+
getChildNodes,
|
|
290
|
+
};
|
|
291
|
+
return node;
|
|
292
|
+
|
|
293
|
+
function getChildNode(fieldName: string) {
|
|
294
|
+
if (isCompoundField(field) && !field.schemaRef && !field.treeChildren) {
|
|
295
|
+
const childField = field.children.find((x) => x.field === fieldName);
|
|
296
|
+
return childField ? nodeForSchema(childField, lookup, node) : undefined;
|
|
297
|
+
}
|
|
298
|
+
return getChildNodes(false, node).find((x) => x.field.field === fieldName);
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
function getChildNodes(
|
|
302
|
+
noRecurse?: boolean,
|
|
303
|
+
withParent?: SchemaNode,
|
|
304
|
+
): SchemaNode[] {
|
|
305
|
+
if (isCompoundField(field)) {
|
|
306
|
+
if (field.treeChildren) {
|
|
307
|
+
return noRecurse
|
|
308
|
+
? []
|
|
309
|
+
: parent!.getChildNodes(false, withParent ?? node);
|
|
310
|
+
}
|
|
311
|
+
const otherRef = field.schemaRef && lookup.getSchema(field.schemaRef);
|
|
312
|
+
if (otherRef) return otherRef.getChildNodes(false, withParent ?? node);
|
|
313
|
+
return field.children.map((x) =>
|
|
314
|
+
nodeForSchema(x, lookup, withParent ?? node),
|
|
315
|
+
);
|
|
316
|
+
}
|
|
317
|
+
return [];
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
export function createSchemaLookup<A extends Record<string, SchemaField[]>>(
|
|
322
|
+
schemaMap: A,
|
|
323
|
+
): {
|
|
324
|
+
getSchema(schemaId: keyof A): SchemaNode;
|
|
325
|
+
} {
|
|
326
|
+
const lookup = {
|
|
327
|
+
getSchema,
|
|
328
|
+
};
|
|
329
|
+
return lookup;
|
|
330
|
+
|
|
331
|
+
function getSchema(schemaId: keyof A): SchemaNode {
|
|
332
|
+
const fields = schemaMap[schemaId];
|
|
333
|
+
if (fields) {
|
|
334
|
+
return rootSchemaNode(fields, lookup);
|
|
335
|
+
}
|
|
336
|
+
return undefined!;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
export function makeSchemaDataNode(
|
|
341
|
+
schema: SchemaNode,
|
|
342
|
+
control: Control<unknown>,
|
|
343
|
+
parent?: SchemaDataNode,
|
|
344
|
+
elementIndex?: number,
|
|
345
|
+
): SchemaDataNode {
|
|
346
|
+
const indexId = typeof elementIndex === "number" ? "/" + elementIndex : "";
|
|
347
|
+
const dataNode = {
|
|
348
|
+
id:
|
|
349
|
+
(parent ? parent.id + "/" + schema.field.field : schema.field.field) +
|
|
350
|
+
indexId,
|
|
351
|
+
schema,
|
|
352
|
+
control,
|
|
353
|
+
parent,
|
|
354
|
+
elementIndex,
|
|
355
|
+
getChild,
|
|
356
|
+
getChildElement,
|
|
357
|
+
};
|
|
358
|
+
return dataNode;
|
|
359
|
+
|
|
360
|
+
function getChild(childNode: SchemaNode): SchemaDataNode {
|
|
361
|
+
const objControl = control as Control<Record<string, unknown>>;
|
|
362
|
+
if (objControl && objControl.current.isNull) {
|
|
363
|
+
objControl.value = {};
|
|
364
|
+
}
|
|
365
|
+
return makeSchemaDataNode(
|
|
366
|
+
childNode,
|
|
367
|
+
objControl?.fields[childNode.field.field],
|
|
368
|
+
dataNode,
|
|
369
|
+
);
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function getChildElement(elementIndex: number): SchemaDataNode {
|
|
373
|
+
return makeSchemaDataNode(
|
|
374
|
+
schema,
|
|
375
|
+
(control as Control<unknown[]>)?.elements?.[elementIndex],
|
|
376
|
+
dataNode,
|
|
377
|
+
elementIndex,
|
|
378
|
+
);
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
export function schemaDataForFieldRef(
|
|
383
|
+
fieldRef: string | undefined,
|
|
384
|
+
schema: SchemaDataNode,
|
|
385
|
+
): SchemaDataNode {
|
|
386
|
+
return schemaDataForFieldPath(fieldRef?.split("/") ?? [], schema);
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
export function schemaForFieldRef(
|
|
390
|
+
fieldRef: string | undefined,
|
|
391
|
+
schema: SchemaNode,
|
|
392
|
+
): SchemaNode {
|
|
393
|
+
return schemaForFieldPath(fieldRef?.split("/") ?? [], schema);
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
export function traverseSchemaPath<A>(
|
|
397
|
+
fieldPath: string[],
|
|
398
|
+
schema: SchemaNode,
|
|
399
|
+
acc: A,
|
|
400
|
+
next: (acc: A, node: SchemaNode) => A,
|
|
401
|
+
): A {
|
|
402
|
+
let i = 0;
|
|
403
|
+
while (i < fieldPath.length) {
|
|
404
|
+
const nextField = fieldPath[i];
|
|
405
|
+
let childNode =
|
|
406
|
+
nextField === ".." ? schema.parent : schema.getChildNode(nextField);
|
|
407
|
+
if (!childNode) {
|
|
408
|
+
childNode = nodeForSchema(missingField(nextField), schema, schema);
|
|
409
|
+
}
|
|
410
|
+
acc = next(acc, childNode);
|
|
411
|
+
schema = childNode;
|
|
412
|
+
i++;
|
|
413
|
+
}
|
|
414
|
+
return acc;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export function traverseData(
|
|
418
|
+
fieldPath: string[],
|
|
419
|
+
root: SchemaNode,
|
|
420
|
+
data: { [k: string]: any },
|
|
421
|
+
): unknown {
|
|
422
|
+
return traverseSchemaPath(
|
|
423
|
+
fieldPath,
|
|
424
|
+
root,
|
|
425
|
+
data,
|
|
426
|
+
(acc, n) => acc?.[n.field.field] as any,
|
|
427
|
+
);
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
export function schemaDataForFieldPath(
|
|
431
|
+
fieldPath: string[],
|
|
432
|
+
dataNode: SchemaDataNode,
|
|
433
|
+
): SchemaDataNode {
|
|
434
|
+
let i = 0;
|
|
435
|
+
while (i < fieldPath.length) {
|
|
436
|
+
const nextField = fieldPath[i];
|
|
437
|
+
let nextNode =
|
|
438
|
+
nextField === ".." ? dataNode.parent : lookupField(nextField);
|
|
439
|
+
nextNode ??= makeSchemaDataNode(
|
|
440
|
+
nodeForSchema(missingField(nextField), dataNode.schema, dataNode.schema),
|
|
441
|
+
newControl(undefined),
|
|
442
|
+
);
|
|
443
|
+
dataNode = nextNode;
|
|
444
|
+
i++;
|
|
445
|
+
}
|
|
446
|
+
return dataNode;
|
|
447
|
+
|
|
448
|
+
function lookupField(field: string): SchemaDataNode | undefined {
|
|
449
|
+
const childNode = dataNode.schema.getChildNode(field);
|
|
450
|
+
if (childNode) {
|
|
451
|
+
return dataNode.getChild(childNode);
|
|
452
|
+
}
|
|
453
|
+
return undefined;
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
export function schemaForFieldPath(
|
|
458
|
+
fieldPath: string[],
|
|
459
|
+
schema: SchemaNode,
|
|
460
|
+
): SchemaNode {
|
|
461
|
+
let i = 0;
|
|
462
|
+
while (i < fieldPath.length) {
|
|
463
|
+
const nextField = fieldPath[i];
|
|
464
|
+
let childNode =
|
|
465
|
+
nextField === ".." ? schema.parent : schema.getChildNode(nextField);
|
|
466
|
+
if (!childNode) {
|
|
467
|
+
childNode = nodeForSchema(missingField(nextField), schema, schema);
|
|
468
|
+
}
|
|
469
|
+
schema = childNode;
|
|
470
|
+
i++;
|
|
471
|
+
}
|
|
472
|
+
return schema;
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
export function rootSchemaNode(
|
|
476
|
+
fields: SchemaField[],
|
|
477
|
+
lookup: SchemaTreeLookup = {
|
|
478
|
+
getSchema(schemaId: string): SchemaNode | undefined {
|
|
479
|
+
return undefined;
|
|
480
|
+
},
|
|
481
|
+
},
|
|
482
|
+
): SchemaNode {
|
|
483
|
+
return nodeForSchema(
|
|
484
|
+
{
|
|
485
|
+
type: FieldType.Compound,
|
|
486
|
+
field: "",
|
|
487
|
+
children: fields,
|
|
488
|
+
} as CompoundField,
|
|
489
|
+
lookup,
|
|
490
|
+
undefined,
|
|
491
|
+
);
|
|
492
|
+
}
|
|
493
|
+
|
|
494
|
+
export function getSchemaNodePath(node: SchemaNode) {
|
|
495
|
+
const paths: string[] = [];
|
|
496
|
+
let curNode: SchemaNode | undefined = node;
|
|
497
|
+
while (curNode) {
|
|
498
|
+
paths.push(curNode.field.field);
|
|
499
|
+
curNode = curNode.parent;
|
|
500
|
+
}
|
|
501
|
+
return paths.reverse();
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
export function isCompoundNode(node: SchemaNode) {
|
|
505
|
+
return isCompoundField(node.field);
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
/**
|
|
509
|
+
* Returns the relative path from a parent node to a child node.
|
|
510
|
+
* @param parent
|
|
511
|
+
* @param child
|
|
512
|
+
*/
|
|
513
|
+
export function relativePath(parent: SchemaNode, child: SchemaNode): string {
|
|
514
|
+
// return the path from child to parent
|
|
515
|
+
if (parent.id === child.id) return "";
|
|
516
|
+
|
|
517
|
+
const parentPath = getSchemaNodePath(parent);
|
|
518
|
+
const childPath = getSchemaNodePath(child);
|
|
519
|
+
|
|
520
|
+
let i = 0;
|
|
521
|
+
while (
|
|
522
|
+
i < parentPath.length &&
|
|
523
|
+
i < childPath.length &&
|
|
524
|
+
parentPath[i] === childPath[i]
|
|
525
|
+
) {
|
|
526
|
+
i++;
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
const upLevels = parentPath.length - i;
|
|
530
|
+
const downPath = childPath.slice(i).join("/");
|
|
531
|
+
|
|
532
|
+
return "../".repeat(upLevels) + downPath;
|
|
533
|
+
}
|
|
534
|
+
|
|
136
535
|
export enum SchemaTags {
|
|
137
536
|
NoControl = "_NoControl",
|
|
138
537
|
HtmlEditor = "_HtmlEditor",
|