diff --git a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap index 2ce2fddd0..8de407e75 100644 --- a/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap +++ b/packages/compiler-vapor/__tests__/__snapshots__/compile.spec.ts.snap @@ -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("
") + 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'; diff --git a/packages/compiler-vapor/__tests__/compile.spec.ts b/packages/compiler-vapor/__tests__/compile.spec.ts index a16b81655..23ba98882 100644 --- a/packages/compiler-vapor/__tests__/compile.spec.ts +++ b/packages/compiler-vapor/__tests__/compile.spec.ts @@ -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(`
`) + expect(code).matchSnapshot() + }) + }) }) diff --git a/packages/compiler-vapor/src/generate.ts b/packages/compiler-vapor/src/generate.ts index bba27e325..4022c5a6c 100644 --- a/packages/compiler-vapor/src/generate.ts +++ b/packages/compiler-vapor/src/generate.ts @@ -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 = {} + for (const oper of ops) { + if (!directiveMap[oper.element]) directiveMap[oper.element] = [] + directiveMap[oper.element].push(oper) + } + return Object.values(directiveMap) +} diff --git a/packages/compiler-vapor/src/generators/directive.ts b/packages/compiler-vapor/src/generators/directive.ts index 4b54bc5b7..0092f9ed1 100644 --- a/packages/compiler-vapor/src/generators/directive.ts +++ b/packages/compiler-vapor/src/generators/directive.ts @@ -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(']') + }), + ) }, ) }