{
    // Global
    "root": true,
    "parser": "@typescript-eslint/parser",
    "extends": [
        "eslint:recommended",
        "plugin:jest/recommended"
    ],
    "rules": {
        "indent": [
            "error",
            4,
            {
                "SwitchCase": 1
            }
        ],
        "quotes": [
            "error",
            "single"
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "eqeqeq": [
            "error",
            "smart"
        ],
        "prefer-const": [
            "error"
        ],
        "no-var": "error",
        "no-use-before-define": "off",
        "no-console": [
            "error",
            {
                "allow": [
                    "info",
                    "warn",
                    "error"
                ]
            }
        ],
        // Jest configuration
        "jest/expect-expect": [
            "error",
            {
                "assertFunctionNames": [
                    "expect*",
                    "checkImageData",
                    "testCode"
                ]
            }
        ]
    },
    "env": {
        "builtin": true,
        "browser": true,
        "es6": true
    },
    "overrides": [
        // All overrides matching a file are applied in-order, with the last
        // taking precedence.
        //
        // TypeScript/TSX-specific configuration
        {
            "files": [
                "*.ts",
                "*.tsx"
            ],
            "plugins": [
                "@typescript-eslint/eslint-plugin"
            ],
            "extends": [
                "plugin:react/recommended",
                "plugin:react-hooks/recommended",
                "plugin:@typescript-eslint/recommended",
                "plugin:@typescript-eslint/recommended-requiring-type-checking"
            ],
            "rules": {
                // recommended is just "warn"
                "@typescript-eslint/no-explicit-any": "error",
                // enforce semicolons at ends of statements
                "semi": "off",
                "@typescript-eslint/semi": [
                    "error",
                    "always"
                ],
                // enforce semicolons to separate members
                "@typescript-eslint/member-delimiter-style": [
                    "error",
                    {
                        "multiline": {
                            "delimiter": "semi",
                            "requireLast": true
                        },
                        "singleline": {
                            "delimiter": "semi",
                            "requireLast": false
                        }
                    }
                ],
                // definitions must come before uses for variables
                "@typescript-eslint/no-use-before-define": [
                    "error",
                    {
                        "functions": false,
                        "classes": false
                    }
                ],
                // no used variables
                "no-unused-vars": "off",
                "@typescript-eslint/no-unused-vars": [
                    "error",
                    {
                        "argsIgnorePattern": "^_"
                    }
                ],
                // no redeclaration of classes, members or variables
                "no-redeclare": "off",
                "@typescript-eslint/no-redeclare": [
                    "error"
                ],
                // allow empty interface definitions and empty extends
                "@typescript-eslint/no-empty-interface": "off",
                // allow explicit type declaration
                "@typescript-eslint/no-inferrable-types": "off",
                // allow some non-string types in templates
                "@typescript-eslint/restrict-template-expressions": [
                    "error",
                    {
                        "allowNumber": true,
                        "allowBoolean": true
                    }
                ],
                // react rules
                "react-hooks/rules-of-hooks": "error",
                "react-hooks/exhaustive-deps": "error"
            },
            "parserOptions": {
                "sourceType": "module",
                "project": "./tsconfig.json"
            }
        },
        // UI elements
        {
            "files": [
                "js/ui/**.ts"
            ],
            "rules": {
                // allow non-null assertions since these classes reference the DOM
                "@typescript-eslint/no-non-null-assertion": "off"
            }
        },
        // JS Node configuration
        {
            "files": [
                "bin/*",
                "babel.config.js",
                "webpack.config.js"
            ],
            "rules": {
                "no-console": 0
            },
            "env": {
                "node": true,
                "jquery": false,
                "browser": false
            }
        },
        // Test configuration
        {
            "files": [
                "test/**/*"
            ],
            "env": {
                "jest": true,
                "jasmine": true,
                "node": true
            },
            "rules": {
                "no-console": 0
            }
        },
        // Entry point configuration
        {
            "files": [
                "js/entry2.ts",
                "js/entry2e.ts",
                "jest.config.js"
            ],
            "env": {
                "commonjs": true
            }
        },
        // Worker configuration
        {
            "files": [
                "workers/*"
            ],
            "parserOptions": {
                "project": "workers/tsconfig.json"
            }
        }
    ],
    "ignorePatterns": [
        "coverage/**/*"
    ],
    "settings": {
        "react": {
            "pragma": "h",
            "version": "16"
        }
    }
}
