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
56 changes: 47 additions & 9 deletions .github/workflows/pull-request-build-lint-web-apps.yml
Original file line number Diff line number Diff line change
Expand Up @@ -117,16 +117,54 @@ jobs:
path: .turbo
key: turbo-${{ runner.os }}-${{ github.event.pull_request.base.sha }}-${{ github.sha }}

# Lint and type checks depend on build artifacts
check:
name: ${{ matrix.task }}
# Lint check - no build dependency, OxLint is a standalone Rust binary
check-lint:
name: check:lint
runs-on: ubuntu-latest
timeout-minutes: 10
if: |
github.event.pull_request.draft == false &&
github.event.pull_request.requested_reviewers != null
env:
TURBO_SCM_BASE: ${{ github.event.pull_request.base.sha }}
TURBO_SCM_HEAD: ${{ github.sha }}
steps:
- name: Checkout code
uses: actions/checkout@v6
with:
fetch-depth: 50
filter: blob:none

- name: Set up Node.js
uses: actions/setup-node@v6

- name: Enable Corepack and pnpm
run: corepack enable pnpm

- name: Get pnpm store directory
shell: bash
run: echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV

- name: Cache pnpm store
uses: actions/cache@v4
with:
path: ${{ env.STORE_PATH }}
key: pnpm-store-${{ runner.os }}-${{ hashFiles('**/pnpm-lock.yaml') }}
restore-keys: |
pnpm-store-${{ runner.os }}-

- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run check:lint
run: pnpm turbo run check:lint --affected

# Type check depends on build artifacts
check-types:
name: check:types
runs-on: ubuntu-latest
needs: build
timeout-minutes: 15
strategy:
fail-fast: false
matrix:
task: [check:lint, check:types]
env:
TURBO_SCM_BASE: ${{ github.event.pull_request.base.sha }}
TURBO_SCM_HEAD: ${{ github.sha }}
Expand Down Expand Up @@ -165,5 +203,5 @@ jobs:
- name: Install dependencies
run: pnpm install --frozen-lockfile

- name: Run ${{ matrix.task }}
run: pnpm turbo run ${{ matrix.task }} --affected
- name: Run check:types
run: pnpm turbo run check:types --affected
49 changes: 49 additions & 0 deletions .oxlintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
{
"$schema": "./node_modules/oxlint/configuration_schema.json",
"plugins": ["react", "typescript", "jsx-a11y", "import", "promise", "unicorn", "oxc"],
"categories": {
"correctness": "warn",
"suspicious": "warn",
"perf": "warn"
},
"env": {
"browser": true,
"node": true,
"es2024": true
},
"settings": {
"react": {
"version": "18.3"
},
"jsx-a11y": {
"polymorphicPropName": "as"
}
},
"ignorePatterns": [
".cache/**",
".next/**",
".react-router/**",
".storybook/**",
".turbo/**",
".vite/**",
"*.config.{js,mjs,cjs,ts}",
"build/**",
"coverage/**",
"dist/**",
"**/public/**",
"storybook-static/**"
],
"rules": {
"react/prop-types": "off",
"unicorn/filename-case": "off",
"unicorn/no-null": "off",
"unicorn/prevent-abbreviations": "off",
"no-unused-vars": ["warn", {
"argsIgnorePattern": "^_",
"varsIgnorePattern": "^_",
"caughtErrorsIgnorePattern": "^_",
"destructuredArrayIgnorePattern": "^_",
"ignoreRestSiblings": true
}]
}
}
6 changes: 3 additions & 3 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
- `pnpm dev` - Start all dev servers (web:3000, admin:3001)
- `pnpm build` - Build all packages and apps
- `pnpm check` - Run all checks (format, lint, types)
- `pnpm check:lint` - ESLint across all packages
- `pnpm check:lint` - OxLint across all packages
- `pnpm check:types` - TypeScript type checking
- `pnpm fix` - Auto-fix format and lint issues
- `pnpm turbo run <command> --filter=<package>` - Target specific package/app
Expand All @@ -15,8 +15,8 @@

- **Imports**: Use `workspace:*` for internal packages, `catalog:` for external deps
- **TypeScript**: Strict mode enabled, all files must be typed
- **Formatting**: Prettier with Tailwind plugin, run `pnpm fix:format`
- **Linting**: ESLint with shared config, max warnings vary by package
- **Formatting**: oxfmt, run `pnpm fix:format`
- **Linting**: OxLint with shared `.oxlintrc.json` config
- **Naming**: camelCase for variables/functions, PascalCase for components/types
- **Error Handling**: Use try-catch with proper error types, log errors appropriately
- **State Management**: MobX stores in `packages/shared-state`, reactive patterns
Expand Down
2 changes: 1 addition & 1 deletion CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ If you would like to _implement_ it, an issue with your proposal must be submitt
To ensure consistency throughout the source code, please keep these rules in mind as you are working:

- All features or bug fixes must be tested by one or more specs (unit-tests).
- We lint with [ESLint 9](https://eslint.org/docs/latest/) using the shared `eslint.config.mjs` (type-aware via `typescript-eslint`) and format with [Prettier](https://prettier.io/) using `prettier.config.cjs`.
- We lint with [OxLint](https://oxc.rs/docs/guide/usage/linter) using the shared `.oxlintrc.json` and format with [oxfmt](https://oxc.rs/docs/guide/usage/formatter) using `.oxfmtrc.json`.

## Ways to contribute

Expand Down
4 changes: 2 additions & 2 deletions apps/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,10 @@
"preview": "react-router build && serve -s build/client -l 3001",
"start": "serve -s build/client -l 3001",
"clean": "rm -rf .turbo && rm -rf .next && rm -rf node_modules && rm -rf dist && rm -rf build",
"check:lint": "eslint . --cache --cache-location node_modules/.cache/eslint/ --max-warnings=485",
"check:lint": "oxlint --max-warnings=758 .",
"check:types": "react-router typegen && tsc --noEmit",
"check:format": "oxfmt --check .",
"fix:lint": "eslint . --cache --cache-location node_modules/.cache/eslint/ --fix --max-warnings=485",
"fix:lint": "oxlint --fix .",
"fix:format": "oxfmt ."
},
"dependencies": {
Expand Down
4 changes: 2 additions & 2 deletions apps/live/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,10 @@
"test": "vitest run",
"test:watch": "vitest",
"test:coverage": "vitest run --coverage",
"check:lint": "eslint . --cache --cache-location node_modules/.cache/eslint/ --max-warnings=160",
"check:lint": "oxlint --max-warnings=119 .",
"check:types": "tsc --noEmit",
"check:format": "oxfmt --check .",
"fix:lint": "eslint . --cache --cache-location node_modules/.cache/eslint/ --fix --max-warnings=160",
"fix:lint": "oxlint --fix .",
"fix:format": "oxfmt .",
"clean": "rm -rf .turbo && rm -rf .next && rm -rf node_modules && rm -rf dist"
},
Expand Down
4 changes: 2 additions & 2 deletions apps/space/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
"preview": "react-router build && PORT=3002 react-router-serve ./build/server/index.js",
"start": "PORT=3002 react-router-serve ./build/server/index.js",
"clean": "rm -rf .turbo && rm -rf .next && rm -rf .react-router && rm -rf node_modules && rm -rf dist && rm -rf build",
"check:lint": "eslint . --cache --cache-location node_modules/.cache/eslint/ --max-warnings=932",
"check:lint": "oxlint --max-warnings=675 .",
"check:types": "react-router typegen && tsc --noEmit",
"check:format": "oxfmt --check .",
"fix:lint": "eslint . --cache --cache-location node_modules/.cache/eslint/ --fix --max-warnings=932",
"fix:lint": "oxlint --fix .",
"fix:format": "oxfmt ."
},
"dependencies": {
Expand Down
4 changes: 2 additions & 2 deletions apps/web/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@
"preview": "react-router build && serve -s build/client -l 3000",
"start": "serve -s build/client -l 3000",
"clean": "rm -rf .turbo && rm -rf .next && rm -rf .react-router && rm -rf node_modules && rm -rf dist && rm -rf build",
"check:lint": "eslint . --cache --cache-location node_modules/.cache/eslint/ --max-warnings=14367",
"check:lint": "oxlint --max-warnings=11957 .",
"check:types": "react-router typegen && tsc --noEmit",
"check:format": "oxfmt --check .",
"fix:lint": "eslint . --cache --cache-location node_modules/.cache/eslint/ --fix --max-warnings=14367",
"fix:lint": "oxlint --fix .",
"fix:format": "oxfmt ."
},
"dependencies": {
Expand Down
103 changes: 0 additions & 103 deletions docs/eslint.md

This file was deleted.

92 changes: 92 additions & 0 deletions docs/linting.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
# Linting in Plane - How It Works

We use [OxLint](https://oxc.rs/docs/guide/usage/linter) for linting across the entire monorepo. OxLint is a single Rust binary that's 50-100x faster than ESLint, with zero Node.js dependencies at runtime.

## Key Points

1. **Single Root Config** - One `.oxlintrc.json` at the repo root handles all packages and apps
2. **No Build Required** - OxLint doesn't need TypeScript build artifacts, so lint runs independently of build
3. **Plugin Coverage** - react, typescript, jsx-a11y, import, promise, unicorn, oxc

## How to Run

From the root of the repo:

```bash
# Check for lint errors
pnpm check:lint

# Auto-fix lint errors
pnpm fix:lint
```

To lint a specific package:

```bash
pnpm turbo run check:lint --filter=@plane/ui
```

## VS Code Integration

Install the [OxLint extension](https://marketplace.visualstudio.com/items?itemName=nicolo-ribaudo.vscode-oxlint) for inline errors/warnings as you type.

## What Gets Linted

The config applies to all TypeScript and JavaScript files across:

- `apps/web`, `apps/admin`, `apps/space`, `apps/live`
- All packages in `packages/`

**Ignored paths:**

- `node_modules/`, `dist/`, `build/`, `.next/`, `.turbo/`
- Config files (`*.config.{js,mjs,cjs,ts}`)
- Public folders, coverage, storybook-static

## Rules Overview

OxLint uses category-based configuration:

| Category | Level | What It Catches |
| --------------- | ----- | -------------------------------------------------- |
| **correctness** | error | Real bugs that will cause runtime errors |
| **suspicious** | warn | Code patterns that are likely mistakes |
| **perf** | warn | Performance anti-patterns |

Additional rule overrides:
- `react/prop-types` off (TypeScript handles prop validation)
- `no-unused-vars` warns with `_` prefix pattern ignored
- Several noisy unicorn rules disabled

## Backward Compatibility

OxLint supports `eslint-disable` comments, so existing inline suppressions continue to work.

## Suppressing Warnings

```typescript
// Single line
// eslint-disable-next-line no-unused-vars
const data = response;

// Block
/* eslint-disable no-unused-vars */
// ... code
/* eslint-enable no-unused-vars */
```

**Please use sparingly** - most warnings indicate real issues that should be fixed.

## Pre-commit Hook

Lint-staged runs automatically on commit via Husky:

- oxfmt formats your staged files
- OxLint fixes what it can (with `--deny-warnings`)

If the commit fails due to lint errors, fix them before committing.

## Reference Files

- [.oxlintrc.json](../.oxlintrc.json) - OxLint configuration
- [package.json](../package.json) - Available scripts
Loading
Loading