@narrative.io/jsonforms-provider-protocols 2.10.0 → 3.0.0-beta.1
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 +166 -30
- package/dist/core/projection.d.ts +32 -0
- package/dist/core/projection.d.ts.map +1 -0
- package/dist/core/projection.js +74 -0
- package/dist/core/projection.js.map +1 -0
- package/dist/core/resolveScope.d.ts +11 -0
- package/dist/core/resolveScope.d.ts.map +1 -0
- package/dist/core/resolveScope.js +22 -0
- package/dist/core/resolveScope.js.map +1 -0
- package/dist/core/transforms.d.ts +8 -10
- package/dist/core/transforms.d.ts.map +1 -1
- package/dist/core/transforms.js +56 -13
- package/dist/core/transforms.js.map +1 -1
- package/dist/core/types.d.ts +7 -0
- package/dist/core/types.d.ts.map +1 -1
- package/dist/index.d.ts +4 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +12 -2
- package/dist/index.js.map +1 -1
- package/dist/jsonforms-provider-protocols.css +2 -2
- package/dist/vue/components/ProviderAutocomplete.vue.d.ts.map +1 -1
- package/dist/vue/components/ProviderAutocomplete.vue.js +4 -2
- package/dist/vue/components/ProviderAutocomplete.vue.js.map +1 -1
- package/dist/vue/components/ProviderMultiSelect.vue.d.ts.map +1 -1
- package/dist/vue/components/ProviderMultiSelect.vue.js +1 -1
- package/dist/vue/components/ProviderMultiSelect.vue2.js +6 -4
- package/dist/vue/components/ProviderMultiSelect.vue2.js.map +1 -1
- package/dist/vue/components/ProviderSelect.vue.d.ts.map +1 -1
- package/dist/vue/components/ProviderSelect.vue.js +1 -1
- package/dist/vue/components/ProviderSelect.vue2.js +5 -3
- package/dist/vue/components/ProviderSelect.vue2.js.map +1 -1
- package/dist/vue/composables/useDataLayer.d.ts +9 -0
- package/dist/vue/composables/useDataLayer.d.ts.map +1 -0
- package/dist/vue/composables/useDataLayer.js +25 -0
- package/dist/vue/composables/useDataLayer.js.map +1 -0
- package/dist/vue/composables/useDerive.d.ts +5 -2
- package/dist/vue/composables/useDerive.d.ts.map +1 -1
- package/dist/vue/composables/useDerive.js +12 -12
- package/dist/vue/composables/useDerive.js.map +1 -1
- package/dist/vue/composables/useProjection.d.ts +35 -0
- package/dist/vue/composables/useProjection.d.ts.map +1 -0
- package/dist/vue/composables/useProjection.js +33 -0
- package/dist/vue/composables/useProjection.js.map +1 -0
- package/dist/vue/index.d.ts +4 -0
- package/dist/vue/index.d.ts.map +1 -1
- package/dist/vue/index.js +15 -29
- package/dist/vue/index.js.map +1 -1
- package/dist/vue/primevue/JfBoolean.vue.d.ts +9 -0
- package/dist/vue/primevue/JfBoolean.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfBoolean.vue.js +10 -5
- package/dist/vue/primevue/JfBoolean.vue.js.map +1 -1
- package/dist/vue/primevue/JfEnum.vue.d.ts +9 -0
- package/dist/vue/primevue/JfEnum.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfEnum.vue.js +12 -7
- package/dist/vue/primevue/JfEnum.vue.js.map +1 -1
- package/dist/vue/primevue/JfEnumArray.vue.d.ts +9 -0
- package/dist/vue/primevue/JfEnumArray.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfEnumArray.vue.js +13 -8
- package/dist/vue/primevue/JfEnumArray.vue.js.map +1 -1
- package/dist/vue/primevue/JfNumber.vue.d.ts +9 -0
- package/dist/vue/primevue/JfNumber.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfNumber.vue.js +11 -6
- package/dist/vue/primevue/JfNumber.vue.js.map +1 -1
- package/dist/vue/primevue/JfText.vue.d.ts +9 -0
- package/dist/vue/primevue/JfText.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfText.vue.js +13 -8
- package/dist/vue/primevue/JfText.vue.js.map +1 -1
- package/dist/vue/primevue/JfTextArea.vue.d.ts +9 -0
- package/dist/vue/primevue/JfTextArea.vue.d.ts.map +1 -1
- package/dist/vue/primevue/JfTextArea.vue.js +11 -6
- package/dist/vue/primevue/JfTextArea.vue.js.map +1 -1
- package/dist/vue/primevue/index.d.ts.map +1 -1
- package/dist/vue/primevue/index.js +22 -7
- package/dist/vue/primevue/index.js.map +1 -1
- package/package.json +7 -3
- package/src/core/projection.ts +136 -0
- package/src/core/resolveScope.ts +39 -0
- package/src/core/transforms.ts +91 -26
- package/src/core/types.ts +8 -0
- package/src/index.ts +7 -0
- package/src/vue/components/ProviderAutocomplete.vue +4 -2
- package/src/vue/components/ProviderMultiSelect.vue +6 -4
- package/src/vue/components/ProviderSelect.vue +5 -3
- package/src/vue/composables/useDataLayer.ts +43 -0
- package/src/vue/composables/useDerive.ts +19 -16
- package/src/vue/composables/useProjection.ts +74 -0
- package/src/vue/index.ts +20 -46
- package/src/vue/primevue/JfBoolean.vue +7 -2
- package/src/vue/primevue/JfEnum.vue +9 -4
- package/src/vue/primevue/JfEnumArray.vue +10 -5
- package/src/vue/primevue/JfNumber.vue +8 -3
- package/src/vue/primevue/JfText.vue +10 -5
- package/src/vue/primevue/JfTextArea.vue +8 -3
- package/src/vue/primevue/index.ts +32 -7
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
|
|
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
|
-
-
|
|
204
|
-
|
|
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
|
|
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
|
-
####
|
|
265
|
-
|
|
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
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
})
|
|
280
|
+
import { createDataLayer } from '@narrative.io/jsonforms-provider-protocols'
|
|
281
|
+
|
|
282
|
+
const dataLayer = createDataLayer()
|
|
283
|
+
dataLayer.push({ dataset_name: "My Dataset" })
|
|
274
284
|
|
|
275
|
-
|
|
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/
|
|
292
|
+
"type": "Control",
|
|
293
|
+
"scope": "#/properties/audience",
|
|
283
294
|
"options": {
|
|
284
|
-
"derive": "
|
|
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
|
|
|
@@ -327,11 +399,75 @@ bun install
|
|
|
327
399
|
# Run tests
|
|
328
400
|
bun test
|
|
329
401
|
|
|
330
|
-
# Build library
|
|
402
|
+
# Build library
|
|
331
403
|
bun run build
|
|
332
404
|
|
|
333
405
|
# Type checking
|
|
334
406
|
bunx vue-tsc --noEmit
|
|
407
|
+
|
|
408
|
+
# Watch mode for development
|
|
409
|
+
bun run dev
|
|
410
|
+
```
|
|
411
|
+
|
|
412
|
+
### Local Development with Consumer Apps
|
|
413
|
+
|
|
414
|
+
To test changes locally in a consumer application, use `bun link` to create a symlink:
|
|
415
|
+
|
|
416
|
+
**In this library:**
|
|
417
|
+
|
|
418
|
+
```bash
|
|
419
|
+
# Build and create a global link
|
|
420
|
+
bun run link:global
|
|
421
|
+
```
|
|
422
|
+
|
|
423
|
+
**In your consumer application:**
|
|
424
|
+
|
|
425
|
+
```bash
|
|
426
|
+
# Link to the local version
|
|
427
|
+
bun link @narrative.io/jsonforms-provider-protocols
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
Changes to the library will be reflected in the consumer app after rebuilding:
|
|
431
|
+
|
|
432
|
+
```bash
|
|
433
|
+
# In this library - rebuild after making changes
|
|
434
|
+
bun run build
|
|
435
|
+
|
|
436
|
+
# Or use watch mode for automatic rebuilds
|
|
437
|
+
bun run dev
|
|
438
|
+
```
|
|
439
|
+
|
|
440
|
+
**Verify the build succeeded:**
|
|
441
|
+
|
|
442
|
+
```bash
|
|
443
|
+
# Check that all dist files exist
|
|
444
|
+
bun run check:built
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
This runs `scripts/ensureBuild.js` to verify that all expected output files exist in the `dist/` directory before linking.
|
|
448
|
+
|
|
449
|
+
To unlink and use the published package again:
|
|
450
|
+
|
|
451
|
+
```bash
|
|
452
|
+
# In your consumer application - remove the symlink and reinstall from npm
|
|
453
|
+
rm -rf node_modules/@narrative.io/jsonforms-provider-protocols
|
|
454
|
+
bun install
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
> **Note:** `bun unlink {packageName}` is not yet implemented, so manual removal is required.
|
|
458
|
+
|
|
459
|
+
### Creating a .tgz Package
|
|
460
|
+
|
|
461
|
+
To create a distributable package for testing:
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
bun run pack:dist
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
This creates a `.tgz` file that can be installed in consumer apps via:
|
|
468
|
+
|
|
469
|
+
```bash
|
|
470
|
+
bun add ./path/to/narrative.io-jsonforms-provider-protocols-x.x.x.tgz
|
|
335
471
|
```
|
|
336
472
|
|
|
337
473
|
## 🤝 Contributing
|
|
@@ -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,CAC/B,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,MAAM,GACX,OAAO,CAiBT;AAED;;;GAGG;AACH,wBAAgB,iBAAiB,CAC/B,IAAI,EAAE,OAAO,EACb,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,OAAO,GACb,OAAO,CAGT;AAkCD;;;;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(\n data: unknown,\n path: string,\n): 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 && current !== undefined && typeof current === \"object\" && !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,kBACd,MACA,MACS;AACT,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,QAAQ,YAAY,UAAa,OAAO,YAAY,YAAY,CAAC,MAAM,QAAQ,OAAO,IAC9F,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
|
|
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,
|
|
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,GAAG,IAAI,GAAG,KAAK,GAAG,OAAO,GAAG,UAAU,GAAG,IAAI,GAAG,KAAK,GAAG,IAAI,GAAG,KAAK,GAAG,UAAU,CAAC;AAE5G,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"}
|
package/dist/core/transforms.js
CHANGED
|
@@ -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,69 @@ 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
|
-
|
|
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
|
-
|
|
69
|
-
return key in itemObj;
|
|
70
|
-
}
|
|
71
|
-
const itemValue = itemObj[key];
|
|
72
|
-
return values.includes(itemValue);
|
|
116
|
+
return conditions.every((condition) => evaluateCondition(itemObj, condition));
|
|
73
117
|
});
|
|
74
118
|
}
|
|
75
|
-
|
|
76
|
-
|
|
119
|
+
transformRegistry["flatten"] = flattenTransform;
|
|
120
|
+
transformRegistry["filter"] = filterTransform;
|
|
77
121
|
export {
|
|
78
|
-
applyTransformPipeline
|
|
79
|
-
registerTransform
|
|
122
|
+
applyTransformPipeline
|
|
80
123
|
};
|
|
81
124
|
//# sourceMappingURL=transforms.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"transforms.js","sources":["../../src/core/transforms.ts"],"sourcesContent":["/**\n * Transform pipeline system for manipulating API response data\n * Transforms are applied sequentially in the order they appear in the pipeline\n */\n\nexport interface Transform {\n name: string;\n [key: string]: unknown;\n}\n\nexport interface FlattenTransform extends Transform {\n name: \"flatten\";\n key: string; // The key containing the nested array to flatten\n labelFormat?: string; // Optional format string like \"{parent.name} → {name}\"\n}\n\nexport interface FilterTransform extends Transform {\n name: \"filter\";\n key
|
|
1
|
+
{"version":3,"file":"transforms.js","sources":["../../src/core/transforms.ts"],"sourcesContent":["/**\n * Transform pipeline system for manipulating API response data\n * Transforms are applied sequentially in the order they appear in the pipeline\n */\n\nexport interface Transform {\n name: string;\n [key: string]: unknown;\n}\n\nexport interface FlattenTransform extends Transform {\n name: \"flatten\";\n key: string; // The key containing the nested array to flatten\n labelFormat?: string; // Optional format string like \"{parent.name} → {name}\"\n}\n\nexport type FilterOperator = \"eq\" | \"neq\" | \"empty\" | \"notEmpty\" | \"gt\" | \"gte\" | \"lt\" | \"lte\" | \"contains\";\n\nexport interface FilterCondition {\n key: string;\n operator?: FilterOperator; // Defaults to \"eq\" when values is provided, \"exists\" behavior when neither\n values?: unknown[];\n}\n\nexport interface FilterTransform extends Transform {\n name: \"filter\";\n key?: string; // Legacy: single key to check\n values?: unknown[]; // Legacy: single values array\n conditions?: FilterCondition[]; // Multi-condition filter (AND logic)\n}\n\nexport type TransformStep = FlattenTransform | FilterTransform;\n\nexport type TransformPipeline = TransformStep[];\n\ntype TransformFunction = (items: unknown[], config: Transform) => unknown[];\n\nconst transformRegistry: Record<string, TransformFunction> = {};\n\n/**\n * Apply a pipeline of transforms to data\n */\nexport function applyTransformPipeline(\n items: unknown[],\n pipeline: TransformPipeline,\n): unknown[] {\n let result = items;\n\n for (const transform of pipeline) {\n const fn = transformRegistry[transform.name];\n if (!fn) {\n throw new Error(`Unknown transform: ${transform.name}`);\n }\n result = fn(result, transform);\n }\n\n return result;\n}\n\n/**\n * Flatten transform - recursively flattens nested arrays into a single level\n */\nfunction flattenTransform(items: unknown[], config: Transform): unknown[] {\n const flattenConfig = config as FlattenTransform;\n const { key, labelFormat } = flattenConfig;\n const flattened: unknown[] = [];\n\n function flattenRecursive(\n item: unknown,\n parent: Record<string, unknown> | null = null,\n depth: number = 0,\n ): void {\n if (typeof item !== \"object\" || item === null) return;\n\n const itemObj = item as Record<string, unknown>;\n\n // Add the current item\n if (labelFormat && parent) {\n const formattedItem = { ...itemObj };\n\n // Replace placeholders like {parent.name} and {name}\n let formattedLabel = labelFormat;\n formattedLabel = formattedLabel.replace(/\\{parent\\.(\\w+)\\}/g, (_, prop) =>\n String(parent[prop] ?? \"\"),\n );\n formattedLabel = formattedLabel.replace(/\\{(\\w+)\\}/g, (_, prop) =>\n String(itemObj[prop] ?? \"\"),\n );\n\n formattedItem._formattedLabel = formattedLabel;\n formattedItem._parent = parent;\n formattedItem._depth = depth;\n flattened.push(formattedItem);\n } else if (parent) {\n // Child node with parent reference\n flattened.push({\n ...itemObj,\n _parent: parent,\n _depth: depth,\n });\n } else {\n // Root node\n flattened.push({\n ...itemObj,\n _depth: depth,\n });\n }\n\n // Recursively flatten children\n const children = itemObj[key];\n if (Array.isArray(children)) {\n for (const child of children) {\n flattenRecursive(child, itemObj, depth + 1);\n }\n }\n }\n\n // Start flattening from root items\n for (const item of items) {\n flattenRecursive(item, null, 0);\n }\n\n return flattened;\n}\n\nfunction isEmpty(value: unknown): boolean {\n if (value === null || value === undefined) return true;\n if (Array.isArray(value)) return value.length === 0;\n if (typeof value === \"string\") return value.length === 0;\n return false;\n}\n\nfunction evaluateCondition(\n itemObj: Record<string, unknown>,\n condition: FilterCondition,\n): boolean {\n const value = itemObj[condition.key];\n const operator = condition.operator ?? (condition.values ? \"eq\" : \"eq\");\n\n switch (operator) {\n case \"eq\":\n if (!condition.values || condition.values.length === 0) {\n return condition.key in itemObj;\n }\n return condition.values.includes(value);\n case \"neq\":\n if (!condition.values || condition.values.length === 0) {\n return !(condition.key in itemObj);\n }\n return !condition.values.includes(value);\n case \"empty\":\n return isEmpty(value);\n case \"notEmpty\":\n return !isEmpty(value);\n case \"gt\":\n return typeof value === \"number\" && condition.values !== undefined && value > (condition.values[0] as number);\n case \"gte\":\n return typeof value === \"number\" && condition.values !== undefined && value >= (condition.values[0] as number);\n case \"lt\":\n return typeof value === \"number\" && condition.values !== undefined && value < (condition.values[0] as number);\n case \"lte\":\n return typeof value === \"number\" && condition.values !== undefined && value <= (condition.values[0] as number);\n case \"contains\":\n if (typeof value === \"string\" && condition.values) {\n return condition.values.some((v) => value.includes(String(v)));\n }\n if (Array.isArray(value) && condition.values) {\n return condition.values.some((v) => value.includes(v));\n }\n return false;\n default:\n return false;\n }\n}\n\n/**\n * Filter transform - filters items based on conditions\n *\n * Supports legacy single key/values syntax and new multi-condition syntax.\n * When using conditions, all conditions must match (AND logic).\n *\n * Operators:\n * eq - item[key] matches one of values (default)\n * neq - item[key] does NOT match any of values\n * empty - item[key] is null, undefined, empty array, or empty string\n * notEmpty - inverse of empty\n * gt - item[key] > values[0]\n * gte - item[key] >= values[0]\n * lt - item[key] < values[0]\n * lte - item[key] <= values[0]\n * contains - string includes substring, or array includes value\n */\nfunction filterTransform(items: unknown[], config: Transform): unknown[] {\n const filterConfig = config as FilterTransform;\n\n // Build conditions array from either new or legacy syntax\n let conditions: FilterCondition[];\n\n if (filterConfig.conditions) {\n conditions = filterConfig.conditions;\n } else if (filterConfig.key) {\n // Legacy single key/values syntax\n conditions = [{ key: filterConfig.key, values: filterConfig.values }];\n } else {\n return items;\n }\n\n return items.filter((item) => {\n if (typeof item !== \"object\" || item === null) return false;\n const itemObj = item as Record<string, unknown>;\n return conditions.every((condition) => evaluateCondition(itemObj, condition));\n });\n}\n\n// Register built-in transforms\ntransformRegistry[\"flatten\"] = flattenTransform;\ntransformRegistry[\"filter\"] = filterTransform;\n"],"names":[],"mappings":"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"}
|
package/dist/core/types.d.ts
CHANGED
|
@@ -41,4 +41,11 @@ export interface AuthConfig {
|
|
|
41
41
|
token?: string | (() => string);
|
|
42
42
|
[key: string]: unknown;
|
|
43
43
|
}
|
|
44
|
+
export interface ConnectorDataLayer {
|
|
45
|
+
dataset_name?: string;
|
|
46
|
+
dataset_description?: string;
|
|
47
|
+
dataset_id?: number;
|
|
48
|
+
profile_id?: string;
|
|
49
|
+
profile_name?: string;
|
|
50
|
+
}
|
|
44
51
|
//# sourceMappingURL=types.d.ts.map
|
package/dist/core/types.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AAEF,MAAM,WAAW,QAAQ,CAAC,GAAG,GAAG,OAAO;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;CACtC;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB"}
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/core/types.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,YAAY,GAAG;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AACF,MAAM,MAAM,cAAc,GAAG;IAC3B,KAAK,EAAE,YAAY,EAAE,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,IAAI,EAAE,OAAO,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,WAAW,CAAC;IACpB,EAAE,CAAC,EAAE;QAAE,KAAK,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;IACxB,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC,CAAC;AAEF,MAAM,WAAW,QAAQ,CAAC,GAAG,GAAG,OAAO;IACrC,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,eAAe,GAAG,OAAO,CAAC,cAAc,CAAC,CAAC;CAClE;AAED,MAAM,WAAW,eAAe;IAC9B,GAAG,EAAE,MAAM,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,IAAI,CAAC,EAAE,UAAU,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,GAAG,SAAS,GAAG,OAAO,CAAC;CACtC;AAED,MAAM,MAAM,OAAO,GAAG;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACjC,MAAM,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IACjC,KAAK,CAAC,EAAE,MAAM,GAAG,CAAC,MAAM,MAAM,CAAC,CAAC;IAChC,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB"}
|
package/dist/index.d.ts
CHANGED
|
@@ -5,9 +5,12 @@ export * from "./core/jsonpath";
|
|
|
5
5
|
export { registry } from "./core/registry";
|
|
6
6
|
export * from "./core/templating";
|
|
7
7
|
export * from "./core/transforms";
|
|
8
|
+
export * from "./core/projection";
|
|
9
|
+
export * from "./core/resolveScope";
|
|
8
10
|
export * from "./core/types";
|
|
9
11
|
export { RestApiProtocol } from "./protocols/rest_api";
|
|
10
|
-
export { providerRenderers, primevueRenderers, ProviderAutocomplete, ProviderSelect, ProviderMultiSelect, useProvider, JfText, JfTextArea, JfNumber, JfEnum, JfEnumArray, JfBoolean, } from "./vue";
|
|
12
|
+
export { providerRenderers, primevueRenderers, ProviderAutocomplete, ProviderSelect, ProviderMultiSelect, useProvider, createDataLayer, useDataLayer, JfText, JfTextArea, JfNumber, JfEnum, JfEnumArray, JfBoolean, } from "./vue";
|
|
13
|
+
export type { DataLayer } from "./vue";
|
|
11
14
|
export interface ProviderConfig {
|
|
12
15
|
protocols?: Protocol[];
|
|
13
16
|
auth?: AuthConfig;
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAG/B,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAG/B,OAAO,KAAK,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,cAAc,CAAC;AAIzD,OAAO,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AACrC,cAAc,iBAAiB,CAAC;AAChC,OAAO,EAAE,QAAQ,EAAE,MAAM,iBAAiB,CAAC;AAC3C,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AAEpC,cAAc,cAAc,CAAC;AAG7B,OAAO,EAAE,eAAe,EAAE,MAAM,sBAAsB,CAAC;AAGvD,OAAO,EACL,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,cAAc,EACd,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,YAAY,EACZ,MAAM,EACN,UAAU,EACV,QAAQ,EACR,MAAM,EACN,WAAW,EACX,SAAS,GACV,MAAM,OAAO,CAAC;AACf,YAAY,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAEvC,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,EAAE,QAAQ,EAAE,CAAC;IACvB,IAAI,CAAC,EAAE,UAAU,CAAC;CACnB;;iBAGc,GAAG,SAAS,cAAc;;AADzC,wBAYE"}
|