From 61b3da517fc00774025e7462cc5b09a26f70a3af Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Thu, 9 May 2024 12:26:17 -0700
Subject: [PATCH 01/17] add script
---
README.md | 21 +--
scripts/generate-summary.mjs | 256 +++++++++++++++++++++++++++++++++++
src/SUMMARY.md | 28 ++--
src/game-support/README.md | 32 +++--
4 files changed, 295 insertions(+), 42 deletions(-)
create mode 100755 scripts/generate-summary.mjs
diff --git a/README.md b/README.md
index 1fcabc4a..8e454f2f 100644
--- a/README.md
+++ b/README.md
@@ -19,7 +19,9 @@ Documentation for Whisky.
cargo install mdbook-alerts
cargo install mdbook-template
```
-5. You can preview changes to the book with `mdbook serve --open`
+5. Install [Node.js](https://nodejs.org/en/download/).
+ You can also install it through [Homebrew](https://brew.sh/) with `brew install node`.
+6. You can preview changes to the book with `mdbook serve --open`
### Adding Game Pages:
0. Standards to uphold:
@@ -68,20 +70,11 @@ Documentation for Whisky.
```
-3. Add your game to `~/whisky-book/src/SUMMARY.md`. Make sure that you insert it in the proper alphabetical order, not deleting any games. Ensure the proper spacing and indentation is followed. Here is an example with [Diablo IV (Battle.net)](https://docs.getwhisky.app/game-support/diablo-4-battle-net.html)
- ```
- ...
- - [Cyberpunk 2077](./game-support/cyberpunk-2077.md)
- - [Dark Souls III](./game-support/dark-souls-3.md)
- - [Diablo IV (Battle.net)](./game-support/diablo-4-battle-net.md)
- - [Diablo IV (Steam)](./game-support/diablo-4-steam.md)
- - [Dorfromantik](./game-support/dorfromantik.md)
- ...
- ```
-4. Add your game to `~/whisky-book/src/game-support/README.md`. Follow the same standards as above.
-5. Create a pull request detailing the changes you made. Ensure that it's consise, yet readable and coherent.
+3. Run the `generate-summary` script with `./scripts/generate-summary.mjs` to update the `SUMMARY.md` and `game-support/README.md` files.
+ This will also make the game appear in the sidebar of the book.
+4. Create a pull request detailing the changes you made. Ensure that it's consise, yet readable and coherent.
- You will need to create a fork of `whisky-book` and push your changes there before creating a PR. Once you've done that, then you can submit a PR to merge your fork with `main`.
-6. Sit back, wait for PR reviews, and make changes as necessary.
+5. Sit back, wait for PR reviews, and make changes as necessary.
Have any questions about this process or anything Whisky-related? Stop by the [Discord](https://discord.gg/CsqAfs9CnM) and ask us a question! We're more than happy to help.
diff --git a/scripts/generate-summary.mjs b/scripts/generate-summary.mjs
new file mode 100755
index 00000000..b0780f14
--- /dev/null
+++ b/scripts/generate-summary.mjs
@@ -0,0 +1,256 @@
+#!/usr/bin/env node
+/**
+ * Generates a SUMMARY.md file for rust book.
+ */
+import { readdir, readFile, writeFile } from 'node:fs/promises';
+import { resolve, dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { format } from 'node:util';
+
+/**
+ * Escapes a string for use in Markdown.
+ * @type {Array<[RegExp, string]>}
+ */
+const markdownEscapeItems = [
+ [/\*/g, '\\*'], // Asterisks
+ [/#/g, '\\#'], // Hashes
+ [/\//g, '\\/'], // Slashes
+ [/\(/g, '\\('], // Open parentheses
+ [/\)/g, '\\)'], // Close parentheses
+ [/\[/g, '\\['], // Open square brackets
+ [/\]/g, '\\]'], // Close square brackets
+ [//g, '>'], // Close angle brackets
+ [/_/g, '\\_'], // Underscores
+ [/`/g, '\\`'], // Backticks
+];
+
+/**
+ * Escapes a string for use in Markdown.
+ * @param {string} str
+ */
+const markdownEscape = (str) => {
+ for (const [regex, replacement] of markdownEscapeItems) {
+ str = str.replace(regex, replacement);
+ }
+ return str;
+}
+
+/**
+ * Fancy colors for console output.
+ * @type {Object<'debug' | 'info' | 'warning' | 'error | 'bold' | 'reset', string>}
+ */
+const colors = {
+ debug: '\x1b[2m',
+ info: '\x1b[36m',
+ warning: '\x1b[33m',
+ error: '\x1b[31m',
+ bold: '\x1b[1m',
+ reset: '\x1b[0m',
+};
+
+/**
+ * Logs a message to the console with fancy colors.
+ * @param {'debug' | 'info' | 'warning' | 'error'} type
+ * @param {string} message
+ * @param {...any} args
+ */
+const fancyLog = (type, message, ...args) => {
+ console.log(
+ '%s%s[%s]%s%s %s%s',
+ colors.bold,
+ colors[type],
+ type.toUpperCase(),
+ colors.reset,
+ colors[type],
+ format(message, ...args),
+ colors.reset,
+ );
+}
+
+/**
+ * Logging functions.
+ * @type {Object<'debug' | 'info' | 'warning' | 'error', (message: string, ...args: any[]) => void>}
+ */
+const logging = {
+ /**
+ * Logs an debug message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ debug: (message, ...args) => fancyLog('debug', message, ...args),
+ /**
+ * Logs an info message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ info: (message, ...args) => fancyLog('info', message, ...args),
+ /**
+ * Logs a warning message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ warning: (message, ...args) => fancyLog('warning', message, ...args),
+ /**
+ * Logs an error message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ error: (message, ...args) => fancyLog('error', message, ...args),
+};
+
+const SCRIPT_GENERATE_START = '';
+const SCRIPT_GENERATE_END = '';
+const GAME_SUPPORT_DIR = 'game-support';
+const INDEX_FILE = 'README.md';
+const FILES_SKIP = ['README.md', 'template.md'];
+
+/**
+ * Gets the start and end sections of a file.
+ * @param {string} content
+ * @returns {[string | null, string | null]}
+ */
+const getStartAndEndSections = (content) => {
+ if (
+ content.split(SCRIPT_GENERATE_START).length !== 2 ||
+ content.split(SCRIPT_GENERATE_END).length !== 2
+ ) {
+ return [null, null];
+ }
+
+ const [start, replaceAndEnd] = content.split(SCRIPT_GENERATE_START);
+ const [_, end] = replaceAndEnd.split(SCRIPT_GENERATE_END);
+ return [start, end];
+}
+
+/**
+ * Main function.
+ * @returns {Promise}
+ */
+const main = async () => {
+ logging.info('Generating SUMMARY.md...');
+ // Get local file paths
+ const dirName = resolve(dirname(fileURLToPath(import.meta.url)), '../', 'src');
+ const summaryFilePath = resolve(dirName, 'SUMMARY.md');
+ const indexFilePath = resolve(dirName, 'game-support', INDEX_FILE);
+ const gameSupportDirPath = resolve(dirName, GAME_SUPPORT_DIR);
+
+ // Read the SUMMARY.md file
+ const [summaryFileContent, summaryFileReadError] = await readFile(summaryFilePath, 'utf-8')
+ .then((data) => [data, null])
+ .catch((error) => [null, error]);
+ if (summaryFileReadError) {
+ logging.error('Failed to read SUMMARY.md: %o', summaryFileReadError);
+ return 1;
+ }
+ const [summaryFileStart, summaryFileEnd] = getStartAndEndSections(summaryFileContent);
+ if (!summaryFileStart === null || !summaryFileEnd === null) {
+ logging.error('Failed to find start and end sections in SUMMARY.md.');
+ return 1;
+ }
+
+ // Read the index file
+ const [indexFileContent, indexFileReadError] = await readFile(indexFilePath, 'utf-8')
+ .then((data) => [data, null])
+ .catch((error) => [null, error]);
+ if (indexFileReadError) {
+ logging.error('Failed to read index file: %o', indexFileReadError);
+ return 1;
+ }
+ const [indexFileStart, indexFileEnd] = getStartAndEndSections(indexFileContent);
+ if (!indexFileStart === null || !indexFileEnd === null) {
+ logging.error('Failed to find start and end sections in index file.');
+ return 1;
+ }
+
+ // Get all files in the game-support directory
+ const [gameSupportDirFiles, gameSupportDirFilesError] = await readdir(gameSupportDirPath, { withFileTypes: true })
+ .then((files) => [files, null])
+ .catch((error) => [null, error]);
+ if (gameSupportDirFilesError) {
+ logging.error('Failed to read game-support directory: %o', gameSupportDirFilesError);
+ return 1;
+ }
+
+ // Filter out directories and non-markdown files
+ const markdownFiles = gameSupportDirFiles
+ .filter((file) => file.isFile() && file.name.endsWith('.md') && !FILES_SKIP.includes(file.name));
+
+ // For all, generate a markdown link
+ /**
+ * @type {Array<{name: string, title: string}>}
+ */
+ const links = [];
+ for (const file of markdownFiles) {
+ // Read the file
+ const filePath = resolve(gameSupportDirPath, file.name);
+ const [fileContent, fileReadError] = await readFile(filePath, 'utf-8')
+ .then((data) => [data, null])
+ .catch((error) => [null, error]);
+ if (fileReadError) {
+ logging.error('Failed to read file %s: %o', filePath, fileReadError);
+ return 1;
+ }
+
+ // Get the title
+ const titleMatch = fileContent.match(/^# (.+)$/m);
+ if (!titleMatch || titleMatch.length < 2) {
+ logging.warning('Failed to find title in file %s. "%s" will be skipped.', filePath, file.name);
+ continue;
+ }
+
+ // Add the link
+ const title = titleMatch[1];
+
+ links.push({
+ name: file.name,
+ title,
+ });
+ }
+
+ // Write the new SUMMARY.md file
+ const newSummaryFileContent = [
+ summaryFileStart,
+ SCRIPT_GENERATE_START,
+ '\n',
+ links.map((link) => {
+ return ` - [${markdownEscape(link.title)}](./${GAME_SUPPORT_DIR}/${encodeURIComponent(link.name)})`;
+ }).join('\n'),
+ '\n',
+ SCRIPT_GENERATE_END,
+ summaryFileEnd,
+ ].join('');
+ const [_a, writeError] = await writeFile(summaryFilePath, newSummaryFileContent)
+ .then(() => [null, null])
+ .catch((error) => [null, error]);
+ if (writeError) {
+ logging.error('Failed to write SUMMARY.md: %o', writeError);
+ return 1;
+ }
+ logging.info('SUMMARY.md generated successfully.');
+
+ // Write the new index file
+ const newIndexFileContent = [
+ indexFileStart,
+ SCRIPT_GENERATE_START,
+ '\n',
+ links.map((link) => {
+ return `- [${markdownEscape(link.title)}](./${encodeURIComponent(link.name)})`;
+ }).join('\n'),
+ '\n',
+ SCRIPT_GENERATE_END,
+ indexFileEnd,
+ ].join('');
+ const [_b, writeIndexError] = await writeFile(indexFilePath, newIndexFileContent)
+ .then(() => [null, null])
+ .catch((error) => [null, error]);
+ if (writeIndexError) {
+ logging.error('Failed to write index file: %o', writeIndexError);
+ return 1;
+ }
+ logging.info('Index file generated successfully.');
+
+ return 0;
+};
+
+main().then((code) => process.exit(code));
\ No newline at end of file
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 482df898..5b79a73e 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -8,12 +8,13 @@
- [Whisky x Heroic](./whisky-x-heroic.md)
- [Debugging](./debugging.md)
- [Game Support](./game-support/README.md)
+
- [Among Us](./game-support/among-us.md)
- [Armored Core VI: Fires of Rubicon](./game-support/armored-core-6.md)
- [Battle Brothers](./game-support/battle-brothers.md)
- [Blasphemous 2](./game-support/blasphemous-2.md)
- [Buckshot Roulette](./game-support/buckshot-roulette.md)
- - [Cities: Skylines II](./game-support/cities-skylines-2.md)
+ - [Cities: Skylines 2](./game-support/cities-skylines-2.md)
- [Content Warning](./game-support/content-warning.md)
- [Contraband Police](./game-support/contraband-police.md)
- [Control](./game-support/control.md)
@@ -21,13 +22,13 @@
- [Cyberpunk 2077](./game-support/cyberpunk-2077.md)
- [Dark Souls III](./game-support/dark-souls-3.md)
- [Dark Souls: Remastered](./game-support/dark-souls-remastered.md)
- - [Dead Space (2023)](./game-support/dead-space-2023.md)
+ - [Dead Space \(2023\)](./game-support/dead-space-2023.md)
- [Deadlink](./game-support/deadlink.md)
- [Deep Rock Galactic](./game-support/deep-rock-galactic.md)
- - [Diablo IV (Battle.net)](./game-support/diablo-4-battle-net.md)
- - [Diablo IV (Steam)](./game-support/diablo-4-steam.md)
- - [Dishonored](./game-support/dishonored.md)
+ - [Diablo IV - Battle.net Version](./game-support/diablo-4-battle-net.md)
+ - [Diablo IV - Steam Version](./game-support/diablo-4-steam.md)
- [Dishonored 2](./game-support/dishonored-2.md)
+ - [Dishonored](./game-support/dishonored.md)
- [Dorfromantik](./game-support/dorfromantik.md)
- [Dying Light 2](./game-support/dying-light-2.md)
- [Elden Ring](./game-support/elden-ring.md)
@@ -36,24 +37,24 @@
- [Fallout 4](./game-support/fallout-4.md)
- [Fear and Hunger](./game-support/fear-and-hunger.md)
- [Forgive Me Father 2](./game-support/forgive-me-father-2.md)
- - [Fortnite](./game-support/fortnite.md)
+ - [No.](./game-support/fortnite.md)
- [Friends vs Friends](./game-support/friends-vs-friends.md)
- - [Geometry Wars 3: Dimensions Evolved](./game-support/gw3-dimensions-evolved.md)
- - [Guild Wars 2](./game-support/gw2.md)
- [Grand Theft Auto V](./game-support/gta-5.md)
+ - [Guild Wars 2](./game-support/gw2.md)
+ - [Geometry Wars 3: Dimensions Evolved](./game-support/gw3-dimensions-evolved.md)
- [Half-Life 1](./game-support/half-life-1.md)
- [Half-Life 2](./game-support/half-life-2.md)
- [Hitman: Contracts](./game-support/hitman-3-c.md)
- [Horizon Zero Dawn](./game-support/horizon-zero-dawn.md)
- [JoJo's Bizarre Adventure: All Star Battle R](./game-support/jjba-asbr.md)
- - [Kenshi](./game-support/kenshi.md)
- [Kingdom Come: Deliverance](./game-support/kcd.md)
+ - [Kenshi](./game-support/kenshi.md)
- [Kingsway](./game-support/kingsway.md)
- [Lego Star Wars: The Skywalker Saga](./game-support/lego-sw-skywalker-saga.md)
- [Lethal Company](./game-support/lethal-company.md)
- - [Metal Gear Solid V: The Phantom Pain](./game-support/mgs-5.md)
- [Metro 2033 Redux](./game-support/metro-2033-rx.md)
- [Metro: Last Light Redux](./game-support/metro-ll-rx.md)
+ - [Metal Gear Solid V: The Phantom Pain](./game-support/mgs-5.md)
- [Monster Hunter World: Iceborne](./game-support/monster-hunter-world-iceborne.md)
- [Neon White](./game-support/neon-white.md)
- [Overwatch 2](./game-support/overwatch-2.md)
@@ -62,7 +63,7 @@
- [Palworld](./game-support/palworld.md)
- [People Playground](./game-support/people-playground.md)
- [Phasmophobia](./game-support/phasmophobia.md)
- - [Prey (2017)](./game-support/prey-2017.md)
+ - [Prey \(2017\)](./game-support/prey-2017.md)
- [Quake II](./game-support/quake2.md)
- [r2modman](./game-support/r2modman.md)
- [Rain World](./game-support/rain-world.md)
@@ -74,10 +75,11 @@
- [Stardew Valley](./game-support/stardew-valley.md)
- [Star Wars Jedi: Fallen Order](./game-support/sw-fallen-order.md)
- [Star Wars: Squadrons](./game-support/sw-squadrons.md)
- - [Tom Clancy's Rainbow Six Siege](./game-support/tcr6s.md)
+ - [Tom Clancy's Rainbow Six Siege \(Steam\)](./game-support/tcr6s.md)
- [The Stanley Parable: Ultra Deluxe](./game-support/tsp-ud.md)
- - [The Wolf Among Us](./game-support/wolf-among-us.md)
- [Turbo Overkill](./game-support/turbo-overkill.md)
- [Ultrakill](./game-support/ultrakill.md)
- [Undertale](./game-support/undertale.md)
- [Warframe](./game-support/warframe.md)
+ - [The Wolf Among Us](./game-support/wolf-among-us.md)
+
\ No newline at end of file
diff --git a/src/game-support/README.md b/src/game-support/README.md
index 13f7ed14..553e156a 100644
--- a/src/game-support/README.md
+++ b/src/game-support/README.md
@@ -19,12 +19,13 @@ title is partially left to the article author, but some general guidelines apply
### Index
+
- [Among Us](./among-us.md)
- [Armored Core VI: Fires of Rubicon](./armored-core-6.md)
- [Battle Brothers](./battle-brothers.md)
- [Blasphemous 2](./blasphemous-2.md)
- [Buckshot Roulette](./buckshot-roulette.md)
-- [Cities: Skylines II](./cities-skylines-2.md)
+- [Cities: Skylines 2](./cities-skylines-2.md)
- [Content Warning](./content-warning.md)
- [Contraband Police](./contraband-police.md)
- [Control](./control.md)
@@ -32,13 +33,13 @@ title is partially left to the article author, but some general guidelines apply
- [Cyberpunk 2077](./cyberpunk-2077.md)
- [Dark Souls III](./dark-souls-3.md)
- [Dark Souls: Remastered](./dark-souls-remastered.md)
-- [Dead Space (2023)](./dead-space-2023.md)
+- [Dead Space \(2023\)](./dead-space-2023.md)
- [Deadlink](./deadlink.md)
- [Deep Rock Galactic](./deep-rock-galactic.md)
-- [Diablo IV (Battle.net)](./diablo-4-battle-net.md)
-- [Diablo IV (Steam)](./diablo-4-steam.md)
-- [Dishonored](./dishonored.md)
+- [Diablo IV - Battle.net Version](./diablo-4-battle-net.md)
+- [Diablo IV - Steam Version](./diablo-4-steam.md)
- [Dishonored 2](./dishonored-2.md)
+- [Dishonored](./dishonored.md)
- [Dorfromantik](./dorfromantik.md)
- [Dying Light 2](./dying-light-2.md)
- [Elden Ring](./elden-ring.md)
@@ -47,24 +48,24 @@ title is partially left to the article author, but some general guidelines apply
- [Fallout 4](./fallout-4.md)
- [Fear and Hunger](./fear-and-hunger.md)
- [Forgive Me Father 2](./forgive-me-father-2.md)
-- [Fortnite](./fortnite.md)
+- [No.](./fortnite.md)
- [Friends vs Friends](./friends-vs-friends.md)
-- [Geometry Wars 3: Dimensions Evolved](./gw3-dimensions-evolved.md)
-- [Guild Wars 2](./gw2.md)
- [Grand Theft Auto V](./gta-5.md)
+- [Guild Wars 2](./gw2.md)
+- [Geometry Wars 3: Dimensions Evolved](./gw3-dimensions-evolved.md)
- [Half-Life 1](./half-life-1.md)
- [Half-Life 2](./half-life-2.md)
- [Hitman: Contracts](./hitman-3-c.md)
- [Horizon Zero Dawn](./horizon-zero-dawn.md)
- [JoJo's Bizarre Adventure: All Star Battle R](./jjba-asbr.md)
-- [Kenshi](./kenshi.md)
- [Kingdom Come: Deliverance](./kcd.md)
+- [Kenshi](./kenshi.md)
- [Kingsway](./kingsway.md)
- [Lego Star Wars: The Skywalker Saga](./lego-sw-skywalker-saga.md)
- [Lethal Company](./lethal-company.md)
-- [Metal Gear Solid V: The Phantom Pain](./mgs-5.md)
- [Metro 2033 Redux](./metro-2033-rx.md)
- [Metro: Last Light Redux](./metro-ll-rx.md)
+- [Metal Gear Solid V: The Phantom Pain](./mgs-5.md)
- [Monster Hunter World: Iceborne](./monster-hunter-world-iceborne.md)
- [Neon White](./neon-white.md)
- [Overwatch 2](./overwatch-2.md)
@@ -73,22 +74,23 @@ title is partially left to the article author, but some general guidelines apply
- [Palworld](./palworld.md)
- [People Playground](./people-playground.md)
- [Phasmophobia](./phasmophobia.md)
-- [Prey (2017)](./prey-2017.md)
-- [Quake 2](./quake2.md)
+- [Prey \(2017\)](./prey-2017.md)
+- [Quake II](./quake2.md)
- [r2modman](./r2modman.md)
- [Rain World](./rain-world.md)
- [Risk of Rain 2](./risk-of-rain-2.md)
-- [Rain World](./rain-world.md)
+- [Risk of Rain Returns](./risk-of-rain-returns.md)
- [Satisfactory](./satisfactory.md)
- [Sekiro: Shadows Die Twice](./sekiro.md)
- [Skyrim SE](./skyrim-se.md)
- [Stardew Valley](./stardew-valley.md)
- [Star Wars Jedi: Fallen Order](./sw-fallen-order.md)
- [Star Wars: Squadrons](./sw-squadrons.md)
-- [Tom Clancy's Rainbow Six Siege](./tcr6s.md)
+- [Tom Clancy's Rainbow Six Siege \(Steam\)](./tcr6s.md)
- [The Stanley Parable: Ultra Deluxe](./tsp-ud.md)
-- [The Wolf Among Us](./wolf-among-us.md)
- [Turbo Overkill](./turbo-overkill.md)
- [Ultrakill](./ultrakill.md)
- [Undertale](./undertale.md)
- [Warframe](./warframe.md)
+- [The Wolf Among Us](./wolf-among-us.md)
+
\ No newline at end of file
From 451d4bb94382e89705cff383458fd6814d3c67a8 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Thu, 9 May 2024 12:28:48 -0700
Subject: [PATCH 02/17] add spacing to summary so it works.
---
src/SUMMARY.md | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 5b79a73e..798f48e5 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -8,7 +8,7 @@
- [Whisky x Heroic](./whisky-x-heroic.md)
- [Debugging](./debugging.md)
- [Game Support](./game-support/README.md)
-
+
- [Among Us](./game-support/among-us.md)
- [Armored Core VI: Fires of Rubicon](./game-support/armored-core-6.md)
- [Battle Brothers](./game-support/battle-brothers.md)
From 5d22ac01d0e2fb89284b3787c85576b0df27f568 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Thu, 9 May 2024 15:36:16 -0700
Subject: [PATCH 03/17] =?UTF-8?q?Add=20games.json=20for=20=E3=82=A6?=
=?UTF-8?q?=E3=82=A3=E3=82=B9=E3=82=AD=E3=83=BC=20Bot?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.github/workflows/mdbook.yml | 5 ++
.gitignore | 1 +
scripts/generate-summary.mjs | 64 ++++++++++++++++++-
src/SUMMARY.md | 4 +-
src/game-support/README.md | 4 +-
src/game-support/armored-core-6.md | 5 ++
src/game-support/cities-skylines-2.md | 3 +
src/game-support/counter-strike-2.md | 4 ++
src/game-support/dark-souls-3.md | 3 +
src/game-support/dark-souls-remastered.md | 3 +
src/game-support/dead-space-2023.md | 4 ++
src/game-support/diablo-4-battle-net.md | 4 ++
src/game-support/diablo-4-steam.md | 6 ++
src/game-support/fortnite.md | 4 +-
src/game-support/gta-5.md | 5 ++
src/game-support/gw3-dimensions-evolved.md | 3 +
src/game-support/half-life-1.md | 5 ++
src/game-support/half-life-2.md | 3 +
src/game-support/hitman-3-c.md | 5 ++
src/game-support/jjba-asbr.md | 10 ++-
src/game-support/kcd.md | 4 ++
src/game-support/lego-sw-skywalker-saga.md | 3 +
src/game-support/metro-ll-rx.md | 3 +
src/game-support/mgs-5.md | 5 ++
.../monster-hunter-world-iceborne.md | 3 +
src/game-support/p3r.md | 3 +
src/game-support/p4g.md | 3 +
src/game-support/prey-2017.md | 3 +
src/game-support/quake2.md | 3 +
src/game-support/sekiro.md | 3 +
src/game-support/sw-fallen-order.md | 3 +
src/game-support/sw-squadrons.md | 3 +
src/game-support/tcr6s.md | 5 ++
src/game-support/tsp-ud.md | 3 +
34 files changed, 184 insertions(+), 8 deletions(-)
diff --git a/.github/workflows/mdbook.yml b/.github/workflows/mdbook.yml
index 8a4c0f48..8dd3be77 100644
--- a/.github/workflows/mdbook.yml
+++ b/.github/workflows/mdbook.yml
@@ -22,6 +22,11 @@ jobs:
CARGO_TERM_COLOR: always
steps:
- uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: latest
+ - name: Generate summary
+ run: node scripts/generate-summary.mjs
- uses: Swatinem/rust-cache@v2
- name: Install mdBook
run: |
diff --git a/.gitignore b/.gitignore
index bad7316d..72d81851 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
book
.idea
**/.DS_Store
+src/games.json
\ No newline at end of file
diff --git a/scripts/generate-summary.mjs b/scripts/generate-summary.mjs
index b0780f14..14276931 100755
--- a/scripts/generate-summary.mjs
+++ b/scripts/generate-summary.mjs
@@ -3,7 +3,7 @@
* Generates a SUMMARY.md file for rust book.
*/
import { readdir, readFile, writeFile } from 'node:fs/promises';
-import { resolve, dirname } from 'node:path';
+import { resolve, dirname, basename } from 'node:path';
import { fileURLToPath } from 'node:url';
import { format } from 'node:util';
@@ -101,8 +101,11 @@ const logging = {
const SCRIPT_GENERATE_START = '';
const SCRIPT_GENERATE_END = '';
+// After the aliases start, we will find a json array of aliases (match everything until the closing comment)
+const SCRIPT_ALIASES_REGEX = //s;
const GAME_SUPPORT_DIR = 'game-support';
const INDEX_FILE = 'README.md';
+const GAMES_OUT_FILE = 'games.json';
const FILES_SKIP = ['README.md', 'template.md'];
/**
@@ -134,6 +137,7 @@ const main = async () => {
const summaryFilePath = resolve(dirName, 'SUMMARY.md');
const indexFilePath = resolve(dirName, 'game-support', INDEX_FILE);
const gameSupportDirPath = resolve(dirName, GAME_SUPPORT_DIR);
+ const gamesOutFilePath = resolve(dirName, GAMES_OUT_FILE);
// Read the SUMMARY.md file
const [summaryFileContent, summaryFileReadError] = await readFile(summaryFilePath, 'utf-8')
@@ -178,7 +182,7 @@ const main = async () => {
// For all, generate a markdown link
/**
- * @type {Array<{name: string, title: string}>}
+ * @type {Array<{name: string, path: string, title: string, aliases: string[]}>}
*/
const links = [];
for (const file of markdownFiles) {
@@ -202,9 +206,48 @@ const main = async () => {
// Add the link
const title = titleMatch[1];
+ // Look for aliases
+ const aliasesMatch = fileContent.match(SCRIPT_ALIASES_REGEX);
+ if (!aliasesMatch || aliasesMatch.length < 2) {
+ links.push({
+ name: file.name,
+ title,
+ aliases: [],
+ });
+ continue;
+ }
+
+ let [aliasesParsed, aliasesError] = (() => {
+ try {
+ return [JSON.parse(aliasesMatch[1]), null];
+ } catch (error) {
+ return [null, error];
+ }
+ })();
+ if (aliasesError) {
+ logging.warning('Failed to parse aliases in file %s: %o', filePath, aliasesError);
+ }
+ if (!aliasesParsed || !Array.isArray(aliasesParsed) || !aliasesParsed.every((alias) => typeof alias === 'string')) {
+ logging.warning('Invalid aliases in file %s: %o', filePath, aliasesParsed);
+ aliasesParsed = null;
+ }
+
+ // Remove duplicates
+ const dupeMap = new Map();
+ let aliases = (aliasesParsed ?? []).map((alias) => alias.toLocaleLowerCase());
+ aliases.push(title.toLocaleLowerCase());
+ aliases = aliases.filter((alias) => {
+ if (dupeMap.has(alias)) {
+ return false;
+ }
+ dupeMap.set(alias, true);
+ return true;
+ });
+
links.push({
name: file.name,
title,
+ aliases
});
}
@@ -250,6 +293,23 @@ const main = async () => {
}
logging.info('Index file generated successfully.');
+ // Write the games.json file
+ const gamesOutFileContent = JSON.stringify(links.map((link) => {
+ return {
+ url: `/${GAME_SUPPORT_DIR}/${encodeURIComponent(basename(link.name) + '.html')}`,
+ title: link.title,
+ aliases: link.aliases,
+ };
+ }), null, 2);
+ const [_c, writeGamesError] = await writeFile(gamesOutFilePath, gamesOutFileContent)
+ .then(() => [null, null])
+ .catch((error) => [null, error]);
+ if (writeGamesError) {
+ logging.error('Failed to write games.json: %o', writeGamesError);
+ return 1;
+ }
+ logging.info('games.json generated successfully.');
+
return 0;
};
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 798f48e5..e7a002ff 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -37,7 +37,7 @@
- [Fallout 4](./game-support/fallout-4.md)
- [Fear and Hunger](./game-support/fear-and-hunger.md)
- [Forgive Me Father 2](./game-support/forgive-me-father-2.md)
- - [No.](./game-support/fortnite.md)
+ - [Fortnite](./game-support/fortnite.md)
- [Friends vs Friends](./game-support/friends-vs-friends.md)
- [Grand Theft Auto V](./game-support/gta-5.md)
- [Guild Wars 2](./game-support/gw2.md)
@@ -46,7 +46,7 @@
- [Half-Life 2](./game-support/half-life-2.md)
- [Hitman: Contracts](./game-support/hitman-3-c.md)
- [Horizon Zero Dawn](./game-support/horizon-zero-dawn.md)
- - [JoJo's Bizarre Adventure: All Star Battle R](./game-support/jjba-asbr.md)
+ - [JoJo's Bizarre Adventure: All-Star Battle R](./game-support/jjba-asbr.md)
- [Kingdom Come: Deliverance](./game-support/kcd.md)
- [Kenshi](./game-support/kenshi.md)
- [Kingsway](./game-support/kingsway.md)
diff --git a/src/game-support/README.md b/src/game-support/README.md
index 553e156a..82f51b99 100644
--- a/src/game-support/README.md
+++ b/src/game-support/README.md
@@ -48,7 +48,7 @@ title is partially left to the article author, but some general guidelines apply
- [Fallout 4](./fallout-4.md)
- [Fear and Hunger](./fear-and-hunger.md)
- [Forgive Me Father 2](./forgive-me-father-2.md)
-- [No.](./fortnite.md)
+- [Fortnite](./fortnite.md)
- [Friends vs Friends](./friends-vs-friends.md)
- [Grand Theft Auto V](./gta-5.md)
- [Guild Wars 2](./gw2.md)
@@ -57,7 +57,7 @@ title is partially left to the article author, but some general guidelines apply
- [Half-Life 2](./half-life-2.md)
- [Hitman: Contracts](./hitman-3-c.md)
- [Horizon Zero Dawn](./horizon-zero-dawn.md)
-- [JoJo's Bizarre Adventure: All Star Battle R](./jjba-asbr.md)
+- [JoJo's Bizarre Adventure: All-Star Battle R](./jjba-asbr.md)
- [Kingdom Come: Deliverance](./kcd.md)
- [Kenshi](./kenshi.md)
- [Kingsway](./kingsway.md)
diff --git a/src/game-support/armored-core-6.md b/src/game-support/armored-core-6.md
index 6c06e3c3..667fe619 100644
--- a/src/game-support/armored-core-6.md
+++ b/src/game-support/armored-core-6.md
@@ -1,4 +1,9 @@
# Armored Core VI: Fires of Rubicon
+
{{#template ../templates/rating.md status=Gold date=08/09/23 installs=Yes opens=Yes}}
diff --git a/src/game-support/cities-skylines-2.md b/src/game-support/cities-skylines-2.md
index 1b418f6f..787a49fd 100644
--- a/src/game-support/cities-skylines-2.md
+++ b/src/game-support/cities-skylines-2.md
@@ -1,4 +1,7 @@
# Cities: Skylines 2
+
{{#template ../templates/rating.md status=Bronze date=11/28/23 installs=Yes opens=Yes}}
diff --git a/src/game-support/counter-strike-2.md b/src/game-support/counter-strike-2.md
index 1011e42a..0f98fe34 100644
--- a/src/game-support/counter-strike-2.md
+++ b/src/game-support/counter-strike-2.md
@@ -1,4 +1,8 @@
# Counter-Strike 2
+
{{#template ../templates/rating.md status=Silver date=10/24/23 installs=Yes opens=Yes}}
diff --git a/src/game-support/dark-souls-3.md b/src/game-support/dark-souls-3.md
index 101b2d07..31a8ba8e 100644
--- a/src/game-support/dark-souls-3.md
+++ b/src/game-support/dark-souls-3.md
@@ -1,4 +1,7 @@
# Dark Souls III
+
{{#template ../templates/rating.md status=Gold date=04/09/23 installs=Yes opens=Yes}}
diff --git a/src/game-support/dark-souls-remastered.md b/src/game-support/dark-souls-remastered.md
index 13b5e0c4..cf160664 100644
--- a/src/game-support/dark-souls-remastered.md
+++ b/src/game-support/dark-souls-remastered.md
@@ -1,4 +1,7 @@
# Dark Souls: Remastered
+
{{#template ../templates/rating.md status=Gold date=03/12/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/dead-space-2023.md b/src/game-support/dead-space-2023.md
index 9f64a93a..fa04cb6d 100644
--- a/src/game-support/dead-space-2023.md
+++ b/src/game-support/dead-space-2023.md
@@ -1,4 +1,8 @@
# Dead Space (2023)
+
{{#template ../templates/rating.md status=Gold date=04/28/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/diablo-4-battle-net.md b/src/game-support/diablo-4-battle-net.md
index 60b1b697..0a622e79 100644
--- a/src/game-support/diablo-4-battle-net.md
+++ b/src/game-support/diablo-4-battle-net.md
@@ -1,4 +1,8 @@
# Diablo IV - Battle.net Version
+
{{#template ../templates/rating.md status=Garbage date=02/04/24 installs=Yes opens=No}}
diff --git a/src/game-support/diablo-4-steam.md b/src/game-support/diablo-4-steam.md
index 681b378b..c3c26558 100644
--- a/src/game-support/diablo-4-steam.md
+++ b/src/game-support/diablo-4-steam.md
@@ -1,4 +1,10 @@
# Diablo IV - Steam Version
+
{{#template ../templates/rating.md status=Garbage date=02/04/24 installs=Yes opens=No}}
diff --git a/src/game-support/fortnite.md b/src/game-support/fortnite.md
index 124f2d39..0932f74d 100644
--- a/src/game-support/fortnite.md
+++ b/src/game-support/fortnite.md
@@ -1 +1,3 @@
-# No.
\ No newline at end of file
+# Fortnite
+
+No.
\ No newline at end of file
diff --git a/src/game-support/gta-5.md b/src/game-support/gta-5.md
index 768e9038..57caec4f 100644
--- a/src/game-support/gta-5.md
+++ b/src/game-support/gta-5.md
@@ -1,4 +1,9 @@
# Grand Theft Auto V
+
{{#template ../templates/rating.md status=Silver date=13/04/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/gw3-dimensions-evolved.md b/src/game-support/gw3-dimensions-evolved.md
index 2f549403..f5643d1a 100644
--- a/src/game-support/gw3-dimensions-evolved.md
+++ b/src/game-support/gw3-dimensions-evolved.md
@@ -1,4 +1,7 @@
# Geometry Wars 3: Dimensions Evolved
+
{{#template ../templates/rating.md status=Gold date=03/04/23 installs=Yes opens=Yes}}
diff --git a/src/game-support/half-life-1.md b/src/game-support/half-life-1.md
index b3bed533..6abfb093 100644
--- a/src/game-support/half-life-1.md
+++ b/src/game-support/half-life-1.md
@@ -1,4 +1,9 @@
# Half-Life 1
+
{{#template ../templates/rating.md status=Garbage date=04/16/24 installs=Yes opens=No}}
diff --git a/src/game-support/half-life-2.md b/src/game-support/half-life-2.md
index f5587be4..2b0e1eb0 100644
--- a/src/game-support/half-life-2.md
+++ b/src/game-support/half-life-2.md
@@ -1,4 +1,7 @@
# Half-Life 2
+
{{#template ../templates/rating.md status=Gold date=04/16/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/hitman-3-c.md b/src/game-support/hitman-3-c.md
index d2ee8e93..2c7029ee 100644
--- a/src/game-support/hitman-3-c.md
+++ b/src/game-support/hitman-3-c.md
@@ -1,4 +1,9 @@
# Hitman: Contracts
+
{{#template ../templates/rating.md status=Silver date=04/05/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/jjba-asbr.md b/src/game-support/jjba-asbr.md
index e83bdc25..e210abcd 100644
--- a/src/game-support/jjba-asbr.md
+++ b/src/game-support/jjba-asbr.md
@@ -1,4 +1,12 @@
-# JoJo's Bizarre Adventure: All Star Battle R
+# JoJo's Bizarre Adventure: All-Star Battle R
+
{{#template ../templates/rating.md status=Gold date=04/28/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/kcd.md b/src/game-support/kcd.md
index 05f09cfd..757990ab 100644
--- a/src/game-support/kcd.md
+++ b/src/game-support/kcd.md
@@ -1,4 +1,8 @@
# Kingdom Come: Deliverance
+
{{#template ../templates/rating.md status=Gold date=05/08/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/lego-sw-skywalker-saga.md b/src/game-support/lego-sw-skywalker-saga.md
index 1e310781..7bb6bef6 100644
--- a/src/game-support/lego-sw-skywalker-saga.md
+++ b/src/game-support/lego-sw-skywalker-saga.md
@@ -1,4 +1,7 @@
# Lego Star Wars: The Skywalker Saga
+
{{#template ../templates/rating.md status=Gold date=04/29/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/metro-ll-rx.md b/src/game-support/metro-ll-rx.md
index 010edb36..a1b1c2ed 100644
--- a/src/game-support/metro-ll-rx.md
+++ b/src/game-support/metro-ll-rx.md
@@ -1,4 +1,7 @@
# Metro: Last Light Redux
+
{{#template ../templates/rating.md status=Gold date=03/05/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/mgs-5.md b/src/game-support/mgs-5.md
index f870ada6..868de089 100644
--- a/src/game-support/mgs-5.md
+++ b/src/game-support/mgs-5.md
@@ -1,4 +1,9 @@
# Metal Gear Solid V: The Phantom Pain
+
{{#template ../templates/rating.md status=Gold date=29/09/23 installs=Yes opens=Yes}}
diff --git a/src/game-support/monster-hunter-world-iceborne.md b/src/game-support/monster-hunter-world-iceborne.md
index c3cd45e0..69efb8f2 100644
--- a/src/game-support/monster-hunter-world-iceborne.md
+++ b/src/game-support/monster-hunter-world-iceborne.md
@@ -1,4 +1,7 @@
# Monster Hunter World: Iceborne
+
{{#template ../templates/rating.md status=Gold date=12/10/23 installs=Yes opens=Yes}}
diff --git a/src/game-support/p3r.md b/src/game-support/p3r.md
index 2a25277b..a212af73 100644
--- a/src/game-support/p3r.md
+++ b/src/game-support/p3r.md
@@ -1,4 +1,7 @@
# Persona 3 Reload
+
{{#template ../templates/rating.md status=Gold date=02/04/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/p4g.md b/src/game-support/p4g.md
index 0bad1d1a..0c3ec82e 100644
--- a/src/game-support/p4g.md
+++ b/src/game-support/p4g.md
@@ -1,4 +1,7 @@
# Persona 4 Golden
+
{{#template ../templates/rating.md status=Garbage date=05/07/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/prey-2017.md b/src/game-support/prey-2017.md
index dc0090f4..7a72af9c 100644
--- a/src/game-support/prey-2017.md
+++ b/src/game-support/prey-2017.md
@@ -1,4 +1,7 @@
# Prey (2017)
+
{{#template ../templates/rating.md status=Silver date=05/05/24 installs=Yes opens=Yes}}
diff --git a/src/game-support/quake2.md b/src/game-support/quake2.md
index 74245a5b..670f72d9 100644
--- a/src/game-support/quake2.md
+++ b/src/game-support/quake2.md
@@ -1,4 +1,7 @@
# Quake II
+
{{#template ../templates/rating.md status=Gold date=04/04/23 installs=Yes opens=Yes}}
diff --git a/src/game-support/sekiro.md b/src/game-support/sekiro.md
index 80b95054..00a8e0de 100644
--- a/src/game-support/sekiro.md
+++ b/src/game-support/sekiro.md
@@ -1,4 +1,7 @@
# Sekiro: Shadows Die Twice
+
{{#template ../templates/rating.md status=Gold date=05/09/23 installs=Yes opens=Yes}}
diff --git a/src/game-support/sw-fallen-order.md b/src/game-support/sw-fallen-order.md
index bfa242fc..3f9aad5c 100644
--- a/src/game-support/sw-fallen-order.md
+++ b/src/game-support/sw-fallen-order.md
@@ -1,4 +1,7 @@
# Star Wars Jedi: Fallen Order
+
{{#template ../templates/rating.md status=Gold date=07/17/23 installs=Yes opens=Yes}}
diff --git a/src/game-support/sw-squadrons.md b/src/game-support/sw-squadrons.md
index 50ff006f..eac8ea1a 100644
--- a/src/game-support/sw-squadrons.md
+++ b/src/game-support/sw-squadrons.md
@@ -1,4 +1,7 @@
# Star Wars: Squadrons
+
{{#template ../templates/rating.md status=Gold date=05/11/23 installs=Yes opens=Yes}}
diff --git a/src/game-support/tcr6s.md b/src/game-support/tcr6s.md
index e8279eae..277d8205 100644
--- a/src/game-support/tcr6s.md
+++ b/src/game-support/tcr6s.md
@@ -1,4 +1,9 @@
# Tom Clancy's Rainbow Six Siege (Steam)
+
+
{{#template ../templates/rating.md status=Garbage date=05/05/24 installs=Yes opens=No}}
Tom Clancy's Rainbow Six Siege is currently **unplayable** in Whisky.
diff --git a/src/game-support/tsp-ud.md b/src/game-support/tsp-ud.md
index 2b422539..afd761db 100644
--- a/src/game-support/tsp-ud.md
+++ b/src/game-support/tsp-ud.md
@@ -1,4 +1,7 @@
# The Stanley Parable: Ultra Deluxe
+
{{#template ../templates/rating.md status=Gold date=05/05/24 installs=Yes opens=Yes}}
From 421ce64056d279d9b473e1fcece40eba221280c8 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Thu, 9 May 2024 19:25:11 -0700
Subject: [PATCH 04/17] Fix games with no aliases in games.json gen
---
scripts/generate-summary.mjs | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/scripts/generate-summary.mjs b/scripts/generate-summary.mjs
index 14276931..18bf5fd0 100755
--- a/scripts/generate-summary.mjs
+++ b/scripts/generate-summary.mjs
@@ -212,7 +212,7 @@ const main = async () => {
links.push({
name: file.name,
title,
- aliases: [],
+ aliases: [title.toLocaleLowerCase()]
});
continue;
}
From a297931cfdaf9ca37ab14da31bba47863c4bfcd2 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Thu, 9 May 2024 19:42:35 -0700
Subject: [PATCH 05/17] Fix file paths containg .md.html in generated
games.json
---
scripts/generate-summary.mjs | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/scripts/generate-summary.mjs b/scripts/generate-summary.mjs
index 18bf5fd0..5bf16f1f 100755
--- a/scripts/generate-summary.mjs
+++ b/scripts/generate-summary.mjs
@@ -3,7 +3,7 @@
* Generates a SUMMARY.md file for rust book.
*/
import { readdir, readFile, writeFile } from 'node:fs/promises';
-import { resolve, dirname, basename } from 'node:path';
+import { resolve, dirname, extname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { format } from 'node:util';
@@ -295,8 +295,12 @@ const main = async () => {
// Write the games.json file
const gamesOutFileContent = JSON.stringify(links.map((link) => {
+ // Strip the extension
+ const name = link.name;
+ const ext = extname(name);
+ const base = name.slice(0, -ext.length);
return {
- url: `/${GAME_SUPPORT_DIR}/${encodeURIComponent(basename(link.name) + '.html')}`,
+ url: `/${GAME_SUPPORT_DIR}/${encodeURIComponent(base + '.html')}`,
title: link.title,
aliases: link.aliases,
};
From 92586f129be4412461980d34c5c19cd5820f20c1 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Fri, 10 May 2024 20:54:10 -0700
Subject: [PATCH 06/17] Regen using script after new games were added
---
src/SUMMARY.md | 1 -
src/game-support/README.md | 1 -
2 files changed, 2 deletions(-)
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index a798caee..e232798b 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -53,7 +53,6 @@
- [Lego Star Wars: The Skywalker Saga](./game-support/lego-sw-skywalker-saga.md)
- [Lethal Company](./game-support/lethal-company.md)
- [Manor Lords](./game-support/manor-lords.md)
- - [Metal Gear Solid V: The Phantom Pain](./game-support/mgs-5.md)
- [Metro 2033 Redux](./game-support/metro-2033-rx.md)
- [Metro: Last Light Redux](./game-support/metro-ll-rx.md)
- [Metal Gear Solid V: The Phantom Pain](./game-support/mgs-5.md)
diff --git a/src/game-support/README.md b/src/game-support/README.md
index ab07e5f8..3fdeb944 100644
--- a/src/game-support/README.md
+++ b/src/game-support/README.md
@@ -64,7 +64,6 @@ title is partially left to the article author, but some general guidelines apply
- [Lego Star Wars: The Skywalker Saga](./lego-sw-skywalker-saga.md)
- [Lethal Company](./lethal-company.md)
- [Manor Lords](./manor-lords.md)
-- [Metal Gear Solid V: The Phantom Pain](./mgs-5.md)
- [Metro 2033 Redux](./metro-2033-rx.md)
- [Metro: Last Light Redux](./metro-ll-rx.md)
- [Metal Gear Solid V: The Phantom Pain](./mgs-5.md)
From b2f1fe4c32d79d4a60df4f75fa43dae2986b23a9 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Sat, 11 May 2024 19:05:09 -0700
Subject: [PATCH 07/17] Fix dates and add ratings to games.json
---
scripts/generate-summary.mjs | 158 ++++++++++++++++-----
src/game-support/among-us.md | 2 +-
src/game-support/battle-brothers.md | 2 +-
src/game-support/cities-skylines-2.md | 2 +-
src/game-support/counter-strike-2.md | 2 +-
src/game-support/dark-souls-remastered.md | 2 +-
src/game-support/dead-space-2023.md | 2 +-
src/game-support/elden-ring.md | 2 +-
src/game-support/fallout-4.md | 2 +-
src/game-support/fear-and-hunger.md | 2 +-
src/game-support/fortnite.md | 2 +
src/game-support/friends-vs-friends.md | 2 +-
src/game-support/half-life-1.md | 2 +-
src/game-support/half-life-2.md | 2 +-
src/game-support/jjba-asbr.md | 2 +-
src/game-support/kcd.md | 2 +-
src/game-support/kingsway.md | 2 +-
src/game-support/lego-sw-skywalker-saga.md | 2 +-
src/game-support/lethal-company.md | 2 +-
src/game-support/manor-lords.md | 2 +-
src/game-support/neon-white.md | 2 +-
src/game-support/p4g.md | 2 +-
src/game-support/palworld.md | 2 +-
src/game-support/r2modman.md | 2 +-
src/game-support/risk-of-rain-returns.md | 2 +-
src/game-support/stardew-valley.md | 2 +-
src/game-support/sw-fallen-order.md | 2 +-
src/game-support/warframe.md | 2 +-
28 files changed, 152 insertions(+), 60 deletions(-)
diff --git a/scripts/generate-summary.mjs b/scripts/generate-summary.mjs
index 5bf16f1f..40334836 100755
--- a/scripts/generate-summary.mjs
+++ b/scripts/generate-summary.mjs
@@ -103,6 +103,7 @@ const SCRIPT_GENERATE_START = '';
const SCRIPT_GENERATE_END = '';
// After the aliases start, we will find a json array of aliases (match everything until the closing comment)
const SCRIPT_ALIASES_REGEX = //s;
+const TEMPLATE_METADATA = /{{#template \.\.\/templates\/rating.md status=(Gold|Silver|Bronze|Garbage) date=(\d{2})\/(\d{2})\/(\d{2}) installs=(Yes|No) opens=(Yes|No)}}/;
const GAME_SUPPORT_DIR = 'game-support';
const INDEX_FILE = 'README.md';
const GAMES_OUT_FILE = 'games.json';
@@ -126,6 +127,96 @@ const getStartAndEndSections = (content) => {
return [start, end];
}
+/**
+ * Parse aliases from a file.
+ * @param {string} content
+ * @returns {[string[], null] | [null, 'not-found' | 'bad-json' | 'bad-json-format']}
+ */
+const parseAliases = (content) => {
+ // Match the aliases section
+ const aliasesMatch = content.match(SCRIPT_ALIASES_REGEX);
+ if (!aliasesMatch || aliasesMatch.length < 2) {
+ return [null, 'not-found'];
+ }
+
+ // Parse the aliases
+ let [aliasesParsed, aliasesError] = (() => {
+ try {
+ return [JSON.parse(aliasesMatch[1]), null];
+ } catch (error) {
+ return [null, error];
+ }
+ })();
+ if (aliasesError) {
+ return [null, 'bad-json'];
+ }
+ if (!aliasesParsed || !Array.isArray(aliasesParsed) || !aliasesParsed.every((alias) => typeof alias === 'string')) {
+ return [null, 'bad-json-format'];
+ }
+
+ return [aliasesParsed, null];
+}
+
+/**
+ * Parse rating information from a file.
+ * @param {string} content
+ * @returns {[{
+ * status: 'Gold' | 'Silver' | 'Bronze' | 'Garbage',
+ * date: Date,
+ * installs: 'Yes' | 'No',
+ * opens: 'Yes' | 'No',
+ * }, null] | [null, 'not-found' | 'bad-date']
+ */
+const parseRating = (content) => {
+ // Match the rating section
+ const ratingMatch = content.match(TEMPLATE_METADATA);
+ if (!ratingMatch || ratingMatch.length < 5) {
+ return [null, 'not-found'];
+ }
+
+ const status = ratingMatch[1];
+ // Guaranteed to be numbers by regex
+ const dateDD = parseInt(ratingMatch[2], 10);
+ const dateMM = parseInt(ratingMatch[3], 10);
+ const dateYY = parseInt(ratingMatch[4], 10);
+ const installs = ratingMatch[5];
+ const opens = ratingMatch[6];
+
+ // Make sure date month is < 12 and date day is < 31 because stupid people put MM/DD/YYYY
+ if (dateMM > 12 || dateDD > 31) {
+ return [null, 'bad-date'];
+ }
+
+
+ const date = new Date(Date.UTC(2000 + dateYY, dateMM - 1, dateDD));
+
+ // Also date can't be greater than today
+ if (isNaN(date.getTime()) || date > new Date()) {
+ return [null, 'bad-date'];
+ }
+
+ return [{
+ status,
+ date,
+ installs,
+ opens,
+ }, null];
+}
+
+/**
+ *
+ */
+
+/**
+ * Remove duplicates from an array.
+ * @param {T[]} arr
+ * @returns {T[]}
+ */
+const removeDuplicates = (arr) => {
+ return [...new Set(arr)];
+}
+
+
/**
* Main function.
* @returns {Promise}
@@ -182,7 +273,18 @@ const main = async () => {
// For all, generate a markdown link
/**
- * @type {Array<{name: string, path: string, title: string, aliases: string[]}>}
+ * @type {Array<{
+ * name: string,
+ * path: string,
+ * title: string,
+ * aliases: string[],
+ * rating: {
+ * status: 'Gold' | 'Silver' | 'Bronze' | 'Garbage',
+ * date: Date,
+ * installs: 'Yes' | 'No',
+ * opens: 'Yes' | 'No',
+ * }
+ * }>}
*/
const links = [];
for (const file of markdownFiles) {
@@ -207,47 +309,28 @@ const main = async () => {
const title = titleMatch[1];
// Look for aliases
- const aliasesMatch = fileContent.match(SCRIPT_ALIASES_REGEX);
- if (!aliasesMatch || aliasesMatch.length < 2) {
- links.push({
- name: file.name,
- title,
- aliases: [title.toLocaleLowerCase()]
- });
+ const [aliasesParsed, aliasesError] = parseAliases(fileContent);
+
+ if (aliasesError && aliasesError !== 'not-found') {
+ logging.warning('Failed to parse aliases in file %s: %s', filePath, aliasesError);
continue;
}
- let [aliasesParsed, aliasesError] = (() => {
- try {
- return [JSON.parse(aliasesMatch[1]), null];
- } catch (error) {
- return [null, error];
- }
- })();
- if (aliasesError) {
- logging.warning('Failed to parse aliases in file %s: %o', filePath, aliasesError);
- }
- if (!aliasesParsed || !Array.isArray(aliasesParsed) || !aliasesParsed.every((alias) => typeof alias === 'string')) {
- logging.warning('Invalid aliases in file %s: %o', filePath, aliasesParsed);
- aliasesParsed = null;
- }
+ const aliases = removeDuplicates([...(aliasesParsed ?? []), title].map((alias) => alias.toLowerCase()));
- // Remove duplicates
- const dupeMap = new Map();
- let aliases = (aliasesParsed ?? []).map((alias) => alias.toLocaleLowerCase());
- aliases.push(title.toLocaleLowerCase());
- aliases = aliases.filter((alias) => {
- if (dupeMap.has(alias)) {
- return false;
- }
- dupeMap.set(alias, true);
- return true;
- });
+ // Look for rating
+ const [ratingParsed, ratingError] = parseRating(fileContent);
+
+ if (ratingError) {
+ logging.warning('Failed to parse rating in file %s: %s', filePath, ratingError);
+ continue;
+ }
links.push({
name: file.name,
title,
- aliases
+ aliases,
+ rating: ratingParsed,
});
}
@@ -299,10 +382,17 @@ const main = async () => {
const name = link.name;
const ext = extname(name);
const base = name.slice(0, -ext.length);
+ link.rating.date instanceof Date || logging.error('Invalid date for %s', name);
return {
url: `/${GAME_SUPPORT_DIR}/${encodeURIComponent(base + '.html')}`,
title: link.title,
aliases: link.aliases,
+ rating: {
+ status: link.rating.status,
+ date: link.rating.date.toISOString(),
+ installs: link.rating.installs,
+ opens: link.rating.opens
+ },
};
}), null, 2);
const [_c, writeGamesError] = await writeFile(gamesOutFilePath, gamesOutFileContent)
diff --git a/src/game-support/among-us.md b/src/game-support/among-us.md
index b3679a61..fa1530ef 100644
--- a/src/game-support/among-us.md
+++ b/src/game-support/among-us.md
@@ -1,6 +1,6 @@
# Among Us
-{{#template ../templates/rating.md status=Gold date=04/29/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=29/04/24 installs=Yes opens=Yes}}
> [!NOTE]
> This game has an iPad Mac port through the App Store.
diff --git a/src/game-support/battle-brothers.md b/src/game-support/battle-brothers.md
index 08f6d8db..5f6241ec 100644
--- a/src/game-support/battle-brothers.md
+++ b/src/game-support/battle-brothers.md
@@ -1,6 +1,6 @@
# Battle Brothers
-{{#template ../templates/rating.md status=Garbage date=05/08/24 installs=Yes opens=No}}
+{{#template ../templates/rating.md status=Garbage date=08/05/24 installs=Yes opens=No}}
## Startup error
The game fails to launch with the following error message.
diff --git a/src/game-support/cities-skylines-2.md b/src/game-support/cities-skylines-2.md
index 787a49fd..6a5414fd 100644
--- a/src/game-support/cities-skylines-2.md
+++ b/src/game-support/cities-skylines-2.md
@@ -3,7 +3,7 @@
"Cities Skylines 2"
] -->
-{{#template ../templates/rating.md status=Bronze date=11/28/23 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Bronze date=28/11/23 installs=Yes opens=Yes}}
## Setup
diff --git a/src/game-support/counter-strike-2.md b/src/game-support/counter-strike-2.md
index 0f98fe34..087384be 100644
--- a/src/game-support/counter-strike-2.md
+++ b/src/game-support/counter-strike-2.md
@@ -4,7 +4,7 @@
"CS2"
] -->
-{{#template ../templates/rating.md status=Silver date=10/24/23 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Silver date=24/10/23 installs=Yes opens=Yes}}
## Setup
diff --git a/src/game-support/dark-souls-remastered.md b/src/game-support/dark-souls-remastered.md
index cf160664..56a122ae 100644
--- a/src/game-support/dark-souls-remastered.md
+++ b/src/game-support/dark-souls-remastered.md
@@ -3,6 +3,6 @@
"Dark Souls Remastered"
] -->
-{{#template ../templates/rating.md status=Gold date=03/12/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=12/03/24 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=570940}}
diff --git a/src/game-support/dead-space-2023.md b/src/game-support/dead-space-2023.md
index fa04cb6d..86d4931f 100644
--- a/src/game-support/dead-space-2023.md
+++ b/src/game-support/dead-space-2023.md
@@ -4,6 +4,6 @@
"Dead Space"
] -->
-{{#template ../templates/rating.md status=Gold date=04/28/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=28/04/24 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=1693980}}
\ No newline at end of file
diff --git a/src/game-support/elden-ring.md b/src/game-support/elden-ring.md
index 3aefdd1c..5b146052 100644
--- a/src/game-support/elden-ring.md
+++ b/src/game-support/elden-ring.md
@@ -1,6 +1,6 @@
# Elden Ring
-{{#template ../templates/rating.md status=Silver date=07/13/23 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Silver date=13/07/23 installs=Yes opens=Yes}}
## Setup
diff --git a/src/game-support/fallout-4.md b/src/game-support/fallout-4.md
index 113a128e..185f1961 100644
--- a/src/game-support/fallout-4.md
+++ b/src/game-support/fallout-4.md
@@ -1,6 +1,6 @@
# Fallout 4
-{{#template ../templates/rating.md status=Silver date=04/25/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Silver date=25/04/24 installs=Yes opens=Yes}}
The recent Next Gen update now allows the game to launch with audio enabled.
diff --git a/src/game-support/fear-and-hunger.md b/src/game-support/fear-and-hunger.md
index 2b4ac09c..f75a4c8c 100644
--- a/src/game-support/fear-and-hunger.md
+++ b/src/game-support/fear-and-hunger.md
@@ -1,6 +1,6 @@
# Fear and Hunger
-{{#template ../templates/rating.md status=Bronze date=03/28/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Bronze date=28/03/24 installs=Yes opens=Yes}}
## Setup
diff --git a/src/game-support/fortnite.md b/src/game-support/fortnite.md
index 0932f74d..1a7d386d 100644
--- a/src/game-support/fortnite.md
+++ b/src/game-support/fortnite.md
@@ -1,3 +1,5 @@
# Fortnite
+{{#template ../templates/rating.md status=Garbage date=21/07/17 installs=No opens=No}}
+
No.
\ No newline at end of file
diff --git a/src/game-support/friends-vs-friends.md b/src/game-support/friends-vs-friends.md
index d7f2e251..b15ad34a 100644
--- a/src/game-support/friends-vs-friends.md
+++ b/src/game-support/friends-vs-friends.md
@@ -1,5 +1,5 @@
# Friends vs Friends
-{{#template ../templates/rating.md status=Gold date=04/29/23 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=29/04/23 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=1785150}}
\ No newline at end of file
diff --git a/src/game-support/half-life-1.md b/src/game-support/half-life-1.md
index 6abfb093..8e9be85c 100644
--- a/src/game-support/half-life-1.md
+++ b/src/game-support/half-life-1.md
@@ -5,7 +5,7 @@
"Half Life 1"
] -->
-{{#template ../templates/rating.md status=Garbage date=04/16/24 installs=Yes opens=No}}
+{{#template ../templates/rating.md status=Garbage date=16/04/24 installs=Yes opens=No}}
Half-Life 1 is currently **unplayable** in Whiskey.
diff --git a/src/game-support/half-life-2.md b/src/game-support/half-life-2.md
index 2b0e1eb0..2b927b4f 100644
--- a/src/game-support/half-life-2.md
+++ b/src/game-support/half-life-2.md
@@ -3,6 +3,6 @@
"Half Life 2"
] -->
-{{#template ../templates/rating.md status=Gold date=04/16/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=16/04/24 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=220}}
diff --git a/src/game-support/jjba-asbr.md b/src/game-support/jjba-asbr.md
index e210abcd..ed2b6e6d 100644
--- a/src/game-support/jjba-asbr.md
+++ b/src/game-support/jjba-asbr.md
@@ -8,6 +8,6 @@
"JoJo's Bizarre Adventure"
] -->
-{{#template ../templates/rating.md status=Gold date=04/28/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=28/04/24 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=1372110}}
\ No newline at end of file
diff --git a/src/game-support/kcd.md b/src/game-support/kcd.md
index 757990ab..0dd3fa5b 100644
--- a/src/game-support/kcd.md
+++ b/src/game-support/kcd.md
@@ -4,6 +4,6 @@
"Kingdom Come"
] -->
-{{#template ../templates/rating.md status=Gold date=05/08/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=08/05/24 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=379430}}
diff --git a/src/game-support/kingsway.md b/src/game-support/kingsway.md
index f3187238..a8a26ff1 100644
--- a/src/game-support/kingsway.md
+++ b/src/game-support/kingsway.md
@@ -1,5 +1,5 @@
# Kingsway
-{{#template ../templates/rating.md status=Gold date=04/29/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=29/04/24 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=588950}}
\ No newline at end of file
diff --git a/src/game-support/lego-sw-skywalker-saga.md b/src/game-support/lego-sw-skywalker-saga.md
index 7bb6bef6..14c3818e 100644
--- a/src/game-support/lego-sw-skywalker-saga.md
+++ b/src/game-support/lego-sw-skywalker-saga.md
@@ -3,6 +3,6 @@
"Lego Star Wars The Skywalker Saga"
] -->
-{{#template ../templates/rating.md status=Gold date=04/29/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=29/04/24 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=920210}}
\ No newline at end of file
diff --git a/src/game-support/lethal-company.md b/src/game-support/lethal-company.md
index 0f01a52a..e555d655 100644
--- a/src/game-support/lethal-company.md
+++ b/src/game-support/lethal-company.md
@@ -1,6 +1,6 @@
# Lethal Company
-{{#template ../templates/rating.md status=Gold date=04/16/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=16/04/24 installs=Yes opens=Yes}}
## Sluggish Gameplay Fix
diff --git a/src/game-support/manor-lords.md b/src/game-support/manor-lords.md
index cc1d7964..1378cc64 100644
--- a/src/game-support/manor-lords.md
+++ b/src/game-support/manor-lords.md
@@ -1,5 +1,5 @@
# Manor Lords
-{{#template ../templates/rating.md status=Gold date=05/10/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=10/05/24 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=1363080}}
diff --git a/src/game-support/neon-white.md b/src/game-support/neon-white.md
index 651af17c..0b97be60 100644
--- a/src/game-support/neon-white.md
+++ b/src/game-support/neon-white.md
@@ -1,5 +1,5 @@
# Neon White
-{{#template ../templates/rating.md status=Gold date=04/29/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=29/04/24 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=1533420}}
\ No newline at end of file
diff --git a/src/game-support/p4g.md b/src/game-support/p4g.md
index 0c3ec82e..4a02b913 100644
--- a/src/game-support/p4g.md
+++ b/src/game-support/p4g.md
@@ -3,7 +3,7 @@
"P4G"
] -->
-{{#template ../templates/rating.md status=Garbage date=05/07/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Garbage date=07/05/24 installs=Yes opens=Yes}}
Game crashes when you enter a dungeon.
diff --git a/src/game-support/palworld.md b/src/game-support/palworld.md
index cba63cfc..d74f8ca1 100644
--- a/src/game-support/palworld.md
+++ b/src/game-support/palworld.md
@@ -1,6 +1,6 @@
# Palworld
-{{#template ../templates/rating.md status=Silver date=11/28/23 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Silver date=28/11/23 installs=Yes opens=Yes}}
## Setup
diff --git a/src/game-support/r2modman.md b/src/game-support/r2modman.md
index cbc930d7..b9d029fb 100644
--- a/src/game-support/r2modman.md
+++ b/src/game-support/r2modman.md
@@ -1,6 +1,6 @@
# r2modman
-{{#template ../templates/rating.md status=Silver date=02/27/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Silver date=27/02/24 installs=Yes opens=Yes}}
## Setup
diff --git a/src/game-support/risk-of-rain-returns.md b/src/game-support/risk-of-rain-returns.md
index acd8e869..8f7aa58e 100644
--- a/src/game-support/risk-of-rain-returns.md
+++ b/src/game-support/risk-of-rain-returns.md
@@ -1,5 +1,5 @@
# Risk of Rain Returns
-{{#template ../templates/rating.md status=Gold date=03/17/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=17/03/24 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=1337520}}
\ No newline at end of file
diff --git a/src/game-support/stardew-valley.md b/src/game-support/stardew-valley.md
index b18fea49..73ee8e35 100644
--- a/src/game-support/stardew-valley.md
+++ b/src/game-support/stardew-valley.md
@@ -1,6 +1,6 @@
# Stardew Valley
-{{#template ../templates/rating.md status=Gold date=02/28/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=28/02/24 installs=Yes opens=Yes}}
> [!NOTE]
> This game has a native Mac port.
diff --git a/src/game-support/sw-fallen-order.md b/src/game-support/sw-fallen-order.md
index 3f9aad5c..da105180 100644
--- a/src/game-support/sw-fallen-order.md
+++ b/src/game-support/sw-fallen-order.md
@@ -3,7 +3,7 @@
"Star Wars Jedi Fallen Order"
] -->
-{{#template ../templates/rating.md status=Gold date=07/17/23 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=17/07/23 installs=Yes opens=Yes}}
## Setup
diff --git a/src/game-support/warframe.md b/src/game-support/warframe.md
index 7d840929..1e2b8b9e 100644
--- a/src/game-support/warframe.md
+++ b/src/game-support/warframe.md
@@ -1,6 +1,6 @@
# Warframe
-{{#template ../templates/rating.md status=Bronze date=11/16/23 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Bronze date=16/11/23 installs=Yes opens=Yes}}
## Setup
- Go to Bottle Configuration -> Open Wine Configuration -> Libraries
From 43131138433bbb647631a95c73e4205743133635 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Sat, 11 May 2024 21:10:04 -0700
Subject: [PATCH 08/17] Add new games and fix one more date.
---
src/SUMMARY.md | 20 ++++++++------------
src/game-support/README.md | 21 ++++++++-------------
src/game-support/dagon.md | 2 +-
3 files changed, 17 insertions(+), 26 deletions(-)
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index eb31d967..4e49ffa1 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -9,18 +9,17 @@
- [Debugging](./debugging.md)
- [Game Support](./game-support/README.md)
+ - [Assassin's Creed: Director's Cut Edition](./game-support/ac-directors-cut.md)
- [Among Us](./game-support/among-us.md)
- [Armored Core VI: Fires of Rubicon](./game-support/armored-core-6.md)
- - [Assassin's Creed: Director's Cut Edition](./game-support/ac-directors-cut.md)
- [Battle Brothers](./game-support/battle-brothers.md)
- [Betrayer](./game-support/betrayer.md)
- [Blasphemous 2](./game-support/blasphemous-2.md)
- [Blitzkrieg 2 Anthology](./game-support/blitzkrieg-2-anthology.md)
- [Buckshot Roulette](./game-support/buckshot-roulette.md)
- - [Cities: Skylines 2](./game-support/cities-skylines-2.md)
- [Call of Cthulhu](./game-support/call-of-cthulhu.md)
+ - [Cities: Skylines 2](./game-support/cities-skylines-2.md)
- [Call of Juarez: Gunslinger](./game-support/coj-gunslinger.md)
- - [Cities: Skylines II](./game-support/cities-skylines-2.md)
- [Content Warning](./game-support/content-warning.md)
- [Contraband Police](./game-support/contraband-police.md)
- [Control](./game-support/control.md)
@@ -53,9 +52,9 @@
- [Geometry Wars 3: Dimensions Evolved](./game-support/gw3-dimensions-evolved.md)
- [Half-Life 1](./game-support/half-life-1.md)
- [Half-Life 2](./game-support/half-life-2.md)
- - [Hearts of Iron III](./game-support/hoi-3.md)
- [Hellblade: Senua's Sacrifice](./game-support/hellblade.md)
- [Hitman: Contracts](./game-support/hitman-3-c.md)
+ - [Hearts of Iron III](./game-support/hoi-3.md)
- [Horizon Zero Dawn](./game-support/horizon-zero-dawn.md)
- [JoJo's Bizarre Adventure: All-Star Battle R](./game-support/jjba-asbr.md)
- [Kingdom Come: Deliverance](./game-support/kcd.md)
@@ -65,11 +64,11 @@
- [LEGO Star Wars: The Skywalker Saga](./game-support/lego-sw-skywalker-saga.md)
- [Lethal Company](./game-support/lethal-company.md)
- [Manor Lords](./game-support/manor-lords.md)
+ - [Mount & Blade: With Fire & Sword](./game-support/mb-wfas.md)
- [Metro 2033 Redux](./game-support/metro-2033-rx.md)
- [Metro: Last Light Redux](./game-support/metro-ll-rx.md)
- [Metal Gear Solid V: The Phantom Pain](./game-support/mgs-5.md)
- [Monster Hunter World: Iceborne](./game-support/monster-hunter-world-iceborne.md)
- - [Mount & Blade: With Fire & Sword](./game-support/mb-wfas.md)
- [Neon White](./game-support/neon-white.md)
- [Overwatch 2](./game-support/overwatch-2.md)
- [Persona 3 Reload](./game-support/p3r.md)
@@ -78,29 +77,26 @@
- [People Playground](./game-support/people-playground.md)
- [Phasmophobia](./game-support/phasmophobia.md)
- [Prey \(2017\)](./game-support/prey-2017.md)
- - [Ruiner](./game-support/ruiner.md)
- [Quake II](./game-support/quake2.md)
- [r2modman](./game-support/r2modman.md)
- [Rain World](./game-support/rain-world.md)
- [Risk of Rain 2](./game-support/risk-of-rain-2.md)
- [Risk of Rain Returns](./game-support/risk-of-rain-returns.md)
+ - [Ruiner](./game-support/ruiner.md)
- [Satisfactory](./game-support/satisfactory.md)
- [Sekiro: Shadows Die Twice](./game-support/sekiro.md)
- [Skyrim SE](./game-support/skyrim-se.md)
- [Stardew Valley](./game-support/stardew-valley.md)
+ - [Stronghold Crusader HD](./game-support/stronghold-crusader-hd.md)
- [Star Wars Jedi: Fallen Order](./game-support/sw-fallen-order.md)
- [Star Wars: Squadrons](./game-support/sw-squadrons.md)
- [Tom Clancy's Rainbow Six Siege \(Steam\)](./game-support/tcr6s.md)
- [The Stanley Parable: Ultra Deluxe](./game-support/tsp-ud.md)
- - [Stronghold Crusader HD](./game-support/stronghold-crusader-hd.md)
- - [Tom Clancy's Rainbow Six Siege](./game-support/tcr6s.md)
- - [The Stanley Parable: Ultra Deluxe](./game-support/tsp-ud.md)
- - [The Vanishing of Ethan Carter](./game-support/vanishing-of-ethan-carter.md)
- - [The Witcher 3: Wild Hunt](./game-support/witcher3.md)
- - [The Wolf Among Us](./game-support/wolf-among-us.md)
- [Turbo Overkill](./game-support/turbo-overkill.md)
- [Ultrakill](./game-support/ultrakill.md)
- [Undertale](./game-support/undertale.md)
+ - [The Vanishing of Ethan Carter](./game-support/vanishing-of-ethan-carter.md)
- [Warframe](./game-support/warframe.md)
+ - [The Witcher 3: Wild Hunt](./game-support/witcher3.md)
- [The Wolf Among Us](./game-support/wolf-among-us.md)
\ No newline at end of file
diff --git a/src/game-support/README.md b/src/game-support/README.md
index c0725cbf..f2bd3770 100644
--- a/src/game-support/README.md
+++ b/src/game-support/README.md
@@ -20,18 +20,17 @@ title is partially left to the article author, but some general guidelines apply
### Index
+- [Assassin's Creed: Director's Cut Edition](./ac-directors-cut.md)
- [Among Us](./among-us.md)
- [Armored Core VI: Fires of Rubicon](./armored-core-6.md)
-- [Assassin's Creed: Director's Cut Edition](./ac-directors-cut.md)
- [Battle Brothers](./battle-brothers.md)
- [Betrayer](./betrayer.md)
- [Blasphemous 2](./blasphemous-2.md)
- [Blitzkrieg 2 Anthology](./blitzkrieg-2-anthology.md)
- [Buckshot Roulette](./buckshot-roulette.md)
-- [Cities: Skylines 2](./cities-skylines-2.md)
- [Call of Cthulhu](./call-of-cthulhu.md)
+- [Cities: Skylines 2](./cities-skylines-2.md)
- [Call of Juarez: Gunslinger](./coj-gunslinger.md)
-- [Cities: Skylines II](./cities-skylines-2.md)
- [Content Warning](./content-warning.md)
- [Contraband Police](./contraband-police.md)
- [Control](./control.md)
@@ -64,9 +63,9 @@ title is partially left to the article author, but some general guidelines apply
- [Geometry Wars 3: Dimensions Evolved](./gw3-dimensions-evolved.md)
- [Half-Life 1](./half-life-1.md)
- [Half-Life 2](./half-life-2.md)
-- [Hearts of Iron III](./hoi-3.md)
- [Hellblade: Senua's Sacrifice](./hellblade.md)
- [Hitman: Contracts](./hitman-3-c.md)
+- [Hearts of Iron III](./hoi-3.md)
- [Horizon Zero Dawn](./horizon-zero-dawn.md)
- [JoJo's Bizarre Adventure: All-Star Battle R](./jjba-asbr.md)
- [Kingdom Come: Deliverance](./kcd.md)
@@ -76,11 +75,11 @@ title is partially left to the article author, but some general guidelines apply
- [LEGO Star Wars: The Skywalker Saga](./lego-sw-skywalker-saga.md)
- [Lethal Company](./lethal-company.md)
- [Manor Lords](./manor-lords.md)
+- [Mount & Blade: With Fire & Sword](./mb-wfas.md)
- [Metro 2033 Redux](./metro-2033-rx.md)
- [Metro: Last Light Redux](./metro-ll-rx.md)
- [Metal Gear Solid V: The Phantom Pain](./mgs-5.md)
- [Monster Hunter World: Iceborne](./monster-hunter-world-iceborne.md)
-- [Mount & Blade: With Fire & Sword](./mb-wfas.md)
- [Neon White](./neon-white.md)
- [Overwatch 2](./overwatch-2.md)
- [Persona 3 Reload](./p3r.md)
@@ -89,30 +88,26 @@ title is partially left to the article author, but some general guidelines apply
- [People Playground](./people-playground.md)
- [Phasmophobia](./phasmophobia.md)
- [Prey \(2017\)](./prey-2017.md)
-- [Ruiner](./ruiner.md)
-- [Prey (2017)](./prey-2017.md)
- [Quake II](./quake2.md)
- [r2modman](./r2modman.md)
- [Rain World](./rain-world.md)
- [Risk of Rain 2](./risk-of-rain-2.md)
- [Risk of Rain Returns](./risk-of-rain-returns.md)
+- [Ruiner](./ruiner.md)
- [Satisfactory](./satisfactory.md)
- [Sekiro: Shadows Die Twice](./sekiro.md)
- [Skyrim SE](./skyrim-se.md)
- [Stardew Valley](./stardew-valley.md)
+- [Stronghold Crusader HD](./stronghold-crusader-hd.md)
- [Star Wars Jedi: Fallen Order](./sw-fallen-order.md)
- [Star Wars: Squadrons](./sw-squadrons.md)
- [Tom Clancy's Rainbow Six Siege \(Steam\)](./tcr6s.md)
- [The Stanley Parable: Ultra Deluxe](./tsp-ud.md)
-- [Stronghold Crusader HD](./stronghold-crusader-hd.md)
-- [Tom Clancy's Rainbow Six Siege](./tcr6s.md)
-- [The Stanley Parable: Ultra Deluxe](./tsp-ud.md)
-- [The Vanishing of Ethan Carter](./vanishing-of-ethan-carter.md)
-- [The Witcher 3: Wild Hunt](./witcher3.md)
-- [The Wolf Among Us](./wolf-among-us.md)
- [Turbo Overkill](./turbo-overkill.md)
- [Ultrakill](./ultrakill.md)
- [Undertale](./undertale.md)
+- [The Vanishing of Ethan Carter](./vanishing-of-ethan-carter.md)
- [Warframe](./warframe.md)
+- [The Witcher 3: Wild Hunt](./witcher3.md)
- [The Wolf Among Us](./wolf-among-us.md)
\ No newline at end of file
diff --git a/src/game-support/dagon.md b/src/game-support/dagon.md
index 0d840c39..a7cdb22b 100644
--- a/src/game-support/dagon.md
+++ b/src/game-support/dagon.md
@@ -1,5 +1,5 @@
# Dagon: by H. P. Lovecraft
-{{#template ../templates/rating.md status=Gold date=05/06/24 installs=Yes opens=Yes}}
+{{#template ../templates/rating.md status=Gold date=06/05/24 installs=Yes opens=Yes}}
{{#template ../templates/steam.md id=1481400}}
\ No newline at end of file
From 6c0b050218bb2fbc24ee31dda5b9a2fbab2107a3 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Sat, 11 May 2024 21:32:00 -0700
Subject: [PATCH 09/17] Update script to not update README.md and to use git to
get last updated
---
scripts/generate-summary.mjs | 91 +++++++++++-------------------------
src/game-support/fortnite.md | 2 +-
2 files changed, 29 insertions(+), 64 deletions(-)
diff --git a/scripts/generate-summary.mjs b/scripts/generate-summary.mjs
index 40334836..e212a97b 100755
--- a/scripts/generate-summary.mjs
+++ b/scripts/generate-summary.mjs
@@ -6,6 +6,7 @@ import { readdir, readFile, writeFile } from 'node:fs/promises';
import { resolve, dirname, extname } from 'node:path';
import { fileURLToPath } from 'node:url';
import { format } from 'node:util';
+import { execSync } from 'node:child_process';
/**
* Escapes a string for use in Markdown.
@@ -103,7 +104,7 @@ const SCRIPT_GENERATE_START = '';
const SCRIPT_GENERATE_END = '';
// After the aliases start, we will find a json array of aliases (match everything until the closing comment)
const SCRIPT_ALIASES_REGEX = //s;
-const TEMPLATE_METADATA = /{{#template \.\.\/templates\/rating.md status=(Gold|Silver|Bronze|Garbage) date=(\d{2})\/(\d{2})\/(\d{2}) installs=(Yes|No) opens=(Yes|No)}}/;
+const TEMPLATE_METADATA = /{{#template \.\.\/templates\/rating.md status=(Gold|Silver|Bronze|Garbage) installs=(Yes|No) opens=(Yes|No)}}/;
const GAME_SUPPORT_DIR = 'game-support';
const INDEX_FILE = 'README.md';
const GAMES_OUT_FILE = 'games.json';
@@ -162,50 +163,42 @@ const parseAliases = (content) => {
* @param {string} content
* @returns {[{
* status: 'Gold' | 'Silver' | 'Bronze' | 'Garbage',
- * date: Date,
* installs: 'Yes' | 'No',
* opens: 'Yes' | 'No',
- * }, null] | [null, 'not-found' | 'bad-date']
+ * }, null] | [null, 'not-found']
*/
const parseRating = (content) => {
// Match the rating section
const ratingMatch = content.match(TEMPLATE_METADATA);
- if (!ratingMatch || ratingMatch.length < 5) {
+ if (!ratingMatch || ratingMatch.length < 4) {
return [null, 'not-found'];
}
const status = ratingMatch[1];
- // Guaranteed to be numbers by regex
- const dateDD = parseInt(ratingMatch[2], 10);
- const dateMM = parseInt(ratingMatch[3], 10);
- const dateYY = parseInt(ratingMatch[4], 10);
- const installs = ratingMatch[5];
- const opens = ratingMatch[6];
-
- // Make sure date month is < 12 and date day is < 31 because stupid people put MM/DD/YYYY
- if (dateMM > 12 || dateDD > 31) {
- return [null, 'bad-date'];
- }
-
-
- const date = new Date(Date.UTC(2000 + dateYY, dateMM - 1, dateDD));
-
- // Also date can't be greater than today
- if (isNaN(date.getTime()) || date > new Date()) {
- return [null, 'bad-date'];
- }
+ const installs = ratingMatch[2];
+ const opens = ratingMatch[3];
return [{
status,
- date,
installs,
opens,
}, null];
}
/**
- *
+ * Get last updated date from a file.
+ * MUST BE IN GIT SOURCE TREE
+ * @param {string} path
+ * @returns {[Date, null] | [null, 'git-error']}
*/
+const getLastUpdated = (path) => {
+ try {
+ const lastUpdated = new Date(execSync(`git log -1 --format=%cd -- ${path}`).toString().trim());
+ return [lastUpdated, null];
+ } catch (error) {
+ return [null, 'git-error'];
+ }
+}
/**
* Remove duplicates from an array.
@@ -244,20 +237,6 @@ const main = async () => {
return 1;
}
- // Read the index file
- const [indexFileContent, indexFileReadError] = await readFile(indexFilePath, 'utf-8')
- .then((data) => [data, null])
- .catch((error) => [null, error]);
- if (indexFileReadError) {
- logging.error('Failed to read index file: %o', indexFileReadError);
- return 1;
- }
- const [indexFileStart, indexFileEnd] = getStartAndEndSections(indexFileContent);
- if (!indexFileStart === null || !indexFileEnd === null) {
- logging.error('Failed to find start and end sections in index file.');
- return 1;
- }
-
// Get all files in the game-support directory
const [gameSupportDirFiles, gameSupportDirFilesError] = await readdir(gameSupportDirPath, { withFileTypes: true })
.then((files) => [files, null])
@@ -277,10 +256,10 @@ const main = async () => {
* name: string,
* path: string,
* title: string,
+ * lastUpdated: Date,
* aliases: string[],
* rating: {
* status: 'Gold' | 'Silver' | 'Bronze' | 'Garbage',
- * date: Date,
* installs: 'Yes' | 'No',
* opens: 'Yes' | 'No',
* }
@@ -326,9 +305,17 @@ const main = async () => {
continue;
}
+ // Look for last updated
+ const [lastUpdated, lastUpdatedError] = getLastUpdated(filePath);
+ if (lastUpdatedError) {
+ logging.warning('Failed to get last updated in file %s: %s', filePath, lastUpdatedError);
+ continue;
+ }
+
links.push({
name: file.name,
title,
+ lastUpdated,
aliases,
rating: ratingParsed,
});
@@ -355,41 +342,19 @@ const main = async () => {
}
logging.info('SUMMARY.md generated successfully.');
- // Write the new index file
- const newIndexFileContent = [
- indexFileStart,
- SCRIPT_GENERATE_START,
- '\n',
- links.map((link) => {
- return `- [${markdownEscape(link.title)}](./${encodeURIComponent(link.name)})`;
- }).join('\n'),
- '\n',
- SCRIPT_GENERATE_END,
- indexFileEnd,
- ].join('');
- const [_b, writeIndexError] = await writeFile(indexFilePath, newIndexFileContent)
- .then(() => [null, null])
- .catch((error) => [null, error]);
- if (writeIndexError) {
- logging.error('Failed to write index file: %o', writeIndexError);
- return 1;
- }
- logging.info('Index file generated successfully.');
-
// Write the games.json file
const gamesOutFileContent = JSON.stringify(links.map((link) => {
// Strip the extension
const name = link.name;
const ext = extname(name);
const base = name.slice(0, -ext.length);
- link.rating.date instanceof Date || logging.error('Invalid date for %s', name);
return {
url: `/${GAME_SUPPORT_DIR}/${encodeURIComponent(base + '.html')}`,
title: link.title,
aliases: link.aliases,
+ lastUpdated: link.lastUpdated.toISOString(),
rating: {
status: link.rating.status,
- date: link.rating.date.toISOString(),
installs: link.rating.installs,
opens: link.rating.opens
},
diff --git a/src/game-support/fortnite.md b/src/game-support/fortnite.md
index 1a7d386d..6a22e70b 100644
--- a/src/game-support/fortnite.md
+++ b/src/game-support/fortnite.md
@@ -1,5 +1,5 @@
# Fortnite
-{{#template ../templates/rating.md status=Garbage date=21/07/17 installs=No opens=No}}
+{{#template ../templates/rating.md status=Garbage installs=No opens=No}}
No.
\ No newline at end of file
From bc228c961bfd0fbce15da83b7e2cd059ca1f0c09 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Sat, 11 May 2024 21:34:01 -0700
Subject: [PATCH 10/17] Refactor getLastUpdated function to handle invalid
dates
---
scripts/generate-summary.mjs | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/scripts/generate-summary.mjs b/scripts/generate-summary.mjs
index e212a97b..407d40ad 100755
--- a/scripts/generate-summary.mjs
+++ b/scripts/generate-summary.mjs
@@ -194,8 +194,14 @@ const parseRating = (content) => {
const getLastUpdated = (path) => {
try {
const lastUpdated = new Date(execSync(`git log -1 --format=%cd -- ${path}`).toString().trim());
+
+ if (isNaN(lastUpdated.getTime())) {
+ throw new Error('Invalid date');
+ }
+
return [lastUpdated, null];
} catch (error) {
+ logging.warning('Failed to get last updated for file %s: %o', path, error);
return [null, 'git-error'];
}
}
From 4d013df557ad27a6d87da9e193eb953dcdd365ea Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Sun, 12 May 2024 01:11:54 -0700
Subject: [PATCH 11/17] Refactor system to do linting.
---
scripts/generate-summary.mjs | 101 +---------------------------------
scripts/utils.mjs | 104 +++++++++++++++++++++++++++++++++++
2 files changed, 105 insertions(+), 100 deletions(-)
create mode 100644 scripts/utils.mjs
diff --git a/scripts/generate-summary.mjs b/scripts/generate-summary.mjs
index 407d40ad..d4ffd98b 100755
--- a/scripts/generate-summary.mjs
+++ b/scripts/generate-summary.mjs
@@ -8,97 +8,7 @@ import { fileURLToPath } from 'node:url';
import { format } from 'node:util';
import { execSync } from 'node:child_process';
-/**
- * Escapes a string for use in Markdown.
- * @type {Array<[RegExp, string]>}
- */
-const markdownEscapeItems = [
- [/\*/g, '\\*'], // Asterisks
- [/#/g, '\\#'], // Hashes
- [/\//g, '\\/'], // Slashes
- [/\(/g, '\\('], // Open parentheses
- [/\)/g, '\\)'], // Close parentheses
- [/\[/g, '\\['], // Open square brackets
- [/\]/g, '\\]'], // Close square brackets
- [//g, '>'], // Close angle brackets
- [/_/g, '\\_'], // Underscores
- [/`/g, '\\`'], // Backticks
-];
-
-/**
- * Escapes a string for use in Markdown.
- * @param {string} str
- */
-const markdownEscape = (str) => {
- for (const [regex, replacement] of markdownEscapeItems) {
- str = str.replace(regex, replacement);
- }
- return str;
-}
-
-/**
- * Fancy colors for console output.
- * @type {Object<'debug' | 'info' | 'warning' | 'error | 'bold' | 'reset', string>}
- */
-const colors = {
- debug: '\x1b[2m',
- info: '\x1b[36m',
- warning: '\x1b[33m',
- error: '\x1b[31m',
- bold: '\x1b[1m',
- reset: '\x1b[0m',
-};
-
-/**
- * Logs a message to the console with fancy colors.
- * @param {'debug' | 'info' | 'warning' | 'error'} type
- * @param {string} message
- * @param {...any} args
- */
-const fancyLog = (type, message, ...args) => {
- console.log(
- '%s%s[%s]%s%s %s%s',
- colors.bold,
- colors[type],
- type.toUpperCase(),
- colors.reset,
- colors[type],
- format(message, ...args),
- colors.reset,
- );
-}
-
-/**
- * Logging functions.
- * @type {Object<'debug' | 'info' | 'warning' | 'error', (message: string, ...args: any[]) => void>}
- */
-const logging = {
- /**
- * Logs an debug message.
- * @param {string} message
- * @param {...any} args
- */
- debug: (message, ...args) => fancyLog('debug', message, ...args),
- /**
- * Logs an info message.
- * @param {string} message
- * @param {...any} args
- */
- info: (message, ...args) => fancyLog('info', message, ...args),
- /**
- * Logs a warning message.
- * @param {string} message
- * @param {...any} args
- */
- warning: (message, ...args) => fancyLog('warning', message, ...args),
- /**
- * Logs an error message.
- * @param {string} message
- * @param {...any} args
- */
- error: (message, ...args) => fancyLog('error', message, ...args),
-};
+import { markdownEscape, logging, removeDuplicates } from './utils.mjs';
const SCRIPT_GENERATE_START = '';
const SCRIPT_GENERATE_END = '';
@@ -206,15 +116,6 @@ const getLastUpdated = (path) => {
}
}
-/**
- * Remove duplicates from an array.
- * @param {T[]} arr
- * @returns {T[]}
- */
-const removeDuplicates = (arr) => {
- return [...new Set(arr)];
-}
-
/**
* Main function.
diff --git a/scripts/utils.mjs b/scripts/utils.mjs
new file mode 100644
index 00000000..a9d8f5f1
--- /dev/null
+++ b/scripts/utils.mjs
@@ -0,0 +1,104 @@
+/**
+ * Escapes a string for use in Markdown.
+ * @type {Array<[RegExp, string]>}
+ */
+const markdownEscapeItems = [
+ [/\*/g, '\\*'], // Asterisks
+ [/#/g, '\\#'], // Hashes
+ [/\//g, '\\/'], // Slashes
+ [/\(/g, '\\('], // Open parentheses
+ [/\)/g, '\\)'], // Close parentheses
+ [/\[/g, '\\['], // Open square brackets
+ [/\]/g, '\\]'], // Close square brackets
+ [//g, '>'], // Close angle brackets
+ [/_/g, '\\_'], // Underscores
+ [/`/g, '\\`'], // Backticks
+];
+
+/**
+ * Escapes a string for use in Markdown.
+ * @param {string} str
+ */
+export const markdownEscape = (str) => {
+ for (const [regex, replacement] of markdownEscapeItems) {
+ str = str.replace(regex, replacement);
+ }
+ return str;
+}
+
+/**
+ * Fancy colors for console output.
+ * @type {Object<'debug' | 'info' | 'warning' | 'error | 'bold' | 'reset', string>}
+ */
+const colors = {
+ debug: '\x1b[2m',
+ info: '\x1b[36m',
+ warning: '\x1b[33m',
+ error: '\x1b[31m',
+ bold: '\x1b[1m',
+ reset: '\x1b[0m',
+};
+
+/**
+ * Logs a message to the console with fancy colors.
+ * @param {'debug' | 'info' | 'warning' | 'error'} type
+ * @param {string} message
+ * @param {...any} args
+ */
+export const fancyLog = (type, message, ...args) => {
+ console.log(
+ '%s%s[%s]%s%s %s%s',
+ colors.bold,
+ colors[type],
+ type.toUpperCase(),
+ colors.reset,
+ colors[type],
+ format(message, ...args),
+ colors.reset,
+ );
+}
+
+/**
+ * Logging functions.
+ * @property {(message: string, ...args: any[]) => void} debug
+ * @property {(message: string, ...args: any[]) => void} info
+ * @property {(message: string, ...args: any[]) => void} warning
+ * @property {(message: string, ...args: any[]) => void} error
+ */
+export const logging = {
+ /**
+ * Logs an debug message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ debug: (message, ...args) => fancyLog('debug', message, ...args),
+ /**
+ * Logs an info message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ info: (message, ...args) => fancyLog('info', message, ...args),
+ /**
+ * Logs a warning message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ warning: (message, ...args) => fancyLog('warning', message, ...args),
+ /**
+ * Logs an error message.
+ * @param {string} message
+ * @param {...any} args
+ */
+ error: (message, ...args) => fancyLog('error', message, ...args),
+};
+
+
+/**
+ * Remove duplicates from an array.
+ * @param {T[]} arr
+ * @returns {T[]}
+ */
+export const removeDuplicates = (arr) => {
+ return [...new Set(arr)];
+}
\ No newline at end of file
From e542c7aad142a759d87d301eac0bfc41ea96fed2 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Sun, 12 May 2024 01:12:28 -0700
Subject: [PATCH 12/17] Whoops, forgot to commit (I hope this gets squashed)
---
.github/workflows/lint.yml | 16 +
.github/workflows/mdbook.yml | 3 +-
README.md | 5 +-
scripts/.prettierrc.yaml | 7 +
scripts/core.mjs | 274 ++++++++++++++
scripts/generate-summary.mjs | 282 ---------------
scripts/generate.mjs | 289 +++++++++++++++
scripts/lint.mjs | 342 ++++++++++++++++++
scripts/utils.mjs | 81 ++++-
src/SUMMARY.md | 182 +++++-----
src/game-support/README.md | 2 +
src/game-support/ac-directors-cut.md | 5 +-
src/game-support/among-us.md | 3 +-
src/game-support/armored-core-6.md | 2 +-
src/game-support/battle-brothers.md | 1 +
src/game-support/betrayer.md | 3 +-
src/game-support/blasphemous-2.md | 3 +-
src/game-support/blitzkrieg-2-anthology.md | 3 +-
src/game-support/buckshot-roulette.md | 3 +-
src/game-support/call-of-cthulhu.md | 3 +-
src/game-support/cities-skylines-2.md | 2 +-
src/game-support/coj-gunslinger.md | 3 +-
src/game-support/content-warning.md | 3 +-
src/game-support/contraband-police.md | 3 +-
src/game-support/control.md | 3 +-
src/game-support/counter-strike-2.md | 2 +-
src/game-support/cyberpunk-2077.md | 3 +-
src/game-support/dagon.md | 5 +-
src/game-support/dark-souls-3.md | 2 +-
src/game-support/dead-space-2023.md | 2 +-
src/game-support/deadlink.md | 3 +-
src/game-support/deep-rock-galactic.md | 3 +-
src/game-support/diablo-4-battle-net.md | 4 +-
src/game-support/diablo-4-steam.md | 4 +-
src/game-support/dishonored-2.md | 3 +-
src/game-support/dishonored.md | 3 +-
src/game-support/dorfromantik.md | 3 +-
src/game-support/dying-light-2.md | 3 +-
src/game-support/elden-ring.md | 3 +-
src/game-support/elite-dangerous.md | 1 +
src/game-support/f1m23.md | 1 +
src/game-support/fallout-3-goty.md | 3 +
src/game-support/fallout-4.md | 1 +
src/game-support/fear-and-hunger.md | 3 +-
src/game-support/flatout.md | 3 +-
src/game-support/forgive-me-father-2.md | 3 +-
src/game-support/fortnite.md | 3 +-
src/game-support/friends-vs-friends.md | 3 +-
src/game-support/gta-5.md | 2 +-
src/game-support/gw2.md | 3 +-
src/game-support/gw3-dimensions-evolved.md | 2 +-
src/game-support/hellblade.md | 5 +-
src/game-support/hitman-3-c.md | 2 +-
src/game-support/hoi-3.md | 3 +-
src/game-support/horizon-zero-dawn.md | 1 +
src/game-support/jjba-asbr.md | 2 +-
src/game-support/kenshi.md | 1 +
src/game-support/kingsway.md | 3 +-
src/game-support/lego-sw-iii-clone-wars.md | 11 +-
src/game-support/lego-sw-skywalker-saga.md | 2 +-
src/game-support/lethal-company.md | 1 +
src/game-support/manor-lords.md | 1 +
src/game-support/mb-wfas.md | 3 +-
src/game-support/metro-2033-rx.md | 3 +-
src/game-support/metro-ll-rx.md | 2 +-
src/game-support/mgs-5.md | 2 +-
.../monster-hunter-world-iceborne.md | 2 +-
src/game-support/neon-white.md | 3 +-
src/game-support/overwatch-2.md | 3 +-
src/game-support/palworld.md | 1 +
src/game-support/people-playground.md | 3 +-
src/game-support/phasmophobia.md | 3 +-
src/game-support/prey-2017.md | 2 +-
src/game-support/quake2.md | 2 +-
src/game-support/r2modman.md | 3 +
src/game-support/rain-world.md | 3 +-
src/game-support/risk-of-rain-2.md | 3 +-
src/game-support/risk-of-rain-returns.md | 3 +-
src/game-support/ruiner.md | 3 +-
src/game-support/satisfactory.md | 3 +-
src/game-support/sekiro.md | 2 +-
src/game-support/skyrim-se.md | 1 +
src/game-support/stardew-valley.md | 3 +-
src/game-support/stronghold-crusader-hd.md | 5 +-
src/game-support/sw-squadrons.md | 4 +-
src/game-support/tcr6s.md | 2 +-
src/game-support/template.md | 3 +-
src/game-support/tsp-ud.md | 2 +-
src/game-support/turbo-overkill.md | 3 +-
src/game-support/ultrakill.md | 3 +-
src/game-support/undertale.md | 3 +-
src/game-support/vanishing-of-ethan-carter.md | 3 +-
src/game-support/warframe.md | 3 +-
src/game-support/witcher3.md | 3 +-
src/game-support/wolf-among-us.md | 3 +-
95 files changed, 1251 insertions(+), 465 deletions(-)
create mode 100644 .github/workflows/lint.yml
create mode 100644 scripts/.prettierrc.yaml
create mode 100644 scripts/core.mjs
delete mode 100755 scripts/generate-summary.mjs
create mode 100755 scripts/generate.mjs
create mode 100755 scripts/lint.mjs
diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml
new file mode 100644
index 00000000..857e9390
--- /dev/null
+++ b/.github/workflows/lint.yml
@@ -0,0 +1,16 @@
+on:
+ push:
+ pull_request:
+ workflow_dispatch:
+
+jobs:
+ lint:
+ runs-on: ubuntu-latest
+ env:
+ GITHUB_ACTIONS: true
+ steps:
+ - uses: actions/checkout@v4
+ - uses: actions/setup-node@v4
+ with:
+ node-version: latest
+ - run: node scripts/lint.mjs
\ No newline at end of file
diff --git a/.github/workflows/mdbook.yml b/.github/workflows/mdbook.yml
index a3583682..81ec1e3d 100644
--- a/.github/workflows/mdbook.yml
+++ b/.github/workflows/mdbook.yml
@@ -20,13 +20,14 @@ jobs:
env:
MDBOOK_VERSION: 0.4.37
CARGO_TERM_COLOR: always
+ GITHUB_ACTIONS: true
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: latest
- name: Generate summary
- run: node scripts/generate-summary.mjs
+ run: node scripts/generate.mjs
- uses: Swatinem/rust-cache@v2
- name: Install mdBook
run: |
diff --git a/README.md b/README.md
index 8d0597d0..029490cb 100644
--- a/README.md
+++ b/README.md
@@ -71,11 +71,12 @@ Documentation for Whisky.
```
-3. Run the `generate-summary` script with `./scripts/generate-summary.mjs` to update the `SUMMARY.md` and `game-support/README.md` files.
+3. Run the `generate` script with `./scripts/generate.mjs` to update `SUMMARY.md`.
This will also make the game appear in the sidebar of the book.
4. Create a pull request detailing the changes you made. Ensure that it's consise, yet readable and coherent.
- You will need to create a fork of `whisky-book` and push your changes there before creating a PR. Once you've done that, then you can submit a PR to merge your fork with `main`.
-5. Sit back, wait for PR reviews, and make changes as necessary.
+5. Run `./scripts/lint.mjs` to ensure that your changes are properly formatted.
+6. Sit back, wait for PR reviews, and make changes as necessary.
Have any questions about this process or anything Whisky-related? Stop by the [Discord](https://discord.gg/CsqAfs9CnM) and ask us a question! We're more than happy to help.
diff --git a/scripts/.prettierrc.yaml b/scripts/.prettierrc.yaml
new file mode 100644
index 00000000..8f5e8ffe
--- /dev/null
+++ b/scripts/.prettierrc.yaml
@@ -0,0 +1,7 @@
+singleQuote: true
+semi: true
+trailingComma: none
+arrowParens: avoid
+endOfLine: lf
+tabWidth: 4
+printWidth: 80
\ No newline at end of file
diff --git a/scripts/core.mjs b/scripts/core.mjs
new file mode 100644
index 00000000..24a5555b
--- /dev/null
+++ b/scripts/core.mjs
@@ -0,0 +1,274 @@
+/**
+ * @fileoverview Core shared functions between linting and generation.
+ */
+import { readdir } from 'node:fs/promises';
+import { getDirName, logging } from './utils.mjs';
+import { resolve } from 'node:path';
+import { request } from 'node:https';
+
+/**
+ * Core directory paths.
+ * @property {string} rootDir
+ * @property {string} srcDir
+ * @property {string} gameSupportDir
+ * @property {string} summaryFile
+ * @property {string} gamesJsonFile
+ * @readonly
+ */
+export const CORE_PATHS = {
+ rootDir: resolve(getDirName(), '..'),
+ srcDir: resolve(getDirName(), '..', 'src'),
+ gameSupportDir: resolve(getDirName(), '..', 'src', 'game-support'),
+ summaryFile: resolve(getDirName(), '..', 'src', 'SUMMARY.md'),
+ gamesJsonFile: resolve(getDirName(), '..', 'src', 'games.json')
+};
+
+export const SCRIPT_GENERATE_START = '';
+export const SCRIPT_GENERATE_END = '';
+
+/**
+ * Gets the start and end sections of a file.
+ * @param {string} content
+ * @returns {[[number, number], null] | [null, 'not-found' | 'invalid-position']}
+ */
+export const sectionsGetStartAndEnd = content => {
+ // The start and end sections both need to be present
+ const startMatch = content.indexOf(SCRIPT_GENERATE_START);
+ const endMatch = content.indexOf(SCRIPT_GENERATE_END);
+ if (startMatch === -1 || endMatch === -1) {
+ logging.debug('Failed to find start or end section in file.');
+ return [null, 'not-found'];
+ }
+
+ // The end section must come after the start section
+ if (startMatch > endMatch) {
+ logging.debug('End section comes before start section in file.');
+ return [null, 'invalid-position'];
+ }
+
+ // Get the start and end sections
+ return [[startMatch, endMatch], null];
+};
+
+export const TITLES_REGEX = /^# (.+)/;
+
+/**
+ * Gets the title of a file.
+ * @param {string} content
+ * @returns {[string, null] | [null, 'not-found']}
+ */
+export const getTitle = content => {
+ // Match the title
+ const titleMatch = content.match(TITLES_REGEX);
+ if (!titleMatch || titleMatch.length < 2) {
+ logging.debug('Failed to find title in file.');
+ return [null, 'not-found'];
+ }
+
+ return [titleMatch[1], null];
+};
+
+export const SCRIPT_ALIASES_REGEX = //;
+
+/**
+ * Parse aliases from a file.
+ * @param {string} content
+ * @returns {[string[], null] | [null, 'not-found' | 'bad-json' | 'bad-json-format']}
+ */
+export const parseAliases = content => {
+ // Match the aliases section
+ const aliasesMatch = content.match(SCRIPT_ALIASES_REGEX);
+ if (!aliasesMatch || aliasesMatch.length < 2) {
+ logging.debug('Failed to find aliases section in file.');
+ return [null, 'not-found'];
+ }
+
+ // Parse the aliases
+ let [aliasesParsed, aliasesError] = (() => {
+ try {
+ return [JSON.parse(aliasesMatch[1]), null];
+ } catch (error) {
+ logging.debug('Failed to parse aliases section in file: %o', error);
+ return [null, error];
+ }
+ })();
+ if (aliasesError) {
+ return [null, 'bad-json'];
+ }
+ if (
+ !aliasesParsed ||
+ !Array.isArray(aliasesParsed) ||
+ !aliasesParsed.every(alias => typeof alias === 'string')
+ ) {
+ logging.debug(
+ 'Failed to parse aliases section in file: not an array of strings.'
+ );
+ return [null, 'bad-json-format'];
+ }
+
+ return [aliasesParsed, null];
+};
+
+export const REVIEW_METADATA_REGEX =
+ /{{#template \.\.\/templates\/rating.md status=(Platinum|Gold|Silver|Bronze|Garbage) installs=(Yes|No) opens=(Yes|No)}}/;
+
+/**
+ * @typedef {'Platinum' | 'Gold' | 'Silver' | 'Bronze' | 'Garbage'} RatingStatus
+ */
+
+/**
+ * Parse rating information from a file.
+ * @param {string} content
+ * @returns {[{
+ * status: RatingStatus,
+ * installs: 'Yes' | 'No',
+ * opens: 'Yes' | 'No',
+ * }, null] | [null, 'not-found']
+ */
+export const parseReviewMetadata = content => {
+ // Match the rating section
+ const ratingMatch = content.match(REVIEW_METADATA_REGEX);
+ if (!ratingMatch || ratingMatch.length < 4) {
+ logging.debug('Failed to find rating section in file.');
+ return [null, 'not-found'];
+ }
+
+ const status = ratingMatch[1];
+ const installs = ratingMatch[2];
+ const opens = ratingMatch[3];
+
+ return [
+ {
+ status,
+ installs,
+ opens
+ },
+ null
+ ];
+};
+
+export const GAMES_EMBEDS_METADATA = {
+ steam: /{{#template ..\/templates\/steam.md id=(\d+)}}/
+};
+
+/**
+ * @typedef {{
+ * type: 'steam',
+ * id: number,
+ * }} GameEmbed
+ */
+
+/**
+ * Get game embeds from a file.
+ * @param {string} content
+ * @returns {[[GameEmbed, number] | null, 'not-found' | 'multiple-found']}
+ *
+ */
+export const parseGameEmbeds = content => {
+ // Match the game embeds section
+ /**
+ * @type {{
+ * location: number,
+ * embed: GameEmbed
+ * }[]}
+ */
+ const embeds = [];
+ for (const [type, regex] of Object.entries(GAMES_EMBEDS_METADATA)) {
+ const match = content.match(regex);
+ if (match && match.length > 1) {
+ embeds.push({
+ location: match.index,
+ embed: {
+ type,
+ id: parseInt(match[1])
+ }
+ });
+ }
+ }
+
+ if (embeds.length === 0) {
+ logging.debug('Failed to find game embeds section in file.');
+ return [null, 'not-found'];
+ }
+ if (embeds.length > 1) {
+ logging.debug('Found multiple game embeds section in file.');
+ return [null, 'multiple-found'];
+ }
+
+ return [[embeds[0].embed, embeds[0].location], null];
+};
+
+/**
+ * Use webservers to check that a GameEmbed is valid.
+ * @param {GameEmbed} embed
+ * @returns {Promise<[boolean, null] | [null, 'invalid-embed' | 'web-request-failed']>}
+ */
+export const checkGameEmbed = async embed => {
+ if (embed.type === 'steam') {
+ const steamUrl =
+ 'https://store.steampowered.com/app/' +
+ encodeURIComponent(embed.id);
+ const url = new URL(steamUrl);
+ /**
+ * @type {import('http').IncomingMessage}
+ */
+ const [response, responseError] = await new Promise(resolve => {
+ request(
+ {
+ hostname: url.hostname,
+ port: 443,
+ path: url.pathname,
+ method: 'GET',
+ headers: {
+ 'User-Agent': 'WhiskyBookBot/1.0'
+ }
+ },
+ resolve
+ ).end();
+ })
+ .then(response => [response, null])
+ .catch(error => [null, error]);
+ if (responseError) {
+ logging.debug('Failed to request Steam URL: %o', responseError);
+ return [null, 'web-request-failed'];
+ }
+
+ return [response.statusCode === 200, null];
+ }
+
+ return [false, 'invalid-embed'];
+};
+
+const FILES_SKIP = ['README.md', 'template.md'];
+
+/**
+ * Gets all markdown files in the game-support directory.
+ * @returns {Promise<[string[], null] | [null, 'failed-to-read-dir']>}
+ */
+export const getMarkdownFiles = async () => {
+ const [gameSupportDirFiles, gameSupportDirFilesError] = await readdir(
+ CORE_PATHS.gameSupportDir,
+ { withFileTypes: true }
+ )
+ .then(files => [files, null])
+ .catch(error => [null, error]);
+ if (gameSupportDirFilesError) {
+ logging.error(
+ 'Failed to read game-support directory: %o',
+ gameSupportDirFilesError
+ );
+ return [null, 'failed-to-read-dir'];
+ }
+
+ return [
+ gameSupportDirFiles
+ .filter(
+ file =>
+ file.isFile() &&
+ file.name.endsWith('.md') &&
+ !FILES_SKIP.includes(file.name)
+ )
+ .map(file => resolve(CORE_PATHS.gameSupportDir, file.name)),
+ null
+ ];
+};
diff --git a/scripts/generate-summary.mjs b/scripts/generate-summary.mjs
deleted file mode 100755
index d4ffd98b..00000000
--- a/scripts/generate-summary.mjs
+++ /dev/null
@@ -1,282 +0,0 @@
-#!/usr/bin/env node
-/**
- * Generates a SUMMARY.md file for rust book.
- */
-import { readdir, readFile, writeFile } from 'node:fs/promises';
-import { resolve, dirname, extname } from 'node:path';
-import { fileURLToPath } from 'node:url';
-import { format } from 'node:util';
-import { execSync } from 'node:child_process';
-
-import { markdownEscape, logging, removeDuplicates } from './utils.mjs';
-
-const SCRIPT_GENERATE_START = '';
-const SCRIPT_GENERATE_END = '';
-// After the aliases start, we will find a json array of aliases (match everything until the closing comment)
-const SCRIPT_ALIASES_REGEX = //s;
-const TEMPLATE_METADATA = /{{#template \.\.\/templates\/rating.md status=(Gold|Silver|Bronze|Garbage) installs=(Yes|No) opens=(Yes|No)}}/;
-const GAME_SUPPORT_DIR = 'game-support';
-const INDEX_FILE = 'README.md';
-const GAMES_OUT_FILE = 'games.json';
-const FILES_SKIP = ['README.md', 'template.md'];
-
-/**
- * Gets the start and end sections of a file.
- * @param {string} content
- * @returns {[string | null, string | null]}
- */
-const getStartAndEndSections = (content) => {
- if (
- content.split(SCRIPT_GENERATE_START).length !== 2 ||
- content.split(SCRIPT_GENERATE_END).length !== 2
- ) {
- return [null, null];
- }
-
- const [start, replaceAndEnd] = content.split(SCRIPT_GENERATE_START);
- const [_, end] = replaceAndEnd.split(SCRIPT_GENERATE_END);
- return [start, end];
-}
-
-/**
- * Parse aliases from a file.
- * @param {string} content
- * @returns {[string[], null] | [null, 'not-found' | 'bad-json' | 'bad-json-format']}
- */
-const parseAliases = (content) => {
- // Match the aliases section
- const aliasesMatch = content.match(SCRIPT_ALIASES_REGEX);
- if (!aliasesMatch || aliasesMatch.length < 2) {
- return [null, 'not-found'];
- }
-
- // Parse the aliases
- let [aliasesParsed, aliasesError] = (() => {
- try {
- return [JSON.parse(aliasesMatch[1]), null];
- } catch (error) {
- return [null, error];
- }
- })();
- if (aliasesError) {
- return [null, 'bad-json'];
- }
- if (!aliasesParsed || !Array.isArray(aliasesParsed) || !aliasesParsed.every((alias) => typeof alias === 'string')) {
- return [null, 'bad-json-format'];
- }
-
- return [aliasesParsed, null];
-}
-
-/**
- * Parse rating information from a file.
- * @param {string} content
- * @returns {[{
- * status: 'Gold' | 'Silver' | 'Bronze' | 'Garbage',
- * installs: 'Yes' | 'No',
- * opens: 'Yes' | 'No',
- * }, null] | [null, 'not-found']
- */
-const parseRating = (content) => {
- // Match the rating section
- const ratingMatch = content.match(TEMPLATE_METADATA);
- if (!ratingMatch || ratingMatch.length < 4) {
- return [null, 'not-found'];
- }
-
- const status = ratingMatch[1];
- const installs = ratingMatch[2];
- const opens = ratingMatch[3];
-
- return [{
- status,
- installs,
- opens,
- }, null];
-}
-
-/**
- * Get last updated date from a file.
- * MUST BE IN GIT SOURCE TREE
- * @param {string} path
- * @returns {[Date, null] | [null, 'git-error']}
- */
-const getLastUpdated = (path) => {
- try {
- const lastUpdated = new Date(execSync(`git log -1 --format=%cd -- ${path}`).toString().trim());
-
- if (isNaN(lastUpdated.getTime())) {
- throw new Error('Invalid date');
- }
-
- return [lastUpdated, null];
- } catch (error) {
- logging.warning('Failed to get last updated for file %s: %o', path, error);
- return [null, 'git-error'];
- }
-}
-
-
-/**
- * Main function.
- * @returns {Promise}
- */
-const main = async () => {
- logging.info('Generating SUMMARY.md...');
- // Get local file paths
- const dirName = resolve(dirname(fileURLToPath(import.meta.url)), '../', 'src');
- const summaryFilePath = resolve(dirName, 'SUMMARY.md');
- const indexFilePath = resolve(dirName, 'game-support', INDEX_FILE);
- const gameSupportDirPath = resolve(dirName, GAME_SUPPORT_DIR);
- const gamesOutFilePath = resolve(dirName, GAMES_OUT_FILE);
-
- // Read the SUMMARY.md file
- const [summaryFileContent, summaryFileReadError] = await readFile(summaryFilePath, 'utf-8')
- .then((data) => [data, null])
- .catch((error) => [null, error]);
- if (summaryFileReadError) {
- logging.error('Failed to read SUMMARY.md: %o', summaryFileReadError);
- return 1;
- }
- const [summaryFileStart, summaryFileEnd] = getStartAndEndSections(summaryFileContent);
- if (!summaryFileStart === null || !summaryFileEnd === null) {
- logging.error('Failed to find start and end sections in SUMMARY.md.');
- return 1;
- }
-
- // Get all files in the game-support directory
- const [gameSupportDirFiles, gameSupportDirFilesError] = await readdir(gameSupportDirPath, { withFileTypes: true })
- .then((files) => [files, null])
- .catch((error) => [null, error]);
- if (gameSupportDirFilesError) {
- logging.error('Failed to read game-support directory: %o', gameSupportDirFilesError);
- return 1;
- }
-
- // Filter out directories and non-markdown files
- const markdownFiles = gameSupportDirFiles
- .filter((file) => file.isFile() && file.name.endsWith('.md') && !FILES_SKIP.includes(file.name));
-
- // For all, generate a markdown link
- /**
- * @type {Array<{
- * name: string,
- * path: string,
- * title: string,
- * lastUpdated: Date,
- * aliases: string[],
- * rating: {
- * status: 'Gold' | 'Silver' | 'Bronze' | 'Garbage',
- * installs: 'Yes' | 'No',
- * opens: 'Yes' | 'No',
- * }
- * }>}
- */
- const links = [];
- for (const file of markdownFiles) {
- // Read the file
- const filePath = resolve(gameSupportDirPath, file.name);
- const [fileContent, fileReadError] = await readFile(filePath, 'utf-8')
- .then((data) => [data, null])
- .catch((error) => [null, error]);
- if (fileReadError) {
- logging.error('Failed to read file %s: %o', filePath, fileReadError);
- return 1;
- }
-
- // Get the title
- const titleMatch = fileContent.match(/^# (.+)$/m);
- if (!titleMatch || titleMatch.length < 2) {
- logging.warning('Failed to find title in file %s. "%s" will be skipped.', filePath, file.name);
- continue;
- }
-
- // Add the link
- const title = titleMatch[1];
-
- // Look for aliases
- const [aliasesParsed, aliasesError] = parseAliases(fileContent);
-
- if (aliasesError && aliasesError !== 'not-found') {
- logging.warning('Failed to parse aliases in file %s: %s', filePath, aliasesError);
- continue;
- }
-
- const aliases = removeDuplicates([...(aliasesParsed ?? []), title].map((alias) => alias.toLowerCase()));
-
- // Look for rating
- const [ratingParsed, ratingError] = parseRating(fileContent);
-
- if (ratingError) {
- logging.warning('Failed to parse rating in file %s: %s', filePath, ratingError);
- continue;
- }
-
- // Look for last updated
- const [lastUpdated, lastUpdatedError] = getLastUpdated(filePath);
- if (lastUpdatedError) {
- logging.warning('Failed to get last updated in file %s: %s', filePath, lastUpdatedError);
- continue;
- }
-
- links.push({
- name: file.name,
- title,
- lastUpdated,
- aliases,
- rating: ratingParsed,
- });
- }
-
- // Write the new SUMMARY.md file
- const newSummaryFileContent = [
- summaryFileStart,
- SCRIPT_GENERATE_START,
- '\n',
- links.map((link) => {
- return ` - [${markdownEscape(link.title)}](./${GAME_SUPPORT_DIR}/${encodeURIComponent(link.name)})`;
- }).join('\n'),
- '\n',
- SCRIPT_GENERATE_END,
- summaryFileEnd,
- ].join('');
- const [_a, writeError] = await writeFile(summaryFilePath, newSummaryFileContent)
- .then(() => [null, null])
- .catch((error) => [null, error]);
- if (writeError) {
- logging.error('Failed to write SUMMARY.md: %o', writeError);
- return 1;
- }
- logging.info('SUMMARY.md generated successfully.');
-
- // Write the games.json file
- const gamesOutFileContent = JSON.stringify(links.map((link) => {
- // Strip the extension
- const name = link.name;
- const ext = extname(name);
- const base = name.slice(0, -ext.length);
- return {
- url: `/${GAME_SUPPORT_DIR}/${encodeURIComponent(base + '.html')}`,
- title: link.title,
- aliases: link.aliases,
- lastUpdated: link.lastUpdated.toISOString(),
- rating: {
- status: link.rating.status,
- installs: link.rating.installs,
- opens: link.rating.opens
- },
- };
- }), null, 2);
- const [_c, writeGamesError] = await writeFile(gamesOutFilePath, gamesOutFileContent)
- .then(() => [null, null])
- .catch((error) => [null, error]);
- if (writeGamesError) {
- logging.error('Failed to write games.json: %o', writeGamesError);
- return 1;
- }
- logging.info('games.json generated successfully.');
-
- return 0;
-};
-
-main().then((code) => process.exit(code));
\ No newline at end of file
diff --git a/scripts/generate.mjs b/scripts/generate.mjs
new file mode 100755
index 00000000..1f4cf313
--- /dev/null
+++ b/scripts/generate.mjs
@@ -0,0 +1,289 @@
+#!/usr/bin/env node
+/**
+ * @fileoverview Generates the SUMMARY.md and games.json files.
+ */
+
+import { readFile, writeFile } from 'node:fs/promises';
+import { extname, basename } from 'node:path';
+
+import {
+ markdownEscape,
+ logging,
+ removeDuplicates,
+ getLastUpdated
+} from './utils.mjs';
+import {
+ CORE_PATHS,
+ sectionsGetStartAndEnd,
+ getMarkdownFiles,
+ getTitle,
+ parseAliases,
+ parseReviewMetadata,
+ parseGameEmbeds,
+ SCRIPT_GENERATE_START,
+ SCRIPT_GENERATE_END
+} from './core.mjs';
+
+/**
+ * @typedef {import('./core.mjs').GameEmbed} GameEmbed
+ * @typedef {import('./core.mjs').RatingStatus} RatingStatus
+ */
+
+/**
+ * @typedef {{
+ * title: string,
+ * lastUpdated: Date,
+ * aliases: string[],
+ * rating: {
+ * status: RatingStatus,
+ * installs: boolean,
+ * opens: boolean,
+ * },
+ * embed: GameEmbed | null,
+ * }} GameMetadata
+ */
+
+/**
+ * Generate GameMetadata for every game.
+ * @returns {Promise<[{
+ * path: string,
+ * game: GameMetadata,
+ * }[], null] | [null, 'folder-read-error']>}
+ */
+export const generateGameMetadata = async () => {
+ const [markdownFiles, markdownFilesError] = await getMarkdownFiles();
+ if (markdownFilesError) {
+ logging.error('Failed to get markdown files: %s', markdownFilesError);
+ return [null, 'folder-read-error'];
+ }
+
+ /**
+ * @type {{
+ * path: string,
+ * game: GameMetadata,
+ * }[]}
+ */
+ const links = [];
+ for (const file of markdownFiles) {
+ // Read the file
+ /**
+ * @type {[string, null] | [null, Error]}
+ */
+ const [fileContent, fileContentError] = await readFile(file, 'utf-8')
+ .then(data => [data, null])
+ .catch(error => [null, error]);
+ if (fileContentError) {
+ logging.error(
+ 'Failed to read file %s: %o',
+ filePath,
+ fileContentError
+ );
+ continue;
+ }
+
+ // Get the title
+ const [title, titleError] = getTitle(fileContent);
+ if (titleError) {
+ logging.warning(
+ 'Failed to get title in file %s: %s',
+ filePath,
+ titleError
+ );
+ continue;
+ }
+
+ // Look for aliases
+ const [aliasesParsed, aliasesError] = parseAliases(fileContent);
+ if (aliasesError && aliasesError !== 'not-found') {
+ logging.error(
+ 'Failed to parse aliases in file %s: %s',
+ filePath,
+ aliasesError
+ );
+ continue;
+ }
+
+ const aliases = removeDuplicates(
+ [...(aliasesParsed ?? []), title].map(alias => alias.toLowerCase())
+ );
+
+ // Look for rating
+ const [ratingParsed, ratingError] = parseReviewMetadata(fileContent);
+ if (ratingError) {
+ logging.error(
+ 'Failed to parse rating in file %s: %s',
+ filePath,
+ ratingError
+ );
+ continue;
+ }
+
+ // Look for embed
+ const [embedData, embedError] = parseGameEmbeds(fileContent);
+ if (embedError && embedError !== 'not-found') {
+ logging.error(
+ 'Failed to parse embed in file %s: %s',
+ filePath,
+ embedError
+ );
+ continue;
+ }
+ const embed = embedData && embedData.length > 0 ? embedData[0] : [];
+
+ // Look for last updated
+ const [lastUpdated, lastUpdatedError] = getLastUpdated(file);
+ if (lastUpdatedError) {
+ logging.error(
+ 'Failed to get last updated in file %s: %s',
+ file,
+ lastUpdatedError
+ );
+ continue;
+ }
+
+ links.push({
+ path: file,
+ game: {
+ title,
+ lastUpdated,
+ aliases,
+ rating: {
+ status: ratingParsed.status,
+ installs: ratingParsed.installs === 'Yes',
+ opens: ratingParsed.opens === 'Yes'
+ },
+ embed: embedError ? null : embed
+ }
+ });
+ }
+
+ return [links, null];
+};
+
+/**
+ * Generate the sidebar links.
+ * @param {{
+ * path: string,
+ * game: GameMetadata
+ * }[]} links
+ * @returns {string}
+ */
+export const generateLinks = links => {
+ return '\n' + links
+ .map(link => {
+ return ` - [${markdownEscape(link.game.title)}](/game-support/${encodeURIComponent(basename(link.path))})`;
+ })
+ .join('\n') + '\n';
+}
+
+/**
+ * Generate the games.json file.
+ * @param {{
+ * path: string,
+ * game: GameMetadata
+ * }[]} links
+ * @returns {string}
+ */
+export const generateGamesJson = links => {
+ return JSON.stringify(
+ links.map(link => {
+ // Strip the extension
+ const name = basename(link.path);
+ const ext = extname(name);
+ const base = name.slice(0, -ext.length);
+ return {
+ url: `/game-support/${encodeURIComponent(base + '.html')}`,
+ title: link.game.title,
+ aliases: link.game.aliases,
+ lastUpdated: link.game.lastUpdated.toISOString(),
+ rating: {
+ status: link.game.rating.status,
+ installs: link.game.rating.installs,
+ opens: link.game.rating.opens
+ },
+ embed: link.game.embed
+ };
+ }),
+ null,
+ 2
+ );
+}
+
+/**
+ * Main function.
+ * @returns {Promise}
+ */
+const main = async () => {
+ logging.info('Generating SUMMARY.md and games.json...');
+ const [gameData, gameDataError] = await generateGameMetadata();
+ if (gameDataError) {
+ return 1;
+ }
+
+
+ // Get the SUMMARY.md file
+ /**
+ * @type {[string, null] | [null, Error]}
+ */
+ const [summaryFile, summaryFileError] = await readFile(
+ CORE_PATHS.summaryFile,
+ 'utf-8'
+ )
+ .then(data => [data, null])
+ .catch(error => [null, error]);
+ if (summaryFileError) {
+ logging.error('Failed to read SUMMARY.md: %o', summaryFileError);
+ return 1;
+ }
+
+ // Get the start and end of the SUMMARY.md file
+ const [summarySections, summarySectionsError] = sectionsGetStartAndEnd(
+ summaryFile
+ );
+ if (summarySectionsError) {
+ logging.error('Failed to find start and end sections in SUMMARY.md.');
+ return 1;
+ }
+ const [start, end] = summarySections;
+
+ // Write the new SUMMARY.md file
+ const newSummaryFileContent = [
+ summaryFile.slice(0, start),
+ SCRIPT_GENERATE_START,
+ generateLinks(gameData),
+ SCRIPT_GENERATE_END,
+ summaryFile.slice(end + SCRIPT_GENERATE_END.length)
+ ].join('');
+ /**
+ * @type {[string, null] | [null, Error]}
+ */
+ const [_1, writeError] = await writeFile(
+ CORE_PATHS.summaryFile,
+ newSummaryFileContent
+ )
+ .then(() => [null, null])
+ .catch(error => [null, error]);
+ if (writeError) {
+ logging.error('Failed to write SUMMARY.md: %o', writeError);
+ return 1;
+ }
+
+ logging.info('SUMMARY.md generated successfully.');
+
+ // Write the games.json file
+ const [_3, writeGamesError] = await writeFile(
+ CORE_PATHS.gamesJsonFile,
+ generateGamesJson(gameData)
+ )
+ .then(() => [null, null])
+ .catch(error => [null, error]);
+ if (writeGamesError) {
+ logging.error('Failed to write games.json: %o', writeGamesError);
+ return 1;
+ }
+ logging.info('games.json generated successfully.');
+
+ return 0;
+};
+
+main().then(code => process.exit(code));
diff --git a/scripts/lint.mjs b/scripts/lint.mjs
new file mode 100755
index 00000000..bdddfb5f
--- /dev/null
+++ b/scripts/lint.mjs
@@ -0,0 +1,342 @@
+#!/usr/bin/env node
+
+/**
+ * @fileoverview Provides linting for the project.
+ */
+
+import { readFile } from 'node:fs/promises';
+
+import { logging } from './utils.mjs';
+import {
+ CORE_PATHS,
+ checkGameEmbed,
+ sectionsGetStartAndEnd,
+ getTitle,
+ getMarkdownFiles,
+ parseAliases,
+ parseReviewMetadata,
+ parseGameEmbeds,
+ SCRIPT_ALIASES_REGEX,
+ SCRIPT_GENERATE_START,
+ REVIEW_METADATA_REGEX
+} from './core.mjs';
+import { generateGameMetadata, generateLinks } from './generate.mjs';
+
+const isGithubAnotationsMode = process.env['GITHUB_ACTIONS'] === 'true';
+
+/**
+ * Remove path prefix to the root directory.
+ * @param {string} path The path to remove the root directory from.
+ * @returns {string}
+ */
+const removeRootDir = path => {
+ return path.replace(CORE_PATHS.rootDir + '/', '');
+};
+
+/**
+ * Logs a lint violation.
+ * @param {'warning' | 'error'} type The type of violation.
+ * @param {string | null} file The file path.
+ * @param {number | null} line The line number.
+ * @param {number | null} column The column number.
+ * @param {string} message The violation message.
+ */
+const logLintViolation = (type = 'error', file, line, column, message) => {
+ if (isGithubAnotationsMode) {
+ const args = [];
+ file !== null && args.push(`file=${removeRootDir(file)}`);
+ line !== null && args.push(`line=${line}`);
+ column !== null && args.push(`col=${column}`);
+ console.log('::%s %s::%s', type, args.join(','), message);
+ } else {
+ if (type === 'warning') {
+ logging.warning('[%s%s] %s', file, line ? `:${line}` : '', message);
+ } else {
+ logging.error('[%s%s] %s', file, line ? `:${line}` : '', message);
+ }
+ }
+};
+
+/**
+ * Check game embeds for linting issues.
+ * @param {GameEmbed}
+ */
+
+/**
+ * Checks a markdown file for linting issues.
+ * @param {string} file The file path.
+ */
+const lintMarkdownFile = async file => {
+ // Read the file
+ /**
+ * @type {[string, null] | [null, Error]}
+ */
+ const [content, error] = await readFile(file, 'utf-8')
+ .then(data => [data, null])
+ .catch(error => [null, error]);
+ if (error) {
+ logging.error('Failed to read file: %o', error);
+ return;
+ }
+ if (content.includes('\r\n')) {
+ logLintViolation(
+ 'warning',
+ file,
+ null,
+ null,
+ 'File contains CRLF line endings, should be LF.'
+ );
+ }
+
+ // Create an array of indexes for each line
+ const lineIndexes = [0];
+ for (let i = 0; i < content.length; i++) {
+ if (content[i] === '\n') {
+ lineIndexes.push(i + 1);
+ }
+ }
+
+ // Check the title
+ const [_0, titleError] = getTitle(content);
+ if (titleError) {
+ const error = {
+ 'not-found': 'Failed to find title in file.'
+ };
+ logLintViolation('error', file, 1, 1, error[titleError]);
+ }
+
+ /**
+ * Find the line and column number from the index.
+ * @param {number} index The index to find the line and column number for.
+ * @returns {[number, number]}
+ */
+ const findLineAndColumn = index => {
+ const line = lineIndexes.filter(i => i <= index).length;
+ const column = index - lineIndexes[line - 1];
+ return [line, column + 1];
+ };
+
+ // Check the line of the aliases (should be on second line)
+ let reviewMetadataExpectedLine = 3;
+ const aliasesMatch = SCRIPT_ALIASES_REGEX.exec(content);
+ if (aliasesMatch !== null) {
+ const [line, column] = findLineAndColumn(aliasesMatch.index);
+ if (column !== 1) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Aliases should be on the first column.'
+ );
+ }
+ if (line !== 2) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Aliases should be on the second line of the file.'
+ );
+ }
+
+ // Update the expected line for the review metadata to be two lines after the aliases
+ const [aliasesLine, _] = findLineAndColumn(
+ aliasesMatch.index + aliasesMatch[0].length
+ );
+
+ reviewMetadataExpectedLine = aliasesLine + 2;
+ }
+
+ // Check the aliases
+ const [_1, aliasesError] = parseAliases(content);
+ if (aliasesError) {
+ const error = {
+ 'not-found': 'Failed to find aliases in file.',
+ 'bad-json': 'Failed to parse aliases JSON in file.',
+ 'bad-json-format':
+ 'Aliases JSON in file is not an array of strings.'
+ };
+ logLintViolation(
+ aliasesError === 'not-found' ? 'warning' : 'error',
+ file,
+ 1,
+ 1,
+ error[aliasesError]
+ );
+ }
+
+ // Check the review metadata
+ const reviewMetadataMatch = REVIEW_METADATA_REGEX.exec(content);
+ if (reviewMetadataMatch.length > 0) {
+ const [line, column] = findLineAndColumn(reviewMetadataMatch.index);
+ if (column !== 1) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Review metadata should be on the first column.'
+ );
+ }
+ if (line !== reviewMetadataExpectedLine) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Review metadata should be on the line after the aliases (line ' +
+ reviewMetadataExpectedLine +
+ ').'
+ );
+ } else {
+ // Make sure the line before the review metadata is empty
+ const previousLineIndex = lineIndexes[line - 2];
+ if (
+ content
+ .slice(previousLineIndex, lineIndexes[line - 1])
+ .trim() !== ''
+ ) {
+ logLintViolation(
+ 'warning',
+ file,
+ line - 1,
+ 1,
+ 'Line before review metadata should be empty.'
+ );
+ }
+ }
+ }
+
+ // Check the review metadata
+ const [_2, reviewMetadataError] = parseReviewMetadata(content);
+ if (reviewMetadataError) {
+ const error = {
+ 'not-found':
+ 'Failed to find review metadata in file. (Might be because it is the wrong format.)'
+ };
+ logLintViolation('error', file, 1, 1, error[reviewMetadataError]);
+ }
+
+ // Game embeds should be on the last line
+ const [gameEmbedsMatch, gameEmbedsMatchError] = parseGameEmbeds(content);
+ if (gameEmbedsMatchError && gameEmbedsMatchError !== 'not-found') {
+ logLintViolation(
+ 'warning',
+ file,
+ null,
+ null,
+ 'Multiple game embeds found in file.'
+ );
+ } else if (gameEmbedsMatch !== null) {
+ const [embed, position] = gameEmbedsMatch;
+ const [line, column] = findLineAndColumn(position);
+ if (column !== 1) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Game embeds should be on the first column.'
+ );
+ }
+ if (line !== lineIndexes.length - 1) {
+ logLintViolation(
+ 'warning',
+ file,
+ line,
+ column,
+ 'Game embeds should be on the second last line of the file. (Line ' +
+ (lineIndexes.length - 1) +
+ ')'
+ );
+ }
+
+ // Check the game embeds is not invalid
+ const [isValid, gameEmbedsError] = await checkGameEmbed(embed);
+ if (!isValid) {
+ const error = {
+ 'invalid-embed': 'Invalid game embed found in file.',
+ 'web-request-failed': 'Failed to fetch game embed data.'
+ };
+ logLintViolation(
+ 'error',
+ file,
+ line,
+ column,
+ error[gameEmbedsError]
+ );
+ }
+ }
+};
+
+/**
+ * Main function.
+ * @returns {Promise}
+ */
+const main = async () => {
+ logging.info('Linting files...');
+
+ // First lint the SUMMARY.md file
+ /**
+ * @type {[string, null] | [null, Error]}
+ */
+ const [summaryFile, summaryFileError] = await readFile(
+ CORE_PATHS.summaryFile,
+ 'utf-8'
+ )
+ .then(data => [data, null])
+ .catch(error => [null, error]);
+ if (summaryFileError) {
+ logging.error('Failed to read SUMMARY.md: %o', summaryFileError);
+ return 1;
+ }
+
+ // Games metadata
+ const [gameData, gameDataError] = await generateGameMetadata();
+
+ // Check if the SUMMARY.md file contains the correct sections
+ const [summarySections, summarySectionsError] =
+ sectionsGetStartAndEnd(summaryFile);
+ if (summarySectionsError) {
+ const error = {
+ 'not-found': 'Failed to find start and end sections in SUMMARY.md.',
+ 'invalid-position':
+ 'End section comes before start section in SUMMARY.md.'
+ };
+ logLintViolation(
+ 'error',
+ CORE_PATHS.summaryFile,
+ null,
+ null,
+ error[summarySectionsError]
+ );
+ } else if (!gameDataError) {
+ const [start, end] = summarySections;
+ // Slice at these indexes to get the content between the sections
+ const contentBetweenSections = summaryFile.slice(start + SCRIPT_GENERATE_START.length, end);
+ // Check if the content between the sections is up to date
+ const expectedContent = generateLinks(gameData);
+ if (contentBetweenSections !== expectedContent) {
+ logLintViolation(
+ 'error',
+ CORE_PATHS.summaryFile,
+ null,
+ null,
+ 'SUMMARY.md content is out of date.'
+ );
+ }
+ }
+
+ // Lint all markdown files in the game-support directory
+ const [markdownFiles, markdownFilesError] = await getMarkdownFiles();
+ if (markdownFilesError) {
+ return 1;
+ }
+
+ await Promise.all(markdownFiles.map(file => lintMarkdownFile(file)));
+
+ return 0;
+};
+
+main().then(code => process.exit(code));
diff --git a/scripts/utils.mjs b/scripts/utils.mjs
index a9d8f5f1..a3b1aa86 100644
--- a/scripts/utils.mjs
+++ b/scripts/utils.mjs
@@ -1,3 +1,19 @@
+/**
+ * @fileoverview Utility functions.
+ */
+import { format } from 'node:util';
+import { dirname } from 'node:path';
+import { fileURLToPath } from 'node:url';
+import { execSync } from 'node:child_process';
+
+/**
+ * Returns the directory of the current module. (utils.mjs)
+ * @returns {string}
+ */
+export const getDirName = () => {
+ return dirname(fileURLToPath(import.meta.url));
+};
+
/**
* Escapes a string for use in Markdown.
* @type {Array<[RegExp, string]>}
@@ -13,19 +29,19 @@ const markdownEscapeItems = [
[//g, '>'], // Close angle brackets
[/_/g, '\\_'], // Underscores
- [/`/g, '\\`'], // Backticks
+ [/`/g, '\\`'] // Backticks
];
/**
* Escapes a string for use in Markdown.
* @param {string} str
*/
-export const markdownEscape = (str) => {
+export const markdownEscape = str => {
for (const [regex, replacement] of markdownEscapeItems) {
str = str.replace(regex, replacement);
}
return str;
-}
+};
/**
* Fancy colors for console output.
@@ -37,7 +53,7 @@ const colors = {
warning: '\x1b[33m',
error: '\x1b[31m',
bold: '\x1b[1m',
- reset: '\x1b[0m',
+ reset: '\x1b[0m'
};
/**
@@ -55,9 +71,18 @@ export const fancyLog = (type, message, ...args) => {
colors.reset,
colors[type],
format(message, ...args),
- colors.reset,
+ colors.reset
);
-}
+};
+
+const LOG_LEVELS = ['debug', 'info', 'warning', 'error', 'none'];
+
+/**
+ * Logging levels.
+ */
+const loggingLevel = LOG_LEVELS.includes(process.env['LOG'])
+ ? LOG_LEVELS.indexOf(process.env['LOG'])
+ : 1;
/**
* Logging functions.
@@ -72,33 +97,63 @@ export const logging = {
* @param {string} message
* @param {...any} args
*/
- debug: (message, ...args) => fancyLog('debug', message, ...args),
+ debug: (message, ...args) =>
+ loggingLevel <= 0 && fancyLog('debug', message, ...args),
/**
* Logs an info message.
* @param {string} message
* @param {...any} args
*/
- info: (message, ...args) => fancyLog('info', message, ...args),
+ info: (message, ...args) =>
+ loggingLevel <= 1 && fancyLog('info', message, ...args),
/**
* Logs a warning message.
* @param {string} message
* @param {...any} args
*/
- warning: (message, ...args) => fancyLog('warning', message, ...args),
+ warning: (message, ...args) =>
+ loggingLevel <= 2 && fancyLog('warning', message, ...args),
/**
* Logs an error message.
* @param {string} message
* @param {...any} args
*/
- error: (message, ...args) => fancyLog('error', message, ...args),
+ error: (message, ...args) =>
+ loggingLevel <= 3 && fancyLog('error', message, ...args)
};
-
/**
* Remove duplicates from an array.
* @param {T[]} arr
* @returns {T[]}
*/
-export const removeDuplicates = (arr) => {
+export const removeDuplicates = arr => {
return [...new Set(arr)];
-}
\ No newline at end of file
+};
+
+/**
+ * Get last updated date from a file.
+ * MUST BE IN GIT SOURCE TREE
+ * @param {string} path
+ * @returns {[Date, null] | [null, 'git-error']}
+ */
+export const getLastUpdated = path => {
+ try {
+ const lastUpdated = new Date(
+ execSync(`git log -1 --format=%cd -- ${path}`).toString().trim()
+ );
+
+ if (isNaN(lastUpdated.getTime())) {
+ throw new Error('Invalid date');
+ }
+
+ return [lastUpdated, null];
+ } catch (error) {
+ logging.warning(
+ 'Failed to get last updated for file %s: %o',
+ path,
+ error
+ );
+ return [null, 'git-error'];
+ }
+};
diff --git a/src/SUMMARY.md b/src/SUMMARY.md
index 4e49ffa1..a1ba4c87 100644
--- a/src/SUMMARY.md
+++ b/src/SUMMARY.md
@@ -8,95 +8,95 @@
- [Whisky x Heroic](./whisky-x-heroic.md)
- [Debugging](./debugging.md)
- [Game Support](./game-support/README.md)
-
- - [Assassin's Creed: Director's Cut Edition](./game-support/ac-directors-cut.md)
- - [Among Us](./game-support/among-us.md)
- - [Armored Core VI: Fires of Rubicon](./game-support/armored-core-6.md)
- - [Battle Brothers](./game-support/battle-brothers.md)
- - [Betrayer](./game-support/betrayer.md)
- - [Blasphemous 2](./game-support/blasphemous-2.md)
- - [Blitzkrieg 2 Anthology](./game-support/blitzkrieg-2-anthology.md)
- - [Buckshot Roulette](./game-support/buckshot-roulette.md)
- - [Call of Cthulhu](./game-support/call-of-cthulhu.md)
- - [Cities: Skylines 2](./game-support/cities-skylines-2.md)
- - [Call of Juarez: Gunslinger](./game-support/coj-gunslinger.md)
- - [Content Warning](./game-support/content-warning.md)
- - [Contraband Police](./game-support/contraband-police.md)
- - [Control](./game-support/control.md)
- - [Counter-Strike 2](./game-support/counter-strike-2.md)
- - [Cyberpunk 2077](./game-support/cyberpunk-2077.md)
- - [Dagon: by H. P. Lovecraft](./game-support/dagon.md)
- - [Dark Souls III](./game-support/dark-souls-3.md)
- - [Dark Souls: Remastered](./game-support/dark-souls-remastered.md)
- - [Dead Space \(2023\)](./game-support/dead-space-2023.md)
- - [Deadlink](./game-support/deadlink.md)
- - [Deep Rock Galactic](./game-support/deep-rock-galactic.md)
- - [Diablo IV - Battle.net Version](./game-support/diablo-4-battle-net.md)
- - [Diablo IV - Steam Version](./game-support/diablo-4-steam.md)
- - [Dishonored 2](./game-support/dishonored-2.md)
- - [Dishonored](./game-support/dishonored.md)
- - [Dorfromantik](./game-support/dorfromantik.md)
- - [Dying Light 2](./game-support/dying-light-2.md)
- - [Elden Ring](./game-support/elden-ring.md)
- - [Elite Dangerous](./game-support/elite-dangerous.md)
- - [F1 Manager 2023](./game-support/f1m23.md)
- - [Fallout 3: Game of the Year Edition](./game-support/fallout-3-goty.md)
- - [Fallout 4](./game-support/fallout-4.md)
- - [Fear and Hunger](./game-support/fear-and-hunger.md)
- - [FlatOut](./game-support/flatout.md)
- - [Forgive Me Father 2](./game-support/forgive-me-father-2.md)
- - [Fortnite](./game-support/fortnite.md)
- - [Friends vs Friends](./game-support/friends-vs-friends.md)
- - [Grand Theft Auto V](./game-support/gta-5.md)
- - [Guild Wars 2](./game-support/gw2.md)
- - [Geometry Wars 3: Dimensions Evolved](./game-support/gw3-dimensions-evolved.md)
- - [Half-Life 1](./game-support/half-life-1.md)
- - [Half-Life 2](./game-support/half-life-2.md)
- - [Hellblade: Senua's Sacrifice](./game-support/hellblade.md)
- - [Hitman: Contracts](./game-support/hitman-3-c.md)
- - [Hearts of Iron III](./game-support/hoi-3.md)
- - [Horizon Zero Dawn](./game-support/horizon-zero-dawn.md)
- - [JoJo's Bizarre Adventure: All-Star Battle R](./game-support/jjba-asbr.md)
- - [Kingdom Come: Deliverance](./game-support/kcd.md)
- - [Kenshi](./game-support/kenshi.md)
- - [Kingsway](./game-support/kingsway.md)
- - [LEGO Star Wars III - The Clone Wars](./game-support/lego-sw-iii-clone-wars.md)
- - [LEGO Star Wars: The Skywalker Saga](./game-support/lego-sw-skywalker-saga.md)
- - [Lethal Company](./game-support/lethal-company.md)
- - [Manor Lords](./game-support/manor-lords.md)
- - [Mount & Blade: With Fire & Sword](./game-support/mb-wfas.md)
- - [Metro 2033 Redux](./game-support/metro-2033-rx.md)
- - [Metro: Last Light Redux](./game-support/metro-ll-rx.md)
- - [Metal Gear Solid V: The Phantom Pain](./game-support/mgs-5.md)
- - [Monster Hunter World: Iceborne](./game-support/monster-hunter-world-iceborne.md)
- - [Neon White](./game-support/neon-white.md)
- - [Overwatch 2](./game-support/overwatch-2.md)
- - [Persona 3 Reload](./game-support/p3r.md)
- - [Persona 4 Golden](./game-support/p4g.md)
- - [Palworld](./game-support/palworld.md)
- - [People Playground](./game-support/people-playground.md)
- - [Phasmophobia](./game-support/phasmophobia.md)
- - [Prey \(2017\)](./game-support/prey-2017.md)
- - [Quake II](./game-support/quake2.md)
- - [r2modman](./game-support/r2modman.md)
- - [Rain World](./game-support/rain-world.md)
- - [Risk of Rain 2](./game-support/risk-of-rain-2.md)
- - [Risk of Rain Returns](./game-support/risk-of-rain-returns.md)
- - [Ruiner](./game-support/ruiner.md)
- - [Satisfactory](./game-support/satisfactory.md)
- - [Sekiro: Shadows Die Twice](./game-support/sekiro.md)
- - [Skyrim SE](./game-support/skyrim-se.md)
- - [Stardew Valley](./game-support/stardew-valley.md)
- - [Stronghold Crusader HD](./game-support/stronghold-crusader-hd.md)
- - [Star Wars Jedi: Fallen Order](./game-support/sw-fallen-order.md)
- - [Star Wars: Squadrons](./game-support/sw-squadrons.md)
- - [Tom Clancy's Rainbow Six Siege \(Steam\)](./game-support/tcr6s.md)
- - [The Stanley Parable: Ultra Deluxe](./game-support/tsp-ud.md)
- - [Turbo Overkill](./game-support/turbo-overkill.md)
- - [Ultrakill](./game-support/ultrakill.md)
- - [Undertale](./game-support/undertale.md)
- - [The Vanishing of Ethan Carter](./game-support/vanishing-of-ethan-carter.md)
- - [Warframe](./game-support/warframe.md)
- - [The Witcher 3: Wild Hunt](./game-support/witcher3.md)
- - [The Wolf Among Us](./game-support/wolf-among-us.md)
+
+ - [Assassin's Creed: Director's Cut Edition](/game-support/ac-directors-cut.md)
+ - [Among Us](/game-support/among-us.md)
+ - [Armored Core VI: Fires of Rubicon](/game-support/armored-core-6.md)
+ - [Battle Brothers](/game-support/battle-brothers.md)
+ - [Betrayer](/game-support/betrayer.md)
+ - [Blasphemous 2](/game-support/blasphemous-2.md)
+ - [Blitzkrieg 2 Anthology](/game-support/blitzkrieg-2-anthology.md)
+ - [Buckshot Roulette](/game-support/buckshot-roulette.md)
+ - [Call of Cthulhu](/game-support/call-of-cthulhu.md)
+ - [Cities: Skylines 2](/game-support/cities-skylines-2.md)
+ - [Call of Juarez: Gunslinger](/game-support/coj-gunslinger.md)
+ - [Content Warning](/game-support/content-warning.md)
+ - [Contraband Police](/game-support/contraband-police.md)
+ - [Control](/game-support/control.md)
+ - [Counter-Strike 2](/game-support/counter-strike-2.md)
+ - [Cyberpunk 2077](/game-support/cyberpunk-2077.md)
+ - [Dagon: by H. P. Lovecraft](/game-support/dagon.md)
+ - [Dark Souls III](/game-support/dark-souls-3.md)
+ - [Dark Souls: Remastered](/game-support/dark-souls-remastered.md)
+ - [Dead Space \(2023\)](/game-support/dead-space-2023.md)
+ - [Deadlink](/game-support/deadlink.md)
+ - [Deep Rock Galactic](/game-support/deep-rock-galactic.md)
+ - [Diablo IV \(Battle.net\)](/game-support/diablo-4-battle-net.md)
+ - [Diablo IV \(Steam\)](/game-support/diablo-4-steam.md)
+ - [Dishonored 2](/game-support/dishonored-2.md)
+ - [Dishonored](/game-support/dishonored.md)
+ - [Dorfromantik](/game-support/dorfromantik.md)
+ - [Dying Light 2](/game-support/dying-light-2.md)
+ - [Elden Ring](/game-support/elden-ring.md)
+ - [Elite Dangerous](/game-support/elite-dangerous.md)
+ - [F1 Manager 2023](/game-support/f1m23.md)
+ - [Fallout 3: Game of the Year Edition](/game-support/fallout-3-goty.md)
+ - [Fallout 4](/game-support/fallout-4.md)
+ - [Fear and Hunger](/game-support/fear-and-hunger.md)
+ - [FlatOut](/game-support/flatout.md)
+ - [Forgive Me Father 2](/game-support/forgive-me-father-2.md)
+ - [Fortnite](/game-support/fortnite.md)
+ - [Friends vs Friends](/game-support/friends-vs-friends.md)
+ - [Grand Theft Auto V](/game-support/gta-5.md)
+ - [Guild Wars 2](/game-support/gw2.md)
+ - [Geometry Wars 3: Dimensions Evolved](/game-support/gw3-dimensions-evolved.md)
+ - [Half-Life 1](/game-support/half-life-1.md)
+ - [Half-Life 2](/game-support/half-life-2.md)
+ - [Hellblade: Senua's Sacrifice](/game-support/hellblade.md)
+ - [Hitman: Contracts](/game-support/hitman-3-c.md)
+ - [Hearts of Iron III](/game-support/hoi-3.md)
+ - [Horizon Zero Dawn](/game-support/horizon-zero-dawn.md)
+ - [JoJo's Bizarre Adventure: All-Star Battle R](/game-support/jjba-asbr.md)
+ - [Kingdom Come: Deliverance](/game-support/kcd.md)
+ - [Kenshi](/game-support/kenshi.md)
+ - [Kingsway](/game-support/kingsway.md)
+ - [LEGO Star Wars III: The Clone Wars](/game-support/lego-sw-iii-clone-wars.md)
+ - [LEGO Star Wars: The Skywalker Saga](/game-support/lego-sw-skywalker-saga.md)
+ - [Lethal Company](/game-support/lethal-company.md)
+ - [Manor Lords](/game-support/manor-lords.md)
+ - [Mount & Blade: With Fire & Sword](/game-support/mb-wfas.md)
+ - [Metro 2033 Redux](/game-support/metro-2033-rx.md)
+ - [Metro: Last Light Redux](/game-support/metro-ll-rx.md)
+ - [Metal Gear Solid V: The Phantom Pain](/game-support/mgs-5.md)
+ - [Monster Hunter World: Iceborne](/game-support/monster-hunter-world-iceborne.md)
+ - [Neon White](/game-support/neon-white.md)
+ - [Overwatch 2](/game-support/overwatch-2.md)
+ - [Persona 3 Reload](/game-support/p3r.md)
+ - [Persona 4 Golden](/game-support/p4g.md)
+ - [Palworld](/game-support/palworld.md)
+ - [People Playground](/game-support/people-playground.md)
+ - [Phasmophobia](/game-support/phasmophobia.md)
+ - [Prey \(2017\)](/game-support/prey-2017.md)
+ - [Quake II](/game-support/quake2.md)
+ - [r2modman](/game-support/r2modman.md)
+ - [Rain World](/game-support/rain-world.md)
+ - [Risk of Rain 2](/game-support/risk-of-rain-2.md)
+ - [Risk of Rain Returns](/game-support/risk-of-rain-returns.md)
+ - [Ruiner](/game-support/ruiner.md)
+ - [Satisfactory](/game-support/satisfactory.md)
+ - [Sekiro: Shadows Die Twice](/game-support/sekiro.md)
+ - [Skyrim SE](/game-support/skyrim-se.md)
+ - [Stardew Valley](/game-support/stardew-valley.md)
+ - [Stronghold Crusader HD](/game-support/stronghold-crusader-hd.md)
+ - [Star Wars Jedi: Fallen Order](/game-support/sw-fallen-order.md)
+ - [Star Wars: Squadrons](/game-support/sw-squadrons.md)
+ - [Tom Clancy's Rainbow Six Siege \(Steam\)](/game-support/tcr6s.md)
+ - [The Stanley Parable: Ultra Deluxe](/game-support/tsp-ud.md)
+ - [Turbo Overkill](/game-support/turbo-overkill.md)
+ - [Ultrakill](/game-support/ultrakill.md)
+ - [Undertale](/game-support/undertale.md)
+ - [The Vanishing of Ethan Carter](/game-support/vanishing-of-ethan-carter.md)
+ - [Warframe](/game-support/warframe.md)
+ - [The Witcher 3: Wild Hunt](/game-support/witcher3.md)
+ - [The Wolf Among Us](/game-support/wolf-among-us.md)
\ No newline at end of file
diff --git a/src/game-support/README.md b/src/game-support/README.md
index f58ac3a0..54ad3732 100644
--- a/src/game-support/README.md
+++ b/src/game-support/README.md
@@ -16,3 +16,5 @@ title is partially left to the article author, but some general guidelines apply
| Silver | Game requires some workarounds, but they are simple and/or there are minor in-game issues |
| Bronze | Game is very difficult to get working and/or has severe in-game issues that limit playability. |
| Garbage | Game does not work at all. |
+
+
diff --git a/src/game-support/ac-directors-cut.md b/src/game-support/ac-directors-cut.md
index ba2fb1b2..5b0fcd38 100644
--- a/src/game-support/ac-directors-cut.md
+++ b/src/game-support/ac-directors-cut.md
@@ -1,4 +1,7 @@
# Assassin's Creed: Director's Cut Edition
+
{{#template ../templates/rating.md status=Bronze installs=Yes opens=Yes}}
@@ -6,4 +9,4 @@
> The game suffers from a severe heartbeat-like sound stuttering. Also it's performance is quite poor.
> DX10 version does not render part of the player and NPCs. DX9 version renders fine.
-{{#template ../templates/steam.md id=15100}}
\ No newline at end of file
+{{#template ../templates/steam.md id=15100}}
diff --git a/src/game-support/among-us.md b/src/game-support/among-us.md
index 23cbb7bf..f1428694 100644
--- a/src/game-support/among-us.md
+++ b/src/game-support/among-us.md
@@ -1,8 +1,9 @@
# Among Us
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> This game has an iPad Mac port through the App Store.
-{{#template ../templates/steam.md id=945360}}
\ No newline at end of file
+{{#template ../templates/steam.md id=945360}}
diff --git a/src/game-support/armored-core-6.md b/src/game-support/armored-core-6.md
index 7db39488..f80c7d9e 100644
--- a/src/game-support/armored-core-6.md
+++ b/src/game-support/armored-core-6.md
@@ -10,4 +10,4 @@
## Setup
- Disable DXVK
-{{#template ../templates/steam.md id=1888160}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1888160}}
diff --git a/src/game-support/battle-brothers.md b/src/game-support/battle-brothers.md
index 6d74a49e..7ff52482 100644
--- a/src/game-support/battle-brothers.md
+++ b/src/game-support/battle-brothers.md
@@ -1,4 +1,5 @@
# Battle Brothers
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
diff --git a/src/game-support/betrayer.md b/src/game-support/betrayer.md
index 09fbc28f..f584244e 100644
--- a/src/game-support/betrayer.md
+++ b/src/game-support/betrayer.md
@@ -1,4 +1,5 @@
# Betrayer
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -8,4 +9,4 @@
> [!WARNING]
> Audio is glitchy - sounds like a mix of original audio quality with 8-bit version of it.
-{{#template ../templates/steam.md id=243120}}
\ No newline at end of file
+{{#template ../templates/steam.md id=243120}}
diff --git a/src/game-support/blasphemous-2.md b/src/game-support/blasphemous-2.md
index c563b1bc..ae875752 100644
--- a/src/game-support/blasphemous-2.md
+++ b/src/game-support/blasphemous-2.md
@@ -1,5 +1,6 @@
# Blasphemous 2
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=2114740}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2114740}}
diff --git a/src/game-support/blitzkrieg-2-anthology.md b/src/game-support/blitzkrieg-2-anthology.md
index c6a24ef2..15da9056 100644
--- a/src/game-support/blitzkrieg-2-anthology.md
+++ b/src/game-support/blitzkrieg-2-anthology.md
@@ -1,4 +1,5 @@
# Blitzkrieg 2 Anthology
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
@@ -7,4 +8,4 @@
> Audio stutters during intro movies.
> There may be issue with exiting. Sometimes it is helpful to use the Activity Monitor and Force Quit if in-game button won't help.
-{{#template ../templates/steam.md id=313500}}
\ No newline at end of file
+{{#template ../templates/steam.md id=313500}}
diff --git a/src/game-support/buckshot-roulette.md b/src/game-support/buckshot-roulette.md
index b10f7876..b0e0a426 100644
--- a/src/game-support/buckshot-roulette.md
+++ b/src/game-support/buckshot-roulette.md
@@ -1,7 +1,8 @@
# Buckshot Roulette
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
Minor graphical issues with particle effects, but the game is playable.
-{{#template ../templates/steam.md id=2835570}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2835570}}
diff --git a/src/game-support/call-of-cthulhu.md b/src/game-support/call-of-cthulhu.md
index a2daef85..aa7ec913 100644
--- a/src/game-support/call-of-cthulhu.md
+++ b/src/game-support/call-of-cthulhu.md
@@ -1,8 +1,9 @@
# Call of Cthulhu
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> Runs great. However when moving mouse intensively a native cursor appears on screen all the time and also hovers the in-game one
-{{#template ../templates/steam.md id=399810}}
\ No newline at end of file
+{{#template ../templates/steam.md id=399810}}
diff --git a/src/game-support/cities-skylines-2.md b/src/game-support/cities-skylines-2.md
index b6ee41e6..1ef3dd07 100644
--- a/src/game-support/cities-skylines-2.md
+++ b/src/game-support/cities-skylines-2.md
@@ -23,4 +23,4 @@
> - Tabbing out will cause the game to become unresponsive and require it to be restarted. Do **not** change window focus while playing.
> - Subsequent launches may fail to open the Paradox Launcher. This can be resolved temporarily by deleting the `Paradox Interactive` folder in `Program Files`. Reinstalling the launcher may also be required.
-{{#template ../templates/steam.md id=949230}}
\ No newline at end of file
+{{#template ../templates/steam.md id=949230}}
diff --git a/src/game-support/coj-gunslinger.md b/src/game-support/coj-gunslinger.md
index 72f0bcad..b645be98 100644
--- a/src/game-support/coj-gunslinger.md
+++ b/src/game-support/coj-gunslinger.md
@@ -1,5 +1,6 @@
# Call of Juarez: Gunslinger
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
-{{#template ../templates/steam.md id=204450}}
\ No newline at end of file
+{{#template ../templates/steam.md id=204450}}
diff --git a/src/game-support/content-warning.md b/src/game-support/content-warning.md
index de09a3d5..2aa6bbc3 100644
--- a/src/game-support/content-warning.md
+++ b/src/game-support/content-warning.md
@@ -1,4 +1,5 @@
# Content Warning
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -8,4 +9,4 @@
> [!WARNING]
> If you press "Paste" in the face editor the game experiences a fatal error and crashes
-{{#template ../templates/steam.md id=2881650}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2881650}}
diff --git a/src/game-support/contraband-police.md b/src/game-support/contraband-police.md
index 1bf6f35a..75290abd 100644
--- a/src/game-support/contraband-police.md
+++ b/src/game-support/contraband-police.md
@@ -1,5 +1,6 @@
# Contraband Police
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=756800}}
\ No newline at end of file
+{{#template ../templates/steam.md id=756800}}
diff --git a/src/game-support/control.md b/src/game-support/control.md
index 007062b3..f6b5b148 100644
--- a/src/game-support/control.md
+++ b/src/game-support/control.md
@@ -1,5 +1,6 @@
# Control
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=870780}}
\ No newline at end of file
+{{#template ../templates/steam.md id=870780}}
diff --git a/src/game-support/counter-strike-2.md b/src/game-support/counter-strike-2.md
index b06067f6..2e7f4c4a 100644
--- a/src/game-support/counter-strike-2.md
+++ b/src/game-support/counter-strike-2.md
@@ -17,4 +17,4 @@
- Start CS2 from Steam as normal
-{{#template ../templates/steam.md id=730}}
\ No newline at end of file
+{{#template ../templates/steam.md id=730}}
diff --git a/src/game-support/cyberpunk-2077.md b/src/game-support/cyberpunk-2077.md
index 29f00aea..3521a9d3 100644
--- a/src/game-support/cyberpunk-2077.md
+++ b/src/game-support/cyberpunk-2077.md
@@ -1,5 +1,6 @@
# Cyberpunk 2077
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1091500}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1091500}}
diff --git a/src/game-support/dagon.md b/src/game-support/dagon.md
index 3eeb3b02..ddff9a73 100644
--- a/src/game-support/dagon.md
+++ b/src/game-support/dagon.md
@@ -1,5 +1,8 @@
# Dagon: by H. P. Lovecraft
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1481400}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1481400}}
diff --git a/src/game-support/dark-souls-3.md b/src/game-support/dark-souls-3.md
index 51db9cba..444cc63a 100644
--- a/src/game-support/dark-souls-3.md
+++ b/src/game-support/dark-souls-3.md
@@ -5,4 +5,4 @@
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=374320}}
\ No newline at end of file
+{{#template ../templates/steam.md id=374320}}
diff --git a/src/game-support/dead-space-2023.md b/src/game-support/dead-space-2023.md
index f4417a8c..3796e98d 100644
--- a/src/game-support/dead-space-2023.md
+++ b/src/game-support/dead-space-2023.md
@@ -6,4 +6,4 @@
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1693980}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1693980}}
diff --git a/src/game-support/deadlink.md b/src/game-support/deadlink.md
index 15795f1b..fa33de54 100644
--- a/src/game-support/deadlink.md
+++ b/src/game-support/deadlink.md
@@ -1,7 +1,8 @@
# Deadlink
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
Viewing an effect for the first time will cause the game to hang for a second. After a few minutes of gameplay stutters stop and the game runs perfectly.
-{{#template ../templates/steam.md id=1676130}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1676130}}
diff --git a/src/game-support/deep-rock-galactic.md b/src/game-support/deep-rock-galactic.md
index f144caf9..7b91febd 100644
--- a/src/game-support/deep-rock-galactic.md
+++ b/src/game-support/deep-rock-galactic.md
@@ -1,7 +1,8 @@
# Deep Rock Galactic
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
When using a controller, both analog sticks look and move at the same time. The UI takes double clicks to interact. I was not able to find any servers or join any games. Solo missions work perfectly. The game runs well in DX12 mode.
-{{#template ../templates/steam.md id=548430}}
\ No newline at end of file
+{{#template ../templates/steam.md id=548430}}
diff --git a/src/game-support/diablo-4-battle-net.md b/src/game-support/diablo-4-battle-net.md
index 4421a202..44ec25c9 100644
--- a/src/game-support/diablo-4-battle-net.md
+++ b/src/game-support/diablo-4-battle-net.md
@@ -1,4 +1,4 @@
-# Diablo IV - Battle.net Version
+# Diablo IV (Battle.net)
-Diablo IV is currently **unplayable** in Whisky.
\ No newline at end of file
+Diablo IV is currently **unplayable** in Whisky.
diff --git a/src/game-support/diablo-4-steam.md b/src/game-support/diablo-4-steam.md
index baaf1c5a..e0fe10d6 100644
--- a/src/game-support/diablo-4-steam.md
+++ b/src/game-support/diablo-4-steam.md
@@ -1,4 +1,4 @@
-# Diablo IV - Steam Version
+# Diablo IV (Steam)
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -8,4 +9,4 @@
> [!NOTE]
> Set "world detail" to low for a smoother experience.
-{{#template ../templates/steam.md id=403640}}
\ No newline at end of file
+{{#template ../templates/steam.md id=403640}}
diff --git a/src/game-support/dishonored.md b/src/game-support/dishonored.md
index d1e4a317..d612dd0d 100644
--- a/src/game-support/dishonored.md
+++ b/src/game-support/dishonored.md
@@ -1,7 +1,8 @@
# Dishonored
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
The game runs with constant stutters.
-{{#template ../templates/steam.md id=205100}}
\ No newline at end of file
+{{#template ../templates/steam.md id=205100}}
diff --git a/src/game-support/dorfromantik.md b/src/game-support/dorfromantik.md
index 1a4e5370..e78273f6 100644
--- a/src/game-support/dorfromantik.md
+++ b/src/game-support/dorfromantik.md
@@ -1,5 +1,6 @@
# Dorfromantik
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1455840}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1455840}}
diff --git a/src/game-support/dying-light-2.md b/src/game-support/dying-light-2.md
index 8060ce1f..91c6eb81 100644
--- a/src/game-support/dying-light-2.md
+++ b/src/game-support/dying-light-2.md
@@ -1,4 +1,5 @@
# Dying Light 2
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -24,4 +25,4 @@
> You can use the above solution to change your texture settings to low (which you are unable to do in the in-game settings menu).
> Set `TextureQuality(...)` to `TextureQuality("Low")`.
-{{#template ../templates/steam.md id=534380}}
\ No newline at end of file
+{{#template ../templates/steam.md id=534380}}
diff --git a/src/game-support/elden-ring.md b/src/game-support/elden-ring.md
index c71bf874..27e1ab99 100644
--- a/src/game-support/elden-ring.md
+++ b/src/game-support/elden-ring.md
@@ -1,4 +1,5 @@
# Elden Ring
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -13,4 +14,4 @@
- Start Elden Ring from Steam as normal
-{{#template ../templates/steam.md id=1245620}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1245620}}
diff --git a/src/game-support/elite-dangerous.md b/src/game-support/elite-dangerous.md
index ae6f32c2..c2b2185b 100644
--- a/src/game-support/elite-dangerous.md
+++ b/src/game-support/elite-dangerous.md
@@ -1,4 +1,5 @@
# Elite Dangerous
+
{{#template ../templates/rating.md status=Bronze installs=Yes opens=Yes}}
diff --git a/src/game-support/f1m23.md b/src/game-support/f1m23.md
index b48e8b4d..33b067c1 100644
--- a/src/game-support/f1m23.md
+++ b/src/game-support/f1m23.md
@@ -1,4 +1,5 @@
# F1 Manager 2023
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/fallout-3-goty.md b/src/game-support/fallout-3-goty.md
index 152b7359..a34041b7 100644
--- a/src/game-support/fallout-3-goty.md
+++ b/src/game-support/fallout-3-goty.md
@@ -1,4 +1,7 @@
# Fallout 3: Game of the Year Edition
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=Yes}}
diff --git a/src/game-support/fallout-4.md b/src/game-support/fallout-4.md
index d78cbc21..b16ae141 100644
--- a/src/game-support/fallout-4.md
+++ b/src/game-support/fallout-4.md
@@ -1,4 +1,5 @@
# Fallout 4
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
diff --git a/src/game-support/fear-and-hunger.md b/src/game-support/fear-and-hunger.md
index d994f287..cdc9bd5a 100644
--- a/src/game-support/fear-and-hunger.md
+++ b/src/game-support/fear-and-hunger.md
@@ -1,4 +1,5 @@
# Fear and Hunger
+
{{#template ../templates/rating.md status=Bronze installs=Yes opens=Yes}}
@@ -14,4 +15,4 @@
> The game is terribly optimized and runs very poorly without community-made fixes, which have not yet been compatible with macOS and Whisky.
> You can find those fixes [here](https://www.pcgamingwiki.com/wiki/Fear_%26_Hunger#Essential_Improvements), however at the current time they **do not work** on macOS and will prevent your game from running.
-{{#template ../templates/steam.md id=1002300}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1002300}}
diff --git a/src/game-support/flatout.md b/src/game-support/flatout.md
index eba3757d..7c5416a7 100644
--- a/src/game-support/flatout.md
+++ b/src/game-support/flatout.md
@@ -1,5 +1,6 @@
# FlatOut
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=6220}}
\ No newline at end of file
+{{#template ../templates/steam.md id=6220}}
diff --git a/src/game-support/forgive-me-father-2.md b/src/game-support/forgive-me-father-2.md
index 5e6517b0..cc93c197 100644
--- a/src/game-support/forgive-me-father-2.md
+++ b/src/game-support/forgive-me-father-2.md
@@ -1,7 +1,8 @@
# Forgive Me Father 2
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
The game complains about you not having the right driver; this prompt can be completely ignored.
-{{#template ../templates/steam.md id=2272250}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2272250}}
diff --git a/src/game-support/fortnite.md b/src/game-support/fortnite.md
index 6a22e70b..525e8c73 100644
--- a/src/game-support/fortnite.md
+++ b/src/game-support/fortnite.md
@@ -1,5 +1,6 @@
# Fortnite
+
{{#template ../templates/rating.md status=Garbage installs=No opens=No}}
-No.
\ No newline at end of file
+No.
diff --git a/src/game-support/friends-vs-friends.md b/src/game-support/friends-vs-friends.md
index be89f190..4be2ce6b 100644
--- a/src/game-support/friends-vs-friends.md
+++ b/src/game-support/friends-vs-friends.md
@@ -1,5 +1,6 @@
# Friends vs Friends
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1785150}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1785150}}
diff --git a/src/game-support/gta-5.md b/src/game-support/gta-5.md
index 6eea34ae..46fb7bbd 100644
--- a/src/game-support/gta-5.md
+++ b/src/game-support/gta-5.md
@@ -9,4 +9,4 @@
Works with DXVK.
-{{#template ../templates/steam.md id=271590}}
\ No newline at end of file
+{{#template ../templates/steam.md id=271590}}
diff --git a/src/game-support/gw2.md b/src/game-support/gw2.md
index 68ac11f4..5c8126df 100644
--- a/src/game-support/gw2.md
+++ b/src/game-support/gw2.md
@@ -1,4 +1,5 @@
# Guild Wars 2
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
@@ -13,4 +14,4 @@
- Download in Steam as normal
-{{#template ../templates/steam.md id=1284210}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1284210}}
diff --git a/src/game-support/gw3-dimensions-evolved.md b/src/game-support/gw3-dimensions-evolved.md
index 50215306..ceadf0bf 100644
--- a/src/game-support/gw3-dimensions-evolved.md
+++ b/src/game-support/gw3-dimensions-evolved.md
@@ -5,4 +5,4 @@
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=310790}}
\ No newline at end of file
+{{#template ../templates/steam.md id=310790}}
diff --git a/src/game-support/hellblade.md b/src/game-support/hellblade.md
index 26444176..60dd800f 100644
--- a/src/game-support/hellblade.md
+++ b/src/game-support/hellblade.md
@@ -1,5 +1,8 @@
# Hellblade: Senua's Sacrifice
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=414340}}
\ No newline at end of file
+{{#template ../templates/steam.md id=414340}}
diff --git a/src/game-support/hitman-3-c.md b/src/game-support/hitman-3-c.md
index a4664d24..4f567ec1 100644
--- a/src/game-support/hitman-3-c.md
+++ b/src/game-support/hitman-3-c.md
@@ -10,4 +10,4 @@
> [!WARNING]
> Sound is stuttering and it is barely audible. Very quiet samples of the game's audio output are played in a heartbeat rhythm.
-{{#template ../templates/steam.md id=247430}}
\ No newline at end of file
+{{#template ../templates/steam.md id=247430}}
diff --git a/src/game-support/hoi-3.md b/src/game-support/hoi-3.md
index 709b6abc..4fd60392 100644
--- a/src/game-support/hoi-3.md
+++ b/src/game-support/hoi-3.md
@@ -1,4 +1,5 @@
# Hearts of Iron III
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -8,4 +9,4 @@
> [!WARNING]
> Music does not play in the game.
-{{#template ../templates/steam.md id=25890}}
\ No newline at end of file
+{{#template ../templates/steam.md id=25890}}
diff --git a/src/game-support/horizon-zero-dawn.md b/src/game-support/horizon-zero-dawn.md
index d92ab354..1aac1ea5 100644
--- a/src/game-support/horizon-zero-dawn.md
+++ b/src/game-support/horizon-zero-dawn.md
@@ -1,4 +1,5 @@
# Horizon Zero Dawn
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
diff --git a/src/game-support/jjba-asbr.md b/src/game-support/jjba-asbr.md
index f155b7b6..4d0000a5 100644
--- a/src/game-support/jjba-asbr.md
+++ b/src/game-support/jjba-asbr.md
@@ -10,4 +10,4 @@
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1372110}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1372110}}
diff --git a/src/game-support/kenshi.md b/src/game-support/kenshi.md
index 6f8923d4..cfcb3dea 100644
--- a/src/game-support/kenshi.md
+++ b/src/game-support/kenshi.md
@@ -1,4 +1,5 @@
# Kenshi
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/kingsway.md b/src/game-support/kingsway.md
index 5c29edd1..17c958a1 100644
--- a/src/game-support/kingsway.md
+++ b/src/game-support/kingsway.md
@@ -1,5 +1,6 @@
# Kingsway
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=588950}}
\ No newline at end of file
+{{#template ../templates/steam.md id=588950}}
diff --git a/src/game-support/lego-sw-iii-clone-wars.md b/src/game-support/lego-sw-iii-clone-wars.md
index 58937f43..d35a6b4a 100644
--- a/src/game-support/lego-sw-iii-clone-wars.md
+++ b/src/game-support/lego-sw-iii-clone-wars.md
@@ -1,8 +1,15 @@
-# LEGO Star Wars III - The Clone Wars
+# LEGO Star Wars III: The Clone Wars
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=Yes}}
> [!WARNING]
> Opening scene is flashing a lot with some simply colored rectangles. In the middle of that, the game crashes.
-{{#template ../templates/steam.md id=32510}}
\ No newline at end of file
+{{#template ../templates/steam.md id=32510}}
diff --git a/src/game-support/lego-sw-skywalker-saga.md b/src/game-support/lego-sw-skywalker-saga.md
index c884aff1..c787f444 100644
--- a/src/game-support/lego-sw-skywalker-saga.md
+++ b/src/game-support/lego-sw-skywalker-saga.md
@@ -5,4 +5,4 @@
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=920210}}
\ No newline at end of file
+{{#template ../templates/steam.md id=920210}}
diff --git a/src/game-support/lethal-company.md b/src/game-support/lethal-company.md
index e69f4c18..32d7803e 100644
--- a/src/game-support/lethal-company.md
+++ b/src/game-support/lethal-company.md
@@ -1,4 +1,5 @@
# Lethal Company
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/manor-lords.md b/src/game-support/manor-lords.md
index 5d1dd143..ebaa6535 100644
--- a/src/game-support/manor-lords.md
+++ b/src/game-support/manor-lords.md
@@ -1,4 +1,5 @@
# Manor Lords
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
diff --git a/src/game-support/mb-wfas.md b/src/game-support/mb-wfas.md
index 41334a6c..cfbeebcf 100644
--- a/src/game-support/mb-wfas.md
+++ b/src/game-support/mb-wfas.md
@@ -1,8 +1,9 @@
# Mount & Blade: With Fire & Sword
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
> [!WARNING]
> Freezes after showing a Bing logo with a black screen.
-{{#template ../templates/steam.md id=48720}}
\ No newline at end of file
+{{#template ../templates/steam.md id=48720}}
diff --git a/src/game-support/metro-2033-rx.md b/src/game-support/metro-2033-rx.md
index ed5ad4f1..954001cb 100644
--- a/src/game-support/metro-2033-rx.md
+++ b/src/game-support/metro-2033-rx.md
@@ -1,8 +1,9 @@
# Metro 2033 Redux
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> Enabling tesselation causes objects that use this option like stones flickering. FPS may drop significantly when entering areas full of smoke and light. Also setting gamma doesn't work.
-{{#template ../templates/steam.md id=286690}}
\ No newline at end of file
+{{#template ../templates/steam.md id=286690}}
diff --git a/src/game-support/metro-ll-rx.md b/src/game-support/metro-ll-rx.md
index ab218f93..9a794ab6 100644
--- a/src/game-support/metro-ll-rx.md
+++ b/src/game-support/metro-ll-rx.md
@@ -8,4 +8,4 @@
> [!NOTE]
> When tesselation is set to "High" or "The Highest" option, it causes random textures to appear above the ground. FPS may drop significantly when entering areas full of smoke and light. Also setting gamma doesn't work.
-{{#template ../templates/steam.md id=287390}}
\ No newline at end of file
+{{#template ../templates/steam.md id=287390}}
diff --git a/src/game-support/mgs-5.md b/src/game-support/mgs-5.md
index 3e4a467e..c2a0e0ed 100644
--- a/src/game-support/mgs-5.md
+++ b/src/game-support/mgs-5.md
@@ -7,4 +7,4 @@
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=287700}}
\ No newline at end of file
+{{#template ../templates/steam.md id=287700}}
diff --git a/src/game-support/monster-hunter-world-iceborne.md b/src/game-support/monster-hunter-world-iceborne.md
index a565bdf3..5fd73f2f 100644
--- a/src/game-support/monster-hunter-world-iceborne.md
+++ b/src/game-support/monster-hunter-world-iceborne.md
@@ -8,4 +8,4 @@
- Do not enable DirectX 12, it will cause the game to crash.
- A black screen may show instead of the Capcom logo.
-{{#template ../templates/steam.md id=1118010}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1118010}}
diff --git a/src/game-support/neon-white.md b/src/game-support/neon-white.md
index 6abf04db..ccb7475b 100644
--- a/src/game-support/neon-white.md
+++ b/src/game-support/neon-white.md
@@ -1,5 +1,6 @@
# Neon White
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1533420}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1533420}}
diff --git a/src/game-support/overwatch-2.md b/src/game-support/overwatch-2.md
index 91f20528..55e2de02 100644
--- a/src/game-support/overwatch-2.md
+++ b/src/game-support/overwatch-2.md
@@ -1,7 +1,8 @@
# Overwatch 2
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
Overwatch 2 is currently **unplayable** in Whisky.
-{{#template ../templates/steam.md id=2357570}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2357570}}
diff --git a/src/game-support/palworld.md b/src/game-support/palworld.md
index 84e4a08e..e57f0218 100644
--- a/src/game-support/palworld.md
+++ b/src/game-support/palworld.md
@@ -1,4 +1,5 @@
# Palworld
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
diff --git a/src/game-support/people-playground.md b/src/game-support/people-playground.md
index 739b55bb..964c2f89 100644
--- a/src/game-support/people-playground.md
+++ b/src/game-support/people-playground.md
@@ -1,5 +1,6 @@
# People Playground
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1118200}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1118200}}
diff --git a/src/game-support/phasmophobia.md b/src/game-support/phasmophobia.md
index 3563fde3..61935e85 100644
--- a/src/game-support/phasmophobia.md
+++ b/src/game-support/phasmophobia.md
@@ -1,5 +1,6 @@
# Phasmophobia
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=739630}}
\ No newline at end of file
+{{#template ../templates/steam.md id=739630}}
diff --git a/src/game-support/prey-2017.md b/src/game-support/prey-2017.md
index cb9d1fff..c8c71174 100644
--- a/src/game-support/prey-2017.md
+++ b/src/game-support/prey-2017.md
@@ -10,4 +10,4 @@ Main game and Mooncrash DLC running smoothly
> [!NOTE]
> Turning V-Sync off will fix any slowdowns that occur. Unfortunately, you may have some screen-tearing.
-{{#template ../templates/steam.md id=480490}}
\ No newline at end of file
+{{#template ../templates/steam.md id=480490}}
diff --git a/src/game-support/quake2.md b/src/game-support/quake2.md
index 1f8f9b6e..e4bb378a 100644
--- a/src/game-support/quake2.md
+++ b/src/game-support/quake2.md
@@ -5,4 +5,4 @@
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=2320}}
\ No newline at end of file
+{{#template ../templates/steam.md id=2320}}
diff --git a/src/game-support/r2modman.md b/src/game-support/r2modman.md
index 57630eca..ad23ed68 100644
--- a/src/game-support/r2modman.md
+++ b/src/game-support/r2modman.md
@@ -1,4 +1,5 @@
# r2modman
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -17,3 +18,5 @@
> [!NOTE]
> If using the BepInEx framework, install `winhttp` through `Winetricks > DLLs` or override `winhttp` to `Native then Builtin` from `Wine Configuration` (console may not show up)
+
+
diff --git a/src/game-support/rain-world.md b/src/game-support/rain-world.md
index 4a777404..8ad7826c 100644
--- a/src/game-support/rain-world.md
+++ b/src/game-support/rain-world.md
@@ -1,7 +1,8 @@
# Rain World
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
Runs out of the box. A controller is required to play.
-{{#template ../templates/steam.md id=312520}}
\ No newline at end of file
+{{#template ../templates/steam.md id=312520}}
diff --git a/src/game-support/risk-of-rain-2.md b/src/game-support/risk-of-rain-2.md
index a505a420..98648328 100644
--- a/src/game-support/risk-of-rain-2.md
+++ b/src/game-support/risk-of-rain-2.md
@@ -1,8 +1,9 @@
# Risk of Rain 2
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
> [!NOTE]
> The game does not work with the multiplayer menu, as selecting multiplayer in the main menu freezes the game. Multiplayer through Steam invites still works, however.
-{{#template ../templates/steam.md id=632360}}
\ No newline at end of file
+{{#template ../templates/steam.md id=632360}}
diff --git a/src/game-support/risk-of-rain-returns.md b/src/game-support/risk-of-rain-returns.md
index ee4fb529..06aa2267 100644
--- a/src/game-support/risk-of-rain-returns.md
+++ b/src/game-support/risk-of-rain-returns.md
@@ -1,5 +1,6 @@
# Risk of Rain Returns
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1337520}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1337520}}
diff --git a/src/game-support/ruiner.md b/src/game-support/ruiner.md
index 4bf93372..5f56640c 100644
--- a/src/game-support/ruiner.md
+++ b/src/game-support/ruiner.md
@@ -1,5 +1,6 @@
# Ruiner
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=464060}}
\ No newline at end of file
+{{#template ../templates/steam.md id=464060}}
diff --git a/src/game-support/satisfactory.md b/src/game-support/satisfactory.md
index a320d0b4..49e3cff6 100644
--- a/src/game-support/satisfactory.md
+++ b/src/game-support/satisfactory.md
@@ -1,5 +1,6 @@
# Satisfactory
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=526870}}
\ No newline at end of file
+{{#template ../templates/steam.md id=526870}}
diff --git a/src/game-support/sekiro.md b/src/game-support/sekiro.md
index f9f75171..b526936e 100644
--- a/src/game-support/sekiro.md
+++ b/src/game-support/sekiro.md
@@ -5,4 +5,4 @@
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=814380}}
\ No newline at end of file
+{{#template ../templates/steam.md id=814380}}
diff --git a/src/game-support/skyrim-se.md b/src/game-support/skyrim-se.md
index d8077e03..4149c719 100644
--- a/src/game-support/skyrim-se.md
+++ b/src/game-support/skyrim-se.md
@@ -1,4 +1,5 @@
# Skyrim SE
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
diff --git a/src/game-support/stardew-valley.md b/src/game-support/stardew-valley.md
index f12943c8..436db496 100644
--- a/src/game-support/stardew-valley.md
+++ b/src/game-support/stardew-valley.md
@@ -1,8 +1,9 @@
# Stardew Valley
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> This game has a native Mac port.
-{{#template ../templates/steam.md id=413150}}
\ No newline at end of file
+{{#template ../templates/steam.md id=413150}}
diff --git a/src/game-support/stronghold-crusader-hd.md b/src/game-support/stronghold-crusader-hd.md
index 8570c37b..6334b3b3 100644
--- a/src/game-support/stronghold-crusader-hd.md
+++ b/src/game-support/stronghold-crusader-hd.md
@@ -1,5 +1,8 @@
# Stronghold Crusader HD
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=40970}}
\ No newline at end of file
+{{#template ../templates/steam.md id=40970}}
diff --git a/src/game-support/sw-squadrons.md b/src/game-support/sw-squadrons.md
index f2b74626..68b7c611 100644
--- a/src/game-support/sw-squadrons.md
+++ b/src/game-support/sw-squadrons.md
@@ -1,8 +1,8 @@
# Star Wars: Squadrons
+] -->
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1222730}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1222730}}
diff --git a/src/game-support/tcr6s.md b/src/game-support/tcr6s.md
index 76c18856..6cf4b334 100644
--- a/src/game-support/tcr6s.md
+++ b/src/game-support/tcr6s.md
@@ -8,4 +8,4 @@
Tom Clancy's Rainbow Six Siege is currently **unplayable** in Whisky.
-{{#template ../templates/steam.md id=359550}}
\ No newline at end of file
+{{#template ../templates/steam.md id=359550}}
diff --git a/src/game-support/template.md b/src/game-support/template.md
index f265be02..37313ff2 100644
--- a/src/game-support/template.md
+++ b/src/game-support/template.md
@@ -1,4 +1,5 @@
# Game Name
+
{{#template ../templates/rating.md status=[RATING] installs=[Y/N] opens=[Y/N]}}
@@ -6,4 +7,4 @@
- Lorem ipsum
-{{#template ../templates/steam.md id=APPID}}
\ No newline at end of file
+{{#template ../templates/steam.md id=APPID}}
diff --git a/src/game-support/tsp-ud.md b/src/game-support/tsp-ud.md
index c2ed017b..957bf6a8 100644
--- a/src/game-support/tsp-ud.md
+++ b/src/game-support/tsp-ud.md
@@ -5,4 +5,4 @@
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1703340}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1703340}}
diff --git a/src/game-support/turbo-overkill.md b/src/game-support/turbo-overkill.md
index 80da66ca..f3d81f0c 100644
--- a/src/game-support/turbo-overkill.md
+++ b/src/game-support/turbo-overkill.md
@@ -1,7 +1,8 @@
# Turbo Overkill
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
The game has longer than normal loading times, and some audio doesn't play during cutscenes. Otherwise, it runs very well.
-{{#template ../templates/steam.md id=1328350}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1328350}}
diff --git a/src/game-support/ultrakill.md b/src/game-support/ultrakill.md
index 5cc8a357..cf547a6b 100644
--- a/src/game-support/ultrakill.md
+++ b/src/game-support/ultrakill.md
@@ -1,5 +1,6 @@
# Ultrakill
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
-{{#template ../templates/steam.md id=1229490}}
\ No newline at end of file
+{{#template ../templates/steam.md id=1229490}}
diff --git a/src/game-support/undertale.md b/src/game-support/undertale.md
index b885713a..86070cd8 100644
--- a/src/game-support/undertale.md
+++ b/src/game-support/undertale.md
@@ -1,4 +1,5 @@
# Undertale
+
{{#template ../templates/rating.md status=Silver installs=Yes opens=Yes}}
@@ -7,4 +8,4 @@
Works, but suffers from severe audio stutters.
-{{#template ../templates/steam.md id=391540}}
\ No newline at end of file
+{{#template ../templates/steam.md id=391540}}
diff --git a/src/game-support/vanishing-of-ethan-carter.md b/src/game-support/vanishing-of-ethan-carter.md
index 27a27ac8..483952fb 100644
--- a/src/game-support/vanishing-of-ethan-carter.md
+++ b/src/game-support/vanishing-of-ethan-carter.md
@@ -1,8 +1,9 @@
# The Vanishing of Ethan Carter
+
{{#template ../templates/rating.md status=Garbage installs=Yes opens=No}}
> [!WARNING]
> The game launcher works. Running 32-bit version of the game causes an instant crash, while 64-bit opens with a few-seconds long black screen and then crashes too.
-{{#template ../templates/steam.md id=258520}}
\ No newline at end of file
+{{#template ../templates/steam.md id=258520}}
diff --git a/src/game-support/warframe.md b/src/game-support/warframe.md
index 6254f4d8..8575fd56 100644
--- a/src/game-support/warframe.md
+++ b/src/game-support/warframe.md
@@ -1,4 +1,5 @@
# Warframe
+
{{#template ../templates/rating.md status=Bronze installs=Yes opens=Yes}}
@@ -6,4 +7,4 @@
- Go to Bottle Configuration -> Open Wine Configuration -> Libraries
- Add `dwrite` library and set it to disabled
-{{#template ../templates/steam.md id=230410}}
\ No newline at end of file
+{{#template ../templates/steam.md id=230410}}
diff --git a/src/game-support/witcher3.md b/src/game-support/witcher3.md
index 28128adb..25fd647a 100644
--- a/src/game-support/witcher3.md
+++ b/src/game-support/witcher3.md
@@ -1,4 +1,5 @@
# The Witcher 3: Wild Hunt
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
@@ -7,4 +8,4 @@
> Ocassionaly there are objects pop-ups but overall it doesn't break the gameplay or immersion.
> DX11 is preffered over the DX12 due to the much better performance.
-{{#template ../templates/steam.md id=292030}}
\ No newline at end of file
+{{#template ../templates/steam.md id=292030}}
diff --git a/src/game-support/wolf-among-us.md b/src/game-support/wolf-among-us.md
index 121422a1..582ad91c 100644
--- a/src/game-support/wolf-among-us.md
+++ b/src/game-support/wolf-among-us.md
@@ -1,8 +1,9 @@
# The Wolf Among Us
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> There are a minor sound and video lags during the fighting scenes. The game sometimes crashes when starting a new Episode for the first time.
-{{#template ../templates/steam.md id=250320}}
\ No newline at end of file
+{{#template ../templates/steam.md id=250320}}
From 0e1a2d6858a63b50c54a09ed4cfef0158922b328 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Sun, 12 May 2024 01:17:59 -0700
Subject: [PATCH 13/17] Test invalid lint via amongus + add trailing new line
---
scripts/generate.mjs | 30 ++++++++++++++++++------------
scripts/lint.mjs | 19 +++++++++++++++++--
src/game-support/among-us.md | 3 ++-
3 files changed, 37 insertions(+), 15 deletions(-)
diff --git a/scripts/generate.mjs b/scripts/generate.mjs
index 1f4cf313..7f32b878 100755
--- a/scripts/generate.mjs
+++ b/scripts/generate.mjs
@@ -169,12 +169,18 @@ export const generateGameMetadata = async () => {
* @returns {string}
*/
export const generateLinks = links => {
- return '\n' + links
- .map(link => {
- return ` - [${markdownEscape(link.game.title)}](/game-support/${encodeURIComponent(basename(link.path))})`;
- })
- .join('\n') + '\n';
-}
+ return (
+ '\n' +
+ links
+ .map(link => {
+ return ` - [${markdownEscape(
+ link.game.title
+ )}](/game-support/${encodeURIComponent(basename(link.path))})`;
+ })
+ .join('\n') +
+ '\n'
+ );
+};
/**
* Generate the games.json file.
@@ -207,7 +213,7 @@ export const generateGamesJson = links => {
null,
2
);
-}
+};
/**
* Main function.
@@ -220,7 +226,6 @@ const main = async () => {
return 1;
}
-
// Get the SUMMARY.md file
/**
* @type {[string, null] | [null, Error]}
@@ -237,9 +242,8 @@ const main = async () => {
}
// Get the start and end of the SUMMARY.md file
- const [summarySections, summarySectionsError] = sectionsGetStartAndEnd(
- summaryFile
- );
+ const [summarySections, summarySectionsError] =
+ sectionsGetStartAndEnd(summaryFile);
if (summarySectionsError) {
logging.error('Failed to find start and end sections in SUMMARY.md.');
return 1;
@@ -286,4 +290,6 @@ const main = async () => {
return 0;
};
-main().then(code => process.exit(code));
+// Check if this is the file that is being run
+if (process.argv[1] === new URL(import.meta.url).pathname)
+ main().then(code => process.exit(code));
diff --git a/scripts/lint.mjs b/scripts/lint.mjs
index bdddfb5f..798df3cb 100755
--- a/scripts/lint.mjs
+++ b/scripts/lint.mjs
@@ -268,6 +268,17 @@ const lintMarkdownFile = async file => {
);
}
}
+
+ // There should be a trailing newline with no content
+ if (lineIndexes[lineIndexes.length - 1] !== content.length) {
+ logLintViolation(
+ 'warning',
+ file,
+ lineIndexes.length,
+ 1,
+ 'File should end with a newline.'
+ );
+ }
};
/**
@@ -314,7 +325,10 @@ const main = async () => {
} else if (!gameDataError) {
const [start, end] = summarySections;
// Slice at these indexes to get the content between the sections
- const contentBetweenSections = summaryFile.slice(start + SCRIPT_GENERATE_START.length, end);
+ const contentBetweenSections = summaryFile.slice(
+ start + SCRIPT_GENERATE_START.length,
+ end
+ );
// Check if the content between the sections is up to date
const expectedContent = generateLinks(gameData);
if (contentBetweenSections !== expectedContent) {
@@ -339,4 +353,5 @@ const main = async () => {
return 0;
};
-main().then(code => process.exit(code));
+if (process.argv[1] === new URL(import.meta.url).pathname)
+ main().then(code => process.exit(code));
diff --git a/src/game-support/among-us.md b/src/game-support/among-us.md
index f1428694..cbe75585 100644
--- a/src/game-support/among-us.md
+++ b/src/game-support/among-us.md
@@ -1,9 +1,10 @@
# Among Us
-
+a
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> This game has an iPad Mac port through the App Store.
{{#template ../templates/steam.md id=945360}}
+a
\ No newline at end of file
From 1cf134133d0afaa9dceffde5e85d22992fe9b80f Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Sun, 12 May 2024 01:25:52 -0700
Subject: [PATCH 14/17] Test if github anotations work
---
scripts/core.mjs | 4 +++-
scripts/lint.mjs | 5 ++++-
src/game-support/among-us.md | 2 +-
3 files changed, 8 insertions(+), 3 deletions(-)
diff --git a/scripts/core.mjs b/scripts/core.mjs
index 24a5555b..aa42afa7 100644
--- a/scripts/core.mjs
+++ b/scripts/core.mjs
@@ -233,7 +233,9 @@ export const checkGameEmbed = async embed => {
return [null, 'web-request-failed'];
}
- return [response.statusCode === 200, null];
+ if (response.statusCode === 200) {
+ return [true, null];
+ }
}
return [false, 'invalid-embed'];
diff --git a/scripts/lint.mjs b/scripts/lint.mjs
index 798df3cb..afccba41 100755
--- a/scripts/lint.mjs
+++ b/scripts/lint.mjs
@@ -33,6 +33,8 @@ const removeRootDir = path => {
return path.replace(CORE_PATHS.rootDir + '/', '');
};
+let hasBeenWarned = false;
+
/**
* Logs a lint violation.
* @param {'warning' | 'error'} type The type of violation.
@@ -42,6 +44,7 @@ const removeRootDir = path => {
* @param {string} message The violation message.
*/
const logLintViolation = (type = 'error', file, line, column, message) => {
+ hasBeenWarned = true;
if (isGithubAnotationsMode) {
const args = [];
file !== null && args.push(`file=${removeRootDir(file)}`);
@@ -350,7 +353,7 @@ const main = async () => {
await Promise.all(markdownFiles.map(file => lintMarkdownFile(file)));
- return 0;
+ return hasBeenWarned ? 1 : 0;
};
if (process.argv[1] === new URL(import.meta.url).pathname)
diff --git a/src/game-support/among-us.md b/src/game-support/among-us.md
index cbe75585..bd9b7601 100644
--- a/src/game-support/among-us.md
+++ b/src/game-support/among-us.md
@@ -6,5 +6,5 @@ a
> [!NOTE]
> This game has an iPad Mac port through the App Store.
-{{#template ../templates/steam.md id=945360}}
+{{#template ../templates/steam.md id=9453609234987329847}}
a
\ No newline at end of file
From f6685df0a190fe99ee01b93f95ca9d4384e3fedf Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Sun, 12 May 2024 01:29:08 -0700
Subject: [PATCH 15/17] Fix lint (:
---
src/game-support/among-us.md | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/src/game-support/among-us.md b/src/game-support/among-us.md
index bd9b7601..f1428694 100644
--- a/src/game-support/among-us.md
+++ b/src/game-support/among-us.md
@@ -1,10 +1,9 @@
# Among Us
-a
+
{{#template ../templates/rating.md status=Gold installs=Yes opens=Yes}}
> [!NOTE]
> This game has an iPad Mac port through the App Store.
-{{#template ../templates/steam.md id=9453609234987329847}}
-a
\ No newline at end of file
+{{#template ../templates/steam.md id=945360}}
From 0dfc5076df954c5f7b878013709dbafebe1f32e9 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Sun, 12 May 2024 01:39:06 -0700
Subject: [PATCH 16/17] Update game support status descriptions
---
src/game-support/README.md | 13 +++++++------
src/game-support/among-us.md | 1 +
2 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/src/game-support/README.md b/src/game-support/README.md
index 54ad3732..26a4591c 100644
--- a/src/game-support/README.md
+++ b/src/game-support/README.md
@@ -10,11 +10,12 @@ be sure to contribute to these docs on GitHub.
Game support status is rated on a scale. The placement of a particular
title is partially left to the article author, but some general guidelines apply.
-| Status | Description |
-| ------- | ---------------------------------------------------------------------------------------------- |
-| Gold | Game works out-of-the-box with no issues and/or requires minimal workarounds. |
-| Silver | Game requires some workarounds, but they are simple and/or there are minor in-game issues |
-| Bronze | Game is very difficult to get working and/or has severe in-game issues that limit playability. |
-| Garbage | Game does not work at all. |
+| Status | Description |
+| -------- | ---------------------------------------------------------------------------------------------- |
+| Platinum | Game without any defects and runs perfectly. |
+| Gold | Game can be configured to run perfectly and without any defects. |
+| Silver | Game requires some configuration to run and or has minor defects. |
+| Bronze | Game is very difficult to get working and/or has severe in-game issues that limit playability. |
+| Garbage | Game does not work at all. |
diff --git a/src/game-support/among-us.md b/src/game-support/among-us.md
index f1428694..60626ade 100644
--- a/src/game-support/among-us.md
+++ b/src/game-support/among-us.md
@@ -7,3 +7,4 @@
> This game has an iPad Mac port through the App Store.
{{#template ../templates/steam.md id=945360}}
+a
\ No newline at end of file
From b25c5bafa68bfe4ec597be29c9bfc564a0509ec2 Mon Sep 17 00:00:00 2001
From: Josh <36625023+JoshuaBrest@users.noreply.github.com>
Date: Sun, 12 May 2024 01:40:33 -0700
Subject: [PATCH 17/17] Remove "a"
---
src/game-support/among-us.md | 1 -
1 file changed, 1 deletion(-)
diff --git a/src/game-support/among-us.md b/src/game-support/among-us.md
index 60626ade..f1428694 100644
--- a/src/game-support/among-us.md
+++ b/src/game-support/among-us.md
@@ -7,4 +7,3 @@
> This game has an iPad Mac port through the App Store.
{{#template ../templates/steam.md id=945360}}
-a
\ No newline at end of file