diff --git a/.codesandbox/tasks.json b/.codesandbox/tasks.json index 51c6e4e16f..43a049736f 100644 --- a/.codesandbox/tasks.json +++ b/.codesandbox/tasks.json @@ -19,11 +19,6 @@ "command": "yarn fix", "runAtStart": false }, - "prettier": { - "name": "Prettify", - "command": "yarn prettier", - "runAtStart": false - }, "start": { "name": "Start Excalidraw", "command": "yarn start", diff --git a/.env.development b/.env.development index 5e2d3dfe36..5a909655e3 100644 --- a/.env.development +++ b/.env.development @@ -37,9 +37,6 @@ VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX= # Set this flag to false if you want to open the overlay by default VITE_APP_COLLAPSE_OVERLAY=true -# Set this flag to false to disable eslint -VITE_APP_ENABLE_ESLINT=true - # Enable PWA in dev server VITE_APP_ENABLE_PWA=false diff --git a/.env.production b/.env.production index 72dd24d6ec..995a96d5d2 100644 --- a/.env.production +++ b/.env.production @@ -29,6 +29,3 @@ PQIDAQAB' # Set the below flags explicitly to false in production mode since vite loads and merges .env.local vars when running the build command VITE_APP_DEBUG_ENABLE_TEXT_CONTAINER_BOUNDING_BOX=false VITE_APP_COLLAPSE_OVERLAY=false -# Enable eslint in dev server -VITE_APP_ENABLE_ESLINT=false - diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index 8b4f458dee..0000000000 --- a/.eslintignore +++ /dev/null @@ -1,11 +0,0 @@ -node_modules/ -build/ -package-lock.json -.vscode/ -firebase/ -dist/ -public/workbox -packages/excalidraw/types -examples/**/public -dev-dist -coverage diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 89f8227361..0000000000 --- a/.eslintrc.json +++ /dev/null @@ -1,43 +0,0 @@ -{ - "extends": ["@excalidraw/eslint-config", "react-app"], - "rules": { - "import/order": [ - "warn", - { - "groups": ["builtin", "external", "internal", "parent", "sibling", "index", "object", "type"], - "pathGroups": [ - { - "pattern": "@excalidraw/**", - "group": "external", - "position": "after" - } - ], - "newlines-between": "always-and-inside-groups", - "warnOnUnassignedImports": true - } - ], - "import/no-anonymous-default-export": "off", - "no-restricted-globals": "off", - "@typescript-eslint/consistent-type-imports": [ - "error", - { - "prefer": "type-imports", - "disallowTypeAnnotations": false, - "fixStyle": "separate-type-imports" - } - ], - "no-restricted-imports": [ - "error", - { - "name": "jotai", - "message": "Do not import from \"jotai\" directly. Use our app-specific modules (\"editor-jotai\" or \"app-jotai\")." - } - ], - "react/jsx-no-target-blank": [ - "error", - { - "allowReferrer": true - } - ] - } -} diff --git a/.gitignore b/.gitignore index 6f3a62bba3..eb45df5a45 100644 --- a/.gitignore +++ b/.gitignore @@ -8,7 +8,9 @@ .history .idea .vercel -.vscode +.vscode/* +!.vscode/extensions.json +!.vscode/settings.recommended.json .yarn *.log *.tgz diff --git a/.lintstagedrc.js b/.lintstagedrc.js index 612d4c39ac..806116817c 100644 --- a/.lintstagedrc.js +++ b/.lintstagedrc.js @@ -1,14 +1,4 @@ -const { CLIEngine } = require("eslint"); - -// see https://github.com/okonet/lint-staged#how-can-i-ignore-files-from-eslintignore- -// for explanation -const cli = new CLIEngine({}); - module.exports = { - "*.{js,ts,tsx}": files => { - return ( - "eslint --max-warnings=0 --fix " + files.filter(file => !cli.isPathIgnored(file)).join(" ") - ); - }, - "*.{css,scss,json,md,html,yml}": ["prettier --write"], + "*.{js,ts,tsx}": ["oxlint --fix", "oxfmt --write"], + "*.{css,scss,json,md,html,yml}": ["oxfmt --write"], }; diff --git a/.oxfmtrc.json b/.oxfmtrc.json new file mode 100644 index 0000000000..c7f8782b40 --- /dev/null +++ b/.oxfmtrc.json @@ -0,0 +1,5 @@ +{ + "printWidth": 80, + "proseWrap": "never", + "trailingComma": "all" +} diff --git a/.oxlintrc.json b/.oxlintrc.json new file mode 100644 index 0000000000..6bd1167c58 --- /dev/null +++ b/.oxlintrc.json @@ -0,0 +1,112 @@ +{ + "$schema": "https://raw.githubusercontent.com/oxc-project/oxc/main/npm/oxlint/configuration_schema.json", + "plugins": ["typescript", "react", "jsx-a11y", "import"], + "rules": { + "no-unused-vars": [ + "warn", + { + "ignoreRestSiblings": true + } + ], + "curly": "warn", + "no-console": [ + "warn", + { + "allow": ["info", "warn", "error"] + } + ], + "no-else-return": "warn", + "no-lonely-if": "warn", + "no-unneeded-ternary": "warn", + "no-unused-expressions": "warn", + "no-useless-return": "warn", + "no-var": "warn", + "one-var": "warn", + "prefer-arrow-callback": "warn", + "prefer-const": "warn", + "prefer-template": "warn", + "typescript/consistent-type-imports": [ + "error", + { + "disallowTypeAnnotations": false + } + ], + "typescript/no-restricted-imports": [ + "error", + { + "patterns": [ + { + "group": [ + "../../excalidraw", + "../../../packages/excalidraw", + "@excalidraw/excalidraw" + ], + "message": "Do not import from '@excalidraw/excalidraw' package anything but types, as this package must be independent.", + "allowTypeImports": true + } + ] + } + ], + "eslint/no-restricted-imports": [ + "error", + { + "paths": [ + { + "name": "jotai", + "message": "Do not import from \"jotai\" directly. Use our app-specific modules (\"editor-jotai\" or \"app-jotai\")." + } + ] + } + ], + "react/jsx-no-target-blank": [ + "error", + { + "allowReferrer": true + } + ], + "jsx-a11y/no-autofocus": "off", + "eslint/no-async-promise-executor": "off", + "eslint-plugin-jsx-a11y/click-events-have-key-events": "off", + "eslint-plugin-jsx-a11y/label-has-associated-control": "off" + }, + "ignorePatterns": [ + "node_modules/", + "build/", + "dist/", + ".vscode/", + "firebase/", + "public/workbox", + "packages/excalidraw/types", + "examples/**/public", + "dev-dist", + "coverage" + ], + "overrides": [ + { + "files": [ + "packages/common/src/**/*.ts", + "packages/common/src/**/*.tsx", + "packages/element/src/**/*.ts", + "packages/element/src/**/*.tsx" + ], + "rules": { + "typescript/no-restricted-imports": [ + "error", + { + "patterns": [ + { + "group": [ + "../../excalidraw", + "../../../packages/excalidraw", + "@excalidraw/excalidraw" + ], + "message": "Do not import from '@excalidraw/excalidraw' package anything but types, as this package must be independent.", + "allowTypeImports": true + } + ] + } + ] + } + } + ] +} diff --git a/.prettierignore b/.prettierignore deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000000..99e2f7ddf7 --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["oxc.oxc-vscode"] +} diff --git a/.vscode/settings.recommended.json b/.vscode/settings.recommended.json new file mode 100644 index 0000000000..2d024f81dc --- /dev/null +++ b/.vscode/settings.recommended.json @@ -0,0 +1,22 @@ +{ + "oxc.enable": true, + "editor.formatOnSave": true, + "[javascript]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[typescript]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[javascriptreact]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[typescriptreact]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[json]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + }, + "[jsonc]": { + "editor.defaultFormatter": "oxc.oxc-vscode" + } +} diff --git a/examples/with-script-in-browser/package.json b/examples/with-script-in-browser/package.json index 653c2be40e..c77a5d4833 100644 --- a/examples/with-script-in-browser/package.json +++ b/examples/with-script-in-browser/package.json @@ -3,14 +3,14 @@ "version": "1.0.0", "private": true, "dependencies": { + "@excalidraw/excalidraw": "0.18.0", + "browser-fs-access": "0.29.1", "react": "19.0.0", - "react-dom": "19.0.0", - "@excalidraw/excalidraw": "*", - "browser-fs-access": "0.29.1" + "react-dom": "19.0.0" }, "devDependencies": { - "vite": "5.0.12", - "typescript": "^5" + "typescript": "^5", + "vite": "5.0.12" }, "scripts": { "start": "vite", diff --git a/excalidraw-app/vite-env.d.ts b/excalidraw-app/vite-env.d.ts index ade60e859e..d83ea55d93 100644 --- a/excalidraw-app/vite-env.d.ts +++ b/excalidraw-app/vite-env.d.ts @@ -26,9 +26,6 @@ interface ImportMetaEnv { // Set this flag to false if you want to open the overlay by default VITE_APP_COLLAPSE_OVERLAY: string; - // Enable eslint in dev server - VITE_APP_ENABLE_ESLINT: string; - // Enable PWA in dev server VITE_APP_ENABLE_PWA: string; diff --git a/excalidraw-app/vite.config.mts b/excalidraw-app/vite.config.mts index a24d0939a6..ecafd829e3 100644 --- a/excalidraw-app/vite.config.mts +++ b/excalidraw-app/vite.config.mts @@ -5,6 +5,7 @@ import svgrPlugin from "vite-plugin-svgr"; import { ViteEjsPlugin } from "vite-plugin-ejs"; import { VitePWA } from "vite-plugin-pwa"; import checker from "vite-plugin-checker"; +import oxlint from "vite-plugin-oxlint"; import { createHtmlPlugin } from "vite-plugin-html"; import Sitemap from "vite-plugin-sitemap"; import { woff2BrowserPlugin } from "../scripts/woff2/woff2-vite-plugins"; @@ -125,15 +126,16 @@ export default defineConfig(({ mode }) => { react(), checker({ typescript: true, - eslint: - envVars.VITE_APP_ENABLE_ESLINT === "false" - ? undefined - : { lintCommand: 'eslint "./**/*.{js,ts,tsx}"' }, overlay: { initialIsOpen: envVars.VITE_APP_COLLAPSE_OVERLAY === "false", badgeStyle: "margin-bottom: 4rem; margin-left: 1rem", }, }), + oxlint({ + configFile: path.resolve(__dirname, "../.oxlintrc.json"), + path: path.resolve(__dirname, ".."), + oxlintPath: path.resolve(__dirname, "../node_modules/.bin/oxlint"), + }), svgrPlugin(), ViteEjsPlugin(), VitePWA({ diff --git a/package.json b/package.json index 65ff221a49..ec854d8667 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,10 @@ "packageManager": "yarn@1.22.22", "workspaces": [ "excalidraw-app", - "packages/*", - "examples/*" + "packages/*" ], "devDependencies": { "@babel/preset-env": "7.26.9", - "@excalidraw/eslint-config": "1.0.3", - "@excalidraw/prettier-config": "1.0.2", "@types/chai": "4.3.0", "@types/jest": "27.4.0", "@types/lodash.throttle": "4.1.7", @@ -22,22 +19,20 @@ "@vitest/ui": "2.0.5", "chai": "4.3.6", "dotenv": "16.0.1", - "eslint-config-prettier": "8.5.0", - "eslint-config-react-app": "7.0.1", - "eslint-plugin-import": "2.31.0", - "eslint-plugin-prettier": "3.3.1", "http-server": "14.1.1", "husky": "7.0.4", "jsdom": "22.1.0", "lint-staged": "12.3.7", + "oxfmt": "0.26.0", + "oxlint": "1.41.0", "pepjs": "0.5.3", - "prettier": "2.6.2", "rewire": "6.0.0", "rimraf": "^5.0.0", "typescript": "5.9.3", "vite": "5.0.12", "vite-plugin-checker": "0.7.2", "vite-plugin-ejs": "1.7.0", + "vite-plugin-oxlint": "github:dwelle/vite-plugin-oxlint", "vite-plugin-pwa": "0.21.1", "vite-plugin-svgr": "4.2.0", "vitest": "3.0.6", @@ -47,7 +42,7 @@ "node": ">=18.0.0" }, "homepage": ".", - "prettier": "@excalidraw/prettier-config", + "scripts": { "build-node": "node ./scripts/build-node.js", "build:app:docker": "yarn --cwd ./excalidraw-app build:app:docker", @@ -65,21 +60,21 @@ "start:example": "yarn build:packages && yarn --cwd ./examples/with-script-in-browser start", "test:all": "yarn test:typecheck && yarn test:code && yarn test:other && yarn test:app --watch=false", "test:app": "vitest", - "test:code": "eslint --max-warnings=0 --ext .js,.ts,.tsx .", - "test:other": "yarn prettier --list-different", + "test:code": "oxlint .", + "test:other": "oxfmt --check .", "test:typecheck": "tsc", "test:update": "yarn test:app --update --watch=false", "test": "yarn test:app", "test:coverage": "vitest --coverage", "test:coverage:watch": "vitest --coverage --watch", "test:ui": "yarn test --ui --coverage.enabled=true", - "fix:code": "yarn test:code --fix", - "fix:other": "yarn prettier --write", - "fix": "yarn fix:other && yarn fix:code", + "lint": "oxlint", + "lint:fix": "oxlint --fix", + "format:fix": "oxfmt", + "fix": "yarn lint:fix && yarn format:fix", "locales-coverage": "node scripts/build-locales-coverage.js", "locales-coverage:description": "node scripts/locales-coverage-description.js", "prepare": "husky install", - "prettier": "prettier \"**/*.{css,scss,json,md,html,yml}\" --ignore-path=.eslintignore", "release": "node scripts/release.js", "release:test": "node scripts/release.js --tag=test", "release:next": "node scripts/release.js --tag=next", @@ -91,4 +86,5 @@ "resolutions": { "strip-ansi": "6.0.1" } + } diff --git a/packages/common/.eslintrc.json b/packages/common/.eslintrc.json deleted file mode 100644 index a31aaa1473..0000000000 --- a/packages/common/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": ["../eslintrc.base.json"] -} diff --git a/packages/element/.eslintrc.json b/packages/element/.eslintrc.json deleted file mode 100644 index a31aaa1473..0000000000 --- a/packages/element/.eslintrc.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "extends": ["../eslintrc.base.json"] -} diff --git a/packages/eslintrc.base.json b/packages/eslintrc.base.json deleted file mode 100644 index 88d006a096..0000000000 --- a/packages/eslintrc.base.json +++ /dev/null @@ -1,21 +0,0 @@ -{ - "overrides": [ - { - "files": ["src/**/*.{ts,tsx}"], - "rules": { - "@typescript-eslint/no-restricted-imports": [ - "error", - { - "patterns": [ - { - "group": ["../../excalidraw", "../../../packages/excalidraw", "@excalidraw/excalidraw"], - "message": "Do not import from '@excalidraw/excalidraw' package anything but types, as this package must be independent.", - "allowTypeImports": true - } - ] - } - ] - } - } - ] -}