Compare commits

..

4 Commits

14 changed files with 78 additions and 54 deletions

View File

@ -62,8 +62,15 @@ jobs:
working-directory: ${{env.api-dir}} working-directory: ${{env.api-dir}}
run: | run: |
cd pokerogue_docs cd pokerogue_docs
pnpm typedoc
pnpm exec typedoc --out /tmp/docs --githubPages false --entryPoints ./src/ pnpm exec typedoc --out /tmp/docs --githubPages false --entryPoints ./src/
- name: Typecheck Node.js Scripts
working-directory: ${{env.api-dir}}
run: |
cd pokerogue_docs
pnpm typecheck:scripts
- name: Commit & Push docs - name: Commit & Push docs
if: github.event_name == 'push' if: github.event_name == 'push'
run: | run: |

View File

@ -177,9 +177,11 @@
} }
}, },
// Overrides to prevent unused import removal inside `overrides.ts` and enums files (for TSDoc linkcodes) // Overrides to prevent unused import removal inside `overrides.ts` and enums files (for TSDoc linkcodes),
// as well as inside script boilerplate files.
{ {
"includes": ["**/src/overrides.ts", "**/src/enums/**/*"], // TODO: Rename existing boilerplates in the folder and remove this last alias
"includes": ["**/src/overrides.ts", "**/src/enums/**/*", "scripts/**/*.boilerplate.ts", "**/boilerplates/*.ts"],
"linter": { "linter": {
"rules": { "rules": {
"correctness": { "correctness": {

View File

@ -16,6 +16,7 @@
"test:create": "node scripts/create-test/create-test.js", "test:create": "node scripts/create-test/create-test.js",
"eggMoves:parse": "node scripts/parse-egg-moves/main.js", "eggMoves:parse": "node scripts/parse-egg-moves/main.js",
"typecheck": "tsc --noEmit", "typecheck": "tsc --noEmit",
"typecheck:scripts": "tsc -p scripts/jsconfig.json",
"eslint": "eslint --fix .", "eslint": "eslint --fix .",
"eslint-ci": "eslint .", "eslint-ci": "eslint .",
"biome": "biome check --write --changed --no-errors-on-unmatched --diagnostic-level=error", "biome": "biome check --write --changed --no-errors-on-unmatched --diagnostic-level=error",
@ -30,6 +31,7 @@
"devDependencies": { "devDependencies": {
"@biomejs/biome": "2.0.0", "@biomejs/biome": "2.0.0",
"@ls-lint/ls-lint": "2.3.1", "@ls-lint/ls-lint": "2.3.1",
"@types/crypto-js": "^4.2.2",
"@types/jsdom": "^21.1.7", "@types/jsdom": "^21.1.7",
"@types/node": "^22.16.5", "@types/node": "^22.16.5",
"@vitest/coverage-istanbul": "^3.2.4", "@vitest/coverage-istanbul": "^3.2.4",

View File

@ -48,6 +48,9 @@ importers:
'@ls-lint/ls-lint': '@ls-lint/ls-lint':
specifier: 2.3.1 specifier: 2.3.1
version: 2.3.1 version: 2.3.1
'@types/crypto-js':
specifier: ^4.2.2
version: 4.2.2
'@types/jsdom': '@types/jsdom':
specifier: ^21.1.7 specifier: ^21.1.7
version: 21.1.7 version: 21.1.7
@ -718,6 +721,9 @@ packages:
'@types/cookie@0.6.0': '@types/cookie@0.6.0':
resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==} resolution: {integrity: sha512-4Kh9a6B2bQciAhf7FSuMRRkUWecJgJu9nPnx3yzpsfXX/c50REIqpHY4C82bXP90qrLtXtkDxTZosYO3UpOwlA==}
'@types/crypto-js@4.2.2':
resolution: {integrity: sha512-sDOLlVbHhXpAUAL0YHDUUwDZf3iN4Bwi4W6a0W0b+QcAezUbRtH4FVb+9J4h+XFPW7l/gQ9F8qC7P+Ec4k8QVQ==}
'@types/deep-eql@4.0.2': '@types/deep-eql@4.0.2':
resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==} resolution: {integrity: sha512-c9h9dVVMigMPc4bwTvC5dxqtqJZwQPePsWjPlpSOnojbor6pGqdk541lfA7AqFQr5pB1BRdq0juY9db81BwyFw==}
@ -2525,6 +2531,8 @@ snapshots:
'@types/cookie@0.6.0': {} '@types/cookie@0.6.0': {}
'@types/crypto-js@4.2.2': {}
'@types/deep-eql@4.0.2': {} '@types/deep-eql@4.0.2': {}
'@types/estree@1.0.8': {} '@types/estree@1.0.8': {}

View File

@ -1,38 +0,0 @@
{
"$schema": "https://biomejs.dev/schemas/2.0.0/schema.json",
// extend from base config in root dir
"extends": "//",
"files": {
"includes": ["**/*.{js,ts,jsx,tsx}"]
},
"linter": {
"rules": {
"style": {
// Unfortunately, TS does not support multiple configs, so we need to have Biome pull the slack
// and effectively enforce `noErasableSyntax`
"noEnum": "error",
"noNamespace": "error",
"noNonNullAssertion": "error", // TODO: Remove once added to main config
"useForOf": "error" // TODO: Move to main config
},
"suspicious": {
"noImplicitAnyLet": "error"
}
}
},
"overrides": [
// Prevent unused import removal inside boilerplate files.
// These are unused in the file themselves, but will become used once copied and converted to actual TS files.
// (If not, the generated files will themselves produce errors.)
{
"includes": ["**/*.boilerplate.ts", "**/boilerplates/*.ts"], // TODO: Rename existing boilerplates in the folder and remove this 2nd alias
"linter": {
"rules": {
"correctness": {
"noUnusedImports": "off"
}
}
}
}
]
}

View File

@ -156,7 +156,7 @@ async function runInteractive() {
console.log(chalk.green.bold(`✔ File created at: test/${localDir}/${fileName}.test.ts\n`)); console.log(chalk.green.bold(`✔ File created at: test/${localDir}/${fileName}.test.ts\n`));
console.groupEnd(); console.groupEnd();
} catch (err) { } catch (err) {
console.error(chalk.red("✗ Error: ", err.message)); console.error(chalk.red("✗ Error: ", err));
} }
} }

View File

@ -1,7 +1,6 @@
// Usage: node decrypt-save.js <encrypted-file> [save-file] // Usage: node decrypt-save.js <encrypted-file> [save-file]
// biome-ignore lint/performance/noNamespaceImport: This is how you import fs from node import fs from "node:fs";
import * as fs from "node:fs";
import crypto_js from "crypto-js"; import crypto_js from "crypto-js";
const { AES, enc } = crypto_js; const { AES, enc } = crypto_js;
@ -60,6 +59,11 @@ function decryptSave(path) {
try { try {
fileData = fs.readFileSync(path, "utf8"); fileData = fs.readFileSync(path, "utf8");
} catch (e) { } catch (e) {
if (!(e instanceof Error)) {
console.error(`Unrecognized error: ${e}`);
process.exit(1);
}
// @ts-expect-error: TODO fix
switch (e.code) { switch (e.code) {
case "ENOENT": case "ENOENT":
console.error(`File not found: ${path}`); console.error(`File not found: ${path}`);
@ -104,6 +108,13 @@ function writeToFile(filePath, data) {
try { try {
fs.writeFileSync(filePath, data); fs.writeFileSync(filePath, data);
} catch (e) { } catch (e) {
if (!(e instanceof Error)) {
console.error("Unknown error detected: ", e);
process.exitCode = 1;
return;
}
// @ts-expect-error - e is usually a SystemError (all of which have codes)
switch (e.code) { switch (e.code) {
case "EACCES": case "EACCES":
console.error(`Could not open ${filePath}: Permission denied`); console.error(`Could not open ${filePath}: Permission denied`);
@ -114,7 +125,8 @@ function writeToFile(filePath, data) {
default: default:
console.error(`Error writing file: ${e.message}`); console.error(`Error writing file: ${e.message}`);
} }
process.exit(1); process.exitCode = 1;
return;
} }
} }

View File

@ -1,12 +1,17 @@
{ {
"extends": "../tsconfig", "include": ["**/*.js"],
"include": ["**/*.{js,jsx}"],
"compilerOptions": { "compilerOptions": {
"allowJs": true,
"checkJs": true, "checkJs": true,
"rootDir": ".",
"target": "esnext", "target": "esnext",
"module": "nodenext", "module": "nodenext",
"moduleResolution": "nodenext", "moduleResolution": "nodenext",
"erasableSyntaxOnly": true, "erasableSyntaxOnly": true,
"strict": true "strict": true,
"noEmit": true,
// Forcibly disable `node_modules` recursion to prevent TSC from typechecking random JS files.
// This is disabled by default in `tsconfig.json`, but needs to be explicitly disabled from the default of `2`
"maxNodeModuleJsDepth": 0
} }
} }

View File

@ -1,5 +1,6 @@
import chalk from "chalk"; import chalk from "chalk";
/** Show help/usage text for the `eggMoves:parse` CLI. */
export function showHelpText() { export function showHelpText() {
console.log(` console.log(`
Usage: ${chalk.cyan("pnpm eggMoves:parse [options]")} Usage: ${chalk.cyan("pnpm eggMoves:parse [options]")}

View File

@ -23,6 +23,12 @@ const templatePath = path.join(__dirname, "egg-move-template.ts");
// TODO: Do we want this to be configurable? // TODO: Do we want this to be configurable?
const eggMoveTargetPath = path.join(projectRoot, "src/data/balance/egg-moves.ts"); const eggMoveTargetPath = path.join(projectRoot, "src/data/balance/egg-moves.ts");
/**
* @typedef {{type: "Console" | "File", value: string} | {type: "Exit"}}
* Option
* An option selected by the user.
*/
/** /**
* Runs the interactive eggMoves:parse CLI. * Runs the interactive eggMoves:parse CLI.
* @returns {Promise<void>} * @returns {Promise<void>}
@ -144,7 +150,7 @@ export async function writeToFile(moves) {
console.log(chalk.green.bold(`\n✔ Egg Moves written to ${eggMoveTargetPath}`)); console.log(chalk.green.bold(`\n✔ Egg Moves written to ${eggMoveTargetPath}`));
console.groupEnd(); console.groupEnd();
} catch (err) { } catch (err) {
console.error(chalk.red("✗ Error while writing egg moves!", err.message)); console.error(chalk.red(`✗ Error while writing egg moves: ${err}`));
process.exitCode = 1; process.exitCode = 1;
} }
} }

View File

@ -1,5 +1,16 @@
import chalk from "chalk"; import chalk from "chalk";
/**
* A single line of the inputted CSV.
* @typedef {[speciesName: string, move1: string, move2: string, move3: string, move4: string]}
* CSVLine
*/
/**
* Regex to determine if a string follows the required CSV format.
*/
const csvRegex = /^((?:[^,]+?,){4}(?:\w|\s)+?,?\n?)+$/g;
/** /**
* Given a CSV string, parse it and return a structured table ready to be inputted into code. * Given a CSV string, parse it and return a structured table ready to be inputted into code.
* @param {string} csv - The formatted CSV string. * @param {string} csv - The formatted CSV string.
@ -7,6 +18,12 @@ import chalk from "chalk";
*/ */
export function parseEggMoves(csv) { export function parseEggMoves(csv) {
console.log(chalk.grey("⚙️ Parsing egg moves...")); console.log(chalk.grey("⚙️ Parsing egg moves..."));
if (!csvRegex.test(csv)) {
console.error(chalk.redBright("! Input was not proper CSV!"));
process.exitCode = 1;
return "";
}
let output = "{\n"; let output = "{\n";
const lines = csv.split(/\n/g); const lines = csv.split(/\n/g);
@ -16,16 +33,17 @@ export function parseEggMoves(csv) {
* The individual CSV column for this species. * The individual CSV column for this species.
*/ */
const cols = const cols =
/** @type {[speciesName: string, move1: string, move2: string, move3: string, move4: string]} */ /** @type {CSVLine} */
(line.split(",").slice(0, 5)); (line.split(",").slice(0, 5));
const speciesName = toUpperSnakeCase(cols[0]); const speciesName = toUpperSnakeCase(cols[0]);
/** @type {string[]} */ const eggMoves =
const eggMoves = []; /** @type {string[]} */
([]);
for (let m = 1; m < 5; m++) { for (let m = 1; m < 5; m++) {
const moveName = cols[m].trim(); const moveName = cols[m].trim();
if (moveName === "N/A") { if (!moveName || moveName === "N/A") {
console.warn(`Species ${speciesName} missing ${m}th egg move!`); console.warn(`Species ${speciesName} missing ${m}th egg move!`);
eggMoves.push("MoveId.NONE"); eggMoves.push("MoveId.NONE");
continue; continue;

View File

@ -1,5 +1,6 @@
import overrides from "#app/overrides"; import overrides from "#app/overrides";
import type { Challenge } from "#data/challenge"; import type { Challenge } from "#data/challenge";
import { copyChallenge } from "#data/challenge";
import { BattleStyle } from "#enums/battle-style"; import { BattleStyle } from "#enums/battle-style";
import type { Challenges } from "#enums/challenges"; import type { Challenges } from "#enums/challenges";
import type { SpeciesId } from "#enums/species-id"; import type { SpeciesId } from "#enums/species-id";
@ -10,7 +11,6 @@ import { SelectStarterPhase } from "#phases/select-starter-phase";
import { TurnInitPhase } from "#phases/turn-init-phase"; import { TurnInitPhase } from "#phases/turn-init-phase";
import { generateStarter } from "#test/test-utils/game-manager-utils"; import { generateStarter } from "#test/test-utils/game-manager-utils";
import { GameManagerHelper } from "#test/test-utils/helpers/game-manager-helper"; import { GameManagerHelper } from "#test/test-utils/helpers/game-manager-helper";
import { copyChallenge } from "data/challenge";
/** /**
* Helper to handle Challenge mode specifics * Helper to handle Challenge mode specifics

View File

@ -57,6 +57,7 @@
"#app/*": ["./src/*.ts"] "#app/*": ["./src/*.ts"]
} }
}, },
"include": ["**/*.{ts,tsx}"], // Exclude checking for script JS files as those are covered by the folder's `jsconfig/json`
"include": ["**/*.ts", "**/*.d.ts"],
"exclude": ["node_modules", "dist", "vite.config.ts", "vitest.config.ts", "vitest.workspace.ts"] "exclude": ["node_modules", "dist", "vite.config.ts", "vitest.config.ts", "vitest.workspace.ts"]
} }