@json-eval-rs/react-native 0.0.28
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/README.md +455 -0
- package/android/CMakeLists.txt +78 -0
- package/android/build.gradle +90 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/cpp/json-eval-rn.cpp +875 -0
- package/android/src/main/java/com/jsonevalrs/JsonEvalRsModule.kt +532 -0
- package/android/src/main/java/com/jsonevalrs/JsonEvalRsPackage.kt +16 -0
- package/android/src/main/jniLibs/arm64-v8a/libjson_eval_rs.so +0 -0
- package/android/src/main/jniLibs/armeabi-v7a/libjson_eval_rs.so +0 -0
- package/android/src/main/jniLibs/x86/libjson_eval_rs.so +0 -0
- package/android/src/main/jniLibs/x86_64/libjson_eval_rs.so +0 -0
- package/cpp/json-eval-bridge.cpp +1366 -0
- package/cpp/json-eval-bridge.h +583 -0
- package/ios/JsonEvalRs.h +5 -0
- package/ios/JsonEvalRs.mm +852 -0
- package/ios/JsonEvalRs.xcframework/Info.plist +44 -0
- package/ios/JsonEvalRs.xcframework/ios-arm64/libjson_eval_rs.a +0 -0
- package/ios/JsonEvalRs.xcframework/ios-arm64_x86_64-simulator/libjson_eval_rs.a +0 -0
- package/json-eval-rs.podspec +33 -0
- package/lib/commonjs/index.js +786 -0
- package/lib/commonjs/index.js.map +1 -0
- package/lib/module/index.js +778 -0
- package/lib/module/index.js.map +1 -0
- package/lib/typescript/index.d.ts +565 -0
- package/lib/typescript/index.d.ts.map +1 -0
- package/package.json +140 -0
- package/src/index.tsx +999 -0
|
@@ -0,0 +1,778 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { NativeModules, Platform } from 'react-native';
|
|
3
|
+
const LINKING_ERROR = `The package '@json-eval-rs/react-native' doesn't seem to be linked. Make sure: \n\n` + Platform.select({
|
|
4
|
+
ios: "- You have run 'pod install'\n",
|
|
5
|
+
default: ''
|
|
6
|
+
}) + '- You rebuilt the app after installing the package\n' + '- You are not using Expo managed workflow\n';
|
|
7
|
+
const JsonEvalRs = NativeModules.JsonEvalRs ? NativeModules.JsonEvalRs : new Proxy({}, {
|
|
8
|
+
get() {
|
|
9
|
+
throw new Error(LINKING_ERROR);
|
|
10
|
+
}
|
|
11
|
+
});
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Validation error for a specific field
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Result of validation operation
|
|
19
|
+
*/
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Dependent field change from evaluateDependents
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Options for creating a JSONEval instance
|
|
27
|
+
*/
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Options for evaluation
|
|
31
|
+
*/
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Options for validation with path filtering
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Cache statistics
|
|
39
|
+
*/
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Options for evaluating dependents
|
|
43
|
+
*/
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Options for evaluating a subform
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Options for validating a subform
|
|
51
|
+
*/
|
|
52
|
+
|
|
53
|
+
/**
|
|
54
|
+
* Options for evaluating dependents in a subform
|
|
55
|
+
*/
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Options for resolving layout in a subform
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Options for getting evaluated schema from a subform
|
|
63
|
+
*/
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* Options for getting schema value from a subform
|
|
67
|
+
*/
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Options for getting evaluated schema by path from a subform
|
|
71
|
+
*/
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Options for getting evaluated schema by multiple paths from a subform
|
|
75
|
+
*/
|
|
76
|
+
|
|
77
|
+
/**
|
|
78
|
+
* Options for getting schema by path from a subform
|
|
79
|
+
*/
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Options for getting schema by multiple paths from a subform
|
|
83
|
+
*/
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* High-performance JSON Logic evaluator with schema validation for React Native
|
|
87
|
+
*
|
|
88
|
+
* ## Zero-Copy Architecture
|
|
89
|
+
*
|
|
90
|
+
* This binding is optimized for minimal memory copies:
|
|
91
|
+
* - **Rust FFI Layer**: Returns raw pointers (zero-copy)
|
|
92
|
+
* - **C++ Bridge**: Uses direct pointer access with single-copy string construction
|
|
93
|
+
* - **Native Platform**: Minimizes intermediate conversions
|
|
94
|
+
* - **JS Bridge**: React Native's architecture requires serialization (unavoidable)
|
|
95
|
+
*
|
|
96
|
+
* While true zero-copy across JS/Native boundary is not possible due to React Native's
|
|
97
|
+
* architecture, we minimize copies within the native layer to maximize performance.
|
|
98
|
+
*
|
|
99
|
+
* @example
|
|
100
|
+
* ```typescript
|
|
101
|
+
* import { JSONEval } from '@json-eval-rs/react-native';
|
|
102
|
+
*
|
|
103
|
+
* const schema = {
|
|
104
|
+
* type: 'object',
|
|
105
|
+
* properties: {
|
|
106
|
+
* user: {
|
|
107
|
+
* type: 'object',
|
|
108
|
+
* properties: {
|
|
109
|
+
* name: {
|
|
110
|
+
* type: 'string',
|
|
111
|
+
* rules: {
|
|
112
|
+
* required: { value: true, message: 'Name is required' }
|
|
113
|
+
* }
|
|
114
|
+
* }
|
|
115
|
+
* }
|
|
116
|
+
* }
|
|
117
|
+
* }
|
|
118
|
+
* };
|
|
119
|
+
*
|
|
120
|
+
* const eval = new JSONEval({ schema });
|
|
121
|
+
*
|
|
122
|
+
* const data = { user: { name: 'John' } };
|
|
123
|
+
* const result = await eval.evaluate({ data });
|
|
124
|
+
* console.log(result);
|
|
125
|
+
*
|
|
126
|
+
* const validation = await eval.validate({ data });
|
|
127
|
+
* if (validation.hasError) {
|
|
128
|
+
* console.error('Validation errors:', validation.errors);
|
|
129
|
+
* }
|
|
130
|
+
*
|
|
131
|
+
* await eval.dispose();
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
export class JSONEval {
|
|
135
|
+
disposed = false;
|
|
136
|
+
|
|
137
|
+
/**
|
|
138
|
+
* Creates a new JSON evaluator instance from a cached ParsedSchema
|
|
139
|
+
* @param cacheKey - Cache key to lookup in the global ParsedSchemaCache
|
|
140
|
+
* @param context - Optional context data
|
|
141
|
+
* @param data - Optional initial data
|
|
142
|
+
* @returns New JSONEval instance
|
|
143
|
+
* @throws {Error} If schema not found in cache or creation fails
|
|
144
|
+
*/
|
|
145
|
+
static fromCache(cacheKey, context, data) {
|
|
146
|
+
const contextStr = context ? typeof context === 'string' ? context : JSON.stringify(context) : null;
|
|
147
|
+
const dataStr = data ? typeof data === 'string' ? data : JSON.stringify(data) : null;
|
|
148
|
+
const handle = JsonEvalRs.createFromCache(cacheKey, contextStr, dataStr);
|
|
149
|
+
return new JSONEval({
|
|
150
|
+
schema: {},
|
|
151
|
+
_handle: handle
|
|
152
|
+
});
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* Creates a new JSON evaluator instance
|
|
157
|
+
* @param options - Configuration options with schema, context, and data
|
|
158
|
+
* @throws {Error} If creation fails
|
|
159
|
+
*/
|
|
160
|
+
constructor(options) {
|
|
161
|
+
// If handle is provided (from static factory), use it directly
|
|
162
|
+
if (options._handle) {
|
|
163
|
+
this.handle = options._handle;
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
const {
|
|
167
|
+
schema,
|
|
168
|
+
context,
|
|
169
|
+
data
|
|
170
|
+
} = options;
|
|
171
|
+
try {
|
|
172
|
+
const schemaStr = typeof schema === 'string' ? schema : JSON.stringify(schema);
|
|
173
|
+
const contextStr = context ? typeof context === 'string' ? context : JSON.stringify(context) : null;
|
|
174
|
+
const dataStr = data ? typeof data === 'string' ? data : JSON.stringify(data) : null;
|
|
175
|
+
this.handle = JsonEvalRs.create(schemaStr, contextStr, dataStr);
|
|
176
|
+
} catch (error) {
|
|
177
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
178
|
+
throw new Error(`Failed to create JSONEval instance: ${errorMessage}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
throwIfDisposed() {
|
|
182
|
+
if (this.disposed) {
|
|
183
|
+
throw new Error('JSONEval instance has been disposed');
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Convert value to JSON string
|
|
189
|
+
* Performance note: If you have a pre-serialized JSON string, pass it directly
|
|
190
|
+
* instead of an object to avoid the JSON.stringify overhead
|
|
191
|
+
*/
|
|
192
|
+
toJsonString(value) {
|
|
193
|
+
return typeof value === 'string' ? value : JSON.stringify(value);
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Evaluate schema with provided data
|
|
198
|
+
* @param options - Evaluation options
|
|
199
|
+
* @returns Promise resolving to evaluated schema object
|
|
200
|
+
* @throws {Error} If evaluation fails
|
|
201
|
+
*/
|
|
202
|
+
async evaluate(options) {
|
|
203
|
+
this.throwIfDisposed();
|
|
204
|
+
try {
|
|
205
|
+
const dataStr = this.toJsonString(options.data);
|
|
206
|
+
const contextStr = options.context ? this.toJsonString(options.context) : null;
|
|
207
|
+
const resultStr = await JsonEvalRs.evaluate(this.handle, dataStr, contextStr);
|
|
208
|
+
return JSON.parse(resultStr);
|
|
209
|
+
} catch (error) {
|
|
210
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
211
|
+
throw new Error(`Evaluation failed: ${errorMessage}`);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/**
|
|
216
|
+
* Validate data against schema rules
|
|
217
|
+
* @param options - Validation options
|
|
218
|
+
* @returns Promise resolving to ValidationResult
|
|
219
|
+
* @throws {Error} If validation operation fails
|
|
220
|
+
*/
|
|
221
|
+
async validate(options) {
|
|
222
|
+
this.throwIfDisposed();
|
|
223
|
+
try {
|
|
224
|
+
const dataStr = this.toJsonString(options.data);
|
|
225
|
+
const contextStr = options.context ? this.toJsonString(options.context) : null;
|
|
226
|
+
const resultStr = await JsonEvalRs.validate(this.handle, dataStr, contextStr);
|
|
227
|
+
return JSON.parse(resultStr);
|
|
228
|
+
} catch (error) {
|
|
229
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
230
|
+
throw new Error(`Validation failed: ${errorMessage}`);
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
/**
|
|
235
|
+
* Re-evaluate fields that depend on a changed path
|
|
236
|
+
* @param options - Dependent evaluation options
|
|
237
|
+
* @returns Promise resolving to array of dependent field changes
|
|
238
|
+
* @throws {Error} If evaluation fails
|
|
239
|
+
*/
|
|
240
|
+
async evaluateDependents(options) {
|
|
241
|
+
this.throwIfDisposed();
|
|
242
|
+
try {
|
|
243
|
+
const {
|
|
244
|
+
changedPaths,
|
|
245
|
+
data,
|
|
246
|
+
context,
|
|
247
|
+
reEvaluate = false
|
|
248
|
+
} = options;
|
|
249
|
+
const changedPathsJson = JSON.stringify(changedPaths);
|
|
250
|
+
const dataStr = data ? this.toJsonString(data) : null;
|
|
251
|
+
const contextStr = context ? this.toJsonString(context) : null;
|
|
252
|
+
const resultStr = await JsonEvalRs.evaluateDependents(this.handle, changedPathsJson, dataStr, contextStr, reEvaluate);
|
|
253
|
+
return JSON.parse(resultStr);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
256
|
+
throw new Error(`Dependent evaluation failed: ${errorMessage}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Get the evaluated schema with optional layout resolution
|
|
262
|
+
* @param skipLayout - Whether to skip layout resolution (default: false)
|
|
263
|
+
* @returns Promise resolving to evaluated schema object
|
|
264
|
+
* @throws {Error} If operation fails
|
|
265
|
+
*/
|
|
266
|
+
async getEvaluatedSchema(skipLayout = false) {
|
|
267
|
+
this.throwIfDisposed();
|
|
268
|
+
const resultStr = await JsonEvalRs.getEvaluatedSchema(this.handle, skipLayout);
|
|
269
|
+
return JSON.parse(resultStr);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Get all schema values (evaluations ending with .value)
|
|
274
|
+
* @returns Promise resolving to map of path -> value
|
|
275
|
+
* @throws {Error} If operation fails
|
|
276
|
+
*/
|
|
277
|
+
async getSchemaValue() {
|
|
278
|
+
this.throwIfDisposed();
|
|
279
|
+
const resultStr = await JsonEvalRs.getSchemaValue(this.handle);
|
|
280
|
+
return JSON.parse(resultStr);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Get the evaluated schema without $params field
|
|
285
|
+
* @param skipLayout - Whether to skip layout resolution (default: false)
|
|
286
|
+
* @returns Promise resolving to evaluated schema object
|
|
287
|
+
* @throws {Error} If operation fails
|
|
288
|
+
*/
|
|
289
|
+
async getEvaluatedSchemaWithoutParams(skipLayout = false) {
|
|
290
|
+
this.throwIfDisposed();
|
|
291
|
+
const resultStr = await JsonEvalRs.getEvaluatedSchemaWithoutParams(this.handle, skipLayout);
|
|
292
|
+
return JSON.parse(resultStr);
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
/**
|
|
296
|
+
* Get a value from the evaluated schema using dotted path notation
|
|
297
|
+
* @param path - Dotted path to the value (e.g., "properties.field.value")
|
|
298
|
+
* @param skipLayout - Whether to skip layout resolution
|
|
299
|
+
* @returns Promise resolving to the value at the path, or null if not found
|
|
300
|
+
* @throws {Error} If operation fails
|
|
301
|
+
*/
|
|
302
|
+
async getEvaluatedSchemaByPath(path, skipLayout = false) {
|
|
303
|
+
this.throwIfDisposed();
|
|
304
|
+
const resultStr = await JsonEvalRs.getEvaluatedSchemaByPath(this.handle, path, skipLayout);
|
|
305
|
+
return resultStr ? JSON.parse(resultStr) : null;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Get values from the evaluated schema using multiple dotted path notations
|
|
310
|
+
* Returns a merged object containing all requested paths (skips paths that are not found)
|
|
311
|
+
* @param paths - Array of dotted paths to retrieve
|
|
312
|
+
* @param skipLayout - Whether to skip layout resolution
|
|
313
|
+
* @returns Promise resolving to merged object containing all found paths
|
|
314
|
+
* @throws {Error} If operation fails
|
|
315
|
+
*/
|
|
316
|
+
async getEvaluatedSchemaByPaths(paths, skipLayout = false) {
|
|
317
|
+
this.throwIfDisposed();
|
|
318
|
+
const pathsJson = JSON.stringify(paths);
|
|
319
|
+
const resultStr = await JsonEvalRs.getEvaluatedSchemaByPaths(this.handle, pathsJson, skipLayout);
|
|
320
|
+
return JSON.parse(resultStr);
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
/**
|
|
324
|
+
* Get a value from the schema using dotted path notation
|
|
325
|
+
* @param path - Dotted path to the value (e.g., "properties.field.value")
|
|
326
|
+
* @returns Promise resolving to the value at the path, or null if not found
|
|
327
|
+
* @throws {Error} If operation fails
|
|
328
|
+
*/
|
|
329
|
+
async getSchemaByPath(path) {
|
|
330
|
+
this.throwIfDisposed();
|
|
331
|
+
const resultStr = await JsonEvalRs.getSchemaByPath(this.handle, path);
|
|
332
|
+
return resultStr ? JSON.parse(resultStr) : null;
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
/**
|
|
336
|
+
* Get values from the schema using multiple dotted path notations
|
|
337
|
+
* Returns a merged object containing all requested paths (skips paths that are not found)
|
|
338
|
+
* @param paths - Array of dotted paths to retrieve
|
|
339
|
+
* @returns Promise resolving to merged object containing all found paths
|
|
340
|
+
* @throws {Error} If operation fails
|
|
341
|
+
*/
|
|
342
|
+
async getSchemaByPaths(paths) {
|
|
343
|
+
this.throwIfDisposed();
|
|
344
|
+
const pathsJson = JSON.stringify(paths);
|
|
345
|
+
const resultStr = await JsonEvalRs.getSchemaByPaths(this.handle, pathsJson);
|
|
346
|
+
return JSON.parse(resultStr);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
/**
|
|
350
|
+
* Reload schema with new data
|
|
351
|
+
* @param options - Configuration options with new schema, context, and data
|
|
352
|
+
* @throws {Error} If reload fails
|
|
353
|
+
*/
|
|
354
|
+
async reloadSchema(options) {
|
|
355
|
+
this.throwIfDisposed();
|
|
356
|
+
try {
|
|
357
|
+
const {
|
|
358
|
+
schema,
|
|
359
|
+
context,
|
|
360
|
+
data
|
|
361
|
+
} = options;
|
|
362
|
+
const schemaStr = typeof schema === 'string' ? schema : JSON.stringify(schema);
|
|
363
|
+
const contextStr = context ? typeof context === 'string' ? context : JSON.stringify(context) : null;
|
|
364
|
+
const dataStr = data ? typeof data === 'string' ? data : JSON.stringify(data) : null;
|
|
365
|
+
await JsonEvalRs.reloadSchema(this.handle, schemaStr, contextStr, dataStr);
|
|
366
|
+
} catch (error) {
|
|
367
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
368
|
+
throw new Error(`Failed to reload schema: ${errorMessage}`);
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* Reload schema from MessagePack bytes
|
|
374
|
+
* @param schemaMsgpack - MessagePack-encoded schema bytes (Uint8Array or number array)
|
|
375
|
+
* @param context - Optional context data
|
|
376
|
+
* @param data - Optional initial data
|
|
377
|
+
* @throws {Error} If reload fails
|
|
378
|
+
*/
|
|
379
|
+
async reloadSchemaMsgpack(schemaMsgpack, context, data) {
|
|
380
|
+
this.throwIfDisposed();
|
|
381
|
+
try {
|
|
382
|
+
// Convert Uint8Array to number array if needed
|
|
383
|
+
const msgpackArray = schemaMsgpack instanceof Uint8Array ? Array.from(schemaMsgpack) : schemaMsgpack;
|
|
384
|
+
const contextStr = context ? typeof context === 'string' ? context : JSON.stringify(context) : null;
|
|
385
|
+
const dataStr = data ? typeof data === 'string' ? data : JSON.stringify(data) : null;
|
|
386
|
+
await JsonEvalRs.reloadSchemaMsgpack(this.handle, msgpackArray, contextStr, dataStr);
|
|
387
|
+
} catch (error) {
|
|
388
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
389
|
+
throw new Error(`Failed to reload schema from MessagePack: ${errorMessage}`);
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
/**
|
|
394
|
+
* Reload schema from ParsedSchemaCache using a cache key
|
|
395
|
+
* @param cacheKey - Cache key to lookup in the global ParsedSchemaCache
|
|
396
|
+
* @param context - Optional context data
|
|
397
|
+
* @param data - Optional initial data
|
|
398
|
+
* @throws {Error} If reload fails or schema not found in cache
|
|
399
|
+
*/
|
|
400
|
+
async reloadSchemaFromCache(cacheKey, context, data) {
|
|
401
|
+
this.throwIfDisposed();
|
|
402
|
+
try {
|
|
403
|
+
const contextStr = context ? typeof context === 'string' ? context : JSON.stringify(context) : null;
|
|
404
|
+
const dataStr = data ? typeof data === 'string' ? data : JSON.stringify(data) : null;
|
|
405
|
+
await JsonEvalRs.reloadSchemaFromCache(this.handle, cacheKey, contextStr, dataStr);
|
|
406
|
+
} catch (error) {
|
|
407
|
+
const errorMessage = error instanceof Error ? error.message : String(error);
|
|
408
|
+
throw new Error(`Failed to reload schema from cache: ${errorMessage}`);
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
/**
|
|
413
|
+
* Get cache statistics
|
|
414
|
+
* @returns Promise resolving to cache statistics
|
|
415
|
+
* @throws {Error} If operation fails
|
|
416
|
+
*/
|
|
417
|
+
async cacheStats() {
|
|
418
|
+
this.throwIfDisposed();
|
|
419
|
+
const resultStr = await JsonEvalRs.cacheStats(this.handle);
|
|
420
|
+
return JSON.parse(resultStr);
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
/**
|
|
424
|
+
* Clear the evaluation cache
|
|
425
|
+
* @returns Promise that resolves when cache is cleared
|
|
426
|
+
* @throws {Error} If operation fails
|
|
427
|
+
*/
|
|
428
|
+
async clearCache() {
|
|
429
|
+
this.throwIfDisposed();
|
|
430
|
+
await JsonEvalRs.clearCache(this.handle);
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
/**
|
|
434
|
+
* Get the number of cached entries
|
|
435
|
+
* @returns Promise resolving to number of cached entries
|
|
436
|
+
* @throws {Error} If operation fails
|
|
437
|
+
*/
|
|
438
|
+
async cacheLen() {
|
|
439
|
+
this.throwIfDisposed();
|
|
440
|
+
return await JsonEvalRs.cacheLen(this.handle);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
/**
|
|
444
|
+
* Enable evaluation caching
|
|
445
|
+
* Useful for reusing JSONEval instances with different data
|
|
446
|
+
* @returns Promise that resolves when cache is enabled
|
|
447
|
+
* @throws {Error} If operation fails
|
|
448
|
+
*/
|
|
449
|
+
async enableCache() {
|
|
450
|
+
this.throwIfDisposed();
|
|
451
|
+
await JsonEvalRs.enableCache(this.handle);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
/**
|
|
455
|
+
* Disable evaluation caching
|
|
456
|
+
* Useful for web API usage where each request creates a new JSONEval instance
|
|
457
|
+
* Improves performance by skipping cache operations that have no benefit for single-use instances
|
|
458
|
+
* @returns Promise that resolves when cache is disabled
|
|
459
|
+
* @throws {Error} If operation fails
|
|
460
|
+
*/
|
|
461
|
+
async disableCache() {
|
|
462
|
+
this.throwIfDisposed();
|
|
463
|
+
await JsonEvalRs.disableCache(this.handle);
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
/**
|
|
467
|
+
* Check if evaluation caching is enabled
|
|
468
|
+
* @returns Boolean indicating if caching is enabled
|
|
469
|
+
* @throws {Error} If operation fails
|
|
470
|
+
*/
|
|
471
|
+
isCacheEnabled() {
|
|
472
|
+
this.throwIfDisposed();
|
|
473
|
+
return JsonEvalRs.isCacheEnabled(this.handle);
|
|
474
|
+
}
|
|
475
|
+
|
|
476
|
+
/**
|
|
477
|
+
* Resolve layout with optional evaluation
|
|
478
|
+
* @param evaluate - If true, runs evaluation before resolving layout (default: false)
|
|
479
|
+
* @returns Promise that resolves when layout resolution is complete
|
|
480
|
+
* @throws {Error} If operation fails
|
|
481
|
+
*/
|
|
482
|
+
async resolveLayout(evaluate = false) {
|
|
483
|
+
this.throwIfDisposed();
|
|
484
|
+
await JsonEvalRs.resolveLayout(this.handle, evaluate);
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
/**
|
|
488
|
+
* Compile and run JSON logic from a JSON logic string
|
|
489
|
+
* @param logicStr - JSON logic expression as a string or object
|
|
490
|
+
* @param data - Optional JSON data string or object (null to use existing data)
|
|
491
|
+
* @param context - Optional context data string or object (null to use existing context)
|
|
492
|
+
* @returns Promise resolving to the result of the evaluation
|
|
493
|
+
* @throws {Error} If compilation or evaluation fails
|
|
494
|
+
*/
|
|
495
|
+
async compileAndRunLogic(logicStr, data, context) {
|
|
496
|
+
this.throwIfDisposed();
|
|
497
|
+
const logic = this.toJsonString(logicStr);
|
|
498
|
+
const dataStr = data ? this.toJsonString(data) : null;
|
|
499
|
+
const contextStr = context ? this.toJsonString(context) : null;
|
|
500
|
+
const resultStr = await JsonEvalRs.compileAndRunLogic(this.handle, logic, dataStr, contextStr);
|
|
501
|
+
return JSON.parse(resultStr);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
/**
|
|
505
|
+
* Compile JSON logic and return a global ID
|
|
506
|
+
* @param logicStr - JSON logic expression as a string or object
|
|
507
|
+
* @returns Promise resolving to the compiled logic ID
|
|
508
|
+
* @throws {Error} If compilation fails
|
|
509
|
+
*/
|
|
510
|
+
async compileLogic(logicStr) {
|
|
511
|
+
this.throwIfDisposed();
|
|
512
|
+
const logic = this.toJsonString(logicStr);
|
|
513
|
+
return await JsonEvalRs.compileLogic(this.handle, logic);
|
|
514
|
+
}
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Run pre-compiled logic by ID
|
|
518
|
+
* @param logicId - Compiled logic ID from compileLogic
|
|
519
|
+
* @param data - Optional JSON data string or object (null to use existing data)
|
|
520
|
+
* @param context - Optional context data string or object (null to use existing context)
|
|
521
|
+
* @returns Promise resolving to the result of the evaluation
|
|
522
|
+
* @throws {Error} If execution fails
|
|
523
|
+
*/
|
|
524
|
+
async runLogic(logicId, data, context) {
|
|
525
|
+
this.throwIfDisposed();
|
|
526
|
+
const dataStr = data ? this.toJsonString(data) : null;
|
|
527
|
+
const contextStr = context ? this.toJsonString(context) : null;
|
|
528
|
+
const resultStr = await JsonEvalRs.runLogic(this.handle, logicId, dataStr, contextStr);
|
|
529
|
+
return JSON.parse(resultStr);
|
|
530
|
+
}
|
|
531
|
+
|
|
532
|
+
/**
|
|
533
|
+
* Validate data against schema rules with optional path filtering
|
|
534
|
+
* @param options - Validation options with optional path filtering
|
|
535
|
+
* @returns Promise resolving to ValidationResult
|
|
536
|
+
* @throws {Error} If validation operation fails
|
|
537
|
+
*/
|
|
538
|
+
async validatePaths(options) {
|
|
539
|
+
this.throwIfDisposed();
|
|
540
|
+
const dataStr = this.toJsonString(options.data);
|
|
541
|
+
const contextStr = options.context ? this.toJsonString(options.context) : null;
|
|
542
|
+
const paths = options.paths || null;
|
|
543
|
+
const resultStr = await JsonEvalRs.validatePaths(this.handle, dataStr, contextStr, paths);
|
|
544
|
+
return JSON.parse(resultStr);
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
// ============================================================================
|
|
548
|
+
// Subform Methods
|
|
549
|
+
// ============================================================================
|
|
550
|
+
|
|
551
|
+
/**
|
|
552
|
+
* Evaluate a subform with data
|
|
553
|
+
* @param options - Evaluation options including subform path and data
|
|
554
|
+
* @returns Promise that resolves when evaluation is complete
|
|
555
|
+
* @throws {Error} If evaluation fails
|
|
556
|
+
*/
|
|
557
|
+
async evaluateSubform(options) {
|
|
558
|
+
this.throwIfDisposed();
|
|
559
|
+
const dataStr = this.toJsonString(options.data);
|
|
560
|
+
const contextStr = options.context ? this.toJsonString(options.context) : null;
|
|
561
|
+
return JsonEvalRs.evaluateSubform(this.handle, options.subformPath, dataStr, contextStr);
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
/**
|
|
565
|
+
* Validate subform data against its schema rules
|
|
566
|
+
* @param options - Validation options including subform path and data
|
|
567
|
+
* @returns Promise resolving to ValidationResult
|
|
568
|
+
* @throws {Error} If validation fails
|
|
569
|
+
*/
|
|
570
|
+
async validateSubform(options) {
|
|
571
|
+
this.throwIfDisposed();
|
|
572
|
+
const dataStr = this.toJsonString(options.data);
|
|
573
|
+
const contextStr = options.context ? this.toJsonString(options.context) : null;
|
|
574
|
+
const resultStr = await JsonEvalRs.validateSubform(this.handle, options.subformPath, dataStr, contextStr);
|
|
575
|
+
return JSON.parse(resultStr);
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
/**
|
|
579
|
+
* Evaluate dependents in a subform when fields change
|
|
580
|
+
* @param options - Options including subform path, changed paths array, and optional data
|
|
581
|
+
* @returns Promise resolving to dependent evaluation results
|
|
582
|
+
* @throws {Error} If evaluation fails
|
|
583
|
+
*/
|
|
584
|
+
async evaluateDependentsSubform(options) {
|
|
585
|
+
this.throwIfDisposed();
|
|
586
|
+
const dataStr = options.data ? this.toJsonString(options.data) : null;
|
|
587
|
+
const contextStr = options.context ? this.toJsonString(options.context) : null;
|
|
588
|
+
|
|
589
|
+
// For now, pass the first path since native bridge expects single path (wraps internally)
|
|
590
|
+
const changedPath = options.changedPaths[0] || '';
|
|
591
|
+
const resultStr = await JsonEvalRs.evaluateDependentsSubform(this.handle, options.subformPath, changedPath, dataStr, contextStr);
|
|
592
|
+
return JSON.parse(resultStr);
|
|
593
|
+
}
|
|
594
|
+
|
|
595
|
+
/**
|
|
596
|
+
* Resolve layout for subform
|
|
597
|
+
* @param options - Options including subform path and evaluate flag
|
|
598
|
+
* @returns Promise that resolves when layout is resolved
|
|
599
|
+
* @throws {Error} If layout resolution fails
|
|
600
|
+
*/
|
|
601
|
+
async resolveLayoutSubform(options) {
|
|
602
|
+
this.throwIfDisposed();
|
|
603
|
+
return JsonEvalRs.resolveLayoutSubform(this.handle, options.subformPath, options.evaluate || false);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
/**
|
|
607
|
+
* Get evaluated schema from subform
|
|
608
|
+
* @param options - Options including subform path and resolveLayout flag
|
|
609
|
+
* @returns Promise resolving to evaluated schema
|
|
610
|
+
* @throws {Error} If operation fails
|
|
611
|
+
*/
|
|
612
|
+
async getEvaluatedSchemaSubform(options) {
|
|
613
|
+
this.throwIfDisposed();
|
|
614
|
+
const resultStr = await JsonEvalRs.getEvaluatedSchemaSubform(this.handle, options.subformPath, options.resolveLayout || false);
|
|
615
|
+
return JSON.parse(resultStr);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
/**
|
|
619
|
+
* Get schema value from subform (all .value fields)
|
|
620
|
+
* @param options - Options including subform path
|
|
621
|
+
* @returns Promise resolving to schema values
|
|
622
|
+
* @throws {Error} If operation fails
|
|
623
|
+
*/
|
|
624
|
+
async getSchemaValueSubform(options) {
|
|
625
|
+
this.throwIfDisposed();
|
|
626
|
+
const resultStr = await JsonEvalRs.getSchemaValueSubform(this.handle, options.subformPath);
|
|
627
|
+
return JSON.parse(resultStr);
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
/**
|
|
631
|
+
* Get evaluated schema without $params from subform
|
|
632
|
+
* @param options - Options including subform path and resolveLayout flag
|
|
633
|
+
* @returns Promise resolving to evaluated schema without $params
|
|
634
|
+
* @throws {Error} If operation fails
|
|
635
|
+
*/
|
|
636
|
+
async getEvaluatedSchemaWithoutParamsSubform(options) {
|
|
637
|
+
this.throwIfDisposed();
|
|
638
|
+
const resultStr = await JsonEvalRs.getEvaluatedSchemaWithoutParamsSubform(this.handle, options.subformPath, options.resolveLayout || false);
|
|
639
|
+
return JSON.parse(resultStr);
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Get evaluated schema by specific path from subform
|
|
644
|
+
* @param options - Options including subform path, schema path, and skipLayout flag
|
|
645
|
+
* @returns Promise resolving to value at path or null if not found
|
|
646
|
+
* @throws {Error} If operation fails
|
|
647
|
+
*/
|
|
648
|
+
async getEvaluatedSchemaByPathSubform(options) {
|
|
649
|
+
this.throwIfDisposed();
|
|
650
|
+
const resultStr = await JsonEvalRs.getEvaluatedSchemaByPathSubform(this.handle, options.subformPath, options.schemaPath, options.skipLayout || false);
|
|
651
|
+
return resultStr ? JSON.parse(resultStr) : null;
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
/**
|
|
655
|
+
* Get evaluated schema by multiple paths from subform
|
|
656
|
+
* Returns a merged object containing all requested paths (skips paths that are not found)
|
|
657
|
+
* @param options - Options including subform path, array of schema paths, and skipLayout flag
|
|
658
|
+
* @returns Promise resolving to merged object containing all found paths
|
|
659
|
+
* @throws {Error} If operation fails
|
|
660
|
+
*/
|
|
661
|
+
async getEvaluatedSchemaByPathsSubform(options) {
|
|
662
|
+
this.throwIfDisposed();
|
|
663
|
+
const pathsJson = JSON.stringify(options.schemaPaths);
|
|
664
|
+
const resultStr = await JsonEvalRs.getEvaluatedSchemaByPathsSubform(this.handle, options.subformPath, pathsJson, options.skipLayout || false);
|
|
665
|
+
return JSON.parse(resultStr);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/**
|
|
669
|
+
* Get list of available subform paths
|
|
670
|
+
* @returns Promise resolving to array of subform paths
|
|
671
|
+
* @throws {Error} If operation fails
|
|
672
|
+
*/
|
|
673
|
+
async getSubformPaths() {
|
|
674
|
+
this.throwIfDisposed();
|
|
675
|
+
const resultStr = await JsonEvalRs.getSubformPaths(this.handle);
|
|
676
|
+
return JSON.parse(resultStr);
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
/**
|
|
680
|
+
* Get schema value by specific path from subform
|
|
681
|
+
* @param options - Options including subform path and schema path
|
|
682
|
+
* @returns Promise resolving to value at path or null if not found
|
|
683
|
+
* @throws {Error} If operation fails
|
|
684
|
+
*/
|
|
685
|
+
async getSchemaByPathSubform(options) {
|
|
686
|
+
this.throwIfDisposed();
|
|
687
|
+
const resultStr = await JsonEvalRs.getSchemaByPathSubform(this.handle, options.subformPath, options.schemaPath);
|
|
688
|
+
return resultStr ? JSON.parse(resultStr) : null;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
/**
|
|
692
|
+
* Get schema values by multiple paths from subform
|
|
693
|
+
* Returns a merged object containing all requested paths (skips paths that are not found)
|
|
694
|
+
* @param options - Options including subform path and array of schema paths
|
|
695
|
+
* @returns Promise resolving to merged object containing all found paths
|
|
696
|
+
* @throws {Error} If operation fails
|
|
697
|
+
*/
|
|
698
|
+
async getSchemaByPathsSubform(options) {
|
|
699
|
+
this.throwIfDisposed();
|
|
700
|
+
const pathsJson = JSON.stringify(options.schemaPaths);
|
|
701
|
+
const resultStr = await JsonEvalRs.getSchemaByPathsSubform(this.handle, options.subformPath, pathsJson);
|
|
702
|
+
return JSON.parse(resultStr);
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
/**
|
|
706
|
+
* Check if a subform exists at the given path
|
|
707
|
+
* @param subformPath - Path to check
|
|
708
|
+
* @returns Promise resolving to true if subform exists, false otherwise
|
|
709
|
+
* @throws {Error} If operation fails
|
|
710
|
+
*/
|
|
711
|
+
async hasSubform(subformPath) {
|
|
712
|
+
this.throwIfDisposed();
|
|
713
|
+
return JsonEvalRs.hasSubform(this.handle, subformPath);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
/**
|
|
717
|
+
* Dispose of the native resources
|
|
718
|
+
* Must be called when done using the instance
|
|
719
|
+
* @returns Promise that resolves when disposal is complete
|
|
720
|
+
*/
|
|
721
|
+
async dispose() {
|
|
722
|
+
if (this.disposed) return;
|
|
723
|
+
await JsonEvalRs.dispose(this.handle);
|
|
724
|
+
this.disposed = true;
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/**
|
|
728
|
+
* Get the library version
|
|
729
|
+
* @returns Promise resolving to version string
|
|
730
|
+
*/
|
|
731
|
+
static async version() {
|
|
732
|
+
return JsonEvalRs.version();
|
|
733
|
+
}
|
|
734
|
+
}
|
|
735
|
+
|
|
736
|
+
/**
|
|
737
|
+
* Hook for using JSONEval in React components with automatic cleanup
|
|
738
|
+
* @param options - Configuration options
|
|
739
|
+
* @returns JSONEval instance or null if not yet initialized
|
|
740
|
+
*
|
|
741
|
+
* @example
|
|
742
|
+
* ```typescript
|
|
743
|
+
* import { useJSONEval } from '@json-eval-rs/react-native';
|
|
744
|
+
*
|
|
745
|
+
* function MyComponent() {
|
|
746
|
+
* const eval = useJSONEval({ schema: mySchema });
|
|
747
|
+
*
|
|
748
|
+
* const handleValidate = async () => {
|
|
749
|
+
* if (!eval) return;
|
|
750
|
+
* const result = await eval.validate({ data: myData });
|
|
751
|
+
* console.log(result);
|
|
752
|
+
* };
|
|
753
|
+
*
|
|
754
|
+
* return <Button onPress={handleValidate} title="Validate" />;
|
|
755
|
+
* }
|
|
756
|
+
* ```
|
|
757
|
+
*/
|
|
758
|
+
export function useJSONEval(options) {
|
|
759
|
+
const [evalInstance, setEvalInstance] = React.useState(null);
|
|
760
|
+
React.useEffect(() => {
|
|
761
|
+
const instance = new JSONEval(options);
|
|
762
|
+
setEvalInstance(instance);
|
|
763
|
+
return () => {
|
|
764
|
+
instance.dispose().catch(console.error);
|
|
765
|
+
};
|
|
766
|
+
// eslint-disable-next-line react-hooks/exhaustive-deps
|
|
767
|
+
}, []);
|
|
768
|
+
return evalInstance;
|
|
769
|
+
}
|
|
770
|
+
|
|
771
|
+
// Default export
|
|
772
|
+
export default JSONEval;
|
|
773
|
+
|
|
774
|
+
// For backwards compatibility
|
|
775
|
+
export const multiply = (a, b) => {
|
|
776
|
+
return JsonEvalRs.multiply(a, b);
|
|
777
|
+
};
|
|
778
|
+
//# sourceMappingURL=index.js.map
|