@json-eval-rs/webcore 0.0.29
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 +139 -0
- package/index.d.ts +368 -0
- package/index.js +715 -0
- package/package.json +27 -0
package/README.md
ADDED
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
# @json-eval-rs/webcore
|
|
2
|
+
|
|
3
|
+
High-level JavaScript API for JSON Eval RS WASM bindings.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Install bridge + your target WASM package
|
|
9
|
+
yarn install @json-eval-rs/webcore @json-eval-rs/bundler
|
|
10
|
+
|
|
11
|
+
# Or for direct browser use
|
|
12
|
+
yarn install @json-eval-rs/webcore @json-eval-rs/vanilla
|
|
13
|
+
|
|
14
|
+
# Or for Node.js
|
|
15
|
+
yarn install @json-eval-rs/webcore @json-eval-rs/node
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Usage
|
|
19
|
+
|
|
20
|
+
### With Bundler (Webpack, Vite, Next.js, etc.)
|
|
21
|
+
|
|
22
|
+
```typescript
|
|
23
|
+
import { JSONEval } from '@json-eval-rs/webcore';
|
|
24
|
+
import * as wasmModule from '@json-eval-rs/bundler';
|
|
25
|
+
|
|
26
|
+
const evaluator = new JSONEval({
|
|
27
|
+
schema: {
|
|
28
|
+
type: 'object',
|
|
29
|
+
properties: {
|
|
30
|
+
name: {
|
|
31
|
+
type: 'string',
|
|
32
|
+
rules: {
|
|
33
|
+
required: { value: true, message: 'Name is required' },
|
|
34
|
+
minLength: { value: 3, message: 'Min 3 characters' }
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
},
|
|
39
|
+
wasmModule // Pass the WASM module explicitly
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
// Validate data
|
|
43
|
+
const result = await evaluator.validate({
|
|
44
|
+
data: { name: 'Jo' }
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
if (result.has_error) {
|
|
48
|
+
console.log('Errors:', result.errors);
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// Don't forget to free resources
|
|
52
|
+
evaluator.free();
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
### Dynamic Import (for Next.js client components)
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
'use client';
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
Promise.all([
|
|
62
|
+
import('@json-eval-rs/webcore'),
|
|
63
|
+
import('@json-eval-rs/bundler')
|
|
64
|
+
]).then(([{ JSONEval }, wasmModule]) => {
|
|
65
|
+
const evaluator = new JSONEval({ schema, wasmModule });
|
|
66
|
+
// Use evaluator...
|
|
67
|
+
});
|
|
68
|
+
}, []);
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### API
|
|
72
|
+
|
|
73
|
+
#### `new JSONEval(options)`
|
|
74
|
+
|
|
75
|
+
Create a new evaluator instance.
|
|
76
|
+
|
|
77
|
+
**Options:**
|
|
78
|
+
- `schema` (required) - JSON schema object
|
|
79
|
+
- `context` (optional) - Context data object
|
|
80
|
+
- `data` (optional) - Initial data object
|
|
81
|
+
- `wasmModule` (optional) - Pre-loaded WASM module
|
|
82
|
+
|
|
83
|
+
#### `await evaluator.validate({ data, context? })`
|
|
84
|
+
|
|
85
|
+
Validate data against schema rules.
|
|
86
|
+
|
|
87
|
+
Returns: `{ has_error: boolean, errors: ValidationError[] }`
|
|
88
|
+
|
|
89
|
+
#### `await evaluator.evaluate({ data, context? })`
|
|
90
|
+
|
|
91
|
+
Evaluate schema with data.
|
|
92
|
+
|
|
93
|
+
Returns: Evaluated schema object
|
|
94
|
+
|
|
95
|
+
#### `await evaluator.evaluateDependents({ changedPaths, data, context?, nested? })`
|
|
96
|
+
|
|
97
|
+
Re-evaluate fields that depend on changed paths.
|
|
98
|
+
|
|
99
|
+
**Options:**
|
|
100
|
+
- `changedPaths` - Array of field paths that changed
|
|
101
|
+
- `data` - Current data
|
|
102
|
+
- `context` (optional) - Context data
|
|
103
|
+
- `nested` (optional, default: true) - Follow dependency chains
|
|
104
|
+
|
|
105
|
+
Returns: Updated evaluated schema
|
|
106
|
+
|
|
107
|
+
#### `evaluator.free()`
|
|
108
|
+
|
|
109
|
+
Free WASM resources. Call this when done.
|
|
110
|
+
|
|
111
|
+
## Why Use the Core?
|
|
112
|
+
|
|
113
|
+
The core package provides:
|
|
114
|
+
|
|
115
|
+
1. **Clean API** - Options objects instead of positional JSON strings
|
|
116
|
+
2. **Type Safety** - Full TypeScript support
|
|
117
|
+
3. **Auto-detection** - Automatically loads the right WASM target
|
|
118
|
+
4. **Flexibility** - Works with bundler/web/node targets
|
|
119
|
+
|
|
120
|
+
## Direct WASM Usage
|
|
121
|
+
|
|
122
|
+
If you prefer minimal overhead, you can use WASM packages directly:
|
|
123
|
+
|
|
124
|
+
```typescript
|
|
125
|
+
import { JSONEvalWasm } from '@json-eval-rs/bundler';
|
|
126
|
+
|
|
127
|
+
const instance = new JSONEvalWasm(
|
|
128
|
+
JSON.stringify(schema),
|
|
129
|
+
JSON.stringify(context),
|
|
130
|
+
JSON.stringify(data)
|
|
131
|
+
);
|
|
132
|
+
|
|
133
|
+
const result = await instance.validate(JSON.stringify(data));
|
|
134
|
+
instance.free();
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
## License
|
|
138
|
+
|
|
139
|
+
MIT
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,368 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @json-eval-rs/webcore - TypeScript definitions
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Get the library version from the WASM module
|
|
7
|
+
* @param wasmModule - WASM module
|
|
8
|
+
* @returns Version string
|
|
9
|
+
*/
|
|
10
|
+
export function getVersion(wasmModule: any): string;
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Return format for path-based methods
|
|
14
|
+
*/
|
|
15
|
+
export enum ReturnFormat {
|
|
16
|
+
/** Nested object preserving the path hierarchy (default) */
|
|
17
|
+
Nested = 0,
|
|
18
|
+
/** Flat object with dotted keys */
|
|
19
|
+
Flat = 1,
|
|
20
|
+
/** Array of values in the order of requested paths */
|
|
21
|
+
Array = 2
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Validation error for a specific field
|
|
26
|
+
*/
|
|
27
|
+
export interface ValidationError {
|
|
28
|
+
/** Field path with the error */
|
|
29
|
+
path: string;
|
|
30
|
+
/** Type of validation rule that failed (e.g., 'required', 'min', 'max', 'pattern') */
|
|
31
|
+
rule_type: string;
|
|
32
|
+
/** Error message */
|
|
33
|
+
message: string;
|
|
34
|
+
/** Optional error code */
|
|
35
|
+
code?: string;
|
|
36
|
+
/** Optional regex pattern (for pattern validation errors) */
|
|
37
|
+
pattern?: string;
|
|
38
|
+
/** Optional field value that failed validation (as string) */
|
|
39
|
+
field_value?: string;
|
|
40
|
+
/** Optional additional data context for the error */
|
|
41
|
+
data?: any;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Result of validation operation
|
|
46
|
+
*/
|
|
47
|
+
export interface ValidationResult {
|
|
48
|
+
/** Whether any validation errors occurred */
|
|
49
|
+
has_error: boolean;
|
|
50
|
+
/** Array of validation errors */
|
|
51
|
+
errors: ValidationError[];
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Dependent field change from evaluateDependents
|
|
56
|
+
*/
|
|
57
|
+
export interface DependentChange {
|
|
58
|
+
/** Path of the dependent field (in dot notation) */
|
|
59
|
+
$ref: string;
|
|
60
|
+
/** Schema definition of the changed field */
|
|
61
|
+
$field?: any;
|
|
62
|
+
/** Schema definition of the parent field */
|
|
63
|
+
$parentField: any;
|
|
64
|
+
/** Whether this is a transitive dependency */
|
|
65
|
+
transitive: boolean;
|
|
66
|
+
/** If true, the field was cleared */
|
|
67
|
+
clear?: boolean;
|
|
68
|
+
/** New value of the field (if changed) */
|
|
69
|
+
value?: any;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Options for creating a JSONEval instance
|
|
74
|
+
*/
|
|
75
|
+
export interface JSONEvalOptions {
|
|
76
|
+
/** JSON schema object */
|
|
77
|
+
schema: any;
|
|
78
|
+
/** Optional context data */
|
|
79
|
+
context?: any;
|
|
80
|
+
/** Optional initial data */
|
|
81
|
+
data?: any;
|
|
82
|
+
/** WASM module instance */
|
|
83
|
+
wasmModule?: any;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Options for validation
|
|
88
|
+
*/
|
|
89
|
+
export interface ValidateOptions {
|
|
90
|
+
/** JSON data to validate */
|
|
91
|
+
data: any;
|
|
92
|
+
/** Optional context data */
|
|
93
|
+
context?: any;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Options for evaluation
|
|
98
|
+
*/
|
|
99
|
+
export interface EvaluateOptions {
|
|
100
|
+
/** JSON data to evaluate */
|
|
101
|
+
data: any;
|
|
102
|
+
/** Optional context data */
|
|
103
|
+
context?: any;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Options for evaluating dependents
|
|
108
|
+
*/
|
|
109
|
+
export interface EvaluateDependentsOptions {
|
|
110
|
+
/** Array of field paths that changed */
|
|
111
|
+
changedPaths: string[];
|
|
112
|
+
/** Updated JSON data */
|
|
113
|
+
data?: any;
|
|
114
|
+
/** Optional context data */
|
|
115
|
+
context?: any;
|
|
116
|
+
/** If true, performs full evaluation after processing dependents */
|
|
117
|
+
reEvaluate?: boolean;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Options for getting evaluated schema
|
|
122
|
+
*/
|
|
123
|
+
export interface GetEvaluatedSchemaOptions {
|
|
124
|
+
/** Whether to skip layout resolution */
|
|
125
|
+
skipLayout?: boolean;
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
/**
|
|
129
|
+
* Options for getting a value by path from evaluated schema
|
|
130
|
+
*/
|
|
131
|
+
export interface GetValueByPathOptions {
|
|
132
|
+
/** Dotted path to the value */
|
|
133
|
+
path: string;
|
|
134
|
+
/** Whether to skip layout resolution */
|
|
135
|
+
skipLayout?: boolean;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Options for getting values by multiple paths from evaluated schema
|
|
140
|
+
*/
|
|
141
|
+
export interface GetValueByPathsOptions {
|
|
142
|
+
/** Array of dotted paths to retrieve */
|
|
143
|
+
paths: string[];
|
|
144
|
+
/** Whether to skip layout resolution */
|
|
145
|
+
skipLayout?: boolean;
|
|
146
|
+
/** Return format (Nested, Flat, or Array) */
|
|
147
|
+
format?: ReturnFormat;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Options for getting a value by path from schema
|
|
152
|
+
*/
|
|
153
|
+
export interface GetSchemaByPathOptions {
|
|
154
|
+
/** Dotted path to the value */
|
|
155
|
+
path: string;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Options for getting values by multiple paths from schema
|
|
160
|
+
*/
|
|
161
|
+
export interface GetSchemaByPathsOptions {
|
|
162
|
+
/** Array of dotted paths to retrieve */
|
|
163
|
+
paths: string[];
|
|
164
|
+
/** Return format (Nested, Flat, or Array) */
|
|
165
|
+
format?: ReturnFormat;
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
/**
|
|
169
|
+
* Options for reloading schema
|
|
170
|
+
*/
|
|
171
|
+
export interface ReloadSchemaOptions {
|
|
172
|
+
/** New JSON schema */
|
|
173
|
+
schema: any;
|
|
174
|
+
/** Optional new context */
|
|
175
|
+
context?: any;
|
|
176
|
+
/** Optional new data */
|
|
177
|
+
data?: any;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
/**
|
|
181
|
+
* Cache statistics
|
|
182
|
+
*/
|
|
183
|
+
export interface CacheStats {
|
|
184
|
+
/** Number of cache hits */
|
|
185
|
+
hits: number;
|
|
186
|
+
/** Number of cache misses */
|
|
187
|
+
misses: number;
|
|
188
|
+
/** Number of cached entries */
|
|
189
|
+
entries: number;
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Options for evaluating a subform
|
|
194
|
+
*/
|
|
195
|
+
export interface EvaluateSubformOptions {
|
|
196
|
+
/** Path to the subform */
|
|
197
|
+
subformPath: string;
|
|
198
|
+
/** JSON data to evaluate */
|
|
199
|
+
data: any;
|
|
200
|
+
/** Optional context data */
|
|
201
|
+
context?: any;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Options for validating a subform
|
|
206
|
+
*/
|
|
207
|
+
export interface ValidateSubformOptions {
|
|
208
|
+
/** Path to the subform */
|
|
209
|
+
subformPath: string;
|
|
210
|
+
/** JSON data to validate */
|
|
211
|
+
data: any;
|
|
212
|
+
/** Optional context data */
|
|
213
|
+
context?: any;
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Options for evaluating dependents in a subform
|
|
218
|
+
*/
|
|
219
|
+
export interface EvaluateDependentsSubformOptions {
|
|
220
|
+
/** Path to the subform */
|
|
221
|
+
subformPath: string;
|
|
222
|
+
/** Array of field paths that changed */
|
|
223
|
+
changedPaths: string[];
|
|
224
|
+
/** Updated JSON data */
|
|
225
|
+
data?: any;
|
|
226
|
+
/** Optional context data */
|
|
227
|
+
context?: any;
|
|
228
|
+
/** If true, performs full evaluation after processing dependents */
|
|
229
|
+
reEvaluate?: boolean;
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Options for resolving layout in a subform
|
|
234
|
+
*/
|
|
235
|
+
export interface ResolveLayoutSubformOptions {
|
|
236
|
+
/** Path to the subform */
|
|
237
|
+
subformPath: string;
|
|
238
|
+
/** Whether to evaluate after resolving layout */
|
|
239
|
+
evaluate?: boolean;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Options for getting evaluated schema from a subform
|
|
244
|
+
*/
|
|
245
|
+
export interface GetEvaluatedSchemaSubformOptions {
|
|
246
|
+
/** Path to the subform */
|
|
247
|
+
subformPath: string;
|
|
248
|
+
/** Whether to resolve layout */
|
|
249
|
+
resolveLayout?: boolean;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/**
|
|
253
|
+
* Options for getting schema value from a subform
|
|
254
|
+
*/
|
|
255
|
+
export interface GetSchemaValueSubformOptions {
|
|
256
|
+
/** Path to the subform */
|
|
257
|
+
subformPath: string;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Options for getting evaluated schema by path from a subform
|
|
262
|
+
*/
|
|
263
|
+
export interface GetEvaluatedSchemaByPathSubformOptions {
|
|
264
|
+
/** Path to the subform */
|
|
265
|
+
subformPath: string;
|
|
266
|
+
/** Dotted path to the value within the subform */
|
|
267
|
+
schemaPath: string;
|
|
268
|
+
/** Whether to skip layout resolution */
|
|
269
|
+
skipLayout?: boolean;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/**
|
|
273
|
+
* Options for getting evaluated schema by multiple paths from a subform
|
|
274
|
+
*/
|
|
275
|
+
export interface GetEvaluatedSchemaByPathsSubformOptions {
|
|
276
|
+
/** Path to the subform */
|
|
277
|
+
subformPath: string;
|
|
278
|
+
/** Array of dotted paths to retrieve within the subform */
|
|
279
|
+
schemaPaths: string[];
|
|
280
|
+
/** Whether to skip layout resolution */
|
|
281
|
+
skipLayout?: boolean;
|
|
282
|
+
/** Return format (Nested, Flat, or Array) */
|
|
283
|
+
format?: ReturnFormat;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
/**
|
|
287
|
+
* Options for getting schema by path from a subform
|
|
288
|
+
*/
|
|
289
|
+
export interface GetSchemaByPathSubformOptions {
|
|
290
|
+
/** Path to the subform */
|
|
291
|
+
subformPath: string;
|
|
292
|
+
/** Dotted path to the value within the subform */
|
|
293
|
+
schemaPath: string;
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
/**
|
|
297
|
+
* Options for getting schema by multiple paths from a subform
|
|
298
|
+
*/
|
|
299
|
+
export interface GetSchemaByPathsSubformOptions {
|
|
300
|
+
/** Path to the subform */
|
|
301
|
+
subformPath: string;
|
|
302
|
+
/** Array of dotted paths to retrieve within the subform */
|
|
303
|
+
schemaPaths: string[];
|
|
304
|
+
/** Return format (Nested, Flat, or Array) */
|
|
305
|
+
format?: ReturnFormat;
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Options for compiling and running logic
|
|
310
|
+
*/
|
|
311
|
+
export interface CompileAndRunLogicOptions {
|
|
312
|
+
/** Logic expression as string or object */
|
|
313
|
+
logicStr: string | object;
|
|
314
|
+
/** Optional data context */
|
|
315
|
+
data?: any;
|
|
316
|
+
/** Optional context data */
|
|
317
|
+
context?: any;
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export class JSONEval {
|
|
321
|
+
constructor(options: JSONEvalOptions);
|
|
322
|
+
static fromCache(cacheKey: string, context?: any, data?: any): JSONEval;
|
|
323
|
+
init(): Promise<void>;
|
|
324
|
+
validate(options: ValidateOptions): Promise<ValidationResult>;
|
|
325
|
+
evaluate(options: EvaluateOptions): Promise<any>;
|
|
326
|
+
evaluateDependents(options: EvaluateDependentsOptions): Promise<DependentChange[]>;
|
|
327
|
+
compileAndRunLogic(options: CompileAndRunLogicOptions): Promise<any>;
|
|
328
|
+
compileLogic(logicStr: string | object): Promise<number>;
|
|
329
|
+
runLogic(logicId: number, data?: any, context?: any): Promise<any>;
|
|
330
|
+
getEvaluatedSchema(options?: GetEvaluatedSchemaOptions): Promise<any>;
|
|
331
|
+
getSchemaValue(): Promise<any>;
|
|
332
|
+
getEvaluatedSchemaWithoutParams(options?: GetEvaluatedSchemaOptions): Promise<any>;
|
|
333
|
+
getValueByPath(options: GetValueByPathOptions): Promise<any | null>;
|
|
334
|
+
getEvaluatedSchemaByPath(options: GetValueByPathOptions): Promise<any | null>;
|
|
335
|
+
getEvaluatedSchemaByPaths(options: GetValueByPathsOptions): Promise<any>;
|
|
336
|
+
getSchemaByPath(options: GetSchemaByPathOptions): Promise<any | null>;
|
|
337
|
+
getSchemaByPaths(options: GetSchemaByPathsOptions): Promise<any>;
|
|
338
|
+
reloadSchema(options: ReloadSchemaOptions): Promise<void>;
|
|
339
|
+
reloadSchemaMsgpack(schemaMsgpack: Uint8Array, context?: any, data?: any): Promise<void>;
|
|
340
|
+
reloadSchemaFromCache(cacheKey: string, context?: any, data?: any): Promise<void>;
|
|
341
|
+
cacheStats(): Promise<CacheStats>;
|
|
342
|
+
clearCache(): Promise<void>;
|
|
343
|
+
cacheLen(): Promise<number>;
|
|
344
|
+
enableCache(): Promise<void>;
|
|
345
|
+
disableCache(): Promise<void>;
|
|
346
|
+
isCacheEnabled(): boolean;
|
|
347
|
+
|
|
348
|
+
// Subform methods
|
|
349
|
+
evaluateSubform(options: EvaluateSubformOptions): Promise<void>;
|
|
350
|
+
validateSubform(options: ValidateSubformOptions): Promise<ValidationResult>;
|
|
351
|
+
evaluateDependentsSubform(options: EvaluateDependentsSubformOptions): Promise<DependentChange[]>;
|
|
352
|
+
resolveLayoutSubform(options: ResolveLayoutSubformOptions): Promise<void>;
|
|
353
|
+
getEvaluatedSchemaSubform(options: GetEvaluatedSchemaSubformOptions): Promise<any>;
|
|
354
|
+
getSchemaValueSubform(options: GetSchemaValueSubformOptions): Promise<any>;
|
|
355
|
+
getEvaluatedSchemaWithoutParamsSubform(options: GetEvaluatedSchemaSubformOptions): Promise<any>;
|
|
356
|
+
getEvaluatedSchemaByPathSubform(options: GetEvaluatedSchemaByPathSubformOptions): Promise<any | null>;
|
|
357
|
+
getEvaluatedSchemaByPathsSubform(options: GetEvaluatedSchemaByPathsSubformOptions): Promise<any>;
|
|
358
|
+
getSchemaByPathSubform(options: GetSchemaByPathSubformOptions): Promise<any | null>;
|
|
359
|
+
getSchemaByPathsSubform(options: GetSchemaByPathsSubformOptions): Promise<any>;
|
|
360
|
+
getSubformPaths(): Promise<string[]>;
|
|
361
|
+
hasSubform(subformPath: string): Promise<boolean>;
|
|
362
|
+
|
|
363
|
+
free(): void;
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
export function version(wasmModule?: any): Promise<string>;
|
|
367
|
+
|
|
368
|
+
export default JSONEval;
|
package/index.js
ADDED
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @json-eval-rs/webcore
|
|
3
|
+
* High-level JavaScript API for JSON Eval RS WASM bindings
|
|
4
|
+
*
|
|
5
|
+
* This package provides a clean, ergonomic API that works with any WASM target:
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Get the library version from the WASM module
|
|
10
|
+
* @param {any} wasmModule - WASM module
|
|
11
|
+
* @returns {string} Version string
|
|
12
|
+
*/
|
|
13
|
+
export function getVersion(wasmModule) {
|
|
14
|
+
if (wasmModule && typeof wasmModule.getVersion === 'function') {
|
|
15
|
+
return wasmModule.getVersion();
|
|
16
|
+
}
|
|
17
|
+
return 'unknown';
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* JSONEval - High-level JavaScript API for JSON Eval RS
|
|
22
|
+
*
|
|
23
|
+
* This is an internal abstraction layer. Use specific packages instead:
|
|
24
|
+
* - @json-eval-rs/bundler (for bundlers like Webpack, Vite, Next.js)
|
|
25
|
+
* - @json-eval-rs/vanilla (for direct browser usage)
|
|
26
|
+
* - @json-eval-rs/node (for Node.js/SSR)
|
|
27
|
+
*
|
|
28
|
+
* @example
|
|
29
|
+
* ```js
|
|
30
|
+
* import { JSONEval } from '@json-eval-rs/webcore';
|
|
31
|
+
*
|
|
32
|
+
* const evaluator = new JSONEval({
|
|
33
|
+
* schema: { type: 'object', properties: { ... } }
|
|
34
|
+
* });
|
|
35
|
+
*
|
|
36
|
+
* await evaluator.init();
|
|
37
|
+
* const result = await evaluator.validate({ data: { name: 'John' } });
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
export class JSONEvalCore {
|
|
41
|
+
/**
|
|
42
|
+
* @param {any} wasmModule - WASM module (injected by wrapper package)
|
|
43
|
+
* @param {object} options
|
|
44
|
+
* @param {object|Uint8Array|string} options.schema - JSON schema, MessagePack bytes, or cache key
|
|
45
|
+
* @param {object} [options.context] - Optional context data
|
|
46
|
+
* @param {object} [options.data] - Optional initial data
|
|
47
|
+
* @param {boolean} [options.fromCache] - If true, schema is treated as a cache key
|
|
48
|
+
*/
|
|
49
|
+
constructor(wasmModule, { schema, context, data, fromCache = false }) {
|
|
50
|
+
this._schema = schema;
|
|
51
|
+
this._wasmModule = wasmModule;
|
|
52
|
+
this._context = context;
|
|
53
|
+
this._data = data;
|
|
54
|
+
this._instance = null;
|
|
55
|
+
this._ready = false;
|
|
56
|
+
this._isMsgpackSchema = schema instanceof Uint8Array;
|
|
57
|
+
this._isFromCache = fromCache;
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/**
|
|
61
|
+
* Initialize the WASM instance
|
|
62
|
+
* Call this before using other methods, or use the async methods which call it automatically
|
|
63
|
+
*/
|
|
64
|
+
async init() {
|
|
65
|
+
if (this._ready) return;
|
|
66
|
+
|
|
67
|
+
// If WASM module not provided, throw error - user must provide it or install peer dependency
|
|
68
|
+
if (!this._wasmModule) {
|
|
69
|
+
throw new Error(
|
|
70
|
+
'No WASM module provided. Please either:\n' +
|
|
71
|
+
'1. Pass wasmModule in constructor: new JSONEval({ schema, wasmModule: await import("@json-eval-rs/bundler") })\n' +
|
|
72
|
+
'2. Or install a peer dependency: yarn install @json-eval-rs/bundler (or @json-eval-rs/vanilla or @json-eval-rs/node)'
|
|
73
|
+
);
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
try {
|
|
77
|
+
const { JSONEvalWasm } = this._wasmModule;
|
|
78
|
+
|
|
79
|
+
// Create instance from cache, MessagePack, or JSON
|
|
80
|
+
if (this._isFromCache) {
|
|
81
|
+
this._instance = JSONEvalWasm.newFromCache(
|
|
82
|
+
this._schema, // cache key
|
|
83
|
+
this._context ? JSON.stringify(this._context) : null,
|
|
84
|
+
this._data ? JSON.stringify(this._data) : null
|
|
85
|
+
);
|
|
86
|
+
} else if (this._isMsgpackSchema) {
|
|
87
|
+
this._instance = JSONEvalWasm.newFromMsgpack(
|
|
88
|
+
this._schema,
|
|
89
|
+
this._context ? JSON.stringify(this._context) : null,
|
|
90
|
+
this._data ? JSON.stringify(this._data) : null
|
|
91
|
+
);
|
|
92
|
+
} else {
|
|
93
|
+
this._instance = new JSONEvalWasm(
|
|
94
|
+
JSON.stringify(this._schema),
|
|
95
|
+
this._context ? JSON.stringify(this._context) : null,
|
|
96
|
+
this._data ? JSON.stringify(this._data) : null
|
|
97
|
+
);
|
|
98
|
+
}
|
|
99
|
+
this._ready = true;
|
|
100
|
+
} catch (error) {
|
|
101
|
+
throw new Error(`Failed to create JSONEval instance: ${error.message || error}`);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Create a new JSONEval instance from a cached ParsedSchema
|
|
107
|
+
* Static factory method for convenience
|
|
108
|
+
*
|
|
109
|
+
* @param {any} wasmModule - WASM module
|
|
110
|
+
* @param {string} cacheKey - Cache key to lookup in ParsedSchemaCache
|
|
111
|
+
* @param {object} [context] - Optional context data
|
|
112
|
+
* @param {object} [data] - Optional initial data
|
|
113
|
+
* @returns {JSONEvalCore} New instance
|
|
114
|
+
*/
|
|
115
|
+
static fromCache(wasmModule, cacheKey, context, data) {
|
|
116
|
+
return new JSONEvalCore(wasmModule, {
|
|
117
|
+
schema: cacheKey,
|
|
118
|
+
context,
|
|
119
|
+
data,
|
|
120
|
+
fromCache: true
|
|
121
|
+
});
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* Validate data against schema (returns parsed JavaScript object)
|
|
126
|
+
* Uses validateJS for Worker-safe serialization
|
|
127
|
+
* @param {object} options
|
|
128
|
+
* @param {object} options.data - Data to validate
|
|
129
|
+
* @param {object} [options.context] - Optional context
|
|
130
|
+
* @returns {Promise<{has_error: boolean, errors: Array<{path: string, rule_type: string, message: string}>}>}
|
|
131
|
+
*/
|
|
132
|
+
async validate({ data, context }) {
|
|
133
|
+
await this.init();
|
|
134
|
+
try {
|
|
135
|
+
// Use validateJS for proper serialization (Worker-safe)
|
|
136
|
+
return this._instance.validateJS(
|
|
137
|
+
JSON.stringify(data),
|
|
138
|
+
context ? JSON.stringify(context) : null
|
|
139
|
+
);
|
|
140
|
+
} catch (error) {
|
|
141
|
+
throw new Error(`Validation failed: ${error.message || error}`);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Evaluate schema with data (returns parsed JavaScript object)
|
|
147
|
+
* @param {object} options
|
|
148
|
+
* @param {object} options.data - Data to evaluate
|
|
149
|
+
* @param {object} [options.context] - Optional context
|
|
150
|
+
* @returns {Promise<any>}
|
|
151
|
+
*/
|
|
152
|
+
async evaluate({ data, context }) {
|
|
153
|
+
await this.init();
|
|
154
|
+
try {
|
|
155
|
+
return this._instance.evaluateJS(
|
|
156
|
+
JSON.stringify(data),
|
|
157
|
+
context ? JSON.stringify(context) : null
|
|
158
|
+
);
|
|
159
|
+
} catch (error) {
|
|
160
|
+
throw new Error(`Evaluation failed: ${error.message || error}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Evaluate dependent fields (returns parsed JavaScript object, processes transitively)
|
|
166
|
+
* @param {object} options
|
|
167
|
+
* @param {string[]} options.changedPaths - Array of changed field paths (e.g., ["#/illustration/properties/field1", "field2"])
|
|
168
|
+
* @param {object} [options.data] - Optional updated data (null to use existing)
|
|
169
|
+
* @param {object} [options.context] - Optional context
|
|
170
|
+
* @param {boolean} [options.reEvaluate] - If true, performs full evaluation after processing dependents
|
|
171
|
+
* @returns {Promise<Array>} Array of dependent change objects
|
|
172
|
+
*/
|
|
173
|
+
async evaluateDependents({ changedPaths, data, context, reEvaluate = false }) {
|
|
174
|
+
await this.init();
|
|
175
|
+
try {
|
|
176
|
+
return this._instance.evaluateDependentsJS(
|
|
177
|
+
JSON.stringify(changedPaths),
|
|
178
|
+
data ? JSON.stringify(data) : null,
|
|
179
|
+
context ? JSON.stringify(context) : null,
|
|
180
|
+
reEvaluate
|
|
181
|
+
);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
throw new Error(`Dependent evaluation failed: ${error.message || error}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Get evaluated schema
|
|
189
|
+
* @param {object} [options]
|
|
190
|
+
* @param {boolean} [options.skipLayout=false] - Skip layout resolution
|
|
191
|
+
* @returns {Promise<any>}
|
|
192
|
+
*/
|
|
193
|
+
async getEvaluatedSchema({ skipLayout = false } = {}) {
|
|
194
|
+
await this.init();
|
|
195
|
+
return this._instance.getEvaluatedSchemaJS(skipLayout);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* Get evaluated schema as MessagePack binary data
|
|
200
|
+
* @param {object} [options]
|
|
201
|
+
* @param {boolean} [options.skipLayout=false] - Skip layout resolution
|
|
202
|
+
* @returns {Promise<Uint8Array>} MessagePack-encoded schema bytes
|
|
203
|
+
*/
|
|
204
|
+
async getEvaluatedSchemaMsgpack({ skipLayout = false } = {}) {
|
|
205
|
+
await this.init();
|
|
206
|
+
return this._instance.getEvaluatedSchemaMsgpack(skipLayout);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Get schema values (evaluations ending with .value)
|
|
211
|
+
* @returns {Promise<object>}
|
|
212
|
+
*/
|
|
213
|
+
async getSchemaValue() {
|
|
214
|
+
await this.init();
|
|
215
|
+
return this._instance.getSchemaValue();
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Get evaluated schema without $params field
|
|
220
|
+
* @param {object} [options]
|
|
221
|
+
* @param {boolean} [options.skipLayout=false] - Skip layout resolution
|
|
222
|
+
* @returns {Promise<any>}
|
|
223
|
+
*/
|
|
224
|
+
async getEvaluatedSchemaWithoutParams({ skipLayout = false } = {}) {
|
|
225
|
+
await this.init();
|
|
226
|
+
return this._instance.getEvaluatedSchemaWithoutParamsJS(skipLayout);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
/**
|
|
230
|
+
* Get a value from the evaluated schema using dotted path notation
|
|
231
|
+
* @param {object} options
|
|
232
|
+
* @param {string} options.path - Dotted path to the value (e.g., "properties.field.value")
|
|
233
|
+
* @param {boolean} [options.skipLayout=false] - Skip layout resolution
|
|
234
|
+
* @returns {Promise<any|null>} Value at the path, or null if not found
|
|
235
|
+
*/
|
|
236
|
+
async getEvaluatedSchemaByPath({ path, skipLayout = false }) {
|
|
237
|
+
await this.init();
|
|
238
|
+
return this._instance.getEvaluatedSchemaByPathJS(path, skipLayout);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Get values from the evaluated schema using multiple dotted path notations
|
|
243
|
+
* Returns data in the specified format (skips paths that are not found)
|
|
244
|
+
* @param {object} options
|
|
245
|
+
* @param {string[]} options.paths - Array of dotted paths to retrieve
|
|
246
|
+
* @param {boolean} [options.skipLayout=false] - Skip layout resolution
|
|
247
|
+
* @param {number} [options.format=0] - Return format (0=Nested, 1=Flat, 2=Array)
|
|
248
|
+
* @returns {Promise<any>} Data in specified format
|
|
249
|
+
*/
|
|
250
|
+
async getEvaluatedSchemaByPaths({ paths, skipLayout = false, format = 0 }) {
|
|
251
|
+
await this.init();
|
|
252
|
+
return this._instance.getEvaluatedSchemaByPathsJS(JSON.stringify(paths), skipLayout, format);
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Get a value from the schema using dotted path notation
|
|
257
|
+
* @param {object} options
|
|
258
|
+
* @param {string} options.path - Dotted path to the value (e.g., "properties.field.value")
|
|
259
|
+
* @returns {Promise<any|null>} Value at the path, or null if not found
|
|
260
|
+
*/
|
|
261
|
+
async getSchemaByPath({ path }) {
|
|
262
|
+
await this.init();
|
|
263
|
+
return this._instance.getSchemaByPathJS(path);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Get values from the schema using multiple dotted path notations
|
|
268
|
+
* Returns data in the specified format (skips paths that are not found)
|
|
269
|
+
* @param {object} options
|
|
270
|
+
* @param {string[]} options.paths - Array of dotted paths to retrieve
|
|
271
|
+
* @param {number} [options.format=0] - Return format (0=Nested, 1=Flat, 2=Array)
|
|
272
|
+
* @returns {Promise<any>} Data in specified format
|
|
273
|
+
*/
|
|
274
|
+
async getSchemaByPaths({ paths, format = 0 }) {
|
|
275
|
+
await this.init();
|
|
276
|
+
return this._instance.getSchemaByPathsJS(JSON.stringify(paths), format);
|
|
277
|
+
}
|
|
278
|
+
|
|
279
|
+
/**
|
|
280
|
+
* Reload schema with new data
|
|
281
|
+
* @param {object} options
|
|
282
|
+
* @param {object} options.schema - New JSON schema
|
|
283
|
+
* @param {object} [options.context] - Optional new context
|
|
284
|
+
* @param {object} [options.data] - Optional new data
|
|
285
|
+
* @returns {Promise<void>}
|
|
286
|
+
*/
|
|
287
|
+
async reloadSchema({ schema, context, data }) {
|
|
288
|
+
if (!this._instance) {
|
|
289
|
+
throw new Error('Instance not initialized. Call init() first.');
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
try {
|
|
293
|
+
await this._instance.reloadSchema(
|
|
294
|
+
JSON.stringify(schema),
|
|
295
|
+
context ? JSON.stringify(context) : null,
|
|
296
|
+
data ? JSON.stringify(data) : null
|
|
297
|
+
);
|
|
298
|
+
|
|
299
|
+
// Update internal state
|
|
300
|
+
this._schema = schema;
|
|
301
|
+
this._context = context;
|
|
302
|
+
this._data = data;
|
|
303
|
+
} catch (error) {
|
|
304
|
+
throw new Error(`Failed to reload schema: ${error.message || error}`);
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
/**
|
|
309
|
+
* Reload schema from MessagePack bytes
|
|
310
|
+
* @param {Uint8Array} schemaMsgpack - MessagePack-encoded schema bytes
|
|
311
|
+
* @param {object} [context] - Optional new context
|
|
312
|
+
* @param {object} [data] - Optional new data
|
|
313
|
+
* @returns {Promise<void>}
|
|
314
|
+
*/
|
|
315
|
+
async reloadSchemaMsgpack(schemaMsgpack, context, data) {
|
|
316
|
+
if (!this._instance) {
|
|
317
|
+
throw new Error('Instance not initialized. Call init() first.');
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
if (!(schemaMsgpack instanceof Uint8Array)) {
|
|
321
|
+
throw new Error('schemaMsgpack must be a Uint8Array');
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
try {
|
|
325
|
+
await this._instance.reloadSchemaMsgpack(
|
|
326
|
+
schemaMsgpack,
|
|
327
|
+
context ? JSON.stringify(context) : null,
|
|
328
|
+
data ? JSON.stringify(data) : null
|
|
329
|
+
);
|
|
330
|
+
|
|
331
|
+
// Update internal state
|
|
332
|
+
this._schema = schemaMsgpack;
|
|
333
|
+
this._context = context;
|
|
334
|
+
this._data = data;
|
|
335
|
+
this._isMsgpackSchema = true;
|
|
336
|
+
} catch (error) {
|
|
337
|
+
throw new Error(`Failed to reload schema from MessagePack: ${error.message || error}`);
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
/**
|
|
342
|
+
* Reload schema from ParsedSchemaCache using a cache key
|
|
343
|
+
* @param {string} cacheKey - Cache key to lookup in the global ParsedSchemaCache
|
|
344
|
+
* @param {object} [context] - Optional new context
|
|
345
|
+
* @param {object} [data] - Optional new data
|
|
346
|
+
* @returns {Promise<void>}
|
|
347
|
+
*/
|
|
348
|
+
async reloadSchemaFromCache(cacheKey, context, data) {
|
|
349
|
+
if (!this._instance) {
|
|
350
|
+
throw new Error('Instance not initialized. Call init() first.');
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (typeof cacheKey !== 'string' || !cacheKey) {
|
|
354
|
+
throw new Error('cacheKey must be a non-empty string');
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
try {
|
|
358
|
+
await this._instance.reloadSchemaFromCache(
|
|
359
|
+
cacheKey,
|
|
360
|
+
context ? JSON.stringify(context) : null,
|
|
361
|
+
data ? JSON.stringify(data) : null
|
|
362
|
+
);
|
|
363
|
+
|
|
364
|
+
// Update internal state
|
|
365
|
+
this._context = context;
|
|
366
|
+
this._data = data;
|
|
367
|
+
// Note: schema is not updated as we don't have access to it from the cache key
|
|
368
|
+
} catch (error) {
|
|
369
|
+
throw new Error(`Failed to reload schema from cache: ${error.message || error}`);
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Get cache statistics
|
|
375
|
+
* @returns {Promise<{hits: number, misses: number, entries: number}>}
|
|
376
|
+
*/
|
|
377
|
+
async cacheStats() {
|
|
378
|
+
await this.init();
|
|
379
|
+
return this._instance.cacheStats();
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/**
|
|
383
|
+
* Clear the evaluation cache
|
|
384
|
+
* @returns {Promise<void>}
|
|
385
|
+
*/
|
|
386
|
+
async clearCache() {
|
|
387
|
+
await this.init();
|
|
388
|
+
this._instance.clearCache();
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/**
|
|
392
|
+
* Get the number of cached entries
|
|
393
|
+
* @returns {Promise<number>}
|
|
394
|
+
*/
|
|
395
|
+
async cacheLen() {
|
|
396
|
+
await this.init();
|
|
397
|
+
return this._instance.cacheLen();
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
/**
|
|
401
|
+
* Enable evaluation caching
|
|
402
|
+
* Useful for reusing JSONEval instances with different data
|
|
403
|
+
* @returns {Promise<void>}
|
|
404
|
+
*/
|
|
405
|
+
async enableCache() {
|
|
406
|
+
await this.init();
|
|
407
|
+
this._instance.enableCache();
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/**
|
|
411
|
+
* Disable evaluation caching
|
|
412
|
+
* Useful for web API usage where each request creates a new JSONEval instance
|
|
413
|
+
* Improves performance by skipping cache operations that have no benefit for single-use instances
|
|
414
|
+
* @returns {Promise<void>}
|
|
415
|
+
*/
|
|
416
|
+
async disableCache() {
|
|
417
|
+
await this.init();
|
|
418
|
+
this._instance.disableCache();
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Check if evaluation caching is enabled
|
|
423
|
+
* @returns {boolean}
|
|
424
|
+
*/
|
|
425
|
+
isCacheEnabled() {
|
|
426
|
+
if (!this._instance) return true; // Default is enabled
|
|
427
|
+
return this._instance.isCacheEnabled();
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
/**
|
|
431
|
+
* Resolve layout with optional evaluation
|
|
432
|
+
* @param {object} [options]
|
|
433
|
+
* @param {boolean} [options.evaluate=false] - If true, runs evaluation before resolving layout
|
|
434
|
+
* @returns {Promise<void>}
|
|
435
|
+
*/
|
|
436
|
+
async resolveLayout({ evaluate = false } = {}) {
|
|
437
|
+
await this.init();
|
|
438
|
+
return this._instance.resolveLayout(evaluate);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
/**
|
|
442
|
+
* Compile and run JSON logic from a JSON logic string
|
|
443
|
+
* @param {object} options - Options for compile and run logic
|
|
444
|
+
* @param {string|object} options.logicStr - JSON logic expression as a string or object
|
|
445
|
+
* @param {object} [options.data] - Optional data to evaluate against (uses existing data if not provided)
|
|
446
|
+
* @param {object} [options.context] - Optional context to use (uses existing context if not provided)
|
|
447
|
+
* @returns {Promise<any>} Result of the evaluation
|
|
448
|
+
*/
|
|
449
|
+
async compileAndRunLogic({ logicStr, data, context }) {
|
|
450
|
+
await this.init();
|
|
451
|
+
const logic = typeof logicStr === 'string' ? logicStr : JSON.stringify(logicStr);
|
|
452
|
+
const result = await this._instance.compileAndRunLogic(
|
|
453
|
+
logic,
|
|
454
|
+
data ? JSON.stringify(data) : null,
|
|
455
|
+
context ? JSON.stringify(context) : null
|
|
456
|
+
);
|
|
457
|
+
// Parse result if it's a string
|
|
458
|
+
return typeof result === 'string' ? JSON.parse(result) : result;
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
/**
|
|
462
|
+
* Compile JSON logic and return a global ID
|
|
463
|
+
* @param {string|object} logicStr - JSON logic expression as a string or object
|
|
464
|
+
* @returns {Promise<number>} Compiled logic ID
|
|
465
|
+
*/
|
|
466
|
+
async compileLogic(logicStr) {
|
|
467
|
+
await this.init();
|
|
468
|
+
const logic = typeof logicStr === 'string' ? logicStr : JSON.stringify(logicStr);
|
|
469
|
+
return this._instance.compileLogic(logic);
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
/**
|
|
473
|
+
* Run pre-compiled logic by ID
|
|
474
|
+
* @param {number} logicId - Compiled logic ID from compileLogic
|
|
475
|
+
* @param {object} [data] - Optional data to evaluate against (uses existing data if not provided)
|
|
476
|
+
* @param {object} [context] - Optional context to use (uses existing context if not provided)
|
|
477
|
+
* @returns {Promise<any>} Result of the evaluation
|
|
478
|
+
*/
|
|
479
|
+
async runLogic(logicId, data, context) {
|
|
480
|
+
await this.init();
|
|
481
|
+
const result = await this._instance.runLogic(
|
|
482
|
+
logicId,
|
|
483
|
+
data ? JSON.stringify(data) : null,
|
|
484
|
+
context ? JSON.stringify(context) : null
|
|
485
|
+
);
|
|
486
|
+
// Parse result if it's a string
|
|
487
|
+
return typeof result === 'string' ? JSON.parse(result) : result;
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Validate data against schema rules with optional path filtering
|
|
492
|
+
* @param {object} options
|
|
493
|
+
* @param {object} options.data - Data to validate
|
|
494
|
+
* @param {object} [options.context] - Optional context
|
|
495
|
+
* @param {Array<string>} [options.paths] - Optional array of paths to validate (null for all)
|
|
496
|
+
* @returns {Promise<{has_error: boolean, errors: Array<{path: string, rule_type: string, message: string}>}>}
|
|
497
|
+
*/
|
|
498
|
+
async validatePaths({ data, context, paths }) {
|
|
499
|
+
await this.init();
|
|
500
|
+
try {
|
|
501
|
+
// Use validatePathsJS for proper serialization (Worker-safe)
|
|
502
|
+
return this._instance.validatePathsJS(
|
|
503
|
+
JSON.stringify(data),
|
|
504
|
+
context ? JSON.stringify(context) : null,
|
|
505
|
+
paths || null
|
|
506
|
+
);
|
|
507
|
+
} catch (error) {
|
|
508
|
+
throw new Error(`Validation failed: ${error.message || error}`);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// ============================================================================
|
|
513
|
+
// Subform Methods
|
|
514
|
+
// ============================================================================
|
|
515
|
+
|
|
516
|
+
/**
|
|
517
|
+
* Evaluate a subform with data
|
|
518
|
+
* @param {object} options
|
|
519
|
+
* @param {string} options.subformPath - Path to the subform (e.g., "#/riders")
|
|
520
|
+
* @param {object} options.data - Data for the subform
|
|
521
|
+
* @param {object} [options.context] - Optional context
|
|
522
|
+
* @returns {Promise<void>}
|
|
523
|
+
*/
|
|
524
|
+
async evaluateSubform({ subformPath, data, context }) {
|
|
525
|
+
await this.init();
|
|
526
|
+
return this._instance.evaluateSubform(
|
|
527
|
+
subformPath,
|
|
528
|
+
JSON.stringify(data),
|
|
529
|
+
context ? JSON.stringify(context) : null
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/**
|
|
534
|
+
* Validate subform data against its schema rules
|
|
535
|
+
* @param {object} options
|
|
536
|
+
* @param {string} options.subformPath - Path to the subform
|
|
537
|
+
* @param {object} options.data - Data for the subform
|
|
538
|
+
* @param {object} [options.context] - Optional context
|
|
539
|
+
* @returns {Promise<{has_error: boolean, errors: Array}>}
|
|
540
|
+
*/
|
|
541
|
+
async validateSubform({ subformPath, data, context }) {
|
|
542
|
+
await this.init();
|
|
543
|
+
return this._instance.validateSubform(
|
|
544
|
+
subformPath,
|
|
545
|
+
JSON.stringify(data),
|
|
546
|
+
context ? JSON.stringify(context) : null
|
|
547
|
+
);
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
/**
|
|
551
|
+
* Evaluate dependent fields in subform
|
|
552
|
+
* @param {object} options
|
|
553
|
+
* @param {string} options.subformPath - Path to the subform
|
|
554
|
+
* @param {string[]} options.changedPaths - Array of field paths that changed
|
|
555
|
+
* @param {object} [options.data] - Optional updated data
|
|
556
|
+
* @param {object} [options.context] - Optional context
|
|
557
|
+
* @param {boolean} [options.reEvaluate=false] - If true, performs full evaluation after processing dependents
|
|
558
|
+
* @returns {Promise<any>}
|
|
559
|
+
*/
|
|
560
|
+
async evaluateDependentsSubform({ subformPath, changedPaths, data, context, reEvaluate = false }) {
|
|
561
|
+
await this.init();
|
|
562
|
+
|
|
563
|
+
// For backward compatibility, accept single changedPath too
|
|
564
|
+
const paths = Array.isArray(changedPaths) ? changedPaths : [changedPaths];
|
|
565
|
+
|
|
566
|
+
return this._instance.evaluateDependentsSubformJS(
|
|
567
|
+
subformPath,
|
|
568
|
+
paths[0], // WASM still expects single path (wraps internally)
|
|
569
|
+
data ? JSON.stringify(data) : null,
|
|
570
|
+
context ? JSON.stringify(context) : null
|
|
571
|
+
);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Resolve layout for subform
|
|
576
|
+
* @param {object} options
|
|
577
|
+
* @param {string} options.subformPath - Path to the subform
|
|
578
|
+
* @param {boolean} [options.evaluate=false] - If true, runs evaluation before resolving layout
|
|
579
|
+
* @returns {Promise<void>}
|
|
580
|
+
*/
|
|
581
|
+
async resolveLayoutSubform({ subformPath, evaluate = false }) {
|
|
582
|
+
await this.init();
|
|
583
|
+
return this._instance.resolveLayoutSubform(subformPath, evaluate);
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Get evaluated schema from subform
|
|
588
|
+
* @param {object} options
|
|
589
|
+
* @param {string} options.subformPath - Path to the subform
|
|
590
|
+
* @param {boolean} [options.resolveLayout=false] - Whether to resolve layout
|
|
591
|
+
* @returns {Promise<any>}
|
|
592
|
+
*/
|
|
593
|
+
async getEvaluatedSchemaSubform({ subformPath, resolveLayout = false }) {
|
|
594
|
+
await this.init();
|
|
595
|
+
return this._instance.getEvaluatedSchemaSubformJS(subformPath, resolveLayout);
|
|
596
|
+
}
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* Get schema value from subform (all .value fields)
|
|
600
|
+
* @param {object} options
|
|
601
|
+
* @param {string} options.subformPath - Path to the subform
|
|
602
|
+
* @returns {Promise<any>}
|
|
603
|
+
*/
|
|
604
|
+
async getSchemaValueSubform({ subformPath }) {
|
|
605
|
+
await this.init();
|
|
606
|
+
return this._instance.getSchemaValueSubform(subformPath);
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
/**
|
|
610
|
+
* Get evaluated schema without $params from subform
|
|
611
|
+
* @param {object} options
|
|
612
|
+
* @param {string} options.subformPath - Path to the subform
|
|
613
|
+
* @param {boolean} [options.resolveLayout=false] - Whether to resolve layout
|
|
614
|
+
* @returns {Promise<any>}
|
|
615
|
+
*/
|
|
616
|
+
async getEvaluatedSchemaWithoutParamsSubform({ subformPath, resolveLayout = false }) {
|
|
617
|
+
await this.init();
|
|
618
|
+
return this._instance.getEvaluatedSchemaWithoutParamsSubformJS(subformPath, resolveLayout);
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
/**
|
|
622
|
+
* Get evaluated schema by specific path from subform
|
|
623
|
+
* @param {object} options
|
|
624
|
+
* @param {string} options.subformPath - Path to the subform
|
|
625
|
+
* @param {string} options.schemaPath - Path within the subform
|
|
626
|
+
* @param {boolean} [options.skipLayout=false] - Whether to skip layout resolution
|
|
627
|
+
* @returns {Promise<any|null>}
|
|
628
|
+
*/
|
|
629
|
+
async getEvaluatedSchemaByPathSubform({ subformPath, schemaPath, skipLayout = false }) {
|
|
630
|
+
await this.init();
|
|
631
|
+
return this._instance.getEvaluatedSchemaByPathSubformJS(subformPath, schemaPath, skipLayout);
|
|
632
|
+
}
|
|
633
|
+
|
|
634
|
+
/**
|
|
635
|
+
* Get evaluated schema by multiple paths from subform
|
|
636
|
+
* Returns data in the specified format (skips paths that are not found)
|
|
637
|
+
* @param {object} options
|
|
638
|
+
* @param {string} options.subformPath - Path to the subform
|
|
639
|
+
* @param {string[]} options.schemaPaths - Array of paths within the subform
|
|
640
|
+
* @param {boolean} [options.skipLayout=false] - Whether to skip layout resolution
|
|
641
|
+
* @param {number} [options.format=0] - Return format (0=Nested, 1=Flat, 2=Array)
|
|
642
|
+
* @returns {Promise<any>}
|
|
643
|
+
*/
|
|
644
|
+
async getEvaluatedSchemaByPathsSubform({ subformPath, schemaPaths, skipLayout = false, format = 0 }) {
|
|
645
|
+
await this.init();
|
|
646
|
+
return this._instance.getEvaluatedSchemaByPathsSubformJS(subformPath, JSON.stringify(schemaPaths), skipLayout, format);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
/**
|
|
650
|
+
* Get list of available subform paths
|
|
651
|
+
* @returns {Promise<Array<string>>}
|
|
652
|
+
*/
|
|
653
|
+
async getSubformPaths() {
|
|
654
|
+
await this.init();
|
|
655
|
+
return this._instance.getSubformPaths();
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
/**
|
|
659
|
+
* Get schema by specific path from subform
|
|
660
|
+
* @param {object} options
|
|
661
|
+
* @param {string} options.subformPath - Path to the subform
|
|
662
|
+
* @param {string} options.schemaPath - Path within the subform
|
|
663
|
+
* @returns {Promise<any|null>}
|
|
664
|
+
*/
|
|
665
|
+
async getSchemaByPathSubform({ subformPath, schemaPath }) {
|
|
666
|
+
await this.init();
|
|
667
|
+
return this._instance.getSchemaByPathSubformJS(subformPath, schemaPath);
|
|
668
|
+
}
|
|
669
|
+
|
|
670
|
+
/**
|
|
671
|
+
* Get schema by multiple paths from subform
|
|
672
|
+
* Returns data in the specified format (skips paths that are not found)
|
|
673
|
+
* @param {object} options
|
|
674
|
+
* @param {string} options.subformPath - Path to the subform
|
|
675
|
+
* @param {string[]} options.schemaPaths - Array of paths within the subform
|
|
676
|
+
* @param {number} [options.format=0] - Return format (0=Nested, 1=Flat, 2=Array)
|
|
677
|
+
* @returns {Promise<any>}
|
|
678
|
+
*/
|
|
679
|
+
async getSchemaByPathsSubform({ subformPath, schemaPaths, format = 0 }) {
|
|
680
|
+
await this.init();
|
|
681
|
+
return this._instance.getSchemaByPathsSubformJS(subformPath, JSON.stringify(schemaPaths), format);
|
|
682
|
+
}
|
|
683
|
+
|
|
684
|
+
/**
|
|
685
|
+
* Check if a subform exists at the given path
|
|
686
|
+
* @param {string} subformPath - Path to check
|
|
687
|
+
* @returns {Promise<boolean>}
|
|
688
|
+
*/
|
|
689
|
+
async hasSubform(subformPath) {
|
|
690
|
+
await this.init();
|
|
691
|
+
return this._instance.hasSubform(subformPath);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
/**
|
|
695
|
+
* Free WASM resources
|
|
696
|
+
*/
|
|
697
|
+
free() {
|
|
698
|
+
if (this._instance) {
|
|
699
|
+
this._instance.free();
|
|
700
|
+
this._instance = null;
|
|
701
|
+
this._ready = false;
|
|
702
|
+
}
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* Get library version (internal - use from specific packages)
|
|
708
|
+
* @param {any} wasmModule - WASM module
|
|
709
|
+
* @returns {string}
|
|
710
|
+
*/
|
|
711
|
+
export function getVersion(wasmModule) {
|
|
712
|
+
return wasmModule.version();
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
export default JSONEvalCore;
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@json-eval-rs/webcore",
|
|
3
|
+
"version": "0.0.29",
|
|
4
|
+
"description": "JSON Eval RS core JavaScript wrapper (internal package - not published)",
|
|
5
|
+
"main": "index.js",
|
|
6
|
+
"types": "index.d.ts",
|
|
7
|
+
"type": "module",
|
|
8
|
+
"files": [
|
|
9
|
+
"index.js",
|
|
10
|
+
"index.d.ts"
|
|
11
|
+
],
|
|
12
|
+
"keywords": [
|
|
13
|
+
"json",
|
|
14
|
+
"json-logic",
|
|
15
|
+
"schema",
|
|
16
|
+
"validation",
|
|
17
|
+
"wasm"
|
|
18
|
+
],
|
|
19
|
+
"author": "Muhamad Rizki",
|
|
20
|
+
"license": "MIT",
|
|
21
|
+
"repository": {
|
|
22
|
+
"type": "git",
|
|
23
|
+
"url": "https://github.com/byrizki/json-eval-rs.git",
|
|
24
|
+
"directory": "bindings/web/packages/core"
|
|
25
|
+
},
|
|
26
|
+
"sideEffects": false
|
|
27
|
+
}
|