Best JavaScript code snippet using playwright-internal
vendor-node_modules_r.js
Source:vendor-node_modules_r.js
...796 else {797 return value;798 }799}800function isCompatEnabled(key, context) {801 const mode = getCompatValue('MODE', context);802 const value = getCompatValue(key, context);803 // in v3 mode, only enable if explicitly set to true804 // otherwise enable for any non-false value805 return mode === 3 ? value === true : value !== false;806}807function checkCompatEnabled(key, context, loc, ...args) {808 const enabled = isCompatEnabled(key, context);809 if (( true) && enabled) {810 warnDeprecation(key, context, loc, ...args);811 }812 return enabled;813}814function warnDeprecation(key, context, loc, ...args) {815 const val = getCompatValue(key, context);816 if (val === 'suppress-warning') {817 return;818 }819 const { message, link } = deprecationData[key];820 const msg = `(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`;821 const err = new SyntaxError(msg);822 err.code = key;823 if (loc)824 err.loc = loc;825 context.onWarn(err);826}827// The default decoder only provides escapes for characters reserved as part of828// the template syntax, and is only used if the custom renderer did not provide829// a platform-specific decoder.830const decodeRE = /&(gt|lt|amp|apos|quot);/g;831const decodeMap = {832 gt: '>',833 lt: '<',834 amp: '&',835 apos: "'",836 quot: '"'837};838const defaultParserOptions = {839 delimiters: [`{{`, `}}`],840 getNamespace: () => 0 /* HTML */,841 getTextMode: () => 0 /* DATA */,842 isVoidTag: _vue_shared__WEBPACK_IMPORTED_MODULE_0__.NO,843 isPreTag: _vue_shared__WEBPACK_IMPORTED_MODULE_0__.NO,844 isCustomElement: _vue_shared__WEBPACK_IMPORTED_MODULE_0__.NO,845 decodeEntities: (rawText) => rawText.replace(decodeRE, (_, p1) => decodeMap[p1]),846 onError: defaultOnError,847 onWarn: defaultOnWarn,848 comments: false849};850function baseParse(content, options = {}) {851 const context = createParserContext(content, options);852 const start = getCursor(context);853 return createRoot(parseChildren(context, 0 /* DATA */, []), getSelection(context, start));854}855function createParserContext(content, rawOptions) {856 const options = (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.extend)({}, defaultParserOptions);857 for (const key in rawOptions) {858 // @ts-ignore859 options[key] = rawOptions[key] || defaultParserOptions[key];860 }861 return {862 options,863 column: 1,864 line: 1,865 offset: 0,866 originalSource: content,867 source: content,868 inPre: false,869 inVPre: false,870 onWarn: options.onWarn871 };872}873function parseChildren(context, mode, ancestors) {874 const parent = last(ancestors);875 const ns = parent ? parent.ns : 0 /* HTML */;876 const nodes = [];877 while (!isEnd(context, mode, ancestors)) {878 const s = context.source;879 let node = undefined;880 if (mode === 0 /* DATA */ || mode === 1 /* RCDATA */) {881 if (!context.inVPre && startsWith(s, context.options.delimiters[0])) {882 // '{{'883 node = parseInterpolation(context, mode);884 }885 else if (mode === 0 /* DATA */ && s[0] === '<') {886 // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state887 if (s.length === 1) {888 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 1);889 }890 else if (s[1] === '!') {891 // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state892 if (startsWith(s, '<!--')) {893 node = parseComment(context);894 }895 else if (startsWith(s, '<!DOCTYPE')) {896 // Ignore DOCTYPE by a limitation.897 node = parseBogusComment(context);898 }899 else if (startsWith(s, '<![CDATA[')) {900 if (ns !== 0 /* HTML */) {901 node = parseCDATA(context, ancestors);902 }903 else {904 emitError(context, 1 /* CDATA_IN_HTML_CONTENT */);905 node = parseBogusComment(context);906 }907 }908 else {909 emitError(context, 11 /* INCORRECTLY_OPENED_COMMENT */);910 node = parseBogusComment(context);911 }912 }913 else if (s[1] === '/') {914 // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state915 if (s.length === 2) {916 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 2);917 }918 else if (s[2] === '>') {919 emitError(context, 14 /* MISSING_END_TAG_NAME */, 2);920 advanceBy(context, 3);921 continue;922 }923 else if (/[a-z]/i.test(s[2])) {924 emitError(context, 23 /* X_INVALID_END_TAG */);925 parseTag(context, 1 /* End */, parent);926 continue;927 }928 else {929 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 2);930 node = parseBogusComment(context);931 }932 }933 else if (/[a-z]/i.test(s[1])) {934 node = parseElement(context, ancestors);935 // 2.x <template> with no directive compat936 if (isCompatEnabled("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context) &&937 node &&938 node.tag === 'template' &&939 !node.props.some(p => p.type === 7 /* DIRECTIVE */ &&940 isSpecialTemplateDirective(p.name))) {941 ( true) &&942 warnDeprecation("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context, node.loc);943 node = node.children;944 }945 }946 else if (s[1] === '?') {947 emitError(context, 21 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */, 1);948 node = parseBogusComment(context);949 }950 else {951 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 1);952 }953 }954 }955 if (!node) {956 node = parseText(context, mode);957 }958 if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isArray)(node)) {959 for (let i = 0; i < node.length; i++) {960 pushNode(nodes, node[i]);961 }962 }963 else {964 pushNode(nodes, node);965 }966 }967 // Whitespace handling strategy like v2968 let removedWhitespace = false;969 if (mode !== 2 /* RAWTEXT */ && mode !== 1 /* RCDATA */) {970 const preserve = context.options.whitespace === 'preserve';971 for (let i = 0; i < nodes.length; i++) {972 const node = nodes[i];973 if (!context.inPre && node.type === 2 /* TEXT */) {974 if (!/[^\t\r\n\f ]/.test(node.content)) {975 const prev = nodes[i - 1];976 const next = nodes[i + 1];977 // Remove if:978 // - the whitespace is the first or last node, or:979 // - (condense mode) the whitespace is adjacent to a comment, or:980 // - (condense mode) the whitespace is between two elements AND contains newline981 if (!prev ||982 !next ||983 (!preserve &&984 (prev.type === 3 /* COMMENT */ ||985 next.type === 3 /* COMMENT */ ||986 (prev.type === 1 /* ELEMENT */ &&987 next.type === 1 /* ELEMENT */ &&988 /[\r\n]/.test(node.content))))) {989 removedWhitespace = true;990 nodes[i] = null;991 }992 else {993 // Otherwise, the whitespace is condensed into a single space994 node.content = ' ';995 }996 }997 else if (!preserve) {998 // in condense mode, consecutive whitespaces in text are condensed999 // down to a single space.1000 node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ');1001 }1002 }1003 // also remove comment nodes in prod by default1004 if (false) {}1005 }1006 if (context.inPre && parent && context.options.isPreTag(parent.tag)) {1007 // remove leading newline per html spec1008 // https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element1009 const first = nodes[0];1010 if (first && first.type === 2 /* TEXT */) {1011 first.content = first.content.replace(/^\r?\n/, '');1012 }1013 }1014 }1015 return removedWhitespace ? nodes.filter(Boolean) : nodes;1016}1017function pushNode(nodes, node) {1018 if (node.type === 2 /* TEXT */) {1019 const prev = last(nodes);1020 // Merge if both this and the previous node are text and those are1021 // consecutive. This happens for cases like "a < b".1022 if (prev &&1023 prev.type === 2 /* TEXT */ &&1024 prev.loc.end.offset === node.loc.start.offset) {1025 prev.content += node.content;1026 prev.loc.end = node.loc.end;1027 prev.loc.source += node.loc.source;1028 return;1029 }1030 }1031 nodes.push(node);1032}1033function parseCDATA(context, ancestors) {1034 advanceBy(context, 9);1035 const nodes = parseChildren(context, 3 /* CDATA */, ancestors);1036 if (context.source.length === 0) {1037 emitError(context, 6 /* EOF_IN_CDATA */);1038 }1039 else {1040 advanceBy(context, 3);1041 }1042 return nodes;1043}1044function parseComment(context) {1045 const start = getCursor(context);1046 let content;1047 // Regular comment.1048 const match = /--(\!)?>/.exec(context.source);1049 if (!match) {1050 content = context.source.slice(4);1051 advanceBy(context, context.source.length);1052 emitError(context, 7 /* EOF_IN_COMMENT */);1053 }1054 else {1055 if (match.index <= 3) {1056 emitError(context, 0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */);1057 }1058 if (match[1]) {1059 emitError(context, 10 /* INCORRECTLY_CLOSED_COMMENT */);1060 }1061 content = context.source.slice(4, match.index);1062 // Advancing with reporting nested comments.1063 const s = context.source.slice(0, match.index);1064 let prevIndex = 1, nestedIndex = 0;1065 while ((nestedIndex = s.indexOf('<!--', prevIndex)) !== -1) {1066 advanceBy(context, nestedIndex - prevIndex + 1);1067 if (nestedIndex + 4 < s.length) {1068 emitError(context, 16 /* NESTED_COMMENT */);1069 }1070 prevIndex = nestedIndex + 1;1071 }1072 advanceBy(context, match.index + match[0].length - prevIndex + 1);1073 }1074 return {1075 type: 3 /* COMMENT */,1076 content,1077 loc: getSelection(context, start)1078 };1079}1080function parseBogusComment(context) {1081 const start = getCursor(context);1082 const contentStart = context.source[1] === '?' ? 1 : 2;1083 let content;1084 const closeIndex = context.source.indexOf('>');1085 if (closeIndex === -1) {1086 content = context.source.slice(contentStart);1087 advanceBy(context, context.source.length);1088 }1089 else {1090 content = context.source.slice(contentStart, closeIndex);1091 advanceBy(context, closeIndex + 1);1092 }1093 return {1094 type: 3 /* COMMENT */,1095 content,1096 loc: getSelection(context, start)1097 };1098}1099function parseElement(context, ancestors) {1100 // Start tag.1101 const wasInPre = context.inPre;1102 const wasInVPre = context.inVPre;1103 const parent = last(ancestors);1104 const element = parseTag(context, 0 /* Start */, parent);1105 const isPreBoundary = context.inPre && !wasInPre;1106 const isVPreBoundary = context.inVPre && !wasInVPre;1107 if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {1108 // #4030 self-closing <pre> tag1109 if (context.options.isPreTag(element.tag)) {1110 context.inPre = false;1111 }1112 return element;1113 }1114 // Children.1115 ancestors.push(element);1116 const mode = context.options.getTextMode(element, parent);1117 const children = parseChildren(context, mode, ancestors);1118 ancestors.pop();1119 // 2.x inline-template compat1120 {1121 const inlineTemplateProp = element.props.find(p => p.type === 6 /* ATTRIBUTE */ && p.name === 'inline-template');1122 if (inlineTemplateProp &&1123 checkCompatEnabled("COMPILER_INLINE_TEMPLATE" /* COMPILER_INLINE_TEMPLATE */, context, inlineTemplateProp.loc)) {1124 const loc = getSelection(context, element.loc.end);1125 inlineTemplateProp.value = {1126 type: 2 /* TEXT */,1127 content: loc.source,1128 loc1129 };1130 }1131 }1132 element.children = children;1133 // End tag.1134 if (startsWithEndTagOpen(context.source, element.tag)) {1135 parseTag(context, 1 /* End */, parent);1136 }1137 else {1138 emitError(context, 24 /* X_MISSING_END_TAG */, 0, element.loc.start);1139 if (context.source.length === 0 && element.tag.toLowerCase() === 'script') {1140 const first = children[0];1141 if (first && startsWith(first.loc.source, '<!--')) {1142 emitError(context, 8 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */);1143 }1144 }1145 }1146 element.loc = getSelection(context, element.loc.start);1147 if (isPreBoundary) {1148 context.inPre = false;1149 }1150 if (isVPreBoundary) {1151 context.inVPre = false;1152 }1153 return element;1154}1155const isSpecialTemplateDirective = /*#__PURE__*/ (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.makeMap)(`if,else,else-if,for,slot`);1156function parseTag(context, type, parent) {1157 // Tag open.1158 const start = getCursor(context);1159 const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source);1160 const tag = match[1];1161 const ns = context.options.getNamespace(tag, parent);1162 advanceBy(context, match[0].length);1163 advanceSpaces(context);1164 // save current state in case we need to re-parse attributes with v-pre1165 const cursor = getCursor(context);1166 const currentSource = context.source;1167 // check <pre> tag1168 const isPreTag = context.options.isPreTag(tag);1169 if (isPreTag) {1170 context.inPre = true;1171 }1172 // Attributes.1173 let props = parseAttributes(context, type);1174 // check v-pre1175 if (type === 0 /* Start */ &&1176 !context.inVPre &&1177 props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'pre')) {1178 context.inVPre = true;1179 // reset context1180 (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.extend)(context, cursor);1181 context.source = currentSource;1182 // re-parse attrs and filter out v-pre itself1183 props = parseAttributes(context, type).filter(p => p.name !== 'v-pre');1184 }1185 // Tag close.1186 let isSelfClosing = false;1187 if (context.source.length === 0) {1188 emitError(context, 9 /* EOF_IN_TAG */);1189 }1190 else {1191 isSelfClosing = startsWith(context.source, '/>');1192 if (type === 1 /* End */ && isSelfClosing) {1193 emitError(context, 4 /* END_TAG_WITH_TRAILING_SOLIDUS */);1194 }1195 advanceBy(context, isSelfClosing ? 2 : 1);1196 }1197 if (type === 1 /* End */) {1198 return;1199 }1200 // 2.x deprecation checks1201 if (( true) &&1202 isCompatEnabled("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context)) {1203 let hasIf = false;1204 let hasFor = false;1205 for (let i = 0; i < props.length; i++) {1206 const p = props[i];1207 if (p.type === 7 /* DIRECTIVE */) {1208 if (p.name === 'if') {1209 hasIf = true;1210 }1211 else if (p.name === 'for') {1212 hasFor = true;1213 }1214 }1215 if (hasIf && hasFor) {1216 warnDeprecation("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context, getSelection(context, start));1217 }1218 }1219 }1220 let tagType = 0 /* ELEMENT */;1221 if (!context.inVPre) {1222 if (tag === 'slot') {1223 tagType = 2 /* SLOT */;1224 }1225 else if (tag === 'template') {1226 if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {1227 tagType = 3 /* TEMPLATE */;1228 }1229 }1230 else if (isComponent(tag, props, context)) {1231 tagType = 1 /* COMPONENT */;1232 }1233 }1234 return {1235 type: 1 /* ELEMENT */,1236 ns,1237 tag,1238 tagType,1239 props,1240 isSelfClosing,1241 children: [],1242 loc: getSelection(context, start),1243 codegenNode: undefined // to be created during transform phase1244 };1245}1246function isComponent(tag, props, context) {1247 const options = context.options;1248 if (options.isCustomElement(tag)) {1249 return false;1250 }1251 if (tag === 'component' ||1252 /^[A-Z]/.test(tag) ||1253 isCoreComponent(tag) ||1254 (options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||1255 (options.isNativeTag && !options.isNativeTag(tag))) {1256 return true;1257 }1258 // at this point the tag should be a native tag, but check for potential "is"1259 // casting1260 for (let i = 0; i < props.length; i++) {1261 const p = props[i];1262 if (p.type === 6 /* ATTRIBUTE */) {1263 if (p.name === 'is' && p.value) {1264 if (p.value.content.startsWith('vue:')) {1265 return true;1266 }1267 else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1268 return true;1269 }1270 }1271 }1272 else {1273 // directive1274 // v-is (TODO Deprecate)1275 if (p.name === 'is') {1276 return true;1277 }1278 else if (1279 // :is on plain element - only treat as component in compat mode1280 p.name === 'bind' &&1281 isBindKey(p.arg, 'is') &&1282 true &&1283 checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1284 return true;1285 }1286 }1287 }1288}1289function parseAttributes(context, type) {1290 const props = [];1291 const attributeNames = new Set();1292 while (context.source.length > 0 &&1293 !startsWith(context.source, '>') &&1294 !startsWith(context.source, '/>')) {1295 if (startsWith(context.source, '/')) {1296 emitError(context, 22 /* UNEXPECTED_SOLIDUS_IN_TAG */);1297 advanceBy(context, 1);1298 advanceSpaces(context);1299 continue;1300 }1301 if (type === 1 /* End */) {1302 emitError(context, 3 /* END_TAG_WITH_ATTRIBUTES */);1303 }1304 const attr = parseAttribute(context, attributeNames);1305 if (type === 0 /* Start */) {1306 props.push(attr);1307 }1308 if (/^[^\t\r\n\f />]/.test(context.source)) {1309 emitError(context, 15 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */);1310 }1311 advanceSpaces(context);1312 }1313 return props;1314}1315function parseAttribute(context, nameSet) {1316 // Name.1317 const start = getCursor(context);1318 const match = /^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(context.source);1319 const name = match[0];1320 if (nameSet.has(name)) {1321 emitError(context, 2 /* DUPLICATE_ATTRIBUTE */);1322 }1323 nameSet.add(name);1324 if (name[0] === '=') {1325 emitError(context, 19 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */);1326 }1327 {1328 const pattern = /["'<]/g;1329 let m;1330 while ((m = pattern.exec(name))) {1331 emitError(context, 17 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */, m.index);1332 }1333 }1334 advanceBy(context, name.length);1335 // Value1336 let value = undefined;1337 if (/^[\t\r\n\f ]*=/.test(context.source)) {1338 advanceSpaces(context);1339 advanceBy(context, 1);1340 advanceSpaces(context);1341 value = parseAttributeValue(context);1342 if (!value) {1343 emitError(context, 13 /* MISSING_ATTRIBUTE_VALUE */);1344 }1345 }1346 const loc = getSelection(context, start);1347 if (!context.inVPre && /^(v-|:|@|#)/.test(name)) {1348 const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^@|^#)(\[[^\]]+\]|[^\.]+))?(.+)?$/i.exec(name);1349 let dirName = match[1] ||1350 (startsWith(name, ':') ? 'bind' : startsWith(name, '@') ? 'on' : 'slot');1351 let arg;1352 if (match[2]) {1353 const isSlot = dirName === 'slot';1354 const startOffset = name.lastIndexOf(match[2]);1355 const loc = getSelection(context, getNewPosition(context, start, startOffset), getNewPosition(context, start, startOffset + match[2].length + ((isSlot && match[3]) || '').length));1356 let content = match[2];1357 let isStatic = true;1358 if (content.startsWith('[')) {1359 isStatic = false;1360 if (!content.endsWith(']')) {1361 emitError(context, 26 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */);1362 }1363 content = content.substr(1, content.length - 2);1364 }1365 else if (isSlot) {1366 // #1241 special case for v-slot: vuetify relies extensively on slot1367 // names containing dots. v-slot doesn't have any modifiers and Vue 2.x1368 // supports such usage so we are keeping it consistent with 2.x.1369 content += match[3] || '';1370 }1371 arg = {1372 type: 4 /* SIMPLE_EXPRESSION */,1373 content,1374 isStatic,1375 constType: isStatic1376 ? 3 /* CAN_STRINGIFY */1377 : 0 /* NOT_CONSTANT */,1378 loc1379 };1380 }1381 if (value && value.isQuoted) {1382 const valueLoc = value.loc;1383 valueLoc.start.offset++;1384 valueLoc.start.column++;1385 valueLoc.end = advancePositionWithClone(valueLoc.start, value.content);1386 valueLoc.source = valueLoc.source.slice(1, -1);1387 }1388 const modifiers = match[3] ? match[3].substr(1).split('.') : [];1389 // 2.x compat v-bind:foo.sync -> v-model:foo1390 if (dirName === 'bind' && arg) {1391 if (modifiers.includes('sync') &&1392 checkCompatEnabled("COMPILER_V_BIND_SYNC" /* COMPILER_V_BIND_SYNC */, context, loc, arg.loc.source)) {1393 dirName = 'model';1394 modifiers.splice(modifiers.indexOf('sync'), 1);1395 }1396 if (( true) && modifiers.includes('prop')) {1397 checkCompatEnabled("COMPILER_V_BIND_PROP" /* COMPILER_V_BIND_PROP */, context, loc);1398 }1399 }1400 return {1401 type: 7 /* DIRECTIVE */,1402 name: dirName,1403 exp: value && {1404 type: 4 /* SIMPLE_EXPRESSION */,1405 content: value.content,1406 isStatic: false,1407 // Treat as non-constant by default. This can be potentially set to1408 // other values by `transformExpression` to make it eligible for hoisting.1409 constType: 0 /* NOT_CONSTANT */,1410 loc: value.loc1411 },1412 arg,1413 modifiers,1414 loc1415 };1416 }1417 return {1418 type: 6 /* ATTRIBUTE */,1419 name,1420 value: value && {1421 type: 2 /* TEXT */,1422 content: value.content,1423 loc: value.loc1424 },1425 loc1426 };1427}1428function parseAttributeValue(context) {1429 const start = getCursor(context);1430 let content;1431 const quote = context.source[0];1432 const isQuoted = quote === `"` || quote === `'`;1433 if (isQuoted) {1434 // Quoted value.1435 advanceBy(context, 1);1436 const endIndex = context.source.indexOf(quote);1437 if (endIndex === -1) {1438 content = parseTextData(context, context.source.length, 4 /* ATTRIBUTE_VALUE */);1439 }1440 else {1441 content = parseTextData(context, endIndex, 4 /* ATTRIBUTE_VALUE */);1442 advanceBy(context, 1);1443 }1444 }1445 else {1446 // Unquoted1447 const match = /^[^\t\r\n\f >]+/.exec(context.source);1448 if (!match) {1449 return undefined;1450 }1451 const unexpectedChars = /["'<=`]/g;1452 let m;1453 while ((m = unexpectedChars.exec(match[0]))) {1454 emitError(context, 18 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */, m.index);1455 }1456 content = parseTextData(context, match[0].length, 4 /* ATTRIBUTE_VALUE */);1457 }1458 return { content, isQuoted, loc: getSelection(context, start) };1459}1460function parseInterpolation(context, mode) {1461 const [open, close] = context.options.delimiters;1462 const closeIndex = context.source.indexOf(close, open.length);1463 if (closeIndex === -1) {1464 emitError(context, 25 /* X_MISSING_INTERPOLATION_END */);1465 return undefined;1466 }1467 const start = getCursor(context);1468 advanceBy(context, open.length);1469 const innerStart = getCursor(context);1470 const innerEnd = getCursor(context);1471 const rawContentLength = closeIndex - open.length;1472 const rawContent = context.source.slice(0, rawContentLength);1473 const preTrimContent = parseTextData(context, rawContentLength, mode);1474 const content = preTrimContent.trim();1475 const startOffset = preTrimContent.indexOf(content);1476 if (startOffset > 0) {1477 advancePositionWithMutation(innerStart, rawContent, startOffset);1478 }1479 const endOffset = rawContentLength - (preTrimContent.length - content.length - startOffset);1480 advancePositionWithMutation(innerEnd, rawContent, endOffset);1481 advanceBy(context, close.length);1482 return {1483 type: 5 /* INTERPOLATION */,1484 content: {1485 type: 4 /* SIMPLE_EXPRESSION */,1486 isStatic: false,1487 // Set `isConstant` to false by default and will decide in transformExpression1488 constType: 0 /* NOT_CONSTANT */,1489 content,1490 loc: getSelection(context, innerStart, innerEnd)1491 },1492 loc: getSelection(context, start)1493 };1494}1495function parseText(context, mode) {1496 const endTokens = ['<', context.options.delimiters[0]];1497 if (mode === 3 /* CDATA */) {1498 endTokens.push(']]>');1499 }1500 let endIndex = context.source.length;1501 for (let i = 0; i < endTokens.length; i++) {1502 const index = context.source.indexOf(endTokens[i], 1);1503 if (index !== -1 && endIndex > index) {1504 endIndex = index;1505 }1506 }1507 const start = getCursor(context);1508 const content = parseTextData(context, endIndex, mode);1509 return {1510 type: 2 /* TEXT */,1511 content,1512 loc: getSelection(context, start)1513 };1514}1515/**1516 * Get text data with a given length from the current location.1517 * This translates HTML entities in the text data.1518 */1519function parseTextData(context, length, mode) {1520 const rawText = context.source.slice(0, length);1521 advanceBy(context, length);1522 if (mode === 2 /* RAWTEXT */ ||1523 mode === 3 /* CDATA */ ||1524 rawText.indexOf('&') === -1) {1525 return rawText;1526 }1527 else {1528 // DATA or RCDATA containing "&"". Entity decoding required.1529 return context.options.decodeEntities(rawText, mode === 4 /* ATTRIBUTE_VALUE */);1530 }1531}1532function getCursor(context) {1533 const { column, line, offset } = context;1534 return { column, line, offset };1535}1536function getSelection(context, start, end) {1537 end = end || getCursor(context);1538 return {1539 start,1540 end,1541 source: context.originalSource.slice(start.offset, end.offset)1542 };1543}1544function last(xs) {1545 return xs[xs.length - 1];1546}1547function startsWith(source, searchString) {1548 return source.startsWith(searchString);1549}1550function advanceBy(context, numberOfCharacters) {1551 const { source } = context;1552 advancePositionWithMutation(context, source, numberOfCharacters);1553 context.source = source.slice(numberOfCharacters);1554}1555function advanceSpaces(context) {1556 const match = /^[\t\r\n\f ]+/.exec(context.source);1557 if (match) {1558 advanceBy(context, match[0].length);1559 }1560}1561function getNewPosition(context, start, numberOfCharacters) {1562 return advancePositionWithClone(start, context.originalSource.slice(start.offset, numberOfCharacters), numberOfCharacters);1563}1564function emitError(context, code, offset, loc = getCursor(context)) {1565 if (offset) {1566 loc.offset += offset;1567 loc.column += offset;1568 }1569 context.options.onError(createCompilerError(code, {1570 start: loc,1571 end: loc,1572 source: ''1573 }));1574}1575function isEnd(context, mode, ancestors) {1576 const s = context.source;1577 switch (mode) {1578 case 0 /* DATA */:1579 if (startsWith(s, '</')) {1580 // TODO: probably bad performance1581 for (let i = ancestors.length - 1; i >= 0; --i) {1582 if (startsWithEndTagOpen(s, ancestors[i].tag)) {1583 return true;1584 }1585 }1586 }1587 break;1588 case 1 /* RCDATA */:1589 case 2 /* RAWTEXT */: {1590 const parent = last(ancestors);1591 if (parent && startsWithEndTagOpen(s, parent.tag)) {1592 return true;1593 }1594 break;1595 }1596 case 3 /* CDATA */:1597 if (startsWith(s, ']]>')) {1598 return true;1599 }1600 break;1601 }1602 return !s;1603}1604function startsWithEndTagOpen(source, tag) {1605 return (startsWith(source, '</') &&1606 source.substr(2, tag.length).toLowerCase() === tag.toLowerCase() &&1607 /[\t\r\n\f />]/.test(source[2 + tag.length] || '>'));1608}1609function hoistStatic(root, context) {1610 walk(root, context, 1611 // Root node is unfortunately non-hoistable due to potential parent1612 // fallthrough attributes.1613 isSingleElementRoot(root, root.children[0]));1614}1615function isSingleElementRoot(root, child) {1616 const { children } = root;1617 return (children.length === 1 &&1618 child.type === 1 /* ELEMENT */ &&1619 !isSlotOutlet(child));1620}1621function walk(node, context, doNotHoistNode = false) {1622 let hasHoistedNode = false;1623 // Some transforms, e.g. transformAssetUrls from @vue/compiler-sfc, replaces1624 // static bindings with expressions. These expressions are guaranteed to be1625 // constant so they are still eligible for hoisting, but they are only1626 // available at runtime and therefore cannot be evaluated ahead of time.1627 // This is only a concern for pre-stringification (via transformHoist by1628 // @vue/compiler-dom), but doing it here allows us to perform only one full1629 // walk of the AST and allow `stringifyStatic` to stop walking as soon as its1630 // stringficiation threshold is met.1631 let canStringify = true;1632 const { children } = node;1633 for (let i = 0; i < children.length; i++) {1634 const child = children[i];1635 // only plain elements & text calls are eligible for hoisting.1636 if (child.type === 1 /* ELEMENT */ &&1637 child.tagType === 0 /* ELEMENT */) {1638 const constantType = doNotHoistNode1639 ? 0 /* NOT_CONSTANT */1640 : getConstantType(child, context);1641 if (constantType > 0 /* NOT_CONSTANT */) {1642 if (constantType < 3 /* CAN_STRINGIFY */) {1643 canStringify = false;1644 }1645 if (constantType >= 2 /* CAN_HOIST */) {1646 child.codegenNode.patchFlag =1647 -1 /* HOISTED */ + (( true) ? ` /* HOISTED */` : 0);1648 child.codegenNode = context.hoist(child.codegenNode);1649 hasHoistedNode = true;1650 continue;1651 }1652 }1653 else {1654 // node may contain dynamic children, but its props may be eligible for1655 // hoisting.1656 const codegenNode = child.codegenNode;1657 if (codegenNode.type === 13 /* VNODE_CALL */) {1658 const flag = getPatchFlag(codegenNode);1659 if ((!flag ||1660 flag === 512 /* NEED_PATCH */ ||1661 flag === 1 /* TEXT */) &&1662 getGeneratedPropsConstantType(child, context) >=1663 2 /* CAN_HOIST */) {1664 const props = getNodeProps(child);1665 if (props) {1666 codegenNode.props = context.hoist(props);1667 }1668 }1669 }1670 }1671 }1672 else if (child.type === 12 /* TEXT_CALL */) {1673 const contentType = getConstantType(child.content, context);1674 if (contentType > 0) {1675 if (contentType < 3 /* CAN_STRINGIFY */) {1676 canStringify = false;1677 }1678 if (contentType >= 2 /* CAN_HOIST */) {1679 child.codegenNode = context.hoist(child.codegenNode);1680 hasHoistedNode = true;1681 }1682 }1683 }1684 // walk further1685 if (child.type === 1 /* ELEMENT */) {1686 const isComponent = child.tagType === 1 /* COMPONENT */;1687 if (isComponent) {1688 context.scopes.vSlot++;1689 }1690 walk(child, context);1691 if (isComponent) {1692 context.scopes.vSlot--;1693 }1694 }1695 else if (child.type === 11 /* FOR */) {1696 // Do not hoist v-for single child because it has to be a block1697 walk(child, context, child.children.length === 1);1698 }1699 else if (child.type === 9 /* IF */) {1700 for (let i = 0; i < child.branches.length; i++) {1701 // Do not hoist v-if single child because it has to be a block1702 walk(child.branches[i], context, child.branches[i].children.length === 1);1703 }1704 }1705 }1706 if (canStringify && hasHoistedNode && context.transformHoist) {1707 context.transformHoist(children, context, node);1708 }1709}1710function getConstantType(node, context) {1711 const { constantCache } = context;1712 switch (node.type) {1713 case 1 /* ELEMENT */:1714 if (node.tagType !== 0 /* ELEMENT */) {1715 return 0 /* NOT_CONSTANT */;1716 }1717 const cached = constantCache.get(node);1718 if (cached !== undefined) {1719 return cached;1720 }1721 const codegenNode = node.codegenNode;1722 if (codegenNode.type !== 13 /* VNODE_CALL */) {1723 return 0 /* NOT_CONSTANT */;1724 }1725 const flag = getPatchFlag(codegenNode);1726 if (!flag) {1727 let returnType = 3 /* CAN_STRINGIFY */;1728 // Element itself has no patch flag. However we still need to check:1729 // 1. Even for a node with no patch flag, it is possible for it to contain1730 // non-hoistable expressions that refers to scope variables, e.g. compiler1731 // injected keys or cached event handlers. Therefore we need to always1732 // check the codegenNode's props to be sure.1733 const generatedPropsType = getGeneratedPropsConstantType(node, context);1734 if (generatedPropsType === 0 /* NOT_CONSTANT */) {1735 constantCache.set(node, 0 /* NOT_CONSTANT */);1736 return 0 /* NOT_CONSTANT */;1737 }1738 if (generatedPropsType < returnType) {1739 returnType = generatedPropsType;1740 }1741 // 2. its children.1742 for (let i = 0; i < node.children.length; i++) {1743 const childType = getConstantType(node.children[i], context);1744 if (childType === 0 /* NOT_CONSTANT */) {1745 constantCache.set(node, 0 /* NOT_CONSTANT */);1746 return 0 /* NOT_CONSTANT */;1747 }1748 if (childType < returnType) {1749 returnType = childType;1750 }1751 }1752 // 3. if the type is not already CAN_SKIP_PATCH which is the lowest non-01753 // type, check if any of the props can cause the type to be lowered1754 // we can skip can_patch because it's guaranteed by the absence of a1755 // patchFlag.1756 if (returnType > 1 /* CAN_SKIP_PATCH */) {1757 for (let i = 0; i < node.props.length; i++) {1758 const p = node.props[i];1759 if (p.type === 7 /* DIRECTIVE */ && p.name === 'bind' && p.exp) {1760 const expType = getConstantType(p.exp, context);1761 if (expType === 0 /* NOT_CONSTANT */) {1762 constantCache.set(node, 0 /* NOT_CONSTANT */);1763 return 0 /* NOT_CONSTANT */;1764 }1765 if (expType < returnType) {1766 returnType = expType;1767 }1768 }1769 }1770 }1771 // only svg/foreignObject could be block here, however if they are1772 // static then they don't need to be blocks since there will be no1773 // nested updates.1774 if (codegenNode.isBlock) {1775 context.removeHelper(OPEN_BLOCK);1776 context.removeHelper(CREATE_BLOCK);1777 codegenNode.isBlock = false;1778 context.helper(CREATE_VNODE);1779 }1780 constantCache.set(node, returnType);1781 return returnType;1782 }1783 else {1784 constantCache.set(node, 0 /* NOT_CONSTANT */);1785 return 0 /* NOT_CONSTANT */;1786 }1787 case 2 /* TEXT */:1788 case 3 /* COMMENT */:1789 return 3 /* CAN_STRINGIFY */;1790 case 9 /* IF */:1791 case 11 /* FOR */:1792 case 10 /* IF_BRANCH */:1793 return 0 /* NOT_CONSTANT */;1794 case 5 /* INTERPOLATION */:1795 case 12 /* TEXT_CALL */:1796 return getConstantType(node.content, context);1797 case 4 /* SIMPLE_EXPRESSION */:1798 return node.constType;1799 case 8 /* COMPOUND_EXPRESSION */:1800 let returnType = 3 /* CAN_STRINGIFY */;1801 for (let i = 0; i < node.children.length; i++) {1802 const child = node.children[i];1803 if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isString)(child) || (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isSymbol)(child)) {1804 continue;1805 }1806 const childType = getConstantType(child, context);1807 if (childType === 0 /* NOT_CONSTANT */) {1808 return 0 /* NOT_CONSTANT */;1809 }1810 else if (childType < returnType) {1811 returnType = childType;1812 }1813 }1814 return returnType;1815 default:1816 if ((true)) ;1817 return 0 /* NOT_CONSTANT */;1818 }1819}1820function getGeneratedPropsConstantType(node, context) {1821 let returnType = 3 /* CAN_STRINGIFY */;1822 const props = getNodeProps(node);1823 if (props && props.type === 15 /* JS_OBJECT_EXPRESSION */) {1824 const { properties } = props;1825 for (let i = 0; i < properties.length; i++) {1826 const { key, value } = properties[i];1827 const keyType = getConstantType(key, context);1828 if (keyType === 0 /* NOT_CONSTANT */) {1829 return keyType;1830 }1831 if (keyType < returnType) {1832 returnType = keyType;1833 }1834 if (value.type !== 4 /* SIMPLE_EXPRESSION */) {1835 return 0 /* NOT_CONSTANT */;1836 }1837 const valueType = getConstantType(value, context);1838 if (valueType === 0 /* NOT_CONSTANT */) {1839 return valueType;1840 }1841 if (valueType < returnType) {1842 returnType = valueType;1843 }1844 }1845 }1846 return returnType;1847}1848function getNodeProps(node) {1849 const codegenNode = node.codegenNode;1850 if (codegenNode.type === 13 /* VNODE_CALL */) {1851 return codegenNode.props;1852 }1853}1854function getPatchFlag(node) {1855 const flag = node.patchFlag;1856 return flag ? parseInt(flag, 10) : undefined;1857}1858function createTransformContext(root, { filename = '', prefixIdentifiers = false, hoistStatic = false, cacheHandlers = false, nodeTransforms = [], directiveTransforms = {}, transformHoist = null, isBuiltInComponent = _vue_shared__WEBPACK_IMPORTED_MODULE_0__.NOOP, isCustomElement = _vue_shared__WEBPACK_IMPORTED_MODULE_0__.NOOP, expressionPlugins = [], scopeId = null, slotted = true, ssr = false, ssrCssVars = ``, bindingMetadata = _vue_shared__WEBPACK_IMPORTED_MODULE_0__.EMPTY_OBJ, inline = false, isTS = false, onError = defaultOnError, onWarn = defaultOnWarn, compatConfig }) {1859 const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/);1860 const context = {1861 // options1862 selfName: nameMatch && (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.capitalize)((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.camelize)(nameMatch[1])),1863 prefixIdentifiers,1864 hoistStatic,1865 cacheHandlers,1866 nodeTransforms,1867 directiveTransforms,1868 transformHoist,1869 isBuiltInComponent,1870 isCustomElement,1871 expressionPlugins,1872 scopeId,1873 slotted,1874 ssr,1875 ssrCssVars,1876 bindingMetadata,1877 inline,1878 isTS,1879 onError,1880 onWarn,1881 compatConfig,1882 // state1883 root,1884 helpers: new Map(),1885 components: new Set(),1886 directives: new Set(),1887 hoists: [],1888 imports: [],1889 constantCache: new Map(),1890 temps: 0,1891 cached: 0,1892 identifiers: Object.create(null),1893 scopes: {1894 vFor: 0,1895 vSlot: 0,1896 vPre: 0,1897 vOnce: 01898 },1899 parent: null,1900 currentNode: root,1901 childIndex: 0,1902 // methods1903 helper(name) {1904 const count = context.helpers.get(name) || 0;1905 context.helpers.set(name, count + 1);1906 return name;1907 },1908 removeHelper(name) {1909 const count = context.helpers.get(name);1910 if (count) {1911 const currentCount = count - 1;1912 if (!currentCount) {1913 context.helpers.delete(name);1914 }1915 else {1916 context.helpers.set(name, currentCount);1917 }1918 }1919 },1920 helperString(name) {1921 return `_${helperNameMap[context.helper(name)]}`;1922 },1923 replaceNode(node) {1924 /* istanbul ignore if */1925 if ((true)) {1926 if (!context.currentNode) {1927 throw new Error(`Node being replaced is already removed.`);1928 }1929 if (!context.parent) {1930 throw new Error(`Cannot replace root node.`);1931 }1932 }1933 context.parent.children[context.childIndex] = context.currentNode = node;1934 },1935 removeNode(node) {1936 if (( true) && !context.parent) {1937 throw new Error(`Cannot remove root node.`);1938 }1939 const list = context.parent.children;1940 const removalIndex = node1941 ? list.indexOf(node)1942 : context.currentNode1943 ? context.childIndex1944 : -1;1945 /* istanbul ignore if */1946 if (( true) && removalIndex < 0) {1947 throw new Error(`node being removed is not a child of current parent`);1948 }1949 if (!node || node === context.currentNode) {1950 // current node removed1951 context.currentNode = null;1952 context.onNodeRemoved();1953 }1954 else {1955 // sibling node removed1956 if (context.childIndex > removalIndex) {1957 context.childIndex--;1958 context.onNodeRemoved();1959 }1960 }1961 context.parent.children.splice(removalIndex, 1);1962 },1963 onNodeRemoved: () => { },1964 addIdentifiers(exp) {1965 },1966 removeIdentifiers(exp) {1967 },1968 hoist(exp) {1969 context.hoists.push(exp);1970 const identifier = createSimpleExpression(`_hoisted_${context.hoists.length}`, false, exp.loc, 2 /* CAN_HOIST */);1971 identifier.hoisted = exp;1972 return identifier;1973 },1974 cache(exp, isVNode = false) {1975 return createCacheExpression(++context.cached, exp, isVNode);1976 }1977 };1978 {1979 context.filters = new Set();1980 }1981 return context;1982}1983function transform(root, options) {1984 const context = createTransformContext(root, options);1985 traverseNode(root, context);1986 if (options.hoistStatic) {1987 hoistStatic(root, context);1988 }1989 if (!options.ssr) {1990 createRootCodegen(root, context);1991 }1992 // finalize meta information1993 root.helpers = [...context.helpers.keys()];1994 root.components = [...context.components];1995 root.directives = [...context.directives];1996 root.imports = context.imports;1997 root.hoists = context.hoists;1998 root.temps = context.temps;1999 root.cached = context.cached;2000 {2001 root.filters = [...context.filters];2002 }2003}2004function createRootCodegen(root, context) {2005 const { helper, removeHelper } = context;2006 const { children } = root;2007 if (children.length === 1) {2008 const child = children[0];2009 // if the single child is an element, turn it into a block.2010 if (isSingleElementRoot(root, child) && child.codegenNode) {2011 // single element root is never hoisted so codegenNode will never be2012 // SimpleExpressionNode2013 const codegenNode = child.codegenNode;2014 if (codegenNode.type === 13 /* VNODE_CALL */) {2015 if (!codegenNode.isBlock) {2016 removeHelper(CREATE_VNODE);2017 codegenNode.isBlock = true;2018 helper(OPEN_BLOCK);2019 helper(CREATE_BLOCK);2020 }2021 }2022 root.codegenNode = codegenNode;2023 }2024 else {2025 // - single <slot/>, IfNode, ForNode: already blocks.2026 // - single text node: always patched.2027 // root codegen falls through via genNode()2028 root.codegenNode = child;2029 }2030 }2031 else if (children.length > 1) {2032 // root has multiple nodes - return a fragment block.2033 let patchFlag = 64 /* STABLE_FRAGMENT */;2034 let patchFlagText = _vue_shared__WEBPACK_IMPORTED_MODULE_0__.PatchFlagNames[64];2035 // check if the fragment actually contains a single valid child with2036 // the rest being comments2037 if (( true) &&2038 children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {2039 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;2040 patchFlagText += `, ${_vue_shared__WEBPACK_IMPORTED_MODULE_0__.PatchFlagNames[2048]}`;2041 }2042 root.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, root.children, patchFlag + (( true) ? ` /* ${patchFlagText} */` : 0), undefined, undefined, true);2043 }2044 else ;2045}2046function traverseChildren(parent, context) {2047 let i = 0;2048 const nodeRemoved = () => {2049 i--;2050 };2051 for (; i < parent.children.length; i++) {2052 const child = parent.children[i];2053 if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isString)(child))2054 continue;2055 context.parent = parent;2056 context.childIndex = i;2057 context.onNodeRemoved = nodeRemoved;2058 traverseNode(child, context);2059 }2060}2061function traverseNode(node, context) {2062 context.currentNode = node;2063 // apply transform plugins2064 const { nodeTransforms } = context;2065 const exitFns = [];2066 for (let i = 0; i < nodeTransforms.length; i++) {2067 const onExit = nodeTransforms[i](node, context);2068 if (onExit) {2069 if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isArray)(onExit)) {2070 exitFns.push(...onExit);2071 }2072 else {2073 exitFns.push(onExit);2074 }2075 }2076 if (!context.currentNode) {2077 // node was removed2078 return;2079 }2080 else {2081 // node may have been replaced2082 node = context.currentNode;2083 }2084 }2085 switch (node.type) {2086 case 3 /* COMMENT */:2087 if (!context.ssr) {2088 // inject import for the Comment symbol, which is needed for creating2089 // comment nodes with `createVNode`2090 context.helper(CREATE_COMMENT);2091 }2092 break;2093 case 5 /* INTERPOLATION */:2094 // no need to traverse, but we need to inject toString helper2095 if (!context.ssr) {2096 context.helper(TO_DISPLAY_STRING);2097 }2098 break;2099 // for container types, further traverse downwards2100 case 9 /* IF */:2101 for (let i = 0; i < node.branches.length; i++) {2102 traverseNode(node.branches[i], context);2103 }2104 break;2105 case 10 /* IF_BRANCH */:2106 case 11 /* FOR */:2107 case 1 /* ELEMENT */:2108 case 0 /* ROOT */:2109 traverseChildren(node, context);2110 break;2111 }2112 // exit transforms2113 context.currentNode = node;2114 let i = exitFns.length;2115 while (i--) {2116 exitFns[i]();2117 }2118}2119function createStructuralDirectiveTransform(name, fn) {2120 const matches = (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isString)(name)2121 ? (n) => n === name2122 : (n) => name.test(n);2123 return (node, context) => {2124 if (node.type === 1 /* ELEMENT */) {2125 const { props } = node;2126 // structural directive transforms are not concerned with slots2127 // as they are handled separately in vSlot.ts2128 if (node.tagType === 3 /* TEMPLATE */ && props.some(isVSlot)) {2129 return;2130 }2131 const exitFns = [];2132 for (let i = 0; i < props.length; i++) {2133 const prop = props[i];2134 if (prop.type === 7 /* DIRECTIVE */ && matches(prop.name)) {2135 // structural directives are removed to avoid infinite recursion2136 // also we remove them *before* applying so that it can further2137 // traverse itself in case it moves the node around2138 props.splice(i, 1);2139 i--;2140 const onExit = fn(node, prop, context);2141 if (onExit)2142 exitFns.push(onExit);2143 }2144 }2145 return exitFns;2146 }2147 };2148}2149const PURE_ANNOTATION = `/*#__PURE__*/`;2150function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssr = false, isTS = false }) {2151 const context = {2152 mode,2153 prefixIdentifiers,2154 sourceMap,2155 filename,2156 scopeId,2157 optimizeImports,2158 runtimeGlobalName,2159 runtimeModuleName,2160 ssr,2161 isTS,2162 source: ast.loc.source,2163 code: ``,2164 column: 1,2165 line: 1,2166 offset: 0,2167 indentLevel: 0,2168 pure: false,2169 map: undefined,2170 helper(key) {2171 return `_${helperNameMap[key]}`;2172 },2173 push(code, node) {2174 context.code += code;2175 },2176 indent() {2177 newline(++context.indentLevel);2178 },2179 deindent(withoutNewLine = false) {2180 if (withoutNewLine) {2181 --context.indentLevel;2182 }2183 else {2184 newline(--context.indentLevel);2185 }2186 },2187 newline() {2188 newline(context.indentLevel);2189 }2190 };2191 function newline(n) {2192 context.push('\n' + ` `.repeat(n));2193 }2194 return context;2195}2196function generate(ast, options = {}) {2197 const context = createCodegenContext(ast, options);2198 if (options.onContextCreated)2199 options.onContextCreated(context);2200 const { mode, push, prefixIdentifiers, indent, deindent, newline, scopeId, ssr } = context;2201 const hasHelpers = ast.helpers.length > 0;2202 const useWithBlock = !prefixIdentifiers && mode !== 'module';2203 // preambles2204 // in setup() inline mode, the preamble is generated in a sub context2205 // and returned separately.2206 const preambleContext = context;2207 {2208 genFunctionPreamble(ast, preambleContext);2209 }2210 // enter render function2211 const functionName = ssr ? `ssrRender` : `render`;2212 const args = ssr ? ['_ctx', '_push', '_parent', '_attrs'] : ['_ctx', '_cache'];2213 const signature = args.join(', ');2214 {2215 push(`function ${functionName}(${signature}) {`);2216 }2217 indent();2218 if (useWithBlock) {2219 push(`with (_ctx) {`);2220 indent();2221 // function mode const declarations should be inside with block2222 // also they should be renamed to avoid collision with user properties2223 if (hasHelpers) {2224 push(`const { ${ast.helpers2225 .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)2226 .join(', ')} } = _Vue`);2227 push(`\n`);2228 newline();2229 }2230 }2231 // generate asset resolution statements2232 if (ast.components.length) {2233 genAssets(ast.components, 'component', context);2234 if (ast.directives.length || ast.temps > 0) {2235 newline();2236 }2237 }2238 if (ast.directives.length) {2239 genAssets(ast.directives, 'directive', context);2240 if (ast.temps > 0) {2241 newline();2242 }2243 }2244 if (ast.filters && ast.filters.length) {2245 newline();2246 genAssets(ast.filters, 'filter', context);2247 newline();2248 }2249 if (ast.temps > 0) {2250 push(`let `);2251 for (let i = 0; i < ast.temps; i++) {2252 push(`${i > 0 ? `, ` : ``}_temp${i}`);2253 }2254 }2255 if (ast.components.length || ast.directives.length || ast.temps) {2256 push(`\n`);2257 newline();2258 }2259 // generate the VNode tree expression2260 if (!ssr) {2261 push(`return `);2262 }2263 if (ast.codegenNode) {2264 genNode(ast.codegenNode, context);2265 }2266 else {2267 push(`null`);2268 }2269 if (useWithBlock) {2270 deindent();2271 push(`}`);2272 }2273 deindent();2274 push(`}`);2275 return {2276 ast,2277 code: context.code,2278 preamble: ``,2279 // SourceMapGenerator does have toJSON() method but it's not in the types2280 map: context.map ? context.map.toJSON() : undefined2281 };2282}2283function genFunctionPreamble(ast, context) {2284 const { ssr, prefixIdentifiers, push, newline, runtimeModuleName, runtimeGlobalName } = context;2285 const VueBinding = runtimeGlobalName;2286 const aliasHelper = (s) => `${helperNameMap[s]}: _${helperNameMap[s]}`;2287 // Generate const declaration for helpers2288 // In prefix mode, we place the const declaration at top so it's done2289 // only once; But if we not prefixing, we place the declaration inside the2290 // with block so it doesn't incur the `in` check cost for every helper access.2291 if (ast.helpers.length > 0) {2292 {2293 // "with" mode.2294 // save Vue in a separate variable to avoid collision2295 push(`const _Vue = ${VueBinding}\n`);2296 // in "with" mode, helpers are declared inside the with block to avoid2297 // has check cost, but hoists are lifted out of the function - we need2298 // to provide the helper here.2299 if (ast.hoists.length) {2300 const staticHelpers = [2301 CREATE_VNODE,2302 CREATE_COMMENT,2303 CREATE_TEXT,2304 CREATE_STATIC2305 ]2306 .filter(helper => ast.helpers.includes(helper))2307 .map(aliasHelper)2308 .join(', ');2309 push(`const { ${staticHelpers} } = _Vue\n`);2310 }2311 }2312 }2313 genHoists(ast.hoists, context);2314 newline();2315 push(`return `);2316}2317function genAssets(assets, type, { helper, push, newline, isTS }) {2318 const resolver = helper(type === 'filter'2319 ? RESOLVE_FILTER2320 : type === 'component'2321 ? RESOLVE_COMPONENT2322 : RESOLVE_DIRECTIVE);2323 for (let i = 0; i < assets.length; i++) {2324 let id = assets[i];2325 // potential component implicit self-reference inferred from SFC filename2326 const maybeSelfReference = id.endsWith('__self');2327 if (maybeSelfReference) {2328 id = id.slice(0, -6);2329 }2330 push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`);2331 if (i < assets.length - 1) {2332 newline();2333 }2334 }2335}2336function genHoists(hoists, context) {2337 if (!hoists.length) {2338 return;2339 }2340 context.pure = true;2341 const { push, newline, helper, scopeId, mode } = context;2342 newline();2343 hoists.forEach((exp, i) => {2344 if (exp) {2345 push(`const _hoisted_${i + 1} = `);2346 genNode(exp, context);2347 newline();2348 }2349 });2350 context.pure = false;2351}2352function isText$1(n) {2353 return ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isString)(n) ||2354 n.type === 4 /* SIMPLE_EXPRESSION */ ||2355 n.type === 2 /* TEXT */ ||2356 n.type === 5 /* INTERPOLATION */ ||2357 n.type === 8 /* COMPOUND_EXPRESSION */);2358}2359function genNodeListAsArray(nodes, context) {2360 const multilines = nodes.length > 3 ||2361 ((( true)) && nodes.some(n => (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isArray)(n) || !isText$1(n)));2362 context.push(`[`);2363 multilines && context.indent();2364 genNodeList(nodes, context, multilines);2365 multilines && context.deindent();2366 context.push(`]`);2367}2368function genNodeList(nodes, context, multilines = false, comma = true) {2369 const { push, newline } = context;2370 for (let i = 0; i < nodes.length; i++) {2371 const node = nodes[i];2372 if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isString)(node)) {2373 push(node);2374 }2375 else if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isArray)(node)) {2376 genNodeListAsArray(node, context);2377 }2378 else {2379 genNode(node, context);2380 }2381 if (i < nodes.length - 1) {2382 if (multilines) {2383 comma && push(',');2384 newline();2385 }2386 else {2387 comma && push(', ');2388 }2389 }2390 }2391}2392function genNode(node, context) {2393 if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isString)(node)) {2394 context.push(node);2395 return;2396 }2397 if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isSymbol)(node)) {2398 context.push(context.helper(node));2399 return;2400 }2401 switch (node.type) {2402 case 1 /* ELEMENT */:2403 case 9 /* IF */:2404 case 11 /* FOR */:2405 ( true) &&2406 assert(node.codegenNode != null, `Codegen node is missing for element/if/for node. ` +2407 `Apply appropriate transforms first.`);2408 genNode(node.codegenNode, context);2409 break;2410 case 2 /* TEXT */:2411 genText(node, context);2412 break;2413 case 4 /* SIMPLE_EXPRESSION */:2414 genExpression(node, context);2415 break;2416 case 5 /* INTERPOLATION */:2417 genInterpolation(node, context);2418 break;2419 case 12 /* TEXT_CALL */:2420 genNode(node.codegenNode, context);2421 break;2422 case 8 /* COMPOUND_EXPRESSION */:2423 genCompoundExpression(node, context);2424 break;2425 case 3 /* COMMENT */:2426 genComment(node, context);2427 break;2428 case 13 /* VNODE_CALL */:2429 genVNodeCall(node, context);2430 break;2431 case 14 /* JS_CALL_EXPRESSION */:2432 genCallExpression(node, context);2433 break;2434 case 15 /* JS_OBJECT_EXPRESSION */:2435 genObjectExpression(node, context);2436 break;2437 case 17 /* JS_ARRAY_EXPRESSION */:2438 genArrayExpression(node, context);2439 break;2440 case 18 /* JS_FUNCTION_EXPRESSION */:2441 genFunctionExpression(node, context);2442 break;2443 case 19 /* JS_CONDITIONAL_EXPRESSION */:2444 genConditionalExpression(node, context);2445 break;2446 case 20 /* JS_CACHE_EXPRESSION */:2447 genCacheExpression(node, context);2448 break;2449 // SSR only types2450 case 21 /* JS_BLOCK_STATEMENT */:2451 break;2452 case 22 /* JS_TEMPLATE_LITERAL */:2453 break;2454 case 23 /* JS_IF_STATEMENT */:2455 break;2456 case 24 /* JS_ASSIGNMENT_EXPRESSION */:2457 break;2458 case 25 /* JS_SEQUENCE_EXPRESSION */:2459 break;2460 case 26 /* JS_RETURN_STATEMENT */:2461 break;2462 /* istanbul ignore next */2463 case 10 /* IF_BRANCH */:2464 // noop2465 break;2466 default:2467 if ((true)) {2468 assert(false, `unhandled codegen node type: ${node.type}`);2469 // make sure we exhaust all possible types2470 const exhaustiveCheck = node;2471 return exhaustiveCheck;2472 }2473 }2474}2475function genText(node, context) {2476 context.push(JSON.stringify(node.content), node);2477}2478function genExpression(node, context) {2479 const { content, isStatic } = node;2480 context.push(isStatic ? JSON.stringify(content) : content, node);2481}2482function genInterpolation(node, context) {2483 const { push, helper, pure } = context;2484 if (pure)2485 push(PURE_ANNOTATION);2486 push(`${helper(TO_DISPLAY_STRING)}(`);2487 genNode(node.content, context);2488 push(`)`);2489}2490function genCompoundExpression(node, context) {2491 for (let i = 0; i < node.children.length; i++) {2492 const child = node.children[i];2493 if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isString)(child)) {2494 context.push(child);2495 }2496 else {2497 genNode(child, context);2498 }2499 }2500}2501function genExpressionAsPropertyKey(node, context) {2502 const { push } = context;2503 if (node.type === 8 /* COMPOUND_EXPRESSION */) {2504 push(`[`);2505 genCompoundExpression(node, context);2506 push(`]`);2507 }2508 else if (node.isStatic) {2509 // only quote keys if necessary2510 const text = isSimpleIdentifier(node.content)2511 ? node.content2512 : JSON.stringify(node.content);2513 push(text, node);2514 }2515 else {2516 push(`[${node.content}]`, node);2517 }2518}2519function genComment(node, context) {2520 const { push, helper, pure } = context;2521 if (pure) {2522 push(PURE_ANNOTATION);2523 }2524 push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node);2525}2526function genVNodeCall(node, context) {2527 const { push, helper, pure } = context;2528 const { tag, props, children, patchFlag, dynamicProps, directives, isBlock, disableTracking } = node;2529 if (directives) {2530 push(helper(WITH_DIRECTIVES) + `(`);2531 }2532 if (isBlock) {2533 push(`(${helper(OPEN_BLOCK)}(${disableTracking ? `true` : ``}), `);2534 }2535 if (pure) {2536 push(PURE_ANNOTATION);2537 }2538 push(helper(isBlock ? CREATE_BLOCK : CREATE_VNODE) + `(`, node);2539 genNodeList(genNullableArgs([tag, props, children, patchFlag, dynamicProps]), context);2540 push(`)`);2541 if (isBlock) {2542 push(`)`);2543 }2544 if (directives) {2545 push(`, `);2546 genNode(directives, context);2547 push(`)`);2548 }2549}2550function genNullableArgs(args) {2551 let i = args.length;2552 while (i--) {2553 if (args[i] != null)2554 break;2555 }2556 return args.slice(0, i + 1).map(arg => arg || `null`);2557}2558// JavaScript2559function genCallExpression(node, context) {2560 const { push, helper, pure } = context;2561 const callee = (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isString)(node.callee) ? node.callee : helper(node.callee);2562 if (pure) {2563 push(PURE_ANNOTATION);2564 }2565 push(callee + `(`, node);2566 genNodeList(node.arguments, context);2567 push(`)`);2568}2569function genObjectExpression(node, context) {2570 const { push, indent, deindent, newline } = context;2571 const { properties } = node;2572 if (!properties.length) {2573 push(`{}`, node);2574 return;2575 }2576 const multilines = properties.length > 1 ||2577 ((( true)) &&2578 properties.some(p => p.value.type !== 4 /* SIMPLE_EXPRESSION */));2579 push(multilines ? `{` : `{ `);2580 multilines && indent();2581 for (let i = 0; i < properties.length; i++) {2582 const { key, value } = properties[i];2583 // key2584 genExpressionAsPropertyKey(key, context);2585 push(`: `);2586 // value2587 genNode(value, context);2588 if (i < properties.length - 1) {2589 // will only reach this if it's multilines2590 push(`,`);2591 newline();2592 }2593 }2594 multilines && deindent();2595 push(multilines ? `}` : ` }`);2596}2597function genArrayExpression(node, context) {2598 genNodeListAsArray(node.elements, context);2599}2600function genFunctionExpression(node, context) {2601 const { push, indent, deindent, scopeId, mode } = context;2602 const { params, returns, body, newline, isSlot } = node;2603 if (isSlot) {2604 // wrap slot functions with owner context2605 push(`_${helperNameMap[WITH_CTX]}(`);2606 }2607 push(`(`, node);2608 if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isArray)(params)) {2609 genNodeList(params, context);2610 }2611 else if (params) {2612 genNode(params, context);2613 }2614 push(`) => `);2615 if (newline || body) {2616 push(`{`);2617 indent();2618 }2619 if (returns) {2620 if (newline) {2621 push(`return `);2622 }2623 if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isArray)(returns)) {2624 genNodeListAsArray(returns, context);2625 }2626 else {2627 genNode(returns, context);2628 }2629 }2630 else if (body) {2631 genNode(body, context);2632 }2633 if (newline || body) {2634 deindent();2635 push(`}`);2636 }2637 if (isSlot) {2638 if (node.isNonScopedSlot) {2639 push(`, undefined, true`);2640 }2641 push(`)`);2642 }2643}2644function genConditionalExpression(node, context) {2645 const { test, consequent, alternate, newline: needNewline } = node;2646 const { push, indent, deindent, newline } = context;2647 if (test.type === 4 /* SIMPLE_EXPRESSION */) {2648 const needsParens = !isSimpleIdentifier(test.content);2649 needsParens && push(`(`);2650 genExpression(test, context);2651 needsParens && push(`)`);2652 }2653 else {2654 push(`(`);2655 genNode(test, context);2656 push(`)`);2657 }2658 needNewline && indent();2659 context.indentLevel++;2660 needNewline || push(` `);2661 push(`? `);2662 genNode(consequent, context);2663 context.indentLevel--;2664 needNewline && newline();2665 needNewline || push(` `);2666 push(`: `);2667 const isNested = alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */;2668 if (!isNested) {2669 context.indentLevel++;2670 }2671 genNode(alternate, context);2672 if (!isNested) {2673 context.indentLevel--;2674 }2675 needNewline && deindent(true /* without newline */);2676}2677function genCacheExpression(node, context) {2678 const { push, helper, indent, deindent, newline } = context;2679 push(`_cache[${node.index}] || (`);2680 if (node.isVNode) {2681 indent();2682 push(`${helper(SET_BLOCK_TRACKING)}(-1),`);2683 newline();2684 }2685 push(`_cache[${node.index}] = `);2686 genNode(node.value, context);2687 if (node.isVNode) {2688 push(`,`);2689 newline();2690 push(`${helper(SET_BLOCK_TRACKING)}(1),`);2691 newline();2692 push(`_cache[${node.index}]`);2693 deindent();2694 }2695 push(`)`);2696}2697// these keywords should not appear inside expressions, but operators like2698// typeof, instanceof and in are allowed2699const prohibitedKeywordRE = new RegExp('\\b' +2700 ('do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,' +2701 'super,throw,while,yield,delete,export,import,return,switch,default,' +2702 'extends,finally,continue,debugger,function,arguments,typeof,void')2703 .split(',')2704 .join('\\b|\\b') +2705 '\\b');2706// strip strings in expressions2707const stripStringRE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`/g;2708/**2709 * Validate a non-prefixed expression.2710 * This is only called when using the in-browser runtime compiler since it2711 * doesn't prefix expressions.2712 */2713function validateBrowserExpression(node, context, asParams = false, asRawStatements = false) {2714 const exp = node.content;2715 // empty expressions are validated per-directive since some directives2716 // do allow empty expressions.2717 if (!exp.trim()) {2718 return;2719 }2720 try {2721 new Function(asRawStatements2722 ? ` ${exp} `2723 : `return ${asParams ? `(${exp}) => {}` : `(${exp})`}`);2724 }2725 catch (e) {2726 let message = e.message;2727 const keywordMatch = exp2728 .replace(stripStringRE, '')2729 .match(prohibitedKeywordRE);2730 if (keywordMatch) {2731 message = `avoid using JavaScript keyword as property name: "${keywordMatch[0]}"`;2732 }2733 context.onError(createCompilerError(43 /* X_INVALID_EXPRESSION */, node.loc, undefined, message));2734 }2735}2736const transformExpression = (node, context) => {2737 if (node.type === 5 /* INTERPOLATION */) {2738 node.content = processExpression(node.content, context);2739 }2740 else if (node.type === 1 /* ELEMENT */) {2741 // handle directives on element2742 for (let i = 0; i < node.props.length; i++) {2743 const dir = node.props[i];2744 // do not process for v-on & v-for since they are special handled2745 if (dir.type === 7 /* DIRECTIVE */ && dir.name !== 'for') {2746 const exp = dir.exp;2747 const arg = dir.arg;2748 // do not process exp if this is v-on:arg - we need special handling2749 // for wrapping inline statements.2750 if (exp &&2751 exp.type === 4 /* SIMPLE_EXPRESSION */ &&2752 !(dir.name === 'on' && arg)) {2753 dir.exp = processExpression(exp, context, 2754 // slot args must be processed as function params2755 dir.name === 'slot');2756 }2757 if (arg && arg.type === 4 /* SIMPLE_EXPRESSION */ && !arg.isStatic) {2758 dir.arg = processExpression(arg, context);2759 }2760 }2761 }2762 }2763};2764// Important: since this function uses Node.js only dependencies, it should2765// always be used with a leading !true check so that it can be2766// tree-shaken from the browser build.2767function processExpression(node, context, 2768// some expressions like v-slot props & v-for aliases should be parsed as2769// function params2770asParams = false, 2771// v-on handler values may contain multiple statements2772asRawStatements = false) {2773 {2774 if ((true)) {2775 // simple in-browser validation (same logic in 2.x)2776 validateBrowserExpression(node, context, asParams, asRawStatements);2777 }2778 return node;2779 }2780}2781const transformIf = createStructuralDirectiveTransform(/^(if|else|else-if)$/, (node, dir, context) => {2782 return processIf(node, dir, context, (ifNode, branch, isRoot) => {2783 // #1587: We need to dynamically increment the key based on the current2784 // node's sibling nodes, since chained v-if/else branches are2785 // rendered at the same depth2786 const siblings = context.parent.children;2787 let i = siblings.indexOf(ifNode);2788 let key = 0;2789 while (i-- >= 0) {2790 const sibling = siblings[i];2791 if (sibling && sibling.type === 9 /* IF */) {2792 key += sibling.branches.length;2793 }2794 }2795 // Exit callback. Complete the codegenNode when all children have been2796 // transformed.2797 return () => {2798 if (isRoot) {2799 ifNode.codegenNode = createCodegenNodeForBranch(branch, key, context);2800 }2801 else {2802 // attach this branch's codegen node to the v-if root.2803 const parentCondition = getParentCondition(ifNode.codegenNode);2804 parentCondition.alternate = createCodegenNodeForBranch(branch, key + ifNode.branches.length - 1, context);2805 }2806 };2807 });2808});2809// target-agnostic transform used for both Client and SSR2810function processIf(node, dir, context, processCodegen) {2811 if (dir.name !== 'else' &&2812 (!dir.exp || !dir.exp.content.trim())) {2813 const loc = dir.exp ? dir.exp.loc : node.loc;2814 context.onError(createCompilerError(27 /* X_V_IF_NO_EXPRESSION */, dir.loc));2815 dir.exp = createSimpleExpression(`true`, false, loc);2816 }2817 if ( true && dir.exp) {2818 validateBrowserExpression(dir.exp, context);2819 }2820 if (dir.name === 'if') {2821 const branch = createIfBranch(node, dir);2822 const ifNode = {2823 type: 9 /* IF */,2824 loc: node.loc,2825 branches: [branch]2826 };2827 context.replaceNode(ifNode);2828 if (processCodegen) {2829 return processCodegen(ifNode, branch, true);2830 }2831 }2832 else {2833 // locate the adjacent v-if2834 const siblings = context.parent.children;2835 const comments = [];2836 let i = siblings.indexOf(node);2837 while (i-- >= -1) {2838 const sibling = siblings[i];2839 if (( true) && sibling && sibling.type === 3 /* COMMENT */) {2840 context.removeNode(sibling);2841 comments.unshift(sibling);2842 continue;2843 }2844 if (sibling &&2845 sibling.type === 2 /* TEXT */ &&2846 !sibling.content.trim().length) {2847 context.removeNode(sibling);2848 continue;2849 }2850 if (sibling && sibling.type === 9 /* IF */) {2851 // move the node to the if node's branches2852 context.removeNode();2853 const branch = createIfBranch(node, dir);2854 if (( true) &&2855 comments.length &&2856 // #3619 ignore comments if the v-if is direct child of <transition>2857 !(context.parent &&2858 context.parent.type === 1 /* ELEMENT */ &&2859 isBuiltInType(context.parent.tag, 'transition'))) {2860 branch.children = [...comments, ...branch.children];2861 }2862 // check if user is forcing same key on different branches2863 if (true) {2864 const key = branch.userKey;2865 if (key) {2866 sibling.branches.forEach(({ userKey }) => {2867 if (isSameKey(userKey, key)) {2868 context.onError(createCompilerError(28 /* X_V_IF_SAME_KEY */, branch.userKey.loc));2869 }2870 });2871 }2872 }2873 sibling.branches.push(branch);2874 const onExit = processCodegen && processCodegen(sibling, branch, false);2875 // since the branch was removed, it will not be traversed.2876 // make sure to traverse here.2877 traverseNode(branch, context);2878 // call on exit2879 if (onExit)2880 onExit();2881 // make sure to reset currentNode after traversal to indicate this2882 // node has been removed.2883 context.currentNode = null;2884 }2885 else {2886 context.onError(createCompilerError(29 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));2887 }2888 break;2889 }2890 }2891}2892function createIfBranch(node, dir) {2893 return {2894 type: 10 /* IF_BRANCH */,2895 loc: node.loc,2896 condition: dir.name === 'else' ? undefined : dir.exp,2897 children: node.tagType === 3 /* TEMPLATE */ && !findDir(node, 'for')2898 ? node.children2899 : [node],2900 userKey: findProp(node, `key`)2901 };2902}2903function createCodegenNodeForBranch(branch, keyIndex, context) {2904 if (branch.condition) {2905 return createConditionalExpression(branch.condition, createChildrenCodegenNode(branch, keyIndex, context), 2906 // make sure to pass in asBlock: true so that the comment node call2907 // closes the current block.2908 createCallExpression(context.helper(CREATE_COMMENT), [2909 ( true) ? '"v-if"' : 0,2910 'true'2911 ]));2912 }2913 else {2914 return createChildrenCodegenNode(branch, keyIndex, context);2915 }2916}2917function createChildrenCodegenNode(branch, keyIndex, context) {2918 const { helper, removeHelper } = context;2919 const keyProperty = createObjectProperty(`key`, createSimpleExpression(`${keyIndex}`, false, locStub, 2 /* CAN_HOIST */));2920 const { children } = branch;2921 const firstChild = children[0];2922 const needFragmentWrapper = children.length !== 1 || firstChild.type !== 1 /* ELEMENT */;2923 if (needFragmentWrapper) {2924 if (children.length === 1 && firstChild.type === 11 /* FOR */) {2925 // optimize away nested fragments when child is a ForNode2926 const vnodeCall = firstChild.codegenNode;2927 injectProp(vnodeCall, keyProperty, context);2928 return vnodeCall;2929 }2930 else {2931 let patchFlag = 64 /* STABLE_FRAGMENT */;2932 let patchFlagText = _vue_shared__WEBPACK_IMPORTED_MODULE_0__.PatchFlagNames[64];2933 // check if the fragment actually contains a single valid child with2934 // the rest being comments2935 if (( true) &&2936 children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {2937 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;2938 patchFlagText += `, ${_vue_shared__WEBPACK_IMPORTED_MODULE_0__.PatchFlagNames[2048]}`;2939 }2940 return createVNodeCall(context, helper(FRAGMENT), createObjectExpression([keyProperty]), children, patchFlag + (( true) ? ` /* ${patchFlagText} */` : 0), undefined, undefined, true, false, branch.loc);2941 }2942 }2943 else {2944 const vnodeCall = firstChild2945 .codegenNode;2946 // Change createVNode to createBlock.2947 if (vnodeCall.type === 13 /* VNODE_CALL */ && !vnodeCall.isBlock) {2948 removeHelper(CREATE_VNODE);2949 vnodeCall.isBlock = true;2950 helper(OPEN_BLOCK);2951 helper(CREATE_BLOCK);2952 }2953 // inject branch key2954 injectProp(vnodeCall, keyProperty, context);2955 return vnodeCall;2956 }2957}2958function isSameKey(a, b) {2959 if (!a || a.type !== b.type) {2960 return false;2961 }2962 if (a.type === 6 /* ATTRIBUTE */) {2963 if (a.value.content !== b.value.content) {2964 return false;2965 }2966 }2967 else {2968 // directive2969 const exp = a.exp;2970 const branchExp = b.exp;2971 if (exp.type !== branchExp.type) {2972 return false;2973 }2974 if (exp.type !== 4 /* SIMPLE_EXPRESSION */ ||2975 (exp.isStatic !== branchExp.isStatic ||2976 exp.content !== branchExp.content)) {2977 return false;2978 }2979 }2980 return true;2981}2982function getParentCondition(node) {2983 while (true) {2984 if (node.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {2985 if (node.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {2986 node = node.alternate;2987 }2988 else {2989 return node;2990 }2991 }2992 else if (node.type === 20 /* JS_CACHE_EXPRESSION */) {2993 node = node.value;2994 }2995 }2996}2997const transformFor = createStructuralDirectiveTransform('for', (node, dir, context) => {2998 const { helper, removeHelper } = context;2999 return processFor(node, dir, context, forNode => {3000 // create the loop render function expression now, and add the3001 // iterator on exit after all children have been traversed3002 const renderExp = createCallExpression(helper(RENDER_LIST), [3003 forNode.source3004 ]);3005 const keyProp = findProp(node, `key`);3006 const keyProperty = keyProp3007 ? createObjectProperty(`key`, keyProp.type === 6 /* ATTRIBUTE */3008 ? createSimpleExpression(keyProp.value.content, true)3009 : keyProp.exp)3010 : null;3011 const isStableFragment = forNode.source.type === 4 /* SIMPLE_EXPRESSION */ &&3012 forNode.source.constType > 0 /* NOT_CONSTANT */;3013 const fragmentFlag = isStableFragment3014 ? 64 /* STABLE_FRAGMENT */3015 : keyProp3016 ? 128 /* KEYED_FRAGMENT */3017 : 256 /* UNKEYED_FRAGMENT */;3018 forNode.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, renderExp, fragmentFlag +3019 (( true) ? ` /* ${_vue_shared__WEBPACK_IMPORTED_MODULE_0__.PatchFlagNames[fragmentFlag]} */` : 0), undefined, undefined, true /* isBlock */, !isStableFragment /* disableTracking */, node.loc);3020 return () => {3021 // finish the codegen now that all children have been traversed3022 let childBlock;3023 const isTemplate = isTemplateNode(node);3024 const { children } = forNode;3025 // check <template v-for> key placement3026 if (( true) && isTemplate) {3027 node.children.some(c => {3028 if (c.type === 1 /* ELEMENT */) {3029 const key = findProp(c, 'key');3030 if (key) {3031 context.onError(createCompilerError(32 /* X_V_FOR_TEMPLATE_KEY_PLACEMENT */, key.loc));3032 return true;3033 }3034 }3035 });3036 }3037 const needFragmentWrapper = children.length !== 1 || children[0].type !== 1 /* ELEMENT */;3038 const slotOutlet = isSlotOutlet(node)3039 ? node3040 : isTemplate &&3041 node.children.length === 1 &&3042 isSlotOutlet(node.children[0])3043 ? node.children[0] // api-extractor somehow fails to infer this3044 : null;3045 if (slotOutlet) {3046 // <slot v-for="..."> or <template v-for="..."><slot/></template>3047 childBlock = slotOutlet.codegenNode;3048 if (isTemplate && keyProperty) {3049 // <template v-for="..." :key="..."><slot/></template>3050 // we need to inject the key to the renderSlot() call.3051 // the props for renderSlot is passed as the 3rd argument.3052 injectProp(childBlock, keyProperty, context);3053 }3054 }3055 else if (needFragmentWrapper) {3056 // <template v-for="..."> with text or multi-elements3057 // should generate a fragment block for each loop3058 childBlock = createVNodeCall(context, helper(FRAGMENT), keyProperty ? createObjectExpression([keyProperty]) : undefined, node.children, 64 /* STABLE_FRAGMENT */ +3059 (( true)3060 ? ` /* ${_vue_shared__WEBPACK_IMPORTED_MODULE_0__.PatchFlagNames[64]} */`3061 : 0), undefined, undefined, true);3062 }3063 else {3064 // Normal element v-for. Directly use the child's codegenNode3065 // but mark it as a block.3066 childBlock = children[0]3067 .codegenNode;3068 if (isTemplate && keyProperty) {3069 injectProp(childBlock, keyProperty, context);3070 }3071 if (childBlock.isBlock !== !isStableFragment) {3072 if (childBlock.isBlock) {3073 // switch from block to vnode3074 removeHelper(OPEN_BLOCK);3075 removeHelper(CREATE_BLOCK);3076 }3077 else {3078 // switch from vnode to block3079 removeHelper(CREATE_VNODE);3080 }3081 }3082 childBlock.isBlock = !isStableFragment;3083 if (childBlock.isBlock) {3084 helper(OPEN_BLOCK);3085 helper(CREATE_BLOCK);3086 }3087 else {3088 helper(CREATE_VNODE);3089 }3090 }3091 renderExp.arguments.push(createFunctionExpression(createForLoopParams(forNode.parseResult), childBlock, true /* force newline */));3092 };3093 });3094});3095// target-agnostic transform used for both Client and SSR3096function processFor(node, dir, context, processCodegen) {3097 if (!dir.exp) {3098 context.onError(createCompilerError(30 /* X_V_FOR_NO_EXPRESSION */, dir.loc));3099 return;3100 }3101 const parseResult = parseForExpression(3102 // can only be simple expression because vFor transform is applied3103 // before expression transform.3104 dir.exp, context);3105 if (!parseResult) {3106 context.onError(createCompilerError(31 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));3107 return;3108 }3109 const { addIdentifiers, removeIdentifiers, scopes } = context;3110 const { source, value, key, index } = parseResult;3111 const forNode = {3112 type: 11 /* FOR */,3113 loc: dir.loc,3114 source,3115 valueAlias: value,3116 keyAlias: key,3117 objectIndexAlias: index,3118 parseResult,3119 children: isTemplateNode(node) ? node.children : [node]3120 };3121 context.replaceNode(forNode);3122 // bookkeeping3123 scopes.vFor++;3124 const onExit = processCodegen && processCodegen(forNode);3125 return () => {3126 scopes.vFor--;3127 if (onExit)3128 onExit();3129 };3130}3131const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;3132// This regex doesn't cover the case if key or index aliases have destructuring,3133// but those do not make sense in the first place, so this works in practice.3134const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;3135const stripParensRE = /^\(|\)$/g;3136function parseForExpression(input, context) {3137 const loc = input.loc;3138 const exp = input.content;3139 const inMatch = exp.match(forAliasRE);3140 if (!inMatch)3141 return;3142 const [, LHS, RHS] = inMatch;3143 const result = {3144 source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),3145 value: undefined,3146 key: undefined,3147 index: undefined3148 };3149 if (true) {3150 validateBrowserExpression(result.source, context);3151 }3152 let valueContent = LHS.trim()3153 .replace(stripParensRE, '')3154 .trim();3155 const trimmedOffset = LHS.indexOf(valueContent);3156 const iteratorMatch = valueContent.match(forIteratorRE);3157 if (iteratorMatch) {3158 valueContent = valueContent.replace(forIteratorRE, '').trim();3159 const keyContent = iteratorMatch[1].trim();3160 let keyOffset;3161 if (keyContent) {3162 keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);3163 result.key = createAliasExpression(loc, keyContent, keyOffset);3164 if (true) {3165 validateBrowserExpression(result.key, context, true);3166 }3167 }3168 if (iteratorMatch[2]) {3169 const indexContent = iteratorMatch[2].trim();3170 if (indexContent) {3171 result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key3172 ? keyOffset + keyContent.length3173 : trimmedOffset + valueContent.length));3174 if (true) {3175 validateBrowserExpression(result.index, context, true);3176 }3177 }3178 }3179 }3180 if (valueContent) {3181 result.value = createAliasExpression(loc, valueContent, trimmedOffset);3182 if (true) {3183 validateBrowserExpression(result.value, context, true);3184 }3185 }3186 return result;3187}3188function createAliasExpression(range, content, offset) {3189 return createSimpleExpression(content, false, getInnerRange(range, offset, content.length));3190}3191function createForLoopParams({ value, key, index }) {3192 const params = [];3193 if (value) {3194 params.push(value);3195 }3196 if (key) {3197 if (!value) {3198 params.push(createSimpleExpression(`_`, false));3199 }3200 params.push(key);3201 }3202 if (index) {3203 if (!key) {3204 if (!value) {3205 params.push(createSimpleExpression(`_`, false));3206 }3207 params.push(createSimpleExpression(`__`, false));3208 }3209 params.push(index);3210 }3211 return params;3212}3213const defaultFallback = createSimpleExpression(`undefined`, false);3214// A NodeTransform that:3215// 1. Tracks scope identifiers for scoped slots so that they don't get prefixed3216// by transformExpression. This is only applied in non-browser builds with3217// { prefixIdentifiers: true }.3218// 2. Track v-slot depths so that we know a slot is inside another slot.3219// Note the exit callback is executed before buildSlots() on the same node,3220// so only nested slots see positive numbers.3221const trackSlotScopes = (node, context) => {3222 if (node.type === 1 /* ELEMENT */ &&3223 (node.tagType === 1 /* COMPONENT */ ||3224 node.tagType === 3 /* TEMPLATE */)) {3225 // We are only checking non-empty v-slot here3226 // since we only care about slots that introduce scope variables.3227 const vSlot = findDir(node, 'slot');3228 if (vSlot) {3229 vSlot.exp;3230 context.scopes.vSlot++;3231 return () => {3232 context.scopes.vSlot--;3233 };3234 }3235 }3236};3237// A NodeTransform that tracks scope identifiers for scoped slots with v-for.3238// This transform is only applied in non-browser builds with { prefixIdentifiers: true }3239const trackVForSlotScopes = (node, context) => {3240 let vFor;3241 if (isTemplateNode(node) &&3242 node.props.some(isVSlot) &&3243 (vFor = findDir(node, 'for'))) {3244 const result = (vFor.parseResult = parseForExpression(vFor.exp, context));3245 if (result) {3246 const { value, key, index } = result;3247 const { addIdentifiers, removeIdentifiers } = context;3248 value && addIdentifiers(value);3249 key && addIdentifiers(key);3250 index && addIdentifiers(index);3251 return () => {3252 value && removeIdentifiers(value);3253 key && removeIdentifiers(key);3254 index && removeIdentifiers(index);3255 };3256 }3257 }3258};3259const buildClientSlotFn = (props, children, loc) => createFunctionExpression(props, children, false /* newline */, true /* isSlot */, children.length ? children[0].loc : loc);3260// Instead of being a DirectiveTransform, v-slot processing is called during3261// transformElement to build the slots object for a component.3262function buildSlots(node, context, buildSlotFn = buildClientSlotFn) {3263 context.helper(WITH_CTX);3264 const { children, loc } = node;3265 const slotsProperties = [];3266 const dynamicSlots = [];3267 // If the slot is inside a v-for or another v-slot, force it to be dynamic3268 // since it likely uses a scope variable.3269 let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0;3270 // 1. Check for slot with slotProps on component itself.3271 // <Comp v-slot="{ prop }"/>3272 const onComponentSlot = findDir(node, 'slot', true);3273 if (onComponentSlot) {3274 const { arg, exp } = onComponentSlot;3275 if (arg && !isStaticExp(arg)) {3276 hasDynamicSlots = true;3277 }3278 slotsProperties.push(createObjectProperty(arg || createSimpleExpression('default', true), buildSlotFn(exp, children, loc)));3279 }3280 // 2. Iterate through children and check for template slots3281 // <template v-slot:foo="{ prop }">3282 let hasTemplateSlots = false;3283 let hasNamedDefaultSlot = false;3284 const implicitDefaultChildren = [];3285 const seenSlotNames = new Set();3286 for (let i = 0; i < children.length; i++) {3287 const slotElement = children[i];3288 let slotDir;3289 if (!isTemplateNode(slotElement) ||3290 !(slotDir = findDir(slotElement, 'slot', true))) {3291 // not a <template v-slot>, skip.3292 if (slotElement.type !== 3 /* COMMENT */) {3293 implicitDefaultChildren.push(slotElement);3294 }3295 continue;3296 }3297 if (onComponentSlot) {3298 // already has on-component slot - this is incorrect usage.3299 context.onError(createCompilerError(36 /* X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc));3300 break;3301 }3302 hasTemplateSlots = true;3303 const { children: slotChildren, loc: slotLoc } = slotElement;3304 const { arg: slotName = createSimpleExpression(`default`, true), exp: slotProps, loc: dirLoc } = slotDir;3305 // check if name is dynamic.3306 let staticSlotName;3307 if (isStaticExp(slotName)) {3308 staticSlotName = slotName ? slotName.content : `default`;3309 }3310 else {3311 hasDynamicSlots = true;3312 }3313 const slotFunction = buildSlotFn(slotProps, slotChildren, slotLoc);3314 // check if this slot is conditional (v-if/v-for)3315 let vIf;3316 let vElse;3317 let vFor;3318 if ((vIf = findDir(slotElement, 'if'))) {3319 hasDynamicSlots = true;3320 dynamicSlots.push(createConditionalExpression(vIf.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback));3321 }3322 else if ((vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))) {3323 // find adjacent v-if3324 let j = i;3325 let prev;3326 while (j--) {3327 prev = children[j];3328 if (prev.type !== 3 /* COMMENT */) {3329 break;3330 }3331 }3332 if (prev && isTemplateNode(prev) && findDir(prev, 'if')) {3333 // remove node3334 children.splice(i, 1);3335 i--;3336 // attach this slot to previous conditional3337 let conditional = dynamicSlots[dynamicSlots.length - 1];3338 while (conditional.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3339 conditional = conditional.alternate;3340 }3341 conditional.alternate = vElse.exp3342 ? createConditionalExpression(vElse.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback)3343 : buildDynamicSlot(slotName, slotFunction);3344 }3345 else {3346 context.onError(createCompilerError(29 /* X_V_ELSE_NO_ADJACENT_IF */, vElse.loc));3347 }3348 }3349 else if ((vFor = findDir(slotElement, 'for'))) {3350 hasDynamicSlots = true;3351 const parseResult = vFor.parseResult ||3352 parseForExpression(vFor.exp, context);3353 if (parseResult) {3354 // Render the dynamic slots as an array and add it to the createSlot()3355 // args. The runtime knows how to handle it appropriately.3356 dynamicSlots.push(createCallExpression(context.helper(RENDER_LIST), [3357 parseResult.source,3358 createFunctionExpression(createForLoopParams(parseResult), buildDynamicSlot(slotName, slotFunction), true /* force newline */)3359 ]));3360 }3361 else {3362 context.onError(createCompilerError(31 /* X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc));3363 }3364 }3365 else {3366 // check duplicate static names3367 if (staticSlotName) {3368 if (seenSlotNames.has(staticSlotName)) {3369 context.onError(createCompilerError(37 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc));3370 continue;3371 }3372 seenSlotNames.add(staticSlotName);3373 if (staticSlotName === 'default') {3374 hasNamedDefaultSlot = true;3375 }3376 }3377 slotsProperties.push(createObjectProperty(slotName, slotFunction));3378 }3379 }3380 if (!onComponentSlot) {3381 const buildDefaultSlotProperty = (props, children) => {3382 const fn = buildSlotFn(props, children, loc);3383 if (context.compatConfig) {3384 fn.isNonScopedSlot = true;3385 }3386 return createObjectProperty(`default`, fn);3387 };3388 if (!hasTemplateSlots) {3389 // implicit default slot (on component)3390 slotsProperties.push(buildDefaultSlotProperty(undefined, children));3391 }3392 else if (implicitDefaultChildren.length &&3393 // #37663394 // with whitespace: 'preserve', whitespaces between slots will end up in3395 // implicitDefaultChildren. Ignore if all implicit children are whitespaces.3396 implicitDefaultChildren.some(node => isNonWhitespaceContent(node))) {3397 // implicit default slot (mixed with named slots)3398 if (hasNamedDefaultSlot) {3399 context.onError(createCompilerError(38 /* X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN */, implicitDefaultChildren[0].loc));3400 }3401 else {3402 slotsProperties.push(buildDefaultSlotProperty(undefined, implicitDefaultChildren));3403 }3404 }3405 }3406 const slotFlag = hasDynamicSlots3407 ? 2 /* DYNAMIC */3408 : hasForwardedSlots(node.children)3409 ? 3 /* FORWARDED */3410 : 1 /* STABLE */;3411 let slots = createObjectExpression(slotsProperties.concat(createObjectProperty(`_`, 3412 // 2 = compiled but dynamic = can skip normalization, but must run diff3413 // 1 = compiled and static = can skip normalization AND diff as optimized3414 createSimpleExpression(slotFlag + (( true) ? ` /* ${_vue_shared__WEBPACK_IMPORTED_MODULE_0__.slotFlagsText[slotFlag]} */` : 0), false))), loc);3415 if (dynamicSlots.length) {3416 slots = createCallExpression(context.helper(CREATE_SLOTS), [3417 slots,3418 createArrayExpression(dynamicSlots)3419 ]);3420 }3421 return {3422 slots,3423 hasDynamicSlots3424 };3425}3426function buildDynamicSlot(name, fn) {3427 return createObjectExpression([3428 createObjectProperty(`name`, name),3429 createObjectProperty(`fn`, fn)3430 ]);3431}3432function hasForwardedSlots(children) {3433 for (let i = 0; i < children.length; i++) {3434 const child = children[i];3435 switch (child.type) {3436 case 1 /* ELEMENT */:3437 if (child.tagType === 2 /* SLOT */ ||3438 ((child.tagType === 0 /* ELEMENT */ ||3439 child.tagType === 3 /* TEMPLATE */) &&3440 hasForwardedSlots(child.children))) {3441 return true;3442 }3443 break;3444 case 9 /* IF */:3445 if (hasForwardedSlots(child.branches))3446 return true;3447 break;3448 case 10 /* IF_BRANCH */:3449 case 11 /* FOR */:3450 if (hasForwardedSlots(child.children))3451 return true;3452 break;3453 }3454 }3455 return false;3456}3457function isNonWhitespaceContent(node) {3458 if (node.type !== 2 /* TEXT */ && node.type !== 12 /* TEXT_CALL */)3459 return true;3460 return node.type === 2 /* TEXT */3461 ? !!node.content.trim()3462 : isNonWhitespaceContent(node.content);3463}3464// some directive transforms (e.g. v-model) may return a symbol for runtime3465// import, which should be used instead of a resolveDirective call.3466const directiveImportMap = new WeakMap();3467// generate a JavaScript AST for this element's codegen3468const transformElement = (node, context) => {3469 // perform the work on exit, after all child expressions have been3470 // processed and merged.3471 return function postTransformElement() {3472 node = context.currentNode;3473 if (!(node.type === 1 /* ELEMENT */ &&3474 (node.tagType === 0 /* ELEMENT */ ||3475 node.tagType === 1 /* COMPONENT */))) {3476 return;3477 }3478 const { tag, props } = node;3479 const isComponent = node.tagType === 1 /* COMPONENT */;3480 // The goal of the transform is to create a codegenNode implementing the3481 // VNodeCall interface.3482 let vnodeTag = isComponent3483 ? resolveComponentType(node, context)3484 : `"${tag}"`;3485 const isDynamicComponent = (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isObject)(vnodeTag) && vnodeTag.callee === RESOLVE_DYNAMIC_COMPONENT;3486 let vnodeProps;3487 let vnodeChildren;3488 let vnodePatchFlag;3489 let patchFlag = 0;3490 let vnodeDynamicProps;3491 let dynamicPropNames;3492 let vnodeDirectives;3493 let shouldUseBlock = 3494 // dynamic component may resolve to plain elements3495 isDynamicComponent ||3496 vnodeTag === TELEPORT ||3497 vnodeTag === SUSPENSE ||3498 (!isComponent &&3499 // <svg> and <foreignObject> must be forced into blocks so that block3500 // updates inside get proper isSVG flag at runtime. (#639, #643)3501 // This is technically web-specific, but splitting the logic out of core3502 // leads to too much unnecessary complexity.3503 (tag === 'svg' ||3504 tag === 'foreignObject' ||3505 // #938: elements with dynamic keys should be forced into blocks3506 findProp(node, 'key', true)));3507 // props3508 if (props.length > 0) {3509 const propsBuildResult = buildProps(node, context);3510 vnodeProps = propsBuildResult.props;3511 patchFlag = propsBuildResult.patchFlag;3512 dynamicPropNames = propsBuildResult.dynamicPropNames;3513 const directives = propsBuildResult.directives;3514 vnodeDirectives =3515 directives && directives.length3516 ? createArrayExpression(directives.map(dir => buildDirectiveArgs(dir, context)))3517 : undefined;3518 }3519 // children3520 if (node.children.length > 0) {3521 if (vnodeTag === KEEP_ALIVE) {3522 // Although a built-in component, we compile KeepAlive with raw children3523 // instead of slot functions so that it can be used inside Transition3524 // or other Transition-wrapping HOCs.3525 // To ensure correct updates with block optimizations, we need to:3526 // 1. Force keep-alive into a block. This avoids its children being3527 // collected by a parent block.3528 shouldUseBlock = true;3529 // 2. Force keep-alive to always be updated, since it uses raw children.3530 patchFlag |= 1024 /* DYNAMIC_SLOTS */;3531 if (( true) && node.children.length > 1) {3532 context.onError(createCompilerError(44 /* X_KEEP_ALIVE_INVALID_CHILDREN */, {3533 start: node.children[0].loc.start,3534 end: node.children[node.children.length - 1].loc.end,3535 source: ''3536 }));3537 }3538 }3539 const shouldBuildAsSlots = isComponent &&3540 // Teleport is not a real component and has dedicated runtime handling3541 vnodeTag !== TELEPORT &&3542 // explained above.3543 vnodeTag !== KEEP_ALIVE;3544 if (shouldBuildAsSlots) {3545 const { slots, hasDynamicSlots } = buildSlots(node, context);3546 vnodeChildren = slots;3547 if (hasDynamicSlots) {3548 patchFlag |= 1024 /* DYNAMIC_SLOTS */;3549 }3550 }3551 else if (node.children.length === 1 && vnodeTag !== TELEPORT) {3552 const child = node.children[0];3553 const type = child.type;3554 // check for dynamic text children3555 const hasDynamicTextChild = type === 5 /* INTERPOLATION */ ||3556 type === 8 /* COMPOUND_EXPRESSION */;3557 if (hasDynamicTextChild &&3558 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {3559 patchFlag |= 1 /* TEXT */;3560 }3561 // pass directly if the only child is a text node3562 // (plain / interpolation / expression)3563 if (hasDynamicTextChild || type === 2 /* TEXT */) {3564 vnodeChildren = child;3565 }3566 else {3567 vnodeChildren = node.children;3568 }3569 }3570 else {3571 vnodeChildren = node.children;3572 }3573 }3574 // patchFlag & dynamicPropNames3575 if (patchFlag !== 0) {3576 if ((true)) {3577 if (patchFlag < 0) {3578 // special flags (negative and mutually exclusive)3579 vnodePatchFlag = patchFlag + ` /* ${_vue_shared__WEBPACK_IMPORTED_MODULE_0__.PatchFlagNames[patchFlag]} */`;3580 }3581 else {3582 // bitwise flags3583 const flagNames = Object.keys(_vue_shared__WEBPACK_IMPORTED_MODULE_0__.PatchFlagNames)3584 .map(Number)3585 .filter(n => n > 0 && patchFlag & n)3586 .map(n => _vue_shared__WEBPACK_IMPORTED_MODULE_0__.PatchFlagNames[n])3587 .join(`, `);3588 vnodePatchFlag = patchFlag + ` /* ${flagNames} */`;3589 }3590 }3591 else {}3592 if (dynamicPropNames && dynamicPropNames.length) {3593 vnodeDynamicProps = stringifyDynamicPropNames(dynamicPropNames);3594 }3595 }3596 node.codegenNode = createVNodeCall(context, vnodeTag, vnodeProps, vnodeChildren, vnodePatchFlag, vnodeDynamicProps, vnodeDirectives, !!shouldUseBlock, false /* disableTracking */, node.loc);3597 };3598};3599function resolveComponentType(node, context, ssr = false) {3600 let { tag } = node;3601 // 1. dynamic component3602 const isExplicitDynamic = isComponentTag(tag);3603 const isProp = findProp(node, 'is');3604 if (isProp) {3605 if (isExplicitDynamic ||3606 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) {3607 const exp = isProp.type === 6 /* ATTRIBUTE */3608 ? isProp.value && createSimpleExpression(isProp.value.content, true)3609 : isProp.exp;3610 if (exp) {3611 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [3612 exp3613 ]);3614 }3615 }3616 else if (isProp.type === 6 /* ATTRIBUTE */ &&3617 isProp.value.content.startsWith('vue:')) {3618 // <button is="vue:xxx">3619 // if not <component>, only is value that starts with "vue:" will be3620 // treated as component by the parse phase and reach here, unless it's3621 // compat mode where all is values are considered components3622 tag = isProp.value.content.slice(4);3623 }3624 }3625 // 1.5 v-is (TODO: Deprecate)3626 const isDir = !isExplicitDynamic && findDir(node, 'is');3627 if (isDir && isDir.exp) {3628 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [3629 isDir.exp3630 ]);3631 }3632 // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)3633 const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);3634 if (builtIn) {3635 // built-ins are simply fallthroughs / have special handling during ssr3636 // so we don't need to import their runtime equivalents3637 if (!ssr)3638 context.helper(builtIn);3639 return builtIn;3640 }3641 // 5. user component (resolve)3642 context.helper(RESOLVE_COMPONENT);3643 context.components.add(tag);3644 return toValidAssetId(tag, `component`);3645}3646function buildProps(node, context, props = node.props, ssr = false) {3647 const { tag, loc: elementLoc } = node;3648 const isComponent = node.tagType === 1 /* COMPONENT */;3649 let properties = [];3650 const mergeArgs = [];3651 const runtimeDirectives = [];3652 // patchFlag analysis3653 let patchFlag = 0;3654 let hasRef = false;3655 let hasClassBinding = false;3656 let hasStyleBinding = false;3657 let hasHydrationEventBinding = false;3658 let hasDynamicKeys = false;3659 let hasVnodeHook = false;3660 const dynamicPropNames = [];3661 const analyzePatchFlag = ({ key, value }) => {3662 if (isStaticExp(key)) {3663 const name = key.content;3664 const isEventHandler = (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isOn)(name);3665 if (!isComponent &&3666 isEventHandler &&3667 // omit the flag for click handlers because hydration gives click3668 // dedicated fast path.3669 name.toLowerCase() !== 'onclick' &&3670 // omit v-model handlers3671 name !== 'onUpdate:modelValue' &&3672 // omit onVnodeXXX hooks3673 !(0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isReservedProp)(name)) {3674 hasHydrationEventBinding = true;3675 }3676 if (isEventHandler && (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isReservedProp)(name)) {3677 hasVnodeHook = true;3678 }3679 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||3680 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||3681 value.type === 8 /* COMPOUND_EXPRESSION */) &&3682 getConstantType(value, context) > 0)) {3683 // skip if the prop is a cached handler or has constant value3684 return;3685 }3686 if (name === 'ref') {3687 hasRef = true;3688 }3689 else if (name === 'class' && !isComponent) {3690 hasClassBinding = true;3691 }3692 else if (name === 'style' && !isComponent) {3693 hasStyleBinding = true;3694 }3695 else if (name !== 'key' && !dynamicPropNames.includes(name)) {3696 dynamicPropNames.push(name);3697 }3698 }3699 else {3700 hasDynamicKeys = true;3701 }3702 };3703 for (let i = 0; i < props.length; i++) {3704 // static attribute3705 const prop = props[i];3706 if (prop.type === 6 /* ATTRIBUTE */) {3707 const { loc, name, value } = prop;3708 let isStatic = true;3709 if (name === 'ref') {3710 hasRef = true;3711 }3712 // skip is on <component>, or is="vue:xxx"3713 if (name === 'is' &&3714 (isComponentTag(tag) ||3715 (value && value.content.startsWith('vue:')) ||3716 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) {3717 continue;3718 }3719 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));3720 }3721 else {3722 // directives3723 const { name, arg, exp, loc } = prop;3724 const isVBind = name === 'bind';3725 const isVOn = name === 'on';3726 // skip v-slot - it is handled by its dedicated transform.3727 if (name === 'slot') {3728 if (!isComponent) {3729 context.onError(createCompilerError(39 /* X_V_SLOT_MISPLACED */, loc));3730 }3731 continue;3732 }3733 // skip v-once - it is handled by its dedicated transform.3734 if (name === 'once') {3735 continue;3736 }3737 // skip v-is and :is on <component>3738 if (name === 'is' ||3739 (isVBind &&3740 isBindKey(arg, 'is') &&3741 (isComponentTag(tag) ||3742 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) {3743 continue;3744 }3745 // skip v-on in SSR compilation3746 if (isVOn && ssr) {3747 continue;3748 }3749 // special case for v-bind and v-on with no argument3750 if (!arg && (isVBind || isVOn)) {3751 hasDynamicKeys = true;3752 if (exp) {3753 if (properties.length) {3754 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3755 properties = [];3756 }3757 if (isVBind) {3758 {3759 // 2.x v-bind object order compat3760 if ((true)) {3761 const hasOverridableKeys = mergeArgs.some(arg => {3762 if (arg.type === 15 /* JS_OBJECT_EXPRESSION */) {3763 return arg.properties.some(({ key }) => {3764 if (key.type !== 4 /* SIMPLE_EXPRESSION */ ||3765 !key.isStatic) {3766 return true;3767 }3768 return (key.content !== 'class' &&3769 key.content !== 'style' &&3770 !(0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isOn)(key.content));3771 });3772 }3773 else {3774 // dynamic expression3775 return true;3776 }3777 });3778 if (hasOverridableKeys) {3779 checkCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context, loc);3780 }3781 }3782 if (isCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context)) {3783 mergeArgs.unshift(exp);3784 continue;3785 }3786 }3787 mergeArgs.push(exp);3788 }3789 else {3790 // v-on="obj" -> toHandlers(obj)3791 mergeArgs.push({3792 type: 14 /* JS_CALL_EXPRESSION */,3793 loc,3794 callee: context.helper(TO_HANDLERS),3795 arguments: [exp]3796 });3797 }3798 }3799 else {3800 context.onError(createCompilerError(isVBind3801 ? 33 /* X_V_BIND_NO_EXPRESSION */3802 : 34 /* X_V_ON_NO_EXPRESSION */, loc));3803 }3804 continue;3805 }3806 const directiveTransform = context.directiveTransforms[name];3807 if (directiveTransform) {3808 // has built-in directive transform.3809 const { props, needRuntime } = directiveTransform(prop, node, context);3810 !ssr && props.forEach(analyzePatchFlag);3811 properties.push(...props);3812 if (needRuntime) {3813 runtimeDirectives.push(prop);3814 if ((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.isSymbol)(needRuntime)) {3815 directiveImportMap.set(prop, needRuntime);3816 }3817 }3818 }3819 else {3820 // no built-in transform, this is a user custom directive.3821 runtimeDirectives.push(prop);3822 }3823 }3824 if (prop.type === 6 /* ATTRIBUTE */ &&3825 prop.name === 'ref' &&3826 context.scopes.vFor > 0 &&3827 checkCompatEnabled("COMPILER_V_FOR_REF" /* COMPILER_V_FOR_REF */, context, prop.loc)) {3828 properties.push(createObjectProperty(createSimpleExpression('refInFor', true), createSimpleExpression('true', false)));3829 }3830 }3831 let propsExpression = undefined;3832 // has v-bind="object" or v-on="object", wrap with mergeProps3833 if (mergeArgs.length) {3834 if (properties.length) {3835 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3836 }3837 if (mergeArgs.length > 1) {3838 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);3839 }3840 else {3841 // single v-bind with nothing else - no need for a mergeProps call3842 propsExpression = mergeArgs[0];3843 }3844 }3845 else if (properties.length) {3846 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);3847 }3848 // patchFlag analysis3849 if (hasDynamicKeys) {3850 patchFlag |= 16 /* FULL_PROPS */;3851 }3852 else {3853 if (hasClassBinding) {3854 patchFlag |= 2 /* CLASS */;3855 }3856 if (hasStyleBinding) {3857 patchFlag |= 4 /* STYLE */;3858 }3859 if (dynamicPropNames.length) {3860 patchFlag |= 8 /* PROPS */;3861 }3862 if (hasHydrationEventBinding) {3863 patchFlag |= 32 /* HYDRATE_EVENTS */;3864 }3865 }3866 if ((patchFlag === 0 || patchFlag === 32 /* HYDRATE_EVENTS */) &&3867 (hasRef || hasVnodeHook || runtimeDirectives.length > 0)) {3868 patchFlag |= 512 /* NEED_PATCH */;3869 }3870 return {3871 props: propsExpression,3872 directives: runtimeDirectives,3873 patchFlag,3874 dynamicPropNames3875 };3876}3877// Dedupe props in an object literal.3878// Literal duplicated attributes would have been warned during the parse phase,3879// however, it's possible to encounter duplicated `onXXX` handlers with different3880// modifiers. We also need to merge static and dynamic class / style attributes.3881// - onXXX handlers / style: merge into array3882// - class: merge into single expression with concatenation3883function dedupeProperties(properties) {3884 const knownProps = new Map();3885 const deduped = [];3886 for (let i = 0; i < properties.length; i++) {3887 const prop = properties[i];3888 // dynamic keys are always allowed3889 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {3890 deduped.push(prop);3891 continue;3892 }3893 const name = prop.key.content;3894 const existing = knownProps.get(name);3895 if (existing) {3896 if (name === 'style' || name === 'class' || name.startsWith('on')) {3897 mergeAsArray(existing, prop);3898 }3899 // unexpected duplicate, should have emitted error during parse3900 }3901 else {3902 knownProps.set(name, prop);3903 deduped.push(prop);3904 }3905 }3906 return deduped;3907}3908function mergeAsArray(existing, incoming) {3909 if (existing.value.type === 17 /* JS_ARRAY_EXPRESSION */) {3910 existing.value.elements.push(incoming.value);3911 }3912 else {3913 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);3914 }3915}3916function buildDirectiveArgs(dir, context) {3917 const dirArgs = [];3918 const runtime = directiveImportMap.get(dir);3919 if (runtime) {3920 // built-in directive with runtime3921 dirArgs.push(context.helperString(runtime));3922 }3923 else {3924 {3925 // inject statement for resolving directive3926 context.helper(RESOLVE_DIRECTIVE);3927 context.directives.add(dir.name);3928 dirArgs.push(toValidAssetId(dir.name, `directive`));3929 }3930 }3931 const { loc } = dir;3932 if (dir.exp)3933 dirArgs.push(dir.exp);3934 if (dir.arg) {3935 if (!dir.exp) {3936 dirArgs.push(`void 0`);3937 }3938 dirArgs.push(dir.arg);3939 }3940 if (Object.keys(dir.modifiers).length) {3941 if (!dir.arg) {3942 if (!dir.exp) {3943 dirArgs.push(`void 0`);3944 }3945 dirArgs.push(`void 0`);3946 }3947 const trueExpression = createSimpleExpression(`true`, false, loc);3948 dirArgs.push(createObjectExpression(dir.modifiers.map(modifier => createObjectProperty(modifier, trueExpression)), loc));3949 }3950 return createArrayExpression(dirArgs, dir.loc);3951}3952function stringifyDynamicPropNames(props) {3953 let propsNamesString = `[`;3954 for (let i = 0, l = props.length; i < l; i++) {3955 propsNamesString += JSON.stringify(props[i]);3956 if (i < l - 1)3957 propsNamesString += ', ';3958 }3959 return propsNamesString + `]`;3960}3961function isComponentTag(tag) {3962 return tag[0].toLowerCase() + tag.slice(1) === 'component';3963}3964( true)3965 ? Object.freeze({})3966 : 0;3967( true) ? Object.freeze([]) : 0;3968const cacheStringFunction = (fn) => {3969 const cache = Object.create(null);3970 return ((str) => {3971 const hit = cache[str];3972 return hit || (cache[str] = fn(str));3973 });3974};3975const camelizeRE = /-(\w)/g;3976/**3977 * @private3978 */3979const camelize = cacheStringFunction((str) => {3980 return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));3981});3982const transformSlotOutlet = (node, context) => {3983 if (isSlotOutlet(node)) {3984 const { children, loc } = node;3985 const { slotName, slotProps } = processSlotOutlet(node, context);3986 const slotArgs = [3987 context.prefixIdentifiers ? `_ctx.$slots` : `$slots`,3988 slotName3989 ];3990 if (slotProps) {3991 slotArgs.push(slotProps);3992 }3993 if (children.length) {3994 if (!slotProps) {3995 slotArgs.push(`{}`);3996 }3997 slotArgs.push(createFunctionExpression([], children, false, false, loc));3998 }3999 if (context.scopeId && !context.slotted) {4000 if (!slotProps) {4001 slotArgs.push(`{}`);4002 }4003 if (!children.length) {4004 slotArgs.push(`undefined`);4005 }4006 slotArgs.push(`true`);4007 }4008 node.codegenNode = createCallExpression(context.helper(RENDER_SLOT), slotArgs, loc);4009 }4010};4011function processSlotOutlet(node, context) {4012 let slotName = `"default"`;4013 let slotProps = undefined;4014 const nonNameProps = [];4015 for (let i = 0; i < node.props.length; i++) {4016 const p = node.props[i];4017 if (p.type === 6 /* ATTRIBUTE */) {4018 if (p.value) {4019 if (p.name === 'name') {4020 slotName = JSON.stringify(p.value.content);4021 }4022 else {4023 p.name = camelize(p.name);4024 nonNameProps.push(p);4025 }4026 }4027 }4028 else {4029 if (p.name === 'bind' && isBindKey(p.arg, 'name')) {4030 if (p.exp)4031 slotName = p.exp;4032 }4033 else {4034 if (p.name === 'bind' && p.arg && isStaticExp(p.arg)) {4035 p.arg.content = camelize(p.arg.content);4036 }4037 nonNameProps.push(p);4038 }4039 }4040 }4041 if (nonNameProps.length > 0) {4042 const { props, directives } = buildProps(node, context, nonNameProps);4043 slotProps = props;4044 if (directives.length) {4045 context.onError(createCompilerError(35 /* X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET */, directives[0].loc));4046 }4047 }4048 return {4049 slotName,4050 slotProps4051 };4052}4053const fnExpRE = /^\s*([\w$_]+|\([^)]*?\))\s*=>|^\s*function(?:\s+[\w$]+)?\s*\(/;4054const transformOn = (dir, node, context, augmentor) => {4055 const { loc, modifiers, arg } = dir;4056 if (!dir.exp && !modifiers.length) {4057 context.onError(createCompilerError(34 /* X_V_ON_NO_EXPRESSION */, loc));4058 }4059 let eventName;4060 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4061 if (arg.isStatic) {4062 const rawName = arg.content;4063 // for all event listeners, auto convert it to camelCase. See issue #22494064 eventName = createSimpleExpression((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.toHandlerKey)((0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.camelize)(rawName)), true, arg.loc);4065 }4066 else {4067 // #23884068 eventName = createCompoundExpression([4069 `${context.helperString(TO_HANDLER_KEY)}(`,4070 arg,4071 `)`4072 ]);4073 }4074 }4075 else {4076 // already a compound expression.4077 eventName = arg;4078 eventName.children.unshift(`${context.helperString(TO_HANDLER_KEY)}(`);4079 eventName.children.push(`)`);4080 }4081 // handler processing4082 let exp = dir.exp;4083 if (exp && !exp.content.trim()) {4084 exp = undefined;4085 }4086 let shouldCache = context.cacheHandlers && !exp;4087 if (exp) {4088 const isMemberExp = isMemberExpression(exp.content);4089 const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content));4090 const hasMultipleStatements = exp.content.includes(`;`);4091 if (true) {4092 validateBrowserExpression(exp, context, false, hasMultipleStatements);4093 }4094 if (isInlineStatement || (shouldCache && isMemberExp)) {4095 // wrap inline statement in a function expression4096 exp = createCompoundExpression([4097 `${isInlineStatement4098 ? `$event`4099 : `${``}(...args)`} => ${hasMultipleStatements ? `{` : `(`}`,4100 exp,4101 hasMultipleStatements ? `}` : `)`4102 ]);4103 }4104 }4105 let ret = {4106 props: [4107 createObjectProperty(eventName, exp || createSimpleExpression(`() => {}`, false, loc))4108 ]4109 };4110 // apply extended compiler augmentor4111 if (augmentor) {4112 ret = augmentor(ret);4113 }4114 if (shouldCache) {4115 // cache handlers so that it's always the same handler being passed down.4116 // this avoids unnecessary re-renders when users use inline handlers on4117 // components.4118 ret.props[0].value = context.cache(ret.props[0].value);4119 }4120 return ret;4121};4122// v-bind without arg is handled directly in ./transformElements.ts due to it affecting4123// codegen for the entire props object. This transform here is only for v-bind4124// *with* args.4125const transformBind = (dir, _node, context) => {4126 const { exp, modifiers, loc } = dir;4127 const arg = dir.arg;4128 if (arg.type !== 4 /* SIMPLE_EXPRESSION */) {4129 arg.children.unshift(`(`);4130 arg.children.push(`) || ""`);4131 }4132 else if (!arg.isStatic) {4133 arg.content = `${arg.content} || ""`;4134 }4135 // .prop is no longer necessary due to new patch behavior4136 // .sync is replaced by v-model:arg4137 if (modifiers.includes('camel')) {4138 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4139 if (arg.isStatic) {4140 arg.content = (0,_vue_shared__WEBPACK_IMPORTED_MODULE_0__.camelize)(arg.content);4141 }4142 else {4143 arg.content = `${context.helperString(CAMELIZE)}(${arg.content})`;4144 }4145 }4146 else {4147 arg.children.unshift(`${context.helperString(CAMELIZE)}(`);4148 arg.children.push(`)`);4149 }4150 }4151 if (!exp ||4152 (exp.type === 4 /* SIMPLE_EXPRESSION */ && !exp.content.trim())) {4153 context.onError(createCompilerError(33 /* X_V_BIND_NO_EXPRESSION */, loc));4154 return {4155 props: [createObjectProperty(arg, createSimpleExpression('', true, loc))]4156 };4157 }4158 return {4159 props: [createObjectProperty(arg, exp)]4160 };4161};4162// Merge adjacent text nodes and expressions into a single expression4163// e.g. <div>abc {{ d }} {{ e }}</div> should have a single expression node as child.4164const transformText = (node, context) => {4165 if (node.type === 0 /* ROOT */ ||4166 node.type === 1 /* ELEMENT */ ||4167 node.type === 11 /* FOR */ ||4168 node.type === 10 /* IF_BRANCH */) {4169 // perform the transform on node exit so that all expressions have already4170 // been processed.4171 return () => {4172 const children = node.children;4173 let currentContainer = undefined;4174 let hasText = false;4175 for (let i = 0; i < children.length; i++) {4176 const child = children[i];4177 if (isText(child)) {4178 hasText = true;4179 for (let j = i + 1; j < children.length; j++) {4180 const next = children[j];4181 if (isText(next)) {4182 if (!currentContainer) {4183 currentContainer = children[i] = {4184 type: 8 /* COMPOUND_EXPRESSION */,4185 loc: child.loc,4186 children: [child]4187 };4188 }4189 // merge adjacent text node into current4190 currentContainer.children.push(` + `, next);4191 children.splice(j, 1);4192 j--;4193 }4194 else {4195 currentContainer = undefined;4196 break;4197 }4198 }4199 }4200 }4201 if (!hasText ||4202 // if this is a plain element with a single text child, leave it4203 // as-is since the runtime has dedicated fast path for this by directly4204 // setting textContent of the element.4205 // for component root it's always normalized anyway.4206 (children.length === 1 &&4207 (node.type === 0 /* ROOT */ ||4208 (node.type === 1 /* ELEMENT */ &&4209 node.tagType === 0 /* ELEMENT */ &&4210 // #37564211 // custom directives can potentially add DOM elements arbitrarily,4212 // we need to avoid setting textContent of the element at runtime4213 // to avoid accidentally overwriting the DOM elements added4214 // by the user through custom directives.4215 !node.props.find(p => p.type === 7 /* DIRECTIVE */ &&4216 !context.directiveTransforms[p.name]) &&4217 // in compat mode, <template> tags with no special directives4218 // will be rendered as a fragment so its children must be4219 // converted into vnodes.4220 !(node.tag === 'template'))))) {4221 return;4222 }4223 // pre-convert text nodes into createTextVNode(text) calls to avoid4224 // runtime normalization.4225 for (let i = 0; i < children.length; i++) {4226 const child = children[i];4227 if (isText(child) || child.type === 8 /* COMPOUND_EXPRESSION */) {4228 const callArgs = [];4229 // createTextVNode defaults to single whitespace, so if it is a4230 // single space the code could be an empty call to save bytes.4231 if (child.type !== 2 /* TEXT */ || child.content !== ' ') {4232 callArgs.push(child);4233 }4234 // mark dynamic text with flag so it gets patched inside a block4235 if (!context.ssr &&4236 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {4237 callArgs.push(1 /* TEXT */ +4238 (( true) ? ` /* ${_vue_shared__WEBPACK_IMPORTED_MODULE_0__.PatchFlagNames[1]} */` : 0));4239 }4240 children[i] = {4241 type: 12 /* TEXT_CALL */,4242 content: child,4243 loc: child.loc,4244 codegenNode: createCallExpression(context.helper(CREATE_TEXT), callArgs)4245 };4246 }4247 }4248 };4249 }4250};4251const seen = new WeakSet();4252const transformOnce = (node, context) => {4253 if (node.type === 1 /* ELEMENT */ && findDir(node, 'once', true)) {4254 if (seen.has(node)) {4255 return;4256 }4257 seen.add(node);4258 context.helper(SET_BLOCK_TRACKING);4259 return () => {4260 const cur = context.currentNode;4261 if (cur.codegenNode) {4262 cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */);4263 }4264 };4265 }4266};4267const transformModel = (dir, node, context) => {4268 const { exp, arg } = dir;4269 if (!exp) {4270 context.onError(createCompilerError(40 /* X_V_MODEL_NO_EXPRESSION */, dir.loc));4271 return createTransformProps();4272 }4273 const rawExp = exp.loc.source;4274 const expString = exp.type === 4 /* SIMPLE_EXPRESSION */ ? exp.content : rawExp;4275 // im SFC <script setup> inline mode, the exp may have been transformed into4276 // _unref(exp)4277 context.bindingMetadata[rawExp];4278 const maybeRef = !true /* SETUP_CONST */;4279 if (!expString.trim() || (!isMemberExpression(expString) && !maybeRef)) {4280 context.onError(createCompilerError(41 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));4281 return createTransformProps();4282 }4283 const propName = arg ? arg : createSimpleExpression('modelValue', true);4284 const eventName = arg4285 ? isStaticExp(arg)4286 ? `onUpdate:${arg.content}`4287 : createCompoundExpression(['"onUpdate:" + ', arg])4288 : `onUpdate:modelValue`;4289 let assignmentExp;4290 const eventArg = context.isTS ? `($event: any)` : `$event`;4291 {4292 assignmentExp = createCompoundExpression([4293 `${eventArg} => (`,4294 exp,4295 ` = $event)`4296 ]);4297 }4298 const props = [4299 // modelValue: foo4300 createObjectProperty(propName, dir.exp),4301 // "onUpdate:modelValue": $event => (foo = $event)4302 createObjectProperty(eventName, assignmentExp)4303 ];4304 // modelModifiers: { foo: true, "bar-baz": true }4305 if (dir.modifiers.length && node.tagType === 1 /* COMPONENT */) {4306 const modifiers = dir.modifiers4307 .map(m => (isSimpleIdentifier(m) ? m : JSON.stringify(m)) + `: true`)4308 .join(`, `);4309 const modifiersKey = arg4310 ? isStaticExp(arg)4311 ? `${arg.content}Modifiers`4312 : createCompoundExpression([arg, ' + "Modifiers"'])4313 : `modelModifiers`;4314 props.push(createObjectProperty(modifiersKey, createSimpleExpression(`{ ${modifiers} }`, false, dir.loc, 2 /* CAN_HOIST */)));4315 }4316 return createTransformProps(props);4317};4318function createTransformProps(props = []) {4319 return { props };4320}4321const validDivisionCharRE = /[\w).+\-_$\]]/;4322const transformFilter = (node, context) => {4323 if (!isCompatEnabled("COMPILER_FILTER" /* COMPILER_FILTERS */, context)) {4324 return;4325 }4326 if (node.type === 5 /* INTERPOLATION */) {4327 // filter rewrite is applied before expression transform so only4328 // simple expressions are possible at this stage4329 rewriteFilter(node.content, context);4330 }4331 if (node.type === 1 /* ELEMENT */) {4332 node.props.forEach((prop) => {4333 if (prop.type === 7 /* DIRECTIVE */ &&4334 prop.name !== 'for' &&4335 prop.exp) {4336 rewriteFilter(prop.exp, context);4337 }...
runtime-dom.esm-browser.js
Source:runtime-dom.esm-browser.js
...2050 }2051 warnCount[dupKey] = 0;2052 const { message, link } = deprecationData[key];2053 warn(`(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`);2054 if (!isCompatEnabled(key, instance, true)) {2055 console.error(`^ The above deprecation's compat behavior is disabled and will likely ` +2056 `lead to runtime errors.`);2057 }2058}2059const globalCompatConfig = {2060 MODE: 22061};2062function getCompatConfigForKey(key, instance) {2063 const instanceConfig = instance && instance.type.compatConfig;2064 if (instanceConfig && key in instanceConfig) {2065 return instanceConfig[key];2066 }2067 return globalCompatConfig[key];2068}2069function isCompatEnabled(key, instance, enableForBuiltIn = false) {2070 // skip compat for built-in components2071 if (!enableForBuiltIn && instance && instance.type.__isBuiltIn) {2072 return false;2073 }2074 const rawMode = getCompatConfigForKey('MODE', instance) || 2;2075 const val = getCompatConfigForKey(key, instance);2076 const mode = isFunction(rawMode)2077 ? rawMode(instance && instance.type)2078 : rawMode;2079 if (mode === 2) {2080 return val !== false;2081 }2082 else {2083 return val === true || val === 'suppress-warning';2084 }2085}2086function emit(instance, event, ...rawArgs) {2087 const props = instance.vnode.props || EMPTY_OBJ;2088 {2089 const { emitsOptions, propsOptions: [propsOptions] } = instance;2090 if (emitsOptions) {2091 if (!(event in emitsOptions) &&2092 !(false )) {2093 if (!propsOptions || !(toHandlerKey(event) in propsOptions)) {2094 warn(`Component emitted event "${event}" but it is neither declared in ` +2095 `the emits option nor as an "${toHandlerKey(event)}" prop.`);2096 }2097 }2098 else {2099 const validator = emitsOptions[event];2100 if (isFunction(validator)) {2101 const isValid = validator(...rawArgs);2102 if (!isValid) {2103 warn(`Invalid event arguments: event validation failed for event "${event}".`);2104 }2105 }2106 }2107 }2108 }2109 let args = rawArgs;2110 const isModelListener = event.startsWith('update:');2111 // for v-model update:xxx events, apply modifiers on args2112 const modelArg = isModelListener && event.slice(7);2113 if (modelArg && modelArg in props) {2114 const modifiersKey = `${modelArg === 'modelValue' ? 'model' : modelArg}Modifiers`;2115 const { number, trim } = props[modifiersKey] || EMPTY_OBJ;2116 if (trim) {2117 args = rawArgs.map(a => a.trim());2118 }2119 else if (number) {2120 args = rawArgs.map(toNumber);2121 }2122 }2123 {2124 devtoolsComponentEmit(instance, event, args);2125 }2126 {2127 const lowerCaseEvent = event.toLowerCase();2128 if (lowerCaseEvent !== event && props[toHandlerKey(lowerCaseEvent)]) {2129 warn(`Event "${lowerCaseEvent}" is emitted in component ` +2130 `${formatComponentName(instance, instance.type)} but the handler is registered for "${event}". ` +2131 `Note that HTML attributes are case-insensitive and you cannot use ` +2132 `v-on to listen to camelCase events when using in-DOM templates. ` +2133 `You should probably use "${hyphenate(event)}" instead of "${event}".`);2134 }2135 }2136 let handlerName;2137 let handler = props[(handlerName = toHandlerKey(event))] ||2138 // also try camelCase event handler (#2249)2139 props[(handlerName = toHandlerKey(camelize(event)))];2140 // for v-model update:xxx events, also trigger kebab-case equivalent2141 // for props passed via kebab-case2142 if (!handler && isModelListener) {2143 handler = props[(handlerName = toHandlerKey(hyphenate(event)))];2144 }2145 if (handler) {2146 callWithAsyncErrorHandling(handler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args);2147 }2148 const onceHandler = props[handlerName + `Once`];2149 if (onceHandler) {2150 if (!instance.emitted) {2151 instance.emitted = {};2152 }2153 else if (instance.emitted[handlerName]) {2154 return;2155 }2156 instance.emitted[handlerName] = true;2157 callWithAsyncErrorHandling(onceHandler, instance, 6 /* COMPONENT_EVENT_HANDLER */, args);2158 }2159}2160function normalizeEmitsOptions(comp, appContext, asMixin = false) {2161 const cache = appContext.emitsCache;2162 const cached = cache.get(comp);2163 if (cached !== undefined) {2164 return cached;2165 }2166 const raw = comp.emits;2167 let normalized = {};2168 // apply mixin/extends props2169 let hasExtends = false;2170 if (!isFunction(comp)) {2171 const extendEmits = (raw) => {2172 const normalizedFromExtend = normalizeEmitsOptions(raw, appContext, true);2173 if (normalizedFromExtend) {2174 hasExtends = true;2175 extend(normalized, normalizedFromExtend);2176 }2177 };2178 if (!asMixin && appContext.mixins.length) {2179 appContext.mixins.forEach(extendEmits);2180 }2181 if (comp.extends) {2182 extendEmits(comp.extends);2183 }2184 if (comp.mixins) {2185 comp.mixins.forEach(extendEmits);2186 }2187 }2188 if (!raw && !hasExtends) {2189 cache.set(comp, null);2190 return null;2191 }2192 if (isArray(raw)) {2193 raw.forEach(key => (normalized[key] = null));2194 }2195 else {2196 extend(normalized, raw);2197 }2198 cache.set(comp, normalized);2199 return normalized;2200}2201// Check if an incoming prop key is a declared emit event listener.2202// e.g. With `emits: { click: null }`, props named `onClick` and `onclick` are2203// both considered matched listeners.2204function isEmitListener(options, key) {2205 if (!options || !isOn(key)) {2206 return false;2207 }2208 key = key.slice(2).replace(/Once$/, '');2209 return (hasOwn(options, key[0].toLowerCase() + key.slice(1)) ||2210 hasOwn(options, hyphenate(key)) ||2211 hasOwn(options, key));2212}2213/**2214 * mark the current rendering instance for asset resolution (e.g.2215 * resolveComponent, resolveDirective) during render2216 */2217let currentRenderingInstance = null;2218let currentScopeId = null;2219/**2220 * Note: rendering calls maybe nested. The function returns the parent rendering2221 * instance if present, which should be restored after the render is done:2222 *2223 * ```js2224 * const prev = setCurrentRenderingInstance(i)2225 * // ...render2226 * setCurrentRenderingInstance(prev)2227 * ```2228 */2229function setCurrentRenderingInstance(instance) {2230 const prev = currentRenderingInstance;2231 currentRenderingInstance = instance;2232 currentScopeId = (instance && instance.type.__scopeId) || null;2233 return prev;2234}2235/**2236 * Set scope id when creating hoisted vnodes.2237 * @private compiler helper2238 */2239function pushScopeId(id) {2240 currentScopeId = id;2241}2242/**2243 * Technically we no longer need this after 3.0.8 but we need to keep the same2244 * API for backwards compat w/ code generated by compilers.2245 * @private2246 */2247function popScopeId() {2248 currentScopeId = null;2249}2250/**2251 * Only for backwards compat2252 * @private2253 */2254const withScopeId = (_id) => withCtx;2255/**2256 * Wrap a slot function to memoize current rendering instance2257 * @private compiler helper2258 */2259function withCtx(fn, ctx = currentRenderingInstance, isNonScopedSlot // false only2260) {2261 if (!ctx)2262 return fn;2263 // already normalized2264 if (fn._n) {2265 return fn;2266 }2267 const renderFnWithContext = (...args) => {2268 // If a user calls a compiled slot inside a template expression (#1745), it2269 // can mess up block tracking, so by default we disable block tracking and2270 // force bail out when invoking a compiled slot (indicated by the ._d flag).2271 // This isn't necessary if rendering a compiled `<slot>`, so we flip the2272 // ._d flag off when invoking the wrapped fn inside `renderSlot`.2273 if (renderFnWithContext._d) {2274 setBlockTracking(-1);2275 }2276 const prevInstance = setCurrentRenderingInstance(ctx);2277 const res = fn(...args);2278 setCurrentRenderingInstance(prevInstance);2279 if (renderFnWithContext._d) {2280 setBlockTracking(1);2281 }2282 {2283 devtoolsComponentUpdated(ctx);2284 }2285 return res;2286 };2287 // mark normalized to avoid duplicated wrapping2288 renderFnWithContext._n = true;2289 // mark this as compiled by default2290 // this is used in vnode.ts -> normalizeChildren() to set the slot2291 // rendering flag.2292 renderFnWithContext._c = true;2293 // disable block tracking by default2294 renderFnWithContext._d = true;2295 return renderFnWithContext;2296}2297/**2298 * dev only flag to track whether $attrs was used during render.2299 * If $attrs was used during render then the warning for failed attrs2300 * fallthrough can be suppressed.2301 */2302let accessedAttrs = false;2303function markAttrsAccessed() {2304 accessedAttrs = true;2305}2306function renderComponentRoot(instance) {2307 const { type: Component, vnode, proxy, withProxy, props, propsOptions: [propsOptions], slots, attrs, emit, render, renderCache, data, setupState, ctx, inheritAttrs } = instance;2308 let result;2309 const prev = setCurrentRenderingInstance(instance);2310 {2311 accessedAttrs = false;2312 }2313 try {2314 let fallthroughAttrs;2315 if (vnode.shapeFlag & 4 /* STATEFUL_COMPONENT */) {2316 // withProxy is a proxy with a different `has` trap only for2317 // runtime-compiled render functions using `with` block.2318 const proxyToUse = withProxy || proxy;2319 result = normalizeVNode(render.call(proxyToUse, proxyToUse, renderCache, props, setupState, data, ctx));2320 fallthroughAttrs = attrs;2321 }2322 else {2323 // functional2324 const render = Component;2325 // in dev, mark attrs accessed if optional props (attrs === props)2326 if (true && attrs === props) {2327 markAttrsAccessed();2328 }2329 result = normalizeVNode(render.length > 12330 ? render(props, true2331 ? {2332 get attrs() {2333 markAttrsAccessed();2334 return attrs;2335 },2336 slots,2337 emit2338 }2339 : { attrs, slots, emit })2340 : render(props, null /* we know it doesn't need it */));2341 fallthroughAttrs = Component.props2342 ? attrs2343 : getFunctionalFallthrough(attrs);2344 }2345 // attr merging2346 // in dev mode, comments are preserved, and it's possible for a template2347 // to have comments along side the root element which makes it a fragment2348 let root = result;2349 let setRoot = undefined;2350 if (true &&2351 result.patchFlag > 0 &&2352 result.patchFlag & 2048 /* DEV_ROOT_FRAGMENT */) {2353 ;2354 [root, setRoot] = getChildRoot(result);2355 }2356 if (fallthroughAttrs && inheritAttrs !== false) {2357 const keys = Object.keys(fallthroughAttrs);2358 const { shapeFlag } = root;2359 if (keys.length) {2360 if (shapeFlag & 1 /* ELEMENT */ ||2361 shapeFlag & 6 /* COMPONENT */) {2362 if (propsOptions && keys.some(isModelListener)) {2363 // If a v-model listener (onUpdate:xxx) has a corresponding declared2364 // prop, it indicates this component expects to handle v-model and2365 // it should not fallthrough.2366 // related: #1543, #1643, #19892367 fallthroughAttrs = filterModelListeners(fallthroughAttrs, propsOptions);2368 }2369 root = cloneVNode(root, fallthroughAttrs);2370 }2371 else if (true && !accessedAttrs && root.type !== Comment$1) {2372 const allAttrs = Object.keys(attrs);2373 const eventAttrs = [];2374 const extraAttrs = [];2375 for (let i = 0, l = allAttrs.length; i < l; i++) {2376 const key = allAttrs[i];2377 if (isOn(key)) {2378 // ignore v-model handlers when they fail to fallthrough2379 if (!isModelListener(key)) {2380 // remove `on`, lowercase first letter to reflect event casing2381 // accurately2382 eventAttrs.push(key[2].toLowerCase() + key.slice(3));2383 }2384 }2385 else {2386 extraAttrs.push(key);2387 }2388 }2389 if (extraAttrs.length) {2390 warn(`Extraneous non-props attributes (` +2391 `${extraAttrs.join(', ')}) ` +2392 `were passed to component but could not be automatically inherited ` +2393 `because component renders fragment or text root nodes.`);2394 }2395 if (eventAttrs.length) {2396 warn(`Extraneous non-emits event listeners (` +2397 `${eventAttrs.join(', ')}) ` +2398 `were passed to component but could not be automatically inherited ` +2399 `because component renders fragment or text root nodes. ` +2400 `If the listener is intended to be a component custom event listener only, ` +2401 `declare it using the "emits" option.`);2402 }2403 }2404 }2405 }2406 if (false &&2407 isCompatEnabled("INSTANCE_ATTRS_CLASS_STYLE" /* INSTANCE_ATTRS_CLASS_STYLE */, instance) &&2408 vnode.shapeFlag & 4 /* STATEFUL_COMPONENT */ &&2409 (root.shapeFlag & 1 /* ELEMENT */ ||2410 root.shapeFlag & 6 /* COMPONENT */)) ;2411 // inherit directives2412 if (vnode.dirs) {2413 if (true && !isElementRoot(root)) {2414 warn(`Runtime directive used on component with non-element root node. ` +2415 `The directives will not function as intended.`);2416 }2417 root.dirs = root.dirs ? root.dirs.concat(vnode.dirs) : vnode.dirs;2418 }2419 // inherit transition data2420 if (vnode.transition) {2421 if (true && !isElementRoot(root)) {...
dep-56143c31.js
Source:dep-56143c31.js
...1419 else {1420 return value;1421 }1422}1423function isCompatEnabled(key, context) {1424 const mode = getCompatValue('MODE', context);1425 const value = getCompatValue(key, context);1426 // in v3 mode, only enable if explicitly set to true1427 // otherwise enable for any non-false value1428 return mode === 3 ? value === true : value !== false;1429}1430function checkCompatEnabled(key, context, loc, ...args) {1431 const enabled = isCompatEnabled(key, context);1432 if ((process.env.NODE_ENV !== 'production') && enabled) {1433 warnDeprecation(key, context, loc, ...args);1434 }1435 return enabled;1436}1437function warnDeprecation(key, context, loc, ...args) {1438 const val = getCompatValue(key, context);1439 if (val === 'suppress-warning') {1440 return;1441 }1442 const { message, link } = deprecationData[key];1443 const msg = `(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`;1444 const err = new SyntaxError(msg);1445 err.code = key;1446 if (loc)1447 err.loc = loc;1448 context.onWarn(err);1449}1450// The default decoder only provides escapes for characters reserved as part of1451// the template syntax, and is only used if the custom renderer did not provide1452// a platform-specific decoder.1453const decodeRE = /&(gt|lt|amp|apos|quot);/g;1454const decodeMap = {1455 gt: '>',1456 lt: '<',1457 amp: '&',1458 apos: "'",1459 quot: '"'1460};1461const defaultParserOptions = {1462 delimiters: [`{{`, `}}`],1463 getNamespace: () => 0 /* HTML */,1464 getTextMode: () => 0 /* DATA */,1465 isVoidTag: NO,1466 isPreTag: NO,1467 isCustomElement: NO,1468 decodeEntities: (rawText) => rawText.replace(decodeRE, (_, p1) => decodeMap[p1]),1469 onError: defaultOnError,1470 onWarn: defaultOnWarn,1471 comments: (process.env.NODE_ENV !== 'production')1472};1473function baseParse(content, options = {}) {1474 const context = createParserContext(content, options);1475 const start = getCursor(context);1476 return createRoot(parseChildren(context, 0 /* DATA */, []), getSelection(context, start));1477}1478function createParserContext(content, rawOptions) {1479 const options = extend({}, defaultParserOptions);1480 let key;1481 for (key in rawOptions) {1482 // @ts-ignore1483 options[key] =1484 rawOptions[key] === undefined1485 ? defaultParserOptions[key]1486 : rawOptions[key];1487 }1488 return {1489 options,1490 column: 1,1491 line: 1,1492 offset: 0,1493 originalSource: content,1494 source: content,1495 inPre: false,1496 inVPre: false,1497 onWarn: options.onWarn1498 };1499}1500function parseChildren(context, mode, ancestors) {1501 const parent = last(ancestors);1502 const ns = parent ? parent.ns : 0 /* HTML */;1503 const nodes = [];1504 while (!isEnd(context, mode, ancestors)) {1505 const s = context.source;1506 let node = undefined;1507 if (mode === 0 /* DATA */ || mode === 1 /* RCDATA */) {1508 if (!context.inVPre && startsWith(s, context.options.delimiters[0])) {1509 // '{{'1510 node = parseInterpolation(context, mode);1511 }1512 else if (mode === 0 /* DATA */ && s[0] === '<') {1513 // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state1514 if (s.length === 1) {1515 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 1);1516 }1517 else if (s[1] === '!') {1518 // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state1519 if (startsWith(s, '<!--')) {1520 node = parseComment(context);1521 }1522 else if (startsWith(s, '<!DOCTYPE')) {1523 // Ignore DOCTYPE by a limitation.1524 node = parseBogusComment(context);1525 }1526 else if (startsWith(s, '<![CDATA[')) {1527 if (ns !== 0 /* HTML */) {1528 node = parseCDATA(context, ancestors);1529 }1530 else {1531 emitError(context, 1 /* CDATA_IN_HTML_CONTENT */);1532 node = parseBogusComment(context);1533 }1534 }1535 else {1536 emitError(context, 11 /* INCORRECTLY_OPENED_COMMENT */);1537 node = parseBogusComment(context);1538 }1539 }1540 else if (s[1] === '/') {1541 // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state1542 if (s.length === 2) {1543 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 2);1544 }1545 else if (s[2] === '>') {1546 emitError(context, 14 /* MISSING_END_TAG_NAME */, 2);1547 advanceBy(context, 3);1548 continue;1549 }1550 else if (/[a-z]/i.test(s[2])) {1551 emitError(context, 23 /* X_INVALID_END_TAG */);1552 parseTag(context, 1 /* End */, parent);1553 continue;1554 }1555 else {1556 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 2);1557 node = parseBogusComment(context);1558 }1559 }1560 else if (/[a-z]/i.test(s[1])) {1561 node = parseElement(context, ancestors);1562 // 2.x <template> with no directive compat1563 if (isCompatEnabled("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context) &&1564 node &&1565 node.tag === 'template' &&1566 !node.props.some(p => p.type === 7 /* DIRECTIVE */ &&1567 isSpecialTemplateDirective(p.name))) {1568 (process.env.NODE_ENV !== 'production') &&1569 warnDeprecation("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context, node.loc);1570 node = node.children;1571 }1572 }1573 else if (s[1] === '?') {1574 emitError(context, 21 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */, 1);1575 node = parseBogusComment(context);1576 }1577 else {1578 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 1);1579 }1580 }1581 }1582 if (!node) {1583 node = parseText(context, mode);1584 }1585 if (isArray(node)) {1586 for (let i = 0; i < node.length; i++) {1587 pushNode(nodes, node[i]);1588 }1589 }1590 else {1591 pushNode(nodes, node);1592 }1593 }1594 // Whitespace handling strategy like v21595 let removedWhitespace = false;1596 if (mode !== 2 /* RAWTEXT */ && mode !== 1 /* RCDATA */) {1597 const shouldCondense = context.options.whitespace !== 'preserve';1598 for (let i = 0; i < nodes.length; i++) {1599 const node = nodes[i];1600 if (!context.inPre && node.type === 2 /* TEXT */) {1601 if (!/[^\t\r\n\f ]/.test(node.content)) {1602 const prev = nodes[i - 1];1603 const next = nodes[i + 1];1604 // Remove if:1605 // - the whitespace is the first or last node, or:1606 // - (condense mode) the whitespace is adjacent to a comment, or:1607 // - (condense mode) the whitespace is between two elements AND contains newline1608 if (!prev ||1609 !next ||1610 (shouldCondense &&1611 (prev.type === 3 /* COMMENT */ ||1612 next.type === 3 /* COMMENT */ ||1613 (prev.type === 1 /* ELEMENT */ &&1614 next.type === 1 /* ELEMENT */ &&1615 /[\r\n]/.test(node.content))))) {1616 removedWhitespace = true;1617 nodes[i] = null;1618 }1619 else {1620 // Otherwise, the whitespace is condensed into a single space1621 node.content = ' ';1622 }1623 }1624 else if (shouldCondense) {1625 // in condense mode, consecutive whitespaces in text are condensed1626 // down to a single space.1627 node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ');1628 }1629 }1630 // Remove comment nodes if desired by configuration.1631 else if (node.type === 3 /* COMMENT */ && !context.options.comments) {1632 removedWhitespace = true;1633 nodes[i] = null;1634 }1635 }1636 if (context.inPre && parent && context.options.isPreTag(parent.tag)) {1637 // remove leading newline per html spec1638 // https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element1639 const first = nodes[0];1640 if (first && first.type === 2 /* TEXT */) {1641 first.content = first.content.replace(/^\r?\n/, '');1642 }1643 }1644 }1645 return removedWhitespace ? nodes.filter(Boolean) : nodes;1646}1647function pushNode(nodes, node) {1648 if (node.type === 2 /* TEXT */) {1649 const prev = last(nodes);1650 // Merge if both this and the previous node are text and those are1651 // consecutive. This happens for cases like "a < b".1652 if (prev &&1653 prev.type === 2 /* TEXT */ &&1654 prev.loc.end.offset === node.loc.start.offset) {1655 prev.content += node.content;1656 prev.loc.end = node.loc.end;1657 prev.loc.source += node.loc.source;1658 return;1659 }1660 }1661 nodes.push(node);1662}1663function parseCDATA(context, ancestors) {1664 advanceBy(context, 9);1665 const nodes = parseChildren(context, 3 /* CDATA */, ancestors);1666 if (context.source.length === 0) {1667 emitError(context, 6 /* EOF_IN_CDATA */);1668 }1669 else {1670 advanceBy(context, 3);1671 }1672 return nodes;1673}1674function parseComment(context) {1675 const start = getCursor(context);1676 let content;1677 // Regular comment.1678 const match = /--(\!)?>/.exec(context.source);1679 if (!match) {1680 content = context.source.slice(4);1681 advanceBy(context, context.source.length);1682 emitError(context, 7 /* EOF_IN_COMMENT */);1683 }1684 else {1685 if (match.index <= 3) {1686 emitError(context, 0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */);1687 }1688 if (match[1]) {1689 emitError(context, 10 /* INCORRECTLY_CLOSED_COMMENT */);1690 }1691 content = context.source.slice(4, match.index);1692 // Advancing with reporting nested comments.1693 const s = context.source.slice(0, match.index);1694 let prevIndex = 1, nestedIndex = 0;1695 while ((nestedIndex = s.indexOf('<!--', prevIndex)) !== -1) {1696 advanceBy(context, nestedIndex - prevIndex + 1);1697 if (nestedIndex + 4 < s.length) {1698 emitError(context, 16 /* NESTED_COMMENT */);1699 }1700 prevIndex = nestedIndex + 1;1701 }1702 advanceBy(context, match.index + match[0].length - prevIndex + 1);1703 }1704 return {1705 type: 3 /* COMMENT */,1706 content,1707 loc: getSelection(context, start)1708 };1709}1710function parseBogusComment(context) {1711 const start = getCursor(context);1712 const contentStart = context.source[1] === '?' ? 1 : 2;1713 let content;1714 const closeIndex = context.source.indexOf('>');1715 if (closeIndex === -1) {1716 content = context.source.slice(contentStart);1717 advanceBy(context, context.source.length);1718 }1719 else {1720 content = context.source.slice(contentStart, closeIndex);1721 advanceBy(context, closeIndex + 1);1722 }1723 return {1724 type: 3 /* COMMENT */,1725 content,1726 loc: getSelection(context, start)1727 };1728}1729function parseElement(context, ancestors) {1730 // Start tag.1731 const wasInPre = context.inPre;1732 const wasInVPre = context.inVPre;1733 const parent = last(ancestors);1734 const element = parseTag(context, 0 /* Start */, parent);1735 const isPreBoundary = context.inPre && !wasInPre;1736 const isVPreBoundary = context.inVPre && !wasInVPre;1737 if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {1738 // #4030 self-closing <pre> tag1739 if (isPreBoundary) {1740 context.inPre = false;1741 }1742 if (isVPreBoundary) {1743 context.inVPre = false;1744 }1745 return element;1746 }1747 // Children.1748 ancestors.push(element);1749 const mode = context.options.getTextMode(element, parent);1750 const children = parseChildren(context, mode, ancestors);1751 ancestors.pop();1752 // 2.x inline-template compat1753 {1754 const inlineTemplateProp = element.props.find(p => p.type === 6 /* ATTRIBUTE */ && p.name === 'inline-template');1755 if (inlineTemplateProp &&1756 checkCompatEnabled("COMPILER_INLINE_TEMPLATE" /* COMPILER_INLINE_TEMPLATE */, context, inlineTemplateProp.loc)) {1757 const loc = getSelection(context, element.loc.end);1758 inlineTemplateProp.value = {1759 type: 2 /* TEXT */,1760 content: loc.source,1761 loc1762 };1763 }1764 }1765 element.children = children;1766 // End tag.1767 if (startsWithEndTagOpen(context.source, element.tag)) {1768 parseTag(context, 1 /* End */, parent);1769 }1770 else {1771 emitError(context, 24 /* X_MISSING_END_TAG */, 0, element.loc.start);1772 if (context.source.length === 0 && element.tag.toLowerCase() === 'script') {1773 const first = children[0];1774 if (first && startsWith(first.loc.source, '<!--')) {1775 emitError(context, 8 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */);1776 }1777 }1778 }1779 element.loc = getSelection(context, element.loc.start);1780 if (isPreBoundary) {1781 context.inPre = false;1782 }1783 if (isVPreBoundary) {1784 context.inVPre = false;1785 }1786 return element;1787}1788const isSpecialTemplateDirective = /*#__PURE__*/ makeMap(`if,else,else-if,for,slot`);1789function parseTag(context, type, parent) {1790 // Tag open.1791 const start = getCursor(context);1792 const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source);1793 const tag = match[1];1794 const ns = context.options.getNamespace(tag, parent);1795 advanceBy(context, match[0].length);1796 advanceSpaces(context);1797 // save current state in case we need to re-parse attributes with v-pre1798 const cursor = getCursor(context);1799 const currentSource = context.source;1800 // check <pre> tag1801 if (context.options.isPreTag(tag)) {1802 context.inPre = true;1803 }1804 // Attributes.1805 let props = parseAttributes(context, type);1806 // check v-pre1807 if (type === 0 /* Start */ &&1808 !context.inVPre &&1809 props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'pre')) {1810 context.inVPre = true;1811 // reset context1812 extend(context, cursor);1813 context.source = currentSource;1814 // re-parse attrs and filter out v-pre itself1815 props = parseAttributes(context, type).filter(p => p.name !== 'v-pre');1816 }1817 // Tag close.1818 let isSelfClosing = false;1819 if (context.source.length === 0) {1820 emitError(context, 9 /* EOF_IN_TAG */);1821 }1822 else {1823 isSelfClosing = startsWith(context.source, '/>');1824 if (type === 1 /* End */ && isSelfClosing) {1825 emitError(context, 4 /* END_TAG_WITH_TRAILING_SOLIDUS */);1826 }1827 advanceBy(context, isSelfClosing ? 2 : 1);1828 }1829 if (type === 1 /* End */) {1830 return;1831 }1832 // 2.x deprecation checks1833 if ((process.env.NODE_ENV !== 'production') &&1834 isCompatEnabled("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context)) {1835 let hasIf = false;1836 let hasFor = false;1837 for (let i = 0; i < props.length; i++) {1838 const p = props[i];1839 if (p.type === 7 /* DIRECTIVE */) {1840 if (p.name === 'if') {1841 hasIf = true;1842 }1843 else if (p.name === 'for') {1844 hasFor = true;1845 }1846 }1847 if (hasIf && hasFor) {1848 warnDeprecation("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context, getSelection(context, start));1849 break;1850 }1851 }1852 }1853 let tagType = 0 /* ELEMENT */;1854 if (!context.inVPre) {1855 if (tag === 'slot') {1856 tagType = 2 /* SLOT */;1857 }1858 else if (tag === 'template') {1859 if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {1860 tagType = 3 /* TEMPLATE */;1861 }1862 }1863 else if (isComponent(tag, props, context)) {1864 tagType = 1 /* COMPONENT */;1865 }1866 }1867 return {1868 type: 1 /* ELEMENT */,1869 ns,1870 tag,1871 tagType,1872 props,1873 isSelfClosing,1874 children: [],1875 loc: getSelection(context, start),1876 codegenNode: undefined // to be created during transform phase1877 };1878}1879function isComponent(tag, props, context) {1880 const options = context.options;1881 if (options.isCustomElement(tag)) {1882 return false;1883 }1884 if (tag === 'component' ||1885 /^[A-Z]/.test(tag) ||1886 isCoreComponent(tag) ||1887 (options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||1888 (options.isNativeTag && !options.isNativeTag(tag))) {1889 return true;1890 }1891 // at this point the tag should be a native tag, but check for potential "is"1892 // casting1893 for (let i = 0; i < props.length; i++) {1894 const p = props[i];1895 if (p.type === 6 /* ATTRIBUTE */) {1896 if (p.name === 'is' && p.value) {1897 if (p.value.content.startsWith('vue:')) {1898 return true;1899 }1900 else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1901 return true;1902 }1903 }1904 }1905 else {1906 // directive1907 // v-is (TODO Deprecate)1908 if (p.name === 'is') {1909 return true;1910 }1911 else if (1912 // :is on plain element - only treat as component in compat mode1913 p.name === 'bind' &&1914 isStaticArgOf(p.arg, 'is') &&1915 true &&1916 checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1917 return true;1918 }1919 }1920 }1921}1922function parseAttributes(context, type) {1923 const props = [];1924 const attributeNames = new Set();1925 while (context.source.length > 0 &&1926 !startsWith(context.source, '>') &&1927 !startsWith(context.source, '/>')) {1928 if (startsWith(context.source, '/')) {1929 emitError(context, 22 /* UNEXPECTED_SOLIDUS_IN_TAG */);1930 advanceBy(context, 1);1931 advanceSpaces(context);1932 continue;1933 }1934 if (type === 1 /* End */) {1935 emitError(context, 3 /* END_TAG_WITH_ATTRIBUTES */);1936 }1937 const attr = parseAttribute(context, attributeNames);1938 // Trim whitespace between class1939 // https://github.com/vuejs/core/issues/42511940 if (attr.type === 6 /* ATTRIBUTE */ &&1941 attr.value &&1942 attr.name === 'class') {1943 attr.value.content = attr.value.content.replace(/\s+/g, ' ').trim();1944 }1945 if (type === 0 /* Start */) {1946 props.push(attr);1947 }1948 if (/^[^\t\r\n\f />]/.test(context.source)) {1949 emitError(context, 15 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */);1950 }1951 advanceSpaces(context);1952 }1953 return props;1954}1955function parseAttribute(context, nameSet) {1956 // Name.1957 const start = getCursor(context);1958 const match = /^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(context.source);1959 const name = match[0];1960 if (nameSet.has(name)) {1961 emitError(context, 2 /* DUPLICATE_ATTRIBUTE */);1962 }1963 nameSet.add(name);1964 if (name[0] === '=') {1965 emitError(context, 19 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */);1966 }1967 {1968 const pattern = /["'<]/g;1969 let m;1970 while ((m = pattern.exec(name))) {1971 emitError(context, 17 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */, m.index);1972 }1973 }1974 advanceBy(context, name.length);1975 // Value1976 let value = undefined;1977 if (/^[\t\r\n\f ]*=/.test(context.source)) {1978 advanceSpaces(context);1979 advanceBy(context, 1);1980 advanceSpaces(context);1981 value = parseAttributeValue(context);1982 if (!value) {1983 emitError(context, 13 /* MISSING_ATTRIBUTE_VALUE */);1984 }1985 }1986 const loc = getSelection(context, start);1987 if (!context.inVPre && /^(v-[A-Za-z0-9-]|:|\.|@|#)/.test(name)) {1988 const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^\.|^@|^#)(\[[^\]]+\]|[^\.]+))?(.+)?$/i.exec(name);1989 let isPropShorthand = startsWith(name, '.');1990 let dirName = match[1] ||1991 (isPropShorthand || startsWith(name, ':')1992 ? 'bind'1993 : startsWith(name, '@')1994 ? 'on'1995 : 'slot');1996 let arg;1997 if (match[2]) {1998 const isSlot = dirName === 'slot';1999 const startOffset = name.lastIndexOf(match[2]);2000 const loc = getSelection(context, getNewPosition(context, start, startOffset), getNewPosition(context, start, startOffset + match[2].length + ((isSlot && match[3]) || '').length));2001 let content = match[2];2002 let isStatic = true;2003 if (content.startsWith('[')) {2004 isStatic = false;2005 if (!content.endsWith(']')) {2006 emitError(context, 27 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */);2007 content = content.slice(1);2008 }2009 else {2010 content = content.slice(1, content.length - 1);2011 }2012 }2013 else if (isSlot) {2014 // #1241 special case for v-slot: vuetify relies extensively on slot2015 // names containing dots. v-slot doesn't have any modifiers and Vue 2.x2016 // supports such usage so we are keeping it consistent with 2.x.2017 content += match[3] || '';2018 }2019 arg = {2020 type: 4 /* SIMPLE_EXPRESSION */,2021 content,2022 isStatic,2023 constType: isStatic2024 ? 3 /* CAN_STRINGIFY */2025 : 0 /* NOT_CONSTANT */,2026 loc2027 };2028 }2029 if (value && value.isQuoted) {2030 const valueLoc = value.loc;2031 valueLoc.start.offset++;2032 valueLoc.start.column++;2033 valueLoc.end = advancePositionWithClone(valueLoc.start, value.content);2034 valueLoc.source = valueLoc.source.slice(1, -1);2035 }2036 const modifiers = match[3] ? match[3].slice(1).split('.') : [];2037 if (isPropShorthand)2038 modifiers.push('prop');2039 // 2.x compat v-bind:foo.sync -> v-model:foo2040 if (dirName === 'bind' && arg) {2041 if (modifiers.includes('sync') &&2042 checkCompatEnabled("COMPILER_V_BIND_SYNC" /* COMPILER_V_BIND_SYNC */, context, loc, arg.loc.source)) {2043 dirName = 'model';2044 modifiers.splice(modifiers.indexOf('sync'), 1);2045 }2046 if ((process.env.NODE_ENV !== 'production') && modifiers.includes('prop')) {2047 checkCompatEnabled("COMPILER_V_BIND_PROP" /* COMPILER_V_BIND_PROP */, context, loc);2048 }2049 }2050 return {2051 type: 7 /* DIRECTIVE */,2052 name: dirName,2053 exp: value && {2054 type: 4 /* SIMPLE_EXPRESSION */,2055 content: value.content,2056 isStatic: false,2057 // Treat as non-constant by default. This can be potentially set to2058 // other values by `transformExpression` to make it eligible for hoisting.2059 constType: 0 /* NOT_CONSTANT */,2060 loc: value.loc2061 },2062 arg,2063 modifiers,2064 loc2065 };2066 }2067 // missing directive name or illegal directive name2068 if (!context.inVPre && startsWith(name, 'v-')) {2069 emitError(context, 26 /* X_MISSING_DIRECTIVE_NAME */);2070 }2071 return {2072 type: 6 /* ATTRIBUTE */,2073 name,2074 value: value && {2075 type: 2 /* TEXT */,2076 content: value.content,2077 loc: value.loc2078 },2079 loc2080 };2081}2082function parseAttributeValue(context) {2083 const start = getCursor(context);2084 let content;2085 const quote = context.source[0];2086 const isQuoted = quote === `"` || quote === `'`;2087 if (isQuoted) {2088 // Quoted value.2089 advanceBy(context, 1);2090 const endIndex = context.source.indexOf(quote);2091 if (endIndex === -1) {2092 content = parseTextData(context, context.source.length, 4 /* ATTRIBUTE_VALUE */);2093 }2094 else {2095 content = parseTextData(context, endIndex, 4 /* ATTRIBUTE_VALUE */);2096 advanceBy(context, 1);2097 }2098 }2099 else {2100 // Unquoted2101 const match = /^[^\t\r\n\f >]+/.exec(context.source);2102 if (!match) {2103 return undefined;2104 }2105 const unexpectedChars = /["'<=`]/g;2106 let m;2107 while ((m = unexpectedChars.exec(match[0]))) {2108 emitError(context, 18 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */, m.index);2109 }2110 content = parseTextData(context, match[0].length, 4 /* ATTRIBUTE_VALUE */);2111 }2112 return { content, isQuoted, loc: getSelection(context, start) };2113}2114function parseInterpolation(context, mode) {2115 const [open, close] = context.options.delimiters;2116 const closeIndex = context.source.indexOf(close, open.length);2117 if (closeIndex === -1) {2118 emitError(context, 25 /* X_MISSING_INTERPOLATION_END */);2119 return undefined;2120 }2121 const start = getCursor(context);2122 advanceBy(context, open.length);2123 const innerStart = getCursor(context);2124 const innerEnd = getCursor(context);2125 const rawContentLength = closeIndex - open.length;2126 const rawContent = context.source.slice(0, rawContentLength);2127 const preTrimContent = parseTextData(context, rawContentLength, mode);2128 const content = preTrimContent.trim();2129 const startOffset = preTrimContent.indexOf(content);2130 if (startOffset > 0) {2131 advancePositionWithMutation(innerStart, rawContent, startOffset);2132 }2133 const endOffset = rawContentLength - (preTrimContent.length - content.length - startOffset);2134 advancePositionWithMutation(innerEnd, rawContent, endOffset);2135 advanceBy(context, close.length);2136 return {2137 type: 5 /* INTERPOLATION */,2138 content: {2139 type: 4 /* SIMPLE_EXPRESSION */,2140 isStatic: false,2141 // Set `isConstant` to false by default and will decide in transformExpression2142 constType: 0 /* NOT_CONSTANT */,2143 content,2144 loc: getSelection(context, innerStart, innerEnd)2145 },2146 loc: getSelection(context, start)2147 };2148}2149function parseText(context, mode) {2150 const endTokens = mode === 3 /* CDATA */ ? [']]>'] : ['<', context.options.delimiters[0]];2151 let endIndex = context.source.length;2152 for (let i = 0; i < endTokens.length; i++) {2153 const index = context.source.indexOf(endTokens[i], 1);2154 if (index !== -1 && endIndex > index) {2155 endIndex = index;2156 }2157 }2158 const start = getCursor(context);2159 const content = parseTextData(context, endIndex, mode);2160 return {2161 type: 2 /* TEXT */,2162 content,2163 loc: getSelection(context, start)2164 };2165}2166/**2167 * Get text data with a given length from the current location.2168 * This translates HTML entities in the text data.2169 */2170function parseTextData(context, length, mode) {2171 const rawText = context.source.slice(0, length);2172 advanceBy(context, length);2173 if (mode === 2 /* RAWTEXT */ ||2174 mode === 3 /* CDATA */ ||2175 !rawText.includes('&')) {2176 return rawText;2177 }2178 else {2179 // DATA or RCDATA containing "&"". Entity decoding required.2180 return context.options.decodeEntities(rawText, mode === 4 /* ATTRIBUTE_VALUE */);2181 }2182}2183function getCursor(context) {2184 const { column, line, offset } = context;2185 return { column, line, offset };2186}2187function getSelection(context, start, end) {2188 end = end || getCursor(context);2189 return {2190 start,2191 end,2192 source: context.originalSource.slice(start.offset, end.offset)2193 };2194}2195function last(xs) {2196 return xs[xs.length - 1];2197}2198function startsWith(source, searchString) {2199 return source.startsWith(searchString);2200}2201function advanceBy(context, numberOfCharacters) {2202 const { source } = context;2203 advancePositionWithMutation(context, source, numberOfCharacters);2204 context.source = source.slice(numberOfCharacters);2205}2206function advanceSpaces(context) {2207 const match = /^[\t\r\n\f ]+/.exec(context.source);2208 if (match) {2209 advanceBy(context, match[0].length);2210 }2211}2212function getNewPosition(context, start, numberOfCharacters) {2213 return advancePositionWithClone(start, context.originalSource.slice(start.offset, numberOfCharacters), numberOfCharacters);2214}2215function emitError(context, code, offset, loc = getCursor(context)) {2216 if (offset) {2217 loc.offset += offset;2218 loc.column += offset;2219 }2220 context.options.onError(createCompilerError(code, {2221 start: loc,2222 end: loc,2223 source: ''2224 }));2225}2226function isEnd(context, mode, ancestors) {2227 const s = context.source;2228 switch (mode) {2229 case 0 /* DATA */:2230 if (startsWith(s, '</')) {2231 // TODO: probably bad performance2232 for (let i = ancestors.length - 1; i >= 0; --i) {2233 if (startsWithEndTagOpen(s, ancestors[i].tag)) {2234 return true;2235 }2236 }2237 }2238 break;2239 case 1 /* RCDATA */:2240 case 2 /* RAWTEXT */: {2241 const parent = last(ancestors);2242 if (parent && startsWithEndTagOpen(s, parent.tag)) {2243 return true;2244 }2245 break;2246 }2247 case 3 /* CDATA */:2248 if (startsWith(s, ']]>')) {2249 return true;2250 }2251 break;2252 }2253 return !s;2254}2255function startsWithEndTagOpen(source, tag) {2256 return (startsWith(source, '</') &&2257 source.slice(2, 2 + tag.length).toLowerCase() === tag.toLowerCase() &&2258 /[\t\r\n\f />]/.test(source[2 + tag.length] || '>'));2259}2260function hoistStatic(root, context) {2261 walk(root, context, 2262 // Root node is unfortunately non-hoistable due to potential parent2263 // fallthrough attributes.2264 isSingleElementRoot(root, root.children[0]));2265}2266function isSingleElementRoot(root, child) {2267 const { children } = root;2268 return (children.length === 1 &&2269 child.type === 1 /* ELEMENT */ &&2270 !isSlotOutlet(child));2271}2272function walk(node, context, doNotHoistNode = false) {2273 const { children } = node;2274 const originalCount = children.length;2275 let hoistedCount = 0;2276 for (let i = 0; i < children.length; i++) {2277 const child = children[i];2278 // only plain elements & text calls are eligible for hoisting.2279 if (child.type === 1 /* ELEMENT */ &&2280 child.tagType === 0 /* ELEMENT */) {2281 const constantType = doNotHoistNode2282 ? 0 /* NOT_CONSTANT */2283 : getConstantType(child, context);2284 if (constantType > 0 /* NOT_CONSTANT */) {2285 if (constantType >= 2 /* CAN_HOIST */) {2286 child.codegenNode.patchFlag =2287 -1 /* HOISTED */ + ((process.env.NODE_ENV !== 'production') ? ` /* HOISTED */` : ``);2288 child.codegenNode = context.hoist(child.codegenNode);2289 hoistedCount++;2290 continue;2291 }2292 }2293 else {2294 // node may contain dynamic children, but its props may be eligible for2295 // hoisting.2296 const codegenNode = child.codegenNode;2297 if (codegenNode.type === 13 /* VNODE_CALL */) {2298 const flag = getPatchFlag(codegenNode);2299 if ((!flag ||2300 flag === 512 /* NEED_PATCH */ ||2301 flag === 1 /* TEXT */) &&2302 getGeneratedPropsConstantType(child, context) >=2303 2 /* CAN_HOIST */) {2304 const props = getNodeProps(child);2305 if (props) {2306 codegenNode.props = context.hoist(props);2307 }2308 }2309 if (codegenNode.dynamicProps) {2310 codegenNode.dynamicProps = context.hoist(codegenNode.dynamicProps);2311 }2312 }2313 }2314 }2315 else if (child.type === 12 /* TEXT_CALL */ &&2316 getConstantType(child.content, context) >= 2 /* CAN_HOIST */) {2317 child.codegenNode = context.hoist(child.codegenNode);2318 hoistedCount++;2319 }2320 // walk further2321 if (child.type === 1 /* ELEMENT */) {2322 const isComponent = child.tagType === 1 /* COMPONENT */;2323 if (isComponent) {2324 context.scopes.vSlot++;2325 }2326 walk(child, context);2327 if (isComponent) {2328 context.scopes.vSlot--;2329 }2330 }2331 else if (child.type === 11 /* FOR */) {2332 // Do not hoist v-for single child because it has to be a block2333 walk(child, context, child.children.length === 1);2334 }2335 else if (child.type === 9 /* IF */) {2336 for (let i = 0; i < child.branches.length; i++) {2337 // Do not hoist v-if single child because it has to be a block2338 walk(child.branches[i], context, child.branches[i].children.length === 1);2339 }2340 }2341 }2342 if (hoistedCount && context.transformHoist) {2343 context.transformHoist(children, context, node);2344 }2345 // all children were hoisted - the entire children array is hoistable.2346 if (hoistedCount &&2347 hoistedCount === originalCount &&2348 node.type === 1 /* ELEMENT */ &&2349 node.tagType === 0 /* ELEMENT */ &&2350 node.codegenNode &&2351 node.codegenNode.type === 13 /* VNODE_CALL */ &&2352 isArray(node.codegenNode.children)) {2353 node.codegenNode.children = context.hoist(createArrayExpression(node.codegenNode.children));2354 }2355}2356function getConstantType(node, context) {2357 const { constantCache } = context;2358 switch (node.type) {2359 case 1 /* ELEMENT */:2360 if (node.tagType !== 0 /* ELEMENT */) {2361 return 0 /* NOT_CONSTANT */;2362 }2363 const cached = constantCache.get(node);2364 if (cached !== undefined) {2365 return cached;2366 }2367 const codegenNode = node.codegenNode;2368 if (codegenNode.type !== 13 /* VNODE_CALL */) {2369 return 0 /* NOT_CONSTANT */;2370 }2371 if (codegenNode.isBlock &&2372 node.tag !== 'svg' &&2373 node.tag !== 'foreignObject') {2374 return 0 /* NOT_CONSTANT */;2375 }2376 const flag = getPatchFlag(codegenNode);2377 if (!flag) {2378 let returnType = 3 /* CAN_STRINGIFY */;2379 // Element itself has no patch flag. However we still need to check:2380 // 1. Even for a node with no patch flag, it is possible for it to contain2381 // non-hoistable expressions that refers to scope variables, e.g. compiler2382 // injected keys or cached event handlers. Therefore we need to always2383 // check the codegenNode's props to be sure.2384 const generatedPropsType = getGeneratedPropsConstantType(node, context);2385 if (generatedPropsType === 0 /* NOT_CONSTANT */) {2386 constantCache.set(node, 0 /* NOT_CONSTANT */);2387 return 0 /* NOT_CONSTANT */;2388 }2389 if (generatedPropsType < returnType) {2390 returnType = generatedPropsType;2391 }2392 // 2. its children.2393 for (let i = 0; i < node.children.length; i++) {2394 const childType = getConstantType(node.children[i], context);2395 if (childType === 0 /* NOT_CONSTANT */) {2396 constantCache.set(node, 0 /* NOT_CONSTANT */);2397 return 0 /* NOT_CONSTANT */;2398 }2399 if (childType < returnType) {2400 returnType = childType;2401 }2402 }2403 // 3. if the type is not already CAN_SKIP_PATCH which is the lowest non-02404 // type, check if any of the props can cause the type to be lowered2405 // we can skip can_patch because it's guaranteed by the absence of a2406 // patchFlag.2407 if (returnType > 1 /* CAN_SKIP_PATCH */) {2408 for (let i = 0; i < node.props.length; i++) {2409 const p = node.props[i];2410 if (p.type === 7 /* DIRECTIVE */ && p.name === 'bind' && p.exp) {2411 const expType = getConstantType(p.exp, context);2412 if (expType === 0 /* NOT_CONSTANT */) {2413 constantCache.set(node, 0 /* NOT_CONSTANT */);2414 return 0 /* NOT_CONSTANT */;2415 }2416 if (expType < returnType) {2417 returnType = expType;2418 }2419 }2420 }2421 }2422 // only svg/foreignObject could be block here, however if they are2423 // static then they don't need to be blocks since there will be no2424 // nested updates.2425 if (codegenNode.isBlock) {2426 context.removeHelper(OPEN_BLOCK);2427 context.removeHelper(getVNodeBlockHelper(context.inSSR, codegenNode.isComponent));2428 codegenNode.isBlock = false;2429 context.helper(getVNodeHelper(context.inSSR, codegenNode.isComponent));2430 }2431 constantCache.set(node, returnType);2432 return returnType;2433 }2434 else {2435 constantCache.set(node, 0 /* NOT_CONSTANT */);2436 return 0 /* NOT_CONSTANT */;2437 }2438 case 2 /* TEXT */:2439 case 3 /* COMMENT */:2440 return 3 /* CAN_STRINGIFY */;2441 case 9 /* IF */:2442 case 11 /* FOR */:2443 case 10 /* IF_BRANCH */:2444 return 0 /* NOT_CONSTANT */;2445 case 5 /* INTERPOLATION */:2446 case 12 /* TEXT_CALL */:2447 return getConstantType(node.content, context);2448 case 4 /* SIMPLE_EXPRESSION */:2449 return node.constType;2450 case 8 /* COMPOUND_EXPRESSION */:2451 let returnType = 3 /* CAN_STRINGIFY */;2452 for (let i = 0; i < node.children.length; i++) {2453 const child = node.children[i];2454 if (isString(child) || isSymbol(child)) {2455 continue;2456 }2457 const childType = getConstantType(child, context);2458 if (childType === 0 /* NOT_CONSTANT */) {2459 return 0 /* NOT_CONSTANT */;2460 }2461 else if (childType < returnType) {2462 returnType = childType;2463 }2464 }2465 return returnType;2466 default:2467 if ((process.env.NODE_ENV !== 'production')) ;2468 return 0 /* NOT_CONSTANT */;2469 }2470}2471const allowHoistedHelperSet = new Set([2472 NORMALIZE_CLASS,2473 NORMALIZE_STYLE,2474 NORMALIZE_PROPS,2475 GUARD_REACTIVE_PROPS2476]);2477function getConstantTypeOfHelperCall(value, context) {2478 if (value.type === 14 /* JS_CALL_EXPRESSION */ &&2479 !isString(value.callee) &&2480 allowHoistedHelperSet.has(value.callee)) {2481 const arg = value.arguments[0];2482 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {2483 return getConstantType(arg, context);2484 }2485 else if (arg.type === 14 /* JS_CALL_EXPRESSION */) {2486 // in the case of nested helper call, e.g. `normalizeProps(guardReactiveProps(exp))`2487 return getConstantTypeOfHelperCall(arg, context);2488 }2489 }2490 return 0 /* NOT_CONSTANT */;2491}2492function getGeneratedPropsConstantType(node, context) {2493 let returnType = 3 /* CAN_STRINGIFY */;2494 const props = getNodeProps(node);2495 if (props && props.type === 15 /* JS_OBJECT_EXPRESSION */) {2496 const { properties } = props;2497 for (let i = 0; i < properties.length; i++) {2498 const { key, value } = properties[i];2499 const keyType = getConstantType(key, context);2500 if (keyType === 0 /* NOT_CONSTANT */) {2501 return keyType;2502 }2503 if (keyType < returnType) {2504 returnType = keyType;2505 }2506 let valueType;2507 if (value.type === 4 /* SIMPLE_EXPRESSION */) {2508 valueType = getConstantType(value, context);2509 }2510 else if (value.type === 14 /* JS_CALL_EXPRESSION */) {2511 // some helper calls can be hoisted,2512 // such as the `normalizeProps` generated by the compiler for pre-normalize class,2513 // in this case we need to respect the ConstantType of the helper's arguments2514 valueType = getConstantTypeOfHelperCall(value, context);2515 }2516 else {2517 valueType = 0 /* NOT_CONSTANT */;2518 }2519 if (valueType === 0 /* NOT_CONSTANT */) {2520 return valueType;2521 }2522 if (valueType < returnType) {2523 returnType = valueType;2524 }2525 }2526 }2527 return returnType;2528}2529function getNodeProps(node) {2530 const codegenNode = node.codegenNode;2531 if (codegenNode.type === 13 /* VNODE_CALL */) {2532 return codegenNode.props;2533 }2534}2535function getPatchFlag(node) {2536 const flag = node.patchFlag;2537 return flag ? parseInt(flag, 10) : undefined;2538}2539function createTransformContext(root, { filename = '', prefixIdentifiers = false, hoistStatic = false, cacheHandlers = false, nodeTransforms = [], directiveTransforms = {}, transformHoist = null, isBuiltInComponent = NOOP, isCustomElement = NOOP, expressionPlugins = [], scopeId = null, slotted = true, ssr = false, inSSR = false, ssrCssVars = ``, bindingMetadata = EMPTY_OBJ, inline = false, isTS = false, onError = defaultOnError, onWarn = defaultOnWarn, compatConfig }) {2540 const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/);2541 const context = {2542 // options2543 selfName: nameMatch && capitalize(camelize$1(nameMatch[1])),2544 prefixIdentifiers,2545 hoistStatic,2546 cacheHandlers,2547 nodeTransforms,2548 directiveTransforms,2549 transformHoist,2550 isBuiltInComponent,2551 isCustomElement,2552 expressionPlugins,2553 scopeId,2554 slotted,2555 ssr,2556 inSSR,2557 ssrCssVars,2558 bindingMetadata,2559 inline,2560 isTS,2561 onError,2562 onWarn,2563 compatConfig,2564 // state2565 root,2566 helpers: new Map(),2567 components: new Set(),2568 directives: new Set(),2569 hoists: [],2570 imports: [],2571 constantCache: new Map(),2572 temps: 0,2573 cached: 0,2574 identifiers: Object.create(null),2575 scopes: {2576 vFor: 0,2577 vSlot: 0,2578 vPre: 0,2579 vOnce: 02580 },2581 parent: null,2582 currentNode: root,2583 childIndex: 0,2584 inVOnce: false,2585 // methods2586 helper(name) {2587 const count = context.helpers.get(name) || 0;2588 context.helpers.set(name, count + 1);2589 return name;2590 },2591 removeHelper(name) {2592 const count = context.helpers.get(name);2593 if (count) {2594 const currentCount = count - 1;2595 if (!currentCount) {2596 context.helpers.delete(name);2597 }2598 else {2599 context.helpers.set(name, currentCount);2600 }2601 }2602 },2603 helperString(name) {2604 return `_${helperNameMap[context.helper(name)]}`;2605 },2606 replaceNode(node) {2607 /* istanbul ignore if */2608 if ((process.env.NODE_ENV !== 'production')) {2609 if (!context.currentNode) {2610 throw new Error(`Node being replaced is already removed.`);2611 }2612 if (!context.parent) {2613 throw new Error(`Cannot replace root node.`);2614 }2615 }2616 context.parent.children[context.childIndex] = context.currentNode = node;2617 },2618 removeNode(node) {2619 if ((process.env.NODE_ENV !== 'production') && !context.parent) {2620 throw new Error(`Cannot remove root node.`);2621 }2622 const list = context.parent.children;2623 const removalIndex = node2624 ? list.indexOf(node)2625 : context.currentNode2626 ? context.childIndex2627 : -1;2628 /* istanbul ignore if */2629 if ((process.env.NODE_ENV !== 'production') && removalIndex < 0) {2630 throw new Error(`node being removed is not a child of current parent`);2631 }2632 if (!node || node === context.currentNode) {2633 // current node removed2634 context.currentNode = null;2635 context.onNodeRemoved();2636 }2637 else {2638 // sibling node removed2639 if (context.childIndex > removalIndex) {2640 context.childIndex--;2641 context.onNodeRemoved();2642 }2643 }2644 context.parent.children.splice(removalIndex, 1);2645 },2646 onNodeRemoved: () => { },2647 addIdentifiers(exp) {2648 },2649 removeIdentifiers(exp) {2650 },2651 hoist(exp) {2652 if (isString(exp))2653 exp = createSimpleExpression(exp);2654 context.hoists.push(exp);2655 const identifier = createSimpleExpression(`_hoisted_${context.hoists.length}`, false, exp.loc, 2 /* CAN_HOIST */);2656 identifier.hoisted = exp;2657 return identifier;2658 },2659 cache(exp, isVNode = false) {2660 return createCacheExpression(context.cached++, exp, isVNode);2661 }2662 };2663 {2664 context.filters = new Set();2665 }2666 return context;2667}2668function transform(root, options) {2669 const context = createTransformContext(root, options);2670 traverseNode(root, context);2671 if (options.hoistStatic) {2672 hoistStatic(root, context);2673 }2674 if (!options.ssr) {2675 createRootCodegen(root, context);2676 }2677 // finalize meta information2678 root.helpers = [...context.helpers.keys()];2679 root.components = [...context.components];2680 root.directives = [...context.directives];2681 root.imports = context.imports;2682 root.hoists = context.hoists;2683 root.temps = context.temps;2684 root.cached = context.cached;2685 {2686 root.filters = [...context.filters];2687 }2688}2689function createRootCodegen(root, context) {2690 const { helper } = context;2691 const { children } = root;2692 if (children.length === 1) {2693 const child = children[0];2694 // if the single child is an element, turn it into a block.2695 if (isSingleElementRoot(root, child) && child.codegenNode) {2696 // single element root is never hoisted so codegenNode will never be2697 // SimpleExpressionNode2698 const codegenNode = child.codegenNode;2699 if (codegenNode.type === 13 /* VNODE_CALL */) {2700 makeBlock(codegenNode, context);2701 }2702 root.codegenNode = codegenNode;2703 }2704 else {2705 // - single <slot/>, IfNode, ForNode: already blocks.2706 // - single text node: always patched.2707 // root codegen falls through via genNode()2708 root.codegenNode = child;2709 }2710 }2711 else if (children.length > 1) {2712 // root has multiple nodes - return a fragment block.2713 let patchFlag = 64 /* STABLE_FRAGMENT */;2714 let patchFlagText = PatchFlagNames[64 /* STABLE_FRAGMENT */];2715 // check if the fragment actually contains a single valid child with2716 // the rest being comments2717 if ((process.env.NODE_ENV !== 'production') &&2718 children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {2719 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;2720 patchFlagText += `, ${PatchFlagNames[2048 /* DEV_ROOT_FRAGMENT */]}`;2721 }2722 root.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, root.children, patchFlag + ((process.env.NODE_ENV !== 'production') ? ` /* ${patchFlagText} */` : ``), undefined, undefined, true, undefined, false /* isComponent */);2723 }2724 else ;2725}2726function traverseChildren(parent, context) {2727 let i = 0;2728 const nodeRemoved = () => {2729 i--;2730 };2731 for (; i < parent.children.length; i++) {2732 const child = parent.children[i];2733 if (isString(child))2734 continue;2735 context.parent = parent;2736 context.childIndex = i;2737 context.onNodeRemoved = nodeRemoved;2738 traverseNode(child, context);2739 }2740}2741function traverseNode(node, context) {2742 context.currentNode = node;2743 // apply transform plugins2744 const { nodeTransforms } = context;2745 const exitFns = [];2746 for (let i = 0; i < nodeTransforms.length; i++) {2747 const onExit = nodeTransforms[i](node, context);2748 if (onExit) {2749 if (isArray(onExit)) {2750 exitFns.push(...onExit);2751 }2752 else {2753 exitFns.push(onExit);2754 }2755 }2756 if (!context.currentNode) {2757 // node was removed2758 return;2759 }2760 else {2761 // node may have been replaced2762 node = context.currentNode;2763 }2764 }2765 switch (node.type) {2766 case 3 /* COMMENT */:2767 if (!context.ssr) {2768 // inject import for the Comment symbol, which is needed for creating2769 // comment nodes with `createVNode`2770 context.helper(CREATE_COMMENT);2771 }2772 break;2773 case 5 /* INTERPOLATION */:2774 // no need to traverse, but we need to inject toString helper2775 if (!context.ssr) {2776 context.helper(TO_DISPLAY_STRING);2777 }2778 break;2779 // for container types, further traverse downwards2780 case 9 /* IF */:2781 for (let i = 0; i < node.branches.length; i++) {2782 traverseNode(node.branches[i], context);2783 }2784 break;2785 case 10 /* IF_BRANCH */:2786 case 11 /* FOR */:2787 case 1 /* ELEMENT */:2788 case 0 /* ROOT */:2789 traverseChildren(node, context);2790 break;2791 }2792 // exit transforms2793 context.currentNode = node;2794 let i = exitFns.length;2795 while (i--) {2796 exitFns[i]();2797 }2798}2799function createStructuralDirectiveTransform(name, fn) {2800 const matches = isString(name)2801 ? (n) => n === name2802 : (n) => name.test(n);2803 return (node, context) => {2804 if (node.type === 1 /* ELEMENT */) {2805 const { props } = node;2806 // structural directive transforms are not concerned with slots2807 // as they are handled separately in vSlot.ts2808 if (node.tagType === 3 /* TEMPLATE */ && props.some(isVSlot)) {2809 return;2810 }2811 const exitFns = [];2812 for (let i = 0; i < props.length; i++) {2813 const prop = props[i];2814 if (prop.type === 7 /* DIRECTIVE */ && matches(prop.name)) {2815 // structural directives are removed to avoid infinite recursion2816 // also we remove them *before* applying so that it can further2817 // traverse itself in case it moves the node around2818 props.splice(i, 1);2819 i--;2820 const onExit = fn(node, prop, context);2821 if (onExit)2822 exitFns.push(onExit);2823 }2824 }2825 return exitFns;2826 }2827 };2828}2829const PURE_ANNOTATION = `/*#__PURE__*/`;2830function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssrRuntimeModuleName = 'vue/server-renderer', ssr = false, isTS = false, inSSR = false }) {2831 const context = {2832 mode,2833 prefixIdentifiers,2834 sourceMap,2835 filename,2836 scopeId,2837 optimizeImports,2838 runtimeGlobalName,2839 runtimeModuleName,2840 ssrRuntimeModuleName,2841 ssr,2842 isTS,2843 inSSR,2844 source: ast.loc.source,2845 code: ``,2846 column: 1,2847 line: 1,2848 offset: 0,2849 indentLevel: 0,2850 pure: false,2851 map: undefined,2852 helper(key) {2853 return `_${helperNameMap[key]}`;2854 },2855 push(code, node) {2856 context.code += code;2857 },2858 indent() {2859 newline(++context.indentLevel);2860 },2861 deindent(withoutNewLine = false) {2862 if (withoutNewLine) {2863 --context.indentLevel;2864 }2865 else {2866 newline(--context.indentLevel);2867 }2868 },2869 newline() {2870 newline(context.indentLevel);2871 }2872 };2873 function newline(n) {2874 context.push('\n' + ` `.repeat(n));2875 }2876 return context;2877}2878function generate(ast, options = {}) {2879 const context = createCodegenContext(ast, options);2880 if (options.onContextCreated)2881 options.onContextCreated(context);2882 const { mode, push, prefixIdentifiers, indent, deindent, newline, scopeId, ssr } = context;2883 const hasHelpers = ast.helpers.length > 0;2884 const useWithBlock = !prefixIdentifiers && mode !== 'module';2885 // preambles2886 // in setup() inline mode, the preamble is generated in a sub context2887 // and returned separately.2888 const preambleContext = context;2889 {2890 genFunctionPreamble(ast, preambleContext);2891 }2892 // enter render function2893 const functionName = ssr ? `ssrRender` : `render`;2894 const args = ssr ? ['_ctx', '_push', '_parent', '_attrs'] : ['_ctx', '_cache'];2895 const signature = args.join(', ');2896 {2897 push(`function ${functionName}(${signature}) {`);2898 }2899 indent();2900 if (useWithBlock) {2901 push(`with (_ctx) {`);2902 indent();2903 // function mode const declarations should be inside with block2904 // also they should be renamed to avoid collision with user properties2905 if (hasHelpers) {2906 push(`const { ${ast.helpers2907 .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)2908 .join(', ')} } = _Vue`);2909 push(`\n`);2910 newline();2911 }2912 }2913 // generate asset resolution statements2914 if (ast.components.length) {2915 genAssets(ast.components, 'component', context);2916 if (ast.directives.length || ast.temps > 0) {2917 newline();2918 }2919 }2920 if (ast.directives.length) {2921 genAssets(ast.directives, 'directive', context);2922 if (ast.temps > 0) {2923 newline();2924 }2925 }2926 if (ast.filters && ast.filters.length) {2927 newline();2928 genAssets(ast.filters, 'filter', context);2929 newline();2930 }2931 if (ast.temps > 0) {2932 push(`let `);2933 for (let i = 0; i < ast.temps; i++) {2934 push(`${i > 0 ? `, ` : ``}_temp${i}`);2935 }2936 }2937 if (ast.components.length || ast.directives.length || ast.temps) {2938 push(`\n`);2939 newline();2940 }2941 // generate the VNode tree expression2942 if (!ssr) {2943 push(`return `);2944 }2945 if (ast.codegenNode) {2946 genNode(ast.codegenNode, context);2947 }2948 else {2949 push(`null`);2950 }2951 if (useWithBlock) {2952 deindent();2953 push(`}`);2954 }2955 deindent();2956 push(`}`);2957 return {2958 ast,2959 code: context.code,2960 preamble: ``,2961 // SourceMapGenerator does have toJSON() method but it's not in the types2962 map: context.map ? context.map.toJSON() : undefined2963 };2964}2965function genFunctionPreamble(ast, context) {2966 const { ssr, prefixIdentifiers, push, newline, runtimeModuleName, runtimeGlobalName, ssrRuntimeModuleName } = context;2967 const VueBinding = runtimeGlobalName;2968 const aliasHelper = (s) => `${helperNameMap[s]}: _${helperNameMap[s]}`;2969 // Generate const declaration for helpers2970 // In prefix mode, we place the const declaration at top so it's done2971 // only once; But if we not prefixing, we place the declaration inside the2972 // with block so it doesn't incur the `in` check cost for every helper access.2973 if (ast.helpers.length > 0) {2974 {2975 // "with" mode.2976 // save Vue in a separate variable to avoid collision2977 push(`const _Vue = ${VueBinding}\n`);2978 // in "with" mode, helpers are declared inside the with block to avoid2979 // has check cost, but hoists are lifted out of the function - we need2980 // to provide the helper here.2981 if (ast.hoists.length) {2982 const staticHelpers = [2983 CREATE_VNODE,2984 CREATE_ELEMENT_VNODE,2985 CREATE_COMMENT,2986 CREATE_TEXT,2987 CREATE_STATIC2988 ]2989 .filter(helper => ast.helpers.includes(helper))2990 .map(aliasHelper)2991 .join(', ');2992 push(`const { ${staticHelpers} } = _Vue\n`);2993 }2994 }2995 }2996 genHoists(ast.hoists, context);2997 newline();2998 push(`return `);2999}3000function genAssets(assets, type, { helper, push, newline, isTS }) {3001 const resolver = helper(type === 'filter'3002 ? RESOLVE_FILTER3003 : type === 'component'3004 ? RESOLVE_COMPONENT3005 : RESOLVE_DIRECTIVE);3006 for (let i = 0; i < assets.length; i++) {3007 let id = assets[i];3008 // potential component implicit self-reference inferred from SFC filename3009 const maybeSelfReference = id.endsWith('__self');3010 if (maybeSelfReference) {3011 id = id.slice(0, -6);3012 }3013 push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`);3014 if (i < assets.length - 1) {3015 newline();3016 }3017 }3018}3019function genHoists(hoists, context) {3020 if (!hoists.length) {3021 return;3022 }3023 context.pure = true;3024 const { push, newline, helper, scopeId, mode } = context;3025 newline();3026 for (let i = 0; i < hoists.length; i++) {3027 const exp = hoists[i];3028 if (exp) {3029 push(`const _hoisted_${i + 1} = ${``}`);3030 genNode(exp, context);3031 newline();3032 }3033 }3034 context.pure = false;3035}3036function isText$1(n) {3037 return (isString(n) ||3038 n.type === 4 /* SIMPLE_EXPRESSION */ ||3039 n.type === 2 /* TEXT */ ||3040 n.type === 5 /* INTERPOLATION */ ||3041 n.type === 8 /* COMPOUND_EXPRESSION */);3042}3043function genNodeListAsArray(nodes, context) {3044 const multilines = nodes.length > 3 ||3045 (((process.env.NODE_ENV !== 'production')) && nodes.some(n => isArray(n) || !isText$1(n)));3046 context.push(`[`);3047 multilines && context.indent();3048 genNodeList(nodes, context, multilines);3049 multilines && context.deindent();3050 context.push(`]`);3051}3052function genNodeList(nodes, context, multilines = false, comma = true) {3053 const { push, newline } = context;3054 for (let i = 0; i < nodes.length; i++) {3055 const node = nodes[i];3056 if (isString(node)) {3057 push(node);3058 }3059 else if (isArray(node)) {3060 genNodeListAsArray(node, context);3061 }3062 else {3063 genNode(node, context);3064 }3065 if (i < nodes.length - 1) {3066 if (multilines) {3067 comma && push(',');3068 newline();3069 }3070 else {3071 comma && push(', ');3072 }3073 }3074 }3075}3076function genNode(node, context) {3077 if (isString(node)) {3078 context.push(node);3079 return;3080 }3081 if (isSymbol(node)) {3082 context.push(context.helper(node));3083 return;3084 }3085 switch (node.type) {3086 case 1 /* ELEMENT */:3087 case 9 /* IF */:3088 case 11 /* FOR */:3089 (process.env.NODE_ENV !== 'production') &&3090 assert(node.codegenNode != null, `Codegen node is missing for element/if/for node. ` +3091 `Apply appropriate transforms first.`);3092 genNode(node.codegenNode, context);3093 break;3094 case 2 /* TEXT */:3095 genText(node, context);3096 break;3097 case 4 /* SIMPLE_EXPRESSION */:3098 genExpression(node, context);3099 break;3100 case 5 /* INTERPOLATION */:3101 genInterpolation(node, context);3102 break;3103 case 12 /* TEXT_CALL */:3104 genNode(node.codegenNode, context);3105 break;3106 case 8 /* COMPOUND_EXPRESSION */:3107 genCompoundExpression(node, context);3108 break;3109 case 3 /* COMMENT */:3110 genComment(node, context);3111 break;3112 case 13 /* VNODE_CALL */:3113 genVNodeCall(node, context);3114 break;3115 case 14 /* JS_CALL_EXPRESSION */:3116 genCallExpression(node, context);3117 break;3118 case 15 /* JS_OBJECT_EXPRESSION */:3119 genObjectExpression(node, context);3120 break;3121 case 17 /* JS_ARRAY_EXPRESSION */:3122 genArrayExpression(node, context);3123 break;3124 case 18 /* JS_FUNCTION_EXPRESSION */:3125 genFunctionExpression(node, context);3126 break;3127 case 19 /* JS_CONDITIONAL_EXPRESSION */:3128 genConditionalExpression(node, context);3129 break;3130 case 20 /* JS_CACHE_EXPRESSION */:3131 genCacheExpression(node, context);3132 break;3133 case 21 /* JS_BLOCK_STATEMENT */:3134 genNodeList(node.body, context, true, false);3135 break;3136 // SSR only types3137 case 22 /* JS_TEMPLATE_LITERAL */:3138 break;3139 case 23 /* JS_IF_STATEMENT */:3140 break;3141 case 24 /* JS_ASSIGNMENT_EXPRESSION */:3142 break;3143 case 25 /* JS_SEQUENCE_EXPRESSION */:3144 break;3145 case 26 /* JS_RETURN_STATEMENT */:3146 break;3147 /* istanbul ignore next */3148 case 10 /* IF_BRANCH */:3149 // noop3150 break;3151 default:3152 if ((process.env.NODE_ENV !== 'production')) {3153 assert(false, `unhandled codegen node type: ${node.type}`);3154 // make sure we exhaust all possible types3155 const exhaustiveCheck = node;3156 return exhaustiveCheck;3157 }3158 }3159}3160function genText(node, context) {3161 context.push(JSON.stringify(node.content), node);3162}3163function genExpression(node, context) {3164 const { content, isStatic } = node;3165 context.push(isStatic ? JSON.stringify(content) : content, node);3166}3167function genInterpolation(node, context) {3168 const { push, helper, pure } = context;3169 if (pure)3170 push(PURE_ANNOTATION);3171 push(`${helper(TO_DISPLAY_STRING)}(`);3172 genNode(node.content, context);3173 push(`)`);3174}3175function genCompoundExpression(node, context) {3176 for (let i = 0; i < node.children.length; i++) {3177 const child = node.children[i];3178 if (isString(child)) {3179 context.push(child);3180 }3181 else {3182 genNode(child, context);3183 }3184 }3185}3186function genExpressionAsPropertyKey(node, context) {3187 const { push } = context;3188 if (node.type === 8 /* COMPOUND_EXPRESSION */) {3189 push(`[`);3190 genCompoundExpression(node, context);3191 push(`]`);3192 }3193 else if (node.isStatic) {3194 // only quote keys if necessary3195 const text = isSimpleIdentifier(node.content)3196 ? node.content3197 : JSON.stringify(node.content);3198 push(text, node);3199 }3200 else {3201 push(`[${node.content}]`, node);3202 }3203}3204function genComment(node, context) {3205 const { push, helper, pure } = context;3206 if (pure) {3207 push(PURE_ANNOTATION);3208 }3209 push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node);3210}3211function genVNodeCall(node, context) {3212 const { push, helper, pure } = context;3213 const { tag, props, children, patchFlag, dynamicProps, directives, isBlock, disableTracking, isComponent } = node;3214 if (directives) {3215 push(helper(WITH_DIRECTIVES) + `(`);3216 }3217 if (isBlock) {3218 push(`(${helper(OPEN_BLOCK)}(${disableTracking ? `true` : ``}), `);3219 }3220 if (pure) {3221 push(PURE_ANNOTATION);3222 }3223 const callHelper = isBlock3224 ? getVNodeBlockHelper(context.inSSR, isComponent)3225 : getVNodeHelper(context.inSSR, isComponent);3226 push(helper(callHelper) + `(`, node);3227 genNodeList(genNullableArgs([tag, props, children, patchFlag, dynamicProps]), context);3228 push(`)`);3229 if (isBlock) {3230 push(`)`);3231 }3232 if (directives) {3233 push(`, `);3234 genNode(directives, context);3235 push(`)`);3236 }3237}3238function genNullableArgs(args) {3239 let i = args.length;3240 while (i--) {3241 if (args[i] != null)3242 break;3243 }3244 return args.slice(0, i + 1).map(arg => arg || `null`);3245}3246// JavaScript3247function genCallExpression(node, context) {3248 const { push, helper, pure } = context;3249 const callee = isString(node.callee) ? node.callee : helper(node.callee);3250 if (pure) {3251 push(PURE_ANNOTATION);3252 }3253 push(callee + `(`, node);3254 genNodeList(node.arguments, context);3255 push(`)`);3256}3257function genObjectExpression(node, context) {3258 const { push, indent, deindent, newline } = context;3259 const { properties } = node;3260 if (!properties.length) {3261 push(`{}`, node);3262 return;3263 }3264 const multilines = properties.length > 1 ||3265 (((process.env.NODE_ENV !== 'production')) &&3266 properties.some(p => p.value.type !== 4 /* SIMPLE_EXPRESSION */));3267 push(multilines ? `{` : `{ `);3268 multilines && indent();3269 for (let i = 0; i < properties.length; i++) {3270 const { key, value } = properties[i];3271 // key3272 genExpressionAsPropertyKey(key, context);3273 push(`: `);3274 // value3275 genNode(value, context);3276 if (i < properties.length - 1) {3277 // will only reach this if it's multilines3278 push(`,`);3279 newline();3280 }3281 }3282 multilines && deindent();3283 push(multilines ? `}` : ` }`);3284}3285function genArrayExpression(node, context) {3286 genNodeListAsArray(node.elements, context);3287}3288function genFunctionExpression(node, context) {3289 const { push, indent, deindent } = context;3290 const { params, returns, body, newline, isSlot } = node;3291 if (isSlot) {3292 // wrap slot functions with owner context3293 push(`_${helperNameMap[WITH_CTX]}(`);3294 }3295 push(`(`, node);3296 if (isArray(params)) {3297 genNodeList(params, context);3298 }3299 else if (params) {3300 genNode(params, context);3301 }3302 push(`) => `);3303 if (newline || body) {3304 push(`{`);3305 indent();3306 }3307 if (returns) {3308 if (newline) {3309 push(`return `);3310 }3311 if (isArray(returns)) {3312 genNodeListAsArray(returns, context);3313 }3314 else {3315 genNode(returns, context);3316 }3317 }3318 else if (body) {3319 genNode(body, context);3320 }3321 if (newline || body) {3322 deindent();3323 push(`}`);3324 }3325 if (isSlot) {3326 if (node.isNonScopedSlot) {3327 push(`, undefined, true`);3328 }3329 push(`)`);3330 }3331}3332function genConditionalExpression(node, context) {3333 const { test, consequent, alternate, newline: needNewline } = node;3334 const { push, indent, deindent, newline } = context;3335 if (test.type === 4 /* SIMPLE_EXPRESSION */) {3336 const needsParens = !isSimpleIdentifier(test.content);3337 needsParens && push(`(`);3338 genExpression(test, context);3339 needsParens && push(`)`);3340 }3341 else {3342 push(`(`);3343 genNode(test, context);3344 push(`)`);3345 }3346 needNewline && indent();3347 context.indentLevel++;3348 needNewline || push(` `);3349 push(`? `);3350 genNode(consequent, context);3351 context.indentLevel--;3352 needNewline && newline();3353 needNewline || push(` `);3354 push(`: `);3355 const isNested = alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */;3356 if (!isNested) {3357 context.indentLevel++;3358 }3359 genNode(alternate, context);3360 if (!isNested) {3361 context.indentLevel--;3362 }3363 needNewline && deindent(true /* without newline */);3364}3365function genCacheExpression(node, context) {3366 const { push, helper, indent, deindent, newline } = context;3367 push(`_cache[${node.index}] || (`);3368 if (node.isVNode) {3369 indent();3370 push(`${helper(SET_BLOCK_TRACKING)}(-1),`);3371 newline();3372 }3373 push(`_cache[${node.index}] = `);3374 genNode(node.value, context);3375 if (node.isVNode) {3376 push(`,`);3377 newline();3378 push(`${helper(SET_BLOCK_TRACKING)}(1),`);3379 newline();3380 push(`_cache[${node.index}]`);3381 deindent();3382 }3383 push(`)`);3384}3385function walkIdentifiers(root, onIdentifier, includeAll = false, parentStack = [], knownIds = Object.create(null)) {3386 {3387 return;3388 }3389}3390function isReferencedIdentifier(id, parent, parentStack) {3391 {3392 return false;3393 }3394}3395function isInDestructureAssignment(parent, parentStack) {3396 if (parent &&3397 (parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')) {3398 let i = parentStack.length;3399 while (i--) {3400 const p = parentStack[i];3401 if (p.type === 'AssignmentExpression') {3402 return true;3403 }3404 else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {3405 break;3406 }3407 }3408 }3409 return false;3410}3411function walkFunctionParams(node, onIdent) {3412 for (const p of node.params) {3413 for (const id of extractIdentifiers(p)) {3414 onIdent(id);3415 }3416 }3417}3418function walkBlockDeclarations(block, onIdent) {3419 for (const stmt of block.body) {3420 if (stmt.type === 'VariableDeclaration') {3421 if (stmt.declare)3422 continue;3423 for (const decl of stmt.declarations) {3424 for (const id of extractIdentifiers(decl.id)) {3425 onIdent(id);3426 }3427 }3428 }3429 else if (stmt.type === 'FunctionDeclaration' ||3430 stmt.type === 'ClassDeclaration') {3431 if (stmt.declare || !stmt.id)3432 continue;3433 onIdent(stmt.id);3434 }3435 }3436}3437function extractIdentifiers(param, nodes = []) {3438 switch (param.type) {3439 case 'Identifier':3440 nodes.push(param);3441 break;3442 case 'MemberExpression':3443 let object = param;3444 while (object.type === 'MemberExpression') {3445 object = object.object;3446 }3447 nodes.push(object);3448 break;3449 case 'ObjectPattern':3450 for (const prop of param.properties) {3451 if (prop.type === 'RestElement') {3452 extractIdentifiers(prop.argument, nodes);3453 }3454 else {3455 extractIdentifiers(prop.value, nodes);3456 }3457 }3458 break;3459 case 'ArrayPattern':3460 param.elements.forEach(element => {3461 if (element)3462 extractIdentifiers(element, nodes);3463 });3464 break;3465 case 'RestElement':3466 extractIdentifiers(param.argument, nodes);3467 break;3468 case 'AssignmentPattern':3469 extractIdentifiers(param.left, nodes);3470 break;3471 }3472 return nodes;3473}3474const isFunctionType = (node) => {3475 return /Function(?:Expression|Declaration)$|Method$/.test(node.type);3476};3477const isStaticProperty = (node) => node &&3478 (node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&3479 !node.computed;3480const isStaticPropertyKey = (node, parent) => isStaticProperty(parent) && parent.key === node;3481// these keywords should not appear inside expressions, but operators like3482// typeof, instanceof and in are allowed3483const prohibitedKeywordRE = new RegExp('\\b' +3484 ('do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,' +3485 'super,throw,while,yield,delete,export,import,return,switch,default,' +3486 'extends,finally,continue,debugger,function,arguments,typeof,void')3487 .split(',')3488 .join('\\b|\\b') +3489 '\\b');3490// strip strings in expressions3491const stripStringRE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`/g;3492/**3493 * Validate a non-prefixed expression.3494 * This is only called when using the in-browser runtime compiler since it3495 * doesn't prefix expressions.3496 */3497function validateBrowserExpression(node, context, asParams = false, asRawStatements = false) {3498 const exp = node.content;3499 // empty expressions are validated per-directive since some directives3500 // do allow empty expressions.3501 if (!exp.trim()) {3502 return;3503 }3504 try {3505 new Function(asRawStatements3506 ? ` ${exp} `3507 : `return ${asParams ? `(${exp}) => {}` : `(${exp})`}`);3508 }3509 catch (e) {3510 let message = e.message;3511 const keywordMatch = exp3512 .replace(stripStringRE, '')3513 .match(prohibitedKeywordRE);3514 if (keywordMatch) {3515 message = `avoid using JavaScript keyword as property name: "${keywordMatch[0]}"`;3516 }3517 context.onError(createCompilerError(44 /* X_INVALID_EXPRESSION */, node.loc, undefined, message));3518 }3519}3520const transformExpression = (node, context) => {3521 if (node.type === 5 /* INTERPOLATION */) {3522 node.content = processExpression(node.content, context);3523 }3524 else if (node.type === 1 /* ELEMENT */) {3525 // handle directives on element3526 for (let i = 0; i < node.props.length; i++) {3527 const dir = node.props[i];3528 // do not process for v-on & v-for since they are special handled3529 if (dir.type === 7 /* DIRECTIVE */ && dir.name !== 'for') {3530 const exp = dir.exp;3531 const arg = dir.arg;3532 // do not process exp if this is v-on:arg - we need special handling3533 // for wrapping inline statements.3534 if (exp &&3535 exp.type === 4 /* SIMPLE_EXPRESSION */ &&3536 !(dir.name === 'on' && arg)) {3537 dir.exp = processExpression(exp, context, 3538 // slot args must be processed as function params3539 dir.name === 'slot');3540 }3541 if (arg && arg.type === 4 /* SIMPLE_EXPRESSION */ && !arg.isStatic) {3542 dir.arg = processExpression(arg, context);3543 }3544 }3545 }3546 }3547};3548// Important: since this function uses Node.js only dependencies, it should3549// always be used with a leading !true check so that it can be3550// tree-shaken from the browser build.3551function processExpression(node, context, 3552// some expressions like v-slot props & v-for aliases should be parsed as3553// function params3554asParams = false, 3555// v-on handler values may contain multiple statements3556asRawStatements = false, localVars = Object.create(context.identifiers)) {3557 {3558 if ((process.env.NODE_ENV !== 'production')) {3559 // simple in-browser validation (same logic in 2.x)3560 validateBrowserExpression(node, context, asParams, asRawStatements);3561 }3562 return node;3563 }3564}3565const transformIf = createStructuralDirectiveTransform(/^(if|else|else-if)$/, (node, dir, context) => {3566 return processIf(node, dir, context, (ifNode, branch, isRoot) => {3567 // #1587: We need to dynamically increment the key based on the current3568 // node's sibling nodes, since chained v-if/else branches are3569 // rendered at the same depth3570 const siblings = context.parent.children;3571 let i = siblings.indexOf(ifNode);3572 let key = 0;3573 while (i-- >= 0) {3574 const sibling = siblings[i];3575 if (sibling && sibling.type === 9 /* IF */) {3576 key += sibling.branches.length;3577 }3578 }3579 // Exit callback. Complete the codegenNode when all children have been3580 // transformed.3581 return () => {3582 if (isRoot) {3583 ifNode.codegenNode = createCodegenNodeForBranch(branch, key, context);3584 }3585 else {3586 // attach this branch's codegen node to the v-if root.3587 const parentCondition = getParentCondition(ifNode.codegenNode);3588 parentCondition.alternate = createCodegenNodeForBranch(branch, key + ifNode.branches.length - 1, context);3589 }3590 };3591 });3592});3593// target-agnostic transform used for both Client and SSR3594function processIf(node, dir, context, processCodegen) {3595 if (dir.name !== 'else' &&3596 (!dir.exp || !dir.exp.content.trim())) {3597 const loc = dir.exp ? dir.exp.loc : node.loc;3598 context.onError(createCompilerError(28 /* X_V_IF_NO_EXPRESSION */, dir.loc));3599 dir.exp = createSimpleExpression(`true`, false, loc);3600 }3601 if ((process.env.NODE_ENV !== 'production') && true && dir.exp) {3602 validateBrowserExpression(dir.exp, context);3603 }3604 if (dir.name === 'if') {3605 const branch = createIfBranch(node, dir);3606 const ifNode = {3607 type: 9 /* IF */,3608 loc: node.loc,3609 branches: [branch]3610 };3611 context.replaceNode(ifNode);3612 if (processCodegen) {3613 return processCodegen(ifNode, branch, true);3614 }3615 }3616 else {3617 // locate the adjacent v-if3618 const siblings = context.parent.children;3619 const comments = [];3620 let i = siblings.indexOf(node);3621 while (i-- >= -1) {3622 const sibling = siblings[i];3623 if ((process.env.NODE_ENV !== 'production') && sibling && sibling.type === 3 /* COMMENT */) {3624 context.removeNode(sibling);3625 comments.unshift(sibling);3626 continue;3627 }3628 if (sibling &&3629 sibling.type === 2 /* TEXT */ &&3630 !sibling.content.trim().length) {3631 context.removeNode(sibling);3632 continue;3633 }3634 if (sibling && sibling.type === 9 /* IF */) {3635 // Check if v-else was followed by v-else-if3636 if (dir.name === 'else-if' &&3637 sibling.branches[sibling.branches.length - 1].condition === undefined) {3638 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));3639 }3640 // move the node to the if node's branches3641 context.removeNode();3642 const branch = createIfBranch(node, dir);3643 if ((process.env.NODE_ENV !== 'production') &&3644 comments.length &&3645 // #3619 ignore comments if the v-if is direct child of <transition>3646 !(context.parent &&3647 context.parent.type === 1 /* ELEMENT */ &&3648 isBuiltInType(context.parent.tag, 'transition'))) {3649 branch.children = [...comments, ...branch.children];3650 }3651 // check if user is forcing same key on different branches3652 if ((process.env.NODE_ENV !== 'production') || !true) {3653 const key = branch.userKey;3654 if (key) {3655 sibling.branches.forEach(({ userKey }) => {3656 if (isSameKey(userKey, key)) {3657 context.onError(createCompilerError(29 /* X_V_IF_SAME_KEY */, branch.userKey.loc));3658 }3659 });3660 }3661 }3662 sibling.branches.push(branch);3663 const onExit = processCodegen && processCodegen(sibling, branch, false);3664 // since the branch was removed, it will not be traversed.3665 // make sure to traverse here.3666 traverseNode(branch, context);3667 // call on exit3668 if (onExit)3669 onExit();3670 // make sure to reset currentNode after traversal to indicate this3671 // node has been removed.3672 context.currentNode = null;3673 }3674 else {3675 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));3676 }3677 break;3678 }3679 }3680}3681function createIfBranch(node, dir) {3682 return {3683 type: 10 /* IF_BRANCH */,3684 loc: node.loc,3685 condition: dir.name === 'else' ? undefined : dir.exp,3686 children: node.tagType === 3 /* TEMPLATE */ && !findDir(node, 'for')3687 ? node.children3688 : [node],3689 userKey: findProp(node, `key`)3690 };3691}3692function createCodegenNodeForBranch(branch, keyIndex, context) {3693 if (branch.condition) {3694 return createConditionalExpression(branch.condition, createChildrenCodegenNode(branch, keyIndex, context), 3695 // make sure to pass in asBlock: true so that the comment node call3696 // closes the current block.3697 createCallExpression(context.helper(CREATE_COMMENT), [3698 (process.env.NODE_ENV !== 'production') ? '"v-if"' : '""',3699 'true'3700 ]));3701 }3702 else {3703 return createChildrenCodegenNode(branch, keyIndex, context);3704 }3705}3706function createChildrenCodegenNode(branch, keyIndex, context) {3707 const { helper } = context;3708 const keyProperty = createObjectProperty(`key`, createSimpleExpression(`${keyIndex}`, false, locStub, 2 /* CAN_HOIST */));3709 const { children } = branch;3710 const firstChild = children[0];3711 const needFragmentWrapper = children.length !== 1 || firstChild.type !== 1 /* ELEMENT */;3712 if (needFragmentWrapper) {3713 if (children.length === 1 && firstChild.type === 11 /* FOR */) {3714 // optimize away nested fragments when child is a ForNode3715 const vnodeCall = firstChild.codegenNode;3716 injectProp(vnodeCall, keyProperty, context);3717 return vnodeCall;3718 }3719 else {3720 let patchFlag = 64 /* STABLE_FRAGMENT */;3721 let patchFlagText = PatchFlagNames[64 /* STABLE_FRAGMENT */];3722 // check if the fragment actually contains a single valid child with3723 // the rest being comments3724 if ((process.env.NODE_ENV !== 'production') &&3725 children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {3726 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;3727 patchFlagText += `, ${PatchFlagNames[2048 /* DEV_ROOT_FRAGMENT */]}`;3728 }3729 return createVNodeCall(context, helper(FRAGMENT), createObjectExpression([keyProperty]), children, patchFlag + ((process.env.NODE_ENV !== 'production') ? ` /* ${patchFlagText} */` : ``), undefined, undefined, true, false, false /* isComponent */, branch.loc);3730 }3731 }3732 else {3733 const ret = firstChild.codegenNode;3734 const vnodeCall = getMemoedVNodeCall(ret);3735 // Change createVNode to createBlock.3736 if (vnodeCall.type === 13 /* VNODE_CALL */) {3737 makeBlock(vnodeCall, context);3738 }3739 // inject branch key3740 injectProp(vnodeCall, keyProperty, context);3741 return ret;3742 }3743}3744function isSameKey(a, b) {3745 if (!a || a.type !== b.type) {3746 return false;3747 }3748 if (a.type === 6 /* ATTRIBUTE */) {3749 if (a.value.content !== b.value.content) {3750 return false;3751 }3752 }3753 else {3754 // directive3755 const exp = a.exp;3756 const branchExp = b.exp;3757 if (exp.type !== branchExp.type) {3758 return false;3759 }3760 if (exp.type !== 4 /* SIMPLE_EXPRESSION */ ||3761 exp.isStatic !== branchExp.isStatic ||3762 exp.content !== branchExp.content) {3763 return false;3764 }3765 }3766 return true;3767}3768function getParentCondition(node) {3769 while (true) {3770 if (node.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3771 if (node.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3772 node = node.alternate;3773 }3774 else {3775 return node;3776 }3777 }3778 else if (node.type === 20 /* JS_CACHE_EXPRESSION */) {3779 node = node.value;3780 }3781 }3782}3783const transformFor = createStructuralDirectiveTransform('for', (node, dir, context) => {3784 const { helper, removeHelper } = context;3785 return processFor(node, dir, context, forNode => {3786 // create the loop render function expression now, and add the3787 // iterator on exit after all children have been traversed3788 const renderExp = createCallExpression(helper(RENDER_LIST), [3789 forNode.source3790 ]);3791 const isTemplate = isTemplateNode(node);3792 const memo = findDir(node, 'memo');3793 const keyProp = findProp(node, `key`);3794 const keyExp = keyProp &&3795 (keyProp.type === 6 /* ATTRIBUTE */3796 ? createSimpleExpression(keyProp.value.content, true)3797 : keyProp.exp);3798 const keyProperty = keyProp ? createObjectProperty(`key`, keyExp) : null;3799 const isStableFragment = forNode.source.type === 4 /* SIMPLE_EXPRESSION */ &&3800 forNode.source.constType > 0 /* NOT_CONSTANT */;3801 const fragmentFlag = isStableFragment3802 ? 64 /* STABLE_FRAGMENT */3803 : keyProp3804 ? 128 /* KEYED_FRAGMENT */3805 : 256 /* UNKEYED_FRAGMENT */;3806 forNode.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, renderExp, fragmentFlag +3807 ((process.env.NODE_ENV !== 'production') ? ` /* ${PatchFlagNames[fragmentFlag]} */` : ``), undefined, undefined, true /* isBlock */, !isStableFragment /* disableTracking */, false /* isComponent */, node.loc);3808 return () => {3809 // finish the codegen now that all children have been traversed3810 let childBlock;3811 const { children } = forNode;3812 // check <template v-for> key placement3813 if (((process.env.NODE_ENV !== 'production') || !true) && isTemplate) {3814 node.children.some(c => {3815 if (c.type === 1 /* ELEMENT */) {3816 const key = findProp(c, 'key');3817 if (key) {3818 context.onError(createCompilerError(33 /* X_V_FOR_TEMPLATE_KEY_PLACEMENT */, key.loc));3819 return true;3820 }3821 }3822 });3823 }3824 const needFragmentWrapper = children.length !== 1 || children[0].type !== 1 /* ELEMENT */;3825 const slotOutlet = isSlotOutlet(node)3826 ? node3827 : isTemplate &&3828 node.children.length === 1 &&3829 isSlotOutlet(node.children[0])3830 ? node.children[0] // api-extractor somehow fails to infer this3831 : null;3832 if (slotOutlet) {3833 // <slot v-for="..."> or <template v-for="..."><slot/></template>3834 childBlock = slotOutlet.codegenNode;3835 if (isTemplate && keyProperty) {3836 // <template v-for="..." :key="..."><slot/></template>3837 // we need to inject the key to the renderSlot() call.3838 // the props for renderSlot is passed as the 3rd argument.3839 injectProp(childBlock, keyProperty, context);3840 }3841 }3842 else if (needFragmentWrapper) {3843 // <template v-for="..."> with text or multi-elements3844 // should generate a fragment block for each loop3845 childBlock = createVNodeCall(context, helper(FRAGMENT), keyProperty ? createObjectExpression([keyProperty]) : undefined, node.children, 64 /* STABLE_FRAGMENT */ +3846 ((process.env.NODE_ENV !== 'production')3847 ? ` /* ${PatchFlagNames[64 /* STABLE_FRAGMENT */]} */`3848 : ``), undefined, undefined, true, undefined, false /* isComponent */);3849 }3850 else {3851 // Normal element v-for. Directly use the child's codegenNode3852 // but mark it as a block.3853 childBlock = children[0]3854 .codegenNode;3855 if (isTemplate && keyProperty) {3856 injectProp(childBlock, keyProperty, context);3857 }3858 if (childBlock.isBlock !== !isStableFragment) {3859 if (childBlock.isBlock) {3860 // switch from block to vnode3861 removeHelper(OPEN_BLOCK);3862 removeHelper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3863 }3864 else {3865 // switch from vnode to block3866 removeHelper(getVNodeHelper(context.inSSR, childBlock.isComponent));3867 }3868 }3869 childBlock.isBlock = !isStableFragment;3870 if (childBlock.isBlock) {3871 helper(OPEN_BLOCK);3872 helper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3873 }3874 else {3875 helper(getVNodeHelper(context.inSSR, childBlock.isComponent));3876 }3877 }3878 if (memo) {3879 const loop = createFunctionExpression(createForLoopParams(forNode.parseResult, [3880 createSimpleExpression(`_cached`)3881 ]));3882 loop.body = createBlockStatement([3883 createCompoundExpression([`const _memo = (`, memo.exp, `)`]),3884 createCompoundExpression([3885 `if (_cached`,3886 ...(keyExp ? [` && _cached.key === `, keyExp] : []),3887 ` && ${context.helperString(IS_MEMO_SAME)}(_cached, _memo)) return _cached`3888 ]),3889 createCompoundExpression([`const _item = `, childBlock]),3890 createSimpleExpression(`_item.memo = _memo`),3891 createSimpleExpression(`return _item`)3892 ]);3893 renderExp.arguments.push(loop, createSimpleExpression(`_cache`), createSimpleExpression(String(context.cached++)));3894 }3895 else {3896 renderExp.arguments.push(createFunctionExpression(createForLoopParams(forNode.parseResult), childBlock, true /* force newline */));3897 }3898 };3899 });3900});3901// target-agnostic transform used for both Client and SSR3902function processFor(node, dir, context, processCodegen) {3903 if (!dir.exp) {3904 context.onError(createCompilerError(31 /* X_V_FOR_NO_EXPRESSION */, dir.loc));3905 return;3906 }3907 const parseResult = parseForExpression(3908 // can only be simple expression because vFor transform is applied3909 // before expression transform.3910 dir.exp, context);3911 if (!parseResult) {3912 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));3913 return;3914 }3915 const { addIdentifiers, removeIdentifiers, scopes } = context;3916 const { source, value, key, index } = parseResult;3917 const forNode = {3918 type: 11 /* FOR */,3919 loc: dir.loc,3920 source,3921 valueAlias: value,3922 keyAlias: key,3923 objectIndexAlias: index,3924 parseResult,3925 children: isTemplateNode(node) ? node.children : [node]3926 };3927 context.replaceNode(forNode);3928 // bookkeeping3929 scopes.vFor++;3930 const onExit = processCodegen && processCodegen(forNode);3931 return () => {3932 scopes.vFor--;3933 if (onExit)3934 onExit();3935 };3936}3937const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;3938// This regex doesn't cover the case if key or index aliases have destructuring,3939// but those do not make sense in the first place, so this works in practice.3940const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;3941const stripParensRE = /^\(|\)$/g;3942function parseForExpression(input, context) {3943 const loc = input.loc;3944 const exp = input.content;3945 const inMatch = exp.match(forAliasRE);3946 if (!inMatch)3947 return;3948 const [, LHS, RHS] = inMatch;3949 const result = {3950 source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),3951 value: undefined,3952 key: undefined,3953 index: undefined3954 };3955 if ((process.env.NODE_ENV !== 'production') && true) {3956 validateBrowserExpression(result.source, context);3957 }3958 let valueContent = LHS.trim().replace(stripParensRE, '').trim();3959 const trimmedOffset = LHS.indexOf(valueContent);3960 const iteratorMatch = valueContent.match(forIteratorRE);3961 if (iteratorMatch) {3962 valueContent = valueContent.replace(forIteratorRE, '').trim();3963 const keyContent = iteratorMatch[1].trim();3964 let keyOffset;3965 if (keyContent) {3966 keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);3967 result.key = createAliasExpression(loc, keyContent, keyOffset);3968 if ((process.env.NODE_ENV !== 'production') && true) {3969 validateBrowserExpression(result.key, context, true);3970 }3971 }3972 if (iteratorMatch[2]) {3973 const indexContent = iteratorMatch[2].trim();3974 if (indexContent) {3975 result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key3976 ? keyOffset + keyContent.length3977 : trimmedOffset + valueContent.length));3978 if ((process.env.NODE_ENV !== 'production') && true) {3979 validateBrowserExpression(result.index, context, true);3980 }3981 }3982 }3983 }3984 if (valueContent) {3985 result.value = createAliasExpression(loc, valueContent, trimmedOffset);3986 if ((process.env.NODE_ENV !== 'production') && true) {3987 validateBrowserExpression(result.value, context, true);3988 }3989 }3990 return result;3991}3992function createAliasExpression(range, content, offset) {3993 return createSimpleExpression(content, false, getInnerRange(range, offset, content.length));3994}3995function createForLoopParams({ value, key, index }, memoArgs = []) {3996 return createParamsList([value, key, index, ...memoArgs]);3997}3998function createParamsList(args) {3999 let i = args.length;4000 while (i--) {4001 if (args[i])4002 break;4003 }4004 return args4005 .slice(0, i + 1)4006 .map((arg, i) => arg || createSimpleExpression(`_`.repeat(i + 1), false));4007}4008const defaultFallback = createSimpleExpression(`undefined`, false);4009// A NodeTransform that:4010// 1. Tracks scope identifiers for scoped slots so that they don't get prefixed4011// by transformExpression. This is only applied in non-browser builds with4012// { prefixIdentifiers: true }.4013// 2. Track v-slot depths so that we know a slot is inside another slot.4014// Note the exit callback is executed before buildSlots() on the same node,4015// so only nested slots see positive numbers.4016const trackSlotScopes = (node, context) => {4017 if (node.type === 1 /* ELEMENT */ &&4018 (node.tagType === 1 /* COMPONENT */ ||4019 node.tagType === 3 /* TEMPLATE */)) {4020 // We are only checking non-empty v-slot here4021 // since we only care about slots that introduce scope variables.4022 const vSlot = findDir(node, 'slot');4023 if (vSlot) {4024 context.scopes.vSlot++;4025 return () => {4026 context.scopes.vSlot--;4027 };4028 }4029 }4030};4031// A NodeTransform that tracks scope identifiers for scoped slots with v-for.4032// This transform is only applied in non-browser builds with { prefixIdentifiers: true }4033const trackVForSlotScopes = (node, context) => {4034 let vFor;4035 if (isTemplateNode(node) &&4036 node.props.some(isVSlot) &&4037 (vFor = findDir(node, 'for'))) {4038 const result = (vFor.parseResult = parseForExpression(vFor.exp, context));4039 if (result) {4040 const { value, key, index } = result;4041 const { addIdentifiers, removeIdentifiers } = context;4042 value && addIdentifiers(value);4043 key && addIdentifiers(key);4044 index && addIdentifiers(index);4045 return () => {4046 value && removeIdentifiers(value);4047 key && removeIdentifiers(key);4048 index && removeIdentifiers(index);4049 };4050 }4051 }4052};4053const buildClientSlotFn = (props, children, loc) => createFunctionExpression(props, children, false /* newline */, true /* isSlot */, children.length ? children[0].loc : loc);4054// Instead of being a DirectiveTransform, v-slot processing is called during4055// transformElement to build the slots object for a component.4056function buildSlots(node, context, buildSlotFn = buildClientSlotFn) {4057 context.helper(WITH_CTX);4058 const { children, loc } = node;4059 const slotsProperties = [];4060 const dynamicSlots = [];4061 // If the slot is inside a v-for or another v-slot, force it to be dynamic4062 // since it likely uses a scope variable.4063 let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0;4064 // 1. Check for slot with slotProps on component itself.4065 // <Comp v-slot="{ prop }"/>4066 const onComponentSlot = findDir(node, 'slot', true);4067 if (onComponentSlot) {4068 const { arg, exp } = onComponentSlot;4069 if (arg && !isStaticExp(arg)) {4070 hasDynamicSlots = true;4071 }4072 slotsProperties.push(createObjectProperty(arg || createSimpleExpression('default', true), buildSlotFn(exp, children, loc)));4073 }4074 // 2. Iterate through children and check for template slots4075 // <template v-slot:foo="{ prop }">4076 let hasTemplateSlots = false;4077 let hasNamedDefaultSlot = false;4078 const implicitDefaultChildren = [];4079 const seenSlotNames = new Set();4080 for (let i = 0; i < children.length; i++) {4081 const slotElement = children[i];4082 let slotDir;4083 if (!isTemplateNode(slotElement) ||4084 !(slotDir = findDir(slotElement, 'slot', true))) {4085 // not a <template v-slot>, skip.4086 if (slotElement.type !== 3 /* COMMENT */) {4087 implicitDefaultChildren.push(slotElement);4088 }4089 continue;4090 }4091 if (onComponentSlot) {4092 // already has on-component slot - this is incorrect usage.4093 context.onError(createCompilerError(37 /* X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc));4094 break;4095 }4096 hasTemplateSlots = true;4097 const { children: slotChildren, loc: slotLoc } = slotElement;4098 const { arg: slotName = createSimpleExpression(`default`, true), exp: slotProps, loc: dirLoc } = slotDir;4099 // check if name is dynamic.4100 let staticSlotName;4101 if (isStaticExp(slotName)) {4102 staticSlotName = slotName ? slotName.content : `default`;4103 }4104 else {4105 hasDynamicSlots = true;4106 }4107 const slotFunction = buildSlotFn(slotProps, slotChildren, slotLoc);4108 // check if this slot is conditional (v-if/v-for)4109 let vIf;4110 let vElse;4111 let vFor;4112 if ((vIf = findDir(slotElement, 'if'))) {4113 hasDynamicSlots = true;4114 dynamicSlots.push(createConditionalExpression(vIf.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback));4115 }4116 else if ((vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))) {4117 // find adjacent v-if4118 let j = i;4119 let prev;4120 while (j--) {4121 prev = children[j];4122 if (prev.type !== 3 /* COMMENT */) {4123 break;4124 }4125 }4126 if (prev && isTemplateNode(prev) && findDir(prev, 'if')) {4127 // remove node4128 children.splice(i, 1);4129 i--;4130 // attach this slot to previous conditional4131 let conditional = dynamicSlots[dynamicSlots.length - 1];4132 while (conditional.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {4133 conditional = conditional.alternate;4134 }4135 conditional.alternate = vElse.exp4136 ? createConditionalExpression(vElse.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback)4137 : buildDynamicSlot(slotName, slotFunction);4138 }4139 else {4140 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, vElse.loc));4141 }4142 }4143 else if ((vFor = findDir(slotElement, 'for'))) {4144 hasDynamicSlots = true;4145 const parseResult = vFor.parseResult ||4146 parseForExpression(vFor.exp, context);4147 if (parseResult) {4148 // Render the dynamic slots as an array and add it to the createSlot()4149 // args. The runtime knows how to handle it appropriately.4150 dynamicSlots.push(createCallExpression(context.helper(RENDER_LIST), [4151 parseResult.source,4152 createFunctionExpression(createForLoopParams(parseResult), buildDynamicSlot(slotName, slotFunction), true /* force newline */)4153 ]));4154 }4155 else {4156 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc));4157 }4158 }4159 else {4160 // check duplicate static names4161 if (staticSlotName) {4162 if (seenSlotNames.has(staticSlotName)) {4163 context.onError(createCompilerError(38 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc));4164 continue;4165 }4166 seenSlotNames.add(staticSlotName);4167 if (staticSlotName === 'default') {4168 hasNamedDefaultSlot = true;4169 }4170 }4171 slotsProperties.push(createObjectProperty(slotName, slotFunction));4172 }4173 }4174 if (!onComponentSlot) {4175 const buildDefaultSlotProperty = (props, children) => {4176 const fn = buildSlotFn(props, children, loc);4177 if (context.compatConfig) {4178 fn.isNonScopedSlot = true;4179 }4180 return createObjectProperty(`default`, fn);4181 };4182 if (!hasTemplateSlots) {4183 // implicit default slot (on component)4184 slotsProperties.push(buildDefaultSlotProperty(undefined, children));4185 }4186 else if (implicitDefaultChildren.length &&4187 // #37664188 // with whitespace: 'preserve', whitespaces between slots will end up in4189 // implicitDefaultChildren. Ignore if all implicit children are whitespaces.4190 implicitDefaultChildren.some(node => isNonWhitespaceContent(node))) {4191 // implicit default slot (mixed with named slots)4192 if (hasNamedDefaultSlot) {4193 context.onError(createCompilerError(39 /* X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN */, implicitDefaultChildren[0].loc));4194 }4195 else {4196 slotsProperties.push(buildDefaultSlotProperty(undefined, implicitDefaultChildren));4197 }4198 }4199 }4200 const slotFlag = hasDynamicSlots4201 ? 2 /* DYNAMIC */4202 : hasForwardedSlots(node.children)4203 ? 3 /* FORWARDED */4204 : 1 /* STABLE */;4205 let slots = createObjectExpression(slotsProperties.concat(createObjectProperty(`_`, 4206 // 2 = compiled but dynamic = can skip normalization, but must run diff4207 // 1 = compiled and static = can skip normalization AND diff as optimized4208 createSimpleExpression(slotFlag + ((process.env.NODE_ENV !== 'production') ? ` /* ${slotFlagsText[slotFlag]} */` : ``), false))), loc);4209 if (dynamicSlots.length) {4210 slots = createCallExpression(context.helper(CREATE_SLOTS), [4211 slots,4212 createArrayExpression(dynamicSlots)4213 ]);4214 }4215 return {4216 slots,4217 hasDynamicSlots4218 };4219}4220function buildDynamicSlot(name, fn) {4221 return createObjectExpression([4222 createObjectProperty(`name`, name),4223 createObjectProperty(`fn`, fn)4224 ]);4225}4226function hasForwardedSlots(children) {4227 for (let i = 0; i < children.length; i++) {4228 const child = children[i];4229 switch (child.type) {4230 case 1 /* ELEMENT */:4231 if (child.tagType === 2 /* SLOT */ ||4232 hasForwardedSlots(child.children)) {4233 return true;4234 }4235 break;4236 case 9 /* IF */:4237 if (hasForwardedSlots(child.branches))4238 return true;4239 break;4240 case 10 /* IF_BRANCH */:4241 case 11 /* FOR */:4242 if (hasForwardedSlots(child.children))4243 return true;4244 break;4245 }4246 }4247 return false;4248}4249function isNonWhitespaceContent(node) {4250 if (node.type !== 2 /* TEXT */ && node.type !== 12 /* TEXT_CALL */)4251 return true;4252 return node.type === 2 /* TEXT */4253 ? !!node.content.trim()4254 : isNonWhitespaceContent(node.content);4255}4256// some directive transforms (e.g. v-model) may return a symbol for runtime4257// import, which should be used instead of a resolveDirective call.4258const directiveImportMap = new WeakMap();4259// generate a JavaScript AST for this element's codegen4260const transformElement = (node, context) => {4261 // perform the work on exit, after all child expressions have been4262 // processed and merged.4263 return function postTransformElement() {4264 node = context.currentNode;4265 if (!(node.type === 1 /* ELEMENT */ &&4266 (node.tagType === 0 /* ELEMENT */ ||4267 node.tagType === 1 /* COMPONENT */))) {4268 return;4269 }4270 const { tag, props } = node;4271 const isComponent = node.tagType === 1 /* COMPONENT */;4272 // The goal of the transform is to create a codegenNode implementing the4273 // VNodeCall interface.4274 let vnodeTag = isComponent4275 ? resolveComponentType(node, context)4276 : `"${tag}"`;4277 const isDynamicComponent = isObject(vnodeTag) && vnodeTag.callee === RESOLVE_DYNAMIC_COMPONENT;4278 let vnodeProps;4279 let vnodeChildren;4280 let vnodePatchFlag;4281 let patchFlag = 0;4282 let vnodeDynamicProps;4283 let dynamicPropNames;4284 let vnodeDirectives;4285 let shouldUseBlock = 4286 // dynamic component may resolve to plain elements4287 isDynamicComponent ||4288 vnodeTag === TELEPORT ||4289 vnodeTag === SUSPENSE ||4290 (!isComponent &&4291 // <svg> and <foreignObject> must be forced into blocks so that block4292 // updates inside get proper isSVG flag at runtime. (#639, #643)4293 // This is technically web-specific, but splitting the logic out of core4294 // leads to too much unnecessary complexity.4295 (tag === 'svg' || tag === 'foreignObject'));4296 // props4297 if (props.length > 0) {4298 const propsBuildResult = buildProps(node, context);4299 vnodeProps = propsBuildResult.props;4300 patchFlag = propsBuildResult.patchFlag;4301 dynamicPropNames = propsBuildResult.dynamicPropNames;4302 const directives = propsBuildResult.directives;4303 vnodeDirectives =4304 directives && directives.length4305 ? createArrayExpression(directives.map(dir => buildDirectiveArgs(dir, context)))4306 : undefined;4307 if (propsBuildResult.shouldUseBlock) {4308 shouldUseBlock = true;4309 }4310 }4311 // children4312 if (node.children.length > 0) {4313 if (vnodeTag === KEEP_ALIVE) {4314 // Although a built-in component, we compile KeepAlive with raw children4315 // instead of slot functions so that it can be used inside Transition4316 // or other Transition-wrapping HOCs.4317 // To ensure correct updates with block optimizations, we need to:4318 // 1. Force keep-alive into a block. This avoids its children being4319 // collected by a parent block.4320 shouldUseBlock = true;4321 // 2. Force keep-alive to always be updated, since it uses raw children.4322 patchFlag |= 1024 /* DYNAMIC_SLOTS */;4323 if ((process.env.NODE_ENV !== 'production') && node.children.length > 1) {4324 context.onError(createCompilerError(45 /* X_KEEP_ALIVE_INVALID_CHILDREN */, {4325 start: node.children[0].loc.start,4326 end: node.children[node.children.length - 1].loc.end,4327 source: ''4328 }));4329 }4330 }4331 const shouldBuildAsSlots = isComponent &&4332 // Teleport is not a real component and has dedicated runtime handling4333 vnodeTag !== TELEPORT &&4334 // explained above.4335 vnodeTag !== KEEP_ALIVE;4336 if (shouldBuildAsSlots) {4337 const { slots, hasDynamicSlots } = buildSlots(node, context);4338 vnodeChildren = slots;4339 if (hasDynamicSlots) {4340 patchFlag |= 1024 /* DYNAMIC_SLOTS */;4341 }4342 }4343 else if (node.children.length === 1 && vnodeTag !== TELEPORT) {4344 const child = node.children[0];4345 const type = child.type;4346 // check for dynamic text children4347 const hasDynamicTextChild = type === 5 /* INTERPOLATION */ ||4348 type === 8 /* COMPOUND_EXPRESSION */;4349 if (hasDynamicTextChild &&4350 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {4351 patchFlag |= 1 /* TEXT */;4352 }4353 // pass directly if the only child is a text node4354 // (plain / interpolation / expression)4355 if (hasDynamicTextChild || type === 2 /* TEXT */) {4356 vnodeChildren = child;4357 }4358 else {4359 vnodeChildren = node.children;4360 }4361 }4362 else {4363 vnodeChildren = node.children;4364 }4365 }4366 // patchFlag & dynamicPropNames4367 if (patchFlag !== 0) {4368 if ((process.env.NODE_ENV !== 'production')) {4369 if (patchFlag < 0) {4370 // special flags (negative and mutually exclusive)4371 vnodePatchFlag = patchFlag + ` /* ${PatchFlagNames[patchFlag]} */`;4372 }4373 else {4374 // bitwise flags4375 const flagNames = Object.keys(PatchFlagNames)4376 .map(Number)4377 .filter(n => n > 0 && patchFlag & n)4378 .map(n => PatchFlagNames[n])4379 .join(`, `);4380 vnodePatchFlag = patchFlag + ` /* ${flagNames} */`;4381 }4382 }4383 else {4384 vnodePatchFlag = String(patchFlag);4385 }4386 if (dynamicPropNames && dynamicPropNames.length) {4387 vnodeDynamicProps = stringifyDynamicPropNames(dynamicPropNames);4388 }4389 }4390 node.codegenNode = createVNodeCall(context, vnodeTag, vnodeProps, vnodeChildren, vnodePatchFlag, vnodeDynamicProps, vnodeDirectives, !!shouldUseBlock, false /* disableTracking */, isComponent, node.loc);4391 };4392};4393function resolveComponentType(node, context, ssr = false) {4394 let { tag } = node;4395 // 1. dynamic component4396 const isExplicitDynamic = isComponentTag(tag);4397 const isProp = findProp(node, 'is');4398 if (isProp) {4399 if (isExplicitDynamic ||4400 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) {4401 const exp = isProp.type === 6 /* ATTRIBUTE */4402 ? isProp.value && createSimpleExpression(isProp.value.content, true)4403 : isProp.exp;4404 if (exp) {4405 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [4406 exp4407 ]);4408 }4409 }4410 else if (isProp.type === 6 /* ATTRIBUTE */ &&4411 isProp.value.content.startsWith('vue:')) {4412 // <button is="vue:xxx">4413 // if not <component>, only is value that starts with "vue:" will be4414 // treated as component by the parse phase and reach here, unless it's4415 // compat mode where all is values are considered components4416 tag = isProp.value.content.slice(4);4417 }4418 }4419 // 1.5 v-is (TODO: Deprecate)4420 const isDir = !isExplicitDynamic && findDir(node, 'is');4421 if (isDir && isDir.exp) {4422 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [4423 isDir.exp4424 ]);4425 }4426 // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)4427 const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);4428 if (builtIn) {4429 // built-ins are simply fallthroughs / have special handling during ssr4430 // so we don't need to import their runtime equivalents4431 if (!ssr)4432 context.helper(builtIn);4433 return builtIn;4434 }4435 // 5. user component (resolve)4436 context.helper(RESOLVE_COMPONENT);4437 context.components.add(tag);4438 return toValidAssetId(tag, `component`);4439}4440function buildProps(node, context, props = node.props, ssr = false) {4441 const { tag, loc: elementLoc, children } = node;4442 const isComponent = node.tagType === 1 /* COMPONENT */;4443 let properties = [];4444 const mergeArgs = [];4445 const runtimeDirectives = [];4446 const hasChildren = children.length > 0;4447 let shouldUseBlock = false;4448 // patchFlag analysis4449 let patchFlag = 0;4450 let hasRef = false;4451 let hasClassBinding = false;4452 let hasStyleBinding = false;4453 let hasHydrationEventBinding = false;4454 let hasDynamicKeys = false;4455 let hasVnodeHook = false;4456 const dynamicPropNames = [];4457 const analyzePatchFlag = ({ key, value }) => {4458 if (isStaticExp(key)) {4459 const name = key.content;4460 const isEventHandler = isOn(name);4461 if (!isComponent &&4462 isEventHandler &&4463 // omit the flag for click handlers because hydration gives click4464 // dedicated fast path.4465 name.toLowerCase() !== 'onclick' &&4466 // omit v-model handlers4467 name !== 'onUpdate:modelValue' &&4468 // omit onVnodeXXX hooks4469 !isReservedProp(name)) {4470 hasHydrationEventBinding = true;4471 }4472 if (isEventHandler && isReservedProp(name)) {4473 hasVnodeHook = true;4474 }4475 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||4476 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||4477 value.type === 8 /* COMPOUND_EXPRESSION */) &&4478 getConstantType(value, context) > 0)) {4479 // skip if the prop is a cached handler or has constant value4480 return;4481 }4482 if (name === 'ref') {4483 hasRef = true;4484 }4485 else if (name === 'class') {4486 hasClassBinding = true;4487 }4488 else if (name === 'style') {4489 hasStyleBinding = true;4490 }4491 else if (name !== 'key' && !dynamicPropNames.includes(name)) {4492 dynamicPropNames.push(name);4493 }4494 // treat the dynamic class and style binding of the component as dynamic props4495 if (isComponent &&4496 (name === 'class' || name === 'style') &&4497 !dynamicPropNames.includes(name)) {4498 dynamicPropNames.push(name);4499 }4500 }4501 else {4502 hasDynamicKeys = true;4503 }4504 };4505 for (let i = 0; i < props.length; i++) {4506 // static attribute4507 const prop = props[i];4508 if (prop.type === 6 /* ATTRIBUTE */) {4509 const { loc, name, value } = prop;4510 let isStatic = true;4511 if (name === 'ref') {4512 hasRef = true;4513 if (context.scopes.vFor > 0) {4514 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));4515 }4516 }4517 // skip is on <component>, or is="vue:xxx"4518 if (name === 'is' &&4519 (isComponentTag(tag) ||4520 (value && value.content.startsWith('vue:')) ||4521 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) {4522 continue;4523 }4524 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));4525 }4526 else {4527 // directives4528 const { name, arg, exp, loc } = prop;4529 const isVBind = name === 'bind';4530 const isVOn = name === 'on';4531 // skip v-slot - it is handled by its dedicated transform.4532 if (name === 'slot') {4533 if (!isComponent) {4534 context.onError(createCompilerError(40 /* X_V_SLOT_MISPLACED */, loc));4535 }4536 continue;4537 }4538 // skip v-once/v-memo - they are handled by dedicated transforms.4539 if (name === 'once' || name === 'memo') {4540 continue;4541 }4542 // skip v-is and :is on <component>4543 if (name === 'is' ||4544 (isVBind &&4545 isStaticArgOf(arg, 'is') &&4546 (isComponentTag(tag) ||4547 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) {4548 continue;4549 }4550 // skip v-on in SSR compilation4551 if (isVOn && ssr) {4552 continue;4553 }4554 if (4555 // #938: elements with dynamic keys should be forced into blocks4556 (isVBind && isStaticArgOf(arg, 'key')) ||4557 // inline before-update hooks need to force block so that it is invoked4558 // before children4559 (isVOn && hasChildren && isStaticArgOf(arg, 'vue:before-update'))) {4560 shouldUseBlock = true;4561 }4562 if (isVBind && isStaticArgOf(arg, 'ref') && context.scopes.vFor > 0) {4563 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));4564 }4565 // special case for v-bind and v-on with no argument4566 if (!arg && (isVBind || isVOn)) {4567 hasDynamicKeys = true;4568 if (exp) {4569 if (properties.length) {4570 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));4571 properties = [];4572 }4573 if (isVBind) {4574 {4575 // 2.x v-bind object order compat4576 if ((process.env.NODE_ENV !== 'production')) {4577 const hasOverridableKeys = mergeArgs.some(arg => {4578 if (arg.type === 15 /* JS_OBJECT_EXPRESSION */) {4579 return arg.properties.some(({ key }) => {4580 if (key.type !== 4 /* SIMPLE_EXPRESSION */ ||4581 !key.isStatic) {4582 return true;4583 }4584 return (key.content !== 'class' &&4585 key.content !== 'style' &&4586 !isOn(key.content));4587 });4588 }4589 else {4590 // dynamic expression4591 return true;4592 }4593 });4594 if (hasOverridableKeys) {4595 checkCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context, loc);4596 }4597 }4598 if (isCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context)) {4599 mergeArgs.unshift(exp);4600 continue;4601 }4602 }4603 mergeArgs.push(exp);4604 }4605 else {4606 // v-on="obj" -> toHandlers(obj)4607 mergeArgs.push({4608 type: 14 /* JS_CALL_EXPRESSION */,4609 loc,4610 callee: context.helper(TO_HANDLERS),4611 arguments: [exp]4612 });4613 }4614 }4615 else {4616 context.onError(createCompilerError(isVBind4617 ? 34 /* X_V_BIND_NO_EXPRESSION */4618 : 35 /* X_V_ON_NO_EXPRESSION */, loc));4619 }4620 continue;4621 }4622 const directiveTransform = context.directiveTransforms[name];4623 if (directiveTransform) {4624 // has built-in directive transform.4625 const { props, needRuntime } = directiveTransform(prop, node, context);4626 !ssr && props.forEach(analyzePatchFlag);4627 properties.push(...props);4628 if (needRuntime) {4629 runtimeDirectives.push(prop);4630 if (isSymbol(needRuntime)) {4631 directiveImportMap.set(prop, needRuntime);4632 }4633 }4634 }4635 else if (!isBuiltInDirective(name)) {4636 // no built-in transform, this is a user custom directive.4637 runtimeDirectives.push(prop);4638 // custom dirs may use beforeUpdate so they need to force blocks4639 // to ensure before-update gets called before children update4640 if (hasChildren) {4641 shouldUseBlock = true;4642 }4643 }4644 }4645 }4646 let propsExpression = undefined;4647 // has v-bind="object" or v-on="object", wrap with mergeProps4648 if (mergeArgs.length) {4649 if (properties.length) {4650 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));4651 }4652 if (mergeArgs.length > 1) {4653 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);4654 }4655 else {4656 // single v-bind with nothing else - no need for a mergeProps call4657 propsExpression = mergeArgs[0];4658 }4659 }4660 else if (properties.length) {4661 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);4662 }4663 // patchFlag analysis4664 if (hasDynamicKeys) {4665 patchFlag |= 16 /* FULL_PROPS */;4666 }4667 else {4668 if (hasClassBinding && !isComponent) {4669 patchFlag |= 2 /* CLASS */;4670 }4671 if (hasStyleBinding && !isComponent) {4672 patchFlag |= 4 /* STYLE */;4673 }4674 if (dynamicPropNames.length) {4675 patchFlag |= 8 /* PROPS */;4676 }4677 if (hasHydrationEventBinding) {4678 patchFlag |= 32 /* HYDRATE_EVENTS */;4679 }4680 }4681 if (!shouldUseBlock &&4682 (patchFlag === 0 || patchFlag === 32 /* HYDRATE_EVENTS */) &&4683 (hasRef || hasVnodeHook || runtimeDirectives.length > 0)) {4684 patchFlag |= 512 /* NEED_PATCH */;4685 }4686 // pre-normalize props, SSR is skipped for now4687 if (!context.inSSR && propsExpression) {4688 switch (propsExpression.type) {4689 case 15 /* JS_OBJECT_EXPRESSION */:4690 // means that there is no v-bind,4691 // but still need to deal with dynamic key binding4692 let classKeyIndex = -1;4693 let styleKeyIndex = -1;4694 let hasDynamicKey = false;4695 for (let i = 0; i < propsExpression.properties.length; i++) {4696 const key = propsExpression.properties[i].key;4697 if (isStaticExp(key)) {4698 if (key.content === 'class') {4699 classKeyIndex = i;4700 }4701 else if (key.content === 'style') {4702 styleKeyIndex = i;4703 }4704 }4705 else if (!key.isHandlerKey) {4706 hasDynamicKey = true;4707 }4708 }4709 const classProp = propsExpression.properties[classKeyIndex];4710 const styleProp = propsExpression.properties[styleKeyIndex];4711 // no dynamic key4712 if (!hasDynamicKey) {4713 if (classProp && !isStaticExp(classProp.value)) {4714 classProp.value = createCallExpression(context.helper(NORMALIZE_CLASS), [classProp.value]);4715 }4716 if (styleProp &&4717 !isStaticExp(styleProp.value) &&4718 // the static style is compiled into an object,4719 // so use `hasStyleBinding` to ensure that it is a dynamic style binding4720 (hasStyleBinding ||4721 // v-bind:style and style both exist,4722 // v-bind:style with static literal object4723 styleProp.value.type === 17 /* JS_ARRAY_EXPRESSION */)) {4724 styleProp.value = createCallExpression(context.helper(NORMALIZE_STYLE), [styleProp.value]);4725 }4726 }4727 else {4728 // dynamic key binding, wrap with `normalizeProps`4729 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [propsExpression]);4730 }4731 break;4732 case 14 /* JS_CALL_EXPRESSION */:4733 // mergeProps call, do nothing4734 break;4735 default:4736 // single v-bind4737 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [4738 createCallExpression(context.helper(GUARD_REACTIVE_PROPS), [4739 propsExpression4740 ])4741 ]);4742 break;4743 }4744 }4745 return {4746 props: propsExpression,4747 directives: runtimeDirectives,4748 patchFlag,4749 dynamicPropNames,4750 shouldUseBlock4751 };4752}4753// Dedupe props in an object literal.4754// Literal duplicated attributes would have been warned during the parse phase,4755// however, it's possible to encounter duplicated `onXXX` handlers with different4756// modifiers. We also need to merge static and dynamic class / style attributes.4757// - onXXX handlers / style: merge into array4758// - class: merge into single expression with concatenation4759function dedupeProperties(properties) {4760 const knownProps = new Map();4761 const deduped = [];4762 for (let i = 0; i < properties.length; i++) {4763 const prop = properties[i];4764 // dynamic keys are always allowed4765 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {4766 deduped.push(prop);4767 continue;4768 }4769 const name = prop.key.content;4770 const existing = knownProps.get(name);4771 if (existing) {4772 if (name === 'style' || name === 'class' || isOn(name)) {4773 mergeAsArray(existing, prop);4774 }4775 // unexpected duplicate, should have emitted error during parse4776 }4777 else {4778 knownProps.set(name, prop);4779 deduped.push(prop);4780 }4781 }4782 return deduped;4783}4784function mergeAsArray(existing, incoming) {4785 if (existing.value.type === 17 /* JS_ARRAY_EXPRESSION */) {4786 existing.value.elements.push(incoming.value);4787 }4788 else {4789 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);4790 }4791}4792function buildDirectiveArgs(dir, context) {4793 const dirArgs = [];4794 const runtime = directiveImportMap.get(dir);4795 if (runtime) {4796 // built-in directive with runtime4797 dirArgs.push(context.helperString(runtime));4798 }4799 else {4800 {4801 // inject statement for resolving directive4802 context.helper(RESOLVE_DIRECTIVE);4803 context.directives.add(dir.name);4804 dirArgs.push(toValidAssetId(dir.name, `directive`));4805 }4806 }4807 const { loc } = dir;4808 if (dir.exp)4809 dirArgs.push(dir.exp);4810 if (dir.arg) {4811 if (!dir.exp) {4812 dirArgs.push(`void 0`);4813 }4814 dirArgs.push(dir.arg);4815 }4816 if (Object.keys(dir.modifiers).length) {4817 if (!dir.arg) {4818 if (!dir.exp) {4819 dirArgs.push(`void 0`);4820 }4821 dirArgs.push(`void 0`);4822 }4823 const trueExpression = createSimpleExpression(`true`, false, loc);4824 dirArgs.push(createObjectExpression(dir.modifiers.map(modifier => createObjectProperty(modifier, trueExpression)), loc));4825 }4826 return createArrayExpression(dirArgs, dir.loc);4827}4828function stringifyDynamicPropNames(props) {4829 let propsNamesString = `[`;4830 for (let i = 0, l = props.length; i < l; i++) {4831 propsNamesString += JSON.stringify(props[i]);4832 if (i < l - 1)4833 propsNamesString += ', ';4834 }4835 return propsNamesString + `]`;4836}4837function isComponentTag(tag) {4838 return tag === 'component' || tag === 'Component';4839}4840(process.env.NODE_ENV !== 'production')4841 ? Object.freeze({})4842 : {};4843(process.env.NODE_ENV !== 'production') ? Object.freeze([]) : [];4844const cacheStringFunction = (fn) => {4845 const cache = Object.create(null);4846 return ((str) => {4847 const hit = cache[str];4848 return hit || (cache[str] = fn(str));4849 });4850};4851const camelizeRE = /-(\w)/g;4852/**4853 * @private4854 */4855const camelize = cacheStringFunction((str) => {4856 return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));4857});4858const transformSlotOutlet = (node, context) => {4859 if (isSlotOutlet(node)) {4860 const { children, loc } = node;4861 const { slotName, slotProps } = processSlotOutlet(node, context);4862 const slotArgs = [4863 context.prefixIdentifiers ? `_ctx.$slots` : `$slots`,4864 slotName,4865 '{}',4866 'undefined',4867 'true'4868 ];4869 let expectedLen = 2;4870 if (slotProps) {4871 slotArgs[2] = slotProps;4872 expectedLen = 3;4873 }4874 if (children.length) {4875 slotArgs[3] = createFunctionExpression([], children, false, false, loc);4876 expectedLen = 4;4877 }4878 if (context.scopeId && !context.slotted) {4879 expectedLen = 5;4880 }4881 slotArgs.splice(expectedLen); // remove unused arguments4882 node.codegenNode = createCallExpression(context.helper(RENDER_SLOT), slotArgs, loc);4883 }4884};4885function processSlotOutlet(node, context) {4886 let slotName = `"default"`;4887 let slotProps = undefined;4888 const nonNameProps = [];4889 for (let i = 0; i < node.props.length; i++) {4890 const p = node.props[i];4891 if (p.type === 6 /* ATTRIBUTE */) {4892 if (p.value) {4893 if (p.name === 'name') {4894 slotName = JSON.stringify(p.value.content);4895 }4896 else {4897 p.name = camelize(p.name);4898 nonNameProps.push(p);4899 }4900 }4901 }4902 else {4903 if (p.name === 'bind' && isStaticArgOf(p.arg, 'name')) {4904 if (p.exp)4905 slotName = p.exp;4906 }4907 else {4908 if (p.name === 'bind' && p.arg && isStaticExp(p.arg)) {4909 p.arg.content = camelize(p.arg.content);4910 }4911 nonNameProps.push(p);4912 }4913 }4914 }4915 if (nonNameProps.length > 0) {4916 const { props, directives } = buildProps(node, context, nonNameProps);4917 slotProps = props;4918 if (directives.length) {4919 context.onError(createCompilerError(36 /* X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET */, directives[0].loc));4920 }4921 }4922 return {4923 slotName,4924 slotProps4925 };4926}4927const fnExpRE = /^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/;4928const transformOn = (dir, node, context, augmentor) => {4929 const { loc, modifiers, arg } = dir;4930 if (!dir.exp && !modifiers.length) {4931 context.onError(createCompilerError(35 /* X_V_ON_NO_EXPRESSION */, loc));4932 }4933 let eventName;4934 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4935 if (arg.isStatic) {4936 let rawName = arg.content;4937 // TODO deprecate @vnodeXXX usage4938 if (rawName.startsWith('vue:')) {4939 rawName = `vnode-${rawName.slice(4)}`;4940 }4941 // for all event listeners, auto convert it to camelCase. See issue #22494942 eventName = createSimpleExpression(toHandlerKey(camelize$1(rawName)), true, arg.loc);4943 }4944 else {4945 // #23884946 eventName = createCompoundExpression([4947 `${context.helperString(TO_HANDLER_KEY)}(`,4948 arg,4949 `)`4950 ]);4951 }4952 }4953 else {4954 // already a compound expression.4955 eventName = arg;4956 eventName.children.unshift(`${context.helperString(TO_HANDLER_KEY)}(`);4957 eventName.children.push(`)`);4958 }4959 // handler processing4960 let exp = dir.exp;4961 if (exp && !exp.content.trim()) {4962 exp = undefined;4963 }4964 let shouldCache = context.cacheHandlers && !exp && !context.inVOnce;4965 if (exp) {4966 const isMemberExp = isMemberExpression(exp.content);4967 const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content));4968 const hasMultipleStatements = exp.content.includes(`;`);4969 if ((process.env.NODE_ENV !== 'production') && true) {4970 validateBrowserExpression(exp, context, false, hasMultipleStatements);4971 }4972 if (isInlineStatement || (shouldCache && isMemberExp)) {4973 // wrap inline statement in a function expression4974 exp = createCompoundExpression([4975 `${isInlineStatement4976 ? `$event`4977 : `${``}(...args)`} => ${hasMultipleStatements ? `{` : `(`}`,4978 exp,4979 hasMultipleStatements ? `}` : `)`4980 ]);4981 }4982 }4983 let ret = {4984 props: [4985 createObjectProperty(eventName, exp || createSimpleExpression(`() => {}`, false, loc))4986 ]4987 };4988 // apply extended compiler augmentor4989 if (augmentor) {4990 ret = augmentor(ret);4991 }4992 if (shouldCache) {4993 // cache handlers so that it's always the same handler being passed down.4994 // this avoids unnecessary re-renders when users use inline handlers on4995 // components.4996 ret.props[0].value = context.cache(ret.props[0].value);4997 }4998 // mark the key as handler for props normalization check4999 ret.props.forEach(p => (p.key.isHandlerKey = true));5000 return ret;5001};5002// v-bind without arg is handled directly in ./transformElements.ts due to it affecting5003// codegen for the entire props object. This transform here is only for v-bind5004// *with* args.5005const transformBind = (dir, _node, context) => {5006 const { exp, modifiers, loc } = dir;5007 const arg = dir.arg;5008 if (arg.type !== 4 /* SIMPLE_EXPRESSION */) {5009 arg.children.unshift(`(`);5010 arg.children.push(`) || ""`);5011 }5012 else if (!arg.isStatic) {5013 arg.content = `${arg.content} || ""`;5014 }5015 // .sync is replaced by v-model:arg5016 if (modifiers.includes('camel')) {5017 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {5018 if (arg.isStatic) {5019 arg.content = camelize$1(arg.content);5020 }5021 else {5022 arg.content = `${context.helperString(CAMELIZE)}(${arg.content})`;5023 }5024 }5025 else {5026 arg.children.unshift(`${context.helperString(CAMELIZE)}(`);5027 arg.children.push(`)`);5028 }5029 }5030 if (!context.inSSR) {5031 if (modifiers.includes('prop')) {5032 injectPrefix(arg, '.');5033 }5034 if (modifiers.includes('attr')) {5035 injectPrefix(arg, '^');5036 }5037 }5038 if (!exp ||5039 (exp.type === 4 /* SIMPLE_EXPRESSION */ && !exp.content.trim())) {5040 context.onError(createCompilerError(34 /* X_V_BIND_NO_EXPRESSION */, loc));5041 return {5042 props: [createObjectProperty(arg, createSimpleExpression('', true, loc))]5043 };5044 }5045 return {5046 props: [createObjectProperty(arg, exp)]5047 };5048};5049const injectPrefix = (arg, prefix) => {5050 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {5051 if (arg.isStatic) {5052 arg.content = prefix + arg.content;5053 }5054 else {5055 arg.content = `\`${prefix}\${${arg.content}}\``;5056 }5057 }5058 else {5059 arg.children.unshift(`'${prefix}' + (`);5060 arg.children.push(`)`);5061 }5062};5063// Merge adjacent text nodes and expressions into a single expression5064// e.g. <div>abc {{ d }} {{ e }}</div> should have a single expression node as child.5065const transformText = (node, context) => {5066 if (node.type === 0 /* ROOT */ ||5067 node.type === 1 /* ELEMENT */ ||5068 node.type === 11 /* FOR */ ||5069 node.type === 10 /* IF_BRANCH */) {5070 // perform the transform on node exit so that all expressions have already5071 // been processed.5072 return () => {5073 const children = node.children;5074 let currentContainer = undefined;5075 let hasText = false;5076 for (let i = 0; i < children.length; i++) {5077 const child = children[i];5078 if (isText(child)) {5079 hasText = true;5080 for (let j = i + 1; j < children.length; j++) {5081 const next = children[j];5082 if (isText(next)) {5083 if (!currentContainer) {5084 currentContainer = children[i] = {5085 type: 8 /* COMPOUND_EXPRESSION */,5086 loc: child.loc,5087 children: [child]5088 };5089 }5090 // merge adjacent text node into current5091 currentContainer.children.push(` + `, next);5092 children.splice(j, 1);5093 j--;5094 }5095 else {5096 currentContainer = undefined;5097 break;5098 }5099 }5100 }5101 }5102 if (!hasText ||5103 // if this is a plain element with a single text child, leave it5104 // as-is since the runtime has dedicated fast path for this by directly5105 // setting textContent of the element.5106 // for component root it's always normalized anyway.5107 (children.length === 1 &&5108 (node.type === 0 /* ROOT */ ||5109 (node.type === 1 /* ELEMENT */ &&5110 node.tagType === 0 /* ELEMENT */ &&5111 // #37565112 // custom directives can potentially add DOM elements arbitrarily,5113 // we need to avoid setting textContent of the element at runtime5114 // to avoid accidentally overwriting the DOM elements added5115 // by the user through custom directives.5116 !node.props.find(p => p.type === 7 /* DIRECTIVE */ &&5117 !context.directiveTransforms[p.name]) &&5118 // in compat mode, <template> tags with no special directives5119 // will be rendered as a fragment so its children must be5120 // converted into vnodes.5121 !(node.tag === 'template'))))) {5122 return;5123 }5124 // pre-convert text nodes into createTextVNode(text) calls to avoid5125 // runtime normalization.5126 for (let i = 0; i < children.length; i++) {5127 const child = children[i];5128 if (isText(child) || child.type === 8 /* COMPOUND_EXPRESSION */) {5129 const callArgs = [];5130 // createTextVNode defaults to single whitespace, so if it is a5131 // single space the code could be an empty call to save bytes.5132 if (child.type !== 2 /* TEXT */ || child.content !== ' ') {5133 callArgs.push(child);5134 }5135 // mark dynamic text with flag so it gets patched inside a block5136 if (!context.ssr &&5137 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {5138 callArgs.push(1 /* TEXT */ +5139 ((process.env.NODE_ENV !== 'production') ? ` /* ${PatchFlagNames[1 /* TEXT */]} */` : ``));5140 }5141 children[i] = {5142 type: 12 /* TEXT_CALL */,5143 content: child,5144 loc: child.loc,5145 codegenNode: createCallExpression(context.helper(CREATE_TEXT), callArgs)5146 };5147 }5148 }5149 };5150 }5151};5152const seen = new WeakSet();5153const transformOnce = (node, context) => {5154 if (node.type === 1 /* ELEMENT */ && findDir(node, 'once', true)) {5155 if (seen.has(node) || context.inVOnce) {5156 return;5157 }5158 seen.add(node);5159 context.inVOnce = true;5160 context.helper(SET_BLOCK_TRACKING);5161 return () => {5162 context.inVOnce = false;5163 const cur = context.currentNode;5164 if (cur.codegenNode) {5165 cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */);5166 }5167 };5168 }5169};5170const transformModel = (dir, node, context) => {5171 const { exp, arg } = dir;5172 if (!exp) {5173 context.onError(createCompilerError(41 /* X_V_MODEL_NO_EXPRESSION */, dir.loc));5174 return createTransformProps();5175 }5176 const rawExp = exp.loc.source;5177 const expString = exp.type === 4 /* SIMPLE_EXPRESSION */ ? exp.content : rawExp;5178 const maybeRef = !true /* SETUP_CONST */;5179 if (!expString.trim() ||5180 (!isMemberExpression(expString) && !maybeRef)) {5181 context.onError(createCompilerError(42 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));5182 return createTransformProps();5183 }5184 const propName = arg ? arg : createSimpleExpression('modelValue', true);5185 const eventName = arg5186 ? isStaticExp(arg)5187 ? `onUpdate:${arg.content}`5188 : createCompoundExpression(['"onUpdate:" + ', arg])5189 : `onUpdate:modelValue`;5190 let assignmentExp;5191 const eventArg = context.isTS ? `($event: any)` : `$event`;5192 {5193 assignmentExp = createCompoundExpression([5194 `${eventArg} => ((`,5195 exp,5196 `) = $event)`5197 ]);5198 }5199 const props = [5200 // modelValue: foo5201 createObjectProperty(propName, dir.exp),5202 // "onUpdate:modelValue": $event => (foo = $event)5203 createObjectProperty(eventName, assignmentExp)5204 ];5205 // modelModifiers: { foo: true, "bar-baz": true }5206 if (dir.modifiers.length && node.tagType === 1 /* COMPONENT */) {5207 const modifiers = dir.modifiers5208 .map(m => (isSimpleIdentifier(m) ? m : JSON.stringify(m)) + `: true`)5209 .join(`, `);5210 const modifiersKey = arg5211 ? isStaticExp(arg)5212 ? `${arg.content}Modifiers`5213 : createCompoundExpression([arg, ' + "Modifiers"'])5214 : `modelModifiers`;5215 props.push(createObjectProperty(modifiersKey, createSimpleExpression(`{ ${modifiers} }`, false, dir.loc, 2 /* CAN_HOIST */)));5216 }5217 return createTransformProps(props);5218};5219function createTransformProps(props = []) {5220 return { props };5221}5222const validDivisionCharRE = /[\w).+\-_$\]]/;5223const transformFilter = (node, context) => {5224 if (!isCompatEnabled("COMPILER_FILTER" /* COMPILER_FILTERS */, context)) {5225 return;5226 }5227 if (node.type === 5 /* INTERPOLATION */) {5228 // filter rewrite is applied before expression transform so only5229 // simple expressions are possible at this stage5230 rewriteFilter(node.content, context);5231 }5232 if (node.type === 1 /* ELEMENT */) {5233 node.props.forEach((prop) => {5234 if (prop.type === 7 /* DIRECTIVE */ &&5235 prop.name !== 'for' &&5236 prop.exp) {5237 rewriteFilter(prop.exp, context);5238 }...
compiler-dom.global.js
Source:compiler-dom.global.js
...941 else {942 return value;943 }944 }945 function isCompatEnabled(key, context) {946 const mode = getCompatValue('MODE', context);947 const value = getCompatValue(key, context);948 // in v3 mode, only enable if explicitly set to true949 // otherwise enable for any non-false value950 return mode === 3 ? value === true : value !== false;951 }952 function checkCompatEnabled(key, context, loc, ...args) {953 const enabled = isCompatEnabled(key, context);954 if (enabled) {955 warnDeprecation(key, context, loc, ...args);956 }957 return enabled;958 }959 function warnDeprecation(key, context, loc, ...args) {960 const val = getCompatValue(key, context);961 if (val === 'suppress-warning') {962 return;963 }964 const { message, link } = deprecationData[key];965 const msg = `(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`;966 const err = new SyntaxError(msg);967 err.code = key;968 if (loc)969 err.loc = loc;970 context.onWarn(err);971 }972 // The default decoder only provides escapes for characters reserved as part of973 // the template syntax, and is only used if the custom renderer did not provide974 // a platform-specific decoder.975 const decodeRE = /&(gt|lt|amp|apos|quot);/g;976 const decodeMap = {977 gt: '>',978 lt: '<',979 amp: '&',980 apos: "'",981 quot: '"'982 };983 const defaultParserOptions = {984 delimiters: [`{{`, `}}`],985 getNamespace: () => 0 /* HTML */,986 getTextMode: () => 0 /* DATA */,987 isVoidTag: NO,988 isPreTag: NO,989 isCustomElement: NO,990 decodeEntities: (rawText) => rawText.replace(decodeRE, (_, p1) => decodeMap[p1]),991 onError: defaultOnError,992 onWarn: defaultOnWarn,993 comments: true994 };995 function baseParse(content, options = {}) {996 const context = createParserContext(content, options);997 const start = getCursor(context);998 return createRoot(parseChildren(context, 0 /* DATA */, []), getSelection(context, start));999 }1000 function createParserContext(content, rawOptions) {1001 const options = extend({}, defaultParserOptions);1002 let key;1003 for (key in rawOptions) {1004 // @ts-ignore1005 options[key] =1006 rawOptions[key] === undefined1007 ? defaultParserOptions[key]1008 : rawOptions[key];1009 }1010 return {1011 options,1012 column: 1,1013 line: 1,1014 offset: 0,1015 originalSource: content,1016 source: content,1017 inPre: false,1018 inVPre: false,1019 onWarn: options.onWarn1020 };1021 }1022 function parseChildren(context, mode, ancestors) {1023 const parent = last(ancestors);1024 const ns = parent ? parent.ns : 0 /* HTML */;1025 const nodes = [];1026 while (!isEnd(context, mode, ancestors)) {1027 const s = context.source;1028 let node = undefined;1029 if (mode === 0 /* DATA */ || mode === 1 /* RCDATA */) {1030 if (!context.inVPre && startsWith(s, context.options.delimiters[0])) {1031 // '{{'1032 node = parseInterpolation(context, mode);1033 }1034 else if (mode === 0 /* DATA */ && s[0] === '<') {1035 // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state1036 if (s.length === 1) {1037 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 1);1038 }1039 else if (s[1] === '!') {1040 // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state1041 if (startsWith(s, '<!--')) {1042 node = parseComment(context);1043 }1044 else if (startsWith(s, '<!DOCTYPE')) {1045 // Ignore DOCTYPE by a limitation.1046 node = parseBogusComment(context);1047 }1048 else if (startsWith(s, '<![CDATA[')) {1049 if (ns !== 0 /* HTML */) {1050 node = parseCDATA(context, ancestors);1051 }1052 else {1053 emitError(context, 1 /* CDATA_IN_HTML_CONTENT */);1054 node = parseBogusComment(context);1055 }1056 }1057 else {1058 emitError(context, 11 /* INCORRECTLY_OPENED_COMMENT */);1059 node = parseBogusComment(context);1060 }1061 }1062 else if (s[1] === '/') {1063 // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state1064 if (s.length === 2) {1065 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 2);1066 }1067 else if (s[2] === '>') {1068 emitError(context, 14 /* MISSING_END_TAG_NAME */, 2);1069 advanceBy(context, 3);1070 continue;1071 }1072 else if (/[a-z]/i.test(s[2])) {1073 emitError(context, 23 /* X_INVALID_END_TAG */);1074 parseTag(context, 1 /* End */, parent);1075 continue;1076 }1077 else {1078 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 2);1079 node = parseBogusComment(context);1080 }1081 }1082 else if (/[a-z]/i.test(s[1])) {1083 node = parseElement(context, ancestors);1084 // 2.x <template> with no directive compat1085 if (isCompatEnabled("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context) &&1086 node &&1087 node.tag === 'template' &&1088 !node.props.some(p => p.type === 7 /* DIRECTIVE */ &&1089 isSpecialTemplateDirective(p.name))) {1090 warnDeprecation("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context, node.loc);1091 node = node.children;1092 }1093 }1094 else if (s[1] === '?') {1095 emitError(context, 21 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */, 1);1096 node = parseBogusComment(context);1097 }1098 else {1099 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 1);1100 }1101 }1102 }1103 if (!node) {1104 node = parseText(context, mode);1105 }1106 if (isArray(node)) {1107 for (let i = 0; i < node.length; i++) {1108 pushNode(nodes, node[i]);1109 }1110 }1111 else {1112 pushNode(nodes, node);1113 }1114 }1115 // Whitespace handling strategy like v21116 let removedWhitespace = false;1117 if (mode !== 2 /* RAWTEXT */ && mode !== 1 /* RCDATA */) {1118 const shouldCondense = context.options.whitespace !== 'preserve';1119 for (let i = 0; i < nodes.length; i++) {1120 const node = nodes[i];1121 if (!context.inPre && node.type === 2 /* TEXT */) {1122 if (!/[^\t\r\n\f ]/.test(node.content)) {1123 const prev = nodes[i - 1];1124 const next = nodes[i + 1];1125 // Remove if:1126 // - the whitespace is the first or last node, or:1127 // - (condense mode) the whitespace is adjacent to a comment, or:1128 // - (condense mode) the whitespace is between two elements AND contains newline1129 if (!prev ||1130 !next ||1131 (shouldCondense &&1132 (prev.type === 3 /* COMMENT */ ||1133 next.type === 3 /* COMMENT */ ||1134 (prev.type === 1 /* ELEMENT */ &&1135 next.type === 1 /* ELEMENT */ &&1136 /[\r\n]/.test(node.content))))) {1137 removedWhitespace = true;1138 nodes[i] = null;1139 }1140 else {1141 // Otherwise, the whitespace is condensed into a single space1142 node.content = ' ';1143 }1144 }1145 else if (shouldCondense) {1146 // in condense mode, consecutive whitespaces in text are condensed1147 // down to a single space.1148 node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ');1149 }1150 }1151 // Remove comment nodes if desired by configuration.1152 else if (node.type === 3 /* COMMENT */ && !context.options.comments) {1153 removedWhitespace = true;1154 nodes[i] = null;1155 }1156 }1157 if (context.inPre && parent && context.options.isPreTag(parent.tag)) {1158 // remove leading newline per html spec1159 // https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element1160 const first = nodes[0];1161 if (first && first.type === 2 /* TEXT */) {1162 first.content = first.content.replace(/^\r?\n/, '');1163 }1164 }1165 }1166 return removedWhitespace ? nodes.filter(Boolean) : nodes;1167 }1168 function pushNode(nodes, node) {1169 if (node.type === 2 /* TEXT */) {1170 const prev = last(nodes);1171 // Merge if both this and the previous node are text and those are1172 // consecutive. This happens for cases like "a < b".1173 if (prev &&1174 prev.type === 2 /* TEXT */ &&1175 prev.loc.end.offset === node.loc.start.offset) {1176 prev.content += node.content;1177 prev.loc.end = node.loc.end;1178 prev.loc.source += node.loc.source;1179 return;1180 }1181 }1182 nodes.push(node);1183 }1184 function parseCDATA(context, ancestors) {1185 advanceBy(context, 9);1186 const nodes = parseChildren(context, 3 /* CDATA */, ancestors);1187 if (context.source.length === 0) {1188 emitError(context, 6 /* EOF_IN_CDATA */);1189 }1190 else {1191 advanceBy(context, 3);1192 }1193 return nodes;1194 }1195 function parseComment(context) {1196 const start = getCursor(context);1197 let content;1198 // Regular comment.1199 const match = /--(\!)?>/.exec(context.source);1200 if (!match) {1201 content = context.source.slice(4);1202 advanceBy(context, context.source.length);1203 emitError(context, 7 /* EOF_IN_COMMENT */);1204 }1205 else {1206 if (match.index <= 3) {1207 emitError(context, 0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */);1208 }1209 if (match[1]) {1210 emitError(context, 10 /* INCORRECTLY_CLOSED_COMMENT */);1211 }1212 content = context.source.slice(4, match.index);1213 // Advancing with reporting nested comments.1214 const s = context.source.slice(0, match.index);1215 let prevIndex = 1, nestedIndex = 0;1216 while ((nestedIndex = s.indexOf('<!--', prevIndex)) !== -1) {1217 advanceBy(context, nestedIndex - prevIndex + 1);1218 if (nestedIndex + 4 < s.length) {1219 emitError(context, 16 /* NESTED_COMMENT */);1220 }1221 prevIndex = nestedIndex + 1;1222 }1223 advanceBy(context, match.index + match[0].length - prevIndex + 1);1224 }1225 return {1226 type: 3 /* COMMENT */,1227 content,1228 loc: getSelection(context, start)1229 };1230 }1231 function parseBogusComment(context) {1232 const start = getCursor(context);1233 const contentStart = context.source[1] === '?' ? 1 : 2;1234 let content;1235 const closeIndex = context.source.indexOf('>');1236 if (closeIndex === -1) {1237 content = context.source.slice(contentStart);1238 advanceBy(context, context.source.length);1239 }1240 else {1241 content = context.source.slice(contentStart, closeIndex);1242 advanceBy(context, closeIndex + 1);1243 }1244 return {1245 type: 3 /* COMMENT */,1246 content,1247 loc: getSelection(context, start)1248 };1249 }1250 function parseElement(context, ancestors) {1251 // Start tag.1252 const wasInPre = context.inPre;1253 const wasInVPre = context.inVPre;1254 const parent = last(ancestors);1255 const element = parseTag(context, 0 /* Start */, parent);1256 const isPreBoundary = context.inPre && !wasInPre;1257 const isVPreBoundary = context.inVPre && !wasInVPre;1258 if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {1259 // #4030 self-closing <pre> tag1260 if (isPreBoundary) {1261 context.inPre = false;1262 }1263 if (isVPreBoundary) {1264 context.inVPre = false;1265 }1266 return element;1267 }1268 // Children.1269 ancestors.push(element);1270 const mode = context.options.getTextMode(element, parent);1271 const children = parseChildren(context, mode, ancestors);1272 ancestors.pop();1273 // 2.x inline-template compat1274 {1275 const inlineTemplateProp = element.props.find(p => p.type === 6 /* ATTRIBUTE */ && p.name === 'inline-template');1276 if (inlineTemplateProp &&1277 checkCompatEnabled("COMPILER_INLINE_TEMPLATE" /* COMPILER_INLINE_TEMPLATE */, context, inlineTemplateProp.loc)) {1278 const loc = getSelection(context, element.loc.end);1279 inlineTemplateProp.value = {1280 type: 2 /* TEXT */,1281 content: loc.source,1282 loc1283 };1284 }1285 }1286 element.children = children;1287 // End tag.1288 if (startsWithEndTagOpen(context.source, element.tag)) {1289 parseTag(context, 1 /* End */, parent);1290 }1291 else {1292 emitError(context, 24 /* X_MISSING_END_TAG */, 0, element.loc.start);1293 if (context.source.length === 0 && element.tag.toLowerCase() === 'script') {1294 const first = children[0];1295 if (first && startsWith(first.loc.source, '<!--')) {1296 emitError(context, 8 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */);1297 }1298 }1299 }1300 element.loc = getSelection(context, element.loc.start);1301 if (isPreBoundary) {1302 context.inPre = false;1303 }1304 if (isVPreBoundary) {1305 context.inVPre = false;1306 }1307 return element;1308 }1309 const isSpecialTemplateDirective = /*#__PURE__*/ makeMap(`if,else,else-if,for,slot`);1310 function parseTag(context, type, parent) {1311 // Tag open.1312 const start = getCursor(context);1313 const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source);1314 const tag = match[1];1315 const ns = context.options.getNamespace(tag, parent);1316 advanceBy(context, match[0].length);1317 advanceSpaces(context);1318 // save current state in case we need to re-parse attributes with v-pre1319 const cursor = getCursor(context);1320 const currentSource = context.source;1321 // check <pre> tag1322 if (context.options.isPreTag(tag)) {1323 context.inPre = true;1324 }1325 // Attributes.1326 let props = parseAttributes(context, type);1327 // check v-pre1328 if (type === 0 /* Start */ &&1329 !context.inVPre &&1330 props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'pre')) {1331 context.inVPre = true;1332 // reset context1333 extend(context, cursor);1334 context.source = currentSource;1335 // re-parse attrs and filter out v-pre itself1336 props = parseAttributes(context, type).filter(p => p.name !== 'v-pre');1337 }1338 // Tag close.1339 let isSelfClosing = false;1340 if (context.source.length === 0) {1341 emitError(context, 9 /* EOF_IN_TAG */);1342 }1343 else {1344 isSelfClosing = startsWith(context.source, '/>');1345 if (type === 1 /* End */ && isSelfClosing) {1346 emitError(context, 4 /* END_TAG_WITH_TRAILING_SOLIDUS */);1347 }1348 advanceBy(context, isSelfClosing ? 2 : 1);1349 }1350 if (type === 1 /* End */) {1351 return;1352 }1353 // 2.x deprecation checks1354 if (isCompatEnabled("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context)) {1355 let hasIf = false;1356 let hasFor = false;1357 for (let i = 0; i < props.length; i++) {1358 const p = props[i];1359 if (p.type === 7 /* DIRECTIVE */) {1360 if (p.name === 'if') {1361 hasIf = true;1362 }1363 else if (p.name === 'for') {1364 hasFor = true;1365 }1366 }1367 if (hasIf && hasFor) {1368 warnDeprecation("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context, getSelection(context, start));1369 break;1370 }1371 }1372 }1373 let tagType = 0 /* ELEMENT */;1374 if (!context.inVPre) {1375 if (tag === 'slot') {1376 tagType = 2 /* SLOT */;1377 }1378 else if (tag === 'template') {1379 if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {1380 tagType = 3 /* TEMPLATE */;1381 }1382 }1383 else if (isComponent(tag, props, context)) {1384 tagType = 1 /* COMPONENT */;1385 }1386 }1387 return {1388 type: 1 /* ELEMENT */,1389 ns,1390 tag,1391 tagType,1392 props,1393 isSelfClosing,1394 children: [],1395 loc: getSelection(context, start),1396 codegenNode: undefined // to be created during transform phase1397 };1398 }1399 function isComponent(tag, props, context) {1400 const options = context.options;1401 if (options.isCustomElement(tag)) {1402 return false;1403 }1404 if (tag === 'component' ||1405 /^[A-Z]/.test(tag) ||1406 isCoreComponent(tag) ||1407 (options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||1408 (options.isNativeTag && !options.isNativeTag(tag))) {1409 return true;1410 }1411 // at this point the tag should be a native tag, but check for potential "is"1412 // casting1413 for (let i = 0; i < props.length; i++) {1414 const p = props[i];1415 if (p.type === 6 /* ATTRIBUTE */) {1416 if (p.name === 'is' && p.value) {1417 if (p.value.content.startsWith('vue:')) {1418 return true;1419 }1420 else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1421 return true;1422 }1423 }1424 }1425 else {1426 // directive1427 // v-is (TODO Deprecate)1428 if (p.name === 'is') {1429 return true;1430 }1431 else if (1432 // :is on plain element - only treat as component in compat mode1433 p.name === 'bind' &&1434 isStaticArgOf(p.arg, 'is') &&1435 true &&1436 checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1437 return true;1438 }1439 }1440 }1441 }1442 function parseAttributes(context, type) {1443 const props = [];1444 const attributeNames = new Set();1445 while (context.source.length > 0 &&1446 !startsWith(context.source, '>') &&1447 !startsWith(context.source, '/>')) {1448 if (startsWith(context.source, '/')) {1449 emitError(context, 22 /* UNEXPECTED_SOLIDUS_IN_TAG */);1450 advanceBy(context, 1);1451 advanceSpaces(context);1452 continue;1453 }1454 if (type === 1 /* End */) {1455 emitError(context, 3 /* END_TAG_WITH_ATTRIBUTES */);1456 }1457 const attr = parseAttribute(context, attributeNames);1458 // Trim whitespace between class1459 // https://github.com/vuejs/vue-next/issues/42511460 if (attr.type === 6 /* ATTRIBUTE */ &&1461 attr.value &&1462 attr.name === 'class') {1463 attr.value.content = attr.value.content.replace(/\s+/g, ' ').trim();1464 }1465 if (type === 0 /* Start */) {1466 props.push(attr);1467 }1468 if (/^[^\t\r\n\f />]/.test(context.source)) {1469 emitError(context, 15 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */);1470 }1471 advanceSpaces(context);1472 }1473 return props;1474 }1475 function parseAttribute(context, nameSet) {1476 // Name.1477 const start = getCursor(context);1478 const match = /^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(context.source);1479 const name = match[0];1480 if (nameSet.has(name)) {1481 emitError(context, 2 /* DUPLICATE_ATTRIBUTE */);1482 }1483 nameSet.add(name);1484 if (name[0] === '=') {1485 emitError(context, 19 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */);1486 }1487 {1488 const pattern = /["'<]/g;1489 let m;1490 while ((m = pattern.exec(name))) {1491 emitError(context, 17 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */, m.index);1492 }1493 }1494 advanceBy(context, name.length);1495 // Value1496 let value = undefined;1497 if (/^[\t\r\n\f ]*=/.test(context.source)) {1498 advanceSpaces(context);1499 advanceBy(context, 1);1500 advanceSpaces(context);1501 value = parseAttributeValue(context);1502 if (!value) {1503 emitError(context, 13 /* MISSING_ATTRIBUTE_VALUE */);1504 }1505 }1506 const loc = getSelection(context, start);1507 if (!context.inVPre && /^(v-[A-Za-z0-9-]|:|\.|@|#)/.test(name)) {1508 const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^\.|^@|^#)(\[[^\]]+\]|[^\.]+))?(.+)?$/i.exec(name);1509 let isPropShorthand = startsWith(name, '.');1510 let dirName = match[1] ||1511 (isPropShorthand || startsWith(name, ':')1512 ? 'bind'1513 : startsWith(name, '@')1514 ? 'on'1515 : 'slot');1516 let arg;1517 if (match[2]) {1518 const isSlot = dirName === 'slot';1519 const startOffset = name.lastIndexOf(match[2]);1520 const loc = getSelection(context, getNewPosition(context, start, startOffset), getNewPosition(context, start, startOffset + match[2].length + ((isSlot && match[3]) || '').length));1521 let content = match[2];1522 let isStatic = true;1523 if (content.startsWith('[')) {1524 isStatic = false;1525 if (!content.endsWith(']')) {1526 emitError(context, 27 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */);1527 content = content.slice(1);1528 }1529 else {1530 content = content.slice(1, content.length - 1);1531 }1532 }1533 else if (isSlot) {1534 // #1241 special case for v-slot: vuetify relies extensively on slot1535 // names containing dots. v-slot doesn't have any modifiers and Vue 2.x1536 // supports such usage so we are keeping it consistent with 2.x.1537 content += match[3] || '';1538 }1539 arg = {1540 type: 4 /* SIMPLE_EXPRESSION */,1541 content,1542 isStatic,1543 constType: isStatic1544 ? 3 /* CAN_STRINGIFY */1545 : 0 /* NOT_CONSTANT */,1546 loc1547 };1548 }1549 if (value && value.isQuoted) {1550 const valueLoc = value.loc;1551 valueLoc.start.offset++;1552 valueLoc.start.column++;1553 valueLoc.end = advancePositionWithClone(valueLoc.start, value.content);1554 valueLoc.source = valueLoc.source.slice(1, -1);1555 }1556 const modifiers = match[3] ? match[3].slice(1).split('.') : [];1557 if (isPropShorthand)1558 modifiers.push('prop');1559 // 2.x compat v-bind:foo.sync -> v-model:foo1560 if (dirName === 'bind' && arg) {1561 if (modifiers.includes('sync') &&1562 checkCompatEnabled("COMPILER_V_BIND_SYNC" /* COMPILER_V_BIND_SYNC */, context, loc, arg.loc.source)) {1563 dirName = 'model';1564 modifiers.splice(modifiers.indexOf('sync'), 1);1565 }1566 if (modifiers.includes('prop')) {1567 checkCompatEnabled("COMPILER_V_BIND_PROP" /* COMPILER_V_BIND_PROP */, context, loc);1568 }1569 }1570 return {1571 type: 7 /* DIRECTIVE */,1572 name: dirName,1573 exp: value && {1574 type: 4 /* SIMPLE_EXPRESSION */,1575 content: value.content,1576 isStatic: false,1577 // Treat as non-constant by default. This can be potentially set to1578 // other values by `transformExpression` to make it eligible for hoisting.1579 constType: 0 /* NOT_CONSTANT */,1580 loc: value.loc1581 },1582 arg,1583 modifiers,1584 loc1585 };1586 }1587 // missing directive name or illegal directive name1588 if (!context.inVPre && startsWith(name, 'v-')) {1589 emitError(context, 26 /* X_MISSING_DIRECTIVE_NAME */);1590 }1591 return {1592 type: 6 /* ATTRIBUTE */,1593 name,1594 value: value && {1595 type: 2 /* TEXT */,1596 content: value.content,1597 loc: value.loc1598 },1599 loc1600 };1601 }1602 function parseAttributeValue(context) {1603 const start = getCursor(context);1604 let content;1605 const quote = context.source[0];1606 const isQuoted = quote === `"` || quote === `'`;1607 if (isQuoted) {1608 // Quoted value.1609 advanceBy(context, 1);1610 const endIndex = context.source.indexOf(quote);1611 if (endIndex === -1) {1612 content = parseTextData(context, context.source.length, 4 /* ATTRIBUTE_VALUE */);1613 }1614 else {1615 content = parseTextData(context, endIndex, 4 /* ATTRIBUTE_VALUE */);1616 advanceBy(context, 1);1617 }1618 }1619 else {1620 // Unquoted1621 const match = /^[^\t\r\n\f >]+/.exec(context.source);1622 if (!match) {1623 return undefined;1624 }1625 const unexpectedChars = /["'<=`]/g;1626 let m;1627 while ((m = unexpectedChars.exec(match[0]))) {1628 emitError(context, 18 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */, m.index);1629 }1630 content = parseTextData(context, match[0].length, 4 /* ATTRIBUTE_VALUE */);1631 }1632 return { content, isQuoted, loc: getSelection(context, start) };1633 }1634 function parseInterpolation(context, mode) {1635 const [open, close] = context.options.delimiters;1636 const closeIndex = context.source.indexOf(close, open.length);1637 if (closeIndex === -1) {1638 emitError(context, 25 /* X_MISSING_INTERPOLATION_END */);1639 return undefined;1640 }1641 const start = getCursor(context);1642 advanceBy(context, open.length);1643 const innerStart = getCursor(context);1644 const innerEnd = getCursor(context);1645 const rawContentLength = closeIndex - open.length;1646 const rawContent = context.source.slice(0, rawContentLength);1647 const preTrimContent = parseTextData(context, rawContentLength, mode);1648 const content = preTrimContent.trim();1649 const startOffset = preTrimContent.indexOf(content);1650 if (startOffset > 0) {1651 advancePositionWithMutation(innerStart, rawContent, startOffset);1652 }1653 const endOffset = rawContentLength - (preTrimContent.length - content.length - startOffset);1654 advancePositionWithMutation(innerEnd, rawContent, endOffset);1655 advanceBy(context, close.length);1656 return {1657 type: 5 /* INTERPOLATION */,1658 content: {1659 type: 4 /* SIMPLE_EXPRESSION */,1660 isStatic: false,1661 // Set `isConstant` to false by default and will decide in transformExpression1662 constType: 0 /* NOT_CONSTANT */,1663 content,1664 loc: getSelection(context, innerStart, innerEnd)1665 },1666 loc: getSelection(context, start)1667 };1668 }1669 function parseText(context, mode) {1670 const endTokens = mode === 3 /* CDATA */ ? [']]>'] : ['<', context.options.delimiters[0]];1671 let endIndex = context.source.length;1672 for (let i = 0; i < endTokens.length; i++) {1673 const index = context.source.indexOf(endTokens[i], 1);1674 if (index !== -1 && endIndex > index) {1675 endIndex = index;1676 }1677 }1678 const start = getCursor(context);1679 const content = parseTextData(context, endIndex, mode);1680 return {1681 type: 2 /* TEXT */,1682 content,1683 loc: getSelection(context, start)1684 };1685 }1686 /**1687 * Get text data with a given length from the current location.1688 * This translates HTML entities in the text data.1689 */1690 function parseTextData(context, length, mode) {1691 const rawText = context.source.slice(0, length);1692 advanceBy(context, length);1693 if (mode === 2 /* RAWTEXT */ ||1694 mode === 3 /* CDATA */ ||1695 rawText.indexOf('&') === -1) {1696 return rawText;1697 }1698 else {1699 // DATA or RCDATA containing "&"". Entity decoding required.1700 return context.options.decodeEntities(rawText, mode === 4 /* ATTRIBUTE_VALUE */);1701 }1702 }1703 function getCursor(context) {1704 const { column, line, offset } = context;1705 return { column, line, offset };1706 }1707 function getSelection(context, start, end) {1708 end = end || getCursor(context);1709 return {1710 start,1711 end,1712 source: context.originalSource.slice(start.offset, end.offset)1713 };1714 }1715 function last(xs) {1716 return xs[xs.length - 1];1717 }1718 function startsWith(source, searchString) {1719 return source.startsWith(searchString);1720 }1721 function advanceBy(context, numberOfCharacters) {1722 const { source } = context;1723 advancePositionWithMutation(context, source, numberOfCharacters);1724 context.source = source.slice(numberOfCharacters);1725 }1726 function advanceSpaces(context) {1727 const match = /^[\t\r\n\f ]+/.exec(context.source);1728 if (match) {1729 advanceBy(context, match[0].length);1730 }1731 }1732 function getNewPosition(context, start, numberOfCharacters) {1733 return advancePositionWithClone(start, context.originalSource.slice(start.offset, numberOfCharacters), numberOfCharacters);1734 }1735 function emitError(context, code, offset, loc = getCursor(context)) {1736 if (offset) {1737 loc.offset += offset;1738 loc.column += offset;1739 }1740 context.options.onError(createCompilerError(code, {1741 start: loc,1742 end: loc,1743 source: ''1744 }));1745 }1746 function isEnd(context, mode, ancestors) {1747 const s = context.source;1748 switch (mode) {1749 case 0 /* DATA */:1750 if (startsWith(s, '</')) {1751 // TODO: probably bad performance1752 for (let i = ancestors.length - 1; i >= 0; --i) {1753 if (startsWithEndTagOpen(s, ancestors[i].tag)) {1754 return true;1755 }1756 }1757 }1758 break;1759 case 1 /* RCDATA */:1760 case 2 /* RAWTEXT */: {1761 const parent = last(ancestors);1762 if (parent && startsWithEndTagOpen(s, parent.tag)) {1763 return true;1764 }1765 break;1766 }1767 case 3 /* CDATA */:1768 if (startsWith(s, ']]>')) {1769 return true;1770 }1771 break;1772 }1773 return !s;1774 }1775 function startsWithEndTagOpen(source, tag) {1776 return (startsWith(source, '</') &&1777 source.slice(2, 2 + tag.length).toLowerCase() === tag.toLowerCase() &&1778 /[\t\r\n\f />]/.test(source[2 + tag.length] || '>'));1779 }1780 function hoistStatic(root, context) {1781 walk(root, context, 1782 // Root node is unfortunately non-hoistable due to potential parent1783 // fallthrough attributes.1784 isSingleElementRoot(root, root.children[0]));1785 }1786 function isSingleElementRoot(root, child) {1787 const { children } = root;1788 return (children.length === 1 &&1789 child.type === 1 /* ELEMENT */ &&1790 !isSlotOutlet(child));1791 }1792 function walk(node, context, doNotHoistNode = false) {1793 const { children } = node;1794 const originalCount = children.length;1795 let hoistedCount = 0;1796 for (let i = 0; i < children.length; i++) {1797 const child = children[i];1798 // only plain elements & text calls are eligible for hoisting.1799 if (child.type === 1 /* ELEMENT */ &&1800 child.tagType === 0 /* ELEMENT */) {1801 const constantType = doNotHoistNode1802 ? 0 /* NOT_CONSTANT */1803 : getConstantType(child, context);1804 if (constantType > 0 /* NOT_CONSTANT */) {1805 if (constantType >= 2 /* CAN_HOIST */) {1806 child.codegenNode.patchFlag =1807 -1 /* HOISTED */ + (` /* HOISTED */` );1808 child.codegenNode = context.hoist(child.codegenNode);1809 hoistedCount++;1810 continue;1811 }1812 }1813 else {1814 // node may contain dynamic children, but its props may be eligible for1815 // hoisting.1816 const codegenNode = child.codegenNode;1817 if (codegenNode.type === 13 /* VNODE_CALL */) {1818 const flag = getPatchFlag(codegenNode);1819 if ((!flag ||1820 flag === 512 /* NEED_PATCH */ ||1821 flag === 1 /* TEXT */) &&1822 getGeneratedPropsConstantType(child, context) >=1823 2 /* CAN_HOIST */) {1824 const props = getNodeProps(child);1825 if (props) {1826 codegenNode.props = context.hoist(props);1827 }1828 }1829 if (codegenNode.dynamicProps) {1830 codegenNode.dynamicProps = context.hoist(codegenNode.dynamicProps);1831 }1832 }1833 }1834 }1835 else if (child.type === 12 /* TEXT_CALL */ &&1836 getConstantType(child.content, context) >= 2 /* CAN_HOIST */) {1837 child.codegenNode = context.hoist(child.codegenNode);1838 hoistedCount++;1839 }1840 // walk further1841 if (child.type === 1 /* ELEMENT */) {1842 const isComponent = child.tagType === 1 /* COMPONENT */;1843 if (isComponent) {1844 context.scopes.vSlot++;1845 }1846 walk(child, context);1847 if (isComponent) {1848 context.scopes.vSlot--;1849 }1850 }1851 else if (child.type === 11 /* FOR */) {1852 // Do not hoist v-for single child because it has to be a block1853 walk(child, context, child.children.length === 1);1854 }1855 else if (child.type === 9 /* IF */) {1856 for (let i = 0; i < child.branches.length; i++) {1857 // Do not hoist v-if single child because it has to be a block1858 walk(child.branches[i], context, child.branches[i].children.length === 1);1859 }1860 }1861 }1862 if (hoistedCount && context.transformHoist) {1863 context.transformHoist(children, context, node);1864 }1865 // all children were hoisted - the entire children array is hoistable.1866 if (hoistedCount &&1867 hoistedCount === originalCount &&1868 node.type === 1 /* ELEMENT */ &&1869 node.tagType === 0 /* ELEMENT */ &&1870 node.codegenNode &&1871 node.codegenNode.type === 13 /* VNODE_CALL */ &&1872 isArray(node.codegenNode.children)) {1873 node.codegenNode.children = context.hoist(createArrayExpression(node.codegenNode.children));1874 }1875 }1876 function getConstantType(node, context) {1877 const { constantCache } = context;1878 switch (node.type) {1879 case 1 /* ELEMENT */:1880 if (node.tagType !== 0 /* ELEMENT */) {1881 return 0 /* NOT_CONSTANT */;1882 }1883 const cached = constantCache.get(node);1884 if (cached !== undefined) {1885 return cached;1886 }1887 const codegenNode = node.codegenNode;1888 if (codegenNode.type !== 13 /* VNODE_CALL */) {1889 return 0 /* NOT_CONSTANT */;1890 }1891 if (codegenNode.isBlock &&1892 node.tag !== 'svg' &&1893 node.tag !== 'foreignObject') {1894 return 0 /* NOT_CONSTANT */;1895 }1896 const flag = getPatchFlag(codegenNode);1897 if (!flag) {1898 let returnType = 3 /* CAN_STRINGIFY */;1899 // Element itself has no patch flag. However we still need to check:1900 // 1. Even for a node with no patch flag, it is possible for it to contain1901 // non-hoistable expressions that refers to scope variables, e.g. compiler1902 // injected keys or cached event handlers. Therefore we need to always1903 // check the codegenNode's props to be sure.1904 const generatedPropsType = getGeneratedPropsConstantType(node, context);1905 if (generatedPropsType === 0 /* NOT_CONSTANT */) {1906 constantCache.set(node, 0 /* NOT_CONSTANT */);1907 return 0 /* NOT_CONSTANT */;1908 }1909 if (generatedPropsType < returnType) {1910 returnType = generatedPropsType;1911 }1912 // 2. its children.1913 for (let i = 0; i < node.children.length; i++) {1914 const childType = getConstantType(node.children[i], context);1915 if (childType === 0 /* NOT_CONSTANT */) {1916 constantCache.set(node, 0 /* NOT_CONSTANT */);1917 return 0 /* NOT_CONSTANT */;1918 }1919 if (childType < returnType) {1920 returnType = childType;1921 }1922 }1923 // 3. if the type is not already CAN_SKIP_PATCH which is the lowest non-01924 // type, check if any of the props can cause the type to be lowered1925 // we can skip can_patch because it's guaranteed by the absence of a1926 // patchFlag.1927 if (returnType > 1 /* CAN_SKIP_PATCH */) {1928 for (let i = 0; i < node.props.length; i++) {1929 const p = node.props[i];1930 if (p.type === 7 /* DIRECTIVE */ && p.name === 'bind' && p.exp) {1931 const expType = getConstantType(p.exp, context);1932 if (expType === 0 /* NOT_CONSTANT */) {1933 constantCache.set(node, 0 /* NOT_CONSTANT */);1934 return 0 /* NOT_CONSTANT */;1935 }1936 if (expType < returnType) {1937 returnType = expType;1938 }1939 }1940 }1941 }1942 // only svg/foreignObject could be block here, however if they are1943 // static then they don't need to be blocks since there will be no1944 // nested updates.1945 if (codegenNode.isBlock) {1946 context.removeHelper(OPEN_BLOCK);1947 context.removeHelper(getVNodeBlockHelper(context.inSSR, codegenNode.isComponent));1948 codegenNode.isBlock = false;1949 context.helper(getVNodeHelper(context.inSSR, codegenNode.isComponent));1950 }1951 constantCache.set(node, returnType);1952 return returnType;1953 }1954 else {1955 constantCache.set(node, 0 /* NOT_CONSTANT */);1956 return 0 /* NOT_CONSTANT */;1957 }1958 case 2 /* TEXT */:1959 case 3 /* COMMENT */:1960 return 3 /* CAN_STRINGIFY */;1961 case 9 /* IF */:1962 case 11 /* FOR */:1963 case 10 /* IF_BRANCH */:1964 return 0 /* NOT_CONSTANT */;1965 case 5 /* INTERPOLATION */:1966 case 12 /* TEXT_CALL */:1967 return getConstantType(node.content, context);1968 case 4 /* SIMPLE_EXPRESSION */:1969 return node.constType;1970 case 8 /* COMPOUND_EXPRESSION */:1971 let returnType = 3 /* CAN_STRINGIFY */;1972 for (let i = 0; i < node.children.length; i++) {1973 const child = node.children[i];1974 if (isString(child) || isSymbol(child)) {1975 continue;1976 }1977 const childType = getConstantType(child, context);1978 if (childType === 0 /* NOT_CONSTANT */) {1979 return 0 /* NOT_CONSTANT */;1980 }1981 else if (childType < returnType) {1982 returnType = childType;1983 }1984 }1985 return returnType;1986 default:1987 return 0 /* NOT_CONSTANT */;1988 }1989 }1990 const allowHoistedHelperSet = new Set([1991 NORMALIZE_CLASS,1992 NORMALIZE_STYLE,1993 NORMALIZE_PROPS,1994 GUARD_REACTIVE_PROPS1995 ]);1996 function getConstantTypeOfHelperCall(value, context) {1997 if (value.type === 14 /* JS_CALL_EXPRESSION */ &&1998 !isString(value.callee) &&1999 allowHoistedHelperSet.has(value.callee)) {2000 const arg = value.arguments[0];2001 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {2002 return getConstantType(arg, context);2003 }2004 else if (arg.type === 14 /* JS_CALL_EXPRESSION */) {2005 // in the case of nested helper call, e.g. `normalizeProps(guardReactiveProps(exp))`2006 return getConstantTypeOfHelperCall(arg, context);2007 }2008 }2009 return 0 /* NOT_CONSTANT */;2010 }2011 function getGeneratedPropsConstantType(node, context) {2012 let returnType = 3 /* CAN_STRINGIFY */;2013 const props = getNodeProps(node);2014 if (props && props.type === 15 /* JS_OBJECT_EXPRESSION */) {2015 const { properties } = props;2016 for (let i = 0; i < properties.length; i++) {2017 const { key, value } = properties[i];2018 const keyType = getConstantType(key, context);2019 if (keyType === 0 /* NOT_CONSTANT */) {2020 return keyType;2021 }2022 if (keyType < returnType) {2023 returnType = keyType;2024 }2025 let valueType;2026 if (value.type === 4 /* SIMPLE_EXPRESSION */) {2027 valueType = getConstantType(value, context);2028 }2029 else if (value.type === 14 /* JS_CALL_EXPRESSION */) {2030 // some helper calls can be hoisted,2031 // such as the `normalizeProps` generated by the compiler for pre-normalize class,2032 // in this case we need to respect the ConstantType of the helper's arguments2033 valueType = getConstantTypeOfHelperCall(value, context);2034 }2035 else {2036 valueType = 0 /* NOT_CONSTANT */;2037 }2038 if (valueType === 0 /* NOT_CONSTANT */) {2039 return valueType;2040 }2041 if (valueType < returnType) {2042 returnType = valueType;2043 }2044 }2045 }2046 return returnType;2047 }2048 function getNodeProps(node) {2049 const codegenNode = node.codegenNode;2050 if (codegenNode.type === 13 /* VNODE_CALL */) {2051 return codegenNode.props;2052 }2053 }2054 function getPatchFlag(node) {2055 const flag = node.patchFlag;2056 return flag ? parseInt(flag, 10) : undefined;2057 }2058 function createTransformContext(root, { filename = '', prefixIdentifiers = false, hoistStatic = false, cacheHandlers = false, nodeTransforms = [], directiveTransforms = {}, transformHoist = null, isBuiltInComponent = NOOP, isCustomElement = NOOP, expressionPlugins = [], scopeId = null, slotted = true, ssr = false, inSSR = false, ssrCssVars = ``, bindingMetadata = EMPTY_OBJ, inline = false, isTS = false, onError = defaultOnError, onWarn = defaultOnWarn, compatConfig }) {2059 const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/);2060 const context = {2061 // options2062 selfName: nameMatch && capitalize(camelize(nameMatch[1])),2063 prefixIdentifiers,2064 hoistStatic,2065 cacheHandlers,2066 nodeTransforms,2067 directiveTransforms,2068 transformHoist,2069 isBuiltInComponent,2070 isCustomElement,2071 expressionPlugins,2072 scopeId,2073 slotted,2074 ssr,2075 inSSR,2076 ssrCssVars,2077 bindingMetadata,2078 inline,2079 isTS,2080 onError,2081 onWarn,2082 compatConfig,2083 // state2084 root,2085 helpers: new Map(),2086 components: new Set(),2087 directives: new Set(),2088 hoists: [],2089 imports: [],2090 constantCache: new Map(),2091 temps: 0,2092 cached: 0,2093 identifiers: Object.create(null),2094 scopes: {2095 vFor: 0,2096 vSlot: 0,2097 vPre: 0,2098 vOnce: 02099 },2100 parent: null,2101 currentNode: root,2102 childIndex: 0,2103 inVOnce: false,2104 // methods2105 helper(name) {2106 const count = context.helpers.get(name) || 0;2107 context.helpers.set(name, count + 1);2108 return name;2109 },2110 removeHelper(name) {2111 const count = context.helpers.get(name);2112 if (count) {2113 const currentCount = count - 1;2114 if (!currentCount) {2115 context.helpers.delete(name);2116 }2117 else {2118 context.helpers.set(name, currentCount);2119 }2120 }2121 },2122 helperString(name) {2123 return `_${helperNameMap[context.helper(name)]}`;2124 },2125 replaceNode(node) {2126 /* istanbul ignore if */2127 {2128 if (!context.currentNode) {2129 throw new Error(`Node being replaced is already removed.`);2130 }2131 if (!context.parent) {2132 throw new Error(`Cannot replace root node.`);2133 }2134 }2135 context.parent.children[context.childIndex] = context.currentNode = node;2136 },2137 removeNode(node) {2138 if (!context.parent) {2139 throw new Error(`Cannot remove root node.`);2140 }2141 const list = context.parent.children;2142 const removalIndex = node2143 ? list.indexOf(node)2144 : context.currentNode2145 ? context.childIndex2146 : -1;2147 /* istanbul ignore if */2148 if (removalIndex < 0) {2149 throw new Error(`node being removed is not a child of current parent`);2150 }2151 if (!node || node === context.currentNode) {2152 // current node removed2153 context.currentNode = null;2154 context.onNodeRemoved();2155 }2156 else {2157 // sibling node removed2158 if (context.childIndex > removalIndex) {2159 context.childIndex--;2160 context.onNodeRemoved();2161 }2162 }2163 context.parent.children.splice(removalIndex, 1);2164 },2165 onNodeRemoved: () => { },2166 addIdentifiers(exp) {2167 },2168 removeIdentifiers(exp) {2169 },2170 hoist(exp) {2171 if (isString(exp))2172 exp = createSimpleExpression(exp);2173 context.hoists.push(exp);2174 const identifier = createSimpleExpression(`_hoisted_${context.hoists.length}`, false, exp.loc, 2 /* CAN_HOIST */);2175 identifier.hoisted = exp;2176 return identifier;2177 },2178 cache(exp, isVNode = false) {2179 return createCacheExpression(context.cached++, exp, isVNode);2180 }2181 };2182 {2183 context.filters = new Set();2184 }2185 return context;2186 }2187 function transform(root, options) {2188 const context = createTransformContext(root, options);2189 traverseNode(root, context);2190 if (options.hoistStatic) {2191 hoistStatic(root, context);2192 }2193 if (!options.ssr) {2194 createRootCodegen(root, context);2195 }2196 // finalize meta information2197 root.helpers = [...context.helpers.keys()];2198 root.components = [...context.components];2199 root.directives = [...context.directives];2200 root.imports = context.imports;2201 root.hoists = context.hoists;2202 root.temps = context.temps;2203 root.cached = context.cached;2204 {2205 root.filters = [...context.filters];2206 }2207 }2208 function createRootCodegen(root, context) {2209 const { helper } = context;2210 const { children } = root;2211 if (children.length === 1) {2212 const child = children[0];2213 // if the single child is an element, turn it into a block.2214 if (isSingleElementRoot(root, child) && child.codegenNode) {2215 // single element root is never hoisted so codegenNode will never be2216 // SimpleExpressionNode2217 const codegenNode = child.codegenNode;2218 if (codegenNode.type === 13 /* VNODE_CALL */) {2219 makeBlock(codegenNode, context);2220 }2221 root.codegenNode = codegenNode;2222 }2223 else {2224 // - single <slot/>, IfNode, ForNode: already blocks.2225 // - single text node: always patched.2226 // root codegen falls through via genNode()2227 root.codegenNode = child;2228 }2229 }2230 else if (children.length > 1) {2231 // root has multiple nodes - return a fragment block.2232 let patchFlag = 64 /* STABLE_FRAGMENT */;2233 let patchFlagText = PatchFlagNames[64 /* STABLE_FRAGMENT */];2234 // check if the fragment actually contains a single valid child with2235 // the rest being comments2236 if (children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {2237 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;2238 patchFlagText += `, ${PatchFlagNames[2048 /* DEV_ROOT_FRAGMENT */]}`;2239 }2240 root.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, root.children, patchFlag + (` /* ${patchFlagText} */` ), undefined, undefined, true, undefined, false /* isComponent */);2241 }2242 else ;2243 }2244 function traverseChildren(parent, context) {2245 let i = 0;2246 const nodeRemoved = () => {2247 i--;2248 };2249 for (; i < parent.children.length; i++) {2250 const child = parent.children[i];2251 if (isString(child))2252 continue;2253 context.parent = parent;2254 context.childIndex = i;2255 context.onNodeRemoved = nodeRemoved;2256 traverseNode(child, context);2257 }2258 }2259 function traverseNode(node, context) {2260 context.currentNode = node;2261 // apply transform plugins2262 const { nodeTransforms } = context;2263 const exitFns = [];2264 for (let i = 0; i < nodeTransforms.length; i++) {2265 const onExit = nodeTransforms[i](node, context);2266 if (onExit) {2267 if (isArray(onExit)) {2268 exitFns.push(...onExit);2269 }2270 else {2271 exitFns.push(onExit);2272 }2273 }2274 if (!context.currentNode) {2275 // node was removed2276 return;2277 }2278 else {2279 // node may have been replaced2280 node = context.currentNode;2281 }2282 }2283 switch (node.type) {2284 case 3 /* COMMENT */:2285 if (!context.ssr) {2286 // inject import for the Comment symbol, which is needed for creating2287 // comment nodes with `createVNode`2288 context.helper(CREATE_COMMENT);2289 }2290 break;2291 case 5 /* INTERPOLATION */:2292 // no need to traverse, but we need to inject toString helper2293 if (!context.ssr) {2294 context.helper(TO_DISPLAY_STRING);2295 }2296 break;2297 // for container types, further traverse downwards2298 case 9 /* IF */:2299 for (let i = 0; i < node.branches.length; i++) {2300 traverseNode(node.branches[i], context);2301 }2302 break;2303 case 10 /* IF_BRANCH */:2304 case 11 /* FOR */:2305 case 1 /* ELEMENT */:2306 case 0 /* ROOT */:2307 traverseChildren(node, context);2308 break;2309 }2310 // exit transforms2311 context.currentNode = node;2312 let i = exitFns.length;2313 while (i--) {2314 exitFns[i]();2315 }2316 }2317 function createStructuralDirectiveTransform(name, fn) {2318 const matches = isString(name)2319 ? (n) => n === name2320 : (n) => name.test(n);2321 return (node, context) => {2322 if (node.type === 1 /* ELEMENT */) {2323 const { props } = node;2324 // structural directive transforms are not concerned with slots2325 // as they are handled separately in vSlot.ts2326 if (node.tagType === 3 /* TEMPLATE */ && props.some(isVSlot)) {2327 return;2328 }2329 const exitFns = [];2330 for (let i = 0; i < props.length; i++) {2331 const prop = props[i];2332 if (prop.type === 7 /* DIRECTIVE */ && matches(prop.name)) {2333 // structural directives are removed to avoid infinite recursion2334 // also we remove them *before* applying so that it can further2335 // traverse itself in case it moves the node around2336 props.splice(i, 1);2337 i--;2338 const onExit = fn(node, prop, context);2339 if (onExit)2340 exitFns.push(onExit);2341 }2342 }2343 return exitFns;2344 }2345 };2346 }2347 const PURE_ANNOTATION = `/*#__PURE__*/`;2348 function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssrRuntimeModuleName = 'vue/server-renderer', ssr = false, isTS = false, inSSR = false }) {2349 const context = {2350 mode,2351 prefixIdentifiers,2352 sourceMap,2353 filename,2354 scopeId,2355 optimizeImports,2356 runtimeGlobalName,2357 runtimeModuleName,2358 ssrRuntimeModuleName,2359 ssr,2360 isTS,2361 inSSR,2362 source: ast.loc.source,2363 code: ``,2364 column: 1,2365 line: 1,2366 offset: 0,2367 indentLevel: 0,2368 pure: false,2369 map: undefined,2370 helper(key) {2371 return `_${helperNameMap[key]}`;2372 },2373 push(code, node) {2374 context.code += code;2375 },2376 indent() {2377 newline(++context.indentLevel);2378 },2379 deindent(withoutNewLine = false) {2380 if (withoutNewLine) {2381 --context.indentLevel;2382 }2383 else {2384 newline(--context.indentLevel);2385 }2386 },2387 newline() {2388 newline(context.indentLevel);2389 }2390 };2391 function newline(n) {2392 context.push('\n' + ` `.repeat(n));2393 }2394 return context;2395 }2396 function generate(ast, options = {}) {2397 const context = createCodegenContext(ast, options);2398 if (options.onContextCreated)2399 options.onContextCreated(context);2400 const { mode, push, prefixIdentifiers, indent, deindent, newline, scopeId, ssr } = context;2401 const hasHelpers = ast.helpers.length > 0;2402 const useWithBlock = !prefixIdentifiers && mode !== 'module';2403 // preambles2404 // in setup() inline mode, the preamble is generated in a sub context2405 // and returned separately.2406 const preambleContext = context;2407 {2408 genFunctionPreamble(ast, preambleContext);2409 }2410 // enter render function2411 const functionName = ssr ? `ssrRender` : `render`;2412 const args = ssr ? ['_ctx', '_push', '_parent', '_attrs'] : ['_ctx', '_cache'];2413 const signature = args.join(', ');2414 {2415 push(`function ${functionName}(${signature}) {`);2416 }2417 indent();2418 if (useWithBlock) {2419 push(`with (_ctx) {`);2420 indent();2421 // function mode const declarations should be inside with block2422 // also they should be renamed to avoid collision with user properties2423 if (hasHelpers) {2424 push(`const { ${ast.helpers2425 .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)2426 .join(', ')} } = _Vue`);2427 push(`\n`);2428 newline();2429 }2430 }2431 // generate asset resolution statements2432 if (ast.components.length) {2433 genAssets(ast.components, 'component', context);2434 if (ast.directives.length || ast.temps > 0) {2435 newline();2436 }2437 }2438 if (ast.directives.length) {2439 genAssets(ast.directives, 'directive', context);2440 if (ast.temps > 0) {2441 newline();2442 }2443 }2444 if (ast.filters && ast.filters.length) {2445 newline();2446 genAssets(ast.filters, 'filter', context);2447 newline();2448 }2449 if (ast.temps > 0) {2450 push(`let `);2451 for (let i = 0; i < ast.temps; i++) {2452 push(`${i > 0 ? `, ` : ``}_temp${i}`);2453 }2454 }2455 if (ast.components.length || ast.directives.length || ast.temps) {2456 push(`\n`);2457 newline();2458 }2459 // generate the VNode tree expression2460 if (!ssr) {2461 push(`return `);2462 }2463 if (ast.codegenNode) {2464 genNode(ast.codegenNode, context);2465 }2466 else {2467 push(`null`);2468 }2469 if (useWithBlock) {2470 deindent();2471 push(`}`);2472 }2473 deindent();2474 push(`}`);2475 return {2476 ast,2477 code: context.code,2478 preamble: ``,2479 // SourceMapGenerator does have toJSON() method but it's not in the types2480 map: context.map ? context.map.toJSON() : undefined2481 };2482 }2483 function genFunctionPreamble(ast, context) {2484 const { ssr, prefixIdentifiers, push, newline, runtimeModuleName, runtimeGlobalName, ssrRuntimeModuleName } = context;2485 const VueBinding = runtimeGlobalName;2486 const aliasHelper = (s) => `${helperNameMap[s]}: _${helperNameMap[s]}`;2487 // Generate const declaration for helpers2488 // In prefix mode, we place the const declaration at top so it's done2489 // only once; But if we not prefixing, we place the declaration inside the2490 // with block so it doesn't incur the `in` check cost for every helper access.2491 if (ast.helpers.length > 0) {2492 {2493 // "with" mode.2494 // save Vue in a separate variable to avoid collision2495 push(`const _Vue = ${VueBinding}\n`);2496 // in "with" mode, helpers are declared inside the with block to avoid2497 // has check cost, but hoists are lifted out of the function - we need2498 // to provide the helper here.2499 if (ast.hoists.length) {2500 const staticHelpers = [2501 CREATE_VNODE,2502 CREATE_ELEMENT_VNODE,2503 CREATE_COMMENT,2504 CREATE_TEXT,2505 CREATE_STATIC2506 ]2507 .filter(helper => ast.helpers.includes(helper))2508 .map(aliasHelper)2509 .join(', ');2510 push(`const { ${staticHelpers} } = _Vue\n`);2511 }2512 }2513 }2514 genHoists(ast.hoists, context);2515 newline();2516 push(`return `);2517 }2518 function genAssets(assets, type, { helper, push, newline, isTS }) {2519 const resolver = helper(type === 'filter'2520 ? RESOLVE_FILTER2521 : type === 'component'2522 ? RESOLVE_COMPONENT2523 : RESOLVE_DIRECTIVE);2524 for (let i = 0; i < assets.length; i++) {2525 let id = assets[i];2526 // potential component implicit self-reference inferred from SFC filename2527 const maybeSelfReference = id.endsWith('__self');2528 if (maybeSelfReference) {2529 id = id.slice(0, -6);2530 }2531 push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`);2532 if (i < assets.length - 1) {2533 newline();2534 }2535 }2536 }2537 function genHoists(hoists, context) {2538 if (!hoists.length) {2539 return;2540 }2541 context.pure = true;2542 const { push, newline, helper, scopeId, mode } = context;2543 newline();2544 for (let i = 0; i < hoists.length; i++) {2545 const exp = hoists[i];2546 if (exp) {2547 push(`const _hoisted_${i + 1} = ${``}`);2548 genNode(exp, context);2549 newline();2550 }2551 }2552 context.pure = false;2553 }2554 function isText$1(n) {2555 return (isString(n) ||2556 n.type === 4 /* SIMPLE_EXPRESSION */ ||2557 n.type === 2 /* TEXT */ ||2558 n.type === 5 /* INTERPOLATION */ ||2559 n.type === 8 /* COMPOUND_EXPRESSION */);2560 }2561 function genNodeListAsArray(nodes, context) {2562 const multilines = nodes.length > 3 ||2563 (nodes.some(n => isArray(n) || !isText$1(n)));2564 context.push(`[`);2565 multilines && context.indent();2566 genNodeList(nodes, context, multilines);2567 multilines && context.deindent();2568 context.push(`]`);2569 }2570 function genNodeList(nodes, context, multilines = false, comma = true) {2571 const { push, newline } = context;2572 for (let i = 0; i < nodes.length; i++) {2573 const node = nodes[i];2574 if (isString(node)) {2575 push(node);2576 }2577 else if (isArray(node)) {2578 genNodeListAsArray(node, context);2579 }2580 else {2581 genNode(node, context);2582 }2583 if (i < nodes.length - 1) {2584 if (multilines) {2585 comma && push(',');2586 newline();2587 }2588 else {2589 comma && push(', ');2590 }2591 }2592 }2593 }2594 function genNode(node, context) {2595 if (isString(node)) {2596 context.push(node);2597 return;2598 }2599 if (isSymbol(node)) {2600 context.push(context.helper(node));2601 return;2602 }2603 switch (node.type) {2604 case 1 /* ELEMENT */:2605 case 9 /* IF */:2606 case 11 /* FOR */:2607 assert(node.codegenNode != null, `Codegen node is missing for element/if/for node. ` +2608 `Apply appropriate transforms first.`);2609 genNode(node.codegenNode, context);2610 break;2611 case 2 /* TEXT */:2612 genText(node, context);2613 break;2614 case 4 /* SIMPLE_EXPRESSION */:2615 genExpression(node, context);2616 break;2617 case 5 /* INTERPOLATION */:2618 genInterpolation(node, context);2619 break;2620 case 12 /* TEXT_CALL */:2621 genNode(node.codegenNode, context);2622 break;2623 case 8 /* COMPOUND_EXPRESSION */:2624 genCompoundExpression(node, context);2625 break;2626 case 3 /* COMMENT */:2627 genComment(node, context);2628 break;2629 case 13 /* VNODE_CALL */:2630 genVNodeCall(node, context);2631 break;2632 case 14 /* JS_CALL_EXPRESSION */:2633 genCallExpression(node, context);2634 break;2635 case 15 /* JS_OBJECT_EXPRESSION */:2636 genObjectExpression(node, context);2637 break;2638 case 17 /* JS_ARRAY_EXPRESSION */:2639 genArrayExpression(node, context);2640 break;2641 case 18 /* JS_FUNCTION_EXPRESSION */:2642 genFunctionExpression(node, context);2643 break;2644 case 19 /* JS_CONDITIONAL_EXPRESSION */:2645 genConditionalExpression(node, context);2646 break;2647 case 20 /* JS_CACHE_EXPRESSION */:2648 genCacheExpression(node, context);2649 break;2650 case 21 /* JS_BLOCK_STATEMENT */:2651 genNodeList(node.body, context, true, false);2652 break;2653 // SSR only types2654 case 22 /* JS_TEMPLATE_LITERAL */:2655 break;2656 case 23 /* JS_IF_STATEMENT */:2657 break;2658 case 24 /* JS_ASSIGNMENT_EXPRESSION */:2659 break;2660 case 25 /* JS_SEQUENCE_EXPRESSION */:2661 break;2662 case 26 /* JS_RETURN_STATEMENT */:2663 break;2664 /* istanbul ignore next */2665 case 10 /* IF_BRANCH */:2666 // noop2667 break;2668 default:2669 {2670 assert(false, `unhandled codegen node type: ${node.type}`);2671 // make sure we exhaust all possible types2672 const exhaustiveCheck = node;2673 return exhaustiveCheck;2674 }2675 }2676 }2677 function genText(node, context) {2678 context.push(JSON.stringify(node.content), node);2679 }2680 function genExpression(node, context) {2681 const { content, isStatic } = node;2682 context.push(isStatic ? JSON.stringify(content) : content, node);2683 }2684 function genInterpolation(node, context) {2685 const { push, helper, pure } = context;2686 if (pure)2687 push(PURE_ANNOTATION);2688 push(`${helper(TO_DISPLAY_STRING)}(`);2689 genNode(node.content, context);2690 push(`)`);2691 }2692 function genCompoundExpression(node, context) {2693 for (let i = 0; i < node.children.length; i++) {2694 const child = node.children[i];2695 if (isString(child)) {2696 context.push(child);2697 }2698 else {2699 genNode(child, context);2700 }2701 }2702 }2703 function genExpressionAsPropertyKey(node, context) {2704 const { push } = context;2705 if (node.type === 8 /* COMPOUND_EXPRESSION */) {2706 push(`[`);2707 genCompoundExpression(node, context);2708 push(`]`);2709 }2710 else if (node.isStatic) {2711 // only quote keys if necessary2712 const text = isSimpleIdentifier(node.content)2713 ? node.content2714 : JSON.stringify(node.content);2715 push(text, node);2716 }2717 else {2718 push(`[${node.content}]`, node);2719 }2720 }2721 function genComment(node, context) {2722 const { push, helper, pure } = context;2723 if (pure) {2724 push(PURE_ANNOTATION);2725 }2726 push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node);2727 }2728 function genVNodeCall(node, context) {2729 const { push, helper, pure } = context;2730 const { tag, props, children, patchFlag, dynamicProps, directives, isBlock, disableTracking, isComponent } = node;2731 if (directives) {2732 push(helper(WITH_DIRECTIVES) + `(`);2733 }2734 if (isBlock) {2735 push(`(${helper(OPEN_BLOCK)}(${disableTracking ? `true` : ``}), `);2736 }2737 if (pure) {2738 push(PURE_ANNOTATION);2739 }2740 const callHelper = isBlock2741 ? getVNodeBlockHelper(context.inSSR, isComponent)2742 : getVNodeHelper(context.inSSR, isComponent);2743 push(helper(callHelper) + `(`, node);2744 genNodeList(genNullableArgs([tag, props, children, patchFlag, dynamicProps]), context);2745 push(`)`);2746 if (isBlock) {2747 push(`)`);2748 }2749 if (directives) {2750 push(`, `);2751 genNode(directives, context);2752 push(`)`);2753 }2754 }2755 function genNullableArgs(args) {2756 let i = args.length;2757 while (i--) {2758 if (args[i] != null)2759 break;2760 }2761 return args.slice(0, i + 1).map(arg => arg || `null`);2762 }2763 // JavaScript2764 function genCallExpression(node, context) {2765 const { push, helper, pure } = context;2766 const callee = isString(node.callee) ? node.callee : helper(node.callee);2767 if (pure) {2768 push(PURE_ANNOTATION);2769 }2770 push(callee + `(`, node);2771 genNodeList(node.arguments, context);2772 push(`)`);2773 }2774 function genObjectExpression(node, context) {2775 const { push, indent, deindent, newline } = context;2776 const { properties } = node;2777 if (!properties.length) {2778 push(`{}`, node);2779 return;2780 }2781 const multilines = properties.length > 1 ||2782 (properties.some(p => p.value.type !== 4 /* SIMPLE_EXPRESSION */));2783 push(multilines ? `{` : `{ `);2784 multilines && indent();2785 for (let i = 0; i < properties.length; i++) {2786 const { key, value } = properties[i];2787 // key2788 genExpressionAsPropertyKey(key, context);2789 push(`: `);2790 // value2791 genNode(value, context);2792 if (i < properties.length - 1) {2793 // will only reach this if it's multilines2794 push(`,`);2795 newline();2796 }2797 }2798 multilines && deindent();2799 push(multilines ? `}` : ` }`);2800 }2801 function genArrayExpression(node, context) {2802 genNodeListAsArray(node.elements, context);2803 }2804 function genFunctionExpression(node, context) {2805 const { push, indent, deindent } = context;2806 const { params, returns, body, newline, isSlot } = node;2807 if (isSlot) {2808 // wrap slot functions with owner context2809 push(`_${helperNameMap[WITH_CTX]}(`);2810 }2811 push(`(`, node);2812 if (isArray(params)) {2813 genNodeList(params, context);2814 }2815 else if (params) {2816 genNode(params, context);2817 }2818 push(`) => `);2819 if (newline || body) {2820 push(`{`);2821 indent();2822 }2823 if (returns) {2824 if (newline) {2825 push(`return `);2826 }2827 if (isArray(returns)) {2828 genNodeListAsArray(returns, context);2829 }2830 else {2831 genNode(returns, context);2832 }2833 }2834 else if (body) {2835 genNode(body, context);2836 }2837 if (newline || body) {2838 deindent();2839 push(`}`);2840 }2841 if (isSlot) {2842 if (node.isNonScopedSlot) {2843 push(`, undefined, true`);2844 }2845 push(`)`);2846 }2847 }2848 function genConditionalExpression(node, context) {2849 const { test, consequent, alternate, newline: needNewline } = node;2850 const { push, indent, deindent, newline } = context;2851 if (test.type === 4 /* SIMPLE_EXPRESSION */) {2852 const needsParens = !isSimpleIdentifier(test.content);2853 needsParens && push(`(`);2854 genExpression(test, context);2855 needsParens && push(`)`);2856 }2857 else {2858 push(`(`);2859 genNode(test, context);2860 push(`)`);2861 }2862 needNewline && indent();2863 context.indentLevel++;2864 needNewline || push(` `);2865 push(`? `);2866 genNode(consequent, context);2867 context.indentLevel--;2868 needNewline && newline();2869 needNewline || push(` `);2870 push(`: `);2871 const isNested = alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */;2872 if (!isNested) {2873 context.indentLevel++;2874 }2875 genNode(alternate, context);2876 if (!isNested) {2877 context.indentLevel--;2878 }2879 needNewline && deindent(true /* without newline */);2880 }2881 function genCacheExpression(node, context) {2882 const { push, helper, indent, deindent, newline } = context;2883 push(`_cache[${node.index}] || (`);2884 if (node.isVNode) {2885 indent();2886 push(`${helper(SET_BLOCK_TRACKING)}(-1),`);2887 newline();2888 }2889 push(`_cache[${node.index}] = `);2890 genNode(node.value, context);2891 if (node.isVNode) {2892 push(`,`);2893 newline();2894 push(`${helper(SET_BLOCK_TRACKING)}(1),`);2895 newline();2896 push(`_cache[${node.index}]`);2897 deindent();2898 }2899 push(`)`);2900 }2901 function walkIdentifiers(root, onIdentifier, includeAll = false, parentStack = [], knownIds = Object.create(null)) {2902 {2903 return;2904 }2905 }2906 function isReferencedIdentifier(id, parent, parentStack) {2907 {2908 return false;2909 }2910 }2911 function isInDestructureAssignment(parent, parentStack) {2912 if (parent &&2913 (parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')) {2914 let i = parentStack.length;2915 while (i--) {2916 const p = parentStack[i];2917 if (p.type === 'AssignmentExpression') {2918 return true;2919 }2920 else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {2921 break;2922 }2923 }2924 }2925 return false;2926 }2927 function walkFunctionParams(node, onIdent) {2928 for (const p of node.params) {2929 for (const id of extractIdentifiers(p)) {2930 onIdent(id);2931 }2932 }2933 }2934 function walkBlockDeclarations(block, onIdent) {2935 for (const stmt of block.body) {2936 if (stmt.type === 'VariableDeclaration') {2937 if (stmt.declare)2938 continue;2939 for (const decl of stmt.declarations) {2940 for (const id of extractIdentifiers(decl.id)) {2941 onIdent(id);2942 }2943 }2944 }2945 else if (stmt.type === 'FunctionDeclaration' ||2946 stmt.type === 'ClassDeclaration') {2947 if (stmt.declare || !stmt.id)2948 continue;2949 onIdent(stmt.id);2950 }2951 }2952 }2953 function extractIdentifiers(param, nodes = []) {2954 switch (param.type) {2955 case 'Identifier':2956 nodes.push(param);2957 break;2958 case 'MemberExpression':2959 let object = param;2960 while (object.type === 'MemberExpression') {2961 object = object.object;2962 }2963 nodes.push(object);2964 break;2965 case 'ObjectPattern':2966 for (const prop of param.properties) {2967 if (prop.type === 'RestElement') {2968 extractIdentifiers(prop.argument, nodes);2969 }2970 else {2971 extractIdentifiers(prop.value, nodes);2972 }2973 }2974 break;2975 case 'ArrayPattern':2976 param.elements.forEach(element => {2977 if (element)2978 extractIdentifiers(element, nodes);2979 });2980 break;2981 case 'RestElement':2982 extractIdentifiers(param.argument, nodes);2983 break;2984 case 'AssignmentPattern':2985 extractIdentifiers(param.left, nodes);2986 break;2987 }2988 return nodes;2989 }2990 const isFunctionType = (node) => {2991 return /Function(?:Expression|Declaration)$|Method$/.test(node.type);2992 };2993 const isStaticProperty = (node) => node &&2994 (node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&2995 !node.computed;2996 const isStaticPropertyKey = (node, parent) => isStaticProperty(parent) && parent.key === node;2997 // these keywords should not appear inside expressions, but operators like2998 // typeof, instanceof and in are allowed2999 const prohibitedKeywordRE = new RegExp('\\b' +3000 ('do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,' +3001 'super,throw,while,yield,delete,export,import,return,switch,default,' +3002 'extends,finally,continue,debugger,function,arguments,typeof,void')3003 .split(',')3004 .join('\\b|\\b') +3005 '\\b');3006 // strip strings in expressions3007 const stripStringRE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`/g;3008 /**3009 * Validate a non-prefixed expression.3010 * This is only called when using the in-browser runtime compiler since it3011 * doesn't prefix expressions.3012 */3013 function validateBrowserExpression(node, context, asParams = false, asRawStatements = false) {3014 const exp = node.content;3015 // empty expressions are validated per-directive since some directives3016 // do allow empty expressions.3017 if (!exp.trim()) {3018 return;3019 }3020 try {3021 new Function(asRawStatements3022 ? ` ${exp} `3023 : `return ${asParams ? `(${exp}) => {}` : `(${exp})`}`);3024 }3025 catch (e) {3026 let message = e.message;3027 const keywordMatch = exp3028 .replace(stripStringRE, '')3029 .match(prohibitedKeywordRE);3030 if (keywordMatch) {3031 message = `avoid using JavaScript keyword as property name: "${keywordMatch[0]}"`;3032 }3033 context.onError(createCompilerError(44 /* X_INVALID_EXPRESSION */, node.loc, undefined, message));3034 }3035 }3036 const transformExpression = (node, context) => {3037 if (node.type === 5 /* INTERPOLATION */) {3038 node.content = processExpression(node.content, context);3039 }3040 else if (node.type === 1 /* ELEMENT */) {3041 // handle directives on element3042 for (let i = 0; i < node.props.length; i++) {3043 const dir = node.props[i];3044 // do not process for v-on & v-for since they are special handled3045 if (dir.type === 7 /* DIRECTIVE */ && dir.name !== 'for') {3046 const exp = dir.exp;3047 const arg = dir.arg;3048 // do not process exp if this is v-on:arg - we need special handling3049 // for wrapping inline statements.3050 if (exp &&3051 exp.type === 4 /* SIMPLE_EXPRESSION */ &&3052 !(dir.name === 'on' && arg)) {3053 dir.exp = processExpression(exp, context, 3054 // slot args must be processed as function params3055 dir.name === 'slot');3056 }3057 if (arg && arg.type === 4 /* SIMPLE_EXPRESSION */ && !arg.isStatic) {3058 dir.arg = processExpression(arg, context);3059 }3060 }3061 }3062 }3063 };3064 // Important: since this function uses Node.js only dependencies, it should3065 // always be used with a leading !true check so that it can be3066 // tree-shaken from the browser build.3067 function processExpression(node, context, 3068 // some expressions like v-slot props & v-for aliases should be parsed as3069 // function params3070 asParams = false, 3071 // v-on handler values may contain multiple statements3072 asRawStatements = false, localVars = Object.create(context.identifiers)) {3073 {3074 {3075 // simple in-browser validation (same logic in 2.x)3076 validateBrowserExpression(node, context, asParams, asRawStatements);3077 }3078 return node;3079 }3080 }3081 const transformIf = createStructuralDirectiveTransform(/^(if|else|else-if)$/, (node, dir, context) => {3082 return processIf(node, dir, context, (ifNode, branch, isRoot) => {3083 // #1587: We need to dynamically increment the key based on the current3084 // node's sibling nodes, since chained v-if/else branches are3085 // rendered at the same depth3086 const siblings = context.parent.children;3087 let i = siblings.indexOf(ifNode);3088 let key = 0;3089 while (i-- >= 0) {3090 const sibling = siblings[i];3091 if (sibling && sibling.type === 9 /* IF */) {3092 key += sibling.branches.length;3093 }3094 }3095 // Exit callback. Complete the codegenNode when all children have been3096 // transformed.3097 return () => {3098 if (isRoot) {3099 ifNode.codegenNode = createCodegenNodeForBranch(branch, key, context);3100 }3101 else {3102 // attach this branch's codegen node to the v-if root.3103 const parentCondition = getParentCondition(ifNode.codegenNode);3104 parentCondition.alternate = createCodegenNodeForBranch(branch, key + ifNode.branches.length - 1, context);3105 }3106 };3107 });3108 });3109 // target-agnostic transform used for both Client and SSR3110 function processIf(node, dir, context, processCodegen) {3111 if (dir.name !== 'else' &&3112 (!dir.exp || !dir.exp.content.trim())) {3113 const loc = dir.exp ? dir.exp.loc : node.loc;3114 context.onError(createCompilerError(28 /* X_V_IF_NO_EXPRESSION */, dir.loc));3115 dir.exp = createSimpleExpression(`true`, false, loc);3116 }3117 if (dir.exp) {3118 validateBrowserExpression(dir.exp, context);3119 }3120 if (dir.name === 'if') {3121 const branch = createIfBranch(node, dir);3122 const ifNode = {3123 type: 9 /* IF */,3124 loc: node.loc,3125 branches: [branch]3126 };3127 context.replaceNode(ifNode);3128 if (processCodegen) {3129 return processCodegen(ifNode, branch, true);3130 }3131 }3132 else {3133 // locate the adjacent v-if3134 const siblings = context.parent.children;3135 const comments = [];3136 let i = siblings.indexOf(node);3137 while (i-- >= -1) {3138 const sibling = siblings[i];3139 if (sibling && sibling.type === 3 /* COMMENT */) {3140 context.removeNode(sibling);3141 comments.unshift(sibling);3142 continue;3143 }3144 if (sibling &&3145 sibling.type === 2 /* TEXT */ &&3146 !sibling.content.trim().length) {3147 context.removeNode(sibling);3148 continue;3149 }3150 if (sibling && sibling.type === 9 /* IF */) {3151 // Check if v-else was followed by v-else-if3152 if (dir.name === 'else-if' &&3153 sibling.branches[sibling.branches.length - 1].condition === undefined) {3154 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));3155 }3156 // move the node to the if node's branches3157 context.removeNode();3158 const branch = createIfBranch(node, dir);3159 if (comments.length &&3160 // #3619 ignore comments if the v-if is direct child of <transition>3161 !(context.parent &&3162 context.parent.type === 1 /* ELEMENT */ &&3163 isBuiltInType(context.parent.tag, 'transition'))) {3164 branch.children = [...comments, ...branch.children];3165 }3166 // check if user is forcing same key on different branches3167 {3168 const key = branch.userKey;3169 if (key) {3170 sibling.branches.forEach(({ userKey }) => {3171 if (isSameKey(userKey, key)) {3172 context.onError(createCompilerError(29 /* X_V_IF_SAME_KEY */, branch.userKey.loc));3173 }3174 });3175 }3176 }3177 sibling.branches.push(branch);3178 const onExit = processCodegen && processCodegen(sibling, branch, false);3179 // since the branch was removed, it will not be traversed.3180 // make sure to traverse here.3181 traverseNode(branch, context);3182 // call on exit3183 if (onExit)3184 onExit();3185 // make sure to reset currentNode after traversal to indicate this3186 // node has been removed.3187 context.currentNode = null;3188 }3189 else {3190 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));3191 }3192 break;3193 }3194 }3195 }3196 function createIfBranch(node, dir) {3197 return {3198 type: 10 /* IF_BRANCH */,3199 loc: node.loc,3200 condition: dir.name === 'else' ? undefined : dir.exp,3201 children: node.tagType === 3 /* TEMPLATE */ && !findDir(node, 'for')3202 ? node.children3203 : [node],3204 userKey: findProp(node, `key`)3205 };3206 }3207 function createCodegenNodeForBranch(branch, keyIndex, context) {3208 if (branch.condition) {3209 return createConditionalExpression(branch.condition, createChildrenCodegenNode(branch, keyIndex, context), 3210 // make sure to pass in asBlock: true so that the comment node call3211 // closes the current block.3212 createCallExpression(context.helper(CREATE_COMMENT), [3213 '"v-if"' ,3214 'true'3215 ]));3216 }3217 else {3218 return createChildrenCodegenNode(branch, keyIndex, context);3219 }3220 }3221 function createChildrenCodegenNode(branch, keyIndex, context) {3222 const { helper } = context;3223 const keyProperty = createObjectProperty(`key`, createSimpleExpression(`${keyIndex}`, false, locStub, 2 /* CAN_HOIST */));3224 const { children } = branch;3225 const firstChild = children[0];3226 const needFragmentWrapper = children.length !== 1 || firstChild.type !== 1 /* ELEMENT */;3227 if (needFragmentWrapper) {3228 if (children.length === 1 && firstChild.type === 11 /* FOR */) {3229 // optimize away nested fragments when child is a ForNode3230 const vnodeCall = firstChild.codegenNode;3231 injectProp(vnodeCall, keyProperty, context);3232 return vnodeCall;3233 }3234 else {3235 let patchFlag = 64 /* STABLE_FRAGMENT */;3236 let patchFlagText = PatchFlagNames[64 /* STABLE_FRAGMENT */];3237 // check if the fragment actually contains a single valid child with3238 // the rest being comments3239 if (children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {3240 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;3241 patchFlagText += `, ${PatchFlagNames[2048 /* DEV_ROOT_FRAGMENT */]}`;3242 }3243 return createVNodeCall(context, helper(FRAGMENT), createObjectExpression([keyProperty]), children, patchFlag + (` /* ${patchFlagText} */` ), undefined, undefined, true, false, false /* isComponent */, branch.loc);3244 }3245 }3246 else {3247 const ret = firstChild.codegenNode;3248 const vnodeCall = getMemoedVNodeCall(ret);3249 // Change createVNode to createBlock.3250 if (vnodeCall.type === 13 /* VNODE_CALL */) {3251 makeBlock(vnodeCall, context);3252 }3253 // inject branch key3254 injectProp(vnodeCall, keyProperty, context);3255 return ret;3256 }3257 }3258 function isSameKey(a, b) {3259 if (!a || a.type !== b.type) {3260 return false;3261 }3262 if (a.type === 6 /* ATTRIBUTE */) {3263 if (a.value.content !== b.value.content) {3264 return false;3265 }3266 }3267 else {3268 // directive3269 const exp = a.exp;3270 const branchExp = b.exp;3271 if (exp.type !== branchExp.type) {3272 return false;3273 }3274 if (exp.type !== 4 /* SIMPLE_EXPRESSION */ ||3275 exp.isStatic !== branchExp.isStatic ||3276 exp.content !== branchExp.content) {3277 return false;3278 }3279 }3280 return true;3281 }3282 function getParentCondition(node) {3283 while (true) {3284 if (node.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3285 if (node.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3286 node = node.alternate;3287 }3288 else {3289 return node;3290 }3291 }3292 else if (node.type === 20 /* JS_CACHE_EXPRESSION */) {3293 node = node.value;3294 }3295 }3296 }3297 const transformFor = createStructuralDirectiveTransform('for', (node, dir, context) => {3298 const { helper, removeHelper } = context;3299 return processFor(node, dir, context, forNode => {3300 // create the loop render function expression now, and add the3301 // iterator on exit after all children have been traversed3302 const renderExp = createCallExpression(helper(RENDER_LIST), [3303 forNode.source3304 ]);3305 const memo = findDir(node, 'memo');3306 const keyProp = findProp(node, `key`);3307 const keyExp = keyProp &&3308 (keyProp.type === 6 /* ATTRIBUTE */3309 ? createSimpleExpression(keyProp.value.content, true)3310 : keyProp.exp);3311 const keyProperty = keyProp ? createObjectProperty(`key`, keyExp) : null;3312 const isStableFragment = forNode.source.type === 4 /* SIMPLE_EXPRESSION */ &&3313 forNode.source.constType > 0 /* NOT_CONSTANT */;3314 const fragmentFlag = isStableFragment3315 ? 64 /* STABLE_FRAGMENT */3316 : keyProp3317 ? 128 /* KEYED_FRAGMENT */3318 : 256 /* UNKEYED_FRAGMENT */;3319 forNode.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, renderExp, fragmentFlag +3320 (` /* ${PatchFlagNames[fragmentFlag]} */` ), undefined, undefined, true /* isBlock */, !isStableFragment /* disableTracking */, false /* isComponent */, node.loc);3321 return () => {3322 // finish the codegen now that all children have been traversed3323 let childBlock;3324 const isTemplate = isTemplateNode(node);3325 const { children } = forNode;3326 // check <template v-for> key placement3327 if (isTemplate) {3328 node.children.some(c => {3329 if (c.type === 1 /* ELEMENT */) {3330 const key = findProp(c, 'key');3331 if (key) {3332 context.onError(createCompilerError(33 /* X_V_FOR_TEMPLATE_KEY_PLACEMENT */, key.loc));3333 return true;3334 }3335 }3336 });3337 }3338 const needFragmentWrapper = children.length !== 1 || children[0].type !== 1 /* ELEMENT */;3339 const slotOutlet = isSlotOutlet(node)3340 ? node3341 : isTemplate &&3342 node.children.length === 1 &&3343 isSlotOutlet(node.children[0])3344 ? node.children[0] // api-extractor somehow fails to infer this3345 : null;3346 if (slotOutlet) {3347 // <slot v-for="..."> or <template v-for="..."><slot/></template>3348 childBlock = slotOutlet.codegenNode;3349 if (isTemplate && keyProperty) {3350 // <template v-for="..." :key="..."><slot/></template>3351 // we need to inject the key to the renderSlot() call.3352 // the props for renderSlot is passed as the 3rd argument.3353 injectProp(childBlock, keyProperty, context);3354 }3355 }3356 else if (needFragmentWrapper) {3357 // <template v-for="..."> with text or multi-elements3358 // should generate a fragment block for each loop3359 childBlock = createVNodeCall(context, helper(FRAGMENT), keyProperty ? createObjectExpression([keyProperty]) : undefined, node.children, 64 /* STABLE_FRAGMENT */ +3360 (` /* ${PatchFlagNames[64 /* STABLE_FRAGMENT */]} */`3361 ), undefined, undefined, true, undefined, false /* isComponent */);3362 }3363 else {3364 // Normal element v-for. Directly use the child's codegenNode3365 // but mark it as a block.3366 childBlock = children[0]3367 .codegenNode;3368 if (isTemplate && keyProperty) {3369 injectProp(childBlock, keyProperty, context);3370 }3371 if (childBlock.isBlock !== !isStableFragment) {3372 if (childBlock.isBlock) {3373 // switch from block to vnode3374 removeHelper(OPEN_BLOCK);3375 removeHelper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3376 }3377 else {3378 // switch from vnode to block3379 removeHelper(getVNodeHelper(context.inSSR, childBlock.isComponent));3380 }3381 }3382 childBlock.isBlock = !isStableFragment;3383 if (childBlock.isBlock) {3384 helper(OPEN_BLOCK);3385 helper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3386 }3387 else {3388 helper(getVNodeHelper(context.inSSR, childBlock.isComponent));3389 }3390 }3391 if (memo) {3392 const loop = createFunctionExpression(createForLoopParams(forNode.parseResult, [3393 createSimpleExpression(`_cached`)3394 ]));3395 loop.body = createBlockStatement([3396 createCompoundExpression([`const _memo = (`, memo.exp, `)`]),3397 createCompoundExpression([3398 `if (_cached`,3399 ...(keyExp ? [` && _cached.key === `, keyExp] : []),3400 ` && ${context.helperString(IS_MEMO_SAME)}(_cached, _memo)) return _cached`3401 ]),3402 createCompoundExpression([`const _item = `, childBlock]),3403 createSimpleExpression(`_item.memo = _memo`),3404 createSimpleExpression(`return _item`)3405 ]);3406 renderExp.arguments.push(loop, createSimpleExpression(`_cache`), createSimpleExpression(String(context.cached++)));3407 }3408 else {3409 renderExp.arguments.push(createFunctionExpression(createForLoopParams(forNode.parseResult), childBlock, true /* force newline */));3410 }3411 };3412 });3413 });3414 // target-agnostic transform used for both Client and SSR3415 function processFor(node, dir, context, processCodegen) {3416 if (!dir.exp) {3417 context.onError(createCompilerError(31 /* X_V_FOR_NO_EXPRESSION */, dir.loc));3418 return;3419 }3420 const parseResult = parseForExpression(3421 // can only be simple expression because vFor transform is applied3422 // before expression transform.3423 dir.exp, context);3424 if (!parseResult) {3425 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));3426 return;3427 }3428 const { addIdentifiers, removeIdentifiers, scopes } = context;3429 const { source, value, key, index } = parseResult;3430 const forNode = {3431 type: 11 /* FOR */,3432 loc: dir.loc,3433 source,3434 valueAlias: value,3435 keyAlias: key,3436 objectIndexAlias: index,3437 parseResult,3438 children: isTemplateNode(node) ? node.children : [node]3439 };3440 context.replaceNode(forNode);3441 // bookkeeping3442 scopes.vFor++;3443 const onExit = processCodegen && processCodegen(forNode);3444 return () => {3445 scopes.vFor--;3446 if (onExit)3447 onExit();3448 };3449 }3450 const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;3451 // This regex doesn't cover the case if key or index aliases have destructuring,3452 // but those do not make sense in the first place, so this works in practice.3453 const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;3454 const stripParensRE = /^\(|\)$/g;3455 function parseForExpression(input, context) {3456 const loc = input.loc;3457 const exp = input.content;3458 const inMatch = exp.match(forAliasRE);3459 if (!inMatch)3460 return;3461 const [, LHS, RHS] = inMatch;3462 const result = {3463 source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),3464 value: undefined,3465 key: undefined,3466 index: undefined3467 };3468 {3469 validateBrowserExpression(result.source, context);3470 }3471 let valueContent = LHS.trim().replace(stripParensRE, '').trim();3472 const trimmedOffset = LHS.indexOf(valueContent);3473 const iteratorMatch = valueContent.match(forIteratorRE);3474 if (iteratorMatch) {3475 valueContent = valueContent.replace(forIteratorRE, '').trim();3476 const keyContent = iteratorMatch[1].trim();3477 let keyOffset;3478 if (keyContent) {3479 keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);3480 result.key = createAliasExpression(loc, keyContent, keyOffset);3481 {3482 validateBrowserExpression(result.key, context, true);3483 }3484 }3485 if (iteratorMatch[2]) {3486 const indexContent = iteratorMatch[2].trim();3487 if (indexContent) {3488 result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key3489 ? keyOffset + keyContent.length3490 : trimmedOffset + valueContent.length));3491 {3492 validateBrowserExpression(result.index, context, true);3493 }3494 }3495 }3496 }3497 if (valueContent) {3498 result.value = createAliasExpression(loc, valueContent, trimmedOffset);3499 {3500 validateBrowserExpression(result.value, context, true);3501 }3502 }3503 return result;3504 }3505 function createAliasExpression(range, content, offset) {3506 return createSimpleExpression(content, false, getInnerRange(range, offset, content.length));3507 }3508 function createForLoopParams({ value, key, index }, memoArgs = []) {3509 return createParamsList([value, key, index, ...memoArgs]);3510 }3511 function createParamsList(args) {3512 let i = args.length;3513 while (i--) {3514 if (args[i])3515 break;3516 }3517 return args3518 .slice(0, i + 1)3519 .map((arg, i) => arg || createSimpleExpression(`_`.repeat(i + 1), false));3520 }3521 const defaultFallback = createSimpleExpression(`undefined`, false);3522 // A NodeTransform that:3523 // 1. Tracks scope identifiers for scoped slots so that they don't get prefixed3524 // by transformExpression. This is only applied in non-browser builds with3525 // { prefixIdentifiers: true }.3526 // 2. Track v-slot depths so that we know a slot is inside another slot.3527 // Note the exit callback is executed before buildSlots() on the same node,3528 // so only nested slots see positive numbers.3529 const trackSlotScopes = (node, context) => {3530 if (node.type === 1 /* ELEMENT */ &&3531 (node.tagType === 1 /* COMPONENT */ ||3532 node.tagType === 3 /* TEMPLATE */)) {3533 // We are only checking non-empty v-slot here3534 // since we only care about slots that introduce scope variables.3535 const vSlot = findDir(node, 'slot');3536 if (vSlot) {3537 vSlot.exp;3538 context.scopes.vSlot++;3539 return () => {3540 context.scopes.vSlot--;3541 };3542 }3543 }3544 };3545 // A NodeTransform that tracks scope identifiers for scoped slots with v-for.3546 // This transform is only applied in non-browser builds with { prefixIdentifiers: true }3547 const trackVForSlotScopes = (node, context) => {3548 let vFor;3549 if (isTemplateNode(node) &&3550 node.props.some(isVSlot) &&3551 (vFor = findDir(node, 'for'))) {3552 const result = (vFor.parseResult = parseForExpression(vFor.exp, context));3553 if (result) {3554 const { value, key, index } = result;3555 const { addIdentifiers, removeIdentifiers } = context;3556 value && addIdentifiers(value);3557 key && addIdentifiers(key);3558 index && addIdentifiers(index);3559 return () => {3560 value && removeIdentifiers(value);3561 key && removeIdentifiers(key);3562 index && removeIdentifiers(index);3563 };3564 }3565 }3566 };3567 const buildClientSlotFn = (props, children, loc) => createFunctionExpression(props, children, false /* newline */, true /* isSlot */, children.length ? children[0].loc : loc);3568 // Instead of being a DirectiveTransform, v-slot processing is called during3569 // transformElement to build the slots object for a component.3570 function buildSlots(node, context, buildSlotFn = buildClientSlotFn) {3571 context.helper(WITH_CTX);3572 const { children, loc } = node;3573 const slotsProperties = [];3574 const dynamicSlots = [];3575 // If the slot is inside a v-for or another v-slot, force it to be dynamic3576 // since it likely uses a scope variable.3577 let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0;3578 // 1. Check for slot with slotProps on component itself.3579 // <Comp v-slot="{ prop }"/>3580 const onComponentSlot = findDir(node, 'slot', true);3581 if (onComponentSlot) {3582 const { arg, exp } = onComponentSlot;3583 if (arg && !isStaticExp(arg)) {3584 hasDynamicSlots = true;3585 }3586 slotsProperties.push(createObjectProperty(arg || createSimpleExpression('default', true), buildSlotFn(exp, children, loc)));3587 }3588 // 2. Iterate through children and check for template slots3589 // <template v-slot:foo="{ prop }">3590 let hasTemplateSlots = false;3591 let hasNamedDefaultSlot = false;3592 const implicitDefaultChildren = [];3593 const seenSlotNames = new Set();3594 for (let i = 0; i < children.length; i++) {3595 const slotElement = children[i];3596 let slotDir;3597 if (!isTemplateNode(slotElement) ||3598 !(slotDir = findDir(slotElement, 'slot', true))) {3599 // not a <template v-slot>, skip.3600 if (slotElement.type !== 3 /* COMMENT */) {3601 implicitDefaultChildren.push(slotElement);3602 }3603 continue;3604 }3605 if (onComponentSlot) {3606 // already has on-component slot - this is incorrect usage.3607 context.onError(createCompilerError(37 /* X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc));3608 break;3609 }3610 hasTemplateSlots = true;3611 const { children: slotChildren, loc: slotLoc } = slotElement;3612 const { arg: slotName = createSimpleExpression(`default`, true), exp: slotProps, loc: dirLoc } = slotDir;3613 // check if name is dynamic.3614 let staticSlotName;3615 if (isStaticExp(slotName)) {3616 staticSlotName = slotName ? slotName.content : `default`;3617 }3618 else {3619 hasDynamicSlots = true;3620 }3621 const slotFunction = buildSlotFn(slotProps, slotChildren, slotLoc);3622 // check if this slot is conditional (v-if/v-for)3623 let vIf;3624 let vElse;3625 let vFor;3626 if ((vIf = findDir(slotElement, 'if'))) {3627 hasDynamicSlots = true;3628 dynamicSlots.push(createConditionalExpression(vIf.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback));3629 }3630 else if ((vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))) {3631 // find adjacent v-if3632 let j = i;3633 let prev;3634 while (j--) {3635 prev = children[j];3636 if (prev.type !== 3 /* COMMENT */) {3637 break;3638 }3639 }3640 if (prev && isTemplateNode(prev) && findDir(prev, 'if')) {3641 // remove node3642 children.splice(i, 1);3643 i--;3644 // attach this slot to previous conditional3645 let conditional = dynamicSlots[dynamicSlots.length - 1];3646 while (conditional.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3647 conditional = conditional.alternate;3648 }3649 conditional.alternate = vElse.exp3650 ? createConditionalExpression(vElse.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback)3651 : buildDynamicSlot(slotName, slotFunction);3652 }3653 else {3654 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, vElse.loc));3655 }3656 }3657 else if ((vFor = findDir(slotElement, 'for'))) {3658 hasDynamicSlots = true;3659 const parseResult = vFor.parseResult ||3660 parseForExpression(vFor.exp, context);3661 if (parseResult) {3662 // Render the dynamic slots as an array and add it to the createSlot()3663 // args. The runtime knows how to handle it appropriately.3664 dynamicSlots.push(createCallExpression(context.helper(RENDER_LIST), [3665 parseResult.source,3666 createFunctionExpression(createForLoopParams(parseResult), buildDynamicSlot(slotName, slotFunction), true /* force newline */)3667 ]));3668 }3669 else {3670 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc));3671 }3672 }3673 else {3674 // check duplicate static names3675 if (staticSlotName) {3676 if (seenSlotNames.has(staticSlotName)) {3677 context.onError(createCompilerError(38 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc));3678 continue;3679 }3680 seenSlotNames.add(staticSlotName);3681 if (staticSlotName === 'default') {3682 hasNamedDefaultSlot = true;3683 }3684 }3685 slotsProperties.push(createObjectProperty(slotName, slotFunction));3686 }3687 }3688 if (!onComponentSlot) {3689 const buildDefaultSlotProperty = (props, children) => {3690 const fn = buildSlotFn(props, children, loc);3691 if (context.compatConfig) {3692 fn.isNonScopedSlot = true;3693 }3694 return createObjectProperty(`default`, fn);3695 };3696 if (!hasTemplateSlots) {3697 // implicit default slot (on component)3698 slotsProperties.push(buildDefaultSlotProperty(undefined, children));3699 }3700 else if (implicitDefaultChildren.length &&3701 // #37663702 // with whitespace: 'preserve', whitespaces between slots will end up in3703 // implicitDefaultChildren. Ignore if all implicit children are whitespaces.3704 implicitDefaultChildren.some(node => isNonWhitespaceContent(node))) {3705 // implicit default slot (mixed with named slots)3706 if (hasNamedDefaultSlot) {3707 context.onError(createCompilerError(39 /* X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN */, implicitDefaultChildren[0].loc));3708 }3709 else {3710 slotsProperties.push(buildDefaultSlotProperty(undefined, implicitDefaultChildren));3711 }3712 }3713 }3714 const slotFlag = hasDynamicSlots3715 ? 2 /* DYNAMIC */3716 : hasForwardedSlots(node.children)3717 ? 3 /* FORWARDED */3718 : 1 /* STABLE */;3719 let slots = createObjectExpression(slotsProperties.concat(createObjectProperty(`_`, 3720 // 2 = compiled but dynamic = can skip normalization, but must run diff3721 // 1 = compiled and static = can skip normalization AND diff as optimized3722 createSimpleExpression(slotFlag + (` /* ${slotFlagsText[slotFlag]} */` ), false))), loc);3723 if (dynamicSlots.length) {3724 slots = createCallExpression(context.helper(CREATE_SLOTS), [3725 slots,3726 createArrayExpression(dynamicSlots)3727 ]);3728 }3729 return {3730 slots,3731 hasDynamicSlots3732 };3733 }3734 function buildDynamicSlot(name, fn) {3735 return createObjectExpression([3736 createObjectProperty(`name`, name),3737 createObjectProperty(`fn`, fn)3738 ]);3739 }3740 function hasForwardedSlots(children) {3741 for (let i = 0; i < children.length; i++) {3742 const child = children[i];3743 switch (child.type) {3744 case 1 /* ELEMENT */:3745 if (child.tagType === 2 /* SLOT */ ||3746 hasForwardedSlots(child.children)) {3747 return true;3748 }3749 break;3750 case 9 /* IF */:3751 if (hasForwardedSlots(child.branches))3752 return true;3753 break;3754 case 10 /* IF_BRANCH */:3755 case 11 /* FOR */:3756 if (hasForwardedSlots(child.children))3757 return true;3758 break;3759 }3760 }3761 return false;3762 }3763 function isNonWhitespaceContent(node) {3764 if (node.type !== 2 /* TEXT */ && node.type !== 12 /* TEXT_CALL */)3765 return true;3766 return node.type === 2 /* TEXT */3767 ? !!node.content.trim()3768 : isNonWhitespaceContent(node.content);3769 }3770 // some directive transforms (e.g. v-model) may return a symbol for runtime3771 // import, which should be used instead of a resolveDirective call.3772 const directiveImportMap = new WeakMap();3773 // generate a JavaScript AST for this element's codegen3774 const transformElement = (node, context) => {3775 // perform the work on exit, after all child expressions have been3776 // processed and merged.3777 return function postTransformElement() {3778 node = context.currentNode;3779 if (!(node.type === 1 /* ELEMENT */ &&3780 (node.tagType === 0 /* ELEMENT */ ||3781 node.tagType === 1 /* COMPONENT */))) {3782 return;3783 }3784 const { tag, props } = node;3785 const isComponent = node.tagType === 1 /* COMPONENT */;3786 // The goal of the transform is to create a codegenNode implementing the3787 // VNodeCall interface.3788 let vnodeTag = isComponent3789 ? resolveComponentType(node, context)3790 : `"${tag}"`;3791 const isDynamicComponent = isObject(vnodeTag) && vnodeTag.callee === RESOLVE_DYNAMIC_COMPONENT;3792 let vnodeProps;3793 let vnodeChildren;3794 let vnodePatchFlag;3795 let patchFlag = 0;3796 let vnodeDynamicProps;3797 let dynamicPropNames;3798 let vnodeDirectives;3799 let shouldUseBlock = 3800 // dynamic component may resolve to plain elements3801 isDynamicComponent ||3802 vnodeTag === TELEPORT ||3803 vnodeTag === SUSPENSE ||3804 (!isComponent &&3805 // <svg> and <foreignObject> must be forced into blocks so that block3806 // updates inside get proper isSVG flag at runtime. (#639, #643)3807 // This is technically web-specific, but splitting the logic out of core3808 // leads to too much unnecessary complexity.3809 (tag === 'svg' || tag === 'foreignObject'));3810 // props3811 if (props.length > 0) {3812 const propsBuildResult = buildProps(node, context);3813 vnodeProps = propsBuildResult.props;3814 patchFlag = propsBuildResult.patchFlag;3815 dynamicPropNames = propsBuildResult.dynamicPropNames;3816 const directives = propsBuildResult.directives;3817 vnodeDirectives =3818 directives && directives.length3819 ? createArrayExpression(directives.map(dir => buildDirectiveArgs(dir, context)))3820 : undefined;3821 if (propsBuildResult.shouldUseBlock) {3822 shouldUseBlock = true;3823 }3824 }3825 // children3826 if (node.children.length > 0) {3827 if (vnodeTag === KEEP_ALIVE) {3828 // Although a built-in component, we compile KeepAlive with raw children3829 // instead of slot functions so that it can be used inside Transition3830 // or other Transition-wrapping HOCs.3831 // To ensure correct updates with block optimizations, we need to:3832 // 1. Force keep-alive into a block. This avoids its children being3833 // collected by a parent block.3834 shouldUseBlock = true;3835 // 2. Force keep-alive to always be updated, since it uses raw children.3836 patchFlag |= 1024 /* DYNAMIC_SLOTS */;3837 if (node.children.length > 1) {3838 context.onError(createCompilerError(45 /* X_KEEP_ALIVE_INVALID_CHILDREN */, {3839 start: node.children[0].loc.start,3840 end: node.children[node.children.length - 1].loc.end,3841 source: ''3842 }));3843 }3844 }3845 const shouldBuildAsSlots = isComponent &&3846 // Teleport is not a real component and has dedicated runtime handling3847 vnodeTag !== TELEPORT &&3848 // explained above.3849 vnodeTag !== KEEP_ALIVE;3850 if (shouldBuildAsSlots) {3851 const { slots, hasDynamicSlots } = buildSlots(node, context);3852 vnodeChildren = slots;3853 if (hasDynamicSlots) {3854 patchFlag |= 1024 /* DYNAMIC_SLOTS */;3855 }3856 }3857 else if (node.children.length === 1 && vnodeTag !== TELEPORT) {3858 const child = node.children[0];3859 const type = child.type;3860 // check for dynamic text children3861 const hasDynamicTextChild = type === 5 /* INTERPOLATION */ ||3862 type === 8 /* COMPOUND_EXPRESSION */;3863 if (hasDynamicTextChild &&3864 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {3865 patchFlag |= 1 /* TEXT */;3866 }3867 // pass directly if the only child is a text node3868 // (plain / interpolation / expression)3869 if (hasDynamicTextChild || type === 2 /* TEXT */) {3870 vnodeChildren = child;3871 }3872 else {3873 vnodeChildren = node.children;3874 }3875 }3876 else {3877 vnodeChildren = node.children;3878 }3879 }3880 // patchFlag & dynamicPropNames3881 if (patchFlag !== 0) {3882 {3883 if (patchFlag < 0) {3884 // special flags (negative and mutually exclusive)3885 vnodePatchFlag = patchFlag + ` /* ${PatchFlagNames[patchFlag]} */`;3886 }3887 else {3888 // bitwise flags3889 const flagNames = Object.keys(PatchFlagNames)3890 .map(Number)3891 .filter(n => n > 0 && patchFlag & n)3892 .map(n => PatchFlagNames[n])3893 .join(`, `);3894 vnodePatchFlag = patchFlag + ` /* ${flagNames} */`;3895 }3896 }3897 if (dynamicPropNames && dynamicPropNames.length) {3898 vnodeDynamicProps = stringifyDynamicPropNames(dynamicPropNames);3899 }3900 }3901 node.codegenNode = createVNodeCall(context, vnodeTag, vnodeProps, vnodeChildren, vnodePatchFlag, vnodeDynamicProps, vnodeDirectives, !!shouldUseBlock, false /* disableTracking */, isComponent, node.loc);3902 };3903 };3904 function resolveComponentType(node, context, ssr = false) {3905 let { tag } = node;3906 // 1. dynamic component3907 const isExplicitDynamic = isComponentTag(tag);3908 const isProp = findProp(node, 'is');3909 if (isProp) {3910 if (isExplicitDynamic ||3911 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) {3912 const exp = isProp.type === 6 /* ATTRIBUTE */3913 ? isProp.value && createSimpleExpression(isProp.value.content, true)3914 : isProp.exp;3915 if (exp) {3916 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [3917 exp3918 ]);3919 }3920 }3921 else if (isProp.type === 6 /* ATTRIBUTE */ &&3922 isProp.value.content.startsWith('vue:')) {3923 // <button is="vue:xxx">3924 // if not <component>, only is value that starts with "vue:" will be3925 // treated as component by the parse phase and reach here, unless it's3926 // compat mode where all is values are considered components3927 tag = isProp.value.content.slice(4);3928 }3929 }3930 // 1.5 v-is (TODO: Deprecate)3931 const isDir = !isExplicitDynamic && findDir(node, 'is');3932 if (isDir && isDir.exp) {3933 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [3934 isDir.exp3935 ]);3936 }3937 // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)3938 const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);3939 if (builtIn) {3940 // built-ins are simply fallthroughs / have special handling during ssr3941 // so we don't need to import their runtime equivalents3942 if (!ssr)3943 context.helper(builtIn);3944 return builtIn;3945 }3946 // 5. user component (resolve)3947 context.helper(RESOLVE_COMPONENT);3948 context.components.add(tag);3949 return toValidAssetId(tag, `component`);3950 }3951 function buildProps(node, context, props = node.props, ssr = false) {3952 const { tag, loc: elementLoc, children } = node;3953 const isComponent = node.tagType === 1 /* COMPONENT */;3954 let properties = [];3955 const mergeArgs = [];3956 const runtimeDirectives = [];3957 const hasChildren = children.length > 0;3958 let shouldUseBlock = false;3959 // patchFlag analysis3960 let patchFlag = 0;3961 let hasRef = false;3962 let hasClassBinding = false;3963 let hasStyleBinding = false;3964 let hasHydrationEventBinding = false;3965 let hasDynamicKeys = false;3966 let hasVnodeHook = false;3967 const dynamicPropNames = [];3968 const analyzePatchFlag = ({ key, value }) => {3969 if (isStaticExp(key)) {3970 const name = key.content;3971 const isEventHandler = isOn(name);3972 if (!isComponent &&3973 isEventHandler &&3974 // omit the flag for click handlers because hydration gives click3975 // dedicated fast path.3976 name.toLowerCase() !== 'onclick' &&3977 // omit v-model handlers3978 name !== 'onUpdate:modelValue' &&3979 // omit onVnodeXXX hooks3980 !isReservedProp(name)) {3981 hasHydrationEventBinding = true;3982 }3983 if (isEventHandler && isReservedProp(name)) {3984 hasVnodeHook = true;3985 }3986 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||3987 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||3988 value.type === 8 /* COMPOUND_EXPRESSION */) &&3989 getConstantType(value, context) > 0)) {3990 // skip if the prop is a cached handler or has constant value3991 return;3992 }3993 if (name === 'ref') {3994 hasRef = true;3995 }3996 else if (name === 'class') {3997 hasClassBinding = true;3998 }3999 else if (name === 'style') {4000 hasStyleBinding = true;4001 }4002 else if (name !== 'key' && !dynamicPropNames.includes(name)) {4003 dynamicPropNames.push(name);4004 }4005 // treat the dynamic class and style binding of the component as dynamic props4006 if (isComponent &&4007 (name === 'class' || name === 'style') &&4008 !dynamicPropNames.includes(name)) {4009 dynamicPropNames.push(name);4010 }4011 }4012 else {4013 hasDynamicKeys = true;4014 }4015 };4016 for (let i = 0; i < props.length; i++) {4017 // static attribute4018 const prop = props[i];4019 if (prop.type === 6 /* ATTRIBUTE */) {4020 const { loc, name, value } = prop;4021 let isStatic = true;4022 if (name === 'ref') {4023 hasRef = true;4024 if (context.scopes.vFor > 0) {4025 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));4026 }4027 }4028 // skip is on <component>, or is="vue:xxx"4029 if (name === 'is' &&4030 (isComponentTag(tag) ||4031 (value && value.content.startsWith('vue:')) ||4032 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) {4033 continue;4034 }4035 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));4036 }4037 else {4038 // directives4039 const { name, arg, exp, loc } = prop;4040 const isVBind = name === 'bind';4041 const isVOn = name === 'on';4042 // skip v-slot - it is handled by its dedicated transform.4043 if (name === 'slot') {4044 if (!isComponent) {4045 context.onError(createCompilerError(40 /* X_V_SLOT_MISPLACED */, loc));4046 }4047 continue;4048 }4049 // skip v-once/v-memo - they are handled by dedicated transforms.4050 if (name === 'once' || name === 'memo') {4051 continue;4052 }4053 // skip v-is and :is on <component>4054 if (name === 'is' ||4055 (isVBind &&4056 isStaticArgOf(arg, 'is') &&4057 (isComponentTag(tag) ||4058 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) {4059 continue;4060 }4061 // skip v-on in SSR compilation4062 if (isVOn && ssr) {4063 continue;4064 }4065 if (4066 // #938: elements with dynamic keys should be forced into blocks4067 (isVBind && isStaticArgOf(arg, 'key')) ||4068 // inline before-update hooks need to force block so that it is invoked4069 // before children4070 (isVOn && hasChildren && isStaticArgOf(arg, 'vue:before-update'))) {4071 shouldUseBlock = true;4072 }4073 if (isVBind && isStaticArgOf(arg, 'ref') && context.scopes.vFor > 0) {4074 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));4075 }4076 // special case for v-bind and v-on with no argument4077 if (!arg && (isVBind || isVOn)) {4078 hasDynamicKeys = true;4079 if (exp) {4080 if (properties.length) {4081 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));4082 properties = [];4083 }4084 if (isVBind) {4085 {4086 // 2.x v-bind object order compat4087 {4088 const hasOverridableKeys = mergeArgs.some(arg => {4089 if (arg.type === 15 /* JS_OBJECT_EXPRESSION */) {4090 return arg.properties.some(({ key }) => {4091 if (key.type !== 4 /* SIMPLE_EXPRESSION */ ||4092 !key.isStatic) {4093 return true;4094 }4095 return (key.content !== 'class' &&4096 key.content !== 'style' &&4097 !isOn(key.content));4098 });4099 }4100 else {4101 // dynamic expression4102 return true;4103 }4104 });4105 if (hasOverridableKeys) {4106 checkCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context, loc);4107 }4108 }4109 if (isCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context)) {4110 mergeArgs.unshift(exp);4111 continue;4112 }4113 }4114 mergeArgs.push(exp);4115 }4116 else {4117 // v-on="obj" -> toHandlers(obj)4118 mergeArgs.push({4119 type: 14 /* JS_CALL_EXPRESSION */,4120 loc,4121 callee: context.helper(TO_HANDLERS),4122 arguments: [exp]4123 });4124 }4125 }4126 else {4127 context.onError(createCompilerError(isVBind4128 ? 34 /* X_V_BIND_NO_EXPRESSION */4129 : 35 /* X_V_ON_NO_EXPRESSION */, loc));4130 }4131 continue;4132 }4133 const directiveTransform = context.directiveTransforms[name];4134 if (directiveTransform) {4135 // has built-in directive transform.4136 const { props, needRuntime } = directiveTransform(prop, node, context);4137 !ssr && props.forEach(analyzePatchFlag);4138 properties.push(...props);4139 if (needRuntime) {4140 runtimeDirectives.push(prop);4141 if (isSymbol(needRuntime)) {4142 directiveImportMap.set(prop, needRuntime);4143 }4144 }4145 }4146 else {4147 // no built-in transform, this is a user custom directive.4148 runtimeDirectives.push(prop);4149 // custom dirs may use beforeUpdate so they need to force blocks4150 // to ensure before-update gets called before children update4151 if (hasChildren) {4152 shouldUseBlock = true;4153 }4154 }4155 }4156 }4157 let propsExpression = undefined;4158 // has v-bind="object" or v-on="object", wrap with mergeProps4159 if (mergeArgs.length) {4160 if (properties.length) {4161 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));4162 }4163 if (mergeArgs.length > 1) {4164 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);4165 }4166 else {4167 // single v-bind with nothing else - no need for a mergeProps call4168 propsExpression = mergeArgs[0];4169 }4170 }4171 else if (properties.length) {4172 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);4173 }4174 // patchFlag analysis4175 if (hasDynamicKeys) {4176 patchFlag |= 16 /* FULL_PROPS */;4177 }4178 else {4179 if (hasClassBinding && !isComponent) {4180 patchFlag |= 2 /* CLASS */;4181 }4182 if (hasStyleBinding && !isComponent) {4183 patchFlag |= 4 /* STYLE */;4184 }4185 if (dynamicPropNames.length) {4186 patchFlag |= 8 /* PROPS */;4187 }4188 if (hasHydrationEventBinding) {4189 patchFlag |= 32 /* HYDRATE_EVENTS */;4190 }4191 }4192 if (!shouldUseBlock &&4193 (patchFlag === 0 || patchFlag === 32 /* HYDRATE_EVENTS */) &&4194 (hasRef || hasVnodeHook || runtimeDirectives.length > 0)) {4195 patchFlag |= 512 /* NEED_PATCH */;4196 }4197 // pre-normalize props, SSR is skipped for now4198 if (!context.inSSR && propsExpression) {4199 switch (propsExpression.type) {4200 case 15 /* JS_OBJECT_EXPRESSION */:4201 // means that there is no v-bind,4202 // but still need to deal with dynamic key binding4203 let classKeyIndex = -1;4204 let styleKeyIndex = -1;4205 let hasDynamicKey = false;4206 for (let i = 0; i < propsExpression.properties.length; i++) {4207 const key = propsExpression.properties[i].key;4208 if (isStaticExp(key)) {4209 if (key.content === 'class') {4210 classKeyIndex = i;4211 }4212 else if (key.content === 'style') {4213 styleKeyIndex = i;4214 }4215 }4216 else if (!key.isHandlerKey) {4217 hasDynamicKey = true;4218 }4219 }4220 const classProp = propsExpression.properties[classKeyIndex];4221 const styleProp = propsExpression.properties[styleKeyIndex];4222 // no dynamic key4223 if (!hasDynamicKey) {4224 if (classProp && !isStaticExp(classProp.value)) {4225 classProp.value = createCallExpression(context.helper(NORMALIZE_CLASS), [classProp.value]);4226 }4227 if (styleProp &&4228 !isStaticExp(styleProp.value) &&4229 // the static style is compiled into an object,4230 // so use `hasStyleBinding` to ensure that it is a dynamic style binding4231 (hasStyleBinding ||4232 // v-bind:style and style both exist,4233 // v-bind:style with static literal object4234 styleProp.value.type === 17 /* JS_ARRAY_EXPRESSION */)) {4235 styleProp.value = createCallExpression(context.helper(NORMALIZE_STYLE), [styleProp.value]);4236 }4237 }4238 else {4239 // dynamic key binding, wrap with `normalizeProps`4240 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [propsExpression]);4241 }4242 break;4243 case 14 /* JS_CALL_EXPRESSION */:4244 // mergeProps call, do nothing4245 break;4246 default:4247 // single v-bind4248 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [4249 createCallExpression(context.helper(GUARD_REACTIVE_PROPS), [4250 propsExpression4251 ])4252 ]);4253 break;4254 }4255 }4256 return {4257 props: propsExpression,4258 directives: runtimeDirectives,4259 patchFlag,4260 dynamicPropNames,4261 shouldUseBlock4262 };4263 }4264 // Dedupe props in an object literal.4265 // Literal duplicated attributes would have been warned during the parse phase,4266 // however, it's possible to encounter duplicated `onXXX` handlers with different4267 // modifiers. We also need to merge static and dynamic class / style attributes.4268 // - onXXX handlers / style: merge into array4269 // - class: merge into single expression with concatenation4270 function dedupeProperties(properties) {4271 const knownProps = new Map();4272 const deduped = [];4273 for (let i = 0; i < properties.length; i++) {4274 const prop = properties[i];4275 // dynamic keys are always allowed4276 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {4277 deduped.push(prop);4278 continue;4279 }4280 const name = prop.key.content;4281 const existing = knownProps.get(name);4282 if (existing) {4283 if (name === 'style' || name === 'class' || isOn(name)) {4284 mergeAsArray(existing, prop);4285 }4286 // unexpected duplicate, should have emitted error during parse4287 }4288 else {4289 knownProps.set(name, prop);4290 deduped.push(prop);4291 }4292 }4293 return deduped;4294 }4295 function mergeAsArray(existing, incoming) {4296 if (existing.value.type === 17 /* JS_ARRAY_EXPRESSION */) {4297 existing.value.elements.push(incoming.value);4298 }4299 else {4300 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);4301 }4302 }4303 function buildDirectiveArgs(dir, context) {4304 const dirArgs = [];4305 const runtime = directiveImportMap.get(dir);4306 if (runtime) {4307 // built-in directive with runtime4308 dirArgs.push(context.helperString(runtime));4309 }4310 else {4311 {4312 // inject statement for resolving directive4313 context.helper(RESOLVE_DIRECTIVE);4314 context.directives.add(dir.name);4315 dirArgs.push(toValidAssetId(dir.name, `directive`));4316 }4317 }4318 const { loc } = dir;4319 if (dir.exp)4320 dirArgs.push(dir.exp);4321 if (dir.arg) {4322 if (!dir.exp) {4323 dirArgs.push(`void 0`);4324 }4325 dirArgs.push(dir.arg);4326 }4327 if (Object.keys(dir.modifiers).length) {4328 if (!dir.arg) {4329 if (!dir.exp) {4330 dirArgs.push(`void 0`);4331 }4332 dirArgs.push(`void 0`);4333 }4334 const trueExpression = createSimpleExpression(`true`, false, loc);4335 dirArgs.push(createObjectExpression(dir.modifiers.map(modifier => createObjectProperty(modifier, trueExpression)), loc));4336 }4337 return createArrayExpression(dirArgs, dir.loc);4338 }4339 function stringifyDynamicPropNames(props) {4340 let propsNamesString = `[`;4341 for (let i = 0, l = props.length; i < l; i++) {4342 propsNamesString += JSON.stringify(props[i]);4343 if (i < l - 1)4344 propsNamesString += ', ';4345 }4346 return propsNamesString + `]`;4347 }4348 function isComponentTag(tag) {4349 return tag === 'component' || tag === 'Component';4350 }4351 const transformSlotOutlet = (node, context) => {4352 if (isSlotOutlet(node)) {4353 const { children, loc } = node;4354 const { slotName, slotProps } = processSlotOutlet(node, context);4355 const slotArgs = [4356 context.prefixIdentifiers ? `_ctx.$slots` : `$slots`,4357 slotName,4358 '{}',4359 'undefined',4360 'true'4361 ];4362 let expectedLen = 2;4363 if (slotProps) {4364 slotArgs[2] = slotProps;4365 expectedLen = 3;4366 }4367 if (children.length) {4368 slotArgs[3] = createFunctionExpression([], children, false, false, loc);4369 expectedLen = 4;4370 }4371 if (context.scopeId && !context.slotted) {4372 expectedLen = 5;4373 }4374 slotArgs.splice(expectedLen); // remove unused arguments4375 node.codegenNode = createCallExpression(context.helper(RENDER_SLOT), slotArgs, loc);4376 }4377 };4378 function processSlotOutlet(node, context) {4379 let slotName = `"default"`;4380 let slotProps = undefined;4381 const nonNameProps = [];4382 for (let i = 0; i < node.props.length; i++) {4383 const p = node.props[i];4384 if (p.type === 6 /* ATTRIBUTE */) {4385 if (p.value) {4386 if (p.name === 'name') {4387 slotName = JSON.stringify(p.value.content);4388 }4389 else {4390 p.name = camelize(p.name);4391 nonNameProps.push(p);4392 }4393 }4394 }4395 else {4396 if (p.name === 'bind' && isStaticArgOf(p.arg, 'name')) {4397 if (p.exp)4398 slotName = p.exp;4399 }4400 else {4401 if (p.name === 'bind' && p.arg && isStaticExp(p.arg)) {4402 p.arg.content = camelize(p.arg.content);4403 }4404 nonNameProps.push(p);4405 }4406 }4407 }4408 if (nonNameProps.length > 0) {4409 const { props, directives } = buildProps(node, context, nonNameProps);4410 slotProps = props;4411 if (directives.length) {4412 context.onError(createCompilerError(36 /* X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET */, directives[0].loc));4413 }4414 }4415 return {4416 slotName,4417 slotProps4418 };4419 }4420 const fnExpRE = /^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/;4421 const transformOn = (dir, node, context, augmentor) => {4422 const { loc, modifiers, arg } = dir;4423 if (!dir.exp && !modifiers.length) {4424 context.onError(createCompilerError(35 /* X_V_ON_NO_EXPRESSION */, loc));4425 }4426 let eventName;4427 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4428 if (arg.isStatic) {4429 let rawName = arg.content;4430 // TODO deprecate @vnodeXXX usage4431 if (rawName.startsWith('vue:')) {4432 rawName = `vnode-${rawName.slice(4)}`;4433 }4434 // for all event listeners, auto convert it to camelCase. See issue #22494435 eventName = createSimpleExpression(toHandlerKey(camelize(rawName)), true, arg.loc);4436 }4437 else {4438 // #23884439 eventName = createCompoundExpression([4440 `${context.helperString(TO_HANDLER_KEY)}(`,4441 arg,4442 `)`4443 ]);4444 }4445 }4446 else {4447 // already a compound expression.4448 eventName = arg;4449 eventName.children.unshift(`${context.helperString(TO_HANDLER_KEY)}(`);4450 eventName.children.push(`)`);4451 }4452 // handler processing4453 let exp = dir.exp;4454 if (exp && !exp.content.trim()) {4455 exp = undefined;4456 }4457 let shouldCache = context.cacheHandlers && !exp && !context.inVOnce;4458 if (exp) {4459 const isMemberExp = isMemberExpression(exp.content);4460 const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content));4461 const hasMultipleStatements = exp.content.includes(`;`);4462 {4463 validateBrowserExpression(exp, context, false, hasMultipleStatements);4464 }4465 if (isInlineStatement || (shouldCache && isMemberExp)) {4466 // wrap inline statement in a function expression4467 exp = createCompoundExpression([4468 `${isInlineStatement4469 ? `$event`4470 : `${``}(...args)`} => ${hasMultipleStatements ? `{` : `(`}`,4471 exp,4472 hasMultipleStatements ? `}` : `)`4473 ]);4474 }4475 }4476 let ret = {4477 props: [4478 createObjectProperty(eventName, exp || createSimpleExpression(`() => {}`, false, loc))4479 ]4480 };4481 // apply extended compiler augmentor4482 if (augmentor) {4483 ret = augmentor(ret);4484 }4485 if (shouldCache) {4486 // cache handlers so that it's always the same handler being passed down.4487 // this avoids unnecessary re-renders when users use inline handlers on4488 // components.4489 ret.props[0].value = context.cache(ret.props[0].value);4490 }4491 // mark the key as handler for props normalization check4492 ret.props.forEach(p => (p.key.isHandlerKey = true));4493 return ret;4494 };4495 // v-bind without arg is handled directly in ./transformElements.ts due to it affecting4496 // codegen for the entire props object. This transform here is only for v-bind4497 // *with* args.4498 const transformBind = (dir, _node, context) => {4499 const { exp, modifiers, loc } = dir;4500 const arg = dir.arg;4501 if (arg.type !== 4 /* SIMPLE_EXPRESSION */) {4502 arg.children.unshift(`(`);4503 arg.children.push(`) || ""`);4504 }4505 else if (!arg.isStatic) {4506 arg.content = `${arg.content} || ""`;4507 }4508 // .sync is replaced by v-model:arg4509 if (modifiers.includes('camel')) {4510 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4511 if (arg.isStatic) {4512 arg.content = camelize(arg.content);4513 }4514 else {4515 arg.content = `${context.helperString(CAMELIZE)}(${arg.content})`;4516 }4517 }4518 else {4519 arg.children.unshift(`${context.helperString(CAMELIZE)}(`);4520 arg.children.push(`)`);4521 }4522 }4523 if (!context.inSSR) {4524 if (modifiers.includes('prop')) {4525 injectPrefix(arg, '.');4526 }4527 if (modifiers.includes('attr')) {4528 injectPrefix(arg, '^');4529 }4530 }4531 if (!exp ||4532 (exp.type === 4 /* SIMPLE_EXPRESSION */ && !exp.content.trim())) {4533 context.onError(createCompilerError(34 /* X_V_BIND_NO_EXPRESSION */, loc));4534 return {4535 props: [createObjectProperty(arg, createSimpleExpression('', true, loc))]4536 };4537 }4538 return {4539 props: [createObjectProperty(arg, exp)]4540 };4541 };4542 const injectPrefix = (arg, prefix) => {4543 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4544 if (arg.isStatic) {4545 arg.content = prefix + arg.content;4546 }4547 else {4548 arg.content = `\`${prefix}\${${arg.content}}\``;4549 }4550 }4551 else {4552 arg.children.unshift(`'${prefix}' + (`);4553 arg.children.push(`)`);4554 }4555 };4556 // Merge adjacent text nodes and expressions into a single expression4557 // e.g. <div>abc {{ d }} {{ e }}</div> should have a single expression node as child.4558 const transformText = (node, context) => {4559 if (node.type === 0 /* ROOT */ ||4560 node.type === 1 /* ELEMENT */ ||4561 node.type === 11 /* FOR */ ||4562 node.type === 10 /* IF_BRANCH */) {4563 // perform the transform on node exit so that all expressions have already4564 // been processed.4565 return () => {4566 const children = node.children;4567 let currentContainer = undefined;4568 let hasText = false;4569 for (let i = 0; i < children.length; i++) {4570 const child = children[i];4571 if (isText(child)) {4572 hasText = true;4573 for (let j = i + 1; j < children.length; j++) {4574 const next = children[j];4575 if (isText(next)) {4576 if (!currentContainer) {4577 currentContainer = children[i] = {4578 type: 8 /* COMPOUND_EXPRESSION */,4579 loc: child.loc,4580 children: [child]4581 };4582 }4583 // merge adjacent text node into current4584 currentContainer.children.push(` + `, next);4585 children.splice(j, 1);4586 j--;4587 }4588 else {4589 currentContainer = undefined;4590 break;4591 }4592 }4593 }4594 }4595 if (!hasText ||4596 // if this is a plain element with a single text child, leave it4597 // as-is since the runtime has dedicated fast path for this by directly4598 // setting textContent of the element.4599 // for component root it's always normalized anyway.4600 (children.length === 1 &&4601 (node.type === 0 /* ROOT */ ||4602 (node.type === 1 /* ELEMENT */ &&4603 node.tagType === 0 /* ELEMENT */ &&4604 // #37564605 // custom directives can potentially add DOM elements arbitrarily,4606 // we need to avoid setting textContent of the element at runtime4607 // to avoid accidentally overwriting the DOM elements added4608 // by the user through custom directives.4609 !node.props.find(p => p.type === 7 /* DIRECTIVE */ &&4610 !context.directiveTransforms[p.name]) &&4611 // in compat mode, <template> tags with no special directives4612 // will be rendered as a fragment so its children must be4613 // converted into vnodes.4614 !(node.tag === 'template'))))) {4615 return;4616 }4617 // pre-convert text nodes into createTextVNode(text) calls to avoid4618 // runtime normalization.4619 for (let i = 0; i < children.length; i++) {4620 const child = children[i];4621 if (isText(child) || child.type === 8 /* COMPOUND_EXPRESSION */) {4622 const callArgs = [];4623 // createTextVNode defaults to single whitespace, so if it is a4624 // single space the code could be an empty call to save bytes.4625 if (child.type !== 2 /* TEXT */ || child.content !== ' ') {4626 callArgs.push(child);4627 }4628 // mark dynamic text with flag so it gets patched inside a block4629 if (!context.ssr &&4630 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {4631 callArgs.push(1 /* TEXT */ +4632 (` /* ${PatchFlagNames[1 /* TEXT */]} */` ));4633 }4634 children[i] = {4635 type: 12 /* TEXT_CALL */,4636 content: child,4637 loc: child.loc,4638 codegenNode: createCallExpression(context.helper(CREATE_TEXT), callArgs)4639 };4640 }4641 }4642 };4643 }4644 };4645 const seen = new WeakSet();4646 const transformOnce = (node, context) => {4647 if (node.type === 1 /* ELEMENT */ && findDir(node, 'once', true)) {4648 if (seen.has(node) || context.inVOnce) {4649 return;4650 }4651 seen.add(node);4652 context.inVOnce = true;4653 context.helper(SET_BLOCK_TRACKING);4654 return () => {4655 context.inVOnce = false;4656 const cur = context.currentNode;4657 if (cur.codegenNode) {4658 cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */);4659 }4660 };4661 }4662 };4663 const transformModel = (dir, node, context) => {4664 const { exp, arg } = dir;4665 if (!exp) {4666 context.onError(createCompilerError(41 /* X_V_MODEL_NO_EXPRESSION */, dir.loc));4667 return createTransformProps();4668 }4669 const rawExp = exp.loc.source;4670 const expString = exp.type === 4 /* SIMPLE_EXPRESSION */ ? exp.content : rawExp;4671 // im SFC <script setup> inline mode, the exp may have been transformed into4672 // _unref(exp)4673 context.bindingMetadata[rawExp];4674 const maybeRef = !true /* SETUP_CONST */;4675 if (!expString.trim() ||4676 (!isMemberExpression(expString) && !maybeRef)) {4677 context.onError(createCompilerError(42 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));4678 return createTransformProps();4679 }4680 const propName = arg ? arg : createSimpleExpression('modelValue', true);4681 const eventName = arg4682 ? isStaticExp(arg)4683 ? `onUpdate:${arg.content}`4684 : createCompoundExpression(['"onUpdate:" + ', arg])4685 : `onUpdate:modelValue`;4686 let assignmentExp;4687 const eventArg = context.isTS ? `($event: any)` : `$event`;4688 {4689 assignmentExp = createCompoundExpression([4690 `${eventArg} => ((`,4691 exp,4692 `) = $event)`4693 ]);4694 }4695 const props = [4696 // modelValue: foo4697 createObjectProperty(propName, dir.exp),4698 // "onUpdate:modelValue": $event => (foo = $event)4699 createObjectProperty(eventName, assignmentExp)4700 ];4701 // modelModifiers: { foo: true, "bar-baz": true }4702 if (dir.modifiers.length && node.tagType === 1 /* COMPONENT */) {4703 const modifiers = dir.modifiers4704 .map(m => (isSimpleIdentifier(m) ? m : JSON.stringify(m)) + `: true`)4705 .join(`, `);4706 const modifiersKey = arg4707 ? isStaticExp(arg)4708 ? `${arg.content}Modifiers`4709 : createCompoundExpression([arg, ' + "Modifiers"'])4710 : `modelModifiers`;4711 props.push(createObjectProperty(modifiersKey, createSimpleExpression(`{ ${modifiers} }`, false, dir.loc, 2 /* CAN_HOIST */)));4712 }4713 return createTransformProps(props);4714 };4715 function createTransformProps(props = []) {4716 return { props };4717 }4718 const validDivisionCharRE = /[\w).+\-_$\]]/;4719 const transformFilter = (node, context) => {4720 if (!isCompatEnabled("COMPILER_FILTER" /* COMPILER_FILTERS */, context)) {4721 return;4722 }4723 if (node.type === 5 /* INTERPOLATION */) {4724 // filter rewrite is applied before expression transform so only4725 // simple expressions are possible at this stage4726 rewriteFilter(node.content, context);4727 }4728 if (node.type === 1 /* ELEMENT */) {4729 node.props.forEach((prop) => {4730 if (prop.type === 7 /* DIRECTIVE */ &&4731 prop.name !== 'for' &&4732 prop.exp) {4733 rewriteFilter(prop.exp, context);4734 }...
compiler-core.cjs.js
Source:compiler-core.cjs.js
...787 else {788 return value;789 }790}791function isCompatEnabled(key, context) {792 const mode = getCompatValue('MODE', context);793 const value = getCompatValue(key, context);794 // in v3 mode, only enable if explicitly set to true795 // otherwise enable for any non-false value796 return mode === 3 ? value === true : value !== false;797}798function checkCompatEnabled(key, context, loc, ...args) {799 const enabled = isCompatEnabled(key, context);800 if (enabled) {801 warnDeprecation(key, context, loc, ...args);802 }803 return enabled;804}805function warnDeprecation(key, context, loc, ...args) {806 const val = getCompatValue(key, context);807 if (val === 'suppress-warning') {808 return;809 }810 const { message, link } = deprecationData[key];811 const msg = `(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`;812 const err = new SyntaxError(msg);813 err.code = key;814 if (loc)815 err.loc = loc;816 context.onWarn(err);817}818// The default decoder only provides escapes for characters reserved as part of819// the template syntax, and is only used if the custom renderer did not provide820// a platform-specific decoder.821const decodeRE = /&(gt|lt|amp|apos|quot);/g;822const decodeMap = {823 gt: '>',824 lt: '<',825 amp: '&',826 apos: "'",827 quot: '"'828};829const defaultParserOptions = {830 delimiters: [`{{`, `}}`],831 getNamespace: () => 0 /* HTML */,832 getTextMode: () => 0 /* DATA */,833 isVoidTag: shared.NO,834 isPreTag: shared.NO,835 isCustomElement: shared.NO,836 decodeEntities: (rawText) => rawText.replace(decodeRE, (_, p1) => decodeMap[p1]),837 onError: defaultOnError,838 onWarn: defaultOnWarn,839 comments: true840};841function baseParse(content, options = {}) {842 const context = createParserContext(content, options);843 const start = getCursor(context);844 return createRoot(parseChildren(context, 0 /* DATA */, []), getSelection(context, start));845}846function createParserContext(content, rawOptions) {847 const options = shared.extend({}, defaultParserOptions);848 let key;849 for (key in rawOptions) {850 // @ts-ignore851 options[key] =852 rawOptions[key] === undefined853 ? defaultParserOptions[key]854 : rawOptions[key];855 }856 return {857 options,858 column: 1,859 line: 1,860 offset: 0,861 originalSource: content,862 source: content,863 inPre: false,864 inVPre: false,865 onWarn: options.onWarn866 };867}868function parseChildren(context, mode, ancestors) {869 const parent = last(ancestors);870 const ns = parent ? parent.ns : 0 /* HTML */;871 const nodes = [];872 while (!isEnd(context, mode, ancestors)) {873 const s = context.source;874 let node = undefined;875 if (mode === 0 /* DATA */ || mode === 1 /* RCDATA */) {876 if (!context.inVPre && startsWith(s, context.options.delimiters[0])) {877 // '{{'878 node = parseInterpolation(context, mode);879 }880 else if (mode === 0 /* DATA */ && s[0] === '<') {881 // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state882 if (s.length === 1) {883 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 1);884 }885 else if (s[1] === '!') {886 // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state887 if (startsWith(s, '<!--')) {888 node = parseComment(context);889 }890 else if (startsWith(s, '<!DOCTYPE')) {891 // Ignore DOCTYPE by a limitation.892 node = parseBogusComment(context);893 }894 else if (startsWith(s, '<![CDATA[')) {895 if (ns !== 0 /* HTML */) {896 node = parseCDATA(context, ancestors);897 }898 else {899 emitError(context, 1 /* CDATA_IN_HTML_CONTENT */);900 node = parseBogusComment(context);901 }902 }903 else {904 emitError(context, 11 /* INCORRECTLY_OPENED_COMMENT */);905 node = parseBogusComment(context);906 }907 }908 else if (s[1] === '/') {909 // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state910 if (s.length === 2) {911 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 2);912 }913 else if (s[2] === '>') {914 emitError(context, 14 /* MISSING_END_TAG_NAME */, 2);915 advanceBy(context, 3);916 continue;917 }918 else if (/[a-z]/i.test(s[2])) {919 emitError(context, 23 /* X_INVALID_END_TAG */);920 parseTag(context, 1 /* End */, parent);921 continue;922 }923 else {924 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 2);925 node = parseBogusComment(context);926 }927 }928 else if (/[a-z]/i.test(s[1])) {929 node = parseElement(context, ancestors);930 // 2.x <template> with no directive compat931 if (isCompatEnabled("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context) &&932 node &&933 node.tag === 'template' &&934 !node.props.some(p => p.type === 7 /* DIRECTIVE */ &&935 isSpecialTemplateDirective(p.name))) {936 warnDeprecation("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context, node.loc);937 node = node.children;938 }939 }940 else if (s[1] === '?') {941 emitError(context, 21 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */, 1);942 node = parseBogusComment(context);943 }944 else {945 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 1);946 }947 }948 }949 if (!node) {950 node = parseText(context, mode);951 }952 if (shared.isArray(node)) {953 for (let i = 0; i < node.length; i++) {954 pushNode(nodes, node[i]);955 }956 }957 else {958 pushNode(nodes, node);959 }960 }961 // Whitespace handling strategy like v2962 let removedWhitespace = false;963 if (mode !== 2 /* RAWTEXT */ && mode !== 1 /* RCDATA */) {964 const shouldCondense = context.options.whitespace !== 'preserve';965 for (let i = 0; i < nodes.length; i++) {966 const node = nodes[i];967 if (!context.inPre && node.type === 2 /* TEXT */) {968 if (!/[^\t\r\n\f ]/.test(node.content)) {969 const prev = nodes[i - 1];970 const next = nodes[i + 1];971 // Remove if:972 // - the whitespace is the first or last node, or:973 // - (condense mode) the whitespace is adjacent to a comment, or:974 // - (condense mode) the whitespace is between two elements AND contains newline975 if (!prev ||976 !next ||977 (shouldCondense &&978 (prev.type === 3 /* COMMENT */ ||979 next.type === 3 /* COMMENT */ ||980 (prev.type === 1 /* ELEMENT */ &&981 next.type === 1 /* ELEMENT */ &&982 /[\r\n]/.test(node.content))))) {983 removedWhitespace = true;984 nodes[i] = null;985 }986 else {987 // Otherwise, the whitespace is condensed into a single space988 node.content = ' ';989 }990 }991 else if (shouldCondense) {992 // in condense mode, consecutive whitespaces in text are condensed993 // down to a single space.994 node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ');995 }996 }997 // Remove comment nodes if desired by configuration.998 else if (node.type === 3 /* COMMENT */ && !context.options.comments) {999 removedWhitespace = true;1000 nodes[i] = null;1001 }1002 }1003 if (context.inPre && parent && context.options.isPreTag(parent.tag)) {1004 // remove leading newline per html spec1005 // https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element1006 const first = nodes[0];1007 if (first && first.type === 2 /* TEXT */) {1008 first.content = first.content.replace(/^\r?\n/, '');1009 }1010 }1011 }1012 return removedWhitespace ? nodes.filter(Boolean) : nodes;1013}1014function pushNode(nodes, node) {1015 if (node.type === 2 /* TEXT */) {1016 const prev = last(nodes);1017 // Merge if both this and the previous node are text and those are1018 // consecutive. This happens for cases like "a < b".1019 if (prev &&1020 prev.type === 2 /* TEXT */ &&1021 prev.loc.end.offset === node.loc.start.offset) {1022 prev.content += node.content;1023 prev.loc.end = node.loc.end;1024 prev.loc.source += node.loc.source;1025 return;1026 }1027 }1028 nodes.push(node);1029}1030function parseCDATA(context, ancestors) {1031 advanceBy(context, 9);1032 const nodes = parseChildren(context, 3 /* CDATA */, ancestors);1033 if (context.source.length === 0) {1034 emitError(context, 6 /* EOF_IN_CDATA */);1035 }1036 else {1037 advanceBy(context, 3);1038 }1039 return nodes;1040}1041function parseComment(context) {1042 const start = getCursor(context);1043 let content;1044 // Regular comment.1045 const match = /--(\!)?>/.exec(context.source);1046 if (!match) {1047 content = context.source.slice(4);1048 advanceBy(context, context.source.length);1049 emitError(context, 7 /* EOF_IN_COMMENT */);1050 }1051 else {1052 if (match.index <= 3) {1053 emitError(context, 0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */);1054 }1055 if (match[1]) {1056 emitError(context, 10 /* INCORRECTLY_CLOSED_COMMENT */);1057 }1058 content = context.source.slice(4, match.index);1059 // Advancing with reporting nested comments.1060 const s = context.source.slice(0, match.index);1061 let prevIndex = 1, nestedIndex = 0;1062 while ((nestedIndex = s.indexOf('<!--', prevIndex)) !== -1) {1063 advanceBy(context, nestedIndex - prevIndex + 1);1064 if (nestedIndex + 4 < s.length) {1065 emitError(context, 16 /* NESTED_COMMENT */);1066 }1067 prevIndex = nestedIndex + 1;1068 }1069 advanceBy(context, match.index + match[0].length - prevIndex + 1);1070 }1071 return {1072 type: 3 /* COMMENT */,1073 content,1074 loc: getSelection(context, start)1075 };1076}1077function parseBogusComment(context) {1078 const start = getCursor(context);1079 const contentStart = context.source[1] === '?' ? 1 : 2;1080 let content;1081 const closeIndex = context.source.indexOf('>');1082 if (closeIndex === -1) {1083 content = context.source.slice(contentStart);1084 advanceBy(context, context.source.length);1085 }1086 else {1087 content = context.source.slice(contentStart, closeIndex);1088 advanceBy(context, closeIndex + 1);1089 }1090 return {1091 type: 3 /* COMMENT */,1092 content,1093 loc: getSelection(context, start)1094 };1095}1096function parseElement(context, ancestors) {1097 // Start tag.1098 const wasInPre = context.inPre;1099 const wasInVPre = context.inVPre;1100 const parent = last(ancestors);1101 const element = parseTag(context, 0 /* Start */, parent);1102 const isPreBoundary = context.inPre && !wasInPre;1103 const isVPreBoundary = context.inVPre && !wasInVPre;1104 if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {1105 // #4030 self-closing <pre> tag1106 if (isPreBoundary) {1107 context.inPre = false;1108 }1109 if (isVPreBoundary) {1110 context.inVPre = false;1111 }1112 return element;1113 }1114 // Children.1115 ancestors.push(element);1116 const mode = context.options.getTextMode(element, parent);1117 const children = parseChildren(context, mode, ancestors);1118 ancestors.pop();1119 // 2.x inline-template compat1120 {1121 const inlineTemplateProp = element.props.find(p => p.type === 6 /* ATTRIBUTE */ && p.name === 'inline-template');1122 if (inlineTemplateProp &&1123 checkCompatEnabled("COMPILER_INLINE_TEMPLATE" /* COMPILER_INLINE_TEMPLATE */, context, inlineTemplateProp.loc)) {1124 const loc = getSelection(context, element.loc.end);1125 inlineTemplateProp.value = {1126 type: 2 /* TEXT */,1127 content: loc.source,1128 loc1129 };1130 }1131 }1132 element.children = children;1133 // End tag.1134 if (startsWithEndTagOpen(context.source, element.tag)) {1135 parseTag(context, 1 /* End */, parent);1136 }1137 else {1138 emitError(context, 24 /* X_MISSING_END_TAG */, 0, element.loc.start);1139 if (context.source.length === 0 && element.tag.toLowerCase() === 'script') {1140 const first = children[0];1141 if (first && startsWith(first.loc.source, '<!--')) {1142 emitError(context, 8 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */);1143 }1144 }1145 }1146 element.loc = getSelection(context, element.loc.start);1147 if (isPreBoundary) {1148 context.inPre = false;1149 }1150 if (isVPreBoundary) {1151 context.inVPre = false;1152 }1153 return element;1154}1155const isSpecialTemplateDirective = /*#__PURE__*/ shared.makeMap(`if,else,else-if,for,slot`);1156function parseTag(context, type, parent) {1157 // Tag open.1158 const start = getCursor(context);1159 const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source);1160 const tag = match[1];1161 const ns = context.options.getNamespace(tag, parent);1162 advanceBy(context, match[0].length);1163 advanceSpaces(context);1164 // save current state in case we need to re-parse attributes with v-pre1165 const cursor = getCursor(context);1166 const currentSource = context.source;1167 // check <pre> tag1168 if (context.options.isPreTag(tag)) {1169 context.inPre = true;1170 }1171 // Attributes.1172 let props = parseAttributes(context, type);1173 // check v-pre1174 if (type === 0 /* Start */ &&1175 !context.inVPre &&1176 props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'pre')) {1177 context.inVPre = true;1178 // reset context1179 shared.extend(context, cursor);1180 context.source = currentSource;1181 // re-parse attrs and filter out v-pre itself1182 props = parseAttributes(context, type).filter(p => p.name !== 'v-pre');1183 }1184 // Tag close.1185 let isSelfClosing = false;1186 if (context.source.length === 0) {1187 emitError(context, 9 /* EOF_IN_TAG */);1188 }1189 else {1190 isSelfClosing = startsWith(context.source, '/>');1191 if (type === 1 /* End */ && isSelfClosing) {1192 emitError(context, 4 /* END_TAG_WITH_TRAILING_SOLIDUS */);1193 }1194 advanceBy(context, isSelfClosing ? 2 : 1);1195 }1196 if (type === 1 /* End */) {1197 return;1198 }1199 // 2.x deprecation checks1200 if (isCompatEnabled("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context)) {1201 let hasIf = false;1202 let hasFor = false;1203 for (let i = 0; i < props.length; i++) {1204 const p = props[i];1205 if (p.type === 7 /* DIRECTIVE */) {1206 if (p.name === 'if') {1207 hasIf = true;1208 }1209 else if (p.name === 'for') {1210 hasFor = true;1211 }1212 }1213 if (hasIf && hasFor) {1214 warnDeprecation("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context, getSelection(context, start));1215 break;1216 }1217 }1218 }1219 let tagType = 0 /* ELEMENT */;1220 if (!context.inVPre) {1221 if (tag === 'slot') {1222 tagType = 2 /* SLOT */;1223 }1224 else if (tag === 'template') {1225 if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {1226 tagType = 3 /* TEMPLATE */;1227 }1228 }1229 else if (isComponent(tag, props, context)) {1230 tagType = 1 /* COMPONENT */;1231 }1232 }1233 return {1234 type: 1 /* ELEMENT */,1235 ns,1236 tag,1237 tagType,1238 props,1239 isSelfClosing,1240 children: [],1241 loc: getSelection(context, start),1242 codegenNode: undefined // to be created during transform phase1243 };1244}1245function isComponent(tag, props, context) {1246 const options = context.options;1247 if (options.isCustomElement(tag)) {1248 return false;1249 }1250 if (tag === 'component' ||1251 /^[A-Z]/.test(tag) ||1252 isCoreComponent(tag) ||1253 (options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||1254 (options.isNativeTag && !options.isNativeTag(tag))) {1255 return true;1256 }1257 // at this point the tag should be a native tag, but check for potential "is"1258 // casting1259 for (let i = 0; i < props.length; i++) {1260 const p = props[i];1261 if (p.type === 6 /* ATTRIBUTE */) {1262 if (p.name === 'is' && p.value) {1263 if (p.value.content.startsWith('vue:')) {1264 return true;1265 }1266 else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1267 return true;1268 }1269 }1270 }1271 else {1272 // directive1273 // v-is (TODO Deprecate)1274 if (p.name === 'is') {1275 return true;1276 }1277 else if (1278 // :is on plain element - only treat as component in compat mode1279 p.name === 'bind' &&1280 isStaticArgOf(p.arg, 'is') &&1281 true &&1282 checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1283 return true;1284 }1285 }1286 }1287}1288function parseAttributes(context, type) {1289 const props = [];1290 const attributeNames = new Set();1291 while (context.source.length > 0 &&1292 !startsWith(context.source, '>') &&1293 !startsWith(context.source, '/>')) {1294 if (startsWith(context.source, '/')) {1295 emitError(context, 22 /* UNEXPECTED_SOLIDUS_IN_TAG */);1296 advanceBy(context, 1);1297 advanceSpaces(context);1298 continue;1299 }1300 if (type === 1 /* End */) {1301 emitError(context, 3 /* END_TAG_WITH_ATTRIBUTES */);1302 }1303 const attr = parseAttribute(context, attributeNames);1304 // Trim whitespace between class1305 // https://github.com/vuejs/vue-next/issues/42511306 if (attr.type === 6 /* ATTRIBUTE */ &&1307 attr.value &&1308 attr.name === 'class') {1309 attr.value.content = attr.value.content.replace(/\s+/g, ' ').trim();1310 }1311 if (type === 0 /* Start */) {1312 props.push(attr);1313 }1314 if (/^[^\t\r\n\f />]/.test(context.source)) {1315 emitError(context, 15 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */);1316 }1317 advanceSpaces(context);1318 }1319 return props;1320}1321function parseAttribute(context, nameSet) {1322 // Name.1323 const start = getCursor(context);1324 const match = /^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(context.source);1325 const name = match[0];1326 if (nameSet.has(name)) {1327 emitError(context, 2 /* DUPLICATE_ATTRIBUTE */);1328 }1329 nameSet.add(name);1330 if (name[0] === '=') {1331 emitError(context, 19 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */);1332 }1333 {1334 const pattern = /["'<]/g;1335 let m;1336 while ((m = pattern.exec(name))) {1337 emitError(context, 17 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */, m.index);1338 }1339 }1340 advanceBy(context, name.length);1341 // Value1342 let value = undefined;1343 if (/^[\t\r\n\f ]*=/.test(context.source)) {1344 advanceSpaces(context);1345 advanceBy(context, 1);1346 advanceSpaces(context);1347 value = parseAttributeValue(context);1348 if (!value) {1349 emitError(context, 13 /* MISSING_ATTRIBUTE_VALUE */);1350 }1351 }1352 const loc = getSelection(context, start);1353 if (!context.inVPre && /^(v-[A-Za-z0-9-]|:|\.|@|#)/.test(name)) {1354 const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^\.|^@|^#)(\[[^\]]+\]|[^\.]+))?(.+)?$/i.exec(name);1355 let isPropShorthand = startsWith(name, '.');1356 let dirName = match[1] ||1357 (isPropShorthand || startsWith(name, ':')1358 ? 'bind'1359 : startsWith(name, '@')1360 ? 'on'1361 : 'slot');1362 let arg;1363 if (match[2]) {1364 const isSlot = dirName === 'slot';1365 const startOffset = name.lastIndexOf(match[2]);1366 const loc = getSelection(context, getNewPosition(context, start, startOffset), getNewPosition(context, start, startOffset + match[2].length + ((isSlot && match[3]) || '').length));1367 let content = match[2];1368 let isStatic = true;1369 if (content.startsWith('[')) {1370 isStatic = false;1371 if (!content.endsWith(']')) {1372 emitError(context, 27 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */);1373 content = content.slice(1);1374 }1375 else {1376 content = content.slice(1, content.length - 1);1377 }1378 }1379 else if (isSlot) {1380 // #1241 special case for v-slot: vuetify relies extensively on slot1381 // names containing dots. v-slot doesn't have any modifiers and Vue 2.x1382 // supports such usage so we are keeping it consistent with 2.x.1383 content += match[3] || '';1384 }1385 arg = {1386 type: 4 /* SIMPLE_EXPRESSION */,1387 content,1388 isStatic,1389 constType: isStatic1390 ? 3 /* CAN_STRINGIFY */1391 : 0 /* NOT_CONSTANT */,1392 loc1393 };1394 }1395 if (value && value.isQuoted) {1396 const valueLoc = value.loc;1397 valueLoc.start.offset++;1398 valueLoc.start.column++;1399 valueLoc.end = advancePositionWithClone(valueLoc.start, value.content);1400 valueLoc.source = valueLoc.source.slice(1, -1);1401 }1402 const modifiers = match[3] ? match[3].slice(1).split('.') : [];1403 if (isPropShorthand)1404 modifiers.push('prop');1405 // 2.x compat v-bind:foo.sync -> v-model:foo1406 if (dirName === 'bind' && arg) {1407 if (modifiers.includes('sync') &&1408 checkCompatEnabled("COMPILER_V_BIND_SYNC" /* COMPILER_V_BIND_SYNC */, context, loc, arg.loc.source)) {1409 dirName = 'model';1410 modifiers.splice(modifiers.indexOf('sync'), 1);1411 }1412 if (modifiers.includes('prop')) {1413 checkCompatEnabled("COMPILER_V_BIND_PROP" /* COMPILER_V_BIND_PROP */, context, loc);1414 }1415 }1416 return {1417 type: 7 /* DIRECTIVE */,1418 name: dirName,1419 exp: value && {1420 type: 4 /* SIMPLE_EXPRESSION */,1421 content: value.content,1422 isStatic: false,1423 // Treat as non-constant by default. This can be potentially set to1424 // other values by `transformExpression` to make it eligible for hoisting.1425 constType: 0 /* NOT_CONSTANT */,1426 loc: value.loc1427 },1428 arg,1429 modifiers,1430 loc1431 };1432 }1433 // missing directive name or illegal directive name1434 if (!context.inVPre && startsWith(name, 'v-')) {1435 emitError(context, 26 /* X_MISSING_DIRECTIVE_NAME */);1436 }1437 return {1438 type: 6 /* ATTRIBUTE */,1439 name,1440 value: value && {1441 type: 2 /* TEXT */,1442 content: value.content,1443 loc: value.loc1444 },1445 loc1446 };1447}1448function parseAttributeValue(context) {1449 const start = getCursor(context);1450 let content;1451 const quote = context.source[0];1452 const isQuoted = quote === `"` || quote === `'`;1453 if (isQuoted) {1454 // Quoted value.1455 advanceBy(context, 1);1456 const endIndex = context.source.indexOf(quote);1457 if (endIndex === -1) {1458 content = parseTextData(context, context.source.length, 4 /* ATTRIBUTE_VALUE */);1459 }1460 else {1461 content = parseTextData(context, endIndex, 4 /* ATTRIBUTE_VALUE */);1462 advanceBy(context, 1);1463 }1464 }1465 else {1466 // Unquoted1467 const match = /^[^\t\r\n\f >]+/.exec(context.source);1468 if (!match) {1469 return undefined;1470 }1471 const unexpectedChars = /["'<=`]/g;1472 let m;1473 while ((m = unexpectedChars.exec(match[0]))) {1474 emitError(context, 18 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */, m.index);1475 }1476 content = parseTextData(context, match[0].length, 4 /* ATTRIBUTE_VALUE */);1477 }1478 return { content, isQuoted, loc: getSelection(context, start) };1479}1480function parseInterpolation(context, mode) {1481 const [open, close] = context.options.delimiters;1482 const closeIndex = context.source.indexOf(close, open.length);1483 if (closeIndex === -1) {1484 emitError(context, 25 /* X_MISSING_INTERPOLATION_END */);1485 return undefined;1486 }1487 const start = getCursor(context);1488 advanceBy(context, open.length);1489 const innerStart = getCursor(context);1490 const innerEnd = getCursor(context);1491 const rawContentLength = closeIndex - open.length;1492 const rawContent = context.source.slice(0, rawContentLength);1493 const preTrimContent = parseTextData(context, rawContentLength, mode);1494 const content = preTrimContent.trim();1495 const startOffset = preTrimContent.indexOf(content);1496 if (startOffset > 0) {1497 advancePositionWithMutation(innerStart, rawContent, startOffset);1498 }1499 const endOffset = rawContentLength - (preTrimContent.length - content.length - startOffset);1500 advancePositionWithMutation(innerEnd, rawContent, endOffset);1501 advanceBy(context, close.length);1502 return {1503 type: 5 /* INTERPOLATION */,1504 content: {1505 type: 4 /* SIMPLE_EXPRESSION */,1506 isStatic: false,1507 // Set `isConstant` to false by default and will decide in transformExpression1508 constType: 0 /* NOT_CONSTANT */,1509 content,1510 loc: getSelection(context, innerStart, innerEnd)1511 },1512 loc: getSelection(context, start)1513 };1514}1515function parseText(context, mode) {1516 const endTokens = mode === 3 /* CDATA */ ? [']]>'] : ['<', context.options.delimiters[0]];1517 let endIndex = context.source.length;1518 for (let i = 0; i < endTokens.length; i++) {1519 const index = context.source.indexOf(endTokens[i], 1);1520 if (index !== -1 && endIndex > index) {1521 endIndex = index;1522 }1523 }1524 const start = getCursor(context);1525 const content = parseTextData(context, endIndex, mode);1526 return {1527 type: 2 /* TEXT */,1528 content,1529 loc: getSelection(context, start)1530 };1531}1532/**1533 * Get text data with a given length from the current location.1534 * This translates HTML entities in the text data.1535 */1536function parseTextData(context, length, mode) {1537 const rawText = context.source.slice(0, length);1538 advanceBy(context, length);1539 if (mode === 2 /* RAWTEXT */ ||1540 mode === 3 /* CDATA */ ||1541 rawText.indexOf('&') === -1) {1542 return rawText;1543 }1544 else {1545 // DATA or RCDATA containing "&"". Entity decoding required.1546 return context.options.decodeEntities(rawText, mode === 4 /* ATTRIBUTE_VALUE */);1547 }1548}1549function getCursor(context) {1550 const { column, line, offset } = context;1551 return { column, line, offset };1552}1553function getSelection(context, start, end) {1554 end = end || getCursor(context);1555 return {1556 start,1557 end,1558 source: context.originalSource.slice(start.offset, end.offset)1559 };1560}1561function last(xs) {1562 return xs[xs.length - 1];1563}1564function startsWith(source, searchString) {1565 return source.startsWith(searchString);1566}1567function advanceBy(context, numberOfCharacters) {1568 const { source } = context;1569 advancePositionWithMutation(context, source, numberOfCharacters);1570 context.source = source.slice(numberOfCharacters);1571}1572function advanceSpaces(context) {1573 const match = /^[\t\r\n\f ]+/.exec(context.source);1574 if (match) {1575 advanceBy(context, match[0].length);1576 }1577}1578function getNewPosition(context, start, numberOfCharacters) {1579 return advancePositionWithClone(start, context.originalSource.slice(start.offset, numberOfCharacters), numberOfCharacters);1580}1581function emitError(context, code, offset, loc = getCursor(context)) {1582 if (offset) {1583 loc.offset += offset;1584 loc.column += offset;1585 }1586 context.options.onError(createCompilerError(code, {1587 start: loc,1588 end: loc,1589 source: ''1590 }));1591}1592function isEnd(context, mode, ancestors) {1593 const s = context.source;1594 switch (mode) {1595 case 0 /* DATA */:1596 if (startsWith(s, '</')) {1597 // TODO: probably bad performance1598 for (let i = ancestors.length - 1; i >= 0; --i) {1599 if (startsWithEndTagOpen(s, ancestors[i].tag)) {1600 return true;1601 }1602 }1603 }1604 break;1605 case 1 /* RCDATA */:1606 case 2 /* RAWTEXT */: {1607 const parent = last(ancestors);1608 if (parent && startsWithEndTagOpen(s, parent.tag)) {1609 return true;1610 }1611 break;1612 }1613 case 3 /* CDATA */:1614 if (startsWith(s, ']]>')) {1615 return true;1616 }1617 break;1618 }1619 return !s;1620}1621function startsWithEndTagOpen(source, tag) {1622 return (startsWith(source, '</') &&1623 source.slice(2, 2 + tag.length).toLowerCase() === tag.toLowerCase() &&1624 /[\t\r\n\f />]/.test(source[2 + tag.length] || '>'));1625}1626function hoistStatic(root, context) {1627 walk(root, context, 1628 // Root node is unfortunately non-hoistable due to potential parent1629 // fallthrough attributes.1630 isSingleElementRoot(root, root.children[0]));1631}1632function isSingleElementRoot(root, child) {1633 const { children } = root;1634 return (children.length === 1 &&1635 child.type === 1 /* ELEMENT */ &&1636 !isSlotOutlet(child));1637}1638function walk(node, context, doNotHoistNode = false) {1639 const { children } = node;1640 const originalCount = children.length;1641 let hoistedCount = 0;1642 for (let i = 0; i < children.length; i++) {1643 const child = children[i];1644 // only plain elements & text calls are eligible for hoisting.1645 if (child.type === 1 /* ELEMENT */ &&1646 child.tagType === 0 /* ELEMENT */) {1647 const constantType = doNotHoistNode1648 ? 0 /* NOT_CONSTANT */1649 : getConstantType(child, context);1650 if (constantType > 0 /* NOT_CONSTANT */) {1651 if (constantType >= 2 /* CAN_HOIST */) {1652 child.codegenNode.patchFlag =1653 -1 /* HOISTED */ + (` /* HOISTED */` );1654 child.codegenNode = context.hoist(child.codegenNode);1655 hoistedCount++;1656 continue;1657 }1658 }1659 else {1660 // node may contain dynamic children, but its props may be eligible for1661 // hoisting.1662 const codegenNode = child.codegenNode;1663 if (codegenNode.type === 13 /* VNODE_CALL */) {1664 const flag = getPatchFlag(codegenNode);1665 if ((!flag ||1666 flag === 512 /* NEED_PATCH */ ||1667 flag === 1 /* TEXT */) &&1668 getGeneratedPropsConstantType(child, context) >=1669 2 /* CAN_HOIST */) {1670 const props = getNodeProps(child);1671 if (props) {1672 codegenNode.props = context.hoist(props);1673 }1674 }1675 if (codegenNode.dynamicProps) {1676 codegenNode.dynamicProps = context.hoist(codegenNode.dynamicProps);1677 }1678 }1679 }1680 }1681 else if (child.type === 12 /* TEXT_CALL */ &&1682 getConstantType(child.content, context) >= 2 /* CAN_HOIST */) {1683 child.codegenNode = context.hoist(child.codegenNode);1684 hoistedCount++;1685 }1686 // walk further1687 if (child.type === 1 /* ELEMENT */) {1688 const isComponent = child.tagType === 1 /* COMPONENT */;1689 if (isComponent) {1690 context.scopes.vSlot++;1691 }1692 walk(child, context);1693 if (isComponent) {1694 context.scopes.vSlot--;1695 }1696 }1697 else if (child.type === 11 /* FOR */) {1698 // Do not hoist v-for single child because it has to be a block1699 walk(child, context, child.children.length === 1);1700 }1701 else if (child.type === 9 /* IF */) {1702 for (let i = 0; i < child.branches.length; i++) {1703 // Do not hoist v-if single child because it has to be a block1704 walk(child.branches[i], context, child.branches[i].children.length === 1);1705 }1706 }1707 }1708 if (hoistedCount && context.transformHoist) {1709 context.transformHoist(children, context, node);1710 }1711 // all children were hoisted - the entire children array is hoistable.1712 if (hoistedCount &&1713 hoistedCount === originalCount &&1714 node.type === 1 /* ELEMENT */ &&1715 node.tagType === 0 /* ELEMENT */ &&1716 node.codegenNode &&1717 node.codegenNode.type === 13 /* VNODE_CALL */ &&1718 shared.isArray(node.codegenNode.children)) {1719 node.codegenNode.children = context.hoist(createArrayExpression(node.codegenNode.children));1720 }1721}1722function getConstantType(node, context) {1723 const { constantCache } = context;1724 switch (node.type) {1725 case 1 /* ELEMENT */:1726 if (node.tagType !== 0 /* ELEMENT */) {1727 return 0 /* NOT_CONSTANT */;1728 }1729 const cached = constantCache.get(node);1730 if (cached !== undefined) {1731 return cached;1732 }1733 const codegenNode = node.codegenNode;1734 if (codegenNode.type !== 13 /* VNODE_CALL */) {1735 return 0 /* NOT_CONSTANT */;1736 }1737 if (codegenNode.isBlock &&1738 node.tag !== 'svg' &&1739 node.tag !== 'foreignObject') {1740 return 0 /* NOT_CONSTANT */;1741 }1742 const flag = getPatchFlag(codegenNode);1743 if (!flag) {1744 let returnType = 3 /* CAN_STRINGIFY */;1745 // Element itself has no patch flag. However we still need to check:1746 // 1. Even for a node with no patch flag, it is possible for it to contain1747 // non-hoistable expressions that refers to scope variables, e.g. compiler1748 // injected keys or cached event handlers. Therefore we need to always1749 // check the codegenNode's props to be sure.1750 const generatedPropsType = getGeneratedPropsConstantType(node, context);1751 if (generatedPropsType === 0 /* NOT_CONSTANT */) {1752 constantCache.set(node, 0 /* NOT_CONSTANT */);1753 return 0 /* NOT_CONSTANT */;1754 }1755 if (generatedPropsType < returnType) {1756 returnType = generatedPropsType;1757 }1758 // 2. its children.1759 for (let i = 0; i < node.children.length; i++) {1760 const childType = getConstantType(node.children[i], context);1761 if (childType === 0 /* NOT_CONSTANT */) {1762 constantCache.set(node, 0 /* NOT_CONSTANT */);1763 return 0 /* NOT_CONSTANT */;1764 }1765 if (childType < returnType) {1766 returnType = childType;1767 }1768 }1769 // 3. if the type is not already CAN_SKIP_PATCH which is the lowest non-01770 // type, check if any of the props can cause the type to be lowered1771 // we can skip can_patch because it's guaranteed by the absence of a1772 // patchFlag.1773 if (returnType > 1 /* CAN_SKIP_PATCH */) {1774 for (let i = 0; i < node.props.length; i++) {1775 const p = node.props[i];1776 if (p.type === 7 /* DIRECTIVE */ && p.name === 'bind' && p.exp) {1777 const expType = getConstantType(p.exp, context);1778 if (expType === 0 /* NOT_CONSTANT */) {1779 constantCache.set(node, 0 /* NOT_CONSTANT */);1780 return 0 /* NOT_CONSTANT */;1781 }1782 if (expType < returnType) {1783 returnType = expType;1784 }1785 }1786 }1787 }1788 // only svg/foreignObject could be block here, however if they are1789 // static then they don't need to be blocks since there will be no1790 // nested updates.1791 if (codegenNode.isBlock) {1792 context.removeHelper(OPEN_BLOCK);1793 context.removeHelper(getVNodeBlockHelper(context.inSSR, codegenNode.isComponent));1794 codegenNode.isBlock = false;1795 context.helper(getVNodeHelper(context.inSSR, codegenNode.isComponent));1796 }1797 constantCache.set(node, returnType);1798 return returnType;1799 }1800 else {1801 constantCache.set(node, 0 /* NOT_CONSTANT */);1802 return 0 /* NOT_CONSTANT */;1803 }1804 case 2 /* TEXT */:1805 case 3 /* COMMENT */:1806 return 3 /* CAN_STRINGIFY */;1807 case 9 /* IF */:1808 case 11 /* FOR */:1809 case 10 /* IF_BRANCH */:1810 return 0 /* NOT_CONSTANT */;1811 case 5 /* INTERPOLATION */:1812 case 12 /* TEXT_CALL */:1813 return getConstantType(node.content, context);1814 case 4 /* SIMPLE_EXPRESSION */:1815 return node.constType;1816 case 8 /* COMPOUND_EXPRESSION */:1817 let returnType = 3 /* CAN_STRINGIFY */;1818 for (let i = 0; i < node.children.length; i++) {1819 const child = node.children[i];1820 if (shared.isString(child) || shared.isSymbol(child)) {1821 continue;1822 }1823 const childType = getConstantType(child, context);1824 if (childType === 0 /* NOT_CONSTANT */) {1825 return 0 /* NOT_CONSTANT */;1826 }1827 else if (childType < returnType) {1828 returnType = childType;1829 }1830 }1831 return returnType;1832 default:1833 return 0 /* NOT_CONSTANT */;1834 }1835}1836const allowHoistedHelperSet = new Set([1837 NORMALIZE_CLASS,1838 NORMALIZE_STYLE,1839 NORMALIZE_PROPS,1840 GUARD_REACTIVE_PROPS1841]);1842function getConstantTypeOfHelperCall(value, context) {1843 if (value.type === 14 /* JS_CALL_EXPRESSION */ &&1844 !shared.isString(value.callee) &&1845 allowHoistedHelperSet.has(value.callee)) {1846 const arg = value.arguments[0];1847 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {1848 return getConstantType(arg, context);1849 }1850 else if (arg.type === 14 /* JS_CALL_EXPRESSION */) {1851 // in the case of nested helper call, e.g. `normalizeProps(guardReactiveProps(exp))`1852 return getConstantTypeOfHelperCall(arg, context);1853 }1854 }1855 return 0 /* NOT_CONSTANT */;1856}1857function getGeneratedPropsConstantType(node, context) {1858 let returnType = 3 /* CAN_STRINGIFY */;1859 const props = getNodeProps(node);1860 if (props && props.type === 15 /* JS_OBJECT_EXPRESSION */) {1861 const { properties } = props;1862 for (let i = 0; i < properties.length; i++) {1863 const { key, value } = properties[i];1864 const keyType = getConstantType(key, context);1865 if (keyType === 0 /* NOT_CONSTANT */) {1866 return keyType;1867 }1868 if (keyType < returnType) {1869 returnType = keyType;1870 }1871 let valueType;1872 if (value.type === 4 /* SIMPLE_EXPRESSION */) {1873 valueType = getConstantType(value, context);1874 }1875 else if (value.type === 14 /* JS_CALL_EXPRESSION */) {1876 // some helper calls can be hoisted,1877 // such as the `normalizeProps` generated by the compiler for pre-normalize class,1878 // in this case we need to respect the ConstantType of the helper's arguments1879 valueType = getConstantTypeOfHelperCall(value, context);1880 }1881 else {1882 valueType = 0 /* NOT_CONSTANT */;1883 }1884 if (valueType === 0 /* NOT_CONSTANT */) {1885 return valueType;1886 }1887 if (valueType < returnType) {1888 returnType = valueType;1889 }1890 }1891 }1892 return returnType;1893}1894function getNodeProps(node) {1895 const codegenNode = node.codegenNode;1896 if (codegenNode.type === 13 /* VNODE_CALL */) {1897 return codegenNode.props;1898 }1899}1900function getPatchFlag(node) {1901 const flag = node.patchFlag;1902 return flag ? parseInt(flag, 10) : undefined;1903}1904function 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 }) {1905 const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/);1906 const context = {1907 // options1908 selfName: nameMatch && shared.capitalize(shared.camelize(nameMatch[1])),1909 prefixIdentifiers,1910 hoistStatic,1911 cacheHandlers,1912 nodeTransforms,1913 directiveTransforms,1914 transformHoist,1915 isBuiltInComponent,1916 isCustomElement,1917 expressionPlugins,1918 scopeId,1919 slotted,1920 ssr,1921 inSSR,1922 ssrCssVars,1923 bindingMetadata,1924 inline,1925 isTS,1926 onError,1927 onWarn,1928 compatConfig,1929 // state1930 root,1931 helpers: new Map(),1932 components: new Set(),1933 directives: new Set(),1934 hoists: [],1935 imports: [],1936 constantCache: new Map(),1937 temps: 0,1938 cached: 0,1939 identifiers: Object.create(null),1940 scopes: {1941 vFor: 0,1942 vSlot: 0,1943 vPre: 0,1944 vOnce: 01945 },1946 parent: null,1947 currentNode: root,1948 childIndex: 0,1949 inVOnce: false,1950 // methods1951 helper(name) {1952 const count = context.helpers.get(name) || 0;1953 context.helpers.set(name, count + 1);1954 return name;1955 },1956 removeHelper(name) {1957 const count = context.helpers.get(name);1958 if (count) {1959 const currentCount = count - 1;1960 if (!currentCount) {1961 context.helpers.delete(name);1962 }1963 else {1964 context.helpers.set(name, currentCount);1965 }1966 }1967 },1968 helperString(name) {1969 return `_${helperNameMap[context.helper(name)]}`;1970 },1971 replaceNode(node) {1972 /* istanbul ignore if */1973 {1974 if (!context.currentNode) {1975 throw new Error(`Node being replaced is already removed.`);1976 }1977 if (!context.parent) {1978 throw new Error(`Cannot replace root node.`);1979 }1980 }1981 context.parent.children[context.childIndex] = context.currentNode = node;1982 },1983 removeNode(node) {1984 if (!context.parent) {1985 throw new Error(`Cannot remove root node.`);1986 }1987 const list = context.parent.children;1988 const removalIndex = node1989 ? list.indexOf(node)1990 : context.currentNode1991 ? context.childIndex1992 : -1;1993 /* istanbul ignore if */1994 if (removalIndex < 0) {1995 throw new Error(`node being removed is not a child of current parent`);1996 }1997 if (!node || node === context.currentNode) {1998 // current node removed1999 context.currentNode = null;2000 context.onNodeRemoved();2001 }2002 else {2003 // sibling node removed2004 if (context.childIndex > removalIndex) {2005 context.childIndex--;2006 context.onNodeRemoved();2007 }2008 }2009 context.parent.children.splice(removalIndex, 1);2010 },2011 onNodeRemoved: () => { },2012 addIdentifiers(exp) {2013 // identifier tracking only happens in non-browser builds.2014 {2015 if (shared.isString(exp)) {2016 addId(exp);2017 }2018 else if (exp.identifiers) {2019 exp.identifiers.forEach(addId);2020 }2021 else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {2022 addId(exp.content);2023 }2024 }2025 },2026 removeIdentifiers(exp) {2027 {2028 if (shared.isString(exp)) {2029 removeId(exp);2030 }2031 else if (exp.identifiers) {2032 exp.identifiers.forEach(removeId);2033 }2034 else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {2035 removeId(exp.content);2036 }2037 }2038 },2039 hoist(exp) {2040 if (shared.isString(exp))2041 exp = createSimpleExpression(exp);2042 context.hoists.push(exp);2043 const identifier = createSimpleExpression(`_hoisted_${context.hoists.length}`, false, exp.loc, 2 /* CAN_HOIST */);2044 identifier.hoisted = exp;2045 return identifier;2046 },2047 cache(exp, isVNode = false) {2048 return createCacheExpression(context.cached++, exp, isVNode);2049 }2050 };2051 {2052 context.filters = new Set();2053 }2054 function addId(id) {2055 const { identifiers } = context;2056 if (identifiers[id] === undefined) {2057 identifiers[id] = 0;2058 }2059 identifiers[id]++;2060 }2061 function removeId(id) {2062 context.identifiers[id]--;2063 }2064 return context;2065}2066function transform(root, options) {2067 const context = createTransformContext(root, options);2068 traverseNode(root, context);2069 if (options.hoistStatic) {2070 hoistStatic(root, context);2071 }2072 if (!options.ssr) {2073 createRootCodegen(root, context);2074 }2075 // finalize meta information2076 root.helpers = [...context.helpers.keys()];2077 root.components = [...context.components];2078 root.directives = [...context.directives];2079 root.imports = context.imports;2080 root.hoists = context.hoists;2081 root.temps = context.temps;2082 root.cached = context.cached;2083 {2084 root.filters = [...context.filters];2085 }2086}2087function createRootCodegen(root, context) {2088 const { helper } = context;2089 const { children } = root;2090 if (children.length === 1) {2091 const child = children[0];2092 // if the single child is an element, turn it into a block.2093 if (isSingleElementRoot(root, child) && child.codegenNode) {2094 // single element root is never hoisted so codegenNode will never be2095 // SimpleExpressionNode2096 const codegenNode = child.codegenNode;2097 if (codegenNode.type === 13 /* VNODE_CALL */) {2098 makeBlock(codegenNode, context);2099 }2100 root.codegenNode = codegenNode;2101 }2102 else {2103 // - single <slot/>, IfNode, ForNode: already blocks.2104 // - single text node: always patched.2105 // root codegen falls through via genNode()2106 root.codegenNode = child;2107 }2108 }2109 else if (children.length > 1) {2110 // root has multiple nodes - return a fragment block.2111 let patchFlag = 64 /* STABLE_FRAGMENT */;2112 let patchFlagText = shared.PatchFlagNames[64 /* STABLE_FRAGMENT */];2113 // check if the fragment actually contains a single valid child with2114 // the rest being comments2115 if (children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {2116 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;2117 patchFlagText += `, ${shared.PatchFlagNames[2048 /* DEV_ROOT_FRAGMENT */]}`;2118 }2119 root.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, root.children, patchFlag + (` /* ${patchFlagText} */` ), undefined, undefined, true, undefined, false /* isComponent */);2120 }2121 else ;2122}2123function traverseChildren(parent, context) {2124 let i = 0;2125 const nodeRemoved = () => {2126 i--;2127 };2128 for (; i < parent.children.length; i++) {2129 const child = parent.children[i];2130 if (shared.isString(child))2131 continue;2132 context.parent = parent;2133 context.childIndex = i;2134 context.onNodeRemoved = nodeRemoved;2135 traverseNode(child, context);2136 }2137}2138function traverseNode(node, context) {2139 context.currentNode = node;2140 // apply transform plugins2141 const { nodeTransforms } = context;2142 const exitFns = [];2143 for (let i = 0; i < nodeTransforms.length; i++) {2144 const onExit = nodeTransforms[i](node, context);2145 if (onExit) {2146 if (shared.isArray(onExit)) {2147 exitFns.push(...onExit);2148 }2149 else {2150 exitFns.push(onExit);2151 }2152 }2153 if (!context.currentNode) {2154 // node was removed2155 return;2156 }2157 else {2158 // node may have been replaced2159 node = context.currentNode;2160 }2161 }2162 switch (node.type) {2163 case 3 /* COMMENT */:2164 if (!context.ssr) {2165 // inject import for the Comment symbol, which is needed for creating2166 // comment nodes with `createVNode`2167 context.helper(CREATE_COMMENT);2168 }2169 break;2170 case 5 /* INTERPOLATION */:2171 // no need to traverse, but we need to inject toString helper2172 if (!context.ssr) {2173 context.helper(TO_DISPLAY_STRING);2174 }2175 break;2176 // for container types, further traverse downwards2177 case 9 /* IF */:2178 for (let i = 0; i < node.branches.length; i++) {2179 traverseNode(node.branches[i], context);2180 }2181 break;2182 case 10 /* IF_BRANCH */:2183 case 11 /* FOR */:2184 case 1 /* ELEMENT */:2185 case 0 /* ROOT */:2186 traverseChildren(node, context);2187 break;2188 }2189 // exit transforms2190 context.currentNode = node;2191 let i = exitFns.length;2192 while (i--) {2193 exitFns[i]();2194 }2195}2196function createStructuralDirectiveTransform(name, fn) {2197 const matches = shared.isString(name)2198 ? (n) => n === name2199 : (n) => name.test(n);2200 return (node, context) => {2201 if (node.type === 1 /* ELEMENT */) {2202 const { props } = node;2203 // structural directive transforms are not concerned with slots2204 // as they are handled separately in vSlot.ts2205 if (node.tagType === 3 /* TEMPLATE */ && props.some(isVSlot)) {2206 return;2207 }2208 const exitFns = [];2209 for (let i = 0; i < props.length; i++) {2210 const prop = props[i];2211 if (prop.type === 7 /* DIRECTIVE */ && matches(prop.name)) {2212 // structural directives are removed to avoid infinite recursion2213 // also we remove them *before* applying so that it can further2214 // traverse itself in case it moves the node around2215 props.splice(i, 1);2216 i--;2217 const onExit = fn(node, prop, context);2218 if (onExit)2219 exitFns.push(onExit);2220 }2221 }2222 return exitFns;2223 }2224 };2225}2226const PURE_ANNOTATION = `/*#__PURE__*/`;2227function 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 }) {2228 const context = {2229 mode,2230 prefixIdentifiers,2231 sourceMap: sourceMap$1,2232 filename,2233 scopeId,2234 optimizeImports,2235 runtimeGlobalName,2236 runtimeModuleName,2237 ssrRuntimeModuleName,2238 ssr,2239 isTS,2240 inSSR,2241 source: ast.loc.source,2242 code: ``,2243 column: 1,2244 line: 1,2245 offset: 0,2246 indentLevel: 0,2247 pure: false,2248 map: undefined,2249 helper(key) {2250 return `_${helperNameMap[key]}`;2251 },2252 push(code, node) {2253 context.code += code;2254 if (context.map) {2255 if (node) {2256 let name;2257 if (node.type === 4 /* SIMPLE_EXPRESSION */ && !node.isStatic) {2258 const content = node.content.replace(/^_ctx\./, '');2259 if (content !== node.content && isSimpleIdentifier(content)) {2260 name = content;2261 }2262 }2263 addMapping(node.loc.start, name);2264 }2265 advancePositionWithMutation(context, code);2266 if (node && node.loc !== locStub) {2267 addMapping(node.loc.end);2268 }2269 }2270 },2271 indent() {2272 newline(++context.indentLevel);2273 },2274 deindent(withoutNewLine = false) {2275 if (withoutNewLine) {2276 --context.indentLevel;2277 }2278 else {2279 newline(--context.indentLevel);2280 }2281 },2282 newline() {2283 newline(context.indentLevel);2284 }2285 };2286 function newline(n) {2287 context.push('\n' + ` `.repeat(n));2288 }2289 function addMapping(loc, name) {2290 context.map.addMapping({2291 name,2292 source: context.filename,2293 original: {2294 line: loc.line,2295 column: loc.column - 1 // source-map column is 0 based2296 },2297 generated: {2298 line: context.line,2299 column: context.column - 12300 }2301 });2302 }2303 if (sourceMap$1) {2304 // lazy require source-map implementation, only in non-browser builds2305 context.map = new sourceMap.SourceMapGenerator();2306 context.map.setSourceContent(filename, context.source);2307 }2308 return context;2309}2310function generate(ast, options = {}) {2311 const context = createCodegenContext(ast, options);2312 if (options.onContextCreated)2313 options.onContextCreated(context);2314 const { mode, push, prefixIdentifiers, indent, deindent, newline, scopeId, ssr } = context;2315 const hasHelpers = ast.helpers.length > 0;2316 const useWithBlock = !prefixIdentifiers && mode !== 'module';2317 const genScopeId = scopeId != null && mode === 'module';2318 const isSetupInlined = !!options.inline;2319 // preambles2320 // in setup() inline mode, the preamble is generated in a sub context2321 // and returned separately.2322 const preambleContext = isSetupInlined2323 ? createCodegenContext(ast, options)2324 : context;2325 if (mode === 'module') {2326 genModulePreamble(ast, preambleContext, genScopeId, isSetupInlined);2327 }2328 else {2329 genFunctionPreamble(ast, preambleContext);2330 }2331 // enter render function2332 const functionName = ssr ? `ssrRender` : `render`;2333 const args = ssr ? ['_ctx', '_push', '_parent', '_attrs'] : ['_ctx', '_cache'];2334 if (options.bindingMetadata && !options.inline) {2335 // binding optimization args2336 args.push('$props', '$setup', '$data', '$options');2337 }2338 const signature = options.isTS2339 ? args.map(arg => `${arg}: any`).join(',')2340 : args.join(', ');2341 if (isSetupInlined) {2342 push(`(${signature}) => {`);2343 }2344 else {2345 push(`function ${functionName}(${signature}) {`);2346 }2347 indent();2348 if (useWithBlock) {2349 push(`with (_ctx) {`);2350 indent();2351 // function mode const declarations should be inside with block2352 // also they should be renamed to avoid collision with user properties2353 if (hasHelpers) {2354 push(`const { ${ast.helpers2355 .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)2356 .join(', ')} } = _Vue`);2357 push(`\n`);2358 newline();2359 }2360 }2361 // generate asset resolution statements2362 if (ast.components.length) {2363 genAssets(ast.components, 'component', context);2364 if (ast.directives.length || ast.temps > 0) {2365 newline();2366 }2367 }2368 if (ast.directives.length) {2369 genAssets(ast.directives, 'directive', context);2370 if (ast.temps > 0) {2371 newline();2372 }2373 }2374 if (ast.filters && ast.filters.length) {2375 newline();2376 genAssets(ast.filters, 'filter', context);2377 newline();2378 }2379 if (ast.temps > 0) {2380 push(`let `);2381 for (let i = 0; i < ast.temps; i++) {2382 push(`${i > 0 ? `, ` : ``}_temp${i}`);2383 }2384 }2385 if (ast.components.length || ast.directives.length || ast.temps) {2386 push(`\n`);2387 newline();2388 }2389 // generate the VNode tree expression2390 if (!ssr) {2391 push(`return `);2392 }2393 if (ast.codegenNode) {2394 genNode(ast.codegenNode, context);2395 }2396 else {2397 push(`null`);2398 }2399 if (useWithBlock) {2400 deindent();2401 push(`}`);2402 }2403 deindent();2404 push(`}`);2405 return {2406 ast,2407 code: context.code,2408 preamble: isSetupInlined ? preambleContext.code : ``,2409 // SourceMapGenerator does have toJSON() method but it's not in the types2410 map: context.map ? context.map.toJSON() : undefined2411 };2412}2413function genFunctionPreamble(ast, context) {2414 const { ssr, prefixIdentifiers, push, newline, runtimeModuleName, runtimeGlobalName, ssrRuntimeModuleName } = context;2415 const VueBinding = ssr2416 ? `require(${JSON.stringify(runtimeModuleName)})`2417 : runtimeGlobalName;2418 const aliasHelper = (s) => `${helperNameMap[s]}: _${helperNameMap[s]}`;2419 // Generate const declaration for helpers2420 // In prefix mode, we place the const declaration at top so it's done2421 // only once; But if we not prefixing, we place the declaration inside the2422 // with block so it doesn't incur the `in` check cost for every helper access.2423 if (ast.helpers.length > 0) {2424 if (prefixIdentifiers) {2425 push(`const { ${ast.helpers.map(aliasHelper).join(', ')} } = ${VueBinding}\n`);2426 }2427 else {2428 // "with" mode.2429 // save Vue in a separate variable to avoid collision2430 push(`const _Vue = ${VueBinding}\n`);2431 // in "with" mode, helpers are declared inside the with block to avoid2432 // has check cost, but hoists are lifted out of the function - we need2433 // to provide the helper here.2434 if (ast.hoists.length) {2435 const staticHelpers = [2436 CREATE_VNODE,2437 CREATE_ELEMENT_VNODE,2438 CREATE_COMMENT,2439 CREATE_TEXT,2440 CREATE_STATIC2441 ]2442 .filter(helper => ast.helpers.includes(helper))2443 .map(aliasHelper)2444 .join(', ');2445 push(`const { ${staticHelpers} } = _Vue\n`);2446 }2447 }2448 }2449 // generate variables for ssr helpers2450 if (ast.ssrHelpers && ast.ssrHelpers.length) {2451 // ssr guarantees prefixIdentifier: true2452 push(`const { ${ast.ssrHelpers2453 .map(aliasHelper)2454 .join(', ')} } = require("${ssrRuntimeModuleName}")\n`);2455 }2456 genHoists(ast.hoists, context);2457 newline();2458 push(`return `);2459}2460function genModulePreamble(ast, context, genScopeId, inline) {2461 const { push, newline, optimizeImports, runtimeModuleName, ssrRuntimeModuleName } = context;2462 if (genScopeId && ast.hoists.length) {2463 ast.helpers.push(PUSH_SCOPE_ID, POP_SCOPE_ID);2464 }2465 // generate import statements for helpers2466 if (ast.helpers.length) {2467 if (optimizeImports) {2468 // when bundled with webpack with code-split, calling an import binding2469 // as a function leads to it being wrapped with `Object(a.b)` or `(0,a.b)`,2470 // incurring both payload size increase and potential perf overhead.2471 // therefore we assign the imports to variables (which is a constant ~50b2472 // cost per-component instead of scaling with template size)2473 push(`import { ${ast.helpers2474 .map(s => helperNameMap[s])2475 .join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`);2476 push(`\n// Binding optimization for webpack code-split\nconst ${ast.helpers2477 .map(s => `_${helperNameMap[s]} = ${helperNameMap[s]}`)2478 .join(', ')}\n`);2479 }2480 else {2481 push(`import { ${ast.helpers2482 .map(s => `${helperNameMap[s]} as _${helperNameMap[s]}`)2483 .join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`);2484 }2485 }2486 if (ast.ssrHelpers && ast.ssrHelpers.length) {2487 push(`import { ${ast.ssrHelpers2488 .map(s => `${helperNameMap[s]} as _${helperNameMap[s]}`)2489 .join(', ')} } from "${ssrRuntimeModuleName}"\n`);2490 }2491 if (ast.imports.length) {2492 genImports(ast.imports, context);2493 newline();2494 }2495 genHoists(ast.hoists, context);2496 newline();2497 if (!inline) {2498 push(`export `);2499 }2500}2501function genAssets(assets, type, { helper, push, newline, isTS }) {2502 const resolver = helper(type === 'filter'2503 ? RESOLVE_FILTER2504 : type === 'component'2505 ? RESOLVE_COMPONENT2506 : RESOLVE_DIRECTIVE);2507 for (let i = 0; i < assets.length; i++) {2508 let id = assets[i];2509 // potential component implicit self-reference inferred from SFC filename2510 const maybeSelfReference = id.endsWith('__self');2511 if (maybeSelfReference) {2512 id = id.slice(0, -6);2513 }2514 push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`);2515 if (i < assets.length - 1) {2516 newline();2517 }2518 }2519}2520function genHoists(hoists, context) {2521 if (!hoists.length) {2522 return;2523 }2524 context.pure = true;2525 const { push, newline, helper, scopeId, mode } = context;2526 const genScopeId = scopeId != null && mode !== 'function';2527 newline();2528 // generate inlined withScopeId helper2529 if (genScopeId) {2530 push(`const _withScopeId = n => (${helper(PUSH_SCOPE_ID)}("${scopeId}"),n=n(),${helper(POP_SCOPE_ID)}(),n)`);2531 newline();2532 }2533 for (let i = 0; i < hoists.length; i++) {2534 const exp = hoists[i];2535 if (exp) {2536 const needScopeIdWrapper = genScopeId && exp.type === 13 /* VNODE_CALL */;2537 push(`const _hoisted_${i + 1} = ${needScopeIdWrapper ? `${PURE_ANNOTATION} _withScopeId(() => ` : ``}`);2538 genNode(exp, context);2539 if (needScopeIdWrapper) {2540 push(`)`);2541 }2542 newline();2543 }2544 }2545 context.pure = false;2546}2547function genImports(importsOptions, context) {2548 if (!importsOptions.length) {2549 return;2550 }2551 importsOptions.forEach(imports => {2552 context.push(`import `);2553 genNode(imports.exp, context);2554 context.push(` from '${imports.path}'`);2555 context.newline();2556 });2557}2558function isText$1(n) {2559 return (shared.isString(n) ||2560 n.type === 4 /* SIMPLE_EXPRESSION */ ||2561 n.type === 2 /* TEXT */ ||2562 n.type === 5 /* INTERPOLATION */ ||2563 n.type === 8 /* COMPOUND_EXPRESSION */);2564}2565function genNodeListAsArray(nodes, context) {2566 const multilines = nodes.length > 3 ||2567 (nodes.some(n => shared.isArray(n) || !isText$1(n)));2568 context.push(`[`);2569 multilines && context.indent();2570 genNodeList(nodes, context, multilines);2571 multilines && context.deindent();2572 context.push(`]`);2573}2574function genNodeList(nodes, context, multilines = false, comma = true) {2575 const { push, newline } = context;2576 for (let i = 0; i < nodes.length; i++) {2577 const node = nodes[i];2578 if (shared.isString(node)) {2579 push(node);2580 }2581 else if (shared.isArray(node)) {2582 genNodeListAsArray(node, context);2583 }2584 else {2585 genNode(node, context);2586 }2587 if (i < nodes.length - 1) {2588 if (multilines) {2589 comma && push(',');2590 newline();2591 }2592 else {2593 comma && push(', ');2594 }2595 }2596 }2597}2598function genNode(node, context) {2599 if (shared.isString(node)) {2600 context.push(node);2601 return;2602 }2603 if (shared.isSymbol(node)) {2604 context.push(context.helper(node));2605 return;2606 }2607 switch (node.type) {2608 case 1 /* ELEMENT */:2609 case 9 /* IF */:2610 case 11 /* FOR */:2611 assert(node.codegenNode != null, `Codegen node is missing for element/if/for node. ` +2612 `Apply appropriate transforms first.`);2613 genNode(node.codegenNode, context);2614 break;2615 case 2 /* TEXT */:2616 genText(node, context);2617 break;2618 case 4 /* SIMPLE_EXPRESSION */:2619 genExpression(node, context);2620 break;2621 case 5 /* INTERPOLATION */:2622 genInterpolation(node, context);2623 break;2624 case 12 /* TEXT_CALL */:2625 genNode(node.codegenNode, context);2626 break;2627 case 8 /* COMPOUND_EXPRESSION */:2628 genCompoundExpression(node, context);2629 break;2630 case 3 /* COMMENT */:2631 genComment(node, context);2632 break;2633 case 13 /* VNODE_CALL */:2634 genVNodeCall(node, context);2635 break;2636 case 14 /* JS_CALL_EXPRESSION */:2637 genCallExpression(node, context);2638 break;2639 case 15 /* JS_OBJECT_EXPRESSION */:2640 genObjectExpression(node, context);2641 break;2642 case 17 /* JS_ARRAY_EXPRESSION */:2643 genArrayExpression(node, context);2644 break;2645 case 18 /* JS_FUNCTION_EXPRESSION */:2646 genFunctionExpression(node, context);2647 break;2648 case 19 /* JS_CONDITIONAL_EXPRESSION */:2649 genConditionalExpression(node, context);2650 break;2651 case 20 /* JS_CACHE_EXPRESSION */:2652 genCacheExpression(node, context);2653 break;2654 case 21 /* JS_BLOCK_STATEMENT */:2655 genNodeList(node.body, context, true, false);2656 break;2657 // SSR only types2658 case 22 /* JS_TEMPLATE_LITERAL */:2659 genTemplateLiteral(node, context);2660 break;2661 case 23 /* JS_IF_STATEMENT */:2662 genIfStatement(node, context);2663 break;2664 case 24 /* JS_ASSIGNMENT_EXPRESSION */:2665 genAssignmentExpression(node, context);2666 break;2667 case 25 /* JS_SEQUENCE_EXPRESSION */:2668 genSequenceExpression(node, context);2669 break;2670 case 26 /* JS_RETURN_STATEMENT */:2671 genReturnStatement(node, context);2672 break;2673 /* istanbul ignore next */2674 case 10 /* IF_BRANCH */:2675 // noop2676 break;2677 default:2678 {2679 assert(false, `unhandled codegen node type: ${node.type}`);2680 // make sure we exhaust all possible types2681 const exhaustiveCheck = node;2682 return exhaustiveCheck;2683 }2684 }2685}2686function genText(node, context) {2687 context.push(JSON.stringify(node.content), node);2688}2689function genExpression(node, context) {2690 const { content, isStatic } = node;2691 context.push(isStatic ? JSON.stringify(content) : content, node);2692}2693function genInterpolation(node, context) {2694 const { push, helper, pure } = context;2695 if (pure)2696 push(PURE_ANNOTATION);2697 push(`${helper(TO_DISPLAY_STRING)}(`);2698 genNode(node.content, context);2699 push(`)`);2700}2701function genCompoundExpression(node, context) {2702 for (let i = 0; i < node.children.length; i++) {2703 const child = node.children[i];2704 if (shared.isString(child)) {2705 context.push(child);2706 }2707 else {2708 genNode(child, context);2709 }2710 }2711}2712function genExpressionAsPropertyKey(node, context) {2713 const { push } = context;2714 if (node.type === 8 /* COMPOUND_EXPRESSION */) {2715 push(`[`);2716 genCompoundExpression(node, context);2717 push(`]`);2718 }2719 else if (node.isStatic) {2720 // only quote keys if necessary2721 const text = isSimpleIdentifier(node.content)2722 ? node.content2723 : JSON.stringify(node.content);2724 push(text, node);2725 }2726 else {2727 push(`[${node.content}]`, node);2728 }2729}2730function genComment(node, context) {2731 const { push, helper, pure } = context;2732 if (pure) {2733 push(PURE_ANNOTATION);2734 }2735 push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node);2736}2737function genVNodeCall(node, context) {2738 const { push, helper, pure } = context;2739 const { tag, props, children, patchFlag, dynamicProps, directives, isBlock, disableTracking, isComponent } = node;2740 if (directives) {2741 push(helper(WITH_DIRECTIVES) + `(`);2742 }2743 if (isBlock) {2744 push(`(${helper(OPEN_BLOCK)}(${disableTracking ? `true` : ``}), `);2745 }2746 if (pure) {2747 push(PURE_ANNOTATION);2748 }2749 const callHelper = isBlock2750 ? getVNodeBlockHelper(context.inSSR, isComponent)2751 : getVNodeHelper(context.inSSR, isComponent);2752 push(helper(callHelper) + `(`, node);2753 genNodeList(genNullableArgs([tag, props, children, patchFlag, dynamicProps]), context);2754 push(`)`);2755 if (isBlock) {2756 push(`)`);2757 }2758 if (directives) {2759 push(`, `);2760 genNode(directives, context);2761 push(`)`);2762 }2763}2764function genNullableArgs(args) {2765 let i = args.length;2766 while (i--) {2767 if (args[i] != null)2768 break;2769 }2770 return args.slice(0, i + 1).map(arg => arg || `null`);2771}2772// JavaScript2773function genCallExpression(node, context) {2774 const { push, helper, pure } = context;2775 const callee = shared.isString(node.callee) ? node.callee : helper(node.callee);2776 if (pure) {2777 push(PURE_ANNOTATION);2778 }2779 push(callee + `(`, node);2780 genNodeList(node.arguments, context);2781 push(`)`);2782}2783function genObjectExpression(node, context) {2784 const { push, indent, deindent, newline } = context;2785 const { properties } = node;2786 if (!properties.length) {2787 push(`{}`, node);2788 return;2789 }2790 const multilines = properties.length > 1 ||2791 (properties.some(p => p.value.type !== 4 /* SIMPLE_EXPRESSION */));2792 push(multilines ? `{` : `{ `);2793 multilines && indent();2794 for (let i = 0; i < properties.length; i++) {2795 const { key, value } = properties[i];2796 // key2797 genExpressionAsPropertyKey(key, context);2798 push(`: `);2799 // value2800 genNode(value, context);2801 if (i < properties.length - 1) {2802 // will only reach this if it's multilines2803 push(`,`);2804 newline();2805 }2806 }2807 multilines && deindent();2808 push(multilines ? `}` : ` }`);2809}2810function genArrayExpression(node, context) {2811 genNodeListAsArray(node.elements, context);2812}2813function genFunctionExpression(node, context) {2814 const { push, indent, deindent } = context;2815 const { params, returns, body, newline, isSlot } = node;2816 if (isSlot) {2817 // wrap slot functions with owner context2818 push(`_${helperNameMap[WITH_CTX]}(`);2819 }2820 push(`(`, node);2821 if (shared.isArray(params)) {2822 genNodeList(params, context);2823 }2824 else if (params) {2825 genNode(params, context);2826 }2827 push(`) => `);2828 if (newline || body) {2829 push(`{`);2830 indent();2831 }2832 if (returns) {2833 if (newline) {2834 push(`return `);2835 }2836 if (shared.isArray(returns)) {2837 genNodeListAsArray(returns, context);2838 }2839 else {2840 genNode(returns, context);2841 }2842 }2843 else if (body) {2844 genNode(body, context);2845 }2846 if (newline || body) {2847 deindent();2848 push(`}`);2849 }2850 if (isSlot) {2851 if (node.isNonScopedSlot) {2852 push(`, undefined, true`);2853 }2854 push(`)`);2855 }2856}2857function genConditionalExpression(node, context) {2858 const { test, consequent, alternate, newline: needNewline } = node;2859 const { push, indent, deindent, newline } = context;2860 if (test.type === 4 /* SIMPLE_EXPRESSION */) {2861 const needsParens = !isSimpleIdentifier(test.content);2862 needsParens && push(`(`);2863 genExpression(test, context);2864 needsParens && push(`)`);2865 }2866 else {2867 push(`(`);2868 genNode(test, context);2869 push(`)`);2870 }2871 needNewline && indent();2872 context.indentLevel++;2873 needNewline || push(` `);2874 push(`? `);2875 genNode(consequent, context);2876 context.indentLevel--;2877 needNewline && newline();2878 needNewline || push(` `);2879 push(`: `);2880 const isNested = alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */;2881 if (!isNested) {2882 context.indentLevel++;2883 }2884 genNode(alternate, context);2885 if (!isNested) {2886 context.indentLevel--;2887 }2888 needNewline && deindent(true /* without newline */);2889}2890function genCacheExpression(node, context) {2891 const { push, helper, indent, deindent, newline } = context;2892 push(`_cache[${node.index}] || (`);2893 if (node.isVNode) {2894 indent();2895 push(`${helper(SET_BLOCK_TRACKING)}(-1),`);2896 newline();2897 }2898 push(`_cache[${node.index}] = `);2899 genNode(node.value, context);2900 if (node.isVNode) {2901 push(`,`);2902 newline();2903 push(`${helper(SET_BLOCK_TRACKING)}(1),`);2904 newline();2905 push(`_cache[${node.index}]`);2906 deindent();2907 }2908 push(`)`);2909}2910function genTemplateLiteral(node, context) {2911 const { push, indent, deindent } = context;2912 push('`');2913 const l = node.elements.length;2914 const multilines = l > 3;2915 for (let i = 0; i < l; i++) {2916 const e = node.elements[i];2917 if (shared.isString(e)) {2918 push(e.replace(/(`|\$|\\)/g, '\\$1'));2919 }2920 else {2921 push('${');2922 if (multilines)2923 indent();2924 genNode(e, context);2925 if (multilines)2926 deindent();2927 push('}');2928 }2929 }2930 push('`');2931}2932function genIfStatement(node, context) {2933 const { push, indent, deindent } = context;2934 const { test, consequent, alternate } = node;2935 push(`if (`);2936 genNode(test, context);2937 push(`) {`);2938 indent();2939 genNode(consequent, context);2940 deindent();2941 push(`}`);2942 if (alternate) {2943 push(` else `);2944 if (alternate.type === 23 /* JS_IF_STATEMENT */) {2945 genIfStatement(alternate, context);2946 }2947 else {2948 push(`{`);2949 indent();2950 genNode(alternate, context);2951 deindent();2952 push(`}`);2953 }2954 }2955}2956function genAssignmentExpression(node, context) {2957 genNode(node.left, context);2958 context.push(` = `);2959 genNode(node.right, context);2960}2961function genSequenceExpression(node, context) {2962 context.push(`(`);2963 genNodeList(node.expressions, context);2964 context.push(`)`);2965}2966function genReturnStatement({ returns }, context) {2967 context.push(`return `);2968 if (shared.isArray(returns)) {2969 genNodeListAsArray(returns, context);2970 }2971 else {2972 genNode(returns, context);2973 }2974}2975function walkIdentifiers(root, onIdentifier, includeAll = false, parentStack = [], knownIds = Object.create(null)) {2976 const rootExp = root.type === 'Program' &&2977 root.body[0].type === 'ExpressionStatement' &&2978 root.body[0].expression;2979 estreeWalker.walk(root, {2980 enter(node, parent) {2981 parent && parentStack.push(parent);2982 if (parent &&2983 parent.type.startsWith('TS') &&2984 parent.type !== 'TSAsExpression' &&2985 parent.type !== 'TSNonNullExpression' &&2986 parent.type !== 'TSTypeAssertion') {2987 return this.skip();2988 }2989 if (node.type === 'Identifier') {2990 const isLocal = !!knownIds[node.name];2991 const isRefed = isReferencedIdentifier(node, parent, parentStack);2992 if (includeAll || (isRefed && !isLocal)) {2993 onIdentifier(node, parent, parentStack, isRefed, isLocal);2994 }2995 }2996 else if (node.type === 'ObjectProperty' &&2997 parent.type === 'ObjectPattern') {2998 node.inPattern = true;2999 }3000 else if (isFunctionType(node)) {3001 // walk function expressions and add its arguments to known identifiers3002 // so that we don't prefix them3003 walkFunctionParams(node, id => markScopeIdentifier(node, id, knownIds));3004 }3005 else if (node.type === 'BlockStatement') {3006 // #3445 record block-level local variables3007 walkBlockDeclarations(node, id => markScopeIdentifier(node, id, knownIds));3008 }3009 },3010 leave(node, parent) {3011 parent && parentStack.pop();3012 if (node !== rootExp && node.scopeIds) {3013 for (const id of node.scopeIds) {3014 knownIds[id]--;3015 if (knownIds[id] === 0) {3016 delete knownIds[id];3017 }3018 }3019 }3020 }3021 });3022}3023function isReferencedIdentifier(id, parent, parentStack) {3024 if (!parent) {3025 return true;3026 }3027 // is a special keyword but parsed as identifier3028 if (id.name === 'arguments') {3029 return false;3030 }3031 if (isReferenced(id, parent)) {3032 return true;3033 }3034 // babel's isReferenced check returns false for ids being assigned to, so we3035 // need to cover those cases here3036 switch (parent.type) {3037 case 'AssignmentExpression':3038 case 'AssignmentPattern':3039 return true;3040 case 'ObjectPattern':3041 case 'ArrayPattern':3042 return isInDestructureAssignment(parent, parentStack);3043 }3044 return false;3045}3046function isInDestructureAssignment(parent, parentStack) {3047 if (parent &&3048 (parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')) {3049 let i = parentStack.length;3050 while (i--) {3051 const p = parentStack[i];3052 if (p.type === 'AssignmentExpression') {3053 return true;3054 }3055 else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {3056 break;3057 }3058 }3059 }3060 return false;3061}3062function walkFunctionParams(node, onIdent) {3063 for (const p of node.params) {3064 for (const id of extractIdentifiers(p)) {3065 onIdent(id);3066 }3067 }3068}3069function walkBlockDeclarations(block, onIdent) {3070 for (const stmt of block.body) {3071 if (stmt.type === 'VariableDeclaration') {3072 if (stmt.declare)3073 continue;3074 for (const decl of stmt.declarations) {3075 for (const id of extractIdentifiers(decl.id)) {3076 onIdent(id);3077 }3078 }3079 }3080 else if (stmt.type === 'FunctionDeclaration' ||3081 stmt.type === 'ClassDeclaration') {3082 if (stmt.declare || !stmt.id)3083 continue;3084 onIdent(stmt.id);3085 }3086 }3087}3088function extractIdentifiers(param, nodes = []) {3089 switch (param.type) {3090 case 'Identifier':3091 nodes.push(param);3092 break;3093 case 'MemberExpression':3094 let object = param;3095 while (object.type === 'MemberExpression') {3096 object = object.object;3097 }3098 nodes.push(object);3099 break;3100 case 'ObjectPattern':3101 for (const prop of param.properties) {3102 if (prop.type === 'RestElement') {3103 extractIdentifiers(prop.argument, nodes);3104 }3105 else {3106 extractIdentifiers(prop.value, nodes);3107 }3108 }3109 break;3110 case 'ArrayPattern':3111 param.elements.forEach(element => {3112 if (element)3113 extractIdentifiers(element, nodes);3114 });3115 break;3116 case 'RestElement':3117 extractIdentifiers(param.argument, nodes);3118 break;3119 case 'AssignmentPattern':3120 extractIdentifiers(param.left, nodes);3121 break;3122 }3123 return nodes;3124}3125function markScopeIdentifier(node, child, knownIds) {3126 const { name } = child;3127 if (node.scopeIds && node.scopeIds.has(name)) {3128 return;3129 }3130 if (name in knownIds) {3131 knownIds[name]++;3132 }3133 else {3134 knownIds[name] = 1;3135 }3136 (node.scopeIds || (node.scopeIds = new Set())).add(name);3137}3138const isFunctionType = (node) => {3139 return /Function(?:Expression|Declaration)$|Method$/.test(node.type);3140};3141const isStaticProperty = (node) => node &&3142 (node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&3143 !node.computed;3144const isStaticPropertyKey = (node, parent) => isStaticProperty(parent) && parent.key === node;3145/**3146 * Copied from https://github.com/babel/babel/blob/main/packages/babel-types/src/validators/isReferenced.ts3147 * To avoid runtime dependency on @babel/types (which includes process references)3148 * This file should not change very often in babel but we may need to keep it3149 * up-to-date from time to time.3150 *3151 * https://github.com/babel/babel/blob/main/LICENSE3152 *3153 */3154function isReferenced(node, parent, grandparent) {3155 switch (parent.type) {3156 // yes: PARENT[NODE]3157 // yes: NODE.child3158 // no: parent.NODE3159 case 'MemberExpression':3160 case 'OptionalMemberExpression':3161 if (parent.property === node) {3162 return !!parent.computed;3163 }3164 return parent.object === node;3165 case 'JSXMemberExpression':3166 return parent.object === node;3167 // no: let NODE = init;3168 // yes: let id = NODE;3169 case 'VariableDeclarator':3170 return parent.init === node;3171 // yes: () => NODE3172 // no: (NODE) => {}3173 case 'ArrowFunctionExpression':3174 return parent.body === node;3175 // no: class { #NODE; }3176 // no: class { get #NODE() {} }3177 // no: class { #NODE() {} }3178 // no: class { fn() { return this.#NODE; } }3179 case 'PrivateName':3180 return false;3181 // no: class { NODE() {} }3182 // yes: class { [NODE]() {} }3183 // no: class { foo(NODE) {} }3184 case 'ClassMethod':3185 case 'ClassPrivateMethod':3186 case 'ObjectMethod':3187 if (parent.key === node) {3188 return !!parent.computed;3189 }3190 return false;3191 // yes: { [NODE]: "" }3192 // no: { NODE: "" }3193 // depends: { NODE }3194 // depends: { key: NODE }3195 case 'ObjectProperty':3196 if (parent.key === node) {3197 return !!parent.computed;3198 }3199 // parent.value === node3200 return !grandparent || grandparent.type !== 'ObjectPattern';3201 // no: class { NODE = value; }3202 // yes: class { [NODE] = value; }3203 // yes: class { key = NODE; }3204 case 'ClassProperty':3205 if (parent.key === node) {3206 return !!parent.computed;3207 }3208 return true;3209 case 'ClassPrivateProperty':3210 return parent.key !== node;3211 // no: class NODE {}3212 // yes: class Foo extends NODE {}3213 case 'ClassDeclaration':3214 case 'ClassExpression':3215 return parent.superClass === node;3216 // yes: left = NODE;3217 // no: NODE = right;3218 case 'AssignmentExpression':3219 return parent.right === node;3220 // no: [NODE = foo] = [];3221 // yes: [foo = NODE] = [];3222 case 'AssignmentPattern':3223 return parent.right === node;3224 // no: NODE: for (;;) {}3225 case 'LabeledStatement':3226 return false;3227 // no: try {} catch (NODE) {}3228 case 'CatchClause':3229 return false;3230 // no: function foo(...NODE) {}3231 case 'RestElement':3232 return false;3233 case 'BreakStatement':3234 case 'ContinueStatement':3235 return false;3236 // no: function NODE() {}3237 // no: function foo(NODE) {}3238 case 'FunctionDeclaration':3239 case 'FunctionExpression':3240 return false;3241 // no: export NODE from "foo";3242 // no: export * as NODE from "foo";3243 case 'ExportNamespaceSpecifier':3244 case 'ExportDefaultSpecifier':3245 return false;3246 // no: export { foo as NODE };3247 // yes: export { NODE as foo };3248 // no: export { NODE as foo } from "foo";3249 case 'ExportSpecifier':3250 // @ts-expect-error3251 if (grandparent === null || grandparent === void 0 ? void 0 : grandparent.source) {3252 return false;3253 }3254 return parent.local === node;3255 // no: import NODE from "foo";3256 // no: import * as NODE from "foo";3257 // no: import { NODE as foo } from "foo";3258 // no: import { foo as NODE } from "foo";3259 // no: import NODE from "bar";3260 case 'ImportDefaultSpecifier':3261 case 'ImportNamespaceSpecifier':3262 case 'ImportSpecifier':3263 return false;3264 // no: import "foo" assert { NODE: "json" }3265 case 'ImportAttribute':3266 return false;3267 // no: <div NODE="foo" />3268 case 'JSXAttribute':3269 return false;3270 // no: [NODE] = [];3271 // no: ({ NODE }) = [];3272 case 'ObjectPattern':3273 case 'ArrayPattern':3274 return false;3275 // no: new.NODE3276 // no: NODE.target3277 case 'MetaProperty':3278 return false;3279 // yes: type X = { somePropert: NODE }3280 // no: type X = { NODE: OtherType }3281 case 'ObjectTypeProperty':3282 return parent.key !== node;3283 // yes: enum X { Foo = NODE }3284 // no: enum X { NODE }3285 case 'TSEnumMember':3286 return parent.id !== node;3287 // yes: { [NODE]: value }3288 // no: { NODE: value }3289 case 'TSPropertySignature':3290 if (parent.key === node) {3291 return !!parent.computed;3292 }3293 return true;3294 }3295 return true;3296}3297const isLiteralWhitelisted = /*#__PURE__*/ shared.makeMap('true,false,null,this');3298const transformExpression = (node, context) => {3299 if (node.type === 5 /* INTERPOLATION */) {3300 node.content = processExpression(node.content, context);3301 }3302 else if (node.type === 1 /* ELEMENT */) {3303 // handle directives on element3304 for (let i = 0; i < node.props.length; i++) {3305 const dir = node.props[i];3306 // do not process for v-on & v-for since they are special handled3307 if (dir.type === 7 /* DIRECTIVE */ && dir.name !== 'for') {3308 const exp = dir.exp;3309 const arg = dir.arg;3310 // do not process exp if this is v-on:arg - we need special handling3311 // for wrapping inline statements.3312 if (exp &&3313 exp.type === 4 /* SIMPLE_EXPRESSION */ &&3314 !(dir.name === 'on' && arg)) {3315 dir.exp = processExpression(exp, context, 3316 // slot args must be processed as function params3317 dir.name === 'slot');3318 }3319 if (arg && arg.type === 4 /* SIMPLE_EXPRESSION */ && !arg.isStatic) {3320 dir.arg = processExpression(arg, context);3321 }3322 }3323 }3324 }3325};3326// Important: since this function uses Node.js only dependencies, it should3327// always be used with a leading !false check so that it can be3328// tree-shaken from the browser build.3329function processExpression(node, context, 3330// some expressions like v-slot props & v-for aliases should be parsed as3331// function params3332asParams = false, 3333// v-on handler values may contain multiple statements3334asRawStatements = false, localVars = Object.create(context.identifiers)) {3335 if (!context.prefixIdentifiers || !node.content.trim()) {3336 return node;3337 }3338 const { inline, bindingMetadata } = context;3339 const rewriteIdentifier = (raw, parent, id) => {3340 const type = shared.hasOwn(bindingMetadata, raw) && bindingMetadata[raw];3341 if (inline) {3342 // x = y3343 const isAssignmentLVal = parent && parent.type === 'AssignmentExpression' && parent.left === id;3344 // x++3345 const isUpdateArg = parent && parent.type === 'UpdateExpression' && parent.argument === id;3346 // ({ x } = y)3347 const isDestructureAssignment = parent && isInDestructureAssignment(parent, parentStack);3348 if (type === "setup-const" /* SETUP_CONST */ || localVars[raw]) {3349 return raw;3350 }3351 else if (type === "setup-ref" /* SETUP_REF */) {3352 return `${raw}.value`;3353 }3354 else if (type === "setup-maybe-ref" /* SETUP_MAYBE_REF */) {3355 // const binding that may or may not be ref3356 // if it's not a ref, then assignments don't make sense -3357 // so we ignore the non-ref assignment case and generate code3358 // that assumes the value to be a ref for more efficiency3359 return isAssignmentLVal || isUpdateArg || isDestructureAssignment3360 ? `${raw}.value`3361 : `${context.helperString(UNREF)}(${raw})`;3362 }3363 else if (type === "setup-let" /* SETUP_LET */) {3364 if (isAssignmentLVal) {3365 // let binding.3366 // this is a bit more tricky as we need to cover the case where3367 // let is a local non-ref value, and we need to replicate the3368 // right hand side value.3369 // x = y --> isRef(x) ? x.value = y : x = y3370 const { right: rVal, operator } = parent;3371 const rExp = rawExp.slice(rVal.start - 1, rVal.end - 1);3372 const rExpString = stringifyExpression(processExpression(createSimpleExpression(rExp, false), context, false, false, knownIds));3373 return `${context.helperString(IS_REF)}(${raw})${context.isTS ? ` //@ts-ignore\n` : ``} ? ${raw}.value ${operator} ${rExpString} : ${raw}`;3374 }3375 else if (isUpdateArg) {3376 // make id replace parent in the code range so the raw update operator3377 // is removed3378 id.start = parent.start;3379 id.end = parent.end;3380 const { prefix: isPrefix, operator } = parent;3381 const prefix = isPrefix ? operator : ``;3382 const postfix = isPrefix ? `` : operator;3383 // let binding.3384 // x++ --> isRef(a) ? a.value++ : a++3385 return `${context.helperString(IS_REF)}(${raw})${context.isTS ? ` //@ts-ignore\n` : ``} ? ${prefix}${raw}.value${postfix} : ${prefix}${raw}${postfix}`;3386 }3387 else if (isDestructureAssignment) {3388 // TODO3389 // let binding in a destructure assignment - it's very tricky to3390 // handle both possible cases here without altering the original3391 // structure of the code, so we just assume it's not a ref here3392 // for now3393 return raw;3394 }3395 else {3396 return `${context.helperString(UNREF)}(${raw})`;3397 }3398 }3399 else if (type === "props" /* PROPS */) {3400 // use __props which is generated by compileScript so in ts mode3401 // it gets correct type3402 return `__props.${raw}`;3403 }3404 else if (type === "props-aliased" /* PROPS_ALIASED */) {3405 // prop with a different local alias (from defineProps() destructure)3406 return `__props.${bindingMetadata.__propsAliases[raw]}`;3407 }3408 }3409 else {3410 if (type && type.startsWith('setup')) {3411 // setup bindings in non-inline mode3412 return `$setup.${raw}`;3413 }3414 else if (type === "props-aliased" /* PROPS_ALIASED */) {3415 return `$props.${bindingMetadata.__propsAliases[raw]}`;3416 }3417 else if (type) {3418 return `$${type}.${raw}`;3419 }3420 }3421 // fallback to ctx3422 return `_ctx.${raw}`;3423 };3424 // fast path if expression is a simple identifier.3425 const rawExp = node.content;3426 // bail constant on parens (function invocation) and dot (member access)3427 const bailConstant = rawExp.indexOf(`(`) > -1 || rawExp.indexOf('.') > 0;3428 if (isSimpleIdentifier(rawExp)) {3429 const isScopeVarReference = context.identifiers[rawExp];3430 const isAllowedGlobal = shared.isGloballyWhitelisted(rawExp);3431 const isLiteral = isLiteralWhitelisted(rawExp);3432 if (!asParams && !isScopeVarReference && !isAllowedGlobal && !isLiteral) {3433 // const bindings exposed from setup can be skipped for patching but3434 // cannot be hoisted to module scope3435 if (bindingMetadata[node.content] === "setup-const" /* SETUP_CONST */) {3436 node.constType = 1 /* CAN_SKIP_PATCH */;3437 }3438 node.content = rewriteIdentifier(rawExp);3439 }3440 else if (!isScopeVarReference) {3441 if (isLiteral) {3442 node.constType = 3 /* CAN_STRINGIFY */;3443 }3444 else {3445 node.constType = 2 /* CAN_HOIST */;3446 }3447 }3448 return node;3449 }3450 let ast;3451 // exp needs to be parsed differently:3452 // 1. Multiple inline statements (v-on, with presence of `;`): parse as raw3453 // exp, but make sure to pad with spaces for consistent ranges3454 // 2. Expressions: wrap with parens (for e.g. object expressions)3455 // 3. Function arguments (v-for, v-slot): place in a function argument position3456 const source = asRawStatements3457 ? ` ${rawExp} `3458 : `(${rawExp})${asParams ? `=>{}` : ``}`;3459 try {3460 ast = parser.parse(source, {3461 plugins: context.expressionPlugins3462 }).program;3463 }3464 catch (e) {3465 context.onError(createCompilerError(44 /* X_INVALID_EXPRESSION */, node.loc, undefined, e.message));3466 return node;3467 }3468 const ids = [];3469 const parentStack = [];3470 const knownIds = Object.create(context.identifiers);3471 walkIdentifiers(ast, (node, parent, _, isReferenced, isLocal) => {3472 if (isStaticPropertyKey(node, parent)) {3473 return;3474 }3475 // v2 wrapped filter call3476 if (node.name.startsWith('_filter_')) {3477 return;3478 }3479 const needPrefix = isReferenced && canPrefix(node);3480 if (needPrefix && !isLocal) {3481 if (isStaticProperty(parent) && parent.shorthand) {3482 node.prefix = `${node.name}: `;3483 }3484 node.name = rewriteIdentifier(node.name, parent, node);3485 ids.push(node);3486 }3487 else {3488 // The identifier is considered constant unless it's pointing to a3489 // local scope variable (a v-for alias, or a v-slot prop)3490 if (!(needPrefix && isLocal) && !bailConstant) {3491 node.isConstant = true;3492 }3493 // also generate sub-expressions for other identifiers for better3494 // source map support. (except for property keys which are static)3495 ids.push(node);3496 }3497 }, true, // invoke on ALL identifiers3498 parentStack, knownIds);3499 // We break up the compound expression into an array of strings and sub3500 // expressions (for identifiers that have been prefixed). In codegen, if3501 // an ExpressionNode has the `.children` property, it will be used instead of3502 // `.content`.3503 const children = [];3504 ids.sort((a, b) => a.start - b.start);3505 ids.forEach((id, i) => {3506 // range is offset by -1 due to the wrapping parens when parsed3507 const start = id.start - 1;3508 const end = id.end - 1;3509 const last = ids[i - 1];3510 const leadingText = rawExp.slice(last ? last.end - 1 : 0, start);3511 if (leadingText.length || id.prefix) {3512 children.push(leadingText + (id.prefix || ``));3513 }3514 const source = rawExp.slice(start, end);3515 children.push(createSimpleExpression(id.name, false, {3516 source,3517 start: advancePositionWithClone(node.loc.start, source, start),3518 end: advancePositionWithClone(node.loc.start, source, end)3519 }, id.isConstant ? 3 /* CAN_STRINGIFY */ : 0 /* NOT_CONSTANT */));3520 if (i === ids.length - 1 && end < rawExp.length) {3521 children.push(rawExp.slice(end));3522 }3523 });3524 let ret;3525 if (children.length) {3526 ret = createCompoundExpression(children, node.loc);3527 }3528 else {3529 ret = node;3530 ret.constType = bailConstant3531 ? 0 /* NOT_CONSTANT */3532 : 3 /* CAN_STRINGIFY */;3533 }3534 ret.identifiers = Object.keys(knownIds);3535 return ret;3536}3537function canPrefix(id) {3538 // skip whitelisted globals3539 if (shared.isGloballyWhitelisted(id.name)) {3540 return false;3541 }3542 // special case for webpack compilation3543 if (id.name === 'require') {3544 return false;3545 }3546 return true;3547}3548function stringifyExpression(exp) {3549 if (shared.isString(exp)) {3550 return exp;3551 }3552 else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {3553 return exp.content;3554 }3555 else {3556 return exp.children3557 .map(stringifyExpression)3558 .join('');3559 }3560}3561const transformIf = createStructuralDirectiveTransform(/^(if|else|else-if)$/, (node, dir, context) => {3562 return processIf(node, dir, context, (ifNode, branch, isRoot) => {3563 // #1587: We need to dynamically increment the key based on the current3564 // node's sibling nodes, since chained v-if/else branches are3565 // rendered at the same depth3566 const siblings = context.parent.children;3567 let i = siblings.indexOf(ifNode);3568 let key = 0;3569 while (i-- >= 0) {3570 const sibling = siblings[i];3571 if (sibling && sibling.type === 9 /* IF */) {3572 key += sibling.branches.length;3573 }3574 }3575 // Exit callback. Complete the codegenNode when all children have been3576 // transformed.3577 return () => {3578 if (isRoot) {3579 ifNode.codegenNode = createCodegenNodeForBranch(branch, key, context);3580 }3581 else {3582 // attach this branch's codegen node to the v-if root.3583 const parentCondition = getParentCondition(ifNode.codegenNode);3584 parentCondition.alternate = createCodegenNodeForBranch(branch, key + ifNode.branches.length - 1, context);3585 }3586 };3587 });3588});3589// target-agnostic transform used for both Client and SSR3590function processIf(node, dir, context, processCodegen) {3591 if (dir.name !== 'else' &&3592 (!dir.exp || !dir.exp.content.trim())) {3593 const loc = dir.exp ? dir.exp.loc : node.loc;3594 context.onError(createCompilerError(28 /* X_V_IF_NO_EXPRESSION */, dir.loc));3595 dir.exp = createSimpleExpression(`true`, false, loc);3596 }3597 if (context.prefixIdentifiers && dir.exp) {3598 // dir.exp can only be simple expression because vIf transform is applied3599 // before expression transform.3600 dir.exp = processExpression(dir.exp, context);3601 }3602 if (dir.name === 'if') {3603 const branch = createIfBranch(node, dir);3604 const ifNode = {3605 type: 9 /* IF */,3606 loc: node.loc,3607 branches: [branch]3608 };3609 context.replaceNode(ifNode);3610 if (processCodegen) {3611 return processCodegen(ifNode, branch, true);3612 }3613 }3614 else {3615 // locate the adjacent v-if3616 const siblings = context.parent.children;3617 const comments = [];3618 let i = siblings.indexOf(node);3619 while (i-- >= -1) {3620 const sibling = siblings[i];3621 if (sibling && sibling.type === 3 /* COMMENT */) {3622 context.removeNode(sibling);3623 comments.unshift(sibling);3624 continue;3625 }3626 if (sibling &&3627 sibling.type === 2 /* TEXT */ &&3628 !sibling.content.trim().length) {3629 context.removeNode(sibling);3630 continue;3631 }3632 if (sibling && sibling.type === 9 /* IF */) {3633 // Check if v-else was followed by v-else-if3634 if (dir.name === 'else-if' &&3635 sibling.branches[sibling.branches.length - 1].condition === undefined) {3636 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));3637 }3638 // move the node to the if node's branches3639 context.removeNode();3640 const branch = createIfBranch(node, dir);3641 if (comments.length &&3642 // #3619 ignore comments if the v-if is direct child of <transition>3643 !(context.parent &&3644 context.parent.type === 1 /* ELEMENT */ &&3645 isBuiltInType(context.parent.tag, 'transition'))) {3646 branch.children = [...comments, ...branch.children];3647 }3648 // check if user is forcing same key on different branches3649 {3650 const key = branch.userKey;3651 if (key) {3652 sibling.branches.forEach(({ userKey }) => {3653 if (isSameKey(userKey, key)) {3654 context.onError(createCompilerError(29 /* X_V_IF_SAME_KEY */, branch.userKey.loc));3655 }3656 });3657 }3658 }3659 sibling.branches.push(branch);3660 const onExit = processCodegen && processCodegen(sibling, branch, false);3661 // since the branch was removed, it will not be traversed.3662 // make sure to traverse here.3663 traverseNode(branch, context);3664 // call on exit3665 if (onExit)3666 onExit();3667 // make sure to reset currentNode after traversal to indicate this3668 // node has been removed.3669 context.currentNode = null;3670 }3671 else {3672 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));3673 }3674 break;3675 }3676 }3677}3678function createIfBranch(node, dir) {3679 return {3680 type: 10 /* IF_BRANCH */,3681 loc: node.loc,3682 condition: dir.name === 'else' ? undefined : dir.exp,3683 children: node.tagType === 3 /* TEMPLATE */ && !findDir(node, 'for')3684 ? node.children3685 : [node],3686 userKey: findProp(node, `key`)3687 };3688}3689function createCodegenNodeForBranch(branch, keyIndex, context) {3690 if (branch.condition) {3691 return createConditionalExpression(branch.condition, createChildrenCodegenNode(branch, keyIndex, context), 3692 // make sure to pass in asBlock: true so that the comment node call3693 // closes the current block.3694 createCallExpression(context.helper(CREATE_COMMENT), [3695 '"v-if"' ,3696 'true'3697 ]));3698 }3699 else {3700 return createChildrenCodegenNode(branch, keyIndex, context);3701 }3702}3703function createChildrenCodegenNode(branch, keyIndex, context) {3704 const { helper } = context;3705 const keyProperty = createObjectProperty(`key`, createSimpleExpression(`${keyIndex}`, false, locStub, 2 /* CAN_HOIST */));3706 const { children } = branch;3707 const firstChild = children[0];3708 const needFragmentWrapper = children.length !== 1 || firstChild.type !== 1 /* ELEMENT */;3709 if (needFragmentWrapper) {3710 if (children.length === 1 && firstChild.type === 11 /* FOR */) {3711 // optimize away nested fragments when child is a ForNode3712 const vnodeCall = firstChild.codegenNode;3713 injectProp(vnodeCall, keyProperty, context);3714 return vnodeCall;3715 }3716 else {3717 let patchFlag = 64 /* STABLE_FRAGMENT */;3718 let patchFlagText = shared.PatchFlagNames[64 /* STABLE_FRAGMENT */];3719 // check if the fragment actually contains a single valid child with3720 // the rest being comments3721 if (children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {3722 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;3723 patchFlagText += `, ${shared.PatchFlagNames[2048 /* DEV_ROOT_FRAGMENT */]}`;3724 }3725 return createVNodeCall(context, helper(FRAGMENT), createObjectExpression([keyProperty]), children, patchFlag + (` /* ${patchFlagText} */` ), undefined, undefined, true, false, false /* isComponent */, branch.loc);3726 }3727 }3728 else {3729 const ret = firstChild.codegenNode;3730 const vnodeCall = getMemoedVNodeCall(ret);3731 // Change createVNode to createBlock.3732 if (vnodeCall.type === 13 /* VNODE_CALL */) {3733 makeBlock(vnodeCall, context);3734 }3735 // inject branch key3736 injectProp(vnodeCall, keyProperty, context);3737 return ret;3738 }3739}3740function isSameKey(a, b) {3741 if (!a || a.type !== b.type) {3742 return false;3743 }3744 if (a.type === 6 /* ATTRIBUTE */) {3745 if (a.value.content !== b.value.content) {3746 return false;3747 }3748 }3749 else {3750 // directive3751 const exp = a.exp;3752 const branchExp = b.exp;3753 if (exp.type !== branchExp.type) {3754 return false;3755 }3756 if (exp.type !== 4 /* SIMPLE_EXPRESSION */ ||3757 exp.isStatic !== branchExp.isStatic ||3758 exp.content !== branchExp.content) {3759 return false;3760 }3761 }3762 return true;3763}3764function getParentCondition(node) {3765 while (true) {3766 if (node.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3767 if (node.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3768 node = node.alternate;3769 }3770 else {3771 return node;3772 }3773 }3774 else if (node.type === 20 /* JS_CACHE_EXPRESSION */) {3775 node = node.value;3776 }3777 }3778}3779const transformFor = createStructuralDirectiveTransform('for', (node, dir, context) => {3780 const { helper, removeHelper } = context;3781 return processFor(node, dir, context, forNode => {3782 // create the loop render function expression now, and add the3783 // iterator on exit after all children have been traversed3784 const renderExp = createCallExpression(helper(RENDER_LIST), [3785 forNode.source3786 ]);3787 const memo = findDir(node, 'memo');3788 const keyProp = findProp(node, `key`);3789 const keyExp = keyProp &&3790 (keyProp.type === 6 /* ATTRIBUTE */3791 ? createSimpleExpression(keyProp.value.content, true)3792 : keyProp.exp);3793 const keyProperty = keyProp ? createObjectProperty(`key`, keyExp) : null;3794 if (context.prefixIdentifiers &&3795 keyProperty &&3796 keyProp.type !== 6 /* ATTRIBUTE */) {3797 // #2085 process :key expression needs to be processed in order for it3798 // to behave consistently for <template v-for> and <div v-for>.3799 // In the case of `<template v-for>`, the node is discarded and never3800 // traversed so its key expression won't be processed by the normal3801 // transforms.3802 keyProperty.value = processExpression(keyProperty.value, context);3803 }3804 const isStableFragment = forNode.source.type === 4 /* SIMPLE_EXPRESSION */ &&3805 forNode.source.constType > 0 /* NOT_CONSTANT */;3806 const fragmentFlag = isStableFragment3807 ? 64 /* STABLE_FRAGMENT */3808 : keyProp3809 ? 128 /* KEYED_FRAGMENT */3810 : 256 /* UNKEYED_FRAGMENT */;3811 forNode.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, renderExp, fragmentFlag +3812 (` /* ${shared.PatchFlagNames[fragmentFlag]} */` ), undefined, undefined, true /* isBlock */, !isStableFragment /* disableTracking */, false /* isComponent */, node.loc);3813 return () => {3814 // finish the codegen now that all children have been traversed3815 let childBlock;3816 const isTemplate = isTemplateNode(node);3817 const { children } = forNode;3818 // check <template v-for> key placement3819 if (isTemplate) {3820 node.children.some(c => {3821 if (c.type === 1 /* ELEMENT */) {3822 const key = findProp(c, 'key');3823 if (key) {3824 context.onError(createCompilerError(33 /* X_V_FOR_TEMPLATE_KEY_PLACEMENT */, key.loc));3825 return true;3826 }3827 }3828 });3829 }3830 const needFragmentWrapper = children.length !== 1 || children[0].type !== 1 /* ELEMENT */;3831 const slotOutlet = isSlotOutlet(node)3832 ? node3833 : isTemplate &&3834 node.children.length === 1 &&3835 isSlotOutlet(node.children[0])3836 ? node.children[0] // api-extractor somehow fails to infer this3837 : null;3838 if (slotOutlet) {3839 // <slot v-for="..."> or <template v-for="..."><slot/></template>3840 childBlock = slotOutlet.codegenNode;3841 if (isTemplate && keyProperty) {3842 // <template v-for="..." :key="..."><slot/></template>3843 // we need to inject the key to the renderSlot() call.3844 // the props for renderSlot is passed as the 3rd argument.3845 injectProp(childBlock, keyProperty, context);3846 }3847 }3848 else if (needFragmentWrapper) {3849 // <template v-for="..."> with text or multi-elements3850 // should generate a fragment block for each loop3851 childBlock = createVNodeCall(context, helper(FRAGMENT), keyProperty ? createObjectExpression([keyProperty]) : undefined, node.children, 64 /* STABLE_FRAGMENT */ +3852 (` /* ${shared.PatchFlagNames[64 /* STABLE_FRAGMENT */]} */`3853 ), undefined, undefined, true, undefined, false /* isComponent */);3854 }3855 else {3856 // Normal element v-for. Directly use the child's codegenNode3857 // but mark it as a block.3858 childBlock = children[0]3859 .codegenNode;3860 if (isTemplate && keyProperty) {3861 injectProp(childBlock, keyProperty, context);3862 }3863 if (childBlock.isBlock !== !isStableFragment) {3864 if (childBlock.isBlock) {3865 // switch from block to vnode3866 removeHelper(OPEN_BLOCK);3867 removeHelper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3868 }3869 else {3870 // switch from vnode to block3871 removeHelper(getVNodeHelper(context.inSSR, childBlock.isComponent));3872 }3873 }3874 childBlock.isBlock = !isStableFragment;3875 if (childBlock.isBlock) {3876 helper(OPEN_BLOCK);3877 helper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3878 }3879 else {3880 helper(getVNodeHelper(context.inSSR, childBlock.isComponent));3881 }3882 }3883 if (memo) {3884 const loop = createFunctionExpression(createForLoopParams(forNode.parseResult, [3885 createSimpleExpression(`_cached`)3886 ]));3887 loop.body = createBlockStatement([3888 createCompoundExpression([`const _memo = (`, memo.exp, `)`]),3889 createCompoundExpression([3890 `if (_cached`,3891 ...(keyExp ? [` && _cached.key === `, keyExp] : []),3892 ` && ${context.helperString(IS_MEMO_SAME)}(_cached, _memo)) return _cached`3893 ]),3894 createCompoundExpression([`const _item = `, childBlock]),3895 createSimpleExpression(`_item.memo = _memo`),3896 createSimpleExpression(`return _item`)3897 ]);3898 renderExp.arguments.push(loop, createSimpleExpression(`_cache`), createSimpleExpression(String(context.cached++)));3899 }3900 else {3901 renderExp.arguments.push(createFunctionExpression(createForLoopParams(forNode.parseResult), childBlock, true /* force newline */));3902 }3903 };3904 });3905});3906// target-agnostic transform used for both Client and SSR3907function processFor(node, dir, context, processCodegen) {3908 if (!dir.exp) {3909 context.onError(createCompilerError(31 /* X_V_FOR_NO_EXPRESSION */, dir.loc));3910 return;3911 }3912 const parseResult = parseForExpression(3913 // can only be simple expression because vFor transform is applied3914 // before expression transform.3915 dir.exp, context);3916 if (!parseResult) {3917 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));3918 return;3919 }3920 const { addIdentifiers, removeIdentifiers, scopes } = context;3921 const { source, value, key, index } = parseResult;3922 const forNode = {3923 type: 11 /* FOR */,3924 loc: dir.loc,3925 source,3926 valueAlias: value,3927 keyAlias: key,3928 objectIndexAlias: index,3929 parseResult,3930 children: isTemplateNode(node) ? node.children : [node]3931 };3932 context.replaceNode(forNode);3933 // bookkeeping3934 scopes.vFor++;3935 if (context.prefixIdentifiers) {3936 // scope management3937 // inject identifiers to context3938 value && addIdentifiers(value);3939 key && addIdentifiers(key);3940 index && addIdentifiers(index);3941 }3942 const onExit = processCodegen && processCodegen(forNode);3943 return () => {3944 scopes.vFor--;3945 if (context.prefixIdentifiers) {3946 value && removeIdentifiers(value);3947 key && removeIdentifiers(key);3948 index && removeIdentifiers(index);3949 }3950 if (onExit)3951 onExit();3952 };3953}3954const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;3955// This regex doesn't cover the case if key or index aliases have destructuring,3956// but those do not make sense in the first place, so this works in practice.3957const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;3958const stripParensRE = /^\(|\)$/g;3959function parseForExpression(input, context) {3960 const loc = input.loc;3961 const exp = input.content;3962 const inMatch = exp.match(forAliasRE);3963 if (!inMatch)3964 return;3965 const [, LHS, RHS] = inMatch;3966 const result = {3967 source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),3968 value: undefined,3969 key: undefined,3970 index: undefined3971 };3972 if (context.prefixIdentifiers) {3973 result.source = processExpression(result.source, context);3974 }3975 let valueContent = LHS.trim().replace(stripParensRE, '').trim();3976 const trimmedOffset = LHS.indexOf(valueContent);3977 const iteratorMatch = valueContent.match(forIteratorRE);3978 if (iteratorMatch) {3979 valueContent = valueContent.replace(forIteratorRE, '').trim();3980 const keyContent = iteratorMatch[1].trim();3981 let keyOffset;3982 if (keyContent) {3983 keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);3984 result.key = createAliasExpression(loc, keyContent, keyOffset);3985 if (context.prefixIdentifiers) {3986 result.key = processExpression(result.key, context, true);3987 }3988 }3989 if (iteratorMatch[2]) {3990 const indexContent = iteratorMatch[2].trim();3991 if (indexContent) {3992 result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key3993 ? keyOffset + keyContent.length3994 : trimmedOffset + valueContent.length));3995 if (context.prefixIdentifiers) {3996 result.index = processExpression(result.index, context, true);3997 }3998 }3999 }4000 }4001 if (valueContent) {4002 result.value = createAliasExpression(loc, valueContent, trimmedOffset);4003 if (context.prefixIdentifiers) {4004 result.value = processExpression(result.value, context, true);4005 }4006 }4007 return result;4008}4009function createAliasExpression(range, content, offset) {4010 return createSimpleExpression(content, false, getInnerRange(range, offset, content.length));4011}4012function createForLoopParams({ value, key, index }, memoArgs = []) {4013 return createParamsList([value, key, index, ...memoArgs]);4014}4015function createParamsList(args) {4016 let i = args.length;4017 while (i--) {4018 if (args[i])4019 break;4020 }4021 return args4022 .slice(0, i + 1)4023 .map((arg, i) => arg || createSimpleExpression(`_`.repeat(i + 1), false));4024}4025const defaultFallback = createSimpleExpression(`undefined`, false);4026// A NodeTransform that:4027// 1. Tracks scope identifiers for scoped slots so that they don't get prefixed4028// by transformExpression. This is only applied in non-browser builds with4029// { prefixIdentifiers: true }.4030// 2. Track v-slot depths so that we know a slot is inside another slot.4031// Note the exit callback is executed before buildSlots() on the same node,4032// so only nested slots see positive numbers.4033const trackSlotScopes = (node, context) => {4034 if (node.type === 1 /* ELEMENT */ &&4035 (node.tagType === 1 /* COMPONENT */ ||4036 node.tagType === 3 /* TEMPLATE */)) {4037 // We are only checking non-empty v-slot here4038 // since we only care about slots that introduce scope variables.4039 const vSlot = findDir(node, 'slot');4040 if (vSlot) {4041 const slotProps = vSlot.exp;4042 if (context.prefixIdentifiers) {4043 slotProps && context.addIdentifiers(slotProps);4044 }4045 context.scopes.vSlot++;4046 return () => {4047 if (context.prefixIdentifiers) {4048 slotProps && context.removeIdentifiers(slotProps);4049 }4050 context.scopes.vSlot--;4051 };4052 }4053 }4054};4055// A NodeTransform that tracks scope identifiers for scoped slots with v-for.4056// This transform is only applied in non-browser builds with { prefixIdentifiers: true }4057const trackVForSlotScopes = (node, context) => {4058 let vFor;4059 if (isTemplateNode(node) &&4060 node.props.some(isVSlot) &&4061 (vFor = findDir(node, 'for'))) {4062 const result = (vFor.parseResult = parseForExpression(vFor.exp, context));4063 if (result) {4064 const { value, key, index } = result;4065 const { addIdentifiers, removeIdentifiers } = context;4066 value && addIdentifiers(value);4067 key && addIdentifiers(key);4068 index && addIdentifiers(index);4069 return () => {4070 value && removeIdentifiers(value);4071 key && removeIdentifiers(key);4072 index && removeIdentifiers(index);4073 };4074 }4075 }4076};4077const buildClientSlotFn = (props, children, loc) => createFunctionExpression(props, children, false /* newline */, true /* isSlot */, children.length ? children[0].loc : loc);4078// Instead of being a DirectiveTransform, v-slot processing is called during4079// transformElement to build the slots object for a component.4080function buildSlots(node, context, buildSlotFn = buildClientSlotFn) {4081 context.helper(WITH_CTX);4082 const { children, loc } = node;4083 const slotsProperties = [];4084 const dynamicSlots = [];4085 // If the slot is inside a v-for or another v-slot, force it to be dynamic4086 // since it likely uses a scope variable.4087 let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0;4088 // with `prefixIdentifiers: true`, this can be further optimized to make4089 // it dynamic only when the slot actually uses the scope variables.4090 if (!context.ssr && context.prefixIdentifiers) {4091 hasDynamicSlots = hasScopeRef(node, context.identifiers);4092 }4093 // 1. Check for slot with slotProps on component itself.4094 // <Comp v-slot="{ prop }"/>4095 const onComponentSlot = findDir(node, 'slot', true);4096 if (onComponentSlot) {4097 const { arg, exp } = onComponentSlot;4098 if (arg && !isStaticExp(arg)) {4099 hasDynamicSlots = true;4100 }4101 slotsProperties.push(createObjectProperty(arg || createSimpleExpression('default', true), buildSlotFn(exp, children, loc)));4102 }4103 // 2. Iterate through children and check for template slots4104 // <template v-slot:foo="{ prop }">4105 let hasTemplateSlots = false;4106 let hasNamedDefaultSlot = false;4107 const implicitDefaultChildren = [];4108 const seenSlotNames = new Set();4109 for (let i = 0; i < children.length; i++) {4110 const slotElement = children[i];4111 let slotDir;4112 if (!isTemplateNode(slotElement) ||4113 !(slotDir = findDir(slotElement, 'slot', true))) {4114 // not a <template v-slot>, skip.4115 if (slotElement.type !== 3 /* COMMENT */) {4116 implicitDefaultChildren.push(slotElement);4117 }4118 continue;4119 }4120 if (onComponentSlot) {4121 // already has on-component slot - this is incorrect usage.4122 context.onError(createCompilerError(37 /* X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc));4123 break;4124 }4125 hasTemplateSlots = true;4126 const { children: slotChildren, loc: slotLoc } = slotElement;4127 const { arg: slotName = createSimpleExpression(`default`, true), exp: slotProps, loc: dirLoc } = slotDir;4128 // check if name is dynamic.4129 let staticSlotName;4130 if (isStaticExp(slotName)) {4131 staticSlotName = slotName ? slotName.content : `default`;4132 }4133 else {4134 hasDynamicSlots = true;4135 }4136 const slotFunction = buildSlotFn(slotProps, slotChildren, slotLoc);4137 // check if this slot is conditional (v-if/v-for)4138 let vIf;4139 let vElse;4140 let vFor;4141 if ((vIf = findDir(slotElement, 'if'))) {4142 hasDynamicSlots = true;4143 dynamicSlots.push(createConditionalExpression(vIf.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback));4144 }4145 else if ((vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))) {4146 // find adjacent v-if4147 let j = i;4148 let prev;4149 while (j--) {4150 prev = children[j];4151 if (prev.type !== 3 /* COMMENT */) {4152 break;4153 }4154 }4155 if (prev && isTemplateNode(prev) && findDir(prev, 'if')) {4156 // remove node4157 children.splice(i, 1);4158 i--;4159 // attach this slot to previous conditional4160 let conditional = dynamicSlots[dynamicSlots.length - 1];4161 while (conditional.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {4162 conditional = conditional.alternate;4163 }4164 conditional.alternate = vElse.exp4165 ? createConditionalExpression(vElse.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback)4166 : buildDynamicSlot(slotName, slotFunction);4167 }4168 else {4169 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, vElse.loc));4170 }4171 }4172 else if ((vFor = findDir(slotElement, 'for'))) {4173 hasDynamicSlots = true;4174 const parseResult = vFor.parseResult ||4175 parseForExpression(vFor.exp, context);4176 if (parseResult) {4177 // Render the dynamic slots as an array and add it to the createSlot()4178 // args. The runtime knows how to handle it appropriately.4179 dynamicSlots.push(createCallExpression(context.helper(RENDER_LIST), [4180 parseResult.source,4181 createFunctionExpression(createForLoopParams(parseResult), buildDynamicSlot(slotName, slotFunction), true /* force newline */)4182 ]));4183 }4184 else {4185 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc));4186 }4187 }4188 else {4189 // check duplicate static names4190 if (staticSlotName) {4191 if (seenSlotNames.has(staticSlotName)) {4192 context.onError(createCompilerError(38 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc));4193 continue;4194 }4195 seenSlotNames.add(staticSlotName);4196 if (staticSlotName === 'default') {4197 hasNamedDefaultSlot = true;4198 }4199 }4200 slotsProperties.push(createObjectProperty(slotName, slotFunction));4201 }4202 }4203 if (!onComponentSlot) {4204 const buildDefaultSlotProperty = (props, children) => {4205 const fn = buildSlotFn(props, children, loc);4206 if (context.compatConfig) {4207 fn.isNonScopedSlot = true;4208 }4209 return createObjectProperty(`default`, fn);4210 };4211 if (!hasTemplateSlots) {4212 // implicit default slot (on component)4213 slotsProperties.push(buildDefaultSlotProperty(undefined, children));4214 }4215 else if (implicitDefaultChildren.length &&4216 // #37664217 // with whitespace: 'preserve', whitespaces between slots will end up in4218 // implicitDefaultChildren. Ignore if all implicit children are whitespaces.4219 implicitDefaultChildren.some(node => isNonWhitespaceContent(node))) {4220 // implicit default slot (mixed with named slots)4221 if (hasNamedDefaultSlot) {4222 context.onError(createCompilerError(39 /* X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN */, implicitDefaultChildren[0].loc));4223 }4224 else {4225 slotsProperties.push(buildDefaultSlotProperty(undefined, implicitDefaultChildren));4226 }4227 }4228 }4229 const slotFlag = hasDynamicSlots4230 ? 2 /* DYNAMIC */4231 : hasForwardedSlots(node.children)4232 ? 3 /* FORWARDED */4233 : 1 /* STABLE */;4234 let slots = createObjectExpression(slotsProperties.concat(createObjectProperty(`_`, 4235 // 2 = compiled but dynamic = can skip normalization, but must run diff4236 // 1 = compiled and static = can skip normalization AND diff as optimized4237 createSimpleExpression(slotFlag + (` /* ${shared.slotFlagsText[slotFlag]} */` ), false))), loc);4238 if (dynamicSlots.length) {4239 slots = createCallExpression(context.helper(CREATE_SLOTS), [4240 slots,4241 createArrayExpression(dynamicSlots)4242 ]);4243 }4244 return {4245 slots,4246 hasDynamicSlots4247 };4248}4249function buildDynamicSlot(name, fn) {4250 return createObjectExpression([4251 createObjectProperty(`name`, name),4252 createObjectProperty(`fn`, fn)4253 ]);4254}4255function hasForwardedSlots(children) {4256 for (let i = 0; i < children.length; i++) {4257 const child = children[i];4258 switch (child.type) {4259 case 1 /* ELEMENT */:4260 if (child.tagType === 2 /* SLOT */ ||4261 hasForwardedSlots(child.children)) {4262 return true;4263 }4264 break;4265 case 9 /* IF */:4266 if (hasForwardedSlots(child.branches))4267 return true;4268 break;4269 case 10 /* IF_BRANCH */:4270 case 11 /* FOR */:4271 if (hasForwardedSlots(child.children))4272 return true;4273 break;4274 }4275 }4276 return false;4277}4278function isNonWhitespaceContent(node) {4279 if (node.type !== 2 /* TEXT */ && node.type !== 12 /* TEXT_CALL */)4280 return true;4281 return node.type === 2 /* TEXT */4282 ? !!node.content.trim()4283 : isNonWhitespaceContent(node.content);4284}4285// some directive transforms (e.g. v-model) may return a symbol for runtime4286// import, which should be used instead of a resolveDirective call.4287const directiveImportMap = new WeakMap();4288// generate a JavaScript AST for this element's codegen4289const transformElement = (node, context) => {4290 // perform the work on exit, after all child expressions have been4291 // processed and merged.4292 return function postTransformElement() {4293 node = context.currentNode;4294 if (!(node.type === 1 /* ELEMENT */ &&4295 (node.tagType === 0 /* ELEMENT */ ||4296 node.tagType === 1 /* COMPONENT */))) {4297 return;4298 }4299 const { tag, props } = node;4300 const isComponent = node.tagType === 1 /* COMPONENT */;4301 // The goal of the transform is to create a codegenNode implementing the4302 // VNodeCall interface.4303 let vnodeTag = isComponent4304 ? resolveComponentType(node, context)4305 : `"${tag}"`;4306 const isDynamicComponent = shared.isObject(vnodeTag) && vnodeTag.callee === RESOLVE_DYNAMIC_COMPONENT;4307 let vnodeProps;4308 let vnodeChildren;4309 let vnodePatchFlag;4310 let patchFlag = 0;4311 let vnodeDynamicProps;4312 let dynamicPropNames;4313 let vnodeDirectives;4314 let shouldUseBlock = 4315 // dynamic component may resolve to plain elements4316 isDynamicComponent ||4317 vnodeTag === TELEPORT ||4318 vnodeTag === SUSPENSE ||4319 (!isComponent &&4320 // <svg> and <foreignObject> must be forced into blocks so that block4321 // updates inside get proper isSVG flag at runtime. (#639, #643)4322 // This is technically web-specific, but splitting the logic out of core4323 // leads to too much unnecessary complexity.4324 (tag === 'svg' || tag === 'foreignObject'));4325 // props4326 if (props.length > 0) {4327 const propsBuildResult = buildProps(node, context);4328 vnodeProps = propsBuildResult.props;4329 patchFlag = propsBuildResult.patchFlag;4330 dynamicPropNames = propsBuildResult.dynamicPropNames;4331 const directives = propsBuildResult.directives;4332 vnodeDirectives =4333 directives && directives.length4334 ? createArrayExpression(directives.map(dir => buildDirectiveArgs(dir, context)))4335 : undefined;4336 if (propsBuildResult.shouldUseBlock) {4337 shouldUseBlock = true;4338 }4339 }4340 // children4341 if (node.children.length > 0) {4342 if (vnodeTag === KEEP_ALIVE) {4343 // Although a built-in component, we compile KeepAlive with raw children4344 // instead of slot functions so that it can be used inside Transition4345 // or other Transition-wrapping HOCs.4346 // To ensure correct updates with block optimizations, we need to:4347 // 1. Force keep-alive into a block. This avoids its children being4348 // collected by a parent block.4349 shouldUseBlock = true;4350 // 2. Force keep-alive to always be updated, since it uses raw children.4351 patchFlag |= 1024 /* DYNAMIC_SLOTS */;4352 if (node.children.length > 1) {4353 context.onError(createCompilerError(45 /* X_KEEP_ALIVE_INVALID_CHILDREN */, {4354 start: node.children[0].loc.start,4355 end: node.children[node.children.length - 1].loc.end,4356 source: ''4357 }));4358 }4359 }4360 const shouldBuildAsSlots = isComponent &&4361 // Teleport is not a real component and has dedicated runtime handling4362 vnodeTag !== TELEPORT &&4363 // explained above.4364 vnodeTag !== KEEP_ALIVE;4365 if (shouldBuildAsSlots) {4366 const { slots, hasDynamicSlots } = buildSlots(node, context);4367 vnodeChildren = slots;4368 if (hasDynamicSlots) {4369 patchFlag |= 1024 /* DYNAMIC_SLOTS */;4370 }4371 }4372 else if (node.children.length === 1 && vnodeTag !== TELEPORT) {4373 const child = node.children[0];4374 const type = child.type;4375 // check for dynamic text children4376 const hasDynamicTextChild = type === 5 /* INTERPOLATION */ ||4377 type === 8 /* COMPOUND_EXPRESSION */;4378 if (hasDynamicTextChild &&4379 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {4380 patchFlag |= 1 /* TEXT */;4381 }4382 // pass directly if the only child is a text node4383 // (plain / interpolation / expression)4384 if (hasDynamicTextChild || type === 2 /* TEXT */) {4385 vnodeChildren = child;4386 }4387 else {4388 vnodeChildren = node.children;4389 }4390 }4391 else {4392 vnodeChildren = node.children;4393 }4394 }4395 // patchFlag & dynamicPropNames4396 if (patchFlag !== 0) {4397 {4398 if (patchFlag < 0) {4399 // special flags (negative and mutually exclusive)4400 vnodePatchFlag = patchFlag + ` /* ${shared.PatchFlagNames[patchFlag]} */`;4401 }4402 else {4403 // bitwise flags4404 const flagNames = Object.keys(shared.PatchFlagNames)4405 .map(Number)4406 .filter(n => n > 0 && patchFlag & n)4407 .map(n => shared.PatchFlagNames[n])4408 .join(`, `);4409 vnodePatchFlag = patchFlag + ` /* ${flagNames} */`;4410 }4411 }4412 if (dynamicPropNames && dynamicPropNames.length) {4413 vnodeDynamicProps = stringifyDynamicPropNames(dynamicPropNames);4414 }4415 }4416 node.codegenNode = createVNodeCall(context, vnodeTag, vnodeProps, vnodeChildren, vnodePatchFlag, vnodeDynamicProps, vnodeDirectives, !!shouldUseBlock, false /* disableTracking */, isComponent, node.loc);4417 };4418};4419function resolveComponentType(node, context, ssr = false) {4420 let { tag } = node;4421 // 1. dynamic component4422 const isExplicitDynamic = isComponentTag(tag);4423 const isProp = findProp(node, 'is');4424 if (isProp) {4425 if (isExplicitDynamic ||4426 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) {4427 const exp = isProp.type === 6 /* ATTRIBUTE */4428 ? isProp.value && createSimpleExpression(isProp.value.content, true)4429 : isProp.exp;4430 if (exp) {4431 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [4432 exp4433 ]);4434 }4435 }4436 else if (isProp.type === 6 /* ATTRIBUTE */ &&4437 isProp.value.content.startsWith('vue:')) {4438 // <button is="vue:xxx">4439 // if not <component>, only is value that starts with "vue:" will be4440 // treated as component by the parse phase and reach here, unless it's4441 // compat mode where all is values are considered components4442 tag = isProp.value.content.slice(4);4443 }4444 }4445 // 1.5 v-is (TODO: Deprecate)4446 const isDir = !isExplicitDynamic && findDir(node, 'is');4447 if (isDir && isDir.exp) {4448 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [4449 isDir.exp4450 ]);4451 }4452 // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)4453 const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);4454 if (builtIn) {4455 // built-ins are simply fallthroughs / have special handling during ssr4456 // so we don't need to import their runtime equivalents4457 if (!ssr)4458 context.helper(builtIn);4459 return builtIn;4460 }4461 // 3. user component (from setup bindings)4462 // this is skipped in browser build since browser builds do not perform4463 // binding analysis.4464 {4465 const fromSetup = resolveSetupReference(tag, context);4466 if (fromSetup) {4467 return fromSetup;4468 }4469 const dotIndex = tag.indexOf('.');4470 if (dotIndex > 0) {4471 const ns = resolveSetupReference(tag.slice(0, dotIndex), context);4472 if (ns) {4473 return ns + tag.slice(dotIndex);4474 }4475 }4476 }4477 // 4. Self referencing component (inferred from filename)4478 if (context.selfName &&4479 shared.capitalize(shared.camelize(tag)) === context.selfName) {4480 context.helper(RESOLVE_COMPONENT);4481 // codegen.ts has special check for __self postfix when generating4482 // component imports, which will pass additional `maybeSelfReference` flag4483 // to `resolveComponent`.4484 context.components.add(tag + `__self`);4485 return toValidAssetId(tag, `component`);4486 }4487 // 5. user component (resolve)4488 context.helper(RESOLVE_COMPONENT);4489 context.components.add(tag);4490 return toValidAssetId(tag, `component`);4491}4492function resolveSetupReference(name, context) {4493 const bindings = context.bindingMetadata;4494 if (!bindings || bindings.__isScriptSetup === false) {4495 return;4496 }4497 const camelName = shared.camelize(name);4498 const PascalName = shared.capitalize(camelName);4499 const checkType = (type) => {4500 if (bindings[name] === type) {4501 return name;4502 }4503 if (bindings[camelName] === type) {4504 return camelName;4505 }4506 if (bindings[PascalName] === type) {4507 return PascalName;4508 }4509 };4510 const fromConst = checkType("setup-const" /* SETUP_CONST */);4511 if (fromConst) {4512 return context.inline4513 ? // in inline mode, const setup bindings (e.g. imports) can be used as-is4514 fromConst4515 : `$setup[${JSON.stringify(fromConst)}]`;4516 }4517 const fromMaybeRef = checkType("setup-let" /* SETUP_LET */) ||4518 checkType("setup-ref" /* SETUP_REF */) ||4519 checkType("setup-maybe-ref" /* SETUP_MAYBE_REF */);4520 if (fromMaybeRef) {4521 return context.inline4522 ? // setup scope bindings that may be refs need to be unrefed4523 `${context.helperString(UNREF)}(${fromMaybeRef})`4524 : `$setup[${JSON.stringify(fromMaybeRef)}]`;4525 }4526}4527function buildProps(node, context, props = node.props, ssr = false) {4528 const { tag, loc: elementLoc, children } = node;4529 const isComponent = node.tagType === 1 /* COMPONENT */;4530 let properties = [];4531 const mergeArgs = [];4532 const runtimeDirectives = [];4533 const hasChildren = children.length > 0;4534 let shouldUseBlock = false;4535 // patchFlag analysis4536 let patchFlag = 0;4537 let hasRef = false;4538 let hasClassBinding = false;4539 let hasStyleBinding = false;4540 let hasHydrationEventBinding = false;4541 let hasDynamicKeys = false;4542 let hasVnodeHook = false;4543 const dynamicPropNames = [];4544 const analyzePatchFlag = ({ key, value }) => {4545 if (isStaticExp(key)) {4546 const name = key.content;4547 const isEventHandler = shared.isOn(name);4548 if (!isComponent &&4549 isEventHandler &&4550 // omit the flag for click handlers because hydration gives click4551 // dedicated fast path.4552 name.toLowerCase() !== 'onclick' &&4553 // omit v-model handlers4554 name !== 'onUpdate:modelValue' &&4555 // omit onVnodeXXX hooks4556 !shared.isReservedProp(name)) {4557 hasHydrationEventBinding = true;4558 }4559 if (isEventHandler && shared.isReservedProp(name)) {4560 hasVnodeHook = true;4561 }4562 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||4563 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||4564 value.type === 8 /* COMPOUND_EXPRESSION */) &&4565 getConstantType(value, context) > 0)) {4566 // skip if the prop is a cached handler or has constant value4567 return;4568 }4569 if (name === 'ref') {4570 hasRef = true;4571 }4572 else if (name === 'class') {4573 hasClassBinding = true;4574 }4575 else if (name === 'style') {4576 hasStyleBinding = true;4577 }4578 else if (name !== 'key' && !dynamicPropNames.includes(name)) {4579 dynamicPropNames.push(name);4580 }4581 // treat the dynamic class and style binding of the component as dynamic props4582 if (isComponent &&4583 (name === 'class' || name === 'style') &&4584 !dynamicPropNames.includes(name)) {4585 dynamicPropNames.push(name);4586 }4587 }4588 else {4589 hasDynamicKeys = true;4590 }4591 };4592 for (let i = 0; i < props.length; i++) {4593 // static attribute4594 const prop = props[i];4595 if (prop.type === 6 /* ATTRIBUTE */) {4596 const { loc, name, value } = prop;4597 let isStatic = true;4598 if (name === 'ref') {4599 hasRef = true;4600 if (context.scopes.vFor > 0) {4601 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));4602 }4603 // in inline mode there is no setupState object, so we can't use string4604 // keys to set the ref. Instead, we need to transform it to pass the4605 // actual ref instead.4606 if (value &&4607 context.inline &&4608 context.bindingMetadata[value.content]) {4609 isStatic = false;4610 properties.push(createObjectProperty(createSimpleExpression('ref_key', true), createSimpleExpression(value.content, true, value.loc)));4611 }4612 }4613 // skip is on <component>, or is="vue:xxx"4614 if (name === 'is' &&4615 (isComponentTag(tag) ||4616 (value && value.content.startsWith('vue:')) ||4617 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) {4618 continue;4619 }4620 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));4621 }4622 else {4623 // directives4624 const { name, arg, exp, loc } = prop;4625 const isVBind = name === 'bind';4626 const isVOn = name === 'on';4627 // skip v-slot - it is handled by its dedicated transform.4628 if (name === 'slot') {4629 if (!isComponent) {4630 context.onError(createCompilerError(40 /* X_V_SLOT_MISPLACED */, loc));4631 }4632 continue;4633 }4634 // skip v-once/v-memo - they are handled by dedicated transforms.4635 if (name === 'once' || name === 'memo') {4636 continue;4637 }4638 // skip v-is and :is on <component>4639 if (name === 'is' ||4640 (isVBind &&4641 isStaticArgOf(arg, 'is') &&4642 (isComponentTag(tag) ||4643 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) {4644 continue;4645 }4646 // skip v-on in SSR compilation4647 if (isVOn && ssr) {4648 continue;4649 }4650 if (4651 // #938: elements with dynamic keys should be forced into blocks4652 (isVBind && isStaticArgOf(arg, 'key')) ||4653 // inline before-update hooks need to force block so that it is invoked4654 // before children4655 (isVOn && hasChildren && isStaticArgOf(arg, 'vue:before-update'))) {4656 shouldUseBlock = true;4657 }4658 if (isVBind && isStaticArgOf(arg, 'ref') && context.scopes.vFor > 0) {4659 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));4660 }4661 // special case for v-bind and v-on with no argument4662 if (!arg && (isVBind || isVOn)) {4663 hasDynamicKeys = true;4664 if (exp) {4665 if (properties.length) {4666 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));4667 properties = [];4668 }4669 if (isVBind) {4670 {4671 // 2.x v-bind object order compat4672 {4673 const hasOverridableKeys = mergeArgs.some(arg => {4674 if (arg.type === 15 /* JS_OBJECT_EXPRESSION */) {4675 return arg.properties.some(({ key }) => {4676 if (key.type !== 4 /* SIMPLE_EXPRESSION */ ||4677 !key.isStatic) {4678 return true;4679 }4680 return (key.content !== 'class' &&4681 key.content !== 'style' &&4682 !shared.isOn(key.content));4683 });4684 }4685 else {4686 // dynamic expression4687 return true;4688 }4689 });4690 if (hasOverridableKeys) {4691 checkCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context, loc);4692 }4693 }4694 if (isCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context)) {4695 mergeArgs.unshift(exp);4696 continue;4697 }4698 }4699 mergeArgs.push(exp);4700 }4701 else {4702 // v-on="obj" -> toHandlers(obj)4703 mergeArgs.push({4704 type: 14 /* JS_CALL_EXPRESSION */,4705 loc,4706 callee: context.helper(TO_HANDLERS),4707 arguments: [exp]4708 });4709 }4710 }4711 else {4712 context.onError(createCompilerError(isVBind4713 ? 34 /* X_V_BIND_NO_EXPRESSION */4714 : 35 /* X_V_ON_NO_EXPRESSION */, loc));4715 }4716 continue;4717 }4718 const directiveTransform = context.directiveTransforms[name];4719 if (directiveTransform) {4720 // has built-in directive transform.4721 const { props, needRuntime } = directiveTransform(prop, node, context);4722 !ssr && props.forEach(analyzePatchFlag);4723 properties.push(...props);4724 if (needRuntime) {4725 runtimeDirectives.push(prop);4726 if (shared.isSymbol(needRuntime)) {4727 directiveImportMap.set(prop, needRuntime);4728 }4729 }4730 }4731 else {4732 // no built-in transform, this is a user custom directive.4733 runtimeDirectives.push(prop);4734 // custom dirs may use beforeUpdate so they need to force blocks4735 // to ensure before-update gets called before children update4736 if (hasChildren) {4737 shouldUseBlock = true;4738 }4739 }4740 }4741 }4742 let propsExpression = undefined;4743 // has v-bind="object" or v-on="object", wrap with mergeProps4744 if (mergeArgs.length) {4745 if (properties.length) {4746 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));4747 }4748 if (mergeArgs.length > 1) {4749 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);4750 }4751 else {4752 // single v-bind with nothing else - no need for a mergeProps call4753 propsExpression = mergeArgs[0];4754 }4755 }4756 else if (properties.length) {4757 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);4758 }4759 // patchFlag analysis4760 if (hasDynamicKeys) {4761 patchFlag |= 16 /* FULL_PROPS */;4762 }4763 else {4764 if (hasClassBinding && !isComponent) {4765 patchFlag |= 2 /* CLASS */;4766 }4767 if (hasStyleBinding && !isComponent) {4768 patchFlag |= 4 /* STYLE */;4769 }4770 if (dynamicPropNames.length) {4771 patchFlag |= 8 /* PROPS */;4772 }4773 if (hasHydrationEventBinding) {4774 patchFlag |= 32 /* HYDRATE_EVENTS */;4775 }4776 }4777 if (!shouldUseBlock &&4778 (patchFlag === 0 || patchFlag === 32 /* HYDRATE_EVENTS */) &&4779 (hasRef || hasVnodeHook || runtimeDirectives.length > 0)) {4780 patchFlag |= 512 /* NEED_PATCH */;4781 }4782 // pre-normalize props, SSR is skipped for now4783 if (!context.inSSR && propsExpression) {4784 switch (propsExpression.type) {4785 case 15 /* JS_OBJECT_EXPRESSION */:4786 // means that there is no v-bind,4787 // but still need to deal with dynamic key binding4788 let classKeyIndex = -1;4789 let styleKeyIndex = -1;4790 let hasDynamicKey = false;4791 for (let i = 0; i < propsExpression.properties.length; i++) {4792 const key = propsExpression.properties[i].key;4793 if (isStaticExp(key)) {4794 if (key.content === 'class') {4795 classKeyIndex = i;4796 }4797 else if (key.content === 'style') {4798 styleKeyIndex = i;4799 }4800 }4801 else if (!key.isHandlerKey) {4802 hasDynamicKey = true;4803 }4804 }4805 const classProp = propsExpression.properties[classKeyIndex];4806 const styleProp = propsExpression.properties[styleKeyIndex];4807 // no dynamic key4808 if (!hasDynamicKey) {4809 if (classProp && !isStaticExp(classProp.value)) {4810 classProp.value = createCallExpression(context.helper(NORMALIZE_CLASS), [classProp.value]);4811 }4812 if (styleProp &&4813 !isStaticExp(styleProp.value) &&4814 // the static style is compiled into an object,4815 // so use `hasStyleBinding` to ensure that it is a dynamic style binding4816 (hasStyleBinding ||4817 // v-bind:style and style both exist,4818 // v-bind:style with static literal object4819 styleProp.value.type === 17 /* JS_ARRAY_EXPRESSION */)) {4820 styleProp.value = createCallExpression(context.helper(NORMALIZE_STYLE), [styleProp.value]);4821 }4822 }4823 else {4824 // dynamic key binding, wrap with `normalizeProps`4825 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [propsExpression]);4826 }4827 break;4828 case 14 /* JS_CALL_EXPRESSION */:4829 // mergeProps call, do nothing4830 break;4831 default:4832 // single v-bind4833 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [4834 createCallExpression(context.helper(GUARD_REACTIVE_PROPS), [4835 propsExpression4836 ])4837 ]);4838 break;4839 }4840 }4841 return {4842 props: propsExpression,4843 directives: runtimeDirectives,4844 patchFlag,4845 dynamicPropNames,4846 shouldUseBlock4847 };4848}4849// Dedupe props in an object literal.4850// Literal duplicated attributes would have been warned during the parse phase,4851// however, it's possible to encounter duplicated `onXXX` handlers with different4852// modifiers. We also need to merge static and dynamic class / style attributes.4853// - onXXX handlers / style: merge into array4854// - class: merge into single expression with concatenation4855function dedupeProperties(properties) {4856 const knownProps = new Map();4857 const deduped = [];4858 for (let i = 0; i < properties.length; i++) {4859 const prop = properties[i];4860 // dynamic keys are always allowed4861 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {4862 deduped.push(prop);4863 continue;4864 }4865 const name = prop.key.content;4866 const existing = knownProps.get(name);4867 if (existing) {4868 if (name === 'style' || name === 'class' || shared.isOn(name)) {4869 mergeAsArray(existing, prop);4870 }4871 // unexpected duplicate, should have emitted error during parse4872 }4873 else {4874 knownProps.set(name, prop);4875 deduped.push(prop);4876 }4877 }4878 return deduped;4879}4880function mergeAsArray(existing, incoming) {4881 if (existing.value.type === 17 /* JS_ARRAY_EXPRESSION */) {4882 existing.value.elements.push(incoming.value);4883 }4884 else {4885 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);4886 }4887}4888function buildDirectiveArgs(dir, context) {4889 const dirArgs = [];4890 const runtime = directiveImportMap.get(dir);4891 if (runtime) {4892 // built-in directive with runtime4893 dirArgs.push(context.helperString(runtime));4894 }4895 else {4896 // user directive.4897 // see if we have directives exposed via <script setup>4898 const fromSetup = resolveSetupReference('v-' + dir.name, context);4899 if (fromSetup) {4900 dirArgs.push(fromSetup);4901 }4902 else {4903 // inject statement for resolving directive4904 context.helper(RESOLVE_DIRECTIVE);4905 context.directives.add(dir.name);4906 dirArgs.push(toValidAssetId(dir.name, `directive`));4907 }4908 }4909 const { loc } = dir;4910 if (dir.exp)4911 dirArgs.push(dir.exp);4912 if (dir.arg) {4913 if (!dir.exp) {4914 dirArgs.push(`void 0`);4915 }4916 dirArgs.push(dir.arg);4917 }4918 if (Object.keys(dir.modifiers).length) {4919 if (!dir.arg) {4920 if (!dir.exp) {4921 dirArgs.push(`void 0`);4922 }4923 dirArgs.push(`void 0`);4924 }4925 const trueExpression = createSimpleExpression(`true`, false, loc);4926 dirArgs.push(createObjectExpression(dir.modifiers.map(modifier => createObjectProperty(modifier, trueExpression)), loc));4927 }4928 return createArrayExpression(dirArgs, dir.loc);4929}4930function stringifyDynamicPropNames(props) {4931 let propsNamesString = `[`;4932 for (let i = 0, l = props.length; i < l; i++) {4933 propsNamesString += JSON.stringify(props[i]);4934 if (i < l - 1)4935 propsNamesString += ', ';4936 }4937 return propsNamesString + `]`;4938}4939function isComponentTag(tag) {4940 return tag === 'component' || tag === 'Component';4941}4942Object.freeze({})4943 ;4944Object.freeze([]) ;4945const cacheStringFunction = (fn) => {4946 const cache = Object.create(null);4947 return ((str) => {4948 const hit = cache[str];4949 return hit || (cache[str] = fn(str));4950 });4951};4952const camelizeRE = /-(\w)/g;4953/**4954 * @private4955 */4956const camelize = cacheStringFunction((str) => {4957 return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));4958});4959const transformSlotOutlet = (node, context) => {4960 if (isSlotOutlet(node)) {4961 const { children, loc } = node;4962 const { slotName, slotProps } = processSlotOutlet(node, context);4963 const slotArgs = [4964 context.prefixIdentifiers ? `_ctx.$slots` : `$slots`,4965 slotName,4966 '{}',4967 'undefined',4968 'true'4969 ];4970 let expectedLen = 2;4971 if (slotProps) {4972 slotArgs[2] = slotProps;4973 expectedLen = 3;4974 }4975 if (children.length) {4976 slotArgs[3] = createFunctionExpression([], children, false, false, loc);4977 expectedLen = 4;4978 }4979 if (context.scopeId && !context.slotted) {4980 expectedLen = 5;4981 }4982 slotArgs.splice(expectedLen); // remove unused arguments4983 node.codegenNode = createCallExpression(context.helper(RENDER_SLOT), slotArgs, loc);4984 }4985};4986function processSlotOutlet(node, context) {4987 let slotName = `"default"`;4988 let slotProps = undefined;4989 const nonNameProps = [];4990 for (let i = 0; i < node.props.length; i++) {4991 const p = node.props[i];4992 if (p.type === 6 /* ATTRIBUTE */) {4993 if (p.value) {4994 if (p.name === 'name') {4995 slotName = JSON.stringify(p.value.content);4996 }4997 else {4998 p.name = camelize(p.name);4999 nonNameProps.push(p);5000 }5001 }5002 }5003 else {5004 if (p.name === 'bind' && isStaticArgOf(p.arg, 'name')) {5005 if (p.exp)5006 slotName = p.exp;5007 }5008 else {5009 if (p.name === 'bind' && p.arg && isStaticExp(p.arg)) {5010 p.arg.content = camelize(p.arg.content);5011 }5012 nonNameProps.push(p);5013 }5014 }5015 }5016 if (nonNameProps.length > 0) {5017 const { props, directives } = buildProps(node, context, nonNameProps);5018 slotProps = props;5019 if (directives.length) {5020 context.onError(createCompilerError(36 /* X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET */, directives[0].loc));5021 }5022 }5023 return {5024 slotName,5025 slotProps5026 };5027}5028const fnExpRE = /^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/;5029const transformOn = (dir, node, context, augmentor) => {5030 const { loc, modifiers, arg } = dir;5031 if (!dir.exp && !modifiers.length) {5032 context.onError(createCompilerError(35 /* X_V_ON_NO_EXPRESSION */, loc));5033 }5034 let eventName;5035 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {5036 if (arg.isStatic) {5037 let rawName = arg.content;5038 // TODO deprecate @vnodeXXX usage5039 if (rawName.startsWith('vue:')) {5040 rawName = `vnode-${rawName.slice(4)}`;5041 }5042 // for all event listeners, auto convert it to camelCase. See issue #22495043 eventName = createSimpleExpression(shared.toHandlerKey(shared.camelize(rawName)), true, arg.loc);5044 }5045 else {5046 // #23885047 eventName = createCompoundExpression([5048 `${context.helperString(TO_HANDLER_KEY)}(`,5049 arg,5050 `)`5051 ]);5052 }5053 }5054 else {5055 // already a compound expression.5056 eventName = arg;5057 eventName.children.unshift(`${context.helperString(TO_HANDLER_KEY)}(`);5058 eventName.children.push(`)`);5059 }5060 // handler processing5061 let exp = dir.exp;5062 if (exp && !exp.content.trim()) {5063 exp = undefined;5064 }5065 let shouldCache = context.cacheHandlers && !exp && !context.inVOnce;5066 if (exp) {5067 const isMemberExp = isMemberExpression(exp.content, context);5068 const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content));5069 const hasMultipleStatements = exp.content.includes(`;`);5070 // process the expression since it's been skipped5071 if (context.prefixIdentifiers) {5072 isInlineStatement && context.addIdentifiers(`$event`);5073 exp = dir.exp = processExpression(exp, context, false, hasMultipleStatements);5074 isInlineStatement && context.removeIdentifiers(`$event`);5075 // with scope analysis, the function is hoistable if it has no reference5076 // to scope variables.5077 shouldCache =5078 context.cacheHandlers &&5079 // unnecessary to cache inside v-once5080 !context.inVOnce &&5081 // runtime constants don't need to be cached5082 // (this is analyzed by compileScript in SFC <script setup>)5083 !(exp.type === 4 /* SIMPLE_EXPRESSION */ && exp.constType > 0) &&5084 // #1541 bail if this is a member exp handler passed to a component -5085 // we need to use the original function to preserve arity,5086 // e.g. <transition> relies on checking cb.length to determine5087 // transition end handling. Inline function is ok since its arity5088 // is preserved even when cached.5089 !(isMemberExp && node.tagType === 1 /* COMPONENT */) &&5090 // bail if the function references closure variables (v-for, v-slot)5091 // it must be passed fresh to avoid stale values.5092 !hasScopeRef(exp, context.identifiers);5093 // If the expression is optimizable and is a member expression pointing5094 // to a function, turn it into invocation (and wrap in an arrow function5095 // below) so that it always accesses the latest value when called - thus5096 // avoiding the need to be patched.5097 if (shouldCache && isMemberExp) {5098 if (exp.type === 4 /* SIMPLE_EXPRESSION */) {5099 exp.content = `${exp.content} && ${exp.content}(...args)`;5100 }5101 else {5102 exp.children = [...exp.children, ` && `, ...exp.children, `(...args)`];5103 }5104 }5105 }5106 if (isInlineStatement || (shouldCache && isMemberExp)) {5107 // wrap inline statement in a function expression5108 exp = createCompoundExpression([5109 `${isInlineStatement5110 ? context.isTS5111 ? `($event: any)`5112 : `$event`5113 : `${context.isTS ? `\n//@ts-ignore\n` : ``}(...args)`} => ${hasMultipleStatements ? `{` : `(`}`,5114 exp,5115 hasMultipleStatements ? `}` : `)`5116 ]);5117 }5118 }5119 let ret = {5120 props: [5121 createObjectProperty(eventName, exp || createSimpleExpression(`() => {}`, false, loc))5122 ]5123 };5124 // apply extended compiler augmentor5125 if (augmentor) {5126 ret = augmentor(ret);5127 }5128 if (shouldCache) {5129 // cache handlers so that it's always the same handler being passed down.5130 // this avoids unnecessary re-renders when users use inline handlers on5131 // components.5132 ret.props[0].value = context.cache(ret.props[0].value);5133 }5134 // mark the key as handler for props normalization check5135 ret.props.forEach(p => (p.key.isHandlerKey = true));5136 return ret;5137};5138// v-bind without arg is handled directly in ./transformElements.ts due to it affecting5139// codegen for the entire props object. This transform here is only for v-bind5140// *with* args.5141const transformBind = (dir, _node, context) => {5142 const { exp, modifiers, loc } = dir;5143 const arg = dir.arg;5144 if (arg.type !== 4 /* SIMPLE_EXPRESSION */) {5145 arg.children.unshift(`(`);5146 arg.children.push(`) || ""`);5147 }5148 else if (!arg.isStatic) {5149 arg.content = `${arg.content} || ""`;5150 }5151 // .sync is replaced by v-model:arg5152 if (modifiers.includes('camel')) {5153 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {5154 if (arg.isStatic) {5155 arg.content = shared.camelize(arg.content);5156 }5157 else {5158 arg.content = `${context.helperString(CAMELIZE)}(${arg.content})`;5159 }5160 }5161 else {5162 arg.children.unshift(`${context.helperString(CAMELIZE)}(`);5163 arg.children.push(`)`);5164 }5165 }5166 if (!context.inSSR) {5167 if (modifiers.includes('prop')) {5168 injectPrefix(arg, '.');5169 }5170 if (modifiers.includes('attr')) {5171 injectPrefix(arg, '^');5172 }5173 }5174 if (!exp ||5175 (exp.type === 4 /* SIMPLE_EXPRESSION */ && !exp.content.trim())) {5176 context.onError(createCompilerError(34 /* X_V_BIND_NO_EXPRESSION */, loc));5177 return {5178 props: [createObjectProperty(arg, createSimpleExpression('', true, loc))]5179 };5180 }5181 return {5182 props: [createObjectProperty(arg, exp)]5183 };5184};5185const injectPrefix = (arg, prefix) => {5186 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {5187 if (arg.isStatic) {5188 arg.content = prefix + arg.content;5189 }5190 else {5191 arg.content = `\`${prefix}\${${arg.content}}\``;5192 }5193 }5194 else {5195 arg.children.unshift(`'${prefix}' + (`);5196 arg.children.push(`)`);5197 }5198};5199// Merge adjacent text nodes and expressions into a single expression5200// e.g. <div>abc {{ d }} {{ e }}</div> should have a single expression node as child.5201const transformText = (node, context) => {5202 if (node.type === 0 /* ROOT */ ||5203 node.type === 1 /* ELEMENT */ ||5204 node.type === 11 /* FOR */ ||5205 node.type === 10 /* IF_BRANCH */) {5206 // perform the transform on node exit so that all expressions have already5207 // been processed.5208 return () => {5209 const children = node.children;5210 let currentContainer = undefined;5211 let hasText = false;5212 for (let i = 0; i < children.length; i++) {5213 const child = children[i];5214 if (isText(child)) {5215 hasText = true;5216 for (let j = i + 1; j < children.length; j++) {5217 const next = children[j];5218 if (isText(next)) {5219 if (!currentContainer) {5220 currentContainer = children[i] = {5221 type: 8 /* COMPOUND_EXPRESSION */,5222 loc: child.loc,5223 children: [child]5224 };5225 }5226 // merge adjacent text node into current5227 currentContainer.children.push(` + `, next);5228 children.splice(j, 1);5229 j--;5230 }5231 else {5232 currentContainer = undefined;5233 break;5234 }5235 }5236 }5237 }5238 if (!hasText ||5239 // if this is a plain element with a single text child, leave it5240 // as-is since the runtime has dedicated fast path for this by directly5241 // setting textContent of the element.5242 // for component root it's always normalized anyway.5243 (children.length === 1 &&5244 (node.type === 0 /* ROOT */ ||5245 (node.type === 1 /* ELEMENT */ &&5246 node.tagType === 0 /* ELEMENT */ &&5247 // #37565248 // custom directives can potentially add DOM elements arbitrarily,5249 // we need to avoid setting textContent of the element at runtime5250 // to avoid accidentally overwriting the DOM elements added5251 // by the user through custom directives.5252 !node.props.find(p => p.type === 7 /* DIRECTIVE */ &&5253 !context.directiveTransforms[p.name]) &&5254 // in compat mode, <template> tags with no special directives5255 // will be rendered as a fragment so its children must be5256 // converted into vnodes.5257 !(node.tag === 'template'))))) {5258 return;5259 }5260 // pre-convert text nodes into createTextVNode(text) calls to avoid5261 // runtime normalization.5262 for (let i = 0; i < children.length; i++) {5263 const child = children[i];5264 if (isText(child) || child.type === 8 /* COMPOUND_EXPRESSION */) {5265 const callArgs = [];5266 // createTextVNode defaults to single whitespace, so if it is a5267 // single space the code could be an empty call to save bytes.5268 if (child.type !== 2 /* TEXT */ || child.content !== ' ') {5269 callArgs.push(child);5270 }5271 // mark dynamic text with flag so it gets patched inside a block5272 if (!context.ssr &&5273 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {5274 callArgs.push(1 /* TEXT */ +5275 (` /* ${shared.PatchFlagNames[1 /* TEXT */]} */` ));5276 }5277 children[i] = {5278 type: 12 /* TEXT_CALL */,5279 content: child,5280 loc: child.loc,5281 codegenNode: createCallExpression(context.helper(CREATE_TEXT), callArgs)5282 };5283 }5284 }5285 };5286 }5287};5288const seen = new WeakSet();5289const transformOnce = (node, context) => {5290 if (node.type === 1 /* ELEMENT */ && findDir(node, 'once', true)) {5291 if (seen.has(node) || context.inVOnce) {5292 return;5293 }5294 seen.add(node);5295 context.inVOnce = true;5296 context.helper(SET_BLOCK_TRACKING);5297 return () => {5298 context.inVOnce = false;5299 const cur = context.currentNode;5300 if (cur.codegenNode) {5301 cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */);5302 }5303 };5304 }5305};5306const transformModel = (dir, node, context) => {5307 const { exp, arg } = dir;5308 if (!exp) {5309 context.onError(createCompilerError(41 /* X_V_MODEL_NO_EXPRESSION */, dir.loc));5310 return createTransformProps();5311 }5312 const rawExp = exp.loc.source;5313 const expString = exp.type === 4 /* SIMPLE_EXPRESSION */ ? exp.content : rawExp;5314 // im SFC <script setup> inline mode, the exp may have been transformed into5315 // _unref(exp)5316 const bindingType = context.bindingMetadata[rawExp];5317 const maybeRef = context.inline &&5318 bindingType &&5319 bindingType !== "setup-const" /* SETUP_CONST */;5320 if (!expString.trim() ||5321 (!isMemberExpression(expString, context) && !maybeRef)) {5322 context.onError(createCompilerError(42 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));5323 return createTransformProps();5324 }5325 if (context.prefixIdentifiers &&5326 isSimpleIdentifier(expString) &&5327 context.identifiers[expString]) {5328 context.onError(createCompilerError(43 /* X_V_MODEL_ON_SCOPE_VARIABLE */, exp.loc));5329 return createTransformProps();5330 }5331 const propName = arg ? arg : createSimpleExpression('modelValue', true);5332 const eventName = arg5333 ? isStaticExp(arg)5334 ? `onUpdate:${arg.content}`5335 : createCompoundExpression(['"onUpdate:" + ', arg])5336 : `onUpdate:modelValue`;5337 let assignmentExp;5338 const eventArg = context.isTS ? `($event: any)` : `$event`;5339 if (maybeRef) {5340 if (bindingType === "setup-ref" /* SETUP_REF */) {5341 // v-model used on known ref.5342 assignmentExp = createCompoundExpression([5343 `${eventArg} => ((`,5344 createSimpleExpression(rawExp, false, exp.loc),5345 `).value = $event)`5346 ]);5347 }5348 else {5349 // v-model used on a potentially ref binding in <script setup> inline mode.5350 // the assignment needs to check whether the binding is actually a ref.5351 const altAssignment = bindingType === "setup-let" /* SETUP_LET */ ? `${rawExp} = $event` : `null`;5352 assignmentExp = createCompoundExpression([5353 `${eventArg} => (${context.helperString(IS_REF)}(${rawExp}) ? (`,5354 createSimpleExpression(rawExp, false, exp.loc),5355 `).value = $event : ${altAssignment})`5356 ]);5357 }5358 }5359 else {5360 assignmentExp = createCompoundExpression([5361 `${eventArg} => ((`,5362 exp,5363 `) = $event)`5364 ]);5365 }5366 const props = [5367 // modelValue: foo5368 createObjectProperty(propName, dir.exp),5369 // "onUpdate:modelValue": $event => (foo = $event)5370 createObjectProperty(eventName, assignmentExp)5371 ];5372 // cache v-model handler if applicable (when it doesn't refer any scope vars)5373 if (context.prefixIdentifiers &&5374 !context.inVOnce &&5375 context.cacheHandlers &&5376 !hasScopeRef(exp, context.identifiers)) {5377 props[1].value = context.cache(props[1].value);5378 }5379 // modelModifiers: { foo: true, "bar-baz": true }5380 if (dir.modifiers.length && node.tagType === 1 /* COMPONENT */) {5381 const modifiers = dir.modifiers5382 .map(m => (isSimpleIdentifier(m) ? m : JSON.stringify(m)) + `: true`)5383 .join(`, `);5384 const modifiersKey = arg5385 ? isStaticExp(arg)5386 ? `${arg.content}Modifiers`5387 : createCompoundExpression([arg, ' + "Modifiers"'])5388 : `modelModifiers`;5389 props.push(createObjectProperty(modifiersKey, createSimpleExpression(`{ ${modifiers} }`, false, dir.loc, 2 /* CAN_HOIST */)));5390 }5391 return createTransformProps(props);5392};5393function createTransformProps(props = []) {5394 return { props };5395}5396const validDivisionCharRE = /[\w).+\-_$\]]/;5397const transformFilter = (node, context) => {5398 if (!isCompatEnabled("COMPILER_FILTER" /* COMPILER_FILTERS */, context)) {5399 return;5400 }5401 if (node.type === 5 /* INTERPOLATION */) {5402 // filter rewrite is applied before expression transform so only5403 // simple expressions are possible at this stage5404 rewriteFilter(node.content, context);5405 }5406 if (node.type === 1 /* ELEMENT */) {5407 node.props.forEach((prop) => {5408 if (prop.type === 7 /* DIRECTIVE */ &&5409 prop.name !== 'for' &&5410 prop.exp) {5411 rewriteFilter(prop.exp, context);5412 }...
compiler-core.cjs.prod.js
Source:compiler-core.cjs.prod.js
...786 else {787 return value;788 }789}790function isCompatEnabled(key, context) {791 const mode = getCompatValue('MODE', context);792 const value = getCompatValue(key, context);793 // in v3 mode, only enable if explicitly set to true794 // otherwise enable for any non-false value795 return mode === 3 ? value === true : value !== false;796}797function checkCompatEnabled(key, context, loc, ...args) {798 const enabled = isCompatEnabled(key, context);799 return enabled;800}801function warnDeprecation(key, context, loc, ...args) {802 const val = getCompatValue(key, context);803 if (val === 'suppress-warning') {804 return;805 }806 const { message, link } = deprecationData[key];807 const msg = `(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`;808 const err = new SyntaxError(msg);809 err.code = key;810 if (loc)811 err.loc = loc;812 context.onWarn(err);813}814// The default decoder only provides escapes for characters reserved as part of815// the template syntax, and is only used if the custom renderer did not provide816// a platform-specific decoder.817const decodeRE = /&(gt|lt|amp|apos|quot);/g;818const decodeMap = {819 gt: '>',820 lt: '<',821 amp: '&',822 apos: "'",823 quot: '"'824};825const defaultParserOptions = {826 delimiters: [`{{`, `}}`],827 getNamespace: () => 0 /* HTML */,828 getTextMode: () => 0 /* DATA */,829 isVoidTag: shared.NO,830 isPreTag: shared.NO,831 isCustomElement: shared.NO,832 decodeEntities: (rawText) => rawText.replace(decodeRE, (_, p1) => decodeMap[p1]),833 onError: defaultOnError,834 onWarn: defaultOnWarn,835 comments: false836};837function baseParse(content, options = {}) {838 const context = createParserContext(content, options);839 const start = getCursor(context);840 return createRoot(parseChildren(context, 0 /* DATA */, []), getSelection(context, start));841}842function createParserContext(content, rawOptions) {843 const options = shared.extend({}, defaultParserOptions);844 let key;845 for (key in rawOptions) {846 // @ts-ignore847 options[key] =848 rawOptions[key] === undefined849 ? defaultParserOptions[key]850 : rawOptions[key];851 }852 return {853 options,854 column: 1,855 line: 1,856 offset: 0,857 originalSource: content,858 source: content,859 inPre: false,860 inVPre: false,861 onWarn: options.onWarn862 };863}864function parseChildren(context, mode, ancestors) {865 const parent = last(ancestors);866 const ns = parent ? parent.ns : 0 /* HTML */;867 const nodes = [];868 while (!isEnd(context, mode, ancestors)) {869 const s = context.source;870 let node = undefined;871 if (mode === 0 /* DATA */ || mode === 1 /* RCDATA */) {872 if (!context.inVPre && startsWith(s, context.options.delimiters[0])) {873 // '{{'874 node = parseInterpolation(context, mode);875 }876 else if (mode === 0 /* DATA */ && s[0] === '<') {877 // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state878 if (s.length === 1) {879 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 1);880 }881 else if (s[1] === '!') {882 // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state883 if (startsWith(s, '<!--')) {884 node = parseComment(context);885 }886 else if (startsWith(s, '<!DOCTYPE')) {887 // Ignore DOCTYPE by a limitation.888 node = parseBogusComment(context);889 }890 else if (startsWith(s, '<![CDATA[')) {891 if (ns !== 0 /* HTML */) {892 node = parseCDATA(context, ancestors);893 }894 else {895 emitError(context, 1 /* CDATA_IN_HTML_CONTENT */);896 node = parseBogusComment(context);897 }898 }899 else {900 emitError(context, 11 /* INCORRECTLY_OPENED_COMMENT */);901 node = parseBogusComment(context);902 }903 }904 else if (s[1] === '/') {905 // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state906 if (s.length === 2) {907 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 2);908 }909 else if (s[2] === '>') {910 emitError(context, 14 /* MISSING_END_TAG_NAME */, 2);911 advanceBy(context, 3);912 continue;913 }914 else if (/[a-z]/i.test(s[2])) {915 emitError(context, 23 /* X_INVALID_END_TAG */);916 parseTag(context, 1 /* End */, parent);917 continue;918 }919 else {920 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 2);921 node = parseBogusComment(context);922 }923 }924 else if (/[a-z]/i.test(s[1])) {925 node = parseElement(context, ancestors);926 // 2.x <template> with no directive compat927 if (isCompatEnabled("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context) &&928 node &&929 node.tag === 'template' &&930 !node.props.some(p => p.type === 7 /* DIRECTIVE */ &&931 isSpecialTemplateDirective(p.name))) {932 node = node.children;933 }934 }935 else if (s[1] === '?') {936 emitError(context, 21 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */, 1);937 node = parseBogusComment(context);938 }939 else {940 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 1);941 }942 }943 }944 if (!node) {945 node = parseText(context, mode);946 }947 if (shared.isArray(node)) {948 for (let i = 0; i < node.length; i++) {949 pushNode(nodes, node[i]);950 }951 }952 else {953 pushNode(nodes, node);954 }955 }956 // Whitespace handling strategy like v2957 let removedWhitespace = false;958 if (mode !== 2 /* RAWTEXT */ && mode !== 1 /* RCDATA */) {959 const shouldCondense = context.options.whitespace !== 'preserve';960 for (let i = 0; i < nodes.length; i++) {961 const node = nodes[i];962 if (!context.inPre && node.type === 2 /* TEXT */) {963 if (!/[^\t\r\n\f ]/.test(node.content)) {964 const prev = nodes[i - 1];965 const next = nodes[i + 1];966 // Remove if:967 // - the whitespace is the first or last node, or:968 // - (condense mode) the whitespace is adjacent to a comment, or:969 // - (condense mode) the whitespace is between two elements AND contains newline970 if (!prev ||971 !next ||972 (shouldCondense &&973 (prev.type === 3 /* COMMENT */ ||974 next.type === 3 /* COMMENT */ ||975 (prev.type === 1 /* ELEMENT */ &&976 next.type === 1 /* ELEMENT */ &&977 /[\r\n]/.test(node.content))))) {978 removedWhitespace = true;979 nodes[i] = null;980 }981 else {982 // Otherwise, the whitespace is condensed into a single space983 node.content = ' ';984 }985 }986 else if (shouldCondense) {987 // in condense mode, consecutive whitespaces in text are condensed988 // down to a single space.989 node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ');990 }991 }992 // Remove comment nodes if desired by configuration.993 else if (node.type === 3 /* COMMENT */ && !context.options.comments) {994 removedWhitespace = true;995 nodes[i] = null;996 }997 }998 if (context.inPre && parent && context.options.isPreTag(parent.tag)) {999 // remove leading newline per html spec1000 // https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element1001 const first = nodes[0];1002 if (first && first.type === 2 /* TEXT */) {1003 first.content = first.content.replace(/^\r?\n/, '');1004 }1005 }1006 }1007 return removedWhitespace ? nodes.filter(Boolean) : nodes;1008}1009function pushNode(nodes, node) {1010 if (node.type === 2 /* TEXT */) {1011 const prev = last(nodes);1012 // Merge if both this and the previous node are text and those are1013 // consecutive. This happens for cases like "a < b".1014 if (prev &&1015 prev.type === 2 /* TEXT */ &&1016 prev.loc.end.offset === node.loc.start.offset) {1017 prev.content += node.content;1018 prev.loc.end = node.loc.end;1019 prev.loc.source += node.loc.source;1020 return;1021 }1022 }1023 nodes.push(node);1024}1025function parseCDATA(context, ancestors) {1026 advanceBy(context, 9);1027 const nodes = parseChildren(context, 3 /* CDATA */, ancestors);1028 if (context.source.length === 0) {1029 emitError(context, 6 /* EOF_IN_CDATA */);1030 }1031 else {1032 advanceBy(context, 3);1033 }1034 return nodes;1035}1036function parseComment(context) {1037 const start = getCursor(context);1038 let content;1039 // Regular comment.1040 const match = /--(\!)?>/.exec(context.source);1041 if (!match) {1042 content = context.source.slice(4);1043 advanceBy(context, context.source.length);1044 emitError(context, 7 /* EOF_IN_COMMENT */);1045 }1046 else {1047 if (match.index <= 3) {1048 emitError(context, 0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */);1049 }1050 if (match[1]) {1051 emitError(context, 10 /* INCORRECTLY_CLOSED_COMMENT */);1052 }1053 content = context.source.slice(4, match.index);1054 // Advancing with reporting nested comments.1055 const s = context.source.slice(0, match.index);1056 let prevIndex = 1, nestedIndex = 0;1057 while ((nestedIndex = s.indexOf('<!--', prevIndex)) !== -1) {1058 advanceBy(context, nestedIndex - prevIndex + 1);1059 if (nestedIndex + 4 < s.length) {1060 emitError(context, 16 /* NESTED_COMMENT */);1061 }1062 prevIndex = nestedIndex + 1;1063 }1064 advanceBy(context, match.index + match[0].length - prevIndex + 1);1065 }1066 return {1067 type: 3 /* COMMENT */,1068 content,1069 loc: getSelection(context, start)1070 };1071}1072function parseBogusComment(context) {1073 const start = getCursor(context);1074 const contentStart = context.source[1] === '?' ? 1 : 2;1075 let content;1076 const closeIndex = context.source.indexOf('>');1077 if (closeIndex === -1) {1078 content = context.source.slice(contentStart);1079 advanceBy(context, context.source.length);1080 }1081 else {1082 content = context.source.slice(contentStart, closeIndex);1083 advanceBy(context, closeIndex + 1);1084 }1085 return {1086 type: 3 /* COMMENT */,1087 content,1088 loc: getSelection(context, start)1089 };1090}1091function parseElement(context, ancestors) {1092 // Start tag.1093 const wasInPre = context.inPre;1094 const wasInVPre = context.inVPre;1095 const parent = last(ancestors);1096 const element = parseTag(context, 0 /* Start */, parent);1097 const isPreBoundary = context.inPre && !wasInPre;1098 const isVPreBoundary = context.inVPre && !wasInVPre;1099 if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {1100 // #4030 self-closing <pre> tag1101 if (isPreBoundary) {1102 context.inPre = false;1103 }1104 if (isVPreBoundary) {1105 context.inVPre = false;1106 }1107 return element;1108 }1109 // Children.1110 ancestors.push(element);1111 const mode = context.options.getTextMode(element, parent);1112 const children = parseChildren(context, mode, ancestors);1113 ancestors.pop();1114 // 2.x inline-template compat1115 {1116 const inlineTemplateProp = element.props.find(p => p.type === 6 /* ATTRIBUTE */ && p.name === 'inline-template');1117 if (inlineTemplateProp &&1118 checkCompatEnabled("COMPILER_INLINE_TEMPLATE" /* COMPILER_INLINE_TEMPLATE */, context, inlineTemplateProp.loc)) {1119 const loc = getSelection(context, element.loc.end);1120 inlineTemplateProp.value = {1121 type: 2 /* TEXT */,1122 content: loc.source,1123 loc1124 };1125 }1126 }1127 element.children = children;1128 // End tag.1129 if (startsWithEndTagOpen(context.source, element.tag)) {1130 parseTag(context, 1 /* End */, parent);1131 }1132 else {1133 emitError(context, 24 /* X_MISSING_END_TAG */, 0, element.loc.start);1134 if (context.source.length === 0 && element.tag.toLowerCase() === 'script') {1135 const first = children[0];1136 if (first && startsWith(first.loc.source, '<!--')) {1137 emitError(context, 8 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */);1138 }1139 }1140 }1141 element.loc = getSelection(context, element.loc.start);1142 if (isPreBoundary) {1143 context.inPre = false;1144 }1145 if (isVPreBoundary) {1146 context.inVPre = false;1147 }1148 return element;1149}1150const isSpecialTemplateDirective = /*#__PURE__*/ shared.makeMap(`if,else,else-if,for,slot`);1151function parseTag(context, type, parent) {1152 // Tag open.1153 const start = getCursor(context);1154 const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source);1155 const tag = match[1];1156 const ns = context.options.getNamespace(tag, parent);1157 advanceBy(context, match[0].length);1158 advanceSpaces(context);1159 // save current state in case we need to re-parse attributes with v-pre1160 const cursor = getCursor(context);1161 const currentSource = context.source;1162 // check <pre> tag1163 if (context.options.isPreTag(tag)) {1164 context.inPre = true;1165 }1166 // Attributes.1167 let props = parseAttributes(context, type);1168 // check v-pre1169 if (type === 0 /* Start */ &&1170 !context.inVPre &&1171 props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'pre')) {1172 context.inVPre = true;1173 // reset context1174 shared.extend(context, cursor);1175 context.source = currentSource;1176 // re-parse attrs and filter out v-pre itself1177 props = parseAttributes(context, type).filter(p => p.name !== 'v-pre');1178 }1179 // Tag close.1180 let isSelfClosing = false;1181 if (context.source.length === 0) {1182 emitError(context, 9 /* EOF_IN_TAG */);1183 }1184 else {1185 isSelfClosing = startsWith(context.source, '/>');1186 if (type === 1 /* End */ && isSelfClosing) {1187 emitError(context, 4 /* END_TAG_WITH_TRAILING_SOLIDUS */);1188 }1189 advanceBy(context, isSelfClosing ? 2 : 1);1190 }1191 if (type === 1 /* End */) {1192 return;1193 }1194 let tagType = 0 /* ELEMENT */;1195 if (!context.inVPre) {1196 if (tag === 'slot') {1197 tagType = 2 /* SLOT */;1198 }1199 else if (tag === 'template') {1200 if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {1201 tagType = 3 /* TEMPLATE */;1202 }1203 }1204 else if (isComponent(tag, props, context)) {1205 tagType = 1 /* COMPONENT */;1206 }1207 }1208 return {1209 type: 1 /* ELEMENT */,1210 ns,1211 tag,1212 tagType,1213 props,1214 isSelfClosing,1215 children: [],1216 loc: getSelection(context, start),1217 codegenNode: undefined // to be created during transform phase1218 };1219}1220function isComponent(tag, props, context) {1221 const options = context.options;1222 if (options.isCustomElement(tag)) {1223 return false;1224 }1225 if (tag === 'component' ||1226 /^[A-Z]/.test(tag) ||1227 isCoreComponent(tag) ||1228 (options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||1229 (options.isNativeTag && !options.isNativeTag(tag))) {1230 return true;1231 }1232 // at this point the tag should be a native tag, but check for potential "is"1233 // casting1234 for (let i = 0; i < props.length; i++) {1235 const p = props[i];1236 if (p.type === 6 /* ATTRIBUTE */) {1237 if (p.name === 'is' && p.value) {1238 if (p.value.content.startsWith('vue:')) {1239 return true;1240 }1241 else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1242 return true;1243 }1244 }1245 }1246 else {1247 // directive1248 // v-is (TODO Deprecate)1249 if (p.name === 'is') {1250 return true;1251 }1252 else if (1253 // :is on plain element - only treat as component in compat mode1254 p.name === 'bind' &&1255 isStaticArgOf(p.arg, 'is') &&1256 true &&1257 checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1258 return true;1259 }1260 }1261 }1262}1263function parseAttributes(context, type) {1264 const props = [];1265 const attributeNames = new Set();1266 while (context.source.length > 0 &&1267 !startsWith(context.source, '>') &&1268 !startsWith(context.source, '/>')) {1269 if (startsWith(context.source, '/')) {1270 emitError(context, 22 /* UNEXPECTED_SOLIDUS_IN_TAG */);1271 advanceBy(context, 1);1272 advanceSpaces(context);1273 continue;1274 }1275 if (type === 1 /* End */) {1276 emitError(context, 3 /* END_TAG_WITH_ATTRIBUTES */);1277 }1278 const attr = parseAttribute(context, attributeNames);1279 // Trim whitespace between class1280 // https://github.com/vuejs/vue-next/issues/42511281 if (attr.type === 6 /* ATTRIBUTE */ &&1282 attr.value &&1283 attr.name === 'class') {1284 attr.value.content = attr.value.content.replace(/\s+/g, ' ').trim();1285 }1286 if (type === 0 /* Start */) {1287 props.push(attr);1288 }1289 if (/^[^\t\r\n\f />]/.test(context.source)) {1290 emitError(context, 15 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */);1291 }1292 advanceSpaces(context);1293 }1294 return props;1295}1296function parseAttribute(context, nameSet) {1297 // Name.1298 const start = getCursor(context);1299 const match = /^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(context.source);1300 const name = match[0];1301 if (nameSet.has(name)) {1302 emitError(context, 2 /* DUPLICATE_ATTRIBUTE */);1303 }1304 nameSet.add(name);1305 if (name[0] === '=') {1306 emitError(context, 19 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */);1307 }1308 {1309 const pattern = /["'<]/g;1310 let m;1311 while ((m = pattern.exec(name))) {1312 emitError(context, 17 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */, m.index);1313 }1314 }1315 advanceBy(context, name.length);1316 // Value1317 let value = undefined;1318 if (/^[\t\r\n\f ]*=/.test(context.source)) {1319 advanceSpaces(context);1320 advanceBy(context, 1);1321 advanceSpaces(context);1322 value = parseAttributeValue(context);1323 if (!value) {1324 emitError(context, 13 /* MISSING_ATTRIBUTE_VALUE */);1325 }1326 }1327 const loc = getSelection(context, start);1328 if (!context.inVPre && /^(v-[A-Za-z0-9-]|:|\.|@|#)/.test(name)) {1329 const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^\.|^@|^#)(\[[^\]]+\]|[^\.]+))?(.+)?$/i.exec(name);1330 let isPropShorthand = startsWith(name, '.');1331 let dirName = match[1] ||1332 (isPropShorthand || startsWith(name, ':')1333 ? 'bind'1334 : startsWith(name, '@')1335 ? 'on'1336 : 'slot');1337 let arg;1338 if (match[2]) {1339 const isSlot = dirName === 'slot';1340 const startOffset = name.lastIndexOf(match[2]);1341 const loc = getSelection(context, getNewPosition(context, start, startOffset), getNewPosition(context, start, startOffset + match[2].length + ((isSlot && match[3]) || '').length));1342 let content = match[2];1343 let isStatic = true;1344 if (content.startsWith('[')) {1345 isStatic = false;1346 if (!content.endsWith(']')) {1347 emitError(context, 27 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */);1348 content = content.slice(1);1349 }1350 else {1351 content = content.slice(1, content.length - 1);1352 }1353 }1354 else if (isSlot) {1355 // #1241 special case for v-slot: vuetify relies extensively on slot1356 // names containing dots. v-slot doesn't have any modifiers and Vue 2.x1357 // supports such usage so we are keeping it consistent with 2.x.1358 content += match[3] || '';1359 }1360 arg = {1361 type: 4 /* SIMPLE_EXPRESSION */,1362 content,1363 isStatic,1364 constType: isStatic1365 ? 3 /* CAN_STRINGIFY */1366 : 0 /* NOT_CONSTANT */,1367 loc1368 };1369 }1370 if (value && value.isQuoted) {1371 const valueLoc = value.loc;1372 valueLoc.start.offset++;1373 valueLoc.start.column++;1374 valueLoc.end = advancePositionWithClone(valueLoc.start, value.content);1375 valueLoc.source = valueLoc.source.slice(1, -1);1376 }1377 const modifiers = match[3] ? match[3].slice(1).split('.') : [];1378 if (isPropShorthand)1379 modifiers.push('prop');1380 // 2.x compat v-bind:foo.sync -> v-model:foo1381 if (dirName === 'bind' && arg) {1382 if (modifiers.includes('sync') &&1383 checkCompatEnabled("COMPILER_V_BIND_SYNC" /* COMPILER_V_BIND_SYNC */, context, loc, arg.loc.source)) {1384 dirName = 'model';1385 modifiers.splice(modifiers.indexOf('sync'), 1);1386 }1387 }1388 return {1389 type: 7 /* DIRECTIVE */,1390 name: dirName,1391 exp: value && {1392 type: 4 /* SIMPLE_EXPRESSION */,1393 content: value.content,1394 isStatic: false,1395 // Treat as non-constant by default. This can be potentially set to1396 // other values by `transformExpression` to make it eligible for hoisting.1397 constType: 0 /* NOT_CONSTANT */,1398 loc: value.loc1399 },1400 arg,1401 modifiers,1402 loc1403 };1404 }1405 // missing directive name or illegal directive name1406 if (!context.inVPre && startsWith(name, 'v-')) {1407 emitError(context, 26 /* X_MISSING_DIRECTIVE_NAME */);1408 }1409 return {1410 type: 6 /* ATTRIBUTE */,1411 name,1412 value: value && {1413 type: 2 /* TEXT */,1414 content: value.content,1415 loc: value.loc1416 },1417 loc1418 };1419}1420function parseAttributeValue(context) {1421 const start = getCursor(context);1422 let content;1423 const quote = context.source[0];1424 const isQuoted = quote === `"` || quote === `'`;1425 if (isQuoted) {1426 // Quoted value.1427 advanceBy(context, 1);1428 const endIndex = context.source.indexOf(quote);1429 if (endIndex === -1) {1430 content = parseTextData(context, context.source.length, 4 /* ATTRIBUTE_VALUE */);1431 }1432 else {1433 content = parseTextData(context, endIndex, 4 /* ATTRIBUTE_VALUE */);1434 advanceBy(context, 1);1435 }1436 }1437 else {1438 // Unquoted1439 const match = /^[^\t\r\n\f >]+/.exec(context.source);1440 if (!match) {1441 return undefined;1442 }1443 const unexpectedChars = /["'<=`]/g;1444 let m;1445 while ((m = unexpectedChars.exec(match[0]))) {1446 emitError(context, 18 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */, m.index);1447 }1448 content = parseTextData(context, match[0].length, 4 /* ATTRIBUTE_VALUE */);1449 }1450 return { content, isQuoted, loc: getSelection(context, start) };1451}1452function parseInterpolation(context, mode) {1453 const [open, close] = context.options.delimiters;1454 const closeIndex = context.source.indexOf(close, open.length);1455 if (closeIndex === -1) {1456 emitError(context, 25 /* X_MISSING_INTERPOLATION_END */);1457 return undefined;1458 }1459 const start = getCursor(context);1460 advanceBy(context, open.length);1461 const innerStart = getCursor(context);1462 const innerEnd = getCursor(context);1463 const rawContentLength = closeIndex - open.length;1464 const rawContent = context.source.slice(0, rawContentLength);1465 const preTrimContent = parseTextData(context, rawContentLength, mode);1466 const content = preTrimContent.trim();1467 const startOffset = preTrimContent.indexOf(content);1468 if (startOffset > 0) {1469 advancePositionWithMutation(innerStart, rawContent, startOffset);1470 }1471 const endOffset = rawContentLength - (preTrimContent.length - content.length - startOffset);1472 advancePositionWithMutation(innerEnd, rawContent, endOffset);1473 advanceBy(context, close.length);1474 return {1475 type: 5 /* INTERPOLATION */,1476 content: {1477 type: 4 /* SIMPLE_EXPRESSION */,1478 isStatic: false,1479 // Set `isConstant` to false by default and will decide in transformExpression1480 constType: 0 /* NOT_CONSTANT */,1481 content,1482 loc: getSelection(context, innerStart, innerEnd)1483 },1484 loc: getSelection(context, start)1485 };1486}1487function parseText(context, mode) {1488 const endTokens = mode === 3 /* CDATA */ ? [']]>'] : ['<', context.options.delimiters[0]];1489 let endIndex = context.source.length;1490 for (let i = 0; i < endTokens.length; i++) {1491 const index = context.source.indexOf(endTokens[i], 1);1492 if (index !== -1 && endIndex > index) {1493 endIndex = index;1494 }1495 }1496 const start = getCursor(context);1497 const content = parseTextData(context, endIndex, mode);1498 return {1499 type: 2 /* TEXT */,1500 content,1501 loc: getSelection(context, start)1502 };1503}1504/**1505 * Get text data with a given length from the current location.1506 * This translates HTML entities in the text data.1507 */1508function parseTextData(context, length, mode) {1509 const rawText = context.source.slice(0, length);1510 advanceBy(context, length);1511 if (mode === 2 /* RAWTEXT */ ||1512 mode === 3 /* CDATA */ ||1513 rawText.indexOf('&') === -1) {1514 return rawText;1515 }1516 else {1517 // DATA or RCDATA containing "&"". Entity decoding required.1518 return context.options.decodeEntities(rawText, mode === 4 /* ATTRIBUTE_VALUE */);1519 }1520}1521function getCursor(context) {1522 const { column, line, offset } = context;1523 return { column, line, offset };1524}1525function getSelection(context, start, end) {1526 end = end || getCursor(context);1527 return {1528 start,1529 end,1530 source: context.originalSource.slice(start.offset, end.offset)1531 };1532}1533function last(xs) {1534 return xs[xs.length - 1];1535}1536function startsWith(source, searchString) {1537 return source.startsWith(searchString);1538}1539function advanceBy(context, numberOfCharacters) {1540 const { source } = context;1541 advancePositionWithMutation(context, source, numberOfCharacters);1542 context.source = source.slice(numberOfCharacters);1543}1544function advanceSpaces(context) {1545 const match = /^[\t\r\n\f ]+/.exec(context.source);1546 if (match) {1547 advanceBy(context, match[0].length);1548 }1549}1550function getNewPosition(context, start, numberOfCharacters) {1551 return advancePositionWithClone(start, context.originalSource.slice(start.offset, numberOfCharacters), numberOfCharacters);1552}1553function emitError(context, code, offset, loc = getCursor(context)) {1554 if (offset) {1555 loc.offset += offset;1556 loc.column += offset;1557 }1558 context.options.onError(createCompilerError(code, {1559 start: loc,1560 end: loc,1561 source: ''1562 }));1563}1564function isEnd(context, mode, ancestors) {1565 const s = context.source;1566 switch (mode) {1567 case 0 /* DATA */:1568 if (startsWith(s, '</')) {1569 // TODO: probably bad performance1570 for (let i = ancestors.length - 1; i >= 0; --i) {1571 if (startsWithEndTagOpen(s, ancestors[i].tag)) {1572 return true;1573 }1574 }1575 }1576 break;1577 case 1 /* RCDATA */:1578 case 2 /* RAWTEXT */: {1579 const parent = last(ancestors);1580 if (parent && startsWithEndTagOpen(s, parent.tag)) {1581 return true;1582 }1583 break;1584 }1585 case 3 /* CDATA */:1586 if (startsWith(s, ']]>')) {1587 return true;1588 }1589 break;1590 }1591 return !s;1592}1593function startsWithEndTagOpen(source, tag) {1594 return (startsWith(source, '</') &&1595 source.slice(2, 2 + tag.length).toLowerCase() === tag.toLowerCase() &&1596 /[\t\r\n\f />]/.test(source[2 + tag.length] || '>'));1597}1598function hoistStatic(root, context) {1599 walk(root, context, 1600 // Root node is unfortunately non-hoistable due to potential parent1601 // fallthrough attributes.1602 isSingleElementRoot(root, root.children[0]));1603}1604function isSingleElementRoot(root, child) {1605 const { children } = root;1606 return (children.length === 1 &&1607 child.type === 1 /* ELEMENT */ &&1608 !isSlotOutlet(child));1609}1610function walk(node, context, doNotHoistNode = false) {1611 const { children } = node;1612 const originalCount = children.length;1613 let hoistedCount = 0;1614 for (let i = 0; i < children.length; i++) {1615 const child = children[i];1616 // only plain elements & text calls are eligible for hoisting.1617 if (child.type === 1 /* ELEMENT */ &&1618 child.tagType === 0 /* ELEMENT */) {1619 const constantType = doNotHoistNode1620 ? 0 /* NOT_CONSTANT */1621 : getConstantType(child, context);1622 if (constantType > 0 /* NOT_CONSTANT */) {1623 if (constantType >= 2 /* CAN_HOIST */) {1624 child.codegenNode.patchFlag =1625 -1 /* HOISTED */ + (``);1626 child.codegenNode = context.hoist(child.codegenNode);1627 hoistedCount++;1628 continue;1629 }1630 }1631 else {1632 // node may contain dynamic children, but its props may be eligible for1633 // hoisting.1634 const codegenNode = child.codegenNode;1635 if (codegenNode.type === 13 /* VNODE_CALL */) {1636 const flag = getPatchFlag(codegenNode);1637 if ((!flag ||1638 flag === 512 /* NEED_PATCH */ ||1639 flag === 1 /* TEXT */) &&1640 getGeneratedPropsConstantType(child, context) >=1641 2 /* CAN_HOIST */) {1642 const props = getNodeProps(child);1643 if (props) {1644 codegenNode.props = context.hoist(props);1645 }1646 }1647 if (codegenNode.dynamicProps) {1648 codegenNode.dynamicProps = context.hoist(codegenNode.dynamicProps);1649 }1650 }1651 }1652 }1653 else if (child.type === 12 /* TEXT_CALL */ &&1654 getConstantType(child.content, context) >= 2 /* CAN_HOIST */) {1655 child.codegenNode = context.hoist(child.codegenNode);1656 hoistedCount++;1657 }1658 // walk further1659 if (child.type === 1 /* ELEMENT */) {1660 const isComponent = child.tagType === 1 /* COMPONENT */;1661 if (isComponent) {1662 context.scopes.vSlot++;1663 }1664 walk(child, context);1665 if (isComponent) {1666 context.scopes.vSlot--;1667 }1668 }1669 else if (child.type === 11 /* FOR */) {1670 // Do not hoist v-for single child because it has to be a block1671 walk(child, context, child.children.length === 1);1672 }1673 else if (child.type === 9 /* IF */) {1674 for (let i = 0; i < child.branches.length; i++) {1675 // Do not hoist v-if single child because it has to be a block1676 walk(child.branches[i], context, child.branches[i].children.length === 1);1677 }1678 }1679 }1680 if (hoistedCount && context.transformHoist) {1681 context.transformHoist(children, context, node);1682 }1683 // all children were hoisted - the entire children array is hoistable.1684 if (hoistedCount &&1685 hoistedCount === originalCount &&1686 node.type === 1 /* ELEMENT */ &&1687 node.tagType === 0 /* ELEMENT */ &&1688 node.codegenNode &&1689 node.codegenNode.type === 13 /* VNODE_CALL */ &&1690 shared.isArray(node.codegenNode.children)) {1691 node.codegenNode.children = context.hoist(createArrayExpression(node.codegenNode.children));1692 }1693}1694function getConstantType(node, context) {1695 const { constantCache } = context;1696 switch (node.type) {1697 case 1 /* ELEMENT */:1698 if (node.tagType !== 0 /* ELEMENT */) {1699 return 0 /* NOT_CONSTANT */;1700 }1701 const cached = constantCache.get(node);1702 if (cached !== undefined) {1703 return cached;1704 }1705 const codegenNode = node.codegenNode;1706 if (codegenNode.type !== 13 /* VNODE_CALL */) {1707 return 0 /* NOT_CONSTANT */;1708 }1709 if (codegenNode.isBlock &&1710 node.tag !== 'svg' &&1711 node.tag !== 'foreignObject') {1712 return 0 /* NOT_CONSTANT */;1713 }1714 const flag = getPatchFlag(codegenNode);1715 if (!flag) {1716 let returnType = 3 /* CAN_STRINGIFY */;1717 // Element itself has no patch flag. However we still need to check:1718 // 1. Even for a node with no patch flag, it is possible for it to contain1719 // non-hoistable expressions that refers to scope variables, e.g. compiler1720 // injected keys or cached event handlers. Therefore we need to always1721 // check the codegenNode's props to be sure.1722 const generatedPropsType = getGeneratedPropsConstantType(node, context);1723 if (generatedPropsType === 0 /* NOT_CONSTANT */) {1724 constantCache.set(node, 0 /* NOT_CONSTANT */);1725 return 0 /* NOT_CONSTANT */;1726 }1727 if (generatedPropsType < returnType) {1728 returnType = generatedPropsType;1729 }1730 // 2. its children.1731 for (let i = 0; i < node.children.length; i++) {1732 const childType = getConstantType(node.children[i], context);1733 if (childType === 0 /* NOT_CONSTANT */) {1734 constantCache.set(node, 0 /* NOT_CONSTANT */);1735 return 0 /* NOT_CONSTANT */;1736 }1737 if (childType < returnType) {1738 returnType = childType;1739 }1740 }1741 // 3. if the type is not already CAN_SKIP_PATCH which is the lowest non-01742 // type, check if any of the props can cause the type to be lowered1743 // we can skip can_patch because it's guaranteed by the absence of a1744 // patchFlag.1745 if (returnType > 1 /* CAN_SKIP_PATCH */) {1746 for (let i = 0; i < node.props.length; i++) {1747 const p = node.props[i];1748 if (p.type === 7 /* DIRECTIVE */ && p.name === 'bind' && p.exp) {1749 const expType = getConstantType(p.exp, context);1750 if (expType === 0 /* NOT_CONSTANT */) {1751 constantCache.set(node, 0 /* NOT_CONSTANT */);1752 return 0 /* NOT_CONSTANT */;1753 }1754 if (expType < returnType) {1755 returnType = expType;1756 }1757 }1758 }1759 }1760 // only svg/foreignObject could be block here, however if they are1761 // static then they don't need to be blocks since there will be no1762 // nested updates.1763 if (codegenNode.isBlock) {1764 context.removeHelper(OPEN_BLOCK);1765 context.removeHelper(getVNodeBlockHelper(context.inSSR, codegenNode.isComponent));1766 codegenNode.isBlock = false;1767 context.helper(getVNodeHelper(context.inSSR, codegenNode.isComponent));1768 }1769 constantCache.set(node, returnType);1770 return returnType;1771 }1772 else {1773 constantCache.set(node, 0 /* NOT_CONSTANT */);1774 return 0 /* NOT_CONSTANT */;1775 }1776 case 2 /* TEXT */:1777 case 3 /* COMMENT */:1778 return 3 /* CAN_STRINGIFY */;1779 case 9 /* IF */:1780 case 11 /* FOR */:1781 case 10 /* IF_BRANCH */:1782 return 0 /* NOT_CONSTANT */;1783 case 5 /* INTERPOLATION */:1784 case 12 /* TEXT_CALL */:1785 return getConstantType(node.content, context);1786 case 4 /* SIMPLE_EXPRESSION */:1787 return node.constType;1788 case 8 /* COMPOUND_EXPRESSION */:1789 let returnType = 3 /* CAN_STRINGIFY */;1790 for (let i = 0; i < node.children.length; i++) {1791 const child = node.children[i];1792 if (shared.isString(child) || shared.isSymbol(child)) {1793 continue;1794 }1795 const childType = getConstantType(child, context);1796 if (childType === 0 /* NOT_CONSTANT */) {1797 return 0 /* NOT_CONSTANT */;1798 }1799 else if (childType < returnType) {1800 returnType = childType;1801 }1802 }1803 return returnType;1804 default:1805 return 0 /* NOT_CONSTANT */;1806 }1807}1808const allowHoistedHelperSet = new Set([1809 NORMALIZE_CLASS,1810 NORMALIZE_STYLE,1811 NORMALIZE_PROPS,1812 GUARD_REACTIVE_PROPS1813]);1814function getConstantTypeOfHelperCall(value, context) {1815 if (value.type === 14 /* JS_CALL_EXPRESSION */ &&1816 !shared.isString(value.callee) &&1817 allowHoistedHelperSet.has(value.callee)) {1818 const arg = value.arguments[0];1819 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {1820 return getConstantType(arg, context);1821 }1822 else if (arg.type === 14 /* JS_CALL_EXPRESSION */) {1823 // in the case of nested helper call, e.g. `normalizeProps(guardReactiveProps(exp))`1824 return getConstantTypeOfHelperCall(arg, context);1825 }1826 }1827 return 0 /* NOT_CONSTANT */;1828}1829function getGeneratedPropsConstantType(node, context) {1830 let returnType = 3 /* CAN_STRINGIFY */;1831 const props = getNodeProps(node);1832 if (props && props.type === 15 /* JS_OBJECT_EXPRESSION */) {1833 const { properties } = props;1834 for (let i = 0; i < properties.length; i++) {1835 const { key, value } = properties[i];1836 const keyType = getConstantType(key, context);1837 if (keyType === 0 /* NOT_CONSTANT */) {1838 return keyType;1839 }1840 if (keyType < returnType) {1841 returnType = keyType;1842 }1843 let valueType;1844 if (value.type === 4 /* SIMPLE_EXPRESSION */) {1845 valueType = getConstantType(value, context);1846 }1847 else if (value.type === 14 /* JS_CALL_EXPRESSION */) {1848 // some helper calls can be hoisted,1849 // such as the `normalizeProps` generated by the compiler for pre-normalize class,1850 // in this case we need to respect the ConstantType of the helper's arguments1851 valueType = getConstantTypeOfHelperCall(value, context);1852 }1853 else {1854 valueType = 0 /* NOT_CONSTANT */;1855 }1856 if (valueType === 0 /* NOT_CONSTANT */) {1857 return valueType;1858 }1859 if (valueType < returnType) {1860 returnType = valueType;1861 }1862 }1863 }1864 return returnType;1865}1866function getNodeProps(node) {1867 const codegenNode = node.codegenNode;1868 if (codegenNode.type === 13 /* VNODE_CALL */) {1869 return codegenNode.props;1870 }1871}1872function getPatchFlag(node) {1873 const flag = node.patchFlag;1874 return flag ? parseInt(flag, 10) : undefined;1875}1876function 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 }) {1877 const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/);1878 const context = {1879 // options1880 selfName: nameMatch && shared.capitalize(shared.camelize(nameMatch[1])),1881 prefixIdentifiers,1882 hoistStatic,1883 cacheHandlers,1884 nodeTransforms,1885 directiveTransforms,1886 transformHoist,1887 isBuiltInComponent,1888 isCustomElement,1889 expressionPlugins,1890 scopeId,1891 slotted,1892 ssr,1893 inSSR,1894 ssrCssVars,1895 bindingMetadata,1896 inline,1897 isTS,1898 onError,1899 onWarn,1900 compatConfig,1901 // state1902 root,1903 helpers: new Map(),1904 components: new Set(),1905 directives: new Set(),1906 hoists: [],1907 imports: [],1908 constantCache: new Map(),1909 temps: 0,1910 cached: 0,1911 identifiers: Object.create(null),1912 scopes: {1913 vFor: 0,1914 vSlot: 0,1915 vPre: 0,1916 vOnce: 01917 },1918 parent: null,1919 currentNode: root,1920 childIndex: 0,1921 inVOnce: false,1922 // methods1923 helper(name) {1924 const count = context.helpers.get(name) || 0;1925 context.helpers.set(name, count + 1);1926 return name;1927 },1928 removeHelper(name) {1929 const count = context.helpers.get(name);1930 if (count) {1931 const currentCount = count - 1;1932 if (!currentCount) {1933 context.helpers.delete(name);1934 }1935 else {1936 context.helpers.set(name, currentCount);1937 }1938 }1939 },1940 helperString(name) {1941 return `_${helperNameMap[context.helper(name)]}`;1942 },1943 replaceNode(node) {1944 context.parent.children[context.childIndex] = context.currentNode = node;1945 },1946 removeNode(node) {1947 const list = context.parent.children;1948 const removalIndex = node1949 ? list.indexOf(node)1950 : context.currentNode1951 ? context.childIndex1952 : -1;1953 if (!node || node === context.currentNode) {1954 // current node removed1955 context.currentNode = null;1956 context.onNodeRemoved();1957 }1958 else {1959 // sibling node removed1960 if (context.childIndex > removalIndex) {1961 context.childIndex--;1962 context.onNodeRemoved();1963 }1964 }1965 context.parent.children.splice(removalIndex, 1);1966 },1967 onNodeRemoved: () => { },1968 addIdentifiers(exp) {1969 // identifier tracking only happens in non-browser builds.1970 {1971 if (shared.isString(exp)) {1972 addId(exp);1973 }1974 else if (exp.identifiers) {1975 exp.identifiers.forEach(addId);1976 }1977 else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {1978 addId(exp.content);1979 }1980 }1981 },1982 removeIdentifiers(exp) {1983 {1984 if (shared.isString(exp)) {1985 removeId(exp);1986 }1987 else if (exp.identifiers) {1988 exp.identifiers.forEach(removeId);1989 }1990 else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {1991 removeId(exp.content);1992 }1993 }1994 },1995 hoist(exp) {1996 if (shared.isString(exp))1997 exp = createSimpleExpression(exp);1998 context.hoists.push(exp);1999 const identifier = createSimpleExpression(`_hoisted_${context.hoists.length}`, false, exp.loc, 2 /* CAN_HOIST */);2000 identifier.hoisted = exp;2001 return identifier;2002 },2003 cache(exp, isVNode = false) {2004 return createCacheExpression(context.cached++, exp, isVNode);2005 }2006 };2007 {2008 context.filters = new Set();2009 }2010 function addId(id) {2011 const { identifiers } = context;2012 if (identifiers[id] === undefined) {2013 identifiers[id] = 0;2014 }2015 identifiers[id]++;2016 }2017 function removeId(id) {2018 context.identifiers[id]--;2019 }2020 return context;2021}2022function transform(root, options) {2023 const context = createTransformContext(root, options);2024 traverseNode(root, context);2025 if (options.hoistStatic) {2026 hoistStatic(root, context);2027 }2028 if (!options.ssr) {2029 createRootCodegen(root, context);2030 }2031 // finalize meta information2032 root.helpers = [...context.helpers.keys()];2033 root.components = [...context.components];2034 root.directives = [...context.directives];2035 root.imports = context.imports;2036 root.hoists = context.hoists;2037 root.temps = context.temps;2038 root.cached = context.cached;2039 {2040 root.filters = [...context.filters];2041 }2042}2043function createRootCodegen(root, context) {2044 const { helper } = context;2045 const { children } = root;2046 if (children.length === 1) {2047 const child = children[0];2048 // if the single child is an element, turn it into a block.2049 if (isSingleElementRoot(root, child) && child.codegenNode) {2050 // single element root is never hoisted so codegenNode will never be2051 // SimpleExpressionNode2052 const codegenNode = child.codegenNode;2053 if (codegenNode.type === 13 /* VNODE_CALL */) {2054 makeBlock(codegenNode, context);2055 }2056 root.codegenNode = codegenNode;2057 }2058 else {2059 // - single <slot/>, IfNode, ForNode: already blocks.2060 // - single text node: always patched.2061 // root codegen falls through via genNode()2062 root.codegenNode = child;2063 }2064 }2065 else if (children.length > 1) {2066 // root has multiple nodes - return a fragment block.2067 let patchFlag = 64 /* STABLE_FRAGMENT */;2068 shared.PatchFlagNames[64 /* STABLE_FRAGMENT */];2069 root.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, root.children, patchFlag + (``), undefined, undefined, true, undefined, false /* isComponent */);2070 }2071 else ;2072}2073function traverseChildren(parent, context) {2074 let i = 0;2075 const nodeRemoved = () => {2076 i--;2077 };2078 for (; i < parent.children.length; i++) {2079 const child = parent.children[i];2080 if (shared.isString(child))2081 continue;2082 context.parent = parent;2083 context.childIndex = i;2084 context.onNodeRemoved = nodeRemoved;2085 traverseNode(child, context);2086 }2087}2088function traverseNode(node, context) {2089 context.currentNode = node;2090 // apply transform plugins2091 const { nodeTransforms } = context;2092 const exitFns = [];2093 for (let i = 0; i < nodeTransforms.length; i++) {2094 const onExit = nodeTransforms[i](node, context);2095 if (onExit) {2096 if (shared.isArray(onExit)) {2097 exitFns.push(...onExit);2098 }2099 else {2100 exitFns.push(onExit);2101 }2102 }2103 if (!context.currentNode) {2104 // node was removed2105 return;2106 }2107 else {2108 // node may have been replaced2109 node = context.currentNode;2110 }2111 }2112 switch (node.type) {2113 case 3 /* COMMENT */:2114 if (!context.ssr) {2115 // inject import for the Comment symbol, which is needed for creating2116 // comment nodes with `createVNode`2117 context.helper(CREATE_COMMENT);2118 }2119 break;2120 case 5 /* INTERPOLATION */:2121 // no need to traverse, but we need to inject toString helper2122 if (!context.ssr) {2123 context.helper(TO_DISPLAY_STRING);2124 }2125 break;2126 // for container types, further traverse downwards2127 case 9 /* IF */:2128 for (let i = 0; i < node.branches.length; i++) {2129 traverseNode(node.branches[i], context);2130 }2131 break;2132 case 10 /* IF_BRANCH */:2133 case 11 /* FOR */:2134 case 1 /* ELEMENT */:2135 case 0 /* ROOT */:2136 traverseChildren(node, context);2137 break;2138 }2139 // exit transforms2140 context.currentNode = node;2141 let i = exitFns.length;2142 while (i--) {2143 exitFns[i]();2144 }2145}2146function createStructuralDirectiveTransform(name, fn) {2147 const matches = shared.isString(name)2148 ? (n) => n === name2149 : (n) => name.test(n);2150 return (node, context) => {2151 if (node.type === 1 /* ELEMENT */) {2152 const { props } = node;2153 // structural directive transforms are not concerned with slots2154 // as they are handled separately in vSlot.ts2155 if (node.tagType === 3 /* TEMPLATE */ && props.some(isVSlot)) {2156 return;2157 }2158 const exitFns = [];2159 for (let i = 0; i < props.length; i++) {2160 const prop = props[i];2161 if (prop.type === 7 /* DIRECTIVE */ && matches(prop.name)) {2162 // structural directives are removed to avoid infinite recursion2163 // also we remove them *before* applying so that it can further2164 // traverse itself in case it moves the node around2165 props.splice(i, 1);2166 i--;2167 const onExit = fn(node, prop, context);2168 if (onExit)2169 exitFns.push(onExit);2170 }2171 }2172 return exitFns;2173 }2174 };2175}2176const PURE_ANNOTATION = `/*#__PURE__*/`;2177function 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 }) {2178 const context = {2179 mode,2180 prefixIdentifiers,2181 sourceMap: sourceMap$1,2182 filename,2183 scopeId,2184 optimizeImports,2185 runtimeGlobalName,2186 runtimeModuleName,2187 ssrRuntimeModuleName,2188 ssr,2189 isTS,2190 inSSR,2191 source: ast.loc.source,2192 code: ``,2193 column: 1,2194 line: 1,2195 offset: 0,2196 indentLevel: 0,2197 pure: false,2198 map: undefined,2199 helper(key) {2200 return `_${helperNameMap[key]}`;2201 },2202 push(code, node) {2203 context.code += code;2204 if (context.map) {2205 if (node) {2206 let name;2207 if (node.type === 4 /* SIMPLE_EXPRESSION */ && !node.isStatic) {2208 const content = node.content.replace(/^_ctx\./, '');2209 if (content !== node.content && isSimpleIdentifier(content)) {2210 name = content;2211 }2212 }2213 addMapping(node.loc.start, name);2214 }2215 advancePositionWithMutation(context, code);2216 if (node && node.loc !== locStub) {2217 addMapping(node.loc.end);2218 }2219 }2220 },2221 indent() {2222 newline(++context.indentLevel);2223 },2224 deindent(withoutNewLine = false) {2225 if (withoutNewLine) {2226 --context.indentLevel;2227 }2228 else {2229 newline(--context.indentLevel);2230 }2231 },2232 newline() {2233 newline(context.indentLevel);2234 }2235 };2236 function newline(n) {2237 context.push('\n' + ` `.repeat(n));2238 }2239 function addMapping(loc, name) {2240 context.map.addMapping({2241 name,2242 source: context.filename,2243 original: {2244 line: loc.line,2245 column: loc.column - 1 // source-map column is 0 based2246 },2247 generated: {2248 line: context.line,2249 column: context.column - 12250 }2251 });2252 }2253 if (sourceMap$1) {2254 // lazy require source-map implementation, only in non-browser builds2255 context.map = new sourceMap.SourceMapGenerator();2256 context.map.setSourceContent(filename, context.source);2257 }2258 return context;2259}2260function generate(ast, options = {}) {2261 const context = createCodegenContext(ast, options);2262 if (options.onContextCreated)2263 options.onContextCreated(context);2264 const { mode, push, prefixIdentifiers, indent, deindent, newline, scopeId, ssr } = context;2265 const hasHelpers = ast.helpers.length > 0;2266 const useWithBlock = !prefixIdentifiers && mode !== 'module';2267 const genScopeId = scopeId != null && mode === 'module';2268 const isSetupInlined = !!options.inline;2269 // preambles2270 // in setup() inline mode, the preamble is generated in a sub context2271 // and returned separately.2272 const preambleContext = isSetupInlined2273 ? createCodegenContext(ast, options)2274 : context;2275 if (mode === 'module') {2276 genModulePreamble(ast, preambleContext, genScopeId, isSetupInlined);2277 }2278 else {2279 genFunctionPreamble(ast, preambleContext);2280 }2281 // enter render function2282 const functionName = ssr ? `ssrRender` : `render`;2283 const args = ssr ? ['_ctx', '_push', '_parent', '_attrs'] : ['_ctx', '_cache'];2284 if (options.bindingMetadata && !options.inline) {2285 // binding optimization args2286 args.push('$props', '$setup', '$data', '$options');2287 }2288 const signature = options.isTS2289 ? args.map(arg => `${arg}: any`).join(',')2290 : args.join(', ');2291 if (isSetupInlined) {2292 push(`(${signature}) => {`);2293 }2294 else {2295 push(`function ${functionName}(${signature}) {`);2296 }2297 indent();2298 if (useWithBlock) {2299 push(`with (_ctx) {`);2300 indent();2301 // function mode const declarations should be inside with block2302 // also they should be renamed to avoid collision with user properties2303 if (hasHelpers) {2304 push(`const { ${ast.helpers2305 .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)2306 .join(', ')} } = _Vue`);2307 push(`\n`);2308 newline();2309 }2310 }2311 // generate asset resolution statements2312 if (ast.components.length) {2313 genAssets(ast.components, 'component', context);2314 if (ast.directives.length || ast.temps > 0) {2315 newline();2316 }2317 }2318 if (ast.directives.length) {2319 genAssets(ast.directives, 'directive', context);2320 if (ast.temps > 0) {2321 newline();2322 }2323 }2324 if (ast.filters && ast.filters.length) {2325 newline();2326 genAssets(ast.filters, 'filter', context);2327 newline();2328 }2329 if (ast.temps > 0) {2330 push(`let `);2331 for (let i = 0; i < ast.temps; i++) {2332 push(`${i > 0 ? `, ` : ``}_temp${i}`);2333 }2334 }2335 if (ast.components.length || ast.directives.length || ast.temps) {2336 push(`\n`);2337 newline();2338 }2339 // generate the VNode tree expression2340 if (!ssr) {2341 push(`return `);2342 }2343 if (ast.codegenNode) {2344 genNode(ast.codegenNode, context);2345 }2346 else {2347 push(`null`);2348 }2349 if (useWithBlock) {2350 deindent();2351 push(`}`);2352 }2353 deindent();2354 push(`}`);2355 return {2356 ast,2357 code: context.code,2358 preamble: isSetupInlined ? preambleContext.code : ``,2359 // SourceMapGenerator does have toJSON() method but it's not in the types2360 map: context.map ? context.map.toJSON() : undefined2361 };2362}2363function genFunctionPreamble(ast, context) {2364 const { ssr, prefixIdentifiers, push, newline, runtimeModuleName, runtimeGlobalName, ssrRuntimeModuleName } = context;2365 const VueBinding = ssr2366 ? `require(${JSON.stringify(runtimeModuleName)})`2367 : runtimeGlobalName;2368 const aliasHelper = (s) => `${helperNameMap[s]}: _${helperNameMap[s]}`;2369 // Generate const declaration for helpers2370 // In prefix mode, we place the const declaration at top so it's done2371 // only once; But if we not prefixing, we place the declaration inside the2372 // with block so it doesn't incur the `in` check cost for every helper access.2373 if (ast.helpers.length > 0) {2374 if (prefixIdentifiers) {2375 push(`const { ${ast.helpers.map(aliasHelper).join(', ')} } = ${VueBinding}\n`);2376 }2377 else {2378 // "with" mode.2379 // save Vue in a separate variable to avoid collision2380 push(`const _Vue = ${VueBinding}\n`);2381 // in "with" mode, helpers are declared inside the with block to avoid2382 // has check cost, but hoists are lifted out of the function - we need2383 // to provide the helper here.2384 if (ast.hoists.length) {2385 const staticHelpers = [2386 CREATE_VNODE,2387 CREATE_ELEMENT_VNODE,2388 CREATE_COMMENT,2389 CREATE_TEXT,2390 CREATE_STATIC2391 ]2392 .filter(helper => ast.helpers.includes(helper))2393 .map(aliasHelper)2394 .join(', ');2395 push(`const { ${staticHelpers} } = _Vue\n`);2396 }2397 }2398 }2399 // generate variables for ssr helpers2400 if (ast.ssrHelpers && ast.ssrHelpers.length) {2401 // ssr guarantees prefixIdentifier: true2402 push(`const { ${ast.ssrHelpers2403 .map(aliasHelper)2404 .join(', ')} } = require("${ssrRuntimeModuleName}")\n`);2405 }2406 genHoists(ast.hoists, context);2407 newline();2408 push(`return `);2409}2410function genModulePreamble(ast, context, genScopeId, inline) {2411 const { push, newline, optimizeImports, runtimeModuleName, ssrRuntimeModuleName } = context;2412 if (genScopeId && ast.hoists.length) {2413 ast.helpers.push(PUSH_SCOPE_ID, POP_SCOPE_ID);2414 }2415 // generate import statements for helpers2416 if (ast.helpers.length) {2417 if (optimizeImports) {2418 // when bundled with webpack with code-split, calling an import binding2419 // as a function leads to it being wrapped with `Object(a.b)` or `(0,a.b)`,2420 // incurring both payload size increase and potential perf overhead.2421 // therefore we assign the imports to variables (which is a constant ~50b2422 // cost per-component instead of scaling with template size)2423 push(`import { ${ast.helpers2424 .map(s => helperNameMap[s])2425 .join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`);2426 push(`\n// Binding optimization for webpack code-split\nconst ${ast.helpers2427 .map(s => `_${helperNameMap[s]} = ${helperNameMap[s]}`)2428 .join(', ')}\n`);2429 }2430 else {2431 push(`import { ${ast.helpers2432 .map(s => `${helperNameMap[s]} as _${helperNameMap[s]}`)2433 .join(', ')} } from ${JSON.stringify(runtimeModuleName)}\n`);2434 }2435 }2436 if (ast.ssrHelpers && ast.ssrHelpers.length) {2437 push(`import { ${ast.ssrHelpers2438 .map(s => `${helperNameMap[s]} as _${helperNameMap[s]}`)2439 .join(', ')} } from "${ssrRuntimeModuleName}"\n`);2440 }2441 if (ast.imports.length) {2442 genImports(ast.imports, context);2443 newline();2444 }2445 genHoists(ast.hoists, context);2446 newline();2447 if (!inline) {2448 push(`export `);2449 }2450}2451function genAssets(assets, type, { helper, push, newline, isTS }) {2452 const resolver = helper(type === 'filter'2453 ? RESOLVE_FILTER2454 : type === 'component'2455 ? RESOLVE_COMPONENT2456 : RESOLVE_DIRECTIVE);2457 for (let i = 0; i < assets.length; i++) {2458 let id = assets[i];2459 // potential component implicit self-reference inferred from SFC filename2460 const maybeSelfReference = id.endsWith('__self');2461 if (maybeSelfReference) {2462 id = id.slice(0, -6);2463 }2464 push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`);2465 if (i < assets.length - 1) {2466 newline();2467 }2468 }2469}2470function genHoists(hoists, context) {2471 if (!hoists.length) {2472 return;2473 }2474 context.pure = true;2475 const { push, newline, helper, scopeId, mode } = context;2476 const genScopeId = scopeId != null && mode !== 'function';2477 newline();2478 // generate inlined withScopeId helper2479 if (genScopeId) {2480 push(`const _withScopeId = n => (${helper(PUSH_SCOPE_ID)}("${scopeId}"),n=n(),${helper(POP_SCOPE_ID)}(),n)`);2481 newline();2482 }2483 for (let i = 0; i < hoists.length; i++) {2484 const exp = hoists[i];2485 if (exp) {2486 const needScopeIdWrapper = genScopeId && exp.type === 13 /* VNODE_CALL */;2487 push(`const _hoisted_${i + 1} = ${needScopeIdWrapper ? `${PURE_ANNOTATION} _withScopeId(() => ` : ``}`);2488 genNode(exp, context);2489 if (needScopeIdWrapper) {2490 push(`)`);2491 }2492 newline();2493 }2494 }2495 context.pure = false;2496}2497function genImports(importsOptions, context) {2498 if (!importsOptions.length) {2499 return;2500 }2501 importsOptions.forEach(imports => {2502 context.push(`import `);2503 genNode(imports.exp, context);2504 context.push(` from '${imports.path}'`);2505 context.newline();2506 });2507}2508function isText$1(n) {2509 return (shared.isString(n) ||2510 n.type === 4 /* SIMPLE_EXPRESSION */ ||2511 n.type === 2 /* TEXT */ ||2512 n.type === 5 /* INTERPOLATION */ ||2513 n.type === 8 /* COMPOUND_EXPRESSION */);2514}2515function genNodeListAsArray(nodes, context) {2516 const multilines = nodes.length > 3 ||2517 (nodes.some(n => shared.isArray(n) || !isText$1(n)));2518 context.push(`[`);2519 multilines && context.indent();2520 genNodeList(nodes, context, multilines);2521 multilines && context.deindent();2522 context.push(`]`);2523}2524function genNodeList(nodes, context, multilines = false, comma = true) {2525 const { push, newline } = context;2526 for (let i = 0; i < nodes.length; i++) {2527 const node = nodes[i];2528 if (shared.isString(node)) {2529 push(node);2530 }2531 else if (shared.isArray(node)) {2532 genNodeListAsArray(node, context);2533 }2534 else {2535 genNode(node, context);2536 }2537 if (i < nodes.length - 1) {2538 if (multilines) {2539 comma && push(',');2540 newline();2541 }2542 else {2543 comma && push(', ');2544 }2545 }2546 }2547}2548function genNode(node, context) {2549 if (shared.isString(node)) {2550 context.push(node);2551 return;2552 }2553 if (shared.isSymbol(node)) {2554 context.push(context.helper(node));2555 return;2556 }2557 switch (node.type) {2558 case 1 /* ELEMENT */:2559 case 9 /* IF */:2560 case 11 /* FOR */:2561 genNode(node.codegenNode, context);2562 break;2563 case 2 /* TEXT */:2564 genText(node, context);2565 break;2566 case 4 /* SIMPLE_EXPRESSION */:2567 genExpression(node, context);2568 break;2569 case 5 /* INTERPOLATION */:2570 genInterpolation(node, context);2571 break;2572 case 12 /* TEXT_CALL */:2573 genNode(node.codegenNode, context);2574 break;2575 case 8 /* COMPOUND_EXPRESSION */:2576 genCompoundExpression(node, context);2577 break;2578 case 3 /* COMMENT */:2579 genComment(node, context);2580 break;2581 case 13 /* VNODE_CALL */:2582 genVNodeCall(node, context);2583 break;2584 case 14 /* JS_CALL_EXPRESSION */:2585 genCallExpression(node, context);2586 break;2587 case 15 /* JS_OBJECT_EXPRESSION */:2588 genObjectExpression(node, context);2589 break;2590 case 17 /* JS_ARRAY_EXPRESSION */:2591 genArrayExpression(node, context);2592 break;2593 case 18 /* JS_FUNCTION_EXPRESSION */:2594 genFunctionExpression(node, context);2595 break;2596 case 19 /* JS_CONDITIONAL_EXPRESSION */:2597 genConditionalExpression(node, context);2598 break;2599 case 20 /* JS_CACHE_EXPRESSION */:2600 genCacheExpression(node, context);2601 break;2602 case 21 /* JS_BLOCK_STATEMENT */:2603 genNodeList(node.body, context, true, false);2604 break;2605 // SSR only types2606 case 22 /* JS_TEMPLATE_LITERAL */:2607 genTemplateLiteral(node, context);2608 break;2609 case 23 /* JS_IF_STATEMENT */:2610 genIfStatement(node, context);2611 break;2612 case 24 /* JS_ASSIGNMENT_EXPRESSION */:2613 genAssignmentExpression(node, context);2614 break;2615 case 25 /* JS_SEQUENCE_EXPRESSION */:2616 genSequenceExpression(node, context);2617 break;2618 case 26 /* JS_RETURN_STATEMENT */:2619 genReturnStatement(node, context);2620 break;2621 }2622}2623function genText(node, context) {2624 context.push(JSON.stringify(node.content), node);2625}2626function genExpression(node, context) {2627 const { content, isStatic } = node;2628 context.push(isStatic ? JSON.stringify(content) : content, node);2629}2630function genInterpolation(node, context) {2631 const { push, helper, pure } = context;2632 if (pure)2633 push(PURE_ANNOTATION);2634 push(`${helper(TO_DISPLAY_STRING)}(`);2635 genNode(node.content, context);2636 push(`)`);2637}2638function genCompoundExpression(node, context) {2639 for (let i = 0; i < node.children.length; i++) {2640 const child = node.children[i];2641 if (shared.isString(child)) {2642 context.push(child);2643 }2644 else {2645 genNode(child, context);2646 }2647 }2648}2649function genExpressionAsPropertyKey(node, context) {2650 const { push } = context;2651 if (node.type === 8 /* COMPOUND_EXPRESSION */) {2652 push(`[`);2653 genCompoundExpression(node, context);2654 push(`]`);2655 }2656 else if (node.isStatic) {2657 // only quote keys if necessary2658 const text = isSimpleIdentifier(node.content)2659 ? node.content2660 : JSON.stringify(node.content);2661 push(text, node);2662 }2663 else {2664 push(`[${node.content}]`, node);2665 }2666}2667function genComment(node, context) {2668 const { push, helper, pure } = context;2669 if (pure) {2670 push(PURE_ANNOTATION);2671 }2672 push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node);2673}2674function genVNodeCall(node, context) {2675 const { push, helper, pure } = context;2676 const { tag, props, children, patchFlag, dynamicProps, directives, isBlock, disableTracking, isComponent } = node;2677 if (directives) {2678 push(helper(WITH_DIRECTIVES) + `(`);2679 }2680 if (isBlock) {2681 push(`(${helper(OPEN_BLOCK)}(${disableTracking ? `true` : ``}), `);2682 }2683 if (pure) {2684 push(PURE_ANNOTATION);2685 }2686 const callHelper = isBlock2687 ? getVNodeBlockHelper(context.inSSR, isComponent)2688 : getVNodeHelper(context.inSSR, isComponent);2689 push(helper(callHelper) + `(`, node);2690 genNodeList(genNullableArgs([tag, props, children, patchFlag, dynamicProps]), context);2691 push(`)`);2692 if (isBlock) {2693 push(`)`);2694 }2695 if (directives) {2696 push(`, `);2697 genNode(directives, context);2698 push(`)`);2699 }2700}2701function genNullableArgs(args) {2702 let i = args.length;2703 while (i--) {2704 if (args[i] != null)2705 break;2706 }2707 return args.slice(0, i + 1).map(arg => arg || `null`);2708}2709// JavaScript2710function genCallExpression(node, context) {2711 const { push, helper, pure } = context;2712 const callee = shared.isString(node.callee) ? node.callee : helper(node.callee);2713 if (pure) {2714 push(PURE_ANNOTATION);2715 }2716 push(callee + `(`, node);2717 genNodeList(node.arguments, context);2718 push(`)`);2719}2720function genObjectExpression(node, context) {2721 const { push, indent, deindent, newline } = context;2722 const { properties } = node;2723 if (!properties.length) {2724 push(`{}`, node);2725 return;2726 }2727 const multilines = properties.length > 1 ||2728 (properties.some(p => p.value.type !== 4 /* SIMPLE_EXPRESSION */));2729 push(multilines ? `{` : `{ `);2730 multilines && indent();2731 for (let i = 0; i < properties.length; i++) {2732 const { key, value } = properties[i];2733 // key2734 genExpressionAsPropertyKey(key, context);2735 push(`: `);2736 // value2737 genNode(value, context);2738 if (i < properties.length - 1) {2739 // will only reach this if it's multilines2740 push(`,`);2741 newline();2742 }2743 }2744 multilines && deindent();2745 push(multilines ? `}` : ` }`);2746}2747function genArrayExpression(node, context) {2748 genNodeListAsArray(node.elements, context);2749}2750function genFunctionExpression(node, context) {2751 const { push, indent, deindent } = context;2752 const { params, returns, body, newline, isSlot } = node;2753 if (isSlot) {2754 // wrap slot functions with owner context2755 push(`_${helperNameMap[WITH_CTX]}(`);2756 }2757 push(`(`, node);2758 if (shared.isArray(params)) {2759 genNodeList(params, context);2760 }2761 else if (params) {2762 genNode(params, context);2763 }2764 push(`) => `);2765 if (newline || body) {2766 push(`{`);2767 indent();2768 }2769 if (returns) {2770 if (newline) {2771 push(`return `);2772 }2773 if (shared.isArray(returns)) {2774 genNodeListAsArray(returns, context);2775 }2776 else {2777 genNode(returns, context);2778 }2779 }2780 else if (body) {2781 genNode(body, context);2782 }2783 if (newline || body) {2784 deindent();2785 push(`}`);2786 }2787 if (isSlot) {2788 if (node.isNonScopedSlot) {2789 push(`, undefined, true`);2790 }2791 push(`)`);2792 }2793}2794function genConditionalExpression(node, context) {2795 const { test, consequent, alternate, newline: needNewline } = node;2796 const { push, indent, deindent, newline } = context;2797 if (test.type === 4 /* SIMPLE_EXPRESSION */) {2798 const needsParens = !isSimpleIdentifier(test.content);2799 needsParens && push(`(`);2800 genExpression(test, context);2801 needsParens && push(`)`);2802 }2803 else {2804 push(`(`);2805 genNode(test, context);2806 push(`)`);2807 }2808 needNewline && indent();2809 context.indentLevel++;2810 needNewline || push(` `);2811 push(`? `);2812 genNode(consequent, context);2813 context.indentLevel--;2814 needNewline && newline();2815 needNewline || push(` `);2816 push(`: `);2817 const isNested = alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */;2818 if (!isNested) {2819 context.indentLevel++;2820 }2821 genNode(alternate, context);2822 if (!isNested) {2823 context.indentLevel--;2824 }2825 needNewline && deindent(true /* without newline */);2826}2827function genCacheExpression(node, context) {2828 const { push, helper, indent, deindent, newline } = context;2829 push(`_cache[${node.index}] || (`);2830 if (node.isVNode) {2831 indent();2832 push(`${helper(SET_BLOCK_TRACKING)}(-1),`);2833 newline();2834 }2835 push(`_cache[${node.index}] = `);2836 genNode(node.value, context);2837 if (node.isVNode) {2838 push(`,`);2839 newline();2840 push(`${helper(SET_BLOCK_TRACKING)}(1),`);2841 newline();2842 push(`_cache[${node.index}]`);2843 deindent();2844 }2845 push(`)`);2846}2847function genTemplateLiteral(node, context) {2848 const { push, indent, deindent } = context;2849 push('`');2850 const l = node.elements.length;2851 const multilines = l > 3;2852 for (let i = 0; i < l; i++) {2853 const e = node.elements[i];2854 if (shared.isString(e)) {2855 push(e.replace(/(`|\$|\\)/g, '\\$1'));2856 }2857 else {2858 push('${');2859 if (multilines)2860 indent();2861 genNode(e, context);2862 if (multilines)2863 deindent();2864 push('}');2865 }2866 }2867 push('`');2868}2869function genIfStatement(node, context) {2870 const { push, indent, deindent } = context;2871 const { test, consequent, alternate } = node;2872 push(`if (`);2873 genNode(test, context);2874 push(`) {`);2875 indent();2876 genNode(consequent, context);2877 deindent();2878 push(`}`);2879 if (alternate) {2880 push(` else `);2881 if (alternate.type === 23 /* JS_IF_STATEMENT */) {2882 genIfStatement(alternate, context);2883 }2884 else {2885 push(`{`);2886 indent();2887 genNode(alternate, context);2888 deindent();2889 push(`}`);2890 }2891 }2892}2893function genAssignmentExpression(node, context) {2894 genNode(node.left, context);2895 context.push(` = `);2896 genNode(node.right, context);2897}2898function genSequenceExpression(node, context) {2899 context.push(`(`);2900 genNodeList(node.expressions, context);2901 context.push(`)`);2902}2903function genReturnStatement({ returns }, context) {2904 context.push(`return `);2905 if (shared.isArray(returns)) {2906 genNodeListAsArray(returns, context);2907 }2908 else {2909 genNode(returns, context);2910 }2911}2912function walkIdentifiers(root, onIdentifier, includeAll = false, parentStack = [], knownIds = Object.create(null)) {2913 const rootExp = root.type === 'Program' &&2914 root.body[0].type === 'ExpressionStatement' &&2915 root.body[0].expression;2916 estreeWalker.walk(root, {2917 enter(node, parent) {2918 parent && parentStack.push(parent);2919 if (parent &&2920 parent.type.startsWith('TS') &&2921 parent.type !== 'TSAsExpression' &&2922 parent.type !== 'TSNonNullExpression' &&2923 parent.type !== 'TSTypeAssertion') {2924 return this.skip();2925 }2926 if (node.type === 'Identifier') {2927 const isLocal = !!knownIds[node.name];2928 const isRefed = isReferencedIdentifier(node, parent, parentStack);2929 if (includeAll || (isRefed && !isLocal)) {2930 onIdentifier(node, parent, parentStack, isRefed, isLocal);2931 }2932 }2933 else if (node.type === 'ObjectProperty' &&2934 parent.type === 'ObjectPattern') {2935 node.inPattern = true;2936 }2937 else if (isFunctionType(node)) {2938 // walk function expressions and add its arguments to known identifiers2939 // so that we don't prefix them2940 walkFunctionParams(node, id => markScopeIdentifier(node, id, knownIds));2941 }2942 else if (node.type === 'BlockStatement') {2943 // #3445 record block-level local variables2944 walkBlockDeclarations(node, id => markScopeIdentifier(node, id, knownIds));2945 }2946 },2947 leave(node, parent) {2948 parent && parentStack.pop();2949 if (node !== rootExp && node.scopeIds) {2950 for (const id of node.scopeIds) {2951 knownIds[id]--;2952 if (knownIds[id] === 0) {2953 delete knownIds[id];2954 }2955 }2956 }2957 }2958 });2959}2960function isReferencedIdentifier(id, parent, parentStack) {2961 if (!parent) {2962 return true;2963 }2964 // is a special keyword but parsed as identifier2965 if (id.name === 'arguments') {2966 return false;2967 }2968 if (isReferenced(id, parent)) {2969 return true;2970 }2971 // babel's isReferenced check returns false for ids being assigned to, so we2972 // need to cover those cases here2973 switch (parent.type) {2974 case 'AssignmentExpression':2975 case 'AssignmentPattern':2976 return true;2977 case 'ObjectPattern':2978 case 'ArrayPattern':2979 return isInDestructureAssignment(parent, parentStack);2980 }2981 return false;2982}2983function isInDestructureAssignment(parent, parentStack) {2984 if (parent &&2985 (parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')) {2986 let i = parentStack.length;2987 while (i--) {2988 const p = parentStack[i];2989 if (p.type === 'AssignmentExpression') {2990 return true;2991 }2992 else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {2993 break;2994 }2995 }2996 }2997 return false;2998}2999function walkFunctionParams(node, onIdent) {3000 for (const p of node.params) {3001 for (const id of extractIdentifiers(p)) {3002 onIdent(id);3003 }3004 }3005}3006function walkBlockDeclarations(block, onIdent) {3007 for (const stmt of block.body) {3008 if (stmt.type === 'VariableDeclaration') {3009 if (stmt.declare)3010 continue;3011 for (const decl of stmt.declarations) {3012 for (const id of extractIdentifiers(decl.id)) {3013 onIdent(id);3014 }3015 }3016 }3017 else if (stmt.type === 'FunctionDeclaration' ||3018 stmt.type === 'ClassDeclaration') {3019 if (stmt.declare || !stmt.id)3020 continue;3021 onIdent(stmt.id);3022 }3023 }3024}3025function extractIdentifiers(param, nodes = []) {3026 switch (param.type) {3027 case 'Identifier':3028 nodes.push(param);3029 break;3030 case 'MemberExpression':3031 let object = param;3032 while (object.type === 'MemberExpression') {3033 object = object.object;3034 }3035 nodes.push(object);3036 break;3037 case 'ObjectPattern':3038 for (const prop of param.properties) {3039 if (prop.type === 'RestElement') {3040 extractIdentifiers(prop.argument, nodes);3041 }3042 else {3043 extractIdentifiers(prop.value, nodes);3044 }3045 }3046 break;3047 case 'ArrayPattern':3048 param.elements.forEach(element => {3049 if (element)3050 extractIdentifiers(element, nodes);3051 });3052 break;3053 case 'RestElement':3054 extractIdentifiers(param.argument, nodes);3055 break;3056 case 'AssignmentPattern':3057 extractIdentifiers(param.left, nodes);3058 break;3059 }3060 return nodes;3061}3062function markScopeIdentifier(node, child, knownIds) {3063 const { name } = child;3064 if (node.scopeIds && node.scopeIds.has(name)) {3065 return;3066 }3067 if (name in knownIds) {3068 knownIds[name]++;3069 }3070 else {3071 knownIds[name] = 1;3072 }3073 (node.scopeIds || (node.scopeIds = new Set())).add(name);3074}3075const isFunctionType = (node) => {3076 return /Function(?:Expression|Declaration)$|Method$/.test(node.type);3077};3078const isStaticProperty = (node) => node &&3079 (node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&3080 !node.computed;3081const isStaticPropertyKey = (node, parent) => isStaticProperty(parent) && parent.key === node;3082/**3083 * Copied from https://github.com/babel/babel/blob/main/packages/babel-types/src/validators/isReferenced.ts3084 * To avoid runtime dependency on @babel/types (which includes process references)3085 * This file should not change very often in babel but we may need to keep it3086 * up-to-date from time to time.3087 *3088 * https://github.com/babel/babel/blob/main/LICENSE3089 *3090 */3091function isReferenced(node, parent, grandparent) {3092 switch (parent.type) {3093 // yes: PARENT[NODE]3094 // yes: NODE.child3095 // no: parent.NODE3096 case 'MemberExpression':3097 case 'OptionalMemberExpression':3098 if (parent.property === node) {3099 return !!parent.computed;3100 }3101 return parent.object === node;3102 case 'JSXMemberExpression':3103 return parent.object === node;3104 // no: let NODE = init;3105 // yes: let id = NODE;3106 case 'VariableDeclarator':3107 return parent.init === node;3108 // yes: () => NODE3109 // no: (NODE) => {}3110 case 'ArrowFunctionExpression':3111 return parent.body === node;3112 // no: class { #NODE; }3113 // no: class { get #NODE() {} }3114 // no: class { #NODE() {} }3115 // no: class { fn() { return this.#NODE; } }3116 case 'PrivateName':3117 return false;3118 // no: class { NODE() {} }3119 // yes: class { [NODE]() {} }3120 // no: class { foo(NODE) {} }3121 case 'ClassMethod':3122 case 'ClassPrivateMethod':3123 case 'ObjectMethod':3124 if (parent.key === node) {3125 return !!parent.computed;3126 }3127 return false;3128 // yes: { [NODE]: "" }3129 // no: { NODE: "" }3130 // depends: { NODE }3131 // depends: { key: NODE }3132 case 'ObjectProperty':3133 if (parent.key === node) {3134 return !!parent.computed;3135 }3136 // parent.value === node3137 return !grandparent || grandparent.type !== 'ObjectPattern';3138 // no: class { NODE = value; }3139 // yes: class { [NODE] = value; }3140 // yes: class { key = NODE; }3141 case 'ClassProperty':3142 if (parent.key === node) {3143 return !!parent.computed;3144 }3145 return true;3146 case 'ClassPrivateProperty':3147 return parent.key !== node;3148 // no: class NODE {}3149 // yes: class Foo extends NODE {}3150 case 'ClassDeclaration':3151 case 'ClassExpression':3152 return parent.superClass === node;3153 // yes: left = NODE;3154 // no: NODE = right;3155 case 'AssignmentExpression':3156 return parent.right === node;3157 // no: [NODE = foo] = [];3158 // yes: [foo = NODE] = [];3159 case 'AssignmentPattern':3160 return parent.right === node;3161 // no: NODE: for (;;) {}3162 case 'LabeledStatement':3163 return false;3164 // no: try {} catch (NODE) {}3165 case 'CatchClause':3166 return false;3167 // no: function foo(...NODE) {}3168 case 'RestElement':3169 return false;3170 case 'BreakStatement':3171 case 'ContinueStatement':3172 return false;3173 // no: function NODE() {}3174 // no: function foo(NODE) {}3175 case 'FunctionDeclaration':3176 case 'FunctionExpression':3177 return false;3178 // no: export NODE from "foo";3179 // no: export * as NODE from "foo";3180 case 'ExportNamespaceSpecifier':3181 case 'ExportDefaultSpecifier':3182 return false;3183 // no: export { foo as NODE };3184 // yes: export { NODE as foo };3185 // no: export { NODE as foo } from "foo";3186 case 'ExportSpecifier':3187 // @ts-expect-error3188 if (grandparent === null || grandparent === void 0 ? void 0 : grandparent.source) {3189 return false;3190 }3191 return parent.local === node;3192 // no: import NODE from "foo";3193 // no: import * as NODE from "foo";3194 // no: import { NODE as foo } from "foo";3195 // no: import { foo as NODE } from "foo";3196 // no: import NODE from "bar";3197 case 'ImportDefaultSpecifier':3198 case 'ImportNamespaceSpecifier':3199 case 'ImportSpecifier':3200 return false;3201 // no: import "foo" assert { NODE: "json" }3202 case 'ImportAttribute':3203 return false;3204 // no: <div NODE="foo" />3205 case 'JSXAttribute':3206 return false;3207 // no: [NODE] = [];3208 // no: ({ NODE }) = [];3209 case 'ObjectPattern':3210 case 'ArrayPattern':3211 return false;3212 // no: new.NODE3213 // no: NODE.target3214 case 'MetaProperty':3215 return false;3216 // yes: type X = { somePropert: NODE }3217 // no: type X = { NODE: OtherType }3218 case 'ObjectTypeProperty':3219 return parent.key !== node;3220 // yes: enum X { Foo = NODE }3221 // no: enum X { NODE }3222 case 'TSEnumMember':3223 return parent.id !== node;3224 // yes: { [NODE]: value }3225 // no: { NODE: value }3226 case 'TSPropertySignature':3227 if (parent.key === node) {3228 return !!parent.computed;3229 }3230 return true;3231 }3232 return true;3233}3234const isLiteralWhitelisted = /*#__PURE__*/ shared.makeMap('true,false,null,this');3235const transformExpression = (node, context) => {3236 if (node.type === 5 /* INTERPOLATION */) {3237 node.content = processExpression(node.content, context);3238 }3239 else if (node.type === 1 /* ELEMENT */) {3240 // handle directives on element3241 for (let i = 0; i < node.props.length; i++) {3242 const dir = node.props[i];3243 // do not process for v-on & v-for since they are special handled3244 if (dir.type === 7 /* DIRECTIVE */ && dir.name !== 'for') {3245 const exp = dir.exp;3246 const arg = dir.arg;3247 // do not process exp if this is v-on:arg - we need special handling3248 // for wrapping inline statements.3249 if (exp &&3250 exp.type === 4 /* SIMPLE_EXPRESSION */ &&3251 !(dir.name === 'on' && arg)) {3252 dir.exp = processExpression(exp, context, 3253 // slot args must be processed as function params3254 dir.name === 'slot');3255 }3256 if (arg && arg.type === 4 /* SIMPLE_EXPRESSION */ && !arg.isStatic) {3257 dir.arg = processExpression(arg, context);3258 }3259 }3260 }3261 }3262};3263// Important: since this function uses Node.js only dependencies, it should3264// always be used with a leading !false check so that it can be3265// tree-shaken from the browser build.3266function processExpression(node, context, 3267// some expressions like v-slot props & v-for aliases should be parsed as3268// function params3269asParams = false, 3270// v-on handler values may contain multiple statements3271asRawStatements = false, localVars = Object.create(context.identifiers)) {3272 if (!context.prefixIdentifiers || !node.content.trim()) {3273 return node;3274 }3275 const { inline, bindingMetadata } = context;3276 const rewriteIdentifier = (raw, parent, id) => {3277 const type = shared.hasOwn(bindingMetadata, raw) && bindingMetadata[raw];3278 if (inline) {3279 // x = y3280 const isAssignmentLVal = parent && parent.type === 'AssignmentExpression' && parent.left === id;3281 // x++3282 const isUpdateArg = parent && parent.type === 'UpdateExpression' && parent.argument === id;3283 // ({ x } = y)3284 const isDestructureAssignment = parent && isInDestructureAssignment(parent, parentStack);3285 if (type === "setup-const" /* SETUP_CONST */ || localVars[raw]) {3286 return raw;3287 }3288 else if (type === "setup-ref" /* SETUP_REF */) {3289 return `${raw}.value`;3290 }3291 else if (type === "setup-maybe-ref" /* SETUP_MAYBE_REF */) {3292 // const binding that may or may not be ref3293 // if it's not a ref, then assignments don't make sense -3294 // so we ignore the non-ref assignment case and generate code3295 // that assumes the value to be a ref for more efficiency3296 return isAssignmentLVal || isUpdateArg || isDestructureAssignment3297 ? `${raw}.value`3298 : `${context.helperString(UNREF)}(${raw})`;3299 }3300 else if (type === "setup-let" /* SETUP_LET */) {3301 if (isAssignmentLVal) {3302 // let binding.3303 // this is a bit more tricky as we need to cover the case where3304 // let is a local non-ref value, and we need to replicate the3305 // right hand side value.3306 // x = y --> isRef(x) ? x.value = y : x = y3307 const { right: rVal, operator } = parent;3308 const rExp = rawExp.slice(rVal.start - 1, rVal.end - 1);3309 const rExpString = stringifyExpression(processExpression(createSimpleExpression(rExp, false), context, false, false, knownIds));3310 return `${context.helperString(IS_REF)}(${raw})${context.isTS ? ` //@ts-ignore\n` : ``} ? ${raw}.value ${operator} ${rExpString} : ${raw}`;3311 }3312 else if (isUpdateArg) {3313 // make id replace parent in the code range so the raw update operator3314 // is removed3315 id.start = parent.start;3316 id.end = parent.end;3317 const { prefix: isPrefix, operator } = parent;3318 const prefix = isPrefix ? operator : ``;3319 const postfix = isPrefix ? `` : operator;3320 // let binding.3321 // x++ --> isRef(a) ? a.value++ : a++3322 return `${context.helperString(IS_REF)}(${raw})${context.isTS ? ` //@ts-ignore\n` : ``} ? ${prefix}${raw}.value${postfix} : ${prefix}${raw}${postfix}`;3323 }3324 else if (isDestructureAssignment) {3325 // TODO3326 // let binding in a destructure assignment - it's very tricky to3327 // handle both possible cases here without altering the original3328 // structure of the code, so we just assume it's not a ref here3329 // for now3330 return raw;3331 }3332 else {3333 return `${context.helperString(UNREF)}(${raw})`;3334 }3335 }3336 else if (type === "props" /* PROPS */) {3337 // use __props which is generated by compileScript so in ts mode3338 // it gets correct type3339 return `__props.${raw}`;3340 }3341 else if (type === "props-aliased" /* PROPS_ALIASED */) {3342 // prop with a different local alias (from defineProps() destructure)3343 return `__props.${bindingMetadata.__propsAliases[raw]}`;3344 }3345 }3346 else {3347 if (type && type.startsWith('setup')) {3348 // setup bindings in non-inline mode3349 return `$setup.${raw}`;3350 }3351 else if (type === "props-aliased" /* PROPS_ALIASED */) {3352 return `$props.${bindingMetadata.__propsAliases[raw]}`;3353 }3354 else if (type) {3355 return `$${type}.${raw}`;3356 }3357 }3358 // fallback to ctx3359 return `_ctx.${raw}`;3360 };3361 // fast path if expression is a simple identifier.3362 const rawExp = node.content;3363 // bail constant on parens (function invocation) and dot (member access)3364 const bailConstant = rawExp.indexOf(`(`) > -1 || rawExp.indexOf('.') > 0;3365 if (isSimpleIdentifier(rawExp)) {3366 const isScopeVarReference = context.identifiers[rawExp];3367 const isAllowedGlobal = shared.isGloballyWhitelisted(rawExp);3368 const isLiteral = isLiteralWhitelisted(rawExp);3369 if (!asParams && !isScopeVarReference && !isAllowedGlobal && !isLiteral) {3370 // const bindings exposed from setup can be skipped for patching but3371 // cannot be hoisted to module scope3372 if (bindingMetadata[node.content] === "setup-const" /* SETUP_CONST */) {3373 node.constType = 1 /* CAN_SKIP_PATCH */;3374 }3375 node.content = rewriteIdentifier(rawExp);3376 }3377 else if (!isScopeVarReference) {3378 if (isLiteral) {3379 node.constType = 3 /* CAN_STRINGIFY */;3380 }3381 else {3382 node.constType = 2 /* CAN_HOIST */;3383 }3384 }3385 return node;3386 }3387 let ast;3388 // exp needs to be parsed differently:3389 // 1. Multiple inline statements (v-on, with presence of `;`): parse as raw3390 // exp, but make sure to pad with spaces for consistent ranges3391 // 2. Expressions: wrap with parens (for e.g. object expressions)3392 // 3. Function arguments (v-for, v-slot): place in a function argument position3393 const source = asRawStatements3394 ? ` ${rawExp} `3395 : `(${rawExp})${asParams ? `=>{}` : ``}`;3396 try {3397 ast = parser.parse(source, {3398 plugins: context.expressionPlugins3399 }).program;3400 }3401 catch (e) {3402 context.onError(createCompilerError(44 /* X_INVALID_EXPRESSION */, node.loc, undefined, e.message));3403 return node;3404 }3405 const ids = [];3406 const parentStack = [];3407 const knownIds = Object.create(context.identifiers);3408 walkIdentifiers(ast, (node, parent, _, isReferenced, isLocal) => {3409 if (isStaticPropertyKey(node, parent)) {3410 return;3411 }3412 // v2 wrapped filter call3413 if (node.name.startsWith('_filter_')) {3414 return;3415 }3416 const needPrefix = isReferenced && canPrefix(node);3417 if (needPrefix && !isLocal) {3418 if (isStaticProperty(parent) && parent.shorthand) {3419 node.prefix = `${node.name}: `;3420 }3421 node.name = rewriteIdentifier(node.name, parent, node);3422 ids.push(node);3423 }3424 else {3425 // The identifier is considered constant unless it's pointing to a3426 // local scope variable (a v-for alias, or a v-slot prop)3427 if (!(needPrefix && isLocal) && !bailConstant) {3428 node.isConstant = true;3429 }3430 // also generate sub-expressions for other identifiers for better3431 // source map support. (except for property keys which are static)3432 ids.push(node);3433 }3434 }, true, // invoke on ALL identifiers3435 parentStack, knownIds);3436 // We break up the compound expression into an array of strings and sub3437 // expressions (for identifiers that have been prefixed). In codegen, if3438 // an ExpressionNode has the `.children` property, it will be used instead of3439 // `.content`.3440 const children = [];3441 ids.sort((a, b) => a.start - b.start);3442 ids.forEach((id, i) => {3443 // range is offset by -1 due to the wrapping parens when parsed3444 const start = id.start - 1;3445 const end = id.end - 1;3446 const last = ids[i - 1];3447 const leadingText = rawExp.slice(last ? last.end - 1 : 0, start);3448 if (leadingText.length || id.prefix) {3449 children.push(leadingText + (id.prefix || ``));3450 }3451 const source = rawExp.slice(start, end);3452 children.push(createSimpleExpression(id.name, false, {3453 source,3454 start: advancePositionWithClone(node.loc.start, source, start),3455 end: advancePositionWithClone(node.loc.start, source, end)3456 }, id.isConstant ? 3 /* CAN_STRINGIFY */ : 0 /* NOT_CONSTANT */));3457 if (i === ids.length - 1 && end < rawExp.length) {3458 children.push(rawExp.slice(end));3459 }3460 });3461 let ret;3462 if (children.length) {3463 ret = createCompoundExpression(children, node.loc);3464 }3465 else {3466 ret = node;3467 ret.constType = bailConstant3468 ? 0 /* NOT_CONSTANT */3469 : 3 /* CAN_STRINGIFY */;3470 }3471 ret.identifiers = Object.keys(knownIds);3472 return ret;3473}3474function canPrefix(id) {3475 // skip whitelisted globals3476 if (shared.isGloballyWhitelisted(id.name)) {3477 return false;3478 }3479 // special case for webpack compilation3480 if (id.name === 'require') {3481 return false;3482 }3483 return true;3484}3485function stringifyExpression(exp) {3486 if (shared.isString(exp)) {3487 return exp;3488 }3489 else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {3490 return exp.content;3491 }3492 else {3493 return exp.children3494 .map(stringifyExpression)3495 .join('');3496 }3497}3498const transformIf = createStructuralDirectiveTransform(/^(if|else|else-if)$/, (node, dir, context) => {3499 return processIf(node, dir, context, (ifNode, branch, isRoot) => {3500 // #1587: We need to dynamically increment the key based on the current3501 // node's sibling nodes, since chained v-if/else branches are3502 // rendered at the same depth3503 const siblings = context.parent.children;3504 let i = siblings.indexOf(ifNode);3505 let key = 0;3506 while (i-- >= 0) {3507 const sibling = siblings[i];3508 if (sibling && sibling.type === 9 /* IF */) {3509 key += sibling.branches.length;3510 }3511 }3512 // Exit callback. Complete the codegenNode when all children have been3513 // transformed.3514 return () => {3515 if (isRoot) {3516 ifNode.codegenNode = createCodegenNodeForBranch(branch, key, context);3517 }3518 else {3519 // attach this branch's codegen node to the v-if root.3520 const parentCondition = getParentCondition(ifNode.codegenNode);3521 parentCondition.alternate = createCodegenNodeForBranch(branch, key + ifNode.branches.length - 1, context);3522 }3523 };3524 });3525});3526// target-agnostic transform used for both Client and SSR3527function processIf(node, dir, context, processCodegen) {3528 if (dir.name !== 'else' &&3529 (!dir.exp || !dir.exp.content.trim())) {3530 const loc = dir.exp ? dir.exp.loc : node.loc;3531 context.onError(createCompilerError(28 /* X_V_IF_NO_EXPRESSION */, dir.loc));3532 dir.exp = createSimpleExpression(`true`, false, loc);3533 }3534 if (context.prefixIdentifiers && dir.exp) {3535 // dir.exp can only be simple expression because vIf transform is applied3536 // before expression transform.3537 dir.exp = processExpression(dir.exp, context);3538 }3539 if (dir.name === 'if') {3540 const branch = createIfBranch(node, dir);3541 const ifNode = {3542 type: 9 /* IF */,3543 loc: node.loc,3544 branches: [branch]3545 };3546 context.replaceNode(ifNode);3547 if (processCodegen) {3548 return processCodegen(ifNode, branch, true);3549 }3550 }3551 else {3552 // locate the adjacent v-if3553 const siblings = context.parent.children;3554 let i = siblings.indexOf(node);3555 while (i-- >= -1) {3556 const sibling = siblings[i];3557 if (sibling &&3558 sibling.type === 2 /* TEXT */ &&3559 !sibling.content.trim().length) {3560 context.removeNode(sibling);3561 continue;3562 }3563 if (sibling && sibling.type === 9 /* IF */) {3564 // Check if v-else was followed by v-else-if3565 if (dir.name === 'else-if' &&3566 sibling.branches[sibling.branches.length - 1].condition === undefined) {3567 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));3568 }3569 // move the node to the if node's branches3570 context.removeNode();3571 const branch = createIfBranch(node, dir);3572 // check if user is forcing same key on different branches3573 {3574 const key = branch.userKey;3575 if (key) {3576 sibling.branches.forEach(({ userKey }) => {3577 if (isSameKey(userKey, key)) {3578 context.onError(createCompilerError(29 /* X_V_IF_SAME_KEY */, branch.userKey.loc));3579 }3580 });3581 }3582 }3583 sibling.branches.push(branch);3584 const onExit = processCodegen && processCodegen(sibling, branch, false);3585 // since the branch was removed, it will not be traversed.3586 // make sure to traverse here.3587 traverseNode(branch, context);3588 // call on exit3589 if (onExit)3590 onExit();3591 // make sure to reset currentNode after traversal to indicate this3592 // node has been removed.3593 context.currentNode = null;3594 }3595 else {3596 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));3597 }3598 break;3599 }3600 }3601}3602function createIfBranch(node, dir) {3603 return {3604 type: 10 /* IF_BRANCH */,3605 loc: node.loc,3606 condition: dir.name === 'else' ? undefined : dir.exp,3607 children: node.tagType === 3 /* TEMPLATE */ && !findDir(node, 'for')3608 ? node.children3609 : [node],3610 userKey: findProp(node, `key`)3611 };3612}3613function createCodegenNodeForBranch(branch, keyIndex, context) {3614 if (branch.condition) {3615 return createConditionalExpression(branch.condition, createChildrenCodegenNode(branch, keyIndex, context), 3616 // make sure to pass in asBlock: true so that the comment node call3617 // closes the current block.3618 createCallExpression(context.helper(CREATE_COMMENT), [3619 '""',3620 'true'3621 ]));3622 }3623 else {3624 return createChildrenCodegenNode(branch, keyIndex, context);3625 }3626}3627function createChildrenCodegenNode(branch, keyIndex, context) {3628 const { helper } = context;3629 const keyProperty = createObjectProperty(`key`, createSimpleExpression(`${keyIndex}`, false, locStub, 2 /* CAN_HOIST */));3630 const { children } = branch;3631 const firstChild = children[0];3632 const needFragmentWrapper = children.length !== 1 || firstChild.type !== 1 /* ELEMENT */;3633 if (needFragmentWrapper) {3634 if (children.length === 1 && firstChild.type === 11 /* FOR */) {3635 // optimize away nested fragments when child is a ForNode3636 const vnodeCall = firstChild.codegenNode;3637 injectProp(vnodeCall, keyProperty, context);3638 return vnodeCall;3639 }3640 else {3641 let patchFlag = 64 /* STABLE_FRAGMENT */;3642 shared.PatchFlagNames[64 /* STABLE_FRAGMENT */];3643 return createVNodeCall(context, helper(FRAGMENT), createObjectExpression([keyProperty]), children, patchFlag + (``), undefined, undefined, true, false, false /* isComponent */, branch.loc);3644 }3645 }3646 else {3647 const ret = firstChild.codegenNode;3648 const vnodeCall = getMemoedVNodeCall(ret);3649 // Change createVNode to createBlock.3650 if (vnodeCall.type === 13 /* VNODE_CALL */) {3651 makeBlock(vnodeCall, context);3652 }3653 // inject branch key3654 injectProp(vnodeCall, keyProperty, context);3655 return ret;3656 }3657}3658function isSameKey(a, b) {3659 if (!a || a.type !== b.type) {3660 return false;3661 }3662 if (a.type === 6 /* ATTRIBUTE */) {3663 if (a.value.content !== b.value.content) {3664 return false;3665 }3666 }3667 else {3668 // directive3669 const exp = a.exp;3670 const branchExp = b.exp;3671 if (exp.type !== branchExp.type) {3672 return false;3673 }3674 if (exp.type !== 4 /* SIMPLE_EXPRESSION */ ||3675 exp.isStatic !== branchExp.isStatic ||3676 exp.content !== branchExp.content) {3677 return false;3678 }3679 }3680 return true;3681}3682function getParentCondition(node) {3683 while (true) {3684 if (node.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3685 if (node.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3686 node = node.alternate;3687 }3688 else {3689 return node;3690 }3691 }3692 else if (node.type === 20 /* JS_CACHE_EXPRESSION */) {3693 node = node.value;3694 }3695 }3696}3697const transformFor = createStructuralDirectiveTransform('for', (node, dir, context) => {3698 const { helper, removeHelper } = context;3699 return processFor(node, dir, context, forNode => {3700 // create the loop render function expression now, and add the3701 // iterator on exit after all children have been traversed3702 const renderExp = createCallExpression(helper(RENDER_LIST), [3703 forNode.source3704 ]);3705 const memo = findDir(node, 'memo');3706 const keyProp = findProp(node, `key`);3707 const keyExp = keyProp &&3708 (keyProp.type === 6 /* ATTRIBUTE */3709 ? createSimpleExpression(keyProp.value.content, true)3710 : keyProp.exp);3711 const keyProperty = keyProp ? createObjectProperty(`key`, keyExp) : null;3712 if (context.prefixIdentifiers &&3713 keyProperty &&3714 keyProp.type !== 6 /* ATTRIBUTE */) {3715 // #2085 process :key expression needs to be processed in order for it3716 // to behave consistently for <template v-for> and <div v-for>.3717 // In the case of `<template v-for>`, the node is discarded and never3718 // traversed so its key expression won't be processed by the normal3719 // transforms.3720 keyProperty.value = processExpression(keyProperty.value, context);3721 }3722 const isStableFragment = forNode.source.type === 4 /* SIMPLE_EXPRESSION */ &&3723 forNode.source.constType > 0 /* NOT_CONSTANT */;3724 const fragmentFlag = isStableFragment3725 ? 64 /* STABLE_FRAGMENT */3726 : keyProp3727 ? 128 /* KEYED_FRAGMENT */3728 : 256 /* UNKEYED_FRAGMENT */;3729 forNode.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, renderExp, fragmentFlag +3730 (``), undefined, undefined, true /* isBlock */, !isStableFragment /* disableTracking */, false /* isComponent */, node.loc);3731 return () => {3732 // finish the codegen now that all children have been traversed3733 let childBlock;3734 const isTemplate = isTemplateNode(node);3735 const { children } = forNode;3736 // check <template v-for> key placement3737 if (isTemplate) {3738 node.children.some(c => {3739 if (c.type === 1 /* ELEMENT */) {3740 const key = findProp(c, 'key');3741 if (key) {3742 context.onError(createCompilerError(33 /* X_V_FOR_TEMPLATE_KEY_PLACEMENT */, key.loc));3743 return true;3744 }3745 }3746 });3747 }3748 const needFragmentWrapper = children.length !== 1 || children[0].type !== 1 /* ELEMENT */;3749 const slotOutlet = isSlotOutlet(node)3750 ? node3751 : isTemplate &&3752 node.children.length === 1 &&3753 isSlotOutlet(node.children[0])3754 ? node.children[0] // api-extractor somehow fails to infer this3755 : null;3756 if (slotOutlet) {3757 // <slot v-for="..."> or <template v-for="..."><slot/></template>3758 childBlock = slotOutlet.codegenNode;3759 if (isTemplate && keyProperty) {3760 // <template v-for="..." :key="..."><slot/></template>3761 // we need to inject the key to the renderSlot() call.3762 // the props for renderSlot is passed as the 3rd argument.3763 injectProp(childBlock, keyProperty, context);3764 }3765 }3766 else if (needFragmentWrapper) {3767 // <template v-for="..."> with text or multi-elements3768 // should generate a fragment block for each loop3769 childBlock = createVNodeCall(context, helper(FRAGMENT), keyProperty ? createObjectExpression([keyProperty]) : undefined, node.children, 64 /* STABLE_FRAGMENT */ +3770 (``), undefined, undefined, true, undefined, false /* isComponent */);3771 }3772 else {3773 // Normal element v-for. Directly use the child's codegenNode3774 // but mark it as a block.3775 childBlock = children[0]3776 .codegenNode;3777 if (isTemplate && keyProperty) {3778 injectProp(childBlock, keyProperty, context);3779 }3780 if (childBlock.isBlock !== !isStableFragment) {3781 if (childBlock.isBlock) {3782 // switch from block to vnode3783 removeHelper(OPEN_BLOCK);3784 removeHelper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3785 }3786 else {3787 // switch from vnode to block3788 removeHelper(getVNodeHelper(context.inSSR, childBlock.isComponent));3789 }3790 }3791 childBlock.isBlock = !isStableFragment;3792 if (childBlock.isBlock) {3793 helper(OPEN_BLOCK);3794 helper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3795 }3796 else {3797 helper(getVNodeHelper(context.inSSR, childBlock.isComponent));3798 }3799 }3800 if (memo) {3801 const loop = createFunctionExpression(createForLoopParams(forNode.parseResult, [3802 createSimpleExpression(`_cached`)3803 ]));3804 loop.body = createBlockStatement([3805 createCompoundExpression([`const _memo = (`, memo.exp, `)`]),3806 createCompoundExpression([3807 `if (_cached`,3808 ...(keyExp ? [` && _cached.key === `, keyExp] : []),3809 ` && ${context.helperString(IS_MEMO_SAME)}(_cached, _memo)) return _cached`3810 ]),3811 createCompoundExpression([`const _item = `, childBlock]),3812 createSimpleExpression(`_item.memo = _memo`),3813 createSimpleExpression(`return _item`)3814 ]);3815 renderExp.arguments.push(loop, createSimpleExpression(`_cache`), createSimpleExpression(String(context.cached++)));3816 }3817 else {3818 renderExp.arguments.push(createFunctionExpression(createForLoopParams(forNode.parseResult), childBlock, true /* force newline */));3819 }3820 };3821 });3822});3823// target-agnostic transform used for both Client and SSR3824function processFor(node, dir, context, processCodegen) {3825 if (!dir.exp) {3826 context.onError(createCompilerError(31 /* X_V_FOR_NO_EXPRESSION */, dir.loc));3827 return;3828 }3829 const parseResult = parseForExpression(3830 // can only be simple expression because vFor transform is applied3831 // before expression transform.3832 dir.exp, context);3833 if (!parseResult) {3834 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));3835 return;3836 }3837 const { addIdentifiers, removeIdentifiers, scopes } = context;3838 const { source, value, key, index } = parseResult;3839 const forNode = {3840 type: 11 /* FOR */,3841 loc: dir.loc,3842 source,3843 valueAlias: value,3844 keyAlias: key,3845 objectIndexAlias: index,3846 parseResult,3847 children: isTemplateNode(node) ? node.children : [node]3848 };3849 context.replaceNode(forNode);3850 // bookkeeping3851 scopes.vFor++;3852 if (context.prefixIdentifiers) {3853 // scope management3854 // inject identifiers to context3855 value && addIdentifiers(value);3856 key && addIdentifiers(key);3857 index && addIdentifiers(index);3858 }3859 const onExit = processCodegen && processCodegen(forNode);3860 return () => {3861 scopes.vFor--;3862 if (context.prefixIdentifiers) {3863 value && removeIdentifiers(value);3864 key && removeIdentifiers(key);3865 index && removeIdentifiers(index);3866 }3867 if (onExit)3868 onExit();3869 };3870}3871const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;3872// This regex doesn't cover the case if key or index aliases have destructuring,3873// but those do not make sense in the first place, so this works in practice.3874const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;3875const stripParensRE = /^\(|\)$/g;3876function parseForExpression(input, context) {3877 const loc = input.loc;3878 const exp = input.content;3879 const inMatch = exp.match(forAliasRE);3880 if (!inMatch)3881 return;3882 const [, LHS, RHS] = inMatch;3883 const result = {3884 source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),3885 value: undefined,3886 key: undefined,3887 index: undefined3888 };3889 if (context.prefixIdentifiers) {3890 result.source = processExpression(result.source, context);3891 }3892 let valueContent = LHS.trim().replace(stripParensRE, '').trim();3893 const trimmedOffset = LHS.indexOf(valueContent);3894 const iteratorMatch = valueContent.match(forIteratorRE);3895 if (iteratorMatch) {3896 valueContent = valueContent.replace(forIteratorRE, '').trim();3897 const keyContent = iteratorMatch[1].trim();3898 let keyOffset;3899 if (keyContent) {3900 keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);3901 result.key = createAliasExpression(loc, keyContent, keyOffset);3902 if (context.prefixIdentifiers) {3903 result.key = processExpression(result.key, context, true);3904 }3905 }3906 if (iteratorMatch[2]) {3907 const indexContent = iteratorMatch[2].trim();3908 if (indexContent) {3909 result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key3910 ? keyOffset + keyContent.length3911 : trimmedOffset + valueContent.length));3912 if (context.prefixIdentifiers) {3913 result.index = processExpression(result.index, context, true);3914 }3915 }3916 }3917 }3918 if (valueContent) {3919 result.value = createAliasExpression(loc, valueContent, trimmedOffset);3920 if (context.prefixIdentifiers) {3921 result.value = processExpression(result.value, context, true);3922 }3923 }3924 return result;3925}3926function createAliasExpression(range, content, offset) {3927 return createSimpleExpression(content, false, getInnerRange(range, offset, content.length));3928}3929function createForLoopParams({ value, key, index }, memoArgs = []) {3930 return createParamsList([value, key, index, ...memoArgs]);3931}3932function createParamsList(args) {3933 let i = args.length;3934 while (i--) {3935 if (args[i])3936 break;3937 }3938 return args3939 .slice(0, i + 1)3940 .map((arg, i) => arg || createSimpleExpression(`_`.repeat(i + 1), false));3941}3942const defaultFallback = createSimpleExpression(`undefined`, false);3943// A NodeTransform that:3944// 1. Tracks scope identifiers for scoped slots so that they don't get prefixed3945// by transformExpression. This is only applied in non-browser builds with3946// { prefixIdentifiers: true }.3947// 2. Track v-slot depths so that we know a slot is inside another slot.3948// Note the exit callback is executed before buildSlots() on the same node,3949// so only nested slots see positive numbers.3950const trackSlotScopes = (node, context) => {3951 if (node.type === 1 /* ELEMENT */ &&3952 (node.tagType === 1 /* COMPONENT */ ||3953 node.tagType === 3 /* TEMPLATE */)) {3954 // We are only checking non-empty v-slot here3955 // since we only care about slots that introduce scope variables.3956 const vSlot = findDir(node, 'slot');3957 if (vSlot) {3958 const slotProps = vSlot.exp;3959 if (context.prefixIdentifiers) {3960 slotProps && context.addIdentifiers(slotProps);3961 }3962 context.scopes.vSlot++;3963 return () => {3964 if (context.prefixIdentifiers) {3965 slotProps && context.removeIdentifiers(slotProps);3966 }3967 context.scopes.vSlot--;3968 };3969 }3970 }3971};3972// A NodeTransform that tracks scope identifiers for scoped slots with v-for.3973// This transform is only applied in non-browser builds with { prefixIdentifiers: true }3974const trackVForSlotScopes = (node, context) => {3975 let vFor;3976 if (isTemplateNode(node) &&3977 node.props.some(isVSlot) &&3978 (vFor = findDir(node, 'for'))) {3979 const result = (vFor.parseResult = parseForExpression(vFor.exp, context));3980 if (result) {3981 const { value, key, index } = result;3982 const { addIdentifiers, removeIdentifiers } = context;3983 value && addIdentifiers(value);3984 key && addIdentifiers(key);3985 index && addIdentifiers(index);3986 return () => {3987 value && removeIdentifiers(value);3988 key && removeIdentifiers(key);3989 index && removeIdentifiers(index);3990 };3991 }3992 }3993};3994const buildClientSlotFn = (props, children, loc) => createFunctionExpression(props, children, false /* newline */, true /* isSlot */, children.length ? children[0].loc : loc);3995// Instead of being a DirectiveTransform, v-slot processing is called during3996// transformElement to build the slots object for a component.3997function buildSlots(node, context, buildSlotFn = buildClientSlotFn) {3998 context.helper(WITH_CTX);3999 const { children, loc } = node;4000 const slotsProperties = [];4001 const dynamicSlots = [];4002 // If the slot is inside a v-for or another v-slot, force it to be dynamic4003 // since it likely uses a scope variable.4004 let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0;4005 // with `prefixIdentifiers: true`, this can be further optimized to make4006 // it dynamic only when the slot actually uses the scope variables.4007 if (!context.ssr && context.prefixIdentifiers) {4008 hasDynamicSlots = hasScopeRef(node, context.identifiers);4009 }4010 // 1. Check for slot with slotProps on component itself.4011 // <Comp v-slot="{ prop }"/>4012 const onComponentSlot = findDir(node, 'slot', true);4013 if (onComponentSlot) {4014 const { arg, exp } = onComponentSlot;4015 if (arg && !isStaticExp(arg)) {4016 hasDynamicSlots = true;4017 }4018 slotsProperties.push(createObjectProperty(arg || createSimpleExpression('default', true), buildSlotFn(exp, children, loc)));4019 }4020 // 2. Iterate through children and check for template slots4021 // <template v-slot:foo="{ prop }">4022 let hasTemplateSlots = false;4023 let hasNamedDefaultSlot = false;4024 const implicitDefaultChildren = [];4025 const seenSlotNames = new Set();4026 for (let i = 0; i < children.length; i++) {4027 const slotElement = children[i];4028 let slotDir;4029 if (!isTemplateNode(slotElement) ||4030 !(slotDir = findDir(slotElement, 'slot', true))) {4031 // not a <template v-slot>, skip.4032 if (slotElement.type !== 3 /* COMMENT */) {4033 implicitDefaultChildren.push(slotElement);4034 }4035 continue;4036 }4037 if (onComponentSlot) {4038 // already has on-component slot - this is incorrect usage.4039 context.onError(createCompilerError(37 /* X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc));4040 break;4041 }4042 hasTemplateSlots = true;4043 const { children: slotChildren, loc: slotLoc } = slotElement;4044 const { arg: slotName = createSimpleExpression(`default`, true), exp: slotProps, loc: dirLoc } = slotDir;4045 // check if name is dynamic.4046 let staticSlotName;4047 if (isStaticExp(slotName)) {4048 staticSlotName = slotName ? slotName.content : `default`;4049 }4050 else {4051 hasDynamicSlots = true;4052 }4053 const slotFunction = buildSlotFn(slotProps, slotChildren, slotLoc);4054 // check if this slot is conditional (v-if/v-for)4055 let vIf;4056 let vElse;4057 let vFor;4058 if ((vIf = findDir(slotElement, 'if'))) {4059 hasDynamicSlots = true;4060 dynamicSlots.push(createConditionalExpression(vIf.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback));4061 }4062 else if ((vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))) {4063 // find adjacent v-if4064 let j = i;4065 let prev;4066 while (j--) {4067 prev = children[j];4068 if (prev.type !== 3 /* COMMENT */) {4069 break;4070 }4071 }4072 if (prev && isTemplateNode(prev) && findDir(prev, 'if')) {4073 // remove node4074 children.splice(i, 1);4075 i--;4076 // attach this slot to previous conditional4077 let conditional = dynamicSlots[dynamicSlots.length - 1];4078 while (conditional.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {4079 conditional = conditional.alternate;4080 }4081 conditional.alternate = vElse.exp4082 ? createConditionalExpression(vElse.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback)4083 : buildDynamicSlot(slotName, slotFunction);4084 }4085 else {4086 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, vElse.loc));4087 }4088 }4089 else if ((vFor = findDir(slotElement, 'for'))) {4090 hasDynamicSlots = true;4091 const parseResult = vFor.parseResult ||4092 parseForExpression(vFor.exp, context);4093 if (parseResult) {4094 // Render the dynamic slots as an array and add it to the createSlot()4095 // args. The runtime knows how to handle it appropriately.4096 dynamicSlots.push(createCallExpression(context.helper(RENDER_LIST), [4097 parseResult.source,4098 createFunctionExpression(createForLoopParams(parseResult), buildDynamicSlot(slotName, slotFunction), true /* force newline */)4099 ]));4100 }4101 else {4102 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc));4103 }4104 }4105 else {4106 // check duplicate static names4107 if (staticSlotName) {4108 if (seenSlotNames.has(staticSlotName)) {4109 context.onError(createCompilerError(38 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc));4110 continue;4111 }4112 seenSlotNames.add(staticSlotName);4113 if (staticSlotName === 'default') {4114 hasNamedDefaultSlot = true;4115 }4116 }4117 slotsProperties.push(createObjectProperty(slotName, slotFunction));4118 }4119 }4120 if (!onComponentSlot) {4121 const buildDefaultSlotProperty = (props, children) => {4122 const fn = buildSlotFn(props, children, loc);4123 if (context.compatConfig) {4124 fn.isNonScopedSlot = true;4125 }4126 return createObjectProperty(`default`, fn);4127 };4128 if (!hasTemplateSlots) {4129 // implicit default slot (on component)4130 slotsProperties.push(buildDefaultSlotProperty(undefined, children));4131 }4132 else if (implicitDefaultChildren.length &&4133 // #37664134 // with whitespace: 'preserve', whitespaces between slots will end up in4135 // implicitDefaultChildren. Ignore if all implicit children are whitespaces.4136 implicitDefaultChildren.some(node => isNonWhitespaceContent(node))) {4137 // implicit default slot (mixed with named slots)4138 if (hasNamedDefaultSlot) {4139 context.onError(createCompilerError(39 /* X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN */, implicitDefaultChildren[0].loc));4140 }4141 else {4142 slotsProperties.push(buildDefaultSlotProperty(undefined, implicitDefaultChildren));4143 }4144 }4145 }4146 const slotFlag = hasDynamicSlots4147 ? 2 /* DYNAMIC */4148 : hasForwardedSlots(node.children)4149 ? 3 /* FORWARDED */4150 : 1 /* STABLE */;4151 let slots = createObjectExpression(slotsProperties.concat(createObjectProperty(`_`, 4152 // 2 = compiled but dynamic = can skip normalization, but must run diff4153 // 1 = compiled and static = can skip normalization AND diff as optimized4154 createSimpleExpression(slotFlag + (``), false))), loc);4155 if (dynamicSlots.length) {4156 slots = createCallExpression(context.helper(CREATE_SLOTS), [4157 slots,4158 createArrayExpression(dynamicSlots)4159 ]);4160 }4161 return {4162 slots,4163 hasDynamicSlots4164 };4165}4166function buildDynamicSlot(name, fn) {4167 return createObjectExpression([4168 createObjectProperty(`name`, name),4169 createObjectProperty(`fn`, fn)4170 ]);4171}4172function hasForwardedSlots(children) {4173 for (let i = 0; i < children.length; i++) {4174 const child = children[i];4175 switch (child.type) {4176 case 1 /* ELEMENT */:4177 if (child.tagType === 2 /* SLOT */ ||4178 hasForwardedSlots(child.children)) {4179 return true;4180 }4181 break;4182 case 9 /* IF */:4183 if (hasForwardedSlots(child.branches))4184 return true;4185 break;4186 case 10 /* IF_BRANCH */:4187 case 11 /* FOR */:4188 if (hasForwardedSlots(child.children))4189 return true;4190 break;4191 }4192 }4193 return false;4194}4195function isNonWhitespaceContent(node) {4196 if (node.type !== 2 /* TEXT */ && node.type !== 12 /* TEXT_CALL */)4197 return true;4198 return node.type === 2 /* TEXT */4199 ? !!node.content.trim()4200 : isNonWhitespaceContent(node.content);4201}4202// some directive transforms (e.g. v-model) may return a symbol for runtime4203// import, which should be used instead of a resolveDirective call.4204const directiveImportMap = new WeakMap();4205// generate a JavaScript AST for this element's codegen4206const transformElement = (node, context) => {4207 // perform the work on exit, after all child expressions have been4208 // processed and merged.4209 return function postTransformElement() {4210 node = context.currentNode;4211 if (!(node.type === 1 /* ELEMENT */ &&4212 (node.tagType === 0 /* ELEMENT */ ||4213 node.tagType === 1 /* COMPONENT */))) {4214 return;4215 }4216 const { tag, props } = node;4217 const isComponent = node.tagType === 1 /* COMPONENT */;4218 // The goal of the transform is to create a codegenNode implementing the4219 // VNodeCall interface.4220 let vnodeTag = isComponent4221 ? resolveComponentType(node, context)4222 : `"${tag}"`;4223 const isDynamicComponent = shared.isObject(vnodeTag) && vnodeTag.callee === RESOLVE_DYNAMIC_COMPONENT;4224 let vnodeProps;4225 let vnodeChildren;4226 let vnodePatchFlag;4227 let patchFlag = 0;4228 let vnodeDynamicProps;4229 let dynamicPropNames;4230 let vnodeDirectives;4231 let shouldUseBlock = 4232 // dynamic component may resolve to plain elements4233 isDynamicComponent ||4234 vnodeTag === TELEPORT ||4235 vnodeTag === SUSPENSE ||4236 (!isComponent &&4237 // <svg> and <foreignObject> must be forced into blocks so that block4238 // updates inside get proper isSVG flag at runtime. (#639, #643)4239 // This is technically web-specific, but splitting the logic out of core4240 // leads to too much unnecessary complexity.4241 (tag === 'svg' || tag === 'foreignObject'));4242 // props4243 if (props.length > 0) {4244 const propsBuildResult = buildProps(node, context);4245 vnodeProps = propsBuildResult.props;4246 patchFlag = propsBuildResult.patchFlag;4247 dynamicPropNames = propsBuildResult.dynamicPropNames;4248 const directives = propsBuildResult.directives;4249 vnodeDirectives =4250 directives && directives.length4251 ? createArrayExpression(directives.map(dir => buildDirectiveArgs(dir, context)))4252 : undefined;4253 if (propsBuildResult.shouldUseBlock) {4254 shouldUseBlock = true;4255 }4256 }4257 // children4258 if (node.children.length > 0) {4259 if (vnodeTag === KEEP_ALIVE) {4260 // Although a built-in component, we compile KeepAlive with raw children4261 // instead of slot functions so that it can be used inside Transition4262 // or other Transition-wrapping HOCs.4263 // To ensure correct updates with block optimizations, we need to:4264 // 1. Force keep-alive into a block. This avoids its children being4265 // collected by a parent block.4266 shouldUseBlock = true;4267 // 2. Force keep-alive to always be updated, since it uses raw children.4268 patchFlag |= 1024 /* DYNAMIC_SLOTS */;4269 }4270 const shouldBuildAsSlots = isComponent &&4271 // Teleport is not a real component and has dedicated runtime handling4272 vnodeTag !== TELEPORT &&4273 // explained above.4274 vnodeTag !== KEEP_ALIVE;4275 if (shouldBuildAsSlots) {4276 const { slots, hasDynamicSlots } = buildSlots(node, context);4277 vnodeChildren = slots;4278 if (hasDynamicSlots) {4279 patchFlag |= 1024 /* DYNAMIC_SLOTS */;4280 }4281 }4282 else if (node.children.length === 1 && vnodeTag !== TELEPORT) {4283 const child = node.children[0];4284 const type = child.type;4285 // check for dynamic text children4286 const hasDynamicTextChild = type === 5 /* INTERPOLATION */ ||4287 type === 8 /* COMPOUND_EXPRESSION */;4288 if (hasDynamicTextChild &&4289 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {4290 patchFlag |= 1 /* TEXT */;4291 }4292 // pass directly if the only child is a text node4293 // (plain / interpolation / expression)4294 if (hasDynamicTextChild || type === 2 /* TEXT */) {4295 vnodeChildren = child;4296 }4297 else {4298 vnodeChildren = node.children;4299 }4300 }4301 else {4302 vnodeChildren = node.children;4303 }4304 }4305 // patchFlag & dynamicPropNames4306 if (patchFlag !== 0) {4307 {4308 vnodePatchFlag = String(patchFlag);4309 }4310 if (dynamicPropNames && dynamicPropNames.length) {4311 vnodeDynamicProps = stringifyDynamicPropNames(dynamicPropNames);4312 }4313 }4314 node.codegenNode = createVNodeCall(context, vnodeTag, vnodeProps, vnodeChildren, vnodePatchFlag, vnodeDynamicProps, vnodeDirectives, !!shouldUseBlock, false /* disableTracking */, isComponent, node.loc);4315 };4316};4317function resolveComponentType(node, context, ssr = false) {4318 let { tag } = node;4319 // 1. dynamic component4320 const isExplicitDynamic = isComponentTag(tag);4321 const isProp = findProp(node, 'is');4322 if (isProp) {4323 if (isExplicitDynamic ||4324 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) {4325 const exp = isProp.type === 6 /* ATTRIBUTE */4326 ? isProp.value && createSimpleExpression(isProp.value.content, true)4327 : isProp.exp;4328 if (exp) {4329 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [4330 exp4331 ]);4332 }4333 }4334 else if (isProp.type === 6 /* ATTRIBUTE */ &&4335 isProp.value.content.startsWith('vue:')) {4336 // <button is="vue:xxx">4337 // if not <component>, only is value that starts with "vue:" will be4338 // treated as component by the parse phase and reach here, unless it's4339 // compat mode where all is values are considered components4340 tag = isProp.value.content.slice(4);4341 }4342 }4343 // 1.5 v-is (TODO: Deprecate)4344 const isDir = !isExplicitDynamic && findDir(node, 'is');4345 if (isDir && isDir.exp) {4346 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [4347 isDir.exp4348 ]);4349 }4350 // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)4351 const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);4352 if (builtIn) {4353 // built-ins are simply fallthroughs / have special handling during ssr4354 // so we don't need to import their runtime equivalents4355 if (!ssr)4356 context.helper(builtIn);4357 return builtIn;4358 }4359 // 3. user component (from setup bindings)4360 // this is skipped in browser build since browser builds do not perform4361 // binding analysis.4362 {4363 const fromSetup = resolveSetupReference(tag, context);4364 if (fromSetup) {4365 return fromSetup;4366 }4367 const dotIndex = tag.indexOf('.');4368 if (dotIndex > 0) {4369 const ns = resolveSetupReference(tag.slice(0, dotIndex), context);4370 if (ns) {4371 return ns + tag.slice(dotIndex);4372 }4373 }4374 }4375 // 4. Self referencing component (inferred from filename)4376 if (context.selfName &&4377 shared.capitalize(shared.camelize(tag)) === context.selfName) {4378 context.helper(RESOLVE_COMPONENT);4379 // codegen.ts has special check for __self postfix when generating4380 // component imports, which will pass additional `maybeSelfReference` flag4381 // to `resolveComponent`.4382 context.components.add(tag + `__self`);4383 return toValidAssetId(tag, `component`);4384 }4385 // 5. user component (resolve)4386 context.helper(RESOLVE_COMPONENT);4387 context.components.add(tag);4388 return toValidAssetId(tag, `component`);4389}4390function resolveSetupReference(name, context) {4391 const bindings = context.bindingMetadata;4392 if (!bindings || bindings.__isScriptSetup === false) {4393 return;4394 }4395 const camelName = shared.camelize(name);4396 const PascalName = shared.capitalize(camelName);4397 const checkType = (type) => {4398 if (bindings[name] === type) {4399 return name;4400 }4401 if (bindings[camelName] === type) {4402 return camelName;4403 }4404 if (bindings[PascalName] === type) {4405 return PascalName;4406 }4407 };4408 const fromConst = checkType("setup-const" /* SETUP_CONST */);4409 if (fromConst) {4410 return context.inline4411 ? // in inline mode, const setup bindings (e.g. imports) can be used as-is4412 fromConst4413 : `$setup[${JSON.stringify(fromConst)}]`;4414 }4415 const fromMaybeRef = checkType("setup-let" /* SETUP_LET */) ||4416 checkType("setup-ref" /* SETUP_REF */) ||4417 checkType("setup-maybe-ref" /* SETUP_MAYBE_REF */);4418 if (fromMaybeRef) {4419 return context.inline4420 ? // setup scope bindings that may be refs need to be unrefed4421 `${context.helperString(UNREF)}(${fromMaybeRef})`4422 : `$setup[${JSON.stringify(fromMaybeRef)}]`;4423 }4424}4425function buildProps(node, context, props = node.props, ssr = false) {4426 const { tag, loc: elementLoc, children } = node;4427 const isComponent = node.tagType === 1 /* COMPONENT */;4428 let properties = [];4429 const mergeArgs = [];4430 const runtimeDirectives = [];4431 const hasChildren = children.length > 0;4432 let shouldUseBlock = false;4433 // patchFlag analysis4434 let patchFlag = 0;4435 let hasRef = false;4436 let hasClassBinding = false;4437 let hasStyleBinding = false;4438 let hasHydrationEventBinding = false;4439 let hasDynamicKeys = false;4440 let hasVnodeHook = false;4441 const dynamicPropNames = [];4442 const analyzePatchFlag = ({ key, value }) => {4443 if (isStaticExp(key)) {4444 const name = key.content;4445 const isEventHandler = shared.isOn(name);4446 if (!isComponent &&4447 isEventHandler &&4448 // omit the flag for click handlers because hydration gives click4449 // dedicated fast path.4450 name.toLowerCase() !== 'onclick' &&4451 // omit v-model handlers4452 name !== 'onUpdate:modelValue' &&4453 // omit onVnodeXXX hooks4454 !shared.isReservedProp(name)) {4455 hasHydrationEventBinding = true;4456 }4457 if (isEventHandler && shared.isReservedProp(name)) {4458 hasVnodeHook = true;4459 }4460 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||4461 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||4462 value.type === 8 /* COMPOUND_EXPRESSION */) &&4463 getConstantType(value, context) > 0)) {4464 // skip if the prop is a cached handler or has constant value4465 return;4466 }4467 if (name === 'ref') {4468 hasRef = true;4469 }4470 else if (name === 'class') {4471 hasClassBinding = true;4472 }4473 else if (name === 'style') {4474 hasStyleBinding = true;4475 }4476 else if (name !== 'key' && !dynamicPropNames.includes(name)) {4477 dynamicPropNames.push(name);4478 }4479 // treat the dynamic class and style binding of the component as dynamic props4480 if (isComponent &&4481 (name === 'class' || name === 'style') &&4482 !dynamicPropNames.includes(name)) {4483 dynamicPropNames.push(name);4484 }4485 }4486 else {4487 hasDynamicKeys = true;4488 }4489 };4490 for (let i = 0; i < props.length; i++) {4491 // static attribute4492 const prop = props[i];4493 if (prop.type === 6 /* ATTRIBUTE */) {4494 const { loc, name, value } = prop;4495 let isStatic = true;4496 if (name === 'ref') {4497 hasRef = true;4498 if (context.scopes.vFor > 0) {4499 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));4500 }4501 // in inline mode there is no setupState object, so we can't use string4502 // keys to set the ref. Instead, we need to transform it to pass the4503 // actual ref instead.4504 if (value &&4505 context.inline &&4506 context.bindingMetadata[value.content]) {4507 isStatic = false;4508 properties.push(createObjectProperty(createSimpleExpression('ref_key', true), createSimpleExpression(value.content, true, value.loc)));4509 }4510 }4511 // skip is on <component>, or is="vue:xxx"4512 if (name === 'is' &&4513 (isComponentTag(tag) ||4514 (value && value.content.startsWith('vue:')) ||4515 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) {4516 continue;4517 }4518 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));4519 }4520 else {4521 // directives4522 const { name, arg, exp, loc } = prop;4523 const isVBind = name === 'bind';4524 const isVOn = name === 'on';4525 // skip v-slot - it is handled by its dedicated transform.4526 if (name === 'slot') {4527 if (!isComponent) {4528 context.onError(createCompilerError(40 /* X_V_SLOT_MISPLACED */, loc));4529 }4530 continue;4531 }4532 // skip v-once/v-memo - they are handled by dedicated transforms.4533 if (name === 'once' || name === 'memo') {4534 continue;4535 }4536 // skip v-is and :is on <component>4537 if (name === 'is' ||4538 (isVBind &&4539 isStaticArgOf(arg, 'is') &&4540 (isComponentTag(tag) ||4541 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) {4542 continue;4543 }4544 // skip v-on in SSR compilation4545 if (isVOn && ssr) {4546 continue;4547 }4548 if (4549 // #938: elements with dynamic keys should be forced into blocks4550 (isVBind && isStaticArgOf(arg, 'key')) ||4551 // inline before-update hooks need to force block so that it is invoked4552 // before children4553 (isVOn && hasChildren && isStaticArgOf(arg, 'vue:before-update'))) {4554 shouldUseBlock = true;4555 }4556 if (isVBind && isStaticArgOf(arg, 'ref') && context.scopes.vFor > 0) {4557 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));4558 }4559 // special case for v-bind and v-on with no argument4560 if (!arg && (isVBind || isVOn)) {4561 hasDynamicKeys = true;4562 if (exp) {4563 if (properties.length) {4564 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));4565 properties = [];4566 }4567 if (isVBind) {4568 {4569 if (isCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context)) {4570 mergeArgs.unshift(exp);4571 continue;4572 }4573 }4574 mergeArgs.push(exp);4575 }4576 else {4577 // v-on="obj" -> toHandlers(obj)4578 mergeArgs.push({4579 type: 14 /* JS_CALL_EXPRESSION */,4580 loc,4581 callee: context.helper(TO_HANDLERS),4582 arguments: [exp]4583 });4584 }4585 }4586 else {4587 context.onError(createCompilerError(isVBind4588 ? 34 /* X_V_BIND_NO_EXPRESSION */4589 : 35 /* X_V_ON_NO_EXPRESSION */, loc));4590 }4591 continue;4592 }4593 const directiveTransform = context.directiveTransforms[name];4594 if (directiveTransform) {4595 // has built-in directive transform.4596 const { props, needRuntime } = directiveTransform(prop, node, context);4597 !ssr && props.forEach(analyzePatchFlag);4598 properties.push(...props);4599 if (needRuntime) {4600 runtimeDirectives.push(prop);4601 if (shared.isSymbol(needRuntime)) {4602 directiveImportMap.set(prop, needRuntime);4603 }4604 }4605 }4606 else {4607 // no built-in transform, this is a user custom directive.4608 runtimeDirectives.push(prop);4609 // custom dirs may use beforeUpdate so they need to force blocks4610 // to ensure before-update gets called before children update4611 if (hasChildren) {4612 shouldUseBlock = true;4613 }4614 }4615 }4616 }4617 let propsExpression = undefined;4618 // has v-bind="object" or v-on="object", wrap with mergeProps4619 if (mergeArgs.length) {4620 if (properties.length) {4621 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));4622 }4623 if (mergeArgs.length > 1) {4624 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);4625 }4626 else {4627 // single v-bind with nothing else - no need for a mergeProps call4628 propsExpression = mergeArgs[0];4629 }4630 }4631 else if (properties.length) {4632 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);4633 }4634 // patchFlag analysis4635 if (hasDynamicKeys) {4636 patchFlag |= 16 /* FULL_PROPS */;4637 }4638 else {4639 if (hasClassBinding && !isComponent) {4640 patchFlag |= 2 /* CLASS */;4641 }4642 if (hasStyleBinding && !isComponent) {4643 patchFlag |= 4 /* STYLE */;4644 }4645 if (dynamicPropNames.length) {4646 patchFlag |= 8 /* PROPS */;4647 }4648 if (hasHydrationEventBinding) {4649 patchFlag |= 32 /* HYDRATE_EVENTS */;4650 }4651 }4652 if (!shouldUseBlock &&4653 (patchFlag === 0 || patchFlag === 32 /* HYDRATE_EVENTS */) &&4654 (hasRef || hasVnodeHook || runtimeDirectives.length > 0)) {4655 patchFlag |= 512 /* NEED_PATCH */;4656 }4657 // pre-normalize props, SSR is skipped for now4658 if (!context.inSSR && propsExpression) {4659 switch (propsExpression.type) {4660 case 15 /* JS_OBJECT_EXPRESSION */:4661 // means that there is no v-bind,4662 // but still need to deal with dynamic key binding4663 let classKeyIndex = -1;4664 let styleKeyIndex = -1;4665 let hasDynamicKey = false;4666 for (let i = 0; i < propsExpression.properties.length; i++) {4667 const key = propsExpression.properties[i].key;4668 if (isStaticExp(key)) {4669 if (key.content === 'class') {4670 classKeyIndex = i;4671 }4672 else if (key.content === 'style') {4673 styleKeyIndex = i;4674 }4675 }4676 else if (!key.isHandlerKey) {4677 hasDynamicKey = true;4678 }4679 }4680 const classProp = propsExpression.properties[classKeyIndex];4681 const styleProp = propsExpression.properties[styleKeyIndex];4682 // no dynamic key4683 if (!hasDynamicKey) {4684 if (classProp && !isStaticExp(classProp.value)) {4685 classProp.value = createCallExpression(context.helper(NORMALIZE_CLASS), [classProp.value]);4686 }4687 if (styleProp &&4688 !isStaticExp(styleProp.value) &&4689 // the static style is compiled into an object,4690 // so use `hasStyleBinding` to ensure that it is a dynamic style binding4691 (hasStyleBinding ||4692 // v-bind:style and style both exist,4693 // v-bind:style with static literal object4694 styleProp.value.type === 17 /* JS_ARRAY_EXPRESSION */)) {4695 styleProp.value = createCallExpression(context.helper(NORMALIZE_STYLE), [styleProp.value]);4696 }4697 }4698 else {4699 // dynamic key binding, wrap with `normalizeProps`4700 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [propsExpression]);4701 }4702 break;4703 case 14 /* JS_CALL_EXPRESSION */:4704 // mergeProps call, do nothing4705 break;4706 default:4707 // single v-bind4708 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [4709 createCallExpression(context.helper(GUARD_REACTIVE_PROPS), [4710 propsExpression4711 ])4712 ]);4713 break;4714 }4715 }4716 return {4717 props: propsExpression,4718 directives: runtimeDirectives,4719 patchFlag,4720 dynamicPropNames,4721 shouldUseBlock4722 };4723}4724// Dedupe props in an object literal.4725// Literal duplicated attributes would have been warned during the parse phase,4726// however, it's possible to encounter duplicated `onXXX` handlers with different4727// modifiers. We also need to merge static and dynamic class / style attributes.4728// - onXXX handlers / style: merge into array4729// - class: merge into single expression with concatenation4730function dedupeProperties(properties) {4731 const knownProps = new Map();4732 const deduped = [];4733 for (let i = 0; i < properties.length; i++) {4734 const prop = properties[i];4735 // dynamic keys are always allowed4736 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {4737 deduped.push(prop);4738 continue;4739 }4740 const name = prop.key.content;4741 const existing = knownProps.get(name);4742 if (existing) {4743 if (name === 'style' || name === 'class' || shared.isOn(name)) {4744 mergeAsArray(existing, prop);4745 }4746 // unexpected duplicate, should have emitted error during parse4747 }4748 else {4749 knownProps.set(name, prop);4750 deduped.push(prop);4751 }4752 }4753 return deduped;4754}4755function mergeAsArray(existing, incoming) {4756 if (existing.value.type === 17 /* JS_ARRAY_EXPRESSION */) {4757 existing.value.elements.push(incoming.value);4758 }4759 else {4760 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);4761 }4762}4763function buildDirectiveArgs(dir, context) {4764 const dirArgs = [];4765 const runtime = directiveImportMap.get(dir);4766 if (runtime) {4767 // built-in directive with runtime4768 dirArgs.push(context.helperString(runtime));4769 }4770 else {4771 // user directive.4772 // see if we have directives exposed via <script setup>4773 const fromSetup = resolveSetupReference('v-' + dir.name, context);4774 if (fromSetup) {4775 dirArgs.push(fromSetup);4776 }4777 else {4778 // inject statement for resolving directive4779 context.helper(RESOLVE_DIRECTIVE);4780 context.directives.add(dir.name);4781 dirArgs.push(toValidAssetId(dir.name, `directive`));4782 }4783 }4784 const { loc } = dir;4785 if (dir.exp)4786 dirArgs.push(dir.exp);4787 if (dir.arg) {4788 if (!dir.exp) {4789 dirArgs.push(`void 0`);4790 }4791 dirArgs.push(dir.arg);4792 }4793 if (Object.keys(dir.modifiers).length) {4794 if (!dir.arg) {4795 if (!dir.exp) {4796 dirArgs.push(`void 0`);4797 }4798 dirArgs.push(`void 0`);4799 }4800 const trueExpression = createSimpleExpression(`true`, false, loc);4801 dirArgs.push(createObjectExpression(dir.modifiers.map(modifier => createObjectProperty(modifier, trueExpression)), loc));4802 }4803 return createArrayExpression(dirArgs, dir.loc);4804}4805function stringifyDynamicPropNames(props) {4806 let propsNamesString = `[`;4807 for (let i = 0, l = props.length; i < l; i++) {4808 propsNamesString += JSON.stringify(props[i]);4809 if (i < l - 1)4810 propsNamesString += ', ';4811 }4812 return propsNamesString + `]`;4813}4814function isComponentTag(tag) {4815 return tag === 'component' || tag === 'Component';4816}4817const cacheStringFunction = (fn) => {4818 const cache = Object.create(null);4819 return ((str) => {4820 const hit = cache[str];4821 return hit || (cache[str] = fn(str));4822 });4823};4824const camelizeRE = /-(\w)/g;4825/**4826 * @private4827 */4828const camelize = cacheStringFunction((str) => {4829 return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));4830});4831const transformSlotOutlet = (node, context) => {4832 if (isSlotOutlet(node)) {4833 const { children, loc } = node;4834 const { slotName, slotProps } = processSlotOutlet(node, context);4835 const slotArgs = [4836 context.prefixIdentifiers ? `_ctx.$slots` : `$slots`,4837 slotName,4838 '{}',4839 'undefined',4840 'true'4841 ];4842 let expectedLen = 2;4843 if (slotProps) {4844 slotArgs[2] = slotProps;4845 expectedLen = 3;4846 }4847 if (children.length) {4848 slotArgs[3] = createFunctionExpression([], children, false, false, loc);4849 expectedLen = 4;4850 }4851 if (context.scopeId && !context.slotted) {4852 expectedLen = 5;4853 }4854 slotArgs.splice(expectedLen); // remove unused arguments4855 node.codegenNode = createCallExpression(context.helper(RENDER_SLOT), slotArgs, loc);4856 }4857};4858function processSlotOutlet(node, context) {4859 let slotName = `"default"`;4860 let slotProps = undefined;4861 const nonNameProps = [];4862 for (let i = 0; i < node.props.length; i++) {4863 const p = node.props[i];4864 if (p.type === 6 /* ATTRIBUTE */) {4865 if (p.value) {4866 if (p.name === 'name') {4867 slotName = JSON.stringify(p.value.content);4868 }4869 else {4870 p.name = camelize(p.name);4871 nonNameProps.push(p);4872 }4873 }4874 }4875 else {4876 if (p.name === 'bind' && isStaticArgOf(p.arg, 'name')) {4877 if (p.exp)4878 slotName = p.exp;4879 }4880 else {4881 if (p.name === 'bind' && p.arg && isStaticExp(p.arg)) {4882 p.arg.content = camelize(p.arg.content);4883 }4884 nonNameProps.push(p);4885 }4886 }4887 }4888 if (nonNameProps.length > 0) {4889 const { props, directives } = buildProps(node, context, nonNameProps);4890 slotProps = props;4891 if (directives.length) {4892 context.onError(createCompilerError(36 /* X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET */, directives[0].loc));4893 }4894 }4895 return {4896 slotName,4897 slotProps4898 };4899}4900const fnExpRE = /^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/;4901const transformOn = (dir, node, context, augmentor) => {4902 const { loc, modifiers, arg } = dir;4903 if (!dir.exp && !modifiers.length) {4904 context.onError(createCompilerError(35 /* X_V_ON_NO_EXPRESSION */, loc));4905 }4906 let eventName;4907 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4908 if (arg.isStatic) {4909 let rawName = arg.content;4910 // TODO deprecate @vnodeXXX usage4911 if (rawName.startsWith('vue:')) {4912 rawName = `vnode-${rawName.slice(4)}`;4913 }4914 // for all event listeners, auto convert it to camelCase. See issue #22494915 eventName = createSimpleExpression(shared.toHandlerKey(shared.camelize(rawName)), true, arg.loc);4916 }4917 else {4918 // #23884919 eventName = createCompoundExpression([4920 `${context.helperString(TO_HANDLER_KEY)}(`,4921 arg,4922 `)`4923 ]);4924 }4925 }4926 else {4927 // already a compound expression.4928 eventName = arg;4929 eventName.children.unshift(`${context.helperString(TO_HANDLER_KEY)}(`);4930 eventName.children.push(`)`);4931 }4932 // handler processing4933 let exp = dir.exp;4934 if (exp && !exp.content.trim()) {4935 exp = undefined;4936 }4937 let shouldCache = context.cacheHandlers && !exp && !context.inVOnce;4938 if (exp) {4939 const isMemberExp = isMemberExpression(exp.content, context);4940 const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content));4941 const hasMultipleStatements = exp.content.includes(`;`);4942 // process the expression since it's been skipped4943 if (context.prefixIdentifiers) {4944 isInlineStatement && context.addIdentifiers(`$event`);4945 exp = dir.exp = processExpression(exp, context, false, hasMultipleStatements);4946 isInlineStatement && context.removeIdentifiers(`$event`);4947 // with scope analysis, the function is hoistable if it has no reference4948 // to scope variables.4949 shouldCache =4950 context.cacheHandlers &&4951 // unnecessary to cache inside v-once4952 !context.inVOnce &&4953 // runtime constants don't need to be cached4954 // (this is analyzed by compileScript in SFC <script setup>)4955 !(exp.type === 4 /* SIMPLE_EXPRESSION */ && exp.constType > 0) &&4956 // #1541 bail if this is a member exp handler passed to a component -4957 // we need to use the original function to preserve arity,4958 // e.g. <transition> relies on checking cb.length to determine4959 // transition end handling. Inline function is ok since its arity4960 // is preserved even when cached.4961 !(isMemberExp && node.tagType === 1 /* COMPONENT */) &&4962 // bail if the function references closure variables (v-for, v-slot)4963 // it must be passed fresh to avoid stale values.4964 !hasScopeRef(exp, context.identifiers);4965 // If the expression is optimizable and is a member expression pointing4966 // to a function, turn it into invocation (and wrap in an arrow function4967 // below) so that it always accesses the latest value when called - thus4968 // avoiding the need to be patched.4969 if (shouldCache && isMemberExp) {4970 if (exp.type === 4 /* SIMPLE_EXPRESSION */) {4971 exp.content = `${exp.content} && ${exp.content}(...args)`;4972 }4973 else {4974 exp.children = [...exp.children, ` && `, ...exp.children, `(...args)`];4975 }4976 }4977 }4978 if (isInlineStatement || (shouldCache && isMemberExp)) {4979 // wrap inline statement in a function expression4980 exp = createCompoundExpression([4981 `${isInlineStatement4982 ? context.isTS4983 ? `($event: any)`4984 : `$event`4985 : `${context.isTS ? `\n//@ts-ignore\n` : ``}(...args)`} => ${hasMultipleStatements ? `{` : `(`}`,4986 exp,4987 hasMultipleStatements ? `}` : `)`4988 ]);4989 }4990 }4991 let ret = {4992 props: [4993 createObjectProperty(eventName, exp || createSimpleExpression(`() => {}`, false, loc))4994 ]4995 };4996 // apply extended compiler augmentor4997 if (augmentor) {4998 ret = augmentor(ret);4999 }5000 if (shouldCache) {5001 // cache handlers so that it's always the same handler being passed down.5002 // this avoids unnecessary re-renders when users use inline handlers on5003 // components.5004 ret.props[0].value = context.cache(ret.props[0].value);5005 }5006 // mark the key as handler for props normalization check5007 ret.props.forEach(p => (p.key.isHandlerKey = true));5008 return ret;5009};5010// v-bind without arg is handled directly in ./transformElements.ts due to it affecting5011// codegen for the entire props object. This transform here is only for v-bind5012// *with* args.5013const transformBind = (dir, _node, context) => {5014 const { exp, modifiers, loc } = dir;5015 const arg = dir.arg;5016 if (arg.type !== 4 /* SIMPLE_EXPRESSION */) {5017 arg.children.unshift(`(`);5018 arg.children.push(`) || ""`);5019 }5020 else if (!arg.isStatic) {5021 arg.content = `${arg.content} || ""`;5022 }5023 // .sync is replaced by v-model:arg5024 if (modifiers.includes('camel')) {5025 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {5026 if (arg.isStatic) {5027 arg.content = shared.camelize(arg.content);5028 }5029 else {5030 arg.content = `${context.helperString(CAMELIZE)}(${arg.content})`;5031 }5032 }5033 else {5034 arg.children.unshift(`${context.helperString(CAMELIZE)}(`);5035 arg.children.push(`)`);5036 }5037 }5038 if (!context.inSSR) {5039 if (modifiers.includes('prop')) {5040 injectPrefix(arg, '.');5041 }5042 if (modifiers.includes('attr')) {5043 injectPrefix(arg, '^');5044 }5045 }5046 if (!exp ||5047 (exp.type === 4 /* SIMPLE_EXPRESSION */ && !exp.content.trim())) {5048 context.onError(createCompilerError(34 /* X_V_BIND_NO_EXPRESSION */, loc));5049 return {5050 props: [createObjectProperty(arg, createSimpleExpression('', true, loc))]5051 };5052 }5053 return {5054 props: [createObjectProperty(arg, exp)]5055 };5056};5057const injectPrefix = (arg, prefix) => {5058 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {5059 if (arg.isStatic) {5060 arg.content = prefix + arg.content;5061 }5062 else {5063 arg.content = `\`${prefix}\${${arg.content}}\``;5064 }5065 }5066 else {5067 arg.children.unshift(`'${prefix}' + (`);5068 arg.children.push(`)`);5069 }5070};5071// Merge adjacent text nodes and expressions into a single expression5072// e.g. <div>abc {{ d }} {{ e }}</div> should have a single expression node as child.5073const transformText = (node, context) => {5074 if (node.type === 0 /* ROOT */ ||5075 node.type === 1 /* ELEMENT */ ||5076 node.type === 11 /* FOR */ ||5077 node.type === 10 /* IF_BRANCH */) {5078 // perform the transform on node exit so that all expressions have already5079 // been processed.5080 return () => {5081 const children = node.children;5082 let currentContainer = undefined;5083 let hasText = false;5084 for (let i = 0; i < children.length; i++) {5085 const child = children[i];5086 if (isText(child)) {5087 hasText = true;5088 for (let j = i + 1; j < children.length; j++) {5089 const next = children[j];5090 if (isText(next)) {5091 if (!currentContainer) {5092 currentContainer = children[i] = {5093 type: 8 /* COMPOUND_EXPRESSION */,5094 loc: child.loc,5095 children: [child]5096 };5097 }5098 // merge adjacent text node into current5099 currentContainer.children.push(` + `, next);5100 children.splice(j, 1);5101 j--;5102 }5103 else {5104 currentContainer = undefined;5105 break;5106 }5107 }5108 }5109 }5110 if (!hasText ||5111 // if this is a plain element with a single text child, leave it5112 // as-is since the runtime has dedicated fast path for this by directly5113 // setting textContent of the element.5114 // for component root it's always normalized anyway.5115 (children.length === 1 &&5116 (node.type === 0 /* ROOT */ ||5117 (node.type === 1 /* ELEMENT */ &&5118 node.tagType === 0 /* ELEMENT */ &&5119 // #37565120 // custom directives can potentially add DOM elements arbitrarily,5121 // we need to avoid setting textContent of the element at runtime5122 // to avoid accidentally overwriting the DOM elements added5123 // by the user through custom directives.5124 !node.props.find(p => p.type === 7 /* DIRECTIVE */ &&5125 !context.directiveTransforms[p.name]) &&5126 // in compat mode, <template> tags with no special directives5127 // will be rendered as a fragment so its children must be5128 // converted into vnodes.5129 !(node.tag === 'template'))))) {5130 return;5131 }5132 // pre-convert text nodes into createTextVNode(text) calls to avoid5133 // runtime normalization.5134 for (let i = 0; i < children.length; i++) {5135 const child = children[i];5136 if (isText(child) || child.type === 8 /* COMPOUND_EXPRESSION */) {5137 const callArgs = [];5138 // createTextVNode defaults to single whitespace, so if it is a5139 // single space the code could be an empty call to save bytes.5140 if (child.type !== 2 /* TEXT */ || child.content !== ' ') {5141 callArgs.push(child);5142 }5143 // mark dynamic text with flag so it gets patched inside a block5144 if (!context.ssr &&5145 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {5146 callArgs.push(1 /* TEXT */ +5147 (``));5148 }5149 children[i] = {5150 type: 12 /* TEXT_CALL */,5151 content: child,5152 loc: child.loc,5153 codegenNode: createCallExpression(context.helper(CREATE_TEXT), callArgs)5154 };5155 }5156 }5157 };5158 }5159};5160const seen = new WeakSet();5161const transformOnce = (node, context) => {5162 if (node.type === 1 /* ELEMENT */ && findDir(node, 'once', true)) {5163 if (seen.has(node) || context.inVOnce) {5164 return;5165 }5166 seen.add(node);5167 context.inVOnce = true;5168 context.helper(SET_BLOCK_TRACKING);5169 return () => {5170 context.inVOnce = false;5171 const cur = context.currentNode;5172 if (cur.codegenNode) {5173 cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */);5174 }5175 };5176 }5177};5178const transformModel = (dir, node, context) => {5179 const { exp, arg } = dir;5180 if (!exp) {5181 context.onError(createCompilerError(41 /* X_V_MODEL_NO_EXPRESSION */, dir.loc));5182 return createTransformProps();5183 }5184 const rawExp = exp.loc.source;5185 const expString = exp.type === 4 /* SIMPLE_EXPRESSION */ ? exp.content : rawExp;5186 // im SFC <script setup> inline mode, the exp may have been transformed into5187 // _unref(exp)5188 const bindingType = context.bindingMetadata[rawExp];5189 const maybeRef = context.inline &&5190 bindingType &&5191 bindingType !== "setup-const" /* SETUP_CONST */;5192 if (!expString.trim() ||5193 (!isMemberExpression(expString, context) && !maybeRef)) {5194 context.onError(createCompilerError(42 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));5195 return createTransformProps();5196 }5197 if (context.prefixIdentifiers &&5198 isSimpleIdentifier(expString) &&5199 context.identifiers[expString]) {5200 context.onError(createCompilerError(43 /* X_V_MODEL_ON_SCOPE_VARIABLE */, exp.loc));5201 return createTransformProps();5202 }5203 const propName = arg ? arg : createSimpleExpression('modelValue', true);5204 const eventName = arg5205 ? isStaticExp(arg)5206 ? `onUpdate:${arg.content}`5207 : createCompoundExpression(['"onUpdate:" + ', arg])5208 : `onUpdate:modelValue`;5209 let assignmentExp;5210 const eventArg = context.isTS ? `($event: any)` : `$event`;5211 if (maybeRef) {5212 if (bindingType === "setup-ref" /* SETUP_REF */) {5213 // v-model used on known ref.5214 assignmentExp = createCompoundExpression([5215 `${eventArg} => ((`,5216 createSimpleExpression(rawExp, false, exp.loc),5217 `).value = $event)`5218 ]);5219 }5220 else {5221 // v-model used on a potentially ref binding in <script setup> inline mode.5222 // the assignment needs to check whether the binding is actually a ref.5223 const altAssignment = bindingType === "setup-let" /* SETUP_LET */ ? `${rawExp} = $event` : `null`;5224 assignmentExp = createCompoundExpression([5225 `${eventArg} => (${context.helperString(IS_REF)}(${rawExp}) ? (`,5226 createSimpleExpression(rawExp, false, exp.loc),5227 `).value = $event : ${altAssignment})`5228 ]);5229 }5230 }5231 else {5232 assignmentExp = createCompoundExpression([5233 `${eventArg} => ((`,5234 exp,5235 `) = $event)`5236 ]);5237 }5238 const props = [5239 // modelValue: foo5240 createObjectProperty(propName, dir.exp),5241 // "onUpdate:modelValue": $event => (foo = $event)5242 createObjectProperty(eventName, assignmentExp)5243 ];5244 // cache v-model handler if applicable (when it doesn't refer any scope vars)5245 if (context.prefixIdentifiers &&5246 !context.inVOnce &&5247 context.cacheHandlers &&5248 !hasScopeRef(exp, context.identifiers)) {5249 props[1].value = context.cache(props[1].value);5250 }5251 // modelModifiers: { foo: true, "bar-baz": true }5252 if (dir.modifiers.length && node.tagType === 1 /* COMPONENT */) {5253 const modifiers = dir.modifiers5254 .map(m => (isSimpleIdentifier(m) ? m : JSON.stringify(m)) + `: true`)5255 .join(`, `);5256 const modifiersKey = arg5257 ? isStaticExp(arg)5258 ? `${arg.content}Modifiers`5259 : createCompoundExpression([arg, ' + "Modifiers"'])5260 : `modelModifiers`;5261 props.push(createObjectProperty(modifiersKey, createSimpleExpression(`{ ${modifiers} }`, false, dir.loc, 2 /* CAN_HOIST */)));5262 }5263 return createTransformProps(props);5264};5265function createTransformProps(props = []) {5266 return { props };5267}5268const validDivisionCharRE = /[\w).+\-_$\]]/;5269const transformFilter = (node, context) => {5270 if (!isCompatEnabled("COMPILER_FILTER" /* COMPILER_FILTERS */, context)) {5271 return;5272 }5273 if (node.type === 5 /* INTERPOLATION */) {5274 // filter rewrite is applied before expression transform so only5275 // simple expressions are possible at this stage5276 rewriteFilter(node.content, context);5277 }5278 if (node.type === 1 /* ELEMENT */) {5279 node.props.forEach((prop) => {5280 if (prop.type === 7 /* DIRECTIVE */ &&5281 prop.name !== 'for' &&5282 prop.exp) {5283 rewriteFilter(prop.exp, context);5284 }...
compiler-dom.esm-browser.js
Source:compiler-dom.esm-browser.js
...939 else {940 return value;941 }942}943function isCompatEnabled(key, context) {944 const mode = getCompatValue('MODE', context);945 const value = getCompatValue(key, context);946 // in v3 mode, only enable if explicitly set to true947 // otherwise enable for any non-false value948 return mode === 3 ? value === true : value !== false;949}950function checkCompatEnabled(key, context, loc, ...args) {951 const enabled = isCompatEnabled(key, context);952 if (enabled) {953 warnDeprecation(key, context, loc, ...args);954 }955 return enabled;956}957function warnDeprecation(key, context, loc, ...args) {958 const val = getCompatValue(key, context);959 if (val === 'suppress-warning') {960 return;961 }962 const { message, link } = deprecationData[key];963 const msg = `(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`;964 const err = new SyntaxError(msg);965 err.code = key;966 if (loc)967 err.loc = loc;968 context.onWarn(err);969}970// The default decoder only provides escapes for characters reserved as part of971// the template syntax, and is only used if the custom renderer did not provide972// a platform-specific decoder.973const decodeRE = /&(gt|lt|amp|apos|quot);/g;974const decodeMap = {975 gt: '>',976 lt: '<',977 amp: '&',978 apos: "'",979 quot: '"'980};981const defaultParserOptions = {982 delimiters: [`{{`, `}}`],983 getNamespace: () => 0 /* HTML */,984 getTextMode: () => 0 /* DATA */,985 isVoidTag: NO,986 isPreTag: NO,987 isCustomElement: NO,988 decodeEntities: (rawText) => rawText.replace(decodeRE, (_, p1) => decodeMap[p1]),989 onError: defaultOnError,990 onWarn: defaultOnWarn,991 comments: true992};993function baseParse(content, options = {}) {994 const context = createParserContext(content, options);995 const start = getCursor(context);996 return createRoot(parseChildren(context, 0 /* DATA */, []), getSelection(context, start));997}998function createParserContext(content, rawOptions) {999 const options = extend({}, defaultParserOptions);1000 let key;1001 for (key in rawOptions) {1002 // @ts-ignore1003 options[key] =1004 rawOptions[key] === undefined1005 ? defaultParserOptions[key]1006 : rawOptions[key];1007 }1008 return {1009 options,1010 column: 1,1011 line: 1,1012 offset: 0,1013 originalSource: content,1014 source: content,1015 inPre: false,1016 inVPre: false,1017 onWarn: options.onWarn1018 };1019}1020function parseChildren(context, mode, ancestors) {1021 const parent = last(ancestors);1022 const ns = parent ? parent.ns : 0 /* HTML */;1023 const nodes = [];1024 while (!isEnd(context, mode, ancestors)) {1025 const s = context.source;1026 let node = undefined;1027 if (mode === 0 /* DATA */ || mode === 1 /* RCDATA */) {1028 if (!context.inVPre && startsWith(s, context.options.delimiters[0])) {1029 // '{{'1030 node = parseInterpolation(context, mode);1031 }1032 else if (mode === 0 /* DATA */ && s[0] === '<') {1033 // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state1034 if (s.length === 1) {1035 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 1);1036 }1037 else if (s[1] === '!') {1038 // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state1039 if (startsWith(s, '<!--')) {1040 node = parseComment(context);1041 }1042 else if (startsWith(s, '<!DOCTYPE')) {1043 // Ignore DOCTYPE by a limitation.1044 node = parseBogusComment(context);1045 }1046 else if (startsWith(s, '<![CDATA[')) {1047 if (ns !== 0 /* HTML */) {1048 node = parseCDATA(context, ancestors);1049 }1050 else {1051 emitError(context, 1 /* CDATA_IN_HTML_CONTENT */);1052 node = parseBogusComment(context);1053 }1054 }1055 else {1056 emitError(context, 11 /* INCORRECTLY_OPENED_COMMENT */);1057 node = parseBogusComment(context);1058 }1059 }1060 else if (s[1] === '/') {1061 // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state1062 if (s.length === 2) {1063 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 2);1064 }1065 else if (s[2] === '>') {1066 emitError(context, 14 /* MISSING_END_TAG_NAME */, 2);1067 advanceBy(context, 3);1068 continue;1069 }1070 else if (/[a-z]/i.test(s[2])) {1071 emitError(context, 23 /* X_INVALID_END_TAG */);1072 parseTag(context, 1 /* End */, parent);1073 continue;1074 }1075 else {1076 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 2);1077 node = parseBogusComment(context);1078 }1079 }1080 else if (/[a-z]/i.test(s[1])) {1081 node = parseElement(context, ancestors);1082 // 2.x <template> with no directive compat1083 if (isCompatEnabled("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context) &&1084 node &&1085 node.tag === 'template' &&1086 !node.props.some(p => p.type === 7 /* DIRECTIVE */ &&1087 isSpecialTemplateDirective(p.name))) {1088 warnDeprecation("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context, node.loc);1089 node = node.children;1090 }1091 }1092 else if (s[1] === '?') {1093 emitError(context, 21 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */, 1);1094 node = parseBogusComment(context);1095 }1096 else {1097 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 1);1098 }1099 }1100 }1101 if (!node) {1102 node = parseText(context, mode);1103 }1104 if (isArray(node)) {1105 for (let i = 0; i < node.length; i++) {1106 pushNode(nodes, node[i]);1107 }1108 }1109 else {1110 pushNode(nodes, node);1111 }1112 }1113 // Whitespace handling strategy like v21114 let removedWhitespace = false;1115 if (mode !== 2 /* RAWTEXT */ && mode !== 1 /* RCDATA */) {1116 const shouldCondense = context.options.whitespace !== 'preserve';1117 for (let i = 0; i < nodes.length; i++) {1118 const node = nodes[i];1119 if (!context.inPre && node.type === 2 /* TEXT */) {1120 if (!/[^\t\r\n\f ]/.test(node.content)) {1121 const prev = nodes[i - 1];1122 const next = nodes[i + 1];1123 // Remove if:1124 // - the whitespace is the first or last node, or:1125 // - (condense mode) the whitespace is adjacent to a comment, or:1126 // - (condense mode) the whitespace is between two elements AND contains newline1127 if (!prev ||1128 !next ||1129 (shouldCondense &&1130 (prev.type === 3 /* COMMENT */ ||1131 next.type === 3 /* COMMENT */ ||1132 (prev.type === 1 /* ELEMENT */ &&1133 next.type === 1 /* ELEMENT */ &&1134 /[\r\n]/.test(node.content))))) {1135 removedWhitespace = true;1136 nodes[i] = null;1137 }1138 else {1139 // Otherwise, the whitespace is condensed into a single space1140 node.content = ' ';1141 }1142 }1143 else if (shouldCondense) {1144 // in condense mode, consecutive whitespaces in text are condensed1145 // down to a single space.1146 node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ');1147 }1148 }1149 // Remove comment nodes if desired by configuration.1150 else if (node.type === 3 /* COMMENT */ && !context.options.comments) {1151 removedWhitespace = true;1152 nodes[i] = null;1153 }1154 }1155 if (context.inPre && parent && context.options.isPreTag(parent.tag)) {1156 // remove leading newline per html spec1157 // https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element1158 const first = nodes[0];1159 if (first && first.type === 2 /* TEXT */) {1160 first.content = first.content.replace(/^\r?\n/, '');1161 }1162 }1163 }1164 return removedWhitespace ? nodes.filter(Boolean) : nodes;1165}1166function pushNode(nodes, node) {1167 if (node.type === 2 /* TEXT */) {1168 const prev = last(nodes);1169 // Merge if both this and the previous node are text and those are1170 // consecutive. This happens for cases like "a < b".1171 if (prev &&1172 prev.type === 2 /* TEXT */ &&1173 prev.loc.end.offset === node.loc.start.offset) {1174 prev.content += node.content;1175 prev.loc.end = node.loc.end;1176 prev.loc.source += node.loc.source;1177 return;1178 }1179 }1180 nodes.push(node);1181}1182function parseCDATA(context, ancestors) {1183 advanceBy(context, 9);1184 const nodes = parseChildren(context, 3 /* CDATA */, ancestors);1185 if (context.source.length === 0) {1186 emitError(context, 6 /* EOF_IN_CDATA */);1187 }1188 else {1189 advanceBy(context, 3);1190 }1191 return nodes;1192}1193function parseComment(context) {1194 const start = getCursor(context);1195 let content;1196 // Regular comment.1197 const match = /--(\!)?>/.exec(context.source);1198 if (!match) {1199 content = context.source.slice(4);1200 advanceBy(context, context.source.length);1201 emitError(context, 7 /* EOF_IN_COMMENT */);1202 }1203 else {1204 if (match.index <= 3) {1205 emitError(context, 0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */);1206 }1207 if (match[1]) {1208 emitError(context, 10 /* INCORRECTLY_CLOSED_COMMENT */);1209 }1210 content = context.source.slice(4, match.index);1211 // Advancing with reporting nested comments.1212 const s = context.source.slice(0, match.index);1213 let prevIndex = 1, nestedIndex = 0;1214 while ((nestedIndex = s.indexOf('<!--', prevIndex)) !== -1) {1215 advanceBy(context, nestedIndex - prevIndex + 1);1216 if (nestedIndex + 4 < s.length) {1217 emitError(context, 16 /* NESTED_COMMENT */);1218 }1219 prevIndex = nestedIndex + 1;1220 }1221 advanceBy(context, match.index + match[0].length - prevIndex + 1);1222 }1223 return {1224 type: 3 /* COMMENT */,1225 content,1226 loc: getSelection(context, start)1227 };1228}1229function parseBogusComment(context) {1230 const start = getCursor(context);1231 const contentStart = context.source[1] === '?' ? 1 : 2;1232 let content;1233 const closeIndex = context.source.indexOf('>');1234 if (closeIndex === -1) {1235 content = context.source.slice(contentStart);1236 advanceBy(context, context.source.length);1237 }1238 else {1239 content = context.source.slice(contentStart, closeIndex);1240 advanceBy(context, closeIndex + 1);1241 }1242 return {1243 type: 3 /* COMMENT */,1244 content,1245 loc: getSelection(context, start)1246 };1247}1248function parseElement(context, ancestors) {1249 // Start tag.1250 const wasInPre = context.inPre;1251 const wasInVPre = context.inVPre;1252 const parent = last(ancestors);1253 const element = parseTag(context, 0 /* Start */, parent);1254 const isPreBoundary = context.inPre && !wasInPre;1255 const isVPreBoundary = context.inVPre && !wasInVPre;1256 if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {1257 // #4030 self-closing <pre> tag1258 if (isPreBoundary) {1259 context.inPre = false;1260 }1261 if (isVPreBoundary) {1262 context.inVPre = false;1263 }1264 return element;1265 }1266 // Children.1267 ancestors.push(element);1268 const mode = context.options.getTextMode(element, parent);1269 const children = parseChildren(context, mode, ancestors);1270 ancestors.pop();1271 // 2.x inline-template compat1272 {1273 const inlineTemplateProp = element.props.find(p => p.type === 6 /* ATTRIBUTE */ && p.name === 'inline-template');1274 if (inlineTemplateProp &&1275 checkCompatEnabled("COMPILER_INLINE_TEMPLATE" /* COMPILER_INLINE_TEMPLATE */, context, inlineTemplateProp.loc)) {1276 const loc = getSelection(context, element.loc.end);1277 inlineTemplateProp.value = {1278 type: 2 /* TEXT */,1279 content: loc.source,1280 loc1281 };1282 }1283 }1284 element.children = children;1285 // End tag.1286 if (startsWithEndTagOpen(context.source, element.tag)) {1287 parseTag(context, 1 /* End */, parent);1288 }1289 else {1290 emitError(context, 24 /* X_MISSING_END_TAG */, 0, element.loc.start);1291 if (context.source.length === 0 && element.tag.toLowerCase() === 'script') {1292 const first = children[0];1293 if (first && startsWith(first.loc.source, '<!--')) {1294 emitError(context, 8 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */);1295 }1296 }1297 }1298 element.loc = getSelection(context, element.loc.start);1299 if (isPreBoundary) {1300 context.inPre = false;1301 }1302 if (isVPreBoundary) {1303 context.inVPre = false;1304 }1305 return element;1306}1307const isSpecialTemplateDirective = /*#__PURE__*/ makeMap(`if,else,else-if,for,slot`);1308function parseTag(context, type, parent) {1309 // Tag open.1310 const start = getCursor(context);1311 const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source);1312 const tag = match[1];1313 const ns = context.options.getNamespace(tag, parent);1314 advanceBy(context, match[0].length);1315 advanceSpaces(context);1316 // save current state in case we need to re-parse attributes with v-pre1317 const cursor = getCursor(context);1318 const currentSource = context.source;1319 // check <pre> tag1320 if (context.options.isPreTag(tag)) {1321 context.inPre = true;1322 }1323 // Attributes.1324 let props = parseAttributes(context, type);1325 // check v-pre1326 if (type === 0 /* Start */ &&1327 !context.inVPre &&1328 props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'pre')) {1329 context.inVPre = true;1330 // reset context1331 extend(context, cursor);1332 context.source = currentSource;1333 // re-parse attrs and filter out v-pre itself1334 props = parseAttributes(context, type).filter(p => p.name !== 'v-pre');1335 }1336 // Tag close.1337 let isSelfClosing = false;1338 if (context.source.length === 0) {1339 emitError(context, 9 /* EOF_IN_TAG */);1340 }1341 else {1342 isSelfClosing = startsWith(context.source, '/>');1343 if (type === 1 /* End */ && isSelfClosing) {1344 emitError(context, 4 /* END_TAG_WITH_TRAILING_SOLIDUS */);1345 }1346 advanceBy(context, isSelfClosing ? 2 : 1);1347 }1348 if (type === 1 /* End */) {1349 return;1350 }1351 // 2.x deprecation checks1352 if (isCompatEnabled("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context)) {1353 let hasIf = false;1354 let hasFor = false;1355 for (let i = 0; i < props.length; i++) {1356 const p = props[i];1357 if (p.type === 7 /* DIRECTIVE */) {1358 if (p.name === 'if') {1359 hasIf = true;1360 }1361 else if (p.name === 'for') {1362 hasFor = true;1363 }1364 }1365 if (hasIf && hasFor) {1366 warnDeprecation("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context, getSelection(context, start));1367 break;1368 }1369 }1370 }1371 let tagType = 0 /* ELEMENT */;1372 if (!context.inVPre) {1373 if (tag === 'slot') {1374 tagType = 2 /* SLOT */;1375 }1376 else if (tag === 'template') {1377 if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {1378 tagType = 3 /* TEMPLATE */;1379 }1380 }1381 else if (isComponent(tag, props, context)) {1382 tagType = 1 /* COMPONENT */;1383 }1384 }1385 return {1386 type: 1 /* ELEMENT */,1387 ns,1388 tag,1389 tagType,1390 props,1391 isSelfClosing,1392 children: [],1393 loc: getSelection(context, start),1394 codegenNode: undefined // to be created during transform phase1395 };1396}1397function isComponent(tag, props, context) {1398 const options = context.options;1399 if (options.isCustomElement(tag)) {1400 return false;1401 }1402 if (tag === 'component' ||1403 /^[A-Z]/.test(tag) ||1404 isCoreComponent(tag) ||1405 (options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||1406 (options.isNativeTag && !options.isNativeTag(tag))) {1407 return true;1408 }1409 // at this point the tag should be a native tag, but check for potential "is"1410 // casting1411 for (let i = 0; i < props.length; i++) {1412 const p = props[i];1413 if (p.type === 6 /* ATTRIBUTE */) {1414 if (p.name === 'is' && p.value) {1415 if (p.value.content.startsWith('vue:')) {1416 return true;1417 }1418 else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1419 return true;1420 }1421 }1422 }1423 else {1424 // directive1425 // v-is (TODO Deprecate)1426 if (p.name === 'is') {1427 return true;1428 }1429 else if (1430 // :is on plain element - only treat as component in compat mode1431 p.name === 'bind' &&1432 isStaticArgOf(p.arg, 'is') &&1433 true &&1434 checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1435 return true;1436 }1437 }1438 }1439}1440function parseAttributes(context, type) {1441 const props = [];1442 const attributeNames = new Set();1443 while (context.source.length > 0 &&1444 !startsWith(context.source, '>') &&1445 !startsWith(context.source, '/>')) {1446 if (startsWith(context.source, '/')) {1447 emitError(context, 22 /* UNEXPECTED_SOLIDUS_IN_TAG */);1448 advanceBy(context, 1);1449 advanceSpaces(context);1450 continue;1451 }1452 if (type === 1 /* End */) {1453 emitError(context, 3 /* END_TAG_WITH_ATTRIBUTES */);1454 }1455 const attr = parseAttribute(context, attributeNames);1456 // Trim whitespace between class1457 // https://github.com/vuejs/vue-next/issues/42511458 if (attr.type === 6 /* ATTRIBUTE */ &&1459 attr.value &&1460 attr.name === 'class') {1461 attr.value.content = attr.value.content.replace(/\s+/g, ' ').trim();1462 }1463 if (type === 0 /* Start */) {1464 props.push(attr);1465 }1466 if (/^[^\t\r\n\f />]/.test(context.source)) {1467 emitError(context, 15 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */);1468 }1469 advanceSpaces(context);1470 }1471 return props;1472}1473function parseAttribute(context, nameSet) {1474 // Name.1475 const start = getCursor(context);1476 const match = /^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(context.source);1477 const name = match[0];1478 if (nameSet.has(name)) {1479 emitError(context, 2 /* DUPLICATE_ATTRIBUTE */);1480 }1481 nameSet.add(name);1482 if (name[0] === '=') {1483 emitError(context, 19 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */);1484 }1485 {1486 const pattern = /["'<]/g;1487 let m;1488 while ((m = pattern.exec(name))) {1489 emitError(context, 17 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */, m.index);1490 }1491 }1492 advanceBy(context, name.length);1493 // Value1494 let value = undefined;1495 if (/^[\t\r\n\f ]*=/.test(context.source)) {1496 advanceSpaces(context);1497 advanceBy(context, 1);1498 advanceSpaces(context);1499 value = parseAttributeValue(context);1500 if (!value) {1501 emitError(context, 13 /* MISSING_ATTRIBUTE_VALUE */);1502 }1503 }1504 const loc = getSelection(context, start);1505 if (!context.inVPre && /^(v-[A-Za-z0-9-]|:|\.|@|#)/.test(name)) {1506 const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^\.|^@|^#)(\[[^\]]+\]|[^\.]+))?(.+)?$/i.exec(name);1507 let isPropShorthand = startsWith(name, '.');1508 let dirName = match[1] ||1509 (isPropShorthand || startsWith(name, ':')1510 ? 'bind'1511 : startsWith(name, '@')1512 ? 'on'1513 : 'slot');1514 let arg;1515 if (match[2]) {1516 const isSlot = dirName === 'slot';1517 const startOffset = name.lastIndexOf(match[2]);1518 const loc = getSelection(context, getNewPosition(context, start, startOffset), getNewPosition(context, start, startOffset + match[2].length + ((isSlot && match[3]) || '').length));1519 let content = match[2];1520 let isStatic = true;1521 if (content.startsWith('[')) {1522 isStatic = false;1523 if (!content.endsWith(']')) {1524 emitError(context, 27 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */);1525 content = content.slice(1);1526 }1527 else {1528 content = content.slice(1, content.length - 1);1529 }1530 }1531 else if (isSlot) {1532 // #1241 special case for v-slot: vuetify relies extensively on slot1533 // names containing dots. v-slot doesn't have any modifiers and Vue 2.x1534 // supports such usage so we are keeping it consistent with 2.x.1535 content += match[3] || '';1536 }1537 arg = {1538 type: 4 /* SIMPLE_EXPRESSION */,1539 content,1540 isStatic,1541 constType: isStatic1542 ? 3 /* CAN_STRINGIFY */1543 : 0 /* NOT_CONSTANT */,1544 loc1545 };1546 }1547 if (value && value.isQuoted) {1548 const valueLoc = value.loc;1549 valueLoc.start.offset++;1550 valueLoc.start.column++;1551 valueLoc.end = advancePositionWithClone(valueLoc.start, value.content);1552 valueLoc.source = valueLoc.source.slice(1, -1);1553 }1554 const modifiers = match[3] ? match[3].slice(1).split('.') : [];1555 if (isPropShorthand)1556 modifiers.push('prop');1557 // 2.x compat v-bind:foo.sync -> v-model:foo1558 if (dirName === 'bind' && arg) {1559 if (modifiers.includes('sync') &&1560 checkCompatEnabled("COMPILER_V_BIND_SYNC" /* COMPILER_V_BIND_SYNC */, context, loc, arg.loc.source)) {1561 dirName = 'model';1562 modifiers.splice(modifiers.indexOf('sync'), 1);1563 }1564 if (modifiers.includes('prop')) {1565 checkCompatEnabled("COMPILER_V_BIND_PROP" /* COMPILER_V_BIND_PROP */, context, loc);1566 }1567 }1568 return {1569 type: 7 /* DIRECTIVE */,1570 name: dirName,1571 exp: value && {1572 type: 4 /* SIMPLE_EXPRESSION */,1573 content: value.content,1574 isStatic: false,1575 // Treat as non-constant by default. This can be potentially set to1576 // other values by `transformExpression` to make it eligible for hoisting.1577 constType: 0 /* NOT_CONSTANT */,1578 loc: value.loc1579 },1580 arg,1581 modifiers,1582 loc1583 };1584 }1585 // missing directive name or illegal directive name1586 if (!context.inVPre && startsWith(name, 'v-')) {1587 emitError(context, 26 /* X_MISSING_DIRECTIVE_NAME */);1588 }1589 return {1590 type: 6 /* ATTRIBUTE */,1591 name,1592 value: value && {1593 type: 2 /* TEXT */,1594 content: value.content,1595 loc: value.loc1596 },1597 loc1598 };1599}1600function parseAttributeValue(context) {1601 const start = getCursor(context);1602 let content;1603 const quote = context.source[0];1604 const isQuoted = quote === `"` || quote === `'`;1605 if (isQuoted) {1606 // Quoted value.1607 advanceBy(context, 1);1608 const endIndex = context.source.indexOf(quote);1609 if (endIndex === -1) {1610 content = parseTextData(context, context.source.length, 4 /* ATTRIBUTE_VALUE */);1611 }1612 else {1613 content = parseTextData(context, endIndex, 4 /* ATTRIBUTE_VALUE */);1614 advanceBy(context, 1);1615 }1616 }1617 else {1618 // Unquoted1619 const match = /^[^\t\r\n\f >]+/.exec(context.source);1620 if (!match) {1621 return undefined;1622 }1623 const unexpectedChars = /["'<=`]/g;1624 let m;1625 while ((m = unexpectedChars.exec(match[0]))) {1626 emitError(context, 18 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */, m.index);1627 }1628 content = parseTextData(context, match[0].length, 4 /* ATTRIBUTE_VALUE */);1629 }1630 return { content, isQuoted, loc: getSelection(context, start) };1631}1632function parseInterpolation(context, mode) {1633 const [open, close] = context.options.delimiters;1634 const closeIndex = context.source.indexOf(close, open.length);1635 if (closeIndex === -1) {1636 emitError(context, 25 /* X_MISSING_INTERPOLATION_END */);1637 return undefined;1638 }1639 const start = getCursor(context);1640 advanceBy(context, open.length);1641 const innerStart = getCursor(context);1642 const innerEnd = getCursor(context);1643 const rawContentLength = closeIndex - open.length;1644 const rawContent = context.source.slice(0, rawContentLength);1645 const preTrimContent = parseTextData(context, rawContentLength, mode);1646 const content = preTrimContent.trim();1647 const startOffset = preTrimContent.indexOf(content);1648 if (startOffset > 0) {1649 advancePositionWithMutation(innerStart, rawContent, startOffset);1650 }1651 const endOffset = rawContentLength - (preTrimContent.length - content.length - startOffset);1652 advancePositionWithMutation(innerEnd, rawContent, endOffset);1653 advanceBy(context, close.length);1654 return {1655 type: 5 /* INTERPOLATION */,1656 content: {1657 type: 4 /* SIMPLE_EXPRESSION */,1658 isStatic: false,1659 // Set `isConstant` to false by default and will decide in transformExpression1660 constType: 0 /* NOT_CONSTANT */,1661 content,1662 loc: getSelection(context, innerStart, innerEnd)1663 },1664 loc: getSelection(context, start)1665 };1666}1667function parseText(context, mode) {1668 const endTokens = mode === 3 /* CDATA */ ? [']]>'] : ['<', context.options.delimiters[0]];1669 let endIndex = context.source.length;1670 for (let i = 0; i < endTokens.length; i++) {1671 const index = context.source.indexOf(endTokens[i], 1);1672 if (index !== -1 && endIndex > index) {1673 endIndex = index;1674 }1675 }1676 const start = getCursor(context);1677 const content = parseTextData(context, endIndex, mode);1678 return {1679 type: 2 /* TEXT */,1680 content,1681 loc: getSelection(context, start)1682 };1683}1684/**1685 * Get text data with a given length from the current location.1686 * This translates HTML entities in the text data.1687 */1688function parseTextData(context, length, mode) {1689 const rawText = context.source.slice(0, length);1690 advanceBy(context, length);1691 if (mode === 2 /* RAWTEXT */ ||1692 mode === 3 /* CDATA */ ||1693 rawText.indexOf('&') === -1) {1694 return rawText;1695 }1696 else {1697 // DATA or RCDATA containing "&"". Entity decoding required.1698 return context.options.decodeEntities(rawText, mode === 4 /* ATTRIBUTE_VALUE */);1699 }1700}1701function getCursor(context) {1702 const { column, line, offset } = context;1703 return { column, line, offset };1704}1705function getSelection(context, start, end) {1706 end = end || getCursor(context);1707 return {1708 start,1709 end,1710 source: context.originalSource.slice(start.offset, end.offset)1711 };1712}1713function last(xs) {1714 return xs[xs.length - 1];1715}1716function startsWith(source, searchString) {1717 return source.startsWith(searchString);1718}1719function advanceBy(context, numberOfCharacters) {1720 const { source } = context;1721 advancePositionWithMutation(context, source, numberOfCharacters);1722 context.source = source.slice(numberOfCharacters);1723}1724function advanceSpaces(context) {1725 const match = /^[\t\r\n\f ]+/.exec(context.source);1726 if (match) {1727 advanceBy(context, match[0].length);1728 }1729}1730function getNewPosition(context, start, numberOfCharacters) {1731 return advancePositionWithClone(start, context.originalSource.slice(start.offset, numberOfCharacters), numberOfCharacters);1732}1733function emitError(context, code, offset, loc = getCursor(context)) {1734 if (offset) {1735 loc.offset += offset;1736 loc.column += offset;1737 }1738 context.options.onError(createCompilerError(code, {1739 start: loc,1740 end: loc,1741 source: ''1742 }));1743}1744function isEnd(context, mode, ancestors) {1745 const s = context.source;1746 switch (mode) {1747 case 0 /* DATA */:1748 if (startsWith(s, '</')) {1749 // TODO: probably bad performance1750 for (let i = ancestors.length - 1; i >= 0; --i) {1751 if (startsWithEndTagOpen(s, ancestors[i].tag)) {1752 return true;1753 }1754 }1755 }1756 break;1757 case 1 /* RCDATA */:1758 case 2 /* RAWTEXT */: {1759 const parent = last(ancestors);1760 if (parent && startsWithEndTagOpen(s, parent.tag)) {1761 return true;1762 }1763 break;1764 }1765 case 3 /* CDATA */:1766 if (startsWith(s, ']]>')) {1767 return true;1768 }1769 break;1770 }1771 return !s;1772}1773function startsWithEndTagOpen(source, tag) {1774 return (startsWith(source, '</') &&1775 source.slice(2, 2 + tag.length).toLowerCase() === tag.toLowerCase() &&1776 /[\t\r\n\f />]/.test(source[2 + tag.length] || '>'));1777}1778function hoistStatic(root, context) {1779 walk(root, context, 1780 // Root node is unfortunately non-hoistable due to potential parent1781 // fallthrough attributes.1782 isSingleElementRoot(root, root.children[0]));1783}1784function isSingleElementRoot(root, child) {1785 const { children } = root;1786 return (children.length === 1 &&1787 child.type === 1 /* ELEMENT */ &&1788 !isSlotOutlet(child));1789}1790function walk(node, context, doNotHoistNode = false) {1791 const { children } = node;1792 const originalCount = children.length;1793 let hoistedCount = 0;1794 for (let i = 0; i < children.length; i++) {1795 const child = children[i];1796 // only plain elements & text calls are eligible for hoisting.1797 if (child.type === 1 /* ELEMENT */ &&1798 child.tagType === 0 /* ELEMENT */) {1799 const constantType = doNotHoistNode1800 ? 0 /* NOT_CONSTANT */1801 : getConstantType(child, context);1802 if (constantType > 0 /* NOT_CONSTANT */) {1803 if (constantType >= 2 /* CAN_HOIST */) {1804 child.codegenNode.patchFlag =1805 -1 /* HOISTED */ + (` /* HOISTED */` );1806 child.codegenNode = context.hoist(child.codegenNode);1807 hoistedCount++;1808 continue;1809 }1810 }1811 else {1812 // node may contain dynamic children, but its props may be eligible for1813 // hoisting.1814 const codegenNode = child.codegenNode;1815 if (codegenNode.type === 13 /* VNODE_CALL */) {1816 const flag = getPatchFlag(codegenNode);1817 if ((!flag ||1818 flag === 512 /* NEED_PATCH */ ||1819 flag === 1 /* TEXT */) &&1820 getGeneratedPropsConstantType(child, context) >=1821 2 /* CAN_HOIST */) {1822 const props = getNodeProps(child);1823 if (props) {1824 codegenNode.props = context.hoist(props);1825 }1826 }1827 if (codegenNode.dynamicProps) {1828 codegenNode.dynamicProps = context.hoist(codegenNode.dynamicProps);1829 }1830 }1831 }1832 }1833 else if (child.type === 12 /* TEXT_CALL */ &&1834 getConstantType(child.content, context) >= 2 /* CAN_HOIST */) {1835 child.codegenNode = context.hoist(child.codegenNode);1836 hoistedCount++;1837 }1838 // walk further1839 if (child.type === 1 /* ELEMENT */) {1840 const isComponent = child.tagType === 1 /* COMPONENT */;1841 if (isComponent) {1842 context.scopes.vSlot++;1843 }1844 walk(child, context);1845 if (isComponent) {1846 context.scopes.vSlot--;1847 }1848 }1849 else if (child.type === 11 /* FOR */) {1850 // Do not hoist v-for single child because it has to be a block1851 walk(child, context, child.children.length === 1);1852 }1853 else if (child.type === 9 /* IF */) {1854 for (let i = 0; i < child.branches.length; i++) {1855 // Do not hoist v-if single child because it has to be a block1856 walk(child.branches[i], context, child.branches[i].children.length === 1);1857 }1858 }1859 }1860 if (hoistedCount && context.transformHoist) {1861 context.transformHoist(children, context, node);1862 }1863 // all children were hoisted - the entire children array is hoistable.1864 if (hoistedCount &&1865 hoistedCount === originalCount &&1866 node.type === 1 /* ELEMENT */ &&1867 node.tagType === 0 /* ELEMENT */ &&1868 node.codegenNode &&1869 node.codegenNode.type === 13 /* VNODE_CALL */ &&1870 isArray(node.codegenNode.children)) {1871 node.codegenNode.children = context.hoist(createArrayExpression(node.codegenNode.children));1872 }1873}1874function getConstantType(node, context) {1875 const { constantCache } = context;1876 switch (node.type) {1877 case 1 /* ELEMENT */:1878 if (node.tagType !== 0 /* ELEMENT */) {1879 return 0 /* NOT_CONSTANT */;1880 }1881 const cached = constantCache.get(node);1882 if (cached !== undefined) {1883 return cached;1884 }1885 const codegenNode = node.codegenNode;1886 if (codegenNode.type !== 13 /* VNODE_CALL */) {1887 return 0 /* NOT_CONSTANT */;1888 }1889 if (codegenNode.isBlock &&1890 node.tag !== 'svg' &&1891 node.tag !== 'foreignObject') {1892 return 0 /* NOT_CONSTANT */;1893 }1894 const flag = getPatchFlag(codegenNode);1895 if (!flag) {1896 let returnType = 3 /* CAN_STRINGIFY */;1897 // Element itself has no patch flag. However we still need to check:1898 // 1. Even for a node with no patch flag, it is possible for it to contain1899 // non-hoistable expressions that refers to scope variables, e.g. compiler1900 // injected keys or cached event handlers. Therefore we need to always1901 // check the codegenNode's props to be sure.1902 const generatedPropsType = getGeneratedPropsConstantType(node, context);1903 if (generatedPropsType === 0 /* NOT_CONSTANT */) {1904 constantCache.set(node, 0 /* NOT_CONSTANT */);1905 return 0 /* NOT_CONSTANT */;1906 }1907 if (generatedPropsType < returnType) {1908 returnType = generatedPropsType;1909 }1910 // 2. its children.1911 for (let i = 0; i < node.children.length; i++) {1912 const childType = getConstantType(node.children[i], context);1913 if (childType === 0 /* NOT_CONSTANT */) {1914 constantCache.set(node, 0 /* NOT_CONSTANT */);1915 return 0 /* NOT_CONSTANT */;1916 }1917 if (childType < returnType) {1918 returnType = childType;1919 }1920 }1921 // 3. if the type is not already CAN_SKIP_PATCH which is the lowest non-01922 // type, check if any of the props can cause the type to be lowered1923 // we can skip can_patch because it's guaranteed by the absence of a1924 // patchFlag.1925 if (returnType > 1 /* CAN_SKIP_PATCH */) {1926 for (let i = 0; i < node.props.length; i++) {1927 const p = node.props[i];1928 if (p.type === 7 /* DIRECTIVE */ && p.name === 'bind' && p.exp) {1929 const expType = getConstantType(p.exp, context);1930 if (expType === 0 /* NOT_CONSTANT */) {1931 constantCache.set(node, 0 /* NOT_CONSTANT */);1932 return 0 /* NOT_CONSTANT */;1933 }1934 if (expType < returnType) {1935 returnType = expType;1936 }1937 }1938 }1939 }1940 // only svg/foreignObject could be block here, however if they are1941 // static then they don't need to be blocks since there will be no1942 // nested updates.1943 if (codegenNode.isBlock) {1944 context.removeHelper(OPEN_BLOCK);1945 context.removeHelper(getVNodeBlockHelper(context.inSSR, codegenNode.isComponent));1946 codegenNode.isBlock = false;1947 context.helper(getVNodeHelper(context.inSSR, codegenNode.isComponent));1948 }1949 constantCache.set(node, returnType);1950 return returnType;1951 }1952 else {1953 constantCache.set(node, 0 /* NOT_CONSTANT */);1954 return 0 /* NOT_CONSTANT */;1955 }1956 case 2 /* TEXT */:1957 case 3 /* COMMENT */:1958 return 3 /* CAN_STRINGIFY */;1959 case 9 /* IF */:1960 case 11 /* FOR */:1961 case 10 /* IF_BRANCH */:1962 return 0 /* NOT_CONSTANT */;1963 case 5 /* INTERPOLATION */:1964 case 12 /* TEXT_CALL */:1965 return getConstantType(node.content, context);1966 case 4 /* SIMPLE_EXPRESSION */:1967 return node.constType;1968 case 8 /* COMPOUND_EXPRESSION */:1969 let returnType = 3 /* CAN_STRINGIFY */;1970 for (let i = 0; i < node.children.length; i++) {1971 const child = node.children[i];1972 if (isString(child) || isSymbol(child)) {1973 continue;1974 }1975 const childType = getConstantType(child, context);1976 if (childType === 0 /* NOT_CONSTANT */) {1977 return 0 /* NOT_CONSTANT */;1978 }1979 else if (childType < returnType) {1980 returnType = childType;1981 }1982 }1983 return returnType;1984 default:1985 return 0 /* NOT_CONSTANT */;1986 }1987}1988const allowHoistedHelperSet = new Set([1989 NORMALIZE_CLASS,1990 NORMALIZE_STYLE,1991 NORMALIZE_PROPS,1992 GUARD_REACTIVE_PROPS1993]);1994function getConstantTypeOfHelperCall(value, context) {1995 if (value.type === 14 /* JS_CALL_EXPRESSION */ &&1996 !isString(value.callee) &&1997 allowHoistedHelperSet.has(value.callee)) {1998 const arg = value.arguments[0];1999 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {2000 return getConstantType(arg, context);2001 }2002 else if (arg.type === 14 /* JS_CALL_EXPRESSION */) {2003 // in the case of nested helper call, e.g. `normalizeProps(guardReactiveProps(exp))`2004 return getConstantTypeOfHelperCall(arg, context);2005 }2006 }2007 return 0 /* NOT_CONSTANT */;2008}2009function getGeneratedPropsConstantType(node, context) {2010 let returnType = 3 /* CAN_STRINGIFY */;2011 const props = getNodeProps(node);2012 if (props && props.type === 15 /* JS_OBJECT_EXPRESSION */) {2013 const { properties } = props;2014 for (let i = 0; i < properties.length; i++) {2015 const { key, value } = properties[i];2016 const keyType = getConstantType(key, context);2017 if (keyType === 0 /* NOT_CONSTANT */) {2018 return keyType;2019 }2020 if (keyType < returnType) {2021 returnType = keyType;2022 }2023 let valueType;2024 if (value.type === 4 /* SIMPLE_EXPRESSION */) {2025 valueType = getConstantType(value, context);2026 }2027 else if (value.type === 14 /* JS_CALL_EXPRESSION */) {2028 // some helper calls can be hoisted,2029 // such as the `normalizeProps` generated by the compiler for pre-normalize class,2030 // in this case we need to respect the ConstantType of the helper's arguments2031 valueType = getConstantTypeOfHelperCall(value, context);2032 }2033 else {2034 valueType = 0 /* NOT_CONSTANT */;2035 }2036 if (valueType === 0 /* NOT_CONSTANT */) {2037 return valueType;2038 }2039 if (valueType < returnType) {2040 returnType = valueType;2041 }2042 }2043 }2044 return returnType;2045}2046function getNodeProps(node) {2047 const codegenNode = node.codegenNode;2048 if (codegenNode.type === 13 /* VNODE_CALL */) {2049 return codegenNode.props;2050 }2051}2052function getPatchFlag(node) {2053 const flag = node.patchFlag;2054 return flag ? parseInt(flag, 10) : undefined;2055}2056function createTransformContext(root, { filename = '', prefixIdentifiers = false, hoistStatic = false, cacheHandlers = false, nodeTransforms = [], directiveTransforms = {}, transformHoist = null, isBuiltInComponent = NOOP, isCustomElement = NOOP, expressionPlugins = [], scopeId = null, slotted = true, ssr = false, inSSR = false, ssrCssVars = ``, bindingMetadata = EMPTY_OBJ, inline = false, isTS = false, onError = defaultOnError, onWarn = defaultOnWarn, compatConfig }) {2057 const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/);2058 const context = {2059 // options2060 selfName: nameMatch && capitalize(camelize(nameMatch[1])),2061 prefixIdentifiers,2062 hoistStatic,2063 cacheHandlers,2064 nodeTransforms,2065 directiveTransforms,2066 transformHoist,2067 isBuiltInComponent,2068 isCustomElement,2069 expressionPlugins,2070 scopeId,2071 slotted,2072 ssr,2073 inSSR,2074 ssrCssVars,2075 bindingMetadata,2076 inline,2077 isTS,2078 onError,2079 onWarn,2080 compatConfig,2081 // state2082 root,2083 helpers: new Map(),2084 components: new Set(),2085 directives: new Set(),2086 hoists: [],2087 imports: [],2088 constantCache: new Map(),2089 temps: 0,2090 cached: 0,2091 identifiers: Object.create(null),2092 scopes: {2093 vFor: 0,2094 vSlot: 0,2095 vPre: 0,2096 vOnce: 02097 },2098 parent: null,2099 currentNode: root,2100 childIndex: 0,2101 inVOnce: false,2102 // methods2103 helper(name) {2104 const count = context.helpers.get(name) || 0;2105 context.helpers.set(name, count + 1);2106 return name;2107 },2108 removeHelper(name) {2109 const count = context.helpers.get(name);2110 if (count) {2111 const currentCount = count - 1;2112 if (!currentCount) {2113 context.helpers.delete(name);2114 }2115 else {2116 context.helpers.set(name, currentCount);2117 }2118 }2119 },2120 helperString(name) {2121 return `_${helperNameMap[context.helper(name)]}`;2122 },2123 replaceNode(node) {2124 /* istanbul ignore if */2125 {2126 if (!context.currentNode) {2127 throw new Error(`Node being replaced is already removed.`);2128 }2129 if (!context.parent) {2130 throw new Error(`Cannot replace root node.`);2131 }2132 }2133 context.parent.children[context.childIndex] = context.currentNode = node;2134 },2135 removeNode(node) {2136 if (!context.parent) {2137 throw new Error(`Cannot remove root node.`);2138 }2139 const list = context.parent.children;2140 const removalIndex = node2141 ? list.indexOf(node)2142 : context.currentNode2143 ? context.childIndex2144 : -1;2145 /* istanbul ignore if */2146 if (removalIndex < 0) {2147 throw new Error(`node being removed is not a child of current parent`);2148 }2149 if (!node || node === context.currentNode) {2150 // current node removed2151 context.currentNode = null;2152 context.onNodeRemoved();2153 }2154 else {2155 // sibling node removed2156 if (context.childIndex > removalIndex) {2157 context.childIndex--;2158 context.onNodeRemoved();2159 }2160 }2161 context.parent.children.splice(removalIndex, 1);2162 },2163 onNodeRemoved: () => { },2164 addIdentifiers(exp) {2165 },2166 removeIdentifiers(exp) {2167 },2168 hoist(exp) {2169 if (isString(exp))2170 exp = createSimpleExpression(exp);2171 context.hoists.push(exp);2172 const identifier = createSimpleExpression(`_hoisted_${context.hoists.length}`, false, exp.loc, 2 /* CAN_HOIST */);2173 identifier.hoisted = exp;2174 return identifier;2175 },2176 cache(exp, isVNode = false) {2177 return createCacheExpression(context.cached++, exp, isVNode);2178 }2179 };2180 {2181 context.filters = new Set();2182 }2183 return context;2184}2185function transform(root, options) {2186 const context = createTransformContext(root, options);2187 traverseNode(root, context);2188 if (options.hoistStatic) {2189 hoistStatic(root, context);2190 }2191 if (!options.ssr) {2192 createRootCodegen(root, context);2193 }2194 // finalize meta information2195 root.helpers = [...context.helpers.keys()];2196 root.components = [...context.components];2197 root.directives = [...context.directives];2198 root.imports = context.imports;2199 root.hoists = context.hoists;2200 root.temps = context.temps;2201 root.cached = context.cached;2202 {2203 root.filters = [...context.filters];2204 }2205}2206function createRootCodegen(root, context) {2207 const { helper } = context;2208 const { children } = root;2209 if (children.length === 1) {2210 const child = children[0];2211 // if the single child is an element, turn it into a block.2212 if (isSingleElementRoot(root, child) && child.codegenNode) {2213 // single element root is never hoisted so codegenNode will never be2214 // SimpleExpressionNode2215 const codegenNode = child.codegenNode;2216 if (codegenNode.type === 13 /* VNODE_CALL */) {2217 makeBlock(codegenNode, context);2218 }2219 root.codegenNode = codegenNode;2220 }2221 else {2222 // - single <slot/>, IfNode, ForNode: already blocks.2223 // - single text node: always patched.2224 // root codegen falls through via genNode()2225 root.codegenNode = child;2226 }2227 }2228 else if (children.length > 1) {2229 // root has multiple nodes - return a fragment block.2230 let patchFlag = 64 /* STABLE_FRAGMENT */;2231 let patchFlagText = PatchFlagNames[64 /* STABLE_FRAGMENT */];2232 // check if the fragment actually contains a single valid child with2233 // the rest being comments2234 if (children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {2235 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;2236 patchFlagText += `, ${PatchFlagNames[2048 /* DEV_ROOT_FRAGMENT */]}`;2237 }2238 root.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, root.children, patchFlag + (` /* ${patchFlagText} */` ), undefined, undefined, true, undefined, false /* isComponent */);2239 }2240 else ;2241}2242function traverseChildren(parent, context) {2243 let i = 0;2244 const nodeRemoved = () => {2245 i--;2246 };2247 for (; i < parent.children.length; i++) {2248 const child = parent.children[i];2249 if (isString(child))2250 continue;2251 context.parent = parent;2252 context.childIndex = i;2253 context.onNodeRemoved = nodeRemoved;2254 traverseNode(child, context);2255 }2256}2257function traverseNode(node, context) {2258 context.currentNode = node;2259 // apply transform plugins2260 const { nodeTransforms } = context;2261 const exitFns = [];2262 for (let i = 0; i < nodeTransforms.length; i++) {2263 const onExit = nodeTransforms[i](node, context);2264 if (onExit) {2265 if (isArray(onExit)) {2266 exitFns.push(...onExit);2267 }2268 else {2269 exitFns.push(onExit);2270 }2271 }2272 if (!context.currentNode) {2273 // node was removed2274 return;2275 }2276 else {2277 // node may have been replaced2278 node = context.currentNode;2279 }2280 }2281 switch (node.type) {2282 case 3 /* COMMENT */:2283 if (!context.ssr) {2284 // inject import for the Comment symbol, which is needed for creating2285 // comment nodes with `createVNode`2286 context.helper(CREATE_COMMENT);2287 }2288 break;2289 case 5 /* INTERPOLATION */:2290 // no need to traverse, but we need to inject toString helper2291 if (!context.ssr) {2292 context.helper(TO_DISPLAY_STRING);2293 }2294 break;2295 // for container types, further traverse downwards2296 case 9 /* IF */:2297 for (let i = 0; i < node.branches.length; i++) {2298 traverseNode(node.branches[i], context);2299 }2300 break;2301 case 10 /* IF_BRANCH */:2302 case 11 /* FOR */:2303 case 1 /* ELEMENT */:2304 case 0 /* ROOT */:2305 traverseChildren(node, context);2306 break;2307 }2308 // exit transforms2309 context.currentNode = node;2310 let i = exitFns.length;2311 while (i--) {2312 exitFns[i]();2313 }2314}2315function createStructuralDirectiveTransform(name, fn) {2316 const matches = isString(name)2317 ? (n) => n === name2318 : (n) => name.test(n);2319 return (node, context) => {2320 if (node.type === 1 /* ELEMENT */) {2321 const { props } = node;2322 // structural directive transforms are not concerned with slots2323 // as they are handled separately in vSlot.ts2324 if (node.tagType === 3 /* TEMPLATE */ && props.some(isVSlot)) {2325 return;2326 }2327 const exitFns = [];2328 for (let i = 0; i < props.length; i++) {2329 const prop = props[i];2330 if (prop.type === 7 /* DIRECTIVE */ && matches(prop.name)) {2331 // structural directives are removed to avoid infinite recursion2332 // also we remove them *before* applying so that it can further2333 // traverse itself in case it moves the node around2334 props.splice(i, 1);2335 i--;2336 const onExit = fn(node, prop, context);2337 if (onExit)2338 exitFns.push(onExit);2339 }2340 }2341 return exitFns;2342 }2343 };2344}2345const PURE_ANNOTATION = `/*#__PURE__*/`;2346function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssrRuntimeModuleName = 'vue/server-renderer', ssr = false, isTS = false, inSSR = false }) {2347 const context = {2348 mode,2349 prefixIdentifiers,2350 sourceMap,2351 filename,2352 scopeId,2353 optimizeImports,2354 runtimeGlobalName,2355 runtimeModuleName,2356 ssrRuntimeModuleName,2357 ssr,2358 isTS,2359 inSSR,2360 source: ast.loc.source,2361 code: ``,2362 column: 1,2363 line: 1,2364 offset: 0,2365 indentLevel: 0,2366 pure: false,2367 map: undefined,2368 helper(key) {2369 return `_${helperNameMap[key]}`;2370 },2371 push(code, node) {2372 context.code += code;2373 },2374 indent() {2375 newline(++context.indentLevel);2376 },2377 deindent(withoutNewLine = false) {2378 if (withoutNewLine) {2379 --context.indentLevel;2380 }2381 else {2382 newline(--context.indentLevel);2383 }2384 },2385 newline() {2386 newline(context.indentLevel);2387 }2388 };2389 function newline(n) {2390 context.push('\n' + ` `.repeat(n));2391 }2392 return context;2393}2394function generate(ast, options = {}) {2395 const context = createCodegenContext(ast, options);2396 if (options.onContextCreated)2397 options.onContextCreated(context);2398 const { mode, push, prefixIdentifiers, indent, deindent, newline, scopeId, ssr } = context;2399 const hasHelpers = ast.helpers.length > 0;2400 const useWithBlock = !prefixIdentifiers && mode !== 'module';2401 // preambles2402 // in setup() inline mode, the preamble is generated in a sub context2403 // and returned separately.2404 const preambleContext = context;2405 {2406 genFunctionPreamble(ast, preambleContext);2407 }2408 // enter render function2409 const functionName = ssr ? `ssrRender` : `render`;2410 const args = ssr ? ['_ctx', '_push', '_parent', '_attrs'] : ['_ctx', '_cache'];2411 const signature = args.join(', ');2412 {2413 push(`function ${functionName}(${signature}) {`);2414 }2415 indent();2416 if (useWithBlock) {2417 push(`with (_ctx) {`);2418 indent();2419 // function mode const declarations should be inside with block2420 // also they should be renamed to avoid collision with user properties2421 if (hasHelpers) {2422 push(`const { ${ast.helpers2423 .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)2424 .join(', ')} } = _Vue`);2425 push(`\n`);2426 newline();2427 }2428 }2429 // generate asset resolution statements2430 if (ast.components.length) {2431 genAssets(ast.components, 'component', context);2432 if (ast.directives.length || ast.temps > 0) {2433 newline();2434 }2435 }2436 if (ast.directives.length) {2437 genAssets(ast.directives, 'directive', context);2438 if (ast.temps > 0) {2439 newline();2440 }2441 }2442 if (ast.filters && ast.filters.length) {2443 newline();2444 genAssets(ast.filters, 'filter', context);2445 newline();2446 }2447 if (ast.temps > 0) {2448 push(`let `);2449 for (let i = 0; i < ast.temps; i++) {2450 push(`${i > 0 ? `, ` : ``}_temp${i}`);2451 }2452 }2453 if (ast.components.length || ast.directives.length || ast.temps) {2454 push(`\n`);2455 newline();2456 }2457 // generate the VNode tree expression2458 if (!ssr) {2459 push(`return `);2460 }2461 if (ast.codegenNode) {2462 genNode(ast.codegenNode, context);2463 }2464 else {2465 push(`null`);2466 }2467 if (useWithBlock) {2468 deindent();2469 push(`}`);2470 }2471 deindent();2472 push(`}`);2473 return {2474 ast,2475 code: context.code,2476 preamble: ``,2477 // SourceMapGenerator does have toJSON() method but it's not in the types2478 map: context.map ? context.map.toJSON() : undefined2479 };2480}2481function genFunctionPreamble(ast, context) {2482 const { ssr, prefixIdentifiers, push, newline, runtimeModuleName, runtimeGlobalName, ssrRuntimeModuleName } = context;2483 const VueBinding = runtimeGlobalName;2484 const aliasHelper = (s) => `${helperNameMap[s]}: _${helperNameMap[s]}`;2485 // Generate const declaration for helpers2486 // In prefix mode, we place the const declaration at top so it's done2487 // only once; But if we not prefixing, we place the declaration inside the2488 // with block so it doesn't incur the `in` check cost for every helper access.2489 if (ast.helpers.length > 0) {2490 {2491 // "with" mode.2492 // save Vue in a separate variable to avoid collision2493 push(`const _Vue = ${VueBinding}\n`);2494 // in "with" mode, helpers are declared inside the with block to avoid2495 // has check cost, but hoists are lifted out of the function - we need2496 // to provide the helper here.2497 if (ast.hoists.length) {2498 const staticHelpers = [2499 CREATE_VNODE,2500 CREATE_ELEMENT_VNODE,2501 CREATE_COMMENT,2502 CREATE_TEXT,2503 CREATE_STATIC2504 ]2505 .filter(helper => ast.helpers.includes(helper))2506 .map(aliasHelper)2507 .join(', ');2508 push(`const { ${staticHelpers} } = _Vue\n`);2509 }2510 }2511 }2512 genHoists(ast.hoists, context);2513 newline();2514 push(`return `);2515}2516function genAssets(assets, type, { helper, push, newline, isTS }) {2517 const resolver = helper(type === 'filter'2518 ? RESOLVE_FILTER2519 : type === 'component'2520 ? RESOLVE_COMPONENT2521 : RESOLVE_DIRECTIVE);2522 for (let i = 0; i < assets.length; i++) {2523 let id = assets[i];2524 // potential component implicit self-reference inferred from SFC filename2525 const maybeSelfReference = id.endsWith('__self');2526 if (maybeSelfReference) {2527 id = id.slice(0, -6);2528 }2529 push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`);2530 if (i < assets.length - 1) {2531 newline();2532 }2533 }2534}2535function genHoists(hoists, context) {2536 if (!hoists.length) {2537 return;2538 }2539 context.pure = true;2540 const { push, newline, helper, scopeId, mode } = context;2541 newline();2542 for (let i = 0; i < hoists.length; i++) {2543 const exp = hoists[i];2544 if (exp) {2545 push(`const _hoisted_${i + 1} = ${``}`);2546 genNode(exp, context);2547 newline();2548 }2549 }2550 context.pure = false;2551}2552function isText$1(n) {2553 return (isString(n) ||2554 n.type === 4 /* SIMPLE_EXPRESSION */ ||2555 n.type === 2 /* TEXT */ ||2556 n.type === 5 /* INTERPOLATION */ ||2557 n.type === 8 /* COMPOUND_EXPRESSION */);2558}2559function genNodeListAsArray(nodes, context) {2560 const multilines = nodes.length > 3 ||2561 (nodes.some(n => isArray(n) || !isText$1(n)));2562 context.push(`[`);2563 multilines && context.indent();2564 genNodeList(nodes, context, multilines);2565 multilines && context.deindent();2566 context.push(`]`);2567}2568function genNodeList(nodes, context, multilines = false, comma = true) {2569 const { push, newline } = context;2570 for (let i = 0; i < nodes.length; i++) {2571 const node = nodes[i];2572 if (isString(node)) {2573 push(node);2574 }2575 else if (isArray(node)) {2576 genNodeListAsArray(node, context);2577 }2578 else {2579 genNode(node, context);2580 }2581 if (i < nodes.length - 1) {2582 if (multilines) {2583 comma && push(',');2584 newline();2585 }2586 else {2587 comma && push(', ');2588 }2589 }2590 }2591}2592function genNode(node, context) {2593 if (isString(node)) {2594 context.push(node);2595 return;2596 }2597 if (isSymbol(node)) {2598 context.push(context.helper(node));2599 return;2600 }2601 switch (node.type) {2602 case 1 /* ELEMENT */:2603 case 9 /* IF */:2604 case 11 /* FOR */:2605 assert(node.codegenNode != null, `Codegen node is missing for element/if/for node. ` +2606 `Apply appropriate transforms first.`);2607 genNode(node.codegenNode, context);2608 break;2609 case 2 /* TEXT */:2610 genText(node, context);2611 break;2612 case 4 /* SIMPLE_EXPRESSION */:2613 genExpression(node, context);2614 break;2615 case 5 /* INTERPOLATION */:2616 genInterpolation(node, context);2617 break;2618 case 12 /* TEXT_CALL */:2619 genNode(node.codegenNode, context);2620 break;2621 case 8 /* COMPOUND_EXPRESSION */:2622 genCompoundExpression(node, context);2623 break;2624 case 3 /* COMMENT */:2625 genComment(node, context);2626 break;2627 case 13 /* VNODE_CALL */:2628 genVNodeCall(node, context);2629 break;2630 case 14 /* JS_CALL_EXPRESSION */:2631 genCallExpression(node, context);2632 break;2633 case 15 /* JS_OBJECT_EXPRESSION */:2634 genObjectExpression(node, context);2635 break;2636 case 17 /* JS_ARRAY_EXPRESSION */:2637 genArrayExpression(node, context);2638 break;2639 case 18 /* JS_FUNCTION_EXPRESSION */:2640 genFunctionExpression(node, context);2641 break;2642 case 19 /* JS_CONDITIONAL_EXPRESSION */:2643 genConditionalExpression(node, context);2644 break;2645 case 20 /* JS_CACHE_EXPRESSION */:2646 genCacheExpression(node, context);2647 break;2648 case 21 /* JS_BLOCK_STATEMENT */:2649 genNodeList(node.body, context, true, false);2650 break;2651 // SSR only types2652 case 22 /* JS_TEMPLATE_LITERAL */:2653 break;2654 case 23 /* JS_IF_STATEMENT */:2655 break;2656 case 24 /* JS_ASSIGNMENT_EXPRESSION */:2657 break;2658 case 25 /* JS_SEQUENCE_EXPRESSION */:2659 break;2660 case 26 /* JS_RETURN_STATEMENT */:2661 break;2662 /* istanbul ignore next */2663 case 10 /* IF_BRANCH */:2664 // noop2665 break;2666 default:2667 {2668 assert(false, `unhandled codegen node type: ${node.type}`);2669 // make sure we exhaust all possible types2670 const exhaustiveCheck = node;2671 return exhaustiveCheck;2672 }2673 }2674}2675function genText(node, context) {2676 context.push(JSON.stringify(node.content), node);2677}2678function genExpression(node, context) {2679 const { content, isStatic } = node;2680 context.push(isStatic ? JSON.stringify(content) : content, node);2681}2682function genInterpolation(node, context) {2683 const { push, helper, pure } = context;2684 if (pure)2685 push(PURE_ANNOTATION);2686 push(`${helper(TO_DISPLAY_STRING)}(`);2687 genNode(node.content, context);2688 push(`)`);2689}2690function genCompoundExpression(node, context) {2691 for (let i = 0; i < node.children.length; i++) {2692 const child = node.children[i];2693 if (isString(child)) {2694 context.push(child);2695 }2696 else {2697 genNode(child, context);2698 }2699 }2700}2701function genExpressionAsPropertyKey(node, context) {2702 const { push } = context;2703 if (node.type === 8 /* COMPOUND_EXPRESSION */) {2704 push(`[`);2705 genCompoundExpression(node, context);2706 push(`]`);2707 }2708 else if (node.isStatic) {2709 // only quote keys if necessary2710 const text = isSimpleIdentifier(node.content)2711 ? node.content2712 : JSON.stringify(node.content);2713 push(text, node);2714 }2715 else {2716 push(`[${node.content}]`, node);2717 }2718}2719function genComment(node, context) {2720 const { push, helper, pure } = context;2721 if (pure) {2722 push(PURE_ANNOTATION);2723 }2724 push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node);2725}2726function genVNodeCall(node, context) {2727 const { push, helper, pure } = context;2728 const { tag, props, children, patchFlag, dynamicProps, directives, isBlock, disableTracking, isComponent } = node;2729 if (directives) {2730 push(helper(WITH_DIRECTIVES) + `(`);2731 }2732 if (isBlock) {2733 push(`(${helper(OPEN_BLOCK)}(${disableTracking ? `true` : ``}), `);2734 }2735 if (pure) {2736 push(PURE_ANNOTATION);2737 }2738 const callHelper = isBlock2739 ? getVNodeBlockHelper(context.inSSR, isComponent)2740 : getVNodeHelper(context.inSSR, isComponent);2741 push(helper(callHelper) + `(`, node);2742 genNodeList(genNullableArgs([tag, props, children, patchFlag, dynamicProps]), context);2743 push(`)`);2744 if (isBlock) {2745 push(`)`);2746 }2747 if (directives) {2748 push(`, `);2749 genNode(directives, context);2750 push(`)`);2751 }2752}2753function genNullableArgs(args) {2754 let i = args.length;2755 while (i--) {2756 if (args[i] != null)2757 break;2758 }2759 return args.slice(0, i + 1).map(arg => arg || `null`);2760}2761// JavaScript2762function genCallExpression(node, context) {2763 const { push, helper, pure } = context;2764 const callee = isString(node.callee) ? node.callee : helper(node.callee);2765 if (pure) {2766 push(PURE_ANNOTATION);2767 }2768 push(callee + `(`, node);2769 genNodeList(node.arguments, context);2770 push(`)`);2771}2772function genObjectExpression(node, context) {2773 const { push, indent, deindent, newline } = context;2774 const { properties } = node;2775 if (!properties.length) {2776 push(`{}`, node);2777 return;2778 }2779 const multilines = properties.length > 1 ||2780 (properties.some(p => p.value.type !== 4 /* SIMPLE_EXPRESSION */));2781 push(multilines ? `{` : `{ `);2782 multilines && indent();2783 for (let i = 0; i < properties.length; i++) {2784 const { key, value } = properties[i];2785 // key2786 genExpressionAsPropertyKey(key, context);2787 push(`: `);2788 // value2789 genNode(value, context);2790 if (i < properties.length - 1) {2791 // will only reach this if it's multilines2792 push(`,`);2793 newline();2794 }2795 }2796 multilines && deindent();2797 push(multilines ? `}` : ` }`);2798}2799function genArrayExpression(node, context) {2800 genNodeListAsArray(node.elements, context);2801}2802function genFunctionExpression(node, context) {2803 const { push, indent, deindent } = context;2804 const { params, returns, body, newline, isSlot } = node;2805 if (isSlot) {2806 // wrap slot functions with owner context2807 push(`_${helperNameMap[WITH_CTX]}(`);2808 }2809 push(`(`, node);2810 if (isArray(params)) {2811 genNodeList(params, context);2812 }2813 else if (params) {2814 genNode(params, context);2815 }2816 push(`) => `);2817 if (newline || body) {2818 push(`{`);2819 indent();2820 }2821 if (returns) {2822 if (newline) {2823 push(`return `);2824 }2825 if (isArray(returns)) {2826 genNodeListAsArray(returns, context);2827 }2828 else {2829 genNode(returns, context);2830 }2831 }2832 else if (body) {2833 genNode(body, context);2834 }2835 if (newline || body) {2836 deindent();2837 push(`}`);2838 }2839 if (isSlot) {2840 if (node.isNonScopedSlot) {2841 push(`, undefined, true`);2842 }2843 push(`)`);2844 }2845}2846function genConditionalExpression(node, context) {2847 const { test, consequent, alternate, newline: needNewline } = node;2848 const { push, indent, deindent, newline } = context;2849 if (test.type === 4 /* SIMPLE_EXPRESSION */) {2850 const needsParens = !isSimpleIdentifier(test.content);2851 needsParens && push(`(`);2852 genExpression(test, context);2853 needsParens && push(`)`);2854 }2855 else {2856 push(`(`);2857 genNode(test, context);2858 push(`)`);2859 }2860 needNewline && indent();2861 context.indentLevel++;2862 needNewline || push(` `);2863 push(`? `);2864 genNode(consequent, context);2865 context.indentLevel--;2866 needNewline && newline();2867 needNewline || push(` `);2868 push(`: `);2869 const isNested = alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */;2870 if (!isNested) {2871 context.indentLevel++;2872 }2873 genNode(alternate, context);2874 if (!isNested) {2875 context.indentLevel--;2876 }2877 needNewline && deindent(true /* without newline */);2878}2879function genCacheExpression(node, context) {2880 const { push, helper, indent, deindent, newline } = context;2881 push(`_cache[${node.index}] || (`);2882 if (node.isVNode) {2883 indent();2884 push(`${helper(SET_BLOCK_TRACKING)}(-1),`);2885 newline();2886 }2887 push(`_cache[${node.index}] = `);2888 genNode(node.value, context);2889 if (node.isVNode) {2890 push(`,`);2891 newline();2892 push(`${helper(SET_BLOCK_TRACKING)}(1),`);2893 newline();2894 push(`_cache[${node.index}]`);2895 deindent();2896 }2897 push(`)`);2898}2899function walkIdentifiers(root, onIdentifier, includeAll = false, parentStack = [], knownIds = Object.create(null)) {2900 {2901 return;2902 }2903}2904function isReferencedIdentifier(id, parent, parentStack) {2905 {2906 return false;2907 }2908}2909function isInDestructureAssignment(parent, parentStack) {2910 if (parent &&2911 (parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')) {2912 let i = parentStack.length;2913 while (i--) {2914 const p = parentStack[i];2915 if (p.type === 'AssignmentExpression') {2916 return true;2917 }2918 else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {2919 break;2920 }2921 }2922 }2923 return false;2924}2925function walkFunctionParams(node, onIdent) {2926 for (const p of node.params) {2927 for (const id of extractIdentifiers(p)) {2928 onIdent(id);2929 }2930 }2931}2932function walkBlockDeclarations(block, onIdent) {2933 for (const stmt of block.body) {2934 if (stmt.type === 'VariableDeclaration') {2935 if (stmt.declare)2936 continue;2937 for (const decl of stmt.declarations) {2938 for (const id of extractIdentifiers(decl.id)) {2939 onIdent(id);2940 }2941 }2942 }2943 else if (stmt.type === 'FunctionDeclaration' ||2944 stmt.type === 'ClassDeclaration') {2945 if (stmt.declare || !stmt.id)2946 continue;2947 onIdent(stmt.id);2948 }2949 }2950}2951function extractIdentifiers(param, nodes = []) {2952 switch (param.type) {2953 case 'Identifier':2954 nodes.push(param);2955 break;2956 case 'MemberExpression':2957 let object = param;2958 while (object.type === 'MemberExpression') {2959 object = object.object;2960 }2961 nodes.push(object);2962 break;2963 case 'ObjectPattern':2964 for (const prop of param.properties) {2965 if (prop.type === 'RestElement') {2966 extractIdentifiers(prop.argument, nodes);2967 }2968 else {2969 extractIdentifiers(prop.value, nodes);2970 }2971 }2972 break;2973 case 'ArrayPattern':2974 param.elements.forEach(element => {2975 if (element)2976 extractIdentifiers(element, nodes);2977 });2978 break;2979 case 'RestElement':2980 extractIdentifiers(param.argument, nodes);2981 break;2982 case 'AssignmentPattern':2983 extractIdentifiers(param.left, nodes);2984 break;2985 }2986 return nodes;2987}2988const isFunctionType = (node) => {2989 return /Function(?:Expression|Declaration)$|Method$/.test(node.type);2990};2991const isStaticProperty = (node) => node &&2992 (node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&2993 !node.computed;2994const isStaticPropertyKey = (node, parent) => isStaticProperty(parent) && parent.key === node;2995// these keywords should not appear inside expressions, but operators like2996// typeof, instanceof and in are allowed2997const prohibitedKeywordRE = new RegExp('\\b' +2998 ('do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,' +2999 'super,throw,while,yield,delete,export,import,return,switch,default,' +3000 'extends,finally,continue,debugger,function,arguments,typeof,void')3001 .split(',')3002 .join('\\b|\\b') +3003 '\\b');3004// strip strings in expressions3005const stripStringRE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`/g;3006/**3007 * Validate a non-prefixed expression.3008 * This is only called when using the in-browser runtime compiler since it3009 * doesn't prefix expressions.3010 */3011function validateBrowserExpression(node, context, asParams = false, asRawStatements = false) {3012 const exp = node.content;3013 // empty expressions are validated per-directive since some directives3014 // do allow empty expressions.3015 if (!exp.trim()) {3016 return;3017 }3018 try {3019 new Function(asRawStatements3020 ? ` ${exp} `3021 : `return ${asParams ? `(${exp}) => {}` : `(${exp})`}`);3022 }3023 catch (e) {3024 let message = e.message;3025 const keywordMatch = exp3026 .replace(stripStringRE, '')3027 .match(prohibitedKeywordRE);3028 if (keywordMatch) {3029 message = `avoid using JavaScript keyword as property name: "${keywordMatch[0]}"`;3030 }3031 context.onError(createCompilerError(44 /* X_INVALID_EXPRESSION */, node.loc, undefined, message));3032 }3033}3034const transformExpression = (node, context) => {3035 if (node.type === 5 /* INTERPOLATION */) {3036 node.content = processExpression(node.content, context);3037 }3038 else if (node.type === 1 /* ELEMENT */) {3039 // handle directives on element3040 for (let i = 0; i < node.props.length; i++) {3041 const dir = node.props[i];3042 // do not process for v-on & v-for since they are special handled3043 if (dir.type === 7 /* DIRECTIVE */ && dir.name !== 'for') {3044 const exp = dir.exp;3045 const arg = dir.arg;3046 // do not process exp if this is v-on:arg - we need special handling3047 // for wrapping inline statements.3048 if (exp &&3049 exp.type === 4 /* SIMPLE_EXPRESSION */ &&3050 !(dir.name === 'on' && arg)) {3051 dir.exp = processExpression(exp, context, 3052 // slot args must be processed as function params3053 dir.name === 'slot');3054 }3055 if (arg && arg.type === 4 /* SIMPLE_EXPRESSION */ && !arg.isStatic) {3056 dir.arg = processExpression(arg, context);3057 }3058 }3059 }3060 }3061};3062// Important: since this function uses Node.js only dependencies, it should3063// always be used with a leading !true check so that it can be3064// tree-shaken from the browser build.3065function processExpression(node, context, 3066// some expressions like v-slot props & v-for aliases should be parsed as3067// function params3068asParams = false, 3069// v-on handler values may contain multiple statements3070asRawStatements = false, localVars = Object.create(context.identifiers)) {3071 {3072 {3073 // simple in-browser validation (same logic in 2.x)3074 validateBrowserExpression(node, context, asParams, asRawStatements);3075 }3076 return node;3077 }3078}3079const transformIf = createStructuralDirectiveTransform(/^(if|else|else-if)$/, (node, dir, context) => {3080 return processIf(node, dir, context, (ifNode, branch, isRoot) => {3081 // #1587: We need to dynamically increment the key based on the current3082 // node's sibling nodes, since chained v-if/else branches are3083 // rendered at the same depth3084 const siblings = context.parent.children;3085 let i = siblings.indexOf(ifNode);3086 let key = 0;3087 while (i-- >= 0) {3088 const sibling = siblings[i];3089 if (sibling && sibling.type === 9 /* IF */) {3090 key += sibling.branches.length;3091 }3092 }3093 // Exit callback. Complete the codegenNode when all children have been3094 // transformed.3095 return () => {3096 if (isRoot) {3097 ifNode.codegenNode = createCodegenNodeForBranch(branch, key, context);3098 }3099 else {3100 // attach this branch's codegen node to the v-if root.3101 const parentCondition = getParentCondition(ifNode.codegenNode);3102 parentCondition.alternate = createCodegenNodeForBranch(branch, key + ifNode.branches.length - 1, context);3103 }3104 };3105 });3106});3107// target-agnostic transform used for both Client and SSR3108function processIf(node, dir, context, processCodegen) {3109 if (dir.name !== 'else' &&3110 (!dir.exp || !dir.exp.content.trim())) {3111 const loc = dir.exp ? dir.exp.loc : node.loc;3112 context.onError(createCompilerError(28 /* X_V_IF_NO_EXPRESSION */, dir.loc));3113 dir.exp = createSimpleExpression(`true`, false, loc);3114 }3115 if (dir.exp) {3116 validateBrowserExpression(dir.exp, context);3117 }3118 if (dir.name === 'if') {3119 const branch = createIfBranch(node, dir);3120 const ifNode = {3121 type: 9 /* IF */,3122 loc: node.loc,3123 branches: [branch]3124 };3125 context.replaceNode(ifNode);3126 if (processCodegen) {3127 return processCodegen(ifNode, branch, true);3128 }3129 }3130 else {3131 // locate the adjacent v-if3132 const siblings = context.parent.children;3133 const comments = [];3134 let i = siblings.indexOf(node);3135 while (i-- >= -1) {3136 const sibling = siblings[i];3137 if (sibling && sibling.type === 3 /* COMMENT */) {3138 context.removeNode(sibling);3139 comments.unshift(sibling);3140 continue;3141 }3142 if (sibling &&3143 sibling.type === 2 /* TEXT */ &&3144 !sibling.content.trim().length) {3145 context.removeNode(sibling);3146 continue;3147 }3148 if (sibling && sibling.type === 9 /* IF */) {3149 // Check if v-else was followed by v-else-if3150 if (dir.name === 'else-if' &&3151 sibling.branches[sibling.branches.length - 1].condition === undefined) {3152 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));3153 }3154 // move the node to the if node's branches3155 context.removeNode();3156 const branch = createIfBranch(node, dir);3157 if (comments.length &&3158 // #3619 ignore comments if the v-if is direct child of <transition>3159 !(context.parent &&3160 context.parent.type === 1 /* ELEMENT */ &&3161 isBuiltInType(context.parent.tag, 'transition'))) {3162 branch.children = [...comments, ...branch.children];3163 }3164 // check if user is forcing same key on different branches3165 {3166 const key = branch.userKey;3167 if (key) {3168 sibling.branches.forEach(({ userKey }) => {3169 if (isSameKey(userKey, key)) {3170 context.onError(createCompilerError(29 /* X_V_IF_SAME_KEY */, branch.userKey.loc));3171 }3172 });3173 }3174 }3175 sibling.branches.push(branch);3176 const onExit = processCodegen && processCodegen(sibling, branch, false);3177 // since the branch was removed, it will not be traversed.3178 // make sure to traverse here.3179 traverseNode(branch, context);3180 // call on exit3181 if (onExit)3182 onExit();3183 // make sure to reset currentNode after traversal to indicate this3184 // node has been removed.3185 context.currentNode = null;3186 }3187 else {3188 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));3189 }3190 break;3191 }3192 }3193}3194function createIfBranch(node, dir) {3195 return {3196 type: 10 /* IF_BRANCH */,3197 loc: node.loc,3198 condition: dir.name === 'else' ? undefined : dir.exp,3199 children: node.tagType === 3 /* TEMPLATE */ && !findDir(node, 'for')3200 ? node.children3201 : [node],3202 userKey: findProp(node, `key`)3203 };3204}3205function createCodegenNodeForBranch(branch, keyIndex, context) {3206 if (branch.condition) {3207 return createConditionalExpression(branch.condition, createChildrenCodegenNode(branch, keyIndex, context), 3208 // make sure to pass in asBlock: true so that the comment node call3209 // closes the current block.3210 createCallExpression(context.helper(CREATE_COMMENT), [3211 '"v-if"' ,3212 'true'3213 ]));3214 }3215 else {3216 return createChildrenCodegenNode(branch, keyIndex, context);3217 }3218}3219function createChildrenCodegenNode(branch, keyIndex, context) {3220 const { helper } = context;3221 const keyProperty = createObjectProperty(`key`, createSimpleExpression(`${keyIndex}`, false, locStub, 2 /* CAN_HOIST */));3222 const { children } = branch;3223 const firstChild = children[0];3224 const needFragmentWrapper = children.length !== 1 || firstChild.type !== 1 /* ELEMENT */;3225 if (needFragmentWrapper) {3226 if (children.length === 1 && firstChild.type === 11 /* FOR */) {3227 // optimize away nested fragments when child is a ForNode3228 const vnodeCall = firstChild.codegenNode;3229 injectProp(vnodeCall, keyProperty, context);3230 return vnodeCall;3231 }3232 else {3233 let patchFlag = 64 /* STABLE_FRAGMENT */;3234 let patchFlagText = PatchFlagNames[64 /* STABLE_FRAGMENT */];3235 // check if the fragment actually contains a single valid child with3236 // the rest being comments3237 if (children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {3238 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;3239 patchFlagText += `, ${PatchFlagNames[2048 /* DEV_ROOT_FRAGMENT */]}`;3240 }3241 return createVNodeCall(context, helper(FRAGMENT), createObjectExpression([keyProperty]), children, patchFlag + (` /* ${patchFlagText} */` ), undefined, undefined, true, false, false /* isComponent */, branch.loc);3242 }3243 }3244 else {3245 const ret = firstChild.codegenNode;3246 const vnodeCall = getMemoedVNodeCall(ret);3247 // Change createVNode to createBlock.3248 if (vnodeCall.type === 13 /* VNODE_CALL */) {3249 makeBlock(vnodeCall, context);3250 }3251 // inject branch key3252 injectProp(vnodeCall, keyProperty, context);3253 return ret;3254 }3255}3256function isSameKey(a, b) {3257 if (!a || a.type !== b.type) {3258 return false;3259 }3260 if (a.type === 6 /* ATTRIBUTE */) {3261 if (a.value.content !== b.value.content) {3262 return false;3263 }3264 }3265 else {3266 // directive3267 const exp = a.exp;3268 const branchExp = b.exp;3269 if (exp.type !== branchExp.type) {3270 return false;3271 }3272 if (exp.type !== 4 /* SIMPLE_EXPRESSION */ ||3273 exp.isStatic !== branchExp.isStatic ||3274 exp.content !== branchExp.content) {3275 return false;3276 }3277 }3278 return true;3279}3280function getParentCondition(node) {3281 while (true) {3282 if (node.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3283 if (node.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3284 node = node.alternate;3285 }3286 else {3287 return node;3288 }3289 }3290 else if (node.type === 20 /* JS_CACHE_EXPRESSION */) {3291 node = node.value;3292 }3293 }3294}3295const transformFor = createStructuralDirectiveTransform('for', (node, dir, context) => {3296 const { helper, removeHelper } = context;3297 return processFor(node, dir, context, forNode => {3298 // create the loop render function expression now, and add the3299 // iterator on exit after all children have been traversed3300 const renderExp = createCallExpression(helper(RENDER_LIST), [3301 forNode.source3302 ]);3303 const memo = findDir(node, 'memo');3304 const keyProp = findProp(node, `key`);3305 const keyExp = keyProp &&3306 (keyProp.type === 6 /* ATTRIBUTE */3307 ? createSimpleExpression(keyProp.value.content, true)3308 : keyProp.exp);3309 const keyProperty = keyProp ? createObjectProperty(`key`, keyExp) : null;3310 const isStableFragment = forNode.source.type === 4 /* SIMPLE_EXPRESSION */ &&3311 forNode.source.constType > 0 /* NOT_CONSTANT */;3312 const fragmentFlag = isStableFragment3313 ? 64 /* STABLE_FRAGMENT */3314 : keyProp3315 ? 128 /* KEYED_FRAGMENT */3316 : 256 /* UNKEYED_FRAGMENT */;3317 forNode.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, renderExp, fragmentFlag +3318 (` /* ${PatchFlagNames[fragmentFlag]} */` ), undefined, undefined, true /* isBlock */, !isStableFragment /* disableTracking */, false /* isComponent */, node.loc);3319 return () => {3320 // finish the codegen now that all children have been traversed3321 let childBlock;3322 const isTemplate = isTemplateNode(node);3323 const { children } = forNode;3324 // check <template v-for> key placement3325 if (isTemplate) {3326 node.children.some(c => {3327 if (c.type === 1 /* ELEMENT */) {3328 const key = findProp(c, 'key');3329 if (key) {3330 context.onError(createCompilerError(33 /* X_V_FOR_TEMPLATE_KEY_PLACEMENT */, key.loc));3331 return true;3332 }3333 }3334 });3335 }3336 const needFragmentWrapper = children.length !== 1 || children[0].type !== 1 /* ELEMENT */;3337 const slotOutlet = isSlotOutlet(node)3338 ? node3339 : isTemplate &&3340 node.children.length === 1 &&3341 isSlotOutlet(node.children[0])3342 ? node.children[0] // api-extractor somehow fails to infer this3343 : null;3344 if (slotOutlet) {3345 // <slot v-for="..."> or <template v-for="..."><slot/></template>3346 childBlock = slotOutlet.codegenNode;3347 if (isTemplate && keyProperty) {3348 // <template v-for="..." :key="..."><slot/></template>3349 // we need to inject the key to the renderSlot() call.3350 // the props for renderSlot is passed as the 3rd argument.3351 injectProp(childBlock, keyProperty, context);3352 }3353 }3354 else if (needFragmentWrapper) {3355 // <template v-for="..."> with text or multi-elements3356 // should generate a fragment block for each loop3357 childBlock = createVNodeCall(context, helper(FRAGMENT), keyProperty ? createObjectExpression([keyProperty]) : undefined, node.children, 64 /* STABLE_FRAGMENT */ +3358 (` /* ${PatchFlagNames[64 /* STABLE_FRAGMENT */]} */`3359 ), undefined, undefined, true, undefined, false /* isComponent */);3360 }3361 else {3362 // Normal element v-for. Directly use the child's codegenNode3363 // but mark it as a block.3364 childBlock = children[0]3365 .codegenNode;3366 if (isTemplate && keyProperty) {3367 injectProp(childBlock, keyProperty, context);3368 }3369 if (childBlock.isBlock !== !isStableFragment) {3370 if (childBlock.isBlock) {3371 // switch from block to vnode3372 removeHelper(OPEN_BLOCK);3373 removeHelper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3374 }3375 else {3376 // switch from vnode to block3377 removeHelper(getVNodeHelper(context.inSSR, childBlock.isComponent));3378 }3379 }3380 childBlock.isBlock = !isStableFragment;3381 if (childBlock.isBlock) {3382 helper(OPEN_BLOCK);3383 helper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3384 }3385 else {3386 helper(getVNodeHelper(context.inSSR, childBlock.isComponent));3387 }3388 }3389 if (memo) {3390 const loop = createFunctionExpression(createForLoopParams(forNode.parseResult, [3391 createSimpleExpression(`_cached`)3392 ]));3393 loop.body = createBlockStatement([3394 createCompoundExpression([`const _memo = (`, memo.exp, `)`]),3395 createCompoundExpression([3396 `if (_cached`,3397 ...(keyExp ? [` && _cached.key === `, keyExp] : []),3398 ` && ${context.helperString(IS_MEMO_SAME)}(_cached, _memo)) return _cached`3399 ]),3400 createCompoundExpression([`const _item = `, childBlock]),3401 createSimpleExpression(`_item.memo = _memo`),3402 createSimpleExpression(`return _item`)3403 ]);3404 renderExp.arguments.push(loop, createSimpleExpression(`_cache`), createSimpleExpression(String(context.cached++)));3405 }3406 else {3407 renderExp.arguments.push(createFunctionExpression(createForLoopParams(forNode.parseResult), childBlock, true /* force newline */));3408 }3409 };3410 });3411});3412// target-agnostic transform used for both Client and SSR3413function processFor(node, dir, context, processCodegen) {3414 if (!dir.exp) {3415 context.onError(createCompilerError(31 /* X_V_FOR_NO_EXPRESSION */, dir.loc));3416 return;3417 }3418 const parseResult = parseForExpression(3419 // can only be simple expression because vFor transform is applied3420 // before expression transform.3421 dir.exp, context);3422 if (!parseResult) {3423 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));3424 return;3425 }3426 const { addIdentifiers, removeIdentifiers, scopes } = context;3427 const { source, value, key, index } = parseResult;3428 const forNode = {3429 type: 11 /* FOR */,3430 loc: dir.loc,3431 source,3432 valueAlias: value,3433 keyAlias: key,3434 objectIndexAlias: index,3435 parseResult,3436 children: isTemplateNode(node) ? node.children : [node]3437 };3438 context.replaceNode(forNode);3439 // bookkeeping3440 scopes.vFor++;3441 const onExit = processCodegen && processCodegen(forNode);3442 return () => {3443 scopes.vFor--;3444 if (onExit)3445 onExit();3446 };3447}3448const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;3449// This regex doesn't cover the case if key or index aliases have destructuring,3450// but those do not make sense in the first place, so this works in practice.3451const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;3452const stripParensRE = /^\(|\)$/g;3453function parseForExpression(input, context) {3454 const loc = input.loc;3455 const exp = input.content;3456 const inMatch = exp.match(forAliasRE);3457 if (!inMatch)3458 return;3459 const [, LHS, RHS] = inMatch;3460 const result = {3461 source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),3462 value: undefined,3463 key: undefined,3464 index: undefined3465 };3466 {3467 validateBrowserExpression(result.source, context);3468 }3469 let valueContent = LHS.trim().replace(stripParensRE, '').trim();3470 const trimmedOffset = LHS.indexOf(valueContent);3471 const iteratorMatch = valueContent.match(forIteratorRE);3472 if (iteratorMatch) {3473 valueContent = valueContent.replace(forIteratorRE, '').trim();3474 const keyContent = iteratorMatch[1].trim();3475 let keyOffset;3476 if (keyContent) {3477 keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);3478 result.key = createAliasExpression(loc, keyContent, keyOffset);3479 {3480 validateBrowserExpression(result.key, context, true);3481 }3482 }3483 if (iteratorMatch[2]) {3484 const indexContent = iteratorMatch[2].trim();3485 if (indexContent) {3486 result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key3487 ? keyOffset + keyContent.length3488 : trimmedOffset + valueContent.length));3489 {3490 validateBrowserExpression(result.index, context, true);3491 }3492 }3493 }3494 }3495 if (valueContent) {3496 result.value = createAliasExpression(loc, valueContent, trimmedOffset);3497 {3498 validateBrowserExpression(result.value, context, true);3499 }3500 }3501 return result;3502}3503function createAliasExpression(range, content, offset) {3504 return createSimpleExpression(content, false, getInnerRange(range, offset, content.length));3505}3506function createForLoopParams({ value, key, index }, memoArgs = []) {3507 return createParamsList([value, key, index, ...memoArgs]);3508}3509function createParamsList(args) {3510 let i = args.length;3511 while (i--) {3512 if (args[i])3513 break;3514 }3515 return args3516 .slice(0, i + 1)3517 .map((arg, i) => arg || createSimpleExpression(`_`.repeat(i + 1), false));3518}3519const defaultFallback = createSimpleExpression(`undefined`, false);3520// A NodeTransform that:3521// 1. Tracks scope identifiers for scoped slots so that they don't get prefixed3522// by transformExpression. This is only applied in non-browser builds with3523// { prefixIdentifiers: true }.3524// 2. Track v-slot depths so that we know a slot is inside another slot.3525// Note the exit callback is executed before buildSlots() on the same node,3526// so only nested slots see positive numbers.3527const trackSlotScopes = (node, context) => {3528 if (node.type === 1 /* ELEMENT */ &&3529 (node.tagType === 1 /* COMPONENT */ ||3530 node.tagType === 3 /* TEMPLATE */)) {3531 // We are only checking non-empty v-slot here3532 // since we only care about slots that introduce scope variables.3533 const vSlot = findDir(node, 'slot');3534 if (vSlot) {3535 vSlot.exp;3536 context.scopes.vSlot++;3537 return () => {3538 context.scopes.vSlot--;3539 };3540 }3541 }3542};3543// A NodeTransform that tracks scope identifiers for scoped slots with v-for.3544// This transform is only applied in non-browser builds with { prefixIdentifiers: true }3545const trackVForSlotScopes = (node, context) => {3546 let vFor;3547 if (isTemplateNode(node) &&3548 node.props.some(isVSlot) &&3549 (vFor = findDir(node, 'for'))) {3550 const result = (vFor.parseResult = parseForExpression(vFor.exp, context));3551 if (result) {3552 const { value, key, index } = result;3553 const { addIdentifiers, removeIdentifiers } = context;3554 value && addIdentifiers(value);3555 key && addIdentifiers(key);3556 index && addIdentifiers(index);3557 return () => {3558 value && removeIdentifiers(value);3559 key && removeIdentifiers(key);3560 index && removeIdentifiers(index);3561 };3562 }3563 }3564};3565const buildClientSlotFn = (props, children, loc) => createFunctionExpression(props, children, false /* newline */, true /* isSlot */, children.length ? children[0].loc : loc);3566// Instead of being a DirectiveTransform, v-slot processing is called during3567// transformElement to build the slots object for a component.3568function buildSlots(node, context, buildSlotFn = buildClientSlotFn) {3569 context.helper(WITH_CTX);3570 const { children, loc } = node;3571 const slotsProperties = [];3572 const dynamicSlots = [];3573 // If the slot is inside a v-for or another v-slot, force it to be dynamic3574 // since it likely uses a scope variable.3575 let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0;3576 // 1. Check for slot with slotProps on component itself.3577 // <Comp v-slot="{ prop }"/>3578 const onComponentSlot = findDir(node, 'slot', true);3579 if (onComponentSlot) {3580 const { arg, exp } = onComponentSlot;3581 if (arg && !isStaticExp(arg)) {3582 hasDynamicSlots = true;3583 }3584 slotsProperties.push(createObjectProperty(arg || createSimpleExpression('default', true), buildSlotFn(exp, children, loc)));3585 }3586 // 2. Iterate through children and check for template slots3587 // <template v-slot:foo="{ prop }">3588 let hasTemplateSlots = false;3589 let hasNamedDefaultSlot = false;3590 const implicitDefaultChildren = [];3591 const seenSlotNames = new Set();3592 for (let i = 0; i < children.length; i++) {3593 const slotElement = children[i];3594 let slotDir;3595 if (!isTemplateNode(slotElement) ||3596 !(slotDir = findDir(slotElement, 'slot', true))) {3597 // not a <template v-slot>, skip.3598 if (slotElement.type !== 3 /* COMMENT */) {3599 implicitDefaultChildren.push(slotElement);3600 }3601 continue;3602 }3603 if (onComponentSlot) {3604 // already has on-component slot - this is incorrect usage.3605 context.onError(createCompilerError(37 /* X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc));3606 break;3607 }3608 hasTemplateSlots = true;3609 const { children: slotChildren, loc: slotLoc } = slotElement;3610 const { arg: slotName = createSimpleExpression(`default`, true), exp: slotProps, loc: dirLoc } = slotDir;3611 // check if name is dynamic.3612 let staticSlotName;3613 if (isStaticExp(slotName)) {3614 staticSlotName = slotName ? slotName.content : `default`;3615 }3616 else {3617 hasDynamicSlots = true;3618 }3619 const slotFunction = buildSlotFn(slotProps, slotChildren, slotLoc);3620 // check if this slot is conditional (v-if/v-for)3621 let vIf;3622 let vElse;3623 let vFor;3624 if ((vIf = findDir(slotElement, 'if'))) {3625 hasDynamicSlots = true;3626 dynamicSlots.push(createConditionalExpression(vIf.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback));3627 }3628 else if ((vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))) {3629 // find adjacent v-if3630 let j = i;3631 let prev;3632 while (j--) {3633 prev = children[j];3634 if (prev.type !== 3 /* COMMENT */) {3635 break;3636 }3637 }3638 if (prev && isTemplateNode(prev) && findDir(prev, 'if')) {3639 // remove node3640 children.splice(i, 1);3641 i--;3642 // attach this slot to previous conditional3643 let conditional = dynamicSlots[dynamicSlots.length - 1];3644 while (conditional.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3645 conditional = conditional.alternate;3646 }3647 conditional.alternate = vElse.exp3648 ? createConditionalExpression(vElse.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback)3649 : buildDynamicSlot(slotName, slotFunction);3650 }3651 else {3652 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, vElse.loc));3653 }3654 }3655 else if ((vFor = findDir(slotElement, 'for'))) {3656 hasDynamicSlots = true;3657 const parseResult = vFor.parseResult ||3658 parseForExpression(vFor.exp, context);3659 if (parseResult) {3660 // Render the dynamic slots as an array and add it to the createSlot()3661 // args. The runtime knows how to handle it appropriately.3662 dynamicSlots.push(createCallExpression(context.helper(RENDER_LIST), [3663 parseResult.source,3664 createFunctionExpression(createForLoopParams(parseResult), buildDynamicSlot(slotName, slotFunction), true /* force newline */)3665 ]));3666 }3667 else {3668 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc));3669 }3670 }3671 else {3672 // check duplicate static names3673 if (staticSlotName) {3674 if (seenSlotNames.has(staticSlotName)) {3675 context.onError(createCompilerError(38 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc));3676 continue;3677 }3678 seenSlotNames.add(staticSlotName);3679 if (staticSlotName === 'default') {3680 hasNamedDefaultSlot = true;3681 }3682 }3683 slotsProperties.push(createObjectProperty(slotName, slotFunction));3684 }3685 }3686 if (!onComponentSlot) {3687 const buildDefaultSlotProperty = (props, children) => {3688 const fn = buildSlotFn(props, children, loc);3689 if (context.compatConfig) {3690 fn.isNonScopedSlot = true;3691 }3692 return createObjectProperty(`default`, fn);3693 };3694 if (!hasTemplateSlots) {3695 // implicit default slot (on component)3696 slotsProperties.push(buildDefaultSlotProperty(undefined, children));3697 }3698 else if (implicitDefaultChildren.length &&3699 // #37663700 // with whitespace: 'preserve', whitespaces between slots will end up in3701 // implicitDefaultChildren. Ignore if all implicit children are whitespaces.3702 implicitDefaultChildren.some(node => isNonWhitespaceContent(node))) {3703 // implicit default slot (mixed with named slots)3704 if (hasNamedDefaultSlot) {3705 context.onError(createCompilerError(39 /* X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN */, implicitDefaultChildren[0].loc));3706 }3707 else {3708 slotsProperties.push(buildDefaultSlotProperty(undefined, implicitDefaultChildren));3709 }3710 }3711 }3712 const slotFlag = hasDynamicSlots3713 ? 2 /* DYNAMIC */3714 : hasForwardedSlots(node.children)3715 ? 3 /* FORWARDED */3716 : 1 /* STABLE */;3717 let slots = createObjectExpression(slotsProperties.concat(createObjectProperty(`_`, 3718 // 2 = compiled but dynamic = can skip normalization, but must run diff3719 // 1 = compiled and static = can skip normalization AND diff as optimized3720 createSimpleExpression(slotFlag + (` /* ${slotFlagsText[slotFlag]} */` ), false))), loc);3721 if (dynamicSlots.length) {3722 slots = createCallExpression(context.helper(CREATE_SLOTS), [3723 slots,3724 createArrayExpression(dynamicSlots)3725 ]);3726 }3727 return {3728 slots,3729 hasDynamicSlots3730 };3731}3732function buildDynamicSlot(name, fn) {3733 return createObjectExpression([3734 createObjectProperty(`name`, name),3735 createObjectProperty(`fn`, fn)3736 ]);3737}3738function hasForwardedSlots(children) {3739 for (let i = 0; i < children.length; i++) {3740 const child = children[i];3741 switch (child.type) {3742 case 1 /* ELEMENT */:3743 if (child.tagType === 2 /* SLOT */ ||3744 hasForwardedSlots(child.children)) {3745 return true;3746 }3747 break;3748 case 9 /* IF */:3749 if (hasForwardedSlots(child.branches))3750 return true;3751 break;3752 case 10 /* IF_BRANCH */:3753 case 11 /* FOR */:3754 if (hasForwardedSlots(child.children))3755 return true;3756 break;3757 }3758 }3759 return false;3760}3761function isNonWhitespaceContent(node) {3762 if (node.type !== 2 /* TEXT */ && node.type !== 12 /* TEXT_CALL */)3763 return true;3764 return node.type === 2 /* TEXT */3765 ? !!node.content.trim()3766 : isNonWhitespaceContent(node.content);3767}3768// some directive transforms (e.g. v-model) may return a symbol for runtime3769// import, which should be used instead of a resolveDirective call.3770const directiveImportMap = new WeakMap();3771// generate a JavaScript AST for this element's codegen3772const transformElement = (node, context) => {3773 // perform the work on exit, after all child expressions have been3774 // processed and merged.3775 return function postTransformElement() {3776 node = context.currentNode;3777 if (!(node.type === 1 /* ELEMENT */ &&3778 (node.tagType === 0 /* ELEMENT */ ||3779 node.tagType === 1 /* COMPONENT */))) {3780 return;3781 }3782 const { tag, props } = node;3783 const isComponent = node.tagType === 1 /* COMPONENT */;3784 // The goal of the transform is to create a codegenNode implementing the3785 // VNodeCall interface.3786 let vnodeTag = isComponent3787 ? resolveComponentType(node, context)3788 : `"${tag}"`;3789 const isDynamicComponent = isObject(vnodeTag) && vnodeTag.callee === RESOLVE_DYNAMIC_COMPONENT;3790 let vnodeProps;3791 let vnodeChildren;3792 let vnodePatchFlag;3793 let patchFlag = 0;3794 let vnodeDynamicProps;3795 let dynamicPropNames;3796 let vnodeDirectives;3797 let shouldUseBlock = 3798 // dynamic component may resolve to plain elements3799 isDynamicComponent ||3800 vnodeTag === TELEPORT ||3801 vnodeTag === SUSPENSE ||3802 (!isComponent &&3803 // <svg> and <foreignObject> must be forced into blocks so that block3804 // updates inside get proper isSVG flag at runtime. (#639, #643)3805 // This is technically web-specific, but splitting the logic out of core3806 // leads to too much unnecessary complexity.3807 (tag === 'svg' || tag === 'foreignObject'));3808 // props3809 if (props.length > 0) {3810 const propsBuildResult = buildProps(node, context);3811 vnodeProps = propsBuildResult.props;3812 patchFlag = propsBuildResult.patchFlag;3813 dynamicPropNames = propsBuildResult.dynamicPropNames;3814 const directives = propsBuildResult.directives;3815 vnodeDirectives =3816 directives && directives.length3817 ? createArrayExpression(directives.map(dir => buildDirectiveArgs(dir, context)))3818 : undefined;3819 if (propsBuildResult.shouldUseBlock) {3820 shouldUseBlock = true;3821 }3822 }3823 // children3824 if (node.children.length > 0) {3825 if (vnodeTag === KEEP_ALIVE) {3826 // Although a built-in component, we compile KeepAlive with raw children3827 // instead of slot functions so that it can be used inside Transition3828 // or other Transition-wrapping HOCs.3829 // To ensure correct updates with block optimizations, we need to:3830 // 1. Force keep-alive into a block. This avoids its children being3831 // collected by a parent block.3832 shouldUseBlock = true;3833 // 2. Force keep-alive to always be updated, since it uses raw children.3834 patchFlag |= 1024 /* DYNAMIC_SLOTS */;3835 if (node.children.length > 1) {3836 context.onError(createCompilerError(45 /* X_KEEP_ALIVE_INVALID_CHILDREN */, {3837 start: node.children[0].loc.start,3838 end: node.children[node.children.length - 1].loc.end,3839 source: ''3840 }));3841 }3842 }3843 const shouldBuildAsSlots = isComponent &&3844 // Teleport is not a real component and has dedicated runtime handling3845 vnodeTag !== TELEPORT &&3846 // explained above.3847 vnodeTag !== KEEP_ALIVE;3848 if (shouldBuildAsSlots) {3849 const { slots, hasDynamicSlots } = buildSlots(node, context);3850 vnodeChildren = slots;3851 if (hasDynamicSlots) {3852 patchFlag |= 1024 /* DYNAMIC_SLOTS */;3853 }3854 }3855 else if (node.children.length === 1 && vnodeTag !== TELEPORT) {3856 const child = node.children[0];3857 const type = child.type;3858 // check for dynamic text children3859 const hasDynamicTextChild = type === 5 /* INTERPOLATION */ ||3860 type === 8 /* COMPOUND_EXPRESSION */;3861 if (hasDynamicTextChild &&3862 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {3863 patchFlag |= 1 /* TEXT */;3864 }3865 // pass directly if the only child is a text node3866 // (plain / interpolation / expression)3867 if (hasDynamicTextChild || type === 2 /* TEXT */) {3868 vnodeChildren = child;3869 }3870 else {3871 vnodeChildren = node.children;3872 }3873 }3874 else {3875 vnodeChildren = node.children;3876 }3877 }3878 // patchFlag & dynamicPropNames3879 if (patchFlag !== 0) {3880 {3881 if (patchFlag < 0) {3882 // special flags (negative and mutually exclusive)3883 vnodePatchFlag = patchFlag + ` /* ${PatchFlagNames[patchFlag]} */`;3884 }3885 else {3886 // bitwise flags3887 const flagNames = Object.keys(PatchFlagNames)3888 .map(Number)3889 .filter(n => n > 0 && patchFlag & n)3890 .map(n => PatchFlagNames[n])3891 .join(`, `);3892 vnodePatchFlag = patchFlag + ` /* ${flagNames} */`;3893 }3894 }3895 if (dynamicPropNames && dynamicPropNames.length) {3896 vnodeDynamicProps = stringifyDynamicPropNames(dynamicPropNames);3897 }3898 }3899 node.codegenNode = createVNodeCall(context, vnodeTag, vnodeProps, vnodeChildren, vnodePatchFlag, vnodeDynamicProps, vnodeDirectives, !!shouldUseBlock, false /* disableTracking */, isComponent, node.loc);3900 };3901};3902function resolveComponentType(node, context, ssr = false) {3903 let { tag } = node;3904 // 1. dynamic component3905 const isExplicitDynamic = isComponentTag(tag);3906 const isProp = findProp(node, 'is');3907 if (isProp) {3908 if (isExplicitDynamic ||3909 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) {3910 const exp = isProp.type === 6 /* ATTRIBUTE */3911 ? isProp.value && createSimpleExpression(isProp.value.content, true)3912 : isProp.exp;3913 if (exp) {3914 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [3915 exp3916 ]);3917 }3918 }3919 else if (isProp.type === 6 /* ATTRIBUTE */ &&3920 isProp.value.content.startsWith('vue:')) {3921 // <button is="vue:xxx">3922 // if not <component>, only is value that starts with "vue:" will be3923 // treated as component by the parse phase and reach here, unless it's3924 // compat mode where all is values are considered components3925 tag = isProp.value.content.slice(4);3926 }3927 }3928 // 1.5 v-is (TODO: Deprecate)3929 const isDir = !isExplicitDynamic && findDir(node, 'is');3930 if (isDir && isDir.exp) {3931 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [3932 isDir.exp3933 ]);3934 }3935 // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)3936 const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);3937 if (builtIn) {3938 // built-ins are simply fallthroughs / have special handling during ssr3939 // so we don't need to import their runtime equivalents3940 if (!ssr)3941 context.helper(builtIn);3942 return builtIn;3943 }3944 // 5. user component (resolve)3945 context.helper(RESOLVE_COMPONENT);3946 context.components.add(tag);3947 return toValidAssetId(tag, `component`);3948}3949function buildProps(node, context, props = node.props, ssr = false) {3950 const { tag, loc: elementLoc, children } = node;3951 const isComponent = node.tagType === 1 /* COMPONENT */;3952 let properties = [];3953 const mergeArgs = [];3954 const runtimeDirectives = [];3955 const hasChildren = children.length > 0;3956 let shouldUseBlock = false;3957 // patchFlag analysis3958 let patchFlag = 0;3959 let hasRef = false;3960 let hasClassBinding = false;3961 let hasStyleBinding = false;3962 let hasHydrationEventBinding = false;3963 let hasDynamicKeys = false;3964 let hasVnodeHook = false;3965 const dynamicPropNames = [];3966 const analyzePatchFlag = ({ key, value }) => {3967 if (isStaticExp(key)) {3968 const name = key.content;3969 const isEventHandler = isOn(name);3970 if (!isComponent &&3971 isEventHandler &&3972 // omit the flag for click handlers because hydration gives click3973 // dedicated fast path.3974 name.toLowerCase() !== 'onclick' &&3975 // omit v-model handlers3976 name !== 'onUpdate:modelValue' &&3977 // omit onVnodeXXX hooks3978 !isReservedProp(name)) {3979 hasHydrationEventBinding = true;3980 }3981 if (isEventHandler && isReservedProp(name)) {3982 hasVnodeHook = true;3983 }3984 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||3985 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||3986 value.type === 8 /* COMPOUND_EXPRESSION */) &&3987 getConstantType(value, context) > 0)) {3988 // skip if the prop is a cached handler or has constant value3989 return;3990 }3991 if (name === 'ref') {3992 hasRef = true;3993 }3994 else if (name === 'class') {3995 hasClassBinding = true;3996 }3997 else if (name === 'style') {3998 hasStyleBinding = true;3999 }4000 else if (name !== 'key' && !dynamicPropNames.includes(name)) {4001 dynamicPropNames.push(name);4002 }4003 // treat the dynamic class and style binding of the component as dynamic props4004 if (isComponent &&4005 (name === 'class' || name === 'style') &&4006 !dynamicPropNames.includes(name)) {4007 dynamicPropNames.push(name);4008 }4009 }4010 else {4011 hasDynamicKeys = true;4012 }4013 };4014 for (let i = 0; i < props.length; i++) {4015 // static attribute4016 const prop = props[i];4017 if (prop.type === 6 /* ATTRIBUTE */) {4018 const { loc, name, value } = prop;4019 let isStatic = true;4020 if (name === 'ref') {4021 hasRef = true;4022 if (context.scopes.vFor > 0) {4023 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));4024 }4025 }4026 // skip is on <component>, or is="vue:xxx"4027 if (name === 'is' &&4028 (isComponentTag(tag) ||4029 (value && value.content.startsWith('vue:')) ||4030 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) {4031 continue;4032 }4033 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));4034 }4035 else {4036 // directives4037 const { name, arg, exp, loc } = prop;4038 const isVBind = name === 'bind';4039 const isVOn = name === 'on';4040 // skip v-slot - it is handled by its dedicated transform.4041 if (name === 'slot') {4042 if (!isComponent) {4043 context.onError(createCompilerError(40 /* X_V_SLOT_MISPLACED */, loc));4044 }4045 continue;4046 }4047 // skip v-once/v-memo - they are handled by dedicated transforms.4048 if (name === 'once' || name === 'memo') {4049 continue;4050 }4051 // skip v-is and :is on <component>4052 if (name === 'is' ||4053 (isVBind &&4054 isStaticArgOf(arg, 'is') &&4055 (isComponentTag(tag) ||4056 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) {4057 continue;4058 }4059 // skip v-on in SSR compilation4060 if (isVOn && ssr) {4061 continue;4062 }4063 if (4064 // #938: elements with dynamic keys should be forced into blocks4065 (isVBind && isStaticArgOf(arg, 'key')) ||4066 // inline before-update hooks need to force block so that it is invoked4067 // before children4068 (isVOn && hasChildren && isStaticArgOf(arg, 'vue:before-update'))) {4069 shouldUseBlock = true;4070 }4071 if (isVBind && isStaticArgOf(arg, 'ref') && context.scopes.vFor > 0) {4072 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));4073 }4074 // special case for v-bind and v-on with no argument4075 if (!arg && (isVBind || isVOn)) {4076 hasDynamicKeys = true;4077 if (exp) {4078 if (properties.length) {4079 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));4080 properties = [];4081 }4082 if (isVBind) {4083 {4084 // 2.x v-bind object order compat4085 {4086 const hasOverridableKeys = mergeArgs.some(arg => {4087 if (arg.type === 15 /* JS_OBJECT_EXPRESSION */) {4088 return arg.properties.some(({ key }) => {4089 if (key.type !== 4 /* SIMPLE_EXPRESSION */ ||4090 !key.isStatic) {4091 return true;4092 }4093 return (key.content !== 'class' &&4094 key.content !== 'style' &&4095 !isOn(key.content));4096 });4097 }4098 else {4099 // dynamic expression4100 return true;4101 }4102 });4103 if (hasOverridableKeys) {4104 checkCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context, loc);4105 }4106 }4107 if (isCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context)) {4108 mergeArgs.unshift(exp);4109 continue;4110 }4111 }4112 mergeArgs.push(exp);4113 }4114 else {4115 // v-on="obj" -> toHandlers(obj)4116 mergeArgs.push({4117 type: 14 /* JS_CALL_EXPRESSION */,4118 loc,4119 callee: context.helper(TO_HANDLERS),4120 arguments: [exp]4121 });4122 }4123 }4124 else {4125 context.onError(createCompilerError(isVBind4126 ? 34 /* X_V_BIND_NO_EXPRESSION */4127 : 35 /* X_V_ON_NO_EXPRESSION */, loc));4128 }4129 continue;4130 }4131 const directiveTransform = context.directiveTransforms[name];4132 if (directiveTransform) {4133 // has built-in directive transform.4134 const { props, needRuntime } = directiveTransform(prop, node, context);4135 !ssr && props.forEach(analyzePatchFlag);4136 properties.push(...props);4137 if (needRuntime) {4138 runtimeDirectives.push(prop);4139 if (isSymbol(needRuntime)) {4140 directiveImportMap.set(prop, needRuntime);4141 }4142 }4143 }4144 else {4145 // no built-in transform, this is a user custom directive.4146 runtimeDirectives.push(prop);4147 // custom dirs may use beforeUpdate so they need to force blocks4148 // to ensure before-update gets called before children update4149 if (hasChildren) {4150 shouldUseBlock = true;4151 }4152 }4153 }4154 }4155 let propsExpression = undefined;4156 // has v-bind="object" or v-on="object", wrap with mergeProps4157 if (mergeArgs.length) {4158 if (properties.length) {4159 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));4160 }4161 if (mergeArgs.length > 1) {4162 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);4163 }4164 else {4165 // single v-bind with nothing else - no need for a mergeProps call4166 propsExpression = mergeArgs[0];4167 }4168 }4169 else if (properties.length) {4170 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);4171 }4172 // patchFlag analysis4173 if (hasDynamicKeys) {4174 patchFlag |= 16 /* FULL_PROPS */;4175 }4176 else {4177 if (hasClassBinding && !isComponent) {4178 patchFlag |= 2 /* CLASS */;4179 }4180 if (hasStyleBinding && !isComponent) {4181 patchFlag |= 4 /* STYLE */;4182 }4183 if (dynamicPropNames.length) {4184 patchFlag |= 8 /* PROPS */;4185 }4186 if (hasHydrationEventBinding) {4187 patchFlag |= 32 /* HYDRATE_EVENTS */;4188 }4189 }4190 if (!shouldUseBlock &&4191 (patchFlag === 0 || patchFlag === 32 /* HYDRATE_EVENTS */) &&4192 (hasRef || hasVnodeHook || runtimeDirectives.length > 0)) {4193 patchFlag |= 512 /* NEED_PATCH */;4194 }4195 // pre-normalize props, SSR is skipped for now4196 if (!context.inSSR && propsExpression) {4197 switch (propsExpression.type) {4198 case 15 /* JS_OBJECT_EXPRESSION */:4199 // means that there is no v-bind,4200 // but still need to deal with dynamic key binding4201 let classKeyIndex = -1;4202 let styleKeyIndex = -1;4203 let hasDynamicKey = false;4204 for (let i = 0; i < propsExpression.properties.length; i++) {4205 const key = propsExpression.properties[i].key;4206 if (isStaticExp(key)) {4207 if (key.content === 'class') {4208 classKeyIndex = i;4209 }4210 else if (key.content === 'style') {4211 styleKeyIndex = i;4212 }4213 }4214 else if (!key.isHandlerKey) {4215 hasDynamicKey = true;4216 }4217 }4218 const classProp = propsExpression.properties[classKeyIndex];4219 const styleProp = propsExpression.properties[styleKeyIndex];4220 // no dynamic key4221 if (!hasDynamicKey) {4222 if (classProp && !isStaticExp(classProp.value)) {4223 classProp.value = createCallExpression(context.helper(NORMALIZE_CLASS), [classProp.value]);4224 }4225 if (styleProp &&4226 !isStaticExp(styleProp.value) &&4227 // the static style is compiled into an object,4228 // so use `hasStyleBinding` to ensure that it is a dynamic style binding4229 (hasStyleBinding ||4230 // v-bind:style and style both exist,4231 // v-bind:style with static literal object4232 styleProp.value.type === 17 /* JS_ARRAY_EXPRESSION */)) {4233 styleProp.value = createCallExpression(context.helper(NORMALIZE_STYLE), [styleProp.value]);4234 }4235 }4236 else {4237 // dynamic key binding, wrap with `normalizeProps`4238 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [propsExpression]);4239 }4240 break;4241 case 14 /* JS_CALL_EXPRESSION */:4242 // mergeProps call, do nothing4243 break;4244 default:4245 // single v-bind4246 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [4247 createCallExpression(context.helper(GUARD_REACTIVE_PROPS), [4248 propsExpression4249 ])4250 ]);4251 break;4252 }4253 }4254 return {4255 props: propsExpression,4256 directives: runtimeDirectives,4257 patchFlag,4258 dynamicPropNames,4259 shouldUseBlock4260 };4261}4262// Dedupe props in an object literal.4263// Literal duplicated attributes would have been warned during the parse phase,4264// however, it's possible to encounter duplicated `onXXX` handlers with different4265// modifiers. We also need to merge static and dynamic class / style attributes.4266// - onXXX handlers / style: merge into array4267// - class: merge into single expression with concatenation4268function dedupeProperties(properties) {4269 const knownProps = new Map();4270 const deduped = [];4271 for (let i = 0; i < properties.length; i++) {4272 const prop = properties[i];4273 // dynamic keys are always allowed4274 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {4275 deduped.push(prop);4276 continue;4277 }4278 const name = prop.key.content;4279 const existing = knownProps.get(name);4280 if (existing) {4281 if (name === 'style' || name === 'class' || isOn(name)) {4282 mergeAsArray(existing, prop);4283 }4284 // unexpected duplicate, should have emitted error during parse4285 }4286 else {4287 knownProps.set(name, prop);4288 deduped.push(prop);4289 }4290 }4291 return deduped;4292}4293function mergeAsArray(existing, incoming) {4294 if (existing.value.type === 17 /* JS_ARRAY_EXPRESSION */) {4295 existing.value.elements.push(incoming.value);4296 }4297 else {4298 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);4299 }4300}4301function buildDirectiveArgs(dir, context) {4302 const dirArgs = [];4303 const runtime = directiveImportMap.get(dir);4304 if (runtime) {4305 // built-in directive with runtime4306 dirArgs.push(context.helperString(runtime));4307 }4308 else {4309 {4310 // inject statement for resolving directive4311 context.helper(RESOLVE_DIRECTIVE);4312 context.directives.add(dir.name);4313 dirArgs.push(toValidAssetId(dir.name, `directive`));4314 }4315 }4316 const { loc } = dir;4317 if (dir.exp)4318 dirArgs.push(dir.exp);4319 if (dir.arg) {4320 if (!dir.exp) {4321 dirArgs.push(`void 0`);4322 }4323 dirArgs.push(dir.arg);4324 }4325 if (Object.keys(dir.modifiers).length) {4326 if (!dir.arg) {4327 if (!dir.exp) {4328 dirArgs.push(`void 0`);4329 }4330 dirArgs.push(`void 0`);4331 }4332 const trueExpression = createSimpleExpression(`true`, false, loc);4333 dirArgs.push(createObjectExpression(dir.modifiers.map(modifier => createObjectProperty(modifier, trueExpression)), loc));4334 }4335 return createArrayExpression(dirArgs, dir.loc);4336}4337function stringifyDynamicPropNames(props) {4338 let propsNamesString = `[`;4339 for (let i = 0, l = props.length; i < l; i++) {4340 propsNamesString += JSON.stringify(props[i]);4341 if (i < l - 1)4342 propsNamesString += ', ';4343 }4344 return propsNamesString + `]`;4345}4346function isComponentTag(tag) {4347 return tag === 'component' || tag === 'Component';4348}4349const transformSlotOutlet = (node, context) => {4350 if (isSlotOutlet(node)) {4351 const { children, loc } = node;4352 const { slotName, slotProps } = processSlotOutlet(node, context);4353 const slotArgs = [4354 context.prefixIdentifiers ? `_ctx.$slots` : `$slots`,4355 slotName,4356 '{}',4357 'undefined',4358 'true'4359 ];4360 let expectedLen = 2;4361 if (slotProps) {4362 slotArgs[2] = slotProps;4363 expectedLen = 3;4364 }4365 if (children.length) {4366 slotArgs[3] = createFunctionExpression([], children, false, false, loc);4367 expectedLen = 4;4368 }4369 if (context.scopeId && !context.slotted) {4370 expectedLen = 5;4371 }4372 slotArgs.splice(expectedLen); // remove unused arguments4373 node.codegenNode = createCallExpression(context.helper(RENDER_SLOT), slotArgs, loc);4374 }4375};4376function processSlotOutlet(node, context) {4377 let slotName = `"default"`;4378 let slotProps = undefined;4379 const nonNameProps = [];4380 for (let i = 0; i < node.props.length; i++) {4381 const p = node.props[i];4382 if (p.type === 6 /* ATTRIBUTE */) {4383 if (p.value) {4384 if (p.name === 'name') {4385 slotName = JSON.stringify(p.value.content);4386 }4387 else {4388 p.name = camelize(p.name);4389 nonNameProps.push(p);4390 }4391 }4392 }4393 else {4394 if (p.name === 'bind' && isStaticArgOf(p.arg, 'name')) {4395 if (p.exp)4396 slotName = p.exp;4397 }4398 else {4399 if (p.name === 'bind' && p.arg && isStaticExp(p.arg)) {4400 p.arg.content = camelize(p.arg.content);4401 }4402 nonNameProps.push(p);4403 }4404 }4405 }4406 if (nonNameProps.length > 0) {4407 const { props, directives } = buildProps(node, context, nonNameProps);4408 slotProps = props;4409 if (directives.length) {4410 context.onError(createCompilerError(36 /* X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET */, directives[0].loc));4411 }4412 }4413 return {4414 slotName,4415 slotProps4416 };4417}4418const fnExpRE = /^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/;4419const transformOn = (dir, node, context, augmentor) => {4420 const { loc, modifiers, arg } = dir;4421 if (!dir.exp && !modifiers.length) {4422 context.onError(createCompilerError(35 /* X_V_ON_NO_EXPRESSION */, loc));4423 }4424 let eventName;4425 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4426 if (arg.isStatic) {4427 let rawName = arg.content;4428 // TODO deprecate @vnodeXXX usage4429 if (rawName.startsWith('vue:')) {4430 rawName = `vnode-${rawName.slice(4)}`;4431 }4432 // for all event listeners, auto convert it to camelCase. See issue #22494433 eventName = createSimpleExpression(toHandlerKey(camelize(rawName)), true, arg.loc);4434 }4435 else {4436 // #23884437 eventName = createCompoundExpression([4438 `${context.helperString(TO_HANDLER_KEY)}(`,4439 arg,4440 `)`4441 ]);4442 }4443 }4444 else {4445 // already a compound expression.4446 eventName = arg;4447 eventName.children.unshift(`${context.helperString(TO_HANDLER_KEY)}(`);4448 eventName.children.push(`)`);4449 }4450 // handler processing4451 let exp = dir.exp;4452 if (exp && !exp.content.trim()) {4453 exp = undefined;4454 }4455 let shouldCache = context.cacheHandlers && !exp && !context.inVOnce;4456 if (exp) {4457 const isMemberExp = isMemberExpression(exp.content);4458 const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content));4459 const hasMultipleStatements = exp.content.includes(`;`);4460 {4461 validateBrowserExpression(exp, context, false, hasMultipleStatements);4462 }4463 if (isInlineStatement || (shouldCache && isMemberExp)) {4464 // wrap inline statement in a function expression4465 exp = createCompoundExpression([4466 `${isInlineStatement4467 ? `$event`4468 : `${``}(...args)`} => ${hasMultipleStatements ? `{` : `(`}`,4469 exp,4470 hasMultipleStatements ? `}` : `)`4471 ]);4472 }4473 }4474 let ret = {4475 props: [4476 createObjectProperty(eventName, exp || createSimpleExpression(`() => {}`, false, loc))4477 ]4478 };4479 // apply extended compiler augmentor4480 if (augmentor) {4481 ret = augmentor(ret);4482 }4483 if (shouldCache) {4484 // cache handlers so that it's always the same handler being passed down.4485 // this avoids unnecessary re-renders when users use inline handlers on4486 // components.4487 ret.props[0].value = context.cache(ret.props[0].value);4488 }4489 // mark the key as handler for props normalization check4490 ret.props.forEach(p => (p.key.isHandlerKey = true));4491 return ret;4492};4493// v-bind without arg is handled directly in ./transformElements.ts due to it affecting4494// codegen for the entire props object. This transform here is only for v-bind4495// *with* args.4496const transformBind = (dir, _node, context) => {4497 const { exp, modifiers, loc } = dir;4498 const arg = dir.arg;4499 if (arg.type !== 4 /* SIMPLE_EXPRESSION */) {4500 arg.children.unshift(`(`);4501 arg.children.push(`) || ""`);4502 }4503 else if (!arg.isStatic) {4504 arg.content = `${arg.content} || ""`;4505 }4506 // .sync is replaced by v-model:arg4507 if (modifiers.includes('camel')) {4508 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4509 if (arg.isStatic) {4510 arg.content = camelize(arg.content);4511 }4512 else {4513 arg.content = `${context.helperString(CAMELIZE)}(${arg.content})`;4514 }4515 }4516 else {4517 arg.children.unshift(`${context.helperString(CAMELIZE)}(`);4518 arg.children.push(`)`);4519 }4520 }4521 if (!context.inSSR) {4522 if (modifiers.includes('prop')) {4523 injectPrefix(arg, '.');4524 }4525 if (modifiers.includes('attr')) {4526 injectPrefix(arg, '^');4527 }4528 }4529 if (!exp ||4530 (exp.type === 4 /* SIMPLE_EXPRESSION */ && !exp.content.trim())) {4531 context.onError(createCompilerError(34 /* X_V_BIND_NO_EXPRESSION */, loc));4532 return {4533 props: [createObjectProperty(arg, createSimpleExpression('', true, loc))]4534 };4535 }4536 return {4537 props: [createObjectProperty(arg, exp)]4538 };4539};4540const injectPrefix = (arg, prefix) => {4541 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4542 if (arg.isStatic) {4543 arg.content = prefix + arg.content;4544 }4545 else {4546 arg.content = `\`${prefix}\${${arg.content}}\``;4547 }4548 }4549 else {4550 arg.children.unshift(`'${prefix}' + (`);4551 arg.children.push(`)`);4552 }4553};4554// Merge adjacent text nodes and expressions into a single expression4555// e.g. <div>abc {{ d }} {{ e }}</div> should have a single expression node as child.4556const transformText = (node, context) => {4557 if (node.type === 0 /* ROOT */ ||4558 node.type === 1 /* ELEMENT */ ||4559 node.type === 11 /* FOR */ ||4560 node.type === 10 /* IF_BRANCH */) {4561 // perform the transform on node exit so that all expressions have already4562 // been processed.4563 return () => {4564 const children = node.children;4565 let currentContainer = undefined;4566 let hasText = false;4567 for (let i = 0; i < children.length; i++) {4568 const child = children[i];4569 if (isText(child)) {4570 hasText = true;4571 for (let j = i + 1; j < children.length; j++) {4572 const next = children[j];4573 if (isText(next)) {4574 if (!currentContainer) {4575 currentContainer = children[i] = {4576 type: 8 /* COMPOUND_EXPRESSION */,4577 loc: child.loc,4578 children: [child]4579 };4580 }4581 // merge adjacent text node into current4582 currentContainer.children.push(` + `, next);4583 children.splice(j, 1);4584 j--;4585 }4586 else {4587 currentContainer = undefined;4588 break;4589 }4590 }4591 }4592 }4593 if (!hasText ||4594 // if this is a plain element with a single text child, leave it4595 // as-is since the runtime has dedicated fast path for this by directly4596 // setting textContent of the element.4597 // for component root it's always normalized anyway.4598 (children.length === 1 &&4599 (node.type === 0 /* ROOT */ ||4600 (node.type === 1 /* ELEMENT */ &&4601 node.tagType === 0 /* ELEMENT */ &&4602 // #37564603 // custom directives can potentially add DOM elements arbitrarily,4604 // we need to avoid setting textContent of the element at runtime4605 // to avoid accidentally overwriting the DOM elements added4606 // by the user through custom directives.4607 !node.props.find(p => p.type === 7 /* DIRECTIVE */ &&4608 !context.directiveTransforms[p.name]) &&4609 // in compat mode, <template> tags with no special directives4610 // will be rendered as a fragment so its children must be4611 // converted into vnodes.4612 !(node.tag === 'template'))))) {4613 return;4614 }4615 // pre-convert text nodes into createTextVNode(text) calls to avoid4616 // runtime normalization.4617 for (let i = 0; i < children.length; i++) {4618 const child = children[i];4619 if (isText(child) || child.type === 8 /* COMPOUND_EXPRESSION */) {4620 const callArgs = [];4621 // createTextVNode defaults to single whitespace, so if it is a4622 // single space the code could be an empty call to save bytes.4623 if (child.type !== 2 /* TEXT */ || child.content !== ' ') {4624 callArgs.push(child);4625 }4626 // mark dynamic text with flag so it gets patched inside a block4627 if (!context.ssr &&4628 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {4629 callArgs.push(1 /* TEXT */ +4630 (` /* ${PatchFlagNames[1 /* TEXT */]} */` ));4631 }4632 children[i] = {4633 type: 12 /* TEXT_CALL */,4634 content: child,4635 loc: child.loc,4636 codegenNode: createCallExpression(context.helper(CREATE_TEXT), callArgs)4637 };4638 }4639 }4640 };4641 }4642};4643const seen = new WeakSet();4644const transformOnce = (node, context) => {4645 if (node.type === 1 /* ELEMENT */ && findDir(node, 'once', true)) {4646 if (seen.has(node) || context.inVOnce) {4647 return;4648 }4649 seen.add(node);4650 context.inVOnce = true;4651 context.helper(SET_BLOCK_TRACKING);4652 return () => {4653 context.inVOnce = false;4654 const cur = context.currentNode;4655 if (cur.codegenNode) {4656 cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */);4657 }4658 };4659 }4660};4661const transformModel = (dir, node, context) => {4662 const { exp, arg } = dir;4663 if (!exp) {4664 context.onError(createCompilerError(41 /* X_V_MODEL_NO_EXPRESSION */, dir.loc));4665 return createTransformProps();4666 }4667 const rawExp = exp.loc.source;4668 const expString = exp.type === 4 /* SIMPLE_EXPRESSION */ ? exp.content : rawExp;4669 // im SFC <script setup> inline mode, the exp may have been transformed into4670 // _unref(exp)4671 context.bindingMetadata[rawExp];4672 const maybeRef = !true /* SETUP_CONST */;4673 if (!expString.trim() ||4674 (!isMemberExpression(expString) && !maybeRef)) {4675 context.onError(createCompilerError(42 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));4676 return createTransformProps();4677 }4678 const propName = arg ? arg : createSimpleExpression('modelValue', true);4679 const eventName = arg4680 ? isStaticExp(arg)4681 ? `onUpdate:${arg.content}`4682 : createCompoundExpression(['"onUpdate:" + ', arg])4683 : `onUpdate:modelValue`;4684 let assignmentExp;4685 const eventArg = context.isTS ? `($event: any)` : `$event`;4686 {4687 assignmentExp = createCompoundExpression([4688 `${eventArg} => ((`,4689 exp,4690 `) = $event)`4691 ]);4692 }4693 const props = [4694 // modelValue: foo4695 createObjectProperty(propName, dir.exp),4696 // "onUpdate:modelValue": $event => (foo = $event)4697 createObjectProperty(eventName, assignmentExp)4698 ];4699 // modelModifiers: { foo: true, "bar-baz": true }4700 if (dir.modifiers.length && node.tagType === 1 /* COMPONENT */) {4701 const modifiers = dir.modifiers4702 .map(m => (isSimpleIdentifier(m) ? m : JSON.stringify(m)) + `: true`)4703 .join(`, `);4704 const modifiersKey = arg4705 ? isStaticExp(arg)4706 ? `${arg.content}Modifiers`4707 : createCompoundExpression([arg, ' + "Modifiers"'])4708 : `modelModifiers`;4709 props.push(createObjectProperty(modifiersKey, createSimpleExpression(`{ ${modifiers} }`, false, dir.loc, 2 /* CAN_HOIST */)));4710 }4711 return createTransformProps(props);4712};4713function createTransformProps(props = []) {4714 return { props };4715}4716const validDivisionCharRE = /[\w).+\-_$\]]/;4717const transformFilter = (node, context) => {4718 if (!isCompatEnabled("COMPILER_FILTER" /* COMPILER_FILTERS */, context)) {4719 return;4720 }4721 if (node.type === 5 /* INTERPOLATION */) {4722 // filter rewrite is applied before expression transform so only4723 // simple expressions are possible at this stage4724 rewriteFilter(node.content, context);4725 }4726 if (node.type === 1 /* ELEMENT */) {4727 node.props.forEach((prop) => {4728 if (prop.type === 7 /* DIRECTIVE */ &&4729 prop.name !== 'for' &&4730 prop.exp) {4731 rewriteFilter(prop.exp, context);4732 }...
compiler-core.esm-bundler.js
Source:compiler-core.esm-bundler.js
...772 else {773 return value;774 }775}776function isCompatEnabled(key, context) {777 const mode = getCompatValue('MODE', context);778 const value = getCompatValue(key, context);779 // in v3 mode, only enable if explicitly set to true780 // otherwise enable for any non-false value781 return mode === 3 ? value === true : value !== false;782}783function checkCompatEnabled(key, context, loc, ...args) {784 const enabled = isCompatEnabled(key, context);785 if ((process.env.NODE_ENV !== 'production') && enabled) {786 warnDeprecation(key, context, loc, ...args);787 }788 return enabled;789}790function warnDeprecation(key, context, loc, ...args) {791 const val = getCompatValue(key, context);792 if (val === 'suppress-warning') {793 return;794 }795 const { message, link } = deprecationData[key];796 const msg = `(deprecation ${key}) ${typeof message === 'function' ? message(...args) : message}${link ? `\n Details: ${link}` : ``}`;797 const err = new SyntaxError(msg);798 err.code = key;799 if (loc)800 err.loc = loc;801 context.onWarn(err);802}803// The default decoder only provides escapes for characters reserved as part of804// the template syntax, and is only used if the custom renderer did not provide805// a platform-specific decoder.806const decodeRE = /&(gt|lt|amp|apos|quot);/g;807const decodeMap = {808 gt: '>',809 lt: '<',810 amp: '&',811 apos: "'",812 quot: '"'813};814const defaultParserOptions = {815 delimiters: [`{{`, `}}`],816 getNamespace: () => 0 /* HTML */,817 getTextMode: () => 0 /* DATA */,818 isVoidTag: NO,819 isPreTag: NO,820 isCustomElement: NO,821 decodeEntities: (rawText) => rawText.replace(decodeRE, (_, p1) => decodeMap[p1]),822 onError: defaultOnError,823 onWarn: defaultOnWarn,824 comments: (process.env.NODE_ENV !== 'production')825};826function baseParse(content, options = {}) {827 const context = createParserContext(content, options);828 const start = getCursor(context);829 return createRoot(parseChildren(context, 0 /* DATA */, []), getSelection(context, start));830}831function createParserContext(content, rawOptions) {832 const options = extend({}, defaultParserOptions);833 let key;834 for (key in rawOptions) {835 // @ts-ignore836 options[key] =837 rawOptions[key] === undefined838 ? defaultParserOptions[key]839 : rawOptions[key];840 }841 return {842 options,843 column: 1,844 line: 1,845 offset: 0,846 originalSource: content,847 source: content,848 inPre: false,849 inVPre: false,850 onWarn: options.onWarn851 };852}853function parseChildren(context, mode, ancestors) {854 const parent = last(ancestors);855 const ns = parent ? parent.ns : 0 /* HTML */;856 const nodes = [];857 while (!isEnd(context, mode, ancestors)) {858 const s = context.source;859 let node = undefined;860 if (mode === 0 /* DATA */ || mode === 1 /* RCDATA */) {861 if (!context.inVPre && startsWith(s, context.options.delimiters[0])) {862 // '{{'863 node = parseInterpolation(context, mode);864 }865 else if (mode === 0 /* DATA */ && s[0] === '<') {866 // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state867 if (s.length === 1) {868 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 1);869 }870 else if (s[1] === '!') {871 // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state872 if (startsWith(s, '<!--')) {873 node = parseComment(context);874 }875 else if (startsWith(s, '<!DOCTYPE')) {876 // Ignore DOCTYPE by a limitation.877 node = parseBogusComment(context);878 }879 else if (startsWith(s, '<![CDATA[')) {880 if (ns !== 0 /* HTML */) {881 node = parseCDATA(context, ancestors);882 }883 else {884 emitError(context, 1 /* CDATA_IN_HTML_CONTENT */);885 node = parseBogusComment(context);886 }887 }888 else {889 emitError(context, 11 /* INCORRECTLY_OPENED_COMMENT */);890 node = parseBogusComment(context);891 }892 }893 else if (s[1] === '/') {894 // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state895 if (s.length === 2) {896 emitError(context, 5 /* EOF_BEFORE_TAG_NAME */, 2);897 }898 else if (s[2] === '>') {899 emitError(context, 14 /* MISSING_END_TAG_NAME */, 2);900 advanceBy(context, 3);901 continue;902 }903 else if (/[a-z]/i.test(s[2])) {904 emitError(context, 23 /* X_INVALID_END_TAG */);905 parseTag(context, 1 /* End */, parent);906 continue;907 }908 else {909 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 2);910 node = parseBogusComment(context);911 }912 }913 else if (/[a-z]/i.test(s[1])) {914 node = parseElement(context, ancestors);915 // 2.x <template> with no directive compat916 if (isCompatEnabled("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context) &&917 node &&918 node.tag === 'template' &&919 !node.props.some(p => p.type === 7 /* DIRECTIVE */ &&920 isSpecialTemplateDirective(p.name))) {921 (process.env.NODE_ENV !== 'production') &&922 warnDeprecation("COMPILER_NATIVE_TEMPLATE" /* COMPILER_NATIVE_TEMPLATE */, context, node.loc);923 node = node.children;924 }925 }926 else if (s[1] === '?') {927 emitError(context, 21 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */, 1);928 node = parseBogusComment(context);929 }930 else {931 emitError(context, 12 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 1);932 }933 }934 }935 if (!node) {936 node = parseText(context, mode);937 }938 if (isArray(node)) {939 for (let i = 0; i < node.length; i++) {940 pushNode(nodes, node[i]);941 }942 }943 else {944 pushNode(nodes, node);945 }946 }947 // Whitespace handling strategy like v2948 let removedWhitespace = false;949 if (mode !== 2 /* RAWTEXT */ && mode !== 1 /* RCDATA */) {950 const shouldCondense = context.options.whitespace !== 'preserve';951 for (let i = 0; i < nodes.length; i++) {952 const node = nodes[i];953 if (!context.inPre && node.type === 2 /* TEXT */) {954 if (!/[^\t\r\n\f ]/.test(node.content)) {955 const prev = nodes[i - 1];956 const next = nodes[i + 1];957 // Remove if:958 // - the whitespace is the first or last node, or:959 // - (condense mode) the whitespace is adjacent to a comment, or:960 // - (condense mode) the whitespace is between two elements AND contains newline961 if (!prev ||962 !next ||963 (shouldCondense &&964 (prev.type === 3 /* COMMENT */ ||965 next.type === 3 /* COMMENT */ ||966 (prev.type === 1 /* ELEMENT */ &&967 next.type === 1 /* ELEMENT */ &&968 /[\r\n]/.test(node.content))))) {969 removedWhitespace = true;970 nodes[i] = null;971 }972 else {973 // Otherwise, the whitespace is condensed into a single space974 node.content = ' ';975 }976 }977 else if (shouldCondense) {978 // in condense mode, consecutive whitespaces in text are condensed979 // down to a single space.980 node.content = node.content.replace(/[\t\r\n\f ]+/g, ' ');981 }982 }983 // Remove comment nodes if desired by configuration.984 else if (node.type === 3 /* COMMENT */ && !context.options.comments) {985 removedWhitespace = true;986 nodes[i] = null;987 }988 }989 if (context.inPre && parent && context.options.isPreTag(parent.tag)) {990 // remove leading newline per html spec991 // https://html.spec.whatwg.org/multipage/grouping-content.html#the-pre-element992 const first = nodes[0];993 if (first && first.type === 2 /* TEXT */) {994 first.content = first.content.replace(/^\r?\n/, '');995 }996 }997 }998 return removedWhitespace ? nodes.filter(Boolean) : nodes;999}1000function pushNode(nodes, node) {1001 if (node.type === 2 /* TEXT */) {1002 const prev = last(nodes);1003 // Merge if both this and the previous node are text and those are1004 // consecutive. This happens for cases like "a < b".1005 if (prev &&1006 prev.type === 2 /* TEXT */ &&1007 prev.loc.end.offset === node.loc.start.offset) {1008 prev.content += node.content;1009 prev.loc.end = node.loc.end;1010 prev.loc.source += node.loc.source;1011 return;1012 }1013 }1014 nodes.push(node);1015}1016function parseCDATA(context, ancestors) {1017 advanceBy(context, 9);1018 const nodes = parseChildren(context, 3 /* CDATA */, ancestors);1019 if (context.source.length === 0) {1020 emitError(context, 6 /* EOF_IN_CDATA */);1021 }1022 else {1023 advanceBy(context, 3);1024 }1025 return nodes;1026}1027function parseComment(context) {1028 const start = getCursor(context);1029 let content;1030 // Regular comment.1031 const match = /--(\!)?>/.exec(context.source);1032 if (!match) {1033 content = context.source.slice(4);1034 advanceBy(context, context.source.length);1035 emitError(context, 7 /* EOF_IN_COMMENT */);1036 }1037 else {1038 if (match.index <= 3) {1039 emitError(context, 0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */);1040 }1041 if (match[1]) {1042 emitError(context, 10 /* INCORRECTLY_CLOSED_COMMENT */);1043 }1044 content = context.source.slice(4, match.index);1045 // Advancing with reporting nested comments.1046 const s = context.source.slice(0, match.index);1047 let prevIndex = 1, nestedIndex = 0;1048 while ((nestedIndex = s.indexOf('<!--', prevIndex)) !== -1) {1049 advanceBy(context, nestedIndex - prevIndex + 1);1050 if (nestedIndex + 4 < s.length) {1051 emitError(context, 16 /* NESTED_COMMENT */);1052 }1053 prevIndex = nestedIndex + 1;1054 }1055 advanceBy(context, match.index + match[0].length - prevIndex + 1);1056 }1057 return {1058 type: 3 /* COMMENT */,1059 content,1060 loc: getSelection(context, start)1061 };1062}1063function parseBogusComment(context) {1064 const start = getCursor(context);1065 const contentStart = context.source[1] === '?' ? 1 : 2;1066 let content;1067 const closeIndex = context.source.indexOf('>');1068 if (closeIndex === -1) {1069 content = context.source.slice(contentStart);1070 advanceBy(context, context.source.length);1071 }1072 else {1073 content = context.source.slice(contentStart, closeIndex);1074 advanceBy(context, closeIndex + 1);1075 }1076 return {1077 type: 3 /* COMMENT */,1078 content,1079 loc: getSelection(context, start)1080 };1081}1082function parseElement(context, ancestors) {1083 // Start tag.1084 const wasInPre = context.inPre;1085 const wasInVPre = context.inVPre;1086 const parent = last(ancestors);1087 const element = parseTag(context, 0 /* Start */, parent);1088 const isPreBoundary = context.inPre && !wasInPre;1089 const isVPreBoundary = context.inVPre && !wasInVPre;1090 if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {1091 // #4030 self-closing <pre> tag1092 if (isPreBoundary) {1093 context.inPre = false;1094 }1095 if (isVPreBoundary) {1096 context.inVPre = false;1097 }1098 return element;1099 }1100 // Children.1101 ancestors.push(element);1102 const mode = context.options.getTextMode(element, parent);1103 const children = parseChildren(context, mode, ancestors);1104 ancestors.pop();1105 // 2.x inline-template compat1106 {1107 const inlineTemplateProp = element.props.find(p => p.type === 6 /* ATTRIBUTE */ && p.name === 'inline-template');1108 if (inlineTemplateProp &&1109 checkCompatEnabled("COMPILER_INLINE_TEMPLATE" /* COMPILER_INLINE_TEMPLATE */, context, inlineTemplateProp.loc)) {1110 const loc = getSelection(context, element.loc.end);1111 inlineTemplateProp.value = {1112 type: 2 /* TEXT */,1113 content: loc.source,1114 loc1115 };1116 }1117 }1118 element.children = children;1119 // End tag.1120 if (startsWithEndTagOpen(context.source, element.tag)) {1121 parseTag(context, 1 /* End */, parent);1122 }1123 else {1124 emitError(context, 24 /* X_MISSING_END_TAG */, 0, element.loc.start);1125 if (context.source.length === 0 && element.tag.toLowerCase() === 'script') {1126 const first = children[0];1127 if (first && startsWith(first.loc.source, '<!--')) {1128 emitError(context, 8 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */);1129 }1130 }1131 }1132 element.loc = getSelection(context, element.loc.start);1133 if (isPreBoundary) {1134 context.inPre = false;1135 }1136 if (isVPreBoundary) {1137 context.inVPre = false;1138 }1139 return element;1140}1141const isSpecialTemplateDirective = /*#__PURE__*/ makeMap(`if,else,else-if,for,slot`);1142function parseTag(context, type, parent) {1143 // Tag open.1144 const start = getCursor(context);1145 const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source);1146 const tag = match[1];1147 const ns = context.options.getNamespace(tag, parent);1148 advanceBy(context, match[0].length);1149 advanceSpaces(context);1150 // save current state in case we need to re-parse attributes with v-pre1151 const cursor = getCursor(context);1152 const currentSource = context.source;1153 // check <pre> tag1154 if (context.options.isPreTag(tag)) {1155 context.inPre = true;1156 }1157 // Attributes.1158 let props = parseAttributes(context, type);1159 // check v-pre1160 if (type === 0 /* Start */ &&1161 !context.inVPre &&1162 props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'pre')) {1163 context.inVPre = true;1164 // reset context1165 extend(context, cursor);1166 context.source = currentSource;1167 // re-parse attrs and filter out v-pre itself1168 props = parseAttributes(context, type).filter(p => p.name !== 'v-pre');1169 }1170 // Tag close.1171 let isSelfClosing = false;1172 if (context.source.length === 0) {1173 emitError(context, 9 /* EOF_IN_TAG */);1174 }1175 else {1176 isSelfClosing = startsWith(context.source, '/>');1177 if (type === 1 /* End */ && isSelfClosing) {1178 emitError(context, 4 /* END_TAG_WITH_TRAILING_SOLIDUS */);1179 }1180 advanceBy(context, isSelfClosing ? 2 : 1);1181 }1182 if (type === 1 /* End */) {1183 return;1184 }1185 // 2.x deprecation checks1186 if ((process.env.NODE_ENV !== 'production') &&1187 isCompatEnabled("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context)) {1188 let hasIf = false;1189 let hasFor = false;1190 for (let i = 0; i < props.length; i++) {1191 const p = props[i];1192 if (p.type === 7 /* DIRECTIVE */) {1193 if (p.name === 'if') {1194 hasIf = true;1195 }1196 else if (p.name === 'for') {1197 hasFor = true;1198 }1199 }1200 if (hasIf && hasFor) {1201 warnDeprecation("COMPILER_V_IF_V_FOR_PRECEDENCE" /* COMPILER_V_IF_V_FOR_PRECEDENCE */, context, getSelection(context, start));1202 break;1203 }1204 }1205 }1206 let tagType = 0 /* ELEMENT */;1207 if (!context.inVPre) {1208 if (tag === 'slot') {1209 tagType = 2 /* SLOT */;1210 }1211 else if (tag === 'template') {1212 if (props.some(p => p.type === 7 /* DIRECTIVE */ && isSpecialTemplateDirective(p.name))) {1213 tagType = 3 /* TEMPLATE */;1214 }1215 }1216 else if (isComponent(tag, props, context)) {1217 tagType = 1 /* COMPONENT */;1218 }1219 }1220 return {1221 type: 1 /* ELEMENT */,1222 ns,1223 tag,1224 tagType,1225 props,1226 isSelfClosing,1227 children: [],1228 loc: getSelection(context, start),1229 codegenNode: undefined // to be created during transform phase1230 };1231}1232function isComponent(tag, props, context) {1233 const options = context.options;1234 if (options.isCustomElement(tag)) {1235 return false;1236 }1237 if (tag === 'component' ||1238 /^[A-Z]/.test(tag) ||1239 isCoreComponent(tag) ||1240 (options.isBuiltInComponent && options.isBuiltInComponent(tag)) ||1241 (options.isNativeTag && !options.isNativeTag(tag))) {1242 return true;1243 }1244 // at this point the tag should be a native tag, but check for potential "is"1245 // casting1246 for (let i = 0; i < props.length; i++) {1247 const p = props[i];1248 if (p.type === 6 /* ATTRIBUTE */) {1249 if (p.name === 'is' && p.value) {1250 if (p.value.content.startsWith('vue:')) {1251 return true;1252 }1253 else if (checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1254 return true;1255 }1256 }1257 }1258 else {1259 // directive1260 // v-is (TODO Deprecate)1261 if (p.name === 'is') {1262 return true;1263 }1264 else if (1265 // :is on plain element - only treat as component in compat mode1266 p.name === 'bind' &&1267 isStaticArgOf(p.arg, 'is') &&1268 true &&1269 checkCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context, p.loc)) {1270 return true;1271 }1272 }1273 }1274}1275function parseAttributes(context, type) {1276 const props = [];1277 const attributeNames = new Set();1278 while (context.source.length > 0 &&1279 !startsWith(context.source, '>') &&1280 !startsWith(context.source, '/>')) {1281 if (startsWith(context.source, '/')) {1282 emitError(context, 22 /* UNEXPECTED_SOLIDUS_IN_TAG */);1283 advanceBy(context, 1);1284 advanceSpaces(context);1285 continue;1286 }1287 if (type === 1 /* End */) {1288 emitError(context, 3 /* END_TAG_WITH_ATTRIBUTES */);1289 }1290 const attr = parseAttribute(context, attributeNames);1291 // Trim whitespace between class1292 // https://github.com/vuejs/vue-next/issues/42511293 if (attr.type === 6 /* ATTRIBUTE */ &&1294 attr.value &&1295 attr.name === 'class') {1296 attr.value.content = attr.value.content.replace(/\s+/g, ' ').trim();1297 }1298 if (type === 0 /* Start */) {1299 props.push(attr);1300 }1301 if (/^[^\t\r\n\f />]/.test(context.source)) {1302 emitError(context, 15 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */);1303 }1304 advanceSpaces(context);1305 }1306 return props;1307}1308function parseAttribute(context, nameSet) {1309 // Name.1310 const start = getCursor(context);1311 const match = /^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(context.source);1312 const name = match[0];1313 if (nameSet.has(name)) {1314 emitError(context, 2 /* DUPLICATE_ATTRIBUTE */);1315 }1316 nameSet.add(name);1317 if (name[0] === '=') {1318 emitError(context, 19 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */);1319 }1320 {1321 const pattern = /["'<]/g;1322 let m;1323 while ((m = pattern.exec(name))) {1324 emitError(context, 17 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */, m.index);1325 }1326 }1327 advanceBy(context, name.length);1328 // Value1329 let value = undefined;1330 if (/^[\t\r\n\f ]*=/.test(context.source)) {1331 advanceSpaces(context);1332 advanceBy(context, 1);1333 advanceSpaces(context);1334 value = parseAttributeValue(context);1335 if (!value) {1336 emitError(context, 13 /* MISSING_ATTRIBUTE_VALUE */);1337 }1338 }1339 const loc = getSelection(context, start);1340 if (!context.inVPre && /^(v-[A-Za-z0-9-]|:|\.|@|#)/.test(name)) {1341 const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^\.|^@|^#)(\[[^\]]+\]|[^\.]+))?(.+)?$/i.exec(name);1342 let isPropShorthand = startsWith(name, '.');1343 let dirName = match[1] ||1344 (isPropShorthand || startsWith(name, ':')1345 ? 'bind'1346 : startsWith(name, '@')1347 ? 'on'1348 : 'slot');1349 let arg;1350 if (match[2]) {1351 const isSlot = dirName === 'slot';1352 const startOffset = name.lastIndexOf(match[2]);1353 const loc = getSelection(context, getNewPosition(context, start, startOffset), getNewPosition(context, start, startOffset + match[2].length + ((isSlot && match[3]) || '').length));1354 let content = match[2];1355 let isStatic = true;1356 if (content.startsWith('[')) {1357 isStatic = false;1358 if (!content.endsWith(']')) {1359 emitError(context, 27 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */);1360 content = content.slice(1);1361 }1362 else {1363 content = content.slice(1, content.length - 1);1364 }1365 }1366 else if (isSlot) {1367 // #1241 special case for v-slot: vuetify relies extensively on slot1368 // names containing dots. v-slot doesn't have any modifiers and Vue 2.x1369 // supports such usage so we are keeping it consistent with 2.x.1370 content += match[3] || '';1371 }1372 arg = {1373 type: 4 /* SIMPLE_EXPRESSION */,1374 content,1375 isStatic,1376 constType: isStatic1377 ? 3 /* CAN_STRINGIFY */1378 : 0 /* NOT_CONSTANT */,1379 loc1380 };1381 }1382 if (value && value.isQuoted) {1383 const valueLoc = value.loc;1384 valueLoc.start.offset++;1385 valueLoc.start.column++;1386 valueLoc.end = advancePositionWithClone(valueLoc.start, value.content);1387 valueLoc.source = valueLoc.source.slice(1, -1);1388 }1389 const modifiers = match[3] ? match[3].slice(1).split('.') : [];1390 if (isPropShorthand)1391 modifiers.push('prop');1392 // 2.x compat v-bind:foo.sync -> v-model:foo1393 if (dirName === 'bind' && arg) {1394 if (modifiers.includes('sync') &&1395 checkCompatEnabled("COMPILER_V_BIND_SYNC" /* COMPILER_V_BIND_SYNC */, context, loc, arg.loc.source)) {1396 dirName = 'model';1397 modifiers.splice(modifiers.indexOf('sync'), 1);1398 }1399 if ((process.env.NODE_ENV !== 'production') && modifiers.includes('prop')) {1400 checkCompatEnabled("COMPILER_V_BIND_PROP" /* COMPILER_V_BIND_PROP */, context, loc);1401 }1402 }1403 return {1404 type: 7 /* DIRECTIVE */,1405 name: dirName,1406 exp: value && {1407 type: 4 /* SIMPLE_EXPRESSION */,1408 content: value.content,1409 isStatic: false,1410 // Treat as non-constant by default. This can be potentially set to1411 // other values by `transformExpression` to make it eligible for hoisting.1412 constType: 0 /* NOT_CONSTANT */,1413 loc: value.loc1414 },1415 arg,1416 modifiers,1417 loc1418 };1419 }1420 // missing directive name or illegal directive name1421 if (!context.inVPre && startsWith(name, 'v-')) {1422 emitError(context, 26 /* X_MISSING_DIRECTIVE_NAME */);1423 }1424 return {1425 type: 6 /* ATTRIBUTE */,1426 name,1427 value: value && {1428 type: 2 /* TEXT */,1429 content: value.content,1430 loc: value.loc1431 },1432 loc1433 };1434}1435function parseAttributeValue(context) {1436 const start = getCursor(context);1437 let content;1438 const quote = context.source[0];1439 const isQuoted = quote === `"` || quote === `'`;1440 if (isQuoted) {1441 // Quoted value.1442 advanceBy(context, 1);1443 const endIndex = context.source.indexOf(quote);1444 if (endIndex === -1) {1445 content = parseTextData(context, context.source.length, 4 /* ATTRIBUTE_VALUE */);1446 }1447 else {1448 content = parseTextData(context, endIndex, 4 /* ATTRIBUTE_VALUE */);1449 advanceBy(context, 1);1450 }1451 }1452 else {1453 // Unquoted1454 const match = /^[^\t\r\n\f >]+/.exec(context.source);1455 if (!match) {1456 return undefined;1457 }1458 const unexpectedChars = /["'<=`]/g;1459 let m;1460 while ((m = unexpectedChars.exec(match[0]))) {1461 emitError(context, 18 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */, m.index);1462 }1463 content = parseTextData(context, match[0].length, 4 /* ATTRIBUTE_VALUE */);1464 }1465 return { content, isQuoted, loc: getSelection(context, start) };1466}1467function parseInterpolation(context, mode) {1468 const [open, close] = context.options.delimiters;1469 const closeIndex = context.source.indexOf(close, open.length);1470 if (closeIndex === -1) {1471 emitError(context, 25 /* X_MISSING_INTERPOLATION_END */);1472 return undefined;1473 }1474 const start = getCursor(context);1475 advanceBy(context, open.length);1476 const innerStart = getCursor(context);1477 const innerEnd = getCursor(context);1478 const rawContentLength = closeIndex - open.length;1479 const rawContent = context.source.slice(0, rawContentLength);1480 const preTrimContent = parseTextData(context, rawContentLength, mode);1481 const content = preTrimContent.trim();1482 const startOffset = preTrimContent.indexOf(content);1483 if (startOffset > 0) {1484 advancePositionWithMutation(innerStart, rawContent, startOffset);1485 }1486 const endOffset = rawContentLength - (preTrimContent.length - content.length - startOffset);1487 advancePositionWithMutation(innerEnd, rawContent, endOffset);1488 advanceBy(context, close.length);1489 return {1490 type: 5 /* INTERPOLATION */,1491 content: {1492 type: 4 /* SIMPLE_EXPRESSION */,1493 isStatic: false,1494 // Set `isConstant` to false by default and will decide in transformExpression1495 constType: 0 /* NOT_CONSTANT */,1496 content,1497 loc: getSelection(context, innerStart, innerEnd)1498 },1499 loc: getSelection(context, start)1500 };1501}1502function parseText(context, mode) {1503 const endTokens = mode === 3 /* CDATA */ ? [']]>'] : ['<', context.options.delimiters[0]];1504 let endIndex = context.source.length;1505 for (let i = 0; i < endTokens.length; i++) {1506 const index = context.source.indexOf(endTokens[i], 1);1507 if (index !== -1 && endIndex > index) {1508 endIndex = index;1509 }1510 }1511 const start = getCursor(context);1512 const content = parseTextData(context, endIndex, mode);1513 return {1514 type: 2 /* TEXT */,1515 content,1516 loc: getSelection(context, start)1517 };1518}1519/**1520 * Get text data with a given length from the current location.1521 * This translates HTML entities in the text data.1522 */1523function parseTextData(context, length, mode) {1524 const rawText = context.source.slice(0, length);1525 advanceBy(context, length);1526 if (mode === 2 /* RAWTEXT */ ||1527 mode === 3 /* CDATA */ ||1528 rawText.indexOf('&') === -1) {1529 return rawText;1530 }1531 else {1532 // DATA or RCDATA containing "&"". Entity decoding required.1533 return context.options.decodeEntities(rawText, mode === 4 /* ATTRIBUTE_VALUE */);1534 }1535}1536function getCursor(context) {1537 const { column, line, offset } = context;1538 return { column, line, offset };1539}1540function getSelection(context, start, end) {1541 end = end || getCursor(context);1542 return {1543 start,1544 end,1545 source: context.originalSource.slice(start.offset, end.offset)1546 };1547}1548function last(xs) {1549 return xs[xs.length - 1];1550}1551function startsWith(source, searchString) {1552 return source.startsWith(searchString);1553}1554function advanceBy(context, numberOfCharacters) {1555 const { source } = context;1556 advancePositionWithMutation(context, source, numberOfCharacters);1557 context.source = source.slice(numberOfCharacters);1558}1559function advanceSpaces(context) {1560 const match = /^[\t\r\n\f ]+/.exec(context.source);1561 if (match) {1562 advanceBy(context, match[0].length);1563 }1564}1565function getNewPosition(context, start, numberOfCharacters) {1566 return advancePositionWithClone(start, context.originalSource.slice(start.offset, numberOfCharacters), numberOfCharacters);1567}1568function emitError(context, code, offset, loc = getCursor(context)) {1569 if (offset) {1570 loc.offset += offset;1571 loc.column += offset;1572 }1573 context.options.onError(createCompilerError(code, {1574 start: loc,1575 end: loc,1576 source: ''1577 }));1578}1579function isEnd(context, mode, ancestors) {1580 const s = context.source;1581 switch (mode) {1582 case 0 /* DATA */:1583 if (startsWith(s, '</')) {1584 // TODO: probably bad performance1585 for (let i = ancestors.length - 1; i >= 0; --i) {1586 if (startsWithEndTagOpen(s, ancestors[i].tag)) {1587 return true;1588 }1589 }1590 }1591 break;1592 case 1 /* RCDATA */:1593 case 2 /* RAWTEXT */: {1594 const parent = last(ancestors);1595 if (parent && startsWithEndTagOpen(s, parent.tag)) {1596 return true;1597 }1598 break;1599 }1600 case 3 /* CDATA */:1601 if (startsWith(s, ']]>')) {1602 return true;1603 }1604 break;1605 }1606 return !s;1607}1608function startsWithEndTagOpen(source, tag) {1609 return (startsWith(source, '</') &&1610 source.slice(2, 2 + tag.length).toLowerCase() === tag.toLowerCase() &&1611 /[\t\r\n\f />]/.test(source[2 + tag.length] || '>'));1612}1613function hoistStatic(root, context) {1614 walk(root, context, 1615 // Root node is unfortunately non-hoistable due to potential parent1616 // fallthrough attributes.1617 isSingleElementRoot(root, root.children[0]));1618}1619function isSingleElementRoot(root, child) {1620 const { children } = root;1621 return (children.length === 1 &&1622 child.type === 1 /* ELEMENT */ &&1623 !isSlotOutlet(child));1624}1625function walk(node, context, doNotHoistNode = false) {1626 const { children } = node;1627 const originalCount = children.length;1628 let hoistedCount = 0;1629 for (let i = 0; i < children.length; i++) {1630 const child = children[i];1631 // only plain elements & text calls are eligible for hoisting.1632 if (child.type === 1 /* ELEMENT */ &&1633 child.tagType === 0 /* ELEMENT */) {1634 const constantType = doNotHoistNode1635 ? 0 /* NOT_CONSTANT */1636 : getConstantType(child, context);1637 if (constantType > 0 /* NOT_CONSTANT */) {1638 if (constantType >= 2 /* CAN_HOIST */) {1639 child.codegenNode.patchFlag =1640 -1 /* HOISTED */ + ((process.env.NODE_ENV !== 'production') ? ` /* HOISTED */` : ``);1641 child.codegenNode = context.hoist(child.codegenNode);1642 hoistedCount++;1643 continue;1644 }1645 }1646 else {1647 // node may contain dynamic children, but its props may be eligible for1648 // hoisting.1649 const codegenNode = child.codegenNode;1650 if (codegenNode.type === 13 /* VNODE_CALL */) {1651 const flag = getPatchFlag(codegenNode);1652 if ((!flag ||1653 flag === 512 /* NEED_PATCH */ ||1654 flag === 1 /* TEXT */) &&1655 getGeneratedPropsConstantType(child, context) >=1656 2 /* CAN_HOIST */) {1657 const props = getNodeProps(child);1658 if (props) {1659 codegenNode.props = context.hoist(props);1660 }1661 }1662 if (codegenNode.dynamicProps) {1663 codegenNode.dynamicProps = context.hoist(codegenNode.dynamicProps);1664 }1665 }1666 }1667 }1668 else if (child.type === 12 /* TEXT_CALL */ &&1669 getConstantType(child.content, context) >= 2 /* CAN_HOIST */) {1670 child.codegenNode = context.hoist(child.codegenNode);1671 hoistedCount++;1672 }1673 // walk further1674 if (child.type === 1 /* ELEMENT */) {1675 const isComponent = child.tagType === 1 /* COMPONENT */;1676 if (isComponent) {1677 context.scopes.vSlot++;1678 }1679 walk(child, context);1680 if (isComponent) {1681 context.scopes.vSlot--;1682 }1683 }1684 else if (child.type === 11 /* FOR */) {1685 // Do not hoist v-for single child because it has to be a block1686 walk(child, context, child.children.length === 1);1687 }1688 else if (child.type === 9 /* IF */) {1689 for (let i = 0; i < child.branches.length; i++) {1690 // Do not hoist v-if single child because it has to be a block1691 walk(child.branches[i], context, child.branches[i].children.length === 1);1692 }1693 }1694 }1695 if (hoistedCount && context.transformHoist) {1696 context.transformHoist(children, context, node);1697 }1698 // all children were hoisted - the entire children array is hoistable.1699 if (hoistedCount &&1700 hoistedCount === originalCount &&1701 node.type === 1 /* ELEMENT */ &&1702 node.tagType === 0 /* ELEMENT */ &&1703 node.codegenNode &&1704 node.codegenNode.type === 13 /* VNODE_CALL */ &&1705 isArray(node.codegenNode.children)) {1706 node.codegenNode.children = context.hoist(createArrayExpression(node.codegenNode.children));1707 }1708}1709function getConstantType(node, context) {1710 const { constantCache } = context;1711 switch (node.type) {1712 case 1 /* ELEMENT */:1713 if (node.tagType !== 0 /* ELEMENT */) {1714 return 0 /* NOT_CONSTANT */;1715 }1716 const cached = constantCache.get(node);1717 if (cached !== undefined) {1718 return cached;1719 }1720 const codegenNode = node.codegenNode;1721 if (codegenNode.type !== 13 /* VNODE_CALL */) {1722 return 0 /* NOT_CONSTANT */;1723 }1724 if (codegenNode.isBlock &&1725 node.tag !== 'svg' &&1726 node.tag !== 'foreignObject') {1727 return 0 /* NOT_CONSTANT */;1728 }1729 const flag = getPatchFlag(codegenNode);1730 if (!flag) {1731 let returnType = 3 /* CAN_STRINGIFY */;1732 // Element itself has no patch flag. However we still need to check:1733 // 1. Even for a node with no patch flag, it is possible for it to contain1734 // non-hoistable expressions that refers to scope variables, e.g. compiler1735 // injected keys or cached event handlers. Therefore we need to always1736 // check the codegenNode's props to be sure.1737 const generatedPropsType = getGeneratedPropsConstantType(node, context);1738 if (generatedPropsType === 0 /* NOT_CONSTANT */) {1739 constantCache.set(node, 0 /* NOT_CONSTANT */);1740 return 0 /* NOT_CONSTANT */;1741 }1742 if (generatedPropsType < returnType) {1743 returnType = generatedPropsType;1744 }1745 // 2. its children.1746 for (let i = 0; i < node.children.length; i++) {1747 const childType = getConstantType(node.children[i], context);1748 if (childType === 0 /* NOT_CONSTANT */) {1749 constantCache.set(node, 0 /* NOT_CONSTANT */);1750 return 0 /* NOT_CONSTANT */;1751 }1752 if (childType < returnType) {1753 returnType = childType;1754 }1755 }1756 // 3. if the type is not already CAN_SKIP_PATCH which is the lowest non-01757 // type, check if any of the props can cause the type to be lowered1758 // we can skip can_patch because it's guaranteed by the absence of a1759 // patchFlag.1760 if (returnType > 1 /* CAN_SKIP_PATCH */) {1761 for (let i = 0; i < node.props.length; i++) {1762 const p = node.props[i];1763 if (p.type === 7 /* DIRECTIVE */ && p.name === 'bind' && p.exp) {1764 const expType = getConstantType(p.exp, context);1765 if (expType === 0 /* NOT_CONSTANT */) {1766 constantCache.set(node, 0 /* NOT_CONSTANT */);1767 return 0 /* NOT_CONSTANT */;1768 }1769 if (expType < returnType) {1770 returnType = expType;1771 }1772 }1773 }1774 }1775 // only svg/foreignObject could be block here, however if they are1776 // static then they don't need to be blocks since there will be no1777 // nested updates.1778 if (codegenNode.isBlock) {1779 context.removeHelper(OPEN_BLOCK);1780 context.removeHelper(getVNodeBlockHelper(context.inSSR, codegenNode.isComponent));1781 codegenNode.isBlock = false;1782 context.helper(getVNodeHelper(context.inSSR, codegenNode.isComponent));1783 }1784 constantCache.set(node, returnType);1785 return returnType;1786 }1787 else {1788 constantCache.set(node, 0 /* NOT_CONSTANT */);1789 return 0 /* NOT_CONSTANT */;1790 }1791 case 2 /* TEXT */:1792 case 3 /* COMMENT */:1793 return 3 /* CAN_STRINGIFY */;1794 case 9 /* IF */:1795 case 11 /* FOR */:1796 case 10 /* IF_BRANCH */:1797 return 0 /* NOT_CONSTANT */;1798 case 5 /* INTERPOLATION */:1799 case 12 /* TEXT_CALL */:1800 return getConstantType(node.content, context);1801 case 4 /* SIMPLE_EXPRESSION */:1802 return node.constType;1803 case 8 /* COMPOUND_EXPRESSION */:1804 let returnType = 3 /* CAN_STRINGIFY */;1805 for (let i = 0; i < node.children.length; i++) {1806 const child = node.children[i];1807 if (isString(child) || isSymbol(child)) {1808 continue;1809 }1810 const childType = getConstantType(child, context);1811 if (childType === 0 /* NOT_CONSTANT */) {1812 return 0 /* NOT_CONSTANT */;1813 }1814 else if (childType < returnType) {1815 returnType = childType;1816 }1817 }1818 return returnType;1819 default:1820 if ((process.env.NODE_ENV !== 'production')) ;1821 return 0 /* NOT_CONSTANT */;1822 }1823}1824const allowHoistedHelperSet = new Set([1825 NORMALIZE_CLASS,1826 NORMALIZE_STYLE,1827 NORMALIZE_PROPS,1828 GUARD_REACTIVE_PROPS1829]);1830function getConstantTypeOfHelperCall(value, context) {1831 if (value.type === 14 /* JS_CALL_EXPRESSION */ &&1832 !isString(value.callee) &&1833 allowHoistedHelperSet.has(value.callee)) {1834 const arg = value.arguments[0];1835 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {1836 return getConstantType(arg, context);1837 }1838 else if (arg.type === 14 /* JS_CALL_EXPRESSION */) {1839 // in the case of nested helper call, e.g. `normalizeProps(guardReactiveProps(exp))`1840 return getConstantTypeOfHelperCall(arg, context);1841 }1842 }1843 return 0 /* NOT_CONSTANT */;1844}1845function getGeneratedPropsConstantType(node, context) {1846 let returnType = 3 /* CAN_STRINGIFY */;1847 const props = getNodeProps(node);1848 if (props && props.type === 15 /* JS_OBJECT_EXPRESSION */) {1849 const { properties } = props;1850 for (let i = 0; i < properties.length; i++) {1851 const { key, value } = properties[i];1852 const keyType = getConstantType(key, context);1853 if (keyType === 0 /* NOT_CONSTANT */) {1854 return keyType;1855 }1856 if (keyType < returnType) {1857 returnType = keyType;1858 }1859 let valueType;1860 if (value.type === 4 /* SIMPLE_EXPRESSION */) {1861 valueType = getConstantType(value, context);1862 }1863 else if (value.type === 14 /* JS_CALL_EXPRESSION */) {1864 // some helper calls can be hoisted,1865 // such as the `normalizeProps` generated by the compiler for pre-normalize class,1866 // in this case we need to respect the ConstantType of the helper's arguments1867 valueType = getConstantTypeOfHelperCall(value, context);1868 }1869 else {1870 valueType = 0 /* NOT_CONSTANT */;1871 }1872 if (valueType === 0 /* NOT_CONSTANT */) {1873 return valueType;1874 }1875 if (valueType < returnType) {1876 returnType = valueType;1877 }1878 }1879 }1880 return returnType;1881}1882function getNodeProps(node) {1883 const codegenNode = node.codegenNode;1884 if (codegenNode.type === 13 /* VNODE_CALL */) {1885 return codegenNode.props;1886 }1887}1888function getPatchFlag(node) {1889 const flag = node.patchFlag;1890 return flag ? parseInt(flag, 10) : undefined;1891}1892function createTransformContext(root, { filename = '', prefixIdentifiers = false, hoistStatic = false, cacheHandlers = false, nodeTransforms = [], directiveTransforms = {}, transformHoist = null, isBuiltInComponent = NOOP, isCustomElement = NOOP, expressionPlugins = [], scopeId = null, slotted = true, ssr = false, inSSR = false, ssrCssVars = ``, bindingMetadata = EMPTY_OBJ, inline = false, isTS = false, onError = defaultOnError, onWarn = defaultOnWarn, compatConfig }) {1893 const nameMatch = filename.replace(/\?.*$/, '').match(/([^/\\]+)\.\w+$/);1894 const context = {1895 // options1896 selfName: nameMatch && capitalize(camelize$1(nameMatch[1])),1897 prefixIdentifiers,1898 hoistStatic,1899 cacheHandlers,1900 nodeTransforms,1901 directiveTransforms,1902 transformHoist,1903 isBuiltInComponent,1904 isCustomElement,1905 expressionPlugins,1906 scopeId,1907 slotted,1908 ssr,1909 inSSR,1910 ssrCssVars,1911 bindingMetadata,1912 inline,1913 isTS,1914 onError,1915 onWarn,1916 compatConfig,1917 // state1918 root,1919 helpers: new Map(),1920 components: new Set(),1921 directives: new Set(),1922 hoists: [],1923 imports: [],1924 constantCache: new Map(),1925 temps: 0,1926 cached: 0,1927 identifiers: Object.create(null),1928 scopes: {1929 vFor: 0,1930 vSlot: 0,1931 vPre: 0,1932 vOnce: 01933 },1934 parent: null,1935 currentNode: root,1936 childIndex: 0,1937 inVOnce: false,1938 // methods1939 helper(name) {1940 const count = context.helpers.get(name) || 0;1941 context.helpers.set(name, count + 1);1942 return name;1943 },1944 removeHelper(name) {1945 const count = context.helpers.get(name);1946 if (count) {1947 const currentCount = count - 1;1948 if (!currentCount) {1949 context.helpers.delete(name);1950 }1951 else {1952 context.helpers.set(name, currentCount);1953 }1954 }1955 },1956 helperString(name) {1957 return `_${helperNameMap[context.helper(name)]}`;1958 },1959 replaceNode(node) {1960 /* istanbul ignore if */1961 if ((process.env.NODE_ENV !== 'production')) {1962 if (!context.currentNode) {1963 throw new Error(`Node being replaced is already removed.`);1964 }1965 if (!context.parent) {1966 throw new Error(`Cannot replace root node.`);1967 }1968 }1969 context.parent.children[context.childIndex] = context.currentNode = node;1970 },1971 removeNode(node) {1972 if ((process.env.NODE_ENV !== 'production') && !context.parent) {1973 throw new Error(`Cannot remove root node.`);1974 }1975 const list = context.parent.children;1976 const removalIndex = node1977 ? list.indexOf(node)1978 : context.currentNode1979 ? context.childIndex1980 : -1;1981 /* istanbul ignore if */1982 if ((process.env.NODE_ENV !== 'production') && removalIndex < 0) {1983 throw new Error(`node being removed is not a child of current parent`);1984 }1985 if (!node || node === context.currentNode) {1986 // current node removed1987 context.currentNode = null;1988 context.onNodeRemoved();1989 }1990 else {1991 // sibling node removed1992 if (context.childIndex > removalIndex) {1993 context.childIndex--;1994 context.onNodeRemoved();1995 }1996 }1997 context.parent.children.splice(removalIndex, 1);1998 },1999 onNodeRemoved: () => { },2000 addIdentifiers(exp) {2001 },2002 removeIdentifiers(exp) {2003 },2004 hoist(exp) {2005 if (isString(exp))2006 exp = createSimpleExpression(exp);2007 context.hoists.push(exp);2008 const identifier = createSimpleExpression(`_hoisted_${context.hoists.length}`, false, exp.loc, 2 /* CAN_HOIST */);2009 identifier.hoisted = exp;2010 return identifier;2011 },2012 cache(exp, isVNode = false) {2013 return createCacheExpression(context.cached++, exp, isVNode);2014 }2015 };2016 {2017 context.filters = new Set();2018 }2019 return context;2020}2021function transform(root, options) {2022 const context = createTransformContext(root, options);2023 traverseNode(root, context);2024 if (options.hoistStatic) {2025 hoistStatic(root, context);2026 }2027 if (!options.ssr) {2028 createRootCodegen(root, context);2029 }2030 // finalize meta information2031 root.helpers = [...context.helpers.keys()];2032 root.components = [...context.components];2033 root.directives = [...context.directives];2034 root.imports = context.imports;2035 root.hoists = context.hoists;2036 root.temps = context.temps;2037 root.cached = context.cached;2038 {2039 root.filters = [...context.filters];2040 }2041}2042function createRootCodegen(root, context) {2043 const { helper } = context;2044 const { children } = root;2045 if (children.length === 1) {2046 const child = children[0];2047 // if the single child is an element, turn it into a block.2048 if (isSingleElementRoot(root, child) && child.codegenNode) {2049 // single element root is never hoisted so codegenNode will never be2050 // SimpleExpressionNode2051 const codegenNode = child.codegenNode;2052 if (codegenNode.type === 13 /* VNODE_CALL */) {2053 makeBlock(codegenNode, context);2054 }2055 root.codegenNode = codegenNode;2056 }2057 else {2058 // - single <slot/>, IfNode, ForNode: already blocks.2059 // - single text node: always patched.2060 // root codegen falls through via genNode()2061 root.codegenNode = child;2062 }2063 }2064 else if (children.length > 1) {2065 // root has multiple nodes - return a fragment block.2066 let patchFlag = 64 /* STABLE_FRAGMENT */;2067 let patchFlagText = PatchFlagNames[64 /* STABLE_FRAGMENT */];2068 // check if the fragment actually contains a single valid child with2069 // the rest being comments2070 if ((process.env.NODE_ENV !== 'production') &&2071 children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {2072 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;2073 patchFlagText += `, ${PatchFlagNames[2048 /* DEV_ROOT_FRAGMENT */]}`;2074 }2075 root.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, root.children, patchFlag + ((process.env.NODE_ENV !== 'production') ? ` /* ${patchFlagText} */` : ``), undefined, undefined, true, undefined, false /* isComponent */);2076 }2077 else ;2078}2079function traverseChildren(parent, context) {2080 let i = 0;2081 const nodeRemoved = () => {2082 i--;2083 };2084 for (; i < parent.children.length; i++) {2085 const child = parent.children[i];2086 if (isString(child))2087 continue;2088 context.parent = parent;2089 context.childIndex = i;2090 context.onNodeRemoved = nodeRemoved;2091 traverseNode(child, context);2092 }2093}2094function traverseNode(node, context) {2095 context.currentNode = node;2096 // apply transform plugins2097 const { nodeTransforms } = context;2098 const exitFns = [];2099 for (let i = 0; i < nodeTransforms.length; i++) {2100 const onExit = nodeTransforms[i](node, context);2101 if (onExit) {2102 if (isArray(onExit)) {2103 exitFns.push(...onExit);2104 }2105 else {2106 exitFns.push(onExit);2107 }2108 }2109 if (!context.currentNode) {2110 // node was removed2111 return;2112 }2113 else {2114 // node may have been replaced2115 node = context.currentNode;2116 }2117 }2118 switch (node.type) {2119 case 3 /* COMMENT */:2120 if (!context.ssr) {2121 // inject import for the Comment symbol, which is needed for creating2122 // comment nodes with `createVNode`2123 context.helper(CREATE_COMMENT);2124 }2125 break;2126 case 5 /* INTERPOLATION */:2127 // no need to traverse, but we need to inject toString helper2128 if (!context.ssr) {2129 context.helper(TO_DISPLAY_STRING);2130 }2131 break;2132 // for container types, further traverse downwards2133 case 9 /* IF */:2134 for (let i = 0; i < node.branches.length; i++) {2135 traverseNode(node.branches[i], context);2136 }2137 break;2138 case 10 /* IF_BRANCH */:2139 case 11 /* FOR */:2140 case 1 /* ELEMENT */:2141 case 0 /* ROOT */:2142 traverseChildren(node, context);2143 break;2144 }2145 // exit transforms2146 context.currentNode = node;2147 let i = exitFns.length;2148 while (i--) {2149 exitFns[i]();2150 }2151}2152function createStructuralDirectiveTransform(name, fn) {2153 const matches = isString(name)2154 ? (n) => n === name2155 : (n) => name.test(n);2156 return (node, context) => {2157 if (node.type === 1 /* ELEMENT */) {2158 const { props } = node;2159 // structural directive transforms are not concerned with slots2160 // as they are handled separately in vSlot.ts2161 if (node.tagType === 3 /* TEMPLATE */ && props.some(isVSlot)) {2162 return;2163 }2164 const exitFns = [];2165 for (let i = 0; i < props.length; i++) {2166 const prop = props[i];2167 if (prop.type === 7 /* DIRECTIVE */ && matches(prop.name)) {2168 // structural directives are removed to avoid infinite recursion2169 // also we remove them *before* applying so that it can further2170 // traverse itself in case it moves the node around2171 props.splice(i, 1);2172 i--;2173 const onExit = fn(node, prop, context);2174 if (onExit)2175 exitFns.push(onExit);2176 }2177 }2178 return exitFns;2179 }2180 };2181}2182const PURE_ANNOTATION = `/*#__PURE__*/`;2183function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap = false, filename = `template.vue.html`, scopeId = null, optimizeImports = false, runtimeGlobalName = `Vue`, runtimeModuleName = `vue`, ssrRuntimeModuleName = 'vue/server-renderer', ssr = false, isTS = false, inSSR = false }) {2184 const context = {2185 mode,2186 prefixIdentifiers,2187 sourceMap,2188 filename,2189 scopeId,2190 optimizeImports,2191 runtimeGlobalName,2192 runtimeModuleName,2193 ssrRuntimeModuleName,2194 ssr,2195 isTS,2196 inSSR,2197 source: ast.loc.source,2198 code: ``,2199 column: 1,2200 line: 1,2201 offset: 0,2202 indentLevel: 0,2203 pure: false,2204 map: undefined,2205 helper(key) {2206 return `_${helperNameMap[key]}`;2207 },2208 push(code, node) {2209 context.code += code;2210 },2211 indent() {2212 newline(++context.indentLevel);2213 },2214 deindent(withoutNewLine = false) {2215 if (withoutNewLine) {2216 --context.indentLevel;2217 }2218 else {2219 newline(--context.indentLevel);2220 }2221 },2222 newline() {2223 newline(context.indentLevel);2224 }2225 };2226 function newline(n) {2227 context.push('\n' + ` `.repeat(n));2228 }2229 return context;2230}2231function generate(ast, options = {}) {2232 const context = createCodegenContext(ast, options);2233 if (options.onContextCreated)2234 options.onContextCreated(context);2235 const { mode, push, prefixIdentifiers, indent, deindent, newline, scopeId, ssr } = context;2236 const hasHelpers = ast.helpers.length > 0;2237 const useWithBlock = !prefixIdentifiers && mode !== 'module';2238 // preambles2239 // in setup() inline mode, the preamble is generated in a sub context2240 // and returned separately.2241 const preambleContext = context;2242 {2243 genFunctionPreamble(ast, preambleContext);2244 }2245 // enter render function2246 const functionName = ssr ? `ssrRender` : `render`;2247 const args = ssr ? ['_ctx', '_push', '_parent', '_attrs'] : ['_ctx', '_cache'];2248 const signature = args.join(', ');2249 {2250 push(`function ${functionName}(${signature}) {`);2251 }2252 indent();2253 if (useWithBlock) {2254 push(`with (_ctx) {`);2255 indent();2256 // function mode const declarations should be inside with block2257 // also they should be renamed to avoid collision with user properties2258 if (hasHelpers) {2259 push(`const { ${ast.helpers2260 .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)2261 .join(', ')} } = _Vue`);2262 push(`\n`);2263 newline();2264 }2265 }2266 // generate asset resolution statements2267 if (ast.components.length) {2268 genAssets(ast.components, 'component', context);2269 if (ast.directives.length || ast.temps > 0) {2270 newline();2271 }2272 }2273 if (ast.directives.length) {2274 genAssets(ast.directives, 'directive', context);2275 if (ast.temps > 0) {2276 newline();2277 }2278 }2279 if (ast.filters && ast.filters.length) {2280 newline();2281 genAssets(ast.filters, 'filter', context);2282 newline();2283 }2284 if (ast.temps > 0) {2285 push(`let `);2286 for (let i = 0; i < ast.temps; i++) {2287 push(`${i > 0 ? `, ` : ``}_temp${i}`);2288 }2289 }2290 if (ast.components.length || ast.directives.length || ast.temps) {2291 push(`\n`);2292 newline();2293 }2294 // generate the VNode tree expression2295 if (!ssr) {2296 push(`return `);2297 }2298 if (ast.codegenNode) {2299 genNode(ast.codegenNode, context);2300 }2301 else {2302 push(`null`);2303 }2304 if (useWithBlock) {2305 deindent();2306 push(`}`);2307 }2308 deindent();2309 push(`}`);2310 return {2311 ast,2312 code: context.code,2313 preamble: ``,2314 // SourceMapGenerator does have toJSON() method but it's not in the types2315 map: context.map ? context.map.toJSON() : undefined2316 };2317}2318function genFunctionPreamble(ast, context) {2319 const { ssr, prefixIdentifiers, push, newline, runtimeModuleName, runtimeGlobalName, ssrRuntimeModuleName } = context;2320 const VueBinding = runtimeGlobalName;2321 const aliasHelper = (s) => `${helperNameMap[s]}: _${helperNameMap[s]}`;2322 // Generate const declaration for helpers2323 // In prefix mode, we place the const declaration at top so it's done2324 // only once; But if we not prefixing, we place the declaration inside the2325 // with block so it doesn't incur the `in` check cost for every helper access.2326 if (ast.helpers.length > 0) {2327 {2328 // "with" mode.2329 // save Vue in a separate variable to avoid collision2330 push(`const _Vue = ${VueBinding}\n`);2331 // in "with" mode, helpers are declared inside the with block to avoid2332 // has check cost, but hoists are lifted out of the function - we need2333 // to provide the helper here.2334 if (ast.hoists.length) {2335 const staticHelpers = [2336 CREATE_VNODE,2337 CREATE_ELEMENT_VNODE,2338 CREATE_COMMENT,2339 CREATE_TEXT,2340 CREATE_STATIC2341 ]2342 .filter(helper => ast.helpers.includes(helper))2343 .map(aliasHelper)2344 .join(', ');2345 push(`const { ${staticHelpers} } = _Vue\n`);2346 }2347 }2348 }2349 genHoists(ast.hoists, context);2350 newline();2351 push(`return `);2352}2353function genAssets(assets, type, { helper, push, newline, isTS }) {2354 const resolver = helper(type === 'filter'2355 ? RESOLVE_FILTER2356 : type === 'component'2357 ? RESOLVE_COMPONENT2358 : RESOLVE_DIRECTIVE);2359 for (let i = 0; i < assets.length; i++) {2360 let id = assets[i];2361 // potential component implicit self-reference inferred from SFC filename2362 const maybeSelfReference = id.endsWith('__self');2363 if (maybeSelfReference) {2364 id = id.slice(0, -6);2365 }2366 push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})${isTS ? `!` : ``}`);2367 if (i < assets.length - 1) {2368 newline();2369 }2370 }2371}2372function genHoists(hoists, context) {2373 if (!hoists.length) {2374 return;2375 }2376 context.pure = true;2377 const { push, newline, helper, scopeId, mode } = context;2378 newline();2379 for (let i = 0; i < hoists.length; i++) {2380 const exp = hoists[i];2381 if (exp) {2382 push(`const _hoisted_${i + 1} = ${``}`);2383 genNode(exp, context);2384 newline();2385 }2386 }2387 context.pure = false;2388}2389function isText$1(n) {2390 return (isString(n) ||2391 n.type === 4 /* SIMPLE_EXPRESSION */ ||2392 n.type === 2 /* TEXT */ ||2393 n.type === 5 /* INTERPOLATION */ ||2394 n.type === 8 /* COMPOUND_EXPRESSION */);2395}2396function genNodeListAsArray(nodes, context) {2397 const multilines = nodes.length > 3 ||2398 (((process.env.NODE_ENV !== 'production')) && nodes.some(n => isArray(n) || !isText$1(n)));2399 context.push(`[`);2400 multilines && context.indent();2401 genNodeList(nodes, context, multilines);2402 multilines && context.deindent();2403 context.push(`]`);2404}2405function genNodeList(nodes, context, multilines = false, comma = true) {2406 const { push, newline } = context;2407 for (let i = 0; i < nodes.length; i++) {2408 const node = nodes[i];2409 if (isString(node)) {2410 push(node);2411 }2412 else if (isArray(node)) {2413 genNodeListAsArray(node, context);2414 }2415 else {2416 genNode(node, context);2417 }2418 if (i < nodes.length - 1) {2419 if (multilines) {2420 comma && push(',');2421 newline();2422 }2423 else {2424 comma && push(', ');2425 }2426 }2427 }2428}2429function genNode(node, context) {2430 if (isString(node)) {2431 context.push(node);2432 return;2433 }2434 if (isSymbol(node)) {2435 context.push(context.helper(node));2436 return;2437 }2438 switch (node.type) {2439 case 1 /* ELEMENT */:2440 case 9 /* IF */:2441 case 11 /* FOR */:2442 (process.env.NODE_ENV !== 'production') &&2443 assert(node.codegenNode != null, `Codegen node is missing for element/if/for node. ` +2444 `Apply appropriate transforms first.`);2445 genNode(node.codegenNode, context);2446 break;2447 case 2 /* TEXT */:2448 genText(node, context);2449 break;2450 case 4 /* SIMPLE_EXPRESSION */:2451 genExpression(node, context);2452 break;2453 case 5 /* INTERPOLATION */:2454 genInterpolation(node, context);2455 break;2456 case 12 /* TEXT_CALL */:2457 genNode(node.codegenNode, context);2458 break;2459 case 8 /* COMPOUND_EXPRESSION */:2460 genCompoundExpression(node, context);2461 break;2462 case 3 /* COMMENT */:2463 genComment(node, context);2464 break;2465 case 13 /* VNODE_CALL */:2466 genVNodeCall(node, context);2467 break;2468 case 14 /* JS_CALL_EXPRESSION */:2469 genCallExpression(node, context);2470 break;2471 case 15 /* JS_OBJECT_EXPRESSION */:2472 genObjectExpression(node, context);2473 break;2474 case 17 /* JS_ARRAY_EXPRESSION */:2475 genArrayExpression(node, context);2476 break;2477 case 18 /* JS_FUNCTION_EXPRESSION */:2478 genFunctionExpression(node, context);2479 break;2480 case 19 /* JS_CONDITIONAL_EXPRESSION */:2481 genConditionalExpression(node, context);2482 break;2483 case 20 /* JS_CACHE_EXPRESSION */:2484 genCacheExpression(node, context);2485 break;2486 case 21 /* JS_BLOCK_STATEMENT */:2487 genNodeList(node.body, context, true, false);2488 break;2489 // SSR only types2490 case 22 /* JS_TEMPLATE_LITERAL */:2491 break;2492 case 23 /* JS_IF_STATEMENT */:2493 break;2494 case 24 /* JS_ASSIGNMENT_EXPRESSION */:2495 break;2496 case 25 /* JS_SEQUENCE_EXPRESSION */:2497 break;2498 case 26 /* JS_RETURN_STATEMENT */:2499 break;2500 /* istanbul ignore next */2501 case 10 /* IF_BRANCH */:2502 // noop2503 break;2504 default:2505 if ((process.env.NODE_ENV !== 'production')) {2506 assert(false, `unhandled codegen node type: ${node.type}`);2507 // make sure we exhaust all possible types2508 const exhaustiveCheck = node;2509 return exhaustiveCheck;2510 }2511 }2512}2513function genText(node, context) {2514 context.push(JSON.stringify(node.content), node);2515}2516function genExpression(node, context) {2517 const { content, isStatic } = node;2518 context.push(isStatic ? JSON.stringify(content) : content, node);2519}2520function genInterpolation(node, context) {2521 const { push, helper, pure } = context;2522 if (pure)2523 push(PURE_ANNOTATION);2524 push(`${helper(TO_DISPLAY_STRING)}(`);2525 genNode(node.content, context);2526 push(`)`);2527}2528function genCompoundExpression(node, context) {2529 for (let i = 0; i < node.children.length; i++) {2530 const child = node.children[i];2531 if (isString(child)) {2532 context.push(child);2533 }2534 else {2535 genNode(child, context);2536 }2537 }2538}2539function genExpressionAsPropertyKey(node, context) {2540 const { push } = context;2541 if (node.type === 8 /* COMPOUND_EXPRESSION */) {2542 push(`[`);2543 genCompoundExpression(node, context);2544 push(`]`);2545 }2546 else if (node.isStatic) {2547 // only quote keys if necessary2548 const text = isSimpleIdentifier(node.content)2549 ? node.content2550 : JSON.stringify(node.content);2551 push(text, node);2552 }2553 else {2554 push(`[${node.content}]`, node);2555 }2556}2557function genComment(node, context) {2558 const { push, helper, pure } = context;2559 if (pure) {2560 push(PURE_ANNOTATION);2561 }2562 push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node);2563}2564function genVNodeCall(node, context) {2565 const { push, helper, pure } = context;2566 const { tag, props, children, patchFlag, dynamicProps, directives, isBlock, disableTracking, isComponent } = node;2567 if (directives) {2568 push(helper(WITH_DIRECTIVES) + `(`);2569 }2570 if (isBlock) {2571 push(`(${helper(OPEN_BLOCK)}(${disableTracking ? `true` : ``}), `);2572 }2573 if (pure) {2574 push(PURE_ANNOTATION);2575 }2576 const callHelper = isBlock2577 ? getVNodeBlockHelper(context.inSSR, isComponent)2578 : getVNodeHelper(context.inSSR, isComponent);2579 push(helper(callHelper) + `(`, node);2580 genNodeList(genNullableArgs([tag, props, children, patchFlag, dynamicProps]), context);2581 push(`)`);2582 if (isBlock) {2583 push(`)`);2584 }2585 if (directives) {2586 push(`, `);2587 genNode(directives, context);2588 push(`)`);2589 }2590}2591function genNullableArgs(args) {2592 let i = args.length;2593 while (i--) {2594 if (args[i] != null)2595 break;2596 }2597 return args.slice(0, i + 1).map(arg => arg || `null`);2598}2599// JavaScript2600function genCallExpression(node, context) {2601 const { push, helper, pure } = context;2602 const callee = isString(node.callee) ? node.callee : helper(node.callee);2603 if (pure) {2604 push(PURE_ANNOTATION);2605 }2606 push(callee + `(`, node);2607 genNodeList(node.arguments, context);2608 push(`)`);2609}2610function genObjectExpression(node, context) {2611 const { push, indent, deindent, newline } = context;2612 const { properties } = node;2613 if (!properties.length) {2614 push(`{}`, node);2615 return;2616 }2617 const multilines = properties.length > 1 ||2618 (((process.env.NODE_ENV !== 'production')) &&2619 properties.some(p => p.value.type !== 4 /* SIMPLE_EXPRESSION */));2620 push(multilines ? `{` : `{ `);2621 multilines && indent();2622 for (let i = 0; i < properties.length; i++) {2623 const { key, value } = properties[i];2624 // key2625 genExpressionAsPropertyKey(key, context);2626 push(`: `);2627 // value2628 genNode(value, context);2629 if (i < properties.length - 1) {2630 // will only reach this if it's multilines2631 push(`,`);2632 newline();2633 }2634 }2635 multilines && deindent();2636 push(multilines ? `}` : ` }`);2637}2638function genArrayExpression(node, context) {2639 genNodeListAsArray(node.elements, context);2640}2641function genFunctionExpression(node, context) {2642 const { push, indent, deindent } = context;2643 const { params, returns, body, newline, isSlot } = node;2644 if (isSlot) {2645 // wrap slot functions with owner context2646 push(`_${helperNameMap[WITH_CTX]}(`);2647 }2648 push(`(`, node);2649 if (isArray(params)) {2650 genNodeList(params, context);2651 }2652 else if (params) {2653 genNode(params, context);2654 }2655 push(`) => `);2656 if (newline || body) {2657 push(`{`);2658 indent();2659 }2660 if (returns) {2661 if (newline) {2662 push(`return `);2663 }2664 if (isArray(returns)) {2665 genNodeListAsArray(returns, context);2666 }2667 else {2668 genNode(returns, context);2669 }2670 }2671 else if (body) {2672 genNode(body, context);2673 }2674 if (newline || body) {2675 deindent();2676 push(`}`);2677 }2678 if (isSlot) {2679 if (node.isNonScopedSlot) {2680 push(`, undefined, true`);2681 }2682 push(`)`);2683 }2684}2685function genConditionalExpression(node, context) {2686 const { test, consequent, alternate, newline: needNewline } = node;2687 const { push, indent, deindent, newline } = context;2688 if (test.type === 4 /* SIMPLE_EXPRESSION */) {2689 const needsParens = !isSimpleIdentifier(test.content);2690 needsParens && push(`(`);2691 genExpression(test, context);2692 needsParens && push(`)`);2693 }2694 else {2695 push(`(`);2696 genNode(test, context);2697 push(`)`);2698 }2699 needNewline && indent();2700 context.indentLevel++;2701 needNewline || push(` `);2702 push(`? `);2703 genNode(consequent, context);2704 context.indentLevel--;2705 needNewline && newline();2706 needNewline || push(` `);2707 push(`: `);2708 const isNested = alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */;2709 if (!isNested) {2710 context.indentLevel++;2711 }2712 genNode(alternate, context);2713 if (!isNested) {2714 context.indentLevel--;2715 }2716 needNewline && deindent(true /* without newline */);2717}2718function genCacheExpression(node, context) {2719 const { push, helper, indent, deindent, newline } = context;2720 push(`_cache[${node.index}] || (`);2721 if (node.isVNode) {2722 indent();2723 push(`${helper(SET_BLOCK_TRACKING)}(-1),`);2724 newline();2725 }2726 push(`_cache[${node.index}] = `);2727 genNode(node.value, context);2728 if (node.isVNode) {2729 push(`,`);2730 newline();2731 push(`${helper(SET_BLOCK_TRACKING)}(1),`);2732 newline();2733 push(`_cache[${node.index}]`);2734 deindent();2735 }2736 push(`)`);2737}2738function walkIdentifiers(root, onIdentifier, includeAll = false, parentStack = [], knownIds = Object.create(null)) {2739 {2740 return;2741 }2742}2743function isReferencedIdentifier(id, parent, parentStack) {2744 {2745 return false;2746 }2747}2748function isInDestructureAssignment(parent, parentStack) {2749 if (parent &&2750 (parent.type === 'ObjectProperty' || parent.type === 'ArrayPattern')) {2751 let i = parentStack.length;2752 while (i--) {2753 const p = parentStack[i];2754 if (p.type === 'AssignmentExpression') {2755 return true;2756 }2757 else if (p.type !== 'ObjectProperty' && !p.type.endsWith('Pattern')) {2758 break;2759 }2760 }2761 }2762 return false;2763}2764function walkFunctionParams(node, onIdent) {2765 for (const p of node.params) {2766 for (const id of extractIdentifiers(p)) {2767 onIdent(id);2768 }2769 }2770}2771function walkBlockDeclarations(block, onIdent) {2772 for (const stmt of block.body) {2773 if (stmt.type === 'VariableDeclaration') {2774 if (stmt.declare)2775 continue;2776 for (const decl of stmt.declarations) {2777 for (const id of extractIdentifiers(decl.id)) {2778 onIdent(id);2779 }2780 }2781 }2782 else if (stmt.type === 'FunctionDeclaration' ||2783 stmt.type === 'ClassDeclaration') {2784 if (stmt.declare || !stmt.id)2785 continue;2786 onIdent(stmt.id);2787 }2788 }2789}2790function extractIdentifiers(param, nodes = []) {2791 switch (param.type) {2792 case 'Identifier':2793 nodes.push(param);2794 break;2795 case 'MemberExpression':2796 let object = param;2797 while (object.type === 'MemberExpression') {2798 object = object.object;2799 }2800 nodes.push(object);2801 break;2802 case 'ObjectPattern':2803 for (const prop of param.properties) {2804 if (prop.type === 'RestElement') {2805 extractIdentifiers(prop.argument, nodes);2806 }2807 else {2808 extractIdentifiers(prop.value, nodes);2809 }2810 }2811 break;2812 case 'ArrayPattern':2813 param.elements.forEach(element => {2814 if (element)2815 extractIdentifiers(element, nodes);2816 });2817 break;2818 case 'RestElement':2819 extractIdentifiers(param.argument, nodes);2820 break;2821 case 'AssignmentPattern':2822 extractIdentifiers(param.left, nodes);2823 break;2824 }2825 return nodes;2826}2827const isFunctionType = (node) => {2828 return /Function(?:Expression|Declaration)$|Method$/.test(node.type);2829};2830const isStaticProperty = (node) => node &&2831 (node.type === 'ObjectProperty' || node.type === 'ObjectMethod') &&2832 !node.computed;2833const isStaticPropertyKey = (node, parent) => isStaticProperty(parent) && parent.key === node;2834// these keywords should not appear inside expressions, but operators like2835// typeof, instanceof and in are allowed2836const prohibitedKeywordRE = new RegExp('\\b' +2837 ('do,if,for,let,new,try,var,case,else,with,await,break,catch,class,const,' +2838 'super,throw,while,yield,delete,export,import,return,switch,default,' +2839 'extends,finally,continue,debugger,function,arguments,typeof,void')2840 .split(',')2841 .join('\\b|\\b') +2842 '\\b');2843// strip strings in expressions2844const stripStringRE = /'(?:[^'\\]|\\.)*'|"(?:[^"\\]|\\.)*"|`(?:[^`\\]|\\.)*\$\{|\}(?:[^`\\]|\\.)*`|`(?:[^`\\]|\\.)*`/g;2845/**2846 * Validate a non-prefixed expression.2847 * This is only called when using the in-browser runtime compiler since it2848 * doesn't prefix expressions.2849 */2850function validateBrowserExpression(node, context, asParams = false, asRawStatements = false) {2851 const exp = node.content;2852 // empty expressions are validated per-directive since some directives2853 // do allow empty expressions.2854 if (!exp.trim()) {2855 return;2856 }2857 try {2858 new Function(asRawStatements2859 ? ` ${exp} `2860 : `return ${asParams ? `(${exp}) => {}` : `(${exp})`}`);2861 }2862 catch (e) {2863 let message = e.message;2864 const keywordMatch = exp2865 .replace(stripStringRE, '')2866 .match(prohibitedKeywordRE);2867 if (keywordMatch) {2868 message = `avoid using JavaScript keyword as property name: "${keywordMatch[0]}"`;2869 }2870 context.onError(createCompilerError(44 /* X_INVALID_EXPRESSION */, node.loc, undefined, message));2871 }2872}2873const transformExpression = (node, context) => {2874 if (node.type === 5 /* INTERPOLATION */) {2875 node.content = processExpression(node.content, context);2876 }2877 else if (node.type === 1 /* ELEMENT */) {2878 // handle directives on element2879 for (let i = 0; i < node.props.length; i++) {2880 const dir = node.props[i];2881 // do not process for v-on & v-for since they are special handled2882 if (dir.type === 7 /* DIRECTIVE */ && dir.name !== 'for') {2883 const exp = dir.exp;2884 const arg = dir.arg;2885 // do not process exp if this is v-on:arg - we need special handling2886 // for wrapping inline statements.2887 if (exp &&2888 exp.type === 4 /* SIMPLE_EXPRESSION */ &&2889 !(dir.name === 'on' && arg)) {2890 dir.exp = processExpression(exp, context, 2891 // slot args must be processed as function params2892 dir.name === 'slot');2893 }2894 if (arg && arg.type === 4 /* SIMPLE_EXPRESSION */ && !arg.isStatic) {2895 dir.arg = processExpression(arg, context);2896 }2897 }2898 }2899 }2900};2901// Important: since this function uses Node.js only dependencies, it should2902// always be used with a leading !true check so that it can be2903// tree-shaken from the browser build.2904function processExpression(node, context, 2905// some expressions like v-slot props & v-for aliases should be parsed as2906// function params2907asParams = false, 2908// v-on handler values may contain multiple statements2909asRawStatements = false, localVars = Object.create(context.identifiers)) {2910 {2911 if ((process.env.NODE_ENV !== 'production')) {2912 // simple in-browser validation (same logic in 2.x)2913 validateBrowserExpression(node, context, asParams, asRawStatements);2914 }2915 return node;2916 }2917}2918const transformIf = createStructuralDirectiveTransform(/^(if|else|else-if)$/, (node, dir, context) => {2919 return processIf(node, dir, context, (ifNode, branch, isRoot) => {2920 // #1587: We need to dynamically increment the key based on the current2921 // node's sibling nodes, since chained v-if/else branches are2922 // rendered at the same depth2923 const siblings = context.parent.children;2924 let i = siblings.indexOf(ifNode);2925 let key = 0;2926 while (i-- >= 0) {2927 const sibling = siblings[i];2928 if (sibling && sibling.type === 9 /* IF */) {2929 key += sibling.branches.length;2930 }2931 }2932 // Exit callback. Complete the codegenNode when all children have been2933 // transformed.2934 return () => {2935 if (isRoot) {2936 ifNode.codegenNode = createCodegenNodeForBranch(branch, key, context);2937 }2938 else {2939 // attach this branch's codegen node to the v-if root.2940 const parentCondition = getParentCondition(ifNode.codegenNode);2941 parentCondition.alternate = createCodegenNodeForBranch(branch, key + ifNode.branches.length - 1, context);2942 }2943 };2944 });2945});2946// target-agnostic transform used for both Client and SSR2947function processIf(node, dir, context, processCodegen) {2948 if (dir.name !== 'else' &&2949 (!dir.exp || !dir.exp.content.trim())) {2950 const loc = dir.exp ? dir.exp.loc : node.loc;2951 context.onError(createCompilerError(28 /* X_V_IF_NO_EXPRESSION */, dir.loc));2952 dir.exp = createSimpleExpression(`true`, false, loc);2953 }2954 if ((process.env.NODE_ENV !== 'production') && true && dir.exp) {2955 validateBrowserExpression(dir.exp, context);2956 }2957 if (dir.name === 'if') {2958 const branch = createIfBranch(node, dir);2959 const ifNode = {2960 type: 9 /* IF */,2961 loc: node.loc,2962 branches: [branch]2963 };2964 context.replaceNode(ifNode);2965 if (processCodegen) {2966 return processCodegen(ifNode, branch, true);2967 }2968 }2969 else {2970 // locate the adjacent v-if2971 const siblings = context.parent.children;2972 const comments = [];2973 let i = siblings.indexOf(node);2974 while (i-- >= -1) {2975 const sibling = siblings[i];2976 if ((process.env.NODE_ENV !== 'production') && sibling && sibling.type === 3 /* COMMENT */) {2977 context.removeNode(sibling);2978 comments.unshift(sibling);2979 continue;2980 }2981 if (sibling &&2982 sibling.type === 2 /* TEXT */ &&2983 !sibling.content.trim().length) {2984 context.removeNode(sibling);2985 continue;2986 }2987 if (sibling && sibling.type === 9 /* IF */) {2988 // Check if v-else was followed by v-else-if2989 if (dir.name === 'else-if' &&2990 sibling.branches[sibling.branches.length - 1].condition === undefined) {2991 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));2992 }2993 // move the node to the if node's branches2994 context.removeNode();2995 const branch = createIfBranch(node, dir);2996 if ((process.env.NODE_ENV !== 'production') &&2997 comments.length &&2998 // #3619 ignore comments if the v-if is direct child of <transition>2999 !(context.parent &&3000 context.parent.type === 1 /* ELEMENT */ &&3001 isBuiltInType(context.parent.tag, 'transition'))) {3002 branch.children = [...comments, ...branch.children];3003 }3004 // check if user is forcing same key on different branches3005 if ((process.env.NODE_ENV !== 'production') || !true) {3006 const key = branch.userKey;3007 if (key) {3008 sibling.branches.forEach(({ userKey }) => {3009 if (isSameKey(userKey, key)) {3010 context.onError(createCompilerError(29 /* X_V_IF_SAME_KEY */, branch.userKey.loc));3011 }3012 });3013 }3014 }3015 sibling.branches.push(branch);3016 const onExit = processCodegen && processCodegen(sibling, branch, false);3017 // since the branch was removed, it will not be traversed.3018 // make sure to traverse here.3019 traverseNode(branch, context);3020 // call on exit3021 if (onExit)3022 onExit();3023 // make sure to reset currentNode after traversal to indicate this3024 // node has been removed.3025 context.currentNode = null;3026 }3027 else {3028 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));3029 }3030 break;3031 }3032 }3033}3034function createIfBranch(node, dir) {3035 return {3036 type: 10 /* IF_BRANCH */,3037 loc: node.loc,3038 condition: dir.name === 'else' ? undefined : dir.exp,3039 children: node.tagType === 3 /* TEMPLATE */ && !findDir(node, 'for')3040 ? node.children3041 : [node],3042 userKey: findProp(node, `key`)3043 };3044}3045function createCodegenNodeForBranch(branch, keyIndex, context) {3046 if (branch.condition) {3047 return createConditionalExpression(branch.condition, createChildrenCodegenNode(branch, keyIndex, context), 3048 // make sure to pass in asBlock: true so that the comment node call3049 // closes the current block.3050 createCallExpression(context.helper(CREATE_COMMENT), [3051 (process.env.NODE_ENV !== 'production') ? '"v-if"' : '""',3052 'true'3053 ]));3054 }3055 else {3056 return createChildrenCodegenNode(branch, keyIndex, context);3057 }3058}3059function createChildrenCodegenNode(branch, keyIndex, context) {3060 const { helper } = context;3061 const keyProperty = createObjectProperty(`key`, createSimpleExpression(`${keyIndex}`, false, locStub, 2 /* CAN_HOIST */));3062 const { children } = branch;3063 const firstChild = children[0];3064 const needFragmentWrapper = children.length !== 1 || firstChild.type !== 1 /* ELEMENT */;3065 if (needFragmentWrapper) {3066 if (children.length === 1 && firstChild.type === 11 /* FOR */) {3067 // optimize away nested fragments when child is a ForNode3068 const vnodeCall = firstChild.codegenNode;3069 injectProp(vnodeCall, keyProperty, context);3070 return vnodeCall;3071 }3072 else {3073 let patchFlag = 64 /* STABLE_FRAGMENT */;3074 let patchFlagText = PatchFlagNames[64 /* STABLE_FRAGMENT */];3075 // check if the fragment actually contains a single valid child with3076 // the rest being comments3077 if ((process.env.NODE_ENV !== 'production') &&3078 children.filter(c => c.type !== 3 /* COMMENT */).length === 1) {3079 patchFlag |= 2048 /* DEV_ROOT_FRAGMENT */;3080 patchFlagText += `, ${PatchFlagNames[2048 /* DEV_ROOT_FRAGMENT */]}`;3081 }3082 return createVNodeCall(context, helper(FRAGMENT), createObjectExpression([keyProperty]), children, patchFlag + ((process.env.NODE_ENV !== 'production') ? ` /* ${patchFlagText} */` : ``), undefined, undefined, true, false, false /* isComponent */, branch.loc);3083 }3084 }3085 else {3086 const ret = firstChild.codegenNode;3087 const vnodeCall = getMemoedVNodeCall(ret);3088 // Change createVNode to createBlock.3089 if (vnodeCall.type === 13 /* VNODE_CALL */) {3090 makeBlock(vnodeCall, context);3091 }3092 // inject branch key3093 injectProp(vnodeCall, keyProperty, context);3094 return ret;3095 }3096}3097function isSameKey(a, b) {3098 if (!a || a.type !== b.type) {3099 return false;3100 }3101 if (a.type === 6 /* ATTRIBUTE */) {3102 if (a.value.content !== b.value.content) {3103 return false;3104 }3105 }3106 else {3107 // directive3108 const exp = a.exp;3109 const branchExp = b.exp;3110 if (exp.type !== branchExp.type) {3111 return false;3112 }3113 if (exp.type !== 4 /* SIMPLE_EXPRESSION */ ||3114 exp.isStatic !== branchExp.isStatic ||3115 exp.content !== branchExp.content) {3116 return false;3117 }3118 }3119 return true;3120}3121function getParentCondition(node) {3122 while (true) {3123 if (node.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3124 if (node.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3125 node = node.alternate;3126 }3127 else {3128 return node;3129 }3130 }3131 else if (node.type === 20 /* JS_CACHE_EXPRESSION */) {3132 node = node.value;3133 }3134 }3135}3136const transformFor = createStructuralDirectiveTransform('for', (node, dir, context) => {3137 const { helper, removeHelper } = context;3138 return processFor(node, dir, context, forNode => {3139 // create the loop render function expression now, and add the3140 // iterator on exit after all children have been traversed3141 const renderExp = createCallExpression(helper(RENDER_LIST), [3142 forNode.source3143 ]);3144 const memo = findDir(node, 'memo');3145 const keyProp = findProp(node, `key`);3146 const keyExp = keyProp &&3147 (keyProp.type === 6 /* ATTRIBUTE */3148 ? createSimpleExpression(keyProp.value.content, true)3149 : keyProp.exp);3150 const keyProperty = keyProp ? createObjectProperty(`key`, keyExp) : null;3151 const isStableFragment = forNode.source.type === 4 /* SIMPLE_EXPRESSION */ &&3152 forNode.source.constType > 0 /* NOT_CONSTANT */;3153 const fragmentFlag = isStableFragment3154 ? 64 /* STABLE_FRAGMENT */3155 : keyProp3156 ? 128 /* KEYED_FRAGMENT */3157 : 256 /* UNKEYED_FRAGMENT */;3158 forNode.codegenNode = createVNodeCall(context, helper(FRAGMENT), undefined, renderExp, fragmentFlag +3159 ((process.env.NODE_ENV !== 'production') ? ` /* ${PatchFlagNames[fragmentFlag]} */` : ``), undefined, undefined, true /* isBlock */, !isStableFragment /* disableTracking */, false /* isComponent */, node.loc);3160 return () => {3161 // finish the codegen now that all children have been traversed3162 let childBlock;3163 const isTemplate = isTemplateNode(node);3164 const { children } = forNode;3165 // check <template v-for> key placement3166 if (((process.env.NODE_ENV !== 'production') || !true) && isTemplate) {3167 node.children.some(c => {3168 if (c.type === 1 /* ELEMENT */) {3169 const key = findProp(c, 'key');3170 if (key) {3171 context.onError(createCompilerError(33 /* X_V_FOR_TEMPLATE_KEY_PLACEMENT */, key.loc));3172 return true;3173 }3174 }3175 });3176 }3177 const needFragmentWrapper = children.length !== 1 || children[0].type !== 1 /* ELEMENT */;3178 const slotOutlet = isSlotOutlet(node)3179 ? node3180 : isTemplate &&3181 node.children.length === 1 &&3182 isSlotOutlet(node.children[0])3183 ? node.children[0] // api-extractor somehow fails to infer this3184 : null;3185 if (slotOutlet) {3186 // <slot v-for="..."> or <template v-for="..."><slot/></template>3187 childBlock = slotOutlet.codegenNode;3188 if (isTemplate && keyProperty) {3189 // <template v-for="..." :key="..."><slot/></template>3190 // we need to inject the key to the renderSlot() call.3191 // the props for renderSlot is passed as the 3rd argument.3192 injectProp(childBlock, keyProperty, context);3193 }3194 }3195 else if (needFragmentWrapper) {3196 // <template v-for="..."> with text or multi-elements3197 // should generate a fragment block for each loop3198 childBlock = createVNodeCall(context, helper(FRAGMENT), keyProperty ? createObjectExpression([keyProperty]) : undefined, node.children, 64 /* STABLE_FRAGMENT */ +3199 ((process.env.NODE_ENV !== 'production')3200 ? ` /* ${PatchFlagNames[64 /* STABLE_FRAGMENT */]} */`3201 : ``), undefined, undefined, true, undefined, false /* isComponent */);3202 }3203 else {3204 // Normal element v-for. Directly use the child's codegenNode3205 // but mark it as a block.3206 childBlock = children[0]3207 .codegenNode;3208 if (isTemplate && keyProperty) {3209 injectProp(childBlock, keyProperty, context);3210 }3211 if (childBlock.isBlock !== !isStableFragment) {3212 if (childBlock.isBlock) {3213 // switch from block to vnode3214 removeHelper(OPEN_BLOCK);3215 removeHelper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3216 }3217 else {3218 // switch from vnode to block3219 removeHelper(getVNodeHelper(context.inSSR, childBlock.isComponent));3220 }3221 }3222 childBlock.isBlock = !isStableFragment;3223 if (childBlock.isBlock) {3224 helper(OPEN_BLOCK);3225 helper(getVNodeBlockHelper(context.inSSR, childBlock.isComponent));3226 }3227 else {3228 helper(getVNodeHelper(context.inSSR, childBlock.isComponent));3229 }3230 }3231 if (memo) {3232 const loop = createFunctionExpression(createForLoopParams(forNode.parseResult, [3233 createSimpleExpression(`_cached`)3234 ]));3235 loop.body = createBlockStatement([3236 createCompoundExpression([`const _memo = (`, memo.exp, `)`]),3237 createCompoundExpression([3238 `if (_cached`,3239 ...(keyExp ? [` && _cached.key === `, keyExp] : []),3240 ` && ${context.helperString(IS_MEMO_SAME)}(_cached, _memo)) return _cached`3241 ]),3242 createCompoundExpression([`const _item = `, childBlock]),3243 createSimpleExpression(`_item.memo = _memo`),3244 createSimpleExpression(`return _item`)3245 ]);3246 renderExp.arguments.push(loop, createSimpleExpression(`_cache`), createSimpleExpression(String(context.cached++)));3247 }3248 else {3249 renderExp.arguments.push(createFunctionExpression(createForLoopParams(forNode.parseResult), childBlock, true /* force newline */));3250 }3251 };3252 });3253});3254// target-agnostic transform used for both Client and SSR3255function processFor(node, dir, context, processCodegen) {3256 if (!dir.exp) {3257 context.onError(createCompilerError(31 /* X_V_FOR_NO_EXPRESSION */, dir.loc));3258 return;3259 }3260 const parseResult = parseForExpression(3261 // can only be simple expression because vFor transform is applied3262 // before expression transform.3263 dir.exp, context);3264 if (!parseResult) {3265 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));3266 return;3267 }3268 const { addIdentifiers, removeIdentifiers, scopes } = context;3269 const { source, value, key, index } = parseResult;3270 const forNode = {3271 type: 11 /* FOR */,3272 loc: dir.loc,3273 source,3274 valueAlias: value,3275 keyAlias: key,3276 objectIndexAlias: index,3277 parseResult,3278 children: isTemplateNode(node) ? node.children : [node]3279 };3280 context.replaceNode(forNode);3281 // bookkeeping3282 scopes.vFor++;3283 const onExit = processCodegen && processCodegen(forNode);3284 return () => {3285 scopes.vFor--;3286 if (onExit)3287 onExit();3288 };3289}3290const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;3291// This regex doesn't cover the case if key or index aliases have destructuring,3292// but those do not make sense in the first place, so this works in practice.3293const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;3294const stripParensRE = /^\(|\)$/g;3295function parseForExpression(input, context) {3296 const loc = input.loc;3297 const exp = input.content;3298 const inMatch = exp.match(forAliasRE);3299 if (!inMatch)3300 return;3301 const [, LHS, RHS] = inMatch;3302 const result = {3303 source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),3304 value: undefined,3305 key: undefined,3306 index: undefined3307 };3308 if ((process.env.NODE_ENV !== 'production') && true) {3309 validateBrowserExpression(result.source, context);3310 }3311 let valueContent = LHS.trim().replace(stripParensRE, '').trim();3312 const trimmedOffset = LHS.indexOf(valueContent);3313 const iteratorMatch = valueContent.match(forIteratorRE);3314 if (iteratorMatch) {3315 valueContent = valueContent.replace(forIteratorRE, '').trim();3316 const keyContent = iteratorMatch[1].trim();3317 let keyOffset;3318 if (keyContent) {3319 keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);3320 result.key = createAliasExpression(loc, keyContent, keyOffset);3321 if ((process.env.NODE_ENV !== 'production') && true) {3322 validateBrowserExpression(result.key, context, true);3323 }3324 }3325 if (iteratorMatch[2]) {3326 const indexContent = iteratorMatch[2].trim();3327 if (indexContent) {3328 result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key3329 ? keyOffset + keyContent.length3330 : trimmedOffset + valueContent.length));3331 if ((process.env.NODE_ENV !== 'production') && true) {3332 validateBrowserExpression(result.index, context, true);3333 }3334 }3335 }3336 }3337 if (valueContent) {3338 result.value = createAliasExpression(loc, valueContent, trimmedOffset);3339 if ((process.env.NODE_ENV !== 'production') && true) {3340 validateBrowserExpression(result.value, context, true);3341 }3342 }3343 return result;3344}3345function createAliasExpression(range, content, offset) {3346 return createSimpleExpression(content, false, getInnerRange(range, offset, content.length));3347}3348function createForLoopParams({ value, key, index }, memoArgs = []) {3349 return createParamsList([value, key, index, ...memoArgs]);3350}3351function createParamsList(args) {3352 let i = args.length;3353 while (i--) {3354 if (args[i])3355 break;3356 }3357 return args3358 .slice(0, i + 1)3359 .map((arg, i) => arg || createSimpleExpression(`_`.repeat(i + 1), false));3360}3361const defaultFallback = createSimpleExpression(`undefined`, false);3362// A NodeTransform that:3363// 1. Tracks scope identifiers for scoped slots so that they don't get prefixed3364// by transformExpression. This is only applied in non-browser builds with3365// { prefixIdentifiers: true }.3366// 2. Track v-slot depths so that we know a slot is inside another slot.3367// Note the exit callback is executed before buildSlots() on the same node,3368// so only nested slots see positive numbers.3369const trackSlotScopes = (node, context) => {3370 if (node.type === 1 /* ELEMENT */ &&3371 (node.tagType === 1 /* COMPONENT */ ||3372 node.tagType === 3 /* TEMPLATE */)) {3373 // We are only checking non-empty v-slot here3374 // since we only care about slots that introduce scope variables.3375 const vSlot = findDir(node, 'slot');3376 if (vSlot) {3377 vSlot.exp;3378 context.scopes.vSlot++;3379 return () => {3380 context.scopes.vSlot--;3381 };3382 }3383 }3384};3385// A NodeTransform that tracks scope identifiers for scoped slots with v-for.3386// This transform is only applied in non-browser builds with { prefixIdentifiers: true }3387const trackVForSlotScopes = (node, context) => {3388 let vFor;3389 if (isTemplateNode(node) &&3390 node.props.some(isVSlot) &&3391 (vFor = findDir(node, 'for'))) {3392 const result = (vFor.parseResult = parseForExpression(vFor.exp, context));3393 if (result) {3394 const { value, key, index } = result;3395 const { addIdentifiers, removeIdentifiers } = context;3396 value && addIdentifiers(value);3397 key && addIdentifiers(key);3398 index && addIdentifiers(index);3399 return () => {3400 value && removeIdentifiers(value);3401 key && removeIdentifiers(key);3402 index && removeIdentifiers(index);3403 };3404 }3405 }3406};3407const buildClientSlotFn = (props, children, loc) => createFunctionExpression(props, children, false /* newline */, true /* isSlot */, children.length ? children[0].loc : loc);3408// Instead of being a DirectiveTransform, v-slot processing is called during3409// transformElement to build the slots object for a component.3410function buildSlots(node, context, buildSlotFn = buildClientSlotFn) {3411 context.helper(WITH_CTX);3412 const { children, loc } = node;3413 const slotsProperties = [];3414 const dynamicSlots = [];3415 // If the slot is inside a v-for or another v-slot, force it to be dynamic3416 // since it likely uses a scope variable.3417 let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0;3418 // 1. Check for slot with slotProps on component itself.3419 // <Comp v-slot="{ prop }"/>3420 const onComponentSlot = findDir(node, 'slot', true);3421 if (onComponentSlot) {3422 const { arg, exp } = onComponentSlot;3423 if (arg && !isStaticExp(arg)) {3424 hasDynamicSlots = true;3425 }3426 slotsProperties.push(createObjectProperty(arg || createSimpleExpression('default', true), buildSlotFn(exp, children, loc)));3427 }3428 // 2. Iterate through children and check for template slots3429 // <template v-slot:foo="{ prop }">3430 let hasTemplateSlots = false;3431 let hasNamedDefaultSlot = false;3432 const implicitDefaultChildren = [];3433 const seenSlotNames = new Set();3434 for (let i = 0; i < children.length; i++) {3435 const slotElement = children[i];3436 let slotDir;3437 if (!isTemplateNode(slotElement) ||3438 !(slotDir = findDir(slotElement, 'slot', true))) {3439 // not a <template v-slot>, skip.3440 if (slotElement.type !== 3 /* COMMENT */) {3441 implicitDefaultChildren.push(slotElement);3442 }3443 continue;3444 }3445 if (onComponentSlot) {3446 // already has on-component slot - this is incorrect usage.3447 context.onError(createCompilerError(37 /* X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc));3448 break;3449 }3450 hasTemplateSlots = true;3451 const { children: slotChildren, loc: slotLoc } = slotElement;3452 const { arg: slotName = createSimpleExpression(`default`, true), exp: slotProps, loc: dirLoc } = slotDir;3453 // check if name is dynamic.3454 let staticSlotName;3455 if (isStaticExp(slotName)) {3456 staticSlotName = slotName ? slotName.content : `default`;3457 }3458 else {3459 hasDynamicSlots = true;3460 }3461 const slotFunction = buildSlotFn(slotProps, slotChildren, slotLoc);3462 // check if this slot is conditional (v-if/v-for)3463 let vIf;3464 let vElse;3465 let vFor;3466 if ((vIf = findDir(slotElement, 'if'))) {3467 hasDynamicSlots = true;3468 dynamicSlots.push(createConditionalExpression(vIf.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback));3469 }3470 else if ((vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))) {3471 // find adjacent v-if3472 let j = i;3473 let prev;3474 while (j--) {3475 prev = children[j];3476 if (prev.type !== 3 /* COMMENT */) {3477 break;3478 }3479 }3480 if (prev && isTemplateNode(prev) && findDir(prev, 'if')) {3481 // remove node3482 children.splice(i, 1);3483 i--;3484 // attach this slot to previous conditional3485 let conditional = dynamicSlots[dynamicSlots.length - 1];3486 while (conditional.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {3487 conditional = conditional.alternate;3488 }3489 conditional.alternate = vElse.exp3490 ? createConditionalExpression(vElse.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback)3491 : buildDynamicSlot(slotName, slotFunction);3492 }3493 else {3494 context.onError(createCompilerError(30 /* X_V_ELSE_NO_ADJACENT_IF */, vElse.loc));3495 }3496 }3497 else if ((vFor = findDir(slotElement, 'for'))) {3498 hasDynamicSlots = true;3499 const parseResult = vFor.parseResult ||3500 parseForExpression(vFor.exp, context);3501 if (parseResult) {3502 // Render the dynamic slots as an array and add it to the createSlot()3503 // args. The runtime knows how to handle it appropriately.3504 dynamicSlots.push(createCallExpression(context.helper(RENDER_LIST), [3505 parseResult.source,3506 createFunctionExpression(createForLoopParams(parseResult), buildDynamicSlot(slotName, slotFunction), true /* force newline */)3507 ]));3508 }3509 else {3510 context.onError(createCompilerError(32 /* X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc));3511 }3512 }3513 else {3514 // check duplicate static names3515 if (staticSlotName) {3516 if (seenSlotNames.has(staticSlotName)) {3517 context.onError(createCompilerError(38 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc));3518 continue;3519 }3520 seenSlotNames.add(staticSlotName);3521 if (staticSlotName === 'default') {3522 hasNamedDefaultSlot = true;3523 }3524 }3525 slotsProperties.push(createObjectProperty(slotName, slotFunction));3526 }3527 }3528 if (!onComponentSlot) {3529 const buildDefaultSlotProperty = (props, children) => {3530 const fn = buildSlotFn(props, children, loc);3531 if (context.compatConfig) {3532 fn.isNonScopedSlot = true;3533 }3534 return createObjectProperty(`default`, fn);3535 };3536 if (!hasTemplateSlots) {3537 // implicit default slot (on component)3538 slotsProperties.push(buildDefaultSlotProperty(undefined, children));3539 }3540 else if (implicitDefaultChildren.length &&3541 // #37663542 // with whitespace: 'preserve', whitespaces between slots will end up in3543 // implicitDefaultChildren. Ignore if all implicit children are whitespaces.3544 implicitDefaultChildren.some(node => isNonWhitespaceContent(node))) {3545 // implicit default slot (mixed with named slots)3546 if (hasNamedDefaultSlot) {3547 context.onError(createCompilerError(39 /* X_V_SLOT_EXTRANEOUS_DEFAULT_SLOT_CHILDREN */, implicitDefaultChildren[0].loc));3548 }3549 else {3550 slotsProperties.push(buildDefaultSlotProperty(undefined, implicitDefaultChildren));3551 }3552 }3553 }3554 const slotFlag = hasDynamicSlots3555 ? 2 /* DYNAMIC */3556 : hasForwardedSlots(node.children)3557 ? 3 /* FORWARDED */3558 : 1 /* STABLE */;3559 let slots = createObjectExpression(slotsProperties.concat(createObjectProperty(`_`, 3560 // 2 = compiled but dynamic = can skip normalization, but must run diff3561 // 1 = compiled and static = can skip normalization AND diff as optimized3562 createSimpleExpression(slotFlag + ((process.env.NODE_ENV !== 'production') ? ` /* ${slotFlagsText[slotFlag]} */` : ``), false))), loc);3563 if (dynamicSlots.length) {3564 slots = createCallExpression(context.helper(CREATE_SLOTS), [3565 slots,3566 createArrayExpression(dynamicSlots)3567 ]);3568 }3569 return {3570 slots,3571 hasDynamicSlots3572 };3573}3574function buildDynamicSlot(name, fn) {3575 return createObjectExpression([3576 createObjectProperty(`name`, name),3577 createObjectProperty(`fn`, fn)3578 ]);3579}3580function hasForwardedSlots(children) {3581 for (let i = 0; i < children.length; i++) {3582 const child = children[i];3583 switch (child.type) {3584 case 1 /* ELEMENT */:3585 if (child.tagType === 2 /* SLOT */ ||3586 hasForwardedSlots(child.children)) {3587 return true;3588 }3589 break;3590 case 9 /* IF */:3591 if (hasForwardedSlots(child.branches))3592 return true;3593 break;3594 case 10 /* IF_BRANCH */:3595 case 11 /* FOR */:3596 if (hasForwardedSlots(child.children))3597 return true;3598 break;3599 }3600 }3601 return false;3602}3603function isNonWhitespaceContent(node) {3604 if (node.type !== 2 /* TEXT */ && node.type !== 12 /* TEXT_CALL */)3605 return true;3606 return node.type === 2 /* TEXT */3607 ? !!node.content.trim()3608 : isNonWhitespaceContent(node.content);3609}3610// some directive transforms (e.g. v-model) may return a symbol for runtime3611// import, which should be used instead of a resolveDirective call.3612const directiveImportMap = new WeakMap();3613// generate a JavaScript AST for this element's codegen3614const transformElement = (node, context) => {3615 // perform the work on exit, after all child expressions have been3616 // processed and merged.3617 return function postTransformElement() {3618 node = context.currentNode;3619 if (!(node.type === 1 /* ELEMENT */ &&3620 (node.tagType === 0 /* ELEMENT */ ||3621 node.tagType === 1 /* COMPONENT */))) {3622 return;3623 }3624 const { tag, props } = node;3625 const isComponent = node.tagType === 1 /* COMPONENT */;3626 // The goal of the transform is to create a codegenNode implementing the3627 // VNodeCall interface.3628 let vnodeTag = isComponent3629 ? resolveComponentType(node, context)3630 : `"${tag}"`;3631 const isDynamicComponent = isObject(vnodeTag) && vnodeTag.callee === RESOLVE_DYNAMIC_COMPONENT;3632 let vnodeProps;3633 let vnodeChildren;3634 let vnodePatchFlag;3635 let patchFlag = 0;3636 let vnodeDynamicProps;3637 let dynamicPropNames;3638 let vnodeDirectives;3639 let shouldUseBlock = 3640 // dynamic component may resolve to plain elements3641 isDynamicComponent ||3642 vnodeTag === TELEPORT ||3643 vnodeTag === SUSPENSE ||3644 (!isComponent &&3645 // <svg> and <foreignObject> must be forced into blocks so that block3646 // updates inside get proper isSVG flag at runtime. (#639, #643)3647 // This is technically web-specific, but splitting the logic out of core3648 // leads to too much unnecessary complexity.3649 (tag === 'svg' || tag === 'foreignObject'));3650 // props3651 if (props.length > 0) {3652 const propsBuildResult = buildProps(node, context);3653 vnodeProps = propsBuildResult.props;3654 patchFlag = propsBuildResult.patchFlag;3655 dynamicPropNames = propsBuildResult.dynamicPropNames;3656 const directives = propsBuildResult.directives;3657 vnodeDirectives =3658 directives && directives.length3659 ? createArrayExpression(directives.map(dir => buildDirectiveArgs(dir, context)))3660 : undefined;3661 if (propsBuildResult.shouldUseBlock) {3662 shouldUseBlock = true;3663 }3664 }3665 // children3666 if (node.children.length > 0) {3667 if (vnodeTag === KEEP_ALIVE) {3668 // Although a built-in component, we compile KeepAlive with raw children3669 // instead of slot functions so that it can be used inside Transition3670 // or other Transition-wrapping HOCs.3671 // To ensure correct updates with block optimizations, we need to:3672 // 1. Force keep-alive into a block. This avoids its children being3673 // collected by a parent block.3674 shouldUseBlock = true;3675 // 2. Force keep-alive to always be updated, since it uses raw children.3676 patchFlag |= 1024 /* DYNAMIC_SLOTS */;3677 if ((process.env.NODE_ENV !== 'production') && node.children.length > 1) {3678 context.onError(createCompilerError(45 /* X_KEEP_ALIVE_INVALID_CHILDREN */, {3679 start: node.children[0].loc.start,3680 end: node.children[node.children.length - 1].loc.end,3681 source: ''3682 }));3683 }3684 }3685 const shouldBuildAsSlots = isComponent &&3686 // Teleport is not a real component and has dedicated runtime handling3687 vnodeTag !== TELEPORT &&3688 // explained above.3689 vnodeTag !== KEEP_ALIVE;3690 if (shouldBuildAsSlots) {3691 const { slots, hasDynamicSlots } = buildSlots(node, context);3692 vnodeChildren = slots;3693 if (hasDynamicSlots) {3694 patchFlag |= 1024 /* DYNAMIC_SLOTS */;3695 }3696 }3697 else if (node.children.length === 1 && vnodeTag !== TELEPORT) {3698 const child = node.children[0];3699 const type = child.type;3700 // check for dynamic text children3701 const hasDynamicTextChild = type === 5 /* INTERPOLATION */ ||3702 type === 8 /* COMPOUND_EXPRESSION */;3703 if (hasDynamicTextChild &&3704 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {3705 patchFlag |= 1 /* TEXT */;3706 }3707 // pass directly if the only child is a text node3708 // (plain / interpolation / expression)3709 if (hasDynamicTextChild || type === 2 /* TEXT */) {3710 vnodeChildren = child;3711 }3712 else {3713 vnodeChildren = node.children;3714 }3715 }3716 else {3717 vnodeChildren = node.children;3718 }3719 }3720 // patchFlag & dynamicPropNames3721 if (patchFlag !== 0) {3722 if ((process.env.NODE_ENV !== 'production')) {3723 if (patchFlag < 0) {3724 // special flags (negative and mutually exclusive)3725 vnodePatchFlag = patchFlag + ` /* ${PatchFlagNames[patchFlag]} */`;3726 }3727 else {3728 // bitwise flags3729 const flagNames = Object.keys(PatchFlagNames)3730 .map(Number)3731 .filter(n => n > 0 && patchFlag & n)3732 .map(n => PatchFlagNames[n])3733 .join(`, `);3734 vnodePatchFlag = patchFlag + ` /* ${flagNames} */`;3735 }3736 }3737 else {3738 vnodePatchFlag = String(patchFlag);3739 }3740 if (dynamicPropNames && dynamicPropNames.length) {3741 vnodeDynamicProps = stringifyDynamicPropNames(dynamicPropNames);3742 }3743 }3744 node.codegenNode = createVNodeCall(context, vnodeTag, vnodeProps, vnodeChildren, vnodePatchFlag, vnodeDynamicProps, vnodeDirectives, !!shouldUseBlock, false /* disableTracking */, isComponent, node.loc);3745 };3746};3747function resolveComponentType(node, context, ssr = false) {3748 let { tag } = node;3749 // 1. dynamic component3750 const isExplicitDynamic = isComponentTag(tag);3751 const isProp = findProp(node, 'is');3752 if (isProp) {3753 if (isExplicitDynamic ||3754 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))) {3755 const exp = isProp.type === 6 /* ATTRIBUTE */3756 ? isProp.value && createSimpleExpression(isProp.value.content, true)3757 : isProp.exp;3758 if (exp) {3759 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [3760 exp3761 ]);3762 }3763 }3764 else if (isProp.type === 6 /* ATTRIBUTE */ &&3765 isProp.value.content.startsWith('vue:')) {3766 // <button is="vue:xxx">3767 // if not <component>, only is value that starts with "vue:" will be3768 // treated as component by the parse phase and reach here, unless it's3769 // compat mode where all is values are considered components3770 tag = isProp.value.content.slice(4);3771 }3772 }3773 // 1.5 v-is (TODO: Deprecate)3774 const isDir = !isExplicitDynamic && findDir(node, 'is');3775 if (isDir && isDir.exp) {3776 return createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [3777 isDir.exp3778 ]);3779 }3780 // 2. built-in components (Teleport, Transition, KeepAlive, Suspense...)3781 const builtIn = isCoreComponent(tag) || context.isBuiltInComponent(tag);3782 if (builtIn) {3783 // built-ins are simply fallthroughs / have special handling during ssr3784 // so we don't need to import their runtime equivalents3785 if (!ssr)3786 context.helper(builtIn);3787 return builtIn;3788 }3789 // 5. user component (resolve)3790 context.helper(RESOLVE_COMPONENT);3791 context.components.add(tag);3792 return toValidAssetId(tag, `component`);3793}3794function buildProps(node, context, props = node.props, ssr = false) {3795 const { tag, loc: elementLoc, children } = node;3796 const isComponent = node.tagType === 1 /* COMPONENT */;3797 let properties = [];3798 const mergeArgs = [];3799 const runtimeDirectives = [];3800 const hasChildren = children.length > 0;3801 let shouldUseBlock = false;3802 // patchFlag analysis3803 let patchFlag = 0;3804 let hasRef = false;3805 let hasClassBinding = false;3806 let hasStyleBinding = false;3807 let hasHydrationEventBinding = false;3808 let hasDynamicKeys = false;3809 let hasVnodeHook = false;3810 const dynamicPropNames = [];3811 const analyzePatchFlag = ({ key, value }) => {3812 if (isStaticExp(key)) {3813 const name = key.content;3814 const isEventHandler = isOn(name);3815 if (!isComponent &&3816 isEventHandler &&3817 // omit the flag for click handlers because hydration gives click3818 // dedicated fast path.3819 name.toLowerCase() !== 'onclick' &&3820 // omit v-model handlers3821 name !== 'onUpdate:modelValue' &&3822 // omit onVnodeXXX hooks3823 !isReservedProp(name)) {3824 hasHydrationEventBinding = true;3825 }3826 if (isEventHandler && isReservedProp(name)) {3827 hasVnodeHook = true;3828 }3829 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||3830 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||3831 value.type === 8 /* COMPOUND_EXPRESSION */) &&3832 getConstantType(value, context) > 0)) {3833 // skip if the prop is a cached handler or has constant value3834 return;3835 }3836 if (name === 'ref') {3837 hasRef = true;3838 }3839 else if (name === 'class') {3840 hasClassBinding = true;3841 }3842 else if (name === 'style') {3843 hasStyleBinding = true;3844 }3845 else if (name !== 'key' && !dynamicPropNames.includes(name)) {3846 dynamicPropNames.push(name);3847 }3848 // treat the dynamic class and style binding of the component as dynamic props3849 if (isComponent &&3850 (name === 'class' || name === 'style') &&3851 !dynamicPropNames.includes(name)) {3852 dynamicPropNames.push(name);3853 }3854 }3855 else {3856 hasDynamicKeys = true;3857 }3858 };3859 for (let i = 0; i < props.length; i++) {3860 // static attribute3861 const prop = props[i];3862 if (prop.type === 6 /* ATTRIBUTE */) {3863 const { loc, name, value } = prop;3864 let isStatic = true;3865 if (name === 'ref') {3866 hasRef = true;3867 if (context.scopes.vFor > 0) {3868 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));3869 }3870 }3871 // skip is on <component>, or is="vue:xxx"3872 if (name === 'is' &&3873 (isComponentTag(tag) ||3874 (value && value.content.startsWith('vue:')) ||3875 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context)))) {3876 continue;3877 }3878 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', isStatic, value ? value.loc : loc)));3879 }3880 else {3881 // directives3882 const { name, arg, exp, loc } = prop;3883 const isVBind = name === 'bind';3884 const isVOn = name === 'on';3885 // skip v-slot - it is handled by its dedicated transform.3886 if (name === 'slot') {3887 if (!isComponent) {3888 context.onError(createCompilerError(40 /* X_V_SLOT_MISPLACED */, loc));3889 }3890 continue;3891 }3892 // skip v-once/v-memo - they are handled by dedicated transforms.3893 if (name === 'once' || name === 'memo') {3894 continue;3895 }3896 // skip v-is and :is on <component>3897 if (name === 'is' ||3898 (isVBind &&3899 isStaticArgOf(arg, 'is') &&3900 (isComponentTag(tag) ||3901 (isCompatEnabled("COMPILER_IS_ON_ELEMENT" /* COMPILER_IS_ON_ELEMENT */, context))))) {3902 continue;3903 }3904 // skip v-on in SSR compilation3905 if (isVOn && ssr) {3906 continue;3907 }3908 if (3909 // #938: elements with dynamic keys should be forced into blocks3910 (isVBind && isStaticArgOf(arg, 'key')) ||3911 // inline before-update hooks need to force block so that it is invoked3912 // before children3913 (isVOn && hasChildren && isStaticArgOf(arg, 'vue:before-update'))) {3914 shouldUseBlock = true;3915 }3916 if (isVBind && isStaticArgOf(arg, 'ref') && context.scopes.vFor > 0) {3917 properties.push(createObjectProperty(createSimpleExpression('ref_for', true), createSimpleExpression('true')));3918 }3919 // special case for v-bind and v-on with no argument3920 if (!arg && (isVBind || isVOn)) {3921 hasDynamicKeys = true;3922 if (exp) {3923 if (properties.length) {3924 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3925 properties = [];3926 }3927 if (isVBind) {3928 {3929 // 2.x v-bind object order compat3930 if ((process.env.NODE_ENV !== 'production')) {3931 const hasOverridableKeys = mergeArgs.some(arg => {3932 if (arg.type === 15 /* JS_OBJECT_EXPRESSION */) {3933 return arg.properties.some(({ key }) => {3934 if (key.type !== 4 /* SIMPLE_EXPRESSION */ ||3935 !key.isStatic) {3936 return true;3937 }3938 return (key.content !== 'class' &&3939 key.content !== 'style' &&3940 !isOn(key.content));3941 });3942 }3943 else {3944 // dynamic expression3945 return true;3946 }3947 });3948 if (hasOverridableKeys) {3949 checkCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context, loc);3950 }3951 }3952 if (isCompatEnabled("COMPILER_V_BIND_OBJECT_ORDER" /* COMPILER_V_BIND_OBJECT_ORDER */, context)) {3953 mergeArgs.unshift(exp);3954 continue;3955 }3956 }3957 mergeArgs.push(exp);3958 }3959 else {3960 // v-on="obj" -> toHandlers(obj)3961 mergeArgs.push({3962 type: 14 /* JS_CALL_EXPRESSION */,3963 loc,3964 callee: context.helper(TO_HANDLERS),3965 arguments: [exp]3966 });3967 }3968 }3969 else {3970 context.onError(createCompilerError(isVBind3971 ? 34 /* X_V_BIND_NO_EXPRESSION */3972 : 35 /* X_V_ON_NO_EXPRESSION */, loc));3973 }3974 continue;3975 }3976 const directiveTransform = context.directiveTransforms[name];3977 if (directiveTransform) {3978 // has built-in directive transform.3979 const { props, needRuntime } = directiveTransform(prop, node, context);3980 !ssr && props.forEach(analyzePatchFlag);3981 properties.push(...props);3982 if (needRuntime) {3983 runtimeDirectives.push(prop);3984 if (isSymbol(needRuntime)) {3985 directiveImportMap.set(prop, needRuntime);3986 }3987 }3988 }3989 else {3990 // no built-in transform, this is a user custom directive.3991 runtimeDirectives.push(prop);3992 // custom dirs may use beforeUpdate so they need to force blocks3993 // to ensure before-update gets called before children update3994 if (hasChildren) {3995 shouldUseBlock = true;3996 }3997 }3998 }3999 }4000 let propsExpression = undefined;4001 // has v-bind="object" or v-on="object", wrap with mergeProps4002 if (mergeArgs.length) {4003 if (properties.length) {4004 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));4005 }4006 if (mergeArgs.length > 1) {4007 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);4008 }4009 else {4010 // single v-bind with nothing else - no need for a mergeProps call4011 propsExpression = mergeArgs[0];4012 }4013 }4014 else if (properties.length) {4015 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);4016 }4017 // patchFlag analysis4018 if (hasDynamicKeys) {4019 patchFlag |= 16 /* FULL_PROPS */;4020 }4021 else {4022 if (hasClassBinding && !isComponent) {4023 patchFlag |= 2 /* CLASS */;4024 }4025 if (hasStyleBinding && !isComponent) {4026 patchFlag |= 4 /* STYLE */;4027 }4028 if (dynamicPropNames.length) {4029 patchFlag |= 8 /* PROPS */;4030 }4031 if (hasHydrationEventBinding) {4032 patchFlag |= 32 /* HYDRATE_EVENTS */;4033 }4034 }4035 if (!shouldUseBlock &&4036 (patchFlag === 0 || patchFlag === 32 /* HYDRATE_EVENTS */) &&4037 (hasRef || hasVnodeHook || runtimeDirectives.length > 0)) {4038 patchFlag |= 512 /* NEED_PATCH */;4039 }4040 // pre-normalize props, SSR is skipped for now4041 if (!context.inSSR && propsExpression) {4042 switch (propsExpression.type) {4043 case 15 /* JS_OBJECT_EXPRESSION */:4044 // means that there is no v-bind,4045 // but still need to deal with dynamic key binding4046 let classKeyIndex = -1;4047 let styleKeyIndex = -1;4048 let hasDynamicKey = false;4049 for (let i = 0; i < propsExpression.properties.length; i++) {4050 const key = propsExpression.properties[i].key;4051 if (isStaticExp(key)) {4052 if (key.content === 'class') {4053 classKeyIndex = i;4054 }4055 else if (key.content === 'style') {4056 styleKeyIndex = i;4057 }4058 }4059 else if (!key.isHandlerKey) {4060 hasDynamicKey = true;4061 }4062 }4063 const classProp = propsExpression.properties[classKeyIndex];4064 const styleProp = propsExpression.properties[styleKeyIndex];4065 // no dynamic key4066 if (!hasDynamicKey) {4067 if (classProp && !isStaticExp(classProp.value)) {4068 classProp.value = createCallExpression(context.helper(NORMALIZE_CLASS), [classProp.value]);4069 }4070 if (styleProp &&4071 !isStaticExp(styleProp.value) &&4072 // the static style is compiled into an object,4073 // so use `hasStyleBinding` to ensure that it is a dynamic style binding4074 (hasStyleBinding ||4075 // v-bind:style and style both exist,4076 // v-bind:style with static literal object4077 styleProp.value.type === 17 /* JS_ARRAY_EXPRESSION */)) {4078 styleProp.value = createCallExpression(context.helper(NORMALIZE_STYLE), [styleProp.value]);4079 }4080 }4081 else {4082 // dynamic key binding, wrap with `normalizeProps`4083 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [propsExpression]);4084 }4085 break;4086 case 14 /* JS_CALL_EXPRESSION */:4087 // mergeProps call, do nothing4088 break;4089 default:4090 // single v-bind4091 propsExpression = createCallExpression(context.helper(NORMALIZE_PROPS), [4092 createCallExpression(context.helper(GUARD_REACTIVE_PROPS), [4093 propsExpression4094 ])4095 ]);4096 break;4097 }4098 }4099 return {4100 props: propsExpression,4101 directives: runtimeDirectives,4102 patchFlag,4103 dynamicPropNames,4104 shouldUseBlock4105 };4106}4107// Dedupe props in an object literal.4108// Literal duplicated attributes would have been warned during the parse phase,4109// however, it's possible to encounter duplicated `onXXX` handlers with different4110// modifiers. We also need to merge static and dynamic class / style attributes.4111// - onXXX handlers / style: merge into array4112// - class: merge into single expression with concatenation4113function dedupeProperties(properties) {4114 const knownProps = new Map();4115 const deduped = [];4116 for (let i = 0; i < properties.length; i++) {4117 const prop = properties[i];4118 // dynamic keys are always allowed4119 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {4120 deduped.push(prop);4121 continue;4122 }4123 const name = prop.key.content;4124 const existing = knownProps.get(name);4125 if (existing) {4126 if (name === 'style' || name === 'class' || isOn(name)) {4127 mergeAsArray(existing, prop);4128 }4129 // unexpected duplicate, should have emitted error during parse4130 }4131 else {4132 knownProps.set(name, prop);4133 deduped.push(prop);4134 }4135 }4136 return deduped;4137}4138function mergeAsArray(existing, incoming) {4139 if (existing.value.type === 17 /* JS_ARRAY_EXPRESSION */) {4140 existing.value.elements.push(incoming.value);4141 }4142 else {4143 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);4144 }4145}4146function buildDirectiveArgs(dir, context) {4147 const dirArgs = [];4148 const runtime = directiveImportMap.get(dir);4149 if (runtime) {4150 // built-in directive with runtime4151 dirArgs.push(context.helperString(runtime));4152 }4153 else {4154 {4155 // inject statement for resolving directive4156 context.helper(RESOLVE_DIRECTIVE);4157 context.directives.add(dir.name);4158 dirArgs.push(toValidAssetId(dir.name, `directive`));4159 }4160 }4161 const { loc } = dir;4162 if (dir.exp)4163 dirArgs.push(dir.exp);4164 if (dir.arg) {4165 if (!dir.exp) {4166 dirArgs.push(`void 0`);4167 }4168 dirArgs.push(dir.arg);4169 }4170 if (Object.keys(dir.modifiers).length) {4171 if (!dir.arg) {4172 if (!dir.exp) {4173 dirArgs.push(`void 0`);4174 }4175 dirArgs.push(`void 0`);4176 }4177 const trueExpression = createSimpleExpression(`true`, false, loc);4178 dirArgs.push(createObjectExpression(dir.modifiers.map(modifier => createObjectProperty(modifier, trueExpression)), loc));4179 }4180 return createArrayExpression(dirArgs, dir.loc);4181}4182function stringifyDynamicPropNames(props) {4183 let propsNamesString = `[`;4184 for (let i = 0, l = props.length; i < l; i++) {4185 propsNamesString += JSON.stringify(props[i]);4186 if (i < l - 1)4187 propsNamesString += ', ';4188 }4189 return propsNamesString + `]`;4190}4191function isComponentTag(tag) {4192 return tag === 'component' || tag === 'Component';4193}4194(process.env.NODE_ENV !== 'production')4195 ? Object.freeze({})4196 : {};4197(process.env.NODE_ENV !== 'production') ? Object.freeze([]) : [];4198const cacheStringFunction = (fn) => {4199 const cache = Object.create(null);4200 return ((str) => {4201 const hit = cache[str];4202 return hit || (cache[str] = fn(str));4203 });4204};4205const camelizeRE = /-(\w)/g;4206/**4207 * @private4208 */4209const camelize = cacheStringFunction((str) => {4210 return str.replace(camelizeRE, (_, c) => (c ? c.toUpperCase() : ''));4211});4212const transformSlotOutlet = (node, context) => {4213 if (isSlotOutlet(node)) {4214 const { children, loc } = node;4215 const { slotName, slotProps } = processSlotOutlet(node, context);4216 const slotArgs = [4217 context.prefixIdentifiers ? `_ctx.$slots` : `$slots`,4218 slotName,4219 '{}',4220 'undefined',4221 'true'4222 ];4223 let expectedLen = 2;4224 if (slotProps) {4225 slotArgs[2] = slotProps;4226 expectedLen = 3;4227 }4228 if (children.length) {4229 slotArgs[3] = createFunctionExpression([], children, false, false, loc);4230 expectedLen = 4;4231 }4232 if (context.scopeId && !context.slotted) {4233 expectedLen = 5;4234 }4235 slotArgs.splice(expectedLen); // remove unused arguments4236 node.codegenNode = createCallExpression(context.helper(RENDER_SLOT), slotArgs, loc);4237 }4238};4239function processSlotOutlet(node, context) {4240 let slotName = `"default"`;4241 let slotProps = undefined;4242 const nonNameProps = [];4243 for (let i = 0; i < node.props.length; i++) {4244 const p = node.props[i];4245 if (p.type === 6 /* ATTRIBUTE */) {4246 if (p.value) {4247 if (p.name === 'name') {4248 slotName = JSON.stringify(p.value.content);4249 }4250 else {4251 p.name = camelize(p.name);4252 nonNameProps.push(p);4253 }4254 }4255 }4256 else {4257 if (p.name === 'bind' && isStaticArgOf(p.arg, 'name')) {4258 if (p.exp)4259 slotName = p.exp;4260 }4261 else {4262 if (p.name === 'bind' && p.arg && isStaticExp(p.arg)) {4263 p.arg.content = camelize(p.arg.content);4264 }4265 nonNameProps.push(p);4266 }4267 }4268 }4269 if (nonNameProps.length > 0) {4270 const { props, directives } = buildProps(node, context, nonNameProps);4271 slotProps = props;4272 if (directives.length) {4273 context.onError(createCompilerError(36 /* X_V_SLOT_UNEXPECTED_DIRECTIVE_ON_SLOT_OUTLET */, directives[0].loc));4274 }4275 }4276 return {4277 slotName,4278 slotProps4279 };4280}4281const fnExpRE = /^\s*([\w$_]+|(async\s*)?\([^)]*?\))\s*=>|^\s*(async\s+)?function(?:\s+[\w$]+)?\s*\(/;4282const transformOn = (dir, node, context, augmentor) => {4283 const { loc, modifiers, arg } = dir;4284 if (!dir.exp && !modifiers.length) {4285 context.onError(createCompilerError(35 /* X_V_ON_NO_EXPRESSION */, loc));4286 }4287 let eventName;4288 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4289 if (arg.isStatic) {4290 let rawName = arg.content;4291 // TODO deprecate @vnodeXXX usage4292 if (rawName.startsWith('vue:')) {4293 rawName = `vnode-${rawName.slice(4)}`;4294 }4295 // for all event listeners, auto convert it to camelCase. See issue #22494296 eventName = createSimpleExpression(toHandlerKey(camelize$1(rawName)), true, arg.loc);4297 }4298 else {4299 // #23884300 eventName = createCompoundExpression([4301 `${context.helperString(TO_HANDLER_KEY)}(`,4302 arg,4303 `)`4304 ]);4305 }4306 }4307 else {4308 // already a compound expression.4309 eventName = arg;4310 eventName.children.unshift(`${context.helperString(TO_HANDLER_KEY)}(`);4311 eventName.children.push(`)`);4312 }4313 // handler processing4314 let exp = dir.exp;4315 if (exp && !exp.content.trim()) {4316 exp = undefined;4317 }4318 let shouldCache = context.cacheHandlers && !exp && !context.inVOnce;4319 if (exp) {4320 const isMemberExp = isMemberExpression(exp.content);4321 const isInlineStatement = !(isMemberExp || fnExpRE.test(exp.content));4322 const hasMultipleStatements = exp.content.includes(`;`);4323 if ((process.env.NODE_ENV !== 'production') && true) {4324 validateBrowserExpression(exp, context, false, hasMultipleStatements);4325 }4326 if (isInlineStatement || (shouldCache && isMemberExp)) {4327 // wrap inline statement in a function expression4328 exp = createCompoundExpression([4329 `${isInlineStatement4330 ? `$event`4331 : `${``}(...args)`} => ${hasMultipleStatements ? `{` : `(`}`,4332 exp,4333 hasMultipleStatements ? `}` : `)`4334 ]);4335 }4336 }4337 let ret = {4338 props: [4339 createObjectProperty(eventName, exp || createSimpleExpression(`() => {}`, false, loc))4340 ]4341 };4342 // apply extended compiler augmentor4343 if (augmentor) {4344 ret = augmentor(ret);4345 }4346 if (shouldCache) {4347 // cache handlers so that it's always the same handler being passed down.4348 // this avoids unnecessary re-renders when users use inline handlers on4349 // components.4350 ret.props[0].value = context.cache(ret.props[0].value);4351 }4352 // mark the key as handler for props normalization check4353 ret.props.forEach(p => (p.key.isHandlerKey = true));4354 return ret;4355};4356// v-bind without arg is handled directly in ./transformElements.ts due to it affecting4357// codegen for the entire props object. This transform here is only for v-bind4358// *with* args.4359const transformBind = (dir, _node, context) => {4360 const { exp, modifiers, loc } = dir;4361 const arg = dir.arg;4362 if (arg.type !== 4 /* SIMPLE_EXPRESSION */) {4363 arg.children.unshift(`(`);4364 arg.children.push(`) || ""`);4365 }4366 else if (!arg.isStatic) {4367 arg.content = `${arg.content} || ""`;4368 }4369 // .sync is replaced by v-model:arg4370 if (modifiers.includes('camel')) {4371 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4372 if (arg.isStatic) {4373 arg.content = camelize$1(arg.content);4374 }4375 else {4376 arg.content = `${context.helperString(CAMELIZE)}(${arg.content})`;4377 }4378 }4379 else {4380 arg.children.unshift(`${context.helperString(CAMELIZE)}(`);4381 arg.children.push(`)`);4382 }4383 }4384 if (!context.inSSR) {4385 if (modifiers.includes('prop')) {4386 injectPrefix(arg, '.');4387 }4388 if (modifiers.includes('attr')) {4389 injectPrefix(arg, '^');4390 }4391 }4392 if (!exp ||4393 (exp.type === 4 /* SIMPLE_EXPRESSION */ && !exp.content.trim())) {4394 context.onError(createCompilerError(34 /* X_V_BIND_NO_EXPRESSION */, loc));4395 return {4396 props: [createObjectProperty(arg, createSimpleExpression('', true, loc))]4397 };4398 }4399 return {4400 props: [createObjectProperty(arg, exp)]4401 };4402};4403const injectPrefix = (arg, prefix) => {4404 if (arg.type === 4 /* SIMPLE_EXPRESSION */) {4405 if (arg.isStatic) {4406 arg.content = prefix + arg.content;4407 }4408 else {4409 arg.content = `\`${prefix}\${${arg.content}}\``;4410 }4411 }4412 else {4413 arg.children.unshift(`'${prefix}' + (`);4414 arg.children.push(`)`);4415 }4416};4417// Merge adjacent text nodes and expressions into a single expression4418// e.g. <div>abc {{ d }} {{ e }}</div> should have a single expression node as child.4419const transformText = (node, context) => {4420 if (node.type === 0 /* ROOT */ ||4421 node.type === 1 /* ELEMENT */ ||4422 node.type === 11 /* FOR */ ||4423 node.type === 10 /* IF_BRANCH */) {4424 // perform the transform on node exit so that all expressions have already4425 // been processed.4426 return () => {4427 const children = node.children;4428 let currentContainer = undefined;4429 let hasText = false;4430 for (let i = 0; i < children.length; i++) {4431 const child = children[i];4432 if (isText(child)) {4433 hasText = true;4434 for (let j = i + 1; j < children.length; j++) {4435 const next = children[j];4436 if (isText(next)) {4437 if (!currentContainer) {4438 currentContainer = children[i] = {4439 type: 8 /* COMPOUND_EXPRESSION */,4440 loc: child.loc,4441 children: [child]4442 };4443 }4444 // merge adjacent text node into current4445 currentContainer.children.push(` + `, next);4446 children.splice(j, 1);4447 j--;4448 }4449 else {4450 currentContainer = undefined;4451 break;4452 }4453 }4454 }4455 }4456 if (!hasText ||4457 // if this is a plain element with a single text child, leave it4458 // as-is since the runtime has dedicated fast path for this by directly4459 // setting textContent of the element.4460 // for component root it's always normalized anyway.4461 (children.length === 1 &&4462 (node.type === 0 /* ROOT */ ||4463 (node.type === 1 /* ELEMENT */ &&4464 node.tagType === 0 /* ELEMENT */ &&4465 // #37564466 // custom directives can potentially add DOM elements arbitrarily,4467 // we need to avoid setting textContent of the element at runtime4468 // to avoid accidentally overwriting the DOM elements added4469 // by the user through custom directives.4470 !node.props.find(p => p.type === 7 /* DIRECTIVE */ &&4471 !context.directiveTransforms[p.name]) &&4472 // in compat mode, <template> tags with no special directives4473 // will be rendered as a fragment so its children must be4474 // converted into vnodes.4475 !(node.tag === 'template'))))) {4476 return;4477 }4478 // pre-convert text nodes into createTextVNode(text) calls to avoid4479 // runtime normalization.4480 for (let i = 0; i < children.length; i++) {4481 const child = children[i];4482 if (isText(child) || child.type === 8 /* COMPOUND_EXPRESSION */) {4483 const callArgs = [];4484 // createTextVNode defaults to single whitespace, so if it is a4485 // single space the code could be an empty call to save bytes.4486 if (child.type !== 2 /* TEXT */ || child.content !== ' ') {4487 callArgs.push(child);4488 }4489 // mark dynamic text with flag so it gets patched inside a block4490 if (!context.ssr &&4491 getConstantType(child, context) === 0 /* NOT_CONSTANT */) {4492 callArgs.push(1 /* TEXT */ +4493 ((process.env.NODE_ENV !== 'production') ? ` /* ${PatchFlagNames[1 /* TEXT */]} */` : ``));4494 }4495 children[i] = {4496 type: 12 /* TEXT_CALL */,4497 content: child,4498 loc: child.loc,4499 codegenNode: createCallExpression(context.helper(CREATE_TEXT), callArgs)4500 };4501 }4502 }4503 };4504 }4505};4506const seen = new WeakSet();4507const transformOnce = (node, context) => {4508 if (node.type === 1 /* ELEMENT */ && findDir(node, 'once', true)) {4509 if (seen.has(node) || context.inVOnce) {4510 return;4511 }4512 seen.add(node);4513 context.inVOnce = true;4514 context.helper(SET_BLOCK_TRACKING);4515 return () => {4516 context.inVOnce = false;4517 const cur = context.currentNode;4518 if (cur.codegenNode) {4519 cur.codegenNode = context.cache(cur.codegenNode, true /* isVNode */);4520 }4521 };4522 }4523};4524const transformModel = (dir, node, context) => {4525 const { exp, arg } = dir;4526 if (!exp) {4527 context.onError(createCompilerError(41 /* X_V_MODEL_NO_EXPRESSION */, dir.loc));4528 return createTransformProps();4529 }4530 const rawExp = exp.loc.source;4531 const expString = exp.type === 4 /* SIMPLE_EXPRESSION */ ? exp.content : rawExp;4532 // im SFC <script setup> inline mode, the exp may have been transformed into4533 // _unref(exp)4534 context.bindingMetadata[rawExp];4535 const maybeRef = !true /* SETUP_CONST */;4536 if (!expString.trim() ||4537 (!isMemberExpression(expString) && !maybeRef)) {4538 context.onError(createCompilerError(42 /* X_V_MODEL_MALFORMED_EXPRESSION */, exp.loc));4539 return createTransformProps();4540 }4541 const propName = arg ? arg : createSimpleExpression('modelValue', true);4542 const eventName = arg4543 ? isStaticExp(arg)4544 ? `onUpdate:${arg.content}`4545 : createCompoundExpression(['"onUpdate:" + ', arg])4546 : `onUpdate:modelValue`;4547 let assignmentExp;4548 const eventArg = context.isTS ? `($event: any)` : `$event`;4549 {4550 assignmentExp = createCompoundExpression([4551 `${eventArg} => ((`,4552 exp,4553 `) = $event)`4554 ]);4555 }4556 const props = [4557 // modelValue: foo4558 createObjectProperty(propName, dir.exp),4559 // "onUpdate:modelValue": $event => (foo = $event)4560 createObjectProperty(eventName, assignmentExp)4561 ];4562 // modelModifiers: { foo: true, "bar-baz": true }4563 if (dir.modifiers.length && node.tagType === 1 /* COMPONENT */) {4564 const modifiers = dir.modifiers4565 .map(m => (isSimpleIdentifier(m) ? m : JSON.stringify(m)) + `: true`)4566 .join(`, `);4567 const modifiersKey = arg4568 ? isStaticExp(arg)4569 ? `${arg.content}Modifiers`4570 : createCompoundExpression([arg, ' + "Modifiers"'])4571 : `modelModifiers`;4572 props.push(createObjectProperty(modifiersKey, createSimpleExpression(`{ ${modifiers} }`, false, dir.loc, 2 /* CAN_HOIST */)));4573 }4574 return createTransformProps(props);4575};4576function createTransformProps(props = []) {4577 return { props };4578}4579const validDivisionCharRE = /[\w).+\-_$\]]/;4580const transformFilter = (node, context) => {4581 if (!isCompatEnabled("COMPILER_FILTER" /* COMPILER_FILTERS */, context)) {4582 return;4583 }4584 if (node.type === 5 /* INTERPOLATION */) {4585 // filter rewrite is applied before expression transform so only4586 // simple expressions are possible at this stage4587 rewriteFilter(node.content, context);4588 }4589 if (node.type === 1 /* ELEMENT */) {4590 node.props.forEach((prop) => {4591 if (prop.type === 7 /* DIRECTIVE */ &&4592 prop.name !== 'for' &&4593 prop.exp) {4594 rewriteFilter(prop.exp, context);4595 }...
Using AI Code Generation
1const { isCompatEnabled } = require('playwright-core/lib/server/browserContext');2const { chromium } = require('playwright-core');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 console.log(isCompatEnabled(context));8 await browser.close();9})();10[MIT](LICENSE)
Using AI Code Generation
1const { devices } = require('playwright');2const iPhone = devices['iPhone 11 Pro'];3const { chromium } = require('playwright');4(async () => {5 const browser = await chromium.launch();6 const context = await browser.newContext({7 geolocation: { longitude: 12.492507, latitude: 41.889938 },8 });9 const page = await context.newPage();10 await page.click('text="Your location"');11 await page.waitForSelector('text="Your device"');12 await page.click('text="Your device"');13 await page.evaluate(() => console.log(navigator.permissions.query));14 await browser.close();15})();16const { devices } = require('playwright');17const iPhone = devices['iPhone 11 Pro'];18const { chromium } = require('playwright');19(async () => {20 const browser = await chromium.launch();21 const context = await browser.newContext({22 geolocation: { longitude: 12.492507, latitude: 41.889938 },23 });24 const page = await context.newPage();25 await page.click('text="Your location"');26 await page.waitForSelector('text="Your device"');27 await page.click('text="Your device"');28 await page.evaluate(() => console.log(navigator.userAgent));29 await browser.close();30})();
Using AI Code Generation
1const { isCompatEnabled } = require('playwright/lib/server/chromium/crBrowser');2const { chromium } = require('playwright');3(async () => {4 const browser = await chromium.launch();5 const page = await browser.newPage();6 console.log(isCompatEnabled(page));7 await browser.close();8})();9We welcome contributions to Playwright! Please read the [contributing guide](
Using AI Code Generation
1const { isCompatEnabled } = require('@playwright/test/lib/server/compat');2const { isCompatEnabled } = require('@playwright/test/lib/server/compat');3const { test, expect } = require('@playwright/test');4test('Test', async ({ page }) => {5 const isCompat = isCompatEnabled(page);6 expect(isCompat).toBe(false);7});8const { test, expect } = require('@playwright/test');9test('Test', async ({ page }) => {10 const isCompat = page.isCompatEnabled();11 expect(isCompat).toBe(true);12});13### `isCompatEnabled(page: Page): boolean`14### `page.isCompatEnabled(): boolean`15- [Playwright](
Using AI Code Generation
1const { isCompatEnabled } = require('@playwright/test/lib/server/compat');2const { isCompatEnabled } = require('@playwright/test/lib/server/compat');3const { test, expect } = require('@playwright/test');4test('test', async ({ page }) => {5 await page.click('text=Get started');6 await page.click('text=Docs');7 await page.click('text=API');8 await page.click('text=
Using AI Code Generation
1const { isCompatEnabled } = require('playwright/lib/server/chromium/crBrowser');2const browser = await chromium.launch();3const page = await browser.newPage();4const isCompat = isCompatEnabled(page);5await browser.close();6const { chromium } = require('playwright');7(async () => {8 const browser = await chromium.launch();9 const context = await browser.newContext();10 const page = await context.newPage();11 await context.close();12})();13- **geolocation** <[Object]> An object which specifies `latitude` (required) and `longitude` (required),
Using AI Code Generation
1const { isCompatEnabled } = require("playwright/lib/server/browserContext");2console.log(isCompatEnabled());3const { isCompatEnabled } = require("playwright/lib/server/browserContext");4console.log(isCompatEnabled());5const { isCompatEnabled } = require("playwright/lib/server/browserContext");6console.log(isCompatEnabled());7const { isCompatEnabled } = require("playwright/lib/server/browserContext");8console.log(isCompatEnabled());9const { isCompatEnabled } = require("playwright/lib/server/browserContext");10console.log(isCompatEnabled());11const { isCompatEnabled } = require("playwright/lib/server/browserContext");12console.log(isCompatEnabled());13const { isCompatEnabled } = require("playwright/lib/server/browserContext");14console.log(isCompatEnabled());
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!