refactor: improve vSlot.ts readability
This commit is contained in:
parent
35cb3700b8
commit
f401ac6b88
@ -19,7 +19,7 @@ import {
|
||||
} from '../ast'
|
||||
import { TransformContext, NodeTransform } from '../transform'
|
||||
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 =>
|
||||
p.type === NodeTypes.DIRECTIVE && p.name === 'slot'
|
||||
@ -29,6 +29,9 @@ const isStaticExp = (p: JSChildNode): p is SimpleExpressionNode =>
|
||||
|
||||
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
|
||||
// don't get prefixed by transformExpression. This transform is only applied
|
||||
// in non-browser builds with { prefixIdentifiers: true }
|
||||
@ -109,7 +112,7 @@ export function buildSlots(
|
||||
} = slotDir
|
||||
|
||||
// check if name is dynamic.
|
||||
let staticSlotName
|
||||
let staticSlotName: string | undefined
|
||||
if (isStaticExp(slotName)) {
|
||||
staticSlotName = slotName ? slotName.content : `default`
|
||||
} else {
|
||||
@ -124,9 +127,9 @@ export function buildSlots(
|
||||
)
|
||||
|
||||
// check if this slot is conditional (v-if/else/else-if)
|
||||
let vIf
|
||||
let vElse
|
||||
if ((vIf = findNonEmptyDir(slotElement, 'if'))) {
|
||||
let vIf: DirectiveNode | undefined
|
||||
let vElse: DirectiveNode | undefined
|
||||
if ((vIf = findDir(slotElement, 'if'))) {
|
||||
hasDynamicSlots = true
|
||||
slots.push(
|
||||
createObjectProperty(
|
||||
@ -134,29 +137,41 @@ export function buildSlots(
|
||||
createConditionalExpression(vIf.exp!, slotFunction, defaultFallback)
|
||||
)
|
||||
)
|
||||
} else if ((vElse = findNonEmptyDir(slotElement, /^else(-if)?$/))) {
|
||||
} else if (
|
||||
(vElse = findDir(slotElement, /^else(-if)?$/, true /* allow empty */))
|
||||
) {
|
||||
hasDynamicSlots = true
|
||||
|
||||
// find adjacent v-if slot
|
||||
let vIfBase
|
||||
let baseIfSlot: Property | undefined
|
||||
let baseIfSlotWithSameName: Property | undefined
|
||||
let i = slots.length
|
||||
while (i--) {
|
||||
if (slots[i].value.type === NodeTypes.JS_CONDITIONAL_EXPRESSION) {
|
||||
vIfBase = slots[i]
|
||||
baseIfSlot = slots[i]
|
||||
if (staticSlotName && hasSameName(baseIfSlot, staticSlotName)) {
|
||||
baseIfSlotWithSameName = baseIfSlot
|
||||
break
|
||||
}
|
||||
}
|
||||
if (vIfBase) {
|
||||
// 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
|
||||
}
|
||||
if (!baseIfSlot) {
|
||||
context.onError(
|
||||
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,
|
||||
@ -170,10 +185,10 @@ export function buildSlots(
|
||||
createObjectProperty(
|
||||
slotName,
|
||||
createConditionalExpression(
|
||||
// negate baseVIf
|
||||
// negate base branch condition
|
||||
mergeExpressions(
|
||||
`!(`,
|
||||
(vIfBase.value as ConditionalExpression).test,
|
||||
(baseIfSlot.value as ConditionalExpression).test,
|
||||
`)`,
|
||||
...(vElse.exp ? [` && (`, vElse.exp, `)`] : [])
|
||||
),
|
||||
@ -183,11 +198,6 @@ export function buildSlots(
|
||||
)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
context.onError(
|
||||
createCompilerError(ErrorCodes.X_ELSE_NO_ADJACENT_IF, vElse.loc)
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// check duplicate static names
|
||||
if (staticSlotName) {
|
||||
|
@ -111,16 +111,17 @@ export function assert(condition: boolean, msg?: string) {
|
||||
}
|
||||
}
|
||||
|
||||
export function findNonEmptyDir(
|
||||
export function findDir(
|
||||
node: ElementNode,
|
||||
name: string | RegExp
|
||||
name: string | RegExp,
|
||||
allowEmpty: boolean = false
|
||||
): DirectiveNode | undefined {
|
||||
for (let i = 0; i < node.props.length; i++) {
|
||||
const p = node.props[i]
|
||||
if (
|
||||
p.type === NodeTypes.DIRECTIVE &&
|
||||
p.exp &&
|
||||
(isString(name) ? p.name === name : name.test(p.name))
|
||||
(allowEmpty || p.exp) &&
|
||||
p.name.match(name)
|
||||
) {
|
||||
return p
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user