@rjsf/utils 6.3.1 → 6.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/types.d.ts CHANGED
@@ -813,6 +813,8 @@ export type UISchemaSubmitButtonOptions = {
813
813
  className?: string;
814
814
  };
815
815
  };
816
+ /** Represents a primitive JSON Schema enum value */
817
+ export type EnumValue = string | number | boolean;
816
818
  /** This type represents an element used to render an enum option */
817
819
  export type EnumOptionsType<S extends StrictRJSFSchema = RJSFSchema> = {
818
820
  /** The value for the enum option */
@@ -855,9 +857,15 @@ type UIOptionsBaseType<T = any, S extends StrictRJSFSchema = RJSFSchema, F exten
855
857
  /** The default value to use when an input for a field is empty */
856
858
  emptyValue?: any;
857
859
  /** Will disable any of the enum options specified in the array (by value) */
858
- enumDisabled?: Array<string | number | boolean>;
859
- /** Allows a user to provide a list of labels for enum values in the schema */
860
- enumNames?: string[];
860
+ enumDisabled?: EnumValue[];
861
+ /** Allows a user to provide a list of labels for enum values in the schema.
862
+ * Can be an array (positional, matched by index) or a Record mapping enum values to labels (matched by value).
863
+ */
864
+ enumNames?: string[] | Record<string | number, string>;
865
+ /** Controls the display order of enum options, following the same pattern as `ui:order` for object properties.
866
+ * Supports a `'*'` wildcard to represent all remaining values in their original schema order.
867
+ */
868
+ enumOrder?: EnumValue[];
861
869
  /** Provides an optional field within a schema to be used as the oneOf/anyOf selector when there isn't a
862
870
  * discriminator
863
871
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rjsf/utils",
3
- "version": "6.3.1",
3
+ "version": "6.4.1",
4
4
  "main": "dist/index.js",
5
5
  "module": "lib/index.js",
6
6
  "typings": "lib/index.d.ts",
package/src/constants.ts CHANGED
@@ -25,6 +25,7 @@ export const READONLY_KEY = 'readonly';
25
25
  export const REQUIRED_KEY = 'required';
26
26
  export const SUBMIT_BTN_OPTIONS_KEY = 'submitButtonOptions';
27
27
  export const REF_KEY = '$ref';
28
+ export const RJSF_REF_KEY = '__rjsf_ref';
28
29
  export const SCHEMA_KEY = '$schema';
29
30
  export const DEFAULT_ID_PREFIX = 'root';
30
31
  export const DEFAULT_ID_SEPARATOR = '_';
@@ -1,7 +1,8 @@
1
1
  import isEqual from 'lodash/isEqual';
2
+ import omit from 'lodash/omit';
2
3
 
3
4
  import { FormContextType, Registry, RJSFSchema, StrictRJSFSchema } from './types';
4
- import { REF_KEY } from './constants';
5
+ import { REF_KEY, RJSF_REF_KEY } from './constants';
5
6
 
6
7
  /** Helper to check whether a JSON schema object is the root schema. The schema is a root schema with root `properties`
7
8
  * key or a root `$ref` key. If the `schemaToCompare` has a root `oneOf` property, the function will
@@ -24,7 +25,7 @@ export default function isRootSchema<T = any, S extends StrictRJSFSchema = RJSFS
24
25
  }
25
26
  if (REF_KEY in rootSchema) {
26
27
  const resolvedSchema = schemaUtils.retrieveSchema(rootSchema);
27
- return isEqual(schemaToCompare, resolvedSchema);
28
+ return isEqual(schemaToCompare, omit(resolvedSchema, RJSF_REF_KEY));
28
29
  }
29
30
  return false;
30
31
  }
@@ -4,7 +4,28 @@ import { CONST_KEY, DEFAULT_KEY, PROPERTIES_KEY } from './constants';
4
4
  import getDiscriminatorFieldFromSchema from './getDiscriminatorFieldFromSchema';
5
5
  import getUiOptions from './getUiOptions';
6
6
  import toConstant from './toConstant';
7
- import { RJSFSchema, EnumOptionsType, StrictRJSFSchema, FormContextType, UiSchema } from './types';
7
+ import { RJSFSchema, EnumOptionsType, EnumValue, StrictRJSFSchema, FormContextType, UiSchema } from './types';
8
+
9
+ /** Reorders `options` according to `order`, which may contain a `'*'` wildcard representing all
10
+ * remaining options in their original order. Options not listed in `order` (and not covered by
11
+ * a wildcard) are dropped.
12
+ */
13
+ function applyEnumOrder<S extends StrictRJSFSchema = RJSFSchema>(
14
+ options: EnumOptionsType<S>[],
15
+ order: EnumValue[],
16
+ ): EnumOptionsType<S>[] {
17
+ const optionsByValue = new Map(options.map((opt) => [String(opt.value), opt]));
18
+ const orderedKeys = new Set(order.filter((v) => v !== '*').map(String));
19
+ const rest = options.filter((opt) => !orderedKeys.has(String(opt.value)));
20
+
21
+ return order.flatMap((entry) => {
22
+ if (entry === '*') {
23
+ return rest;
24
+ }
25
+ const opt = optionsByValue.get(String(entry));
26
+ return opt ? [opt] : [];
27
+ });
28
+ }
8
29
 
9
30
  /** Gets the list of options from the `schema`. If the schema has an enum list, then those enum values are returned. The
10
31
  * label will be the same as the `value`.
@@ -24,15 +45,23 @@ export default function optionsList<T = any, S extends StrictRJSFSchema = RJSFSc
24
45
  uiSchema?: UiSchema<T, S, F>,
25
46
  ): EnumOptionsType<S>[] | undefined {
26
47
  if (schema.enum) {
27
- let enumNames: string[] | undefined;
48
+ let enumNames: string[] | Record<string | number, string> | undefined;
49
+ let enumOrder: EnumValue[] | undefined;
28
50
  if (uiSchema) {
29
- const { enumNames: uiEnumNames } = getUiOptions<T, S, F>(uiSchema);
51
+ const { enumNames: uiEnumNames, enumOrder: uiEnumOrder } = getUiOptions<T, S, F>(uiSchema);
30
52
  enumNames = uiEnumNames;
53
+ enumOrder = uiEnumOrder;
31
54
  }
32
- return schema.enum.map((value, i) => {
33
- const label = enumNames?.[i] || String(value);
55
+ let options = schema.enum.map((value, i) => {
56
+ const label = Array.isArray(enumNames)
57
+ ? enumNames[i] || String(value)
58
+ : enumNames?.[String(value)] || String(value);
34
59
  return { label, value };
35
60
  });
61
+ if (enumOrder) {
62
+ options = applyEnumOrder(options, enumOrder);
63
+ }
64
+ return options;
36
65
  }
37
66
  let altSchemas: S['anyOf'] | S['oneOf'] = undefined;
38
67
  let altUiSchemas: UiSchema<T, S, F> | undefined = undefined;
@@ -6,6 +6,7 @@ import {
6
6
  ONE_OF_KEY,
7
7
  PROPERTIES_KEY,
8
8
  REF_KEY,
9
+ RJSF_REF_KEY,
9
10
  } from './constants';
10
11
  import findSchemaDefinition from './findSchemaDefinition';
11
12
  import isObject from './isObject';
@@ -141,7 +142,7 @@ export default function resolveUiSchema<
141
142
  S extends StrictRJSFSchema = RJSFSchema,
142
143
  F extends FormContextType = any,
143
144
  >(schema: S, localUiSchema: UiSchema<T, S, F> | undefined, registry: Registry<T, S, F>): UiSchema<T, S, F> {
144
- const ref = schema[REF_KEY] as string | undefined;
145
+ const ref = ((schema as GenericObjectType)[RJSF_REF_KEY] ?? schema[REF_KEY]) as string | undefined;
145
146
  const definitionUiSchema = ref ? registry.uiSchemaDefinitions?.[ref] : undefined;
146
147
 
147
148
  if (!definitionUiSchema) {
@@ -22,6 +22,7 @@ import {
22
22
  PATTERN_PROPERTIES_KEY,
23
23
  PROPERTIES_KEY,
24
24
  REF_KEY,
25
+ RJSF_REF_KEY,
25
26
  } from '../constants';
26
27
  import findSchemaDefinition, { splitKeyElementFromObject } from '../findSchemaDefinition';
27
28
  import getDiscriminatorFieldFromSchema from '../getDiscriminatorFieldFromSchema';
@@ -371,7 +372,7 @@ export function resolveAllReferences<S extends StrictRJSFSchema = RJSFSchema>(
371
372
  recurseList.push($ref!);
372
373
  // Retrieve the referenced schema definition.
373
374
  const refSchema = findSchemaDefinition<S>($ref, rootSchema, baseURI);
374
- resolvedSchema = { ...refSchema, ...localSchema };
375
+ resolvedSchema = { ...refSchema, ...localSchema, [RJSF_REF_KEY]: $ref };
375
376
  if (ID_KEY in resolvedSchema) {
376
377
  baseURI = resolvedSchema[ID_KEY];
377
378
  }
@@ -1,4 +1,5 @@
1
1
  import get from 'lodash/get';
2
+ import isObject from 'lodash/isObject';
2
3
  import set from 'lodash/set';
3
4
 
4
5
  import {
@@ -98,6 +99,23 @@ function toPathSchemaInternal<T = any, S extends StrictRJSFSchema = RJSFSchema,
98
99
 
99
100
  if (ADDITIONAL_PROPERTIES_KEY in schema && schema[ADDITIONAL_PROPERTIES_KEY] !== false) {
100
101
  set(pathSchema, RJSF_ADDITIONAL_PROPERTIES_FLAG, true);
102
+ const additionalSchema = (
103
+ isObject(schema[ADDITIONAL_PROPERTIES_KEY]) ? schema[ADDITIONAL_PROPERTIES_KEY] : {}
104
+ ) as S;
105
+ const definedProperties = get(schema, PROPERTIES_KEY, {});
106
+ for (const key of Object.keys((formData ?? {}) as GenericObjectType)) {
107
+ if (!(key in definedProperties)) {
108
+ (pathSchema as PathSchema<GenericObjectType>)[key] = toPathSchemaInternal<T, S, F>(
109
+ validator,
110
+ additionalSchema,
111
+ `${name}.${key}`,
112
+ rootSchema,
113
+ get(formData, [key]),
114
+ _recurseList,
115
+ experimental_customMergeAllOf,
116
+ );
117
+ }
118
+ }
101
119
  }
102
120
 
103
121
  if (ITEMS_KEY in schema && Array.isArray(formData)) {
package/src/types.ts CHANGED
@@ -1008,6 +1008,9 @@ export type UISchemaSubmitButtonOptions = {
1008
1008
  };
1009
1009
  };
1010
1010
 
1011
+ /** Represents a primitive JSON Schema enum value */
1012
+ export type EnumValue = string | number | boolean;
1013
+
1011
1014
  /** This type represents an element used to render an enum option */
1012
1015
  export type EnumOptionsType<S extends StrictRJSFSchema = RJSFSchema> = {
1013
1016
  /** The value for the enum option */
@@ -1071,9 +1074,15 @@ type UIOptionsBaseType<T = any, S extends StrictRJSFSchema = RJSFSchema, F exten
1071
1074
  /** The default value to use when an input for a field is empty */
1072
1075
  emptyValue?: any;
1073
1076
  /** Will disable any of the enum options specified in the array (by value) */
1074
- enumDisabled?: Array<string | number | boolean>;
1075
- /** Allows a user to provide a list of labels for enum values in the schema */
1076
- enumNames?: string[];
1077
+ enumDisabled?: EnumValue[];
1078
+ /** Allows a user to provide a list of labels for enum values in the schema.
1079
+ * Can be an array (positional, matched by index) or a Record mapping enum values to labels (matched by value).
1080
+ */
1081
+ enumNames?: string[] | Record<string | number, string>;
1082
+ /** Controls the display order of enum options, following the same pattern as `ui:order` for object properties.
1083
+ * Supports a `'*'` wildcard to represent all remaining values in their original schema order.
1084
+ */
1085
+ enumOrder?: EnumValue[];
1077
1086
  /** Provides an optional field within a schema to be used as the oneOf/anyOf selector when there isn't a
1078
1087
  * discriminator
1079
1088
  */