diff --git a/.eslintrc.json b/.eslintrc.json index 14c4ada..426b9a4 100644 --- a/.eslintrc.json +++ b/.eslintrc.json @@ -1,62 +1,133 @@ { - "env": { - "browser": true, - "es2021": true - }, + "root": true, + "parser": "@typescript-eslint/parser", "extends": [ "eslint:recommended", - "plugin:react/recommended", - "plugin:react/jsx-runtime", - "plugin:react-hooks/recommended", - "plugin:@typescript-eslint/recommended", + "plugin:@typescript-eslint/strict-type-checked", + "plugin:@typescript-eslint/stylistic-type-checked", "plugin:import/recommended", "plugin:import/typescript", + "plugin:react/recommended", + "plugin:react-hooks/recommended", + "plugin:jsx-a11y/strict", "prettier" ], - "parser": "@typescript-eslint/parser", "parserOptions": { - "ecmaFeatures": { - "jsx": true - }, "ecmaVersion": "latest", - "sourceType": "module" + "project": true }, - "plugins": ["react", "@typescript-eslint", "import"], + "plugins": ["@typescript-eslint", "import", "react", "jsx-a11y", "react-refresh", "no-array-concat"], "settings": { - "react": { - "version": "detect" - } + "import/core-modules": ["react", "react-dom", "react-dom/client"] }, "rules": { - "@typescript-eslint/no-unused-expressions": [ + "default-case-last": "error", + "eqeqeq": "error", + "func-style": ["error", "declaration"], + "grouped-accessor-pairs": ["error", "getBeforeSet"], + "logical-assignment-operators": "error", + "no-array-concat/no-array-concat": "error", + "no-constant-binary-expression": "error", + "no-control-regex": "off", + "no-irregular-whitespace": [ "error", { - "allowShortCircuit": true, - "allowTaggedTemplates": true + "skipStrings": true, + "skipComments": true, + "skipRegExps": true, + "skipTemplates": true, + "skipJSXText": true } ], + "no-negated-condition": "warn", + "no-self-compare": "error", + "no-template-curly-in-string": "warn", + "no-undef-init": "error", + "no-unmodified-loop-condition": "warn", + "no-unneeded-ternary": "error", + "no-unreachable-loop": "warn", + "no-useless-computed-key": "error", + "no-useless-concat": "error", + "no-useless-return": "error", + "no-var": "error", + "operator-assignment": "error", + "prefer-const": "error", + "prefer-exponentiation-operator": "error", + "prefer-object-spread": "error", + "prefer-regex-literals": "error", + "prefer-rest-params": "error", + "prefer-template": "warn", + "@typescript-eslint/consistent-type-exports": "error", + "@typescript-eslint/default-param-last": "error", + "@typescript-eslint/no-confusing-void-expression": "off", + "@typescript-eslint/no-loop-func": "warn", + "@typescript-eslint/no-misused-promises": ["error", { "checksVoidReturn": false }], + "@typescript-eslint/no-non-null-assertion": "off", + "@typescript-eslint/no-unnecessary-qualifier": "error", + "@typescript-eslint/no-useless-empty-export": "error", + "@typescript-eslint/parameter-properties": ["error", { "prefer": "parameter-property" }], + "@typescript-eslint/prefer-nullish-coalescing": "off", + "@typescript-eslint/prefer-regexp-exec": "error", + "@typescript-eslint/prefer-string-starts-ends-with": "off", + "@typescript-eslint/require-await": "off", + "@typescript-eslint/restrict-plus-operands": [ + "error", + { + "allowAny": true, + "allowBoolean": true, + "allowNumberAndString": true + } + ], + "@typescript-eslint/restrict-template-expressions": [ + "error", + { + "allowAny": true, + "allowBoolean": true, + "allowNumber": true, + "allowNever": true + } + ], + + "import/consistent-type-specifier-style": ["error", "prefer-top-level"], + "import/extensions": "error", + "import/first": "error", + "import/newline-after-import": "error", + "import/no-absolute-path": "error", + "import/no-anonymous-default-export": ["warn", { "allowCallExpression": false }], + "import/no-extraneous-dependencies": [ + "error", + { + "devDependencies": ["*.config.ts"], + "includeInternal": true, + "includeTypes": true + } + ], + "import/no-named-default": "error", + "import/no-self-import": "error", + "import/no-unresolved": ["error", { "ignore": ["\\?(?:worker(&inline|&url)?|raw)$"] }], + "import/no-useless-path-segments": ["error", { "noUselessIndex": true }], "import/order": [ "error", { - "groups": [["builtin", "external"], "internal", ["parent", "sibling", "index"], "type", "unknown", "object"], + "groups": ["builtin", "external", "internal", ["parent", "sibling", "index"], "type", "unknown", "object"], "pathGroups": [ - { - "pattern": "{react,react-dom,react-dom/client}", - "group": "builtin", - "position": "before" - }, { "pattern": "@**/**", "group": "external", "position": "after" } ], - "pathGroupsExcludedImportTypes": ["{react,react-dom,react-dom/client}", "@**/**"], + "pathGroupsExcludedImportTypes": ["@**/**"], "newlines-between": "always", - "alphabetize": { "order": "asc", "caseInsensitive": true } + "alphabetize": { "order": "asc", "orderImportKind": "asc", "caseInsensitive": true }, + "warnOnUnassignedImports": true } ], - "import/no-unresolved": ["error", { "ignore": ["\\?(?:worker(&inline|&url)?|raw)$"] }] + + "react/react-in-jsx-scope": "off", + "react/prop-types": "off", + + "react-refresh/only-export-components": ["warn", { "allowConstantExport": true }] } } diff --git a/package-lock.json b/package-lock.json index cdf1bcd..8b45b62 100644 --- a/package-lock.json +++ b/package-lock.json @@ -41,8 +41,11 @@ "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "^3.6.3", "eslint-plugin-import": "^2.30.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-no-array-concat": "^0.1.2", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.12", "patch-package": "^8.0.0", "prettier": "^3.3.3", "typescript": "^5.6.2", @@ -1546,6 +1549,12 @@ "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==", "dev": true }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==", + "dev": true + }, "node_modules/@types/json5": { "version": "0.0.29", "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", @@ -1595,6 +1604,12 @@ "@types/react": "*" } }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, "node_modules/@types/wicg-file-system-access": { "version": "2023.10.5", "resolved": "https://registry.npmjs.org/@types/wicg-file-system-access/-/wicg-file-system-access-2023.10.5.tgz", @@ -1885,6 +1900,15 @@ "dev": true, "license": "Python-2.0" }, + "node_modules/aria-query": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", + "integrity": "sha512-R5iJ5lkuHybztUfuOAznmboyjWq8O6sqNqtK7CLOqdydi54VNbORp49mb14KbWgG1QD3JFO9hJdZ+y4KutfdOQ==", + "dev": true, + "dependencies": { + "deep-equal": "^2.0.5" + } + }, "node_modules/array-buffer-byte-length": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz", @@ -1923,6 +1947,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/array.prototype.findlast": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", @@ -2043,6 +2076,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/ast-types-flow": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ast-types-flow/-/ast-types-flow-0.0.8.tgz", + "integrity": "sha512-OH/2E5Fg20h2aPrbe+QL8JZQFko0YZaF+j4mnQ7BGhfavO7OpSLa8a0y9sBwomHdSbkhTS8TQNayBfnW5DwbvQ==", + "dev": true + }, "node_modules/at-least-node": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", @@ -2069,6 +2108,24 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/axe-core": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/axe-core/-/axe-core-4.10.0.tgz", + "integrity": "sha512-Mr2ZakwQ7XUAjp7pAwQWRhhK8mQQ6JAaNWSjmjxil0R8BPioMtQsTLOolGYkji1rcL++3dCqZA3zWqpT+9Ew6g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/axobject-query": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.1.0.tgz", + "integrity": "sha512-qIj0G9wZbMGNLjLmg1PT6v2mE9AH2zlnADJD/2tC6E00hgmhUOfEB6greHPAfLRSufHqROIUTkw6E+M3lH0PTQ==", + "dev": true, + "engines": { + "node": ">= 0.4" + } + }, "node_modules/babel-plugin-macros": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/babel-plugin-macros/-/babel-plugin-macros-3.1.0.tgz", @@ -2300,6 +2357,12 @@ "integrity": "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==", "license": "MIT" }, + "node_modules/damerau-levenshtein": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/damerau-levenshtein/-/damerau-levenshtein-1.0.8.tgz", + "integrity": "sha512-sdQSFB7+llfUcQHUQO3+B8ERRj0Oa4w9POWMI/puGtuf7gFywGmkaLCElnudfTiKZV+NvHqL0ifzdrI8Ro7ESA==", + "dev": true + }, "node_modules/data-view-buffer": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/data-view-buffer/-/data-view-buffer-1.0.1.tgz", @@ -2371,6 +2434,38 @@ } } }, + "node_modules/deep-equal": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz", + "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==", + "dev": true, + "dependencies": { + "array-buffer-byte-length": "^1.0.0", + "call-bind": "^1.0.5", + "es-get-iterator": "^1.1.3", + "get-intrinsic": "^1.2.2", + "is-arguments": "^1.1.1", + "is-array-buffer": "^3.0.2", + "is-date-object": "^1.0.5", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.2", + "isarray": "^2.0.5", + "object-is": "^1.1.5", + "object-keys": "^1.1.1", + "object.assign": "^4.1.4", + "regexp.prototype.flags": "^1.5.1", + "side-channel": "^1.0.4", + "which-boxed-primitive": "^1.0.2", + "which-collection": "^1.0.1", + "which-typed-array": "^1.1.13" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/deep-is": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", @@ -2414,6 +2509,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/doctrine": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", @@ -2434,6 +2541,12 @@ "dev": true, "license": "ISC" }, + "node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "dev": true + }, "node_modules/enhanced-resolve": { "version": "5.17.1", "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", @@ -2541,6 +2654,26 @@ "node": ">= 0.4" } }, + "node_modules/es-get-iterator": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz", + "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.3", + "has-symbols": "^1.0.3", + "is-arguments": "^1.1.1", + "is-map": "^2.0.2", + "is-set": "^2.0.2", + "is-string": "^1.0.7", + "isarray": "^2.0.5", + "stop-iteration-iterator": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/es-iterator-helpers": { "version": "1.0.19", "resolved": "https://registry.npmjs.org/es-iterator-helpers/-/es-iterator-helpers-1.0.19.tgz", @@ -2739,6 +2872,19 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-ast-utils": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/eslint-ast-utils/-/eslint-ast-utils-1.1.0.tgz", + "integrity": "sha512-otzzTim2/1+lVrlH19EfQQJEhVJSu0zOb9ygb3iapN6UlyaDtyRq4b5U1FuW0v1lRa9Fp/GJyHkSwm6NqABgCA==", + "dev": true, + "dependencies": { + "lodash.get": "^4.4.2", + "lodash.zip": "^4.2.0" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/eslint-config-prettier": { "version": "9.1.0", "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", @@ -2926,6 +3072,190 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-jsx-a11y": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.0.tgz", + "integrity": "sha512-ySOHvXX8eSN6zz8Bywacm7CvGNhUtdjvqfQDVe6020TUK34Cywkw7m0KsCCk1Qtm9G1FayfTN1/7mMYnYO2Bhg==", + "dev": true, + "dependencies": { + "aria-query": "~5.1.3", + "array-includes": "^3.1.8", + "array.prototype.flatmap": "^1.3.2", + "ast-types-flow": "^0.0.8", + "axe-core": "^4.10.0", + "axobject-query": "^4.1.0", + "damerau-levenshtein": "^1.0.8", + "emoji-regex": "^9.2.2", + "es-iterator-helpers": "^1.0.19", + "hasown": "^2.0.2", + "jsx-ast-utils": "^3.3.5", + "language-tags": "^1.0.9", + "minimatch": "^3.1.2", + "object.fromentries": "^2.0.8", + "safe-regex-test": "^1.0.3", + "string.prototype.includes": "^2.0.0" + }, + "engines": { + "node": ">=4.0" + }, + "peerDependencies": { + "eslint": "^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/eslint-plugin-jsx-a11y/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/eslint-plugin-no-array-concat": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-array-concat/-/eslint-plugin-no-array-concat-0.1.2.tgz", + "integrity": "sha512-HCduSzDF3KeJAp6wGWVf2WBj3f1LO+L3r4Ug2SWIX5zn6vPQnfXus0egBTCYXsjvswsOAR/QlYLxdS1k0rBvUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/utils": "^5.12.0", + "eslint-ast-utils": "^1.1.0" + } + }, + "node_modules/eslint-plugin-no-array-concat/node_modules/@typescript-eslint/scope-manager": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.62.0.tgz", + "integrity": "sha512-VXuvVvZeQCQb5Zgf4HAxc04q5j+WrNAtNh9OwCsCgpKqESMTu3tF/jhZ3xG6T4NZwWl65Bg8KuS2uEvhSfLl0w==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-no-array-concat/node_modules/@typescript-eslint/types": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.62.0.tgz", + "integrity": "sha512-87NVngcbVXUahrRTqIK27gD2t5Cu1yuCXxbLcFtCzZGlfyVWWh8mLHkoxzjsB6DDNnvdL+fW8MiwPEJyGJQDgQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-no-array-concat/node_modules/@typescript-eslint/typescript-estree": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.62.0.tgz", + "integrity": "sha512-CmcQ6uY7b9y694lKdRB8FEel7JbU/40iSAPomu++SjLMntB+2Leay2LO6i8VnJk58MtE9/nQSFIH6jpyRWyYzA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/visitor-keys": "5.62.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/eslint-plugin-no-array-concat/node_modules/@typescript-eslint/utils": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.62.0.tgz", + "integrity": "sha512-n8oxjeb5aIbPFEtmQxQYOLI0i9n5ySBEY/ZEHHZqKQSFnxio1rv6dthascc9dLuwrL0RC5mPCxB7vnAVGAYWAQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.62.0", + "@typescript-eslint/types": "5.62.0", + "@typescript-eslint/typescript-estree": "5.62.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/eslint-plugin-no-array-concat/node_modules/@typescript-eslint/visitor-keys": { + "version": "5.62.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.62.0.tgz", + "integrity": "sha512-07ny+LHRzQXepkGg6w0mFY41fVUNBrL2Roj/++7V1txKugfjm/Ci/qSND03r2RhlJhJYMcTn9AhhSSqQp0Ysyw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.62.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/eslint-plugin-no-array-concat/node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-plugin-no-array-concat/node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, "node_modules/eslint-plugin-react": { "version": "7.37.0", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.37.0.tgz", @@ -2971,6 +3301,15 @@ "eslint": "^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0" } }, + "node_modules/eslint-plugin-react-refresh": { + "version": "0.4.12", + "resolved": "https://registry.npmjs.org/eslint-plugin-react-refresh/-/eslint-plugin-react-refresh-0.4.12.tgz", + "integrity": "sha512-9neVjoGv20FwYtCP6CB1dzR1vr57ZDNOXst21wd2xJ/cTlM2xLq0GWVlSNTdMn/4BtP6cHYBMCSp1wFBJ9jBsg==", + "dev": true, + "peerDependencies": { + "eslint": ">=7" + } + }, "node_modules/eslint-plugin-react/node_modules/brace-expansion": { "version": "1.1.11", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", @@ -3620,6 +3959,35 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/globby/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -3812,6 +4180,22 @@ "node": ">= 0.4" } }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/is-array-buffer": { "version": "3.0.4", "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz", @@ -4408,6 +4792,24 @@ "graceful-fs": "^4.1.11" } }, + "node_modules/language-subtag-registry": { + "version": "0.3.23", + "resolved": "https://registry.npmjs.org/language-subtag-registry/-/language-subtag-registry-0.3.23.tgz", + "integrity": "sha512-0K65Lea881pHotoGEa5gDlMxt3pctLi2RplBb7Ezh4rRdLEOtgi7n4EwK9lamnUCkKBqaeKRVebTq6BAxSkpXQ==", + "dev": true + }, + "node_modules/language-tags": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/language-tags/-/language-tags-1.0.9.tgz", + "integrity": "sha512-MbjN408fEndfiQXbFQ1vnd+1NoLDsnQW41410oQBXiyXDMYH5z505juWa4KUE1LqxRC7DgOgZDbKLxHIwm27hA==", + "dev": true, + "dependencies": { + "language-subtag-registry": "^0.3.20" + }, + "engines": { + "node": ">=0.10" + } + }, "node_modules/levn": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", @@ -4444,6 +4846,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", @@ -4451,6 +4859,12 @@ "dev": true, "license": "MIT" }, + "node_modules/lodash.zip": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/lodash.zip/-/lodash.zip-4.2.0.tgz", + "integrity": "sha512-C7IOaBBK/0gMORRBd8OETNx3kmOkgIWIPvyDpZSCTwUrpYmgZwJkjZeOD8ww4xbOUOs4/attY+pciKvadNfFbg==", + "dev": true + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -4587,6 +5001,22 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/object-is": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz", + "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==", + "dev": true, + "dependencies": { + "call-bind": "^1.0.7", + "define-properties": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, "node_modules/object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -5489,6 +5919,28 @@ "integrity": "sha512-HTEHMNieakEnoe33shBYcZ7NX83ACUjCu8c40iOGEZsngj9zRnkqS9j1pqQPXwobB0ZcVTk27REb7COQ0UR59w==", "license": "MIT" }, + "node_modules/stop-iteration-iterator": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz", + "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==", + "dev": true, + "dependencies": { + "internal-slot": "^1.0.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/string.prototype.includes": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz", + "integrity": "sha512-E34CkBgyeqNDcrbU76cDjL5JLcVrtSdYq0MEh/B10r17pRP4ciHLwTgnuLV8Ay6cgEMLkcBkFCKyFZ43YldYzg==", + "dev": true, + "dependencies": { + "define-properties": "^1.1.3", + "es-abstract": "^1.17.5" + } + }, "node_modules/string.prototype.matchall": { "version": "4.0.11", "resolved": "https://registry.npmjs.org/string.prototype.matchall/-/string.prototype.matchall-4.0.11.tgz", @@ -5773,6 +6225,27 @@ "tshet-uinh": "^0.15.0" } }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", diff --git a/package.json b/package.json index 3d39aad..1a00142 100644 --- a/package.json +++ b/package.json @@ -60,8 +60,11 @@ "eslint-config-prettier": "^9.1.0", "eslint-import-resolver-typescript": "^3.6.3", "eslint-plugin-import": "^2.30.0", + "eslint-plugin-jsx-a11y": "^6.10.0", + "eslint-plugin-no-array-concat": "^0.1.2", "eslint-plugin-react": "^7.37.0", "eslint-plugin-react-hooks": "^4.6.2", + "eslint-plugin-react-refresh": "^0.4.12", "patch-package": "^8.0.0", "prettier": "^3.3.3", "typescript": "^5.6.2", diff --git a/src/Classes/CustomElement.tsx b/src/Classes/CustomElement.tsx index 4fa2157..4259182 100644 --- a/src/Classes/CustomElement.tsx +++ b/src/Classes/CustomElement.tsx @@ -1,10 +1,10 @@ import { createElement, Fragment } from "react"; -import type { HTMLAttributes, ReactElement } from "react"; import styled from "@emotion/styled"; import type { ReactNode } from "../consts"; import type { Property } from "csstype"; +import type { HTMLAttributes, ReactElement } from "react"; const Missing = styled.span` &:after { @@ -12,7 +12,7 @@ const Missing = styled.span` } `; -type TagToProp = { +interface TagToProp { f: undefined; b: undefined; i: undefined; @@ -23,7 +23,7 @@ type TagToProp = { fg: Property.Color; bg: Property.BackgroundColor; size: Property.FontSize; -}; +} type AllTags = keyof TagToProp; type Tag = { diff --git a/src/Components/App.tsx b/src/Components/App.tsx index 3a6c004..472663f 100644 --- a/src/Components/App.tsx +++ b/src/Components/App.tsx @@ -1,7 +1,9 @@ -import "purecss/build/pure.css"; - import { useCallback, useRef } from "react"; +import "purecss/build/pure.css"; +// NOTE sweetalert2's ESM export does not setup styles properly, manually importing +import "sweetalert2/dist/sweetalert2.css"; + import { injectGlobal, css as stylesheet } from "@emotion/css"; import styled from "@emotion/styled"; import { faCirclePlay, faExternalLink, faInfo, faQuestion } from "@fortawesome/free-solid-svg-icons"; @@ -11,9 +13,7 @@ import Main from "./Main"; import Swal from "../Classes/SwalReact"; import { codeFontFamily, noop } from "../consts"; -// NOTE sweetalert2's ESM export does not setup styles properly, manually importing -import "sweetalert2/dist/sweetalert2.css"; - +// eslint-disable-next-line @typescript-eslint/no-unused-expressions injectGlobal` html, body { diff --git a/src/Components/CreateSchemaDialog.tsx b/src/Components/CreateSchemaDialog.tsx index 17e0fe5..237d13f 100644 --- a/src/Components/CreateSchemaDialog.tsx +++ b/src/Components/CreateSchemaDialog.tsx @@ -1,4 +1,4 @@ -import { ChangeEventHandler, forwardRef, RefObject, useCallback, useEffect, useMemo, useRef, useState } from "react"; +import { forwardRef, useCallback, useEffect, useMemo, useRef, useState } from "react"; import { createPortal } from "react-dom"; import { css } from "@emotion/react"; @@ -10,11 +10,12 @@ import ExplorerFolder from "./ExplorerFolder"; import Spinner from "./Spinner"; import actions from "../actions"; import Swal from "../Classes/SwalReact"; -import { invalidCharsRegex, newFileTemplate, tshetUinhExamplesURLPrefix, UseMainState } from "../consts"; +import { invalidCharsRegex, newFileTemplate, tshetUinhExamplesURLPrefix } from "../consts"; import samples from "../samples"; import { fetchFile, normalizeFileName } from "../utils"; -import type { Folder, Sample, SchemaState } from "../consts"; +import type { Folder, Sample, SchemaState, UseMainState } from "../consts"; +import type { ChangeEventHandler, RefObject } from "react"; const Container = styled.dialog` transform: scale(0.9); @@ -183,12 +184,12 @@ const CreateSchemaDialog = forwardRef getDefaultFileName("") + ".js"); + const [createSchemaName, setCreateSchemaName] = useState(() => `${getDefaultFileName("")}.js`); const [createSchemaSample, setCreateSchemaSample] = useState(""); const [loading, setLoading] = useState(false); const resetDialog = useCallback(() => { - setCreateSchemaName(getDefaultFileName("") + ".js"); + setCreateSchemaName(`${getDefaultFileName("")}.js`); setCreateSchemaSample(""); setLoading(false); // eslint-disable-next-line react-hooks/exhaustive-deps @@ -199,7 +200,7 @@ const CreateSchemaDialog = forwardRef { const name = normalizeFileName(createSchemaName); if (!name || name === getDefaultFileName(createSchemaSample)) - setCreateSchemaName(getDefaultFileName(sample) + ".js"); + setCreateSchemaName(`${getDefaultFileName(sample)}.js`); setCreateSchemaSample(sample); }}>
@@ -236,9 +237,9 @@ const CreateSchemaDialog = forwardRef { const name = normalizeFileName(createSchemaName); if (!name || name === getDefaultFileName(createSchemaSample)) - setCreateSchemaName(getDefaultFileName("") + ".js"); + setCreateSchemaName(`${getDefaultFileName("")}.js`); setCreateSchemaSample(""); }}>
diff --git a/src/Components/Main.tsx b/src/Components/Main.tsx index a21c944..ade7aa5 100644 --- a/src/Components/Main.tsx +++ b/src/Components/Main.tsx @@ -1,4 +1,4 @@ -import { MutableRefObject, useCallback, useEffect, useReducer, useRef, useState } from "react"; +import { useCallback, useEffect, useReducer, useRef, useState } from "react"; import { createPortal } from "react-dom"; import styled from "@emotion/styled"; @@ -16,6 +16,7 @@ import initialState, { stateStorageLocation } from "../state"; import { copy, notifyError } from "../utils"; import type { MainState, Option, ReactNode } from "../consts"; +import type { MutableRefObject } from "react"; const dummyOutput = document.createElement("output"); diff --git a/src/Components/SchemaEditor.tsx b/src/Components/SchemaEditor.tsx index 9f37192..c2a554d 100644 --- a/src/Components/SchemaEditor.tsx +++ b/src/Components/SchemaEditor.tsx @@ -1,5 +1,4 @@ import { useCallback, useEffect, useMemo, useRef, useState } from "react"; -import type { MouseEvent, MutableRefObject } from "react"; import { createPortal } from "react-dom"; import { css } from "@emotion/react"; @@ -18,6 +17,7 @@ import "../editor/setup"; import { memoize, normalizeFileName, notifyError } from "../utils"; import type { UseMainState, ReactNode } from "../consts"; +import type { MouseEvent, MutableRefObject } from "react"; const TabBar = styled.div` display: flex; @@ -234,10 +234,10 @@ export default function SchemaEditor({ state, setState, commonOptions, evaluateH sample ||= "untitled"; const indices = schemaNames .map(name => { - if (name === sample + ".js") return 0; - if (!name.startsWith(sample + "-") || !name.endsWith(".js")) return -1; + if (name === `${sample}.js`) return 0; + if (!name.startsWith(`${sample}-`) || !name.endsWith(".js")) return -1; const start = sample.length + 1; - for (let i = start; i < name.length - 3; i++) if (name[i] < +(i === start) + "" || name[i] > "9") return -1; + for (let i = start; i < name.length - 3; i++) if (name[i] < `${+(i === start)}` || name[i] > "9") return -1; return +name.slice(start, -3); }) .sort((a, b) => a - b); @@ -268,10 +268,9 @@ export default function SchemaEditor({ state, setState, commonOptions, evaluateH for (const file of files) { // POSIX allows all characters other than `\0` and `/` in file names, // this is necessary to ensure that the file name is valid on all platforms. - const name = - getDefaultFileNameWithSchemaNames(currSchemaNames)( - normalizeFileName(file.name).replace(invalidCharsRegex, "_"), - ) + ".js"; + const name = `${getDefaultFileNameWithSchemaNames(currSchemaNames)( + normalizeFileName(file.name).replace(invalidCharsRegex, "_"), + )}.js`; currSchemaNames.push(name); newState = actions.addSchema({ name, input: contents[i++] })(newState); } @@ -408,7 +407,7 @@ export default function SchemaEditor({ state, setState, commonOptions, evaluateH const index = schemas.findIndex(schema => schema.name === name); const children = [].slice.call(tabBarRef.current.children, 0, -1) as HTMLElement[]; const widths = children.map(element => element.getBoundingClientRect().width); - const currentWidth = widths[index] + "px"; + const currentWidth = `${widths[index]}px`; const threshold: number[] = []; threshold[index] = 0; @@ -424,9 +423,9 @@ export default function SchemaEditor({ state, setState, commonOptions, evaluateH let clientX = startX; function move(event: { clientX: number } | TouchEvent) { - clientX = "clientX" in event ? event.clientX : (event.touches?.[0]?.clientX ?? clientX); + clientX = "clientX" in event ? event.clientX : (event.touches[0].clientX ?? clientX); let value = clientX - startX; - children[index].style.left = value + "px"; + children[index].style.left = `${value}px`; if (value < 0) { value = -value; for (let i = 0; i < index; i++) children[i].style.left = value >= threshold[i] ? currentWidth : ""; @@ -434,12 +433,12 @@ export default function SchemaEditor({ state, setState, commonOptions, evaluateH } else { for (let i = 0; i < index; i++) children[i].style.left = ""; for (let i = length - 1; i > index; i--) - children[i].style.left = value >= threshold[i] ? "-" + currentWidth : ""; + children[i].style.left = value >= threshold[i] ? `-${currentWidth}` : ""; } } function end(event: { clientX: number } | TouchEvent) { - clientX = "clientX" in event ? event.clientX : (event.touches?.[0]?.clientX ?? clientX); + clientX = "clientX" in event ? event.clientX : (event.touches[0].clientX ?? clientX); let value = clientX - startX; children.forEach(element => (element.style.left = "")); let i: number; @@ -475,7 +474,7 @@ export default function SchemaEditor({ state, setState, commonOptions, evaluateH const hasSchemaName = (name: string) => schemas.find(schema => schema.name === name); if (!name) return "檔案名稱為空"; if (invalidCharsRegex.test(name)) return "檔案名稱含有特殊字元"; - if (hasSchemaName(name + ".js")) return "檔案名稱與現有檔案重複"; + if (hasSchemaName(`${name}.js`)) return "檔案名稱與現有檔案重複"; return ""; } @@ -497,15 +496,15 @@ export default function SchemaEditor({ state, setState, commonOptions, evaluateH confirmButtonText: "確定", cancelButtonText: "取消", }); - const confirmButton = Swal.getConfirmButton() as HTMLButtonElement; + const confirmButton = Swal.getConfirmButton()!; confirmButton.disabled = true; confirmButton.style.pointerEvents = "none"; - const input = Swal.getInput() as HTMLInputElement; + const input = Swal.getInput()!; input.addEventListener("input", () => { const newName = normalizeFileName(input.value); const validation = validateFileName(newName); if (validation) { - if (newName + ".js" !== name) { + if (`${newName}.js` !== name) { const { selectionStart, selectionEnd, selectionDirection } = input; Swal.showValidationMessage(validation); input.setSelectionRange(selectionStart, selectionEnd, selectionDirection || undefined); @@ -521,7 +520,7 @@ export default function SchemaEditor({ state, setState, commonOptions, evaluateH const { isConfirmed, value } = await promise; if (isConfirmed) { const newName = normalizeFileName(value); - if (!validateFileName(newName)) setState(actions.renameSchema(name, newName + ".js")); + if (!validateFileName(newName)) setState(actions.renameSchema(name, `${newName}.js`)); } } } diff --git a/src/Components/Tooltip.tsx b/src/Components/Tooltip.tsx index 1a5624b..e51f1de 100644 --- a/src/Components/Tooltip.tsx +++ b/src/Components/Tooltip.tsx @@ -1,9 +1,10 @@ -import { cloneElement, ReactElement, useCallback, useEffect, useRef } from "react"; -import type { SyntheticEvent } from "react"; +import { cloneElement, useCallback, useEffect, useRef } from "react"; import { createRoot } from "react-dom/client"; import { css as stylesheet } from "@emotion/css"; +import type { ReactElement, SyntheticEvent } from "react"; + function getPageWidth() { return Math.max( document.body.scrollWidth, @@ -68,9 +69,9 @@ function TooltipAnchor({ targetLeft = Math.min(getPageWidth() - oneRemSize - divInnerBox.width, Math.max(oneRemSize, targetLeft)); targetLeft += window.scrollX; - div.className = tooltipStyle + (fixedWidth ? " " + fixedWidthStyle : ""); - div.style.top = targetTop + "px"; - div.style.left = targetLeft + "px"; + div.className = tooltipStyle + (fixedWidth ? ` ${fixedWidthStyle}` : ""); + div.style.top = `${targetTop}px`; + div.style.left = `${targetLeft}px`; div.style.visibility = "visible"; }); diff --git a/src/Components/TooltipChar.tsx b/src/Components/TooltipChar.tsx index 445d984..a5fa87b 100644 --- a/src/Components/TooltipChar.tsx +++ b/src/Components/TooltipChar.tsx @@ -112,10 +112,9 @@ export default function TooltipChar({ } } 各反切.反 = new Set(Array.from(各反切.反).filter(反切 => !各反切.切.has(反切))); - const 反切text = - (["反", "切"] as const) - .flatMap(x => (各反切[x].size ? [[...各反切[x]].join("/") + x] : [])) - .join(" ") + " "; + const 反切text = `${(["反", "切"] as const) + .flatMap(x => (各反切[x].size ? [[...各反切[x]].join("/") + x] : [])) + .join(" ")} `; const 出處text = 來源 && ["廣韻", "王三"].includes(來源.文獻) ? `[${來源.文獻} ${來源.韻目}韻]` : ""; return ( diff --git a/src/Yitizi.d.ts b/src/Yitizi.d.ts index 84abfad..18e801d 100644 --- a/src/Yitizi.d.ts +++ b/src/Yitizi.d.ts @@ -1,4 +1,4 @@ declare module "yitizi" { - export const yitiziData: { [c: string]: string }; + export const yitiziData: Record; export function get(c: string): string[]; } diff --git a/src/actions.ts b/src/actions.ts index ca8b44b..841b907 100644 --- a/src/actions.ts +++ b/src/actions.ts @@ -58,7 +58,7 @@ export default { const schemas = [...state.schemas]; const index = schemas.findIndex(schema => schema.name === name); const newState = { ...schemas[index], input }; - newState.parameters = newState.parameters?.refresh(input) || ParameterSet.from(input); + newState.parameters = newState.parameters.refresh(input) || ParameterSet.from(input); schemas[index] = newState; return { ...state, schemas }; }, diff --git a/src/consts.ts b/src/consts.ts index 3b7f0a0..978f7df 100644 --- a/src/consts.ts +++ b/src/consts.ts @@ -1,8 +1,7 @@ -import type { Dispatch, DispatchWithoutAction, ReactChild, ReactPortal, SetStateAction } from "react"; - import type { CustomNode } from "./Classes/CustomElement"; import type ParameterSet from "./Classes/ParameterSet"; import type samples from "./samples"; +import type { Dispatch, DispatchWithoutAction, ReactChild, ReactPortal, SetStateAction } from "react"; import type { 資料 } from "tshet-uinh"; export const tshetUinhExamplesURLPrefix = "https://cdn.jsdelivr.net/gh/nk2028/tshet-uinh-examples@main/"; @@ -85,7 +84,9 @@ export type Query = Readonly = T extends Record ? Values : T; export type Sample = Values; -export type Folder = { [name: string]: Folder | Sample }; +export interface Folder { + [name: string]: Folder | Sample; +} type UseGet = { [P in K]: T }; type UseSet = { [P in `set${Capitalize}`]: Dispatch> }; diff --git a/src/evaluate.ts b/src/evaluate.ts index 34001ef..acd1cad 100644 --- a/src/evaluate.ts +++ b/src/evaluate.ts @@ -1,10 +1,11 @@ import { 推導方案 } from "tshet-uinh-deriver-tools"; -import { CustomNode, Formatter } from "./Classes/CustomElement"; +import { Formatter } from "./Classes/CustomElement"; import { tshetUinhTextLabelURLPrefix } from "./consts"; import { evaluateOption, getArticle, setArticle } from "./options"; import { fetchFile, normalizeFileName, notifyError } from "./utils"; +import type { CustomNode } from "./Classes/CustomElement"; import type { MainState, ReactNode } from "./consts"; import type { 音韻地位 } from "tshet-uinh"; import type { 原始推導函數, 推導函數 } from "tshet-uinh-deriver-tools"; @@ -26,7 +27,7 @@ export default async function evaluate(state: MainState): Promise { const { schemas, option } = state; if (option === "convertPresetArticle" && !getArticle()) - setArticle(await fetchFile(tshetUinhTextLabelURLPrefix + "index.txt")); + setArticle(await fetchFile(`${tshetUinhTextLabelURLPrefix}index.txt`)); else if (option === "compareSchemas" && schemas.length < 2) throw notifyError("此選項需要兩個或以上方案"); else await new Promise(resolve => setTimeout(resolve)); @@ -47,9 +48,9 @@ export default async function evaluate(state: MainState): Promise { function require(current: string, references: string[] = []): Require { const newReferences = references.concat(current); - if (references.includes(current)) throw notifyError("Circular reference detected: " + newReferences.join(" -> ")); + if (references.includes(current)) throw notifyError(`Circular reference detected: ${newReferences.join(" -> ")}`); return (音韻地位, 字頭) => sample => { - const schema = schemas.find(({ name }) => name === normalizeFileName(sample) + ".js"); + const schema = schemas.find(({ name }) => name === `${normalizeFileName(sample)}.js`); if (!schema) throw notifyError("Schema not found"); return new SchemaFromRequire(rawDeriverFrom(schema.input), require(sample, newReferences), 音韻地位, 字頭); }; diff --git a/src/options.tsx b/src/options.tsx index 6540dbb..c996420 100644 --- a/src/options.tsx +++ b/src/options.tsx @@ -1,5 +1,4 @@ import { Fragment } from "react"; - import { 資料, 音韻地位 } from "tshet-uinh"; import Yitizi from "yitizi"; @@ -192,7 +191,7 @@ export const evaluateOption: Record = { return ( b[2] - a[2]).map(([, 擬音陣列, count]) => [...wrap(擬音陣列), count + ""])} + body={result.sort((a, b) => b[2] - a[2]).map(([, 擬音陣列, count]) => [...wrap(擬音陣列), `${count}`])} /> ); }, diff --git a/src/utils.tsx b/src/utils.tsx index 13488fe..32ba010 100644 --- a/src/utils.tsx +++ b/src/utils.tsx @@ -26,10 +26,10 @@ export function notifyError(msg: string, err?: unknown) { let curErr: Error = err; while (curErr.cause instanceof Error) { curErr = curErr.cause; - technical += "\n" + curErr.message; + technical += `\n${curErr.message}`; } if (curErr.stack) { - technical += "\n\n" + curErr.stack; + technical += `\n\n${curErr.stack}`; } } const config: SweetAlertOptions = { diff --git a/tsconfig.json b/tsconfig.json index f2ae9d0..a87d569 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -2,6 +2,9 @@ "compilerOptions": { "target": "ESNext", "lib": ["DOM", "DOM.Iterable", "ES2020", "ES2022.Error"], + "module": "ESNext", + "moduleResolution": "Bundler", + "moduleDetection": "force", "strict": true, "allowUnusedLabels": false, @@ -12,13 +15,15 @@ "exactOptionalPropertyTypes": true, "noFallthroughCasesInSwitch": true, "forceConsistentCasingInFileNames": true, + "isolatedModules": true, + "verbatimModuleSyntax": true, - "module": "ESNext", - "moduleResolution": "Bundler", - "skipLibCheck": true, "esModuleInterop": true, "resolveJsonModule": true, - "isolatedModules": true, + "useDefineForClassFields": true, + "skipLibCheck": true, + "incremental": true, + "noEmit": true, "jsx": "react-jsx" }, "include": ["./src"]