Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 0 additions & 32 deletions .github/workflows/check_updates.generated.yml

This file was deleted.

52 changes: 0 additions & 52 deletions .github/workflows/check_updates.ts

This file was deleted.

10 changes: 9 additions & 1 deletion .github/workflows/ci.generated.yml
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,15 @@ jobs:
- name: Test debug
if: matrix.config.kind == 'test_debug'
run: cargo test
- name: Test tracing
if: matrix.config.kind == 'test_debug'
run: cargo test --features tracing
- name: Clippy
if: matrix.config.kind == 'test_debug'
run: cargo clippy --all-targets -- -D warnings
- name: Check formatting
if: matrix.config.kind == 'test_debug'
run: cargo fmt --check
- name: Test release
if: matrix.config.kind == 'test_release'
run: cargo test --release
Expand Down Expand Up @@ -90,4 +99,3 @@ jobs:
./.github/workflows/ci.ts --lint
./.github/workflows/publish_npm.ts --lint
./.github/workflows/release.ts --lint
./.github/workflows/check_updates.ts --lint
4 changes: 3 additions & 1 deletion .github/workflows/ci.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,9 @@ const buildJob = job("build", {
},

{ name: "Test debug", if: isDebug, run: "cargo test" },
{ name: "Test tracing", if: isDebug, run: "cargo test --features tracing" },
{ name: "Clippy", if: isDebug, run: "cargo clippy --all-targets -- -D warnings" },
{ name: "Check formatting", if: isDebug, run: "cargo fmt --check" },
{ name: "Test release", if: isRelease, run: "cargo test --release" },

getTagVersion,
Expand Down Expand Up @@ -122,7 +125,6 @@ const buildJob = job("build", {
"./.github/workflows/ci.ts --lint",
"./.github/workflows/publish_npm.ts --lint",
"./.github/workflows/release.ts --lint",
"./.github/workflows/check_updates.ts --lint",
],
},
],
Expand Down
32 changes: 23 additions & 9 deletions CLAUDE.md
Original file line number Diff line number Diff line change
@@ -1,32 +1,45 @@
# dprint-plugin-sql

Wrapper around [sqlformat-rs](https://github.com/shssoichiro/sqlformat-rs) for use as a dprint formatting plugin.
SQL formatting plugin for dprint, with its own lexer, parser and formatter that build dprint-core's IR.

## Commands

- `cargo test` — run all tests
- `cargo test --test specs` — run only the spec tests
- `cargo clippy --all-targets --all-features -- -D warnings` — lint
- `cargo build --target wasm32-unknown-unknown --features wasm --release` — build the wasm plugin
- `cd deployment/npm && node setup.js && npm test` — test the npm package (requires wasm build first)

## Architecture

- `src/format_text.rs` — core formatting logic, delegates to `sqlformat::format()`
The pipeline is lex → parse → generate IR → print → verify.

- `src/lexer.rs` — splits the text into tokens, losslessly. This is where the dialects differ (`#`, `[..]`, backslash escapes, dollar quotes, `GO`, `DELIMITER`, client commands)
- `src/parser.rs` — builds statements, procedural blocks (`BEGIN .. END`, `IF`, loops, `CASE` statements, declaration sections), brackets and `CASE` expressions. Also splits T-SQL statements written without semicolons
- `src/ast.rs` — the tree the parser builds
- `src/generation/generate.rs` — the layout: splits statements into clauses, lists and conditions, and generates the IR
- `src/keywords.rs` — sorted tables of keywords
- `src/format_text.rs` — formatting a file, and the verification that formatting changed nothing but whitespace (keyword casing aside), which errors rather than return changed code
- `src/format_range.rs` — formatting the top level statements a range touches
- `src/wasm_plugin.rs` — dprint wasm plugin interface (compiled only for wasm32 target with `wasm` feature)
- `src/configuration/` — config types, resolution, and builder
- `deployment/npm/` — npm package that ships `plugin.wasm`
- `deployment/schema.json` — JSON schema for plugin configuration
- `scripts/update.ts` — Deno script that checks crates.io for new sqlformat versions and auto-publishes
- `scripts/generateReleaseNotes.ts` — generates changelog for GitHub releases

## Adding a new config option
## Principles

When sqlformat-rs adds new options:
- Formatting only ever changes the whitespace between tokens. Anything the parser doesn't understand is written as a run of tokens rather than reported, since the dialect it's in may use those words differently
- When the dialects disagree on what some text is, the configured dialect decides. The generic dialect must pick what's least likely to be wrong, since a wrong guess there is the most likely kind of bug
- Formatting must be stable: formatting the output again gives the same output. Every spec is formatted twice to check this, and `tests/test.rs` also formats every spec's input in every dialect at two widths and checks it's stable and changes nothing but whitespace

## Adding a new config option

1. Add the field to `Configuration` in `src/configuration/configuration.rs` (add enums with `generate_str_to_from!` if needed)
2. Add resolution in `src/configuration/resolve_config.rs` using `get_value()`
3. Add a builder method in `src/configuration/builder.rs` and update the `check_all_values_set` test
4. Wire it through in `src/format_text.rs` when constructing `FormatOptions`
5. Add the property to `deployment/schema.json`
4. Use it in `src/generation/generate.rs`
5. Add the property to `deployment/schema.json` and the table in `README.md`
6. Add a spec test file in `tests/specs/Config/`

## Test specs
Expand All @@ -36,10 +49,11 @@ Spec files live in `tests/specs/` and use the dprint-development format:
- `== message ==` starts a test case
- `[expect]` separates input from expected output
- `~~ key: value, key: value ~~` at the top of a file sets config for all specs in that file
- Each config variation needs its own file since config is file-level
- Each config variation needs its own file since config is file-level, which is why each dialect has its own directory
- `[|` and `|]` mark the range to format in a spec's text
- A spec file can't start with a SQL comment, since a first line starting with `--` names the spec's file

## Releases

- Manual: trigger the `release` workflow with patch/minor
- Automatic: `check_updates` workflow runs daily, detects new sqlformat versions, and auto-publishes
- On tag push: CI creates a GitHub release with `plugin.wasm`, and `publish_npm` publishes to npm
79 changes: 48 additions & 31 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 10 additions & 4 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ homepage = "https://github.com/dprint/dprint-plugin-sql"
keywords = ["formatting", "formatter", "sql"]
license = "MIT"
repository = "https://github.com/dprint/dprint-plugin-sql"
description = "SQL formatter for dprint via sqlformat-rs."
description = "SQL formatter for dprint."

[lib]
crate-type = ["lib", "cdylib"]
Expand All @@ -22,13 +22,19 @@ panic = "abort"

[features]
wasm = ["serde_json", "dprint-core/wasm"]
tracing = ["dprint-core/tracing"]

[[test]]
name = "specs"
path = "tests/spec_test.rs"
harness = false

[dependencies]
dprint-core = { version = "0.69.1", default-features = false }
dprint-core = { version = "0.71.0", features = ["formatting"], default-features = false }
serde = { version = "1.0.88", features = ["derive"] }
serde_json = { version = "1.0", optional = true }
sqlformat = "0.5.0"
thiserror = "2"

[dev-dependencies]
dprint-development = "0.11.0"
dprint-development = "0.12.1"
serde_json = { version = "1.0" }
Loading
Loading