Skip to content

Commit

Permalink
feat: js panel add jsx support (opentiny#253)
Browse files Browse the repository at this point in the history
* feat: JS面板支持JSX语法

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

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

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

* fix: 修改变量名
  • Loading branch information
gene9831 authored Jan 19, 2024
1 parent 9c72525 commit 91ff6ae
Show file tree
Hide file tree
Showing 4 changed files with 73 additions and 21 deletions.
24 changes: 16 additions & 8 deletions packages/canvas/src/components/render/render.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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({})

Expand Down Expand Up @@ -138,20 +145,25 @@ 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
} else if (data.value.indexOf('t(') > -1) {
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
}
}
Expand Down Expand Up @@ -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() { }')

Expand Down
2 changes: 1 addition & 1 deletion packages/common/component/MetaCodeEditor.vue
Original file line number Diff line number Diff line change
Expand Up @@ -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)
})
Expand Down
22 changes: 11 additions & 11 deletions packages/common/js/ast.js
Original file line number Diff line number Diff line change
@@ -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'
Expand All @@ -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

Expand Down
46 changes: 45 additions & 1 deletion packages/design-core/public/mock/bundle.json
Original file line number Diff line number Diff line change
Expand Up @@ -10910,7 +10910,7 @@
"zh_CN": "基础信息"
},
"collapse": {
"number": 6,
"number": 10,
"text": {
"zh_CN": "显示更多"
}
Expand Down Expand Up @@ -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": {
Expand Down Expand Up @@ -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": {
Expand Down

0 comments on commit 91ff6ae

Please sign in to comment.