![]() Server : Apache System : Linux server2.corals.io 4.18.0-348.2.1.el8_5.x86_64 #1 SMP Mon Nov 15 09:17:08 EST 2021 x86_64 User : corals ( 1002) PHP Version : 7.4.33 Disable Function : exec,passthru,shell_exec,system Directory : /home/corals/ts.corals.io/frontend/node_modules/@vue/compiler-core/dist/ |
'use strict'; Object.defineProperty(exports, '__esModule', { value: true }); var shared = require('@vue/shared'); var parser = require('@babel/parser'); var sourceMap = require('source-map'); var estreeWalker = require('estree-walker'); function defaultOnError(error) { throw error; } function defaultOnWarn(msg) { } function createCompilerError(code, loc, messages, additionalMessage) { const msg = (messages || errorMessages)[code] + (additionalMessage || ``) ; const error = new SyntaxError(String(msg)); error.code = code; error.loc = loc; return error; } const errorMessages = { // parse errors [0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */]: 'Illegal comment.', [1 /* CDATA_IN_HTML_CONTENT */]: 'CDATA section is allowed only in XML context.', [2 /* DUPLICATE_ATTRIBUTE */]: 'Duplicate attribute.', [3 /* END_TAG_WITH_ATTRIBUTES */]: 'End tag cannot have attributes.', [4 /* END_TAG_WITH_TRAILING_SOLIDUS */]: "Illegal '/' in tags.", [5 /* EOF_BEFORE_TAG_NAME */]: 'Unexpected EOF in tag.', [6 /* EOF_IN_CDATA */]: 'Unexpected EOF in CDATA section.', [7 /* EOF_IN_COMMENT */]: 'Unexpected EOF in comment.', [8 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */]: 'Unexpected EOF in script.', [9 /* EOF_IN_TAG */]: 'Unexpected EOF in tag.', [10 /* INCORRECTLY_CLOSED_COMMENT */]: 'Incorrectly closed comment.', [11 /* INCORRECTLY_OPENED_COMMENT */]: 'Incorrectly opened comment.', [12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */]: "Illegal tag name. Use '<' to print '<'.", [13 /* MISSING_ATTRIBUTE_VALUE */]: 'Attribute value was expected.', [14 /* MISSING_END_TAG_NAME */]: 'End tag name was expected.', [15 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */]: 'Whitespace was expected.', [16 /* NESTED_COMMENT */]: "Unexpected '<!--' in comment.", [17 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */]: 'Attribute name cannot contain U+0022 ("), U+0027 (\'), and U+003C (<).', [18 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */]: 'Unquoted attribute value cannot contain U+0022 ("), U+0027 (\'), U+003C (<), U+003D (=), and U+0060 (`).', [19 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */]: "Attribute name cannot start with '='.", [21 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */]: "'<?' is allowed only in XML context.", [20 /* UNEXPECTED_NULL_CHARACTER */]: `Unexpected null character.`, [22 /* UNEXPECTED_SOLIDUS_IN_TAG */]: "Illegal '/' in tags.", // Vue-specific parse errors [23 /* X_INVALID_END_TAG */]: 'Invalid end tag.', [24 /* X_MISSING_END_TAG */]: 'Element is missing end tag.', [25 /* X_MISSING_INTERPOLATION_END */]: 'Interpolation end sign was not found.', [27 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */]: 'End bracket for dynamic directive argument was not found. ' + 'Note that dynamic directive argument cannot contain spaces.', [26 /* X_MISSING_DIRECTIVE_NAME */]: 'Legal directive name was expected.', // transform errors [28 /* X_V_IF_NO_EXPRESSION */]: `v-if/v-else-if is missing expression.`, [29 /* X_V_IF_SAME_KEY */]: `v-if/else branches must use unique keys.`, [30 /* X_V_ELSE_NO_ADJACENT_IF */]: `v-else/v-else-if has no adjacent v-if or v-else-if.`, [31 /* X_V_FOR_NO_EXPRESSION */]: `v-for is missing expression.`, [32 /* X_V_FOR_MALFORMED_EXPRESSION */]: `v-for has invalid expression.`, [33 /* X_V_FOR_TEMPLATE_KEY_PLACEMENT */]: `<template v-for> key should be placed on the <template> tag.`, [34 /* X_V_BIND_NO_EXPRESSION */]: `v-bind is missing expression.`, [35 /* X_V_ON_NO_EXPRESSION */]: `v-on is missing expression.`, [36 /* X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET */]: `Unexpected custom directive on <slot> outlet.`, [37 /* X_V_SLOT_MIXED_SLOT_USAGE */]: `Mixed v-slot usage on both the component and nested <template>.` + `When there are multiple named slots, all slots should use <template> ` + `syntax to avoid scope ambiguity.`, [38 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */]: `Duplicate slot names found. `, [39 /* X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN */]: `Extraneous children found when component already has explicitly named ` + `default slot. These children will be ignored.`, [40 /* X_V_SLOT_MISPLACED */]: `v-slot can only be used on components or <template> tags.`, [41 /* X_V_MODEL_NO_EXPRESSION */]: `v-model is missing expression.`, [42 /* X_V_MODEL_MALFORMED_EXPRESSION */]: `v-model value must be a valid JavaScript member expression.`, [43 /* X_V_MODEL_ON_SCOPE_VARIABLE */]: `v-model cannot be used on v-for or v-slot scope variables because they are not writable.`, [44 /* X_INVALID_EXPRESSION */]: `Error parsing JavaScript expression: `, [45 /* X_KEEP_ALIVE_INVALID_CHILDREN */]: `<KeepAlive> expects exactly one child component.`, // generic errors [46 /* X_PREFIX_ID_NOT_SUPPORTED */]: `"prefixIdentifiers" option is not supported in this build of compiler.`, [47 /* X_MODULE_MODE_NOT_SUPPORTED */]: `ES module mode is not supported in this build of compiler.`, [48 /* X_CACHE_HANDLER_NOT_SUPPORTED */]: `"cacheHandlers" option is only supported when the "prefixIdentifiers" option is enabled.`, [49 /* X_SCOPE_ID_NOT_SUPPORTED */]: `"scopeId" option is only supported in module mode.`, // just to fulfill types [50 /* __EXTEND_POINT__ */]: `` }; const FRAGMENT = Symbol(``); const TELEPORT = Symbol(``); const SUSPENSE = Symbol(``); const KEEP_ALIVE = Symbol(``); const BASE_TRANSITION = Symbol(``); const OPEN_BLOCK = Symbol(``); const CREATE_BLOCK = Symbol(``); const CREATE_ELEMENT_BLOCK = Symbol(``); const CREATE_VNODE = Symbol(``); const CREATE_ELEMENT_VNODE = Symbol(``); const CREATE_COMMENT = Symbol(``); const CREATE_TEXT = Symbol(``); const CREATE_STATIC = Symbol(``); const RESOLVE_COMPONENT = Symbol(``); const RESOLVE_DYNAMIC_COMPONENT = Symbol(``); const RESOLVE_DIRECTIVE = Symbol(``); const RESOLVE_FILTER = Symbol(``); const WITH_DIRECTIVES = Symbol(``); const RENDER_LIST = Symbol(``); const RENDER_SLOT = Symbol(``); const CREATE_SLOTS = Symbol(``); const TO_DISPLAY_STRING = Symbol(``); const MERGE_PROPS = Symbol(``); const NORMALIZE_CLASS = Symbol(``); const NORMALIZE_STYLE = Symbol(``); const NORMALIZE_PROPS = Symbol(``); const GUARD_REACTIVE_PROPS = Symbol(``); const TO_HANDLERS = Symbol(``); const CAMELIZE = Symbol(``); const CAPITALIZE = Symbol(``); const TO_HANDLER_KEY = Symbol(``); const SET_BLOCK_TRACKING = Symbol(``); const PUSH_SCOPE_ID = Symbol(``); const POP_SCOPE_ID = Symbol(``); const WITH_CTX = Symbol(``); const UNREF = Symbol(``); const IS_REF = Symbol(``); const WITH_MEMO = Symbol(``); const IS_MEMO_SAME = Symbol(``); // Name mapping for runtime helpers that need to be imported from 'vue' in // generated code. Make sure these are correctly exported in the runtime! // Using `any` here because TS doesn't allow symbols as index type. const helperNameMap = { [FRAGMENT]: `Fragment`, [TELEPORT]: `Teleport`, [SUSPENSE]: `Suspense`, [KEEP_ALIVE]: `KeepAlive`, [BASE_TRANSITION]: `BaseTransition`, [OPEN_BLOCK]: `openBlock`, [CREATE_BLOCK]: `createBlock`, [CREATE_ELEMENT_BLOCK]: `createElementBlock`, [CREATE_VNODE]: `createVNode`, [CREATE_ELEMENT_VNODE]: `createElementVNode`, [CREATE_COMMENT]: `createCommentVNode`, [CREATE_TEXT]: `createTextVNode`, [CREATE_STATIC]: `createStaticVNode`, [RESOLVE_COMPONENT]: `resolveComponent`, [RESOLVE_DYNAMIC_COMPONENT]: `resolveDynamicComponent`, [RESOLVE_DIRECTIVE]: `resolveDirective`, [RESOLVE_FILTER]: `resolveFilter`, [WITH_DIRECTIVES]: `withDirectives`, [RENDER_LIST]: `renderList`, [RENDER_SLOT]: `renderSlot`, [CREATE_SLOTS]: `createSlots`, [TO_DISPLAY_STRING]: `toDisplayString`, [MERGE_PROPS]: `mergeProps`, [NORMALIZE_CLASS]: `normalizeClass`, [NORMALIZE_STYLE]: `normalizeStyle`, [NORMALIZE_PROPS]: `normalizeProps`, [GUARD_REACTIVE_PROPS]: `guardReactiveProps`, [TO_HANDLERS]: `toHandlers`, [CAMELIZE]: `camelize`, [CAPITALIZE]: `capitalize`, [TO_HANDLER_KEY]: `toHandlerKey`, [SET_BLOCK_TRACKING]: `setBlockTracking`, [PUSH_SCOPE_ID]: `pushScopeId`, [POP_SCOPE_ID]: `popScopeId`, [WITH_CTX]: `withCtx`, [UNREF]: `unref`, [IS_REF]: `isRef`, [WITH_MEMO]: `withMemo`, [IS_MEMO_SAME]: `isMemoSame` }; function registerRuntimeHelpers(helpers) { Object.getOwnPropertySymbols(helpers).forEach(s => { helperNameMap[s] = helpers[s]; }); } // AST Utilities --------------------------------------------------------------- // Some expressions, e.g. sequence and conditional expressions, are never // associated with template nodes, so their source locations are just a stub. // Container types like CompoundExpression also don't need a real location. const locStub = { source: '', start: { line: 1, column: 1, offset: 0 }, end: { line: 1, column: 1, offset: 0 } }; function createRoot(children, loc = locStub) { return { type: 0 /* ROOT */, children, helpers: [], components: [], directives: [], hoists: [], imports: [], cached: 0, temps: 0, codegenNode: undefined, loc }; } function createVNodeCall(context, tag, props, children, patchFlag, dynamicProps, directives, isBlock = false, disableTracking = false, isComponent = false, loc = locStub) { if (context) { if (isBlock) { context.helper(OPEN_BLOCK); context.helper(getVNodeBlockHelper(context.inSSR, isComponent)); } else { context.helper(getVNodeHelper(context.inSSR, isComponent)); } if (directives) { context.helper(WITH_DIRECTIVES); } } return { type: 13 /* VNODE_CALL */, tag, props, children, patchFlag, dynamicProps, directives, isBlock, disableTracking, isComponent, loc }; } function createArrayExpression(elements, loc = locStub) { return { type: 17 /* JS_ARRAY_EXPRESSION */, loc, elements }; } function createObjectExpression(properties, loc = locStub) { return { type: 15 /* JS_OBJECT_EXPRESSION */, loc, properties }; } function createObjectProperty(key, value) { return { type: 16 /* JS_PROPERTY */, loc: locStub, key: shared.isString(key) ? createSimpleExpression(key, true) : key, value }; } function createSimpleExpression(content, isStatic = false, loc = locStub, constType = 0 /* NOT_CONSTANT */) { return { type: 4 /* SIMPLE_EXPRESSION */, loc, content, isStatic, constType: isStatic ? 3 /* CAN_STRINGIFY */ : constType }; } function createInterpolation(content, loc) { return { type: 5 /* INTERPOLATION */, loc, content: shared.isString(content) ? createSimpleExpression(content, false, loc) : content }; } function createCompoundExpression(children, loc = locStub) { return { type: 8 /* COMPOUND_EXPRESSION */, loc, children }; } function createCallExpression(callee, args = [], loc = locStub) { return { type: 14 /* JS_CALL_EXPRESSION */, loc, callee, arguments: args }; } function createFunctionExpression(params, returns = undefined, newline = false, isSlot = false, loc = locStub) { return { type: 18 /* JS_FUNCTION_EXPRESSION */, params, returns, newline, isSlot, loc }; } function createConditionalExpression(test, consequent, alternate, newline = true) { return { type: 19 /* JS_CONDITIONAL_EXPRESSION */, test, consequent, alternate, newline, loc: locStub }; } function createCacheExpression(index, value, isVNode = false) { return { type: 20 /* JS_CACHE_EXPRESSION */, index, value, isVNode, loc: locStub }; } function createBlockStatement(body) { return { type: 21 /* JS_BLOCK_STATEMENT */, body, loc: locStub }; } function createTemplateLiteral(elements) { return { type: 22 /* JS_TEMPLATE_LITERAL */, elements, loc: locStub }; } function createIfStatement(test, consequent, alternate) { return { type: 23 /* JS_IF_STATEMENT */, test, consequent, alternate, loc: locStub }; } function createAssignmentExpression(left, right) { return { type: 24 /* JS_ASSIGNMENT_EXPRESSION */, left, right, loc: locStub }; } function createSequenceExpression(expressions) { return { type: 25 /* JS_SEQUENCE_EXPRESSION */, expressions, loc: locStub }; } function createReturnStatement(returns) { return { type: 26 /* JS_RETURN_STATEMENT */, returns, loc: locStub }; } const isStaticExp = (p) => p.type === 4 /* SIMPLE_EXPRESSION */ && p.isStatic; const isBuiltInType = (tag, expected) => tag === expected || tag === shared.hyphenate(expected); function isCoreComponent(tag) { if (isBuiltInType(tag, 'Teleport')) { return TELEPORT; } else if (isBuiltInType(tag, 'Suspense')) { return SUSPENSE; } else if (isBuiltInType(tag, 'KeepAlive')) { return KEEP_ALIVE; } else if (isBuiltInType(tag, 'BaseTransition')) { return BASE_TRANSITION; } } const nonIdentifierRE = /^\d|[^\$\w]/; const isSimpleIdentifier = (name) => !nonIdentifierRE.test(name); const validFirstIdentCharRE = /[A-Za-z_$\xA0-\uFFFF]/; const validIdentCharRE = /[\.\?\w$\xA0-\uFFFF]/; const whitespaceRE = /\s+[.[]\s*|\s*[.[]\s+/g; /** * Simple lexer to check if an expression is a member expression. This is * lax and only checks validity at the root level (i.e. does not validate exps * inside square brackets), but it's ok since these are only used on template * expressions and false positives are invalid expressions in the first place. */ const isMemberExpressionBrowser = (path) => { // remove whitespaces around . or [ first path = path.trim().replace(whitespaceRE, s => s.trim()); let state = 0 /* inMemberExp */; let stateStack = []; let currentOpenBracketCount = 0; let currentOpenParensCount = 0; let currentStringType = null; for (let i = 0; i < path.length; i++) { const char = path.charAt(i); switch (state) { case 0 /* inMemberExp */: if (char === '[') { stateStack.push(state); state = 1 /* inBrackets */; currentOpenBracketCount++; } else if (char === '(') { stateStack.push(state); state = 2 /* inParens */; currentOpenParensCount++; } else if (!(i === 0 ? validFirstIdentCharRE : validIdentCharRE).test(char)) { return false; } break; case 1 /* inBrackets */: if (char === `'` || char === `"` || char === '`') { stateStack.push(state); state = 3 /* inString */; currentStringType = char; } else if (char === `[`) { currentOpenBracketCount++; } else if (char === `]`) { if (!--currentOpenBracketCount) { state = stateStack.pop(); } } break; case 2 /* inParens */: if (char === `'` || char === `"` || char === '`') { stateStack.push(state); state = 3 /* inString */; currentStringType = char; } else if (char === `(`) { currentOpenParensCount++; } else if (char === `)`) { // if the exp ends as a call then it should not be considered valid if (i === path.length - 1) { return false; } if (!--currentOpenParensCount) { state = stateStack.pop(); } } break; case 3 /* inString */: if (char === currentStringType) { state = stateStack.pop(); currentStringType = null; } break; } } return !currentOpenBracketCount && !currentOpenParensCount; }; const isMemberExpressionNode = (path, context) => { try { let ret = parser.parseExpression(path, { plugins: context.expressionPlugins }); if (ret.type === 'TSAsExpression' || ret.type === 'TSTypeAssertion') { ret = ret.expression; } return (ret.type === 'MemberExpression' || ret.type === 'OptionalMemberExpression' || ret.type === 'Identifier'); } catch (e) { return false; } }; const isMemberExpression = isMemberExpressionNode; function getInnerRange(loc, offset, length) { const source = loc.source.slice(offset, offset + length); const newLoc = { source, start: advancePositionWithClone(loc.start, loc.source, offset), end: loc.end }; if (length != null) { newLoc.end = advancePositionWithClone(loc.start, loc.source, offset + length); } return newLoc; } function advancePositionWithClone(pos, source, numberOfCharacters = source.length) { return advancePositionWithMutation(shared.extend({}, pos), source, numberOfCharacters); } // advance by mutation without cloning (for performance reasons), since this // gets called a lot in the parser function advancePositionWithMutation(pos, source, numberOfCharacters = source.length) { let linesCount = 0; let lastNewLinePos = -1; for (let i = 0; i < numberOfCharacters; i++) { if (source.charCodeAt(i) === 10 /* newline char code */) { linesCount++; lastNewLinePos = i; } } pos.offset += numberOfCharacters; pos.line += linesCount; pos.column = lastNewLinePos === -1 ? pos.column + numberOfCharacters : numberOfCharacters - lastNewLinePos; return pos; } function assert(condition, msg) { /* istanbul ignore if */ if (!condition) { throw new Error(msg || `unexpected compiler condition`); } } function findDir(node, name, allowEmpty = false) { for (let i = 0; i < node.props.length; i++) { const p = node.props[i]; if (p.type === 7 /* DIRECTIVE */ && (allowEmpty || p.exp) && (shared.isString(name) ? p.name === name : name.test(p.name))) { return p; } } } function findProp(node, name, dynamicOnly = false, allowEmpty = false) { for (let i = 0; i < node.props.length; i++) { const p = node.props[i]; if (p.type === 6 /* ATTRIBUTE */) { if (dynamicOnly) continue; if (p.name === name && (p.value || allowEmpty)) { return p; } } else if (p.name === 'bind' && (p.exp || allowEmpty) && isStaticArgOf(p.arg, name)) { return p; } } } function isStaticArgOf(arg, name) { return !!(arg && isStaticExp(arg) && arg.content === name); } function hasDynamicKeyVBind(node) { return node.props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'bind' && (!p.arg || // v-bind="obj" p.arg.type !== 4 /* SIMPLE_EXPRESSION */ || // v-bind:[_ctx.foo] !p.arg.isStatic) // v-bind:[foo] ); } function isText(node) { return node.type === 5 /* INTERPOLATION */ || node.type === 2 /* TEXT */; } function isVSlot(p) { return p.type === 7 /* DIRECTIVE */ && p.name === 'slot'; } function isTemplateNode(node) { return (node.type === 1 /* ELEMENT */ && node.tagType === 3 /* TEMPLATE */); } function isSlotOutlet(node) { return node.type === 1 /* ELEMENT */ && node.tagType === 2 /* SLOT */; } function getVNodeHelper(ssr, isComponent) { return ssr || isComponent ? CREATE_VNODE : CREATE_ELEMENT_VNODE; } function getVNodeBlockHelper(ssr, isComponent) { return ssr || isComponent ? CREATE_BLOCK : CREATE_ELEMENT_BLOCK; } const propsHelperSet = new Set([NORMALIZE_PROPS, GUARD_REACTIVE_PROPS]); function getUnnormalizedProps(props, callPath = []) { if (props && !shared.isString(props) && props.type === 14 /* JS_CALL_EXPRESSION */) { const callee = props.callee; if (!shared.isString(callee) && propsHelperSet.has(callee)) { return getUnnormalizedProps(props.arguments[0], callPath.concat(props)); } } return [props, callPath]; } function injectProp(node, prop, context) { let propsWithInjection; /** * 1. mergeProps(...) * 2. toHandlers(...) * 3. normalizeProps(...) * 4. normalizeProps(guardReactiveProps(...)) * * we need to get the real props before normalization */ let props = node.type === 13 /* VNODE_CALL */ ? node.props : node.arguments[2]; let callPath = []; let parentCall; if (props && !shared.isString(props) && props.type === 14 /* JS_CALL_EXPRESSION */) { const ret = getUnnormalizedProps(props); props = ret[0]; callPath = ret[1]; parentCall = callPath[callPath.length - 1]; } if (props == null || shared.isString(props)) { propsWithInjection = createObjectExpression([prop]); } else if (props.type === 14 /* JS_CALL_EXPRESSION */) { // merged props... add ours // only inject key to object literal if it's the first argument so that // if doesn't override user provided keys const first = props.arguments[0]; if (!shared.isString(first) && first.type === 15 /* JS_OBJECT_EXPRESSION */) { first.properties.unshift(prop); } else { if (props.callee === TO_HANDLERS) { // #2366 propsWithInjection = createCallExpression(context.helper(MERGE_PROPS), [ createObjectExpression([prop]), props ]); } else { props.arguments.unshift(createObjectExpression([prop])); } } !propsWithInjection && (propsWithInjection = props); } else if (props.type === 15 /* JS_OBJECT_EXPRESSION */) { let alreadyExists = false; // check existing key to avoid overriding user provided keys if (prop.key.type === 4 /* SIMPLE_EXPRESSION */) { const propKeyName = prop.key.content; alreadyExists = props.properties.some(p => p.key.type === 4 /* SIMPLE_EXPRESSION */ && p.key.content === propKeyName); } if (!alreadyExists) { props.properties.unshift(prop); } propsWithInjection = props; } else { // single v-bind with expression, return a merged replacement propsWithInjection = createCallExpression(context.helper(MERGE_PROPS), [ createObjectExpression([prop]), props ]); // in the case of nested helper call, e.g. `normalizeProps(guardReactiveProps(props))`, // it will be rewritten as `normalizeProps(mergeProps({ key: 0 }, props))`, // the `guardReactiveProps` will no longer be needed if (parentCall && parentCall.callee === GUARD_REACTIVE_PROPS) { parentCall = callPath[callPath.length - 2]; } } if (node.type === 13 /* VNODE_CALL */) { if (parentCall) { parentCall.arguments[0] = propsWithInjection; } else { node.props = propsWithInjection; } } else { if (parentCall) { parentCall.arguments[0] = propsWithInjection; } else { node.arguments[2] = propsWithInjection; } } } function toValidAssetId(name, type) { // see issue#4422, we need adding identifier on validAssetId if variable `name` has specific character return `_${type}_${name.replace(/[^\w]/g, (searchValue, replaceValue) => { return searchValue === '-' ? '_' : name.charCodeAt(replaceValue).toString(); })}`; } // Check if a node contains expressions that reference current context scope ids function hasScopeRef(node, ids) { if (!node || Object.keys(ids).length === 0) { return false; } switch (node.type) { case 1 /* ELEMENT */: for (let i = 0; i < node.props.length; i++) { const p = node.props[i]; if (p.type === 7 /* DIRECTIVE */ && (hasScopeRef(p.arg, ids) || hasScopeRef(p.exp, ids))) { return true; } } return node.children.some(c => hasScopeRef(c, ids)); case 11 /* FOR */: if (hasScopeRef(node.source, ids)) { return true; } return node.children.some(c => hasScopeRef(c, ids)); case 9 /* IF */: return node.branches.some(b => hasScopeRef(b, ids)); case 10 /* IF_BRANCH */: if (hasScopeRef(node.condition, ids)) { return true; } return node.children.some(c => hasScopeRef(c, ids)); case 4 /* SIMPLE_EXPRESSION */: return (!node.isStatic && isSimpleIdentifier(node.content) && !!ids[node.content]); case 8 /* COMPOUND_EXPRESSION */: return node.children.some(c => shared.isObject(c) && hasScopeRef(c, ids)); case 5 /* INTERPOLATION */: case 12 /* TEXT_CALL */: return hasScopeRef(node.content, ids); case 2 /* TEXT */: case 3 /* COMMENT */: return false; default: return false; } } function getMemoedVNodeCall(node) { if (node.type === 14 /* JS_CALL_EXPRESSION */ && node.callee === WITH_MEMO) { return node.arguments[1].returns; } else { return node; } } function makeBlock(node, { helper, removeHelper, inSSR }) { if (!node.isBlock) { node.isBlock = true; removeHelper(getVNodeHelper(inSSR, node.isComponent)); helper(OPEN_BLOCK); helper(getVNodeBlockHelper(inSSR, node.isComponent)); } } const deprecationData = { ["COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */]: { message: `Platform-native elements with "is" prop will no longer be ` + `treated as components in Vue 3 unless the "is" value is explicitly ` + `prefixed with "vue:".`, link: `https://v3-migration.vuejs.org/breaking-changes/custom-elements-interop.html` }, ["COMPILER_V_BIND_SYNC" /* COMPILER_V_BIND_SYNC */]: { message: key => `.sync modifier for v-bind has been removed. Use v-model with ` + `argument instead. \`v-bind:${key}.sync\` should be changed to ` + `\`v-model:${key}\`.`, link: `https://v3-migration.vuejs.org/breaking-changes/v-model.html` }, ["COMPILER_V_BIND_PROP" /* COMPILER_V_BIND_PROP */]: { message: `.prop modifier for v-bind has been removed and no longer necessary. ` + `Vue 3 will automatically set a binding as DOM property when appropriate.` }, ["COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */]: { message: `v-bind="obj" usage is now order sensitive and behaves like JavaScript ` + `object spread: it will now overwrite an existing non-mergeable attribute ` + `that appears before v-bind in the case of conflict. ` + `To retain 2.x behavior, move v-bind to make it the first attribute. ` + `You can also suppress this warning if the usage is intended.`, link: `https://v3-migration.vuejs.org/breaking-changes/v-bind.html` }, ["COMPILER_V_ON_NATIVE" /* COMPILER_V_ON_NATIVE */]: { message: `.native modifier for v-on has been removed as is no longer necessary.`, link: `https://v3-migration.vuejs.org/breaking-changes/v-on-native-modifier-removed.html` }, ["COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */]: { message: `v-if / v-for precedence when used on the same element has changed ` + `in Vue 3: v-if now takes higher precedence and will no longer have ` + `access to v-for scope variables. It is best to avoid the ambiguity ` + `with <template> tags or use a computed property that filters v-for ` + `data source.`, link: `https://v3-migration.vuejs.org/breaking-changes/v-if-v-for.html` }, ["COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */]: { message: `<template> with no special directives will render as a native template ` + `element instead of its inner content in Vue 3.` }, ["COMPILER_INLINE_TEMPLATE" /* COMPILER_INLINE_TEMPLATE */]: { message: `"inline-template" has been removed in Vue 3.`, link: `https://v3-migration.vuejs.org/breaking-changes/inline-template-attribute.html` }, ["COMPILER_FILTER" /* COMPILER_FILTERS */]: { message: `filters have been removed in Vue 3. ` + `The "|" symbol will be treated as native JavaScript bitwise OR operator. ` + `Use method calls or computed properties instead.`, link: `https://v3-migration.vuejs.org/breaking-changes/filters.html` } }; function getCompatValue(key, context) { const config = context.options ? context.options.compatConfig : context.compatConfig; const value = config && config[key]; if (key === 'MODE') { return value || 3; // compiler defaults to v3 behavior } else { return value; } } function isCompatEnabled(key, context) { const mode = getCompatValue('MODE', context); const value = getCompatValue(key, context); // in v3 mode, only enable if explicitly set to true // otherwise enable for any non-false value return mode === 3 ? value === true : value !== false; } function checkCompatEnabled(key, context, loc, ...args) { const enabled = isCompatEnabled(key, context); return enabled; } function warnDeprecation(key, context, loc, ...args) { const val = getCompatValue(key, context); if (val === 'suppress-warning') { return; } const { message, link } = deprecationData[key]; const msg = `(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`; const err = new SyntaxError(msg); err.code = key; if (loc) err.loc = loc; context.onWarn(err); } // The default decoder only provides escapes for characters reserved as part of // the template syntax, and is only used if the custom renderer did not provide // a platform-specific decoder. const decodeRE = /&(gt|lt|amp|apos|quot);/g; const decodeMap = { gt: '>', lt: '<', amp: '&', apos: "'", quot: '"' }; const defaultParserOptions = { delimiters: [`{{`, `}}`], getNamespace: () => 0 /* HTML */, getTextMode: () => 0 /* DATA */, isVoidTag: shared.NO, isPreTag: shared.NO, isCustomElement: shared.NO, decodeEntities: (rawText) => rawText.replace(decodeRE, (_, p1) => decodeMap[p1]), onError: defaultOnError, onWarn: defaultOnWarn, comments: false }; function baseParse(content, options = {}) { const context = createParserContext(content, options); const start = getCursor(context); return createRoot(parseChildren(context, 0 /* DATA */, []), getSelection(context, start)); } function createParserContext(content, rawOptions) { const options = shared.extend({}, defaultParserOptions); let key; for (key in rawOptions) { // @ts-ignore options[key] = rawOptions[key] === undefined ? defaultParserOptions[key] : rawOptions[key]; } return { options, column: 1, line: 1, offset: 0, originalSource: content, source: content, inPre: false, inVPre: false, onWarn: options.onWarn }; } function parseChildren(context, mode, ancestors) { const parent = last(ancestors); const ns = parent ? parent.ns : 0 /* HTML */; const nodes = []; while (!isEnd(context, mode, ancestors)) { const s = context.source; let node = undefined; if (mode === 0 /* DATA */ || mode === 1 /* RCDATA */) { if (!context.inVPre && startsWith(s, context.options.delimiters[0])) { // '{{' node = parseInterpolation(context, mode); } else if (mode === 0 /* DATA */ && s[0] === '<') { // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state if (s.length === 1) { emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 1); } else if (s[1] === '!') { // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state if (startsWith(s, '<!--')) { node = parseComment(context); } else if (startsWith(s, '<!DOCTYPE')) { // Ignore DOCTYPE by a limitation. node = parseBogusComment(context); } else if (startsWith(s, '<![CDATA[')) { if (ns !== 0 /* HTML */) { node = parseCDATA(context, ancestors); } else { emitError(context, 1 /* CDATA_IN_HTML_CONTENT */); node = parseBogusComment(context); } } else { emitError(context, 11 /* INCORRECTLY_OPENED_COMMENT */); node = parseBogusComment(context); } } else if (s[1] === '/') { // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state if (s.length === 2) { emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 2); } else if (s[2] === '>') { emitError(context, 14 /* MISSING_END_TAG_NAME */, 2); advanceBy(context, 3); continue; } else if (/[a-z]/i.test(s[2])) { emitError(context, 23 /* X_INVALID_END_TAG */); parseTag(context, 1 /* End */, parent); continue; } else { emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 2); node = parseBogusComment(context); } } else if (/[a-z]/i.test(s[1])) { node = parseElement(context, ancestors); // 2.x <template> with no directive compat if (isCompatEnabled("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context) && node && node.tag === 'template' && !node.props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) { node = node.children; } } else if (s[1] === '?') { emitError(context, 21 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */, 1); node = parseBogusComment(context); } else { emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 1); } } } if (!node) { node = parseText(context, mode); } if (shared.isArray(node)) { for (let i = 0; i < node.length; i++) { pushNode(nodes, node[i]); } } else { pushNode(nodes, node); } } // Whitespace handling strategy like v2 let removedWhitespace = false; if (mode !== 2 /* RAWTEXT */ && mode !== 1 /* RCDATA */) { const shouldCondense = context.options.whitespace !== 'preserve'; for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; if (!context.inPre && node.type === 2 /* TEXT */) { if (!/[^\t\r\n\f ]/.test(node.content)) { const prev = nodes[i - 1]; const next = nodes[i + 1]; // Remove if: // - the whitespace is the first or last node, or: // - (condense mode) the whitespace is adjacent to a comment, or: // - (condense mode) the whitespace is between two elements AND contains newline if (!prev || !next || (shouldCondense && (prev.type === 3 /* COMMENT */ || next.type === 3 /* COMMENT */ || (prev.type === 1 /* ELEMENT */ && next.type === 1 /* ELEMENT */ && /[\r\n]/.test(node.content))))) { removedWhitespace = true; nodes[i] = null; } else { // Otherwise, the whitespace is condensed into a single space node.content = ' '; } } else if (shouldCondense) { // in condense mode, consecutive whitespaces in text are condensed // down to a single space. node.content = node.content.replace(/[\t\r\n\f ]+/g, ' '); } } // Remove comment nodes if desired by configuration. else if (node.type === 3 /* COMMENT */ && !context.options.comments) { removedWhitespace = true; nodes[i] = null; } } if (context.inPre && parent && context.options.isPreTag(parent.tag)) { // remove leading newline per html spec // https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element const first = nodes[0]; if (first && first.type === 2 /* TEXT */) { first.content = first.content.replace(/^\r?\n/, ''); } } } return removedWhitespace ? nodes.filter(Boolean) : nodes; } function pushNode(nodes, node) { if (node.type === 2 /* TEXT */) { const prev = last(nodes); // Merge if both this and the previous node are text and those are // consecutive. This happens for cases like "a < b". if (prev && prev.type === 2 /* TEXT */ && prev.loc.end.offset === node.loc.start.offset) { prev.content += node.content; prev.loc.end = node.loc.end; prev.loc.source += node.loc.source; return; } } nodes.push(node); } function parseCDATA(context, ancestors) { advanceBy(context, 9); const nodes = parseChildren(context, 3 /* CDATA */, ancestors); if (context.source.length === 0) { emitError(context, 6 /* EOF_IN_CDATA */); } else { advanceBy(context, 3); } return nodes; } function parseComment(context) { const start = getCursor(context); let content; // Regular comment. const match = /--(\!)?>/.exec(context.source); if (!match) { content = context.source.slice(4); advanceBy(context, context.source.length); emitError(context, 7 /* EOF_IN_COMMENT */); } else { if (match.index <= 3) { emitError(context, 0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */); } if (match[1]) { emitError(context, 10 /* INCORRECTLY_CLOSED_COMMENT */); } content = context.source.slice(4, match.index); // Advancing with reporting nested comments. const s = context.source.slice(0, match.index); let prevIndex = 1, nestedIndex = 0; while ((nestedIndex = s.indexOf('<!--', prevIndex)) !== -1) { advanceBy(context, nestedIndex - prevIndex + 1); if (nestedIndex + 4 < s.length) { emitError(context, 16 /* NESTED_COMMENT */); } prevIndex = nestedIndex + 1; } advanceBy(context, match.index + match[0].length - prevIndex + 1); } return { type: 3 /* COMMENT */, content, loc: getSelection(context, start) }; } function parseBogusComment(context) { const start = getCursor(context); const contentStart = context.source[1] === '?' ? 1 : 2; let content; const closeIndex = context.source.indexOf('>'); if (closeIndex === -1) { content = context.source.slice(contentStart); advanceBy(context, context.source.length); } else { content = context.source.slice(contentStart, closeIndex); advanceBy(context, closeIndex + 1); } return { type: 3 /* COMMENT */, content, loc: getSelection(context, start) }; } function parseElement(context, ancestors) { // Start tag. const wasInPre = context.inPre; const wasInVPre = context.inVPre; const parent = last(ancestors); const element = parseTag(context, 0 /* Start */, parent); const isPreBoundary = context.inPre && !wasInPre; const isVPreBoundary = context.inVPre && !wasInVPre; if (element.isSelfClosing || context.options.isVoidTag(element.tag)) { // #4030 self-closing <pre> tag if (isPreBoundary) { context.inPre = false; } if (isVPreBoundary) { context.inVPre = false; } return element; } // Children. ancestors.push(element); const mode = context.options.getTextMode(element, parent); const children = parseChildren(context, mode, ancestors); ancestors.pop(); // 2.x inline-template compat { const inlineTemplateProp = element.props.find(p => p.type === 6 /* ATTRIBUTE */ && p.name === 'inline-template'); if (inlineTemplateProp && checkCompatEnabled("COMPILER_INLINE_TEMPLATE" /* COMPILER_INLINE_TEMPLATE */, context, inlineTemplateProp.loc)) { const loc = getSelection(context, element.loc.end); inlineTemplateProp.value = { type: 2 /* TEXT */, content: loc.source, loc }; } } element.children = children; // End tag. if (startsWithEndTagOpen(context.source, element.tag)) { parseTag(context, 1 /* End */, parent); } else { emitError(context, 24 /* X_MISSING_END_TAG */, 0, element.loc.start); if (context.source.length === 0 && element.tag.toLowerCase() === 'script') { const first = children[0]; if (first && startsWith(first.loc.source, '<!--')) { emitError(context, 8 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */); } } } element.loc = getSelection(context, element.loc.start); if (isPreBoundary) { context.inPre = false; } if (isVPreBoundary) { context.inVPre = false; } return element; } const isSpecialTemplateDirective = /*#__PURE__*/ shared.makeMap(`if,else,else-if,for,slot`); function parseTag(context, type, parent) { // Tag open. const start = getCursor(context); const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source); const tag = match[1]; const ns = context.options.getNamespace(tag, parent); advanceBy(context, match[0].length); advanceSpaces(context); // save current state in case we need to re-parse attributes with v-pre const cursor = getCursor(context); const currentSource = context.source; // check <pre> tag if (context.options.isPreTag(tag)) { context.inPre = true; } // Attributes. let props = parseAttributes(context, type); // check v-pre if (type === 0 /* Start */ && !context.inVPre && props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'pre')) { context.inVPre = true; // reset context shared.extend(context, cursor); context.source = currentSource; // re-parse attrs and filter out v-pre itself props = parseAttributes(context, type).filter(p => p.name !== 'v-pre'); } // Tag close. let isSelfClosing = false; if (context.source.length === 0) { emitError(context, 9 /* EOF_IN_TAG */); } else { isSelfClosing = startsWith(context.source, '/>'); if (type === 1 /* End */ && isSelfClosing) { emitError(context, 4 /* END_TAG_WITH_TRAILING_SOLIDUS */); } advanceBy(context, isSelfClosing ? 2 : 1); } if (type === 1 /* End */) { return; } let tagType = 0 /* ELEMENT */; if (!context.inVPre) { if (tag === 'slot') { tagType = 2 /* SLOT */; } else if (tag === 'template') { if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) { tagType = 3 /* TEMPLATE */; } } else if (isComponent(tag, props, context)) { tagType = 1 /* COMPONENT */; } } return { type: 1 /* ELEMENT */, ns, tag, tagType, props, isSelfClosing, children: [], loc: getSelection(context, start), codegenNode: undefined // to be created during transform phase }; } function isComponent(tag, props, context) { const options = context.options; if (options.isCustomElement(tag)) { return false; } if (tag === 'component' || /^[A-Z]/.test(tag) || isCoreComponent(tag) || (options.isBuiltInComponent && options.isBuiltInComponent(tag)) || (options.isNativeTag && !options.isNativeTag(tag))) { return true; } // at this point the tag should be a native tag, but check for potential "is" // casting for (let i = 0; i < props.length; i++) { const p = props[i]; if (p.type === 6 /* ATTRIBUTE */) { if (p.name === 'is' && p.value) { if (p.value.content.startsWith('vue:')) { return true; } else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) { return true; } } } else { // directive // v-is (TODO Deprecate) if (p.name === 'is') { return true; } else if ( // :is on plain element - only treat as component in compat mode p.name === 'bind' && isStaticArgOf(p.arg, 'is') && true && checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) { return true; } } } } function parseAttributes(context, type) { const props = []; const attributeNames = new Set(); while (context.source.length > 0 && !startsWith(context.source, '>') && !startsWith(context.source, '/>')) { if (startsWith(context.source, '/')) { emitError(context, 22 /* UNEXPECTED_SOLIDUS_IN_TAG */); advanceBy(context, 1); advanceSpaces(context); continue; } if (type === 1 /* End */) { emitError(context, 3 /* END_TAG_WITH_ATTRIBUTES */); } const attr = parseAttribute(context, attributeNames); // Trim whitespace between class // https://github.com/vuejs/core/issues/4251 if (attr.type === 6 /* ATTRIBUTE */ && attr.value && attr.name === 'class') { attr.value.content = attr.value.content.replace(/\s+/g, ' ').trim(); } if (type === 0 /* Start */) { props.push(attr); } if (/^[^\t\r\n\f />]/.test(context.source)) { emitError(context, 15 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */); } advanceSpaces(context); } return props; } function parseAttribute(context, nameSet) { // Name. const start = getCursor(context); const match = /^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(context.source); const name = match[0]; if (nameSet.has(name)) { emitError(context, 2 /* DUPLICATE_ATTRIBUTE */); } nameSet.add(name); if (name[0] === '=') { emitError(context, 19 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */); } { const pattern = /["'<]/g; let m; while ((m = pattern.exec(name))) { emitError(context, 17 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */, m.index); } } advanceBy(context, name.length); // Value let value = undefined; if (/^[\t\r\n\f ]*=/.test(context.source)) { advanceSpaces(context); advanceBy(context, 1); advanceSpaces(context); value = parseAttributeValue(context); if (!value) { emitError(context, 13 /* MISSING_ATTRIBUTE_VALUE */); } } const loc = getSelection(context, start); if (!context.inVPre && /^(v-[A-Za-z0-9-]|:|\.|@|#)/.test(name)) { const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^\.|^@|^#)(\[[^\]]+\]|[^\.]+))?(.+)?$/i.exec(name); let isPropShorthand = startsWith(name, '.'); let dirName = match[1] || (isPropShorthand || startsWith(name, ':') ? 'bind' : startsWith(name, '@') ? 'on' : 'slot'); let arg; if (match[2]) { const isSlot = dirName === 'slot'; const startOffset = name.lastIndexOf(match[2]); const loc = getSelection(context, getNewPosition(context, start, startOffset), getNewPosition(context, start, startOffset + match[2].length + ((isSlot && match[3]) || '').length)); let content = match[2]; let isStatic = true; if (content.startsWith('[')) { isStatic = false; if (!content.endsWith(']')) { emitError(context, 27 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */); content = content.slice(1); } else { content = content.slice(1, content.length - 1); } } else if (isSlot) { // #1241 special case for v-slot: vuetify relies extensively on slot // names containing dots. v-slot doesn't have any modifiers and Vue 2.x // supports such usage so we are keeping it consistent with 2.x. content += match[3] || ''; } arg = { type: 4 /* SIMPLE_EXPRESSION */, content, isStatic, constType: isStatic ? 3 /* CAN_STRINGIFY */ : 0 /* NOT_CONSTANT */, loc }; } if (value && value.isQuoted) { const valueLoc = value.loc; valueLoc.start.offset++; valueLoc.start.column++; valueLoc.end = advancePositionWithClone(valueLoc.start, value.content); valueLoc.source = valueLoc.source.slice(1, -1); } const modifiers = match[3] ? match[3].slice(1).split('.') : []; if (isPropShorthand) modifiers.push('prop'); // 2.x compat v-bind:foo.sync -> v-model:foo if (dirName === 'bind' && arg) { if (modifiers.includes('sync') && checkCompatEnabled("COMPILER_V_BIND_SYNC" /* COMPILER_V_BIND_SYNC */, context, loc, arg.loc.source)) { dirName = 'model'; modifiers.splice(modifiers.indexOf('sync'), 1); } } return { type: 7 /* DIRECTIVE */, name: dirName, exp: value && { type: 4 /* SIMPLE_EXPRESSION */, content: value.content, isStatic: false, // Treat as non-constant by default. This can be potentially set to // other values by `transformExpression` to make it eligible for hoisting. constType: 0 /* NOT_CONSTANT */, loc: value.loc }, arg, modifiers, loc }; } // missing directive name or illegal directive name if (!context.inVPre && startsWith(name, 'v-')) { emitError(context, 26 /* X_MISSING_DIRECTIVE_NAME */); } return { type: 6 /* ATTRIBUTE */, name, value: value && { type: 2 /* TEXT */, content: value.content, loc: value.loc }, loc }; } function parseAttributeValue(context) { const start = getCursor(context); let content; const quote = context.source[0]; const isQuoted = quote === `"` || quote === `'`; if (isQuoted) { // Quoted value. advanceBy(context, 1); const endIndex = context.source.indexOf(quote); if (endIndex === -1) { content = parseTextData(context, context.source.length, 4 /* ATTRIBUTE_VALUE */); } else { content = parseTextData(context, endIndex, 4 /* ATTRIBUTE_VALUE */); advanceBy(context, 1); } } else { // Unquoted const match = /^[^\t\r\n\f >]+/.exec(context.source); if (!match) { return undefined; } const unexpectedChars = /["'<=`]/g; let m; while ((m = unexpectedChars.exec(match[0]))) { emitError(context, 18 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */, m.index); } content = parseTextData(context, match[0].length, 4 /* ATTRIBUTE_VALUE */); } return { content, isQuoted, loc: getSelection(context, start) }; } function parseInterpolation(context, mode) { const [open, close] = context.options.delimiters; const closeIndex = context.source.indexOf(close, open.length); if (closeIndex === -1) { emitError(context, 25 /* X_MISSING_INTERPOLATION_END */); return undefined; } const start = getCursor(context); advanceBy(context, open.length); const innerStart = getCursor(context); const innerEnd = getCursor(context); const rawContentLength = closeIndex - open.length; const rawContent = context.source.slice(0, rawContentLength); const preTrimContent = parseTextData(context, rawContentLength, mode); const content = preTrimContent.trim(); const startOffset = preTrimContent.indexOf(content); if (startOffset > 0) { advancePositionWithMutation(innerStart, rawContent, startOffset); } const endOffset = rawContentLength - (preTrimContent.length - content.length - startOffset); advancePositionWithMutation(innerEnd, rawContent, endOffset); advanceBy(context, close.length); return { type: 5 /* INTERPOLATION */, content: { type: 4 /* SIMPLE_EXPRESSION */, isStatic: false, // Set `isConstant` to false by default and will decide in transformExpression constType: 0 /* NOT_CONSTANT */, content, loc: getSelection(context, innerStart, innerEnd) }, loc: getSelection(context, start) }; } function parseText(context, mode) { const endTokens = mode === 3 /* CDATA */ ? [']]>'] : ['<', context.options.delimiters[0]]; let endIndex = context.source.length; for (let i = 0; i < endTokens.length; i++) { const index = context.source.indexOf(endTokens[i], 1); if (index !== -1 && endIndex > index) { endIndex = index; } } const start = getCursor(context); const content = parseTextData(context, endIndex, mode); return { type: 2 /* TEXT */, content, loc: getSelection(context, start) }; } /** * Get text data with a given length from the current location. * This translates HTML entities in the text data. */ function parseTextData(context, length, mode) { const rawText = context.source.slice(0, length); advanceBy(context, length); if (mode === 2 /* RAWTEXT */ || mode === 3 /* CDATA */ || !rawText.includes('&')) { return rawText; } else { // DATA or RCDATA containing "&"". Entity decoding required. return context.options.decodeEntities(rawText, mode === 4 /* ATTRIBUTE_VALUE */); } } function getCursor(context) { const { column, line, offset } = context; return { column, line, offset }; } function getSelection(context, start, end) { end = end || getCursor(context); return { start, end, source: context.originalSource.slice(start.offset, end.offset) }; } function last(xs) { return xs[xs.length - 1]; } function startsWith(source, searchString) { return source.startsWith(searchString); } function advanceBy(context, numberOfCharacters) { const { source } = context; advancePositionWithMutation(context, source, numberOfCharacters); context.source = source.slice(numberOfCharacters); } function advanceSpaces(context) { const match = /^[\t\r\n\f ]+/.exec(context.source); if (match) { advanceBy(context, match[0].length); } } function getNewPosition(context, start, numberOfCharacters) { return advancePositionWithClone(start, context.originalSource.slice(start.offset, numberOfCharacters), numberOfCharacters); } function emitError(context, code, offset, loc = getCursor(context)) { if (offset) { loc.offset += offset; loc.column += offset; } context.options.onError(createCompilerError(code, { start: loc, end: loc, source: '' })); } function isEnd(context, mode, ancestors) { const s = context.source; switch (mode) { case 0 /* DATA */: if (startsWith(s, '</')) { // TODO: probably bad performance for (let i = ancestors.length - 1; i >= 0; --i) { if (startsWithEndTagOpen(s, ancestors[i].tag)) { return true; } } } break; case 1 /* RCDATA */: case 2 /* RAWTEXT */: { const parent = last(ancestors); if (parent && startsWithEndTagOpen(s, parent.tag)) { return true; } break; } case 3 /* CDATA */: if (startsWith(s, ']]>')) { return true; } break; } return !s; } function startsWithEndTagOpen(source, tag) { return (startsWith(source, '</') && source.slice(2, 2 + tag.length).toLowerCase() === tag.toLowerCase() && /[\t\r\n\f />]/.test(source[2 + tag.length] || '>')); } function hoistStatic(root, context) { walk(root, context, // Root node is unfortunately non-hoistable due to potential parent // fallthrough attributes. isSingleElementRoot(root, root.children[0])); } function isSingleElementRoot(root, child) { const { children } = root; return (children.length === 1 && child.type === 1 /* ELEMENT */ && !isSlotOutlet(child)); } function walk(node, context, doNotHoistNode = false) { const { children } = node; const originalCount = children.length; let hoistedCount = 0; for (let i = 0; i < children.length; i++) { const child = children[i]; // only plain elements & text calls are eligible for hoisting. if (child.type === 1 /* ELEMENT */ && child.tagType === 0 /* ELEMENT */) { const constantType = doNotHoistNode ? 0 /* NOT_CONSTANT */ : getConstantType(child, context); if (constantType > 0 /* NOT_CONSTANT */) { if (constantType >= 2 /* CAN_HOIST */) { child.codegenNode.patchFlag = -1 /* HOISTED */ + (``); child.codegenNode = context.hoist(child.codegenNode); hoistedCount++; continue; } } else { // node may contain dynamic children, but its props may be eligible for // hoisting. const codegenNode = child.codegenNode; if (codegenNode.type === 13 /* VNODE_CALL */) { const flag = getPatchFlag(codegenNode); if ((!flag || flag === 512 /* NEED_PATCH */ || flag === 1 /* TEXT */) && getGeneratedPropsConstantType(child, context) >= 2 /* CAN_HOIST */) { const props = getNodeProps(child); if (props) { codegenNode.props = context.hoist(props); } } if (codegenNode.dynamicProps) { codegenNode.dynamicProps = context.hoist(codegenNode.dynamicProps); } } } } else if (child.type === 12 /* TEXT_CALL */ && getConstantType(child.content, context) >= 2 /* CAN_HOIST */) { child.codegenNode = context.hoist(child.codegenNode); hoistedCount++; } // walk further if (child.type === 1 /* ELEMENT */) { const isComponent = child.tagType === 1 /* COMPONENT */; if (isComponent) { context.scopes.vSlot++; } walk(child, context); if (isComponent) { context.scopes.vSlot--; } } else if (child.type === 11 /* FOR */) { // Do not hoist v-for single child because it has to be a block walk(child, context, child.children.length === 1); } else if (child.type === 9 /* IF */) { for (let i = 0; i < child.branches.length; i++) { // Do not hoist v-if single child because it has to be a block walk(child.branches[i], context, child.branches[i].children.length === 1); } } } if (hoistedCount && context.transformHoist) { context.transformHoist(children, context, node); } // all children were hoisted - the entire children array is hoistable. if (hoistedCount && hoistedCount === originalCount && node.type === 1 /* ELEMENT */ && node.tagType === 0 /* ELEMENT */ && node.codegenNode && node.codegenNode.type === 13 /* VNODE_CALL */ && shared.isArray(node.codegenNode.children)) { node.codegenNode.children = context.hoist(createArrayExpression(node.codegenNode.children)); } } function getConstantType(node, context) { const { constantCache } = context; switch (node.type) { case 1 /* ELEMENT */: if (node.tagType !== 0 /* ELEMENT */) { return 0 /* NOT_CONSTANT */; } const cached = constantCache.get(node); if (cached !== undefined) { return cached; } const codegenNode = node.codegenNode; if (codegenNode.type !== 13 /* VNODE_CALL */) { return 0 /* NOT_CONSTANT */; } if (codegenNode.isBlock && node.tag !== 'svg' && node.tag !== 'foreignObject') { return 0 /* NOT_CONSTANT */; } const flag = getPatchFlag(codegenNode); if (!flag) { let returnType = 3 /* CAN_STRINGIFY */; // Element itself has no patch flag. However we still need to check: // 1. Even for a node with no patch flag, it is possible for it to contain // non-hoistable expressions that refers to scope variables, e.g. compiler // injected keys or cached event handlers. Therefore we need to always // check the codegenNode's props to be sure. const generatedPropsType = getGeneratedPropsConstantType(node, context); if (generatedPropsType === 0 /* NOT_CONSTANT */) { constantCache.set(node, 0 /* NOT_CONSTANT */); return 0 /* NOT_CONSTANT */; } if (generatedPropsType < returnType) { returnType = generatedPropsType; } // 2. its children. for (let i = 0; i < node.children.length; i++) { const childType = getConstantType(node.children[i], context); if (childType === 0 /* NOT_CONSTANT */) { constantCache.set(node, 0 /* NOT_CONSTANT */); return 0 /* NOT_CONSTANT */; } if (childType < returnType) { returnType = childType; } } // 3. if the type is not already CAN_SKIP_PATCH which is the lowest non-0 // type, check if any of the props can cause the type to be lowered // we can skip can_patch because it's guaranteed by the absence of a // patchFlag. if (returnType > 1 /* CAN_SKIP_PATCH */) { for (let i = 0; i < node.props.length; i++) { const p = node.props[i]; if (p.type === 7 /* DIRECTIVE */ && p.name === 'bind' && p.exp) { const expType = getConstantType(p.exp, context); if (expType === 0 /* NOT_CONSTANT */) { constantCache.set(node, 0 /* NOT_CONSTANT */); return 0 /* NOT_CONSTANT */; } if (expType < returnType) { returnType = expType; } } } } // only svg/foreignObject could be block here, however if they are // static then they don't need to be blocks since there will be no // nested updates. if (codegenNode.isBlock) { context.removeHelper(OPEN_BLOCK); context.removeHelper(getVNodeBlockHelper(context.inSSR, codegenNode.isComponent)); codegenNode.isBlock = false; context.helper(getVNodeHelper(context.inSSR, codegenNode.isComponent)); } constantCache.set(node, returnType); return returnType; } else { constantCache.set(node, 0 /* NOT_CONSTANT */); return 0 /* NOT_CONSTANT */; } case 2 /* TEXT */: case 3 /* COMMENT */: return 3 /* CAN_STRINGIFY */; case 9 /* IF */: case 11 /* FOR */: case 10 /* IF_BRANCH */: return 0 /* NOT_CONSTANT */; case 5 /* INTERPOLATION */: case 12 /* TEXT_CALL */: return getConstantType(node.content, context); case 4 /* SIMPLE_EXPRESSION */: return node.constType; case 8 /* COMPOUND_EXPRESSION */: let returnType = 3 /* CAN_STRINGIFY */; for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; if (shared.isString(child) || shared.isSymbol(child)) { continue; } const childType = getConstantType(child, context); if (childType === 0 /* NOT_CONSTANT */) { return 0 /* NOT_CONSTANT */; } else if (childType < returnType) { returnType = childType; } } return returnType; default: return 0 /* NOT_CONSTANT */; } } const allowHoistedHelperSet = new Set([ NORMALIZE_CLASS, NORMALIZE_STYLE, NORMALIZE_PROPS, GUARD_REACTIVE_PROPS ]); function getConstantTypeOfHelperCall(value, context) { if (value.type === 14 /* JS_CALL_EXPRESSION */ && !shared.isString(value.callee) && allowHoistedHelperSet.has(value.callee)) { const arg = value.arguments[0]; if (arg.type === 4 /* SIMPLE_EXPRESSION */) { return getConstantType(arg, context); } else if (arg.type === 14 /* JS_CALL_EXPRESSION */) { // in the case of nested helper call, e.g. `normalizeProps(guardReactiveProps(exp))` return getConstantTypeOfHelperCall(arg, context); } } return 0 /* NOT_CONSTANT */; } function getGeneratedPropsConstantType(node, context) { let returnType = 3 /* CAN_STRINGIFY */; const props = getNodeProps(node); if (props && props.type === 15 /* JS_OBJECT_EXPRESSION */) { const { properties } = props; for (let i = 0; i < properties.length; i++) { const { key, value } = properties[i]; const keyType = getConstantType(key, context); if (keyType === 0 /* NOT_CONSTANT */) { return keyType; } if (keyType < returnType) { returnType = keyType; } let valueType; if (value.type === 4 /* SIMPLE_EXPRESSION */) { valueType = getConstantType(value, context); } else if (value.type === 14 /* JS_CALL_EXPRESSION */) { // some helper calls can be hoisted, // such as the `normalizeProps` generated by the compiler for pre-normalize class, // in this case we need to respect the ConstantType of the helper's arguments valueType = getConstantTypeOfHelperCall(value, context); } else { valueType = 0 /* NOT_CONSTANT */; } if (valueType === 0 /* NOT_CONSTANT */) { return valueType; } if (valueType < returnType) { returnType = valueType; } } } return returnType; } function getNodeProps(node) { const codegenNode = node.codegenNode; if (codegenNode.type === 13 /* VNODE_CALL */) { return codegenNode.props; } } function getPatchFlag(node) { const flag = node.patchFlag; return flag ? parseInt(flag, 10) : undefined; } function createTransformContext(root, { filename = '', prefixIdentifiers = false, hoistStatic = false, cacheHandlers = false, nodeTransforms = [], directiveTransforms = {}, transformHoist = null, isBuiltInComponent = shared.NOOP, isCustomElement = shared.NOOP, expressionPlugins = [], scopeId = null, slotted = true, ssr = false, inSSR = false, ssrCssVars = ``, bindingMetadata = shared.EMPTY_OBJ, inline = false, isTS = false, onError = defaultOnError, onWarn = defaultOnWarn, compatConfig }) { const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/); const context = { // options selfName: nameMatch && shared.capitalize(shared.camelize(nameMatch[1])), prefixIdentifiers, hoistStatic, cacheHandlers, nodeTransforms, directiveTransforms, transformHoist, isBuiltInComponent, isCustomElement, expressionPlugins, scopeId, slotted, ssr, inSSR, ssrCssVars, bindingMetadata, inline, isTS, onError, onWarn, compatConfig, // state root, helpers: new Map(), components: new Set(), directives: new Set(), hoists: [], imports: [], constantCache: new Map(), temps: 0, cached: 0, identifiers: Object.create(null), scopes: { vFor: 0, vSlot: 0, vPre: 0, vOnce: 0 }, parent: null, currentNode: root, childIndex: 0, inVOnce: false, // methods helper(name) { const count = context.helpers.get(name) || 0; context.helpers.set(name, count + 1); return name; }, removeHelper(name) { const count = context.helpers.get(name); if (count) { const currentCount = count - 1; if (!currentCount) { context.helpers.delete(name); } else { context.helpers.set(name, currentCount); } } }, helperString(name) { return `_${helperNameMap[context.helper(name)]}`; }, replaceNode(node) { context.parent.children[context.childIndex] = context.currentNode = node; }, removeNode(node) { const list = context.parent.children; const removalIndex = node ? list.indexOf(node) : context.currentNode ? context.childIndex : -1; if (!node || node === context.currentNode) { // current node removed context.currentNode = null; context.onNodeRemoved(); } else { // sibling node removed if (context.childIndex > removalIndex) { context.childIndex--; context.onNodeRemoved(); } } context.parent.children.splice(removalIndex, 1); }, onNodeRemoved: () => { }, addIdentifiers(exp) { // identifier tracking only happens in non-browser builds. { if (shared.isString(exp)) { addId(exp); } else if (exp.identifiers) { exp.identifiers.forEach(addId); } else if (exp.type === 4 /* SIMPLE_EXPRESSION */) { addId(exp.content); } } }, removeIdentifiers(exp) { { if (shared.isString(exp)) { removeId(exp); } else if (exp.identifiers) { exp.identifiers.forEach(removeId); } else if (exp.type === 4 /* SIMPLE_EXPRESSION */) { removeId(exp.content); } } }, hoist(exp) { if (shared.isString(exp)) exp = createSimpleExpression(exp); context.hoists.push(exp); const identifier = createSimpleExpression(`_hoisted_${context.hoists.length}`, false, exp.loc, 2 /* CAN_HOIST */); identifier.hoisted = exp; return identifier; }, cache(exp, isVNode = false) { return createCacheExpression(context.cached++, exp, isVNode); } }; { context.filters = new Set(); } function addId(id) { const { identifiers } = context; if (identifiers[id] === undefined) { identifiers[id] = 0; } identifiers[id]++; } function removeId(id) { context.identifiers[id]--; } return context; } function transform(root, options) { const context = createTransformContext(root, options); traverseNode(root, context); if (options.hoistStatic) { hoistStatic(root, context); } if (!options.ssr) { createRootCodegen(root, context); } // finalize meta information root.helpers = [...context.helpers.keys()]; root.components = [...context.components]; root.directives = [...context.directives]; root.imports = context.imports; root.hoists = context.hoists; root.temps = context.temps; root.cached = context.cached; { root.filters = [...context.filters]; } } function createRootCodegen(root, context) { const { helper } = context; const { children } = root; if (children.length === 1) { const child = children[0]; // if the single child is an element, turn it into a block. if (isSingleElementRoot(root, child) && child.codegenNode) { // single element root is never hoisted so codegenNode will never be // SimpleExpressionNode const codegenNode = child.codegenNode; if (codegenNode.type === 13 /* VNODE_CALL */) { makeBlock(codegenNode, context); } root.codegenNode = codegenNode; } else { // - single <slot/>, IfNode, ForNode: already blocks. // - single text node: always patched. // root codegen falls through via genNode() root.codegenNode = child; } } else if (children.length > 1) { // root has multiple nodes - return a fragment block. let patchFlag = 64 /* STABLE_FRAGMENT */; shared.PatchFlagNames[64 /* STABLE_FRAGMENT */]; root.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, root.children, patchFlag + (``), undefined, undefined, true, undefined, false /* isComponent */); } else ; } function traverseChildren(parent, context) { let i = 0; const nodeRemoved = () => { i--; }; for (; i < parent.children.length; i++) { const child = parent.children[i]; if (shared.isString(child)) continue; context.parent = parent; context.childIndex = i; context.onNodeRemoved = nodeRemoved; traverseNode(child, context); } } function traverseNode(node, context) { context.currentNode = node; // apply transform plugins const { nodeTransforms } = context; const exitFns = []; for (let i = 0; i < nodeTransforms.length; i++) { const onExit = nodeTransforms[i](node, context); if (onExit) { if (shared.isArray(onExit)) { exitFns.push(...onExit); } else { exitFns.push(onExit); } } if (!context.currentNode) { // node was removed return; } else { // node may have been replaced node = context.currentNode; } } switch (node.type) { case 3 /* COMMENT */: if (!context.ssr) { // inject import for the Comment symbol, which is needed for creating // comment nodes with `createVNode` context.helper(CREATE_COMMENT); } break; case 5 /* INTERPOLATION */: // no need to traverse, but we need to inject toString helper if (!context.ssr) { context.helper(TO_DISPLAY_STRING); } break; // for container types, further traverse downwards case 9 /* IF */: for (let i = 0; i < node.branches.length; i++) { traverseNode(node.branches[i], context); } break; case 10 /* IF_BRANCH */: case 11 /* FOR */: case 1 /* ELEMENT */: case 0 /* ROOT */: traverseChildren(node, context); break; } // exit transforms context.currentNode = node; let i = exitFns.length; while (i--) { exitFns[i](); } } function createStructuralDirectiveTransform(name, fn) { const matches = shared.isString(name) ? (n) => n === name : (n) => name.test(n); return (node, context) => { if (node.type === 1 /* ELEMENT */) { const { props } = node; // structural directive transforms are not concerned with slots // as they are handled separately in vSlot.ts if (node.tagType === 3 /* TEMPLATE */ && props.some(isVSlot)) { return; } const exitFns = []; for (let i = 0; i < props.length; i++) { const prop = props[i]; if (prop.type === 7 /* DIRECTIVE */ && matches(prop.name)) { // structural directives are removed to avoid infinite recursion // also we remove them *before* applying so that it can further // traverse itself in case it moves the node around props.splice(i, 1); i--; const onExit = fn(node, prop, context); if (onExit) exitFns.push(onExit); } } return exitFns; } }; } const PURE_ANNOTATION = `/*#__PURE__*/`; function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap: sourceMap$1 = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssrRuntimeModuleName = 'vue/server-renderer', ssr = false, isTS = false, inSSR = false }) { const context = { mode, prefixIdentifiers, sourceMap: sourceMap$1, filename, scopeId, optimizeImports, runtimeGlobalName, runtimeModuleName, ssrRuntimeModuleName, ssr, isTS, inSSR, source: ast.loc.source, code: ``, column: 1, line: 1, offset: 0, indentLevel: 0, pure: false, map: undefined, helper(key) { return `_${helperNameMap[key]}`; }, push(code, node) { context.code += code; if (context.map) { if (node) { let name; if (node.type === 4 /* SIMPLE_EXPRESSION */ && !node.isStatic) { const content = node.content.replace(/^_ctx\./, ''); if (content !== node.content && isSimpleIdentifier(content)) { name = content; } } addMapping(node.loc.start, name); } advancePositionWithMutation(context, code); if (node && node.loc !== locStub) { addMapping(node.loc.end); } } }, indent() { newline(++context.indentLevel); }, deindent(withoutNewLine = false) { if (withoutNewLine) { --context.indentLevel; } else { newline(--context.indentLevel); } }, newline() { newline(context.indentLevel); } }; function newline(n) { context.push('\n' + ` `.repeat(n)); } function addMapping(loc, name) { context.map.addMapping({ name, source: context.filename, original: { line: loc.line, column: loc.column - 1 // source-map column is 0 based }, generated: { line: context.line, column: context.column - 1 } }); } if (sourceMap$1) { // lazy require source-map implementation, only in non-browser builds context.map = new sourceMap.SourceMapGenerator(); context.map.setSourceContent(filename, context.source); } return context; } function generate(ast, options = {}) { const context = createCodegenContext(ast, options); if (options.onContextCreated) options.onContextCreated(context); const { mode, push, prefixIdentifiers, indent, deindent, newline, scopeId, ssr } = context; const hasHelpers = ast.helpers.length > 0; const useWithBlock = !prefixIdentifiers && mode !== 'module'; const genScopeId = scopeId != null && mode === 'module'; const isSetupInlined = !!options.inline; // preambles // in setup() inline mode, the preamble is generated in a sub context // and returned separately. const preambleContext = isSetupInlined ? createCodegenContext(ast, options) : context; if (mode === 'module') { genModulePreamble(ast, preambleContext, genScopeId, isSetupInlined); } else { genFunctionPreamble(ast, preambleContext); } // enter render function const functionName = ssr ? `ssrRender` : `render`; const args = ssr ? ['_ctx', '_push', '_parent', '_attrs'] : ['_ctx', '_cache']; if (options.bindingMetadata && !options.inline) { // binding optimization args args.push('$props', '$setup', '$data', '$options'); } const signature = options.isTS ? args.map(arg => `${arg}: any`).join(',') : args.join(', '); if (isSetupInlined) { push(`(${signature}) => {`); } else { push(`function ${functionName}(${signature}) {`); } indent(); if (useWithBlock) { push(`with (_ctx) {`); indent(); // function mode const declarations should be inside with block // also they should be renamed to avoid collision with user properties if (hasHelpers) { push(`const { ${ast.helpers .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`) .join(', ')} } = _Vue`); push(`\n`); newline(); } } // generate asset resolution statements if (ast.components.length) { genAssets(ast.components, 'component', context); if (ast.directives.length || ast.temps > 0) { newline(); } } if (ast.directives.length) { genAssets(ast.directives, 'directive', context); if (ast.temps > 0) { newline(); } } if (ast.filters && ast.filters.length) { newline(); genAssets(ast.filters, 'filter', context); newline(); } if (ast.temps > 0) { push(`let `); for (let i = 0; i < ast.temps; i++) { push(`${i > 0 ? `, ` : ``}_temp${i}`); } } if (ast.components.length || ast.directives.length || ast.temps) { push(`\n`); newline(); } // generate the VNode tree expression if (!ssr) { push(`return `); } if (ast.codegenNode) { genNode(ast.codegenNode, context); } else { push(`null`); } if (useWithBlock) { deindent(); push(`}`); } deindent(); push(`}`); return { ast, code: context.code, preamble: isSetupInlined ? preambleContext.code : ``, // SourceMapGenerator does have toJSON() method but it's not in the types map: context.map ? context.map.toJSON() : undefined }; } function genFunctionPreamble(ast, context) { const { ssr, prefixIdentifiers, push, newline, runtimeModuleName, runtimeGlobalName, ssrRuntimeModuleName } = context; const VueBinding = ssr ? `require(${JSON.stringify(runtimeModuleName)})` : runtimeGlobalName; const aliasHelper = (s) => `${helperNameMap[s]}: _${helperNameMap[s]}`; // Generate const declaration for helpers // In prefix mode, we place the const declaration at top so it's done // only once; But if we not prefixing, we place the declaration inside the // with block so it doesn't incur the `in` check cost for every helper access. if (ast.helpers.length > 0) { if (prefixIdentifiers) { push(`const { ${ast.helpers.map(aliasHelper).join(', ')} } = ${VueBinding}\n`); } else { // "with" mode. // save Vue in a separate variable to avoid collision push(`const _Vue = ${VueBinding}\n`); // in "with" mode, helpers are declared inside the with block to avoid // has check cost, but hoists are lifted out of the function - we need // to provide the helper here. if (ast.hoists.length) { const staticHelpers = [ CREATE_VNODE, CREATE_ELEMENT_VNODE, CREATE_COMMENT, CREATE_TEXT, CREATE_STATIC ] .filter(helper => ast.helpers.includes(helper)) .map(aliasHelper) .join(', '); push(`const { ${staticHelpers} } = _Vue\n`); } } } // generate variables for ssr helpers if (ast.ssrHelpers && ast.ssrHelpers.length) { // ssr guarantees prefixIdentifier: true push(`const { ${ast.ssrHelpers .map(aliasHelper) .join(', ')} } = require("${ssrRuntimeModuleName}")\n`); } genHoists(ast.hoists, context); newline(); push(`return `); } function genModulePreamble(ast, context, genScopeId, inline) { const { push, newline, optimizeImports, runtimeModuleName, ssrRuntimeModuleName } = context; if (genScopeId && ast.hoists.length) { ast.helpers.push(PUSH_SCOPE_ID, POP_SCOPE_ID); } // generate import statements for helpers if (ast.helpers.length) { if (optimizeImports) { // when bundled with webpack with code-split, calling an import binding // as a function leads to it being wrapped with `Object(a.b)` or `(0,a.b)`, // incurring both payload size increase and potential perf overhead. // therefore we assign the imports to variables (which is a constant ~50b // cost per-component instead of scaling with template size) push(`import { ${ast.helpers .map(s => helperNameMap[s]) .join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`); push(`\n// Binding optimization for webpack code-split\nconst ${ast.helpers .map(s => `_${helperNameMap[s]} = ${helperNameMap[s]}`) .join(', ')}\n`); } else { push(`import { ${ast.helpers .map(s => `${helperNameMap[s]} as _${helperNameMap[s]}`) .join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`); } } if (ast.ssrHelpers && ast.ssrHelpers.length) { push(`import { ${ast.ssrHelpers .map(s => `${helperNameMap[s]} as _${helperNameMap[s]}`) .join(', ')} } from "${ssrRuntimeModuleName}"\n`); } if (ast.imports.length) { genImports(ast.imports, context); newline(); } genHoists(ast.hoists, context); newline(); if (!inline) { push(`export `); } } function genAssets(assets, type, { helper, push, newline, isTS }) { const resolver = helper(type === 'filter' ? RESOLVE_FILTER : type === 'component' ? RESOLVE_COMPONENT : RESOLVE_DIRECTIVE); for (let i = 0; i < assets.length; i++) { let id = assets[i]; // potential component implicit self-reference inferred from SFC filename const maybeSelfReference = id.endsWith('__self'); if (maybeSelfReference) { id = id.slice(0, -6); } push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`); if (i < assets.length - 1) { newline(); } } } function genHoists(hoists, context) { if (!hoists.length) { return; } context.pure = true; const { push, newline, helper, scopeId, mode } = context; const genScopeId = scopeId != null && mode !== 'function'; newline(); // generate inlined withScopeId helper if (genScopeId) { push(`const _withScopeId = n => (${helper(PUSH_SCOPE_ID)}("${scopeId}"),n=n(),${helper(POP_SCOPE_ID)}(),n)`); newline(); } for (let i = 0; i < hoists.length; i++) { const exp = hoists[i]; if (exp) { const needScopeIdWrapper = genScopeId && exp.type === 13 /* VNODE_CALL */; push(`const _hoisted_${i + 1} = ${needScopeIdWrapper ? `${PURE_ANNOTATION} _withScopeId(() => ` : ``}`); genNode(exp, context); if (needScopeIdWrapper) { push(`)`); } newline(); } } context.pure = false; } function genImports(importsOptions, context) { if (!importsOptions.length) { return; } importsOptions.forEach(imports => { context.push(`import `); genNode(imports.exp, context); context.push(` from '${imports.path}'`); context.newline(); }); } function isText$1(n) { return (shared.isString(n) || n.type === 4 /* SIMPLE_EXPRESSION */ || n.type === 2 /* TEXT */ || n.type === 5 /* INTERPOLATION */ || n.type === 8 /* COMPOUND_EXPRESSION */); } function genNodeListAsArray(nodes, context) { const multilines = nodes.length > 3 || (nodes.some(n => shared.isArray(n) || !isText$1(n))); context.push(`[`); multilines && context.indent(); genNodeList(nodes, context, multilines); multilines && context.deindent(); context.push(`]`); } function genNodeList(nodes, context, multilines = false, comma = true) { const { push, newline } = context; for (let i = 0; i < nodes.length; i++) { const node = nodes[i]; if (shared.isString(node)) { push(node); } else if (shared.isArray(node)) { genNodeListAsArray(node, context); } else { genNode(node, context); } if (i < nodes.length - 1) { if (multilines) { comma && push(','); newline(); } else { comma && push(', '); } } } } function genNode(node, context) { if (shared.isString(node)) { context.push(node); return; } if (shared.isSymbol(node)) { context.push(context.helper(node)); return; } switch (node.type) { case 1 /* ELEMENT */: case 9 /* IF */: case 11 /* FOR */: genNode(node.codegenNode, context); break; case 2 /* TEXT */: genText(node, context); break; case 4 /* SIMPLE_EXPRESSION */: genExpression(node, context); break; case 5 /* INTERPOLATION */: genInterpolation(node, context); break; case 12 /* TEXT_CALL */: genNode(node.codegenNode, context); break; case 8 /* COMPOUND_EXPRESSION */: genCompoundExpression(node, context); break; case 3 /* COMMENT */: genComment(node, context); break; case 13 /* VNODE_CALL */: genVNodeCall(node, context); break; case 14 /* JS_CALL_EXPRESSION */: genCallExpression(node, context); break; case 15 /* JS_OBJECT_EXPRESSION */: genObjectExpression(node, context); break; case 17 /* JS_ARRAY_EXPRESSION */: genArrayExpression(node, context); break; case 18 /* JS_FUNCTION_EXPRESSION */: genFunctionExpression(node, context); break; case 19 /* JS_CONDITIONAL_EXPRESSION */: genConditionalExpression(node, context); break; case 20 /* JS_CACHE_EXPRESSION */: genCacheExpression(node, context); break; case 21 /* JS_BLOCK_STATEMENT */: genNodeList(node.body, context, true, false); break; // SSR only types case 22 /* JS_TEMPLATE_LITERAL */: genTemplateLiteral(node, context); break; case 23 /* JS_IF_STATEMENT */: genIfStatement(node, context); break; case 24 /* JS_ASSIGNMENT_EXPRESSION */: genAssignmentExpression(node, context); break; case 25 /* JS_SEQUENCE_EXPRESSION */: genSequenceExpression(node, context); break; case 26 /* JS_RETURN_STATEMENT */: genReturnStatement(node, context); break; } } function genText(node, context) { context.push(JSON.stringify(node.content), node); } function genExpression(node, context) { const { content, isStatic } = node; context.push(isStatic ? JSON.stringify(content) : content, node); } function genInterpolation(node, context) { const { push, helper, pure } = context; if (pure) push(PURE_ANNOTATION); push(`${helper(TO_DISPLAY_STRING)}(`); genNode(node.content, context); push(`)`); } function genCompoundExpression(node, context) { for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; if (shared.isString(child)) { context.push(child); } else { genNode(child, context); } } } function genExpressionAsPropertyKey(node, context) { const { push } = context; if (node.type === 8 /* COMPOUND_EXPRESSION */) { push(`[`); genCompoundExpression(node, context); push(`]`); } else if (node.isStatic) { // only quote keys if necessary const text = isSimpleIdentifier(node.content) ? node.content : JSON.stringify(node.content); push(text, node); } else { push(`[${node.content}]`, node); } } function genComment(node, context) { const { push, helper, pure } = context; if (pure) { push(PURE_ANNOTATION); } push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node); } function genVNodeCall(node, context) { const { push, helper, pure } = context; const { tag, props, children, patchFlag, dynamicProps, directives, isBlock, disableTracking, isComponent } = node; if (directives) { push(helper(WITH_DIRECTIVES) + `(`); } if (isBlock) { push(`(${helper(OPEN_BLOCK)}(${disableTracking ? `true` : ``}), `); } if (pure) { push(PURE_ANNOTATION); } const callHelper = isBlock ? getVNodeBlockHelper(context.inSSR, isComponent) : getVNodeHelper(context.inSSR, isComponent); push(helper(callHelper) + `(`, node); genNodeList(genNullableArgs([tag, props, children, patchFlag, dynamicProps]), context); push(`)`); if (isBlock) { push(`)`); } if (directives) { push(`, `); genNode(directives, context); push(`)`); } } function genNullableArgs(args) { let i = args.length; while (i--) { if (args[i] != null) break; } return args.slice(0, i + 1).map(arg => arg || `null`); } // JavaScript function genCallExpression(node, context) { const { push, helper, pure } = context; const callee = shared.isString(node.callee) ? node.callee : helper(node.callee); if (pure) { push(PURE_ANNOTATION); } push(callee + `(`, node); genNodeList(node.arguments, context); push(`)`); } function genObjectExpression(node, context) { const { push, indent, deindent, newline } = context; const { properties } = node; if (!properties.length) { push(`{}`, node); return; } const multilines = properties.length > 1 || (properties.some(p => p.value.type !== 4 /* SIMPLE_EXPRESSION */)); push(multilines ? `{` : `{ `); multilines && indent(); for (let i = 0; i < properties.length; i++) { const { key, value } = properties[i]; // key genExpressionAsPropertyKey(key, context); push(`: `); // value genNode(value, context); if (i < properties.length - 1) { // will only reach this if it's multilines push(`,`); newline(); } } multilines && deindent(); push(multilines ? `}` : ` }`); } function genArrayExpression(node, context) { genNodeListAsArray(node.elements, context); } function genFunctionExpression(node, context) { const { push, indent, deindent } = context; const { params, returns, body, newline, isSlot } = node; if (isSlot) { // wrap slot functions with owner context push(`_${helperNameMap[WITH_CTX]}(`); } push(`(`, node); if (shared.isArray(params)) { genNodeList(params, context); } else if (params) { genNode(params, context); } push(`) => `); if (newline || body) { push(`{`); indent(); } if (returns) { if (newline) { push(`return `); } if (shared.isArray(returns)) { genNodeListAsArray(returns, context); } else { genNode(returns, context); } } else if (body) { genNode(body, context); } if (newline || body) { deindent(); push(`}`); } if (isSlot) { if (node.isNonScopedSlot) { push(`, undefined, true`); } push(`)`); } } function genConditionalExpression(node, context) { const { test, consequent, alternate, newline: needNewline } = node; const { push, indent, deindent, newline } = context; if (test.type === 4 /* SIMPLE_EXPRESSION */) { const needsParens = !isSimpleIdentifier(test.content); needsParens && push(`(`); genExpression(test, context); needsParens && push(`)`); } else { push(`(`); genNode(test, context); push(`)`); } needNewline && indent(); context.indentLevel++; needNewline || push(` `); push(`? `); genNode(consequent, context); context.indentLevel--; needNewline && newline(); needNewline || push(` `); push(`: `); const isNested = alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */; if (!isNested) { context.indentLevel++; } genNode(alternate, context); if (!isNested) { context.indentLevel--; } needNewline && deindent(true /* without newline */); } function genCacheExpression(node, context) { const { push, helper, indent, deindent, newline } = context; push(`_cache[${node.index}] || (`); if (node.isVNode) { indent(); push(`${helper(SET_BLOCK_TRACKING)}(-1),`); newline(); } push(`_cache[${node.index}] = `); genNode(node.value, context); if (node.isVNode) { push(`,`); newline(); push(`${helper(SET_BLOCK_TRACKING)}(1),`); newline(); push(`_cache[${node.index}]`); deindent(); } push(`)`); } function genTemplateLiteral(node, context) { const { push, indent, deindent } = context; push('`'); const l = node.elements.length; const multilines = l > 3; for (let i = 0; i < l; i++) { const e = node.elements[i]; if (shared.isString(e)) { push(e.replace(/(`|\$|\\)/g, '\\$1')); } else { push('${'); if (multilines) indent(); genNode(e, context); if (multilines) deindent(); push('}'); } } push('`'); } function genIfStatement(node, context) { const { push, indent, deindent } = context; const { test, consequent, alternate } = node; push(`if (`); genNode(test, context); push(`) {`); indent(); genNode(consequent, context); deindent(); push(`}`); if (alternate) { push(` else `); if (alternate.type === 23 /* JS_IF_STATEMENT */) { genIfStatement(alternate, context); } else { push(`{`); indent(); genNode(alternate, context); deindent(); push(`}`); } } } function genAssignmentExpression(node, context) { genNode(node.left, context); context.push(` = `); genNode(node.right, context); } function genSequenceExpression(node, context) { context.push(`(`); genNodeList(node.expressions, context); context.push(`)`); } function genReturnStatement({ returns }, context) { context.push(`return `); if (shared.isArray(returns)) { genNodeListAsArray(returns, context); } else { genNode(returns, context); } } function walkIdentifiers(root, onIdentifier, includeAll = false, parentStack = [], knownIds = Object.create(null)) { const rootExp = root.type === 'Program' && root.body[0].type === 'ExpressionStatement' && root.body[0].expression; estreeWalker.walk(root, { enter(node, parent) { parent && parentStack.push(parent); if (parent && parent.type.startsWith('TS') && parent.type !== 'TSAsExpression' && parent.type !== 'TSNonNullExpression' && parent.type !== 'TSTypeAssertion') { return this.skip(); } if (node.type === 'Identifier') { const isLocal = !!knownIds[node.name]; const isRefed = isReferencedIdentifier(node, parent, parentStack); if (includeAll || (isRefed && !isLocal)) { onIdentifier(node, parent, parentStack, isRefed, isLocal); } } else if (node.type === 'ObjectProperty' && parent.type === 'ObjectPattern') { node.inPattern = true; } else if (isFunctionType(node)) { // walk function expressions and add its arguments to known identifiers // so that we don't prefix them walkFunctionParams(node, id => markScopeIdentifier(node, id, knownIds)); } else if (node.type === 'BlockStatement') { // #3445 record block-level local variables walkBlockDeclarations(node, id => markScopeIdentifier(node, id, knownIds)); } }, leave(node, parent) { parent && parentStack.pop(); if (node !== rootExp && node.scopeIds) { for (const id of node.scopeIds) { knownIds[id]--; if (knownIds[id] === 0) { delete knownIds[id]; } } } } }); } function isReferencedIdentifier(id, parent, parentStack) { if (!parent) { return true; } // is a special keyword but parsed as identifier if (id.name === 'arguments') { return false; } if (isReferenced(id, parent)) { return true; } // babel's isReferenced check returns false for ids being assigned to, so we // need to cover those cases here switch (parent.type) { case 'AssignmentExpression': case 'AssignmentPattern': return true; case 'ObjectPattern': case 'ArrayPattern': return isInDestructureAssignment(parent, parentStack); } return false; } function isInDestructureAssignment(parent, parentStack) { if (parent && (parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')) { let i = parentStack.length; while (i--) { const p = parentStack[i]; if (p.type === 'AssignmentExpression') { return true; } else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) { break; } } } return false; } function walkFunctionParams(node, onIdent) { for (const p of node.params) { for (const id of extractIdentifiers(p)) { onIdent(id); } } } function walkBlockDeclarations(block, onIdent) { for (const stmt of block.body) { if (stmt.type === 'VariableDeclaration') { if (stmt.declare) continue; for (const decl of stmt.declarations) { for (const id of extractIdentifiers(decl.id)) { onIdent(id); } } } else if (stmt.type === 'FunctionDeclaration' || stmt.type === 'ClassDeclaration') { if (stmt.declare || !stmt.id) continue; onIdent(stmt.id); } } } function extractIdentifiers(param, nodes = []) { switch (param.type) { case 'Identifier': nodes.push(param); break; case 'MemberExpression': let object = param; while (object.type === 'MemberExpression') { object = object.object; } nodes.push(object); break; case 'ObjectPattern': for (const prop of param.properties) { if (prop.type === 'RestElement') { extractIdentifiers(prop.argument, nodes); } else { extractIdentifiers(prop.value, nodes); } } break; case 'ArrayPattern': param.elements.forEach(element => { if (element) extractIdentifiers(element, nodes); }); break; case 'RestElement': extractIdentifiers(param.argument, nodes); break; case 'AssignmentPattern': extractIdentifiers(param.left, nodes); break; } return nodes; } function markScopeIdentifier(node, child, knownIds) { const { name } = child; if (node.scopeIds && node.scopeIds.has(name)) { return; } if (name in knownIds) { knownIds[name]++; } else { knownIds[name] = 1; } (node.scopeIds || (node.scopeIds = new Set())).add(name); } const isFunctionType = (node) => { return /Function(?:Expression|Declaration)$|Method$/.test(node.type); }; const isStaticProperty = (node) => node && (node.type === 'ObjectProperty' || node.type === 'ObjectMethod') && !node.computed; const isStaticPropertyKey = (node, parent) => isStaticProperty(parent) && parent.key === node; /** * Copied from https://github.com/babel/babel/blob/main/packages/babel-types/src/validators/isReferenced.ts * To avoid runtime dependency on @babel/types (which includes process references) * This file should not change very often in babel but we may need to keep it * up-to-date from time to time. * * https://github.com/babel/babel/blob/main/LICENSE * */ function isReferenced(node, parent, grandparent) { switch (parent.type) { // yes: PARENT[NODE] // yes: NODE.child // no: parent.NODE case 'MemberExpression': case 'OptionalMemberExpression': if (parent.property === node) { return !!parent.computed; } return parent.object === node; case 'JSXMemberExpression': return parent.object === node; // no: let NODE = init; // yes: let id = NODE; case 'VariableDeclarator': return parent.init === node; // yes: () => NODE // no: (NODE) => {} case 'ArrowFunctionExpression': return parent.body === node; // no: class { #NODE; } // no: class { get #NODE() {} } // no: class { #NODE() {} } // no: class { fn() { return this.#NODE; } } case 'PrivateName': return false; // no: class { NODE() {} } // yes: class { [NODE]() {} } // no: class { foo(NODE) {} } case 'ClassMethod': case 'ClassPrivateMethod': case 'ObjectMethod': if (parent.key === node) { return !!parent.computed; } return false; // yes: { [NODE]: "" } // no: { NODE: "" } // depends: { NODE } // depends: { key: NODE } case 'ObjectProperty': if (parent.key === node) { return !!parent.computed; } // parent.value === node return !grandparent || grandparent.type !== 'ObjectPattern'; // no: class { NODE = value; } // yes: class { [NODE] = value; } // yes: class { key = NODE; } case 'ClassProperty': if (parent.key === node) { return !!parent.computed; } return true; case 'ClassPrivateProperty': return parent.key !== node; // no: class NODE {} // yes: class Foo extends NODE {} case 'ClassDeclaration': case 'ClassExpression': return parent.superClass === node; // yes: left = NODE; // no: NODE = right; case 'AssignmentExpression': return parent.right === node; // no: [NODE = foo] = []; // yes: [foo = NODE] = []; case 'AssignmentPattern': return parent.right === node; // no: NODE: for (;;) {} case 'LabeledStatement': return false; // no: try {} catch (NODE) {} case 'CatchClause': return false; // no: function foo(...NODE) {} case 'RestElement': return false; case 'BreakStatement': case 'ContinueStatement': return false; // no: function NODE() {} // no: function foo(NODE) {} case 'FunctionDeclaration': case 'FunctionExpression': return false; // no: export NODE from "foo"; // no: export * as NODE from "foo"; case 'ExportNamespaceSpecifier': case 'ExportDefaultSpecifier': return false; // no: export { foo as NODE }; // yes: export { NODE as foo }; // no: export { NODE as foo } from "foo"; case 'ExportSpecifier': // @ts-expect-error if (grandparent === null || grandparent === void 0 ? void 0 : grandparent.source) { return false; } return parent.local === node; // no: import NODE from "foo"; // no: import * as NODE from "foo"; // no: import { NODE as foo } from "foo"; // no: import { foo as NODE } from "foo"; // no: import NODE from "bar"; case 'ImportDefaultSpecifier': case 'ImportNamespaceSpecifier': case 'ImportSpecifier': return false; // no: import "foo" assert { NODE: "json" } case 'ImportAttribute': return false; // no: <div NODE="foo" /> case 'JSXAttribute': return false; // no: [NODE] = []; // no: ({ NODE }) = []; case 'ObjectPattern': case 'ArrayPattern': return false; // no: new.NODE // no: NODE.target case 'MetaProperty': return false; // yes: type X = { someProperty: NODE } // no: type X = { NODE: OtherType } case 'ObjectTypeProperty': return parent.key !== node; // yes: enum X { Foo = NODE } // no: enum X { NODE } case 'TSEnumMember': return parent.id !== node; // yes: { [NODE]: value } // no: { NODE: value } case 'TSPropertySignature': if (parent.key === node) { return !!parent.computed; } return true; } return true; } const isLiteralWhitelisted = /*#__PURE__*/ shared.makeMap('true,false,null,this'); const transformExpression = (node, context) => { if (node.type === 5 /* INTERPOLATION */) { node.content = processExpression(node.content, context); } else if (node.type === 1 /* ELEMENT */) { // handle directives on element for (let i = 0; i < node.props.length; i++) { const dir = node.props[i]; // do not process for v-on & v-for since they are special handled if (dir.type === 7 /* DIRECTIVE */ && dir.name !== 'for') { const exp = dir.exp; const arg = dir.arg; // do not process exp if this is v-on:arg - we need special handling // for wrapping inline statements. if (exp && exp.type === 4 /* SIMPLE_EXPRESSION */ && !(dir.name === 'on' && arg)) { dir.exp = processExpression(exp, context, // slot args must be processed as function params dir.name === 'slot'); } if (arg && arg.type === 4 /* SIMPLE_EXPRESSION */ && !arg.isStatic) { dir.arg = processExpression(arg, context); } } } } }; // Important: since this function uses Node.js only dependencies, it should // always be used with a leading !false check so that it can be // tree-shaken from the browser build. function processExpression(node, context, // some expressions like v-slot props & v-for aliases should be parsed as // function params asParams = false, // v-on handler values may contain multiple statements asRawStatements = false, localVars = Object.create(context.identifiers)) { if (!context.prefixIdentifiers || !node.content.trim()) { return node; } const { inline, bindingMetadata } = context; const rewriteIdentifier = (raw, parent, id) => { const type = shared.hasOwn(bindingMetadata, raw) && bindingMetadata[raw]; if (inline) { // x = y const isAssignmentLVal = parent && parent.type === 'AssignmentExpression' && parent.left === id; // x++ const isUpdateArg = parent && parent.type === 'UpdateExpression' && parent.argument === id; // ({ x } = y) const isDestructureAssignment = parent && isInDestructureAssignment(parent, parentStack); if (type === "setup-const" /* SETUP_CONST */ || localVars[raw]) { return raw; } else if (type === "setup-ref" /* SETUP_REF */) { return `${raw}.value`; } else if (type === "setup-maybe-ref" /* SETUP_MAYBE_REF */) { // const binding that may or may not be ref // if it's not a ref, then assignments don't make sense - // so we ignore the non-ref assignment case and generate code // that assumes the value to be a ref for more efficiency return isAssignmentLVal || isUpdateArg || isDestructureAssignment ? `${raw}.value` : `${context.helperString(UNREF)}(${raw})`; } else if (type === "setup-let" /* SETUP_LET */) { if (isAssignmentLVal) { // let binding. // this is a bit more tricky as we need to cover the case where // let is a local non-ref value, and we need to replicate the // right hand side value. // x = y --> isRef(x) ? x.value = y : x = y const { right: rVal, operator } = parent; const rExp = rawExp.slice(rVal.start - 1, rVal.end - 1); const rExpString = stringifyExpression(processExpression(createSimpleExpression(rExp, false), context, false, false, knownIds)); return `${context.helperString(IS_REF)}(${raw})${context.isTS ? ` //@ts-ignore\n` : ``} ? ${raw}.value ${operator} ${rExpString} : ${raw}`; } else if (isUpdateArg) { // make id replace parent in the code range so the raw update operator // is removed id.start = parent.start; id.end = parent.end; const { prefix: isPrefix, operator } = parent; const prefix = isPrefix ? operator : ``; const postfix = isPrefix ? `` : operator; // let binding. // x++ --> isRef(a) ? a.value++ : a++ return `${context.helperString(IS_REF)}(${raw})${context.isTS ? ` //@ts-ignore\n` : ``} ? ${prefix}${raw}.value${postfix} : ${prefix}${raw}${postfix}`; } else if (isDestructureAssignment) { // TODO // let binding in a destructure assignment - it's very tricky to // handle both possible cases here without altering the original // structure of the code, so we just assume it's not a ref here // for now return raw; } else { return `${context.helperString(UNREF)}(${raw})`; } } else if (type === "props" /* PROPS */) { // use __props which is generated by compileScript so in ts mode // it gets correct type return `__props.${raw}`; } else if (type === "props-aliased" /* PROPS_ALIASED */) { // prop with a different local alias (from defineProps() destructure) return `__props.${bindingMetadata.__propsAliases[raw]}`; } } else { if (type && type.startsWith('setup')) { // setup bindings in non-inline mode return `$setup.${raw}`; } else if (type === "props-aliased" /* PROPS_ALIASED */) { return `$props.${bindingMetadata.__propsAliases[raw]}`; } else if (type) { return `$${type}.${raw}`; } } // fallback to ctx return `_ctx.${raw}`; }; // fast path if expression is a simple identifier. const rawExp = node.content; // bail constant on parens (function invocation) and dot (member access) const bailConstant = rawExp.indexOf(`(`) > -1 || rawExp.indexOf('.') > 0; if (isSimpleIdentifier(rawExp)) { const isScopeVarReference = context.identifiers[rawExp]; const isAllowedGlobal = shared.isGloballyWhitelisted(rawExp); const isLiteral = isLiteralWhitelisted(rawExp); if (!asParams && !isScopeVarReference && !isAllowedGlobal && !isLiteral) { // const bindings exposed from setup can be skipped for patching but // cannot be hoisted to module scope if (bindingMetadata[node.content] === "setup-const" /* SETUP_CONST */) { node.constType = 1 /* CAN_SKIP_PATCH */; } node.content = rewriteIdentifier(rawExp); } else if (!isScopeVarReference) { if (isLiteral) { node.constType = 3 /* CAN_STRINGIFY */; } else { node.constType = 2 /* CAN_HOIST */; } } return node; } let ast; // exp needs to be parsed differently: // 1. Multiple inline statements (v-on, with presence of `;`): parse as raw // exp, but make sure to pad with spaces for consistent ranges // 2. Expressions: wrap with parens (for e.g. object expressions) // 3. Function arguments (v-for, v-slot): place in a function argument position const source = asRawStatements ? ` ${rawExp} ` : `(${rawExp})${asParams ? `=>{}` : ``}`; try { ast = parser.parse(source, { plugins: context.expressionPlugins }).program; } catch (e) { context.onError(createCompilerError(44 /* X_INVALID_EXPRESSION */, node.loc, undefined, e.message)); return node; } const ids = []; const parentStack = []; const knownIds = Object.create(context.identifiers); walkIdentifiers(ast, (node, parent, _, isReferenced, isLocal) => { if (isStaticPropertyKey(node, parent)) { return; } // v2 wrapped filter call if (node.name.startsWith('_filter_')) { return; } const needPrefix = isReferenced && canPrefix(node); if (needPrefix && !isLocal) { if (isStaticProperty(parent) && parent.shorthand) { node.prefix = `${node.name}: `; } node.name = rewriteIdentifier(node.name, parent, node); ids.push(node); } else { // The identifier is considered constant unless it's pointing to a // local scope variable (a v-for alias, or a v-slot prop) if (!(needPrefix && isLocal) && !bailConstant) { node.isConstant = true; } // also generate sub-expressions for other identifiers for better // source map support. (except for property keys which are static) ids.push(node); } }, true, // invoke on ALL identifiers parentStack, knownIds); // We break up the compound expression into an array of strings and sub // expressions (for identifiers that have been prefixed). In codegen, if // an ExpressionNode has the `.children` property, it will be used instead of // `.content`. const children = []; ids.sort((a, b) => a.start - b.start); ids.forEach((id, i) => { // range is offset by -1 due to the wrapping parens when parsed const start = id.start - 1; const end = id.end - 1; const last = ids[i - 1]; const leadingText = rawExp.slice(last ? last.end - 1 : 0, start); if (leadingText.length || id.prefix) { children.push(leadingText + (id.prefix || ``)); } const source = rawExp.slice(start, end); children.push(createSimpleExpression(id.name, false, { source, start: advancePositionWithClone(node.loc.start, source, start), end: advancePositionWithClone(node.loc.start, source, end) }, id.isConstant ? 3 /* CAN_STRINGIFY */ : 0 /* NOT_CONSTANT */)); if (i === ids.length - 1 && end < rawExp.length) { children.push(rawExp.slice(end)); } }); let ret; if (children.length) { ret = createCompoundExpression(children, node.loc); } else { ret = node; ret.constType = bailConstant ? 0 /* NOT_CONSTANT */ : 3 /* CAN_STRINGIFY */; } ret.identifiers = Object.keys(knownIds); return ret; } function canPrefix(id) { // skip whitelisted globals if (shared.isGloballyWhitelisted(id.name)) { return false; } // special case for webpack compilation if (id.name === 'require') { return false; } return true; } function stringifyExpression(exp) { if (shared.isString(exp)) { return exp; } else if (exp.type === 4 /* SIMPLE_EXPRESSION */) { return exp.content; } else { return exp.children .map(stringifyExpression) .join(''); } } const transformIf = createStructuralDirectiveTransform(/^(if|else|else-if)$/, (node, dir, context) => { return processIf(node, dir, context, (ifNode, branch, isRoot) => { // #1587: We need to dynamically increment the key based on the current // node's sibling nodes, since chained v-if/else branches are // rendered at the same depth const siblings = context.parent.children; let i = siblings.indexOf(ifNode); let key = 0; while (i-- >= 0) { const sibling = siblings[i]; if (sibling && sibling.type === 9 /* IF */) { key += sibling.branches.length; } } // Exit callback. Complete the codegenNode when all children have been // transformed. return () => { if (isRoot) { ifNode.codegenNode = createCodegenNodeForBranch(branch, key, context); } else { // attach this branch's codegen node to the v-if root. const parentCondition = getParentCondition(ifNode.codegenNode); parentCondition.alternate = createCodegenNodeForBranch(branch, key + ifNode.branches.length - 1, context); } }; }); }); // target-agnostic transform used for both Client and SSR function processIf(node, dir, context, processCodegen) { if (dir.name !== 'else' && (!dir.exp || !dir.exp.content.trim())) { const loc = dir.exp ? dir.exp.loc : node.loc; context.onError(createCompilerError(28 /* X_V_IF_NO_EXPRESSION */, dir.loc)); dir.exp = createSimpleExpression(`true`, false, loc); } if (context.prefixIdentifiers && dir.exp) { // dir.exp can only be simple expression because vIf transform is applied // before expression transform. dir.exp = processExpression(dir.exp, context); } if (dir.name === 'if') { const branch = createIfBranch(node, dir); const ifNode = { type: 9 /* IF */, loc: node.loc, branches: [branch] }; context.replaceNode(ifNode); if (processCodegen) { return processCodegen(ifNode, branch, true); } } else { // locate the adjacent v-if const siblings = context.parent.children; let i = siblings.indexOf(node); while (i-- >= -1) { const sibling = siblings[i]; if (sibling && sibling.type === 2 /* TEXT */ && !sibling.content.trim().length) { context.removeNode(sibling); continue; } if (sibling && sibling.type === 9 /* IF */) { // Check if v-else was followed by v-else-if if (dir.name === 'else-if' && sibling.branches[sibling.branches.length - 1].condition === undefined) { context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc)); } // move the node to the if node's branches context.removeNode(); const branch = createIfBranch(node, dir); // check if user is forcing same key on different branches { const key = branch.userKey; if (key) { sibling.branches.forEach(({ userKey }) => { if (isSameKey(userKey, key)) { context.onError(createCompilerError(29 /* X_V_IF_SAME_KEY */, branch.userKey.loc)); } }); } } sibling.branches.push(branch); const onExit = processCodegen && processCodegen(sibling, branch, false); // since the branch was removed, it will not be traversed. // make sure to traverse here. traverseNode(branch, context); // call on exit if (onExit) onExit(); // make sure to reset currentNode after traversal to indicate this // node has been removed. context.currentNode = null; } else { context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc)); } break; } } } function createIfBranch(node, dir) { return { type: 10 /* IF_BRANCH */, loc: node.loc, condition: dir.name === 'else' ? undefined : dir.exp, children: node.tagType === 3 /* TEMPLATE */ && !findDir(node, 'for') ? node.children : [node], userKey: findProp(node, `key`) }; } function createCodegenNodeForBranch(branch, keyIndex, context) { if (branch.condition) { return createConditionalExpression(branch.condition, createChildrenCodegenNode(branch, keyIndex, context), // make sure to pass in asBlock: true so that the comment node call // closes the current block. createCallExpression(context.helper(CREATE_COMMENT), [ '""', 'true' ])); } else { return createChildrenCodegenNode(branch, keyIndex, context); } } function createChildrenCodegenNode(branch, keyIndex, context) { const { helper } = context; const keyProperty = createObjectProperty(`key`, createSimpleExpression(`${keyIndex}`, false, locStub, 2 /* CAN_HOIST */)); const { children } = branch; const firstChild = children[0]; const needFragmentWrapper = children.length !== 1 || firstChild.type !== 1 /* ELEMENT */; if (needFragmentWrapper) { if (children.length === 1 && firstChild.type === 11 /* FOR */) { // optimize away nested fragments when child is a ForNode const vnodeCall = firstChild.codegenNode; injectProp(vnodeCall, keyProperty, context); return vnodeCall; } else { let patchFlag = 64 /* STABLE_FRAGMENT */; shared.PatchFlagNames[64 /* STABLE_FRAGMENT */]; return createVNodeCall(context, helper(FRAGMENT), createObjectExpression([keyProperty]), children, patchFlag + (``), undefined, undefined, true, false, false /* isComponent */, branch.loc); } } else { const ret = firstChild.codegenNode; const vnodeCall = getMemoedVNodeCall(ret); // Change createVNode to createBlock. if (vnodeCall.type === 13 /* VNODE_CALL */) { makeBlock(vnodeCall, context); } // inject branch key injectProp(vnodeCall, keyProperty, context); return ret; } } function isSameKey(a, b) { if (!a || a.type !== b.type) { return false; } if (a.type === 6 /* ATTRIBUTE */) { if (a.value.content !== b.value.content) { return false; } } else { // directive const exp = a.exp; const branchExp = b.exp; if (exp.type !== branchExp.type) { return false; } if (exp.type !== 4 /* SIMPLE_EXPRESSION */ || exp.isStatic !== branchExp.isStatic || exp.content !== branchExp.content) { return false; } } return true; } function getParentCondition(node) { while (true) { if (node.type === 19 /* JS_CONDITIONAL_EXPRESSION */) { if (node.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) { node = node.alternate; } else { return node; } } else if (node.type === 20 /* JS_CACHE_EXPRESSION */) { node = node.value; } } } const transformFor = createStructuralDirectiveTransform('for', (node, dir, context) => { const { helper, removeHelper } = context; return processFor(node, dir, context, forNode => { // create the loop render function expression now, and add the // iterator on exit after all children have been traversed const renderExp = createCallExpression(helper(RENDER_LIST), [ forNode.source ]); const isTemplate = isTemplateNode(node); const memo = findDir(node, 'memo'); const keyProp = findProp(node, `key`); const keyExp = keyProp && (keyProp.type === 6 /* ATTRIBUTE */ ? createSimpleExpression(keyProp.value.content, true) : keyProp.exp); const keyProperty = keyProp ? createObjectProperty(`key`, keyExp) : null; if (isTemplate) { // #2085 / #5288 process :key and v-memo expressions need to be // processed on `<template v-for>`. In this case the node is discarded // and never traversed so its binding expressions won't be processed // by the normal transforms. if (memo) { memo.exp = processExpression(memo.exp, context); } if (keyProperty && keyProp.type !== 6 /* ATTRIBUTE */) { keyProperty.value = processExpression(keyProperty.value, context); } } const isStableFragment = forNode.source.type === 4 /* SIMPLE_EXPRESSION */ && forNode.source.constType > 0 /* NOT_CONSTANT */; const fragmentFlag = isStableFragment ? 64 /* STABLE_FRAGMENT */ : keyProp ? 128 /* KEYED_FRAGMENT */ : 256 /* UNKEYED_FRAGMENT */; forNode.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, renderExp, fragmentFlag + (``), undefined, undefined, true /* isBlock */, !isStableFragment /* disableTracking */, false /* isComponent */, node.loc); return () => { // finish the codegen now that all children have been traversed let childBlock; const { children } = forNode; // check <template v-for> key placement if (isTemplate) { node.children.some(c => { if (c.type === 1 /* ELEMENT */) { const key = findProp(c, 'key'); if (key) { context.onError(createCompilerError(33 /* X_V_FOR_TEMPLATE_KEY_PLACEMENT */, key.loc)); return true; } } }); } const needFragmentWrapper = children.length !== 1 || children[0].type !== 1 /* ELEMENT */; const slotOutlet = isSlotOutlet(node) ? node : isTemplate && node.children.length === 1 && isSlotOutlet(node.children[0]) ? node.children[0] // api-extractor somehow fails to infer this : null; if (slotOutlet) { // <slot v-for="..."> or <template v-for="..."><slot/></template> childBlock = slotOutlet.codegenNode; if (isTemplate && keyProperty) { // <template v-for="..." :key="..."><slot/></template> // we need to inject the key to the renderSlot() call. // the props for renderSlot is passed as the 3rd argument. injectProp(childBlock, keyProperty, context); } } else if (needFragmentWrapper) { // <template v-for="..."> with text or multi-elements // should generate a fragment block for each loop childBlock = createVNodeCall(context, helper(FRAGMENT), keyProperty ? createObjectExpression([keyProperty]) : undefined, node.children, 64 /* STABLE_FRAGMENT */ + (``), undefined, undefined, true, undefined, false /* isComponent */); } else { // Normal element v-for. Directly use the child's codegenNode // but mark it as a block. childBlock = children[0] .codegenNode; if (isTemplate && keyProperty) { injectProp(childBlock, keyProperty, context); } if (childBlock.isBlock !== !isStableFragment) { if (childBlock.isBlock) { // switch from block to vnode removeHelper(OPEN_BLOCK); removeHelper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent)); } else { // switch from vnode to block removeHelper(getVNodeHelper(context.inSSR, childBlock.isComponent)); } } childBlock.isBlock = !isStableFragment; if (childBlock.isBlock) { helper(OPEN_BLOCK); helper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent)); } else { helper(getVNodeHelper(context.inSSR, childBlock.isComponent)); } } if (memo) { const loop = createFunctionExpression(createForLoopParams(forNode.parseResult, [ createSimpleExpression(`_cached`) ])); loop.body = createBlockStatement([ createCompoundExpression([`const _memo = (`, memo.exp, `)`]), createCompoundExpression([ `if (_cached`, ...(keyExp ? [` && _cached.key === `, keyExp] : []), ` && ${context.helperString(IS_MEMO_SAME)}(_cached, _memo)) return _cached` ]), createCompoundExpression([`const _item = `, childBlock]), createSimpleExpression(`_item.memo = _memo`), createSimpleExpression(`return _item`) ]); renderExp.arguments.push(loop, createSimpleExpression(`_cache`), createSimpleExpression(String(context.cached++))); } else { renderExp.arguments.push(createFunctionExpression(createForLoopParams(forNode.parseResult), childBlock, true /* force newline */)); } }; }); }); // target-agnostic transform used for both Client and SSR function processFor(node, dir, context, processCodegen) { if (!dir.exp) { context.onError(createCompilerError(31 /* X_V_FOR_NO_EXPRESSION */, dir.loc)); return; } const parseResult = parseForExpression( // can only be simple expression because vFor transform is applied // before expression transform. dir.exp, context); if (!parseResult) { context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc)); return; } const { addIdentifiers, removeIdentifiers, scopes } = context; const { source, value, key, index } = parseResult; const forNode = { type: 11 /* FOR */, loc: dir.loc, source, valueAlias: value, keyAlias: key, objectIndexAlias: index, parseResult, children: isTemplateNode(node) ? node.children : [node] }; context.replaceNode(forNode); // bookkeeping scopes.vFor++; if (context.prefixIdentifiers) { // scope management // inject identifiers to context value && addIdentifiers(value); key && addIdentifiers(key); index && addIdentifiers(index); } const onExit = processCodegen && processCodegen(forNode); return () => { scopes.vFor--; if (context.prefixIdentifiers) { value && removeIdentifiers(value); key && removeIdentifiers(key); index && removeIdentifiers(index); } if (onExit) onExit(); }; } const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/; // This regex doesn't cover the case if key or index aliases have destructuring, // but those do not make sense in the first place, so this works in practice. const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/; const stripParensRE = /^\(|\)$/g; function parseForExpression(input, context) { const loc = input.loc; const exp = input.content; const inMatch = exp.match(forAliasRE); if (!inMatch) return; const [, LHS, RHS] = inMatch; const result = { source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)), value: undefined, key: undefined, index: undefined }; if (context.prefixIdentifiers) { result.source = processExpression(result.source, context); } let valueContent = LHS.trim().replace(stripParensRE, '').trim(); const trimmedOffset = LHS.indexOf(valueContent); const iteratorMatch = valueContent.match(forIteratorRE); if (iteratorMatch) { valueContent = valueContent.replace(forIteratorRE, '').trim(); const keyContent = iteratorMatch[1].trim(); let keyOffset; if (keyContent) { keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length); result.key = createAliasExpression(loc, keyContent, keyOffset); if (context.prefixIdentifiers) { result.key = processExpression(result.key, context, true); } } if (iteratorMatch[2]) { const indexContent = iteratorMatch[2].trim(); if (indexContent) { result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key ? keyOffset + keyContent.length : trimmedOffset + valueContent.length)); if (context.prefixIdentifiers) { result.index = processExpression(result.index, context, true); } } } } if (valueContent) { result.value = createAliasExpression(loc, valueContent, trimmedOffset); if (context.prefixIdentifiers) { result.value = processExpression(result.value, context, true); } } return result; } function createAliasExpression(range, content, offset) { return createSimpleExpression(content, false, getInnerRange(range, offset, content.length)); } function createForLoopParams({ value, key, index }, memoArgs = []) { return createParamsList([value, key, index, ...memoArgs]); } function createParamsList(args) { let i = args.length; while (i--) { if (args[i]) break; } return args .slice(0, i + 1) .map((arg, i) => arg || createSimpleExpression(`_`.repeat(i + 1), false)); } const defaultFallback = createSimpleExpression(`undefined`, false); // A NodeTransform that: // 1. Tracks scope identifiers for scoped slots so that they don't get prefixed // by transformExpression. This is only applied in non-browser builds with // { prefixIdentifiers: true }. // 2. Track v-slot depths so that we know a slot is inside another slot. // Note the exit callback is executed before buildSlots() on the same node, // so only nested slots see positive numbers. const trackSlotScopes = (node, context) => { if (node.type === 1 /* ELEMENT */ && (node.tagType === 1 /* COMPONENT */ || node.tagType === 3 /* TEMPLATE */)) { // We are only checking non-empty v-slot here // since we only care about slots that introduce scope variables. const vSlot = findDir(node, 'slot'); if (vSlot) { const slotProps = vSlot.exp; if (context.prefixIdentifiers) { slotProps && context.addIdentifiers(slotProps); } context.scopes.vSlot++; return () => { if (context.prefixIdentifiers) { slotProps && context.removeIdentifiers(slotProps); } context.scopes.vSlot--; }; } } }; // A NodeTransform that tracks scope identifiers for scoped slots with v-for. // This transform is only applied in non-browser builds with { prefixIdentifiers: true } const trackVForSlotScopes = (node, context) => { let vFor; if (isTemplateNode(node) && node.props.some(isVSlot) && (vFor = findDir(node, 'for'))) { const result = (vFor.parseResult = parseForExpression(vFor.exp, context)); if (result) { const { value, key, index } = result; const { addIdentifiers, removeIdentifiers } = context; value && addIdentifiers(value); key && addIdentifiers(key); index && addIdentifiers(index); return () => { value && removeIdentifiers(value); key && removeIdentifiers(key); index && removeIdentifiers(index); }; } } }; const buildClientSlotFn = (props, children, loc) => createFunctionExpression(props, children, false /* newline */, true /* isSlot */, children.length ? children[0].loc : loc); // Instead of being a DirectiveTransform, v-slot processing is called during // transformElement to build the slots object for a component. function buildSlots(node, context, buildSlotFn = buildClientSlotFn) { context.helper(WITH_CTX); const { children, loc } = node; const slotsProperties = []; const dynamicSlots = []; // If the slot is inside a v-for or another v-slot, force it to be dynamic // since it likely uses a scope variable. let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0; // with `prefixIdentifiers: true`, this can be further optimized to make // it dynamic only when the slot actually uses the scope variables. if (!context.ssr && context.prefixIdentifiers) { hasDynamicSlots = hasScopeRef(node, context.identifiers); } // 1. Check for slot with slotProps on component itself. // <Comp v-slot="{ prop }"/> const onComponentSlot = findDir(node, 'slot', true); if (onComponentSlot) { const { arg, exp } = onComponentSlot; if (arg && !isStaticExp(arg)) { hasDynamicSlots = true; } slotsProperties.push(createObjectProperty(arg || createSimpleExpression('default', true), buildSlotFn(exp, children, loc))); } // 2. Iterate through children and check for template slots // <template v-slot:foo="{ prop }"> let hasTemplateSlots = false; let hasNamedDefaultSlot = false; const implicitDefaultChildren = []; const seenSlotNames = new Set(); for (let i = 0; i < children.length; i++) { const slotElement = children[i]; let slotDir; if (!isTemplateNode(slotElement) || !(slotDir = findDir(slotElement, 'slot', true))) { // not a <template v-slot>, skip. if (slotElement.type !== 3 /* COMMENT */) { implicitDefaultChildren.push(slotElement); } continue; } if (onComponentSlot) { // already has on-component slot - this is incorrect usage. context.onError(createCompilerError(37 /* X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc)); break; } hasTemplateSlots = true; const { children: slotChildren, loc: slotLoc } = slotElement; const { arg: slotName = createSimpleExpression(`default`, true), exp: slotProps, loc: dirLoc } = slotDir; // check if name is dynamic. let staticSlotName; if (isStaticExp(slotName)) { staticSlotName = slotName ? slotName.content : `default`; } else { hasDynamicSlots = true; } const slotFunction = buildSlotFn(slotProps, slotChildren, slotLoc); // check if this slot is conditional (v-if/v-for) let vIf; let vElse; let vFor; if ((vIf = findDir(slotElement, 'if'))) { hasDynamicSlots = true; dynamicSlots.push(createConditionalExpression(vIf.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback)); } else if ((vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))) { // find adjacent v-if let j = i; let prev; while (j--) { prev = children[j]; if (prev.type !== 3 /* COMMENT */) { break; } } if (prev && isTemplateNode(prev) && findDir(prev, 'if')) { // remove node children.splice(i, 1); i--; // attach this slot to previous conditional let conditional = dynamicSlots[dynamicSlots.length - 1]; while (conditional.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) { conditional = conditional.alternate; } conditional.alternate = vElse.exp ? createConditionalExpression(vElse.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback) : buildDynamicSlot(slotName, slotFunction); } else { context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, vElse.loc)); } } else if ((vFor = findDir(slotElement, 'for'))) { hasDynamicSlots = true; const parseResult = vFor.parseResult || parseForExpression(vFor.exp, context); if (parseResult) { // Render the dynamic slots as an array and add it to the createSlot() // args. The runtime knows how to handle it appropriately. dynamicSlots.push(createCallExpression(context.helper(RENDER_LIST), [ parseResult.source, createFunctionExpression(createForLoopParams(parseResult), buildDynamicSlot(slotName, slotFunction), true /* force newline */) ])); } else { context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc)); } } else { // check duplicate static names if (staticSlotName) { if (seenSlotNames.has(staticSlotName)) { context.onError(createCompilerError(38 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc)); continue; } seenSlotNames.add(staticSlotName); if (staticSlotName === 'default') { hasNamedDefaultSlot = true; } } slotsProperties.push(createObjectProperty(slotName, slotFunction)); } } if (!onComponentSlot) { const buildDefaultSlotProperty = (props, children) => { const fn = buildSlotFn(props, children, loc); if (context.compatConfig) { fn.isNonScopedSlot = true; } return createObjectProperty(`default`, fn); }; if (!hasTemplateSlots) { // implicit default slot (on component) slotsProperties.push(buildDefaultSlotProperty(undefined, children)); } else if (implicitDefaultChildren.length && // #3766 // with whitespace: 'preserve', whitespaces between slots will end up in // implicitDefaultChildren. Ignore if all implicit children are whitespaces. implicitDefaultChildren.some(node => isNonWhitespaceContent(node))) { // implicit default slot (mixed with named slots) if (hasNamedDefaultSlot) { context.onError(createCompilerError(39 /* X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN */, implicitDefaultChildren[0].loc)); } else { slotsProperties.push(buildDefaultSlotProperty(undefined, implicitDefaultChildren)); } } } const slotFlag = hasDynamicSlots ? 2 /* DYNAMIC */ : hasForwardedSlots(node.children) ? 3 /* FORWARDED */ : 1 /* STABLE */; let slots = createObjectExpression(slotsProperties.concat(createObjectProperty(`_`, // 2 = compiled but dynamic = can skip normalization, but must run diff // 1 = compiled and static = can skip normalization AND diff as optimized createSimpleExpression(slotFlag + (``), false))), loc); if (dynamicSlots.length) { slots = createCallExpression(context.helper(CREATE_SLOTS), [ slots, createArrayExpression(dynamicSlots) ]); } return { slots, hasDynamicSlots }; } function buildDynamicSlot(name, fn) { return createObjectExpression([ createObjectProperty(`name`, name), createObjectProperty(`fn`, fn) ]); } function hasForwardedSlots(children) { for (let i = 0; i < children.length; i++) { const child = children[i]; switch (child.type) { case 1 /* ELEMENT */: if (child.tagType === 2 /* SLOT */ || hasForwardedSlots(child.children)) { return true; } break; case 9 /* IF */: if (hasForwardedSlots(child.branches)) return true; break; case 10 /* IF_BRANCH */: case 11 /* FOR */: if (hasForwardedSlots(child.children)) return true; break; } } return false; } function isNonWhitespaceContent(node) { if (node.type !== 2 /* TEXT */ && node.type !== 12 /* TEXT_CALL */) return true; return node.type === 2 /* TEXT */ ? !!node.content.trim() : isNonWhitespaceContent(node.content); } // some directive transforms (e.g. v-model) may return a symbol for runtime // import, which should be used instead of a resolveDirective call. const directiveImportMap = new WeakMap(); // generate a JavaScript AST for this element's codegen const transformElement = (node, context) => { // perform the work on exit, after all child expressions have been // processed and merged. return function postTransformElement() { node = context.currentNode; if (!(node.type === 1 /* ELEMENT */ && (node.tagType === 0 /* ELEMENT */ || node.tagType === 1 /* COMPONENT */))) { return; } const { tag, props } = node; const isComponent = node.tagType === 1 /* COMPONENT */; // The goal of the transform is to create a codegenNode implementing the // VNodeCall interface. let vnodeTag = isComponent ? resolveComponentType(node, context) : `"${tag}"`; const isDynamicComponent = shared.isObject(vnodeTag) && vnodeTag.callee === RESOLVE_DYNAMIC_COMPONENT; let vnodeProps; let vnodeChildren; let vnodePatchFlag; let patchFlag = 0; let vnodeDynamicProps; let dynamicPropNames; let vnodeDirectives; let shouldUseBlock = // dynamic component may resolve to plain elements isDynamicComponent || vnodeTag === TELEPORT || vnodeTag === SUSPENSE || (!isComponent && // <svg> and <foreignObject> must be forced into blocks so that block // updates inside get proper isSVG flag at runtime. (#639, #643) // This is technically web-specific, but splitting the logic out of core // leads to too much unnecessary complexity. (tag === 'svg' || tag === 'foreignObject')); // props if (props.length > 0) { const propsBuildResult = buildProps(node, context); vnodeProps = propsBuildResult.props; patchFlag = propsBuildResult.patchFlag; dynamicPropNames = propsBuildResult.dynamicPropNames; const directives = propsBuildResult.directives; vnodeDirectives = directives && directives.length ? createArrayExpression(directives.map(dir => buildDirectiveArgs(dir, context))) : undefined; if (propsBuildResult.shouldUseBlock) { shouldUseBlock = true; } } // children if (node.children.length > 0) { if (vnodeTag === KEEP_ALIVE) { // Although a built-in component, we compile KeepAlive with raw children // instead of slot functions so that it can be used inside Transition // or other Transition-wrapping HOCs. // To ensure correct updates with block optimizations, we need to: // 1. Force keep-alive into a block. This avoids its children being // collected by a parent block. shouldUseBlock = true; // 2. Force keep-alive to always be updated, since it uses raw children. patchFlag |= 1024 /* DYNAMIC_SLOTS */; } const shouldBuildAsSlots = isComponent && // Teleport is not a real component and has dedicated runtime handling vnodeTag !== TELEPORT && // explained above. vnodeTag !== KEEP_ALIVE; if (shouldBuildAsSlots) { const { slots, hasDynamicSlots } = buildSlots(node, context); vnodeChildren = slots; if (hasDynamicSlots) { patchFlag |= 1024 /* DYNAMIC_SLOTS */; } } else if (node.children.length === 1 && vnodeTag !== TELEPORT) { const child = node.children[0]; const type = child.type; // check for dynamic text children const hasDynamicTextChild = type === 5 /* INTERPOLATION */ || type === 8 /* COMPOUND_EXPRESSION */; if (hasDynamicTextChild && getConstantType(child, context) === 0 /* NOT_CONSTANT */) { patchFlag |= 1 /* TEXT */; } // pass directly if the only child is a text node // (plain / interpolation / expression) if (hasDynamicTextChild || type === 2 /* TEXT */) { vnodeChildren = child; } else { vnodeChildren = node.children; } } else { vnodeChildren = node.children; } } // patchFlag & dynamicPropNames if (patchFlag !== 0) { { vnodePatchFlag = String(patchFlag); } if (dynamicPropNames && dynamicPropNames.length) { vnodeDynamicProps = stringifyDynamicPropNames(dynamicPropNames); } } node.codegenNode = createVNodeCall(context, vnodeTag, vnodeProps, vnodeChildren, vnodePatchFlag, vnodeDynamicProps, vnodeDirectives, !!shouldUseBlock, false /* disableTracking */, isComponent, node.loc); }; }; function resolveComponentType(node, context, ssr = false) { let { tag } = node; // 1. dynamic component const isExplicitDynamic = isComponentTag(tag); const isProp = findProp(node, 'is'); if (isProp) { if (isExplicitDynamic || (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) { const exp = isProp.type === 6 /* ATTRIBUTE */ ? isProp.value && createSimpleExpression(isProp.value.content, true) : isProp.exp; if (exp) { return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [ exp ]); } } else if (isProp.type === 6 /* ATTRIBUTE */ && isProp.value.content.startsWith('vue:')) { // <button is="vue:xxx"> // if not <component>, only is value that starts with "vue:" will be // treated as component by the parse phase and reach here, unless it's // compat mode where all is values are considered components tag = isProp.value.content.slice(4); } } // 1.5 v-is (TODO: Deprecate) const isDir = !isExplicitDynamic && findDir(node, 'is'); if (isDir && isDir.exp) { return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [ isDir.exp ]); } // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...) const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag); if (builtIn) { // built-ins are simply fallthroughs / have special handling during ssr // so we don't need to import their runtime equivalents if (!ssr) context.helper(builtIn); return builtIn; } // 3. user component (from setup bindings) // this is skipped in browser build since browser builds do not perform // binding analysis. { const fromSetup = resolveSetupReference(tag, context); if (fromSetup) { return fromSetup; } const dotIndex = tag.indexOf('.'); if (dotIndex > 0) { const ns = resolveSetupReference(tag.slice(0, dotIndex), context); if (ns) { return ns + tag.slice(dotIndex); } } } // 4. Self referencing component (inferred from filename) if (context.selfName && shared.capitalize(shared.camelize(tag)) === context.selfName) { context.helper(RESOLVE_COMPONENT); // codegen.ts has special check for __self postfix when generating // component imports, which will pass additional `maybeSelfReference` flag // to `resolveComponent`. context.components.add(tag + `__self`); return toValidAssetId(tag, `component`); } // 5. user component (resolve) context.helper(RESOLVE_COMPONENT); context.components.add(tag); return toValidAssetId(tag, `component`); } function resolveSetupReference(name, context) { const bindings = context.bindingMetadata; if (!bindings || bindings.__isScriptSetup === false) { return; } const camelName = shared.camelize(name); const PascalName = shared.capitalize(camelName); const checkType = (type) => { if (bindings[name] === type) { return name; } if (bindings[camelName] === type) { return camelName; } if (bindings[PascalName] === type) { return PascalName; } }; const fromConst = checkType("setup-const" /* SETUP_CONST */); if (fromConst) { return context.inline ? // in inline mode, const setup bindings (e.g. imports) can be used as-is fromConst : `$setup[${JSON.stringify(fromConst)}]`; } const fromMaybeRef = checkType("setup-let" /* SETUP_LET */) || checkType("setup-ref" /* SETUP_REF */) || checkType("setup-maybe-ref" /* SETUP_MAYBE_REF */); if (fromMaybeRef) { return context.inline ? // setup scope bindings that may be refs need to be unrefed `${context.helperString(UNREF)}(${fromMaybeRef})` : `$setup[${JSON.stringify(fromMaybeRef)}]`; } } function buildProps(node, context, props = node.props, ssr = false) { const { tag, loc: elementLoc, children } = node; const isComponent = node.tagType === 1 /* COMPONENT */; let properties = []; const mergeArgs = []; const runtimeDirectives = []; const hasChildren = children.length > 0; let shouldUseBlock = false; // patchFlag analysis let patchFlag = 0; let hasRef = false; let hasClassBinding = false; let hasStyleBinding = false; let hasHydrationEventBinding = false; let hasDynamicKeys = false; let hasVnodeHook = false; const dynamicPropNames = []; const analyzePatchFlag = ({ key, value }) => { if (isStaticExp(key)) { const name = key.content; const isEventHandler = shared.isOn(name); if (!isComponent && isEventHandler && // omit the flag for click handlers because hydration gives click // dedicated fast path. name.toLowerCase() !== 'onclick' && // omit v-model handlers name !== 'onUpdate:modelValue' && // omit onVnodeXXX hooks !shared.isReservedProp(name)) { hasHydrationEventBinding = true; } if (isEventHandler && shared.isReservedProp(name)) { hasVnodeHook = true; } if (value.type === 20 /* JS_CACHE_EXPRESSION */ || ((value.type === 4 /* SIMPLE_EXPRESSION */ || value.type === 8 /* COMPOUND_EXPRESSION */) && getConstantType(value, context) > 0)) { // skip if the prop is a cached handler or has constant value return; } if (name === 'ref') { hasRef = true; } else if (name === 'class') { hasClassBinding = true; } else if (name === 'style') { hasStyleBinding = true; } else if (name !== 'key' && !dynamicPropNames.includes(name)) { dynamicPropNames.push(name); } // treat the dynamic class and style binding of the component as dynamic props if (isComponent && (name === 'class' || name === 'style') && !dynamicPropNames.includes(name)) { dynamicPropNames.push(name); } } else { hasDynamicKeys = true; } }; for (let i = 0; i < props.length; i++) { // static attribute const prop = props[i]; if (prop.type === 6 /* ATTRIBUTE */) { const { loc, name, value } = prop; let isStatic = true; if (name === 'ref') { hasRef = true; if (context.scopes.vFor > 0) { properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true'))); } // in inline mode there is no setupState object, so we can't use string // keys to set the ref. Instead, we need to transform it to pass the // actual ref instead. if (value && context.inline && context.bindingMetadata[value.content]) { isStatic = false; properties.push(createObjectProperty(createSimpleExpression('ref_key', true), createSimpleExpression(value.content, true, value.loc))); } } // skip is on <component>, or is="vue:xxx" if (name === 'is' && (isComponentTag(tag) || (value && value.content.startsWith('vue:')) || (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) { continue; } properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc))); } else { // directives const { name, arg, exp, loc } = prop; const isVBind = name === 'bind'; const isVOn = name === 'on'; // skip v-slot - it is handled by its dedicated transform. if (name === 'slot') { if (!isComponent) { context.onError(createCompilerError(40 /* X_V_SLOT_MISPLACED */, loc)); } continue; } // skip v-once/v-memo - they are handled by dedicated transforms. if (name === 'once' || name === 'memo') { continue; } // skip v-is and :is on <component> if (name === 'is' || (isVBind && isStaticArgOf(arg, 'is') && (isComponentTag(tag) || (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) { continue; } // skip v-on in SSR compilation if (isVOn && ssr) { continue; } if ( // #938: elements with dynamic keys should be forced into blocks (isVBind && isStaticArgOf(arg, 'key')) || // inline before-update hooks need to force block so that it is invoked // before children (isVOn && hasChildren && isStaticArgOf(arg, 'vue:before-update'))) { shouldUseBlock = true; } if (isVBind && isStaticArgOf(arg, 'ref') && context.scopes.vFor > 0) { properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true'))); } // special case for v-bind and v-on with no argument if (!arg && (isVBind || isVOn)) { hasDynamicKeys = true; if (exp) { if (properties.length) { mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc)); properties = []; } if (isVBind) { { if (isCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context)) { mergeArgs.unshift(exp); continue; } } mergeArgs.push(exp); } else { // v-on="obj" -> toHandlers(obj) mergeArgs.push({ type: 14 /* JS_CALL_EXPRESSION */, loc, callee: context.helper(TO_HANDLERS), arguments: [exp] }); } } else { context.onError(createCompilerError(isVBind ? 34 /* X_V_BIND_NO_EXPRESSION */ : 35 /* X_V_ON_NO_EXPRESSION */, loc)); } continue; } const directiveTransform = context.directiveTransforms[name]; if (directiveTransform) { // has built-in directive transform. const { props, needRuntime } = directiveTransform(prop, node, context); !ssr && props.forEach(analyzePatchFlag); properties.push(...props); if (needRuntime) { runtimeDirectives.push(prop); if (shared.isSymbol(needRuntime)) { directiveImportMap.set(prop, needRuntime); } } } else if (!shared.isBuiltInDirective(name)) { // no built-in transform, this is a user custom directive. runtimeDirectives.push(prop); // custom dirs may use beforeUpdate so they need to force blocks // to ensure before-update gets called before children update if (hasChildren) { shouldUseBlock = true; } } } } let propsExpression = undefined; // has v-bind="object" or v-on="object", wrap with mergeProps if (mergeArgs.length) { if (properties.length) { mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc)); } if (mergeArgs.length > 1) { propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc); } else { // single v-bind with nothing else - no need for a mergeProps call propsExpression = mergeArgs[0]; } } else if (properties.length) { propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc); } // patchFlag analysis if (hasDynamicKeys) { patchFlag |= 16 /* FULL_PROPS */; } else { if (hasClassBinding && !isComponent) { patchFlag |= 2 /* CLASS */; } if (hasStyleBinding && !isComponent) { patchFlag |= 4 /* STYLE */; } if (dynamicPropNames.length) { patchFlag |= 8 /* PROPS */; } if (hasHydrationEventBinding) { patchFlag |= 32 /* HYDRATE_EVENTS */; } } if (!shouldUseBlock && (patchFlag === 0 || patchFlag === 32 /* HYDRATE_EVENTS */) && (hasRef || hasVnodeHook || runtimeDirectives.length > 0)) { patchFlag |= 512 /* NEED_PATCH */; } // pre-normalize props, SSR is skipped for now if (!context.inSSR && propsExpression) { switch (propsExpression.type) { case 15 /* JS_OBJECT_EXPRESSION */: // means that there is no v-bind, // but still need to deal with dynamic key binding let classKeyIndex = -1; let styleKeyIndex = -1; let hasDynamicKey = false; for (let i = 0; i < propsExpression.properties.length; i++) { const key = propsExpression.properties[i].key; if (isStaticExp(key)) { if (key.content === 'class') { classKeyIndex = i; } else if (key.content === 'style') { styleKeyIndex = i; } } else if (!key.isHandlerKey) { hasDynamicKey = true; } } const classProp = propsExpression.properties[classKeyIndex]; const styleProp = propsExpression.properties[styleKeyIndex]; // no dynamic key if (!hasDynamicKey) { if (classProp && !isStaticExp(classProp.value)) { classProp.value = createCallExpression(context.helper(NORMALIZE_CLASS), [classProp.value]); } if (styleProp && !isStaticExp(styleProp.value) && // the static style is compiled into an object, // so use `hasStyleBinding` to ensure that it is a dynamic style binding (hasStyleBinding || // v-bind:style and style both exist, // v-bind:style with static literal object styleProp.value.type === 17 /* JS_ARRAY_EXPRESSION */)) { styleProp.value = createCallExpression(context.helper(NORMALIZE_STYLE), [styleProp.value]); } } else { // dynamic key binding, wrap with `normalizeProps` propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [propsExpression]); } break; case 14 /* JS_CALL_EXPRESSION */: // mergeProps call, do nothing break; default: // single v-bind propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [ createCallExpression(context.helper(GUARD_REACTIVE_PROPS), [ propsExpression ]) ]); break; } } return { props: propsExpression, directives: runtimeDirectives, patchFlag, dynamicPropNames, shouldUseBlock }; } // Dedupe props in an object literal. // Literal duplicated attributes would have been warned during the parse phase, // however, it's possible to encounter duplicated `onXXX` handlers with different // modifiers. We also need to merge static and dynamic class / style attributes. // - onXXX handlers / style: merge into array // - class: merge into single expression with concatenation function dedupeProperties(properties) { const knownProps = new Map(); const deduped = []; for (let i = 0; i < properties.length; i++) { const prop = properties[i]; // dynamic keys are always allowed if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) { deduped.push(prop); continue; } const name = prop.key.content; const existing = knownProps.get(name); if (existing) { if (name === 'style' || name === 'class' || shared.isOn(name)) { mergeAsArray(existing, prop); } // unexpected duplicate, should have emitted error during parse } else { knownProps.set(name, prop); deduped.push(prop); } } return deduped; } function mergeAsArray(existing, incoming) { if (existing.value.type === 17 /* JS_ARRAY_EXPRESSION */) { existing.value.elements.push(incoming.value); } else { existing.value = createArrayExpression([existing.value, incoming.value], existing.loc); } } function buildDirectiveArgs(dir, context) { const dirArgs = []; const runtime = directiveImportMap.get(dir); if (runtime) { // built-in directive with runtime dirArgs.push(context.helperString(runtime)); } else { // user directive. // see if we have directives exposed via <script setup> const fromSetup = resolveSetupReference('v-' + dir.name, context); if (fromSetup) { dirArgs.push(fromSetup); } else { // inject statement for resolving directive context.helper(RESOLVE_DIRECTIVE); context.directives.add(dir.name); dirArgs.push(toValidAssetId(dir.name, `directive`)); } } const { loc } = dir; if (dir.exp) dirArgs.push(dir.exp); if (dir.arg) { if (!dir.exp) { dirArgs.push(`void 0`); } dirArgs.push(dir.arg); } if (Object.keys(dir.modifiers).length) { if (!dir.arg) { if (!dir.exp) { dirArgs.push(`void 0`); } dirArgs.push(`void 0`); } const trueExpression = createSimpleExpression(`true`, false, loc); dirArgs.push(createObjectExpression(dir.modifiers.map(modifier => createObjectProperty(modifier, trueExpression)), loc)); } return createArrayExpression(dirArgs, dir.loc); } function stringifyDynamicPropNames(props) { let propsNamesString = `[`; for (let i = 0, l = props.length; i < l; i++) { propsNamesString += JSON.stringify(props[i]); if (i < l - 1) propsNamesString += ', '; } return propsNamesString + `]`; } function isComponentTag(tag) { return tag === 'component' || tag === 'Component'; } const cacheStringFunction = (fn) => { const cache = Object.create(null); return ((str) => { const hit = cache[str]; return hit || (cache[str] = fn(str)); }); }; const camelizeRE = /-(\w)/g; /** * @private */ const camelize = cacheStringFunction((str) => { return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : '')); }); const transformSlotOutlet = (node, context) => { if (isSlotOutlet(node)) { const { children, loc } = node; const { slotName, slotProps } = processSlotOutlet(node, context); const slotArgs = [ context.prefixIdentifiers ? `_ctx.$slots` : `$slots`, slotName, '{}', 'undefined', 'true' ]; let expectedLen = 2; if (slotProps) { slotArgs[2] = slotProps; expectedLen = 3; } if (children.length) { slotArgs[3] = createFunctionExpression([], children, false, false, loc); expectedLen = 4; } if (context.scopeId && !context.slotted) { expectedLen = 5; } slotArgs.splice(expectedLen); // remove unused arguments node.codegenNode = createCallExpression(context.helper(RENDER_SLOT), slotArgs, loc); } }; function processSlotOutlet(node, context) { let slotName = `"default"`; let slotProps = undefined; const nonNameProps = []; for (let i = 0; i < node.props.length; i++) { const p = node.props[i]; if (p.type === 6 /* ATTRIBUTE */) { if (p.value) { if (p.name === 'name') { slotName = JSON.stringify(p.value.content); } else { p.name = camelize(p.name); nonNameProps.push(p); } } } else { if (p.name === 'bind' && isStaticArgOf(p.arg, 'name')) { if (p.exp) slotName = p.exp; } else { if (p.name === 'bind' && p.arg && isStaticExp(p.arg)) { p.arg.content = camelize(p.arg.content); } nonNameProps.push(p); } } } if (nonNameProps.length > 0) { const { props, directives } = buildProps(node, context, nonNameProps); slotProps = props; if (directives.length) { context.onError(createCompilerError(36 /* X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET */, directives[0].loc)); } } return { slotName, slotProps }; } const fnExpRE = /^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/; const transformOn = (dir, node, context, augmentor) => { const { loc, modifiers, arg } = dir; if (!dir.exp && !modifiers.length) { context.onError(createCompilerError(35 /* X_V_ON_NO_EXPRESSION */, loc)); } let eventName; if (arg.type === 4 /* SIMPLE_EXPRESSION */) { if (arg.isStatic) { let rawName = arg.content; // TODO deprecate @vnodeXXX usage if (rawName.startsWith('vue:')) { rawName = `vnode-${rawName.slice(4)}`; } // for all event listeners, auto convert it to camelCase. See issue #2249 eventName = createSimpleExpression(shared.toHandlerKey(shared.camelize(rawName)), true, arg.loc); } else { // #2388 eventName = createCompoundExpression([ `${context.helperString(TO_HANDLER_KEY)}(`, arg, `)` ]); } } else { // already a compound expression. eventName = arg; eventName.children.unshift(`${context.helperString(TO_HANDLER_KEY)}(`); eventName.children.push(`)`); } // handler processing let exp = dir.exp; if (exp && !exp.content.trim()) { exp = undefined; } let shouldCache = context.cacheHandlers && !exp && !context.inVOnce; if (exp) { const isMemberExp = isMemberExpression(exp.content, context); const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content)); const hasMultipleStatements = exp.content.includes(`;`); // process the expression since it's been skipped if (context.prefixIdentifiers) { isInlineStatement && context.addIdentifiers(`$event`); exp = dir.exp = processExpression(exp, context, false, hasMultipleStatements); isInlineStatement && context.removeIdentifiers(`$event`); // with scope analysis, the function is hoistable if it has no reference // to scope variables. shouldCache = context.cacheHandlers && // unnecessary to cache inside v-once !context.inVOnce && // runtime constants don't need to be cached // (this is analyzed by compileScript in SFC <script setup>) !(exp.type === 4 /* SIMPLE_EXPRESSION */ && exp.constType > 0) && // #1541 bail if this is a member exp handler passed to a component - // we need to use the original function to preserve arity, // e.g. <transition> relies on checking cb.length to determine // transition end handling. Inline function is ok since its arity // is preserved even when cached. !(isMemberExp && node.tagType === 1 /* COMPONENT */) && // bail if the function references closure variables (v-for, v-slot) // it must be passed fresh to avoid stale values. !hasScopeRef(exp, context.identifiers); // If the expression is optimizable and is a member expression pointing // to a function, turn it into invocation (and wrap in an arrow function // below) so that it always accesses the latest value when called - thus // avoiding the need to be patched. if (shouldCache && isMemberExp) { if (exp.type === 4 /* SIMPLE_EXPRESSION */) { exp.content = `${exp.content} && ${exp.content}(...args)`; } else { exp.children = [...exp.children, ` && `, ...exp.children, `(...args)`]; } } } if (isInlineStatement || (shouldCache && isMemberExp)) { // wrap inline statement in a function expression exp = createCompoundExpression([ `${isInlineStatement ? context.isTS ? `($event: any)` : `$event` : `${context.isTS ? `\n//@ts-ignore\n` : ``}(...args)`} => ${hasMultipleStatements ? `{` : `(`}`, exp, hasMultipleStatements ? `}` : `)` ]); } } let ret = { props: [ createObjectProperty(eventName, exp || createSimpleExpression(`() => {}`, false, loc)) ] }; // apply extended compiler augmentor if (augmentor) { ret = augmentor(ret); } if (shouldCache) { // cache handlers so that it's always the same handler being passed down. // this avoids unnecessary re-renders when users use inline handlers on // components. ret.props[0].value = context.cache(ret.props[0].value); } // mark the key as handler for props normalization check ret.props.forEach(p => (p.key.isHandlerKey = true)); return ret; }; // v-bind without arg is handled directly in ./transformElements.ts due to it affecting // codegen for the entire props object. This transform here is only for v-bind // *with* args. const transformBind = (dir, _node, context) => { const { exp, modifiers, loc } = dir; const arg = dir.arg; if (arg.type !== 4 /* SIMPLE_EXPRESSION */) { arg.children.unshift(`(`); arg.children.push(`) || ""`); } else if (!arg.isStatic) { arg.content = `${arg.content} || ""`; } // .sync is replaced by v-model:arg if (modifiers.includes('camel')) { if (arg.type === 4 /* SIMPLE_EXPRESSION */) { if (arg.isStatic) { arg.content = shared.camelize(arg.content); } else { arg.content = `${context.helperString(CAMELIZE)}(${arg.content})`; } } else { arg.children.unshift(`${context.helperString(CAMELIZE)}(`); arg.children.push(`)`); } } if (!context.inSSR) { if (modifiers.includes('prop')) { injectPrefix(arg, '.'); } if (modifiers.includes('attr')) { injectPrefix(arg, '^'); } } if (!exp || (exp.type === 4 /* SIMPLE_EXPRESSION */ && !exp.content.trim())) { context.onError(createCompilerError(34 /* X_V_BIND_NO_EXPRESSION */, loc)); return { props: [createObjectProperty(arg, createSimpleExpression('', true, loc))] }; } return { props: [createObjectProperty(arg, exp)] }; }; const injectPrefix = (arg, prefix) => { if (arg.type === 4 /* SIMPLE_EXPRESSION */) { if (arg.isStatic) { arg.content = prefix + arg.content; } else { arg.content = `\`${prefix}\${${arg.content}}\``; } } else { arg.children.unshift(`'${prefix}' + (`); arg.children.push(`)`); } }; // 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. const transformText = (node, context) => { if (node.type === 0 /* ROOT */ || node.type === 1 /* ELEMENT */ || node.type === 11 /* FOR */ || node.type === 10 /* IF_BRANCH */) { // perform the transform on node exit so that all expressions have already // been processed. return () => { const children = node.children; let currentContainer = 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] = { type: 8 /* COMPOUND_EXPRESSION */, loc: child.loc, children: [child] }; } // 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 === 0 /* ROOT */ || (node.type === 1 /* ELEMENT */ && node.tagType === 0 /* 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 === 7 /* 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. !(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 === 8 /* COMPOUND_EXPRESSION */) { const callArgs = []; // 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 !== 2 /* TEXT */ || child.content !== ' ') { callArgs.push(child); } // mark dynamic text with flag so it gets patched inside a block if (!context.ssr && getConstantType(child, context) === 0 /* NOT_CONSTANT */) { callArgs.push(1 /* TEXT */ + (``)); } children[i] = { type: 12 /* TEXT_CALL */, content: child, loc: child.loc, codegenNode: createCallExpression(context.helper(CREATE_TEXT), callArgs) }; } } }; } }; const seen = new WeakSet(); const transformOnce = (node, context) => { if (node.type === 1 /* ELEMENT */ && findDir(node, 'once', true)) { if (seen.has(node) || context.inVOnce) { return; } seen.add(node); context.inVOnce = true; context.helper(SET_BLOCK_TRACKING); return () => { context.inVOnce = false; const cur = context.currentNode; if (cur.codegenNode) { cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */); } }; } }; const transformModel = (dir, node, context) => { const { exp, arg } = dir; if (!exp) { context.onError(createCompilerError(41 /* X_V_MODEL_NO_EXPRESSION */, dir.loc)); return createTransformProps(); } const rawExp = exp.loc.source; const expString = exp.type === 4 /* SIMPLE_EXPRESSION */ ? exp.content : rawExp; // im SFC <script setup> inline mode, the exp may have been transformed into // _unref(exp) const bindingType = context.bindingMetadata[rawExp]; const maybeRef = context.inline && bindingType && bindingType !== "setup-const" /* SETUP_CONST */; if (!expString.trim() || (!isMemberExpression(expString, context) && !maybeRef)) { context.onError(createCompilerError(42 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc)); return createTransformProps(); } if (context.prefixIdentifiers && isSimpleIdentifier(expString) && context.identifiers[expString]) { context.onError(createCompilerError(43 /* X_V_MODEL_ON_SCOPE_VARIABLE */, exp.loc)); return createTransformProps(); } const propName = arg ? arg : createSimpleExpression('modelValue', true); const eventName = arg ? isStaticExp(arg) ? `onUpdate:${arg.content}` : createCompoundExpression(['"onUpdate:" + ', arg]) : `onUpdate:modelValue`; let assignmentExp; const eventArg = context.isTS ? `($event: any)` : `$event`; if (maybeRef) { if (bindingType === "setup-ref" /* SETUP_REF */) { // v-model used on known ref. assignmentExp = createCompoundExpression([ `${eventArg} => ((`, createSimpleExpression(rawExp, false, exp.loc), `).value = $event)` ]); } else { // v-model used on a potentially ref binding in <script setup> inline mode. // the assignment needs to check whether the binding is actually a ref. const altAssignment = bindingType === "setup-let" /* SETUP_LET */ ? `${rawExp} = $event` : `null`; assignmentExp = createCompoundExpression([ `${eventArg} => (${context.helperString(IS_REF)}(${rawExp}) ? (`, createSimpleExpression(rawExp, false, exp.loc), `).value = $event : ${altAssignment})` ]); } } else { assignmentExp = createCompoundExpression([ `${eventArg} => ((`, exp, `) = $event)` ]); } const props = [ // modelValue: foo createObjectProperty(propName, dir.exp), // "onUpdate:modelValue": $event => (foo = $event) createObjectProperty(eventName, assignmentExp) ]; // cache v-model handler if applicable (when it doesn't refer any scope vars) if (context.prefixIdentifiers && !context.inVOnce && context.cacheHandlers && !hasScopeRef(exp, context.identifiers)) { props[1].value = context.cache(props[1].value); } // modelModifiers: { foo: true, "bar-baz": true } if (dir.modifiers.length && node.tagType === 1 /* COMPONENT */) { const modifiers = dir.modifiers .map(m => (isSimpleIdentifier(m) ? m : JSON.stringify(m)) + `: true`) .join(`, `); const modifiersKey = arg ? isStaticExp(arg) ? `${arg.content}Modifiers` : createCompoundExpression([arg, ' + "Modifiers"']) : `modelModifiers`; props.push(createObjectProperty(modifiersKey, createSimpleExpression(`{ ${modifiers} }`, false, dir.loc, 2 /* CAN_HOIST */))); } return createTransformProps(props); }; function createTransformProps(props = []) { return { props }; } const validDivisionCharRE = /[\w).+\-_$\]]/; const transformFilter = (node, context) => { if (!isCompatEnabled("COMPILER_FILTER" /* COMPILER_FILTERS */, context)) { return; } if (node.type === 5 /* INTERPOLATION */) { // filter rewrite is applied before expression transform so only // simple expressions are possible at this stage rewriteFilter(node.content, context); } if (node.type === 1 /* ELEMENT */) { node.props.forEach((prop) => { if (prop.type === 7 /* DIRECTIVE */ && prop.name !== 'for' && prop.exp) { rewriteFilter(prop.exp, context); } }); } }; function rewriteFilter(node, context) { if (node.type === 4 /* SIMPLE_EXPRESSION */) { parseFilter(node, context); } else { for (let i = 0; i < node.children.length; i++) { const child = node.children[i]; if (typeof child !== 'object') continue; if (child.type === 4 /* SIMPLE_EXPRESSION */) { parseFilter(child, context); } else if (child.type === 8 /* COMPOUND_EXPRESSION */) { rewriteFilter(node, context); } else if (child.type === 5 /* INTERPOLATION */) { rewriteFilter(child.content, context); } } } } function parseFilter(node, context) { const exp = node.content; let inSingle = false; let inDouble = false; let inTemplateString = false; let inRegex = false; let curly = 0; let square = 0; let paren = 0; let lastFilterIndex = 0; let c, prev, i, expression, filters = []; for (i = 0; i < exp.length; i++) { prev = c; c = exp.charCodeAt(i); if (inSingle) { if (c === 0x27 && prev !== 0x5c) inSingle = false; } else if (inDouble) { if (c === 0x22 && prev !== 0x5c) inDouble = false; } else if (inTemplateString) { if (c === 0x60 && prev !== 0x5c) inTemplateString = false; } else if (inRegex) { if (c === 0x2f && prev !== 0x5c) inRegex = false; } else if (c === 0x7c && // pipe exp.charCodeAt(i + 1) !== 0x7c && exp.charCodeAt(i - 1) !== 0x7c && !curly && !square && !paren) { if (expression === undefined) { // first filter, end of expression lastFilterIndex = i + 1; expression = exp.slice(0, i).trim(); } else { pushFilter(); } } else { switch (c) { case 0x22: inDouble = true; break; // " case 0x27: inSingle = true; break; // ' case 0x60: inTemplateString = true; break; // ` case 0x28: paren++; break; // ( case 0x29: paren--; break; // ) case 0x5b: square++; break; // [ case 0x5d: square--; break; // ] case 0x7b: curly++; break; // { case 0x7d: curly--; break; // } } if (c === 0x2f) { // / let j = i - 1; let p; // find first non-whitespace prev char for (; j >= 0; j--) { p = exp.charAt(j); if (p !== ' ') break; } if (!p || !validDivisionCharRE.test(p)) { inRegex = true; } } } } if (expression === undefined) { expression = exp.slice(0, i).trim(); } else if (lastFilterIndex !== 0) { pushFilter(); } function pushFilter() { filters.push(exp.slice(lastFilterIndex, i).trim()); lastFilterIndex = i + 1; } if (filters.length) { for (i = 0; i < filters.length; i++) { expression = wrapFilter(expression, filters[i], context); } node.content = expression; } } function wrapFilter(exp, filter, context) { context.helper(RESOLVE_FILTER); const i = filter.indexOf('('); if (i < 0) { context.filters.add(filter); return `${toValidAssetId(filter, 'filter')}(${exp})`; } else { const name = filter.slice(0, i); const args = filter.slice(i + 1); context.filters.add(name); return `${toValidAssetId(name, 'filter')}(${exp}${args !== ')' ? ',' + args : args}`; } } const seen$1 = new WeakSet(); const transformMemo = (node, context) => { if (node.type === 1 /* ELEMENT */) { const dir = findDir(node, 'memo'); if (!dir || seen$1.has(node)) { return; } seen$1.add(node); return () => { const codegenNode = node.codegenNode || context.currentNode.codegenNode; if (codegenNode && codegenNode.type === 13 /* VNODE_CALL */) { // non-component sub tree should be turned into a block if (node.tagType !== 1 /* COMPONENT */) { makeBlock(codegenNode, context); } node.codegenNode = createCallExpression(context.helper(WITH_MEMO), [ dir.exp, createFunctionExpression(undefined, codegenNode), `_cache`, String(context.cached++) ]); } }; } }; function getBaseTransformPreset(prefixIdentifiers) { return [ [ transformOnce, transformIf, transformMemo, transformFor, ...([transformFilter] ), ...(prefixIdentifiers ? [ // order is important trackVForSlotScopes, transformExpression ] : []), transformSlotOutlet, transformElement, trackSlotScopes, transformText ], { on: transformOn, bind: transformBind, model: transformModel } ]; } // we name it `baseCompile` so that higher order compilers like // @vue/compiler-dom can export `compile` while re-exporting everything else. function baseCompile(template, options = {}) { const onError = options.onError || defaultOnError; const isModuleMode = options.mode === 'module'; const prefixIdentifiers = (options.prefixIdentifiers === true || isModuleMode); if (!prefixIdentifiers && options.cacheHandlers) { onError(createCompilerError(48 /* X_CACHE_HANDLER_NOT_SUPPORTED */)); } if (options.scopeId && !isModuleMode) { onError(createCompilerError(49 /* X_SCOPE_ID_NOT_SUPPORTED */)); } const ast = shared.isString(template) ? baseParse(template, options) : template; const [nodeTransforms, directiveTransforms] = getBaseTransformPreset(prefixIdentifiers); if (options.isTS) { const { expressionPlugins } = options; if (!expressionPlugins || !expressionPlugins.includes('typescript')) { options.expressionPlugins = [...(expressionPlugins || []), 'typescript']; } } transform(ast, shared.extend({}, options, { prefixIdentifiers, nodeTransforms: [ ...nodeTransforms, ...(options.nodeTransforms || []) // user transforms ], directiveTransforms: shared.extend({}, directiveTransforms, options.directiveTransforms || {} // user transforms ) })); return generate(ast, shared.extend({}, options, { prefixIdentifiers })); } const noopDirectiveTransform = () => ({ props: [] }); exports.generateCodeFrame = shared.generateCodeFrame; exports.BASE_TRANSITION = BASE_TRANSITION; exports.CAMELIZE = CAMELIZE; exports.CAPITALIZE = CAPITALIZE; exports.CREATE_BLOCK = CREATE_BLOCK; exports.CREATE_COMMENT = CREATE_COMMENT; exports.CREATE_ELEMENT_BLOCK = CREATE_ELEMENT_BLOCK; exports.CREATE_ELEMENT_VNODE = CREATE_ELEMENT_VNODE; exports.CREATE_SLOTS = CREATE_SLOTS; exports.CREATE_STATIC = CREATE_STATIC; exports.CREATE_TEXT = CREATE_TEXT; exports.CREATE_VNODE = CREATE_VNODE; exports.FRAGMENT = FRAGMENT; exports.GUARD_REACTIVE_PROPS = GUARD_REACTIVE_PROPS; exports.IS_MEMO_SAME = IS_MEMO_SAME; exports.IS_REF = IS_REF; exports.KEEP_ALIVE = KEEP_ALIVE; exports.MERGE_PROPS = MERGE_PROPS; exports.NORMALIZE_CLASS = NORMALIZE_CLASS; exports.NORMALIZE_PROPS = NORMALIZE_PROPS; exports.NORMALIZE_STYLE = NORMALIZE_STYLE; exports.OPEN_BLOCK = OPEN_BLOCK; exports.POP_SCOPE_ID = POP_SCOPE_ID; exports.PUSH_SCOPE_ID = PUSH_SCOPE_ID; exports.RENDER_LIST = RENDER_LIST; exports.RENDER_SLOT = RENDER_SLOT; exports.RESOLVE_COMPONENT = RESOLVE_COMPONENT; exports.RESOLVE_DIRECTIVE = RESOLVE_DIRECTIVE; exports.RESOLVE_DYNAMIC_COMPONENT = RESOLVE_DYNAMIC_COMPONENT; exports.RESOLVE_FILTER = RESOLVE_FILTER; exports.SET_BLOCK_TRACKING = SET_BLOCK_TRACKING; exports.SUSPENSE = SUSPENSE; exports.TELEPORT = TELEPORT; exports.TO_DISPLAY_STRING = TO_DISPLAY_STRING; exports.TO_HANDLERS = TO_HANDLERS; exports.TO_HANDLER_KEY = TO_HANDLER_KEY; exports.UNREF = UNREF; exports.WITH_CTX = WITH_CTX; exports.WITH_DIRECTIVES = WITH_DIRECTIVES; exports.WITH_MEMO = WITH_MEMO; exports.advancePositionWithClone = advancePositionWithClone; exports.advancePositionWithMutation = advancePositionWithMutation; exports.assert = assert; exports.baseCompile = baseCompile; exports.baseParse = baseParse; exports.buildDirectiveArgs = buildDirectiveArgs; exports.buildProps = buildProps; exports.buildSlots = buildSlots; exports.checkCompatEnabled = checkCompatEnabled; exports.createArrayExpression = createArrayExpression; exports.createAssignmentExpression = createAssignmentExpression; exports.createBlockStatement = createBlockStatement; exports.createCacheExpression = createCacheExpression; exports.createCallExpression = createCallExpression; exports.createCompilerError = createCompilerError; exports.createCompoundExpression = createCompoundExpression; exports.createConditionalExpression = createConditionalExpression; exports.createForLoopParams = createForLoopParams; exports.createFunctionExpression = createFunctionExpression; exports.createIfStatement = createIfStatement; exports.createInterpolation = createInterpolation; exports.createObjectExpression = createObjectExpression; exports.createObjectProperty = createObjectProperty; exports.createReturnStatement = createReturnStatement; exports.createRoot = createRoot; exports.createSequenceExpression = createSequenceExpression; exports.createSimpleExpression = createSimpleExpression; exports.createStructuralDirectiveTransform = createStructuralDirectiveTransform; exports.createTemplateLiteral = createTemplateLiteral; exports.createTransformContext = createTransformContext; exports.createVNodeCall = createVNodeCall; exports.extractIdentifiers = extractIdentifiers; exports.findDir = findDir; exports.findProp = findProp; exports.generate = generate; exports.getBaseTransformPreset = getBaseTransformPreset; exports.getInnerRange = getInnerRange; exports.getMemoedVNodeCall = getMemoedVNodeCall; exports.getVNodeBlockHelper = getVNodeBlockHelper; exports.getVNodeHelper = getVNodeHelper; exports.hasDynamicKeyVBind = hasDynamicKeyVBind; exports.hasScopeRef = hasScopeRef; exports.helperNameMap = helperNameMap; exports.injectProp = injectProp; exports.isBuiltInType = isBuiltInType; exports.isCoreComponent = isCoreComponent; exports.isFunctionType = isFunctionType; exports.isInDestructureAssignment = isInDestructureAssignment; exports.isMemberExpression = isMemberExpression; exports.isMemberExpressionBrowser = isMemberExpressionBrowser; exports.isMemberExpressionNode = isMemberExpressionNode; exports.isReferencedIdentifier = isReferencedIdentifier; exports.isSimpleIdentifier = isSimpleIdentifier; exports.isSlotOutlet = isSlotOutlet; exports.isStaticArgOf = isStaticArgOf; exports.isStaticExp = isStaticExp; exports.isStaticProperty = isStaticProperty; exports.isStaticPropertyKey = isStaticPropertyKey; exports.isTemplateNode = isTemplateNode; exports.isText = isText; exports.isVSlot = isVSlot; exports.locStub = locStub; exports.makeBlock = makeBlock; exports.noopDirectiveTransform = noopDirectiveTransform; exports.processExpression = processExpression; exports.processFor = processFor; exports.processIf = processIf; exports.processSlotOutlet = processSlotOutlet; exports.registerRuntimeHelpers = registerRuntimeHelpers; exports.resolveComponentType = resolveComponentType; exports.toValidAssetId = toValidAssetId; exports.trackSlotScopes = trackSlotScopes; exports.trackVForSlotScopes = trackVForSlotScopes; exports.transform = transform; exports.transformBind = transformBind; exports.transformElement = transformElement; exports.transformExpression = transformExpression; exports.transformModel = transformModel; exports.transformOn = transformOn; exports.traverseNode = traverseNode; exports.walkBlockDeclarations = walkBlockDeclarations; exports.walkFunctionParams = walkFunctionParams; exports.walkIdentifiers = walkIdentifiers; exports.warnDeprecation = warnDeprecation;