How to use toValidAssetId method in Playwright Internal

Best JavaScript code snippet using playwright-internal

compiler-dom.global.js

Source:compiler-dom.global.js Github

copy

Full Screen

...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`);...

Full Screen

Full Screen

compiler-core.cjs.js

Source:compiler-core.cjs.js Github

copy

Full Screen

...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`);...

Full Screen

Full Screen

compiler-core.cjs.prod.js

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

copy

Full Screen

...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`);...

Full Screen

Full Screen

genCode.js

Source:genCode.js Github

copy

Full Screen

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

Full Screen

Full Screen

transformElement.js

Source:transformElement.js Github

copy

Full Screen

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

Full Screen

Full Screen

utils.js

Source:utils.js Github

copy

Full Screen

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

Full Screen

Full Screen

codegen.js

Source:codegen.js Github

copy

Full Screen

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

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

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

Full Screen

Using AI Code Generation

copy

Full Screen

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)

Full Screen

Playwright tutorial

LambdaTest’s Playwright tutorial will give you a broader idea about the Playwright automation framework, its unique features, and use cases with examples to exceed your understanding of Playwright testing. This tutorial will give A to Z guidance, from installing the Playwright framework to some best practices and advanced concepts.

Chapters:

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

Run Playwright Internal automation tests on LambdaTest cloud grid

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

Try LambdaTest Now !!

Get 100 minutes of automation test minutes FREE!!

Next-Gen App & Browser Testing Cloud

Was this article helpful?

Helpful

NotHelpful