UNPKG

prettier-plugin-marko

Version:

A prettier plugin for parsing and printing Marko files

1,491 lines (1,478 loc) 51.9 kB
"use strict"; var __create = Object.create; var __defProp = Object.defineProperty; var __getOwnPropDesc = Object.getOwnPropertyDescriptor; var __getOwnPropNames = Object.getOwnPropertyNames; var __getProtoOf = Object.getPrototypeOf; var __hasOwnProp = Object.prototype.hasOwnProperty; var __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; var __copyProps = (to, from, except, desc) => { if (from && typeof from === "object" || typeof from === "function") { for (let key of __getOwnPropNames(from)) if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); } return to; }; var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps( // If the importer is in node compatibility mode or this is not an ESM // file that has been converted to a CommonJS file using a Babel- // compatible transform (i.e. "__esModule" has not been set), then set // "default" to the CommonJS "module.exports" for node compatibility. isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var index_exports = {}; __export(index_exports, { languages: () => languages, options: () => options, parsers: () => parsers, printers: () => printers, setCompiler: () => setCompiler }); module.exports = __toCommonJS(index_exports); var import_path = require("path"); var import_module = require("module"); var import_prettier5 = require("prettier"); // src/constants.ts var scriptParser = "babel-ts"; var expressionParser = "__ts_expression"; var enclosedNodeTypeReg = /^(?:Identifier|.*Literal|(?:Object|Array|Parenthesized|Record|Tuple)Expression)$/; var styleReg = /^style((?:\.[^\s\\/:*?"<>|({]+)+)?\s*\{?/; var voidHTMLReg = /^(?:area|b(?:ase|r)|col|embed|hr|i(?:mg|nput)|keygen|link|meta|param|source|track|wbr|const|debug|id|let|lifecycle|log|return)$/; var shorthandIdOrClassReg = /^[a-zA-Z0-9_$][a-zA-Z0-9_$-]*(?:\s+[a-zA-Z0-9_$][a-zA-Z0-9_$-]*)*$/; var preserveSpaceTagsReg = /^(?:textarea|pre|html-(?:comment|script|style))$/; // src/utils/loc-to-pos.ts function locToPos(loc, opts) { const { markoLinePositions } = opts; return markoLinePositions[loc.line - 1] + loc.column + (loc.line === 1 ? 0 : 1); } // src/utils/is-text-like.ts function isTextLike(node, parent, opts) { if (isText(node)) { return true; } else if (isInlineComment(node, opts)) { const body = parent.type === "Program" ? parent.body : parent.body.body; const i = body.indexOf(node); let j = i; while (j > 0) { const check = body[--j]; if (isText(check)) return true; else if (!isInlineComment(check, opts)) break; } j = i; while (j < body.length - 1) { const check = body[++j]; if (isText(check)) return true; else if (!isInlineComment(check, opts)) break; } } return false; } function getCommentType(node, opts) { var _a; const start = (_a = node.loc) == null ? void 0 : _a.start; switch (start != null && opts.originalText[locToPos(start, opts) + 1]) { case "/": return "/"; case "*": return "*"; default: return "-"; } } function isInlineComment(node, opts) { return node.type === "MarkoComment" && getCommentType(node, opts) !== "/"; } function isText(node) { return node.type === "MarkoText" || node.type === "MarkoPlaceholder"; } // src/utils/with-line-if-needed.ts var import_prettier = require("prettier"); var { builders: b } = import_prettier.doc; function withLineIfNeeded(node, opts, doc4) { const { originalText } = opts; let pos = node.loc ? locToPos(node.loc.start, opts) : 0; let count = 0; while (--pos >= 0) { let char = originalText[pos]; if (char === "\n") { if (++count === 2) { while (--pos >= 0) { char = originalText[pos]; if (char !== "\n" && char !== " " && char !== "\r" && char !== " ") { return [b.hardline, doc4]; } } return doc4; } } else if (char !== " " && char !== "\r" && char !== " ") { break; } } return doc4; } // src/utils/with-block-if-needed.ts var import_prettier2 = require("prettier"); // src/utils/outer-code-matches.ts var enclosedPatterns = []; enclosedPatterns.push( { // Ignored match: /[a-z0-9_$#@.]+/iy }, { // Line comments match: /\/\/.*$/y }, { // Multi line comments match: /\/\*.*?\*\//y }, { // Parens match: /\s*\(/y, patterns: enclosedPatterns, until: /\)/y }, { // Braces match: /\s*{/y, patterns: enclosedPatterns, until: /}/y }, { // Brackets match: /\s*\[/y, patterns: enclosedPatterns, until: /]/y }, { // Single quote string match: /'(?:\\.|[^'\\])*'/y }, { // Double quote string match: /"(?:\\.|[^"\\])*"/y }, { // Template literal match: /`/y, patterns: [ { // Content match: /\\.|\$(?!{)|[^`\\$]+/y }, { // Expressions match: /\${/y, patterns: enclosedPatterns, until: /}/y } ], until: /`/y }, { // RegExp match: /\/(?:\\.|\[(?:\\.|[^\]\\]+)\]|[^[/\\])+\/[a-z]*/iy } ); var unenclosedPatterns = [ { // Word operators match: /\b\s*(?:as|async|await|class|function|in(?:stanceof)?|new|void|delete|keyof|typeof|satisfies|extends)(?:\s+|\b)/y }, { // Symbol operators match: /\s*(?:[\^~%!]|\+{1,2}|\*{1,2}|-(?:-(?!\s))?|&{1,2}|\|{1,2}|!={0,2}|===?|<{1,3}|>{2,3}|<=?|=>)\s*/y } ].concat(enclosedPatterns); function outerCodeMatches(str, test, enclosed) { const stack = [ { until: test, patterns: enclosed ? enclosedPatterns : unenclosedPatterns } ]; let pos = 0; do { const { until, patterns } = stack[stack.length - 1]; outer: while (pos < str.length) { for (const pattern of patterns) { pattern.match.lastIndex = pos; if (pattern.match.test(str)) { pos = pattern.match.lastIndex; if (pattern.until) { stack.push(pattern); break outer; } else { continue outer; } } } until.lastIndex = pos; if (until.test(str)) { pos = until.lastIndex; if (stack.length === 1) return true; stack.pop(); break; } pos++; } } while (pos < str.length && stack.length); return false; } // src/utils/print-doc.ts var DocCache = /* @__PURE__ */ new WeakMap(); function printDoc(doc4) { switch (typeof doc4) { case "string": return doc4; case "object": if (doc4 !== null) { let cached = DocCache.get(doc4); if (cached !== void 0) return cached; if (Array.isArray(doc4)) { cached = ""; for (const item of doc4) { cached += printDoc(item); } } else { switch (doc4.type) { case "align": cached = ` ${printDoc(doc4.contents)} `; break; case "indent": cached = ` ${printDoc(doc4.contents)} `; break; case "break-parent": case "cursor": case "line-suffix-boundary": case "trim": cached = ""; break; case "fill": cached = ` ${printDoc(doc4.parts)} `; break; case "group": cached = printDoc(doc4.contents) + printDoc(doc4.expandedStates); break; case "if-break": cached = printDoc(doc4.flatContents) + printDoc(doc4.breakContents); break; case "indent-if-break": cached = " "; break; case "label": case "line-suffix": cached = printDoc(doc4.contents); break; case "line": default: cached = "\n"; break; } } DocCache.set(doc4, cached); return cached; } } return ""; } // src/utils/with-block-if-needed.ts var { builders: b2 } = import_prettier2.doc; function withBlockIfNeeded(node, doc4) { if (!enclosedNodeTypeReg.test(node.type) && outerCodeMatches(printDoc(doc4).trim(), /[\n\r]/y) || node.leadingComments || node.trailingComments) { return b2.group([ b2.indent([b2.ifBreak(["{", b2.line]), doc4]), b2.ifBreak([b2.line, "}"]) ]); } return doc4; } // src/utils/with-parens-if-needed.ts var import_prettier3 = require("prettier"); var { builders: b3 } = import_prettier3.doc; function withParensIfNeeded(node, doc4, enclosed) { var _a, _b; if (((_a = node.leadingComments) == null ? void 0 : _a.length) || ((_b = node.trailingComments) == null ? void 0 : _b.length) || !enclosedNodeTypeReg.test(node.type) && outerCodeMatches(printDoc(doc4).trim(), /\s|>/y, enclosed)) { return b3.group(["(", b3.indent([b3.softline, doc4]), b3.softline, ")"]); } if (node.type === "LogicalExpression") { return withParensIfBreak(node, doc4); } return doc4; } function withParensIfBreak(node, doc4) { var _a, _b; if (((_a = node.leadingComments) == null ? void 0 : _a.length) || ((_b = node.trailingComments) == null ? void 0 : _b.length) || !enclosedNodeTypeReg.test(node.type) && outerCodeMatches(printDoc(doc4).trim(), /\n/y, true)) { return b3.group([ b3.ifBreak("(", ""), b3.indent([b3.softline, doc4]), b3.softline, b3.ifBreak(")", "") ]); } return doc4; } // src/utils/as-literal-text-content.ts var import_prettier4 = require("prettier"); var { builders: b4 } = import_prettier4.doc; var temp = [""]; function asLiteralTextContent(val, escapeBackslashes = false) { let charPos = 0; let slotPos = 0; for (let i = 0, len = val.length; i < len; i++) { switch (val.charAt(i)) { case (escapeBackslashes && "\\"): temp.push("\\\\"); break; case "\n": temp.push(b4.literalline); break; default: continue; } temp[slotPos] = val.slice(charPos, i); slotPos = temp.push("") - 1; charPos = i + 1; } if (charPos) { const result = temp; result[slotPos] = val.slice(charPos); temp = [""]; return result; } else { return val; } } function asFilledTextContent(val) { const parts = val.split(/\s+/); const len = parts.length; switch (len) { case 0: return ""; case 1: return asLiteralTextContent(parts[0], true); } const doc4 = []; const last = len - 1; for (let i = 0; i < last; i++) { doc4.push(asLiteralTextContent(parts[i], true), b4.line); } doc4.push(asLiteralTextContent(parts[last], true)); return b4.fill(doc4); } // src/utils/get-original-code.ts var import_generator = __toESM(require("@babel/generator")); var generate = import_generator.default.default || import_generator.default; function getOriginalCodeForNode(opts, node, path) { var _a, _b, _c; const hasLeadingComments = ((_a = node.leadingComments) == null ? void 0 : _a.length) && !(path && ((_b = path.getParentNode()) == null ? void 0 : _b.type) === "MarkoScriptlet" && !path.isFirst); const hasTrailingComments = (_c = node.trailingComments) == null ? void 0 : _c.length; if (!hasLeadingComments && !hasTrailingComments) { switch (node.type) { case "StringLiteral": return JSON.stringify(node.value); case "BooleanLiteral": case "NumericLiteral": return "" + node.value; case "NullLiteral": return "null"; } } const loc = node.loc; if (!loc) { return generate(node, { filename: opts.filepath, compact: false, comments: true, sourceMaps: false }).code; } let start = loc.start; if (hasLeadingComments) { const commentStart = node.leadingComments[0].loc.start; if (commentStart.line < start.line || commentStart.line === start.line && commentStart.column < start.column) { start = commentStart; } } let end = loc.end; if (hasTrailingComments) { const commentEnd = node.trailingComments[node.trailingComments.length - 1].loc.end; if (commentEnd.line > end.line || commentEnd.line === end.line && commentEnd.column > end.column) { end = commentEnd; } } return opts.originalText.slice(locToPos(start, opts), locToPos(end, opts)); } // src/index.ts var defaultFilePath = (0, import_path.resolve)("index.marko"); var rootRequire = (0, import_module.createRequire)(defaultFilePath); var { builders: b5, utils } = import_prettier5.doc; var identity = (val) => val; var emptyArr = []; var embeddedPlaceholderReg = /__EMBEDDED_PLACEHOLDER_(\d+)__/g; var currentCompiler; var currentConfig; var languages = [ { name: "marko", aceMode: "text", parsers: ["marko"], aliases: ["markojs"], tmScope: "text.marko", codemirrorMode: "htmlmixed", vscodeLanguageIds: ["marko"], linguistLanguageId: 932782397, codemirrorMimeType: "text/html", extensions: [".marko"] } ]; var options = { markoSyntax: { type: "choice", default: "auto", category: "Marko", description: "Change output syntax between HTML mode, concise mode and auto.", choices: [ { value: "auto", description: "Determine output syntax by the input syntax used." }, { value: "html", description: "Force the output to use the HTML syntax." }, { value: "concise", description: "Force the output to use the concise syntax." } ] }, markoAttrParen: { type: "boolean", default: (() => { try { const compilerRequire = (0, import_module.createRequire)( rootRequire.resolve("@marko/compiler") ); const [major, minor] = compilerRequire("htmljs-parser/package.json").version.split(".").map((v) => parseInt(v, 10)); return major < 2 || major === 2 && minor < 11; } catch { return false; } })(), category: "Marko", description: "If enabled all attributes with unenclosed whitespace will be wrapped in parens." } }; var parsers = { marko: { astFormat: "marko-ast", async parse(text, opts) { ensureCompiler(); const { filepath = defaultFilePath } = opts; const { compile, types: t } = currentCompiler; const { ast } = await compile(`${text} `, filepath, currentConfig); opts.originalText = text; opts.markoLinePositions = [0]; opts.markoPreservingSpace = false; for (let i = 0; i < text.length; i++) { if (text[i] === "\n") { opts.markoLinePositions.push(i); } } if (opts.markoSyntax === "auto") { opts.markoSyntax = "html"; for (const childNode of ast.program.body) { if (t.isMarkoTag(childNode)) { if (t.isStringLiteral(childNode.name) && childNode.name.value === "style" && styleReg.exec(childNode.rawValue || "style")[0].endsWith("{")) { continue; } if (opts.originalText[locToPos(childNode.loc.start, opts)] !== "<") { opts.markoSyntax = "concise"; } break; } } } t.traverseFast(ast, (node) => { if (node.type === "MarkoAttribute") { switch (node.name) { case "class": case "id": switch (node.value.type) { case "StringLiteral": case "ArrayExpression": case "TemplateLiteral": case "ObjectExpression": node.value.loc = null; break; } break; } } }); return ast; }, locStart(node) { var _a, _b; return ((_b = (_a = node.loc) == null ? void 0 : _a.start) == null ? void 0 : _b.index) || 0; }, locEnd(node) { var _a, _b; return ((_b = (_a = node.loc) == null ? void 0 : _a.end) == null ? void 0 : _b.index) || 0; } } }; var printers = { "marko-ast": { print(path, opts, print) { var _a, _b, _c, _d; const node = path.getNode(); if (!node) return ""; const { types: t } = currentCompiler; switch (node.type) { case "File": return path.call(print, "program"); case "Program": { let text = []; const lastIndex = node.body.length - 1; const bodyDocs = []; path.each((child, i) => { const childNode = child.getNode(); const isText2 = isTextLike(childNode, node, opts); if (isText2) { text.push(print(child)); if (i !== lastIndex) return; } if (text.length) { const textDoc = b5.group([ printDashes(node), b5.indent([b5.line, b5.fill(text)]) ]); if (isText2) { bodyDocs.push(textDoc); } else { text = []; bodyDocs.push(textDoc, print(child)); } } else { bodyDocs.push(print(child)); } }, "body"); return [b5.join(b5.hardline, bodyDocs), b5.hardline]; } case "MarkoDocumentType": return `<!${node.value.replace(/\s+/g, " ").trim()}>`; case "MarkoDeclaration": return asLiteralTextContent(`<?${node.value}?>`); case "MarkoComment": { switch (getCommentType(node, opts)) { case "/": return asLiteralTextContent(`//${node.value}`); case "*": return asLiteralTextContent(`/*${node.value}*/`); default: return asLiteralTextContent(`<!--${node.value}-->`); } } case "MarkoCDATA": return asLiteralTextContent(`<![CDATA[${node.value}]]>`); case "MarkoTag": { const tagPath = path; const groupId = Symbol(); const doc4 = [opts.markoSyntax === "html" ? "<" : ""]; const { markoPreservingSpace } = opts; const literalTagName = t.isStringLiteral(node.name) ? node.name.value : ""; const preserveSpace = markoPreservingSpace || (opts.markoPreservingSpace = preserveSpaceTagsReg.test(literalTagName)); if (literalTagName) { doc4.push(literalTagName); } else { doc4.push( b5.group([ "${", b5.indent([b5.softline, tagPath.call(print, "name")]), b5.softline, "}" ]) ); } if (node.typeArguments) { doc4.push( tagPath.call(print, "typeArguments") ); } if (node.body.typeParameters) { if (!node.typeArguments) { doc4.push(" "); } doc4.push( tagPath.call(print, "body", "typeParameters") ); } const shorthandIndex = doc4.push("") - 1; if (node.var) { doc4.push( "/", tagPath.call( print, "var" ) ); } if ((_a = node.arguments) == null ? void 0 : _a.length) { doc4.push( b5.group([ "(", b5.indent([ b5.softline, b5.join( [",", b5.line], tagPath.map((it) => print(it), "arguments") ), opts.trailingComma === "all" && !preventTrailingCommaTagArgs(literalTagName) ? b5.ifBreak(",") : "" ]), b5.softline, ")" ]) ); } if (node.body.params.length) { doc4.push( b5.group([ "|", b5.indent([ b5.softline, b5.join( [",", b5.line], tagPath.map((it) => print(it), "body", "params") ), opts.trailingComma === "all" ? b5.ifBreak(",") : "" ]), b5.softline, "|" ]) ); } if (node.attributes.length) { const attrsDoc = []; tagPath.each((attrPath) => { const attrNode = attrPath.getNode(); if (t.isMarkoAttribute(attrNode) && (attrNode.name === "class" || attrNode.name === "id")) { if (opts.markoSyntax === "concise" && t.isStringLiteral(attrNode.value) && !attrNode.modifier && shorthandIdOrClassReg.test(attrNode.value.value)) { const symbol = attrNode.name === "class" ? "." : "#"; doc4[shorthandIndex] += symbol + attrNode.value.value.split(/ +/).join(symbol); } else { attrsDoc.push(print(attrPath)); } } else if (attrNode.default) { doc4.push(print(attrPath)); } else { attrsDoc.push(print(attrPath)); } }, "attributes"); if (attrsDoc.length) { if (attrsDoc.length === 1) { doc4.push(" ", attrsDoc[0]); } else { const attrSep = opts.markoSyntax === "concise" ? [b5.line, b5.ifBreak(",")] : b5.line; doc4.push( b5.group(b5.indent([attrSep, b5.join(attrSep, attrsDoc)])) ); } } } const hasAttrTags = !!((_b = node.attributeTags) == null ? void 0 : _b.length); if (voidHTMLReg.test(literalTagName)) { if (opts.markoSyntax === "html") doc4.push(">"); } else if (node.body.body.length || hasAttrTags) { const lastIndex = node.body.body.length - 1; const bodyDocs = hasAttrTags ? tagPath.map(print, "attributeTags") : []; let textOnly = !hasAttrTags; let textDocs = []; tagPath.each( (childPath, i) => { const childNode = childPath.getNode(); const isText2 = isTextLike(childNode, node, opts); const isLast = i === lastIndex; if (isText2) { if (preserveSpace && opts.markoSyntax === "concise") { bodyDocs.push( b5.group([printDashes(node), " ", print(childPath)]) ); } else { textDocs.push(print(childPath)); } if (textOnly || !isLast) return; } else { textOnly = false; } if (textDocs.length) { if (opts.markoSyntax === "html") { bodyDocs.push(textDocs); } else if (!preserveSpace) { const dashes = printDashes(node); bodyDocs.push( b5.group([ dashes, b5.line, textDocs, b5.ifBreak([b5.line, dashes]) ]) ); } if (!isText2) { textDocs = []; bodyDocs.push(print(childPath)); } } else { bodyDocs.push(print(childPath)); } }, "body", "body" ); if (opts.markoSyntax === "html") { const joinSep = preserveSpace ? "" : textOnly ? b5.softline : b5.hardline; const wrapSep = !preserveSpace && (node.var || node.body.params.length || ((_c = node.arguments) == null ? void 0 : _c.length) || node.attributes.length || node.body.body.some( (child) => !isTextLike(child, node, opts) )) ? b5.hardline : joinSep; doc4.push( ">", b5.indent([ wrapSep, textOnly ? b5.group(textDocs) : b5.join(joinSep, bodyDocs) ]), wrapSep, `</${literalTagName}>` ); } else { if (!preserveSpace && textOnly) { if (node.attributes.length) { doc4.push( b5.indent([ b5.line, b5.group([ printDashes(node), b5.indent([b5.line, textDocs]) ]) ]) ); } else { doc4.push( b5.group([ " " + printDashes(node), b5.indent([b5.line, textDocs]) ]) ); } } else { if (textOnly && bodyDocs.length === 1) { doc4.push(" ", bodyDocs); } else { doc4.push( b5.indent([b5.hardline, b5.join(b5.hardline, bodyDocs)]) ); } } } } else if (opts.markoSyntax === "html") { doc4.push("/>"); } opts.markoPreservingSpace = markoPreservingSpace; return withLineIfNeeded(node, opts, b5.group(doc4, { id: groupId })); } case "MarkoAttribute": { const attrPath = path; const doc4 = []; const { value } = node; if (!node.default) { doc4.push(node.name); if (node.modifier) { doc4.push(`:${node.modifier}`); } if ((_d = node.arguments) == null ? void 0 : _d.length) { doc4.push( b5.group([ "(", b5.indent([ b5.softline, b5.join( [",", b5.line], attrPath.map((it) => print(it), "arguments") ), opts.trailingComma === "all" && !preventTrailingCommaAttrArgs(node.name) ? b5.ifBreak(",") : "" ]), b5.softline, ")" ]) ); } } if (node.default || !t.isBooleanLiteral(value, { value: true })) { if (t.isFunctionExpression(value) && !(value.id || value.async || value.generator)) { doc4.push(attrPath.call(print, "value")); } else { doc4.push( node.bound ? ":=" : "=", b5.group( withParensIfNeeded( value, attrPath.call(print, "value"), opts.markoAttrParen ) ) ); } } return doc4; } case "MarkoSpreadAttribute": { return ["..."].concat( withParensIfNeeded( node.value, path.call( print, "value" ), opts.markoAttrParen ) ); } case "MarkoPlaceholder": return [ node.escape ? "${" : "$!{", path.call(print, "value"), "}" ]; case "MarkoScriptlet": { const prefix = node.static ? node.target || "static" : "$"; if (node.body.filter((child) => !isEmpty(child)).length <= 1) { let bodyDoc = []; path.each((childPath) => { const childNode = childPath.getNode(); if (childNode && !isEmpty(childNode)) { bodyDoc = withLineIfNeeded( childNode, opts, printSpecialDeclaration(childPath, prefix, opts, print) || [ prefix + " ", withBlockIfNeeded(childNode, childPath.call(print)) ] ); } }, "body"); return bodyDoc; } else { return [ prefix, " {", b5.indent([ b5.hardline, b5.join( b5.hardline, path.map((childPath) => { if (childPath.node.type !== "EmptyStatement") { return childPath.call(print); } return []; }, "body") ) ]), b5.hardline, "}" ]; } } case "MarkoText": { const parent = getTextParent(path); let { value } = node; const isConcise = opts.markoSyntax === "concise"; if (isConcise && opts.markoPreservingSpace) { return toPlaceholder(value, opts.singleQuote); } const dashMatch = isConcise && /---*/.exec(value); if (dashMatch) { minDashLookup.set( parent, Math.max(minDashLookup.get(parent) || 0, dashMatch[0].length) ); } if (opts.markoPreservingSpace) { return asLiteralTextContent(value); } let prefix = ""; let suffix = ""; if (value[0] === " " && !(path.previous && isTextLike(path.previous, parent, opts))) { prefix = opts.singleQuote ? "${' '}" : '${" "}'; value = value.slice(1); } const last = value.length - 1; if (value[last] === " " && !(path.next && isTextLike(path.next, parent, opts))) { suffix = opts.singleQuote ? "${' '}" : '${" "}'; value = value.slice(0, last); } return [prefix, asFilledTextContent(value), suffix]; } default: throw new Error(`Unknown node type in Marko template: ${node.type}`); } }, embed(path, opts) { ensureCompiler(); const node = path.getNode(); const type = node == null ? void 0 : node.type; const { types: t } = currentCompiler; switch (type) { case "File": case "Program": return null; case "MarkoClass": return (toDoc) => toDoc( `class ${getOriginalCodeForNode( opts, node.body )}`, { parser: expressionParser } ); case "MarkoTag": if (node.name.type === "StringLiteral") { switch (node.name.value) { case "script": return async (toDoc, print) => { var _a; const placeholders = []; const groupId = Symbol(); const parser = getScriptParser(node); const doc4 = [ opts.markoSyntax === "html" ? "<" : "", "script" ]; let placeholderId = 0; if (node.var) { doc4.push( "/", path.call(print, "var") ); } let bodyOverrideCode; if (node.attributes.length) { const attrsDoc = []; path.each((attrPath) => { const attrNode = attrPath.getNode(); if (attrNode.type === "MarkoAttribute" && attrNode.name === "value" && !node.body.body.length && (attrNode.value.type === "FunctionExpression" || attrNode.value.type === "ArrowFunctionExpression") && !(attrNode.value.generator || attrNode.value.returnType || attrNode.value.typeParameters)) { bodyOverrideCode = getOriginalCodeForNode( opts, attrNode.value.body ).replace(/^\s*{\s*/, "").replace(/\s*}\s*$/, ""); } else if (attrNode.default) { doc4.push(print(attrPath)); } else { attrsDoc.push(print(attrPath)); } }, "attributes"); if (attrsDoc.length) { if (attrsDoc.length === 1) { doc4.push(" ", attrsDoc[0]); } else { const attrSep = opts.markoSyntax === "concise" ? [b5.line, b5.ifBreak(",")] : b5.line; doc4.push( b5.group( b5.indent([attrSep, b5.join(attrSep, attrsDoc)]) ) ); } } } const bodyOverride = bodyOverrideCode !== void 0 && await toDoc(bodyOverrideCode, { parser }).catch(() => asLiteralTextContent(bodyOverrideCode)); if (bodyOverride || node.body.body.length) { let embeddedCode = ""; if (!bodyOverride) { path.each( (childPath) => { const childNode = childPath.getNode(); if (childNode.type === "MarkoText") { embeddedCode += childNode.value; } else { embeddedCode += `__EMBEDDED_PLACEHOLDER_${placeholderId++}__`; placeholders.push(print(childPath)); } }, "body", "body" ); } const bodyDoc = bodyOverride || replaceEmbeddedPlaceholders( !parser ? asLiteralTextContent(embeddedCode.trim()) : await toDoc(embeddedCode, { parser }).catch( () => asLiteralTextContent(embeddedCode.trim()) ), placeholders ); if (opts.markoSyntax === "html") { const wrapSep = node.var || node.body.params.length || ((_a = node.arguments) == null ? void 0 : _a.length) || node.attributes.length || !bodyOverride && node.body.body.some( (child) => child.type === "MarkoScriptlet" || !isTextLike(child, node, opts) ) ? b5.hardline : b5.softline; doc4.push( ">", b5.indent([wrapSep, bodyDoc]), wrapSep, `</script>` ); } else { doc4.push( b5.group([ " " + printDashes(node), b5.indent([b5.line, bodyDoc]) ]) ); } } else if (opts.markoSyntax === "html") { doc4.push("/>"); } return withLineIfNeeded( node, opts, b5.group(doc4, { id: groupId }) ); }; case "style": { const rawValue = node.rawValue; const [startContent, lang] = styleReg.exec( rawValue || "style" ); const parser = lang ? getParserNameFromExt(lang) : "css"; if (startContent.endsWith("{")) { const codeSartOffset = startContent.length; const codeEndOffset = node.rawValue.lastIndexOf("}"); const code = rawValue.slice(codeSartOffset, codeEndOffset).trim(); return async (toDoc) => { try { return withLineIfNeeded( node, opts, b5.group([ "style", !lang || lang === ".css" ? "" : lang, " {", b5.indent([ b5.line, await toDoc(code, { parser }).catch( () => asLiteralTextContent(code.trim()) ) ]), b5.line, "}" ]) ); } catch { return withLineIfNeeded( node, opts, asLiteralTextContent(rawValue) ); } }; } else { return async (toDoc, print) => { var _a; const placeholders = []; const groupId = Symbol(); const doc4 = [ opts.markoSyntax === "html" ? "<" : "", "style", !lang || lang === ".css" ? "" : lang ]; let placeholderId = 0; if (node.var) { doc4.push( "/", path.call(print, "var") ); } if (!lang && node.attributes.length) { const attrsDoc = []; path.each((attrPath) => { const attrNode = attrPath.getNode(); if (attrNode.default) { doc4.push(print(attrPath)); } else { attrsDoc.push(print(attrPath)); } }, "attributes"); if (attrsDoc.length) { if (attrsDoc.length === 1) { doc4.push(" ", attrsDoc[0]); } else { const attrSep = opts.markoSyntax === "concise" ? [b5.line, b5.ifBreak(",")] : b5.line; doc4.push( b5.group( b5.indent([attrSep, b5.join(attrSep, attrsDoc)]) ) ); } } } if (node.body.body.length) { let embeddedCode = ""; path.each( (childPath) => { const childNode = childPath.getNode(); if (childNode.type === "MarkoText") { embeddedCode += childNode.value; } else { embeddedCode += `__EMBEDDED_PLACEHOLDER_${placeholderId++}__`; placeholders.push(print(childPath)); } }, "body", "body" ); const bodyDoc = replaceEmbeddedPlaceholders( !parser ? asLiteralTextContent(embeddedCode.trim()) : await toDoc(embeddedCode, { parser }).catch( () => asLiteralTextContent(embeddedCode.trim()) ), placeholders ); if (opts.markoSyntax === "html") { const wrapSep = node.var || node.body.params.length || ((_a = node.arguments) == null ? void 0 : _a.length) || node.attributes.length ? b5.hardline : b5.softline; doc4.push( ">", b5.indent([wrapSep, bodyDoc]), wrapSep, `</style>` ); } else { doc4.push( b5.group([ " " + printDashes(node), b5.indent([b5.line, bodyDoc]) ]) ); } } else if (opts.markoSyntax === "html") { doc4.push("/>"); } return withLineIfNeeded( node, opts, b5.group(doc4, { id: groupId }) ); }; } } } } } if (type.startsWith("Marko")) return null; let parent = path.parent; if (parent.type !== "Program") { let parentIndex = 0; while (!(parent.type === "ExportNamedDeclaration" || parent.type.startsWith("Marko"))) { parent = path.getParentNode(++parentIndex); if (!parent) return null; } } return async (toDoc, print) => { switch (node.type) { case "EmptyStatement": return void 0; case "ExportNamedDeclaration": if (node.declaration) { const printedDeclaration = path.call( (childPath) => printSpecialDeclaration( childPath, "export", opts, print ), "declaration" ); if (printedDeclaration) return printedDeclaration; } break; } const code = getOriginalCodeForNode( opts, node, path ); if (t.isStatement(node)) { return tryPrintEmbed(code, scriptParser); } else { const parent2 = path.getParentNode(); const parentType = parent2 == null ? void 0 : parent2.type; if (parentType === "MarkoTag" && path.key === "typeArguments") { return tryPrintEmbed( `_${code}`, scriptParser, (doc4) => { const last = doc4.length - 1; doc4[0] = doc4[0].replace(/^_/, ""); doc4[last] = doc4[last].replace(/;$/, ""); return doc4; }, code ); } else if (parentType === "MarkoTagBody" && path.key === "typeParameters") { return tryPrintEmbed( `function _${code}() {}`, scriptParser, (doc4) => { return doc4[1]; }, code ); } else if (parentType === "MarkoTagBody" || parentType === "VariableDeclarator" && path.key === "id" || parentType === "MarkoTag" && path.key === "var") { return tryPrintEmbed( `var ${code}=_`, scriptParser, (doc4) => { const contents = doc4[0].contents[1].contents; for (let i = contents.length; i--; ) { const item = contents[i]; if (typeof item === "string") { const match = /\s*=\s*$/.exec(item); if (match) { contents[i] = item.slice(0, -match[0].length); contents.length = i + 1; break; } } } return contents; }, code ); } else if (parentType === "MarkoAttribute" && path.key === "value" && node.type === "FunctionExpression" && !(node.async || node.generator || node.id)) { return tryPrintEmbed( `({_${code.replace(/^\s*function\s*/, "")}})`, scriptParser, (doc4) => { return doc4[1].contents[1].contents[1].contents.slice(1); }, code ); } return tryPrintEmbed(code, expressionParser); } async function tryPrintEmbed(code2, parser, normalize = identity, fallback = code2) { try { return normalize(await toDoc(code2, { parser })); } catch { return [asLiteralTextContent(fallback)]; } } }; }, getVisitorKeys(node) { ensureCompiler(); return currentCompiler.types.VISITOR_KEYS[node.type] || emptyArr; } } }; function setCompiler(compiler, config) { currentCompiler = compiler; setConfig(config); } function printSpecialDeclaration(path, prefix, opts, print) { const node = path.getNode(); switch (node == null ? void 0 : node.type) { case "TSTypeAliasDeclaration": return [ prefix + " type ", node.id.name, node.typeParameters ? [ "<", b5.group([ b5.indent([ b5.softline, path.call( (paramsPath) => b5.join( [",", b5.line], paramsPath.map((param) => param.call(print)) ), "typeParameters", "params" ) ]), b5.softline, ">" ]) ] : "", " = ", withParensIfBreak( node.typeAnnotation, path.call(print, "typeAnnotation") ), opts.semi ? ";" : "" ]; case "VariableDeclaration": { if (path.node.leadingComments || path.node.trailingComments) { break; } return b5.join( b5.hardline, path.map((declPath) => { const decl = declPath.getNode(); return [ prefix + " " + (node.declare ? "declare " : "") + node.kind + " ", declPath.call(print, "id"), decl.init ? [ " = ", withParensIfBreak( decl.init, declPath.call(print, "init") ) ] : "", opts.semi ? ";" : "" ]; }, "declarations") ); } case "EmptyStatement": { if (node.trailingComments) { if (node.trailingComments.length > 1) { return b5.join(b5.hardline, [ b5.indent( b5.join(b5.hardline, [ prefix + " {", ...printComments(node.trailingComments) ]) ), "}" ]); } else { return prefix + " " + printComments(node.trailingComments)[0]; } } else { return []; } } } } function printComments(comments) { return comments.map( (comment) => comment.type === "CommentBlock" ? `/*${comment.value}*/` : "//" + comment.value ); } function replaceEmbeddedPlaceholders(doc4, placeholders) { if (!placeholders.length) return doc4; return utils.mapDoc(doc4, (cur) => { if (typeof cur === "string") { let match = embeddedPlaceholderReg.exec(cur); if (match) { const replacementDocs = []; let index = 0; do { const placeholderIndex = +match[1]; if (index !== match.index) { replacementDocs.push(cur.slice(index, match.index)); } replacementDocs.push(placeholders[placeholderIndex]); index = match.index + match[0].length; } while (match = embeddedPlaceholderReg.exec(cur)); if (index !== cur.length) { replacementDocs.push(cur.slice(index)); } if (replacementDocs.length === 1) { return replacementDocs[0]; } return replacementDocs; } } return cur; }); } function getParserNameFromExt(ext) { switch (ext) { case ".css": return "css"; case ".less": return "less"; case ".scss": return "scss"; case ".js": case ".mjs": case ".cjs": return "babel"; case ".ts": case ".mts": case ".cts": return "babel-ts"; } } function preventTrailingCommaTagArgs(tagName) { switch (tagName) { case "if": case "else-if": case "while": return true; default: return false; } } function preventTrailingCommaAttrArgs(attrName) { switch (attrName) { case "if": case "while": case "no-update-if": case "no-update-body-if": return true; default: return false; } } function ensureCompiler() { if (!currentConfig) { let config; try { currentCompiler = rootRequire("@marko/compiler"); config = rootRequire("@marko/compiler/config").default; } catch (cause) { throw new Error( "You must have @marko/compiler installed to use prettier-plugin-marko.", { cause } ); } setConfig(config); } } function setConfig(config) { let { translator } = config; if (typeof translator === "string") { try { translator = rootRequire(translator); } catch { } } currentConfig = { ...config, translator, ast: true, code: false, optimize: false, output: "source", sourceMaps: false, writeVersionComment: false, babelConfig: { caller: { name: "@marko/prettier" }, babelrc: false, configFile: false, parserOpts: { allowUndeclare