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 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 | 87x 87x 87x 87x 87x 87x 1595x 1199x 1197x 1197x 1197x 1197x 1102x 1102x 267x 267x 101x 101x 83x 34x 83x 83x 83x 18x 18x 1197x 89x 1137x 60x 93x 93x 61x 61x 59x 61x 34x 61x | import { NodeTransform } from '../transform'
import {
NodeTypes,
CompoundExpressionNode,
createCallExpression,
CallExpression,
ElementTypes,
ConstantTypes,
createCompoundExpression
} from '../ast'
import { isText } from '../utils'
import { CREATE_TEXT } from '../runtimeHelpers'
import { PatchFlags, PatchFlagNames } from '@vue/shared'
import { getConstantType } from './hoistStatic'
// Merge adjacent text nodes and expressions into a single expression
// e.g. <div>abc {{ d }} {{ e }}</div> should have a single expression node as child.
export const transformText: NodeTransform = (node, context) => {
if (
node.type === NodeTypes.ROOT ||
node.type === NodeTypes.ELEMENT ||
node.type === NodeTypes.FOR ||
node.type === NodeTypes.IF_BRANCH
) {
// perform the transform on node exit so that all expressions have already
// been processed.
return () => {
const children = node.children
let currentContainer: CompoundExpressionNode | undefined = undefined
let hasText = false
for (let i = 0; i < children.length; i++) {
const child = children[i]
if (isText(child)) {
hasText = true
for (let j = i + 1; j < children.length; j++) {
const next = children[j]
if (isText(next)) {
if (!currentContainer) {
currentContainer = children[i] = createCompoundExpression(
[child],
child.loc
)
}
// merge adjacent text node into current
currentContainer.children.push(` + `, next)
children.splice(j, 1)
j--
} else {
currentContainer = undefined
break
}
}
}
}
if (
!hasText ||
// if this is a plain element with a single text child, leave it
// as-is since the runtime has dedicated fast path for this by directly
// setting textContent of the element.
// for component root it's always normalized anyway.
(children.length === 1 &&
(node.type === NodeTypes.ROOT ||
(node.type === NodeTypes.ELEMENT &&
node.tagType === ElementTypes.ELEMENT &&
// #3756
// custom directives can potentially add DOM elements arbitrarily,
// we need to avoid setting textContent of the element at runtime
// to avoid accidentally overwriting the DOM elements added
// by the user through custom directives.
!node.props.find(
p =>
p.type === NodeTypes.DIRECTIVE &&
!context.directiveTransforms[p.name]
) &&
// in compat mode, <template> tags with no special directives
// will be rendered as a fragment so its children must be
// converted into vnodes.
!(__COMPAT__ && node.tag === 'template'))))
) {
return
}
// pre-convert text nodes into createTextVNode(text) calls to avoid
// runtime normalization.
for (let i = 0; i < children.length; i++) {
const child = children[i]
if (isText(child) || child.type === NodeTypes.COMPOUND_EXPRESSION) {
const callArgs: CallExpression['arguments'] = []
// createTextVNode defaults to single whitespace, so if it is a
// single space the code could be an empty call to save bytes.
if (child.type !== NodeTypes.TEXT || child.content !== ' ') {
callArgs.push(child)
}
// mark dynamic text with flag so it gets patched inside a block
if (
!context.ssr &&
getConstantType(child, context) === ConstantTypes.NOT_CONSTANT
) {
callArgs.push(
PatchFlags.TEXT +
(__DEV__ ? ` /* ${PatchFlagNames[PatchFlags.TEXT]} */` : ``)
)
}
children[i] = {
type: NodeTypes.TEXT_CALL,
content: child,
loc: child.loc,
codegenNode: createCallExpression(
context.helper(CREATE_TEXT),
callArgs
)
}
}
}
}
}
}
|