toggleVisible("newGame");
}
+let lastAliases = [];
+function replaceAliases() {
+ for (const k of lastAliases)
+ delete window[k];
+ for (const [k, v] of Object.entries(V.Aliases))
+ window[k] = v;
+ lastAliases = Object.keys(V.Aliases);
+}
+
// Play with a friend (or not ^^)
function showNewGameForm() {
const vname = $.getElementById("selectVariant").value;
toggleVisible("newGameForm");
import(`/variants/${vname}/class.js`).then(module => {
window.V = module.default;
- for (const [k, v] of Object.entries(V.Aliases))
- window[k] = v;
+ replaceAliases();
prepareOptions();
});
}
}
-function backToNormalSeek() { //TODO: index.html......
+function backToNormalSeek() {
toggleVisible("newGame");
}
}
}
-function prepareOptions() {
- options = {};
- let optHtml = "";
- if (V.Options.select) {
- optHtml += V.Options.select.map(select => { return `
- <div class="option-select">
- <label for="var_${select.variable}">${select.label}</label>
- <div class="select">
- <select id="var_${select.variable}">` +
- select.options.map(option => { return `
- <option
- value="${option.value}"
- ${option.value == select.defaut ? " selected" : ""}
- >
- ${option.label}
- </option>`;
- }).join("") + `
- </select>
- <span class="focus"></span>
- </div>
- </div>`;
- }).join("");
- }
- if (V.Options.input) {
- optHtml += V.Options.input.map(input => { return `
- <div class="option-input">
- <label class="input">
- <input id="var_${input.variable}"
- type="${input.type}"
- ${input.type == "checkbox" && input.defaut
- ? "checked"
- : 'value="' + input.defaut + '"'}
- />
- <span class="spacer"></span>
- <span>${input.label}</span>
- </label>
- </div>`;
- }).join("");
- }
- if (V.Options.styles) {
- optHtml += '<div class="words">';
- let i = 0;
- const stylesLength = V.Options.styles.length;
- while (i < stylesLength) {
- optHtml += '<div class="row">';
- for (let j=i; j<i+4; j++) {
- if (j == stylesLength)
- break;
- const style = V.Options.styles[j];
- optHtml += `<span onClick="toggleStyle(event, this)">${style}</span>`;
- }
- optHtml += "</div>";
- i += 4;
- }
- optHtml += "</div>";
- }
- $.getElementById("gameOptions").innerHTML = optHtml;
-}
-
function getGameLink() {
const vname = $.getElementById("selectVariant").value;
const color = $.getElementById("selectColor").value;
});
}
-
-
-
function fillGameInfos(gameInfos, oppIndex) {
fetch(`/variants/${gameInfos.vname}/rules.html`)
.then(res => res.text())
.then(txt => {
const container = $.getElementById("gameInfos");
- container.innerHTML = ""; // Nettoyage initial
+ container.innerHTML = ""; //initial cleaning
- // 1. Infos Joueurs
+ // 1. Players infos
const playerDiv = h('div', { class: 'players-info' }, [
h('p', null, [
h('span', { class: 'bold', textContent: gameInfos.vdisp }),
])
]);
- // 2. Traitement des Options (Filtrage + Groupement par 4)
+ // 2. Options treatment (Filtering + Group by 4)
const optionsInfos = h('div', { class: 'options-info' });
- const activeOptions = Object.entries(gameInfos.options).filter(opt => !!opt[1]);
+ const activeOptions =
+ Object.entries(gameInfos.options).filter(opt => !!opt[1]);
let i = 0;
while (i < activeOptions.length) {
i += 4;
}
- // 3. Règles (on garde innerHTML ici car le HTML vient de ton fichier local rules.html)
+ // 3. Rules (keeping innerHTML here because trusted from file rules.html)
const rulesDiv = h('div', { class: 'rules' });
rulesDiv.innerHTML = txt;
- // 4. Bouton de retour
+ // 4. Game infos button
const btnWrap = h('div', { class: 'btn-wrap' }, [
- h('button', {
- onclick: toggleGameInfos,
- textContent: "Back to game"
+ h('button', {
+ onclick: toggleGameInfos,
+ textContent: "Back to game"
})
]);
- // Assemblage final
+ // Final assembling
container.append(
- playerDiv,
- activeOptions.length > 0 ? optionsInfos : null,
- rulesDiv,
+ playerDiv,
+ activeOptions.length > 0 ? optionsInfos : null,
+ rulesDiv,
btnWrap
);
});
}
-
-
-function fillGameInfos(gameInfos, oppIndex) {
- fetch(`/variants/${gameInfos.vname}/rules.html`)
- .then(res => res.text())
- .then(txt => {
- let htmlContent = `
- <div class="players-info">
- <p>
- <span class="bold">${gameInfos.vdisp}</span>
- <span>vs. ${gameInfos.players[oppIndex].name}</span>
- </p>
- </div>`;
- const _options = Object.entries(gameInfos.options);
- if (_options.length > 0) {
- htmlContent += '<div class="options-info">';
- let i = 0;
- while (i < _options.length) {
- htmlContent += '<div class="row">';
- for (let j=i; j<i+4; j++) {
- if (j == _options.length)
- break;
- const opt = _options[j];
- if (!opt[1]) //includes 0 and false (lighter display)
- continue;
- htmlContent +=
- '<span class="option">' +
- (opt[1] === true ? opt[0] : `${opt[0]}:${opt[1]}`) + " " +
- "</span>";
- }
- htmlContent += "</div>";
- i += 4;
- }
- htmlContent += "</div>";
- }
- htmlContent += `
- <div class="rules">${txt}</div>
- <div class="btn-wrap">
- <button onClick="toggleGameInfos()">Back to game</button>
- </div>`;
- $.getElementById("gameInfos").innerHTML = htmlContent;
- });
-}
-
////////////////
// Communication
// Game vs. friend just created on server: share link now
case "gamecreated": {
const link = `${Params.http_server}/#${obj.gid}`;
- $.getElementById("gameLink").innerHTML = `
- <p>
- <a href="${getWhatsApp(link)}">WhatsApp</a>
- /
- <span onClick="copyClipboard('${link}')">ToClipboard</span>
- </p>
- <p>${link}</p>
- `;
+ const container = $.getElementById("gameLink");
+ container.innerHTML = ""; //emptying
+ container.append(
+ h('p', null, [
+ h('a', { href: getWhatsApp(link), textContent: "WhatsApp" }),
+ " / ",
+ h('span', {
+ onclick: () => copyClipboard(link),
+ textContent: "ToClipboard",
+ //style: "cursor:pointer; text-decoration:underline"
+ })
+ ]),
+ h('p', { textContent: link })
+ );
break;
}
// Game vs. friend joined after 1 minute (try again!)
}
};
-
-
-
-
-
-
+let vr = null, playerColor, lastVname = undefined;
function initializeGame(obj) {
- const container = $.getElementById("boardContainer");
- container.innerHTML = ""; // Nettoyage
+ const options = obj.options || {};
- // Créer les boutons de contrôle proprement
- const infoBtn = createSVGButton("upLeftInfos", toggleGameInfos);
- const stopBtn = createSVGButton("upRightStop", confirmStopGame);
- const board = $.createElement("div");
- board.className = "chessboard";
+ // 1. Dynamic loading of variant js module
+ import(`/variants/${obj.vname}/class.js`).then(module => {
+ window.V = module.default;
- container.append(infoBtn, stopBtn, board);
+ // Export aliases in global scope (used by variants classes)
+ replaceAliases();
+ // 2. Dynamic management of CSS (Unload old / Load new)
+ if (lastVname !== obj.vname) {
+ if (lastVname) {
+ const oldCss = $.getElementById(`${lastVname}_css`);
+ if (oldCss)
+ oldCss.remove();
+ }
+ $.head.append(
+ h('link', {
+ id: `${obj.vname}_css`,
+ rel: 'stylesheet',
+ href: `/variants/${obj.vname}/style.css`
+ })
+ );
+ lastVname = obj.vname;
+ }
+ playerColor = (sid == obj.players[0].sid ? 'w' : 'b');
+ // 3. Building Board Container
+ const container = $.getElementById("boardContainer");
+ container.innerHTML = ""; // On vide proprement l'ancien plateau
+ // Create SVG icons with a string, inserted securely.
+ const infoIcon = h('div', { id: 'upLeftInfos', onclick: toggleGameInfos });
+ infoIcon.innerHTML = `<svg viewBox="0.5 0.5 100 100"><path d="M50.5,0.5c-27.614,0-50,22.386-50,50c0,27.614,22.386,50,50,50s50-22.386,50-50C100.5,22.886,78.114,0.5,50.5,0.5z M60.5,85.5h-20v-40h20V85.5z M50.5,35.5c-5.523,0-10-4.477-10-10s4.477-10,10-10c5.522,0,10,4.477,10,10S56.022,35.5,50.5,35.5z"/></svg>`;
+ const stopIcon = h('div', { id: 'upRightStop', onclick: confirmStopGame });
+ stopIcon.innerHTML = `<svg viewBox="0 0 533.333 533.333"><path d="M528.468,428.468c-0.002-0.002-0.004-0.004-0.006-0.005L366.667,266.666l161.795-161.797c0.002-0.002,0.004-0.003,0.006-0.005c1.741-1.742,3.001-3.778,3.809-5.946c2.211-5.925,0.95-12.855-3.814-17.62l-76.431-76.43 c-4.765-4.763-11.694-6.024-17.619-3.812c-2.167,0.807-4.203,2.066-5.946,3.807L266.667,166.666 L104.87,4.869c-5.945-3.807-92.993-1.156-81.3,4.869 L4.869,81.3c-4.764,4.765-6.024,11.694-3.813,17.619l161.797,161.796L4.869,428.464c3.813,17.619,81.3,528.464,98.92,532.277c161.796-161.797l161.795,161.797c5.927,2.212,17.619-3.813l76.43-76.432c3.815-17.62 C531.469,432.246,528.468,428.468z"/></svg>`;
+ const board = h('div', { class: 'chessboard' });
-let vr = null, playerColor, lastVname = undefined;
-function initializeGame(obj) {
- const options = obj.options || {};
- import(`/variants/${obj.vname}/class.js`).then(module => {
- window.V = module.default;
- for (const [k, v] of Object.entries(V.Aliases))
- window[k] = v;
- if (lastVname != obj.vname) {
- // Load CSS + unload potential previous one.
- if (lastVname)
- document.getElementById(lastVname + "_css").remove();
- $.getElementsByTagName("head")[0].insertAdjacentHTML(
- "beforeend",
- `<link id="${obj.vname + '_css'}" rel="stylesheet"
- href="/variants/${obj.vname}/style.css"/>`);
- lastVname = obj.vname;
- }
- playerColor = (sid == obj.players[0].sid ? "w" : "b");
- // Init + remove potential extra DOM elements from a previous game:
- document.getElementById("boardContainer").innerHTML = `
- <div id="upLeftInfos"
- onClick="toggleGameInfos()">
- <svg version="1.1"
- viewBox="0.5 0.5 100 100">
- <g>
- <path d="M50.5,0.5c-27.614,0-50,22.386-50,50c0,27.614,22.386,50,50,50s50-22.386,50-50C100.5,22.886,78.114,0.5,50.5,0.5z M60.5,85.5h-20v-40h20V85.5z M50.5,35.5c-5.523,0-10-4.477-10-10s4.477-10,10-10c5.522,0,10,4.477,10,10S56.022,35.5,50.5,35.5z"/>
- </g>
- </svg>
- </div>
- <div id="upRightStop"
- onClick="confirmStopGame()">
- <svg version="1.1"
- viewBox="0 0 533.333 533.333">
- <g>
- <path d="M528.468,428.468c-0.002-0.002-0.004-0.004-0.006-0.005L366.667,266.666l161.795-161.797 c0.002-0.002,0.004-0.003,0.006-0.005c1.741-1.742,3.001-3.778,3.809-5.946c2.211-5.925,0.95-12.855-3.814-17.62l-76.431-76.43 c-4.765-4.763-11.694-6.024-17.619-3.812c-2.167,0.807-4.203,2.066-5.946,3.807c0,0.002-0.002,0.003-0.005,0.005L266.667,166.666 L104.87,4.869c-0.002-0.002-0.003-0.003-0.005-0.005c-1.743-1.74-3.778-3-5.945-3.807C92.993-1.156,86.065,0.105,81.3,4.869 L4.869,81.3c-4.764,4.765-6.024,11.694-3.813,17.619c0.808,2.167,2.067,4.205,3.808,5.946c0.002,0.001,0.003,0.003,0.005,0.005 l161.797,161.796L4.869,428.464c-0.001,0.002-0.003,0.003-0.004,0.005c-1.741,1.742-3,3.778-3.809,5.945 c-2.212,5.924-0.951,12.854,3.813,17.619L81.3,528.464c4.766,4.765,11.694,6.025,17.62,3.813c2.167-0.809,4.203-2.068,5.946-3.809 c0.001-0.002,0.003-0.003,0.005-0.005l161.796-161.797l161.795,161.797c0.003,0.001,0.005,0.003,0.007,0.004 c1.743,1.741,3.778,3.001,5.944,3.81c5.927,2.212,12.856,0.951,17.619-3.813l76.43-76.432c4.766-4.765,6.026-11.696,3.815-17.62 C531.469,432.246,530.209,430.21,528.468,428.468z"/>
- </g>
- </svg>
- </div>
- <div class="chessboard"></div>`;
+ container.append(infoIcon, stopIcon, board);
+
+ // 4. Initialize game engine (vr)
if (vr)
- // Avoid interferences:
vr.removeListeners();
+
vr = new V({
- seed: obj.seed, //may be null if FEN already exists (running game)
+ seed: obj.seed,
fen: obj.fen,
element: "boardContainer",
color: playerColor,
afterPlay: afterPlay,
options: options
});
+
+ // 5. Handling game state
const gameCreation = !obj.fen;
if (gameCreation) {
- // Both players set FEN, in case of one is offline
- send("setfen", {gid: obj.gid, fen: vr.getFen()});
+ send("setfen", { gid: obj.gid, fen: vr.getFen() });
localStorage.setItem("gid", obj.gid);
}
- const select = $.getElementById("selectVariant");
- obj.vdisp = "";
- for (let i=0; i<select.options.length; i++) {
- if (select.options[i].value == obj.vname) {
- obj.vdisp = select.options[i].text;
- break;
- }
- }
+
+ // 6. Update variant's informations (vdisp)
+ const variantOption = Array.from($.getElementById("selectVariant").options)
+ .find(opt => opt.value === obj.vname);
+ obj.vdisp = variantOption ? variantOption.text : obj.vname;
+
const playerIndex = (playerColor == "w" ? 0 : 1);
fillGameInfos(obj, 1 - playerIndex);
- if (obj.players[playerIndex].randvar && gameCreation)
+
+ // 7. Final output
+ if (obj.players[playerIndex].randvar && gameCreation) {
toggleVisible("gameInfos");
+ }
else
toggleVisible("boardContainer");
+
toggleTurnIndicator(vr.turn == playerColor);
});
}
"ws": "^7.5.3"
},
"devDependencies": {
- "chokidar": "^3.5.3"
+ "chokidar": "^3.5.3",
+ "nodemon": "^3.1.14"
}
},
"node_modules/anymatch": {
"node": ">= 8"
}
},
+ "node_modules/balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
"node_modules/binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"node": ">=8"
}
},
+ "node_modules/brace-expansion": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+ "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "balanced-match": "^4.0.2"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ }
+ },
"node_modules/braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"fsevents": "~2.3.2"
}
},
+ "node_modules/debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ms": "^2.1.3"
+ },
+ "engines": {
+ "node": ">=6.0"
+ },
+ "peerDependenciesMeta": {
+ "supports-color": {
+ "optional": true
+ }
+ }
+ },
"node_modules/fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"node": ">= 6"
}
},
+ "node_modules/has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true,
+ "license": "ISC"
+ },
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"node": ">=0.12.0"
}
},
+ "node_modules/minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "license": "BlueOak-1.0.0",
+ "dependencies": {
+ "brace-expansion": "^5.0.5"
+ },
+ "engines": {
+ "node": "18 || 20 || >=22"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/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,
+ "license": "MIT"
+ },
+ "node_modules/nodemon": {
+ "version": "3.1.14",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz",
+ "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "chokidar": "^3.5.2",
+ "debug": "^4",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^10.2.1",
+ "pstree.remy": "^1.1.8",
+ "semver": "^7.5.3",
+ "simple-update-notifier": "^2.0.0",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ },
+ "bin": {
+ "nodemon": "bin/nodemon.js"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/nodemon"
+ }
+ },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
}
},
"node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
"dev": true,
+ "license": "MIT",
"engines": {
"node": ">=8.6"
},
"url": "https://github.com/sponsors/jonschlinkert"
}
},
+ "node_modules/pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/readdirp": {
"version": "3.6.0",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
"node": ">=8.10.0"
}
},
+ "node_modules/semver": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "semver": "bin/semver.js"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/simple-update-notifier": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+ "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "semver": "^7.5.3"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "has-flag": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=4"
+ }
+ },
"node_modules/to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"node": ">=8.0"
}
},
+ "node_modules/touch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
+ "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
+ "dev": true,
+ "license": "ISC",
+ "bin": {
+ "nodetouch": "bin/nodetouch.js"
+ }
+ },
+ "node_modules/undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",
"picomatch": "^2.0.4"
}
},
+ "balanced-match": {
+ "version": "4.0.4",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-4.0.4.tgz",
+ "integrity": "sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==",
+ "dev": true
+ },
"binary-extensions": {
"version": "2.2.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
"integrity": "sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==",
"dev": true
},
+ "brace-expansion": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-5.0.5.tgz",
+ "integrity": "sha512-VZznLgtwhn+Mact9tfiwx64fA9erHH/MCXEUfB/0bX/6Fz6ny5EGTXYltMocqg4xFAQZtnO3DHWWXi8RiuN7cQ==",
+ "dev": true,
+ "requires": {
+ "balanced-match": "^4.0.2"
+ }
+ },
"braces": {
"version": "3.0.3",
"resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
"readdirp": "~3.6.0"
}
},
+ "debug": {
+ "version": "4.4.3",
+ "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz",
+ "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==",
+ "dev": true,
+ "requires": {
+ "ms": "^2.1.3"
+ }
+ },
"fill-range": {
"version": "7.1.1",
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
"is-glob": "^4.0.1"
}
},
+ "has-flag": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
+ "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
+ "dev": true
+ },
+ "ignore-by-default": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/ignore-by-default/-/ignore-by-default-1.0.1.tgz",
+ "integrity": "sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==",
+ "dev": true
+ },
"is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
"dev": true
},
+ "minimatch": {
+ "version": "10.2.5",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.2.5.tgz",
+ "integrity": "sha512-MULkVLfKGYDFYejP07QOurDLLQpcjk7Fw+7jXS2R2czRQzR56yHRveU5NDJEOviH+hETZKSkIk5c+T23GjFUMg==",
+ "dev": true,
+ "requires": {
+ "brace-expansion": "^5.0.5"
+ }
+ },
+ "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
+ },
+ "nodemon": {
+ "version": "3.1.14",
+ "resolved": "https://registry.npmjs.org/nodemon/-/nodemon-3.1.14.tgz",
+ "integrity": "sha512-jakjZi93UtB3jHMWsXL68FXSAosbLfY0In5gtKq3niLSkrWznrVBzXFNOEMJUfc9+Ke7SHWoAZsiMkNP3vq6Jw==",
+ "dev": true,
+ "requires": {
+ "chokidar": "^3.5.2",
+ "debug": "^4",
+ "ignore-by-default": "^1.0.1",
+ "minimatch": "^10.2.1",
+ "pstree.remy": "^1.1.8",
+ "semver": "^7.5.3",
+ "simple-update-notifier": "^2.0.0",
+ "supports-color": "^5.5.0",
+ "touch": "^3.1.0",
+ "undefsafe": "^2.0.5"
+ }
+ },
"normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"dev": true
},
"picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "version": "2.3.2",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.2.tgz",
+ "integrity": "sha512-V7+vQEJ06Z+c5tSye8S+nHUfI51xoXIXjHQ99cQtKUkQqqO1kO/KCJUfZXuB47h/YBlDhah2H3hdUGXn8ie0oA==",
+ "dev": true
+ },
+ "pstree.remy": {
+ "version": "1.1.8",
+ "resolved": "https://registry.npmjs.org/pstree.remy/-/pstree.remy-1.1.8.tgz",
+ "integrity": "sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==",
"dev": true
},
"readdirp": {
"picomatch": "^2.2.1"
}
},
+ "semver": {
+ "version": "7.7.4",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-7.7.4.tgz",
+ "integrity": "sha512-vFKC2IEtQnVhpT78h1Yp8wzwrf8CM+MzKMHGJZfBtzhZNycRFnXsHk6E5TxIkkMsgNS7mdX3AGB7x2QM2di4lA==",
+ "dev": true
+ },
+ "simple-update-notifier": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/simple-update-notifier/-/simple-update-notifier-2.0.0.tgz",
+ "integrity": "sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==",
+ "dev": true,
+ "requires": {
+ "semver": "^7.5.3"
+ }
+ },
+ "supports-color": {
+ "version": "5.5.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
+ "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
+ "dev": true,
+ "requires": {
+ "has-flag": "^3.0.0"
+ }
+ },
"to-regex-range": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
"is-number": "^7.0.0"
}
},
+ "touch": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/touch/-/touch-3.1.1.tgz",
+ "integrity": "sha512-r0eojU4bI8MnHr8c5bNo7lJDdI2qXlWWJk6a9EAFG7vbhTjElYhBVS3/miuE0uOuoLdb8Mc/rVfsmm6eo5o9GA==",
+ "dev": true
+ },
+ "undefsafe": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/undefsafe/-/undefsafe-2.0.5.tgz",
+ "integrity": "sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==",
+ "dev": true
+ },
"ws": {
"version": "7.5.10",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.5.10.tgz",