Skip to content

feat: add plpgsql-parse package with comment preservation for PL/pgSQL function bodies#293

Open
pyramation wants to merge 4 commits intomainfrom
devin/1775777114-plpgsql-parse-package
Open

feat: add plpgsql-parse package with comment preservation for PL/pgSQL function bodies#293
pyramation wants to merge 4 commits intomainfrom
devin/1775777114-plpgsql-parse-package

Conversation

@pyramation
Copy link
Copy Markdown
Collaborator

@pyramation pyramation commented Apr 9, 2026

Summary

New packages/plpgsql-parse/ workspace package that preserves -- line comments inside PL/pgSQL function bodies through parse→deparse round trips. Wraps existing plpgsql-parser and plpgsql-deparser without modifying them — same pattern as the pgsql-parse package from PR #290.

How it works:

  1. Parse: Uses pgsql-parse for outer SQL comment/whitespace preservation, then for each PL/pgSQL function, scans the $$...$$ body to extract -- comments with their line numbers and anchor them to the nearest following statement
  2. Deparse: Re-injects body comments into the deparsed output by collecting statement line numbers from the PL/pgSQL AST, mapping them to expected keywords, and walking the deparsed body line-by-line to find insertion points

Key modules:

  • body-scanner.ts — extract -- comments from function body text, group by anchor statement
  • parse.ts — enhanced parse combining pgsql-parse + body comment extraction
  • deparse.ts — re-inject body comments using keyword matching against PL/pgSQL AST
  • return-info.ts — extract return type info for correct plpgsql-deparser invocation

Tests: 57 tests (9 scanner + 9 parse + 39 round-trip), 8 SQL fixtures with snapshots covering: simple functions, multiple comment groups, trigger functions, exception handlers, loops, nested blocks, multi-function files, and no-comment baselines.

Updates since last revision

  • Added README.md for the package (was missing, causing makage assets copy step to fail in CI)
  • Simplified jest.config.js to match existing package conventions — removed moduleNameMapper and custom transformIgnorePatterns; now uses the standard transformIgnorePatterns: ['/node_modules/*'] pattern like deparser and plpgsql-deparser
  • Removed tsconfig.test.json entirely — pnpm handles workspace linking, no manual paths mappings needed. Jest now uses tsconfig.json directly, matching the convention of other packages in the monorepo
  • All 9/9 CI checks pass

Review & Testing Checklist for Human

  • as any casts in parse.ts and deparse.tsrawStmt?.stmt is cast to any to access CreateFunctionStmt and PL/pgSQL AST nodes. These bypass type safety and would silently break if AST shapes change upstream. Verify the access patterns match actual node shapes from @pgsql/types and plpgsql-parser.
  • Keyword matching heuristic in deparse.ts — Comments are re-inserted by matching statement keywords (e.g., IF, FOR, RETURN) against deparsed output lines. Review getKeywordsForStmtKind() and lineMatchesKeywords() for edge cases where keywords could appear in string literals, column names, or unexpected formatting.
  • PL/pgSQL statement type coveragecollectStmtLinenos and buildStmtKeywords do a DFS walk over the PL/pgSQL AST. Verify all relevant statement types are handled (especially less common ones like PLpgSQL_stmt_dynexecute, PLpgSQL_stmt_case, PLpgSQL_stmt_forc, etc.).
  • Lockfile diffpnpm-lock.yaml has a large diff (mostly quote style reformatting from a pnpm version difference). Verify no unintended dependency additions or version changes beyond the new plpgsql-parse workspace entry.
  • Test plan: Run cd packages/plpgsql-parse && npx jest --verbose locally. Try adding a new .sql fixture with a complex real-world PL/pgSQL function (e.g., one with dynamic SQL, cursors, or nested exception blocks) to stress-test the comment round trip.

Notes

  • Only -- line comments are supported (no /* */ block comments) — this was a deliberate decision.
  • This package does NOT modify plpgsql-parser, plpgsql-deparser, pgsql-deparser, or any other existing packages.
  • Mid-body-statement comments are hoisted to before the statement (same approach as pgsql-parse).

Link to Devin session: https://app.devin.ai/sessions/67facbcfe0ae424bad3eafb4e6ca9059
Requested by: @pyramation

…L function bodies

New packages/plpgsql-parse/ package that wraps plpgsql-parser and
plpgsql-deparser to preserve -- line comments and vertical whitespace
inside PL/pgSQL function bodies through parse→deparse round trips.

- body-scanner.ts: extract comments from function bodies with line numbers
- parse.ts: combines pgsql-parse (outer SQL) + body comment extraction
- deparse.ts: re-injects body comments into deparsed PL/pgSQL output
- return-info.ts: extract return type info for correct RETURN handling
- 57 tests, 8 fixtures with snapshots, all passing
- No modifications to existing packages (plpgsql-parser, plpgsql-deparser, etc.)
@devin-ai-integration
Copy link
Copy Markdown
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant