| 486 | } |
| 487 | |
| 488 | export function createStructuralDirectiveTransform( |
| 489 | name: string | RegExp, |
| 490 | fn: StructuralDirectiveTransform, |
| 491 | ): NodeTransform { |
| 492 | const matches = isString(name) |
| 493 | ? (n: string) => n === name |
| 494 | : (n: string) => name.test(n) |
| 495 | |
| 496 | return (node, context) => { |
| 497 | if (node.type === NodeTypes.ELEMENT) { |
| 498 | const { props } = node |
| 499 | // structural directive transforms are not concerned with slots |
| 500 | // as they are handled separately in vSlot.ts |
| 501 | if (node.tagType === ElementTypes.TEMPLATE && props.some(isVSlot)) { |
| 502 | return |
| 503 | } |
| 504 | const exitFns = [] |
| 505 | for (let i = 0; i < props.length; i++) { |
| 506 | const prop = props[i] |
| 507 | if (prop.type === NodeTypes.DIRECTIVE && matches(prop.name)) { |
| 508 | // structural directives are removed to avoid infinite recursion |
| 509 | // also we remove them *before* applying so that it can further |
| 510 | // traverse itself in case it moves the node around |
| 511 | props.splice(i, 1) |
| 512 | i-- |
| 513 | const onExit = fn(node, prop, context) |
| 514 | if (onExit) exitFns.push(onExit) |
| 515 | } |
| 516 | } |
| 517 | return exitFns |
| 518 | } |
| 519 | } |
| 520 | } |