@json-layout/core 1.15.4 → 1.15.6

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@json-layout/core",
3
- "version": "1.15.4",
3
+ "version": "1.15.6",
4
4
  "description": "Compilation and state management utilities for JSON Layout.",
5
5
  "type": "module",
6
6
  "exports": {
@@ -309,6 +309,15 @@ export function makeSkeletonNode (
309
309
  type,
310
310
  nullable
311
311
  )
312
+ if (!isSwitchStruct(normalizationResult.layout)) {
313
+ let defaultData
314
+ if ('default' in schema && (options.useDefault === 'data' || options.useDefault === true || required)) defaultData = schema.default
315
+ else defaultData = nullable ? null : {}
316
+ if (normalizationResult.layout.defaultData === undefined) normalizationResult.layout.defaultData = defaultData
317
+ if (normalizationResult.layout.defaultData !== undefined && !normalizationResult.layout.getDefaultData) normalizationResult.layout.getDefaultData = { type: 'js-eval', expr: 'layout.defaultData', pure: true, dataAlias: 'value' }
318
+ if (normalizationResult.layout.getDefaultData) pushExpression(expressions, normalizationResult.layout.getDefaultData)
319
+ }
320
+
312
321
  normalizedLayouts[oneOfPointer] = normalizationResult.layout
313
322
  if (normalizationResult.errors.length) {
314
323
  validationErrors[oneOfPointer.replace('_jl#', '/')] = normalizationResult.errors
@@ -316,6 +325,10 @@ export function makeSkeletonNode (
316
325
  }
317
326
  /** @type {string[]} */
318
327
  const childrenTrees = []
328
+ /** @type {string[]} */
329
+ let propertyKeys = []
330
+ /** @type {string[]} */
331
+ let roPropertyKeys = []
319
332
  for (let i = 0; i < schema.oneOf.length; i++) {
320
333
  if (!schema.oneOf[i].type) schema.oneOf[i].type = type
321
334
  const childTreePointer = `${oneOfPointer}/${i}`
@@ -340,6 +353,12 @@ export function makeSkeletonNode (
340
353
  )
341
354
  }
342
355
  childrenTrees.push(childTreePointer)
356
+ // @ts-ignore
357
+ if (skeletonTrees[childTreePointer] !== 'recursing') {
358
+ const rootSkeletonNode = skeletonNodes[skeletonTrees[childTreePointer].root]
359
+ propertyKeys = propertyKeys.concat(rootSkeletonNode.propertyKeys)
360
+ roPropertyKeys = roPropertyKeys.concat(rootSkeletonNode.roPropertyKeys)
361
+ }
343
362
  }
344
363
  if (!skeletonNodes[oneOfPointer]) {
345
364
  skeletonNodes[oneOfPointer] = {
@@ -349,10 +368,12 @@ export function makeSkeletonNode (
349
368
  childrenTrees,
350
369
  discriminator,
351
370
  pure: !childrenTrees.some(childTree => !skeletonNodes[skeletonTrees[childTree]?.root]?.pure),
352
- propertyKeys: [],
353
- roPropertyKeys: []
371
+ propertyKeys,
372
+ roPropertyKeys
354
373
  }
355
374
  }
375
+ node.propertyKeys = node.propertyKeys.concat(skeletonNodes[oneOfPointer].propertyKeys)
376
+ node.roPropertyKeys = node.roPropertyKeys.concat(skeletonNodes[oneOfPointer].roPropertyKeys)
356
377
  node.children = node.children ?? []
357
378
  node.children.push(oneOfPointer)
358
379
  }
@@ -446,6 +467,8 @@ export function makeSkeletonNode (
446
467
  )
447
468
  }
448
469
  node.children = node.children ?? []
470
+ node.propertyKeys = node.propertyKeys.concat(skeletonNodes[childPointer].propertyKeys)
471
+ node.roPropertyKeys = node.roPropertyKeys.concat(skeletonNodes[childPointer].roPropertyKeys)
449
472
  node.children.push(childPointer)
450
473
  }
451
474
  if (schema.else) {
@@ -473,6 +496,8 @@ export function makeSkeletonNode (
473
496
  )
474
497
  }
475
498
  node.children = node.children ?? []
499
+ node.propertyKeys = node.propertyKeys.concat(skeletonNodes[childPointer].propertyKeys)
500
+ node.roPropertyKeys = node.roPropertyKeys.concat(skeletonNodes[childPointer].roPropertyKeys)
476
501
  node.children.push(childPointer)
477
502
  }
478
503
  }
@@ -434,7 +434,9 @@ export class StatefulLayout {
434
434
  const parentNode = this._lastCreateStateTreeContext.nodes.find(p => p.fullKey === node.parentFullKey)
435
435
  if (!parentNode) throw new Error(`parent with key "${node.parentFullKey}" not found`)
436
436
  const newParentValue = producePatchedData(
437
- parentNode.data ?? (typeof node.key === 'number' ? [] : {}),
437
+ // WARN: this manner of creating empty object or array based on the type of the child key does not seem very safe
438
+ // can we find a better way to discriminate ? maybe store an extra info on the the skeleton, like "emptyData" ?
439
+ parentNode.data ?? ((typeof node.key === 'number' && parentNode.key !== '$oneOf') ? [] : {}),
438
440
  node,
439
441
  (data === null || data === undefined) ? (node.skeleton.nullable ? null : undefined) : data
440
442
  )
@@ -91,14 +91,15 @@ const produceStateNodeDataChildrenArray = produce((draft, children) => {
91
91
  const produceStateNodeDataArray = produce((draft, parentDataPath, additionalPropertiesErrors, propertyKeys, removePropertyKeys) => {
92
92
  for (let i = 0; i < draft.length; i++) {
93
93
  if (!(draft[i] instanceof File)) {
94
- draft[i] = produceStateNodeData(draft[i], parentDataPath + '/' + i, undefined, additionalPropertiesErrors, propertyKeys, removePropertyKeys)
94
+ draft[i] = cleanNodeData(draft[i], parentDataPath + '/' + i, additionalPropertiesErrors, propertyKeys, removePropertyKeys)
95
95
  }
96
96
  }
97
97
  })
98
98
 
99
- /** @type {(draft: Record<string, unknown>, parentDataPath: string, children?: import('../index.js').StateNode[], additionalPropertiesErrors?: import('ajv').ErrorObject[], propertyKeys?: string[], removePropertyKeys?: string[]) => Record<string, unknown>} */
100
- const produceStateNodeData = produce((draft, parentDataPath, children, additionalPropertiesErrors, propertyKeys, removePropertyKeys) => {
101
- if (propertyKeys && (propertyKeys.length || children?.length)) {
99
+ /** @type {(draft: Record<string, unknown>, parentDataPath: string, additionalPropertiesErrors?: import('ajv').ErrorObject[], propertyKeys?: string[], removePropertyKeys?: string[]) => Record<string, unknown>} */
100
+ const cleanNodeData = produce((draft, parentDataPath, additionalPropertiesErrors, propertyKeys, removePropertyKeys) => {
101
+ // if (propertyKeys && (propertyKeys.length || children?.length)) {
102
+ if (propertyKeys) {
102
103
  for (const key of Object.keys(draft)) {
103
104
  if (!propertyKeys.includes(key)) delete draft[key]
104
105
  }
@@ -109,26 +110,6 @@ const produceStateNodeData = produce((draft, parentDataPath, children, additiona
109
110
  }
110
111
  }
111
112
 
112
- if (children) {
113
- for (const child of children) {
114
- if (parentDataPath === child.dataPath) {
115
- if (child.data === undefined || child.data === null) continue
116
- if (children.length > 1) {
117
- for (const key of Object.keys(child.data)) {
118
- if (children.some(c => c.key === key)) continue
119
- if (!child.skeleton.propertyKeys.includes(key) && children.some(c => c.key !== child.key && c.skeleton.propertyKeys.includes(key))) continue
120
- draft[key] = /** @type {any} */(child.data)[key]
121
- }
122
- } else {
123
- Object.assign(draft, child.data)
124
- }
125
- } else {
126
- if (child.data === undefined) delete draft[child.key]
127
- else draft[child.key] = child.data
128
- }
129
- }
130
- }
131
-
132
113
  if (additionalPropertiesErrors?.length) {
133
114
  for (const error of additionalPropertiesErrors) {
134
115
  if (error.instancePath !== parentDataPath) continue
@@ -140,6 +121,34 @@ const produceStateNodeData = produce((draft, parentDataPath, children, additiona
140
121
  }
141
122
  }
142
123
  }
124
+
125
+ for (const key of Object.keys(draft)) {
126
+ if (draft[key] === undefined) delete draft[key]
127
+ }
128
+ })
129
+
130
+ /** @type {(draft: Record<string, unknown>, parentDataPath: string, hydratedChild: import('../index.js').StateNode, childrenSkeletons: import('../index.js').SkeletonNode[] | undefined) => Record<string, unknown>} */
131
+ const produceHydratedStateNodeData = produce((draft, parentDataPath, hydratedChild, childrenSkeletons) => {
132
+ if (hydratedChild.dataPath === parentDataPath) {
133
+ if (hydratedChild.data === undefined || hydratedChild.data === null) return
134
+ if (childrenSkeletons && childrenSkeletons.length > 1) {
135
+ for (const key of Object.keys(hydratedChild.data)) {
136
+ if (!hydratedChild.skeleton.propertyKeys.includes(key)) continue
137
+ if (!hydratedChild.skeleton.propertyKeys.includes(key) && childrenSkeletons.some(s => s !== hydratedChild.skeleton && s.propertyKeys.includes(key))) continue
138
+ draft[key] = /** @type {any} */(hydratedChild.data)[key]
139
+ }
140
+ } else {
141
+ Object.assign(draft, hydratedChild.data)
142
+ }
143
+ for (const key of hydratedChild.skeleton.propertyKeys) {
144
+ if (/** @type {any} */(hydratedChild.data)[key] === undefined) {
145
+ delete draft[key]
146
+ }
147
+ }
148
+ } else {
149
+ if (hydratedChild.data === undefined) delete draft[hydratedChild.key]
150
+ else draft[hydratedChild.key] = hydratedChild.data
151
+ }
143
152
  })
144
153
 
145
154
  /** @type {(draft: Record<string, unknown>, parentData: Record<string, unknown>, propertyKeys: string[], patterns: string[]) => Record<string, unknown>} */
@@ -427,12 +436,31 @@ export function createStateNode (
427
436
  context.autofocusTarget = fullKey
428
437
  }
429
438
 
439
+ let nodeData = data
440
+
441
+ if (nodeData === null && !layout.nullable) nodeData = undefined
442
+ const shouldUseDefaultData = layout.getDefaultData && useDefaultData(nodeData, layout, options) && context.currentInput !== fullKey
443
+ if (layout.getConstData) {
444
+ if (!context.rehydrate) {
445
+ nodeData = evalExpression(compiledLayout.expressions, layout.getConstData, nodeData, options, display, layout, compiledLayout.validates, context.rootData, parentContext)
446
+ }
447
+ } else {
448
+ if (shouldUseDefaultData && layout.getDefaultData && !context.rehydrate) {
449
+ const defaultData = evalExpression(compiledLayout.expressions, layout.getDefaultData, nodeData, options, display, layout, compiledLayout.validates, context.rootData, parentContext)
450
+ if (nodeData === undefined || !isDataEmpty(defaultData)) {
451
+ nodeData = defaultData
452
+ }
453
+ }
454
+ }
455
+
430
456
  /** @type {import('./types.js').StateNode[] | undefined} */
431
457
  let children
432
458
  if (isCompositeLayout(layout, compiledLayout.components)) {
433
459
  // TODO: make this type casting safe using prior validation
434
- const objectData = /** @type {Record<string, unknown>} */(data ?? {})
460
+ const objectData = /** @type {Record<string, unknown>} */(nodeData ?? {})
435
461
  const childrenOptions = produceCompositeChildrenOptions(options, layout)
462
+ let actualPropertyKeys = skeleton.propertyKeys
463
+ const removePropertyKeys = options.readOnlyPropertiesMode === 'remove' ? skeleton.roPropertyKeys : []
436
464
  children = []
437
465
  let focusChild = context.autofocusTarget === fullKey
438
466
  for (let i = 0; i < layout.children.length; i++) {
@@ -446,13 +474,25 @@ export function createStateNode (
446
474
  if (childSkeletonKey !== undefined) childSkeleton = compiledLayout.skeletonNodes[childSkeletonKey]
447
475
  if (childSkeleton.condition) {
448
476
  if (!evalExpression(compiledLayout.expressions, childSkeleton.condition, objectData, parentOptions, display, layout, compiledLayout.validates, context.rootData, parentContext)) {
477
+ if (childLayout.key === '$then' || childLayout.key === '$else') {
478
+ const reverseChildSkeletonKey = skeleton.children?.find(c => compiledLayout.skeletonNodes[c].key === (childLayout.key === '$then' ? '$else' : '$then'))
479
+ const reverseChildSkeleton = reverseChildSkeletonKey !== undefined && compiledLayout.skeletonNodes[reverseChildSkeletonKey]
480
+ if (reverseChildSkeleton) {
481
+ for (const key of childSkeleton.propertyKeys) {
482
+ if (!reverseChildSkeleton.propertyKeys.includes(key)) {
483
+ removePropertyKeys.push(key)
484
+ }
485
+ }
486
+ }
487
+ }
449
488
  continue
450
489
  }
451
490
  }
452
491
  const isSameDataPath = typeof childLayout.key === 'string' && childLayout.key.startsWith('$')
453
492
  const childFullKey = `${fullKey}/${childLayout.key}`
454
493
  if (focusChild) context.autofocusTarget = childFullKey
455
- let childData = isSameDataPath ? objectData : objectData[childLayout.key]
494
+ const ogChildData = isSameDataPath ? objectData : objectData[childLayout.key]
495
+ let childData = ogChildData
456
496
  if (childLayout.key === '$patternProperties') {
457
497
  const childNormalizedLayout = /** @type {import('@json-layout/vocabulary').List} */(compiledLayout.normalizedLayouts[childSkeleton.pointer])
458
498
  childData = producePatternPropertiesData(
@@ -461,6 +501,7 @@ export function createStateNode (
461
501
  skeleton.propertyKeys,
462
502
  childNormalizedLayout.indexed ?? []
463
503
  )
504
+ actualPropertyKeys = actualPropertyKeys.concat(Object.keys(/** @type {any} */(childData)))
464
505
  }
465
506
  const child = createStateNode(
466
507
  context,
@@ -480,8 +521,29 @@ export function createStateNode (
480
521
  reusedNode?.children?.find(c => c.fullKey === childFullKey)
481
522
  )
482
523
  if (child.autofocus || child.autofocusChild !== undefined) focusChild = false
524
+ // the child data was hydrated
525
+ if (child.data !== ogChildData) {
526
+ // WARN: this manner of creating empty object or array based on the type of the child key does not seem very safe
527
+ // can we find a better way to discriminate ? maybe store an extra info on the the skeleton, like "emptyData" ?
528
+ nodeData = produceHydratedStateNodeData(
529
+ nodeData ?? ((typeof child.key === 'number' && key !== '$oneOf') ? [] : {}),
530
+ dataPath,
531
+ child,
532
+ skeleton.children?.map(childSkeletonKey => compiledLayout.skeletonNodes[childSkeletonKey])
533
+ )
534
+ }
535
+
483
536
  children.push(child)
484
537
  }
538
+
539
+ const removeAdditional = [true, 'unknown'].includes(options.removeAdditional) || children?.some(c => c.key === '$patternProperties')
540
+ nodeData = cleanNodeData(
541
+ /** @type {Record<string, unknown>} */(nodeData ?? {}),
542
+ dataPath,
543
+ context.additionalPropertiesErrors,
544
+ removeAdditional ? actualPropertyKeys : undefined,
545
+ removePropertyKeys
546
+ )
485
547
  }
486
548
 
487
549
  if (skeleton.nullable && context.errors) {
@@ -543,31 +605,35 @@ export function createStateNode (
543
605
  const activeChildKey = `${fullKey}/${activeChildTreeIndex}`
544
606
  if (context.autofocusTarget === fullKey) context.autofocusTarget = activeChildKey
545
607
 
546
- children = [
547
- createStateNode(
548
- context,
549
- options,
550
- compiledLayout,
551
- activeChildTreeIndex,
552
- activeChildKey,
553
- fullKey,
554
- dataPath,
555
- dataPath,
556
- activeChildNode,
557
- null,
558
- display,
559
- data,
560
- { parent: parentContext, data },
561
- validationState,
562
- reusedNode?.children?.[0]
563
- )
564
- ]
608
+ const child = createStateNode(
609
+ context,
610
+ options,
611
+ compiledLayout,
612
+ activeChildTreeIndex,
613
+ activeChildKey,
614
+ fullKey,
615
+ dataPath,
616
+ dataPath,
617
+ activeChildNode,
618
+ null,
619
+ display,
620
+ nodeData,
621
+ { parent: parentContext, data: nodeData },
622
+ validationState,
623
+ reusedNode?.children?.[0]
624
+ )
625
+ // the oneOf was hydrated
626
+ if (child.data !== nodeData) {
627
+ // nodeData = produceHydratedStateNodeData(nodeData, dataPath, child, skeleton.children?.map(childSkeletonKey => compiledLayout.skeletonNodes[childSkeletonKey]))
628
+ nodeData = child.data
629
+ }
630
+ children = [child]
565
631
  }
566
632
  }
567
633
 
568
634
  if (isListLayout(layout)) {
569
635
  if (layout.indexed) {
570
- const objectData = /** @type {Record<string, unknown>} */(data ?? [])
636
+ const objectData = /** @type {Record<string, unknown>} */(nodeData ?? [])
571
637
  const listItemOptions = layout.listEditMode === 'inline' ? options : produceReadonlyArrayItemOptions(options)
572
638
  children = []
573
639
  let focusChild = context.autofocusTarget === fullKey
@@ -590,6 +656,7 @@ export function createStateNode (
590
656
  if (valueChildSkeleton) {
591
657
  const childFullKey = `${fullKey}/${childKey}`
592
658
  if (focusChild) context.autofocusTarget = childFullKey
659
+ const valueChildData = objectData[childKey]
593
660
  const valueChild = createStateNode(
594
661
  context,
595
662
  (layout.listEditMode === 'inline-single' && context.activatedItems[fullKey] === i) ? options : listItemOptions,
@@ -602,17 +669,28 @@ export function createStateNode (
602
669
  valueChildSkeleton,
603
670
  null,
604
671
  display,
605
- objectData[childKey],
672
+ valueChildData,
606
673
  { parent: parentContext, data: objectData },
607
674
  validationState,
608
675
  reusedNode?.children?.find(c => c.key === childKey)
609
676
  )
610
677
  if (valueChild.autofocus || valueChild.autofocusChild !== undefined) focusChild = false
611
678
  children.push(valueChild)
679
+
680
+ if (valueChild.data !== valueChildData) {
681
+ // WARN: this manner of creating empty object or array based on the type of the child key does not seem very safe
682
+ // can we find a better way to discriminate ? maybe store an extra info on the the skeleton, like "emptyData" ?
683
+ nodeData = produceHydratedStateNodeData(
684
+ nodeData ?? {},
685
+ dataPath,
686
+ valueChild,
687
+ skeleton.children?.map(childSkeletonKey => compiledLayout.skeletonNodes[childSkeletonKey])
688
+ )
689
+ }
612
690
  }
613
691
  }
614
692
  } else {
615
- const arrayData = /** @type {unknown[]} */(data ?? [])
693
+ const arrayData = /** @type {unknown[]} */(nodeData ?? [])
616
694
  const childSkeleton = /** @type {import('../index.js').SkeletonNode} */(skeleton?.childrenTrees?.[0] && compiledLayout.skeletonNodes[compiledLayout.skeletonTrees[skeleton?.childrenTrees?.[0]]?.root])
617
695
  const listItemOptions = layout.listEditMode === 'inline' ? options : produceReadonlyArrayItemOptions(options)
618
696
  children = []
@@ -691,80 +769,62 @@ export function createStateNode (
691
769
  }
692
770
  }
693
771
 
694
- let nodeData = data
695
- if (nodeData === null && !layout.nullable) nodeData = undefined
696
-
697
- const validated = validationState.validatedForm ||
698
- validationState.validatedChildren.includes(fullKey) ||
699
- (validationState.initialized === false && options.initialValidation === 'always') ||
700
- (validationState.initialized === false && options.initialValidation === 'withData' && !isDataEmpty(nodeData))
701
-
702
- if (typeof children?.[0]?.key === 'number' && layout.comp !== 'one-of-select' && !layout.indexed) {
703
- // case of an array of children nodes
704
- nodeData = produceStateNodeDataChildrenArray(
772
+ if (!layout.getConstData) {
773
+ if (typeof children?.[0]?.key === 'number' && layout.comp !== 'one-of-select' && !layout.indexed) {
774
+ // case of an array of children nodes
775
+ nodeData = produceStateNodeDataChildrenArray(
705
776
  /** @type {unknown[]} */(nodeData ?? []),
706
- children
707
- )
708
- } else if (Array.isArray(nodeData)) {
709
- // case of an array without children nodes, so a select of objects for example
710
- const itemsSkeletonTree = skeleton.childrenTrees?.[0] && compiledLayout.skeletonTrees[skeleton.childrenTrees?.[0]]
711
- const itemsSkeletonNode = (itemsSkeletonTree && compiledLayout.skeletonNodes[itemsSkeletonTree.root]) || null
712
- nodeData = produceStateNodeDataArray(
713
- /** @type {Record<string, unknown>[]} */(nodeData ?? []),
714
- dataPath,
715
- context.additionalPropertiesErrors,
716
- [true, 'unknown'].includes(options.removeAdditional) ? itemsSkeletonNode?.propertyKeys : undefined,
717
- options.readOnlyPropertiesMode === 'remove' ? itemsSkeletonNode?.roPropertyKeys : undefined
718
- )
719
- } else if ((typeof nodeData === 'object' || (nodeData === undefined && children?.length)) && !(nodeData instanceof File)) {
720
- // case of an object base on children nodes or not
721
- const removeAdditional = [true, 'unknown'].includes(options.removeAdditional) || children?.some(c => c.key === '$patternProperties')
722
- nodeData = produceStateNodeData(
777
+ children
778
+ )
779
+ } else if (Array.isArray(nodeData) && !children) {
780
+ // case of an array without children nodes, so a select of objects for example
781
+ const itemsSkeletonTree = skeleton.childrenTrees?.[0] && compiledLayout.skeletonTrees[skeleton.childrenTrees?.[0]]
782
+ const itemsSkeletonNode = (itemsSkeletonTree && compiledLayout.skeletonNodes[itemsSkeletonTree.root]) || null
783
+ nodeData = produceStateNodeDataArray(
784
+ /** @type {Record<string, unknown>[]} */(nodeData ?? []),
785
+ dataPath,
786
+ context.additionalPropertiesErrors,
787
+ itemsSkeletonNode?.propertyKeys.length ? itemsSkeletonNode?.propertyKeys : undefined,
788
+ options.readOnlyPropertiesMode === 'remove' ? itemsSkeletonNode?.roPropertyKeys : undefined
789
+ )
790
+ } else if (typeof nodeData === 'object' && !(nodeData instanceof File) && !children) {
791
+ // case of an object outside of a composite component, probably a select
792
+ nodeData = cleanNodeData(
723
793
  /** @type {Record<string, unknown>} */(nodeData ?? {}),
724
- dataPath,
725
- children,
726
- context.additionalPropertiesErrors,
727
- removeAdditional ? skeleton.propertyKeys : undefined,
728
- options.readOnlyPropertiesMode === 'remove' ? skeleton.roPropertyKeys : undefined
729
- )
730
- }
731
-
732
- // the producer is not perfect, sometimes data is considered mutated but it is actually the same
733
- // we double check here to avoid unnecessary re-renders
734
- if (nodeData !== data) {
735
- if (Array.isArray(data) && Array.isArray(nodeData)) nodeData = shallowProduceArray(data, nodeData)
736
- // @ts-ignore
737
- else if (typeof data === 'object' && typeof nodeData === 'object') nodeData = shallowProduceObject(data, nodeData)
738
- }
794
+ dataPath,
795
+ context.additionalPropertiesErrors,
796
+ skeleton?.propertyKeys.length ? skeleton?.propertyKeys : undefined,
797
+ options.readOnlyPropertiesMode === 'remove' ? skeleton?.roPropertyKeys : undefined
798
+ )
799
+ }
739
800
 
740
- if (layout.getConstData) {
741
- if (!context.rehydrate) {
742
- nodeData = evalExpression(compiledLayout.expressions, layout.getConstData, nodeData, options, display, layout, compiledLayout.validates, context.rootData, parentContext)
801
+ // the producer is not perfect, sometimes data is considered mutated but it is actually the same
802
+ // we double check here to avoid unnecessary re-renders
803
+ if (nodeData !== data) {
804
+ if (Array.isArray(data) && Array.isArray(nodeData)) nodeData = shallowProduceArray(data, nodeData)
805
+ // @ts-ignore
806
+ else if (typeof data === 'object' && typeof nodeData === 'object') nodeData = shallowProduceObject(data, nodeData)
743
807
  }
744
- } else {
745
- if (layout.getDefaultData && useDefaultData(nodeData, layout, options) && context.currentInput !== fullKey) {
746
- if (!context.rehydrate) {
747
- const defaultData = evalExpression(compiledLayout.expressions, layout.getDefaultData, nodeData, options, display, layout, compiledLayout.validates, context.rootData, parentContext)
748
- if (nodeData === undefined || !isDataEmpty(defaultData)) {
749
- nodeData = defaultData
750
- }
751
- }
752
- } else {
753
- if (isDataEmpty(nodeData)) {
754
- if (layout.nullable) {
755
- // if a property is nullable empty values are converted to null
756
- // except for undefined if we need to distinguish between empty and missing data
757
- if (options.defaultOn !== 'missing' || nodeData !== undefined) {
758
- nodeData = null
759
- }
760
- } else if (options.defaultOn !== 'missing') {
761
- // remove empty data, except if we need to distinguish between empty and missing data
762
- nodeData = undefined
808
+
809
+ if (!(shouldUseDefaultData) && isDataEmpty(nodeData)) {
810
+ if (layout.nullable) {
811
+ // if a property is nullable empty values are converted to null
812
+ // except for undefined if we need to distinguish between empty and missing data
813
+ if (options.defaultOn !== 'missing' || nodeData !== undefined) {
814
+ nodeData = null
763
815
  }
816
+ } else if (options.defaultOn !== 'missing') {
817
+ // remove empty data, except if we need to distinguish between empty and missing data
818
+ nodeData = undefined
764
819
  }
765
820
  }
766
821
  }
767
822
 
823
+ const validated = validationState.validatedForm ||
824
+ validationState.validatedChildren.includes(fullKey) ||
825
+ (validationState.initialized === false && options.initialValidation === 'always') ||
826
+ (validationState.initialized === false && options.initialValidation === 'withData' && !isDataEmpty(nodeData))
827
+
768
828
  let props
769
829
  if (layout.getProps) {
770
830
  props = evalExpression(compiledLayout.expressions, layout.getProps, nodeData, options, display, layout, compiledLayout.validates, context.rootData, parentContext)
@@ -827,6 +887,7 @@ export function createStateNode (
827
887
  } else if (layout.comp === 'list' && itemsCacheKey) {
828
888
  logGetItems(fullKey, 'list component with unchanged getItems cache key, no fetch will be triggered', itemsCacheKey)
829
889
  }
890
+
830
891
  const node = produceStateNode(
831
892
  reusedNode ?? /** @type {import('./types.js').StateNode} */({}),
832
893
  key,
@@ -1 +1 @@
1
- {"version":3,"file":"skeleton-node.d.ts","sourceRoot":"","sources":["../../src/compile/skeleton-node.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;GAkBG;AACH,4CAlBW,GAAG,kBACH,MAAM,WACN,OAAO,YAAY,EAAE,cAAc,cACnC,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,iBACxD,MAAM,CAAC,MAAM,EAAE,OAAO,YAAY,EAAE,YAAY,CAAC,iBACjD,MAAM,CAAC,MAAM,EAAE,OAAO,YAAY,EAAE,YAAY,CAAC,oBACjD,MAAM,EAAE,oBACR,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,qBACxB,MAAM,CAAC,MAAM,EAAE,OAAO,yBAAyB,EAAE,gBAAgB,CAAC,eAClE,OAAO,yBAAyB,EAAE,UAAU,EAAE,OAC9C,MAAM,GAAG,MAAM,WACf,MAAM,YACN,OAAO,cACP,MAAM,cACN,OAAO,cACP,MAAM,GACJ,OAAO,YAAY,EAAE,YAAY,CAuhB7C"}
1
+ {"version":3,"file":"skeleton-node.d.ts","sourceRoot":"","sources":["../../src/compile/skeleton-node.js"],"names":[],"mappings":"AAMA;;;;;;;;;;;;;;;;;;GAkBG;AACH,4CAlBW,GAAG,kBACH,MAAM,WACN,OAAO,YAAY,EAAE,cAAc,cACnC,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,CAAC,iBACxD,MAAM,CAAC,MAAM,EAAE,OAAO,YAAY,EAAE,YAAY,CAAC,iBACjD,MAAM,CAAC,MAAM,EAAE,OAAO,YAAY,EAAE,YAAY,CAAC,oBACjD,MAAM,EAAE,oBACR,MAAM,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC,qBACxB,MAAM,CAAC,MAAM,EAAE,OAAO,yBAAyB,EAAE,gBAAgB,CAAC,eAClE,OAAO,yBAAyB,EAAE,UAAU,EAAE,OAC9C,MAAM,GAAG,MAAM,WACf,MAAM,YACN,OAAO,cACP,MAAM,cACN,OAAO,cACP,MAAM,GACJ,OAAO,YAAY,EAAE,YAAY,CAgjB7C"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/state/index.js"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/state/index.js"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"state-node.d.ts","sourceRoot":"","sources":["../../src/state/state-node.js"],"names":[],"mappings":"AA0QA;;;;;;;;;;;GAWG;AACH,4CAXW,OAAO,aAAa,EAAE,kBAAkB,EAAE,cAC1C,OAAO,yBAAyB,EAAE,UAAU,QAC5C,GAAG,WACH,OAAO,YAAY,EAAE,gBAAgB,WACrC,OAAO,oBAAoB,EAAE,OAAO,UACpC,OAAO,yBAAyB,EAAE,cAAc,aAChD,MAAM,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE,gBAAgB,CAAC,YAC9C,OAAO,iBACP,OAAO,qBAAqB,EAAE,uBAAuB,GAAG,IAAI,GAC1D,GAAG,CAsBf;AAiCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,yCAjBW,OAAO,YAAY,EAAE,sBAAsB,iBAC3C,OAAO,YAAY,EAAE,gBAAgB,kBACrC,OAAO,aAAa,EAAE,cAAc,OACpC,MAAM,GAAG,MAAM,WACf,MAAM,iBACN,MAAM,GAAG,IAAI,YACb,MAAM,kBACN,MAAM,GAAG,IAAI,YACb,OAAO,aAAa,EAAE,YAAY,mBAClC,OAAO,yBAAyB,EAAE,KAAK,GAAG,IAAI,iBAC9C,OAAO,oBAAoB,EAAE,OAAO,QACpC,GAAG,iBACH,OAAO,qBAAqB,EAAE,uBAAuB,GAAG,IAAI,mBAC5D,OAAO,YAAY,EAAE,eAAe,eACpC,OAAO,YAAY,EAAE,SAAS,GAC5B,OAAO,YAAY,EAAE,SAAS,CAggB1C;AA/zBM,qCALI,OAAO,UACP,OAAO,yBAAyB,EAAE,cAAc,WAChD,OAAO,YAAY,EAAE,gBAAgB,GACnC,OAAO,CAMnB;AA6zBD,uFAAuF;AACvF,iCADW,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,KAAK,GAAG,CAgBjF;AAEF,kKAAkK;AAClK,8BADW,CAAC,YAAY,EAAE,GAAG,EAAE,EAAE,aAAa,EAAE,OAAO,yBAAyB,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,yBAAyB,EAAE,WAAW,KAAK,GAAG,CAY7J"}
1
+ {"version":3,"file":"state-node.d.ts","sourceRoot":"","sources":["../../src/state/state-node.js"],"names":[],"mappings":"AAmRA;;;;;;;;;;;GAWG;AACH,4CAXW,OAAO,aAAa,EAAE,kBAAkB,EAAE,cAC1C,OAAO,yBAAyB,EAAE,UAAU,QAC5C,GAAG,WACH,OAAO,YAAY,EAAE,gBAAgB,WACrC,OAAO,oBAAoB,EAAE,OAAO,UACpC,OAAO,yBAAyB,EAAE,cAAc,aAChD,MAAM,CAAC,MAAM,EAAE,OAAO,KAAK,EAAE,gBAAgB,CAAC,YAC9C,OAAO,iBACP,OAAO,qBAAqB,EAAE,uBAAuB,GAAG,IAAI,GAC1D,GAAG,CAsBf;AAiCD;;;;;;;;;;;;;;;;;;GAkBG;AACH,yCAjBW,OAAO,YAAY,EAAE,sBAAsB,iBAC3C,OAAO,YAAY,EAAE,gBAAgB,kBACrC,OAAO,aAAa,EAAE,cAAc,OACpC,MAAM,GAAG,MAAM,WACf,MAAM,iBACN,MAAM,GAAG,IAAI,YACb,MAAM,kBACN,MAAM,GAAG,IAAI,YACb,OAAO,aAAa,EAAE,YAAY,mBAClC,OAAO,yBAAyB,EAAE,KAAK,GAAG,IAAI,iBAC9C,OAAO,oBAAoB,EAAE,OAAO,QACpC,GAAG,iBACH,OAAO,qBAAqB,EAAE,uBAAuB,GAAG,IAAI,mBAC5D,OAAO,YAAY,EAAE,eAAe,eACpC,OAAO,YAAY,EAAE,SAAS,GAC5B,OAAO,YAAY,EAAE,SAAS,CAojB1C;AA53BM,qCALI,OAAO,UACP,OAAO,yBAAyB,EAAE,cAAc,WAChD,OAAO,YAAY,EAAE,gBAAgB,GACnC,OAAO,CAMnB;AA03BD,uFAAuF;AACvF,iCADW,CAAC,KAAK,EAAE,GAAG,EAAE,IAAI,EAAE,OAAO,YAAY,EAAE,SAAS,EAAE,IAAI,EAAE,OAAO,KAAK,GAAG,CAgBjF;AAEF,kKAAkK;AAClK,8BADW,CAAC,YAAY,EAAE,GAAG,EAAE,EAAE,aAAa,EAAE,OAAO,yBAAyB,EAAE,WAAW,EAAE,QAAQ,EAAE,OAAO,yBAAyB,EAAE,WAAW,KAAK,GAAG,CAY7J"}