exports[`compiler v-bind > .camel modifier w/ dynamic arg 1`] = `
"import { camelize as _camelize } from 'vue';
+import { template as _template, children as _children, renderEffect as _renderEffect, setDynamicProp as _setDynamicProp } from 'vue/vapor';
export function render(_ctx) {
const t0 = _template("<div></div>")
export type CodeFragment =
| typeof NEWLINE
+ | typeof LF
| typeof INDENT_START
| typeof INDENT_END
| string
}
export const NEWLINE = Symbol(__DEV__ ? `newline` : ``)
+/** increase offset but don't push actual code */
+export const LF = Symbol(__DEV__ ? `line feed` : ``)
export const INDENT_START = Symbol(__DEV__ ? `indent start` : ``)
export const INDENT_END = Symbol(__DEV__ ? `indent end` : ``)
ir: RootIRNode,
options: CodegenOptions = {},
): VaporCodegenResult {
- const ctx = new CodegenContext(ir, options)
- const { push, helpers, vaporHelpers } = ctx
+ const context = new CodegenContext(ir, options)
+ const { push, helpers, vaporHelpers } = context
const functionName = 'render'
const isSetupInlined = !!options.inline
if (isSetupInlined) {
push(`(() => {`)
} else {
- push(
- // placeholder for preamble
- NEWLINE,
- NEWLINE,
- `export function ${functionName}(_ctx) {`,
- )
+ push(NEWLINE, `export function ${functionName}(_ctx) {`)
}
push(INDENT_START)
- ir.template.forEach((template, i) => push(...genTemplate(template, i, ctx)))
- push(...genBlockFunctionContent(ir, ctx))
+ ir.template.forEach((template, i) =>
+ push(...genTemplate(template, i, context)),
+ )
+ push(...genBlockFunctionContent(ir, context))
push(INDENT_END, NEWLINE)
if (isSetupInlined) {
push('}')
}
- let preamble = ''
- if (vaporHelpers.size)
- // TODO: extract import codegen
- preamble = `import { ${[...vaporHelpers]
- .map(h => `${h} as _${h}`)
- .join(', ')} } from 'vue/vapor';`
- if (helpers.size)
- preamble = `import { ${[...helpers]
- .map(h => `${h} as _${h}`)
- .join(', ')} } from 'vue';`
+ const preamble = genHelperImports(context)
+ let codegen = genCodeFragment(context)
- let codegen = genCodeFragment(ctx)
if (!isSetupInlined) {
codegen = preamble + codegen
}
code: codegen,
ast: ir,
preamble,
- map: ctx.map ? ctx.map.toJSON() : undefined,
+ map: context.map ? context.map.toJSON() : undefined,
helpers,
vaporHelpers,
}
} else if (frag === INDENT_END) {
indentLevel--
continue
+ } else if (frag === LF) {
+ pos.line++
+ pos.column = 0
+ pos.offset++
+ continue
}
if (isString(frag)) frag = [frag]
const push = frag.push.bind(frag)
return [frag, push] as const
}
+
+function genHelperImports({ helpers, vaporHelpers, code }: CodegenContext) {
+ let imports = ''
+ if (helpers.size) {
+ code.unshift(LF)
+ imports += `import { ${[...helpers]
+ .map(h => `${h} as _${h}`)
+ .join(', ')} } from 'vue';\n`
+ }
+ if (vaporHelpers.size) {
+ code.unshift(LF)
+ imports += `import { ${[...vaporHelpers]
+ .map(h => `${h} as _${h}`)
+ .join(', ')} } from 'vue/vapor';\n`
+ }
+ return imports
+}
export function genBlockFunctionContent(
ir: BlockFunctionIRNode | RootIRNode,
- ctx: CodegenContext,
+ context: CodegenContext,
returnValue?: () => CodeFragment[],
): CodeFragment[] {
- const { vaporHelper } = ctx
+ const { vaporHelper } = context
const [frag, push] = buildCodeFragment(
NEWLINE,
`const n${ir.dynamic.id} = t${ir.templateIndex}()`,
oper.type === IRNodeTypes.WITH_DIRECTIVE,
)
for (const directives of groupDirective(directiveOps)) {
- push(...genWithDirective(directives, ctx))
+ push(...genWithDirective(directives, context))
}
- push(...genOperations(ir.operation, ctx))
- push(...genEffects(ir.effect, ctx))
+ push(...genOperations(ir.operation, context))
+ push(...genEffects(ir.effect, context))
push(
NEWLINE,
import { genSetRef } from './ref'
import { genCreateTextNode, genSetText } from './text'
-export function genOperations(opers: OperationNode[], ctx: CodegenContext) {
+export function genOperations(opers: OperationNode[], context: CodegenContext) {
const [frag, push] = buildCodeFragment()
for (const operation of opers) {
- push(...genOperation(operation, ctx))
+ push(...genOperation(operation, context))
}
return frag
}
): TransformContext<RootNode> {
let globalId = 0
- const ctx: TransformContext<RootNode> = {
+ const context: TransformContext<RootNode> = {
node,
parent: null,
index: 0,
this.block.operation.push(...node)
},
}
- ctx.root = ctx
- ctx.reference()
- return ctx
+ context.root = context
+ context.reference()
+ return context
}
function createContext<T extends TemplateChildNode>(
parent: TransformContext<ParentNode>,
index: number,
): TransformContext<T> {
- const ctx: TransformContext<T> = extend({}, parent, {
+ return extend({}, parent, {
node,
parent,
index,
template: '',
childrenTemplate: [],
dynamic: genDefaultDynamic(),
- } satisfies Partial<TransformContext<T>>)
- return ctx
+ } satisfies Partial<TransformContext<T>>) satisfies TransformContext<T>
}
// AST -> IR
operation: [],
}
- const ctx = createRootContext(ir, root, options)
+ const context = createRootContext(ir, root, options)
- transformNode(ctx)
- ctx.registerTemplate()
+ transformNode(context)
+ context.registerTemplate()
return ir
}
context.template += context.childrenTemplate.filter(Boolean).join('')
}
-function transformChildren(ctx: TransformContext<RootNode | ElementNode>) {
- const { children } = ctx.node
+function transformChildren(context: TransformContext<RootNode | ElementNode>) {
+ const { children } = context.node
for (const [i, child] of children.entries()) {
- const childContext = createContext(child, ctx, i)
+ const childContext = createContext(child, context, i)
transformNode(childContext)
- ctx.childrenTemplate.push(childContext.template)
- ctx.dynamic.children[i] = childContext.dynamic
+ context.childrenTemplate.push(childContext.template)
+ context.dynamic.children[i] = childContext.dynamic
}
- processDynamicChildren(ctx)
+ processDynamicChildren(context)
}
function processDynamicChildren(
import type { NodeTransform, TransformContext } from '../transform'
import { IRNodeTypes, type VaporDirectiveNode } from '../ir'
-export const transformElement: NodeTransform = (node, ctx) => {
+export const transformElement: NodeTransform = (node, context) => {
return function postTransformElement() {
- node = ctx.node
+ node = context.node
if (
!(
const { tag, props } = node
const isComponent = node.tagType === ElementTypes.COMPONENT
- ctx.template += `<${tag}`
+ context.template += `<${tag}`
if (props.length) {
buildProps(
node,
- ctx as TransformContext<ElementNode>,
+ context as TransformContext<ElementNode>,
undefined,
isComponent,
)
}
- ctx.template += `>` + ctx.childrenTemplate.join('')
+ context.template += `>` + context.childrenTemplate.join('')
// TODO remove unnecessary close tag, e.g. if it's the last element of the template
if (!isVoidTag(tag)) {
- ctx.template += `</${tag}>`
+ context.template += `</${tag}>`
}
}
}
import type { NodeTransform } from '../transform'
import { DynamicFlag, IRNodeTypes } from '../ir'
-export const transformInterpolation: NodeTransform = (node, ctx) => {
+export const transformInterpolation: NodeTransform = (node, context) => {
if (node.type !== NodeTypes.INTERPOLATION) return
const expr = node.content as SimpleExpressionNode
- const parentChildren = ctx.parent ? ctx.parent.node.children : []
- const isFirst = ctx.index === 0
- const isLast = ctx.index === parentChildren.length - 1
- const isRoot = ctx.parent === ctx.root
+ const parentChildren = context.parent ? context.parent.node.children : []
+ const isFirst = context.index === 0
+ const isLast = context.index === parentChildren.length - 1
+ const isRoot = context.parent === context.root
if (isFirst && isLast && !isRoot) {
- const parent = ctx.parent!
+ const parent = context.parent!
const parentId = parent.reference()
- ctx.registerEffect(
+ context.registerEffect(
[expr],
[
{
],
)
} else {
- const id = ctx.reference()
- ctx.dynamic.flags |= DynamicFlag.INSERT | DynamicFlag.NON_TEMPLATE
- ctx.registerOperation({
+ const id = context.reference()
+ context.dynamic.flags |= DynamicFlag.INSERT | DynamicFlag.NON_TEMPLATE
+ context.registerOperation({
type: IRNodeTypes.CREATE_TEXT_NODE,
id,
})
- ctx.registerEffect(
+ context.registerEffect(
[expr],
[
{