From 5b16ab26a12ecb08df8a8e9f954da23d88834391 Mon Sep 17 00:00:00 2001 From: Krasimir Chobantonov Date: Sat, 23 Aug 2025 12:56:00 -0400 Subject: [PATCH 1/3] feat(validator): add config to ValidateFunctionContext --- .../layouts/categorization-layout.renderer.ts | 9 +- .../src/library/other/util.ts | 9 +- packages/core/src/mappers/cell.ts | 4 +- packages/core/src/mappers/renderer.ts | 21 +++- packages/core/src/mappers/util.ts | 2 +- packages/core/src/models/uischema.ts | 2 + packages/core/src/util/runtime.ts | 35 ++++-- packages/core/src/util/util.ts | 18 ++- packages/core/test/util/runtime.test.ts | 119 +++++++++++++----- .../layouts/MaterialCategorizationLayout.tsx | 5 +- .../MaterialCategorizationStepperLayout.tsx | 4 +- .../categorization/CategorizationList.tsx | 7 +- .../categorization/CategorizationRenderer.tsx | 2 + 13 files changed, 173 insertions(+), 64 deletions(-) diff --git a/packages/angular-material/src/library/layouts/categorization-layout.renderer.ts b/packages/angular-material/src/library/layouts/categorization-layout.renderer.ts index 06c6465a74..999843f2f5 100644 --- a/packages/angular-material/src/library/layouts/categorization-layout.renderer.ts +++ b/packages/angular-material/src/library/layouts/categorization-layout.renderer.ts @@ -30,6 +30,7 @@ import { defaultJsonFormsI18nState, deriveLabelForUISchemaElement, getAjv, + getConfig, isVisible, JsonFormsState, Labelable, @@ -87,7 +88,13 @@ export class CategorizationTabLayoutRenderer this.hidden = !props.visible; this.visibleCategories = this.uischema.elements.filter( (category: Category | Categorization) => - isVisible(category, props.data, undefined, getAjv(state)) + isVisible( + category, + props.data, + undefined, + getAjv(state), + getConfig(state) + ) ); this.categoryLabels = this.visibleCategories.map((element) => deriveLabelForUISchemaElement( diff --git a/packages/angular-material/src/library/other/util.ts b/packages/angular-material/src/library/other/util.ts index 7672002873..4d2fa04fb4 100644 --- a/packages/angular-material/src/library/other/util.ts +++ b/packages/angular-material/src/library/other/util.ts @@ -25,6 +25,7 @@ import { ControlElement, getAjv, + getConfig, getData, isVisible, JsonFormsState, @@ -44,7 +45,13 @@ export const mapStateToVisible = ( const visible = ownProps.visible !== undefined ? ownProps.visible - : isVisible(ownProps.uischema, getData(state), undefined, getAjv(state)); + : isVisible( + ownProps.uischema, + getData(state), + undefined, + getAjv(state), + getConfig(state) + ); return { visible, diff --git a/packages/core/src/mappers/cell.ts b/packages/core/src/mappers/cell.ts index 8c011cca40..73f01d7f6a 100644 --- a/packages/core/src/mappers/cell.ts +++ b/packages/core/src/mappers/cell.ts @@ -112,13 +112,13 @@ export const mapStateToCellProps = ( ): StatePropsOfCell => { const { id, schema, path, uischema, renderers, cells } = ownProps; const rootData = getData(state); + const config = getConfig(state); const visible = ownProps.visible !== undefined ? ownProps.visible - : isVisible(uischema, rootData, undefined, getAjv(state)); + : isVisible(uischema, rootData, undefined, getAjv(state), config); const rootSchema = getSchema(state); - const config = getConfig(state); /* When determining the enabled state of cells we take a shortcut: At the * moment it's only possible to configure enablement and disablement at the diff --git a/packages/core/src/mappers/renderer.ts b/packages/core/src/mappers/renderer.ts index f677303341..2eca53d057 100644 --- a/packages/core/src/mappers/renderer.ts +++ b/packages/core/src/mappers/renderer.ts @@ -582,9 +582,11 @@ export const mapStateToControlProps = ( const { uischema } = ownProps; const rootData = getData(state); const path = composeWithUi(uischema, ownProps.path); + const config = getConfig(state); + const visible: boolean = ownProps.visible === undefined || hasShowRule(uischema) - ? isVisible(uischema, rootData, ownProps.path, getAjv(state)) + ? isVisible(uischema, rootData, ownProps.path, getAjv(state), config) : ownProps.visible; const controlElement = uischema as ControlElement; const id = ownProps.id; @@ -604,7 +606,6 @@ export const mapStateToControlProps = ( const data = Resolve.data(rootData, path); const labelDesc = createLabelDescriptionFrom(uischema, resolvedSchema); const label = labelDesc.show ? labelDesc.text : ''; - const config = getConfig(state); const enabled: boolean = isInherentlyEnabled( state, ownProps, @@ -1042,7 +1043,13 @@ export const mapStateToLayoutProps = ( const { uischema } = ownProps; const visible: boolean = ownProps.visible === undefined || hasShowRule(uischema) - ? isVisible(ownProps.uischema, rootData, ownProps.path, getAjv(state)) + ? isVisible( + ownProps.uischema, + rootData, + ownProps.path, + getAjv(state), + getConfig(state) + ) : ownProps.visible; const data = Resolve.data(rootData, ownProps.path); @@ -1280,7 +1287,13 @@ export const mapStateToLabelProps = ( const visible: boolean = props.visible === undefined || hasShowRule(uischema) - ? isVisible(props.uischema, getData(state), props.path, getAjv(state)) + ? isVisible( + props.uischema, + getData(state), + props.path, + getAjv(state), + getConfig(state) + ) : props.visible; const text = uischema.text; diff --git a/packages/core/src/mappers/util.ts b/packages/core/src/mappers/util.ts index e084a529ff..c393073d81 100644 --- a/packages/core/src/mappers/util.ts +++ b/packages/core/src/mappers/util.ts @@ -19,7 +19,7 @@ export const isInherentlyEnabled = ( return false; } if (uischema && hasEnableRule(uischema)) { - return isEnabled(uischema, rootData, ownProps?.path, getAjv(state)); + return isEnabled(uischema, rootData, ownProps?.path, getAjv(state), config); } if (typeof uischema?.options?.readonly === 'boolean') { return !uischema.options.readonly; diff --git a/packages/core/src/models/uischema.ts b/packages/core/src/models/uischema.ts index 229cbe5249..e61f6f83db 100644 --- a/packages/core/src/models/uischema.ts +++ b/packages/core/src/models/uischema.ts @@ -169,6 +169,8 @@ export interface ValidateFunctionContext { path: string | undefined; /** The `UISchemaElement` containing the rule that uses the ValidateFunctionCondition, e.g. a `ControlElement` */ uischemaElement: UISchemaElement; + /** The form config */ + config: any; } /** diff --git a/packages/core/src/util/runtime.ts b/packages/core/src/util/runtime.ts index 540bf9d7ba..e2262ef587 100644 --- a/packages/core/src/util/runtime.ts +++ b/packages/core/src/util/runtime.ts @@ -67,16 +67,19 @@ const evaluateCondition = ( uischema: UISchemaElement, condition: Condition, path: string, - ajv: Ajv + ajv: Ajv, + config: any ): boolean => { if (isAndCondition(condition)) { return condition.conditions.reduce( - (acc, cur) => acc && evaluateCondition(data, uischema, cur, path, ajv), + (acc, cur) => + acc && evaluateCondition(data, uischema, cur, path, ajv, config), true ); } else if (isOrCondition(condition)) { return condition.conditions.reduce( - (acc, cur) => acc || evaluateCondition(data, uischema, cur, path, ajv), + (acc, cur) => + acc || evaluateCondition(data, uischema, cur, path, ajv, config), false ); } else if (isLeafCondition(condition)) { @@ -95,6 +98,7 @@ const evaluateCondition = ( fullData: data, path, uischemaElement: uischema, + config, }; return condition.validate(context); } else { @@ -107,19 +111,21 @@ const isRuleFulfilled = ( uischema: UISchemaElement, data: any, path: string, - ajv: Ajv + ajv: Ajv, + config: any ): boolean => { const condition = uischema.rule.condition; - return evaluateCondition(data, uischema, condition, path, ajv); + return evaluateCondition(data, uischema, condition, path, ajv, config); }; export const evalVisibility = ( uischema: UISchemaElement, data: any, path: string = undefined, - ajv: Ajv + ajv: Ajv, + config: any ): boolean => { - const fulfilled = isRuleFulfilled(uischema, data, path, ajv); + const fulfilled = isRuleFulfilled(uischema, data, path, ajv, config); switch (uischema.rule.effect) { case RuleEffect.HIDE: @@ -136,9 +142,10 @@ export const evalEnablement = ( uischema: UISchemaElement, data: any, path: string = undefined, - ajv: Ajv + ajv: Ajv, + config: any ): boolean => { - const fulfilled = isRuleFulfilled(uischema, data, path, ajv); + const fulfilled = isRuleFulfilled(uischema, data, path, ajv, config); switch (uischema.rule.effect) { case RuleEffect.DISABLE: @@ -177,10 +184,11 @@ export const isVisible = ( uischema: UISchemaElement, data: any, path: string = undefined, - ajv: Ajv + ajv: Ajv, + config: any ): boolean => { if (uischema.rule) { - return evalVisibility(uischema, data, path, ajv); + return evalVisibility(uischema, data, path, ajv, config); } return true; @@ -190,10 +198,11 @@ export const isEnabled = ( uischema: UISchemaElement, data: any, path: string = undefined, - ajv: Ajv + ajv: Ajv, + config: any ): boolean => { if (uischema.rule) { - return evalEnablement(uischema, data, path, ajv); + return evalEnablement(uischema, data, path, ajv, config); } return true; diff --git a/packages/core/src/util/util.ts b/packages/core/src/util/util.ts index 67d934b8bf..8b8e60976a 100644 --- a/packages/core/src/util/util.ts +++ b/packages/core/src/util/util.ts @@ -163,10 +163,20 @@ export const Paths = { // Runtime -- export const Runtime = { - isEnabled(uischema: UISchemaElement, data: any, ajv: Ajv): boolean { - return isEnabled(uischema, data, undefined, ajv); + isEnabled( + uischema: UISchemaElement, + data: any, + ajv: Ajv, + config: any + ): boolean { + return isEnabled(uischema, data, undefined, ajv, config); }, - isVisible(uischema: UISchemaElement, data: any, ajv: Ajv): boolean { - return isVisible(uischema, data, undefined, ajv); + isVisible( + uischema: UISchemaElement, + data: any, + ajv: Ajv, + config: any + ): boolean { + return isVisible(uischema, data, undefined, ajv, config); }, }; diff --git a/packages/core/test/util/runtime.test.ts b/packages/core/test/util/runtime.test.ts index cfb4c745cf..94376a0792 100644 --- a/packages/core/test/util/runtime.test.ts +++ b/packages/core/test/util/runtime.test.ts @@ -56,7 +56,7 @@ test('evalVisibility show valid case', (t) => { value: 'foo', ruleValue: 'bar', }; - t.is(evalVisibility(uischema, data, undefined, createAjv()), true); + t.is(evalVisibility(uischema, data, undefined, createAjv(), undefined), true); }); test('evalVisibility show valid case based on AndCondition', (t) => { @@ -87,7 +87,7 @@ test('evalVisibility show valid case based on AndCondition', (t) => { ruleValue1: 'bar', ruleValue2: 'foo', }; - t.is(evalVisibility(uischema, data, undefined, createAjv()), true); + t.is(evalVisibility(uischema, data, undefined, createAjv(), undefined), true); }); test('evalVisibility show invalid case based on AndCondition', (t) => { @@ -118,7 +118,10 @@ test('evalVisibility show invalid case based on AndCondition', (t) => { ruleValue1: 'bar', ruleValue2: 'foo', }; - t.is(evalVisibility(uischema, data, undefined, createAjv()), false); + t.is( + evalVisibility(uischema, data, undefined, createAjv(), undefined), + false + ); }); test('evalVisibility show valid case based on OrCondition', (t) => { @@ -149,7 +152,7 @@ test('evalVisibility show valid case based on OrCondition', (t) => { ruleValue1: 'bar1', ruleValue2: 'foo', }; - t.is(evalVisibility(uischema, data, undefined, createAjv()), true); + t.is(evalVisibility(uischema, data, undefined, createAjv(), undefined), true); }); test('evalVisibility show invalid case based on OrCondition', (t) => { @@ -180,7 +183,10 @@ test('evalVisibility show invalid case based on OrCondition', (t) => { ruleValue1: 'bar', ruleValue2: 'foo', }; - t.is(evalVisibility(uischema, data, undefined, createAjv()), false); + t.is( + evalVisibility(uischema, data, undefined, createAjv(), undefined), + false + ); }); test('evalVisibility show valid case based on schema condition', (t) => { @@ -202,7 +208,7 @@ test('evalVisibility show valid case based on schema condition', (t) => { value: 'foo', ruleValue: 'bar', }; - t.is(evalVisibility(uischema, data, undefined, createAjv()), true); + t.is(evalVisibility(uischema, data, undefined, createAjv(), undefined), true); }); test('evalVisibility show valid case based on schema condition and enum', (t) => { @@ -224,13 +230,14 @@ test('evalVisibility show valid case based on schema condition and enum', (t) => value: 'foo', ruleValue: 'bar', }; - t.is(evalVisibility(uischema, data, undefined, createAjv()), true); + t.is(evalVisibility(uischema, data, undefined, createAjv(), undefined), true); t.is( evalVisibility( uischema, { ...data, ruleValue: 'baz' }, undefined, - createAjv() + createAjv(), + undefined ), true ); @@ -239,7 +246,8 @@ test('evalVisibility show valid case based on schema condition and enum', (t) => uischema, { ...data, ruleValue: 'foo' }, undefined, - createAjv() + createAjv(), + undefined ), false ); @@ -263,7 +271,10 @@ test('evalVisibility show invalid case', (t) => { value: 'foo', ruleValue: 'foobar', }; - t.deepEqual(evalVisibility(uischema, data, undefined, createAjv()), false); + t.deepEqual( + evalVisibility(uischema, data, undefined, createAjv(), undefined), + false + ); }); test('evalVisibility hide valid case', (t) => { const leafCondition: LeafCondition = { @@ -283,7 +294,10 @@ test('evalVisibility hide valid case', (t) => { value: 'foo', ruleValue: 'bar', }; - t.is(evalVisibility(uischema, data, undefined, createAjv()), false); + t.is( + evalVisibility(uischema, data, undefined, createAjv(), undefined), + false + ); }); test('evalVisibility hide invalid case', (t) => { @@ -304,7 +318,7 @@ test('evalVisibility hide invalid case', (t) => { value: 'foo', ruleValue: 'foobar', }; - t.is(evalVisibility(uischema, data, undefined, createAjv()), true); + t.is(evalVisibility(uischema, data, undefined, createAjv(), undefined), true); }); test('evalEnablement enable valid case', (t) => { @@ -325,7 +339,7 @@ test('evalEnablement enable valid case', (t) => { value: 'foo', ruleValue: 'bar', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), true); + t.is(evalEnablement(uischema, data, undefined, createAjv(), undefined), true); }); test('evalEnablement show valid case based on AndCondition', (t) => { @@ -356,7 +370,7 @@ test('evalEnablement show valid case based on AndCondition', (t) => { ruleValue1: 'bar', ruleValue2: 'foo', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), true); + t.is(evalEnablement(uischema, data, undefined, createAjv(), undefined), true); }); test('evalEnablement show invalid case based on AndCondition', (t) => { @@ -387,7 +401,10 @@ test('evalEnablement show invalid case based on AndCondition', (t) => { ruleValue1: 'bar', ruleValue2: 'foo', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), false); + t.is( + evalEnablement(uischema, data, undefined, createAjv(), undefined), + false + ); }); test('evalEnablement show valid case based on OrCondition', (t) => { @@ -418,7 +435,7 @@ test('evalEnablement show valid case based on OrCondition', (t) => { ruleValue1: 'bar1', ruleValue2: 'foo', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), true); + t.is(evalEnablement(uischema, data, undefined, createAjv(), undefined), true); }); test('evalEnablement show invalid case based on OrCondition', (t) => { @@ -449,7 +466,10 @@ test('evalEnablement show invalid case based on OrCondition', (t) => { ruleValue1: 'bar', ruleValue2: 'foo', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), false); + t.is( + evalEnablement(uischema, data, undefined, createAjv(), undefined), + false + ); }); test('evalEnablement enable invalid case', (t) => { @@ -470,7 +490,10 @@ test('evalEnablement enable invalid case', (t) => { value: 'foo', ruleValue: 'foobar', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), false); + t.is( + evalEnablement(uischema, data, undefined, createAjv(), undefined), + false + ); }); test('evalEnablement disable valid case', (t) => { const leafCondition: LeafCondition = { @@ -490,7 +513,10 @@ test('evalEnablement disable valid case', (t) => { value: 'foo', ruleValue: 'bar', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), false); + t.is( + evalEnablement(uischema, data, undefined, createAjv(), undefined), + false + ); }); // Add test case for ValidateFunctionCondition with evalEnablement (valid enable case) @@ -511,7 +537,7 @@ test('evalEnablement enable valid case based on ValidateFunctionCondition', (t) value: 'foo', ruleValue: 'bar', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), true); + t.is(evalEnablement(uischema, data, undefined, createAjv(), undefined), true); }); // Add test case for ValidateFunctionCondition with evalEnablement (invalid enable case) @@ -532,7 +558,10 @@ test('evalEnablement enable invalid case based on ValidateFunctionCondition', (t value: 'foo', ruleValue: 'foobar', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), false); + t.is( + evalEnablement(uischema, data, undefined, createAjv(), undefined), + false + ); }); // Add test case for ValidateFunctionCondition with evalEnablement (valid disable case) @@ -553,7 +582,10 @@ test('evalEnablement disable valid case based on ValidateFunctionCondition', (t) value: 'foo', ruleValue: 'bar', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), false); + t.is( + evalEnablement(uischema, data, undefined, createAjv(), undefined), + false + ); }); // Add test case for ValidateFunctionCondition with evalEnablement (invalid disable case) @@ -574,7 +606,7 @@ test('evalEnablement disable invalid case based on ValidateFunctionCondition', ( value: 'foo', ruleValue: 'foobar', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), true); + t.is(evalEnablement(uischema, data, undefined, createAjv(), undefined), true); }); // Test context properties for ValidateFunctionCondition @@ -587,7 +619,8 @@ test('ValidateFunctionCondition correctly passes context parameters', (t) => { context.data === 'bar' && (context.fullData as any).value === 'foo' && context.path === undefined && - (context.uischemaElement as any).scope === '#/properties/value' + (context.uischemaElement as any).scope === '#/properties/value' && + typeof context.config.externalValidator === 'function' ); }, }; @@ -603,7 +636,12 @@ test('ValidateFunctionCondition correctly passes context parameters', (t) => { value: 'foo', ruleValue: 'bar', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), true); + const config = { + externalValidator: (_context: ValidateFunctionContext): boolean => { + return true; + }, + }; + t.is(evalEnablement(uischema, data, undefined, createAjv(), config), true); }); test('evalEnablement disable invalid case', (t) => { @@ -624,7 +662,7 @@ test('evalEnablement disable invalid case', (t) => { value: 'foo', ruleValue: 'foobar', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), true); + t.is(evalEnablement(uischema, data, undefined, createAjv(), undefined), true); }); test('evalEnablement disable invalid case based on schema condition', (t) => { @@ -646,13 +684,17 @@ test('evalEnablement disable invalid case based on schema condition', (t) => { value: 'foo', ruleValue: 'bar', }; - t.is(evalEnablement(uischema, data, undefined, createAjv()), false); + t.is( + evalEnablement(uischema, data, undefined, createAjv(), undefined), + false + ); t.is( evalEnablement( uischema, { ...data, ruleValue: 'baz' }, undefined, - createAjv() + createAjv(), + undefined ), false ); @@ -661,7 +703,8 @@ test('evalEnablement disable invalid case based on schema condition', (t) => { uischema, { ...data, ruleValue: 'foo' }, undefined, - createAjv() + createAjv(), + undefined ), true ); @@ -711,12 +754,24 @@ test('evalEnablement fail on failWhenUndefined', (t) => { value: 'foo', }; t.is( - evalEnablement(failConditionTrueUischema, data, undefined, createAjv()), + evalEnablement( + failConditionTrueUischema, + data, + undefined, + createAjv(), + undefined + ), true ); t.is( - evalEnablement(failConditionFalseUischema, data, undefined, createAjv()), - evalEnablement(uischema, data, undefined, createAjv()) + evalEnablement( + failConditionFalseUischema, + data, + undefined, + createAjv(), + undefined + ), + evalEnablement(uischema, data, undefined, createAjv(), undefined) ); }); diff --git a/packages/material-renderers/src/layouts/MaterialCategorizationLayout.tsx b/packages/material-renderers/src/layouts/MaterialCategorizationLayout.tsx index 13ff5a61a0..c45490b2e0 100644 --- a/packages/material-renderers/src/layouts/MaterialCategorizationLayout.tsx +++ b/packages/material-renderers/src/layouts/MaterialCategorizationLayout.tsx @@ -96,6 +96,7 @@ export const MaterialCategorizationLayoutRenderer = ( enabled, selected, onChange, + config, ajv, t, } = props; @@ -106,9 +107,9 @@ export const MaterialCategorizationLayoutRenderer = ( const categories = useMemo( () => categorization.elements.filter((category: Category) => - isVisible(category, data, undefined, ajv) + isVisible(category, data, undefined, ajv, config) ), - [categorization, data, ajv] + [categorization, data, ajv, config] ); if (categorization !== previousCategorization) { diff --git a/packages/material-renderers/src/layouts/MaterialCategorizationStepperLayout.tsx b/packages/material-renderers/src/layouts/MaterialCategorizationStepperLayout.tsx index a863aaea86..eedfdf800b 100644 --- a/packages/material-renderers/src/layouts/MaterialCategorizationStepperLayout.tsx +++ b/packages/material-renderers/src/layouts/MaterialCategorizationStepperLayout.tsx @@ -107,9 +107,9 @@ export const MaterialCategorizationStepperLayoutRenderer = ( const categories = useMemo( () => categorization.elements.filter((category: Category) => - isVisible(category, data, undefined, ajv) + isVisible(category, data, undefined, ajv, config) ), - [categorization, data, ajv] + [categorization, data, ajv, config] ); const childProps: MaterialLayoutRendererProps = { elements: categories[activeCategory].elements, diff --git a/packages/vanilla-renderers/src/complex/categorization/CategorizationList.tsx b/packages/vanilla-renderers/src/complex/categorization/CategorizationList.tsx index b723413fa2..074dccd606 100644 --- a/packages/vanilla-renderers/src/complex/categorization/CategorizationList.tsx +++ b/packages/vanilla-renderers/src/complex/categorization/CategorizationList.tsx @@ -47,6 +47,7 @@ export interface CategorizationProps { subcategoriesClassName: string; groupClassName: string; t: Translator; + config: any; } export const CategorizationList = ({ @@ -59,12 +60,13 @@ export const CategorizationList = ({ groupClassName, t, ajv, + config, }: CategorizationProps & AjvProps) => { const filteredElements = useMemo(() => { return elements.filter((category: Category | Categorization) => - isVisible(category, data, undefined, ajv) + isVisible(category, data, undefined, ajv, config) ); - }, [elements, data, ajv]); + }, [elements, data, ajv, config]); const categoryLabels = useMemo( () => filteredElements.map((cat) => deriveLabelForUISchemaElement(cat, t)), @@ -83,6 +85,7 @@ export const CategorizationList = ({ elements={category.elements} data={data} ajv={ajv} + config={config} depth={depth + 1} onSelect={onSelect} subcategoriesClassName={subcategoriesClassName} diff --git a/packages/vanilla-renderers/src/complex/categorization/CategorizationRenderer.tsx b/packages/vanilla-renderers/src/complex/categorization/CategorizationRenderer.tsx index 47bcb5f370..695af5a5ab 100644 --- a/packages/vanilla-renderers/src/complex/categorization/CategorizationRenderer.tsx +++ b/packages/vanilla-renderers/src/complex/categorization/CategorizationRenderer.tsx @@ -54,6 +54,7 @@ export const CategorizationRenderer = ({ getStyleAsClassName, onChange, ajv, + config, }: LayoutProps & VanillaRendererProps & TranslateProps & @@ -97,6 +98,7 @@ export const CategorizationRenderer = ({ selectedCategory={elements[safeCategory] as Category} data={data} ajv={ajv} + config={config} depth={0} onSelect={onCategorySelected} subcategoriesClassName={subcategoriesClassName} From 2c347300a2218b3a910dfbabb9594b7cb094090a Mon Sep 17 00:00:00 2001 From: Stefan Dirix Date: Mon, 22 Sep 2025 11:33:23 +0200 Subject: [PATCH 2/3] replace config:any with config:unknown --- packages/core/src/models/uischema.ts | 2 +- packages/core/src/util/runtime.ts | 12 ++++++------ packages/core/src/util/util.ts | 4 ++-- .../complex/categorization/CategorizationList.tsx | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/packages/core/src/models/uischema.ts b/packages/core/src/models/uischema.ts index e61f6f83db..cc5ae938c6 100644 --- a/packages/core/src/models/uischema.ts +++ b/packages/core/src/models/uischema.ts @@ -170,7 +170,7 @@ export interface ValidateFunctionContext { /** The `UISchemaElement` containing the rule that uses the ValidateFunctionCondition, e.g. a `ControlElement` */ uischemaElement: UISchemaElement; /** The form config */ - config: any; + config: unknown; } /** diff --git a/packages/core/src/util/runtime.ts b/packages/core/src/util/runtime.ts index e2262ef587..77caca7621 100644 --- a/packages/core/src/util/runtime.ts +++ b/packages/core/src/util/runtime.ts @@ -68,7 +68,7 @@ const evaluateCondition = ( condition: Condition, path: string, ajv: Ajv, - config: any + config: unknown ): boolean => { if (isAndCondition(condition)) { return condition.conditions.reduce( @@ -112,7 +112,7 @@ const isRuleFulfilled = ( data: any, path: string, ajv: Ajv, - config: any + config: unknown ): boolean => { const condition = uischema.rule.condition; return evaluateCondition(data, uischema, condition, path, ajv, config); @@ -123,7 +123,7 @@ export const evalVisibility = ( data: any, path: string = undefined, ajv: Ajv, - config: any + config: unknown ): boolean => { const fulfilled = isRuleFulfilled(uischema, data, path, ajv, config); @@ -143,7 +143,7 @@ export const evalEnablement = ( data: any, path: string = undefined, ajv: Ajv, - config: any + config: unknown ): boolean => { const fulfilled = isRuleFulfilled(uischema, data, path, ajv, config); @@ -185,7 +185,7 @@ export const isVisible = ( data: any, path: string = undefined, ajv: Ajv, - config: any + config: unknown ): boolean => { if (uischema.rule) { return evalVisibility(uischema, data, path, ajv, config); @@ -199,7 +199,7 @@ export const isEnabled = ( data: any, path: string = undefined, ajv: Ajv, - config: any + config: unknown ): boolean => { if (uischema.rule) { return evalEnablement(uischema, data, path, ajv, config); diff --git a/packages/core/src/util/util.ts b/packages/core/src/util/util.ts index 8b8e60976a..959651e433 100644 --- a/packages/core/src/util/util.ts +++ b/packages/core/src/util/util.ts @@ -167,7 +167,7 @@ export const Runtime = { uischema: UISchemaElement, data: any, ajv: Ajv, - config: any + config: unknown ): boolean { return isEnabled(uischema, data, undefined, ajv, config); }, @@ -175,7 +175,7 @@ export const Runtime = { uischema: UISchemaElement, data: any, ajv: Ajv, - config: any + config: unknown ): boolean { return isVisible(uischema, data, undefined, ajv, config); }, diff --git a/packages/vanilla-renderers/src/complex/categorization/CategorizationList.tsx b/packages/vanilla-renderers/src/complex/categorization/CategorizationList.tsx index 074dccd606..4b354b432d 100644 --- a/packages/vanilla-renderers/src/complex/categorization/CategorizationList.tsx +++ b/packages/vanilla-renderers/src/complex/categorization/CategorizationList.tsx @@ -47,7 +47,7 @@ export interface CategorizationProps { subcategoriesClassName: string; groupClassName: string; t: Translator; - config: any; + config: unknown; } export const CategorizationList = ({ From a499eec9c863e10e76e3b1fe5cc0c29edef9f1ae Mon Sep 17 00:00:00 2001 From: Stefan Dirix Date: Mon, 22 Sep 2025 12:09:10 +0200 Subject: [PATCH 3/3] fix typing in runtime.test.ts --- packages/core/test/util/runtime.test.ts | 92 +++++++++++++++++-------- 1 file changed, 63 insertions(+), 29 deletions(-) diff --git a/packages/core/test/util/runtime.test.ts b/packages/core/test/util/runtime.test.ts index 94376a0792..3f068ff658 100644 --- a/packages/core/test/util/runtime.test.ts +++ b/packages/core/test/util/runtime.test.ts @@ -620,7 +620,7 @@ test('ValidateFunctionCondition correctly passes context parameters', (t) => { (context.fullData as any).value === 'foo' && context.path === undefined && (context.uischemaElement as any).scope === '#/properties/value' && - typeof context.config.externalValidator === 'function' + typeof (context.config as any).externalValidator === 'function' ); }, }; @@ -780,8 +780,8 @@ test('isInherentlyEnabled disabled globally', (t) => { isInherentlyEnabled( { jsonforms: { readonly: true } }, null, - null, - null, + null as any, + undefined, null, null ) @@ -790,21 +790,37 @@ test('isInherentlyEnabled disabled globally', (t) => { test('isInherentlyEnabled disabled by ownProps', (t) => { t.false( - isInherentlyEnabled(null, { enabled: false }, null, null, null, null) + isInherentlyEnabled( + null as any, + { enabled: false }, + null as any, + undefined, + null, + null + ) ); }); test('isInherentlyEnabled enabled by ownProps', (t) => { - t.true(isInherentlyEnabled(null, { enabled: true }, null, null, null, null)); + t.true( + isInherentlyEnabled( + null as any, + { enabled: true }, + null as any, + undefined, + null, + null + ) + ); }); test('isInherentlyEnabled disabled by uischema', (t) => { t.false( isInherentlyEnabled( - null, + null as any, null, { options: { readonly: true } } as unknown as ControlElement, - null, + undefined, null, null ) @@ -814,10 +830,10 @@ test('isInherentlyEnabled disabled by uischema', (t) => { test('isInherentlyEnabled disabled by uischema over ownProps', (t) => { t.false( isInherentlyEnabled( - null, + null as any, { enabled: true }, { options: { readonly: true } } as unknown as ControlElement, - null, + undefined, null, null ) @@ -827,7 +843,7 @@ test('isInherentlyEnabled disabled by uischema over ownProps', (t) => { test('isInherentlyEnabled enabled by uischema over schema', (t) => { t.true( isInherentlyEnabled( - null, + null as any, null, { options: { readonly: false } } as unknown as ControlElement, { readOnly: true }, @@ -840,9 +856,9 @@ test('isInherentlyEnabled enabled by uischema over schema', (t) => { test('isInherentlyEnabled disabled by ownProps over schema enablement', (t) => { t.false( isInherentlyEnabled( - null, + null as any, { enabled: false }, - null, + null as any, { readOnly: false }, null, null @@ -853,7 +869,7 @@ test('isInherentlyEnabled disabled by ownProps over schema enablement', (t) => { test('isInherentlyEnabled disabled by uischema over schema', (t) => { t.false( isInherentlyEnabled( - null, + null as any, null, { options: { readonly: true } } as unknown as ControlElement, { readOnly: false }, @@ -865,16 +881,23 @@ test('isInherentlyEnabled disabled by uischema over schema', (t) => { test('isInherentlyEnabled disabled by schema', (t) => { t.false( - isInherentlyEnabled(null, null, null, { readOnly: true }, null, null) + isInherentlyEnabled( + null as any, + null, + null as any, + { readOnly: true }, + null, + null + ) ); }); test('isInherentlyEnabled disabled by schema over ownProps', (t) => { t.false( isInherentlyEnabled( - null, + null as any, { enabled: true }, - null, + null as any, { readOnly: true }, null, null @@ -905,7 +928,7 @@ test('isInherentlyEnabled disabled by rule', (t) => { { jsonforms: { core: { ajv: createAjv() } as JsonFormsCore } }, null, uischema, - null, + undefined, data, null ) @@ -940,7 +963,7 @@ test('isInherentlyEnabled disabled by global over rule ', (t) => { }, null, uischema, - null, + undefined, data, null ) @@ -949,25 +972,34 @@ test('isInherentlyEnabled disabled by global over rule ', (t) => { test('isInherentlyEnabled disabled by config', (t) => { t.false( - isInherentlyEnabled(null, null, null, null, null, { readonly: true }) + isInherentlyEnabled(null as any, null, null as any, undefined, null, { + readonly: true, + }) ); }); test('isInherentlyEnabled enabled by config over ownProps', (t) => { t.true( - isInherentlyEnabled(null, { enabled: false }, null, null, null, { - readonly: false, - }) + isInherentlyEnabled( + null as any, + { enabled: false }, + null as any, + undefined, + null, + { + readonly: false, + } + ) ); }); test('isInherentlyEnabled enabled by uischema over config', (t) => { t.true( isInherentlyEnabled( - null, + null as any, null, { options: { readonly: false } } as unknown as ControlElement, - null, + undefined, null, { readonly: true } ) @@ -977,24 +1009,24 @@ test('isInherentlyEnabled enabled by uischema over config', (t) => { test('isInherentlyEnabled prefer readonly over readOnly', (t) => { t.true( isInherentlyEnabled( - null, + null as any, null, { options: { readonly: false, readOnly: true }, } as unknown as ControlElement, - null, + undefined, null, null ) ); t.false( isInherentlyEnabled( - null, + null as any, null, { options: { readonly: true, readOnly: false }, } as unknown as ControlElement, - null, + undefined, null, null ) @@ -1002,5 +1034,7 @@ test('isInherentlyEnabled prefer readonly over readOnly', (t) => { }); test('isInherentlyEnabled enabled', (t) => { - t.true(isInherentlyEnabled(null, null, null, null, null, null)); + t.true( + isInherentlyEnabled(null as any, null, null as any, undefined, null, null) + ); });