All files / server-renderer/src/helpers ssrRenderAttrs.ts

90.54% Statements 67/74
94.73% Branches 36/38
100% Functions 5/5
90.54% Lines 67/74

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 91 92 93 94 95 96 97 98 992x         2x                     2x     2x 2x 2x   2x 189x 189x 189x 189x 189x 166x 166x 155x 146x 166x 23x 23x 143x 165x 25x 165x 9x 117x 2x 109x 107x 107x 166x 189x 189x     2x 107x 107x 107x 107x 107x 6x 6x 101x 107x 2x 99x 107x 23x 107x 78x 78x           107x       2x 8x 2x 2x 6x 6x   2x 36x 36x   2x 16x     16x 2x 2x 14x 14x 14x  
import {
  escapeHtml,
  isRenderableAttrValue,
  isSVGTag,
  stringifyStyle,
} from '@vue/shared'
import {
  includeBooleanAttr,
  isBooleanAttr,
  isOn,
  isSSRSafeAttrName,
  isString,
  makeMap,
  normalizeClass,
  normalizeStyle,
  propsToAttrMap,
} from '@vue/shared'
 
// leading comma for empty string ""
const shouldIgnoreProp = /*@__PURE__*/ makeMap(
  `,key,ref,innerHTML,textContent,ref_key,ref_for`,
)
 
export function ssrRenderAttrs(
  props: Record<string, unknown>,
  tag?: string,
): string {
  let ret = ''
  for (const key in props) {
    if (
      shouldIgnoreProp(key) ||
      isOn(key) ||
      (tag === 'textarea' && key === 'value')
    ) {
      continue
    }
    const value = props[key]
    if (key === 'class') {
      ret += ` class="${ssrRenderClass(value)}"`
    } else if (key === 'style') {
      ret += ` style="${ssrRenderStyle(value)}"`
    } else if (key === 'className') {
      ret += ` class="${String(value)}"`
    } else {
      ret += ssrRenderDynamicAttr(key, value, tag)
    }
  }
  return ret
}
 
// render an attr with dynamic (unknown) key.
export function ssrRenderDynamicAttr(
  key: string,
  value: unknown,
  tag?: string,
): string {
  if (!isRenderableAttrValue(value)) {
    return ``
  }
  const attrKey =
    tag && (tag.indexOf('-') > 0 || isSVGTag(tag))
      ? key // preserve raw name on custom elements and svg
      : propsToAttrMap[key] || key.toLowerCase()
  if (isBooleanAttr(attrKey)) {
    return includeBooleanAttr(value) ? ` ${attrKey}` : ``
  } else if (isSSRSafeAttrName(attrKey)) {
    return value === '' ? ` ${attrKey}` : ` ${attrKey}="${escapeHtml(value)}"`
  } else {
    console.warn(
      `[@vue/server-renderer] Skipped rendering unsafe attribute name: ${attrKey}`,
    )
    return ``
  }
}
 
// Render a v-bind attr with static key. The key is pre-processed at compile
// time and we only need to check and escape value.
export function ssrRenderAttr(key: string, value: unknown): string {
  if (!isRenderableAttrValue(value)) {
    return ``
  }
  return ` ${key}="${escapeHtml(value)}"`
}
 
export function ssrRenderClass(raw: unknown): string {
  return escapeHtml(normalizeClass(raw))
}
 
export function ssrRenderStyle(raw: unknown): string {
  if (!raw) {
    return ''
  }
  if (isString(raw)) {
    return escapeHtml(raw)
  }
  const styles = normalizeStyle(raw)
  return escapeHtml(stringifyStyle(styles))
}