@json-eval-rs/react-native 0.0.54 → 0.0.56

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/src/index.tsx CHANGED
@@ -18,6 +18,16 @@ const JsonEvalRs = NativeModules.JsonEvalRs
18
18
  }
19
19
  );
20
20
 
21
+ /**
22
+ * Item for get schema value array results
23
+ */
24
+ export interface SchemaValueItem {
25
+ /** Dotted path (e.g., "field1.field2") */
26
+ path: string;
27
+ /** Value at this path */
28
+ value: any;
29
+ }
30
+
21
31
  /**
22
32
  * Return format for path-based methods
23
33
  */
@@ -27,7 +37,7 @@ export enum ReturnFormat {
27
37
  /** Flat object with dotted keys */
28
38
  Flat = 1,
29
39
  /** Array of values in the order of requested paths */
30
- Array = 2
40
+ Array = 2,
31
41
  }
32
42
 
33
43
  /**
@@ -260,22 +270,22 @@ export interface GetSchemaByPathsSubformOptions {
260
270
 
261
271
  /**
262
272
  * High-performance JSON Logic evaluator with schema validation for React Native
263
- *
273
+ *
264
274
  * ## Zero-Copy Architecture
265
- *
275
+ *
266
276
  * This binding is optimized for minimal memory copies:
267
277
  * - **Rust FFI Layer**: Returns raw pointers (zero-copy)
268
278
  * - **C++ Bridge**: Uses direct pointer access with single-copy string construction
269
279
  * - **Native Platform**: Minimizes intermediate conversions
270
280
  * - **JS Bridge**: React Native's architecture requires serialization (unavoidable)
271
- *
281
+ *
272
282
  * While true zero-copy across JS/Native boundary is not possible due to React Native's
273
283
  * architecture, we minimize copies within the native layer to maximize performance.
274
- *
284
+ *
275
285
  * @example
276
286
  * ```typescript
277
287
  * import { JSONEval } from '@json-eval-rs/react-native';
278
- *
288
+ *
279
289
  * const schema = {
280
290
  * type: 'object',
281
291
  * properties: {
@@ -292,18 +302,18 @@ export interface GetSchemaByPathsSubformOptions {
292
302
  * }
293
303
  * }
294
304
  * };
295
- *
305
+ *
296
306
  * const eval = new JSONEval({ schema });
297
- *
307
+ *
298
308
  * const data = { user: { name: 'John' } };
299
309
  * const result = await eval.evaluate({ data });
300
310
  * console.log(result);
301
- *
311
+ *
302
312
  * const validation = await eval.validate({ data });
303
313
  * if (validation.hasError) {
304
314
  * console.error('Validation errors:', validation.errors);
305
315
  * }
306
- *
316
+ *
307
317
  * await eval.dispose();
308
318
  * ```
309
319
  */
@@ -324,13 +334,54 @@ export class JSONEval {
324
334
  context?: string | object | null,
325
335
  data?: string | object | null
326
336
  ): JSONEval {
327
- const contextStr = context ? (typeof context === 'string' ? context : JSON.stringify(context)) : null;
328
- const dataStr = data ? (typeof data === 'string' ? data : JSON.stringify(data)) : null;
329
-
337
+ const contextStr = context
338
+ ? typeof context === 'string'
339
+ ? context
340
+ : JSON.stringify(context)
341
+ : null;
342
+ const dataStr = data
343
+ ? typeof data === 'string'
344
+ ? data
345
+ : JSON.stringify(data)
346
+ : null;
347
+
330
348
  const handle = JsonEvalRs.createFromCache(cacheKey, contextStr, dataStr);
331
349
  return new JSONEval({ schema: {}, _handle: handle });
332
350
  }
333
351
 
352
+ /**
353
+ * Evaluates logic expression without creating an instance
354
+ * @param logicStr - JSON Logic expression as string or object
355
+ * @param data - Optional data as string or object
356
+ * @param context - Optional context as string or object
357
+ * @returns Promise resolving to evaluation result
358
+ */
359
+ static async evaluateLogic(
360
+ logicStr: string | object,
361
+ data?: string | object | null,
362
+ context?: string | object | null
363
+ ): Promise<any> {
364
+ const logic =
365
+ typeof logicStr === 'string' ? logicStr : JSON.stringify(logicStr);
366
+ const dataStr = data
367
+ ? typeof data === 'string'
368
+ ? data
369
+ : JSON.stringify(data)
370
+ : null;
371
+ const contextStr = context
372
+ ? typeof context === 'string'
373
+ ? context
374
+ : JSON.stringify(context)
375
+ : null;
376
+
377
+ const resultStr = await JsonEvalRs.evaluateLogic(
378
+ logic,
379
+ dataStr,
380
+ contextStr
381
+ );
382
+ return JSON.parse(resultStr);
383
+ }
384
+
334
385
  /**
335
386
  * Creates a new JSON evaluator instance
336
387
  * @param options - Configuration options with schema, context, and data
@@ -342,17 +393,27 @@ export class JSONEval {
342
393
  this.handle = options._handle;
343
394
  return;
344
395
  }
345
-
396
+
346
397
  const { schema, context, data } = options;
347
-
398
+
348
399
  try {
349
- const schemaStr = typeof schema === 'string' ? schema : JSON.stringify(schema);
350
- const contextStr = context ? (typeof context === 'string' ? context : JSON.stringify(context)) : null;
351
- const dataStr = data ? (typeof data === 'string' ? data : JSON.stringify(data)) : null;
352
-
400
+ const schemaStr =
401
+ typeof schema === 'string' ? schema : JSON.stringify(schema);
402
+ const contextStr = context
403
+ ? typeof context === 'string'
404
+ ? context
405
+ : JSON.stringify(context)
406
+ : null;
407
+ const dataStr = data
408
+ ? typeof data === 'string'
409
+ ? data
410
+ : JSON.stringify(data)
411
+ : null;
412
+
353
413
  this.handle = JsonEvalRs.create(schemaStr, contextStr, dataStr);
354
414
  } catch (error) {
355
- const errorMessage = error instanceof Error ? error.message : String(error);
415
+ const errorMessage =
416
+ error instanceof Error ? error.message : String(error);
356
417
  throw new Error(`Failed to create JSONEval instance: ${errorMessage}`);
357
418
  }
358
419
  }
@@ -374,7 +435,7 @@ export class JSONEval {
374
435
 
375
436
  /**
376
437
  * Cancel any running evaluation
377
- * The generic auto-cancellation on new evaluation will still work,
438
+ * The generic auto-cancellation on new evaluation will still work,
378
439
  * but this allows manual cancellation.
379
440
  */
380
441
  async cancel(): Promise<void> {
@@ -390,16 +451,24 @@ export class JSONEval {
390
451
  */
391
452
  async evaluate(options: EvaluateOptions): Promise<any> {
392
453
  this.throwIfDisposed();
393
-
454
+
394
455
  try {
395
456
  const dataStr = this.toJsonString(options.data);
396
- const contextStr = options.context ? this.toJsonString(options.context) : null;
457
+ const contextStr = options.context
458
+ ? this.toJsonString(options.context)
459
+ : null;
397
460
  const pathsJson = options.paths ? JSON.stringify(options.paths) : null;
398
-
399
- const resultStr = await JsonEvalRs.evaluate(this.handle, dataStr, contextStr, pathsJson);
461
+
462
+ const resultStr = await JsonEvalRs.evaluate(
463
+ this.handle,
464
+ dataStr,
465
+ contextStr,
466
+ pathsJson
467
+ );
400
468
  return JSON.parse(resultStr);
401
469
  } catch (error) {
402
- const errorMessage = error instanceof Error ? error.message : String(error);
470
+ const errorMessage =
471
+ error instanceof Error ? error.message : String(error);
403
472
  throw new Error(`Evaluation failed: ${errorMessage}`);
404
473
  }
405
474
  }
@@ -412,15 +481,22 @@ export class JSONEval {
412
481
  */
413
482
  async validate(options: EvaluateOptions): Promise<ValidationResult> {
414
483
  this.throwIfDisposed();
415
-
484
+
416
485
  try {
417
486
  const dataStr = this.toJsonString(options.data);
418
- const contextStr = options.context ? this.toJsonString(options.context) : null;
419
-
420
- const resultStr = await JsonEvalRs.validate(this.handle, dataStr, contextStr);
487
+ const contextStr = options.context
488
+ ? this.toJsonString(options.context)
489
+ : null;
490
+
491
+ const resultStr = await JsonEvalRs.validate(
492
+ this.handle,
493
+ dataStr,
494
+ contextStr
495
+ );
421
496
  return JSON.parse(resultStr);
422
497
  } catch (error) {
423
- const errorMessage = error instanceof Error ? error.message : String(error);
498
+ const errorMessage =
499
+ error instanceof Error ? error.message : String(error);
424
500
  throw new Error(`Validation failed: ${errorMessage}`);
425
501
  }
426
502
  }
@@ -431,15 +507,17 @@ export class JSONEval {
431
507
  * @returns Promise resolving to array of dependent field changes
432
508
  * @throws {Error} If evaluation fails
433
509
  */
434
- async evaluateDependents(options: EvaluateDependentsOptions): Promise<DependentChange[]> {
510
+ async evaluateDependents(
511
+ options: EvaluateDependentsOptions
512
+ ): Promise<DependentChange[]> {
435
513
  this.throwIfDisposed();
436
-
514
+
437
515
  try {
438
516
  const { changedPaths, data, context, reEvaluate = true } = options;
439
517
  const changedPathsJson = JSON.stringify(changedPaths);
440
518
  const dataStr = data ? this.toJsonString(data) : null;
441
519
  const contextStr = context ? this.toJsonString(context) : null;
442
-
520
+
443
521
  const resultStr = await JsonEvalRs.evaluateDependents(
444
522
  this.handle,
445
523
  changedPathsJson,
@@ -449,7 +527,8 @@ export class JSONEval {
449
527
  );
450
528
  return JSON.parse(resultStr);
451
529
  } catch (error) {
452
- const errorMessage = error instanceof Error ? error.message : String(error);
530
+ const errorMessage =
531
+ error instanceof Error ? error.message : String(error);
453
532
  throw new Error(`Dependent evaluation failed: ${errorMessage}`);
454
533
  }
455
534
  }
@@ -462,7 +541,10 @@ export class JSONEval {
462
541
  */
463
542
  async getEvaluatedSchema(skipLayout: boolean = false): Promise<any> {
464
543
  this.throwIfDisposed();
465
- const resultStr = await JsonEvalRs.getEvaluatedSchema(this.handle, skipLayout);
544
+ const resultStr = await JsonEvalRs.getEvaluatedSchema(
545
+ this.handle,
546
+ skipLayout
547
+ );
466
548
  return JSON.parse(resultStr);
467
549
  }
468
550
 
@@ -477,15 +559,44 @@ export class JSONEval {
477
559
  return JSON.parse(resultStr);
478
560
  }
479
561
 
562
+ /**
563
+ * Get all schema values as array of path-value pairs
564
+ * Returns [{path: "", value: ""}, ...]
565
+ * @returns Promise resolving to array of SchemaValueItem objects
566
+ * @throws {Error} If operation fails
567
+ */
568
+ async getSchemaValueArray(): Promise<SchemaValueItem[]> {
569
+ this.throwIfDisposed();
570
+ const resultStr = await JsonEvalRs.getSchemaValueArray(this.handle);
571
+ return JSON.parse(resultStr);
572
+ }
573
+
574
+ /**
575
+ * Get all schema values as object with dotted path keys
576
+ * Returns {path: value, ...}
577
+ * @returns Promise resolving to flat object with dotted paths as keys
578
+ * @throws {Error} If operation fails
579
+ */
580
+ async getSchemaValueObject(): Promise<Record<string, any>> {
581
+ this.throwIfDisposed();
582
+ const resultStr = await JsonEvalRs.getSchemaValueObject(this.handle);
583
+ return JSON.parse(resultStr);
584
+ }
585
+
480
586
  /**
481
587
  * Get the evaluated schema without $params field
482
588
  * @param skipLayout - Whether to skip layout resolution (default: false)
483
589
  * @returns Promise resolving to evaluated schema object
484
590
  * @throws {Error} If operation fails
485
591
  */
486
- async getEvaluatedSchemaWithoutParams(skipLayout: boolean = false): Promise<any> {
592
+ async getEvaluatedSchemaWithoutParams(
593
+ skipLayout: boolean = false
594
+ ): Promise<any> {
487
595
  this.throwIfDisposed();
488
- const resultStr = await JsonEvalRs.getEvaluatedSchemaWithoutParams(this.handle, skipLayout);
596
+ const resultStr = await JsonEvalRs.getEvaluatedSchemaWithoutParams(
597
+ this.handle,
598
+ skipLayout
599
+ );
489
600
  return JSON.parse(resultStr);
490
601
  }
491
602
 
@@ -496,9 +607,16 @@ export class JSONEval {
496
607
  * @returns Promise resolving to the value at the path, or null if not found
497
608
  * @throws {Error} If operation fails
498
609
  */
499
- async getEvaluatedSchemaByPath(path: string, skipLayout: boolean = false): Promise<any | null> {
610
+ async getEvaluatedSchemaByPath(
611
+ path: string,
612
+ skipLayout: boolean = false
613
+ ): Promise<any | null> {
500
614
  this.throwIfDisposed();
501
- const resultStr = await JsonEvalRs.getEvaluatedSchemaByPath(this.handle, path, skipLayout);
615
+ const resultStr = await JsonEvalRs.getEvaluatedSchemaByPath(
616
+ this.handle,
617
+ path,
618
+ skipLayout
619
+ );
502
620
  return resultStr ? JSON.parse(resultStr) : null;
503
621
  }
504
622
 
@@ -511,10 +629,19 @@ export class JSONEval {
511
629
  * @returns Promise resolving to data in the specified format
512
630
  * @throws {Error} If operation fails
513
631
  */
514
- async getEvaluatedSchemaByPaths(paths: string[], skipLayout: boolean = false, format: ReturnFormat = ReturnFormat.Nested): Promise<any> {
632
+ async getEvaluatedSchemaByPaths(
633
+ paths: string[],
634
+ skipLayout: boolean = false,
635
+ format: ReturnFormat = ReturnFormat.Nested
636
+ ): Promise<any> {
515
637
  this.throwIfDisposed();
516
638
  const pathsJson = JSON.stringify(paths);
517
- const resultStr = await JsonEvalRs.getEvaluatedSchemaByPaths(this.handle, pathsJson, skipLayout, format);
639
+ const resultStr = await JsonEvalRs.getEvaluatedSchemaByPaths(
640
+ this.handle,
641
+ pathsJson,
642
+ skipLayout,
643
+ format
644
+ );
518
645
  return JSON.parse(resultStr);
519
646
  }
520
647
 
@@ -538,10 +665,17 @@ export class JSONEval {
538
665
  * @returns Promise resolving to data in the specified format
539
666
  * @throws {Error} If operation fails
540
667
  */
541
- async getSchemaByPaths(paths: string[], format: ReturnFormat = ReturnFormat.Nested): Promise<any> {
668
+ async getSchemaByPaths(
669
+ paths: string[],
670
+ format: ReturnFormat = ReturnFormat.Nested
671
+ ): Promise<any> {
542
672
  this.throwIfDisposed();
543
673
  const pathsJson = JSON.stringify(paths);
544
- const resultStr = await JsonEvalRs.getSchemaByPaths(this.handle, pathsJson, format);
674
+ const resultStr = await JsonEvalRs.getSchemaByPaths(
675
+ this.handle,
676
+ pathsJson,
677
+ format
678
+ );
545
679
  return JSON.parse(resultStr);
546
680
  }
547
681
 
@@ -552,16 +686,31 @@ export class JSONEval {
552
686
  */
553
687
  async reloadSchema(options: JSONEvalOptions): Promise<void> {
554
688
  this.throwIfDisposed();
555
-
689
+
556
690
  try {
557
691
  const { schema, context, data } = options;
558
- const schemaStr = typeof schema === 'string' ? schema : JSON.stringify(schema);
559
- const contextStr = context ? (typeof context === 'string' ? context : JSON.stringify(context)) : null;
560
- const dataStr = data ? (typeof data === 'string' ? data : JSON.stringify(data)) : null;
561
-
562
- await JsonEvalRs.reloadSchema(this.handle, schemaStr, contextStr, dataStr);
692
+ const schemaStr =
693
+ typeof schema === 'string' ? schema : JSON.stringify(schema);
694
+ const contextStr = context
695
+ ? typeof context === 'string'
696
+ ? context
697
+ : JSON.stringify(context)
698
+ : null;
699
+ const dataStr = data
700
+ ? typeof data === 'string'
701
+ ? data
702
+ : JSON.stringify(data)
703
+ : null;
704
+
705
+ await JsonEvalRs.reloadSchema(
706
+ this.handle,
707
+ schemaStr,
708
+ contextStr,
709
+ dataStr
710
+ );
563
711
  } catch (error) {
564
- const errorMessage = error instanceof Error ? error.message : String(error);
712
+ const errorMessage =
713
+ error instanceof Error ? error.message : String(error);
565
714
  throw new Error(`Failed to reload schema: ${errorMessage}`);
566
715
  }
567
716
  }
@@ -579,20 +728,37 @@ export class JSONEval {
579
728
  data?: string | object | null
580
729
  ): Promise<void> {
581
730
  this.throwIfDisposed();
582
-
731
+
583
732
  try {
584
733
  // Convert Uint8Array to number array if needed
585
- const msgpackArray = schemaMsgpack instanceof Uint8Array
586
- ? Array.from(schemaMsgpack)
587
- : schemaMsgpack;
588
-
589
- const contextStr = context ? (typeof context === 'string' ? context : JSON.stringify(context)) : null;
590
- const dataStr = data ? (typeof data === 'string' ? data : JSON.stringify(data)) : null;
591
-
592
- await JsonEvalRs.reloadSchemaMsgpack(this.handle, msgpackArray, contextStr, dataStr);
734
+ const msgpackArray =
735
+ schemaMsgpack instanceof Uint8Array
736
+ ? Array.from(schemaMsgpack)
737
+ : schemaMsgpack;
738
+
739
+ const contextStr = context
740
+ ? typeof context === 'string'
741
+ ? context
742
+ : JSON.stringify(context)
743
+ : null;
744
+ const dataStr = data
745
+ ? typeof data === 'string'
746
+ ? data
747
+ : JSON.stringify(data)
748
+ : null;
749
+
750
+ await JsonEvalRs.reloadSchemaMsgpack(
751
+ this.handle,
752
+ msgpackArray,
753
+ contextStr,
754
+ dataStr
755
+ );
593
756
  } catch (error) {
594
- const errorMessage = error instanceof Error ? error.message : String(error);
595
- throw new Error(`Failed to reload schema from MessagePack: ${errorMessage}`);
757
+ const errorMessage =
758
+ error instanceof Error ? error.message : String(error);
759
+ throw new Error(
760
+ `Failed to reload schema from MessagePack: ${errorMessage}`
761
+ );
596
762
  }
597
763
  }
598
764
 
@@ -609,14 +775,28 @@ export class JSONEval {
609
775
  data?: string | object | null
610
776
  ): Promise<void> {
611
777
  this.throwIfDisposed();
612
-
778
+
613
779
  try {
614
- const contextStr = context ? (typeof context === 'string' ? context : JSON.stringify(context)) : null;
615
- const dataStr = data ? (typeof data === 'string' ? data : JSON.stringify(data)) : null;
616
-
617
- await JsonEvalRs.reloadSchemaFromCache(this.handle, cacheKey, contextStr, dataStr);
780
+ const contextStr = context
781
+ ? typeof context === 'string'
782
+ ? context
783
+ : JSON.stringify(context)
784
+ : null;
785
+ const dataStr = data
786
+ ? typeof data === 'string'
787
+ ? data
788
+ : JSON.stringify(data)
789
+ : null;
790
+
791
+ await JsonEvalRs.reloadSchemaFromCache(
792
+ this.handle,
793
+ cacheKey,
794
+ contextStr,
795
+ dataStr
796
+ );
618
797
  } catch (error) {
619
- const errorMessage = error instanceof Error ? error.message : String(error);
798
+ const errorMessage =
799
+ error instanceof Error ? error.message : String(error);
620
800
  throw new Error(`Failed to reload schema from cache: ${errorMessage}`);
621
801
  }
622
802
  }
@@ -702,15 +882,15 @@ export class JSONEval {
702
882
  * Pass null to reset to UTC
703
883
  * @returns Promise that resolves when timezone is set
704
884
  * @throws {Error} If operation fails
705
- *
885
+ *
706
886
  * @example
707
887
  * ```typescript
708
888
  * // Set to UTC+7 (Jakarta, Bangkok)
709
889
  * await eval.setTimezoneOffset(420);
710
- *
890
+ *
711
891
  * // Set to UTC-5 (New York, EST)
712
892
  * await eval.setTimezoneOffset(-300);
713
- *
893
+ *
714
894
  * // Reset to UTC
715
895
  * await eval.setTimezoneOffset(null);
716
896
  * ```
@@ -728,14 +908,23 @@ export class JSONEval {
728
908
  * @returns Promise resolving to the result of the evaluation
729
909
  * @throws {Error} If compilation or evaluation fails
730
910
  */
731
- async compileAndRunLogic(logicStr: string | object, data?: string | object, context?: string | object): Promise<any> {
911
+ async compileAndRunLogic(
912
+ logicStr: string | object,
913
+ data?: string | object,
914
+ context?: string | object
915
+ ): Promise<any> {
732
916
  this.throwIfDisposed();
733
-
917
+
734
918
  const logic = this.toJsonString(logicStr);
735
919
  const dataStr = data ? this.toJsonString(data) : null;
736
920
  const contextStr = context ? this.toJsonString(context) : null;
737
-
738
- const resultStr = await JsonEvalRs.compileAndRunLogic(this.handle, logic, dataStr, contextStr);
921
+
922
+ const resultStr = await JsonEvalRs.compileAndRunLogic(
923
+ this.handle,
924
+ logic,
925
+ dataStr,
926
+ contextStr
927
+ );
739
928
  return JSON.parse(resultStr);
740
929
  }
741
930
 
@@ -747,7 +936,7 @@ export class JSONEval {
747
936
  */
748
937
  async compileLogic(logicStr: string | object): Promise<number> {
749
938
  this.throwIfDisposed();
750
-
939
+
751
940
  const logic = this.toJsonString(logicStr);
752
941
  return await JsonEvalRs.compileLogic(this.handle, logic);
753
942
  }
@@ -760,13 +949,22 @@ export class JSONEval {
760
949
  * @returns Promise resolving to the result of the evaluation
761
950
  * @throws {Error} If execution fails
762
951
  */
763
- async runLogic(logicId: number, data?: string | object, context?: string | object): Promise<any> {
952
+ async runLogic(
953
+ logicId: number,
954
+ data?: string | object,
955
+ context?: string | object
956
+ ): Promise<any> {
764
957
  this.throwIfDisposed();
765
-
958
+
766
959
  const dataStr = data ? this.toJsonString(data) : null;
767
960
  const contextStr = context ? this.toJsonString(context) : null;
768
-
769
- const resultStr = await JsonEvalRs.runLogic(this.handle, logicId, dataStr, contextStr);
961
+
962
+ const resultStr = await JsonEvalRs.runLogic(
963
+ this.handle,
964
+ logicId,
965
+ dataStr,
966
+ contextStr
967
+ );
770
968
  return JSON.parse(resultStr);
771
969
  }
772
970
 
@@ -776,14 +974,23 @@ export class JSONEval {
776
974
  * @returns Promise resolving to ValidationResult
777
975
  * @throws {Error} If validation operation fails
778
976
  */
779
- async validatePaths(options: ValidatePathsOptions): Promise<ValidationResult> {
977
+ async validatePaths(
978
+ options: ValidatePathsOptions
979
+ ): Promise<ValidationResult> {
780
980
  this.throwIfDisposed();
781
-
981
+
782
982
  const dataStr = this.toJsonString(options.data);
783
- const contextStr = options.context ? this.toJsonString(options.context) : null;
983
+ const contextStr = options.context
984
+ ? this.toJsonString(options.context)
985
+ : null;
784
986
  const paths = options.paths || null;
785
-
786
- const resultStr = await JsonEvalRs.validatePaths(this.handle, dataStr, contextStr, paths);
987
+
988
+ const resultStr = await JsonEvalRs.validatePaths(
989
+ this.handle,
990
+ dataStr,
991
+ contextStr,
992
+ paths
993
+ );
787
994
  return JSON.parse(resultStr);
788
995
  }
789
996
 
@@ -799,11 +1006,19 @@ export class JSONEval {
799
1006
  */
800
1007
  async evaluateSubform(options: EvaluateSubformOptions): Promise<void> {
801
1008
  this.throwIfDisposed();
802
-
1009
+
803
1010
  const dataStr = this.toJsonString(options.data);
804
- const contextStr = options.context ? this.toJsonString(options.context) : null;
805
-
806
- return JsonEvalRs.evaluateSubform(this.handle, options.subformPath, dataStr, contextStr, options.paths);
1011
+ const contextStr = options.context
1012
+ ? this.toJsonString(options.context)
1013
+ : null;
1014
+
1015
+ return JsonEvalRs.evaluateSubform(
1016
+ this.handle,
1017
+ options.subformPath,
1018
+ dataStr,
1019
+ contextStr,
1020
+ options.paths
1021
+ );
807
1022
  }
808
1023
 
809
1024
  /**
@@ -812,13 +1027,22 @@ export class JSONEval {
812
1027
  * @returns Promise resolving to ValidationResult
813
1028
  * @throws {Error} If validation fails
814
1029
  */
815
- async validateSubform(options: ValidateSubformOptions): Promise<ValidationResult> {
1030
+ async validateSubform(
1031
+ options: ValidateSubformOptions
1032
+ ): Promise<ValidationResult> {
816
1033
  this.throwIfDisposed();
817
-
1034
+
818
1035
  const dataStr = this.toJsonString(options.data);
819
- const contextStr = options.context ? this.toJsonString(options.context) : null;
820
-
821
- const resultStr = await JsonEvalRs.validateSubform(this.handle, options.subformPath, dataStr, contextStr);
1036
+ const contextStr = options.context
1037
+ ? this.toJsonString(options.context)
1038
+ : null;
1039
+
1040
+ const resultStr = await JsonEvalRs.validateSubform(
1041
+ this.handle,
1042
+ options.subformPath,
1043
+ dataStr,
1044
+ contextStr
1045
+ );
822
1046
  return JSON.parse(resultStr);
823
1047
  }
824
1048
 
@@ -828,15 +1052,19 @@ export class JSONEval {
828
1052
  * @returns Promise resolving to dependent evaluation results
829
1053
  * @throws {Error} If evaluation fails
830
1054
  */
831
- async evaluateDependentsSubform(options: EvaluateDependentsSubformOptions): Promise<DependentChange[]> {
1055
+ async evaluateDependentsSubform(
1056
+ options: EvaluateDependentsSubformOptions
1057
+ ): Promise<DependentChange[]> {
832
1058
  this.throwIfDisposed();
833
-
1059
+
834
1060
  const dataStr = options.data ? this.toJsonString(options.data) : null;
835
- const contextStr = options.context ? this.toJsonString(options.context) : null;
836
-
1061
+ const contextStr = options.context
1062
+ ? this.toJsonString(options.context)
1063
+ : null;
1064
+
837
1065
  // For now, pass the first path since native bridge expects single path (wraps internally)
838
1066
  const changedPath = options.changedPaths[0] || '';
839
-
1067
+
840
1068
  const resultStr = await JsonEvalRs.evaluateDependentsSubform(
841
1069
  this.handle,
842
1070
  options.subformPath,
@@ -854,10 +1082,16 @@ export class JSONEval {
854
1082
  * @returns Promise that resolves when layout is resolved
855
1083
  * @throws {Error} If layout resolution fails
856
1084
  */
857
- async resolveLayoutSubform(options: ResolveLayoutSubformOptions): Promise<void> {
1085
+ async resolveLayoutSubform(
1086
+ options: ResolveLayoutSubformOptions
1087
+ ): Promise<void> {
858
1088
  this.throwIfDisposed();
859
-
860
- return JsonEvalRs.resolveLayoutSubform(this.handle, options.subformPath, options.evaluate || false);
1089
+
1090
+ return JsonEvalRs.resolveLayoutSubform(
1091
+ this.handle,
1092
+ options.subformPath,
1093
+ options.evaluate || false
1094
+ );
861
1095
  }
862
1096
 
863
1097
  /**
@@ -866,9 +1100,11 @@ export class JSONEval {
866
1100
  * @returns Promise resolving to evaluated schema
867
1101
  * @throws {Error} If operation fails
868
1102
  */
869
- async getEvaluatedSchemaSubform(options: GetEvaluatedSchemaSubformOptions): Promise<any> {
1103
+ async getEvaluatedSchemaSubform(
1104
+ options: GetEvaluatedSchemaSubformOptions
1105
+ ): Promise<any> {
870
1106
  this.throwIfDisposed();
871
-
1107
+
872
1108
  const resultStr = await JsonEvalRs.getEvaluatedSchemaSubform(
873
1109
  this.handle,
874
1110
  options.subformPath,
@@ -883,10 +1119,53 @@ export class JSONEval {
883
1119
  * @returns Promise resolving to schema values
884
1120
  * @throws {Error} If operation fails
885
1121
  */
886
- async getSchemaValueSubform(options: GetSchemaValueSubformOptions): Promise<any> {
1122
+ async getSchemaValueSubform(
1123
+ options: GetSchemaValueSubformOptions
1124
+ ): Promise<any> {
1125
+ this.throwIfDisposed();
1126
+
1127
+ const resultStr = await JsonEvalRs.getSchemaValueSubform(
1128
+ this.handle,
1129
+ options.subformPath
1130
+ );
1131
+ return JSON.parse(resultStr);
1132
+ }
1133
+
1134
+ /**
1135
+ * Get schema values from subform as a flat array of path-value pairs.
1136
+ * Returns an array like `[{path: "field.sub", value: 123}, ...]`.
1137
+ * @param options - Options including subform path
1138
+ * @returns Promise resolving to array of SchemaValueItem objects
1139
+ * @throws {Error} If operation fails
1140
+ */
1141
+ async getSchemaValueArraySubform(
1142
+ options: GetSchemaValueSubformOptions
1143
+ ): Promise<SchemaValueItem[]> {
887
1144
  this.throwIfDisposed();
888
-
889
- const resultStr = await JsonEvalRs.getSchemaValueSubform(this.handle, options.subformPath);
1145
+
1146
+ const resultStr = await JsonEvalRs.getSchemaValueArraySubform(
1147
+ this.handle,
1148
+ options.subformPath
1149
+ );
1150
+ return JSON.parse(resultStr);
1151
+ }
1152
+
1153
+ /**
1154
+ * Get schema values from subform as a flat object with dotted path keys.
1155
+ * Returns an object like `{"field.sub": 123, ...}`.
1156
+ * @param options - Options including subform path
1157
+ * @returns Promise resolving to flat object with dotted paths
1158
+ * @throws {Error} If operation fails
1159
+ */
1160
+ async getSchemaValueObjectSubform(
1161
+ options: GetSchemaValueSubformOptions
1162
+ ): Promise<Record<string, any>> {
1163
+ this.throwIfDisposed();
1164
+
1165
+ const resultStr = await JsonEvalRs.getSchemaValueObjectSubform(
1166
+ this.handle,
1167
+ options.subformPath
1168
+ );
890
1169
  return JSON.parse(resultStr);
891
1170
  }
892
1171
 
@@ -896,9 +1175,11 @@ export class JSONEval {
896
1175
  * @returns Promise resolving to evaluated schema without $params
897
1176
  * @throws {Error} If operation fails
898
1177
  */
899
- async getEvaluatedSchemaWithoutParamsSubform(options: GetEvaluatedSchemaSubformOptions): Promise<any> {
1178
+ async getEvaluatedSchemaWithoutParamsSubform(
1179
+ options: GetEvaluatedSchemaSubformOptions
1180
+ ): Promise<any> {
900
1181
  this.throwIfDisposed();
901
-
1182
+
902
1183
  const resultStr = await JsonEvalRs.getEvaluatedSchemaWithoutParamsSubform(
903
1184
  this.handle,
904
1185
  options.subformPath,
@@ -913,9 +1194,11 @@ export class JSONEval {
913
1194
  * @returns Promise resolving to value at path or null if not found
914
1195
  * @throws {Error} If operation fails
915
1196
  */
916
- async getEvaluatedSchemaByPathSubform(options: GetEvaluatedSchemaByPathSubformOptions): Promise<any | null> {
1197
+ async getEvaluatedSchemaByPathSubform(
1198
+ options: GetEvaluatedSchemaByPathSubformOptions
1199
+ ): Promise<any | null> {
917
1200
  this.throwIfDisposed();
918
-
1201
+
919
1202
  const resultStr = await JsonEvalRs.getEvaluatedSchemaByPathSubform(
920
1203
  this.handle,
921
1204
  options.subformPath,
@@ -932,9 +1215,11 @@ export class JSONEval {
932
1215
  * @returns Promise resolving to data in the specified format
933
1216
  * @throws {Error} If operation fails
934
1217
  */
935
- async getEvaluatedSchemaByPathsSubform(options: GetEvaluatedSchemaByPathsSubformOptions): Promise<any> {
1218
+ async getEvaluatedSchemaByPathsSubform(
1219
+ options: GetEvaluatedSchemaByPathsSubformOptions
1220
+ ): Promise<any> {
936
1221
  this.throwIfDisposed();
937
-
1222
+
938
1223
  const pathsJson = JSON.stringify(options.schemaPaths);
939
1224
  const resultStr = await JsonEvalRs.getEvaluatedSchemaByPathsSubform(
940
1225
  this.handle,
@@ -953,7 +1238,7 @@ export class JSONEval {
953
1238
  */
954
1239
  async getSubformPaths(): Promise<string[]> {
955
1240
  this.throwIfDisposed();
956
-
1241
+
957
1242
  const resultStr = await JsonEvalRs.getSubformPaths(this.handle);
958
1243
  return JSON.parse(resultStr);
959
1244
  }
@@ -964,9 +1249,11 @@ export class JSONEval {
964
1249
  * @returns Promise resolving to value at path or null if not found
965
1250
  * @throws {Error} If operation fails
966
1251
  */
967
- async getSchemaByPathSubform(options: GetSchemaByPathSubformOptions): Promise<any | null> {
1252
+ async getSchemaByPathSubform(
1253
+ options: GetSchemaByPathSubformOptions
1254
+ ): Promise<any | null> {
968
1255
  this.throwIfDisposed();
969
-
1256
+
970
1257
  const resultStr = await JsonEvalRs.getSchemaByPathSubform(
971
1258
  this.handle,
972
1259
  options.subformPath,
@@ -982,9 +1269,11 @@ export class JSONEval {
982
1269
  * @returns Promise resolving to data in the specified format
983
1270
  * @throws {Error} If operation fails
984
1271
  */
985
- async getSchemaByPathsSubform(options: GetSchemaByPathsSubformOptions): Promise<any> {
1272
+ async getSchemaByPathsSubform(
1273
+ options: GetSchemaByPathsSubformOptions
1274
+ ): Promise<any> {
986
1275
  this.throwIfDisposed();
987
-
1276
+
988
1277
  const pathsJson = JSON.stringify(options.schemaPaths);
989
1278
  const resultStr = await JsonEvalRs.getSchemaByPathsSubform(
990
1279
  this.handle,
@@ -1003,7 +1292,7 @@ export class JSONEval {
1003
1292
  */
1004
1293
  async hasSubform(subformPath: string): Promise<boolean> {
1005
1294
  this.throwIfDisposed();
1006
-
1295
+
1007
1296
  return JsonEvalRs.hasSubform(this.handle, subformPath);
1008
1297
  }
1009
1298
 
@@ -1014,7 +1303,7 @@ export class JSONEval {
1014
1303
  */
1015
1304
  async dispose(): Promise<void> {
1016
1305
  if (this.disposed) return;
1017
-
1306
+
1018
1307
  await JsonEvalRs.dispose(this.handle);
1019
1308
  this.disposed = true;
1020
1309
  }
@@ -1032,20 +1321,20 @@ export class JSONEval {
1032
1321
  * Hook for using JSONEval in React components with automatic cleanup
1033
1322
  * @param options - Configuration options
1034
1323
  * @returns JSONEval instance or null if not yet initialized
1035
- *
1324
+ *
1036
1325
  * @example
1037
1326
  * ```typescript
1038
1327
  * import { useJSONEval } from '@json-eval-rs/react-native';
1039
- *
1328
+ *
1040
1329
  * function MyComponent() {
1041
1330
  * const eval = useJSONEval({ schema: mySchema });
1042
- *
1331
+ *
1043
1332
  * const handleValidate = async () => {
1044
1333
  * if (!eval) return;
1045
1334
  * const result = await eval.validate({ data: myData });
1046
1335
  * console.log(result);
1047
1336
  * };
1048
- *
1337
+ *
1049
1338
  * return <Button onPress={handleValidate} title="Validate" />;
1050
1339
  * }
1051
1340
  * ```