@ea-lab/reactive-json-docs 2.2.0 → 2.3.0

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ea-lab/reactive-json-docs",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Complete documentation for Reactive-JSON - Components, examples and LLM-parsable guides",
5
5
  "main": "public/rjbuild/docs/index.yaml",
6
6
  "files": [
@@ -266,15 +266,112 @@ additionalDataSource:
266
266
  ```
267
267
 
268
268
  ### Properties
269
- - **`src`** (required): URL of the data source. Can be a **string** (used as-is) or an **array of segments** that are resolved and concatenated (see [Dynamic URLs](#dynamic-urls-with-src-as-array) below)
270
- - **`path`** (optional): Path where to place the data (template syntax)
271
- - **`method`** (optional): HTTP method (GET, POST, etc.)
272
- - **`dataMapping`** (optional): Configure selective data dispatch using mapping processors
273
- - **`blocking`** (optional): If `true`, waits for loading before displaying
269
+ - **`src`** (required): URL of the data source. Can be a **string** (used as-is) or an **array of segments** see [Dynamic URLs](#dynamic-urls-with-src-as-array) below.
270
+ - **`path`** (optional): Path where to place the data (template syntax).
271
+ - **`method`** (optional): HTTP method (GET, POST, etc.).
272
+ - **`dataMapping`** (optional): Configure selective data dispatch using mapping processors.
273
+ - **`blocking`** (optional): If `true`, waits for loading before displaying.
274
+ - **`fallbackDataSource`** (optional): An alternate source tried when the primary fails — see [Fallback Sources](#fallback-sources) below.
274
275
 
275
276
  ### Dynamic URLs with `src` as Array
276
277
 
277
- When `src` is an array, each segment is resolved individually and then concatenated into the final URL. Segments starting with `~~.` are treated as references to the store data and are replaced with their resolved values.
278
+ When `src` is an array, each element is processed individually and the results are assembled into the final URL. The array can mix three kinds of elements:
279
+
280
+ #### 1. Plain strings and store references
281
+
282
+ A plain string is used as a literal. A string starting with `~~.` or `~.` is resolved from the root store data (both notations are equivalent in this context).
283
+
284
+ ```yaml
285
+ additionalDataSource:
286
+ - src:
287
+ - "/api/items/"
288
+ - ~~.itemId # resolved from root data
289
+ - "/details"
290
+ path: ~~.itemDetails
291
+ blocking: true
292
+ ```
293
+
294
+ #### 2. Segment objects — `{ segment, required? }`
295
+
296
+ A segment object resolves a dynamic value and inserts it as a path part.
297
+
298
+ ```yaml
299
+ additionalDataSource:
300
+ - src:
301
+ - "/api/"
302
+ - segment: ~~.category # resolved as a path segment
303
+ - "/items"
304
+ path: ~~.items
305
+ blocking: true
306
+ ```
307
+
308
+ When `required: true` is set and the segment resolves to `null` or empty, the entire URL is aborted (returns `null`) instead of producing a broken URL. This triggers the `fallbackDataSource` if one is defined, otherwise the source is skipped with a warning.
309
+
310
+ ```yaml
311
+ additionalDataSource:
312
+ - src:
313
+ - "/api/items/"
314
+ - segment: ~~.requiredId
315
+ required: true # abort URL if null
316
+ fallbackDataSource:
317
+ src: "/api/items/default"
318
+ path: ~~.item
319
+ path: ~~.item
320
+ blocking: true
321
+ ```
322
+
323
+ #### 3. Query param objects — `{ param, value, required? }`
324
+
325
+ A param object adds a key-value pair to the URL query string. Both the key and the value accept store references.
326
+
327
+ ```yaml
328
+ additionalDataSource:
329
+ - src:
330
+ - "/api/items"
331
+ - param: id
332
+ value: ~~.itemId # ?id=<itemId>
333
+ - param: ~~.filterParamName
334
+ value: ~~.filterValue # dynamic key and value
335
+ path: ~~.items
336
+ blocking: true
337
+ ```
338
+
339
+ **Null handling for params:**
340
+ - If either the key or the value resolves to `null`/empty and `required` is absent or `false`, the param is **silently omitted** from the URL.
341
+ - If either resolves to `null`/empty and `required: true` is set, the entire URL is **aborted**, triggering `fallbackDataSource` if defined.
342
+
343
+ ```yaml
344
+ additionalDataSource:
345
+ - src:
346
+ - "/api/search"
347
+ - param: q
348
+ value: ~~.searchQuery # omitted if null
349
+ - param: type
350
+ value: ~~.filterType
351
+ required: true # abort if null
352
+ path: ~~.results
353
+ blocking: true
354
+ ```
355
+
356
+ #### Mixing all three types
357
+
358
+ Path parts (plain strings, `~~.`/`~.` strings, and `segment` objects) are concatenated in order. All `param` objects are collected and appended as a query string after the path.
359
+
360
+ ```yaml
361
+ additionalDataSource:
362
+ - src:
363
+ - "/api/"
364
+ - segment: ~~.category # path: /api/electronics
365
+ required: true # abort URL if category is null
366
+ - "/items" # path: /api/electronics/items
367
+ - param: id
368
+ value: ~~.itemId # ?id=42
369
+ - param: ~~.extraKey
370
+ value: ~~.extraValue # &q=hello
371
+ path: ~~.result
372
+ blocking: true
373
+ # Resolved URL: /api/electronics/items?id=42&q=hello
374
+ ```
278
375
 
279
376
  This is particularly useful when an RjBuild is loaded inside a `ReactiveJsonSubroot` with `dataOverride`, where dynamic values (like entity IDs) are injected by the parent.
280
377
 
@@ -288,25 +385,54 @@ This is particularly useful when an RjBuild is loaded inside a `ReactiveJsonSubr
288
385
  ```
289
386
 
290
387
  ```yaml
291
- # TimeLogManager.yaml — uses taskId in additionalDataSource
388
+ # TimeLogManager.yaml — uses taskId as a query param
292
389
  additionalDataSource:
293
390
  - src:
294
- - "/api/time-logs?filter[task]="
295
- - ~~.taskId
391
+ - "/api/time-logs"
392
+ - param: "filter[task]"
393
+ value: ~~.taskId
394
+ required: true
296
395
  path: ~~.timeLogs
297
396
  blocking: true
298
397
 
299
398
  data:
300
- taskId: "" # Will be overridden by dataOverride
399
+ taskId: "" # Will be overridden by dataOverride
301
400
  timeLogs: []
302
401
  ```
303
402
 
304
- In this example, if `taskId` is `"42"`, the resolved URL will be `/api/time-logs?filter[task]=42`.
403
+ ### Fallback Sources
404
+
405
+ The `fallbackDataSource` property defines an alternate source that is tried automatically when the primary source cannot be used. It accepts the same structure as a regular `additionalDataSource` item, including its own `fallbackDataSource` for chaining.
406
+
407
+ A fallback is triggered in two situations:
408
+
409
+ 1. **The URL cannot be resolved** — a segment or param marked `required: true` resolved to `null` or empty.
410
+ 2. **The HTTP request fails** — the server returns an error (4xx, 5xx, network failure, etc.).
305
411
 
306
- **Rules:**
307
- - Only `~~.` (global/root data) references are supported in `src` segments — `~.` (local template context) is not available during initialization
308
- - If a `~~.` reference resolves to `null` or `undefined`, it is replaced with an empty string and a warning is logged
309
- - When `src` is a plain string, it behaves exactly as before (full backward compatibility)
412
+ ```yaml
413
+ additionalDataSource:
414
+ # Fallback on missing required param
415
+ - src:
416
+ - "/api/items"
417
+ - param: id
418
+ value: ~~.selectedId
419
+ required: true
420
+ path: ~~.item
421
+ fallbackDataSource:
422
+ src: "/api/items/default"
423
+ path: ~~.item
424
+ blocking: true
425
+
426
+ # Fallback on HTTP error
427
+ - src: "/api/live-config"
428
+ path: ~~.config
429
+ fallbackDataSource:
430
+ src: "/api/config-cache"
431
+ path: ~~.config
432
+ blocking: true
433
+ ```
434
+
435
+ When a fallback is triggered, a warning is logged in the console explaining the reason. If no fallback is defined and the primary fails, the source is skipped with a warning.
310
436
 
311
437
  ### Loading Modes
312
438
 
@@ -368,30 +494,47 @@ additionalDataSource:
368
494
  ### Complete Example
369
495
 
370
496
  ```yaml
371
- renderView:
372
- - type: div
373
- content:
374
- - type: h1
375
- content: ["Hello ", ~~.currentUser.name]
376
- - type: p
377
- content: ["Version: ", ~~.systemConfig.version]
378
-
379
497
  data:
380
- currentUser:
381
- name: "Loading..." # Temporary value
382
- systemConfig:
383
- version: "Loading..."
498
+ userId: "42"
499
+ section: "reports"
500
+ formatParam: "json"
501
+ optionalFilter: null # null → param silently omitted
502
+ fallbackSection: "home"
384
503
 
385
504
  additionalDataSource:
386
- # Critical user data (blocking)
505
+ # Static URL simple string form
387
506
  - src: "/api/user-profile.json"
388
507
  path: ~~.currentUser
389
508
  blocking: true
390
-
391
- # System configuration (non-blocking)
392
- - src: "/api/system-config.json"
509
+
510
+ # Dynamic path segment + query params
511
+ - src:
512
+ - "/api/"
513
+ - segment: ~~.section # e.g. /api/reports
514
+ - param: userId
515
+ value: ~~.userId # ?userId=42
516
+ - param: format
517
+ value: ~~.formatParam # &format=json
518
+ - param: filter
519
+ value: ~~.optionalFilter # null → omitted
520
+ path: ~~.sectionData
521
+ blocking: true
522
+
523
+ # Required param with fallback on failure or HTTP error
524
+ - src: "/api/system-config"
393
525
  path: ~~.systemConfig
526
+ fallbackDataSource:
527
+ src: "/api/system-config-cache"
528
+ path: ~~.systemConfig
394
529
  blocking: false
530
+
531
+ renderView:
532
+ - type: div
533
+ content:
534
+ - type: h1
535
+ content: ["Hello ", ~~.currentUser.name]
536
+ - type: p
537
+ content: ["Version: ", ~~.systemConfig.version]
395
538
  ```
396
539
 
397
540
  ## Best Practices
@@ -305,15 +305,100 @@ renderView:
305
305
  content: |
306
306
 
307
307
  ### Properties
308
- - **`src`** (required): URL of the data source. Can be a **string** (used as-is) or an **array of segments** that are resolved and concatenated (see [Dynamic URLs](#dynamic-urls-with-src-as-array) below)
309
- - **`path`** (optional): Path where to place the data (template syntax)
310
- - **`method`** (optional): HTTP method (GET, POST, etc.)
311
- - **`dataMapping`** (optional): Configure selective data dispatch using mapping processors
312
- - **`blocking`** (optional): If `true`, waits for loading before displaying
308
+ - **`src`** (required): URL of the data source. Can be a **string** (used as-is) or an **array of segments** see [Dynamic URLs](#dynamic-urls-with-src-as-array) below.
309
+ - **`path`** (optional): Path where to place the data (template syntax).
310
+ - **`method`** (optional): HTTP method (GET, POST, etc.).
311
+ - **`dataMapping`** (optional): Configure selective data dispatch using mapping processors.
312
+ - **`blocking`** (optional): If `true`, waits for loading before displaying.
313
+ - **`fallbackDataSource`** (optional): An alternate source tried when the primary fails — see [Fallback Sources](#fallback-sources) below.
313
314
 
314
315
  ### Dynamic URLs with `src` as Array
315
316
 
316
- When `src` is an array, each segment is resolved individually and then concatenated into the final URL. Segments starting with `~~.` are treated as references to the store data and are replaced with their resolved values.
317
+ When `src` is an array, each element is processed individually and the results are assembled into the final URL. The array can mix three kinds of elements:
318
+
319
+ #### 1. Plain strings and store references
320
+
321
+ A plain string is used as a literal. A string starting with `~~.` or `~.` is resolved from the root store data (both notations are equivalent in this context).
322
+
323
+ - type: TabbedSerializer
324
+ yamlSerializedContent: |
325
+ additionalDataSource:
326
+ - src:
327
+ - "/api/items/"
328
+ - ~~.itemId # resolved from root data
329
+ - "/details"
330
+ path: ~~.itemDetails
331
+ blocking: true
332
+
333
+ - type: Markdown
334
+ content: |
335
+
336
+ #### 2. Segment objects — `{ segment, required? }`
337
+
338
+ A segment object resolves a dynamic value and inserts it as a path part. When `required: true` is set and the segment resolves to `null` or empty, the entire URL is aborted instead of producing a broken URL. This triggers `fallbackDataSource` if one is defined.
339
+
340
+ - type: TabbedSerializer
341
+ yamlSerializedContent: |
342
+ additionalDataSource:
343
+ - src:
344
+ - "/api/"
345
+ - segment: ~~.category # resolved as a path segment
346
+ required: true # abort URL if null
347
+ - "/items"
348
+ path: ~~.items
349
+ blocking: true
350
+
351
+ - type: Markdown
352
+ content: |
353
+
354
+ #### 3. Query param objects — `{ param, value, required? }`
355
+
356
+ A param object adds a key-value pair to the URL query string. Both the key and the value accept store references.
357
+
358
+ **Null handling:**
359
+ - If either the key or the value resolves to `null`/empty and `required` is absent or `false`, the param is **silently omitted** from the URL.
360
+ - If either resolves to `null`/empty and `required: true` is set, the entire URL is **aborted**, triggering `fallbackDataSource` if defined.
361
+
362
+ - type: TabbedSerializer
363
+ yamlSerializedContent: |
364
+ additionalDataSource:
365
+ - src:
366
+ - "/api/search"
367
+ - param: q
368
+ value: ~~.searchQuery # omitted if null
369
+ - param: ~~.filterParamName # dynamic key
370
+ value: ~~.filterValue # dynamic value
371
+ - param: type
372
+ value: ~~.filterType
373
+ required: true # abort if null
374
+ path: ~~.results
375
+ blocking: true
376
+
377
+ - type: Markdown
378
+ content: |
379
+
380
+ #### Mixing all three types
381
+
382
+ Path parts (plain strings, `~~.`/`~.` strings, and `segment` objects) are concatenated in order. All `param` objects are collected and appended as a query string after the path.
383
+
384
+ - type: TabbedSerializer
385
+ yamlSerializedContent: |
386
+ additionalDataSource:
387
+ - src:
388
+ - "/api/"
389
+ - segment: ~~.category # path: /api/electronics
390
+ required: true # abort URL if category is null
391
+ - "/items" # path: /api/electronics/items
392
+ - param: id
393
+ value: ~~.itemId # ?id=42
394
+ - param: ~~.extraKey
395
+ value: ~~.extraValue # &q=hello
396
+ path: ~~.result
397
+ blocking: true
398
+ # Resolved URL: /api/electronics/items?id=42&q=hello
399
+
400
+ - type: Markdown
401
+ content: |
317
402
 
318
403
  This is particularly useful when an RjBuild is loaded inside a `ReactiveJsonSubroot` with `dataOverride`, where dynamic values (like entity IDs) are injected by the parent.
319
404
 
@@ -327,32 +412,58 @@ renderView:
327
412
  dataOverride:
328
413
  taskId: ~.task.id
329
414
 
330
- - type: Markdown
331
- content: |
332
-
333
415
  - type: TabbedSerializer
334
416
  yamlSerializedContent: |
335
- # TimeLogManager.yaml — uses taskId in additionalDataSource
417
+ # TimeLogManager.yaml — uses taskId as a query param
336
418
  additionalDataSource:
337
419
  - src:
338
- - "/api/time-logs?filter[task]="
339
- - ~~.taskId
420
+ - "/api/time-logs"
421
+ - param: "filter[task]"
422
+ value: ~~.taskId
423
+ required: true
340
424
  path: ~~.timeLogs
341
425
  blocking: true
342
426
 
343
427
  data:
344
- taskId: "" # Will be overridden by dataOverride
428
+ taskId: "" # Will be overridden by dataOverride
345
429
  timeLogs: []
346
430
 
347
431
  - type: Markdown
348
432
  content: |
349
433
 
350
- In this example, if `taskId` is `"42"`, the resolved URL will be `/api/time-logs?filter[task]=42`.
434
+ ### Fallback Sources
435
+
436
+ The `fallbackDataSource` property defines an alternate source that is tried automatically when the primary source cannot be used. It accepts the same structure as a regular `additionalDataSource` item, including its own `fallbackDataSource` for chaining.
437
+
438
+ A fallback is triggered in two situations:
351
439
 
352
- **Rules:**
353
- - Only `~~.` (global/root data) references are supported in `src` segments `~.` (local template context) is not available during initialization
354
- - If a `~~.` reference resolves to `null` or `undefined`, it is replaced with an empty string and a warning is logged
355
- - When `src` is a plain string, it behaves exactly as before (full backward compatibility)
440
+ 1. **The URL cannot be resolved** — a segment or param marked `required: true` resolved to `null` or empty.
441
+ 2. **The HTTP request fails** the server returns an error (4xx, 5xx, network failure, etc.).
442
+
443
+ When a fallback is triggered, a warning is logged in the console explaining the reason.
444
+
445
+ - type: TabbedSerializer
446
+ yamlSerializedContent: |
447
+ additionalDataSource:
448
+ # Fallback on missing required param
449
+ - src:
450
+ - "/api/items"
451
+ - param: id
452
+ value: ~~.selectedId
453
+ required: true
454
+ path: ~~.item
455
+ fallbackDataSource:
456
+ src: "/api/items/default"
457
+ path: ~~.item
458
+ blocking: true
459
+
460
+ # Fallback on HTTP error
461
+ - src: "/api/live-config"
462
+ path: ~~.config
463
+ fallbackDataSource:
464
+ src: "/api/config-cache"
465
+ path: ~~.config
466
+ blocking: true
356
467
 
357
468
  ### Loading Modes
358
469
 
@@ -434,31 +545,48 @@ renderView:
434
545
 
435
546
  - type: TabbedSerializer
436
547
  yamlSerializedContent: |
437
- renderView:
438
- - type: div
439
- content:
440
- - type: h1
441
- content: ["Hello ", ~~.currentUser.name]
442
- - type: p
443
- content: ["Version: ", ~~.systemConfig.version]
444
-
445
548
  data:
446
- currentUser:
447
- name: "Loading..." # Temporary value
448
- systemConfig:
449
- version: "Loading..."
549
+ userId: "42"
550
+ section: "reports"
551
+ formatParam: "json"
552
+ optionalFilter: null # null → param silently omitted
450
553
 
451
554
  additionalDataSource:
452
- # Critical user data (blocking)
555
+ # Static URL simple string form
453
556
  - src: "/api/user-profile.json"
454
557
  path: ~~.currentUser
455
558
  blocking: true
456
-
457
- # System configuration (non-blocking)
458
- - src: "/api/system-config.json"
559
+
560
+ # Dynamic path segment + query params
561
+ - src:
562
+ - "/api/"
563
+ - segment: ~~.section # e.g. /api/reports
564
+ required: true
565
+ - param: userId
566
+ value: ~~.userId # ?userId=42
567
+ - param: format
568
+ value: ~~.formatParam # &format=json
569
+ - param: filter
570
+ value: ~~.optionalFilter # null → omitted
571
+ path: ~~.sectionData
572
+ blocking: true
573
+
574
+ # Fallback on HTTP error or unavailable source
575
+ - src: "/api/system-config"
459
576
  path: ~~.systemConfig
577
+ fallbackDataSource:
578
+ src: "/api/system-config-cache"
579
+ path: ~~.systemConfig
460
580
  blocking: false
461
581
 
582
+ renderView:
583
+ - type: div
584
+ content:
585
+ - type: h1
586
+ content: ["Hello ", ~~.currentUser.name]
587
+ - type: p
588
+ content: ["Version: ", ~~.systemConfig.version]
589
+
462
590
  - type: Markdown
463
591
  content: |
464
592