Skip to content

Update conditional spect and add support for new operators#35

Merged
doneill merged 3 commits intodevelopfrom
34-updated-conditional
Mar 10, 2026
Merged

Update conditional spect and add support for new operators#35
doneill merged 3 commits intodevelopfrom
34-updated-conditional

Conversation

@doneill
Copy link
Collaborator

@doneill doneill commented Mar 5, 2026

Proposed Changes

  • src/common/types.ts

    • Added 5 new operators to V2ConditionOperator
      • IS_EMPTY
      • IS_NOT_EMPTY
      • IS_EXACTLY
      • IS_CONTAINED_BY
      • IS_NOT_CONTAINED_BY
    • Extended V2Condition.value to include string[] for multi-value conditions
  • src/v2/conditions.ts

    • buildContainsSchema
      • rewritten to return a full anyOf with array (contains), object (required), and string (pattern) branches
    • buildIsEmptySchema(fieldName)
      • root-scoped anyOf checking not-required, empty array, null, empty object, empty string
    • buildIsExactlySchema(value)
      • anyOf with per-type branches (array/boolean/number/object/string); boolean and number branches resolve the parsed value for single strings, become const: null for arrays
    • buildIsContainedBySchema(value)
      • anyOf with items.enum / propertyNames.enum / enum branches
    • buildIsNotContainedBySchema(value)
      • anyOf with negated items.enum / propertyNames.enum / enum branches
    • buildConditionSchema
      • routes IS_EMPTY to its root-level schema directly instead of wrapping in properties/required
    • buildSchemaBasedCondition
      • single IS_EMPTY condition uses scope: #; all others use scope: #/properties/fieldName
    • getOperatorSchema
      • handles all new operators; HAS_INPUT and IS_NOT_EMPTY share the same builder
    • validateConditions
      • validates value requirements for all new operators

Implementation Test

In React Native client app, e.g. EarthRanger

- yarn remove @earthranger/react-native-jsonforms-formatter
- yarn add @earthranger/react-native-jsonforms-formatter@2.0.0-beta.24

Unit Tests

jest test/v2.conditions.test.ts
 PASS  test/v2.conditions.test.ts
  buildContainsSchema
    ✓ single-element array behaves the same as single string (1 ms)
    single string value
      ✓ returns anyOf with three branches (1 ms)
      ✓ array branch uses contains
      ✓ object branch uses required (1 ms)
      ✓ string branch uses pattern
    array of values
      ✓ array branch has one contains entry per value (1 ms)
      ✓ object branch requires all values
      ✓ string branch is unsatisfiable (const: null)
  buildIsEmptySchema
    ✓ returns an anyOf with 5 branches
    ✓ first branch: field not required (absent)
    ✓ second branch: empty array
    ✓ third branch: null value (1 ms)
    ✓ fourth branch: empty object
    ✓ fifth branch: empty string
  buildHasInputSchema
    ✓ uses allOf with not-null + anyOf of non-empty types
    ✓ inner anyOf covers array, boolean, number, object, string (1 ms)
  buildDoesNotHaveInputSchema
    ✓ wraps buildHasInputSchema in a not
  buildIsExactlySchema
    single plain string ("elephant")
      ✓ array branch: contains + maxItems 1
      ✓ boolean branch: impossible (const: null)
      ✓ number branch: impossible (const: null)
      ✓ object branch: properties + required + unevaluatedProperties
      ✓ string branch: exact const
    single boolean-parseable string ("true")
      ✓ boolean branch resolves to true
      ✓ number branch is still impossible
      ✓ string branch: const is "true"
    single boolean-parseable string ("false")
      ✓ boolean branch resolves to false
    single number-parseable string ("42")
      ✓ number branch resolves to 42
      ✓ boolean branch is still impossible
    array of strings
      ✓ array branch: all contains + maxItems equals count
      ✓ boolean branch: impossible
      ✓ number branch: impossible (1 ms)
      ✓ object branch: all values as properties
      ✓ string branch: impossible
  buildInputIsExactlySchema
    ✓ null → type null
    ✓ boolean → const boolean
    ✓ number → enum with number and string form
    ✓ numeric string → enum with number and string form (1 ms)
    ✓ non-numeric string → const string
  buildIsContainedBySchema
    ✓ single string is normalized to array
    with an array of values
      ✓ array branch: items enum + minItems 1
      ✓ object branch: propertyNames enum + minProperties 1
      ✓ string branch: enum
  buildIsNotContainedBySchema
    ✓ array branch: minItems + not(items enum) (1 ms)
    ✓ object branch: minProperties + not(propertyNames enum)
    ✓ string branch: not enum
    ✓ single string is normalized to array
  getOperatorSchema
    ✓ CONTAINS delegates to buildContainsSchema
    ✓ CONTAINS with array value
    ✓ CONTAINS throws when value is missing (11 ms)
    ✓ HAS_INPUT delegates to buildHasInputSchema
    ✓ IS_NOT_EMPTY produces the same schema as HAS_INPUT (1 ms)
    ✓ DOES_NOT_HAVE_INPUT delegates to buildDoesNotHaveInputSchema
    ✓ IS_EMPTY returns root-level anyOf with 5 branches
    ✓ INPUT_IS_EXACTLY delegates to buildInputIsExactlySchema
    ✓ INPUT_IS_EXACTLY throws when value is undefined
    ✓ IS_EXACTLY delegates to buildIsExactlySchema (1 ms)
    ✓ IS_EXACTLY throws when value is missing
    ✓ IS_CONTAINED_BY delegates to buildIsContainedBySchema
    ✓ IS_CONTAINED_BY throws when value is missing
    ✓ IS_NOT_CONTAINED_BY delegates to buildIsNotContainedBySchema
    ✓ IS_NOT_CONTAINED_BY throws when value is missing
  buildConditionSchema
    ✓ IS_EMPTY returns root-level anyOf directly (no properties wrapper)
    ✓ non-IS_EMPTY operators are wrapped in properties/required
    ✓ IS_NOT_EMPTY is wrapped in properties/required
    ✓ IS_EXACTLY is wrapped in properties/required (1 ms)
  buildSchemaBasedCondition
    ✓ throws when conditions array is empty
    single condition (non-IS_EMPTY)
      ✓ uses field scope
      ✓ schema is the operator schema (not wrapped)
      ✓ IS_EXACTLY single field scope
    single IS_EMPTY condition
      ✓ uses root scope
      ✓ schema is the IS_EMPTY anyOf (1 ms)
    multiple conditions
      ✓ uses root scope with allOf
      ✓ each non-IS_EMPTY condition is wrapped in properties/required
      ✓ IS_EMPTY in multi-condition contributes root-level anyOf directly
      ✓ IS_CONTAINED_BY multi-value condition
  createSectionRule
    ✓ creates a SHOW rule
    ✓ condition scope matches field for single non-IS_EMPTY
    ✓ condition scope is root for IS_EMPTY
  validateConditions
    ✓ passes with valid CONTAINS condition
    ✓ passes with IS_EMPTY (no value required)
    ✓ passes with IS_NOT_EMPTY
    ✓ throws for unknown operator (1 ms)
    ✓ throws for unknown field
    ✓ throws when CONTAINS value is missing
    ✓ throws when CONTAINS value is null
    ✓ throws when IS_EXACTLY value is missing (1 ms)
    ✓ throws when IS_CONTAINED_BY value is missing
    ✓ throws when IS_NOT_CONTAINED_BY value is missing
    ✓ throws when INPUT_IS_EXACTLY value is undefined
    ✓ INPUT_IS_EXACTLY allows null value
    ✓ validates multiple conditions together (1 ms)
    ✓ reports the first invalid condition in a list

Test Suites: 1 passed, 1 total
Tests:       92 passed, 92 total
Snapshots:   0 total
Time:        0.284 s, estimated 1 s

@doneill doneill self-assigned this Mar 6, 2026
@doneill doneill merged commit 3560ac8 into develop Mar 10, 2026
2 checks passed
@doneill doneill deleted the 34-updated-conditional branch March 10, 2026 16:37
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

B - Ready To Merge PR is ready to be merged

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant