diff --git a/build.mjs b/build.mjs index 088ec23c8..9755511a2 100644 --- a/build.mjs +++ b/build.mjs @@ -1,10 +1,13 @@ +// This script deploys all files from /src/client to /dist in order to run the website. +// Depending on the value of DEV_BUILD in /src/server/config/config.js, this happens either in development mode or in production mode. +// Development mode: All files are simply copied over unmodified. +// Production mode: All non-script assets are copied over unmodified, +// but all game scripts in /src/client/scripts/game are concatenated into app.js. +// Further, all scripts are minified with the use of terser. + import { readdir, cp as copy, rm as remove, readFile, writeFile } from "node:fs/promises"; import { minify } from "terser"; import { DEV_BUILD } from "./src/server/config/config.js"; -import { exit } from "node:process"; - -/** Whether to generate source maps in production */ -const generateSourceMapsInProduction = false; /** * @@ -30,57 +33,61 @@ async function getExtFiles(path, ext) { return files; } -/** - * @param {string} path - * @returns {string} - */ -function getFilenamePath(path) { - const places = path.split("/"); - return places[places.length-1]; -} - +// remove dist await remove("./dist", { recursive: true, force: true, }); -await copy("./src/client", "./dist", { - recursive: true, - force: true, -}); - -if (DEV_BUILD) exit(); - -const clientScript = await getExtFiles("./src/client/scripts", ".js"); -const clientStyle = []; // await getExtFiles("./src/client/css", ".css"); - -const clientFiles = []; -clientFiles.push( - ...clientScript.map(v => `scripts/${v}`), - ...clientStyle.map(v => `css/${v}`) -); - -const filesToWrite = []; - -for (const file of clientFiles) { - const code = await readFile(`./src/client/${file}`, 'utf8'); - - const minifyInput = {}; - minifyInput[`/src/client/${file}`] = code; - - const minified = await minify(minifyInput, { - mangle: true, // Disable variable name mangling - compress: true, // Enable compression - sourceMap: generateSourceMapsInProduction ? { - includeSources: true, - url: `${getFilenamePath(file)}.map`, - } : false +if (DEV_BUILD){ + // in dev mode, copy all clientside files over to dist and exit + await copy("./src/client", "./dist", { + recursive: true, + force: true + }); +} else{ + // in prod mode, copy all clientside files over to dist, except for those contained in scripts + await copy("./src/client", "./dist", { + recursive: true, + force: true, + filter: filename => { + return !/(\\|\/)scripts(\\|\/)/.test(filename) || /(\\|\/)game$/.test(filename) // make sure to create the scripts/game/folder + } }); - filesToWrite.push(writeFile(`./dist/${file}`, minified.code, 'utf8')); - if (generateSourceMapsInProduction) { - filesToWrite.push(writeFile(`./dist/${file}.map`, minified.map, 'utf8') ) + // make a list of all client scripts: + const clientFiles = []; + const clientScripts = await getExtFiles("./src/client/scripts", ".js"); + clientFiles.push(...clientScripts.map(v => `scripts/${v}`)); + + const filesToWrite = []; // array of output files that will need to be written + let gamecode = ""; // string containing all code in /game except for htmlscript.js + + for (const file of clientFiles) { + // If the client script is htmlscript.js or not in scripts/game, then minify it and copy it over + if (/\/htmlscript\.js$/.test(file) || !/scripts(\\|\/)+game(\\|\/)/.test(file) ){ + const code = await readFile(`./src/client/${file}`, 'utf8'); + const minified = await minify(code, { + mangle: true, // Enable variable name mangling + compress: true, // Enable compression + sourceMap: false + }); + filesToWrite.push(writeFile(`./dist/${file}`, minified.code, 'utf8')); + } + // Collect the code of all js files in /game except for htmlscript.js: + else{ + gamecode += await readFile(`./src/client/${file}`, 'utf8'); + } } -} -await Promise.all(filesToWrite); \ No newline at end of file + // Combine all gamecode files into app.js + const minifiedgame = await minify(gamecode, { + mangle: true, + compress: true, + sourceMap: false + }); + filesToWrite.push(writeFile(`./dist/scripts/game/app.js`, minifiedgame.code, 'utf8')); + + // finally, write to the needed files + await Promise.all(filesToWrite); +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 6936dbce8..9991e773a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15,6 +15,7 @@ "date-fns": "^2.23.0", "dotenv": "^16.0.3", "express": "^4.18.2", + "glob": "^11.0.0", "jsonwebtoken": "^9.0.2", "node-forge": "^1.3.1", "nodemailer": "^6.8.0", @@ -39,6 +40,68 @@ "node": ">=6.9.0" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/@jridgewell/gen-mapping": { "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", @@ -151,6 +214,15 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, "node_modules/@types/node": { "version": "20.14.10", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.14.10.tgz", @@ -229,6 +301,17 @@ "node": ">=8" } }, + "node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, "node_modules/anymatch": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", @@ -404,6 +487,22 @@ "node": ">=10" } }, + "node_modules/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==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/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==" + }, "node_modules/color-support": { "version": "1.1.3", "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", @@ -484,6 +583,19 @@ "node": ">= 0.10" } }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/date-fns": { "version": "2.30.0", "resolved": "https://registry.npmjs.org/date-fns/-/date-fns-2.30.0.tgz", @@ -564,6 +676,11 @@ "url": "https://dotenvx.com" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -699,6 +816,32 @@ "node": ">= 0.8" } }, + "node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/forwarded": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", @@ -801,6 +944,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/glob": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/glob-parent": { "version": "5.1.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", @@ -812,6 +977,36 @@ "node": ">= 6" } }, + "node_modules/glob/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/glob/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -1018,6 +1213,28 @@ "node": ">=0.12.0" } }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + }, + "node_modules/jackspeak": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -1098,6 +1315,14 @@ "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" }, + "node_modules/lru-cache": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", + "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", + "engines": { + "node": "20 || >=22" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -1394,6 +1619,11 @@ "wrappy": "1" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==" + }, "node_modules/parseurl": { "version": "1.3.3", "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", @@ -1410,6 +1640,37 @@ "node": ">=0.10.0" } }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -1629,6 +1890,25 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, "node_modules/side-channel": { "version": "1.0.6", "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", @@ -1710,6 +1990,20 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -1721,6 +2015,18 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/supports-color": { "version": "5.5.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", @@ -1872,6 +2178,20 @@ "webidl-conversions": "^3.0.0" } }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/wide-align": { "version": "1.1.5", "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.5.tgz", @@ -1880,6 +2200,99 @@ "string-width": "^1.0.2 || 2 || 3 || 4" } }, + "node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/wrap-ansi/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/wrap-ansi/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", diff --git a/package.json b/package.json index 97454969c..0290600b3 100644 --- a/package.json +++ b/package.json @@ -12,6 +12,7 @@ "date-fns": "^2.23.0", "dotenv": "^16.0.3", "express": "^4.18.2", + "glob": "^11.0.0", "jsonwebtoken": "^9.0.2", "node-forge": "^1.3.1", "nodemailer": "^6.8.0", diff --git a/src/client/scripts/game/chess/formatconverter.js b/src/client/scripts/game/chess/formatconverter.js index 4c08576fa..83c5b3bb1 100644 --- a/src/client/scripts/game/chess/formatconverter.js +++ b/src/client/scripts/game/chess/formatconverter.js @@ -1,7 +1,7 @@ /* * Universal Infinite Chess Notation [Converter] and Interface - * by Andreas Tsevasa and Naviary + * by Andreas Tsevas and Naviary * https://github.com/tsevasa/infinite-chess-notation * * This script converts primed gamefiles from JSON notation to a diff --git a/src/client/scripts/game/chess/variantomega.js b/src/client/scripts/game/chess/variantomega.js index 6862346d0..3ef3b3f70 100644 --- a/src/client/scripts/game/chess/variantomega.js +++ b/src/client/scripts/game/chess/variantomega.js @@ -22,7 +22,7 @@ const variantomega = (function(){ } /** - * Inits the gamefile for Andreas Tsevasa's "Omega^2". Sets the startSnapshot and gameRules properties. + * Inits the gamefile for Andreas Tsevas's "Omega^2". Sets the startSnapshot and gameRules properties. * @param {gamefile} gamefile - The gamefile */ function initOmegaSquared(gamefile, { Variant, Date }) { diff --git a/src/client/views/play.html b/src/client/views/play.html index 35d63fdbd..728e736b3 100644 --- a/src/client/views/play.html +++ b/src/client/views/play.html @@ -1,8 +1,8 @@ - - + + @@ -18,145 +18,10 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + diff --git a/src/server/game/variantomega1.js b/src/server/game/variantomega1.js index 8e61c7838..719045a66 100644 --- a/src/server/game/variantomega1.js +++ b/src/server/game/variantomega1.js @@ -26,7 +26,7 @@ const variantomega1 = (function(){ } /** - * Inits the gamefile for Andreas Tsevasa's "Omega^2". Sets the startSnapshot and gameRules properties. + * Inits the gamefile for Andreas Tsevas's "Omega^2". Sets the startSnapshot and gameRules properties. * @param {gamefile} gamefile - The gamefile */ function initOmegaSquared(gamefile, { Variant, Date }) { diff --git a/src/server/utility/HTMLScriptInjector.js b/src/server/utility/HTMLScriptInjector.js index aa940879b..1d91587af 100644 --- a/src/server/utility/HTMLScriptInjector.js +++ b/src/server/utility/HTMLScriptInjector.js @@ -1,8 +1,10 @@ /** * This module, at runtime, creates a list of a few - * of our htmls in which we want to manually injected - * some javascript into before sharing to the client. + * of our htmls into which we want to manually inject + * some javascript before sharing to the client. + * (Currently, htmlscript.js is injected in full into play.html. + * Also, calls to the game scripts in /src/client/scripts/game are injected into play.html) * * We keep the javascript separate in development, so as * to not break Intellisense's sense of the javascript project. @@ -11,6 +13,7 @@ const fs = require('fs'); const path = require('path'); +const glob = require('glob'); /** * A cache object that has file paths for the keys, and for the values- @@ -24,9 +27,11 @@ let htmlCache = {}; * @param {string} htmlFilePath - The path of the html document in the project * @param {string} jsFilePath - The path of the javascript file containing the desired javascript code to inject. * @param {string} injectAfterTag - The HTML tag after which the JavaScript code will be injected (typically the ``). + * @param {Object} [stringInjection] - Optional argument: An object of the form {string: "htmlstring", injectafter: "tags"}. + * The string will be insterted after the specified tags into the html doc */ -function prepareAndCacheHTML(htmlFilePath, jsFilePath, injectAfterTag) { - injectScript(htmlFilePath, jsFilePath, injectAfterTag) +function prepareAndCacheHTML(htmlFilePath, jsFilePath, injectAfterTag, stringInjection = {}) { + injectScript(htmlFilePath, jsFilePath, injectAfterTag, stringInjection) .then(modifiedHTML => { htmlCache[htmlFilePath] = modifiedHTML; }) @@ -39,9 +44,11 @@ function prepareAndCacheHTML(htmlFilePath, jsFilePath, injectAfterTag) { * @param {string} htmlFilePath - The path of the html document in the project * @param {string} jsFilePath - The path of the javascript file containing the desired javascript code to inject. * @param {string} injectAfterTag - The HTML tag after which the JavaScript code will be injected (typically the ``). + * @param {Object} [stringInjection] - Optional argument: An object of the form {string: "htmlstring", injectafter: "tags"}. + * The string will be insterted after the specified tags into the html doc * @returns {Promise} - A promise that resolves with the modified HTML content, or rejects with an error message. */ -function injectScript(htmlFilePath, jsFilePath, injectAfterTag) { +function injectScript(htmlFilePath, jsFilePath, injectAfterTag, stringInjection = {}) { return new Promise((resolve, reject) => { // Read the JavaScript file fs.readFile(jsFilePath, 'utf8', (jsErr, jsData) => { @@ -59,7 +66,11 @@ function injectScript(htmlFilePath, jsFilePath, injectAfterTag) { return; } // Inject the script tag before the specified closing tag - const modifiedHTML = htmlData.replace(injectAfterTag, `${injectAfterTag}${scriptTag}`); + let modifiedHTML = htmlData.replace(injectAfterTag, `${injectAfterTag}${scriptTag}`); + // Inject the string of the optional argument "stringInjection" into the HTML file, if applicable + if (Object.keys(stringInjection).length != 0){ + modifiedHTML = modifiedHTML.replace(stringInjection.injectafter, `${stringInjection.injectafter}${stringInjection.string}`); + } resolve(modifiedHTML); }); }); @@ -91,11 +102,27 @@ function getCachedHTML(htmlFilePath) { } // Inject the scripts we want... - -{ // Inject into play.html, our OBFUSCATED htmlscript.js script. +{ + // Prepare the injection of our (potentially minified) htmlscript.js script into play.html const htmlFilePath = path.join(__dirname, '..', '..', "..", 'dist', 'views', 'play.html'); const jsFilePath = path.join(__dirname, '..', '..', '..', 'dist', 'scripts', 'game', 'htmlscript.js'); - prepareAndCacheHTML(htmlFilePath, jsFilePath, ''); + + // Prepare the injection of references to all other game scripts into play.html + const HMTL_scriptcall_p1 = `` + const injectafter_string = `${HMTL_scriptcall_p1}validation.js${HMTL_scriptcall_p2}` // we will insert the other game scripts after this exact place in the HTML code + + // Automatically build the list of scripts to be injected into play.html by including everything in scripts/game except for htmlscripts.js + let HTML_callGame_JS_string = ""; + const game_JSscripts = glob.sync(`./dist/scripts/game/**/*.js`).filter(file => {return !/htmlscript\.js/.test(file)}); + // Convert the list of scripts into an explicit HTML string that imports them all + for (file of game_JSscripts){ + const js_filename = file.split(/(\\|\/)+/).slice(4).join(""); // discard "dist/scripts/" + HTML_callGame_JS_string += `\n\t\t${HMTL_scriptcall_p1}${js_filename}${HMTL_scriptcall_p2}`; + } + + // Finally, perform the injection into play.html + prepareAndCacheHTML(htmlFilePath, jsFilePath, '', {string: HTML_callGame_JS_string, injectafter: injectafter_string}); } module.exports = {