npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@sanity/groq-wasm

v0.0.1

Published

WASM bindings for GROQ linting and formatting (groq-lint + groq-format)

Readme

@sanity/groq-wasm

WASM bindings for GROQ linting and formatting.

This package provides TypeScript wrappers around:

Both are compiled to WebAssembly for use in Node.js and browsers without requiring the Rust toolchain.

Installation

npm install @sanity/groq-wasm

Usage

import { initWasm, lint, format } from '@sanity/groq-wasm'

// Initialize WASM (call once at startup)
await initWasm()

// Lint a query
const findings = lint('*[_type == "post"]{ author-> }')
console.log(findings)
// [{ ruleId: 'join-in-filter', message: '...', severity: 'error' }]

// Format a query
const formatted = format('*[_type=="post"]{title,body}')
console.log(formatted)
// '*[_type == "post"]{ title, body }'

API

Initialization

initWasm(): Promise<void>

Initialize the WASM modules. Must be called before using lint() or format(). Safe to call multiple times.

isInitialized(): boolean

Check if WASM modules are initialized.

Linting

lint(query: string, config?: WasmLintConfig): Finding[]

Lint a GROQ query and return findings.

interface WasmLintConfig {
  rules?: Record<string, boolean> // Enable/disable specific rules
}

lintAsync(query: string, config?: WasmLintConfig): Promise<Finding[]>

Async version of lint().

Formatting

format(query: string, config?: WasmFormatConfig): string

Format a GROQ query.

interface WasmFormatConfig {
  width?: number // Max line width (default: 80)
}

formatAsync(query: string, config?: WasmFormatConfig): Promise<string>

Async version of format().

isValidSyntax(query: string): boolean

Check if a query has valid GROQ syntax.

Constants

DEFAULT_WIDTH: number

Default line width for formatting (80).

RULE_ID_MAP: Record<string, string>

Mapping from Rust rule IDs (snake_case) to TS convention (kebab-case).

Lint Rules

The following rules are available (from Rust groq-lint):

| Rule ID | Severity | Description | | ------------------------------ | -------- | ---------------------------------------------------- | | join-in-filter | error | Dereference (->) inside filter prevents optimization | | join-to-get-id | warning | Using -> to get _id (use ._ref instead) | | computed-value-in-filter | error | Computed values in filter prevent optimization | | match-on-id | info | Using match on _id with wildcard | | order-on-expr | error | Ordering on computed values | | deep-pagination | warning | Large offset in slice (>=1000) | | large-pages | warning | Fetching >100 results from index 0 | | non-literal-comparison | error | Comparing two non-literal expressions | | repeated-dereference | info | Multiple -> on same attribute in projection | | count-in-correlated-subquery | info | count() on correlated subqueries | | very-large-query | error | Query exceeds 10KB | | extremely-large-query | error | Query exceeds 100KB | | many-joins | warning | Query has >10 dereference operators |

Error Handling

import { WasmError } from '@sanity/groq-wasm'

try {
  const findings = lint(query)
} catch (error) {
  if (error instanceof WasmError) {
    switch (error.code) {
      case 'NOT_INITIALIZED':
        // Call initWasm() first
        break
      case 'PARSE_ERROR':
        // Invalid GROQ syntax
        break
      case 'WASM_ERROR':
        // Other WASM error
        break
    }
  }
}

Browser Support

This package works in modern browsers that support WebAssembly. The WASM modules are loaded automatically based on the environment.

// In browser
import { initWasm, lint } from '@sanity/groq-wasm'

await initWasm()
const findings = lint(query)

Architecture

This package uses a wrapper crate approach:

packages/groq-wasm/
├── rust/                    # Rust wrapper crate
│   ├── Cargo.toml          # Depends on groq-lint & groq-format
│   └── src/lib.rs          # wasm-bindgen exports
├── wasm/                    # Built WASM output (generated)
├── src/                     # TypeScript wrappers
│   ├── index.ts            # Main exports
│   ├── lint.ts             # Linting API
│   ├── format.ts           # Formatting API
│   └── wasm-loader.ts      # WASM initialization
└── scripts/
    └── build-wasm.sh       # Build script

The Rust crate depends on upstream repos as git dependencies (no forking required).

Building from Source

To rebuild the WASM bindings:

Prerequisites

# Install Rust
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

# Add WASM target
rustup target add wasm32-unknown-unknown

# Install wasm-pack
cargo install wasm-pack

Build

cd packages/groq-wasm
./scripts/build-wasm.sh

This will:

  1. Compile the Rust wrapper crate to WASM
  2. Generate JS bindings via wasm-bindgen
  3. Output files to wasm/

Performance

The WASM implementation provides significant performance benefits:

  • Linting: ~5-10x faster than TypeScript for complex queries
  • Formatting: Near-instant formatting for most queries
  • Memory: Lower memory footprint than JavaScript AST processing

License

MIT