init
This commit is contained in:
264
node_modules/vue/src/server/optimizing-compiler/codegen.js
generated
vendored
Normal file
264
node_modules/vue/src/server/optimizing-compiler/codegen.js
generated
vendored
Normal file
@@ -0,0 +1,264 @@
|
||||
/* @flow */
|
||||
|
||||
// The SSR codegen is essentially extending the default codegen to handle
|
||||
// SSR-optimizable nodes and turn them into string render fns. In cases where
|
||||
// a node is not optimizable it simply falls back to the default codegen.
|
||||
|
||||
import {
|
||||
genIf,
|
||||
genFor,
|
||||
genData,
|
||||
genText,
|
||||
genElement,
|
||||
genChildren,
|
||||
CodegenState
|
||||
} from 'compiler/codegen/index'
|
||||
|
||||
import {
|
||||
genAttrSegments,
|
||||
genDOMPropSegments,
|
||||
genClassSegments,
|
||||
genStyleSegments,
|
||||
applyModelTransform
|
||||
} from './modules'
|
||||
|
||||
import { escape } from 'web/server/util'
|
||||
import { optimizability } from './optimizer'
|
||||
import type { CodegenResult } from 'compiler/codegen/index'
|
||||
|
||||
export type StringSegment = {
|
||||
type: number;
|
||||
value: string;
|
||||
};
|
||||
|
||||
// segment types
|
||||
export const RAW = 0
|
||||
export const INTERPOLATION = 1
|
||||
export const EXPRESSION = 2
|
||||
|
||||
export function generate (
|
||||
ast: ASTElement | void,
|
||||
options: CompilerOptions
|
||||
): CodegenResult {
|
||||
const state = new CodegenState(options)
|
||||
const code = ast ? genSSRElement(ast, state) : '_c("div")'
|
||||
return {
|
||||
render: `with(this){return ${code}}`,
|
||||
staticRenderFns: state.staticRenderFns
|
||||
}
|
||||
}
|
||||
|
||||
function genSSRElement (el: ASTElement, state: CodegenState): string {
|
||||
if (el.for && !el.forProcessed) {
|
||||
return genFor(el, state, genSSRElement)
|
||||
} else if (el.if && !el.ifProcessed) {
|
||||
return genIf(el, state, genSSRElement)
|
||||
} else if (el.tag === 'template' && !el.slotTarget) {
|
||||
return el.ssrOptimizability === optimizability.FULL
|
||||
? genChildrenAsStringNode(el, state)
|
||||
: genSSRChildren(el, state) || 'void 0'
|
||||
}
|
||||
|
||||
switch (el.ssrOptimizability) {
|
||||
case optimizability.FULL:
|
||||
// stringify whole tree
|
||||
return genStringElement(el, state)
|
||||
case optimizability.SELF:
|
||||
// stringify self and check children
|
||||
return genStringElementWithChildren(el, state)
|
||||
case optimizability.CHILDREN:
|
||||
// generate self as VNode and stringify children
|
||||
return genNormalElement(el, state, true)
|
||||
case optimizability.PARTIAL:
|
||||
// generate self as VNode and check children
|
||||
return genNormalElement(el, state, false)
|
||||
default:
|
||||
// bail whole tree
|
||||
return genElement(el, state)
|
||||
}
|
||||
}
|
||||
|
||||
function genNormalElement (el, state, stringifyChildren) {
|
||||
const data = el.plain ? undefined : genData(el, state)
|
||||
const children = stringifyChildren
|
||||
? `[${genChildrenAsStringNode(el, state)}]`
|
||||
: genSSRChildren(el, state, true)
|
||||
return `_c('${el.tag}'${
|
||||
data ? `,${data}` : ''
|
||||
}${
|
||||
children ? `,${children}` : ''
|
||||
})`
|
||||
}
|
||||
|
||||
function genSSRChildren (el, state, checkSkip) {
|
||||
return genChildren(el, state, checkSkip, genSSRElement, genSSRNode)
|
||||
}
|
||||
|
||||
function genSSRNode (el, state) {
|
||||
return el.type === 1
|
||||
? genSSRElement(el, state)
|
||||
: genText(el)
|
||||
}
|
||||
|
||||
function genChildrenAsStringNode (el, state) {
|
||||
return el.children.length
|
||||
? `_ssrNode(${flattenSegments(childrenToSegments(el, state))})`
|
||||
: ''
|
||||
}
|
||||
|
||||
function genStringElement (el, state) {
|
||||
return `_ssrNode(${elementToString(el, state)})`
|
||||
}
|
||||
|
||||
function genStringElementWithChildren (el, state) {
|
||||
const children = genSSRChildren(el, state, true)
|
||||
return `_ssrNode(${
|
||||
flattenSegments(elementToOpenTagSegments(el, state))
|
||||
},"</${el.tag}>"${
|
||||
children ? `,${children}` : ''
|
||||
})`
|
||||
}
|
||||
|
||||
function elementToString (el, state) {
|
||||
return `(${flattenSegments(elementToSegments(el, state))})`
|
||||
}
|
||||
|
||||
function elementToSegments (el, state): Array<StringSegment> {
|
||||
// v-for / v-if
|
||||
if (el.for && !el.forProcessed) {
|
||||
el.forProcessed = true
|
||||
return [{
|
||||
type: EXPRESSION,
|
||||
value: genFor(el, state, elementToString, '_ssrList')
|
||||
}]
|
||||
} else if (el.if && !el.ifProcessed) {
|
||||
el.ifProcessed = true
|
||||
return [{
|
||||
type: EXPRESSION,
|
||||
value: genIf(el, state, elementToString, '"<!---->"')
|
||||
}]
|
||||
} else if (el.tag === 'template') {
|
||||
return childrenToSegments(el, state)
|
||||
}
|
||||
|
||||
const openSegments = elementToOpenTagSegments(el, state)
|
||||
const childrenSegments = childrenToSegments(el, state)
|
||||
const { isUnaryTag } = state.options
|
||||
const close = (isUnaryTag && isUnaryTag(el.tag))
|
||||
? []
|
||||
: [{ type: RAW, value: `</${el.tag}>` }]
|
||||
return openSegments.concat(childrenSegments, close)
|
||||
}
|
||||
|
||||
function elementToOpenTagSegments (el, state): Array<StringSegment> {
|
||||
applyModelTransform(el, state)
|
||||
let binding
|
||||
const segments = [{ type: RAW, value: `<${el.tag}` }]
|
||||
// attrs
|
||||
if (el.attrs) {
|
||||
segments.push.apply(segments, genAttrSegments(el.attrs))
|
||||
}
|
||||
// domProps
|
||||
if (el.props) {
|
||||
segments.push.apply(segments, genDOMPropSegments(el.props, el.attrs))
|
||||
}
|
||||
// v-bind="object"
|
||||
if ((binding = el.attrsMap['v-bind'])) {
|
||||
segments.push({ type: EXPRESSION, value: `_ssrAttrs(${binding})` })
|
||||
}
|
||||
// v-bind.prop="object"
|
||||
if ((binding = el.attrsMap['v-bind.prop'])) {
|
||||
segments.push({ type: EXPRESSION, value: `_ssrDOMProps(${binding})` })
|
||||
}
|
||||
// class
|
||||
if (el.staticClass || el.classBinding) {
|
||||
segments.push.apply(
|
||||
segments,
|
||||
genClassSegments(el.staticClass, el.classBinding)
|
||||
)
|
||||
}
|
||||
// style & v-show
|
||||
if (el.staticStyle || el.styleBinding || el.attrsMap['v-show']) {
|
||||
segments.push.apply(
|
||||
segments,
|
||||
genStyleSegments(
|
||||
el.attrsMap.style,
|
||||
el.staticStyle,
|
||||
el.styleBinding,
|
||||
el.attrsMap['v-show']
|
||||
)
|
||||
)
|
||||
}
|
||||
// _scopedId
|
||||
if (state.options.scopeId) {
|
||||
segments.push({ type: RAW, value: ` ${state.options.scopeId}` })
|
||||
}
|
||||
segments.push({ type: RAW, value: `>` })
|
||||
return segments
|
||||
}
|
||||
|
||||
function childrenToSegments (el, state): Array<StringSegment> {
|
||||
let binding
|
||||
if ((binding = el.attrsMap['v-html'])) {
|
||||
return [{ type: EXPRESSION, value: `_s(${binding})` }]
|
||||
}
|
||||
if ((binding = el.attrsMap['v-text'])) {
|
||||
return [{ type: INTERPOLATION, value: `_s(${binding})` }]
|
||||
}
|
||||
if (el.tag === 'textarea' && (binding = el.attrsMap['v-model'])) {
|
||||
return [{ type: INTERPOLATION, value: `_s(${binding})` }]
|
||||
}
|
||||
return el.children
|
||||
? nodesToSegments(el.children, state)
|
||||
: []
|
||||
}
|
||||
|
||||
function nodesToSegments (
|
||||
children: Array<ASTNode>,
|
||||
state: CodegenState
|
||||
): Array<StringSegment> {
|
||||
const segments = []
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const c = children[i]
|
||||
if (c.type === 1) {
|
||||
segments.push.apply(segments, elementToSegments(c, state))
|
||||
} else if (c.type === 2) {
|
||||
segments.push({ type: INTERPOLATION, value: c.expression })
|
||||
} else if (c.type === 3) {
|
||||
let text = escape(c.text)
|
||||
if (c.isComment) {
|
||||
text = '<!--' + text + '-->'
|
||||
}
|
||||
segments.push({ type: RAW, value: text })
|
||||
}
|
||||
}
|
||||
return segments
|
||||
}
|
||||
|
||||
function flattenSegments (segments: Array<StringSegment>): string {
|
||||
const mergedSegments = []
|
||||
let textBuffer = ''
|
||||
|
||||
const pushBuffer = () => {
|
||||
if (textBuffer) {
|
||||
mergedSegments.push(JSON.stringify(textBuffer))
|
||||
textBuffer = ''
|
||||
}
|
||||
}
|
||||
|
||||
for (let i = 0; i < segments.length; i++) {
|
||||
const s = segments[i]
|
||||
if (s.type === RAW) {
|
||||
textBuffer += s.value
|
||||
} else if (s.type === INTERPOLATION) {
|
||||
pushBuffer()
|
||||
mergedSegments.push(`_ssrEscape(${s.value})`)
|
||||
} else if (s.type === EXPRESSION) {
|
||||
pushBuffer()
|
||||
mergedSegments.push(`(${s.value})`)
|
||||
}
|
||||
}
|
||||
pushBuffer()
|
||||
|
||||
return mergedSegments.join('+')
|
||||
}
|
20
node_modules/vue/src/server/optimizing-compiler/index.js
generated
vendored
Normal file
20
node_modules/vue/src/server/optimizing-compiler/index.js
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
/* @flow */
|
||||
|
||||
import { parse } from 'compiler/parser/index'
|
||||
import { generate } from './codegen'
|
||||
import { optimize } from './optimizer'
|
||||
import { createCompilerCreator } from 'compiler/create-compiler'
|
||||
|
||||
export const createCompiler = createCompilerCreator(function baseCompile (
|
||||
template: string,
|
||||
options: CompilerOptions
|
||||
): CompiledResult {
|
||||
const ast = parse(template.trim(), options)
|
||||
optimize(ast, options)
|
||||
const code = generate(ast, options)
|
||||
return {
|
||||
ast,
|
||||
render: code.render,
|
||||
staticRenderFns: code.staticRenderFns
|
||||
}
|
||||
})
|
124
node_modules/vue/src/server/optimizing-compiler/modules.js
generated
vendored
Normal file
124
node_modules/vue/src/server/optimizing-compiler/modules.js
generated
vendored
Normal file
@@ -0,0 +1,124 @@
|
||||
/* @flow */
|
||||
|
||||
import {
|
||||
RAW,
|
||||
// INTERPOLATION,
|
||||
EXPRESSION
|
||||
} from './codegen'
|
||||
|
||||
import {
|
||||
propsToAttrMap,
|
||||
isRenderableAttr
|
||||
} from 'web/server/util'
|
||||
|
||||
import {
|
||||
isBooleanAttr,
|
||||
isEnumeratedAttr
|
||||
} from 'web/util/attrs'
|
||||
|
||||
import type { StringSegment } from './codegen'
|
||||
import type { CodegenState } from 'compiler/codegen/index'
|
||||
|
||||
const plainStringRE = /^"(?:[^"\\]|\\.)*"$|^'(?:[^'\\]|\\.)*'$/
|
||||
|
||||
// let the model AST transform translate v-model into appropriate
|
||||
// props bindings
|
||||
export function applyModelTransform (el: ASTElement, state: CodegenState) {
|
||||
if (el.directives) {
|
||||
for (let i = 0; i < el.directives.length; i++) {
|
||||
const dir = el.directives[i]
|
||||
if (dir.name === 'model') {
|
||||
state.directives.model(el, dir, state.warn)
|
||||
// remove value for textarea as its converted to text
|
||||
if (el.tag === 'textarea' && el.props) {
|
||||
el.props = el.props.filter(p => p.name !== 'value')
|
||||
}
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function genAttrSegments (
|
||||
attrs: Array<ASTAttr>
|
||||
): Array<StringSegment> {
|
||||
return attrs.map(({ name, value }) => genAttrSegment(name, value))
|
||||
}
|
||||
|
||||
export function genDOMPropSegments (
|
||||
props: Array<ASTAttr>,
|
||||
attrs: ?Array<ASTAttr>
|
||||
): Array<StringSegment> {
|
||||
const segments = []
|
||||
props.forEach(({ name, value }) => {
|
||||
name = propsToAttrMap[name] || name.toLowerCase()
|
||||
if (isRenderableAttr(name) &&
|
||||
!(attrs && attrs.some(a => a.name === name))
|
||||
) {
|
||||
segments.push(genAttrSegment(name, value))
|
||||
}
|
||||
})
|
||||
return segments
|
||||
}
|
||||
|
||||
function genAttrSegment (name: string, value: string): StringSegment {
|
||||
if (plainStringRE.test(value)) {
|
||||
// force double quote
|
||||
value = value.replace(/^'|'$/g, '"')
|
||||
// force enumerated attr to "true"
|
||||
if (isEnumeratedAttr(name) && value !== `"false"`) {
|
||||
value = `"true"`
|
||||
}
|
||||
return {
|
||||
type: RAW,
|
||||
value: isBooleanAttr(name)
|
||||
? ` ${name}="${name}"`
|
||||
: value === '""'
|
||||
? ` ${name}`
|
||||
: ` ${name}="${JSON.parse(value)}"`
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
type: EXPRESSION,
|
||||
value: `_ssrAttr(${JSON.stringify(name)},${value})`
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function genClassSegments (
|
||||
staticClass: ?string,
|
||||
classBinding: ?string
|
||||
): Array<StringSegment> {
|
||||
if (staticClass && !classBinding) {
|
||||
return [{ type: RAW, value: ` class="${JSON.parse(staticClass)}"` }]
|
||||
} else {
|
||||
return [{
|
||||
type: EXPRESSION,
|
||||
value: `_ssrClass(${staticClass || 'null'},${classBinding || 'null'})`
|
||||
}]
|
||||
}
|
||||
}
|
||||
|
||||
export function genStyleSegments (
|
||||
staticStyle: ?string,
|
||||
parsedStaticStyle: ?string,
|
||||
styleBinding: ?string,
|
||||
vShowExpression: ?string
|
||||
): Array<StringSegment> {
|
||||
if (staticStyle && !styleBinding && !vShowExpression) {
|
||||
return [{ type: RAW, value: ` style=${JSON.stringify(staticStyle)}` }]
|
||||
} else {
|
||||
return [{
|
||||
type: EXPRESSION,
|
||||
value: `_ssrStyle(${
|
||||
parsedStaticStyle || 'null'
|
||||
},${
|
||||
styleBinding || 'null'
|
||||
}, ${
|
||||
vShowExpression
|
||||
? `{ display: (${vShowExpression}) ? '' : 'none' }`
|
||||
: 'null'
|
||||
})`
|
||||
}]
|
||||
}
|
||||
}
|
141
node_modules/vue/src/server/optimizing-compiler/optimizer.js
generated
vendored
Normal file
141
node_modules/vue/src/server/optimizing-compiler/optimizer.js
generated
vendored
Normal file
@@ -0,0 +1,141 @@
|
||||
/* @flow */
|
||||
|
||||
/**
|
||||
* In SSR, the vdom tree is generated only once and never patched, so
|
||||
* we can optimize most element / trees into plain string render functions.
|
||||
* The SSR optimizer walks the AST tree to detect optimizable elements and trees.
|
||||
*
|
||||
* The criteria for SSR optimizability is quite a bit looser than static tree
|
||||
* detection (which is designed for client re-render). In SSR we bail only for
|
||||
* components/slots/custom directives.
|
||||
*/
|
||||
|
||||
import { no, makeMap, isBuiltInTag } from 'shared/util'
|
||||
|
||||
// optimizability constants
|
||||
export const optimizability = {
|
||||
FALSE: 0, // whole sub tree un-optimizable
|
||||
FULL: 1, // whole sub tree optimizable
|
||||
SELF: 2, // self optimizable but has some un-optimizable children
|
||||
CHILDREN: 3, // self un-optimizable but have fully optimizable children
|
||||
PARTIAL: 4 // self un-optimizable with some un-optimizable children
|
||||
}
|
||||
|
||||
let isPlatformReservedTag
|
||||
|
||||
export function optimize (root: ?ASTElement, options: CompilerOptions) {
|
||||
if (!root) return
|
||||
isPlatformReservedTag = options.isReservedTag || no
|
||||
walk(root, true)
|
||||
}
|
||||
|
||||
function walk (node: ASTNode, isRoot?: boolean) {
|
||||
if (isUnOptimizableTree(node)) {
|
||||
node.ssrOptimizability = optimizability.FALSE
|
||||
return
|
||||
}
|
||||
// root node or nodes with custom directives should always be a VNode
|
||||
const selfUnoptimizable = isRoot || hasCustomDirective(node)
|
||||
const check = child => {
|
||||
if (child.ssrOptimizability !== optimizability.FULL) {
|
||||
node.ssrOptimizability = selfUnoptimizable
|
||||
? optimizability.PARTIAL
|
||||
: optimizability.SELF
|
||||
}
|
||||
}
|
||||
if (selfUnoptimizable) {
|
||||
node.ssrOptimizability = optimizability.CHILDREN
|
||||
}
|
||||
if (node.type === 1) {
|
||||
for (let i = 0, l = node.children.length; i < l; i++) {
|
||||
const child = node.children[i]
|
||||
walk(child)
|
||||
check(child)
|
||||
}
|
||||
if (node.ifConditions) {
|
||||
for (let i = 1, l = node.ifConditions.length; i < l; i++) {
|
||||
const block = node.ifConditions[i].block
|
||||
walk(block, isRoot)
|
||||
check(block)
|
||||
}
|
||||
}
|
||||
if (node.ssrOptimizability == null ||
|
||||
(!isRoot && (node.attrsMap['v-html'] || node.attrsMap['v-text']))
|
||||
) {
|
||||
node.ssrOptimizability = optimizability.FULL
|
||||
} else {
|
||||
node.children = optimizeSiblings(node)
|
||||
}
|
||||
} else {
|
||||
node.ssrOptimizability = optimizability.FULL
|
||||
}
|
||||
}
|
||||
|
||||
function optimizeSiblings (el) {
|
||||
const children = el.children
|
||||
const optimizedChildren = []
|
||||
|
||||
let currentOptimizableGroup = []
|
||||
const pushGroup = () => {
|
||||
if (currentOptimizableGroup.length) {
|
||||
optimizedChildren.push({
|
||||
type: 1,
|
||||
parent: el,
|
||||
tag: 'template',
|
||||
attrsList: [],
|
||||
attrsMap: {},
|
||||
rawAttrsMap: {},
|
||||
children: currentOptimizableGroup,
|
||||
ssrOptimizability: optimizability.FULL
|
||||
})
|
||||
}
|
||||
currentOptimizableGroup = []
|
||||
}
|
||||
|
||||
for (let i = 0; i < children.length; i++) {
|
||||
const c = children[i]
|
||||
if (c.ssrOptimizability === optimizability.FULL) {
|
||||
currentOptimizableGroup.push(c)
|
||||
} else {
|
||||
// wrap fully-optimizable adjacent siblings inside a template tag
|
||||
// so that they can be optimized into a single ssrNode by codegen
|
||||
pushGroup()
|
||||
optimizedChildren.push(c)
|
||||
}
|
||||
}
|
||||
pushGroup()
|
||||
return optimizedChildren
|
||||
}
|
||||
|
||||
function isUnOptimizableTree (node: ASTNode): boolean {
|
||||
if (node.type === 2 || node.type === 3) { // text or expression
|
||||
return false
|
||||
}
|
||||
return (
|
||||
isBuiltInTag(node.tag) || // built-in (slot, component)
|
||||
!isPlatformReservedTag(node.tag) || // custom component
|
||||
!!node.component || // "is" component
|
||||
isSelectWithModel(node) // <select v-model> requires runtime inspection
|
||||
)
|
||||
}
|
||||
|
||||
const isBuiltInDir = makeMap('text,html,show,on,bind,model,pre,cloak,once')
|
||||
|
||||
function hasCustomDirective (node: ASTNode): ?boolean {
|
||||
return (
|
||||
node.type === 1 &&
|
||||
node.directives &&
|
||||
node.directives.some(d => !isBuiltInDir(d.name))
|
||||
)
|
||||
}
|
||||
|
||||
// <select v-model> cannot be optimized because it requires a runtime check
|
||||
// to determine proper selected option
|
||||
function isSelectWithModel (node: ASTNode): boolean {
|
||||
return (
|
||||
node.type === 1 &&
|
||||
node.tag === 'select' &&
|
||||
node.directives != null &&
|
||||
node.directives.some(d => d.name === 'model')
|
||||
)
|
||||
}
|
150
node_modules/vue/src/server/optimizing-compiler/runtime-helpers.js
generated
vendored
Normal file
150
node_modules/vue/src/server/optimizing-compiler/runtime-helpers.js
generated
vendored
Normal file
@@ -0,0 +1,150 @@
|
||||
/* @flow */
|
||||
|
||||
import { escape, isSSRUnsafeAttr } from 'web/server/util'
|
||||
import { isObject, extend } from 'shared/util'
|
||||
import { renderAttr } from 'web/server/modules/attrs'
|
||||
import { renderClass } from 'web/util/class'
|
||||
import { genStyle } from 'web/server/modules/style'
|
||||
import { normalizeStyleBinding } from 'web/util/style'
|
||||
|
||||
import {
|
||||
normalizeChildren,
|
||||
simpleNormalizeChildren
|
||||
} from 'core/vdom/helpers/normalize-children'
|
||||
|
||||
import {
|
||||
propsToAttrMap,
|
||||
isRenderableAttr
|
||||
} from 'web/server/util'
|
||||
|
||||
const ssrHelpers = {
|
||||
_ssrEscape: escape,
|
||||
_ssrNode: renderStringNode,
|
||||
_ssrList: renderStringList,
|
||||
_ssrAttr: renderAttr,
|
||||
_ssrAttrs: renderAttrs,
|
||||
_ssrDOMProps: renderDOMProps,
|
||||
_ssrClass: renderSSRClass,
|
||||
_ssrStyle: renderSSRStyle
|
||||
}
|
||||
|
||||
export function installSSRHelpers (vm: Component) {
|
||||
if (vm._ssrNode) {
|
||||
return
|
||||
}
|
||||
let Vue = vm.constructor
|
||||
while (Vue.super) {
|
||||
Vue = Vue.super
|
||||
}
|
||||
extend(Vue.prototype, ssrHelpers)
|
||||
if (Vue.FunctionalRenderContext) {
|
||||
extend(Vue.FunctionalRenderContext.prototype, ssrHelpers)
|
||||
}
|
||||
}
|
||||
|
||||
class StringNode {
|
||||
isString: boolean;
|
||||
open: string;
|
||||
close: ?string;
|
||||
children: ?Array<any>;
|
||||
|
||||
constructor (
|
||||
open: string,
|
||||
close?: string,
|
||||
children?: Array<any>,
|
||||
normalizationType?: number
|
||||
) {
|
||||
this.isString = true
|
||||
this.open = open
|
||||
this.close = close
|
||||
if (children) {
|
||||
this.children = normalizationType === 1
|
||||
? simpleNormalizeChildren(children)
|
||||
: normalizationType === 2
|
||||
? normalizeChildren(children)
|
||||
: children
|
||||
} else {
|
||||
this.children = void 0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function renderStringNode (
|
||||
open: string,
|
||||
close?: string,
|
||||
children?: Array<any>,
|
||||
normalizationType?: number
|
||||
): StringNode {
|
||||
return new StringNode(open, close, children, normalizationType)
|
||||
}
|
||||
|
||||
function renderStringList (
|
||||
val: any,
|
||||
render: (
|
||||
val: any,
|
||||
keyOrIndex: string | number,
|
||||
index?: number
|
||||
) => string
|
||||
): string {
|
||||
let ret = ''
|
||||
let i, l, keys, key
|
||||
if (Array.isArray(val) || typeof val === 'string') {
|
||||
for (i = 0, l = val.length; i < l; i++) {
|
||||
ret += render(val[i], i)
|
||||
}
|
||||
} else if (typeof val === 'number') {
|
||||
for (i = 0; i < val; i++) {
|
||||
ret += render(i + 1, i)
|
||||
}
|
||||
} else if (isObject(val)) {
|
||||
keys = Object.keys(val)
|
||||
for (i = 0, l = keys.length; i < l; i++) {
|
||||
key = keys[i]
|
||||
ret += render(val[key], key, i)
|
||||
}
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
function renderAttrs (obj: Object): string {
|
||||
let res = ''
|
||||
for (const key in obj) {
|
||||
if (isSSRUnsafeAttr(key)) {
|
||||
continue
|
||||
}
|
||||
res += renderAttr(key, obj[key])
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function renderDOMProps (obj: Object): string {
|
||||
let res = ''
|
||||
for (const key in obj) {
|
||||
const attr = propsToAttrMap[key] || key.toLowerCase()
|
||||
if (isRenderableAttr(attr)) {
|
||||
res += renderAttr(attr, obj[key])
|
||||
}
|
||||
}
|
||||
return res
|
||||
}
|
||||
|
||||
function renderSSRClass (
|
||||
staticClass: ?string,
|
||||
dynamic: any
|
||||
): string {
|
||||
const res = renderClass(staticClass, dynamic)
|
||||
return res === '' ? res : ` class="${escape(res)}"`
|
||||
}
|
||||
|
||||
function renderSSRStyle (
|
||||
staticStyle: ?Object,
|
||||
dynamic: any,
|
||||
extra: ?Object
|
||||
): string {
|
||||
const style = {}
|
||||
if (staticStyle) extend(style, staticStyle)
|
||||
if (dynamic) extend(style, normalizeStyleBinding(dynamic))
|
||||
if (extra) extend(style, extra)
|
||||
const res = genStyle(style)
|
||||
return res === '' ? res : ` style=${JSON.stringify(escape(res))}`
|
||||
}
|
Reference in New Issue
Block a user