From 53994e71e5e1a94cb291925365a615094fd6fcd9 Mon Sep 17 00:00:00 2001
From: Lipis <lipiridis@gmail.com>
Date: Sun, 2 Feb 2020 20:04:35 +0200
Subject: [PATCH] Add more ESLint rules and change the formatting scripts
 (#626)

* Add curly rule in ESLint for consistency

* Fix rules

* More rules

* REturn

* Push

* no else return

* prefer const

* destructing
---
 .github/workflows/lint.yml            |  1 +
 .lintstagedrc.js                      |  5 +-
 package-lock.json                     | 41 ++++++++++++++
 package.json                          | 35 ++++++++++--
 src/actions/manager.tsx               |  4 +-
 src/components/ColorPicker.tsx        | 14 +++--
 src/components/ExportDialog.tsx       |  2 +-
 src/components/FixedSideContainer.tsx |  2 +-
 src/components/Popover.tsx            |  8 ++-
 src/components/ProjectName.tsx        |  4 +-
 src/components/ToolButton.tsx         |  3 +-
 src/element/collision.ts              | 25 +++++----
 src/element/handlerRectangles.ts      |  2 +-
 src/element/resizeTest.ts             |  8 ++-
 src/element/textWysiwyg.tsx           |  4 +-
 src/i18n.ts                           |  4 +-
 src/index.tsx                         | 79 +++++++++++++++++++--------
 src/renderer/renderElement.ts         |  4 +-
 src/renderer/renderScene.ts           | 20 ++++---
 src/scene/data.ts                     | 10 ++--
 src/shapes.tsx                        |  3 +-
 21 files changed, 201 insertions(+), 77 deletions(-)

diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
index 918bf8b3cd..a5e3c84f8f 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 87a02c84d8..18e1d218e9 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 c6dc04f433..1fc882dafc 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 ea80804179..26fed6faee 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 ace170d9e7..399fd70d4e 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 7e670e8d06..d505f0a323 100644
--- a/src/components/ColorPicker.tsx
+++ b/src/components/ColorPicker.tsx
@@ -109,7 +109,9 @@ const Picker = function({
         <div
           className="colors-gallery"
           ref={el => {
-            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 4458941260..7eeaa8957e 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 8a49de5159..cc37144a44 100644
--- a/src/components/FixedSideContainer.tsx
+++ b/src/components/FixedSideContainer.tsx
@@ -12,7 +12,7 @@ export function FixedSideContainer({
   side,
 }: FixedSideContainerProps) {
   return (
-    <div className={"FixedSideContainer FixedSideContainer_side_" + side}>
+    <div className={`FixedSideContainer FixedSideContainer_side_${side}`}>
       {children}
     </div>
   );
diff --git a/src/components/Popover.tsx b/src/components/Popover.tsx
index 7b76af14a3..6e62e03f2c 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 f13d154ade..9696ab45d5 100644
--- a/src/components/ProjectName.tsx
+++ b/src/components/ProjectName.tsx
@@ -16,7 +16,9 @@ export class ProjectName extends Component<Props> {
 
   private handleBlur = (e: React.FocusEvent<HTMLElement>) => {
     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 120a3f83f7..62c89c0b69 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 (
       <button
         className={`ToolIcon_type_button ToolIcon ${sizeCn}`}
@@ -50,6 +50,7 @@ export const ToolButton = React.forwardRef(function(
         </div>
       </button>
     );
+  }
 
   return (
     <label className="ToolIcon" title={props.title}>
diff --git a/src/element/collision.ts b/src/element/collision.ts
index 97965f02da..9133f39330 100644
--- a/src/element/collision.ts
+++ b/src/element/collision.ts
@@ -61,9 +61,8 @@ export function hitTest(
       return (
         a * tx - (px - lineThreshold) >= 0 && b * ty - (py - lineThreshold) >= 0
       );
-    } else {
-      return Math.hypot(a * tx - px, b * ty - py) < lineThreshold;
     }
+    return Math.hypot(a * tx - px, b * ty - py) < lineThreshold;
   } else if (element.type === "rectangle") {
     const [x1, y1, x2, y2] = getElementAbsoluteCoords(element);
 
@@ -88,7 +87,6 @@ export function hitTest(
   } else if (element.type === "diamond") {
     x -= element.x;
     y -= element.y;
-
     let [
       topX,
       topY,
@@ -102,8 +100,12 @@ export function hitTest(
 
     if (isElementDraggableFromInside(element)) {
       // TODO: remove this when we normalize coordinates globally
-      if (topY > bottomY) [bottomY, topY] = [topY, bottomY];
-      if (rightX < leftX) [leftX, rightX] = [rightX, leftX];
+      if (topY > bottomY) {
+        [bottomY, topY] = [topY, bottomY];
+      }
+      if (rightX < leftX) {
+        [leftX, rightX] = [rightX, leftX];
+      }
 
       topY -= lineThreshold;
       bottomY += lineThreshold;
@@ -153,10 +155,14 @@ export function hitTest(
     const shape = element.shape as Drawable[];
     // If shape does not consist of curve and two line segments
     // for arrow shape, return false
-    if (shape.length < 3) return false;
+    if (shape.length < 3) {
+      return false;
+    }
 
     const [x1, y1, x2, y2] = getArrowAbsoluteBounds(element);
-    if (x < x1 || y < y1 - 10 || x > x2 || y > y2 + 10) return false;
+    if (x < x1 || y < y1 - 10 || x > x2 || y > y2 + 10) {
+      return false;
+    }
 
     const relX = x - element.x;
     const relY = y - element.y;
@@ -181,9 +187,8 @@ export function hitTest(
   } else if (element.type === "selection") {
     console.warn("This should not happen, we need to investigate why it does.");
     return false;
-  } else {
-    throw new Error("Unimplemented type " + element.type);
   }
+  throw new Error(`Unimplemented type ${element.type}`);
 }
 
 const pointInBezierEquation = (
@@ -249,7 +254,7 @@ const hitTestRoughShape = (opSet: OpSet[], x: number, y: number) => {
       // check if points are on the curve
       // cubic bezier curves require four parameters
       // the first parameter is the last stored position (p0)
-      let retVal = pointInBezierEquation(p0, p1, p2, p3, [x, y]);
+      const retVal = pointInBezierEquation(p0, p1, p2, p3, [x, y]);
 
       // set end point of bezier curve as the new starting point for
       // upcoming operations as each operation is based on the last drawn
diff --git a/src/element/handlerRectangles.ts b/src/element/handlerRectangles.ts
index d202fd81bd..a12842a39f 100644
--- a/src/element/handlerRectangles.ts
+++ b/src/element/handlerRectangles.ts
@@ -15,7 +15,7 @@ export function handlerRectangles(
   let marginX = -8;
   let marginY = -8;
 
-  let minimumSize = 40;
+  const minimumSize = 40;
   if (element.type === "arrow") {
     [elementX1, elementY1, elementX2, elementY2] = getArrowAbsoluteBounds(
       element,
diff --git a/src/element/resizeTest.ts b/src/element/resizeTest.ts
index 532b9b94f7..3d7ae80752 100644
--- a/src/element/resizeTest.ts
+++ b/src/element/resizeTest.ts
@@ -11,13 +11,17 @@ export function resizeTest(
   y: number,
   { scrollX, scrollY }: SceneScroll,
 ): HandlerRectanglesRet | false {
-  if (!element.isSelected || element.type === "text") return false;
+  if (!element.isSelected || element.type === "text") {
+    return false;
+  }
 
   const handlers = handlerRectangles(element, { scrollX, scrollY });
 
   const filter = Object.keys(handlers).filter(key => {
     const handler = handlers[key as HandlerRectanglesRet]!;
-    if (!handler) return false;
+    if (!handler) {
+      return false;
+    }
 
     return (
       x + scrollX >= handler[0] &&
diff --git a/src/element/textWysiwyg.tsx b/src/element/textWysiwyg.tsx
index cdeeac21ca..ba6e6eaf8f 100644
--- a/src/element/textWysiwyg.tsx
+++ b/src/element/textWysiwyg.tsx
@@ -41,8 +41,8 @@ export function textWysiwyg({
     color: strokeColor,
     position: "fixed",
     opacity: opacity / 100,
-    top: y + "px",
-    left: x + "px",
+    top: `${y}px`,
+    left: `${x}px`,
     transform: "translate(-50%, -50%)",
     textAlign: "left",
     display: "inline-block",
diff --git a/src/i18n.ts b/src/i18n.ts
index 5a40e32cd5..1889af33f8 100644
--- a/src/i18n.ts
+++ b/src/i18n.ts
@@ -43,12 +43,12 @@ export function t(path: string, replacement?: { [key: string]: string }) {
     findPartsForData(currentLanguage.data, parts) ||
     findPartsForData(fallbackLanguage.data, parts);
   if (translation === undefined) {
-    throw new Error("Can't find translation for " + path);
+    throw new Error(`Can't find translation for ${path}`);
   }
 
   if (replacement) {
     for (var key in replacement) {
-      translation = translation.replace("{{" + key + "}}", replacement[key]);
+      translation = translation.replace(`{{${key}}}`, replacement[key]);
     }
   }
   return translation;
diff --git a/src/index.tsx b/src/index.tsx
index 55cc28bc26..98f10edffd 100644
--- a/src/index.tsx
+++ b/src/index.tsx
@@ -221,7 +221,9 @@ export class App extends React.Component<any, AppState> {
   };
 
   private onCut = (e: ClipboardEvent) => {
-    if (isInputLike(e.target) && !isToolIcon(e.target)) return;
+    if (isInputLike(e.target) && !isToolIcon(e.target)) {
+      return;
+    }
     e.clipboardData?.setData(
       "text/plain",
       JSON.stringify(
@@ -235,7 +237,9 @@ export class App extends React.Component<any, AppState> {
     e.preventDefault();
   };
   private onCopy = (e: ClipboardEvent) => {
-    if (isInputLike(e.target) && !isToolIcon(e.target)) return;
+    if (isInputLike(e.target) && !isToolIcon(e.target)) {
+      return;
+    }
     e.clipboardData?.setData(
       "text/plain",
       JSON.stringify(
@@ -247,7 +251,9 @@ export class App extends React.Component<any, AppState> {
     e.preventDefault();
   };
   private onPaste = (e: ClipboardEvent) => {
-    if (isInputLike(e.target) && !isToolIcon(e.target)) return;
+    if (isInputLike(e.target) && !isToolIcon(e.target)) {
+      return;
+    }
     const paste = e.clipboardData?.getData("text") || "";
     this.addElementsFromPaste(paste);
     e.preventDefault();
@@ -339,7 +345,9 @@ export class App extends React.Component<any, AppState> {
   };
 
   private onKeyDown = (event: KeyboardEvent) => {
-    if (isInputLike(event.target) && event.key !== KEYS.ESCAPE) return;
+    if (isInputLike(event.target) && event.key !== KEYS.ESCAPE) {
+      return;
+    }
 
     const actionResult = this.actionManager.handleKeyDown(
       event,
@@ -349,7 +357,9 @@ export class App extends React.Component<any, AppState> {
 
     if (actionResult) {
       this.syncActionResult(actionResult);
-      if (actionResult) return;
+      if (actionResult) {
+        return;
+      }
     }
 
     const shape = findShapeByKey(event.key);
@@ -361,10 +371,15 @@ export class App extends React.Component<any, AppState> {
       elements = elements.map(el => {
         if (el.isSelected) {
           const element = { ...el };
-          if (event.key === KEYS.ARROW_LEFT) element.x -= step;
-          else if (event.key === KEYS.ARROW_RIGHT) element.x += step;
-          else if (event.key === KEYS.ARROW_UP) element.y -= step;
-          else if (event.key === KEYS.ARROW_DOWN) element.y += step;
+          if (event.key === KEYS.ARROW_LEFT) {
+            element.x -= step;
+          } else if (event.key === KEYS.ARROW_RIGHT) {
+            element.x += step;
+          } else if (event.key === KEYS.ARROW_UP) {
+            element.y -= step;
+          } else if (event.key === KEYS.ARROW_DOWN) {
+            element.y += step;
+          }
           return element;
         }
         return el;
@@ -602,13 +617,14 @@ export class App extends React.Component<any, AppState> {
             actionManager={this.actionManager}
             syncActionResult={this.syncActionResult}
             onExportToPng={(exportedElements, scale) => {
-              if (this.canvas)
+              if (this.canvas) {
                 exportCanvas("png", exportedElements, this.canvas, {
                   exportBackground: this.state.exportBackground,
                   name: this.state.name,
                   viewBackgroundColor: this.state.viewBackgroundColor,
                   scale,
                 });
+              }
             }}
             onExportToSvg={(exportedElements, scale) => {
               if (this.canvas) {
@@ -621,16 +637,17 @@ export class App extends React.Component<any, AppState> {
               }
             }}
             onExportToClipboard={(exportedElements, scale) => {
-              if (this.canvas)
+              if (this.canvas) {
                 exportCanvas("clipboard", exportedElements, this.canvas, {
                   exportBackground: this.state.exportBackground,
                   name: this.state.name,
                   viewBackgroundColor: this.state.viewBackgroundColor,
                   scale,
                 });
+              }
             }}
             onExportToBackend={exportedElements => {
-              if (this.canvas)
+              if (this.canvas) {
                 exportCanvas(
                   "backend",
                   exportedElements.map(element => ({
@@ -640,6 +657,7 @@ export class App extends React.Component<any, AppState> {
                   this.canvas,
                   this.state,
                 );
+              }
             }}
           />
           {this.actionManager.renderAction(
@@ -813,7 +831,9 @@ export class App extends React.Component<any, AppState> {
                 lastMouseUp(e);
               }
 
-              if (isPanning) return;
+              if (isPanning) {
+                return;
+              }
 
               // pan canvas on wheel button drag or space+drag
               if (
@@ -826,8 +846,8 @@ export class App extends React.Component<any, AppState> {
                 document.documentElement.style.cursor = CURSOR_TYPE.GRABBING;
                 let { clientX: lastX, clientY: lastY } = e;
                 const onMouseMove = (e: MouseEvent) => {
-                  let deltaX = lastX - e.clientX;
-                  let deltaY = lastY - e.clientY;
+                  const deltaX = lastX - e.clientX;
+                  const deltaY = lastY - e.clientY;
                   lastX = e.clientX;
                   lastY = e.clientY;
                   // We don't want to save history when panning around
@@ -857,7 +877,9 @@ export class App extends React.Component<any, AppState> {
               }
 
               // only handle left mouse button
-              if (e.button !== MOUSE_BUTTON.MAIN) return;
+              if (e.button !== MOUSE_BUTTON.MAIN) {
+                return;
+              }
               // fixes mousemove causing selection of UI texts #32
               e.preventDefault();
               // Preventing the event above disables default behavior
@@ -1080,7 +1102,7 @@ export class App extends React.Component<any, AppState> {
                   const absPx = p1[0] + element.x;
                   const absPy = p1[1] + element.y;
 
-                  let { width, height } = getPerfectElementSize(
+                  const { width, height } = getPerfectElementSize(
                     "arrow",
                     mouseX - element.x - p1[0],
                     mouseY - element.y - p1[1],
@@ -1155,8 +1177,9 @@ export class App extends React.Component<any, AppState> {
                 //  triggering mousemove)
                 if (!draggingOccurred && this.state.elementType === "arrow") {
                   const { x, y } = viewportCoordsToSceneCoords(e, this.state);
-                  if (distance2d(x, y, originX, originY) < DRAGGING_THRESHOLD)
+                  if (distance2d(x, y, originX, originY) < DRAGGING_THRESHOLD) {
                     return;
+                  }
                 }
 
                 if (isResizingElements && this.state.resizingElement) {
@@ -1432,7 +1455,9 @@ export class App extends React.Component<any, AppState> {
                 // It is very important to read this.state within each move event,
                 // otherwise we would read a stale one!
                 const draggingElement = this.state.draggingElement;
-                if (!draggingElement) return;
+                if (!draggingElement) {
+                  return;
+                }
 
                 const { x, y } = viewportCoordsToSceneCoords(e, this.state);
 
@@ -1443,8 +1468,12 @@ export class App extends React.Component<any, AppState> {
                   this.state.elementType === "line" ||
                   this.state.elementType === "arrow";
 
-                if (isLinear && x < originX) width = -width;
-                if (isLinear && y < originY) height = -height;
+                if (isLinear && x < originX) {
+                  width = -width;
+                }
+                if (isLinear && y < originY) {
+                  height = -height;
+                }
 
                 if (e.shiftKey) {
                   ({ width, height } = getPerfectElementSize(
@@ -1453,7 +1482,9 @@ export class App extends React.Component<any, AppState> {
                     !isLinear && y < originY ? -height : height,
                   ));
 
-                  if (!isLinear && height < 0) height = -height;
+                  if (!isLinear && height < 0) {
+                    height = -height;
+                  }
                 }
 
                 if (!isLinear) {
@@ -1724,7 +1755,9 @@ export class App extends React.Component<any, AppState> {
               });
             }}
             onMouseMove={e => {
-              if (isHoldingSpace || isPanning) return;
+              if (isHoldingSpace || isPanning) {
+                return;
+              }
               const hasDeselectedButton = Boolean(e.buttons);
               if (
                 hasDeselectedButton ||
diff --git a/src/renderer/renderElement.ts b/src/renderer/renderElement.ts
index 0e9d175ab7..e42c871db5 100644
--- a/src/renderer/renderElement.ts
+++ b/src/renderer/renderElement.ts
@@ -176,7 +176,7 @@ export function renderElement(
         context.font = font;
         context.globalAlpha = 1;
       } else {
-        throw new Error("Unimplemented type " + element.type);
+        throw new Error(`Unimplemented type ${element.type}`);
       }
     }
   }
@@ -267,7 +267,7 @@ export function renderElementToSvg(
         }
         svgRoot.appendChild(node);
       } else {
-        throw new Error("Unimplemented type " + element.type);
+        throw new Error(`Unimplemented type ${element.type}`);
       }
     }
   }
diff --git a/src/renderer/renderScene.ts b/src/renderer/renderScene.ts
index 096392520e..c63073bc8e 100644
--- a/src/renderer/renderScene.ts
+++ b/src/renderer/renderScene.ts
@@ -32,7 +32,9 @@ export function renderScene(
     renderSelection?: boolean;
   } = {},
 ) {
-  if (!canvas) return false;
+  if (!canvas) {
+    return false;
+  }
   const context = canvas.getContext("2d")!;
 
   const fillStyle = context.fillStyle;
@@ -130,7 +132,7 @@ export function renderScene(
     context.fillStyle = SCROLLBAR_COLOR;
     context.strokeStyle = "rgba(255,255,255,0.8)";
     [scrollBars.horizontal, scrollBars.vertical].forEach(scrollBar => {
-      if (scrollBar)
+      if (scrollBar) {
         roundRect(
           context,
           scrollBar.x,
@@ -139,6 +141,7 @@ export function renderScene(
           scrollBar.height,
           SCROLLBAR_WIDTH / 2,
         );
+      }
     });
     context.strokeStyle = strokeStyle;
     context.fillStyle = fillStyle;
@@ -161,14 +164,13 @@ function isVisibleElement(
     x2 += scrollX;
     y2 += scrollY;
     return x2 >= 0 && x1 <= canvasWidth && y2 >= 0 && y1 <= canvasHeight;
-  } else {
-    return (
-      x2 + scrollX >= 0 &&
-      x1 + scrollX <= canvasWidth &&
-      y2 + scrollY >= 0 &&
-      y1 + scrollY <= canvasHeight
-    );
   }
+  return (
+    x2 + scrollX >= 0 &&
+    x1 + scrollX <= canvasWidth &&
+    y2 + scrollY >= 0 &&
+    y1 + scrollY <= canvasHeight
+  );
 }
 
 // This should be only called for exporting purposes
diff --git a/src/scene/data.ts b/src/scene/data.ts
index efe69cdd3c..4f2a713b15 100644
--- a/src/scene/data.ts
+++ b/src/scene/data.ts
@@ -49,7 +49,7 @@ export function serializeAsJSON(
 export function calculateScrollCenter(
   elements: readonly ExcalidrawElement[],
 ): { scrollX: number; scrollY: number } {
-  let [x1, y1, x2, y2] = getCommonBounds(elements);
+  const [x1, y1, x2, y2] = getCommonBounds(elements);
 
   const centerX = (x1 + x2) / 2;
   const centerY = (y1 + y2) / 2;
@@ -149,7 +149,6 @@ export async function exportToBackend(
     }
   } catch (e) {
     window.alert(t("alerts.couldNotCreateShareableLink"));
-    return;
   }
 }
 
@@ -194,8 +193,9 @@ export async function exportCanvas(
     scale?: number;
   },
 ) {
-  if (!elements.length)
+  if (!elements.length) {
     return window.alert(t("alerts.cannotExportEmptyCanvas"));
+  }
   // calculate smallest area to fit the contents in
 
   if (type === "svg") {
@@ -252,7 +252,9 @@ export async function exportCanvas(
   }
 
   // clean up the DOM
-  if (tempCanvas !== canvas) tempCanvas.remove();
+  if (tempCanvas !== canvas) {
+    tempCanvas.remove();
+  }
 }
 
 function restore(
diff --git a/src/shapes.tsx b/src/shapes.tsx
index 942e018bc4..91db7faaf6 100644
--- a/src/shapes.tsx
+++ b/src/shapes.tsx
@@ -75,8 +75,9 @@ export const shapesShortcutKeys = SHAPES.map((shape, index) => [
 export function findShapeByKey(key: string) {
   const defaultElement = "selection";
   return SHAPES.reduce((element, shape, index) => {
-    if (shape.value[0] !== key && key !== (index + 1).toString())
+    if (shape.value[0] !== key && key !== (index + 1).toString()) {
       return element;
+    }
 
     return shape.value;
   }, defaultElement);