UNPKG

prettierx

Version:

prettierX - a less opinionated fork of the Prettier code formatter

1,192 lines (1,104 loc) 33.5 kB
"use strict"; /** * @typedef {import("../document").Doc} Doc */ const assert = require("assert"); const { builders: { breakParent, dedentToRoot, fill, group, hardline, ifBreak, indentIfBreak, indent, join, line, literalline, softline, }, utils: { mapDoc, cleanDoc, getDocParts, isConcat, replaceEndOfLineWith }, } = require("../document"); const { isNonEmptyArray } = require("../common/util"); const printFrontMatter = require("../utils/front-matter/print"); const clean = require("./clean"); const { htmlTrimPreserveIndentation, splitByHtmlWhitespace, countChars, countParents, dedentString, forceBreakChildren, forceBreakContent, forceNextEmptyLine, getLastDescendant, getPrettierIgnoreAttributeCommentData, hasPrettierIgnore, inferScriptParser, isVueCustomBlock, isVueNonHtmlBlock, isVueSlotAttribute, isVueSfcBindingsAttribute, isScriptLikeTag, isTextLikeNode, preferHardlineAsLeadingSpaces, shouldNotPrintClosingTag, shouldPreserveContent, unescapeQuoteEntities, isPreLikeNode, // [prettierx] support --html-void-tags option: isHtmlVoidTagNeeded, } = require("./utils"); const preprocess = require("./print-preprocess"); const { insertPragma } = require("./pragma"); const { locStart, locEnd } = require("./loc"); const { printVueFor, printVueBindings, isVueEventBindingExpression, } = require("./syntax-vue"); const { printImgSrcset, printClassNames } = require("./syntax-attribute"); function embed(path, print, textToDoc, options) { const node = path.getValue(); switch (node.type) { case "element": { if (isScriptLikeTag(node) || node.type === "interpolation") { // Fall through to "text" return; } if (!node.isSelfClosing && isVueNonHtmlBlock(node, options)) { const parser = inferScriptParser(node, options); if (!parser) { return; } const content = getNodeContent(node, options); let isEmpty = /^\s*$/.test(content); let doc = ""; if (!isEmpty) { doc = textToDoc( htmlTrimPreserveIndentation(content), { parser, __embeddedInHtml: true }, { stripTrailingHardline: true } ); isEmpty = doc === ""; } return [ printOpeningTagPrefix(node, options), group(printOpeningTag(path, options, print)), isEmpty ? "" : hardline, doc, isEmpty ? "" : hardline, printClosingTag(node, options), printClosingTagSuffix(node, options), ]; } break; } case "text": { if (isScriptLikeTag(node.parent)) { const parser = inferScriptParser(node.parent); if (parser) { const value = parser === "markdown" ? dedentString(node.value.replace(/^[^\S\n]*?\n/, "")) : node.value; const textToDocOptions = { parser, __embeddedInHtml: true }; if (options.parser === "html" && parser === "babel") { let sourceType = "script"; const { attrMap } = node.parent; if ( attrMap && (attrMap.type === "module" || (attrMap.type === "text/babel" && attrMap["data-type"] === "module")) ) { sourceType = "module"; } textToDocOptions.__babelSourceType = sourceType; } return [ breakParent, printOpeningTagPrefix(node, options), textToDoc(value, textToDocOptions, { stripTrailingHardline: true, }), printClosingTagSuffix(node, options), ]; } } else if (node.parent.type === "interpolation") { const textToDocOptions = { __isInHtmlInterpolation: true, // to avoid unexpected `}}` __embeddedInHtml: true, }; if (options.parser === "angular") { textToDocOptions.parser = "__ng_interpolation"; textToDocOptions.trailingComma = "none"; } else if (options.parser === "vue") { textToDocOptions.parser = "__vue_expression"; } else { textToDocOptions.parser = "__js_expression"; } return [ indent([ line, textToDoc(node.value, textToDocOptions, { stripTrailingHardline: true, }), ]), node.parent.next && needsToBorrowPrevClosingTagEndMarker(node.parent.next) ? " " : line, ]; } break; } case "attribute": { if (!node.value) { break; } // lit-html: html`<my-element obj=${obj}></my-element>` if ( /^PRETTIER_HTML_PLACEHOLDER_\d+_\d+_IN_JS$/.test( options.originalText.slice( node.valueSpan.start.offset, node.valueSpan.end.offset ) ) ) { return [node.rawName, "=", node.value]; } // lwc: html`<my-element data-for={value}></my-element>` if (options.parser === "lwc") { const interpolationRegex = /^{.*}$/s; if ( interpolationRegex.test( options.originalText.slice( node.valueSpan.start.offset, node.valueSpan.end.offset ) ) ) { return [node.rawName, "=", node.value]; } } const embeddedAttributeValueDoc = printEmbeddedAttributeValue( node, (code, opts) => // strictly prefer single quote to avoid unnecessary html entity escape textToDoc( code, { __isInHtmlAttribute: true, __embeddedInHtml: true, ...opts }, { stripTrailingHardline: true } ), options ); if (embeddedAttributeValueDoc) { return [ node.rawName, '="', group( mapDoc(embeddedAttributeValueDoc, (doc) => typeof doc === "string" ? doc.replace(/"/g, "&quot;") : doc ) ), '"', ]; } break; } case "front-matter": return printFrontMatter(node, textToDoc); } } function genericPrint(path, options, print) { const node = path.getValue(); switch (node.type) { case "front-matter": return replaceEndOfLineWith(node.raw, literalline); case "root": if (options.__onHtmlRoot) { options.__onHtmlRoot(node); } // use original concat to not break stripTrailingHardline return [group(printChildren(path, options, print)), hardline]; case "element": case "ieConditionalComment": { if (shouldPreserveContent(node, options)) { return [ printOpeningTagPrefix(node, options), group(printOpeningTag(path, options, print)), ...replaceEndOfLineWith(getNodeContent(node, options), literalline), ...printClosingTag(node, options), printClosingTagSuffix(node, options), ]; } /** * do not break: * * <div>{{ * ~ * interpolation * }}</div> * ~ * * exception: break if the opening tag breaks * * <div * long * ~ * >{{ * interpolation * }}</div * ~ * > */ const shouldHugContent = node.children.length === 1 && node.firstChild.type === "interpolation" && node.firstChild.isLeadingSpaceSensitive && !node.firstChild.hasLeadingSpaces && node.lastChild.isTrailingSpaceSensitive && !node.lastChild.hasTrailingSpaces; const attrGroupId = Symbol("element-attr-group-id"); return [ group([ group(printOpeningTag(path, options, print), { id: attrGroupId }), node.children.length === 0 ? node.hasDanglingSpaces && node.isDanglingSpaceSensitive ? line : "" : [ forceBreakContent(node) ? breakParent : "", ((childrenDoc) => shouldHugContent ? indentIfBreak(childrenDoc, { groupId: attrGroupId }) : (isScriptLikeTag(node) || isVueCustomBlock(node, options)) && node.parent.type === "root" && options.parser === "vue" && !options.vueIndentScriptAndStyle ? childrenDoc : indent(childrenDoc))([ shouldHugContent ? ifBreak(softline, "", { groupId: attrGroupId }) : node.firstChild.hasLeadingSpaces && node.firstChild.isLeadingSpaceSensitive ? line : node.firstChild.type === "text" && node.isWhitespaceSensitive && node.isIndentationSensitive ? dedentToRoot(softline) : softline, printChildren(path, options, print), ]), ( node.next ? needsToBorrowPrevClosingTagEndMarker(node.next) : needsToBorrowLastChildClosingTagEndMarker(node.parent) ) ? node.lastChild.hasTrailingSpaces && node.lastChild.isTrailingSpaceSensitive ? " " : "" : shouldHugContent ? ifBreak(softline, "", { groupId: attrGroupId }) : node.lastChild.hasTrailingSpaces && node.lastChild.isTrailingSpaceSensitive ? line : (node.lastChild.type === "comment" || (node.lastChild.type === "text" && node.isWhitespaceSensitive && node.isIndentationSensitive)) && new RegExp( `\\n[\\t ]{${ options.tabWidth * countParents( path, (node) => node.parent && node.parent.type !== "root" ) }}$` ).test(node.lastChild.value) ? /** * <div> * <pre> * something * </pre> * ~ * </div> */ "" : softline, ], ]), printClosingTag(node, options), ]; } case "ieConditionalStartComment": case "ieConditionalEndComment": return [printOpeningTagStart(node), printClosingTagEnd(node)]; case "interpolation": return [ printOpeningTagStart(node, options), ...path.map(print, "children"), printClosingTagEnd(node, options), ]; case "text": { if (node.parent.type === "interpolation") { // replace the trailing literalline with hardline for better readability const trailingNewlineRegex = /\n[^\S\n]*?$/; const hasTrailingNewline = trailingNewlineRegex.test(node.value); const value = hasTrailingNewline ? node.value.replace(trailingNewlineRegex, "") : node.value; return [ ...replaceEndOfLineWith(value, literalline), hasTrailingNewline ? hardline : "", ]; } const printed = cleanDoc([ printOpeningTagPrefix(node, options), ...getTextValueParts(node), printClosingTagSuffix(node, options), ]); if (isConcat(printed) || printed.type === "fill") { return fill(getDocParts(printed)); } /* istanbul ignore next */ return printed; } case "docType": return [ group([ printOpeningTagStart(node, options), " ", node.value.replace(/^html\b/i, "html").replace(/\s+/g, " "), ]), printClosingTagEnd(node, options), ]; case "comment": { return [ printOpeningTagPrefix(node, options), ...replaceEndOfLineWith( options.originalText.slice(locStart(node), locEnd(node)), literalline ), printClosingTagSuffix(node, options), ]; } case "attribute": { if (node.value === null) { return node.rawName; } const value = unescapeQuoteEntities(node.value); const singleQuoteCount = countChars(value, "'"); const doubleQuoteCount = countChars(value, '"'); const quote = singleQuoteCount < doubleQuoteCount ? "'" : '"'; return [ node.rawName, "=", quote, ...replaceEndOfLineWith( quote === '"' ? value.replace(/"/g, "&quot;") : value.replace(/'/g, "&apos;"), literalline ), quote, ]; } default: /* istanbul ignore next */ throw new Error(`Unexpected node type ${node.type}`); } } function printChildren(path, options, print) { const node = path.getValue(); if (forceBreakChildren(node)) { return [ breakParent, ...path.map((childPath) => { const childNode = childPath.getValue(); const prevBetweenLine = !childNode.prev ? "" : printBetweenLine(childNode.prev, childNode); return [ !prevBetweenLine ? "" : [ prevBetweenLine, forceNextEmptyLine(childNode.prev) ? hardline : "", ], printChild(childPath), ]; }, "children"), ]; } const groupIds = node.children.map(() => Symbol("")); return path.map((childPath, childIndex) => { const childNode = childPath.getValue(); if (isTextLikeNode(childNode)) { if (childNode.prev && isTextLikeNode(childNode.prev)) { const prevBetweenLine = printBetweenLine(childNode.prev, childNode); if (prevBetweenLine) { if (forceNextEmptyLine(childNode.prev)) { return [hardline, hardline, printChild(childPath)]; } return [prevBetweenLine, printChild(childPath)]; } } return printChild(childPath); } const prevParts = []; const leadingParts = []; const trailingParts = []; const nextParts = []; const prevBetweenLine = childNode.prev ? printBetweenLine(childNode.prev, childNode) : ""; const nextBetweenLine = childNode.next ? printBetweenLine(childNode, childNode.next) : ""; if (prevBetweenLine) { if (forceNextEmptyLine(childNode.prev)) { prevParts.push(hardline, hardline); } else if (prevBetweenLine === hardline) { prevParts.push(hardline); } else { if (isTextLikeNode(childNode.prev)) { leadingParts.push(prevBetweenLine); } else { leadingParts.push( ifBreak("", softline, { groupId: groupIds[childIndex - 1], }) ); } } } if (nextBetweenLine) { if (forceNextEmptyLine(childNode)) { if (isTextLikeNode(childNode.next)) { nextParts.push(hardline, hardline); } } else if (nextBetweenLine === hardline) { if (isTextLikeNode(childNode.next)) { nextParts.push(hardline); } } else { trailingParts.push(nextBetweenLine); } } return [ ...prevParts, group([ ...leadingParts, group([printChild(childPath), ...trailingParts], { id: groupIds[childIndex], }), ]), ...nextParts, ]; }, "children"); function printChild(childPath) { const child = childPath.getValue(); if (hasPrettierIgnore(child)) { return [ printOpeningTagPrefix(child, options), ...replaceEndOfLineWith( options.originalText.slice( locStart(child) + (child.prev && needsToBorrowNextOpeningTagStartMarker(child.prev) ? printOpeningTagStartMarker(child).length : 0), locEnd(child) - (child.next && needsToBorrowPrevClosingTagEndMarker(child.next) ? printClosingTagEndMarker(child, options).length : 0) ), literalline ), printClosingTagSuffix(child, options), ]; } return print(); } function printBetweenLine(prevNode, nextNode) { return isTextLikeNode(prevNode) && isTextLikeNode(nextNode) ? prevNode.isTrailingSpaceSensitive ? prevNode.hasTrailingSpaces ? preferHardlineAsLeadingSpaces(nextNode) ? hardline : line : "" : preferHardlineAsLeadingSpaces(nextNode) ? hardline : softline : (needsToBorrowNextOpeningTagStartMarker(prevNode) && (hasPrettierIgnore(nextNode) || /** * 123<a * ~ * ><b> */ nextNode.firstChild || /** * 123<!-- * ~ * --> */ nextNode.isSelfClosing || /** * 123<span * ~ * attr */ (nextNode.type === "element" && nextNode.attrs.length > 0))) || /** * <img * src="long" * ~ * />123 */ (prevNode.type === "element" && prevNode.isSelfClosing && needsToBorrowPrevClosingTagEndMarker(nextNode)) ? "" : !nextNode.isLeadingSpaceSensitive || preferHardlineAsLeadingSpaces(nextNode) || /** * Want to write us a letter? Use our<a * ><b><a>mailing address</a></b></a * ~ * >. */ (needsToBorrowPrevClosingTagEndMarker(nextNode) && prevNode.lastChild && needsToBorrowParentClosingTagStartMarker(prevNode.lastChild) && prevNode.lastChild.lastChild && needsToBorrowParentClosingTagStartMarker( prevNode.lastChild.lastChild )) ? hardline : nextNode.hasLeadingSpaces ? line : softline; } } function getNodeContent(node, options) { let start = node.startSourceSpan.end.offset; if ( node.firstChild && needsToBorrowParentOpeningTagEndMarker(node.firstChild) ) { start -= printOpeningTagEndMarker(node).length; } let end = node.endSourceSpan.start.offset; if ( node.lastChild && needsToBorrowParentClosingTagStartMarker(node.lastChild) ) { end += printClosingTagStartMarker(node, options).length; } else if (needsToBorrowLastChildClosingTagEndMarker(node)) { end -= printClosingTagEndMarker(node.lastChild, options).length; } return options.originalText.slice(start, end); } function printAttributes(path, options, print) { const node = path.getValue(); if (!isNonEmptyArray(node.attrs)) { // [prettierx merge update from prettier@2.3.2] --html-void-tags option: return node.isSelfClosing && !isHtmlVoidTagNeeded(node, options) ? /** * <br /> * ^ */ " " : ""; } const ignoreAttributeData = node.prev && node.prev.type === "comment" && getPrettierIgnoreAttributeCommentData(node.prev.value); const hasPrettierIgnoreAttribute = typeof ignoreAttributeData === "boolean" ? () => ignoreAttributeData : Array.isArray(ignoreAttributeData) ? (attribute) => ignoreAttributeData.includes(attribute.rawName) : () => false; const printedAttributes = path.map((attributePath) => { const attribute = attributePath.getValue(); return hasPrettierIgnoreAttribute(attribute) ? replaceEndOfLineWith( options.originalText.slice(locStart(attribute), locEnd(attribute)), literalline ) : print(); }, "attrs"); const forceNotToBreakAttrContent = node.type === "element" && node.fullName === "script" && node.attrs.length === 1 && node.attrs[0].fullName === "src" && node.children.length === 0; /** @type {Doc[]} */ const parts = [ indent([ forceNotToBreakAttrContent ? " " : line, join(line, printedAttributes), ]), ]; if ( /** * 123<a * attr * ~ * >456 */ (node.firstChild && needsToBorrowParentOpeningTagEndMarker(node.firstChild)) || /** * <span * >123<meta * ~ * /></span> */ (node.isSelfClosing && needsToBorrowLastChildClosingTagEndMarker(node.parent)) || forceNotToBreakAttrContent ) { // [prettierx merge update from prettier@2.3.2] --html-void-tags option: parts.push( node.isSelfClosing && !isHtmlVoidTagNeeded(node, options) ? " " : "" ); } else { // [prettierx merge update from prettier@2.3.2] --html-void-tags option: parts.push( node.isSelfClosing && !isHtmlVoidTagNeeded(node, options) ? line : softline ); } return parts; } function printOpeningTag(path, options, print) { const node = path.getValue(); return [ printOpeningTagStart(node, options), printAttributes(path, options, print), node.isSelfClosing ? "" : printOpeningTagEnd(node), ]; } function printOpeningTagStart(node, options) { return node.prev && needsToBorrowNextOpeningTagStartMarker(node.prev) ? "" : [printOpeningTagPrefix(node, options), printOpeningTagStartMarker(node)]; } function printOpeningTagEnd(node) { return node.firstChild && needsToBorrowParentOpeningTagEndMarker(node.firstChild) ? "" : printOpeningTagEndMarker(node); } function printClosingTag(node, options) { return [ node.isSelfClosing ? "" : printClosingTagStart(node, options), printClosingTagEnd(node, options), ]; } function printClosingTagStart(node, options) { return node.lastChild && needsToBorrowParentClosingTagStartMarker(node.lastChild) ? "" : [ printClosingTagPrefix(node, options), printClosingTagStartMarker(node, options), ]; } function printClosingTagEnd(node, options) { return ( node.next ? needsToBorrowPrevClosingTagEndMarker(node.next) : needsToBorrowLastChildClosingTagEndMarker(node.parent) ) ? "" : [ printClosingTagEndMarker(node, options), printClosingTagSuffix(node, options), ]; } function needsToBorrowNextOpeningTagStartMarker(node) { /** * 123<p * ^^ * > */ return ( node.next && !isTextLikeNode(node.next) && isTextLikeNode(node) && node.isTrailingSpaceSensitive && !node.hasTrailingSpaces ); } function needsToBorrowParentOpeningTagEndMarker(node) { /** * <p * >123 * ^ * * <p * ><a * ^ */ return !node.prev && node.isLeadingSpaceSensitive && !node.hasLeadingSpaces; } function needsToBorrowPrevClosingTagEndMarker(node) { /** * <p></p * >123 * ^ * * <p></p * ><a * ^ */ return ( node.prev && node.prev.type !== "docType" && !isTextLikeNode(node.prev) && node.isLeadingSpaceSensitive && !node.hasLeadingSpaces ); } function needsToBorrowLastChildClosingTagEndMarker(node) { /** * <p * ><a></a * ></p * ^ * > */ return ( node.lastChild && node.lastChild.isTrailingSpaceSensitive && !node.lastChild.hasTrailingSpaces && !isTextLikeNode(getLastDescendant(node.lastChild)) && !isPreLikeNode(node) ); } function needsToBorrowParentClosingTagStartMarker(node) { /** * <p> * 123</p * ^^^ * > * * 123</b * ></a * ^^^ * > */ return ( !node.next && !node.hasTrailingSpaces && node.isTrailingSpaceSensitive && isTextLikeNode(getLastDescendant(node)) ); } function printOpeningTagPrefix(node, options) { return needsToBorrowParentOpeningTagEndMarker(node) ? printOpeningTagEndMarker(node.parent) : needsToBorrowPrevClosingTagEndMarker(node) ? printClosingTagEndMarker(node.prev, options) : ""; } function printClosingTagPrefix(node, options) { return needsToBorrowLastChildClosingTagEndMarker(node) ? printClosingTagEndMarker(node.lastChild, options) : ""; } function printClosingTagSuffix(node, options) { return needsToBorrowParentClosingTagStartMarker(node) ? printClosingTagStartMarker(node.parent, options) : needsToBorrowNextOpeningTagStartMarker(node) ? printOpeningTagStartMarker(node.next) : ""; } function printOpeningTagStartMarker(node) { switch (node.type) { case "ieConditionalComment": case "ieConditionalStartComment": return `<!--[if ${node.condition}`; case "ieConditionalEndComment": return "<!--<!"; case "interpolation": return "{{"; case "docType": return "<!DOCTYPE"; case "element": if (node.condition) { return `<!--[if ${node.condition}]><!--><${node.rawName}`; } // fall through default: return `<${node.rawName}`; } } function printOpeningTagEndMarker(node) { assert(!node.isSelfClosing); switch (node.type) { case "ieConditionalComment": return "]>"; case "element": if (node.condition) { return "><!--<![endif]-->"; } // fall through default: return ">"; } } function printClosingTagStartMarker(node, options) { assert(!node.isSelfClosing); /* istanbul ignore next */ if (shouldNotPrintClosingTag(node, options)) { return ""; } switch (node.type) { case "ieConditionalComment": return "<!"; case "element": if (node.hasHtmComponentClosingTag) { return "<//"; } // fall through default: return `</${node.rawName}`; } } function printClosingTagEndMarker(node, options) { if (shouldNotPrintClosingTag(node, options)) { return ""; } switch (node.type) { case "ieConditionalComment": case "ieConditionalEndComment": return "[endif]-->"; case "ieConditionalStartComment": return "]><!-->"; case "interpolation": return "}}"; case "element": if (node.isSelfClosing) { // [prettierx] support --html-void-tags option: return isHtmlVoidTagNeeded(node, options) ? ">" : "/>"; } // fall through default: return ">"; } } function getTextValueParts(node, value = node.value) { return node.parent.isWhitespaceSensitive ? node.parent.isIndentationSensitive ? replaceEndOfLineWith(value, literalline) : replaceEndOfLineWith( dedentString(htmlTrimPreserveIndentation(value)), hardline ) : getDocParts(join(line, splitByHtmlWhitespace(value))); } function printEmbeddedAttributeValue(node, originalTextToDoc, options) { const isKeyMatched = (patterns) => new RegExp(patterns.join("|")).test(node.fullName); const getValue = () => unescapeQuoteEntities(node.value); let shouldHug = false; const __onHtmlBindingRoot = (root, options) => { const rootNode = root.type === "NGRoot" ? root.node.type === "NGMicrosyntax" && root.node.body.length === 1 && root.node.body[0].type === "NGMicrosyntaxExpression" ? root.node.body[0].expression : root.node : root.type === "JsExpressionRoot" ? root.node : root; if ( rootNode && (rootNode.type === "ObjectExpression" || rootNode.type === "ArrayExpression" || (options.parser === "__vue_expression" && (rootNode.type === "TemplateLiteral" || rootNode.type === "StringLiteral"))) ) { shouldHug = true; } }; const printHug = (doc) => group(doc); const printExpand = (doc, canHaveTrailingWhitespace = true) => group([indent([softline, doc]), canHaveTrailingWhitespace ? softline : ""]); const printMaybeHug = (doc) => (shouldHug ? printHug(doc) : printExpand(doc)); const attributeTextToDoc = (code, opts) => originalTextToDoc( code, { __onHtmlBindingRoot, __embeddedInHtml: true, ...opts }, { stripTrailingHardline: true } ); if ( node.fullName === "srcset" && (node.parent.fullName === "img" || node.parent.fullName === "source") ) { return printExpand(printImgSrcset(getValue())); } if (node.fullName === "class" && !options.parentParser) { const value = getValue(); if (!value.includes("{{")) { return printClassNames(value); } } if (node.fullName === "style" && !options.parentParser) { const value = getValue(); if (!value.includes("{{")) { return printExpand( attributeTextToDoc(value, { parser: "css", __isHTMLStyleAttribute: true, }) ); } } if (options.parser === "vue") { if (node.fullName === "v-for") { return printVueFor(getValue(), attributeTextToDoc); } if (isVueSlotAttribute(node) || isVueSfcBindingsAttribute(node, options)) { return printVueBindings(getValue(), attributeTextToDoc); } /** * @click="jsStatement" * @click="jsExpression" * v-on:click="jsStatement" * v-on:click="jsExpression" */ const vueEventBindingPatterns = ["^@", "^v-on:"]; /** * :class="vueExpression" * v-bind:id="vueExpression" */ const vueExpressionBindingPatterns = ["^:", "^v-bind:"]; /** * v-if="jsExpression" */ const jsExpressionBindingPatterns = ["^v-"]; if (isKeyMatched(vueEventBindingPatterns)) { const value = getValue(); return printMaybeHug( attributeTextToDoc(value, { parser: isVueEventBindingExpression(value) ? "__js_expression" : "__vue_event_binding", }) ); } if (isKeyMatched(vueExpressionBindingPatterns)) { return printMaybeHug( attributeTextToDoc(getValue(), { parser: "__vue_expression" }) ); } if (isKeyMatched(jsExpressionBindingPatterns)) { return printMaybeHug( attributeTextToDoc(getValue(), { parser: "__js_expression" }) ); } } if (options.parser === "angular") { const ngTextToDoc = (code, opts) => // angular does not allow trailing comma attributeTextToDoc(code, { ...opts, trailingComma: "none" }); /** * *directive="angularDirective" */ const ngDirectiveBindingPatterns = ["^\\*"]; /** * (click)="angularStatement" * on-click="angularStatement" */ const ngStatementBindingPatterns = ["^\\(.+\\)$", "^on-"]; /** * [target]="angularExpression" * bind-target="angularExpression" * [(target)]="angularExpression" * bindon-target="angularExpression" */ const ngExpressionBindingPatterns = [ "^\\[.+\\]$", "^bind(on)?-", // Unofficial rudimentary support for some of the most used directives of AngularJS 1.x "^ng-(if|show|hide|class|style)$", ]; /** * i18n="longDescription" * i18n-attr="longDescription" */ const ngI18nPatterns = ["^i18n(-.+)?$"]; if (isKeyMatched(ngStatementBindingPatterns)) { return printMaybeHug(ngTextToDoc(getValue(), { parser: "__ng_action" })); } if (isKeyMatched(ngExpressionBindingPatterns)) { return printMaybeHug(ngTextToDoc(getValue(), { parser: "__ng_binding" })); } if (isKeyMatched(ngI18nPatterns)) { const value = getValue().trim(); return printExpand( fill(getTextValueParts(node, value)), !value.includes("@@") ); } if (isKeyMatched(ngDirectiveBindingPatterns)) { return printMaybeHug( ngTextToDoc(getValue(), { parser: "__ng_directive" }) ); } const interpolationRegex = /{{(.+?)}}/gs; const value = getValue(); if (interpolationRegex.test(value)) { const parts = []; for (const [index, part] of value.split(interpolationRegex).entries()) { if (index % 2 === 0) { parts.push(replaceEndOfLineWith(part, literalline)); } else { try { parts.push( group([ "{{", indent([ line, ngTextToDoc(part, { parser: "__ng_interpolation", __isInHtmlInterpolation: true, // to avoid unexpected `}}` }), ]), line, "}}", ]) ); } catch { parts.push("{{", replaceEndOfLineWith(part, literalline), "}}"); } } } return group(parts); } } return null; } module.exports = { preprocess, print: genericPrint, insertPragma, massageAstNode: clean, embed, };