Best JavaScript code snippet using playwright-internal
compiler-dom.global.js
Source:compiler-dom.global.js
...425 else {426 node.arguments[1] = propsWithInjection;427 }428 }429 function toValidAssetId(name, type) {430 return `_${type}_${name.replace(/[^\w]/g, '_')}`;431 }432 // Check if a node contains expressions that reference current context scope ids433 function hasScopeRef(node, ids) {434 if (!node || Object.keys(ids).length === 0) {435 return false;436 }437 switch (node.type) {438 case 1 /* ELEMENT */:439 for (let i = 0; i < node.props.length; i++) {440 const p = node.props[i];441 if (p.type === 7 /* DIRECTIVE */ &&442 (hasScopeRef(p.arg, ids) || hasScopeRef(p.exp, ids))) {443 return true;444 }445 }446 return node.children.some(c => hasScopeRef(c, ids));447 case 11 /* FOR */:448 if (hasScopeRef(node.source, ids)) {449 return true;450 }451 return node.children.some(c => hasScopeRef(c, ids));452 case 9 /* IF */:453 return node.branches.some(b => hasScopeRef(b, ids));454 case 10 /* IF_BRANCH */:455 if (hasScopeRef(node.condition, ids)) {456 return true;457 }458 return node.children.some(c => hasScopeRef(c, ids));459 case 4 /* SIMPLE_EXPRESSION */:460 return (!node.isStatic &&461 isSimpleIdentifier(node.content) &&462 !!ids[node.content]);463 case 8 /* COMPOUND_EXPRESSION */:464 return node.children.some(c => isObject(c) && hasScopeRef(c, ids));465 case 5 /* INTERPOLATION */:466 case 12 /* TEXT_CALL */:467 return hasScopeRef(node.content, ids);468 case 2 /* TEXT */:469 case 3 /* COMMENT */:470 return false;471 default:472 return false;473 }474 }475 const defaultParserOptions = {476 delimiters: [`{{`, `}}`],477 getNamespace: () => 0 /* HTML */,478 getTextMode: () => 0 /* DATA */,479 isVoidTag: NO,480 isPreTag: NO,481 isCustomElement: NO,482 namedCharacterReferences: {483 'gt;': '>',484 'lt;': '<',485 'amp;': '&',486 'apos;': "'",487 'quot;': '"'488 },489 onError: defaultOnError490 };491 function parse(content, options = {}) {492 const context = createParserContext(content, options);493 const start = getCursor(context);494 return {495 type: 0 /* ROOT */,496 children: parseChildren(context, 0 /* DATA */, []),497 helpers: [],498 components: [],499 directives: [],500 hoists: [],501 cached: 0,502 codegenNode: undefined,503 loc: getSelection(context, start)504 };505 }506 function createParserContext(content, options) {507 return {508 options: {509 ...defaultParserOptions,510 ...options511 },512 column: 1,513 line: 1,514 offset: 0,515 originalSource: content,516 source: content,517 maxCRNameLength: Object.keys(options.namedCharacterReferences ||518 defaultParserOptions.namedCharacterReferences).reduce((max, name) => Math.max(max, name.length), 0),519 inPre: false520 };521 }522 function parseChildren(context, mode, ancestors) {523 const parent = last(ancestors);524 const ns = parent ? parent.ns : 0 /* HTML */;525 const nodes = [];526 while (!isEnd(context, mode, ancestors)) {527 assert(context.source.length > 0);528 const s = context.source;529 let node = undefined;530 if (!context.inPre && startsWith(s, context.options.delimiters[0])) {531 // '{{'532 node = parseInterpolation(context, mode);533 }534 else if (mode === 0 /* DATA */ && s[0] === '<') {535 // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state536 if (s.length === 1) {537 emitError(context, 8 /* EOF_BEFORE_TAG_NAME */, 1);538 }539 else if (s[1] === '!') {540 // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state541 if (startsWith(s, '<!--')) {542 node = parseComment(context);543 }544 else if (startsWith(s, '<!DOCTYPE')) {545 // Ignore DOCTYPE by a limitation.546 node = parseBogusComment(context);547 }548 else if (startsWith(s, '<![CDATA[')) {549 if (ns !== 0 /* HTML */) {550 node = parseCDATA(context, ancestors);551 }552 else {553 emitError(context, 2 /* CDATA_IN_HTML_CONTENT */);554 node = parseBogusComment(context);555 }556 }557 else {558 emitError(context, 14 /* INCORRECTLY_OPENED_COMMENT */);559 node = parseBogusComment(context);560 }561 }562 else if (s[1] === '/') {563 // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state564 if (s.length === 2) {565 emitError(context, 8 /* EOF_BEFORE_TAG_NAME */, 2);566 }567 else if (s[2] === '>') {568 emitError(context, 17 /* MISSING_END_TAG_NAME */, 2);569 advanceBy(context, 3);570 continue;571 }572 else if (/[a-z]/i.test(s[2])) {573 emitError(context, 31 /* X_INVALID_END_TAG */);574 parseTag(context, 1 /* End */, parent);575 continue;576 }577 else {578 emitError(context, 15 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 2);579 node = parseBogusComment(context);580 }581 }582 else if (/[a-z]/i.test(s[1])) {583 node = parseElement(context, ancestors);584 }585 else if (s[1] === '?') {586 emitError(context, 28 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */, 1);587 node = parseBogusComment(context);588 }589 else {590 emitError(context, 15 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 1);591 }592 }593 if (!node) {594 node = parseText(context, mode);595 }596 if (Array.isArray(node)) {597 for (let i = 0; i < node.length; i++) {598 pushNode(nodes, node[i]);599 }600 }601 else {602 pushNode(nodes, node);603 }604 }605 // Whitespace management for more efficient output606 // (same as v2 whitespance: 'condense')607 let removedWhitespace = false;608 if (!parent || !context.options.isPreTag(parent.tag)) {609 for (let i = 0; i < nodes.length; i++) {610 const node = nodes[i];611 if (node.type === 2 /* TEXT */) {612 if (!node.content.trim()) {613 const prev = nodes[i - 1];614 const next = nodes[i + 1];615 // If:616 // - the whitespace is the first or last node, or:617 // - the whitespace is adjacent to a comment, or:618 // - the whitespace is between two elements AND contains newline619 // Then the whitespace is ignored.620 if (!prev ||621 !next ||622 prev.type === 3 /* COMMENT */ ||623 next.type === 3 /* COMMENT */ ||624 (prev.type === 1 /* ELEMENT */ &&625 next.type === 1 /* ELEMENT */ &&626 /[\r\n]/.test(node.content))) {627 removedWhitespace = true;628 nodes[i] = null;629 }630 else {631 // Otherwise, condensed consecutive whitespace inside the text down to632 // a single space633 node.content = ' ';634 }635 }636 else {637 node.content = node.content.replace(/\s+/g, ' ');638 }639 }640 }641 }642 return removedWhitespace ? nodes.filter(node => node !== null) : nodes;643 }644 function pushNode(nodes, node) {645 if (node.type === 2 /* TEXT */) {646 const prev = last(nodes);647 // Merge if both this and the previous node are text and those are648 // consecutive. This happens for cases like "a < b".649 if (prev &&650 prev.type === 2 /* TEXT */ &&651 prev.loc.end.offset === node.loc.start.offset) {652 prev.content += node.content;653 prev.loc.end = node.loc.end;654 prev.loc.source += node.loc.source;655 return;656 }657 }658 nodes.push(node);659 }660 function parseCDATA(context, ancestors) {661 662 assert(last(ancestors) == null || last(ancestors).ns !== 0 /* HTML */);663 assert(startsWith(context.source, '<![CDATA['));664 advanceBy(context, 9);665 const nodes = parseChildren(context, 3 /* CDATA */, ancestors);666 if (context.source.length === 0) {667 emitError(context, 9 /* EOF_IN_CDATA */);668 }669 else {670 assert(startsWith(context.source, ']]>'));671 advanceBy(context, 3);672 }673 return nodes;674 }675 function parseComment(context) {676 assert(startsWith(context.source, '<!--'));677 const start = getCursor(context);678 let content;679 // Regular comment.680 const match = /--(\!)?>/.exec(context.source);681 if (!match) {682 content = context.source.slice(4);683 advanceBy(context, context.source.length);684 emitError(context, 10 /* EOF_IN_COMMENT */);685 }686 else {687 if (match.index <= 3) {688 emitError(context, 0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */);689 }690 if (match[1]) {691 emitError(context, 13 /* INCORRECTLY_CLOSED_COMMENT */);692 }693 content = context.source.slice(4, match.index);694 // Advancing with reporting nested comments.695 const s = context.source.slice(0, match.index);696 let prevIndex = 1, nestedIndex = 0;697 while ((nestedIndex = s.indexOf('<!--', prevIndex)) !== -1) {698 advanceBy(context, nestedIndex - prevIndex + 1);699 if (nestedIndex + 4 < s.length) {700 emitError(context, 20 /* NESTED_COMMENT */);701 }702 prevIndex = nestedIndex + 1;703 }704 advanceBy(context, match.index + match[0].length - prevIndex + 1);705 }706 return {707 type: 3 /* COMMENT */,708 content,709 loc: getSelection(context, start)710 };711 }712 function parseBogusComment(context) {713 assert(/^<(?:[\!\?]|\/[^a-z>])/i.test(context.source));714 const start = getCursor(context);715 const contentStart = context.source[1] === '?' ? 1 : 2;716 let content;717 const closeIndex = context.source.indexOf('>');718 if (closeIndex === -1) {719 content = context.source.slice(contentStart);720 advanceBy(context, context.source.length);721 }722 else {723 content = context.source.slice(contentStart, closeIndex);724 advanceBy(context, closeIndex + 1);725 }726 return {727 type: 3 /* COMMENT */,728 content,729 loc: getSelection(context, start)730 };731 }732 function parseElement(context, ancestors) {733 assert(/^<[a-z]/i.test(context.source));734 // Start tag.735 const wasInPre = context.inPre;736 const parent = last(ancestors);737 const element = parseTag(context, 0 /* Start */, parent);738 const isPreBoundary = context.inPre && !wasInPre;739 if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {740 return element;741 }742 // Children.743 ancestors.push(element);744 const mode = context.options.getTextMode(element.tag, element.ns);745 const children = parseChildren(context, mode, ancestors);746 ancestors.pop();747 element.children = children;748 // End tag.749 if (startsWithEndTagOpen(context.source, element.tag)) {750 parseTag(context, 1 /* End */, parent);751 }752 else {753 emitError(context, 32 /* X_MISSING_END_TAG */);754 if (context.source.length === 0 && element.tag.toLowerCase() === 'script') {755 const first = children[0];756 if (first && startsWith(first.loc.source, '<!--')) {757 emitError(context, 11 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */);758 }759 }760 }761 element.loc = getSelection(context, element.loc.start);762 if (isPreBoundary) {763 context.inPre = false;764 }765 return element;766 }767 /**768 * Parse a tag (E.g. `<div id=a>`) with that type (start tag or end tag).769 */770 function parseTag(context, type, parent) {771 assert(/^<\/?[a-z]/i.test(context.source));772 773 assert(type === (startsWith(context.source, '</') ? 1 /* End */ : 0 /* Start */));774 // Tag open.775 const start = getCursor(context);776 const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source);777 const tag = match[1];778 const ns = context.options.getNamespace(tag, parent);779 advanceBy(context, match[0].length);780 advanceSpaces(context);781 // save current state in case we need to re-parse attributes with v-pre782 const cursor = getCursor(context);783 const currentSource = context.source;784 // Attributes.785 let props = parseAttributes(context, type);786 // check v-pre787 if (!context.inPre &&788 props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'pre')) {789 context.inPre = true;790 // reset context791 extend(context, cursor);792 context.source = currentSource;793 // re-parse attrs and filter out v-pre itself794 props = parseAttributes(context, type).filter(p => p.name !== 'v-pre');795 }796 // Tag close.797 let isSelfClosing = false;798 if (context.source.length === 0) {799 emitError(context, 12 /* EOF_IN_TAG */);800 }801 else {802 isSelfClosing = startsWith(context.source, '/>');803 if (type === 1 /* End */ && isSelfClosing) {804 emitError(context, 7 /* END_TAG_WITH_TRAILING_SOLIDUS */);805 }806 advanceBy(context, isSelfClosing ? 2 : 1);807 }808 let tagType = 0 /* ELEMENT */;809 if (!context.inPre && !context.options.isCustomElement(tag)) {810 if (context.options.isNativeTag) {811 if (!context.options.isNativeTag(tag))812 tagType = 1 /* COMPONENT */;813 }814 else {815 if (/^[A-Z]/.test(tag))816 tagType = 1 /* COMPONENT */;817 }818 if (tag === 'slot')819 tagType = 2 /* SLOT */;820 else if (tag === 'template')821 tagType = 3 /* TEMPLATE */;822 else if (tag === 'portal' || tag === 'Portal')823 tagType = 4 /* PORTAL */;824 else if (tag === 'suspense' || tag === 'Suspense')825 tagType = 5 /* SUSPENSE */;826 }827 return {828 type: 1 /* ELEMENT */,829 ns,830 tag,831 tagType,832 props,833 isSelfClosing,834 children: [],835 loc: getSelection(context, start),836 codegenNode: undefined // to be created during transform phase837 };838 }839 function parseAttributes(context, type) {840 const props = [];841 const attributeNames = new Set();842 while (context.source.length > 0 &&843 !startsWith(context.source, '>') &&844 !startsWith(context.source, '/>')) {845 if (startsWith(context.source, '/')) {846 emitError(context, 29 /* UNEXPECTED_SOLIDUS_IN_TAG */);847 advanceBy(context, 1);848 advanceSpaces(context);849 continue;850 }851 if (type === 1 /* End */) {852 emitError(context, 6 /* END_TAG_WITH_ATTRIBUTES */);853 }854 const attr = parseAttribute(context, attributeNames);855 if (type === 0 /* Start */) {856 props.push(attr);857 }858 if (/^[^\t\r\n\f />]/.test(context.source)) {859 emitError(context, 19 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */);860 }861 advanceSpaces(context);862 }863 return props;864 }865 function parseAttribute(context, nameSet) {866 assert(/^[^\t\r\n\f />]/.test(context.source));867 // Name.868 const start = getCursor(context);869 const match = /^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(context.source);870 const name = match[0];871 if (nameSet.has(name)) {872 emitError(context, 5 /* DUPLICATE_ATTRIBUTE */);873 }874 nameSet.add(name);875 if (name[0] === '=') {876 emitError(context, 26 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */);877 }878 {879 const pattern = /["'<]/g;880 let m;881 while ((m = pattern.exec(name)) !== null) {882 emitError(context, 24 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */, m.index);883 }884 }885 advanceBy(context, name.length);886 // Value887 let value = undefined;888 if (/^[\t\r\n\f ]*=/.test(context.source)) {889 advanceSpaces(context);890 advanceBy(context, 1);891 advanceSpaces(context);892 value = parseAttributeValue(context);893 if (!value) {894 emitError(context, 16 /* MISSING_ATTRIBUTE_VALUE */);895 }896 }897 const loc = getSelection(context, start);898 if (!context.inPre && /^(v-|:|@|#)/.test(name)) {899 const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^@|^#)([^\.]+))?(.+)?$/i.exec(name);900 let arg;901 if (match[2]) {902 const startOffset = name.split(match[2], 2).shift().length;903 const loc = getSelection(context, getNewPosition(context, start, startOffset), getNewPosition(context, start, startOffset + match[2].length));904 let content = match[2];905 let isStatic = true;906 if (content.startsWith('[')) {907 isStatic = false;908 if (!content.endsWith(']')) {909 emitError(context, 34 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */);910 }911 content = content.substr(1, content.length - 2);912 }913 arg = {914 type: 4 /* SIMPLE_EXPRESSION */,915 content,916 isStatic,917 isConstant: isStatic,918 loc919 };920 }921 if (value && value.isQuoted) {922 const valueLoc = value.loc;923 valueLoc.start.offset++;924 valueLoc.start.column++;925 valueLoc.end = advancePositionWithClone(valueLoc.start, value.content);926 valueLoc.source = valueLoc.source.slice(1, -1);927 }928 return {929 type: 7 /* DIRECTIVE */,930 name: match[1] ||931 (startsWith(name, ':')932 ? 'bind'933 : startsWith(name, '@')934 ? 'on'935 : 'slot'),936 exp: value && {937 type: 4 /* SIMPLE_EXPRESSION */,938 content: value.content,939 isStatic: false,940 // Treat as non-constant by default. This can be potentially set to941 // true by `transformExpression` to make it eligible for hoisting.942 isConstant: false,943 loc: value.loc944 },945 arg,946 modifiers: match[3] ? match[3].substr(1).split('.') : [],947 loc948 };949 }950 return {951 type: 6 /* ATTRIBUTE */,952 name,953 value: value && {954 type: 2 /* TEXT */,955 content: value.content,956 loc: value.loc957 },958 loc959 };960 }961 function parseAttributeValue(context) {962 const start = getCursor(context);963 let content;964 const quote = context.source[0];965 const isQuoted = quote === `"` || quote === `'`;966 if (isQuoted) {967 // Quoted value.968 advanceBy(context, 1);969 const endIndex = context.source.indexOf(quote);970 if (endIndex === -1) {971 content = parseTextData(context, context.source.length, 4 /* ATTRIBUTE_VALUE */);972 }973 else {974 content = parseTextData(context, endIndex, 4 /* ATTRIBUTE_VALUE */);975 advanceBy(context, 1);976 }977 }978 else {979 // Unquoted980 const match = /^[^\t\r\n\f >]+/.exec(context.source);981 if (!match) {982 return undefined;983 }984 let unexpectedChars = /["'<=`]/g;985 let m;986 while ((m = unexpectedChars.exec(match[0])) !== null) {987 emitError(context, 25 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */, m.index);988 }989 content = parseTextData(context, match[0].length, 4 /* ATTRIBUTE_VALUE */);990 }991 return { content, isQuoted, loc: getSelection(context, start) };992 }993 function parseInterpolation(context, mode) {994 const [open, close] = context.options.delimiters;995 assert(startsWith(context.source, open));996 const closeIndex = context.source.indexOf(close, open.length);997 if (closeIndex === -1) {998 emitError(context, 33 /* X_MISSING_INTERPOLATION_END */);999 return undefined;1000 }1001 const start = getCursor(context);1002 advanceBy(context, open.length);1003 const innerStart = getCursor(context);1004 const innerEnd = getCursor(context);1005 const rawContentLength = closeIndex - open.length;1006 const rawContent = context.source.slice(0, rawContentLength);1007 const preTrimContent = parseTextData(context, rawContentLength, mode);1008 const content = preTrimContent.trim();1009 const startOffset = preTrimContent.indexOf(content);1010 if (startOffset > 0) {1011 advancePositionWithMutation(innerStart, rawContent, startOffset);1012 }1013 const endOffset = rawContentLength - (preTrimContent.length - content.length - startOffset);1014 advancePositionWithMutation(innerEnd, rawContent, endOffset);1015 advanceBy(context, close.length);1016 return {1017 type: 5 /* INTERPOLATION */,1018 content: {1019 type: 4 /* SIMPLE_EXPRESSION */,1020 isStatic: false,1021 // Set `isConstant` to false by default and will decide in transformExpression1022 isConstant: false,1023 content,1024 loc: getSelection(context, innerStart, innerEnd)1025 },1026 loc: getSelection(context, start)1027 };1028 }1029 function parseText(context, mode) {1030 assert(context.source.length > 0);1031 const [open] = context.options.delimiters;1032 // TODO could probably use some perf optimization1033 const endIndex = Math.min(...[1034 context.source.indexOf('<', 1),1035 context.source.indexOf(open, 1),1036 mode === 3 /* CDATA */ ? context.source.indexOf(']]>') : -1,1037 context.source.length1038 ].filter(n => n !== -1));1039 assert(endIndex > 0);1040 const start = getCursor(context);1041 const content = parseTextData(context, endIndex, mode);1042 return {1043 type: 2 /* TEXT */,1044 content,1045 loc: getSelection(context, start)1046 };1047 }1048 /**1049 * Get text data with a given length from the current location.1050 * This translates HTML entities in the text data.1051 */1052 function parseTextData(context, length, mode) {1053 if (mode === 2 /* RAWTEXT */ || mode === 3 /* CDATA */) {1054 const text = context.source.slice(0, length);1055 advanceBy(context, length);1056 return text;1057 }1058 // DATA or RCDATA. Entity decoding required.1059 const end = context.offset + length;1060 let text = '';1061 while (context.offset < end) {1062 const head = /&(?:#x?)?/i.exec(context.source);1063 if (!head || context.offset + head.index >= end) {1064 const remaining = end - context.offset;1065 text += context.source.slice(0, remaining);1066 advanceBy(context, remaining);1067 break;1068 }1069 // Advance to the "&".1070 text += context.source.slice(0, head.index);1071 advanceBy(context, head.index);1072 if (head[0] === '&') {1073 // Named character reference.1074 let name = '', value = undefined;1075 if (/[0-9a-z]/i.test(context.source[1])) {1076 for (let length = context.maxCRNameLength; !value && length > 0; --length) {1077 name = context.source.substr(1, length);1078 value = context.options.namedCharacterReferences[name];1079 }1080 if (value) {1081 const semi = name.endsWith(';');1082 if (mode === 4 /* ATTRIBUTE_VALUE */ &&1083 !semi &&1084 /[=a-z0-9]/i.test(context.source[1 + name.length] || '')) {1085 text += '&';1086 text += name;1087 advanceBy(context, 1 + name.length);1088 }1089 else {1090 text += value;1091 advanceBy(context, 1 + name.length);1092 if (!semi) {1093 emitError(context, 18 /* MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE */);1094 }1095 }1096 }1097 else {1098 emitError(context, 30 /* UNKNOWN_NAMED_CHARACTER_REFERENCE */);1099 text += '&';1100 text += name;1101 advanceBy(context, 1 + name.length);1102 }1103 }1104 else {1105 text += '&';1106 advanceBy(context, 1);1107 }1108 }1109 else {1110 // Numeric character reference.1111 const hex = head[0] === '&#x';1112 const pattern = hex ? /^&#x([0-9a-f]+);?/i : /^&#([0-9]+);?/;1113 const body = pattern.exec(context.source);1114 if (!body) {1115 text += head[0];1116 emitError(context, 1 /* ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE */);1117 advanceBy(context, head[0].length);1118 }1119 else {1120 // https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state1121 let cp = Number.parseInt(body[1], hex ? 16 : 10);1122 if (cp === 0) {1123 emitError(context, 22 /* NULL_CHARACTER_REFERENCE */);1124 cp = 0xfffd;1125 }1126 else if (cp > 0x10ffff) {1127 emitError(context, 3 /* CHARACTER_REFERENCE_OUTSIDE_UNICODE_RANGE */);1128 cp = 0xfffd;1129 }1130 else if (cp >= 0xd800 && cp <= 0xdfff) {1131 emitError(context, 23 /* SURROGATE_CHARACTER_REFERENCE */);1132 cp = 0xfffd;1133 }1134 else if ((cp >= 0xfdd0 && cp <= 0xfdef) || (cp & 0xfffe) === 0xfffe) {1135 emitError(context, 21 /* NONCHARACTER_CHARACTER_REFERENCE */);1136 }1137 else if ((cp >= 0x01 && cp <= 0x08) ||1138 cp === 0x0b ||1139 (cp >= 0x0d && cp <= 0x1f) ||1140 (cp >= 0x7f && cp <= 0x9f)) {1141 emitError(context, 4 /* CONTROL_CHARACTER_REFERENCE */);1142 cp = CCR_REPLACEMENTS[cp] || cp;1143 }1144 text += String.fromCodePoint(cp);1145 advanceBy(context, body[0].length);1146 if (!body[0].endsWith(';')) {1147 emitError(context, 18 /* MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE */);1148 }1149 }1150 }1151 }1152 return text;1153 }1154 function getCursor(context) {1155 const { column, line, offset } = context;1156 return { column, line, offset };1157 }1158 function getSelection(context, start, end) {1159 end = end || getCursor(context);1160 return {1161 start,1162 end,1163 source: context.originalSource.slice(start.offset, end.offset)1164 };1165 }1166 function last(xs) {1167 return xs[xs.length - 1];1168 }1169 function startsWith(source, searchString) {1170 return source.startsWith(searchString);1171 }1172 function advanceBy(context, numberOfCharacters) {1173 const { source } = context;1174 assert(numberOfCharacters <= source.length);1175 advancePositionWithMutation(context, source, numberOfCharacters);1176 context.source = source.slice(numberOfCharacters);1177 }1178 function advanceSpaces(context) {1179 const match = /^[\t\r\n\f ]+/.exec(context.source);1180 if (match) {1181 advanceBy(context, match[0].length);1182 }1183 }1184 function getNewPosition(context, start, numberOfCharacters) {1185 return advancePositionWithClone(start, context.originalSource.slice(start.offset, numberOfCharacters), numberOfCharacters);1186 }1187 function emitError(context, code, offset) {1188 const loc = getCursor(context);1189 if (offset) {1190 loc.offset += offset;1191 loc.column += offset;1192 }1193 context.options.onError(createCompilerError(code, {1194 start: loc,1195 end: loc,1196 source: ''1197 }));1198 }1199 function isEnd(context, mode, ancestors) {1200 const s = context.source;1201 switch (mode) {1202 case 0 /* DATA */:1203 if (startsWith(s, '</')) {1204 //TODO: probably bad performance1205 for (let i = ancestors.length - 1; i >= 0; --i) {1206 if (startsWithEndTagOpen(s, ancestors[i].tag)) {1207 return true;1208 }1209 }1210 }1211 break;1212 case 1 /* RCDATA */:1213 case 2 /* RAWTEXT */: {1214 const parent = last(ancestors);1215 if (parent && startsWithEndTagOpen(s, parent.tag)) {1216 return true;1217 }1218 break;1219 }1220 case 3 /* CDATA */:1221 if (startsWith(s, ']]>')) {1222 return true;1223 }1224 break;1225 }1226 return !s;1227 }1228 function startsWithEndTagOpen(source, tag) {1229 return (startsWith(source, '</') &&1230 source.substr(2, tag.length).toLowerCase() === tag.toLowerCase() &&1231 /[\t\n\f />]/.test(source[2 + tag.length] || '>'));1232 }1233 // https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state1234 const CCR_REPLACEMENTS = {1235 0x80: 0x20ac,1236 0x82: 0x201a,1237 0x83: 0x0192,1238 0x84: 0x201e,1239 0x85: 0x2026,1240 0x86: 0x2020,1241 0x87: 0x2021,1242 0x88: 0x02c6,1243 0x89: 0x2030,1244 0x8a: 0x0160,1245 0x8b: 0x2039,1246 0x8c: 0x0152,1247 0x8e: 0x017d,1248 0x91: 0x2018,1249 0x92: 0x2019,1250 0x93: 0x201c,1251 0x94: 0x201d,1252 0x95: 0x2022,1253 0x96: 0x2013,1254 0x97: 0x2014,1255 0x98: 0x02dc,1256 0x99: 0x2122,1257 0x9a: 0x0161,1258 0x9b: 0x203a,1259 0x9c: 0x0153,1260 0x9e: 0x017e,1261 0x9f: 0x01781262 };1263 function hoistStatic(root, context) {1264 walk(root.children, context, new Map(), isSingleElementRoot(root, root.children[0]));1265 }1266 function isSingleElementRoot(root, child) {1267 const { children } = root;1268 return (children.length === 1 &&1269 child.type === 1 /* ELEMENT */ &&1270 !isSlotOutlet(child));1271 }1272 function walk(children, context, resultCache, doNotHoistNode = false) {1273 for (let i = 0; i < children.length; i++) {1274 const child = children[i];1275 // only plain elements are eligible for hoisting.1276 if (child.type === 1 /* ELEMENT */ &&1277 child.tagType === 0 /* ELEMENT */) {1278 if (!doNotHoistNode && isStaticNode(child, resultCache)) {1279 // whole tree is static1280 child.codegenNode = context.hoist(child.codegenNode);1281 continue;1282 }1283 else {1284 // node may contain dynamic children, but its props may be eligible for1285 // hoisting.1286 const codegenNode = child.codegenNode;1287 if (codegenNode.type === 13 /* JS_CALL_EXPRESSION */) {1288 const flag = getPatchFlag(codegenNode);1289 if ((!flag ||1290 flag === 32 /* NEED_PATCH */ ||1291 flag === 1 /* TEXT */) &&1292 !hasDynamicKeyOrRef(child) &&1293 !hasCachedProps()) {1294 const props = getNodeProps(child);1295 if (props && props !== `null`) {1296 getVNodeCall(codegenNode).arguments[1] = context.hoist(props);1297 }1298 }1299 }1300 }1301 }1302 if (child.type === 1 /* ELEMENT */) {1303 walk(child.children, context, resultCache);1304 }1305 else if (child.type === 11 /* FOR */) {1306 // Do not hoist v-for single child because it has to be a block1307 walk(child.children, context, resultCache, child.children.length === 1);1308 }1309 else if (child.type === 9 /* IF */) {1310 for (let i = 0; i < child.branches.length; i++) {1311 const branchChildren = child.branches[i].children;1312 // Do not hoist v-if single child because it has to be a block1313 walk(branchChildren, context, resultCache, branchChildren.length === 1);1314 }1315 }1316 }1317 }1318 function isStaticNode(node, resultCache = new Map()) {1319 switch (node.type) {1320 case 1 /* ELEMENT */:1321 if (node.tagType !== 0 /* ELEMENT */) {1322 return false;1323 }1324 const cached = resultCache.get(node);1325 if (cached !== undefined) {1326 return cached;1327 }1328 const codegenNode = node.codegenNode;1329 if (codegenNode.type !== 13 /* JS_CALL_EXPRESSION */) {1330 return false;1331 }1332 const flag = getPatchFlag(codegenNode);1333 if (!flag && !hasDynamicKeyOrRef(node) && !hasCachedProps()) {1334 // element self is static. check its children.1335 for (let i = 0; i < node.children.length; i++) {1336 if (!isStaticNode(node.children[i], resultCache)) {1337 resultCache.set(node, false);1338 return false;1339 }1340 }1341 resultCache.set(node, true);1342 return true;1343 }1344 else {1345 resultCache.set(node, false);1346 return false;1347 }1348 case 2 /* TEXT */:1349 case 3 /* COMMENT */:1350 return true;1351 case 9 /* IF */:1352 case 11 /* FOR */:1353 return false;1354 case 5 /* INTERPOLATION */:1355 case 12 /* TEXT_CALL */:1356 return isStaticNode(node.content, resultCache);1357 case 4 /* SIMPLE_EXPRESSION */:1358 return node.isConstant;1359 case 8 /* COMPOUND_EXPRESSION */:1360 return node.children.every(child => {1361 return (isString(child) || isSymbol(child) || isStaticNode(child, resultCache));1362 });1363 default:1364 return false;1365 }1366 }1367 function hasDynamicKeyOrRef(node) {1368 return !!(findProp(node, 'key', true) || findProp(node, 'ref', true));1369 }1370 function hasCachedProps(node) {1371 {1372 return false;1373 }1374 }1375 function getNodeProps(node) {1376 const codegenNode = node.codegenNode;1377 if (codegenNode.type === 13 /* JS_CALL_EXPRESSION */) {1378 return getVNodeArgAt(codegenNode, 1);1379 }1380 }1381 function getVNodeArgAt(node, index) {1382 return getVNodeCall(node).arguments[index];1383 }1384 function getVNodeCall(node) {1385 return node.callee === WITH_DIRECTIVES ? node.arguments[0] : node;1386 }1387 function getPatchFlag(node) {1388 const flag = getVNodeArgAt(node, 3);1389 return flag ? parseInt(flag, 10) : undefined;1390 }1391 function createTransformContext(root, { prefixIdentifiers = false, hoistStatic = false, cacheHandlers = false, nodeTransforms = [], directiveTransforms = {}, onError = defaultOnError }) {1392 const context = {1393 root,1394 helpers: new Set(),1395 components: new Set(),1396 directives: new Set(),1397 hoists: [],1398 cached: 0,1399 identifiers: {},1400 scopes: {1401 vFor: 0,1402 vSlot: 0,1403 vPre: 0,1404 vOnce: 01405 },1406 prefixIdentifiers,1407 hoistStatic,1408 cacheHandlers,1409 nodeTransforms,1410 directiveTransforms,1411 onError,1412 parent: null,1413 currentNode: root,1414 childIndex: 0,1415 helper(name) {1416 context.helpers.add(name);1417 return name;1418 },1419 helperString(name) {1420 return ((context.prefixIdentifiers ? `` : `_`) +1421 helperNameMap[context.helper(name)]);1422 },1423 replaceNode(node) {1424 /* istanbul ignore if */1425 {1426 if (!context.currentNode) {1427 throw new Error(`Node being replaced is already removed.`);1428 }1429 if (!context.parent) {1430 throw new Error(`Cannot replace root node.`);1431 }1432 }1433 context.parent.children[context.childIndex] = context.currentNode = node;1434 },1435 removeNode(node) {1436 if ( !context.parent) {1437 throw new Error(`Cannot remove root node.`);1438 }1439 const list = context.parent.children;1440 const removalIndex = node1441 ? list.indexOf(node)1442 : context.currentNode1443 ? context.childIndex1444 : -1;1445 /* istanbul ignore if */1446 if ( removalIndex < 0) {1447 throw new Error(`node being removed is not a child of current parent`);1448 }1449 if (!node || node === context.currentNode) {1450 // current node removed1451 context.currentNode = null;1452 context.onNodeRemoved();1453 }1454 else {1455 // sibling node removed1456 if (context.childIndex > removalIndex) {1457 context.childIndex--;1458 context.onNodeRemoved();1459 }1460 }1461 context.parent.children.splice(removalIndex, 1);1462 },1463 onNodeRemoved: () => { },1464 addIdentifiers(exp) {1465 },1466 removeIdentifiers(exp) {1467 },1468 hoist(exp) {1469 context.hoists.push(exp);1470 return createSimpleExpression(`_hoisted_${context.hoists.length}`, false, exp.loc, true);1471 },1472 cache(exp, isVNode = false) {1473 return createCacheExpression(++context.cached, exp, isVNode);1474 }1475 };1476 return context;1477 }1478 function transform(root, options) {1479 const context = createTransformContext(root, options);1480 traverseNode(root, context);1481 if (options.hoistStatic) {1482 hoistStatic(root, context);1483 }1484 finalizeRoot(root, context);1485 }1486 function finalizeRoot(root, context) {1487 const { helper } = context;1488 const { children } = root;1489 const child = children[0];1490 if (children.length === 1) {1491 // if the single child is an element, turn it into a block.1492 if (isSingleElementRoot(root, child) && child.codegenNode) {1493 // single element root is never hoisted so codegenNode will never be1494 // SimpleExpressionNode1495 const codegenNode = child.codegenNode;1496 if (codegenNode.type !== 20 /* JS_CACHE_EXPRESSION */) {1497 if (codegenNode.callee === WITH_DIRECTIVES) {1498 codegenNode.arguments[0].callee = helper(CREATE_BLOCK);1499 }1500 else {1501 codegenNode.callee = helper(CREATE_BLOCK);1502 }1503 root.codegenNode = createBlockExpression(codegenNode, context);1504 }1505 else {1506 root.codegenNode = codegenNode;1507 }1508 }1509 else {1510 // - single <slot/>, IfNode, ForNode: already blocks.1511 // - single text node: always patched.1512 // root codegen falls through via genNode()1513 root.codegenNode = child;1514 }1515 }1516 else if (children.length > 1) {1517 // root has multiple nodes - return a fragment block.1518 root.codegenNode = createBlockExpression(createCallExpression(helper(CREATE_BLOCK), [1519 helper(FRAGMENT),1520 `null`,1521 root.children1522 ]), context);1523 }1524 // finalize meta information1525 root.helpers = [...context.helpers];1526 root.components = [...context.components];1527 root.directives = [...context.directives];1528 root.hoists = context.hoists;1529 root.cached = context.cached;1530 }1531 function traverseChildren(parent, context) {1532 let i = 0;1533 const nodeRemoved = () => {1534 i--;1535 };1536 for (; i < parent.children.length; i++) {1537 const child = parent.children[i];1538 if (isString(child))1539 continue;1540 context.currentNode = child;1541 context.parent = parent;1542 context.childIndex = i;1543 context.onNodeRemoved = nodeRemoved;1544 traverseNode(child, context);1545 }1546 }1547 function traverseNode(node, context) {1548 // apply transform plugins1549 const { nodeTransforms } = context;1550 const exitFns = [];1551 for (let i = 0; i < nodeTransforms.length; i++) {1552 const onExit = nodeTransforms[i](node, context);1553 if (onExit) {1554 if (isArray(onExit)) {1555 exitFns.push(...onExit);1556 }1557 else {1558 exitFns.push(onExit);1559 }1560 }1561 if (!context.currentNode) {1562 // node was removed1563 return;1564 }1565 else {1566 // node may have been replaced1567 node = context.currentNode;1568 }1569 }1570 switch (node.type) {1571 case 3 /* COMMENT */:1572 // inject import for the Comment symbol, which is needed for creating1573 // comment nodes with `createVNode`1574 context.helper(CREATE_COMMENT);1575 break;1576 case 5 /* INTERPOLATION */:1577 // no need to traverse, but we need to inject toString helper1578 context.helper(TO_STRING);1579 break;1580 // for container types, further traverse downwards1581 case 9 /* IF */:1582 for (let i = 0; i < node.branches.length; i++) {1583 traverseChildren(node.branches[i], context);1584 }1585 break;1586 case 11 /* FOR */:1587 case 1 /* ELEMENT */:1588 case 0 /* ROOT */:1589 traverseChildren(node, context);1590 break;1591 }1592 // exit transforms1593 let i = exitFns.length;1594 while (i--) {1595 exitFns[i]();1596 }1597 }1598 function createStructuralDirectiveTransform(name, fn) {1599 const matches = isString(name)1600 ? (n) => n === name1601 : (n) => name.test(n);1602 return (node, context) => {1603 if (node.type === 1 /* ELEMENT */) {1604 const { props } = node;1605 // structural directive transforms are not concerned with slots1606 // as they are handled separately in vSlot.ts1607 if (node.tagType === 3 /* TEMPLATE */ && props.some(isVSlot)) {1608 return;1609 }1610 const exitFns = [];1611 for (let i = 0; i < props.length; i++) {1612 const prop = props[i];1613 if (prop.type === 7 /* DIRECTIVE */ && matches(prop.name)) {1614 // structural directives are removed to avoid infinite recursion1615 // also we remove them *before* applying so that it can further1616 // traverse itself in case it moves the node around1617 props.splice(i, 1);1618 i--;1619 const onExit = fn(node, prop, context);1620 if (onExit)1621 exitFns.push(onExit);1622 }1623 }1624 return exitFns;1625 }1626 };1627 }1628 function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap = false, filename = `template.vue.html` }) {1629 const context = {1630 mode,1631 prefixIdentifiers,1632 sourceMap,1633 filename,1634 source: ast.loc.source,1635 code: ``,1636 column: 1,1637 line: 1,1638 offset: 0,1639 indentLevel: 0,1640 // lazy require source-map implementation, only in non-browser builds!1641 map: undefined1642 ,1643 helper(key) {1644 const name = helperNameMap[key];1645 return prefixIdentifiers ? name : `_${name}`;1646 },1647 push(code, node, openOnly) {1648 context.code += code;1649 },1650 resetMapping(loc) {1651 },1652 indent() {1653 newline(++context.indentLevel);1654 },1655 deindent(withoutNewLine = false) {1656 if (withoutNewLine) {1657 --context.indentLevel;1658 }1659 else {1660 newline(--context.indentLevel);1661 }1662 },1663 newline() {1664 newline(context.indentLevel);1665 }1666 };1667 function newline(n) {1668 context.push('\n' + ` `.repeat(n));1669 }1670 return context;1671 }1672 function generate(ast, options = {}) {1673 const context = createCodegenContext(ast, options);1674 const { mode, push, helper, prefixIdentifiers, indent, deindent, newline } = context;1675 const hasHelpers = ast.helpers.length > 0;1676 const useWithBlock = !prefixIdentifiers && mode !== 'module';1677 // preambles1678 if (mode === 'function') {1679 // Generate const declaration for helpers1680 // In prefix mode, we place the const declaration at top so it's done1681 // only once; But if we not prefixing, we place the declaration inside the1682 // with block so it doesn't incur the `in` check cost for every helper access.1683 if (hasHelpers) {1684 if (prefixIdentifiers) {1685 push(`const { ${ast.helpers.map(helper).join(', ')} } = Vue\n`);1686 }1687 else {1688 // "with" mode.1689 // save Vue in a separate variable to avoid collision1690 push(`const _Vue = Vue\n`);1691 // in "with" mode, helpers are declared inside the with block to avoid1692 // has check cost, but hoists are lifted out of the function - we need1693 // to provide the helper here.1694 if (ast.hoists.length) {1695 push(`const _${helperNameMap[CREATE_VNODE]} = Vue.${helperNameMap[CREATE_VNODE]}\n`);1696 if (ast.helpers.includes(CREATE_COMMENT)) {1697 push(`const _${helperNameMap[CREATE_COMMENT]} = Vue.${helperNameMap[CREATE_COMMENT]}\n`);1698 }1699 }1700 }1701 }1702 genHoists(ast.hoists, context);1703 newline();1704 push(`return `);1705 }1706 else {1707 // generate import statements for helpers1708 if (hasHelpers) {1709 push(`import { ${ast.helpers.map(helper).join(', ')} } from "vue"\n`);1710 }1711 genHoists(ast.hoists, context);1712 newline();1713 push(`export default `);1714 }1715 // enter render function1716 push(`function render() {`);1717 indent();1718 if (useWithBlock) {1719 push(`with (this) {`);1720 indent();1721 // function mode const declarations should be inside with block1722 // also they should be renamed to avoid collision with user properties1723 if (hasHelpers) {1724 push(`const { ${ast.helpers1725 .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)1726 .join(', ')} } = _Vue`);1727 newline();1728 if (ast.cached > 0) {1729 push(`const _cache = $cache`);1730 newline();1731 }1732 newline();1733 }1734 }1735 else {1736 push(`const _ctx = this`);1737 if (ast.cached > 0) {1738 newline();1739 push(`const _cache = _ctx.$cache`);1740 }1741 newline();1742 }1743 // generate asset resolution statements1744 if (ast.components.length) {1745 genAssets(ast.components, 'component', context);1746 }1747 if (ast.directives.length) {1748 genAssets(ast.directives, 'directive', context);1749 }1750 if (ast.components.length || ast.directives.length) {1751 newline();1752 }1753 // generate the VNode tree expression1754 push(`return `);1755 if (ast.codegenNode) {1756 genNode(ast.codegenNode, context);1757 }1758 else {1759 push(`null`);1760 }1761 if (useWithBlock) {1762 deindent();1763 push(`}`);1764 }1765 deindent();1766 push(`}`);1767 return {1768 ast,1769 code: context.code,1770 map: undefined //context.map ? context.map.toJSON() : undefined1771 };1772 }1773 function genAssets(assets, type, context) {1774 const resolver = context.helper(type === 'component' ? RESOLVE_COMPONENT : RESOLVE_DIRECTIVE);1775 for (let i = 0; i < assets.length; i++) {1776 const id = assets[i];1777 context.push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)})`);1778 context.newline();1779 }1780 }1781 function genHoists(hoists, context) {1782 if (!hoists.length) {1783 return;1784 }1785 context.newline();1786 hoists.forEach((exp, i) => {1787 context.push(`const _hoisted_${i + 1} = `);1788 genNode(exp, context);1789 context.newline();1790 });1791 }1792 function isText(n) {1793 return (isString(n) ||1794 n.type === 4 /* SIMPLE_EXPRESSION */ ||1795 n.type === 2 /* TEXT */ ||1796 n.type === 5 /* INTERPOLATION */ ||1797 n.type === 8 /* COMPOUND_EXPRESSION */);1798 }1799 function genNodeListAsArray(nodes, context) {1800 const multilines = nodes.length > 3 ||1801 ( nodes.some(n => isArray(n) || !isText(n)));1802 context.push(`[`);1803 multilines && context.indent();1804 genNodeList(nodes, context, multilines);1805 multilines && context.deindent();1806 context.push(`]`);1807 }1808 function genNodeList(nodes, context, multilines = false) {1809 const { push, newline } = context;1810 for (let i = 0; i < nodes.length; i++) {1811 const node = nodes[i];1812 if (isString(node)) {1813 push(node);1814 }1815 else if (isArray(node)) {1816 genNodeListAsArray(node, context);1817 }1818 else {1819 genNode(node, context);1820 }1821 if (i < nodes.length - 1) {1822 if (multilines) {1823 push(',');1824 newline();1825 }1826 else {1827 push(', ');1828 }1829 }1830 }1831 }1832 function genNode(node, context) {1833 if (isString(node)) {1834 context.push(node);1835 return;1836 }1837 if (isSymbol(node)) {1838 context.push(context.helper(node));1839 return;1840 }1841 switch (node.type) {1842 case 1 /* ELEMENT */:1843 case 9 /* IF */:1844 case 11 /* FOR */:1845 1846 assert(node.codegenNode != null, `Codegen node is missing for element/if/for node. ` +1847 `Apply appropriate transforms first.`);1848 genNode(node.codegenNode, context);1849 break;1850 case 2 /* TEXT */:1851 genText(node, context);1852 break;1853 case 4 /* SIMPLE_EXPRESSION */:1854 genExpression(node, context);1855 break;1856 case 5 /* INTERPOLATION */:1857 genInterpolation(node, context);1858 break;1859 case 12 /* TEXT_CALL */:1860 genNode(node.codegenNode, context);1861 break;1862 case 8 /* COMPOUND_EXPRESSION */:1863 genCompoundExpression(node, context);1864 break;1865 case 3 /* COMMENT */:1866 genComment(node, context);1867 break;1868 case 13 /* JS_CALL_EXPRESSION */:1869 genCallExpression(node, context);1870 break;1871 case 14 /* JS_OBJECT_EXPRESSION */:1872 genObjectExpression(node, context);1873 break;1874 case 16 /* JS_ARRAY_EXPRESSION */:1875 genArrayExpression(node, context);1876 break;1877 case 17 /* JS_FUNCTION_EXPRESSION */:1878 genFunctionExpression(node, context);1879 break;1880 case 18 /* JS_SEQUENCE_EXPRESSION */:1881 genSequenceExpression(node, context);1882 break;1883 case 19 /* JS_CONDITIONAL_EXPRESSION */:1884 genConditionalExpression(node, context);1885 break;1886 case 20 /* JS_CACHE_EXPRESSION */:1887 genCacheExpression(node, context);1888 break;1889 /* istanbul ignore next */1890 default:1891 {1892 assert(false, `unhandled codegen node type: ${node.type}`);1893 // make sure we exhaust all possible types1894 const exhaustiveCheck = node;1895 return exhaustiveCheck;1896 }1897 }1898 }1899 function genText(node, context) {1900 context.push(JSON.stringify(node.content), node);1901 }1902 function genExpression(node, context) {1903 const { content, isStatic } = node;1904 context.push(isStatic ? JSON.stringify(content) : content, node);1905 }1906 function genInterpolation(node, context) {1907 const { push, helper } = context;1908 push(`${helper(TO_STRING)}(`);1909 genNode(node.content, context);1910 push(`)`);1911 }1912 function genCompoundExpression(node, context) {1913 for (let i = 0; i < node.children.length; i++) {1914 const child = node.children[i];1915 if (isString(child)) {1916 context.push(child);1917 }1918 else {1919 genNode(child, context);1920 }1921 }1922 }1923 function genExpressionAsPropertyKey(node, context) {1924 const { push } = context;1925 if (node.type === 8 /* COMPOUND_EXPRESSION */) {1926 push(`[`);1927 genCompoundExpression(node, context);1928 push(`]`);1929 }1930 else if (node.isStatic) {1931 // only quote keys if necessary1932 const text = isSimpleIdentifier(node.content)1933 ? node.content1934 : JSON.stringify(node.content);1935 push(text, node);1936 }1937 else {1938 push(`[${node.content}]`, node);1939 }1940 }1941 function genComment(node, context) {1942 {1943 const { push, helper } = context;1944 push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node);1945 }1946 }1947 // JavaScript1948 function genCallExpression(node, context) {1949 const callee = isString(node.callee)1950 ? node.callee1951 : context.helper(node.callee);1952 context.push(callee + `(`, node, true);1953 genNodeList(node.arguments, context);1954 context.push(`)`);1955 }1956 function genObjectExpression(node, context) {1957 const { push, indent, deindent, newline, resetMapping } = context;1958 const { properties } = node;1959 if (!properties.length) {1960 push(`{}`, node);1961 return;1962 }1963 const multilines = properties.length > 1 ||1964 (1965 properties.some(p => p.value.type !== 4 /* SIMPLE_EXPRESSION */));1966 push(multilines ? `{` : `{ `);1967 multilines && indent();1968 for (let i = 0; i < properties.length; i++) {1969 const { key, value, loc } = properties[i];1970 resetMapping(loc); // reset source mapping for every property.1971 // key1972 genExpressionAsPropertyKey(key, context);1973 push(`: `);1974 // value1975 genNode(value, context);1976 if (i < properties.length - 1) {1977 // will only reach this if it's multilines1978 push(`,`);1979 newline();1980 }1981 }1982 multilines && deindent();1983 const lastChar = context.code[context.code.length - 1];1984 push(multilines || /[\])}]/.test(lastChar) ? `}` : ` }`);1985 }1986 function genArrayExpression(node, context) {1987 genNodeListAsArray(node.elements, context);1988 }1989 function genFunctionExpression(node, context) {1990 const { push, indent, deindent } = context;1991 const { params, returns, newline } = node;1992 push(`(`, node);1993 if (isArray(params)) {1994 genNodeList(params, context);1995 }1996 else if (params) {1997 genNode(params, context);1998 }1999 push(`) => `);2000 if (newline) {2001 push(`{`);2002 indent();2003 push(`return `);2004 }2005 if (isArray(returns)) {2006 genNodeListAsArray(returns, context);2007 }2008 else {2009 genNode(returns, context);2010 }2011 if (newline) {2012 deindent();2013 push(`}`);2014 }2015 }2016 function genConditionalExpression(node, context) {2017 const { test, consequent, alternate } = node;2018 const { push, indent, deindent, newline } = context;2019 if (test.type === 4 /* SIMPLE_EXPRESSION */) {2020 const needsParens = !isSimpleIdentifier(test.content);2021 needsParens && push(`(`);2022 genExpression(test, context);2023 needsParens && push(`)`);2024 }2025 else {2026 push(`(`);2027 genCompoundExpression(test, context);2028 push(`)`);2029 }2030 indent();2031 context.indentLevel++;2032 push(`? `);2033 genNode(consequent, context);2034 context.indentLevel--;2035 newline();2036 push(`: `);2037 const isNested = alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */;2038 if (!isNested) {2039 context.indentLevel++;2040 }2041 genNode(alternate, context);2042 if (!isNested) {2043 context.indentLevel--;2044 }2045 deindent(true /* without newline */);2046 }2047 function genSequenceExpression(node, context) {2048 context.push(`(`);2049 genNodeList(node.expressions, context);2050 context.push(`)`);2051 }2052 function genCacheExpression(node, context) {2053 const { push, helper, indent, deindent, newline } = context;2054 push(`_cache[${node.index}] || (`);2055 if (node.isVNode) {2056 indent();2057 push(`${helper(SET_BLOCK_TRACKING)}(-1),`);2058 newline();2059 }2060 push(`_cache[${node.index}] = `);2061 genNode(node.value, context);2062 if (node.isVNode) {2063 push(`,`);2064 newline();2065 push(`${helper(SET_BLOCK_TRACKING)}(1),`);2066 newline();2067 push(`_cache[${node.index}]`);2068 deindent();2069 }2070 push(`)`);2071 }2072 const transformIf = createStructuralDirectiveTransform(/^(if|else|else-if)$/, (node, dir, context) => {2073 if (dir.name !== 'else' &&2074 (!dir.exp || !dir.exp.content.trim())) {2075 const loc = dir.exp ? dir.exp.loc : node.loc;2076 context.onError(createCompilerError(35 /* X_V_IF_NO_EXPRESSION */, dir.loc));2077 dir.exp = createSimpleExpression(`true`, false, loc);2078 }2079 if (dir.name === 'if') {2080 const branch = createIfBranch(node, dir);2081 const codegenNode = createSequenceExpression([2082 createCallExpression(context.helper(OPEN_BLOCK))2083 ]);2084 context.replaceNode({2085 type: 9 /* IF */,2086 loc: node.loc,2087 branches: [branch],2088 codegenNode2089 });2090 // Exit callback. Complete the codegenNode when all children have been2091 // transformed.2092 return () => {2093 codegenNode.expressions.push(createCodegenNodeForBranch(branch, 0, context));2094 };2095 }2096 else {2097 // locate the adjacent v-if2098 const siblings = context.parent.children;2099 const comments = [];2100 let i = siblings.indexOf(node);2101 while (i-- >= -1) {2102 const sibling = siblings[i];2103 if ( sibling && sibling.type === 3 /* COMMENT */) {2104 context.removeNode(sibling);2105 comments.unshift(sibling);2106 continue;2107 }2108 if (sibling && sibling.type === 9 /* IF */) {2109 // move the node to the if node's branches2110 context.removeNode();2111 const branch = createIfBranch(node, dir);2112 if ( comments.length) {2113 branch.children = [...comments, ...branch.children];2114 }2115 sibling.branches.push(branch);2116 // since the branch was removed, it will not be traversed.2117 // make sure to traverse here.2118 traverseChildren(branch, context);2119 // make sure to reset currentNode after traversal to indicate this2120 // node has been removed.2121 context.currentNode = null;2122 // attach this branch's codegen node to the v-if root.2123 let parentCondition = sibling.codegenNode2124 .expressions[1];2125 while (true) {2126 if (parentCondition.alternate.type ===2127 19 /* JS_CONDITIONAL_EXPRESSION */) {2128 parentCondition = parentCondition.alternate;2129 }2130 else {2131 parentCondition.alternate = createCodegenNodeForBranch(branch, sibling.branches.length - 1, context);2132 break;2133 }2134 }2135 }2136 else {2137 context.onError(createCompilerError(36 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));2138 }2139 break;2140 }2141 }2142 });2143 function createIfBranch(node, dir) {2144 return {2145 type: 10 /* IF_BRANCH */,2146 loc: node.loc,2147 condition: dir.name === 'else' ? undefined : dir.exp,2148 children: node.tagType === 3 /* TEMPLATE */ ? node.children : [node]2149 };2150 }2151 function createCodegenNodeForBranch(branch, index, context) {2152 if (branch.condition) {2153 return createConditionalExpression(branch.condition, createChildrenCodegenNode(branch, index, context), 2154 // make sure to pass in asBlock: true so that the comment node call2155 // closes the current block.2156 createCallExpression(context.helper(CREATE_COMMENT), [2157 '"v-if"' ,2158 'true'2159 ]));2160 }2161 else {2162 return createChildrenCodegenNode(branch, index, context);2163 }2164 }2165 function createChildrenCodegenNode(branch, index, context) {2166 const { helper } = context;2167 const keyProperty = createObjectProperty(`key`, createSimpleExpression(index + '', false));2168 const { children } = branch;2169 const child = children[0];2170 const needFragmentWrapper = children.length !== 1 || child.type !== 1 /* ELEMENT */;2171 if (needFragmentWrapper) {2172 const blockArgs = [2173 helper(FRAGMENT),2174 createObjectExpression([keyProperty]),2175 children2176 ];2177 if (children.length === 1 && child.type === 11 /* FOR */) {2178 // optimize away nested fragments when child is a ForNode2179 const forBlockArgs = child.codegenNode.expressions[1].arguments;2180 // directly use the for block's children and patchFlag2181 blockArgs[2] = forBlockArgs[2];2182 blockArgs[3] = forBlockArgs[3];2183 }2184 return createCallExpression(helper(CREATE_BLOCK), blockArgs);2185 }2186 else {2187 const childCodegen = child.codegenNode;2188 let vnodeCall = childCodegen;2189 // Element with custom directives. Locate the actual createVNode() call.2190 if (vnodeCall.callee === WITH_DIRECTIVES) {2191 vnodeCall = vnodeCall.arguments[0];2192 }2193 // Change createVNode to createBlock.2194 if (vnodeCall.callee === CREATE_VNODE) {2195 vnodeCall.callee = helper(CREATE_BLOCK);2196 }2197 // inject branch key2198 injectProp(vnodeCall, keyProperty, context);2199 return childCodegen;2200 }2201 }2202 const transformFor = createStructuralDirectiveTransform('for', (node, dir, context) => {2203 if (!dir.exp) {2204 context.onError(createCompilerError(37 /* X_V_FOR_NO_EXPRESSION */, dir.loc));2205 return;2206 }2207 const parseResult = parseForExpression(2208 // can only be simple expression because vFor transform is applied2209 // before expression transform.2210 dir.exp);2211 if (!parseResult) {2212 context.onError(createCompilerError(38 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));2213 return;2214 }2215 const { helper, addIdentifiers, removeIdentifiers, scopes } = context;2216 const { source, value, key, index } = parseResult;2217 // create the loop render function expression now, and add the2218 // iterator on exit after all children have been traversed2219 const renderExp = createCallExpression(helper(RENDER_LIST), [source]);2220 const keyProp = findProp(node, `key`);2221 const fragmentFlag = keyProp2222 ? 64 /* KEYED_FRAGMENT */2223 : 128 /* UNKEYED_FRAGMENT */;2224 const codegenNode = createSequenceExpression([2225 // fragment blocks disable tracking since they always diff their children2226 createCallExpression(helper(OPEN_BLOCK), [`false`]),2227 createCallExpression(helper(CREATE_BLOCK), [2228 helper(FRAGMENT),2229 `null`,2230 renderExp,2231 fragmentFlag + ( ` /* ${PatchFlagNames[fragmentFlag]} */` )2232 ])2233 ]);2234 context.replaceNode({2235 type: 11 /* FOR */,2236 loc: dir.loc,2237 source,2238 valueAlias: value,2239 keyAlias: key,2240 objectIndexAlias: index,2241 children: node.tagType === 3 /* TEMPLATE */ ? node.children : [node],2242 codegenNode2243 });2244 // bookkeeping2245 scopes.vFor++;2246 return () => {2247 scopes.vFor--;2248 // finish the codegen now that all children have been traversed2249 let childBlock;2250 const isTemplate = isTemplateNode(node);2251 const slotOutlet = isSlotOutlet(node)2252 ? node2253 : isTemplate &&2254 node.children.length === 1 &&2255 isSlotOutlet(node.children[0])2256 ? node.children[0] // api-extractor somehow fails to infer this2257 : null;2258 const keyProperty = keyProp2259 ? createObjectProperty(`key`, keyProp.type === 6 /* ATTRIBUTE */2260 ? createSimpleExpression(keyProp.value.content, true)2261 : keyProp.exp)2262 : null;2263 if (slotOutlet) {2264 // <slot v-for="..."> or <template v-for="..."><slot/></template>2265 childBlock = slotOutlet.codegenNode;2266 if (isTemplate && keyProperty) {2267 // <template v-for="..." :key="..."><slot/></template>2268 // we need to inject the key to the renderSlot() call.2269 // the props for renderSlot is passed as the 3rd argument.2270 injectProp(childBlock, keyProperty, context);2271 }2272 }2273 else if (isTemplate) {2274 // <template v-for="...">2275 // should generate a fragment block for each loop2276 childBlock = createBlockExpression(createCallExpression(helper(CREATE_BLOCK), [2277 helper(FRAGMENT),2278 keyProperty ? createObjectExpression([keyProperty]) : `null`,2279 node.children2280 ]), context);2281 }2282 else {2283 // Normal element v-for. Directly use the child's codegenNode2284 // arguments, but replace createVNode() with createBlock()2285 let codegenNode = node.codegenNode;2286 if (codegenNode.callee === WITH_DIRECTIVES) {2287 codegenNode.arguments[0].callee = helper(CREATE_BLOCK);2288 }2289 else {2290 codegenNode.callee = helper(CREATE_BLOCK);2291 }2292 childBlock = createBlockExpression(codegenNode, context);2293 }2294 renderExp.arguments.push(createFunctionExpression(createForLoopParams(parseResult), childBlock, true /* force newline */));2295 };2296 });2297 const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;2298 // This regex doesn't cover the case if key or index aliases have destructuring,2299 // but those do not make sense in the first place, so this works in practice.2300 const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;2301 const stripParensRE = /^\(|\)$/g;2302 function parseForExpression(input, context) {2303 const loc = input.loc;2304 const exp = input.content;2305 const inMatch = exp.match(forAliasRE);2306 if (!inMatch)2307 return;2308 const [, LHS, RHS] = inMatch;2309 const result = {2310 source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),2311 value: undefined,2312 key: undefined,2313 index: undefined2314 };2315 let valueContent = LHS.trim()2316 .replace(stripParensRE, '')2317 .trim();2318 const trimmedOffset = LHS.indexOf(valueContent);2319 const iteratorMatch = valueContent.match(forIteratorRE);2320 if (iteratorMatch) {2321 valueContent = valueContent.replace(forIteratorRE, '').trim();2322 const keyContent = iteratorMatch[1].trim();2323 let keyOffset;2324 if (keyContent) {2325 keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);2326 result.key = createAliasExpression(loc, keyContent, keyOffset);2327 }2328 if (iteratorMatch[2]) {2329 const indexContent = iteratorMatch[2].trim();2330 if (indexContent) {2331 result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key2332 ? keyOffset + keyContent.length2333 : trimmedOffset + valueContent.length));2334 }2335 }2336 }2337 if (valueContent) {2338 result.value = createAliasExpression(loc, valueContent, trimmedOffset);2339 }2340 return result;2341 }2342 function createAliasExpression(range, content, offset) {2343 return createSimpleExpression(content, false, getInnerRange(range, offset, content.length));2344 }2345 function createForLoopParams({ value, key, index }) {2346 const params = [];2347 if (value) {2348 params.push(value);2349 }2350 if (key) {2351 if (!value) {2352 params.push(createSimpleExpression(`_`, false));2353 }2354 params.push(key);2355 }2356 if (index) {2357 if (!key) {2358 if (!value) {2359 params.push(createSimpleExpression(`_`, false));2360 }2361 params.push(createSimpleExpression(`__`, false));2362 }2363 params.push(index);2364 }2365 return params;2366 }2367 const isStaticExp = (p) => p.type === 4 /* SIMPLE_EXPRESSION */ && p.isStatic;2368 const defaultFallback = createSimpleExpression(`undefined`, false);2369 // A NodeTransform that:2370 // 1. Tracks scope identifiers for scoped slots so that they don't get prefixed2371 // by transformExpression. This is only applied in non-browser builds with2372 // { prefixIdentifiers: true }.2373 // 2. Track v-slot depths so that we know a slot is inside another slot.2374 // Note the exit callback is executed before buildSlots() on the same node,2375 // so only nested slots see positive numbers.2376 const trackSlotScopes = (node, context) => {2377 if (node.type === 1 /* ELEMENT */ &&2378 (node.tagType === 1 /* COMPONENT */ ||2379 node.tagType === 3 /* TEMPLATE */)) {2380 // We are only checking non-empty v-slot here2381 // since we only care about slots that introduce scope variables.2382 const vSlot = findDir(node, 'slot');2383 if (vSlot) {2384 const slotProps = vSlot.exp;2385 context.scopes.vSlot++;2386 return () => {2387 context.scopes.vSlot--;2388 };2389 }2390 }2391 };2392 // Instead of being a DirectiveTransform, v-slot processing is called during2393 // transformElement to build the slots object for a component.2394 function buildSlots(node, context) {2395 const { children, loc } = node;2396 const slotsProperties = [];2397 const dynamicSlots = [];2398 // If the slot is inside a v-for or another v-slot, force it to be dynamic2399 // since it likely uses a scope variable.2400 let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0;2401 // 1. Check for default slot with slotProps on component itself.2402 // <Comp v-slot="{ prop }"/>2403 const explicitDefaultSlot = findDir(node, 'slot', true);2404 if (explicitDefaultSlot) {2405 const { arg, exp, loc } = explicitDefaultSlot;2406 if (arg) {2407 context.onError(createCompilerError(42 /* X_V_SLOT_NAMED_SLOT_ON_COMPONENT */, loc));2408 }2409 slotsProperties.push(buildDefaultSlot(exp, children, loc));2410 }2411 // 2. Iterate through children and check for template slots2412 // <template v-slot:foo="{ prop }">2413 let hasTemplateSlots = false;2414 let extraneousChild = undefined;2415 const seenSlotNames = new Set();2416 for (let i = 0; i < children.length; i++) {2417 const slotElement = children[i];2418 let slotDir;2419 if (!isTemplateNode(slotElement) ||2420 !(slotDir = findDir(slotElement, 'slot', true))) {2421 // not a <template v-slot>, skip.2422 if (slotElement.type !== 3 /* COMMENT */ && !extraneousChild) {2423 extraneousChild = slotElement;2424 }2425 continue;2426 }2427 if (explicitDefaultSlot) {2428 // already has on-component default slot - this is incorrect usage.2429 context.onError(createCompilerError(43 /* X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc));2430 break;2431 }2432 hasTemplateSlots = true;2433 const { children: slotChildren, loc: slotLoc } = slotElement;2434 const { arg: slotName = createSimpleExpression(`default`, true), exp: slotProps, loc: dirLoc } = slotDir;2435 // check if name is dynamic.2436 let staticSlotName;2437 if (isStaticExp(slotName)) {2438 staticSlotName = slotName ? slotName.content : `default`;2439 }2440 else {2441 hasDynamicSlots = true;2442 }2443 const slotFunction = createFunctionExpression(slotProps, slotChildren, false, slotChildren.length ? slotChildren[0].loc : slotLoc);2444 // check if this slot is conditional (v-if/v-for)2445 let vIf;2446 let vElse;2447 let vFor;2448 if ((vIf = findDir(slotElement, 'if'))) {2449 hasDynamicSlots = true;2450 dynamicSlots.push(createConditionalExpression(vIf.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback));2451 }2452 else if ((vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))) {2453 // find adjacent v-if2454 let j = i;2455 let prev;2456 while (j--) {2457 prev = children[j];2458 if (prev.type !== 3 /* COMMENT */) {2459 break;2460 }2461 }2462 if (prev && isTemplateNode(prev) && findDir(prev, 'if')) {2463 // remove node2464 children.splice(i, 1);2465 i--;2466 assert(dynamicSlots.length > 0);2467 // attach this slot to previous conditional2468 let conditional = dynamicSlots[dynamicSlots.length - 1];2469 while (conditional.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {2470 conditional = conditional.alternate;2471 }2472 conditional.alternate = vElse.exp2473 ? createConditionalExpression(vElse.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback)2474 : buildDynamicSlot(slotName, slotFunction);2475 }2476 else {2477 context.onError(createCompilerError(36 /* X_V_ELSE_NO_ADJACENT_IF */, vElse.loc));2478 }2479 }2480 else if ((vFor = findDir(slotElement, 'for'))) {2481 hasDynamicSlots = true;2482 const parseResult = vFor.parseResult ||2483 parseForExpression(vFor.exp);2484 if (parseResult) {2485 // Render the dynamic slots as an array and add it to the createSlot()2486 // args. The runtime knows how to handle it appropriately.2487 dynamicSlots.push(createCallExpression(context.helper(RENDER_LIST), [2488 parseResult.source,2489 createFunctionExpression(createForLoopParams(parseResult), buildDynamicSlot(slotName, slotFunction), true)2490 ]));2491 }2492 else {2493 context.onError(createCompilerError(38 /* X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc));2494 }2495 }2496 else {2497 // check duplicate static names2498 if (staticSlotName) {2499 if (seenSlotNames.has(staticSlotName)) {2500 context.onError(createCompilerError(44 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc));2501 continue;2502 }2503 seenSlotNames.add(staticSlotName);2504 }2505 slotsProperties.push(createObjectProperty(slotName, slotFunction));2506 }2507 }2508 if (hasTemplateSlots && extraneousChild) {2509 context.onError(createCompilerError(45 /* X_V_SLOT_EXTRANEOUS_NON_SLOT_CHILDREN */, extraneousChild.loc));2510 }2511 if (!explicitDefaultSlot && !hasTemplateSlots) {2512 // implicit default slot.2513 slotsProperties.push(buildDefaultSlot(undefined, children, loc));2514 }2515 let slots = createObjectExpression(slotsProperties.concat(createObjectProperty(`_compiled`, createSimpleExpression(`true`, false))), loc);2516 if (dynamicSlots.length) {2517 slots = createCallExpression(context.helper(CREATE_SLOTS), [2518 slots,2519 createArrayExpression(dynamicSlots)2520 ]);2521 }2522 return {2523 slots,2524 hasDynamicSlots2525 };2526 }2527 function buildDefaultSlot(slotProps, children, loc) {2528 return createObjectProperty(`default`, createFunctionExpression(slotProps, children, false, children.length ? children[0].loc : loc));2529 }2530 function buildDynamicSlot(name, fn) {2531 return createObjectExpression([2532 createObjectProperty(`name`, name),2533 createObjectProperty(`fn`, fn)2534 ]);2535 }2536 // some directive transforms (e.g. v-model) may return a symbol for runtime2537 // import, which should be used instead of a resolveDirective call.2538 const directiveImportMap = new WeakMap();2539 // generate a JavaScript AST for this element's codegen2540 const transformElement = (node, context) => {2541 if (node.type !== 1 /* ELEMENT */ ||2542 // handled by transformSlotOutlet2543 node.tagType === 2 /* SLOT */ ||2544 // <template v-if/v-for> should have already been replaced2545 // <templte v-slot> is handled by buildSlots2546 (node.tagType === 3 /* TEMPLATE */ && node.props.some(isVSlot))) {2547 return;2548 }2549 // perform the work on exit, after all child expressions have been2550 // processed and merged.2551 return () => {2552 const isComponent = node.tagType === 1 /* COMPONENT */;2553 let hasProps = node.props.length > 0;2554 let patchFlag = 0;2555 let runtimeDirectives;2556 let dynamicPropNames;2557 let dynamicComponent;2558 // handle dynamic component2559 const isProp = findProp(node, 'is');2560 if (node.tag === 'component') {2561 if (isProp) {2562 // static <component is="foo" />2563 if (isProp.type === 6 /* ATTRIBUTE */) {2564 const tag = isProp.value && isProp.value.content;2565 if (tag) {2566 context.helper(RESOLVE_COMPONENT);2567 context.components.add(tag);2568 dynamicComponent = toValidAssetId(tag, `component`);2569 }2570 }2571 // dynamic <component :is="asdf" />2572 else if (isProp.exp) {2573 dynamicComponent = createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [isProp.exp]);2574 }2575 }2576 }2577 if (isComponent && !dynamicComponent) {2578 context.helper(RESOLVE_COMPONENT);2579 context.components.add(node.tag);2580 }2581 const args = [2582 dynamicComponent2583 ? dynamicComponent2584 : isComponent2585 ? toValidAssetId(node.tag, `component`)2586 : node.tagType === 4 /* PORTAL */2587 ? context.helper(PORTAL)2588 : node.tagType === 5 /* SUSPENSE */2589 ? context.helper(SUSPENSE)2590 : `"${node.tag}"`2591 ];2592 // props2593 if (hasProps) {2594 const propsBuildResult = buildProps(node, context, 2595 // skip reserved "is" prop <component is>2596 node.props.filter(p => p !== isProp));2597 patchFlag = propsBuildResult.patchFlag;2598 dynamicPropNames = propsBuildResult.dynamicPropNames;2599 runtimeDirectives = propsBuildResult.directives;2600 if (!propsBuildResult.props) {2601 hasProps = false;2602 }2603 else {2604 args.push(propsBuildResult.props);2605 }2606 }2607 // children2608 const hasChildren = node.children.length > 0;2609 if (hasChildren) {2610 if (!hasProps) {2611 args.push(`null`);2612 }2613 if (isComponent || node.tagType === 5 /* SUSPENSE */) {2614 const { slots, hasDynamicSlots } = buildSlots(node, context);2615 args.push(slots);2616 if (hasDynamicSlots) {2617 patchFlag |= 256 /* DYNAMIC_SLOTS */;2618 }2619 }2620 else if (node.children.length === 1) {2621 const child = node.children[0];2622 const type = child.type;2623 // check for dynamic text children2624 const hasDynamicTextChild = type === 5 /* INTERPOLATION */ ||2625 type === 8 /* COMPOUND_EXPRESSION */;2626 if (hasDynamicTextChild && !isStaticNode(child)) {2627 patchFlag |= 1 /* TEXT */;2628 }2629 // pass directly if the only child is a text node2630 // (plain / interpolation / expression)2631 if (hasDynamicTextChild || type === 2 /* TEXT */) {2632 args.push(child);2633 }2634 else {2635 args.push(node.children);2636 }2637 }2638 else {2639 args.push(node.children);2640 }2641 }2642 // patchFlag & dynamicPropNames2643 if (patchFlag !== 0) {2644 if (!hasChildren) {2645 if (!hasProps) {2646 args.push(`null`);2647 }2648 args.push(`null`);2649 }2650 {2651 const flagNames = Object.keys(PatchFlagNames)2652 .map(Number)2653 .filter(n => n > 0 && patchFlag & n)2654 .map(n => PatchFlagNames[n])2655 .join(`, `);2656 args.push(patchFlag + ` /* ${flagNames} */`);2657 }2658 if (dynamicPropNames && dynamicPropNames.length) {2659 args.push(`[${dynamicPropNames.map(n => JSON.stringify(n)).join(`, `)}]`);2660 }2661 }2662 const { loc } = node;2663 const vnode = createCallExpression(context.helper(CREATE_VNODE), args, loc);2664 if (runtimeDirectives && runtimeDirectives.length) {2665 node.codegenNode = createCallExpression(context.helper(WITH_DIRECTIVES), [2666 vnode,2667 createArrayExpression(runtimeDirectives.map(dir => buildDirectiveArgs(dir, context)), loc)2668 ], loc);2669 }2670 else {2671 node.codegenNode = vnode;2672 }2673 };2674 };2675 function buildProps(node, context, props = node.props) {2676 const elementLoc = node.loc;2677 const isComponent = node.tagType === 1 /* COMPONENT */;2678 let properties = [];2679 const mergeArgs = [];2680 const runtimeDirectives = [];2681 // patchFlag analysis2682 let patchFlag = 0;2683 let hasRef = false;2684 let hasClassBinding = false;2685 let hasStyleBinding = false;2686 let hasDynamicKeys = false;2687 const dynamicPropNames = [];2688 const analyzePatchFlag = ({ key, value }) => {2689 if (key.type === 4 /* SIMPLE_EXPRESSION */ && key.isStatic) {2690 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||2691 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||2692 value.type === 8 /* COMPOUND_EXPRESSION */) &&2693 isStaticNode(value))) {2694 return;2695 }2696 const name = key.content;2697 if (name === 'ref') {2698 hasRef = true;2699 }2700 else if (name === 'class') {2701 hasClassBinding = true;2702 }2703 else if (name === 'style') {2704 hasStyleBinding = true;2705 }2706 else if (name !== 'key') {2707 dynamicPropNames.push(name);2708 }2709 }2710 else {2711 hasDynamicKeys = true;2712 }2713 };2714 for (let i = 0; i < props.length; i++) {2715 // static attribute2716 const prop = props[i];2717 if (prop.type === 6 /* ATTRIBUTE */) {2718 const { loc, name, value } = prop;2719 if (name === 'ref') {2720 hasRef = true;2721 }2722 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', true, value ? value.loc : loc)));2723 }2724 else {2725 // directives2726 const { name, arg, exp, loc } = prop;2727 // skip v-slot - it is handled by its dedicated transform.2728 if (name === 'slot') {2729 if (!isComponent) {2730 context.onError(createCompilerError(46 /* X_V_SLOT_MISPLACED */, loc));2731 }2732 continue;2733 }2734 // skip v-once - it is handled by its dedicated transform.2735 if (name === 'once') {2736 continue;2737 }2738 // special case for v-bind and v-on with no argument2739 const isBind = name === 'bind';2740 const isOn = name === 'on';2741 if (!arg && (isBind || isOn)) {2742 hasDynamicKeys = true;2743 if (exp) {2744 if (properties.length) {2745 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));2746 properties = [];2747 }2748 if (isBind) {2749 mergeArgs.push(exp);2750 }2751 else {2752 // v-on="obj" -> toHandlers(obj)2753 mergeArgs.push({2754 type: 13 /* JS_CALL_EXPRESSION */,2755 loc,2756 callee: context.helper(TO_HANDLERS),2757 arguments: [exp]2758 });2759 }2760 }2761 else {2762 context.onError(createCompilerError(isBind2763 ? 39 /* X_V_BIND_NO_EXPRESSION */2764 : 40 /* X_V_ON_NO_EXPRESSION */, loc));2765 }2766 continue;2767 }2768 const directiveTransform = context.directiveTransforms[name];2769 if (directiveTransform) {2770 // has built-in directive transform.2771 const { props, needRuntime } = directiveTransform(prop, node, context);2772 props.forEach(analyzePatchFlag);2773 properties.push(...props);2774 if (needRuntime) {2775 runtimeDirectives.push(prop);2776 if (isSymbol(needRuntime)) {2777 directiveImportMap.set(prop, needRuntime);2778 }2779 }2780 }2781 else {2782 // no built-in transform, this is a user custom directive.2783 runtimeDirectives.push(prop);2784 }2785 }2786 }2787 let propsExpression = undefined;2788 // has v-bind="object" or v-on="object", wrap with mergeProps2789 if (mergeArgs.length) {2790 if (properties.length) {2791 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));2792 }2793 if (mergeArgs.length > 1) {2794 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);2795 }2796 else {2797 // single v-bind with nothing else - no need for a mergeProps call2798 propsExpression = mergeArgs[0];2799 }2800 }2801 else if (properties.length) {2802 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);2803 }2804 // patchFlag analysis2805 if (hasDynamicKeys) {2806 patchFlag |= 16 /* FULL_PROPS */;2807 }2808 else {2809 if (hasClassBinding) {2810 patchFlag |= 2 /* CLASS */;2811 }2812 if (hasStyleBinding) {2813 patchFlag |= 4 /* STYLE */;2814 }2815 if (dynamicPropNames.length) {2816 patchFlag |= 8 /* PROPS */;2817 }2818 }2819 if (patchFlag === 0 && (hasRef || runtimeDirectives.length > 0)) {2820 patchFlag |= 32 /* NEED_PATCH */;2821 }2822 return {2823 props: propsExpression,2824 directives: runtimeDirectives,2825 patchFlag,2826 dynamicPropNames2827 };2828 }2829 // Dedupe props in an object literal.2830 // Literal duplicated attributes would have been warned during the parse phase,2831 // however, it's possible to encounter duplicated `onXXX` handlers with different2832 // modifiers. We also need to merge static and dynamic class / style attributes.2833 // - onXXX handlers / style: merge into array2834 // - class: merge into single expression with concatenation2835 function dedupeProperties(properties) {2836 const knownProps = {};2837 const deduped = [];2838 for (let i = 0; i < properties.length; i++) {2839 const prop = properties[i];2840 // dynamic keys are always allowed2841 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {2842 deduped.push(prop);2843 continue;2844 }2845 const name = prop.key.content;2846 const existing = knownProps[name];2847 if (existing) {2848 if (name === 'style' ||2849 name === 'class' ||2850 name.startsWith('on') ||2851 name.startsWith('vnode')) {2852 mergeAsArray(existing, prop);2853 }2854 // unexpected duplicate, should have emitted error during parse2855 }2856 else {2857 knownProps[name] = prop;2858 deduped.push(prop);2859 }2860 }2861 return deduped;2862 }2863 function mergeAsArray(existing, incoming) {2864 if (existing.value.type === 16 /* JS_ARRAY_EXPRESSION */) {2865 existing.value.elements.push(incoming.value);2866 }2867 else {2868 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);2869 }2870 }2871 function buildDirectiveArgs(dir, context) {2872 const dirArgs = [];2873 const runtime = directiveImportMap.get(dir);2874 if (runtime) {2875 context.helper(runtime);2876 dirArgs.push(context.helperString(runtime));2877 }2878 else {2879 // inject statement for resolving directive2880 context.helper(RESOLVE_DIRECTIVE);2881 context.directives.add(dir.name);2882 dirArgs.push(toValidAssetId(dir.name, `directive`));2883 }2884 const { loc } = dir;2885 if (dir.exp)2886 dirArgs.push(dir.exp);2887 if (dir.arg) {2888 if (!dir.exp) {2889 dirArgs.push(`void 0`);2890 }2891 dirArgs.push(dir.arg);2892 }2893 if (Object.keys(dir.modifiers).length) {2894 if (!dir.arg) {2895 if (!dir.exp) {2896 dirArgs.push(`void 0`);...
compiler-core.cjs.js
Source:compiler-core.cjs.js
...429 else {430 node.arguments[1] = propsWithInjection;431 }432}433function toValidAssetId(name, type) {434 return `_${type}_${name.replace(/[^\w]/g, '_')}`;435}436// Check if a node contains expressions that reference current context scope ids437function hasScopeRef(node, ids) {438 if (!node || Object.keys(ids).length === 0) {439 return false;440 }441 switch (node.type) {442 case 1 /* ELEMENT */:443 for (let i = 0; i < node.props.length; i++) {444 const p = node.props[i];445 if (p.type === 7 /* DIRECTIVE */ &&446 (hasScopeRef(p.arg, ids) || hasScopeRef(p.exp, ids))) {447 return true;448 }449 }450 return node.children.some(c => hasScopeRef(c, ids));451 case 11 /* FOR */:452 if (hasScopeRef(node.source, ids)) {453 return true;454 }455 return node.children.some(c => hasScopeRef(c, ids));456 case 9 /* IF */:457 return node.branches.some(b => hasScopeRef(b, ids));458 case 10 /* IF_BRANCH */:459 if (hasScopeRef(node.condition, ids)) {460 return true;461 }462 return node.children.some(c => hasScopeRef(c, ids));463 case 4 /* SIMPLE_EXPRESSION */:464 return (!node.isStatic &&465 isSimpleIdentifier(node.content) &&466 !!ids[node.content]);467 case 8 /* COMPOUND_EXPRESSION */:468 return node.children.some(c => isObject(c) && hasScopeRef(c, ids));469 case 5 /* INTERPOLATION */:470 case 12 /* TEXT_CALL */:471 return hasScopeRef(node.content, ids);472 case 2 /* TEXT */:473 case 3 /* COMMENT */:474 return false;475 default:476 return false;477 }478}479const defaultParserOptions = {480 delimiters: [`{{`, `}}`],481 getNamespace: () => 0 /* HTML */,482 getTextMode: () => 0 /* DATA */,483 isVoidTag: NO,484 isPreTag: NO,485 isCustomElement: NO,486 namedCharacterReferences: {487 'gt;': '>',488 'lt;': '<',489 'amp;': '&',490 'apos;': "'",491 'quot;': '"'492 },493 onError: defaultOnError494};495function parse(content, options = {}) {496 const context = createParserContext(content, options);497 const start = getCursor(context);498 return {499 type: 0 /* ROOT */,500 children: parseChildren(context, 0 /* DATA */, []),501 helpers: [],502 components: [],503 directives: [],504 hoists: [],505 cached: 0,506 codegenNode: undefined,507 loc: getSelection(context, start)508 };509}510function createParserContext(content, options) {511 return {512 options: {513 ...defaultParserOptions,514 ...options515 },516 column: 1,517 line: 1,518 offset: 0,519 originalSource: content,520 source: content,521 maxCRNameLength: Object.keys(options.namedCharacterReferences ||522 defaultParserOptions.namedCharacterReferences).reduce((max, name) => Math.max(max, name.length), 0),523 inPre: false524 };525}526function parseChildren(context, mode, ancestors) {527 const parent = last(ancestors);528 const ns = parent ? parent.ns : 0 /* HTML */;529 const nodes = [];530 while (!isEnd(context, mode, ancestors)) {531 assert(context.source.length > 0);532 const s = context.source;533 let node = undefined;534 if (!context.inPre && startsWith(s, context.options.delimiters[0])) {535 // '{{'536 node = parseInterpolation(context, mode);537 }538 else if (mode === 0 /* DATA */ && s[0] === '<') {539 // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state540 if (s.length === 1) {541 emitError(context, 8 /* EOF_BEFORE_TAG_NAME */, 1);542 }543 else if (s[1] === '!') {544 // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state545 if (startsWith(s, '<!--')) {546 node = parseComment(context);547 }548 else if (startsWith(s, '<!DOCTYPE')) {549 // Ignore DOCTYPE by a limitation.550 node = parseBogusComment(context);551 }552 else if (startsWith(s, '<![CDATA[')) {553 if (ns !== 0 /* HTML */) {554 node = parseCDATA(context, ancestors);555 }556 else {557 emitError(context, 2 /* CDATA_IN_HTML_CONTENT */);558 node = parseBogusComment(context);559 }560 }561 else {562 emitError(context, 14 /* INCORRECTLY_OPENED_COMMENT */);563 node = parseBogusComment(context);564 }565 }566 else if (s[1] === '/') {567 // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state568 if (s.length === 2) {569 emitError(context, 8 /* EOF_BEFORE_TAG_NAME */, 2);570 }571 else if (s[2] === '>') {572 emitError(context, 17 /* MISSING_END_TAG_NAME */, 2);573 advanceBy(context, 3);574 continue;575 }576 else if (/[a-z]/i.test(s[2])) {577 emitError(context, 31 /* X_INVALID_END_TAG */);578 parseTag(context, 1 /* End */, parent);579 continue;580 }581 else {582 emitError(context, 15 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 2);583 node = parseBogusComment(context);584 }585 }586 else if (/[a-z]/i.test(s[1])) {587 node = parseElement(context, ancestors);588 }589 else if (s[1] === '?') {590 emitError(context, 28 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */, 1);591 node = parseBogusComment(context);592 }593 else {594 emitError(context, 15 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 1);595 }596 }597 if (!node) {598 node = parseText(context, mode);599 }600 if (Array.isArray(node)) {601 for (let i = 0; i < node.length; i++) {602 pushNode(nodes, node[i]);603 }604 }605 else {606 pushNode(nodes, node);607 }608 }609 // Whitespace management for more efficient output610 // (same as v2 whitespance: 'condense')611 let removedWhitespace = false;612 if (!parent || !context.options.isPreTag(parent.tag)) {613 for (let i = 0; i < nodes.length; i++) {614 const node = nodes[i];615 if (node.type === 2 /* TEXT */) {616 if (!node.content.trim()) {617 const prev = nodes[i - 1];618 const next = nodes[i + 1];619 // If:620 // - the whitespace is the first or last node, or:621 // - the whitespace is adjacent to a comment, or:622 // - the whitespace is between two elements AND contains newline623 // Then the whitespace is ignored.624 if (!prev ||625 !next ||626 prev.type === 3 /* COMMENT */ ||627 next.type === 3 /* COMMENT */ ||628 (prev.type === 1 /* ELEMENT */ &&629 next.type === 1 /* ELEMENT */ &&630 /[\r\n]/.test(node.content))) {631 removedWhitespace = true;632 nodes[i] = null;633 }634 else {635 // Otherwise, condensed consecutive whitespace inside the text down to636 // a single space637 node.content = ' ';638 }639 }640 else {641 node.content = node.content.replace(/\s+/g, ' ');642 }643 }644 }645 }646 return removedWhitespace ? nodes.filter(node => node !== null) : nodes;647}648function pushNode(nodes, node) {649 if (node.type === 2 /* TEXT */) {650 const prev = last(nodes);651 // Merge if both this and the previous node are text and those are652 // consecutive. This happens for cases like "a < b".653 if (prev &&654 prev.type === 2 /* TEXT */ &&655 prev.loc.end.offset === node.loc.start.offset) {656 prev.content += node.content;657 prev.loc.end = node.loc.end;658 prev.loc.source += node.loc.source;659 return;660 }661 }662 nodes.push(node);663}664function parseCDATA(context, ancestors) {665 666 assert(last(ancestors) == null || last(ancestors).ns !== 0 /* HTML */);667 assert(startsWith(context.source, '<![CDATA['));668 advanceBy(context, 9);669 const nodes = parseChildren(context, 3 /* CDATA */, ancestors);670 if (context.source.length === 0) {671 emitError(context, 9 /* EOF_IN_CDATA */);672 }673 else {674 assert(startsWith(context.source, ']]>'));675 advanceBy(context, 3);676 }677 return nodes;678}679function parseComment(context) {680 assert(startsWith(context.source, '<!--'));681 const start = getCursor(context);682 let content;683 // Regular comment.684 const match = /--(\!)?>/.exec(context.source);685 if (!match) {686 content = context.source.slice(4);687 advanceBy(context, context.source.length);688 emitError(context, 10 /* EOF_IN_COMMENT */);689 }690 else {691 if (match.index <= 3) {692 emitError(context, 0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */);693 }694 if (match[1]) {695 emitError(context, 13 /* INCORRECTLY_CLOSED_COMMENT */);696 }697 content = context.source.slice(4, match.index);698 // Advancing with reporting nested comments.699 const s = context.source.slice(0, match.index);700 let prevIndex = 1, nestedIndex = 0;701 while ((nestedIndex = s.indexOf('<!--', prevIndex)) !== -1) {702 advanceBy(context, nestedIndex - prevIndex + 1);703 if (nestedIndex + 4 < s.length) {704 emitError(context, 20 /* NESTED_COMMENT */);705 }706 prevIndex = nestedIndex + 1;707 }708 advanceBy(context, match.index + match[0].length - prevIndex + 1);709 }710 return {711 type: 3 /* COMMENT */,712 content,713 loc: getSelection(context, start)714 };715}716function parseBogusComment(context) {717 assert(/^<(?:[\!\?]|\/[^a-z>])/i.test(context.source));718 const start = getCursor(context);719 const contentStart = context.source[1] === '?' ? 1 : 2;720 let content;721 const closeIndex = context.source.indexOf('>');722 if (closeIndex === -1) {723 content = context.source.slice(contentStart);724 advanceBy(context, context.source.length);725 }726 else {727 content = context.source.slice(contentStart, closeIndex);728 advanceBy(context, closeIndex + 1);729 }730 return {731 type: 3 /* COMMENT */,732 content,733 loc: getSelection(context, start)734 };735}736function parseElement(context, ancestors) {737 assert(/^<[a-z]/i.test(context.source));738 // Start tag.739 const wasInPre = context.inPre;740 const parent = last(ancestors);741 const element = parseTag(context, 0 /* Start */, parent);742 const isPreBoundary = context.inPre && !wasInPre;743 if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {744 return element;745 }746 // Children.747 ancestors.push(element);748 const mode = context.options.getTextMode(element.tag, element.ns);749 const children = parseChildren(context, mode, ancestors);750 ancestors.pop();751 element.children = children;752 // End tag.753 if (startsWithEndTagOpen(context.source, element.tag)) {754 parseTag(context, 1 /* End */, parent);755 }756 else {757 emitError(context, 32 /* X_MISSING_END_TAG */);758 if (context.source.length === 0 && element.tag.toLowerCase() === 'script') {759 const first = children[0];760 if (first && startsWith(first.loc.source, '<!--')) {761 emitError(context, 11 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */);762 }763 }764 }765 element.loc = getSelection(context, element.loc.start);766 if (isPreBoundary) {767 context.inPre = false;768 }769 return element;770}771/**772 * Parse a tag (E.g. `<div id=a>`) with that type (start tag or end tag).773 */774function parseTag(context, type, parent) {775 assert(/^<\/?[a-z]/i.test(context.source));776 777 assert(type === (startsWith(context.source, '</') ? 1 /* End */ : 0 /* Start */));778 // Tag open.779 const start = getCursor(context);780 const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source);781 const tag = match[1];782 const ns = context.options.getNamespace(tag, parent);783 advanceBy(context, match[0].length);784 advanceSpaces(context);785 // save current state in case we need to re-parse attributes with v-pre786 const cursor = getCursor(context);787 const currentSource = context.source;788 // Attributes.789 let props = parseAttributes(context, type);790 // check v-pre791 if (!context.inPre &&792 props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'pre')) {793 context.inPre = true;794 // reset context795 extend(context, cursor);796 context.source = currentSource;797 // re-parse attrs and filter out v-pre itself798 props = parseAttributes(context, type).filter(p => p.name !== 'v-pre');799 }800 // Tag close.801 let isSelfClosing = false;802 if (context.source.length === 0) {803 emitError(context, 12 /* EOF_IN_TAG */);804 }805 else {806 isSelfClosing = startsWith(context.source, '/>');807 if (type === 1 /* End */ && isSelfClosing) {808 emitError(context, 7 /* END_TAG_WITH_TRAILING_SOLIDUS */);809 }810 advanceBy(context, isSelfClosing ? 2 : 1);811 }812 let tagType = 0 /* ELEMENT */;813 if (!context.inPre && !context.options.isCustomElement(tag)) {814 if (context.options.isNativeTag) {815 if (!context.options.isNativeTag(tag))816 tagType = 1 /* COMPONENT */;817 }818 else {819 if (/^[A-Z]/.test(tag))820 tagType = 1 /* COMPONENT */;821 }822 if (tag === 'slot')823 tagType = 2 /* SLOT */;824 else if (tag === 'template')825 tagType = 3 /* TEMPLATE */;826 else if (tag === 'portal' || tag === 'Portal')827 tagType = 4 /* PORTAL */;828 else if (tag === 'suspense' || tag === 'Suspense')829 tagType = 5 /* SUSPENSE */;830 }831 return {832 type: 1 /* ELEMENT */,833 ns,834 tag,835 tagType,836 props,837 isSelfClosing,838 children: [],839 loc: getSelection(context, start),840 codegenNode: undefined // to be created during transform phase841 };842}843function parseAttributes(context, type) {844 const props = [];845 const attributeNames = new Set();846 while (context.source.length > 0 &&847 !startsWith(context.source, '>') &&848 !startsWith(context.source, '/>')) {849 if (startsWith(context.source, '/')) {850 emitError(context, 29 /* UNEXPECTED_SOLIDUS_IN_TAG */);851 advanceBy(context, 1);852 advanceSpaces(context);853 continue;854 }855 if (type === 1 /* End */) {856 emitError(context, 6 /* END_TAG_WITH_ATTRIBUTES */);857 }858 const attr = parseAttribute(context, attributeNames);859 if (type === 0 /* Start */) {860 props.push(attr);861 }862 if (/^[^\t\r\n\f />]/.test(context.source)) {863 emitError(context, 19 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */);864 }865 advanceSpaces(context);866 }867 return props;868}869function parseAttribute(context, nameSet) {870 assert(/^[^\t\r\n\f />]/.test(context.source));871 // Name.872 const start = getCursor(context);873 const match = /^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(context.source);874 const name = match[0];875 if (nameSet.has(name)) {876 emitError(context, 5 /* DUPLICATE_ATTRIBUTE */);877 }878 nameSet.add(name);879 if (name[0] === '=') {880 emitError(context, 26 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */);881 }882 {883 const pattern = /["'<]/g;884 let m;885 while ((m = pattern.exec(name)) !== null) {886 emitError(context, 24 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */, m.index);887 }888 }889 advanceBy(context, name.length);890 // Value891 let value = undefined;892 if (/^[\t\r\n\f ]*=/.test(context.source)) {893 advanceSpaces(context);894 advanceBy(context, 1);895 advanceSpaces(context);896 value = parseAttributeValue(context);897 if (!value) {898 emitError(context, 16 /* MISSING_ATTRIBUTE_VALUE */);899 }900 }901 const loc = getSelection(context, start);902 if (!context.inPre && /^(v-|:|@|#)/.test(name)) {903 const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^@|^#)([^\.]+))?(.+)?$/i.exec(name);904 let arg;905 if (match[2]) {906 const startOffset = name.split(match[2], 2).shift().length;907 const loc = getSelection(context, getNewPosition(context, start, startOffset), getNewPosition(context, start, startOffset + match[2].length));908 let content = match[2];909 let isStatic = true;910 if (content.startsWith('[')) {911 isStatic = false;912 if (!content.endsWith(']')) {913 emitError(context, 34 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */);914 }915 content = content.substr(1, content.length - 2);916 }917 arg = {918 type: 4 /* SIMPLE_EXPRESSION */,919 content,920 isStatic,921 isConstant: isStatic,922 loc923 };924 }925 if (value && value.isQuoted) {926 const valueLoc = value.loc;927 valueLoc.start.offset++;928 valueLoc.start.column++;929 valueLoc.end = advancePositionWithClone(valueLoc.start, value.content);930 valueLoc.source = valueLoc.source.slice(1, -1);931 }932 return {933 type: 7 /* DIRECTIVE */,934 name: match[1] ||935 (startsWith(name, ':')936 ? 'bind'937 : startsWith(name, '@')938 ? 'on'939 : 'slot'),940 exp: value && {941 type: 4 /* SIMPLE_EXPRESSION */,942 content: value.content,943 isStatic: false,944 // Treat as non-constant by default. This can be potentially set to945 // true by `transformExpression` to make it eligible for hoisting.946 isConstant: false,947 loc: value.loc948 },949 arg,950 modifiers: match[3] ? match[3].substr(1).split('.') : [],951 loc952 };953 }954 return {955 type: 6 /* ATTRIBUTE */,956 name,957 value: value && {958 type: 2 /* TEXT */,959 content: value.content,960 loc: value.loc961 },962 loc963 };964}965function parseAttributeValue(context) {966 const start = getCursor(context);967 let content;968 const quote = context.source[0];969 const isQuoted = quote === `"` || quote === `'`;970 if (isQuoted) {971 // Quoted value.972 advanceBy(context, 1);973 const endIndex = context.source.indexOf(quote);974 if (endIndex === -1) {975 content = parseTextData(context, context.source.length, 4 /* ATTRIBUTE_VALUE */);976 }977 else {978 content = parseTextData(context, endIndex, 4 /* ATTRIBUTE_VALUE */);979 advanceBy(context, 1);980 }981 }982 else {983 // Unquoted984 const match = /^[^\t\r\n\f >]+/.exec(context.source);985 if (!match) {986 return undefined;987 }988 let unexpectedChars = /["'<=`]/g;989 let m;990 while ((m = unexpectedChars.exec(match[0])) !== null) {991 emitError(context, 25 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */, m.index);992 }993 content = parseTextData(context, match[0].length, 4 /* ATTRIBUTE_VALUE */);994 }995 return { content, isQuoted, loc: getSelection(context, start) };996}997function parseInterpolation(context, mode) {998 const [open, close] = context.options.delimiters;999 assert(startsWith(context.source, open));1000 const closeIndex = context.source.indexOf(close, open.length);1001 if (closeIndex === -1) {1002 emitError(context, 33 /* X_MISSING_INTERPOLATION_END */);1003 return undefined;1004 }1005 const start = getCursor(context);1006 advanceBy(context, open.length);1007 const innerStart = getCursor(context);1008 const innerEnd = getCursor(context);1009 const rawContentLength = closeIndex - open.length;1010 const rawContent = context.source.slice(0, rawContentLength);1011 const preTrimContent = parseTextData(context, rawContentLength, mode);1012 const content = preTrimContent.trim();1013 const startOffset = preTrimContent.indexOf(content);1014 if (startOffset > 0) {1015 advancePositionWithMutation(innerStart, rawContent, startOffset);1016 }1017 const endOffset = rawContentLength - (preTrimContent.length - content.length - startOffset);1018 advancePositionWithMutation(innerEnd, rawContent, endOffset);1019 advanceBy(context, close.length);1020 return {1021 type: 5 /* INTERPOLATION */,1022 content: {1023 type: 4 /* SIMPLE_EXPRESSION */,1024 isStatic: false,1025 // Set `isConstant` to false by default and will decide in transformExpression1026 isConstant: false,1027 content,1028 loc: getSelection(context, innerStart, innerEnd)1029 },1030 loc: getSelection(context, start)1031 };1032}1033function parseText(context, mode) {1034 assert(context.source.length > 0);1035 const [open] = context.options.delimiters;1036 // TODO could probably use some perf optimization1037 const endIndex = Math.min(...[1038 context.source.indexOf('<', 1),1039 context.source.indexOf(open, 1),1040 mode === 3 /* CDATA */ ? context.source.indexOf(']]>') : -1,1041 context.source.length1042 ].filter(n => n !== -1));1043 assert(endIndex > 0);1044 const start = getCursor(context);1045 const content = parseTextData(context, endIndex, mode);1046 return {1047 type: 2 /* TEXT */,1048 content,1049 loc: getSelection(context, start)1050 };1051}1052/**1053 * Get text data with a given length from the current location.1054 * This translates HTML entities in the text data.1055 */1056function parseTextData(context, length, mode) {1057 if (mode === 2 /* RAWTEXT */ || mode === 3 /* CDATA */) {1058 const text = context.source.slice(0, length);1059 advanceBy(context, length);1060 return text;1061 }1062 // DATA or RCDATA. Entity decoding required.1063 const end = context.offset + length;1064 let text = '';1065 while (context.offset < end) {1066 const head = /&(?:#x?)?/i.exec(context.source);1067 if (!head || context.offset + head.index >= end) {1068 const remaining = end - context.offset;1069 text += context.source.slice(0, remaining);1070 advanceBy(context, remaining);1071 break;1072 }1073 // Advance to the "&".1074 text += context.source.slice(0, head.index);1075 advanceBy(context, head.index);1076 if (head[0] === '&') {1077 // Named character reference.1078 let name = '', value = undefined;1079 if (/[0-9a-z]/i.test(context.source[1])) {1080 for (let length = context.maxCRNameLength; !value && length > 0; --length) {1081 name = context.source.substr(1, length);1082 value = context.options.namedCharacterReferences[name];1083 }1084 if (value) {1085 const semi = name.endsWith(';');1086 if (mode === 4 /* ATTRIBUTE_VALUE */ &&1087 !semi &&1088 /[=a-z0-9]/i.test(context.source[1 + name.length] || '')) {1089 text += '&';1090 text += name;1091 advanceBy(context, 1 + name.length);1092 }1093 else {1094 text += value;1095 advanceBy(context, 1 + name.length);1096 if (!semi) {1097 emitError(context, 18 /* MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE */);1098 }1099 }1100 }1101 else {1102 emitError(context, 30 /* UNKNOWN_NAMED_CHARACTER_REFERENCE */);1103 text += '&';1104 text += name;1105 advanceBy(context, 1 + name.length);1106 }1107 }1108 else {1109 text += '&';1110 advanceBy(context, 1);1111 }1112 }1113 else {1114 // Numeric character reference.1115 const hex = head[0] === '&#x';1116 const pattern = hex ? /^&#x([0-9a-f]+);?/i : /^&#([0-9]+);?/;1117 const body = pattern.exec(context.source);1118 if (!body) {1119 text += head[0];1120 emitError(context, 1 /* ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE */);1121 advanceBy(context, head[0].length);1122 }1123 else {1124 // https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state1125 let cp = Number.parseInt(body[1], hex ? 16 : 10);1126 if (cp === 0) {1127 emitError(context, 22 /* NULL_CHARACTER_REFERENCE */);1128 cp = 0xfffd;1129 }1130 else if (cp > 0x10ffff) {1131 emitError(context, 3 /* CHARACTER_REFERENCE_OUTSIDE_UNICODE_RANGE */);1132 cp = 0xfffd;1133 }1134 else if (cp >= 0xd800 && cp <= 0xdfff) {1135 emitError(context, 23 /* SURROGATE_CHARACTER_REFERENCE */);1136 cp = 0xfffd;1137 }1138 else if ((cp >= 0xfdd0 && cp <= 0xfdef) || (cp & 0xfffe) === 0xfffe) {1139 emitError(context, 21 /* NONCHARACTER_CHARACTER_REFERENCE */);1140 }1141 else if ((cp >= 0x01 && cp <= 0x08) ||1142 cp === 0x0b ||1143 (cp >= 0x0d && cp <= 0x1f) ||1144 (cp >= 0x7f && cp <= 0x9f)) {1145 emitError(context, 4 /* CONTROL_CHARACTER_REFERENCE */);1146 cp = CCR_REPLACEMENTS[cp] || cp;1147 }1148 text += String.fromCodePoint(cp);1149 advanceBy(context, body[0].length);1150 if (!body[0].endsWith(';')) {1151 emitError(context, 18 /* MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE */);1152 }1153 }1154 }1155 }1156 return text;1157}1158function getCursor(context) {1159 const { column, line, offset } = context;1160 return { column, line, offset };1161}1162function getSelection(context, start, end) {1163 end = end || getCursor(context);1164 return {1165 start,1166 end,1167 source: context.originalSource.slice(start.offset, end.offset)1168 };1169}1170function last(xs) {1171 return xs[xs.length - 1];1172}1173function startsWith(source, searchString) {1174 return source.startsWith(searchString);1175}1176function advanceBy(context, numberOfCharacters) {1177 const { source } = context;1178 assert(numberOfCharacters <= source.length);1179 advancePositionWithMutation(context, source, numberOfCharacters);1180 context.source = source.slice(numberOfCharacters);1181}1182function advanceSpaces(context) {1183 const match = /^[\t\r\n\f ]+/.exec(context.source);1184 if (match) {1185 advanceBy(context, match[0].length);1186 }1187}1188function getNewPosition(context, start, numberOfCharacters) {1189 return advancePositionWithClone(start, context.originalSource.slice(start.offset, numberOfCharacters), numberOfCharacters);1190}1191function emitError(context, code, offset) {1192 const loc = getCursor(context);1193 if (offset) {1194 loc.offset += offset;1195 loc.column += offset;1196 }1197 context.options.onError(createCompilerError(code, {1198 start: loc,1199 end: loc,1200 source: ''1201 }));1202}1203function isEnd(context, mode, ancestors) {1204 const s = context.source;1205 switch (mode) {1206 case 0 /* DATA */:1207 if (startsWith(s, '</')) {1208 //TODO: probably bad performance1209 for (let i = ancestors.length - 1; i >= 0; --i) {1210 if (startsWithEndTagOpen(s, ancestors[i].tag)) {1211 return true;1212 }1213 }1214 }1215 break;1216 case 1 /* RCDATA */:1217 case 2 /* RAWTEXT */: {1218 const parent = last(ancestors);1219 if (parent && startsWithEndTagOpen(s, parent.tag)) {1220 return true;1221 }1222 break;1223 }1224 case 3 /* CDATA */:1225 if (startsWith(s, ']]>')) {1226 return true;1227 }1228 break;1229 }1230 return !s;1231}1232function startsWithEndTagOpen(source, tag) {1233 return (startsWith(source, '</') &&1234 source.substr(2, tag.length).toLowerCase() === tag.toLowerCase() &&1235 /[\t\n\f />]/.test(source[2 + tag.length] || '>'));1236}1237// https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state1238const CCR_REPLACEMENTS = {1239 0x80: 0x20ac,1240 0x82: 0x201a,1241 0x83: 0x0192,1242 0x84: 0x201e,1243 0x85: 0x2026,1244 0x86: 0x2020,1245 0x87: 0x2021,1246 0x88: 0x02c6,1247 0x89: 0x2030,1248 0x8a: 0x0160,1249 0x8b: 0x2039,1250 0x8c: 0x0152,1251 0x8e: 0x017d,1252 0x91: 0x2018,1253 0x92: 0x2019,1254 0x93: 0x201c,1255 0x94: 0x201d,1256 0x95: 0x2022,1257 0x96: 0x2013,1258 0x97: 0x2014,1259 0x98: 0x02dc,1260 0x99: 0x2122,1261 0x9a: 0x0161,1262 0x9b: 0x203a,1263 0x9c: 0x0153,1264 0x9e: 0x017e,1265 0x9f: 0x01781266};1267function hoistStatic(root, context) {1268 walk(root.children, context, new Map(), isSingleElementRoot(root, root.children[0]));1269}1270function isSingleElementRoot(root, child) {1271 const { children } = root;1272 return (children.length === 1 &&1273 child.type === 1 /* ELEMENT */ &&1274 !isSlotOutlet(child));1275}1276function walk(children, context, resultCache, doNotHoistNode = false) {1277 for (let i = 0; i < children.length; i++) {1278 const child = children[i];1279 // only plain elements are eligible for hoisting.1280 if (child.type === 1 /* ELEMENT */ &&1281 child.tagType === 0 /* ELEMENT */) {1282 if (!doNotHoistNode && isStaticNode(child, resultCache)) {1283 // whole tree is static1284 child.codegenNode = context.hoist(child.codegenNode);1285 continue;1286 }1287 else {1288 // node may contain dynamic children, but its props may be eligible for1289 // hoisting.1290 const codegenNode = child.codegenNode;1291 if (codegenNode.type === 13 /* JS_CALL_EXPRESSION */) {1292 const flag = getPatchFlag(codegenNode);1293 if ((!flag ||1294 flag === 32 /* NEED_PATCH */ ||1295 flag === 1 /* TEXT */) &&1296 !hasDynamicKeyOrRef(child) &&1297 !hasCachedProps(child)) {1298 const props = getNodeProps(child);1299 if (props && props !== `null`) {1300 getVNodeCall(codegenNode).arguments[1] = context.hoist(props);1301 }1302 }1303 }1304 }1305 }1306 if (child.type === 1 /* ELEMENT */) {1307 walk(child.children, context, resultCache);1308 }1309 else if (child.type === 11 /* FOR */) {1310 // Do not hoist v-for single child because it has to be a block1311 walk(child.children, context, resultCache, child.children.length === 1);1312 }1313 else if (child.type === 9 /* IF */) {1314 for (let i = 0; i < child.branches.length; i++) {1315 const branchChildren = child.branches[i].children;1316 // Do not hoist v-if single child because it has to be a block1317 walk(branchChildren, context, resultCache, branchChildren.length === 1);1318 }1319 }1320 }1321}1322function isStaticNode(node, resultCache = new Map()) {1323 switch (node.type) {1324 case 1 /* ELEMENT */:1325 if (node.tagType !== 0 /* ELEMENT */) {1326 return false;1327 }1328 const cached = resultCache.get(node);1329 if (cached !== undefined) {1330 return cached;1331 }1332 const codegenNode = node.codegenNode;1333 if (codegenNode.type !== 13 /* JS_CALL_EXPRESSION */) {1334 return false;1335 }1336 const flag = getPatchFlag(codegenNode);1337 if (!flag && !hasDynamicKeyOrRef(node) && !hasCachedProps(node)) {1338 // element self is static. check its children.1339 for (let i = 0; i < node.children.length; i++) {1340 if (!isStaticNode(node.children[i], resultCache)) {1341 resultCache.set(node, false);1342 return false;1343 }1344 }1345 resultCache.set(node, true);1346 return true;1347 }1348 else {1349 resultCache.set(node, false);1350 return false;1351 }1352 case 2 /* TEXT */:1353 case 3 /* COMMENT */:1354 return true;1355 case 9 /* IF */:1356 case 11 /* FOR */:1357 return false;1358 case 5 /* INTERPOLATION */:1359 case 12 /* TEXT_CALL */:1360 return isStaticNode(node.content, resultCache);1361 case 4 /* SIMPLE_EXPRESSION */:1362 return node.isConstant;1363 case 8 /* COMPOUND_EXPRESSION */:1364 return node.children.every(child => {1365 return (isString(child) || isSymbol(child) || isStaticNode(child, resultCache));1366 });1367 default:1368 return false;1369 }1370}1371function hasDynamicKeyOrRef(node) {1372 return !!(findProp(node, 'key', true) || findProp(node, 'ref', true));1373}1374function hasCachedProps(node) {1375 const props = getNodeProps(node);1376 if (props &&1377 props !== 'null' &&1378 props.type === 14 /* JS_OBJECT_EXPRESSION */) {1379 const { properties } = props;1380 for (let i = 0; i < properties.length; i++) {1381 if (properties[i].value.type === 20 /* JS_CACHE_EXPRESSION */) {1382 return true;1383 }1384 }1385 }1386 return false;1387}1388function getNodeProps(node) {1389 const codegenNode = node.codegenNode;1390 if (codegenNode.type === 13 /* JS_CALL_EXPRESSION */) {1391 return getVNodeArgAt(codegenNode, 1);1392 }1393}1394function getVNodeArgAt(node, index) {1395 return getVNodeCall(node).arguments[index];1396}1397function getVNodeCall(node) {1398 return node.callee === WITH_DIRECTIVES ? node.arguments[0] : node;1399}1400function getPatchFlag(node) {1401 const flag = getVNodeArgAt(node, 3);1402 return flag ? parseInt(flag, 10) : undefined;1403}1404function createTransformContext(root, { prefixIdentifiers = false, hoistStatic = false, cacheHandlers = false, nodeTransforms = [], directiveTransforms = {}, onError = defaultOnError }) {1405 const context = {1406 root,1407 helpers: new Set(),1408 components: new Set(),1409 directives: new Set(),1410 hoists: [],1411 cached: 0,1412 identifiers: {},1413 scopes: {1414 vFor: 0,1415 vSlot: 0,1416 vPre: 0,1417 vOnce: 01418 },1419 prefixIdentifiers,1420 hoistStatic,1421 cacheHandlers,1422 nodeTransforms,1423 directiveTransforms,1424 onError,1425 parent: null,1426 currentNode: root,1427 childIndex: 0,1428 helper(name) {1429 context.helpers.add(name);1430 return name;1431 },1432 helperString(name) {1433 return ((context.prefixIdentifiers ? `` : `_`) +1434 helperNameMap[context.helper(name)]);1435 },1436 replaceNode(node) {1437 /* istanbul ignore if */1438 {1439 if (!context.currentNode) {1440 throw new Error(`Node being replaced is already removed.`);1441 }1442 if (!context.parent) {1443 throw new Error(`Cannot replace root node.`);1444 }1445 }1446 context.parent.children[context.childIndex] = context.currentNode = node;1447 },1448 removeNode(node) {1449 if ( !context.parent) {1450 throw new Error(`Cannot remove root node.`);1451 }1452 const list = context.parent.children;1453 const removalIndex = node1454 ? list.indexOf(node)1455 : context.currentNode1456 ? context.childIndex1457 : -1;1458 /* istanbul ignore if */1459 if ( removalIndex < 0) {1460 throw new Error(`node being removed is not a child of current parent`);1461 }1462 if (!node || node === context.currentNode) {1463 // current node removed1464 context.currentNode = null;1465 context.onNodeRemoved();1466 }1467 else {1468 // sibling node removed1469 if (context.childIndex > removalIndex) {1470 context.childIndex--;1471 context.onNodeRemoved();1472 }1473 }1474 context.parent.children.splice(removalIndex, 1);1475 },1476 onNodeRemoved: () => { },1477 addIdentifiers(exp) {1478 // identifier tracking only happens in non-browser builds.1479 {1480 if (isString(exp)) {1481 addId(exp);1482 }1483 else if (exp.identifiers) {1484 exp.identifiers.forEach(addId);1485 }1486 else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {1487 addId(exp.content);1488 }1489 }1490 },1491 removeIdentifiers(exp) {1492 {1493 if (isString(exp)) {1494 removeId(exp);1495 }1496 else if (exp.identifiers) {1497 exp.identifiers.forEach(removeId);1498 }1499 else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {1500 removeId(exp.content);1501 }1502 }1503 },1504 hoist(exp) {1505 context.hoists.push(exp);1506 return createSimpleExpression(`_hoisted_${context.hoists.length}`, false, exp.loc, true);1507 },1508 cache(exp, isVNode = false) {1509 return createCacheExpression(++context.cached, exp, isVNode);1510 }1511 };1512 function addId(id) {1513 const { identifiers } = context;1514 if (identifiers[id] === undefined) {1515 identifiers[id] = 0;1516 }1517 identifiers[id]++;1518 }1519 function removeId(id) {1520 context.identifiers[id]--;1521 }1522 return context;1523}1524function transform(root, options) {1525 const context = createTransformContext(root, options);1526 traverseNode(root, context);1527 if (options.hoistStatic) {1528 hoistStatic(root, context);1529 }1530 finalizeRoot(root, context);1531}1532function finalizeRoot(root, context) {1533 const { helper } = context;1534 const { children } = root;1535 const child = children[0];1536 if (children.length === 1) {1537 // if the single child is an element, turn it into a block.1538 if (isSingleElementRoot(root, child) && child.codegenNode) {1539 // single element root is never hoisted so codegenNode will never be1540 // SimpleExpressionNode1541 const codegenNode = child.codegenNode;1542 if (codegenNode.type !== 20 /* JS_CACHE_EXPRESSION */) {1543 if (codegenNode.callee === WITH_DIRECTIVES) {1544 codegenNode.arguments[0].callee = helper(CREATE_BLOCK);1545 }1546 else {1547 codegenNode.callee = helper(CREATE_BLOCK);1548 }1549 root.codegenNode = createBlockExpression(codegenNode, context);1550 }1551 else {1552 root.codegenNode = codegenNode;1553 }1554 }1555 else {1556 // - single <slot/>, IfNode, ForNode: already blocks.1557 // - single text node: always patched.1558 // root codegen falls through via genNode()1559 root.codegenNode = child;1560 }1561 }1562 else if (children.length > 1) {1563 // root has multiple nodes - return a fragment block.1564 root.codegenNode = createBlockExpression(createCallExpression(helper(CREATE_BLOCK), [1565 helper(FRAGMENT),1566 `null`,1567 root.children1568 ]), context);1569 }1570 // finalize meta information1571 root.helpers = [...context.helpers];1572 root.components = [...context.components];1573 root.directives = [...context.directives];1574 root.hoists = context.hoists;1575 root.cached = context.cached;1576}1577function traverseChildren(parent, context) {1578 let i = 0;1579 const nodeRemoved = () => {1580 i--;1581 };1582 for (; i < parent.children.length; i++) {1583 const child = parent.children[i];1584 if (isString(child))1585 continue;1586 context.currentNode = child;1587 context.parent = parent;1588 context.childIndex = i;1589 context.onNodeRemoved = nodeRemoved;1590 traverseNode(child, context);1591 }1592}1593function traverseNode(node, context) {1594 // apply transform plugins1595 const { nodeTransforms } = context;1596 const exitFns = [];1597 for (let i = 0; i < nodeTransforms.length; i++) {1598 const onExit = nodeTransforms[i](node, context);1599 if (onExit) {1600 if (isArray(onExit)) {1601 exitFns.push(...onExit);1602 }1603 else {1604 exitFns.push(onExit);1605 }1606 }1607 if (!context.currentNode) {1608 // node was removed1609 return;1610 }1611 else {1612 // node may have been replaced1613 node = context.currentNode;1614 }1615 }1616 switch (node.type) {1617 case 3 /* COMMENT */:1618 // inject import for the Comment symbol, which is needed for creating1619 // comment nodes with `createVNode`1620 context.helper(CREATE_COMMENT);1621 break;1622 case 5 /* INTERPOLATION */:1623 // no need to traverse, but we need to inject toString helper1624 context.helper(TO_STRING);1625 break;1626 // for container types, further traverse downwards1627 case 9 /* IF */:1628 for (let i = 0; i < node.branches.length; i++) {1629 traverseChildren(node.branches[i], context);1630 }1631 break;1632 case 11 /* FOR */:1633 case 1 /* ELEMENT */:1634 case 0 /* ROOT */:1635 traverseChildren(node, context);1636 break;1637 }1638 // exit transforms1639 let i = exitFns.length;1640 while (i--) {1641 exitFns[i]();1642 }1643}1644function createStructuralDirectiveTransform(name, fn) {1645 const matches = isString(name)1646 ? (n) => n === name1647 : (n) => name.test(n);1648 return (node, context) => {1649 if (node.type === 1 /* ELEMENT */) {1650 const { props } = node;1651 // structural directive transforms are not concerned with slots1652 // as they are handled separately in vSlot.ts1653 if (node.tagType === 3 /* TEMPLATE */ && props.some(isVSlot)) {1654 return;1655 }1656 const exitFns = [];1657 for (let i = 0; i < props.length; i++) {1658 const prop = props[i];1659 if (prop.type === 7 /* DIRECTIVE */ && matches(prop.name)) {1660 // structural directives are removed to avoid infinite recursion1661 // also we remove them *before* applying so that it can further1662 // traverse itself in case it moves the node around1663 props.splice(i, 1);1664 i--;1665 const onExit = fn(node, prop, context);1666 if (onExit)1667 exitFns.push(onExit);1668 }1669 }1670 return exitFns;1671 }1672 };1673}1674function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap = false, filename = `template.vue.html` }) {1675 const context = {1676 mode,1677 prefixIdentifiers,1678 sourceMap,1679 filename,1680 source: ast.loc.source,1681 code: ``,1682 column: 1,1683 line: 1,1684 offset: 0,1685 indentLevel: 0,1686 // lazy require source-map implementation, only in non-browser builds!1687 map: !sourceMap1688 ? undefined1689 : new (loadDep('source-map')).SourceMapGenerator(),1690 helper(key) {1691 const name = helperNameMap[key];1692 return prefixIdentifiers ? name : `_${name}`;1693 },1694 push(code, node, openOnly) {1695 context.code += code;1696 if ( context.map) {1697 if (node) {1698 let name;1699 if (node.type === 4 /* SIMPLE_EXPRESSION */ && !node.isStatic) {1700 const content = node.content.replace(/^_ctx\./, '');1701 if (content !== node.content && isSimpleIdentifier(content)) {1702 name = content;1703 }1704 }1705 addMapping(node.loc.start, name);1706 }1707 advancePositionWithMutation(context, code);1708 if (node && !openOnly) {1709 addMapping(node.loc.end);1710 }1711 }1712 },1713 resetMapping(loc) {1714 if ( context.map) {1715 addMapping(loc.start);1716 }1717 },1718 indent() {1719 newline(++context.indentLevel);1720 },1721 deindent(withoutNewLine = false) {1722 if (withoutNewLine) {1723 --context.indentLevel;1724 }1725 else {1726 newline(--context.indentLevel);1727 }1728 },1729 newline() {1730 newline(context.indentLevel);1731 }1732 };1733 function newline(n) {1734 context.push('\n' + ` `.repeat(n));1735 }1736 function addMapping(loc, name) {1737 context.map.addMapping({1738 name,1739 source: context.filename,1740 original: {1741 line: loc.line,1742 column: loc.column - 1 // source-map column is 0 based1743 },1744 generated: {1745 line: context.line,1746 column: context.column - 11747 }1748 });1749 }1750 if ( context.map) {1751 context.map.setSourceContent(filename, context.source);1752 }1753 return context;1754}1755function generate(ast, options = {}) {1756 const context = createCodegenContext(ast, options);1757 const { mode, push, helper, prefixIdentifiers, indent, deindent, newline } = context;1758 const hasHelpers = ast.helpers.length > 0;1759 const useWithBlock = !prefixIdentifiers && mode !== 'module';1760 // preambles1761 if (mode === 'function') {1762 // Generate const declaration for helpers1763 // In prefix mode, we place the const declaration at top so it's done1764 // only once; But if we not prefixing, we place the declaration inside the1765 // with block so it doesn't incur the `in` check cost for every helper access.1766 if (hasHelpers) {1767 if (prefixIdentifiers) {1768 push(`const { ${ast.helpers.map(helper).join(', ')} } = Vue\n`);1769 }1770 else {1771 // "with" mode.1772 // save Vue in a separate variable to avoid collision1773 push(`const _Vue = Vue\n`);1774 // in "with" mode, helpers are declared inside the with block to avoid1775 // has check cost, but hoists are lifted out of the function - we need1776 // to provide the helper here.1777 if (ast.hoists.length) {1778 push(`const _${helperNameMap[CREATE_VNODE]} = Vue.${helperNameMap[CREATE_VNODE]}\n`);1779 if (ast.helpers.includes(CREATE_COMMENT)) {1780 push(`const _${helperNameMap[CREATE_COMMENT]} = Vue.${helperNameMap[CREATE_COMMENT]}\n`);1781 }1782 }1783 }1784 }1785 genHoists(ast.hoists, context);1786 newline();1787 push(`return `);1788 }1789 else {1790 // generate import statements for helpers1791 if (hasHelpers) {1792 push(`import { ${ast.helpers.map(helper).join(', ')} } from "vue"\n`);1793 }1794 genHoists(ast.hoists, context);1795 newline();1796 push(`export default `);1797 }1798 // enter render function1799 push(`function render() {`);1800 indent();1801 if (useWithBlock) {1802 push(`with (this) {`);1803 indent();1804 // function mode const declarations should be inside with block1805 // also they should be renamed to avoid collision with user properties1806 if (hasHelpers) {1807 push(`const { ${ast.helpers1808 .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)1809 .join(', ')} } = _Vue`);1810 newline();1811 if (ast.cached > 0) {1812 push(`const _cache = $cache`);1813 newline();1814 }1815 newline();1816 }1817 }1818 else {1819 push(`const _ctx = this`);1820 if (ast.cached > 0) {1821 newline();1822 push(`const _cache = _ctx.$cache`);1823 }1824 newline();1825 }1826 // generate asset resolution statements1827 if (ast.components.length) {1828 genAssets(ast.components, 'component', context);1829 }1830 if (ast.directives.length) {1831 genAssets(ast.directives, 'directive', context);1832 }1833 if (ast.components.length || ast.directives.length) {1834 newline();1835 }1836 // generate the VNode tree expression1837 push(`return `);1838 if (ast.codegenNode) {1839 genNode(ast.codegenNode, context);1840 }1841 else {1842 push(`null`);1843 }1844 if (useWithBlock) {1845 deindent();1846 push(`}`);1847 }1848 deindent();1849 push(`}`);1850 return {1851 ast,1852 code: context.code,1853 map: undefined //context.map ? context.map.toJSON() : undefined1854 };1855}1856function genAssets(assets, type, context) {1857 const resolver = context.helper(type === 'component' ? RESOLVE_COMPONENT : RESOLVE_DIRECTIVE);1858 for (let i = 0; i < assets.length; i++) {1859 const id = assets[i];1860 context.push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)})`);1861 context.newline();1862 }1863}1864function genHoists(hoists, context) {1865 if (!hoists.length) {1866 return;1867 }1868 context.newline();1869 hoists.forEach((exp, i) => {1870 context.push(`const _hoisted_${i + 1} = `);1871 genNode(exp, context);1872 context.newline();1873 });1874}1875function isText(n) {1876 return (isString(n) ||1877 n.type === 4 /* SIMPLE_EXPRESSION */ ||1878 n.type === 2 /* TEXT */ ||1879 n.type === 5 /* INTERPOLATION */ ||1880 n.type === 8 /* COMPOUND_EXPRESSION */);1881}1882function genNodeListAsArray(nodes, context) {1883 const multilines = nodes.length > 3 ||1884 ( nodes.some(n => isArray(n) || !isText(n)));1885 context.push(`[`);1886 multilines && context.indent();1887 genNodeList(nodes, context, multilines);1888 multilines && context.deindent();1889 context.push(`]`);1890}1891function genNodeList(nodes, context, multilines = false) {1892 const { push, newline } = context;1893 for (let i = 0; i < nodes.length; i++) {1894 const node = nodes[i];1895 if (isString(node)) {1896 push(node);1897 }1898 else if (isArray(node)) {1899 genNodeListAsArray(node, context);1900 }1901 else {1902 genNode(node, context);1903 }1904 if (i < nodes.length - 1) {1905 if (multilines) {1906 push(',');1907 newline();1908 }1909 else {1910 push(', ');1911 }1912 }1913 }1914}1915function genNode(node, context) {1916 if (isString(node)) {1917 context.push(node);1918 return;1919 }1920 if (isSymbol(node)) {1921 context.push(context.helper(node));1922 return;1923 }1924 switch (node.type) {1925 case 1 /* ELEMENT */:1926 case 9 /* IF */:1927 case 11 /* FOR */:1928 1929 assert(node.codegenNode != null, `Codegen node is missing for element/if/for node. ` +1930 `Apply appropriate transforms first.`);1931 genNode(node.codegenNode, context);1932 break;1933 case 2 /* TEXT */:1934 genText(node, context);1935 break;1936 case 4 /* SIMPLE_EXPRESSION */:1937 genExpression(node, context);1938 break;1939 case 5 /* INTERPOLATION */:1940 genInterpolation(node, context);1941 break;1942 case 12 /* TEXT_CALL */:1943 genNode(node.codegenNode, context);1944 break;1945 case 8 /* COMPOUND_EXPRESSION */:1946 genCompoundExpression(node, context);1947 break;1948 case 3 /* COMMENT */:1949 genComment(node, context);1950 break;1951 case 13 /* JS_CALL_EXPRESSION */:1952 genCallExpression(node, context);1953 break;1954 case 14 /* JS_OBJECT_EXPRESSION */:1955 genObjectExpression(node, context);1956 break;1957 case 16 /* JS_ARRAY_EXPRESSION */:1958 genArrayExpression(node, context);1959 break;1960 case 17 /* JS_FUNCTION_EXPRESSION */:1961 genFunctionExpression(node, context);1962 break;1963 case 18 /* JS_SEQUENCE_EXPRESSION */:1964 genSequenceExpression(node, context);1965 break;1966 case 19 /* JS_CONDITIONAL_EXPRESSION */:1967 genConditionalExpression(node, context);1968 break;1969 case 20 /* JS_CACHE_EXPRESSION */:1970 genCacheExpression(node, context);1971 break;1972 /* istanbul ignore next */1973 default:1974 {1975 assert(false, `unhandled codegen node type: ${node.type}`);1976 // make sure we exhaust all possible types1977 const exhaustiveCheck = node;1978 return exhaustiveCheck;1979 }1980 }1981}1982function genText(node, context) {1983 context.push(JSON.stringify(node.content), node);1984}1985function genExpression(node, context) {1986 const { content, isStatic } = node;1987 context.push(isStatic ? JSON.stringify(content) : content, node);1988}1989function genInterpolation(node, context) {1990 const { push, helper } = context;1991 push(`${helper(TO_STRING)}(`);1992 genNode(node.content, context);1993 push(`)`);1994}1995function genCompoundExpression(node, context) {1996 for (let i = 0; i < node.children.length; i++) {1997 const child = node.children[i];1998 if (isString(child)) {1999 context.push(child);2000 }2001 else {2002 genNode(child, context);2003 }2004 }2005}2006function genExpressionAsPropertyKey(node, context) {2007 const { push } = context;2008 if (node.type === 8 /* COMPOUND_EXPRESSION */) {2009 push(`[`);2010 genCompoundExpression(node, context);2011 push(`]`);2012 }2013 else if (node.isStatic) {2014 // only quote keys if necessary2015 const text = isSimpleIdentifier(node.content)2016 ? node.content2017 : JSON.stringify(node.content);2018 push(text, node);2019 }2020 else {2021 push(`[${node.content}]`, node);2022 }2023}2024function genComment(node, context) {2025 {2026 const { push, helper } = context;2027 push(`${helper(CREATE_COMMENT)}(${JSON.stringify(node.content)})`, node);2028 }2029}2030// JavaScript2031function genCallExpression(node, context) {2032 const callee = isString(node.callee)2033 ? node.callee2034 : context.helper(node.callee);2035 context.push(callee + `(`, node, true);2036 genNodeList(node.arguments, context);2037 context.push(`)`);2038}2039function genObjectExpression(node, context) {2040 const { push, indent, deindent, newline, resetMapping } = context;2041 const { properties } = node;2042 if (!properties.length) {2043 push(`{}`, node);2044 return;2045 }2046 const multilines = properties.length > 1 ||2047 (2048 properties.some(p => p.value.type !== 4 /* SIMPLE_EXPRESSION */));2049 push(multilines ? `{` : `{ `);2050 multilines && indent();2051 for (let i = 0; i < properties.length; i++) {2052 const { key, value, loc } = properties[i];2053 resetMapping(loc); // reset source mapping for every property.2054 // key2055 genExpressionAsPropertyKey(key, context);2056 push(`: `);2057 // value2058 genNode(value, context);2059 if (i < properties.length - 1) {2060 // will only reach this if it's multilines2061 push(`,`);2062 newline();2063 }2064 }2065 multilines && deindent();2066 const lastChar = context.code[context.code.length - 1];2067 push(multilines || /[\])}]/.test(lastChar) ? `}` : ` }`);2068}2069function genArrayExpression(node, context) {2070 genNodeListAsArray(node.elements, context);2071}2072function genFunctionExpression(node, context) {2073 const { push, indent, deindent } = context;2074 const { params, returns, newline } = node;2075 push(`(`, node);2076 if (isArray(params)) {2077 genNodeList(params, context);2078 }2079 else if (params) {2080 genNode(params, context);2081 }2082 push(`) => `);2083 if (newline) {2084 push(`{`);2085 indent();2086 push(`return `);2087 }2088 if (isArray(returns)) {2089 genNodeListAsArray(returns, context);2090 }2091 else {2092 genNode(returns, context);2093 }2094 if (newline) {2095 deindent();2096 push(`}`);2097 }2098}2099function genConditionalExpression(node, context) {2100 const { test, consequent, alternate } = node;2101 const { push, indent, deindent, newline } = context;2102 if (test.type === 4 /* SIMPLE_EXPRESSION */) {2103 const needsParens = !isSimpleIdentifier(test.content);2104 needsParens && push(`(`);2105 genExpression(test, context);2106 needsParens && push(`)`);2107 }2108 else {2109 push(`(`);2110 genCompoundExpression(test, context);2111 push(`)`);2112 }2113 indent();2114 context.indentLevel++;2115 push(`? `);2116 genNode(consequent, context);2117 context.indentLevel--;2118 newline();2119 push(`: `);2120 const isNested = alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */;2121 if (!isNested) {2122 context.indentLevel++;2123 }2124 genNode(alternate, context);2125 if (!isNested) {2126 context.indentLevel--;2127 }2128 deindent(true /* without newline */);2129}2130function genSequenceExpression(node, context) {2131 context.push(`(`);2132 genNodeList(node.expressions, context);2133 context.push(`)`);2134}2135function genCacheExpression(node, context) {2136 const { push, helper, indent, deindent, newline } = context;2137 push(`_cache[${node.index}] || (`);2138 if (node.isVNode) {2139 indent();2140 push(`${helper(SET_BLOCK_TRACKING)}(-1),`);2141 newline();2142 }2143 push(`_cache[${node.index}] = `);2144 genNode(node.value, context);2145 if (node.isVNode) {2146 push(`,`);2147 newline();2148 push(`${helper(SET_BLOCK_TRACKING)}(1),`);2149 newline();2150 push(`_cache[${node.index}]`);2151 deindent();2152 }2153 push(`)`);2154}2155const isLiteralWhitelisted = /*#__PURE__*/ makeMap('true,false,null,this');2156const transformExpression = (node, context) => {2157 if (node.type === 5 /* INTERPOLATION */) {2158 node.content = processExpression(node.content, context);2159 }2160 else if (node.type === 1 /* ELEMENT */) {2161 // handle directives on element2162 for (let i = 0; i < node.props.length; i++) {2163 const dir = node.props[i];2164 // do not process for v-on & v-for since they are special handled2165 if (dir.type === 7 /* DIRECTIVE */ && dir.name !== 'for') {2166 const exp = dir.exp;2167 const arg = dir.arg;2168 // do not process exp if this is v-on:arg - we need special handling2169 // for wrapping inline statements.2170 if (exp && !(dir.name === 'on' && arg)) {2171 dir.exp = processExpression(exp, context, 2172 // slot args must be processed as function params2173 dir.name === 'slot');2174 }2175 if (arg && !arg.isStatic) {2176 dir.arg = processExpression(arg, context);2177 }2178 }2179 }2180 }2181};2182// Important: since this function uses Node.js only dependencies, it should2183// always be used with a leading !false check so that it can be2184// tree-shaken from the browser build.2185function processExpression(node, context, 2186// some expressions like v-slot props & v-for aliases should be parsed as2187// function params2188asParams = false) {2189 if (!context.prefixIdentifiers || !node.content.trim()) {2190 return node;2191 }2192 // fast path if expression is a simple identifier.2193 const rawExp = node.content;2194 if (isSimpleIdentifier(rawExp)) {2195 if (!asParams &&2196 !context.identifiers[rawExp] &&2197 !isGloballyWhitelisted(rawExp) &&2198 !isLiteralWhitelisted(rawExp)) {2199 node.content = `_ctx.${rawExp}`;2200 }2201 else if (!context.identifiers[rawExp]) {2202 // mark node constant for hoisting unless it's referring a scope variable2203 node.isConstant = true;2204 }2205 return node;2206 }2207 let ast;2208 // if the expression is supposed to be used in a function params position2209 // we need to parse it differently.2210 const source = `(${rawExp})${asParams ? `=>{}` : ``}`;2211 try {2212 ast = parseJS(source, { ranges: true });2213 }2214 catch (e) {2215 context.onError(createCompilerError(50 /* X_INVALID_EXPRESSION */, node.loc));2216 return node;2217 }2218 const ids = [];2219 const knownIds = Object.create(context.identifiers);2220 // walk the AST and look for identifiers that need to be prefixed with `_ctx.`.2221 walkJS(ast, {2222 enter(node, parent) {2223 if (node.type === 'Identifier') {2224 if (!ids.includes(node)) {2225 const needPrefix = shouldPrefix(node, parent);2226 if (!knownIds[node.name] && needPrefix) {2227 if (isPropertyShorthand(node, parent)) {2228 // property shorthand like { foo }, we need to add the key since we2229 // rewrite the value2230 node.prefix = `${node.name}: `;2231 }2232 node.name = `_ctx.${node.name}`;2233 node.isConstant = false;2234 ids.push(node);2235 }2236 else if (!isStaticPropertyKey(node, parent)) {2237 // The identifier is considered constant unless it's pointing to a2238 // scope variable (a v-for alias, or a v-slot prop)2239 node.isConstant = !(needPrefix && knownIds[node.name]);2240 // also generate sub-expressions for other identifiers for better2241 // source map support. (except for property keys which are static)2242 ids.push(node);2243 }2244 }2245 }2246 else if (isFunction$1(node)) {2247 // walk function expressions and add its arguments to known identifiers2248 // so that we don't prefix them2249 node.params.forEach((p) => walkJS(p, {2250 enter(child, parent) {2251 if (child.type === 'Identifier' &&2252 // do not record as scope variable if is a destructured key2253 !isStaticPropertyKey(child, parent) &&2254 // do not record if this is a default value2255 // assignment of a destructured variable2256 !(parent &&2257 parent.type === 'AssignmentPattern' &&2258 parent.right === child)) {2259 const { name } = child;2260 if (node.scopeIds && node.scopeIds.has(name)) {2261 return;2262 }2263 if (name in knownIds) {2264 knownIds[name]++;2265 }2266 else {2267 knownIds[name] = 1;2268 }2269 (node.scopeIds || (node.scopeIds = new Set())).add(name);2270 }2271 }2272 }));2273 }2274 },2275 leave(node) {2276 if (node !== ast.body[0].expression && node.scopeIds) {2277 node.scopeIds.forEach((id) => {2278 knownIds[id]--;2279 if (knownIds[id] === 0) {2280 delete knownIds[id];2281 }2282 });2283 }2284 }2285 });2286 // We break up the compound expression into an array of strings and sub2287 // expressions (for identifiers that have been prefixed). In codegen, if2288 // an ExpressionNode has the `.children` property, it will be used instead of2289 // `.content`.2290 const children = [];2291 ids.sort((a, b) => a.start - b.start);2292 ids.forEach((id, i) => {2293 // range is offset by -1 due to the wrapping parens when parsed2294 const start = id.start - 1;2295 const end = id.end - 1;2296 const last = ids[i - 1];2297 const leadingText = rawExp.slice(last ? last.end - 1 : 0, start);2298 if (leadingText.length || id.prefix) {2299 children.push(leadingText + (id.prefix || ``));2300 }2301 const source = rawExp.slice(start, end);2302 children.push(createSimpleExpression(id.name, false, {2303 source,2304 start: advancePositionWithClone(node.loc.start, source, start),2305 end: advancePositionWithClone(node.loc.start, source, end)2306 }, id.isConstant /* isConstant */));2307 if (i === ids.length - 1 && end < rawExp.length) {2308 children.push(rawExp.slice(end));2309 }2310 });2311 let ret;2312 if (children.length) {2313 ret = createCompoundExpression(children, node.loc);2314 }2315 else {2316 ret = node;2317 ret.isConstant = true;2318 }2319 ret.identifiers = Object.keys(knownIds);2320 return ret;2321}2322const isFunction$1 = (node) => /Function(Expression|Declaration)$/.test(node.type);2323const isPropertyKey = (node, parent) => parent &&2324 parent.type === 'Property' &&2325 parent.key === node &&2326 !parent.computed;2327const isPropertyShorthand = (node, parent) => isPropertyKey(node, parent) && parent.value === node;2328const isStaticPropertyKey = (node, parent) => isPropertyKey(node, parent) && parent.value !== node;2329function shouldPrefix(identifier, parent) {2330 if (!(isFunction$1(parent) &&2331 // not id of a FunctionDeclaration2332 (parent.id === identifier ||2333 // not a params of a function2334 parent.params.includes(identifier))) &&2335 // not a key of Property2336 !isStaticPropertyKey(identifier, parent) &&2337 // not a property of a MemberExpression2338 !(parent.type === 'MemberExpression' &&2339 parent.property === identifier &&2340 !parent.computed) &&2341 // not in an Array destructure pattern2342 !(parent.type === 'ArrayPattern') &&2343 // skip whitelisted globals2344 !isGloballyWhitelisted(identifier.name) &&2345 // special case for webpack compilation2346 identifier.name !== `require` &&2347 // is a special keyword but parsed as identifier2348 identifier.name !== `arguments`) {2349 return true;2350 }2351}2352const transformIf = createStructuralDirectiveTransform(/^(if|else|else-if)$/, (node, dir, context) => {2353 if (dir.name !== 'else' &&2354 (!dir.exp || !dir.exp.content.trim())) {2355 const loc = dir.exp ? dir.exp.loc : node.loc;2356 context.onError(createCompilerError(35 /* X_V_IF_NO_EXPRESSION */, dir.loc));2357 dir.exp = createSimpleExpression(`true`, false, loc);2358 }2359 if ( context.prefixIdentifiers && dir.exp) {2360 // dir.exp can only be simple expression because vIf transform is applied2361 // before expression transform.2362 dir.exp = processExpression(dir.exp, context);2363 }2364 if (dir.name === 'if') {2365 const branch = createIfBranch(node, dir);2366 const codegenNode = createSequenceExpression([2367 createCallExpression(context.helper(OPEN_BLOCK))2368 ]);2369 context.replaceNode({2370 type: 9 /* IF */,2371 loc: node.loc,2372 branches: [branch],2373 codegenNode2374 });2375 // Exit callback. Complete the codegenNode when all children have been2376 // transformed.2377 return () => {2378 codegenNode.expressions.push(createCodegenNodeForBranch(branch, 0, context));2379 };2380 }2381 else {2382 // locate the adjacent v-if2383 const siblings = context.parent.children;2384 const comments = [];2385 let i = siblings.indexOf(node);2386 while (i-- >= -1) {2387 const sibling = siblings[i];2388 if ( sibling && sibling.type === 3 /* COMMENT */) {2389 context.removeNode(sibling);2390 comments.unshift(sibling);2391 continue;2392 }2393 if (sibling && sibling.type === 9 /* IF */) {2394 // move the node to the if node's branches2395 context.removeNode();2396 const branch = createIfBranch(node, dir);2397 if ( comments.length) {2398 branch.children = [...comments, ...branch.children];2399 }2400 sibling.branches.push(branch);2401 // since the branch was removed, it will not be traversed.2402 // make sure to traverse here.2403 traverseChildren(branch, context);2404 // make sure to reset currentNode after traversal to indicate this2405 // node has been removed.2406 context.currentNode = null;2407 // attach this branch's codegen node to the v-if root.2408 let parentCondition = sibling.codegenNode2409 .expressions[1];2410 while (true) {2411 if (parentCondition.alternate.type ===2412 19 /* JS_CONDITIONAL_EXPRESSION */) {2413 parentCondition = parentCondition.alternate;2414 }2415 else {2416 parentCondition.alternate = createCodegenNodeForBranch(branch, sibling.branches.length - 1, context);2417 break;2418 }2419 }2420 }2421 else {2422 context.onError(createCompilerError(36 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));2423 }2424 break;2425 }2426 }2427});2428function createIfBranch(node, dir) {2429 return {2430 type: 10 /* IF_BRANCH */,2431 loc: node.loc,2432 condition: dir.name === 'else' ? undefined : dir.exp,2433 children: node.tagType === 3 /* TEMPLATE */ ? node.children : [node]2434 };2435}2436function createCodegenNodeForBranch(branch, index, context) {2437 if (branch.condition) {2438 return createConditionalExpression(branch.condition, createChildrenCodegenNode(branch, index, context), 2439 // make sure to pass in asBlock: true so that the comment node call2440 // closes the current block.2441 createCallExpression(context.helper(CREATE_COMMENT), [2442 '"v-if"' ,2443 'true'2444 ]));2445 }2446 else {2447 return createChildrenCodegenNode(branch, index, context);2448 }2449}2450function createChildrenCodegenNode(branch, index, context) {2451 const { helper } = context;2452 const keyProperty = createObjectProperty(`key`, createSimpleExpression(index + '', false));2453 const { children } = branch;2454 const child = children[0];2455 const needFragmentWrapper = children.length !== 1 || child.type !== 1 /* ELEMENT */;2456 if (needFragmentWrapper) {2457 const blockArgs = [2458 helper(FRAGMENT),2459 createObjectExpression([keyProperty]),2460 children2461 ];2462 if (children.length === 1 && child.type === 11 /* FOR */) {2463 // optimize away nested fragments when child is a ForNode2464 const forBlockArgs = child.codegenNode.expressions[1].arguments;2465 // directly use the for block's children and patchFlag2466 blockArgs[2] = forBlockArgs[2];2467 blockArgs[3] = forBlockArgs[3];2468 }2469 return createCallExpression(helper(CREATE_BLOCK), blockArgs);2470 }2471 else {2472 const childCodegen = child.codegenNode;2473 let vnodeCall = childCodegen;2474 // Element with custom directives. Locate the actual createVNode() call.2475 if (vnodeCall.callee === WITH_DIRECTIVES) {2476 vnodeCall = vnodeCall.arguments[0];2477 }2478 // Change createVNode to createBlock.2479 if (vnodeCall.callee === CREATE_VNODE) {2480 vnodeCall.callee = helper(CREATE_BLOCK);2481 }2482 // inject branch key2483 injectProp(vnodeCall, keyProperty, context);2484 return childCodegen;2485 }2486}2487const transformFor = createStructuralDirectiveTransform('for', (node, dir, context) => {2488 if (!dir.exp) {2489 context.onError(createCompilerError(37 /* X_V_FOR_NO_EXPRESSION */, dir.loc));2490 return;2491 }2492 const parseResult = parseForExpression(2493 // can only be simple expression because vFor transform is applied2494 // before expression transform.2495 dir.exp, context);2496 if (!parseResult) {2497 context.onError(createCompilerError(38 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));2498 return;2499 }2500 const { helper, addIdentifiers, removeIdentifiers, scopes } = context;2501 const { source, value, key, index } = parseResult;2502 // create the loop render function expression now, and add the2503 // iterator on exit after all children have been traversed2504 const renderExp = createCallExpression(helper(RENDER_LIST), [source]);2505 const keyProp = findProp(node, `key`);2506 const fragmentFlag = keyProp2507 ? 64 /* KEYED_FRAGMENT */2508 : 128 /* UNKEYED_FRAGMENT */;2509 const codegenNode = createSequenceExpression([2510 // fragment blocks disable tracking since they always diff their children2511 createCallExpression(helper(OPEN_BLOCK), [`false`]),2512 createCallExpression(helper(CREATE_BLOCK), [2513 helper(FRAGMENT),2514 `null`,2515 renderExp,2516 fragmentFlag + ( ` /* ${PatchFlagNames[fragmentFlag]} */` )2517 ])2518 ]);2519 context.replaceNode({2520 type: 11 /* FOR */,2521 loc: dir.loc,2522 source,2523 valueAlias: value,2524 keyAlias: key,2525 objectIndexAlias: index,2526 children: node.tagType === 3 /* TEMPLATE */ ? node.children : [node],2527 codegenNode2528 });2529 // bookkeeping2530 scopes.vFor++;2531 if ( context.prefixIdentifiers) {2532 // scope management2533 // inject identifiers to context2534 value && addIdentifiers(value);2535 key && addIdentifiers(key);2536 index && addIdentifiers(index);2537 }2538 return () => {2539 scopes.vFor--;2540 if ( context.prefixIdentifiers) {2541 value && removeIdentifiers(value);2542 key && removeIdentifiers(key);2543 index && removeIdentifiers(index);2544 }2545 // finish the codegen now that all children have been traversed2546 let childBlock;2547 const isTemplate = isTemplateNode(node);2548 const slotOutlet = isSlotOutlet(node)2549 ? node2550 : isTemplate &&2551 node.children.length === 1 &&2552 isSlotOutlet(node.children[0])2553 ? node.children[0] // api-extractor somehow fails to infer this2554 : null;2555 const keyProperty = keyProp2556 ? createObjectProperty(`key`, keyProp.type === 6 /* ATTRIBUTE */2557 ? createSimpleExpression(keyProp.value.content, true)2558 : keyProp.exp)2559 : null;2560 if (slotOutlet) {2561 // <slot v-for="..."> or <template v-for="..."><slot/></template>2562 childBlock = slotOutlet.codegenNode;2563 if (isTemplate && keyProperty) {2564 // <template v-for="..." :key="..."><slot/></template>2565 // we need to inject the key to the renderSlot() call.2566 // the props for renderSlot is passed as the 3rd argument.2567 injectProp(childBlock, keyProperty, context);2568 }2569 }2570 else if (isTemplate) {2571 // <template v-for="...">2572 // should generate a fragment block for each loop2573 childBlock = createBlockExpression(createCallExpression(helper(CREATE_BLOCK), [2574 helper(FRAGMENT),2575 keyProperty ? createObjectExpression([keyProperty]) : `null`,2576 node.children2577 ]), context);2578 }2579 else {2580 // Normal element v-for. Directly use the child's codegenNode2581 // arguments, but replace createVNode() with createBlock()2582 let codegenNode = node.codegenNode;2583 if (codegenNode.callee === WITH_DIRECTIVES) {2584 codegenNode.arguments[0].callee = helper(CREATE_BLOCK);2585 }2586 else {2587 codegenNode.callee = helper(CREATE_BLOCK);2588 }2589 childBlock = createBlockExpression(codegenNode, context);2590 }2591 renderExp.arguments.push(createFunctionExpression(createForLoopParams(parseResult), childBlock, true /* force newline */));2592 };2593});2594const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;2595// This regex doesn't cover the case if key or index aliases have destructuring,2596// but those do not make sense in the first place, so this works in practice.2597const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;2598const stripParensRE = /^\(|\)$/g;2599function parseForExpression(input, context) {2600 const loc = input.loc;2601 const exp = input.content;2602 const inMatch = exp.match(forAliasRE);2603 if (!inMatch)2604 return;2605 const [, LHS, RHS] = inMatch;2606 const result = {2607 source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),2608 value: undefined,2609 key: undefined,2610 index: undefined2611 };2612 if ( context.prefixIdentifiers) {2613 result.source = processExpression(result.source, context);2614 }2615 let valueContent = LHS.trim()2616 .replace(stripParensRE, '')2617 .trim();2618 const trimmedOffset = LHS.indexOf(valueContent);2619 const iteratorMatch = valueContent.match(forIteratorRE);2620 if (iteratorMatch) {2621 valueContent = valueContent.replace(forIteratorRE, '').trim();2622 const keyContent = iteratorMatch[1].trim();2623 let keyOffset;2624 if (keyContent) {2625 keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);2626 result.key = createAliasExpression(loc, keyContent, keyOffset);2627 if ( context.prefixIdentifiers) {2628 result.key = processExpression(result.key, context, true);2629 }2630 }2631 if (iteratorMatch[2]) {2632 const indexContent = iteratorMatch[2].trim();2633 if (indexContent) {2634 result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key2635 ? keyOffset + keyContent.length2636 : trimmedOffset + valueContent.length));2637 if ( context.prefixIdentifiers) {2638 result.index = processExpression(result.index, context, true);2639 }2640 }2641 }2642 }2643 if (valueContent) {2644 result.value = createAliasExpression(loc, valueContent, trimmedOffset);2645 if ( context.prefixIdentifiers) {2646 result.value = processExpression(result.value, context, true);2647 }2648 }2649 return result;2650}2651function createAliasExpression(range, content, offset) {2652 return createSimpleExpression(content, false, getInnerRange(range, offset, content.length));2653}2654function createForLoopParams({ value, key, index }) {2655 const params = [];2656 if (value) {2657 params.push(value);2658 }2659 if (key) {2660 if (!value) {2661 params.push(createSimpleExpression(`_`, false));2662 }2663 params.push(key);2664 }2665 if (index) {2666 if (!key) {2667 if (!value) {2668 params.push(createSimpleExpression(`_`, false));2669 }2670 params.push(createSimpleExpression(`__`, false));2671 }2672 params.push(index);2673 }2674 return params;2675}2676const isStaticExp = (p) => p.type === 4 /* SIMPLE_EXPRESSION */ && p.isStatic;2677const defaultFallback = createSimpleExpression(`undefined`, false);2678// A NodeTransform that:2679// 1. Tracks scope identifiers for scoped slots so that they don't get prefixed2680// by transformExpression. This is only applied in non-browser builds with2681// { prefixIdentifiers: true }.2682// 2. Track v-slot depths so that we know a slot is inside another slot.2683// Note the exit callback is executed before buildSlots() on the same node,2684// so only nested slots see positive numbers.2685const trackSlotScopes = (node, context) => {2686 if (node.type === 1 /* ELEMENT */ &&2687 (node.tagType === 1 /* COMPONENT */ ||2688 node.tagType === 3 /* TEMPLATE */)) {2689 // We are only checking non-empty v-slot here2690 // since we only care about slots that introduce scope variables.2691 const vSlot = findDir(node, 'slot');2692 if (vSlot) {2693 const slotProps = vSlot.exp;2694 if ( context.prefixIdentifiers) {2695 slotProps && context.addIdentifiers(slotProps);2696 }2697 context.scopes.vSlot++;2698 return () => {2699 if ( context.prefixIdentifiers) {2700 slotProps && context.removeIdentifiers(slotProps);2701 }2702 context.scopes.vSlot--;2703 };2704 }2705 }2706};2707// A NodeTransform that tracks scope identifiers for scoped slots with v-for.2708// This transform is only applied in non-browser builds with { prefixIdentifiers: true }2709const trackVForSlotScopes = (node, context) => {2710 let vFor;2711 if (isTemplateNode(node) &&2712 node.props.some(isVSlot) &&2713 (vFor = findDir(node, 'for'))) {2714 const result = (vFor.parseResult = parseForExpression(vFor.exp, context));2715 if (result) {2716 const { value, key, index } = result;2717 const { addIdentifiers, removeIdentifiers } = context;2718 value && addIdentifiers(value);2719 key && addIdentifiers(key);2720 index && addIdentifiers(index);2721 return () => {2722 value && removeIdentifiers(value);2723 key && removeIdentifiers(key);2724 index && removeIdentifiers(index);2725 };2726 }2727 }2728};2729// Instead of being a DirectiveTransform, v-slot processing is called during2730// transformElement to build the slots object for a component.2731function buildSlots(node, context) {2732 const { children, loc } = node;2733 const slotsProperties = [];2734 const dynamicSlots = [];2735 // If the slot is inside a v-for or another v-slot, force it to be dynamic2736 // since it likely uses a scope variable.2737 let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0;2738 // with `prefixIdentifiers: true`, this can be further optimized to make2739 // it dynamic only when the slot actually uses the scope variables.2740 if ( context.prefixIdentifiers) {2741 hasDynamicSlots = hasScopeRef(node, context.identifiers);2742 }2743 // 1. Check for default slot with slotProps on component itself.2744 // <Comp v-slot="{ prop }"/>2745 const explicitDefaultSlot = findDir(node, 'slot', true);2746 if (explicitDefaultSlot) {2747 const { arg, exp, loc } = explicitDefaultSlot;2748 if (arg) {2749 context.onError(createCompilerError(42 /* X_V_SLOT_NAMED_SLOT_ON_COMPONENT */, loc));2750 }2751 slotsProperties.push(buildDefaultSlot(exp, children, loc));2752 }2753 // 2. Iterate through children and check for template slots2754 // <template v-slot:foo="{ prop }">2755 let hasTemplateSlots = false;2756 let extraneousChild = undefined;2757 const seenSlotNames = new Set();2758 for (let i = 0; i < children.length; i++) {2759 const slotElement = children[i];2760 let slotDir;2761 if (!isTemplateNode(slotElement) ||2762 !(slotDir = findDir(slotElement, 'slot', true))) {2763 // not a <template v-slot>, skip.2764 if (slotElement.type !== 3 /* COMMENT */ && !extraneousChild) {2765 extraneousChild = slotElement;2766 }2767 continue;2768 }2769 if (explicitDefaultSlot) {2770 // already has on-component default slot - this is incorrect usage.2771 context.onError(createCompilerError(43 /* X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc));2772 break;2773 }2774 hasTemplateSlots = true;2775 const { children: slotChildren, loc: slotLoc } = slotElement;2776 const { arg: slotName = createSimpleExpression(`default`, true), exp: slotProps, loc: dirLoc } = slotDir;2777 // check if name is dynamic.2778 let staticSlotName;2779 if (isStaticExp(slotName)) {2780 staticSlotName = slotName ? slotName.content : `default`;2781 }2782 else {2783 hasDynamicSlots = true;2784 }2785 const slotFunction = createFunctionExpression(slotProps, slotChildren, false, slotChildren.length ? slotChildren[0].loc : slotLoc);2786 // check if this slot is conditional (v-if/v-for)2787 let vIf;2788 let vElse;2789 let vFor;2790 if ((vIf = findDir(slotElement, 'if'))) {2791 hasDynamicSlots = true;2792 dynamicSlots.push(createConditionalExpression(vIf.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback));2793 }2794 else if ((vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))) {2795 // find adjacent v-if2796 let j = i;2797 let prev;2798 while (j--) {2799 prev = children[j];2800 if (prev.type !== 3 /* COMMENT */) {2801 break;2802 }2803 }2804 if (prev && isTemplateNode(prev) && findDir(prev, 'if')) {2805 // remove node2806 children.splice(i, 1);2807 i--;2808 assert(dynamicSlots.length > 0);2809 // attach this slot to previous conditional2810 let conditional = dynamicSlots[dynamicSlots.length - 1];2811 while (conditional.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {2812 conditional = conditional.alternate;2813 }2814 conditional.alternate = vElse.exp2815 ? createConditionalExpression(vElse.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback)2816 : buildDynamicSlot(slotName, slotFunction);2817 }2818 else {2819 context.onError(createCompilerError(36 /* X_V_ELSE_NO_ADJACENT_IF */, vElse.loc));2820 }2821 }2822 else if ((vFor = findDir(slotElement, 'for'))) {2823 hasDynamicSlots = true;2824 const parseResult = vFor.parseResult ||2825 parseForExpression(vFor.exp, context);2826 if (parseResult) {2827 // Render the dynamic slots as an array and add it to the createSlot()2828 // args. The runtime knows how to handle it appropriately.2829 dynamicSlots.push(createCallExpression(context.helper(RENDER_LIST), [2830 parseResult.source,2831 createFunctionExpression(createForLoopParams(parseResult), buildDynamicSlot(slotName, slotFunction), true)2832 ]));2833 }2834 else {2835 context.onError(createCompilerError(38 /* X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc));2836 }2837 }2838 else {2839 // check duplicate static names2840 if (staticSlotName) {2841 if (seenSlotNames.has(staticSlotName)) {2842 context.onError(createCompilerError(44 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc));2843 continue;2844 }2845 seenSlotNames.add(staticSlotName);2846 }2847 slotsProperties.push(createObjectProperty(slotName, slotFunction));2848 }2849 }2850 if (hasTemplateSlots && extraneousChild) {2851 context.onError(createCompilerError(45 /* X_V_SLOT_EXTRANEOUS_NON_SLOT_CHILDREN */, extraneousChild.loc));2852 }2853 if (!explicitDefaultSlot && !hasTemplateSlots) {2854 // implicit default slot.2855 slotsProperties.push(buildDefaultSlot(undefined, children, loc));2856 }2857 let slots = createObjectExpression(slotsProperties.concat(createObjectProperty(`_compiled`, createSimpleExpression(`true`, false))), loc);2858 if (dynamicSlots.length) {2859 slots = createCallExpression(context.helper(CREATE_SLOTS), [2860 slots,2861 createArrayExpression(dynamicSlots)2862 ]);2863 }2864 return {2865 slots,2866 hasDynamicSlots2867 };2868}2869function buildDefaultSlot(slotProps, children, loc) {2870 return createObjectProperty(`default`, createFunctionExpression(slotProps, children, false, children.length ? children[0].loc : loc));2871}2872function buildDynamicSlot(name, fn) {2873 return createObjectExpression([2874 createObjectProperty(`name`, name),2875 createObjectProperty(`fn`, fn)2876 ]);2877}2878// some directive transforms (e.g. v-model) may return a symbol for runtime2879// import, which should be used instead of a resolveDirective call.2880const directiveImportMap = new WeakMap();2881// generate a JavaScript AST for this element's codegen2882const transformElement = (node, context) => {2883 if (node.type !== 1 /* ELEMENT */ ||2884 // handled by transformSlotOutlet2885 node.tagType === 2 /* SLOT */ ||2886 // <template v-if/v-for> should have already been replaced2887 // <templte v-slot> is handled by buildSlots2888 (node.tagType === 3 /* TEMPLATE */ && node.props.some(isVSlot))) {2889 return;2890 }2891 // perform the work on exit, after all child expressions have been2892 // processed and merged.2893 return () => {2894 const isComponent = node.tagType === 1 /* COMPONENT */;2895 let hasProps = node.props.length > 0;2896 let patchFlag = 0;2897 let runtimeDirectives;2898 let dynamicPropNames;2899 let dynamicComponent;2900 // handle dynamic component2901 const isProp = findProp(node, 'is');2902 if (node.tag === 'component') {2903 if (isProp) {2904 // static <component is="foo" />2905 if (isProp.type === 6 /* ATTRIBUTE */) {2906 const tag = isProp.value && isProp.value.content;2907 if (tag) {2908 context.helper(RESOLVE_COMPONENT);2909 context.components.add(tag);2910 dynamicComponent = toValidAssetId(tag, `component`);2911 }2912 }2913 // dynamic <component :is="asdf" />2914 else if (isProp.exp) {2915 dynamicComponent = createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [isProp.exp]);2916 }2917 }2918 }2919 if (isComponent && !dynamicComponent) {2920 context.helper(RESOLVE_COMPONENT);2921 context.components.add(node.tag);2922 }2923 const args = [2924 dynamicComponent2925 ? dynamicComponent2926 : isComponent2927 ? toValidAssetId(node.tag, `component`)2928 : node.tagType === 4 /* PORTAL */2929 ? context.helper(PORTAL)2930 : node.tagType === 5 /* SUSPENSE */2931 ? context.helper(SUSPENSE)2932 : `"${node.tag}"`2933 ];2934 // props2935 if (hasProps) {2936 const propsBuildResult = buildProps(node, context, 2937 // skip reserved "is" prop <component is>2938 node.props.filter(p => p !== isProp));2939 patchFlag = propsBuildResult.patchFlag;2940 dynamicPropNames = propsBuildResult.dynamicPropNames;2941 runtimeDirectives = propsBuildResult.directives;2942 if (!propsBuildResult.props) {2943 hasProps = false;2944 }2945 else {2946 args.push(propsBuildResult.props);2947 }2948 }2949 // children2950 const hasChildren = node.children.length > 0;2951 if (hasChildren) {2952 if (!hasProps) {2953 args.push(`null`);2954 }2955 if (isComponent || node.tagType === 5 /* SUSPENSE */) {2956 const { slots, hasDynamicSlots } = buildSlots(node, context);2957 args.push(slots);2958 if (hasDynamicSlots) {2959 patchFlag |= 256 /* DYNAMIC_SLOTS */;2960 }2961 }2962 else if (node.children.length === 1) {2963 const child = node.children[0];2964 const type = child.type;2965 // check for dynamic text children2966 const hasDynamicTextChild = type === 5 /* INTERPOLATION */ ||2967 type === 8 /* COMPOUND_EXPRESSION */;2968 if (hasDynamicTextChild && !isStaticNode(child)) {2969 patchFlag |= 1 /* TEXT */;2970 }2971 // pass directly if the only child is a text node2972 // (plain / interpolation / expression)2973 if (hasDynamicTextChild || type === 2 /* TEXT */) {2974 args.push(child);2975 }2976 else {2977 args.push(node.children);2978 }2979 }2980 else {2981 args.push(node.children);2982 }2983 }2984 // patchFlag & dynamicPropNames2985 if (patchFlag !== 0) {2986 if (!hasChildren) {2987 if (!hasProps) {2988 args.push(`null`);2989 }2990 args.push(`null`);2991 }2992 {2993 const flagNames = Object.keys(PatchFlagNames)2994 .map(Number)2995 .filter(n => n > 0 && patchFlag & n)2996 .map(n => PatchFlagNames[n])2997 .join(`, `);2998 args.push(patchFlag + ` /* ${flagNames} */`);2999 }3000 if (dynamicPropNames && dynamicPropNames.length) {3001 args.push(`[${dynamicPropNames.map(n => JSON.stringify(n)).join(`, `)}]`);3002 }3003 }3004 const { loc } = node;3005 const vnode = createCallExpression(context.helper(CREATE_VNODE), args, loc);3006 if (runtimeDirectives && runtimeDirectives.length) {3007 node.codegenNode = createCallExpression(context.helper(WITH_DIRECTIVES), [3008 vnode,3009 createArrayExpression(runtimeDirectives.map(dir => buildDirectiveArgs(dir, context)), loc)3010 ], loc);3011 }3012 else {3013 node.codegenNode = vnode;3014 }3015 };3016};3017function buildProps(node, context, props = node.props) {3018 const elementLoc = node.loc;3019 const isComponent = node.tagType === 1 /* COMPONENT */;3020 let properties = [];3021 const mergeArgs = [];3022 const runtimeDirectives = [];3023 // patchFlag analysis3024 let patchFlag = 0;3025 let hasRef = false;3026 let hasClassBinding = false;3027 let hasStyleBinding = false;3028 let hasDynamicKeys = false;3029 const dynamicPropNames = [];3030 const analyzePatchFlag = ({ key, value }) => {3031 if (key.type === 4 /* SIMPLE_EXPRESSION */ && key.isStatic) {3032 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||3033 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||3034 value.type === 8 /* COMPOUND_EXPRESSION */) &&3035 isStaticNode(value))) {3036 return;3037 }3038 const name = key.content;3039 if (name === 'ref') {3040 hasRef = true;3041 }3042 else if (name === 'class') {3043 hasClassBinding = true;3044 }3045 else if (name === 'style') {3046 hasStyleBinding = true;3047 }3048 else if (name !== 'key') {3049 dynamicPropNames.push(name);3050 }3051 }3052 else {3053 hasDynamicKeys = true;3054 }3055 };3056 for (let i = 0; i < props.length; i++) {3057 // static attribute3058 const prop = props[i];3059 if (prop.type === 6 /* ATTRIBUTE */) {3060 const { loc, name, value } = prop;3061 if (name === 'ref') {3062 hasRef = true;3063 }3064 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', true, value ? value.loc : loc)));3065 }3066 else {3067 // directives3068 const { name, arg, exp, loc } = prop;3069 // skip v-slot - it is handled by its dedicated transform.3070 if (name === 'slot') {3071 if (!isComponent) {3072 context.onError(createCompilerError(46 /* X_V_SLOT_MISPLACED */, loc));3073 }3074 continue;3075 }3076 // skip v-once - it is handled by its dedicated transform.3077 if (name === 'once') {3078 continue;3079 }3080 // special case for v-bind and v-on with no argument3081 const isBind = name === 'bind';3082 const isOn = name === 'on';3083 if (!arg && (isBind || isOn)) {3084 hasDynamicKeys = true;3085 if (exp) {3086 if (properties.length) {3087 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3088 properties = [];3089 }3090 if (isBind) {3091 mergeArgs.push(exp);3092 }3093 else {3094 // v-on="obj" -> toHandlers(obj)3095 mergeArgs.push({3096 type: 13 /* JS_CALL_EXPRESSION */,3097 loc,3098 callee: context.helper(TO_HANDLERS),3099 arguments: [exp]3100 });3101 }3102 }3103 else {3104 context.onError(createCompilerError(isBind3105 ? 39 /* X_V_BIND_NO_EXPRESSION */3106 : 40 /* X_V_ON_NO_EXPRESSION */, loc));3107 }3108 continue;3109 }3110 const directiveTransform = context.directiveTransforms[name];3111 if (directiveTransform) {3112 // has built-in directive transform.3113 const { props, needRuntime } = directiveTransform(prop, node, context);3114 props.forEach(analyzePatchFlag);3115 properties.push(...props);3116 if (needRuntime) {3117 runtimeDirectives.push(prop);3118 if (isSymbol(needRuntime)) {3119 directiveImportMap.set(prop, needRuntime);3120 }3121 }3122 }3123 else {3124 // no built-in transform, this is a user custom directive.3125 runtimeDirectives.push(prop);3126 }3127 }3128 }3129 let propsExpression = undefined;3130 // has v-bind="object" or v-on="object", wrap with mergeProps3131 if (mergeArgs.length) {3132 if (properties.length) {3133 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3134 }3135 if (mergeArgs.length > 1) {3136 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);3137 }3138 else {3139 // single v-bind with nothing else - no need for a mergeProps call3140 propsExpression = mergeArgs[0];3141 }3142 }3143 else if (properties.length) {3144 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);3145 }3146 // patchFlag analysis3147 if (hasDynamicKeys) {3148 patchFlag |= 16 /* FULL_PROPS */;3149 }3150 else {3151 if (hasClassBinding) {3152 patchFlag |= 2 /* CLASS */;3153 }3154 if (hasStyleBinding) {3155 patchFlag |= 4 /* STYLE */;3156 }3157 if (dynamicPropNames.length) {3158 patchFlag |= 8 /* PROPS */;3159 }3160 }3161 if (patchFlag === 0 && (hasRef || runtimeDirectives.length > 0)) {3162 patchFlag |= 32 /* NEED_PATCH */;3163 }3164 return {3165 props: propsExpression,3166 directives: runtimeDirectives,3167 patchFlag,3168 dynamicPropNames3169 };3170}3171// Dedupe props in an object literal.3172// Literal duplicated attributes would have been warned during the parse phase,3173// however, it's possible to encounter duplicated `onXXX` handlers with different3174// modifiers. We also need to merge static and dynamic class / style attributes.3175// - onXXX handlers / style: merge into array3176// - class: merge into single expression with concatenation3177function dedupeProperties(properties) {3178 const knownProps = {};3179 const deduped = [];3180 for (let i = 0; i < properties.length; i++) {3181 const prop = properties[i];3182 // dynamic keys are always allowed3183 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {3184 deduped.push(prop);3185 continue;3186 }3187 const name = prop.key.content;3188 const existing = knownProps[name];3189 if (existing) {3190 if (name === 'style' ||3191 name === 'class' ||3192 name.startsWith('on') ||3193 name.startsWith('vnode')) {3194 mergeAsArray(existing, prop);3195 }3196 // unexpected duplicate, should have emitted error during parse3197 }3198 else {3199 knownProps[name] = prop;3200 deduped.push(prop);3201 }3202 }3203 return deduped;3204}3205function mergeAsArray(existing, incoming) {3206 if (existing.value.type === 16 /* JS_ARRAY_EXPRESSION */) {3207 existing.value.elements.push(incoming.value);3208 }3209 else {3210 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);3211 }3212}3213function buildDirectiveArgs(dir, context) {3214 const dirArgs = [];3215 const runtime = directiveImportMap.get(dir);3216 if (runtime) {3217 context.helper(runtime);3218 dirArgs.push(context.helperString(runtime));3219 }3220 else {3221 // inject statement for resolving directive3222 context.helper(RESOLVE_DIRECTIVE);3223 context.directives.add(dir.name);3224 dirArgs.push(toValidAssetId(dir.name, `directive`));3225 }3226 const { loc } = dir;3227 if (dir.exp)3228 dirArgs.push(dir.exp);3229 if (dir.arg) {3230 if (!dir.exp) {3231 dirArgs.push(`void 0`);3232 }3233 dirArgs.push(dir.arg);3234 }3235 if (Object.keys(dir.modifiers).length) {3236 if (!dir.arg) {3237 if (!dir.exp) {3238 dirArgs.push(`void 0`);...
compiler-core.cjs.prod.js
Source:compiler-core.cjs.prod.js
...425 else {426 node.arguments[1] = propsWithInjection;427 }428}429function toValidAssetId(name, type) {430 return `_${type}_${name.replace(/[^\w]/g, '_')}`;431}432// Check if a node contains expressions that reference current context scope ids433function hasScopeRef(node, ids) {434 if (!node || Object.keys(ids).length === 0) {435 return false;436 }437 switch (node.type) {438 case 1 /* ELEMENT */:439 for (let i = 0; i < node.props.length; i++) {440 const p = node.props[i];441 if (p.type === 7 /* DIRECTIVE */ &&442 (hasScopeRef(p.arg, ids) || hasScopeRef(p.exp, ids))) {443 return true;444 }445 }446 return node.children.some(c => hasScopeRef(c, ids));447 case 11 /* FOR */:448 if (hasScopeRef(node.source, ids)) {449 return true;450 }451 return node.children.some(c => hasScopeRef(c, ids));452 case 9 /* IF */:453 return node.branches.some(b => hasScopeRef(b, ids));454 case 10 /* IF_BRANCH */:455 if (hasScopeRef(node.condition, ids)) {456 return true;457 }458 return node.children.some(c => hasScopeRef(c, ids));459 case 4 /* SIMPLE_EXPRESSION */:460 return (!node.isStatic &&461 isSimpleIdentifier(node.content) &&462 !!ids[node.content]);463 case 8 /* COMPOUND_EXPRESSION */:464 return node.children.some(c => isObject(c) && hasScopeRef(c, ids));465 case 5 /* INTERPOLATION */:466 case 12 /* TEXT_CALL */:467 return hasScopeRef(node.content, ids);468 case 2 /* TEXT */:469 case 3 /* COMMENT */:470 return false;471 default:472 return false;473 }474}475const defaultParserOptions = {476 delimiters: [`{{`, `}}`],477 getNamespace: () => 0 /* HTML */,478 getTextMode: () => 0 /* DATA */,479 isVoidTag: NO,480 isPreTag: NO,481 isCustomElement: NO,482 namedCharacterReferences: {483 'gt;': '>',484 'lt;': '<',485 'amp;': '&',486 'apos;': "'",487 'quot;': '"'488 },489 onError: defaultOnError490};491function parse(content, options = {}) {492 const context = createParserContext(content, options);493 const start = getCursor(context);494 return {495 type: 0 /* ROOT */,496 children: parseChildren(context, 0 /* DATA */, []),497 helpers: [],498 components: [],499 directives: [],500 hoists: [],501 cached: 0,502 codegenNode: undefined,503 loc: getSelection(context, start)504 };505}506function createParserContext(content, options) {507 return {508 options: {509 ...defaultParserOptions,510 ...options511 },512 column: 1,513 line: 1,514 offset: 0,515 originalSource: content,516 source: content,517 maxCRNameLength: Object.keys(options.namedCharacterReferences ||518 defaultParserOptions.namedCharacterReferences).reduce((max, name) => Math.max(max, name.length), 0),519 inPre: false520 };521}522function parseChildren(context, mode, ancestors) {523 const parent = last(ancestors);524 const ns = parent ? parent.ns : 0 /* HTML */;525 const nodes = [];526 while (!isEnd(context, mode, ancestors)) {527 const s = context.source;528 let node = undefined;529 if (!context.inPre && startsWith(s, context.options.delimiters[0])) {530 // '{{'531 node = parseInterpolation(context, mode);532 }533 else if (mode === 0 /* DATA */ && s[0] === '<') {534 // https://html.spec.whatwg.org/multipage/parsing.html#tag-open-state535 if (s.length === 1) {536 emitError(context, 8 /* EOF_BEFORE_TAG_NAME */, 1);537 }538 else if (s[1] === '!') {539 // https://html.spec.whatwg.org/multipage/parsing.html#markup-declaration-open-state540 if (startsWith(s, '<!--')) {541 node = parseComment(context);542 }543 else if (startsWith(s, '<!DOCTYPE')) {544 // Ignore DOCTYPE by a limitation.545 node = parseBogusComment(context);546 }547 else if (startsWith(s, '<![CDATA[')) {548 if (ns !== 0 /* HTML */) {549 node = parseCDATA(context, ancestors);550 }551 else {552 emitError(context, 2 /* CDATA_IN_HTML_CONTENT */);553 node = parseBogusComment(context);554 }555 }556 else {557 emitError(context, 14 /* INCORRECTLY_OPENED_COMMENT */);558 node = parseBogusComment(context);559 }560 }561 else if (s[1] === '/') {562 // https://html.spec.whatwg.org/multipage/parsing.html#end-tag-open-state563 if (s.length === 2) {564 emitError(context, 8 /* EOF_BEFORE_TAG_NAME */, 2);565 }566 else if (s[2] === '>') {567 emitError(context, 17 /* MISSING_END_TAG_NAME */, 2);568 advanceBy(context, 3);569 continue;570 }571 else if (/[a-z]/i.test(s[2])) {572 emitError(context, 31 /* X_INVALID_END_TAG */);573 parseTag(context, 1 /* End */, parent);574 continue;575 }576 else {577 emitError(context, 15 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 2);578 node = parseBogusComment(context);579 }580 }581 else if (/[a-z]/i.test(s[1])) {582 node = parseElement(context, ancestors);583 }584 else if (s[1] === '?') {585 emitError(context, 28 /* UNEXPECTED_QUESTION_MARK_INSTEAD_OF_TAG_NAME */, 1);586 node = parseBogusComment(context);587 }588 else {589 emitError(context, 15 /* INVALID_FIRST_CHARACTER_OF_TAG_NAME */, 1);590 }591 }592 if (!node) {593 node = parseText(context, mode);594 }595 if (Array.isArray(node)) {596 for (let i = 0; i < node.length; i++) {597 pushNode(nodes, node[i]);598 }599 }600 else {601 pushNode(nodes, node);602 }603 }604 // Whitespace management for more efficient output605 // (same as v2 whitespance: 'condense')606 let removedWhitespace = false;607 if (!parent || !context.options.isPreTag(parent.tag)) {608 for (let i = 0; i < nodes.length; i++) {609 const node = nodes[i];610 if (node.type === 2 /* TEXT */) {611 if (!node.content.trim()) {612 const prev = nodes[i - 1];613 const next = nodes[i + 1];614 // If:615 // - the whitespace is the first or last node, or:616 // - the whitespace is adjacent to a comment, or:617 // - the whitespace is between two elements AND contains newline618 // Then the whitespace is ignored.619 if (!prev ||620 !next ||621 prev.type === 3 /* COMMENT */ ||622 next.type === 3 /* COMMENT */ ||623 (prev.type === 1 /* ELEMENT */ &&624 next.type === 1 /* ELEMENT */ &&625 /[\r\n]/.test(node.content))) {626 removedWhitespace = true;627 nodes[i] = null;628 }629 else {630 // Otherwise, condensed consecutive whitespace inside the text down to631 // a single space632 node.content = ' ';633 }634 }635 else {636 node.content = node.content.replace(/\s+/g, ' ');637 }638 }639 }640 }641 return removedWhitespace ? nodes.filter(node => node !== null) : nodes;642}643function pushNode(nodes, node) {644 // ignore comments in production645 /* istanbul ignore next */646 if ( node.type === 3 /* COMMENT */) {647 return;648 }649 if (node.type === 2 /* TEXT */) {650 const prev = last(nodes);651 // Merge if both this and the previous node are text and those are652 // consecutive. This happens for cases like "a < b".653 if (prev &&654 prev.type === 2 /* TEXT */ &&655 prev.loc.end.offset === node.loc.start.offset) {656 prev.content += node.content;657 prev.loc.end = node.loc.end;658 prev.loc.source += node.loc.source;659 return;660 }661 }662 nodes.push(node);663}664function parseCDATA(context, ancestors) {665 advanceBy(context, 9);666 const nodes = parseChildren(context, 3 /* CDATA */, ancestors);667 if (context.source.length === 0) {668 emitError(context, 9 /* EOF_IN_CDATA */);669 }670 else {671 advanceBy(context, 3);672 }673 return nodes;674}675function parseComment(context) {676 const start = getCursor(context);677 let content;678 // Regular comment.679 const match = /--(\!)?>/.exec(context.source);680 if (!match) {681 content = context.source.slice(4);682 advanceBy(context, context.source.length);683 emitError(context, 10 /* EOF_IN_COMMENT */);684 }685 else {686 if (match.index <= 3) {687 emitError(context, 0 /* ABRUPT_CLOSING_OF_EMPTY_COMMENT */);688 }689 if (match[1]) {690 emitError(context, 13 /* INCORRECTLY_CLOSED_COMMENT */);691 }692 content = context.source.slice(4, match.index);693 // Advancing with reporting nested comments.694 const s = context.source.slice(0, match.index);695 let prevIndex = 1, nestedIndex = 0;696 while ((nestedIndex = s.indexOf('<!--', prevIndex)) !== -1) {697 advanceBy(context, nestedIndex - prevIndex + 1);698 if (nestedIndex + 4 < s.length) {699 emitError(context, 20 /* NESTED_COMMENT */);700 }701 prevIndex = nestedIndex + 1;702 }703 advanceBy(context, match.index + match[0].length - prevIndex + 1);704 }705 return {706 type: 3 /* COMMENT */,707 content,708 loc: getSelection(context, start)709 };710}711function parseBogusComment(context) {712 const start = getCursor(context);713 const contentStart = context.source[1] === '?' ? 1 : 2;714 let content;715 const closeIndex = context.source.indexOf('>');716 if (closeIndex === -1) {717 content = context.source.slice(contentStart);718 advanceBy(context, context.source.length);719 }720 else {721 content = context.source.slice(contentStart, closeIndex);722 advanceBy(context, closeIndex + 1);723 }724 return {725 type: 3 /* COMMENT */,726 content,727 loc: getSelection(context, start)728 };729}730function parseElement(context, ancestors) {731 // Start tag.732 const wasInPre = context.inPre;733 const parent = last(ancestors);734 const element = parseTag(context, 0 /* Start */, parent);735 const isPreBoundary = context.inPre && !wasInPre;736 if (element.isSelfClosing || context.options.isVoidTag(element.tag)) {737 return element;738 }739 // Children.740 ancestors.push(element);741 const mode = context.options.getTextMode(element.tag, element.ns);742 const children = parseChildren(context, mode, ancestors);743 ancestors.pop();744 element.children = children;745 // End tag.746 if (startsWithEndTagOpen(context.source, element.tag)) {747 parseTag(context, 1 /* End */, parent);748 }749 else {750 emitError(context, 32 /* X_MISSING_END_TAG */);751 if (context.source.length === 0 && element.tag.toLowerCase() === 'script') {752 const first = children[0];753 if (first && startsWith(first.loc.source, '<!--')) {754 emitError(context, 11 /* EOF_IN_SCRIPT_HTML_COMMENT_LIKE_TEXT */);755 }756 }757 }758 element.loc = getSelection(context, element.loc.start);759 if (isPreBoundary) {760 context.inPre = false;761 }762 return element;763}764/**765 * Parse a tag (E.g. `<div id=a>`) with that type (start tag or end tag).766 */767function parseTag(context, type, parent) {768 // Tag open.769 const start = getCursor(context);770 const match = /^<\/?([a-z][^\t\r\n\f />]*)/i.exec(context.source);771 const tag = match[1];772 const ns = context.options.getNamespace(tag, parent);773 advanceBy(context, match[0].length);774 advanceSpaces(context);775 // save current state in case we need to re-parse attributes with v-pre776 const cursor = getCursor(context);777 const currentSource = context.source;778 // Attributes.779 let props = parseAttributes(context, type);780 // check v-pre781 if (!context.inPre &&782 props.some(p => p.type === 7 /* DIRECTIVE */ && p.name === 'pre')) {783 context.inPre = true;784 // reset context785 extend(context, cursor);786 context.source = currentSource;787 // re-parse attrs and filter out v-pre itself788 props = parseAttributes(context, type).filter(p => p.name !== 'v-pre');789 }790 // Tag close.791 let isSelfClosing = false;792 if (context.source.length === 0) {793 emitError(context, 12 /* EOF_IN_TAG */);794 }795 else {796 isSelfClosing = startsWith(context.source, '/>');797 if (type === 1 /* End */ && isSelfClosing) {798 emitError(context, 7 /* END_TAG_WITH_TRAILING_SOLIDUS */);799 }800 advanceBy(context, isSelfClosing ? 2 : 1);801 }802 let tagType = 0 /* ELEMENT */;803 if (!context.inPre && !context.options.isCustomElement(tag)) {804 if (context.options.isNativeTag) {805 if (!context.options.isNativeTag(tag))806 tagType = 1 /* COMPONENT */;807 }808 else {809 if (/^[A-Z]/.test(tag))810 tagType = 1 /* COMPONENT */;811 }812 if (tag === 'slot')813 tagType = 2 /* SLOT */;814 else if (tag === 'template')815 tagType = 3 /* TEMPLATE */;816 else if (tag === 'portal' || tag === 'Portal')817 tagType = 4 /* PORTAL */;818 else if (tag === 'suspense' || tag === 'Suspense')819 tagType = 5 /* SUSPENSE */;820 }821 return {822 type: 1 /* ELEMENT */,823 ns,824 tag,825 tagType,826 props,827 isSelfClosing,828 children: [],829 loc: getSelection(context, start),830 codegenNode: undefined // to be created during transform phase831 };832}833function parseAttributes(context, type) {834 const props = [];835 const attributeNames = new Set();836 while (context.source.length > 0 &&837 !startsWith(context.source, '>') &&838 !startsWith(context.source, '/>')) {839 if (startsWith(context.source, '/')) {840 emitError(context, 29 /* UNEXPECTED_SOLIDUS_IN_TAG */);841 advanceBy(context, 1);842 advanceSpaces(context);843 continue;844 }845 if (type === 1 /* End */) {846 emitError(context, 6 /* END_TAG_WITH_ATTRIBUTES */);847 }848 const attr = parseAttribute(context, attributeNames);849 if (type === 0 /* Start */) {850 props.push(attr);851 }852 if (/^[^\t\r\n\f />]/.test(context.source)) {853 emitError(context, 19 /* MISSING_WHITESPACE_BETWEEN_ATTRIBUTES */);854 }855 advanceSpaces(context);856 }857 return props;858}859function parseAttribute(context, nameSet) {860 // Name.861 const start = getCursor(context);862 const match = /^[^\t\r\n\f />][^\t\r\n\f />=]*/.exec(context.source);863 const name = match[0];864 if (nameSet.has(name)) {865 emitError(context, 5 /* DUPLICATE_ATTRIBUTE */);866 }867 nameSet.add(name);868 if (name[0] === '=') {869 emitError(context, 26 /* UNEXPECTED_EQUALS_SIGN_BEFORE_ATTRIBUTE_NAME */);870 }871 {872 const pattern = /["'<]/g;873 let m;874 while ((m = pattern.exec(name)) !== null) {875 emitError(context, 24 /* UNEXPECTED_CHARACTER_IN_ATTRIBUTE_NAME */, m.index);876 }877 }878 advanceBy(context, name.length);879 // Value880 let value = undefined;881 if (/^[\t\r\n\f ]*=/.test(context.source)) {882 advanceSpaces(context);883 advanceBy(context, 1);884 advanceSpaces(context);885 value = parseAttributeValue(context);886 if (!value) {887 emitError(context, 16 /* MISSING_ATTRIBUTE_VALUE */);888 }889 }890 const loc = getSelection(context, start);891 if (!context.inPre && /^(v-|:|@|#)/.test(name)) {892 const match = /(?:^v-([a-z0-9-]+))?(?:(?::|^@|^#)([^\.]+))?(.+)?$/i.exec(name);893 let arg;894 if (match[2]) {895 const startOffset = name.split(match[2], 2).shift().length;896 const loc = getSelection(context, getNewPosition(context, start, startOffset), getNewPosition(context, start, startOffset + match[2].length));897 let content = match[2];898 let isStatic = true;899 if (content.startsWith('[')) {900 isStatic = false;901 if (!content.endsWith(']')) {902 emitError(context, 34 /* X_MISSING_DYNAMIC_DIRECTIVE_ARGUMENT_END */);903 }904 content = content.substr(1, content.length - 2);905 }906 arg = {907 type: 4 /* SIMPLE_EXPRESSION */,908 content,909 isStatic,910 isConstant: isStatic,911 loc912 };913 }914 if (value && value.isQuoted) {915 const valueLoc = value.loc;916 valueLoc.start.offset++;917 valueLoc.start.column++;918 valueLoc.end = advancePositionWithClone(valueLoc.start, value.content);919 valueLoc.source = valueLoc.source.slice(1, -1);920 }921 return {922 type: 7 /* DIRECTIVE */,923 name: match[1] ||924 (startsWith(name, ':')925 ? 'bind'926 : startsWith(name, '@')927 ? 'on'928 : 'slot'),929 exp: value && {930 type: 4 /* SIMPLE_EXPRESSION */,931 content: value.content,932 isStatic: false,933 // Treat as non-constant by default. This can be potentially set to934 // true by `transformExpression` to make it eligible for hoisting.935 isConstant: false,936 loc: value.loc937 },938 arg,939 modifiers: match[3] ? match[3].substr(1).split('.') : [],940 loc941 };942 }943 return {944 type: 6 /* ATTRIBUTE */,945 name,946 value: value && {947 type: 2 /* TEXT */,948 content: value.content,949 loc: value.loc950 },951 loc952 };953}954function parseAttributeValue(context) {955 const start = getCursor(context);956 let content;957 const quote = context.source[0];958 const isQuoted = quote === `"` || quote === `'`;959 if (isQuoted) {960 // Quoted value.961 advanceBy(context, 1);962 const endIndex = context.source.indexOf(quote);963 if (endIndex === -1) {964 content = parseTextData(context, context.source.length, 4 /* ATTRIBUTE_VALUE */);965 }966 else {967 content = parseTextData(context, endIndex, 4 /* ATTRIBUTE_VALUE */);968 advanceBy(context, 1);969 }970 }971 else {972 // Unquoted973 const match = /^[^\t\r\n\f >]+/.exec(context.source);974 if (!match) {975 return undefined;976 }977 let unexpectedChars = /["'<=`]/g;978 let m;979 while ((m = unexpectedChars.exec(match[0])) !== null) {980 emitError(context, 25 /* UNEXPECTED_CHARACTER_IN_UNQUOTED_ATTRIBUTE_VALUE */, m.index);981 }982 content = parseTextData(context, match[0].length, 4 /* ATTRIBUTE_VALUE */);983 }984 return { content, isQuoted, loc: getSelection(context, start) };985}986function parseInterpolation(context, mode) {987 const [open, close] = context.options.delimiters;988 const closeIndex = context.source.indexOf(close, open.length);989 if (closeIndex === -1) {990 emitError(context, 33 /* X_MISSING_INTERPOLATION_END */);991 return undefined;992 }993 const start = getCursor(context);994 advanceBy(context, open.length);995 const innerStart = getCursor(context);996 const innerEnd = getCursor(context);997 const rawContentLength = closeIndex - open.length;998 const rawContent = context.source.slice(0, rawContentLength);999 const preTrimContent = parseTextData(context, rawContentLength, mode);1000 const content = preTrimContent.trim();1001 const startOffset = preTrimContent.indexOf(content);1002 if (startOffset > 0) {1003 advancePositionWithMutation(innerStart, rawContent, startOffset);1004 }1005 const endOffset = rawContentLength - (preTrimContent.length - content.length - startOffset);1006 advancePositionWithMutation(innerEnd, rawContent, endOffset);1007 advanceBy(context, close.length);1008 return {1009 type: 5 /* INTERPOLATION */,1010 content: {1011 type: 4 /* SIMPLE_EXPRESSION */,1012 isStatic: false,1013 // Set `isConstant` to false by default and will decide in transformExpression1014 isConstant: false,1015 content,1016 loc: getSelection(context, innerStart, innerEnd)1017 },1018 loc: getSelection(context, start)1019 };1020}1021function parseText(context, mode) {1022 const [open] = context.options.delimiters;1023 // TODO could probably use some perf optimization1024 const endIndex = Math.min(...[1025 context.source.indexOf('<', 1),1026 context.source.indexOf(open, 1),1027 mode === 3 /* CDATA */ ? context.source.indexOf(']]>') : -1,1028 context.source.length1029 ].filter(n => n !== -1));1030 const start = getCursor(context);1031 const content = parseTextData(context, endIndex, mode);1032 return {1033 type: 2 /* TEXT */,1034 content,1035 loc: getSelection(context, start)1036 };1037}1038/**1039 * Get text data with a given length from the current location.1040 * This translates HTML entities in the text data.1041 */1042function parseTextData(context, length, mode) {1043 if (mode === 2 /* RAWTEXT */ || mode === 3 /* CDATA */) {1044 const text = context.source.slice(0, length);1045 advanceBy(context, length);1046 return text;1047 }1048 // DATA or RCDATA. Entity decoding required.1049 const end = context.offset + length;1050 let text = '';1051 while (context.offset < end) {1052 const head = /&(?:#x?)?/i.exec(context.source);1053 if (!head || context.offset + head.index >= end) {1054 const remaining = end - context.offset;1055 text += context.source.slice(0, remaining);1056 advanceBy(context, remaining);1057 break;1058 }1059 // Advance to the "&".1060 text += context.source.slice(0, head.index);1061 advanceBy(context, head.index);1062 if (head[0] === '&') {1063 // Named character reference.1064 let name = '', value = undefined;1065 if (/[0-9a-z]/i.test(context.source[1])) {1066 for (let length = context.maxCRNameLength; !value && length > 0; --length) {1067 name = context.source.substr(1, length);1068 value = context.options.namedCharacterReferences[name];1069 }1070 if (value) {1071 const semi = name.endsWith(';');1072 if (mode === 4 /* ATTRIBUTE_VALUE */ &&1073 !semi &&1074 /[=a-z0-9]/i.test(context.source[1 + name.length] || '')) {1075 text += '&';1076 text += name;1077 advanceBy(context, 1 + name.length);1078 }1079 else {1080 text += value;1081 advanceBy(context, 1 + name.length);1082 if (!semi) {1083 emitError(context, 18 /* MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE */);1084 }1085 }1086 }1087 else {1088 emitError(context, 30 /* UNKNOWN_NAMED_CHARACTER_REFERENCE */);1089 text += '&';1090 text += name;1091 advanceBy(context, 1 + name.length);1092 }1093 }1094 else {1095 text += '&';1096 advanceBy(context, 1);1097 }1098 }1099 else {1100 // Numeric character reference.1101 const hex = head[0] === '&#x';1102 const pattern = hex ? /^&#x([0-9a-f]+);?/i : /^&#([0-9]+);?/;1103 const body = pattern.exec(context.source);1104 if (!body) {1105 text += head[0];1106 emitError(context, 1 /* ABSENCE_OF_DIGITS_IN_NUMERIC_CHARACTER_REFERENCE */);1107 advanceBy(context, head[0].length);1108 }1109 else {1110 // https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state1111 let cp = Number.parseInt(body[1], hex ? 16 : 10);1112 if (cp === 0) {1113 emitError(context, 22 /* NULL_CHARACTER_REFERENCE */);1114 cp = 0xfffd;1115 }1116 else if (cp > 0x10ffff) {1117 emitError(context, 3 /* CHARACTER_REFERENCE_OUTSIDE_UNICODE_RANGE */);1118 cp = 0xfffd;1119 }1120 else if (cp >= 0xd800 && cp <= 0xdfff) {1121 emitError(context, 23 /* SURROGATE_CHARACTER_REFERENCE */);1122 cp = 0xfffd;1123 }1124 else if ((cp >= 0xfdd0 && cp <= 0xfdef) || (cp & 0xfffe) === 0xfffe) {1125 emitError(context, 21 /* NONCHARACTER_CHARACTER_REFERENCE */);1126 }1127 else if ((cp >= 0x01 && cp <= 0x08) ||1128 cp === 0x0b ||1129 (cp >= 0x0d && cp <= 0x1f) ||1130 (cp >= 0x7f && cp <= 0x9f)) {1131 emitError(context, 4 /* CONTROL_CHARACTER_REFERENCE */);1132 cp = CCR_REPLACEMENTS[cp] || cp;1133 }1134 text += String.fromCodePoint(cp);1135 advanceBy(context, body[0].length);1136 if (!body[0].endsWith(';')) {1137 emitError(context, 18 /* MISSING_SEMICOLON_AFTER_CHARACTER_REFERENCE */);1138 }1139 }1140 }1141 }1142 return text;1143}1144function getCursor(context) {1145 const { column, line, offset } = context;1146 return { column, line, offset };1147}1148function getSelection(context, start, end) {1149 end = end || getCursor(context);1150 return {1151 start,1152 end,1153 source: context.originalSource.slice(start.offset, end.offset)1154 };1155}1156function last(xs) {1157 return xs[xs.length - 1];1158}1159function startsWith(source, searchString) {1160 return source.startsWith(searchString);1161}1162function advanceBy(context, numberOfCharacters) {1163 const { source } = context;1164 advancePositionWithMutation(context, source, numberOfCharacters);1165 context.source = source.slice(numberOfCharacters);1166}1167function advanceSpaces(context) {1168 const match = /^[\t\r\n\f ]+/.exec(context.source);1169 if (match) {1170 advanceBy(context, match[0].length);1171 }1172}1173function getNewPosition(context, start, numberOfCharacters) {1174 return advancePositionWithClone(start, context.originalSource.slice(start.offset, numberOfCharacters), numberOfCharacters);1175}1176function emitError(context, code, offset) {1177 const loc = getCursor(context);1178 if (offset) {1179 loc.offset += offset;1180 loc.column += offset;1181 }1182 context.options.onError(createCompilerError(code, {1183 start: loc,1184 end: loc,1185 source: ''1186 }));1187}1188function isEnd(context, mode, ancestors) {1189 const s = context.source;1190 switch (mode) {1191 case 0 /* DATA */:1192 if (startsWith(s, '</')) {1193 //TODO: probably bad performance1194 for (let i = ancestors.length - 1; i >= 0; --i) {1195 if (startsWithEndTagOpen(s, ancestors[i].tag)) {1196 return true;1197 }1198 }1199 }1200 break;1201 case 1 /* RCDATA */:1202 case 2 /* RAWTEXT */: {1203 const parent = last(ancestors);1204 if (parent && startsWithEndTagOpen(s, parent.tag)) {1205 return true;1206 }1207 break;1208 }1209 case 3 /* CDATA */:1210 if (startsWith(s, ']]>')) {1211 return true;1212 }1213 break;1214 }1215 return !s;1216}1217function startsWithEndTagOpen(source, tag) {1218 return (startsWith(source, '</') &&1219 source.substr(2, tag.length).toLowerCase() === tag.toLowerCase() &&1220 /[\t\n\f />]/.test(source[2 + tag.length] || '>'));1221}1222// https://html.spec.whatwg.org/multipage/parsing.html#numeric-character-reference-end-state1223const CCR_REPLACEMENTS = {1224 0x80: 0x20ac,1225 0x82: 0x201a,1226 0x83: 0x0192,1227 0x84: 0x201e,1228 0x85: 0x2026,1229 0x86: 0x2020,1230 0x87: 0x2021,1231 0x88: 0x02c6,1232 0x89: 0x2030,1233 0x8a: 0x0160,1234 0x8b: 0x2039,1235 0x8c: 0x0152,1236 0x8e: 0x017d,1237 0x91: 0x2018,1238 0x92: 0x2019,1239 0x93: 0x201c,1240 0x94: 0x201d,1241 0x95: 0x2022,1242 0x96: 0x2013,1243 0x97: 0x2014,1244 0x98: 0x02dc,1245 0x99: 0x2122,1246 0x9a: 0x0161,1247 0x9b: 0x203a,1248 0x9c: 0x0153,1249 0x9e: 0x017e,1250 0x9f: 0x01781251};1252function hoistStatic(root, context) {1253 walk(root.children, context, new Map(), isSingleElementRoot(root, root.children[0]));1254}1255function isSingleElementRoot(root, child) {1256 const { children } = root;1257 return (children.length === 1 &&1258 child.type === 1 /* ELEMENT */ &&1259 !isSlotOutlet(child));1260}1261function walk(children, context, resultCache, doNotHoistNode = false) {1262 for (let i = 0; i < children.length; i++) {1263 const child = children[i];1264 // only plain elements are eligible for hoisting.1265 if (child.type === 1 /* ELEMENT */ &&1266 child.tagType === 0 /* ELEMENT */) {1267 if (!doNotHoistNode && isStaticNode(child, resultCache)) {1268 // whole tree is static1269 child.codegenNode = context.hoist(child.codegenNode);1270 continue;1271 }1272 else {1273 // node may contain dynamic children, but its props may be eligible for1274 // hoisting.1275 const codegenNode = child.codegenNode;1276 if (codegenNode.type === 13 /* JS_CALL_EXPRESSION */) {1277 const flag = getPatchFlag(codegenNode);1278 if ((!flag ||1279 flag === 32 /* NEED_PATCH */ ||1280 flag === 1 /* TEXT */) &&1281 !hasDynamicKeyOrRef(child) &&1282 !hasCachedProps(child)) {1283 const props = getNodeProps(child);1284 if (props && props !== `null`) {1285 getVNodeCall(codegenNode).arguments[1] = context.hoist(props);1286 }1287 }1288 }1289 }1290 }1291 if (child.type === 1 /* ELEMENT */) {1292 walk(child.children, context, resultCache);1293 }1294 else if (child.type === 11 /* FOR */) {1295 // Do not hoist v-for single child because it has to be a block1296 walk(child.children, context, resultCache, child.children.length === 1);1297 }1298 else if (child.type === 9 /* IF */) {1299 for (let i = 0; i < child.branches.length; i++) {1300 const branchChildren = child.branches[i].children;1301 // Do not hoist v-if single child because it has to be a block1302 walk(branchChildren, context, resultCache, branchChildren.length === 1);1303 }1304 }1305 }1306}1307function isStaticNode(node, resultCache = new Map()) {1308 switch (node.type) {1309 case 1 /* ELEMENT */:1310 if (node.tagType !== 0 /* ELEMENT */) {1311 return false;1312 }1313 const cached = resultCache.get(node);1314 if (cached !== undefined) {1315 return cached;1316 }1317 const codegenNode = node.codegenNode;1318 if (codegenNode.type !== 13 /* JS_CALL_EXPRESSION */) {1319 return false;1320 }1321 const flag = getPatchFlag(codegenNode);1322 if (!flag && !hasDynamicKeyOrRef(node) && !hasCachedProps(node)) {1323 // element self is static. check its children.1324 for (let i = 0; i < node.children.length; i++) {1325 if (!isStaticNode(node.children[i], resultCache)) {1326 resultCache.set(node, false);1327 return false;1328 }1329 }1330 resultCache.set(node, true);1331 return true;1332 }1333 else {1334 resultCache.set(node, false);1335 return false;1336 }1337 case 2 /* TEXT */:1338 case 3 /* COMMENT */:1339 return true;1340 case 9 /* IF */:1341 case 11 /* FOR */:1342 return false;1343 case 5 /* INTERPOLATION */:1344 case 12 /* TEXT_CALL */:1345 return isStaticNode(node.content, resultCache);1346 case 4 /* SIMPLE_EXPRESSION */:1347 return node.isConstant;1348 case 8 /* COMPOUND_EXPRESSION */:1349 return node.children.every(child => {1350 return (isString(child) || isSymbol(child) || isStaticNode(child, resultCache));1351 });1352 default:1353 return false;1354 }1355}1356function hasDynamicKeyOrRef(node) {1357 return !!(findProp(node, 'key', true) || findProp(node, 'ref', true));1358}1359function hasCachedProps(node) {1360 const props = getNodeProps(node);1361 if (props &&1362 props !== 'null' &&1363 props.type === 14 /* JS_OBJECT_EXPRESSION */) {1364 const { properties } = props;1365 for (let i = 0; i < properties.length; i++) {1366 if (properties[i].value.type === 20 /* JS_CACHE_EXPRESSION */) {1367 return true;1368 }1369 }1370 }1371 return false;1372}1373function getNodeProps(node) {1374 const codegenNode = node.codegenNode;1375 if (codegenNode.type === 13 /* JS_CALL_EXPRESSION */) {1376 return getVNodeArgAt(codegenNode, 1);1377 }1378}1379function getVNodeArgAt(node, index) {1380 return getVNodeCall(node).arguments[index];1381}1382function getVNodeCall(node) {1383 return node.callee === WITH_DIRECTIVES ? node.arguments[0] : node;1384}1385function getPatchFlag(node) {1386 const flag = getVNodeArgAt(node, 3);1387 return flag ? parseInt(flag, 10) : undefined;1388}1389function createTransformContext(root, { prefixIdentifiers = false, hoistStatic = false, cacheHandlers = false, nodeTransforms = [], directiveTransforms = {}, onError = defaultOnError }) {1390 const context = {1391 root,1392 helpers: new Set(),1393 components: new Set(),1394 directives: new Set(),1395 hoists: [],1396 cached: 0,1397 identifiers: {},1398 scopes: {1399 vFor: 0,1400 vSlot: 0,1401 vPre: 0,1402 vOnce: 01403 },1404 prefixIdentifiers,1405 hoistStatic,1406 cacheHandlers,1407 nodeTransforms,1408 directiveTransforms,1409 onError,1410 parent: null,1411 currentNode: root,1412 childIndex: 0,1413 helper(name) {1414 context.helpers.add(name);1415 return name;1416 },1417 helperString(name) {1418 return ((context.prefixIdentifiers ? `` : `_`) +1419 helperNameMap[context.helper(name)]);1420 },1421 replaceNode(node) {1422 context.parent.children[context.childIndex] = context.currentNode = node;1423 },1424 removeNode(node) {1425 const list = context.parent.children;1426 const removalIndex = node1427 ? list.indexOf(node)1428 : context.currentNode1429 ? context.childIndex1430 : -1;1431 if (!node || node === context.currentNode) {1432 // current node removed1433 context.currentNode = null;1434 context.onNodeRemoved();1435 }1436 else {1437 // sibling node removed1438 if (context.childIndex > removalIndex) {1439 context.childIndex--;1440 context.onNodeRemoved();1441 }1442 }1443 context.parent.children.splice(removalIndex, 1);1444 },1445 onNodeRemoved: () => { },1446 addIdentifiers(exp) {1447 // identifier tracking only happens in non-browser builds.1448 {1449 if (isString(exp)) {1450 addId(exp);1451 }1452 else if (exp.identifiers) {1453 exp.identifiers.forEach(addId);1454 }1455 else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {1456 addId(exp.content);1457 }1458 }1459 },1460 removeIdentifiers(exp) {1461 {1462 if (isString(exp)) {1463 removeId(exp);1464 }1465 else if (exp.identifiers) {1466 exp.identifiers.forEach(removeId);1467 }1468 else if (exp.type === 4 /* SIMPLE_EXPRESSION */) {1469 removeId(exp.content);1470 }1471 }1472 },1473 hoist(exp) {1474 context.hoists.push(exp);1475 return createSimpleExpression(`_hoisted_${context.hoists.length}`, false, exp.loc, true);1476 },1477 cache(exp, isVNode = false) {1478 return createCacheExpression(++context.cached, exp, isVNode);1479 }1480 };1481 function addId(id) {1482 const { identifiers } = context;1483 if (identifiers[id] === undefined) {1484 identifiers[id] = 0;1485 }1486 identifiers[id]++;1487 }1488 function removeId(id) {1489 context.identifiers[id]--;1490 }1491 return context;1492}1493function transform(root, options) {1494 const context = createTransformContext(root, options);1495 traverseNode(root, context);1496 if (options.hoistStatic) {1497 hoistStatic(root, context);1498 }1499 finalizeRoot(root, context);1500}1501function finalizeRoot(root, context) {1502 const { helper } = context;1503 const { children } = root;1504 const child = children[0];1505 if (children.length === 1) {1506 // if the single child is an element, turn it into a block.1507 if (isSingleElementRoot(root, child) && child.codegenNode) {1508 // single element root is never hoisted so codegenNode will never be1509 // SimpleExpressionNode1510 const codegenNode = child.codegenNode;1511 if (codegenNode.type !== 20 /* JS_CACHE_EXPRESSION */) {1512 if (codegenNode.callee === WITH_DIRECTIVES) {1513 codegenNode.arguments[0].callee = helper(CREATE_BLOCK);1514 }1515 else {1516 codegenNode.callee = helper(CREATE_BLOCK);1517 }1518 root.codegenNode = createBlockExpression(codegenNode, context);1519 }1520 else {1521 root.codegenNode = codegenNode;1522 }1523 }1524 else {1525 // - single <slot/>, IfNode, ForNode: already blocks.1526 // - single text node: always patched.1527 // root codegen falls through via genNode()1528 root.codegenNode = child;1529 }1530 }1531 else if (children.length > 1) {1532 // root has multiple nodes - return a fragment block.1533 root.codegenNode = createBlockExpression(createCallExpression(helper(CREATE_BLOCK), [1534 helper(FRAGMENT),1535 `null`,1536 root.children1537 ]), context);1538 }1539 // finalize meta information1540 root.helpers = [...context.helpers];1541 root.components = [...context.components];1542 root.directives = [...context.directives];1543 root.hoists = context.hoists;1544 root.cached = context.cached;1545}1546function traverseChildren(parent, context) {1547 let i = 0;1548 const nodeRemoved = () => {1549 i--;1550 };1551 for (; i < parent.children.length; i++) {1552 const child = parent.children[i];1553 if (isString(child))1554 continue;1555 context.currentNode = child;1556 context.parent = parent;1557 context.childIndex = i;1558 context.onNodeRemoved = nodeRemoved;1559 traverseNode(child, context);1560 }1561}1562function traverseNode(node, context) {1563 // apply transform plugins1564 const { nodeTransforms } = context;1565 const exitFns = [];1566 for (let i = 0; i < nodeTransforms.length; i++) {1567 const onExit = nodeTransforms[i](node, context);1568 if (onExit) {1569 if (isArray(onExit)) {1570 exitFns.push(...onExit);1571 }1572 else {1573 exitFns.push(onExit);1574 }1575 }1576 if (!context.currentNode) {1577 // node was removed1578 return;1579 }1580 else {1581 // node may have been replaced1582 node = context.currentNode;1583 }1584 }1585 switch (node.type) {1586 case 3 /* COMMENT */:1587 // inject import for the Comment symbol, which is needed for creating1588 // comment nodes with `createVNode`1589 context.helper(CREATE_COMMENT);1590 break;1591 case 5 /* INTERPOLATION */:1592 // no need to traverse, but we need to inject toString helper1593 context.helper(TO_STRING);1594 break;1595 // for container types, further traverse downwards1596 case 9 /* IF */:1597 for (let i = 0; i < node.branches.length; i++) {1598 traverseChildren(node.branches[i], context);1599 }1600 break;1601 case 11 /* FOR */:1602 case 1 /* ELEMENT */:1603 case 0 /* ROOT */:1604 traverseChildren(node, context);1605 break;1606 }1607 // exit transforms1608 let i = exitFns.length;1609 while (i--) {1610 exitFns[i]();1611 }1612}1613function createStructuralDirectiveTransform(name, fn) {1614 const matches = isString(name)1615 ? (n) => n === name1616 : (n) => name.test(n);1617 return (node, context) => {1618 if (node.type === 1 /* ELEMENT */) {1619 const { props } = node;1620 // structural directive transforms are not concerned with slots1621 // as they are handled separately in vSlot.ts1622 if (node.tagType === 3 /* TEMPLATE */ && props.some(isVSlot)) {1623 return;1624 }1625 const exitFns = [];1626 for (let i = 0; i < props.length; i++) {1627 const prop = props[i];1628 if (prop.type === 7 /* DIRECTIVE */ && matches(prop.name)) {1629 // structural directives are removed to avoid infinite recursion1630 // also we remove them *before* applying so that it can further1631 // traverse itself in case it moves the node around1632 props.splice(i, 1);1633 i--;1634 const onExit = fn(node, prop, context);1635 if (onExit)1636 exitFns.push(onExit);1637 }1638 }1639 return exitFns;1640 }1641 };1642}1643function createCodegenContext(ast, { mode = 'function', prefixIdentifiers = mode === 'module', sourceMap = false, filename = `template.vue.html` }) {1644 const context = {1645 mode,1646 prefixIdentifiers,1647 sourceMap,1648 filename,1649 source: ast.loc.source,1650 code: ``,1651 column: 1,1652 line: 1,1653 offset: 0,1654 indentLevel: 0,1655 // lazy require source-map implementation, only in non-browser builds!1656 map: !sourceMap1657 ? undefined1658 : new (loadDep('source-map')).SourceMapGenerator(),1659 helper(key) {1660 const name = helperNameMap[key];1661 return prefixIdentifiers ? name : `_${name}`;1662 },1663 push(code, node, openOnly) {1664 context.code += code;1665 if ( context.map) {1666 if (node) {1667 let name;1668 if (node.type === 4 /* SIMPLE_EXPRESSION */ && !node.isStatic) {1669 const content = node.content.replace(/^_ctx\./, '');1670 if (content !== node.content && isSimpleIdentifier(content)) {1671 name = content;1672 }1673 }1674 addMapping(node.loc.start, name);1675 }1676 advancePositionWithMutation(context, code);1677 if (node && !openOnly) {1678 addMapping(node.loc.end);1679 }1680 }1681 },1682 resetMapping(loc) {1683 if ( context.map) {1684 addMapping(loc.start);1685 }1686 },1687 indent() {1688 newline(++context.indentLevel);1689 },1690 deindent(withoutNewLine = false) {1691 if (withoutNewLine) {1692 --context.indentLevel;1693 }1694 else {1695 newline(--context.indentLevel);1696 }1697 },1698 newline() {1699 newline(context.indentLevel);1700 }1701 };1702 function newline(n) {1703 context.push('\n' + ` `.repeat(n));1704 }1705 function addMapping(loc, name) {1706 context.map.addMapping({1707 name,1708 source: context.filename,1709 original: {1710 line: loc.line,1711 column: loc.column - 1 // source-map column is 0 based1712 },1713 generated: {1714 line: context.line,1715 column: context.column - 11716 }1717 });1718 }1719 if ( context.map) {1720 context.map.setSourceContent(filename, context.source);1721 }1722 return context;1723}1724function generate(ast, options = {}) {1725 const context = createCodegenContext(ast, options);1726 const { mode, push, helper, prefixIdentifiers, indent, deindent, newline } = context;1727 const hasHelpers = ast.helpers.length > 0;1728 const useWithBlock = !prefixIdentifiers && mode !== 'module';1729 // preambles1730 if (mode === 'function') {1731 // Generate const declaration for helpers1732 // In prefix mode, we place the const declaration at top so it's done1733 // only once; But if we not prefixing, we place the declaration inside the1734 // with block so it doesn't incur the `in` check cost for every helper access.1735 if (hasHelpers) {1736 if (prefixIdentifiers) {1737 push(`const { ${ast.helpers.map(helper).join(', ')} } = Vue\n`);1738 }1739 else {1740 // "with" mode.1741 // save Vue in a separate variable to avoid collision1742 push(`const _Vue = Vue\n`);1743 // in "with" mode, helpers are declared inside the with block to avoid1744 // has check cost, but hoists are lifted out of the function - we need1745 // to provide the helper here.1746 if (ast.hoists.length) {1747 push(`const _${helperNameMap[CREATE_VNODE]} = Vue.${helperNameMap[CREATE_VNODE]}\n`);1748 if (ast.helpers.includes(CREATE_COMMENT)) {1749 push(`const _${helperNameMap[CREATE_COMMENT]} = Vue.${helperNameMap[CREATE_COMMENT]}\n`);1750 }1751 }1752 }1753 }1754 genHoists(ast.hoists, context);1755 newline();1756 push(`return `);1757 }1758 else {1759 // generate import statements for helpers1760 if (hasHelpers) {1761 push(`import { ${ast.helpers.map(helper).join(', ')} } from "vue"\n`);1762 }1763 genHoists(ast.hoists, context);1764 newline();1765 push(`export default `);1766 }1767 // enter render function1768 push(`function render() {`);1769 indent();1770 if (useWithBlock) {1771 push(`with (this) {`);1772 indent();1773 // function mode const declarations should be inside with block1774 // also they should be renamed to avoid collision with user properties1775 if (hasHelpers) {1776 push(`const { ${ast.helpers1777 .map(s => `${helperNameMap[s]}: _${helperNameMap[s]}`)1778 .join(', ')} } = _Vue`);1779 newline();1780 if (ast.cached > 0) {1781 push(`const _cache = $cache`);1782 newline();1783 }1784 newline();1785 }1786 }1787 else {1788 push(`const _ctx = this`);1789 if (ast.cached > 0) {1790 newline();1791 push(`const _cache = _ctx.$cache`);1792 }1793 newline();1794 }1795 // generate asset resolution statements1796 if (ast.components.length) {1797 genAssets(ast.components, 'component', context);1798 }1799 if (ast.directives.length) {1800 genAssets(ast.directives, 'directive', context);1801 }1802 if (ast.components.length || ast.directives.length) {1803 newline();1804 }1805 // generate the VNode tree expression1806 push(`return `);1807 if (ast.codegenNode) {1808 genNode(ast.codegenNode, context);1809 }1810 else {1811 push(`null`);1812 }1813 if (useWithBlock) {1814 deindent();1815 push(`}`);1816 }1817 deindent();1818 push(`}`);1819 return {1820 ast,1821 code: context.code,1822 map: undefined //context.map ? context.map.toJSON() : undefined1823 };1824}1825function genAssets(assets, type, context) {1826 const resolver = context.helper(type === 'component' ? RESOLVE_COMPONENT : RESOLVE_DIRECTIVE);1827 for (let i = 0; i < assets.length; i++) {1828 const id = assets[i];1829 context.push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)})`);1830 context.newline();1831 }1832}1833function genHoists(hoists, context) {1834 if (!hoists.length) {1835 return;1836 }1837 context.newline();1838 hoists.forEach((exp, i) => {1839 context.push(`const _hoisted_${i + 1} = `);1840 genNode(exp, context);1841 context.newline();1842 });1843}1844function isText(n) {1845 return (isString(n) ||1846 n.type === 4 /* SIMPLE_EXPRESSION */ ||1847 n.type === 2 /* TEXT */ ||1848 n.type === 5 /* INTERPOLATION */ ||1849 n.type === 8 /* COMPOUND_EXPRESSION */);1850}1851function genNodeListAsArray(nodes, context) {1852 const multilines = nodes.length > 3 ||1853 ( nodes.some(n => isArray(n) || !isText(n)));1854 context.push(`[`);1855 multilines && context.indent();1856 genNodeList(nodes, context, multilines);1857 multilines && context.deindent();1858 context.push(`]`);1859}1860function genNodeList(nodes, context, multilines = false) {1861 const { push, newline } = context;1862 for (let i = 0; i < nodes.length; i++) {1863 const node = nodes[i];1864 if (isString(node)) {1865 push(node);1866 }1867 else if (isArray(node)) {1868 genNodeListAsArray(node, context);1869 }1870 else {1871 genNode(node, context);1872 }1873 if (i < nodes.length - 1) {1874 if (multilines) {1875 push(',');1876 newline();1877 }1878 else {1879 push(', ');1880 }1881 }1882 }1883}1884function genNode(node, context) {1885 if (isString(node)) {1886 context.push(node);1887 return;1888 }1889 if (isSymbol(node)) {1890 context.push(context.helper(node));1891 return;1892 }1893 switch (node.type) {1894 case 1 /* ELEMENT */:1895 case 9 /* IF */:1896 case 11 /* FOR */:1897 genNode(node.codegenNode, context);1898 break;1899 case 2 /* TEXT */:1900 genText(node, context);1901 break;1902 case 4 /* SIMPLE_EXPRESSION */:1903 genExpression(node, context);1904 break;1905 case 5 /* INTERPOLATION */:1906 genInterpolation(node, context);1907 break;1908 case 12 /* TEXT_CALL */:1909 genNode(node.codegenNode, context);1910 break;1911 case 8 /* COMPOUND_EXPRESSION */:1912 genCompoundExpression(node, context);1913 break;1914 case 3 /* COMMENT */:1915 break;1916 case 13 /* JS_CALL_EXPRESSION */:1917 genCallExpression(node, context);1918 break;1919 case 14 /* JS_OBJECT_EXPRESSION */:1920 genObjectExpression(node, context);1921 break;1922 case 16 /* JS_ARRAY_EXPRESSION */:1923 genArrayExpression(node, context);1924 break;1925 case 17 /* JS_FUNCTION_EXPRESSION */:1926 genFunctionExpression(node, context);1927 break;1928 case 18 /* JS_SEQUENCE_EXPRESSION */:1929 genSequenceExpression(node, context);1930 break;1931 case 19 /* JS_CONDITIONAL_EXPRESSION */:1932 genConditionalExpression(node, context);1933 break;1934 case 20 /* JS_CACHE_EXPRESSION */:1935 genCacheExpression(node, context);1936 break;1937 }1938}1939function genText(node, context) {1940 context.push(JSON.stringify(node.content), node);1941}1942function genExpression(node, context) {1943 const { content, isStatic } = node;1944 context.push(isStatic ? JSON.stringify(content) : content, node);1945}1946function genInterpolation(node, context) {1947 const { push, helper } = context;1948 push(`${helper(TO_STRING)}(`);1949 genNode(node.content, context);1950 push(`)`);1951}1952function genCompoundExpression(node, context) {1953 for (let i = 0; i < node.children.length; i++) {1954 const child = node.children[i];1955 if (isString(child)) {1956 context.push(child);1957 }1958 else {1959 genNode(child, context);1960 }1961 }1962}1963function genExpressionAsPropertyKey(node, context) {1964 const { push } = context;1965 if (node.type === 8 /* COMPOUND_EXPRESSION */) {1966 push(`[`);1967 genCompoundExpression(node, context);1968 push(`]`);1969 }1970 else if (node.isStatic) {1971 // only quote keys if necessary1972 const text = isSimpleIdentifier(node.content)1973 ? node.content1974 : JSON.stringify(node.content);1975 push(text, node);1976 }1977 else {1978 push(`[${node.content}]`, node);1979 }1980}1981// JavaScript1982function genCallExpression(node, context) {1983 const callee = isString(node.callee)1984 ? node.callee1985 : context.helper(node.callee);1986 context.push(callee + `(`, node, true);1987 genNodeList(node.arguments, context);1988 context.push(`)`);1989}1990function genObjectExpression(node, context) {1991 const { push, indent, deindent, newline, resetMapping } = context;1992 const { properties } = node;1993 if (!properties.length) {1994 push(`{}`, node);1995 return;1996 }1997 const multilines = properties.length > 1 ||1998 (1999 properties.some(p => p.value.type !== 4 /* SIMPLE_EXPRESSION */));2000 push(multilines ? `{` : `{ `);2001 multilines && indent();2002 for (let i = 0; i < properties.length; i++) {2003 const { key, value, loc } = properties[i];2004 resetMapping(loc); // reset source mapping for every property.2005 // key2006 genExpressionAsPropertyKey(key, context);2007 push(`: `);2008 // value2009 genNode(value, context);2010 if (i < properties.length - 1) {2011 // will only reach this if it's multilines2012 push(`,`);2013 newline();2014 }2015 }2016 multilines && deindent();2017 const lastChar = context.code[context.code.length - 1];2018 push(multilines || /[\])}]/.test(lastChar) ? `}` : ` }`);2019}2020function genArrayExpression(node, context) {2021 genNodeListAsArray(node.elements, context);2022}2023function genFunctionExpression(node, context) {2024 const { push, indent, deindent } = context;2025 const { params, returns, newline } = node;2026 push(`(`, node);2027 if (isArray(params)) {2028 genNodeList(params, context);2029 }2030 else if (params) {2031 genNode(params, context);2032 }2033 push(`) => `);2034 if (newline) {2035 push(`{`);2036 indent();2037 push(`return `);2038 }2039 if (isArray(returns)) {2040 genNodeListAsArray(returns, context);2041 }2042 else {2043 genNode(returns, context);2044 }2045 if (newline) {2046 deindent();2047 push(`}`);2048 }2049}2050function genConditionalExpression(node, context) {2051 const { test, consequent, alternate } = node;2052 const { push, indent, deindent, newline } = context;2053 if (test.type === 4 /* SIMPLE_EXPRESSION */) {2054 const needsParens = !isSimpleIdentifier(test.content);2055 needsParens && push(`(`);2056 genExpression(test, context);2057 needsParens && push(`)`);2058 }2059 else {2060 push(`(`);2061 genCompoundExpression(test, context);2062 push(`)`);2063 }2064 indent();2065 context.indentLevel++;2066 push(`? `);2067 genNode(consequent, context);2068 context.indentLevel--;2069 newline();2070 push(`: `);2071 const isNested = alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */;2072 if (!isNested) {2073 context.indentLevel++;2074 }2075 genNode(alternate, context);2076 if (!isNested) {2077 context.indentLevel--;2078 }2079 deindent(true /* without newline */);2080}2081function genSequenceExpression(node, context) {2082 context.push(`(`);2083 genNodeList(node.expressions, context);2084 context.push(`)`);2085}2086function genCacheExpression(node, context) {2087 const { push, helper, indent, deindent, newline } = context;2088 push(`_cache[${node.index}] || (`);2089 if (node.isVNode) {2090 indent();2091 push(`${helper(SET_BLOCK_TRACKING)}(-1),`);2092 newline();2093 }2094 push(`_cache[${node.index}] = `);2095 genNode(node.value, context);2096 if (node.isVNode) {2097 push(`,`);2098 newline();2099 push(`${helper(SET_BLOCK_TRACKING)}(1),`);2100 newline();2101 push(`_cache[${node.index}]`);2102 deindent();2103 }2104 push(`)`);2105}2106const isLiteralWhitelisted = /*#__PURE__*/ makeMap('true,false,null,this');2107const transformExpression = (node, context) => {2108 if (node.type === 5 /* INTERPOLATION */) {2109 node.content = processExpression(node.content, context);2110 }2111 else if (node.type === 1 /* ELEMENT */) {2112 // handle directives on element2113 for (let i = 0; i < node.props.length; i++) {2114 const dir = node.props[i];2115 // do not process for v-on & v-for since they are special handled2116 if (dir.type === 7 /* DIRECTIVE */ && dir.name !== 'for') {2117 const exp = dir.exp;2118 const arg = dir.arg;2119 // do not process exp if this is v-on:arg - we need special handling2120 // for wrapping inline statements.2121 if (exp && !(dir.name === 'on' && arg)) {2122 dir.exp = processExpression(exp, context, 2123 // slot args must be processed as function params2124 dir.name === 'slot');2125 }2126 if (arg && !arg.isStatic) {2127 dir.arg = processExpression(arg, context);2128 }2129 }2130 }2131 }2132};2133// Important: since this function uses Node.js only dependencies, it should2134// always be used with a leading !false check so that it can be2135// tree-shaken from the browser build.2136function processExpression(node, context, 2137// some expressions like v-slot props & v-for aliases should be parsed as2138// function params2139asParams = false) {2140 if (!context.prefixIdentifiers || !node.content.trim()) {2141 return node;2142 }2143 // fast path if expression is a simple identifier.2144 const rawExp = node.content;2145 if (isSimpleIdentifier(rawExp)) {2146 if (!asParams &&2147 !context.identifiers[rawExp] &&2148 !isGloballyWhitelisted(rawExp) &&2149 !isLiteralWhitelisted(rawExp)) {2150 node.content = `_ctx.${rawExp}`;2151 }2152 else if (!context.identifiers[rawExp]) {2153 // mark node constant for hoisting unless it's referring a scope variable2154 node.isConstant = true;2155 }2156 return node;2157 }2158 let ast;2159 // if the expression is supposed to be used in a function params position2160 // we need to parse it differently.2161 const source = `(${rawExp})${asParams ? `=>{}` : ``}`;2162 try {2163 ast = parseJS(source, { ranges: true });2164 }2165 catch (e) {2166 context.onError(createCompilerError(50 /* X_INVALID_EXPRESSION */, node.loc));2167 return node;2168 }2169 const ids = [];2170 const knownIds = Object.create(context.identifiers);2171 // walk the AST and look for identifiers that need to be prefixed with `_ctx.`.2172 walkJS(ast, {2173 enter(node, parent) {2174 if (node.type === 'Identifier') {2175 if (!ids.includes(node)) {2176 const needPrefix = shouldPrefix(node, parent);2177 if (!knownIds[node.name] && needPrefix) {2178 if (isPropertyShorthand(node, parent)) {2179 // property shorthand like { foo }, we need to add the key since we2180 // rewrite the value2181 node.prefix = `${node.name}: `;2182 }2183 node.name = `_ctx.${node.name}`;2184 node.isConstant = false;2185 ids.push(node);2186 }2187 else if (!isStaticPropertyKey(node, parent)) {2188 // The identifier is considered constant unless it's pointing to a2189 // scope variable (a v-for alias, or a v-slot prop)2190 node.isConstant = !(needPrefix && knownIds[node.name]);2191 // also generate sub-expressions for other identifiers for better2192 // source map support. (except for property keys which are static)2193 ids.push(node);2194 }2195 }2196 }2197 else if (isFunction$1(node)) {2198 // walk function expressions and add its arguments to known identifiers2199 // so that we don't prefix them2200 node.params.forEach((p) => walkJS(p, {2201 enter(child, parent) {2202 if (child.type === 'Identifier' &&2203 // do not record as scope variable if is a destructured key2204 !isStaticPropertyKey(child, parent) &&2205 // do not record if this is a default value2206 // assignment of a destructured variable2207 !(parent &&2208 parent.type === 'AssignmentPattern' &&2209 parent.right === child)) {2210 const { name } = child;2211 if (node.scopeIds && node.scopeIds.has(name)) {2212 return;2213 }2214 if (name in knownIds) {2215 knownIds[name]++;2216 }2217 else {2218 knownIds[name] = 1;2219 }2220 (node.scopeIds || (node.scopeIds = new Set())).add(name);2221 }2222 }2223 }));2224 }2225 },2226 leave(node) {2227 if (node !== ast.body[0].expression && node.scopeIds) {2228 node.scopeIds.forEach((id) => {2229 knownIds[id]--;2230 if (knownIds[id] === 0) {2231 delete knownIds[id];2232 }2233 });2234 }2235 }2236 });2237 // We break up the compound expression into an array of strings and sub2238 // expressions (for identifiers that have been prefixed). In codegen, if2239 // an ExpressionNode has the `.children` property, it will be used instead of2240 // `.content`.2241 const children = [];2242 ids.sort((a, b) => a.start - b.start);2243 ids.forEach((id, i) => {2244 // range is offset by -1 due to the wrapping parens when parsed2245 const start = id.start - 1;2246 const end = id.end - 1;2247 const last = ids[i - 1];2248 const leadingText = rawExp.slice(last ? last.end - 1 : 0, start);2249 if (leadingText.length || id.prefix) {2250 children.push(leadingText + (id.prefix || ``));2251 }2252 const source = rawExp.slice(start, end);2253 children.push(createSimpleExpression(id.name, false, {2254 source,2255 start: advancePositionWithClone(node.loc.start, source, start),2256 end: advancePositionWithClone(node.loc.start, source, end)2257 }, id.isConstant /* isConstant */));2258 if (i === ids.length - 1 && end < rawExp.length) {2259 children.push(rawExp.slice(end));2260 }2261 });2262 let ret;2263 if (children.length) {2264 ret = createCompoundExpression(children, node.loc);2265 }2266 else {2267 ret = node;2268 ret.isConstant = true;2269 }2270 ret.identifiers = Object.keys(knownIds);2271 return ret;2272}2273const isFunction$1 = (node) => /Function(Expression|Declaration)$/.test(node.type);2274const isPropertyKey = (node, parent) => parent &&2275 parent.type === 'Property' &&2276 parent.key === node &&2277 !parent.computed;2278const isPropertyShorthand = (node, parent) => isPropertyKey(node, parent) && parent.value === node;2279const isStaticPropertyKey = (node, parent) => isPropertyKey(node, parent) && parent.value !== node;2280function shouldPrefix(identifier, parent) {2281 if (!(isFunction$1(parent) &&2282 // not id of a FunctionDeclaration2283 (parent.id === identifier ||2284 // not a params of a function2285 parent.params.includes(identifier))) &&2286 // not a key of Property2287 !isStaticPropertyKey(identifier, parent) &&2288 // not a property of a MemberExpression2289 !(parent.type === 'MemberExpression' &&2290 parent.property === identifier &&2291 !parent.computed) &&2292 // not in an Array destructure pattern2293 !(parent.type === 'ArrayPattern') &&2294 // skip whitelisted globals2295 !isGloballyWhitelisted(identifier.name) &&2296 // special case for webpack compilation2297 identifier.name !== `require` &&2298 // is a special keyword but parsed as identifier2299 identifier.name !== `arguments`) {2300 return true;2301 }2302}2303const transformIf = createStructuralDirectiveTransform(/^(if|else|else-if)$/, (node, dir, context) => {2304 if (dir.name !== 'else' &&2305 (!dir.exp || !dir.exp.content.trim())) {2306 const loc = dir.exp ? dir.exp.loc : node.loc;2307 context.onError(createCompilerError(35 /* X_V_IF_NO_EXPRESSION */, dir.loc));2308 dir.exp = createSimpleExpression(`true`, false, loc);2309 }2310 if ( context.prefixIdentifiers && dir.exp) {2311 // dir.exp can only be simple expression because vIf transform is applied2312 // before expression transform.2313 dir.exp = processExpression(dir.exp, context);2314 }2315 if (dir.name === 'if') {2316 const branch = createIfBranch(node, dir);2317 const codegenNode = createSequenceExpression([2318 createCallExpression(context.helper(OPEN_BLOCK))2319 ]);2320 context.replaceNode({2321 type: 9 /* IF */,2322 loc: node.loc,2323 branches: [branch],2324 codegenNode2325 });2326 // Exit callback. Complete the codegenNode when all children have been2327 // transformed.2328 return () => {2329 codegenNode.expressions.push(createCodegenNodeForBranch(branch, 0, context));2330 };2331 }2332 else {2333 // locate the adjacent v-if2334 const siblings = context.parent.children;2335 let i = siblings.indexOf(node);2336 while (i-- >= -1) {2337 const sibling = siblings[i];2338 if (sibling && sibling.type === 9 /* IF */) {2339 // move the node to the if node's branches2340 context.removeNode();2341 const branch = createIfBranch(node, dir);2342 sibling.branches.push(branch);2343 // since the branch was removed, it will not be traversed.2344 // make sure to traverse here.2345 traverseChildren(branch, context);2346 // make sure to reset currentNode after traversal to indicate this2347 // node has been removed.2348 context.currentNode = null;2349 // attach this branch's codegen node to the v-if root.2350 let parentCondition = sibling.codegenNode2351 .expressions[1];2352 while (true) {2353 if (parentCondition.alternate.type ===2354 19 /* JS_CONDITIONAL_EXPRESSION */) {2355 parentCondition = parentCondition.alternate;2356 }2357 else {2358 parentCondition.alternate = createCodegenNodeForBranch(branch, sibling.branches.length - 1, context);2359 break;2360 }2361 }2362 }2363 else {2364 context.onError(createCompilerError(36 /* X_V_ELSE_NO_ADJACENT_IF */, node.loc));2365 }2366 break;2367 }2368 }2369});2370function createIfBranch(node, dir) {2371 return {2372 type: 10 /* IF_BRANCH */,2373 loc: node.loc,2374 condition: dir.name === 'else' ? undefined : dir.exp,2375 children: node.tagType === 3 /* TEMPLATE */ ? node.children : [node]2376 };2377}2378function createCodegenNodeForBranch(branch, index, context) {2379 if (branch.condition) {2380 return createConditionalExpression(branch.condition, createChildrenCodegenNode(branch, index, context), 2381 // make sure to pass in asBlock: true so that the comment node call2382 // closes the current block.2383 createCallExpression(context.helper(CREATE_COMMENT), [2384 '""',2385 'true'2386 ]));2387 }2388 else {2389 return createChildrenCodegenNode(branch, index, context);2390 }2391}2392function createChildrenCodegenNode(branch, index, context) {2393 const { helper } = context;2394 const keyProperty = createObjectProperty(`key`, createSimpleExpression(index + '', false));2395 const { children } = branch;2396 const child = children[0];2397 const needFragmentWrapper = children.length !== 1 || child.type !== 1 /* ELEMENT */;2398 if (needFragmentWrapper) {2399 const blockArgs = [2400 helper(FRAGMENT),2401 createObjectExpression([keyProperty]),2402 children2403 ];2404 if (children.length === 1 && child.type === 11 /* FOR */) {2405 // optimize away nested fragments when child is a ForNode2406 const forBlockArgs = child.codegenNode.expressions[1].arguments;2407 // directly use the for block's children and patchFlag2408 blockArgs[2] = forBlockArgs[2];2409 blockArgs[3] = forBlockArgs[3];2410 }2411 return createCallExpression(helper(CREATE_BLOCK), blockArgs);2412 }2413 else {2414 const childCodegen = child.codegenNode;2415 let vnodeCall = childCodegen;2416 // Element with custom directives. Locate the actual createVNode() call.2417 if (vnodeCall.callee === WITH_DIRECTIVES) {2418 vnodeCall = vnodeCall.arguments[0];2419 }2420 // Change createVNode to createBlock.2421 if (vnodeCall.callee === CREATE_VNODE) {2422 vnodeCall.callee = helper(CREATE_BLOCK);2423 }2424 // inject branch key2425 injectProp(vnodeCall, keyProperty, context);2426 return childCodegen;2427 }2428}2429const transformFor = createStructuralDirectiveTransform('for', (node, dir, context) => {2430 if (!dir.exp) {2431 context.onError(createCompilerError(37 /* X_V_FOR_NO_EXPRESSION */, dir.loc));2432 return;2433 }2434 const parseResult = parseForExpression(2435 // can only be simple expression because vFor transform is applied2436 // before expression transform.2437 dir.exp, context);2438 if (!parseResult) {2439 context.onError(createCompilerError(38 /* X_V_FOR_MALFORMED_EXPRESSION */, dir.loc));2440 return;2441 }2442 const { helper, addIdentifiers, removeIdentifiers, scopes } = context;2443 const { source, value, key, index } = parseResult;2444 // create the loop render function expression now, and add the2445 // iterator on exit after all children have been traversed2446 const renderExp = createCallExpression(helper(RENDER_LIST), [source]);2447 const keyProp = findProp(node, `key`);2448 const fragmentFlag = keyProp2449 ? 64 /* KEYED_FRAGMENT */2450 : 128 /* UNKEYED_FRAGMENT */;2451 const codegenNode = createSequenceExpression([2452 // fragment blocks disable tracking since they always diff their children2453 createCallExpression(helper(OPEN_BLOCK), [`false`]),2454 createCallExpression(helper(CREATE_BLOCK), [2455 helper(FRAGMENT),2456 `null`,2457 renderExp,2458 fragmentFlag + ( ``)2459 ])2460 ]);2461 context.replaceNode({2462 type: 11 /* FOR */,2463 loc: dir.loc,2464 source,2465 valueAlias: value,2466 keyAlias: key,2467 objectIndexAlias: index,2468 children: node.tagType === 3 /* TEMPLATE */ ? node.children : [node],2469 codegenNode2470 });2471 // bookkeeping2472 scopes.vFor++;2473 if ( context.prefixIdentifiers) {2474 // scope management2475 // inject identifiers to context2476 value && addIdentifiers(value);2477 key && addIdentifiers(key);2478 index && addIdentifiers(index);2479 }2480 return () => {2481 scopes.vFor--;2482 if ( context.prefixIdentifiers) {2483 value && removeIdentifiers(value);2484 key && removeIdentifiers(key);2485 index && removeIdentifiers(index);2486 }2487 // finish the codegen now that all children have been traversed2488 let childBlock;2489 const isTemplate = isTemplateNode(node);2490 const slotOutlet = isSlotOutlet(node)2491 ? node2492 : isTemplate &&2493 node.children.length === 1 &&2494 isSlotOutlet(node.children[0])2495 ? node.children[0] // api-extractor somehow fails to infer this2496 : null;2497 const keyProperty = keyProp2498 ? createObjectProperty(`key`, keyProp.type === 6 /* ATTRIBUTE */2499 ? createSimpleExpression(keyProp.value.content, true)2500 : keyProp.exp)2501 : null;2502 if (slotOutlet) {2503 // <slot v-for="..."> or <template v-for="..."><slot/></template>2504 childBlock = slotOutlet.codegenNode;2505 if (isTemplate && keyProperty) {2506 // <template v-for="..." :key="..."><slot/></template>2507 // we need to inject the key to the renderSlot() call.2508 // the props for renderSlot is passed as the 3rd argument.2509 injectProp(childBlock, keyProperty, context);2510 }2511 }2512 else if (isTemplate) {2513 // <template v-for="...">2514 // should generate a fragment block for each loop2515 childBlock = createBlockExpression(createCallExpression(helper(CREATE_BLOCK), [2516 helper(FRAGMENT),2517 keyProperty ? createObjectExpression([keyProperty]) : `null`,2518 node.children2519 ]), context);2520 }2521 else {2522 // Normal element v-for. Directly use the child's codegenNode2523 // arguments, but replace createVNode() with createBlock()2524 let codegenNode = node.codegenNode;2525 if (codegenNode.callee === WITH_DIRECTIVES) {2526 codegenNode.arguments[0].callee = helper(CREATE_BLOCK);2527 }2528 else {2529 codegenNode.callee = helper(CREATE_BLOCK);2530 }2531 childBlock = createBlockExpression(codegenNode, context);2532 }2533 renderExp.arguments.push(createFunctionExpression(createForLoopParams(parseResult), childBlock, true /* force newline */));2534 };2535});2536const forAliasRE = /([\s\S]*?)\s+(?:in|of)\s+([\s\S]*)/;2537// This regex doesn't cover the case if key or index aliases have destructuring,2538// but those do not make sense in the first place, so this works in practice.2539const forIteratorRE = /,([^,\}\]]*)(?:,([^,\}\]]*))?$/;2540const stripParensRE = /^\(|\)$/g;2541function parseForExpression(input, context) {2542 const loc = input.loc;2543 const exp = input.content;2544 const inMatch = exp.match(forAliasRE);2545 if (!inMatch)2546 return;2547 const [, LHS, RHS] = inMatch;2548 const result = {2549 source: createAliasExpression(loc, RHS.trim(), exp.indexOf(RHS, LHS.length)),2550 value: undefined,2551 key: undefined,2552 index: undefined2553 };2554 if ( context.prefixIdentifiers) {2555 result.source = processExpression(result.source, context);2556 }2557 let valueContent = LHS.trim()2558 .replace(stripParensRE, '')2559 .trim();2560 const trimmedOffset = LHS.indexOf(valueContent);2561 const iteratorMatch = valueContent.match(forIteratorRE);2562 if (iteratorMatch) {2563 valueContent = valueContent.replace(forIteratorRE, '').trim();2564 const keyContent = iteratorMatch[1].trim();2565 let keyOffset;2566 if (keyContent) {2567 keyOffset = exp.indexOf(keyContent, trimmedOffset + valueContent.length);2568 result.key = createAliasExpression(loc, keyContent, keyOffset);2569 if ( context.prefixIdentifiers) {2570 result.key = processExpression(result.key, context, true);2571 }2572 }2573 if (iteratorMatch[2]) {2574 const indexContent = iteratorMatch[2].trim();2575 if (indexContent) {2576 result.index = createAliasExpression(loc, indexContent, exp.indexOf(indexContent, result.key2577 ? keyOffset + keyContent.length2578 : trimmedOffset + valueContent.length));2579 if ( context.prefixIdentifiers) {2580 result.index = processExpression(result.index, context, true);2581 }2582 }2583 }2584 }2585 if (valueContent) {2586 result.value = createAliasExpression(loc, valueContent, trimmedOffset);2587 if ( context.prefixIdentifiers) {2588 result.value = processExpression(result.value, context, true);2589 }2590 }2591 return result;2592}2593function createAliasExpression(range, content, offset) {2594 return createSimpleExpression(content, false, getInnerRange(range, offset, content.length));2595}2596function createForLoopParams({ value, key, index }) {2597 const params = [];2598 if (value) {2599 params.push(value);2600 }2601 if (key) {2602 if (!value) {2603 params.push(createSimpleExpression(`_`, false));2604 }2605 params.push(key);2606 }2607 if (index) {2608 if (!key) {2609 if (!value) {2610 params.push(createSimpleExpression(`_`, false));2611 }2612 params.push(createSimpleExpression(`__`, false));2613 }2614 params.push(index);2615 }2616 return params;2617}2618const isStaticExp = (p) => p.type === 4 /* SIMPLE_EXPRESSION */ && p.isStatic;2619const defaultFallback = createSimpleExpression(`undefined`, false);2620// A NodeTransform that:2621// 1. Tracks scope identifiers for scoped slots so that they don't get prefixed2622// by transformExpression. This is only applied in non-browser builds with2623// { prefixIdentifiers: true }.2624// 2. Track v-slot depths so that we know a slot is inside another slot.2625// Note the exit callback is executed before buildSlots() on the same node,2626// so only nested slots see positive numbers.2627const trackSlotScopes = (node, context) => {2628 if (node.type === 1 /* ELEMENT */ &&2629 (node.tagType === 1 /* COMPONENT */ ||2630 node.tagType === 3 /* TEMPLATE */)) {2631 // We are only checking non-empty v-slot here2632 // since we only care about slots that introduce scope variables.2633 const vSlot = findDir(node, 'slot');2634 if (vSlot) {2635 const slotProps = vSlot.exp;2636 if ( context.prefixIdentifiers) {2637 slotProps && context.addIdentifiers(slotProps);2638 }2639 context.scopes.vSlot++;2640 return () => {2641 if ( context.prefixIdentifiers) {2642 slotProps && context.removeIdentifiers(slotProps);2643 }2644 context.scopes.vSlot--;2645 };2646 }2647 }2648};2649// A NodeTransform that tracks scope identifiers for scoped slots with v-for.2650// This transform is only applied in non-browser builds with { prefixIdentifiers: true }2651const trackVForSlotScopes = (node, context) => {2652 let vFor;2653 if (isTemplateNode(node) &&2654 node.props.some(isVSlot) &&2655 (vFor = findDir(node, 'for'))) {2656 const result = (vFor.parseResult = parseForExpression(vFor.exp, context));2657 if (result) {2658 const { value, key, index } = result;2659 const { addIdentifiers, removeIdentifiers } = context;2660 value && addIdentifiers(value);2661 key && addIdentifiers(key);2662 index && addIdentifiers(index);2663 return () => {2664 value && removeIdentifiers(value);2665 key && removeIdentifiers(key);2666 index && removeIdentifiers(index);2667 };2668 }2669 }2670};2671// Instead of being a DirectiveTransform, v-slot processing is called during2672// transformElement to build the slots object for a component.2673function buildSlots(node, context) {2674 const { children, loc } = node;2675 const slotsProperties = [];2676 const dynamicSlots = [];2677 // If the slot is inside a v-for or another v-slot, force it to be dynamic2678 // since it likely uses a scope variable.2679 let hasDynamicSlots = context.scopes.vSlot > 0 || context.scopes.vFor > 0;2680 // with `prefixIdentifiers: true`, this can be further optimized to make2681 // it dynamic only when the slot actually uses the scope variables.2682 if ( context.prefixIdentifiers) {2683 hasDynamicSlots = hasScopeRef(node, context.identifiers);2684 }2685 // 1. Check for default slot with slotProps on component itself.2686 // <Comp v-slot="{ prop }"/>2687 const explicitDefaultSlot = findDir(node, 'slot', true);2688 if (explicitDefaultSlot) {2689 const { arg, exp, loc } = explicitDefaultSlot;2690 if (arg) {2691 context.onError(createCompilerError(42 /* X_V_SLOT_NAMED_SLOT_ON_COMPONENT */, loc));2692 }2693 slotsProperties.push(buildDefaultSlot(exp, children, loc));2694 }2695 // 2. Iterate through children and check for template slots2696 // <template v-slot:foo="{ prop }">2697 let hasTemplateSlots = false;2698 let extraneousChild = undefined;2699 const seenSlotNames = new Set();2700 for (let i = 0; i < children.length; i++) {2701 const slotElement = children[i];2702 let slotDir;2703 if (!isTemplateNode(slotElement) ||2704 !(slotDir = findDir(slotElement, 'slot', true))) {2705 // not a <template v-slot>, skip.2706 if (slotElement.type !== 3 /* COMMENT */ && !extraneousChild) {2707 extraneousChild = slotElement;2708 }2709 continue;2710 }2711 if (explicitDefaultSlot) {2712 // already has on-component default slot - this is incorrect usage.2713 context.onError(createCompilerError(43 /* X_V_SLOT_MIXED_SLOT_USAGE */, slotDir.loc));2714 break;2715 }2716 hasTemplateSlots = true;2717 const { children: slotChildren, loc: slotLoc } = slotElement;2718 const { arg: slotName = createSimpleExpression(`default`, true), exp: slotProps, loc: dirLoc } = slotDir;2719 // check if name is dynamic.2720 let staticSlotName;2721 if (isStaticExp(slotName)) {2722 staticSlotName = slotName ? slotName.content : `default`;2723 }2724 else {2725 hasDynamicSlots = true;2726 }2727 const slotFunction = createFunctionExpression(slotProps, slotChildren, false, slotChildren.length ? slotChildren[0].loc : slotLoc);2728 // check if this slot is conditional (v-if/v-for)2729 let vIf;2730 let vElse;2731 let vFor;2732 if ((vIf = findDir(slotElement, 'if'))) {2733 hasDynamicSlots = true;2734 dynamicSlots.push(createConditionalExpression(vIf.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback));2735 }2736 else if ((vElse = findDir(slotElement, /^else(-if)?$/, true /* allowEmpty */))) {2737 // find adjacent v-if2738 let j = i;2739 let prev;2740 while (j--) {2741 prev = children[j];2742 if (prev.type !== 3 /* COMMENT */) {2743 break;2744 }2745 }2746 if (prev && isTemplateNode(prev) && findDir(prev, 'if')) {2747 // remove node2748 children.splice(i, 1);2749 i--;2750 // attach this slot to previous conditional2751 let conditional = dynamicSlots[dynamicSlots.length - 1];2752 while (conditional.alternate.type === 19 /* JS_CONDITIONAL_EXPRESSION */) {2753 conditional = conditional.alternate;2754 }2755 conditional.alternate = vElse.exp2756 ? createConditionalExpression(vElse.exp, buildDynamicSlot(slotName, slotFunction), defaultFallback)2757 : buildDynamicSlot(slotName, slotFunction);2758 }2759 else {2760 context.onError(createCompilerError(36 /* X_V_ELSE_NO_ADJACENT_IF */, vElse.loc));2761 }2762 }2763 else if ((vFor = findDir(slotElement, 'for'))) {2764 hasDynamicSlots = true;2765 const parseResult = vFor.parseResult ||2766 parseForExpression(vFor.exp, context);2767 if (parseResult) {2768 // Render the dynamic slots as an array and add it to the createSlot()2769 // args. The runtime knows how to handle it appropriately.2770 dynamicSlots.push(createCallExpression(context.helper(RENDER_LIST), [2771 parseResult.source,2772 createFunctionExpression(createForLoopParams(parseResult), buildDynamicSlot(slotName, slotFunction), true)2773 ]));2774 }2775 else {2776 context.onError(createCompilerError(38 /* X_V_FOR_MALFORMED_EXPRESSION */, vFor.loc));2777 }2778 }2779 else {2780 // check duplicate static names2781 if (staticSlotName) {2782 if (seenSlotNames.has(staticSlotName)) {2783 context.onError(createCompilerError(44 /* X_V_SLOT_DUPLICATE_SLOT_NAMES */, dirLoc));2784 continue;2785 }2786 seenSlotNames.add(staticSlotName);2787 }2788 slotsProperties.push(createObjectProperty(slotName, slotFunction));2789 }2790 }2791 if (hasTemplateSlots && extraneousChild) {2792 context.onError(createCompilerError(45 /* X_V_SLOT_EXTRANEOUS_NON_SLOT_CHILDREN */, extraneousChild.loc));2793 }2794 if (!explicitDefaultSlot && !hasTemplateSlots) {2795 // implicit default slot.2796 slotsProperties.push(buildDefaultSlot(undefined, children, loc));2797 }2798 let slots = createObjectExpression(slotsProperties.concat(createObjectProperty(`_compiled`, createSimpleExpression(`true`, false))), loc);2799 if (dynamicSlots.length) {2800 slots = createCallExpression(context.helper(CREATE_SLOTS), [2801 slots,2802 createArrayExpression(dynamicSlots)2803 ]);2804 }2805 return {2806 slots,2807 hasDynamicSlots2808 };2809}2810function buildDefaultSlot(slotProps, children, loc) {2811 return createObjectProperty(`default`, createFunctionExpression(slotProps, children, false, children.length ? children[0].loc : loc));2812}2813function buildDynamicSlot(name, fn) {2814 return createObjectExpression([2815 createObjectProperty(`name`, name),2816 createObjectProperty(`fn`, fn)2817 ]);2818}2819// some directive transforms (e.g. v-model) may return a symbol for runtime2820// import, which should be used instead of a resolveDirective call.2821const directiveImportMap = new WeakMap();2822// generate a JavaScript AST for this element's codegen2823const transformElement = (node, context) => {2824 if (node.type !== 1 /* ELEMENT */ ||2825 // handled by transformSlotOutlet2826 node.tagType === 2 /* SLOT */ ||2827 // <template v-if/v-for> should have already been replaced2828 // <templte v-slot> is handled by buildSlots2829 (node.tagType === 3 /* TEMPLATE */ && node.props.some(isVSlot))) {2830 return;2831 }2832 // perform the work on exit, after all child expressions have been2833 // processed and merged.2834 return () => {2835 const isComponent = node.tagType === 1 /* COMPONENT */;2836 let hasProps = node.props.length > 0;2837 let patchFlag = 0;2838 let runtimeDirectives;2839 let dynamicPropNames;2840 let dynamicComponent;2841 // handle dynamic component2842 const isProp = findProp(node, 'is');2843 if (node.tag === 'component') {2844 if (isProp) {2845 // static <component is="foo" />2846 if (isProp.type === 6 /* ATTRIBUTE */) {2847 const tag = isProp.value && isProp.value.content;2848 if (tag) {2849 context.helper(RESOLVE_COMPONENT);2850 context.components.add(tag);2851 dynamicComponent = toValidAssetId(tag, `component`);2852 }2853 }2854 // dynamic <component :is="asdf" />2855 else if (isProp.exp) {2856 dynamicComponent = createCallExpression(context.helper(RESOLVE_DYNAMIC_COMPONENT), [isProp.exp]);2857 }2858 }2859 }2860 if (isComponent && !dynamicComponent) {2861 context.helper(RESOLVE_COMPONENT);2862 context.components.add(node.tag);2863 }2864 const args = [2865 dynamicComponent2866 ? dynamicComponent2867 : isComponent2868 ? toValidAssetId(node.tag, `component`)2869 : node.tagType === 4 /* PORTAL */2870 ? context.helper(PORTAL)2871 : node.tagType === 5 /* SUSPENSE */2872 ? context.helper(SUSPENSE)2873 : `"${node.tag}"`2874 ];2875 // props2876 if (hasProps) {2877 const propsBuildResult = buildProps(node, context, 2878 // skip reserved "is" prop <component is>2879 node.props.filter(p => p !== isProp));2880 patchFlag = propsBuildResult.patchFlag;2881 dynamicPropNames = propsBuildResult.dynamicPropNames;2882 runtimeDirectives = propsBuildResult.directives;2883 if (!propsBuildResult.props) {2884 hasProps = false;2885 }2886 else {2887 args.push(propsBuildResult.props);2888 }2889 }2890 // children2891 const hasChildren = node.children.length > 0;2892 if (hasChildren) {2893 if (!hasProps) {2894 args.push(`null`);2895 }2896 if (isComponent || node.tagType === 5 /* SUSPENSE */) {2897 const { slots, hasDynamicSlots } = buildSlots(node, context);2898 args.push(slots);2899 if (hasDynamicSlots) {2900 patchFlag |= 256 /* DYNAMIC_SLOTS */;2901 }2902 }2903 else if (node.children.length === 1) {2904 const child = node.children[0];2905 const type = child.type;2906 // check for dynamic text children2907 const hasDynamicTextChild = type === 5 /* INTERPOLATION */ ||2908 type === 8 /* COMPOUND_EXPRESSION */;2909 if (hasDynamicTextChild && !isStaticNode(child)) {2910 patchFlag |= 1 /* TEXT */;2911 }2912 // pass directly if the only child is a text node2913 // (plain / interpolation / expression)2914 if (hasDynamicTextChild || type === 2 /* TEXT */) {2915 args.push(child);2916 }2917 else {2918 args.push(node.children);2919 }2920 }2921 else {2922 args.push(node.children);2923 }2924 }2925 // patchFlag & dynamicPropNames2926 if (patchFlag !== 0) {2927 if (!hasChildren) {2928 if (!hasProps) {2929 args.push(`null`);2930 }2931 args.push(`null`);2932 }2933 {2934 args.push(patchFlag + '');2935 }2936 if (dynamicPropNames && dynamicPropNames.length) {2937 args.push(`[${dynamicPropNames.map(n => JSON.stringify(n)).join(`, `)}]`);2938 }2939 }2940 const { loc } = node;2941 const vnode = createCallExpression(context.helper(CREATE_VNODE), args, loc);2942 if (runtimeDirectives && runtimeDirectives.length) {2943 node.codegenNode = createCallExpression(context.helper(WITH_DIRECTIVES), [2944 vnode,2945 createArrayExpression(runtimeDirectives.map(dir => buildDirectiveArgs(dir, context)), loc)2946 ], loc);2947 }2948 else {2949 node.codegenNode = vnode;2950 }2951 };2952};2953function buildProps(node, context, props = node.props) {2954 const elementLoc = node.loc;2955 const isComponent = node.tagType === 1 /* COMPONENT */;2956 let properties = [];2957 const mergeArgs = [];2958 const runtimeDirectives = [];2959 // patchFlag analysis2960 let patchFlag = 0;2961 let hasRef = false;2962 let hasClassBinding = false;2963 let hasStyleBinding = false;2964 let hasDynamicKeys = false;2965 const dynamicPropNames = [];2966 const analyzePatchFlag = ({ key, value }) => {2967 if (key.type === 4 /* SIMPLE_EXPRESSION */ && key.isStatic) {2968 if (value.type === 20 /* JS_CACHE_EXPRESSION */ ||2969 ((value.type === 4 /* SIMPLE_EXPRESSION */ ||2970 value.type === 8 /* COMPOUND_EXPRESSION */) &&2971 isStaticNode(value))) {2972 return;2973 }2974 const name = key.content;2975 if (name === 'ref') {2976 hasRef = true;2977 }2978 else if (name === 'class') {2979 hasClassBinding = true;2980 }2981 else if (name === 'style') {2982 hasStyleBinding = true;2983 }2984 else if (name !== 'key') {2985 dynamicPropNames.push(name);2986 }2987 }2988 else {2989 hasDynamicKeys = true;2990 }2991 };2992 for (let i = 0; i < props.length; i++) {2993 // static attribute2994 const prop = props[i];2995 if (prop.type === 6 /* ATTRIBUTE */) {2996 const { loc, name, value } = prop;2997 if (name === 'ref') {2998 hasRef = true;2999 }3000 properties.push(createObjectProperty(createSimpleExpression(name, true, getInnerRange(loc, 0, name.length)), createSimpleExpression(value ? value.content : '', true, value ? value.loc : loc)));3001 }3002 else {3003 // directives3004 const { name, arg, exp, loc } = prop;3005 // skip v-slot - it is handled by its dedicated transform.3006 if (name === 'slot') {3007 if (!isComponent) {3008 context.onError(createCompilerError(46 /* X_V_SLOT_MISPLACED */, loc));3009 }3010 continue;3011 }3012 // skip v-once - it is handled by its dedicated transform.3013 if (name === 'once') {3014 continue;3015 }3016 // special case for v-bind and v-on with no argument3017 const isBind = name === 'bind';3018 const isOn = name === 'on';3019 if (!arg && (isBind || isOn)) {3020 hasDynamicKeys = true;3021 if (exp) {3022 if (properties.length) {3023 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3024 properties = [];3025 }3026 if (isBind) {3027 mergeArgs.push(exp);3028 }3029 else {3030 // v-on="obj" -> toHandlers(obj)3031 mergeArgs.push({3032 type: 13 /* JS_CALL_EXPRESSION */,3033 loc,3034 callee: context.helper(TO_HANDLERS),3035 arguments: [exp]3036 });3037 }3038 }3039 else {3040 context.onError(createCompilerError(isBind3041 ? 39 /* X_V_BIND_NO_EXPRESSION */3042 : 40 /* X_V_ON_NO_EXPRESSION */, loc));3043 }3044 continue;3045 }3046 const directiveTransform = context.directiveTransforms[name];3047 if (directiveTransform) {3048 // has built-in directive transform.3049 const { props, needRuntime } = directiveTransform(prop, node, context);3050 props.forEach(analyzePatchFlag);3051 properties.push(...props);3052 if (needRuntime) {3053 runtimeDirectives.push(prop);3054 if (isSymbol(needRuntime)) {3055 directiveImportMap.set(prop, needRuntime);3056 }3057 }3058 }3059 else {3060 // no built-in transform, this is a user custom directive.3061 runtimeDirectives.push(prop);3062 }3063 }3064 }3065 let propsExpression = undefined;3066 // has v-bind="object" or v-on="object", wrap with mergeProps3067 if (mergeArgs.length) {3068 if (properties.length) {3069 mergeArgs.push(createObjectExpression(dedupeProperties(properties), elementLoc));3070 }3071 if (mergeArgs.length > 1) {3072 propsExpression = createCallExpression(context.helper(MERGE_PROPS), mergeArgs, elementLoc);3073 }3074 else {3075 // single v-bind with nothing else - no need for a mergeProps call3076 propsExpression = mergeArgs[0];3077 }3078 }3079 else if (properties.length) {3080 propsExpression = createObjectExpression(dedupeProperties(properties), elementLoc);3081 }3082 // patchFlag analysis3083 if (hasDynamicKeys) {3084 patchFlag |= 16 /* FULL_PROPS */;3085 }3086 else {3087 if (hasClassBinding) {3088 patchFlag |= 2 /* CLASS */;3089 }3090 if (hasStyleBinding) {3091 patchFlag |= 4 /* STYLE */;3092 }3093 if (dynamicPropNames.length) {3094 patchFlag |= 8 /* PROPS */;3095 }3096 }3097 if (patchFlag === 0 && (hasRef || runtimeDirectives.length > 0)) {3098 patchFlag |= 32 /* NEED_PATCH */;3099 }3100 return {3101 props: propsExpression,3102 directives: runtimeDirectives,3103 patchFlag,3104 dynamicPropNames3105 };3106}3107// Dedupe props in an object literal.3108// Literal duplicated attributes would have been warned during the parse phase,3109// however, it's possible to encounter duplicated `onXXX` handlers with different3110// modifiers. We also need to merge static and dynamic class / style attributes.3111// - onXXX handlers / style: merge into array3112// - class: merge into single expression with concatenation3113function dedupeProperties(properties) {3114 const knownProps = {};3115 const deduped = [];3116 for (let i = 0; i < properties.length; i++) {3117 const prop = properties[i];3118 // dynamic keys are always allowed3119 if (prop.key.type === 8 /* COMPOUND_EXPRESSION */ || !prop.key.isStatic) {3120 deduped.push(prop);3121 continue;3122 }3123 const name = prop.key.content;3124 const existing = knownProps[name];3125 if (existing) {3126 if (name === 'style' ||3127 name === 'class' ||3128 name.startsWith('on') ||3129 name.startsWith('vnode')) {3130 mergeAsArray(existing, prop);3131 }3132 // unexpected duplicate, should have emitted error during parse3133 }3134 else {3135 knownProps[name] = prop;3136 deduped.push(prop);3137 }3138 }3139 return deduped;3140}3141function mergeAsArray(existing, incoming) {3142 if (existing.value.type === 16 /* JS_ARRAY_EXPRESSION */) {3143 existing.value.elements.push(incoming.value);3144 }3145 else {3146 existing.value = createArrayExpression([existing.value, incoming.value], existing.loc);3147 }3148}3149function buildDirectiveArgs(dir, context) {3150 const dirArgs = [];3151 const runtime = directiveImportMap.get(dir);3152 if (runtime) {3153 context.helper(runtime);3154 dirArgs.push(context.helperString(runtime));3155 }3156 else {3157 // inject statement for resolving directive3158 context.helper(RESOLVE_DIRECTIVE);3159 context.directives.add(dir.name);3160 dirArgs.push(toValidAssetId(dir.name, `directive`));3161 }3162 const { loc } = dir;3163 if (dir.exp)3164 dirArgs.push(dir.exp);3165 if (dir.arg) {3166 if (!dir.exp) {3167 dirArgs.push(`void 0`);3168 }3169 dirArgs.push(dir.arg);3170 }3171 if (Object.keys(dir.modifiers).length) {3172 if (!dir.arg) {3173 if (!dir.exp) {3174 dirArgs.push(`void 0`);...
genCode.js
Source:genCode.js
...193 const maybeSelfReference = id.endsWith('__self');194 if (maybeSelfReference) {195 id = id.slice(0, -6);196 }197 push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)}${maybeSelfReference ? `, true` : ``})`);198 if (i < assets.length - 1) {199 newline();200 }201 }202}203function genHoists(hoists, context) {204 if (!hoists.length) {205 return;206 }207 context.pure = true;208 const { push, newline, helper, scopeId, mode } = context;209 newline();210 hoists.forEach((exp, i) => {211 if (exp) {...
transformElement.js
Source:transformElement.js
...133 const { tag } = node;134 // TODO 1. å¨æç»ä»¶å¤ç135 // TODO 2. å
ç½®ç»ä»¶å¤ç(Teleport, Transition, KeepAlive, Suspense...)136 // TODO 3. ç¨æ·ç»ä»¶å¤ç137 return toValidAssetId(tag, `component`);138}139export function buildProps(node, context, props = node.props, ssr = false) {140 const { tag, loc: elementLoc } = node;141 const isComponent = node.tagType === ElementTypes.COMPONENT;142 let properties = [];143 // ä¿åå并ä¹åçå±æ§ï¼åææ¯æéå¤å±æ§ï¼æ¯å¦ï¼144 // class,style ä¼å并æä¸ä¸ª145 // v-on ç handlers ä¼å并ææ°ç»146 const mergeArgs = [];147 const runtimeDirectives = [];148 let patchFlag = 0;149 let hasRef = false;150 let hasClassBinding = false;151 let hasStyleBinding = false;...
utils.js
Source:utils.js
...174 node.arguments[1] = propsWithInjection;175 }176}177exports.injectProp = injectProp;178function toValidAssetId(name, type) {179 return "_" + type + "_" + name.replace(/[^\w]/g, '_');180}181exports.toValidAssetId = toValidAssetId;182function hasScopeRef(node, ids) {183 if (!node || Object.keys(ids).length === 0) {184 return false;185 }186 switch (node.type) {187 case 1:188 for (var i = 0; i < node.props.length; i++) {189 var p = node.props[i];190 if (p.type === 7 &&191 (hasScopeRef(p.arg, ids) || hasScopeRef(p.exp, ids))) {192 return true;...
codegen.js
Source:codegen.js
...168function genAssets(assets, type, { helper, push, newline }) {169 const resolver = helper(type === 'component' ? RESOLVE_COMPONENT : RESOLVE_DIRECTIVE)170 for (let i = 0; i < assets.length; i++) {171 const id = assets[i]172 push(`const ${toValidAssetId(id, type)} = ${resolver}(${JSON.stringify(id)})`)173 if (i < assets.length - 1) {174 newline()175 }176 }...
Using AI Code Generation
1const { toValidAssetId } = require('@playwright/test/lib/utils/utils');2const assetId = toValidAssetId('test');3console.log(assetId);4const { toValidAssetId } = require('playwright-internal-api');5const assetId = toValidAssetId('test');6console.log(assetId);7const { toValidAssetId } = require('playwright-internal-api');8const assetId = toValidAssetId('test');9console.log(assetId);
Using AI Code Generation
1const { toValidAssetId } = require('@playwright/test/lib/utils/utils');2const id = toValidAssetId('test');3console.log(id);4 at Object.<anonymous> (/Users/xxx/playwright-test/test.js:5:31)5 at Module._compile (internal/modules/cjs/loader.js:1137:30)6 at Object.Module._extensions..js (internal/modules/cjs/loader.js:1157:10)7 at Module.load (internal/modules/cjs/loader.js:985:32)8 at Function.Module._load (internal/modules/cjs/loader.js:878:14)9 at Function.executeUserEntryPoint [as runMain] (internal/modules/run_main.js:71:12)
LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.
Get 100 minutes of automation test minutes FREE!!