import { escapeHtml, stringifyStyle } from '@vue/shared' import { normalizeClass, normalizeStyle, propsToAttrMap, isString, isOn, isSSRSafeAttrName, isBooleanAttr, makeMap } from '@vue/shared' // leading comma for empty string "" const shouldIgnoreProp = makeMap(`,key,ref,innerHTML,textContent`) export function ssrRenderAttrs( props: Record, 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 { 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 (!isRenderableValue(value)) { return `` } const attrKey = tag && tag.indexOf('-') > 0 ? key // preserve raw name on custom elements : propsToAttrMap[key] || key.toLowerCase() if (isBooleanAttr(attrKey)) { return value === false ? `` : ` ${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 (!isRenderableValue(value)) { return `` } return ` ${key}="${escapeHtml(value)}"` } function isRenderableValue(value: unknown): boolean { if (value == null) { return false } const type = typeof value return type === 'string' || type === 'number' || type === 'boolean' } 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)) }