How to use isCompatEnabled method in Playwright Internal

Best JavaScript code snippet using playwright-internal

vendor-node_modules_r.js

Source:vendor-node_modules_r.js Github

copy

Full Screen

...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 }...

Full Screen

Full Screen

runtime-dom.esm-browser.js

Source:runtime-dom.esm-browser.js Github

copy

Full Screen

...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)) {...

Full Screen

Full Screen

dep-56143c31.js

Source:dep-56143c31.js Github

copy

Full Screen

...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 }...

Full Screen

Full Screen

compiler-dom.global.js

Source:compiler-dom.global.js Github

copy

Full Screen

...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 }...

Full Screen

Full Screen

compiler-core.cjs.js

Source:compiler-core.cjs.js Github

copy

Full Screen

...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 }...

Full Screen

Full Screen

compiler-core.cjs.prod.js

Source:compiler-core.cjs.prod.js Github

copy

Full Screen

...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 }...

Full Screen

Full Screen

compiler-dom.esm-browser.js

Source:compiler-dom.esm-browser.js Github

copy

Full Screen

...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 }...

Full Screen

Full Screen

compiler-core.esm-bundler.js

Source:compiler-core.esm-bundler.js Github

copy

Full Screen

...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 }...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

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)

Full Screen

Using AI Code Generation

copy

Full Screen

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})();

Full Screen

Using AI Code Generation

copy

Full Screen

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](

Full Screen

Using AI Code Generation

copy

Full Screen

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](

Full Screen

Using AI Code Generation

copy

Full Screen

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=

Full Screen

Using AI Code Generation

copy

Full Screen

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),

Full Screen

Using AI Code Generation

copy

Full Screen

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());

Full Screen

Playwright tutorial

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.

Chapters:

  1. What is Playwright : Playwright is comparatively new but has gained good popularity. Get to know some history of the Playwright with some interesting facts connected with it.
  2. How To Install Playwright : Learn in detail about what basic configuration and dependencies are required for installing Playwright and run a test. Get a step-by-step direction for installing the Playwright automation framework.
  3. Playwright Futuristic Features: Launched in 2020, Playwright gained huge popularity quickly because of some obliging features such as Playwright Test Generator and Inspector, Playwright Reporter, Playwright auto-waiting mechanism and etc. Read up on those features to master Playwright testing.
  4. What is Component Testing: Component testing in Playwright is a unique feature that allows a tester to test a single component of a web application without integrating them with other elements. Learn how to perform Component testing on the Playwright automation framework.
  5. Inputs And Buttons In Playwright: Every website has Input boxes and buttons; learn about testing inputs and buttons with different scenarios and examples.
  6. Functions and Selectors in Playwright: Learn how to launch the Chromium browser with Playwright. Also, gain a better understanding of some important functions like “BrowserContext,” which allows you to run multiple browser sessions, and “newPage” which interacts with a page.
  7. Handling Alerts and Dropdowns in Playwright : Playwright interact with different types of alerts and pop-ups, such as simple, confirmation, and prompt, and different types of dropdowns, such as single selector and multi-selector get your hands-on with handling alerts and dropdown in Playright testing.
  8. Playwright vs Puppeteer: Get to know about the difference between two testing frameworks and how they are different than one another, which browsers they support, and what features they provide.
  9. Run Playwright Tests on LambdaTest: Playwright testing with LambdaTest leverages test performance to the utmost. You can run multiple Playwright tests in Parallel with the LammbdaTest test cloud. Get a step-by-step guide to run your Playwright test on the LambdaTest platform.
  10. Playwright Python Tutorial: Playwright automation framework support all major languages such as Python, JavaScript, TypeScript, .NET and etc. However, there are various advantages to Python end-to-end testing with Playwright because of its versatile utility. Get the hang of Playwright python testing with this chapter.
  11. Playwright End To End Testing Tutorial: Get your hands on with Playwright end-to-end testing and learn to use some exciting features such as TraceViewer, Debugging, Networking, Component testing, Visual testing, and many more.
  12. Playwright Video Tutorial: Watch the video tutorials on Playwright testing from experts and get a consecutive in-depth explanation of Playwright automation testing.

Run Playwright Internal automation tests on LambdaTest cloud grid

Perform automation testing on 3000+ real desktop and mobile devices online.

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful