Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ permissions:

jobs:
lint:
name: Lint and format check
name: Lint, format, and typecheck
runs-on: ubuntu-latest
timeout-minutes: 10

Expand All @@ -28,10 +28,12 @@ jobs:
with:
bun-version: "1.3.11"
- run: bun install --frozen-lockfile
- name: ESLint
- name: Oxlint
run: bun run lint
- name: Prettier
run: bun run format:check
- name: TypeScript
run: bun run typecheck

unit:
name: Unit tests
Expand Down
343 changes: 343 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,343 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["typescript"],
"categories": {
"correctness": "off"
},
"options": {
"typeAware": true
},
"env": {
"builtin": true
},
"ignorePatterns": [
".cache/**",
".claude/**",
".tmp/**",
"build/**",
"coverage/**",
"node_modules/**",
"public/third_party/**",
"scripts/.deps/**",
"src/third_party/**"
],
"rules": {
"no-array-constructor": "error",
"no-unused-expressions": "error",
"no-unused-vars": "error",
"typescript/ban-ts-comment": "error",
"typescript/no-duplicate-enum-values": "error",
"typescript/no-empty-object-type": "error",
"typescript/no-explicit-any": "error",
"typescript/no-extra-non-null-assertion": "error",
"typescript/no-misused-new": "error",
"typescript/no-namespace": "error",
"typescript/no-non-null-asserted-optional-chain": "error",
"typescript/no-require-imports": "error",
"typescript/no-this-alias": "error",
"typescript/no-unnecessary-type-constraint": "error",
"typescript/no-unsafe-declaration-merging": "error",
"typescript/no-unsafe-function-type": "error",
"typescript/no-wrapper-object-types": "error",
"typescript/prefer-as-const": "error",
"typescript/prefer-namespace-keyword": "error",
"typescript/triple-slash-reference": "error"
},
"overrides": [
{
"files": ["**/*.{js,mjs,cjs,ts,mts,cts}"],
"rules": {
"constructor-super": "error",
"for-direction": "error",
"getter-return": "error",
"no-async-promise-executor": "error",
"no-case-declarations": "error",
"no-class-assign": "error",
"no-compare-neg-zero": "error",
"no-cond-assign": "error",
"no-const-assign": "error",
"no-constant-binary-expression": "error",
"no-constant-condition": "error",
"no-control-regex": "error",
"no-debugger": "error",
"no-delete-var": "error",
"no-dupe-class-members": "error",
"no-dupe-else-if": "error",
"no-dupe-keys": "error",
"no-duplicate-case": "error",
"no-empty": "error",
"no-empty-character-class": "error",
"no-empty-pattern": "error",
"no-empty-static-block": "error",
"no-ex-assign": "error",
"no-extra-boolean-cast": "error",
"no-fallthrough": "error",
"no-func-assign": "error",
"no-global-assign": "error",
"no-import-assign": "error",
"no-invalid-regexp": "error",
"no-irregular-whitespace": "error",
"no-loss-of-precision": "error",
"no-misleading-character-class": "error",
"no-new-native-nonconstructor": "error",
"no-nonoctal-decimal-escape": "error",
"no-obj-calls": "error",
"no-prototype-builtins": "error",
"no-redeclare": "error",
"no-regex-spaces": "error",
"no-self-assign": "error",
"no-setter-return": "error",
"no-shadow-restricted-names": "error",
"no-sparse-arrays": "error",
"no-this-before-super": "error",
"no-unassigned-vars": "error",
"no-undef": "error",
"no-unexpected-multiline": "error",
"no-unreachable": "error",
"no-unsafe-finally": "error",
"no-unsafe-negation": "error",
"no-unsafe-optional-chaining": "error",
"no-unused-labels": "error",
"no-unused-private-class-members": "error",
"no-useless-assignment": "error",
"no-useless-backreference": "error",
"no-useless-catch": "error",
"no-useless-escape": "error",
"no-with": "error",
"preserve-caught-error": "error",
"require-yield": "error",
"use-isnan": "error",
"valid-typeof": "error"
}
},
{
"files": ["**/*.ts", "**/*.tsx", "**/*.mts", "**/*.cts"],
"rules": {
"constructor-super": "off",
"getter-return": "off",
"no-class-assign": "off",
"no-const-assign": "off",
"no-dupe-class-members": "off",
"no-dupe-keys": "off",
"no-func-assign": "off",
"no-import-assign": "off",
"no-new-native-nonconstructor": "off",
"no-obj-calls": "off",
"no-redeclare": "off",
"no-setter-return": "off",
"no-this-before-super": "off",
"no-undef": "off",
"no-unreachable": "off",
"no-unsafe-negation": "off",
"no-var": "error",
"no-with": "off",
"prefer-const": "error",
"prefer-rest-params": "error",
"prefer-spread": "error"
}
},
{
"files": ["src/**/*.{ts,mts,cts,d.ts}"],
"rules": {
"typescript/await-thenable": "error",
"typescript/no-array-delete": "error",
"typescript/no-base-to-string": "error",
"typescript/no-duplicate-type-constituents": "error",
"typescript/no-floating-promises": "error",
"typescript/no-for-in-array": "error",
"typescript/no-implied-eval": "error",
"typescript/no-misused-promises": "error",
"typescript/no-redundant-type-constituents": "error",
"typescript/no-unnecessary-type-assertion": "error",
"typescript/no-unsafe-argument": "error",
"typescript/no-unsafe-assignment": "error",
"typescript/no-unsafe-call": "error",
"typescript/no-unsafe-enum-comparison": "error",
"typescript/no-unsafe-member-access": "error",
"typescript/no-unsafe-return": "error",
"typescript/no-unsafe-unary-minus": "error",
"typescript/only-throw-error": "error",
"typescript/prefer-promise-reject-errors": "error",
"typescript/require-await": "error",
"typescript/restrict-plus-operands": "error",
"typescript/restrict-template-expressions": "error",
"typescript/unbound-method": "error"
}
},
{
"files": ["src/**/*.{js,mjs,cjs,ts,mts,cts,d.ts}"],
"env": {
"browser": true,
"webextensions": true
}
},
{
"files": ["tests/**/*.{js,mjs,cjs,ts,mts,cts}"],
"globals": {
"BuildError": "readonly",
"BuildMessage": "readonly",
"Bun": "readonly",
"HTMLRewriter": "readonly",
"Loader": "readonly",
"ResolveError": "readonly",
"ResolveMessage": "readonly",
"ShadowRealm": "readonly"
},
"env": {
"browser": true,
"jest": true,
"node": true,
"webextensions": true
}
},
{
"files": ["build.ts", "scripts/**/*.{js,mjs,cjs,ts,mts,cts}"],
"globals": {
"addEventListener": "readonly",
"alert": "readonly",
"BuildError": "readonly",
"BuildMessage": "readonly",
"Bun": "readonly",
"confirm": "readonly",
"dispatchEvent": "readonly",
"HTMLRewriter": "readonly",
"Loader": "readonly",
"onerror": "writable",
"onmessage": "writable",
"PerformanceServerTiming": "readonly",
"PerformanceTiming": "readonly",
"postMessage": "readonly",
"prompt": "readonly",
"removeEventListener": "readonly",
"reportError": "readonly",
"ResolveError": "readonly",
"ResolveMessage": "readonly",
"self": "readonly",
"ShadowRealm": "readonly",
"Worker": "readonly"
},
"env": {
"node": true
}
},
{
"files": ["scripts/**/*.cjs"],
"rules": {
"prefer-template": "off",
"typescript/no-require-imports": "off"
}
},
{
"files": ["src/**/*.{ts,mts,cts,d.ts}"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["src/background/*", "src/content-script/*", "src/shared/*"],
"message": "Legacy module roots are deprecated. Import from @core, @adapters, or @ui."
}
]
}
]
}
},
{
"files": ["src/core/domain/**/*.{ts,mts,cts,d.ts}"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["@core/application/*", "@adapters/*", "@ui/*"],
"message": "Domain must not depend on application, adapters, or UI."
}
]
}
]
}
},
{
"files": ["src/core/application/**/*.{ts,mts,cts,d.ts}"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["@adapters/*", "@ui/*"],
"message": "Application must not depend on adapters or UI."
}
]
}
]
}
},
{
"files": ["src/adapters/chrome/**/*.{ts,mts,cts,d.ts}"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["@ui/*"],
"message": "Adapters must not depend on UI."
}
]
}
]
}
},
{
"files": ["src/adapters/chrome/background/**/*.{ts,mts,cts,d.ts}"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["@adapters/chrome/content-script/*"],
"message": "Background adapter must not import content-script modules directly."
}
]
}
]
}
},
{
"files": ["src/adapters/chrome/content-script/**/*.{ts,mts,cts,d.ts}"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["@adapters/chrome/background/*"],
"message": "Content-script adapter must not import background modules directly."
}
]
}
]
}
},
{
"files": ["src/ui/**/*.{ts,mts,cts,d.ts}"],
"rules": {
"no-restricted-imports": [
"error",
{
"patterns": [
{
"group": ["@adapters/chrome/background/*", "@adapters/chrome/content-script/*"],
"message": "UI modules must not depend on adapter internals."
}
]
}
]
}
}
]
}
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ Additionally, background and content-script are isolated from each other:
- `src/adapters/chrome/background/` must not import from `content-script/`
- `src/adapters/chrome/content-script/` must not import from `background/`

These boundaries are enforced by ESLint `no-restricted-imports` rules.
These boundaries are enforced by Oxlint `no-restricted-imports` rules.

### Entry Points

Expand Down
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,8 +113,8 @@ bun run build --platform=firefox

```bash
bun run check # lint + format + typecheck
bun run lint # ESLint only
bun run typecheck # TypeScript only
bun run lint # Oxlint with TypeScript-aware rules
bun run typecheck # TypeScript 7 only
bun run format:check # Prettier only
```

Expand Down Expand Up @@ -153,7 +153,7 @@ src/
onboarding/ # First-run experience
```

Layer boundaries are enforced by ESLint `no-restricted-imports` rules. See [docs/agents/architecture.md](docs/agents/architecture.md) for details.
Layer boundaries are enforced by Oxlint `no-restricted-imports` rules. See [docs/agents/architecture.md](docs/agents/architecture.md) for details.

## Bug Reporting

Expand Down
Loading
Loading