1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
// SPDX-License-Identifier: MIT
// Copyright (c) 2026 Moderately AI Inc.
//! Pretty-printing SQL formatter (feature `document-render`).
//!
//! A layout-IR renderer that formats *from the validated AST*, not by re-tokenizing
//! and relaying out source text. That is the differentiator (ticket
//! `render-pretty-print-layout-ir`): the output is guaranteed to re-parse, layout is
//! dialect-aware, and it composes with the crate's other render modes. It is built
//! from four pieces:
//!
//! - [`doc`](crate::format::doc) — a Wadler/Prettier `Doc` combinator IR (`text` / `line` / `softline` /
//! `group` / `nest`) plus a width-aware layouter.
//! - [`comments`](crate::format::comments) — the trivia -> node [`CommentAttachments`](crate::format::comments::CommentAttachments) pass, so comments
//! captured out of band survive a format (leading / trailing / dangling), anchored
//! with the parser's opt-in clause marks.
//! - [`keyword_case`](crate::format::keyword_case) — the `keywordCase` post-pass (`upper` / `lower` / `preserve`).
//! - `render` — the pretty render path that emits the `Doc` tree, structuring the
//! statement list, `WITH`/CTEs, set operations, and `SELECT` clauses while
//! delegating expressions and exotic constructs to the canonical renderer.
//!
//! # Example
//!
//! ```
//! use squonk::BuiltinDialect;
//! use squonk::format::{format_sql, FormatOptions};
//!
//! let sql = "select a,b from t where a=1 and b=2";
//! let out = format_sql(sql, BuiltinDialect::Ansi, &FormatOptions::default()).unwrap();
//! assert!(out.contains("SELECT"));
//! ```
//!
//! # v1 support tier: stable surface vs preview
//!
//! The formatter ships as a **documented preview**, not a full-fidelity formatter.
//! One fixture per family in the `format::coverage` test module measures the exact
//! current behaviour of everything below; that inventory is the source of truth and any
//! future fix lands as a reviewable snapshot diff.
//!
//! ## Stable in v1 (guaranteed)
//!
//! - **Parse-back.** Formatted output always re-parses to a structurally equal tree —
//! unrecognised constructs fall back to the total canonical renderer, so nothing is
//! dropped or reshaped.
//! - **Spelling fidelity.** Every `PreserveSource`-tagged spelling round-trips (types,
//! literals — including `U&'…' UESCAPE '…'` string literals — and quote styles,
//! including the `U&"…" [UESCAPE '…']` Unicode-escaped *identifier* form):
//! fragments are canonical renders, so layout only moves whitespace.
//! - **Minimal-paren normalization.** The formatter emits the minimal parentheses the
//! binding-power table requires (the AST records no parenthesization; the structural
//! oracle proves semantic safety; prettier precedent).
//! - **Structured layout** of the statement list, `WITH`/CTEs, set operations, and the
//! `SELECT` clause skeleton (`SELECT`/`DISTINCT`, `FROM`, `WHERE`, `GROUP BY`,
//! `HAVING`, `ORDER BY`, `LIMIT`) — one clause per line, width-aware list breaking.
//! - **Recursive subquery re-layout.** A subquery in a structured position — a `FROM`
//! derived table, a scalar / `IN` / `EXISTS` / quantified predicate reachable in
//! `WHERE`/`HAVING` or the projection, and a CTE body — is re-laid out with the same
//! clause-per-line treatment, indented one level. A subquery whose structured layout
//! would still be a single line (`(SELECT 1)`) stays inline; one with an exotic body
//! falls back to a flat fragment (the completeness net). The threshold is structural
//! (does the layout carry a forced break?), not a size heuristic — see
//! `format::render`.
//! - **Style knobs:** indent width, max line length, keyword case
//! (`upper` / `lower` / `preserve`).
//! - **Position-stable comments.** Every captured comment renders at a stable position
//! near its source, and formatting is idempotent (`format(format(x)) == format(x)`):
//! - an end-of-line comment trailing a non-final list item stays with that item;
//! - a comment before a clause keyword anchors before the keyword (parser clause marks);
//! - a statement-boundary comment (leading a statement, between statements, or
//! trailing the last one) holds its boundary;
//! - a comment inside a re-laid-out subquery renders at its exact structured
//! position (e.g. trailing the projection item it followed);
//! - a comment anchored inside a *flattened* fragment (across an operator, in empty
//! parens, inside an inline-kept subquery, or inside a fallback statement) hoists
//! adjacent to the fragment that owns it rather than relocating to the output tail;
//! - a list-item comment written before its separating comma renders before the comma.
//!
//! ## Preview in v1 (NOT full-fidelity; each limitation has an owner ticket)
//!
//! Measured against `format::coverage`. The pretty path never drops a comment (the
//! no-drop safety net re-emits any it cannot place) and no longer relocates one to the
//! tail; the remaining gap is layout-depth:
//!
//! 1. **Deep expression re-layout** — nested *expressions* (long arithmetic / boolean
//! chains, function arguments, `CASE` arms) are embedded as single-line canonical
//! fragments, never re-laid out; this includes a subquery buried in a position the
//! re-layout pass does not reach (a function argument, a `CASE` arm, an `ORDER
//! BY`/`GROUP BY` item). A comment buried inside such a *flat* fragment renders
//! *adjacent* to the fragment (trailing it), not re-injected at its exact interior
//! column — adjacency is the fidelity ceiling for the unstructured fragment path,
//! while a comment inside a re-laid-out subquery now places exactly. Owner ticket
//! `formatter-structured-subquery-relayout` (subquery re-layout itself shipped
//! there; the expression-depth remainder stays with it).
//!
//! Comments are rendered from the out-of-band attachment table and never mutate the
//! AST, so structural equality is preserved regardless of placement.
pub use ;
pub use KeywordCase;
use crateNoExt;
use crateSourceStore;
use crateBuiltinDialect;
use crateParseError;
use crate;
/// The v1 style surface. Deliberately small (ticket point 4): indent width, max line
/// length, keyword case — explicitly **not** sql-formatter's full option catalog.
/// Format an already-parsed tree, applying `dialect` for the keyword-casing token
/// pass and for re-tokenizing fragments during subquery re-layout — pass the dialect
/// the tree was parsed under. Comments are formatted only when the parse captured
/// trivia ([`ParseConfig::capture_trivia`](crate::ParseConfig::capture_trivia)).
///
/// The tree must be the standard (`NoExt`) AST; the layouter reuses the canonical
/// renderer for expression fragments, so any spelling the canonical path preserves is
/// preserved here.
/// Parse `sql` under a runtime-selected built-in `dialect` (capturing trivia so
/// comments format) and pretty-print it. The one-shot string-to-string convenience
/// the language bindings wrap.