All files / compiler-ssr/src/transforms ssrInjectFallthroughAttrs.ts

96.96% Statements 32/33
97.05% Branches 33/34
100% Functions 5/5
100% Lines 30/30

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 9133x                         33x 319x   33x 251x   33x       788x 217x     788x           7x 7x 5x 5x   5x       783x 783x 540x     243x   17x 17x 25x         17x 17x 8x           1x     16x 226x 202x         223x           195x                    
import {
  NodeTransform,
  NodeTypes,
  ElementTypes,
  locStub,
  createSimpleExpression,
  RootNode,
  TemplateChildNode,
  ParentNode,
  findDir,
  isBuiltInType
} from '@vue/compiler-dom'
 
const filterChild = (node: ParentNode) =>
  node.children.filter(n => n.type !== NodeTypes.COMMENT)
 
const hasSingleChild = (node: ParentNode): boolean =>
  filterChild(node).length === 1
 
export const ssrInjectFallthroughAttrs: NodeTransform = (node, context) => {
  // _attrs is provided as a function argument.
  // mark it as a known identifier so that it doesn't get prefixed by
  // transformExpression.
  if (node.type === NodeTypes.ROOT) {
    context.identifiers._attrs = 1
  }
 
  if (
    node.type === NodeTypes.ELEMENT &&
    node.tagType === ElementTypes.COMPONENT &&
    (isBuiltInType(node.tag, 'Transition') ||
      isBuiltInType(node.tag, 'KeepAlive'))
  ) {
    const rootChildren = filterChild(context.root)
    if (rootChildren.length === 1 && rootChildren[0] === node) {
      if (hasSingleChild(node)) {
        injectFallthroughAttrs(node.children[0])
      }
      return
    }
  }
 
  const parent = context.parent
  if (!parent || parent.type !== NodeTypes.ROOT) {
    return
  }
 
  if (node.type === NodeTypes.IF_BRANCH && hasSingleChild(node)) {
    // detect cases where the parent v-if is not the only root level node
    let hasEncounteredIf = false
    for (const c of filterChild(parent)) {
      if (
        c.type === NodeTypes.IF ||
        (c.type === NodeTypes.ELEMENT && findDir(c, 'if'))
      ) {
        // multiple root v-if
        Iif (hasEncounteredIf) return
        hasEncounteredIf = true
      } else if (
        // node before v-if
        !hasEncounteredIf ||
        // non else nodes
        !(c.type === NodeTypes.ELEMENT && findDir(c, /else/, true))
      ) {
        return
      }
    }
    injectFallthroughAttrs(node.children[0])
  } else if (hasSingleChild(parent)) {
    injectFallthroughAttrs(node)
  }
}
 
function injectFallthroughAttrs(node: RootNode | TemplateChildNode) {
  if (
    node.type === NodeTypes.ELEMENT &&
    (node.tagType === ElementTypes.ELEMENT ||
      node.tagType === ElementTypes.COMPONENT) &&
    !findDir(node, 'for')
  ) {
    node.props.push({
      type: NodeTypes.DIRECTIVE,
      name: 'bind',
      arg: undefined,
      exp: createSimpleExpression(`_attrs`, false),
      modifiers: [],
      loc: locStub
    })
  }
}