@supersoniks/concorde 4.9.92 → 4.9.94

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 (111) hide show
  1. package/ai/cursor/rules/concorde.mdc +7 -0
  2. package/ai/jetbrains/rules/concorde.md +6 -0
  3. package/ai/skills/concorde/SKILL.md +48 -0
  4. package/build-infos.json +1 -1
  5. package/concorde-core.bundle.js +299 -292
  6. package/concorde-core.es.js +10139 -6035
  7. package/dist/concorde-core.bundle.js +299 -292
  8. package/dist/concorde-core.es.js +10139 -6035
  9. package/dist/docs-mock-api-sw.js +110 -0
  10. package/dist/docs-mock-api-sw.js.map +3 -3
  11. package/dist/js/core/components/functional/functional.js +1 -0
  12. package/dist/js/core/components/functional/functional.js.map +1 -1
  13. package/dist/js/core/components/functional/jsonata/jsonata.js +119 -0
  14. package/dist/js/core/components/functional/jsonata/jsonata.js.map +1 -0
  15. package/dist/js/core/components/ui/button/button.js +1 -1
  16. package/dist/js/core/components/ui/button/button.js.map +1 -1
  17. package/dist/js/core/decorators/Subscriber.js +1 -0
  18. package/dist/js/core/decorators/Subscriber.js.map +1 -1
  19. package/dist/js/core/decorators/api.js +108 -16
  20. package/dist/js/core/decorators/api.js.map +1 -1
  21. package/dist/js/core/decorators/subscriber/derive.js +60 -0
  22. package/dist/js/core/decorators/subscriber/derive.js.map +1 -0
  23. package/dist/js/core/utils/api.js +29 -8
  24. package/dist/js/core/utils/api.js.map +1 -1
  25. package/dist/js/core/utils/derive.js +246 -0
  26. package/dist/js/core/utils/derive.js.map +1 -0
  27. package/dist/js/core/utils/jsonataHelpers.js +69 -0
  28. package/dist/js/core/utils/jsonataHelpers.js.map +1 -0
  29. package/dist/js/core/utils/jsonataRuntime.js +75 -0
  30. package/dist/js/core/utils/jsonataRuntime.js.map +1 -0
  31. package/dist/js/utils.js +2 -0
  32. package/dist/js/utils.js.map +1 -1
  33. package/dist/types/core/components/functional/functional.d.ts +1 -0
  34. package/dist/types/core/components/functional/functional.d.ts.map +1 -1
  35. package/dist/types/core/components/functional/jsonata/jsonata.d.ts +29 -0
  36. package/dist/types/core/components/functional/jsonata/jsonata.d.ts.map +1 -0
  37. package/dist/types/core/components/ui/button/button.d.ts +1 -1
  38. package/dist/types/core/components/ui/button/button.d.ts.map +1 -1
  39. package/dist/types/core/components/ui/form/checkbox/checkbox.d.ts +3 -3
  40. package/dist/types/core/components/ui/form/input/input.d.ts +3 -3
  41. package/dist/types/core/components/ui/form/input-autocomplete/input-autocomplete.d.ts +3 -3
  42. package/dist/types/core/components/ui/form/textarea/textarea.d.ts +3 -3
  43. package/dist/types/core/decorators/Subscriber.d.ts +2 -0
  44. package/dist/types/core/decorators/Subscriber.d.ts.map +1 -1
  45. package/dist/types/core/decorators/api.d.ts +21 -12
  46. package/dist/types/core/decorators/api.d.ts.map +1 -1
  47. package/dist/types/core/decorators/subscriber/derive.d.ts +30 -0
  48. package/dist/types/core/decorators/subscriber/derive.d.ts.map +1 -0
  49. package/dist/types/core/utils/api.d.ts +1 -1
  50. package/dist/types/core/utils/api.d.ts.map +1 -1
  51. package/dist/types/core/utils/derive.d.ts +40 -0
  52. package/dist/types/core/utils/derive.d.ts.map +1 -0
  53. package/dist/types/core/utils/jsonataHelpers.d.ts +15 -0
  54. package/dist/types/core/utils/jsonataHelpers.d.ts.map +1 -0
  55. package/dist/types/core/utils/jsonataRuntime.d.ts +13 -0
  56. package/dist/types/core/utils/jsonataRuntime.d.ts.map +1 -0
  57. package/dist/types/mixins.d.ts +3 -3
  58. package/dist/types/utils.d.ts +2 -0
  59. package/dist/types/utils.d.ts.map +1 -1
  60. package/docs/assets/{index-DURr6O71.js → index-DpIkksht.js} +652 -479
  61. package/docs/crawl/docs/_decorators/get.html +27 -6
  62. package/docs/crawl/docs/_decorators/patch.html +6 -0
  63. package/docs/crawl/docs/_decorators/post.html +8 -0
  64. package/docs/crawl/docs/_decorators/put.html +6 -0
  65. package/docs/crawl/hubs/decorators.html +36 -31
  66. package/docs/crawl/hubs/remote-data.html +36 -31
  67. package/docs/index.html +1 -1
  68. package/docs/llms-full.txt +47 -3
  69. package/docs/src/docs/_decorators/get.md +31 -0
  70. package/docs/src/docs/_decorators/patch.md +9 -0
  71. package/docs/src/docs/_decorators/post.md +11 -0
  72. package/docs/src/docs/_decorators/put.md +9 -0
  73. package/docs/src/docs/search/docs-search.json +120 -5
  74. package/docs/src/tsconfig.json +268 -268
  75. package/package.json +28 -3
  76. package/public/docs-mock-api-sw.js +110 -0
  77. package/public/docs-mock-api-sw.js.map +3 -3
  78. package/src/core/components/functional/functional.ts +1 -0
  79. package/src/core/components/functional/jsonata/jsonata.md +56 -0
  80. package/src/core/components/functional/jsonata/jsonata.spec.ts +202 -0
  81. package/src/core/components/functional/jsonata/jsonata.ts +116 -0
  82. package/src/core/components/ui/button/button.ts +2 -2
  83. package/src/core/decorators/Subscriber.ts +2 -0
  84. package/src/core/decorators/api.post.spec.ts +99 -4
  85. package/src/core/decorators/api.spec.ts +90 -0
  86. package/src/core/decorators/api.ts +212 -92
  87. package/src/core/decorators/subscriber/derive.ts +95 -0
  88. package/src/core/utils/api.spec.ts +73 -0
  89. package/src/core/utils/api.ts +44 -11
  90. package/src/core/utils/derive.spec.ts +190 -0
  91. package/src/core/utils/derive.ts +357 -0
  92. package/src/core/utils/jsonataHelpers.ts +100 -0
  93. package/src/core/utils/jsonataRuntime.ts +88 -0
  94. package/src/docs/_core-concept/dataFlow.md +9 -0
  95. package/src/docs/_decorators/get.md +31 -0
  96. package/src/docs/_decorators/patch.md +9 -0
  97. package/src/docs/_decorators/post.md +11 -0
  98. package/src/docs/_decorators/put.md +9 -0
  99. package/src/docs/_misc/docs-mock-api.md +3 -0
  100. package/src/docs/components/docs-demo-sources.ts +40 -0
  101. package/src/docs/docs.ts +1 -0
  102. package/src/docs/example/decorators-demo-post.ts +70 -0
  103. package/src/docs/example/decorators-demo-subscribe-publish-get-demos.ts +59 -0
  104. package/src/docs/example/docs-jsonata-demos.ts +128 -0
  105. package/src/docs/mock-api/fixtures-jsonata.ts +131 -0
  106. package/src/docs/mock-api/router.ts +26 -0
  107. package/src/docs/navigation/navigation.ts +4 -0
  108. package/src/docs/search/docs-search.json +300 -5
  109. package/src/tsconfig.json +18 -0
  110. package/src/tsconfig.tsbuildinfo +1 -1
  111. package/src/utils.ts +13 -0
@@ -81,6 +81,24 @@ export const DOCS_LIT_DEMO_REGISTRY: Record<string, DocsLitDemoConfig> = {
81
81
  { path: "src/docs/example/docs-users-list.ts", line: 15, label: "docs-users-list" },
82
82
  ],
83
83
  },
84
+ "docs-jsonata-space-cats-demo": {
85
+ sources: [
86
+ {
87
+ path: "src/docs/example/docs-jsonata-demos.ts",
88
+ line: 26,
89
+ label: "top-n",
90
+ },
91
+ ],
92
+ },
93
+ "docs-jsonata-table-totals-demo": {
94
+ sources: [
95
+ {
96
+ path: "src/docs/example/docs-jsonata-demos.ts",
97
+ line: 69,
98
+ label: "totals",
99
+ },
100
+ ],
101
+ },
84
102
  "docs-list-alternate-demo": {
85
103
  sources: [
86
104
  { path: "src/docs/example/docs-list-demos.ts", line: 51, label: "alternate" },
@@ -204,6 +222,14 @@ export const DOCS_DEMO_SOURCE_REGISTRY: Record<string, DocsSource[]> = {
204
222
  "docs-joke-search-demo": [
205
223
  { path: "src/docs/example/docs-joke-demos.ts", label: "joke demos" },
206
224
  ],
225
+ "docs-jsonata-space-cats-demo": [
226
+ { path: "src/docs/example/docs-jsonata-demos.ts", label: "jsonata demos" },
227
+ { path: "src/docs/mock-api/fixtures-jsonata.ts", label: "fixtures" },
228
+ ],
229
+ "docs-jsonata-table-totals-demo": [
230
+ { path: "src/docs/example/docs-jsonata-demos.ts", label: "jsonata demos" },
231
+ { path: "src/docs/mock-api/fixtures-jsonata.ts", label: "fixtures" },
232
+ ],
207
233
  "docs-joke-lang-demo": [
208
234
  { path: "src/docs/example/docs-joke-demos.ts", label: "joke demos" },
209
235
  ],
@@ -252,6 +278,13 @@ export const DOCS_DEMO_SOURCE_REGISTRY: Record<string, DocsSource[]> = {
252
278
  { path: "src/docs/example/decorators-demo-geo.ts", label: "geo API" },
253
279
  { path: "src/docs/mock-api/router.ts", label: "mock router" },
254
280
  ],
281
+ "demo-api-get-method": [
282
+ {
283
+ path: "src/docs/example/decorators-demo-subscribe-publish-get-demos.ts",
284
+ label: "demo-api-get-method",
285
+ },
286
+ { path: "src/docs/example/decorators-demo-geo.ts", label: "geo API" },
287
+ ],
255
288
  "demo-api-get-configuration-key": [
256
289
  {
257
290
  path: "src/docs/example/decorators-demo-subscribe-publish-get-demos.ts",
@@ -276,6 +309,13 @@ export const DOCS_DEMO_SOURCE_REGISTRY: Record<string, DocsSource[]> = {
276
309
  },
277
310
  { path: "src/docs/mock-api/router.ts", label: "mock router" },
278
311
  ],
312
+ "demo-api-post-method": [
313
+ {
314
+ path: "src/docs/example/decorators-demo-post.ts",
315
+ label: "demo-api-post-method",
316
+ },
317
+ { path: "src/docs/mock-api/router.ts", label: "mock router" },
318
+ ],
279
319
  "demo-api-post-dynamic": [
280
320
  {
281
321
  path: "src/docs/example/decorators-demo-post.ts",
package/src/docs/docs.ts CHANGED
@@ -15,6 +15,7 @@ import "./example/docs-joke-demos";
15
15
  import "./example/docs-queue-demos";
16
16
  import "./example/docs-toggle-demos";
17
17
  import "./example/docs-list-demos";
18
+ import "./example/docs-jsonata-demos";
18
19
  import "./example/docs-router-demos";
19
20
  import "./example/docs-submit-demos";
20
21
  import "./example/docs-api-config-demos";
@@ -65,6 +65,12 @@ export const docsDemoPostPublishRequestKey = new DataProviderKey<RegisterRequest
65
65
  export const docsDemoPostTriggerKey = new DataProviderKey<number>(
66
66
  "docsDemoPostTrigger",
67
67
  );
68
+ export const docsDemoPostMethodRequestKey = new DataProviderKey<RegisterRequest>(
69
+ "docsDemoPostMethodRequest",
70
+ );
71
+ export const docsDemoPostMethodTriggerKey = new DataProviderKey<number>(
72
+ "docsDemoPostMethodTrigger",
73
+ );
68
74
  export const docsDemoPostDynamicRequestKey = new DataProviderKey<SessionSyncRequest>(
69
75
  "docsDemoPostDynamicRequest",
70
76
  );
@@ -140,6 +146,70 @@ export class DemoApiPost extends LitElement {
140
146
  }
141
147
  }
142
148
 
149
+ @customElement("demo-api-post-method")
150
+ export class DemoApiPostMethod extends LitElement {
151
+ static styles = [tailwind];
152
+
153
+ @state()
154
+ private payload?: ApiResult<RegisterResult>;
155
+
156
+ connectedCallback() {
157
+ super.connectedCallback();
158
+ set(docsDemoPostMethodRequestKey, {
159
+ email: "method@concorde.local",
160
+ password: "method-password",
161
+ });
162
+ set(docsDemoPostMethodTriggerKey, 0);
163
+ }
164
+
165
+ @post(
166
+ registerPostEndpoint,
167
+ docsDemoPostMethodRequestKey,
168
+ docsDemoReqresApiConfigurationKey,
169
+ { triggerKey: docsDemoPostMethodTriggerKey },
170
+ )
171
+ handlePayload(payload?: ApiResult<RegisterResult>) {
172
+ this.payload = payload;
173
+ }
174
+
175
+ private updateBody() {
176
+ set(docsDemoPostMethodRequestKey, {
177
+ email: `method-${Date.now()}@concorde.local`,
178
+ password: "method-password",
179
+ });
180
+ }
181
+
182
+ private resend() {
183
+ dp(docsDemoPostMethodTriggerKey).invalidate();
184
+ }
185
+
186
+ render() {
187
+ const result = this.payload?.result;
188
+ return html`
189
+ <div class="space-y-3">
190
+ <div class="flex flex-wrap items-center gap-2">
191
+ <span class="text-sm font-medium">✉️ POST function mode</span>
192
+ <sonic-button size="sm" @click=${this.updateBody}>
193
+ Update body &amp; POST
194
+ </sonic-button>
195
+ <sonic-button size="sm" variant="secondary" @click=${this.resend}>
196
+ Invalidate trigger
197
+ </sonic-button>
198
+ </div>
199
+ <p class="text-sm text-neutral-600 dark:text-neutral-400">
200
+ The <code>@post</code> decorator calls
201
+ <code>handlePayload</code> with the complete API payload.
202
+ </p>
203
+ <p class="text-xs text-neutral-500">
204
+ HTTP status:
205
+ <strong>${this.payload?.response?.status ?? "loading…"}</strong>
206
+ · email: <strong>${result?.email ?? "—"}</strong>
207
+ </p>
208
+ </div>
209
+ `;
210
+ }
211
+ }
212
+
143
213
  @customElement("demo-api-post-dynamic")
144
214
  export class DemoApiPostDynamic extends LitElement {
145
215
  static styles = [tailwind];
@@ -5,6 +5,7 @@ import type { ApiResult } from "@supersoniks/concorde/core/utils/api";
5
5
  import { DataProviderKey } from "@supersoniks/concorde/core/utils/dataProviderKey";
6
6
  import { sub } from "@supersoniks/concorde/directives";
7
7
  import {
8
+ dp,
8
9
  get as storeGet,
9
10
  set,
10
11
  } from "@supersoniks/concorde/core/utils/PublisherProxy";
@@ -28,6 +29,9 @@ const geoCommunesGet = get(
28
29
  geoCommunesApiGetEndpoint,
29
30
  docsDemoGeoApiConfigurationKey,
30
31
  );
32
+ const geoCommunesMethodTriggerKey = new DataProviderKey<number>(
33
+ "docsDemoGeoCommunesMethodTrigger",
34
+ );
31
35
 
32
36
  @customElement("demo-publish")
33
37
  export class DemoPublish extends LitElement {
@@ -124,6 +128,61 @@ export class DemoApiGet extends LitElement {
124
128
  }
125
129
  }
126
130
 
131
+ @customElement("demo-api-get-method")
132
+ export class DemoApiGetMethod extends LitElement {
133
+ static styles = [tailwind];
134
+
135
+ @state()
136
+ private payload?: ApiResult<GeoCommuneRow[]>;
137
+
138
+ connectedCallback() {
139
+ super.connectedCallback();
140
+ set(geoCommunesMethodTriggerKey, 0);
141
+ }
142
+
143
+ @get(geoCommunesApiGetEndpoint, docsDemoGeoApiConfigurationKey, {
144
+ triggerKey: geoCommunesMethodTriggerKey,
145
+ })
146
+ handlePayload(payload?: ApiResult<GeoCommuneRow[]>) {
147
+ this.payload = payload;
148
+ }
149
+
150
+ private refresh() {
151
+ dp(geoCommunesMethodTriggerKey).invalidate();
152
+ }
153
+
154
+ render() {
155
+ const rows = this.payload?.result ?? [];
156
+ return html`
157
+ <div class="space-y-3">
158
+ <div class="flex flex-wrap items-center gap-3">
159
+ <span class="text-sm font-medium">🗺️ GET function mode</span>
160
+ <sonic-button size="sm" @click=${this.refresh}>
161
+ Invalidate trigger
162
+ </sonic-button>
163
+ </div>
164
+ <p class="text-sm text-neutral-600 dark:text-neutral-400">
165
+ The <code>@get</code> decorator calls <code>handlePayload</code> with
166
+ the complete API payload.
167
+ </p>
168
+ <p class="text-xs text-neutral-500">
169
+ HTTP status:
170
+ <strong>${this.payload?.response?.status ?? "loading…"}</strong>
171
+ </p>
172
+ <ul class="grid gap-1 sm:grid-cols-2">
173
+ ${rows.slice(0, 6).map(
174
+ (commune) =>
175
+ html`<li class="text-sm">
176
+ ${commune.nom}
177
+ <span class="text-neutral-500">(${commune.code})</span>
178
+ </li>`,
179
+ )}
180
+ </ul>
181
+ </div>
182
+ `;
183
+ }
184
+ }
185
+
127
186
  @customElement("demo-api-get-configuration-key")
128
187
  export class DemoApiGetConfigurationKey extends LitElement {
129
188
  static styles = [tailwind];
@@ -0,0 +1,128 @@
1
+ import { html, LitElement } from "lit";
2
+ import { customElement } from "lit/decorators.js";
3
+ import { tailwind } from "../tailwind";
4
+ import { DOCS_MOCK_API_BASE } from "../mock-api/urls";
5
+ import { Endpoint } from "@supersoniks/concorde/core/utils/endpoint";
6
+ import { DataProviderKey } from "@supersoniks/concorde/dataProviderKey";
7
+ import { set } from "@supersoniks/concorde/utils";
8
+
9
+ import "../../core/components/functional/fetch/fetch";
10
+ import "../../core/components/functional/jsonata/jsonata";
11
+ import "../../core/components/functional/list/list";
12
+ import "../../core/components/functional/value/value";
13
+ import "../../core/components/ui/form/input/input";
14
+
15
+ const missions = new Endpoint<unknown>("api/space-cats");
16
+ const topForm = new DataProviderKey<{ top: number | string }>(
17
+ "jsonataTopForm",
18
+ );
19
+
20
+ const order = new Endpoint<unknown>("api/market-order");
21
+ const taxForm = new DataProviderKey<{ taxPercent: number | string }>(
22
+ "jsonataTaxForm",
23
+ );
24
+
25
+ /** Cas 1 — groupby + top N (recalcul via form, sans refetch). */
26
+ @customElement("docs-jsonata-space-cats-demo")
27
+ export class DocsJsonataSpaceCatsDemo extends LitElement {
28
+ static styles = [tailwind];
29
+
30
+ connectedCallback(): void {
31
+ super.connectedCallback();
32
+ set(topForm, { top: 3 });
33
+ }
34
+
35
+ render() {
36
+ return html`
37
+ <div serviceURL=${DOCS_MOCK_API_BASE} class="flex flex-col gap-3">
38
+ <div formDataProvider=${topForm.path} class="max-w-xs">
39
+ <sonic-input name="top" type="number" label="Top N" value="3"></sonic-input>
40
+ </div>
41
+
42
+ <sonic-fetch
43
+ dataProvider=${missions.path}
44
+ endPoint=${missions.path}
45
+ key="data"
46
+ ></sonic-fetch>
47
+
48
+ <sonic-jsonata
49
+ inputProvider=${missions.path}
50
+ outputProvider="spaceCatLeaderboard"
51
+ formDataProvider=${topForm.path}
52
+ expression='$input{name: $sum(points)} ~> $each(function($v,$k){{"name":$k,"points":$v}}) ^(>points)[[0..$number($top)-1]]'
53
+ ></sonic-jsonata>
54
+
55
+ <sonic-list
56
+ dataProvider="spaceCatLeaderboard"
57
+ class="flex flex-col gap-1"
58
+ .items=${({ name, points }: { name: string; points: number }) =>
59
+ html`<div class="flex gap-3 text-sm">
60
+ <span class="font-medium">${name}</span>
61
+ <span class="ml-auto tabular-nums text-neutral-500">${points}</span>
62
+ </div>`}
63
+ ></sonic-list>
64
+ </div>
65
+ `;
66
+ }
67
+ }
68
+
69
+ /** Cas 2 — totaux d’un tableau (somme + taxe via form). */
70
+ @customElement("docs-jsonata-table-totals-demo")
71
+ export class DocsJsonataTableTotalsDemo extends LitElement {
72
+ static styles = [tailwind];
73
+
74
+ connectedCallback(): void {
75
+ super.connectedCallback();
76
+ set(taxForm, { taxPercent: 10 });
77
+ }
78
+
79
+ render() {
80
+ return html`
81
+ <div serviceURL=${DOCS_MOCK_API_BASE} class="flex flex-col gap-3">
82
+ <div formDataProvider=${taxForm.path} class="max-w-xs">
83
+ <sonic-input
84
+ name="taxPercent"
85
+ type="number"
86
+ label="Tax %"
87
+ value="10"
88
+ ></sonic-input>
89
+ </div>
90
+
91
+ <sonic-fetch
92
+ dataProvider=${order.path}
93
+ endPoint=${order.path}
94
+ key="data"
95
+ ></sonic-fetch>
96
+
97
+ <sonic-jsonata
98
+ inputProvider=${order.path}
99
+ outputProvider="marketOrderTotals"
100
+ formDataProvider=${taxForm.path}
101
+ expression='(
102
+ $sub := $sum($input.(qty * unitPrice));
103
+ {
104
+ "subtotal": $round($sub, 2),
105
+ "tax": $round($sub * $number($taxPercent) / 100, 2),
106
+ "grandTotal": $round($sub * (1 + $number($taxPercent) / 100), 2)
107
+ }
108
+ )'
109
+ ></sonic-jsonata>
110
+
111
+ <div dataProvider="marketOrderTotals" class="flex gap-6 text-sm">
112
+ <div>
113
+ <div class="text-neutral-400">Subtotal</div>
114
+ <sonic-value key="subtotal"></sonic-value>
115
+ </div>
116
+ <div>
117
+ <div class="text-neutral-400">Tax</div>
118
+ <sonic-value key="tax"></sonic-value>
119
+ </div>
120
+ <div>
121
+ <div class="text-neutral-400">Total</div>
122
+ <span class="font-semibold"><sonic-value key="grandTotal"></sonic-value></span>
123
+ </div>
124
+ </div>
125
+ </div>
126
+ `;
127
+ }
128
+ }
@@ -0,0 +1,131 @@
1
+ /**
2
+ * Fixtures fun pour démos / tests sonic-jsonata (hors billetterie).
3
+ */
4
+
5
+ const avatar = (seed: string) =>
6
+ `https://i.pravatar.cc/150?u=${encodeURIComponent(seed)}`;
7
+
8
+ /** Missions de chats spatiaux — groupby name + top N points. */
9
+ export type SpaceCatMission = {
10
+ id: number;
11
+ name: string;
12
+ planet: string;
13
+ mission: string;
14
+ points: number;
15
+ avatar: string;
16
+ };
17
+
18
+ export const DOCS_SPACE_CAT_MISSIONS: SpaceCatMission[] = [
19
+ {
20
+ id: 1,
21
+ name: "Captain Whiskers",
22
+ planet: "Mars",
23
+ mission: "Laser hunt",
24
+ points: 40,
25
+ avatar: avatar("captain-whiskers"),
26
+ },
27
+ {
28
+ id: 2,
29
+ name: "Captain Whiskers",
30
+ planet: "Mars",
31
+ mission: "Dust nap",
32
+ points: 25,
33
+ avatar: avatar("captain-whiskers"),
34
+ },
35
+ {
36
+ id: 3,
37
+ name: "Nebula Paws",
38
+ planet: "Europa",
39
+ mission: "Ice fishing",
40
+ points: 55,
41
+ avatar: avatar("nebula-paws"),
42
+ },
43
+ {
44
+ id: 4,
45
+ name: "Astro Mittens",
46
+ planet: "Titan",
47
+ mission: "Methane surf",
48
+ points: 33,
49
+ avatar: avatar("astro-mittens"),
50
+ },
51
+ {
52
+ id: 5,
53
+ name: "Nebula Paws",
54
+ planet: "Europa",
55
+ mission: "Comet chase",
56
+ points: 20,
57
+ avatar: avatar("nebula-paws"),
58
+ },
59
+ {
60
+ id: 6,
61
+ name: "Professor Meowington",
62
+ planet: "Venus",
63
+ mission: "Cloud tasting",
64
+ points: 48,
65
+ avatar: avatar("prof-meowington"),
66
+ },
67
+ {
68
+ id: 7,
69
+ name: "Astro Mittens",
70
+ planet: "Titan",
71
+ mission: "Antenna polish",
72
+ points: 12,
73
+ avatar: avatar("astro-mittens"),
74
+ },
75
+ {
76
+ id: 8,
77
+ name: "Zero-G Socks",
78
+ planet: "Moon",
79
+ mission: "Flag knitting",
80
+ points: 61,
81
+ avatar: avatar("zero-g-socks"),
82
+ },
83
+ ];
84
+
85
+ /** Sacs de café — groupby origin + filtre roast. */
86
+ export type CoffeeBag = {
87
+ id: number;
88
+ origin: string;
89
+ roast: "light" | "medium" | "dark";
90
+ kg: number;
91
+ farm: string;
92
+ };
93
+
94
+ export const DOCS_COFFEE_BAGS: CoffeeBag[] = [
95
+ { id: 1, origin: "Ethiopia", roast: "light", kg: 12, farm: "Yirgacheffe Hills" },
96
+ { id: 2, origin: "Ethiopia", roast: "medium", kg: 8, farm: "Sidamo Ridge" },
97
+ { id: 3, origin: "Colombia", roast: "medium", kg: 15, farm: "Huila Valley" },
98
+ { id: 4, origin: "Colombia", roast: "dark", kg: 6, farm: "Cauca Peak" },
99
+ { id: 5, origin: "Brazil", roast: "dark", kg: 22, farm: "Minas Gerais" },
100
+ { id: 6, origin: "Brazil", roast: "medium", kg: 10, farm: "Cerrado" },
101
+ { id: 7, origin: "Guatemala", roast: "light", kg: 9, farm: "Antigua" },
102
+ { id: 8, origin: "Guatemala", roast: "dark", kg: 5, farm: "Huehuetenango" },
103
+ { id: 9, origin: "Ethiopia", roast: "light", kg: 4, farm: "Guji Forest" },
104
+ ];
105
+
106
+ export function filterCoffeeBags(
107
+ bags: CoffeeBag[],
108
+ roast: string | null | undefined,
109
+ ): CoffeeBag[] {
110
+ const r = roast?.trim().toLowerCase();
111
+ if (!r || r === "all") return bags;
112
+ return bags.filter((b) => b.roast === r);
113
+ }
114
+
115
+ /** Lignes de commande (table) — total / moyenne par ligne. */
116
+ export type MarketOrderLine = {
117
+ id: number;
118
+ name: string;
119
+ qty: number;
120
+ unitPrice: number;
121
+ category: string;
122
+ };
123
+
124
+ export const DOCS_MARKET_ORDER_LINES: MarketOrderLine[] = [
125
+ { id: 1, name: "Heirloom tomatoes", qty: 4, unitPrice: 3.5, category: "veg" },
126
+ { id: 2, name: "Sourdough loaf", qty: 2, unitPrice: 6.0, category: "bakery" },
127
+ { id: 3, name: "Goat cheese", qty: 1, unitPrice: 8.5, category: "dairy" },
128
+ { id: 4, name: "Honey jar", qty: 3, unitPrice: 5.2, category: "pantry" },
129
+ { id: 5, name: "Sunflowers", qty: 5, unitPrice: 2.0, category: "flowers" },
130
+ { id: 6, name: "Free-range eggs", qty: 2, unitPrice: 4.8, category: "dairy" },
131
+ ];
@@ -8,6 +8,12 @@ import {
8
8
  type ReqresUserResponse,
9
9
  type ReqresUsersListResponse,
10
10
  } from "./fixtures";
11
+ import {
12
+ DOCS_COFFEE_BAGS,
13
+ DOCS_MARKET_ORDER_LINES,
14
+ DOCS_SPACE_CAT_MISSIONS,
15
+ filterCoffeeBags,
16
+ } from "./fixtures-jsonata";
11
17
 
12
18
  export const DOCS_MOCK_API_PREFIX = "/docs-mock-api";
13
19
 
@@ -241,6 +247,26 @@ export async function handleDocsMockApiRequest(
241
247
  return json(paginateUsers(url));
242
248
  }
243
249
 
250
+ if (subPath === "/api/space-cats") {
251
+ return json({
252
+ data: DOCS_SPACE_CAT_MISSIONS,
253
+ total: DOCS_SPACE_CAT_MISSIONS.length,
254
+ });
255
+ }
256
+
257
+ if (subPath === "/api/coffee-bags") {
258
+ const roast = url.searchParams.get("roast");
259
+ const data = filterCoffeeBags(DOCS_COFFEE_BAGS, roast);
260
+ return json({ data, total: data.length });
261
+ }
262
+
263
+ if (subPath === "/api/market-order") {
264
+ return json({
265
+ data: DOCS_MARKET_ORDER_LINES,
266
+ total: DOCS_MARKET_ORDER_LINES.length,
267
+ });
268
+ }
269
+
244
270
  if (subPath === "/geo/communes" || subPath.startsWith("/geo/communes")) {
245
271
  return json(geoCommunes(url), {
246
272
  headers: { "X-Fetched-At": new Date().toISOString() },
@@ -40,6 +40,10 @@ export class DocsNavigation extends LitElement {
40
40
  { label: "If", href: "#core/components/functional/if/if.md/if" },
41
41
  { label: "List", href: "#core/components/functional/list/list.md/list" },
42
42
  { label: "Mix", href: "#core/components/functional/mix/mix.md/mix" },
43
+ {
44
+ label: "Jsonata",
45
+ href: "#core/components/functional/jsonata/jsonata.md/jsonata",
46
+ },
43
47
  {
44
48
  label: "Queue",
45
49
  href: "#core/components/functional/queue/queue.md/queue",