diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 918bf8b3..a5e3c84f 100644
--- a/.github/workflows/lint.yml
+++ b/.github/workflows/lint.yml
@@ -17,6 +17,7 @@ jobs:
- name: Install and lint
run: |
npm ci
+ npm run test:other
npm run test:code
env:
CI: true
diff --git a/.lintstagedrc.js b/.lintstagedrc.js
index 87a02c84..18e1d218 100644
--- a/.lintstagedrc.js
+++ b/.lintstagedrc.js
@@ -7,9 +7,8 @@ const cli = new CLIEngine({});
module.exports = {
"*.{js,ts,tsx}": files => {
return (
- "eslint --max-warnings=0 " +
- files.filter(file => !cli.isPathIgnored(file)).join(" ")
+ "eslint --fix" + files.filter(file => !cli.isPathIgnored(file)).join(" ")
);
},
- "*.{js,css,scss,json,md,ts,tsx,html,yml}": ["prettier --write"],
+ "*.{css,scss,json,md,html,yml}": ["prettier --write"],
};
diff --git a/package-lock.json b/package-lock.json
index c6dc04f4..1fc882da 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -5299,6 +5299,23 @@
}
}
},
+ "eslint-config-prettier": {
+ "version": "6.10.0",
+ "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-6.10.0.tgz",
+ "integrity": "sha512-AtndijGte1rPILInUdHjvKEGbIV06NuvPrqlIEaEaWtbtvJh464mDeyGMdZEQMsGvC0ZVkiex1fSNcC4HAbRGg==",
+ "dev": true,
+ "requires": {
+ "get-stdin": "^6.0.0"
+ },
+ "dependencies": {
+ "get-stdin": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-6.0.0.tgz",
+ "integrity": "sha512-jp4tHawyV7+fkkSKyvjuLZswblUtz+SQKzSWnBbii16BuZksJlU1wuBYXY75r+duh/llF1ur6oNwi+2ZzjKZ7g==",
+ "dev": true
+ }
+ }
+ },
"eslint-config-react-app": {
"version": "5.1.0",
"resolved": "https://registry.npmjs.org/eslint-config-react-app/-/eslint-config-react-app-5.1.0.tgz",
@@ -5583,6 +5600,15 @@
}
}
},
+ "eslint-plugin-prettier": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.1.2.tgz",
+ "integrity": "sha512-GlolCC9y3XZfv3RQfwGew7NnuFDKsfI4lbvRK+PIIo23SFH+LemGs4cKwzAaRa+Mdb+lQO/STaIayno8T5sJJA==",
+ "dev": true,
+ "requires": {
+ "prettier-linter-helpers": "^1.0.0"
+ }
+ },
"eslint-plugin-react": {
"version": "7.16.0",
"resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.16.0.tgz",
@@ -5976,6 +6002,12 @@
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.1.tgz",
"integrity": "sha512-8UEa58QDLauDNfpbrX55Q9jrGHThw2ZMdOky5Gl1CDtVeJDPVrG4Jxx1N8jw2gkWaff5UUuX1KJd+9zGe2B+ZA=="
},
+ "fast-diff": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.2.0.tgz",
+ "integrity": "sha512-xJuoT5+L99XlZ8twedaRf6Ax2TgQVxvgZOYoPKqZufmJib0tL2tegPBOZb1pVNgIhlqDlA0eO0c3wBvQcmzx4w==",
+ "dev": true
+ },
"fast-glob": {
"version": "2.2.7",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-2.2.7.tgz",
@@ -12119,6 +12151,15 @@
"integrity": "sha512-s7PoyDv/II1ObgQunCbB9PdLmUcBZcnWOcxDh7O0N/UwDEsHyqkW+Qh28jW+mVuCdx7gLB0BotYI1Y6uI9iyew==",
"dev": true
},
+ "prettier-linter-helpers": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz",
+ "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==",
+ "dev": true,
+ "requires": {
+ "fast-diff": "^1.1.2"
+ }
+ },
"pretty-bytes": {
"version": "5.3.0",
"resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.3.0.tgz",
diff --git a/package.json b/package.json
index ea808041..26fed6fa 100644
--- a/package.json
+++ b/package.json
@@ -20,6 +20,9 @@
"@types/nanoid": "2.1.0",
"@types/react": "16.9.19",
"@types/react-dom": "16.9.5",
+ "eslint": "6.8.0",
+ "eslint-config-prettier": "6.10.0",
+ "eslint-plugin-prettier": "3.1.2",
"husky": "4.2.1",
"lint-staged": "10.0.3",
"node-sass": "4.13.1",
@@ -28,10 +31,17 @@
"typescript": "3.7.5"
},
"eslintConfig": {
- "extends": "react-app",
+ "extends": [
+ "prettier",
+ "react-app"
+ ],
+ "plugins": [
+ "prettier"
+ ],
"rules": {
+ "curly": "error",
"no-console": [
- "warn",
+ "error",
{
"allow": [
"warn",
@@ -39,7 +49,17 @@
"info"
]
}
- ]
+ ],
+ "no-else-return": "error",
+ "no-useless-return": "error",
+ "prefer-const": [
+ "error",
+ {
+ "destructuring": "all"
+ }
+ ],
+ "prefer-template": "error",
+ "prettier/prettier": "error"
}
},
"homepage": "https://excalidraw.com",
@@ -54,12 +74,15 @@
"build": "react-scripts build",
"build-node": "./scripts/build-node.js",
"eject": "react-scripts eject",
- "fix": "npm run prettier -- --write",
- "prettier": "prettier \"**/*.{js,css,scss,json,md,ts,tsx,html,yml}\" --ignore-path=.eslintignore",
+ "fix": "npm run fix:other && npm run fix:code",
+ "fix:code": "npm run test:code -- --fix",
+ "fix:other": "npm run prettier -- --write",
+ "prettier": "prettier \"**/*.{css,scss,json,md,html,yml}\" --ignore-path=.eslintignore",
"start": "react-scripts start",
"test": "npm run test:app",
"test:app": "react-scripts test --env=jsdom --passWithNoTests",
- "test:code": "npm run prettier -- --list-different"
+ "test:code": "eslint --ignore-path .gitignore --ext .js,.ts,.tsx .",
+ "test:other": "npm run prettier -- --list-different"
},
"version": "1.0.0",
"license": "MIT",
diff --git a/src/actions/manager.tsx b/src/actions/manager.tsx
index ace170d9..399fd70d 100644
--- a/src/actions/manager.tsx
+++ b/src/actions/manager.tsx
@@ -37,7 +37,9 @@ export class ActionManager implements ActionsManagerInterface {
action => action.keyTest && action.keyTest(event, appState, elements),
);
- if (data.length === 0) return null;
+ if (data.length === 0) {
+ return null;
+ }
event.preventDefault();
return data[0].perform(elements, appState, null);
diff --git a/src/components/ColorPicker.tsx b/src/components/ColorPicker.tsx
index 7e670e8d..d505f0a3 100644
--- a/src/components/ColorPicker.tsx
+++ b/src/components/ColorPicker.tsx
@@ -109,7 +109,9 @@ const Picker = function({
{
- if (el) gallery.current = el;
+ if (el) {
+ gallery.current = el;
+ }
}}
>
{colors.map((_color, i) => (
@@ -124,8 +126,12 @@ const Picker = function({
style={{ backgroundColor: _color }}
key={_color}
ref={el => {
- if (el && i === 0) firstItem.current = el;
- if (el && _color === color) activeItem.current = el;
+ if (el && i === 0) {
+ firstItem.current = el;
+ }
+ if (el && _color === color) {
+ activeItem.current = el;
+ }
}}
onFocus={() => {
onChange(_color);
@@ -186,7 +192,7 @@ const ColorInput = React.forwardRef(
onChange={e => {
const value = e.target.value.toLowerCase();
if (value.match(colorRegex)) {
- onChange(value === "transparent" ? "transparent" : "#" + value);
+ onChange(value === "transparent" ? "transparent" : `#${value}`);
}
setInnerValue(value);
}}
diff --git a/src/components/ExportDialog.tsx b/src/components/ExportDialog.tsx
index 44589412..7eeaa895 100644
--- a/src/components/ExportDialog.tsx
+++ b/src/components/ExportDialog.tsx
@@ -178,7 +178,7 @@ function ExportModal({
key={s}
size="s"
type="radio"
- icon={"x" + s}
+ icon={`x${s}`}
name="export-canvas-scale"
aria-label={`Scale ${s} x`}
id="export-canvas-scale"
diff --git a/src/components/FixedSideContainer.tsx b/src/components/FixedSideContainer.tsx
index 8a49de51..cc37144a 100644
--- a/src/components/FixedSideContainer.tsx
+++ b/src/components/FixedSideContainer.tsx
@@ -12,7 +12,7 @@ export function FixedSideContainer({
side,
}: FixedSideContainerProps) {
return (
-
+
{children}
);
diff --git a/src/components/Popover.tsx b/src/components/Popover.tsx
index 7b76af14..6e62e03f 100644
--- a/src/components/Popover.tsx
+++ b/src/components/Popover.tsx
@@ -26,11 +26,11 @@ export function Popover({
const viewportWidth = window.innerWidth;
if (x + width > viewportWidth) {
- element.style.left = viewportWidth - width + "px";
+ element.style.left = `${viewportWidth - width}px`;
}
const viewportHeight = window.innerHeight;
if (y + height > viewportHeight) {
- element.style.top = viewportHeight - height + "px";
+ element.style.top = `${viewportHeight - height}px`;
}
}
}, [fitInViewport]);
@@ -42,7 +42,9 @@ export function Popover({
onClick={onCloseRequest}
onContextMenu={e => {
e.preventDefault();
- if (onCloseRequest) onCloseRequest();
+ if (onCloseRequest) {
+ onCloseRequest();
+ }
}}
/>
{children}
diff --git a/src/components/ProjectName.tsx b/src/components/ProjectName.tsx
index f13d154a..9696ab45 100644
--- a/src/components/ProjectName.tsx
+++ b/src/components/ProjectName.tsx
@@ -16,7 +16,9 @@ export class ProjectName extends Component
{
private handleBlur = (e: React.FocusEvent) => {
const value = e.currentTarget.innerText.trim();
- if (value !== this.props.value) this.props.onChange(value);
+ if (value !== this.props.value) {
+ this.props.onChange(value);
+ }
removeSelection();
};
diff --git a/src/components/ToolButton.tsx b/src/components/ToolButton.tsx
index 120a3f83..62c89c0b 100644
--- a/src/components/ToolButton.tsx
+++ b/src/components/ToolButton.tsx
@@ -35,7 +35,7 @@ export const ToolButton = React.forwardRef(function(
React.useImperativeHandle(ref, () => innerRef.current);
const sizeCn = `ToolIcon_size_${props.size || DEFAULT_SIZE}`;
- if (props.type === "button")
+ if (props.type === "button") {
return (
);
+ }
return (