{"id":34731573,"url":"https://github.com/ysknsid25/eslint-plugin-hono","last_synced_at":"2026-01-20T17:00:57.161Z","repository":{"id":328801344,"uuid":"1116665476","full_name":"ysknsid25/eslint-plugin-hono","owner":"ysknsid25","description":"🔥 ESLint plugin for Hono and all Hono lovers","archived":false,"fork":false,"pushed_at":"2025-12-16T12:11:42.000Z","size":310,"stargazers_count":5,"open_issues_count":2,"forks_count":1,"subscribers_count":0,"default_branch":"master","last_synced_at":"2025-12-26T13:48:50.544Z","etag":null,"topics":["2025","eslint","eslint-plugin","honojs","javascript","npm","typescript","works"],"latest_commit_sha":null,"homepage":"https://www.npmjs.com/package/eslint-plugin-hono","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ysknsid25.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null},"funding":{"github":"ysknsid25","patreon":null,"open_collective":null,"ko_fi":null,"tidelift":null,"community_bridge":null,"liberapay":null,"issuehunt":null,"otechie":null,"lfx_crowdfunding":null,"custom":null}},"created_at":"2025-12-15T07:53:32.000Z","updated_at":"2025-12-25T03:40:54.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ysknsid25/eslint-plugin-hono","commit_stats":null,"previous_names":["ysknsid25/eslint-plugin-hono"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ysknsid25/eslint-plugin-hono","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysknsid25%2Feslint-plugin-hono","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysknsid25%2Feslint-plugin-hono/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysknsid25%2Feslint-plugin-hono/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysknsid25%2Feslint-plugin-hono/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ysknsid25","download_url":"https://codeload.github.com/ysknsid25/eslint-plugin-hono/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ysknsid25%2Feslint-plugin-hono/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28607624,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-20T16:10:39.856Z","status":"ssl_error","status_checked_at":"2026-01-20T16:10:39.493Z","response_time":117,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["2025","eslint","eslint-plugin","honojs","javascript","npm","typescript","works"],"created_at":"2025-12-25T03:00:33.723Z","updated_at":"2026-01-20T17:00:56.977Z","avatar_url":"https://github.com/ysknsid25.png","language":"TypeScript","funding_links":["https://github.com/sponsors/ysknsid25"],"categories":[],"sub_categories":[],"readme":"# eslint-plugin-hono\n\n🔥 ESLint plugin for [Hono](https://hono.dev/) and all Hono lovers\n\n## ⚠️ Still in alpha version ⚠️\n\nIn order for this plugin to become a major release, it's extremely important that you experiment with it. \n\nPlease try it out and incorporate it into your Hono project. \n\nPlease also create issues with any bugs, improvement requests, and new feature suggestions.\n\n## Installation\n\n```bash\nnpm install -D eslint-plugin-hono@alpha\n```\n\n## Usage (Flat Config)\n\nTo use the recommended configuration, create an `eslint.config.js` file in your project root and add the following:\n\n```javascript\nimport globals from \"globals\";\nimport pluginJs from \"@eslint/js\";\nimport tseslint from \"typescript-eslint\";\nimport hono from \"eslint-plugin-hono\";\n\nexport default [\n    {\n        plugins: {\n            hono: hono,\n        },\n    },\n    pluginJs.configs.recommended,\n    ...tseslint.configs.recommended,\n    ...hono.configs.recommended,\n    {\n        files: [\"**/*.{ts,tsx,cts,mts}\"],\n        languageOptions: {\n            parser: tseslint.parser,\n            parserOptions: {\n                ecmaVersion: \"latest\",\n                sourceType: \"module\",\n                project: \"./tsconfig.json\",\n            },\n            globals: globals.node,\n        },\n    },\n];\n```\n\nIf you want to apply the rules only to specific files, you can use the `files` property:\n\n```javascript\nimport globals from \"globals\";\nimport pluginJs from \"@eslint/js\";\nimport tseslint from \"typescript-eslint\";\nimport hono from \"eslint-plugin-hono\";\n\nexport default [\n    {\n        plugins: {\n            hono: hono,\n        },\n    },\n    pluginJs.configs.recommended,\n    ...tseslint.configs.recommended,\n    ...hono.configs.recommended,\n    {\n        files: [\"**/*.{ts,tsx,cts,mts}\"],\n        languageOptions: {\n            parser: tseslint.parser,\n            parserOptions: {\n                ecmaVersion: \"latest\",\n                sourceType: \"module\",\n                project: \"./tsconfig.json\",\n            },\n            globals: globals.node,\n        },\n        rules: {\n            // custom rules\n        }\n    },\n];\n```\n\n## Rules\n\n| Rule | ⚠️ warn | 🚨 error | 🔧 fix |\n| :--- | :---: | :---: | :---: |\n| [route-grouping](#hono-route-grouping) | | ✅ | ✅ |\n| [prefer-http-exception](#hono-prefer-http-exception) | ✅ | | |\n| [param-name-mismatch](#hono-param-name-mismatch) | | ✅ | |\n| [no-multiple-next](#hono-no-multiple-next) | | ✅ | |\n| [no-unused-context-response](#hono-no-unused-context-response) | | ✅ | |\n| [no-process-env](#hono-no-process-env) | ✅ | | |\n| [global-middleware-placement](#hono-global-middleware-placement) | ✅ | | |\n\n### hono/route-grouping\n\nEnforce grouping and ordering of routes by HTTP method and Hono instance.\n\nThis rule enhances code organization by checking three things:\n1.  **Instance Grouping**: All route definitions for a specific Hono instance must be contiguous. Once you start defining routes for another instance, you cannot add more routes to the previous one.\n2.  **Path Grouping**: Routes for the same path (e.g., `/users`) must be grouped together.\n3.  **Method Order**: Within a path group, methods must follow a consistent order (e.g., `get` before `post`).\n\n**Note**: `app.route()` calls are excluded from these checks. Method chains (e.g., `.get(...).post(...)`) are exempt from method order checking.\n\n#### Options\n\n```json\n{\n  \"hono/route-grouping\": [\"error\", {\n    \"order\": [\n      \"use\",\n      \"all\",\n      \"get\",\n      \"post\",\n      \"put\",\n      \"patch\",\n      \"delete\",\n      \"options\",\n      \"on\"\n    ]\n  }]\n}\n```\n\n`order`: (array of strings, optional) Specifies the desired order of HTTP methods. The default order is `[\"use\", \"all\", \"get\", \"post\", \"put\", \"patch\", \"delete\", \"options\", \"on\"]`.\n\n#### Examples\n\n**Incorrect Path Grouping**\n\n```typescript\nconst app = new Hono();\napp.get('/path1', (c) =\u003e c.text('get'));\napp.get('/path2', (c) =\u003e c.text('get'));\napp.post('/path1', (c) =\u003e c.text('post'));\n```\n\n**Correct**\n\n```typescript\nconst app = new Hono();\napp.get('/path1', (c) =\u003e c.text('get'));\napp.post('/path1', (c) =\u003e c.text('post'));\napp.get('/path2', (c) =\u003e c.text('get'));\n```\n\n**Incorrect Method Order**\n\n```typescript\nconst app = new Hono();\napp.post('/path1', (c) =\u003e c.text('post'));\napp.get('/path1', (c) =\u003e c.text('get'));\n```\n\n**Correct**\n\n```typescript\nconst app = new Hono();\napp.get('/path1', (c) =\u003e c.text('get'));\napp.post('/path1', (c) =\u003e c.text('post'));\n```\n\n**Incorrect Instance Grouping**\n```typescript\nconst books = new Hono();\nconst users = new Hono();\n\nbooks.get('/books', (c) =\u003e c.text('get books'));\nusers.get('/users', (c) =\u003e c.text('get users'));\nbooks.post('/books', (c) =\u003e c.text('create book')); // Error: books routes should be together\n```\n\n**Correct**\n```typescript\nconst books = new Hono();\nconst users = new Hono();\n\nbooks.get('/books', (c) =\u003e c.text('get books'));\nbooks.post('/books', (c) =\u003e c.text('create book'));\n\nusers.get('/users', (c) =\u003e c.text('get users'));\n```\n\n### hono/prefer-http-exception\n\nSuggest using `HTTPException` instead of generic `Error` for HTTP errors.\n\nThis rule detects when a standard `Error` is thrown with a message that corresponds to a standard HTTP status code (e.g., \"Not Found\", \"Unauthorized\"). In Hono applications, it is better to use `HTTPException` to return proper HTTP status codes.\n\n#### Examples\n\n**Incorrect**\n\n```typescript\nthrow new Error('Not Found');\nthrow new Error('Unauthorized');\nthrow new Error('Bad Request');\n```\n\n**Correct**\n\n```typescript\nimport { HTTPException } from 'hono/http-exception';\n\nthrow new HTTPException(404, { message: 'Not Found' });\nthrow new HTTPException(401, { message: 'Unauthorized' });\nthrow new HTTPException(400, { message: 'Bad Request' });\n```\n\n### hono/param-name-mismatch\n\nEnsure parameter name in `c.req.param()` matches the route definition.\n\nThis rule checks that the parameter names used in `c.req.param('name')` call inside a route handler match the parameters defined in the route path (e.g., `/posts/:postId`). This prevents runtime errors caused by typos or mismatched parameter names.\n\n#### Examples\n\n**Incorrect**\n\n```typescript\nconst app = new Hono();\napp.get('/posts/:postId', (c) =\u003e {\n  const id = c.req.param('id'); // 'id' is not defined in '/posts/:postId'\n  return c.text(id);\n});\n```\n\n**Correct**\n\n```typescript\nconst app = new Hono();\napp.get('/posts/:postId', (c) =\u003e {\n  const postId = c.req.param('postId');\n  return c.text(postId);\n});\n```\n\n### hono/no-multiple-next\n\nDisallow multiple calls to `next()` in a single middleware execution path.\n\nHono middleware relies on `await next()` to pass control to the next middleware. Calling `next()` multiple times in the same middleware function will cause a runtime error (\"next() called multiple times\"). This rule detects and prevents such patterns.\n\n#### Examples\n\n**Incorrect**\n\n```typescript\nconst middleware = async (c, next) =\u003e {\n  await next();\n  await next(); // Error\n};\n```\n\n```typescript\nconst middleware = async (c, next) =\u003e {\n  if (condition) {\n    await next();\n  }\n  await next(); // Error if condition is true\n};\n```\n\n**Correct**\n\n```typescript\nconst middleware = async (c, next) =\u003e {\n  await next();\n};\n```\n\n```typescript\nconst middleware = async (c, next) =\u003e {\n  if (condition) {\n    await next();\n  } else {\n    await next();\n  }\n};\n```\n\n### hono/no-unused-context-response\n\nDisallow unused calls to Context response methods (`c.json`, `c.text`, etc.).\n\nIn Hono, methods like `c.json()` create a response object but do not send it automatically. If the return value is not returned from the handler (or awaited/used), the request might hang or result in a 404.\n\n#### Examples\n\n**Incorrect**\n\n```typescript\napp.get('/', (c) =\u003e {\n  c.json({ message: 'hello' }); // return is missing!\n});\n```\n\n**Correct**\n\n```typescript\napp.get('/', (c) =\u003e {\n  return c.json({ message: 'hello' });\n});\n```\n\n### hono/no-process-env\n\nDisallow the use of `process.env` in favor of `c.env`.\n\nThis rule enforces the use of `c.env` for accessing environment variables within Hono handlers instead of `process.env`. Using `c.env` ensures your application remains platform-agnostic, as it abstracts away environment-specific details (e.g., Cloudflare Workers bindings vs. Node.js `process.env`).\n\n#### Examples\n\n**Incorrect**\n\n```typescript\nconst app = new Hono();\napp.get('/', (c) =\u003e {\n  const apiKey = process.env.API_KEY; // Disallowed\n  return c.text(apiKey);\n});\n```\n\n**Correct**\n\n```typescript\nconst app = new Hono();\napp.get('/', (c) =\u003e {\n  const apiKey = c.env.API_KEY;\n  return c.text(apiKey);\n});\n```\n\n### hono/global-middleware-placement\n\nEnforce that global middleware is placed before route definitions.\n\nThis rule ensures that global middleware (e.g., `app.use(logger)` or `app.use('*', logger)`) is defined immediately after the Hono instance is created, and before any routes (`app.get()`, `app.post()`, etc.) are defined. This improves code readability and predictability. Path-specific middleware (e.g., `app.use('/admin/*', adminAuth)`) is ignored by this rule to allow for logical grouping with the routes it applies to.\n\n#### Examples\n\n**Incorrect**\n\n```typescript\nconst app = new Hono();\napp.get('/', (c) =\u003e c.text('Hello'));\napp.use('*', logger()); // Global middleware defined after a route.\n```\n\n**Correct**\n\n```typescript\nconst app = new Hono();\napp.use('*', logger());\napp.get('/', (c) =\u003e c.text('Hello'));\napp.use('/admin', adminOnly()); // Path-specific middleware can be defined later.\napp.get('/admin/dashboard', (c) =\u003e c.text('Dashboard'));\n```\n\n# License\n\nMade by [Kanon](https://github.com/ysknsid25). Publish under [MIT License](https://github.com/ysknsid25/eslint-plugin-citty/blob/master/LICENSE).","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fysknsid25%2Feslint-plugin-hono","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fysknsid25%2Feslint-plugin-hono","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fysknsid25%2Feslint-plugin-hono/lists"}