@dou-ui/form-builder 0.0.0-stage → 0.1.0-alpha.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +10 -2
- package/dist/builder/canvas.js +695 -0
- package/dist/builder/canvas.js.map +1 -0
- package/dist/builder/completion.js +49 -0
- package/dist/builder/completion.js.map +1 -0
- package/dist/builder/condition-editor.js +6 -0
- package/dist/builder/condition-editor.js.map +1 -0
- package/dist/builder/condition-editor.vue_vue_type_script_setup_true_lang.js +410 -0
- package/dist/builder/condition-editor.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/condition.js +159 -0
- package/dist/builder/condition.js.map +1 -0
- package/dist/builder/context.js +477 -0
- package/dist/builder/context.js.map +1 -0
- package/dist/builder/core/commands.js +373 -0
- package/dist/builder/core/commands.js.map +1 -0
- package/dist/builder/core/history.js +76 -0
- package/dist/builder/core/history.js.map +1 -0
- package/dist/builder/core/transaction.js +298 -0
- package/dist/builder/core/transaction.js.map +1 -0
- package/dist/builder/drag.js +466 -0
- package/dist/builder/drag.js.map +1 -0
- package/dist/builder/expression-box.js +19 -0
- package/dist/builder/expression-box.js.map +1 -0
- package/dist/builder/expression-input.js +6 -0
- package/dist/builder/expression-input.js.map +1 -0
- package/dist/builder/expression-input.vue_vue_type_script_setup_true_lang.js +117 -0
- package/dist/builder/expression-input.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/extension.js +47 -0
- package/dist/builder/extension.js.map +1 -0
- package/dist/builder/form-builder.js +6 -0
- package/dist/builder/form-builder.js.map +1 -0
- package/dist/builder/form-builder.vue_vue_type_script_setup_true_lang.js +450 -0
- package/dist/builder/form-builder.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/index.js +22 -0
- package/dist/builder/index.js.map +1 -0
- package/dist/builder/inspector.js +6 -0
- package/dist/builder/inspector.js.map +1 -0
- package/dist/builder/inspector.vue_vue_type_script_setup_true_lang.js +442 -0
- package/dist/builder/inspector.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/json-dialog.js +6 -0
- package/dist/builder/json-dialog.js.map +1 -0
- package/dist/builder/json-dialog.vue_vue_type_script_setup_true_lang.js +281 -0
- package/dist/builder/json-dialog.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/locale.js +1271 -0
- package/dist/builder/locale.js.map +1 -0
- package/dist/builder/logic-fields.js +18 -0
- package/dist/builder/logic-fields.js.map +1 -0
- package/dist/builder/logic.js +332 -0
- package/dist/builder/logic.js.map +1 -0
- package/dist/builder/menu.js +92 -0
- package/dist/builder/menu.js.map +1 -0
- package/dist/builder/outline-row.js +6 -0
- package/dist/builder/outline-row.js.map +1 -0
- package/dist/builder/outline-row.vue_vue_type_script_setup_true_lang.js +88 -0
- package/dist/builder/outline-row.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/outline.js +6 -0
- package/dist/builder/outline.js.map +1 -0
- package/dist/builder/outline.vue_vue_type_script_setup_true_lang.js +111 -0
- package/dist/builder/outline.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/palette.js +6 -0
- package/dist/builder/palette.js.map +1 -0
- package/dist/builder/palette.vue_vue_type_script_setup_true_lang.js +96 -0
- package/dist/builder/palette.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/preview.js +6 -0
- package/dist/builder/preview.js.map +1 -0
- package/dist/builder/preview.vue_vue_type_script_setup_true_lang.js +111 -0
- package/dist/builder/preview.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/builder/settings-binding.js +57 -0
- package/dist/builder/settings-binding.js.map +1 -0
- package/dist/builder/settings.js +487 -0
- package/dist/builder/settings.js.map +1 -0
- package/dist/builder/span-field.js +104 -0
- package/dist/builder/span-field.js.map +1 -0
- package/dist/code/expression-input.js +6 -0
- package/dist/code/expression-input.js.map +1 -0
- package/dist/code/expression-input.vue_vue_type_script_setup_true_lang.js +88 -0
- package/dist/code/expression-input.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/code/extension.js +202 -0
- package/dist/code/extension.js.map +1 -0
- package/dist/code/index.js +19 -0
- package/dist/code/index.js.map +1 -0
- package/dist/code/language.js +43 -0
- package/dist/code/language.js.map +1 -0
- package/dist/collaboration/index.js +382 -0
- package/dist/collaboration/index.js.map +1 -0
- package/dist/collaboration/order.js +88 -0
- package/dist/collaboration/order.js.map +1 -0
- package/dist/core/check.js +314 -0
- package/dist/core/check.js.map +1 -0
- package/dist/core/document.js +112 -0
- package/dist/core/document.js.map +1 -0
- package/dist/core/expression.js +854 -0
- package/dist/core/expression.js.map +1 -0
- package/dist/core/formulas.js +242 -0
- package/dist/core/formulas.js.map +1 -0
- package/dist/core/rules.js +83 -0
- package/dist/core/rules.js.map +1 -0
- package/dist/core/values.js +80 -0
- package/dist/core/values.js.map +1 -0
- package/dist/fields/builtin.js +167 -0
- package/dist/fields/builtin.js.map +1 -0
- package/dist/fields/components.js +155 -0
- package/dist/fields/components.js.map +1 -0
- package/dist/fields/define.js +44 -0
- package/dist/fields/define.js.map +1 -0
- package/dist/fields/format.js +125 -0
- package/dist/fields/format.js.map +1 -0
- package/dist/fields/options.js +54 -0
- package/dist/fields/options.js.map +1 -0
- package/dist/index.js +20 -0
- package/dist/locale.js +161 -0
- package/dist/locale.js.map +1 -0
- package/dist/renderer/containers.js +430 -0
- package/dist/renderer/containers.js.map +1 -0
- package/dist/renderer/context.js +21 -0
- package/dist/renderer/context.js.map +1 -0
- package/dist/renderer/form-renderer.js +6 -0
- package/dist/renderer/form-renderer.js.map +1 -0
- package/dist/renderer/form-renderer.vue_vue_type_script_setup_true_lang.js +272 -0
- package/dist/renderer/form-renderer.vue_vue_type_script_setup_true_lang.js.map +1 -0
- package/dist/renderer/index.js +19 -0
- package/dist/renderer/index.js.map +1 -0
- package/dist/renderer/node-view.js +385 -0
- package/dist/renderer/node-view.js.map +1 -0
- package/dist/style.css +1 -0
- package/dist/style.d.ts +1 -0
- package/dist/style.js +27 -0
- package/dist/types/builder/canvas.d.ts +5 -0
- package/dist/types/builder/completion.d.ts +35 -0
- package/dist/types/builder/condition-editor.vue.d.ts +17 -0
- package/dist/types/builder/condition.d.ts +37 -0
- package/dist/types/builder/context.d.ts +149 -0
- package/dist/types/builder/core/commands.d.ts +74 -0
- package/dist/types/builder/core/history.d.ts +23 -0
- package/dist/types/builder/core/transaction.d.ts +108 -0
- package/dist/types/builder/drag.d.ts +52 -0
- package/dist/types/builder/expression-box.d.ts +8 -0
- package/dist/types/builder/expression-input.vue.d.ts +29 -0
- package/dist/types/builder/extension.d.ts +149 -0
- package/dist/types/builder/form-builder.vue.d.ts +24 -0
- package/dist/types/builder/index.d.ts +76 -0
- package/dist/types/builder/inspector.vue.d.ts +3 -0
- package/dist/types/builder/json-dialog.vue.d.ts +10 -0
- package/dist/types/builder/locale.d.ts +195 -0
- package/dist/types/builder/logic-fields.d.ts +2 -0
- package/dist/types/builder/logic.d.ts +57 -0
- package/dist/types/builder/menu.d.ts +23 -0
- package/dist/types/builder/outline-row.vue.d.ts +19 -0
- package/dist/types/builder/outline.vue.d.ts +3 -0
- package/dist/types/builder/palette.vue.d.ts +3 -0
- package/dist/types/builder/preview.vue.d.ts +3 -0
- package/dist/types/builder/settings-binding.d.ts +23 -0
- package/dist/types/builder/settings.d.ts +49 -0
- package/dist/types/builder/span-field.d.ts +4 -0
- package/dist/types/builder/types.d.ts +59 -0
- package/dist/types/code/expression-input.vue.d.ts +23 -0
- package/dist/types/code/extension.d.ts +45 -0
- package/dist/types/code/index.d.ts +12 -0
- package/dist/types/code/language.d.ts +6 -0
- package/dist/types/collaboration/index.d.ts +64 -0
- package/dist/types/collaboration/order.d.ts +20 -0
- package/dist/types/core/check.d.ts +68 -0
- package/dist/types/core/document.d.ts +36 -0
- package/dist/types/core/expression.d.ts +175 -0
- package/dist/types/core/formulas.d.ts +44 -0
- package/dist/types/core/rules.d.ts +23 -0
- package/dist/types/core/types.d.ts +211 -0
- package/dist/types/core/values.d.ts +22 -0
- package/dist/types/fields/builtin.d.ts +9 -0
- package/dist/types/fields/components.d.ts +177 -0
- package/dist/types/fields/define.d.ts +93 -0
- package/dist/types/fields/format.d.ts +76 -0
- package/dist/types/fields/options.d.ts +11 -0
- package/dist/types/index.d.ts +3 -0
- package/dist/types/locale.d.ts +45 -0
- package/dist/types/renderer/containers.d.ts +20 -0
- package/dist/types/renderer/context.d.ts +186 -0
- package/dist/types/renderer/form-renderer.vue.d.ts +25 -0
- package/dist/types/renderer/index.d.ts +81 -0
- package/dist/types/renderer/node-view.d.ts +56 -0
- package/package.json +88 -4
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { builtinFunctions, checkExpression } from "../core/expression.js";
|
|
2
|
+
import { formatMessage } from "../locale.js";
|
|
3
|
+
import { useBuilderState } from "../builder/context.js";
|
|
4
|
+
import { expressionCodeExtension } from "./extension.js";
|
|
5
|
+
import { formExpression } from "./language.js";
|
|
6
|
+
import { computed, createCommentVNode, createElementBlock, createVNode, defineComponent, mergeProps, openBlock, toDisplayString, unref, useId } from "vue";
|
|
7
|
+
import { DouCodeInput } from "@dou-ui/code";
|
|
8
|
+
// src/code/expression-input.vue?vue&type=script&setup=true&lang.ts
|
|
9
|
+
var _hoisted_1 = { class: "dou-form-builder__expression" };
|
|
10
|
+
/**
|
|
11
|
+
* The builder's expression box as a code input: colored, with completions
|
|
12
|
+
* of field paths and functions, parameter hints, and problems underlined
|
|
13
|
+
* as well as written under it.
|
|
14
|
+
*/
|
|
15
|
+
var expression_input_vue_vue_type_script_setup_true_lang_default = /*@__PURE__*/ defineComponent({
|
|
16
|
+
name: "DouFormBuilderCodeExpression",
|
|
17
|
+
inheritAttrs: false,
|
|
18
|
+
__name: "expression-input",
|
|
19
|
+
props: {
|
|
20
|
+
modelValue: { default: "" },
|
|
21
|
+
names: { default: () => [] },
|
|
22
|
+
itemNames: { default: void 0 },
|
|
23
|
+
readsValue: { type: Boolean },
|
|
24
|
+
placeholder: { default: void 0 },
|
|
25
|
+
disabled: { type: Boolean },
|
|
26
|
+
readonly: { type: Boolean }
|
|
27
|
+
},
|
|
28
|
+
emits: ["update:modelValue"],
|
|
29
|
+
setup(__props, { emit: __emit }) {
|
|
30
|
+
const props = __props;
|
|
31
|
+
const emit = __emit;
|
|
32
|
+
const state = useBuilderState();
|
|
33
|
+
const errorId = `dou-form-builder-expression-${useId()}`;
|
|
34
|
+
const words = computed(() => state.messages.expression);
|
|
35
|
+
const problemMessage = (problem) => formatMessage(words.value.problems[problem.code] ?? problem.message, { text: problem.text });
|
|
36
|
+
const extensions = [expressionCodeExtension({
|
|
37
|
+
names: () => props.names,
|
|
38
|
+
itemNames: () => props.itemNames,
|
|
39
|
+
readsValue: () => !!props.readsValue,
|
|
40
|
+
functions: () => state.functionNames.value,
|
|
41
|
+
functionInfo: () => words.value.functions,
|
|
42
|
+
labels: () => words.value,
|
|
43
|
+
problemMessage
|
|
44
|
+
})];
|
|
45
|
+
const text = computed(() => props.modelValue ?? "");
|
|
46
|
+
const problem = computed(() => {
|
|
47
|
+
if (!text.value.trim()) return void 0;
|
|
48
|
+
const found = checkExpression(text.value, {
|
|
49
|
+
fields: props.names.map((name) => name.path),
|
|
50
|
+
itemFields: props.itemNames ? props.itemNames.map((name) => name.path) : [],
|
|
51
|
+
functions: [.../* @__PURE__ */ new Set([...Object.keys(builtinFunctions), ...state.functionNames.value])]
|
|
52
|
+
})[0];
|
|
53
|
+
return found && problemMessage(found);
|
|
54
|
+
});
|
|
55
|
+
return (_ctx, _cache) => {
|
|
56
|
+
return openBlock(), createElementBlock("div", _hoisted_1, [createVNode(unref(DouCodeInput), mergeProps(_ctx.$attrs, {
|
|
57
|
+
"model-value": text.value,
|
|
58
|
+
language: unref(formExpression),
|
|
59
|
+
extensions,
|
|
60
|
+
placeholder: __props.placeholder,
|
|
61
|
+
disabled: __props.disabled,
|
|
62
|
+
readonly: __props.readonly,
|
|
63
|
+
invalid: !!problem.value,
|
|
64
|
+
"aria-describedby": problem.value ? errorId : void 0,
|
|
65
|
+
multiline: "",
|
|
66
|
+
autosize: { maxRows: 4 },
|
|
67
|
+
size: "sm",
|
|
68
|
+
class: "dou-form-builder__expression-input",
|
|
69
|
+
"onUpdate:modelValue": _cache[0] || (_cache[0] = ($event) => emit("update:modelValue", $event))
|
|
70
|
+
}), null, 16, [
|
|
71
|
+
"model-value",
|
|
72
|
+
"language",
|
|
73
|
+
"placeholder",
|
|
74
|
+
"disabled",
|
|
75
|
+
"readonly",
|
|
76
|
+
"invalid",
|
|
77
|
+
"aria-describedby"
|
|
78
|
+
]), problem.value ? (openBlock(), createElementBlock("div", {
|
|
79
|
+
key: 0,
|
|
80
|
+
id: errorId,
|
|
81
|
+
class: "dou-form-builder__expression-error"
|
|
82
|
+
}, toDisplayString(problem.value), 1)) : createCommentVNode("", true)]);
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
export { expression_input_vue_vue_type_script_setup_true_lang_default as default };
|
|
87
|
+
|
|
88
|
+
//# sourceMappingURL=expression-input.vue_vue_type_script_setup_true_lang.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expression-input.vue_vue_type_script_setup_true_lang.js","names":["$attrs","_openBlock","_createElementBlock","_createVNode","_unref","_mergeProps","_toDisplayString","_createCommentVNode"],"sources":["../../src/code/expression-input.vue"],"sourcesContent":["<script setup lang=\"ts\">\nimport { DouCodeInput } from '@dou-ui/code'\nimport { computed, useId } from 'vue'\nimport { builtinFunctions, checkExpression } from '../core/expression'\nimport { formatMessage } from '../locale'\nimport { useBuilderState } from '../builder/context'\nimport { expressionCodeExtension } from './extension'\nimport type { ExpressionName } from './extension'\nimport { formExpression } from './language'\n\n/**\n * The builder's expression box as a code input: colored, with completions\n * of field paths and functions, parameter hints, and problems underlined\n * as well as written under it.\n */\ndefineOptions({ name: 'DouFormBuilderCodeExpression', inheritAttrs: false })\n\nconst props = withDefaults(\n defineProps<{\n modelValue?: string | null\n names?: ExpressionName[]\n itemNames?: ExpressionName[]\n readsValue?: boolean\n placeholder?: string\n disabled?: boolean\n /** Shown and selectable, but not changed; also when the form around is read-only. */\n readonly?: boolean\n }>(),\n { modelValue: '', names: () => [], itemNames: undefined, placeholder: undefined },\n)\nconst emit = defineEmits<{ 'update:modelValue': [value: string] }>()\n\nconst state = useBuilderState()\nconst errorId = `dou-form-builder-expression-${useId()}`\nconst words = computed(() => state.messages.expression)\n\nconst problemMessage = (problem: { code: string; message: string; text: string }) =>\n formatMessage(words.value.problems[problem.code] ?? problem.message, { text: problem.text })\n\nconst extensions = [\n expressionCodeExtension({\n names: () => props.names,\n itemNames: () => props.itemNames,\n readsValue: () => !!props.readsValue,\n functions: () => state.functionNames.value,\n functionInfo: () => words.value.functions,\n labels: () => words.value,\n problemMessage,\n }),\n]\n\nconst text = computed(() => props.modelValue ?? '')\n\n// The first problem in words too, for screen readers and at a glance.\nconst problem = computed(() => {\n if (!text.value.trim()) return undefined\n const found = checkExpression(text.value, {\n fields: props.names.map((name) => name.path),\n itemFields: props.itemNames ? props.itemNames.map((name) => name.path) : [],\n functions: [...new Set([...Object.keys(builtinFunctions), ...state.functionNames.value])],\n })[0]\n return found && problemMessage(found)\n})\n</script>\n\n<template>\n <div class=\"dou-form-builder__expression\">\n <DouCodeInput\n v-bind=\"$attrs\"\n :model-value=\"text\"\n :language=\"formExpression\"\n :extensions=\"extensions\"\n :placeholder=\"placeholder\"\n :disabled=\"disabled\"\n :readonly=\"readonly\"\n :invalid=\"!!problem\"\n :aria-describedby=\"problem ? errorId : undefined\"\n multiline\n :autosize=\"{ maxRows: 4 }\"\n size=\"sm\"\n class=\"dou-form-builder__expression-input\"\n @update:model-value=\"emit('update:modelValue', $event)\"\n />\n <div v-if=\"problem\" :id=\"errorId\" class=\"dou-form-builder__expression-error\">\n {{ problem }}\n </div>\n </div>\n</template>\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;EAiBA,MAAM,QAAQ;EAad,MAAM,OAAO;EAEb,MAAM,QAAQ,gBAAgB;EAC9B,MAAM,UAAU,+BAA+B,MAAM;EACrD,MAAM,QAAQ,eAAe,MAAM,SAAS,UAAU;EAEtD,MAAM,kBAAkB,YACtB,cAAc,MAAM,MAAM,SAAS,QAAQ,SAAS,QAAQ,SAAS,EAAE,MAAM,QAAQ,KAAK,CAAC;EAE7F,MAAM,aAAa,CACjB,wBAAwB;GACtB,aAAa,MAAM;GACnB,iBAAiB,MAAM;GACvB,kBAAkB,CAAC,CAAC,MAAM;GAC1B,iBAAiB,MAAM,cAAc;GACrC,oBAAoB,MAAM,MAAM;GAChC,cAAc,MAAM;GACpB;EACF,CAAC,CACH;EAEA,MAAM,OAAO,eAAe,MAAM,cAAc,EAAE;EAGlD,MAAM,UAAU,eAAe;GAC7B,IAAI,CAAC,KAAK,MAAM,KAAK,GAAG,OAAO,KAAA;GAC/B,MAAM,QAAQ,gBAAgB,KAAK,OAAO;IACxC,QAAQ,MAAM,MAAM,KAAK,SAAS,KAAK,IAAI;IAC3C,YAAY,MAAM,YAAY,MAAM,UAAU,KAAK,SAAS,KAAK,IAAI,IAAI,CAAC;IAC1E,WAAW,CAAC,mBAAG,IAAI,IAAI,CAAC,GAAG,OAAO,KAAK,gBAAgB,GAAG,GAAG,MAAM,cAAc,KAAK,CAAC,CAAC;GAC1F,CAAC,CAAC,CAAC;GACH,OAAO,SAAS,eAAe,KAAK;EACtC,CAAC;;GAIC,OAAAC,UAAA,GAAAC,mBAoBM,OApBN,YAoBM,CAnBJC,YAeEC,MAAA,YAAA,GAfFC,WACUL,KAcR,QAdc;IACb,eAAa,KAAA;IACb,UAAUI,MAAA,cAAA;IACE;IACZ,aAAa,QAAA;IACb,UAAU,QAAA;IACV,UAAU,QAAA;IACV,SAAO,CAAA,CAAI,QAAA;IACX,oBAAkB,QAAA,QAAU,UAAU,KAAA;IACvC,WAAA;IACC,UAAU,EAAA,SAAA,EAAA;IACX,MAAK;IACL,OAAM;IACL,uBAAkB,OAAA,OAAA,OAAA,MAAA,WAAE,KAAI,qBAAsB,MAAM;;;;;;;;;G,IAE5C,QAAA,SAAXH,UAAA,GAAAC,mBAEM,OAAA;;IAFe,IAAI;IAAS,OAAM;GACnC,GAAAI,gBAAA,QAAA,KAAO,GAAA,CAAA,K"}
|
|
@@ -0,0 +1,202 @@
|
|
|
1
|
+
import { builtinFunctions, checkExpression } from "../core/expression.js";
|
|
2
|
+
import { referenceSource } from "../builder/condition.js";
|
|
3
|
+
import { defineCodeExtension } from "@dou-ui/code";
|
|
4
|
+
// src/code/extension.ts
|
|
5
|
+
var read = (value) => typeof value === "function" ? value() : value;
|
|
6
|
+
var KEYWORDS = [
|
|
7
|
+
"true",
|
|
8
|
+
"false",
|
|
9
|
+
"null",
|
|
10
|
+
"in"
|
|
11
|
+
];
|
|
12
|
+
/** Whether `text` ends inside quoted text. */
|
|
13
|
+
function inString(text) {
|
|
14
|
+
let quote = "";
|
|
15
|
+
for (let i = 0; i < text.length; i++) {
|
|
16
|
+
const char = text[i];
|
|
17
|
+
if (quote) {
|
|
18
|
+
if (char === "\\") i++;
|
|
19
|
+
else if (char === quote) quote = "";
|
|
20
|
+
} else if (char === "'" || char === "\"") quote = char;
|
|
21
|
+
}
|
|
22
|
+
return !!quote;
|
|
23
|
+
}
|
|
24
|
+
/** The parameters of `signature` as `[from, to]` in it. */
|
|
25
|
+
function paramsOf(signature) {
|
|
26
|
+
const open = signature.indexOf("(");
|
|
27
|
+
const close = signature.lastIndexOf(")");
|
|
28
|
+
if (open < 0 || close <= open + 1) return [];
|
|
29
|
+
const out = [];
|
|
30
|
+
let from = open + 1;
|
|
31
|
+
for (let i = from; i <= close; i++) if (i === close || signature[i] === ",") {
|
|
32
|
+
let a = from;
|
|
33
|
+
while (signature[a] === " ") a++;
|
|
34
|
+
out.push([a, i]);
|
|
35
|
+
from = i + 1;
|
|
36
|
+
}
|
|
37
|
+
return out;
|
|
38
|
+
}
|
|
39
|
+
/** The call around `pos` in `text`: its name and which argument the cursor is in. */
|
|
40
|
+
function callAt(text, pos) {
|
|
41
|
+
let depth = 0;
|
|
42
|
+
let commas = 0;
|
|
43
|
+
let quote = "";
|
|
44
|
+
const plain = text.slice(0, pos).split("");
|
|
45
|
+
for (let i = 0; i < plain.length; i++) {
|
|
46
|
+
const char = plain[i];
|
|
47
|
+
if (quote) {
|
|
48
|
+
if (char === "\\") {
|
|
49
|
+
plain[i] = " ";
|
|
50
|
+
if (i + 1 < plain.length) plain[++i] = " ";
|
|
51
|
+
continue;
|
|
52
|
+
}
|
|
53
|
+
if (char === quote) quote = "";
|
|
54
|
+
plain[i] = " ";
|
|
55
|
+
} else if (char === "'" || char === "\"") {
|
|
56
|
+
quote = char;
|
|
57
|
+
plain[i] = " ";
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
for (let i = plain.length - 1; i >= 0; i--) {
|
|
61
|
+
const char = plain[i];
|
|
62
|
+
if (char === ")" || char === "]") depth++;
|
|
63
|
+
else if (char === "[") {
|
|
64
|
+
if (depth-- === 0) return null;
|
|
65
|
+
} else if (char === "," && depth === 0) commas++;
|
|
66
|
+
else if (char === "(") {
|
|
67
|
+
if (depth-- > 0) continue;
|
|
68
|
+
const name = /([A-Za-z_$À-][\w$À-]*)\s*$/.exec(plain.slice(0, i).join(""));
|
|
69
|
+
return name ? {
|
|
70
|
+
name: name[1],
|
|
71
|
+
arg: commas
|
|
72
|
+
} : null;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Completions, hover text, parameter hints and problems for form
|
|
79
|
+
* expressions in a `DouCodeEditor` or `DouCodeInput`: field paths after
|
|
80
|
+
* `values.` and `item.`, functions as snippets, and the problems of
|
|
81
|
+
* `checkExpression` underlined where they are.
|
|
82
|
+
*/
|
|
83
|
+
function expressionCodeExtension(options = {}) {
|
|
84
|
+
const functionNames = () => [.../* @__PURE__ */ new Set([...Object.keys(builtinFunctions), ...read(options.functions ?? [])])];
|
|
85
|
+
const infoOf = (name) => read(options.functionInfo ?? {})[name];
|
|
86
|
+
return defineCodeExtension({
|
|
87
|
+
name: "form-expression",
|
|
88
|
+
completionTriggers: ["."],
|
|
89
|
+
completion({ pos, word }, { doc }) {
|
|
90
|
+
const line = doc.lineAt(pos);
|
|
91
|
+
const before = line.text.slice(0, pos - line.from);
|
|
92
|
+
if (inString(before)) return null;
|
|
93
|
+
const labels = read(options.labels ?? {});
|
|
94
|
+
const path = /\b(values|item)\.([\w$.À-]*)$/.exec(before);
|
|
95
|
+
if (path) {
|
|
96
|
+
const root = path[1];
|
|
97
|
+
const list = root === "values" ? read(options.names ?? []) : read(options.itemNames);
|
|
98
|
+
if (!list) return null;
|
|
99
|
+
return {
|
|
100
|
+
from: pos - path[2].length,
|
|
101
|
+
options: list.filter(({ path: name }) => referenceSource(root, name) === `${root}.${name}`).map(({ path: name, label }) => ({
|
|
102
|
+
label: name,
|
|
103
|
+
kind: "property",
|
|
104
|
+
detail: label
|
|
105
|
+
}))
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
if (before.slice(0, before.length - word.text.length).endsWith(".")) return null;
|
|
109
|
+
const entries = [{
|
|
110
|
+
label: "values",
|
|
111
|
+
kind: "variable",
|
|
112
|
+
detail: labels.values,
|
|
113
|
+
boost: 2
|
|
114
|
+
}];
|
|
115
|
+
if (read(options.itemNames)) entries.push({
|
|
116
|
+
label: "item",
|
|
117
|
+
kind: "variable",
|
|
118
|
+
detail: labels.item,
|
|
119
|
+
boost: 2
|
|
120
|
+
});
|
|
121
|
+
if (read(options.readsValue ?? false)) entries.push({
|
|
122
|
+
label: "value",
|
|
123
|
+
kind: "variable",
|
|
124
|
+
detail: labels.value,
|
|
125
|
+
boost: 2
|
|
126
|
+
});
|
|
127
|
+
for (const name of functionNames()) {
|
|
128
|
+
const info = infoOf(name);
|
|
129
|
+
const required = (info ? paramsOf(info.signature) : []).map(([a, b]) => info.signature.slice(a, b)).filter((param) => !param.endsWith("?"));
|
|
130
|
+
const fields = required.map((param, i) => `\${${i + 1}:${param.replace(/^\.\.\./, "")}}`).join(", ");
|
|
131
|
+
entries.push({
|
|
132
|
+
label: name,
|
|
133
|
+
kind: "function",
|
|
134
|
+
detail: info ? info.signature.slice(name.length) : "()",
|
|
135
|
+
info: info?.info,
|
|
136
|
+
snippet: required.length ? `${name}(${fields})` : `${name}($0)`
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
for (const keyword of KEYWORDS) entries.push({
|
|
140
|
+
label: keyword,
|
|
141
|
+
kind: "keyword",
|
|
142
|
+
detail: labels.keyword,
|
|
143
|
+
boost: -1
|
|
144
|
+
});
|
|
145
|
+
return {
|
|
146
|
+
from: word.from,
|
|
147
|
+
options: entries
|
|
148
|
+
};
|
|
149
|
+
},
|
|
150
|
+
hover({ pos }, { doc }) {
|
|
151
|
+
const line = doc.lineAt(pos);
|
|
152
|
+
const col = pos - line.from;
|
|
153
|
+
for (const match of line.text.matchAll(/[A-Za-z_$À-][\w$À-]*/g)) {
|
|
154
|
+
const from = match.index;
|
|
155
|
+
const to = from + match[0].length;
|
|
156
|
+
if (col < from || col > to) continue;
|
|
157
|
+
const info = infoOf(match[0]);
|
|
158
|
+
if (!info || !/^\s*\(/.test(line.text.slice(to))) return null;
|
|
159
|
+
return {
|
|
160
|
+
from: line.from + from,
|
|
161
|
+
to: line.from + to,
|
|
162
|
+
content: info.info ? `${info.signature}\n${info.info}` : info.signature
|
|
163
|
+
};
|
|
164
|
+
}
|
|
165
|
+
return null;
|
|
166
|
+
},
|
|
167
|
+
signature({ pos }, { doc }) {
|
|
168
|
+
const line = doc.lineAt(pos);
|
|
169
|
+
const call = callAt(line.text, pos - line.from);
|
|
170
|
+
const info = call && infoOf(call.name);
|
|
171
|
+
if (!call || !info) return null;
|
|
172
|
+
const params = paramsOf(info.signature);
|
|
173
|
+
const last = params.length - 1;
|
|
174
|
+
const active = last >= 0 && info.signature.slice(params[last][0]).startsWith("...") ? Math.min(call.arg, last) : call.arg;
|
|
175
|
+
if (active > last) return null;
|
|
176
|
+
return {
|
|
177
|
+
label: info.signature,
|
|
178
|
+
params,
|
|
179
|
+
active,
|
|
180
|
+
info: info.info
|
|
181
|
+
};
|
|
182
|
+
},
|
|
183
|
+
lint: options.lint === false ? void 0 : ({ doc }) => {
|
|
184
|
+
const source = doc.toString();
|
|
185
|
+
if (!source.trim()) return [];
|
|
186
|
+
const itemNames = read(options.itemNames);
|
|
187
|
+
return checkExpression(source, {
|
|
188
|
+
fields: read(options.names ?? []).map((name) => name.path),
|
|
189
|
+
itemFields: itemNames ? itemNames.map((name) => name.path) : [],
|
|
190
|
+
functions: read(options.functions ?? [])
|
|
191
|
+
}).map((problem) => ({
|
|
192
|
+
from: problem.start,
|
|
193
|
+
to: Math.max(problem.end, problem.start),
|
|
194
|
+
severity: "error",
|
|
195
|
+
message: options.problemMessage?.(problem) ?? problem.message
|
|
196
|
+
}));
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
export { expressionCodeExtension };
|
|
201
|
+
|
|
202
|
+
//# sourceMappingURL=extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.js","names":[],"sources":["../../src/code/extension.ts"],"sourcesContent":["import { defineCodeExtension } from '@dou-ui/code'\nimport type {\n CodeCompletion,\n CodeDiagnostic,\n CodeExtension,\n CodeSignatureResult,\n} from '@dou-ui/code'\nimport { builtinFunctions, checkExpression } from '../core/expression'\nimport type { ExpressionProblem } from '../core/expression'\nimport { referenceSource } from '../builder/condition'\n\n/** A path an expression can read, with what to show beside it. */\nexport interface ExpressionName {\n path: string\n label?: string\n}\n\n/** What a function takes and does, for hover text and parameter hints. */\nexport interface ExpressionFunctionInfo {\n /** As it is called, e.g. `round(value, digits?)`. */\n signature: string\n info?: string\n}\n\ntype Getter<T> = T | (() => T)\nconst read = <T>(value: Getter<T>): T =>\n typeof value === 'function' ? (value as () => T)() : value\n\nexport interface ExpressionCodeOptions {\n /** The paths `values` can read. */\n names?: Getter<readonly ExpressionName[]>\n /** The paths `item` can read; left out where there is no list item. */\n itemNames?: Getter<readonly ExpressionName[] | undefined>\n /** Whether `value` (the field's own value) can be read, as in a check. */\n readsValue?: Getter<boolean>\n /** Functions besides the built-in ones. */\n functions?: Getter<readonly string[]>\n /** What each function takes and does, by name. */\n functionInfo?: Getter<Readonly<Record<string, ExpressionFunctionInfo>>>\n /** Shown beside `values`, `item`, `value` and the keywords in completions. */\n labels?: Getter<{ values?: string; item?: string; value?: string; keyword?: string }>\n /** The words for a problem; the English description by default. */\n problemMessage?: (problem: ExpressionProblem) => string\n /** Finds problems as the expression is typed. On by default. */\n lint?: boolean\n}\n\nconst KEYWORDS = ['true', 'false', 'null', 'in']\n\n/** Whether `text` ends inside quoted text. */\nfunction inString(text: string) {\n let quote = ''\n for (let i = 0; i < text.length; i++) {\n const char = text[i]!\n if (quote) {\n if (char === '\\\\') i++\n else if (char === quote) quote = ''\n } else if (char === \"'\" || char === '\"') quote = char\n }\n return !!quote\n}\n\n/** The parameters of `signature` as `[from, to]` in it. */\nfunction paramsOf(signature: string): Array<[number, number]> {\n const open = signature.indexOf('(')\n const close = signature.lastIndexOf(')')\n if (open < 0 || close <= open + 1) return []\n const out: Array<[number, number]> = []\n let from = open + 1\n for (let i = from; i <= close; i++) {\n if (i === close || signature[i] === ',') {\n let a = from\n while (signature[a] === ' ') a++\n out.push([a, i])\n from = i + 1\n }\n }\n return out\n}\n\n/** The call around `pos` in `text`: its name and which argument the cursor is in. */\nfunction callAt(text: string, pos: number) {\n let depth = 0\n let commas = 0\n let quote = ''\n // Strings first: brackets and commas inside them don't count.\n const plain = text.slice(0, pos).split('')\n for (let i = 0; i < plain.length; i++) {\n const char = plain[i]!\n if (quote) {\n if (char === '\\\\') {\n plain[i] = ' '\n if (i + 1 < plain.length) plain[++i] = ' '\n continue\n }\n if (char === quote) quote = ''\n plain[i] = ' '\n } else if (char === \"'\" || char === '\"') {\n quote = char\n plain[i] = ' '\n }\n }\n for (let i = plain.length - 1; i >= 0; i--) {\n const char = plain[i]\n if (char === ')' || char === ']') depth++\n else if (char === '[') {\n if (depth-- === 0) return null\n } else if (char === ',' && depth === 0) commas++\n else if (char === '(') {\n if (depth-- > 0) continue\n const name = /([A-Za-z_$À-][\\w$À-]*)\\s*$/.exec(plain.slice(0, i).join(''))\n return name ? { name: name[1]!, arg: commas } : null\n }\n }\n return null\n}\n\n/**\n * Completions, hover text, parameter hints and problems for form\n * expressions in a `DouCodeEditor` or `DouCodeInput`: field paths after\n * `values.` and `item.`, functions as snippets, and the problems of\n * `checkExpression` underlined where they are.\n */\nexport function expressionCodeExtension(options: ExpressionCodeOptions = {}): CodeExtension {\n const functionNames = () => [\n ...new Set([...Object.keys(builtinFunctions), ...read(options.functions ?? [])]),\n ]\n const infoOf = (name: string) => read(options.functionInfo ?? {})[name]\n\n return defineCodeExtension({\n name: 'form-expression',\n completionTriggers: ['.'],\n completion({ pos, word }, { doc }) {\n const line = doc.lineAt(pos)\n const before = line.text.slice(0, pos - line.from)\n if (inString(before)) return null\n const labels = read(options.labels ?? {})\n\n // A path after `values.` or `item.`, dots and all.\n const path = /\\b(values|item)\\.([\\w$.À-]*)$/.exec(before)\n if (path) {\n const root = path[1] as 'values' | 'item'\n const list = root === 'values' ? read(options.names ?? []) : read(options.itemNames)\n if (!list) return null\n const typed = path[2]!\n const from = pos - typed.length\n return {\n from,\n options: list\n // Paths written with brackets are left to type by hand.\n .filter(({ path: name }) => referenceSource(root, name) === `${root}.${name}`)\n .map(({ path: name, label }) => ({\n label: name,\n kind: 'property' as const,\n detail: label,\n })),\n }\n }\n // After any other dot there is nothing to offer.\n if (before.slice(0, before.length - word.text.length).endsWith('.')) return null\n\n const entries: CodeCompletion[] = [\n { label: 'values', kind: 'variable', detail: labels.values, boost: 2 },\n ]\n if (read(options.itemNames))\n entries.push({ label: 'item', kind: 'variable', detail: labels.item, boost: 2 })\n if (read(options.readsValue ?? false))\n entries.push({ label: 'value', kind: 'variable', detail: labels.value, boost: 2 })\n for (const name of functionNames()) {\n const info = infoOf(name)\n // The parameters to fill in: the required ones; `...rest` once.\n const required = (info ? paramsOf(info.signature) : [])\n .map(([a, b]) => info!.signature.slice(a, b))\n .filter((param) => !param.endsWith('?'))\n const fields = required\n .map((param, i) => `\\${${i + 1}:${param.replace(/^\\.\\.\\./, '')}}`)\n .join(', ')\n entries.push({\n label: name,\n kind: 'function',\n detail: info ? info.signature.slice(name.length) : '()',\n info: info?.info,\n snippet: required.length ? `${name}(${fields})` : `${name}($0)`,\n })\n }\n for (const keyword of KEYWORDS)\n entries.push({ label: keyword, kind: 'keyword', detail: labels.keyword, boost: -1 })\n return { from: word.from, options: entries }\n },\n\n hover({ pos }, { doc }) {\n const line = doc.lineAt(pos)\n const col = pos - line.from\n for (const match of line.text.matchAll(/[A-Za-z_$À-][\\w$À-]*/g)) {\n const from = match.index!\n const to = from + match[0].length\n if (col < from || col > to) continue\n const info = infoOf(match[0])\n if (!info || !/^\\s*\\(/.test(line.text.slice(to))) return null\n return {\n from: line.from + from,\n to: line.from + to,\n content: info.info ? `${info.signature}\\n${info.info}` : info.signature,\n }\n }\n return null\n },\n\n signature({ pos }, { doc }): CodeSignatureResult | null {\n const line = doc.lineAt(pos)\n const call = callAt(line.text, pos - line.from)\n const info = call && infoOf(call.name)\n if (!call || !info) return null\n const params = paramsOf(info.signature)\n // `...numbers` takes the rest.\n const last = params.length - 1\n const rest = last >= 0 && info.signature.slice(params[last]![0]).startsWith('...')\n const active = rest ? Math.min(call.arg, last) : call.arg\n if (active > last) return null\n return { label: info.signature, params, active, info: info.info }\n },\n\n lint:\n options.lint === false\n ? undefined\n : ({ doc }) => {\n const source = doc.toString()\n if (!source.trim()) return []\n const itemNames = read(options.itemNames)\n return checkExpression(source, {\n fields: read(options.names ?? []).map((name) => name.path),\n itemFields: itemNames ? itemNames.map((name) => name.path) : [],\n functions: read(options.functions ?? []),\n }).map((problem): CodeDiagnostic => ({\n from: problem.start,\n to: Math.max(problem.end, problem.start),\n severity: 'error',\n message: options.problemMessage?.(problem) ?? problem.message,\n }))\n },\n })\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { defineFormBuilderExtension } from "../builder/extension.js";
|
|
2
|
+
import { expressionCodeExtension } from "./extension.js";
|
|
3
|
+
import { formExpression } from "./language.js";
|
|
4
|
+
import expression_input_default from "./expression-input.js";
|
|
5
|
+
// src/code/index.ts
|
|
6
|
+
/**
|
|
7
|
+
* Writes the builder's expressions (formulas, checks, conditions as text)
|
|
8
|
+
* in `@dou-ui/code`'s code input: colored, with completions, parameter
|
|
9
|
+
* hints and problems underlined. Needs `@dou-ui/code` and its styles.
|
|
10
|
+
*/
|
|
11
|
+
function codeExpressions() {
|
|
12
|
+
return defineFormBuilderExtension({
|
|
13
|
+
name: "code-expressions",
|
|
14
|
+
expressionInput: expression_input_default
|
|
15
|
+
});
|
|
16
|
+
}
|
|
17
|
+
export { expression_input_default as CodeExpressionInput, codeExpressions, expressionCodeExtension, formExpression };
|
|
18
|
+
|
|
19
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","names":["CodeExpressionInput"],"sources":["../../src/code/index.ts"],"sourcesContent":["import { defineFormBuilderExtension } from '../builder/extension'\nimport type { FormBuilderExtension } from '../builder/extension'\nimport CodeExpressionInput from './expression-input.vue'\n\nexport { expressionCodeExtension } from './extension'\nexport type { ExpressionCodeOptions, ExpressionFunctionInfo, ExpressionName } from './extension'\nexport { formExpression } from './language'\nexport { CodeExpressionInput }\n\n/**\n * Writes the builder's expressions (formulas, checks, conditions as text)\n * in `@dou-ui/code`'s code input: colored, with completions, parameter\n * hints and problems underlined. Needs `@dou-ui/code` and its styles.\n */\nexport function codeExpressions(): FormBuilderExtension {\n return defineFormBuilderExtension({\n name: 'code-expressions',\n expressionInput: CodeExpressionInput,\n })\n}\n"],"mappings":";;;;;;;;;;AAcA,SAAgB,kBAAwC;CACtD,OAAO,2BAA2B;EAChC,MAAM;EACN,iBAAiBA;CACnB,CAAC;AACH"}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { defineCodeLanguage } from "@dou-ui/code";
|
|
2
|
+
// src/code/language.ts
|
|
3
|
+
var NAMES = /* @__PURE__ */ new Set([
|
|
4
|
+
"values",
|
|
5
|
+
"value",
|
|
6
|
+
"item"
|
|
7
|
+
]);
|
|
8
|
+
var KEYWORDS = /* @__PURE__ */ new Set([
|
|
9
|
+
"true",
|
|
10
|
+
"false",
|
|
11
|
+
"null",
|
|
12
|
+
"in"
|
|
13
|
+
]);
|
|
14
|
+
/**
|
|
15
|
+
* The form expression language for `@dou-ui/code`: `values` and its
|
|
16
|
+
* paths, strings, numbers, function calls and operators, colored as in
|
|
17
|
+
* the code editor.
|
|
18
|
+
*/
|
|
19
|
+
var formExpression = defineCodeLanguage({
|
|
20
|
+
name: "form-expression",
|
|
21
|
+
token(stream) {
|
|
22
|
+
if (stream.eatSpace()) return null;
|
|
23
|
+
if (stream.match(/^(['"])(?:\\.|(?!\1).)*\1?/)) return "string";
|
|
24
|
+
if (stream.match(/^\d+(?:\.\d+)?(?:e[+-]?\d+)?/i)) return "number";
|
|
25
|
+
const word = stream.match(/^[A-Za-z_$À-][\w$À-]*/);
|
|
26
|
+
if (word) {
|
|
27
|
+
const text = word[0];
|
|
28
|
+
if (KEYWORDS.has(text)) return "keyword";
|
|
29
|
+
if (NAMES.has(text)) return "variable";
|
|
30
|
+
if (stream.string.charAt(stream.start - 1) === ".") return "property";
|
|
31
|
+
if (/^\s*\(/.test(stream.string.slice(stream.pos))) return "function";
|
|
32
|
+
return "invalid";
|
|
33
|
+
}
|
|
34
|
+
if (stream.match(/^(?:==|!=|<=|>=|&&|\|\||[<>!+\-*/%?:])/)) return "operator";
|
|
35
|
+
stream.next();
|
|
36
|
+
return "punctuation";
|
|
37
|
+
},
|
|
38
|
+
brackets: "()[]",
|
|
39
|
+
autoClose: `(['"`
|
|
40
|
+
});
|
|
41
|
+
export { formExpression };
|
|
42
|
+
|
|
43
|
+
//# sourceMappingURL=language.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"language.js","names":[],"sources":["../../src/code/language.ts"],"sourcesContent":["import { defineCodeLanguage } from '@dou-ui/code'\n\nconst NAMES = new Set(['values', 'value', 'item'])\nconst KEYWORDS = new Set(['true', 'false', 'null', 'in'])\n\n/**\n * The form expression language for `@dou-ui/code`: `values` and its\n * paths, strings, numbers, function calls and operators, colored as in\n * the code editor.\n */\nexport const formExpression = defineCodeLanguage({\n name: 'form-expression',\n token(stream) {\n if (stream.eatSpace()) return null\n if (stream.match(/^(['\"])(?:\\\\.|(?!\\1).)*\\1?/)) return 'string'\n if (stream.match(/^\\d+(?:\\.\\d+)?(?:e[+-]?\\d+)?/i)) return 'number'\n const word = stream.match(/^[A-Za-z_$À-][\\w$À-]*/)\n if (word) {\n const text = word[0]\n if (KEYWORDS.has(text)) return 'keyword'\n if (NAMES.has(text)) return 'variable'\n // A key after a dot, or a name called.\n if (stream.string.charAt(stream.start - 1) === '.') return 'property'\n if (/^\\s*\\(/.test(stream.string.slice(stream.pos))) return 'function'\n return 'invalid'\n }\n if (stream.match(/^(?:==|!=|<=|>=|&&|\\|\\||[<>!+\\-*/%?:])/)) return 'operator'\n stream.next()\n return 'punctuation'\n },\n brackets: '()[]',\n autoClose: `(['\"`,\n})\n"],"mappings":";;AAEA,IAAM,wBAAQ,IAAI,IAAI;CAAC;CAAU;CAAS;AAAM,CAAC;AACjD,IAAM,2BAAW,IAAI,IAAI;CAAC;CAAQ;CAAS;CAAQ;AAAI,CAAC;;;;;;AAOxD,IAAa,iBAAiB,mBAAmB;CAC/C,MAAM;CACN,MAAM,QAAQ;EACZ,IAAI,OAAO,SAAS,GAAG,OAAO;EAC9B,IAAI,OAAO,MAAM,4BAA4B,GAAG,OAAO;EACvD,IAAI,OAAO,MAAM,+BAA+B,GAAG,OAAO;EAC1D,MAAM,OAAO,OAAO,MAAM,yBAAyB;EACnD,IAAI,MAAM;GACR,MAAM,OAAO,KAAK;GAClB,IAAI,SAAS,IAAI,IAAI,GAAG,OAAO;GAC/B,IAAI,MAAM,IAAI,IAAI,GAAG,OAAO;GAE5B,IAAI,OAAO,OAAO,OAAO,OAAO,QAAQ,CAAC,MAAM,KAAK,OAAO;GAC3D,IAAI,SAAS,KAAK,OAAO,OAAO,MAAM,OAAO,GAAG,CAAC,GAAG,OAAO;GAC3D,OAAO;EACT;EACA,IAAI,OAAO,MAAM,wCAAwC,GAAG,OAAO;EACnE,OAAO,KAAK;EACZ,OAAO;CACT;CACA,UAAU;CACV,WAAW;AACb,CAAC"}
|