Skip to content

Commit

Permalink
feat: improve code2value function and fix related issues
Browse files Browse the repository at this point in the history
  • Loading branch information
wwsun committed May 16, 2024
1 parent a87d8fc commit 4e77d7a
Show file tree
Hide file tree
Showing 7 changed files with 27 additions and 115 deletions.
19 changes: 11 additions & 8 deletions packages/core/src/helpers/code-helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,18 @@ export function value2code(val: any) {
export const value2expressionCode = value2code;

/**
* 代码字符串转为 js value
* TODO: 暂时还没有使用,需要测试充分
* FIXME: expect(code2value('{ foo: "foo", ...{ bar: "bar"} }')).toEqual({ foo: 'foo', bar: 'bar' });
* 代码字符串转为具体的 js value
* @example `() => {}` 返回 undefined
*
* @param rawCode 代码字符串
* @returns 返回解析后的 js value,包括:string, number, boolean, simpleObject, simpleArray
*/
export function code2value(code: string) {
if (isWrappedCode(code)) {
code = getCodeOfWrappedCode(code);
}
const node = code2expression(code);
export function code2value(rawCode: string) {
const node = code2expression(rawCode);
const value = node2value(node);
if (isWrappedCode(value)) {
// 能转的就转,转不能的就返回空
return;
}
return value;
}
3 changes: 1 addition & 2 deletions packages/core/tests/ast.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,8 +54,7 @@ describe('ast helpers', () => {

it('code2expression', () => {
expect(code2expression('')).toBeUndefined();
expect(code2expression('{tango.stores.app}')).toBeUndefined();

expect(code2expression('tango.stores.app').type).toBe('MemberExpression');
expect(code2expression('{ type: window.bar }').type).toEqual('ObjectExpression');
expect(code2expression('() => {};').type).toEqual('ArrowFunctionExpression');
expect(code2expression('<Button>hello</Button>').type).toBe('JSXElement');
Expand Down
16 changes: 10 additions & 6 deletions packages/core/tests/helpers.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -223,11 +223,15 @@ describe('schema helpers', () => {

describe('code helper', () => {
it('code2value', () => {
expect(code2value('1')).toBe(1);
expect(code2value('{{1}}')).toBe(1);
expect(code2value('{{false}}')).toEqual(false);
expect(code2value('{{"foo"}}')).toBe('foo');
// TODO: 这种情况需要考虑下
// expect(code2value('{ foo: "foo", ...{ bar: "bar"} }')).toBe('foo');
expect(code2value(`1`)).toEqual(1);
expect(code2value(`false`)).toEqual(false);
expect(code2value(`"foo"`)).toEqual('foo');
expect(code2value(`{ foo: "foo" }`)).toEqual({ foo: 'foo' });
expect(code2value(`[{ foo: "foo" }]`)).toEqual([{ foo: 'foo' }]);
expect(code2value(`{ foo: "foo", ...{ bar: "bar"} }`)).toBe(undefined);
expect(code2value(`() => {}`)).toBe(undefined);
expect(code2value(`tango.stores.app.name`)).toBe(undefined);
expect(code2value(`window`)).toBe(undefined);
expect(code2value(`<div>hello</div>`)).toBe(undefined);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ import { Box } from 'coral-system';
import { Button, Empty } from 'antd';
import { PlayCircleOutlined } from '@ant-design/icons';
import { InputCode, Panel, JsonView } from '@music163/tango-ui';
import { isNil, logger, code2object, getValue } from '@music163/tango-helpers';
import { isNil, logger, getValue } from '@music163/tango-helpers';
import { code2value } from '@music163/tango-core';

export interface ServicePreviewProps {
appContext?: any;
Expand All @@ -22,7 +23,7 @@ export function ServicePreview({ appContext, functionKey }: ServicePreviewProps)
editable
showLineNumbers
onChange={(value: string) => {
const obj = code2object(value);
const obj = code2value(value); // 转为 object 对象
setPayload(obj);
}}
/>
Expand Down
65 changes: 0 additions & 65 deletions packages/helpers/src/helpers/code-helper.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,24 +32,6 @@ export function isValidFunctionCode(str: string) {
}
}

/**
* 是否是有效的对象字符串
*
* @example { foo: 'foo' }
* @example [{ foo: 'foo' }]
* TODO: 考虑箭头函数的情况 () => {}
*
* @param str
* @returns
*/
export function isValidObjectString(str: string) {
const obj = code2object(str);
if (obj && typeof obj === 'object') {
return true;
}
return false;
}

const templatePattern = /^{{(.+)}}$/s;

/**
Expand Down Expand Up @@ -119,53 +101,6 @@ export function isPlainString(str: string) {
return isString && !isWrapped;
}

// 提供给代码执行环境的全局变量
const patchCode = `
var tango = {
stores: {},
services: {},
config: {},
refs: {},
};
`;

/**
* 将代码放到函数体中进行执行
* @param code
* @returns 函数执行的结果
*/
export function runCode(code: string) {
let ret;
try {
// eslint-disable-next-line no-new-func
ret = new Function(`${patchCode}\n return ${code}`)();
} catch (err) {
// ignore error
}
return ret;
}

// eslint-disable-next-line no-useless-escape
const objectWrapperPattern = /^[{\[].*[}\]]$/s;

/**
* 将代码片段转成 js 对象
* FIXME: 这个逻辑有问题,不严谨
* @warning 不严谨,待优化
* @param code 代码文本
* @param isStrict 是否为严格模式(是否废弃)
* @returns
*/
export function code2object(code: string, isStrict = true) {
// 非严格模式直接执行
// 严格模式下需检测 code 是一个对象
if (!isStrict || (isStrict && objectWrapperPattern.test(code))) {
const ret = runCode(code);
return typeof ret === 'object' ? ret : undefined;
}
return code;
}

const codeBlockPattern = /```(\w*)([\s\S]*?)```/g;

/**
Expand Down
28 changes: 0 additions & 28 deletions packages/helpers/tests/helpers.test.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,12 @@
import {
isVariableString,
isValidObjectString,
code2object,
parseDndTrackId,
getVariableContent,
camelCase,
parseDndId,
isValidUrl,
getCodeBlockFormMarkdown,
upperCamelCase,
runCode,
} from '../src/helpers';

describe('string', () => {
Expand Down Expand Up @@ -54,24 +51,6 @@ describe('string', () => {
expect(getVariableContent('{{!false}}')).toBe('!false');
});

it('isValidObjectString', () => {
expect(isValidObjectString('{ foo: "bar" }')).toBeTruthy();
expect(isValidObjectString('[{ foo: "bar" }]')).toBeTruthy();
expect(isValidObjectString('[1,2,3]')).toBeTruthy();
expect(isValidObjectString('["hello", "world"]')).toBeTruthy();
// expect(isValidObjectString('() => {}')).toBeTruthy();
expect(isValidObjectString('hello')).toBeFalsy();
});

it('code2object', () => {
expect(code2object(`{ foo: 12 }`)).toEqual({ foo: 12 });
expect(code2object(`[]`)).toEqual([]);
expect(code2object(`{this.foo}`)).toBeUndefined();
expect(code2object(`{foo}`)).toBeUndefined();
expect(code2object('() => {}')).toEqual('() => {}');
expect(code2object('hello')).toEqual('hello');
});

it('parseDndTrackId', () => {
expect(parseDndTrackId('Button:123')).toEqual(['Button', 'Button:123']);
expect(parseDndTrackId('Button.Group:123')).toEqual(['Button.Group', 'Button.Group:123']);
Expand Down Expand Up @@ -104,10 +83,3 @@ describe('string', () => {
);
});
});

describe('code helper', () => {
it('runCode', () => {
expect(runCode('{}')).toEqual({});
expect(runCode('{ foo: "foo" }')).toEqual({ foo: 'foo' });
});
});
6 changes: 2 additions & 4 deletions packages/setting-form/src/form-item.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,10 @@ import {
isNil,
isString,
isWrappedCode,
runCode,
wrapCode,
} from '@music163/tango-helpers';
import { ErrorBoundary } from '@music163/tango-ui';
import { value2code } from '@music163/tango-core';
import { code2value, value2code } from '@music163/tango-core';
import { InputProps } from 'antd';
import { useFormModel, useFormVariable } from './context';
import { FormControl, ToggleCodeButton } from './form-ui';
Expand Down Expand Up @@ -89,8 +88,7 @@ function parseFieldValue(fieldValue: any) {
const isCodeString = isString(fieldValue) && isWrappedCode(fieldValue);
if (isCodeString) {
code = getCodeOfWrappedCode(fieldValue);
// FIXME: runCode 的逻辑有问题,拿到的是解析的后的结果,不是真正的代码,这里应该是 code2value
value = runCode(code);
value = code2value(code);
} else {
code = value2code(fieldValue);
value = fieldValue;
Expand Down

0 comments on commit 4e77d7a

Please sign in to comment.