diff --git a/crates/squawk_fmt/src/fmt.rs b/crates/squawk_fmt/src/fmt.rs index 81c28ad6..3571bee9 100644 --- a/crates/squawk_fmt/src/fmt.rs +++ b/crates/squawk_fmt/src/fmt.rs @@ -5950,12 +5950,10 @@ fn build_import_table_filter<'a>(ctx: &Ctx, filter: ast::ImportTableFilter) -> D ) .unwrap_or_else(Doc::nil); doc = doc - .append(Doc::space()) .append( l_paren - .clone() - .map(|el| comments_before(&el)) - .unwrap_or_else(Doc::nil), + .map(|el| space_or_comments_before(&el)) + .unwrap_or_else(Doc::space), ) .append(Doc::text("(")) .append(wrap_body(ctx, body, r_paren)) @@ -9520,9 +9518,11 @@ fn build_publication_object<'a>(ctx: &Ctx, object: ast::PublicationObject) -> Do let parenthesized = object.l_paren_token().is_some(); if let Some(l_paren) = object.l_paren_token() { if has_prefix { - doc = doc.append(Doc::space()); + doc = doc.append(space_or_comments_before(&l_paren)); + } else { + doc = doc.append(comments_before(&l_paren)); } - doc = doc.append(comments_before(&l_paren)).append(Doc::text("(")); + doc = doc.append(Doc::text("(")); } if let Some(table) = object.table_name_ref() { if !parenthesized && has_prefix { @@ -9582,8 +9582,7 @@ fn build_except_table_clause<'a>(ctx: &Ctx, clause: ast::ExceptTableClause) -> D let mut doc = Doc::text("except"); if let Some(l_paren) = clause.l_paren_token() { doc = doc - .append(Doc::space()) - .append(comments_before(&l_paren)) + .append(space_or_comments_before(&l_paren)) .append(Doc::text("(")); } let items = clause.except_table_names().map(|name| { @@ -11831,11 +11830,10 @@ fn build_drop_element_properties<'a>(ctx: &Ctx, n: ast::DropVertexEdgeLabelPrope }); let body = build_comma_separated_docs(items).unwrap_or_else(Doc::nil); detail = detail - .append(Doc::space()) .append( n.l_paren_token() - .map(|el| comments_before(&el)) - .unwrap_or_else(Doc::nil), + .map(|el| space_or_comments_before(&el)) + .unwrap_or_else(Doc::space), ) .append(Doc::text("(")) .append(wrap_body(ctx, body, n.r_paren_token())) @@ -11864,11 +11862,10 @@ fn build_drop_element_tables<'a>( }); let body = build_comma_separated_docs(items).unwrap_or_else(Doc::nil); doc = doc - .append(Doc::space()) .append( l.clone() - .map(|el| comments_before(&el)) - .unwrap_or_else(Doc::nil), + .map(|el| space_or_comments_before(&el)) + .unwrap_or_else(Doc::space), ) .append(Doc::text("(")) .append(wrap_body(ctx, body, r)) @@ -11894,11 +11891,10 @@ fn build_vertex_tables<'a>(ctx: &Ctx, n: ast::VertexTables) -> Doc<'a> { }); let body = build_comma_separated_docs(items).unwrap_or_else(Doc::nil); doc = doc - .append(Doc::space()) .append( n.l_paren_token() - .map(|el| comments_before(&el)) - .unwrap_or_else(Doc::nil), + .map(|el| space_or_comments_before(&el)) + .unwrap_or_else(Doc::space), ) .append(Doc::text("(")) .append(wrap_body(ctx, body, n.r_paren_token())) @@ -11943,11 +11939,10 @@ fn build_edge_tables<'a>(ctx: &Ctx, n: ast::EdgeTables) -> Doc<'a> { }); let body = build_comma_separated_docs(items).unwrap_or_else(Doc::nil); doc = doc - .append(Doc::space()) .append( n.l_paren_token() - .map(|el| comments_before(&el)) - .unwrap_or_else(Doc::nil), + .map(|el| space_or_comments_before(&el)) + .unwrap_or_else(Doc::space), ) .append(Doc::text("(")) .append(wrap_body(ctx, body, n.r_paren_token())) diff --git a/crates/squawk_fmt/tests/after/alter_property_graph.snap b/crates/squawk_fmt/tests/after/alter_property_graph.snap index f92dfffb..9f34f3c0 100644 --- a/crates/squawk_fmt/tests/after/alter_property_graph.snap +++ b/crates/squawk_fmt/tests/after/alter_property_graph.snap @@ -82,3 +82,11 @@ alter property graph social_graph people, organizations -- trailing ) cascade; + +alter property graph social_graph + alter relationship table follows + alter label connection drop properties /* before paren */( + created_at + ); + +alter property graph social_graph drop vertex tables /* before paren */(people); diff --git a/crates/squawk_fmt/tests/after/create_property_graph.snap b/crates/squawk_fmt/tests/after/create_property_graph.snap index a60c1615..aa4326ab 100644 --- a/crates/squawk_fmt/tests/after/create_property_graph.snap +++ b/crates/squawk_fmt/tests/after/create_property_graph.snap @@ -53,7 +53,7 @@ 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 */( + /* 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 52c1e544..4695fba0 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 */ ) @@ -59,3 +59,6 @@ create /* after create */ publication /* after publication */ commented_pub with /* after with */ ( /* before option */ publish /* before equals */ = /* before value */ 'insert' /* before options close */ ) /* before semicolon */; + +create publication except_paren_comment + for all tables except /* before paren */(table audit.secret_events); diff --git a/crates/squawk_fmt/tests/after/import_foreign_schema.snap b/crates/squawk_fmt/tests/after/import_foreign_schema.snap index 6c627558..a6b92266 100644 --- a/crates/squawk_fmt/tests/after/import_foreign_schema.snap +++ b/crates/squawk_fmt/tests/after/import_foreign_schema.snap @@ -19,7 +19,7 @@ import foreign schema remote /* before import */ import /* before foreign */ foreign /* before schema */ schema /* before remote */ remote - /* before limit */ limit /* before to */ to /* before open */( + /* 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/before/alter_property_graph.sql b/crates/squawk_fmt/tests/before/alter_property_graph.sql index 19e00483..62e71f28 100644 --- a/crates/squawk_fmt/tests/before/alter_property_graph.sql +++ b/crates/squawk_fmt/tests/before/alter_property_graph.sql @@ -28,3 +28,7 @@ alter property graph social_graph owner /* to */ to /* role */ graph_administrat alter property graph social_graph drop vertex tables (people, organizations -- trailing ) cascade; + +alter property graph social_graph alter relationship table follows alter label connection drop properties /* before paren */ (created_at); + +alter property graph social_graph drop vertex tables /* before paren */ (people); diff --git a/crates/squawk_fmt/tests/before/create_publication.sql b/crates/squawk_fmt/tests/before/create_publication.sql index c07e80d6..81941792 100644 --- a/crates/squawk_fmt/tests/before/create_publication.sql +++ b/crates/squawk_fmt/tests/before/create_publication.sql @@ -16,3 +16,5 @@ create publication omitted_schema_keywords for tables in schema first_schema, /* 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 */ (/* before column */ id /* before comma */, /* after comma */ payload /* before columns close */) /* before where */ where /* before where open */ (/* before expression */ id > 0 /* before where close */), /* after object comma */ tables /* after tables */ in /* after in */ schema /* after schema */ current_schema with /* after with */ (/* before option */ publish /* before equals */ = /* before value */ 'insert' /* before options close */) /* before semicolon */; + +create publication except_paren_comment for all tables except /* before paren */ (table audit.secret_events); diff --git a/crates/squawk_fmt/tests/tests.rs b/crates/squawk_fmt/tests/tests.rs index 3923ef9e..07ce8b43 100644 --- a/crates/squawk_fmt/tests/tests.rs +++ b/crates/squawk_fmt/tests/tests.rs @@ -1,7 +1,9 @@ +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}; #[dir_test( dir: "$CARGO_MANIFEST_DIR/tests/before", @@ -19,6 +21,7 @@ fn fmt(fixture: Fixture<&str>) { assert_no_dropped_tokens(content, &formatted); assert_parses(&formatted); + assert_no_extra_spaces(&formatted); assert_eq!( squawk_fmt::fmt_str(&formatted, Default::default()).unwrap(), formatted, @@ -175,3 +178,29 @@ fn assert_parses(formatted: &str) { .join("\n") ); } + +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])); + } +}