refactor: improve vSlot.ts readability
This commit is contained in:
parent
35cb3700b8
commit
f401ac6b88
@ -19,7 +19,7 @@ import {
|
|||||||
} from '../ast'
|
} from '../ast'
|
||||||
import { TransformContext, NodeTransform } from '../transform'
|
import { TransformContext, NodeTransform } from '../transform'
|
||||||
import { createCompilerError, ErrorCodes } from '../errors'
|
import { createCompilerError, ErrorCodes } from '../errors'
|
||||||
import { mergeExpressions, findNonEmptyDir } from '../utils'
|
import { mergeExpressions, findDir } from '../utils'
|
||||||
|
|
||||||
export const isVSlot = (p: ElementNode['props'][0]): p is DirectiveNode =>
|
export const isVSlot = (p: ElementNode['props'][0]): p is DirectiveNode =>
|
||||||
p.type === NodeTypes.DIRECTIVE && p.name === 'slot'
|
p.type === NodeTypes.DIRECTIVE && p.name === 'slot'
|
||||||
@ -29,6 +29,9 @@ const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode =>
|
|||||||
|
|
||||||
const defaultFallback = createSimpleExpression(`undefined`, false)
|
const defaultFallback = createSimpleExpression(`undefined`, false)
|
||||||
|
|
||||||
|
const hasSameName = (slot: Property, name: string): boolean =>
|
||||||
|
isStaticExp(slot.key) && slot.key.content === name
|
||||||
|
|
||||||
// A NodeTransform that tracks scope identifiers for scoped slots so that they
|
// A NodeTransform that tracks scope identifiers for scoped slots so that they
|
||||||
// don't get prefixed by transformExpression. This transform is only applied
|
// don't get prefixed by transformExpression. This transform is only applied
|
||||||
// in non-browser builds with { prefixIdentifiers: true }
|
// in non-browser builds with { prefixIdentifiers: true }
|
||||||
@ -109,7 +112,7 @@ export function buildSlots(
|
|||||||
} = slotDir
|
} = slotDir
|
||||||
|
|
||||||
// check if name is dynamic.
|
// check if name is dynamic.
|
||||||
let staticSlotName
|
let staticSlotName: string | undefined
|
||||||
if (isStaticExp(slotName)) {
|
if (isStaticExp(slotName)) {
|
||||||
staticSlotName = slotName ? slotName.content : `default`
|
staticSlotName = slotName ? slotName.content : `default`
|
||||||
} else {
|
} else {
|
||||||
@ -124,9 +127,9 @@ export function buildSlots(
|
|||||||
)
|
)
|
||||||
|
|
||||||
// check if this slot is conditional (v-if/else/else-if)
|
// check if this slot is conditional (v-if/else/else-if)
|
||||||
let vIf
|
let vIf: DirectiveNode | undefined
|
||||||
let vElse
|
let vElse: DirectiveNode | undefined
|
||||||
if ((vIf = findNonEmptyDir(slotElement, 'if'))) {
|
if ((vIf = findDir(slotElement, 'if'))) {
|
||||||
hasDynamicSlots = true
|
hasDynamicSlots = true
|
||||||
slots.push(
|
slots.push(
|
||||||
createObjectProperty(
|
createObjectProperty(
|
||||||
@ -134,59 +137,66 @@ export function buildSlots(
|
|||||||
createConditionalExpression(vIf.exp!, slotFunction, defaultFallback)
|
createConditionalExpression(vIf.exp!, slotFunction, defaultFallback)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
} else if ((vElse = findNonEmptyDir(slotElement, /^else(-if)?$/))) {
|
} else if (
|
||||||
|
(vElse = findDir(slotElement, /^else(-if)?$/, true /* allow empty */))
|
||||||
|
) {
|
||||||
hasDynamicSlots = true
|
hasDynamicSlots = true
|
||||||
|
|
||||||
// find adjacent v-if slot
|
// find adjacent v-if slot
|
||||||
let vIfBase
|
let baseIfSlot: Property | undefined
|
||||||
|
let baseIfSlotWithSameName: Property | undefined
|
||||||
let i = slots.length
|
let i = slots.length
|
||||||
while (i--) {
|
while (i--) {
|
||||||
if (slots[i].value.type === NodeTypes.JS_CONDITIONAL_EXPRESSION) {
|
if (slots[i].value.type === NodeTypes.JS_CONDITIONAL_EXPRESSION) {
|
||||||
vIfBase = slots[i]
|
baseIfSlot = slots[i]
|
||||||
break
|
if (staticSlotName && hasSameName(baseIfSlot, staticSlotName)) {
|
||||||
|
baseIfSlotWithSameName = baseIfSlot
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (vIfBase) {
|
if (!baseIfSlot) {
|
||||||
// check if the v-else and the base v-if has the same slot name
|
|
||||||
if (
|
|
||||||
isStaticExp(vIfBase.key) &&
|
|
||||||
vIfBase.key.content === staticSlotName
|
|
||||||
) {
|
|
||||||
let conditional = vIfBase.value as ConditionalExpression
|
|
||||||
while (
|
|
||||||
conditional.alternate.type === NodeTypes.JS_CONDITIONAL_EXPRESSION
|
|
||||||
) {
|
|
||||||
conditional = conditional.alternate
|
|
||||||
}
|
|
||||||
conditional.alternate = vElse.exp
|
|
||||||
? createConditionalExpression(
|
|
||||||
vElse.exp,
|
|
||||||
slotFunction,
|
|
||||||
defaultFallback
|
|
||||||
)
|
|
||||||
: slotFunction
|
|
||||||
} else {
|
|
||||||
// not the same slot name. generate a separate property.
|
|
||||||
slots.push(
|
|
||||||
createObjectProperty(
|
|
||||||
slotName,
|
|
||||||
createConditionalExpression(
|
|
||||||
// negate baseVIf
|
|
||||||
mergeExpressions(
|
|
||||||
`!(`,
|
|
||||||
(vIfBase.value as ConditionalExpression).test,
|
|
||||||
`)`,
|
|
||||||
...(vElse.exp ? [` && (`, vElse.exp, `)`] : [])
|
|
||||||
),
|
|
||||||
slotFunction,
|
|
||||||
defaultFallback
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
context.onError(
|
context.onError(
|
||||||
createCompilerError(ErrorCodes.X_ELSE_NO_ADJACENT_IF, vElse.loc)
|
createCompilerError(ErrorCodes.X_ELSE_NO_ADJACENT_IF, vElse.loc)
|
||||||
)
|
)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if (baseIfSlotWithSameName) {
|
||||||
|
// v-else branch has same slot name with base v-if branch
|
||||||
|
let conditional = baseIfSlotWithSameName.value as ConditionalExpression
|
||||||
|
// locate the deepest conditional in case we have nested ones
|
||||||
|
while (
|
||||||
|
conditional.alternate.type === NodeTypes.JS_CONDITIONAL_EXPRESSION
|
||||||
|
) {
|
||||||
|
conditional = conditional.alternate
|
||||||
|
}
|
||||||
|
// attach the v-else branch to the base v-if's conditional expression
|
||||||
|
conditional.alternate = vElse.exp
|
||||||
|
? createConditionalExpression(
|
||||||
|
vElse.exp,
|
||||||
|
slotFunction,
|
||||||
|
defaultFallback
|
||||||
|
)
|
||||||
|
: slotFunction
|
||||||
|
} else {
|
||||||
|
// not the same slot name. generate a separate property.
|
||||||
|
slots.push(
|
||||||
|
createObjectProperty(
|
||||||
|
slotName,
|
||||||
|
createConditionalExpression(
|
||||||
|
// negate base branch condition
|
||||||
|
mergeExpressions(
|
||||||
|
`!(`,
|
||||||
|
(baseIfSlot.value as ConditionalExpression).test,
|
||||||
|
`)`,
|
||||||
|
...(vElse.exp ? [` && (`, vElse.exp, `)`] : [])
|
||||||
|
),
|
||||||
|
slotFunction,
|
||||||
|
defaultFallback
|
||||||
|
)
|
||||||
|
)
|
||||||
|
)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// check duplicate static names
|
// check duplicate static names
|
||||||
|
@ -111,16 +111,17 @@ export function assert(condition: boolean, msg?: string) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export function findNonEmptyDir(
|
export function findDir(
|
||||||
node: ElementNode,
|
node: ElementNode,
|
||||||
name: string | RegExp
|
name: string | RegExp,
|
||||||
|
allowEmpty: boolean = false
|
||||||
): DirectiveNode | undefined {
|
): DirectiveNode | undefined {
|
||||||
for (let i = 0; i < node.props.length; i++) {
|
for (let i = 0; i < node.props.length; i++) {
|
||||||
const p = node.props[i]
|
const p = node.props[i]
|
||||||
if (
|
if (
|
||||||
p.type === NodeTypes.DIRECTIVE &&
|
p.type === NodeTypes.DIRECTIVE &&
|
||||||
p.exp &&
|
(allowEmpty || p.exp) &&
|
||||||
(isString(name) ? p.name === name : name.test(p.name))
|
p.name.match(name)
|
||||||
) {
|
) {
|
||||||
return p
|
return p
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user