npm package: @nativewrappers/protogen
Description: Protocol Buffer code generator for TypeScript with esbuild and Vite plugins
Latest version: 0.0.4

# @nativewrappers/protogen

A Protocol Buffer code generator for TypeScript. Generates static encode/decode functions from `.proto` files as an esbuild plugin.


## Installation

```bash
pnpm add @nativewrappers/protogen protobufjs
```

## Usage

### esbuild Plugin

```typescript
import esbuild from "esbuild";
import { protogenPlugin } from "@nativewrappers/protogen";

await esbuild.build({
  entryPoints: ["src/**/*.ts"],
  outdir: "dist",
  plugins: [
    protogenPlugin({
      protoDirs: ["./src/protos"],
      watch: true, // Enable watching .proto files
    }),
  ],
});
```

### Vite Plugin

```typescript
import { defineConfig } from "vite";
import { protogenVitePlugin } from "@nativewrappers/protogen/vite";

export default defineConfig({
  plugins: [
    protogenVitePlugin({
      protoDirs: ["./src/protos"],
    }),
  ],
});
```

Both plugins generate `_pb.ts` files from `.proto` files at build start. In watch/dev mode, they automatically regenerate when proto files change.

### Generated Code

For proto files:

```protobuf
message ProtoVec3 {
  float x = 1;
  float y = 2;
  float z = 3;
}

message ProtoNetVehicle {
  int32 net_id = 1;
}
```

The generator produces:

```typescript
import { Reader, Writer } from "protobufjs/minimal.js";

export type Vec3 = {
  x: number;
  y: number;
  z: number;
};

export const ProtoVec3 = {
  name: "ProtoVec3" as const,
  encode: (msg: Vec3): Uint8Array => { ... },
  decode: (bytes: Uint8Array): Vec3 => { ... },
  create: (data?: Partial<Vec3>): Vec3 => ({ ... }),
};

export type NetVehicle = {
  net_id: number;
};

export const ProtoNetVehicle = {
  name: "ProtoNetVehicle" as const,
  encode: (msg: NetVehicle): Uint8Array => { ... },
  decode: (bytes: Uint8Array): NetVehicle => { ... },
  create: (data?: Partial<NetVehicle>): NetVehicle => ({ ... }),
};
```

### Importing Generated Code

```typescript
import { ProtoVec3, ProtoNetVehicle } from "./protos/Types_pb";

const bytes = ProtoVec3.encode({ x: 1.0, y: 2.5, z: 3.0 });
const position = ProtoVec3.decode(bytes);
```

## Configuration

### Plugin Options

```typescript
protogenPlugin({
  // Directories containing .proto files
  protoDirs: ["./src/protos"],

  // Output file suffix (default: "_pb.ts")
  suffix: "_pb.ts",

  // Include 'name' field in output (default: true)
  generateName: true,

  // Include 'create' method (default: true)
  generateCreate: true,

  // Field naming: "snake" or "camel" (default: "snake")
  fieldCase: "snake",

  // Custom decode transforms
  transforms: {},
});
```

### Minimal Output

```typescript
protogenPlugin({
  protoDirs: ["./src/protos"],
  generateName: false,
  generateCreate: false,
});
```

Generates only `encode` and `decode`:

```typescript
export const ProtoVec3 = {
  encode: (msg: Vec3): Uint8Array => { ... },
  decode: (bytes: Uint8Array): Vec3 => { ... },
};
```

## Transforms

Wrap decoded messages in custom classes:

```typescript
protogenPlugin({
  protoDirs: ["./src/protos"],
  transforms: {
    ProtoVec3: {
      import: "@nativewrappers/common",
      importName: "Vector3",
      returnType: "Vector3",
      transform: (msg) => `new Vector3(${msg}.x, ${msg}.y, ${msg}.z)`,
    },
    ProtoNetVehicle: {
      import: "@nativewrappers/redm",
      importName: "Vehicle",
      returnType: "Vehicle | null",
      transform: (msg) => `Vehicle.fromNetId(${msg}.net_id)`,
    },
  },
});
```

With transforms, the generated code changes to:

```typescript
import { Reader, Writer } from "protobufjs/minimal.js";
import { Vector3 } from "@nativewrappers/common";
import { Vehicle } from "@nativewrappers/redm";

export const ProtoVec3 = {
  name: "ProtoVec3" as const,
  encode: (msg: Vec3): Uint8Array => { ... },
  decode: (bytes: Uint8Array): Vector3 => {
    // ... decodes to raw Vec3, then:
    return new Vector3(message.x, message.y, message.z);
  },
};

export const ProtoNetVehicle = {
  name: "ProtoNetVehicle" as const,
  encode: (msg: NetVehicle): Uint8Array => { ... },
  decode: (bytes: Uint8Array): Vehicle | null => {
    // ... decodes to raw NetVehicle, then:
    return Vehicle.fromNetId(message.net_id);
  },
};
```

## Build Setup

For projects needing `.d.ts` declarations:

```json
{
  "scripts": {
    "build": "node build.js && tsc --emitDeclarationOnly"
  }
}
```

## Supported Types

| Proto Type | TypeScript Type |
|------------|-----------------|
| double, float | number |
| int32, uint32, sint32, fixed32, sfixed32 | number |
| int64, uint64, sint64, fixed64, sfixed64 | bigint |
| bool | boolean |
| string | string |
| bytes | Uint8Array |
| enum | enum |
| message | type |
| repeated T | T[] |

## License

This is free and unencumbered software released into the public domain. See [LICENSE](LICENSE) for details.