UNPKG

prettier-plugin-rust

Version:
1,403 lines (1,396 loc) 155 kB
import { DelimKind, rs, NodeType, TK, PRCD } from 'jinx-rust'; import { start, end, insertNodes, is_BlockCommentKind, is_Snippet, is_Program, each_childNode, is_ExpressionStatement, is_FlowControlExpression, is_ReassignmentNode, reassignNodeProperty, is_ClosureFunctionExpression, is_BlockExpression, is_ExpressionWithBodyOrCases, is_IfBlockExpression, transferAttributes, hasTypeBounds, is_TypeDynBounds, is_TypeImplBounds, unsafe_set_nodeType, is_TypeTraitBound, is_TypeBoundsStandaloneNode, hasAttributes, is_DocCommentAttribute, insertNode, getBodyOrCases, deleteAttributes, is_NodeWithBodyOrCases, is_AttributeOrDocComment, ownStart, is_Attribute, is_StructLiteralProperty, is_Comment, is_MissingNode, is_PunctuationToken, is_MacroInvocation, is_CallExpression, getMacroName, hasMethod, includesTK, is_BareTypeTraitBound, getNodeChildren, is_NodeWithBodyNoBody, is_StructLiteralPropertySpread, nisAnyOf, hasOuterAttributes, is_FunctionDeclaration, is_StatementNode, is_FunctionNode, getLastParameter, is_MacroRule, is_LocArray, is_LineCommentNode, is_BlockCommentNode, is_UnionPattern, is_ExpressionAsTypeCast, is_FlowControlMaybeValueExpression, is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation, is_MemberExpression, is_ElseBlock, is_NodeWithMaybePatternNoUnionBody, is_UnaryExpression, is_ReturnExpression, is_YieldExpression, can_have_OuterAttributes, is_Identifier, is_Literal, is_LiteralNumberLike, is_StructLiteral, is_ParenthesizedNode, is_RangeLiteral, is_LogicalExpression, is_PostfixExpression, is_OperationExpression, is_ComparisonExpression, is_LetScrutinee, is_TypeFunctionNode, is_UnaryType, is_PatternVariableDeclaration, is_BitwiseOperator, is_EqualityOperator, getPrecedence, is_multiplicativeOperator, is_bitshiftOperator, getAstPath, is_MatchExpressionCase, is_EnumMemberDeclaration, is_StructPropertyDeclaration, is_StructPatternProperty, is_LineCommentKind, is_CommentOrDocComment, is_ExternSpecifier, hasSuffix, getDelimChars, is_ArrayOrTupleLiteral, is_Node, is_MatchExpression, is_SourceFile, is_MacroGroup, is_DelimGroup, is_MacroParameterDeclaration, is_MacroInlineRuleDeclaration, is_ExpressionPath, is_ReassignmentExpression, is_GenericParameterDeclaration, is_TypeCallNamedArgument, is_VariableDeclarationNode, is_LiteralStringLike, is_UnwrapExpression, is_IdentifierOrIndex, is_ExpressionTypeCast, hasSemiNoBody, is_OrExpression, is_ImplDeclarationNode, is_TupleStructDeclaration, hasParameters, hasSelfParameter, is_ClosureBlock, hasCondition, is_TupleNode, hasProperties, hasItems, is_TupleLiteral, is_TuplePattern, is_RangePattern, is_RestPattern, is_TypeTuple, hasSemiNoProperties, is_StructPattern, is_UnionDeclaration, is_StructDeclaration, is_EnumMemberStructDeclaration, getParameters, is_FunctionParameterDeclaration, isInner, is_FunctionSpread, isTK, hasLetScrutineeCondition, is_ImplicitReturnAbleNode, is_ExpressionWithBody, is_ForInBlockExpression, is_LoopBlockExpression, is_WhileBlockExpression, hasBody, is_MinusExpression, is_StructPatternPropertyDestructured, is_StructProperty, is_LiteralBooleanLike, getOwnChildAstPath } from 'jinx-rust/utils'; import doc from 'prettier/doc.js'; // src/format/plugin.ts // src/utils/debug.ts var cwd = typeof process === "object" && typeof (process == null ? void 0 : process.cwd) === "function" ? /* @__PURE__ */ normPath(/* @__PURE__ */ process.cwd() ?? "") : ""; function normPath_strip_cwd(filepath) { let normFilePath = normPath(filepath); return normFilePath.startsWith(cwd) ? normFilePath.slice(cwd.length + 1) : normFilePath; } var StackLine = class { constructor(raw) { ({ 1: this.callee = "", 2: this.filepath = "", 3: this.line = "", 4: this.col = "", 5: this.other = "" } = (this.raw = raw).match(/at (?:(.+?)\s+\()?(?:(.+?):([0-9]+)(?::([0-9]+))?|([^)]+))\)?/) ?? ["", "", "", "", "", ""]); this.url = this.filepath ? normPath_strip_cwd(this.filepath) + (this.line && this.col && `:${this.line}:${this.col}`) : this.other === "native" ? "<native>" : ""; } }; function getPrintWidth() { return clamp(0, getTerminalWidth(128), 200) - 4; } var StackItem = class extends StackLine { constructor(stack, i, raw) { super(raw); this.stack = stack; this.i = i; this.hidden = false; } hide() { this.hidden = true; return this; } hideNext(n) { var _a; for (let i = 0; i < n; i++) (_a = this.at(i)) == null ? void 0 : _a.hide(); } hideWhileTrue(test) { let line2 = this; while (line2 && test(line2)) line2 = line2.hide().next(); } at(relIndex) { return this.i + relIndex >= this.stack.length || this.i + relIndex < 0 ? void 0 : this.stack[this.i + relIndex]; } next() { return this.at(1); } toString() { var _a, _b, _c, _d; const url = this.url; const calleeColor = ((_b = (_a = this.stack.style) == null ? void 0 : _a.callee) == null ? void 0 : _b.call(_a, this.callee, this)) ?? color.cyan; const urlColor = ((_d = (_c = this.stack.style) == null ? void 0 : _c.url) == null ? void 0 : _d.call(_c, url, this)) ?? color.grey; return compose2Cols(" at " + calleeColor(this.callee), urlColor(url), getPrintWidth()); } }; function createStack(message, Error_stack, style) { for (var STACK = [], i = 0, stack = Error_stack.split("\n").slice(2); i < stack.length; i++) STACK[i] = new StackItem(STACK, i, stack[i]); return STACK.message = message, STACK.style = style, STACK; } function composeStack(stack) { var hidden = 0; var str = stack.message; for (var item of stack) item.hidden ? ++hidden : str += "\n" + item.toString(); return str + (hidden > 0 ? "\n" + color.grey(compose2Cols("", `...filtered ${hidden} lines`, getPrintWidth())) : ""); } function createCustomError({ message = "Unknown Error", editStack = (stack) => { }, style = void 0, stackTraceLimit = 20 }) { const _stackTraceLimit = Error.stackTraceLimit; const _prepareStackTrace = Error.prepareStackTrace; Error.stackTraceLimit = stackTraceLimit; const _ctx = {}; Error.captureStackTrace(_ctx, createCustomError); const stack = createStack(message, _ctx.stack, style); Error.prepareStackTrace = function(err2, calls) { editStack(stack); return composeStack(stack); }; const err = new Error(message); err.stack = err.stack; Error.stackTraceLimit = _stackTraceLimit; Error.prepareStackTrace = _prepareStackTrace; return err; } function compose2Cols(left, right, len = 64, min = 1) { return left + " ".repeat(clamp(min, len, len - (color.unstyledLength(left) + color.unstyledLength(right)))) + right; } function exit(message, ...ctx2) { if (ctx2.length > 0) console.log("Error context:", { ...ctx2 }); throw createCustomError({ message }); } exit.never = function never(...ctx2) { exit("Reached unreachable code", ...ctx2); }; function assert(predicate, err, ...ctx2) { if (false === predicate) exit(err ?? "Assertion failed", ...ctx2); } function Identity(v) { return v; } function last_of(arr) { return arr[arr.length - 1]; } function normPath(filepath) { return filepath.replace(/^file:\/\/\//, "").replace(/\\\\?/g, "/"); } function binarySearchIn(array, target, toValue) { if (isEmpty(array)) return -1; let i = 0; let low = 0; let high = array.length - 1; let value = toValue(array[high]); if (target >= value) return high; else high--; while (low <= high) { i = low + (high - low >> 1); value = toValue(array[i]); if (target === value) return i; if (target > value) low = i + 1; else high = i - 1; } return low - 1; } function getTerminalWidth(fallbackWidth = 200) { var _a, _b; return ((_b = (_a = globalThis == null ? void 0 : globalThis.process) == null ? void 0 : _a.stdout) == null ? void 0 : _b.columns) ?? fallbackWidth; } var isBrowser = typeof window !== "undefined" && typeof window.document !== "undefined"; var color = ((cfn, mfn) => ({ black: cfn(30), red: cfn(31), green: cfn(32), yellow: cfn(33), blue: cfn(34), magenta: cfn(35), cyan: cfn(36), white: cfn(37), grey: cfn(90), bold: mfn(1, 22), italic: mfn(3, 23), underline: mfn(4, 24), hidden: mfn(8, 28), hiddenCursor: (str) => `\x1B[?25l${str}\x1B[?25h`, unstyle: (str) => str.replace(/\x1B\[[0-9][0-9]?m/g, ""), unstyledLength: (str) => str.replace(/\x1B\[[0-9][0-9]?m/g, "").length, link: (str) => color.underline(color.blue(str)) }))( (c1) => isBrowser ? Identity : (str) => `\x1B[${c1}m${str.replace(/\x1B\[39m/g, `\x1B[${c1}m`)}\x1B[39m`, (c1, c2) => isBrowser ? Identity : (str) => `\x1B[${c1}m${str}\x1B[${c2}m` ); function Map_get(map, key, init) { if (!map.has(key)) map.set(key, init(key)); return map.get(key); } function isEmpty(array) { return 0 === array.length; } function Array_splice(array, target, index = array.indexOf(target)) { array.splice(index, 1); } function Array_replace(array, target, ...replacements) { array.indexOf(target); array.splice(array.indexOf(target), 1, ...replacements); } function has_key_defined(o, k) { return k in o && void 0 !== o[k]; } function is_array(data) { return Array.isArray(data); } function each(data, callback) { switch (data.constructor) { case Array: { let i = 0; for (; i < data.length; i++) callback(data[i], i); return; } case Object: { let k; for (k in data) callback(data[k], k); return; } case Set: { let d; for (d of data) callback(d, void 0); return; } case Map: { let e; for (e of data) callback(e[1], e[0]); return; } default: { let x; for (x of data) callback(x, void 0); return; } } } function iLast(index, array) { return 1 + index === array.length; } function try_eval(fn) { try { return fn(); } catch (e) { return void 0; } } function clamp(min, max, value) { return value > min ? value < max ? value : max : min; } function flat(arr) { return arr.flat(Infinity); } function map_tagged_template(args, map) { const arr = [args[0][0]]; for (var i = 1; i < args.length; i++) arr.push(map(args[i]), args[0][i]); return arr; } function spliceAll(array) { const r = [...array]; array.length = 0; return r; } function spread(fn) { return [...fn()]; } var { join, line, softline, hardline, literalline, group, conditionalGroup, fill, lineSuffix, lineSuffixBoundary, cursor, breakParent, ifBreak, trim, indent, indentIfBreak, align, addAlignmentToDoc, markAsRoot, dedentToRoot, dedent, hardlineWithoutBreakParent, literallineWithoutBreakParent, label } = doc.builders; var { isConcat, getDocParts, willBreak, traverseDoc, findInDoc, mapDoc, propagateBreaks, removeLines, stripTrailingHardline, normalizeParts, normalizeDoc, cleanDoc, canBreak } = doc.utils; var Symbol_comments = Symbol.for("comments"); var DCM = /* @__PURE__ */ ((DCM2) => { DCM2["arguments"] = "arguments"; DCM2["parameters"] = "parameters"; DCM2["items"] = "items"; DCM2["properties"] = "properties"; DCM2["members"] = "members"; DCM2["body"] = "body"; DCM2["cases"] = "cases"; DCM2["typeArguments"] = "typeArguments"; DCM2["ltParameters"] = "ltParameters"; DCM2["generics"] = "generics"; DCM2["specifiers"] = "specifiers"; DCM2["rules"] = "rules"; DCM2["match"] = "match"; DCM2["transform"] = "transform"; DCM2["segments"] = "segments"; return DCM2; })(DCM || {}); // src/format/complexity.ts var DEPTH = 0; var ANCESTRY = []; var LONE_SHORT_ARGUMENT_THRESHOLD_RATE = 0.25; function withCheckContext(fn) { if (0 === DEPTH) { return fn(); } else { DEPTH = 0; const prev = spliceAll(ANCESTRY); try { return fn(); } finally { DEPTH = ANCESTRY.push(...prev); } } } function is_short(str) { return str.length <= LONE_SHORT_ARGUMENT_THRESHOLD_RATE * getOptions().printWidth; } function print(target) { const current = getNode(); const keys = [...getAstPath(ANCESTRY[0], getNode())]; for (let i = 1; i < ANCESTRY.length; i++) keys.push(...getOwnChildAstPath(ANCESTRY[i - 1], ANCESTRY[i])); keys.push(...getOwnChildAstPath(last_of(ANCESTRY), target)); try { return getContext().path.call(() => getPrintFn()(), ...keys); } catch (e) { console.log({ current, target, keys, ANCESTRY }); throw e; } } function IsSimpleFunction(fn) { return function(node) { if (0 !== DEPTH && node === ANCESTRY[DEPTH - 1]) { return fn(node); } if (DEPTH >= 2) { return isShortBasic(node); } try { return fn(ANCESTRY[DEPTH++] = node); } finally { ANCESTRY.length = --DEPTH; } }; } function HasComplexFunction(fn) { return function(node) { if (0 !== DEPTH && node === ANCESTRY[DEPTH - 1]) { return fn(node); } if (DEPTH >= 2) { return !isShortBasic(node); } try { return fn(ANCESTRY[DEPTH++] = node); } finally { ANCESTRY.length = --DEPTH; } }; } var isShortBasic = (node) => { switch (node.nodeType) { case NodeType.MissingNode: return true; case NodeType.Identifier: case NodeType.Index: case NodeType.LtIdentifier: case NodeType.LbIdentifier: case NodeType.McIdentifier: return is_short(node.name); case NodeType.Literal: return is_short(node.value) && !/\n/.test(node.value); } return false; }; var isSimpleType = IsSimpleFunction((node) => { switch (node.nodeType) { case NodeType.MissingNode: case NodeType.FunctionSpread: return true; case NodeType.MacroInvocation: return false; case NodeType.Identifier: case NodeType.TypeNever: case NodeType.TypeInferred: return true; case NodeType.TypePath: return isShortBasic(node.segment) && (!node.namespace || isSimpleType(node.namespace)); case NodeType.TypeCall: return isSimpleType(node.typeCallee) && !hasComplexTypeArguments(node); case NodeType.ExpressionTypeSelector: return isSimpleType(node.typeTarget) && (!node.typeExpression || isSimpleType(node.typeExpression)); case NodeType.TypeDynBounds: return !hasComplexTypeBounds(node); case NodeType.TypeImplBounds: return !hasComplexTypeBounds(node); case NodeType.TypeFnPointer: { const param = node.parameters[0]; return (!node.extern || !node.extern.abi || isShortBasic(node.extern.abi)) && !hasComplexLtParameters(node) && (node.parameters.length === 0 || node.parameters.length === 1 && (is_FunctionSpread(param) || !is_TypeFunctionNode(param.typeAnnotation) && isSimpleType(param.typeAnnotation))) && (!node.returnType || isSimpleType(node.returnType)); } case NodeType.TypeFunction: return isSimpleType(node.callee) && node.parameters.every(isSimpleType) && (!node.returnType || isSimpleType(node.returnType)); case NodeType.TypeSizedArray: return isSimpleType(node.typeExpression) && isShortBasic(node.sizeExpression); case NodeType.TypeSlice: return isSimpleType(node.typeExpression); case NodeType.TypeTuple: return node.items.length === 0 || node.items.length === 1 && isSimpleType(node.items[0]); case NodeType.TypeReference: case NodeType.TypeDereferenceMut: case NodeType.TypeDereferenceConst: case NodeType.TypeParenthesized: return isSimpleType(node.typeExpression); default: return false; } }); var hasComplexTypeBounds = HasComplexFunction((node) => { return !!node.typeBounds && node.typeBounds.length > 1 && !node.typeBounds.every(isSimpleTypeBound); }); var isSimpleTypeBound = (node) => { switch (node.nodeType) { case NodeType.TypeParenthesized: return isSimpleTypeBound(node.typeExpression); case NodeType.LtIdentifier: case NodeType.LtElided: case NodeType.LtStatic: return true; case NodeType.TypeTraitBound: return is_BareTypeTraitBound(node) && isSimpleTypeNamespaceTargetNoSelector(node.typeExpression); default: return false; } function isSimpleTypeNamespaceTargetNoSelector(node2) { switch (node2.nodeType) { case NodeType.Identifier: return true; case NodeType.TypePath: return void 0 === node2.namespace || isSimpleTypeNamespaceTargetNoSelector(node2.namespace); case NodeType.TypeCall: return false; case NodeType.TypeFunction: return isSimpleTypeNamespaceTargetNoSelector(node2.callee) && node2.parameters.length === 0 && !node2.returnType; default: return false; } } }; var hasComplexTypeArguments = HasComplexFunction( (node) => !node.typeArguments || node.typeArguments.length === 0 ? false : node.typeArguments.length === 1 ? (() => { const arg = node.typeArguments[0]; return is_TypeBoundsStandaloneNode(arg) || canBreak(print(arg)); })() : true ); var hasComplexLtParameters = HasComplexFunction((node) => { const ltParameters = node.ltParameters; if (!ltParameters || ltParameters.length === 0) { return false; } if (ltParameters.length === 1) { const arg = ltParameters[0]; if (arg.ltBounds && arg.ltBounds.length > 1) { return true; } return false; } return true; }); var isShortGenericParameterDeclaration = IsSimpleFunction((node) => { switch (node.nodeType) { case NodeType.GenericTypeParameterDeclaration: return !node.typeBounds && !node.typeDefault; case NodeType.ConstTypeParameterDeclaration: return (!node.typeAnnotation || is_MissingNode(node)) && !node.typeDefault; case NodeType.GenericLtParameterDeclaration: return !node.ltBounds; default: exit.never(); } }); var hasComplexGenerics = HasComplexFunction((node) => { return has_key_defined(node, "generics") && node.generics.length > 0 && !node.generics.every(isShortGenericParameterDeclaration); }); var hasComplexTypeAnnotation = HasComplexFunction((node) => { if (is_VariableDeclarationNode(node) && !is_LetScrutinee(node)) { const { typeAnnotation } = node; return !!typeAnnotation && !is_MissingNode(typeAnnotation) && !isSimpleType(typeAnnotation); } else { return false; } }); function isIdent(node, name) { return !!node && is_Identifier(node) && node.name === name; } function isToken(node, tk) { return !!node && isTK(node, tk); } function isGroup(node, dk) { return !!node && is_DelimGroup(node) && node.segments.dk === dk; } // src/format/macros/cfg_if.ts function transform_macro_cfg_if(segments) { const danglingAttributes = []; const comments = []; const block = function create_if_block(i) { if (i >= segments.length) return void 0; const _if = segments[i]; const pound = segments[i + 1]; const grp = segments[i + 2]; const block2 = segments[i + 3]; const _else = segments[i + 4]; assert( isIdent(_if, "if") && isToken(pound, TK["#"]) && isGroup(grp, DelimKind["[]"]) && isGroup(block2, DelimKind["{}"]) && (!_else || isIdent(_else, "else")) ); return create_block( block2, (body) => rs.mockNode(NodeType.IfBlockExpression, block2.loc.cloneFrom(start(_if)), { label: void 0, condition: rs.mockNode(NodeType.Attribute, grp.loc.cloneFrom(start(pound)), { segments: grp.segments, value: grp.segments.loc.sliceText(), line: false, inner: false }), body, else: (_else && iLast(i + 5, segments) ? function create_else_block(i2) { const block3 = segments[i2]; assert(isGroup(block3, DelimKind["{}"])); return create_block( block3, (body2) => rs.mockNode(NodeType.BlockExpression, body2.loc.clone(), { label: void 0, body: body2 }) ); } : create_if_block)(i + 5) }) ); }(0); const ast = rs.createLocArray( segments.dk, segments.loc, block && [ rs.mockNode(NodeType.ExpressionStatement, block.loc.clone(), { expression: block, semi: false }) ] ); return rs.mockNode(NodeType.Snippet, segments.loc.clone(), { ast, danglingAttributes, comments }); function create_block(group2, fn) { const snippet = rs.toBlockBody(group2.segments); insertNodes(danglingAttributes, snippet.danglingAttributes); insertNodes(comments, snippet.comments); const block2 = fn(snippet.ast); transferAttributes(snippet, block2); return block2; } } // src/format/transform.ts function is_CallLikeMacroInvocation(node) { return is_MacroInvocation(node) && "arguments" in node; } function is_BlockLikeMacroInvocation(node) { return is_MacroInvocation(node) && "body" in node; } function is_CallExpression_or_CallLikeMacroInvocation(node) { return is_CallExpression(node) || is_CallLikeMacroInvocation(node); } var IGNORED_MACROS = /* @__PURE__ */ new Set([ "quote" ]); var HARDCODED_MACRO_DELIMS = /* @__PURE__ */ new Map(); each( { [DelimKind["{}"]]: [ "thread_local", "cfg_if" ], [DelimKind["()"]]: [ "assert_eq", "assert_ne", "assert", "cfg", "concat_bytes", "concat_idents", "concat", "debug_assert_eq", "debug_assert_ne", "debug_assert", "eprint", "eprintln", "format_args_nl", "format_args", "format", "matches", "panic", "print", "println", "try", "unimplemented", "unreachable", "write", "writeln" ], [DelimKind["[]"]]: [ "vec" ] }, (names, tk) => each(names, (name) => { HARDCODED_MACRO_DELIMS.set(name, +tk); }) ); var _COMMENTS = void 0; var _DANGLING_ATTRIBUTES = void 0; function transform_ast(options2) { try { _COMMENTS = options2.comments; _DANGLING_ATTRIBUTES = options2.danglingAttributes; transformNode(options2.rsParsedFile); } finally { _depth = 0; _COMMENTS = void 0; _DANGLING_ATTRIBUTES = void 0; } } var _depth = 0; var isReadingSnippet = () => 0 !== _depth; function maybe_transform_node(node, read_snippet, fn) { const snippet = try_eval(read_snippet); if (snippet) { ++_depth; transformNode(snippet); --_depth; fn(node, snippet); transformed.add(node); return node; } } var transformed = /* @__PURE__ */ new WeakSet(); function isTransformed(node) { return transformed.has(node); } var transform = { [NodeType.Attribute](node) { maybe_transform_node( node, () => rs.toCallExpressionArguments(node.segments), (node2, snippet) => { node2.segments = snippet.ast; } ); }, [NodeType.MacroInlineRuleDeclaration](node) { node.match.dk = DelimKind["()"]; node.transform.dk = DelimKind["{}"]; }, [NodeType.MacroInvocation](node) { const name = getMacroName(node); if (IGNORED_MACROS.has(name) || node.segments.length === 0 || node.segments.length === 1 && is_PunctuationToken(node.segments[0])) { return; } const tk = transformMacroDelim(name, node); if (name === "cfg_if") { transformBlockLike(() => transform_macro_cfg_if(node.segments)); } else if (tk === DelimKind["{}"]) { transformBlockLike(); } else { transformCallLike(); } function transformBlockLike(transform2 = () => rs.toBlockBody(node.segments)) { return maybe_transform_node(node, transform2, (node2, snippet) => { const _body = snippet.ast; _body.dk = tk; node2.body = _body; node2.segments = _body; transferAttributes(snippet, node2); }); } function transformCallLike() { return maybe_transform_node( node, () => rs.toCallExpressionArguments(node.segments), (node2, snippet) => { const _arguments = snippet.ast; _arguments.dk = tk; node2.method = void 0; node2.typeArguments = void 0; node2.arguments = _arguments; node2.segments = _arguments; } ); } }, [NodeType.CallExpression](node) { if (hasMethod(node)) { node.callee = rs.mockNode(NodeType.MemberExpression, node.method.loc.cloneFrom(start(node.callee)), { expression: node.callee, property: node.method, computed: false }); node.method = void 0; getOptions().actuallyMethodNodes.add(node.callee); } }, [NodeType.AutoTraitDeclaration](node) { mockBodyNoBody(node); }, [NodeType.NegativeImplDeclaration](node) { mockBodyNoBody(node); }, [NodeType.StructLiteral](node) { moveSpreadsToEnd(node); }, [NodeType.StructPattern](node) { moveSpreadsToEnd(node); } }; function moveSpreadsToEnd(node) { const props = node.properties; if (props.some((p, i, a) => is_StructSpread(p) && !iLast(i, a))) { const spreads = []; for (let i = 0; i < props.length; i++) { const prop = props[i]; if (is_StructSpread(prop)) { Array_splice(props, prop, i--); spreads.push(prop); } } props.push(...spreads); } } function mockBodyNoBody(node) { node.body = rs.createLocArray(last_of(rs.toTokens(node).ast).loc.clone(), DelimKind["{}"]); } function transformMacroDelim(name, node) { if (HARDCODED_MACRO_DELIMS.has(name)) { return HARDCODED_MACRO_DELIMS.get(name); } if (node.segments.dk === DelimKind["{}"] && includesTK(node, TK[","])) { return DelimKind["()"]; } if (node.segments.dk === DelimKind["()"] && includesTK(node, TK[";"])) { return DelimKind["{}"]; } return node.segments.dk; } var seen = /* @__PURE__ */ new WeakSet(); function transformNode(node, parent, key, index) { var _a; if (!seen.has(node)) { seen.add(node); if (is_Snippet(node) || is_Program(node)) { registerPogramLike(node); } each_childNode(node, transformNode); insert_blocks(node, parent, key, index); (_a = transform[node.nodeType]) == null ? void 0 : _a.call(transform, node); flatten_typeBounds(node); transform_nodeAttributes(node); } return node; } function insert_blocks(node, parent, key, index) { if (parent && key) { if (!is_ExpressionStatement(parent) && (is_FlowControlExpression(node) || !isReadingSnippet() && is_ReassignmentNode(node) && !(is_ReassignmentNode(parent) && parent.left === node))) { reassignNodeProperty(blockify(node), parent, key, index); } else if (is_ClosureFunctionExpression(node) && (!!node.returnType && !is_BlockExpression(node.expression) || is_ExpressionWithBodyOrCases(node.expression) && !is_BlockExpression(node.expression) && !is_IfBlockExpression(node.expression))) { node.expression = blockify(node.expression); } } function blockify(node2) { const block = rs.mockNode(NodeType.BlockExpression, node2.loc.clone(), { label: void 0, body: rs.createLocArray(DelimKind["{}"], node2.loc.clone(), [ rs.mockNode(NodeType.ExpressionStatement, node2.loc.clone(), { semi: false, expression: node2 }) ]) }); transferAttributes(node2, block); return block; } } function flatten_typeBounds(topNode) { if (hasTypeBounds(topNode)) { const nestedBounds = topNode.typeBounds.filter(isBoundWithNestedBounds); const [first, ...subsequent] = nestedBounds; const flatten = (bound) => Array_replace(topNode.typeBounds, bound, ...bound.typeExpression.typeBounds); if (nestedBounds.every(isBareBoundWithNestedBoundsNoPrefix)) { each(nestedBounds, flatten); } else if (!hasDefinedPrefix(topNode) && first === topNode.typeBounds[0] && !isBareBoundWithNestedBoundsNoPrefix(first) && subsequent.every(isBareBoundWithNestedBoundsNoPrefix)) { if (is_TypeDynBounds(topNode)) { if (is_TypeImplBounds(first.typeExpression)) { unsafe_set_nodeType(topNode, NodeType.TypeImplBounds); } else { topNode.dyn = true; } each(nestedBounds, flatten); } else { each(subsequent, flatten); first.typeExpression.typeBounds.push(...topNode.typeBounds.slice(1)); topNode.typeBounds.length = 1; } } } function isBoundWithNestedBounds(bound) { return is_TypeTraitBound(bound) && is_TypeBoundsStandaloneNode(bound.typeExpression); } function isBareBoundWithNestedBounds(bound) { return isBoundWithNestedBounds(bound) && is_BareTypeTraitBound(bound); } function isBareBoundWithNestedBoundsNoPrefix(bound) { return isBareBoundWithNestedBounds(bound) && !hasDefinedPrefix(bound.typeExpression); } function hasDefinedPrefix(node) { return is_TypeDynBounds(node) && node.dyn || is_TypeImplBounds(node); } } function transform_nodeAttributes(node) { if (hasAttributes(node)) { const attrs = node.attributes; for (let i = 0; i < attrs.length; i++) { const attr = attrs[i]; if (isReadingSnippet() && is_DocCommentAttribute(attr)) { const index = binarySearchIn(_COMMENTS, start(attr), start); _COMMENTS.splice(index, 1); } if (attr.inner) { if (isPrettierIgnoreAttribute(attr)) { setPrettierIgnoreTarget(is_Program(node) ? node.loc.src : node, attr); } insertNode(is_Snippet(node) ? node.ast : getBodyOrCases(node), attr); Array_splice(attrs, attr, i--); } } if (attrs.length === 0) { deleteAttributes(node); } } } function registerPogramLike(program) { const comments = spliceAll(program.comments); const danglingAttributes = spliceAll(program.danglingAttributes); for (let i = 0; i < danglingAttributes.length; i++) { const attr = danglingAttributes[i]; if (is_DocCommentAttribute(attr)) { if (isReadingSnippet()) { const index = binarySearchIn(_COMMENTS, start(attr), start); _COMMENTS.splice(index, 1); } } else { transformNode(danglingAttributes[i], program, "danglingAttributes", i); } } if (!isReadingSnippet()) insertNodes(_COMMENTS, comments); insertNodes(_DANGLING_ATTRIBUTES, danglingAttributes); } var CommentChildNodes = /* @__PURE__ */ new WeakMap(); function getCommentChildNodes(n) { const children = Map_get(CommentChildNodes, n, getTransformedNodeChildren); if (is_NodeWithBodyOrCases(n) || is_BlockLikeMacroInvocation(n)) { for (let i = 0; i < children.length; i++) { const attr = children[i]; if (is_AttributeOrDocComment(attr)) { const target = children.find((n2) => start(n2) <= start(attr) && ownStart(n2) >= end(attr)); if (target) { children.splice(i--, 1); insertNode(Map_get(CommentChildNodes, target, getTransformedNodeChildren), attr); } } } } return children; function getTransformedNodeChildren(node) { if (is_Program(node)) node.comments ?? (node.comments = []); const children2 = getNodeChildren(node); if (is_NodeWithBodyNoBody(node)) { insertNodes(children2, node.body); } return children2; } } // src/format/styling.ts function needsOuterSoftbreakParens(node) { const parent = getParentNode(); if (!parent) return false; if (is_ExpressionAsTypeCast(node)) { return precedenceNeedsParens(node, parent); } if (is_FlowControlMaybeValueExpression(parent) && parent.expression === node && flowControlExpressionNeedsOuterParens(parent)) { return true; } if (is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(node) && (is_MemberExpression(parent) && parent.expression === node || is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(parent) && !is_ElseBlock(node, parent))) { return true; } if (is_UnionPattern(node) && is_NodeWithMaybePatternNoUnionBody(parent)) { return true; } if (hasComment(node)) { if (is_UnaryExpression(parent)) { return true; } if (hasComment(node, 32 /* Line */)) { if (is_ReturnExpression(parent) || is_YieldExpression(parent) && parent.expression === node) { return true; } } if (hasComment(node, 2 /* Leading */, (comment) => is_Attribute(comment) && !comment.inner) && !can_have_OuterAttributes(node, parent, true)) { return true; } } return false; } function needsInnerParens(node) { if (needsOuterSoftbreakParens(node)) { return false; } const parent = getParentNode(); if (!parent) { return false; } if (is_Identifier(node)) { return false; } if (is_Literal(node)) { return is_LiteralNumberLike(node) && is_MemberExpression(parent) && node === parent.expression; } if (is_CallExpression(parent) && parent.callee === node && is_MemberExpression(node)) { return !getOptions().actuallyMethodNodes.has(node); } if (is_ReassignmentNode(node)) { if (is_printing_macro()) { return false; } if (is_ClosureFunctionExpression(parent) && node === parent.expression) { return true; } if (is_ExpressionStatement(parent)) { return is_StructLiteral(node.left); } if (is_ReassignmentNode(parent)) { return false; } return true; } if (is_ParenthesizedNode(parent)) { return false; } if (is_ExpressionStatement(parent)) { return false; } if (is_RangeLiteral(node)) { return is_ExpressionAsTypeCast(parent) || is_LogicalExpression(parent) || is_UnaryExpression(parent) || is_PostfixExpression(parent) || is_MemberExpression(parent) && node === parent.expression || is_CallExpression(parent) && node === parent.callee || is_OperationExpression(parent) || is_ComparisonExpression(parent); } if (is_LetScrutinee(parent) && is_LogicalExpression(node) && parent.expression === node) { return true; } if (is_UnaryExpression(node)) { switch (parent.nodeType) { case NodeType.MemberExpression: case NodeType.AwaitExpression: return node === parent.expression; case NodeType.CallExpression: return node === parent.callee; default: return false; } } if (is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(node)) { if (is_ExpressionWithBodyOrCases(parent)) { return !is_ElseBlock(node, parent); } if (is_LetScrutinee(parent) && parent.expression === node && is_ExpressionWithBodyOrCases(getGrandParentNode())) { return true; } return is_ExpressionAsTypeCast(parent) || is_LogicalExpression(parent) || is_UnaryExpression(parent) || is_PostfixExpression(parent) || is_MemberExpression(parent) && node === parent.expression || is_CallExpression(parent) && node === parent.callee || is_OperationExpression(parent) || is_ComparisonExpression(parent) || is_RangeLiteral(parent); } if (is_StructLiteral(node)) { if (is_ExpressionWithBodyOrCases(parent)) { return true; } if (is_LetScrutinee(parent) && parent.expression === node && is_ExpressionWithBodyOrCases(getGrandParentNode())) { return true; } if (is_UnaryExpression(parent) || is_PostfixExpression(parent) || is_MemberExpression(parent)) { return parent.expression === node; } if (is_CallExpression(parent)) { return parent.callee === node; } } if (is_LogicalExpression(node) || is_OperationExpression(node) || is_ComparisonExpression(node) || is_ClosureFunctionExpression(node)) { return precedenceNeedsParens(node, parent); } if (is_TypeFunctionNode(node)) { const gp = getGrandParentNode(); if (node.returnType && is_TypeTraitBound(parent) && is_TypeBoundsStandaloneNode(gp) && last_of(gp.typeBounds) !== parent) { return true; } } if (is_TypeBoundsStandaloneNode(node)) { return is_UnaryType(parent) && node.typeBounds.length > 1 || is_TypeBoundsStandaloneNode(parent) || is_TypeTraitBound(parent) || is_TypeFunctionNode(parent) && parent.returnType === node; } if (is_PatternVariableDeclaration(parent)) { return is_UnionPattern(node); } return false; } function precedenceNeedsParens(node, parent) { if (is_UnaryExpression(parent) || is_PostfixExpression(parent)) return true; if (is_ReassignmentNode(parent)) return parent.left === node; if (is_MemberExpression(parent)) return parent.expression === node; if (is_CallExpression(parent)) return parent.callee === node; if (is_ExpressionAsTypeCast(parent)) return !is_ExpressionAsTypeCast(node); if (is_LogicalExpression(parent)) return is_LogicalExpression(node) ? parent.nodeType !== node.nodeType : evalPrecedence(node, parent); if (is_OperationExpression(parent) || is_ComparisonExpression(parent)) return evalPrecedence(node, parent); return false; function evalPrecedence(child, parent2) { if (is_ExpressionAsTypeCast(child) || is_ClosureFunctionExpression(child)) { return true; } function getPrec(node2, bool) { return getPrecedence(node2, bool); } const childPRCD = getPrec(child, is_insideScrutinee(child)); const parentPRCD = getPrec(parent2, is_insideScrutinee(parent2)); if (parentPRCD > childPRCD) { return true; } if (parentPRCD === childPRCD && parent2.right === child) { return true; } if (parentPRCD === childPRCD && !shouldFlatten(parent2, child)) { return true; } if (parentPRCD < childPRCD && child.tk === TK["%"]) { return parentPRCD === PRCD["+-"]; } if (is_BitwiseOperator(parent2.tk) || is_BitwiseOperator(child.tk) && is_EqualityOperator(parent2.tk)) { return true; } return false; } } function shouldFlatten(parent, node) { if (getPrecedence(node, is_insideScrutinee(node)) !== getPrecedence(parent, is_insideScrutinee(parent))) return false; if (is_ComparisonExpression(parent) && is_ComparisonExpression(node)) return false; if (is_OperationExpression(parent) && is_OperationExpression(node)) { if (node.tk === TK["%"] && is_multiplicativeOperator(parent.tk) || parent.tk === TK["%"] && is_multiplicativeOperator(node.tk) || node.tk !== parent.tk && is_multiplicativeOperator(node.tk) && is_multiplicativeOperator(parent.tk) || is_bitshiftOperator(node.tk) && is_bitshiftOperator(parent.tk)) return false; } return true; } function needsParens(node) { return needsOuterSoftbreakParens(node) || needsInnerParens(node); } function stmtNeedsSemi(stmt, disregardExprType = false) { return pathCallParentOf(stmt, (parent) => needsSemi(parent, stmt, disregardExprType)); } var NoNode = { nodeType: 0 }; function needsSemi(parent, stmt, disregardExprType = false) { const expr = disregardExprType ? NoNode : stmt.expression; const hadSemi = !disregardExprType && stmt.semi; return !!expr && (forcePreserveSemi() ? true : shouldNeverSemi() ? false : shouldPreserveSemi() ? hadSemi || shouldAlwaysSemi() || canAutoCompleteSemi() : true); function forcePreserveSemi() { return hadSemi && stmt === last_of(parent.body) && (is_IfBlockExpression(expr) && hasLetScrutineeCondition(expr) && !(is_LetScrutinee(expr.condition) && is_Identifier(expr.condition.expression)) || is_MatchExpression(expr) && !is_Identifier(expr.expression)); } function shouldNeverSemi() { return is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(expr); } function shouldPreserveSemi() { return stmt === last_of(parent.body) && (is_ImplicitReturnAbleNode(parent) || is_BlockLikeMacroInvocation(parent)); } function shouldAlwaysSemi() { return is_FlowControlExpression(expr) || is_ReassignmentNode(expr); } function canAutoCompleteSemi() { return withPathAt(parent, function checkParent(child) { return pathCallParentOf(child, (parent2) => { if (is_IfBlockExpression(parent2) && parent2.else === child) { return checkParent(parent2); } if (is_ExpressionStatement(parent2)) { if (hasOuterAttributes(parent2)) return false; return stmtNeedsSemi(parent2, true); } if (is_MatchExpressionCase(parent2) && parent2.expression === child) { return pathCallParentOf(parent2, checkParent); } return false; }); }); } } function canInlineBlockBody(node) { if (!is_ExpressionWithBody(node)) { return false; } const body = node.body; if (body.length === 0) { return canInlineInlineable(node); } if (body.length === 1) { const stmt = body[0]; if (is_AttributeOrDocComment(stmt)) { return true; } if (is_ExpressionStatement(stmt) && !needsSemi(node, stmt)) { const expr = stmt.expression; if (is_FlowControlExpression(expr) || is_ClosureFunctionExpression(expr) || is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(expr)) { return false; } return canInlineInlineable(node); } } return false; } function canInlineInlineable(node) { if (is_ForInBlockExpression(node) || is_LoopBlockExpression(node)) { return false; } if (is_WhileBlockExpression(node)) { return true; } const parent = getParentNode(); if (is_ExpressionStatement(parent) && (!is_ImplicitReturnAbleNode(node) || pathCallAtParent(parent, (parent2) => stmtNeedsSemi(parent2, true)))) { return false; } if (is_ElseBlock(node, parent)) { return pathCallAtParent(parent, canInlineBlockBody); } if (is_IfBlockExpression(node)) { if (!node.else || is_ExpressionWithBodyOrCases_or_BlockLikeMacroInvocation(node.condition) || willBreak(getPrintFn()("condition"))) { return false; } const grandparent = getGrandParentNode(); if (is_ExpressionStatement(parent) && hasBody(grandparent) && grandparent.body.length > 1) { return false; } } return true; } function emptyContent(node) { switch (node.nodeType) { case NodeType.Program: case NodeType.MacroRulesDeclaration: case NodeType.MacroDeclaration: case NodeType.ExternBlockDeclaration: case NodeType.ModuleDeclaration: case NodeType.TraitDeclaration: case NodeType.StructDeclaration: case NodeType.MacroInvocation: case NodeType.FunctionDeclaration: case NodeType.ImplDeclaration: case NodeType.UnionDeclaration: case NodeType.EnumDeclaration: case NodeType.EnumMemberStructDeclaration: case NodeType.StructLiteral: case NodeType.StructPattern: return ""; case NodeType.BlockExpression: case NodeType.WhileBlockExpression: case NodeType.ForInBlockExpression: case NodeType.TryBlockExpression: case NodeType.IfBlockExpression: return canInlineInlineable(node) ? is_IfBlockExpression(node) || is_ElseBlock(node, getParentNode()) ? softline : "" : hardline; case NodeType.LoopBlockExpression: case NodeType.MatchExpression: return hardline; default: if (is_NodeWithBodyNoBody(node)) { return ""; } return ""; } } function is_insideScrutinee(target) { return withPathAt(target, (n) => stackIncludes("condition") && r(n)); function r(CHILD) { switch (CHILD.nodeType) { case NodeType.OrExpression: case NodeType.AndExpression: return pathCallParentOf( CHILD, (PARENT) => hasCondition(PARENT) && PARENT.condition === CHILD ? hasLetScrutineeCondition(PARENT) : r(PARENT) ); case NodeType.LetScrutinee: return true; default: return false; } } } function withPathAt(target, callback) { if (target === getNode()) return callback(target); if (target === getParentNode()) return pathCallAtParent(target, () => callback(target)); if (stackIncludes(target)) return pathCallAtParent(getParentNode(), () => withPathAt(target, callback)); return getContext().path.call(() => { return callback(target); }, ...getAstPath(getNode(), target)); } function shouldPrintOuterAttributesAbove(node) { return is_StatementNode(node) || is_MatchExpressionCase(node) || hasAttributes(node) && node.attributes.some( canInlineOuterAttribute(node) ? (attr) => is_DocCommentAttribute(attr) || hasBreaklineAfter(attr) : is_DocCommentAttribute ); function canInlineOuterAttribute(node2) { return is_EnumMemberDeclaration(node2) || is_StructPropertyDeclaration(node2) || is_StructLiteralProperty(node2) || is_StructPatternProperty(node2); } } // src/format/core.ts function isNoopExpressionStatement(node) { return is_ExpressionStatement(node) && void 0 === node.expression && !hasAttributes(node) && !hasComment(node); } function is_xVariableEqualishLike(node) { switch (node.nodeType) { case NodeType.LetScrutinee: case NodeType.LetVariableDeclaration: case NodeType.ConstVariableDeclaration: case NodeType.StaticVariableDeclaration: case NodeType.TypeAliasDeclaration: case NodeType.TraitAliasDeclaration: return true; default: return false; } } function is_BinaryishExpression(node) { switch (node.nodeType) { case NodeType.OrExpression: case NodeType.AndExpression: case NodeType.OperationExpression: case NodeType.ComparisonExpression: return true; default: return false; } } function is_StructSpread(node) { switch (node.nodeType) { case NodeType.StructLiteralPropertySpread: case NodeType.StructLiteralRestUnassigned: case NodeType.RestPattern: return true; default: return false; } } function isConciselyPrintedArray(node) { return node.items.length > 1 && node.items.every( (element) => (is_LiteralNumberLike(element) || is_MinusExpression(element) && is_LiteralNumberLike(element.expression) && !hasComment(element.expression)) && !hasComment(element, 4 /* Trailing */ | 32 /* Line */, (comment) => !hasBreaklineBefore(comment)) ); } function printNumber(rawNumber) { return rawNumber.toLowerCase().replace(/^([\d.]+e)(?:\+|(-))?0*(\d)/, "$1$2$3").replace(/^(\d+)e[+-]?0+$/, "$1.0").replace(/^([\d.]+)e[+-]?0+$/, "$1").replace(/\.(\d+?)0+(?=e|$)/, ".$1").replace(/\.(?=e|$)/, ".0"); } function printOnOwnLine(node, printed) { return [printed, maybeEmptyLine(node)]; } function maybeEmptyLine(node) { return isNextLineEmpty(node) ? [hardline, hardline] : hardline; } function printBodyOrCases(print4, node) { const p = []; if (is_MatchExpression(node)) { pathCallEach(node, "cases", (mCase) => { p.push({ node: mCase, doc: is_MatchExpressionCase(mCase) && !is_ExpressionWithBodyOrCases(mCase.expression) ? [print4(), ","] : print4() }); }); } else { pathCallEach(node, "body", (stmt) => { if (!isNoopExpressionStatement(stmt)) { p.push({ node: stmt, doc: print4() }); } }); } const printed = bumpInnerAttributes(p).map( ({ doc: doc2, node: node2 }, i, a) => iLast(i, a) ? group(doc2) : printOnOwnLine(node2, group(doc2)) ); const comments = printDanglingCommentsForInline(node, "body" /* body */); if (comments) printed.push(comments); const ccomments = printDanglingCommentsForInline(node, "cases" /* cases */); if (ccomments) printed.push(ccomments); if (is_Program(node) && is_SourceFile(getParentNode()) && printed.length > 0 && !comments) { printed.push(hardline); } return printed; function bumpInnerAttributes(arr) { return arr.sort((a, b) => ownStart(a.node) - ownStart(b.node)); } } function printMacroRules(print4, node) { return !Array.isArray(node.rules) ? print4("rules") : node.rules.length > 0 ? [" {", indent([hardline, ...print4.join("rules", (rule) => maybeEmptyLine(rule))]), hardline, "}"] : [" {", printDanglingCommentsForInline(node, "rules" /* rules */) || emptyContent(node), "}"]; } function is_unary_token(item) { switch (item && is_PunctuationToken(item) ? item.tk : TK.None) { case TK["-"]: case TK["*"]: case TK["&"]: case TK["#"]: case TK["!"]: case TK["~"]: return true; case TK["?"]: return !/\s/.test(getOptions().originalText.charAt(end(item))); default: return false; } } function can_unary(node) { return (!is_PunctuationToken(node) || is_unary_token(node)) && (!is_MacroGroup(node) || is_optional_unary(node)); } function is_optional_token(item) { return !!item && is_MacroGroup(item) && item.kind === "?" && item.segments.length === 1 && is_PunctuationToken(item.segments[0]); } function is_optional_unary(item) { return is_optional_token(item) && is_unary_token(item.segments[0]); } function printRuleMatch(print4, rule) { return print_map(rule, "match"); function print_map(node, property) { const arr = node[property]; const shouldHug = should_hug(arr); const dline = arr.dk === DelimKind["{}"] ? line : shouldHug ? "" : softline; const isParamsLike = is_params_like(arr); const shouldBreak = should_break(arr); const d = getDelimChars(arr); if (arr.length === 0) return [d.left, printDanglingCommentsForInline(node, DCM[property]), d.right]; const printed = flat(print4.map_join(property, print_item, join_item)); return group([d.left, !dline ? printed : [indent([dline, printed]), dline], d.right], { shouldBreak, id: getMacroGroupId(node) }); function should_hug(arr2) { if (node === rule) return false; let has_nonToken = false; return arr2.every((item) => !is_MacroGroup(item) && (is_PunctuationToken(item) || has_nonToken !== (has_nonToken = true))); } function should_break(arr2) { let has_decl = false; return arr2.some( (item, i, a) => is_match_any(item) && arr2.length !== 1 || !iLast(i, a) && isDeclStart(item, a[i + 1]) && has_decl === (has_decl = true) ); } function print_item(item, index, arr2) { switch (item.nodeType) { case NodeType.Identifier: case NodeType.LtIdentifier: case NodeType.Literal: case NodeType.PunctuationToken: case NodeType.MacroParameterDeclaration: return print4(); case NodeType.MacroGroup: return printComments(["$", print_map(item, "segments"), print4("sep"), item.kind]); case NodeType.DelimGroup: return printComments(print_map(item, "segments")); } function printComment