@narrative.io/jsonforms-provider-protocols 2.11.0 → 3.0.0-beta.10

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.
Files changed (110) hide show
  1. package/README.md +101 -29
  2. package/dist/core/initFormData.d.ts +10 -0
  3. package/dist/core/initFormData.d.ts.map +1 -0
  4. package/dist/core/initFormData.js +99 -0
  5. package/dist/core/initFormData.js.map +1 -0
  6. package/dist/core/projection.d.ts +32 -0
  7. package/dist/core/projection.d.ts.map +1 -0
  8. package/dist/core/projection.js +74 -0
  9. package/dist/core/projection.js.map +1 -0
  10. package/dist/core/resolveScope.d.ts +11 -0
  11. package/dist/core/resolveScope.d.ts.map +1 -0
  12. package/dist/core/resolveScope.js +22 -0
  13. package/dist/core/resolveScope.js.map +1 -0
  14. package/dist/core/transforms.d.ts +8 -10
  15. package/dist/core/transforms.d.ts.map +1 -1
  16. package/dist/core/transforms.js +58 -13
  17. package/dist/core/transforms.js.map +1 -1
  18. package/dist/core/types.d.ts +8 -0
  19. package/dist/core/types.d.ts.map +1 -1
  20. package/dist/index.d.ts +5 -1
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +14 -3
  23. package/dist/index.js.map +1 -1
  24. package/dist/jsonforms-provider-protocols.css +2 -2
  25. package/dist/vue/components/ProviderAutocomplete.vue.d.ts.map +1 -1
  26. package/dist/vue/components/ProviderAutocomplete.vue.js +10 -5
  27. package/dist/vue/components/ProviderAutocomplete.vue.js.map +1 -1
  28. package/dist/vue/components/ProviderMultiSelect.vue.d.ts.map +1 -1
  29. package/dist/vue/components/ProviderMultiSelect.vue.js +1 -1
  30. package/dist/vue/components/ProviderMultiSelect.vue2.js +12 -7
  31. package/dist/vue/components/ProviderMultiSelect.vue2.js.map +1 -1
  32. package/dist/vue/components/ProviderSelect.vue.d.ts.map +1 -1
  33. package/dist/vue/components/ProviderSelect.vue.js +1 -1
  34. package/dist/vue/components/ProviderSelect.vue2.js +13 -6
  35. package/dist/vue/components/ProviderSelect.vue2.js.map +1 -1
  36. package/dist/vue/composables/useDataLayer.d.ts +10 -0
  37. package/dist/vue/composables/useDataLayer.d.ts.map +1 -0
  38. package/dist/vue/composables/useDataLayer.js +26 -0
  39. package/dist/vue/composables/useDataLayer.js.map +1 -0
  40. package/dist/vue/composables/useDerive.d.ts +5 -2
  41. package/dist/vue/composables/useDerive.d.ts.map +1 -1
  42. package/dist/vue/composables/useDerive.js +29 -12
  43. package/dist/vue/composables/useDerive.js.map +1 -1
  44. package/dist/vue/composables/useDeriveInitialValue.d.ts +36 -0
  45. package/dist/vue/composables/useDeriveInitialValue.d.ts.map +1 -0
  46. package/dist/vue/composables/useDeriveInitialValue.js +125 -0
  47. package/dist/vue/composables/useDeriveInitialValue.js.map +1 -0
  48. package/dist/vue/composables/useDirtyValidation.d.ts +9 -0
  49. package/dist/vue/composables/useDirtyValidation.d.ts.map +1 -0
  50. package/dist/vue/composables/useDirtyValidation.js +15 -0
  51. package/dist/vue/composables/useDirtyValidation.js.map +1 -0
  52. package/dist/vue/composables/useProjection.d.ts +41 -0
  53. package/dist/vue/composables/useProjection.d.ts.map +1 -0
  54. package/dist/vue/composables/useProjection.js +84 -0
  55. package/dist/vue/composables/useProjection.js.map +1 -0
  56. package/dist/vue/index.d.ts +7 -0
  57. package/dist/vue/index.d.ts.map +1 -1
  58. package/dist/vue/index.js +35 -27
  59. package/dist/vue/index.js.map +1 -1
  60. package/dist/vue/primevue/JfBoolean.vue.d.ts +9 -0
  61. package/dist/vue/primevue/JfBoolean.vue.d.ts.map +1 -1
  62. package/dist/vue/primevue/JfBoolean.vue.js +35 -13
  63. package/dist/vue/primevue/JfBoolean.vue.js.map +1 -1
  64. package/dist/vue/primevue/JfEnum.vue.d.ts +9 -0
  65. package/dist/vue/primevue/JfEnum.vue.d.ts.map +1 -1
  66. package/dist/vue/primevue/JfEnum.vue.js +31 -22
  67. package/dist/vue/primevue/JfEnum.vue.js.map +1 -1
  68. package/dist/vue/primevue/JfEnumArray.vue.d.ts +9 -0
  69. package/dist/vue/primevue/JfEnumArray.vue.d.ts.map +1 -1
  70. package/dist/vue/primevue/JfEnumArray.vue.js +33 -18
  71. package/dist/vue/primevue/JfEnumArray.vue.js.map +1 -1
  72. package/dist/vue/primevue/JfNumber.vue.d.ts +9 -0
  73. package/dist/vue/primevue/JfNumber.vue.d.ts.map +1 -1
  74. package/dist/vue/primevue/JfNumber.vue.js +31 -22
  75. package/dist/vue/primevue/JfNumber.vue.js.map +1 -1
  76. package/dist/vue/primevue/JfText.vue.d.ts +9 -0
  77. package/dist/vue/primevue/JfText.vue.d.ts.map +1 -1
  78. package/dist/vue/primevue/JfText.vue.js +40 -32
  79. package/dist/vue/primevue/JfText.vue.js.map +1 -1
  80. package/dist/vue/primevue/JfTextArea.vue.d.ts +9 -0
  81. package/dist/vue/primevue/JfTextArea.vue.d.ts.map +1 -1
  82. package/dist/vue/primevue/JfTextArea.vue.js +32 -18
  83. package/dist/vue/primevue/JfTextArea.vue.js.map +1 -1
  84. package/dist/vue/primevue/index.d.ts.map +1 -1
  85. package/dist/vue/primevue/index.js +100 -8
  86. package/dist/vue/primevue/index.js.map +1 -1
  87. package/package.json +3 -1
  88. package/src/core/initFormData.ts +189 -0
  89. package/src/core/projection.ts +136 -0
  90. package/src/core/resolveScope.ts +39 -0
  91. package/src/core/transforms.ts +118 -26
  92. package/src/core/types.ts +9 -0
  93. package/src/index.ts +7 -1
  94. package/src/vue/components/ProviderAutocomplete.vue +10 -5
  95. package/src/vue/components/ProviderMultiSelect.vue +14 -7
  96. package/src/vue/components/ProviderSelect.vue +15 -6
  97. package/src/vue/composables/useDataLayer.ts +43 -0
  98. package/src/vue/composables/useDerive.ts +62 -16
  99. package/src/vue/composables/useDeriveInitialValue.ts +195 -0
  100. package/src/vue/composables/useDirtyValidation.ts +20 -0
  101. package/src/vue/composables/useProjection.ts +181 -0
  102. package/src/vue/index.ts +35 -41
  103. package/src/vue/primevue/JfBoolean.vue +25 -7
  104. package/src/vue/primevue/JfEnum.vue +29 -22
  105. package/src/vue/primevue/JfEnumArray.vue +31 -16
  106. package/src/vue/primevue/JfNumber.vue +29 -22
  107. package/src/vue/primevue/JfText.vue +34 -27
  108. package/src/vue/primevue/JfTextArea.vue +29 -17
  109. package/src/vue/primevue/index.ts +114 -8
  110. package/src/vue/styles.css +26 -1
package/README.md CHANGED
@@ -190,7 +190,9 @@ Recursively flattens nested tree structures into a single-level array:
190
190
  - Adds `_depth`, `_parent`, and `_formattedLabel` metadata to items
191
191
 
192
192
  **Filter Transform**
193
- Filters items based on property values:
193
+ Filters items based on conditions. Supports a simple single-key syntax and a multi-condition syntax with operators.
194
+
195
+ Simple syntax (single key/values):
194
196
 
195
197
  ```json
196
198
  {
@@ -200,8 +202,31 @@ Filters items based on property values:
200
202
  }
201
203
  ```
202
204
 
203
- - `key`: The property to check
204
- - `values` (optional): Array of values to match. If omitted, filters by key existence
205
+ Multi-condition syntax (AND logic):
206
+
207
+ ```json
208
+ {
209
+ "name": "filter",
210
+ "conditions": [
211
+ { "key": "status", "values": ["active"] },
212
+ { "key": "connections", "operator": "empty" }
213
+ ]
214
+ }
215
+ ```
216
+
217
+ Available operators:
218
+
219
+ | Operator | Description |
220
+ |----------|-------------|
221
+ | `eq` | Value matches one of `values` (default) |
222
+ | `neq` | Value does NOT match any of `values` |
223
+ | `empty` | Value is null, undefined, empty array, or empty string |
224
+ | `notEmpty` | Inverse of `empty` |
225
+ | `gt` | Value > `values[0]` |
226
+ | `gte` | Value >= `values[0]` |
227
+ | `lt` | Value < `values[0]` |
228
+ | `lte` | Value <= `values[0]` |
229
+ | `contains` | String includes substring, or array includes value |
205
230
 
206
231
  **Combining Transforms**
207
232
  Transforms are applied sequentially in pipeline order:
@@ -215,20 +240,6 @@ Transforms are applied sequentially in pipeline order:
215
240
  }
216
241
  ```
217
242
 
218
- **Custom Transforms**
219
- Register custom transforms for your specific needs:
220
-
221
- ```typescript
222
- import { registerTransform } from '@narrative.io/jsonforms-provider-protocols'
223
-
224
- registerTransform('uppercase', (items, config) => {
225
- return items.map(item => ({
226
- ...item,
227
- name: item.name.toUpperCase()
228
- }))
229
- })
230
- ```
231
-
232
243
  ### Template Variables
233
244
  Create dynamic URLs using form data:
234
245
 
@@ -247,7 +258,7 @@ Control when data is fetched:
247
258
  - `query` - Load when user types (autocomplete)
248
259
 
249
260
  ### Derive Functionality
250
- Auto-populate fields from form data or external sources:
261
+ Auto-populate fields from form data or the dataLayer:
251
262
 
252
263
  ```json
253
264
  {
@@ -261,33 +272,56 @@ Auto-populate fields from form data or external sources:
261
272
  }
262
273
  ```
263
274
 
264
- #### External Data Support
265
- Access external data sources separate from form data using the `externalData()` syntax:
275
+ #### DataLayer Support
276
+ Inject external data into forms using the `createDataLayer` API and reference it with the `dataLayer()` derive syntax:
266
277
 
267
278
  ```vue
268
279
  <script setup>
269
- // Provide external data to the form
270
- const externalData = ref({
271
- user: { preferences: { theme: "dark" } },
272
- tree: { name: "Oak", type: "Deciduous" }
273
- })
280
+ import { createDataLayer } from '@narrative.io/jsonforms-provider-protocols'
274
281
 
275
- provide('externalData', externalData)
282
+ const dataLayer = createDataLayer()
283
+ dataLayer.push({ dataset_name: "My Dataset" })
284
+
285
+ // Merge additional data at any time
286
+ dataLayer.push({ dataset_id: 42 })
276
287
  </script>
277
288
  ```
278
289
 
279
290
  ```json
280
291
  {
281
- "type": "Control",
282
- "scope": "#/properties/tree_preference",
292
+ "type": "Control",
293
+ "scope": "#/properties/audience",
283
294
  "options": {
284
- "derive": "externalData(tree.name)",
295
+ "derive": "dataLayer(dataset_name)",
285
296
  "mode": "follow",
286
297
  "readonly": true
287
298
  }
288
299
  }
289
300
  ```
290
301
 
302
+ The `ConnectorDataLayer` type defines available properties:
303
+
304
+ ```typescript
305
+ interface ConnectorDataLayer {
306
+ dataset_name?: string
307
+ dataset_description?: string
308
+ dataset_id?: number
309
+ profile_id?: string
310
+ profile_name?: string
311
+ }
312
+ ```
313
+
314
+ You can also read the dataLayer state directly in components:
315
+
316
+ ```vue
317
+ <script setup>
318
+ import { useDataLayer } from '@narrative.io/jsonforms-provider-protocols'
319
+
320
+ const dataLayerState = useDataLayer()
321
+ // dataLayerState.value.dataset_name
322
+ </script>
323
+ ```
324
+
291
325
  ### Error Handling
292
326
  Control error display behavior with the `showError` property:
293
327
 
@@ -307,6 +341,44 @@ Control error display behavior with the `showError` property:
307
341
 
308
342
  When `showError` is `false`, failed requests return empty results instead of throwing errors. Defaults to `true`.
309
343
 
344
+ ### Projection
345
+ Render simple controls (text, number) against deeply nested or array-wrapped data structures using the `projection` UISchema option. The control sees a simple value, while the underlying form data maintains the full structure.
346
+
347
+ The projection path is **relative to the control's `scope`**. So when `scope` is `#/properties/data_rates` and the projection is `"0.video_rate_usd"`, it resolves to `data_rates[0].video_rate_usd` in the form data:
348
+
349
+ ```json
350
+ {
351
+ "type": "Control",
352
+ "scope": "#/properties/data_rates",
353
+ "options": {
354
+ "placeholder": "Enter video rate...",
355
+ "projection": "0.video_rate_usd"
356
+ }
357
+ }
358
+ ```
359
+
360
+ With form data `{ data_rates: [{ video_rate_usd: 2.5, display_rate_usd: 1.5 }] }`, the control renders `2.5` as a simple number input. When the user changes the value, only `video_rate_usd` is updated — all sibling properties are preserved.
361
+
362
+ **Path syntax:** Dot-separated segments (similar to Lodash `_.get`) where numeric segments are array indices and string segments are object keys.
363
+
364
+ | Projection Path | Data Shape | Control Sees |
365
+ |-----------------|-----------|-------------|
366
+ | `0` | `[123]` | `123` |
367
+ | `0.video_rate_usd` | `[{ video_rate_usd: 2.5 }]` | `2.5` |
368
+ | `include` | `{ include: ["a", "b"] }` | `["a", "b"]` |
369
+
370
+ The schema is also resolved through the projection path, so validation works correctly on the projected value.
371
+
372
+ Use `useProjection` directly in custom components:
373
+
374
+ ```vue
375
+ <script setup>
376
+ import { useProjection } from '@narrative.io/jsonforms-provider-protocols'
377
+
378
+ const { projectedData, projectedSchema, handleProjectedChange, hasProjection } = useProjection(control, handleChange)
379
+ </script>
380
+ ```
381
+
310
382
  ### Composables
311
383
  Use providers directly in your components:
312
384
 
@@ -0,0 +1,10 @@
1
+ /**
2
+ * Initialize a form data object from a JSON Schema.
3
+ * Resolves $ref, const, default, oneOf/discriminator, and typed empty values.
4
+ *
5
+ * @param schema - The full JSON Schema (must include $defs if $refs are used)
6
+ * @param seed - Optional existing data to merge (seed values take priority)
7
+ * @returns A data object with all schema-defined fields initialized
8
+ */
9
+ export declare function initFormDataFromSchema(schema: Record<string, unknown>, seed?: Record<string, unknown>): Record<string, unknown>;
10
+ //# sourceMappingURL=initFormData.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initFormData.d.ts","sourceRoot":"","sources":["../../src/core/initFormData.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,wBAAgB,sBAAsB,CACpC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC7B,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAyBzB"}
@@ -0,0 +1,99 @@
1
+ function initFormDataFromSchema(schema, seed) {
2
+ const result = initProperty(schema, schema, seed);
3
+ if (result && typeof result === "object" && !Array.isArray(result) && seed && typeof seed === "object") {
4
+ const schemaKeys = new Set(
5
+ Object.keys(
6
+ resolveRef(schema, schema)?.properties ?? {}
7
+ )
8
+ );
9
+ for (const key of Object.keys(seed)) {
10
+ if (!schemaKeys.has(key) && !(key in result)) {
11
+ result[key] = seed[key];
12
+ }
13
+ }
14
+ }
15
+ return result ?? {};
16
+ }
17
+ function resolveRef(property, root, seen) {
18
+ if (!property || typeof property !== "object") return property;
19
+ const ref = property.$ref;
20
+ if (!ref) return property;
21
+ const visited = seen ?? /* @__PURE__ */ new Set();
22
+ if (visited.has(ref)) return property;
23
+ visited.add(ref);
24
+ const resolved = resolvePointer(root, ref);
25
+ if (!resolved) return property;
26
+ return resolveRef(resolved, root, visited);
27
+ }
28
+ function resolvePointer(obj, pointer) {
29
+ if (!pointer.startsWith("#/")) return void 0;
30
+ const parts = pointer.slice(2).split("/");
31
+ let current = obj;
32
+ for (const part of parts) {
33
+ if (current && typeof current === "object" && part in current) {
34
+ current = current[part];
35
+ } else {
36
+ return void 0;
37
+ }
38
+ }
39
+ return current;
40
+ }
41
+ function initProperty(property, root, seed) {
42
+ if (!property || typeof property !== "object") return null;
43
+ const resolved = resolveRef(property, root);
44
+ if (Array.isArray(resolved.oneOf)) {
45
+ return initOneOf(resolved, root, seed);
46
+ }
47
+ const type = resolved.type;
48
+ if (seed !== void 0 && seed !== null && type !== "object") {
49
+ return seed;
50
+ }
51
+ if ("const" in resolved) {
52
+ return resolved.const;
53
+ }
54
+ if (Array.isArray(resolved.enum) && resolved.enum.length === 1) {
55
+ return resolved.enum[0];
56
+ }
57
+ if ("default" in resolved) {
58
+ return resolved.default;
59
+ }
60
+ switch (type) {
61
+ case "object":
62
+ return initObject(resolved, root, seed);
63
+ case "array":
64
+ return seed !== void 0 && seed !== null ? seed : [];
65
+ case "string":
66
+ return "";
67
+ case "boolean":
68
+ return false;
69
+ case "number":
70
+ case "integer":
71
+ return null;
72
+ default:
73
+ return null;
74
+ }
75
+ }
76
+ function initObject(schema, root, seed) {
77
+ const properties = schema.properties;
78
+ if (!properties) {
79
+ return seed && typeof seed === "object" ? { ...seed } : {};
80
+ }
81
+ const result = {};
82
+ for (const [key, propSchema] of Object.entries(properties)) {
83
+ const seedValue = seed && typeof seed === "object" ? seed[key] : void 0;
84
+ result[key] = initProperty(propSchema, root, seedValue);
85
+ }
86
+ return result;
87
+ }
88
+ function initOneOf(schema, root, seed) {
89
+ const variants = schema.oneOf;
90
+ if (!variants || variants.length === 0) return null;
91
+ const first = variants[0];
92
+ if (!first) return null;
93
+ const firstVariant = resolveRef(first, root);
94
+ return initProperty(firstVariant, root, seed);
95
+ }
96
+ export {
97
+ initFormDataFromSchema
98
+ };
99
+ //# sourceMappingURL=initFormData.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"initFormData.js","sources":["../../src/core/initFormData.ts"],"sourcesContent":["/**\n * Initialize a form data object from a JSON Schema.\n * Resolves $ref, const, default, oneOf/discriminator, and typed empty values.\n *\n * @param schema - The full JSON Schema (must include $defs if $refs are used)\n * @param seed - Optional existing data to merge (seed values take priority)\n * @returns A data object with all schema-defined fields initialized\n */\nexport function initFormDataFromSchema(\n schema: Record<string, unknown>,\n seed?: Record<string, unknown>,\n): Record<string, unknown> {\n const result = initProperty(schema, schema, seed) as Record<string, unknown>;\n\n // If result is an object and seed has extra keys not in schema, preserve them\n if (\n result &&\n typeof result === \"object\" &&\n !Array.isArray(result) &&\n seed &&\n typeof seed === \"object\"\n ) {\n const schemaKeys = new Set(\n Object.keys(\n (resolveRef(schema, schema) as Record<string, unknown>)?.properties ??\n {},\n ),\n );\n for (const key of Object.keys(seed)) {\n if (!schemaKeys.has(key) && !(key in result)) {\n result[key] = seed[key];\n }\n }\n }\n\n return result ?? {};\n}\n\n/**\n * Resolve a $ref pointer against the root schema's $defs.\n * Supports nested $ref chains.\n */\nfunction resolveRef(\n property: Record<string, unknown>,\n root: Record<string, unknown>,\n seen?: Set<string>,\n): Record<string, unknown> {\n if (!property || typeof property !== \"object\") return property;\n\n const ref = property.$ref as string | undefined;\n if (!ref) return property;\n\n // Guard against circular refs\n const visited = seen ?? new Set<string>();\n if (visited.has(ref)) return property;\n visited.add(ref);\n\n const resolved = resolvePointer(root, ref);\n if (!resolved) return property;\n\n // Continue resolving if the result itself has a $ref\n return resolveRef(resolved as Record<string, unknown>, root, visited);\n}\n\n/**\n * Resolve a JSON pointer like \"#/$defs/Price\" against an object.\n */\nfunction resolvePointer(\n obj: Record<string, unknown>,\n pointer: string,\n): unknown {\n if (!pointer.startsWith(\"#/\")) return undefined;\n const parts = pointer.slice(2).split(\"/\");\n let current: unknown = obj;\n for (const part of parts) {\n if (current && typeof current === \"object\" && part in current) {\n current = (current as Record<string, unknown>)[part];\n } else {\n return undefined;\n }\n }\n return current;\n}\n\n/**\n * Initialize a single property value based on its schema definition.\n */\nfunction initProperty(\n property: Record<string, unknown>,\n root: Record<string, unknown>,\n seed?: unknown,\n): unknown {\n if (!property || typeof property !== \"object\") return null;\n\n // Resolve $ref first\n const resolved = resolveRef(property, root);\n\n // Handle oneOf with discriminator — pick first variant\n if (Array.isArray(resolved.oneOf)) {\n return initOneOf(resolved, root, seed);\n }\n\n // Priority 1: seed wins (for object types, we merge recursively below)\n // For non-object types, return seed directly if present\n const type = resolved.type as string | undefined;\n if (seed !== undefined && seed !== null && type !== \"object\") {\n return seed;\n }\n\n // Priority 2: const\n if (\"const\" in resolved) {\n return resolved.const;\n }\n\n // Priority 3: single-value enum\n if (\n Array.isArray(resolved.enum) &&\n (resolved.enum as unknown[]).length === 1\n ) {\n return (resolved.enum as unknown[])[0];\n }\n\n // Priority 4: default\n if (\"default\" in resolved) {\n return resolved.default;\n }\n\n // Priority 5: typed empty values\n switch (type) {\n case \"object\":\n return initObject(resolved, root, seed as Record<string, unknown>);\n case \"array\":\n return seed !== undefined && seed !== null ? seed : [];\n case \"string\":\n return \"\";\n case \"boolean\":\n return false;\n case \"number\":\n case \"integer\":\n return null;\n default:\n return null;\n }\n}\n\n/**\n * Initialize an object type by recursing into its properties.\n */\nfunction initObject(\n schema: Record<string, unknown>,\n root: Record<string, unknown>,\n seed?: Record<string, unknown>,\n): Record<string, unknown> {\n const properties = schema.properties as\n | Record<string, Record<string, unknown>>\n | undefined;\n if (!properties) {\n // Object with no defined properties — return seed or empty object\n return seed && typeof seed === \"object\" ? { ...seed } : {};\n }\n\n const result: Record<string, unknown> = {};\n\n for (const [key, propSchema] of Object.entries(properties)) {\n const seedValue = seed && typeof seed === \"object\" ? seed[key] : undefined;\n result[key] = initProperty(propSchema, root, seedValue);\n }\n\n return result;\n}\n\n/**\n * Handle oneOf schemas — pick the first variant and initialize it.\n */\nfunction initOneOf(\n schema: Record<string, unknown>,\n root: Record<string, unknown>,\n seed?: unknown,\n): unknown {\n const variants = schema.oneOf as Record<string, unknown>[];\n if (!variants || variants.length === 0) return null;\n\n const first = variants[0];\n if (!first) return null;\n\n // Pick first variant, resolve its $ref if needed\n const firstVariant = resolveRef(first, root);\n return initProperty(firstVariant, root, seed);\n}\n"],"names":[],"mappings":"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"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * Projection utilities for navigating complex data structures
3
+ * through a dot-separated path where numeric segments are array indices.
4
+ *
5
+ * Examples:
6
+ * "0" → first element of an array
7
+ * "include" → the `include` property of an object
8
+ * "0.video_rate_usd" → nested property inside the first array element
9
+ */
10
+ export type ProjectionSegment = string | number;
11
+ /**
12
+ * Parse a projection path string into typed segments.
13
+ * Numeric strings become numbers (array indices), others stay as strings (object keys).
14
+ */
15
+ export declare function parseProjectionPath(path: string): ProjectionSegment[];
16
+ /**
17
+ * Read a value from `data` by following the projection path.
18
+ * Returns `undefined` if any segment along the path is missing.
19
+ */
20
+ export declare function getProjectedValue(data: unknown, path: string): unknown;
21
+ /**
22
+ * Immutably set a value at the projection path, preserving all sibling data.
23
+ * Constructs missing intermediate structures (arrays for numeric segments, objects for string segments).
24
+ */
25
+ export declare function setProjectedValue(data: unknown, path: string, value: unknown): unknown;
26
+ /**
27
+ * Resolve the schema at the projected path.
28
+ * Numeric segments traverse into `items` (array item schema).
29
+ * String segments traverse into `properties[segment]`.
30
+ */
31
+ export declare function getProjectedSchema(schema: Record<string, any>, path: string): Record<string, any>;
32
+ //# sourceMappingURL=projection.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection.d.ts","sourceRoot":"","sources":["../../src/core/projection.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,MAAM,iBAAiB,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhD;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,GAAG,iBAAiB,EAAE,CAMrE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAiBtE;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,OAAO,CAGT;AAqCD;;;;GAIG;AACH,wBAAgB,kBAAkB,CAEhC,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC3B,IAAI,EAAE,MAAM,GAEX,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CA8BrB"}
@@ -0,0 +1,74 @@
1
+ function parseProjectionPath(path) {
2
+ if (!path) return [];
3
+ return path.split(".").map((s) => {
4
+ const n = Number(s);
5
+ return Number.isInteger(n) && n >= 0 ? n : s;
6
+ });
7
+ }
8
+ function getProjectedValue(data, path) {
9
+ const segments = parseProjectionPath(path);
10
+ let current = data;
11
+ for (const seg of segments) {
12
+ if (current === null || current === void 0) return void 0;
13
+ if (typeof seg === "number") {
14
+ if (!Array.isArray(current)) return void 0;
15
+ current = current[seg];
16
+ } else {
17
+ if (typeof current !== "object") return void 0;
18
+ current = current[seg];
19
+ }
20
+ }
21
+ return current;
22
+ }
23
+ function setProjectedValue(data, path, value) {
24
+ const segments = parseProjectionPath(path);
25
+ return setAtPath(data, segments, 0, value);
26
+ }
27
+ function setAtPath(current, segments, index, value) {
28
+ if (index === segments.length) {
29
+ return value;
30
+ }
31
+ const seg = segments[index];
32
+ if (typeof seg === "number") {
33
+ const arr = Array.isArray(current) ? [...current] : [];
34
+ while (arr.length <= seg) {
35
+ arr.push(void 0);
36
+ }
37
+ arr[seg] = setAtPath(arr[seg], segments, index + 1, value);
38
+ return arr;
39
+ } else {
40
+ const obj = current !== null && current !== void 0 && typeof current === "object" && !Array.isArray(current) ? { ...current } : {};
41
+ obj[seg] = setAtPath(obj[seg], segments, index + 1, value);
42
+ return obj;
43
+ }
44
+ }
45
+ function getProjectedSchema(schema, path) {
46
+ const segments = parseProjectionPath(path);
47
+ let current = schema;
48
+ for (const seg of segments) {
49
+ if (!current) return {};
50
+ if (typeof seg === "number") {
51
+ const items = current.items;
52
+ if (items && typeof items === "object") {
53
+ current = items;
54
+ } else {
55
+ return {};
56
+ }
57
+ } else {
58
+ const properties = current.properties;
59
+ if (properties && properties[seg]) {
60
+ current = properties[seg];
61
+ } else {
62
+ return {};
63
+ }
64
+ }
65
+ }
66
+ return current;
67
+ }
68
+ export {
69
+ getProjectedSchema,
70
+ getProjectedValue,
71
+ parseProjectionPath,
72
+ setProjectedValue
73
+ };
74
+ //# sourceMappingURL=projection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"projection.js","sources":["../../src/core/projection.ts"],"sourcesContent":["/**\n * Projection utilities for navigating complex data structures\n * through a dot-separated path where numeric segments are array indices.\n *\n * Examples:\n * \"0\" → first element of an array\n * \"include\" → the `include` property of an object\n * \"0.video_rate_usd\" → nested property inside the first array element\n */\n\nexport type ProjectionSegment = string | number;\n\n/**\n * Parse a projection path string into typed segments.\n * Numeric strings become numbers (array indices), others stay as strings (object keys).\n */\nexport function parseProjectionPath(path: string): ProjectionSegment[] {\n if (!path) return [];\n return path.split(\".\").map((s) => {\n const n = Number(s);\n return Number.isInteger(n) && n >= 0 ? n : s;\n });\n}\n\n/**\n * Read a value from `data` by following the projection path.\n * Returns `undefined` if any segment along the path is missing.\n */\nexport function getProjectedValue(data: unknown, path: string): unknown {\n const segments = parseProjectionPath(path);\n let current: unknown = data;\n\n for (const seg of segments) {\n if (current === null || current === undefined) return undefined;\n\n if (typeof seg === \"number\") {\n if (!Array.isArray(current)) return undefined;\n current = current[seg];\n } else {\n if (typeof current !== \"object\") return undefined;\n current = (current as Record<string, unknown>)[seg];\n }\n }\n\n return current;\n}\n\n/**\n * Immutably set a value at the projection path, preserving all sibling data.\n * Constructs missing intermediate structures (arrays for numeric segments, objects for string segments).\n */\nexport function setProjectedValue(\n data: unknown,\n path: string,\n value: unknown,\n): unknown {\n const segments = parseProjectionPath(path);\n return setAtPath(data, segments, 0, value);\n}\n\nfunction setAtPath(\n current: unknown,\n segments: ProjectionSegment[],\n index: number,\n value: unknown,\n): unknown {\n if (index === segments.length) {\n return value;\n }\n\n const seg = segments[index]!;\n\n if (typeof seg === \"number\") {\n // Array index — ensure we have an array\n const arr = Array.isArray(current) ? [...current] : [];\n // Pad array if index is out of bounds\n while (arr.length <= seg) {\n arr.push(undefined);\n }\n arr[seg] = setAtPath(arr[seg], segments, index + 1, value);\n return arr;\n } else {\n // Object key — ensure we have an object\n const obj: Record<string, unknown> =\n current !== null &&\n current !== undefined &&\n typeof current === \"object\" &&\n !Array.isArray(current)\n ? { ...(current as Record<string, unknown>) }\n : {};\n obj[seg] = setAtPath(obj[seg], segments, index + 1, value);\n return obj;\n }\n}\n\n/**\n * Resolve the schema at the projected path.\n * Numeric segments traverse into `items` (array item schema).\n * String segments traverse into `properties[segment]`.\n */\nexport function getProjectedSchema(\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n schema: Record<string, any>,\n path: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Record<string, any> {\n const segments = parseProjectionPath(path);\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: Record<string, any> = schema;\n\n for (const seg of segments) {\n if (!current) return {};\n\n if (typeof seg === \"number\") {\n // Array index → traverse into items schema\n const items = current.items;\n if (items && typeof items === \"object\") {\n current = items as Record<string, unknown>;\n } else {\n return {};\n }\n } else {\n // Object key → traverse into properties[key]\n const properties = current.properties as\n | Record<string, Record<string, unknown>>\n | undefined;\n if (properties && properties[seg]) {\n current = properties[seg];\n } else {\n return {};\n }\n }\n }\n\n return current;\n}\n"],"names":[],"mappings":"AAgBO,SAAS,oBAAoB,MAAmC;AACrE,MAAI,CAAC,KAAM,QAAO,CAAA;AAClB,SAAO,KAAK,MAAM,GAAG,EAAE,IAAI,CAAC,MAAM;AAChC,UAAM,IAAI,OAAO,CAAC;AAClB,WAAO,OAAO,UAAU,CAAC,KAAK,KAAK,IAAI,IAAI;AAAA,EAC7C,CAAC;AACH;AAMO,SAAS,kBAAkB,MAAe,MAAuB;AACtE,QAAM,WAAW,oBAAoB,IAAI;AACzC,MAAI,UAAmB;AAEvB,aAAW,OAAO,UAAU;AAC1B,QAAI,YAAY,QAAQ,YAAY,OAAW,QAAO;AAEtD,QAAI,OAAO,QAAQ,UAAU;AAC3B,UAAI,CAAC,MAAM,QAAQ,OAAO,EAAG,QAAO;AACpC,gBAAU,QAAQ,GAAG;AAAA,IACvB,OAAO;AACL,UAAI,OAAO,YAAY,SAAU,QAAO;AACxC,gBAAW,QAAoC,GAAG;AAAA,IACpD;AAAA,EACF;AAEA,SAAO;AACT;AAMO,SAAS,kBACd,MACA,MACA,OACS;AACT,QAAM,WAAW,oBAAoB,IAAI;AACzC,SAAO,UAAU,MAAM,UAAU,GAAG,KAAK;AAC3C;AAEA,SAAS,UACP,SACA,UACA,OACA,OACS;AACT,MAAI,UAAU,SAAS,QAAQ;AAC7B,WAAO;AAAA,EACT;AAEA,QAAM,MAAM,SAAS,KAAK;AAE1B,MAAI,OAAO,QAAQ,UAAU;AAE3B,UAAM,MAAM,MAAM,QAAQ,OAAO,IAAI,CAAC,GAAG,OAAO,IAAI,CAAA;AAEpD,WAAO,IAAI,UAAU,KAAK;AACxB,UAAI,KAAK,MAAS;AAAA,IACpB;AACA,QAAI,GAAG,IAAI,UAAU,IAAI,GAAG,GAAG,UAAU,QAAQ,GAAG,KAAK;AACzD,WAAO;AAAA,EACT,OAAO;AAEL,UAAM,MACJ,YAAY,QACZ,YAAY,UACZ,OAAO,YAAY,YACnB,CAAC,MAAM,QAAQ,OAAO,IAClB,EAAE,GAAI,QAAA,IACN,CAAA;AACN,QAAI,GAAG,IAAI,UAAU,IAAI,GAAG,GAAG,UAAU,QAAQ,GAAG,KAAK;AACzD,WAAO;AAAA,EACT;AACF;AAOO,SAAS,mBAEd,QACA,MAEqB;AACrB,QAAM,WAAW,oBAAoB,IAAI;AAEzC,MAAI,UAA+B;AAEnC,aAAW,OAAO,UAAU;AAC1B,QAAI,CAAC,QAAS,QAAO,CAAA;AAErB,QAAI,OAAO,QAAQ,UAAU;AAE3B,YAAM,QAAQ,QAAQ;AACtB,UAAI,SAAS,OAAO,UAAU,UAAU;AACtC,kBAAU;AAAA,MACZ,OAAO;AACL,eAAO,CAAA;AAAA,MACT;AAAA,IACF,OAAO;AAEL,YAAM,aAAa,QAAQ;AAG3B,UAAI,cAAc,WAAW,GAAG,GAAG;AACjC,kBAAU,WAAW,GAAG;AAAA,MAC1B,OAAO;AACL,eAAO,CAAA;AAAA,MACT;AAAA,IACF;AAAA,EACF;AAEA,SAAO;AACT;"}
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Resolve a JSON Forms scope path to its schema within a root schema.
3
+ * Handles nested paths like "#/properties/parent/properties/child".
4
+ *
5
+ * Follows JSON Schema structure:
6
+ * - "properties" segments navigate into object `.properties`
7
+ * - "items" segments navigate into array `.items`
8
+ * - all other segments index directly into the current object
9
+ */
10
+ export declare function resolveScopeSchema(scope: string, rootSchema: Record<string, any>): Record<string, any> | undefined;
11
+ //# sourceMappingURL=resolveScope.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveScope.d.ts","sourceRoot":"","sources":["../../src/core/resolveScope.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,wBAAgB,kBAAkB,CAChC,KAAK,EAAE,MAAM,EAEb,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAE9B,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,SAAS,CAwBjC"}
@@ -0,0 +1,22 @@
1
+ function resolveScopeSchema(scope, rootSchema) {
2
+ if (!scope || !rootSchema) return void 0;
3
+ const path = scope.replace(/^#\/?/, "");
4
+ if (!path) return rootSchema;
5
+ const segments = path.split("/");
6
+ let current = rootSchema;
7
+ for (const segment of segments) {
8
+ if (!current || typeof current !== "object") return void 0;
9
+ if (segment === "properties") {
10
+ current = current.properties;
11
+ } else if (segment === "items") {
12
+ current = current.items;
13
+ } else {
14
+ current = current[segment];
15
+ }
16
+ }
17
+ return current;
18
+ }
19
+ export {
20
+ resolveScopeSchema
21
+ };
22
+ //# sourceMappingURL=resolveScope.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveScope.js","sources":["../../src/core/resolveScope.ts"],"sourcesContent":["/**\n * Resolve a JSON Forms scope path to its schema within a root schema.\n * Handles nested paths like \"#/properties/parent/properties/child\".\n *\n * Follows JSON Schema structure:\n * - \"properties\" segments navigate into object `.properties`\n * - \"items\" segments navigate into array `.items`\n * - all other segments index directly into the current object\n */\nexport function resolveScopeSchema(\n scope: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n rootSchema: Record<string, any>,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n): Record<string, any> | undefined {\n if (!scope || !rootSchema) return undefined;\n\n // Remove the leading \"#/\" and split into segments\n const path = scope.replace(/^#\\/?/, \"\");\n if (!path) return rootSchema;\n\n const segments = path.split(\"/\");\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n let current: any = rootSchema;\n\n for (const segment of segments) {\n if (!current || typeof current !== \"object\") return undefined;\n\n if (segment === \"properties\") {\n current = current.properties;\n } else if (segment === \"items\") {\n current = current.items;\n } else {\n current = current[segment];\n }\n }\n\n return current;\n}\n"],"names":[],"mappings":"AASO,SAAS,mBACd,OAEA,YAEiC;AACjC,MAAI,CAAC,SAAS,CAAC,WAAY,QAAO;AAGlC,QAAM,OAAO,MAAM,QAAQ,SAAS,EAAE;AACtC,MAAI,CAAC,KAAM,QAAO;AAElB,QAAM,WAAW,KAAK,MAAM,GAAG;AAE/B,MAAI,UAAe;AAEnB,aAAW,WAAW,UAAU;AAC9B,QAAI,CAAC,WAAW,OAAO,YAAY,SAAU,QAAO;AAEpD,QAAI,YAAY,cAAc;AAC5B,gBAAU,QAAQ;AAAA,IACpB,WAAW,YAAY,SAAS;AAC9B,gBAAU,QAAQ;AAAA,IACpB,OAAO;AACL,gBAAU,QAAQ,OAAO;AAAA,IAC3B;AAAA,EACF;AAEA,SAAO;AACT;"}
@@ -11,24 +11,22 @@ export interface FlattenTransform extends Transform {
11
11
  key: string;
12
12
  labelFormat?: string;
13
13
  }
14
+ export type FilterOperator = "eq" | "neq" | "empty" | "notEmpty" | "gt" | "gte" | "lt" | "lte" | "contains";
15
+ export interface FilterCondition {
16
+ key: string;
17
+ operator?: FilterOperator;
18
+ values?: unknown[];
19
+ }
14
20
  export interface FilterTransform extends Transform {
15
21
  name: "filter";
16
- key: string;
22
+ key?: string;
17
23
  values?: unknown[];
24
+ conditions?: FilterCondition[];
18
25
  }
19
26
  export type TransformStep = FlattenTransform | FilterTransform;
20
27
  export type TransformPipeline = TransformStep[];
21
- /**
22
- * Registry of transform functions
23
- */
24
- type TransformFunction = (items: unknown[], config: Transform) => unknown[];
25
- /**
26
- * Register a transform function
27
- */
28
- export declare function registerTransform(name: string, fn: TransformFunction): void;
29
28
  /**
30
29
  * Apply a pipeline of transforms to data
31
30
  */
32
31
  export declare function applyTransformPipeline(items: unknown[], pipeline: TransformPipeline): unknown[];
33
- export {};
34
32
  //# sourceMappingURL=transforms.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"transforms.d.ts","sourceRoot":"","sources":["../../src/core/transforms.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB;AAED,MAAM,MAAM,aAAa,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAE/D,MAAM,MAAM,iBAAiB,GAAG,aAAa,EAAE,CAAC;AAEhD;;GAEG;AACH,KAAK,iBAAiB,GAAG,CAAC,KAAK,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,SAAS,KAAK,OAAO,EAAE,CAAC;AAI5E;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,EAAE,iBAAiB,GAAG,IAAI,CAE3E;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,EAAE,EAChB,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,EAAE,CAYX"}
1
+ {"version":3,"file":"transforms.d.ts","sourceRoot":"","sources":["../../src/core/transforms.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,gBAAiB,SAAQ,SAAS;IACjD,IAAI,EAAE,SAAS,CAAC;IAChB,GAAG,EAAE,MAAM,CAAC;IACZ,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,MAAM,cAAc,GACtB,IAAI,GACJ,KAAK,GACL,OAAO,GACP,UAAU,GACV,IAAI,GACJ,KAAK,GACL,IAAI,GACJ,KAAK,GACL,UAAU,CAAC;AAEf,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;CACpB;AAED,MAAM,WAAW,eAAgB,SAAQ,SAAS;IAChD,IAAI,EAAE,QAAQ,CAAC;IACf,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,OAAO,EAAE,CAAC;IACnB,UAAU,CAAC,EAAE,eAAe,EAAE,CAAC;CAChC;AAED,MAAM,MAAM,aAAa,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAE/D,MAAM,MAAM,iBAAiB,GAAG,aAAa,EAAE,CAAC;AAMhD;;GAEG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,OAAO,EAAE,EAChB,QAAQ,EAAE,iBAAiB,GAC1B,OAAO,EAAE,CAYX"}
@@ -1,7 +1,4 @@
1
1
  const transformRegistry = {};
2
- function registerTransform(name, fn) {
3
- transformRegistry[name] = fn;
4
- }
5
2
  function applyTransformPipeline(items, pipeline) {
6
3
  let result = items;
7
4
  for (const transform of pipeline) {
@@ -59,23 +56,71 @@ function flattenTransform(items, config) {
59
56
  }
60
57
  return flattened;
61
58
  }
59
+ function isEmpty(value) {
60
+ if (value === null || value === void 0) return true;
61
+ if (Array.isArray(value)) return value.length === 0;
62
+ if (typeof value === "string") return value.length === 0;
63
+ return false;
64
+ }
65
+ function evaluateCondition(itemObj, condition) {
66
+ const value = itemObj[condition.key];
67
+ const operator = condition.operator ?? (condition.values ? "eq" : "eq");
68
+ switch (operator) {
69
+ case "eq":
70
+ if (!condition.values || condition.values.length === 0) {
71
+ return condition.key in itemObj;
72
+ }
73
+ return condition.values.includes(value);
74
+ case "neq":
75
+ if (!condition.values || condition.values.length === 0) {
76
+ return !(condition.key in itemObj);
77
+ }
78
+ return !condition.values.includes(value);
79
+ case "empty":
80
+ return isEmpty(value);
81
+ case "notEmpty":
82
+ return !isEmpty(value);
83
+ case "gt":
84
+ return typeof value === "number" && condition.values !== void 0 && value > condition.values[0];
85
+ case "gte":
86
+ return typeof value === "number" && condition.values !== void 0 && value >= condition.values[0];
87
+ case "lt":
88
+ return typeof value === "number" && condition.values !== void 0 && value < condition.values[0];
89
+ case "lte":
90
+ return typeof value === "number" && condition.values !== void 0 && value <= condition.values[0];
91
+ case "contains":
92
+ if (typeof value === "string" && condition.values) {
93
+ return condition.values.some((v) => value.includes(String(v)));
94
+ }
95
+ if (Array.isArray(value) && condition.values) {
96
+ return condition.values.some((v) => value.includes(v));
97
+ }
98
+ return false;
99
+ default:
100
+ return false;
101
+ }
102
+ }
62
103
  function filterTransform(items, config) {
63
104
  const filterConfig = config;
64
- const { key, values } = filterConfig;
105
+ let conditions;
106
+ if (filterConfig.conditions) {
107
+ conditions = filterConfig.conditions;
108
+ } else if (filterConfig.key) {
109
+ conditions = [{ key: filterConfig.key, values: filterConfig.values }];
110
+ } else {
111
+ return items;
112
+ }
65
113
  return items.filter((item) => {
66
114
  if (typeof item !== "object" || item === null) return false;
67
115
  const itemObj = item;
68
- if (!values || values.length === 0) {
69
- return key in itemObj;
70
- }
71
- const itemValue = itemObj[key];
72
- return values.includes(itemValue);
116
+ return conditions.every(
117
+ (condition) => evaluateCondition(itemObj, condition)
118
+ );
73
119
  });
74
120
  }
75
- registerTransform("flatten", flattenTransform);
76
- registerTransform("filter", filterTransform);
121
+ transformRegistry["flatten"] = flattenTransform;
122
+ transformRegistry["filter"] = filterTransform;
77
123
  export {
78
- applyTransformPipeline,
79
- registerTransform
124
+ applyTransformPipeline
80
125
  };
81
126
  //# sourceMappingURL=transforms.js.map