feat(editor): 新增parseDSL配置,用于解析DSL,默认使用eval

This commit is contained in:
roymondchen 2023-06-19 11:27:47 +08:00
parent 1f5527270c
commit 2b881c3863
10 changed files with 36 additions and 21 deletions

View File

@ -33,7 +33,7 @@
</TMagicCard> </TMagicCard>
</template> </template>
<script lang="ts" setup> <script lang="ts" setup>
import { inject, ref, watchEffect } from 'vue'; import { inject, provide, ref, watchEffect } from 'vue';
import { cloneDeep } from 'lodash-es'; import { cloneDeep } from 'lodash-es';
import { TMagicCard, TMagicInput, tMagicMessage } from '@tmagic/design'; import { TMagicCard, TMagicInput, tMagicMessage } from '@tmagic/design';
@ -41,6 +41,7 @@ import { ColumnConfig, TableConfig } from '@tmagic/form';
import { CodeParam, Id } from '@tmagic/schema'; import { CodeParam, Id } from '@tmagic/schema';
import type { Services } from '@editor/type'; import type { Services } from '@editor/type';
import { getConfig } from '@editor/utils/config';
import CodeDraftEditor from './CodeDraftEditor.vue'; import CodeDraftEditor from './CodeDraftEditor.vue';
@ -48,6 +49,8 @@ defineOptions({
name: 'MEditorFunctionEditor', name: 'MEditorFunctionEditor',
}); });
provide('mForm', {});
const defaultParamColConfig: ColumnConfig = { const defaultParamColConfig: ColumnConfig = {
type: 'row', type: 'row',
label: '参数类型', label: '参数类型',
@ -147,9 +150,8 @@ initTableModel();
// //
const beforeSave = (codeValue: string): boolean => { const beforeSave = (codeValue: string): boolean => {
try { try {
// evaljs // js
// eslint-disable-next-line no-eval getConfig('parseDSL')(codeValue);
eval(codeValue);
return true; return true;
} catch (e: any) { } catch (e: any) {
tMagicMessage.error(e.stack); tMagicMessage.error(e.stack);

View File

@ -6,6 +6,8 @@
import { computed, reactive, watch } from 'vue'; import { computed, reactive, watch } from 'vue';
import serialize from 'serialize-javascript'; import serialize from 'serialize-javascript';
import { getConfig } from '@editor/utils/config';
defineOptions({ defineOptions({
name: 'MEditorCodeLink', name: 'MEditorCodeLink',
}); });
@ -69,8 +71,8 @@ const changeHandler = (v: Record<string, any>) => {
if (!props.name || !props.model) return; if (!props.name || !props.model) return;
try { try {
// eslint-disable-next-line no-eval const parseDSL = getConfig('parseDSL');
props.model[props.name] = eval(`(${v[props.name]})`); props.model[props.name] = parseDSL(`(${v[props.name]})`);
emit('change', props.model[props.name]); emit('change', props.model[props.name]);
} catch (e) { } catch (e) {
console.error(e); console.error(e);

View File

@ -64,11 +64,12 @@ export { default as LayoutContainer } from './components/SplitView.vue';
export { default as SplitView } from './components/SplitView.vue'; export { default as SplitView } from './components/SplitView.vue';
const defaultInstallOpt: InstallOptions = { const defaultInstallOpt: InstallOptions = {
// @todo, 自定义图片上传方法等编辑器依赖的外部选项 // eslint-disable-next-line no-eval
parseDSL: (dsl: string) => eval(dsl),
}; };
export default { export default {
install: (app: App, opt?: InstallOptions): void => { install: (app: App, opt?: Partial<InstallOptions>): void => {
const option = Object.assign(defaultInstallOpt, opt || {}); const option = Object.assign(defaultInstallOpt, opt || {});
// eslint-disable-next-line no-param-reassign // eslint-disable-next-line no-param-reassign

View File

@ -52,6 +52,7 @@ import { TMagicScrollbar } from '@tmagic/design';
import SplitView from '@editor/components/SplitView.vue'; import SplitView from '@editor/components/SplitView.vue';
import type { GetColumnWidth, Services } from '@editor/type'; import type { GetColumnWidth, Services } from '@editor/type';
import { getConfig } from '@editor/utils/config';
import AddPageBox from './AddPageBox.vue'; import AddPageBox from './AddPageBox.vue';
import CodeEditor from './CodeEditor.vue'; import CodeEditor from './CodeEditor.vue';
@ -131,8 +132,8 @@ const columnWidthChange = (columnW: GetColumnWidth) => {
const saveCode = (value: string) => { const saveCode = (value: string) => {
try { try {
// eslint-disable-next-line no-eval const parseDSL = getConfig('parseDSL');
editorService?.set('root', eval(value)); editorService?.set('root', parseDSL(value));
} catch (e: any) { } catch (e: any) {
console.error(e); console.error(e);
} }

View File

@ -36,6 +36,7 @@ import StageCore, { calcValueByFontsize, getOffset, Runtime } from '@tmagic/stag
import ScrollViewer from '@editor/components/ScrollViewer.vue'; import ScrollViewer from '@editor/components/ScrollViewer.vue';
import { Layout, MenuButton, MenuComponent, Services, StageOptions } from '@editor/type'; import { Layout, MenuButton, MenuComponent, Services, StageOptions } from '@editor/type';
import { getConfig } from '@editor/utils/config';
import { useStage } from '@editor/utils/stage'; import { useStage } from '@editor/utils/stage';
import ViewerMenu from './ViewerMenu.vue'; import ViewerMenu from './ViewerMenu.vue';
@ -162,8 +163,8 @@ const dropHandler = async (e: DragEvent) => {
} }
if (e.dataTransfer && parent && stageContainer.value && stage) { if (e.dataTransfer && parent && stageContainer.value && stage) {
// eslint-disable-next-line no-eval const parseDSL = getConfig('parseDSL');
const config = eval(`(${e.dataTransfer.getData('data')})`); const config = parseDSL(`(${e.dataTransfer.getData('data')})`);
const layout = await services?.editorService.getLayout(parent); const layout = await services?.editorService.getLayout(parent);
const containerRect = stageContainer.value.getBoundingClientRect(); const containerRect = stageContainer.value.getBoundingClientRect();

View File

@ -23,6 +23,7 @@ import { CodeBlockContent, CodeBlockDSL, Id } from '@tmagic/schema';
import type { CodeState } from '@editor/type'; import type { CodeState } from '@editor/type';
import { CODE_DRAFT_STORAGE_KEY } from '@editor/type'; import { CODE_DRAFT_STORAGE_KEY } from '@editor/type';
import { getConfig } from '@editor/utils/config';
import BaseService from './BaseService'; import BaseService from './BaseService';
@ -95,8 +96,8 @@ class CodeBlock extends BaseService {
const codeConfigProcessed = codeConfig; const codeConfigProcessed = codeConfig;
if (codeConfig.content) { if (codeConfig.content) {
// 在保存的时候转换代码内容 // 在保存的时候转换代码内容
// eslint-disable-next-line no-eval const parseDSL = getConfig('parseDSL');
codeConfigProcessed.content = eval(codeConfig.content); codeConfigProcessed.content = parseDSL(codeConfig.content);
} }
const existContent = codeDsl[id] || {}; const existContent = codeDsl[id] || {};

View File

@ -1,5 +1,7 @@
import serialize from 'serialize-javascript'; import serialize from 'serialize-javascript';
import { getConfig } from '@editor/utils/config';
import BaseService from './BaseService'; import BaseService from './BaseService';
interface Options { interface Options {
@ -64,8 +66,7 @@ export class WebStorage extends BaseService {
switch (protocol) { switch (protocol) {
case Protocol.OBJECT: case Protocol.OBJECT:
// eslint-disable-next-line no-eval return getConfig('parseDSL')(`(${item})`);
return eval(`(${item})`);
case Protocol.JSON: case Protocol.JSON:
return JSON.parse(item); return JSON.parse(item);
case Protocol.NUMBER: case Protocol.NUMBER:

View File

@ -45,6 +45,7 @@ export type BeforeAdd = (config: MNode, parent: MContainer) => Promise<MNode> |
export type GetConfig = (config: FormConfig) => Promise<FormConfig> | FormConfig; export type GetConfig = (config: FormConfig) => Promise<FormConfig> | FormConfig;
export interface InstallOptions { export interface InstallOptions {
parseDSL: (dsl: string) => MApp;
[key: string]: any; [key: string]: any;
} }

View File

@ -24,6 +24,6 @@ const setConfig = (option: InstallOptions): void => {
$TMAGIC_EDITOR = option; $TMAGIC_EDITOR = option;
}; };
const getConfig = (key: keyof InstallOptions): unknown => $TMAGIC_EDITOR[key]; const getConfig = <K extends keyof InstallOptions>(key: K): InstallOptions[K] => $TMAGIC_EDITOR[key];
export { getConfig, setConfig }; export { getConfig, setConfig };

View File

@ -25,7 +25,12 @@ import { NodeType } from '@tmagic/schema';
import editorService from '@editor/services/editor'; import editorService from '@editor/services/editor';
import historyService from '@editor/services/history'; import historyService from '@editor/services/history';
import storageService from '@editor/services/storage'; import storageService from '@editor/services/storage';
import { COPY_STORAGE_KEY } from '@editor/utils'; import { COPY_STORAGE_KEY, setConfig } from '@editor/utils';
setConfig({
// eslint-disable-next-line no-eval
parseDSL: (dsl: string) => eval(dsl),
});
// mock window.localStage // mock window.localStage
class LocalStorageMock { class LocalStorageMock {
@ -306,7 +311,7 @@ describe('update', () => {
test('没有id', async () => { test('没有id', async () => {
try { try {
await editorService.update({ type: 'text', text: 'text', id: '' }); await editorService.update({ type: 'text', text: 'text', id: '' });
} catch (e: InstanceType<Error>) { } catch (e: any) {
expect(e.message).toBe('没有配置或者配置缺少id值'); expect(e.message).toBe('没有配置或者配置缺少id值');
} }
}); });
@ -315,7 +320,7 @@ describe('update', () => {
// 一般可能出现在外边扩展功能 // 一般可能出现在外边扩展功能
try { try {
await editorService.update({ type: '', text: 'text', id: NodeId.NODE_ID }); await editorService.update({ type: '', text: 'text', id: NodeId.NODE_ID });
} catch (e: InstanceType<Error>) { } catch (e: any) {
expect(e.message).toBe('配置缺少type值'); expect(e.message).toBe('配置缺少type值');
} }
}); });
@ -325,7 +330,7 @@ describe('update', () => {
// 设置当前编辑的页面 // 设置当前编辑的页面
await editorService.select(NodeId.PAGE_ID); await editorService.select(NodeId.PAGE_ID);
await editorService.update({ type: 'text', text: 'text', id: NodeId.ERROR_NODE_ID }); await editorService.update({ type: 'text', text: 'text', id: NodeId.ERROR_NODE_ID });
} catch (e: InstanceType<Error>) { } catch (e: any) {
expect(e.message).toBe(`获取不到id为${NodeId.ERROR_NODE_ID}的节点`); expect(e.message).toBe(`获取不到id为${NodeId.ERROR_NODE_ID}的节点`);
} }
}); });