Skip to content

Commit a0bd0e9

Browse files
Jevon617LittleSoundsxzz
authored
feat(compiler-vapor): ref for v-for (#167)
Co-authored-by: Rizumu Ayaka <[email protected]> Co-authored-by: 三咲智子 Kevin Deng <[email protected]>
1 parent 98bae0c commit a0bd0e9

File tree

10 files changed

+267
-29
lines changed

10 files changed

+267
-29
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
2+
3+
exports[`compiler: template ref transform > dynamic ref 1`] = `
4+
"import { setRef as _setRef, template as _template } from 'vue/vapor';
5+
const t0 = _template("<div></div>")
6+
7+
export function render(_ctx) {
8+
const n0 = t0()
9+
_setRef(n0, _ctx.foo)
10+
return n0
11+
}"
12+
`;
13+
14+
exports[`compiler: template ref transform > ref + v-for 1`] = `
15+
"import { setRef as _setRef, createFor as _createFor, template as _template } from 'vue/vapor';
16+
const t0 = _template("<div></div>")
17+
18+
export function render(_ctx) {
19+
const n0 = _createFor(() => ([1,2,3]), (_block) => {
20+
const n2 = t0()
21+
_setRef(n2, "foo", true)
22+
return [n2, () => {}]
23+
})
24+
return n0
25+
}"
26+
`;
27+
28+
exports[`compiler: template ref transform > ref + v-if 1`] = `
29+
"import { setRef as _setRef, createIf as _createIf, template as _template } from 'vue/vapor';
30+
const t0 = _template("<div></div>")
31+
32+
export function render(_ctx) {
33+
const n0 = _createIf(() => (true), () => {
34+
const n2 = t0()
35+
_setRef(n2, "foo")
36+
return n2
37+
})
38+
return n0
39+
}"
40+
`;
41+
42+
exports[`compiler: template ref transform > static ref 1`] = `
43+
"import { setRef as _setRef, template as _template } from 'vue/vapor';
44+
const t0 = _template("<div></div>")
45+
46+
export function render(_ctx) {
47+
const n0 = t0()
48+
_setRef(n0, "foo")
49+
return n0
50+
}"
51+
`;
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,127 @@
1-
// TODO: add tests for this transform
1+
import {
2+
DynamicFlag,
3+
type ForIRNode,
4+
IRNodeTypes,
5+
type IfIRNode,
6+
transformChildren,
7+
transformElement,
8+
transformRef,
9+
transformVFor,
10+
transformVIf,
11+
} from '../../src'
12+
import { makeCompile } from './_utils'
13+
14+
const compileWithTransformRef = makeCompile({
15+
nodeTransforms: [
16+
transformVIf,
17+
transformVFor,
18+
transformRef,
19+
transformElement,
20+
transformChildren,
21+
],
22+
})
23+
224
describe('compiler: template ref transform', () => {
3-
test.todo('basic')
25+
test('static ref', () => {
26+
const { ir, code } = compileWithTransformRef(`<div ref="foo" />`)
27+
28+
expect(ir.block.dynamic.children[0]).toMatchObject({
29+
id: 0,
30+
flags: DynamicFlag.REFERENCED,
31+
})
32+
expect(ir.template).toEqual(['<div></div>'])
33+
expect(ir.block.operation).lengthOf(1)
34+
expect(ir.block.operation[0]).toMatchObject({
35+
type: IRNodeTypes.SET_REF,
36+
element: 0,
37+
value: {
38+
content: 'foo',
39+
isStatic: true,
40+
loc: {
41+
start: { line: 1, column: 10, offset: 9 },
42+
end: { line: 1, column: 15, offset: 14 },
43+
},
44+
},
45+
})
46+
47+
expect(code).matchSnapshot()
48+
expect(code).contains('_setRef(n0, "foo")')
49+
})
50+
51+
test('dynamic ref', () => {
52+
const { ir, code } = compileWithTransformRef(`<div :ref="foo" />`)
53+
54+
expect(ir.block.dynamic.children[0]).toMatchObject({
55+
id: 0,
56+
flags: DynamicFlag.REFERENCED,
57+
})
58+
expect(ir.template).toEqual(['<div></div>'])
59+
expect(ir.block.operation).lengthOf(1)
60+
expect(ir.block.operation[0]).toMatchObject({
61+
type: IRNodeTypes.SET_REF,
62+
element: 0,
63+
value: {
64+
content: 'foo',
65+
isStatic: false,
66+
loc: {
67+
start: { line: 1, column: 12, offset: 11 },
68+
end: { line: 1, column: 15, offset: 14 },
69+
},
70+
},
71+
})
72+
expect(code).matchSnapshot()
73+
expect(code).contains('_setRef(n0, _ctx.foo)')
74+
})
75+
76+
test('ref + v-if', () => {
77+
const { ir, code } = compileWithTransformRef(
78+
`<div ref="foo" v-if="true" />`,
79+
)
80+
81+
expect(ir.block.operation).lengthOf(1)
82+
expect(ir.block.operation[0].type).toBe(IRNodeTypes.IF)
83+
84+
const { positive } = ir.block.operation[0] as IfIRNode
85+
86+
expect(positive.operation).lengthOf(1)
87+
expect(positive.operation[0]).toMatchObject({
88+
type: IRNodeTypes.SET_REF,
89+
element: 2,
90+
value: {
91+
content: 'foo',
92+
isStatic: true,
93+
loc: {
94+
start: { line: 1, column: 10, offset: 9 },
95+
end: { line: 1, column: 15, offset: 14 },
96+
},
97+
},
98+
})
99+
100+
expect(code).matchSnapshot()
101+
expect(code).contains('_setRef(n2, "foo")')
102+
})
103+
104+
test('ref + v-for', () => {
105+
const { ir, code } = compileWithTransformRef(
106+
`<div ref="foo" v-for="item in [1,2,3]" />`,
107+
)
108+
109+
const { render } = ir.block.operation[0] as ForIRNode
110+
expect(render.operation).lengthOf(1)
111+
expect(render.operation[0]).toMatchObject({
112+
type: IRNodeTypes.SET_REF,
113+
element: 2,
114+
value: {
115+
content: 'foo',
116+
isStatic: true,
117+
loc: {
118+
start: { line: 1, column: 10, offset: 9 },
119+
end: { line: 1, column: 15, offset: 14 },
120+
},
121+
},
122+
refFor: true,
123+
})
124+
expect(code).matchSnapshot()
125+
expect(code).contains('_setRef(n2, "foo", true)')
126+
})
4127
})

packages/compiler-vapor/src/compile.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -102,9 +102,9 @@ export function getBaseTransformPreset(
102102
return [
103103
[
104104
transformOnce,
105-
transformRef,
106105
transformVIf,
107106
transformVFor,
107+
transformRef,
108108
transformText,
109109
transformElement,
110110
transformComment,

packages/compiler-vapor/src/generators/ref.ts

+1
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ export function genSetRef(
1414
vaporHelper('setRef'),
1515
[`n${oper.element}`],
1616
genExpression(oper.value, context),
17+
oper.refFor && 'true',
1718
),
1819
]
1920
}

packages/compiler-vapor/src/index.ts

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ export {
3636

3737
export { transformElement } from './transforms/transformElement'
3838
export { transformChildren } from './transforms/transformChildren'
39+
export { transformRef } from './transforms/transformRef'
3940
export { transformText } from './transforms/transformText'
4041
export { transformVBind } from './transforms/vBind'
4142
export { transformVHtml } from './transforms/vHtml'

packages/compiler-vapor/src/ir.ts

+1
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,7 @@ export interface SetRefIRNode extends BaseIRNode {
138138
type: IRNodeTypes.SET_REF
139139
element: number
140140
value: SimpleExpressionNode
141+
refFor: boolean
141142
}
142143

143144
export interface SetModelValueIRNode extends BaseIRNode {

packages/compiler-vapor/src/transform.ts

+6-2
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,9 @@ export interface TransformContext<T extends AllNode = AllNode> {
7272
comment: CommentNode[]
7373

7474
inVOnce: boolean
75+
inVFor: number
7576

76-
enterBlock(ir: TransformContext['block']): () => void
77+
enterBlock(ir: TransformContext['block'], isVFor?: boolean): () => void
7778
reference(): number
7879
increaseId(): number
7980
registerTemplate(): number
@@ -122,23 +123,26 @@ function createRootContext(
122123
index: 0,
123124
root: null!, // set later
124125
block: root.block,
125-
enterBlock(ir) {
126+
enterBlock(ir, inVFor = false) {
126127
const { block, template, dynamic, childrenTemplate } = this
127128
this.block = ir
128129
this.dynamic = ir.dynamic
129130
this.template = ''
130131
this.childrenTemplate = []
132+
inVFor && this.inVFor++
131133
return () => {
132134
// exit
133135
this.block = block
134136
this.template = template
135137
this.dynamic = dynamic
136138
this.childrenTemplate = childrenTemplate
139+
inVFor && this.inVFor--
137140
}
138141
},
139142
options: extend({}, defaultOptions, options),
140143
dynamic: root.block.dynamic,
141144
inVOnce: false,
145+
inVFor: 0,
142146
comment: [],
143147

144148
increaseId: () => globalId++,

packages/compiler-vapor/src/transforms/transformRef.ts

+3
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import { EMPTY_EXPRESSION } from './utils'
1111

1212
export const transformRef: NodeTransform = (node, context) => {
1313
if (node.type !== NodeTypes.ELEMENT) return
14+
1415
const dir = findProp(node, 'ref', false, true)
1516
if (!dir) return
1617

@@ -22,10 +23,12 @@ export const transformRef: NodeTransform = (node, context) => {
2223
? createSimpleExpression(dir.value.content, true, dir.value.loc)
2324
: EMPTY_EXPRESSION
2425
}
26+
2527
return () =>
2628
context.registerOperation({
2729
type: IRNodeTypes.SET_REF,
2830
element: context.reference(),
2931
value,
32+
refFor: !!context.inVFor,
3033
})
3134
}

packages/compiler-vapor/src/transforms/vFor.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ export function processFor(
6060
operation: [],
6161
returns: [],
6262
}
63-
const exitBlock = context.enterBlock(render)
63+
const exitBlock = context.enterBlock(render, true)
6464
context.reference()
6565

6666
return () => {

0 commit comments

Comments
 (0)