Skip to content

Commit fca1501

Browse files
committed
feat: support jsxAttribute
1 parent c4ff1d0 commit fca1501

File tree

6 files changed

+71
-30
lines changed

6 files changed

+71
-30
lines changed

README.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,12 @@ defineExpose$({
168168
defineExpose({
169169
base64: $$(base64),
170170
})
171+
172+
let compRef = $useRef()
173+
defineRender(<Comp ref$={compRef} />)
174+
// convert to:
175+
let compRef = $(useRef())
176+
defineRender(<Comp ref={$$(compRef)} />)
171177
</script>
172178
```
173179

playground/src/App.vue

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
<script setup lang="ts">
2-
import { inject, provide, toRefs, watch } from 'vue'
1+
<script setup lang="tsx">
2+
import { type Ref, inject, provide, toRefs, watch } from 'vue'
33
import { useBase64 } from '@vueuse/core'
44
import { useUserStore } from '../store/user'
55
@@ -21,6 +21,10 @@ const stop = watch$(base64, () => {
2121
defineExpose$({
2222
base64,
2323
})
24+
25+
const title = $ref('title')
26+
const Comp = ({ title }: { title: Ref<string> }) => <div>{title.value}</div>
27+
const Render = <Comp title$={title} />
2428
</script>
2529

2630
<template>

src/index.ts

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -105,24 +105,34 @@ function transformReactivityFunction(
105105
if (node.type === 'TSNonNullExpression') {
106106
node = node.expression
107107
}
108-
if (node.type !== 'CallExpression') return
108+
if (node.type === 'CallExpression') {
109+
if (
110+
parent?.type === 'VariableDeclarator' &&
111+
new RegExp(`^\\$(?!(\\$|${ignore.join('|')})?$)`).test(
112+
s.sliceNode(node.callee, { offset }),
113+
)
114+
) {
115+
s.appendRight(node.callee.start! + offset + 1, '(')
116+
s.appendRight(node.end! + offset, ')')
117+
}
109118

110-
if (
111-
parent?.type === 'VariableDeclarator' &&
112-
new RegExp(`^\\$(?!(\\$|${ignore.join('|')})?$)`).test(
113-
s.sliceNode(node.callee, { offset }),
114-
)
115-
) {
116-
s.appendRight(node.callee.start! + offset + 1, '(')
117-
s.appendRight(node.end! + offset, ')')
118-
}
119+
if (/(?<!^(\$)?)\$$/.test(s.sliceNode(node.callee, { offset }))) {
120+
s.remove(node.callee.end! + offset - 1, node.callee.end! + offset)
119121

120-
if (/(?<!^(\$)?)\$$/.test(s.sliceNode(node.callee, { offset }))) {
121-
s.remove(node.callee.end! + offset - 1, node.callee.end! + offset)
122-
123-
node.arguments.forEach((argument) => {
124-
transformArguments(argument, s, offset)
125-
})
122+
node.arguments.forEach((argument) => {
123+
transformArguments(argument, s, offset)
124+
})
125+
}
126+
} else if (
127+
node.type === 'JSXAttribute' &&
128+
node.value?.type === 'JSXExpressionContainer' &&
129+
s.sliceNode(node.name).endsWith('$')
130+
) {
131+
s.remove(node.name.end! - 1, node.name.end!)
132+
if (node.value.expression) {
133+
s.appendLeft(node.value.expression.start! + offset, '$$(')
134+
s.appendRight(node.value.expression.end! + offset, ')')
135+
}
126136
}
127137
},
128138
})

src/volar.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,28 @@ function transform({
108108
transformArguments(argument)
109109
})
110110
}
111+
} else if (
112+
ts.isJsxAttribute(node) &&
113+
node.initializer &&
114+
ts.isJsxExpression(node.initializer) &&
115+
node.initializer.expression &&
116+
getText(node.name, ast, ts).endsWith('$')
117+
) {
118+
replaceSourceRange(codes, source, node.name.end - 1, node.name.end)
119+
replaceSourceRange(
120+
codes,
121+
source,
122+
node.initializer.expression.pos,
123+
node.initializer.expression.pos,
124+
'$$(',
125+
)
126+
replaceSourceRange(
127+
codes,
128+
source,
129+
node.initializer.expression.end,
130+
node.initializer.expression?.end,
131+
')',
132+
)
111133
}
112134

113135
ts.forEachChild(node, (child) => {

tests/__snapshots__/basic.test.ts.snap

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
22

33
exports[`fixtures > tests/fixtures/basic.vue 1`] = `
4-
"import { defineComponent, ref, watch, openBlock, createElementBlock, toDisplayString, unref } from 'vue';
4+
"import { defineComponent, ref, watch, openBlock, createBlock } from 'vue';
55
import _export_sfc from '[NULL]/plugin-vue/export-helper';
66
77
"use strict";
@@ -25,14 +25,11 @@ var _sfc_main = /* @__PURE__ */ defineComponent({
2525
defineExpose({
2626
name: $$(name)
2727
});
28+
const title = $ref("title");
29+
const Comp = ({ title: title2 }) => title2.value;
30+
const Render = () => /* @__PURE__ */ React.createElement(Comp, { title: $$(title) });
2831
return (_ctx, _cache) => {
29-
return openBlock(), createElementBlock(
30-
"div",
31-
null,
32-
toDisplayString(unref(name)),
33-
1
34-
/* TEXT */
35-
);
32+
return openBlock(), createBlock(Render);
3633
};
3734
}
3835
});

tests/fixtures/basic.vue

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
<script setup lang="tsx">
2-
import { ref, watch } from 'vue'
2+
import { Ref, ref, watch } from 'vue'
33
44
function useApi(defaultName = ref('')) {
55
const id = ref(1)
@@ -22,10 +22,12 @@ watch$(name, () => {})
2222
defineExpose$({
2323
name,
2424
})
25+
26+
const title = $ref<string>('title')
27+
const Comp = ({ title }: { title: Ref<string> }) => title.value
28+
const Render = () => <Comp title$={title} />
2529
</script>
2630

2731
<template>
28-
<div>
29-
{{ name }}
30-
</div>
32+
<Render />
3133
</template>

0 commit comments

Comments
 (0)