Skip to content

About

Common ast-grep rules for use across my projects

Resources

Code of conduct

Stars

13 stars

Watchers

0 watching

Forks

Repository files navigation

ast-grep-rules

An opinionated set of ast-grep rules for Rust, TypeScript, Svelte, HTML, Python, Go, Pi extensions, and OpenCode plugins.

The rules catch API design problems, weak error handling, deprecated Svelte patterns, and code clutter. Pre-commit users can choose rules by language or run the whole set.

Use with prek or pre-commit

Install prek (recommended for faster installs and runs) or pre-commit. Both use the same .pre-commit-config.yaml.

Choose all to run every rule:

repos:
  - repo: https://github.com/joshuadavidthomas/ast-grep-rules
    rev: main
    hooks:
      - id: all

Set rev to a release tag when you want a fixed version. To select rule groups instead, list only the hooks the project needs:

repos:
  - repo: https://github.com/joshuadavidthomas/ast-grep-rules
    rev: main
    hooks:
      - id: pi
      - id: opencode
Hook Files checked Rules selected
all All text files Every rule
rust Rust IDs starting with rust-
typescript TypeScript and Svelte script blocks IDs starting with typescript-
pi TypeScript Pi extensions IDs starting with pi-
opencode TypeScript and TSX OpenCode plugins IDs starting with opencode-
svelte Svelte IDs starting with svelte-
html HTML IDs starting with html-
python Python IDs starting with python-
go Go IDs starting with go-

Language hooks include the shared checks for that language because shared rule IDs carry the same language prefix. For example, rust includes rust-no-code-barricade. Pi and OpenCode use product prefixes so each plugin ecosystem can run only its own rules.

With prek, install the Git hook and prepare its environment up front:

prek install --prepare-hooks
prek run all --all-files

The equivalent pre-commit commands are:

pre-commit install --install-hooks
pre-commit run all --all-files

Preparing the hook downloads an isolated Node.js environment, ast-grep, and the Svelte parser. Later runs reuse that environment. The project does not need Node.js or an sgconfig.yml.

Both tools scan tracked files. Add a new file to version control before expecting --all-files to include it. Rules with warning severity print findings without failing the hook; error rules fail it.

Turn off rules

Pass ast-grep's --off option once for each rule:

repos:
  - repo: https://github.com/joshuadavidthomas/ast-grep-rules
    rev: main
    hooks:
      - id: rust
        args:
          - --off=rust-no-single-field-struct
          - --off=rust-no-visible-bool-argument

Use as a Node.js command

Install the tagged Git package in a project that uses Node.js 22, 24, or 26:

npm install --save-dev "github:joshuadavidthomas/ast-grep-rules#v0.6.0"
npx ast-grep-rules .

The command uses its packaged rules and configuration. Pass any ast-grep scan options after the command.

Run from this repository

Install a maintained Node.js release (22, 24, or 26) and just, then install the pinned ast-grep CLI and Svelte parser:

npm install

Scan a project:

just scan /path/to/project

just scan also reports blanket suppressions and stale suppression comments. To run the rule tests:

just test

Install uv only if you need to audit the GitHub Actions workflows with Zizmor:

just lint

Rule reference

All rules link to their definitions. Most definitions include a note with exceptions and replacement advice.

Common

Rule Language Severity Reports
rust-no-code-barricade Rust warning Decorative divider comments made from repeated punctuation. Use a plain section comment or split the file.
typescript-no-code-barricade TypeScript warning Decorative divider comments made from repeated punctuation. Use a plain section comment or split the file.
html-no-code-barricade HTML warning Decorative divider comments made from repeated punctuation. Use a plain section comment or split the file.
svelte-no-code-barricade Svelte warning Decorative divider comments in Svelte templates. Use a plain section comment or split the file.
python-no-code-barricade Python warning Decorative divider comments made from repeated punctuation. Use a plain section comment or split the file.
go-no-code-barricade Go warning Decorative divider comments made from repeated punctuation. Use a plain section comment or split the file.

Rust

Rule Severity Reports
rust-no-anyhow-in-public-api warning Visible functions, trait methods, and type aliases that expose anyhow. Return an error type callers can inspect.
rust-no-deny-warnings warning #![deny(warnings)], which can break a build when a compiler or dependency adds a warning. Set explicit lint levels instead.
rust-no-deref-polymorphism warning Deref implementations used for API forwarding. Reserve Deref for smart pointers and expose methods on other types.
rust-no-dropped-error-source warning map_err(|_| Error::Variant) and .ok().ok_or(...) that discard the original error. Carry the source in the new error instead.
rust-no-empty-braced-struct warning Empty braced structs. Use a unit struct unless braces carry a schema, FFI, or code-generation contract.
rust-no-indexed-array-rebuild warning [bytes[0], bytes[1], ...] array literals that index the same slice element by element. Take the chunk with split_first_chunk or try_into instead.
rust-no-option-bool-field warning Option<bool> struct fields. Name the three states with an enum.
rust-no-panicking-fallback error unwrap_or_else and map_or_else fallbacks that end in a panic or another diverging macro. Handle the failed or absent value instead. Skips test files and #[cfg(test)] items.
rust-no-panicking-let-else error let-else branches that end in a panic or another diverging macro. Return, break, continue, or model the failed pattern. Skips test files and #[cfg(test)] items.
rust-no-panicking-match-arm error Match arms that end in a panic or another diverging macro. Return, propagate, or give the arm a real value. Skips test files and #[cfg(test)] items.
rust-no-public-struct-fields warning Visible fields on visible structs. Keep representation private unless the struct is passive data.
rust-no-public-tuple-newtype-field warning Visible tuple-newtype fields. Keep the field private and expose chosen constructors or accessors.
rust-no-single-field-struct warning Named-field structs with one field. Use a tuple newtype unless an external schema or FFI needs the field name.
rust-no-single-member-enum warning Enums with one variant, except #[non_exhaustive] enums. Use a struct or newtype, or add the missing variants.
rust-no-string-error-variant warning Bare String payloads in variants of enums named Error or ending in Error. Keep structured fields or source errors.
rust-no-trivial-whitespace-helper error Local helpers that only wrap standard whitespace checks. Inline the check or name the domain policy it implements.
rust-no-visible-bool-argument warning bool parameters in visible functions and trait methods. Use a named enum or split the operation.
rust-require-reasoned-clippy-suppression warning Clippy allow and expect attributes without a reason. Record why the local exception should remain.
rust-require-thiserror-error-enum warning Error enums without a thiserror::Error derive. Derive it instead of hand-writing error behavior.

TypeScript

Rule Severity Reports
typescript-no-chained-type-assertions error Nested as or angle-bracket assertions, except chains made only of const. Keep the original type or parse unknown input at its boundary.
typescript-no-conditional-empty-object-spread error Object spreads that use {} on one side of a ternary to omit a field. Write the property or build the object in later statements.
typescript-no-generic-error-message-helper error Helpers that reduce an unknown error to error.message or String(error). Preserve the original error and write separate user-facing text.
typescript-no-hand-rolled-object-type-guard error Object type predicates over unknown input that rely on typeof value === "object". Parse the expected shape with a schema validator.
typescript-no-known-value-widening warning A written literal, array, object, or function given an explicit unknown, object, Record, or anonymous object type. Keep inference, use satisfies, or name the owner type.
typescript-no-object-parameters error Function parameters typed as object. Use the owner type or parse the input at its boundary.
typescript-no-record-string-unknown error Dictionary types whose value is unknown, any, object, or {}, including index signatures and Readonly/NonNullable wrappers. Declare the actual value type, or keep the input unknown and parse it at the boundary.
typescript-no-runtime-typeof error Runtime typeof checks. Parse the value into a domain type at the I/O boundary.
typescript-no-shape-in-symbol-names warning The word shape in a TypeScript identifier. Name the owner type or the parsed domain value.
typescript-no-shape-in-symbol-names-tsx warning The same shape name check for TSX identifiers.
typescript-no-unknown-parameters error Parameters typed as unknown, except a parameter named cause. Give the input a named contract or parse it at the I/O boundary.
typescript-no-unknown-type-aliases error Type aliases that only rename unknown. Keep unknown visible or replace it with the parsed owner type.
typescript-no-widen-then-assert warning A local const widened to unknown, any, object, or Record<..., unknown> and later asserted to a narrower type. Keep the precise type, or parse unknown input once at the boundary.

Pi

Rule Severity Reports
pi-extension-no-console-log error console.log in a typed Pi extension entry point. Use ctx.ui, tool result rendering, or a message or entry renderer.

OpenCode

Rule Severity Reports
opencode-plugin-no-console-log error console.log in TypeScript modules that import OpenCode's plugin API. Use TUI feedback, structured server logging, or a tool result.
opencode-plugin-no-console-log-tsx error The same OpenCode plugin check for TSX modules.

Svelte

Rule Severity Reports
svelte-no-create-event-dispatcher warning createEventDispatcher imports and direct calls. Svelte 5 components should declare and call callback props.

The wrapper registers tree-sitter-svelte as an ast-grep custom language, so Svelte rules can match component and template nodes such as {#if} and {#each} blocks. It injects every <script> body as TypeScript so script rules also work with plain and lang="ts" blocks.

The parser installs without a compiler on glibc Linux x64, macOS x64 and arm64, and Windows x64. Linux arm64 and Windows arm64 or 32-bit x86 build the parser from source and need Python plus a native compiler. The pinned ast-grep CLI does not support other targets such as musl Linux.

Add or change a rule

  1. Add the rule under rules/<prefix>-<rule-id>.yml.
  2. Add valid and invalid examples under tests/<prefix>-<rule-id>-test.yml.
  3. Run just test.
  4. If the expected findings changed, run just test --update-all and review the snapshots in tests/__snapshots__/.
  5. Add or update the rule in the reference above.

Use common- for files that contain rules for several languages and a language prefix such as rust- for files tied to one language. Start every rule ID with its language, such as rust-no-deny-warnings. Keep rule IDs stable, descriptive, and kebab-cased.

Repository layout

  • rules/ contains the rule definitions.
  • tests/ contains valid and invalid examples, generated snapshots, and a real .svelte scan test.
  • sgconfig.yml defines the rules, tests, custom Svelte language, and script injection.
  • bin/ast-grep-rules.mjs resolves the native parser, renders the config paths, and runs the pinned ast-grep CLI.
  • .agents/skills/ast-grep/ contains the local agent guide for writing and debugging rules.

License

ast-grep-rules is licensed under the MIT license. See LICENSE for details.

About

Common ast-grep rules for use across my projects

Resources

Code of conduct

Stars

13 stars

Watchers

0 watching

Forks

Releases

Sponsor this project

Packages

Contributors

Languages