From d9e7889e6c52146973315663e2995581c613897e Mon Sep 17 00:00:00 2001 From: conor Date: Sun, 4 Feb 2024 17:48:54 -0800 Subject: [PATCH] * replace props with typed props * add vue-i18n linting * fix i18n linting errors --- client/.eslintrc.cjs | 17 +- client/src/components/endGame/EndGame.vue | 8 +- .../src/components/endRound/PlayerChooser.vue | 2 +- .../gameShared/NotificationCount.vue | 18 +- client/src/components/gameShared/Prompt.vue | 21 +- .../components/gameShared/ResponseList.vue | 31 ++- .../components/gameShared/SelectionType.vue | 12 +- client/src/components/gameShared/Timer.vue | 10 +- .../components/gameShared/VolumeControl.vue | 2 +- client/src/components/lobby/Lobby.vue | 4 +- client/src/components/lobby/Options.vue | 14 +- client/src/components/lobby/PlayerCard.vue | 10 +- client/src/components/lobby/PlayerList.vue | 2 +- .../responseMatching/ActiveMatching.vue | 2 +- .../responseMatching/DisputeIcon.vue | 20 +- .../components/responseMatching/MatchCard.vue | 18 +- .../responseMatching/MatchingSummary.vue | 2 +- .../responseSelection/SelectionPicker.vue | 4 +- client/src/locales/en.ts | 5 +- client/src/views/About.vue | 2 +- client/src/views/Game.vue | 14 +- package-lock.json | 201 ++++++++++++++++++ package.json | 1 + 23 files changed, 302 insertions(+), 118 deletions(-) diff --git a/client/.eslintrc.cjs b/client/.eslintrc.cjs index 11b0154..43f98bb 100644 --- a/client/.eslintrc.cjs +++ b/client/.eslintrc.cjs @@ -3,10 +3,9 @@ require('@rushstack/eslint-patch/modern-module-resolution'); module.exports = { extends: [ - 'plugin:vue/vue3-essential', - 'plugin:vue/vue3-strongly-recommended', 'plugin:vue/vue3-recommended', 'eslint:recommended', + 'plugin:@intlify/vue-i18n/recommended', 'plugin:@typescript-eslint/recommended-type-checked', '@vue/eslint-config-typescript', '@vue/eslint-config-prettier/skip-formatting', @@ -29,13 +28,23 @@ module.exports = { 'vue/component-api-style': [2, ['script-setup']], 'vue/block-lang': [2, { script: { lang: 'ts' } }], 'vue/define-macros-order': 2, - // 'vue/define-props-declaration': 2, + 'vue/define-props-declaration': 2, 'vue/no-ref-object-reactivity-loss': 2, 'vue/no-undef-properties': 2, 'vue/no-unused-components': [2, { ignoreWhenBindingPresent: true }], 'vue/no-unused-properties': 2, 'vue/no-unused-refs': 2, + '@intlify/vue-i18n/valid-message-syntax': 2, + '@intlify/vue-i18n/key-format-style': [2, 'camelCase', {allowArray: true}], + '@intlify/vue-i18n/no-duplicate-keys-in-locale': 2, + '@intlify/vue-i18n/no-missing-keys-in-other-locales': 2, 'prettier/prettier': 2 }, - ignorePatterns: ['/*', '!/src'] + ignorePatterns: ['/*', '!/src'], + settings: { + 'vue-i18n': { + localeDir: './src/locales/*.{ts}', // extension is glob formatting! + messageSyntaxVersion: '^9.9.1' + } + } }; diff --git a/client/src/components/endGame/EndGame.vue b/client/src/components/endGame/EndGame.vue index d72418f..022c947 100644 --- a/client/src/components/endGame/EndGame.vue +++ b/client/src/components/endGame/EndGame.vue @@ -9,7 +9,7 @@ const click = new AudioWrap(ClickMp3); const gameStore = useGameStore(); -const rank = computed((): number[] => { +const rank = computed(() => { let result = []; let lastScore = -1; let lastRank = 1; @@ -39,7 +39,11 @@ const { n } = useI18n();
- {{ rank[index] }}. {{ score.player.name }}: {{ n(score.points) }} +
diff --git a/client/src/components/endRound/PlayerChooser.vue b/client/src/components/endRound/PlayerChooser.vue index 36ab5c0..3292cce 100644 --- a/client/src/components/endRound/PlayerChooser.vue +++ b/client/src/components/endRound/PlayerChooser.vue @@ -11,7 +11,7 @@ const hoverLeft = ref(false); const hoverRight = ref(false); const model = defineModel({ type: String, required: true }); -const selectedName = computed((): string => { +const selectedName = computed(() => { if (!model.value) return ''; const name = roomStore.players.find((player: Player) => player.id === model.value)?.name; return name === undefined ? '' : name; diff --git a/client/src/components/gameShared/NotificationCount.vue b/client/src/components/gameShared/NotificationCount.vue index bdd426c..db664b7 100644 --- a/client/src/components/gameShared/NotificationCount.vue +++ b/client/src/components/gameShared/NotificationCount.vue @@ -1,18 +1,16 @@ diff --git a/client/src/components/gameShared/ResponseList.vue b/client/src/components/gameShared/ResponseList.vue index a2f1016..f5e6d8e 100644 --- a/client/src/components/gameShared/ResponseList.vue +++ b/client/src/components/gameShared/ResponseList.vue @@ -6,19 +6,14 @@ import Click1Mp3 from '@/assets/audio/click1.mp3'; import Click2Mp3 from '@/assets/audio/click2.mp3'; import { useGameStore } from '@/stores/game.js'; -const props = defineProps({ - selectable: { - type: Boolean, - required: true - }, - playerId: { - type: String, - default: '' - }, - height: { - type: Number, - default: 30 - } +interface Props { + selectable: boolean; + playerId?: string; + height?: number; +} +const props = withDefaults(defineProps(), { + playerId: '', + height: 30 }); const gameStore = useGameStore(); @@ -27,19 +22,19 @@ const model = defineModel({ type: String }); const selected = ref(-1); -const responses = computed((): string[] => { +const responses = computed(() => { return gameStore.playerResponses(props.playerId).all; }); -const usedResponses = computed((): string[] => { +const usedResponses = computed(() => { return gameStore.playerResponses(props.playerId).used; }); -const selectedStrike = computed((): string => { +const selectedStrike = computed(() => { return gameStore.playerResponses(props.playerId).selectedStrike; }); -const selectedSike = computed((): string => { +const selectedSike = computed(() => { return gameStore.playerResponses(props.playerId).selectedSike; }); -const cssProps = computed((): Record => { +const cssProps = computed>(() => { return { '--max-height': props.height + 'vh' }; diff --git a/client/src/components/gameShared/SelectionType.vue b/client/src/components/gameShared/SelectionType.vue index bdabd95..f5b2f12 100644 --- a/client/src/components/gameShared/SelectionType.vue +++ b/client/src/components/gameShared/SelectionType.vue @@ -6,16 +6,16 @@ import ChoiceImg from '@/assets/images/choice.png'; import { useGameStore } from '@/stores/game.js'; import { useI18n } from 'vue-i18n'; -defineProps({ - tooltip: { - type: Boolean, - default: true - } +interface Props { + tooltip?: boolean; +} +withDefaults(defineProps(), { + tooltip: true }); const gameStore = useGameStore(); -const typeImg = computed(() => { +const typeImg = computed(() => { if (gameStore.selectionType === 'strike') { return StrikeImg; } else if (gameStore.selectionType === 'sike') { diff --git a/client/src/components/gameShared/Timer.vue b/client/src/components/gameShared/Timer.vue index c203831..a65caf5 100644 --- a/client/src/components/gameShared/Timer.vue +++ b/client/src/components/gameShared/Timer.vue @@ -6,12 +6,10 @@ import timerMp3 from '@/assets/audio/timer_full.mp3'; import timerCompleteMp3 from '@/assets/audio/timerComplete.mp3'; import { useI18n } from 'vue-i18n'; -defineProps({ - time: { - type: Number, - required: true - } -}); +defineProps<{ + time: number; +}>(); + const timer = new AudioWrap(timerMp3); const timerComplete = new AudioWrap(timerCompleteMp3); const gameStore = useGameStore(); diff --git a/client/src/components/gameShared/VolumeControl.vue b/client/src/components/gameShared/VolumeControl.vue index 4c9a22b..e0b5a5d 100644 --- a/client/src/components/gameShared/VolumeControl.vue +++ b/client/src/components/gameShared/VolumeControl.vue @@ -7,7 +7,7 @@ const settingsStore = useSettingsStore(); const showing = ref(false); const timer: Ref = ref(null); -const value = computed({ +const value = computed({ get(): number { return Math.round(settingsStore.volume * 100); }, diff --git a/client/src/components/lobby/Lobby.vue b/client/src/components/lobby/Lobby.vue index 1ca7ad9..99e367e 100644 --- a/client/src/components/lobby/Lobby.vue +++ b/client/src/components/lobby/Lobby.vue @@ -10,10 +10,10 @@ import { useI18n } from 'vue-i18n'; const click = new AudioWrap(ClickMp3); const roomStore = useRoomStore(); -const leader = computed((): boolean => { +const leader = computed(() => { return !!roomStore.self && roomStore.self.leader; }); -const canStart = computed((): boolean => { +const canStart = computed(() => { return leader.value && roomStore.players.length >= 3; }); diff --git a/client/src/components/lobby/Options.vue b/client/src/components/lobby/Options.vue index 9654dc4..e8a5686 100644 --- a/client/src/components/lobby/Options.vue +++ b/client/src/components/lobby/Options.vue @@ -6,12 +6,9 @@ import { useGameStore } from '@/stores/game.js'; import { useI18n } from 'vue-i18n'; import { useRoomStore } from '@/stores/room.js'; -defineProps({ - disabled: { - type: Boolean, - required: true - } -}); +defineProps<{ + disabled: boolean; +}>(); const customSelected = ref(false); const timerDuration: Ref = ref(null); @@ -204,14 +201,13 @@ const { t } = useI18n();

+ aria-controls="form" />

diff --git a/client/src/components/lobby/PlayerCard.vue b/client/src/components/lobby/PlayerCard.vue index 45b5428..b7d2d59 100644 --- a/client/src/components/lobby/PlayerCard.vue +++ b/client/src/components/lobby/PlayerCard.vue @@ -1,12 +1,8 @@ diff --git a/client/src/components/responseMatching/DisputeIcon.vue b/client/src/components/responseMatching/DisputeIcon.vue index 6486a62..e796438 100644 --- a/client/src/components/responseMatching/DisputeIcon.vue +++ b/client/src/components/responseMatching/DisputeIcon.vue @@ -7,19 +7,13 @@ import socket from '@/socket/socket.js'; import { useI18n } from 'vue-i18n'; import { useGameStore } from '@/stores/game.js'; -defineProps({ - disabled: { - type: Boolean, - default: false - }, - response: { - type: String, - required: true - }, - placement: { - type: String, - required: true - } +interface Props { + disabled?: boolean; + response: string; + placement: string; +} +withDefaults(defineProps(), { + disabled: false }); const pressedVote = ref(false); diff --git a/client/src/components/responseMatching/MatchCard.vue b/client/src/components/responseMatching/MatchCard.vue index 1f9ec56..86c6b90 100644 --- a/client/src/components/responseMatching/MatchCard.vue +++ b/client/src/components/responseMatching/MatchCard.vue @@ -1,21 +1,15 @@ diff --git a/package-lock.json b/package-lock.json index e9f9632..59dc52e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,6 +14,7 @@ ], "devDependencies": { "@babel/types": "^7.23.6", + "@intlify/eslint-plugin-vue-i18n": "^2.0.0", "@rushstack/eslint-patch": "^1.6.1", "@typescript-eslint/eslint-plugin": "^6.18.0", "@typescript-eslint/parser": "^6.18.0", @@ -680,6 +681,18 @@ "node": ">=6.0.0" } }, + "node_modules/@babel/runtime": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.23.9.tgz", + "integrity": "sha512-0CX6F+BI2s9dkUqr08KFrAIZgNFj75rdBU/DjCyYLIaV/quFjkk6T+EJ2LkZHyZTbEV4L5p97mNkUsHl2wLFAw==", + "dev": true, + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, "node_modules/@babel/types": { "version": "7.23.6", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.6.tgz", @@ -1250,6 +1263,123 @@ "url": "https://github.com/sponsors/kazupon" } }, + "node_modules/@intlify/eslint-plugin-vue-i18n": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@intlify/eslint-plugin-vue-i18n/-/eslint-plugin-vue-i18n-2.0.0.tgz", + "integrity": "sha512-ECBD0TvQNa56XKyuM6FPIGAAl7MP6ODcgjBQJrzucNxcTb8fYTWmZ+xgBuvmvAtA0iE0D4Wp18UMild2N0bGyw==", + "dev": true, + "dependencies": { + "@eslint/eslintrc": "^1.2.0", + "@intlify/core-base": "^9.1.9", + "@intlify/message-compiler": "^9.1.9", + "debug": "^4.3.1", + "glob": "^8.0.0", + "ignore": "^5.0.5", + "is-language-code": "^3.1.0", + "js-yaml": "^4.0.0", + "json5": "^2.1.3", + "jsonc-eslint-parser": "^2.0.0", + "lodash": "^4.17.11", + "parse5": "^7.0.0", + "semver": "^7.3.4", + "vue-eslint-parser": "^9.0.0", + "yaml-eslint-parser": "^1.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@intlify/eslint-plugin-vue-i18n/node_modules/@eslint/eslintrc": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.4.1.tgz", + "integrity": "sha512-XXrH9Uarn0stsyldqDYq8r++mROmWRI1xKMXa640Bb//SY1+ECYX6VzT6Lcx5frD0V30XieqJ0oX9I2Xj5aoMA==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.4.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@intlify/eslint-plugin-vue-i18n/node_modules/glob": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", + "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^5.0.1", + "once": "^1.3.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@intlify/eslint-plugin-vue-i18n/node_modules/glob/node_modules/minimatch": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz", + "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@intlify/eslint-plugin-vue-i18n/node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@intlify/eslint-plugin-vue-i18n/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/@intlify/eslint-plugin-vue-i18n/node_modules/minimatch/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/@intlify/message-compiler": { "version": "9.9.1", "resolved": "https://registry.npmjs.org/@intlify/message-compiler/-/message-compiler-9.9.1.tgz", @@ -5235,6 +5365,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-language-code": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-language-code/-/is-language-code-3.1.0.tgz", + "integrity": "sha512-zJdQ3QTeLye+iphMeK3wks+vXSRFKh68/Pnlw7aOfApFSEIOhYa8P9vwwa6QrImNNBMJTiL1PpYF0f4BxDuEgA==", + "dev": true, + "dependencies": { + "@babel/runtime": "^7.14.0" + } + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -5390,6 +5529,24 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonc-eslint-parser": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/jsonc-eslint-parser/-/jsonc-eslint-parser-2.4.0.tgz", + "integrity": "sha512-WYDyuc/uFcGp6YtM2H0uKmUwieOuzeE/5YocFJLnLfclZ4inf3mRn8ZVy1s7Hxji7Jxm6Ss8gqpexD/GlKoGgg==", + "dev": true, + "dependencies": { + "acorn": "^8.5.0", + "eslint-visitor-keys": "^3.0.0", + "espree": "^9.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -6129,6 +6286,18 @@ "node": ">=6" } }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dev": true, + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -6562,6 +6731,12 @@ "node": ">= 10.13.0" } }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==", + "dev": true + }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -8254,6 +8429,32 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/yaml": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.3.4.tgz", + "integrity": "sha512-8aAvwVUSHpfEqTQ4w/KMlf3HcRdt50E5ODIQJBw1fQ5RL34xabzxtUlzTXVqc4rkZsPbvrXKWnABCD7kWSmocA==", + "dev": true, + "engines": { + "node": ">= 14" + } + }, + "node_modules/yaml-eslint-parser": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/yaml-eslint-parser/-/yaml-eslint-parser-1.2.2.tgz", + "integrity": "sha512-pEwzfsKbTrB8G3xc/sN7aw1v6A6c/pKxLAkjclnAyo5g5qOh6eL9WGu0o3cSDQZKrTNk4KL4lQSwZW+nBkANEg==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.0.0", + "lodash": "^4.17.21", + "yaml": "^2.0.0" + }, + "engines": { + "node": "^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ota-meshi" + } + }, "node_modules/yargs": { "version": "16.2.0", "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", diff --git a/package.json b/package.json index b2683be..434c645 100644 --- a/package.json +++ b/package.json @@ -21,6 +21,7 @@ }, "devDependencies": { "@babel/types": "^7.23.6", + "@intlify/eslint-plugin-vue-i18n": "^2.0.0", "@rushstack/eslint-patch": "^1.6.1", "@typescript-eslint/eslint-plugin": "^6.18.0", "@typescript-eslint/parser": "^6.18.0",