Typstyle

Adding Formatter Options

Formatter options cross crate and application boundaries. Changing only core ConfigConfig can leave the CLI, WASM bindings, embedded package, playground, or docs with stale values.

Change Checklist

Core Configuration

  1. Add the field to crates/typstyle-core/src/config.rscrates/typstyle-core/src/config.rs, set its Config::default()Config::default() value, and add a builder method when useful to library callers.
  2. Update every formatter path that reads it; search for the field and related builder methods.
Important
Adding, removing, or changing a public ConfigConfig field changes the Rust API. Decide whether the release may be breaking and migrate every in-workspace consumer together.

CLI

  1. Add the argument/value enum in crates/typstyle/src/cli.rscrates/typstyle/src/cli.rs and map it to core ConfigConfig in crates/typstyle/src/fmt.rscrates/typstyle/src/fmt.rs.
  2. Preserve existing invocations when extending a boolean flag into an optional value. Require == for values so paths are not consumed: --wrap-text=sentence--wrap-text=sentence, while --wrap-text file.typ--wrap-text file.typ remains valid.
  3. Test positional paths and invalid values in crates/typstyle/tests/test_style_args.rscrates/typstyle/tests/test_style_args.rs.
  4. Run just generate-cli-helpjust generate-cli-help and update copied help text in README.mdREADME.md.

Tests and Rust Consumers

  1. Update direct ConfigConfig literals in crates/crates/ and tests/tests/; update tests/src/common/directive.rstests/src/common/directive.rs if fixtures need to select the option.
  2. Add focused semantic tests and representative fixture snapshots. Keep convergence and consistency checks enabled unless disabling them is understood and documented.

Before considering migration complete, search the repository and check the workspace:

rg 'old_field|OldVariant' --glob '!target/**'
cargo check --workspace
rg 'old_field|OldVariant' --glob '!target/**'
cargo check --workspace

Serialized, Embedded, and Documentation Consumers

ConfigConfig is deserialized by typstyle-wasmtypstyle-wasm and typstyle-typlugintypstyle-typlugin. For serialized options:

  1. Test serde serialization and deserialization in typstyle-coretypstyle-core.
  2. Ensure crates/typstyle-wasm/build.rscrates/typstyle-wasm/build.rs translates the field type into the generated TypeScript ConfigConfig interface and honors serde names instead of Rust variant names.
  3. Update defaults in contrib/typstyle-embedded/src/lib.typcontrib/typstyle-embedded/src/lib.typ and its README.
  4. Update docs/pages/docs/pages/ render directives: examples use embedded-plugin configuration, not CLI argument names. Run just build-pluginjust build-plugin before building docs.

Playground

  1. Update FormatOptionsFormatOptions, defaults, and formatOptionsToConfigformatOptionsToConfig in playground/src/utils/formatter.tsplayground/src/utils/formatter.ts, plus the control in playground/src/components/forms/SettingsPanel.tsxplayground/src/components/forms/SettingsPanel.tsx.
  2. Update URL-state expectations if the option name or type changed, and add a WASM binding test for its serialized value.
  3. Rebuild generated bindings before TypeScript validation:

    cd playground
    pnpm build:wasm
    pnpm build
    pnpm test:run
    cd playground
    pnpm build:wasm
    pnpm build
    pnpm test:run

Final Validation

Run checks appropriate to every touched boundary:

cargo fmt --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features
cargo nextest run --workspace --no-fail-fast
just build-docs
cargo fmt --check
cargo check --workspace
cargo clippy --workspace --all-targets --all-features
cargo nextest run --workspace --no-fail-fast
just build-docs

For behavior changes, review snapshots and test narrow widths, inline markup, comments, line-sensitive markup markers, and repeated formatting for convergence.