plotnik-langs 0.3.2

Tree-sitter language bindings for Plotnik query language
Documentation
<br/>

<p align="center">
  <img width="400" alt="The logo: a curled wood shaving on a workbench" src="https://github.com/user-attachments/assets/8f1162aa-5769-415d-babe-56b962256747" />
</p>

<h1><p align="center">Plotnik</p></h1>

<br/>

<p align="center">
  A type-safe query language for <a href="https://tree-sitter.github.io">Tree-sitter</a>.<br/>
  Powered by the <a href="https://github.com/bearcove/arborium">arborium</a> grammar collection.
</p>
  
<br/>

<p align="center">
  <a href="https://github.com/plotnik-lang/plotnik/actions/workflows/stable.yml"><img src="https://github.com/plotnik-lang/plotnik/actions/workflows/stable.yml/badge.svg" alt="stable"></a>
  <a href="https://github.com/plotnik-lang/plotnik/actions/workflows/nightly.yml"><img src="https://github.com/plotnik-lang/plotnik/actions/workflows/nightly.yml/badge.svg" alt="nightly"></a>
  <a href="https://codecov.io/gh/plotnik-lang/plotnik"><img src="https://codecov.io/gh/plotnik-lang/plotnik/graph/badge.svg?token=071HXJIY3E"/></a>
  <a href="LICENSE"><img src="https://img.shields.io/badge/license-Apache--2.0-blue.svg" alt="Apache-2.0 License"></a>
</p>

<br/>

<p align="center">
    <sub>
      <strong>
        ⚠️ BETA: NOT FOR PRODUCTION USE ⚠️<br/>
      </strong>
    </sub>
</p>

<br/>

Tree-sitter gives you the syntax tree. Extracting structured data from it still means writing imperative navigation code, null checks, and maintaining type definitions by hand. Plotnik makes extraction declarative: write a pattern, get typed data. The query is the type definition.

## Features

- [x] Static type inference from query structure
- [x] Named expressions for composition and reuse
- [x] Recursion for nested structures
- [x] Tagged unions (discriminated unions)
- [x] TypeScript type generation
- [x] CLI: `exec` for matches, `infer` for types, `ast`/`trace`/`dump` for debug
- [ ] Full validation against grammar (reject queries that can never match)
- [ ] Compile-time queries via proc-macro
- [ ] WASM
- [ ] LSP, editor extensions

## Installation

```sh
cargo install plotnik
```

By default, 15 common languages are included. To add specific languages:

```sh
cargo install plotnik --features lang-ruby,lang-elixir
```

Or with all 80+ languages:

```sh
cargo install plotnik --features all-languages
```

## Example

Extract function signatures from Rust. `Type` references itself to handle nested generics like `Option<Vec<String>>`.

`query.ptk`:

```clojure
Type = [
  Simple: [(type_identifier) (primitive_type)] @name :: string
  Generic: (generic_type
    type: (type_identifier) @name :: string
    type_arguments: (type_arguments (Type)* @args))
]

Func = (function_item
  name: (identifier) @name :: string
  parameters: (parameters
    (parameter
      pattern: (identifier) @param :: string
      type: (Type) @type
    )* @params))

Funcs = (source_file (Func)* @funcs)
```

`lib.rs`:

```rust
fn get(key: Option<Vec<String>>) {}

fn set(key: String, val: i32) {}
```

Plotnik infers TypeScript types from the query structure. `Type` is recursive: `args: Type[]`.

```sh
❯ plotnik infer query.ptk --lang rust
export type Type =
  | { $tag: "Simple"; $data: { name: string } }
  | { $tag: "Generic"; $data: { name: string; args: Type[] } };

export interface Func {
  name: string;
  params: { param: string; type: Type }[];
}

export interface Funcs {
  funcs: Func[];
}
```

Run the query against `lib.rs` to extract structured JSON:

```sh
❯ plotnik exec query.ptk lib.rs
{
  "funcs": [
    {
      "name": "get",
      "params": [{
        "param": "key",
        "type": {
          "$tag": "Generic",
          "$data": {
            "name": "Option",
            "args": [{
              "$tag": "Generic",
              "$data": {
                "name": "Vec",
                "args": [{ "$tag": "Simple", "$data": { "name": "String" } }]
              }
            }]
          }
        }
      }]
    },
    {
      "name": "set",
      "params": [
        { "param": "key", "type": { "$tag": "Simple", "$data": { "name": "String" } } },
        { "param": "val", "type": { "$tag": "Simple", "$data": { "name": "i32" } } }
      ]
    }
  ]
}
```

## Why

Pattern matching over syntax trees is powerful, but tree-sitter queries produce flat capture lists. You still need to assemble the results, handle missing captures, and define types by hand. Plotnik closes this gap: the query describes structure, the engine guarantees it.

## Documentation

- [CLI Guide]docs/cli.md
- [Language Reference]docs/lang-reference.md
- [Type System]docs/type-system.md

## Acknowledgments

[Max Brunsfeld](https://github.com/maxbrunsfeld) created Tree-sitter; [Amaan Qureshi](https://github.com/amaanq) and other contributors maintain the parser ecosystem that makes this project possible.

## License

This project is licensed under the [Apache License (Version 2.0)].

[Apache License (Version 2.0)]: LICENSE