{"_id":"@021.is/spine-lint","_rev":"3-db49aeb09e2ae690c5e71d5223d0bff9","name":"@021.is/spine-lint","dist-tags":{"latest":"0.4.4"},"versions":{"0.4.2":{"name":"@021.is/spine-lint","version":"0.4.2","license":"MIT","_id":"@021.is/spine-lint@0.4.2","maintainers":[{"name":"edvone","email":"edvard@edvone.dev"}],"homepage":"https://github.com/021is/spine-ts#readme","bugs":{"url":"https://github.com/021is/spine-ts/issues"},"bin":{"spine-lint":"dist/bin.js"},"dist":{"shasum":"8204739530f16637e41bebf52afe1ffa493881e1","tarball":"https://registry.npmjs.org/@021.is/spine-lint/-/spine-lint-0.4.2.tgz","fileCount":7,"integrity":"sha512-PvCsvq7VZhnvNF89VeB1BFlJtLTFAMdsT9S5nMgHmTJTNil5BMTZKMVidN6n//rJkViSXglhEAN2TSFJ+Gxn7Q==","signatures":[{"sig":"MEQCIDJkNpuLiWQ8xmM5Drb9bm4IVb3N4UJ3v23TOmtxm6U/AiARrZIjuKAJ8zvgAZg/uhlHrhq846MgX/JKrRc8TcbQAg==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":23476},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"e4434c6f59db8f586e0f05ffdb3b88a96e68e67b","scripts":{"build":"tsup src/index.ts src/bin.ts --format esm --dts --clean","typecheck":"tsc --noEmit"},"_npmUser":{"name":"edvone","email":"edvard@edvone.dev"},"repository":{"url":"git+https://github.com/021is/spine-ts.git","type":"git","directory":"packages/lint"},"_npmVersion":"10.9.4","description":"Spine-specific AST checks that biome can't express: enum-over-string, ResponseDto enforcement, endpoint documentation, i18n key parity, no raw SQL. Runs in CI as the spine-lint job + locally via `spine-lint .`.","directories":{},"_nodeVersion":"22.22.0","dependencies":{"cac":"^6.7.14","kleur":"^4.1.5","fast-glob":"^3.3.2","@typescript-eslint/typescript-estree":"^8.10.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/spine-lint_0.4.2_1779981958938_0.779291879978105","host":"s3://npm-registry-packages-npm-production"}},"0.4.3":{"name":"@021.is/spine-lint","version":"0.4.3","license":"MIT","_id":"@021.is/spine-lint@0.4.3","maintainers":[{"name":"edvone","email":"edvard@edvone.dev"}],"homepage":"https://github.com/021is/spine-ts#readme","bugs":{"url":"https://github.com/021is/spine-ts/issues"},"bin":{"spine-lint":"dist/bin.js"},"dist":{"shasum":"84fced3237640b4acc02b201db0a3e8fbdc3a45a","tarball":"https://registry.npmjs.org/@021.is/spine-lint/-/spine-lint-0.4.3.tgz","fileCount":8,"integrity":"sha512-/uEQt2LBTmspOjM9DmRU4TpRT0rw649d3d/HjjVjEDDwRcl9iZpEYKoX0nnVUefGKD4ui1I/81E4D9KyX61YOg==","signatures":[{"sig":"MEUCIF2hMc6HSo5f2rLGnvDsf8kYmT5DDqU+IKAafId9vZtsAiEAzIuBf0zc4rUhESviEKSQbWF1xpFDPvf0AGTx8y94ldU=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":25100},"main":"./dist/index.js","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"b9f9333776fa55686cc2feb05f851aa6000b0e05","scripts":{"build":"tsup src/index.ts src/bin.ts --format esm --dts --clean","typecheck":"tsc --noEmit"},"_npmUser":{"name":"edvone","email":"edvard@edvone.dev"},"repository":{"url":"git+https://github.com/021is/spine-ts.git","type":"git","directory":"packages/lint"},"_npmVersion":"10.9.4","description":"Spine-specific AST checks that biome can't express: enum-over-string, ResponseDto enforcement, endpoint documentation, i18n key parity, no raw SQL. Runs in CI as the spine-lint job + locally via `spine-lint .`.","directories":{},"_nodeVersion":"22.22.0","dependencies":{"cac":"^6.7.14","kleur":"^4.1.5","fast-glob":"^3.3.2","@typescript-eslint/typescript-estree":"^8.10.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"tmp":"tmp/spine-lint_0.4.3_1779995247079_0.5921410931219082","host":"s3://npm-registry-packages-npm-production"}},"0.4.4":{"_id":"@021.is/spine-lint@0.4.4","bin":{"spine-lint":"dist/bin.js"},"bugs":{"url":"https://github.com/021is/spine-ts/issues"},"dist":{"shasum":"2d4acd587aff3af028be2229d7edf97b52282e68","tarball":"https://registry.npmjs.org/@021.is/spine-lint/-/spine-lint-0.4.4.tgz","fileCount":8,"integrity":"sha512-SMF0VHS/T4FkOgH/1+30gt09I6UAqJoAasCj43IBkUB2cWWikt24F0bCaGhpEOz5EWjXOmhzq6SlTJ3ZDtPeFg==","signatures":[{"sig":"MEUCIG7JVbwswKOQNGVobBs5NwQ7LyMt/O9EahOSXA/+cUs3AiEApaY58HNovIFLMYoBmSUuv5pFGcHhSr4EVFf66G75eCI=","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"},{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEYCIQCnxKBKVyquw5sSI9PfSxotEPO05hecytTqE200FyQsDAIhAK9jwDky2gJwaoiEjPJKaVL4Tr8dmSqkAAIvSnjbCsyS"}],"attestations":{"url":"https://registry.npmjs.org/-/npm/v1/attestations/@021.is%2fspine-lint@0.4.4","provenance":{"predicateType":"https://slsa.dev/provenance/v1"}},"unpackedSize":25704},"main":"./dist/index.js","name":"@021.is/spine-lint","type":"module","types":"./dist/index.d.ts","exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"b8f2080ba21928b558d6a8b8a6b6f2fccf1bd3dd","license":"MIT","scripts":{"build":"tsup src/index.ts src/bin.ts --format esm --dts --clean","typecheck":"tsc --noEmit"},"version":"0.4.4","_npmUser":{"name":"edvone","email":"edvard@edvone.dev"},"homepage":"https://github.com/021is/spine-ts#readme","repository":{"url":"git+https://github.com/021is/spine-ts.git","type":"git","directory":"packages/lint"},"_npmVersion":"10.9.9","description":"Spine-specific AST checks that biome can't express: enum-over-string, ResponseDto enforcement, endpoint documentation, i18n key parity, no raw SQL. Runs in CI as the spine-lint job + locally via `spine-lint .`.","directories":{},"maintainers":[{"name":"edvone","email":"edvard@edvone.dev"}],"_nodeVersion":"22.23.3","dependencies":{"cac":"^6.7.14","kleur":"^4.1.5","fast-glob":"^3.3.2","@typescript-eslint/typescript-estree":"^8.10.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/spine-lint_0.4.4_1790886051550_0.6252401210466891"}}},"time":{"created":"2026-05-28T15:25:58.762Z","modified":"2026-10-01T20:20:52.094Z","0.4.2":"2026-05-28T15:25:59.104Z","0.4.3":"2026-05-28T19:07:27.238Z","0.4.4":"2026-10-01T20:20:51.657Z"},"bugs":{"url":"https://github.com/021is/spine-ts/issues"},"license":"MIT","homepage":"https://github.com/021is/spine-ts#readme","repository":{"url":"git+https://github.com/021is/spine-ts.git","type":"git","directory":"packages/lint"},"description":"Spine-specific AST checks that biome can't express: enum-over-string, ResponseDto enforcement, endpoint documentation, i18n key parity, no raw SQL. Runs in CI as the spine-lint job + locally via `spine-lint .`.","maintainers":[{"name":"edvone","email":"edvard@edvone.dev"}],"readme":"# @021.is/spine-lint\n\nSpine-specific AST checks that biome can't express. Runs in CI as the `spine-lint` job in the quality gate; also runs locally via `spine-lint .`.\n\n## Rules\n\n| Rule | Severity | What |\n|---|---|---|\n| `spine/enum-over-string` | error / warning | Forbids inline string-literal unions (`: \"a\" \\| \"b\" \\| \"c\"`). Warns on repeated string-literal comparisons (`x === \"foo\"` ≥2 times). Locked. |\n| `spine/route-returns-response-dto` | error | Every Next.js route handler must go through `withErrorHandling` from `@021.is/spine-errors/next` OR explicitly call `ok()` / `err()`. |\n| `spine/endpoint-documented` | warning | Every route handler must have a JSDoc block above it. |\n| `spine/i18n-key-parity` | error | Every `t(\"namespace.key\")` exists in every locale catalog under `src/i18n/`. Prevents the silent UX bug where production renders raw keys in foreign locales. |\n| `spine/no-raw-sql` | error | Blocks `$queryRawUnsafe` / `$executeRawUnsafe`. Use Prisma or `$queryRaw\\`…\\`` tagged-template. |\n\n## CLI\n\n```bash\nspine-lint .                           # run all rules on src/**\nspine-lint src/feature/event          # narrow to one path\nspine-lint --rule spine/enum-over-string .\nspine-lint --github .                   # emit GitHub Actions annotations\nspine-lint --list-rules\n```\n\nExit code 1 on any error-level violation. Used as a required check in the spine-quality-gate workflow.\n\n## Disabling for a single line\n\n```ts\n// spine-lint-disable-next-line spine/no-raw-sql — needed for the pg_stat query\nawait prisma.$queryRawUnsafe(`SELECT * FROM pg_stat_activity`);\n```\n\n(Disables ALL rules on the next line if no rule id given.) **You must always include the WHY comment.** PR reviewers + future-you will look there first.\n\n## Enum pattern (the rule you'll hit most)\n\n```ts\n// ❌ inline union\nfunction setStatus(s: \"active\" | \"inactive\" | \"deleted\") { ... }\n\n// ✓ const-as-object enum\nexport const STATUS = { ACTIVE: \"active\", INACTIVE: \"inactive\", DELETED: \"deleted\" } as const;\nexport type Status = (typeof STATUS)[keyof typeof STATUS];\n\nfunction setStatus(s: Status) { ... }\n```\n\nWhy const-as-object instead of `enum`:\n- Tree-shakable (TS `enum` compiles to runtime objects).\n- Pure values; no class machinery.\n- Plays nice with `as const` and `Object.values()`.\n- Industry standard (TanStack, Next.js codebase, Vercel SDK).\n","readmeFilename":"README.md"}