ESLint

Catch Kizuna mistakes in your editor with the official ESLint plugin.

@kizunajs/eslint-plugin catches Kizuna mistakes in your editor, as you type. These are things the type system can't express on its own.

pnpm add @kizunajs/eslint-plugin@beta
bun add @kizunajs/eslint-plugin@beta
npm install @kizunajs/eslint-plugin@beta

Setup

Add the recommended config to your eslint.config.js, alongside whatever else you already run:

eslint.config.js
import js from '@eslint/js';
import tseslint from 'typescript-eslint';
import kizuna from '@kizunajs/eslint-plugin';

export default [js.configs.recommended, ...tseslint.configs.recommended, kizuna.configs.recommended];

Turning a rule off

Override it after the recommended config:

eslint.config.js
import kizuna from '@kizunajs/eslint-plugin';

export default [
    kizuna.configs.recommended,
    {
        rules: {
            '@kizunajs/no-unsupported-schema': 'off',
        },
    },
];

Or silence a single line inline:

query: z.object({
    // eslint-disable-next-line @kizunajs/no-unsupported-schema
    page: z.coerce.number(),
}),

no-unsupported-schema

Flags anything using something Kizuna can't support: body, query, pathParams, headers, and response schemas in your routes, plus Kizuna.model schemas, inline or imported. It follows imports, so the error lands on the offending field when it's local, or on the reference when the schema comes from another file.

z.coerce

Kizuna already coerces query, path, and header params to their declared types (see Coercion), so z.coerce is redundant, and k.routes throws on it. Use the plain schema:

// flagged
query: z.object({
    page: z.coerce.number(),
});

// good, kizuna coerces the string for you
query: z.object({
    page: z.number(),
});

Across files

A schema defined elsewhere, such as a shared PaginationQuery in its own zod-only module, is still caught, and the error lands on the reference:

pagination.ts
import { z } from 'zod';

export const PaginationQuery = z.object({
    page: z.coerce.number(),
});
users.ts
import { PaginationQuery } from './pagination.js';

export const users = k.routes('users', {
    listUsers: k
        .route({
            method: 'GET',
            path: '/users',
            query: PaginationQuery, // flagged here, PaginationQuery uses z.coerce
            responses: {
                200: UserListSchema,
            },
        })
        .handler(/* ... */),
});

On this page