@shwfed/config 2.5.3 → 2.7.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/dist/mcp.mjs +1220 -1045
- package/dist/module.json +1 -1
- package/dist/module.mjs +7 -1
- package/dist/preview/assets/config-B5FFtD0s.js +1 -0
- package/dist/preview/assets/config-BpWP2vu_.js +1 -0
- package/dist/preview/assets/{config-ekMG8PO0.js → config-C2OqUTNd.js} +1 -1
- package/dist/preview/assets/{config-BVjCjkAL.js → config-D7cjMBeK.js} +1 -1
- package/dist/preview/assets/config-DhORWTZC.js +1 -0
- package/dist/preview/assets/config-DuuYvFG_.js +1 -0
- package/dist/preview/assets/config-dpwN2-UY.js +1 -0
- package/dist/preview/assets/{config-DN6k6pjm.js → config-eP0EblYK.js} +1 -1
- package/dist/preview/assets/{config-CtGduGcR.js → config-hs_pZ5MM.js} +1 -1
- package/dist/preview/assets/{definition.vue_vue_type_script_setup_true_lang-I7unZVnH.js → definition.vue_vue_type_script_setup_true_lang-B8-Uydoy.js} +1 -1
- package/dist/preview/assets/index-BGFrUxgg.js +680 -0
- package/dist/preview/assets/index-BoGW90Pq.css +1 -0
- package/dist/preview/assets/index-Bw16PZhL.js +1 -0
- package/dist/preview/assets/index-CG261V86.js +1 -0
- package/dist/preview/assets/item-aVe51Gy6.js +1 -0
- package/dist/preview/assets/runtime-3rNI0KDH.js +1 -0
- package/dist/preview/assets/runtime-BOn8EwHL.js +1 -0
- package/dist/preview/assets/runtime-Bwr-rb58.js +1 -0
- package/dist/preview/assets/runtime-CXQuhSAX.js +1 -0
- package/dist/preview/assets/runtime-CYGmRjmI.js +1 -0
- package/dist/preview/assets/runtime-Ca79Fs6I.js +1 -0
- package/dist/preview/assets/runtime-CfVt6IWe.js +1 -0
- package/dist/preview/assets/runtime-DYj-R8SZ.js +1 -0
- package/dist/preview/assets/runtime-Dd1GqYeP.js +1 -0
- package/dist/preview/index.html +2 -2
- package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/config.d.vue.ts +59 -0
- package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/config.vue +452 -0
- package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/config.vue.d.ts +59 -0
- package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/item.d.vue.ts +7 -0
- package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/item.vue +112 -0
- package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/item.vue.d.ts +7 -0
- package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/runtime.d.vue.ts +59 -0
- package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/runtime.vue +47 -0
- package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/runtime.vue.d.ts +59 -0
- package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/schema.d.ts +92 -0
- package/dist/runtime/components/config/blocks/2026-06-01/com.shwfed.block.animated.number/schema.js +117 -0
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.d.vue.ts +4 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.daterange/config.vue.d.ts +4 -4
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.d.vue.ts +6 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.datetimerange/config.vue.d.ts +6 -6
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.d.vue.ts +2 -2
- package/dist/runtime/components/form/fields/2026-04-27/com.shwfed.form.field.timerange/config.vue.d.ts +2 -2
- package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.d.vue.ts +4 -4
- package/dist/runtime/components/form/fields/2026-05-24/com.shwfed.form.field.monthrange/config.vue.d.ts +4 -4
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.multi/schema.js +1 -1
- package/dist/runtime/components/form/fields/2026-05-28/com.shwfed.form.field.combobox.single/schema.js +1 -1
- package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-remote/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-24/com.shwfed.table.column.combobox-single.remote.options-static/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-remote/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-25/com.shwfed.table.column.combobox-multi.remote.options-static/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-multi.remote/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-26/com.shwfed.table.column.combobox-single.remote/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-multi/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.d.vue.ts +2 -2
- package/dist/runtime/components/table/columns/2026-05-28/com.shwfed.table.column.combobox-single/config.vue.d.ts +2 -2
- package/dist/runtime/components/table/config.vue +17 -1
- package/dist/runtime/components/table/index.vue +1 -0
- package/dist/runtime/components/table/row-provider.d.vue.ts +1 -0
- package/dist/runtime/components/table/row-provider.vue +9 -2
- package/dist/runtime/components/table/row-provider.vue.d.ts +1 -0
- package/dist/runtime/components/ui/date-picker/DatePickerInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerTimeInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-picker/DatePickerTimeInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.d.vue.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerInput.vue.d.ts +1 -1
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.d.vue.ts +2 -2
- package/dist/runtime/components/ui/date-range-picker/DateRangePickerTimeInput.vue.d.ts +2 -2
- package/dist/runtime/components/ui/expression-editor/CodeMirrorInput.d.vue.ts +22 -0
- package/dist/runtime/components/ui/expression-editor/CodeMirrorInput.vue +134 -0
- package/dist/runtime/components/ui/expression-editor/CodeMirrorInput.vue.d.ts +22 -0
- package/dist/runtime/components/ui/expression-editor/ExpressionEditor.d.vue.ts +2 -2
- package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue +71 -50
- package/dist/runtime/components/ui/expression-editor/ExpressionEditor.vue.d.ts +2 -2
- package/dist/runtime/components/ui/expression-editor/cel-language.d.ts +16 -0
- package/dist/runtime/components/ui/expression-editor/cel-language.js +114 -0
- package/dist/runtime/components/ui/expression-editor/chip-extension.d.ts +5 -0
- package/dist/runtime/components/ui/expression-editor/chip-extension.js +123 -0
- package/dist/runtime/components/ui/expression-editor/picker-entries.d.ts +17 -0
- package/dist/runtime/components/ui/expression-editor/picker-entries.js +34 -0
- package/dist/runtime/components/ui/expression-editor/scope-refs.d.ts +20 -0
- package/dist/runtime/components/ui/expression-editor/scope-refs.js +39 -0
- package/dist/runtime/share/expression.js +9 -0
- package/dist/runtime/utils/cel-context.d.ts +36 -0
- package/dist/runtime/utils/cel-context.js +39 -0
- package/package.json +7 -1
- package/dist/preview/assets/config-C5TWIUX-.js +0 -1
- package/dist/preview/assets/config-CH28q4_H.js +0 -1
- package/dist/preview/assets/config-D9tBv8LD.js +0 -1
- package/dist/preview/assets/config-DxB8qwAu.js +0 -1
- package/dist/preview/assets/config-U359oLg8.js +0 -1
- package/dist/preview/assets/index-CZ-XSjS_.js +0 -668
- package/dist/preview/assets/index-HfGseg4M.js +0 -1
- package/dist/preview/assets/index-nvAUAYGM.css +0 -1
- package/dist/preview/assets/runtime-27bDIkKv.js +0 -1
- package/dist/preview/assets/runtime-BAQ6ezPo.js +0 -1
- package/dist/preview/assets/runtime-BKQvzSax.js +0 -1
- package/dist/preview/assets/runtime-BafXFP0s.js +0 -1
- package/dist/preview/assets/runtime-CAzVJ-if.js +0 -1
- package/dist/preview/assets/runtime-CQly-3c3.js +0 -1
- package/dist/preview/assets/runtime-DJgDXKfE.js +0 -1
- package/dist/preview/assets/runtime-Dhd51Wyr.js +0 -1
- package/dist/preview/assets/runtime-x8IdC454.js +0 -1
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
<script setup>
|
|
2
|
+
import { Compartment, EditorState } from "@codemirror/state";
|
|
3
|
+
import { EditorView, keymap, placeholder as cmPlaceholder } from "@codemirror/view";
|
|
4
|
+
import { defaultKeymap, history, historyKeymap } from "@codemirror/commands";
|
|
5
|
+
import { onBeforeUnmount, onMounted, useTemplateRef, watch } from "vue";
|
|
6
|
+
import { cn } from "../../../utils/cn";
|
|
7
|
+
import { celHighlighting } from "./cel-language";
|
|
8
|
+
import { scopeChips, scopeLookupFacet } from "./chip-extension";
|
|
9
|
+
defineOptions({ name: "UiCodeMirrorInput" });
|
|
10
|
+
const props = defineProps({
|
|
11
|
+
class: { type: [Boolean, null, String, Object, Array], required: false, skipCheck: true },
|
|
12
|
+
defaultValue: { type: String, required: false },
|
|
13
|
+
modelValue: { type: String, required: false },
|
|
14
|
+
multiline: { type: Boolean, required: false },
|
|
15
|
+
placeholder: { type: String, required: false },
|
|
16
|
+
scopeLookup: { type: Map, required: true }
|
|
17
|
+
});
|
|
18
|
+
const emits = defineEmits(["update:modelValue"]);
|
|
19
|
+
const host = useTemplateRef("host");
|
|
20
|
+
let view = null;
|
|
21
|
+
const lookupCompartment = new Compartment();
|
|
22
|
+
const modeCompartment = new Compartment();
|
|
23
|
+
let applyingExternal = false;
|
|
24
|
+
const editorTheme = EditorView.theme({
|
|
25
|
+
"&": {
|
|
26
|
+
fontSize: "0.875rem",
|
|
27
|
+
color: "var(--color-zinc-700)",
|
|
28
|
+
backgroundColor: "transparent"
|
|
29
|
+
},
|
|
30
|
+
"&.cm-focused": {
|
|
31
|
+
outline: "none"
|
|
32
|
+
},
|
|
33
|
+
".cm-content": {
|
|
34
|
+
fontFamily: "var(--font-mono)",
|
|
35
|
+
padding: "7px 0",
|
|
36
|
+
lineHeight: "1.5",
|
|
37
|
+
caretColor: "var(--color-zinc-700)"
|
|
38
|
+
},
|
|
39
|
+
".cm-placeholder": {
|
|
40
|
+
color: "var(--color-zinc-200)"
|
|
41
|
+
},
|
|
42
|
+
".cm-scroller": {
|
|
43
|
+
fontFamily: "var(--font-mono)",
|
|
44
|
+
lineHeight: "1.5"
|
|
45
|
+
},
|
|
46
|
+
".cm-line": {
|
|
47
|
+
padding: "0"
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
function modeExtension(multiline) {
|
|
51
|
+
if (multiline) return EditorView.lineWrapping;
|
|
52
|
+
return EditorState.transactionFilter.of((tr) => {
|
|
53
|
+
if (!tr.docChanged) return tr;
|
|
54
|
+
let hasNewline = false;
|
|
55
|
+
tr.changes.iterChanges((_fromA, _toA, _fromB, _toB, inserted) => {
|
|
56
|
+
if (inserted.lines > 1) hasNewline = true;
|
|
57
|
+
});
|
|
58
|
+
return hasNewline ? [] : tr;
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
function makeState(doc) {
|
|
62
|
+
return EditorState.create({
|
|
63
|
+
doc,
|
|
64
|
+
extensions: [
|
|
65
|
+
history(),
|
|
66
|
+
keymap.of([...defaultKeymap, ...historyKeymap]),
|
|
67
|
+
cmPlaceholder(props.placeholder ?? ""),
|
|
68
|
+
lookupCompartment.of(scopeLookupFacet.of(props.scopeLookup)),
|
|
69
|
+
modeCompartment.of(modeExtension(!!props.multiline)),
|
|
70
|
+
editorTheme,
|
|
71
|
+
// CEL syntax colours sit *under* the chips: the chip plugin's
|
|
72
|
+
// `Decoration.replace` widgets hide the `__scopes__[...]` spans, so the
|
|
73
|
+
// marks here only show through on ordinary expression text.
|
|
74
|
+
celHighlighting(),
|
|
75
|
+
scopeChips(),
|
|
76
|
+
EditorView.contentAttributes.of({ "aria-label": props.placeholder ?? "Expression" }),
|
|
77
|
+
EditorView.updateListener.of((update) => {
|
|
78
|
+
if (!update.docChanged || applyingExternal) return;
|
|
79
|
+
emits("update:modelValue", update.state.doc.toString());
|
|
80
|
+
})
|
|
81
|
+
]
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
onMounted(() => {
|
|
85
|
+
if (!host.value) return;
|
|
86
|
+
view = new EditorView({
|
|
87
|
+
state: makeState(props.modelValue ?? props.defaultValue ?? ""),
|
|
88
|
+
parent: host.value
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
onBeforeUnmount(() => {
|
|
92
|
+
view?.destroy();
|
|
93
|
+
view = null;
|
|
94
|
+
});
|
|
95
|
+
watch(() => props.modelValue, (next) => {
|
|
96
|
+
if (!view) return;
|
|
97
|
+
const incoming = next ?? "";
|
|
98
|
+
if (incoming === view.state.doc.toString()) return;
|
|
99
|
+
applyingExternal = true;
|
|
100
|
+
view.dispatch({ changes: { from: 0, to: view.state.doc.length, insert: incoming } });
|
|
101
|
+
applyingExternal = false;
|
|
102
|
+
});
|
|
103
|
+
watch(() => props.scopeLookup, (lookup) => {
|
|
104
|
+
view?.dispatch({ effects: lookupCompartment.reconfigure(scopeLookupFacet.of(lookup)) });
|
|
105
|
+
});
|
|
106
|
+
watch(() => props.multiline, (multiline) => {
|
|
107
|
+
view?.dispatch({ effects: modeCompartment.reconfigure(modeExtension(!!multiline)) });
|
|
108
|
+
});
|
|
109
|
+
function insertAtSelection(text) {
|
|
110
|
+
if (!view) return;
|
|
111
|
+
const { from, to } = view.state.selection.main;
|
|
112
|
+
view.dispatch({
|
|
113
|
+
changes: { from, to, insert: text },
|
|
114
|
+
selection: { anchor: from + text.length }
|
|
115
|
+
});
|
|
116
|
+
view.focus();
|
|
117
|
+
}
|
|
118
|
+
function focus() {
|
|
119
|
+
view?.focus();
|
|
120
|
+
}
|
|
121
|
+
defineExpose({ insertAtSelection, focus });
|
|
122
|
+
</script>
|
|
123
|
+
|
|
124
|
+
<template>
|
|
125
|
+
<div
|
|
126
|
+
ref="host"
|
|
127
|
+
data-slot="input-group-control"
|
|
128
|
+
:class="cn(
|
|
129
|
+
'flex-1 min-w-0 self-stretch overflow-x-auto px-3',
|
|
130
|
+
props.multiline ? '[&_.cm-content]:min-h-16' : '[&_.cm-scroller]:items-center',
|
|
131
|
+
props.class
|
|
132
|
+
)"
|
|
133
|
+
/>
|
|
134
|
+
</template>
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { HTMLAttributes } from 'vue';
|
|
2
|
+
import type { ScopeInfo } from './scope-refs.js';
|
|
3
|
+
type __VLS_Props = {
|
|
4
|
+
class?: HTMLAttributes['class'];
|
|
5
|
+
defaultValue?: string;
|
|
6
|
+
modelValue?: string;
|
|
7
|
+
multiline?: boolean;
|
|
8
|
+
placeholder?: string;
|
|
9
|
+
scopeLookup: Map<string, ScopeInfo>;
|
|
10
|
+
};
|
|
11
|
+
declare function insertAtSelection(text: string): void;
|
|
12
|
+
declare function focus(): void;
|
|
13
|
+
declare const __VLS_export: import("vue").DefineComponent<__VLS_Props, {
|
|
14
|
+
insertAtSelection: typeof insertAtSelection;
|
|
15
|
+
focus: typeof focus;
|
|
16
|
+
}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
17
|
+
"update:modelValue": (payload: string) => any;
|
|
18
|
+
}, string, import("vue").PublicProps, Readonly<__VLS_Props> & Readonly<{
|
|
19
|
+
"onUpdate:modelValue"?: ((payload: string) => any) | undefined;
|
|
20
|
+
}>, {}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
21
|
+
declare const _default: typeof __VLS_export;
|
|
22
|
+
export default _default;
|
|
@@ -13,11 +13,11 @@ type __VLS_Props = {
|
|
|
13
13
|
resultType?: string | string[];
|
|
14
14
|
extraVars?: Record<string, VarSpec>;
|
|
15
15
|
};
|
|
16
|
-
declare var __VLS_14: {},
|
|
16
|
+
declare var __VLS_14: {}, __VLS_130: {};
|
|
17
17
|
type __VLS_Slots = {} & {
|
|
18
18
|
leading?: (props: typeof __VLS_14) => any;
|
|
19
19
|
} & {
|
|
20
|
-
trailing?: (props: typeof
|
|
20
|
+
trailing?: (props: typeof __VLS_130) => any;
|
|
21
21
|
};
|
|
22
22
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
23
23
|
"update:modelValue": (payload: string) => any;
|
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
<script setup>
|
|
2
2
|
import { Icon } from "@iconify/vue";
|
|
3
|
-
import { computed, ref, useSlots, watch } from "vue";
|
|
4
|
-
import { injectCELContext } from "../../../utils/cel-context";
|
|
3
|
+
import { computed, ref, useSlots, useTemplateRef, watch } from "vue";
|
|
4
|
+
import { injectCELContext, useScopeAncestry } from "../../../utils/cel-context";
|
|
5
5
|
import { Markdown } from "../markdown";
|
|
6
|
-
import
|
|
6
|
+
import CodeMirrorInput from "./CodeMirrorInput.vue";
|
|
7
|
+
import { buildScopeLookup } from "./scope-refs";
|
|
8
|
+
import { buildScopeEntries, buildVarEntries } from "./picker-entries";
|
|
7
9
|
import { Command, CommandEmpty, CommandGroup, CommandInput, CommandItem, CommandList } from "../command";
|
|
8
|
-
import { InputGroup, InputGroupAddon, InputGroupButton
|
|
10
|
+
import { InputGroup, InputGroupAddon, InputGroupButton } from "../input-group";
|
|
9
11
|
import { Popover, PopoverContent, PopoverTrigger } from "../popover";
|
|
10
12
|
defineOptions({ name: "UiExpressionEditor" });
|
|
11
13
|
const props = defineProps({
|
|
@@ -19,31 +21,31 @@ const props = defineProps({
|
|
|
19
21
|
});
|
|
20
22
|
const emits = defineEmits(["update:modelValue"]);
|
|
21
23
|
const celContext = injectCELContext();
|
|
22
|
-
const
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
for (const [name, meta] of Object.entries(props.extraVars ?? {})) {
|
|
28
|
-
if (seen.has(name)) continue;
|
|
29
|
-
out.push({ name, meta });
|
|
30
|
-
}
|
|
31
|
-
return out;
|
|
32
|
-
});
|
|
33
|
-
const hasVars = computed(() => mergedEntries.value.length > 0);
|
|
24
|
+
const scopeAncestry = useScopeAncestry();
|
|
25
|
+
const varEntries = computed(() => buildVarEntries(celContext, props.extraVars));
|
|
26
|
+
const scopeEntries = computed(() => buildScopeEntries(scopeAncestry.value.slice(1)));
|
|
27
|
+
const scopeLookup = computed(() => buildScopeLookup(scopeAncestry.value));
|
|
28
|
+
const hasVars = computed(() => varEntries.value.length > 0 || scopeEntries.value.length > 0);
|
|
34
29
|
const open = ref(false);
|
|
35
30
|
const entries = ref([]);
|
|
31
|
+
const shownVars = computed(() => entries.value.filter((e) => e.group === "var"));
|
|
32
|
+
const shownScopes = computed(() => entries.value.filter((e) => e.group === "scope"));
|
|
36
33
|
const hoveredName = ref(null);
|
|
34
|
+
const editorRef = useTemplateRef("editor");
|
|
35
|
+
function insertVariable(text) {
|
|
36
|
+
editorRef.value?.insertAtSelection(text);
|
|
37
|
+
open.value = false;
|
|
38
|
+
}
|
|
37
39
|
watch(open, (v) => {
|
|
38
40
|
if (v) {
|
|
39
|
-
entries.value =
|
|
40
|
-
hoveredName.value = entries.value[0]?.
|
|
41
|
+
entries.value = [...varEntries.value, ...scopeEntries.value];
|
|
42
|
+
hoveredName.value = entries.value[0]?.id ?? null;
|
|
41
43
|
}
|
|
42
44
|
});
|
|
43
|
-
const
|
|
44
|
-
() => entries.value.find((e) => e.
|
|
45
|
+
const hoveredEntry = computed(
|
|
46
|
+
() => entries.value.find((e) => e.id === hoveredName.value) ?? null
|
|
45
47
|
);
|
|
46
|
-
const hoveredDescription = computed(() =>
|
|
48
|
+
const hoveredDescription = computed(() => hoveredEntry.value?.description ?? "");
|
|
47
49
|
const resultTypeLabel = computed(() => {
|
|
48
50
|
const rt = props.resultType;
|
|
49
51
|
if (!rt) return null;
|
|
@@ -65,21 +67,15 @@ const addonAlign = computed(
|
|
|
65
67
|
>
|
|
66
68
|
<slot name="leading" />
|
|
67
69
|
</InputGroupAddon>
|
|
68
|
-
<
|
|
69
|
-
|
|
70
|
+
<CodeMirrorInput
|
|
71
|
+
ref="editor"
|
|
70
72
|
:model-value="props.modelValue"
|
|
71
73
|
:default-value="props.defaultValue"
|
|
72
74
|
:placeholder="props.placeholder"
|
|
73
|
-
:
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
v-else
|
|
78
|
-
:model-value="props.modelValue"
|
|
79
|
-
:default-value="props.defaultValue"
|
|
80
|
-
:placeholder="props.placeholder"
|
|
81
|
-
:class="cn('font-mono text-xs', props.class)"
|
|
82
|
-
@update:model-value="(v) => emits('update:modelValue', String(v))"
|
|
75
|
+
:multiline="props.multiline"
|
|
76
|
+
:scope-lookup="scopeLookup"
|
|
77
|
+
:class="props.class"
|
|
78
|
+
@update:model-value="(v) => emits('update:modelValue', v)"
|
|
83
79
|
/>
|
|
84
80
|
<InputGroupAddon
|
|
85
81
|
v-if="showAddon"
|
|
@@ -109,34 +105,59 @@ const addonAlign = computed(
|
|
|
109
105
|
<CommandEmpty>No variables.</CommandEmpty>
|
|
110
106
|
<CommandGroup>
|
|
111
107
|
<CommandItem
|
|
112
|
-
v-for="entry in
|
|
113
|
-
:key="entry.
|
|
114
|
-
:value="entry.
|
|
115
|
-
class="cursor-
|
|
116
|
-
@
|
|
117
|
-
@
|
|
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"
|
|
118
115
|
>
|
|
119
|
-
<
|
|
120
|
-
|
|
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>
|
|
121
122
|
<span class="rounded bg-purple-100 px-1.5 py-0.5 font-mono text-[10px] leading-none text-purple-700 select-none">
|
|
122
|
-
{{ entry.
|
|
123
|
+
{{ entry.type }}
|
|
124
|
+
</span>
|
|
125
|
+
</CommandItem>
|
|
126
|
+
</CommandGroup>
|
|
127
|
+
<CommandGroup
|
|
128
|
+
v-if="shownScopes.length > 0"
|
|
129
|
+
heading="跨层引用"
|
|
130
|
+
>
|
|
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 }}
|
|
123
147
|
</span>
|
|
124
148
|
</CommandItem>
|
|
125
149
|
</CommandGroup>
|
|
126
150
|
</CommandList>
|
|
127
151
|
<div
|
|
128
|
-
v-if="
|
|
152
|
+
v-if="hoveredEntry"
|
|
129
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"
|
|
130
154
|
>
|
|
131
|
-
<div class="
|
|
132
|
-
<span class="
|
|
133
|
-
<span class="rounded bg-purple-100 px-1.5 py-0.5 font-mono text-[10px] leading-none text-purple-700 select-none">
|
|
134
|
-
{{
|
|
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 }}
|
|
135
159
|
</span>
|
|
136
160
|
</div>
|
|
137
|
-
<div class="text-xs font-medium text-zinc-700">
|
|
138
|
-
{{ hoveredMeta.label }}
|
|
139
|
-
</div>
|
|
140
161
|
<Markdown
|
|
141
162
|
v-if="hoveredDescription"
|
|
142
163
|
:source="hoveredDescription"
|
|
@@ -13,11 +13,11 @@ type __VLS_Props = {
|
|
|
13
13
|
resultType?: string | string[];
|
|
14
14
|
extraVars?: Record<string, VarSpec>;
|
|
15
15
|
};
|
|
16
|
-
declare var __VLS_14: {},
|
|
16
|
+
declare var __VLS_14: {}, __VLS_130: {};
|
|
17
17
|
type __VLS_Slots = {} & {
|
|
18
18
|
leading?: (props: typeof __VLS_14) => any;
|
|
19
19
|
} & {
|
|
20
|
-
trailing?: (props: typeof
|
|
20
|
+
trailing?: (props: typeof __VLS_130) => any;
|
|
21
21
|
};
|
|
22
22
|
declare const __VLS_base: import("vue").DefineComponent<__VLS_Props, {}, {}, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {} & {
|
|
23
23
|
"update:modelValue": (payload: string) => any;
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import type { Extension } from '@codemirror/state';
|
|
2
|
+
import { StreamLanguage } from '@codemirror/language';
|
|
3
|
+
type State = {
|
|
4
|
+
afterDot: boolean;
|
|
5
|
+
};
|
|
6
|
+
/** The CEL stream language (tokeniser only — no indentation/folding services). */
|
|
7
|
+
export declare const celLanguage: StreamLanguage<State>;
|
|
8
|
+
/** One tokenised slice of a line: the source `text` and its stream-token name. */
|
|
9
|
+
export type CELToken = {
|
|
10
|
+
text: string;
|
|
11
|
+
token: string | null;
|
|
12
|
+
};
|
|
13
|
+
export declare function tokenizeCEL(line: string): CELToken[];
|
|
14
|
+
/** Full lexical-highlighting extension: the CEL language + its colour scheme. */
|
|
15
|
+
export declare function celHighlighting(): Extension;
|
|
16
|
+
export {};
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
import {
|
|
2
|
+
HighlightStyle,
|
|
3
|
+
StreamLanguage,
|
|
4
|
+
StringStream,
|
|
5
|
+
syntaxHighlighting
|
|
6
|
+
} from "@codemirror/language";
|
|
7
|
+
import { tags as t } from "@lezer/highlight";
|
|
8
|
+
const ATOMS = /* @__PURE__ */ new Set(["true", "false", "null"]);
|
|
9
|
+
const OPERATOR_RE = /^(?:==|!=|<=|>=|&&|\|\||[+\-*/%<>!?])/;
|
|
10
|
+
const IDENT_RE = /^[A-Z_$][\w$]*/i;
|
|
11
|
+
const NUMBER_RE = /^(?:0x[0-9a-f]+|\d+\.\d*(?:e[+-]?\d+)?|\d+(?:e[+-]?\d+)?)u?/i;
|
|
12
|
+
function eatString(stream) {
|
|
13
|
+
const s = stream.string;
|
|
14
|
+
const start = stream.pos;
|
|
15
|
+
let i = start;
|
|
16
|
+
let prefixLen = 0;
|
|
17
|
+
while (prefixLen < 2 && /[br]/i.test(s[i + prefixLen] ?? "")) prefixLen++;
|
|
18
|
+
const quote = s[i + prefixLen];
|
|
19
|
+
if (quote !== '"' && quote !== "'") return false;
|
|
20
|
+
const raw = /r/i.test(s.slice(i, i + prefixLen));
|
|
21
|
+
i += prefixLen;
|
|
22
|
+
const triple = s.slice(i, i + 3) === quote + quote + quote;
|
|
23
|
+
const closer = triple ? quote + quote + quote : quote;
|
|
24
|
+
i += closer.length;
|
|
25
|
+
while (i < s.length) {
|
|
26
|
+
const c = s[i];
|
|
27
|
+
if (!raw && c === "\\") {
|
|
28
|
+
i += 2;
|
|
29
|
+
continue;
|
|
30
|
+
}
|
|
31
|
+
if (s.slice(i, i + closer.length) === closer) {
|
|
32
|
+
i += closer.length;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
if (!triple && (c === "\n" || c === "\r")) break;
|
|
36
|
+
i++;
|
|
37
|
+
}
|
|
38
|
+
stream.pos = Math.min(i, s.length);
|
|
39
|
+
return true;
|
|
40
|
+
}
|
|
41
|
+
const celStreamParser = {
|
|
42
|
+
startState: () => ({ afterDot: false }),
|
|
43
|
+
copyState: (state) => ({ afterDot: state.afterDot }),
|
|
44
|
+
token(stream, state) {
|
|
45
|
+
if (stream.eatSpace()) return null;
|
|
46
|
+
if (stream.match(/^\.\.\./)) {
|
|
47
|
+
state.afterDot = false;
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
if (eatString(stream)) {
|
|
51
|
+
state.afterDot = false;
|
|
52
|
+
return "string";
|
|
53
|
+
}
|
|
54
|
+
if (stream.match(NUMBER_RE)) {
|
|
55
|
+
state.afterDot = false;
|
|
56
|
+
return "number";
|
|
57
|
+
}
|
|
58
|
+
const ident = stream.match(IDENT_RE);
|
|
59
|
+
if (ident) {
|
|
60
|
+
const word = ident[0];
|
|
61
|
+
const afterDot = state.afterDot;
|
|
62
|
+
state.afterDot = false;
|
|
63
|
+
if (afterDot) return "propertyName";
|
|
64
|
+
if (word === "in") return "keyword";
|
|
65
|
+
if (ATOMS.has(word)) return "atom";
|
|
66
|
+
return stream.peek() === "(" ? "variableName.function" : "variableName";
|
|
67
|
+
}
|
|
68
|
+
if (stream.match(OPERATOR_RE)) {
|
|
69
|
+
state.afterDot = false;
|
|
70
|
+
return "operator";
|
|
71
|
+
}
|
|
72
|
+
if (stream.eat(".")) {
|
|
73
|
+
state.afterDot = true;
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
state.afterDot = false;
|
|
77
|
+
stream.next();
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
};
|
|
81
|
+
export const celLanguage = StreamLanguage.define(celStreamParser);
|
|
82
|
+
export function tokenizeCEL(line) {
|
|
83
|
+
const stream = new StringStream(line, 4, 2);
|
|
84
|
+
const state = celStreamParser.startState();
|
|
85
|
+
const out = [];
|
|
86
|
+
while (!stream.eol()) {
|
|
87
|
+
stream.start = stream.pos;
|
|
88
|
+
const token = celStreamParser.token(stream, state);
|
|
89
|
+
if (stream.pos === stream.start) stream.next();
|
|
90
|
+
out.push({ text: line.slice(stream.start, stream.pos), token });
|
|
91
|
+
}
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
const celHighlightStyle = HighlightStyle.define([
|
|
95
|
+
{ tag: t.keyword, color: "#5a3e8e" },
|
|
96
|
+
// magenta — control keyword `in`
|
|
97
|
+
{ tag: t.operator, color: "#5a3e8e" },
|
|
98
|
+
// magenta — && || == + - …
|
|
99
|
+
{ tag: t.string, color: "#385f0d" },
|
|
100
|
+
// green — strings / bytes
|
|
101
|
+
{ tag: t.number, color: "#965027" },
|
|
102
|
+
// orange — numbers
|
|
103
|
+
{ tag: t.atom, color: "#965027" },
|
|
104
|
+
// orange — true / false / null
|
|
105
|
+
{ tag: t.variableName, color: "#343b58" },
|
|
106
|
+
// navy — variables
|
|
107
|
+
{ tag: t.propertyName, color: "#0f4b6e" },
|
|
108
|
+
// cyan — object properties / member access
|
|
109
|
+
{ tag: t.function(t.variableName), color: "#2959aa" }
|
|
110
|
+
// blue — function calls
|
|
111
|
+
]);
|
|
112
|
+
export function celHighlighting() {
|
|
113
|
+
return [celLanguage, syntaxHighlighting(celHighlightStyle)];
|
|
114
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type Extension, Facet } from '@codemirror/state';
|
|
2
|
+
import { type ScopeInfo } from './scope-refs.js';
|
|
3
|
+
export declare const scopeLookupFacet: Facet<Map<string, ScopeInfo>, Map<string, ScopeInfo>>;
|
|
4
|
+
/** The full inline-chip extension: decoration plugin + theme. */
|
|
5
|
+
export declare function scopeChips(): Extension;
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { Facet, RangeSetBuilder } from "@codemirror/state";
|
|
2
|
+
import {
|
|
3
|
+
Decoration,
|
|
4
|
+
EditorView,
|
|
5
|
+
ViewPlugin,
|
|
6
|
+
WidgetType
|
|
7
|
+
} from "@codemirror/view";
|
|
8
|
+
import { scanScopeRefs } from "./scope-refs.js";
|
|
9
|
+
export const scopeLookupFacet = Facet.define({
|
|
10
|
+
combine: (values) => values.length > 0 ? values[values.length - 1] : /* @__PURE__ */ new Map()
|
|
11
|
+
});
|
|
12
|
+
class ScopeChipWidget extends WidgetType {
|
|
13
|
+
constructor(id, member, resolved) {
|
|
14
|
+
super();
|
|
15
|
+
this.id = id;
|
|
16
|
+
this.member = member;
|
|
17
|
+
this.resolved = resolved;
|
|
18
|
+
}
|
|
19
|
+
eq(other) {
|
|
20
|
+
return other.id === this.id && other.member === this.member && other.resolved?.origin === this.resolved?.origin && other.resolved?.label === this.resolved?.label && other.resolved?.type === this.resolved?.type;
|
|
21
|
+
}
|
|
22
|
+
toDOM() {
|
|
23
|
+
const chip = document.createElement("span");
|
|
24
|
+
chip.className = "cm-scope-chip";
|
|
25
|
+
chip.setAttribute("data-scope-id", this.id);
|
|
26
|
+
chip.setAttribute("data-scope-member", this.member);
|
|
27
|
+
const text = document.createElement("span");
|
|
28
|
+
text.className = "cm-scope-chip-label";
|
|
29
|
+
if (this.resolved) {
|
|
30
|
+
text.textContent = `${this.resolved.origin} \u203A ${this.resolved.label}`;
|
|
31
|
+
chip.title = this.resolved.origin;
|
|
32
|
+
} else {
|
|
33
|
+
chip.classList.add("cm-scope-chip-dangling");
|
|
34
|
+
const short = this.id.length > 8 ? `${this.id.slice(0, 8)}\u2026` : this.id;
|
|
35
|
+
text.textContent = `${short} \u203A ${this.member}`;
|
|
36
|
+
chip.title = `\u672A\u77E5\u4F5C\u7528\u57DF ${this.id}`;
|
|
37
|
+
}
|
|
38
|
+
chip.appendChild(text);
|
|
39
|
+
const type = this.resolved?.type;
|
|
40
|
+
if (type) {
|
|
41
|
+
const badge = document.createElement("span");
|
|
42
|
+
badge.className = "cm-scope-chip-type";
|
|
43
|
+
badge.textContent = type;
|
|
44
|
+
chip.appendChild(badge);
|
|
45
|
+
}
|
|
46
|
+
return chip;
|
|
47
|
+
}
|
|
48
|
+
ignoreEvent() {
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
function buildChips(view) {
|
|
53
|
+
const lookup = view.state.facet(scopeLookupFacet);
|
|
54
|
+
const builder = new RangeSetBuilder();
|
|
55
|
+
for (const ref of scanScopeRefs(view.state.doc.toString())) {
|
|
56
|
+
const info = lookup.get(ref.id);
|
|
57
|
+
const member = info?.members.get(ref.member);
|
|
58
|
+
const resolved = info && member ? { origin: info.origin, label: member.label, type: member.type } : null;
|
|
59
|
+
builder.add(
|
|
60
|
+
ref.from,
|
|
61
|
+
ref.to,
|
|
62
|
+
Decoration.replace({ widget: new ScopeChipWidget(ref.id, ref.member, resolved) })
|
|
63
|
+
);
|
|
64
|
+
}
|
|
65
|
+
return builder.finish();
|
|
66
|
+
}
|
|
67
|
+
const chipPlugin = ViewPlugin.fromClass(
|
|
68
|
+
class {
|
|
69
|
+
decorations;
|
|
70
|
+
constructor(view) {
|
|
71
|
+
this.decorations = buildChips(view);
|
|
72
|
+
}
|
|
73
|
+
update(update) {
|
|
74
|
+
if (update.docChanged || update.viewportChanged || update.startState.facet(scopeLookupFacet) !== update.state.facet(scopeLookupFacet)) {
|
|
75
|
+
this.decorations = buildChips(update.view);
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
decorations: (plugin) => plugin.decorations,
|
|
81
|
+
// Atomic ranges so the caret steps over a chip and Backspace removes the
|
|
82
|
+
// whole `__scopes__[...].member` at once — the user's delete-as-unit choice.
|
|
83
|
+
provide: (plugin) => EditorView.atomicRanges.of((view) => view.plugin(plugin)?.decorations ?? Decoration.none)
|
|
84
|
+
}
|
|
85
|
+
);
|
|
86
|
+
const chipTheme = EditorView.theme({
|
|
87
|
+
".cm-scope-chip": {
|
|
88
|
+
display: "inline-flex",
|
|
89
|
+
alignItems: "center",
|
|
90
|
+
gap: "0.25rem",
|
|
91
|
+
margin: "0 1px",
|
|
92
|
+
padding: "0.125rem 0.25rem",
|
|
93
|
+
borderRadius: "0.25rem",
|
|
94
|
+
background: "#f4f4f5",
|
|
95
|
+
border: "1px solid #e4e4e7",
|
|
96
|
+
color: "#3f3f46",
|
|
97
|
+
fontFamily: "ui-sans-serif, system-ui, sans-serif",
|
|
98
|
+
verticalAlign: "baseline",
|
|
99
|
+
cursor: "default",
|
|
100
|
+
whiteSpace: "nowrap"
|
|
101
|
+
},
|
|
102
|
+
".cm-scope-chip-dangling": {
|
|
103
|
+
background: "#fef2f2",
|
|
104
|
+
borderColor: "#fecaca",
|
|
105
|
+
color: "#b91c1c"
|
|
106
|
+
},
|
|
107
|
+
".cm-scope-chip-label": {
|
|
108
|
+
fontSize: "0.75rem",
|
|
109
|
+
lineHeight: "1.1"
|
|
110
|
+
},
|
|
111
|
+
".cm-scope-chip-type": {
|
|
112
|
+
borderRadius: "0.25rem",
|
|
113
|
+
background: "#f3e8ff",
|
|
114
|
+
padding: "0.05rem 0.25rem",
|
|
115
|
+
fontFamily: "var(--font-mono)",
|
|
116
|
+
fontSize: "10px",
|
|
117
|
+
lineHeight: "1",
|
|
118
|
+
color: "#7e22ce"
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
export function scopeChips() {
|
|
122
|
+
return [chipPlugin, chipTheme];
|
|
123
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type ScopeAncestor } from '../../../utils/cel-context.js';
|
|
2
|
+
export type PickEntry = {
|
|
3
|
+
id: string;
|
|
4
|
+
group: 'var' | 'scope';
|
|
5
|
+
insert: string;
|
|
6
|
+
display: string;
|
|
7
|
+
label: string;
|
|
8
|
+
type: string;
|
|
9
|
+
description?: string;
|
|
10
|
+
};
|
|
11
|
+
export type PickVarMeta = {
|
|
12
|
+
type: string;
|
|
13
|
+
label: string;
|
|
14
|
+
description?: string;
|
|
15
|
+
};
|
|
16
|
+
export declare function buildVarEntries(celContext: Record<string, PickVarMeta>, extraVars?: Record<string, PickVarMeta>): PickEntry[];
|
|
17
|
+
export declare function buildScopeEntries(ancestry: ReadonlyArray<ScopeAncestor>): PickEntry[];
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import { SCOPE_ADDRESS_VAR } from "../../../utils/cel-context.js";
|
|
2
|
+
import { scopeOrigin } from "./scope-refs.js";
|
|
3
|
+
export function buildVarEntries(celContext, extraVars) {
|
|
4
|
+
const out = [];
|
|
5
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6
|
+
for (const [name, meta] of Object.entries(celContext)) {
|
|
7
|
+
if (name === SCOPE_ADDRESS_VAR) continue;
|
|
8
|
+
seen.add(name);
|
|
9
|
+
out.push({ id: name, group: "var", insert: name, display: name, label: meta.label, type: meta.type, description: meta.description });
|
|
10
|
+
}
|
|
11
|
+
for (const [name, meta] of Object.entries(extraVars ?? {})) {
|
|
12
|
+
if (seen.has(name) || name === SCOPE_ADDRESS_VAR) continue;
|
|
13
|
+
out.push({ id: name, group: "var", insert: name, display: name, label: meta.label, type: meta.type, description: meta.description });
|
|
14
|
+
}
|
|
15
|
+
return out;
|
|
16
|
+
}
|
|
17
|
+
export function buildScopeEntries(ancestry) {
|
|
18
|
+
const out = [];
|
|
19
|
+
for (const ancestor of ancestry) {
|
|
20
|
+
const origin = scopeOrigin(ancestor);
|
|
21
|
+
for (const member of ancestor.members) {
|
|
22
|
+
out.push({
|
|
23
|
+
id: `scope:${ancestor.id}:${member.key}`,
|
|
24
|
+
group: "scope",
|
|
25
|
+
insert: `${SCOPE_ADDRESS_VAR}[${JSON.stringify(ancestor.id)}].${member.key}`,
|
|
26
|
+
display: `${origin} \u203A ${member.label}`,
|
|
27
|
+
label: origin,
|
|
28
|
+
type: member.type,
|
|
29
|
+
description: member.description
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return out;
|
|
34
|
+
}
|