@shwfed/config 2.7.5 → 2.7.7

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 (121) hide show
  1. package/dist/mcp.mjs +73 -21
  2. package/dist/module.json +1 -1
  3. package/dist/preview/assets/badge-B0tiCpa_.js +1 -0
  4. package/dist/preview/assets/config-BG9TRQcv.js +1 -0
  5. package/dist/preview/assets/{config-ulTPyAGw.js → config-Bfb2sH6S.js} +1 -1
  6. package/dist/preview/assets/config-C-XJ-8Rs.js +1 -0
  7. package/dist/preview/assets/{config-ISM4vT-S.js → config-CGvnv-5x.js} +1 -1
  8. package/dist/preview/assets/config-DDPihojt.js +1 -0
  9. package/dist/preview/assets/config-Dafqx9xC.js +1 -0
  10. package/dist/preview/assets/{config-DBviu6U0.js → config-DqMRy1WL.js} +1 -1
  11. package/dist/preview/assets/{config-CtPQb6dK.js → config-GCvXe12z.js} +1 -1
  12. package/dist/preview/assets/{config-CYixJlBY.js → config-jDPbLgBr.js} +1 -1
  13. package/dist/preview/assets/definition.vue_vue_type_script_setup_true_lang-DBXfCj4Q.js +1 -0
  14. package/dist/preview/assets/{index-CqWUukUH.css → index-B0PL01fm.css} +1 -1
  15. package/dist/preview/assets/index-CHzOsSTW.js +680 -0
  16. package/dist/preview/assets/index-CSfKAdi7.js +1 -0
  17. package/dist/preview/assets/{index-D6fhWrrp.js → index-D7jDE3kp.js} +1 -1
  18. package/dist/preview/assets/item-DV-Garrg.js +1 -0
  19. package/dist/preview/assets/runtime-BovPWken.js +1 -0
  20. package/dist/preview/assets/runtime-BxBBFFHA.js +1 -0
  21. package/dist/preview/assets/{runtime-B7NcvR9y.js → runtime-CwmJ9MLQ.js} +1 -1
  22. package/dist/preview/assets/runtime-Cyjx6haa.js +1 -0
  23. package/dist/preview/assets/runtime-D-LBi56N.js +1 -0
  24. package/dist/preview/assets/{runtime-BqlrYWt_.js → runtime-DA77AmOP.js} +1 -1
  25. package/dist/preview/assets/{runtime-jVzpCkuu.js → runtime-DHTqFEQI.js} +1 -1
  26. package/dist/preview/assets/runtime-DKtlQWwc.js +1 -0
  27. package/dist/preview/assets/runtime-UmLaEUGf.js +1 -0
  28. package/dist/preview/index.html +2 -2
  29. package/dist/runtime/components/actions/buttons/2026-04-21/com.shwfed.actions.button.navigation/runtime.vue +16 -2
  30. package/dist/runtime/components/config/blocks/2026-05-17/com.shwfed.block.chart.xy/runtime.vue +2 -2
  31. package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/item.vue +2 -2
  32. package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/schema.js +2 -2
  33. package/dist/runtime/components/config/blocks/2026-06-02/com.shwfed.block.card/badge.vue +3 -2
  34. package/dist/runtime/components/config/blocks/2026-06-02/com.shwfed.block.card/schema.js +2 -2
  35. package/dist/runtime/components/config/config.vue +9 -1
  36. package/dist/runtime/components/config/index.vue +11 -1
  37. package/dist/runtime/components/config/schema.d.ts +25 -0
  38. package/dist/runtime/components/config/schema.js +8 -0
  39. package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/runtime.vue +6 -5
  40. package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/schema.js +2 -2
  41. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/runtime.vue +3 -4
  42. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/runtime.vue +3 -4
  43. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/runtime.vue +3 -4
  44. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/runtime.vue +6 -5
  45. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/schema.js +2 -2
  46. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/runtime.vue +6 -5
  47. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/schema.js +2 -2
  48. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/runtime.vue +3 -4
  49. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/runtime.vue +3 -4
  50. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/runtime.vue +3 -4
  51. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/runtime.vue +3 -4
  52. package/dist/runtime/components/form/schema.js +2 -2
  53. package/dist/runtime/components/form/utils/initial.d.ts +5 -4
  54. package/dist/runtime/components/form/utils/initial.js +2 -2
  55. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.d.vue.ts +2 -2
  56. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.vue.d.ts +2 -2
  57. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/runtime.vue +7 -6
  58. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/schema.js +2 -2
  59. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.d.vue.ts +2 -2
  60. package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.vue.d.ts +2 -2
  61. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.d.vue.ts +2 -2
  62. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.vue.d.ts +2 -2
  63. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/runtime.vue +7 -6
  64. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/schema.js +2 -2
  65. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.d.vue.ts +2 -2
  66. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.vue.d.ts +2 -2
  67. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi/runtime.vue +7 -6
  68. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi/schema.js +2 -2
  69. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.d.vue.ts +2 -2
  70. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.vue.d.ts +2 -2
  71. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/runtime.vue +7 -6
  72. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/schema.js +2 -2
  73. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single/runtime.vue +7 -6
  74. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single/schema.js +2 -2
  75. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.d.vue.ts +2 -2
  76. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.vue.d.ts +2 -2
  77. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/runtime.vue +7 -6
  78. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/schema.js +2 -2
  79. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/runtime.vue +3 -4
  80. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/schema.js +2 -2
  81. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/runtime.vue +3 -4
  82. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/schema.js +2 -2
  83. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.d.vue.ts +2 -2
  84. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.vue.d.ts +2 -2
  85. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/runtime.vue +7 -6
  86. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/schema.js +2 -2
  87. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.d.vue.ts +2 -2
  88. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.vue.d.ts +2 -2
  89. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/runtime.vue +7 -6
  90. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/schema.js +2 -2
  91. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/runtime.vue +3 -4
  92. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/schema.js +2 -2
  93. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/runtime.vue +3 -4
  94. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/schema.js +2 -2
  95. package/dist/runtime/components/table/index.vue +3 -4
  96. package/dist/runtime/components/table/schema.js +3 -3
  97. package/dist/runtime/share/event-bus.d.ts +23 -4
  98. package/dist/runtime/share/expression.d.ts +13 -0
  99. package/dist/runtime/share/expression.js +1 -0
  100. package/dist/runtime/share/request.d.ts +29 -0
  101. package/dist/runtime/share/request.js +11 -0
  102. package/dist/runtime/vendor/cel-js/CLAUDE.md +2 -2
  103. package/dist/runtime/vendor/cel-js/PROMPT.md +35 -3
  104. package/dist/runtime/vendor/cel-js/lib/functions.js +2 -2
  105. package/dist/runtime/vendor/cel-js/lib/optional.js +52 -1
  106. package/package.json +1 -1
  107. package/dist/preview/assets/badge-DamXUB_x.js +0 -1
  108. package/dist/preview/assets/config-CXgHZFVu.js +0 -1
  109. package/dist/preview/assets/config-Dtj6xvFB.js +0 -1
  110. package/dist/preview/assets/config-DyKtOYYU.js +0 -1
  111. package/dist/preview/assets/config-v7KXfP3A.js +0 -1
  112. package/dist/preview/assets/definition.vue_vue_type_script_setup_true_lang-C-3KP_in.js +0 -1
  113. package/dist/preview/assets/index-CzxZSeNm.js +0 -680
  114. package/dist/preview/assets/index-DUSkLHHf.js +0 -1
  115. package/dist/preview/assets/item-BAj_4_7-.js +0 -1
  116. package/dist/preview/assets/runtime-CiWg_Jub.js +0 -1
  117. package/dist/preview/assets/runtime-CpMT9U1z.js +0 -1
  118. package/dist/preview/assets/runtime-CswN1gKf.js +0 -1
  119. package/dist/preview/assets/runtime-DOK5OTJn.js +0 -1
  120. package/dist/preview/assets/runtime-DldmFxn1.js +0 -1
  121. package/dist/preview/assets/runtime-WZBVKYom.js +0 -1
@@ -2,6 +2,19 @@ import { Schema } from 'effect';
2
2
  import { Environment } from '../vendor/cel-js/lib/index.js';
3
3
  import { Locale } from './locale.js';
4
4
  export type ResultType = string | string[] | ((type: string) => boolean);
5
+ /**
6
+ * Result-type matcher for a request expression. A request expression may now
7
+ * evaluate to `optional<HttpRequest>` — `None` means "no request, skip the
8
+ * fetch" — letting authors fetch conditionally (e.g. only when a `form_id` is
9
+ * present). For back-compat a bare `HttpRequest` still passes (always fetch).
10
+ * `dyn` and `optional<dyn>` are accepted too; the runtime normalizer
11
+ * (`asRequest`) treats any non-builder payload as `None` at dispatch time.
12
+ *
13
+ * Authors wrap both ternary branches in optionals, e.g.
14
+ * `form_id == "" ? optional.none() : optional.of(http.get(url))`, which the
15
+ * type-checker infers as `optional<HttpRequest>`.
16
+ */
17
+ export declare const HttpRequestResult: ResultType;
5
18
  export declare function Expression(options: {
6
19
  configure: (env: Environment) => void;
7
20
  resultType?: ResultType;
@@ -2,6 +2,7 @@ import { Either, Schema } from "effect";
2
2
  import { Environment } from "../vendor/cel-js/lib/index.js";
3
3
  import { CelError } from "../vendor/cel-js/lib/errors.js";
4
4
  import { Locale } from "./locale.js";
5
+ export const HttpRequestResult = (t) => t === "HttpRequest" || t === "optional<HttpRequest>" || t === "optional<dyn>" || t === "dyn";
5
6
  function matchesResultType(actual, expected) {
6
7
  if (typeof expected === "string") return expected === "dyn" || actual === expected;
7
8
  if (Array.isArray(expected)) return expected.includes("dyn") || expected.includes(actual);
@@ -0,0 +1,29 @@
1
+ import { Effect, Option } from 'effect';
2
+ import type { Fetch } from 'fx-fetch';
3
+ import type { HttpRequestBuilder } from '../vendor/cel-js/lib/http-builder.js';
4
+ /**
5
+ * Normalize the value a request expression evaluates to into an
6
+ * `Option<HttpRequestBuilder>`.
7
+ *
8
+ * A request expression now expects `optional<HttpRequest>` — `None` means the
9
+ * author opted out ("no request, skip the fetch"), enabling conditional fetches
10
+ * (e.g. only when a `form_id` is present). For back-compat a bare `HttpRequest`
11
+ * still works (always fetch) and maps to `Some`. A stray `null`/`undefined` is
12
+ * also treated as `None`.
13
+ *
14
+ * We only distinguish *present* from *absent* here — we do NOT `instanceof`-
15
+ * guard the payload. The type-checker already guarantees an `HttpRequest` at
16
+ * this boundary (the `HttpRequestResult` matcher), and a misconfigured non-
17
+ * builder would fail at `.json()`/`.file()` exactly as it did before this
18
+ * contract existed. (Guarding on `instanceof HttpRequestBuilder` would also
19
+ * wrongly reject test doubles that aren't real instances.)
20
+ */
21
+ export declare function asRequest(result: unknown): Option.Option<HttpRequestBuilder>;
22
+ /**
23
+ * Resolve a request expression's value to its JSON response as an `Option`:
24
+ * `Some(body)` when a request was produced and issued, `None` when the
25
+ * expression opted out (or produced no builder). The returned Effect needs a
26
+ * `Fetch` layer. Mirrors the `{ request?, data }` datasource shape, where the
27
+ * response is exposed to the `data` expression as the `json` Option.
28
+ */
29
+ export declare function fetchJsonOption(result: unknown): Effect.Effect<Option.Option<unknown>, unknown, Fetch.Fetch>;
@@ -0,0 +1,11 @@
1
+ import { Effect, Option } from "effect";
2
+ export function asRequest(result) {
3
+ if (Option.isOption(result)) return result;
4
+ return result == null ? Option.none() : Option.some(result);
5
+ }
6
+ export function fetchJsonOption(result) {
7
+ return Option.match(asRequest(result), {
8
+ onNone: () => Effect.succeed(Option.none()),
9
+ onSome: (builder) => Effect.map(builder.json(), Option.some)
10
+ });
11
+ }
@@ -18,7 +18,7 @@ A `range()` built-in has been added (not from upstream) — `range(number, numbe
18
18
 
19
19
  The `homogeneousAggregateLiterals` and `enableOptionalTypes` environment options have been removed. Aggregate data structures (lists, maps) are always heterogeneous — mixed-type literals are inferred as `list<dyn>` or `map<dyn, dyn>`. Optional types (`.?`, `[?]`, `optional.*` helpers) are always enabled.
20
20
 
21
- The custom `Optional` class has been replaced with Effect's `Option` type (`import { Option } from 'effect'`). Internal helpers `optionalOf(value)` and `optionalValue(opt)` in `optional.js` handle the CEL-specific semantics (treating `undefined` as `None`, throwing `EvaluationError` on missing value access).
21
+ The custom `Optional` class has been replaced with Effect's `Option` type (`import { Option } from 'effect'`). Internal helpers `optionalOf(value)` and `optionalValue(opt)` in `optional.js` handle the CEL-specific semantics (treating `undefined` as `None`, throwing `EvaluationError` on missing value access). The optional surface is `optional.of(A): optional<A>` (the lift / `pure`), `optional.none()`, `optional.hasValue()`, `optional.value()`, `optional.or(optional)`, `optional.orValue(value)`, plus `optional<A>.flatMap(var, body): optional<B>` — monadic bind, a local addition (not from upstream). `flatMap` is a variable-binding macro (registered with `(ast, ast)` arg types so its body stays unevaluated): on `Some` it binds the value and evaluates `body` (which must itself yield an `optional`); on `None` it short-circuits without touching `body`. Map (`fmap`) is the derived `o.flatMap(v, optional.of(f(v)))`.
22
22
 
23
23
  An `http` built-in has been added (`http-builtins.ts`, `http-builder.ts`) — not from upstream. It registers the `http` constant and the `http` / `HttpRequest` types on `globalRegistry`, so `http.get(url).header(...).body(...)` expressions type-check and evaluate in every `Environment`. A CEL expression only builds an `HttpRequestBuilder` — a pure description of a request; it never issues one. Both terminal methods, `.json()` and `.file()`, are dispatched by the host on the returned builder (neither is a CEL method), so expression evaluation stays free of IO. Endpoints must be absolute URLs — there is no base-URL resolution. Depends on `fx-fetch`. The host can register process-wide default headers via `HttpRequestBuilder.setDefaultHeader(name, valueOrGetter)` / `clearDefaultHeader(name)`; they are merged in at `#buildRequest()` time, with case-insensitive precedence to an explicit `.header(...)` on the builder. A getter that returns `null` / `undefined` / `''` skips the header for that request, so the host can source values from live refs (e.g. the active i18n locale for `Accept-Language`) without baking in stale snapshots.
24
24
 
@@ -77,7 +77,7 @@ Internal-only (not re-exported from `index.js`): `parse`, standalone `evaluate`/
77
77
 
78
78
  Primitives: `string`, `bool`, `number`, `bytes`, `null_type`, `type`
79
79
  Composites: `list<T>`, `map<K, V>`, `optional<T>`, `dyn`, `message`
80
- Custom: `Date` (backed by `TZDate` from `@date-fns/tz`), `URL` (backed by the native `URL`; method `URL.param(string): string` reads a search param), `File` (native), `FormData` (native — see `form-builtins.ts`), `http` / `HttpRequest` (local addition — see `http-builtins.ts`)
80
+ Custom: `Date` (backed by `TZDate` from `@date-fns/tz`), `URL` (backed by the native `URL`; method `URL.query(string): optional<string>` reads a search param — `None` when absent, distinguishing it from a present-but-empty value), `File` (native), `FormData` (native — see `form-builtins.ts`), `http` / `HttpRequest` (local addition — see `http-builtins.ts`)
81
81
 
82
82
  ## Function Signature Format
83
83
 
@@ -242,10 +242,13 @@ range(date("2024-01-01"), date("2024-04-01"), "month")
242
242
  ### URL
243
243
  A `URL` value is supplied by the host (e.g. a `location` variable bound to the
244
244
  current page URL). You cannot construct one in CEL.
245
+ `query(name)` returns `optional<string>` — `Some(value)` when the param is
246
+ present (including a present-but-empty value), `None` when it is absent. Unwrap
247
+ it with `.orValue(...)` / `.hasValue()` / `.value()`.
245
248
  ```cel
246
- location.param("tab") // value of the ?tab= search param
247
- location.param("missing") // "" — absent params yield empty string
248
- location.param("id") // first value when a param repeats
249
+ location.query("tab").orValue("") // value of the ?tab= search param, "" if absent
250
+ location.query("missing").hasValue() // false — absent params are None
251
+ location.query("id").orValue("") // first value when a param repeats
249
252
  ```
250
253
 
251
254
  ## HTTP
@@ -297,6 +300,35 @@ http.post("https://api.example.com/users")
297
300
  .body({"name": "Alice"})
298
301
  ```
299
302
 
303
+ ## Optionals
304
+
305
+ An `optional<T>` is either present (`Some`) or absent (`None`). They come from
306
+ `.?` / `[?]` access, `find`, and `URL.query`. Build them with `optional.of(x)`
307
+ (the lift — wraps a value as present) and `optional.none()`.
308
+
309
+ ```cel
310
+ optional.of(5) // present, holds 5
311
+ optional.none() // absent
312
+
313
+ o.hasValue() // bool — is it present?
314
+ o.value() // unwrap — ERRORS if absent
315
+ o.orValue(default) // unwrap, or `default` when absent
316
+ o.or(otherOptional) // first present optional wins
317
+ ```
318
+
319
+ ### flatMap — chain a computation that may itself be absent
320
+ `o.flatMap(v, body)` binds the present value to `v` and evaluates `body` — which
321
+ must itself return an `optional` — only when `o` is present; an absent `o`
322
+ short-circuits to `None` and `body` is never evaluated.
323
+ ```cel
324
+ loc.query("id").flatMap(v, optional.of("user-" + v)).orValue("anon")
325
+ // "user-42" when ?id=42 is present; "anon" when absent
326
+
327
+ optional.of(2).flatMap(v, optional.none()).hasValue() // false — body collapsed it
328
+ ```
329
+ Together with `optional.of` this is a lawful monad. A plain map (`fmap`) is the
330
+ derived form `o.flatMap(v, optional.of(f(v)))`.
331
+
300
332
  ## Macros
301
333
 
302
334
  Macros are special forms — they look like method calls but have special evaluation semantics.
@@ -1,7 +1,7 @@
1
1
  import { evaluationError } from "./errors.js";
2
2
  import { Decimal } from "./decimal.js";
3
3
  import { TYPES, Type } from "./registry.js";
4
- import { register as registerOptional } from "./optional.js";
4
+ import { register as registerOptional, optionalOf } from "./optional.js";
5
5
  import { objKeys, arrayFrom } from "./globals.js";
6
6
  import { TZDate } from "@date-fns/tz";
7
7
  import { startOfDay, startOfWeek, startOfMonth, startOfYear, endOfDay, endOfWeek, endOfMonth, endOfYear, addDays, addWeeks, addMonths, addYears, addHours, addMinutes, setDate as setDayOfMonth, setMonth, setYear, format as formatDate } from "date-fns";
@@ -392,7 +392,7 @@ export function registerFunctions(registry) {
392
392
  functionOverload("Date.format(string): string", (d, fmt) => formatDate(d, fmt));
393
393
  registry.registerType("File", File);
394
394
  registry.registerType("URL", URL);
395
- functionOverload("URL.param(string): string", (url, key) => url.searchParams.get(key) ?? "");
395
+ functionOverload("URL.query(string): optional<string>", (url, key) => optionalOf(url.searchParams.get(key) ?? void 0));
396
396
  registerOptional(registry);
397
397
  }
398
398
  function stringSize(str) {
@@ -1,5 +1,5 @@
1
1
  import { Effect, Option } from "effect";
2
- import { evaluationError } from "./errors.js";
2
+ import { evaluationError, parseError } from "./errors.js";
3
3
  export function optionalOf(value) {
4
4
  return value === void 0 ? Option.none() : Option.some(value);
5
5
  }
@@ -108,4 +108,55 @@ export function register(registry) {
108
108
  }
109
109
  })
110
110
  );
111
+ registry.registerFunctionOverload(
112
+ "optional<A>.flatMap(ast, ast): optional<dyn>",
113
+ createFlatMapExpander()
114
+ );
115
+ }
116
+ function createFlatMapExpander() {
117
+ const functionDesc = "optional.flatMap(var, body)";
118
+ const invalidVar = `${functionDesc} invalid iteration variable`;
119
+ const invalidReceiver = `${functionDesc} receiver`;
120
+ const invalidBody = `${functionDesc} body`;
121
+ function ensureOptional(value, ast, description) {
122
+ if (Option.isOption(value)) return value;
123
+ throw evaluationError("optional_expected", `${description} must be optional`, ast);
124
+ }
125
+ function ensureOptionalType(checker, node, ctx, description) {
126
+ const type = checker.check(node, ctx);
127
+ if (type.kind === "optional") return type;
128
+ if (type.kind === "dyn") return checker.getType("optional");
129
+ throw checker.createError("optional_expected", `${description} must be optional, got '${type}'`, node);
130
+ }
131
+ function typeCheck(checker, macro, ctx) {
132
+ const receiverType = ensureOptionalType(checker, macro.receiver, ctx, invalidReceiver);
133
+ const innerType = receiverType.valueType ?? checker.getType("dyn");
134
+ macro.iterCtx = ctx.forkWithVariable(macro.iterVarName, innerType);
135
+ return ensureOptionalType(checker, macro.body, macro.iterCtx, invalidBody);
136
+ }
137
+ function evaluate(ev, macro, ctx) {
138
+ return Effect.gen(function* () {
139
+ const recv = yield* ev.eval(macro.receiver, ctx);
140
+ const optional = ensureOptional(recv, macro.receiver, invalidReceiver);
141
+ if (Option.isNone(optional)) return Option.none();
142
+ const iterCtx = macro.iterCtx.reuse(ctx);
143
+ const result = yield* ev.eval(macro.body, iterCtx.setIterValue(optional.value, ev));
144
+ return ensureOptional(result, macro.body, invalidBody);
145
+ });
146
+ }
147
+ return (opts) => {
148
+ const { args, receiver, ast } = opts;
149
+ const iterVar = args[0];
150
+ if (iterVar.op !== "id") throw parseError("invalid_macro_argument", invalidVar, iterVar);
151
+ return {
152
+ ast,
153
+ receiver,
154
+ functionDesc,
155
+ iterVarName: iterVar.args,
156
+ body: args[1],
157
+ iterCtx: void 0,
158
+ evaluate,
159
+ typeCheck
160
+ };
161
+ };
111
162
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shwfed/config",
3
- "version": "2.7.5",
3
+ "version": "2.7.7",
4
4
  "description": "Configurable UI for SHWFED",
5
5
  "type": "module",
6
6
  "publishConfig": {
@@ -1 +0,0 @@
1
- import{d as M,F,u as $,o as z,w as p,a as v,y as E,c as w,z as x,b as f,_ as y,G as I,H as L,I as N,J as P,K as S,e as t,g as V,f as m,i as A,p as G,l as H,j as J,r as K,k as O,q as T,L as W,M as D,t as Q,m as R,s as U}from"./index-CzxZSeNm.js";const Y=M({name:"ShwfedBlockCardBadge",inheritAttrs:!1,__name:"badge",props:{badge:{}},setup(n){const a=n,{locale:k}=F(),j=T(),o=K(void 0);function i(){return O(j)}const g=t(()=>o.value===void 0?R():U(o.value)),l=t(()=>W(a.badge.content,k.value)||""),C=t(()=>l.value?D(l.value,m,{...i(),json:g.value}):""),B=t(()=>{const e=a.badge.show;if(!e)return!0;try{return Q(m(e,{...i(),json:g.value}))}catch(r){return console.warn("[shwfed-card-badge] show evaluation failed",r),!0}});async function s(){const e=a.badge.request;if(!e)return;const r=i(),q=V(function*(){return yield*(yield*m(e,r)).json()});try{o.value=await A(G(q,H))}catch(h){console.warn("[shwfed-card-badge] fetch failed",h)}}const u=t(()=>!!a.badge.request&&(a.badge.interval??0)>0),_=t(()=>Math.max(1,a.badge.interval??1)*1e3),c=J(),{pause:b,resume:d}=$(()=>{s()},_,{immediate:!1});return z(()=>{s(),u.value&&c.value&&d()}),p(c,e=>{u.value&&(e?(s(),d()):b())}),p(()=>[a.badge.request??"",a.badge.interval??0].join("|"),()=>{s(),u.value&&c.value?d():b()}),(e,r)=>l.value&&B.value?(v(),E(P,{key:0},[n.badge.dot?(v(),w(f(y),x({key:0,variant:n.badge.variant??"default",class:"size-2.5 min-w-0 rounded-full p-0"},e.$attrs),null,16,["variant"])):(v(),w(f(y),x({key:1,variant:n.badge.variant??"default"},e.$attrs),{default:I(()=>[L(f(N),{source:C.value,class:"max-w-none text-inherit [&_*]:text-inherit [&_p]:m-0"},null,8,["source"])]),_:1},16,["variant"]))],64)):S("",!0)}});export{Y as default};
@@ -1 +0,0 @@
1
- import{d as g,P as d,a2 as u,az as f,y as m,H as s,G as i,b as r,a as p,T as _,V as v,W as x,a1 as h,S as T,e as V}from"./index-CzxZSeNm.js";const S={class:"flex flex-col gap-3"},C=g({name:"ShwfedEventDispatchActionConfig",__name:"config",props:{modelValue:{required:!0},modelModifiers:{}},emits:["update:modelValue"],setup(l){const t=d(l,"modelValue"),o=u(f(),"triggers")??"触发的操作",n=V(()=>t.value.triggers??[]);function c(a){const e={...t.value};a.length===0?Reflect.deleteProperty(e,"triggers"):e.triggers=a,t.value=e}return(a,e)=>(p(),m("div",S,[s(r(T),{orientation:"vertical"},{default:i(()=>[s(r(_),{class:"text-xs text-zinc-500"},{default:i(()=>[v(x(r(o)),1)]),_:1}),s(h,{triggers:n.value,"onUpdate:triggers":c},null,8,["triggers"])]),_:1})]))}});export{C as default};
@@ -1 +0,0 @@
1
- import{d as x,P as k,b0 as S,y as V,H as e,G as l,b as a,a as g,T as r,U as m,V as d,W as f,I as p,au as $,S as _,Y as b,a2 as w,a3 as y}from"./index-CzxZSeNm.js";const z={class:"flex flex-col gap-4"},h=x({name:"ShwfedMarkdownItemConfig",__name:"config",props:{modelValue:{required:!0},modelModifiers:{}},emits:["update:modelValue"],setup(v){const t=k(v,"modelValue"),c=S(),u=o=>w(c,o)??o,s=o=>y(c,o);return(o,n)=>(g(),V("div",z,[e(a(_),{orientation:"vertical"},{default:l(()=>[e(a(r),{class:"text-xs text-zinc-500"},m({default:l(()=>[d(" "+f(u("name")),1)]),_:2},[s("name")?{name:"tooltip",fn:l(()=>[e(a(p),{source:s("name"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),e(a($),{"model-value":t.value.name,placeholder:"仅用于编辑器内识别","onUpdate:modelValue":n[0]||(n[0]=i=>t.value={...t.value,name:String(i)})},null,8,["model-value"])]),_:1}),e(a(_),{orientation:"vertical"},{default:l(()=>[e(a(r),{class:"text-xs text-zinc-500"},m({default:l(()=>[d(" "+f(u("content")),1)]),_:2},[s("content")?{name:"tooltip",fn:l(()=>[e(a(p),{source:s("content"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),e(a(b),{markdown:"",multiline:"","model-value":t.value.content,"onUpdate:modelValue":n[1]||(n[1]=i=>t.value={...t.value,content:i})},null,8,["model-value"])]),_:1})]))}});export{h as default};
@@ -1 +0,0 @@
1
- import{d as z,a as y,y as E,v as V,N as T,b as e,O as U,P as $,Q as j,c as F,G as l,R as v,H as s,S as d,T as u,U as p,V as m,W as f,I as g,X as b,Y as N,Z as h,$ as B,J as C,a0 as H,a1 as O,a2 as R,a3 as D}from"./index-CzxZSeNm.js";const P=z({__name:"FieldGroup",props:{class:{type:[Boolean,null,String,Object,Array]}},setup(_){const r=_;return(x,i)=>(y(),E("div",{"data-slot":"field-group",class:T(e(U)("group/field-group @container/field-group flex w-full flex-col gap-7 data-[slot=checkbox-group]:gap-3 *:data-[slot=field-group]:gap-4",r.class))},[V(x.$slots,"default")],2))}}),q={class:"grid grid-cols-2 gap-4"},I={class:"grid grid-cols-2 gap-4"},J={class:"flex items-start gap-2"},L={class:"grid grid-cols-2 gap-3"},G=z({name:"ShwfedHttpRequestConfirmActionConfig",__name:"config",props:{modelValue:{required:!0},modelModifiers:{}},emits:["update:modelValue"],setup(_){const r=$(_,"modelValue"),x=j(()=>{}),i=n=>R(x,n)??n,a=n=>D(x,n);function c(n){const t={...r.value,...n};for(const[o,k]of Object.entries(n))k===void 0&&Reflect.deleteProperty(t,o);r.value=t}const S=["onSuccess","onWarning","onError","onInfo"];function w(n,t){c({[n]:t.length===0?void 0:t})}return(n,t)=>(y(),F(e(P),null,{default:l(()=>[v("div",q,[s(e(d),{orientation:"vertical"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("expression")),1)]),_:2},[a("expression")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("expression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(b),{"model-value":r.value.expression,multiline:"",placeholder:"例:http.post('/api/foo').body({ id: row.id })","result-type":"HttpRequest",class:"min-h-16","onUpdate:modelValue":t[0]||(t[0]=o=>c({expression:o}))},null,8,["model-value"])]),_:1}),s(e(d),{orientation:"vertical"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("markdown")),1)]),_:2},[a("markdown")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("markdown"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(N),{markdown:"","model-value":r.value.markdown,"onUpdate:modelValue":t[1]||(t[1]=o=>c({markdown:o}))},null,8,["model-value"])]),_:1})]),v("div",I,[s(e(d),{orientation:"vertical"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("icon")),1)]),_:2},[a("icon")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("icon"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(h),{"model-value":r.value.icon??"","onUpdate:modelValue":t[2]||(t[2]=o=>c(o.trim()===""?{icon:void 0}:{icon:o}))},null,8,["model-value"])]),_:1}),s(e(d),{orientation:"vertical"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("color")),1)]),_:2},[a("color")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("color"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(B),{"model-value":r.value.color??"","onUpdate:modelValue":t[3]||(t[3]=o=>c(o.trim()===""?{color:void 0}:{color:o}))},null,8,["model-value"])]),_:1})]),v("div",J,[s(e(d),{orientation:"vertical",class:"flex-1 basis-0 min-w-0"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("messageExpression")),1)]),_:2},[a("messageExpression")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("messageExpression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(b),{"model-value":r.value.messageExpression??"",placeholder:"例:string(json.message)","result-type":"string","extra-vars":{json:{type:"dyn",label:"HTTP 响应体(已解析 JSON)"}},"onUpdate:modelValue":t[4]||(t[4]=o=>c({messageExpression:o===""?void 0:o}))},null,8,["model-value"])]),_:1}),s(e(d),{orientation:"vertical",class:"flex-1 basis-0 min-w-0"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i("resultExpression")),1)]),_:2},[a("resultExpression")?{name:"tooltip",fn:l(()=>[s(e(g),{source:a("resultExpression"),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(e(b),{"model-value":r.value.resultExpression??"",placeholder:"例:json.code == 0 ? 'success' : 'error'","result-type":"string","extra-vars":{json:{type:"dyn",label:"HTTP 响应体(已解析 JSON)"}},"onUpdate:modelValue":t[5]||(t[5]=o=>c({resultExpression:o===""?void 0:o}))},null,8,["model-value"])]),_:1})]),v("div",L,[(y(),E(C,null,H(S,o=>s(e(d),{key:o,orientation:"vertical",class:"min-w-0"},{default:l(()=>[s(e(u),{class:"text-xs text-zinc-500"},p({default:l(()=>[m(" "+f(i(o)),1)]),_:2},[a(o)?{name:"tooltip",fn:l(()=>[s(e(g),{source:a(o),block:"",class:"prose prose-sm prose-zinc"},null,8,["source"])]),key:"0"}:void 0]),1024),s(O,{triggers:r.value[o]??[],"onUpdate:triggers":k=>w(o,k)},null,8,["triggers","onUpdate:triggers"])]),_:2},1024)),64))])]),_:1}))}});export{G as default};
@@ -1 +0,0 @@
1
- import{d as _,P as y,a5 as x,a6 as b,y as c,R as i,H as n,G as o,b as t,a as l,a7 as v,a8 as u,a9 as g,aa as D,J as h,a0 as S,c as $,ab as k,W as p,ac as w}from"./index-CzxZSeNm.js";const B={class:"flex flex-col gap-3"},C={class:"flex-1"},V={class:"ml-auto text-xs tabular-nums text-zinc-400"},N=_({name:"ShwfedPrototypeActionConfig",__name:"config",props:{modelValue:{required:!0},modelModifiers:{}},emits:["update:modelValue"],setup(m){const r=y(m,"modelValue"),f=(()=>{const s=new Map;for(const e of x){if(e.type===b||e.deprecated)continue;const a=s.get(e.type);(!a||e.compatibilityDate>a.compatibilityDate)&&s.set(e.type,{type:e.type,compatibilityDate:e.compatibilityDate,name:e.metadata.name,icon:e.metadata.icon})}return[...s.values()].sort((e,a)=>e.name.localeCompare(a.name,"zh"))})();function d(s,e){r.value={type:s,compatibilityDate:e}}return(s,e)=>(l(),c("div",B,[e[0]||(e[0]=i("p",{class:"text-xs text-zinc-500"}," 原型按钮点击后无任何副作用,用于占位。选择下方任意类型可将其转换为正式按钮 —— 此转换仅能进行一次。 ",-1)),n(t(w),null,{default:o(()=>[n(t(v),{align:"inline-start"},{default:o(()=>[n(t(u),{icon:"fluent:arrow-swap-20-regular"})]),_:1}),n(t(g),null,{default:o(()=>[n(t(D),null,{default:o(()=>[(l(!0),c(h,null,S(t(f),a=>(l(),$(t(k),{key:a.type,value:a.type,onSelect:z=>d(a.type,a.compatibilityDate)},{default:o(()=>[n(t(u),{icon:a.icon,class:"size-4 shrink-0"},null,8,["icon"]),i("span",C,p(a.name),1),i("span",V,p(a.compatibilityDate),1)]),_:2},1032,["value","onSelect"]))),128))]),_:1})]),_:1})]),_:1})]))}});export{N as default};
@@ -1 +0,0 @@
1
- import{d as f,aZ as u,o as m,a_ as p,al as g,K as l,x as I,a$ as _}from"./index-CzxZSeNm.js";const w=f({name:"ShwfedActionDefinition",inheritAttrs:!1,__name:"definition",props:{actionId:{},effect:{}},setup(r){const n=r,a=u(),t=I(_,void 0),i=crypto.randomUUID(),c=import.meta.dev;let e,s=!1;function d(){!c||s||(s=!0,console.warn("[shwfed-action-definition] must be used inside <shwfed-actions>."))}function o(){if(!t){d();return}e&&e!==n.actionId&&t.unregisterAction(e,i),t.registerAction({ownerId:i,actionId:n.actionId,effect:n.effect,render:a.default}),e=n.actionId}return o(),m(()=>{o()}),p(()=>{o()}),g(()=>{!t||!e||t.unregisterAction(e,i)}),(y,A)=>l("",!0)}});export{w as _};