refactor(compiler-vapor): group directives by same element

This commit is contained in:
三咲智子 Kevin Deng 2024-01-27 20:49:43 +08:00
parent 0255505b5d
commit c2c8070207
No known key found for this signature in database
GPG Key ID: 69992F2250DFD93E
4 changed files with 77 additions and 42 deletions

View File

@ -16,6 +16,18 @@ export function render(_ctx) {
}"
`;
exports[`compile > custom directive > basic 1`] = `
"import { template as _template, children as _children, withDirectives as _withDirectives, resolveDirective("vTest") as _resolveDirective("vTest"), resolveDirective("vHello") as _resolveDirective("vHello") } from 'vue/vapor';
export function render(_ctx) {
const t0 = _template("<div></div>")
const n0 = t0()
const { 0: [n1],} = _children(n0)
_withDirectives(n1, [[_resolveDirective("vTest")], [_resolveDirective("vHello"), void 0, void 0, { world: true }]])
return n0
}"
`;
exports[`compile > directives > custom directive > basic 1`] = `
"import { template as _template, children as _children, withDirectives as _withDirectives } from 'vue/vapor';

View File

@ -207,4 +207,11 @@ describe('compile', () => {
// TODO: add more test for expression parsing (v-on, v-slot, v-for)
})
describe('custom directive', () => {
test('basic', () => {
const code = compile(`<div v-test v-hello.world />`)
expect(code).matchSnapshot()
})
})
})

View File

@ -281,11 +281,12 @@ export function generate(
)
}
for (const oper of ir.operation.filter(
const directiveOps = ir.operation.filter(
(oper): oper is WithDirectiveIRNode =>
oper.type === IRNodeTypes.WITH_DIRECTIVE,
)) {
genWithDirective(oper, ctx)
)
for (const directives of groupDirective(directiveOps)) {
genWithDirective(directives, ctx)
}
for (const operation of ir.operation) {
@ -393,3 +394,12 @@ function genOperation(oper: OperationNode, context: CodegenContext) {
return checkNever(oper)
}
}
function groupDirective(ops: WithDirectiveIRNode[]): WithDirectiveIRNode[][] {
const directiveMap: Record<number, WithDirectiveIRNode[]> = {}
for (const oper of ops) {
if (!directiveMap[oper.element]) directiveMap[oper.element] = []
directiveMap[oper.element].push(oper)
}
return Object.values(directiveMap)
}

View File

@ -5,61 +5,67 @@ import type { CodegenContext } from '../generate'
import type { WithDirectiveIRNode } from '../ir'
export function genWithDirective(
oper: WithDirectiveIRNode,
opers: WithDirectiveIRNode[],
context: CodegenContext,
) {
const { push, newline, pushFnCall, pushMulti, vaporHelper, bindingMetadata } =
context
const { dir, builtin } = oper
// TODO merge directive for the same node
newline()
pushFnCall(
vaporHelper('withDirectives'),
// 1st arg: node
`n${oper.element}`,
`n${opers[0].element}`,
// 2nd arg: directives
() => {
push('[')
// directive
pushMulti(['[', ']', ', '], () => {
if (dir.name === 'show') {
push(vaporHelper('vShow'))
} else if (builtin) {
push(vaporHelper(builtin))
} else {
const directiveReference = camelize(`v-${dir.name}`)
// TODO resolve directive
if (bindingMetadata[directiveReference]) {
const directiveExpression =
createSimpleExpression(directiveReference)
directiveExpression.ast = null
genExpression(directiveExpression, context)
pushMulti(
['[', ']', ', '],
...opers.map((oper) => () => {
push('[')
const { dir, builtin } = oper
if (dir.name === 'show') {
push(vaporHelper('vShow'))
} else if (builtin) {
push(vaporHelper(builtin))
} else {
const directiveReference = camelize(`v-${dir.name}`)
// TODO resolve directive
if (bindingMetadata[directiveReference]) {
const directiveExpression =
createSimpleExpression(directiveReference)
directiveExpression.ast = null
genExpression(directiveExpression, context)
} else {
push(vaporHelper(`resolveDirective("${directiveReference}")`))
}
}
}
if (dir.exp) {
push(', () => ')
genExpression(dir.exp, context)
} else if (dir.arg || dir.modifiers.length) {
push(', void 0')
}
if (dir.exp) {
push(', () => ')
genExpression(dir.exp, context)
} else if (dir.arg || dir.modifiers.length) {
push(', void 0')
}
if (dir.arg) {
push(', ')
genExpression(dir.arg, context)
} else if (dir.modifiers.length) {
push(', void 0')
}
if (dir.arg) {
push(', ')
genExpression(dir.arg, context)
} else if (dir.modifiers.length) {
push(', void 0')
}
if (dir.modifiers.length) {
push(', ')
push('{ ')
push(genDirectiveModifiers(dir.modifiers))
push(' }')
}
})
push(']')
if (dir.modifiers.length) {
push(', ')
push('{ ')
push(genDirectiveModifiers(dir.modifiers))
push(' }')
}
push(']')
}),
)
},
)
}