From a159c3175f5f60a9de00f4d3c73787ffa6c63ddd Mon Sep 17 00:00:00 2001 From: silverwind Date: Mon, 22 Nov 2021 09:19:01 +0100 Subject: [PATCH] Add new JS linter rules (#17699) * Add new JS linter rules Adds a few useful rules from eslint-plugin-github. Notable changes: - Forbid dataset usage, its camel-casing behaviour makes it hard to grep for attributes. - Forbid .then() and .catch(), we should generally prefer await for new code. For rare cases where they are useful, a eslint-disable-line directive can be set. - Add docs js to linting * also enable github/array-foreach * small tweak Co-authored-by: Andrew Thornton Co-authored-by: techknowlogick Co-authored-by: wxiaoguang --- .eslintrc | 18 + Makefile | 2 +- build/generate-images.js | 2 +- build/generate-svg.js | 2 +- docs/assets/js/search.js | 26 +- package-lock.json | 710 ++++++++++++++++++++++++- package.json | 1 + templates/repo/clone_buttons.tmpl | 2 +- templates/repo/empty.tmpl | 2 +- web_src/js/features/clipboard.js | 8 +- web_src/js/features/codeeditor.js | 9 +- web_src/js/features/common-issue.js | 22 +- web_src/js/features/comp/ImagePaste.js | 4 +- web_src/js/features/heatmap.js | 4 +- web_src/js/features/repo-code.js | 8 +- web_src/js/features/repo-home.js | 8 +- web_src/js/features/repo-issue.js | 17 +- web_src/js/features/repo-legacy.js | 6 +- web_src/js/features/repo-projects.js | 83 ++- web_src/js/features/tablesort.js | 4 +- web_src/js/features/user-auth-u2f.js | 5 +- web_src/js/markup/tasklist.js | 9 +- web_src/js/standalone/swagger.js | 2 +- 23 files changed, 845 insertions(+), 109 deletions(-) diff --git a/.eslintrc b/.eslintrc index 30f5aceb647..97806688c59 100644 --- a/.eslintrc +++ b/.eslintrc @@ -13,6 +13,7 @@ plugins: - eslint-plugin-import - eslint-plugin-vue - eslint-plugin-html + - eslint-plugin-github extends: - plugin:vue/recommended @@ -96,6 +97,23 @@ rules: function-paren-newline: [0] generator-star-spacing: [0] getter-return: [2] + github/array-foreach: [2] + github/async-currenttarget: [2] + github/async-preventdefault: [2] + github/authenticity-token: [0] + github/get-attribute: [2] + github/js-class-name: [0] + github/no-blur: [0] + github/no-d-none: [0] + github/no-dataset: [2] + github/no-implicit-buggy-globals: [0] + github/no-inner-html: [0] + github/no-innerText: [2] + github/no-then: [2] + github/no-useless-passive: [2] + github/prefer-observers: [0] + github/require-passive-events: [2] + github/unescaped-html-literal: [0] grouped-accessor-pairs: [2] guard-for-in: [0] id-blacklist: [0] diff --git a/Makefile b/Makefile index eea9f7ad530..5f267bcac4e 100644 --- a/Makefile +++ b/Makefile @@ -328,7 +328,7 @@ lint: lint-frontend lint-backend .PHONY: lint-frontend lint-frontend: node_modules - npx eslint --color --max-warnings=0 web_src/js build templates *.config.js + npx eslint --color --max-warnings=0 web_src/js build templates *.config.js docs/assets/js npx stylelint --color --max-warnings=0 web_src/less npx editorconfig-checker templates diff --git a/build/generate-images.js b/build/generate-images.js index b8284b1be2f..ab4073dfcc6 100755 --- a/build/generate-images.js +++ b/build/generate-images.js @@ -80,5 +80,5 @@ async function main() { ]); } -main().then(exit).catch(exit); +main().then(exit).catch(exit); // eslint-disable-line github/no-then diff --git a/build/generate-svg.js b/build/generate-svg.js index 29b7d476938..53ec000d12e 100755 --- a/build/generate-svg.js +++ b/build/generate-svg.js @@ -54,5 +54,5 @@ async function main() { ]); } -main().then(exit).catch(exit); +main().then(exit).catch(exit); // eslint-disable-line github/no-then diff --git a/docs/assets/js/search.js b/docs/assets/js/search.js index a4dea55e0e3..315a5ebd918 100644 --- a/docs/assets/js/search.js +++ b/docs/assets/js/search.js @@ -15,7 +15,7 @@ const fuseOptions = { shouldSort: true, includeMatches: true, matchAllTokens: true, - threshold: 0.0, // for parsing diacritics + threshold: 0, // for parsing diacritics tokenize: true, location: 0, distance: 100, @@ -52,7 +52,7 @@ function doSearch() { executeSearch(searchQuery); } else { const para = document.createElement('P'); - para.innerText = 'Please enter a word or phrase above'; + para.textContent = 'Please enter a word or phrase above'; document.getElementById('search-results').appendChild(para); } } @@ -60,17 +60,17 @@ function doSearch() { function getJSON(url, fn) { const request = new XMLHttpRequest(); request.open('GET', url, true); - request.onload = function () { + request.addEventListener('load', () => { if (request.status >= 200 && request.status < 400) { const data = JSON.parse(request.responseText); fn(data); } else { console.error(`Target reached on ${url} with error ${request.status}`); } - }; - request.onerror = function () { + }); + request.addEventListener('error', () => { console.error(`Connection error ${request.status}`); - }; + }); request.send(); } @@ -84,20 +84,20 @@ function executeSearch(searchQuery) { populateResults(result); } else { const para = document.createElement('P'); - para.innerText = 'No matches found'; + para.textContent = 'No matches found'; document.getElementById('search-results').appendChild(para); } }); } function populateResults(result) { - result.forEach((value, key) => { + for (const [key, value] of result.entries()) { const content = value.item.contents; let snippet = ''; const snippetHighlights = []; if (fuseOptions.tokenize) { snippetHighlights.push(searchQuery); - value.matches.forEach((mvalue) => { + for (const mvalue of value.matches) { if (mvalue.key === 'tags' || mvalue.key === 'categories') { snippetHighlights.push(mvalue.value); } else if (mvalue.key === 'contents') { @@ -111,7 +111,7 @@ function populateResults(result) { snippetHighlights.push(mvalue.value.substring(mvalue.indices[0][0], mvalue.indices[0][1] - mvalue.indices[0][0] + 1)); } } - }); + } } if (snippet.length < 1) { @@ -130,10 +130,10 @@ function populateResults(result) { }); document.getElementById('search-results').appendChild(htmlToElement(output)); - snippetHighlights.forEach((snipvalue) => { + for (const snipvalue of snippetHighlights) { new Mark(document.getElementById(`summary-${key}`)).mark(snipvalue); - }); - }); + } + } } function render(templateString, data) { diff --git a/package-lock.json b/package-lock.json index 2ebeff0f305..498d1865069 100644 --- a/package-lock.json +++ b/package-lock.json @@ -45,6 +45,7 @@ "devDependencies": { "editorconfig-checker": "4.0.2", "eslint": "8.2.0", + "eslint-plugin-github": "4.3.5", "eslint-plugin-html": "6.2.0", "eslint-plugin-import": "2.25.3", "eslint-plugin-unicorn": "38.0.1", @@ -1440,6 +1441,194 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.4.0.tgz", + "integrity": "sha512-9/yPSBlwzsetCsGEn9j24D8vGQgJkOTr4oMLas/w886ZtzKIs1iyoqFrwsX2fqYEeUwsdBpC21gcjRGo57u0eg==", + "dev": true, + "dependencies": { + "@typescript-eslint/experimental-utils": "5.4.0", + "@typescript-eslint/scope-manager": "5.4.0", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", + "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/@typescript-eslint/experimental-utils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.4.0.tgz", + "integrity": "sha512-Nz2JDIQUdmIGd6p33A+naQmwfkU5KVTLb/5lTk+tLVTDacZKoGQisj8UCxk7onJcrgjIvr8xWqkYI+DbI3TfXg==", + "dev": true, + "dependencies": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.4.0", + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/typescript-estree": "5.4.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/@typescript-eslint/experimental-utils/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/@typescript-eslint/experimental-utils/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/@typescript-eslint/parser": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.4.0.tgz", + "integrity": "sha512-JoB41EmxiYpaEsRwpZEYAJ9XQURPFer8hpkIW9GiaspVLX8oqbqNM8P4EP8HOZg96yaALiLEVWllA2E8vwsIKw==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.4.0", + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/typescript-estree": "5.4.0", + "debug": "^4.3.2" + }, + "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" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.4.0.tgz", + "integrity": "sha512-pRxFjYwoi8R+n+sibjgF9iUiAELU9ihPBtHzocyW8v8D8G8KeQvXTsW7+CBYIyTYsmhtNk50QPGLE3vrvhM5KA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/visitor-keys": "5.4.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.4.0.tgz", + "integrity": "sha512-GjXNpmn+n1LvnttarX+sPD6+S7giO+9LxDIGlRl4wK3a7qMWALOHYuVSZpPTfEIklYjaWuMtfKdeByx0AcaThA==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.4.0.tgz", + "integrity": "sha512-nhlNoBdhKuwiLMx6GrybPT3SFILm5Gij2YBdPEPFlYNFAXUJWX6QRgvi/lwVoadaQEFsizohs6aFRMqsXI2ewA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/visitor-keys": "5.4.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "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/@typescript-eslint/visitor-keys": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.4.0.tgz", + "integrity": "sha512-PVbax7MeE7tdLfW5SA0fs8NGVVr+buMPrcj+CWYWPXsZCH8qZ1THufDzbXm1xrZ2b2PA1iENJ0sRq5fuUtvsJg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.4.0", + "eslint-visitor-keys": "^3.0.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, "node_modules/@vue/component-compiler-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", @@ -4155,6 +4344,18 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, "node_modules/eslint-import-resolver-node": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", @@ -4197,6 +4398,97 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-plugin-escompat": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-escompat/-/eslint-plugin-escompat-3.1.0.tgz", + "integrity": "sha512-Fon3eRv8fOQPZTjT3h8Ga85Xx7Eg+CNZBL7OIYSM2f+p3W4oXTxiSnFUbNDrayRBK3CQjG2dwR+iYeKDDSkXyA==", + "dev": true, + "dependencies": { + "browserslist": "^4.12.0" + }, + "peerDependencies": { + "eslint": ">=5.14.1" + } + }, + "node_modules/eslint-plugin-eslint-comments": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", + "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^1.0.5", + "ignore": "^5.0.5" + }, + "engines": { + "node": ">=6.5.0" + }, + "funding": { + "url": "https://github.com/sponsors/mysticatea" + }, + "peerDependencies": { + "eslint": ">=4.19.1" + } + }, + "node_modules/eslint-plugin-eslint-comments/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint-plugin-eslint-comments/node_modules/ignore": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", + "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/eslint-plugin-filenames": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-filenames/-/eslint-plugin-filenames-1.3.2.tgz", + "integrity": "sha512-tqxJTiEM5a0JmRCUYQmxw23vtTxrb2+a3Q2mMOPhFxvt7ZQQJmdiuMby9B/vUAuVMghyP7oET+nIf6EO6CBd/w==", + "dev": true, + "dependencies": { + "lodash.camelcase": "4.3.0", + "lodash.kebabcase": "4.1.1", + "lodash.snakecase": "4.1.1", + "lodash.upperfirst": "4.3.1" + }, + "peerDependencies": { + "eslint": "*" + } + }, + "node_modules/eslint-plugin-github": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-4.3.5.tgz", + "integrity": "sha512-3OPCn/kkFcTq1aYgJJVKzqzmcOn432eaup79TQ5mpWA11JXgF/KvVmIS1RF6har/gMueINMq1P5wDEFS6YQ/Pw==", + "dev": true, + "dependencies": { + "@typescript-eslint/eslint-plugin": "^5.1.0", + "@typescript-eslint/parser": "^5.1.0", + "eslint-config-prettier": ">=8.0.0", + "eslint-plugin-escompat": "^3.1.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-filenames": "^1.3.2", + "eslint-plugin-i18n-text": "^1.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-no-only-tests": "^2.6.0", + "eslint-plugin-prettier": "^3.3.1", + "eslint-rule-documentation": ">=1.0.0", + "prettier": "^2.2.1", + "svg-element-attributes": "^1.3.1" + }, + "bin": { + "eslint-ignore-errors": "bin/eslint-ignore-errors.js" + }, + "peerDependencies": { + "eslint": "^8.0.1" + } + }, "node_modules/eslint-plugin-html": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-6.2.0.tgz", @@ -4206,6 +4498,15 @@ "htmlparser2": "^7.1.2" } }, + "node_modules/eslint-plugin-i18n-text": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-i18n-text/-/eslint-plugin-i18n-text-1.0.1.tgz", + "integrity": "sha512-3G3UetST6rdqhqW9SfcfzNYMpQXS7wNkJvp6dsXnjzGiku6Iu5hl3B0kmk6lIcFPwYjhQIY+tXVRtK9TlGT7RA==", + "dev": true, + "peerDependencies": { + "eslint": ">=5.0.0" + } + }, "node_modules/eslint-plugin-import": { "version": "2.25.3", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", @@ -4260,6 +4561,36 @@ "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", "dev": true }, + "node_modules/eslint-plugin-no-only-tests": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-2.6.0.tgz", + "integrity": "sha512-T9SmE/g6UV1uZo1oHAqOvL86XWl7Pl2EpRpnLI8g/bkJu+h7XBCB+1LnubRZ2CUQXj805vh4/CYZdnqtVaEo2Q==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", + "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0" + }, + "engines": { + "node": ">=6.0.0" + }, + "peerDependencies": { + "eslint": ">=5.0.0", + "prettier": ">=1.13.0" + }, + "peerDependenciesMeta": { + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-unicorn": { "version": "38.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-38.0.1.tgz", @@ -4310,6 +4641,15 @@ "eslint": "^6.2.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/eslint-rule-documentation": { + "version": "1.0.23", + "resolved": "https://registry.npmjs.org/eslint-rule-documentation/-/eslint-rule-documentation-1.0.23.tgz", + "integrity": "sha512-pWReu3fkohwyvztx/oQWWgld2iad25TfUdi6wvhhaDPIQjHU/pyvlKgXFw1kX31SQK2Nq9MH+vRDWB0ZLy8fYw==", + "dev": true, + "engines": { + "node": ">=4.0.0" + } + }, "node_modules/eslint-scope": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", @@ -4536,6 +4876,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "node_modules/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 + }, "node_modules/fast-glob": { "version": "3.2.7", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", @@ -6862,12 +7208,30 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" }, + "node_modules/lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "node_modules/lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=", + "dev": true + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40=", + "dev": true + }, "node_modules/lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -6891,6 +7255,12 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "node_modules/lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984=", + "dev": true + }, "node_modules/lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -7873,7 +8243,7 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", - "optional": true, + "devOptional": true, "bin": { "prettier": "bin-prettier.js" }, @@ -7881,6 +8251,18 @@ "node": ">=10.13.0" } }, + "node_modules/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, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/pretty-format": { "version": "27.3.1", "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.3.1.tgz", @@ -8855,6 +9237,16 @@ "node": ">=8" } }, + "node_modules/svg-element-attributes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/svg-element-attributes/-/svg-element-attributes-1.3.1.tgz", + "integrity": "sha512-Bh05dSOnJBf3miNMqpsormfNtfidA/GxQVakhtn0T4DECWKeXQRQUceYjJ+OxYiiLdGe4Jo9iFV8wICFapFeIA==", + "dev": true, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/wooorm" + } + }, "node_modules/svg-tags": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", @@ -9172,6 +9564,27 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, + "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/tsutils/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/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -9213,6 +9626,20 @@ "is-typedarray": "^1.0.0" } }, + "node_modules/typescript": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "dev": true, + "peer": true, + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, "node_modules/typo-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.1.tgz", @@ -11090,6 +11517,115 @@ "integrity": "sha512-7tFImggNeNBVMsn0vLrpn1H1uPrUBdnARPTpZoitY37ZrdJREzf7I16tMrlK3hen349gr1NYh8CmZQa7CTG6Aw==", "dev": true }, + "@typescript-eslint/eslint-plugin": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.4.0.tgz", + "integrity": "sha512-9/yPSBlwzsetCsGEn9j24D8vGQgJkOTr4oMLas/w886ZtzKIs1iyoqFrwsX2fqYEeUwsdBpC21gcjRGo57u0eg==", + "dev": true, + "requires": { + "@typescript-eslint/experimental-utils": "5.4.0", + "@typescript-eslint/scope-manager": "5.4.0", + "debug": "^4.3.2", + "functional-red-black-tree": "^1.0.1", + "ignore": "^5.1.8", + "regexpp": "^3.2.0", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + }, + "dependencies": { + "ignore": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", + "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "dev": true + } + } + }, + "@typescript-eslint/experimental-utils": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/experimental-utils/-/experimental-utils-5.4.0.tgz", + "integrity": "sha512-Nz2JDIQUdmIGd6p33A+naQmwfkU5KVTLb/5lTk+tLVTDacZKoGQisj8UCxk7onJcrgjIvr8xWqkYI+DbI3TfXg==", + "dev": true, + "requires": { + "@types/json-schema": "^7.0.9", + "@typescript-eslint/scope-manager": "5.4.0", + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/typescript-estree": "5.4.0", + "eslint-scope": "^5.1.1", + "eslint-utils": "^3.0.0" + }, + "dependencies": { + "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, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + } + } + }, + "@typescript-eslint/parser": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.4.0.tgz", + "integrity": "sha512-JoB41EmxiYpaEsRwpZEYAJ9XQURPFer8hpkIW9GiaspVLX8oqbqNM8P4EP8HOZg96yaALiLEVWllA2E8vwsIKw==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.4.0", + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/typescript-estree": "5.4.0", + "debug": "^4.3.2" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.4.0.tgz", + "integrity": "sha512-pRxFjYwoi8R+n+sibjgF9iUiAELU9ihPBtHzocyW8v8D8G8KeQvXTsW7+CBYIyTYsmhtNk50QPGLE3vrvhM5KA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/visitor-keys": "5.4.0" + } + }, + "@typescript-eslint/types": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.4.0.tgz", + "integrity": "sha512-GjXNpmn+n1LvnttarX+sPD6+S7giO+9LxDIGlRl4wK3a7qMWALOHYuVSZpPTfEIklYjaWuMtfKdeByx0AcaThA==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.4.0.tgz", + "integrity": "sha512-nhlNoBdhKuwiLMx6GrybPT3SFILm5Gij2YBdPEPFlYNFAXUJWX6QRgvi/lwVoadaQEFsizohs6aFRMqsXI2ewA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.4.0", + "@typescript-eslint/visitor-keys": "5.4.0", + "debug": "^4.3.2", + "globby": "^11.0.4", + "is-glob": "^4.0.3", + "semver": "^7.3.5", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.4.0.tgz", + "integrity": "sha512-PVbax7MeE7tdLfW5SA0fs8NGVVr+buMPrcj+CWYWPXsZCH8qZ1THufDzbXm1xrZ2b2PA1iENJ0sRq5fuUtvsJg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.4.0", + "eslint-visitor-keys": "^3.0.0" + } + }, "@vue/component-compiler-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/@vue/component-compiler-utils/-/component-compiler-utils-3.3.0.tgz", @@ -13163,6 +13699,13 @@ "v8-compile-cache": "^2.0.3" } }, + "eslint-config-prettier": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.3.0.tgz", + "integrity": "sha512-BgZuLUSeKzvlL/VUjx/Yb787VQ26RU3gGjA3iiFvdsp/2bMfVIWUVP7tjxtjS0e+HP409cPlPvNkQloz8C91ew==", + "dev": true, + "requires": {} + }, "eslint-import-resolver-node": { "version": "0.3.6", "resolved": "https://registry.npmjs.org/eslint-import-resolver-node/-/eslint-import-resolver-node-0.3.6.tgz", @@ -13206,6 +13749,72 @@ } } }, + "eslint-plugin-escompat": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-escompat/-/eslint-plugin-escompat-3.1.0.tgz", + "integrity": "sha512-Fon3eRv8fOQPZTjT3h8Ga85Xx7Eg+CNZBL7OIYSM2f+p3W4oXTxiSnFUbNDrayRBK3CQjG2dwR+iYeKDDSkXyA==", + "dev": true, + "requires": { + "browserslist": "^4.12.0" + } + }, + "eslint-plugin-eslint-comments": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-eslint-comments/-/eslint-plugin-eslint-comments-3.2.0.tgz", + "integrity": "sha512-0jkOl0hfojIHHmEHgmNdqv4fmh7300NdpA9FFpF7zaoLvB/QeXOGNLIo86oAveJFrfB1p05kC8hpEMHM8DwWVQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^1.0.5", + "ignore": "^5.0.5" + }, + "dependencies": { + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "ignore": { + "version": "5.1.9", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.9.tgz", + "integrity": "sha512-2zeMQpbKz5dhZ9IwL0gbxSW5w0NK/MSAMtNuhgIHEPmaU3vPdKPL0UdvUCXs5SS4JAwsBxysK5sFMW8ocFiVjQ==", + "dev": true + } + } + }, + "eslint-plugin-filenames": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/eslint-plugin-filenames/-/eslint-plugin-filenames-1.3.2.tgz", + "integrity": "sha512-tqxJTiEM5a0JmRCUYQmxw23vtTxrb2+a3Q2mMOPhFxvt7ZQQJmdiuMby9B/vUAuVMghyP7oET+nIf6EO6CBd/w==", + "dev": true, + "requires": { + "lodash.camelcase": "4.3.0", + "lodash.kebabcase": "4.1.1", + "lodash.snakecase": "4.1.1", + "lodash.upperfirst": "4.3.1" + } + }, + "eslint-plugin-github": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/eslint-plugin-github/-/eslint-plugin-github-4.3.5.tgz", + "integrity": "sha512-3OPCn/kkFcTq1aYgJJVKzqzmcOn432eaup79TQ5mpWA11JXgF/KvVmIS1RF6har/gMueINMq1P5wDEFS6YQ/Pw==", + "dev": true, + "requires": { + "@typescript-eslint/eslint-plugin": "^5.1.0", + "@typescript-eslint/parser": "^5.1.0", + "eslint-config-prettier": ">=8.0.0", + "eslint-plugin-escompat": "^3.1.0", + "eslint-plugin-eslint-comments": "^3.2.0", + "eslint-plugin-filenames": "^1.3.2", + "eslint-plugin-i18n-text": "^1.0.1", + "eslint-plugin-import": "^2.25.2", + "eslint-plugin-no-only-tests": "^2.6.0", + "eslint-plugin-prettier": "^3.3.1", + "eslint-rule-documentation": ">=1.0.0", + "prettier": "^2.2.1", + "svg-element-attributes": "^1.3.1" + } + }, "eslint-plugin-html": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/eslint-plugin-html/-/eslint-plugin-html-6.2.0.tgz", @@ -13215,6 +13824,13 @@ "htmlparser2": "^7.1.2" } }, + "eslint-plugin-i18n-text": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-i18n-text/-/eslint-plugin-i18n-text-1.0.1.tgz", + "integrity": "sha512-3G3UetST6rdqhqW9SfcfzNYMpQXS7wNkJvp6dsXnjzGiku6Iu5hl3B0kmk6lIcFPwYjhQIY+tXVRtK9TlGT7RA==", + "dev": true, + "requires": {} + }, "eslint-plugin-import": { "version": "2.25.3", "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.3.tgz", @@ -13262,6 +13878,21 @@ } } }, + "eslint-plugin-no-only-tests": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-no-only-tests/-/eslint-plugin-no-only-tests-2.6.0.tgz", + "integrity": "sha512-T9SmE/g6UV1uZo1oHAqOvL86XWl7Pl2EpRpnLI8g/bkJu+h7XBCB+1LnubRZ2CUQXj805vh4/CYZdnqtVaEo2Q==", + "dev": true + }, + "eslint-plugin-prettier": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-3.4.1.tgz", + "integrity": "sha512-htg25EUYUeIhKHXjOinK4BgCcDwtLHjqaxCDsMy5nbnUMkKFvIhMVCp+5GFUXQ4Nr8lBsPqtGAqBenbpFqAA2g==", + "dev": true, + "requires": { + "prettier-linter-helpers": "^1.0.0" + } + }, "eslint-plugin-unicorn": { "version": "38.0.1", "resolved": "https://registry.npmjs.org/eslint-plugin-unicorn/-/eslint-plugin-unicorn-38.0.1.tgz", @@ -13297,6 +13928,12 @@ "vue-eslint-parser": "^8.0.1" } }, + "eslint-rule-documentation": { + "version": "1.0.23", + "resolved": "https://registry.npmjs.org/eslint-rule-documentation/-/eslint-rule-documentation-1.0.23.tgz", + "integrity": "sha512-pWReu3fkohwyvztx/oQWWgld2iad25TfUdi6wvhhaDPIQjHU/pyvlKgXFw1kX31SQK2Nq9MH+vRDWB0ZLy8fYw==", + "dev": true + }, "eslint-scope": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-6.0.0.tgz", @@ -13459,6 +14096,12 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, + "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": "3.2.7", "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.7.tgz", @@ -15207,12 +15850,30 @@ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz", "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0=" }, + "lodash.camelcase": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz", + "integrity": "sha1-soqmKIorn8ZRA1x3EfZathkDMaY=", + "dev": true + }, + "lodash.kebabcase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz", + "integrity": "sha1-hImxyw0p/4gZXM7KRI/21swpXDY=", + "dev": true + }, "lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "lodash.snakecase": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.snakecase/-/lodash.snakecase-4.1.1.tgz", + "integrity": "sha1-OdcUo1NXFHg3rv1ktdy7Fr7Nj40=", + "dev": true + }, "lodash.template": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz", @@ -15236,6 +15897,12 @@ "integrity": "sha1-WjUNoLERO4N+z//VgSy+WNbq4ZM=", "dev": true }, + "lodash.upperfirst": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/lodash.upperfirst/-/lodash.upperfirst-4.3.1.tgz", + "integrity": "sha1-E2Xt9DFIBIHvDRxolXpe2Z1J984=", + "dev": true + }, "lru-cache": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", @@ -15955,7 +16622,16 @@ "version": "2.4.1", "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.4.1.tgz", "integrity": "sha512-9fbDAXSBcc6Bs1mZrDYb3XKzDLm4EXXL9sC1LqKP5rZkT6KRr/rf9amVUcODVXgguK/isJz0d0hP72WeaKWsvA==", - "optional": true + "devOptional": 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-format": { "version": "27.3.1", @@ -16696,6 +17372,12 @@ "supports-color": "^7.0.0" } }, + "svg-element-attributes": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/svg-element-attributes/-/svg-element-attributes-1.3.1.tgz", + "integrity": "sha512-Bh05dSOnJBf3miNMqpsormfNtfidA/GxQVakhtn0T4DECWKeXQRQUceYjJ+OxYiiLdGe4Jo9iFV8wICFapFeIA==", + "dev": true + }, "svg-tags": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/svg-tags/-/svg-tags-1.0.0.tgz", @@ -16939,6 +17621,23 @@ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.1.tgz", "integrity": "sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==" }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + }, + "dependencies": { + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + } + } + }, "type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -16968,6 +17667,13 @@ "is-typedarray": "^1.0.0" } }, + "typescript": { + "version": "4.5.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.5.2.tgz", + "integrity": "sha512-5BlMof9H1yGt0P8/WF+wPNw6GfctgGjXp5hkblpyT+8rkASSmkUKMXrxR0Xg8ThVCi/JnHQiKXeBaEwCeQwMFw==", + "dev": true, + "peer": true + }, "typo-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/typo-js/-/typo-js-1.2.1.tgz", diff --git a/package.json b/package.json index 3c63141922f..20a05dad5fc 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "devDependencies": { "editorconfig-checker": "4.0.2", "eslint": "8.2.0", + "eslint-plugin-github": "4.3.5", "eslint-plugin-html": "6.2.0", "eslint-plugin-import": "2.25.3", "eslint-plugin-unicorn": "38.0.1", diff --git a/templates/repo/clone_buttons.tmpl b/templates/repo/clone_buttons.tmpl index 218eb31cb64..29d3fe76d78 100644 --- a/templates/repo/clone_buttons.tmpl +++ b/templates/repo/clone_buttons.tmpl @@ -24,7 +24,7 @@ const sshButton = document.getElementById('repo-clone-ssh'); const httpsButton = document.getElementById('repo-clone-https'); const input = document.getElementById('repo-clone-url'); - if (input) input.value = (isSSH ? sshButton : httpsButton).dataset.link; + if (input) input.value = (isSSH ? sshButton : httpsButton).getAttribute('data-link'); if (sshButton) sshButton.classList[isSSH ? 'add' : 'remove']('primary'); if (httpsButton) httpsButton.classList[isSSH ? 'remove' : 'add']('primary'); setTimeout(() => { diff --git a/templates/repo/empty.tmpl b/templates/repo/empty.tmpl index 485a6aa4e55..20563f59e6b 100644 --- a/templates/repo/empty.tmpl +++ b/templates/repo/empty.tmpl @@ -51,7 +51,7 @@ git push -u origin {{.Repository.DefaultBranch}} const cloneUrls = document.getElementsByClassName('clone-url'); if (cloneUrls) { for (let i = 0; i < cloneUrls.length; i++) { - cloneUrls[i].textContent = (isSSH ? sshButton : httpsButton).dataset.link; + cloneUrls[i].textContent = (isSSH ? sshButton : httpsButton).getAttribute('data-link'); } } diff --git a/web_src/js/features/clipboard.js b/web_src/js/features/clipboard.js index b0c4134537f..83626b614ee 100644 --- a/web_src/js/features/clipboard.js +++ b/web_src/js/features/clipboard.js @@ -52,12 +52,8 @@ export default function initGlobalCopyToClipboardListener() { // in case , so we just search // up to 3 levels for performance for (let i = 0; i < 3 && target; i++) { - let text; - if (target.dataset.clipboardText) { - text = target.dataset.clipboardText; - } else if (target.dataset.clipboardTarget) { - text = document.querySelector(target.dataset.clipboardTarget)?.value; - } + const text = target.getAttribute('data-clipboard-text') || document.querySelector(target.getAttribute('data-clipboard-target'))?.value; + if (text) { e.preventDefault(); diff --git a/web_src/js/features/codeeditor.js b/web_src/js/features/codeeditor.js index d4fd303fbf7..a22043c9d48 100644 --- a/web_src/js/features/codeeditor.js +++ b/web_src/js/features/codeeditor.js @@ -21,7 +21,7 @@ const baseOptions = { function getEditorconfig(input) { try { - return JSON.parse(input.dataset.editorconfig); + return JSON.parse(input.getAttribute('data-editorconfig')); } catch { return null; } @@ -132,14 +132,15 @@ function getFileBasedOptions(filename, lineWrapExts) { export async function createCodeEditor(textarea, filenameInput, previewFileModes) { const filename = basename(filenameInput.value); const previewLink = document.querySelector('a[data-tab=preview]'); - const markdownExts = (textarea.dataset.markdownFileExts || '').split(','); - const lineWrapExts = (textarea.dataset.lineWrapExtensions || '').split(','); + const markdownExts = (textarea.getAttribute('data-markdown-file-exts') || '').split(','); + const lineWrapExts = (textarea.getAttribute('data-line-wrap-extensions') || '').split(','); const isMarkdown = markdownExts.includes(extname(filename)); const editorConfig = getEditorconfig(filenameInput); if (previewLink) { if (isMarkdown && (previewFileModes || []).includes('markdown')) { - previewLink.dataset.url = previewLink.dataset.url.replace(/(.*)\/.*/i, `$1/markdown`); + const newUrl = (previewLink.getAttribute('data-url') || '').replace(/(.*)\/.*/i, `$1/markdown`); + previewLink.setAttribute('data-url', newUrl); previewLink.style.display = ''; } else { previewLink.style.display = 'none'; diff --git a/web_src/js/features/common-issue.js b/web_src/js/features/common-issue.js index f89690abc03..07086d9e63b 100644 --- a/web_src/js/features/common-issue.js +++ b/web_src/js/features/common-issue.js @@ -12,17 +12,25 @@ export function initCommonIssue() { } }); - $('.issue-action').on('click', function () { - let {action, elementId, url} = this.dataset; + $('.issue-action').on('click', async function () { + let action = this.getAttribute('data-action'); + let elementId = this.getAttribute('data-element-id'); + const url = this.getAttribute('data-url'); const issueIDs = $('.issue-checkbox').children('input:checked').map((_, el) => { - return el.dataset.issueId; + return el.getAttribute('data-issue-id'); }).get().join(','); if (elementId === '0' && url.substr(-9) === '/assignee') { elementId = ''; action = 'clear'; } - updateIssuesMeta(url, action, issueIDs, elementId).then(() => { - // NOTICE: This reset of checkbox state targets Firefox caching behaviour, as the checkboxes stay checked after reload + updateIssuesMeta( + url, + action, + issueIDs, + elementId + ).then(() => { // eslint-disable-line github/no-then + // NOTICE: This reset of checkbox state targets Firefox caching behaviour, as the + // checkboxes stay checked after reload if (action === 'close' || action === 'open') { // uncheck all checkboxes $('.issue-checkbox input[type="checkbox"]').each((_, e) => { e.checked = false }); @@ -31,8 +39,8 @@ export function initCommonIssue() { }); }); - // NOTICE: This event trigger targets Firefox caching behaviour, as the checkboxes stay checked after reload - // trigger ckecked event, if checkboxes are checked on load + // NOTICE: This event trigger targets Firefox caching behaviour, as the checkboxes stay + // checked after reload trigger ckecked event, if checkboxes are checked on load $('.issue-checkbox input[type="checkbox"]:checked').first().each((_, e) => { e.checked = false; $(e).trigger('click'); diff --git a/web_src/js/features/comp/ImagePaste.js b/web_src/js/features/comp/ImagePaste.js index f7f076bf805..99f4e069cc3 100644 --- a/web_src/js/features/comp/ImagePaste.js +++ b/web_src/js/features/comp/ImagePaste.js @@ -59,7 +59,7 @@ export function initCompImagePaste($target) { if (!dropzone) { return; } - const uploadUrl = dropzone.dataset.uploadUrl; + const uploadUrl = dropzone.getAttribute('data-upload-url'); const dropzoneFiles = dropzone.querySelector('.files'); for (const textarea of this.querySelectorAll('textarea')) { textarea.addEventListener('paste', async (e) => { @@ -77,7 +77,7 @@ export function initCompImagePaste($target) { } export function initSimpleMDEImagePaste(simplemde, dropzone, files) { - const uploadUrl = dropzone.dataset.uploadUrl; + const uploadUrl = dropzone.getAttribute('data-upload-url'); simplemde.codemirror.on('paste', async (_, e) => { for (const img of clipboardPastedImages(e)) { const name = img.name.substr(0, img.name.lastIndexOf('.')); diff --git a/web_src/js/features/heatmap.js b/web_src/js/features/heatmap.js index 52b7517c1ac..e652f4ed98e 100644 --- a/web_src/js/features/heatmap.js +++ b/web_src/js/features/heatmap.js @@ -8,11 +8,11 @@ export default function initHeatmap() { try { const heatmap = {}; - JSON.parse(el.dataset.heatmapData).forEach(({contributions, timestamp}) => { + for (const {contributions, timestamp} of JSON.parse(el.getAttribute('data-heatmap-data'))) { // Convert to user timezone and sum contributions by date const dateStr = new Date(timestamp * 1000).toDateString(); heatmap[dateStr] = (heatmap[dateStr] || 0) + contributions; - }); + } const values = Object.keys(heatmap).map((v) => { return {date: new Date(v), count: heatmap[v]}; diff --git a/web_src/js/features/repo-code.js b/web_src/js/features/repo-code.js index 8a361a750d0..1855f86b41c 100644 --- a/web_src/js/features/repo-code.js +++ b/web_src/js/features/repo-code.js @@ -131,12 +131,14 @@ export function initRepoCodeView() { } $(document).on('click', '.fold-file', ({currentTarget}) => { const box = currentTarget.closest('.file-content'); - const folded = box.dataset.folded !== 'true'; + const folded = box.getAttribute('data-folded') !== 'true'; currentTarget.innerHTML = svg(`octicon-chevron-${folded ? 'right' : 'down'}`, 18); - box.dataset.folded = String(folded); + box.setAttribute('data-folded', String(folded)); }); $(document).on('click', '.blob-excerpt', async ({currentTarget}) => { - const {url, query, anchor} = currentTarget.dataset; + const url = currentTarget.getAttribute('data-url'); + const query = currentTarget.getAttribute('data-query'); + const anchor = currentTarget.getAttribute('data-anchor'); if (!url) return; const blob = await $.get(`${url}?${query}&anchor=${anchor}`); currentTarget.closest('tr').outerHTML = blob; diff --git a/web_src/js/features/repo-home.js b/web_src/js/features/repo-home.js index f8bf9318ce1..29b44706192 100644 --- a/web_src/js/features/repo-home.js +++ b/web_src/js/features/repo-home.js @@ -57,13 +57,13 @@ export function initRepoTopicBar() { const {invalidTopics} = xhr.responseJSON; const topicLables = topicDropdown.children('a.ui.label'); - topics.split(',').forEach((value, index) => { + for (const [index, value] of topics.split(',').entries()) { for (let i = 0; i < invalidTopics.length; i++) { if (invalidTopics[i] === value) { topicLables.eq(index).removeClass('green').addClass('red'); } } - }); + } } else { topicPrompts.countPrompt = xhr.responseJSON.message; } @@ -101,7 +101,9 @@ export function initRepoTopicBar() { const query = stripTags(this.urlData.query.trim()); let found_query = false; const current_topics = []; - topicDropdown.find('div.label.visible.topic,a.label.visible').each((_, e) => { current_topics.push(e.dataset.value) }); + topicDropdown.find('div.label.visible.topic,a.label.visible').each((_, el) => { + current_topics.push(el.getAttribute('data-value')); + }); if (res.topics) { let found = false; diff --git a/web_src/js/features/repo-issue.js b/web_src/js/features/repo-issue.js index 1476571cc7a..b224245fdfe 100644 --- a/web_src/js/features/repo-issue.js +++ b/web_src/js/features/repo-issue.js @@ -182,7 +182,8 @@ export function initRepoIssueCommentDelete() { export function initRepoIssueDependencyDelete() { // Delete Issue dependency $(document).on('click', '.delete-dependency-button', (e) => { - const {id, type} = e.currentTarget.dataset; + const id = e.currentTarget.getAttribute('data-id'); + const type = e.currentTarget.getAttribute('data-type'); $('.remove-dependency').modal({ closable: false, @@ -348,22 +349,19 @@ export async function updateIssuesMeta(url, action, issueIds, elementId) { export function initRepoIssueComments() { if ($('.repository.view.issue .timeline').length === 0) return; - $('.re-request-review').on('click', function (event) { + $('.re-request-review').on('click', function (e) { + e.preventDefault(); const url = $(this).data('update-url'); const issueId = $(this).data('issue-id'); const id = $(this).data('id'); const isChecked = $(this).hasClass('checked'); - event.preventDefault(); updateIssuesMeta( url, isChecked ? 'detach' : 'attach', issueId, id, - ).then(() => { - window.location.reload(); - }); - return false; + ).then(() => window.location.reload()); // eslint-disable-line github/no-then }); $('.dismiss-review-btn').on('click', function (e) { @@ -550,7 +548,10 @@ export function initRepoIssueWipToggle() { // Toggle WIP $('.toggle-wip a, .toggle-wip button').on('click', async (e) => { e.preventDefault(); - const {title, wipPrefix, updateUrl} = e.currentTarget.closest('.toggle-wip').dataset; + const toggleWip = e.currentTarget.closest('.toggle-wip'); + const title = toggleWip.getAttribute('data-title'); + const wipPrefix = toggleWip.getAttribute('data-wip-prefix'); + const updateUrl = toggleWip.getAttribute('data-update-url'); await $.post(updateUrl, { _csrf: csrfToken, title: title?.startsWith(wipPrefix) ? title.substr(wipPrefix.length).trim() : `${wipPrefix.trim()} ${title}`, diff --git a/web_src/js/features/repo-legacy.js b/web_src/js/features/repo-legacy.js index d8530fe24ff..5904b3ce225 100644 --- a/web_src/js/features/repo-legacy.js +++ b/web_src/js/features/repo-legacy.js @@ -162,7 +162,7 @@ export function initRepoCommentForm() { 'clear', $listMenu.data('issue-id'), '', - ).then(() => window.location.reload()); + ).then(() => window.location.reload()); // eslint-disable-line github/no-then } $(this).parent().find('.item').each(function () { @@ -205,7 +205,7 @@ export function initRepoCommentForm() { '', $menu.data('issue-id'), $(this).data('id'), - ).then(() => window.location.reload()); + ).then(() => window.location.reload()); // eslint-disable-line github/no-then } let icon = ''; @@ -238,7 +238,7 @@ export function initRepoCommentForm() { '', $menu.data('issue-id'), $(this).data('id'), - ).then(() => window.location.reload()); + ).then(() => window.location.reload()); // eslint-disable-line github/no-then } $list.find('.selected').html(''); diff --git a/web_src/js/features/repo-projects.js b/web_src/js/features/repo-projects.js index ef664b48085..d9baa589166 100644 --- a/web_src/js/features/repo-projects.js +++ b/web_src/js/features/repo-projects.js @@ -6,57 +6,54 @@ async function initRepoProjectSortable() { const {Sortable} = await import(/* webpackChunkName: "sortable" */'sortablejs'); const boardColumns = document.getElementsByClassName('board-column'); - new Sortable( - els[0], - { - group: 'board-column', - draggable: '.board-column', - animation: 150, - ghostClass: 'card-ghost', - onSort: () => { - const board = document.getElementsByClassName('board')[0]; - const boardColumns = board.getElementsByClassName('board-column'); - - boardColumns.forEach((column, i) => { - if (parseInt($(column).data('sorting')) !== i) { - $.ajax({ - url: $(column).data('url'), - data: JSON.stringify({sorting: i, color: rgbToHex($(column).css('backgroundColor'))}), - headers: { - 'X-Csrf-Token': csrfToken, - 'X-Remote': true, - }, - contentType: 'application/json', - method: 'PUT', - }); - } - }); - }, - }, - ); - for (const column of boardColumns) { - new Sortable( - column.getElementsByClassName('board')[0], - { - group: 'shared', - animation: 150, - ghostClass: 'card-ghost', - onAdd: (e) => { - $.ajax(`${e.to.dataset.url}/${e.item.dataset.issue}`, { + new Sortable(els[0], { + group: 'board-column', + draggable: '.board-column', + animation: 150, + ghostClass: 'card-ghost', + onSort: () => { + const board = document.getElementsByClassName('board')[0]; + const boardColumns = board.getElementsByClassName('board-column'); + + for (const [i, column] of boardColumns.entries()) { + if (parseInt($(column).data('sorting')) !== i) { + $.ajax({ + url: $(column).data('url'), + data: JSON.stringify({sorting: i, color: rgbToHex($(column).css('backgroundColor'))}), headers: { 'X-Csrf-Token': csrfToken, 'X-Remote': true, }, contentType: 'application/json', - type: 'POST', - error: () => { - e.from.insertBefore(e.item, e.from.children[e.oldIndex]); - }, + method: 'PUT', }); - }, + } + } + }, + }); + + for (const column of boardColumns) { + new Sortable(column.getElementsByClassName('board')[0], { + group: 'shared', + animation: 150, + ghostClass: 'card-ghost', + onAdd: ({item, from, to, oldIndex}) => { + const url = to.getAttribute('data-url'); + const issue = item.getAttribute('data-issue'); + $.ajax(`${url}/${issue}`, { + headers: { + 'X-Csrf-Token': csrfToken, + 'X-Remote': true, + }, + contentType: 'application/json', + type: 'POST', + error: () => { + from.insertBefore(item, from.children[oldIndex]); + }, + }); }, - ); + }); } } diff --git a/web_src/js/features/tablesort.js b/web_src/js/features/tablesort.js index 17da2985a09..55238ac0ac8 100644 --- a/web_src/js/features/tablesort.js +++ b/web_src/js/features/tablesort.js @@ -1,6 +1,8 @@ export default function initTableSort() { for (const header of document.querySelectorAll('th[data-sortt-asc]') || []) { - const {sorttAsc, sorttDesc, sorttDefault} = header.dataset; + const sorttAsc = header.getAttribute('sortt-asc'); + const sorttDesc = header.getAttribute('sortt-desc'); + const sorttDefault = header.getAttribute('sortt-default'); header.addEventListener('click', () => { tableSort(sorttAsc, sorttDesc, sorttDefault); }); diff --git a/web_src/js/features/user-auth-u2f.js b/web_src/js/features/user-auth-u2f.js index 15beaaa207f..8951c8a4abf 100644 --- a/web_src/js/features/user-auth-u2f.js +++ b/web_src/js/features/user-auth-u2f.js @@ -1,3 +1,4 @@ +/* eslint-disable github/no-then */ const {appSubUrl, csrfToken} = window.config; export function initUserAuthU2fAuth() { @@ -77,11 +78,11 @@ function u2fError(errorType) { }; u2fErrors[errorType].removeClass('hide'); - Object.keys(u2fErrors).forEach((type) => { + for (const type of Object.keys(u2fErrors)) { if (type !== `${errorType}`) { u2fErrors[type].addClass('hide'); } - }); + } $('#u2f-error').modal('show'); } diff --git a/web_src/js/markup/tasklist.js b/web_src/js/markup/tasklist.js index f8ca5b0406e..149027d4285 100644 --- a/web_src/js/markup/tasklist.js +++ b/web_src/js/markup/tasklist.js @@ -14,14 +14,14 @@ export function initMarkupTasklist() { const checkboxes = el.querySelectorAll(`.task-list-item input[type=checkbox]`); for (const checkbox of checkboxes) { - if (checkbox.dataset.editable) { + if (checkbox.hasAttribute('data-editable')) { return; } - checkbox.dataset.editable = 'true'; + checkbox.setAttribute('data-editable', 'true'); checkbox.addEventListener('input', async () => { const checkboxCharacter = checkbox.checked ? 'x' : ' '; - const position = parseInt(checkbox.dataset.sourcePosition) + 1; + const position = parseInt(checkbox.getAttribute('data-source-position')) + 1; const rawContent = container.querySelector('.raw-content'); const oldContent = rawContent.textContent; @@ -43,7 +43,8 @@ export function initMarkupTasklist() { try { const editContentZone = container.querySelector('.edit-content-zone'); - const {updateUrl, context} = editContentZone.dataset; + const updateUrl = editContentZone.getAttribute('data-update-url'); + const context = editContentZone.getAttribute('data-context'); await $.post(updateUrl, { ignore_attachments: true, diff --git a/web_src/js/standalone/swagger.js b/web_src/js/standalone/swagger.js index 5d8b7192b23..cb91089daff 100644 --- a/web_src/js/standalone/swagger.js +++ b/web_src/js/standalone/swagger.js @@ -2,7 +2,7 @@ import SwaggerUI from 'swagger-ui-dist/swagger-ui-es-bundle.js'; import 'swagger-ui-dist/swagger-ui.css'; window.addEventListener('load', async () => { - const url = document.getElementById('swagger-ui').dataset.source; + const url = document.getElementById('swagger-ui').getAttribute('data-source'); const res = await fetch(url); const spec = await res.json();