@shwfed/config 2.7.6 → 2.7.8

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/dist/mcp.mjs +165 -52
  2. package/dist/module.json +1 -1
  3. package/dist/preview/assets/badge-KAEXz3VO.js +1 -0
  4. package/dist/preview/assets/{config-C947O8za.js → config-BXx5syNf.js} +1 -1
  5. package/dist/preview/assets/{config-DhAntnE5.js → config-Bb9Yeh33.js} +1 -1
  6. package/dist/preview/assets/config-C-QRPeN1.js +1 -0
  7. package/dist/preview/assets/config-CkKx7sVR.js +1 -0
  8. package/dist/preview/assets/config-CtbYlZCL.js +1 -0
  9. package/dist/preview/assets/{config-Bl8L6943.js → config-DPlbFBRi.js} +1 -1
  10. package/dist/preview/assets/config-DbfJWa8K.js +1 -0
  11. package/dist/preview/assets/{config-DppExb4h.js → config-DbirfZyy.js} +1 -1
  12. package/dist/preview/assets/{config-B7hXY5FF.js → config-ZczGik30.js} +1 -1
  13. package/dist/preview/assets/definition.vue_vue_type_script_setup_true_lang-CQ6MUPKO.js +1 -0
  14. package/dist/preview/assets/{index-DiC1rvCq.js → index-Bv_aA34a.js} +1 -1
  15. package/dist/preview/assets/{index-B0PL01fm.css → index-C9P-6gZd.css} +1 -1
  16. package/dist/preview/assets/index-CJFU9znN.js +1 -0
  17. package/dist/preview/assets/index-DUOkekYu.js +680 -0
  18. package/dist/preview/assets/item-SC0WQMVu.js +1 -0
  19. package/dist/preview/assets/{runtime-DmV_M4B_.js → runtime-BPOf7Yqz.js} +1 -1
  20. package/dist/preview/assets/runtime-CC2caFS9.js +1 -0
  21. package/dist/preview/assets/runtime-CLaRFZzt.js +1 -0
  22. package/dist/preview/assets/runtime-Ckuz5Kxm.js +1 -0
  23. package/dist/preview/assets/{runtime-BQnHKogz.js → runtime-CnKlH0mi.js} +1 -1
  24. package/dist/preview/assets/runtime-DO0anKbw.js +1 -0
  25. package/dist/preview/assets/{runtime-kLWO8JbC.js → runtime-DcStOiOi.js} +1 -1
  26. package/dist/preview/assets/runtime-EVgYW6_7.js +1 -0
  27. package/dist/preview/assets/runtime-i32sR7d3.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/block-layout-editor/index.vue +1 -4
  31. package/dist/runtime/components/config/blocks/2026-05-17/com.shwfed.block.chart.xy/config.vue +5 -0
  32. package/dist/runtime/components/config/blocks/2026-05-17/com.shwfed.block.chart.xy/runtime.vue +2 -2
  33. package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/item.vue +2 -2
  34. package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/schema.js +2 -2
  35. package/dist/runtime/components/config/blocks/2026-06-02/com.shwfed.block.card/badge.vue +3 -2
  36. package/dist/runtime/components/config/blocks/2026-06-02/com.shwfed.block.card/schema.js +2 -2
  37. package/dist/runtime/components/form/config.vue +24 -16
  38. package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/runtime.vue +6 -5
  39. package/dist/runtime/components/form/fields/2026-05-13/com.shwfed.form.field.combobox.single.remote/schema.js +2 -2
  40. package/dist/runtime/components/form/fields/2026-05-23/com.shwfed.form.field.tree.multi/runtime.vue +3 -4
  41. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.multi/runtime.vue +3 -4
  42. package/dist/runtime/components/form/fields/2026-05-26/com.shwfed.form.field.tree.combobox.single/runtime.vue +3 -4
  43. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/runtime.vue +6 -5
  44. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/schema.js +2 -2
  45. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/runtime.vue +6 -5
  46. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/schema.js +2 -2
  47. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.multi/runtime.vue +3 -4
  48. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.combobox.single/runtime.vue +3 -4
  49. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.multi/runtime.vue +3 -4
  50. package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.tree.single/runtime.vue +3 -4
  51. package/dist/runtime/components/form/schema.d.ts +1 -1
  52. package/dist/runtime/components/form/schema.js +8 -3
  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/form/utils/schema-meta.d.ts +2 -0
  56. package/dist/runtime/components/form/utils/schema-meta.js +24 -0
  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-25/com.shwfed.table.column.combobox-multi.remote.options-remote/runtime.vue +7 -6
  60. package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/schema.js +2 -2
  61. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi/runtime.vue +7 -6
  62. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi/schema.js +2 -2
  63. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/runtime.vue +7 -6
  64. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/schema.js +2 -2
  65. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single/runtime.vue +7 -6
  66. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single/schema.js +2 -2
  67. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/runtime.vue +7 -6
  68. package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/schema.js +2 -2
  69. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/runtime.vue +3 -4
  70. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-multi/schema.js +2 -2
  71. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/runtime.vue +3 -4
  72. package/dist/runtime/components/table/columns/2026-05-27/com.shwfed.table.column.tree-combobox-single/schema.js +2 -2
  73. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/runtime.vue +7 -6
  74. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/schema.js +2 -2
  75. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/runtime.vue +7 -6
  76. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/schema.js +2 -2
  77. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/runtime.vue +3 -4
  78. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-multi/schema.js +2 -2
  79. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/runtime.vue +3 -4
  80. package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.tree-combobox-single/schema.js +2 -2
  81. package/dist/runtime/components/table/config.vue +0 -36
  82. package/dist/runtime/components/table/index.vue +3 -4
  83. package/dist/runtime/components/table/schema.js +3 -3
  84. package/dist/runtime/components/ui/expression-editor/ExpressionEditor.d.vue.ts +4 -3
  85. package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue +135 -111
  86. package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue.d.ts +4 -3
  87. package/dist/runtime/share/expression.d.ts +36 -0
  88. package/dist/runtime/share/expression.js +38 -17
  89. package/dist/runtime/share/request.d.ts +29 -0
  90. package/dist/runtime/share/request.js +11 -0
  91. package/dist/runtime/vendor/cel-js/CLAUDE.md +3 -3
  92. package/dist/runtime/vendor/cel-js/PROMPT.md +44 -3
  93. package/dist/runtime/vendor/cel-js/lib/functions.js +2 -2
  94. package/dist/runtime/vendor/cel-js/lib/macros.js +66 -14
  95. package/dist/runtime/vendor/cel-js/lib/optional.js +52 -1
  96. package/package.json +1 -1
  97. package/dist/preview/assets/badge-C-IvPZBx.js +0 -1
  98. package/dist/preview/assets/config-DXlCQMVi.js +0 -1
  99. package/dist/preview/assets/config-Dj0rEZRq.js +0 -1
  100. package/dist/preview/assets/config-_aVQvlhc.js +0 -1
  101. package/dist/preview/assets/config-l01zamcS.js +0 -1
  102. package/dist/preview/assets/definition.vue_vue_type_script_setup_true_lang-BbuC0qEM.js +0 -1
  103. package/dist/preview/assets/index-BNaI1T0H.js +0 -680
  104. package/dist/preview/assets/index-BwoBmSxu.js +0 -1
  105. package/dist/preview/assets/item-GFiAkFW6.js +0 -1
  106. package/dist/preview/assets/runtime-5h5U6Ozr.js +0 -1
  107. package/dist/preview/assets/runtime-B6dXW6zW.js +0 -1
  108. package/dist/preview/assets/runtime-BEOIc4zU.js +0 -1
  109. package/dist/preview/assets/runtime-Bx7G-5dR.js +0 -1
  110. package/dist/preview/assets/runtime-TNDFpOlo.js +0 -1
  111. package/dist/preview/assets/runtime-g9hb36Vh.js +0 -1
@@ -1,11 +1,12 @@
1
1
  <script setup>
2
2
  import { Icon } from "@iconify/vue";
3
- import { Effect } from "effect";
3
+ import { Effect, Option } from "effect";
4
4
  import { Fetch } from "fx-fetch";
5
5
  import { watchDebounced } from "@vueuse/core";
6
6
  import { toast } from "vue-sonner";
7
7
  import { computed, nextTick, ref, watch } from "vue";
8
8
  import { useI18n } from "vue-i18n";
9
+ import { asRequest, fetchJsonOption } from "../../../../../share/request";
9
10
  import { cel as _rawCel } from "../../../../../utils/cel";
10
11
  import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
11
12
  import { getLocalizedText } from "../../../../../share/locale";
@@ -108,10 +109,10 @@ const requestSignature = computed(() => {
108
109
  const expr = props.column.options.request;
109
110
  if (!expr) return null;
110
111
  try {
111
- const builder = Effect.runSync(
112
+ const req = asRequest(Effect.runSync(
112
113
  $cel(expr, { row: row.value, index: rowIndex.value })
113
- );
114
- return JSON.stringify(builder.describe());
114
+ ));
115
+ return Option.isSome(req) ? JSON.stringify(req.value.describe()) : null;
115
116
  } catch {
116
117
  return null;
117
118
  }
@@ -126,8 +127,8 @@ async function fetchOptions() {
126
127
  const expr = props.column.options.request;
127
128
  remoteLoading.value = true;
128
129
  const program = Effect.gen(function* () {
129
- const builder = yield* $cel(expr, { row: row.value, index: rowIndex.value });
130
- return yield* builder.json();
130
+ const json = yield* fetchJsonOption(yield* $cel(expr, { row: row.value, index: rowIndex.value }));
131
+ return Option.getOrNull(json);
131
132
  });
132
133
  try {
133
134
  const result = await Effect.runPromise(Effect.provide(program, sharedFetchLayer));
@@ -1,6 +1,6 @@
1
1
  import { Effect, Schema } from "effect";
2
2
  import { getProperty } from "dot-prop";
3
- import { Expression, LocaleMarkdown } from "../../../../../share/expression.js";
3
+ import { Expression, HttpRequestResult, LocaleMarkdown } from "../../../../../share/expression.js";
4
4
  import { Locale } from "../../../../../share/locale.js";
5
5
  import { Triggers } from "../../../../../share/event-bus.js";
6
6
  import {
@@ -58,7 +58,7 @@ export function remoteOptionsSchema(configure) {
58
58
  configure(env);
59
59
  registerRowVariablesIfAbsent(env);
60
60
  },
61
- resultType: "HttpRequest"
61
+ resultType: HttpRequestResult
62
62
  });
63
63
  const CelOptions = Expression({
64
64
  configure: (env) => {
@@ -6,6 +6,7 @@ import { useI18n } from "vue-i18n";
6
6
  import { cel as _rawCel } from "../../../../../utils/cel";
7
7
  import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
8
8
  import { getLocalizedText } from "../../../../../share/locale";
9
+ import { fetchJsonOption } from "../../../../../share/request";
9
10
  import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "../../../../ui/input-group";
10
11
  import { Markdown } from "../../../../ui/markdown";
11
12
  import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../../../../ui/popover";
@@ -156,12 +157,10 @@ async function fetchTree() {
156
157
  const effect = Effect.gen(function* () {
157
158
  let jsonOpt = Option.none();
158
159
  if (dataSource.request) {
159
- const builder = yield* $cel(dataSource.request, {
160
+ jsonOpt = yield* fetchJsonOption(yield* $cel(dataSource.request, {
160
161
  row: row.value,
161
162
  index: rowIndex.value
162
- });
163
- const response = yield* builder.json();
164
- jsonOpt = Option.some(response);
163
+ }));
165
164
  }
166
165
  const dataRaw = yield* $cel(dataSource.data, {
167
166
  row: row.value,
@@ -1,7 +1,7 @@
1
1
  import { Effect, Schema } from "effect";
2
2
  import { getProperty } from "dot-prop";
3
3
  import { Locale } from "../../../../../share/locale.js";
4
- import { Expression, LocaleMarkdown } from "../../../../../share/expression.js";
4
+ import { Expression, HttpRequestResult, LocaleMarkdown } from "../../../../../share/expression.js";
5
5
  import {
6
6
  CelRowAccess,
7
7
  derivedRowField,
@@ -37,7 +37,7 @@ export function schema(configure) {
37
37
  };
38
38
  const CelDataSourceRequest = Expression({
39
39
  configure: dataSourceConfigure,
40
- resultType: "HttpRequest"
40
+ resultType: HttpRequestResult
41
41
  });
42
42
  const CelDataSourceData = Expression({
43
43
  configure: (env) => {
@@ -6,6 +6,7 @@ import { useI18n } from "vue-i18n";
6
6
  import { cel as _rawCel } from "../../../../../utils/cel";
7
7
  import { celBindings, injectCELContext } from "../../../../../utils/cel-context";
8
8
  import { getLocalizedText } from "../../../../../share/locale";
9
+ import { fetchJsonOption } from "../../../../../share/request";
9
10
  import { InputGroup, InputGroupAddon, InputGroupButton, InputGroupInput } from "../../../../ui/input-group";
10
11
  import { Markdown } from "../../../../ui/markdown";
11
12
  import { Popover, PopoverAnchor, PopoverContent, PopoverTrigger } from "../../../../ui/popover";
@@ -159,12 +160,10 @@ async function fetchTree() {
159
160
  const effect = Effect.gen(function* () {
160
161
  let jsonOpt = Option.none();
161
162
  if (dataSource.request) {
162
- const builder = yield* $cel(dataSource.request, {
163
+ jsonOpt = yield* fetchJsonOption(yield* $cel(dataSource.request, {
163
164
  row: row.value,
164
165
  index: rowIndex.value
165
- });
166
- const response = yield* builder.json();
167
- jsonOpt = Option.some(response);
166
+ }));
168
167
  }
169
168
  const dataRaw = yield* $cel(dataSource.data, {
170
169
  row: row.value,
@@ -1,7 +1,7 @@
1
1
  import { Effect, Schema } from "effect";
2
2
  import { getProperty } from "dot-prop";
3
3
  import { Locale } from "../../../../../share/locale.js";
4
- import { Expression, LocaleMarkdown } from "../../../../../share/expression.js";
4
+ import { Expression, HttpRequestResult, LocaleMarkdown } from "../../../../../share/expression.js";
5
5
  import {
6
6
  CelRowAccess,
7
7
  derivedRowField,
@@ -37,7 +37,7 @@ export function schema(configure) {
37
37
  };
38
38
  const CelDataSourceRequest = Expression({
39
39
  configure: dataSourceConfigure,
40
- resultType: "HttpRequest"
40
+ resultType: HttpRequestResult
41
41
  });
42
42
  const CelDataSourceData = Expression({
43
43
  configure: (env) => {
@@ -1249,12 +1249,6 @@ const tableQueryValue = computed({
1249
1249
  @update:model-value="(v) => updateGeneralOptionalString('rowKey', v)"
1250
1250
  />
1251
1251
  </RowKeyCELContext>
1252
- <p
1253
- v-if="getError('rowKey')"
1254
- class="text-xs text-red-500"
1255
- >
1256
- {{ getError("rowKey") }}
1257
- </p>
1258
1252
  </Field>
1259
1253
 
1260
1254
  <!-- Host slot inside the general grid: a wrapping editor (e.g. the
@@ -1297,12 +1291,6 @@ const tableQueryValue = computed({
1297
1291
  @update:model-value="(v) => updateDataSourceOptional('request', v)"
1298
1292
  />
1299
1293
  </RequestCELContext>
1300
- <p
1301
- v-if="getError('dataSource.request')"
1302
- class="text-xs text-red-500"
1303
- >
1304
- {{ getError("dataSource.request") }}
1305
- </p>
1306
1294
  </Field>
1307
1295
 
1308
1296
  <div class="grid grid-cols-2 gap-x-6 gap-y-4">
@@ -1328,12 +1316,6 @@ const tableQueryValue = computed({
1328
1316
  @update:model-value="(v) => setDataSourceField('data', v)"
1329
1317
  />
1330
1318
  </JsonCELContext>
1331
- <p
1332
- v-if="getError('dataSource.data')"
1333
- class="text-xs text-red-500"
1334
- >
1335
- {{ getError("dataSource.data") }}
1336
- </p>
1337
1319
  </Field>
1338
1320
  <Field orientation="vertical">
1339
1321
  <FieldLabel class="text-xs text-zinc-500">
@@ -1357,12 +1339,6 @@ const tableQueryValue = computed({
1357
1339
  @update:model-value="(v) => updateDataSourceOptional('total', v)"
1358
1340
  />
1359
1341
  </JsonCELContext>
1360
- <p
1361
- v-if="getError('dataSource.total')"
1362
- class="text-xs text-red-500"
1363
- >
1364
- {{ getError("dataSource.total") }}
1365
- </p>
1366
1342
  </Field>
1367
1343
  </div>
1368
1344
  </div>
@@ -1515,12 +1491,6 @@ const tableQueryValue = computed({
1515
1491
  @update:model-value="(v) => updateGeneralOptionalString('cellStyle', v)"
1516
1492
  />
1517
1493
  </CellStyleCELContext>
1518
- <p
1519
- v-if="getError('cellStyle')"
1520
- class="text-xs text-red-500"
1521
- >
1522
- {{ getError("cellStyle") }}
1523
- </p>
1524
1494
  </Field>
1525
1495
 
1526
1496
  <Field orientation="vertical">
@@ -1543,12 +1513,6 @@ const tableQueryValue = computed({
1543
1513
  class="min-h-20 font-mono text-xs"
1544
1514
  @update:model-value="(v) => updateGeneralOptionalString('style', String(v))"
1545
1515
  />
1546
- <p
1547
- v-if="getError('style')"
1548
- class="text-xs text-red-500"
1549
- >
1550
- {{ getError("style") }}
1551
- </p>
1552
1516
  </Field>
1553
1517
  </div>
1554
1518
  </div>
@@ -14,6 +14,7 @@ import { Effect, Fiber, Option } from "effect";
14
14
  import { Fetch } from "fx-fetch";
15
15
  import { Pagination } from "reka-ui/namespaced";
16
16
  import { computed, h, onMounted, ref, toRaw, watch } from "vue";
17
+ import { fetchJsonOption } from "../../share/request";
17
18
  import { useI18n } from "vue-i18n";
18
19
  import { celBindings, provideCELContext, injectCELContext } from "../../utils/cel-context";
19
20
  import TableRowProvider from "./row-provider.vue";
@@ -336,12 +337,10 @@ async function fetchDataSource() {
336
337
  const effect = Effect.gen(function* () {
337
338
  let jsonOpt = Option.none();
338
339
  if (dataSource.request) {
339
- const builder = yield* $cel(
340
+ jsonOpt = yield* fetchJsonOption(yield* $cel(
340
341
  dataSource.request,
341
342
  mergeCelContext({ pageIndex, pageSize })
342
- );
343
- const response = yield* builder.json();
344
- jsonOpt = Option.some(response);
343
+ ));
345
344
  }
346
345
  const nextRowsRaw = yield* $cel(
347
346
  dataSource.data,
@@ -1,5 +1,5 @@
1
1
  import { Schema } from "effect";
2
- import { Expression } from "../../share/expression.js";
2
+ import { Expression, HttpRequestResult } from "../../share/expression.js";
3
3
  import { Locale } from "../../share/locale.js";
4
4
  import { md } from "../../share/markdown.js";
5
5
  import { ActionSchemaFields } from "../actions/schema.js";
@@ -186,7 +186,7 @@ export function DataSource(configure, extras) {
186
186
  configure(env);
187
187
  extras?.request?.(env);
188
188
  },
189
- resultType: "HttpRequest"
189
+ resultType: HttpRequestResult
190
190
  });
191
191
  const CelRows = Expression({
192
192
  configure: (env) => {
@@ -218,7 +218,7 @@ export function tableDataSource(configure) {
218
218
  configure(env);
219
219
  registerDataSourceRequestVars(env);
220
220
  },
221
- resultType: "HttpRequest"
221
+ resultType: HttpRequestResult
222
222
  });
223
223
  const CelRows = Expression({
224
224
  configure: (env) => {
@@ -12,12 +12,13 @@ type __VLS_Props = {
12
12
  placeholder?: string;
13
13
  resultType?: string | string[];
14
14
  extraVars?: Record<string, VarSpec>;
15
+ unlistedVarsAreDyn?: boolean;
15
16
  };
16
- declare var __VLS_14: {}, __VLS_130: {};
17
+ declare var __VLS_13: {}, __VLS_129: {};
17
18
  type __VLS_Slots = {} & {
18
- leading?: (props: typeof __VLS_14) => any;
19
+ leading?: (props: typeof __VLS_13) => any;
19
20
  } & {
20
- trailing?: (props: typeof __VLS_130) => any;
21
+ trailing?: (props: typeof __VLS_129) => any;
21
22
  };
22
23
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
23
24
  "update:modelValue": (payload: string) => any;
@@ -1,6 +1,7 @@
1
1
  <script setup>
2
2
  import { Icon } from "@iconify/vue";
3
3
  import { computed, ref, useSlots, useTemplateRef, watch } from "vue";
4
+ import { buildCheckEnvironment, evaluateExpression } from "../../../share/expression";
4
5
  import { injectCELContext, useScopeAncestry } from "../../../utils/cel-context";
5
6
  import { Markdown } from "../markdown";
6
7
  import CodeMirrorInput from "./CodeMirrorInput.vue";
@@ -17,7 +18,8 @@ const props = defineProps({
17
18
  multiline: { type: Boolean, required: false },
18
19
  placeholder: { type: String, required: false },
19
20
  resultType: { type: [String, Array], required: false },
20
- extraVars: { type: Object, required: false }
21
+ extraVars: { type: Object, required: false },
22
+ unlistedVarsAreDyn: { type: Boolean, required: false }
21
23
  });
22
24
  const emits = defineEmits(["update:modelValue"]);
23
25
  const celContext = injectCELContext();
@@ -26,6 +28,20 @@ const varEntries = computed(() => buildVarEntries(celContext, props.extraVars));
26
28
  const scopeEntries = computed(() => buildScopeEntries(scopeAncestry.value.slice(1)));
27
29
  const scopeLookup = computed(() => buildScopeLookup(scopeAncestry.value));
28
30
  const hasVars = computed(() => varEntries.value.length > 0 || scopeEntries.value.length > 0);
31
+ const checkEnvironment = computed(() => {
32
+ const vars = /* @__PURE__ */ new Map();
33
+ for (const [name, entry] of Object.entries(celContext)) vars.set(name, entry.type);
34
+ for (const [name, spec] of Object.entries(props.extraVars ?? {})) vars.set(name, spec.type);
35
+ return buildCheckEnvironment(
36
+ [...vars].map(([name, type]) => ({ name, type })),
37
+ { unlistedVariablesAreDyn: props.unlistedVarsAreDyn }
38
+ );
39
+ });
40
+ const validationError = computed(() => {
41
+ const value = props.modelValue ?? props.defaultValue ?? "";
42
+ if (value.trim() === "") return null;
43
+ return evaluateExpression(checkEnvironment.value, value, props.resultType);
44
+ });
29
45
  const open = ref(false);
30
46
  const entries = ref([]);
31
47
  const shownVars = computed(() => entries.value.filter((e) => e.group === "var"));
@@ -60,120 +76,128 @@ const addonAlign = computed(
60
76
  </script>
61
77
 
62
78
  <template>
63
- <InputGroup>
64
- <InputGroupAddon
65
- v-if="$slots.leading"
66
- align="inline-start"
67
- >
68
- <slot name="leading" />
69
- </InputGroupAddon>
70
- <CodeMirrorInput
71
- ref="editor"
72
- :model-value="props.modelValue"
73
- :default-value="props.defaultValue"
74
- :placeholder="props.placeholder"
75
- :multiline="props.multiline"
76
- :scope-lookup="scopeLookup"
77
- :class="props.class"
78
- @update:model-value="(v) => emits('update:modelValue', v)"
79
- />
80
- <InputGroupAddon
81
- v-if="showAddon"
82
- :align="addonAlign"
83
- class="justify-end gap-1.5"
84
- >
85
- <Popover
86
- v-if="hasVars"
87
- v-model:open="open"
79
+ <div class="flex flex-col gap-1.5">
80
+ <InputGroup>
81
+ <InputGroupAddon
82
+ v-if="$slots.leading"
83
+ align="inline-start"
88
84
  >
89
- <PopoverTrigger as-child>
90
- <InputGroupButton
91
- size="icon-xs"
92
- aria-label="Inspect available variables"
93
- >
94
- <Icon icon="fluent:braces-variable-20-regular" />
95
- </InputGroupButton>
96
- </PopoverTrigger>
97
- <PopoverContent
98
- align="end"
99
- :side-offset="6"
100
- class="group/popover w-80 p-0 data-[side=top]:**:data-[slot=command-input-wrapper]:border-t data-[side=top]:**:data-[slot=command-input-wrapper]:border-b-0"
85
+ <slot name="leading" />
86
+ </InputGroupAddon>
87
+ <CodeMirrorInput
88
+ ref="editor"
89
+ :model-value="props.modelValue"
90
+ :default-value="props.defaultValue"
91
+ :placeholder="props.placeholder"
92
+ :multiline="props.multiline"
93
+ :scope-lookup="scopeLookup"
94
+ :class="props.class"
95
+ @update:model-value="(v) => emits('update:modelValue', v)"
96
+ />
97
+ <InputGroupAddon
98
+ v-if="showAddon"
99
+ :align="addonAlign"
100
+ class="justify-end gap-1.5"
101
+ >
102
+ <Popover
103
+ v-if="hasVars"
104
+ v-model:open="open"
101
105
  >
102
- <Command class="rounded group-data-[side=top]/popover:flex-col-reverse">
103
- <CommandInput placeholder="搜索可用变量" />
104
- <CommandList class="max-h-48 overflow-y-auto">
105
- <CommandEmpty>No variables.</CommandEmpty>
106
- <CommandGroup>
107
- <CommandItem
108
- v-for="entry in shownVars"
109
- :key="entry.id"
110
- :value="entry.display"
111
- class="cursor-pointer gap-2"
112
- @select="insertVariable(entry.insert)"
113
- @mouseenter="hoveredName = entry.id"
114
- @focus="hoveredName = entry.id"
106
+ <PopoverTrigger as-child>
107
+ <InputGroupButton
108
+ size="icon-xs"
109
+ aria-label="Inspect available variables"
110
+ >
111
+ <Icon icon="fluent:braces-variable-20-regular" />
112
+ </InputGroupButton>
113
+ </PopoverTrigger>
114
+ <PopoverContent
115
+ align="end"
116
+ :side-offset="6"
117
+ class="group/popover w-80 p-0 data-[side=top]:**:data-[slot=command-input-wrapper]:border-t data-[side=top]:**:data-[slot=command-input-wrapper]:border-b-0"
118
+ >
119
+ <Command class="rounded group-data-[side=top]/popover:flex-col-reverse">
120
+ <CommandInput placeholder="搜索可用变量" />
121
+ <CommandList class="max-h-48 overflow-y-auto">
122
+ <CommandEmpty>No variables.</CommandEmpty>
123
+ <CommandGroup>
124
+ <CommandItem
125
+ v-for="entry in shownVars"
126
+ :key="entry.id"
127
+ :value="entry.display"
128
+ class="cursor-pointer gap-2"
129
+ @select="insertVariable(entry.insert)"
130
+ @mouseenter="hoveredName = entry.id"
131
+ @focus="hoveredName = entry.id"
132
+ >
133
+ <Icon
134
+ icon="fluent:braces-variable-20-regular"
135
+ class="size-3.5 shrink-0 text-zinc-400"
136
+ />
137
+ <span class="font-mono text-xs text-zinc-800">{{ entry.display }}</span>
138
+ <span class="flex-1 truncate text-xs text-zinc-500">{{ entry.label }}</span>
139
+ <span class="rounded bg-purple-100 px-1.5 py-0.5 font-mono text-[10px] leading-none text-purple-700 select-none">
140
+ {{ entry.type }}
141
+ </span>
142
+ </CommandItem>
143
+ </CommandGroup>
144
+ <CommandGroup
145
+ v-if="shownScopes.length > 0"
146
+ heading="跨层引用"
115
147
  >
116
- <Icon
117
- icon="fluent:braces-variable-20-regular"
118
- class="size-3.5 shrink-0 text-zinc-400"
119
- />
120
- <span class="font-mono text-xs text-zinc-800">{{ entry.display }}</span>
121
- <span class="flex-1 truncate text-xs text-zinc-500">{{ entry.label }}</span>
122
- <span class="rounded bg-purple-100 px-1.5 py-0.5 font-mono text-[10px] leading-none text-purple-700 select-none">
123
- {{ entry.type }}
124
- </span>
125
- </CommandItem>
126
- </CommandGroup>
127
- <CommandGroup
128
- v-if="shownScopes.length > 0"
129
- heading="跨层引用"
148
+ <CommandItem
149
+ v-for="entry in shownScopes"
150
+ :key="entry.id"
151
+ :value="`${entry.display} ${entry.id}`"
152
+ class="cursor-pointer gap-2"
153
+ @select="insertVariable(entry.insert)"
154
+ @mouseenter="hoveredName = entry.id"
155
+ @focus="hoveredName = entry.id"
156
+ >
157
+ <Icon
158
+ icon="fluent:link-20-regular"
159
+ class="size-3.5 shrink-0 text-zinc-400"
160
+ />
161
+ <span class="flex-1 truncate text-xs text-zinc-700">{{ entry.display }}</span>
162
+ <span class="rounded bg-purple-100 px-1.5 py-0.5 font-mono text-[10px] leading-none text-purple-700 select-none">
163
+ {{ entry.type }}
164
+ </span>
165
+ </CommandItem>
166
+ </CommandGroup>
167
+ </CommandList>
168
+ <div
169
+ v-if="hoveredEntry"
170
+ class="border-t border-zinc-200 px-3 py-2 group-data-[side=top]/popover:border-t-0 group-data-[side=top]/popover:border-b"
130
171
  >
131
- <CommandItem
132
- v-for="entry in shownScopes"
133
- :key="entry.id"
134
- :value="`${entry.display} ${entry.id}`"
135
- class="cursor-pointer gap-2"
136
- @select="insertVariable(entry.insert)"
137
- @mouseenter="hoveredName = entry.id"
138
- @focus="hoveredName = entry.id"
139
- >
140
- <Icon
141
- icon="fluent:link-20-regular"
142
- class="size-3.5 shrink-0 text-zinc-400"
143
- />
144
- <span class="flex-1 truncate text-xs text-zinc-700">{{ entry.display }}</span>
145
- <span class="rounded bg-purple-100 px-1.5 py-0.5 font-mono text-[10px] leading-none text-purple-700 select-none">
146
- {{ entry.type }}
172
+ <div class="flex items-center gap-2">
173
+ <span class="text-xs font-medium text-zinc-700">{{ hoveredEntry.label }}</span>
174
+ <span class="ml-auto shrink-0 rounded bg-purple-100 px-1.5 py-0.5 font-mono text-[10px] leading-none text-purple-700 select-none">
175
+ {{ hoveredEntry.type }}
147
176
  </span>
148
- </CommandItem>
149
- </CommandGroup>
150
- </CommandList>
151
- <div
152
- v-if="hoveredEntry"
153
- class="border-t border-zinc-200 px-3 py-2 group-data-[side=top]/popover:border-t-0 group-data-[side=top]/popover:border-b"
154
- >
155
- <div class="flex items-center gap-2">
156
- <span class="text-xs font-medium text-zinc-700">{{ hoveredEntry.label }}</span>
157
- <span class="ml-auto shrink-0 rounded bg-purple-100 px-1.5 py-0.5 font-mono text-[10px] leading-none text-purple-700 select-none">
158
- {{ hoveredEntry.type }}
159
- </span>
177
+ </div>
178
+ <Markdown
179
+ v-if="hoveredDescription"
180
+ :source="hoveredDescription"
181
+ class="prose prose-zinc prose-sm mt-1 text-xs"
182
+ />
160
183
  </div>
161
- <Markdown
162
- v-if="hoveredDescription"
163
- :source="hoveredDescription"
164
- class="prose prose-zinc prose-sm mt-1 text-xs"
165
- />
166
- </div>
167
- </Command>
168
- </PopoverContent>
169
- </Popover>
170
- <span
171
- v-if="resultTypeLabel"
172
- class="rounded bg-purple-100 px-1.5 py-0.5 font-mono text-[10px] leading-none text-purple-700 select-none"
173
- >
174
- {{ resultTypeLabel }}
175
- </span>
176
- <slot name="trailing" />
177
- </InputGroupAddon>
178
- </InputGroup>
184
+ </Command>
185
+ </PopoverContent>
186
+ </Popover>
187
+ <span
188
+ v-if="resultTypeLabel"
189
+ class="rounded bg-purple-100 px-1.5 py-0.5 font-mono text-[10px] leading-none text-purple-700 select-none"
190
+ >
191
+ {{ resultTypeLabel }}
192
+ </span>
193
+ <slot name="trailing" />
194
+ </InputGroupAddon>
195
+ </InputGroup>
196
+ <p
197
+ v-if="validationError"
198
+ class="text-xs text-red-500"
199
+ >
200
+ {{ validationError }}
201
+ </p>
202
+ </div>
179
203
  </template>
@@ -12,12 +12,13 @@ type __VLS_Props = {
12
12
  placeholder?: string;
13
13
  resultType?: string | string[];
14
14
  extraVars?: Record<string, VarSpec>;
15
+ unlistedVarsAreDyn?: boolean;
15
16
  };
16
- declare var __VLS_14: {}, __VLS_130: {};
17
+ declare var __VLS_13: {}, __VLS_129: {};
17
18
  type __VLS_Slots = {} & {
18
- leading?: (props: typeof __VLS_14) => any;
19
+ leading?: (props: typeof __VLS_13) => any;
19
20
  } & {
20
- trailing?: (props: typeof __VLS_130) => any;
21
+ trailing?: (props: typeof __VLS_129) => any;
21
22
  };
22
23
  declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
23
24
  "update:modelValue": (payload: string) => any;
@@ -2,6 +2,42 @@ 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;
18
+ /**
19
+ * Type-check `expression` against `env` and, if `resultType` is given, verify the
20
+ * inferred type satisfies it. Returns a Chinese error message, or `null` when the
21
+ * expression is valid. This is the single chokepoint both the schema validator
22
+ * (`Expression`'s filter) and the live `ExpressionEditor` call, so an inline
23
+ * verdict can never disagree with the save-time decode.
24
+ */
25
+ export declare function evaluateExpression(env: Environment, expression: string, resultType?: ResultType): string | null;
26
+ /**
27
+ * Build a checking `Environment` from a flat list of `{ name, type }` variable
28
+ * specs — the projection an `ExpressionEditor` already holds via its injected CEL
29
+ * context plus `extraVars`. Functions/operators come free from the cloned
30
+ * `globalRegistry`; only variables are host-scoped, so this is all the editor
31
+ * needs to reproduce the schema's validation env. `__scopes__` is registered
32
+ * canonically here (and skipped from `vars`) exactly as `Expression` does, so
33
+ * cross-layer addressing type-checks in the editor too.
34
+ */
35
+ export declare function buildCheckEnvironment(vars: Iterable<{
36
+ name: string;
37
+ type: string;
38
+ }>, options?: {
39
+ unlistedVariablesAreDyn?: boolean;
40
+ }): Environment;
5
41
  export declare function Expression(options: {
6
42
  configure: (env: Environment) => void;
7
43
  resultType?: ResultType;