@dou-ui/form-builder 0.0.0-stage → 0.1.0-alpha.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/dist/builder/canvas.js +695 -0
  4. package/dist/builder/canvas.js.map +1 -0
  5. package/dist/builder/completion.js +49 -0
  6. package/dist/builder/completion.js.map +1 -0
  7. package/dist/builder/condition-editor.js +6 -0
  8. package/dist/builder/condition-editor.js.map +1 -0
  9. package/dist/builder/condition-editor.vue_vue_type_script_setup_true_lang.js +410 -0
  10. package/dist/builder/condition-editor.vue_vue_type_script_setup_true_lang.js.map +1 -0
  11. package/dist/builder/condition.js +159 -0
  12. package/dist/builder/condition.js.map +1 -0
  13. package/dist/builder/context.js +477 -0
  14. package/dist/builder/context.js.map +1 -0
  15. package/dist/builder/core/commands.js +373 -0
  16. package/dist/builder/core/commands.js.map +1 -0
  17. package/dist/builder/core/history.js +76 -0
  18. package/dist/builder/core/history.js.map +1 -0
  19. package/dist/builder/core/transaction.js +298 -0
  20. package/dist/builder/core/transaction.js.map +1 -0
  21. package/dist/builder/drag.js +466 -0
  22. package/dist/builder/drag.js.map +1 -0
  23. package/dist/builder/expression-box.js +19 -0
  24. package/dist/builder/expression-box.js.map +1 -0
  25. package/dist/builder/expression-input.js +6 -0
  26. package/dist/builder/expression-input.js.map +1 -0
  27. package/dist/builder/expression-input.vue_vue_type_script_setup_true_lang.js +117 -0
  28. package/dist/builder/expression-input.vue_vue_type_script_setup_true_lang.js.map +1 -0
  29. package/dist/builder/extension.js +47 -0
  30. package/dist/builder/extension.js.map +1 -0
  31. package/dist/builder/form-builder.js +6 -0
  32. package/dist/builder/form-builder.js.map +1 -0
  33. package/dist/builder/form-builder.vue_vue_type_script_setup_true_lang.js +450 -0
  34. package/dist/builder/form-builder.vue_vue_type_script_setup_true_lang.js.map +1 -0
  35. package/dist/builder/index.js +22 -0
  36. package/dist/builder/index.js.map +1 -0
  37. package/dist/builder/inspector.js +6 -0
  38. package/dist/builder/inspector.js.map +1 -0
  39. package/dist/builder/inspector.vue_vue_type_script_setup_true_lang.js +442 -0
  40. package/dist/builder/inspector.vue_vue_type_script_setup_true_lang.js.map +1 -0
  41. package/dist/builder/json-dialog.js +6 -0
  42. package/dist/builder/json-dialog.js.map +1 -0
  43. package/dist/builder/json-dialog.vue_vue_type_script_setup_true_lang.js +281 -0
  44. package/dist/builder/json-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
  45. package/dist/builder/locale.js +1271 -0
  46. package/dist/builder/locale.js.map +1 -0
  47. package/dist/builder/logic-fields.js +18 -0
  48. package/dist/builder/logic-fields.js.map +1 -0
  49. package/dist/builder/logic.js +332 -0
  50. package/dist/builder/logic.js.map +1 -0
  51. package/dist/builder/menu.js +92 -0
  52. package/dist/builder/menu.js.map +1 -0
  53. package/dist/builder/outline-row.js +6 -0
  54. package/dist/builder/outline-row.js.map +1 -0
  55. package/dist/builder/outline-row.vue_vue_type_script_setup_true_lang.js +88 -0
  56. package/dist/builder/outline-row.vue_vue_type_script_setup_true_lang.js.map +1 -0
  57. package/dist/builder/outline.js +6 -0
  58. package/dist/builder/outline.js.map +1 -0
  59. package/dist/builder/outline.vue_vue_type_script_setup_true_lang.js +111 -0
  60. package/dist/builder/outline.vue_vue_type_script_setup_true_lang.js.map +1 -0
  61. package/dist/builder/palette.js +6 -0
  62. package/dist/builder/palette.js.map +1 -0
  63. package/dist/builder/palette.vue_vue_type_script_setup_true_lang.js +96 -0
  64. package/dist/builder/palette.vue_vue_type_script_setup_true_lang.js.map +1 -0
  65. package/dist/builder/preview.js +6 -0
  66. package/dist/builder/preview.js.map +1 -0
  67. package/dist/builder/preview.vue_vue_type_script_setup_true_lang.js +111 -0
  68. package/dist/builder/preview.vue_vue_type_script_setup_true_lang.js.map +1 -0
  69. package/dist/builder/settings-binding.js +57 -0
  70. package/dist/builder/settings-binding.js.map +1 -0
  71. package/dist/builder/settings.js +487 -0
  72. package/dist/builder/settings.js.map +1 -0
  73. package/dist/builder/span-field.js +104 -0
  74. package/dist/builder/span-field.js.map +1 -0
  75. package/dist/code/expression-input.js +6 -0
  76. package/dist/code/expression-input.js.map +1 -0
  77. package/dist/code/expression-input.vue_vue_type_script_setup_true_lang.js +88 -0
  78. package/dist/code/expression-input.vue_vue_type_script_setup_true_lang.js.map +1 -0
  79. package/dist/code/extension.js +202 -0
  80. package/dist/code/extension.js.map +1 -0
  81. package/dist/code/index.js +19 -0
  82. package/dist/code/index.js.map +1 -0
  83. package/dist/code/language.js +43 -0
  84. package/dist/code/language.js.map +1 -0
  85. package/dist/collaboration/index.js +382 -0
  86. package/dist/collaboration/index.js.map +1 -0
  87. package/dist/collaboration/order.js +88 -0
  88. package/dist/collaboration/order.js.map +1 -0
  89. package/dist/core/check.js +314 -0
  90. package/dist/core/check.js.map +1 -0
  91. package/dist/core/document.js +112 -0
  92. package/dist/core/document.js.map +1 -0
  93. package/dist/core/expression.js +854 -0
  94. package/dist/core/expression.js.map +1 -0
  95. package/dist/core/formulas.js +242 -0
  96. package/dist/core/formulas.js.map +1 -0
  97. package/dist/core/rules.js +83 -0
  98. package/dist/core/rules.js.map +1 -0
  99. package/dist/core/values.js +80 -0
  100. package/dist/core/values.js.map +1 -0
  101. package/dist/fields/builtin.js +167 -0
  102. package/dist/fields/builtin.js.map +1 -0
  103. package/dist/fields/components.js +155 -0
  104. package/dist/fields/components.js.map +1 -0
  105. package/dist/fields/define.js +44 -0
  106. package/dist/fields/define.js.map +1 -0
  107. package/dist/fields/format.js +125 -0
  108. package/dist/fields/format.js.map +1 -0
  109. package/dist/fields/options.js +54 -0
  110. package/dist/fields/options.js.map +1 -0
  111. package/dist/index.js +20 -0
  112. package/dist/locale.js +161 -0
  113. package/dist/locale.js.map +1 -0
  114. package/dist/renderer/containers.js +430 -0
  115. package/dist/renderer/containers.js.map +1 -0
  116. package/dist/renderer/context.js +21 -0
  117. package/dist/renderer/context.js.map +1 -0
  118. package/dist/renderer/form-renderer.js +6 -0
  119. package/dist/renderer/form-renderer.js.map +1 -0
  120. package/dist/renderer/form-renderer.vue_vue_type_script_setup_true_lang.js +272 -0
  121. package/dist/renderer/form-renderer.vue_vue_type_script_setup_true_lang.js.map +1 -0
  122. package/dist/renderer/index.js +19 -0
  123. package/dist/renderer/index.js.map +1 -0
  124. package/dist/renderer/node-view.js +385 -0
  125. package/dist/renderer/node-view.js.map +1 -0
  126. package/dist/style.css +1 -0
  127. package/dist/style.d.ts +1 -0
  128. package/dist/style.js +27 -0
  129. package/dist/types/builder/canvas.d.ts +5 -0
  130. package/dist/types/builder/completion.d.ts +35 -0
  131. package/dist/types/builder/condition-editor.vue.d.ts +17 -0
  132. package/dist/types/builder/condition.d.ts +37 -0
  133. package/dist/types/builder/context.d.ts +149 -0
  134. package/dist/types/builder/core/commands.d.ts +74 -0
  135. package/dist/types/builder/core/history.d.ts +23 -0
  136. package/dist/types/builder/core/transaction.d.ts +108 -0
  137. package/dist/types/builder/drag.d.ts +52 -0
  138. package/dist/types/builder/expression-box.d.ts +8 -0
  139. package/dist/types/builder/expression-input.vue.d.ts +29 -0
  140. package/dist/types/builder/extension.d.ts +149 -0
  141. package/dist/types/builder/form-builder.vue.d.ts +24 -0
  142. package/dist/types/builder/index.d.ts +76 -0
  143. package/dist/types/builder/inspector.vue.d.ts +3 -0
  144. package/dist/types/builder/json-dialog.vue.d.ts +10 -0
  145. package/dist/types/builder/locale.d.ts +195 -0
  146. package/dist/types/builder/logic-fields.d.ts +2 -0
  147. package/dist/types/builder/logic.d.ts +57 -0
  148. package/dist/types/builder/menu.d.ts +23 -0
  149. package/dist/types/builder/outline-row.vue.d.ts +19 -0
  150. package/dist/types/builder/outline.vue.d.ts +3 -0
  151. package/dist/types/builder/palette.vue.d.ts +3 -0
  152. package/dist/types/builder/preview.vue.d.ts +3 -0
  153. package/dist/types/builder/settings-binding.d.ts +23 -0
  154. package/dist/types/builder/settings.d.ts +49 -0
  155. package/dist/types/builder/span-field.d.ts +4 -0
  156. package/dist/types/builder/types.d.ts +59 -0
  157. package/dist/types/code/expression-input.vue.d.ts +23 -0
  158. package/dist/types/code/extension.d.ts +45 -0
  159. package/dist/types/code/index.d.ts +12 -0
  160. package/dist/types/code/language.d.ts +6 -0
  161. package/dist/types/collaboration/index.d.ts +64 -0
  162. package/dist/types/collaboration/order.d.ts +20 -0
  163. package/dist/types/core/check.d.ts +68 -0
  164. package/dist/types/core/document.d.ts +36 -0
  165. package/dist/types/core/expression.d.ts +175 -0
  166. package/dist/types/core/formulas.d.ts +44 -0
  167. package/dist/types/core/rules.d.ts +23 -0
  168. package/dist/types/core/types.d.ts +211 -0
  169. package/dist/types/core/values.d.ts +22 -0
  170. package/dist/types/fields/builtin.d.ts +9 -0
  171. package/dist/types/fields/components.d.ts +177 -0
  172. package/dist/types/fields/define.d.ts +93 -0
  173. package/dist/types/fields/format.d.ts +76 -0
  174. package/dist/types/fields/options.d.ts +11 -0
  175. package/dist/types/index.d.ts +3 -0
  176. package/dist/types/locale.d.ts +45 -0
  177. package/dist/types/renderer/containers.d.ts +20 -0
  178. package/dist/types/renderer/context.d.ts +186 -0
  179. package/dist/types/renderer/form-renderer.vue.d.ts +25 -0
  180. package/dist/types/renderer/index.d.ts +81 -0
  181. package/dist/types/renderer/node-view.d.ts +56 -0
  182. package/package.json +88 -4
@@ -0,0 +1 @@
1
+ {"version":3,"file":"condition-editor.vue_vue_type_script_setup_true_lang.js","names":["_openBlock","_createElementBlock","_unref","_createCommentVNode","_Fragment","_createBlock","_renderList","_createElementVNode","_createVNode","_withCtx","ExpressionInput","_createTextVNode","_toDisplayString"],"sources":["../../src/builder/condition-editor.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { computed, shallowRef, watch } from 'vue'\nimport {\n DouButton,\n DouInput,\n DouInputNumber,\n DouSegmentedControl,\n DouSelect,\n DouTooltip,\n useFormReadonly,\n} from 'dou-ui'\nimport type { SelectValue } from 'dou-ui'\nimport { BracesIcon, CloseIcon, FilterIcon, PlusIcon } from '@dou-ui/icons'\nimport { parseCondition, printCondition, unaryOperators } from './condition'\nimport type { Condition, ConditionLiteral, ConditionOperator, ConditionRow } from './condition'\nimport { useBuilderState } from './context'\nimport ExpressionInput from './expression-box'\nimport { operatorsOf } from './logic'\nimport type { LogicTarget } from './logic'\n\n/**\n * A condition as rows of \"field, how, value\", written to the node as\n * expression text. An expression the rows cannot say is edited as text.\n */\ndefineOptions({ name: 'DouFormBuilderCondition' })\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string | null\n /** The fields the rows can read. */\n targets?: LogicTarget[]\n disabled?: boolean\n }>(),\n { modelValue: '', targets: () => [] },\n)\nconst emit = defineEmits<{ 'update:modelValue': [value: string] }>()\n\nconst state = useBuilderState()\nconst words = computed(() => state.messages.condition)\n// Read-only, the rows show as they are, without buttons to change them.\nconst readonly = useFormReadonly(() => state.readonly)\n\nconst condition = shallowRef<Condition>({ join: 'and', rows: [] })\nconst asText = shallowRef(false)\n/** The text this editor wrote last, which needs no reading back. */\nlet written: string | undefined\n\nwatch(\n () => props.modelValue ?? '',\n (source) => {\n if (source === written) return\n written = undefined\n const parsed = parseCondition(source)\n asText.value = !parsed\n if (parsed) condition.value = parsed\n },\n { immediate: true },\n)\n\nfunction commit(next: Condition) {\n condition.value = next\n const text = printCondition(next)\n written = text\n if (text !== (props.modelValue ?? '')) emit('update:modelValue', text)\n}\n\nconst keyOf = (scope: string, path: string) => `${scope}:${path}`\nconst option = (target: LogicTarget) => ({\n value: keyOf(target.scope, target.path),\n label: target.label === target.path ? target.path : `${target.label} · ${target.path}`,\n})\nconst targetsByKey = computed(\n () => new Map(props.targets.map((target) => [keyOf(target.scope, target.path), target])),\n)\nconst fieldOptions = computed(() => {\n const own = props.targets.filter((target) => target.scope === 'item')\n const all = props.targets.filter((target) => target.scope === 'values')\n if (!own.length) return all.map(option)\n return [\n { label: words.value.itemGroup, options: own.map(option) },\n { label: words.value.formGroup, options: all.map(option) },\n ]\n})\n\nconst targetOf = (row: ConditionRow) => targetsByKey.value.get(keyOf(row.scope, row.path))\nconst operators = (row: ConditionRow): ConditionOperator[] => {\n const target = targetOf(row)\n return target ? operatorsOf[target.kind] : operatorsOf.text\n}\nfunction operatorOptions(row: ConditionRow) {\n const date = targetOf(row)?.kind === 'date'\n const labels = words.value.operators\n const dates = words.value.dateOperators\n return operators(row).map((op) => ({\n value: op,\n label: (date ? dates[op] : undefined) ?? labels[op] ?? op,\n }))\n}\n\nfunction setRow(index: number, patch: Partial<ConditionRow>) {\n const rows = condition.value.rows.slice()\n rows[index] = { ...rows[index]!, ...patch }\n commit({ ...condition.value, rows })\n}\n\nfunction pickField(index: number, key: SelectValue | SelectValue[] | null | undefined) {\n const target = targetsByKey.value.get(String(key))\n if (!target) return\n const row = condition.value.rows[index]!\n const ops = operatorsOf[target.kind]\n const op = ops.includes(row.op) ? row.op : ops[0]!\n setRow(index, { scope: target.scope, path: target.path, op, value: initial(target, op) })\n}\n\nfunction initial(target: LogicTarget, op: ConditionOperator) {\n if (unaryOperators.has(op)) return undefined\n if (target.kind === 'boolean') return true\n return op === 'in' ? [] : undefined\n}\n\nfunction pickOperator(index: number, op: ConditionOperator) {\n const row = condition.value.rows[index]!\n const target = targetOf(row)\n const keep = !unaryOperators.has(op) && (op === 'in') === Array.isArray(row.value)\n setRow(index, { op, value: keep ? row.value : target ? initial(target, op) : undefined })\n}\n\nfunction addRow() {\n const first = props.targets[0]\n const row: ConditionRow = first\n ? {\n scope: first.scope,\n path: first.path,\n op: operatorsOf[first.kind][0]!,\n value: initial(first, operatorsOf[first.kind][0]!),\n }\n : { scope: 'values', path: '', op: 'eq' }\n commit({ ...condition.value, rows: [...condition.value.rows, row] })\n}\n\nfunction removeRow(index: number) {\n const rows = condition.value.rows.filter((_, at) => at !== index)\n commit({ ...condition.value, rows })\n}\n\nconst joinOptions = computed(() => [\n { value: 'and', label: words.value.all },\n { value: 'or', label: words.value.any },\n])\n\n/** What a row's value input is. */\nfunction valueInput(row: ConditionRow) {\n if (unaryOperators.has(row.op)) return 'none'\n const target = targetOf(row)\n if (!target) return 'text'\n if (target.kind === 'boolean') return 'boolean'\n if (row.op === 'in' || target.options?.length) return 'select'\n if (target.kind === 'number') return 'number'\n return 'text'\n}\n\nconst booleanOptions = computed(() => [\n { value: true, label: words.value.yes },\n { value: false, label: words.value.no },\n])\n\nfunction selectOptions(row: ConditionRow) {\n return (targetOf(row)?.options ?? []) as { label: string; value: SelectValue }[]\n}\n\nconst canUseRows = computed(() => !!parseCondition(props.modelValue ?? ''))\nfunction toRows() {\n const parsed = parseCondition(props.modelValue ?? '')\n if (!parsed) return\n condition.value = parsed\n asText.value = false\n}\n\nconst names = computed(() =>\n props.targets\n .filter((target) => target.scope === 'values')\n .map((target) => ({ path: target.path, label: target.label })),\n)\nconst itemNames = computed(() => {\n const own = props.targets.filter((target) => target.scope === 'item')\n return own.length ? own.map((target) => ({ path: target.path, label: target.label })) : undefined\n})\nconst textValue = computed({\n get: () => props.modelValue ?? '',\n // Text typed here stays text, even once it could be shown as rows.\n set: (value: string) => {\n written = value\n emit('update:modelValue', value)\n },\n})\n</script>\n\n<template>\n <div class=\"dou-form-builder__condition\">\n <!-- Read-only, a condition not set shows a dash. -->\n <div\n v-if=\"readonly && !asText && !condition.rows.length\"\n class=\"dou-form-builder__condition-empty\"\n >\n —\n </div>\n <template v-if=\"!asText\">\n <DouSegmentedControl\n v-if=\"condition.rows.length > 1\"\n :model-value=\"condition.join\"\n :options=\"joinOptions\"\n :disabled=\"disabled\"\n size=\"sm\"\n block\n @update:model-value=\"commit({ ...condition, join: $event as 'and' | 'or' })\"\n />\n <div\n v-for=\"(row, index) in condition.rows\"\n :key=\"index\"\n class=\"dou-form-builder__condition-row\"\n role=\"group\"\n :aria-label=\"`${words.row} ${index + 1}`\"\n >\n <div class=\"dou-form-builder__condition-line\">\n <DouSelect\n :model-value=\"row.path ? keyOf(row.scope, row.path) : null\"\n :options=\"fieldOptions\"\n :placeholder=\"words.field\"\n :aria-label=\"words.field\"\n :disabled=\"disabled\"\n :filterable=\"targets.length > 8\"\n size=\"sm\"\n class=\"dou-form-builder__condition-field\"\n @update:model-value=\"pickField(index, $event)\"\n />\n <DouTooltip v-if=\"!readonly\" :content=\"words.remove\">\n <DouButton\n :aria-label=\"words.remove\"\n :disabled=\"disabled\"\n size=\"sm\"\n variant=\"ghost\"\n @click=\"removeRow(index)\"\n >\n <CloseIcon />\n </DouButton>\n </DouTooltip>\n </div>\n <div class=\"dou-form-builder__condition-line\">\n <DouSelect\n :model-value=\"row.op\"\n :options=\"operatorOptions(row)\"\n :aria-label=\"words.operator\"\n :disabled=\"disabled\"\n size=\"sm\"\n class=\"dou-form-builder__condition-op\"\n @update:model-value=\"pickOperator(index, $event as ConditionOperator)\"\n />\n <template v-if=\"valueInput(row) !== 'none'\">\n <DouSelect\n v-if=\"valueInput(row) === 'boolean'\"\n :model-value=\"row.value as SelectValue\"\n :options=\"booleanOptions\"\n :aria-label=\"words.value\"\n :disabled=\"disabled\"\n size=\"sm\"\n class=\"dou-form-builder__condition-value\"\n @update:model-value=\"setRow(index, { value: $event as boolean })\"\n />\n <DouSelect\n v-else-if=\"valueInput(row) === 'select'\"\n :model-value=\"row.value as SelectValue | SelectValue[]\"\n :options=\"selectOptions(row)\"\n :multiple=\"row.op === 'in'\"\n :creatable=\"!selectOptions(row).length\"\n :filterable=\"!selectOptions(row).length\"\n :placeholder=\"words.value\"\n :aria-label=\"words.value\"\n :disabled=\"disabled\"\n size=\"sm\"\n class=\"dou-form-builder__condition-value\"\n @update:model-value=\"\n setRow(index, { value: $event as ConditionLiteral | ConditionLiteral[] })\n \"\n />\n <DouInputNumber\n v-else-if=\"valueInput(row) === 'number'\"\n :model-value=\"typeof row.value === 'number' ? row.value : null\"\n :controls=\"false\"\n :placeholder=\"words.value\"\n :aria-label=\"words.value\"\n :disabled=\"disabled\"\n size=\"sm\"\n class=\"dou-form-builder__condition-value\"\n @update:model-value=\"setRow(index, { value: $event ?? undefined })\"\n />\n <DouInput\n v-else\n :model-value=\"typeof row.value === 'string' ? row.value : ''\"\n :placeholder=\"targetOf(row)?.kind === 'date' ? 'YYYY-MM-DD' : words.value\"\n :aria-label=\"words.value\"\n :disabled=\"disabled\"\n size=\"sm\"\n class=\"dou-form-builder__condition-value\"\n @update:model-value=\"setRow(index, { value: $event })\"\n />\n </template>\n </div>\n </div>\n </template>\n <ExpressionInput\n v-else\n v-model=\"textValue\"\n :names=\"names\"\n :item-names=\"itemNames\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n />\n <div v-if=\"!readonly\" class=\"dou-form-builder__condition-footer\">\n <DouButton\n v-if=\"!asText\"\n size=\"sm\"\n variant=\"ghost\"\n :disabled=\"disabled || !targets.length\"\n @click=\"addRow\"\n >\n <template #leading><PlusIcon /></template>\n {{ words.add }}\n </DouButton>\n <DouButton\n v-if=\"!asText\"\n size=\"sm\"\n variant=\"ghost\"\n class=\"dou-form-builder__condition-mode\"\n :disabled=\"disabled\"\n @click=\"asText = true\"\n >\n <template #leading><BracesIcon /></template>\n {{ words.toText }}\n </DouButton>\n <!-- Says why rows are out of reach. -->\n <DouTooltip v-else :content=\"words.notRows\" :disabled=\"canUseRows\">\n <DouButton\n size=\"sm\"\n variant=\"ghost\"\n class=\"dou-form-builder__condition-mode\"\n :disabled=\"disabled || !canUseRows\"\n @click=\"toRows\"\n >\n <template #leading><FilterIcon /></template>\n {{ words.toRows }}\n </DouButton>\n </DouTooltip>\n </div>\n </div>\n</template>\n"],"mappings":"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"}
@@ -0,0 +1,159 @@
1
+ import { parseExpression } from "../core/expression.js";
2
+ // src/builder/condition.ts
3
+ var COMPARE = {
4
+ "==": "eq",
5
+ "!=": "ne",
6
+ ">": "gt",
7
+ ">=": "ge",
8
+ "<": "lt",
9
+ "<=": "le"
10
+ };
11
+ var SYMBOL = {
12
+ eq: "==",
13
+ ne: "!=",
14
+ gt: ">",
15
+ ge: ">=",
16
+ lt: "<",
17
+ le: "<="
18
+ };
19
+ /** Operators that need no value. */
20
+ var unaryOperators = /* @__PURE__ */ new Set(["empty", "filled"]);
21
+ var IDENTIFIER = /^[A-Za-z_$À-￿][\w$À-￿]*$/;
22
+ /** A literal as expression text. */
23
+ function literalSource(value) {
24
+ if (typeof value === "string") return `'${value.replace(/\\/g, "\\\\").replace(/'/g, "\\'")}'`;
25
+ return String(value);
26
+ }
27
+ /** `values.contact.phone`, with brackets for keys that are not plain names. */
28
+ function referenceSource(scope, path) {
29
+ let text = scope;
30
+ for (const key of path.split(".")) text += IDENTIFIER.test(key) ? `.${key}` : `[${literalSource(key)}]`;
31
+ return text;
32
+ }
33
+ /** Whether a row says enough to be written. */
34
+ function rowComplete(entry) {
35
+ if (!entry.path) return false;
36
+ if (unaryOperators.has(entry.op)) return true;
37
+ if (entry.op === "in") return Array.isArray(entry.value) && entry.value.length > 0;
38
+ return entry.value !== void 0 && entry.value !== "" && !Array.isArray(entry.value);
39
+ }
40
+ function rowSource(entry) {
41
+ const ref = referenceSource(entry.scope, entry.path);
42
+ switch (entry.op) {
43
+ case "empty": return `empty(${ref})`;
44
+ case "filled": return `!empty(${ref})`;
45
+ case "in": return `${ref} in [${entry.value.map(literalSource).join(", ")}]`;
46
+ case "contains": return `contains(${ref}, ${literalSource(entry.value)})`;
47
+ default: return `${ref} ${SYMBOL[entry.op]} ${literalSource(entry.value)}`;
48
+ }
49
+ }
50
+ /** The condition as expression text, leaving out rows that are not filled in; `''` for none. */
51
+ function printCondition(condition) {
52
+ return condition.rows.filter(rowComplete).map(rowSource).join(condition.join === "and" ? " && " : " || ");
53
+ }
54
+ /** The path a member chain reads under `values` or `item`, if its keys are all literals. */
55
+ function reference(node) {
56
+ const keys = [];
57
+ let current = node;
58
+ while (current.kind === "member") {
59
+ const key = current.key;
60
+ if (key.kind !== "literal" || typeof key.value !== "string" && typeof key.value !== "number") return void 0;
61
+ keys.unshift(String(key.value));
62
+ current = current.object;
63
+ }
64
+ if (current.kind !== "name" || current.name === "value" || !keys.length) return void 0;
65
+ return {
66
+ scope: current.name,
67
+ path: keys.join(".")
68
+ };
69
+ }
70
+ function literal(node) {
71
+ if (node.kind === "literal") return node.value;
72
+ if (node.kind === "unary" && node.operator === "-" && node.argument.kind === "literal" && typeof node.argument.value === "number") return -node.argument.value;
73
+ }
74
+ function rowOf(node) {
75
+ if (node.kind === "call" && node.args.length >= 1) {
76
+ const ref = reference(node.args[0]);
77
+ if (!ref) return void 0;
78
+ if (node.name === "empty" && node.args.length === 1) return {
79
+ ...ref,
80
+ op: "empty"
81
+ };
82
+ if (node.name === "contains" && node.args.length === 2) {
83
+ const value = literal(node.args[1]);
84
+ return value === void 0 ? void 0 : {
85
+ ...ref,
86
+ op: "contains",
87
+ value
88
+ };
89
+ }
90
+ return;
91
+ }
92
+ if (node.kind === "unary" && node.operator === "!") {
93
+ const inner = rowOf(node.argument);
94
+ return inner?.op === "empty" ? {
95
+ ...inner,
96
+ op: "filled"
97
+ } : void 0;
98
+ }
99
+ if (node.kind !== "binary") return void 0;
100
+ const ref = reference(node.left);
101
+ if (!ref) return void 0;
102
+ if (node.operator === "in") {
103
+ if (node.right.kind !== "list") return void 0;
104
+ const values = node.right.items.map(literal);
105
+ if (values.some((value) => value === void 0)) return void 0;
106
+ return {
107
+ ...ref,
108
+ op: "in",
109
+ value: values
110
+ };
111
+ }
112
+ const op = COMPARE[node.operator];
113
+ const value = literal(node.right);
114
+ return op && value !== void 0 ? {
115
+ ...ref,
116
+ op,
117
+ value
118
+ } : void 0;
119
+ }
120
+ /** The leaves of a chain of one operator, left to right. */
121
+ function chain(node, operator, out) {
122
+ if (node.kind === "binary" && node.operator === operator) {
123
+ chain(node.left, operator, out);
124
+ chain(node.right, operator, out);
125
+ } else out.push(node);
126
+ return out;
127
+ }
128
+ /**
129
+ * The condition an expression says, when it is rows joined by one of
130
+ * `&&` and `||`; `undefined` for any other expression, or one that does
131
+ * not parse. Empty text is a condition without rows.
132
+ */
133
+ function parseCondition(source) {
134
+ if (!source?.trim()) return {
135
+ join: "and",
136
+ rows: []
137
+ };
138
+ let ast;
139
+ try {
140
+ ast = parseExpression(source);
141
+ } catch {
142
+ return;
143
+ }
144
+ const join = ast.kind === "binary" && ast.operator === "||" ? "or" : "and";
145
+ const leaves = chain(ast, join === "and" ? "&&" : "||", []);
146
+ const rows = [];
147
+ for (const leaf of leaves) {
148
+ const each = rowOf(leaf);
149
+ if (!each) return void 0;
150
+ rows.push(each);
151
+ }
152
+ return {
153
+ join,
154
+ rows
155
+ };
156
+ }
157
+ export { literalSource, parseCondition, printCondition, referenceSource, rowComplete, unaryOperators };
158
+
159
+ //# sourceMappingURL=condition.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"condition.js","names":[],"sources":["../../src/builder/condition.ts"],"sourcesContent":["import { parseExpression } from '../core/expression'\nimport type { ExpressionNode } from '../core/expression'\n\n/**\n * Conditions as the condition editor shows them: rows of \"field, how,\n * value\", all of which must hold (`and`) or one of which (`or`). They are\n * written to the node as expression text, and read back from it when the\n * text has that shape; other expressions are edited as text.\n */\nexport type ConditionOperator =\n 'eq' | 'ne' | 'gt' | 'ge' | 'lt' | 'le' | 'in' | 'contains' | 'empty' | 'filled'\n\nexport type ConditionLiteral = string | number | boolean | null\n\nexport interface ConditionRow {\n /** What the row reads: the form's values, or the list item around the node. */\n scope: 'values' | 'item'\n /** The path read, e.g. `contact.phone`; empty while no field is picked. */\n path: string\n op: ConditionOperator\n /** A literal, or a list of them for `in`. Unused by `empty` and `filled`. */\n value?: ConditionLiteral | ConditionLiteral[]\n}\n\nexport interface Condition {\n join: 'and' | 'or'\n rows: ConditionRow[]\n}\n\nconst COMPARE: Partial<Record<string, ConditionOperator>> = {\n '==': 'eq',\n '!=': 'ne',\n '>': 'gt',\n '>=': 'ge',\n '<': 'lt',\n '<=': 'le',\n}\nconst SYMBOL: Record<string, string> = { eq: '==', ne: '!=', gt: '>', ge: '>=', lt: '<', le: '<=' }\n\n/** Operators that need no value. */\nexport const unaryOperators: ReadonlySet<ConditionOperator> = new Set(['empty', 'filled'])\n\nconst IDENTIFIER = /^[A-Za-z_$À-￿][\\w$À-￿]*$/\n\n/** A literal as expression text. */\nexport function literalSource(value: ConditionLiteral): string {\n if (typeof value === 'string') return `'${value.replace(/\\\\/g, '\\\\\\\\').replace(/'/g, \"\\\\'\")}'`\n return String(value)\n}\n\n/** `values.contact.phone`, with brackets for keys that are not plain names. */\nexport function referenceSource(scope: 'values' | 'item', path: string): string {\n let text = scope\n for (const key of path.split('.'))\n text += IDENTIFIER.test(key) ? `.${key}` : `[${literalSource(key)}]`\n return text\n}\n\n/** Whether a row says enough to be written. */\nexport function rowComplete(entry: ConditionRow): boolean {\n if (!entry.path) return false\n if (unaryOperators.has(entry.op)) return true\n if (entry.op === 'in') return Array.isArray(entry.value) && entry.value.length > 0\n return entry.value !== undefined && entry.value !== '' && !Array.isArray(entry.value)\n}\n\nfunction rowSource(entry: ConditionRow): string {\n const ref = referenceSource(entry.scope, entry.path)\n switch (entry.op) {\n case 'empty':\n return `empty(${ref})`\n case 'filled':\n return `!empty(${ref})`\n case 'in':\n return `${ref} in [${(entry.value as ConditionLiteral[]).map(literalSource).join(', ')}]`\n case 'contains':\n return `contains(${ref}, ${literalSource(entry.value as ConditionLiteral)})`\n default:\n return `${ref} ${SYMBOL[entry.op]} ${literalSource(entry.value as ConditionLiteral)}`\n }\n}\n\n/** The condition as expression text, leaving out rows that are not filled in; `''` for none. */\nexport function printCondition(condition: Condition): string {\n return condition.rows\n .filter(rowComplete)\n .map(rowSource)\n .join(condition.join === 'and' ? ' && ' : ' || ')\n}\n\n/** The path a member chain reads under `values` or `item`, if its keys are all literals. */\nfunction reference(node: ExpressionNode): { scope: 'values' | 'item'; path: string } | undefined {\n const keys: string[] = []\n let current = node\n while (current.kind === 'member') {\n const key = current.key\n if (key.kind !== 'literal' || (typeof key.value !== 'string' && typeof key.value !== 'number'))\n return undefined\n keys.unshift(String(key.value))\n current = current.object\n }\n if (current.kind !== 'name' || current.name === 'value' || !keys.length) return undefined\n return { scope: current.name, path: keys.join('.') }\n}\n\nfunction literal(node: ExpressionNode): ConditionLiteral | undefined {\n if (node.kind === 'literal') return node.value\n // A negative number is `-` applied to a number.\n if (\n node.kind === 'unary' &&\n node.operator === '-' &&\n node.argument.kind === 'literal' &&\n typeof node.argument.value === 'number'\n )\n return -node.argument.value\n return undefined\n}\n\nfunction rowOf(node: ExpressionNode): ConditionRow | undefined {\n if (node.kind === 'call' && node.args.length >= 1) {\n const ref = reference(node.args[0]!)\n if (!ref) return undefined\n if (node.name === 'empty' && node.args.length === 1) return { ...ref, op: 'empty' }\n if (node.name === 'contains' && node.args.length === 2) {\n const value = literal(node.args[1]!)\n return value === undefined ? undefined : { ...ref, op: 'contains', value }\n }\n return undefined\n }\n if (node.kind === 'unary' && node.operator === '!') {\n const inner = rowOf(node.argument)\n return inner?.op === 'empty' ? { ...inner, op: 'filled' } : undefined\n }\n if (node.kind !== 'binary') return undefined\n const ref = reference(node.left)\n if (!ref) return undefined\n if (node.operator === 'in') {\n if (node.right.kind !== 'list') return undefined\n const values = node.right.items.map(literal)\n if (values.some((value) => value === undefined)) return undefined\n return { ...ref, op: 'in', value: values as ConditionLiteral[] }\n }\n const op = COMPARE[node.operator]\n const value = literal(node.right)\n return op && value !== undefined ? { ...ref, op, value } : undefined\n}\n\n/** The leaves of a chain of one operator, left to right. */\nfunction chain(node: ExpressionNode, operator: '&&' | '||', out: ExpressionNode[]) {\n if (node.kind === 'binary' && node.operator === operator) {\n chain(node.left, operator, out)\n chain(node.right, operator, out)\n } else out.push(node)\n return out\n}\n\n/**\n * The condition an expression says, when it is rows joined by one of\n * `&&` and `||`; `undefined` for any other expression, or one that does\n * not parse. Empty text is a condition without rows.\n */\nexport function parseCondition(source: string | undefined): Condition | undefined {\n if (!source?.trim()) return { join: 'and', rows: [] }\n let ast: ExpressionNode\n try {\n ast = parseExpression(source)\n } catch {\n return undefined\n }\n const join = ast.kind === 'binary' && ast.operator === '||' ? 'or' : 'and'\n const leaves = chain(ast, join === 'and' ? '&&' : '||', [])\n const rows: ConditionRow[] = []\n for (const leaf of leaves) {\n const each = rowOf(leaf)\n if (!each) return undefined\n rows.push(each)\n }\n return { join, rows }\n}\n"],"mappings":"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"}