From f5c098421177c60cbf300ec96043a8cb04e73b9e Mon Sep 17 00:00:00 2001 From: AlecM33 Date: Tue, 11 Jan 2022 20:36:10 -0500 Subject: [PATCH] lint codebase --- .eslintrc.json | 28 + client/src/config/customCards.js | 12 - client/src/config/defaultCards.js | 54 +- client/src/config/globals.js | 34 +- client/src/model/Game.js | 2 +- client/src/modules/DeckStateManager.js | 101 +- client/src/modules/GameCreationStepManager.js | 429 +++-- client/src/modules/GameStateRenderer.js | 273 ++- client/src/modules/GameTimerManager.js | 69 +- client/src/modules/ModalManager.js | 16 +- client/src/modules/Navbar.js | 40 +- client/src/modules/StateBucket.js | 2 +- client/src/modules/Templates.js | 222 +-- client/src/modules/Timer.js | 23 +- client/src/modules/Toast.js | 16 +- client/src/modules/XHRUtility.js | 3 +- client/src/scripts/create.js | 14 +- client/src/scripts/game.js | 154 +- client/src/scripts/home.js | 45 +- client/src/scripts/howToUse.js | 2 +- client/src/scripts/notFound.js | 2 +- package-lock.json | 1501 ++++++++++++++++- package.json | 12 +- server/api/GamesAPI.js | 8 +- server/config/globals.js | 54 +- server/main.js | 10 +- server/model/Game.js | 2 +- server/model/Person.js | 4 +- server/modules/ActiveGameRunner.js | 2 +- server/modules/GameManager.js | 143 +- server/modules/GameProcess.js | 5 +- server/modules/GameStateCurator.js | 35 +- server/modules/Logger.js | 2 +- server/modules/ServerBootstrapper.js | 42 +- server/modules/ServerTimer.js | 18 +- server/modules/UsernameGenerator.js | 6 +- server/routes/router.js | 1 - server/routes/util.js | 4 +- 38 files changed, 2422 insertions(+), 968 deletions(-) create mode 100644 .eslintrc.json delete mode 100644 client/src/config/customCards.js diff --git a/.eslintrc.json b/.eslintrc.json new file mode 100644 index 0000000..6287566 --- /dev/null +++ b/.eslintrc.json @@ -0,0 +1,28 @@ +{ + "env": { + "browser": true, + "es2021": true, + "node": true + }, + "extends": [ + "standard" + ], + "ignorePatterns": ["/client/dist/*", "client/certs/*", "client/favicon_package/*", "client/webpack/*", "node_modules/*"], + "parser": "@babel/eslint-parser", + "parserOptions": { + "requireConfigFile": false, + "ecmaVersion": 12, + "sourceType": "module" + }, + "rules": { + "indent": ["error", 4, { "SwitchCase": 1 }], + "semi": [2, "always"], + "operator-linebreak": [2, "after", { "overrides": { "?": "before", ":": "before", "&&": "before", "||": "before", "+": "after" } }], + "no-void": ["error", { "allowAsStatement": true }], + "no-prototype-builtins": "off", + "no-undef": "off", + "no-return-assign": "warn", + "prefer-promise-reject-errors": "warn", + "no-trailing-spaces": "off" + } +} diff --git a/client/src/config/customCards.js b/client/src/config/customCards.js deleted file mode 100644 index 1bd4271..0000000 --- a/client/src/config/customCards.js +++ /dev/null @@ -1,12 +0,0 @@ -export const customCards = [ - { - role: "Santa", - team: "evil", - description: "hohoho", - }, - { - role: "The Thing", - team: "good", - description: "you go bump in the night", - }, -]; diff --git a/client/src/config/defaultCards.js b/client/src/config/defaultCards.js index 115b804..39891b4 100644 --- a/client/src/config/defaultCards.js +++ b/client/src/config/defaultCards.js @@ -1,47 +1,47 @@ export const defaultCards = [ { - role: "Villager", - team: "good", - description: "During the day, find the wolves and kill them.", + role: 'Villager', + team: 'good', + description: 'During the day, find the wolves and kill them.' }, { - role: "Werewolf", - team: "evil", - description: "During the night, choose a villager to kill. Don't get killed.", + role: 'Werewolf', + team: 'evil', + description: "During the night, choose a villager to kill. Don't get killed." }, { - role: "Dream Wolf", - team: "evil", - description: "You are a Werewolf, but you don't wake up with the other Werewolves until one of them dies.", + role: 'Dream Wolf', + team: 'evil', + description: "You are a Werewolf, but you don't wake up with the other Werewolves until one of them dies." }, { - role: "Sorceress", - team: "evil", - description: "Each night, learn if a chosen person is the Seer.", + role: 'Sorceress', + team: 'evil', + description: 'Each night, learn if a chosen person is the Seer.' }, { - role: "Minion", - team: "evil", - description: "You are an evil Villager, and you know who the Werewolves are.", + role: 'Minion', + team: 'evil', + description: 'You are an evil Villager, and you know who the Werewolves are.' }, { - role: "Blind Minion", - team: "evil", - description: "You are an evil villager, but you don't know who the Werewolves are.", + role: 'Blind Minion', + team: 'evil', + description: "You are an evil villager, but you don't know who the Werewolves are." }, { - role: "Seer", - team: "good", - description: "Each night, learn if a chosen person is a Werewolf.", + role: 'Seer', + team: 'good', + description: 'Each night, learn if a chosen person is a Werewolf.' }, { - role: "Parity Hunter", - team: "good", - description: "You beat a werewolf in a 1v1 situation, winning the game for the village.", + role: 'Parity Hunter', + team: 'good', + description: 'You beat a werewolf in a 1v1 situation, winning the game for the village.' }, { - role: "Hunter", - team: "good", - description: "When you are eliminated, choose another player to go with you.", + role: 'Hunter', + team: 'good', + description: 'When you are eliminated, choose another player to go with you.' } ]; diff --git a/client/src/config/globals.js b/client/src/config/globals.js index e50b2f7..5b374b8 100644 --- a/client/src/config/globals.js +++ b/client/src/config/globals.js @@ -22,37 +22,37 @@ export const globals = { FETCH_IN_PROGRESS_STATE: 'fetchInitialInProgressState' }, STATUS: { - LOBBY: "lobby", - IN_PROGRESS: "in progress", - ENDED: "ended" + LOBBY: 'lobby', + IN_PROGRESS: 'in progress', + ENDED: 'ended' }, ALIGNMENT: { - GOOD: "good", - EVIL: "evil" + GOOD: 'good', + EVIL: 'evil' }, MESSAGES: { - ENTER_NAME: "Client must enter name." + ENTER_NAME: 'Client must enter name.' }, EVENTS: { - PLAYER_JOINED: "playerJoined", - SYNC_GAME_STATE: "syncGameState", - START_TIMER: "startTimer", - KILL_PLAYER: "killPlayer", + PLAYER_JOINED: 'playerJoined', + SYNC_GAME_STATE: 'syncGameState', + START_TIMER: 'startTimer', + KILL_PLAYER: 'killPlayer', REVEAL_PLAYER: 'revealPlayer', CHANGE_NAME: 'changeName', START_GAME: 'startGame', PLAYER_LEFT: 'playerLeft' }, USER_TYPES: { - MODERATOR: "moderator", - PLAYER: "player", - TEMPORARY_MODERATOR: "player / temp mod", - KILLED_PLAYER: "killed", - SPECTATOR: "spectator" + MODERATOR: 'moderator', + PLAYER: 'player', + TEMPORARY_MODERATOR: 'player / temp mod', + KILLED_PLAYER: 'killed', + SPECTATOR: 'spectator' }, ENVIRONMENT: { - LOCAL: "local", - PRODUCTION: "production" + LOCAL: 'local', + PRODUCTION: 'production' }, USER_TYPE_ICONS: { player: ' \uD83C\uDFAE', diff --git a/client/src/model/Game.js b/client/src/model/Game.js index 54854c3..2b725e4 100644 --- a/client/src/model/Game.js +++ b/client/src/model/Game.js @@ -1,5 +1,5 @@ export class Game { - constructor(deck, hasTimer, hasDedicatedModerator, timerParams=null) { + constructor (deck, hasTimer, hasDedicatedModerator, timerParams = null) { this.deck = deck; this.hasTimer = hasTimer; this.timerParams = timerParams; diff --git a/client/src/modules/DeckStateManager.js b/client/src/modules/DeckStateManager.js index 99912da..12235cd 100644 --- a/client/src/modules/DeckStateManager.js +++ b/client/src/modules/DeckStateManager.js @@ -1,17 +1,17 @@ -import { globals } from "../config/globals.js"; -import {toast} from "./Toast.js"; -import {ModalManager} from "./ModalManager"; +import { globals } from '../config/globals.js'; +import { toast } from './Toast.js'; +import { ModalManager } from './ModalManager'; export class DeckStateManager { - constructor() { + constructor () { this.deck = null; this.customRoleOptions = []; this.createMode = false; this.currentlyEditingRoleName = null; } - addToDeck(role) { - let option = this.customRoleOptions.find((option) => option.role === role); + addToDeck (role) { + const option = this.customRoleOptions.find((option) => option.role === role); if (option) { option.quantity = 0; this.deck.push(option); @@ -19,102 +19,102 @@ export class DeckStateManager { } } - addToCustomRoleOptions(role) { + addToCustomRoleOptions (role) { this.customRoleOptions.push(role); - localStorage.setItem("play-werewolf-custom-roles", JSON.stringify(this.customRoleOptions.concat(this.deck.filter(card => card.custom === true)))); + localStorage.setItem('play-werewolf-custom-roles', JSON.stringify(this.customRoleOptions.concat(this.deck.filter(card => card.custom === true)))); } - updateCustomRoleOption(option, name, description, team) { + updateCustomRoleOption (option, name, description, team) { option.role = name; option.description = description; option.team = team; - localStorage.setItem("play-werewolf-custom-roles", JSON.stringify(this.customRoleOptions.concat(this.deck.filter(card => card.custom === true)))); + localStorage.setItem('play-werewolf-custom-roles', JSON.stringify(this.customRoleOptions.concat(this.deck.filter(card => card.custom === true)))); } - removeFromCustomRoleOptions(name) { - let option = this.customRoleOptions.find((option) => option.role === name); + removeFromCustomRoleOptions (name) { + const option = this.customRoleOptions.find((option) => option.role === name); if (option) { this.customRoleOptions.splice(this.customRoleOptions.indexOf(option), 1); - localStorage.setItem("play-werewolf-custom-roles", JSON.stringify(this.customRoleOptions.concat(this.deck.filter(card => card.custom === true)))); + localStorage.setItem('play-werewolf-custom-roles', JSON.stringify(this.customRoleOptions.concat(this.deck.filter(card => card.custom === true)))); toast('"' + name + '" deleted.', 'error', true, true, 3); } } - addCopyOfCard(role) { - let existingCard = this.deck.find((card) => card.role === role) + addCopyOfCard (role) { + const existingCard = this.deck.find((card) => card.role === role); if (existingCard) { existingCard.quantity += 1; } } - removeCopyOfCard(role) { - let existingCard = this.deck.find((card) => card.role === role) + removeCopyOfCard (role) { + const existingCard = this.deck.find((card) => card.role === role); if (existingCard && existingCard.quantity > 0) { existingCard.quantity -= 1; } } - getCurrentDeck() { return this.deck; } + getCurrentDeck () { return this.deck; } - getCard(role) { + getCard (role) { return this.deck.find( (card) => card.role.toLowerCase().trim() === role.toLowerCase().trim() ); } - getCurrentCustomRoleOptions() { return this.customRoleOptions; } + getCurrentCustomRoleOptions () { return this.customRoleOptions; } - getCustomRoleOption(role) { + getCustomRoleOption (role) { return this.customRoleOptions.find( (option) => option.role.toLowerCase().trim() === role.toLowerCase().trim() - ) + ); }; - getDeckSize() { + getDeckSize () { let total = 0; - for (let role of this.deck) { + for (const role of this.deck) { total += role.quantity; } return total; } - loadCustomRolesFromCookies() { - let customRoles = localStorage.getItem('play-werewolf-custom-roles'); + loadCustomRolesFromCookies () { + const customRoles = localStorage.getItem('play-werewolf-custom-roles'); if (customRoles !== null && validateCustomRoleCookie(customRoles)) { this.customRoleOptions = JSON.parse(customRoles); // we know it is valid JSON from the validate function } } - loadCustomRolesFromFile(file, updateRoleListFunction, loadDefaultCardsFn, showIncludedCardsFn) { - let reader = new FileReader(); + loadCustomRolesFromFile (file, updateRoleListFunction, loadDefaultCardsFn, showIncludedCardsFn) { + const reader = new FileReader(); reader.onerror = (e) => { - toast(reader.error.message, "error", true, true, 5); - } + toast(reader.error.message, 'error', true, true, 5); + }; reader.onload = (e) => { let string; - if (typeof e.target.result !== "string") { - string = new TextDecoder("utf-8").decode(e.target.result); + if (typeof e.target.result !== 'string') { + string = new TextDecoder('utf-8').decode(e.target.result); } else { string = e.target.result; } if (validateCustomRoleCookie(string)) { this.customRoleOptions = JSON.parse(string); // we know it is valid JSON from the validate function - ModalManager.dispelModal("upload-custom-roles-modal", "modal-background"); - toast("Roles imported successfully", "success", true, true, 3); - localStorage.setItem("play-werewolf-custom-roles", JSON.stringify(this.customRoleOptions)); - updateRoleListFunction(this, document.getElementById("deck-select")); + ModalManager.dispelModal('upload-custom-roles-modal', 'modal-background'); + toast('Roles imported successfully', 'success', true, true, 3); + localStorage.setItem('play-werewolf-custom-roles', JSON.stringify(this.customRoleOptions)); + updateRoleListFunction(this, document.getElementById('deck-select')); // loadDefaultCardsFn(this); // showIncludedCardsFn(this); } else { - toast("Invalid formatting. Make sure you import the file as downloaded from this page.", "error", true, true, 5); + toast('Invalid formatting. Make sure you import the file as downloaded from this page.', 'error', true, true, 5); } - } + }; reader.readAsText(file); } // via https://stackoverflow.com/a/18197341 - downloadCustomRoles(filename, text) { - let element = document.createElement('a'); + downloadCustomRoles (filename, text) { + const element = document.createElement('a'); element.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(text)); element.setAttribute('download', filename); @@ -125,21 +125,20 @@ export class DeckStateManager { document.body.removeChild(element); } - } // this is user-supplied, so we should validate it fully -function validateCustomRoleCookie(cookie) { - let valid = false; - if (typeof cookie === "string" && new Blob([cookie]).size <= 1000000) { +function validateCustomRoleCookie (cookie) { + const valid = false; + if (typeof cookie === 'string' && new Blob([cookie]).size <= 1000000) { try { - let cookieJSON = JSON.parse(cookie); + const cookieJSON = JSON.parse(cookie); if (Array.isArray(cookieJSON)) { - for (let entry of cookieJSON) { - if (typeof entry === "object") { - if (typeof entry.role !== "string" || entry.role.length > globals.MAX_CUSTOM_ROLE_NAME_LENGTH - || typeof entry.team !== "string" || (entry.team !== globals.ALIGNMENT.GOOD && entry.team !== globals.ALIGNMENT.EVIL) - || typeof entry.description !== "string" || entry.description.length > globals.MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH + for (const entry of cookieJSON) { + if (typeof entry === 'object') { + if (typeof entry.role !== 'string' || entry.role.length > globals.MAX_CUSTOM_ROLE_NAME_LENGTH + || typeof entry.team !== 'string' || (entry.team !== globals.ALIGNMENT.GOOD && entry.team !== globals.ALIGNMENT.EVIL) + || typeof entry.description !== 'string' || entry.description.length > globals.MAX_CUSTOM_ROLE_DESCRIPTION_LENGTH ) { return false; } @@ -149,7 +148,7 @@ function validateCustomRoleCookie(cookie) { } return true; } - } catch(e) { + } catch (e) { return false; } } diff --git a/client/src/modules/GameCreationStepManager.js b/client/src/modules/GameCreationStepManager.js index f06a0cb..a126d62 100644 --- a/client/src/modules/GameCreationStepManager.js +++ b/client/src/modules/GameCreationStepManager.js @@ -1,14 +1,13 @@ -import { Game } from "../model/Game.js"; -import { cancelCurrentToast, toast } from "./Toast.js"; -import { customCards } from "../config/customCards.js"; -import { ModalManager } from "./ModalManager.js"; -import {XHRUtility} from "./XHRUtility.js"; -import {globals} from "../config/globals.js"; -import {templates} from "./Templates.js"; -import {defaultCards} from "../config/defaultCards"; +import { Game } from '../model/Game.js'; +import { cancelCurrentToast, toast } from './Toast.js'; +import { ModalManager } from './ModalManager.js'; +import { XHRUtility } from './XHRUtility.js'; +import { globals } from '../config/globals.js'; +import { templates } from './Templates.js'; +import { defaultCards } from '../config/defaultCards'; export class GameCreationStepManager { - constructor(deckManager) { + constructor (deckManager) { loadDefaultCards(deckManager); deckManager.loadCustomRolesFromCookies(); this.step = 1; @@ -18,42 +17,42 @@ export class GameCreationStepManager { cancelCurrentToast(); this.removeStepElementsFromDOM(this.step); this.decrementStep(); - this.renderStep("creation-step-container", this.step); - } + this.renderStep('creation-step-container', this.step); + }; this.steps = { 1: { - title: "Select your method of moderation:", + title: 'Select your method of moderation:', forwardHandler: () => { if (this.currentGame.hasDedicatedModerator !== null) { cancelCurrentToast(); this.removeStepElementsFromDOM(this.step); this.incrementStep(); - this.renderStep("creation-step-container", this.step); + this.renderStep('creation-step-container', this.step); } else { - toast("You must select a moderation option.", "error", true); + toast('You must select a moderation option.', 'error', true); } } }, 2: { - title: "Create your deck of cards:", + title: 'Create your deck of cards:', forwardHandler: () => { if (this.deckManager.getDeckSize() >= 5 && this.deckManager.getDeckSize() <= 50) { - this.currentGame.deck = deckManager.getCurrentDeck().filter((card) => card.quantity > 0) + this.currentGame.deck = deckManager.getCurrentDeck().filter((card) => card.quantity > 0); cancelCurrentToast(); this.removeStepElementsFromDOM(this.step); this.incrementStep(); - this.renderStep("creation-step-container", this.step); + this.renderStep('creation-step-container', this.step); } else { - toast("You must have a deck for between 5 and 50 players", "error", true); + toast('You must have a deck for between 5 and 50 players', 'error', true); } }, backHandler: this.defaultBackHandler }, 3: { - title: "Set an optional timer:", + title: 'Set an optional timer:', forwardHandler: () => { - let hours = parseInt(document.getElementById("game-hours").value); - let minutes = parseInt(document.getElementById("game-minutes").value); + const hours = parseInt(document.getElementById('game-hours').value); + const minutes = parseInt(document.getElementById('game-minutes').value); if ((isNaN(hours) && isNaN(minutes)) || (isNaN(hours) && minutes > 0 && minutes < 60) || (isNaN(minutes) && hours > 0 && hours < 6) @@ -66,7 +65,7 @@ export class GameCreationStepManager { this.currentGame.timerParams = { hours: hours, minutes: minutes - } + }; } else { this.currentGame.hasTimer = false; this.currentGame.timerParams = null; @@ -74,19 +73,19 @@ export class GameCreationStepManager { cancelCurrentToast(); this.removeStepElementsFromDOM(this.step); this.incrementStep(); - this.renderStep("creation-step-container", this.step); + this.renderStep('creation-step-container', this.step); } else { if (hours === 0 && minutes === 0) { - toast("You must enter a non-zero amount of time.", "error", true); + toast('You must enter a non-zero amount of time.', 'error', true); } else { - toast("Invalid timer options. Hours can be a max of 5, Minutes a max of 59.", "error", true); + toast('Invalid timer options. Hours can be a max of 5, Minutes a max of 59.', 'error', true); } } }, backHandler: this.defaultBackHandler }, 4: { - title: "Review and submit:", + title: 'Review and submit:', backHandler: this.defaultBackHandler, forwardHandler: (deck, hasTimer, hasDedicatedModerator, timerParams) => { XHRUtility.xhr( @@ -97,40 +96,40 @@ export class GameCreationStepManager { new Game(deck, hasTimer, hasDedicatedModerator, timerParams) ) ) - .then((res) => { - if (res + .then((res) => { + if (res && typeof res === 'object' && Object.prototype.hasOwnProperty.call(res, 'content') && typeof res.content === 'string' - ) { - window.location = ('/game/' + res.content); - } - }).catch((e) => { - if (e.status === 429) { - toast('You\'ve sent this request too many times.', 'error', true, true, 6); - } - }); + ) { + window.location = ('/game/' + res.content); + } + }).catch((e) => { + if (e.status === 429) { + toast('You\'ve sent this request too many times.', 'error', true, true, 6); + } + }); } } - } + }; } - incrementStep() { + incrementStep () { if (this.step < Object.keys(this.steps).length) { this.step += 1; } } - decrementStep() { + decrementStep () { if (this.step > 1) { this.step -= 1; } } - renderStep(containerId, step) { + renderStep (containerId, step) { document.querySelectorAll('.animated-placeholder').forEach((el) => el.remove()); document.querySelectorAll('.placeholder-row').forEach((el) => el.remove()); - document.getElementById("step-title").innerText = this.steps[step].title; + document.getElementById('step-title').innerText = this.steps[step].title; switch (step) { case 1: renderModerationTypeStep(this.currentGame, containerId, step); @@ -154,24 +153,24 @@ export class GameCreationStepManager { updateTracker(step); } - removeStepElementsFromDOM(stepNumber) { + removeStepElementsFromDOM (stepNumber) { document.getElementById('step-' + stepNumber)?.remove(); } } -function renderModerationTypeStep(game, containerId, stepNumber) { - const stepContainer = document.createElement("div"); - setAttributes(stepContainer, {'id': 'step-' + stepNumber, 'class': 'flex-row-container step'}); +function renderModerationTypeStep (game, containerId, stepNumber) { + const stepContainer = document.createElement('div'); + setAttributes(stepContainer, { id: 'step-' + stepNumber, class: 'flex-row-container step' }); stepContainer.innerHTML = "
I will be the dedicated mod. Don't deal me a card.
" + "
The first person out will mod. Deal me into the game (mod will be assigned automatically).
"; - let dedicatedOption = stepContainer.querySelector('#moderation-dedicated'); + const dedicatedOption = stepContainer.querySelector('#moderation-dedicated'); if (game.hasDedicatedModerator) { dedicatedOption.classList.add('option-selected'); } - let selfOption = stepContainer.querySelector('#moderation-self'); + const selfOption = stepContainer.querySelector('#moderation-self'); if (game.hasDedicatedModerator === false) { selfOption.classList.add('option-selected'); } @@ -191,9 +190,9 @@ function renderModerationTypeStep(game, containerId, stepNumber) { document.getElementById(containerId).appendChild(stepContainer); } -function renderRoleSelectionStep(game, containerId, step, deckManager) { - const stepContainer = document.createElement("div"); - setAttributes(stepContainer, {'id': 'step-' + step, 'class': 'flex-row-container-left-align step'}); +function renderRoleSelectionStep (game, containerId, step, deckManager) { + const stepContainer = document.createElement('div'); + setAttributes(stepContainer, { id: 'step-' + step, class: 'flex-row-container-left-align step' }); stepContainer.innerHTML = templates.CREATE_GAME_CUSTOM_ROLES; stepContainer.innerHTML += templates.CREATE_GAME_DECK_STATUS; @@ -207,32 +206,32 @@ function renderRoleSelectionStep(game, containerId, step, deckManager) { document.querySelector('#custom-roles-import').addEventListener('click', (e) => { e.preventDefault(); - ModalManager.displayModal("upload-custom-roles-modal", "modal-background", "close-upload-custom-roles-modal-button"); + ModalManager.displayModal('upload-custom-roles-modal', 'modal-background', 'close-upload-custom-roles-modal-button'); }); - document.getElementById("upload-custom-roles-form").onsubmit = (e) => { + document.getElementById('upload-custom-roles-form').onsubmit = (e) => { e.preventDefault(); - let fileList = document.getElementById("upload-custom-roles").files; + const fileList = document.getElementById('upload-custom-roles').files; if (fileList.length > 0) { - let file = fileList[0]; + const file = fileList[0]; if (file.size > 1000000) { - toast("Your file is too large (max 1MB)", "error", true, true, 5); + toast('Your file is too large (max 1MB)', 'error', true, true, 5); return; } - if (file.type !== "text/plain") { - toast("Your file must be a text file", "error", true, true, 5); + if (file.type !== 'text/plain') { + toast('Your file must be a text file', 'error', true, true, 5); return; } deckManager.loadCustomRolesFromFile(file, updateCustomRoleOptionsList, loadDefaultCards, showIncludedCards); } else { - toast("You must upload a text file", "error", true, true, 5); + toast('You must upload a text file', 'error', true, true, 5); } - } + }; - let clickHandler = () => { - console.log("fired"); - let actions = document.getElementById("custom-role-actions"); + const clickHandler = () => { + console.log('fired'); + const actions = document.getElementById('custom-role-actions'); if (actions.style.display !== 'none') { actions.style.display = 'none'; } else { @@ -240,7 +239,7 @@ function renderRoleSelectionStep(game, containerId, step, deckManager) { } }; - document.getElementById("custom-role-hamburger").addEventListener("click", clickHandler); + document.getElementById('custom-role-hamburger').addEventListener('click', clickHandler); showIncludedCards(deckManager); @@ -251,27 +250,27 @@ function renderRoleSelectionStep(game, containerId, step, deckManager) { initializeRemainingEventListeners(deckManager); } -function renderTimerStep(containerId, stepNumber, game) { - let div = document.createElement("div"); - div.setAttribute("id", "step-" + stepNumber); +function renderTimerStep (containerId, stepNumber, game) { + const div = document.createElement('div'); + div.setAttribute('id', 'step-' + stepNumber); div.classList.add('step'); - let timeContainer = document.createElement("div"); - timeContainer.setAttribute("id", "game-time"); + const timeContainer = document.createElement('div'); + timeContainer.setAttribute('id', 'game-time'); - let hoursDiv = document.createElement("div"); - let hoursLabel = document.createElement("label"); - hoursLabel.setAttribute("for", "game-hours"); - hoursLabel.innerText = "Hours (max 5)" - let hours = document.createElement("input"); - setAttributes(hours, {type: "number", id: "game-hours", name: "game-hours", min: "0", max: "5", value: game.timerParams?.hours}) + const hoursDiv = document.createElement('div'); + const hoursLabel = document.createElement('label'); + hoursLabel.setAttribute('for', 'game-hours'); + hoursLabel.innerText = 'Hours (max 5)'; + const hours = document.createElement('input'); + setAttributes(hours, { type: 'number', id: 'game-hours', name: 'game-hours', min: '0', max: '5', value: game.timerParams?.hours }); - let minutesDiv = document.createElement("div"); - let minsLabel = document.createElement("label"); - minsLabel.setAttribute("for", "game-minutes"); - minsLabel.innerText = "Minutes" - let minutes = document.createElement("input"); - setAttributes(minutes, {type: "number", id: "game-minutes", name: "game-minutes", min: "1", max: "60", value: game.timerParams?.minutes}) + const minutesDiv = document.createElement('div'); + const minsLabel = document.createElement('label'); + minsLabel.setAttribute('for', 'game-minutes'); + minsLabel.innerText = 'Minutes'; + const minutes = document.createElement('input'); + setAttributes(minutes, { type: 'number', id: 'game-minutes', name: 'game-minutes', min: '1', max: '60', value: game.timerParams?.minutes }); hoursDiv.appendChild(hoursLabel); hoursDiv.appendChild(hours); @@ -284,46 +283,45 @@ function renderTimerStep(containerId, stepNumber, game) { document.getElementById(containerId).appendChild(div); } -function renderReviewAndCreateStep(containerId, stepNumber, game) { - let div = document.createElement("div"); - div.setAttribute("id", "step-" + stepNumber); +function renderReviewAndCreateStep (containerId, stepNumber, game) { + const div = document.createElement('div'); + div.setAttribute('id', 'step-' + stepNumber); div.classList.add('step'); div.innerHTML = - "
" + + '
' + "" + "
" + - "
" + - "
" + + '
' + + '
' + "" + "
" + - "
" + - "
" + + '
' + + '
' + "" + "
" + - "
"; - + '
'; div.querySelector('#mod-option').innerText = game.hasDedicatedModerator - ? "I will be the dedicated mod. Don't deal me a card." - : "The first person out will mod. Deal me into the game."; + ? "I will be the dedicated mod. Don't deal me a card." + : 'The first person out will mod. Deal me into the game.'; if (game.hasTimer) { - let formattedHours = !isNaN(game.timerParams.hours) + const formattedHours = !isNaN(game.timerParams.hours) ? game.timerParams.hours + ' Hours' - : '0 Hours' + : '0 Hours'; - let formattedMinutes = !isNaN(game.timerParams.minutes) + const formattedMinutes = !isNaN(game.timerParams.minutes) ? game.timerParams.minutes + ' Minutes' - : '0 Minutes' + : '0 Minutes'; - div.querySelector('#timer-option').innerText = formattedHours + " " + formattedMinutes; + div.querySelector('#timer-option').innerText = formattedHours + ' ' + formattedMinutes; } else { - div.querySelector('#timer-option').innerText = "untimed" + div.querySelector('#timer-option').innerText = 'untimed'; } - for (let card of game.deck) { - let roleEl = document.createElement("div"); + for (const card of game.deck) { + const roleEl = document.createElement('div'); roleEl.innerText = card.quantity + 'x ' + card.role; div.querySelector('#roles-option').appendChild(roleEl); } @@ -331,49 +329,49 @@ function renderReviewAndCreateStep(containerId, stepNumber, game) { document.getElementById(containerId).appendChild(div); } -function setAttributes(element, attributeObject) { - for (let key of Object.keys(attributeObject)) { +function setAttributes (element, attributeObject) { + for (const key of Object.keys(attributeObject)) { element.setAttribute(key, attributeObject[key]); } } -function updateTracker(step) { +function updateTracker (step) { document.querySelectorAll('.creation-step').forEach((element, i) => { if ((i + 1) <= step) { element.classList.add('creation-step-filled'); } else { element.classList.remove('creation-step-filled'); } - }) + }); } -function showButtons(back, forward, forwardHandler, backHandler, builtGame=null) { - document.querySelector("#step-back-button")?.remove(); - document.querySelector("#step-forward-button")?.remove(); - document.querySelector("#create-game")?.remove(); +function showButtons (back, forward, forwardHandler, backHandler, builtGame = null) { + document.querySelector('#step-back-button')?.remove(); + document.querySelector('#step-forward-button')?.remove(); + document.querySelector('#create-game')?.remove(); if (back) { - let backButton = document.createElement("button"); - backButton.innerText = "\u25C0"; + const backButton = document.createElement('button'); + backButton.innerText = '\u25C0'; backButton.addEventListener('click', backHandler); - backButton.setAttribute("id", "step-back-button"); + backButton.setAttribute('id', 'step-back-button'); backButton.classList.add('cancel'); backButton.classList.add('app-button'); - document.getElementById("tracker-container").prepend(backButton); + document.getElementById('tracker-container').prepend(backButton); } if (forward && builtGame === null) { - let fwdButton = document.createElement("button"); - fwdButton.innerHTML = "\u25b6"; + const fwdButton = document.createElement('button'); + fwdButton.innerHTML = '\u25b6'; fwdButton.addEventListener('click', forwardHandler); - fwdButton.setAttribute("id", "step-forward-button"); + fwdButton.setAttribute('id', 'step-forward-button'); fwdButton.classList.add('app-button'); - document.getElementById("tracker-container").appendChild(fwdButton); + document.getElementById('tracker-container').appendChild(fwdButton); } else if (forward && builtGame !== null) { - let createButton = document.createElement("button"); - createButton.innerText = "Create"; - createButton.setAttribute("id", "create-game"); + const createButton = document.createElement('button'); + createButton.innerText = 'Create'; + createButton.setAttribute('id', 'create-game'); createButton.classList.add('app-button'); - createButton.addEventListener("click", () => { + createButton.addEventListener('click', () => { forwardHandler( builtGame.deck.filter((card) => card.quantity > 0), builtGame.hasTimer, @@ -381,66 +379,65 @@ function showButtons(back, forward, forwardHandler, backHandler, builtGame=null) builtGame.timerParams ); }); - document.getElementById("tracker-container").appendChild(createButton); + document.getElementById('tracker-container').appendChild(createButton); } } // Display a widget for each default card that allows copies of it to be added/removed. Set initial deck state. -function showIncludedCards(deckManager) { - document.querySelectorAll('.compact-card').forEach((el) => { el.remove() }); - for (let i = 0; i < deckManager.getCurrentDeck().length; i ++) { - let card = deckManager.getCurrentDeck()[i]; - let cardEl = constructCompactDeckBuilderElement(card, deckManager); +function showIncludedCards (deckManager) { + document.querySelectorAll('.compact-card').forEach((el) => { el.remove(); }); + for (let i = 0; i < deckManager.getCurrentDeck().length; i++) { + const card = deckManager.getCurrentDeck()[i]; + const cardEl = constructCompactDeckBuilderElement(card, deckManager); if (card.team === globals.ALIGNMENT.GOOD) { - document.getElementById("deck-good").appendChild(cardEl); + document.getElementById('deck-good').appendChild(cardEl); } else { - document.getElementById("deck-evil").appendChild(cardEl); + document.getElementById('deck-evil').appendChild(cardEl); } } } /* Display a dropdown containing all the custom roles. Adding one will add it to the game deck and create a widget for it */ -function loadCustomRoles(deckManager) { - let select = document.getElementById("deck-select"); - addOptionsToList(deckManager, document.getElementById("deck-select")); +function loadCustomRoles (deckManager) { + addOptionsToList(deckManager, document.getElementById('deck-select')); } -function loadDefaultCards(deckManager) { +function loadDefaultCards (deckManager) { defaultCards.sort((a, b) => { if (a.team !== b.team) { return a.team === globals.ALIGNMENT.GOOD ? 1 : -1; } return a.role.localeCompare(b.role); }); - let deck = []; - for (let i = 0; i < defaultCards.length; i ++) { - let card = defaultCards[i]; + const deck = []; + for (let i = 0; i < defaultCards.length; i++) { + const card = defaultCards[i]; card.quantity = 0; deck.push(card); } deckManager.deck = deck; } -function constructCompactDeckBuilderElement(card, deckManager) { - const cardContainer = document.createElement("div"); - let alignmentClass = card.team === globals.ALIGNMENT.GOOD ? globals.ALIGNMENT.GOOD : globals.ALIGNMENT.EVIL +function constructCompactDeckBuilderElement (card, deckManager) { + const cardContainer = document.createElement('div'); + const alignmentClass = card.team === globals.ALIGNMENT.GOOD ? globals.ALIGNMENT.GOOD : globals.ALIGNMENT.EVIL; - cardContainer.setAttribute("class", "compact-card " + alignmentClass); + cardContainer.setAttribute('class', 'compact-card ' + alignmentClass); - cardContainer.setAttribute("id", "card-" + card.role.replaceAll(' ', '-')); + cardContainer.setAttribute('id', 'card-' + card.role.replaceAll(' ', '-')); cardContainer.innerHTML = "
" + - "

-

" + - "
" + + '

-

' + + '' + "
" + "

" + "
" + - "
" + + '' + "
" + - "

+

" + - "
"; + '

+

' + + ''; cardContainer.querySelector('.card-role').innerText = card.role; cardContainer.title = card.role; @@ -455,7 +452,7 @@ function constructCompactDeckBuilderElement(card, deckManager) { updateDeckStatus(deckManager); cardContainer.querySelector('.card-quantity').innerText = deckManager.getCard(card.role).quantity; if (deckManager.getCard(card.role).quantity > 0) { - document.getElementById('card-' + card.role.replaceAll(' ', '-')).classList.add('selected-card') + document.getElementById('card-' + card.role.replaceAll(' ', '-')).classList.add('selected-card'); } }); cardContainer.querySelector('.compact-card-left').addEventListener('click', () => { @@ -463,95 +460,95 @@ function constructCompactDeckBuilderElement(card, deckManager) { updateDeckStatus(deckManager); cardContainer.querySelector('.card-quantity').innerText = deckManager.getCard(card.role).quantity; if (deckManager.getCard(card.role).quantity === 0) { - document.getElementById('card-' + card.role.replaceAll(' ', '-')).classList.remove('selected-card') + document.getElementById('card-' + card.role.replaceAll(' ', '-')).classList.remove('selected-card'); } }); return cardContainer; } -function initializeRemainingEventListeners(deckManager) { - document.getElementById("role-form").onsubmit = (e) => { +function initializeRemainingEventListeners (deckManager) { + document.getElementById('role-form').onsubmit = (e) => { e.preventDefault(); - let name = document.getElementById("role-name").value.trim(); - let description = document.getElementById("role-description").value.trim(); - let team = document.getElementById("role-alignment").value.toLowerCase().trim(); + const name = document.getElementById('role-name').value.trim(); + const description = document.getElementById('role-description').value.trim(); + const team = document.getElementById('role-alignment').value.toLowerCase().trim(); if (deckManager.createMode) { if (!deckManager.getCustomRoleOption(name) && !deckManager.getCard(name)) { // confirm there is no existing custom role with the same name - processNewCustomRoleSubmission(name, description, team, deckManager,false); + processNewCustomRoleSubmission(name, description, team, deckManager, false); } else { - toast("There is already a role with this name", "error", true, true, 3); + toast('There is already a role with this name', 'error', true, true, 3); } } else { - let option = deckManager.getCustomRoleOption(deckManager.currentlyEditingRoleName); + const option = deckManager.getCustomRoleOption(deckManager.currentlyEditingRoleName); if (name === option.role) { // did they edit the name? - processNewCustomRoleSubmission(name, description, team, deckManager,true, option); + processNewCustomRoleSubmission(name, description, team, deckManager, true, option); } else { if (!deckManager.getCustomRoleOption(name) && !deckManager.getCard(name)) { processNewCustomRoleSubmission(name, description, team, deckManager, true, option); } else { - toast("There is already a role with this name", "error", true, true, 3); + toast('There is already a role with this name', 'error', true, true, 3); } } } - } - document.getElementById("custom-role-btn").addEventListener( - "click", () => { - let createBtn = document.getElementById("create-role-button"); - createBtn.setAttribute("value", "Create"); + }; + document.getElementById('custom-role-btn').addEventListener( + 'click', () => { + const createBtn = document.getElementById('create-role-button'); + createBtn.setAttribute('value', 'Create'); deckManager.createMode = true; deckManager.currentlyEditingRoleName = null; - document.getElementById("role-name").value = ""; - document.getElementById("role-alignment").value = globals.ALIGNMENT.GOOD; - document.getElementById("role-description").value = ""; + document.getElementById('role-name').value = ''; + document.getElementById('role-alignment').value = globals.ALIGNMENT.GOOD; + document.getElementById('role-description').value = ''; ModalManager.displayModal( - "role-modal", - "modal-background", - "close-modal-button" - ) + 'role-modal', + 'modal-background', + 'close-modal-button' + ); } - ) + ); } -function processNewCustomRoleSubmission(name, description, team, deckManager, isUpdate, option=null) { +function processNewCustomRoleSubmission (name, description, team, deckManager, isUpdate, option = null) { if (name.length > 40) { - toast('Your name is too long (max 40 characters).', "error", true); + toast('Your name is too long (max 40 characters).', 'error', true); return; } if (description.length > 500) { - toast('Your description is too long (max 500 characters).', "error", true); + toast('Your description is too long (max 500 characters).', 'error', true); return; } if (isUpdate) { deckManager.updateCustomRoleOption(option, name, description, team); - ModalManager.dispelModal("role-modal", "modal-background"); - toast("Role Updated", "success", true); + ModalManager.dispelModal('role-modal', 'modal-background'); + toast('Role Updated', 'success', true); } else { - deckManager.addToCustomRoleOptions({role: name, description: description, team: team, custom: true}); - ModalManager.dispelModal("role-modal", "modal-background"); - toast("Role Created", "success", true); + deckManager.addToCustomRoleOptions({ role: name, description: description, team: team, custom: true }); + ModalManager.dispelModal('role-modal', 'modal-background'); + toast('Role Created', 'success', true); } - updateCustomRoleOptionsList(deckManager, document.getElementById("deck-select")); + updateCustomRoleOptionsList(deckManager, document.getElementById('deck-select')); } -function updateCustomRoleOptionsList(deckManager, selectEl) { +function updateCustomRoleOptionsList (deckManager, selectEl) { document.querySelectorAll('#deck-select .deck-select-role').forEach(e => e.remove()); addOptionsToList(deckManager, selectEl); } -function addOptionsToList(deckManager, selectEl) { - let options = deckManager.getCurrentCustomRoleOptions(); +function addOptionsToList (deckManager, selectEl) { + const options = deckManager.getCurrentCustomRoleOptions(); options.sort((a, b) => { if (a.team !== b.team) { return a.team === globals.ALIGNMENT.GOOD ? 1 : -1; } return a.role.localeCompare(b.role); }); - for (let i = 0; i < options.length; i ++) { - let optionEl = document.createElement("div"); + for (let i = 0; i < options.length; i++) { + const optionEl = document.createElement('div'); optionEl.innerHTML = templates.DECK_SELECT_ROLE; optionEl.classList.add('deck-select-role'); - let alignmentClass = options[i].team === globals.ALIGNMENT.GOOD ? globals.ALIGNMENT.GOOD : globals.ALIGNMENT.EVIL + const alignmentClass = options[i].team === globals.ALIGNMENT.GOOD ? globals.ALIGNMENT.GOOD : globals.ALIGNMENT.EVIL; optionEl.classList.add(alignmentClass); optionEl.querySelector('.deck-select-role-name').innerText = options[i].role; selectEl.appendChild(optionEl); @@ -560,19 +557,19 @@ function addOptionsToList(deckManager, selectEl) { addCustomRoleEventListeners(deckManager, selectEl); } -function addCustomRoleEventListeners(deckManager, select) { +function addCustomRoleEventListeners (deckManager, select) { document.querySelectorAll('.deck-select-role').forEach((role) => { - let name = role.querySelector('.deck-select-role-name').innerText; + const name = role.querySelector('.deck-select-role-name').innerText; role.querySelector('.deck-select-include').addEventListener('click', (e) => { e.preventDefault(); if (!deckManager.getCard(name)) { deckManager.addToDeck(name); - let cardEl = constructCompactDeckBuilderElement(deckManager.getCard(name), deckManager); + const cardEl = constructCompactDeckBuilderElement(deckManager.getCard(name), deckManager); toast('"' + name + '" made available below.', 'success', true, true, 4); if (deckManager.getCard(name).team === globals.ALIGNMENT.GOOD) { - document.getElementById("deck-good").appendChild(cardEl); + document.getElementById('deck-good').appendChild(cardEl); } else { - document.getElementById("deck-evil").appendChild(cardEl); + document.getElementById('deck-evil').appendChild(cardEl); } updateCustomRoleOptionsList(deckManager, select); } else { @@ -589,52 +586,48 @@ function addCustomRoleEventListeners(deckManager, select) { }); role.querySelector('.deck-select-info').addEventListener('click', (e) => { - let alignmentEl = document.getElementById("custom-role-info-modal-alignment"); + const alignmentEl = document.getElementById('custom-role-info-modal-alignment'); alignmentEl.classList.remove(globals.ALIGNMENT.GOOD); alignmentEl.classList.remove(globals.ALIGNMENT.EVIL); e.preventDefault(); - let option = deckManager.getCustomRoleOption(name); - document.getElementById("custom-role-info-modal-name").innerText = name; + const option = deckManager.getCustomRoleOption(name); + document.getElementById('custom-role-info-modal-name').innerText = name; alignmentEl.classList.add(option.team); - document.getElementById("custom-role-info-modal-description").innerText = option.description; + document.getElementById('custom-role-info-modal-description').innerText = option.description; alignmentEl.innerText = option.team; - ModalManager.displayModal("custom-role-info-modal", "modal-background", "close-custom-role-info-modal-button"); + ModalManager.displayModal('custom-role-info-modal', 'modal-background', 'close-custom-role-info-modal-button'); }); role.querySelector('.deck-select-edit').addEventListener('click', (e) => { e.preventDefault(); - let option = deckManager.getCustomRoleOption(name); - document.getElementById("role-name").value = option.role; - document.getElementById("role-alignment").value = option.team; - document.getElementById("role-description").value = option.description; + const option = deckManager.getCustomRoleOption(name); + document.getElementById('role-name').value = option.role; + document.getElementById('role-alignment').value = option.team; + document.getElementById('role-description').value = option.description; deckManager.createMode = false; deckManager.currentlyEditingRoleName = option.role; - let createBtn = document.getElementById("create-role-button"); - createBtn.setAttribute("value", "Update"); - ModalManager.displayModal("role-modal", "modal-background", "close-modal-button"); + const createBtn = document.getElementById('create-role-button'); + createBtn.setAttribute('value', 'Update'); + ModalManager.displayModal('role-modal', 'modal-background', 'close-modal-button'); }); }); } -function displayCustomRoleModalInAddOrEditMode() { - let ad -} - -function updateDeckStatus(deckManager) { +function updateDeckStatus (deckManager) { document.querySelectorAll('.deck-role').forEach((el) => el.remove()); - document.getElementById("deck-count").innerText = deckManager.getDeckSize() + " Players"; + document.getElementById('deck-count').innerText = deckManager.getDeckSize() + ' Players'; if (deckManager.getDeckSize() === 0) { - let placeholder = document.createElement("div"); - placeholder.setAttribute("id", "deck-list-placeholder"); - placeholder.innerText = "Add a card from the available roles below."; - document.getElementById("deck-list").appendChild(placeholder); + const placeholder = document.createElement('div'); + placeholder.setAttribute('id', 'deck-list-placeholder'); + placeholder.innerText = 'Add a card from the available roles below.'; + document.getElementById('deck-list').appendChild(placeholder); } else { - if (document.getElementById("deck-list-placeholder")) { - document.getElementById("deck-list-placeholder").remove(); + if (document.getElementById('deck-list-placeholder')) { + document.getElementById('deck-list-placeholder').remove(); } - for (let card of deckManager.getCurrentDeck()) { + for (const card of deckManager.getCurrentDeck()) { if (card.quantity > 0) { - let roleEl = document.createElement("div"); + const roleEl = document.createElement('div'); roleEl.classList.add('deck-role'); if (card.team === globals.ALIGNMENT.GOOD) { roleEl.classList.add(globals.ALIGNMENT.GOOD); @@ -642,12 +635,12 @@ function updateDeckStatus(deckManager) { roleEl.classList.add(globals.ALIGNMENT.EVIL); } roleEl.innerText = card.quantity + 'x ' + card.role; - document.getElementById("deck-list").appendChild(roleEl); + document.getElementById('deck-list').appendChild(roleEl); } } } } -function hasTimer(hours, minutes) { +function hasTimer (hours, minutes) { return (!isNaN(hours) || !isNaN(minutes)); } diff --git a/client/src/modules/GameStateRenderer.js b/client/src/modules/GameStateRenderer.js index 1b91c39..29ac700 100644 --- a/client/src/modules/GameStateRenderer.js +++ b/client/src/modules/GameStateRenderer.js @@ -1,10 +1,10 @@ -import { globals } from "../config/globals.js"; -import { toast } from "./Toast.js"; -import {templates} from "./Templates.js"; -import {ModalManager} from "./ModalManager.js"; +import { globals } from '../config/globals.js'; +import { toast } from './Toast.js'; +import { templates } from './Templates.js'; +import { ModalManager } from './ModalManager.js'; export class GameStateRenderer { - constructor(stateBucket, socket) { + constructor (stateBucket, socket) { this.stateBucket = stateBucket; this.socket = socket; this.killPlayerHandlers = {}; @@ -12,38 +12,38 @@ export class GameStateRenderer { this.transferModHandlers = {}; this.startGameHandler = (e) => { e.preventDefault(); - if (confirm("Start the game and deal roles?")) { + if (confirm('Start the game and deal roles?')) { socket.emit(globals.COMMANDS.START_GAME, this.stateBucket.currentGameState.accessCode); } - } + }; } - renderLobbyPlayers() { - document.querySelectorAll('.lobby-player').forEach((el) => el.remove()) - let lobbyPlayersContainer = document.getElementById("lobby-players"); + renderLobbyPlayers () { + document.querySelectorAll('.lobby-player').forEach((el) => el.remove()); + const lobbyPlayersContainer = document.getElementById('lobby-players'); if (this.stateBucket.currentGameState.moderator.userType === globals.USER_TYPES.MODERATOR) { lobbyPlayersContainer.appendChild( renderLobbyPerson( this.stateBucket.currentGameState.moderator.name, this.stateBucket.currentGameState.moderator.userType ) - ) + ); } - for (let person of this.stateBucket.currentGameState.people) { - lobbyPlayersContainer.appendChild(renderLobbyPerson(person.name,person.userType)) + for (const person of this.stateBucket.currentGameState.people) { + lobbyPlayersContainer.appendChild(renderLobbyPerson(person.name, person.userType)); } - let playerCount = this.stateBucket.currentGameState.people.length; + const playerCount = this.stateBucket.currentGameState.people.length; document.querySelector("label[for='lobby-players']").innerText = - "Participants (" + playerCount + "/" + getGameSize(this.stateBucket.currentGameState.deck) + " Players)"; + 'Participants (' + playerCount + '/' + getGameSize(this.stateBucket.currentGameState.deck) + ' Players)'; } - renderLobbyHeader() { + renderLobbyHeader () { removeExistingTitle(); - let title = document.createElement("h1"); - title.innerText = "Lobby"; - document.getElementById("game-title").appendChild(title); - let gameLinkContainer = document.getElementById("game-link"); - let linkDiv = document.createElement("div"); + const title = document.createElement('h1'); + title.innerText = 'Lobby'; + document.getElementById('game-title').appendChild(title); + const gameLinkContainer = document.getElementById('game-link'); + const linkDiv = document.createElement('div'); linkDiv.innerText = window.location; gameLinkContainer.prepend(linkDiv); gameLinkContainer.addEventListener('click', () => { @@ -51,27 +51,27 @@ export class GameStateRenderer { toast('Link copied!', 'success', true); }); }); - let copyImg = document.createElement("img"); - copyImg.setAttribute("src", "../images/copy.svg"); + const copyImg = document.createElement('img'); + copyImg.setAttribute('src', '../images/copy.svg'); gameLinkContainer.appendChild(copyImg); - let time = document.getElementById("game-time"); - let playerCount = document.getElementById("game-player-count"); - playerCount.innerText = getGameSize(this.stateBucket.currentGameState.deck) + ' Players' + const time = document.getElementById('game-time'); + const playerCount = document.getElementById('game-player-count'); + playerCount.innerText = getGameSize(this.stateBucket.currentGameState.deck) + ' Players'; if (this.stateBucket.currentGameState.timerParams) { - let timeString = ""; - let hours = this.stateBucket.currentGameState.timerParams.hours; - let minutes = this.stateBucket.currentGameState.timerParams.minutes + let timeString = ''; + const hours = this.stateBucket.currentGameState.timerParams.hours; + const minutes = this.stateBucket.currentGameState.timerParams.minutes; if (hours) { timeString += hours > 1 ? hours + ' hours ' - : hours + ' hour ' + : hours + ' hour '; } if (minutes) { timeString += minutes > 1 ? minutes + ' minutes ' - : minutes + ' minute ' + : minutes + ' minute '; } time.innerText = timeString; } else { @@ -79,76 +79,75 @@ export class GameStateRenderer { } } - renderLobbyFooter() { - let gameDeckContainer = document.getElementById("game-deck"); - for (let card of this.stateBucket.currentGameState.deck) { - let cardEl = document.createElement("div"); + renderLobbyFooter () { + for (const card of this.stateBucket.currentGameState.deck) { + const cardEl = document.createElement('div'); cardEl.innerText = card.quantity + 'x ' + card.role; - cardEl.classList.add('lobby-card') + cardEl.classList.add('lobby-card'); } } - renderGameHeader() { + renderGameHeader () { removeExistingTitle(); // let title = document.createElement("h1"); // title.innerText = "Game"; // document.getElementById("game-title").appendChild(title); } - renderModeratorView() { + renderModeratorView () { createEndGamePromptComponent(this.socket, this.stateBucket); - let modTransferButton = document.getElementById("mod-transfer-button"); + const modTransferButton = document.getElementById('mod-transfer-button'); modTransferButton.addEventListener( - "click", () => { + 'click', () => { this.displayAvailableModerators(); ModalManager.displayModal( - "transfer-mod-modal", - "transfer-mod-modal-background", - "close-mod-transfer-modal-button" - ) + 'transfer-mod-modal', + 'transfer-mod-modal-background', + 'close-mod-transfer-modal-button' + ); } - ) + ); this.renderPlayersWithRoleAndAlignmentInfo(); } - renderTempModView() { - createEndGamePromptComponent(this.socket, this.stateBucket) + renderTempModView () { + createEndGamePromptComponent(this.socket, this.stateBucket); renderPlayerRole(this.stateBucket.currentGameState); this.renderPlayersWithNoRoleInformationUnlessRevealed(true); } - renderPlayerView(isKilled=false) { + renderPlayerView (isKilled = false) { if (isKilled) { - let clientUserType = document.getElementById("client-user-type"); + const clientUserType = document.getElementById('client-user-type'); if (clientUserType) { - clientUserType.innerText = globals.USER_TYPES.KILLED_PLAYER + ' \uD83D\uDC80' + clientUserType.innerText = globals.USER_TYPES.KILLED_PLAYER + ' \uD83D\uDC80'; } } renderPlayerRole(this.stateBucket.currentGameState); this.renderPlayersWithNoRoleInformationUnlessRevealed(false); } - renderSpectatorView() { + renderSpectatorView () { this.renderPlayersWithNoRoleInformationUnlessRevealed(); } - refreshPlayerList(isModerator) { + refreshPlayerList (isModerator) { if (isModerator) { - this.renderPlayersWithRoleAndAlignmentInfo() + this.renderPlayersWithRoleAndAlignmentInfo(); } else { this.renderPlayersWithNoRoleInformationUnlessRevealed(); } } - renderPlayersWithRoleAndAlignmentInfo() { + renderPlayersWithRoleAndAlignmentInfo () { removeExistingPlayerElements(this.killPlayerHandlers, this.revealRoleHandlers); this.stateBucket.currentGameState.people.sort((a, b) => { return a.name >= b.name ? 1 : -1; }); - let teamGood = this.stateBucket.currentGameState.people.filter((person) => person.alignment === globals.ALIGNMENT.GOOD); - let teamEvil = this.stateBucket.currentGameState.people.filter((person) => person.alignment === globals.ALIGNMENT.EVIL); + const teamGood = this.stateBucket.currentGameState.people.filter((person) => person.alignment === globals.ALIGNMENT.GOOD); + const teamEvil = this.stateBucket.currentGameState.people.filter((person) => person.alignment === globals.ALIGNMENT.EVIL); renderGroupOfPlayers( teamEvil, this.killPlayerHandlers, @@ -167,16 +166,15 @@ export class GameStateRenderer { this.stateBucket.currentGameState.moderator.userType, this.socket ); - document.getElementById("players-alive-label").innerText = - 'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' - + this.stateBucket.currentGameState.people.length + ' Alive'; - + document.getElementById('players-alive-label').innerText = + 'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' + + this.stateBucket.currentGameState.people.length + ' Alive'; } - renderPlayersWithNoRoleInformationUnlessRevealed(tempMod = false) { + renderPlayersWithNoRoleInformationUnlessRevealed (tempMod = false) { if (tempMod) { document.querySelectorAll('.game-player').forEach((el) => { - let pointer = el.dataset.pointer; + const pointer = el.dataset.pointer; if (pointer && this.killPlayerHandlers[pointer]) { el.removeEventListener('click', this.killPlayerHandlers[pointer]); delete this.killPlayerHandlers[pointer]; @@ -190,7 +188,7 @@ export class GameStateRenderer { } document.querySelectorAll('.game-player').forEach((el) => el.remove()); sortPeopleByStatus(this.stateBucket.currentGameState.people); - let modType = tempMod ? this.stateBucket.currentGameState.moderator.userType : null; + const modType = tempMod ? this.stateBucket.currentGameState.moderator.userType : null; renderGroupOfPlayers( this.stateBucket.currentGameState.people, this.killPlayerHandlers, @@ -200,24 +198,23 @@ export class GameStateRenderer { modType, this.socket ); - document.getElementById("players-alive-label").innerText = - 'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' - + this.stateBucket.currentGameState.people.length + ' Alive'; - + document.getElementById('players-alive-label').innerText = + 'Players: ' + this.stateBucket.currentGameState.people.filter((person) => !person.out).length + ' / ' + + this.stateBucket.currentGameState.people.length + ' Alive'; } - updatePlayerCardToKilledState() { - document.querySelector('#role-image').classList.add("killed-card"); - document.getElementById("role-image").setAttribute( + updatePlayerCardToKilledState () { + document.querySelector('#role-image').classList.add('killed-card'); + document.getElementById('role-image').setAttribute( 'src', '../images/tombstone.png' ); } - displayAvailableModerators() { - document.getElementById("transfer-mod-modal-content").innerText = ""; + displayAvailableModerators () { + document.getElementById('transfer-mod-modal-content').innerText = ''; document.querySelectorAll('.potential-moderator').forEach((el) => { - let pointer = el.dataset.pointer; + const pointer = el.dataset.pointer; if (pointer && this.transferModHandlers[pointer]) { el.removeEventListener('click', this.transferModHandlers[pointer]); delete this.transferModHandlers[pointer]; @@ -238,28 +235,28 @@ export class GameStateRenderer { ); if (document.querySelectorAll('.potential-moderator').length === 0) { - document.getElementById("transfer-mod-modal-content").innerText = "There is nobody available to transfer to." + document.getElementById('transfer-mod-modal-content').innerText = 'There is nobody available to transfer to.'; } } - renderEndOfGame() { + renderEndOfGame () { this.renderPlayersWithNoRoleInformationUnlessRevealed(); } } -function renderPotentialMods(gameState, group, transferModHandlers, socket) { - let modalContent = document.getElementById("transfer-mod-modal-content"); - for (let member of group) { +function renderPotentialMods (gameState, group, transferModHandlers, socket) { + const modalContent = document.getElementById('transfer-mod-modal-content'); + for (const member of group) { if ((member.out || member.userType === globals.USER_TYPES.SPECTATOR) && !(member.id === gameState.client.id)) { - let container = document.createElement("div"); + const container = document.createElement('div'); container.classList.add('potential-moderator'); container.dataset.pointer = member.id; container.innerText = member.name; transferModHandlers[member.id] = () => { - if (confirm("Transfer moderator powers to " + member.name + "?")) { + if (confirm('Transfer moderator powers to ' + member.name + '?')) { socket.emit(globals.COMMANDS.TRANSFER_MODERATOR, gameState.accessCode, member.id); } - } + }; container.addEventListener('click', transferModHandlers[member.id]); modalContent.appendChild(container); @@ -267,10 +264,10 @@ function renderPotentialMods(gameState, group, transferModHandlers, socket) { } } -function renderLobbyPerson(name, userType) { - let el = document.createElement("div"); - let personNameEl = document.createElement("div"); - let personTypeEl = document.createElement("div"); +function renderLobbyPerson (name, userType) { + const el = document.createElement('div'); + const personNameEl = document.createElement('div'); + const personTypeEl = document.createElement('div'); personNameEl.innerText = name; personTypeEl.innerText = userType + globals.USER_TYPE_ICONS[userType]; el.classList.add('lobby-player'); @@ -281,47 +278,47 @@ function renderLobbyPerson(name, userType) { return el; } -function sortPeopleByStatus(people) { +function sortPeopleByStatus (people) { people.sort((a, b) => { if (a.out !== b.out) { return a.out ? 1 : -1; } else { if (a.revealed !== b.revealed) { - return a.revealed? -1 : 1; + return a.revealed ? -1 : 1; } return a.name >= b.name ? 1 : -1; } }); } -function getGameSize(cards) { +function getGameSize (cards) { let quantity = 0; - for (let card of cards) { + for (const card of cards) { quantity += card.quantity; } return quantity; } -function removeExistingTitle() { - let existingTitle = document.querySelector('#game-title h1'); +function removeExistingTitle () { + const existingTitle = document.querySelector('#game-title h1'); if (existingTitle) { existingTitle.remove(); } } // TODO: refactor to reduce the cyclomatic complexity of this function -function renderGroupOfPlayers( +function renderGroupOfPlayers ( people, killPlayerHandlers, revealRoleHandlers, - accessCode=null, - alignment=null, + accessCode = null, + alignment = null, moderatorType, - socket=null + socket = null ) { - for (let player of people) { - let container = document.createElement("div"); + for (const player of people) { + const container = document.createElement('div'); container.classList.add('game-player'); if (moderatorType) { container.dataset.pointer = player.id; @@ -330,44 +327,44 @@ function renderGroupOfPlayers( container.innerHTML = templates.GAME_PLAYER; } container.querySelector('.game-player-name').innerText = player.name; - let roleElement = container.querySelector('.game-player-role') + const roleElement = container.querySelector('.game-player-role'); if (moderatorType) { roleElement.classList.add(alignment); if (moderatorType === globals.USER_TYPES.MODERATOR) { roleElement.innerText = player.gameRole; - document.getElementById("player-list-moderator-team-" + alignment).appendChild(container); + document.getElementById('player-list-moderator-team-' + alignment).appendChild(container); } else { if (player.revealed) { roleElement.innerText = player.gameRole; roleElement.classList.add(player.alignment); } else { - roleElement.innerText = "Unknown"; + roleElement.innerText = 'Unknown'; } - document.getElementById("game-player-list").appendChild(container); + document.getElementById('game-player-list').appendChild(container); } } else if (player.revealed) { roleElement.classList.add(player.alignment); roleElement.innerText = player.gameRole; - document.getElementById("game-player-list").appendChild(container); + document.getElementById('game-player-list').appendChild(container); } else { - roleElement.innerText = "Unknown"; - document.getElementById("game-player-list").appendChild(container); + roleElement.innerText = 'Unknown'; + document.getElementById('game-player-list').appendChild(container); } if (player.out) { container.classList.add('killed'); if (moderatorType) { container.querySelector('.kill-player-button')?.remove(); - insertPlaceholderButton(container, false, "killed"); + insertPlaceholderButton(container, false, 'killed'); } } else { if (moderatorType) { killPlayerHandlers[player.id] = () => { - if (confirm("KILL " + player.name + "?")) { + if (confirm('KILL ' + player.name + '?')) { socket.emit(globals.COMMANDS.KILL_PLAYER, accessCode, player.id); } - } + }; container.querySelector('.kill-player-button').addEventListener('click', killPlayerHandlers[player.id]); } } @@ -375,52 +372,52 @@ function renderGroupOfPlayers( if (player.revealed) { if (moderatorType) { container.querySelector('.reveal-role-button')?.remove(); - insertPlaceholderButton(container, true, "revealed"); + insertPlaceholderButton(container, true, 'revealed'); } } else { if (moderatorType) { revealRoleHandlers[player.id] = () => { - if (confirm("REVEAL " + player.name + "?")) { + if (confirm('REVEAL ' + player.name + '?')) { socket.emit(globals.COMMANDS.REVEAL_PLAYER, accessCode, player.id); } - } + }; container.querySelector('.reveal-role-button').addEventListener('click', revealRoleHandlers[player.id]); } } } } -function renderPlayerRole(gameState) { - let name = document.querySelector('#role-name'); +function renderPlayerRole (gameState) { + const name = document.querySelector('#role-name'); name.innerText = gameState.client.gameRole; if (gameState.client.alignment === globals.ALIGNMENT.GOOD) { - document.getElementById("game-role").classList.add('game-role-good'); + document.getElementById('game-role').classList.add('game-role-good'); name.classList.add('good'); } else { - document.getElementById("game-role").classList.add('game-role-evil'); + document.getElementById('game-role').classList.add('game-role-evil'); name.classList.add('evil'); } - name.setAttribute("title", gameState.client.gameRole); + name.setAttribute('title', gameState.client.gameRole); if (gameState.client.out) { - document.querySelector('#role-image').classList.add("killed-card"); - document.getElementById("role-image").setAttribute( + document.querySelector('#role-image').classList.add('killed-card'); + document.getElementById('role-image').setAttribute( 'src', '../images/tombstone.png' ); } else { if (gameState.client.gameRole.toLowerCase() === 'villager') { - document.getElementById("role-image").setAttribute( + document.getElementById('role-image').setAttribute( 'src', '../images/roles/Villager' + Math.ceil(Math.random() * 2) + '.png' ); } else { if (gameState.client.customRole) { - document.getElementById("role-image").setAttribute( + document.getElementById('role-image').setAttribute( 'src', '../images/roles/custom-role.svg' ); } else { - document.getElementById("role-image").setAttribute( + document.getElementById('role-image').setAttribute( 'src', '../images/roles/' + gameState.client.gameRole.replaceAll(' ', '') + '.png' ); @@ -430,24 +427,24 @@ function renderPlayerRole(gameState) { document.querySelector('#role-description').innerText = gameState.client.gameRoleDescription; - document.getElementById("game-role-back").addEventListener('click', () => { - document.getElementById("game-role").style.display = 'flex'; - document.getElementById("game-role-back").style.display = 'none'; + document.getElementById('game-role-back').addEventListener('click', () => { + document.getElementById('game-role').style.display = 'flex'; + document.getElementById('game-role-back').style.display = 'none'; }); - document.getElementById("game-role").addEventListener('click', () => { - document.getElementById("game-role-back").style.display = 'flex'; - document.getElementById("game-role").style.display = 'none'; + document.getElementById('game-role').addEventListener('click', () => { + document.getElementById('game-role-back').style.display = 'flex'; + document.getElementById('game-role').style.display = 'none'; }); } -function insertPlaceholderButton(container, append, type) { - let button = document.createElement("div"); +function insertPlaceholderButton (container, append, type) { + const button = document.createElement('div'); button.classList.add('placeholder-button'); - if (type === "killed") { + if (type === 'killed') { button.innerText = 'Killed'; } else { - button.innerText = "Revealed"; + button.innerText = 'Revealed'; } if (append) { container.querySelector('.player-action-buttons').appendChild(button); @@ -456,9 +453,9 @@ function insertPlaceholderButton(container, append, type) { } } -function removeExistingPlayerElements(killPlayerHandlers, revealRoleHandlers) { +function removeExistingPlayerElements (killPlayerHandlers, revealRoleHandlers) { document.querySelectorAll('.game-player').forEach((el) => { - let pointer = el.dataset.pointer; + const pointer = el.dataset.pointer; if (pointer && killPlayerHandlers[pointer]) { el.removeEventListener('click', killPlayerHandlers[pointer]); delete killPlayerHandlers[pointer]; @@ -471,19 +468,19 @@ function removeExistingPlayerElements(killPlayerHandlers, revealRoleHandlers) { }); } -function createEndGamePromptComponent(socket, stateBucket) { - if (document.querySelector("#end-game-prompt") === null) { - let div = document.createElement("div"); +function createEndGamePromptComponent (socket, stateBucket) { + if (document.querySelector('#end-game-prompt') === null) { + const div = document.createElement('div'); div.innerHTML = templates.END_GAME_PROMPT; - div.querySelector("#end-game-button").addEventListener('click', (e) => { + div.querySelector('#end-game-button').addEventListener('click', (e) => { e.preventDefault(); - if (confirm("End the game?")) { + if (confirm('End the game?')) { socket.emit( globals.COMMANDS.END_GAME, stateBucket.currentGameState.accessCode ); } }); - document.getElementById("game-content").appendChild(div); + document.getElementById('game-content').appendChild(div); } } diff --git a/client/src/modules/GameTimerManager.js b/client/src/modules/GameTimerManager.js index 4fe03f9..2e977a6 100644 --- a/client/src/modules/GameTimerManager.js +++ b/client/src/modules/GameTimerManager.js @@ -1,17 +1,17 @@ -import {globals} from "../config/globals.js"; +import { globals } from '../config/globals.js'; export class GameTimerManager { - constructor(stateBucket, socket) { + constructor (stateBucket, socket) { this.stateBucket = stateBucket; this.playListener = () => { socket.emit(globals.COMMANDS.RESUME_TIMER, this.stateBucket.currentGameState.accessCode); - } + }; this.pauseListener = () => { socket.emit(globals.COMMANDS.PAUSE_TIMER, this.stateBucket.currentGameState.accessCode); - } + }; } - resumeGameTimer(totalTime, tickRate, soundManager, timerWorker) { + resumeGameTimer (totalTime, tickRate, soundManager, timerWorker) { if (window.Worker) { if ( this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR @@ -19,8 +19,8 @@ export class GameTimerManager { ) { this.swapToPauseButton(); } - let instance = this; - let timer = document.getElementById('game-timer'); + const instance = this; + const timer = document.getElementById('game-timer'); timer.classList.remove('paused'); timer.classList.remove('paused-low'); timer.classList.remove('low'); @@ -46,7 +46,7 @@ export class GameTimerManager { } } - pauseGameTimer(timerWorker, timeRemaining) { + pauseGameTimer (timerWorker, timeRemaining) { if (window.Worker) { if ( this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR @@ -56,7 +56,7 @@ export class GameTimerManager { } timerWorker.postMessage('stop'); - let timer = document.getElementById('game-timer'); + const timer = document.getElementById('game-timer'); if (timeRemaining < 60000) { timer.innerText = returnHumanReadableTime(timeRemaining, true); timer.classList.add('paused-low'); @@ -68,7 +68,7 @@ export class GameTimerManager { } } - displayPausedTime(time) { + displayPausedTime (time) { if ( this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR || this.stateBucket.currentGameState.client.userType === globals.USER_TYPES.TEMPORARY_MODERATOR @@ -76,7 +76,7 @@ export class GameTimerManager { this.swapToPlayButton(); } - let timer = document.getElementById('game-timer'); + const timer = document.getElementById('game-timer'); if (time < 60000) { timer.innerText = returnHumanReadableTime(time, true); timer.classList.add('paused-low'); @@ -87,71 +87,71 @@ export class GameTimerManager { } } - displayExpiredTime() { - let currentBtn = document.querySelector('#play-pause img'); + displayExpiredTime () { + const currentBtn = document.querySelector('#play-pause img'); if (currentBtn) { currentBtn.removeEventListener('click', this.pauseListener); currentBtn.removeEventListener('click', this.playListener); currentBtn.remove(); } - let timer = document.getElementById('game-timer'); + const timer = document.getElementById('game-timer'); timer.innerText = returnHumanReadableTime(0, true); } - attachTimerSocketListeners(socket, timerWorker, gameStateRenderer) { - if(!socket.hasListeners(globals.COMMANDS.PAUSE_TIMER)) { + attachTimerSocketListeners (socket, timerWorker, gameStateRenderer) { + if (!socket.hasListeners(globals.COMMANDS.PAUSE_TIMER)) { socket.on(globals.COMMANDS.PAUSE_TIMER, (timeRemaining) => { - this.pauseGameTimer(timerWorker, timeRemaining) + this.pauseGameTimer(timerWorker, timeRemaining); }); } - if(!socket.hasListeners(globals.COMMANDS.RESUME_TIMER)) { + if (!socket.hasListeners(globals.COMMANDS.RESUME_TIMER)) { socket.on(globals.COMMANDS.RESUME_TIMER, (timeRemaining) => { this.resumeGameTimer(timeRemaining, globals.CLOCK_TICK_INTERVAL_MILLIS, null, timerWorker); }); } - if(!socket.hasListeners(globals.COMMANDS.GET_TIME_REMAINING)) { + if (!socket.hasListeners(globals.COMMANDS.GET_TIME_REMAINING)) { socket.on(globals.COMMANDS.GET_TIME_REMAINING, (timeRemaining, paused) => { if (paused) { this.displayPausedTime(timeRemaining); } else if (timeRemaining === 0) { this.displayExpiredTime(); } else { - this.resumeGameTimer(timeRemaining, globals.CLOCK_TICK_INTERVAL_MILLIS, null, timerWorker); + this.resumeGameTimer(timeRemaining, globals.CLOCK_TICK_INTERVAL_MILLIS, null, timerWorker); } }); } } - swapToPlayButton() { - let currentBtn = document.querySelector('#play-pause img'); + swapToPlayButton () { + const currentBtn = document.querySelector('#play-pause img'); if (currentBtn) { currentBtn.removeEventListener('click', this.pauseListener); currentBtn.remove(); } - let playBtn = document.createElement('img'); + const playBtn = document.createElement('img'); playBtn.setAttribute('src', '../images/play-button.svg'); playBtn.addEventListener('click', this.playListener); document.getElementById('play-pause').appendChild(playBtn); } - swapToPauseButton() { - let currentBtn = document.querySelector('#play-pause img'); + swapToPauseButton () { + const currentBtn = document.querySelector('#play-pause img'); if (currentBtn) { currentBtn.removeEventListener('click', this.playListener); currentBtn.remove(); } - let pauseBtn = document.createElement('img'); + const pauseBtn = document.createElement('img'); pauseBtn.setAttribute('src', '../images/pause-button.svg'); pauseBtn.addEventListener('click', this.pauseListener); document.getElementById('play-pause').appendChild(pauseBtn); } - processTimeRemaining(timeRemaining, paused, timerWorker) { + processTimeRemaining (timeRemaining, paused, timerWorker) { if (paused) { this.displayPausedTime(timeRemaining); } else if (timeRemaining === 0) { @@ -162,18 +162,17 @@ export class GameTimerManager { } } -function returnHumanReadableTime(milliseconds, tenthsOfSeconds=false) { - - let tenths = Math.floor((milliseconds / 100) % 10); +function returnHumanReadableTime (milliseconds, tenthsOfSeconds = false) { + const tenths = Math.floor((milliseconds / 100) % 10); let seconds = Math.floor((milliseconds / 1000) % 60); let minutes = Math.floor((milliseconds / (1000 * 60)) % 60); let hours = Math.floor((milliseconds / (1000 * 60 * 60)) % 24); - hours = hours < 10 ? "0" + hours : hours; - minutes = minutes < 10 ? "0" + minutes : minutes; - seconds = seconds < 10 ? "0" + seconds : seconds; + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + seconds = seconds < 10 ? '0' + seconds : seconds; return tenthsOfSeconds - ? hours + ":" + minutes + ":" + seconds + '.' + tenths - : hours + ":" + minutes + ":" + seconds; + ? hours + ':' + minutes + ':' + seconds + '.' + tenths + : hours + ':' + minutes + ':' + seconds; } diff --git a/client/src/modules/ModalManager.js b/client/src/modules/ModalManager.js index e5e4d19..75a4457 100644 --- a/client/src/modules/ModalManager.js +++ b/client/src/modules/ModalManager.js @@ -1,9 +1,9 @@ export const ModalManager = { displayModal: displayModal, dispelModal: dispelModal -} +}; -function displayModal(modalId, backgroundId, closeButtonId) { +function displayModal (modalId, backgroundId, closeButtonId) { const modal = document.getElementById(modalId); const modalOverlay = document.getElementById(backgroundId); const closeBtn = document.getElementById(closeButtonId); @@ -11,19 +11,19 @@ function displayModal(modalId, backgroundId, closeButtonId) { if (modal && modalOverlay && closeBtn) { modal.style.display = 'flex'; modalOverlay.style.display = 'flex'; - modalOverlay.removeEventListener("click", closeModalHandler); - modalOverlay.addEventListener("click", closeModalHandler = function(e) { + modalOverlay.removeEventListener('click', closeModalHandler); + modalOverlay.addEventListener('click', closeModalHandler = function (e) { e.preventDefault(); dispelModal(modalId, backgroundId); }); - closeBtn.removeEventListener("click", closeModalHandler); - closeBtn.addEventListener("click", closeModalHandler); + closeBtn.removeEventListener('click', closeModalHandler); + closeBtn.addEventListener('click', closeModalHandler); } else { - throw new Error("One or more of the ids supplied to ModalManager.displayModal is invalid."); + throw new Error('One or more of the ids supplied to ModalManager.displayModal is invalid.'); } } -function dispelModal(modalId, backgroundId) { +function dispelModal (modalId, backgroundId) { const modal = document.getElementById(modalId); const modalOverlay = document.getElementById(backgroundId); if (modal && modalOverlay) { diff --git a/client/src/modules/Navbar.js b/client/src/modules/Navbar.js index c22411a..642b61a 100644 --- a/client/src/modules/Navbar.js +++ b/client/src/modules/Navbar.js @@ -1,23 +1,23 @@ -export const injectNavbar = (page=null) => { +export const injectNavbar = (page = null) => { if (document.getElementById('navbar') !== null) { document.getElementById('navbar').innerHTML = - "' - + '' - + '' - + '
' - + '' - + '
' - + ''; + "' + + '' + + '' + + '
' + + '' + + '
' + + ''; } attachHamburgerListener(); }; @@ -35,7 +35,7 @@ function flipHamburger () { } } -function getNavbarLinks (page=null, device) { +function getNavbarLinks (page = null, device) { const linkClass = device === 'mobile' ? 'mobile-link' : 'desktop-link'; return 'Create' + 'How to Use' + 'Contact' + - 'Support the App' + 'Support the App'; } function attachHamburgerListener () { diff --git a/client/src/modules/StateBucket.js b/client/src/modules/StateBucket.js index 7571fc2..af46c84 100644 --- a/client/src/modules/StateBucket.js +++ b/client/src/modules/StateBucket.js @@ -5,4 +5,4 @@ export const stateBucket = { currentGameState: null, timerWorker: null -} +}; diff --git a/client/src/modules/Templates.js b/client/src/modules/Templates.js index 4fe03b8..6d23494 100644 --- a/client/src/modules/Templates.js +++ b/client/src/modules/Templates.js @@ -1,165 +1,165 @@ export const templates = { LOBBY: "
" + - "
" + + '
' + "" + "" + - "
" + + '
' + "
" + - "
" + + '
' + "clock" + "
" + - "
" + - "
" + + '
' + + '
' + "person" + "
" + - "
" + - "
" + - "
" + + '
' + + '
' + + '
' + "
" + - "
" + - "
" + + '
' + + '' + + '
' + "
" + "" + "
" + - "
" + + '
' + "" + - "", + '' + + '', START_GAME_PROMPT: "
" + "" + - "
", + '', END_GAME_PROMPT: "
" + "" + - "
", + '', PLAYER_GAME_VIEW: "
" + - "
" + + '
' + "" + "
" + - "
" + - "
" + + '
' + + '
' + "
" + - "
" + + '
' + + '' + "" + + '' + "
" + - "

Click to show your role

" + - "

(click again to hide)

" + - "
" + + '

Click to show your role

' + + '

(click again to hide)

' + + '' + "
" + "" + "
" + - "
", + '', SPECTATOR_GAME_VIEW: "
" + - "
" + + '
' + "" + "
" + - "
" + - "
" + + '
' + + '
' + "
" + - "
" + + '
' + + '' + "
" + "" + "
" + - "
", + '', MODERATOR_GAME_VIEW: "" + "" + + '' + + '' + "
" + "
" + - "
" + + '
' + "" + "
" + - "
" + - "
" + "
" + - "
" + + '
' + + "
" + '
' + + '
' + "" + - "
" + + '
' + "
" + - "
" + - "
" + + '
' + + '' + + '
' + "" + "
" + "
" + "" + "
" + - "
" + + '
' + "
" + "" + "
" + - "
" + - "
" + - "", + '' + + '' + + '', TEMP_MOD_GAME_VIEW: "" + "' + "" + - "" + - "" + + '' + + '' + + '' + "
" + "
" + - "
" + + '
' + "" + "
" + - "
" + - "
" + "
" + - "
" + - "
" + + '
' + + "
" + '
' + + '
' + + '
' + "
" + - "
" + + '' + + '' + "" + + '' + "
" + - "

Click to show your role

" + - "

(click again to hide)

" + - "
" + + '

Click to show your role

' + + '

(click again to hide)

' + + '' + "
" + "" + "
" + - "
" + - "", + '' + + '', MODERATOR_PLAYER: - "
" + + '
' + "
" + "
" + - "
" + + '
' + "
" + "" + "" + - "
", + '', GAME_PLAYER: - "
" + + '
' + "
" + "
" + - "
", + '
', INITIAL_GAME_DOM: "
" + "
" + @@ -167,25 +167,25 @@ export const templates = { "
" + "
" + "
" + - "
" + - "
" + + '' + + '' + "
", // via https://loading.io/css/ SPINNER: - "
" + - "
" + - "
" + - "
" + - "
" + - "
" + - "
" + - "
" + - "
" + - "
" + - "
" + - "
" + - "
" + - "
", + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
', NAME_CHANGE_MODAL: "" + "' + "" + - "" + - "", + '' + + '' + + '', ROLE_INFO_MODAL: "" + "", + '' + + '', END_OF_GAME_VIEW: - "

The moderator has ended the game. Roles are revealed.

" + + '

The moderator has ended the game. Roles are revealed.

' + "
" + - "
" + + '
' + "
" + - "
" + + '
' + + '
' + "" + "" + - "" + - "
" + - "
" + + '' + + '
' + + '' + "
" + "" + "
" + - "
", + '', CREATE_GAME_DECK: "
" + - "
" + + '
' + "" + "
" + - "
" + - "
" + + '
' + + '
' + "" + "
" + - "
" + - "
", + '
' + + '', CREATE_GAME_CUSTOM_ROLES: - '
' + + '
' + '
' + - '' + - '
' + - '' + + '' + + '
' + + '' + '
', CREATE_GAME_DECK_STATUS: '
' + @@ -263,4 +263,4 @@ export const templates = { 'edit' + 'remove' + '
' -} +}; diff --git a/client/src/modules/Timer.js b/client/src/modules/Timer.js index abc81cf..ff0c180 100644 --- a/client/src/modules/Timer.js +++ b/client/src/modules/Timer.js @@ -38,7 +38,7 @@ function stepFn (expected, interval, start, totalTime) { } const delta = now - expected; expected += interval; - let displayTime = (totalTime - (now - start)) < 60000 + const displayTime = (totalTime - (now - start)) < 60000 ? returnHumanReadableTime(totalTime - (now - start), true) : returnHumanReadableTime(totalTime - (now - start)); postMessage({ @@ -46,8 +46,8 @@ function stepFn (expected, interval, start, totalTime) { displayTime: displayTime }); Singleton.setNewTimeoutReference(setTimeout(() => { - stepFn(expected, interval, start, totalTime); - }, Math.max(0, interval - delta) + stepFn(expected, interval, start, totalTime); + }, Math.max(0, interval - delta) )); // take into account drift - also retain a reference to this clock tick so it can be cleared later } @@ -73,7 +73,7 @@ class Timer { } } - stopTimer() { + stopTimer () { if (this.timeoutId) { clearTimeout(this.timeoutId); } @@ -105,18 +105,17 @@ class Singleton { } } -function returnHumanReadableTime(milliseconds, tenthsOfSeconds=false) { - - let tenths = Math.floor((milliseconds / 100) % 10); +function returnHumanReadableTime (milliseconds, tenthsOfSeconds = false) { + const tenths = Math.floor((milliseconds / 100) % 10); let seconds = Math.floor((milliseconds / 1000) % 60); let minutes = Math.floor((milliseconds / (1000 * 60)) % 60); let hours = Math.floor((milliseconds / (1000 * 60 * 60)) % 24); - hours = hours < 10 ? "0" + hours : hours; - minutes = minutes < 10 ? "0" + minutes : minutes; - seconds = seconds < 10 ? "0" + seconds : seconds; + hours = hours < 10 ? '0' + hours : hours; + minutes = minutes < 10 ? '0' + minutes : minutes; + seconds = seconds < 10 ? '0' + seconds : seconds; return tenthsOfSeconds - ? hours + ":" + minutes + ":" + seconds + '.' + tenths - : hours + ":" + minutes + ":" + seconds; + ? hours + ':' + minutes + ':' + seconds + '.' + tenths + : hours + ':' + minutes + ':' + seconds; } diff --git a/client/src/modules/Toast.js b/client/src/modules/Toast.js index 8c83b17..0302da8 100644 --- a/client/src/modules/Toast.js +++ b/client/src/modules/Toast.js @@ -1,6 +1,6 @@ -import {globals} from "../config/globals.js"; +import { globals } from '../config/globals.js'; -export const toast = (message, type, positionAtTop = true, dispelAutomatically=true, duration=null) => { +export const toast = (message, type, positionAtTop = true, dispelAutomatically = true, duration = null) => { if (message && type) { buildAndInsertMessageElement(message, type, positionAtTop, dispelAutomatically, duration); } @@ -21,21 +21,21 @@ function buildAndInsertMessageElement (message, type, positionAtTop, dispelAutom break; case 'success': backgroundColor = '#bef5cb'; - border = '3px solid #8ac78a;' + border = '3px solid #8ac78a;'; break; } - let durationInSeconds = duration ? duration + 's' : globals.TOAST_DURATION_DEFAULT + 's'; + const durationInSeconds = duration ? duration + 's' : globals.TOAST_DURATION_DEFAULT + 's'; let animation = ''; if (dispelAutomatically) { animation = 'animation:fade-in-slide-down-then-exit ' + durationInSeconds + ' ease normal forwards'; } else { animation = 'animation:fade-in-slide-down ' + durationInSeconds + ' ease normal forwards'; } - const messageEl = document.createElement("div"); - messageEl.setAttribute("id", "current-info-message"); - messageEl.setAttribute("style", 'background-color:' + backgroundColor + ';' + 'border:' + border + ';' + position + animation); - messageEl.setAttribute("class", 'info-message'); + const messageEl = document.createElement('div'); + messageEl.setAttribute('id', 'current-info-message'); + messageEl.setAttribute('style', 'background-color:' + backgroundColor + ';' + 'border:' + border + ';' + position + animation); + messageEl.setAttribute('class', 'info-message'); messageEl.innerText = message; document.body.prepend(messageEl); } diff --git a/client/src/modules/XHRUtility.js b/client/src/modules/XHRUtility.js index 758d5e5..0607047 100644 --- a/client/src/modules/XHRUtility.js +++ b/client/src/modules/XHRUtility.js @@ -34,7 +34,6 @@ export const XHRUtility = }; body ? req.send(body) : req.send(); }); - }, - + } }; diff --git a/client/src/scripts/create.js b/client/src/scripts/create.js index 5ddf3db..241bb49 100644 --- a/client/src/scripts/create.js +++ b/client/src/scripts/create.js @@ -1,13 +1,13 @@ -import { DeckStateManager } from "../modules/DeckStateManager.js"; -import { GameCreationStepManager } from "../modules/GameCreationStepManager.js"; -import { injectNavbar } from "../modules/Navbar.js"; +import { DeckStateManager } from '../modules/DeckStateManager.js'; +import { GameCreationStepManager } from '../modules/GameCreationStepManager.js'; +import { injectNavbar } from '../modules/Navbar.js'; const create = () => { injectNavbar(); - let deckManager = new DeckStateManager(); - let gameCreationStepManager = new GameCreationStepManager(deckManager); - gameCreationStepManager.renderStep("creation-step-container", 1); -} + const deckManager = new DeckStateManager(); + const gameCreationStepManager = new GameCreationStepManager(deckManager); + gameCreationStepManager.renderStep('creation-step-container', 1); +}; if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { module.exports = create; diff --git a/client/src/scripts/game.js b/client/src/scripts/game.js index b27a201..0b3edaf 100644 --- a/client/src/scripts/game.js +++ b/client/src/scripts/game.js @@ -1,13 +1,13 @@ -import { UserUtility } from "../modules/UserUtility.js"; -import { globals } from "../config/globals.js"; -import {templates} from "../modules/Templates.js"; -import {GameStateRenderer} from "../modules/GameStateRenderer.js"; -import {cancelCurrentToast, toast} from "../modules/Toast.js"; -import {GameTimerManager} from "../modules/GameTimerManager.js"; -import {ModalManager} from "../modules/ModalManager.js"; -import {stateBucket} from "../modules/StateBucket.js"; +import { UserUtility } from '../modules/UserUtility.js'; +import { globals } from '../config/globals.js'; +import { templates } from '../modules/Templates.js'; +import { GameStateRenderer } from '../modules/GameStateRenderer.js'; +import { toast } from '../modules/Toast.js'; +import { GameTimerManager } from '../modules/GameTimerManager.js'; +import { ModalManager } from '../modules/ModalManager.js'; +import { stateBucket } from '../modules/StateBucket.js'; import { io } from 'socket.io-client'; -import { injectNavbar } from "../modules/Navbar.js"; +import { injectNavbar } from '../modules/Navbar.js'; const game = () => { injectNavbar(); @@ -25,10 +25,10 @@ const game = () => { timerWorker = new Worker(new URL('../modules/Timer.js', import.meta.url)); prepareGamePage(returnedEnvironment, socket, timerWorker); }); - }) + }); }; -function prepareGamePage(environment, socket, timerWorker) { +function prepareGamePage (environment, socket, timerWorker) { let userId = UserUtility.validateAnonUserSignature(environment); const splitUrl = window.location.href.split('/game/'); const accessCode = splitUrl[1]; @@ -41,11 +41,11 @@ function prepareGamePage(environment, socket, timerWorker) { if (gameState === null) { window.location = '/not-found?reason=' + encodeURIComponent('game-not-found'); } else { - document.getElementById("game-content").innerHTML = templates.INITIAL_GAME_DOM; + document.getElementById('game-content').innerHTML = templates.INITIAL_GAME_DOM; toast('You are connected.', 'success', true, true, 2); userId = gameState.client.cookie; UserUtility.setAnonymousUserId(userId, environment); - let gameStateRenderer = new GameStateRenderer(stateBucket, socket); + const gameStateRenderer = new GameStateRenderer(stateBucket, socket); let gameTimerManager; if (stateBucket.currentGameState.timerParams) { gameTimerManager = new GameTimerManager(stateBucket, socket); @@ -53,30 +53,30 @@ function prepareGamePage(environment, socket, timerWorker) { initializeGame(stateBucket, socket, timerWorker, userId, gameStateRenderer, gameTimerManager); if (!gameState.client.hasEnteredName) { - document.getElementById("prompt").innerHTML = templates.NAME_CHANGE_MODAL; - document.getElementById("change-name-form").onsubmit = (e) => { + document.getElementById('prompt').innerHTML = templates.NAME_CHANGE_MODAL; + document.getElementById('change-name-form').onsubmit = (e) => { e.preventDefault(); - let name = document.getElementById("player-new-name").value; + const name = document.getElementById('player-new-name').value; if (validateName(name)) { socket.emit(globals.COMMANDS.CHANGE_NAME, gameState.accessCode, { name: name, personId: gameState.client.id }, (result) => { switch (result) { - case "taken": + case 'taken': toast('This name is already taken.', 'error', true, true, 8); break; - case "changed": - ModalManager.dispelModal("change-name-modal", "change-name-modal-background") + case 'changed': + ModalManager.dispelModal('change-name-modal', 'change-name-modal-background'); toast('Name set.', 'success', true, true, 5); propagateNameChange(stateBucket.currentGameState, name, stateBucket.currentGameState.client.id); processGameState(stateBucket.currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker); } - }) + }); } else { - toast("Name must be between 1 and 30 characters.", 'error', true, true, 8); + toast('Name must be between 1 and 30 characters.', 'error', true, true, 8); } - } + }; } } }); @@ -85,20 +85,20 @@ function prepareGamePage(environment, socket, timerWorker) { } } -function initializeGame(stateBucket, socket, timerWorker, userId, gameStateRenderer, gameTimerManager) { +function initializeGame (stateBucket, socket, timerWorker, userId, gameStateRenderer, gameTimerManager) { setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWorker, gameTimerManager); processGameState(stateBucket.currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker); } -function processGameState (currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker, refreshPrompt=true) { +function processGameState (currentGameState, userId, socket, gameStateRenderer, gameTimerManager, timerWorker, refreshPrompt = true) { displayClientInfo(currentGameState.client.name, currentGameState.client.userType); if (refreshPrompt) { removeStartGameFunctionalityIfPresent(gameStateRenderer); - document.querySelector("#end-game-prompt")?.remove(); + document.querySelector('#end-game-prompt')?.remove(); } switch (currentGameState.status) { case globals.STATUS.LOBBY: - document.getElementById("game-state-container").innerHTML = templates.LOBBY; + document.getElementById('game-state-container').innerHTML = templates.LOBBY; gameStateRenderer.renderLobbyHeader(); gameStateRenderer.renderLobbyPlayers(); if ( @@ -109,31 +109,31 @@ function processGameState (currentGameState, userId, socket, gameStateRenderer, ) && refreshPrompt ) { - displayStartGamePromptForModerators(currentGameState, gameStateRenderer); + displayStartGamePromptForModerators(currentGameState, gameStateRenderer); } break; case globals.STATUS.IN_PROGRESS: gameStateRenderer.renderGameHeader(); switch (currentGameState.client.userType) { case globals.USER_TYPES.PLAYER: - document.getElementById("game-state-container").innerHTML = templates.PLAYER_GAME_VIEW; + document.getElementById('game-state-container').innerHTML = templates.PLAYER_GAME_VIEW; gameStateRenderer.renderPlayerView(); break; case globals.USER_TYPES.KILLED_PLAYER: - document.getElementById("game-state-container").innerHTML = templates.PLAYER_GAME_VIEW; + document.getElementById('game-state-container').innerHTML = templates.PLAYER_GAME_VIEW; gameStateRenderer.renderPlayerView(true); break; case globals.USER_TYPES.MODERATOR: - document.getElementById("game-state-container").innerHTML = templates.MODERATOR_GAME_VIEW; + document.getElementById('game-state-container').innerHTML = templates.MODERATOR_GAME_VIEW; gameStateRenderer.renderModeratorView(); break; case globals.USER_TYPES.TEMPORARY_MODERATOR: - document.getElementById("game-state-container").innerHTML = templates.TEMP_MOD_GAME_VIEW; + document.getElementById('game-state-container').innerHTML = templates.TEMP_MOD_GAME_VIEW; gameStateRenderer.renderTempModView(); break; case globals.USER_TYPES.SPECTATOR: - document.getElementById("game-state-container").innerHTML = templates.SPECTATOR_GAME_VIEW; + document.getElementById('game-state-container').innerHTML = templates.SPECTATOR_GAME_VIEW; gameStateRenderer.renderSpectatorView(); break; default: @@ -148,12 +148,13 @@ function processGameState (currentGameState, userId, socket, gameStateRenderer, document.querySelector('label[for="game-timer"]')?.remove(); } break; - case globals.STATUS.ENDED: - let container = document.getElementById("game-state-container") + case globals.STATUS.ENDED: { + const container = document.getElementById('game-state-container'); container.innerHTML = templates.END_OF_GAME_VIEW; container.classList.add('vertical-flex'); gameStateRenderer.renderEndOfGame(); break; + } default: break; } @@ -161,16 +162,16 @@ function processGameState (currentGameState, userId, socket, gameStateRenderer, activateRoleInfoButton(stateBucket.currentGameState.deck); } -function displayClientInfo(name, userType) { - document.getElementById("client-name").innerText = name; - document.getElementById("client-user-type").innerText = userType; - document.getElementById("client-user-type").innerText += globals.USER_TYPE_ICONS[userType]; +function displayClientInfo (name, userType) { + document.getElementById('client-name').innerText = name; + document.getElementById('client-user-type').innerText = userType; + document.getElementById('client-user-type').innerText += globals.USER_TYPE_ICONS[userType]; } -function setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWorker, gameTimerManager) { +function setClientSocketHandlers (stateBucket, gameStateRenderer, socket, timerWorker, gameTimerManager) { if (!socket.hasListeners(globals.EVENTS.PLAYER_JOINED)) { socket.on(globals.EVENTS.PLAYER_JOINED, (player, gameIsFull) => { - toast(player.name + " joined!", "success", false, true, 3); + toast(player.name + ' joined!', 'success', false, true, 3); stateBucket.currentGameState.people.push(player); stateBucket.currentGameState.isFull = gameIsFull; gameStateRenderer.renderLobbyPlayers(); @@ -189,8 +190,8 @@ function setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWo if (!socket.hasListeners(globals.EVENTS.PLAYER_LEFT)) { socket.on(globals.EVENTS.PLAYER_LEFT, (player) => { removeStartGameFunctionalityIfPresent(gameStateRenderer); - toast(player.name + " has left!", "error", false, true, 3); - let index = stateBucket.currentGameState.people.findIndex(person => person.id === player.id); + toast(player.name + ' has left!', 'error', false, true, 3); + const index = stateBucket.currentGameState.people.findIndex(person => person.id === player.id); if (index >= 0) { stateBucket.currentGameState.people.splice( index, @@ -248,17 +249,17 @@ function setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWo if (!socket.hasListeners(globals.EVENTS.KILL_PLAYER)) { socket.on(globals.EVENTS.KILL_PLAYER, (id) => { - let killedPerson = stateBucket.currentGameState.people.find((person) => person.id === id); + const killedPerson = stateBucket.currentGameState.people.find((person) => person.id === id); if (killedPerson) { killedPerson.out = true; if (stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR) { toast(killedPerson.name + ' killed.', 'success', true, true, 6); - gameStateRenderer.renderPlayersWithRoleAndAlignmentInfo(stateBucket.currentGameState.status === globals.STATUS.ENDED) + gameStateRenderer.renderPlayersWithRoleAndAlignmentInfo(stateBucket.currentGameState.status === globals.STATUS.ENDED); } else { if (killedPerson.id === stateBucket.currentGameState.client.id) { - let clientUserType = document.getElementById("client-user-type"); + const clientUserType = document.getElementById('client-user-type'); if (clientUserType) { - clientUserType.innerText = globals.USER_TYPES.KILLED_PLAYER + ' \uD83D\uDC80' + clientUserType.innerText = globals.USER_TYPES.KILLED_PLAYER + ' \uD83D\uDC80'; } gameStateRenderer.updatePlayerCardToKilledState(); toast('You have been killed!', 'warning', true, true, 6); @@ -277,14 +278,14 @@ function setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWo if (!socket.hasListeners(globals.EVENTS.REVEAL_PLAYER)) { socket.on(globals.EVENTS.REVEAL_PLAYER, (revealData) => { - let revealedPerson = stateBucket.currentGameState.people.find((person) => person.id === revealData.id); + const revealedPerson = stateBucket.currentGameState.people.find((person) => person.id === revealData.id); if (revealedPerson) { revealedPerson.revealed = true; revealedPerson.gameRole = revealData.gameRole; revealedPerson.alignment = revealData.alignment; if (stateBucket.currentGameState.client.userType === globals.USER_TYPES.MODERATOR) { toast(revealedPerson.name + ' revealed.', 'success', true, true, 6); - gameStateRenderer.renderPlayersWithRoleAndAlignmentInfo(stateBucket.currentGameState.status === globals.STATUS.ENDED) + gameStateRenderer.renderPlayersWithRoleAndAlignmentInfo(stateBucket.currentGameState.status === globals.STATUS.ENDED); } else { if (revealedPerson.id === stateBucket.currentGameState.client.id) { toast('Your role has been revealed!', 'warning', true, true, 6); @@ -333,38 +334,27 @@ function setClientSocketHandlers(stateBucket, gameStateRenderer, socket, timerWo } } -function displayStartGamePromptForModerators(gameState, gameStateRenderer) { - let div = document.createElement("div"); +function displayStartGamePromptForModerators (gameState, gameStateRenderer) { + const div = document.createElement('div'); div.innerHTML = templates.START_GAME_PROMPT; div.querySelector('#start-game-button').addEventListener('click', gameStateRenderer.startGameHandler); document.body.appendChild(div); } -function runGameTimer (hours, minutes, tickRate, soundManager, timerWorker) { - if (window.Worker) { - timerWorker.onmessage = function (e) { - if (e.data.hasOwnProperty('timeRemainingInMilliseconds') && e.data.timeRemainingInMilliseconds > 0) { - document.getElementById('game-timer').innerText = e.data.displayTime; - } - }; - timerWorker.postMessage({ hours: hours, minutes: minutes, tickInterval: tickRate }); - } -} - -function validateName(name) { +function validateName (name) { return typeof name === 'string' && name.length > 0 && name.length <= 30; } -function removeStartGameFunctionalityIfPresent(gameStateRenderer) { - document.querySelector("#start-game-prompt")?.removeEventListener('click', gameStateRenderer.startGameHandler); - document.querySelector("#start-game-prompt")?.remove(); +function removeStartGameFunctionalityIfPresent (gameStateRenderer) { + document.querySelector('#start-game-prompt')?.removeEventListener('click', gameStateRenderer.startGameHandler); + document.querySelector('#start-game-prompt')?.remove(); } -function propagateNameChange(gameState, name, personId) { +function propagateNameChange (gameState, name, personId) { if (gameState.client.id === personId) { gameState.client.name = name; } - let matchingPerson = gameState.people.find((person) => person.id === personId); + const matchingPerson = gameState.people.find((person) => person.id === personId); if (matchingPerson) { matchingPerson.name = name; } @@ -373,13 +363,13 @@ function propagateNameChange(gameState, name, personId) { gameState.moderator.name = name; } - let matchingSpectator = gameState.spectators?.find((spectator) => spectator.id === personId); + const matchingSpectator = gameState.spectators?.find((spectator) => spectator.id === personId); if (matchingSpectator) { matchingSpectator.name = name; } } -function updateDOMWithNameChange(gameState, gameStateRenderer) { +function updateDOMWithNameChange (gameState, gameStateRenderer) { if (gameState.status === globals.STATUS.IN_PROGRESS) { switch (gameState.client.userType) { case globals.USER_TYPES.PLAYER: @@ -401,23 +391,23 @@ function updateDOMWithNameChange(gameState, gameStateRenderer) { } } -function activateRoleInfoButton(deck) { +function activateRoleInfoButton (deck) { deck.sort((a, b) => { return a.team === globals.ALIGNMENT.GOOD ? 1 : -1; - }) - document.getElementById("role-info-button").addEventListener("click", (e) => { + }); + document.getElementById('role-info-button').addEventListener('click', (e) => { e.preventDefault(); - document.getElementById("prompt").innerHTML = templates.ROLE_INFO_MODAL; - let modalContent = document.getElementById('game-role-info-container'); - for (let card of deck) { - let roleDiv = document.createElement("div"); - let roleNameDiv = document.createElement("div"); + document.getElementById('prompt').innerHTML = templates.ROLE_INFO_MODAL; + const modalContent = document.getElementById('game-role-info-container'); + for (const card of deck) { + const roleDiv = document.createElement('div'); + const roleNameDiv = document.createElement('div'); roleNameDiv.classList.add('role-info-name'); - let roleName = document.createElement("h5"); - let roleQuantity = document.createElement("h5"); - let roleDescription = document.createElement("p"); + const roleName = document.createElement('h5'); + const roleQuantity = document.createElement('h5'); + const roleDescription = document.createElement('p'); roleDescription.innerText = card.description; roleName.innerText = card.role; @@ -429,8 +419,8 @@ function activateRoleInfoButton(deck) { roleName.classList.add(globals.ALIGNMENT.EVIL); } - roleNameDiv .appendChild(roleQuantity); - roleNameDiv .appendChild(roleName); + roleNameDiv.appendChild(roleQuantity); + roleNameDiv.appendChild(roleName); roleDiv.appendChild(roleNameDiv); roleDiv.appendChild(roleDescription); diff --git a/client/src/scripts/home.js b/client/src/scripts/home.js index b7372a0..15cf119 100644 --- a/client/src/scripts/home.js +++ b/client/src/scripts/home.js @@ -1,44 +1,44 @@ -import { XHRUtility } from "../modules/XHRUtility.js"; -import { toast } from "../modules/Toast.js"; -import { injectNavbar } from "../modules/Navbar.js"; +import { XHRUtility } from '../modules/XHRUtility.js'; +import { toast } from '../modules/Toast.js'; +import { injectNavbar } from '../modules/Navbar.js'; const home = () => { injectNavbar(); - document.getElementById("join-form").onsubmit = (e) => { + document.getElementById('join-form').onsubmit = (e) => { e.preventDefault(); - let userCode = document.getElementById("room-code").value; + const userCode = document.getElementById('room-code').value; if (roomCodeIsValid(userCode)) { attemptToJoinGame(userCode); } else { toast('Invalid code. Codes are 6 numbers or letters.', 'error', true, true); } - } + }; }; -function roomCodeIsValid(code) { - return typeof code === "string" && /^[a-z0-9]{6}$/.test(code.toLowerCase()); +function roomCodeIsValid (code) { + return typeof code === 'string' && /^[a-z0-9]{6}$/.test(code.toLowerCase()); } -function attemptToJoinGame(code) { +function attemptToJoinGame (code) { XHRUtility.xhr( '/api/games/availability/' + code.toLowerCase().trim(), 'GET', null, null ) - .then((res) => { - if (res.status === 200) { - window.location = '/game/' + res.content; - } - }).catch((res) => { - if (res.status === 404) { - toast("Game not found", "error", true); - } else if (res.status === 400) { - toast(res.content, "error", true); - } else { - toast("An unknown error occurred. Please try again later.", "error", true); - } - }); + .then((res) => { + if (res.status === 200) { + window.location = '/game/' + res.content; + } + }).catch((res) => { + if (res.status === 404) { + toast('Game not found', 'error', true); + } else if (res.status === 400) { + toast(res.content, 'error', true); + } else { + toast('An unknown error occurred. Please try again later.', 'error', true); + } + }); } if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { @@ -46,4 +46,3 @@ if (typeof module !== 'undefined' && typeof module.exports !== 'undefined') { } else { home(); } - diff --git a/client/src/scripts/howToUse.js b/client/src/scripts/howToUse.js index ee25480..e7d2679 100644 --- a/client/src/scripts/howToUse.js +++ b/client/src/scripts/howToUse.js @@ -1,4 +1,4 @@ -import { injectNavbar } from "../modules/Navbar.js"; +import { injectNavbar } from '../modules/Navbar.js'; const howToUse = () => { injectNavbar(); }; diff --git a/client/src/scripts/notFound.js b/client/src/scripts/notFound.js index e5a5ee2..68e7047 100644 --- a/client/src/scripts/notFound.js +++ b/client/src/scripts/notFound.js @@ -1,4 +1,4 @@ -import { injectNavbar } from "../modules/Navbar.js"; +import { injectNavbar } from '../modules/Navbar.js'; const notFound = () => { injectNavbar(); }; diff --git a/package-lock.json b/package-lock.json index d41b01d..6c5fd3e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -18,19 +18,20 @@ "integrity": "sha512-1o/jo7D+kC9ZjHX5v+EHrdjl3PhxMrLSOTGsOdHJ+KL8HCaEK6ehrVL2RS6oHDZp+L7xLirLrPmQtEng769J/Q==" }, "@babel/core": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.5.tgz", - "integrity": "sha512-wUcenlLzuWMZ9Zt8S0KmFwGlH6QKRh3vsm/dhDA3CHkiTA45YuG1XkHRcNRl73EFPXDp/d5kVOU0/y7x2w6OaQ==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.16.7.tgz", + "integrity": "sha512-aeLaqcqThRNZYmbMqtulsetOQZ/5gbR/dWruUCJcpas4Qoyy+QeagfDsPdMrqwsPRDNxJvBlRiZxxX7THO7qtA==", + "dev": true, "requires": { - "@babel/code-frame": "^7.16.0", - "@babel/generator": "^7.16.5", - "@babel/helper-compilation-targets": "^7.16.3", - "@babel/helper-module-transforms": "^7.16.5", - "@babel/helpers": "^7.16.5", - "@babel/parser": "^7.16.5", - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0", + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.7", + "@babel/helper-compilation-targets": "^7.16.7", + "@babel/helper-module-transforms": "^7.16.7", + "@babel/helpers": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7", "convert-source-map": "^1.7.0", "debug": "^4.1.0", "gensync": "^1.0.0-beta.2", @@ -39,10 +40,192 @@ "source-map": "^0.5.0" }, "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/generator": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz", + "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.8", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.16.7.tgz", + "integrity": "sha512-mGojBwIWcwGD6rfqgRXVlVYmPAv7eOpIemUG3dGnDdCY4Pae70ROij3XmfrH6Fa1h1aiDylpglbZyktfzyo/hA==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.16.4", + "@babel/helper-validator-option": "^7.16.7", + "browserslist": "^4.17.5", + "semver": "^6.3.0" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-imports": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.16.7.tgz", + "integrity": "sha512-LVtS6TqjJHFc+nYeITRo6VLXve70xmq7wPhWTqDJusJEgGmkAACWwMiTNrvfoQo6hEhFwAIixNkvB0jPXDL8Wg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-module-transforms": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.16.7.tgz", + "integrity": "sha512-gaqtLDxJEFCeQbYp9aLAefjhkKdjKcdh6DB7jniIGU3Pz52WAmP268zK0VgPz9hUNkMSYeH976K2/Y6yPadpng==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-module-imports": "^7.16.7", + "@babel/helper-simple-access": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/helper-validator-identifier": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-simple-access": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.16.7.tgz", + "integrity": "sha512-ZIzHVyoeLMvXMN/vok/a4LWRy8G2v205mNP0XOuf9XRLyX5/u9CnVulUtDgUTama3lT+bf/UqucuZjqiGuTS1g==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.16.7.tgz", + "integrity": "sha512-TRtenOuRUVo9oIQGPC5G9DgK4743cdxvtOw0weQNpZXaS16SCBi5MNjZF8vba3ETURjZpTbVn7Vvcf2eAwFozQ==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz", + "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==", + "dev": true + }, + "@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/traverse": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz", + "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.8", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.16.8", + "@babel/types": "^7.16.8", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz", + "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + }, "debug": { "version": "4.3.3", "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, "requires": { "ms": "2.1.2" } @@ -50,10 +233,22 @@ "ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true } } }, + "@babel/eslint-parser": { + "version": "7.16.5", + "resolved": "https://registry.npmjs.org/@babel/eslint-parser/-/eslint-parser-7.16.5.tgz", + "integrity": "sha512-mUqYa46lgWqHKQ33Q6LNCGp/wPR3eqOYTUixHFsfrSQqRxH0+WOzca75iEjFr5RDGH1dDz622LaHhLOzOuQRUA==", + "dev": true, + "requires": { + "eslint-scope": "^5.1.1", + "eslint-visitor-keys": "^2.1.0", + "semver": "^6.3.0" + } + }, "@babel/generator": { "version": "7.16.5", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.5.tgz", @@ -299,13 +494,160 @@ } }, "@babel/helpers": { - "version": "7.16.5", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.5.tgz", - "integrity": "sha512-TLgi6Lh71vvMZGEkFuIxzaPsyeYCHQ5jJOOX1f0xXn0uciFuE8cEk0wyBquMcCxBXZ5BJhE2aUB7pnWTD150Tw==", + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.16.7.tgz", + "integrity": "sha512-9ZDoqtfY7AuEOt3cxchfii6C7GDyyMBffktR5B2jvWv8u2+efwvpnVKXMWzNehqy68tKgAfSwfdw/lWpthS2bw==", + "dev": true, "requires": { - "@babel/template": "^7.16.0", - "@babel/traverse": "^7.16.5", - "@babel/types": "^7.16.0" + "@babel/template": "^7.16.7", + "@babel/traverse": "^7.16.7", + "@babel/types": "^7.16.7" + }, + "dependencies": { + "@babel/code-frame": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.16.7.tgz", + "integrity": "sha512-iAXqUn8IIeBTNd72xsFlgaXHkMBMt6y4HJp1tIaK465CWLT/fG1aqB7ykr95gHHmlBdGbFeWWfyB4NJJ0nmeIg==", + "dev": true, + "requires": { + "@babel/highlight": "^7.16.7" + } + }, + "@babel/generator": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.16.8.tgz", + "integrity": "sha512-1ojZwE9+lOXzcWdWmO6TbUzDfqLD39CmEhN8+2cX9XkDo5yW1OpgfejfliysR2AWLpMamTiOiAp/mtroaymhpw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.8", + "jsesc": "^2.5.1", + "source-map": "^0.5.0" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.16.7.tgz", + "integrity": "sha512-SLLb0AAn6PkUeAfKJCCOl9e1R53pQlGAfc4y4XuMRZfqeMYLE0dM1LMhqbGAlGQY0lfw5/ohoYWAe9V1yibRag==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-function-name": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.16.7.tgz", + "integrity": "sha512-QfDfEnIUyyBSR3HtrtGECuZ6DAyCkYFp7GHl75vFtTnn6pjKeK0T1DB5lLkFvBea8MdaiUABx3osbgLyInoejA==", + "dev": true, + "requires": { + "@babel/helper-get-function-arity": "^7.16.7", + "@babel/template": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-get-function-arity": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-get-function-arity/-/helper-get-function-arity-7.16.7.tgz", + "integrity": "sha512-flc+RLSOBXzNzVhcLu6ujeHUrD6tANAOU5ojrRx/as+tbzf8+stUCj7+IfRRoAbEZqj/ahXEMsjhOhgeZsrnTw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.16.7.tgz", + "integrity": "sha512-m04d/0Op34H5v7pbZw6pSKP7weA6lsMvfiIAMeIvkY/R4xQtBSMFEigu9QTZ2qB/9l22vsxtM8a+Q8CzD255fg==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.16.7.tgz", + "integrity": "sha512-xbWoy/PFoxSWazIToT9Sif+jJTlrMcndIsaOKvTA6u7QEo7ilkRZpjew18/W3c7nm8fXdUDXh02VXTbZ0pGDNw==", + "dev": true, + "requires": { + "@babel/types": "^7.16.7" + } + }, + "@babel/helper-validator-identifier": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.16.7.tgz", + "integrity": "sha512-hsEnFemeiW4D08A5gUAZxLBTXpZ39P+a+DGDsHw1yxqyQ/jzFEnxf5uTEGp+3bzAbNOxU1paTgYS4ECU/IgfDw==", + "dev": true + }, + "@babel/highlight": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.16.7.tgz", + "integrity": "sha512-aKpPMfLvGO3Q97V0qhw/V2SWNWlwfJknuwAunU7wZLSfrM4xTBvg7E5opUVi1kJTBKihE38CPg4nBiqX83PWYw==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "chalk": "^2.0.0", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.16.8.tgz", + "integrity": "sha512-i7jDUfrVBWc+7OKcBzEe5n7fbv3i2fWtxKzzCvOjnzSxMfWMigAhtfJ7qzZNGFNMsCCd67+uz553dYKWXPvCKw==", + "dev": true + }, + "@babel/template": { + "version": "7.16.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.16.7.tgz", + "integrity": "sha512-I8j/x8kHUrbYRTUxXrrMbfCa7jxkE7tZre39x3kjr9hvI82cK1FfqLygotcWN5kdPGWcLdWMHpSBavse5tWw3w==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/parser": "^7.16.7", + "@babel/types": "^7.16.7" + } + }, + "@babel/traverse": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.16.8.tgz", + "integrity": "sha512-xe+H7JlvKsDQwXRsBhSnq1/+9c+LlQcCK3Tn/l5sbx02HYns/cn7ibp9+RV1sIUqu7hKg91NWsgHurO9dowITQ==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.16.7", + "@babel/generator": "^7.16.8", + "@babel/helper-environment-visitor": "^7.16.7", + "@babel/helper-function-name": "^7.16.7", + "@babel/helper-hoist-variables": "^7.16.7", + "@babel/helper-split-export-declaration": "^7.16.7", + "@babel/parser": "^7.16.8", + "@babel/types": "^7.16.8", + "debug": "^4.1.0", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.16.8", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.16.8.tgz", + "integrity": "sha512-smN2DQc5s4M7fntyjGtyIPbRJv6wW4rU/94fmYJ7PKQuZkC0qGMHXJbg6sNGt12JmVr4k5YaptI/XtiLJBnmIg==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.16.7", + "to-fast-properties": "^2.0.0" + } + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } } }, "@babel/highlight": { @@ -1042,6 +1384,83 @@ "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.6.tgz", "integrity": "sha512-ws57AidsDvREKrZKYffXddNkyaF14iHNHm8VQnZH6t99E8gczjNN0GpvcGny0imC80yQ0tHz1xVUKk/KFQSUyA==" }, + "@eslint/eslintrc": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-1.0.5.tgz", + "integrity": "sha512-BLxsnmK3KyPunz5wmCCpqy0YelEoxxGmH73Is+Z74oOTMtExcjkr3dDR6quwrjh1YspA8DH9gnX1o069KiS9AQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.2.0", + "globals": "^13.9.0", + "ignore": "^4.0.6", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.0.4", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "globals": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", + "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@humanwhocodes/config-array": { + "version": "0.9.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.9.2.tgz", + "integrity": "sha512-UXOuFCGcwciWckOpmfKDq/GyhlTf9pN/BzG//x8p8zTOFEcGuA68ANXheFS0AGvy3qgZqLBUkMs7hqzqCKOVwA==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.4" + }, + "dependencies": { + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + } + } + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, "@socket.io/component-emitter": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.0.0.tgz", @@ -1090,6 +1509,12 @@ "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.9.tgz", "integrity": "sha512-qcUXuemtEu+E5wZSJHNxUXeCZhAfXKQ41D+duX+VYPde7xyEVZci+/oXKJL13tnRs9lR2pr4fod59GT6/X1/yQ==" }, + "@types/json5": { + "version": "0.0.29", + "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", + "integrity": "sha1-7ihweulOEdK4J7y+UnC86n8+ce4=", + "dev": true + }, "@types/node": { "version": "17.0.3", "resolved": "https://registry.npmjs.org/@types/node/-/node-17.0.3.tgz", @@ -1273,6 +1698,12 @@ "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.8.0.tgz", "integrity": "sha512-m7VZ3jwz4eK6A4Vtt8Ew1/mNbP24u0FhdyfA7fSvnJR6LMdfOYnmuIrrJAgrYfYJ10F/otaHTtrtrtmHdMNzEw==" }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true + }, "ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1289,6 +1720,18 @@ "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==" }, + "ansi-colors": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.1.tgz", + "integrity": "sha512-JoX0apGbHaUJBNl6yF+p6JAFYZ666/hhCGKN5t9QFjbJQKUU/g8MNbFDbvfrgKXvI1QpZplPOnwIo99lX/AAmA==", + "dev": true + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, "ansi-styles": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", @@ -1297,11 +1740,61 @@ "color-convert": "^1.9.0" } }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, "array-flatten": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha1-ml9pkFGx5wczKPKgCJaLZOopVdI=" }, + "array-includes": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/array-includes/-/array-includes-3.1.4.tgz", + "integrity": "sha512-ZTNSQkmWumEbiHO2GF4GmWxYVTiQyJy2XOTa15sdQSrvKn7l+180egQMqlrMOUMCyLMD7pmyQe4mMDUT6Behrw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1", + "get-intrinsic": "^1.1.1", + "is-string": "^1.0.7" + } + }, + "array.prototype.flat": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/array.prototype.flat/-/array.prototype.flat-1.2.5.tgz", + "integrity": "sha512-KaYU+S+ndVqyUnignHftkwc58o3uVU1jzczILJ1tN2YaIZpFIKBiP/x/j97E5MVPsaCloPbqWLB/8qCTVvT2qg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.0" + } + }, + "babel-eslint": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-10.1.0.tgz", + "integrity": "sha512-ifWaTHQ0ce+448CYop8AdrQiBsGrnC+bMgfyKFdi6EsPLTAWG+QfyDeM6OH+FmWnKvEq5NnBMLvlBUPKQZoDSg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "@babel/parser": "^7.7.0", + "@babel/traverse": "^7.7.0", + "@babel/types": "^7.7.0", + "eslint-visitor-keys": "^1.0.0", + "resolve": "^1.12.0" + }, + "dependencies": { + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==" + } + } + }, "babel-loader": { "version": "8.2.3", "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-8.2.3.tgz", @@ -1430,6 +1923,12 @@ "get-intrinsic": "^1.0.2" } }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, "caniuse-lite": { "version": "1.0.30001292", "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001292.tgz", @@ -1522,6 +2021,7 @@ "version": "1.8.0", "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.8.0.tgz", "integrity": "sha512-+OQdjP49zViI/6i7nIJpA8rAl4sV/JdPfU9nZs3VqOwGIgizICvuN2ru6fMd+4llL0tar18UYJXfZ/TWtmhUjA==", + "dev": true, "requires": { "safe-buffer": "~5.1.1" } @@ -1579,6 +2079,12 @@ "ms": "2.0.0" } }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, "define-properties": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", @@ -1597,6 +2103,15 @@ "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=" }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, "ee-first": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", @@ -1697,16 +2212,64 @@ "tapable": "^2.2.0" } }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "dev": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, "envinfo": { "version": "7.8.1", "resolved": "https://registry.npmjs.org/envinfo/-/envinfo-7.8.1.tgz", "integrity": "sha512-/o+BXHmB7ocbHEAs6F2EnG0ogybVVUdkRunTT2glZU9XAaGmhqskrvKwqXuDfNjEO0LZKWdejEEpnq8aM0tOaw==" }, + "es-abstract": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.19.1.tgz", + "integrity": "sha512-2vJ6tjA/UfqLm2MPs7jxVybLoB8i1t1Jd9R3kISld20sIxPcTbLuggQOUxeWeAvIUkduv/CfMjuh4WmiXr2v9w==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "get-symbol-description": "^1.0.0", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "internal-slot": "^1.0.3", + "is-callable": "^1.2.4", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.4", + "is-shared-array-buffer": "^1.0.1", + "is-string": "^1.0.7", + "is-weakref": "^1.0.1", + "object-inspect": "^1.11.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.1" + } + }, "es-module-lexer": { "version": "0.9.3", "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-0.9.3.tgz", "integrity": "sha512-1HQ2M2sPtxwnvOvT1ZClHyQDiggdNjURWpY2we6aMKCQiUVxTmVs2UYPLIrD84sS+kMdUwfBSylbJPwNnBrnHQ==" }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dev": true, + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, "escalade": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", @@ -1722,6 +2285,374 @@ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" }, + "eslint": { + "version": "8.6.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.6.0.tgz", + "integrity": "sha512-UvxdOJ7mXFlw7iuHZA4jmzPaUqIw54mZrv+XPYKNbKdLR0et4rf60lIZUU9kiNtnzzMzGWxMV+tQ7uG7JG8DPw==", + "dev": true, + "requires": { + "@eslint/eslintrc": "^1.0.5", + "@humanwhocodes/config-array": "^0.9.2", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "enquirer": "^2.3.5", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.0", + "eslint-utils": "^3.0.0", + "eslint-visitor-keys": "^3.1.0", + "espree": "^9.3.0", + "esquery": "^1.4.0", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "functional-red-black-tree": "^1.0.1", + "glob-parent": "^6.0.1", + "globals": "^13.6.0", + "ignore": "^4.0.6", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.0.4", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "progress": "^2.0.0", + "regexpp": "^3.2.0", + "semver": "^7.2.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0", + "v8-compile-cache": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "debug": { + "version": "4.3.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.3.tgz", + "integrity": "sha512-/zxw5+vh1Tfv+4Qn7a5nsbcJKPaSvCDhojn6FEl9vupwK2VCSDtEiEtqr8DFtzYFOdz63LBkxec7DYuc2jon6Q==", + "dev": true, + "requires": { + "ms": "2.1.2" + } + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint-scope": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.0.tgz", + "integrity": "sha512-aWwkhnS0qAXqNOgKOK0dJ2nvzEbhEvpy8OlJ9kZ0FeZnA6zpjv1/Vei+puGFFX7zkPCkHHXb7IDX3A+7yPrRWg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "eslint-visitor-keys": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", + "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "dev": true + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "globals": { + "version": "13.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.12.0.tgz", + "integrity": "sha512-uS8X6lSKN2JumVoXrbUz+uG4BYG+eiawqm3qFcT7ammfbUHeCBoJMlHcec/S3krSk73/AE/f0szYFmgAA3kYZg==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", + "dev": true + }, + "semver": { + "version": "7.3.5", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.3.5.tgz", + "integrity": "sha512-PoeGJYh8HK4BTO/a9Tf6ZG3veo/A7ZVsYrSA6J8ny9nb3B1VrpkuN+z9OE5wfE5p6H4LchYZsegiQgbJD94ZFQ==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "eslint-config-standard": { + "version": "16.0.3", + "resolved": "https://registry.npmjs.org/eslint-config-standard/-/eslint-config-standard-16.0.3.tgz", + "integrity": "sha512-x4fmJL5hGqNJKGHSjnLdgA6U6h1YW/G2dW9fA+cyVur4SK6lyue8+UgNKWlZtUDTXvgKDD/Oa3GQjmB5kjtVvg==" + }, + "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", + "integrity": "sha512-0En0w03NRVMn9Uiyn8YRPDKvWjxCWkslUEhGNTdGx15RvPJYQ+lbOlqrlNI2vEAs4pDYK4f/HN2TbDmk5TP0iw==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "resolve": "^1.20.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + } + } + }, + "eslint-module-utils": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/eslint-module-utils/-/eslint-module-utils-2.7.2.tgz", + "integrity": "sha512-zquepFnWCY2ISMFwD/DqzaM++H+7PDzOpUvotJWm/y1BAFt5R4oeULgdrTejKqLkz7MA/tgstsUMNYc7wNdTrg==", + "dev": true, + "requires": { + "debug": "^3.2.7", + "find-up": "^2.1.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dev": true, + "requires": { + "ms": "^2.1.1" + } + }, + "find-up": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-2.1.0.tgz", + "integrity": "sha1-RdG35QbHF93UgndaK3eSCjwMV6c=", + "dev": true, + "requires": { + "locate-path": "^2.0.0" + } + }, + "locate-path": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-2.0.0.tgz", + "integrity": "sha1-K1aLJl7slExtnA3pw9u7ygNUzY4=", + "dev": true, + "requires": { + "p-locate": "^2.0.0", + "path-exists": "^3.0.0" + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true + }, + "p-limit": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz", + "integrity": "sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q==", + "dev": true, + "requires": { + "p-try": "^1.0.0" + } + }, + "p-locate": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-2.0.0.tgz", + "integrity": "sha1-IKAQOyIqcMj9OcwuWAaA893l7EM=", + "dev": true, + "requires": { + "p-limit": "^1.1.0" + } + }, + "p-try": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-1.0.0.tgz", + "integrity": "sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M=", + "dev": true + }, + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "eslint-plugin-es": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/eslint-plugin-es/-/eslint-plugin-es-3.0.1.tgz", + "integrity": "sha512-GUmAsJaN4Fc7Gbtl8uOBlayo2DqhwWvEzykMHSCZHU3XdJ+NSzzZcVhXh3VxX5icqQ+oQdIEawXX8xkR3mIFmQ==", + "dev": true, + "requires": { + "eslint-utils": "^2.0.0", + "regexpp": "^3.0.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + } + } + }, + "eslint-plugin-import": { + "version": "2.25.4", + "resolved": "https://registry.npmjs.org/eslint-plugin-import/-/eslint-plugin-import-2.25.4.tgz", + "integrity": "sha512-/KJBASVFxpu0xg1kIBn9AUa8hQVnszpwgE7Ld0lKAlx7Ie87yzEzCgSkekt+le/YVhiaosO4Y14GDAOc41nfxA==", + "dev": true, + "requires": { + "array-includes": "^3.1.4", + "array.prototype.flat": "^1.2.5", + "debug": "^2.6.9", + "doctrine": "^2.1.0", + "eslint-import-resolver-node": "^0.3.6", + "eslint-module-utils": "^2.7.2", + "has": "^1.0.3", + "is-core-module": "^2.8.0", + "is-glob": "^4.0.3", + "minimatch": "^3.0.4", + "object.values": "^1.1.5", + "resolve": "^1.20.0", + "tsconfig-paths": "^3.12.0" + }, + "dependencies": { + "doctrine": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", + "integrity": "sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + } + } + }, + "eslint-plugin-node": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-node/-/eslint-plugin-node-11.1.0.tgz", + "integrity": "sha512-oUwtPJ1W0SKD0Tr+wqu92c5xuCeQqB3hSCHasn/ZgjFdA9iDGNkNf2Zi9ztY7X+hNuMib23LNGRm6+uN+KLE3g==", + "dev": true, + "requires": { + "eslint-plugin-es": "^3.0.0", + "eslint-utils": "^2.0.0", + "ignore": "^5.1.1", + "minimatch": "^3.0.4", + "resolve": "^1.10.1", + "semver": "^6.1.0" + }, + "dependencies": { + "eslint-utils": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-2.1.0.tgz", + "integrity": "sha512-w94dQYoauyvlDc43XnGB8lU3Zt713vNChgt4EWwhXAP2XkBvndfxF0AgIqKOOasjPIPzj9JqgwkwbCYD0/V3Zg==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^1.1.0" + } + }, + "eslint-visitor-keys": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz", + "integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ==", + "dev": true + }, + "ignore": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.0.tgz", + "integrity": "sha512-CmxgYGiEPCLhfLnpPp1MoRmifwEIOgjcHXxOBjv7mY96c+eWScsOP9c112ZyLdWHi0FxHjI+4uVhKYp/gcdRmQ==", + "dev": true + } + } + }, + "eslint-plugin-promise": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/eslint-plugin-promise/-/eslint-plugin-promise-6.0.0.tgz", + "integrity": "sha512-7GPezalm5Bfi/E22PnQxDWH2iW9GTvAlUNTztemeHb6c1BniSyoeTrM87JkC0wYdi6aQrZX9p2qEiAno8aTcbw==", + "dev": true + }, "eslint-scope": { "version": "5.1.1", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", @@ -1731,6 +2662,63 @@ "estraverse": "^4.1.1" } }, + "eslint-utils": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/eslint-utils/-/eslint-utils-3.0.0.tgz", + "integrity": "sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^2.0.0" + } + }, + "eslint-visitor-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz", + "integrity": "sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw==", + "dev": true + }, + "espree": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.3.0.tgz", + "integrity": "sha512-d/5nCsb0JcqsSEeQzFZ8DH1RmxPcglRWh24EFTlUEmCKoehXGdpsx0RkHDubqUI8LSAIKMQp4r9SzQ3n+sm4HQ==", + "dev": true, + "requires": { + "acorn": "^8.7.0", + "acorn-jsx": "^5.3.1", + "eslint-visitor-keys": "^3.1.0" + }, + "dependencies": { + "acorn": { + "version": "8.7.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.0.tgz", + "integrity": "sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==", + "dev": true + }, + "eslint-visitor-keys": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.1.0.tgz", + "integrity": "sha512-yWJFpu4DtjsWKkt5GeNBBuZMlNcYVs6vRCLoCVEJrTjaSB6LC98gFipNK/erM2Heg/E8mIK+hXG/pJMLK+eRZA==", + "dev": true + } + } + }, + "esquery": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.4.0.tgz", + "integrity": "sha512-cCDispWt5vHHtwMY2YrAQ4ibFkAL8RbH5YGBnZBc90MolvvfkkQcJro/aZiAQUlQ3qgrYS6D6v8Gc5G5CQsc9w==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, "esrecurse": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", @@ -1846,11 +2834,26 @@ "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=", + "dev": true + }, "fastest-levenshtein": { "version": "1.0.12", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.12.tgz", "integrity": "sha512-On2N+BpYJ15xIC974QNVuYGMOlEVt4s0EOI3wwMqOmK1fdDY+FN/zltPV8vosq4ad4c/gJ1KHScUn/6AWIgiow==" }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, "finalhandler": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", @@ -1884,6 +2887,22 @@ "path-exists": "^4.0.0" } }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.4.tgz", + "integrity": "sha512-8/sOawo8tJ4QOBX8YlQBMxL8+RLZfxMQOif9o0KUKTNTjMYElWPE0r/m5VNFxTRd0NSw8qSy8dajrwX4RYI1Hw==", + "dev": true + }, "forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -1904,10 +2923,17 @@ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==" }, + "functional-red-black-tree": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz", + "integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=", + "dev": true + }, "gensync": { "version": "1.0.0-beta.2", "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", - "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true }, "get-intrinsic": { "version": "1.1.1", @@ -1924,6 +2950,16 @@ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" }, + "get-symbol-description": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.0.0.tgz", + "integrity": "sha512-2EmdH1YvIQiZpltCNgkuiUnyukzxM/R6NDJX31Ke3BG1Nq5b0S2PhX59UKi9vZpPDQVdqn+1IcaAwnzTT5vCjw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "get-intrinsic": "^1.1.1" + } + }, "glob": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", @@ -1937,6 +2973,15 @@ "path-is-absolute": "^1.0.0" } }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, "glob-to-regexp": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", @@ -1960,6 +3005,12 @@ "function-bind": "^1.1.1" } }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "dev": true + }, "has-cors": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-cors/-/has-cors-1.1.0.tgz", @@ -1975,6 +3026,15 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.2.tgz", "integrity": "sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==" }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, "http-errors": { "version": "1.8.1", "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.8.1.tgz", @@ -2007,6 +3067,30 @@ "safer-buffer": ">= 2.1.2 < 3" } }, + "ignore": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz", + "integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + } + } + }, "import-local": { "version": "3.0.3", "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.0.3.tgz", @@ -2016,6 +3100,12 @@ "resolve-cwd": "^3.0.0" } }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, "inflight": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", @@ -2030,6 +3120,17 @@ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, + "internal-slot": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.3.tgz", + "integrity": "sha512-O0DB1JC/sPyZl7cIo78n5dR7eUSwwpYPiXRhTzNxZVAMUuB8vlnRFyLxdrVToks6XPLVnFfbzaVd5WLjhgg+vA==", + "dev": true, + "requires": { + "get-intrinsic": "^1.1.0", + "has": "^1.0.3", + "side-channel": "^1.0.4" + } + }, "interpret": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz", @@ -2040,6 +3141,31 @@ "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" }, + "is-bigint": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz", + "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==", + "dev": true, + "requires": { + "has-bigints": "^1.0.1" + } + }, + "is-boolean-object": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz", + "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-callable": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.4.tgz", + "integrity": "sha512-nsuwtxZfMX67Oryl9LCQ+upnC0Z0BgpwntpS89m1H/TLF0zNfzfLMV/9Wa/6MZsj0acpEjAO0KF1xT6ZdLl95w==", + "dev": true + }, "is-core-module": { "version": "2.8.0", "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.8.0.tgz", @@ -2048,11 +3174,50 @@ "has": "^1.0.3" } }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-docker": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.1.1.tgz", "integrity": "sha512-ZOoqiXfEwtGknTiuDEy8pN2CfE3TxMHprvNer1mXiqwkOT77Rw3YVrUQ52EqAOU3QAWDQ+bQdx7HJzrv7LS2Hw==" }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negative-zero": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.2.tgz", + "integrity": "sha512-dqJvarLawXsFbNDeJW7zAz8ItJ9cd28YufuuFzh0G8pNHjJMnY08Dv7sYX2uF5UpQOwieAeOExEYAWWfu7ZZUA==", + "dev": true + }, + "is-number-object": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.6.tgz", + "integrity": "sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, "is-plain-object": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", @@ -2061,11 +3226,54 @@ "isobject": "^3.0.1" } }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-shared-array-buffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.1.tgz", + "integrity": "sha512-IU0NmyknYZN0rChcKhRO1X8LYz5Isj/Fsqh8NJOSf+N/hCOTwy29F32Ik7a+QszE63IdvmwdTPDd6cZ5pg4cwA==", + "dev": true + }, "is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" }, + "is-string": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz", + "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==", + "dev": true, + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-symbol": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz", + "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==", + "dev": true, + "requires": { + "has-symbols": "^1.0.2" + } + }, + "is-weakref": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-weakref/-/is-weakref-1.0.2.tgz", + "integrity": "sha512-qctsuLZmIQ0+vSSMfoVvyFe2+GSEvnmZ2ezTup1SBse9+twCCeial6EEi3Nc2KFcf6+qz2FBPnjXsk8xhKSaPQ==", + "dev": true, + "requires": { + "call-bind": "^1.0.2" + } + }, "is-wsl": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", @@ -2128,6 +3336,15 @@ "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, "jsesc": { "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", @@ -2143,10 +3360,17 @@ "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, "json5": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.0.tgz", "integrity": "sha512-f+8cldu7X/y7RAJurMEJmdoKXGB/X550w2Nr3tTbezL6RwEE/iMcm+tZnXeoZtKuOq6ft8+CqzEkrIgx1fPoQA==", + "dev": true, "requires": { "minimist": "^1.2.5" } @@ -2156,6 +3380,16 @@ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, "loader-runner": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", @@ -2194,6 +3428,21 @@ "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=" }, + "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 + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, "make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -2263,6 +3512,12 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=", + "dev": true + }, "negotiator": { "version": "0.6.2", "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.2.tgz", @@ -2291,6 +3546,12 @@ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" }, + "object-inspect": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.12.0.tgz", + "integrity": "sha512-Ho2z80bVIvJloH+YzRmpZVQe87+qASmBUKZDWgx9cu+KDrX2ZDH/3tMy+gXbZETVGs2M8YdxObOh7XAtim9Y0g==", + "dev": true + }, "object-keys": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", @@ -2307,6 +3568,17 @@ "object-keys": "^1.1.1" } }, + "object.values": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/object.values/-/object.values-1.1.5.tgz", + "integrity": "sha512-QUZRW0ilQ3PnPpbNtgdNV1PDbEqLIiSFB3l+EnGtBQ/8SUTLj1PZwtQHABZtLgwpJZTSZhuGLOGk57Drx2IvYg==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3", + "es-abstract": "^1.19.1" + } + }, "on-finished": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", @@ -2340,6 +3612,20 @@ "is-wsl": "^2.1.1" } }, + "optionator": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.1.tgz", + "integrity": "sha512-74RlY5FCnhq4jRxVUPKDaRwrVNXMqsGsiW6AJw4XK8hmtm10wC0ypZBLw5IIp85NZMr91+qd1RvvENwg7jjRFw==", + "dev": true, + "requires": { + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0", + "word-wrap": "^1.2.3" + } + }, "p-limit": { "version": "2.3.0", "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", @@ -2361,6 +3647,15 @@ "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, "parseqs": { "version": "0.0.6", "resolved": "https://registry.npmjs.org/parseqs/-/parseqs-0.0.6.tgz", @@ -2414,6 +3709,18 @@ "find-up": "^4.0.0" } }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "progress": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz", + "integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==", + "dev": true + }, "proxy-addr": { "version": "2.0.7", "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", @@ -2491,6 +3798,12 @@ "@babel/runtime": "^7.8.4" } }, + "regexpp": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/regexpp/-/regexpp-3.2.0.tgz", + "integrity": "sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==", + "dev": true + }, "regexpu-core": { "version": "4.8.0", "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-4.8.0.tgz", @@ -2546,6 +3859,15 @@ "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, "safe-buffer": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", @@ -2643,6 +3965,17 @@ "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dev": true, + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, "signal-exit": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.6.tgz", @@ -2769,11 +4102,52 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dev": true, + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", + "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", + "dev": true + }, "strip-final-newline": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, "supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -2833,6 +4207,12 @@ } } }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ=", + "dev": true + }, "to-fast-properties": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", @@ -2843,6 +4223,44 @@ "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" }, + "tsconfig-paths": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.12.0.tgz", + "integrity": "sha512-e5adrnOYT6zqVnWqZu7i/BQ3BnhzvGbjEjejFXO20lKIKpwTaupkCPgEfv4GZK1IBciJUEhYs3J3p75FdaTFVg==", + "dev": true, + "requires": { + "@types/json5": "^0.0.29", + "json5": "^1.0.1", + "minimist": "^1.2.0", + "strip-bom": "^3.0.0" + }, + "dependencies": { + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + } + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + }, "type-is": { "version": "1.6.18", "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", @@ -2852,6 +4270,18 @@ "mime-types": "~2.1.24" } }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, "unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", @@ -2894,6 +4324,12 @@ "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" }, + "v8-compile-cache": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz", + "integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==", + "dev": true + }, "vary": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", @@ -3009,11 +4445,30 @@ "isexe": "^2.0.0" } }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dev": true, + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, "wildcard": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.0.tgz", "integrity": "sha512-JcKqAHLPxcdb9KM49dufGXn2x3ssnfjbcaQdLlfZsL9rH9wgDQjUtDxbo8NE0F6SFvydeu1VhZe7hZuHsB2/pw==" }, + "word-wrap": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", + "integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==", + "dev": true + }, "wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -3029,6 +4484,12 @@ "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==" }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, "yeast": { "version": "0.1.2", "resolved": "https://registry.npmjs.org/yeast/-/yeast-0.1.2.tgz", diff --git a/package.json b/package.json index 463e854..1235b00 100644 --- a/package.json +++ b/package.json @@ -21,13 +21,14 @@ "author": "", "license": "ISC", "dependencies": { - "@babel/core": "^7.16.5", "@babel/plugin-transform-object-assign": "^7.16.5", "@babel/preset-env": "^7.16.5", "acorn": "^8.6.0", + "babel-eslint": "^10.1.0", "babel-loader": "^8.2.3", "body-parser": "^1.19.1", "cors": "^2.8.5", + "eslint-config-standard": "^16.0.3", "express": "^4.17.1", "express-force-https": "^1.0.0", "express-rate-limit": "^6.0.1", @@ -39,7 +40,14 @@ "webpack-cli": "^4.9.1", "webpack-remove-debug": "^0.1.0" }, - "devDependencies": {}, + "devDependencies": { + "@babel/core": "^7.16.7", + "@babel/eslint-parser": "^7.16.5", + "eslint": "^8.6.0", + "eslint-plugin-import": "^2.25.4", + "eslint-plugin-node": "^11.1.0", + "eslint-plugin-promise": "^6.0.0" + }, "nodemonConfig": { "ignore": [ "client/*", diff --git a/server/api/GamesAPI.js b/server/api/GamesAPI.js index 82aebc9..206f745 100644 --- a/server/api/GamesAPI.js +++ b/server/api/GamesAPI.js @@ -3,7 +3,7 @@ const router = express.Router(); const debugMode = Array.from(process.argv.map((arg) => arg.trim().toLowerCase())).includes('debug'); const logger = require('../modules/Logger')(debugMode); const GameManager = require('../modules/GameManager.js'); -const rateLimit = require('express-rate-limit').default +const rateLimit = require('express-rate-limit').default; const globals = require('../config/globals'); const gameManager = new GameManager().getInstance(); @@ -12,8 +12,8 @@ const apiLimiter = rateLimit({ windowMs: 600000, max: 5, standardHeaders: true, - legacyHeaders: false, -}) + legacyHeaders: false +}); if (process.env.NODE_ENV.trim() === 'production') { // in prod, limit clients to creating 5 games per 10 minutes. router.use('/create', apiLimiter); @@ -42,7 +42,7 @@ router.get('/availability/:code', function (req, res) { res.status(404).send(); } else if (result instanceof Error) { res.status(400).send(result.message); - } else if (typeof result === "string") { + } else if (typeof result === 'string') { logger.debug(result); res.status(200).send(result); } else { diff --git a/server/config/globals.js b/server/config/globals.js index 4ee35bc..59c26d0 100644 --- a/server/config/globals.js +++ b/server/config/globals.js @@ -18,48 +18,48 @@ const globals = { FETCH_IN_PROGRESS_STATE: 'fetchInitialInProgressState' }, MESSAGES: { - ENTER_NAME: "Client must enter name." + ENTER_NAME: 'Client must enter name.' }, STATUS: { - LOBBY: "lobby", - IN_PROGRESS: "in progress", - ENDED: "ended" + LOBBY: 'lobby', + IN_PROGRESS: 'in progress', + ENDED: 'ended' }, USER_SIGNATURE_LENGTH: 25, USER_TYPES: { - MODERATOR: "moderator", - PLAYER: "player", - TEMPORARY_MODERATOR: "player / temp mod", - KILLED_PLAYER: "killed", - SPECTATOR: "spectator" + MODERATOR: 'moderator', + PLAYER: 'player', + TEMPORARY_MODERATOR: 'player / temp mod', + KILLED_PLAYER: 'killed', + SPECTATOR: 'spectator' }, ERROR_MESSAGE: { - GAME_IS_FULL: "This game is full", - BAD_CREATE_REQUEST: "Game has invalid options." + GAME_IS_FULL: 'This game is full', + BAD_CREATE_REQUEST: 'Game has invalid options.' }, EVENTS: { - PLAYER_JOINED: "playerJoined", - PLAYER_LEFT: "playerLeft", - SYNC_GAME_STATE: "syncGameState" + PLAYER_JOINED: 'playerJoined', + PLAYER_LEFT: 'playerLeft', + SYNC_GAME_STATE: 'syncGameState' }, ENVIRONMENT: { - LOCAL: "local", - PRODUCTION: "production" + LOCAL: 'local', + PRODUCTION: 'production' }, LOG_LEVEL: { - INFO: "info", - DEBUG: "debug", - ERROR: "error", - WARN: "warn", - TRACE: "trace" + INFO: 'info', + DEBUG: 'debug', + ERROR: 'error', + WARN: 'warn', + TRACE: 'trace' }, GAME_PROCESS_COMMANDS: { - END_TIMER: "endTimer", - START_GAME: "startGame", - START_TIMER: "startTimer", - PAUSE_TIMER: "pauseTimer", - RESUME_TIMER: "resumeTimer", - GET_TIME_REMAINING: "getTimeRemaining" + END_TIMER: 'endTimer', + START_GAME: 'startGame', + START_TIMER: 'startTimer', + PAUSE_TIMER: 'pauseTimer', + RESUME_TIMER: 'resumeTimer', + GET_TIME_REMAINING: 'getTimeRemaining' } }; diff --git a/server/main.js b/server/main.js index cb742a9..a2d3748 100644 --- a/server/main.js +++ b/server/main.js @@ -2,7 +2,7 @@ const express = require('express'); const path = require('path'); const app = express(); const bodyParser = require('body-parser'); -const GameManager = require('./modules/GameManager.js'); +const GameManager = require('./modules/GameManager.js'); const globals = require('./config/globals'); const ServerBootstrapper = require('./modules/ServerBootstrapper'); @@ -16,15 +16,15 @@ const args = ServerBootstrapper.processCLIArgs(); const logger = require('./modules/Logger')(args.logLevel); logger.info('LOG LEVEL IS: ' + args.logLevel); -const main = ServerBootstrapper.createServerWithCorrectHTTPProtocol(app, args.useHttps, args.port, logger) +const main = ServerBootstrapper.createServerWithCorrectHTTPProtocol(app, args.useHttps, args.port, logger); app.set('port', args.port); const inGameSocketServer = ServerBootstrapper.createSocketServer(main, app, args.port); inGameSocketServer.on('connection', function (socket) { - socket.on("disconnecting", (reason) => { - logger.trace('client socket disconnecting because: ' + reason) + socket.on('disconnecting', (reason) => { + logger.trace('client socket disconnecting because: ' + reason); gameManager.removeClientFromLobbyIfApplicable(socket); }); gameManager.addGameSocketHandlers(inGameSocketServer, socket); @@ -70,5 +70,5 @@ app.use(function (req, res) { }); main.listen(args.port, function () { - logger.info(`Starting server on port ${args.port}` ); + logger.info(`Starting server on port ${args.port}`); }); diff --git a/server/model/Game.js b/server/model/Game.js index 0e4c6f1..7a35f89 100644 --- a/server/model/Game.js +++ b/server/model/Game.js @@ -1,5 +1,5 @@ class Game { - constructor(accessCode, status, people, deck, hasTimer, moderator, timerParams=null) { + constructor (accessCode, status, people, deck, hasTimer, moderator, timerParams = null) { this.accessCode = accessCode; this.status = status; this.moderator = moderator; diff --git a/server/model/Person.js b/server/model/Person.js index 5e1eb6f..3c6afa0 100644 --- a/server/model/Person.js +++ b/server/model/Person.js @@ -1,8 +1,8 @@ // noinspection DuplicatedCode class Person { - constructor(id, cookie, name, userType, gameRole=null, gameRoleDescription=null, alignment=null, assigned=false) { + constructor (id, cookie, name, userType, gameRole = null, gameRoleDescription = null, alignment = null, assigned = false) { this.id = id; - this.cookie = cookie + this.cookie = cookie; this.socketId = null; this.name = name; this.userType = userType; diff --git a/server/modules/ActiveGameRunner.js b/server/modules/ActiveGameRunner.js index ba0d32a..66b79f8 100644 --- a/server/modules/ActiveGameRunner.js +++ b/server/modules/ActiveGameRunner.js @@ -58,7 +58,7 @@ class ActiveGameRunner { minutes: game.timerParams.minutes }); game.startTime = new Date().toJSON(); - } + }; } class Singleton { diff --git a/server/modules/GameManager.js b/server/modules/GameManager.js index 6438a62..5c36be1 100644 --- a/server/modules/GameManager.js +++ b/server/modules/GameManager.js @@ -50,7 +50,7 @@ class GameManager { }); socket.on(globals.CLIENT_COMMANDS.START_GAME, (accessCode) => { - let game = this.activeGameRunner.activeGames[accessCode]; + const game = this.activeGameRunner.activeGames[accessCode]; if (game && game.isFull) { game.status = globals.STATUS.IN_PROGRESS; if (game.hasTimer) { @@ -63,9 +63,9 @@ class GameManager { socket.on(globals.CLIENT_COMMANDS.PAUSE_TIMER, (accessCode) => { this.logger.trace(accessCode); - let game = this.activeGameRunner.activeGames[accessCode]; + const game = this.activeGameRunner.activeGames[accessCode]; if (game) { - let thread = this.activeGameRunner.timerThreads[accessCode]; + const thread = this.activeGameRunner.timerThreads[accessCode]; if (thread) { this.logger.debug('Timer thread found for game ' + accessCode); thread.send({ @@ -79,9 +79,9 @@ class GameManager { socket.on(globals.CLIENT_COMMANDS.RESUME_TIMER, (accessCode) => { this.logger.trace(accessCode); - let game = this.activeGameRunner.activeGames[accessCode]; + const game = this.activeGameRunner.activeGames[accessCode]; if (game) { - let thread = this.activeGameRunner.timerThreads[accessCode]; + const thread = this.activeGameRunner.timerThreads[accessCode]; if (thread) { this.logger.debug('Timer thread found for game ' + accessCode); thread.send({ @@ -94,9 +94,9 @@ class GameManager { }); socket.on(globals.CLIENT_COMMANDS.GET_TIME_REMAINING, (accessCode) => { - let game = this.activeGameRunner.activeGames[accessCode]; + const game = this.activeGameRunner.activeGames[accessCode]; if (game) { - let thread = this.activeGameRunner.timerThreads[accessCode]; + const thread = this.activeGameRunner.timerThreads[accessCode]; if (thread) { thread.send({ command: globals.GAME_PROCESS_COMMANDS.GET_TIME_REMAINING, @@ -113,17 +113,17 @@ class GameManager { }); socket.on(globals.CLIENT_COMMANDS.KILL_PLAYER, (accessCode, personId) => { - let game = this.activeGameRunner.activeGames[accessCode]; + const game = this.activeGameRunner.activeGames[accessCode]; if (game) { - let person = game.people.find((person) => person.id === personId) + const person = game.people.find((person) => person.id === personId); this.killPlayer(game, person, namespace, this.logger); } }); socket.on(globals.CLIENT_COMMANDS.REVEAL_PLAYER, (accessCode, personId) => { - let game = this.activeGameRunner.activeGames[accessCode]; + const game = this.activeGameRunner.activeGames[accessCode]; if (game) { - let person = game.people.find((person) => person.id === personId) + const person = game.people.find((person) => person.id === personId); if (person && !person.revealed) { this.logger.debug('game ' + accessCode + ': revealing player ' + person.name); person.revealed = true; @@ -133,51 +133,50 @@ class GameManager { id: person.id, gameRole: person.gameRole, alignment: person.alignment - }) + }); } } }); socket.on(globals.CLIENT_COMMANDS.TRANSFER_MODERATOR, (accessCode, personId) => { - let game = this.activeGameRunner.activeGames[accessCode]; + const game = this.activeGameRunner.activeGames[accessCode]; if (game) { - let person = game.people.find((person) => person.id === personId) + let person = game.people.find((person) => person.id === personId); if (!person) { - person = game.spectators.find((spectator) => spectator.id === personId) + person = game.spectators.find((spectator) => spectator.id === personId); } this.transferModeratorPowers(game, person, namespace, this.logger); } }); socket.on(globals.CLIENT_COMMANDS.CHANGE_NAME, (accessCode, data, ackFn) => { - let game = this.activeGameRunner.activeGames[accessCode]; + const game = this.activeGameRunner.activeGames[accessCode]; if (game) { - let person = findPersonById(game, data.personId); + const person = findPersonById(game, data.personId); if (person) { if (!isNameTaken(game, data.name)) { - ackFn("changed"); + ackFn('changed'); person.name = data.name.trim(); person.hasEnteredName = true; namespace.in(accessCode).emit(globals.CLIENT_COMMANDS.CHANGE_NAME, person.id, person.name); } else { - ackFn("taken"); + ackFn('taken'); } } } }); socket.on(globals.CLIENT_COMMANDS.END_GAME, (accessCode) => { - let game = this.activeGameRunner.activeGames[accessCode]; + const game = this.activeGameRunner.activeGames[accessCode]; if (game) { game.status = globals.STATUS.ENDED; - for (let person of game.people) { + for (const person of game.people) { person.revealed = true; } namespace.in(accessCode).emit(globals.CLIENT_COMMANDS.END_GAME, GameStateCurator.mapPeopleForModerator(game.people)); } - }) - } - + }); + }; createGame = (gameParams) => { const expectedKeys = ['deck', 'hasTimer', 'timerParams']; @@ -190,7 +189,7 @@ class GameManager { // to avoid excessive memory build-up, every time a game is created, check for and purge any stale games. pruneStaleGames(this.activeGameRunner.activeGames, this.activeGameRunner.timerThreads, this.logger); const newAccessCode = this.generateAccessCode(); - let moderator = initializeModerator(UsernameGenerator.generate(), gameParams.hasDedicatedModerator); + const moderator = initializeModerator(UsernameGenerator.generate(), gameParams.hasDedicatedModerator); if (gameParams.timerParams !== null) { gameParams.timerParams.paused = false; } @@ -206,12 +205,12 @@ class GameManager { this.activeGameRunner.activeGames[newAccessCode].createTime = new Date().toJSON(); return Promise.resolve(newAccessCode); } - } + }; joinGame = (code) => { - let game = this.activeGameRunner.activeGames[code]; + const game = this.activeGameRunner.activeGames[code]; if (game) { - let unassignedPerson = game.people.find((person) => person.assigned === false); + const unassignedPerson = game.people.find((person) => person.assigned === false); if (!unassignedPerson) { return Promise.resolve(new Error(globals.ERROR_MESSAGE.GAME_IS_FULL)); } else { @@ -220,7 +219,7 @@ class GameManager { } else { return Promise.resolve(404); } - } + }; generateAccessCode = () => { const numLetters = globals.ACCESS_CODE_CHAR_POOL.length; @@ -231,7 +230,7 @@ class GameManager { codeDigits.push(globals.ACCESS_CODE_CHAR_POOL[getRandomInt(numLetters)]); } return codeDigits.join(''); - } + }; transferModeratorPowers = (game, person, namespace, logger) => { if (person && (person.out || person.userType === globals.USER_TYPES.SPECTATOR)) { @@ -259,7 +258,7 @@ class GameManager { namespace.in(game.accessCode).emit(globals.EVENTS.SYNC_GAME_STATE); } - } + }; killPlayer = (game, person, namespace, logger) => { if (person && !person.out) { @@ -274,25 +273,24 @@ class GameManager { this.transferModeratorPowers(game, person, namespace, logger); } } - } + }; - - handleRequestForGameState = (namespace, logger, gameRunner, accessCode, personCookie, ackFn, socket, handleNoMatch=true) => { + handleRequestForGameState = (namespace, logger, gameRunner, accessCode, personCookie, ackFn, socket, handleNoMatch = true) => { const game = gameRunner.activeGames[accessCode]; if (game) { let matchingPerson = game.people.find((person) => person.cookie === personCookie); if (!matchingPerson) { matchingPerson = game.spectators.find((spectator) => spectator.cookie === personCookie); } - if (!matchingPerson && game.moderator.cookie === personCookie) { + if (!matchingPerson && game.moderator.cookie === personCookie) { matchingPerson = game.moderator; } if (matchingPerson) { if (matchingPerson.socketId === socket.id) { - logger.trace("matching person found with an established connection to the room: " + matchingPerson.name); + logger.trace('matching person found with an established connection to the room: ' + matchingPerson.name); ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, matchingPerson, gameRunner, socket, logger)); } else { - logger.trace("matching person found with a new connection to the room: " + matchingPerson.name); + logger.trace('matching person found with a new connection to the room: ' + matchingPerson.name); socket.join(accessCode); matchingPerson.socketId = socket.id; ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, matchingPerson, gameRunner, socket, logger)); @@ -304,23 +302,23 @@ class GameManager { rejectClientRequestForGameState(ackFn); logger.trace('the game ' + accessCode + ' was not found'); } - } + }; handleRequestFromNonMatchingPerson = (game, socket, gameRunner, ackFn, logger) => { - let personWithMatchingSocketId = findPersonWithMatchingSocketId(game, socket.id); + const personWithMatchingSocketId = findPersonWithMatchingSocketId(game, socket.id); if (personWithMatchingSocketId) { - logger.trace("matching person found whose cookie got cleared after establishing a connection to the room: " + personWithMatchingSocketId.name); + logger.trace('matching person found whose cookie got cleared after establishing a connection to the room: ' + personWithMatchingSocketId.name); ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, personWithMatchingSocketId, gameRunner, socket, logger)); } else { - let unassignedPerson = game.moderator.assigned === false + const unassignedPerson = game.moderator.assigned === false ? game.moderator : game.people.find((person) => person.assigned === false); if (unassignedPerson) { - logger.trace("completely new person with a first connection to the room: " + unassignedPerson.name); + logger.trace('completely new person with a first connection to the room: ' + unassignedPerson.name); unassignedPerson.assigned = true; unassignedPerson.socketId = socket.id; ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, unassignedPerson, gameRunner, socket, logger)); - let isFull = isGameFull(game); + const isFull = isGameFull(game); game.isFull = isFull; socket.to(game.accessCode).emit( globals.EVENTS.PLAYER_JOINED, @@ -328,29 +326,29 @@ class GameManager { isFull ); } else { // if the game is full, make them a spectator. - let spectator = new Person( + const spectator = new Person( createRandomId(), createRandomId(), UsernameGenerator.generate(), globals.USER_TYPES.SPECTATOR ); - logger.trace("new spectator: " + spectator.name); + logger.trace('new spectator: ' + spectator.name); game.spectators.push(spectator); ackFn(GameStateCurator.getGameStateFromPerspectiveOfPerson(game, spectator, gameRunner, socket, logger)); } socket.join(game.accessCode); } - } + }; - removeClientFromLobbyIfApplicable(socket) { + removeClientFromLobbyIfApplicable (socket) { socket.rooms.forEach((room) => { if (this.activeGameRunner.activeGames[room]) { this.logger.trace('disconnected socket is in a game'); - let game = this.activeGameRunner.activeGames[room]; + const game = this.activeGameRunner.activeGames[room]; if (game.status === globals.STATUS.LOBBY) { - let matchingPlayer = findPlayerBySocketId(game.people, socket.id); + const matchingPlayer = findPlayerBySocketId(game.people, socket.id); if (matchingPlayer) { - this.logger.trace("un-assigning disconnected player: " + matchingPlayer.name); + this.logger.trace('un-assigning disconnected player: ' + matchingPlayer.name); matchingPlayer.assigned = false; matchingPlayer.socketId = null; matchingPlayer.cookie = createRandomId(); @@ -364,7 +362,7 @@ class GameManager { } } } - }) + }); } } @@ -372,21 +370,21 @@ function getRandomInt (max) { return Math.floor(Math.random() * Math.floor(max)); } -function initializeModerator(name, hasDedicatedModerator) { +function initializeModerator (name, hasDedicatedModerator) { const userType = hasDedicatedModerator ? globals.USER_TYPES.MODERATOR : globals.USER_TYPES.TEMPORARY_MODERATOR; - return new Person(createRandomId(), createRandomId(), name, userType);; + return new Person(createRandomId(), createRandomId(), name, userType); ; } -function initializePeopleForGame(uniqueCards, moderator) { - let people = []; +function initializePeopleForGame (uniqueCards, moderator) { + const people = []; let cards = []; // this will contain copies of each card equal to the quantity. let numberOfRoles = 0; - for (let card of uniqueCards) { - for (let i = 0; i < card.quantity; i ++) { + for (const card of uniqueCards) { + for (let i = 0; i < card.quantity; i++) { cards.push(card); - numberOfRoles ++; + numberOfRoles++; } } @@ -399,11 +397,11 @@ function initializePeopleForGame(uniqueCards, moderator) { moderator.gameRoleDescription = cards[j].description; moderator.alignment = cards[j].team; people.push(moderator); - j ++; + j++; } while (j < numberOfRoles) { - let person = new Person( + const person = new Person( createRandomId(), createRandomId(), UsernameGenerator.generate(), @@ -415,7 +413,7 @@ function initializePeopleForGame(uniqueCards, moderator) { person.customRole = cards[j].custom; person.hasEnteredName = false; people.push(person); - j ++; + j++; } return people; @@ -439,11 +437,11 @@ function createRandomId () { return id; } -function rejectClientRequestForGameState(acknowledgementFunction) { +function rejectClientRequestForGameState (acknowledgementFunction) { return acknowledgementFunction(null); } -function findPersonWithMatchingSocketId(game, socketId) { +function findPersonWithMatchingSocketId (game, socketId) { let person = game.people.find((person) => person.socketId === socketId); if (!person) { person = game.spectators.find((spectator) => spectator.socketId === socketId); @@ -454,15 +452,15 @@ function findPersonWithMatchingSocketId(game, socketId) { return person; } -function findPlayerBySocketId(people, socketId) { +function findPlayerBySocketId (people, socketId) { return people.find((person) => person.socketId === socketId && person.userType === globals.USER_TYPES.PLAYER); } -function isGameFull(game) { +function isGameFull (game) { return game.moderator.assigned === true && !game.people.find((person) => person.assigned === false); } -function findPersonById(game, id) { +function findPersonById (game, id) { let person; if (id === game.moderator.id) { person = game.moderator; @@ -471,22 +469,22 @@ function findPersonById(game, id) { person = game.people.find((person) => person.id === id); } if (!person) { - person = game.spectators.find((spectator) => spectator.id === id) + person = game.spectators.find((spectator) => spectator.id === id); } return person; } -function isNameTaken(game, name) { - let processedName = name.toLowerCase().trim(); +function isNameTaken (game, name) { + const processedName = name.toLowerCase().trim(); return (game.people.find((person) => person.name.toLowerCase().trim() === processedName)) || (game.moderator.name.toLowerCase().trim() === processedName) - || (game.spectators.find((spectator) => spectator.name.toLowerCase().trim() === processedName)) + || (game.spectators.find((spectator) => spectator.name.toLowerCase().trim() === processedName)); } -function pruneStaleGames(activeGames, timerThreads, logger) { +function pruneStaleGames (activeGames, timerThreads, logger) { for (const [accessCode, game] of Object.entries(activeGames)) { if (game.createTime) { - let createDate = new Date(game.createTime); + const createDate = new Date(game.createTime); if (createDate.setHours(createDate.getHours() + globals.STALE_GAME_HOURS) < Date.now()) { // clear games created more than 12 hours ago logger.info('PRUNING STALE GAME ' + accessCode); delete activeGames[accessCode]; @@ -513,5 +511,4 @@ class Singleton { } } - module.exports = Singleton; diff --git a/server/modules/GameProcess.js b/server/modules/GameProcess.js index bf1227c..dd44e5e 100644 --- a/server/modules/GameProcess.js +++ b/server/modules/GameProcess.js @@ -24,7 +24,7 @@ process.on('message', (msg) => { case globals.GAME_PROCESS_COMMANDS.PAUSE_TIMER: timer.stopTimer(); logger.trace('CHILD PROCESS ' + msg.accessCode + ': PAUSE TIMER'); - process.send({ command: globals.GAME_PROCESS_COMMANDS.PAUSE_TIMER, timeRemaining: timer.currentTimeInMillis}); + process.send({ command: globals.GAME_PROCESS_COMMANDS.PAUSE_TIMER, timeRemaining: timer.currentTimeInMillis }); break; @@ -35,7 +35,7 @@ process.on('message', (msg) => { process.exit(0); }); logger.trace('CHILD PROCESS ' + msg.accessCode + ': RESUME TIMER'); - process.send({ command: globals.GAME_PROCESS_COMMANDS.RESUME_TIMER, timeRemaining: timer.currentTimeInMillis}); + process.send({ command: globals.GAME_PROCESS_COMMANDS.RESUME_TIMER, timeRemaining: timer.currentTimeInMillis }); break; @@ -50,4 +50,3 @@ process.on('message', (msg) => { break; } }); - diff --git a/server/modules/GameStateCurator.js b/server/modules/GameStateCurator.js index 74859f7..8d24ceb 100644 --- a/server/modules/GameStateCurator.js +++ b/server/modules/GameStateCurator.js @@ -1,4 +1,4 @@ -const globals = require("../config/globals") +const globals = require('../config/globals'); /* The purpose of this component is to only return the game state information that is necessary. For example, we only want to return player role information to moderators. This avoids any possibility of a player having access to @@ -12,7 +12,7 @@ const GameStateCurator = { mapPeopleForModerator: (people) => { return people .filter((person) => { - return person.assigned === true + return person.assigned === true; }) .map((person) => ({ name: person.name, @@ -40,10 +40,10 @@ const GameStateCurator = { return { name: person.name, id: person.id, userType: person.userType, out: person.out, revealed: person.revealed }; } } -} +}; -function getGameStateBasedOnPermissions(game, person, gameRunner) { - let client = game.status === globals.STATUS.LOBBY // people won't be able to know their role until past the lobby stage. +function getGameStateBasedOnPermissions (game, person, gameRunner) { + const client = game.status === globals.STATUS.LOBBY // people won't be able to know their role until past the lobby stage. ? { name: person.name, hasEnteredName: person.hasEnteredName, id: person.id, cookie: person.cookie, userType: person.userType } : { name: person.name, @@ -56,11 +56,11 @@ function getGameStateBasedOnPermissions(game, person, gameRunner) { customRole: person.customRole, alignment: person.alignment, out: person.out - } + }; switch (person.userType) { case globals.USER_TYPES.PLAYER: - case globals.USER_TYPES.KILLED_PLAYER: - let state = { + case globals.USER_TYPES.KILLED_PLAYER: { + const state = { accessCode: game.accessCode, status: game.status, moderator: GameStateCurator.mapPerson(game.moderator), @@ -68,18 +68,19 @@ function getGameStateBasedOnPermissions(game, person, gameRunner) { deck: game.deck, people: game.people .filter((person) => { - return person.assigned === true + return person.assigned === true; }) .map((filteredPerson) => GameStateCurator.mapPerson(filteredPerson) ), timerParams: game.timerParams, - isFull: game.isFull, - } + isFull: game.isFull + }; if (game.status === globals.STATUS.ENDED) { state.people = GameStateCurator.mapPeopleForModerator(game.people); } return state; + } case globals.USER_TYPES.MODERATOR: return { accessCode: game.accessCode, @@ -91,7 +92,7 @@ function getGameStateBasedOnPermissions(game, person, gameRunner) { timerParams: game.timerParams, isFull: game.isFull, spectators: game.spectators - } + }; case globals.USER_TYPES.TEMPORARY_MODERATOR: return { accessCode: game.accessCode, @@ -101,12 +102,12 @@ function getGameStateBasedOnPermissions(game, person, gameRunner) { deck: game.deck, people: game.people .filter((person) => { - return person.assigned === true + return person.assigned === true; }) .map((filteredPerson) => GameStateCurator.mapPerson(filteredPerson)), timerParams: game.timerParams, isFull: game.isFull - } + }; case globals.USER_TYPES.SPECTATOR: return { accessCode: game.accessCode, @@ -116,12 +117,12 @@ function getGameStateBasedOnPermissions(game, person, gameRunner) { deck: game.deck, people: game.people .filter((person) => { - return person.assigned === true + return person.assigned === true; }) .map((filteredPerson) => GameStateCurator.mapPerson(filteredPerson)), timerParams: game.timerParams, - isFull: game.isFull, - } + isFull: game.isFull + }; default: break; } diff --git a/server/modules/Logger.js b/server/modules/Logger.js index 49429be..80d5d96 100644 --- a/server/modules/Logger.js +++ b/server/modules/Logger.js @@ -31,7 +31,7 @@ module.exports = function (logLevel = globals.LOG_LEVEL.INFO) { console.debug('DEBUG ', now.toGMTString(), ': ', message); }, - trace(message = '') { + trace (message = '') { if ( logLevel === globals.LOG_LEVEL.INFO || logLevel === globals.LOG_LEVEL.WARN diff --git a/server/modules/ServerBootstrapper.js b/server/modules/ServerBootstrapper.js index a946de3..a59f3cb 100644 --- a/server/modules/ServerBootstrapper.js +++ b/server/modules/ServerBootstrapper.js @@ -3,12 +3,12 @@ const http = require('http'); const https = require('https'); const path = require('path'); const fs = require('fs'); -const cors = require('cors') +const cors = require('cors'); const ServerBootstrapper = { processCLIArgs: () => { try { - let args = Array.from(process.argv.map((arg) => arg.trim().toLowerCase())); + const args = Array.from(process.argv.map((arg) => arg.trim().toLowerCase())); const useHttps = args.includes('protocol=https'); const port = process.env.PORT || args .filter((arg) => { @@ -31,7 +31,7 @@ const ServerBootstrapper = { logLevel: logLevel }; } catch (e) { - throw new Error("Your server run command is malformed. Consult the codebase wiki for proper usage. Error: " + e); + throw new Error('Your server run command is malformed. Consult the codebase wiki for proper usage. Error: ' + e); } }, @@ -67,40 +67,40 @@ const ServerBootstrapper = { let io; if (process.env.NODE_ENV.trim() === 'development') { const corsOptions = { - origin: "http://localhost:" + port, + origin: 'http://localhost:' + port, optionsSuccessStatus: 200, - methods: ["GET", "POST"] - } + methods: ['GET', 'POST'] + }; app.use(cors(corsOptions)); - io = require("socket.io")(main, { + io = require('socket.io')(main, { cors: { - origin: "http://localhost:" + port, - methods: ["GET", "POST"], - allowedHeaders: ["Content-Type", "X-Requested-With", "Accept"], + origin: 'http://localhost:' + port, + methods: ['GET', 'POST'], + allowedHeaders: ['Content-Type', 'X-Requested-With', 'Accept'], credentials: false } }); } else { const corsOptions = { - origin: ["https://playwerewolf.uk.r.appspot.com"], - methods: ["GET", "POST"], - allowedHeaders: ["Content-Type", "X-Requested-With", "Accept"], - optionsSuccessStatus: 200, - } + origin: ['https://playwerewolf.uk.r.appspot.com'], + methods: ['GET', 'POST'], + allowedHeaders: ['Content-Type', 'X-Requested-With', 'Accept'], + optionsSuccessStatus: 200 + }; app.use(cors(corsOptions)); - io = require("socket.io")(main, { + io = require('socket.io')(main, { cors: { - origin: ["https://playwerewolf.uk.r.appspot.com", "wss://playwerewolf.uk.r.appspot.com"], - methods: ["GET", "POST"], - allowedHeaders: ["Content-Type", "X-Requested-With", "Accept"], + origin: ['https://playwerewolf.uk.r.appspot.com', 'wss://playwerewolf.uk.r.appspot.com'], + methods: ['GET', 'POST'], + allowedHeaders: ['Content-Type', 'X-Requested-With', 'Accept'], credentials: true }, - transports: ["polling"] + transports: ['polling'] }); } return io.of('/in-game'); } -} +}; module.exports = ServerBootstrapper; diff --git a/server/modules/ServerTimer.js b/server/modules/ServerTimer.js index 603a93d..ad29705 100644 --- a/server/modules/ServerTimer.js +++ b/server/modules/ServerTimer.js @@ -4,8 +4,8 @@ function stepFn (serverTimerInstance, expected) { serverTimerInstance.currentTimeInMillis = serverTimerInstance.totalTime - (now - serverTimerInstance.start); if (now - serverTimerInstance.start >= serverTimerInstance.totalTime) { // check if the time has elapsed serverTimerInstance.logger.debug( - 'ELAPSED: ' + (now - serverTimerInstance.start) + 'ms (~' - + (Math.abs(serverTimerInstance.totalTime - (now - serverTimerInstance.start)) / serverTimerInstance.totalTime).toFixed(3) + '% error).' + 'ELAPSED: ' + (now - serverTimerInstance.start) + 'ms (~' + + (Math.abs(serverTimerInstance.totalTime - (now - serverTimerInstance.start)) / serverTimerInstance.totalTime).toFixed(3) + '% error).' ); serverTimerInstance.timesUpResolver(); // this is a reference to the callback defined in the construction of the promise in runTimer() clearTimeout(serverTimerInstance.ticking); @@ -22,7 +22,6 @@ function stepFn (serverTimerInstance, expected) { } class ServerTimer { - constructor (hours, minutes, tickInterval, logger) { this.hours = hours; this.minutes = minutes; @@ -36,8 +35,8 @@ class ServerTimer { this.totalTime = null; } - runTimer (pausedInitially=true) { - let total = convertFromHoursToMilliseconds(this.hours) + convertFromMinutesToMilliseconds(this.minutes); + runTimer (pausedInitially = true) { + const total = convertFromHoursToMilliseconds(this.hours) + convertFromMinutesToMilliseconds(this.minutes); this.totalTime = total; this.currentTimeInMillis = total; this.logger.debug('STARTING TIMER FOR ' + this.totalTime + 'ms'); @@ -59,14 +58,13 @@ class ServerTimer { return this.timesUpPromise; } - stopTimer() { + stopTimer () { if (this.ticking) { clearTimeout(this.ticking); } - let now = Date.now(); } - resumeTimer() { + resumeTimer () { this.logger.debug('RESUMING TIMER FOR ' + this.currentTimeInMillis + 'ms'); this.start = Date.now(); this.totalTime = this.currentTimeInMillis; @@ -83,11 +81,11 @@ class ServerTimer { } } -function convertFromMinutesToMilliseconds(minutes) { +function convertFromMinutesToMilliseconds (minutes) { return minutes * 60 * 1000; } -function convertFromHoursToMilliseconds(hours) { +function convertFromHoursToMilliseconds (hours) { return hours * 60 * 60 * 1000; } diff --git a/server/modules/UsernameGenerator.js b/server/modules/UsernameGenerator.js index 498c202..81a839a 100644 --- a/server/modules/UsernameGenerator.js +++ b/server/modules/UsernameGenerator.js @@ -3,9 +3,9 @@ const usernameGenerator = { const randAdjIndex = Math.floor(Math.random() * adjectives.length); const randAnimalIndex = Math.floor(Math.random() * animals.length); const randNumber = Math.floor(Math.random() * 100); - return adjectives[randAdjIndex].charAt(0).toUpperCase() + adjectives[randAdjIndex].slice(1) - + animals[randAnimalIndex].replace(/ /g, '') - + randNumber; + return adjectives[randAdjIndex].charAt(0).toUpperCase() + adjectives[randAdjIndex].slice(1) + + animals[randAnimalIndex].replace(/ /g, '') + + randNumber; } }; diff --git a/server/routes/router.js b/server/routes/router.js index d60c298..9ec2a57 100644 --- a/server/routes/router.js +++ b/server/routes/router.js @@ -26,5 +26,4 @@ router.get('/readiness_check', (req, res) => { res.sendStatus(200); }); - module.exports = router; diff --git a/server/routes/util.js b/server/routes/util.js index 56b38c7..4d1626f 100644 --- a/server/routes/util.js +++ b/server/routes/util.js @@ -1,9 +1,9 @@ const fs = require('fs'); -function checkIfFileExists(file) { +function checkIfFileExists (file) { return fs.promises.access(file, fs.constants.F_OK) .then(() => true) - .catch((e) => { console.error(e); return false }); + .catch((e) => { console.error(e); return false; }); } module.exports = checkIfFileExists;