@shwfed/config 2.5.3 → 2.6.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 +8 -0
- package/dist/module.json +1 -1
- package/dist/module.mjs +6 -1
- package/dist/preview/assets/{config-U359oLg8.js → config-BF-HYbrD.js} +1 -1
- package/dist/preview/assets/{config-C5TWIUX-.js → config-CevoqLCe.js} +1 -1
- package/dist/preview/assets/{config-ekMG8PO0.js → config-Co--BPbb.js} +1 -1
- package/dist/preview/assets/{config-CH28q4_H.js → config-DMOAQ9zl.js} +1 -1
- package/dist/preview/assets/{config-DN6k6pjm.js → config-Du7AdGIY.js} +1 -1
- package/dist/preview/assets/{config-CtGduGcR.js → config-LdNKbqCx.js} +1 -1
- package/dist/preview/assets/{config-D9tBv8LD.js → config-RACtdV3v.js} +1 -1
- package/dist/preview/assets/{config-BVjCjkAL.js → config-VChcvg_y.js} +1 -1
- package/dist/preview/assets/{config-DxB8qwAu.js → config-oBOXGUjR.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-Ma8i-2ox.js} +1 -1
- package/dist/preview/assets/index-C-nzF9-u.js +1 -0
- package/dist/preview/assets/index-CHEiFlnE.css +1 -0
- package/dist/preview/assets/index-rxUrWg1Y.js +680 -0
- package/dist/preview/assets/{runtime-CQly-3c3.js → runtime-BNzaUtd-.js} +1 -1
- package/dist/preview/assets/{runtime-BKQvzSax.js → runtime-CAj4SjAs.js} +1 -1
- package/dist/preview/assets/{runtime-BafXFP0s.js → runtime-CE_42oyr.js} +1 -1
- package/dist/preview/assets/{runtime-DJgDXKfE.js → runtime-CLMz0SYI.js} +1 -1
- package/dist/preview/assets/{runtime-x8IdC454.js → runtime-COCfVWBL.js} +1 -1
- package/dist/preview/assets/{runtime-CAzVJ-if.js → runtime-GfHY6wxJ.js} +1 -1
- package/dist/preview/assets/{runtime-BAQ6ezPo.js → runtime-Y00C-S73.js} +1 -1
- package/dist/preview/assets/{runtime-Dhd51Wyr.js → runtime-llw5ZA1Z.js} +1 -1
- package/dist/preview/assets/{runtime-27bDIkKv.js → runtime-wAJ77Q3a.js} +1 -1
- package/dist/preview/index.html +2 -2
- 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/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 +6 -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
|
@@ -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
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type ScopeAncestor } from '../../../utils/cel-context.js';
|
|
2
|
+
export declare function scopeOrigin(ancestor: Pick<ScopeAncestor, 'name' | 'typeName'>): string;
|
|
3
|
+
export type ScopeRef = {
|
|
4
|
+
from: number;
|
|
5
|
+
to: number;
|
|
6
|
+
id: string;
|
|
7
|
+
member: string;
|
|
8
|
+
};
|
|
9
|
+
export declare function scanScopeRefs(text: string): ScopeRef[];
|
|
10
|
+
/** A member of an addressable scope, resolved for chip display. */
|
|
11
|
+
export type ScopeMemberInfo = {
|
|
12
|
+
label: string;
|
|
13
|
+
type: string;
|
|
14
|
+
};
|
|
15
|
+
/** Display data for one addressable ancestor, keyed by member name. */
|
|
16
|
+
export type ScopeInfo = {
|
|
17
|
+
origin: string;
|
|
18
|
+
members: Map<string, ScopeMemberInfo>;
|
|
19
|
+
};
|
|
20
|
+
export declare function buildScopeLookup(ancestry: ReadonlyArray<ScopeAncestor>): Map<string, ScopeInfo>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { SCOPE_ADDRESS_VAR } from "../../../utils/cel-context.js";
|
|
2
|
+
export function scopeOrigin(ancestor) {
|
|
3
|
+
return ancestor.name ? `${ancestor.typeName}\u300C${ancestor.name}\u300D` : ancestor.typeName;
|
|
4
|
+
}
|
|
5
|
+
const SCOPE_REF_RE = new RegExp(
|
|
6
|
+
`${SCOPE_ADDRESS_VAR}\\[("(?:[^"\\\\]|\\\\.)*")\\]\\.([A-Za-z_$][\\w$]*)`,
|
|
7
|
+
"g"
|
|
8
|
+
);
|
|
9
|
+
export function scanScopeRefs(text) {
|
|
10
|
+
const out = [];
|
|
11
|
+
SCOPE_REF_RE.lastIndex = 0;
|
|
12
|
+
let match;
|
|
13
|
+
while ((match = SCOPE_REF_RE.exec(text)) !== null) {
|
|
14
|
+
let id;
|
|
15
|
+
try {
|
|
16
|
+
id = JSON.parse(match[1]);
|
|
17
|
+
} catch {
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
out.push({
|
|
21
|
+
from: match.index,
|
|
22
|
+
to: match.index + match[0].length,
|
|
23
|
+
id,
|
|
24
|
+
member: match[2]
|
|
25
|
+
});
|
|
26
|
+
}
|
|
27
|
+
return out;
|
|
28
|
+
}
|
|
29
|
+
export function buildScopeLookup(ancestry) {
|
|
30
|
+
const lookup = /* @__PURE__ */ new Map();
|
|
31
|
+
for (const ancestor of ancestry) {
|
|
32
|
+
const members = /* @__PURE__ */ new Map();
|
|
33
|
+
for (const member of ancestor.members) {
|
|
34
|
+
members.set(member.key, { label: member.label, type: member.type });
|
|
35
|
+
}
|
|
36
|
+
lookup.set(ancestor.id, { origin: scopeOrigin(ancestor), members });
|
|
37
|
+
}
|
|
38
|
+
return lookup;
|
|
39
|
+
}
|
|
@@ -12,6 +12,12 @@ function formatExpectedType(expected) {
|
|
|
12
12
|
if (Array.isArray(expected)) return expected.join(" | ");
|
|
13
13
|
return "(\u81EA\u5B9A\u4E49)";
|
|
14
14
|
}
|
|
15
|
+
function registerScopeAddressVar(env) {
|
|
16
|
+
env.registerVariable("__scopes__", "map<string, dyn>", {
|
|
17
|
+
label: "\u8DE8\u5C42\u4F5C\u7528\u57DF",
|
|
18
|
+
description: "\u6309 UUID \u5BFB\u5740\u88AB\u906E\u853D\u7684\u7956\u5148\u4F5C\u7528\u57DF"
|
|
19
|
+
});
|
|
20
|
+
}
|
|
15
21
|
function buildDescription(baseline, env, resultType) {
|
|
16
22
|
const defs = env.getDefinitions();
|
|
17
23
|
const baselineVarNames = new Set(baseline.variables.map((v) => v.name));
|
|
@@ -39,6 +45,7 @@ export function Expression(options) {
|
|
|
39
45
|
const env = new Environment({
|
|
40
46
|
unlistedVariablesAreDyn: options.unlistedVariablesAreDyn ?? false
|
|
41
47
|
});
|
|
48
|
+
registerScopeAddressVar(env);
|
|
42
49
|
const baseline = env.getDefinitions();
|
|
43
50
|
options.configure(env);
|
|
44
51
|
const description = buildDescription(baseline, env, options.resultType);
|
|
@@ -69,6 +76,7 @@ export function Expression(options) {
|
|
|
69
76
|
const INTERPOLATION_RE = /\{\{(.*?)\}\}/gs;
|
|
70
77
|
export function Markdown(options) {
|
|
71
78
|
const env = new Environment({ unlistedVariablesAreDyn: false });
|
|
79
|
+
registerScopeAddressVar(env);
|
|
72
80
|
const baseline = env.getDefinitions();
|
|
73
81
|
options.configure(env);
|
|
74
82
|
const description = `Markdown with CEL interpolation via {{ expression }}. ${buildDescription(baseline, env).slice("CEL expression. ".length)}`;
|
|
@@ -100,6 +108,7 @@ export function Markdown(options) {
|
|
|
100
108
|
}
|
|
101
109
|
export function LocaleMarkdown(options) {
|
|
102
110
|
const env = new Environment({ unlistedVariablesAreDyn: false });
|
|
111
|
+
registerScopeAddressVar(env);
|
|
103
112
|
const baseline = env.getDefinitions();
|
|
104
113
|
options.configure(env);
|
|
105
114
|
const description = `Locale with Markdown CEL interpolation via {{ expression }}. ${buildDescription(baseline, env).slice("CEL expression. ".length)}`;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { Ref } from 'vue';
|
|
1
2
|
export type CELVar = {
|
|
2
3
|
type: string;
|
|
3
4
|
label: string;
|
|
@@ -5,6 +6,41 @@ export type CELVar = {
|
|
|
5
6
|
value: unknown;
|
|
6
7
|
};
|
|
7
8
|
export type CELContext = Record<string, CELVar>;
|
|
9
|
+
export declare const SCOPE_ADDRESS_VAR = "__scopes__";
|
|
10
|
+
export type ScopeAccessor = Record<string, () => unknown>;
|
|
8
11
|
export declare function provideCELContext(context: CELContext): void;
|
|
9
12
|
export declare function injectCELContext(): CELContext;
|
|
13
|
+
export declare function provideScopeAddress(uuid: string, accessor: ScopeAccessor): void;
|
|
14
|
+
/** One addressable member of an ancestor scope, e.g. `row` / `index`. */
|
|
15
|
+
export type ScopeAncestorMember = Readonly<{
|
|
16
|
+
/** Member name appended after the address — `__scopes__["id"].<key>`. */
|
|
17
|
+
key: string;
|
|
18
|
+
label: string;
|
|
19
|
+
/** CEL type shown as the picker badge. */
|
|
20
|
+
type: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
}>;
|
|
23
|
+
/** A scope-exposing ancestor instance, as seen by an expression-editor picker. */
|
|
24
|
+
export type ScopeAncestor = Readonly<{
|
|
25
|
+
/** Instance id keyed into `__scopes__["<id>"]`. */
|
|
26
|
+
id: string;
|
|
27
|
+
/** Instance display name (a table's 内部名称); blank → show the type name alone. */
|
|
28
|
+
name?: string;
|
|
29
|
+
/** Component type display name (from type metadata). */
|
|
30
|
+
typeName: string;
|
|
31
|
+
/** Component type icon (from type metadata). */
|
|
32
|
+
typeIcon?: string;
|
|
33
|
+
members: ReadonlyArray<ScopeAncestorMember>;
|
|
34
|
+
}>;
|
|
35
|
+
/**
|
|
36
|
+
* Contribute one scope-exposing ancestor frame. Descendant editors see it
|
|
37
|
+
* prepended (nearest first) to the inherited chain. A `null` value contributes
|
|
38
|
+
* nothing — for an editor whose current target may or may not own an `id`.
|
|
39
|
+
*/
|
|
40
|
+
export declare function provideScopeAncestor(ancestor: Ref<ScopeAncestor | null>): void;
|
|
41
|
+
/**
|
|
42
|
+
* The scope-exposing ancestors enclosing the current editing position, nearest
|
|
43
|
+
* first. Empty when nothing up the config tree exposes an addressable scope.
|
|
44
|
+
*/
|
|
45
|
+
export declare function useScopeAncestry(): Ref<ReadonlyArray<ScopeAncestor>>;
|
|
10
46
|
export declare function celBindings(context: CELContext): Record<string, unknown>;
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
import { computed, inject, provide, shallowRef } from "vue";
|
|
1
2
|
import { injectLocal, provideLocal } from "@vueuse/core";
|
|
3
|
+
export const SCOPE_ADDRESS_VAR = "__scopes__";
|
|
2
4
|
const CEL_CONTEXT_KEY = Symbol("cel-context");
|
|
3
5
|
export function provideCELContext(context) {
|
|
4
6
|
const parent = injectLocal(CEL_CONTEXT_KEY, {});
|
|
@@ -7,6 +9,43 @@ export function provideCELContext(context) {
|
|
|
7
9
|
export function injectCELContext() {
|
|
8
10
|
return injectLocal(CEL_CONTEXT_KEY, {});
|
|
9
11
|
}
|
|
12
|
+
function resolveScopeAccessor(accessor) {
|
|
13
|
+
const resolved = {};
|
|
14
|
+
for (const [member, thunk] of Object.entries(accessor)) resolved[member] = thunk();
|
|
15
|
+
return resolved;
|
|
16
|
+
}
|
|
17
|
+
export function provideScopeAddress(uuid, accessor) {
|
|
18
|
+
const parentScopes = injectCELContext()[SCOPE_ADDRESS_VAR];
|
|
19
|
+
provideCELContext({
|
|
20
|
+
[SCOPE_ADDRESS_VAR]: {
|
|
21
|
+
type: "map<string, dyn>",
|
|
22
|
+
label: "\u8DE8\u5C42\u4F5C\u7528\u57DF",
|
|
23
|
+
description: '\u6309 UUID \u5BFB\u5740\u88AB\u906E\u853D\u7684\u7956\u5148\u4F5C\u7528\u57DF\uFF08\u5982 `__scopes__["<uuid>"].row`\uFF09\uFF1B\u4EC5\u80FD\u547D\u4E2D\u8BCD\u6CD5\u4E0A\u5305\u4F4F\u5F53\u524D\u4F4D\u7F6E\u7684\u4F5C\u7528\u57DF\u3002',
|
|
24
|
+
// Resolved fresh each binding pass: invoke the parent thunk for live
|
|
25
|
+
// ancestor rows, then overlay this uuid. Picker-stored expressions index
|
|
26
|
+
// this by uuid; a uuid not on the ancestor chain is simply absent, so
|
|
27
|
+
// bracket access throws a located `No such key` at the offending uuid.
|
|
28
|
+
value: () => {
|
|
29
|
+
const base = parentScopes ? typeof parentScopes.value === "function" ? parentScopes.value() : parentScopes.value : {};
|
|
30
|
+
return { ...base, [uuid]: resolveScopeAccessor(accessor) };
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
const SCOPE_ANCESTRY_KEY = Symbol("cel-scope-ancestry");
|
|
36
|
+
export function provideScopeAncestor(ancestor) {
|
|
37
|
+
const parent = inject(SCOPE_ANCESTRY_KEY, void 0);
|
|
38
|
+
provide(
|
|
39
|
+
SCOPE_ANCESTRY_KEY,
|
|
40
|
+
computed(() => {
|
|
41
|
+
const chain = parent?.value ?? [];
|
|
42
|
+
return ancestor.value ? [ancestor.value, ...chain] : chain;
|
|
43
|
+
})
|
|
44
|
+
);
|
|
45
|
+
}
|
|
46
|
+
export function useScopeAncestry() {
|
|
47
|
+
return inject(SCOPE_ANCESTRY_KEY, void 0) ?? shallowRef([]);
|
|
48
|
+
}
|
|
10
49
|
export function celBindings(context) {
|
|
11
50
|
const out = {};
|
|
12
51
|
for (const [name, entry] of Object.entries(context)) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shwfed/config",
|
|
3
|
-
"version": "2.
|
|
3
|
+
"version": "2.6.0",
|
|
4
4
|
"description": "Configurable UI for SHWFED",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"publishConfig": {
|
|
@@ -44,10 +44,15 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@atlaskit/pragmatic-drag-and-drop": "^1.8.1",
|
|
46
46
|
"@atlaskit/pragmatic-drag-and-drop-hitbox": "^1.1.0",
|
|
47
|
+
"@codemirror/commands": "^6.10.3",
|
|
48
|
+
"@codemirror/language": "^6.12.3",
|
|
49
|
+
"@codemirror/state": "^6.6.0",
|
|
50
|
+
"@codemirror/view": "^6.43.0",
|
|
47
51
|
"@date-fns/tz": "^1.4.1",
|
|
48
52
|
"@iconify/vue": "^5.0.1",
|
|
49
53
|
"@internationalized/date": "^3.12.1",
|
|
50
54
|
"@intlify/unplugin-vue-i18n": "^11.2.3",
|
|
55
|
+
"@lezer/highlight": "^1.2.3",
|
|
51
56
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
52
57
|
"@nuxt/kit": "^4.4.5",
|
|
53
58
|
"@tailwindcss/typography": "^0.5.19",
|