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

biome-plugin-roblox-ts

v1.0.0

Published

Biome GritQL rules for roblox-ts projects

Downloads

296

Readme

cover

biome-plugin-roblox-ts

A port of the eslint-plugin-roblox-ts ruleset to Biome. Designed for roblox-ts development.

This plugin enforces TypeScript restrictions, Lua compatibility patterns, and Roblox-specific best practices using GritQL rules.

v1.0 Stable — 23 of 34 rules are fully functional, covering all rules possible with Biome's current GritQL plugin system. The remaining 11 rules are blocked by upstream Biome limitations (plugin node type support and lack of TypeScript type access) that affect all GritQL plugins, not just this one. Blocked rules are kept in the codebase and will activate automatically as Biome expands support. See Limitations for details.

Installation

1. Install Biome and the Plugin

# npm
npm install --save-dev @biomejs/biome biome-plugin-roblox-ts

# bun
bun add -D @biomejs/biome biome-plugin-roblox-ts

# yarn
yarn add -D @biomejs/biome biome-plugin-roblox-ts

2. Initialize Biome (if not already done)

npx @biomejs/biome init

3. Install Biome VS Code Extension

Install the Biome VS Code extension for IDE integration.

Configuration

Add the plugin to your biome.json:

{
  "extends": ["biome-plugin-roblox-ts/biome"]
}

Customizing Rules

You can disable or adjust specific rules in your biome.json:

{
  "linter": {
    "rules": {
      "nursery": {
        "noNull": "off",
        "noAnyType": "warn"
      }
    }
  }
}

Rules

Rules marked with ^ are blocked by a Biome plugin limitation and do not currently fire diagnostics. They are included so they will automatically activate when Biome expands its plugin node type support.

Lua Truthiness (3 rules)

| Rule | Description | |------|-------------| | luaTruthiness | Warns when empty strings are used in conditions (falsy in TS but truthy in Lua) | | luaTruthinessZero | Warns when 0 is used in conditions (falsy in TS but truthy in Lua) | | luaTruthinessNaN | Warns when NaN is used in conditions (falsy in TS but truthy in Lua) |

Operators & Math (5 rules)

| Rule | Description | |------|-------------| | noObjectMath | Bans + operator on Roblox data types (use .add()) | | noMathSub | Bans - operator on Roblox data types (use .sub()) | | noMathMul | Bans * operator on Roblox data types (use .mul()) | | noMathDiv | Bans / operator on Roblox data types (use .div()) | | sizeMethod* | Warns on .length property access (use .size() method instead) |

TypeScript Restrictions (7 rules)

| Rule | Description | |------|-------------| | noAnyType | Bans any type (use unknown instead) | | noEnumMerging^ | Bans enum declarations (enum merging is not supported) | | noNamespaceMerging^ | Bans namespace declarations (namespace merging is not supported) | | noPrivateIdentifier^ | Bans # private fields (not supported in Luau) | | noGettersOrSetters^ | Bans getter methods (not supported for performance reasons) | | noSetters^ | Bans setter methods (not supported for performance reasons) | | noExportAssignmentLet | Bans export = syntax |

Lua Compatibility (5 rules)

| Rule | Description | |------|-------------| | noInvalidIdentifier | Bans Luau reserved keywords as identifiers (and, end, local, nil, not, or, elseif, repeat, then, until) | | noNull | Bans null (use undefined instead, which maps to Lua nil) | | noForIn^ | Bans for-in loops (iterator always types as string; use for-of) | | noArrayPairs | Bans pairs() on arrays (indices won't be shifted from 1-indexed) | | noArrayIPairs | Bans ipairs() on arrays (indices won't be shifted from 1-indexed) |

Unsupported Syntax (5 rules)

| Rule | Description | |------|-------------| | noGlobalThis | Bans globalThis (not supported in Luau) | | noLabels^ | Bans labeled statements (not supported in Luau) | | noPrototype | Bans .prototype access (not supported in Luau) | | noRegex | Bans regex literals (not supported in Luau) | | noSpreadingTuples | Bans spreading tuples (not supported in Luau) |

Roblox-Specific (6 rules)

| Rule | Description | |------|-------------| | noRbxPostFixNew | Bans .new() (use new X() instead) | | noImplicitSelf^ | Bans : method call syntax (use . instead) | | preferTaskLibrary | Prefers task library over coroutine for better performance | | preferGetPlayers | Prefers Players.GetPlayers() over Players.GetChildren() | | noValueTypeOf | Bans typeof operator (use typeIs() or typeOf()) | | noPrecedingSpreadElement | Enforces spread element comes last in arguments |

Other (3 rules)

| Rule | Description | |------|-------------| | noFunctionExpressionName | Bans named function expressions | | misleadingLuatupleChecks* | Warns about LuaTuple in conditional expressions | | noUndeclaredScope* | Validates scoped npm packages against typeRoots |

Built-in Biome Rules (4 rules)

These rules are provided by Biome itself and enabled as warnings:

  • noDebugger - Bans debugger statements
  • noDelete - Bans delete operator
  • noNonNullAssertion - Bans ! assertion operator
  • noWithStatement - Bans with statements

Limitations

GritQL is currently the only way to write custom Biome lint rules. There is no WASM, JS/TS, or Rust plugin API available to third parties — native rules must be merged directly into Biome's codebase. These limitations affect all GritQL plugin authors, not just this project.

Biome Plugin Node Type Support (^)

Biome's GritQL plugin system only visits a subset of AST node types (expressions, identifiers, literals, and a few statement types). Patterns that target declarations (enums, namespaces), class members (getters/setters), for-in statements, labeled statements, and private identifiers do not fire as lint diagnostics — even though they match correctly in biome search.

8 rules are blocked by this limitation: noEnumMerging, noGettersOrSetters, noSetters, noNamespaceMerging, noLabels, noForIn, noImplicitSelf, noPrivateIdentifier

These rules are kept in the plugin so they will automatically start working when Biome expands its plugin support. You can verify the patterns work today using biome search:

npx @biomejs/biome search '`enum $name { $body }`' ./src/

TypeScript Type Information (*)

GritQL does not have access to TypeScript's type checker:

  • misleadingLuatupleChecks - Cannot detect LuaTuple types
  • noUndeclaredScope - Cannot read tsconfig typeRoots or check file system
  • sizeMethod - Cannot verify if .length is on a string/array vs other types (may produce false positives)

For full type-aware linting, use the original eslint-plugin-roblox-ts alongside this plugin.

Path to Full Coverage

The blocked rules could be implemented as native Rust rules contributed upstream to the Biome project, which would have full AST and type access. This is being explored as a future effort.

Testing

bun test

Tests use Bun's test runner with fixture files in tests/invalid/ and tests/valid/. Rules blocked by Biome limitations are automatically skipped.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT License - see LICENSE for details.

Related Projects