Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
f565cea
Emit Oxlint suppressions from generated code
dahlia Nov 2, 2026
d17936d
Add an Oxlint configuration mirroring deno lint
dahlia Nov 2, 2026
d00db68
Run repository linting with Oxlint
dahlia Nov 2, 2026
b96c6a3
Warn on awaited operations inside loops
dahlia Nov 2, 2026
0ca44c7
Keep directive audit independent of Git hooks
dahlia Nov 2, 2026
2207c66
Warn on console calls outside the CLI
dahlia Nov 2, 2026
cc5bee3
Vendor anti-slop and enable its low-risk rules
dahlia Nov 2, 2026
409c969
Recognize eslint directives in lint audit
dahlia Nov 2, 2026
3cb41c7
Enable promise/no-nesting and fix upstream lint
dahlia Nov 2, 2026
c92b6ae
Enable promise/no-return-wrap
dahlia Nov 2, 2026
a88368d
Enable eslint/no-throw-literal
dahlia Nov 3, 2026
dbcf757
Enable eslint/no-unsafe-optional-chaining
dahlia Nov 3, 2026
fbec4d0
Enable eslint/no-self-compare
dahlia Nov 3, 2026
aad3c9e
Enable eslint/no-useless-escape
dahlia Nov 3, 2026
2ded180
Enable unicorn/prefer-node-protocol
dahlia Nov 3, 2026
2c5e43e
Enable unicorn/prefer-includes
dahlia Nov 3, 2026
357151d
Enable unicorn/error-message
dahlia Nov 3, 2026
a624ff0
Sync Deno import maps with Oxlint 1.90.0
dahlia Nov 3, 2026
a73fe5a
Enable unicorn/no-array-for-each
dahlia Nov 3, 2026
0b40ce3
Enable typescript/no-import-type-side-effects
dahlia Nov 3, 2026
f6d5681
Enable typescript/prefer-for-of
dahlia Nov 3, 2026
73cc2de
Enable typescript/no-extraneous-class
dahlia Nov 3, 2026
7e6f446
Add LogTape lint rules and align versions
dahlia Nov 3, 2026
f4006f4
Cover TypeScript getter returns in Oxlint
dahlia Nov 5, 2026
b3d4ba7
Assert formatted benchmark warning text
dahlia Nov 6, 2026
7c65b08
Audit non-ASCII paths in lint directives
dahlia Nov 6, 2026
091a156
Avoid leaking type substitutions into alias bodies
dahlia Nov 6, 2026
2ca1294
Build lint plugin before Deno tests
dahlia Nov 6, 2026
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
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
]
},
"tasks": {
"check": "deno fmt --check && deno lint && deno check src/*.ts",
"check": "deno fmt --check && deno check src/*.ts",
"test": "deno test" // Add if --allow-* for permissions is needed
}
}
1 change: 1 addition & 0 deletions .devcontainer/devcontainer.json
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
"vscode": {
"extensions": [
"denoland.vscode-deno",
"oxc.oxc-vscode",
"redhat.vscode-yaml",
"streetsidesoftware.code-spell-checker"
]
Expand Down
1 change: 1 addition & 0 deletions .hongdown.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ exclude = [
"WARP.md",
"changes.d/**",
"packages/fedify/src/cfworkers/**",
"tools/oxlint/anti-slop/**",
"plan.md",
"**/plans/**",
]
Expand Down
249 changes: 249 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,249 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": [
"typescript",
"react",
"unicorn",
"oxc",
"import",
"promise",
"vitest",
"jsx-a11y"
],
"categories": {
"correctness": "off",
"suspicious": "off",
"pedantic": "off",
"perf": "off",
"style": "off",
"restriction": "off",
"nursery": "off"
},
"options": {
"reportUnusedDisableDirectives": "error"
},
"jsPlugins": [
{
"name": "anti-slop",
"specifier": "./tools/oxlint/anti-slop/index.ts"
},
{
"name": "@logtape",
"specifier": "@logtape/lint/eslint"
}
],
"overrides": [
{
"files": [
"packages/cli/**"
],
"rules": {
"eslint/no-console": "off"
}
},
{
"files": [
"examples/fresh/**"
],
"rules": {
"react/no-danger": "error",
"react/no-danger-with-children": "error",
"react/rules-of-hooks": "error"
}
}
],
"rules": {
"typescript/adjacent-overload-signatures": "error",
"typescript/ban-ts-comment": [
"error",
{
"ts-check": false,
"ts-expect-error": "allow-with-description",
"ts-ignore": "allow-with-description",
"ts-nocheck": "allow-with-description",
"minimumDescriptionLength": 1
}
],
"typescript/no-wrapper-object-types": "error",
"typescript/no-unsafe-function-type": "error",
"eslint/constructor-super": "error",
"eslint/for-direction": "error",
"eslint/getter-return": "error",
Comment thread
dahlia marked this conversation as resolved.
Resolved
"react/jsx-boolean-value": "error",
"react/button-has-type": "error",
"react/jsx-curly-brace-presence": [
"error",
{
"propElementValues": "always"
}
],
"react/jsx-key": [
"error",
{
"checkKeyMustBeforeSpread": false
}
],
"react/no-children-prop": "error",
"react/jsx-no-comment-textnodes": "error",
"react/jsx-no-duplicate-props": "error",
"react/no-unescaped-entities": "error",
"react/jsx-no-useless-fragment": "error",
"react/jsx-props-no-spread-multi": "error",
"react/void-dom-elements-no-children": "error",
"eslint/no-array-constructor": "error",
"eslint/no-async-promise-executor": "error",
"eslint/no-await-in-loop": "warn",
"eslint/no-case-declarations": "error",
"eslint/no-class-assign": "error",
"eslint/no-compare-neg-zero": "error",
"eslint/no-cond-assign": "error",
"eslint/no-console": "warn",
"eslint/no-const-assign": "error",
"eslint/no-constant-condition": [
"error",
{
"checkLoops": false
}
],
"eslint/no-control-regex": "error",
"eslint/no-debugger": "error",
"eslint/no-delete-var": "error",
"eslint/no-dupe-class-members": "error",
"eslint/no-dupe-else-if": "error",
"eslint/no-dupe-keys": "error",
"eslint/no-duplicate-case": "error",
"eslint/no-empty": "error",
"eslint/no-empty-character-class": "error",
"typescript/no-empty-interface": [
"error",
{
"allowSingleExtends": true
}
],
"typescript/no-empty-object-type": [
"error",
{
"allowInterfaces": "always"
}
],
"eslint/no-empty-pattern": "error",
"eslint/no-ex-assign": "error",
"typescript/no-explicit-any": "error",
"eslint/no-extra-boolean-cast": "error",
"typescript/no-extra-non-null-assertion": "error",
"eslint/no-fallthrough": "error",
"eslint/no-func-assign": "error",
"eslint/no-global-assign": "error",
"eslint/no-import-assign": "error",
"eslint/no-inner-declarations": "error",
"eslint/no-invalid-regexp": "error",
"eslint/no-irregular-whitespace": "error",
"typescript/no-misused-new": "error",
"typescript/no-namespace": "error",
"eslint/no-new-native-nonconstructor": "error",
"eslint/no-obj-calls": "error",
"eslint/no-prototype-builtins": "error",
"eslint/no-redeclare": "error",
"eslint/no-regex-spaces": "error",
"eslint/no-self-assign": "error",
"eslint/no-setter-return": "error",
"eslint/no-shadow-restricted-names": "error",
"typescript/no-this-alias": "error",
"eslint/no-this-before-super": "error",
"eslint/no-unreachable": "error",
"eslint/no-unsafe-finally": "error",
"eslint/no-unsafe-negation": "error",
"eslint/no-unused-labels": "error",
"eslint/no-unused-vars": [
"error",
{
"args": "all",
"argsIgnorePattern": "^_",
"caughtErrors": "all",
"caughtErrorsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"varsIgnorePattern": "^_"
}
],
"eslint/no-var": "error",
"eslint/no-with": "error",
"typescript/prefer-as-const": "error",
"eslint/prefer-const": [
"error",
{
"destructuring": "all"
}
],
"typescript/prefer-namespace-keyword": "error",
"eslint/require-await": "error",
"eslint/require-yield": "error",
"eslint/use-isnan": "error",
"eslint/valid-typeof": "error",
"oxc/no-accumulating-spread": "error",
"anti-slop/no-module-mocking": "error",
"anti-slop/no-reduce-accumulator-copy": "error",
"anti-slop/no-unknown-type-aliases": "error",
"anti-slop/no-widen-then-assert": "error",
"anti-slop/no-array-filter-map": "error",
"anti-slop/no-reflect-get": "error",
"anti-slop/no-reflect-apply": "error",
"import/no-duplicates": "error",
"promise/no-nesting": "error",
"promise/no-return-wrap": "error",
"eslint/no-throw-literal": "error",
"eslint/no-unsafe-optional-chaining": "error",
"eslint/no-self-compare": "error",
"eslint/no-useless-escape": "error",
"unicorn/prefer-node-protocol": "error",
"unicorn/prefer-includes": "error",
"unicorn/error-message": "error",
"unicorn/no-array-for-each": "error",
"typescript/no-import-type-side-effects": "error",
"typescript/prefer-for-of": "error",
"typescript/no-extraneous-class": "error",
"@logtape/no-message-interpolation": "error",
"@logtape/prefer-lazy-evaluation": "warn",
"@logtape/no-unawaited-log": "error",
"@logtape/require-meta-sink": "warn",
"eslint/no-useless-return": "error"
},
"ignorePatterns": [
"**/pnpm-lock.yaml",
"pnpm-workspace.yaml",
".agents/skills/**",
".claude/skills/**",
".claude-plugin/**",
".github/**",
"claude-plugin/**",
"docs/**",
"**/*.md",
"**/*.html",
"**/*.svg",
"**/*.astro",
"**/*.svelte",
"**/*.vue",
"**/*.css",
"examples/cloudflare-workers/worker-configuration.d.ts",
"packages/cli/src/init/templates/**",
"packages/init/src/templates/**",
"packages/cfworkers/test/**",
"packages/fedify/src/cfworkers/dist/**",
"packages/fedify/src/cfworkers/fixtures/**",
"packages/fedify/src/cfworkers/imports.ts",
"packages/fedify/src/cfworkers/server.ts",
"packages/fedify/src/cfworkers/runner.ts",
"packages/fedify/src/cfworkers/selftest.ts",
"packages/fedify/src/cfworkers/server.js",
"packages/fedify/src/cfworkers/server.js.map",
"packages/sqlite/src/sqlite.bun.ts",
"examples/fresh/_fresh/**",
"examples/astro/.astro/**",
"**/dist/**",
"**/dist-tests/**",
"**/node_modules/**",
"**/npm/**",
"**/apidoc/**",
"**/*.test-report.xml",
"tools/oxlint/anti-slop/**"
]
}
1 change: 1 addition & 0 deletions .vscode/extensions.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
{
"recommendations": [
"denoland.vscode-deno",
"oxc.oxc-vscode",
"redhat.vscode-yaml",
"streetsidesoftware.code-spell-checker"
]
Expand Down
1 change: 1 addition & 0 deletions .vscode/settings.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
{
"deno.enable": true,
"deno.lint": false,
"deno.unstable": true,
"editor.detectIndentation": false,
"editor.indentSize": 2,
Expand Down
1 change: 1 addition & 0 deletions .zed/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
"settings": {
"deno": {
"enable": true,
"lint": false,
"unstable": true
}
}
Expand Down
27 changes: 23 additions & 4 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,8 @@ Development environment
-----------------------

Fedify is a TypeScript monorepo. Node.js runs dependency installation, code
generation, builds, type checking, maintenance scripts, and test harnesses.
Formatting, linting, and the local CLI still use Deno. Supported packages
generation, builds, type checking, maintenance scripts, test harnesses, and
linting. Formatting and the local CLI still use Deno. Supported packages
are tested on Deno, Node.js, and Bun. [mise] installs the required tool
versions and runs repository tasks. Install mise before bootstrapping; it
provisions Node.js and the tools declared in *mise.toml*, so Node.js needs no
Expand All @@ -135,8 +135,8 @@ Install or refresh the pre-commit hook explicitly with

To bootstrap without installing Deno, set `MISE_DISABLE_TOOLS=deno` before
running `mise install` (for example, `$env:MISE_DISABLE_TOOLS = "deno"` in
PowerShell). Deno is still needed for the current formatting, linting, and
Deno compatibility tasks; those tools are being migrated separately.
PowerShell). Deno is still needed for the current formatting and Deno
compatibility tasks; linting runs on Oxlint and does not need Deno.

Run development workflows through mise. Do not call `npm` or `pnpm` directly
for repository tasks. Start by inspecting the available commands:
Expand Down Expand Up @@ -238,6 +238,25 @@ Deno task, since that option omits task dependencies. The existing Deno
`compile` tasks still generate vocabulary, but no longer cache or type-check it
as a side effect.

### Linting

Linting uses [Oxlint] and the root *.oxlintrc.json*. Run it with:

~~~~ bash
mise run check:lint
mise run check-each fedify
~~~~

The configuration mirrors the rule set that the repository previously used
with `deno lint`; [linting.md] documents the mapping and the accepted gaps.
Name rules explicitly in `oxlint-disable` comments and add a short reason when
the suppression is not obvious. The editor setup keeps the Deno language
server for formatting and type diagnostics but disables `deno.lint`, so Oxlint
is the only lint source.

[Oxlint]: https://oxc.rs/docs/guide/usage/linter/
[linting.md]: LINTING.md

### Type checking

`mise run check:types` type-checks the repository with TypeScript on Node.js,
Expand Down
Loading
Loading