From 0c4ad31e13ce4b5d7022f604495b84b55d7331cd Mon Sep 17 00:00:00 2001 From: Steve Dignam Date: Fri, 2 Oct 2026 21:15:30 -0400 Subject: [PATCH 1/7] fmt: add check for spacing around comments --- crates/squawk_fmt/tests/tests.rs | 255 +++++++++++++++++++++++++++++++ 1 file changed, 255 insertions(+) diff --git a/crates/squawk_fmt/tests/tests.rs b/crates/squawk_fmt/tests/tests.rs index 07ce8b43..6010de00 100644 --- a/crates/squawk_fmt/tests/tests.rs +++ b/crates/squawk_fmt/tests/tests.rs @@ -22,6 +22,7 @@ fn fmt(fixture: Fixture<&str>) { assert_no_dropped_tokens(content, &formatted); assert_parses(&formatted); assert_no_extra_spaces(&formatted); + assert_comment_spacing(&formatted); assert_eq!( squawk_fmt::fmt_str(&formatted, Default::default()).unwrap(), formatted, @@ -179,6 +180,84 @@ fn assert_parses(formatted: &str) { ); } +fn comment_spacing_error(formatted: &str) -> Option<(std::ops::Range, &'static str)> { + let mut offset = 0; + let mut tokens = tokenize(formatted) + .map(|Token { kind, len }| { + let start = offset; + offset += len as usize; + (kind, start..offset) + }) + .filter(|(kind, _)| *kind != TokenKind::Whitespace) + .peekable(); + + let mut previous = None; + while let Some((kind, span)) = tokens.next() { + let left = previous.replace((kind, span.end)); + if !matches!( + kind, + TokenKind::LineComment | TokenKind::BlockComment { .. } + ) { + continue; + } + if let Some((previous, previous_end)) = left { + let touching = previous_end == span.start; + let must_touch = matches!(kind, TokenKind::BlockComment { .. }) + && matches!( + previous, + TokenKind::OpenParen | TokenKind::OpenBracket | TokenKind::OpenCurly + ); + if must_touch && !touching { + return Some(( + span, + "block comment must touch the opening delimiter on its left", + )); + } + if !must_touch && touching { + return Some((span, "comment must have whitespace on its left")); + } + } + if matches!(kind, TokenKind::BlockComment { .. }) + && let Some((next, next_span)) = tokens.peek() + { + let touching = span.end == next_span.start; + let must_touch = matches!( + next, + TokenKind::CloseParen + | TokenKind::CloseBracket + | TokenKind::CloseCurly + | TokenKind::Comma + | TokenKind::Semi + | TokenKind::OpenParen + | TokenKind::OpenBracket + | TokenKind::OpenCurly + ); + if must_touch && !touching { + return Some((span, "block comment must touch the delimiter on its right")); + } + if !must_touch && touching { + return Some((span, "block comment must have whitespace on its right")); + } + } + } + None +} + +fn comment_spacing_diagnostic(formatted: &str) -> Option { + let (span, message) = comment_spacing_error(formatted)?; + let snippet = Snippet::source(formatted) + .fold(true) + .annotation(AnnotationKind::Primary.span(span)); + let group = Level::ERROR.primary_title(message).element(snippet); + Some(Renderer::plain().render(&[group]).to_string()) +} + +fn assert_comment_spacing(formatted: &str) { + if let Some(diagnostic) = comment_spacing_diagnostic(formatted) { + panic!("{diagnostic}"); + } +} + fn assert_no_extra_spaces(formatted: &str) { let mut offset = 0; for Token { kind, len } in tokenize(formatted) { @@ -204,3 +283,179 @@ fn assert_no_extra_spaces(formatted: &str) { panic!("{}", Renderer::plain().render(&[group])); } } + +#[cfg(test)] +mod comment_spacing_test { + use insta::assert_snapshot; + + use crate::{assert_comment_spacing, comment_spacing_diagnostic}; + + /// Block & line comments do not need whitespace at file boundaries. + #[test] + fn file_boundaries() { + for sql in [ + "/* foo */", + "-- foo", + "/* foo */\nselect 1;\n/* bar */", + "-- foo\nselect 1;\n-- bar", + ] { + assert_comment_spacing(sql); + } + } + + /// Trailing line comments must have whitespace on their left. + #[test] + fn trailing_line_comments() { + assert_comment_spacing("select 1; -- comment"); + assert_snapshot!(comment_spacing_diagnostic("select 1;-- comment").unwrap(), @" + error: comment must have whitespace on its left + | + 1 | select 1;-- comment + | ^^^^^^^^^^ + "); + } + + /// Block comments must be surrounded with whitespace. + #[test] + fn block_comments_surrounded_by_whitespace() { + for sql in [ + "select 1 /*c*/ + 1;", + "create function f(v accounts.id /* c */ % /* c */ type) returns int language sql return 1;", + "table foo /* c */ *;", + "select * from graph_table(g match (a)-[e] /* c */ - /* c */ > (b) columns (a.id));", + "select 1 /* c */ ::int;", + "select (array[1, 2, 3])[1 /* c */ : /* c */ 2];", + ] { + assert_comment_spacing(sql); + } + assert_snapshot!(comment_spacing_diagnostic("select 1/*c*/ + 1;").unwrap(), @" + error: comment must have whitespace on its left + | + 1 | select 1/*c*/ + 1; + | ^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select 1 /*c*/+ 1;").unwrap(), @" + error: block comment must have whitespace on its right + | + 1 | select 1 /*c*/+ 1; + | ^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select foo(x)/* c */;").unwrap(), @" + error: comment must have whitespace on its left + | + 1 | select foo(x)/* c */; + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select foo(x,/* c */ y);").unwrap(), @" + error: comment must have whitespace on its left + | + 1 | select foo(x,/* c */ y); + | ^^^^^^^ + "); + } + + /// Block comments must have whitespace between them. + #[test] + fn between_block_comments() { + assert_comment_spacing("select 1 /* foo */ /* bar */;"); + assert_snapshot!(comment_spacing_diagnostic("select 1 /* foo *//* bar */;").unwrap(), @" + error: block comment must have whitespace on its right + | + 1 | select 1 /* foo *//* bar */; + | ^^^^^^^^^ + "); + } + + /// Block comments must touch `(`, `[`, `{` on their left. + #[test] + fn block_comments_touch_left_delimiters() { + for sql in [ + "select foo(/* c */ x);", + "select (array[1, 2, 3])[/* c */ 1];", + "select * from graph_table(g match (a)->{/* c */ 1, 3}(b) columns (a.id));", + ] { + assert_comment_spacing(sql); + } + assert_snapshot!(comment_spacing_diagnostic("select foo( /* c */ x);").unwrap(), @" + error: block comment must touch the opening delimiter on its left + | + 1 | select foo( /* c */ x); + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select (array[1, 2, 3])[ /* c */ 1];").unwrap(), @" + error: block comment must touch the opening delimiter on its left + | + 1 | select (array[1, 2, 3])[ /* c */ 1]; + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select * from graph_table(g match (a)->{ /* c */ 1, 3}(b) columns (a.id));").unwrap(), @" + error: block comment must touch the opening delimiter on its left + | + 1 | select * from graph_table(g match (a)->{ /* c */ 1, 3}(b) columns (a.id)); + | ^^^^^^^ + "); + } + + /// Block comments must touch `)`, `]`, `}`, `,`, `;`, `(`, `[`, `{` on their right. + #[test] + fn block_comments_touch_right_delimiters() { + for sql in [ + "select foo(x /* c */);", + "select foo(x /* c */, y);", + "select 1 /* c */;", + "create function f /* c */(a int) returns int language sql return 1;", + "select (array[1, 2, 3]) /* c */[1];", + "select * from graph_table(g match (a)-> /* c */{1, 3}(b) columns (a.id));", + ] { + assert_comment_spacing(sql); + } + assert_snapshot!(comment_spacing_diagnostic("select foo(x /* c */ );").unwrap(), @" + error: block comment must touch the delimiter on its right + | + 1 | select foo(x /* c */ ); + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select foo(x /* c */ , y);").unwrap(), @" + error: block comment must touch the delimiter on its right + | + 1 | select foo(x /* c */ , y); + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select 1 /* c */ ;").unwrap(), @" + error: block comment must touch the delimiter on its right + | + 1 | select 1 /* c */ ; + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select (array[1, 2, 3])[1 /* c */ ];").unwrap(), @" + error: block comment must touch the delimiter on its right + | + 1 | select (array[1, 2, 3])[1 /* c */ ]; + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select * from graph_table(g match (a)->{1, 3 /* c */ }(b) columns (a.id));").unwrap(), @" + error: block comment must touch the delimiter on its right + | + 1 | select * from graph_table(g match (a)->{1, 3 /* c */ }(b) columns (a.id)); + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("create function f /* c */ (a int) returns int language sql return 1;").unwrap(), @" + error: block comment must touch the delimiter on its right + | + 1 | create function f /* c */ (a int) returns int language sql return 1; + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select (array[1, 2, 3]) /* c */ [1];").unwrap(), @" + error: block comment must touch the delimiter on its right + | + 1 | select (array[1, 2, 3]) /* c */ [1]; + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select * from graph_table(g match (a)-> /* c */ {1, 3}(b) columns (a.id));").unwrap(), @" + error: block comment must touch the delimiter on its right + | + 1 | select * from graph_table(g match (a)-> /* c */ {1, 3}(b) columns (a.id)); + | ^^^^^^^ + "); + } +} From ebab670838db4e96afd44a47543547354e48b6ec Mon Sep 17 00:00:00 2001 From: Steve Dignam Date: Sat, 3 Oct 2026 12:37:50 -0400 Subject: [PATCH 2/7] fmt: add check comments with wrapping --- crates/squawk_fmt/tests/tests.rs | 225 ++++++++++++++++++++++--------- 1 file changed, 161 insertions(+), 64 deletions(-) diff --git a/crates/squawk_fmt/tests/tests.rs b/crates/squawk_fmt/tests/tests.rs index 6010de00..0ff8bd45 100644 --- a/crates/squawk_fmt/tests/tests.rs +++ b/crates/squawk_fmt/tests/tests.rs @@ -166,6 +166,27 @@ fn preserves_a_leading_bom() { ); } +#[test] +fn removes_leading_and_trailing_whitespace() { + for (sql, expected) in [ + ("\n\n\n\n select 1;\n\n\n", "select 1;\n"), + ("select 1; ", "select 1;"), + ("select 1; -- c\n\n\n", "select 1; -- c\n"), + ("select 1;\n\n/* c */\n\n", "select 1;\n\n/* c */\n"), + (" /* c */ select 1;", "/* c */ select 1;"), + (" -- c\nselect 1;", "-- c\nselect 1;"), + ("\n\n select 1;", "select 1;"), + ("\u{feff} /* c */ select 1;", "\u{feff}/* c */ select 1;"), + ] { + let formatted = squawk_fmt::fmt_str(sql, Default::default()).unwrap(); + assert_eq!(formatted, expected); + assert_eq!( + squawk_fmt::fmt_str(&formatted, Default::default()).unwrap(), + expected + ); + } +} + fn assert_parses(formatted: &str) { let parse = squawk_syntax::ast::SourceFile::parse(formatted); assert!( @@ -202,12 +223,26 @@ fn comment_spacing_error(formatted: &str) -> Option<(std::ops::Range, &'s } if let Some((previous, previous_end)) = left { let touching = previous_end == span.start; - let must_touch = matches!(kind, TokenKind::BlockComment { .. }) - && matches!( - previous, - TokenKind::OpenParen | TokenKind::OpenBracket | TokenKind::OpenCurly - ); - if must_touch && !touching { + let own_line = formatted[previous_end..span.start].contains(['\n', '\r']); + let after_opening_delimiter = matches!( + previous, + TokenKind::OpenParen | TokenKind::OpenBracket | TokenKind::OpenCurly + ); + if after_opening_delimiter && !own_line { + let wraps = kind == TokenKind::LineComment + || tokens.peek().is_some_and(|(_, next_span)| { + formatted[span.end..next_span.start].contains(['\n', '\r']) + }); + if wraps { + return Some(( + span, + "comment after an opening delimiter must be on its own line when the contents wrap", + )); + } + } + let must_touch = + matches!(kind, TokenKind::BlockComment { .. }) && after_opening_delimiter; + if must_touch && !touching && !own_line { return Some(( span, "block comment must touch the opening delimiter on its left", @@ -221,6 +256,7 @@ fn comment_spacing_error(formatted: &str) -> Option<(std::ops::Range, &'s && let Some((next, next_span)) = tokens.peek() { let touching = span.end == next_span.start; + let own_line = formatted[span.end..next_span.start].contains(['\n', '\r']); let must_touch = matches!( next, TokenKind::CloseParen @@ -228,11 +264,8 @@ fn comment_spacing_error(formatted: &str) -> Option<(std::ops::Range, &'s | TokenKind::CloseCurly | TokenKind::Comma | TokenKind::Semi - | TokenKind::OpenParen - | TokenKind::OpenBracket - | TokenKind::OpenCurly ); - if must_touch && !touching { + if must_touch && !touching && !own_line { return Some((span, "block comment must touch the delimiter on its right")); } if !must_touch && touching { @@ -293,14 +326,38 @@ mod comment_spacing_test { /// Block & line comments do not need whitespace at file boundaries. #[test] fn file_boundaries() { - for sql in [ - "/* foo */", - "-- foo", - "/* foo */\nselect 1;\n/* bar */", - "-- foo\nselect 1;\n-- bar", - ] { - assert_comment_spacing(sql); - } + assert_comment_spacing( + r"/* foo */ +select 1; +/* bar */", + ); + assert_comment_spacing( + r"-- foo +select 1; +-- bar", + ); + } + + /// Block and line comments are fine by themselves. + #[test] + fn own_line() { + assert_comment_spacing( + r" +-- foo +select 1; +/* foo */ +select 1;", + ); + } + + #[test] + fn delimiters_across_line_breaks() { + assert_comment_spacing( + r"create table t ( + /* a */ a int, + b int /* b */ +);", + ); } /// Trailing line comments must have whitespace on their left. @@ -318,16 +375,19 @@ mod comment_spacing_test { /// Block comments must be surrounded with whitespace. #[test] fn block_comments_surrounded_by_whitespace() { - for sql in [ - "select 1 /*c*/ + 1;", - "create function f(v accounts.id /* c */ % /* c */ type) returns int language sql return 1;", - "table foo /* c */ *;", - "select * from graph_table(g match (a)-[e] /* c */ - /* c */ > (b) columns (a.id));", - "select 1 /* c */ ::int;", - "select (array[1, 2, 3])[1 /* c */ : /* c */ 2];", - ] { - assert_comment_spacing(sql); - } + assert_comment_spacing( + r" +select 1 /*c*/ + 1; +create function f(v accounts.id /* c */ % /* c */ type) returns int language sql return 1; +table foo /* c */ *; +select * from graph_table(g match (a)-[e] /* c */ - /* c */ > (b) columns (a.id)); +select 1 /* c */ ::int; +select (array[1, 2, 3])[1 /* c */ : /* c */ 2]; +create function f /* c */ (a int) returns int language sql return 1; +select (array[1, 2, 3]) /* c */ [1]; +select * from graph_table(g match (a)-> /* c */ {1, 3}(b) columns (a.id)); +", + ); assert_snapshot!(comment_spacing_diagnostic("select 1/*c*/ + 1;").unwrap(), @" error: comment must have whitespace on its left | @@ -351,6 +411,24 @@ mod comment_spacing_test { | 1 | select foo(x,/* c */ y); | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("create function f /* c */(a int) returns int language sql return 1;").unwrap(), @" + error: block comment must have whitespace on its right + | + 1 | create function f /* c */(a int) returns int language sql return 1; + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select (array[1, 2, 3]) /* c */[1];").unwrap(), @" + error: block comment must have whitespace on its right + | + 1 | select (array[1, 2, 3]) /* c */[1]; + | ^^^^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select * from graph_table(g match (a)-> /* c */{1, 3}(b) columns (a.id));").unwrap(), @" + error: block comment must have whitespace on its right + | + 1 | select * from graph_table(g match (a)-> /* c */{1, 3}(b) columns (a.id)); + | ^^^^^^^ "); } @@ -369,13 +447,13 @@ mod comment_spacing_test { /// Block comments must touch `(`, `[`, `{` on their left. #[test] fn block_comments_touch_left_delimiters() { - for sql in [ - "select foo(/* c */ x);", - "select (array[1, 2, 3])[/* c */ 1];", - "select * from graph_table(g match (a)->{/* c */ 1, 3}(b) columns (a.id));", - ] { - assert_comment_spacing(sql); - } + assert_comment_spacing( + r" +select foo(/* c */ x); +select (array[1, 2, 3])[/* c */ 1]; +select * from graph_table(g match (a)->{/* c */ 1, 3}(b) columns (a.id)); +", + ); assert_snapshot!(comment_spacing_diagnostic("select foo( /* c */ x);").unwrap(), @" error: block comment must touch the opening delimiter on its left | @@ -396,19 +474,56 @@ mod comment_spacing_test { "); } - /// Block comments must touch `)`, `]`, `}`, `,`, `;`, `(`, `[`, `{` on their right. + /// Comments only share a line with `(`, `[`, `{` when the contents don't wrap. + #[test] + fn opening_delimiter_comments_when_wrapping() { + assert_comment_spacing( + r" +select foo(/* c */ x); +select foo( + -- c + x +); +select foo( + /* c */ + x +); +select foo( + /* c */ x, + y +); +", + ); + assert_snapshot!(comment_spacing_diagnostic("select foo(-- c\n x);").unwrap(), @" + error: comment after an opening delimiter must be on its own line when the contents wrap + | + 1 | select foo(-- c + | ^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select foo( -- c\n x\n);").unwrap(), @" + error: comment after an opening delimiter must be on its own line when the contents wrap + | + 1 | select foo( -- c + | ^^^^ + "); + assert_snapshot!(comment_spacing_diagnostic("select foo(/* c */\n x\n);").unwrap(), @" + error: comment after an opening delimiter must be on its own line when the contents wrap + | + 1 | select foo(/* c */ + | ^^^^^^^ + "); + } + + /// Block comments must touch `)`, `]`, `}`, `,`, `;` on their right. #[test] fn block_comments_touch_right_delimiters() { - for sql in [ - "select foo(x /* c */);", - "select foo(x /* c */, y);", - "select 1 /* c */;", - "create function f /* c */(a int) returns int language sql return 1;", - "select (array[1, 2, 3]) /* c */[1];", - "select * from graph_table(g match (a)-> /* c */{1, 3}(b) columns (a.id));", - ] { - assert_comment_spacing(sql); - } + assert_comment_spacing( + r" +select foo(x /* c */); +select foo(x /* c */, y); +select 1 /* c */; +", + ); assert_snapshot!(comment_spacing_diagnostic("select foo(x /* c */ );").unwrap(), @" error: block comment must touch the delimiter on its right | @@ -438,24 +553,6 @@ mod comment_spacing_test { | 1 | select * from graph_table(g match (a)->{1, 3 /* c */ }(b) columns (a.id)); | ^^^^^^^ - "); - assert_snapshot!(comment_spacing_diagnostic("create function f /* c */ (a int) returns int language sql return 1;").unwrap(), @" - error: block comment must touch the delimiter on its right - | - 1 | create function f /* c */ (a int) returns int language sql return 1; - | ^^^^^^^ - "); - assert_snapshot!(comment_spacing_diagnostic("select (array[1, 2, 3]) /* c */ [1];").unwrap(), @" - error: block comment must touch the delimiter on its right - | - 1 | select (array[1, 2, 3]) /* c */ [1]; - | ^^^^^^^ - "); - assert_snapshot!(comment_spacing_diagnostic("select * from graph_table(g match (a)-> /* c */ {1, 3}(b) columns (a.id));").unwrap(), @" - error: block comment must touch the delimiter on its right - | - 1 | select * from graph_table(g match (a)-> /* c */ {1, 3}(b) columns (a.id)); - | ^^^^^^^ "); } } From fcb64a7ad66f174b071238f5cce4e71674755e17 Mon Sep 17 00:00:00 2001 From: Steve Dignam Date: Sat, 3 Oct 2026 12:43:35 -0400 Subject: [PATCH 3/7] add before & after --- .../tests/after/alter_extension.snap | 2 +- .../tests/after/alter_operator_family.snap | 2 +- .../tests/after/alter_property_graph.snap | 7 +- .../squawk_fmt/tests/after/alter_table.snap | 10 +-- crates/squawk_fmt/tests/after/analyze.snap | 5 +- crates/squawk_fmt/tests/after/call.snap | 3 +- crates/squawk_fmt/tests/after/checkpoint.snap | 3 +- crates/squawk_fmt/tests/after/close.snap | 3 +- crates/squawk_fmt/tests/after/cluster.snap | 11 ++- crates/squawk_fmt/tests/after/comments.snap | 2 + crates/squawk_fmt/tests/after/copy.snap | 4 +- .../squawk_fmt/tests/after/create_domain.snap | 3 +- .../tests/after/create_event_trigger.snap | 5 +- .../tests/after/create_extension.snap | 3 +- .../after/create_foreign_data_wrapper.snap | 3 +- .../tests/after/create_foreign_table.snap | 5 +- .../tests/after/create_function.snap | 8 +- .../squawk_fmt/tests/after/create_index.snap | 2 +- .../tests/after/create_language.snap | 2 +- .../tests/after/create_materialized_view.snap | 2 +- .../tests/after/create_operator.snap | 4 +- .../tests/after/create_operator_class.snap | 6 +- .../tests/after/create_operator_family.snap | 2 +- .../squawk_fmt/tests/after/create_policy.snap | 2 +- .../tests/after/create_procedure.snap | 2 +- .../tests/after/create_property_graph.snap | 6 +- .../tests/after/create_publication.snap | 4 +- .../squawk_fmt/tests/after/create_rule.snap | 2 +- .../squawk_fmt/tests/after/create_schema.snap | 2 +- .../squawk_fmt/tests/after/create_table.snap | 15 +++- .../tests/after/create_table_as.snap | 4 +- .../tests/after/create_table_options.snap | 6 +- .../create_text_search_configuration.snap | 2 +- .../after/create_text_search_dictionary.snap | 2 +- .../after/create_text_search_parser.snap | 2 +- .../after/create_text_search_template.snap | 2 +- .../tests/after/create_transform.snap | 6 +- .../tests/after/create_trigger.snap | 6 +- .../squawk_fmt/tests/after/create_view.snap | 2 +- crates/squawk_fmt/tests/after/deallocate.snap | 3 +- crates/squawk_fmt/tests/after/declare.snap | 3 +- crates/squawk_fmt/tests/after/delete.snap | 3 +- crates/squawk_fmt/tests/after/discard.snap | 3 +- crates/squawk_fmt/tests/after/do.snap | 3 +- .../tests/after/drop_foreign_table.snap | 2 +- .../squawk_fmt/tests/after/drop_function.snap | 2 +- crates/squawk_fmt/tests/after/drop_index.snap | 2 +- .../tests/after/drop_materialized_view.snap | 2 +- .../squawk_fmt/tests/after/drop_operator.snap | 2 +- .../tests/after/drop_operator_class.snap | 2 +- .../tests/after/drop_operator_family.snap | 2 +- .../squawk_fmt/tests/after/drop_policy.snap | 2 +- .../tests/after/drop_procedure.snap | 2 +- .../tests/after/drop_property_graph.snap | 2 +- .../squawk_fmt/tests/after/drop_routine.snap | 2 +- crates/squawk_fmt/tests/after/drop_rule.snap | 2 +- .../squawk_fmt/tests/after/drop_sequence.snap | 4 +- .../tests/after/drop_statistics.snap | 2 +- crates/squawk_fmt/tests/after/drop_table.snap | 2 +- .../tests/after/drop_text_search_config.snap | 2 +- .../tests/after/drop_text_search_dict.snap | 2 +- .../tests/after/drop_text_search_parser.snap | 2 +- .../after/drop_text_search_template.snap | 2 +- .../tests/after/drop_transform.snap | 2 +- .../squawk_fmt/tests/after/drop_trigger.snap | 2 +- crates/squawk_fmt/tests/after/drop_type.snap | 2 +- crates/squawk_fmt/tests/after/drop_view.snap | 2 +- crates/squawk_fmt/tests/after/empty_stmt.snap | 7 +- crates/squawk_fmt/tests/after/execute.snap | 3 +- crates/squawk_fmt/tests/after/explain.snap | 3 +- crates/squawk_fmt/tests/after/fetch.snap | 3 +- crates/squawk_fmt/tests/after/from.snap | 32 +++---- crates/squawk_fmt/tests/after/grant.snap | 5 +- .../squawk_fmt/tests/after/graph_table.snap | 16 ++-- crates/squawk_fmt/tests/after/group_by.snap | 10 +-- .../tests/after/import_foreign_schema.snap | 5 +- crates/squawk_fmt/tests/after/insert.snap | 5 +- crates/squawk_fmt/tests/after/listen.snap | 4 +- crates/squawk_fmt/tests/after/load.snap | 3 +- crates/squawk_fmt/tests/after/lock.snap | 5 +- crates/squawk_fmt/tests/after/merge.snap | 3 +- crates/squawk_fmt/tests/after/move.snap | 3 +- crates/squawk_fmt/tests/after/notify.snap | 3 +- crates/squawk_fmt/tests/after/prepare.snap | 6 +- crates/squawk_fmt/tests/after/reassign.snap | 3 +- crates/squawk_fmt/tests/after/refresh.snap | 5 +- crates/squawk_fmt/tests/after/reindex.snap | 5 +- crates/squawk_fmt/tests/after/repack.snap | 7 +- crates/squawk_fmt/tests/after/reset.snap | 5 +- crates/squawk_fmt/tests/after/reset_role.snap | 3 +- .../tests/after/reset_session_auth.snap | 3 +- crates/squawk_fmt/tests/after/revoke.snap | 5 +- .../tests/after/security_label.snap | 5 +- crates/squawk_fmt/tests/after/select.snap | 6 +- .../tests/after/select_clauses.snap | 2 +- .../tests/after/select_comments.snap | 18 ++++ .../squawk_fmt/tests/after/select_expr.snap | 84 +++++++++++-------- .../squawk_fmt/tests/after/select_into.snap | 7 +- crates/squawk_fmt/tests/after/set.snap | 5 +- .../tests/after/set_constraints.snap | 5 +- crates/squawk_fmt/tests/after/set_role.snap | 3 +- .../tests/after/set_session_auth.snap | 3 +- .../tests/after/set_transaction.snap | 3 +- crates/squawk_fmt/tests/after/show.snap | 5 +- crates/squawk_fmt/tests/after/table.snap | 5 +- .../tests/after/table_constraints.snap | 4 +- crates/squawk_fmt/tests/after/truncate.snap | 5 +- crates/squawk_fmt/tests/after/types.snap | 28 ++++--- crates/squawk_fmt/tests/after/unlisten.snap | 4 +- crates/squawk_fmt/tests/after/update.snap | 10 +-- crates/squawk_fmt/tests/after/vacuum.snap | 5 +- crates/squawk_fmt/tests/after/values.snap | 3 +- .../squawk_fmt/tests/after/xml_functions.snap | 18 ++-- crates/squawk_fmt/tests/before/comments.sql | 2 + .../squawk_fmt/tests/before/create_table.sql | 2 + .../tests/before/select_comments.sql | 16 ++++ .../squawk_fmt/tests/before/select_expr.sql | 7 ++ crates/squawk_fmt/tests/before/types.sql | 4 +- 118 files changed, 332 insertions(+), 304 deletions(-) diff --git a/crates/squawk_fmt/tests/after/alter_extension.snap b/crates/squawk_fmt/tests/after/alter_extension.snap index 2cb19eb7..b086eaa4 100644 --- a/crates/squawk_fmt/tests/after/alter_extension.snap +++ b/crates/squawk_fmt/tests/after/alter_extension.snap @@ -84,7 +84,7 @@ alter /* extension */ extension /* name */ an_exceedingly_long_extension_name_fo /* action */ add /* object kind */ operator /* operator name */ application_schema.=== - /* open paren */( + /* open paren */ ( /* left type */ application_schema.exceedingly_long_left_operand_type, /* right type */ application_schema.exceedingly_long_right_operand_type /* close paren */ ) /* semicolon */; diff --git a/crates/squawk_fmt/tests/after/alter_operator_family.snap b/crates/squawk_fmt/tests/after/alter_operator_family.snap index 39346a43..2f4206f0 100644 --- a/crates/squawk_fmt/tests/after/alter_operator_family.snap +++ b/crates/squawk_fmt/tests/after/alter_operator_family.snap @@ -5,7 +5,7 @@ input_file: crates/squawk_fmt/tests/before/alter_operator_family.sql alter /* operator */ operator /* family */ family /* name */ public.integer_family /* using */ using /* method */ btree /* add */ add - /* operator option */ operator /* strategy */ 1 /* op */ < /* left paren */( + /* operator option */ operator /* strategy */ 1 /* op */ < /* left paren */ ( /* lhs */ integer /* comma */, /* rhs */ integer /* right paren */ ) diff --git a/crates/squawk_fmt/tests/after/alter_property_graph.snap b/crates/squawk_fmt/tests/after/alter_property_graph.snap index 9f34f3c0..83f00244 100644 --- a/crates/squawk_fmt/tests/after/alter_property_graph.snap +++ b/crates/squawk_fmt/tests/after/alter_property_graph.snap @@ -85,8 +85,11 @@ alter property graph social_graph alter property graph social_graph alter relationship table follows - alter label connection drop properties /* before paren */( + alter label connection drop properties /* before paren */ ( created_at ); -alter property graph social_graph drop vertex tables /* before paren */(people); +alter property graph social_graph + drop vertex tables /* before paren */ ( + people + ); diff --git a/crates/squawk_fmt/tests/after/alter_table.snap b/crates/squawk_fmt/tests/after/alter_table.snap index a0670e27..73aebc36 100644 --- a/crates/squawk_fmt/tests/after/alter_table.snap +++ b/crates/squawk_fmt/tests/after/alter_table.snap @@ -50,7 +50,7 @@ alter table all in tablespace old_reporting_tablespace set tablespace new_reporting_tablespace nowait; -alter /* table */ table /* if */ if /* exists */ exists /* only */ only /* left paren */(/* relation */ reporting.commented_customer_activity /* right paren */) +alter /* table */ table /* if */ if /* exists */ exists /* only */ only /* left paren */ (/* relation */ reporting.commented_customer_activity /* right paren */) /* action */ alter /* column */ column /* column name */ activity_description /* set */ set /* default */ default /* expression */ 'A very long default activity description used to verify formatter wrapping behavior', @@ -126,7 +126,7 @@ alter /* table */ table /* relation */ partitions_merge_schema.sales_range /* second partition */ sales_feb2022, /* third partition */ sales_mar2022 /* right paren */ ) - /* into */ into /* target partition */ partitions_merge_schema./* target name */ sales_jan_feb_mar2022 /* semicolon */; + /* into */ into /* target partition */ partitions_merge_schema. /* target name */ sales_jan_feb_mar2022 /* semicolon */; alter table sales_range split partition sales_feb_mar_apr2022 into ( @@ -137,8 +137,8 @@ alter table sales_range ); alter /* table */ table /* relation */ sales_range - /* split */ split /* partition */ partition /* source */ partition_split_schema./* source name */ sales_all /* into */ into /* list left */ ( - /* first partition */ partition /* first name */ partition_split_schema./* name */ sales_first + /* split */ split /* partition */ partition /* source */ partition_split_schema. /* source name */ sales_all /* into */ into /* list left */ ( + /* first partition */ partition /* first name */ partition_split_schema. /* name */ sales_first /* for */ for /* values */ values /* from */ from /* lower left */ ( /* lower */ '2022-01-01' /* lower right */ ) @@ -146,7 +146,7 @@ alter /* table */ table /* relation */ sales_range /* upper */ '2022-02-01' /* upper right */ ) /* comma */, /* second partition */ partition /* second name */ sales_second - /* for */ for /* values */ values /* in */ in /* in left */( + /* for */ for /* values */ values /* in */ in /* in left */ ( /* first value */ 'one' /* value comma */, /* second value */ 'two' /* in right */ ), diff --git a/crates/squawk_fmt/tests/after/analyze.snap b/crates/squawk_fmt/tests/after/analyze.snap index b8faa5df..9e7a36ea 100644 --- a/crates/squawk_fmt/tests/after/analyze.snap +++ b/crates/squawk_fmt/tests/after/analyze.snap @@ -18,12 +18,11 @@ analyze an_intentionally_long_column_name ); -/* before analyze */ -analyze /* before options */ ( +/* before analyze */ analyze /* before options */ ( /* before verbose */ verbose /* before true */ true /* before comma */, /* before skip locked */ skip_locked /* before false */ false /* before close */ ) - /* before table */ public /* before dot */./* after dot */ records /* before columns */ ( + /* before table */ public /* before dot */ . /* after dot */ records /* before columns */ ( /* before id */ id /* before column comma */, /* before payload */ payload /* before columns close */ ) /* before table comma */, diff --git a/crates/squawk_fmt/tests/after/call.snap b/crates/squawk_fmt/tests/after/call.snap index 3a4fd9ea..c858e6b5 100644 --- a/crates/squawk_fmt/tests/after/call.snap +++ b/crates/squawk_fmt/tests/after/call.snap @@ -11,8 +11,7 @@ call process_a_record_with_an_intentionally_long_procedure_name( another_intentionally_long_argument_name => 12345 ); -/* before */ -call /* after call */ public /* before dot */./* after dot */ process_record /* before left paren */( +/* before */ call /* after call */ public /* before dot */ . /* after dot */ process_record /* before left paren */ ( /* after left paren */ 1 /* before comma */, /* after comma */ argument_name /* before arrow */ => /* after arrow */ 'value' /* before second comma */, /* after second comma */ variadic /* after variadic */ array[ diff --git a/crates/squawk_fmt/tests/after/checkpoint.snap b/crates/squawk_fmt/tests/after/checkpoint.snap index b738f71f..3105f0da 100644 --- a/crates/squawk_fmt/tests/after/checkpoint.snap +++ b/crates/squawk_fmt/tests/after/checkpoint.snap @@ -17,8 +17,7 @@ checkpoint ( another_intentionally_long_checkpoint_option_name another_intentionally_long_value_name ); -/* before checkpoint */ -checkpoint /* before left paren */ ( +/* before checkpoint */ checkpoint /* before left paren */ ( /* after left paren */ mode /* before value */ fast /* before comma */, /* after comma */ flush_unlogged /* before second value */ false /* before right paren */ ) /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/close.snap b/crates/squawk_fmt/tests/after/close.snap index ae8ae90d..584cf032 100644 --- a/crates/squawk_fmt/tests/after/close.snap +++ b/crates/squawk_fmt/tests/after/close.snap @@ -11,7 +11,6 @@ close "Case-Sensitive Cursor"; close cursor_with_an_intentionally_long_name_that_makes_this_close_statement_longer_than_eighty_characters; -/* before */ -close /* after close */ all /* before semicolon */; +/* before */ close /* after close */ all /* before semicolon */; close /* before cursor */ cursor_name /* before cursor semicolon */; diff --git a/crates/squawk_fmt/tests/after/cluster.snap b/crates/squawk_fmt/tests/after/cluster.snap index a50eb1bf..c4ac1088 100644 --- a/crates/squawk_fmt/tests/after/cluster.snap +++ b/crates/squawk_fmt/tests/after/cluster.snap @@ -17,15 +17,14 @@ cluster a_very_long_schema_name.an_intentionally_long_table_name using a_very_long_schema_name.an_intentionally_long_index_name; -/* before */ -cluster +/* before */ cluster /* after cluster */ ( /* after left paren */ verbose /* before comma */, /* after comma */ analyze /* before value */ true /* before right paren */ ) - /* before table */ public /* before table dot */./* after table dot */ records -/* before using */ using /* after using */ public /* before index dot */./* after index dot */ records_idx /* before semicolon */; + /* before table */ public /* before table dot */ . /* after table dot */ records +/* before using */ using /* after using */ public /* before index dot */ . /* after index dot */ records_idx /* before semicolon */; cluster - /* before legacy index */ public /* before legacy index dot */./* after legacy index dot */ records_idx - /* before on */ on /* after on */ public /* before legacy table dot */./* after legacy table dot */ records /* before legacy semicolon */; + /* before legacy index */ public /* before legacy index dot */ . /* after legacy index dot */ records_idx + /* before on */ on /* after on */ public /* before legacy table dot */ . /* after legacy table dot */ records /* before legacy semicolon */; diff --git a/crates/squawk_fmt/tests/after/comments.snap b/crates/squawk_fmt/tests/after/comments.snap index 885a7a0f..38c5eeeb 100644 --- a/crates/squawk_fmt/tests/after/comments.snap +++ b/crates/squawk_fmt/tests/after/comments.snap @@ -42,3 +42,5 @@ select 1; /*foo*/ select 1; + +/* first */ /* second */ select 1; -- directly trailing diff --git a/crates/squawk_fmt/tests/after/copy.snap b/crates/squawk_fmt/tests/after/copy.snap index 8898cd15..97e29966 100644 --- a/crates/squawk_fmt/tests/after/copy.snap +++ b/crates/squawk_fmt/tests/after/copy.snap @@ -1,6 +1,5 @@ --- source: crates/squawk_fmt/tests/tests.rs -assertion_line: 29 input_file: crates/squawk_fmt/tests/before/copy.sql --- copy foo from '/tmp/foo.csv'; @@ -35,8 +34,7 @@ force quote * force null description where id > 0; -/* before */ -copy /* after copy */ binary /* after binary */ public /* before dot */./* after dot */ records /* before columns */ ( +/* before */ copy /* after copy */ binary /* after binary */ public /* before dot */ . /* after dot */ records /* before columns */ ( /* after left paren */ id /* before comma */, /* after comma */ description /* before right paren */ ) diff --git a/crates/squawk_fmt/tests/after/create_domain.snap b/crates/squawk_fmt/tests/after/create_domain.snap index 72d338f9..238978c0 100644 --- a/crates/squawk_fmt/tests/after/create_domain.snap +++ b/crates/squawk_fmt/tests/after/create_domain.snap @@ -16,8 +16,7 @@ create domain extraordinarily_long_schema_name.extraordinarily_long_domain_name check (length(value) > 3) not null; -/* before create */ -create /* before domain */ domain /* before name */ public.commented_domain +/* before create */ create /* before domain */ domain /* before name */ public.commented_domain /* before as */ as /* before type */ text /* before collate */ collate /* before collation */ "C" /* before constraint */ constraint /* before constraint name */ valid_value /* before check */ check /* before left paren */ ( diff --git a/crates/squawk_fmt/tests/after/create_event_trigger.snap b/crates/squawk_fmt/tests/after/create_event_trigger.snap index e0d6355a..c9b7ea6b 100644 --- a/crates/squawk_fmt/tests/after/create_event_trigger.snap +++ b/crates/squawk_fmt/tests/after/create_event_trigger.snap @@ -13,8 +13,7 @@ create event trigger extraordinarily_long_event_trigger_name execute procedure extraordinarily_long_schema_name.extraordinarily_long_event_trigger_procedure(); -/* before create */ -create /* before event */ event /* before trigger */ trigger /* before name */ commented_trigger +/* before create */ create /* before event */ event /* before trigger */ trigger /* before name */ commented_trigger /* before on */ on /* before event name */ ddl_command_end /* before when */ when /* before variable */ tag /* before in */ in /* before left paren */ ( /* before first literal */ 'CREATE TABLE' /* before comma */, @@ -24,6 +23,6 @@ create /* before event */ event /* before trigger */ trigger /* before name */ c /* before second literal */ 'postgis' /* before second right paren */ ) /* before execute */ execute /* before function */ function - /* before call */ audit.log_ddl /* before call left paren */( + /* before call */ audit.log_ddl /* before call left paren */ ( /* before call right paren */ ) /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/create_extension.snap b/crates/squawk_fmt/tests/after/create_extension.snap index dc1308d9..0975f43e 100644 --- a/crates/squawk_fmt/tests/after/create_extension.snap +++ b/crates/squawk_fmt/tests/after/create_extension.snap @@ -16,8 +16,7 @@ create extension if not exists extraordinarily_long_extension_name version 'extraordinarily-long-extension-version-number' cascade; -/* before create */ -create /* before extension */ extension /* before if */ if /* before not */ not /* before exists */ exists /* before name */ commented_extension +/* before create */ create /* before extension */ extension /* before if */ if /* before not */ not /* before exists */ exists /* before name */ commented_extension /* before with */ with /* before schema */ schema /* before schema name */ extensions /* before version */ version /* before version value */ '1.2.3' diff --git a/crates/squawk_fmt/tests/after/create_foreign_data_wrapper.snap b/crates/squawk_fmt/tests/after/create_foreign_data_wrapper.snap index 58557bff..5ba1822d 100644 --- a/crates/squawk_fmt/tests/after/create_foreign_data_wrapper.snap +++ b/crates/squawk_fmt/tests/after/create_foreign_data_wrapper.snap @@ -16,8 +16,7 @@ create foreign data wrapper extraordinarily_long_foreign_data_wrapper_name extraordinarily_long_option_name 'extraordinarily long foreign data wrapper option value' ); -/* before create */ -create /* before foreign */ foreign /* before data */ data /* before wrapper */ wrapper /* before name */ commented_fdw +/* before create */ create /* before foreign */ foreign /* before data */ data /* before wrapper */ wrapper /* before name */ commented_fdw /* before handler */ handler /* before handler name */ public.handler_fn /* before validator */ validator /* before validator name */ public.validator_fn /* before options */ options /* before left paren */ ( diff --git a/crates/squawk_fmt/tests/after/create_foreign_table.snap b/crates/squawk_fmt/tests/after/create_foreign_table.snap index ca6f064a..f74acea1 100644 --- a/crates/squawk_fmt/tests/after/create_foreign_table.snap +++ b/crates/squawk_fmt/tests/after/create_foreign_table.snap @@ -4,7 +4,7 @@ input_file: crates/squawk_fmt/tests/before/create_foreign_table.sql --- create foreign table t () server s; -create foreign table empty_arg_comment ( /* inside empty args */ ) server s; +create foreign table empty_arg_comment (/* inside empty args */) server s; create foreign table empty_arg_line_comment ( -- inside empty args @@ -48,8 +48,7 @@ create foreign table an_intentionally_long_schema_name.an_intentionally_long_for table_name 'an_intentionally_long_foreign_table_name' ); -/* before create */ -create /* before foreign */ foreign /* before table */ table /* before if */ if /* before not */ not /* before exists */ exists /* before table name */ public /* before dot */./* after dot */ remote_records /* before left paren */ ( +/* before create */ create /* before foreign */ foreign /* before table */ table /* before if */ if /* before not */ not /* before exists */ exists /* before table name */ public /* before dot */ . /* after dot */ remote_records /* before left paren */ ( /* after left paren */ id /* before type */ bigint /* before comma */, /* after comma */ name /* before second type */ text /* before right paren */ ) diff --git a/crates/squawk_fmt/tests/after/create_function.snap b/crates/squawk_fmt/tests/after/create_function.snap index 81da1414..91f9314b 100644 --- a/crates/squawk_fmt/tests/after/create_function.snap +++ b/crates/squawk_fmt/tests/after/create_function.snap @@ -68,7 +68,7 @@ create function percent_type_param( create function percent_type_table( unused integer -) returns table (value accounts /*pct1*/.id /*pct2*/% /*pct3*/type) +) returns table (value accounts /*pct1*/ .id /*pct2*/ % /*pct3*/ type) language sql as $$ select 1 $$; @@ -82,7 +82,7 @@ END; $$ language plpgsql; -create function foo( /* no params */ ) returns t +create function foo(/* no params */) returns t as $$select 1$$ language sql; @@ -103,7 +103,7 @@ create function comment_before_language( as $$select 1$$; -- comments in every position -create /*a*/ or /*b*/ replace /*c*/ function /*d*/ app /*e*/./*f*/ commented( +create /*a*/ or /*b*/ replace /*c*/ function /*d*/ app /*e*/ . /*f*/ commented( /*g*/ in /*h*/ value /*i*/ integer /*j*/ default /*k*/ 1 /*l*/, /*m*/ in /*n*/ result /*o*/ text /*p*/ ) /*q*/ returns /*r*/ table /*s*/ ( @@ -119,7 +119,7 @@ create /*a*/ or /*b*/ replace /*c*/ function /*d*/ app /*e*/./*f*/ commented( /*aj*/ security /*ak*/ definer /*al*/ set /*am*/ search_path /*an*/ to /*ao*/ public /*ap*/, /*aq*/ pg_temp /*ar*/ /*as*/ reset /*at*/ all - /*au*/ support /*av*/ public /*aw*/./*ax*/ support_fn + /*au*/ support /*av*/ public /*aw*/ . /*ax*/ support_fn /*ay*/ as /*az*/ $$ select value::text $$ /*ba*/; create function increment(value integer) returns integer diff --git a/crates/squawk_fmt/tests/after/create_index.snap b/crates/squawk_fmt/tests/after/create_index.snap index c126bddb..bf0335a6 100644 --- a/crates/squawk_fmt/tests/after/create_index.snap +++ b/crates/squawk_fmt/tests/after/create_index.snap @@ -41,7 +41,7 @@ create index long_index_name_for_testing_line_wrapping -- comments in every position create /*a*/ unique /*b*/ index /*c*/ concurrently /*d*/ if /*e*/ not /*f*/ exists /*g*/ idx - /*h*/ on /*i*/ only /*j*/ app /*k*/./*l*/ users + /*h*/ on /*i*/ only /*j*/ app /*k*/ . /*l*/ users /*m*/ using /*n*/ btree /*o*/ ( /*p*/ email /*q*/ collate /*r*/ "C" /*s*/ text_pattern_ops /*t*/ desc /*u*/ nulls /*v*/ last /*w*/, /*x*/ (lower(name)) /*y*/ asc /*z*/ diff --git a/crates/squawk_fmt/tests/after/create_language.snap b/crates/squawk_fmt/tests/after/create_language.snap index ab8d0214..558c5551 100644 --- a/crates/squawk_fmt/tests/after/create_language.snap +++ b/crates/squawk_fmt/tests/after/create_language.snap @@ -13,6 +13,6 @@ create or replace trusted procedural language -- comments in every position create /* or */ or /* replace */ replace /* trusted */ trusted /* procedural */ procedural /* language */ language /* name */ commented_language - /* handler */ handler /* handler schema */ handlers /* dot */./* handler function */ call_handler + /* handler */ handler /* handler schema */ handlers /* dot */ . /* handler function */ call_handler /* inline */ inline /* inline function */ handlers.call_inline /* validator */ validator /* validator function */ handlers.call_validator /* semicolon */; diff --git a/crates/squawk_fmt/tests/after/create_materialized_view.snap b/crates/squawk_fmt/tests/after/create_materialized_view.snap index d1ef8584..a9c316ab 100644 --- a/crates/squawk_fmt/tests/after/create_materialized_view.snap +++ b/crates/squawk_fmt/tests/after/create_materialized_view.snap @@ -22,7 +22,7 @@ create materialized view if not exists -- comments in every position create /* materialized */ materialized /* view */ view /* if */ if /* not */ not /* exists */ exists - /* schema */ app /* dot */./* name */ account_rollup /* columns */ ( + /* schema */ app /* dot */ . /* name */ account_rollup /* columns */ ( /* first column */ account_id /* comma */, /* second column */ total /* close columns */ ) diff --git a/crates/squawk_fmt/tests/after/create_operator.snap b/crates/squawk_fmt/tests/after/create_operator.snap index 4799a753..3ea91a20 100644 --- a/crates/squawk_fmt/tests/after/create_operator.snap +++ b/crates/squawk_fmt/tests/after/create_operator.snap @@ -43,7 +43,7 @@ create operator extraordinarily_long_schema_name.## ( ); -- comments in every position -create /* operator */ operator /* schema */ app /* dot */./* symbol */ # /* attributes */ ( +create /* operator */ operator /* schema */ app /* dot */ . /* symbol */ # /* attributes */ ( /* function name */ function /* equals */ = /* function value */ app.compare_values /* comma */, /* left argument */ leftarg /* second equals */ = /* type */ integer /* comma */, /* marker */ hashes /* closing parenthesis */ @@ -68,5 +68,5 @@ create operator + ( ); create operator + ( - commutator /* before qualified operator */ = /* before operator keyword */ operator /* before open paren */(/* before operator */ pg_catalog.+ /* before close paren */) /* before semicolon */ + commutator /* before qualified operator */ = /* before operator keyword */ operator /* before open paren */ (/* before operator */ pg_catalog.+ /* before close paren */) /* before semicolon */ ); diff --git a/crates/squawk_fmt/tests/after/create_operator_class.snap b/crates/squawk_fmt/tests/after/create_operator_class.snap index e7d75950..c44672df 100644 --- a/crates/squawk_fmt/tests/after/create_operator_class.snap +++ b/crates/squawk_fmt/tests/after/create_operator_class.snap @@ -29,11 +29,11 @@ create operator class extraordinarily_long_schema_name.extraordinarily_long_inte storage extraordinarily_long_schema_name.extraordinarily_long_storage_type; -- comments in every position -create /* operator */ operator /* class */ class /* schema */ app /* dot */./* name */ integer_ops +create /* operator */ operator /* class */ class /* schema */ app /* dot */ . /* name */ integer_ops /* default */ default /* for */ for /* type keyword */ type /* data type */ integer /* using */ using /* method */ btree - /* family */ family /* family schema */ app /* family dot */./* family name */ integer_family /* as */ as - /* option */ operator /* number */ 1 /* operator name */ < /* left paren */( + /* family */ family /* family schema */ app /* family dot */ . /* family name */ integer_family /* as */ as + /* option */ operator /* number */ 1 /* operator name */ < /* left paren */ ( /* left type */ integer /* type comma */, /* right type */ integer /* right paren */ ) diff --git a/crates/squawk_fmt/tests/after/create_operator_family.snap b/crates/squawk_fmt/tests/after/create_operator_family.snap index 342120eb..0ebf85b5 100644 --- a/crates/squawk_fmt/tests/after/create_operator_family.snap +++ b/crates/squawk_fmt/tests/after/create_operator_family.snap @@ -11,5 +11,5 @@ create operator family -- comments in every position create /* operator */ operator /* family */ family - /* schema */ app /* dot */./* name */ integer_family + /* schema */ app /* dot */ . /* name */ integer_family /* using */ using /* method */ btree /* end */; diff --git a/crates/squawk_fmt/tests/after/create_policy.snap b/crates/squawk_fmt/tests/after/create_policy.snap index fd64fd89..6ee43c24 100644 --- a/crates/squawk_fmt/tests/after/create_policy.snap +++ b/crates/squawk_fmt/tests/after/create_policy.snap @@ -17,7 +17,7 @@ create policy extraordinarily_long_account_access_policy_name -- comments in every position create /* policy */ policy /* name */ account_access - /* on */ on /* schema */ public /* dot */./* table */ accounts + /* on */ on /* schema */ public /* dot */ . /* table */ accounts /* as */ as /* policy type */ restrictive /* for */ for /* command */ select /* to */ to /* first role */ account_admin /* comma */, diff --git a/crates/squawk_fmt/tests/after/create_procedure.snap b/crates/squawk_fmt/tests/after/create_procedure.snap index 72f37f0e..c0bff953 100644 --- a/crates/squawk_fmt/tests/after/create_procedure.snap +++ b/crates/squawk_fmt/tests/after/create_procedure.snap @@ -17,7 +17,7 @@ create or replace procedure extraordinarily_long_schema_name.extraordinarily_lon as $$ begin null; end $$; -- comments in every position -create /* or */ or /* replace */ replace /* procedure */ procedure /* schema */ app /* dot */./* name */ recalculate/* params */ ( +create /* or */ or /* replace */ replace /* procedure */ procedure /* schema */ app /* dot */ . /* name */ recalculate /* params */ ( /* mode */ in /* parameter */ account_id /* type */ integer /* comma */, /* out mode */ out /* output */ result /* output type */ text /* close */ ) diff --git a/crates/squawk_fmt/tests/after/create_property_graph.snap b/crates/squawk_fmt/tests/after/create_property_graph.snap index aa4326ab..6c1435a0 100644 --- a/crates/squawk_fmt/tests/after/create_property_graph.snap +++ b/crates/squawk_fmt/tests/after/create_property_graph.snap @@ -52,8 +52,8 @@ create property graph social ); -- comments in every position -create /* persistence */ local /* temporary */ temporary /* property */ property /* graph */ graph /* graph name */ public /* dot */./* name */ social - /* vertex */ vertex /* tables */ tables /* left paren */( +create /* persistence */ local /* temporary */ temporary /* property */ property /* graph */ graph /* graph name */ public /* dot */ . /* name */ social + /* vertex */ vertex /* tables */ tables /* left paren */ ( /* table */ people /* key */ key /* key left */ ( /* key column */ id /* key right */ ) @@ -63,7 +63,7 @@ create /* persistence */ local /* temporary */ temporary /* property */ property /* second table */ organizations /* no */ no /* properties */ properties /* vertex right */ ) - /* edge */ edge /* edge tables */ tables /* edge left */( + /* edge */ edge /* edge tables */ tables /* edge left */ ( /* edge table */ follows /* source */ source /* source key */ key /* source left */ ( /* source column */ follower_id /* source right */ diff --git a/crates/squawk_fmt/tests/after/create_publication.snap b/crates/squawk_fmt/tests/after/create_publication.snap index 4695fba0..1916e6c8 100644 --- a/crates/squawk_fmt/tests/after/create_publication.snap +++ b/crates/squawk_fmt/tests/after/create_publication.snap @@ -48,7 +48,7 @@ create publication omitted_schema_keywords create /* after create */ publication /* after publication */ commented_pub for - /* after for */ table /* after table */ only /* after only */(/* before table name */ public.commented /* before close */)/* before star */ * /* before columns */ ( + /* after for */ table /* after table */ only /* after only */ (/* before table name */ public.commented /* before close */) /* before star */ * /* before columns */ ( /* before column */ id /* before comma */, /* after comma */ payload /* before columns close */ ) @@ -61,4 +61,4 @@ create /* after create */ publication /* after publication */ commented_pub ) /* before semicolon */; create publication except_paren_comment - for all tables except /* before paren */(table audit.secret_events); + for all tables except /* before paren */ (table audit.secret_events); diff --git a/crates/squawk_fmt/tests/after/create_rule.snap b/crates/squawk_fmt/tests/after/create_rule.snap index ad7f5b97..33b13c19 100644 --- a/crates/squawk_fmt/tests/after/create_rule.snap +++ b/crates/squawk_fmt/tests/after/create_rule.snap @@ -24,7 +24,7 @@ create or replace rule extraordinarily_long_rule_name_for_recording_all_account_ -- comments in every position create /* or */ or /* replace */ replace /* rule */ rule /* name */ audit_change /* as */ as /* on */ on /* event */ update - /* to */ to /* schema */ public /* dot */./* relation */ accounts + /* to */ to /* schema */ public /* dot */ . /* relation */ accounts /* where */ where /* left paren */ ( /* condition */ old.owner_id is distinct from new.owner_id /* right paren */ diff --git a/crates/squawk_fmt/tests/after/create_schema.snap b/crates/squawk_fmt/tests/after/create_schema.snap index 15d2df0d..7c65ee0b 100644 --- a/crates/squawk_fmt/tests/after/create_schema.snap +++ b/crates/squawk_fmt/tests/after/create_schema.snap @@ -38,7 +38,7 @@ create schema create /* schema keyword */ schema /* authorization keyword */ authorization /* role */ schema_owner - /* schema element */ create /* function keyword */ function /* function name */ app /* separator */./* local name */ calculate( + /* schema element */ create /* function keyword */ function /* function name */ app /* separator */ . /* local name */ calculate( /* parameter */ value integer ) /* return type */ returns integer /* language option */ language /* language */ sql diff --git a/crates/squawk_fmt/tests/after/create_table.snap b/crates/squawk_fmt/tests/after/create_table.snap index 189b7c22..8533aac7 100644 --- a/crates/squawk_fmt/tests/after/create_table.snap +++ b/crates/squawk_fmt/tests/after/create_table.snap @@ -4,7 +4,7 @@ input_file: crates/squawk_fmt/tests/before/create_table.sql --- create table u (); -create table empty_table_arg_comment ( /* inside empty args */ ); +create table empty_table_arg_comment (/* inside empty args */); create table empty_table_arg_line_comment ( -- inside empty args @@ -39,7 +39,7 @@ create table "left" (id int); create table "table" (id int); create table U&"d\0061t\+000061" (id int); create table U&"d!0061tum" uescape '!' (id int); -create table /* foo */ foo /* bar */./* buzz */ bar (id int); +create table /* foo */ foo /* bar */ . /* buzz */ bar (id int); -- comments inside a name node create table U&"d!0061tum" /* mid */ uescape '!' (id int); @@ -47,7 +47,7 @@ create table t (U&"c!006fl" /* c */ uescape '!' int); create table t (U&"c!006fl" uescape /* c */ '!' int); -- comments inside a path -create table foo /*a*/ /*b*/.bar (id int); +create table foo /*a*/ /*b*/ .bar (id int); create table foo -- a line comment .bar (id int); @@ -126,7 +126,7 @@ create table column_option_comments ( /*k*/ add /*l*/ formatter /*m*/ 'x' /*n*/, /*o*/ set /*p*/ formatter /*q*/ 'y' /*r*/, /*s*/ drop /*t*/ formatter /*u*/ - ) /*v*/ collate /*w*/ public /*x*/./*y*/ "C" + ) /*v*/ collate /*w*/ public /*x*/ . /*y*/ "C" /*z*/ constraint /*aa*/ payload_required /*ab*/ not /*ac*/ null /*ad*/ deferrable, /*ae*/ id /*af*/ bigint @@ -197,3 +197,10 @@ create table default_expression_comments ( ) /* before comma */, b int ); + +create table default_subquery ( + a int default ( + select count(*) + from an_extraordinarily_long_table_name_that_forces_the_subquery_to_wrap + ) +); diff --git a/crates/squawk_fmt/tests/after/create_table_as.snap b/crates/squawk_fmt/tests/after/create_table_as.snap index 71e9f46e..8bd9141c 100644 --- a/crates/squawk_fmt/tests/after/create_table_as.snap +++ b/crates/squawk_fmt/tests/after/create_table_as.snap @@ -33,7 +33,7 @@ create table cached_result as with data; -- comments in every position -create /*a*/ temp /*b*/ table /*c*/ if /*d*/ not /*e*/ exists /*f*/ app /*g*/./*h*/ report /*i*/ ( +create /*a*/ temp /*b*/ table /*c*/ if /*d*/ not /*e*/ exists /*f*/ app /*g*/ . /*h*/ report /*i*/ ( /*j*/ id /*k*/, /*l*/ total /*m*/ ) @@ -46,5 +46,5 @@ create /*a*/ temp /*b*/ table /*c*/ if /*d*/ not /*e*/ exists /*f*/ app /*g*/./* /*ad*/ with /*ae*/ no /*af*/ data /*ag*/; create table executed /*a*/ as - /*b*/ execute /*c*/ refresh_report /*d*/(/*e*/ 1 /*f*/, /*g*/ 'full' /*h*/) + /*b*/ execute /*c*/ refresh_report /*d*/ (/*e*/ 1 /*f*/, /*g*/ 'full' /*h*/) /*i*/ with /*j*/ data /*k*/; diff --git a/crates/squawk_fmt/tests/after/create_table_options.snap b/crates/squawk_fmt/tests/after/create_table_options.snap index 96d6a02d..2962c392 100644 --- a/crates/squawk_fmt/tests/after/create_table_options.snap +++ b/crates/squawk_fmt/tests/after/create_table_options.snap @@ -60,7 +60,7 @@ create table partitioned ( create /*a*/ local /*b*/ temporary /*c*/ table /*d*/ if /*e*/ not /*f*/ exists /*g*/ commented ( /*h*/ id int /*i*/ ) - /*j*/ inherits /*k*/(/*l*/ parent /*m*/, /*n*/ archive.parent /*o*/) + /*j*/ inherits /*k*/ (/*l*/ parent /*m*/, /*n*/ archive.parent /*o*/) /*p*/ partition /*q*/ by /*r*/ hash /*s*/ (/*t*/ id /*u*/) /*v*/ using /*w*/ heap /*x*/ with /*y*/ (fillfactor /*z*/ = /*aa*/ 70 /*ab*/) @@ -73,10 +73,10 @@ create table child /*l*/ to /*m*/ (/*n*/ maxvalue /*o*/, /*p*/ 100 /*q*/); create table child_in partition of parent - for /*a*/ values /*b*/ in /*c*/(/*d*/ 1 /*e*/, /*f*/ 2 /*g*/); + for /*a*/ values /*b*/ in /*c*/ (/*d*/ 1 /*e*/, /*f*/ 2 /*g*/); create table child_hash partition of parent - for /*a*/ values /*b*/ with /*c*/( + for /*a*/ values /*b*/ with /*c*/ ( /*d*/ modulus /*e*/ 4 /*f*/, /*g*/ remainder /*h*/ 0 /*i*/ ); diff --git a/crates/squawk_fmt/tests/after/create_text_search_configuration.snap b/crates/squawk_fmt/tests/after/create_text_search_configuration.snap index 4b89e1ef..374810bc 100644 --- a/crates/squawk_fmt/tests/after/create_text_search_configuration.snap +++ b/crates/squawk_fmt/tests/after/create_text_search_configuration.snap @@ -12,7 +12,7 @@ create text search configuration ); create /* text keyword */ text /* search keyword */ search /* configuration keyword */ configuration - /* name */ public /* dot */./* name segment */ commented_configuration /* left parenthesis */ ( + /* name */ public /* dot */ . /* name segment */ commented_configuration /* left parenthesis */ ( /* first option */ parser /* equals */ = /* value */ public.default_parser /* comma */, /* second option */ copy = /* second value */ public.english /* right parenthesis */ ) /* semicolon */; diff --git a/crates/squawk_fmt/tests/after/create_text_search_dictionary.snap b/crates/squawk_fmt/tests/after/create_text_search_dictionary.snap index 828fe5f1..910cf0ff 100644 --- a/crates/squawk_fmt/tests/after/create_text_search_dictionary.snap +++ b/crates/squawk_fmt/tests/after/create_text_search_dictionary.snap @@ -12,7 +12,7 @@ create text search dictionary extraordinarily_long_schema_name.extraordinarily_l stopwords = 'extraordinarily_long_stopword_dictionary_name' ); -create /* text keyword */ text /* search keyword */ search /* dictionary keyword */ dictionary /* name */ public /* dot */./* name segment */ commented_dictionary /* left parenthesis */ ( +create /* text keyword */ text /* search keyword */ search /* dictionary keyword */ dictionary /* name */ public /* dot */ . /* name segment */ commented_dictionary /* left parenthesis */ ( /* first option */ template /* equals */ = /* value */ public.snowball /* comma */, /* second option */ language = /* second value */ english /* right parenthesis */ ) /* semicolon */; diff --git a/crates/squawk_fmt/tests/after/create_text_search_parser.snap b/crates/squawk_fmt/tests/after/create_text_search_parser.snap index 86f83945..594db36a 100644 --- a/crates/squawk_fmt/tests/after/create_text_search_parser.snap +++ b/crates/squawk_fmt/tests/after/create_text_search_parser.snap @@ -17,7 +17,7 @@ create text search parser extraordinarily_long_schema_name.extraordinarily_long_ headline = public.extraordinarily_long_parser_headline_function_name ); -create /* text keyword */ text /* search keyword */ search /* parser keyword */ parser /* name */ public /* dot */./* name segment */ commented_parser /* left parenthesis */ ( +create /* text keyword */ text /* search keyword */ search /* parser keyword */ parser /* name */ public /* dot */ . /* name segment */ commented_parser /* left parenthesis */ ( /* first option */ start /* equals */ = /* value */ public.parser_start /* comma */, /* second option */ gettoken = /* second value */ public.parser_gettoken /* comma two */, /* third option */ end = public.parser_end, diff --git a/crates/squawk_fmt/tests/after/create_text_search_template.snap b/crates/squawk_fmt/tests/after/create_text_search_template.snap index 7dbc54f1..0d95e1b6 100644 --- a/crates/squawk_fmt/tests/after/create_text_search_template.snap +++ b/crates/squawk_fmt/tests/after/create_text_search_template.snap @@ -11,7 +11,7 @@ create text search template extraordinarily_long_schema_name.extraordinarily_lon lexize = public.extraordinarily_long_template_lexize_function_name ); -create /* text keyword */ text /* search keyword */ search /* template keyword */ template /* name */ public /* dot */./* name segment */ commented_template /* left parenthesis */ ( +create /* text keyword */ text /* search keyword */ search /* template keyword */ template /* name */ public /* dot */ . /* name segment */ commented_template /* left parenthesis */ ( /* first option */ init /* equals */ = /* value */ public.simple_init /* comma */, /* second option */ lexize = /* second value */ public.simple_lexize /* right parenthesis */ ) /* semicolon */; diff --git a/crates/squawk_fmt/tests/after/create_transform.snap b/crates/squawk_fmt/tests/after/create_transform.snap index ef43732e..eafb5cf4 100644 --- a/crates/squawk_fmt/tests/after/create_transform.snap +++ b/crates/squawk_fmt/tests/after/create_transform.snap @@ -24,14 +24,14 @@ create transform for -- comments in every position create /*a*/ or /*b*/ replace /*c*/ transform /*d*/ for - /*e*/ app /*f*/./*g*/ custom_type + /*e*/ app /*f*/ . /*g*/ custom_type /*h*/ language /*i*/ plpgsql /*j*/ ( /*k*/ from /*l*/ sql /*m*/ with /*n*/ function - /*o*/ app /*p*/./*q*/ from_sql( + /*o*/ app /*p*/ . /*q*/ from_sql( /*r*/ integer /*s*/ ) /*t*/, /*u*/ to /*v*/ sql /*w*/ with /*x*/ function - /*y*/ app /*z*/./*aa*/ to_sql( + /*y*/ app /*z*/ . /*aa*/ to_sql( /*ab*/ integer /*ac*/ ) /*ad*/ ) /*ae*/; diff --git a/crates/squawk_fmt/tests/after/create_trigger.snap b/crates/squawk_fmt/tests/after/create_trigger.snap index 2dfb0294..116aa6cc 100644 --- a/crates/squawk_fmt/tests/after/create_trigger.snap +++ b/crates/squawk_fmt/tests/after/create_trigger.snap @@ -67,8 +67,8 @@ create /*a*/ or /*b*/ replace /*c*/ constraint /*d*/ trigger /*e*/ commented_tri /*h*/ update /*i*/ of /*j*/ first_column /*k*/, /*l*/ second_column /*m*/ or /*n*/ delete - /*o*/ on /*p*/ app /*q*/./*r*/ records - /*s*/ from /*t*/ app /*u*/./*v*/ source_records + /*o*/ on /*p*/ app /*q*/ . /*r*/ records + /*s*/ from /*t*/ app /*u*/ . /*v*/ source_records /*w*/ deferrable /*x*/ initially /*y*/ deferred /*z*/ referencing @@ -77,7 +77,7 @@ create /*a*/ or /*b*/ replace /*c*/ constraint /*d*/ trigger /*e*/ commented_tri /*ah*/ for /*ai*/ each /*aj*/ row /*ak*/ when /*al*/ (/*am*/ old_rows.first_column /*an*/ > /*ao*/ 1 /*ap*/) /*aq*/ execute /*ar*/ function - /*as*/ app /*at*/./*au*/ handle_records( + /*as*/ app /*at*/ . /*au*/ handle_records( /*av*/ 1 /*aw*/, /*ax*/ 'two' /*ay*/ ) /*az*/; diff --git a/crates/squawk_fmt/tests/after/create_view.snap b/crates/squawk_fmt/tests/after/create_view.snap index bbffc556..5288f05d 100644 --- a/crates/squawk_fmt/tests/after/create_view.snap +++ b/crates/squawk_fmt/tests/after/create_view.snap @@ -27,7 +27,7 @@ create view a_very_long_schema_name.a_very_long_view_name ( with cascaded check option; -- comments in every position -create /*a*/ or /*b*/ replace /*c*/ temp /*d*/ recursive /*e*/ view /*f*/ app /*g*/./*h*/ dashboard /*i*/ ( +create /*a*/ or /*b*/ replace /*c*/ temp /*d*/ recursive /*e*/ view /*f*/ app /*g*/ . /*h*/ dashboard /*i*/ ( /*j*/ account_id /*k*/, /*l*/ total /*m*/ ) diff --git a/crates/squawk_fmt/tests/after/deallocate.snap b/crates/squawk_fmt/tests/after/deallocate.snap index e58b2506..1dbce416 100644 --- a/crates/squawk_fmt/tests/after/deallocate.snap +++ b/crates/squawk_fmt/tests/after/deallocate.snap @@ -16,8 +16,7 @@ deallocate prepare prepared_statement_with_an_intentionally_long_name_that_makes_the_statement_longer_than_eighty_characters; -/* before deallocate */ -deallocate +/* before deallocate */ deallocate /* before prepare */ prepare /* before target */ statement_name /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/declare.snap b/crates/squawk_fmt/tests/after/declare.snap index ee5a8b24..64417222 100644 --- a/crates/squawk_fmt/tests/after/declare.snap +++ b/crates/squawk_fmt/tests/after/declare.snap @@ -26,8 +26,7 @@ for select another_intentionally_long_column_name from an_intentionally_long_table_name; -/* before declare */ -declare +/* before declare */ declare /* before cursor name */ c /* before binary */ binary /* before sensitivity */ insensitive diff --git a/crates/squawk_fmt/tests/after/delete.snap b/crates/squawk_fmt/tests/after/delete.snap index 0dbae8d8..fcfa9717 100644 --- a/crates/squawk_fmt/tests/after/delete.snap +++ b/crates/squawk_fmt/tests/after/delete.snap @@ -55,8 +55,7 @@ delete from t3 ) /*before where*/ where t3.x > t1.a; -/*before*/ -delete /*a*/ from /*b*/ foo +/*before*/ delete /*a*/ from /*b*/ foo /*c*/ for /*d*/ portion /*e*/ of /*f*/ valid_at /*g*/ from /*h*/ 1 /*i*/ to /*j*/ 2 /*k*/ as /*l*/ f /*m*/ using /*n*/ bar /*o*/ b /*p*/, /*q*/ baz diff --git a/crates/squawk_fmt/tests/after/discard.snap b/crates/squawk_fmt/tests/after/discard.snap index 7ceb69cd..ceba6824 100644 --- a/crates/squawk_fmt/tests/after/discard.snap +++ b/crates/squawk_fmt/tests/after/discard.snap @@ -12,6 +12,5 @@ discard temporary; discard temp; -/* before discard */ -discard +/* before discard */ discard /* first comment before target */ /* second comment before target */ /* third comment before target */ all /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/do.snap b/crates/squawk_fmt/tests/after/do.snap index 33cc5bd4..8c783bc1 100644 --- a/crates/squawk_fmt/tests/after/do.snap +++ b/crates/squawk_fmt/tests/after/do.snap @@ -17,8 +17,7 @@ begin end $body$; -/* before */ -do /* after do */ language /* after language */ plpgsql +/* before */ do /* after do */ language /* after language */ plpgsql /* before body */ $body$BEGIN NULL; END$body$ /* before semicolon */; do /* before trailing body */ $body$BEGIN NULL; END$body$ /* before trailing language */ language /* before language literal */ 'plpgsql' /* before trailing semicolon */; diff --git a/crates/squawk_fmt/tests/after/drop_foreign_table.snap b/crates/squawk_fmt/tests/after/drop_foreign_table.snap index c0214219..8d7042e5 100644 --- a/crates/squawk_fmt/tests/after/drop_foreign_table.snap +++ b/crates/squawk_fmt/tests/after/drop_foreign_table.snap @@ -11,6 +11,6 @@ drop foreign table if exists -- comments in every position drop /* foreign */ foreign /* table */ table /* if */ if /* exists */ exists - /* first table */ public /* dot */.events /* before comma */, + /* first table */ public /* dot */ .events /* before comma */, /* second table */ reporting.archive /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_function.snap b/crates/squawk_fmt/tests/after/drop_function.snap index 1cce4199..1fbf9a10 100644 --- a/crates/squawk_fmt/tests/after/drop_function.snap +++ b/crates/squawk_fmt/tests/after/drop_function.snap @@ -16,7 +16,7 @@ drop function if exists -- comments in every position drop /* function */ function /* if */ if /* exists */ exists - /* first function */ public /* dot */.calculate_total /* open */( + /* first function */ public /* dot */ .calculate_total /* open */ ( /* first argument */ integer /* argument comma */, /* second argument */ numeric /* close */ ) /* function comma */, diff --git a/crates/squawk_fmt/tests/after/drop_index.snap b/crates/squawk_fmt/tests/after/drop_index.snap index 75997cda..a2c2a741 100644 --- a/crates/squawk_fmt/tests/after/drop_index.snap +++ b/crates/squawk_fmt/tests/after/drop_index.snap @@ -11,6 +11,6 @@ drop index concurrently if exists -- comments in every position drop /* index */ index /* concurrently */ concurrently /* if */ if /* exists */ exists - /* first index */ public /* dot */.events_idx /* before comma */, + /* first index */ public /* dot */ .events_idx /* before comma */, /* second index */ reporting.archive_idx /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_materialized_view.snap b/crates/squawk_fmt/tests/after/drop_materialized_view.snap index c9a6ab9a..f061f301 100644 --- a/crates/squawk_fmt/tests/after/drop_materialized_view.snap +++ b/crates/squawk_fmt/tests/after/drop_materialized_view.snap @@ -11,6 +11,6 @@ drop materialized view if exists -- comments in every position drop /* materialized */ materialized /* view */ view /* if */ if /* exists */ exists - /* first view */ public /* dot */.monthly_sales /* before comma */, + /* first view */ public /* dot */ .monthly_sales /* before comma */, /* second view */ reporting.archived_sales /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_operator.snap b/crates/squawk_fmt/tests/after/drop_operator.snap index 3d6267f6..5cb918c5 100644 --- a/crates/squawk_fmt/tests/after/drop_operator.snap +++ b/crates/squawk_fmt/tests/after/drop_operator.snap @@ -14,7 +14,7 @@ drop operator if exists -- comments in every position drop /* operator */ operator /* if */ if /* exists */ exists - /* first operator */ public /* path dot */.=== /* open */ ( + /* first operator */ public /* path dot */ .=== /* open */ ( /* left type */ integer /* type comma */, /* right type */ integer /* close */ ) /* signature comma */, diff --git a/crates/squawk_fmt/tests/after/drop_operator_class.snap b/crates/squawk_fmt/tests/after/drop_operator_class.snap index 10e52340..6b6ba3ca 100644 --- a/crates/squawk_fmt/tests/after/drop_operator_class.snap +++ b/crates/squawk_fmt/tests/after/drop_operator_class.snap @@ -11,6 +11,6 @@ drop operator class if exists -- comments in every position drop /* operator */ operator /* class */ class /* if */ if /* exists */ exists - /* class name */ public /* dot */.text_pattern_ops + /* class name */ public /* dot */ .text_pattern_ops /* using */ using /* method */ btree /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_operator_family.snap b/crates/squawk_fmt/tests/after/drop_operator_family.snap index 15b65922..56f82be9 100644 --- a/crates/squawk_fmt/tests/after/drop_operator_family.snap +++ b/crates/squawk_fmt/tests/after/drop_operator_family.snap @@ -11,6 +11,6 @@ drop operator family if exists -- comments in every position drop /* operator */ operator /* family */ family /* if */ if /* exists */ exists - /* family name */ public /* dot */.integer_ops + /* family name */ public /* dot */ .integer_ops /* using */ using /* method */ hash /* behavior */ cascade /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_policy.snap b/crates/squawk_fmt/tests/after/drop_policy.snap index b3913dc2..e91586e2 100644 --- a/crates/squawk_fmt/tests/after/drop_policy.snap +++ b/crates/squawk_fmt/tests/after/drop_policy.snap @@ -12,5 +12,5 @@ drop policy if exists -- comments in every position drop /* policy */ policy /* if */ if /* exists */ exists /* policy name */ account_policy - /* on */ on /* table schema */ public /* dot */.accounts + /* on */ on /* table schema */ public /* dot */ .accounts /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_procedure.snap b/crates/squawk_fmt/tests/after/drop_procedure.snap index 2c9cece2..cfb761ea 100644 --- a/crates/squawk_fmt/tests/after/drop_procedure.snap +++ b/crates/squawk_fmt/tests/after/drop_procedure.snap @@ -16,7 +16,7 @@ drop procedure if exists -- comments in every position drop /* procedure */ procedure /* if */ if /* exists */ exists - /* first procedure */ public /* dot */.refresh_accounts /* open */( + /* first procedure */ public /* dot */ .refresh_accounts /* open */ ( /* first argument */ integer /* argument comma */, /* second argument */ text /* close */ ) /* procedure comma */, diff --git a/crates/squawk_fmt/tests/after/drop_property_graph.snap b/crates/squawk_fmt/tests/after/drop_property_graph.snap index c8ef146e..1ded4b53 100644 --- a/crates/squawk_fmt/tests/after/drop_property_graph.snap +++ b/crates/squawk_fmt/tests/after/drop_property_graph.snap @@ -10,5 +10,5 @@ drop property graph if exists -- comments in every position drop /* property */ property /* graph */ graph /* if */ if /* exists */ exists - /* schema */ public /* dot */./* graph name */ social_graph + /* schema */ public /* dot */ . /* graph name */ social_graph /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_routine.snap b/crates/squawk_fmt/tests/after/drop_routine.snap index fd8b1857..97e5ec5f 100644 --- a/crates/squawk_fmt/tests/after/drop_routine.snap +++ b/crates/squawk_fmt/tests/after/drop_routine.snap @@ -16,7 +16,7 @@ drop routine if exists -- comments in every position drop /* routine */ routine /* if */ if /* exists */ exists - /* first routine */ public /* dot */.calculate_total /* open */( + /* first routine */ public /* dot */ .calculate_total /* open */ ( /* first argument */ integer /* argument comma */, /* second argument */ numeric /* close */ ) /* routine comma */, diff --git a/crates/squawk_fmt/tests/after/drop_rule.snap b/crates/squawk_fmt/tests/after/drop_rule.snap index ebfe44c5..4b193b51 100644 --- a/crates/squawk_fmt/tests/after/drop_rule.snap +++ b/crates/squawk_fmt/tests/after/drop_rule.snap @@ -12,5 +12,5 @@ drop rule if exists -- comments in every position drop /* rule */ rule /* if */ if /* exists */ exists /* rule name */ archive_order - /* on */ on /* relation schema */ public /* dot */.orders + /* on */ on /* relation schema */ public /* dot */ .orders /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_sequence.snap b/crates/squawk_fmt/tests/after/drop_sequence.snap index 67fc6a68..7c05f3ed 100644 --- a/crates/squawk_fmt/tests/after/drop_sequence.snap +++ b/crates/squawk_fmt/tests/after/drop_sequence.snap @@ -11,6 +11,6 @@ drop sequence if exists -- comments in every position drop /* sequence */ sequence /* if */ if /* exists */ exists - /* first schema */ public /* first dot */.order_number_seq /* comma */, - /* second schema */ accounting /* second dot */.invoice_number_seq + /* first schema */ public /* first dot */ .order_number_seq /* comma */, + /* second schema */ accounting /* second dot */ .invoice_number_seq /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_statistics.snap b/crates/squawk_fmt/tests/after/drop_statistics.snap index d62a1940..da793b17 100644 --- a/crates/squawk_fmt/tests/after/drop_statistics.snap +++ b/crates/squawk_fmt/tests/after/drop_statistics.snap @@ -11,6 +11,6 @@ drop statistics if exists -- comments in every position drop /* statistics */ statistics /* if */ if /* exists */ exists - /* first statistics */ public /* dot */.user_stats /* before comma */, + /* first statistics */ public /* dot */ .user_stats /* before comma */, /* second statistics */ reporting.activity_stats /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_table.snap b/crates/squawk_fmt/tests/after/drop_table.snap index 4e9e43ab..5801e43f 100644 --- a/crates/squawk_fmt/tests/after/drop_table.snap +++ b/crates/squawk_fmt/tests/after/drop_table.snap @@ -11,6 +11,6 @@ drop table if exists -- comments in every position drop /* table */ table /* if */ if /* exists */ exists - /* first table */ public /* dot */.accounts /* before comma */, + /* first table */ public /* dot */ .accounts /* before comma */, /* second table */ archive.old_accounts /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_text_search_config.snap b/crates/squawk_fmt/tests/after/drop_text_search_config.snap index 3678a8a4..52526e79 100644 --- a/crates/squawk_fmt/tests/after/drop_text_search_config.snap +++ b/crates/squawk_fmt/tests/after/drop_text_search_config.snap @@ -10,5 +10,5 @@ drop text search configuration if exists -- comments in every position drop /* text */ text /* search */ search /* configuration */ configuration /* if */ if /* exists */ exists - /* configuration */ public /* dot */.english + /* configuration */ public /* dot */ .english /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_text_search_dict.snap b/crates/squawk_fmt/tests/after/drop_text_search_dict.snap index ba2f33a8..32f9f4f5 100644 --- a/crates/squawk_fmt/tests/after/drop_text_search_dict.snap +++ b/crates/squawk_fmt/tests/after/drop_text_search_dict.snap @@ -10,5 +10,5 @@ drop text search dictionary if exists -- comments in every position drop /* text */ text /* search */ search /* dictionary */ dictionary /* if */ if /* exists */ exists - /* dictionary */ public /* dot */.english_stem + /* dictionary */ public /* dot */ .english_stem /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_text_search_parser.snap b/crates/squawk_fmt/tests/after/drop_text_search_parser.snap index 9ad0340f..17d13214 100644 --- a/crates/squawk_fmt/tests/after/drop_text_search_parser.snap +++ b/crates/squawk_fmt/tests/after/drop_text_search_parser.snap @@ -10,5 +10,5 @@ drop text search parser if exists -- comments in every position drop /* text */ text /* search */ search /* parser */ parser /* if */ if /* exists */ exists - /* parser name */ public /* dot */.default_parser + /* parser name */ public /* dot */ .default_parser /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_text_search_template.snap b/crates/squawk_fmt/tests/after/drop_text_search_template.snap index ac63b723..60687d83 100644 --- a/crates/squawk_fmt/tests/after/drop_text_search_template.snap +++ b/crates/squawk_fmt/tests/after/drop_text_search_template.snap @@ -10,5 +10,5 @@ drop text search template if exists -- comments in every position drop /* text */ text /* search */ search /* template */ template /* if */ if /* exists */ exists - /* template name */ public /* dot */.simple_template + /* template name */ public /* dot */ .simple_template /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_transform.snap b/crates/squawk_fmt/tests/after/drop_transform.snap index 68cca5fb..ea498f61 100644 --- a/crates/squawk_fmt/tests/after/drop_transform.snap +++ b/crates/squawk_fmt/tests/after/drop_transform.snap @@ -11,6 +11,6 @@ drop transform if exists for -- comments in every position drop /* transform */ transform /* if */ if /* exists */ exists /* for */ for - /* type */ public /* dot */.customer_document + /* type */ public /* dot */ .customer_document /* language */ language /* language name */ plpgsql /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_trigger.snap b/crates/squawk_fmt/tests/after/drop_trigger.snap index c537035f..942b44a8 100644 --- a/crates/squawk_fmt/tests/after/drop_trigger.snap +++ b/crates/squawk_fmt/tests/after/drop_trigger.snap @@ -12,5 +12,5 @@ drop trigger if exists -- comments in every position drop /* trigger */ trigger /* if */ if /* exists */ exists /* name */ audit_trigger - /* on */ on /* relation */ public /* dot */.accounts + /* on */ on /* relation */ public /* dot */ .accounts /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_type.snap b/crates/squawk_fmt/tests/after/drop_type.snap index 4d5676ef..c7c2d58e 100644 --- a/crates/squawk_fmt/tests/after/drop_type.snap +++ b/crates/squawk_fmt/tests/after/drop_type.snap @@ -11,6 +11,6 @@ drop type if exists -- comments in every position drop /* type */ type /* if */ if /* exists */ exists - /* first */ public /* dot */.customer_kind /* comma */, + /* first */ public /* dot */ .customer_kind /* comma */, /* second */ reporting.event_kind /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/drop_view.snap b/crates/squawk_fmt/tests/after/drop_view.snap index f2d6f161..3fbc32b3 100644 --- a/crates/squawk_fmt/tests/after/drop_view.snap +++ b/crates/squawk_fmt/tests/after/drop_view.snap @@ -11,6 +11,6 @@ drop view if exists -- comments in every position drop /* view */ view /* if */ if /* exists */ exists - /* first view */ public /* dot */.active_accounts /* before comma */, + /* first view */ public /* dot */ .active_accounts /* before comma */, /* second view */ reporting.archived_accounts /* behavior */ restrict /* end */; diff --git a/crates/squawk_fmt/tests/after/empty_stmt.snap b/crates/squawk_fmt/tests/after/empty_stmt.snap index cd19e129..c4845f72 100644 --- a/crates/squawk_fmt/tests/after/empty_stmt.snap +++ b/crates/squawk_fmt/tests/after/empty_stmt.snap @@ -6,9 +6,6 @@ input_file: crates/squawk_fmt/tests/before/empty_stmt.sql ;; -/* before empty statement */ -; +/* before empty statement */; -; -/* between empty statements */ -; +; /* between empty statements */; diff --git a/crates/squawk_fmt/tests/after/execute.snap b/crates/squawk_fmt/tests/after/execute.snap index 40907aee..185f2b16 100644 --- a/crates/squawk_fmt/tests/after/execute.snap +++ b/crates/squawk_fmt/tests/after/execute.snap @@ -14,8 +14,7 @@ execute statement_name( a_third_intentionally_long_argument_name ); -/* before execute */ -execute /* before statement */ statement_name /* before left paren */( +/* before execute */ execute /* before statement */ statement_name /* before left paren */ ( /* after left paren */ 1 /* before comma */, /* after comma */ true /* before right paren */ ) /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/explain.snap b/crates/squawk_fmt/tests/after/explain.snap index 0bf3afad..6b3ed814 100644 --- a/crates/squawk_fmt/tests/after/explain.snap +++ b/crates/squawk_fmt/tests/after/explain.snap @@ -16,8 +16,7 @@ explain ( from an_intentionally_long_table_name where an_intentionally_long_column_name > 0; -/* before explain */ -explain /* before options */ ( +/* before explain */ explain /* before options */ ( /* before analyze */ analyze /* before value */ true /* before comma */, /* before format */ format /* before json */ json /* before close */ ) diff --git a/crates/squawk_fmt/tests/after/fetch.snap b/crates/squawk_fmt/tests/after/fetch.snap index 19a13d3b..26211b71 100644 --- a/crates/squawk_fmt/tests/after/fetch.snap +++ b/crates/squawk_fmt/tests/after/fetch.snap @@ -37,8 +37,7 @@ fetch from cursor_with_an_intentionally_long_name_that_makes_this_fetch_statement_longer_than_eighty_characters; -/* before fetch */ -fetch +/* before fetch */ fetch /* before action */ forward /* before all */ all /* before from */ from /* before cursor */ cursor_name /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/from.snap b/crates/squawk_fmt/tests/after/from.snap index 8fba00ca..9578cae7 100644 --- a/crates/squawk_fmt/tests/after/from.snap +++ b/crates/squawk_fmt/tests/after/from.snap @@ -14,13 +14,13 @@ from foo /* before alias */ as /* before alias name */ f /* before open paren */ select * from users tablesample bernoulli (10) repeatable (42); select t.id from test_tablesample as t tablesample system (50) repeatable (0); select * -from users /* before alias */ as /* before alias name */ u /* before tablesample */ tablesample /* before method */ bernoulli /* before sample opening paren */( +from users /* before alias */ as /* before alias name */ u /* before tablesample */ tablesample /* before method */ bernoulli /* before sample opening paren */ ( /* before percentage */ 10 /* before sample closing paren */ -) /* before repeatable */ repeatable /* before seed opening paren */(/* before seed */ 42 /* before seed closing paren */); +) /* before repeatable */ repeatable /* before seed opening paren */ (/* before seed */ 42 /* before seed closing paren */); select * from generate_series(1, 3); select * from lateral generate_series(1, 3) with ordinality as g (n, ord); select * -from /* before lateral */ lateral /* before call */ generate_series /* before opening paren */( +from /* before lateral */ lateral /* before call */ generate_series /* before opening paren */ ( /* before first argument */ 1 /* before comma */, /* before second argument */ 3 /* before closing paren */ ) /* before with */ with /* before ordinality */ ordinality /* before alias */ as /* before alias name */ g /* before alias opening paren */ ( @@ -34,7 +34,7 @@ from lateral cast( ) as converted; select * from collation for (foo) as collation_name; select * -from /* before lateral */ lateral /* before cast */ cast /* before opening paren */( +from /* before lateral */ lateral /* before cast */ cast /* before opening paren */ ( /* before expression */ value /* before as */ as /* before type */ int8 /* before closing paren */ ) /* before alias */ as /* before alias name */ converted; @@ -55,7 +55,7 @@ from rows from ( unnest(array[1, 2]) as (value int8) ) with ordinality as generated (first_value, second_value, ordinality); select * -from /* before lateral */ lateral /* before rows */ rows /* before from */ from /* before opening paren */( +from /* before lateral */ lateral /* before rows */ rows /* before from */ from /* before opening paren */ ( /* before first argument */ generate_series(1, 3) /* before argument comma */, /* before second argument */ unnest( array[1, 2] @@ -85,8 +85,8 @@ from lateral xmltable( a_very_long_ordinality_column_name for ordinality ) as a_very_long_xml_table_alias; select * -from /* before lateral */ lateral /* before xmltable */ xmltable /* before opening paren */( - /* before namespaces */ xmlnamespaces /* before namespace opening paren */( +from /* before lateral */ lateral /* before xmltable */ xmltable /* before opening paren */ ( + /* before namespaces */ xmlnamespaces /* before namespace opening paren */ ( /* before namespace expression */ 'urn:a' /* before as */ as /* before prefix */ a /* before namespace comma */, /* before default */ default /* before default expression */ 'urn:default' /* before namespace closing paren */ ) /* before outer comma */, @@ -148,12 +148,12 @@ from lateral json_table( error on error ) as a_very_long_json_table_alias; select * -from /* before lateral */ lateral /* before json table */ json_table /* before opening paren */( +from /* before lateral */ lateral /* before json table */ json_table /* before opening paren */ ( /* before document */ doc /* before format */ format /* before json */ json /* before comma */, /* before path */ '$[*]' /* before path as */ as /* before path name */ root /* before passing */ passing /* before argument */ x /* before argument as */ as /* before variable */ foo - /* before columns */ columns /* before columns opening paren */( + /* before columns */ columns /* before columns opening paren */ ( /* before ordinality column */ ord /* before for */ for /* before ordinality */ ordinality /* before column comma */, /* before value column */ value /* before type */ text /* before path keyword */ path /* before column path */ '$.value' /* before second column comma */, @@ -161,17 +161,17 @@ from /* before lateral */ lateral /* before json table */ json_table /* before o /* before exists */ exists /* before exists path */ path /* before exists path expression */ '$.value' /* before nested comma */, /* before nested */ nested /* before nested path */ path /* before nested expression */ '$.items[*]' /* before nested as */ as /* before nested name */ items - /* before nested columns */ columns /* before nested opening paren */( + /* before nested columns */ columns /* before nested opening paren */ ( /* before nested column */ item /* before nested type */ text /* before nested closing paren */ ) /* before columns closing paren */ ) - /* before plan */ plan /* before plan opening paren */( + /* before plan */ plan /* before plan opening paren */ ( /* before plan name */ items /* before plan closing paren */ ) /* before on error */ error /* before on */ on /* before error */ error /* before closing paren */ ) /* before alias */ as /* before alias name */ jt; select * -/* before from */ from /* before item */ only /* before relation */ public /* before dot */./* before table */ foo /* before star */ * /* before alias */ as /* before alias name */ f /* before item comma */, +/* before from */ from /* before item */ only /* before relation */ public /* before dot */ . /* before table */ foo /* before star */ * /* before alias */ as /* before alias name */ f /* before item comma */, /* before second item */ other /* before second alias */ o; select * @@ -215,7 +215,7 @@ from /* before joined relation */ pg_class /* before join */ left /* before outer */ outer /* before join keyword */ join /* before joined table */ pg_inherits /* before on */ on /* before left operand */ inhrelid /* before equals */ = /* before right operand */ oid /* before comma */, - /* before lateral item */ lateral /* before function */ pg_get_indexdef /* before opening paren */( + /* before lateral item */ lateral /* before function */ pg_get_indexdef /* before opening paren */ ( /* before argument */ pg_class.oid /* before closing paren */ ); @@ -237,7 +237,7 @@ select * from (a join b on a.id = b.id) as joined_tables; select * from a /*ja*/ left /*jb*/ outer /*jc*/ join /*jd*/ b /*je*/ on - /*jf*/ a /*jg*/./*jh*/ id /*ji*/ = /*jj*/ b /*jk*/./*jl*/ id, + /*jf*/ a /*jg*/ . /*jh*/ id /*ji*/ = /*jj*/ b /*jk*/ . /*jl*/ id, /*jm*/ c /*jn*/ join /*jo*/ d /*jp*/ using /*jq*/ ( @@ -263,8 +263,8 @@ from pg_statistic_ext s select * from statistics /* before base alias */ s - /* before cross */ cross /* before cross join */ join /* before lateral */ lateral /* before function */ unnest /* before function opening paren */( - /* before argument */ s.keys /* before cast */::int2[] /* before function closing paren */ + /* before cross */ cross /* before cross join */ join /* before lateral */ lateral /* before function */ unnest /* before function opening paren */ ( + /* before argument */ s.keys /* before cast */ ::int2[] /* before function closing paren */ ) /* before with */ with /* before ordinality */ ordinality /* before function alias */ as /* before function alias name */ u /* before alias opening paren */ ( /* before first alias column */ attnum /* before alias comma */, /* before second alias column */ ord /* before alias closing paren */ diff --git a/crates/squawk_fmt/tests/after/grant.snap b/crates/squawk_fmt/tests/after/grant.snap index 587a81ef..f80b542b 100644 --- a/crates/squawk_fmt/tests/after/grant.snap +++ b/crates/squawk_fmt/tests/after/grant.snap @@ -72,14 +72,13 @@ grant execute on procedure /* before procedure */ p(integer) to app_user; grant execute on routine /* before routine */ r(integer) to app_user; -/* before grant */ -grant +/* before grant */ grant /* before select */ select /* before columns */ ( /* before column */ payload /* before close */ ) /* before on */ on /* before table */ table - /* before object */ public /* before dot */./* after dot */ records + /* before object */ public /* before dot */ . /* after dot */ records /* before to */ to /* before role */ app_user /* before with */ with /* before grant option */ grant /* before option */ option diff --git a/crates/squawk_fmt/tests/after/graph_table.snap b/crates/squawk_fmt/tests/after/graph_table.snap index df54cbcd..c02933fe 100644 --- a/crates/squawk_fmt/tests/after/graph_table.snap +++ b/crates/squawk_fmt/tests/after/graph_table.snap @@ -51,29 +51,29 @@ from graph_table( ); select * -from /* before graph table */ graph_table /* before outer opening paren */( - /* before graph */ public /* before graph dot */./* before graph name */ g +from /* before graph table */ graph_table /* before outer opening paren */ ( + /* before graph */ public /* before graph dot */ . /* before graph name */ g /* before match */ match /* before first vertex opening paren */ (/* before first variable */ a /* before is */ is /* before first label */ person /* before vertex where */ where /* before vertex expression */ a.active /* before first vertex closing paren */) - /* before first edge minus */ - /* before edge opening bracket */[/* before edge variable */ e + /* before first edge minus */ - /* before edge opening bracket */ [/* before edge variable */ e /* before edge is */ is /* before edge label */ knows /* before edge where */ where - /* before edge expression */ e.active /* before edge closing bracket */] /* before edge ending minus */- /* before right angle */> + /* before edge expression */ e.active /* before edge closing bracket */] /* before edge ending minus */ - /* before right angle */ > /* before second vertex */ (b) /* before qualifier opening curly */ {/* before qualifier min */ 1 /* before qualifier comma */, /* before qualifier max */ 3 /* before qualifier closing curly */} /* before pattern comma */, - /* before second pattern */ /* before left angle */ < /* before left minus */- /* before left opening bracket */[left_edge /* before left closing bracket */] /* before left ending minus */- + /* before second pattern */ /* before left angle */ < /* before left minus */ - /* before left opening bracket */ [left_edge /* before left closing bracket */] /* before left ending minus */ - (c), (d) - /* before any edge */ - /* before any opening bracket */[any_edge /* before any closing bracket */] /* before any ending minus */- + /* before any edge */ - /* before any opening bracket */ [any_edge /* before any closing bracket */] /* before any ending minus */ - (e), /* before nested opening paren */ (/* before nested pattern */ (x) - /* before simple edge */ - /* before simple right angle */> + /* before simple edge */ - /* before simple right angle */ > (y) /* before nested where */ where /* before nested expression */ x.active /* before nested closing paren */) /* before graph where */ where /* before graph expression */ b.active - /* before columns */ columns /* before columns opening paren */( + /* before columns */ columns /* before columns opening paren */ ( /* before first column */ a.name /* before column as */ as /* before column name */ source /* before column comma */, /* before second column */ b.name /* before columns closing paren */ ) /* before outer closing paren */ diff --git a/crates/squawk_fmt/tests/after/group_by.snap b/crates/squawk_fmt/tests/after/group_by.snap index 60646541..f0b8e05b 100644 --- a/crates/squawk_fmt/tests/after/group_by.snap +++ b/crates/squawk_fmt/tests/after/group_by.snap @@ -4,7 +4,7 @@ input_file: crates/squawk_fmt/tests/before/group_by.sql --- select 1 group by all; select 1 group by 1, foo + 2; -select sum(c) from gs group by "rollup"(c), "cube" /* before args */(c); +select sum(c) from gs group by "rollup"(c), "cube" /* before args */ (c); select 1 group by all rollup (1, 2), cube (3, 4); select 1 group by distinct grouping sets ((), (1, 2), rollup (3), cube (4)); select @@ -23,15 +23,15 @@ group by grouping sets ( select 1 -group /* before by */ by /* before distinct */ distinct /* before grouping */ grouping /* before sets */ sets /* before outer paren */( - /* before rollup */ rollup /* before rollup paren */( +group /* before by */ by /* before distinct */ distinct /* before grouping */ grouping /* before sets */ sets /* before outer paren */ ( + /* before rollup */ rollup /* before rollup paren */ ( /* before first expression */ 1 /* before expression comma */, /* before second expression */ 2 /* before rollup close */ ) /* before group-by comma */, - /* before cube */ cube /* before cube paren */( + /* before cube */ cube /* before cube paren */ ( /* before cube expression */ 3 /* before cube close */ ) /* before second group-by comma */, - /* before nested grouping */ grouping /* before nested sets */ sets /* before nested paren */( + /* before nested grouping */ grouping /* before nested sets */ sets /* before nested paren */ ( /* before empty tuple */ () /* before nested comma */, /* before grouping expression */ ( 4 /* before tuple comma */, diff --git a/crates/squawk_fmt/tests/after/import_foreign_schema.snap b/crates/squawk_fmt/tests/after/import_foreign_schema.snap index a6b92266..d06199dc 100644 --- a/crates/squawk_fmt/tests/after/import_foreign_schema.snap +++ b/crates/squawk_fmt/tests/after/import_foreign_schema.snap @@ -17,9 +17,8 @@ import foreign schema remote from server foreign_server into an_intentionally_long_local_schema_name_that_makes_the_statement_exceed_eighty_characters; -/* before import */ -import /* before foreign */ foreign /* before schema */ schema /* before remote */ remote - /* before limit */ limit /* before to */ to /* before open */( +/* before import */ import /* before foreign */ foreign /* before schema */ schema /* before remote */ remote + /* before limit */ limit /* before to */ to /* before open */ ( /* before table */ records /* before comma */, /* before second */ users /* before close */ ) diff --git a/crates/squawk_fmt/tests/after/insert.snap b/crates/squawk_fmt/tests/after/insert.snap index 1e236f1f..ff523e70 100644 --- a/crates/squawk_fmt/tests/after/insert.snap +++ b/crates/squawk_fmt/tests/after/insert.snap @@ -45,11 +45,10 @@ with inserted as ( select organization_identifier, extremely_long_descriptive_column_name from inserted; -/*before*/ -with /*a*/ inserted/*b*/ ( +/*before*/ with /*a*/ inserted /*b*/ ( /*c*/ result_id /*d*/ ) /*e*/ as /*f*/ not /*g*/ materialized /*h*/ ( - /*i*/ insert /*j*/ into /*k*/ public /*l*/./*m*/ foo /*n*/ as /*o*/ f /*p*/ ( + /*i*/ insert /*j*/ into /*k*/ public /*l*/ . /*m*/ foo /*n*/ as /*o*/ f /*p*/ ( /*q*/ id /*r*/, /*s*/ payload /*t*/ ) diff --git a/crates/squawk_fmt/tests/after/listen.snap b/crates/squawk_fmt/tests/after/listen.snap index c1fb9be8..ff317632 100644 --- a/crates/squawk_fmt/tests/after/listen.snap +++ b/crates/squawk_fmt/tests/after/listen.snap @@ -7,5 +7,5 @@ listen events; listen an_intentionally_long_channel_name_that_makes_this_statement_longer_than_eighty_characters; -/* before listen */ -listen /* before channel */ event_channel /* before semicolon */; +/* before listen */ listen + /* before channel */ event_channel /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/load.snap b/crates/squawk_fmt/tests/after/load.snap index b13789e3..c2c532bb 100644 --- a/crates/squawk_fmt/tests/after/load.snap +++ b/crates/squawk_fmt/tests/after/load.snap @@ -9,5 +9,4 @@ load '$libdir/extension'; load 'an/intentionally/long/path/to/a/postgresql/shared/library/that/makes/this/load/statement/longer/than/eighty/characters'; -/* before load */ -load /* before filename */ 'filename' /* before semicolon */; +/* before load */ load /* before filename */ 'filename' /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/lock.snap b/crates/squawk_fmt/tests/after/lock.snap index 0cd8f659..d90daf39 100644 --- a/crates/squawk_fmt/tests/after/lock.snap +++ b/crates/squawk_fmt/tests/after/lock.snap @@ -30,9 +30,8 @@ lock table in access exclusive mode nowait; -/* before lock */ -lock /* before table */ table - /* before first relation */ only /* before first name */ public /* before dot */./* after dot */ records /* before comma */, +/* before lock */ lock /* before table */ table + /* before first relation */ only /* before first name */ public /* before dot */ . /* after dot */ records /* before comma */, /* after comma */ archived_records /* before in */ in /* before access */ access /* before exclusive */ exclusive /* before mode */ mode /* before nowait */ nowait /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/merge.snap b/crates/squawk_fmt/tests/after/merge.snap index f9a70efb..7627f1b2 100644 --- a/crates/squawk_fmt/tests/after/merge.snap +++ b/crates/squawk_fmt/tests/after/merge.snap @@ -55,8 +55,7 @@ using /* before left source */ source1 /* before left alias */ s1 when matched then delete; -/* before merge */ -merge /* before into */ into /* before target */ only /* before target open */(/* before schema */ public /* before dot */./* before table */ target /* before target close */) /* before as */ as /* before target alias */ t +/* before merge */ merge /* before into */ into /* before target */ only /* before target open */ (/* before schema */ public /* before dot */ . /* before table */ target /* before target close */) /* before as */ as /* before target alias */ t /* before using */ using /* before source */ source /* before source as */ as /* before source alias */ s /* before on */ on /* before condition */ t.id = s.id /* before first when */ when /* before matched */ matched /* before and */ and diff --git a/crates/squawk_fmt/tests/after/move.snap b/crates/squawk_fmt/tests/after/move.snap index 325399b9..45da2f15 100644 --- a/crates/squawk_fmt/tests/after/move.snap +++ b/crates/squawk_fmt/tests/after/move.snap @@ -11,8 +11,7 @@ move from an_intentionally_long_cursor_name; -/* before move */ -move +/* before move */ move /* before backward */ backward /* before all */ all /* before from */ from /* before cursor */ cursor_name /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/notify.snap b/crates/squawk_fmt/tests/after/notify.snap index 76e6137f..8c01a955 100644 --- a/crates/squawk_fmt/tests/after/notify.snap +++ b/crates/squawk_fmt/tests/after/notify.snap @@ -9,6 +9,5 @@ notify events, 'payload'; notify an_intentionally_long_channel_name_that_makes_this_statement_longer_than_eighty_characters, 'an intentionally long payload that also wraps'; -/* before notify */ -notify /* before channel */ events /* before comma */, +/* before notify */ notify /* before channel */ events /* before comma */, /* before payload */ 'payload' /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/prepare.snap b/crates/squawk_fmt/tests/after/prepare.snap index 070bf132..f8b3cd7f 100644 --- a/crates/squawk_fmt/tests/after/prepare.snap +++ b/crates/squawk_fmt/tests/after/prepare.snap @@ -1,6 +1,5 @@ --- source: crates/squawk_fmt/tests/tests.rs -assertion_line: 29 input_file: crates/squawk_fmt/tests/before/prepare.sql --- prepare statement_name as @@ -29,9 +28,8 @@ prepare select an_intentionally_long_column_name from an_intentionally_long_table_name; -/* before prepare */ -prepare - /* before name */ statement_name/* before left paren */ ( +/* before prepare */ prepare + /* before name */ statement_name /* before left paren */ ( /* after left paren */ int /* before comma */, /* after comma */ text /* before right paren */ ) diff --git a/crates/squawk_fmt/tests/after/reassign.snap b/crates/squawk_fmt/tests/after/reassign.snap index 8a1710f7..118d3646 100644 --- a/crates/squawk_fmt/tests/after/reassign.snap +++ b/crates/squawk_fmt/tests/after/reassign.snap @@ -10,8 +10,7 @@ reassign owned by current_user to an_intentionally_long_role_name_that_makes_this_statement_longer_than_eighty_characters; -/* before reassign */ -reassign /* before owned */ owned /* before by */ by +/* before reassign */ reassign /* before owned */ owned /* before by */ by /* before first */ alice /* before comma */, /* before second */ bob /* before to */ to /* before new owner */ carol /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/refresh.snap b/crates/squawk_fmt/tests/after/refresh.snap index 0a67ba1c..ac388682 100644 --- a/crates/squawk_fmt/tests/after/refresh.snap +++ b/crates/squawk_fmt/tests/after/refresh.snap @@ -8,7 +8,6 @@ refresh materialized view concurrently public.an_intentionally_long_materialized_view_name_that_makes_this_statement_longer_than_eighty_characters with no data; -/* before refresh */ -refresh /* before materialized */ materialized /* before view */ view /* before concurrently */ concurrently - /* before name */ public /* before dot */./* after dot */ summary +/* before refresh */ refresh /* before materialized */ materialized /* before view */ view /* before concurrently */ concurrently + /* before name */ public /* before dot */ . /* after dot */ summary /* before with */ with /* before no */ no /* before data */ data /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/reindex.snap b/crates/squawk_fmt/tests/after/reindex.snap index e8b3b3d0..a11702b6 100644 --- a/crates/squawk_fmt/tests/after/reindex.snap +++ b/crates/squawk_fmt/tests/after/reindex.snap @@ -30,10 +30,9 @@ reindex ( ) table concurrently an_intentionally_long_schema_name.an_intentionally_long_table_name; -/* before reindex */ -reindex /* before left paren */ ( +/* before reindex */ reindex /* before left paren */ ( /* after left paren */ concurrently /* before option value */ true /* before comma */, /* after comma */ tablespace /* before tablespace */ new_tablespace /* before second comma */, /* after second comma */ verbose /* before verbose value */ no /* before right paren */ ) - /* before target */ table /* before concurrently */ concurrently /* before table name */ public /* before dot */./* after dot */ records /* before semicolon */; + /* before target */ table /* before concurrently */ concurrently /* before table name */ public /* before dot */ . /* after dot */ records /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/repack.snap b/crates/squawk_fmt/tests/after/repack.snap index c1851e9d..cb9a0d30 100644 --- a/crates/squawk_fmt/tests/after/repack.snap +++ b/crates/squawk_fmt/tests/after/repack.snap @@ -13,12 +13,11 @@ repack repack an_intentionally_long_schema_name.an_intentionally_long_table_name_that_makes_this_statement_exceed_eighty_characters; -/* before repack */ -repack +/* before repack */ repack /* before options */ ( /* before verbose */ verbose /* before true */ true /* before close */ ) - /* before table */ public /* before dot */./* after dot */ records /* before columns */ ( + /* before table */ public /* before dot */ . /* after dot */ records /* before columns */ ( /* before column */ id /* before close */ ) - /* before using */ using /* before index */ index /* before index name */ public /* before index dot */./* after index dot */ records_idx /* before semicolon */; + /* before using */ using /* before index */ index /* before index name */ public /* before index dot */ . /* after index dot */ records_idx /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/reset.snap b/crates/squawk_fmt/tests/after/reset.snap index 9b6427ed..dc081274 100644 --- a/crates/squawk_fmt/tests/after/reset.snap +++ b/crates/squawk_fmt/tests/after/reset.snap @@ -15,9 +15,8 @@ reset transaction isolation level; reset an_intentionally_long_config_namespace.an_intentionally_long_config_group.an_intentionally_long_config_parameter_name; -/* before reset */ -reset - /* before parameter */ custom /* before first dot */./* after first dot */ group_name /* before second dot */./* after second dot */ parameter_name /* before semicolon */; +/* before reset */ reset + /* before parameter */ custom /* before first dot */ . /* after first dot */ group_name /* before second dot */ . /* after second dot */ parameter_name /* before semicolon */; reset /* before transaction */ transaction /* before isolation */ isolation /* before level */ level /* before transaction semicolon */; diff --git a/crates/squawk_fmt/tests/after/reset_role.snap b/crates/squawk_fmt/tests/after/reset_role.snap index 4a374ba6..ef699a34 100644 --- a/crates/squawk_fmt/tests/after/reset_role.snap +++ b/crates/squawk_fmt/tests/after/reset_role.snap @@ -4,5 +4,4 @@ input_file: crates/squawk_fmt/tests/before/reset_role.sql --- reset role; -/* before reset */ -reset /* before role */ role /* before semicolon */; +/* before reset */ reset /* before role */ role /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/reset_session_auth.snap b/crates/squawk_fmt/tests/after/reset_session_auth.snap index d05a7e4a..8b7b6259 100644 --- a/crates/squawk_fmt/tests/after/reset_session_auth.snap +++ b/crates/squawk_fmt/tests/after/reset_session_auth.snap @@ -4,5 +4,4 @@ input_file: crates/squawk_fmt/tests/before/reset_session_auth.sql --- reset session authorization; -/* before reset */ -reset /* before session */ session /* before authorization */ authorization /* before semicolon */; +/* before reset */ reset /* before session */ session /* before authorization */ authorization /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/revoke.snap b/crates/squawk_fmt/tests/after/revoke.snap index 45bea8fb..7ffda372 100644 --- a/crates/squawk_fmt/tests/after/revoke.snap +++ b/crates/squawk_fmt/tests/after/revoke.snap @@ -37,13 +37,12 @@ revoke from public; -/* before revoke */ -revoke +/* before revoke */ revoke /* before grant */ grant /* before option */ option /* before for */ for /* before select */ select /* before on */ on /* before table */ table - /* before object */ public /* before dot */./* after dot */ records + /* before object */ public /* before dot */ . /* after dot */ records /* before from */ from /* before role */ app_user /* before granted */ granted /* before by */ by /* before grantor */ current_user diff --git a/crates/squawk_fmt/tests/after/security_label.snap b/crates/squawk_fmt/tests/after/security_label.snap index 2792fb11..db6d07f4 100644 --- a/crates/squawk_fmt/tests/after/security_label.snap +++ b/crates/squawk_fmt/tests/after/security_label.snap @@ -14,9 +14,8 @@ security label security label on function public.process_record(bigint, text) is 'trusted'; -/* before security */ -security /* before label */ label +/* before security */ security /* before label */ label /* before for */ for /* before provider */ selinux /* before on */ on /* before foreign */ foreign /* before table */ table - /* before name */ public /* before dot */./* after dot */ records + /* before name */ public /* before dot */ . /* after dot */ records /* before is */ is /* before value */ 'trusted' /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/select.snap b/crates/squawk_fmt/tests/after/select.snap index 3553c6f4..ef3f9c30 100644 --- a/crates/squawk_fmt/tests/after/select.snap +++ b/crates/squawk_fmt/tests/after/select.snap @@ -77,12 +77,14 @@ select * from t; -- above with with -- above first -t as ( -- after open paren +t as ( + -- after open paren -- above select select 1 ), -- after comma -- above second -x as ( -- after open paren +x as ( + -- after open paren -- above select select 2 ) -- after close paren diff --git a/crates/squawk_fmt/tests/after/select_clauses.snap b/crates/squawk_fmt/tests/after/select_clauses.snap index 4d23c687..04552b5a 100644 --- a/crates/squawk_fmt/tests/after/select_clauses.snap +++ b/crates/squawk_fmt/tests/after/select_clauses.snap @@ -35,7 +35,7 @@ for no key update of a_very_long_common_table_expression_name skip locked limit a_very_long_limit_expression offset a_very_long_offset_expression rows; -with /* before recursive */ recursive /* before cte */ cte/* before columns */ ( +with /* before recursive */ recursive /* before cte */ cte /* before columns */ ( /* before column */ x /* before columns close */ ) /* before as */ as /* before materialized */ materialized /* before query open */ ( /* before query */ select 1 /* before query close */ diff --git a/crates/squawk_fmt/tests/after/select_comments.snap b/crates/squawk_fmt/tests/after/select_comments.snap index 134ee17a..19b08a7f 100644 --- a/crates/squawk_fmt/tests/after/select_comments.snap +++ b/crates/squawk_fmt/tests/after/select_comments.snap @@ -101,3 +101,21 @@ select 1 between a -- lower bound and b; + +select foo(/* first */ /* second */); + +select array[/* empty */]; + +select 1 /* first */ /* second */ + /* third */ 2; + +select (/* outer */ foo(/* inner */ 1 /* close inner */) /* close outer */); + +select + foo. + -- own-line comment after dot + bar; + +select + foo. + /* own-line block comment after dot */ + bar; diff --git a/crates/squawk_fmt/tests/after/select_expr.snap b/crates/squawk_fmt/tests/after/select_expr.snap index 271f0478..ebefe9af 100644 --- a/crates/squawk_fmt/tests/after/select_expr.snap +++ b/crates/squawk_fmt/tests/after/select_expr.snap @@ -7,7 +7,7 @@ select array[1, 2], array(select 1), array(select '1 4'::int2vector union all select '1 2'::int2vector), - /* before array query */ array /* before opening paren */( + /* before array query */ array /* before opening paren */ ( /* before left select */ select /* before left target */ 1 /* before union */ union /* before all */ all /* before right select */ select @@ -21,7 +21,7 @@ select from a_very_long_second_array_select_relation ), array[[1, 2], [3, 4]], - /* before array */ array /* before opening bracket */[ + /* before array */ array /* before opening bracket */ [ /* before first */ 1 /* before comma */, /* before second */ 2 /* before closing bracket */ ] /* after array */, @@ -57,7 +57,7 @@ select ) ) ), - /* before nested array */ array /* before outer opening paren */( + /* before nested array */ array /* before outer opening paren */ ( /* after outer opening paren */ ( /* after middle opening paren */ ( /* before select */ select @@ -97,7 +97,7 @@ select ts at time zone 'UTC', 2 ^ 3, name collate "C", - name /* before collate */ collate /* before collation */ public /* before dot */./* before name */ "C", + name /* before collate */ collate /* before collation */ public /* before dot */ . /* before name */ "C", 1 = 1, 1 >= 1, 'foo' ilike 'F%', @@ -120,7 +120,7 @@ select 1 operator(+) 1, 1 operator(public.+) 1, 1 - operator /* before paren */(/* before path */ public /* before dot */./* before op */ + /* after op */) /* after paren */ 1, + operator /* before paren */ (/* before path */ public /* before dot */ . /* before op */ + /* after op */) /* after paren */ 1, true or false, (1, 2) overlaps (3, 4), 10 % 3, @@ -136,7 +136,7 @@ select 2 = all(select x from things), 3 = some(array[3]), 4 /* before op */ - = /* before any */ any /* before opening paren */( + = /* before any */ any /* before opening paren */ ( /* before expr */ array[4] /* before closing paren */ ) /* after any */, exists(select 1 from things), @@ -160,14 +160,14 @@ select select a_very_long_exists_select_expression from a_very_long_exists_relation_name ), - /* before exists */ exists /* before opening paren */( + /* before exists */ exists /* before opening paren */ ( /* before select */ select 1 /* before closing paren */ ) /* after exists */, collation for (b + c), collation for ( a_very_long_collation_input_expression_that_forces_the_builtin_to_wrap ), - /* before collation */ collation /* before for */ for /* before opening paren */( + /* before collation */ collation /* before for */ for /* before opening paren */ ( /* before expr */ foo /* before closing paren */ ) /* after collation */, extract(year from timestamp '2001-02-16 20:38:40'), @@ -177,7 +177,7 @@ select a_very_long_field_name from a_very_long_timestamp_expression_that_forces_the_builtin_to_wrap ), - /* before extract */ extract /* before opening paren */( + /* before extract */ extract /* before opening paren */ ( /* before field */ day /* before from */ from /* before expr */ ts /* before closing paren */ ) /* after extract */, @@ -187,7 +187,7 @@ select in a_very_long_string_expression_that_forces_wrapping ), - /* before position */ position /* before opening paren */( + /* before position */ position /* before opening paren */ ( /* before substring */ 'om' /* before in */ in /* before string */ 'Thomas' /* before closing paren */ @@ -208,13 +208,13 @@ select a_very_long_start_expression, a_very_long_count_name => a_very_long_count_expression ), - /* before overlay */ overlay /* before opening paren */( + /* before overlay */ overlay /* before opening paren */ ( /* before string */ 'Txxxxas' /* before placing */ placing /* before replacement */ 'hom' /* before from */ from /* before start */ 2 /* before for */ for /* before count */ 4 /* before closing paren */ ) /* after overlay */, - overlay /* before opening paren */( + overlay /* before opening paren */ ( /* before string */ 'Txxxxas' /* before comma */, /* before replacement */ 'hom' /* before comma */, /* before start */ 2 /* before comma */, @@ -249,7 +249,7 @@ select substring( 'Thomas' /* before comma */, /* before start */ 2, /* before count */ 3 ), - /* before substring */ substring /* before opening paren */( + /* before substring */ substring /* before opening paren */ ( /* before string */ 'Thomas' /* before from */ from /* before start */ 2 /* before for */ for /* before count */ 3 /* before closing paren */ @@ -278,7 +278,7 @@ select a_second_very_long_trim_expression, a_third_very_long_trim_expression ), - /* before trim */ trim /* before opening paren */( + /* before trim */ trim /* before opening paren */ ( /* before side */ both /* before trim char */ 'x' /* before from */ from /* before string */ 'xfoox' /* before closing paren */ ) /* after trim */, @@ -289,7 +289,7 @@ select third_very_long_argument_name ), foo(), - foo( /* inside empty args */ ), + foo(/* inside empty args */), foo( -- inside empty args ), @@ -356,7 +356,7 @@ select absent on null returning a_very_long_json_arrayagg_return_type format json ), - json_arrayagg /* before opening paren */( + json_arrayagg /* before opening paren */ ( /* before value */ v /* before value format */ format /* before value json */ json /* before encoding */ encoding /* before encoding name */ utf8 @@ -395,7 +395,7 @@ select json_array((select 1)), json_array(table things), json_array(values (1), (2)), - json_array /* before opening paren */( + json_array /* before opening paren */ ( /* before first */ 1 /* before comma */, /* before second */ 2 /* before format */ format /* before json */ json @@ -418,7 +418,7 @@ select passing a_very_long_json_exists_argument as a_very_long_json_exists_name false on error ), - json_exists /* before opening paren */( + json_exists /* before opening paren */ ( /* before document */ doc /* before format */ format /* before json */ json /* before encoding */ encoding /* before encoding name */ utf8 /* before comma */, @@ -438,7 +438,7 @@ select a_very_long_json_scalar_input_expression_that_forces_the_builtin_to_wrap ), json_scalar(), - json_scalar /* before opening paren */( + json_scalar /* before opening paren */ ( /* before expression */ 1 /* before closing paren */ ), json_serialize(doc), @@ -450,7 +450,7 @@ select returning a_very_long_json_serialize_return_type_name_that_forces_returning_to_wrap format json ), - json_serialize /* before opening paren */( + json_serialize /* before opening paren */ ( /* before document */ doc /* before format */ format /* before json */ json /* before returning */ returning /* before type */ text @@ -471,7 +471,7 @@ select default a_very_long_json_query_empty_value on empty error on error ), - json_query /* before opening paren */( + json_query /* before opening paren */ ( /* before document */ doc /* before format */ format /* before json */ json /* before encoding */ encoding /* before encoding name */ utf8 /* before comma */, @@ -494,7 +494,7 @@ select default a_very_long_json_value_empty_value on empty error on error ), - json_value /* before opening paren */( + json_value /* before opening paren */ ( /* before document */ doc /* before format */ format /* before json */ json /* before comma */, /* before path */ '$.a' @@ -511,7 +511,7 @@ select format json encoding utf8 with unique keys ), - json /* before opening paren */( + json /* before opening paren */ ( /* before expression */ doc /* before format */ format /* before json */ json /* before encoding */ encoding /* before encoding name */ utf8 @@ -531,7 +531,7 @@ select with unique keys returning a_very_long_json_objectagg_return_type format json ), - json_objectagg /* before opening paren */( + json_objectagg /* before opening paren */ ( /* before key */ k /* before value keyword */ value /* before value */ v /* before value format */ format /* before value json */ json /* before null */ null /* before on */ on /* before second null */ null @@ -557,8 +557,8 @@ select returning a_very_long_json_object_return_type format json ), json_object(returning jsonb), - json_object /* before opening paren */( - /* before key */ 'a' /* before colon */: /* before value */ 1 /* before comma */, + json_object /* before opening paren */ ( + /* before key */ 'a' /* before colon */ : /* before value */ 1 /* before comma */, /* before second key */ 'b' /* before value keyword */ value /* before second value */ 2 /* before format */ format /* before json */ json /* before absent */ absent /* before on */ on /* before null */ null @@ -567,7 +567,7 @@ select /* before returning format */ format /* before returning json */ json /* before closing paren */ ), public.foo(1), - foo /* before opening paren */( + foo /* before opening paren */ ( /* before first arg */ 1 /* before comma */, /* before second arg */ 2 /* before closing paren */ ), @@ -677,7 +677,7 @@ select foo.*, (foo).bar, (/* after opening paren */ foo /* before closing paren */).bar, - foo /* before dot */./* before field */ bar, + foo /* before dot */ . /* before field */ bar, a_very_long_field_base_expression.a_very_long_first_field_name.a_very_long_second_field_name, ( a_very_long_parenthesized_field_base_expression_that_forces_wrapping @@ -686,7 +686,7 @@ select a[1], a[1][2], a[1 + 2], - a /* before bracket */[/* before index */ 1 /* before closing bracket */], + a /* before bracket */ [/* before index */ 1 /* before closing bracket */], a_very_long_indexed_expression[a_very_long_first_index_expression][ a_very_long_second_index_expression + a_very_long_index_offset_expression ], @@ -729,7 +729,7 @@ select (table foo order by a desc, b asc), ( /* before table */ table - /* before only */ only /* before relation opening paren */(/* before relation */ public /* before dot */./* before name */ foo /* before relation closing paren */) /* before outer closing paren */ + /* before only */ only /* before relation opening paren */ (/* before relation */ public /* before dot */ . /* before name */ foo /* before relation closing paren */) /* before outer closing paren */ ), ( table @@ -798,7 +798,7 @@ select c[2:], c[:3], c[:], - c /* before bracket */[/* before start */ 1 /* before colon */:/* before end */ 2 /* before closing bracket */], + c /* before bracket */ [/* before start */ 1 /* before colon */ : /* before end */ 2 /* before closing bracket */], a_very_long_sliced_expression[a_very_long_slice_start_expression:a_very_long_slice_end_expression][a_second_very_long_slice_start_expression:a_second_very_long_slice_end_expression], -- tuple expr (1, 2, 3), @@ -808,12 +808,12 @@ select third_very_long_tuple_expression ), row(), - row( /* inside empty row */ ), + row(/* inside empty row */), row( -- inside empty row ), row(1), - row /* before opening paren */(1), + row /* before opening paren */ (1), row(1, 2), row( a_very_long_first_row_expression, @@ -978,3 +978,21 @@ select -- end array ]; -- trailing statement -- after comment placement expression + +select + an_extraordinarily_long_left_operand_name in ( + select an_extraordinarily_long_column_name + from an_extraordinarily_long_table_name + ); +select + an_extraordinarily_long_left_operand_name not in ( + select an_extraordinarily_long_column_name + from an_extraordinarily_long_table_name + ); + +select treat( + an_extraordinarily_long_expression_name as an_extraordinarily_long_type_name +); + +select + an_extraordinarily_long_expression_name::an_extraordinarily_long_type_name; diff --git a/crates/squawk_fmt/tests/after/select_into.snap b/crates/squawk_fmt/tests/after/select_into.snap index 837df429..486f2321 100644 --- a/crates/squawk_fmt/tests/after/select_into.snap +++ b/crates/squawk_fmt/tests/after/select_into.snap @@ -5,11 +5,10 @@ input_file: crates/squawk_fmt/tests/before/select_into.sql select 1 into foo; select a, b into temporary table public.foo from bar; select 1 into unlogged foo; -/* before select */ -select +/* before select */ select /* before distinct */ distinct /* before first target */ a /* before target comma */, /* before second target */ b -/* before into */ into /* before local */ local /* before temporary */ temporary /* before table */ table /* before schema */ public /* before dot */./* before table name */ foo +/* before into */ into /* before local */ local /* before temporary */ temporary /* before table */ table /* before schema */ public /* before dot */ . /* before table name */ foo /* before from */ from /* before relation */ bar /* before group */ group /* before by */ by /* before group expression */ a /* before order */ order /* before order by */ by @@ -44,7 +43,7 @@ for no key update of source skip locked limit 10 offset 2 rows; -with /* before recursive */ recursive /* before cte */ cte/* before columns */ ( +with /* before recursive */ recursive /* before cte */ cte /* before columns */ ( /* before column */ a /* before column comma */, /* before second column */ b /* before columns close */ ) /* before as */ as /* before not */ not /* before materialized */ materialized /* before query open */ ( diff --git a/crates/squawk_fmt/tests/after/set.snap b/crates/squawk_fmt/tests/after/set.snap index c9f373c7..c95d98b9 100644 --- a/crates/squawk_fmt/tests/after/set.snap +++ b/crates/squawk_fmt/tests/after/set.snap @@ -57,10 +57,9 @@ set an_intentionally_long_config_namespace.an_intentionally_long_config_group.an_intentionally_long_parameter_name to an_intentionally_long_value_name, another_intentionally_long_value_name; -/* before set */ -set +/* before set */ set /* before scope */ local - /* before parameter */ custom /* before dot */./* after dot */ parameter + /* before parameter */ custom /* before dot */ . /* after dot */ parameter /* before equals */ = /* before first value */ first_value /* before comma */, /* after comma */ 'second value' /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/set_constraints.snap b/crates/squawk_fmt/tests/after/set_constraints.snap index 5b77eeff..aebe0ac9 100644 --- a/crates/squawk_fmt/tests/after/set_constraints.snap +++ b/crates/squawk_fmt/tests/after/set_constraints.snap @@ -12,11 +12,10 @@ set another_intentionally_long_constraint_name deferred; -/* before set */ -set +/* before set */ set /* before constraints */ constraints /* before first name */ first_constraint /* before comma */, - /* before second name */ public /* before dot */./* after dot */ second_constraint + /* before second name */ public /* before dot */ . /* after dot */ second_constraint /* before timing */ immediate /* before semicolon */; set diff --git a/crates/squawk_fmt/tests/after/set_role.snap b/crates/squawk_fmt/tests/after/set_role.snap index 81be69ec..7fcecbd8 100644 --- a/crates/squawk_fmt/tests/after/set_role.snap +++ b/crates/squawk_fmt/tests/after/set_role.snap @@ -19,8 +19,7 @@ set role an_intentionally_long_role_name_that_makes_this_statement_longer_than_eighty_characters; -/* before set */ -set +/* before set */ set /* before scope */ local /* before role */ role /* before target */ group /* before role name */ legacy_user /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/set_session_auth.snap b/crates/squawk_fmt/tests/after/set_session_auth.snap index d2406716..ae9fb50e 100644 --- a/crates/squawk_fmt/tests/after/set_session_auth.snap +++ b/crates/squawk_fmt/tests/after/set_session_auth.snap @@ -15,8 +15,7 @@ set authorization an_intentionally_long_role_name_that_makes_this_statement_longer_than_eighty_characters; -/* before set */ -set +/* before set */ set /* before scope */ local /* before session */ session /* before authorization */ authorization diff --git a/crates/squawk_fmt/tests/after/set_transaction.snap b/crates/squawk_fmt/tests/after/set_transaction.snap index d271bfe0..eb62537f 100644 --- a/crates/squawk_fmt/tests/after/set_transaction.snap +++ b/crates/squawk_fmt/tests/after/set_transaction.snap @@ -26,8 +26,7 @@ set read write, not deferrable; -/* before set */ -set +/* before set */ set /* before transaction */ transaction /* before first mode */ isolation /* before level */ level /* before serializable */ serializable /* before comma */, /* before read */ read /* before only */ only /* before second comma */, diff --git a/crates/squawk_fmt/tests/after/show.snap b/crates/squawk_fmt/tests/after/show.snap index af33ca20..177ba741 100644 --- a/crates/squawk_fmt/tests/after/show.snap +++ b/crates/squawk_fmt/tests/after/show.snap @@ -15,9 +15,8 @@ show transaction isolation level; show session authorization; -/* before show */ -show - /* before parameter */ custom /* before dot */./* after dot */ parameter /* before semicolon */; +/* before show */ show + /* before parameter */ custom /* before dot */ . /* after dot */ parameter /* before semicolon */; show /* before transaction */ transaction /* before isolation */ isolation /* before level */ level /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/table.snap b/crates/squawk_fmt/tests/after/table.snap index c056dde1..ec7b6518 100644 --- a/crates/squawk_fmt/tests/after/table.snap +++ b/crates/squawk_fmt/tests/after/table.snap @@ -6,9 +6,8 @@ table foo; table public.foo *; table only (public.foo); table foo order by a desc, b asc; -/* before table */ -table - /* before only */ only /* before relation opening paren */(/* before relation */ public /* before dot */./* before name */ foo /* before relation closing paren */) +/* before table */ table + /* before only */ only /* before relation opening paren */ (/* before relation */ public /* before dot */ . /* before name */ foo /* before relation closing paren */) /* before order */ order /* before by */ by /* before first expression */ a /* before desc */ desc /* before comma */, /* before second expression */ b /* before asc */ asc /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/table_constraints.snap b/crates/squawk_fmt/tests/after/table_constraints.snap index cf8652b3..fcf99c74 100644 --- a/crates/squawk_fmt/tests/after/table_constraints.snap +++ b/crates/squawk_fmt/tests/after/table_constraints.snap @@ -139,7 +139,7 @@ create table commented_constraints ( /* before foreign */ foreign /* before key */ key /* before from opening paren */ ( /* before from column */ parent_id /* before from closing paren */ ) - /* before references */ references /* before table */ public /* before dot */./* before table name */ parents /* before to opening paren */ ( + /* before references */ references /* before table */ public /* before dot */ . /* before table name */ parents /* before to opening paren */ ( /* before to column */ id /* before to closing paren */ ) /* before match */ match /* before simple */ simple @@ -152,7 +152,7 @@ create table commented_constraints ( /* before exclusion expression */ id /* before exclusion with */ with /* before exclusion op */ = /* before exclusion comma */, /* before second exclusion */ valid_at - with /* before operator */ operator /* before operator opening paren */(/* before operator name */ public /* before operator dot */./* before operator op */ && /* before operator closing paren */) /* before exclusion closing paren */ + with /* before operator */ operator /* before operator opening paren */ (/* before operator name */ public /* before operator dot */ . /* before operator op */ && /* before operator closing paren */) /* before exclusion closing paren */ ) /* before include */ include /* before include opening paren */ ( id /* before include closing paren */ diff --git a/crates/squawk_fmt/tests/after/truncate.snap b/crates/squawk_fmt/tests/after/truncate.snap index d643103e..9c2645ac 100644 --- a/crates/squawk_fmt/tests/after/truncate.snap +++ b/crates/squawk_fmt/tests/after/truncate.snap @@ -6,9 +6,8 @@ truncate foo; truncate table only foo continue identity restrict; truncate foo *, bar restart identity cascade; -/*before*/ -truncate /*a*/ table - /*b*/ public /*c*/./*d*/ foo /*e*/ * /*f*/, +/*before*/ truncate /*a*/ table + /*b*/ public /*c*/ . /*d*/ foo /*e*/ * /*f*/, /*g*/ bar /*h*/ continue /*i*/ identity /*j*/ restrict /*k*/; diff --git a/crates/squawk_fmt/tests/after/types.snap b/crates/squawk_fmt/tests/after/types.snap index 2c24e1ca..3ef42bb6 100644 --- a/crates/squawk_fmt/tests/after/types.snap +++ b/crates/squawk_fmt/tests/after/types.snap @@ -76,21 +76,23 @@ select 1::setof int; -- comments inside types create table t ( - a national /*a*/ char /*b*/ varying /*c*/(2), - b int /*d*/[], - c interval /*e*/ day to /*f*/ second /*g*/(3), - d numeric /*h*/(/*i*/ 10 /*j*/, /*k*/ 2 /*l*/), - e time /*m*/(/*n*/ 3 /*o*/) /*p*/ with /*q*/ time /*r*/ zone, - f int[ /*s*/][/*t*/ 3 /*u*/], + a national /*a*/ char /*b*/ varying /*c*/ (2), + b int /*d*/ [], + c interval /*e*/ day to /*f*/ second /*g*/ (3), + d numeric /*h*/ (/*i*/ 10 /*j*/, /*k*/ 2 /*l*/), + e time /*m*/ (/*n*/ 3 /*o*/) /*p*/ with /*q*/ time /*r*/ zone, + f int[/*s*/][/*t*/ 3 /*u*/], g timestamp /*v*/ without /*w*/ time /*x*/ zone, h timestamp with /*y*/ time /*z*/ zone, i double /*aa*/ precision, j character /*bb*/ varying, k national /*cc*/ character, - l bit /*dd*/ varying /*ee*/(/*ff*/ 3 /*gg*/), - m interval year /*hh*/ to /*ii*/ month + l bit /*dd*/ varying /*ee*/ (/*ff*/ 3 /*gg*/), + m bit /*hh*/ (3), + n character /*ii*/ (4), + o interval year /*jj*/ to /*kk*/ month ); -select 1::setof /*a*/ int, 2::pg_catalog /*b*/./*c*/ int4; +select 1::setof /*a*/ int, 2::pg_catalog /*b*/ . /*c*/ int4; -- line comments inside types create table t ( @@ -113,14 +115,14 @@ select interval(4) '3'; -- comments around casts -select 1 /*a*/::/*b*/ int8; -select cast /*c*/(/*d*/ 1 /*e*/ as /*f*/ int8 /*g*/); +select 1 /*a*/ :: /*b*/ int8; +select cast /*c*/ (/*d*/ 1 /*e*/ as /*f*/ int8 /*g*/); select a_very_long_expression_name_that_forces_the_select_to_wrap, - cast /*c*/( + cast /*c*/ ( /*d*/ 1 /*e*/ as /*f*/ int8 /*g*/ ); -select treat /*h*/(2 as /*i*/ bigint); +select treat /*h*/ (2 as /*i*/ bigint); select pg_catalog.varchar(10) /*j*/ 'foo'; select interval '4' /*k*/ year to month; diff --git a/crates/squawk_fmt/tests/after/unlisten.snap b/crates/squawk_fmt/tests/after/unlisten.snap index cf40e56c..36c76c1d 100644 --- a/crates/squawk_fmt/tests/after/unlisten.snap +++ b/crates/squawk_fmt/tests/after/unlisten.snap @@ -9,7 +9,7 @@ unlisten *; unlisten an_intentionally_long_channel_name_that_makes_this_statement_longer_than_eighty_characters; -/* before unlisten */ -unlisten /* before channel */ event_channel /* before semicolon */; +/* before unlisten */ unlisten + /* before channel */ event_channel /* before semicolon */; unlisten /* before star */ * /* before semicolon */; diff --git a/crates/squawk_fmt/tests/after/update.snap b/crates/squawk_fmt/tests/after/update.snap index c5aa957e..33e0f77f 100644 --- a/crates/squawk_fmt/tests/after/update.snap +++ b/crates/squawk_fmt/tests/after/update.snap @@ -37,13 +37,12 @@ from source where foo.id = source.id returning foo.id; -/*before*/ -update /*a*/ only /*b*/(/*c*/ public /*d*/./*e*/ foo /*f*/) +/*before*/ update /*a*/ only /*b*/ (/*c*/ public /*d*/ . /*e*/ foo /*f*/) /*g*/ for /*h*/ portion /*i*/ of /*j*/ valid_at /*k*/ from /*l*/ 1 /*m*/ to /*n*/ 2 /*o*/ as /*p*/ f /*q*/ set - /*r*/ payload/*s*/ ./*t*/ field/*u*/ [/*v*/ 1 /*w*/:/*x*/ 2 /*y*/] + /*r*/ payload /*s*/ . /*t*/ field /*u*/ [/*v*/ 1 /*w*/ : /*x*/ 2 /*y*/] /*z*/ = /*aa*/ 'new' /*ab*/, - /*ac*/ (/*ad*/ a /*ae*/, /*af*/ b /*ag*/) /*ah*/ = /*ai*/ row /*aj*/( + /*ac*/ (/*ad*/ a /*ae*/, /*af*/ b /*ag*/) /*ah*/ = /*ai*/ row /*aj*/ ( /*ak*/ 1 /*al*/, /*am*/ default /*an*/ ) @@ -52,7 +51,8 @@ update /*a*/ only /*b*/(/*c*/ public /*d*/./*e*/ foo /*f*/) /*as*/ returning /*at*/ f.id /*au*/, /*av*/ f.payload /*aw*/; -- top -with source as ( -- trailing with +with source as ( + -- trailing with select id, value from incoming -- trailing select ) -- trailing paren update foo -- trailing update diff --git a/crates/squawk_fmt/tests/after/vacuum.snap b/crates/squawk_fmt/tests/after/vacuum.snap index e0bee3ba..0397580a 100644 --- a/crates/squawk_fmt/tests/after/vacuum.snap +++ b/crates/squawk_fmt/tests/after/vacuum.snap @@ -32,13 +32,12 @@ vacuum (analyze, verbose, index_cleanup auto, parallel 4) ), another_very_long_schema_name.another_intentionally_long_table_name; -/* before */ -vacuum /* after vacuum */ ( +/* before */ vacuum /* after vacuum */ ( /* after left paren */ full /* before comma */, /* after comma */ analyze /* before value */ true /* before second comma */, /* after second comma */ index_cleanup /* before name value */ auto /* before right paren */ ) - /* before tables */ public /* before table dot */./* after table dot */ records /* before columns */ ( + /* before tables */ public /* before table dot */ . /* after table dot */ records /* before columns */ ( /* after columns left paren */ id /* before column comma */, /* after column comma */ name /* before columns right paren */ ) /* before table comma */, diff --git a/crates/squawk_fmt/tests/after/values.snap b/crates/squawk_fmt/tests/after/values.snap index adee3298..da467357 100644 --- a/crates/squawk_fmt/tests/after/values.snap +++ b/crates/squawk_fmt/tests/after/values.snap @@ -4,8 +4,7 @@ input_file: crates/squawk_fmt/tests/before/values.sql --- values (1, 2), (3, 4); values (1), (2) order by column1 desc, column2 asc; -/* before values */ -values +/* before values */ values /* before first row */ ( /* before first expression */ 1 /* before expression comma */, /* before second expression */ 2 /* before first row closing paren */ diff --git a/crates/squawk_fmt/tests/after/xml_functions.snap b/crates/squawk_fmt/tests/after/xml_functions.snap index ab7a7a66..ae78ed7a 100644 --- a/crates/squawk_fmt/tests/after/xml_functions.snap +++ b/crates/squawk_fmt/tests/after/xml_functions.snap @@ -17,9 +17,9 @@ select second_very_long_content_expression, third_very_long_content_expression ), - /* before element */ xmlelement /* before outer opening paren */( + /* before element */ xmlelement /* before outer opening paren */ ( /* before name */ name /* before tag */ tag /* before attributes comma */, - /* before xmlattributes */ xmlattributes /* before attributes opening paren */( + /* before xmlattributes */ xmlattributes /* before attributes opening paren */ ( /* before first attribute */ a /* before as */ as /* before attribute name */ attr /* before attribute comma */, /* before second attribute */ b /* before attributes closing paren */ ) /* before content comma */, @@ -35,7 +35,7 @@ select a_very_long_xml_exists_document_expression by value ), - /* before exists */ xmlexists /* before opening paren */( + /* before exists */ xmlexists /* before opening paren */ ( /* before row */ '/foo' /* before passing */ passing /* before first by */ by /* before ref */ ref @@ -47,7 +47,7 @@ select first_very_long_expression as first_very_long_element_name, second_very_long_expression as second_very_long_element_name ), - /* before forest */ xmlforest /* before opening paren */( + /* before forest */ xmlforest /* before opening paren */ ( /* before first expression */ a /* before as */ as /* before tag */ first /* before comma */, /* before second expression */ b /* before closing paren */ ) /* after forest */, @@ -58,7 +58,7 @@ select a_very_long_xml_parse_document_expression_that_forces_the_xml_parse_node_to_wrap preserve whitespace ), - /* before parse */ xmlparse /* before opening paren */( + /* before parse */ xmlparse /* before opening paren */ ( /* before kind */ document /* before expression */ value /* before preserve */ preserve /* before whitespace */ whitespace /* before closing paren */ @@ -69,7 +69,7 @@ select name a_very_long_xml_processing_instruction_target, a_very_long_xml_processing_instruction_expression_that_forces_the_xml_pi_node_to_wrap ), - /* before pi */ xmlpi /* before opening paren */( + /* before pi */ xmlpi /* before opening paren */ ( /* before name */ name /* before target */ php /* before comma */, /* before expression */ 'echo' /* before closing paren */ ) /* after pi */, @@ -82,9 +82,9 @@ select version a_very_long_xml_root_version_expression, standalone no value ), - /* before root */ xmlroot /* before opening paren */( + /* before root */ xmlroot /* before opening paren */ ( /* before expression */ doc /* before version comma */, - /* before version */ version /* before no */ no /* before version value */ value/* before standalone comma */ , + /* before version */ version /* before no */ no /* before version value */ value /* before standalone comma */, /* before standalone */ standalone /* before standalone no */ no /* before standalone value */ value /* before closing paren */ ) /* after root */, xmlserialize(document doc as text), @@ -95,7 +95,7 @@ select as a_very_long_xml_serialize_return_type no indent ), - /* before serialize */ xmlserialize /* before opening paren */( + /* before serialize */ xmlserialize /* before opening paren */ ( /* before kind */ content /* before expression */ doc /* before as */ as /* before type */ text /* before no */ no /* before indent */ indent /* before closing paren */ diff --git a/crates/squawk_fmt/tests/before/comments.sql b/crates/squawk_fmt/tests/before/comments.sql index bdaa1933..fdf22c8e 100644 --- a/crates/squawk_fmt/tests/before/comments.sql +++ b/crates/squawk_fmt/tests/before/comments.sql @@ -47,3 +47,5 @@ select 1; /*foo*/ select 1; + +/* first *//* second */select 1;-- directly trailing diff --git a/crates/squawk_fmt/tests/before/create_table.sql b/crates/squawk_fmt/tests/before/create_table.sql index 070e4fc2..c1509ba0 100644 --- a/crates/squawk_fmt/tests/before/create_table.sql +++ b/crates/squawk_fmt/tests/before/create_table.sql @@ -97,3 +97,5 @@ create table t (a int default (1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 + 9 + 10 + 11 + 12 -- comments in parenthesized default expressions create table default_expression_comments (a int /* before default */ default /* before open */ (/* before expression */ greatest(/* before first */ 1 /* before comma */, /* before second */ 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 /* before call close */) /* before default close */) /* before comma */, b int); + +create table default_subquery (a int default (select count(*) from an_extraordinarily_long_table_name_that_forces_the_subquery_to_wrap)); diff --git a/crates/squawk_fmt/tests/before/select_comments.sql b/crates/squawk_fmt/tests/before/select_comments.sql index 6ad08b78..796428a7 100644 --- a/crates/squawk_fmt/tests/before/select_comments.sql +++ b/crates/squawk_fmt/tests/before/select_comments.sql @@ -76,3 +76,19 @@ and b; select 1 between a -- lower bound and b; + +select foo( /* first */ /* second */ ); + +select array[ /* empty */ ]; + +select 1/* first *//* second */+/* third */2; + +select ( /* outer */ foo( /* inner */ 1 /* close inner */ ) /* close outer */ ); + +select foo. +-- own-line comment after dot +bar; + +select foo. +/* own-line block comment after dot */ +bar; diff --git a/crates/squawk_fmt/tests/before/select_expr.sql b/crates/squawk_fmt/tests/before/select_expr.sql index 878d8e7d..c79a919a 100644 --- a/crates/squawk_fmt/tests/before/select_expr.sql +++ b/crates/squawk_fmt/tests/before/select_expr.sql @@ -430,3 +430,10 @@ select -- end array ]; -- trailing statement -- after comment placement expression + +select an_extraordinarily_long_left_operand_name in (select an_extraordinarily_long_column_name from an_extraordinarily_long_table_name); +select an_extraordinarily_long_left_operand_name not in (select an_extraordinarily_long_column_name from an_extraordinarily_long_table_name); + +select treat(an_extraordinarily_long_expression_name as an_extraordinarily_long_type_name); + +select an_extraordinarily_long_expression_name::an_extraordinarily_long_type_name; diff --git a/crates/squawk_fmt/tests/before/types.sql b/crates/squawk_fmt/tests/before/types.sql index f38f0f74..9c85c5ec 100644 --- a/crates/squawk_fmt/tests/before/types.sql +++ b/crates/squawk_fmt/tests/before/types.sql @@ -56,7 +56,9 @@ create table t ( j CHARACTER /*bb*/ VARYING, k NATIONAL /*cc*/ CHARACTER, l BIT /*dd*/ VARYING /*ee*/ ( /*ff*/ 3 /*gg*/ ), - m INTERVAL YEAR /*hh*/ TO /*ii*/ MONTH + m BIT /*hh*/ (3), + n CHARACTER /*ii*/ (4), + o INTERVAL YEAR /*jj*/ TO /*kk*/ MONTH ); select 1::SETOF /*a*/ INT, 2::pg_catalog /*b*/ . /*c*/ int4; From 7aad502d8a59d425f31f269c3814aafb3edcfa61 Mon Sep 17 00:00:00 2001 From: Steve Dignam Date: Sat, 3 Oct 2026 19:45:09 -0400 Subject: [PATCH 4/7] refactor validation --- crates/squawk_fmt/src/lib.rs | 2 +- crates/squawk_fmt/src/main.rs | 28 +-- crates/squawk_fmt/src/token_compare.rs | 131 ---------- crates/squawk_fmt/src/validation.rs | 316 +++++++++++++++++++++++++ crates/squawk_fmt/tests/tests.rs | 250 +++++-------------- 5 files changed, 380 insertions(+), 347 deletions(-) delete mode 100644 crates/squawk_fmt/src/token_compare.rs create mode 100644 crates/squawk_fmt/src/validation.rs diff --git a/crates/squawk_fmt/src/lib.rs b/crates/squawk_fmt/src/lib.rs index 96c37397..b2ac2283 100644 --- a/crates/squawk_fmt/src/lib.rs +++ b/crates/squawk_fmt/src/lib.rs @@ -1,5 +1,5 @@ mod comment; mod fmt; -pub mod token_compare; +pub mod validation; pub use fmt::{FormatOptions, fmt, fmt_str}; diff --git a/crates/squawk_fmt/src/main.rs b/crates/squawk_fmt/src/main.rs index 7597794b..5de12130 100644 --- a/crates/squawk_fmt/src/main.rs +++ b/crates/squawk_fmt/src/main.rs @@ -5,7 +5,7 @@ use std::process::ExitCode; use annotate_snippets::{AnnotationKind, Level, Renderer, Snippet, renderer::DecorStyle}; use anyhow::Result; use clap::Parser; -use squawk_fmt::{FormatOptions, token_compare::assert_no_dropped_tokens}; +use squawk_fmt::{FormatOptions, validation::validate_format}; use squawk_syntax::SourceFile; #[derive(Parser)] @@ -58,26 +58,12 @@ fn main() -> Result { return Ok(ExitCode::FAILURE); } - let formatted = squawk_fmt::fmt_str( - &input, - FormatOptions { - indent: cli.indent, - width: cli.width, - }, - )?; - assert_no_dropped_tokens(&input, &formatted); - - let reparse = SourceFile::parse(&formatted); - assert!( - reparse.errors().is_empty(), - "formatted output has syntax errors:\n{}\n\nformatted output:\n{formatted}", - reparse - .errors() - .iter() - .map(ToString::to_string) - .collect::>() - .join("\n") - ); + let options = FormatOptions { + indent: cli.indent, + width: cli.width, + }; + let formatted = squawk_fmt::fmt_str(&input, options)?; + validate_format(&input, &formatted, options)?; write!(io::stdout().lock(), "{formatted}")?; Ok(ExitCode::SUCCESS) diff --git a/crates/squawk_fmt/src/token_compare.rs b/crates/squawk_fmt/src/token_compare.rs deleted file mode 100644 index c103722a..00000000 --- a/crates/squawk_fmt/src/token_compare.rs +++ /dev/null @@ -1,131 +0,0 @@ -use squawk_lexer::{Token, TokenKind, tokenize}; -use squawk_line_index::UniversalNewlines; - -fn meaningful_tokens(text: &str) -> Vec<(TokenKind, &str)> { - let mut tokens = Vec::new(); - let mut offset = 0; - for Token { kind, len } in tokenize(text) { - let len = len as usize; - if kind != TokenKind::Eof && kind != TokenKind::Whitespace { - tokens.push((kind, &text[offset..offset + len])); - } - offset += len; - } - tokens -} - -fn line_comments_equivalent(before: &str, after: &str) -> bool { - let before = before.trim_end_matches([' ', '\t']); - let after = after.trim_end_matches([' ', '\t']); - if before == after { - return true; - } - - let Some(content) = before.strip_prefix("--") else { - return false; - }; - if content.is_empty() || content.starts_with(' ') || content.starts_with('\t') { - return false; - } - - after.strip_prefix("-- ") == Some(content) -} - -fn tokens_equivalent(before: (TokenKind, &str), after: (TokenKind, &str)) -> bool { - let (before_kind, before_text) = before; - let (after_kind, after_text) = after; - - if before_kind == after_kind { - if before_kind == TokenKind::LineComment { - return line_comments_equivalent(before_text, after_text); - } - if matches!(before_kind, TokenKind::BlockComment { .. }) { - let normalize = |text: &str| { - let align_stars = text - .universal_newlines() - .skip(1) - .all(|line| line.as_str().trim_start().starts_with('*')); - text.universal_newlines() - .map(|line| { - let line = line.as_str().trim_end_matches([' ', '\t']); - if align_stars && line.trim_start().starts_with('*') { - format!(" {}", line.trim()) - } else { - line.to_string() - } - }) - .collect::>() - .join("\n") - }; - return normalize(before_text) == normalize(after_text); - } - return before_text.eq_ignore_ascii_case(after_text); - } - - // The formatter removes unnecessary identifier quotes, so compare quoted - // and unquoted identifier tokens by their contents. - fn unquote<'a>(kind: &TokenKind, text: &'a str) -> Option<&'a str> { - match kind { - TokenKind::QuotedIdent { .. } => text - .strip_prefix('"') - .and_then(|text| text.strip_suffix('"')), - TokenKind::Ident => Some(text), - _ => None, - } - } - - match ( - unquote(&before_kind, before_text), - unquote(&after_kind, after_text), - ) { - (Some(before), Some(after)) => before.eq_ignore_ascii_case(after), - _ => false, - } -} - -pub fn assert_no_dropped_tokens(before: &str, after: &str) { - let before_tokens = meaningful_tokens(before); - let after_tokens = meaningful_tokens(after); - - let before_len = before_tokens.len(); - let after_len = after_tokens.len(); - - for (index, (&before, &after)) in before_tokens.iter().zip(&after_tokens).enumerate() { - assert!( - tokens_equivalent(before, after), - "token mismatch at position {index}:\n before: {:?} {:?}\n after: {:?} {:?}", - before.0, - before.1, - after.0, - after.1 - ); - } - - assert!( - before_len == after_len, - "token count mismatch: before has {before_len} tokens, after has {after_len} tokens\n {}", - if before_len > after_len { - let dropped = &before_tokens[after_len..]; - format!( - "dropped {} token(s): {}", - dropped.len(), - dropped - .iter() - .map(|(kind, text)| format!("{kind:?} {text:?}")) - .collect::>() - .join(", ") - ) - } else { - let extra = &after_tokens[before_len..]; - format!( - "extra {} token(s): {}", - extra.len(), - extra - .iter() - .map(|(kind, text)| format!("{kind:?} {text:?}")) - .collect::>() - .join(", ") - ) - } - ); -} diff --git a/crates/squawk_fmt/src/validation.rs b/crates/squawk_fmt/src/validation.rs new file mode 100644 index 00000000..8be2384b --- /dev/null +++ b/crates/squawk_fmt/src/validation.rs @@ -0,0 +1,316 @@ +use std::ops::Range; + +use annotate_snippets::{AnnotationKind, Level, Renderer, Snippet}; +use anyhow::{Result, bail, ensure}; +use squawk_lexer::{BOM, Token, TokenKind, tokenize}; +use squawk_line_index::UniversalNewlines; + +use crate::fmt::{FormatOptions, fmt_str}; + +pub fn validate_format(before: &str, formatted: &str, options: FormatOptions) -> Result<()> { + validate_no_dropped_tokens(before, formatted)?; + validate_parses(formatted)?; + validate_no_extra_spaces(formatted)?; + validate_indentation(formatted, options.indent)?; + validate_comment_spacing(formatted)?; + ensure!( + fmt_str(formatted, options)? == formatted, + "formatting isn't idempotent" + ); + Ok(()) +} + +#[track_caller] +pub fn assert_valid_format(before: &str, formatted: &str, options: FormatOptions) { + if let Err(error) = validate_format(before, formatted, options) { + panic!("{error}"); + } +} + +fn validate_parses(formatted: &str) -> Result<()> { + let parse = squawk_syntax::ast::SourceFile::parse(formatted); + ensure!( + parse.errors().is_empty(), + "formatted output has syntax errors:\n{}\n\nformatted output:\n{formatted}", + parse + .errors() + .iter() + .map(ToString::to_string) + .collect::>() + .join("\n") + ); + Ok(()) +} + +fn validate_no_extra_spaces(formatted: &str) -> Result<()> { + let mut offset = 0; + for Token { kind, len } in tokenize(formatted) { + let start = offset; + offset += len as usize; + if kind != TokenKind::Whitespace { + continue; + } + let text = &formatted[start..offset]; + let at_line_start = start == 0 || formatted[..start].ends_with(['\n', '\r']); + let at_eof = offset == formatted.len(); + if at_line_start || at_eof || text.contains(['\n', '\r']) || text == " " { + continue; + } + let snippet = Snippet::source(formatted) + .fold(true) + .annotation(AnnotationKind::Primary.span(start..offset)); + let group = Level::ERROR + .primary_title(format!( + "expected a single space between tokens, found {text:?}" + )) + .element(snippet); + bail!(Renderer::plain().render(&[group]).to_string()); + } + Ok(()) +} + +fn validate_indentation(formatted: &str, indent: usize) -> Result<()> { + ensure!(indent > 0, "indent must be greater than zero"); + let mut offset = 0; + for Token { kind, len } in tokenize(formatted) { + let start = offset; + offset += len as usize; + if kind != TokenKind::Whitespace { + continue; + } + let text = &formatted[start..offset]; + let mut indentation_start = match text.rfind(['\n', '\r']) { + Some(newline) => start + newline + 1, + None if start == 0 => 0, + None => continue, + }; + if formatted[indentation_start..offset].starts_with(BOM) { + indentation_start += BOM.len(); + } + let indentation = offset - indentation_start; + ensure!( + indentation % indent == 0, + "indentation must be a multiple of {indent}, found {indentation} spaces at byte {indentation_start}" + ); + } + Ok(()) +} + +fn comment_spacing_error(formatted: &str) -> Option<(Range, &'static str)> { + let mut offset = 0; + let mut tokens = tokenize(formatted) + .map(|Token { kind, len }| { + let start = offset; + offset += len as usize; + (kind, start..offset) + }) + .filter(|(kind, _)| *kind != TokenKind::Whitespace) + .peekable(); + + let mut previous = None; + while let Some((kind, span)) = tokens.next() { + let left = previous.replace((kind, span.end)); + if !matches!( + kind, + TokenKind::LineComment | TokenKind::BlockComment { .. } + ) { + continue; + } + if let Some((previous, previous_end)) = left { + let touching = previous_end == span.start; + let own_line = formatted[previous_end..span.start].contains(['\n', '\r']); + let after_opening_delimiter = matches!( + previous, + TokenKind::OpenParen | TokenKind::OpenBracket | TokenKind::OpenCurly + ); + if after_opening_delimiter && !own_line { + let wraps = kind == TokenKind::LineComment + || tokens.peek().is_some_and(|(_, next_span)| { + formatted[span.end..next_span.start].contains(['\n', '\r']) + }); + if wraps { + return Some(( + span, + "comment after an opening delimiter must be on its own line when the contents wrap", + )); + } + } + let must_touch = + matches!(kind, TokenKind::BlockComment { .. }) && after_opening_delimiter; + if must_touch && !touching && !own_line { + return Some(( + span, + "block comment must touch the opening delimiter on its left", + )); + } + if !must_touch && touching { + return Some((span, "comment must have whitespace on its left")); + } + } + if matches!(kind, TokenKind::BlockComment { .. }) + && let Some((next, next_span)) = tokens.peek() + { + let touching = span.end == next_span.start; + let own_line = formatted[span.end..next_span.start].contains(['\n', '\r']); + let must_touch = matches!( + next, + TokenKind::CloseParen + | TokenKind::CloseBracket + | TokenKind::CloseCurly + | TokenKind::Comma + | TokenKind::Semi + ); + if must_touch && !touching && !own_line { + return Some((span, "block comment must touch the delimiter on its right")); + } + if !must_touch && touching { + return Some((span, "block comment must have whitespace on its right")); + } + } + } + None +} + +fn comment_spacing_diagnostic(formatted: &str) -> Option { + let (span, message) = comment_spacing_error(formatted)?; + let snippet = Snippet::source(formatted) + .fold(true) + .annotation(AnnotationKind::Primary.span(span)); + let group = Level::ERROR.primary_title(message).element(snippet); + Some(Renderer::plain().render(&[group]).to_string()) +} + +fn validate_comment_spacing(formatted: &str) -> Result<()> { + if let Some(diagnostic) = comment_spacing_diagnostic(formatted) { + bail!(diagnostic); + } + Ok(()) +} + +fn meaningful_tokens(text: &str) -> Vec<(TokenKind, &str)> { + let mut tokens = Vec::new(); + let mut offset = 0; + for Token { kind, len } in tokenize(text) { + let len = len as usize; + if kind != TokenKind::Eof && kind != TokenKind::Whitespace { + tokens.push((kind, &text[offset..offset + len])); + } + offset += len; + } + tokens +} + +fn line_comments_equivalent(before: &str, after: &str) -> bool { + let before = before.trim_end_matches([' ', '\t']); + let after = after.trim_end_matches([' ', '\t']); + if before == after { + return true; + } + + let Some(content) = before.strip_prefix("--") else { + return false; + }; + if content.is_empty() || content.starts_with(' ') || content.starts_with('\t') { + return false; + } + + after.strip_prefix("-- ") == Some(content) +} + +fn tokens_equivalent(before: (TokenKind, &str), after: (TokenKind, &str)) -> bool { + let (before_kind, before_text) = before; + let (after_kind, after_text) = after; + + if before_kind == after_kind { + if before_kind == TokenKind::LineComment { + return line_comments_equivalent(before_text, after_text); + } + if matches!(before_kind, TokenKind::BlockComment { .. }) { + let normalize = |text: &str| { + let align_stars = text + .universal_newlines() + .skip(1) + .all(|line| line.as_str().trim_start().starts_with('*')); + text.universal_newlines() + .map(|line| { + let line = line.as_str().trim_end_matches([' ', '\t']); + if align_stars && line.trim_start().starts_with('*') { + format!(" {}", line.trim()) + } else { + line.to_string() + } + }) + .collect::>() + .join("\n") + }; + return normalize(before_text) == normalize(after_text); + } + return before_text.eq_ignore_ascii_case(after_text); + } + + fn unquote<'a>(kind: &TokenKind, text: &'a str) -> Option<&'a str> { + match kind { + TokenKind::QuotedIdent { .. } => text + .strip_prefix('"') + .and_then(|text| text.strip_suffix('"')), + TokenKind::Ident => Some(text), + _ => None, + } + } + + match ( + unquote(&before_kind, before_text), + unquote(&after_kind, after_text), + ) { + (Some(before), Some(after)) => before.eq_ignore_ascii_case(after), + _ => false, + } +} + +fn validate_no_dropped_tokens(before: &str, after: &str) -> Result<()> { + let before_tokens = meaningful_tokens(before); + let after_tokens = meaningful_tokens(after); + + let before_len = before_tokens.len(); + let after_len = after_tokens.len(); + + for (index, (&before, &after)) in before_tokens.iter().zip(&after_tokens).enumerate() { + ensure!( + tokens_equivalent(before, after), + "token mismatch at position {index}:\n before: {:?} {:?}\n after: {:?} {:?}", + before.0, + before.1, + after.0, + after.1 + ); + } + + ensure!( + before_len == after_len, + "token count mismatch: before has {before_len} tokens, after has {after_len} tokens\n {}", + if before_len > after_len { + let dropped = &before_tokens[after_len..]; + format!( + "dropped {} token(s): {}", + dropped.len(), + dropped + .iter() + .map(|(kind, text)| format!("{kind:?} {text:?}")) + .collect::>() + .join(", ") + ) + } else { + let extra = &after_tokens[before_len..]; + format!( + "extra {} token(s): {}", + extra.len(), + extra + .iter() + .map(|(kind, text)| format!("{kind:?} {text:?}")) + .collect::>() + .join(", ") + ) + } + ); + Ok(()) +} diff --git a/crates/squawk_fmt/tests/tests.rs b/crates/squawk_fmt/tests/tests.rs index 0ff8bd45..e488f753 100644 --- a/crates/squawk_fmt/tests/tests.rs +++ b/crates/squawk_fmt/tests/tests.rs @@ -1,9 +1,7 @@ -use annotate_snippets::{AnnotationKind, Level, Renderer, Snippet}; use camino::Utf8Path; use dir_test::{Fixture, dir_test}; use insta::{assert_snapshot, with_settings}; -use squawk_fmt::token_compare::assert_no_dropped_tokens; -use squawk_lexer::{Token, TokenKind, tokenize}; +use squawk_fmt::validation::assert_valid_format; #[dir_test( dir: "$CARGO_MANIFEST_DIR/tests/before", @@ -19,15 +17,7 @@ fn fmt(fixture: Fixture<&str>) { let formatted = squawk_fmt::fmt_str(content, Default::default()).unwrap(); - assert_no_dropped_tokens(content, &formatted); - assert_parses(&formatted); - assert_no_extra_spaces(&formatted); - assert_comment_spacing(&formatted); - assert_eq!( - squawk_fmt::fmt_str(&formatted, Default::default()).unwrap(), - formatted, - "formatting isn't idempotent" - ); + assert_valid_format(content, &formatted, Default::default()); with_settings!({ omit_expression => true, input_file => absolute_fixture_path, @@ -53,8 +43,7 @@ fn fmt_with_line_ending(line_ending: &str) -> String { match squawk_fmt::fmt_str(&sql, Default::default()) { Ok(formatted) => { - assert_no_dropped_tokens(&sql, &formatted); - assert_parses(&formatted); + assert_valid_format(&sql, &formatted, Default::default()); formatted.replace('\r', "") } Err(err) => format!("error: {err}"), @@ -105,7 +94,9 @@ fn configurable_indent() { ..Default::default() }; - assert_snapshot!(squawk_fmt::fmt_str(sql, options).unwrap(), @" + let formatted = squawk_fmt::fmt_str(sql, options).unwrap(); + assert_valid_format(sql, &formatted, options); + assert_snapshot!(formatted, @" select 'a', 'really long string '; @@ -120,7 +111,9 @@ fn configurable_width() { ..Default::default() }; - assert_snapshot!(squawk_fmt::fmt_str(sql, options).unwrap(), @" + let formatted = squawk_fmt::fmt_str(sql, options).unwrap(); + assert_valid_format(sql, &formatted, options); + assert_snapshot!(formatted, @" select first_column, second_column; @@ -133,11 +126,8 @@ fn normalizes_line_endings_inside_block_comments() { let expected = "select 1;\r\n/* a\r\n * comment\r\n */\r\nselect 2;\r\n"; let formatted = squawk_fmt::fmt_str(sql, Default::default()).unwrap(); + assert_valid_format(sql, &formatted, Default::default()); assert_eq!(formatted, expected); - assert_eq!( - squawk_fmt::fmt_str(&formatted, Default::default()).unwrap(), - expected - ); } #[test] @@ -145,10 +135,9 @@ fn removes_trailing_whitespace_from_comments() { let sql = "select 1; -- ok \n/* a \n * comment\t\n */\nselect 2;\n"; let expected = "select 1; -- ok\n/* a\n * comment\n */\nselect 2;\n"; - assert_eq!( - squawk_fmt::fmt_str(sql, Default::default()).unwrap(), - expected - ); + let formatted = squawk_fmt::fmt_str(sql, Default::default()).unwrap(); + assert_valid_format(sql, &formatted, Default::default()); + assert_eq!(formatted, expected); } #[test] @@ -157,13 +146,8 @@ fn preserves_a_leading_bom() { let expected = "\u{feff}select 1;\n"; let formatted = squawk_fmt::fmt_str(sql, Default::default()).unwrap(); - assert_no_dropped_tokens(sql, &formatted); - assert_parses(&formatted); + assert_valid_format(sql, &formatted, Default::default()); assert_eq!(formatted, expected); - assert_eq!( - squawk_fmt::fmt_str(&formatted, Default::default()).unwrap(), - expected - ); } #[test] @@ -179,159 +163,37 @@ fn removes_leading_and_trailing_whitespace() { ("\u{feff} /* c */ select 1;", "\u{feff}/* c */ select 1;"), ] { let formatted = squawk_fmt::fmt_str(sql, Default::default()).unwrap(); + assert_valid_format(sql, &formatted, Default::default()); assert_eq!(formatted, expected); - assert_eq!( - squawk_fmt::fmt_str(&formatted, Default::default()).unwrap(), - expected - ); } } -fn assert_parses(formatted: &str) { - let parse = squawk_syntax::ast::SourceFile::parse(formatted); - assert!( - parse.errors().is_empty(), - "formatted output has syntax errors:\n{}\n\nformatted output:\n{formatted}", - parse - .errors() - .iter() - .map(ToString::to_string) - .collect::>() - .join("\n") - ); -} - -fn comment_spacing_error(formatted: &str) -> Option<(std::ops::Range, &'static str)> { - let mut offset = 0; - let mut tokens = tokenize(formatted) - .map(|Token { kind, len }| { - let start = offset; - offset += len as usize; - (kind, start..offset) - }) - .filter(|(kind, _)| *kind != TokenKind::Whitespace) - .peekable(); - - let mut previous = None; - while let Some((kind, span)) = tokens.next() { - let left = previous.replace((kind, span.end)); - if !matches!( - kind, - TokenKind::LineComment | TokenKind::BlockComment { .. } - ) { - continue; - } - if let Some((previous, previous_end)) = left { - let touching = previous_end == span.start; - let own_line = formatted[previous_end..span.start].contains(['\n', '\r']); - let after_opening_delimiter = matches!( - previous, - TokenKind::OpenParen | TokenKind::OpenBracket | TokenKind::OpenCurly - ); - if after_opening_delimiter && !own_line { - let wraps = kind == TokenKind::LineComment - || tokens.peek().is_some_and(|(_, next_span)| { - formatted[span.end..next_span.start].contains(['\n', '\r']) - }); - if wraps { - return Some(( - span, - "comment after an opening delimiter must be on its own line when the contents wrap", - )); - } - } - let must_touch = - matches!(kind, TokenKind::BlockComment { .. }) && after_opening_delimiter; - if must_touch && !touching && !own_line { - return Some(( - span, - "block comment must touch the opening delimiter on its left", - )); - } - if !must_touch && touching { - return Some((span, "comment must have whitespace on its left")); - } - } - if matches!(kind, TokenKind::BlockComment { .. }) - && let Some((next, next_span)) = tokens.peek() - { - let touching = span.end == next_span.start; - let own_line = formatted[span.end..next_span.start].contains(['\n', '\r']); - let must_touch = matches!( - next, - TokenKind::CloseParen - | TokenKind::CloseBracket - | TokenKind::CloseCurly - | TokenKind::Comma - | TokenKind::Semi - ); - if must_touch && !touching && !own_line { - return Some((span, "block comment must touch the delimiter on its right")); - } - if !must_touch && touching { - return Some((span, "block comment must have whitespace on its right")); - } - } - } - None -} +#[cfg(test)] +mod comment_spacing_test { + use insta::assert_snapshot; -fn comment_spacing_diagnostic(formatted: &str) -> Option { - let (span, message) = comment_spacing_error(formatted)?; - let snippet = Snippet::source(formatted) - .fold(true) - .annotation(AnnotationKind::Primary.span(span)); - let group = Level::ERROR.primary_title(message).element(snippet); - Some(Renderer::plain().render(&[group]).to_string()) -} + use squawk_fmt::validation::validate_format; -fn assert_comment_spacing(formatted: &str) { - if let Some(diagnostic) = comment_spacing_diagnostic(formatted) { - panic!("{diagnostic}"); + fn assert_valid(sql: &str) { + let formatted = squawk_fmt::fmt_str(sql, Default::default()).unwrap(); + validate_format(sql, &formatted, Default::default()).unwrap(); } -} -fn assert_no_extra_spaces(formatted: &str) { - let mut offset = 0; - for Token { kind, len } in tokenize(formatted) { - let start = offset; - offset += len as usize; - if kind != TokenKind::Whitespace { - continue; - } - let text = &formatted[start..offset]; - let at_line_start = start == 0 || formatted[..start].ends_with(['\n', '\r']); - let at_eof = offset == formatted.len(); - if at_line_start || at_eof || text.contains(['\n', '\r']) || text == " " { - continue; - } - let snippet = Snippet::source(formatted) - .fold(true) - .annotation(AnnotationKind::Primary.span(start..offset)); - let group = Level::ERROR - .primary_title(format!( - "expected a single space between tokens, found {text:?}" - )) - .element(snippet); - panic!("{}", Renderer::plain().render(&[group])); + fn validation_diagnostic(formatted: &str) -> String { + validate_format(formatted, formatted, Default::default()) + .unwrap_err() + .to_string() } -} - -#[cfg(test)] -mod comment_spacing_test { - use insta::assert_snapshot; - - use crate::{assert_comment_spacing, comment_spacing_diagnostic}; /// Block & line comments do not need whitespace at file boundaries. #[test] fn file_boundaries() { - assert_comment_spacing( + assert_valid( r"/* foo */ select 1; /* bar */", ); - assert_comment_spacing( + assert_valid( r"-- foo select 1; -- bar", @@ -341,7 +203,7 @@ select 1; /// Block and line comments are fine by themselves. #[test] fn own_line() { - assert_comment_spacing( + assert_valid( r" -- foo select 1; @@ -352,7 +214,7 @@ select 1;", #[test] fn delimiters_across_line_breaks() { - assert_comment_spacing( + assert_valid( r"create table t ( /* a */ a int, b int /* b */ @@ -363,8 +225,8 @@ select 1;", /// Trailing line comments must have whitespace on their left. #[test] fn trailing_line_comments() { - assert_comment_spacing("select 1; -- comment"); - assert_snapshot!(comment_spacing_diagnostic("select 1;-- comment").unwrap(), @" + assert_valid("select 1; -- comment"); + assert_snapshot!(validation_diagnostic("select 1;-- comment"), @" error: comment must have whitespace on its left | 1 | select 1;-- comment @@ -375,7 +237,7 @@ select 1;", /// Block comments must be surrounded with whitespace. #[test] fn block_comments_surrounded_by_whitespace() { - assert_comment_spacing( + assert_valid( r" select 1 /*c*/ + 1; create function f(v accounts.id /* c */ % /* c */ type) returns int language sql return 1; @@ -388,43 +250,43 @@ select (array[1, 2, 3]) /* c */ [1]; select * from graph_table(g match (a)-> /* c */ {1, 3}(b) columns (a.id)); ", ); - assert_snapshot!(comment_spacing_diagnostic("select 1/*c*/ + 1;").unwrap(), @" + assert_snapshot!(validation_diagnostic("select 1/*c*/ + 1;"), @" error: comment must have whitespace on its left | 1 | select 1/*c*/ + 1; | ^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select 1 /*c*/+ 1;").unwrap(), @" + assert_snapshot!(validation_diagnostic("select 1 /*c*/+ 1;"), @" error: block comment must have whitespace on its right | 1 | select 1 /*c*/+ 1; | ^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select foo(x)/* c */;").unwrap(), @" + assert_snapshot!(validation_diagnostic("select foo(x)/* c */;"), @" error: comment must have whitespace on its left | 1 | select foo(x)/* c */; | ^^^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select foo(x,/* c */ y);").unwrap(), @" + assert_snapshot!(validation_diagnostic("select foo(x,/* c */ y);"), @" error: comment must have whitespace on its left | 1 | select foo(x,/* c */ y); | ^^^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("create function f /* c */(a int) returns int language sql return 1;").unwrap(), @" + assert_snapshot!(validation_diagnostic("create function f /* c */(a int) returns int language sql return 1;"), @" error: block comment must have whitespace on its right | 1 | create function f /* c */(a int) returns int language sql return 1; | ^^^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select (array[1, 2, 3]) /* c */[1];").unwrap(), @" + assert_snapshot!(validation_diagnostic("select (array[1, 2, 3]) /* c */[1];"), @" error: block comment must have whitespace on its right | 1 | select (array[1, 2, 3]) /* c */[1]; | ^^^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select * from graph_table(g match (a)-> /* c */{1, 3}(b) columns (a.id));").unwrap(), @" + assert_snapshot!(validation_diagnostic("select * from graph_table(g match (a)-> /* c */{1, 3}(b) columns (a.id));"), @" error: block comment must have whitespace on its right | 1 | select * from graph_table(g match (a)-> /* c */{1, 3}(b) columns (a.id)); @@ -435,8 +297,8 @@ select * from graph_table(g match (a)-> /* c */ {1, 3}(b) columns (a.id)); /// Block comments must have whitespace between them. #[test] fn between_block_comments() { - assert_comment_spacing("select 1 /* foo */ /* bar */;"); - assert_snapshot!(comment_spacing_diagnostic("select 1 /* foo *//* bar */;").unwrap(), @" + assert_valid("select 1 /* foo */ /* bar */;"); + assert_snapshot!(validation_diagnostic("select 1 /* foo *//* bar */;"), @" error: block comment must have whitespace on its right | 1 | select 1 /* foo *//* bar */; @@ -447,26 +309,26 @@ select * from graph_table(g match (a)-> /* c */ {1, 3}(b) columns (a.id)); /// Block comments must touch `(`, `[`, `{` on their left. #[test] fn block_comments_touch_left_delimiters() { - assert_comment_spacing( + assert_valid( r" select foo(/* c */ x); select (array[1, 2, 3])[/* c */ 1]; select * from graph_table(g match (a)->{/* c */ 1, 3}(b) columns (a.id)); ", ); - assert_snapshot!(comment_spacing_diagnostic("select foo( /* c */ x);").unwrap(), @" + assert_snapshot!(validation_diagnostic("select foo( /* c */ x);"), @" error: block comment must touch the opening delimiter on its left | 1 | select foo( /* c */ x); | ^^^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select (array[1, 2, 3])[ /* c */ 1];").unwrap(), @" + assert_snapshot!(validation_diagnostic("select (array[1, 2, 3])[ /* c */ 1];"), @" error: block comment must touch the opening delimiter on its left | 1 | select (array[1, 2, 3])[ /* c */ 1]; | ^^^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select * from graph_table(g match (a)->{ /* c */ 1, 3}(b) columns (a.id));").unwrap(), @" + assert_snapshot!(validation_diagnostic("select * from graph_table(g match (a)->{ /* c */ 1, 3}(b) columns (a.id));"), @" error: block comment must touch the opening delimiter on its left | 1 | select * from graph_table(g match (a)->{ /* c */ 1, 3}(b) columns (a.id)); @@ -477,7 +339,7 @@ select * from graph_table(g match (a)->{/* c */ 1, 3}(b) columns (a.id)); /// Comments only share a line with `(`, `[`, `{` when the contents don't wrap. #[test] fn opening_delimiter_comments_when_wrapping() { - assert_comment_spacing( + assert_valid( r" select foo(/* c */ x); select foo( @@ -494,19 +356,19 @@ select foo( ); ", ); - assert_snapshot!(comment_spacing_diagnostic("select foo(-- c\n x);").unwrap(), @" + assert_snapshot!(validation_diagnostic("select foo(-- c\n x);"), @" error: comment after an opening delimiter must be on its own line when the contents wrap | 1 | select foo(-- c | ^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select foo( -- c\n x\n);").unwrap(), @" + assert_snapshot!(validation_diagnostic("select foo( -- c\n x\n);"), @" error: comment after an opening delimiter must be on its own line when the contents wrap | 1 | select foo( -- c | ^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select foo(/* c */\n x\n);").unwrap(), @" + assert_snapshot!(validation_diagnostic("select foo(/* c */\n x\n);"), @" error: comment after an opening delimiter must be on its own line when the contents wrap | 1 | select foo(/* c */ @@ -517,38 +379,38 @@ select foo( /// Block comments must touch `)`, `]`, `}`, `,`, `;` on their right. #[test] fn block_comments_touch_right_delimiters() { - assert_comment_spacing( + assert_valid( r" select foo(x /* c */); select foo(x /* c */, y); select 1 /* c */; ", ); - assert_snapshot!(comment_spacing_diagnostic("select foo(x /* c */ );").unwrap(), @" + assert_snapshot!(validation_diagnostic("select foo(x /* c */ );"), @" error: block comment must touch the delimiter on its right | 1 | select foo(x /* c */ ); | ^^^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select foo(x /* c */ , y);").unwrap(), @" + assert_snapshot!(validation_diagnostic("select foo(x /* c */ , y);"), @" error: block comment must touch the delimiter on its right | 1 | select foo(x /* c */ , y); | ^^^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select 1 /* c */ ;").unwrap(), @" + assert_snapshot!(validation_diagnostic("select 1 /* c */ ;"), @" error: block comment must touch the delimiter on its right | 1 | select 1 /* c */ ; | ^^^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select (array[1, 2, 3])[1 /* c */ ];").unwrap(), @" + assert_snapshot!(validation_diagnostic("select (array[1, 2, 3])[1 /* c */ ];"), @" error: block comment must touch the delimiter on its right | 1 | select (array[1, 2, 3])[1 /* c */ ]; | ^^^^^^^ "); - assert_snapshot!(comment_spacing_diagnostic("select * from graph_table(g match (a)->{1, 3 /* c */ }(b) columns (a.id));").unwrap(), @" + assert_snapshot!(validation_diagnostic("select * from graph_table(g match (a)->{1, 3 /* c */ }(b) columns (a.id));"), @" error: block comment must touch the delimiter on its right | 1 | select * from graph_table(g match (a)->{1, 3 /* c */ }(b) columns (a.id)); From 7c20b08c66de2e7abb7f5e776831a2131d7bd3c1 Mon Sep 17 00:00:00 2001 From: Steve Dignam Date: Sat, 3 Oct 2026 19:58:20 -0400 Subject: [PATCH 5/7] update validation --- crates/squawk_fmt/src/validation.rs | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/crates/squawk_fmt/src/validation.rs b/crates/squawk_fmt/src/validation.rs index 8be2384b..9356657a 100644 --- a/crates/squawk_fmt/src/validation.rs +++ b/crates/squawk_fmt/src/validation.rs @@ -245,24 +245,25 @@ fn tokens_equivalent(before: (TokenKind, &str), after: (TokenKind, &str)) -> boo }; return normalize(before_text) == normalize(after_text); } - return before_text.eq_ignore_ascii_case(after_text); + return if before_kind == TokenKind::Ident { + before_text.eq_ignore_ascii_case(after_text) + } else { + before_text == after_text + }; } - fn unquote<'a>(kind: &TokenKind, text: &'a str) -> Option<&'a str> { - match kind { - TokenKind::QuotedIdent { .. } => text - .strip_prefix('"') - .and_then(|text| text.strip_suffix('"')), - TokenKind::Ident => Some(text), - _ => None, - } + fn unquote(text: &str) -> Option<&str> { + text.strip_prefix('"') + .and_then(|text| text.strip_suffix('"')) } - match ( - unquote(&before_kind, before_text), - unquote(&after_kind, after_text), - ) { - (Some(before), Some(after)) => before.eq_ignore_ascii_case(after), + match (before_kind, after_kind) { + (TokenKind::QuotedIdent { .. }, TokenKind::Ident) => { + unquote(before_text) == Some(after_text.to_ascii_lowercase().as_str()) + } + (TokenKind::Ident, TokenKind::QuotedIdent { .. }) => { + unquote(after_text) == Some(before_text.to_ascii_lowercase().as_str()) + } _ => false, } } From 6c27b4c29e30121af2d18f0f262dadbf37599131 Mon Sep 17 00:00:00 2001 From: Steve Dignam Date: Sat, 3 Oct 2026 21:18:55 -0400 Subject: [PATCH 6/7] validation fix --- crates/squawk_fmt/src/validation.rs | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/crates/squawk_fmt/src/validation.rs b/crates/squawk_fmt/src/validation.rs index 9356657a..26820ea5 100644 --- a/crates/squawk_fmt/src/validation.rs +++ b/crates/squawk_fmt/src/validation.rs @@ -2,7 +2,7 @@ use std::ops::Range; use annotate_snippets::{AnnotationKind, Level, Renderer, Snippet}; use anyhow::{Result, bail, ensure}; -use squawk_lexer::{BOM, Token, TokenKind, tokenize}; +use squawk_lexer::{BOM, LiteralKind, Token, TokenKind, tokenize}; use squawk_line_index::UniversalNewlines; use crate::fmt::{FormatOptions, fmt_str}; @@ -245,6 +245,19 @@ fn tokens_equivalent(before: (TokenKind, &str), after: (TokenKind, &str)) -> boo }; return normalize(before_text) == normalize(after_text); } + if let TokenKind::Literal { + kind: + LiteralKind::NationalStr { .. } + | LiteralKind::ByteStr { .. } + | LiteralKind::BitStr { .. } + | LiteralKind::UnicodeEscStr { .. } + | LiteralKind::EscStr { .. }, + } = before_kind + && let Some((before_prefix, before_rest)) = before_text.split_once('\'') + && let Some((after_prefix, after_rest)) = after_text.split_once('\'') + { + return before_prefix.eq_ignore_ascii_case(after_prefix) && before_rest == after_rest; + } return if before_kind == TokenKind::Ident { before_text.eq_ignore_ascii_case(after_text) } else { From 43669f49d73549bc3ea89a4fa8a61ef7ee6237cb Mon Sep 17 00:00:00 2001 From: Steve Dignam Date: Sat, 3 Oct 2026 23:12:45 -0400 Subject: [PATCH 7/7] fix the failures --- crates/squawk_fmt/src/comment.rs | 88 ++++++++++++----- crates/squawk_fmt/src/fmt.rs | 159 ++++++++++++++++++------------- 2 files changed, 155 insertions(+), 92 deletions(-) diff --git a/crates/squawk_fmt/src/comment.rs b/crates/squawk_fmt/src/comment.rs index 15d950ce..394150eb 100644 --- a/crates/squawk_fmt/src/comment.rs +++ b/crates/squawk_fmt/src/comment.rs @@ -86,6 +86,10 @@ impl CommentRun { self.tokens.is_empty() } + pub(crate) fn last(&self) -> Option<&SyntaxToken> { + self.tokens.last() + } + fn doc<'a>(&self) -> Doc<'a> { let mut docs = vec![]; for (index, token) in self.tokens.iter().enumerate() { @@ -167,25 +171,6 @@ impl CommentRun { .append(self.separator_after(Doc::space())) } - pub(crate) fn split_trailing(self) -> (CommentRun, CommentRun) { - let count = self - .tokens - .iter() - .take_while(|token| is_trailing_comment(token)) - .position(is_line_comment) - .map_or(0, |index| index + 1); - let mut trailing = self.tokens; - let rest = trailing.split_off(count); - (Self { tokens: trailing }, Self { tokens: rest }) - } - - pub(crate) fn trailing<'a>(&self) -> Doc<'a> { - if self.is_empty() { - return Doc::nil(); - } - Doc::space().append(self.doc()) - } - pub(crate) fn leading<'a>(&self) -> Doc<'a> { if self.is_empty() { return Doc::nil(); @@ -210,12 +195,65 @@ pub(crate) fn comment_run_after(el: &(impl Into + Clone)) -> Comm } } +fn kind_before(comments: &CommentRun) -> Option { + let mut token = comments.tokens.first().and_then(|token| token.prev_token()); + while let Some(curr) = token { + match curr.kind() { + SyntaxKind::COMMENT | SyntaxKind::WHITESPACE => token = curr.prev_token(), + kind => return Some(kind), + } + } + None +} + +fn starts_with_closing_token(el: SyntaxElement) -> bool { + let first = match el { + rowan::NodeOrToken::Node(node) => node.first_token(), + rowan::NodeOrToken::Token(token) => Some(token), + }; + first.is_none_or(|token| { + matches!( + token.kind(), + SyntaxKind::R_PAREN + | SyntaxKind::R_BRACK + | SyntaxKind::R_CURLY + | SyntaxKind::COMMA + | SyntaxKind::SEMICOLON + ) + }) +} + pub(crate) fn leading_comments<'a>(el: &(impl Into + Clone)) -> Doc<'a> { - comment_run_before(el).leading() + let comments = comment_run_before(el); + match kind_before(&comments) { + Some(SyntaxKind::DOT | SyntaxKind::COLON) => { + comments.between_nodes(if has_own_line_comments_before(el) { + Doc::hard_line() + } else { + Doc::space() + }) + } + _ => comments.leading(), + } } pub(crate) fn comments_before<'a>(el: &(impl Into + Clone)) -> Doc<'a> { - comment_run_before(el).after_node(Doc::nil()) + let comments = comment_run_before(el); + if comments.is_empty() { + return Doc::nil(); + } + let before = match kind_before(&comments) { + Some(SyntaxKind::L_PAREN | SyntaxKind::L_BRACK | SyntaxKind::L_CURLY) => Doc::nil(), + _ => Doc::space(), + }; + let after = if starts_with_closing_token(el.clone().into()) { + Doc::nil() + } else { + Doc::space() + }; + before + .append(comments.doc()) + .append(comments.separator_after(after)) } pub(crate) fn trailing_comments<'a>(el: &(impl Into + Clone)) -> Doc<'a> { @@ -223,11 +261,11 @@ pub(crate) fn trailing_comments<'a>(el: &(impl Into + Clone)) -> } pub(crate) fn space_or_comments_before<'a>(el: &(impl Into + Clone)) -> Doc<'a> { - let comments = comment_run_before(el); - if comments.is_empty() { - return Doc::space(); + if has_comments_before(el) { + comments_before(el) + } else { + Doc::space() } - comments.after_node(Doc::nil()) } pub(crate) fn space_before<'a>(el: &(impl Into + Clone)) -> Doc<'a> { diff --git a/crates/squawk_fmt/src/fmt.rs b/crates/squawk_fmt/src/fmt.rs index 3571bee9..ad0a0b86 100644 --- a/crates/squawk_fmt/src/fmt.rs +++ b/crates/squawk_fmt/src/fmt.rs @@ -43,6 +43,8 @@ struct Ctx { fn build_source_file<'a>(ctx: &Ctx, source_file: &'a ast::SourceFile) -> Doc<'a> { let mut doc = Doc::nil(); let mut previous_was_stmt = false; + let mut needs_space = false; + let mut at_start = true; for el in source_file.syntax().children_with_tokens() { match el { rowan::NodeOrToken::Node(node) => { @@ -50,27 +52,42 @@ fn build_source_file<'a>(ctx: &Ctx, source_file: &'a ast::SourceFile) -> Doc<'a> let is_empty_stmt = matches!(&stmt, ast::Stmt::EmptyStmt(_)); if previous_was_stmt && !is_empty_stmt { doc = doc.append(Doc::empty_line()); + } else if needs_space && !is_empty_stmt { + doc = doc.append(Doc::space()); } doc = doc.append(build_stmt(ctx, stmt)); previous_was_stmt = !is_empty_stmt; } else { previous_was_stmt = false; } + needs_space = true; + at_start = false; } rowan::NodeOrToken::Token(token) => { previous_was_stmt = false; if token.kind() == SyntaxKind::COMMENT { + if needs_space { + doc = doc.append(Doc::space()); + } doc = doc.append(build_comment(&token)); + needs_space = true; + at_start = false; } else if token.text() == BOM { doc = doc.append(Doc::text(BOM)); - } else if token.kind() == SyntaxKind::WHITESPACE { - // TODO: I think we can improve this - let gap = if token.text().universal_newlines().count() >= 2 { - Doc::empty_line().append(Doc::empty_line()) - } else { - Doc::empty_line() - }; - doc = doc.append(comment_run_after(&token).separator_before(gap)); + } else if token.kind() == SyntaxKind::WHITESPACE && !at_start { + let newlines = token + .text() + .universal_newlines() + .filter(|line| line.line_ending().is_some()) + .count(); + if newlines == 0 { + continue; + } + needs_space = false; + doc = doc.append(Doc::empty_line()); + if newlines >= 2 && token.next_sibling_or_token().is_some() { + doc = doc.append(Doc::empty_line()); + } } } } @@ -223,7 +240,7 @@ fn build_prepare<'a>(ctx: &Ctx, prepare: &ast::Prepare) -> Doc<'a> { .map(|name| leading_comments(name.syntax()).append(build_name(name.syntax()))); if let Some(params) = prepare.param_list() { let params = - leading_comments(params.syntax()).append(build_function_param_list(ctx, params)); + comments_before(params.syntax()).append(build_function_param_list(ctx, params)); header_body = Some(match header_body { Some(header_body) => header_body.append(params), None => params, @@ -1204,7 +1221,7 @@ fn build_column_target<'a>(ctx: &Ctx, target: ast::ColumnTarget) -> Doc<'a> { .unwrap_or_else(Doc::nil); for accessor in target.accessors() { doc = doc - .append(leading_comments(accessor.syntax())) + .append(comments_before(accessor.syntax())) .append(build_accessor(ctx, accessor)); } doc @@ -1570,15 +1587,17 @@ fn build_referencing_table<'a>(table: ast::ReferencingTable) -> Doc<'a> { fn build_trigger_when_condition<'a>(ctx: &Ctx, condition: ast::WhenCondition) -> Doc<'a> { let mut doc = Doc::text("when"); - if let Some(l_paren) = condition.l_paren_token() { - doc = doc.append(comments_before(&l_paren)); - } + doc = doc.append( + condition + .l_paren_token() + .map(|l_paren| space_or_comments_before(&l_paren)) + .unwrap_or_else(Doc::space), + ); let body = condition .expr() .map(|expr| leading_comments(expr.syntax()).append(build_expr(ctx, expr))) .unwrap_or_else(Doc::nil); - doc.append(Doc::space()) - .append(Doc::text("(")) + doc.append(Doc::text("(")) .append(wrap_body(ctx, body, condition.r_paren_token())) .append(Doc::text(")")) .group() @@ -1618,9 +1637,11 @@ fn build_create_transform<'a>(ctx: &Ctx, stmt: &ast::CreateTransform) -> Doc<'a> } doc = doc.group(); - if let Some(l_paren) = stmt.l_paren_token() { - doc = doc.append(comments_before(&l_paren)); - } + doc = doc.append( + stmt.l_paren_token() + .map(|l_paren| space_or_comments_before(&l_paren)) + .unwrap_or_else(Doc::space), + ); let funcs = stmt.transform_funcs().map(|func| { let syntax = func.syntax().clone(); ( @@ -1629,8 +1650,7 @@ fn build_create_transform<'a>(ctx: &Ctx, stmt: &ast::CreateTransform) -> Doc<'a> ) }); let body = build_comma_separated_docs(funcs).unwrap_or_else(Doc::nil); - doc.append(Doc::space()) - .append(Doc::text("(")) + doc.append(Doc::text("(")) .append(wrap_body(ctx, body, stmt.r_paren_token())) .append(Doc::text(")")) .group() @@ -1690,7 +1710,7 @@ fn build_create_function<'a>(ctx: &Ctx, create_function: &ast::CreateFunction) - } if let Some(params) = create_function.param_list() { doc = doc - .append(leading_comments(params.syntax())) + .append(comments_before(params.syntax())) .append(build_function_param_list(ctx, params)); } if let Some(ret_type) = create_function.ret_type() { @@ -3364,7 +3384,7 @@ fn build_create_aggregate<'a>(ctx: &Ctx, stmt: &ast::CreateAggregate) -> Doc<'a> } if let Some(params) = stmt.param_list() { doc = doc - .append(leading_comments(params.syntax())) + .append(comments_before(params.syntax())) .append(build_aggregate_param_list(ctx, params)); } if let Some(attributes) = stmt.attribute_list() { @@ -3678,9 +3698,12 @@ fn build_event_trigger_when<'a>(ctx: &Ctx, filter: ast::EventTriggerWhen) -> Doc if let Some(in_token) = filter.in_token() { doc = doc.append(space_before(&in_token)).append(Doc::text("in")); } - if let Some(l_paren) = filter.l_paren_token() { - doc = doc.append(comments_before(&l_paren)); - } + doc = doc.append( + filter + .l_paren_token() + .map(|l_paren| space_or_comments_before(&l_paren)) + .unwrap_or_else(Doc::space), + ); let items = filter.literals().map(|literal| { let syntax = literal.syntax().clone(); ( @@ -3689,8 +3712,7 @@ fn build_event_trigger_when<'a>(ctx: &Ctx, filter: ast::EventTriggerWhen) -> Doc ) }); let body = build_comma_separated_docs(items).unwrap_or_else(Doc::nil); - doc.append(Doc::space()) - .append(Doc::text("(")) + doc.append(Doc::text("(")) .append(wrap_body(ctx, body, filter.r_paren_token())) .append(Doc::text(")")) .group() @@ -5222,7 +5244,7 @@ fn build_create_procedure<'a>(ctx: &Ctx, stmt: &ast::CreateProcedure) -> Doc<'a> } if let Some(params) = stmt.param_list() { doc = doc - .append(leading_comments(params.syntax())) + .append(comments_before(params.syntax())) .append(build_function_param_list(ctx, params)); } doc = doc.group(); @@ -6172,7 +6194,7 @@ fn build_aggregate_sig<'a>(ctx: &Ctx, aggregate: ast::Aggregate) -> Doc<'a> { .unwrap_or_else(Doc::nil); if let Some(params) = aggregate.param_list() { doc = doc - .append(leading_comments(params.syntax())) + .append(comments_before(params.syntax())) .append(build_aggregate_param_list(ctx, params)); } doc @@ -7570,9 +7592,10 @@ fn build_path_parts<'a>( ) -> Doc<'a> { let mut doc = Doc::nil(); if let Some(qualifier) = qualifier { - doc = doc - .append(build_path_ref(&qualifier)) - .append(trailing_comments(qualifier.syntax())); + doc = doc.append(build_path_ref(&qualifier)); + if let Some(dot) = &dot { + doc = doc.append(comments_before(dot)); + } } let is_qualified = dot.is_some(); if is_qualified { @@ -9096,7 +9119,7 @@ fn build_with_table<'a>(ctx: &Ctx, table: ast::WithTable) -> Doc<'a> { .unwrap_or_else(Doc::nil); if let Some(columns) = table.column_list() { doc = doc - .append(leading_comments(columns.syntax())) + .append(comments_before(columns.syntax())) .append(build_cte_column_list(ctx, columns)); } if let Some(as_token) = table.as_token() { @@ -9122,13 +9145,7 @@ fn build_with_table<'a>(ctx: &Ctx, table: ast::WithTable) -> Doc<'a> { doc = doc.append(space_before(&l_paren)).append(Doc::text("(")); } let body = match table.query() { - Some(query) => { - let (trailing, leading) = comment_run_before(query.syntax()).split_trailing(); - doc = doc.append(trailing.trailing()); - leading - .before_node(Doc::nil()) - .append(build_with_query(ctx, query)) - } + Some(query) => leading_comments(query.syntax()).append(build_with_query(ctx, query)), None => Doc::nil(), }; doc = doc @@ -9537,7 +9554,7 @@ fn build_publication_object<'a>(ctx: &Ctx, object: ast::PublicationObject) -> Do doc = doc.append(comments_before(&r_paren)).append(Doc::text(")")); } if let Some(star) = object.star_token() { - doc = doc.append(leading_comments(&star)).append(Doc::text("*")); + doc = doc.append(comments_before(&star)).append(Doc::text("*")); } if let Some(columns) = object.column_ref_list() { doc = doc @@ -13797,7 +13814,7 @@ fn build_extension_operator<'a>(ctx: &Ctx, node: ast::ObjectOperator) -> Doc<'a> Doc::line_or_space() .append( node.l_paren_token() - .map(|el| comments_before(&el)) + .map(|el| leading_comments(&el)) .unwrap_or_else(Doc::nil), ) .append(Doc::text("(")) @@ -16427,9 +16444,8 @@ fn build_from_alias_columns<'a>(ctx: &Ctx, columns: ast::FromAliasColumns) -> Do syntax, ) }); - comments_before(list.syntax()).append(build_from_alias_column_list( + space_or_comments_before(list.syntax()).append(build_from_alias_column_list( ctx, - list.l_paren_token(), items, list.r_paren_token(), )) @@ -16453,9 +16469,8 @@ fn build_from_alias_columns<'a>(ctx: &Ctx, columns: ast::FromAliasColumns) -> Do } (doc, syntax) }); - comments_before(list.syntax()).append(build_from_alias_column_list( + space_or_comments_before(list.syntax()).append(build_from_alias_column_list( ctx, - list.l_paren_token(), items, list.r_paren_token(), )) @@ -16465,18 +16480,12 @@ fn build_from_alias_columns<'a>(ctx: &Ctx, columns: ast::FromAliasColumns) -> Do fn build_from_alias_column_list<'a>( ctx: &Ctx, - l_paren: Option, items: impl Iterator, SyntaxNode)>, r_paren: Option, ) -> Doc<'a> { - let mut doc = Doc::nil(); - if let Some(l_paren) = &l_paren { - doc = doc.append(space_or_comments_before(l_paren)); - } - doc = doc.append(Doc::text("(")); - let body = build_comma_separated_docs(items).unwrap_or_else(Doc::nil); - doc.append(wrap_body(ctx, body, r_paren)) + Doc::text("(") + .append(wrap_body(ctx, body, r_paren)) .append(Doc::text(")")) .group() } @@ -16646,8 +16655,8 @@ fn wrap_empty_body<'a>(ctx: &Ctx, r_delimiter: Option) -> Doc<'a> { if comments.is_empty() { return Doc::nil(); } - let (comment_doc, closing_separator) = comments.before_closing_delimiter(Doc::line_or_space()); - Doc::line_or_space() + let (comment_doc, closing_separator) = comments.before_closing_delimiter(Doc::line_or_nil()); + Doc::line_or_nil() .append(comment_doc) .nest(ctx.indent) .append(closing_separator) @@ -17659,7 +17668,7 @@ fn build_xml_root_fn<'a>(ctx: &Ctx, xml_root_fn: ast::XmlRootFn) -> Doc<'a> { } if let Some(standalone) = xml_root_fn.xml_standalone() { body = body - .append(leading_comments(standalone.syntax())) + .append(comments_before(standalone.syntax())) .append(build_xml_standalone(standalone)); } @@ -19192,9 +19201,12 @@ fn build_collate_expr<'a>(ctx: &Ctx, collate: ast::Collate) -> Doc<'a> { .unwrap_or_else(Doc::nil); if let Some(collate_token) = collate.collate_token() { - doc = doc.append(comments_before(&collate_token)); - } - if has_expr { + doc = doc.append(if has_expr { + space_or_comments_before(&collate_token) + } else { + comments_before(&collate_token) + }); + } else if has_expr { doc = doc.append(Doc::space()); } doc = doc.append(Doc::text("collate")); @@ -20040,16 +20052,17 @@ fn build_type<'a>(ctx: &Ctx, ty: ast::Type) -> Doc<'a> { doc } ast::Type::BitType(bit_type) => { - build_keyword_node(bit_type.syntax()).append(build_type_args(ctx, bit_type.arg_list())) + build_keyword_type(ctx, bit_type.syntax(), bit_type.arg_list()) } ast::Type::BitVaryingType(bit_varying_type) => { - build_keyword_node(bit_varying_type.syntax()) - .append(build_type_args(ctx, bit_varying_type.arg_list())) + build_keyword_type(ctx, bit_varying_type.syntax(), bit_varying_type.arg_list()) + } + ast::Type::CharacterType(character_type) => { + build_keyword_type(ctx, character_type.syntax(), character_type.arg_list()) + } + ast::Type::VarcharType(varchar_type) => { + build_keyword_type(ctx, varchar_type.syntax(), varchar_type.arg_list()) } - ast::Type::CharacterType(character_type) => build_keyword_node(character_type.syntax()) - .append(build_type_args(ctx, character_type.arg_list())), - ast::Type::VarcharType(varchar_type) => build_keyword_node(varchar_type.syntax()) - .append(build_type_args(ctx, varchar_type.arg_list())), ast::Type::DoubleType(double_type) => build_keyword_node(double_type.syntax()), ast::Type::IntervalType(interval_type) => { let mut doc = build_setof(interval_type.setof_token()); @@ -20134,6 +20147,18 @@ fn build_array_bound<'a>(ctx: &Ctx, bound: &ast::ArrayBound) -> Doc<'a> { doc.append(Doc::text("]")) } +fn build_keyword_type<'a>(ctx: &Ctx, node: &SyntaxNode, arg_list: Option) -> Doc<'a> { + let mut doc = build_keyword_node(node); + if arg_list.as_ref().is_some_and(|arg_list| { + comment_run_before(arg_list.syntax()) + .last() + .is_some_and(|token| !is_line_comment(token)) + }) { + doc = doc.append(Doc::space()); + } + doc.append(build_type_args(ctx, arg_list)) +} + fn build_type_args<'a>(ctx: &Ctx, arg_list: Option) -> Doc<'a> { let Some(arg_list) = arg_list else { return Doc::nil();