Skip to content

Commit

Permalink
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(compiler): v-if
Browse files Browse the repository at this point in the history
LittleSound authored and sxzz committed Jan 21, 2024

Verified

This commit was signed with the committer’s verified signature. The key has expired.
Urhengulas Johann Hemmann
1 parent 32604cf commit 08fc9e9
Showing 7 changed files with 300 additions and 69 deletions.
9 changes: 8 additions & 1 deletion packages/compiler-vapor/src/compile.ts
Original file line number Diff line number Diff line change
@@ -25,6 +25,7 @@ import { transformRef } from './transforms/transformRef'
import { transformInterpolation } from './transforms/transformInterpolation'
import type { HackOptions } from './ir'
import { transformVModel } from './transforms/vModel'
import { transformIf } from './transforms/vIf'

export type CompilerOptions = HackOptions<BaseCompilerOptions>

@@ -97,7 +98,13 @@ export function getBaseTransformPreset(
prefixIdentifiers?: boolean,
): TransformPreset {
return [
[transformOnce, transformRef, transformInterpolation, transformElement],
[
transformOnce,
transformRef,
transformInterpolation,
transformIf,
transformElement,
],
{
bind: transformVBind,
on: transformVOn,
78 changes: 43 additions & 35 deletions packages/compiler-vapor/src/generate.ts
Original file line number Diff line number Diff line change
@@ -8,6 +8,7 @@ import {
locStub,
} from '@vue/compiler-dom'
import {
type BlockFunctionIRNode,
type IRDynamicChildren,
IRNodeTypes,
type OperationNode,
@@ -26,6 +27,7 @@ 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'

interface CodegenOptions extends BaseCodegenOptions {
expressionPlugins?: ParserPlugin[]
@@ -271,41 +273,7 @@ export function generate(
}
})

{
pushNewline(`const n${ir.dynamic.id} = t0()`)

const children = genChildren(ir.dynamic.children)
if (children) {
pushNewline(
`const ${children} = ${vaporHelper('children')}(n${ir.dynamic.id})`,
)
}

for (const oper of ir.operation.filter(
(oper): oper is WithDirectiveIRNode =>
oper.type === IRNodeTypes.WITH_DIRECTIVE,
)) {
genWithDirective(oper, ctx)
}

for (const operation of ir.operation) {
genOperation(operation, ctx)
}

for (const { operations } of ir.effect) {
pushNewline(`${vaporHelper('renderEffect')}(() => {`)
withIndent(() => {
for (const operation of operations) {
genOperation(operation, ctx)
}
})
pushNewline('})')
}

// TODO multiple-template
// TODO return statement in IR
pushNewline(`return n${ir.dynamic.id}`)
}
genBlockFunctionContent(ir, ctx)
})

newline()
@@ -386,10 +354,50 @@ function genOperation(oper: OperationNode, context: CodegenContext) {
return genPrependNode(oper, context)
case IRNodeTypes.APPEND_NODE:
return genAppendNode(oper, context)
case IRNodeTypes.IF:
return genIf(oper, context)
case IRNodeTypes.WITH_DIRECTIVE:
// generated, skip
return
default:
return checkNever(oper)
}
}

export function genBlockFunctionContent(
ir: Omit<BlockFunctionIRNode, 'type'>,
ctx: CodegenContext,
) {
const { pushNewline, withIndent, vaporHelper } = ctx
pushNewline(`const n${ir.dynamic.id} = t${ir.templateIndex}()`)

const children = genChildren(ir.dynamic.children)
if (children) {
pushNewline(
`const ${children} = ${vaporHelper('children')}(n${ir.dynamic.id})`,
)
}

for (const oper of ir.operation.filter(
(oper): oper is WithDirectiveIRNode =>
oper.type === IRNodeTypes.WITH_DIRECTIVE,
)) {
genWithDirective(oper, ctx)
}

for (const operation of ir.operation) {
genOperation(operation, ctx)
}

for (const { operations } of ir.effect) {
pushNewline(`${vaporHelper('renderEffect')}(() => {`)
withIndent(() => {
for (const operation of operations) {
genOperation(operation, ctx)
}
})
pushNewline('})')
}

pushNewline(`return n${ir.dynamic.id}`)
}
32 changes: 32 additions & 0 deletions packages/compiler-vapor/src/generators/if.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { type CodegenContext, genBlockFunctionContent } from '../generate'
import type { BlockFunctionIRNode, IfIRNode } from '../ir'
import { genExpression } from './expression'

export function genIf(oper: IfIRNode, context: CodegenContext) {
const { pushFnCall, vaporHelper, pushNewline, push } = context
const { condition, truthyBranch, falsyBranch } = oper

pushNewline(`const n${oper.id} = `)
pushFnCall(
vaporHelper('createIf'),
() => {
push('() => (')
genExpression(condition, context)
push(')')
},
() => genBlockFunction(truthyBranch, context),
!!falsyBranch && (() => genBlockFunction(falsyBranch!, context)),
)
}

export function genBlockFunction(
oper: Omit<BlockFunctionIRNode, 'type'>,
context: CodegenContext,
) {
const { push, pushNewline, withIndent } = context
push('() => {')
withIndent(() => {
genBlockFunctionContent(oper, context)
})
pushNewline('}')
}
27 changes: 23 additions & 4 deletions packages/compiler-vapor/src/ir.ts
Original file line number Diff line number Diff line change
@@ -5,6 +5,7 @@ import type {
RootNode,
SimpleExpressionNode,
SourceLocation,
TemplateChildNode,
} from '@vue/compiler-dom'
import type { Prettify } from '@vue/shared'
import type { DirectiveTransform, NodeTransform } from './transform'
@@ -27,6 +28,9 @@ export enum IRNodeTypes {
CREATE_TEXT_NODE,

WITH_DIRECTIVE,

IF,
BLOCK_FUNCTION,
}

export interface BaseIRNode {
@@ -37,18 +41,32 @@ export interface BaseIRNode {
// TODO refactor
export type VaporHelper = keyof typeof import('../../runtime-vapor/src')

export interface RootIRNode extends BaseIRNode {
type: IRNodeTypes.ROOT
export interface BlockFunctionIRNode extends BaseIRNode {
type: IRNodeTypes.BLOCK_FUNCTION
source: string
node: RootNode
template: Array<TemplateFactoryIRNode | FragmentFactoryIRNode>
node: RootNode | TemplateChildNode
templateIndex: number
dynamic: IRDynamicInfo
effect: IREffect[]
operation: OperationNode[]
}

export interface RootIRNode extends Omit<BlockFunctionIRNode, 'type'> {
type: IRNodeTypes.ROOT
node: RootNode
template: Array<TemplateFactoryIRNode | FragmentFactoryIRNode>
helpers: Set<string>
vaporHelpers: Set<VaporHelper>
}

export interface IfIRNode extends BaseIRNode {
type: IRNodeTypes.IF
id: number
condition: IRExpression
truthyBranch: BlockFunctionIRNode
falsyBranch?: BlockFunctionIRNode
}

export interface TemplateFactoryIRNode extends BaseIRNode {
type: IRNodeTypes.TEMPLATE_FACTORY
template: string
@@ -160,6 +178,7 @@ export type OperationNode =
| PrependNodeIRNode
| AppendNodeIRNode
| WithDirectiveIRNode
| IfIRNode

export interface IRDynamicInfo {
id: number | null
Loading

0 comments on commit 08fc9e9

Please sign in to comment.