refactor(compiler-vapor): add placeholder for optional argument

This commit is contained in:
三咲智子 Kevin Deng 2024-05-13 01:35:35 +08:00
parent 72589be6aa
commit 30f98942db
No known key found for this signature in database
10 changed files with 73 additions and 63 deletions

View File

@ -13,8 +13,8 @@ import {
LF,
NEWLINE,
buildCodeFragment,
codeFragmentToString,
genCall,
genCodeFragment,
} from './generators/utils'
export type CodegenOptions = Omit<BaseCodegenOptions, 'optimizeImports'>
@ -132,7 +132,7 @@ export function generate(
frag.unshift(...new Array<CodeFragment>(newlineCount).fill(LF))
}
let [code, map] = genCodeFragment(frag, context)
let [code, map] = codeFragmentToString(frag, context)
if (!inline) {
code = preamble + code
}

View File

@ -1,10 +1,10 @@
import type { BlockIRNode } from '../ir'
import {
type CodeFragment,
DELIMITERS_ARRAY,
INDENT_END,
INDENT_START,
NEWLINE,
SEGMENTS_ARRAY,
buildCodeFragment,
genCall,
genMulti,
@ -71,7 +71,7 @@ export function genBlockContent(
const returnNodes = returns.map(n => `n${n}`)
const returnsCode: CodeFragment[] =
returnNodes.length > 1
? genMulti(SEGMENTS_ARRAY, ...returnNodes)
? genMulti(DELIMITERS_ARRAY, ...returnNodes)
: [returnNodes[0] || 'null']
push(...(customReturns ? customReturns(returnsCode) : returnsCode))

View File

@ -11,11 +11,11 @@ import {
} from '../ir'
import {
type CodeFragment,
DELIMITERS_ARRAY,
DELIMITERS_ARRAY_NEWLINE,
DELIMITERS_OBJECT,
DELIMITERS_OBJECT_NEWLINE,
NEWLINE,
SEGMENTS_ARRAY,
SEGMENTS_ARRAY_NEWLINE,
SEGMENTS_OBJECT,
SEGMENTS_OBJECT_NEWLINE,
genCall,
genMulti,
} from './utils'
@ -43,13 +43,9 @@ export function genCreateComponent(
...genCall(
vaporHelper('createComponent'),
tag,
rawProps || (slots || dynamicSlots || root ? 'null' : false),
slots ? genSlots(slots, context) : dynamicSlots || root ? 'null' : false,
dynamicSlots
? genDynamicSlots(dynamicSlots, context)
: root
? 'null'
: false,
rawProps,
slots && genSlots(slots, context),
dynamicSlots && genDynamicSlots(dynamicSlots, context),
root && 'true',
),
...genDirectivesForElement(oper.id, context),
@ -77,7 +73,7 @@ export function genRawProps(props: IRProps[], context: CodegenContext) {
} else {
let expr: CodeFragment[]
if (props.kind === IRDynamicPropsKind.ATTRIBUTE)
expr = genMulti(SEGMENTS_OBJECT, genProp(props, context))
expr = genMulti(DELIMITERS_OBJECT, genProp(props, context))
else {
expr = genExpression(props.value, context)
if (props.handler) expr = genCall(vaporHelper('toHandlers'), expr)
@ -89,7 +85,7 @@ export function genRawProps(props: IRProps[], context: CodegenContext) {
Boolean as any as (v: CodeFragment[] | undefined) => v is CodeFragment[],
)
if (frag.length) {
return genMulti(SEGMENTS_ARRAY_NEWLINE, ...frag)
return genMulti(DELIMITERS_ARRAY_NEWLINE, ...frag)
}
}
@ -98,7 +94,7 @@ function genStaticProps(
context: CodegenContext,
): CodeFragment[] {
return genMulti(
props.length > 1 ? SEGMENTS_OBJECT_NEWLINE : SEGMENTS_OBJECT,
props.length > 1 ? DELIMITERS_OBJECT_NEWLINE : DELIMITERS_OBJECT,
...props.map(prop => genProp(prop, context, true)),
)
}
@ -147,7 +143,7 @@ function genModelModifiers(
function genSlots(slots: ComponentSlots, context: CodegenContext) {
const slotList = Object.entries(slots)
return genMulti(
slotList.length > 1 ? SEGMENTS_OBJECT_NEWLINE : SEGMENTS_OBJECT,
slotList.length > 1 ? DELIMITERS_OBJECT_NEWLINE : DELIMITERS_OBJECT,
...slotList.map(([name, slot]) => [name, ': ', ...genBlock(slot, context)]),
)
}
@ -157,10 +153,10 @@ function genDynamicSlots(
context: CodegenContext,
) {
const slotsExpr = genMulti(
dynamicSlots.length > 1 ? SEGMENTS_ARRAY_NEWLINE : SEGMENTS_ARRAY,
dynamicSlots.length > 1 ? DELIMITERS_ARRAY_NEWLINE : DELIMITERS_ARRAY,
...dynamicSlots.map(({ name, fn }) =>
genMulti(
SEGMENTS_OBJECT_NEWLINE,
DELIMITERS_OBJECT_NEWLINE,
['name: ', ...genExpression(name, context)],
['fn: ', ...genBlock(fn, context)],
),

View File

@ -4,8 +4,9 @@ import { genExpression } from './expression'
import type { CodegenContext } from '../generate'
import {
type CodeFragment,
type CodeFragmentDelimiters,
DELIMITERS_ARRAY,
NEWLINE,
SEGMENTS_ARRAY,
genCall,
genMulti,
} from './utils'
@ -28,7 +29,7 @@ export function genWithDirective(
const element = `n${opers[0].element}`
const directiveItems = opers.map(genDirective)
const directives = genMulti(SEGMENTS_ARRAY, ...directiveItems)
const directives = genMulti(DELIMITERS_ARRAY, ...directiveItems)
return [
NEWLINE,
@ -36,24 +37,22 @@ export function genWithDirective(
]
function genDirective({ dir, builtin }: WithDirectiveIRNode): CodeFragment[] {
const NULL = 'void 0'
const directive = genDirective()
const value = dir.exp
? ['() => ', ...genExpression(dir.exp, context)]
: dir.arg || dir.modifiers.length
? NULL
: false
const argument = dir.arg
? genExpression(dir.arg, context)
: dir.modifiers.length
? NULL
: false
const modifiers = dir.modifiers.length
? ['{ ', genDirectiveModifiers(dir.modifiers), ' }']
: false
const value = dir.exp && ['() => ', ...genExpression(dir.exp, context)]
const argument = dir.arg && genExpression(dir.arg, context)
const modifiers = !!dir.modifiers.length && [
'{ ',
genDirectiveModifiers(dir.modifiers),
' }',
]
return genMulti(SEGMENTS_ARRAY, directive, value, argument, modifiers)
return genMulti(
DELIMITERS_ARRAY.concat('void 0') as CodeFragmentDelimiters,
directive,
value,
argument,
modifiers,
)
function genDirective() {
const {

View File

@ -8,8 +8,8 @@ import type { SetDynamicEventsIRNode, SetEventIRNode } from '../ir'
import { genExpression } from './expression'
import {
type CodeFragment,
DELIMITERS_OBJECT_NEWLINE,
NEWLINE,
SEGMENTS_OBJECT_NEWLINE,
genCall,
genMulti,
} from './utils'
@ -59,7 +59,7 @@ export function genSetEvent(
if (!options.length && !nonKeys.length && !keys.length && !effect) return
return genMulti(
SEGMENTS_OBJECT_NEWLINE,
DELIMITERS_OBJECT_NEWLINE,
!!nonKeys.length && ['modifiers: ', genArrayExpression(nonKeys)],
!!keys.length && ['keys: ', genArrayExpression(keys)],
effect && ['effect: true'],

View File

@ -36,7 +36,7 @@ export function genIf(
vaporHelper('createIf'),
conditionExpr,
positiveArg,
negativeArg || (once ? 'null' : false),
negativeArg,
once && 'true',
),
)

View File

@ -14,9 +14,9 @@ import {
import { genExpression } from './expression'
import {
type CodeFragment,
DELIMITERS_ARRAY,
DELIMITERS_OBJECT,
NEWLINE,
SEGMENTS_ARRAY,
SEGMENTS_OBJECT,
genCall,
genMulti,
} from './utils'
@ -51,7 +51,7 @@ export function genSetProp(
return [
NEWLINE,
...genCall(
vaporHelper(helperName),
[vaporHelper(helperName), null],
`n${oper.element}`,
omitKey ? false : genExpression(key, context),
genPropValue(values, context),
@ -87,7 +87,7 @@ function genLiteralObjectProps(
context: CodegenContext,
): CodeFragment[] {
return genMulti(
SEGMENTS_OBJECT,
DELIMITERS_OBJECT,
...props.map(prop => [
...genPropKey(prop, context),
`: `,
@ -130,7 +130,7 @@ function genPropValue(values: SimpleExpressionNode[], context: CodegenContext) {
return genExpression(values[0], context)
}
return genMulti(
SEGMENTS_ARRAY,
DELIMITERS_ARRAY,
...values.map(expr => genExpression(expr, context)),
)
}

View File

@ -3,8 +3,8 @@ import type { CreateTextNodeIRNode, SetTextIRNode } from '../ir'
import { genExpression } from './expression'
import {
type CodeFragment,
DELIMITERS_ARRAY,
NEWLINE,
SEGMENTS_ARRAY,
genCall,
genMulti,
} from './utils'
@ -37,7 +37,7 @@ export function genCreateTextNode(
...genCall(vaporHelper('createTextNode'), [
effect && '() => ',
...genMulti(
SEGMENTS_ARRAY,
DELIMITERS_ARRAY,
...values.map(value => genExpression(value, context)),
),
]),

View File

@ -27,22 +27,34 @@ export type CodeFragment =
| FalsyValue
export type CodeFragments = Exclude<CodeFragment, any[]> | CodeFragment[]
export function buildCodeFragment(...frag: CodeFragment[]) {
export function buildCodeFragment(
...frag: CodeFragment[]
): [CodeFragment[], (...items: CodeFragment[]) => number] {
const push = frag.push.bind(frag)
return [frag, push] as const
return [frag, push]
}
type Segments = [
export type CodeFragmentDelimiters = [
left: CodeFragments,
right: CodeFragments,
segment: CodeFragments,
delimiter: CodeFragments,
placeholder?: CodeFragments,
]
export function genMulti(
[left, right, seg]: Segments,
[left, right, seg, placeholder]: CodeFragmentDelimiters,
...frags: CodeFragments[]
): CodeFragment[] {
if (placeholder) {
while (!frags[frags.length - 1]) {
frags.pop()
}
frags = frags.map(frag => frag || placeholder)
} else {
frags = frags.filter(Boolean)
}
const frag: CodeFragment[] = []
frags = frags.filter(Boolean)
push(left)
for (let [i, fn] of (
frags as Array<Exclude<CodeFragments, FalsyValue>>
@ -58,27 +70,30 @@ export function genMulti(
frag.push(...fn)
}
}
export const SEGMENTS_ARRAY: Segments = ['[', ']', ', ']
export const SEGMENTS_ARRAY_NEWLINE: Segments = [
export const DELIMITERS_ARRAY: CodeFragmentDelimiters = ['[', ']', ', ']
export const DELIMITERS_ARRAY_NEWLINE: CodeFragmentDelimiters = [
['[', INDENT_START, NEWLINE],
[INDENT_END, NEWLINE, ']'],
[', ', NEWLINE],
]
export const SEGMENTS_OBJECT: Segments = ['{ ', ' }', ', ']
export const SEGMENTS_OBJECT_NEWLINE: Segments = [
export const DELIMITERS_OBJECT: CodeFragmentDelimiters = ['{ ', ' }', ', ']
export const DELIMITERS_OBJECT_NEWLINE: CodeFragmentDelimiters = [
['{', INDENT_START, NEWLINE],
[INDENT_END, NEWLINE, '}'],
[', ', NEWLINE],
]
export function genCall(
name: string,
name: string | [name: string, placeholder?: CodeFragments],
...frags: CodeFragments[]
): CodeFragment[] {
return [name, ...genMulti(['(', ')', ', '], ...frags)]
const hasPlaceholder = isArray(name)
const fnName = hasPlaceholder ? name[0] : name
const placeholder = hasPlaceholder ? name[1] : 'null'
return [fnName, ...genMulti(['(', ')', ', ', placeholder], ...frags)]
}
export function genCodeFragment(
export function codeFragmentToString(
code: CodeFragment[],
context: CodegenContext,
): [code: string, map: CodegenSourceMapGenerator | undefined] {

View File

@ -17,7 +17,7 @@ export {
genCall,
genMulti,
buildCodeFragment,
genCodeFragment,
codeFragmentToString,
type CodeFragment,
} from './generators/utils'
export {