From 4f7c26293f83df75d3a089f415824298c57680b2 Mon Sep 17 00:00:00 2001 From: Victor Geraldsson Date: Thu, 4 Apr 2024 08:58:56 +0200 Subject: [PATCH] fix(form): avoid splitting property names in schema path The schema path passed to custom components in the `formInfo` prop didn't handle property names containing underscore as expected. Now the schema id is not split when a property name can be found in the form data matching all or some leading parts of the schema id. --- src/components/form/fields/schema-field.ts | 56 +++++++++++++++++++++- 1 file changed, 54 insertions(+), 2 deletions(-) diff --git a/src/components/form/fields/schema-field.ts b/src/components/form/fields/schema-field.ts index bd1043b89c..02403a8e6b 100644 --- a/src/components/form/fields/schema-field.ts +++ b/src/components/form/fields/schema-field.ts @@ -2,7 +2,7 @@ import { LimeElementsAdapter } from '../adapters'; import JSONSchemaField from '@rjsf/core/lib/components/fields/SchemaField'; import React from 'react'; import { FieldProps } from './types'; -import { isEmpty, capitalize } from 'lodash-es'; +import { isEmpty, capitalize, has } from 'lodash-es'; import { resetDependentFields } from './field-helpers'; import { FieldTemplate } from '../templates'; import { getHelpComponent } from '../help'; @@ -293,6 +293,58 @@ export class SchemaField extends React.Component { return undefined; } - return schemaId.replace('root_', '').split('_'); + let path: string[] = []; + const idSeparator = '_'; + const startIndex = schemaId.indexOf(idSeparator) + 1; + const endIndex = schemaId.lastIndexOf(idSeparator + this.props.name); + + if (endIndex > startIndex) { + path = this.splitSchemaId( + schemaId.slice(startIndex, endIndex), + idSeparator, + ); + } + + path.push(this.props.name); + + return path; + } + + // Splits schemaId into a property path array, + // preserving property names that contain the separator + private splitSchemaId(schemaId: string, separator: string): string[] { + const idParts = schemaId.split(separator); + let formData = this.props.registry.formContext.rootValue; + + if (has(formData, idParts)) { + return idParts; + } + + const path = []; + + // Finds the next key to add to the path, + // while removing elements from the beginning of the idParts array + const nextKey = () => { + let count = idParts.length; + while ( + count > 1 && + !(idParts.slice(0, count).join(separator) in formData) + ) { + count--; + } + + return idParts.splice(0, count).join(separator); + }; + + while (formData && typeof formData === 'object' && idParts.length > 0) { + const key = nextKey(); + + path.push(key); + formData = formData[key]; + } + + path.push(...idParts); + + return path; } }