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