@visorian/code-standards
v0.7.0
Published
Shared oxlint, oxfmt, ESLint (Vue), commitlint, lefthook and TypeScript settings for Visorian projects
Readme
@visorian/code-standards
Shared lint, format, commit and TypeScript settings for Visorian projects. Repositories import small factories instead of copying config files, so a rule change is one release of this package.
| Entry point | What it provides |
| ----------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| @visorian/code-standards/oxlint | defineOxlintConfig(): the strict oxlint baseline (type-aware, type check, e18e, Nuxt and anti-slop rules) |
| @visorian/code-standards/eslint | defineVueEslintConfig(): Vue templates and Nuxt auto-import checks; other script rules come from oxlint |
| @visorian/code-standards/oxfmt | defineOxfmtConfig(): formatter settings |
| @visorian/code-standards/commitlint | defineCommitlintConfig(): conventional commits with optional scopes |
| @visorian/code-standards/nuxt | Nuxt module applying strict compiler options and checking framework configuration |
| @visorian/code-standards/compiler-options | strictCompilerOptions for Nitro-only apps |
| @visorian/code-standards/tsconfig/strict.json | extends target for plain TypeScript packages |
| @visorian/code-standards/lefthook.yml | Shared git hooks (format, lint, commitlint, Vue typecheck where defined) |
| .github/workflows/quality.yml | Reusable CI job: format check, lint, Vue typecheck where defined, optional tests |
Type checking
oxlint is the type checker. defineOxlintConfig() enables typeAware and typeCheck, so one oxlint
run reports TypeScript compiler errors (typescript(TSxxxx)) next to the type-aware rules, using the
TypeScript 7 checker from oxlint-tsgolint and each file's nearest tsconfig.json. We treat
typeCheck as stable.
| Command | Checks | Where |
| ------------------------------------------ | ------------------------------------------------------------------------------------------- | --------------------------------------- |
| lint (oxlint) | Compiler errors and type-aware rules for all .ts/.mts files (JavaScript with checkJs) | Every repository |
| typecheck (nuxt typecheck / vue-tsc) | .vue files, including templates, which oxlint skips | Only Nuxt and Vue projects |
| tsc | Nothing extra: only emits dist and .d.ts | Only packages that publish build output |
- Don't add
tsc --noEmitscripts; they repeat whatlintalready reports. Hooks and the reusable workflow runbun run --if-present typecheck, so repositories without Vue simply don't define it. - oxlint only type-checks files it lints. Every source, test, script and config file must be inside
the lint scope, and each must belong to a
tsconfig.json(otherwise TypeScript falls back to an inferred project without the strict options). Keepignorepatterns to generated output. - Types from other workspaces that are consumed as build output (
dist/*.d.ts) must be built before linting.
Requirements
The setup targets Bun-managed TypeScript projects: the hooks and the reusable workflow call bun/bunx.
- Node 22.18 or newer: TypeScript config files and the lint plugins load through Node type stripping.
typescript-native-bridgeships native binaries for macOS, Windows and glibc Linux (glibc 2.35 or newer). Alpine/musl is not supported, so run typecheck and lint in a glibc image (for examplenode:24-bookworm-slimoroven/bun) and only deploy from Alpine. Plain TypeScript packages that don't needvue-tscor@typescript-eslint/parsercan installtypescript@7directly instead.- The Vitest rules only report in files that use Vitest; they don't require it.
Installation
The package is published on npm:
bun add --dev @visorian/code-standardsThe source repository and the reusable workflow stay internal to the Visorian organization.
Updating: read the changelog, then bump the version in package.json and in the
reusable workflow reference. Coming from the git+ssh tags (0.3.0 and older): replace the git spec
with a version range and drop the git-token secret from the reusable workflow call, unless the
repository has other private git dependencies.
Setup in a repository
Tool binaries have to be direct dependencies, and the TypeScript override only works in the root
package.json:
{
"scripts": {
"lint": "bun run lint:ox && bun run lint:vue",
"lint:ox": "oxlint",
"lint:vue": "eslint --max-warnings 0 --cache --cache-location node_modules/.cache/eslint/ '**/*.vue'",
"fmt": "oxfmt",
"fmt:check": "oxfmt --check",
"typecheck": "nuxt typecheck",
"prepare": "if git rev-parse --git-dir >/dev/null 2>&1; then lefthook install; fi"
},
"devDependencies": {
"@commitlint/cli": "^21.2.3",
"eslint": "^10.11.0",
"lefthook": "^2.1.14",
"oxfmt": "^0.73.0",
"oxlint": "1.88.0",
"oxlint-tsgolint": "^7.0.2003",
"typescript": "npm:[email protected]",
"vue-tsc": "^3.3.11"
},
"overrides": {
"typescript": "npm:[email protected]"
}
}typescript-native-bridge runs the TypeScript 7 checker behind the classic TypeScript API, which
vue-tsc and @typescript-eslint/parser still need.
oxlint.config.ts:
import { defineOxlintConfig } from '@visorian/code-standards/oxlint'
export default defineOxlintConfig({
nuxt: true, // @nuxt/eslint-plugin rules and nuxt.config overrides (default: true)
vue: true, // vue plugin rules for <script> blocks (default: true)
tests: ['test/**', 'e2e/**'], // relaxed rules for tests
ignore: ['infrastructure/azuredeploy.json'],
})Plain TypeScript projects (no Nuxt, no Vue) switch both off, skip ESLint, use lint: "oxlint"
without a typecheck script and a tsconfig.json that extends the shared strict set:
export default defineOxlintConfig({ nuxt: false, vue: false }){ "extends": "@visorian/code-standards/tsconfig/strict.json" }eslint.config.mjs (Vue projects only):
import { defineVueEslintConfig } from '@visorian/code-standards/eslint'
import oxlint from './oxlint.config.ts'
export default defineVueEslintConfig({ oxlint })oxfmt.config.ts:
import { defineOxfmtConfig } from '@visorian/code-standards/oxfmt'
export default defineOxfmtConfig({ tailwindStylesheet: './app/assets/css/main.css' })commitlint.config.mjs:
import { defineCommitlintConfig } from '@visorian/code-standards/commitlint'
export default defineCommitlintConfig({
scopes: ['frontend', 'backend', 'docs', 'deps', 'config', 'ci'],
})lefthook.yml:
extends:
- node_modules/@visorian/code-standards/lefthook.ymlnuxt.config.ts:
export default defineNuxtConfig({
modules: ['@visorian/code-standards/nuxt'],
// Optional: codeStandards: { compilerOptions: { … }, vueShim: true },
})The Nuxt module checks the resolved configuration after modules are installed, including values
inherited from layers. Checks run during nuxt dev, nuxt prepare and nuxt build. They print
warnings without changing settings or failing the command.
nuxt/future-compatibilityexpectsfuture.compatibilityVersion: 5when running Nuxt 4.nuxt-ui/component-detectionexpectsui.experimental.componentDetection: truewhen@nuxt/uiis used. This checks for exactlytrue; component-name arrays also produce a warning.
Both checks are enabled by default. Disable individual checks by name:
export default defineNuxtConfig({
modules: ['@visorian/code-standards/nuxt'],
codeStandards: {
checks: {
'nuxt/future-compatibility': false,
},
},
})Set codeStandards: { checks: false } to disable all configuration checks, including future ones.
Both forms keep the compiler settings and Vue shim option working, even in projects using Nuxt UI.
Nuxt UI remains optional.
.github/workflows/ci.yml:
jobs:
quality:
uses: Visorian/code-standards/.github/workflows/[email protected]
with:
prepare: bunx nuxt prepare
test: bun run test:unitLegacy debt
Fix findings instead of budgeting them. debt is a last resort for findings that cannot be fixed
yet, for example while a large codebase adopts the standard; it is not a baseline to start from.
debt: { rules, maxWarnings } lowers the listed rules to warn and keeps their options, and
maxWarnings replaces denyWarnings, so lint fails as soon as the warning count grows. Lower the
number with every fix and remove debt once the repository is clean. For a single deliberate
exception, a one-line oxlint-disable-next-line <rule> -- <reason> is the narrower tool. Test,
script and .vue overrides still apply on top of debt.
Changing the standards
- Add Nuxt configuration checks to
configChecksinsrc/nuxt-checks.ts, with a stable name, an actionable message and ashouldWarnpredicate. The accepted option names come from this list. - Any change that can produce new diagnostics (a new rule, a stricter option, a newly enabled
category) is a major release. Lint warnings fail lint just like errors (
denyWarnings, or the exactdebt.maxWarningsbudget), so a lint rule'swarnseverity is not a migration period. Repositories adopt lint changes by fixing the findings;debtis only for findings that cannot be fixed yet. Nuxt configuration warnings remain advisory and can be disabled throughcodeStandards.checks. oxlintand@oxlint/pluginsmust stay on the same exact version (the vendored anti-slop plugin depends on it), so they are bumped together here and in every consumer.- The anti-slop subset is vendored from upstream, see
src/anti-slop/UPSTREAM.md.
Releasing
Release Please keeps a chore(release): v… pull
request open that bumps the version and updates the changelog from the conventional
commits on main. Merging it runs the quality gate, stages the version on npm through trusted
publishing, tags the merge commit (v0.4.0) and creates the GitHub release. The staged version stays
private until a maintainer approves it with 2FA:
npm stage list @visorian/code-standards
npm stage approve <stage-id> # or `npm stage reject <stage-id>`The npm trust relationship for release-please.yml only allows npm stage publish, so the workflow
can't publish on its own. If a release job fails, re-run the failed jobs of that run; each step skips
work that is already done.
npm can't stage a package that doesn't exist yet, so 0.3.0 was published by hand
(bun install --frozen-lockfile && npm publish --ignore-scripts) before the first staged release. Git
tags before v0.4.0 contain the built package for the old git+ssh installs.
Development
bun install # also builds dist and installs the git hooks
bun run lint # the package lints and type-checks itself from source
bun run build # also type-checks the vendored anti-slop plugin while emitting it
bun run test # runs oxlint, ESLint, commitlint and `nuxt prepare` against fixturesRequires Node 22.18 or newer (TypeScript config files and plugins load through Node type stripping).
