How to use createCacheExpression method in Playwright Internal

Best JavaScript code snippet using playwright-internal

compiler-dom.global.js

Source:compiler-dom.global.js Github

copy

Full Screen

...213 alternate,214 loc: locStub215 };216 }217 function createCacheExpression(index, value, isVNode = false) {218 return {219 type: 20 /* JS_CACHE_EXPRESSION */,220 index,221 value,222 isVNode,223 loc: locStub224 };225 }226 const FRAGMENT = Symbol( `Fragment` );227 const PORTAL = Symbol( `Portal` );228 const SUSPENSE = Symbol( `Suspense` );229 const OPEN_BLOCK = Symbol( `openBlock` );230 const CREATE_BLOCK = Symbol( `createBlock` );231 const CREATE_VNODE = Symbol( `createVNode` );232 const CREATE_COMMENT = Symbol( `createCommentVNode` );233 const CREATE_TEXT = Symbol( `createTextVNode` );234 const RESOLVE_COMPONENT = Symbol( `resolveComponent` );235 const RESOLVE_DYNAMIC_COMPONENT = Symbol( `resolveDynamicComponent` );236 const RESOLVE_DIRECTIVE = Symbol( `resolveDirective` );237 const WITH_DIRECTIVES = Symbol( `withDirectives` );238 const RENDER_LIST = Symbol( `renderList` );239 const RENDER_SLOT = Symbol( `renderSlot` );240 const CREATE_SLOTS = Symbol( `createSlots` );241 const TO_STRING = Symbol( `toString` );242 const MERGE_PROPS = Symbol( `mergeProps` );243 const TO_HANDLERS = Symbol( `toHandlers` );244 const CAMELIZE = Symbol( `camelize` );245 const SET_BLOCK_TRACKING = Symbol( `setBlockTracking` );246 // Name mapping for runtime helpers that need to be imported from 'vue' in247 // generated code. Make sure these are correctly exported in the runtime!248 // Using `any` here because TS doesn't allow symbols as index type.249 const helperNameMap = {250 [FRAGMENT]: `Fragment`,251 [PORTAL]: `Portal`,252 [SUSPENSE]: `Suspense`,253 [OPEN_BLOCK]: `openBlock`,254 [CREATE_BLOCK]: `createBlock`,255 [CREATE_VNODE]: `createVNode`,256 [CREATE_COMMENT]: `createCommentVNode`,257 [CREATE_TEXT]: `createTextVNode`,258 [RESOLVE_COMPONENT]: `resolveComponent`,259 [RESOLVE_DYNAMIC_COMPONENT]: `resolveDynamicComponent`,260 [RESOLVE_DIRECTIVE]: `resolveDirective`,261 [WITH_DIRECTIVES]: `withDirectives`,262 [RENDER_LIST]: `renderList`,263 [RENDER_SLOT]: `renderSlot`,264 [CREATE_SLOTS]: `createSlots`,265 [TO_STRING]: `toString`,266 [MERGE_PROPS]: `mergeProps`,267 [TO_HANDLERS]: `toHandlers`,268 [CAMELIZE]: `camelize`,269 [SET_BLOCK_TRACKING]: `setBlockTracking`270 };271 function registerRuntimeHelpers(helpers) {272 Object.getOwnPropertySymbols(helpers).forEach(s => {273 helperNameMap[s] = helpers[s];274 });275 }276 // cache node requires277 // lazy require dependencies so that they don't end up in rollup's dep graph278 // and thus can be tree-shaken in browser builds.279 let _parse;280 let _walk;281 function loadDep(name) {282 if (typeof process !== 'undefined' && isFunction(require)) {283 return require(name);284 }285 else {286 // This is only used when we are building a dev-only build of the compiler287 // which runs in the browser but also uses Node deps.288 return window._deps[name];289 }290 }291 const parseJS = (code, options) => {292 assert(!true, `Expression AST analysis can only be performed in non-browser builds.`);293 const parse = _parse || (_parse = loadDep('acorn').parse);294 return parse(code, options);295 };296 const walkJS = (ast, walker) => {297 assert(!true, `Expression AST analysis can only be performed in non-browser builds.`);298 const walk = _walk || (_walk = loadDep('estree-walker').walk);299 return walk(ast, walker);300 };301 const nonIdentifierRE = /^\d|[^\$\w]/;302 const isSimpleIdentifier = (name) => !nonIdentifierRE.test(name);303 const memberExpRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\[[^\]]+\])*$/;304 const isMemberExpression = (path) => memberExpRE.test(path);305 function getInnerRange(loc, offset, length) {306 assert(offset <= loc.source.length);307 const source = loc.source.substr(offset, length);308 const newLoc = {309 source,310 start: advancePositionWithClone(loc.start, loc.source, offset),311 end: loc.end312 };313 if (length != null) {314 assert(offset + length <= loc.source.length);315 newLoc.end = advancePositionWithClone(loc.start, loc.source, offset + length);316 }317 return newLoc;318 }319 function advancePositionWithClone(pos, source, numberOfCharacters = source.length) {320 return advancePositionWithMutation({ ...pos }, source, numberOfCharacters);321 }322 // advance by mutation without cloning (for performance reasons), since this323 // gets called a lot in the parser324 function advancePositionWithMutation(pos, source, numberOfCharacters = source.length) {325 let linesCount = 0;326 let lastNewLinePos = -1;327 for (let i = 0; i < numberOfCharacters; i++) {328 if (source.charCodeAt(i) === 10 /* newline char code */) {329 linesCount++;330 lastNewLinePos = i;331 }332 }333 pos.offset += numberOfCharacters;334 pos.line += linesCount;335 pos.column =336 lastNewLinePos === -1337 ? pos.column + numberOfCharacters338 : Math.max(1, numberOfCharacters - lastNewLinePos);339 return pos;340 }341 function assert(condition, msg) {342 /* istanbul ignore if */343 if (!condition) {344 throw new Error(msg || `unexpected compiler condition`);345 }346 }347 function findDir(node, name, allowEmpty = false) {348 for (let i = 0; i < node.props.length; i++) {349 const p = node.props[i];350 if (p.type === 7 /* DIRECTIVE */ &&351 (allowEmpty || p.exp) &&352 (isString(name) ? p.name === name : name.test(p.name))) {353 return p;354 }355 }356 }357 function findProp(node, name, dynamicOnly = false) {358 for (let i = 0; i < node.props.length; i++) {359 const p = node.props[i];360 if (p.type === 6 /* ATTRIBUTE */) {361 if (dynamicOnly)362 continue;363 if (p.name === name && p.value) {364 return p;365 }366 }367 else if (p.name === 'bind' &&368 p.arg &&369 p.arg.type === 4 /* SIMPLE_EXPRESSION */ &&370 p.arg.isStatic &&371 p.arg.content === name &&372 p.exp) {373 return p;374 }375 }376 }377 function createBlockExpression(blockExp, context) {378 return createSequenceExpression([379 createCallExpression(context.helper(OPEN_BLOCK)),380 blockExp381 ]);382 }383 function isVSlot(p) {384 return p.type === 7 /* DIRECTIVE */ && p.name === 'slot';385 }386 function isTemplateNode(node) {387 return (node.type === 1 /* ELEMENT */ && node.tagType === 3 /* TEMPLATE */);388 }389 function isSlotOutlet(node) {390 return node.type === 1 /* ELEMENT */ && node.tagType === 2 /* SLOT */;391 }392 function injectProp(node, prop, context) {393 let propsWithInjection;394 const props = node.callee === RENDER_SLOT ? node.arguments[2] : node.arguments[1];395 if (props == null || isString(props)) {396 propsWithInjection = createObjectExpression([prop]);397 }398 else if (props.type === 13 /* JS_CALL_EXPRESSION */) {399 // merged props... add ours400 // only inject key to object literal if it's the first argument so that401 // if doesn't override user provided keys402 const first = props.arguments[0];403 if (!isString(first) && first.type === 14 /* JS_OBJECT_EXPRESSION */) {404 first.properties.unshift(prop);405 }406 else {407 props.arguments.unshift(createObjectExpression([prop]));408 }409 propsWithInjection = props;410 }411 else if (props.type === 14 /* JS_OBJECT_EXPRESSION */) {412 props.properties.unshift(prop);413 propsWithInjection = props;414 }415 else {416 // single v-bind with expression, return a merged replacement417 propsWithInjection = createCallExpression(context.helper(MERGE_PROPS), [418 createObjectExpression([prop]),419 props420 ]);421 }422 if (node.callee === RENDER_SLOT) {423 node.arguments[2] = propsWithInjection;424 }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;...

Full Screen

Full Screen

compiler-core.cjs.js

Source:compiler-core.cjs.js Github

copy

Full Screen

...217 alternate,218 loc: locStub219 };220}221function createCacheExpression(index, value, isVNode = false) {222 return {223 type: 20 /* JS_CACHE_EXPRESSION */,224 index,225 value,226 isVNode,227 loc: locStub228 };229}230const FRAGMENT = Symbol( `Fragment` );231const PORTAL = Symbol( `Portal` );232const SUSPENSE = Symbol( `Suspense` );233const OPEN_BLOCK = Symbol( `openBlock` );234const CREATE_BLOCK = Symbol( `createBlock` );235const CREATE_VNODE = Symbol( `createVNode` );236const CREATE_COMMENT = Symbol( `createCommentVNode` );237const CREATE_TEXT = Symbol( `createTextVNode` );238const RESOLVE_COMPONENT = Symbol( `resolveComponent` );239const RESOLVE_DYNAMIC_COMPONENT = Symbol( `resolveDynamicComponent` );240const RESOLVE_DIRECTIVE = Symbol( `resolveDirective` );241const WITH_DIRECTIVES = Symbol( `withDirectives` );242const RENDER_LIST = Symbol( `renderList` );243const RENDER_SLOT = Symbol( `renderSlot` );244const CREATE_SLOTS = Symbol( `createSlots` );245const TO_STRING = Symbol( `toString` );246const MERGE_PROPS = Symbol( `mergeProps` );247const TO_HANDLERS = Symbol( `toHandlers` );248const CAMELIZE = Symbol( `camelize` );249const SET_BLOCK_TRACKING = Symbol( `setBlockTracking` );250// Name mapping for runtime helpers that need to be imported from 'vue' in251// generated code. Make sure these are correctly exported in the runtime!252// Using `any` here because TS doesn't allow symbols as index type.253const helperNameMap = {254 [FRAGMENT]: `Fragment`,255 [PORTAL]: `Portal`,256 [SUSPENSE]: `Suspense`,257 [OPEN_BLOCK]: `openBlock`,258 [CREATE_BLOCK]: `createBlock`,259 [CREATE_VNODE]: `createVNode`,260 [CREATE_COMMENT]: `createCommentVNode`,261 [CREATE_TEXT]: `createTextVNode`,262 [RESOLVE_COMPONENT]: `resolveComponent`,263 [RESOLVE_DYNAMIC_COMPONENT]: `resolveDynamicComponent`,264 [RESOLVE_DIRECTIVE]: `resolveDirective`,265 [WITH_DIRECTIVES]: `withDirectives`,266 [RENDER_LIST]: `renderList`,267 [RENDER_SLOT]: `renderSlot`,268 [CREATE_SLOTS]: `createSlots`,269 [TO_STRING]: `toString`,270 [MERGE_PROPS]: `mergeProps`,271 [TO_HANDLERS]: `toHandlers`,272 [CAMELIZE]: `camelize`,273 [SET_BLOCK_TRACKING]: `setBlockTracking`274};275function registerRuntimeHelpers(helpers) {276 Object.getOwnPropertySymbols(helpers).forEach(s => {277 helperNameMap[s] = helpers[s];278 });279}280// cache node requires281// lazy require dependencies so that they don't end up in rollup's dep graph282// and thus can be tree-shaken in browser builds.283let _parse;284let _walk;285function loadDep(name) {286 if (typeof process !== 'undefined' && isFunction(require)) {287 return require(name);288 }289 else {290 // This is only used when we are building a dev-only build of the compiler291 // which runs in the browser but also uses Node deps.292 return window._deps[name];293 }294}295const parseJS = (code, options) => {296 assert(!false, `Expression AST analysis can only be performed in non-browser builds.`);297 const parse = _parse || (_parse = loadDep('acorn').parse);298 return parse(code, options);299};300const walkJS = (ast, walker) => {301 assert(!false, `Expression AST analysis can only be performed in non-browser builds.`);302 const walk = _walk || (_walk = loadDep('estree-walker').walk);303 return walk(ast, walker);304};305const nonIdentifierRE = /^\d|[^\$\w]/;306const isSimpleIdentifier = (name) => !nonIdentifierRE.test(name);307const memberExpRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\[[^\]]+\])*$/;308const isMemberExpression = (path) => memberExpRE.test(path);309function getInnerRange(loc, offset, length) {310 assert(offset <= loc.source.length);311 const source = loc.source.substr(offset, length);312 const newLoc = {313 source,314 start: advancePositionWithClone(loc.start, loc.source, offset),315 end: loc.end316 };317 if (length != null) {318 assert(offset + length <= loc.source.length);319 newLoc.end = advancePositionWithClone(loc.start, loc.source, offset + length);320 }321 return newLoc;322}323function advancePositionWithClone(pos, source, numberOfCharacters = source.length) {324 return advancePositionWithMutation({ ...pos }, source, numberOfCharacters);325}326// advance by mutation without cloning (for performance reasons), since this327// gets called a lot in the parser328function advancePositionWithMutation(pos, source, numberOfCharacters = source.length) {329 let linesCount = 0;330 let lastNewLinePos = -1;331 for (let i = 0; i < numberOfCharacters; i++) {332 if (source.charCodeAt(i) === 10 /* newline char code */) {333 linesCount++;334 lastNewLinePos = i;335 }336 }337 pos.offset += numberOfCharacters;338 pos.line += linesCount;339 pos.column =340 lastNewLinePos === -1341 ? pos.column + numberOfCharacters342 : Math.max(1, numberOfCharacters - lastNewLinePos);343 return pos;344}345function assert(condition, msg) {346 /* istanbul ignore if */347 if (!condition) {348 throw new Error(msg || `unexpected compiler condition`);349 }350}351function findDir(node, name, allowEmpty = false) {352 for (let i = 0; i < node.props.length; i++) {353 const p = node.props[i];354 if (p.type === 7 /* DIRECTIVE */ &&355 (allowEmpty || p.exp) &&356 (isString(name) ? p.name === name : name.test(p.name))) {357 return p;358 }359 }360}361function findProp(node, name, dynamicOnly = false) {362 for (let i = 0; i < node.props.length; i++) {363 const p = node.props[i];364 if (p.type === 6 /* ATTRIBUTE */) {365 if (dynamicOnly)366 continue;367 if (p.name === name && p.value) {368 return p;369 }370 }371 else if (p.name === 'bind' &&372 p.arg &&373 p.arg.type === 4 /* SIMPLE_EXPRESSION */ &&374 p.arg.isStatic &&375 p.arg.content === name &&376 p.exp) {377 return p;378 }379 }380}381function createBlockExpression(blockExp, context) {382 return createSequenceExpression([383 createCallExpression(context.helper(OPEN_BLOCK)),384 blockExp385 ]);386}387function isVSlot(p) {388 return p.type === 7 /* DIRECTIVE */ && p.name === 'slot';389}390function isTemplateNode(node) {391 return (node.type === 1 /* ELEMENT */ && node.tagType === 3 /* TEMPLATE */);392}393function isSlotOutlet(node) {394 return node.type === 1 /* ELEMENT */ && node.tagType === 2 /* SLOT */;395}396function injectProp(node, prop, context) {397 let propsWithInjection;398 const props = node.callee === RENDER_SLOT ? node.arguments[2] : node.arguments[1];399 if (props == null || isString(props)) {400 propsWithInjection = createObjectExpression([prop]);401 }402 else if (props.type === 13 /* JS_CALL_EXPRESSION */) {403 // merged props... add ours404 // only inject key to object literal if it's the first argument so that405 // if doesn't override user provided keys406 const first = props.arguments[0];407 if (!isString(first) && first.type === 14 /* JS_OBJECT_EXPRESSION */) {408 first.properties.unshift(prop);409 }410 else {411 props.arguments.unshift(createObjectExpression([prop]));412 }413 propsWithInjection = props;414 }415 else if (props.type === 14 /* JS_OBJECT_EXPRESSION */) {416 props.properties.unshift(prop);417 propsWithInjection = props;418 }419 else {420 // single v-bind with expression, return a merged replacement421 propsWithInjection = createCallExpression(context.helper(MERGE_PROPS), [422 createObjectExpression([prop]),423 props424 ]);425 }426 if (node.callee === RENDER_SLOT) {427 node.arguments[2] = propsWithInjection;428 }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}...

Full Screen

Full Screen

compiler-core.cjs.prod.js

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

copy

Full Screen

...215 alternate,216 loc: locStub217 };218}219function createCacheExpression(index, value, isVNode = false) {220 return {221 type: 20 /* JS_CACHE_EXPRESSION */,222 index,223 value,224 isVNode,225 loc: locStub226 };227}228const FRAGMENT = Symbol( ``);229const PORTAL = Symbol( ``);230const SUSPENSE = Symbol( ``);231const OPEN_BLOCK = Symbol( ``);232const CREATE_BLOCK = Symbol( ``);233const CREATE_VNODE = Symbol( ``);234const CREATE_COMMENT = Symbol( ``);235const CREATE_TEXT = Symbol( ``);236const RESOLVE_COMPONENT = Symbol( ``);237const RESOLVE_DYNAMIC_COMPONENT = Symbol( ``);238const RESOLVE_DIRECTIVE = Symbol( ``);239const WITH_DIRECTIVES = Symbol( ``);240const RENDER_LIST = Symbol( ``);241const RENDER_SLOT = Symbol( ``);242const CREATE_SLOTS = Symbol( ``);243const TO_STRING = Symbol( ``);244const MERGE_PROPS = Symbol( ``);245const TO_HANDLERS = Symbol( ``);246const CAMELIZE = Symbol( ``);247const SET_BLOCK_TRACKING = Symbol( ``);248// Name mapping for runtime helpers that need to be imported from 'vue' in249// generated code. Make sure these are correctly exported in the runtime!250// Using `any` here because TS doesn't allow symbols as index type.251const helperNameMap = {252 [FRAGMENT]: `Fragment`,253 [PORTAL]: `Portal`,254 [SUSPENSE]: `Suspense`,255 [OPEN_BLOCK]: `openBlock`,256 [CREATE_BLOCK]: `createBlock`,257 [CREATE_VNODE]: `createVNode`,258 [CREATE_COMMENT]: `createCommentVNode`,259 [CREATE_TEXT]: `createTextVNode`,260 [RESOLVE_COMPONENT]: `resolveComponent`,261 [RESOLVE_DYNAMIC_COMPONENT]: `resolveDynamicComponent`,262 [RESOLVE_DIRECTIVE]: `resolveDirective`,263 [WITH_DIRECTIVES]: `withDirectives`,264 [RENDER_LIST]: `renderList`,265 [RENDER_SLOT]: `renderSlot`,266 [CREATE_SLOTS]: `createSlots`,267 [TO_STRING]: `toString`,268 [MERGE_PROPS]: `mergeProps`,269 [TO_HANDLERS]: `toHandlers`,270 [CAMELIZE]: `camelize`,271 [SET_BLOCK_TRACKING]: `setBlockTracking`272};273function registerRuntimeHelpers(helpers) {274 Object.getOwnPropertySymbols(helpers).forEach(s => {275 helperNameMap[s] = helpers[s];276 });277}278// cache node requires279// lazy require dependencies so that they don't end up in rollup's dep graph280// and thus can be tree-shaken in browser builds.281let _parse;282let _walk;283function loadDep(name) {284 if (typeof process !== 'undefined' && isFunction(require)) {285 return require(name);286 }287 else {288 // This is only used when we are building a dev-only build of the compiler289 // which runs in the browser but also uses Node deps.290 return window._deps[name];291 }292}293const parseJS = (code, options) => {294 assert(!false, `Expression AST analysis can only be performed in non-browser builds.`);295 const parse = _parse || (_parse = loadDep('acorn').parse);296 return parse(code, options);297};298const walkJS = (ast, walker) => {299 assert(!false, `Expression AST analysis can only be performed in non-browser builds.`);300 const walk = _walk || (_walk = loadDep('estree-walker').walk);301 return walk(ast, walker);302};303const nonIdentifierRE = /^\d|[^\$\w]/;304const isSimpleIdentifier = (name) => !nonIdentifierRE.test(name);305const memberExpRE = /^[A-Za-z_$][\w$]*(?:\.[A-Za-z_$][\w$]*|\[[^\]]+\])*$/;306const isMemberExpression = (path) => memberExpRE.test(path);307function getInnerRange(loc, offset, length) {308 const source = loc.source.substr(offset, length);309 const newLoc = {310 source,311 start: advancePositionWithClone(loc.start, loc.source, offset),312 end: loc.end313 };314 if (length != null) {315 newLoc.end = advancePositionWithClone(loc.start, loc.source, offset + length);316 }317 return newLoc;318}319function advancePositionWithClone(pos, source, numberOfCharacters = source.length) {320 return advancePositionWithMutation({ ...pos }, source, numberOfCharacters);321}322// advance by mutation without cloning (for performance reasons), since this323// gets called a lot in the parser324function advancePositionWithMutation(pos, source, numberOfCharacters = source.length) {325 let linesCount = 0;326 let lastNewLinePos = -1;327 for (let i = 0; i < numberOfCharacters; i++) {328 if (source.charCodeAt(i) === 10 /* newline char code */) {329 linesCount++;330 lastNewLinePos = i;331 }332 }333 pos.offset += numberOfCharacters;334 pos.line += linesCount;335 pos.column =336 lastNewLinePos === -1337 ? pos.column + numberOfCharacters338 : Math.max(1, numberOfCharacters - lastNewLinePos);339 return pos;340}341function assert(condition, msg) {342 /* istanbul ignore if */343 if (!condition) {344 throw new Error(msg || `unexpected compiler condition`);345 }346}347function findDir(node, name, allowEmpty = false) {348 for (let i = 0; i < node.props.length; i++) {349 const p = node.props[i];350 if (p.type === 7 /* DIRECTIVE */ &&351 (allowEmpty || p.exp) &&352 (isString(name) ? p.name === name : name.test(p.name))) {353 return p;354 }355 }356}357function findProp(node, name, dynamicOnly = false) {358 for (let i = 0; i < node.props.length; i++) {359 const p = node.props[i];360 if (p.type === 6 /* ATTRIBUTE */) {361 if (dynamicOnly)362 continue;363 if (p.name === name && p.value) {364 return p;365 }366 }367 else if (p.name === 'bind' &&368 p.arg &&369 p.arg.type === 4 /* SIMPLE_EXPRESSION */ &&370 p.arg.isStatic &&371 p.arg.content === name &&372 p.exp) {373 return p;374 }375 }376}377function createBlockExpression(blockExp, context) {378 return createSequenceExpression([379 createCallExpression(context.helper(OPEN_BLOCK)),380 blockExp381 ]);382}383function isVSlot(p) {384 return p.type === 7 /* DIRECTIVE */ && p.name === 'slot';385}386function isTemplateNode(node) {387 return (node.type === 1 /* ELEMENT */ && node.tagType === 3 /* TEMPLATE */);388}389function isSlotOutlet(node) {390 return node.type === 1 /* ELEMENT */ && node.tagType === 2 /* SLOT */;391}392function injectProp(node, prop, context) {393 let propsWithInjection;394 const props = node.callee === RENDER_SLOT ? node.arguments[2] : node.arguments[1];395 if (props == null || isString(props)) {396 propsWithInjection = createObjectExpression([prop]);397 }398 else if (props.type === 13 /* JS_CALL_EXPRESSION */) {399 // merged props... add ours400 // only inject key to object literal if it's the first argument so that401 // if doesn't override user provided keys402 const first = props.arguments[0];403 if (!isString(first) && first.type === 14 /* JS_OBJECT_EXPRESSION */) {404 first.properties.unshift(prop);405 }406 else {407 props.arguments.unshift(createObjectExpression([prop]));408 }409 propsWithInjection = props;410 }411 else if (props.type === 14 /* JS_OBJECT_EXPRESSION */) {412 props.properties.unshift(prop);413 propsWithInjection = props;414 }415 else {416 // single v-bind with expression, return a merged replacement417 propsWithInjection = createCallExpression(context.helper(MERGE_PROPS), [418 createObjectExpression([prop]),419 props420 ]);421 }422 if (node.callee === RENDER_SLOT) {423 node.arguments[2] = propsWithInjection;424 }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}...

Full Screen

Full Screen

codegen.js

Source:codegen.js Github

copy

Full Screen

...103 alternate,104 loc: locStub105 };106}107function createCacheExpression(index, value, isVNode = false) {108 return {109 type: 20 /* JS_CACHE_EXPRESSION */,110 index,111 value,112 isVNode,113 loc: locStub114 };115}116function createElementWithCodegen(args) {117 return {118 type: 1,119 loc: locStub,120 ns: 0,121 tag: 'div',122 tagType: 0,123 isSelfClosing: false,124 props: [],125 children: [],126 codegenNode: {127 type: 13,128 loc: locStub,129 callee: CREATE_VNODE,130 arguments: args131 }132 }133}134/**135 * @function createRoot 136 * 通过上面可以发现,这个方法就是返回一个根节点。把参数合并进去137 */138const root = createRoot({139 helpers: [CREATE_VNODE, RESOLVE_DIRECTIVE]140})141const rootResult = { 142 type: 0,143 children: [],144 helpers: [ CREATE_VNODE, RESOLVE_DIRECTIVE ],145 components: [],146 directives: [],147 hoists: [],148 cached: 0,149 codegenNode: { 150 type: 4,151 loc: [null],152 isConstant: false,153 content: 'null',154 isStatic: false 155 },156 loc: 'USELESS2' 157}158/**159 * @param { Number 001 }160 * @function generate 161 * 方法入参:根节点root、module模式162 * 方法出参:ast、code163 * 方法总结:164 * 1、generate能够import helpers里面对应的模块165 */166const untest001 = generate(root, { mode: 'module' })167const output001 = { 168 ast: { 169 type: 0,170 children: [],171 helpers: [ CREATE_VNODE, RESOLVE_DIRECTIVE ],172 components: [],173 directives: [],174 hoists: [],175 cached: 0,176 codegenNode: { 177 type: 4,178 loc: [null],179 isConstant: false,180 content: 'null',181 isStatic: false 182 },183 loc: 'USELESS2' 184 },185 code: `186 import { createVNode, resolveDirective } from "vue"187 export default function render() {188 const _ctx = this189 return null190 }191 `,192 map: undefined 193}194/**195 * @symbol 196 * 关注点:我们可以看看Vue里面是如何使用symbol的197 */198function anonymous(){199 const result = `import { ${helperNameMap[CREATE_VNODE]}, ${200 helperNameMap[RESOLVE_DIRECTIVE]201 } } from "vue"`202 const CREATE_VNODE = Symbol('createVNode')203 const RESOLVE_DIRECTIVE = Symbol('resolveDirective')204 const helperNameMap = {205 [CREATE_VNODE]: 'createVNode',206 [RESOLVE_DIRECTIVE]: 'resolveDirective',207 }208 // import { createVNode, resolveDirective } from "vue"209}210/**211 * @param { Number 002 }212 * @function generate 213 * 方法入参:根节点root、function模式214 * 方法出参:ast、code215 * 方法总结:216 * 1、generate能够import helpers里面对应的模块217 * 2、并且会加上下划线的预处理218 */219const untest002 = generate(root, { mode: 'function' })220const output002 = { 221 ast: { 222 root223 },224 code: `225 const _Vue = Vue226 return function render() {227 with (this) {228 const { createVNode: _createVNode , resolveDirective: _resolveDirective } = _Vue229 return null230 }231 }`,232 map: undefined 233}234/**235 * @param { Number 003 }236 * @function generate237 * 方法入参:根节点root、function模式、前缀标志符true238 * 方法出参:ast、code239 * 方法总结:240 * 1、不包含const _Vue241 * 2、包含对helpers里面的解构赋值242 */243const untest003 = generate(root, { mode: 'function', prefixIdentifiers: true })244const output003 = { 245 ast: { 246 root247 },248 code: `249 const { createVNode, resolveDirective } = Vue250 return function render() {251 const _ctx = this252 return null253 }254 `,255 map: undefined 256}257/**258 * @param { Number 004 }259 * @function generate260 * 方法入参:根节点root2、function模式261 * 方法出参:ast、code262 * 方法总结:263 * 1、能够根据根节点root2里面的components、directives,在代码中正确的const引出264 */265const root2 = createRoot({266 components: [`Foo`, `bar-baz`, `barbaz`],267 directives: [`my_dir`]268})269const untest004 = generate(root2, { mode: 'function' })270const output004 = { 271 ast: { 272 components: [ 'Foo', 'bar-baz', 'barbaz' ],273 directives: [ 'my_dir' ],274 ...root2275 },276 code: `277 return function render() {278 with (this) {279 const _component_Foo = _resolveComponent("Foo")280 const _component_bar_baz = _resolveComponent("bar-baz")281 const _component_barbaz = _resolveComponent("barbaz")282 const _directive_my_dir = _resolveDirective("my_dir")283 return null284 }285 }286 `,287 map: undefined 288}289/**290 * @param { Number 005 }291 * @function generate292 * 方法入参:hoists:字符串293 * 方法出参:ast、code294 * 方法总结:295 * 1、createSimpleExpression 创建一个声明字符串的表达式296 * 2、createObjectExpression 创建一个对象297 * 3、createObjectProperty 创建一个对象的属性298 */299const root3 = createRoot({300 hoists: [301 createSimpleExpression(`hello`, false, locStub),302 createObjectExpression(303 [304 createObjectProperty(305 createSimpleExpression(`id`, true, locStub),306 createSimpleExpression(`foo`, true, locStub)307 )308 ],309 locStub310 )311 ]312})313const untest005 = generate(root3)314const output005 = { 315 ast: { 316 root317 },318 code:`319 const _hoisted_1 = hello320 const _hoisted_2 = { id: "foo" }321 return function render() {322 with (this) {323 return null324 }325 }326 `,327 map: undefined 328}329/**330 * @param { Number 006 }331 * @function generate prefixIdentifiers332 * 方法入参:空root,前缀表达式false333 * 方法出参:ast、code334 * 方法总结:335 * 1、包含const _ctx = this 336 */337const untest006 = generate(createRoot(), { prefixIdentifiers: true })338const output006 = { 339 ast: { 340 root341 },342 code:`343 return function render() { 344 const _ctx = this 345 return null346 }347 `,348 map: undefined 349}350/**351 * @param { Number 007 }352 * @function generate 353 * 方法入参:codegenNode354 * 方法出参:ast、code355 * 方法总结:356 * 1、针对NodeTypes.TEXT类型,能够返回codegenNode里面的content字段357 */358const untest007 = generate(359 createRoot({360 codegenNode: {361 type: 2,362 content: 'hello',363 loc: locStub364 }365 })366)367var output007 = { 368 ast: { 369 root370 },371 code:`372 return function render() {373 with (this) {374 return "hello" 375 }376 }377 `,378 map: undefined 379}380/**381 * @param { Number 008 }382 * @function generate interpolation383 * 方法入参:codegenNode 创建插值384 * 方法出参:ast、code385 * 方法总结:386 * 1、针对createInterpolation,能够返回参数的toString387 */388const untest008 = generate(389 createRoot({390 codegenNode: createInterpolation(`hello`, locStub)391 })392)393const output008 = {394 ast: {395 },396 code:`397 return function render() {398 with (this) {399 return _toString(hello) 400 }401 }402 `403}404/**405 * @param { Number 009 }406 * @function generate 407 * 方法入参:codegenNode 创建插值408 * 方法出参:ast、code409 * 方法总结:410 * 1、针对NodeTypes.COMMENT,能够返回参数的_createCommentVNode411 */412const untest009 = generate(413 createRoot({414 codegenNode: {415 type: 3,416 content: 'foo',417 loc: {}418 }419 })420)421const output009 = { 422 ast: {423 },424 code: `425 return function render() {426 with (this) {427 return _createCommentVNode("foo")428 }429 }430 `,431 map: undefined 432}433/**434 * @param { Number 010 }435 * @function generate 436 * 方法入参:codegenNode 创建复合表达式437 * 方法出参:ast、code438 * 方法总结:439 * 1、针对createCompoundExpression,能够返回正确的前缀 + toString440 */441const untest010 = generate(442 createRoot({443 codegenNode: createCompoundExpression([444 `_ctx.`,445 createSimpleExpression(`foo`, false, locStub),446 ` + `,447 {448 type: 5,449 loc: locStub,450 content: createSimpleExpression(`bar`, false, locStub)451 }452 ])453 })454)455const output010 = { 456 ast: {457 },458 code: `459 return function render() {460 with (this) {461 return _ctx.foo + _toString(bar)462 }463 }464 `,465 map: undefined 466}467/**468 * @param { Number 011 }469 * @function generate 470 * 方法入参:codegenNode 创建序列表达式471 * 方法出参:ast、code472 * 方法总结:473 * 1、NodeTypes.IF474 */475const untest011 = generate(476 createRoot({477 codegenNode: {478 type: 9,479 loc: locStub,480 branches: [],481 codegenNode: createSequenceExpression([482 createSimpleExpression('foo', false),483 createSimpleExpression('bar', false)484 ])485 }486 })487)488const output011 = { 489 ast: {490 },491 code:492 `return function render() {493 with (this) {494 return (foo, bar)495 }496 }497 `,498 map: undefined 499}500/**501 * @param { Number 012 }502 * @function generate 503 * 方法入参:codegenNode 创建序列表达式504 * 方法出参:ast、code505 * 方法总结:506 * 1、针对NodeTypes.IF507 */508const expression012 = generate(509 createRoot({510 codegenNode: {511 type: 11,512 loc: locStub,513 source: createSimpleExpression('foo', false),514 valueAlias: undefined,515 keyAlias: undefined,516 objectIndexAlias: undefined,517 children: [],518 codegenNode: createSequenceExpression([519 createSimpleExpression('foo', false),520 createSimpleExpression('bar', false)521 ])522 }523 })524)525const result012 = { ast:526 { type: 0,527 children: [],528 helpers: [],529 components: [],530 directives: [],531 hoists: [],532 cached: 0,533 codegenNode:534 { type: 11,535 loc: [Object],536 source: [Object],537 valueAlias: undefined,538 keyAlias: undefined,539 objectIndexAlias: undefined,540 children: [],541 codegenNode: [Object] },542 loc: 'USELESS2' },543 code:544 `545 return function render() {546 with (this) {547 return (foo, bar)548 }549 }550 `,551 map: undefined }552 /**553 * @param { Number 013 }554 * @function generate 555 * 方法入参:556 * 方法出参:557 * 方法总结:558 * 1、559 */560const expression013 = generate(561 createRoot({562 codegenNode: createElementWithCodegen([563 // string564 `"div"`,565 // ObjectExpression566 createObjectExpression(567 [568 createObjectProperty(569 createSimpleExpression(`id`, true, locStub),570 createSimpleExpression(`foo`, true, locStub)571 ),572 createObjectProperty(573 createSimpleExpression(`prop`, false, locStub),574 createSimpleExpression(`bar`, false, locStub)575 ),576 // compound expression as computed key577 createObjectProperty(578 {579 type: 8,580 loc: locStub,581 children: [582 `foo + `,583 createSimpleExpression(`bar`, false, locStub)584 ]585 },586 createSimpleExpression(`bar`, false, locStub)587 )588 ],589 locStub590 ),591 // ChildNode[]592 [593 createElementWithCodegen([594 `"p"`,595 createObjectExpression(596 [597 createObjectProperty(598 // should quote the key!599 createSimpleExpression(`some-key`, true, locStub),600 createSimpleExpression(`foo`, true, locStub)601 )602 ],603 locStub604 )605 ])606 ],607 // flag608 (1 << 4) + ''609 ])610 })611)612const result013 = { ast:613 { type: 0,614 children: [],615 helpers: [],616 components: [],617 directives: [],618 hoists: [],619 cached: 0,620 codegenNode:621 { type: 1,622 loc: [Object],623 ns: 0,624 tag: 'div',625 tagType: 0,626 isSelfClosing: false,627 props: [],628 children: [],629 codegenNode: [Object] },630 loc: 'USELESS2' },631 code:632 `633 return function render() {634 with (this) {635 return _createVNode("div", {636 id: "foo",637 [prop]: bar,638 [foo + bar]: bar639 }, [640 _createVNode("p", { "some-key": "foo" })641 ], 16)642 }643 }644 `,645 map: undefined }646/**647 * @param { Number 014 }648 * @function generate 649 * 方法入参:650 * 方法出参:651 * 方法总结:652 * 1、653 */654const expression014 = generate(655 createRoot({656 codegenNode: createArrayExpression([657 createSimpleExpression(`foo`, false),658 createCallExpression(`bar`, [`baz`])659 ])660 })661)662const result014 = { ast:663 { type: 0,664 children: [],665 helpers: [],666 components: [],667 directives: [],668 hoists: [],669 cached: 0,670 codegenNode: { type: 16, loc: undefined, elements: [Array] },671 loc: 'USELESS2' },672 code:673 `674 return function render() {675 with (this) {676 return [677 foo,678 bar(baz)679 ]680 }681 }682 `,683 map: undefined }684/**685 * @param { Number 015 }686 * @function generate 687 * 方法入参:688 * 方法出参:689 * 方法总结:690 * 1、691 */692const expression015 = generate(693 createRoot({694 codegenNode: createSequenceExpression([695 createSimpleExpression(`foo`, false),696 createCallExpression(`bar`, [`baz`])697 ])698 })699)700const result015 = { ast:701 { type: 0,702 children: [],703 helpers: [],704 components: [],705 directives: [],706 hoists: [],707 cached: 0,708 codegenNode: { type: 18, expressions: [Array], loc: [Object] },709 loc: 'USELESS2' },710 code:711 `712 return function render() {713 with (this) {714 return (foo, bar(baz))715 }716 }717 `,718 map: undefined }719/**720 * @param { Number 016 }721 * @function generate 722 * 方法入参:723 * 方法出参:724 * 方法总结:725 * 1、726 */727const expression016 = generate(728 createRoot({729 codegenNode: createConditionalExpression(730 createSimpleExpression(`ok`, false),731 createCallExpression(`foo`),732 createConditionalExpression(733 createSimpleExpression(`orNot`, false),734 createCallExpression(`bar`),735 createCallExpression(`baz`)736 )737 )738 })739)740const result016 = { ast:741 { type: 0,742 children: [],743 helpers: [],744 components: [],745 directives: [],746 hoists: [],747 cached: 0,748 codegenNode:749 { type: 19,750 test: [Object],751 consequent: [Object],752 alternate: [Object],753 loc: [Object] },754 loc: 'USELESS2' },755 code:756 `757 return function render() {758 with (this) {759 return ok760 ? foo()761 : orNot762 ? bar()763 : baz()764 }765 }766 `,767 map: undefined }768/**769 * @param { Number 017 }770 * @function generate 771 * 方法入参:772 * 方法出参:773 * 方法总结:774 * 1、775 */776const expression017 = generate(777 createRoot({778 cached: 1,779 codegenNode: createCacheExpression(780 1,781 createSimpleExpression(`foo`, false)782 )783 }),784 {785 mode: 'module',786 prefixIdentifiers: true787 }788)789const result017 = { ast:790 { type: 0,791 children: [],792 helpers: [],793 components: [],794 directives: [],795 hoists: [],796 cached: 1,797 codegenNode:798 { type: 20,799 index: 1,800 value: [Object],801 isVNode: false,802 loc: [Object] },803 loc: 'USELESS2' },804 code:805 `806 export default function render() {807 const _ctx = this808 const _cache = _ctx.$cache809 return _cache[1] || (_cache[1] = foo)810 }811 `,812 map: undefined }813/**814 * @param { Number 018 }815 * @function generate 816 * 方法入参:817 * 方法出参:818 * 方法总结:819 * 1、820 */821const expression018 = generate(822 createRoot({823 cached: 1,824 codegenNode: createCacheExpression(825 1,826 createSimpleExpression(`foo`, false),827 true828 )829 }),830 {831 mode: 'module',832 prefixIdentifiers: true833 }834)835const result018 = { ast:836 { type: 0,837 children: [],838 helpers: [],...

Full Screen

Full Screen

~codegen.js

Source:~codegen.js Github

copy

Full Screen

...114 alternate,115 loc: locStub116 };117}118function createCacheExpression(index, value, isVNode = false) {119 return {120 type: 20 /* JS_CACHE_EXPRESSION */,121 index,122 value,123 isVNode,124 loc: locStub125 };126}127function createElementWithCodegen(args) {128 return {129 type: 1,130 loc: locStub,131 ns: 0,132 tag: 'div',133 tagType: 0,134 isSelfClosing: false,135 props: [],136 children: [],137 codegenNode: {138 type: 13,139 loc: locStub,140 callee: CREATE_VNODE,141 arguments: args142 }143 }144}145/**146 * @function createRoot 147 * 通过上面可以发现,这个方法就是返回一个根节点。把参数合并进去148 */149const root = createRoot({150 helpers: [CREATE_VNODE, RESOLVE_DIRECTIVE]151})152const rootResult = { 153 type: 0,154 helpers: [ CREATE_VNODE, RESOLVE_DIRECTIVE ],155 codegenNode: { 156 type: 4,157 loc: [null],158 isConstant: false,159 content: 'null',160 isStatic: false 161 },162 loc: 'USELESS2' 163}164/**165 * @param { Number 001 }166 * @function generate 167 * 方法入参:根节点root、module模式168 * 方法出参:ast、code169 * 方法总结:170 * 1、generate能够import helpers里面对应的模块171 */172const untest001 = generate(root, { mode: 'module' })173const output001 = { 174 ast: { 175 type: 0,176 children: [],177 helpers: [ CREATE_VNODE, RESOLVE_DIRECTIVE ],178 components: [],179 directives: [],180 hoists: [],181 cached: 0,182 codegenNode: { 183 type: 4,184 loc: [null],185 isConstant: false,186 content: 'null',187 isStatic: false 188 },189 loc: 'USELESS2' 190 },191 code: `192 import { createVNode, resolveDirective } from "vue"193 export default function render() {194 const _ctx = this195 return null196 }197 `,198 map: undefined 199}200/**201 * @symbol 202 * 关注点:我们可以看看Vue里面是如何使用symbol的203 */204function anonymous(){205 const result = `import { ${helperNameMap[CREATE_VNODE]}, ${206 helperNameMap[RESOLVE_DIRECTIVE]207 } } from "vue"`208 const CREATE_VNODE = Symbol('createVNode')209 const RESOLVE_DIRECTIVE = Symbol('resolveDirective')210 const helperNameMap = {211 [CREATE_VNODE]: 'createVNode',212 [RESOLVE_DIRECTIVE]: 'resolveDirective',213 }214 // import { createVNode, resolveDirective } from "vue"215}216/**217 * @param { Number 002 }218 * @function generate 219 * 方法入参:根节点root、function模式220 * 方法出参:ast、code221 * 方法总结:222 * 1、generate能够import helpers里面对应的模块223 * 2、并且会加上下划线的预处理224 */225const untest002 = generate(root, { mode: 'function' })226const output002 = { 227 ast: { 228 root229 },230 code: `231 const _Vue = Vue232 return function render() {233 with (this) {234 const { createVNode: _createVNode , resolveDirective: _resolveDirective } = _Vue235 return null236 }237 }`,238 map: undefined 239}240/**241 * @param { Number 003 }242 * @function generate243 * 方法入参:根节点root、function模式、前缀标志符true244 * 方法出参:ast、code245 * 方法总结:246 * 1、不包含const _Vue247 * 2、包含对helpers里面的解构赋值248 */249const untest003 = generate(root, { mode: 'function', prefixIdentifiers: true })250const output003 = { 251 ast: { 252 root253 },254 code: `255 const { createVNode, resolveDirective } = Vue256 return function render() {257 const _ctx = this258 return null259 }260 `,261 map: undefined 262}263/**264 * @param { Number 004 }265 * @function generate266 * 方法入参:根节点root2、function模式267 * 方法出参:ast、code268 * 方法总结:269 * 1、能够根据根节点root2里面的components、directives,在代码中正确的const引出270 */271const root2 = createRoot({272 components: [`Foo`, `bar-baz`, `barbaz`],273 directives: [`my_dir`]274})275const untest004 = generate(root2, { mode: 'function' })276const output004 = { 277 ast: { 278 components: [ 'Foo', 'bar-baz', 'barbaz' ],279 directives: [ 'my_dir' ],280 ...root2281 },282 code: `283 return function render() {284 with (this) {285 const _component_Foo = _resolveComponent("Foo")286 const _component_bar_baz = _resolveComponent("bar-baz")287 const _component_barbaz = _resolveComponent("barbaz")288 const _directive_my_dir = _resolveDirective("my_dir")289 return null290 }291 }292 `,293 map: undefined 294}295/**296 * @param { Number 005 }297 * @function generate298 * 方法入参:hoists:字符串299 * 方法出参:ast、code300 * 方法总结:301 * 1、createSimpleExpression 创建一个声明字符串的表达式302 * 2、createObjectExpression 创建一个对象303 * 3、createObjectProperty 创建一个对象的属性304 */305const root3 = createRoot({306 hoists: [307 createSimpleExpression(`hello`, false, locStub),308 createObjectExpression(309 [310 createObjectProperty(311 createSimpleExpression(`id`, true, locStub),312 createSimpleExpression(`foo`, true, locStub)313 )314 ],315 locStub316 )317 ]318})319const untest005 = generate(root3)320const output005 = { 321 ast: { 322 root323 },324 code:`325 const _hoisted_1 = hello326 const _hoisted_2 = { id: "foo" }327 return function render() {328 with (this) {329 return null330 }331 }332 `,333 map: undefined 334}335/**336 * @param { Number 006 }337 * @function generate prefixIdentifiers338 * 方法入参:空root,前缀表达式false339 * 方法出参:ast、code340 * 方法总结:341 * 1、包含const _ctx = this 342 */343const untest006 = generate(createRoot(), { prefixIdentifiers: true })344const output006 = { 345 ast: { 346 root347 },348 code:`349 return function render() { 350 const _ctx = this 351 return null352 }353 `,354 map: undefined 355}356/**357 * @param { Number 007 }358 * @function generate 359 * 方法入参:codegenNode360 * 方法出参:ast、code361 * 方法总结:362 * 1、针对NodeTypes.TEXT类型,能够返回codegenNode里面的content字段363 */364const untest007 = generate(365 createRoot({366 codegenNode: {367 type: 2,368 content: 'hello',369 loc: locStub370 }371 })372)373var output007 = { 374 ast: { 375 root376 },377 code:`378 return function render() {379 with (this) {380 return "hello" 381 }382 }383 `,384 map: undefined 385}386/**387 * @param { Number 008 }388 * @function generate interpolation389 * 方法入参:codegenNode 创建插值390 * 方法出参:ast、code391 * 方法总结:392 * 1、针对createInterpolation,能够返回参数的toString393 */394const untest008 = generate(395 createRoot({396 codegenNode: createInterpolation(`hello`, locStub)397 })398)399const output008 = {400 ast: {401 },402 code:`403 return function render() {404 with (this) {405 return _toString(hello) 406 }407 }408 `409}410/**411 * @param { Number 009 }412 * @function generate 413 * 方法入参:codegenNode 创建插值414 * 方法出参:ast、code415 * 方法总结:416 * 1、针对NodeTypes.COMMENT,能够返回参数的_createCommentVNode417 */418const untest009 = generate(419 createRoot({420 codegenNode: {421 type: 3,422 content: 'foo',423 loc: {}424 }425 })426)427const output009 = { 428 ast: {429 },430 code: `431 return function render() {432 with (this) {433 return _createCommentVNode("foo")434 }435 }436 `,437 map: undefined 438}439/**440 * @param { Number 010 }441 * @function generate 442 * 方法入参:codegenNode 创建复合表达式443 * 方法出参:ast、code444 * 方法总结:445 * 1、针对createCompoundExpression,能够返回正确的前缀 + toString446 */447const untest010 = generate(448 createRoot({449 codegenNode: createCompoundExpression([450 `_ctx.`,451 createSimpleExpression(`foo`, false, locStub),452 ` + `,453 {454 type: 5,455 loc: locStub,456 content: createSimpleExpression(`bar`, false, locStub)457 }458 ])459 })460)461const output010 = { 462 ast: {463 },464 code: `465 return function render() {466 with (this) {467 return _ctx.foo + _toString(bar)468 }469 }470 `,471 map: undefined 472}473/**474 * @param { Number 011 }475 * @function generate 476 * 方法入参:codegenNode 创建序列表达式477 * 方法出参:ast、code478 * 方法总结:479 * 1、针对NodeTypes.IF,能返回序列表达式参数480 */481const untest011 = generate(482 createRoot({483 codegenNode: {484 type: 9,485 loc: locStub,486 branches: [],487 codegenNode: createSequenceExpression([488 createSimpleExpression('foo', false),489 createSimpleExpression('bar', false)490 ])491 }492 })493)494const output011 = { 495 ast: {496 },497 code:498 `return function render() {499 with (this) {500 return (foo, bar)501 }502 }503 `,504 map: undefined 505}506/**507 * @param { Number 012 }508 * @function generate 509 * 方法入参:codegenNode 创建序列表达式510 * 方法出参:ast、code511 * 方法总结:512 * 1、针对NodeTypes.FOR,能返回序列表达式参数513 */514const untest012 = generate(515 createRoot({516 codegenNode: {517 type: 11,518 loc: locStub,519 source: createSimpleExpression('foo', false),520 valueAlias: undefined,521 keyAlias: undefined,522 objectIndexAlias: undefined,523 children: [],524 codegenNode: createSequenceExpression([525 createSimpleExpression('foo', false),526 createSimpleExpression('bar', false)527 ])528 }529 })530)531const output012 = { 532 ast: {533 },534 code:`535 return function render() {536 with (this) {537 return (foo, bar)538 }539 }540 `,541 map: undefined 542}543 /**544 * @param { Number 013 }545 * @function generate 546 * 方法入参:若干方法,创建vnode547 * 方法出参:ast、code548 * 方法总结:549 * 0、createElementWithCodegen 根据Codegen创建对象550 * 1、createSimpleExpression 创建一个声明字符串的表达式551 * 2、createObjectExpression 创建一个对象552 * 3、createObjectProperty 创建一个对象的属性553 */554const untest013 = generate(555 createRoot({556 codegenNode: createElementWithCodegen([557 // string558 `"div"`,559 // ObjectExpression560 createObjectExpression(561 [562 createObjectProperty(563 createSimpleExpression(`id`, true, locStub),564 createSimpleExpression(`foo`, true, locStub)565 ),566 createObjectProperty(567 createSimpleExpression(`prop`, false, locStub),568 createSimpleExpression(`bar`, false, locStub)569 ),570 // compound expression as computed key571 createObjectProperty(572 {573 type: 8,574 loc: locStub,575 children: [576 `foo + `,577 createSimpleExpression(`bar`, false, locStub)578 ]579 },580 createSimpleExpression(`bar`, false, locStub)581 )582 ],583 locStub584 ),585 // ChildNode[]586 [587 createElementWithCodegen([588 `"p"`,589 createObjectExpression(590 [591 createObjectProperty(592 // should quote the key!593 createSimpleExpression(`some-key`, true, locStub),594 createSimpleExpression(`foo`, true, locStub)595 )596 ],597 locStub598 )599 ])600 ],601 // flag602 (1 << 4) + ''603 ])604 })605)606const output013 = { 607 ast: {608 },609 code: `610 return function render() {611 with (this) {612 return _createVNode("div", {613 id: "foo",614 [prop]: bar,615 [foo + bar]: bar616 }, [617 _createVNode("p", { "some-key": "foo" })618 ], 16)619 }620 }621 `,622 map: undefined 623}624/**625 * @param { Number 014 }626 * @function generate 627 * 方法入参:createArrayExpression 创建数组表达式628 * 方法出参:ast、code629 * 方法总结:630 * 1、能返回正确的数组表达式631 */632const untest014 = generate(633 createRoot({634 codegenNode: createArrayExpression([635 createSimpleExpression(`foo`, false),636 createCallExpression(`bar`, [`baz`])637 ])638 })639)640const output014 = { 641 ast:{642 },643 code:`644 return function render() {645 with (this) {646 return [647 foo,648 bar(baz)649 ]650 }651 }652 `,653 map: undefined 654}655/**656 * @param { Number 015 }657 * @function generate 658 * 方法入参:createSequenceExpression 创建序列表达式659 * 方法出参:ast、code660 * 方法总结:661 * 1、能返回正确的序列表达式662 */663const untest015 = generate(664 createRoot({665 codegenNode: createSequenceExpression([666 createSimpleExpression(`foo`, false),667 createCallExpression(`bar`, [`baz`])668 ])669 })670)671const output015 = { 672 ast: { 673 },674 code:675 `676 return function render() {677 with (this) {678 return (foo, bar(baz))679 }680 }681 `,682 map: undefined 683}684/**685 * @param { Number 016 }686 * @function generate 687 * 方法入参:createConditionalExpression 创建条件表达式688 * 方法出参:ast、code689 * 方法总结:690 * 1、能返回正确的条件表达式691 */692const untest016 = generate(693 createRoot({694 codegenNode: createConditionalExpression(695 createSimpleExpression(`ok`, false),696 createCallExpression(`foo`),697 createConditionalExpression(698 createSimpleExpression(`orNot`, false),699 createCallExpression(`bar`),700 createCallExpression(`baz`)701 )702 )703 })704)705const output016 = { 706 ast: {707 708 },709 code:`710 return function render() {711 with (this) {712 return ok713 ? foo()714 : orNot715 ? bar()716 : baz()717 }718 }719 `,720 map: undefined 721}722/**723 * @param { Number 017 }724 * @function generate 725 * 方法入参:createCacheExpression 创建缓存表达式726 * 方法出参:ast、code727 * 方法总结:728 * 1、能返回正确的缓存表达式729 */730const untest017 = generate(731 createRoot({732 cached: 1,733 codegenNode: createCacheExpression(734 1,735 createSimpleExpression(`foo`, false)736 )737 }),738 {739 mode: 'module',740 prefixIdentifiers: true741 }742)743const output017 = { 744 ast: {745 },746 code: `747 export default function render() {748 const _ctx = this749 const _cache = _ctx.$cache750 return _cache[1] || (_cache[1] = foo)751 }752 `,753 map: undefined 754}755/**756 * @param { Number 018 }757 * @function generate 758 * 方法入参:createCacheExpression 创建缓存表达式,多了一个true759 * 方法出参:ast、code760 * 方法总结:761 * 1、能返回正确的缓存表达式762 * 2、多了一个setBlockTracking763 */764const untest018 = generate(765 createRoot({766 cached: 1,767 codegenNode: createCacheExpression(768 1,769 createSimpleExpression(`foo`, false),770 true771 )772 }),773 {774 mode: 'module',775 prefixIdentifiers: true776 }777)778const output018 = { 779 ast: {780 },781 code: `...

Full Screen

Full Screen

codegen.spec.js

Source:codegen.spec.js Github

copy

Full Screen

...218 });219 test('CacheExpression', function () {220 var code = src_1.generate(createRoot({221 cached: 1,222 codegenNode: src_1.createCacheExpression(1, src_1.createSimpleExpression("foo", false))223 }), {224 mode: 'module',225 prefixIdentifiers: true226 }).code;227 expect(code).toMatch("const _cache = _ctx.$cache");228 expect(code).toMatch("_cache[1] || (_cache[1] = foo)");229 expect(code).toMatchSnapshot();230 });231 test('CacheExpression w/ isVNode: true', function () {232 var code = src_1.generate(createRoot({233 cached: 1,234 codegenNode: src_1.createCacheExpression(1, src_1.createSimpleExpression("foo", false), true)235 }), {236 mode: 'module',237 prefixIdentifiers: true238 }).code;239 expect(code).toMatch("const _cache = _ctx.$cache");240 expect(code).toMatch("\n _cache[1] || (\n setBlockTracking(-1),\n _cache[1] = foo,\n setBlockTracking(1),\n _cache[1]\n )\n ".trim());241 expect(code).toMatchSnapshot();242 });...

Full Screen

Full Screen

transform.js

Source:transform.js Github

copy

Full Screen

...118 identifier.hoisted = exp;119 return identifier;120 },121 cache(exp, isVNode = false) {122 return createCacheExpression(++context.cached, exp, isVNode);123 },124 };125 function addId(id) {}126 function removeId(id) {}127 return context;128}129export function traverseNode(node, context) {130 context.currentNode = node;131 const { nodeTransforms } = context;132 const exitFns = [];133 for (let i = 0; i < nodeTransforms.length; i++) {134 // 调用诸如 transformText 的函数135 const onExit = nodeTransforms[i](node, context);136 if (onExit) {...

Full Screen

Full Screen

ast.js

Source:ast.js Github

copy

Full Screen

...104 loc: exports.locStub105 };106}107exports.createConditionalExpression = createConditionalExpression;108function createCacheExpression(index, value, isVNode) {109 if (isVNode === void 0) { isVNode = false; }110 return {111 type: 20,112 index: index,113 value: value,114 isVNode: isVNode,115 loc: exports.locStub116 };117}...

Full Screen

Full Screen

Using AI Code Generation

copy

Full Screen

1import { createCacheExpression } from 'playwright/lib/server/frames';2const cacheExpression = createCacheExpression('test');3console.log(cacheExpression);4import { createCacheExpression } from 'playwright/lib/server/frames';5const cacheExpression = createCacheExpression('test', 'test');6console.log(cacheExpression);7import { createCacheExpression } from 'playwright/lib/server/frames';8const cacheExpression = createCacheExpression('test', 'test', 'test');9console.log(cacheExpression);10import { createCacheExpression } from 'playwright/lib/server/frames';11const cacheExpression = createCacheExpression('test', 'test', 'test', 'test');12console.log(cacheExpression);13import { createCacheExpression } from 'playwright/lib/server/frames';14const cacheExpression = createCacheExpression('test', 'test', 'test', 'test', 'test');15console.log(cacheExpression);16import { createCacheExpression } from 'playwright/lib/server/frames';17const cacheExpression = createCacheExpression('test', 'test', 'test', 'test', 'test', 'test');18console.log(cacheExpression);19import { createCacheExpression } from 'playwright/lib/server/frames';20const cacheExpression = createCacheExpression('test', 'test', 'test', 'test', 'test', 'test', 'test');21console.log(cacheExpression);22import { createCacheExpression } from 'playwright/lib/server/frames';23const cacheExpression = createCacheExpression('test', 'test', 'test', 'test', 'test', 'test', 'test', 'test');24console.log(cacheExpression);25import { createCacheExpression } from 'playwright/lib/server/frames';

Full Screen

Using AI Code Generation

copy

Full Screen

1const { createCacheExpression } = require('playwright/lib/server/frames');2const cacheExpression = createCacheExpression('test');3const result = await page.evaluate(cacheExpression, 'test');4console.log(result);5{6}

Full Screen

Using AI Code Generation

copy

Full Screen

1const { createCacheExpression } = require("playwright/lib/server/browserContext");2const { createHash } = require("crypto");3const { serialize } = require("playwright/lib/server/serializers");4const { createHash } = require("crypto");5const { serialize } = require("playwright/lib/server/serializers");6const { createCacheExpression } = require("playwright/lib/server/browserContext");7const { createHash } = require("crypto");8const { serialize } = require("playwright/lib/server/serializers");9const { createCacheExpression } = require("playwright/lib/server/browserContext");10const { createHash } = require("crypto");11const { serialize } = require("playwright/lib/server/serializers");12const { createCacheExpression } = require("playwright/lib/server/browserContext");13const { createHash } = require("crypto");14const { serialize } = require("playwright/lib/server/serializers");15const { createCacheExpression } = require("playwright/lib/server/browserContext");16const { createHash } = require("crypto");17const { serialize } = require("playwright/lib/server/serializers");18const { createCacheExpression } = require("playwright/lib/server/browserContext");19const { createHash } = require("crypto");20const { serialize } = require("playwright/lib/server/serializers");21const { createCacheExpression } = require("playwright/lib/server/browserContext");22const { createHash } = require("crypto");23const { serialize } = require("playwright/lib/server/serializers");24const { createCacheExpression } = require("playwright/lib/server/browserContext");25const { createHash } = require("crypto");26const { serialize } = require("playwright/lib/server/serializers");27const { createCacheExpression } = require("playwright/lib/server/browserContext");28const { createHash } = require("crypto");29const { serialize } = require("playwright/lib/server/serializers");30const { createCacheExpression } = require("playwright/lib/server/browserContext");31const { createHash } = require("crypto");32const { serialize } = require("playwright/lib/server/serializers");33const { createCacheExpression } = require("playwright/lib/server/browserContext");34const { createHash } = require("crypto");35const { serialize } = require("playwright/lib/server/serializers");36const { createCacheExpression } = require("playwright/lib/server/browserContext");37const { createHash }

Full Screen

Using AI Code Generation

copy

Full Screen

1const { createCacheExpression, createCacheKey } = require('@playwright/test/lib/server/cacheUtils');2const path = require('path');3const fs = require('fs');4const cacheExpression = createCacheExpression(5 path.resolve(__dirname, 'test.js'),6 fs.readFileSync(path.resolve(__dirname, 'test.js')),7 {8 },

Full Screen

Using AI Code Generation

copy

Full Screen

1const { createCacheExpression } = require('playwright/lib/server/cacheStorage');2console.log(cacheExpression);3const { createCacheExpression } = require('playwright/lib/server/cacheStorage');4const cookies = [{name: 'foo', value: 'bar'}];5console.log(cacheExpression);6const { createCacheExpression } = require('playwright/lib/server/cacheStorage');7const headers = { 'foo': 'bar' };8console.log(cacheExpression);9const { createCacheExpression } = require('playwright/lib/server/cacheStorage');10const cookies = [{name: 'foo', value: 'bar'}];11const headers = { 'foo': 'bar' };12console.log(cacheExpression);13const { createCacheExpression } = require('playwright/lib/server/cacheStorage');14const cookies = [{name: 'foo', value: 'bar'}];15const headers = { 'foo': 'bar' };16console.log(cacheExpression);17const { createCacheExpression } = require('playwright/lib/server/cacheStorage');18const cookies = [{name: 'foo', value: 'bar'}];19const headers = { 'foo': 'bar' };

Full Screen

Using AI Code Generation

copy

Full Screen

1const { createCacheExpression } = require('@playwright/test');2const cacheExpression = createCacheExpression('myCacheExpression', 'myCacheKey', (a, b) => a + b);3cacheExpression(2, 3);4cacheExpression(2, 3);5const { createCacheExpression } = require('@playwright/test');6const cacheExpression = createCacheExpression('myCacheExpression', 'myCacheKey', (a, b) => a + b);7cacheExpression(2, 3);8cacheExpression(2, 3);9const { createCacheExpression } = require('@playwright/test');10const cacheExpression = createCacheExpression('myCacheExpression', 'myCacheKey', (a, b) => a + b);11cacheExpression(2, 3);12cacheExpression(2, 3);13const { createCacheExpression } = require('@playwright/test');14const cacheExpression = createCacheExpression('myCacheExpression', 'myCacheKey', (a, b) => a + b);15cacheExpression(2, 3);16cacheExpression(2, 3);17const { createCacheExpression } = require('@playwright/test');18const cacheExpression = createCacheExpression('myCacheExpression', 'myCacheKey', (a, b) => a + b);19cacheExpression(2, 3);20cacheExpression(2, 3);21const { createCacheExpression } = require('@playwright/test');22const cacheExpression = createCacheExpression('myCacheExpression', 'myCacheKey', (a, b) => a + b);23cacheExpression(2, 3);24cacheExpression(2, 3);25const { createCacheExpression } = require('@playwright/test');26const cacheExpression = createCacheExpression('myCacheExpression', 'myCacheKey', (a, b) => a + b);27cacheExpression(2, 3);28cacheExpression(2, 3);29const { createCacheExpression } =

Full Screen

Using AI Code Generation

copy

Full Screen

1const { createCacheExpression } = require('playwright/lib/internal/recorder/frames');2const elementHandle = await page.$('css=div');3const cacheExpression = await createCacheExpression(elementHandle);4const element = await page.evaluateHandle(cacheExpression);5const { createCacheExpression } = require('playwright/lib/internal/recorder/frames');6const elementHandle = await page.$('css=div');7const cacheExpression = await createCacheExpression(elementHandle);8const element = await page.evaluateHandle(cacheExpression);9const { createCacheExpression } = require('playwright/lib/internal/recorder/frames');10const elementHandle = await page.$('css=div');11const cacheExpression = await createCacheExpression(elementHandle);12const element = await page.evaluateHandle(cacheExpression);13const { createCacheExpression } = require('playwright/lib/internal/recorder/frames');14const elementHandle = await page.$('css=div');15const cacheExpression = await createCacheExpression(elementHandle);16const element = await page.evaluateHandle(cacheExpression);17const { createCacheExpression } = require('playwright/lib/internal/recorder/frames');18const elementHandle = await page.$('css=div');19const cacheExpression = await createCacheExpression(elementHandle);20const element = await page.evaluateHandle(cacheExpression);

Full Screen

Using AI Code Generation

copy

Full Screen

1const { chromium } = require('playwright');2const { createCacheExpression } = require('playwright/lib/server/cacheUtils');3(async () => {4 const browser = await chromium.launch();5 const context = await browser.newContext();6 const page = await context.newPage();7 await page.route('**', (route) => {8 route.fulfill({9 headers: {10 },11 });12 });13 await page.close();14 await context.close();15 await browser.close();16})();17const { chromium } = require('playwright');18const { createCacheExpression } = require('playwright/lib/server/cacheUtils');19(async () => {20 const browser = await chromium.launch();21 const context = await browser.newContext();22 const page = await context.newPage();23 await page.route('**', (route) => {24 route.fulfill({25 headers: {26 },27 });28 });29 await page.close();30 await context.close();31 await browser.close();32})();33const { chromium } = require('playwright');34const { createCacheExpression } = require('playwright/lib/server/cacheUtils');35(async () => {36 const browser = await chromium.launch();

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