feat(format): skip non-plpgsql bodies; keep literals and embedded code safe
- Only restyle bodies for plpgsql/sql; skip pl* (plpython3u, plperl, ...), c and internal - Keep LANGUAGE clause on DO blocks - Carry multi-line string and dollar-quoted literals verbatim in bodies and DML - Format dollar-quoted literals that contain code (declare/begin/select/...), never format() templates - Fix code joined onto -- comments, early flush after raise exception, dropped comment before BEGIN - Regenerate test_mm_proc golden; document in README, plan, todo
This commit is contained in:
@@ -67,6 +67,9 @@ to the intended style below.
|
||||
on own line; `AS` then `$$` on its own line; body; closing `$$;` on its own line.
|
||||
- PL/pgSQL: `DECLARE` alone, vars 2-space indented; `--Block--` comment markers preserved;
|
||||
`BEGIN`/`END` at body level; `IF/THEN/ELSIF/ELSE/END IF`, loops, `CASE` indent their bodies.
|
||||
- Procedural languages: bodies in any `pl*` language other than `plpgsql` (`plpython3u`,
|
||||
`plperl`, `pltcl`, …) and in `c` / `internal` are emitted verbatim; `plpgsql`, `sql` and routines with no `LANGUAGE` clause (treated as `sql`) are formatted. The
|
||||
function header is always formatted.
|
||||
- Spacing: spaces around binary operators (`=`,`<>`,`||`,…) and `:=`; **no** space around
|
||||
`::`, `->`, `->>`, array `[...]`, or before a call's `(`.
|
||||
- Dollar-quote tags preserved verbatim (`$$`, `$S$`, `$Z$`, …).
|
||||
|
||||
+31
-2
@@ -36,9 +36,9 @@ Legend: ✅ done · 🚧 in progress · ⬜ not started
|
||||
- `parser_test.go`: small round-trips, CreateFunction shape assertions, Raw fallback, and
|
||||
**corpus round-trip** — reconstructs all 4 files byte-for-byte; structures all 4 functions.
|
||||
- **Status:** all tests pass.
|
||||
- _Still TODO (later): DML/other-DDL structuring (currently Raw) for full formatting._
|
||||
- _Note: DML/other-DDL still parse to `Raw`; they are formatted at token level by `pkg/format/dml.go`, not via structured CST nodes._
|
||||
|
||||
### 🚧 PL/pgSQL body parser ← NEXT (the remaining V1 piece)
|
||||
### ✅ PL/pgSQL body parser
|
||||
|
||||
#### ✅ DECLARE section — `pkg/format/body.go`
|
||||
- `formatBody` splits the dollar-quote tag, calls `formatBodyInner`.
|
||||
@@ -243,6 +243,11 @@ Tests: `TestDMLInsertValues*`.
|
||||
|
||||
### ✅ Formatter — PL/pgSQL body settings (`pkg/format/body.go`)
|
||||
|
||||
- Language gate (`isPlpgsql` in `pkg/format/format.go`): bodies in a `pl*` language other than
|
||||
`plpgsql` (`plpython3u`, `plperl`, …), `c` and `internal` are skipped and kept verbatim; `plpgsql`, `sql` and no
|
||||
clause (treated as `sql`) are formatted. Header is always formatted. Test:
|
||||
`TestNonPlpgsqlBodyVerbatim`.
|
||||
|
||||
- `plpgsql_max_blank_lines`: blank-line runs capped at the configured limit; default `1`.
|
||||
- `plpgsql_declare_align_type` + `plpgsql_declare_align_eq`: two-pass declare formatter
|
||||
measures name/type widths then pads for alignment; `writeDeclareAligned` helper. Both
|
||||
@@ -286,3 +291,27 @@ not implemented.
|
||||
## Open risks
|
||||
- `go-pgquery` tracks PG17 (not PG18) — fine for lint; irrelevant to formatter path.
|
||||
- Leading-comma + one-per-line is a first-class style option, not an afterthought.
|
||||
|
||||
### ✅ Literal & embedded-code safety (found via `temp/` corpus)
|
||||
|
||||
- Multi-line quoted strings and dollar-quoted literals inside bodies are carried verbatim
|
||||
(never re-indented); only the code outside them is scanned for parens / terminators / block
|
||||
depth (`formatBodyStatements`, `cut`/`tail` handling). Same for top-level DML
|
||||
(`litNL` sentinel in `dml.go`).
|
||||
- Dollar-quoted literals whose content starts like code (`declare`/`begin` → PL/pgSQL block;
|
||||
`select`/`insert`/`update`/`delete`/`with` → DML) are formatted recursively
|
||||
(`formatEmbedded`); anything else (fragments, prose, other languages) stays verbatim. Literals
|
||||
containing `format()` placeholders (`%s`, `%I`, `%L`, `%1$s`) are never touched, and a result
|
||||
that fails `SemanticallyEqual`/`CommentsPreserved` is discarded.
|
||||
- `DO LANGUAGE x $$…$$` keeps its `LANGUAGE` clause (it was being dropped).
|
||||
- Code is never joined onto a line that ends in a `--` comment.
|
||||
- A line ending in a literal or non-keyword no longer counts as ending in `EXCEPTION`/`THEN`/….
|
||||
- Comments between the last DECLARE variable and `BEGIN` are kept.
|
||||
- Golden `testdata/corpus/test_mm_proc.pgsql` regenerated: nested dollar-quoted dynamic SQL is no
|
||||
longer re-flowed.
|
||||
|
||||
## Local corpus (`temp/`)
|
||||
|
||||
`temp/` holds real-world routines (plpgsql, plpython3u, triggers) used for local testing only
|
||||
(not committed). Run `pgtidy fmt` over it to find safety-gate failures. See "Language gate" above
|
||||
for how non-plpgsql bodies are handled.
|
||||
|
||||
Reference in New Issue
Block a user