@tmagic/editor 1.8.0-beta.10 → 1.8.0-beta.12
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/es/Editor.vue_vue_type_script_setup_true_lang.js +7 -4
- package/dist/es/components/CodeBlockEditor.vue_vue_type_script_setup_true_lang.js +4 -0
- package/dist/es/components/CodeParams.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/es/components/CompareForm.vue_vue_type_script_setup_true_lang.js +5 -2
- package/dist/es/components/FloatingBox.vue_vue_type_script_setup_true_lang.js +60 -14
- package/dist/es/components/ScrollBar.js +0 -1
- package/dist/es/editorProps.js +6 -1
- package/dist/es/fields/CodeSelect.vue_vue_type_script_setup_true_lang.js +15 -3
- package/dist/es/fields/CondOpSelect.vue_vue_type_script_setup_true_lang.js +2 -17
- package/dist/es/fields/DataSourceFieldSelect/FieldSelect.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/es/fields/DataSourceFields.vue_vue_type_script_setup_true_lang.js +7 -0
- package/dist/es/fields/DataSourceInput.vue_vue_type_script_setup_true_lang.js +5 -17
- package/dist/es/fields/DataSourceMocks.vue_vue_type_script_setup_true_lang.js +4 -0
- package/dist/es/fields/DisplayConds.vue_vue_type_script_setup_true_lang.js +29 -3
- package/dist/es/fields/EventSelect.vue_vue_type_script_setup_true_lang.js +50 -88
- package/dist/es/fields/StyleSetter/Index.vue_vue_type_script_setup_true_lang.js +2 -5
- package/dist/es/fields/StyleSetter/pro/Background.vue_vue_type_script_setup_true_lang.js +48 -23
- package/dist/es/fields/StyleSetter/pro/Border.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/es/fields/StyleSetter/pro/Font.vue_vue_type_script_setup_true_lang.js +28 -22
- package/dist/es/fields/StyleSetter/pro/Layout.vue_vue_type_script_setup_true_lang.js +28 -22
- package/dist/es/fields/StyleSetter/pro/Position.vue_vue_type_script_setup_true_lang.js +28 -22
- package/dist/es/fields/StyleSetter/pro/Transform.vue_vue_type_script_setup_true_lang.js +6 -3
- package/dist/es/fields/UISelect.js +0 -1
- package/dist/es/index.js +9 -6
- package/dist/es/layouts/CodeEditor.vue_vue_type_script_setup_true_lang.js +21 -6
- package/dist/es/layouts/Framework.vue_vue_type_script_setup_true_lang.js +9 -6
- package/dist/es/layouts/history-list/HistoryDiffDialog.vue_vue_type_script_setup_true_lang.js +14 -4
- package/dist/es/layouts/history-list/composables.js +1 -1
- package/dist/es/layouts/history-list/useHistoryRevert.js +17 -6
- package/dist/es/layouts/props-panel/FormPanel.vue_vue_type_script_setup_true_lang.js +44 -5
- package/dist/es/layouts/props-panel/PropsPanel.vue_vue_type_script_setup_true_lang.js +15 -8
- package/dist/es/layouts/props-panel/use-style-panel.js +3 -2
- package/dist/es/layouts/sidebar/Sidebar.vue_vue_type_script_setup_true_lang.js +15 -31
- package/dist/es/layouts/sidebar/code-block/CodeBlockListPanel.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/sidebar/code-block/useContentMenu.js +18 -3
- package/dist/es/layouts/sidebar/data-source/DataSourceConfigPanel.vue_vue_type_script_setup_true_lang.js +4 -0
- package/dist/es/layouts/sidebar/data-source/DataSourceListPanel.vue_vue_type_script_setup_true_lang.js +2 -2
- package/dist/es/layouts/sidebar/data-source/useContentMenu.js +18 -3
- package/dist/es/layouts/sidebar/layer/LayerNodeContent.js +5 -0
- package/dist/es/layouts/sidebar/layer/LayerNodeContent.vue_vue_type_script_setup_true_lang.js +46 -0
- package/dist/es/layouts/sidebar/layer/LayerPanel.vue_vue_type_script_setup_true_lang.js +2 -1
- package/dist/es/layouts/workspace/viewer/NodeListMenu.vue_vue_type_script_setup_true_lang.js +8 -2
- package/dist/es/plugin.js +3 -1
- package/dist/es/services/editor.js +104 -5
- package/dist/es/services/props.js +2 -1
- package/dist/es/services/storage.js +1 -1
- package/dist/es/services/ui.js +3 -0
- package/dist/es/style.css +104 -55
- package/dist/es/utils/data-source/index.js +30 -11
- package/dist/es/utils/event.js +123 -0
- package/dist/es/utils/monaco-editor.js +22 -6
- package/dist/es/utils/props.js +94 -8
- package/dist/es/utils/type-match-rules.js +360 -0
- package/dist/style.css +104 -55
- package/dist/tmagic-editor.umd.cjs +16923 -15771
- package/package.json +8 -8
- package/src/Editor.vue +3 -1
- package/src/components/CodeBlockEditor.vue +3 -0
- package/src/components/CompareForm.vue +7 -0
- package/src/components/FloatingBox.vue +77 -8
- package/src/components/ScrollBar.vue +0 -67
- package/src/editorProps.ts +13 -0
- package/src/fields/CodeSelect.vue +4 -1
- package/src/fields/CondOpSelect.vue +2 -24
- package/src/fields/DataSourceFields.vue +5 -0
- package/src/fields/DataSourceInput.vue +7 -25
- package/src/fields/DataSourceMocks.vue +3 -0
- package/src/fields/DisplayConds.vue +14 -0
- package/src/fields/EventSelect.vue +84 -129
- package/src/fields/StyleSetter/Index.vue +2 -8
- package/src/fields/StyleSetter/pro/Background.vue +94 -55
- package/src/fields/StyleSetter/pro/Border.vue +9 -11
- package/src/fields/StyleSetter/pro/Font.vue +66 -64
- package/src/fields/StyleSetter/pro/Layout.vue +140 -138
- package/src/fields/StyleSetter/pro/Position.vue +69 -67
- package/src/fields/StyleSetter/pro/Transform.vue +23 -25
- package/src/fields/UISelect.vue +0 -12
- package/src/index.ts +1 -0
- package/src/layouts/CodeEditor.vue +32 -6
- package/src/layouts/Framework.vue +7 -6
- package/src/layouts/history-list/HistoryDiffDialog.vue +23 -5
- package/src/layouts/history-list/useHistoryRevert.ts +25 -5
- package/src/layouts/props-panel/FormPanel.vue +66 -5
- package/src/layouts/props-panel/PropsPanel.vue +20 -6
- package/src/layouts/props-panel/use-style-panel.ts +4 -3
- package/src/layouts/sidebar/Sidebar.vue +2 -0
- package/src/layouts/sidebar/code-block/CodeBlockListPanel.vue +4 -1
- package/src/layouts/sidebar/code-block/useContentMenu.ts +13 -1
- package/src/layouts/sidebar/data-source/DataSourceConfigPanel.vue +3 -0
- package/src/layouts/sidebar/data-source/DataSourceListPanel.vue +2 -2
- package/src/layouts/sidebar/data-source/useContentMenu.ts +13 -1
- package/src/layouts/sidebar/layer/LayerNodeContent.vue +57 -0
- package/src/layouts/sidebar/layer/LayerPanel.vue +4 -1
- package/src/layouts/workspace/viewer/NodeListMenu.vue +4 -1
- package/src/plugin.ts +3 -1
- package/src/services/editor.ts +168 -3
- package/src/services/ui.ts +6 -0
- package/src/theme/event.scss +8 -0
- package/src/theme/floating-box.scss +9 -1
- package/src/theme/layer-node-content.scss +14 -0
- package/src/theme/scroll-bar.scss +64 -0
- package/src/theme/theme.scss +3 -0
- package/src/theme/ui-select.scss +9 -0
- package/src/type.ts +72 -2
- package/src/utils/data-source/index.ts +30 -12
- package/src/utils/event.ts +224 -0
- package/src/utils/index.ts +2 -0
- package/src/utils/monaco-editor.ts +27 -0
- package/src/utils/props.ts +160 -2
- package/src/utils/type-match-rules.ts +678 -0
- package/types/index.d.ts +391 -85
|
@@ -0,0 +1,678 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Tencent is pleased to support the open source community by making TMagicEditor available.
|
|
3
|
+
*
|
|
4
|
+
* Copyright (C) 2025 Tencent. All rights reserved.
|
|
5
|
+
*
|
|
6
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
7
|
+
* you may not use this file except in compliance with the License.
|
|
8
|
+
* You may obtain a copy of the License at
|
|
9
|
+
*
|
|
10
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
11
|
+
*
|
|
12
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
13
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
14
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
15
|
+
* See the License for the specific language governing permissions and
|
|
16
|
+
* limitations under the License.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { DataSourceFieldType, DataSourceSchema, Id } from '@tmagic/core';
|
|
20
|
+
import { NodeType } from '@tmagic/core';
|
|
21
|
+
import { appendValidateSuggestion } from '@tmagic/design';
|
|
22
|
+
import type { TypeMatchValidateContext, TypeMatchValidator } from '@tmagic/form';
|
|
23
|
+
import {
|
|
24
|
+
DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX,
|
|
25
|
+
DATA_SOURCE_SET_DATA_METHOD_NAME,
|
|
26
|
+
dataSourceTemplateRegExp,
|
|
27
|
+
getKeysArray,
|
|
28
|
+
removeDataSourceFieldPrefix,
|
|
29
|
+
} from '@tmagic/utils';
|
|
30
|
+
|
|
31
|
+
import codeBlockService from '@editor/services/codeBlock';
|
|
32
|
+
import dataSourceService from '@editor/services/dataSource';
|
|
33
|
+
import editorService from '@editor/services/editor';
|
|
34
|
+
import { getFieldType, resolveFieldByPath } from '@editor/utils/data-source';
|
|
35
|
+
import {
|
|
36
|
+
arrayOptions,
|
|
37
|
+
booleanOptions,
|
|
38
|
+
eqOptions,
|
|
39
|
+
getCondOpOptionsByFieldType,
|
|
40
|
+
numberOptions,
|
|
41
|
+
} from '@editor/utils/props';
|
|
42
|
+
|
|
43
|
+
/**
|
|
44
|
+
* 将值格式化为可读的参考示例字符串。
|
|
45
|
+
*/
|
|
46
|
+
const stringifyExampleValue = (value: any): string => {
|
|
47
|
+
if (typeof value === 'string') return `"${value}"`;
|
|
48
|
+
if (value === null || value === undefined) return String(value);
|
|
49
|
+
if (typeof value === 'object') {
|
|
50
|
+
try {
|
|
51
|
+
return JSON.stringify(value);
|
|
52
|
+
} catch {
|
|
53
|
+
return String(value);
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return String(value);
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// 参考建议中最多展示的可选值个数,超出以「等」省略。
|
|
60
|
+
const MAX_SUGGESTION_OPTIONS = 5;
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* 生成「请使用以下某一个值:xxx;xxx」形式的参考建议;无可选值时返回空字符串(不追加建议)。
|
|
64
|
+
*/
|
|
65
|
+
const listSuggestion = (values: any[]): string => {
|
|
66
|
+
const list = values.filter((item) => typeof item !== 'undefined' && item !== null && item !== '');
|
|
67
|
+
if (!list.length) return '';
|
|
68
|
+
const shown = list.slice(0, MAX_SUGGESTION_OPTIONS).map(stringifyExampleValue);
|
|
69
|
+
const suffix = list.length > MAX_SUGGESTION_OPTIONS ? ' 等' : '';
|
|
70
|
+
return `请使用以下某一个值:${shown.join(';')}${suffix}`;
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* 列出当前可用数据源 id 的参考建议。
|
|
75
|
+
*/
|
|
76
|
+
const dataSourceIdSuggestion = (): string => listSuggestion(getDataSources().map((ds) => `${ds.id}`));
|
|
77
|
+
|
|
78
|
+
// 各类型 / 结构的参考示例值
|
|
79
|
+
const SUGGESTION_STRING = '请参考以下示例值:"文本内容"';
|
|
80
|
+
const SUGGESTION_STRING_OR_NUMBER = '请参考以下示例值:"文本内容" 或 123';
|
|
81
|
+
const SUGGESTION_OBJECT = '请参考以下示例值:{ "key": "value" }';
|
|
82
|
+
const SUGGESTION_ARRAY = '请参考以下示例值:[]';
|
|
83
|
+
const SUGGESTION_STRING_ARRAY = '请参考以下示例值:["字段1", "字段2"]';
|
|
84
|
+
const SUGGESTION_METHOD_TUPLE = '请参考以下示例值:["数据源ID", "方法名"]';
|
|
85
|
+
const SUGGESTION_DS_BINDING = '请参考以下示例值:"${数据源ID.字段名}"';
|
|
86
|
+
const SUGGESTION_DS_BIND_OBJECT = '请参考以下示例值:{ "isBindDataSource": true, "dataSourceId": "数据源ID" }';
|
|
87
|
+
const SUGGESTION_UI_ID = '请参考以下示例值:画布中已存在组件的 id';
|
|
88
|
+
const SUGGESTION_FIELD_ITEM = '请参考以下示例值:{ "name": "字段名", "type": "string" }';
|
|
89
|
+
const SUGGESTION_CODE_SELECT = '请参考以下示例值:{ "hookData": [{ "codeId": "代码块ID", "params": {} }] }';
|
|
90
|
+
const SUGGESTION_HOOK_ITEM = '请参考以下示例值:{ "codeId": "代码块ID", "params": {} }';
|
|
91
|
+
const SUGGESTION_MOCK_ITEM =
|
|
92
|
+
'请参考以下示例值:{ "title": "mock 名称", "enable": true, "useInEditor": false, "data": {} }';
|
|
93
|
+
const SUGGESTION_METHOD_ITEM = '请参考以下示例值:{ "name": "方法名", "content": "() => {}" }';
|
|
94
|
+
const SUGGESTION_EVENT_ITEM = '请参考以下示例值:{ "name": "事件名", "actions": [] }';
|
|
95
|
+
const SUGGESTION_DISPLAY_COND = '请参考以下示例值:[{ "cond": [{ "field": ["数据源ID", "字段名"], "op": "==" }] }]';
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* 返回最终错误文案。
|
|
99
|
+
*
|
|
100
|
+
* - 传入了自定义 `message` 时,直接使用自定义文案(不追加建议);
|
|
101
|
+
* - 否则使用默认文案 `fallback`,并在其后拼接「参考建议」。
|
|
102
|
+
* 参考建议给出一个可参考的示例值(如可选项列表、示例数据),仅用于错误汇总展示;
|
|
103
|
+
* form-item 行内错误不展示建议(由 @tmagic/design FormItem 在渲染时截断建议)。
|
|
104
|
+
* 主文案与建议的拼接/截断统一复用 @tmagic/design 的 `appendValidateSuggestion`。
|
|
105
|
+
*/
|
|
106
|
+
const defaultMessage = (message: string | undefined, fallback: string, suggestion?: string) => {
|
|
107
|
+
if (message) return message;
|
|
108
|
+
return appendValidateSuggestion(fallback, suggestion);
|
|
109
|
+
};
|
|
110
|
+
|
|
111
|
+
const isPlainObject = (value: any): value is Record<string, any> =>
|
|
112
|
+
Object.prototype.toString.call(value) === '[object Object]';
|
|
113
|
+
|
|
114
|
+
const isId = (value: any): value is Id => typeof value === 'string' || typeof value === 'number';
|
|
115
|
+
|
|
116
|
+
const DATA_SOURCE_FIELD_TYPES = new Set<DataSourceFieldType>([
|
|
117
|
+
'null',
|
|
118
|
+
'boolean',
|
|
119
|
+
'object',
|
|
120
|
+
'array',
|
|
121
|
+
'number',
|
|
122
|
+
'string',
|
|
123
|
+
'any',
|
|
124
|
+
]);
|
|
125
|
+
|
|
126
|
+
export const ALL_COND_OPS = new Set<string>([
|
|
127
|
+
...arrayOptions.map((item) => item.value),
|
|
128
|
+
...eqOptions.map((item) => item.value),
|
|
129
|
+
...numberOptions.map((item) => item.value),
|
|
130
|
+
...booleanOptions.map((item) => item.value),
|
|
131
|
+
]);
|
|
132
|
+
|
|
133
|
+
const getCondOpsByFieldType = (type: string): Set<string> =>
|
|
134
|
+
new Set(getCondOpOptionsByFieldType(type).map((item) => item.value));
|
|
135
|
+
|
|
136
|
+
const getDataSources = (): DataSourceSchema[] => dataSourceService.get('dataSources') || [];
|
|
137
|
+
|
|
138
|
+
const findDataSource = (id: string): DataSourceSchema | undefined =>
|
|
139
|
+
getDataSources().find((ds) => `${ds.id}` === `${id}`);
|
|
140
|
+
|
|
141
|
+
const getMethodNamesForDataSource = (ds: DataSourceSchema): Set<string> => {
|
|
142
|
+
const names = new Set<string>([DATA_SOURCE_SET_DATA_METHOD_NAME]);
|
|
143
|
+
(dataSourceService.getFormMethod(ds.type) || []).forEach((item) => {
|
|
144
|
+
if (item?.value) names.add(item.value);
|
|
145
|
+
});
|
|
146
|
+
(ds.methods || []).forEach((method) => {
|
|
147
|
+
if (method?.name) names.add(method.name);
|
|
148
|
+
});
|
|
149
|
+
return names;
|
|
150
|
+
};
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* 递归收集画布中真实存在的组件 id。
|
|
154
|
+
*/
|
|
155
|
+
const collectNodeIds = (limit = MAX_SUGGESTION_OPTIONS): Id[] => {
|
|
156
|
+
const ids: Id[] = [];
|
|
157
|
+
const walk = (nodes?: any[]): boolean => {
|
|
158
|
+
for (const node of nodes || []) {
|
|
159
|
+
if (typeof node?.id !== 'undefined') {
|
|
160
|
+
ids.push(node.id);
|
|
161
|
+
if (ids.length >= limit) return true;
|
|
162
|
+
}
|
|
163
|
+
if (Array.isArray(node?.items) && walk(node.items)) return true;
|
|
164
|
+
}
|
|
165
|
+
return false;
|
|
166
|
+
};
|
|
167
|
+
walk(editorService.get('root')?.items);
|
|
168
|
+
return ids;
|
|
169
|
+
};
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* 取数据源的第一个字段名,用于拼接真实的字段路径示例。
|
|
173
|
+
*/
|
|
174
|
+
const firstDataSourceFieldName = (ds?: DataSourceSchema): string | undefined =>
|
|
175
|
+
(ds?.fields || []).find((item) => typeof item?.name === 'string')?.name;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* 列出画布中真实存在的组件 id 作为参考建议;无组件时回退到通用示例。
|
|
179
|
+
*/
|
|
180
|
+
const uiIdSuggestion = (): string => listSuggestion(collectNodeIds().map((id) => `${id}`)) || SUGGESTION_UI_ID;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* 用真实数据源 id、字段名拼接数据源绑定表达式示例;无数据源时回退到通用示例。
|
|
184
|
+
*/
|
|
185
|
+
const dataSourceBindingSuggestion = (): string => {
|
|
186
|
+
const ds = getDataSources()[0];
|
|
187
|
+
if (!ds) return SUGGESTION_DS_BINDING;
|
|
188
|
+
const field = firstDataSourceFieldName(ds);
|
|
189
|
+
const path = field ? `${ds.id}.${field}` : `${ds.id}`;
|
|
190
|
+
return `请参考以下示例值:"\${${path}}"`;
|
|
191
|
+
};
|
|
192
|
+
|
|
193
|
+
/**
|
|
194
|
+
* 用真实数据源 id 拼接数据源绑定对象示例;无数据源时回退到通用示例。
|
|
195
|
+
*/
|
|
196
|
+
const dataSourceBindObjectSuggestion = (dataSources: DataSourceSchema[] = getDataSources()): string => {
|
|
197
|
+
const ds = dataSources[0];
|
|
198
|
+
if (!ds) return SUGGESTION_DS_BIND_OBJECT;
|
|
199
|
+
return `请参考以下示例值:${stringifyExampleValue({ isBindDataSource: true, dataSourceId: `${ds.id}` })}`;
|
|
200
|
+
};
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* 用真实数据源 id、字段名拼接字段路径数组示例;无数据源时回退到通用示例。
|
|
204
|
+
*/
|
|
205
|
+
const dataSourceFieldPathSuggestion = (): string => {
|
|
206
|
+
const ds = getDataSources()[0];
|
|
207
|
+
if (!ds) return SUGGESTION_STRING_ARRAY;
|
|
208
|
+
const field = firstDataSourceFieldName(ds);
|
|
209
|
+
return `请参考以下示例值:${stringifyExampleValue(field ? [`${ds.id}`, field] : [`${ds.id}`])}`;
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* 用真实数据源 id、方法名拼接方法元组示例;无数据源时回退到通用示例。
|
|
214
|
+
*/
|
|
215
|
+
const methodTupleSuggestion = (): string => {
|
|
216
|
+
const ds = getDataSources()[0];
|
|
217
|
+
if (!ds) return SUGGESTION_METHOD_TUPLE;
|
|
218
|
+
const [methodName] = [...getMethodNamesForDataSource(ds)];
|
|
219
|
+
return `请参考以下示例值:${stringifyExampleValue([`${ds.id}`, methodName])}`;
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* 用真实数据源 id、字段名拼接显示条件结构示例;无数据源时回退到通用示例。
|
|
224
|
+
*/
|
|
225
|
+
const displayCondSuggestion = (): string => {
|
|
226
|
+
const ds = getDataSources()[0];
|
|
227
|
+
if (!ds) return SUGGESTION_DISPLAY_COND;
|
|
228
|
+
const field = firstDataSourceFieldName(ds);
|
|
229
|
+
const fieldPath = field ? [`${ds.id}`, field] : [`${ds.id}`];
|
|
230
|
+
return `请参考以下示例值:${stringifyExampleValue([{ cond: [{ field: fieldPath, op: '==' }] }])}`;
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
const validateDataSourceFieldPath = (
|
|
234
|
+
path: string[],
|
|
235
|
+
options: {
|
|
236
|
+
dataSourceId?: string;
|
|
237
|
+
valueMode?: 'key' | 'value';
|
|
238
|
+
dataSourceFieldType?: DataSourceFieldType[];
|
|
239
|
+
message?: string;
|
|
240
|
+
} = {},
|
|
241
|
+
): string | undefined => {
|
|
242
|
+
const dataSources = getDataSources();
|
|
243
|
+
if (!dataSources.length) {
|
|
244
|
+
return undefined;
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
let dsId = options.dataSourceId;
|
|
248
|
+
let fieldNames = path;
|
|
249
|
+
|
|
250
|
+
if (!dsId) {
|
|
251
|
+
if (!path.length) {
|
|
252
|
+
return defaultMessage(options.message, '值不在可选项中', dataSourceIdSuggestion());
|
|
253
|
+
}
|
|
254
|
+
const rawDsId = path[0];
|
|
255
|
+
dsId =
|
|
256
|
+
options.valueMode === 'key' || !`${rawDsId}`.startsWith(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX)
|
|
257
|
+
? `${rawDsId}`
|
|
258
|
+
: removeDataSourceFieldPrefix(`${rawDsId}`);
|
|
259
|
+
fieldNames = path.slice(1);
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
const ds = findDataSource(`${dsId}`);
|
|
263
|
+
if (!ds) {
|
|
264
|
+
return defaultMessage(options.message, '值不在可选项中', dataSourceIdSuggestion());
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
if (!fieldNames.length) {
|
|
268
|
+
return undefined;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
const { field, ok } = resolveFieldByPath(ds.fields, fieldNames);
|
|
272
|
+
if (!ok) {
|
|
273
|
+
return defaultMessage(options.message, '值不在可选项中', dataSourceIdSuggestion());
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
const allowedTypes = options.dataSourceFieldType || ['any'];
|
|
277
|
+
if (!allowedTypes.length || allowedTypes.includes('any')) {
|
|
278
|
+
return undefined;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const leafType = field?.type || 'any';
|
|
282
|
+
if (leafType === 'any' || allowedTypes.includes(leafType)) {
|
|
283
|
+
return undefined;
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
return defaultMessage(options.message, '值不在可选项中', dataSourceIdSuggestion());
|
|
287
|
+
};
|
|
288
|
+
|
|
289
|
+
const validateDataSourceMethodTuple = (value: any, message?: string): string | undefined => {
|
|
290
|
+
if (!Array.isArray(value) || value.length !== 2 || value.some((item) => typeof item !== 'string')) {
|
|
291
|
+
return defaultMessage(message, `${value}类型应为长度为 2 的字符串数组`, methodTupleSuggestion());
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const dataSources = getDataSources();
|
|
295
|
+
if (!dataSources.length) {
|
|
296
|
+
return undefined;
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
const [dsId, methodName] = value;
|
|
300
|
+
const ds = findDataSource(dsId);
|
|
301
|
+
if (!ds) {
|
|
302
|
+
return defaultMessage(message, `数据源(${dsId})不存在`, dataSourceIdSuggestion());
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
if (!getMethodNamesForDataSource(ds).has(methodName)) {
|
|
306
|
+
return defaultMessage(
|
|
307
|
+
message,
|
|
308
|
+
`数据源方法(${methodName})不存在`,
|
|
309
|
+
listSuggestion([...getMethodNamesForDataSource(ds)]),
|
|
310
|
+
);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
return undefined;
|
|
314
|
+
};
|
|
315
|
+
|
|
316
|
+
const validateDataSourceTemplateBindings = (value: string, message?: string): string | undefined => {
|
|
317
|
+
const dataSources = getDataSources();
|
|
318
|
+
if (!dataSources.length) {
|
|
319
|
+
return undefined;
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
const matches = value.matchAll(dataSourceTemplateRegExp);
|
|
323
|
+
for (const match of matches) {
|
|
324
|
+
const keys = getKeysArray(match[1]);
|
|
325
|
+
if (!keys.length) {
|
|
326
|
+
return defaultMessage(message, `数据源绑定(${value})不合法`, dataSourceBindingSuggestion());
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
const [dsId, ...fieldNames] = keys;
|
|
330
|
+
const ds = findDataSource(`${dsId}`);
|
|
331
|
+
if (!ds) {
|
|
332
|
+
return defaultMessage(message, `数据源绑定(${value})不合法`, dataSourceBindingSuggestion());
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const { ok } = resolveFieldByPath(ds.fields, fieldNames, { skipNumberIndices: true });
|
|
336
|
+
if (!ok) {
|
|
337
|
+
return defaultMessage(message, `数据源绑定(${value})不合法`, dataSourceBindingSuggestion());
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
return undefined;
|
|
342
|
+
};
|
|
343
|
+
|
|
344
|
+
const validateDataSourceFieldsItem = (item: any, message?: string): string | undefined => {
|
|
345
|
+
if (!isPlainObject(item) || typeof item.name !== 'string') {
|
|
346
|
+
return defaultMessage(message, '字段项结构不合法', SUGGESTION_FIELD_ITEM);
|
|
347
|
+
}
|
|
348
|
+
|
|
349
|
+
if (typeof item.type !== 'undefined' && !DATA_SOURCE_FIELD_TYPES.has(item.type)) {
|
|
350
|
+
return defaultMessage(message, '字段类型不合法', listSuggestion([...DATA_SOURCE_FIELD_TYPES]));
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
if (typeof item.fields !== 'undefined') {
|
|
354
|
+
if (!Array.isArray(item.fields)) {
|
|
355
|
+
return defaultMessage(message, '字段项结构不合法', SUGGESTION_FIELD_ITEM);
|
|
356
|
+
}
|
|
357
|
+
for (const child of item.fields) {
|
|
358
|
+
const error = validateDataSourceFieldsItem(child, message);
|
|
359
|
+
if (error) return error;
|
|
360
|
+
}
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
return undefined;
|
|
364
|
+
};
|
|
365
|
+
|
|
366
|
+
const validateKeyValue: TypeMatchValidator = (value, { message, props }) => {
|
|
367
|
+
if (props.config?.advanced && typeof value === 'function') {
|
|
368
|
+
return undefined;
|
|
369
|
+
}
|
|
370
|
+
if (!isPlainObject(value)) {
|
|
371
|
+
return defaultMessage(message, '值类型应为对象', SUGGESTION_OBJECT);
|
|
372
|
+
}
|
|
373
|
+
return undefined;
|
|
374
|
+
};
|
|
375
|
+
|
|
376
|
+
const validateStyleSetter: TypeMatchValidator = (value, { message }) => {
|
|
377
|
+
if (!isPlainObject(value)) {
|
|
378
|
+
return defaultMessage(message, '值类型应为对象', SUGGESTION_OBJECT);
|
|
379
|
+
}
|
|
380
|
+
return undefined;
|
|
381
|
+
};
|
|
382
|
+
|
|
383
|
+
const validateCondOpSelect: TypeMatchValidator = (value, { message, props }) => {
|
|
384
|
+
if (typeof value !== 'string') {
|
|
385
|
+
return defaultMessage(message, '值类型应为字符串', SUGGESTION_STRING);
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
const parentFields = props.config?.parentFields || [];
|
|
389
|
+
const fieldPath = Array.isArray(props.model?.field) ? props.model.field : [];
|
|
390
|
+
const [id, ...fieldNames] = [...parentFields, ...fieldPath];
|
|
391
|
+
const ds = id ? findDataSource(`${id}`) : undefined;
|
|
392
|
+
const fieldType = getFieldType(ds, fieldNames);
|
|
393
|
+
const allowed = getCondOpsByFieldType(fieldType);
|
|
394
|
+
|
|
395
|
+
if (!allowed.has(value)) {
|
|
396
|
+
return defaultMessage(message, `${value} 不在可选项中`, listSuggestion([...allowed]));
|
|
397
|
+
}
|
|
398
|
+
return undefined;
|
|
399
|
+
};
|
|
400
|
+
|
|
401
|
+
const validateCodeSelectCol: TypeMatchValidator = (value, { message }) => {
|
|
402
|
+
if (typeof value !== 'string') {
|
|
403
|
+
return defaultMessage(message, `${value}类型应为字符串`, SUGGESTION_STRING);
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
const codeDsl = codeBlockService.getCodeDsl();
|
|
407
|
+
if (!codeDsl || !Object.keys(codeDsl).length) {
|
|
408
|
+
return undefined;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
if (!(value in codeDsl)) {
|
|
412
|
+
return defaultMessage(message, `代码块(${value})不存在`, listSuggestion(Object.keys(codeDsl)));
|
|
413
|
+
}
|
|
414
|
+
return undefined;
|
|
415
|
+
};
|
|
416
|
+
|
|
417
|
+
const validatePageFragmentSelect: TypeMatchValidator = (value, { message }) => {
|
|
418
|
+
if (!isId(value)) {
|
|
419
|
+
return defaultMessage(message, `${value}类型应为字符串或数字`, SUGGESTION_STRING_OR_NUMBER);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
const items = editorService.get('root')?.items;
|
|
423
|
+
if (!items?.length) {
|
|
424
|
+
return undefined;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const fragments = items.filter((item) => item.type === NodeType.PAGE_FRAGMENT);
|
|
428
|
+
const exists = fragments.some((item) => `${item.id}` === `${value}`);
|
|
429
|
+
if (!exists) {
|
|
430
|
+
return defaultMessage(message, `页面片段(${value})不存在`, listSuggestion(fragments.map((item) => `${item.id}`)));
|
|
431
|
+
}
|
|
432
|
+
return undefined;
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
const validateUiSelect: TypeMatchValidator = (value, { message }) => {
|
|
436
|
+
if (!isId(value)) {
|
|
437
|
+
return defaultMessage(message, `${value}类型应为字符串或数字`, SUGGESTION_STRING_OR_NUMBER);
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
const root = editorService.get('root');
|
|
441
|
+
if (!root) {
|
|
442
|
+
return undefined;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
if (!editorService.getNodeById(value)) {
|
|
446
|
+
return defaultMessage(message, `组件(${value})不存在`, uiIdSuggestion());
|
|
447
|
+
}
|
|
448
|
+
return undefined;
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
const validateDataSourceInput: TypeMatchValidator = (value, { message }) => {
|
|
452
|
+
if (typeof value !== 'string') {
|
|
453
|
+
return defaultMessage(message, `${value}类型应为字符串`, SUGGESTION_STRING);
|
|
454
|
+
}
|
|
455
|
+
return validateDataSourceTemplateBindings(value, message);
|
|
456
|
+
};
|
|
457
|
+
|
|
458
|
+
const validateDataSourceMethodSelect: TypeMatchValidator = (value, { message }) =>
|
|
459
|
+
validateDataSourceMethodTuple(value, message);
|
|
460
|
+
|
|
461
|
+
const isDataSourceFieldPathValue = (value: any, config: any): value is string[] => {
|
|
462
|
+
if (!Array.isArray(value) || !value.length || value.some((item) => typeof item !== 'string')) {
|
|
463
|
+
return false;
|
|
464
|
+
}
|
|
465
|
+
if (config.dataSourceId) {
|
|
466
|
+
return true;
|
|
467
|
+
}
|
|
468
|
+
if (config.value === 'key') {
|
|
469
|
+
return true;
|
|
470
|
+
}
|
|
471
|
+
return `${value[0]}`.startsWith(DATA_SOURCE_FIELDS_SELECT_VALUE_PREFIX);
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
const validateDataSourceFieldSelect: TypeMatchValidator = (value, { message, props }) => {
|
|
475
|
+
const config = props.config || {};
|
|
476
|
+
|
|
477
|
+
if (config.fieldConfig && !isDataSourceFieldPathValue(value, config)) {
|
|
478
|
+
return undefined;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
if (!Array.isArray(value) || value.some((item) => typeof item !== 'string')) {
|
|
482
|
+
return defaultMessage(message, `${value}类型应为字符串数组`, dataSourceFieldPathSuggestion());
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return validateDataSourceFieldPath(value, {
|
|
486
|
+
dataSourceId: config.dataSourceId,
|
|
487
|
+
valueMode: config.value,
|
|
488
|
+
dataSourceFieldType: config.dataSourceFieldType,
|
|
489
|
+
message,
|
|
490
|
+
});
|
|
491
|
+
};
|
|
492
|
+
|
|
493
|
+
const validateDataSourceSelect: TypeMatchValidator = (value, { message, props }) => {
|
|
494
|
+
const config = props.config || {};
|
|
495
|
+
const dataSources = getDataSources();
|
|
496
|
+
const filtered = config.dataSourceType ? dataSources.filter((ds) => ds.type === config.dataSourceType) : dataSources;
|
|
497
|
+
|
|
498
|
+
if (config.value === 'id') {
|
|
499
|
+
if (typeof value !== 'string') {
|
|
500
|
+
return defaultMessage(message, `${value}类型应为字符串`, SUGGESTION_STRING);
|
|
501
|
+
}
|
|
502
|
+
if (!filtered.length) {
|
|
503
|
+
return undefined;
|
|
504
|
+
}
|
|
505
|
+
if (!filtered.some((ds) => `${ds.id}` === `${value}`)) {
|
|
506
|
+
return defaultMessage(message, `${value}不在可选项中`, listSuggestion(filtered.map((ds) => `${ds.id}`)));
|
|
507
|
+
}
|
|
508
|
+
return undefined;
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
if (!isPlainObject(value) || value.isBindDataSource !== true || typeof value.dataSourceId === 'undefined') {
|
|
512
|
+
return defaultMessage(message, `${value}类型不合法`, dataSourceBindObjectSuggestion(filtered));
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (!filtered.length) {
|
|
516
|
+
return undefined;
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
const ds = filtered.find((item) => `${item.id}` === `${value.dataSourceId}`);
|
|
520
|
+
if (!ds) {
|
|
521
|
+
return defaultMessage(message, `${value}不在可选项中`, listSuggestion(filtered.map((item) => `${item.id}`)));
|
|
522
|
+
}
|
|
523
|
+
|
|
524
|
+
if (typeof value.dataSourceType !== 'undefined' && value.dataSourceType !== ds.type) {
|
|
525
|
+
return defaultMessage(message, `${value}不在可选项中`, listSuggestion(filtered.map((item) => `${item.id}`)));
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
return undefined;
|
|
529
|
+
};
|
|
530
|
+
|
|
531
|
+
const validateCodeSelect: TypeMatchValidator = (value, { message }) => {
|
|
532
|
+
if (!isPlainObject(value) || !Array.isArray(value.hookData)) {
|
|
533
|
+
return defaultMessage(message, `${value}类型不合法`, SUGGESTION_CODE_SELECT);
|
|
534
|
+
}
|
|
535
|
+
|
|
536
|
+
// 「codeId 是否存在 / 数据源方法是否存在」由 CodeSelect 内部 code-select-col、
|
|
537
|
+
// data-source-method-select 单元格各自的 typeMatch 校验,只标红出错单元格。此处仅做结构校验。
|
|
538
|
+
for (const item of value.hookData) {
|
|
539
|
+
if (!isPlainObject(item)) {
|
|
540
|
+
return defaultMessage(message, '钩子项结构不合法', SUGGESTION_HOOK_ITEM);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (typeof item.params !== 'undefined' && !isPlainObject(item.params)) {
|
|
544
|
+
return defaultMessage(message, '钩子项结构不合法', SUGGESTION_HOOK_ITEM);
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
return undefined;
|
|
549
|
+
};
|
|
550
|
+
|
|
551
|
+
const validateDataSourceFields: TypeMatchValidator = (value, { message }) => {
|
|
552
|
+
if (!Array.isArray(value)) {
|
|
553
|
+
return defaultMessage(message, `${value}类型应为数组`, SUGGESTION_ARRAY);
|
|
554
|
+
}
|
|
555
|
+
for (const item of value) {
|
|
556
|
+
const error = validateDataSourceFieldsItem(item, message);
|
|
557
|
+
if (error) return error;
|
|
558
|
+
}
|
|
559
|
+
return undefined;
|
|
560
|
+
};
|
|
561
|
+
|
|
562
|
+
const validateDataSourceMocks: TypeMatchValidator = (value, { message }) => {
|
|
563
|
+
if (!Array.isArray(value)) {
|
|
564
|
+
return defaultMessage(message, `${value}类型应为数组`, SUGGESTION_ARRAY);
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
for (const item of value) {
|
|
568
|
+
if (
|
|
569
|
+
!isPlainObject(item) ||
|
|
570
|
+
typeof item.title !== 'string' ||
|
|
571
|
+
typeof item.enable !== 'boolean' ||
|
|
572
|
+
typeof item.useInEditor !== 'boolean' ||
|
|
573
|
+
!isPlainObject(item.data)
|
|
574
|
+
) {
|
|
575
|
+
return defaultMessage(message, 'mock 项结构不合法', SUGGESTION_MOCK_ITEM);
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
return undefined;
|
|
580
|
+
};
|
|
581
|
+
|
|
582
|
+
const validateDataSourceMethods: TypeMatchValidator = (value, { message }) => {
|
|
583
|
+
if (!Array.isArray(value)) {
|
|
584
|
+
return defaultMessage(message, `${value}类型应为数组`, SUGGESTION_ARRAY);
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
for (const item of value) {
|
|
588
|
+
if (!isPlainObject(item) || typeof item.name !== 'string') {
|
|
589
|
+
return defaultMessage(message, '方法项结构不合法', SUGGESTION_METHOD_ITEM);
|
|
590
|
+
}
|
|
591
|
+
if (typeof item.content !== 'undefined' && typeof item.content !== 'string' && typeof item.content !== 'function') {
|
|
592
|
+
return defaultMessage(message, '方法项结构不合法', SUGGESTION_METHOD_ITEM);
|
|
593
|
+
}
|
|
594
|
+
if (typeof item.params !== 'undefined' && !Array.isArray(item.params)) {
|
|
595
|
+
return defaultMessage(message, '方法项结构不合法', SUGGESTION_METHOD_ITEM);
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
|
|
599
|
+
return undefined;
|
|
600
|
+
};
|
|
601
|
+
|
|
602
|
+
const validateEventSelect: TypeMatchValidator = (value, { message }) => {
|
|
603
|
+
if (!Array.isArray(value)) {
|
|
604
|
+
return defaultMessage(message, `${value}类型应为数组`, SUGGESTION_ARRAY);
|
|
605
|
+
}
|
|
606
|
+
|
|
607
|
+
// 「事件名 / 动作名是否在可选项中」由 EventSelect 的 eventNameConfig.rules、compActionConfig.rules 单独校验,
|
|
608
|
+
// 以便只标红对应 select,而不是整张联动卡片。此处仅做结构校验。
|
|
609
|
+
for (const item of value) {
|
|
610
|
+
if (!isPlainObject(item) || typeof item.name !== 'string') {
|
|
611
|
+
return defaultMessage(message, '事件项结构不合法', SUGGESTION_EVENT_ITEM);
|
|
612
|
+
}
|
|
613
|
+
|
|
614
|
+
if (Array.isArray(item.actions)) {
|
|
615
|
+
for (const action of item.actions) {
|
|
616
|
+
if (!isPlainObject(action) || typeof action.actionType === 'undefined') {
|
|
617
|
+
return defaultMessage(message, '事件项结构不合法', SUGGESTION_EVENT_ITEM);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
continue;
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
if (typeof item.to === 'undefined' || typeof item.method !== 'string') {
|
|
624
|
+
return defaultMessage(message, '事件项结构不合法', SUGGESTION_EVENT_ITEM);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
return undefined;
|
|
629
|
+
};
|
|
630
|
+
|
|
631
|
+
const validateDisplayConds: TypeMatchValidator = (value, { message }) => {
|
|
632
|
+
if (!Array.isArray(value)) {
|
|
633
|
+
return defaultMessage(message, `${value}类型应为数组`, SUGGESTION_ARRAY);
|
|
634
|
+
}
|
|
635
|
+
|
|
636
|
+
// 「op 是否为合法算子 / 字段路径是否存在」由 DisplayConds 内部 cond-op-select、
|
|
637
|
+
// field 单元格(data-source-field-select / cascader)各自的 typeMatch 校验,只标红出错单元格。
|
|
638
|
+
// 此处仅做结构校验。
|
|
639
|
+
for (const item of value) {
|
|
640
|
+
if (!isPlainObject(item) || !Array.isArray(item.cond)) {
|
|
641
|
+
return defaultMessage(message, '显示条件结构不合法', displayCondSuggestion());
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
for (const cond of item.cond) {
|
|
645
|
+
if (
|
|
646
|
+
!isPlainObject(cond) ||
|
|
647
|
+
!Array.isArray(cond.field) ||
|
|
648
|
+
cond.field.some((part: any) => typeof part !== 'string') ||
|
|
649
|
+
typeof cond.op !== 'string'
|
|
650
|
+
) {
|
|
651
|
+
return defaultMessage(message, '显示条件结构不合法', displayCondSuggestion());
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
}
|
|
655
|
+
|
|
656
|
+
return undefined;
|
|
657
|
+
};
|
|
658
|
+
|
|
659
|
+
export const editorTypeMatchRules: Record<string, TypeMatchValidator> = {
|
|
660
|
+
'key-value': validateKeyValue,
|
|
661
|
+
'style-setter': validateStyleSetter,
|
|
662
|
+
'cond-op-select': validateCondOpSelect,
|
|
663
|
+
'code-select-col': validateCodeSelectCol,
|
|
664
|
+
'page-fragment-select': validatePageFragmentSelect,
|
|
665
|
+
'ui-select': validateUiSelect,
|
|
666
|
+
'data-source-input': validateDataSourceInput,
|
|
667
|
+
'data-source-method-select': validateDataSourceMethodSelect,
|
|
668
|
+
'data-source-field-select': validateDataSourceFieldSelect,
|
|
669
|
+
'data-source-select': validateDataSourceSelect,
|
|
670
|
+
'code-select': validateCodeSelect,
|
|
671
|
+
'data-source-fields': validateDataSourceFields,
|
|
672
|
+
'data-source-mocks': validateDataSourceMocks,
|
|
673
|
+
'data-source-methods': validateDataSourceMethods,
|
|
674
|
+
'event-select': validateEventSelect,
|
|
675
|
+
'display-conds': validateDisplayConds,
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
export type { TypeMatchValidateContext };
|