Replace ESLint and Prettier with Oxlint and Oxfmt
This commit is contained in:
committed by
James Brunton
parent
596f5fd42c
commit
3a57da928d
+4
-47
@@ -195,15 +195,9 @@ tasks:
|
||||
desc: "Run linting"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- task: lint:eslint
|
||||
- task: lint:oxlint
|
||||
- task: lint:dpdm
|
||||
|
||||
lint:eslint:
|
||||
desc: "Run ESLint linting"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- npx eslint --max-warnings=0
|
||||
|
||||
lint:dpdm:
|
||||
desc: "Run circular import linting"
|
||||
deps: [install]
|
||||
@@ -216,19 +210,19 @@ tasks:
|
||||
desc: "Auto-fix lint issues"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- npx eslint --fix
|
||||
- npx oxlint --fix
|
||||
|
||||
format:
|
||||
desc: "Auto-fix code formatting"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- npx prettier --write .
|
||||
- npx oxfmt --write .
|
||||
|
||||
format:check:
|
||||
desc: "Check code formatting"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- npx prettier --check .
|
||||
- npx oxfmt --check .
|
||||
|
||||
fix:
|
||||
desc: "Auto-fix lint and format"
|
||||
@@ -236,49 +230,12 @@ tasks:
|
||||
- task: format
|
||||
- task: lint:fix
|
||||
|
||||
# ------------------------------------------------------------
|
||||
# OSS oxc toolchain (oxlint + oxfmt) - evaluation
|
||||
# Runs in parallel with the ESLint/Prettier tasks above so the
|
||||
# two toolchains can be benchmarked head-to-head before any swap.
|
||||
# Config: frontend/oxlint.config.ts, frontend/.oxfmtrc.json
|
||||
# ------------------------------------------------------------
|
||||
|
||||
lint:oxlint:
|
||||
desc: "Run oxlint linting"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- npx oxlint --max-warnings=0
|
||||
|
||||
lint:oxlint:fix:
|
||||
desc: "Auto-fix lint issues with oxlint"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- npx oxlint --fix
|
||||
|
||||
format:oxfmt:
|
||||
desc: "Auto-fix code formatting with oxfmt"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- npx oxfmt --write .
|
||||
|
||||
format:oxfmt:check:
|
||||
desc: "Check code formatting with oxfmt"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- npx oxfmt --check .
|
||||
|
||||
bench:lint:
|
||||
desc: "Time ESLint against oxlint on the same tree"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- bash -c 'echo "=== ESLint ===" && time npx eslint --max-warnings=0 || true; echo; echo "=== oxlint ===" && time npx oxlint --max-warnings=0 || true'
|
||||
|
||||
bench:format:
|
||||
desc: "Time Prettier against oxfmt on the same tree"
|
||||
deps: [install]
|
||||
cmds:
|
||||
- bash -c 'echo "=== Prettier ===" && time npx prettier --check . || true; echo; echo "=== oxfmt ===" && time npx oxfmt --check . || true'
|
||||
|
||||
typecheck:
|
||||
desc: "Typecheck default build of the app"
|
||||
cmds:
|
||||
|
||||
Vendored
+1
-1
@@ -19,6 +19,6 @@
|
||||
"yzhang.markdown-all-in-one", // Markdown All-in-One extension for enhanced Markdown editing
|
||||
"stylelint.vscode-stylelint", // Stylelint extension for CSS and SCSS linting
|
||||
"redhat.vscode-yaml", // YAML extension for Visual Studio Code
|
||||
"dbaeumer.vscode-eslint", // ESLint extension for TypeScript linting
|
||||
"oxc.oxc-vscode", // Oxc (oxlint) extension for TypeScript/JavaScript linting
|
||||
]
|
||||
}
|
||||
|
||||
+1
-1
@@ -158,7 +158,7 @@ Stirling-PDF/
|
||||
│ │ │ └── locales/ # Internationalization files (JSON)
|
||||
│ │ └── vite.config.ts # Vite configuration
|
||||
│ ├── package.json # Shared workspace dependencies
|
||||
│ └── eslint.config.mjs # Shared lint config
|
||||
│ └── oxlint.config.ts # Shared lint config (oxlint)
|
||||
├── customFiles/ # Custom static files and templates (generated at runtime used to replace existing files)
|
||||
├── docs/ # Documentation files
|
||||
├── exampleYmlFiles/ # Example YAML configuration files
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
dist/
|
||||
editor/dist/
|
||||
# Tauri/Cargo build output (binary assets named *.js etc. confuse Prettier).
|
||||
# Match nested target/ dirs too - provisioner/ and thumbnail-handler/ each
|
||||
# have their own Cargo workspace under src-tauri/.
|
||||
editor/src-tauri/**/target/
|
||||
editor/src-tauri/gen/
|
||||
node_modules/
|
||||
editor/public/vendor/
|
||||
# Auto-generated by MSW (`msw init`); regenerated verbatim, not hand-formatted.
|
||||
editor/public/mockServiceWorker.js
|
||||
# Auto-generated OG/social-preview metadata (scripts/generate-og-metadata.mjs); regenerated verbatim.
|
||||
editor/public/og-metadata.json
|
||||
editor/src/core/data/ogImageMap.json
|
||||
editor/public/pdfjs*/
|
||||
editor/public/js/thirdParty/
|
||||
editor/public/css/cookieconsent.css
|
||||
# Build / test artifacts that may exist locally even though they're gitignored
|
||||
storybook-static/
|
||||
playwright-report/
|
||||
editor/playwright-report/
|
||||
test-results/
|
||||
editor/test-results/
|
||||
*.min.*
|
||||
*.md
|
||||
*.wxs
|
||||
editor/src/output.css
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"printWidth": 80,
|
||||
"tabWidth": 2,
|
||||
"useTabs": false,
|
||||
"endOfLine": "lf"
|
||||
}
|
||||
@@ -1,227 +0,0 @@
|
||||
// @ts-check
|
||||
|
||||
import eslint from "@eslint/js";
|
||||
import globals from "globals";
|
||||
import { defineConfig } from "eslint/config";
|
||||
import tseslint from "typescript-eslint";
|
||||
|
||||
const srcGlobs = [
|
||||
// The portal layer lives under editor/src/portal, so editor/src/** covers it.
|
||||
"editor/src/**/*.{js,mjs,jsx,ts,tsx}",
|
||||
];
|
||||
const nodeGlobs = [
|
||||
"scripts/**/*.{js,ts,mjs,mts}",
|
||||
"editor/scripts/**/*.{js,ts,mjs,mts}",
|
||||
// Covers editor/vite.config.ts and editor/vitest.config.ts.
|
||||
"editor/*.config.{js,ts,mjs}",
|
||||
"*.config.{js,ts,mjs}",
|
||||
".storybook/*.{js,ts,mjs,mts,tsx}",
|
||||
];
|
||||
|
||||
const baseRestrictedImportPatterns = [
|
||||
{
|
||||
regex: "^\\.",
|
||||
message:
|
||||
"Use a workspace alias (@app/* for editor, @portal/* for portal) instead of relative imports.",
|
||||
},
|
||||
{
|
||||
regex: "^src/",
|
||||
message: "Use a workspace alias instead of absolute src/ imports.",
|
||||
},
|
||||
];
|
||||
|
||||
export default defineConfig(
|
||||
{
|
||||
// Everything that contains 3rd party code that we don't want to lint
|
||||
ignores: [
|
||||
"dist",
|
||||
"node_modules",
|
||||
"playwright-report",
|
||||
"storybook-static",
|
||||
"test-results",
|
||||
"editor/dist",
|
||||
"editor/public",
|
||||
"editor/src-tauri",
|
||||
"editor/playwright-report",
|
||||
"editor/test-results",
|
||||
],
|
||||
},
|
||||
eslint.configs.recommended,
|
||||
tseslint.configs.recommended,
|
||||
{
|
||||
rules: {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
patterns: baseRestrictedImportPatterns,
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-empty-object-type": [
|
||||
"error",
|
||||
{
|
||||
// Allow empty extending interfaces because there's no real reason not to, and it makes it obvious where to put extra attributes in the future
|
||||
allowInterfaces: "with-single-extends",
|
||||
},
|
||||
],
|
||||
"@typescript-eslint/no-explicit-any": "off", // Temporarily disabled until codebase conformant
|
||||
"@typescript-eslint/no-unused-vars": [
|
||||
"error",
|
||||
{
|
||||
args: "all", // All function args must be used (or explicitly ignored)
|
||||
argsIgnorePattern: "^_", // Allow unused variables beginning with an underscore
|
||||
caughtErrors: "all", // Caught errors must be used (or explicitly ignored)
|
||||
caughtErrorsIgnorePattern: "^_", // Allow unused variables beginning with an underscore
|
||||
destructuredArrayIgnorePattern: "^_", // Allow unused variables beginning with an underscore
|
||||
varsIgnorePattern: "^_", // Allow unused variables beginning with an underscore
|
||||
ignoreRestSiblings: true, // Allow unused variables when removing attributes from objects (otherwise this requires explicit renaming like `({ x: _x, ...y }) => y`, which is clunky)
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
// Desktop-only packages must not be imported from core or proprietary code.
|
||||
// Use the stub/shadow pattern instead: define a stub in editor/src/core/ and override in editor/src/desktop/.
|
||||
{
|
||||
files: srcGlobs,
|
||||
ignores: ["editor/src/desktop/**"],
|
||||
rules: {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
patterns: [
|
||||
...baseRestrictedImportPatterns,
|
||||
{
|
||||
regex: "^@tauri-apps/",
|
||||
message:
|
||||
"Tauri APIs are desktop-only. Review frontend/editor/DeveloperGuide.md for structure advice.",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
// The cloud/ layer is the SHARED hosted/SaaS experience consumed by BOTH the
|
||||
// saas and desktop leaves, so it must stay platform-portable. It must not
|
||||
// reach platform-specific things directly (Supabase, Tauri, raw fetch,
|
||||
// window.location, web storage, or import.meta.env.VITE_*) — those arrive via
|
||||
// @app/* seams (services/apiClient, auth/session, platform/openExternal, ...)
|
||||
// that each leaf provides for its own platform.
|
||||
{
|
||||
files: ["editor/src/cloud/**/*.{js,mjs,jsx,ts,tsx}"],
|
||||
rules: {
|
||||
"no-restricted-imports": [
|
||||
"error",
|
||||
{
|
||||
patterns: [
|
||||
...baseRestrictedImportPatterns,
|
||||
{
|
||||
regex: "^@supabase/",
|
||||
message:
|
||||
"cloud/ must stay platform-portable. Reach Supabase via an @app/* seam (e.g. @app/auth/supabase, @app/auth/session) provided per-platform in saas/ and desktop/.",
|
||||
},
|
||||
{
|
||||
regex: "^@tauri-apps/",
|
||||
message:
|
||||
"cloud/ must stay platform-portable. Tauri APIs are desktop-only — reach native features via an @app/* seam (e.g. @app/platform/openExternal).",
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
"no-restricted-globals": [
|
||||
"error",
|
||||
{
|
||||
name: "fetch",
|
||||
message:
|
||||
"cloud/ must not call raw fetch — use @app/services/apiClient so each platform supplies its own transport.",
|
||||
},
|
||||
{
|
||||
name: "localStorage",
|
||||
message:
|
||||
"cloud/ must not touch localStorage — use an @app/* storage seam so desktop/web can differ.",
|
||||
},
|
||||
{
|
||||
name: "sessionStorage",
|
||||
message:
|
||||
"cloud/ must not touch sessionStorage — use an @app/* storage seam so desktop/web can differ.",
|
||||
},
|
||||
],
|
||||
"no-restricted-syntax": [
|
||||
"error",
|
||||
{
|
||||
selector:
|
||||
"MemberExpression[object.name='window'][property.name='location']",
|
||||
message:
|
||||
"cloud/ must not touch window.location — use an @app/* seam (e.g. @app/platform/openExternal) so desktop/web can differ.",
|
||||
},
|
||||
{
|
||||
selector:
|
||||
"MemberExpression[property.name='env'][object.type='MetaProperty'][object.meta.name='import'][object.property.name='meta']",
|
||||
message:
|
||||
"cloud/ must not read import.meta.env — use @app/constants/app / @app/platform seams so config is supplied per-platform.",
|
||||
},
|
||||
],
|
||||
},
|
||||
},
|
||||
// Stricter rules that not all sub-folders are conformant to yet
|
||||
{
|
||||
files: srcGlobs,
|
||||
ignores: [
|
||||
"editor/src/core/components/annotation/**/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/pageEditor/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/pageEditor/commands/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/pageEditor/hooks/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/shared/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/shared/config/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/shared/config/configSections/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/shared/pageEditor/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/addStamp/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/automate/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/bookletImposition/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/certSign/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/pdfTextEditor/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/tools/shared/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/components/viewer/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/contexts/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/contexts/file/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/contexts/viewer/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/signing/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/tools/adjustContrast/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/tools/convert/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/tools/removePassword/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/hooks/tools/shared/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/services/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/tools/annotate/useAnnotationSelection.ts",
|
||||
"editor/src/core/types/*.{js,mjs,jsx,ts,tsx}",
|
||||
"editor/src/core/utils/*.{js,mjs,jsx,ts,tsx}",
|
||||
],
|
||||
languageOptions: {
|
||||
parserOptions: {
|
||||
project: true,
|
||||
tsconfigRootDir: import.meta.dirname,
|
||||
},
|
||||
},
|
||||
rules: {
|
||||
"@typescript-eslint/no-explicit-any": "error",
|
||||
"@typescript-eslint/no-unnecessary-type-assertion": "error",
|
||||
},
|
||||
},
|
||||
// Config for browser scripts
|
||||
{
|
||||
files: srcGlobs,
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.browser,
|
||||
},
|
||||
},
|
||||
},
|
||||
// Config for node scripts
|
||||
{
|
||||
files: nodeGlobs,
|
||||
languageOptions: {
|
||||
globals: {
|
||||
...globals.node,
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
@@ -1,6 +1,6 @@
|
||||
import { defineConfig } from "oxlint";
|
||||
|
||||
// App source globs (mirrors srcGlobs in eslint.config.mjs).
|
||||
// App source globs
|
||||
const srcGlobs = [
|
||||
"editor/src/**/*.{js,mjs,jsx,ts,tsx}",
|
||||
"portal/src/**/*.{js,mjs,jsx,ts,tsx}",
|
||||
|
||||
Generated
+3
-957
File diff suppressed because it is too large
Load Diff
@@ -58,7 +58,6 @@
|
||||
"autoprefixer": "^10.4.21",
|
||||
"axios": "^1.15.0",
|
||||
"d3": "^7.9.0",
|
||||
"globals": "^17.5.0",
|
||||
"i18next": "^25.10.10",
|
||||
"i18next-browser-languagedetector": "^8.2.0",
|
||||
"jszip": "^3.10.1",
|
||||
@@ -107,7 +106,6 @@
|
||||
]
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "^10.0.1",
|
||||
"@iconify-json/material-symbols": "^1.2.53",
|
||||
"@iconify/utils": "^3.1.0",
|
||||
"@playwright/test": "^1.55.0",
|
||||
@@ -128,14 +126,11 @@
|
||||
"@types/node": "^24.5.2",
|
||||
"@types/react": "^19.1.13",
|
||||
"@types/react-dom": "^19.1.9",
|
||||
"@typescript-eslint/eslint-plugin": "^8.61.1",
|
||||
"@typescript-eslint/parser": "^8.61.1",
|
||||
"@typescript/native-preview": "7.0.0-dev.20260624.1",
|
||||
"@vitejs/plugin-react-swc": "^4.1.0",
|
||||
"@vitest/coverage-v8": "^3.2.4",
|
||||
"dotenv": "^16.4.7",
|
||||
"dpdm": "^3.14.0",
|
||||
"eslint": "^10.0.2",
|
||||
"fake-indexeddb": "^6.2.5",
|
||||
"jsdom": "^27.0.0",
|
||||
"json-schema-to-typescript": "^15.0.4",
|
||||
@@ -148,13 +143,11 @@
|
||||
"postcss-cli": "^11.0.1",
|
||||
"postcss-preset-mantine": "^1.18.0",
|
||||
"postcss-simple-vars": "^7.0.1",
|
||||
"prettier": "^3.8.1",
|
||||
"puppeteer": "^24.25.0",
|
||||
"rollup-plugin-visualizer": "^7.0.1",
|
||||
"storybook": "^9.1.20",
|
||||
"tsx": "^4.21.0",
|
||||
"typescript": "^6.0.3",
|
||||
"typescript-eslint": "^8.61.1",
|
||||
"vite": "^7.3.2",
|
||||
"vite-plugin-compression2": "^2.5.3",
|
||||
"vite-plugin-static-copy": "^3.1.4",
|
||||
|
||||
Reference in New Issue
Block a user