🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

prettier-plugin-marko

Package Overview
Dependencies
Maintainers
7
Versions
69
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

prettier-plugin-marko - npm Package Compare versions

Comparing version
4.0.3
to
4.0.4
+225
dist/parser.d.ts
import { type Range, type Ranges, TagType } from "htmljs-parser";
export type Repeated<T> = [T, ...T[]] | [...T[], T] | [T, ...T[], T];
export type Repeatable<T> = undefined | Repeated<T>;
export declare const UNFINISHED: number;
export { getLines, getLocation, getPosition, type Location, type Position, type Range, type Ranges, TagType, } from "htmljs-parser";
export type Parsed = ReturnType<typeof parse>;
export declare enum NodeType {
Program = 0,
Tag = 1,
OpenTagName = 2,
ShorthandId = 3,
ShorthandClassName = 4,
TagTypeArgs = 5,
TagTypeParams = 6,
TagVar = 7,
TagArgs = 8,
TagParams = 9,
AttrNamed = 10,
AttrName = 11,
AttrArgs = 12,
AttrValue = 13,
AttrMethod = 14,
AttrSpread = 15,
AttrTag = 16,
Text = 17,
CDATA = 18,
Doctype = 19,
Declaration = 20,
Comment = 21,
Placeholder = 22,
Scriptlet = 23,
Import = 24,
Export = 25,
Class = 26,
Style = 27,
Static = 28
}
export declare namespace Node {
type AnyNode = Program | Tag | OpenTagName | ShorthandId | ShorthandClassName | TagTypeArgs | TagTypeParams | TagVar | TagArgs | TagParams | AttrNamed | AttrName | AttrArgs | AttrValue | AttrMethod | AttrSpread | AttrTag | Text | CDATA | Doctype | Declaration | Comment | Placeholder | Scriptlet | Import | Export | Class | Style | Static;
type ParentNode = Program | Tag | AttrTag;
type StaticNode = Import | Export | Class | Style | Static;
type ParentTag = Tag | AttrTag;
type AttrNode = AttrNamed | AttrSpread;
type ControlFlowTag = Tag & {
nameText: "if" | "else" | "else-if" | "for" | "while";
bodyType: TagType.html;
};
type ChildNode = Tag | AttrTag | Text | Doctype | Declaration | CDATA | Placeholder | Scriptlet | Comment;
interface Program extends Range {
type: NodeType.Program;
parent: undefined;
static: StaticNode[];
body: ChildNode[];
}
interface Tag extends Range {
type: NodeType.Tag;
parent: ParentNode;
owner: undefined;
concise: boolean;
selfClosed: boolean;
hasAttrTags: boolean;
open: Range;
close: Range | undefined;
nameText: string | undefined;
bodyType: Exclude<TagType, "statement">;
name: OpenTagName;
var: TagVar | undefined;
args: TagArgs | undefined;
params: TagParams | undefined;
shorthandId: ShorthandId | undefined;
shorthandClassNames: Repeatable<ShorthandClassName>;
typeArgs: TagTypeArgs | undefined;
typeParams: TagTypeParams | undefined;
attrs: Repeatable<AttrNode>;
body: Repeatable<ChildNode>;
}
interface AttrTag extends Range {
type: NodeType.AttrTag;
parent: ParentTag;
owner: Tag | undefined;
concise: boolean;
selfClosed: boolean;
hasAttrTags: boolean;
open: Range;
close: Range | undefined;
nameText: string;
bodyType: TagType.html;
name: OpenTagName;
var: TagVar | undefined;
args: TagArgs | undefined;
params: TagParams | undefined;
shorthandId: ShorthandId | undefined;
shorthandClassNames: Repeatable<ShorthandClassName>;
typeArgs: TagTypeArgs | undefined;
typeParams: TagTypeParams | undefined;
attrs: Repeatable<AttrNode>;
body: Repeatable<ChildNode>;
}
interface OpenTagName extends Ranges.Template {
type: NodeType.OpenTagName;
parent: ParentTag;
}
interface ShorthandId extends Ranges.Template {
type: NodeType.ShorthandId;
parent: ParentTag;
}
interface ShorthandClassName extends Ranges.Template {
type: NodeType.ShorthandClassName;
parent: ParentTag;
}
interface TagTypeArgs extends Ranges.Value {
type: NodeType.TagTypeArgs;
parent: ParentTag;
}
interface TagTypeParams extends Ranges.Value {
type: NodeType.TagTypeParams;
parent: ParentTag;
}
interface TagVar extends Ranges.Value {
type: NodeType.TagVar;
parent: ParentTag;
}
interface TagArgs extends Ranges.Value {
type: NodeType.TagArgs;
parent: ParentTag;
}
interface TagParams extends Ranges.Value {
type: NodeType.TagParams;
parent: ParentTag;
}
interface Text extends Range {
type: NodeType.Text;
parent: ParentNode;
}
interface CDATA extends Ranges.Value {
type: NodeType.CDATA;
parent: ParentNode;
}
interface Doctype extends Ranges.Value {
type: NodeType.Doctype;
parent: ParentNode;
}
interface Declaration extends Ranges.Value {
type: NodeType.Declaration;
parent: ParentNode;
}
interface Comment extends Ranges.Value {
type: NodeType.Comment;
parent: ParentNode;
block: boolean;
}
interface Placeholder extends Ranges.Value {
type: NodeType.Placeholder;
parent: ParentNode;
escape: boolean;
}
interface Scriptlet extends Ranges.Value {
type: NodeType.Scriptlet;
parent: ParentNode;
block: boolean;
}
interface AttrNamed extends Range {
type: NodeType.AttrNamed;
parent: ParentTag;
name: AttrName;
args: undefined | AttrArgs;
value: undefined | AttrValue | AttrMethod;
}
interface AttrName extends Range {
type: NodeType.AttrName;
parent: AttrNamed;
}
interface AttrArgs extends Ranges.Value {
type: NodeType.AttrArgs;
parent: AttrNamed;
}
interface AttrValue extends Range {
type: NodeType.AttrValue;
parent: AttrNamed;
value: Range;
bound: boolean;
}
interface AttrMethod extends Range {
type: NodeType.AttrMethod;
parent: AttrNamed;
typeParams: undefined | Ranges.Value;
params: Range;
body: Range;
}
interface AttrSpread extends Ranges.Value {
type: NodeType.AttrSpread;
parent: ParentTag;
}
interface Import extends Range {
type: NodeType.Import;
parent: ParentNode;
}
interface Export extends Range {
type: NodeType.Export;
parent: ParentNode;
}
interface Class extends Range {
type: NodeType.Class;
parent: ParentNode;
}
interface Style extends Range {
type: NodeType.Style;
parent: ParentNode;
ext: string | undefined;
value: Range;
}
interface Static extends Range {
type: NodeType.Static;
parent: ParentNode;
target: "client" | "server" | "static";
}
}
export declare function parse(code: string, filename?: string): {
read: (range: Range) => string;
locationAt: (range: Range) => import("htmljs-parser").Location;
positionAt: (offset: number) => import("htmljs-parser").Position;
filename: string;
program: Node.Program;
code: string;
};
import { type AstPath, type Doc, doc, type Options } from "prettier";
import { type Node } from "../parser";
export declare function getFormattedBody(tag: AstPath<Node.Tag>, parser: Options["parser"] | false, toDoc: (text: string, options: Options) => Promise<Doc>, print: (selector: AstPath) => Doc, opts: Options): Promise<doc.builders.Doc>;
import type { Options } from "prettier";
import { type Node } from "../parser";
export declare function getParserFromExt(ext: string): false | "babel-ts" | "babel" | "css" | "less" | "scss";
export declare function hasTagParser(tag: Node.Tag): boolean;
export declare function getTagParser(tag: Node.Tag, opts: Options): false | import("prettier").LiteralUnion<import("prettier").BuiltInParserName, string> | undefined;
import type { Options } from "prettier";
import type { Range } from "../parser";
export declare function read(range: Range, opts: Options): string;
import { type Doc, type Options } from "prettier";
export declare const singleQuoteSpace = "${' '}";
export declare const doubleQuoteSpace = "${\" \"}";
export declare function ensureVisibleSpace(parts: Doc[], opts: Options): void;
export declare function ensureVisibleTrailingSpace(parts: Doc[], opts: Options): void;
export declare function ensureVisibleSpaceBetweenTags(parts: Doc[], opts: Options): void;
export declare function getVisibleSpace(opts: Options): "${' '}" | "${\" \"}";
export declare function isVisibleSpace(code: string): boolean;
+15
-7

@@ -1,10 +0,18 @@

import { SupportLanguage, Parser, Printer, SupportOptions } from "prettier";
import type * as Compiler from "@marko/compiler";
import type { types, Config } from "@marko/compiler";
type Node = types.Node;
import { type Parser, type Printer, type SupportLanguage, type SupportOptions } from "prettier";
import { type Node, type Parsed } from "./parser";
declare module "prettier" {
interface Options {
markoSyntax?: "auto" | "html" | "concise";
_markoParsed?: Parsed;
}
interface ParserOptions {
markoSyntax?: "auto" | "html" | "concise";
_markoParsed?: Parsed;
}
}
type AnyNode = Node.AnyNode;
export declare const languages: SupportLanguage[];
export declare const options: SupportOptions;
export declare const parsers: Record<string, Parser<Node>>;
export declare const printers: Record<string, Printer<types.Node>>;
export declare function setCompiler(compiler: typeof Compiler, config: Config): void;
export declare const parsers: Record<string, Parser<AnyNode>>;
export declare const printers: Record<string, Printer<AnyNode>>;
export {};
+1332
-1540

@@ -1,1571 +0,1363 @@

"use strict";
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
for (var name in all)
__defProp(target, name, { get: all[name], enumerable: true });
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
let prettier = require("prettier");
let htmljs_parser = require("htmljs-parser");
const styleBlockReg = /((?:\.[^\s\\/:*?"<>|({]+)*)\s*\{/y;
const UNFINISHED = Number.MAX_SAFE_INTEGER;
let NodeType = /* @__PURE__ */ function(NodeType) {
NodeType[NodeType["Program"] = 0] = "Program";
NodeType[NodeType["Tag"] = 1] = "Tag";
NodeType[NodeType["OpenTagName"] = 2] = "OpenTagName";
NodeType[NodeType["ShorthandId"] = 3] = "ShorthandId";
NodeType[NodeType["ShorthandClassName"] = 4] = "ShorthandClassName";
NodeType[NodeType["TagTypeArgs"] = 5] = "TagTypeArgs";
NodeType[NodeType["TagTypeParams"] = 6] = "TagTypeParams";
NodeType[NodeType["TagVar"] = 7] = "TagVar";
NodeType[NodeType["TagArgs"] = 8] = "TagArgs";
NodeType[NodeType["TagParams"] = 9] = "TagParams";
NodeType[NodeType["AttrNamed"] = 10] = "AttrNamed";
NodeType[NodeType["AttrName"] = 11] = "AttrName";
NodeType[NodeType["AttrArgs"] = 12] = "AttrArgs";
NodeType[NodeType["AttrValue"] = 13] = "AttrValue";
NodeType[NodeType["AttrMethod"] = 14] = "AttrMethod";
NodeType[NodeType["AttrSpread"] = 15] = "AttrSpread";
NodeType[NodeType["AttrTag"] = 16] = "AttrTag";
NodeType[NodeType["Text"] = 17] = "Text";
NodeType[NodeType["CDATA"] = 18] = "CDATA";
NodeType[NodeType["Doctype"] = 19] = "Doctype";
NodeType[NodeType["Declaration"] = 20] = "Declaration";
NodeType[NodeType["Comment"] = 21] = "Comment";
NodeType[NodeType["Placeholder"] = 22] = "Placeholder";
NodeType[NodeType["Scriptlet"] = 23] = "Scriptlet";
NodeType[NodeType["Import"] = 24] = "Import";
NodeType[NodeType["Export"] = 25] = "Export";
NodeType[NodeType["Class"] = 26] = "Class";
NodeType[NodeType["Style"] = 27] = "Style";
NodeType[NodeType["Static"] = 28] = "Static";
return NodeType;
}({});
function parse(code, filename = "index.marko") {
const builder = new Builder(code);
const parser = (0, htmljs_parser.createParser)(builder);
parser.parse(code);
const program = builder.end();
return {
read: parser.read,
locationAt: parser.locationAt,
positionAt: parser.positionAt,
filename,
program,
code
};
}
var Builder = class {
#code;
#program;
#openTagStart;
#parentNode;
#staticNode;
#attrNode;
constructor(code) {
this.#code = code;
this.#program = this.#parentNode = {
type: NodeType.Program,
parent: void 0,
static: [],
body: [],
start: 0,
end: code.length
};
}
end() {
return this.#program;
}
onText(range) {
pushBody(this.#parentNode, {
type: NodeType.Text,
parent: this.#parentNode,
start: range.start,
end: range.end
});
}
onCDATA(range) {
pushBody(this.#parentNode, {
type: NodeType.CDATA,
parent: this.#parentNode,
value: range.value,
start: range.start,
end: range.end
});
}
onDoctype(range) {
pushBody(this.#parentNode, {
type: NodeType.Doctype,
parent: this.#parentNode,
value: range.value,
start: range.start,
end: range.end
});
}
onDeclaration(range) {
pushBody(this.#parentNode, {
type: NodeType.Declaration,
parent: this.#parentNode,
value: range.value,
start: range.start,
end: range.end
});
}
onComment(range) {
pushBody(this.#parentNode, {
type: NodeType.Comment,
parent: this.#parentNode,
block: this.#code.charAt(range.start + 1) !== "/",
value: range.value,
start: range.start,
end: range.end
});
}
onPlaceholder(range) {
pushBody(this.#parentNode, {
type: NodeType.Placeholder,
parent: this.#parentNode,
value: range.value,
escape: range.escape,
start: range.start,
end: range.end
});
}
onScriptlet(range) {
pushBody(this.#parentNode, {
type: NodeType.Scriptlet,
parent: this.#parentNode,
value: range.value,
block: range.block,
start: range.start,
end: range.end
});
}
onOpenTagStart(range) {
this.#openTagStart = range;
}
onOpenTagName(range) {
let concise = true;
let start = range.start;
let type = NodeType.Tag;
let bodyType = htmljs_parser.TagType.html;
let nameText = void 0;
if (this.#openTagStart) {
concise = false;
start = this.#openTagStart.start;
this.#openTagStart = void 0;
}
if (!range.expressions.length) switch (nameText = this.#code.slice(range.start, range.end) || "div") {
case "style": {
styleBlockReg.lastIndex = range.end;
const styleBlockMatch = styleBlockReg.exec(this.#code);
if (styleBlockMatch) {
const [{ length }, ext] = styleBlockMatch;
this.#program.static.push(this.#staticNode = {
type: NodeType.Style,
parent: this.#program,
ext: ext || void 0,
value: {
start: range.end + length,
end: UNFINISHED
},
start: range.start,
end: UNFINISHED
});
return htmljs_parser.TagType.statement;
} else {
bodyType = htmljs_parser.TagType.text;
break;
}
}
case "class":
this.#program.static.push(this.#staticNode = {
type: NodeType.Class,
parent: this.#program,
start: range.start,
end: UNFINISHED
});
return htmljs_parser.TagType.statement;
case "export":
this.#program.static.push(this.#staticNode = {
type: NodeType.Export,
parent: this.#program,
start: range.start,
end: UNFINISHED
});
return htmljs_parser.TagType.statement;
case "import":
this.#program.static.push(this.#staticNode = {
type: NodeType.Import,
parent: this.#program,
start: range.start,
end: UNFINISHED
});
return htmljs_parser.TagType.statement;
case "server":
case "client":
case "static":
this.#program.static.push(this.#staticNode = {
type: NodeType.Static,
parent: this.#program,
target: nameText,
start: range.start,
end: UNFINISHED
});
return htmljs_parser.TagType.statement;
case "area":
case "base":
case "br":
case "col":
case "embed":
case "hr":
case "img":
case "input":
case "link":
case "meta":
case "param":
case "source":
case "track":
case "wbr":
case "const":
case "debug":
case "id":
case "let":
case "lifecycle":
case "log":
case "return":
bodyType = htmljs_parser.TagType.void;
break;
case "html-comment":
case "html-script":
case "html-style":
case "script":
case "textarea":
bodyType = htmljs_parser.TagType.text;
break;
default:
if (nameText[0] === "@") type = NodeType.AttrTag;
break;
}
const parent = this.#parentNode;
const end = UNFINISHED;
const name = {
type: NodeType.OpenTagName,
parent: void 0,
quasis: range.quasis,
expressions: range.expressions,
start: range.start,
end: range.end
};
const tag = this.#parentNode = name.parent = {
type,
parent,
owner: void 0,
concise,
selfClosed: false,
hasAttrTags: false,
open: {
start,
end
},
nameText,
name,
var: void 0,
args: void 0,
params: void 0,
shorthandId: void 0,
shorthandClassNames: void 0,
typeArgs: void 0,
typeParams: void 0,
attrs: void 0,
bodyType,
body: void 0,
close: void 0,
start,
end
};
if (tag.type === NodeType.AttrTag) {
let parentTag = parent;
let nameText = tag.nameText.slice(1);
while (parentTag.type === NodeType.Tag && isControlFlowTag(parentTag)) {
parentTag.hasAttrTags = true;
parentTag = parentTag.parent;
}
switch (parentTag.type) {
case NodeType.AttrTag:
tag.owner = parentTag.owner;
parentTag.hasAttrTags = true;
nameText = `${parentTag.nameText}:${nameText}`;
break;
case NodeType.Tag:
tag.owner = parentTag;
parentTag.hasAttrTags = true;
nameText = `${parentTag.nameText || "*"}:${nameText}`;
break;
}
tag.nameText = nameText;
}
pushBody(parent, tag);
this.#openTagStart = void 0;
return bodyType;
}
onTagShorthandId(range) {
const parent = this.#parentNode;
parent.shorthandId = {
type: NodeType.ShorthandId,
parent,
quasis: range.quasis,
expressions: range.expressions,
start: range.start,
end: range.end
};
}
onTagShorthandClass(range) {
const parent = this.#parentNode;
const shorthandClassName = {
type: NodeType.ShorthandClassName,
parent,
quasis: range.quasis,
expressions: range.expressions,
start: range.start,
end: range.end
};
if (parent.shorthandClassNames) parent.shorthandClassNames.push(shorthandClassName);
else parent.shorthandClassNames = [shorthandClassName];
}
onTagTypeArgs(range) {
const parent = this.#parentNode;
parent.typeArgs = {
type: NodeType.TagTypeArgs,
parent,
value: range.value,
start: range.start,
end: range.end
};
}
onTagTypeParams(range) {
const parent = this.#parentNode;
parent.typeParams = {
type: NodeType.TagTypeParams,
parent,
value: range.value,
start: range.start,
end: range.end
};
}
onTagVar(range) {
const parent = this.#parentNode;
parent.var = {
type: NodeType.TagVar,
parent,
value: range.value,
start: range.start,
end: range.end
};
}
onTagParams(range) {
const parent = this.#parentNode;
parent.params = {
type: NodeType.TagParams,
parent,
value: range.value,
start: range.start,
end: range.end
};
}
onTagArgs(range) {
const parent = this.#parentNode;
parent.args = {
type: NodeType.TagArgs,
parent,
value: range.value,
start: range.start,
end: range.end
};
}
onAttrName(range) {
const parent = this.#parentNode;
const name = {
type: NodeType.AttrName,
parent: void 0,
start: range.start,
end: range.end
};
pushAttr(parent, this.#attrNode = name.parent = {
type: NodeType.AttrNamed,
parent,
name,
value: void 0,
args: void 0,
start: range.start,
end: range.end
});
}
onAttrArgs(range) {
const parent = this.#attrNode;
parent.args = {
type: NodeType.AttrArgs,
parent,
value: range.value,
start: range.start,
end: range.end
};
parent.end = range.end;
}
onAttrValue(range) {
const parent = this.#attrNode;
parent.value = {
type: NodeType.AttrValue,
parent,
value: range.value,
bound: range.bound,
start: range.start,
end: range.end
};
parent.end = range.end;
}
onAttrMethod(range) {
const parent = this.#attrNode;
parent.value = {
type: NodeType.AttrMethod,
parent,
typeParams: range.typeParams,
params: range.params,
body: range.body,
start: range.start,
end: range.end
};
parent.end = range.end;
}
onAttrSpread(range) {
const parent = this.#parentNode;
pushAttr(parent, {
type: NodeType.AttrSpread,
parent,
value: range.value,
start: range.start,
end: range.end
});
}
onOpenTagEnd(range) {
if (this.#staticNode) {
if (this.#staticNode.type === NodeType.Style) this.#staticNode.value.end = range.end - 1;
this.#staticNode.end = range.end;
this.#staticNode = void 0;
} else {
this.#attrNode = void 0;
const tag = this.#parentNode;
tag.open.end = range.end;
if (range.selfClosed || tag.bodyType === htmljs_parser.TagType.void) {
this.#parentNode = tag.parent;
tag.end = range.end;
tag.selfClosed = range.selfClosed;
}
}
}
onCloseTagStart(range) {
this.#parentNode.close = {
start: range.start,
end: UNFINISHED
};
}
onCloseTagEnd(range) {
const parent = this.#parentNode;
if (hasCloseTag(parent)) parent.close.end = range.end;
parent.end = range.end;
this.#parentNode = parent.parent;
}
};
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 __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|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);
function pushBody(parent, node) {
if (parent.body) parent.body.push(node);
else parent.body = [node];
}
// 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 pushAttr(parent, node) {
if (parent.attrs) parent.attrs.push(node);
else parent.attrs = [node];
}
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 hasCloseTag(parent) {
return parent.close !== void 0;
}
function isInlineComment(node, opts) {
return node.type === "MarkoComment" && getCommentType(node, opts) !== "/";
/**
* Used to check if a node should be ignored as the parent of an attribute tag.
* When control flow is the parent of an attribute tag, we add the attribute tag to
* the closest non control flow ancestor attrs instead.
*/
function isControlFlowTag(node) {
switch (node.nameText) {
case "if":
case "else":
case "else-if":
case "for":
case "while": return true;
default: return false;
}
}
function isText(node) {
return node.type === "MarkoText" || node.type === "MarkoPlaceholder";
function read(range, opts) {
return opts._markoParsed.read(range);
}
// 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;
const placeholderReg = /MARKO_(\d+)_/g;
const { mapDoc } = prettier.doc.utils;
async function getFormattedBody(tag, parser, toDoc, print, opts) {
let pid = 0;
let code = "";
let placeholders;
tag.each((child) => {
if (child.node.type === NodeType.Placeholder) {
code += `MARKO_${pid++}_`;
(placeholders ||= []).push(print(child));
} else code += read(child.node, opts);
}, "body");
const doc = parser ? await toDoc(code, { parser }) : code;
return !placeholders ? doc : mapDoc(doc, (cur) => {
if (typeof cur === "string") {
let match = placeholderReg.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 = placeholderReg.exec(cur));
if (index !== cur.length) replacementDocs.push(cur.slice(index));
if (replacementDocs.length === 1) return replacementDocs[0];
return replacementDocs;
}
}
return cur;
});
}
// 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;
function getParserFromExt(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";
default: 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 "";
function hasTagParser(tag) {
switch (tag.nameText) {
case "script":
case "html-script":
case "style":
case "html-style": return true;
default: return false;
}
}
// 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;
function getTagParser(tag, opts) {
switch (tag.body && tag.nameText) {
case "script":
case "html-script": return getScriptTagParser(tag, opts);
case "style": return getStyleTagParser(tag, opts);
case "html-style": return "css";
}
}
// 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 getScriptTagParser(tag, opts) {
if (tag.attrs?.length) {
for (const attr of tag.attrs) if (attr.type === NodeType.AttrNamed && attr.value?.type === NodeType.AttrValue && read(attr.name, opts) === "type") {
const { code } = opts._markoParsed;
const value = attr.value.value;
const start = code.charAt(value.start);
switch ((start === "\"" || start === "'") && start === code.charAt(value.end - 1) ? code.slice(value.start + 1, value.end - 1) : "") {
case "module":
case "text/javascript":
case "application/javascript": return "babel-ts";
case "importmap":
case "speculationrules":
case "application/json": return "json";
default: return false;
}
}
}
return "babel-ts";
}
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;
function getStyleTagParser(tag, opts) {
return getParserFromExt(tag.shorthandClassNames && read(tag.shorthandClassNames[tag.shorthandClassNames.length - 1], opts) || ".css");
}
// 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;
}
const b$3 = prettier.doc.builders;
const singleQuoteSpace = "${' '}";
const doubleQuoteSpace = "${\" \"}";
const singleQuoteSpaceIfBreak = b$3.ifBreak([singleQuoteSpace, b$3.line], " ");
const doubleQuoteSpaceIfBreak = b$3.ifBreak([doubleQuoteSpace, b$3.line], " ");
function ensureVisibleSpace(parts, opts) {
if (parts[0] === b$3.line) parts[0] = getVisibleSpace(opts);
if (parts[parts.length - 1] === b$3.line) parts[parts.length - 1] = getVisibleSpace(opts);
}
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);
function ensureVisibleTrailingSpace(parts, opts) {
const last = parts.length - 1;
if (typeof parts[last] === "string" && /[ \t]$/.test(parts[last])) parts[last] = parts[last].slice(0, -1) + getVisibleSpace(opts);
}
// src/utils/get-original-code.ts
var import_babel = require("@marko/compiler/internal/babel");
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 (0, import_babel.generator)(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));
function ensureVisibleSpaceBetweenTags(parts, opts) {
const last = parts.length - 1;
if (last > 0 && parts[last] === b$3.line) {
if (typeof parts[last - 1] !== "string") parts[last] = opts.singleQuote ? singleQuoteSpaceIfBreak : doubleQuoteSpaceIfBreak;
}
}
// 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"]
}
function getVisibleSpace(opts) {
return opts.singleQuote ? singleQuoteSpace : doubleQuoteSpace;
}
function isVisibleSpace(code) {
switch (code) {
case singleQuoteSpace:
case doubleQuoteSpace: return true;
default: return false;
}
}
const DocCache = /* @__PURE__ */ new WeakMap();
function printDoc(doc) {
switch (typeof doc) {
case "string": return doc;
case "object": if (doc !== null) {
let cached = DocCache.get(doc);
if (cached !== void 0) return cached;
if (Array.isArray(doc)) {
cached = "";
for (const item of doc) cached += printDoc(item);
} else switch (doc.type) {
case "align":
cached = `\n${printDoc(doc.contents)}\n`;
break;
case "indent":
cached = ` ${printDoc(doc.contents)} `;
break;
case "break-parent":
case "cursor":
case "line-suffix-boundary":
case "trim":
cached = "";
break;
case "fill":
cached = ` ${printDoc(doc.parts)} `;
break;
case "group":
cached = printDoc(doc.contents) + printDoc(doc.expandedStates);
break;
case "if-break":
cached = printDoc(doc.flatContents) + printDoc(doc.breakContents);
break;
case "indent-if-break":
cached = " ";
break;
case "label":
case "line-suffix":
cached = printDoc(doc.contents);
break;
default:
cached = "\n";
break;
}
DocCache.set(doc, cached);
return cached;
}
}
return "";
}
const { builders: b$2 } = prettier.doc;
function withBlockIfNeeded(doc) {
if ((0, htmljs_parser.isValidStatement)(printDoc(doc).trim()) !== htmljs_parser.Validity.invalid) return doc;
return b$2.group([
b$2.ifBreak("{"),
b$2.indent([b$2.softline, doc]),
b$2.softline,
b$2.ifBreak("}")
]);
}
const { builders: b$1 } = prettier.doc;
function withParensIfNeeded(doc, concise) {
switch ((0, htmljs_parser.isValidAttrValue)(printDoc(doc).trim(), concise)) {
case htmljs_parser.Validity.enclosed: return doc;
case htmljs_parser.Validity.valid: return b$1.group([
b$1.ifBreak("("),
b$1.indent([b$1.softline, doc]),
b$1.softline,
b$1.ifBreak(")")
]);
default: return b$1.group([
b$1.indent([
"(",
b$1.softline,
doc
]),
b$1.softline,
")"
]);
}
}
const b = prettier.doc.builders;
const traverseDoc = prettier.doc.utils.traverseDoc;
const stmtParse = { parser: "babel-ts" };
const exprParse = { parser: "__ts_expression" };
const noVisitorKeys = [];
const tagVisitorKeys = [
"name",
"shorthandId",
"shorthandClassNames",
"var",
"args",
"typeArgs",
"params",
"typeParams",
"attrs",
"body"
];
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."
}
const visitorKeys = {
[NodeType.Tag]: tagVisitorKeys,
[NodeType.AttrTag]: tagVisitorKeys,
[NodeType.Program]: ["static", "body"],
[NodeType.AttrNamed]: ["args", "value"]
};
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;
}
}
const languages = [{
name: "marko",
aceMode: "text",
parsers: ["marko"],
aliases: ["markojs"],
tmScope: "text.marko",
codemirrorMode: "htmlmixed",
vscodeLanguageIds: ["marko"],
linguistLanguageId: 932782397,
codemirrorMimeType: "text/html",
extensions: [".marko"]
}];
const 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."
}
]
} };
const parsers = { marko: {
astFormat: "marko-ast",
parse(text, opts) {
const { program } = opts._markoParsed = parse(text, opts.filepath);
if (opts.markoSyntax === "auto") {
opts.markoSyntax = "html";
for (const child of program.body) if (child.type === NodeType.Tag) {
if (child.concise) opts.markoSyntax = "concise";
break;
}
}
return program;
},
locStart(node) {
return node.start;
},
locEnd(node) {
return node.end;
}
} };
const printers = { "marko-ast": {
print(path, opts, print) {
const { node } = path;
switch (node.type) {
case NodeType.AttrArgs:
case NodeType.AttrMethod:
case NodeType.AttrNamed:
case NodeType.AttrSpread:
case NodeType.Class:
case NodeType.Export:
case NodeType.Import:
case NodeType.OpenTagName:
case NodeType.Placeholder:
case NodeType.Scriptlet:
case NodeType.ShorthandClassName:
case NodeType.ShorthandId:
case NodeType.Static:
case NodeType.Style:
case NodeType.TagArgs:
case NodeType.TagParams:
case NodeType.TagTypeArgs:
case NodeType.TagTypeParams:
case NodeType.TagVar: return printExact(path, opts, print);
case NodeType.CDATA: return printCDATA(path, opts, print);
case NodeType.Comment: return printComment(path, opts, print);
case NodeType.Doctype: return printDoctype(path, opts, print);
case NodeType.Declaration: return printDeclaration(path, opts, print);
case NodeType.Program: return printProgram(path, opts, print);
case NodeType.Tag:
case NodeType.AttrTag: return printTag(path, opts, print);
case NodeType.Text: return printText(path, opts, print);
default: throw new Error(`Unknown node type in Marko template: ${NodeType[node.type] || node.type}`);
}
},
embed(path, opts) {
switch (path.node?.type) {
case NodeType.AttrNamed: return embedAttrNamed;
case NodeType.AttrSpread: return embedAttrSpread;
case NodeType.Class: return embedClass;
case NodeType.Export: return embedExport;
case NodeType.Import: return embedImport;
case NodeType.OpenTagName: return embedOpenTagName;
case NodeType.Placeholder: return embedPlaceholder;
case NodeType.Scriptlet: return embedScriptlet;
case NodeType.ShorthandClassName: return embedShorthandClassName;
case NodeType.ShorthandId: return embedShorthandId;
case NodeType.Static: return embedStatic;
case NodeType.Style: return embedStyle;
case NodeType.Tag: return embedTag(path, opts);
case NodeType.TagArgs: return embedTagArgs;
case NodeType.TagParams: return embedTagParams;
case NodeType.TagTypeArgs: return embedTagTypeArgs;
case NodeType.TagTypeParams: return embedTagTypeParams;
case NodeType.TagVar: return embedTagVar;
}
return null;
},
getVisitorKeys(node) {
return visitorKeys[node.type] || noVisitorKeys;
}
} };
const printProgram = (path, opts, print) => {
const body = printBody(path, opts, print);
const lastStatic = path.node.static.length - (body ? 0 : 1);
let programDoc = path.map((child, i) => i !== lastStatic && hasExplicitLine(child, opts) ? [child.call(print), b.hardline] : child.call(print), "static");
if (body) if (body.inline) programDoc.push(wrapConciseText(body.content));
else programDoc = [...programDoc, ...body.content];
return [b.join(b.hardline, programDoc), b.hardline];
};
var printers = {
"marko-ast": {
print(path, opts, print) {
var _a, _b, _c, _d, _e, _f;
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 bodyDocs = [];
if (hasAttrTags) {
tagPath.each((attrTag) => {
bodyDocs.push(print(attrTag));
if (opts.markoSyntax === "html") {
bodyDocs.push(b5.hardline);
}
}, "attributeTags");
if (!tagPath.node.body.body.length && opts.markoSyntax === "html") {
bodyDocs.pop();
}
}
let textOnly = !hasAttrTags;
let textDocs = [];
let leadingLine = false;
tagPath.each(
(childPath) => {
var _a2;
const childNode = childPath.getNode();
const isText2 = isTextLike(childNode, node, opts);
if (opts.markoSyntax === "html" && !preserveSpace) {
const { type } = childNode;
const prevType = (_a2 = childPath.previous) == null ? void 0 : _a2.type;
if (prevType === "MarkoScriptlet" || prevType === "MarkoComment" && getCommentType(childPath.previous, opts) === "/" || type === "MarkoTag" && prevType === "MarkoTag") {
textDocs.push(b5.hardline);
} else if (type === "MarkoTag" && prevType === "MarkoText" && /\S\s+$/.test(childPath.previous.value)) {
leadingLine = true;
}
}
if (isText2) {
if (preserveSpace && opts.markoSyntax === "concise") {
bodyDocs.push(
b5.group([printDashes(node), " ", print(childPath)])
);
} else {
textDocs.push(print(childPath));
}
if (textOnly || !childPath.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(
leadingLine ? b5.group([b5.softline, print(childPath)]) : print(childPath)
);
leadingLine = false;
}
} else {
bodyDocs.push(print(childPath));
}
},
"body",
"body"
);
if (opts.markoSyntax === "html") {
const joinSep = preserveSpace ? "" : textOnly ? b5.softline : b5.hardline;
const wrapSep = !preserveSpace && (node.body.body.some(
(child) => !isTextLike(child, node, opts)
) || node.loc && opts.originalText[locToPos(node.loc.start, opts)] === "<" && ((_c = node.body.body[0]) == null ? void 0 : _c.loc) && node.loc.start.line < node.body.body[0].loc.start.line) ? b5.hardline : joinSep;
doc4.push(
">",
b5.indent([
wrapSep,
textOnly ? b5.group(textDocs) : b5.fill(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 (canInlineMethod(value)) {
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)) && (isConcise || ((_e = path.parent) == null ? void 0 : _e.type) === "Program" || path.isFirst)) {
prefix = opts.singleQuote ? "${' '}" : '${" "}';
value = value.slice(1);
}
const last = value.length - 1;
if (value[last] === " " && !(path.next && isTextLike(path.next, parent, opts)) && (isConcise || ((_f = path.parent) == null ? void 0 : _f.type) === "Program" || path.isLast)) {
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) => {
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 = !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 codeStartOffset = startContent.length;
const codeEndOffset = node.rawValue.lastIndexOf("}");
const code = rawValue.slice(codeStartOffset, 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" && canInlineMethod(node)) {
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;
}
}
const printDoctype = (path, opts) => {
return `<!${read(path.node.value, opts).replace(/\s+/g, " ").trim()}>`;
};
function setCompiler(compiler, config) {
currentCompiler = compiler;
setConfig(config);
const printDeclaration = (path, opts) => {
return `<?${read(path.node.value, opts).trim()}?>`;
};
const printCDATA = (path, opts) => {
return `<![CDATA[${read(path.node.value, opts)}]]>`;
};
const printComment = (path, opts) => {
const { node } = path;
const code = read(node, opts);
if (node.block) {
if (code.includes("\n")) {
const lines = code.split("\n");
const len = lines.length;
let indent = Infinity;
for (let i = 1; i < len; i++) {
const match = lines[i].match(/^(\s+)/);
if (match) indent = Math.min(indent, match[1].length);
else {
indent = 0;
break;
}
}
const parts = [lines[0]];
for (let i = 1; i < len; i++) parts.push(b.hardline, indent ? lines[i].slice(indent) : lines[i]);
return parts;
}
return code;
}
return b.lineSuffix(code);
};
const printTag = ((path, opts, print, body = printBody(path, opts, print)) => {
return (isConcise(opts) ? printConciseTag : printHTMLTag)(path, opts, print, body);
});
const printHTMLTag = ((path, opts, print, body) => {
const { node } = path;
const openTagDoc = ["<", printTagBeforeAttrs(path, opts, print)];
if (node.attrs) {
const hasDefault = isDefaultAttr(node.attrs[0]);
let attrsDocs = path.map(print, "attrs");
if (hasDefault) {
openTagDoc.push(attrsDocs[0]);
attrsDocs = attrsDocs.slice(1);
}
if (attrsDocs.length) if (attrsDocs.length === 1 && !(hasDefault || node.params || node.args)) openTagDoc.push(" ", attrsDocs[0]);
else openTagDoc.push(b.indent([b.line, b.join(b.line, attrsDocs)]), b.softline);
}
openTagDoc.push(body || node.bodyType === htmljs_parser.TagType.void ? ">" : "/>");
if (body) {
const bodyLine = body.inline ? b.softline : b.hardline;
const closeTagDoc = `</${node.name.expressions.length ? "" : read(node.name, opts)}>`;
if (body.preserve) return b.group([
b.group(openTagDoc),
body.content,
closeTagDoc
]);
return b.group([
b.group(openTagDoc),
b.indent([bodyLine, body.inline ? body.content : b.join(bodyLine, body.content)]),
bodyLine,
closeTagDoc
]);
}
return b.group(openTagDoc);
});
const printConciseTag = ((path, opts, print, body) => {
const { node } = path;
const tagDoc = [printTagBeforeAttrs(path, opts, print)];
if (node.attrs) {
const hasDefault = isDefaultAttr(node.attrs[0]);
let attrsDocs = path.map(print, "attrs");
if (hasDefault) {
tagDoc.push(attrsDocs[0]);
attrsDocs = attrsDocs.slice(1);
}
if (attrsDocs.length) if (attrsDocs.length === 1 && !(hasDefault || node.params || node.args)) tagDoc.push(" ", attrsDocs[0]);
else {
const attrsDoc = [];
for (const attrDoc of attrsDocs) attrsDoc.push(b.line, b.ifBreak(","), attrDoc);
tagDoc.push(b.group(b.indent(attrsDoc)));
}
}
if (body) tagDoc.push(b.group(body.inline ? body.preserve ? b.indent([b.line, wrapConciseText(body.content)]) : [" --", b.indent([b.line, body.content])] : b.indent([b.hardline, b.join(b.hardline, body.content)])));
return b.group(tagDoc);
});
const printTagBeforeAttrs = (path, _opts, print) => {
const { node } = path;
const name = path.call(print, "name");
const doc = [name];
if (pathHas(path, "typeArgs")) doc.push(path.call(print, "typeArgs"));
if (pathHas(path, "shorthandId")) doc.push(path.call(print, "shorthandId"));
if (pathHas(path, "shorthandClassNames")) doc.push(path.map(print, "shorthandClassNames"));
if (pathHas(path, "args")) doc.push(path.call(print, "args"));
if (pathHas(path, "var")) doc.push(path.call(print, "var"));
if (pathHas(path, "params")) {
if (pathHas(path, "typeParams")) {
if (!(node.typeArgs || node.args || node.var)) doc.push(" ");
doc.push(path.call(print, "typeParams"));
}
doc.push(path.call(print, "params"));
}
return doc.length === 1 ? name : doc;
};
const printBody = (path, opts, print) => {
const { node } = path;
if (!node.body) return;
const concise = !node.parent || isConcise(opts);
const isInline = concise ? isTextLike : isInlineHTML;
const preserve = hasPreservedText(node);
let content;
let inline;
let inlineIndex = -1;
if (preserve) {
path.each((child) => {
const childDoc = child.call(print);
if (!childDoc) return;
content ||= [];
if (isInline(child.node)) {
if (!inline) {
inline = [];
inlineIndex = content.push(inline) - 1;
}
if (child.node.type === NodeType.Text && typeof childDoc === "string") {
const nl = isConcise(opts) ? b.hardline : b.literalline;
let lineStart = 0;
for (let i = 0; i < childDoc.length; i++) if (childDoc.charAt(i) === "\n") {
if (lineStart !== i) inline.push(childDoc.slice(lineStart, i));
inline.push(nl);
lineStart = i + 1;
}
if (!lineStart) inline.push(childDoc);
else if (lineStart !== childDoc.length) inline.push(childDoc.slice(lineStart));
} else inline.push(childDoc);
} else {
if (inline) {
if (concise) {
ensureVisibleTrailingSpace(inline, opts);
content[inlineIndex] = wrapConciseText(content[inlineIndex]);
}
inline = void 0;
}
content.push(childDoc);
}
}, "body");
if (inline && concise) ensureVisibleTrailingSpace(inline, opts);
} else {
let isInlineTag = false;
let isExplicitLine = false;
path.each((child) => {
const wasInlineTag = isInlineTag;
const inlineChild = isInline(child.node);
let childDoc = child.call(print);
if (child.node.type === NodeType.Text && typeof childDoc === "string") childDoc = trimText(childDoc, child);
if (!childDoc) return;
isInlineTag = false;
content ||= [];
if (isExplicitLine) {
const last = content.length - 1;
isExplicitLine = false;
content[last] = [content[last], b.hardline];
}
if (inlineChild) {
if (!inline) {
inline = [];
inlineIndex = content.push(b.fill(inline)) - 1;
}
switch (child.node.type) {
case NodeType.Text:
if (typeof childDoc === "string") {
const len = childDoc.length;
let start = 0;
for (let i = 0; i < len; i++) if (childDoc.charAt(i) === " ") {
if (start !== i) inline.push(childDoc.slice(start, i));
if (i || !endsWithLine(inline)) inline.push(b.line);
start = i + 1;
}
if (start === len) return;
if (start) childDoc = childDoc.slice(start);
}
break;
case NodeType.Placeholder:
if (typeof childDoc === "string" && isVisibleSpace(childDoc)) {
if (endsWithLine(inline)) {
const last = inline.length - 1;
if (inline[last] === b.softline) inline[last] = b.line;
return;
}
childDoc = b.line;
}
break;
case NodeType.Tag:
isInlineTag = true;
ensureVisibleSpaceBetweenTags(inline, opts);
if (wasInlineTag) inline.push(b.softline);
break;
}
inline.push(childDoc);
} else {
isExplicitLine = !child.isLast && hasExplicitLine(child, opts);
if (inline) {
ensureVisibleSpace(inline, opts);
inline = void 0;
if (concise) content[inlineIndex] = wrapConciseText(content[inlineIndex]);
}
content.push(childDoc);
}
}, "body");
}
if (content) {
if (inline) {
ensureVisibleSpace(inline, opts);
if (inlineIndex === 0) return {
inline: true,
preserve,
content: content[inlineIndex]
};
if (concise) content[inlineIndex] = wrapConciseText(content[inlineIndex]);
}
return {
inline: false,
preserve,
content
};
}
};
const printText = (path, opts) => {
const text = read(path.node, opts).replace(/\\/g, "\\\\");
if (/^\$!?{/.test(text)) return "\\" + text;
return text;
};
const printExact = (path, opts) => read(path.node, opts);
const embedClass = (toDoc, _print, path, opts) => toDoc(read(path.node, opts), exprParse);
const embedImport = (toDoc, _print, path, opts) => toDoc(read(path.node, opts), stmtParse);
const embedExport = (toDoc, _print, path, opts) => toDoc(read(path.node, opts), stmtParse);
const embedStyle = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).trim();
const parser = getParserFromExt(node.ext?.slice(node.ext.lastIndexOf(".")) || ".css");
if (parser) return b.group([
`style${node.ext || ""} {`,
b.indent([b.line, await toDoc(code, { parser })]),
b.line,
"}"
]);
};
const embedStatic = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = opts._markoParsed.code.slice(node.start + node.target.length + 1, node.end).replace(/^\s*\{([\s\S]*)\}\s*$/, "$1").trim();
return code ? [`${node.target} `, withBlockIfNeeded(await toDoc(code, stmtParse))] : [];
};
const embedScriptlet = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).replace(/^\s*\{([\s\S]*)\}\s*$/, "$1").trim();
return code ? [
b.breakParent,
"$ ",
withBlockIfNeeded(await toDoc(code, stmtParse))
] : [];
};
const embedOpenTagName = async (toDoc, _print, path, opts) => embedTemplate(toDoc, _print, path, opts);
const embedPlaceholder = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts);
if (code === "\" \"" || code === "' '") return getVisibleSpace(opts);
return b.group([
"${",
b.indent([b.softline, await toDoc(code, exprParse)]),
b.softline,
"}"
]);
};
const embedTagArgs = (toDoc, _print, path, opts) => {
return argsToDoc(path.node, opts, toDoc);
};
const embedAttrNamed = async (toDoc, _print, path, opts) => {
const node = path.node;
const name = read(node.name, opts);
if (!(node.args || node.value)) return name;
const attrDoc = [name];
if (node.args) {
const argsDoc = await argsToDoc(node.args, opts, toDoc);
if (argsDoc) attrDoc.push(argsDoc);
else return unexpectedDoc(opts, node);
}
if (node.value) if (node.value.type === NodeType.AttrMethod) {
const attrMethodDoc = await toDoc(`function${read(node.value, opts)}`, exprParse);
if (Array.isArray(attrMethodDoc) && attrMethodDoc.length && typeof attrMethodDoc[0] === "string") {
attrMethodDoc[0] = attrMethodDoc[0].replace(/^function\s*/, "");
attrDoc.push(attrMethodDoc);
} else return unexpectedDoc(opts, node);
} else attrDoc.push(node.value.bound ? ":=" : "=", withParensIfNeeded(await toDoc(read(node.value.value, opts), exprParse), isConcise(opts)));
return b.group(attrDoc);
};
const embedAttrSpread = async (toDoc, _print, path, opts) => {
const node = path.node;
return b.group(["...", withParensIfNeeded(await toDoc(read(node.value, opts), exprParse), isConcise(opts))]);
};
const embedShorthandId = async (toDoc, print, path, opts) => ["#", await embedTemplate(toDoc, print, path, opts)];
const embedShorthandClassName = async (toDoc, print, path, opts) => [".", await embedTemplate(toDoc, print, path, opts)];
const embedTag = (path, opts) => {
const tag = path.node;
const parser = getTagParser(tag, opts);
if (parser === void 0) return null;
return async (toDoc, print, path, opts) => printTag(path, opts, print, {
inline: true,
preserve: parser === false,
content: await getFormattedBody(path, parser, toDoc, print, opts)
});
};
const embedTagVar = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).trim();
if (code) {
let doc = await toDoc(`var ${code}=_`, stmtParse);
if (Array.isArray(doc) && doc.length === 1) doc = doc[0];
if (typeof doc === "object" && !Array.isArray(doc) && doc.type === "group") doc = doc.contents;
if (Array.isArray(doc) && doc.length > 1) {
const varPart = doc[1];
if (typeof varPart === "object" && "type" in varPart && varPart.type === "group" && Array.isArray(varPart.contents)) {
const varContents = varPart.contents;
for (let i = varContents.length; i--;) {
const item = varContents[i];
if (typeof item === "string") {
const match = /\s*=\s*$/.exec(item);
if (match) {
varContents[i] = item.slice(0, -match[0].length);
varContents.length = i + 1;
return ["/", varContents];
}
}
}
}
}
return unexpectedDoc(opts, node);
}
return [];
};
const embedTagTypeArgs = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).trim();
if (code) {
const doc = await toDoc(`_<${code}>`, exprParse);
if (typeof doc === "string") return doc.replace(/^_/, "");
if (Array.isArray(doc) && typeof doc[0] === "string") {
doc[0] = doc[0].replace(/^_/, "");
return doc;
}
return unexpectedDoc(opts, node);
}
return [];
};
const embedTagParams = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).trim();
if (code) {
const doc = await toDoc(`function _(${code}){}`, stmtParse);
if (Array.isArray(doc) && doc.length > 1) {
const paramsGroup = doc[1];
if (paramsGroup && typeof paramsGroup === "object" && "type" in paramsGroup && paramsGroup.type === "group" && Array.isArray(paramsGroup.contents)) {
const paramsContents = [...paramsGroup.contents];
const first = paramsContents[0];
const last = paramsContents[paramsContents.length - 1];
if (typeof first === "string" && typeof last === "string") {
paramsContents[0] = first.replace(/^\(/, "|");
paramsContents[paramsContents.length - 1] = last.replace(/\)$/, "|");
}
return b.group(paramsContents);
}
}
return unexpectedDoc(opts, node);
}
return [];
};
const embedTagTypeParams = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).trim();
if (code) {
const doc = await toDoc(`function _<${code}>(){}`, stmtParse);
if (Array.isArray(doc) && doc.length > 1) return doc[1];
return unexpectedDoc(opts, node);
}
return [];
};
const embedTemplate = async (toDoc, _print, path, opts) => {
const { expressions, quasis } = path.node;
const first = read(quasis[0], opts);
const len = expressions.length;
if (!len) return first;
const shorthandDoc = [first];
for (let i = 0; i < len; i++) {
const quasi = read(quasis[i + 1], opts);
const expr = read(expressions[i].value, opts);
shorthandDoc.push(b.group([
"${",
b.indent([b.softline, await toDoc(expr, exprParse)]),
b.softline,
"}"
]));
if (quasi) shorthandDoc.push(quasi);
}
return shorthandDoc;
};
async function argsToDoc(node, opts, toDoc) {
const code = read(node.value, opts).trim();
if (code) {
const doc = await toDoc(`_(${code})`, exprParse);
if (Array.isArray(doc) && doc.length && typeof doc[0] === "string") {
doc[0] = doc[0].replace(/^_/, "");
return doc;
}
return unexpectedDoc(opts, node);
}
return [];
}
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 wrapConciseText(doc) {
let maxDashes = 0;
traverseDoc(doc, (child) => {
if (typeof child === "string") {
let current = 0;
for (const char of child) if (char === "-") {
current++;
if (current > maxDashes) maxDashes = current;
} else current = 0;
}
});
const breakDashes = maxDashes > 1 ? "-".repeat(maxDashes + 1) : "--";
return b.group([
b.ifBreak(breakDashes, "--"),
b.line,
doc,
b.ifBreak([b.line, breakDashes])
]);
}
function printComments(comments) {
return comments.map(
(comment) => comment.type === "CommentBlock" ? `/*${comment.value}*/` : "//" + comment.value
);
function trimText(text, path) {
if (/^(?:\n\s*)?(?:\n\s*)?$/.test(text)) return "";
const siblings = path.siblings;
let trimmed = text;
let prev;
let next;
for (let i = path.index; --i >= 0;) {
const sibling = siblings[i];
if (sibling.type !== NodeType.Scriptlet && sibling.type !== NodeType.Comment) {
prev = sibling;
break;
}
}
for (let i = path.index; ++i < siblings.length;) {
const sibling = siblings[i];
if (sibling.type !== NodeType.Scriptlet && sibling.type !== NodeType.Comment) {
next = sibling;
break;
}
}
const parent = path.node.parent;
const isInline = !parent.parent || parent.concise ? isTextLike : isInlineHTML;
const trimStart = !(prev && isInline(prev));
const trimEnd = !(next && isInline(next));
if (trimStart) trimmed = trimmed.replace(/^\n\s*/, "");
if (trimEnd) trimmed = trimmed.replace(/\n\s*$/, "");
return trimmed.replace(/\s+/g, " ");
}
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 isTextLike(node) {
switch (node.type) {
case NodeType.Text:
case NodeType.Placeholder: return true;
case NodeType.Comment: return node.block;
default: return false;
}
}
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 isInlineHTML(node) {
switch (node.type) {
case NodeType.Text:
case NodeType.Placeholder: return true;
case NodeType.Comment: return node.block;
case NodeType.Tag: return !!node.nameText && /^(?:a(?:bbr|cronym)?|b(?:do|ig|r)?|cite|code|dfn|em|i(?:mg)?|kbd|label|map|object|output|q|samp|small|span|strong|sub|sup|time|tt|var)$/.test(node.nameText);
default: return false;
}
}
function preventTrailingCommaTagArgs(tagName) {
switch (tagName) {
case "if":
case "else-if":
case "while":
return true;
default:
return false;
}
function hasPreservedText(node) {
if (node.type === NodeType.Tag && hasTagParser(node)) return true;
let cur = node;
while (cur.type === NodeType.Tag) {
if (cur.nameText && /^(?:textarea|pre)$/.test(cur.nameText)) return true;
cur = cur.parent;
}
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 isDefaultAttr(node) {
if (node.type === NodeType.AttrNamed && node.value && node.name.start === node.name.end) return true;
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 isConcise(opts) {
return opts.markoSyntax === "concise";
}
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,
browserslistConfigFile: false,
parserOpts: {
allowUndeclaredExports: true,
allowAwaitOutsideFunction: true,
allowReturnOutsideFunction: true,
allowImportExportEverywhere: true,
plugins: ["exportDefaultFrom", "importAssertions"]
}
}
};
const explicitLineReg = /\S?\n\n/y;
function hasExplicitLine(path, opts) {
explicitLineReg.lastIndex = path.node.end - 1;
return explicitLineReg.test(opts._markoParsed.code);
}
function getScriptParser(tag) {
for (const attr of tag.attributes) {
if (attr.type === "MarkoAttribute" && attr.name === "type") {
switch (attr.value.type === "StringLiteral" ? attr.value.value : void 0) {
case "module":
case "text/javascript":
case "application/javascript":
return scriptParser;
case "importmap":
case "speculationrules":
case "application/json":
return "json";
default:
return false;
}
}
}
return scriptParser;
function endsWithLine(doc) {
switch (doc.length && doc[doc.length - 1]) {
case b.line:
case b.hardline:
case b.literalline:
case b.softline:
case b.hardlineWithoutBreakParent: return true;
default: return false;
}
}
function getTextParent(text) {
const parent = text.parent;
return parent.type === "Program" ? parent : text.getParentNode(1);
function pathHas(path, key) {
return !!path.node[key];
}
var minDashLookup = /* @__PURE__ */ new WeakMap();
function printDashes(parent) {
const dashes = minDashLookup.get(parent);
if (dashes === void 0) return "--";
minDashLookup.delete(parent);
return "-".repeat(dashes + 1);
function unexpectedDoc(opts, node) {
const parsed = opts._markoParsed;
const pos = parsed.positionAt(node.start);
console.warn(`Unable to format "${NodeType[node.type]}", please open an issue https://github.com/marko-js/prettier/issues.${opts.filepath ? `:\n at ${opts.filepath}:${pos.line + 1}:${pos.character + 1}` : ""}\n${parsed.read(node).replace(/(?:^|\n)(?!\n])/, opts.filepath ? "$& " : "$& ")}\n`);
}
function toPlaceholder(str, singleQuote) {
const quote = str.includes("\n") ? "`" : singleQuote ? "'" : '"';
let escaped = str.replace(/\\/g, "\\\\");
switch (quote) {
case "`":
escaped = escaped.replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
break;
case "'":
escaped = escaped.replace(/'/g, "\\'");
break;
default:
escaped = escaped.replace(/"/g, '\\"');
break;
}
return "${" + quote + escaped + quote + "}";
}
function isEmpty(node) {
return node.type === "EmptyStatement" && !node.leadingComments && !node.trailingComments;
}
function canInlineMethod(node) {
return node.type === "FunctionExpression" && !(node.id || node.async || node.generator);
}
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
languages,
options,
parsers,
printers,
setCompiler
});
exports.languages = languages;
exports.options = options;
exports.parsers = parsers;
exports.printers = printers;
+1330
-1514

@@ -1,1544 +0,1360 @@

// src/index.ts
import { resolve } from "path";
import { createRequire } from "module";
import {
doc as doc3
} from "prettier";
// src/constants.ts
var scriptParser = "babel-ts";
var expressionParser = "__ts_expression";
var enclosedNodeTypeReg = /^(?:Identifier|.*Literal|(?:Object|Array|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);
import "node:module";
import { doc } from "prettier";
import { TagType, TagType as TagType$1, Validity, createParser, isValidAttrValue, isValidStatement } from "htmljs-parser";
const styleBlockReg = /((?:\.[^\s\\/:*?"<>|({]+)*)\s*\{/y;
const UNFINISHED = Number.MAX_SAFE_INTEGER;
let NodeType = /* @__PURE__ */ function(NodeType) {
NodeType[NodeType["Program"] = 0] = "Program";
NodeType[NodeType["Tag"] = 1] = "Tag";
NodeType[NodeType["OpenTagName"] = 2] = "OpenTagName";
NodeType[NodeType["ShorthandId"] = 3] = "ShorthandId";
NodeType[NodeType["ShorthandClassName"] = 4] = "ShorthandClassName";
NodeType[NodeType["TagTypeArgs"] = 5] = "TagTypeArgs";
NodeType[NodeType["TagTypeParams"] = 6] = "TagTypeParams";
NodeType[NodeType["TagVar"] = 7] = "TagVar";
NodeType[NodeType["TagArgs"] = 8] = "TagArgs";
NodeType[NodeType["TagParams"] = 9] = "TagParams";
NodeType[NodeType["AttrNamed"] = 10] = "AttrNamed";
NodeType[NodeType["AttrName"] = 11] = "AttrName";
NodeType[NodeType["AttrArgs"] = 12] = "AttrArgs";
NodeType[NodeType["AttrValue"] = 13] = "AttrValue";
NodeType[NodeType["AttrMethod"] = 14] = "AttrMethod";
NodeType[NodeType["AttrSpread"] = 15] = "AttrSpread";
NodeType[NodeType["AttrTag"] = 16] = "AttrTag";
NodeType[NodeType["Text"] = 17] = "Text";
NodeType[NodeType["CDATA"] = 18] = "CDATA";
NodeType[NodeType["Doctype"] = 19] = "Doctype";
NodeType[NodeType["Declaration"] = 20] = "Declaration";
NodeType[NodeType["Comment"] = 21] = "Comment";
NodeType[NodeType["Placeholder"] = 22] = "Placeholder";
NodeType[NodeType["Scriptlet"] = 23] = "Scriptlet";
NodeType[NodeType["Import"] = 24] = "Import";
NodeType[NodeType["Export"] = 25] = "Export";
NodeType[NodeType["Class"] = 26] = "Class";
NodeType[NodeType["Style"] = 27] = "Style";
NodeType[NodeType["Static"] = 28] = "Static";
return NodeType;
}({});
function parse(code, filename = "index.marko") {
const builder = new Builder(code);
const parser = createParser(builder);
parser.parse(code);
const program = builder.end();
return {
read: parser.read,
locationAt: parser.locationAt,
positionAt: parser.positionAt,
filename,
program,
code
};
}
// 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;
var Builder = class {
#code;
#program;
#openTagStart;
#parentNode;
#staticNode;
#attrNode;
constructor(code) {
this.#code = code;
this.#program = this.#parentNode = {
type: NodeType.Program,
parent: void 0,
static: [],
body: [],
start: 0,
end: code.length
};
}
end() {
return this.#program;
}
onText(range) {
pushBody(this.#parentNode, {
type: NodeType.Text,
parent: this.#parentNode,
start: range.start,
end: range.end
});
}
onCDATA(range) {
pushBody(this.#parentNode, {
type: NodeType.CDATA,
parent: this.#parentNode,
value: range.value,
start: range.start,
end: range.end
});
}
onDoctype(range) {
pushBody(this.#parentNode, {
type: NodeType.Doctype,
parent: this.#parentNode,
value: range.value,
start: range.start,
end: range.end
});
}
onDeclaration(range) {
pushBody(this.#parentNode, {
type: NodeType.Declaration,
parent: this.#parentNode,
value: range.value,
start: range.start,
end: range.end
});
}
onComment(range) {
pushBody(this.#parentNode, {
type: NodeType.Comment,
parent: this.#parentNode,
block: this.#code.charAt(range.start + 1) !== "/",
value: range.value,
start: range.start,
end: range.end
});
}
onPlaceholder(range) {
pushBody(this.#parentNode, {
type: NodeType.Placeholder,
parent: this.#parentNode,
value: range.value,
escape: range.escape,
start: range.start,
end: range.end
});
}
onScriptlet(range) {
pushBody(this.#parentNode, {
type: NodeType.Scriptlet,
parent: this.#parentNode,
value: range.value,
block: range.block,
start: range.start,
end: range.end
});
}
onOpenTagStart(range) {
this.#openTagStart = range;
}
onOpenTagName(range) {
let concise = true;
let start = range.start;
let type = NodeType.Tag;
let bodyType = TagType.html;
let nameText = void 0;
if (this.#openTagStart) {
concise = false;
start = this.#openTagStart.start;
this.#openTagStart = void 0;
}
if (!range.expressions.length) switch (nameText = this.#code.slice(range.start, range.end) || "div") {
case "style": {
styleBlockReg.lastIndex = range.end;
const styleBlockMatch = styleBlockReg.exec(this.#code);
if (styleBlockMatch) {
const [{ length }, ext] = styleBlockMatch;
this.#program.static.push(this.#staticNode = {
type: NodeType.Style,
parent: this.#program,
ext: ext || void 0,
value: {
start: range.end + length,
end: UNFINISHED
},
start: range.start,
end: UNFINISHED
});
return TagType.statement;
} else {
bodyType = TagType.text;
break;
}
}
case "class":
this.#program.static.push(this.#staticNode = {
type: NodeType.Class,
parent: this.#program,
start: range.start,
end: UNFINISHED
});
return TagType.statement;
case "export":
this.#program.static.push(this.#staticNode = {
type: NodeType.Export,
parent: this.#program,
start: range.start,
end: UNFINISHED
});
return TagType.statement;
case "import":
this.#program.static.push(this.#staticNode = {
type: NodeType.Import,
parent: this.#program,
start: range.start,
end: UNFINISHED
});
return TagType.statement;
case "server":
case "client":
case "static":
this.#program.static.push(this.#staticNode = {
type: NodeType.Static,
parent: this.#program,
target: nameText,
start: range.start,
end: UNFINISHED
});
return TagType.statement;
case "area":
case "base":
case "br":
case "col":
case "embed":
case "hr":
case "img":
case "input":
case "link":
case "meta":
case "param":
case "source":
case "track":
case "wbr":
case "const":
case "debug":
case "id":
case "let":
case "lifecycle":
case "log":
case "return":
bodyType = TagType.void;
break;
case "html-comment":
case "html-script":
case "html-style":
case "script":
case "textarea":
bodyType = TagType.text;
break;
default:
if (nameText[0] === "@") type = NodeType.AttrTag;
break;
}
const parent = this.#parentNode;
const end = UNFINISHED;
const name = {
type: NodeType.OpenTagName,
parent: void 0,
quasis: range.quasis,
expressions: range.expressions,
start: range.start,
end: range.end
};
const tag = this.#parentNode = name.parent = {
type,
parent,
owner: void 0,
concise,
selfClosed: false,
hasAttrTags: false,
open: {
start,
end
},
nameText,
name,
var: void 0,
args: void 0,
params: void 0,
shorthandId: void 0,
shorthandClassNames: void 0,
typeArgs: void 0,
typeParams: void 0,
attrs: void 0,
bodyType,
body: void 0,
close: void 0,
start,
end
};
if (tag.type === NodeType.AttrTag) {
let parentTag = parent;
let nameText = tag.nameText.slice(1);
while (parentTag.type === NodeType.Tag && isControlFlowTag(parentTag)) {
parentTag.hasAttrTags = true;
parentTag = parentTag.parent;
}
switch (parentTag.type) {
case NodeType.AttrTag:
tag.owner = parentTag.owner;
parentTag.hasAttrTags = true;
nameText = `${parentTag.nameText}:${nameText}`;
break;
case NodeType.Tag:
tag.owner = parentTag;
parentTag.hasAttrTags = true;
nameText = `${parentTag.nameText || "*"}:${nameText}`;
break;
}
tag.nameText = nameText;
}
pushBody(parent, tag);
this.#openTagStart = void 0;
return bodyType;
}
onTagShorthandId(range) {
const parent = this.#parentNode;
parent.shorthandId = {
type: NodeType.ShorthandId,
parent,
quasis: range.quasis,
expressions: range.expressions,
start: range.start,
end: range.end
};
}
onTagShorthandClass(range) {
const parent = this.#parentNode;
const shorthandClassName = {
type: NodeType.ShorthandClassName,
parent,
quasis: range.quasis,
expressions: range.expressions,
start: range.start,
end: range.end
};
if (parent.shorthandClassNames) parent.shorthandClassNames.push(shorthandClassName);
else parent.shorthandClassNames = [shorthandClassName];
}
onTagTypeArgs(range) {
const parent = this.#parentNode;
parent.typeArgs = {
type: NodeType.TagTypeArgs,
parent,
value: range.value,
start: range.start,
end: range.end
};
}
onTagTypeParams(range) {
const parent = this.#parentNode;
parent.typeParams = {
type: NodeType.TagTypeParams,
parent,
value: range.value,
start: range.start,
end: range.end
};
}
onTagVar(range) {
const parent = this.#parentNode;
parent.var = {
type: NodeType.TagVar,
parent,
value: range.value,
start: range.start,
end: range.end
};
}
onTagParams(range) {
const parent = this.#parentNode;
parent.params = {
type: NodeType.TagParams,
parent,
value: range.value,
start: range.start,
end: range.end
};
}
onTagArgs(range) {
const parent = this.#parentNode;
parent.args = {
type: NodeType.TagArgs,
parent,
value: range.value,
start: range.start,
end: range.end
};
}
onAttrName(range) {
const parent = this.#parentNode;
const name = {
type: NodeType.AttrName,
parent: void 0,
start: range.start,
end: range.end
};
pushAttr(parent, this.#attrNode = name.parent = {
type: NodeType.AttrNamed,
parent,
name,
value: void 0,
args: void 0,
start: range.start,
end: range.end
});
}
onAttrArgs(range) {
const parent = this.#attrNode;
parent.args = {
type: NodeType.AttrArgs,
parent,
value: range.value,
start: range.start,
end: range.end
};
parent.end = range.end;
}
onAttrValue(range) {
const parent = this.#attrNode;
parent.value = {
type: NodeType.AttrValue,
parent,
value: range.value,
bound: range.bound,
start: range.start,
end: range.end
};
parent.end = range.end;
}
onAttrMethod(range) {
const parent = this.#attrNode;
parent.value = {
type: NodeType.AttrMethod,
parent,
typeParams: range.typeParams,
params: range.params,
body: range.body,
start: range.start,
end: range.end
};
parent.end = range.end;
}
onAttrSpread(range) {
const parent = this.#parentNode;
pushAttr(parent, {
type: NodeType.AttrSpread,
parent,
value: range.value,
start: range.start,
end: range.end
});
}
onOpenTagEnd(range) {
if (this.#staticNode) {
if (this.#staticNode.type === NodeType.Style) this.#staticNode.value.end = range.end - 1;
this.#staticNode.end = range.end;
this.#staticNode = void 0;
} else {
this.#attrNode = void 0;
const tag = this.#parentNode;
tag.open.end = range.end;
if (range.selfClosed || tag.bodyType === TagType.void) {
this.#parentNode = tag.parent;
tag.end = range.end;
tag.selfClosed = range.selfClosed;
}
}
}
onCloseTagStart(range) {
this.#parentNode.close = {
start: range.start,
end: UNFINISHED
};
}
onCloseTagEnd(range) {
const parent = this.#parentNode;
if (hasCloseTag(parent)) parent.close.end = range.end;
parent.end = range.end;
this.#parentNode = parent.parent;
}
};
function pushBody(parent, node) {
if (parent.body) parent.body.push(node);
else parent.body = [node];
}
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 pushAttr(parent, node) {
if (parent.attrs) parent.attrs.push(node);
else parent.attrs = [node];
}
function isInlineComment(node, opts) {
return node.type === "MarkoComment" && getCommentType(node, opts) !== "/";
function hasCloseTag(parent) {
return parent.close !== void 0;
}
function isText(node) {
return node.type === "MarkoText" || node.type === "MarkoPlaceholder";
/**
* Used to check if a node should be ignored as the parent of an attribute tag.
* When control flow is the parent of an attribute tag, we add the attribute tag to
* the closest non control flow ancestor attrs instead.
*/
function isControlFlowTag(node) {
switch (node.nameText) {
case "if":
case "else":
case "else-if":
case "for":
case "while": return true;
default: return false;
}
}
// src/utils/with-line-if-needed.ts
import { doc } from "prettier";
var { builders: b } = 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;
function read(range, opts) {
return opts._markoParsed.read(range);
}
// src/utils/with-block-if-needed.ts
import { doc as d } from "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;
const placeholderReg = /MARKO_(\d+)_/g;
const { mapDoc } = doc.utils;
async function getFormattedBody(tag, parser, toDoc, print, opts) {
let pid = 0;
let code = "";
let placeholders;
tag.each((child) => {
if (child.node.type === NodeType.Placeholder) {
code += `MARKO_${pid++}_`;
(placeholders ||= []).push(print(child));
} else code += read(child.node, opts);
}, "body");
const doc = parser ? await toDoc(code, { parser }) : code;
return !placeholders ? doc : mapDoc(doc, (cur) => {
if (typeof cur === "string") {
let match = placeholderReg.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 = placeholderReg.exec(cur));
if (index !== cur.length) replacementDocs.push(cur.slice(index));
if (replacementDocs.length === 1) return replacementDocs[0];
return replacementDocs;
}
}
return cur;
});
}
// 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 "";
function getParserFromExt(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";
default: return false;
}
}
// src/utils/with-block-if-needed.ts
var { builders: b2 } = d;
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;
function hasTagParser(tag) {
switch (tag.nameText) {
case "script":
case "html-script":
case "style":
case "html-style": return true;
default: return false;
}
}
// src/utils/with-parens-if-needed.ts
import { doc as d2 } from "prettier";
var { builders: b3 } = d2;
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 getTagParser(tag, opts) {
switch (tag.body && tag.nameText) {
case "script":
case "html-script": return getScriptTagParser(tag, opts);
case "style": return getStyleTagParser(tag, opts);
case "html-style": return "css";
}
}
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;
function getScriptTagParser(tag, opts) {
if (tag.attrs?.length) {
for (const attr of tag.attrs) if (attr.type === NodeType.AttrNamed && attr.value?.type === NodeType.AttrValue && read(attr.name, opts) === "type") {
const { code } = opts._markoParsed;
const value = attr.value.value;
const start = code.charAt(value.start);
switch ((start === "\"" || start === "'") && start === code.charAt(value.end - 1) ? code.slice(value.start + 1, value.end - 1) : "") {
case "module":
case "text/javascript":
case "application/javascript": return "babel-ts";
case "importmap":
case "speculationrules":
case "application/json": return "json";
default: return false;
}
}
}
return "babel-ts";
}
// src/utils/as-literal-text-content.ts
import { doc as doc2 } from "prettier";
var { builders: b4 } = doc2;
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 getStyleTagParser(tag, opts) {
return getParserFromExt(tag.shorthandClassNames && read(tag.shorthandClassNames[tag.shorthandClassNames.length - 1], opts) || ".css");
}
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);
const b$3 = doc.builders;
const singleQuoteSpace = "${' '}";
const doubleQuoteSpace = "${\" \"}";
const singleQuoteSpaceIfBreak = b$3.ifBreak([singleQuoteSpace, b$3.line], " ");
const doubleQuoteSpaceIfBreak = b$3.ifBreak([doubleQuoteSpace, b$3.line], " ");
function ensureVisibleSpace(parts, opts) {
if (parts[0] === b$3.line) parts[0] = getVisibleSpace(opts);
if (parts[parts.length - 1] === b$3.line) parts[parts.length - 1] = getVisibleSpace(opts);
}
// src/utils/get-original-code.ts
import { generator } from "@marko/compiler/internal/babel";
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 generator(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));
function ensureVisibleTrailingSpace(parts, opts) {
const last = parts.length - 1;
if (typeof parts[last] === "string" && /[ \t]$/.test(parts[last])) parts[last] = parts[last].slice(0, -1) + getVisibleSpace(opts);
}
// src/index.ts
var defaultFilePath = resolve("index.marko");
var rootRequire = createRequire(defaultFilePath);
var { builders: b5, utils } = doc3;
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"]
}
function ensureVisibleSpaceBetweenTags(parts, opts) {
const last = parts.length - 1;
if (last > 0 && parts[last] === b$3.line) {
if (typeof parts[last - 1] !== "string") parts[last] = opts.singleQuote ? singleQuoteSpaceIfBreak : doubleQuoteSpaceIfBreak;
}
}
function getVisibleSpace(opts) {
return opts.singleQuote ? singleQuoteSpace : doubleQuoteSpace;
}
function isVisibleSpace(code) {
switch (code) {
case singleQuoteSpace:
case doubleQuoteSpace: return true;
default: return false;
}
}
const DocCache = /* @__PURE__ */ new WeakMap();
function printDoc(doc) {
switch (typeof doc) {
case "string": return doc;
case "object": if (doc !== null) {
let cached = DocCache.get(doc);
if (cached !== void 0) return cached;
if (Array.isArray(doc)) {
cached = "";
for (const item of doc) cached += printDoc(item);
} else switch (doc.type) {
case "align":
cached = `\n${printDoc(doc.contents)}\n`;
break;
case "indent":
cached = ` ${printDoc(doc.contents)} `;
break;
case "break-parent":
case "cursor":
case "line-suffix-boundary":
case "trim":
cached = "";
break;
case "fill":
cached = ` ${printDoc(doc.parts)} `;
break;
case "group":
cached = printDoc(doc.contents) + printDoc(doc.expandedStates);
break;
case "if-break":
cached = printDoc(doc.flatContents) + printDoc(doc.breakContents);
break;
case "indent-if-break":
cached = " ";
break;
case "label":
case "line-suffix":
cached = printDoc(doc.contents);
break;
default:
cached = "\n";
break;
}
DocCache.set(doc, cached);
return cached;
}
}
return "";
}
const { builders: b$2 } = doc;
function withBlockIfNeeded(doc) {
if (isValidStatement(printDoc(doc).trim()) !== Validity.invalid) return doc;
return b$2.group([
b$2.ifBreak("{"),
b$2.indent([b$2.softline, doc]),
b$2.softline,
b$2.ifBreak("}")
]);
}
const { builders: b$1 } = doc;
function withParensIfNeeded(doc, concise) {
switch (isValidAttrValue(printDoc(doc).trim(), concise)) {
case Validity.enclosed: return doc;
case Validity.valid: return b$1.group([
b$1.ifBreak("("),
b$1.indent([b$1.softline, doc]),
b$1.softline,
b$1.ifBreak(")")
]);
default: return b$1.group([
b$1.indent([
"(",
b$1.softline,
doc
]),
b$1.softline,
")"
]);
}
}
const b = doc.builders;
const traverseDoc = doc.utils.traverseDoc;
const stmtParse = { parser: "babel-ts" };
const exprParse = { parser: "__ts_expression" };
const noVisitorKeys = [];
const tagVisitorKeys = [
"name",
"shorthandId",
"shorthandClassNames",
"var",
"args",
"typeArgs",
"params",
"typeParams",
"attrs",
"body"
];
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 = 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."
}
const visitorKeys = {
[NodeType.Tag]: tagVisitorKeys,
[NodeType.AttrTag]: tagVisitorKeys,
[NodeType.Program]: ["static", "body"],
[NodeType.AttrNamed]: ["args", "value"]
};
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;
}
}
const languages = [{
name: "marko",
aceMode: "text",
parsers: ["marko"],
aliases: ["markojs"],
tmScope: "text.marko",
codemirrorMode: "htmlmixed",
vscodeLanguageIds: ["marko"],
linguistLanguageId: 932782397,
codemirrorMimeType: "text/html",
extensions: [".marko"]
}];
const 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."
}
]
} };
const parsers = { marko: {
astFormat: "marko-ast",
parse(text, opts) {
const { program } = opts._markoParsed = parse(text, opts.filepath);
if (opts.markoSyntax === "auto") {
opts.markoSyntax = "html";
for (const child of program.body) if (child.type === NodeType.Tag) {
if (child.concise) opts.markoSyntax = "concise";
break;
}
}
return program;
},
locStart(node) {
return node.start;
},
locEnd(node) {
return node.end;
}
} };
const printers = { "marko-ast": {
print(path, opts, print) {
const { node } = path;
switch (node.type) {
case NodeType.AttrArgs:
case NodeType.AttrMethod:
case NodeType.AttrNamed:
case NodeType.AttrSpread:
case NodeType.Class:
case NodeType.Export:
case NodeType.Import:
case NodeType.OpenTagName:
case NodeType.Placeholder:
case NodeType.Scriptlet:
case NodeType.ShorthandClassName:
case NodeType.ShorthandId:
case NodeType.Static:
case NodeType.Style:
case NodeType.TagArgs:
case NodeType.TagParams:
case NodeType.TagTypeArgs:
case NodeType.TagTypeParams:
case NodeType.TagVar: return printExact(path, opts, print);
case NodeType.CDATA: return printCDATA(path, opts, print);
case NodeType.Comment: return printComment(path, opts, print);
case NodeType.Doctype: return printDoctype(path, opts, print);
case NodeType.Declaration: return printDeclaration(path, opts, print);
case NodeType.Program: return printProgram(path, opts, print);
case NodeType.Tag:
case NodeType.AttrTag: return printTag(path, opts, print);
case NodeType.Text: return printText(path, opts, print);
default: throw new Error(`Unknown node type in Marko template: ${NodeType[node.type] || node.type}`);
}
},
embed(path, opts) {
switch (path.node?.type) {
case NodeType.AttrNamed: return embedAttrNamed;
case NodeType.AttrSpread: return embedAttrSpread;
case NodeType.Class: return embedClass;
case NodeType.Export: return embedExport;
case NodeType.Import: return embedImport;
case NodeType.OpenTagName: return embedOpenTagName;
case NodeType.Placeholder: return embedPlaceholder;
case NodeType.Scriptlet: return embedScriptlet;
case NodeType.ShorthandClassName: return embedShorthandClassName;
case NodeType.ShorthandId: return embedShorthandId;
case NodeType.Static: return embedStatic;
case NodeType.Style: return embedStyle;
case NodeType.Tag: return embedTag(path, opts);
case NodeType.TagArgs: return embedTagArgs;
case NodeType.TagParams: return embedTagParams;
case NodeType.TagTypeArgs: return embedTagTypeArgs;
case NodeType.TagTypeParams: return embedTagTypeParams;
case NodeType.TagVar: return embedTagVar;
}
return null;
},
getVisitorKeys(node) {
return visitorKeys[node.type] || noVisitorKeys;
}
} };
const printProgram = (path, opts, print) => {
const body = printBody(path, opts, print);
const lastStatic = path.node.static.length - (body ? 0 : 1);
let programDoc = path.map((child, i) => i !== lastStatic && hasExplicitLine(child, opts) ? [child.call(print), b.hardline] : child.call(print), "static");
if (body) if (body.inline) programDoc.push(wrapConciseText(body.content));
else programDoc = [...programDoc, ...body.content];
return [b.join(b.hardline, programDoc), b.hardline];
};
var printers = {
"marko-ast": {
print(path, opts, print) {
var _a, _b, _c, _d, _e, _f;
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 bodyDocs = [];
if (hasAttrTags) {
tagPath.each((attrTag) => {
bodyDocs.push(print(attrTag));
if (opts.markoSyntax === "html") {
bodyDocs.push(b5.hardline);
}
}, "attributeTags");
if (!tagPath.node.body.body.length && opts.markoSyntax === "html") {
bodyDocs.pop();
}
}
let textOnly = !hasAttrTags;
let textDocs = [];
let leadingLine = false;
tagPath.each(
(childPath) => {
var _a2;
const childNode = childPath.getNode();
const isText2 = isTextLike(childNode, node, opts);
if (opts.markoSyntax === "html" && !preserveSpace) {
const { type } = childNode;
const prevType = (_a2 = childPath.previous) == null ? void 0 : _a2.type;
if (prevType === "MarkoScriptlet" || prevType === "MarkoComment" && getCommentType(childPath.previous, opts) === "/" || type === "MarkoTag" && prevType === "MarkoTag") {
textDocs.push(b5.hardline);
} else if (type === "MarkoTag" && prevType === "MarkoText" && /\S\s+$/.test(childPath.previous.value)) {
leadingLine = true;
}
}
if (isText2) {
if (preserveSpace && opts.markoSyntax === "concise") {
bodyDocs.push(
b5.group([printDashes(node), " ", print(childPath)])
);
} else {
textDocs.push(print(childPath));
}
if (textOnly || !childPath.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(
leadingLine ? b5.group([b5.softline, print(childPath)]) : print(childPath)
);
leadingLine = false;
}
} else {
bodyDocs.push(print(childPath));
}
},
"body",
"body"
);
if (opts.markoSyntax === "html") {
const joinSep = preserveSpace ? "" : textOnly ? b5.softline : b5.hardline;
const wrapSep = !preserveSpace && (node.body.body.some(
(child) => !isTextLike(child, node, opts)
) || node.loc && opts.originalText[locToPos(node.loc.start, opts)] === "<" && ((_c = node.body.body[0]) == null ? void 0 : _c.loc) && node.loc.start.line < node.body.body[0].loc.start.line) ? b5.hardline : joinSep;
doc4.push(
">",
b5.indent([
wrapSep,
textOnly ? b5.group(textDocs) : b5.fill(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 (canInlineMethod(value)) {
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)) && (isConcise || ((_e = path.parent) == null ? void 0 : _e.type) === "Program" || path.isFirst)) {
prefix = opts.singleQuote ? "${' '}" : '${" "}';
value = value.slice(1);
}
const last = value.length - 1;
if (value[last] === " " && !(path.next && isTextLike(path.next, parent, opts)) && (isConcise || ((_f = path.parent) == null ? void 0 : _f.type) === "Program" || path.isLast)) {
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) => {
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 = !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 codeStartOffset = startContent.length;
const codeEndOffset = node.rawValue.lastIndexOf("}");
const code = rawValue.slice(codeStartOffset, 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" && canInlineMethod(node)) {
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;
}
}
const printDoctype = (path, opts) => {
return `<!${read(path.node.value, opts).replace(/\s+/g, " ").trim()}>`;
};
function setCompiler(compiler, config) {
currentCompiler = compiler;
setConfig(config);
const printDeclaration = (path, opts) => {
return `<?${read(path.node.value, opts).trim()}?>`;
};
const printCDATA = (path, opts) => {
return `<![CDATA[${read(path.node.value, opts)}]]>`;
};
const printComment = (path, opts) => {
const { node } = path;
const code = read(node, opts);
if (node.block) {
if (code.includes("\n")) {
const lines = code.split("\n");
const len = lines.length;
let indent = Infinity;
for (let i = 1; i < len; i++) {
const match = lines[i].match(/^(\s+)/);
if (match) indent = Math.min(indent, match[1].length);
else {
indent = 0;
break;
}
}
const parts = [lines[0]];
for (let i = 1; i < len; i++) parts.push(b.hardline, indent ? lines[i].slice(indent) : lines[i]);
return parts;
}
return code;
}
return b.lineSuffix(code);
};
const printTag = ((path, opts, print, body = printBody(path, opts, print)) => {
return (isConcise(opts) ? printConciseTag : printHTMLTag)(path, opts, print, body);
});
const printHTMLTag = ((path, opts, print, body) => {
const { node } = path;
const openTagDoc = ["<", printTagBeforeAttrs(path, opts, print)];
if (node.attrs) {
const hasDefault = isDefaultAttr(node.attrs[0]);
let attrsDocs = path.map(print, "attrs");
if (hasDefault) {
openTagDoc.push(attrsDocs[0]);
attrsDocs = attrsDocs.slice(1);
}
if (attrsDocs.length) if (attrsDocs.length === 1 && !(hasDefault || node.params || node.args)) openTagDoc.push(" ", attrsDocs[0]);
else openTagDoc.push(b.indent([b.line, b.join(b.line, attrsDocs)]), b.softline);
}
openTagDoc.push(body || node.bodyType === TagType$1.void ? ">" : "/>");
if (body) {
const bodyLine = body.inline ? b.softline : b.hardline;
const closeTagDoc = `</${node.name.expressions.length ? "" : read(node.name, opts)}>`;
if (body.preserve) return b.group([
b.group(openTagDoc),
body.content,
closeTagDoc
]);
return b.group([
b.group(openTagDoc),
b.indent([bodyLine, body.inline ? body.content : b.join(bodyLine, body.content)]),
bodyLine,
closeTagDoc
]);
}
return b.group(openTagDoc);
});
const printConciseTag = ((path, opts, print, body) => {
const { node } = path;
const tagDoc = [printTagBeforeAttrs(path, opts, print)];
if (node.attrs) {
const hasDefault = isDefaultAttr(node.attrs[0]);
let attrsDocs = path.map(print, "attrs");
if (hasDefault) {
tagDoc.push(attrsDocs[0]);
attrsDocs = attrsDocs.slice(1);
}
if (attrsDocs.length) if (attrsDocs.length === 1 && !(hasDefault || node.params || node.args)) tagDoc.push(" ", attrsDocs[0]);
else {
const attrsDoc = [];
for (const attrDoc of attrsDocs) attrsDoc.push(b.line, b.ifBreak(","), attrDoc);
tagDoc.push(b.group(b.indent(attrsDoc)));
}
}
if (body) tagDoc.push(b.group(body.inline ? body.preserve ? b.indent([b.line, wrapConciseText(body.content)]) : [" --", b.indent([b.line, body.content])] : b.indent([b.hardline, b.join(b.hardline, body.content)])));
return b.group(tagDoc);
});
const printTagBeforeAttrs = (path, _opts, print) => {
const { node } = path;
const name = path.call(print, "name");
const doc = [name];
if (pathHas(path, "typeArgs")) doc.push(path.call(print, "typeArgs"));
if (pathHas(path, "shorthandId")) doc.push(path.call(print, "shorthandId"));
if (pathHas(path, "shorthandClassNames")) doc.push(path.map(print, "shorthandClassNames"));
if (pathHas(path, "args")) doc.push(path.call(print, "args"));
if (pathHas(path, "var")) doc.push(path.call(print, "var"));
if (pathHas(path, "params")) {
if (pathHas(path, "typeParams")) {
if (!(node.typeArgs || node.args || node.var)) doc.push(" ");
doc.push(path.call(print, "typeParams"));
}
doc.push(path.call(print, "params"));
}
return doc.length === 1 ? name : doc;
};
const printBody = (path, opts, print) => {
const { node } = path;
if (!node.body) return;
const concise = !node.parent || isConcise(opts);
const isInline = concise ? isTextLike : isInlineHTML;
const preserve = hasPreservedText(node);
let content;
let inline;
let inlineIndex = -1;
if (preserve) {
path.each((child) => {
const childDoc = child.call(print);
if (!childDoc) return;
content ||= [];
if (isInline(child.node)) {
if (!inline) {
inline = [];
inlineIndex = content.push(inline) - 1;
}
if (child.node.type === NodeType.Text && typeof childDoc === "string") {
const nl = isConcise(opts) ? b.hardline : b.literalline;
let lineStart = 0;
for (let i = 0; i < childDoc.length; i++) if (childDoc.charAt(i) === "\n") {
if (lineStart !== i) inline.push(childDoc.slice(lineStart, i));
inline.push(nl);
lineStart = i + 1;
}
if (!lineStart) inline.push(childDoc);
else if (lineStart !== childDoc.length) inline.push(childDoc.slice(lineStart));
} else inline.push(childDoc);
} else {
if (inline) {
if (concise) {
ensureVisibleTrailingSpace(inline, opts);
content[inlineIndex] = wrapConciseText(content[inlineIndex]);
}
inline = void 0;
}
content.push(childDoc);
}
}, "body");
if (inline && concise) ensureVisibleTrailingSpace(inline, opts);
} else {
let isInlineTag = false;
let isExplicitLine = false;
path.each((child) => {
const wasInlineTag = isInlineTag;
const inlineChild = isInline(child.node);
let childDoc = child.call(print);
if (child.node.type === NodeType.Text && typeof childDoc === "string") childDoc = trimText(childDoc, child);
if (!childDoc) return;
isInlineTag = false;
content ||= [];
if (isExplicitLine) {
const last = content.length - 1;
isExplicitLine = false;
content[last] = [content[last], b.hardline];
}
if (inlineChild) {
if (!inline) {
inline = [];
inlineIndex = content.push(b.fill(inline)) - 1;
}
switch (child.node.type) {
case NodeType.Text:
if (typeof childDoc === "string") {
const len = childDoc.length;
let start = 0;
for (let i = 0; i < len; i++) if (childDoc.charAt(i) === " ") {
if (start !== i) inline.push(childDoc.slice(start, i));
if (i || !endsWithLine(inline)) inline.push(b.line);
start = i + 1;
}
if (start === len) return;
if (start) childDoc = childDoc.slice(start);
}
break;
case NodeType.Placeholder:
if (typeof childDoc === "string" && isVisibleSpace(childDoc)) {
if (endsWithLine(inline)) {
const last = inline.length - 1;
if (inline[last] === b.softline) inline[last] = b.line;
return;
}
childDoc = b.line;
}
break;
case NodeType.Tag:
isInlineTag = true;
ensureVisibleSpaceBetweenTags(inline, opts);
if (wasInlineTag) inline.push(b.softline);
break;
}
inline.push(childDoc);
} else {
isExplicitLine = !child.isLast && hasExplicitLine(child, opts);
if (inline) {
ensureVisibleSpace(inline, opts);
inline = void 0;
if (concise) content[inlineIndex] = wrapConciseText(content[inlineIndex]);
}
content.push(childDoc);
}
}, "body");
}
if (content) {
if (inline) {
ensureVisibleSpace(inline, opts);
if (inlineIndex === 0) return {
inline: true,
preserve,
content: content[inlineIndex]
};
if (concise) content[inlineIndex] = wrapConciseText(content[inlineIndex]);
}
return {
inline: false,
preserve,
content
};
}
};
const printText = (path, opts) => {
const text = read(path.node, opts).replace(/\\/g, "\\\\");
if (/^\$!?{/.test(text)) return "\\" + text;
return text;
};
const printExact = (path, opts) => read(path.node, opts);
const embedClass = (toDoc, _print, path, opts) => toDoc(read(path.node, opts), exprParse);
const embedImport = (toDoc, _print, path, opts) => toDoc(read(path.node, opts), stmtParse);
const embedExport = (toDoc, _print, path, opts) => toDoc(read(path.node, opts), stmtParse);
const embedStyle = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).trim();
const parser = getParserFromExt(node.ext?.slice(node.ext.lastIndexOf(".")) || ".css");
if (parser) return b.group([
`style${node.ext || ""} {`,
b.indent([b.line, await toDoc(code, { parser })]),
b.line,
"}"
]);
};
const embedStatic = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = opts._markoParsed.code.slice(node.start + node.target.length + 1, node.end).replace(/^\s*\{([\s\S]*)\}\s*$/, "$1").trim();
return code ? [`${node.target} `, withBlockIfNeeded(await toDoc(code, stmtParse))] : [];
};
const embedScriptlet = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).replace(/^\s*\{([\s\S]*)\}\s*$/, "$1").trim();
return code ? [
b.breakParent,
"$ ",
withBlockIfNeeded(await toDoc(code, stmtParse))
] : [];
};
const embedOpenTagName = async (toDoc, _print, path, opts) => embedTemplate(toDoc, _print, path, opts);
const embedPlaceholder = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts);
if (code === "\" \"" || code === "' '") return getVisibleSpace(opts);
return b.group([
"${",
b.indent([b.softline, await toDoc(code, exprParse)]),
b.softline,
"}"
]);
};
const embedTagArgs = (toDoc, _print, path, opts) => {
return argsToDoc(path.node, opts, toDoc);
};
const embedAttrNamed = async (toDoc, _print, path, opts) => {
const node = path.node;
const name = read(node.name, opts);
if (!(node.args || node.value)) return name;
const attrDoc = [name];
if (node.args) {
const argsDoc = await argsToDoc(node.args, opts, toDoc);
if (argsDoc) attrDoc.push(argsDoc);
else return unexpectedDoc(opts, node);
}
if (node.value) if (node.value.type === NodeType.AttrMethod) {
const attrMethodDoc = await toDoc(`function${read(node.value, opts)}`, exprParse);
if (Array.isArray(attrMethodDoc) && attrMethodDoc.length && typeof attrMethodDoc[0] === "string") {
attrMethodDoc[0] = attrMethodDoc[0].replace(/^function\s*/, "");
attrDoc.push(attrMethodDoc);
} else return unexpectedDoc(opts, node);
} else attrDoc.push(node.value.bound ? ":=" : "=", withParensIfNeeded(await toDoc(read(node.value.value, opts), exprParse), isConcise(opts)));
return b.group(attrDoc);
};
const embedAttrSpread = async (toDoc, _print, path, opts) => {
const node = path.node;
return b.group(["...", withParensIfNeeded(await toDoc(read(node.value, opts), exprParse), isConcise(opts))]);
};
const embedShorthandId = async (toDoc, print, path, opts) => ["#", await embedTemplate(toDoc, print, path, opts)];
const embedShorthandClassName = async (toDoc, print, path, opts) => [".", await embedTemplate(toDoc, print, path, opts)];
const embedTag = (path, opts) => {
const tag = path.node;
const parser = getTagParser(tag, opts);
if (parser === void 0) return null;
return async (toDoc, print, path, opts) => printTag(path, opts, print, {
inline: true,
preserve: parser === false,
content: await getFormattedBody(path, parser, toDoc, print, opts)
});
};
const embedTagVar = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).trim();
if (code) {
let doc = await toDoc(`var ${code}=_`, stmtParse);
if (Array.isArray(doc) && doc.length === 1) doc = doc[0];
if (typeof doc === "object" && !Array.isArray(doc) && doc.type === "group") doc = doc.contents;
if (Array.isArray(doc) && doc.length > 1) {
const varPart = doc[1];
if (typeof varPart === "object" && "type" in varPart && varPart.type === "group" && Array.isArray(varPart.contents)) {
const varContents = varPart.contents;
for (let i = varContents.length; i--;) {
const item = varContents[i];
if (typeof item === "string") {
const match = /\s*=\s*$/.exec(item);
if (match) {
varContents[i] = item.slice(0, -match[0].length);
varContents.length = i + 1;
return ["/", varContents];
}
}
}
}
}
return unexpectedDoc(opts, node);
}
return [];
};
const embedTagTypeArgs = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).trim();
if (code) {
const doc = await toDoc(`_<${code}>`, exprParse);
if (typeof doc === "string") return doc.replace(/^_/, "");
if (Array.isArray(doc) && typeof doc[0] === "string") {
doc[0] = doc[0].replace(/^_/, "");
return doc;
}
return unexpectedDoc(opts, node);
}
return [];
};
const embedTagParams = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).trim();
if (code) {
const doc = await toDoc(`function _(${code}){}`, stmtParse);
if (Array.isArray(doc) && doc.length > 1) {
const paramsGroup = doc[1];
if (paramsGroup && typeof paramsGroup === "object" && "type" in paramsGroup && paramsGroup.type === "group" && Array.isArray(paramsGroup.contents)) {
const paramsContents = [...paramsGroup.contents];
const first = paramsContents[0];
const last = paramsContents[paramsContents.length - 1];
if (typeof first === "string" && typeof last === "string") {
paramsContents[0] = first.replace(/^\(/, "|");
paramsContents[paramsContents.length - 1] = last.replace(/\)$/, "|");
}
return b.group(paramsContents);
}
}
return unexpectedDoc(opts, node);
}
return [];
};
const embedTagTypeParams = async (toDoc, _print, path, opts) => {
const node = path.node;
const code = read(node.value, opts).trim();
if (code) {
const doc = await toDoc(`function _<${code}>(){}`, stmtParse);
if (Array.isArray(doc) && doc.length > 1) return doc[1];
return unexpectedDoc(opts, node);
}
return [];
};
const embedTemplate = async (toDoc, _print, path, opts) => {
const { expressions, quasis } = path.node;
const first = read(quasis[0], opts);
const len = expressions.length;
if (!len) return first;
const shorthandDoc = [first];
for (let i = 0; i < len; i++) {
const quasi = read(quasis[i + 1], opts);
const expr = read(expressions[i].value, opts);
shorthandDoc.push(b.group([
"${",
b.indent([b.softline, await toDoc(expr, exprParse)]),
b.softline,
"}"
]));
if (quasi) shorthandDoc.push(quasi);
}
return shorthandDoc;
};
async function argsToDoc(node, opts, toDoc) {
const code = read(node.value, opts).trim();
if (code) {
const doc = await toDoc(`_(${code})`, exprParse);
if (Array.isArray(doc) && doc.length && typeof doc[0] === "string") {
doc[0] = doc[0].replace(/^_/, "");
return doc;
}
return unexpectedDoc(opts, node);
}
return [];
}
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 wrapConciseText(doc) {
let maxDashes = 0;
traverseDoc(doc, (child) => {
if (typeof child === "string") {
let current = 0;
for (const char of child) if (char === "-") {
current++;
if (current > maxDashes) maxDashes = current;
} else current = 0;
}
});
const breakDashes = maxDashes > 1 ? "-".repeat(maxDashes + 1) : "--";
return b.group([
b.ifBreak(breakDashes, "--"),
b.line,
doc,
b.ifBreak([b.line, breakDashes])
]);
}
function printComments(comments) {
return comments.map(
(comment) => comment.type === "CommentBlock" ? `/*${comment.value}*/` : "//" + comment.value
);
function trimText(text, path) {
if (/^(?:\n\s*)?(?:\n\s*)?$/.test(text)) return "";
const siblings = path.siblings;
let trimmed = text;
let prev;
let next;
for (let i = path.index; --i >= 0;) {
const sibling = siblings[i];
if (sibling.type !== NodeType.Scriptlet && sibling.type !== NodeType.Comment) {
prev = sibling;
break;
}
}
for (let i = path.index; ++i < siblings.length;) {
const sibling = siblings[i];
if (sibling.type !== NodeType.Scriptlet && sibling.type !== NodeType.Comment) {
next = sibling;
break;
}
}
const parent = path.node.parent;
const isInline = !parent.parent || parent.concise ? isTextLike : isInlineHTML;
const trimStart = !(prev && isInline(prev));
const trimEnd = !(next && isInline(next));
if (trimStart) trimmed = trimmed.replace(/^\n\s*/, "");
if (trimEnd) trimmed = trimmed.replace(/\n\s*$/, "");
return trimmed.replace(/\s+/g, " ");
}
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 isTextLike(node) {
switch (node.type) {
case NodeType.Text:
case NodeType.Placeholder: return true;
case NodeType.Comment: return node.block;
default: return false;
}
}
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 isInlineHTML(node) {
switch (node.type) {
case NodeType.Text:
case NodeType.Placeholder: return true;
case NodeType.Comment: return node.block;
case NodeType.Tag: return !!node.nameText && /^(?:a(?:bbr|cronym)?|b(?:do|ig|r)?|cite|code|dfn|em|i(?:mg)?|kbd|label|map|object|output|q|samp|small|span|strong|sub|sup|time|tt|var)$/.test(node.nameText);
default: return false;
}
}
function preventTrailingCommaTagArgs(tagName) {
switch (tagName) {
case "if":
case "else-if":
case "while":
return true;
default:
return false;
}
function hasPreservedText(node) {
if (node.type === NodeType.Tag && hasTagParser(node)) return true;
let cur = node;
while (cur.type === NodeType.Tag) {
if (cur.nameText && /^(?:textarea|pre)$/.test(cur.nameText)) return true;
cur = cur.parent;
}
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 isDefaultAttr(node) {
if (node.type === NodeType.AttrNamed && node.value && node.name.start === node.name.end) return true;
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 isConcise(opts) {
return opts.markoSyntax === "concise";
}
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,
browserslistConfigFile: false,
parserOpts: {
allowUndeclaredExports: true,
allowAwaitOutsideFunction: true,
allowReturnOutsideFunction: true,
allowImportExportEverywhere: true,
plugins: ["exportDefaultFrom", "importAssertions"]
}
}
};
const explicitLineReg = /\S?\n\n/y;
function hasExplicitLine(path, opts) {
explicitLineReg.lastIndex = path.node.end - 1;
return explicitLineReg.test(opts._markoParsed.code);
}
function getScriptParser(tag) {
for (const attr of tag.attributes) {
if (attr.type === "MarkoAttribute" && attr.name === "type") {
switch (attr.value.type === "StringLiteral" ? attr.value.value : void 0) {
case "module":
case "text/javascript":
case "application/javascript":
return scriptParser;
case "importmap":
case "speculationrules":
case "application/json":
return "json";
default:
return false;
}
}
}
return scriptParser;
function endsWithLine(doc) {
switch (doc.length && doc[doc.length - 1]) {
case b.line:
case b.hardline:
case b.literalline:
case b.softline:
case b.hardlineWithoutBreakParent: return true;
default: return false;
}
}
function getTextParent(text) {
const parent = text.parent;
return parent.type === "Program" ? parent : text.getParentNode(1);
function pathHas(path, key) {
return !!path.node[key];
}
var minDashLookup = /* @__PURE__ */ new WeakMap();
function printDashes(parent) {
const dashes = minDashLookup.get(parent);
if (dashes === void 0) return "--";
minDashLookup.delete(parent);
return "-".repeat(dashes + 1);
function unexpectedDoc(opts, node) {
const parsed = opts._markoParsed;
const pos = parsed.positionAt(node.start);
console.warn(`Unable to format "${NodeType[node.type]}", please open an issue https://github.com/marko-js/prettier/issues.${opts.filepath ? `:\n at ${opts.filepath}:${pos.line + 1}:${pos.character + 1}` : ""}\n${parsed.read(node).replace(/(?:^|\n)(?!\n])/, opts.filepath ? "$& " : "$& ")}\n`);
}
function toPlaceholder(str, singleQuote) {
const quote = str.includes("\n") ? "`" : singleQuote ? "'" : '"';
let escaped = str.replace(/\\/g, "\\\\");
switch (quote) {
case "`":
escaped = escaped.replace(/`/g, "\\`").replace(/\$\{/g, "\\${");
break;
case "'":
escaped = escaped.replace(/'/g, "\\'");
break;
default:
escaped = escaped.replace(/"/g, '\\"');
break;
}
return "${" + quote + escaped + quote + "}";
}
function isEmpty(node) {
return node.type === "EmptyStatement" && !node.leadingComments && !node.trailingComments;
}
function canInlineMethod(node) {
return node.type === "FunctionExpression" && !(node.id || node.async || node.generator);
}
export {
languages,
options,
parsers,
printers,
setCompiler
};
export { languages, options, parsers, printers };

@@ -1,3 +0,2 @@

import type { types as t } from "@marko/compiler";
import { doc as d, type Doc } from "prettier";
export default function withBlockIfNeeded(node: t.Statement, doc: Doc): d.builders.Doc;
import { type Doc, doc as d } from "prettier";
export default function withBlockIfNeeded(doc: Doc): d.builders.Doc;

@@ -1,4 +0,2 @@

import { doc as d, type Doc } from "prettier";
import type { types as t } from "@marko/compiler";
export declare function withParensIfNeeded(node: t.Node, doc: Doc, enclosed?: boolean): d.builders.Doc;
export declare function withParensIfBreak(node: t.Node, doc: Doc): d.builders.Doc;
import { type Doc, doc as d } from "prettier";
export default function withParensIfNeeded(doc: Doc, concise: boolean): d.builders.Doc;
MIT License
Copyright (c) 2021 eBay Inc. and contributors
Copyright (c) 2026 eBay Inc. and contributors

@@ -5,0 +5,0 @@ Permission is hereby granted, free of charge, to any person obtaining a copy

{
"name": "prettier-plugin-marko",
"version": "4.0.4",
"description": "A prettier plugin for parsing and printing Marko files",
"version": "4.0.3",
"author": "Dylan Piercey <dpiercey@ebay.com>",
"keywords": [
"format",
"marko",
"prettier",
"prettyprint"
],
"homepage": "https://github.com/marko-js/prettier",
"bugs": "https://github.com/marko-js/prettier/issues",
"dependencies": {
"@marko/compiler": "^5.39.52"
"repository": {
"type": "git",
"url": "git+https://github.com/marko-js/prettier.git"
},
"devDependencies": {
"@commitlint/cli": "^20.2.0",
"@commitlint/config-conventional": "^20.2.0",
"@istanbuljs/nyc-config-typescript": "^1.0.2",
"@types/babel__generator": "^7.27.0",
"@types/mocha": "^10.0.10",
"@types/node": "^22.10.2",
"@typescript-eslint/eslint-plugin": "^6.7.5",
"@typescript-eslint/parser": "^6.7.5",
"esbuild": "^0.25.9",
"esbuild-register": "^3.6.0",
"eslint": "^8.51.0",
"eslint-config-prettier": "^9.0.0",
"fast-glob": "^3.3.3",
"fixpack": "^4.0.0",
"husky": "^8.0.3",
"lint-staged": "^14.0.1",
"marko": "^5.38.21",
"mocha": "^10.7.3",
"mocha-snap": "^5.0.0",
"nyc": "^15.1.0",
"prettier": "^3.6.2",
"semantic-release": "^25.0.2",
"typescript": "^5.9.2"
},
"license": "MIT",
"author": "Dylan Piercey <dpiercey@ebay.com>",
"exports": {

@@ -41,2 +25,4 @@ ".": {

},
"main": "dist/index.js",
"module": "dist/index.mjs",
"files": [

@@ -47,39 +33,44 @@ "dist",

],
"homepage": "https://github.com/marko-js/prettier",
"keywords": [
"format",
"marko",
"prettier",
"prettyprint"
],
"license": "MIT",
"main": "dist/index.js",
"module": "dist/index.mjs",
"peerDependencies": {
"prettier": "^3"
},
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/marko-js/prettier"
},
"scripts": {
"build": "tsc -b && node -r esbuild-register build",
"ci:test": "nyc npm run mocha -- --forbid-pending --forbid-only",
"format": "npm run lint:eslint -- --fix && npm run lint:prettier -- --write && (fixpack || true)",
"lint": "tsc -b && npm run lint:eslint && npm run lint:prettier -- -l && fixpack",
"lint:eslint": "eslint -f visualstudio .",
"lint:prettier": "prettier '**/*{.ts,.js,.json,.md,.yml,rc}'",
"mocha": "NODE_ENV=test mocha 'src/**/__tests__/*.test.ts'",
"prepare": "husky install",
"prepublishOnly": "npm run build",
"release": "semantic-release",
"@ci:build": "npm run build",
"@ci:lint": "eslint . && prettier . --check --log-level=warn",
"@ci:release": "npm run build && changeset publish && npm ci",
"@ci:test": "c8 npm test -- --forbid-pending --forbid-only",
"@ci:version": "npm run build && npm run format && changeset version && npm i --package-lock-only",
"build": "tsc -b && rolldown -c",
"change": "changeset add",
"format": "eslint --fix .; prettier . --write --log-level=warn",
"prepare": "husky",
"report": "open ./coverage/lcov-report/index.html",
"test": "npm run mocha -- --watch",
"test:inspect": "npm test -- --inspect",
"test:update": "npm run mocha -- --update"
"test": "cross-env NODE_ENV=test mocha 'src/**/__tests__/*.test.ts'",
"test:update": "npm test -- --update"
},
"types": "dist/index.d.ts"
"dependencies": {
"htmljs-parser": "^5.9.0"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.2",
"@changesets/cli": "^2.29.8",
"@eslint/js": "^10.0.1",
"@marko/compiler": "^5.39.55",
"@types/mocha": "^10.0.10",
"@types/node": "^25.2.3",
"c8": "^10.1.3",
"cross-env": "^10.1.0",
"eslint": "^10.0.0",
"eslint-plugin-simple-import-sort": "^12.1.1",
"fast-glob": "^3.3.3",
"globals": "^17.3.0",
"husky": "^9.1.7",
"lint-staged": "^16.2.7",
"marko": "^6.0.145",
"mocha": "^11.7.5",
"mocha-snap": "^5.0.1",
"prettier": "^3.8.1",
"prettier-plugin-packagejson": "^3.0.0",
"rolldown": "^1.0.0-rc.4",
"tsx": "^4.21.0",
"typescript": "^5.9.3",
"typescript-eslint": "^8.55.1-alpha.4"
}
}

@@ -46,34 +46,22 @@ <h1 align="center">

### yarn
```console
yarn add prettier prettier-plugin-marko -D
```
# Usage
## NPM 6
See the Prettier ["using plugins"](https://prettier.io/docs/plugins#using-plugins) guide.
```console
npx --no-install prettier --write "**/*.marko"
npm exec -- prettier --write "**/*.marko" --plugin=prettier-plugin-marko
```
## NPM 7
Or via [prettier configuration](https://prettier.io/docs/configuration) like:
```console
npm exec -- prettier --write "**/*.marko"
```json
{
"plugins": ["prettier-plugin-marko"]
}
```
## Yarn
```console
yarn prettier --write "**/*.marko"
```
## Editors
Editors such as [Atom](https://atom.io/packages/prettier-atom) and [VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) provide plugins for calling [Prettier](https://prettier.io/) directly from your editor.
Editors such as [VSCode](https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode) provide plugins for calling [Prettier](https://prettier.io/) directly from your editor.
If you'd like to use these plugins **without** installing `prettier-plugin-marko` in the project, you can also install `prettier-plugin-marko` globally with either [npm](https://docs.npmjs.com/downloading-and-installing-packages-globally), [yarn](https://classic.yarnpkg.com/en/docs/cli/global/) or your package manager choice.
# Options

@@ -90,9 +78,4 @@

## `markoAttrParen: boolean`
For the most part Marko is very flexible when it comes to the [expressions uses within attributes](https://markojs.com/docs/syntax/#attributes).
By default this plugin will not wrap attribute values in parenthesis unless absolutely necessary. By setting this value to true it will instead output parenthesis whenever the attribute value contains any unenclosed whitespace.
# Code of Conduct
This project adheres to the [eBay Code of Conduct](./.github/CODE_OF_CONDUCT.md). By participating in this project you agree to abide by its terms.
declare module "prettier" {
interface Options {
markoSyntax?: "auto" | "html" | "concise";
markoAttrParen?: boolean;
}
interface ParserOptions {
markoSyntax?: "auto" | "html" | "concise";
markoAttrParen?: boolean;
}
}
export declare const scriptParser = "babel-ts";
export declare const expressionParser = "__ts_expression";
export declare const enclosedNodeTypeReg: RegExp;
export declare const styleReg: RegExp;
export declare const voidHTMLReg: RegExp;
export declare const shorthandIdOrClassReg: RegExp;
export declare const preserveSpaceTagsReg: RegExp;
import { Doc } from "prettier";
/**
* Normalizes newlines and backslashes to work in a printed document.
*/
export default function asLiteralTextContent(val: string, escapeBackslashes?: boolean): Doc;
export declare function asFilledTextContent(val: string): Doc;
import { AstPath, ParserOptions } from "prettier";
import type { types as t } from "@marko/compiler";
export declare function getOriginalCodeForNode(opts: ParserOptions<t.Node>, node: t.Node, path?: AstPath<t.Node>): string;
import type { types as t } from "@marko/compiler";
import { AstPath } from "prettier";
export default function getSibling(path: AstPath<t.Node>, direction: 1 | -1): t.MarkoTagBody["body"][number] | null;
import type { types as t } from "@marko/compiler";
import { ParserOptions } from "prettier";
export default function isTextLike(node: t.Node, parent: t.MarkoTag | t.Program, opts: ParserOptions<t.Node>): node is t.MarkoText | t.MarkoPlaceholder | t.MarkoComment;
export declare function getCommentType(node: t.MarkoComment, opts: ParserOptions<t.Node>): "/" | "*" | "-";
import { ParserOptions } from "prettier";
import type { types as t } from "@marko/compiler";
export default function locToPos(loc: {
line: number;
column: number;
}, opts: ParserOptions<t.Node>): number;
export default function outerCodeMatches(str: string, test: RegExp, enclosed?: boolean): boolean;
import { doc, Doc, ParserOptions } from "prettier";
import type { types as t } from "@marko/compiler";
export default function withLineIfNeeded(node: t.Node, opts: ParserOptions<t.Node>, doc: Doc): doc.builders.Doc;