diff --git a/packages/compiler-vapor/src/generate.ts b/packages/compiler-vapor/src/generate.ts index f9c39c428..1b26c7a02 100644 --- a/packages/compiler-vapor/src/generate.ts +++ b/packages/compiler-vapor/src/generate.ts @@ -8,14 +8,10 @@ import { locStub, } from '@vue/compiler-dom' import { - type BlockFunctionIRNode, - DynamicFlag, - type IRDynamicInfo, IRNodeTypes, type OperationNode, type RootIRNode, type VaporHelper, - type WithDirectiveIRNode, } from './ir' import { SourceMapGenerator } from 'source-map-js' import { extend, isString } from '@vue/shared' @@ -27,18 +23,14 @@ import { genSetHtml } from './generators/html' import { genSetRef } from './generators/ref' import { genSetModelValue } from './generators/modelValue' import { genAppendNode, genInsertNode, genPrependNode } from './generators/dom' -import { genWithDirective } from './generators/directive' import { genIf } from './generators/if' import { genTemplate } from './generators/template' +import { genBlockFunctionContent } from './generators/block' interface CodegenOptions extends BaseCodegenOptions { expressionPlugins?: ParserPlugin[] } -// remove when stable -// @ts-expect-error -function checkNever(x: never): never {} - export type CodeFragment = | string | [code: string, newlineIndex?: number, loc?: SourceLocation, name?: string] @@ -275,37 +267,13 @@ function genCodeFragment(context: CodegenContext) { } } -function genChildren(children: IRDynamicInfo[]) { - let code = '' - let offset = 0 - - for (const [index, child] of children.entries()) { - if (child.flags & DynamicFlag.NON_TEMPLATE) { - offset-- - } - - const idx = Number(index) + offset - const id = - child.flags & DynamicFlag.REFERENCED - ? child.flags & DynamicFlag.INSERT - ? child.anchor - : child.id - : null - const childrenString = genChildren(child.children) - - if (id !== null || childrenString) { - code += ` ${idx}: [` - if (id !== null) code += `n${id}` - if (childrenString) code += `, ${childrenString}` - code += '],' - } - } - - if (!code) return '' - return `{${code}}` +export function buildCodeFragment() { + const frag: CodeFragment[] = [] + const push = frag.push.bind(frag) + return [frag, push] as const } -function genOperation( +export function genOperation( oper: OperationNode, context: CodegenContext, ): CodeFragment[] { @@ -343,59 +311,6 @@ function genOperation( return [] } -export function buildCodeFragment() { - const frag: CodeFragment[] = [] - const push = frag.push.bind(frag) - return [frag, push] as const -} - -export function genBlockFunctionContent( - ir: BlockFunctionIRNode | RootIRNode, - ctx: CodegenContext, -): CodeFragment[] { - const { newline, withIndent, vaporHelper } = ctx - const [frag, push] = buildCodeFragment() - - push(newline(), `const n${ir.dynamic.id} = t${ir.templateIndex}()`) - - const children = genChildren(ir.dynamic.children) - if (children) { - push( - newline(), - `const ${children} = ${vaporHelper('children')}(n${ir.dynamic.id})`, - ) - } - - const directiveOps = ir.operation.filter( - (oper): oper is WithDirectiveIRNode => - oper.type === IRNodeTypes.WITH_DIRECTIVE, - ) - for (const directives of groupDirective(directiveOps)) { - push(...genWithDirective(directives, ctx)) - } - - for (const operation of ir.operation) { - push(...genOperation(operation, ctx)) - } - - for (const { operations } of ir.effect) { - push(newline(), `${vaporHelper('renderEffect')}(() => {`) - withIndent(() => { - operations.forEach(op => push(...genOperation(op, ctx))) - }) - push(newline(), '})') - } - - push(newline(), `return n${ir.dynamic.id}`) - - return frag -} - -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) -} +// remove when stable +// @ts-expect-error +function checkNever(x: never): never {} diff --git a/packages/compiler-vapor/src/generators/block.ts b/packages/compiler-vapor/src/generators/block.ts new file mode 100644 index 000000000..bc0ecc840 --- /dev/null +++ b/packages/compiler-vapor/src/generators/block.ts @@ -0,0 +1,109 @@ +import { + type BlockFunctionIRNode, + DynamicFlag, + type IRDynamicInfo, + IRNodeTypes, + type RootIRNode, + type WithDirectiveIRNode, +} from '../ir' +import { + type CodeFragment, + type CodegenContext, + buildCodeFragment, + genOperation, +} from '../generate' +import { genWithDirective } from './directive' + +export function genBlockFunction( + oper: BlockFunctionIRNode, + context: CodegenContext, +): CodeFragment[] { + const { newline, withIndent } = context + return [ + '() => {', + ...withIndent(() => genBlockFunctionContent(oper, context)), + newline(), + '}', + ] +} + +export function genBlockFunctionContent( + ir: BlockFunctionIRNode | RootIRNode, + ctx: CodegenContext, +): CodeFragment[] { + const { newline, withIndent, vaporHelper } = ctx + const [frag, push] = buildCodeFragment() + + push(newline(), `const n${ir.dynamic.id} = t${ir.templateIndex}()`) + + const children = genChildren(ir.dynamic.children) + if (children) { + push( + newline(), + `const ${children} = ${vaporHelper('children')}(n${ir.dynamic.id})`, + ) + } + + const directiveOps = ir.operation.filter( + (oper): oper is WithDirectiveIRNode => + oper.type === IRNodeTypes.WITH_DIRECTIVE, + ) + for (const directives of groupDirective(directiveOps)) { + push(...genWithDirective(directives, ctx)) + } + + for (const operation of ir.operation) { + push(...genOperation(operation, ctx)) + } + + for (const { operations } of ir.effect) { + push(newline(), `${vaporHelper('renderEffect')}(() => {`) + withIndent(() => { + operations.forEach(op => push(...genOperation(op, ctx))) + }) + push(newline(), '})') + } + + push(newline(), `return n${ir.dynamic.id}`) + + return frag +} + +function genChildren(children: IRDynamicInfo[]) { + let code = '' + let offset = 0 + + for (const [index, child] of children.entries()) { + if (child.flags & DynamicFlag.NON_TEMPLATE) { + offset-- + } + + const idx = Number(index) + offset + const id = + child.flags & DynamicFlag.REFERENCED + ? child.flags & DynamicFlag.INSERT + ? child.anchor + : child.id + : null + const childrenString = genChildren(child.children) + + if (id !== null || childrenString) { + code += ` ${idx}: [` + if (id !== null) code += `n${id}` + if (childrenString) code += `, ${childrenString}` + code += '],' + } + } + + if (!code) return '' + return `{${code}}` +} + +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/if.ts b/packages/compiler-vapor/src/generators/if.ts index 69848b424..7c3eeb6c6 100644 --- a/packages/compiler-vapor/src/generators/if.ts +++ b/packages/compiler-vapor/src/generators/if.ts @@ -2,9 +2,9 @@ import { type CodeFragment, type CodegenContext, buildCodeFragment, - genBlockFunctionContent, } from '../generate' -import { type BlockFunctionIRNode, IRNodeTypes, type IfIRNode } from '../ir' +import { IRNodeTypes, type IfIRNode } from '../ir' +import { genBlockFunction } from './block' import { genExpression } from './expression' export function genIf( @@ -40,16 +40,3 @@ export function genIf( return frag } - -function genBlockFunction( - oper: BlockFunctionIRNode, - context: CodegenContext, -): CodeFragment[] { - const { newline, withIndent } = context - return [ - '() => {', - ...withIndent(() => genBlockFunctionContent(oper, context)), - newline(), - '}', - ] -} diff --git a/packages/compiler-vapor/src/transforms/vIf.ts b/packages/compiler-vapor/src/transforms/vIf.ts index 3628ad7fe..03bb22b15 100644 --- a/packages/compiler-vapor/src/transforms/vIf.ts +++ b/packages/compiler-vapor/src/transforms/vIf.ts @@ -3,7 +3,6 @@ import { ElementTypes, ErrorCodes, NodeTypes, - type RootNode, type TemplateChildNode, type TemplateNode, createCompilerError, @@ -32,7 +31,7 @@ export const transformVIf = createStructuralDirectiveTransform( export function processIf( node: ElementNode, dir: VaporDirectiveNode, - context: TransformContext, + context: TransformContext, ) { if (dir.name !== 'else' && (!dir.exp || !dir.exp.content.trim())) { const loc = dir.exp ? dir.exp.loc : node.loc @@ -144,7 +143,7 @@ export function processIf( export function createIfBranch( node: ElementNode, - context: TransformContext, + context: TransformContext, ): [BlockFunctionIRNode, () => void] { context.node = node = wrapTemplate(node)