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

eslint-plugin-nitro-modules

v0.2.2

Published

ESLint plugin for enforcing best practices when developing with [Nitro](https://nitro.margelo.com) - a framework for building cross-platform modules with Swift, Kotlin, and C++.

Readme

eslint-plugin-nitro-modules

ESLint plugin for enforcing best practices when developing with Nitro - a framework for building cross-platform modules with Swift, Kotlin, and C++.

Installation

Install the package with your preferred package manager:

bun add -D eslint-plugin-nitro-modules
# or
npm install --save-dev eslint-plugin-nitro-modules
# or
yarn add -D eslint-plugin-nitro-modules
# or
pnpm add -D eslint-plugin-nitro-modules

Usage

This plugin is authored for ESLint 9’s flat config. Add it to eslint.config.js (or eslint.config.mjs):

import { defineConfig } from "eslint/config";
import nitroModulesPlugin from "eslint-plugin-nitro-modules";

export default defineConfig([
    // Start from the preset (includes plugin registration)
    nitroModulesPlugin.configs.recommended,

    // Optional: override specific rules (dotted rule keys)
    {
        plugins: {
            "nitro-modules-eslint": nitroModulesPlugin,
        },
        rules: {
            "nitro-modules-eslint/require-hybrid-object-platform-lang": "error",
            "nitro-modules-eslint/require-hybrid-view-platform-lang": "error",
            "nitro-modules-eslint/require-callback-wrapper-for-view-callbacks": "error",
            "nitro-modules-eslint/no-untyped-map": "warn",
            "nitro-modules-eslint/no-variant": "warn",
            "nitro-modules-eslint/no-object-param": "warn",
            "nitro-modules-eslint/prefer-arraybuffer-for-binary": "warn",
            "nitro-modules-eslint/no-unknown-nitro-type": "error",
        },
    },
]);

Available Rules

| Rule | Recommended | Strict | What it enforces | | --------------------------------------------- | ----------- | ------ | -------------------------------------------------------------------------------------------- | | require-hybrid-object-platform-lang | error | error | HybridObject must declare a valid platform language config. | | require-hybrid-view-platform-lang | error | error | HybridView must declare type params + a valid platform language config. | | require-callback-wrapper-for-view-callbacks | error | error | Nitro HostComponent callback props must be wrapped with callback(...) (not raw functions). | | no-untyped-map | warn | error | Avoid untyped AnyMap in Nitro APIs to reduce allocations. | | no-variant | warn | error | Avoid Nitro variant APIs; prefer strongly typed interfaces. | | no-object-param | warn | error | Avoid “bag object” parameters; flatten params to reduce allocations. | | prefer-arraybuffer-for-binary | warn | error | Avoid number[] for binary data; Nitro binary data should use ArrayBuffer. | | no-unknown-nitro-type | error | error | Disallow types not supported by Nitro’s typing system in Nitro API method params/returns. |

Rule Details

require-hybrid-object-platform-lang (Error)

Enforces that HybridObject interfaces specify a platform language configuration for at least one platform. The config is an object literal with ios and/or android keys.

  • iOS allowed values: 'swift' or 'c++'
  • Android allowed values: 'kotlin' or 'c++'
  • If you specify both platforms, the only valid combinations are:
    • { ios: 'swift', android: 'kotlin' }
    • { ios: 'c++', android: 'c++' }

Bad:

export interface BadSpec extends HybridObject {
    // ...
}

Good:

export interface GoodSpec extends HybridObject<{ ios: "swift"; android: "kotlin" }> {
    // ...
}

no-unknown-nitro-type (Error)

Enforces that Nitro API method parameter and return types are part of Nitro’s supported typing system, or are locally-defined custom types (interfaces, enums, type aliases).

Bad:

export interface BadSpec extends HybridObject<{ ios: "swift" }> {
    // Map/Set/Uint8Array/inline object types are not supported Nitro types
    bad1(x: Map<string, number>): void;
    bad2(x: { a: number }): void;
    bad3(): Uint8Array;
}

Good:

export interface GoodSpec extends HybridObject<{ ios: "swift" }> {
    ok1(x: Record<string, number>): void;
    ok2(): ArrayBuffer;
}

require-hybrid-view-platform-lang (Error)

Enforces that HybridView type aliases specify all three type parameters and a valid platform language configuration:

  • Props: first type parameter; must be an interface extending HybridViewProps (no inline object types)
  • Methods: second type parameter; must be an interface extending HybridViewMethods (no inline object types)
  • Platform config: third type parameter; object with ios and/or android keys
  • Allowed values: iOS 'swift', Android 'kotlin'
  • Valid combination when both platforms specified: { ios: 'swift', android: 'kotlin' }

Bad:

export type BadView = HybridView<
    { enabled: boolean }, // inline object type (disallowed)
    { onTap(): void }, // inline object type (disallowed)
    { ios: "swift"; android: "kotlin" }
>;

Good:

export interface GoodViewProps extends HybridViewProps {
    enabled: boolean;
}

export interface GoodViewMethods extends HybridViewMethods {
    onTap(): void;
}

export type GoodView = HybridView<
    GoodViewProps,
    GoodViewMethods,
    { ios: "swift"; android: "kotlin" }
>;

no-untyped-map (Error)

Prevents using untyped AnyMap objects in Nitro APIs to avoid extra allocations. Use typed maps or alternatives.

Bad:

export interface Spec extends HybridObject<{ ios: "swift"; android: "kotlin" }> {
    // AnyMap is a dynamic map type (discouraged)
    getConfig(): AnyMap;
}

Good:

export interface Config {
    enabled: boolean;
    maxRetries: number;
}

export interface Spec extends HybridObject<{ ios: "swift"; android: "kotlin" }> {
    getConfig(): Config;
}

no-variant (Warning/Error)

Discourages using variant APIs in Nitro. Prefer strongly-typed interfaces.

Bad:

export interface Spec extends HybridObject<{ ios: "swift"; android: "kotlin" }> {
    setValue(value: string | number): void;
}

Good:

export interface Spec extends HybridObject<{ ios: "swift"; android: "kotlin" }> {
    setStringValue(value: string): void;
    setNumberValue(value: number): void;
}

no-object-param (Warning/Error)

Discourages single bag-object parameters in Nitro API methods. Flatten parameters to avoid extra native allocations.

Bad:

export interface Spec extends HybridObject<{ ios: "swift"; android: "kotlin" }> {
    make(payload: { id: string; size: number }): void;
}

Good:

export interface Spec extends HybridObject<{ ios: "swift"; android: "kotlin" }> {
    make(id: string, size: number): void;
}

prefer-arraybuffer-for-binary (Warning/Error)

Prevents using number[] for binary data in Nitro APIs (to minimize copying/allocations). Nitro binary data should use ArrayBuffer.

Bad:

export interface Spec extends HybridObject<{ ios: "swift"; android: "kotlin" }> {
    // number[] forces extra copying/allocations
    encode(data: number[]): ArrayBuffer;
}

Good:

export interface Spec extends HybridObject<{ ios: "swift"; android: "kotlin" }> {
    encode(data: ArrayBuffer): ArrayBuffer;
}

require-callback-wrapper-for-view-callbacks (Error)

Enforces that callback props for Nitro HostComponents created with getHostComponent(...) are wrapped using callback(...) (instead of passing raw functions).

Bad:

// Given: const NitroView = getHostComponent<...>("NitroView")
<NitroView onReady={() => {}} />

Good:

import { callback } from "react-native-nitro-modules";

// Given: const NitroView = getHostComponent<...>("NitroView")
<NitroView onReady={callback(() => {})} />;

Development

Prerequisites

  • Bun v1.3.0 or higher
  • TypeScript

Getting Started

  1. Clone the repository
  2. Install dependencies:
bun install
  1. Build the project:
bun run build
  1. Type check the project:
bun run typecheck

Project Structure

eslint-plugin-nitro-modules/
├── src/
│   ├── index.ts              # Main plugin entry point
│   ├── utils.ts              # Shared utilities
│   └── rules/
│       ├── _rule-creator.ts  # Rule creator helper
│       ├── no-object-param.ts
│       ├── no-untyped-map.ts
│       ├── no-variant.ts
│       ├── prefer-arraybuffer-for-binary.ts
│       ├── require-callback-wrapper-for-view-callbacks.ts
│       ├── require-hybrid-object-platform-lang.ts
│       └── require-hybrid-view-platform-lang.ts
├── tests/                    # Test files for each rule
└── dist/                     # Compiled output (generated)

Running Tests

Tests use Bun's built-in test runner and TypeScript ESLint's RuleTester:

bun test

Adding a New Rule

  1. Create a new rule file in src/rules/ using createNitroRule helper
  2. Export the rule from src/index.ts
  3. Add the rule to the recommended and strict configs
  4. Create a test file in tests/
  5. Run tests: bun test

Example rule skeleton:

import { createNitroRule } from "./_rule-creator";

export default createNitroRule<[], "messageId">({
    name: "your-rule-name",
    meta: {
        type: "suggestion",
        docs: {
            description: "Rule description",
            url: "https://nitro.margelo.com/docs/...",
        },
        messages: {
            messageId: "Your error message",
        },
        schema: [],
    },
    defaultOptions: [],
    create(ctx) {
        return {
            // AST visitor methods
        };
    },
});

Writing Tests

Use TypeScript ESLint's RuleTester. Each test case must include a name and code:

import { ruleTester } from "./ruleTester";
import rule from "../src/rules/your-rule";

ruleTester.run("your-rule", rule, {
    valid: [
        {
            name: "short descriptive test name",
            code: `
        // Your valid TypeScript code here
        interface MyInterface extends HybridObject<{ ios: 'swift', android: 'kotlin' }> {
          someMethod(): void;
        }
      `,
        },
    ],
    invalid: [
        {
            name: "short descriptive error test name",
            code: `
        // Your invalid TypeScript code here
        interface BadInterface {
          badMethod(options: object): void;
        }
      `,
            errors: [{ messageId: "yourMessageId" }],
        },
    ],
});

Important: Always include descriptive name fields for each test case to make test failures easier to identify.

Contributing

Contributions are welcome — please see CONTRIBUTING.md.

License

This project is open source and available under the MIT License.

Resources