feat: gen code support attr with function (#1369)
This commit is contained in:
parent
8b91cf12ce
commit
b63169431c
|
|
@ -21,7 +21,8 @@ import {
|
|||
handleObjBindAttrHook,
|
||||
handleEventAttrHook,
|
||||
handleTinyIconPropsHook,
|
||||
handleJsxModelValueUpdate
|
||||
handleJsxModelValueUpdate,
|
||||
handleJSFunctionAttrHook
|
||||
} from './generateAttribute'
|
||||
import {
|
||||
GEN_SCRIPT_HOOKS,
|
||||
|
|
@ -227,6 +228,7 @@ export const genSFCWithDefaultPlugin = (schema, componentsMap, config = {}, next
|
|||
handleAttrKeyHook,
|
||||
handlePrimitiveAttributeHook,
|
||||
handleExpressionAttrHook,
|
||||
handleJSFunctionAttrHook,
|
||||
handleI18nAttrHook,
|
||||
handleTinyIconPropsHook,
|
||||
handleObjBindAttrHook,
|
||||
|
|
|
|||
|
|
@ -1,3 +1,4 @@
|
|||
import { parse } from '@babel/parser'
|
||||
import {
|
||||
JS_EXPRESSION,
|
||||
JS_FUNCTION,
|
||||
|
|
@ -358,6 +359,38 @@ export const handleExpressionAttrHook = (schemaData, globalHooks, config) => {
|
|||
})
|
||||
}
|
||||
|
||||
export const handleJSFunctionAttrHook = (schemaData, globalHooks, config) => {
|
||||
const { attributes, schema: { props = {} } = {} } = schemaData || {}
|
||||
const isJSX = config.isJSX
|
||||
Object.entries(props).forEach(([key, value]) => {
|
||||
if (value?.type === JS_FUNCTION && !isOn(key)) {
|
||||
let functionName = `${key}Fun`
|
||||
|
||||
try {
|
||||
const ast = parse(value.value, { sourceType: 'module', plugins: ['typescript', 'jsx'] })
|
||||
// 这里可能会存在命名冲突的场景,应该在设计态阻止命名冲突
|
||||
functionName = ast.program.body[0].id.name
|
||||
|
||||
globalHooks.addStatement({
|
||||
position: INSERT_POSITION.AFTER_METHODS,
|
||||
value: `const ${functionName} = wrap(${value.value})`,
|
||||
key: functionName
|
||||
})
|
||||
} catch (error) {
|
||||
const logger = console
|
||||
logger.warn(`解析失败属性 ${key} 失败: ${error.message || error}`)
|
||||
|
||||
// 解析失败,不处理,原样绑定到属性上
|
||||
functionName = value.value
|
||||
}
|
||||
|
||||
attributes.push(handleJSExpressionBinding(key, { value: functionName }, isJSX))
|
||||
|
||||
delete props[key]
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export const handleI18nAttrHook = (schemaData, globalHooks, config) => {
|
||||
const { attributes, schema: { props = {} } = {} } = schemaData || {}
|
||||
const isJSX = config.isJSX
|
||||
|
|
|
|||
|
|
@ -98,9 +98,9 @@ import { IconSearch, IconDel, iconHelpCircle, IconEdit } from '@opentiny/vue-ico
|
|||
import * as vue from 'vue'
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
import { I18nInjectionKey } from 'vue-i18n'
|
||||
import CrmQuoteListGridStatus from '../components/CrmQuoteListGridStatus.vue'
|
||||
import CrmQuoteListGridStatus from '@/components/CrmQuoteListGridStatus.vue'
|
||||
|
||||
import ImageTitle from '../components/ImageTitle.vue'
|
||||
import ImageTitle from '@/components/ImageTitle.vue'
|
||||
|
||||
const TinyIconSearch = IconSearch()
|
||||
const TinyIconDel = IconDel()
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import { Form as TinyForm, FormItem as TinyFormItem } from '@opentiny/vue'
|
|||
import * as vue from 'vue'
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
import { I18nInjectionKey } from 'vue-i18n'
|
||||
import PropAccessor from '../components/PropAccessor.vue'
|
||||
import PropAccessor from '@/components/PropAccessor.vue'
|
||||
|
||||
const props = defineProps({})
|
||||
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ import { Form as TinyForm, FormItem as TinyFormItem } from '@opentiny/vue'
|
|||
import * as vue from 'vue'
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
import { I18nInjectionKey } from 'vue-i18n'
|
||||
import StateAccessor from '../components/StateAccessor.vue'
|
||||
import StateAccessor from '@/components/StateAccessor.vue'
|
||||
|
||||
const props = defineProps({})
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,9 @@
|
|||
[
|
||||
{
|
||||
"componentName": "TinyTree",
|
||||
"exportName": "Tree",
|
||||
"package": "@opentiny/vue",
|
||||
"version": "^3.10.0",
|
||||
"destructuring": true
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
<template>
|
||||
<div>
|
||||
<div>
|
||||
<tiny-tree
|
||||
class="component-base-style"
|
||||
:render-content="render"
|
||||
:data="[
|
||||
{ label: '一级 1', children: [{ label: '二级 1-1', children: [{ label: '三级 1-1-1' }] }] },
|
||||
{
|
||||
label: '一级 2',
|
||||
children: [
|
||||
{ label: '二级 2-1', children: [{ label: '三级 2-1-1' }] },
|
||||
{ label: '二级 2-2', children: [{ label: '三级 2-2-1' }] }
|
||||
]
|
||||
}
|
||||
]"
|
||||
></tiny-tree>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup lang="jsx">
|
||||
import { Tree as TinyTree } from '@opentiny/vue'
|
||||
import * as vue from 'vue'
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
import { I18nInjectionKey } from 'vue-i18n'
|
||||
|
||||
const props = defineProps({})
|
||||
|
||||
const emit = defineEmits([])
|
||||
const { t, lowcodeWrap, stores } = vue.inject(I18nInjectionKey).lowcode()
|
||||
const wrap = lowcodeWrap(props, { emit })
|
||||
wrap({ stores })
|
||||
|
||||
const state = vue.reactive({})
|
||||
wrap({ state })
|
||||
|
||||
const render = wrap(function render(h, { node, data }) {
|
||||
return <span style="color: red;font-size: 20px;">{node.label}</span>
|
||||
})
|
||||
</script>
|
||||
<style scoped></style>
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
import { expect, test } from 'vitest'
|
||||
import { genSFCWithDefaultPlugin } from '@/generator/vue/sfc'
|
||||
import schema from './page.schema.json'
|
||||
import componentsMap from './components-map.json'
|
||||
import { formatCode } from '@/utils/formatCode'
|
||||
|
||||
test('should generate extra jsFunction on setup', async () => {
|
||||
const res = genSFCWithDefaultPlugin(schema, componentsMap)
|
||||
const formattedCode = formatCode(res, 'vue')
|
||||
|
||||
await expect(formattedCode).toMatchFileSnapshot('./expected/jsFunctionAttrTest.vue')
|
||||
})
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
{
|
||||
"state": {},
|
||||
"methods": {},
|
||||
"componentName": "Page",
|
||||
"css": "",
|
||||
"props": {},
|
||||
"lifeCycles": {},
|
||||
"children": [
|
||||
{
|
||||
"componentName": "div",
|
||||
"props": {},
|
||||
"id": "85375559",
|
||||
"children": [
|
||||
{
|
||||
"componentName": "TinyTree",
|
||||
"props": {
|
||||
"data": [
|
||||
{
|
||||
"label": "一级 1",
|
||||
"children": [
|
||||
{
|
||||
"label": "二级 1-1",
|
||||
"children": [
|
||||
{
|
||||
"label": "三级 1-1-1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "一级 2",
|
||||
"children": [
|
||||
{
|
||||
"label": "二级 2-1",
|
||||
"children": [
|
||||
{
|
||||
"label": "三级 2-1-1"
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"label": "二级 2-2",
|
||||
"children": [
|
||||
{
|
||||
"label": "三级 2-2-1"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"className": "component-base-style",
|
||||
"render-content": {
|
||||
"type": "JSFunction",
|
||||
"value": "function render(h, { node, data }) {\n return <span style=\"color: red;font-size: 20px;\">{node.label}</span>\n}\n"
|
||||
}
|
||||
},
|
||||
"children": [],
|
||||
"id": "43235432"
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"dataSource": {
|
||||
"list": []
|
||||
},
|
||||
"utils": [],
|
||||
"bridge": [],
|
||||
"inputs": [],
|
||||
"outputs": [],
|
||||
"fileName": "jsFunctionAttrTest"
|
||||
}
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
import * as vue from 'vue'
|
||||
import { defineProps, defineEmits } from 'vue'
|
||||
import { I18nInjectionKey } from 'vue-i18n'
|
||||
import BlockSlotParams from '../components/BlockSlotParams.vue'
|
||||
import BlockSlotParams from '@/components/BlockSlotParams.vue'
|
||||
|
||||
const props = defineProps({})
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue