Skip to content

Commit

Permalink
CODEBASE: Fix lint errors 3 (bitburner-official#1758)
Browse files Browse the repository at this point in the history
This is a really big refactor because it actually *fixes* a lot of the lint errors instead of disabling them.
  • Loading branch information
catloversg authored Nov 14, 2024
1 parent 97ca8c5 commit 75cf9c8
Show file tree
Hide file tree
Showing 31 changed files with 187 additions and 51 deletions.
14 changes: 14 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,4 +42,18 @@ module.exports = {
version: "detect",
},
},
overrides: [
/**
* Some enums are subsets of other enums. For example, UniversityLocationName contains locations of 3 universities.
* With each member, we refer to the respective LocationName's member instead of using a literal string. This usage
* is okay, but it triggers the "prefer-literal-enum-member" rule. This rule is not useful in this case, so we
* suppress it in NetscriptDefinitions.d.ts.
*/
{
files: ["src/ScriptEditor/NetscriptDefinitions.d.ts"],
rules: {
"@typescript-eslint/prefer-literal-enum-member": ["off"],
},
},
],
};
8 changes: 8 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"@types/react-beautiful-dnd": "^13.1.5",
"@types/react-dom": "^17.0.21",
"@types/react-resizable": "^3.0.5",
"@types/sprintf-js": "^1.1.4",
"@typescript-eslint/eslint-plugin": "^6.9.1",
"@typescript-eslint/parser": "^6.9.1",
"babel-jest": "^29.7.0",
Expand Down
6 changes: 4 additions & 2 deletions src/Bladeburner/Bladeburner.ts
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ import { Sleeve } from "../PersonObjects/Sleeve/Sleeve";
import { autoCompleteTypeShorthand } from "./utils/terminalShorthands";
import { resolveTeamCasualties, type OperationTeam } from "./Actions/TeamCasualties";
import { shuffleArray } from "../Infiltration/ui/BribeGame";
import { objectAssert } from "../utils/helpers/typeAssertion";

export const BladeburnerPromise: PromisePair<number> = { promise: null, resolve: null };

Expand Down Expand Up @@ -1403,9 +1404,10 @@ export class Bladeburner implements OperationTeam {

/** Initializes a Bladeburner object from a JSON save state. */
static fromJSON(value: IReviverValue): Bladeburner {
objectAssert(value.data);
// operations and contracts are not loaded directly from the save, we load them in using a different method
const contractsData = value.data?.contracts;
const operationsData = value.data?.operations;
const contractsData = value.data.contracts;
const operationsData = value.data.operations;
const bladeburner = Generic_fromJSON(Bladeburner, value.data, Bladeburner.keysToLoad);
// Loading this way allows better typesafety and also allows faithfully reconstructing contracts/operations
// even from save data that is missing a lot of static info about the objects.
Expand Down
2 changes: 2 additions & 0 deletions src/CodingContracts.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { codingContractTypesMetadata } from "./data/codingcontracttypes";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "./utils/JSONReviver";
import { CodingContractEvent } from "./ui/React/CodingContractModal";
import { ContractFilePath, resolveContractFilePath } from "./Paths/ContractFilePath";
import { objectAssert } from "./utils/helpers/typeAssertion";

/* Contract Types */
export const CodingContractTypes = Object.fromEntries(codingContractTypesMetadata.map((x) => [x.name, x]));
Expand Down Expand Up @@ -127,6 +128,7 @@ export class CodingContract {

/** Initializes a CodingContract from a JSON save state. */
static fromJSON(value: IReviverValue): CodingContract {
objectAssert(value.data);
// In previous versions, there was a data field instead of a state field.
if ("data" in value.data) {
value.data.state = value.data.data;
Expand Down
1 change: 1 addition & 0 deletions src/Corporation/CorporationState.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { CorpStateName } from "@nsdefs";
import { Generic_fromJSON, Generic_toJSON, IReviverValue, constructorsForReviver } from "../utils/JSONReviver";
import { stateNames } from "./data/Constants";

export class CorporationState {
// Number representing what state the Corporation is in. The number
// is an index for the array that holds all Corporation States
Expand Down
6 changes: 0 additions & 6 deletions src/Gang/GangMember.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,12 +100,6 @@ export class GangMember {
}

getTask(): GangMemberTask {
// TODO unplanned: transfer that to a save file migration function
// Backwards compatibility
if ((this.task as any) instanceof GangMemberTask) {
this.task = (this.task as any).name;
}

if (Object.hasOwn(GangMemberTasks, this.task)) {
return GangMemberTasks[this.task];
}
Expand Down
4 changes: 2 additions & 2 deletions src/Infiltration/ui/MinesweeperGame.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -165,9 +165,9 @@ function fieldEquals(a: boolean[][], b: boolean[][]): boolean {
}

function generateEmptyField(difficulty: Difficulty): boolean[][] {
const field = [];
const field: boolean[][] = [];
for (let i = 0; i < Math.round(difficulty.height); i++) {
field.push(new Array(Math.round(difficulty.width)).fill(false));
field.push(new Array<boolean>(Math.round(difficulty.width)).fill(false));
}
return field;
}
Expand Down
21 changes: 17 additions & 4 deletions src/NetscriptFunctions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,12 @@ import {
GymType,
JobName,
JobField,
LiteratureName,
type LiteratureName,
LocationName,
ToastVariant,
UniversityClassType,
CompanyName,
type MessageFilename,
} from "@enums";
import { PromptEvent } from "./ui/React/PromptManager";
import { GetServer, DeleteServer, AddToAllServers, createUniqueRandomIp } from "./Server/AllServers";
Expand Down Expand Up @@ -145,8 +146,19 @@ export const ns: InternalAPI<NSFull> = {
stock: NetscriptStockMarket(),
grafting: NetscriptGrafting(),
hacknet: NetscriptHacknet(),
sprintf: () => sprintf,
vsprintf: () => vsprintf,
sprintf:
(ctx) =>
(_format, ...args) => {
const format = helpers.string(ctx, "format", _format);
return sprintf(format, ...(args as unknown[]));
},
vsprintf: (ctx) => (_format, _args) => {
const format = helpers.string(ctx, "format", _format);
if (!Array.isArray(_args)) {
throw helpers.errorMessage(ctx, `args must be an array.`);
}
return vsprintf(format, _args);
},
scan: (ctx) => (_hostname) => {
const hostname = _hostname ? helpers.string(ctx, "hostname", _hostname) : ctx.workerScript.hostname;
const server = helpers.getServer(ctx, hostname);
Expand Down Expand Up @@ -1163,7 +1175,8 @@ export const ns: InternalAPI<NSFull> = {
if (!path) return false;
if (hasScriptExtension(path)) return server.scripts.has(path);
if (hasTextExtension(path)) return server.textFiles.has(path);
if (path.endsWith(".lit") || path.endsWith(".msg")) return server.messages.includes(path as any);
if (path.endsWith(".lit") || path.endsWith(".msg"))
return server.messages.includes(path as LiteratureName | MessageFilename);
if (hasContractExtension(path)) return !!server.contracts.find(({ fn }) => fn === path);
const lowerPath = path.toLowerCase();
return server.programs.map((programName) => programName.toLowerCase()).includes(lowerPath);
Expand Down
7 changes: 5 additions & 2 deletions src/NetscriptFunctions/Flags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { toNative } from "./toNative";
import libarg from "arg";
import { NetscriptContext } from "../Netscript/APIWrapper";

export type Schema = [string, string | number | boolean | string[]][];
type FlagType = StringConstructor | NumberConstructor | BooleanConstructor | StringConstructor[];
type FlagsRet = Record<string, ScriptArg | string[]>;
export function Flags(ctx: NetscriptContext | string[]): (data: unknown) => FlagsRet {
Expand All @@ -12,7 +13,7 @@ export function Flags(ctx: NetscriptContext | string[]): (data: unknown) => Flag
if (!Array.isArray(schema)) throw new Error("flags schema passed in is invalid.");
const args: Record<string, FlagType> = {};

for (const d of schema) {
for (const d of schema as Schema) {
let t: FlagType = String;
if (typeof d[1] === "number") {
t = Number;
Expand All @@ -24,13 +25,15 @@ export function Flags(ctx: NetscriptContext | string[]): (data: unknown) => Flag
const numDashes = d[0].length > 1 ? 2 : 1;
args["-".repeat(numDashes) + d[0]] = t;
}
// eslint-disable-next-line @typescript-eslint/no-unsafe-call, @typescript-eslint/no-unsafe-assignment
const ret: FlagsRet = libarg(args, { argv: vargs });
for (const d of schema) {
for (const d of schema as Schema) {
if (!Object.hasOwn(ret, "--" + d[0]) || !Object.hasOwn(ret, "-" + d[0])) ret[d[0]] = d[1];
}
for (const key of Object.keys(ret)) {
if (!key.startsWith("-")) continue;
const value = ret[key];
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete ret[key];
const numDashes = key.length === 2 ? 1 : 2;
ret[key.slice(numDashes)] = value;
Expand Down
6 changes: 3 additions & 3 deletions src/NetscriptFunctions/UserInterface.ts
Original file line number Diff line number Diff line change
Expand Up @@ -82,14 +82,14 @@ export function NetscriptUserInterface(): InternalAPI<IUserInterface> {
setStyles: (ctx) => (newStyles) => {
const styleValidator: Record<string, string | number | undefined> = {};
assertObjectType(ctx, "newStyles", newStyles, styleValidator);
const currentStyles = { ...Settings.styles };
const currentStyles: Record<string, unknown> = { ...Settings.styles };
const errors: string[] = [];
for (const key of Object.keys(newStyles)) {
if (!(currentStyles as any)[key]) {
if (!currentStyles[key]) {
// Invalid key
errors.push(`Invalid key "${key}"`);
} else {
(currentStyles as any)[key] = newStyles[key];
currentStyles[key] = newStyles[key];
}
}

Expand Down
1 change: 1 addition & 0 deletions src/PersonObjects/Player/PlayerObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ export class PlayerObject extends Person implements IPlayer {
// Remove any invalid jobs
for (const [loadedCompanyName, loadedJobName] of Object.entries(player.jobs)) {
if (!isMember("CompanyName", loadedCompanyName) || !isMember("JobName", loadedJobName)) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete player.jobs[loadedCompanyName as CompanyName];
}
}
Expand Down
1 change: 1 addition & 0 deletions src/PersonObjects/Player/PlayerObjectGeneralMethods.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ export function quitJob(this: PlayerObject, company: CompanyName, suppressDialog
}
}
}
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete this.jobs[company];
}

Expand Down
2 changes: 2 additions & 0 deletions src/PersonObjects/Sleeve/Work/SleeveBladeburnerWork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import { scaleWorkStats } from "../../../Work/WorkStats";
import { getKeyList } from "../../../utils/helpers/getKeyList";
import { loadActionIdentifier } from "../../../Bladeburner/utils/loadActionIdentifier";
import { invalidWork } from "../../../Work/InvalidWork";
import { objectAssert } from "../../../utils/helpers/typeAssertion";

interface SleeveBladeburnerWorkParams {
actionId: ActionIdentifier & { type: BladeburnerActionType.General | BladeburnerActionType.Contract };
Expand Down Expand Up @@ -98,6 +99,7 @@ export class SleeveBladeburnerWork extends SleeveWorkClass {

/** Initializes a BladeburnerWork object from a JSON save state. */
static fromJSON(value: IReviverValue): SleeveBladeburnerWork {
objectAssert(value.data);
const actionId = loadActionIdentifier(value.data?.actionId);
if (!actionId) return invalidWork();
value.data.actionId = actionId;
Expand Down
10 changes: 8 additions & 2 deletions src/PersonObjects/Sleeve/Work/SleeveClassWork.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import { Sleeve } from "../Sleeve";
import { scaleWorkStats, WorkStats } from "../../../Work/WorkStats";
import { Locations } from "../../../Locations/Locations";
import { isMember } from "../../../utils/EnumHelper";
import { objectAssert } from "../../../utils/helpers/typeAssertion";

export const isSleeveClassWork = (w: SleeveWorkClass | null): w is SleeveClassWork =>
w !== null && w.type === SleeveWorkType.CLASS;
Expand Down Expand Up @@ -54,8 +55,13 @@ export class SleeveClassWork extends SleeveWorkClass {

/** Initializes a ClassWork object from a JSON save state. */
static fromJSON(value: IReviverValue): SleeveClassWork {
if (!(value.data.classType in Classes)) value.data.classType = "Computer Science";
if (!(value.data.location in Locations)) value.data.location = LocationName.Sector12RothmanUniversity;
objectAssert(value.data);
if (typeof value.data.classType !== "string" || !(value.data.classType in Classes)) {
value.data.classType = "Computer Science";
}
if (typeof value.data.location !== "string" || !(value.data.location in Locations)) {
value.data.location = LocationName.Sector12RothmanUniversity;
}
return Generic_fromJSON(SleeveClassWork, value.data);
}
}
Expand Down
9 changes: 8 additions & 1 deletion src/SaveObject.ts
Original file line number Diff line number Diff line change
Expand Up @@ -225,7 +225,12 @@ class BitburnerSaveObject {

let parsedSaveData;
try {
parsedSaveData = JSON.parse(decodedSaveData);
parsedSaveData = JSON.parse(decodedSaveData) as {
ctor: string;
data: {
PlayerSave: string;
};
};
} catch (error) {
console.error(error); // We'll handle below
}
Expand Down Expand Up @@ -632,6 +637,7 @@ function evaluateVersionCompatibility(ver: string | number): void {
if (isNaN(intExp)) intExp = 0;
anyPlayer.exp.intelligence += intExp;
for (const field of removePlayerFields) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete anyPlayer[field];
}
for (const sleeve of anyPlayer.sleeves) {
Expand All @@ -640,6 +646,7 @@ function evaluateVersionCompatibility(ver: string | number): void {
if (isNaN(intExp)) intExp = 0;
anySleeve.exp.intelligence += intExp;
for (const field of removeSleeveFields) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete sleeve[field];
}
}
Expand Down
5 changes: 4 additions & 1 deletion src/ScriptEditor/ui/themes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,10 @@ export const sanitizeTheme = (theme: IScriptEditorTheme): void => {
return;
}
for (const themeKey of getRecordKeys(theme)) {
if (typeof theme[themeKey] !== "object") delete theme[themeKey];
if (typeof theme[themeKey] !== "object") {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete theme[themeKey];
}
switch (themeKey) {
case "base":
if (!["vs-dark", "vs"].includes(theme.base)) theme.base = "vs-dark";
Expand Down
14 changes: 13 additions & 1 deletion src/Server/AllServers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import { currentNodeMults } from "../BitNode/BitNodeMultipliers";
import { IPAddress, isIPAddress } from "../Types/strings";

import "../Script/RunningScript"; // For reviver side-effect
import { objectAssert } from "../utils/helpers/typeAssertion";

/**
* Map of all Servers that exist in the game
Expand Down Expand Up @@ -63,6 +64,7 @@ export function DeleteServer(serverkey: string): void {
for (const key of Object.keys(AllServers)) {
const server = AllServers[key];
if (server.ip !== serverkey && server.hostname !== serverkey) continue;
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete AllServers[key];
break;
}
Expand Down Expand Up @@ -100,6 +102,7 @@ export function AddToAllServers(server: Server | HacknetServer): void {

export const renameServer = (hostname: string, newName: string): void => {
AllServers[newName] = AllServers[hostname];
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete AllServers[hostname];
};

Expand Down Expand Up @@ -188,13 +191,22 @@ export function initForeignServers(homeComputer: Server): void {

export function prestigeAllServers(): void {
for (const member of Object.keys(AllServers)) {
// eslint-disable-next-line @typescript-eslint/no-dynamic-delete
delete AllServers[member];
}
AllServers = {};
}

export function loadAllServers(saveString: string): void {
AllServers = JSON.parse(saveString, Reviver);
const allServersData: unknown = JSON.parse(saveString, Reviver);
objectAssert(allServersData);
for (const [serverName, server] of Object.entries(allServersData)) {
if (!(server instanceof Server) && !(server instanceof HacknetServer)) {
throw new Error(`Server ${serverName} is not an instance of Server or HacknetServer.`);
}
}
// We validated the data above, so it's safe to typecast here.
AllServers = allServersData as typeof AllServers;
}

export function saveAllServers(): string {
Expand Down
Loading

0 comments on commit 75cf9c8

Please sign in to comment.