feat: js panel add jsx support (#253)

* feat: JS面板支持JSX语法

* fix: 画布解析JS表达式时支持JSX语法

* fix: 修复画布解析JSX表达式时会返回undefined

* feat: 添加Tree和Tooltip的自定义渲染函数属性

* fix: 修改变量名
This commit is contained in:
Gene 2024-01-19 15:58:44 +08:00 committed by GitHub
parent 9c72525db6
commit 91ff6aed55
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 73 additions and 21 deletions

View File

@ -34,8 +34,8 @@ const { BROADCAST_CHANNEL } = constants
const { hyphenateRE } = utils
const customElements = {}
const transformJSX = (code) =>
transformSync(code, {
const transformJSX = (code) => {
const res = transformSync(code, {
plugins: [
[
babelPluginJSX,
@ -46,6 +46,13 @@ const transformJSX = (code) =>
]
]
})
return (res.code || '')
.replace(/import \{.+\} from "vue";/, '')
.replace(/h\(_?resolveComponent\((.*?)\)/g, `h(this.getComponent($1)`)
.replace(/_?resolveComponent/g, 'h')
.replace(/_?createTextVNode\((.*?)\)/g, '$1')
.trim()
}
export const blockSlotDataMap = reactive({})
@ -138,7 +145,7 @@ export const newFn = (...argv) => {
return new Fn(...argv)
}
const parseExpression = (data, scope, ctx) => {
const parseExpression = (data, scope, ctx, isJsx = false) => {
try {
if (data.value.indexOf('this.i18n') > -1) {
ctx.i18n = i18nHost.global.t
@ -146,12 +153,17 @@ const parseExpression = (data, scope, ctx) => {
ctx.t = i18nHost.global.t
}
return newFn('$scope', `with($scope || {}) { return ${data.value} }`).call(ctx, {
const expression = isJsx ? transformJSX(data.value) : data.value
return newFn('$scope', `with($scope || {}) { return ${expression} }`).call(ctx, {
...ctx,
...scope,
slotScope: scope
})
} catch (err) {
// 解析抛出异常,则再尝试解析 JSX 语法。如果解析 JSX 语法仍然出现错误isJsx 变量会确保不会再次递归执行解析
if (!isJsx) {
return parseExpression(data, scope, ctx, true)
}
return undefined
}
}
@ -347,10 +359,6 @@ export const getComponent = (name) => {
const parseJSXFunction = (data, ctx) => {
try {
const newValue = transformJSX(data.value)
.code.replace(/import \{.+\} from "vue";/, '')
.replace(/h\(_?resolveComponent\((.*?)\)/g, `h(this.getComponent($1)`)
.replace(/_?resolveComponent/g, 'h')
.replace(/_?createTextVNode\((.*?)\)/g, '$1')
const fnInfo = parseFunctionString(newValue)
if (!fnInfo) throw Error('函数解析失败请检查格式。示例function fnName() { }')

View File

@ -139,7 +139,7 @@ export default {
watchEffect(() => {
const { modelValue, dataType } = props
const val = dataType ? modelValue?.value : modelValue
const val = dataType ? modelValue?.value || '' : modelValue
value.value = typeof val === 'string' ? val : JSON.stringify(val, null, 2)
})

View File

@ -1,14 +1,14 @@
/**
* Copyright (c) 2023 - present TinyEngine Authors.
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
* Copyright (c) 2023 - present TinyEngine Authors.
* Copyright (c) 2023 - present Huawei Cloud Computing Technologies Co., Ltd.
*
* Use of this source code is governed by an MIT-style license.
*
* THE OPEN SOURCE SOFTWARE IN THIS PRODUCT IS DISTRIBUTED IN THE HOPE THAT IT WILL BE USEFUL,
* BUT WITHOUT ANY WARRANTY, WITHOUT EVEN THE IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR
* A PARTICULAR PURPOSE. SEE THE APPLICABLE LICENSES FOR MORE DETAILS.
*
*/
import { parse, parseExpression } from '@babel/parser'
import generate from '@babel/generator'
@ -24,7 +24,7 @@ export const insertName = (name, content) => content.replace(METHOD_REGEXP, `fun
export const removeName = (content) => content.replace(METHOD_REGEXP, 'function (')
export const string2Ast = (string = '') => parse(string, { sourceType: 'module', plugins: ['typescript'] })
export const string2Ast = (string = '') => parse(string, { sourceType: 'module', plugins: ['typescript', 'jsx'] })
export const ast2String = (ast) => generate(ast, { retainLines: true }).code

View File

@ -10910,7 +10910,7 @@
"zh_CN": "基础信息"
},
"collapse": {
"number": 6,
"number": 10,
"text": {
"zh_CN": "显示更多"
}
@ -10985,6 +10985,28 @@
},
"labelPosition": "left"
},
{
"property": "render-content",
"label": {
"text": {
"zh_CN": "渲染函数"
}
},
"required": false,
"readOnly": false,
"disabled": false,
"cols": 12,
"widget": {
"component": "MetaInput",
"props": {
"disabled": true,
"placeholder": "请使用变量绑定来绑定函数"
}
},
"description": {
"zh_CN": "树节点的内容区的渲染函数"
}
},
{
"property": "icon-trigger-click-node",
"label": {
@ -11532,6 +11554,28 @@
"zh_CN": "显示的内容,也可以通过 slot#content 传入 DOM"
}
},
{
"property": "render-content",
"label": {
"text": {
"zh_CN": "渲染函数"
}
},
"required": false,
"readOnly": false,
"disabled": false,
"cols": 12,
"widget": {
"component": "MetaInput",
"props": {
"disabled": true,
"placeholder": "请使用变量绑定来绑定函数"
}
},
"description": {
"zh_CN": "自定义渲染函数,返回需要渲染的节点内容"
}
},
{
"property": "modelValue",
"label": {