Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 76 additions & 53 deletions biome.json
Original file line number Diff line number Diff line change
@@ -1,55 +1,78 @@
{
"$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
"vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
"files": {
"ignoreUnknown": true,
"includes": ["test/**/*.ts", "lib/**/*.ts"]
},
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 80,
"attributePosition": "auto",
"bracketSameLine": false,
"bracketSpacing": true,
"expand": "auto",
"useEditorconfig": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": { "useArrowFunction": "off" },
"style": { "noNonNullAssertion": "off", "useImportType": "on" },
"suspicious": { "noExplicitAny": "warn" }
},
"includes": ["**", "!.github/**", "!docs/**", "!data/**"],
"domains": { "test": "recommended" }
},
"javascript": {
"formatter": {
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"trailingCommas": "all",
"semicolons": "asNeeded",
"arrowParentheses": "always",
"bracketSameLine": false,
"quoteStyle": "single",
"attributePosition": "auto",
"bracketSpacing": true
}
},
"html": {
"formatter": {
"indentScriptAndStyle": false,
"selfCloseVoidElements": "always"
}
},
"assist": {
"enabled": true,
"actions": { "source": { "organizeImports": "on" } }
}
"$schema": "https://biomejs.dev/schemas/2.3.10/schema.json",
"vcs": { "enabled": false, "clientKind": "git", "useIgnoreFile": false },
"files": {
"ignoreUnknown": true,
"includes": ["test/**/*.ts", "lib/**/*.ts"]
},
"formatter": {
"enabled": true,
"formatWithErrors": false,
"indentStyle": "space",
"indentWidth": 2,
"lineEnding": "lf",
"lineWidth": 80,
"attributePosition": "auto",
"bracketSameLine": false,
"bracketSpacing": true,
"expand": "auto",
"useEditorconfig": true
},
"linter": {
"enabled": true,
"rules": {
"recommended": true,
"complexity": { "useArrowFunction": "off" },
"style": { "noNonNullAssertion": "off", "useImportType": "on" },
"suspicious": { "noExplicitAny": "warn" }
},
"includes": ["**", "!.github/**", "!docs/**", "!data/**"],
"domains": { "test": "recommended" }
},
"javascript": {
"formatter": {
"jsxQuoteStyle": "double",
"quoteProperties": "asNeeded",
"trailingCommas": "es5",
"semicolons": "always",
"arrowParentheses": "always",
"bracketSameLine": false,
"quoteStyle": "single",
"attributePosition": "auto",
"bracketSpacing": true
}
},
"html": {
"formatter": {
"indentScriptAndStyle": false,
"selfCloseVoidElements": "always"
}
},
"assist": {
"enabled": true,
"actions": {
"source": {
"organizeImports": {
"level": "on",
"options": {
"identifierOrder": "natural",
"groups": [
":URL:",
":BLANK_LINE:",
[":NODE:", ":BUN:"],
":BLANK_LINE:",
["!@*/**", ":PACKAGE_WITH_PROTOCOL:", ":PACKAGE:"],
":BLANK_LINE:",
["@wfcd/", "@wfcd/**"],
":BLANK_LINE:",
["@/models", "@/models/**", "@/supporting", "@/supporting/**"],
["@/data/**"],
":BLANK_LINE:",
":RELATIVE:"
]
}
}
}
}
}
}
167 changes: 112 additions & 55 deletions lib/WorldState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,42 +2,63 @@ import { createHash } from 'node:crypto';

import wsData from 'warframe-worldstate-data';
import { parseDate } from 'warframe-worldstate-data/utilities';
import Alert, { type RawAlert } from './models/Alert';
import Archimedea, { type RawArchimedea } from './models/Archidemea';
import Calendar, { type RawCalender } from './models/Calendar';
import CambionCycle from './models/CambionCycle';
import CetusCycle from './models/CetusCycle';
import ConclaveChallenge, { type RawChallenge } from './models/ConclaveChallenge';
import ConstructionProgress from './models/ConstructionProgress';
import DailyDeal, { type RawDailyDeal } from './models/DailyDeal';
import DarkSector, { type RawDarkSector } from './models/DarkSector';
import DuviriCycle from './models/DuviriCycle';
import EarthCycle from './models/EarthCycle';
import Fissure, { type RawFissure } from './models/Fissure';
import FlashSale, { type RawFlashSale } from './models/FlashSale';
import GlobalUpgrade, { type RawGlobalUpgrade } from './models/GlobalUpgrade';
import Invasion, { type RawInvasion } from './models/Invasion';
import type Kinepage from './models/Kinepage';
import Kuva from './models/Kuva';
import News, { type RawNews } from './models/News';
import Nightwave, { type RawNightwave } from './models/Nightwave';
import PersistentEnemy, { type RawPersistentEnemy } from './models/PersistentEnemy';
import type SentientOutpost from './models/SentientOutpost';
import Simaris, { type LibraryInfo } from './models/Simaris';
import Sortie, { type RawSortie } from './models/Sortie';
import SteelPathOffering from './models/SteelPathOffering';
import SyndicateMission, { type RawSyndicateMission } from './models/SyndicateMission';
import VallisCycle from './models/VallisCycle';
import VoidTrader, { type RawVoidTrader } from './models/VoidTrader';
import WeeklyChallenge, { type RawWeeklyChallenge } from './models/WeeklyChallenge';
import WorldEvent, { type RawWorldEvent } from './models/WorldEvent';
import type WorldstateObject from './models/WorldstateObject';
import type { BaseContentObject } from './models/WorldstateObject';
import ZarimanCycle from './models/ZarimanCycle';
import type Dependency from './supporting/Dependency';
import DuviriChoice, { type RawChoice } from './supporting/DuviriChoice';
import type ExternalMission from './supporting/ExternalMission';
import { Tmp } from './Tmp';

import {
Alert,
Archimedea,
type BaseContentObject,
Calendar,
CambionCycle,
CetusCycle,
ConclaveChallenge,
ConstructionProgress,
DailyDeal,
DarkSector,
DuviriCycle,
EarthCycle,
Fissure,
FlashSale,
GlobalUpgrade,
Invasion,
type Kinepage,
Kuva,
type LibraryInfo,
News,
Nightwave,
PersistentEnemy,
type RawAlert,
type RawArchimedea,
type RawCalender,
type RawChallenge,
type RawDailyDeal,
type RawDarkSector,
type RawFissure,
type RawFlashSale,
type RawGlobalUpgrade,
type RawInvasion,
type RawNews,
type RawNightwave,
type RawPersistentEnemy,
type RawSortie,
type RawSyndicateMission,
type RawVoidTrader,
type RawWeeklyChallenge,
type RawWorldEvent,
type SentientOutpost,
Simaris,
Sortie,
SteelPathOfferings,
SyndicateMission,
Tmp,
VallisCycle,
VoidTrader,
WeeklyChallenge,
WorldEvent,
type WorldStateObject,
ZarimanCycle,
} from '@/models';
import type { Dependency, ExternalMission } from '@/supporting';
import { DuviriChoice, type RawChoice } from '@/supporting';

const { sortie } = wsData;

Expand All @@ -62,7 +83,8 @@ const defaultDeps: Dependency = {
* @param uniqueField field to treat as unique
* @returns array of parsed objects
*/
export function parseArray<T, D extends BaseContentObject>( // Not all instances of T extend WorldstateObject
export function parseArray<T, D extends BaseContentObject>(
// Not all instances of T extend WorldStateObject
ParserClass: new (data: D, deps: Dependency) => T,
dataArray: Array<D>,
deps: Dependency,
Expand Down Expand Up @@ -94,7 +116,10 @@ export function parseArray<T, D extends BaseContentObject>( // Not all instances
* @param uniqueField field to treat as unique
* @returns array of parsed objects
*/
export async function parseAsyncArray<T extends WorldstateObject, D extends BaseContentObject>(
export async function parseAsyncArray<
T extends WorldStateObject,
D extends BaseContentObject,
>(
ParserClass: { build: (data: D, deps: Dependency) => Promise<T> },
dataArray: Array<D>,
deps: Dependency,
Expand Down Expand Up @@ -308,7 +333,7 @@ export class WorldState {
/**
* Steel path offering rotation
*/
steelPath: SteelPathOffering;
steelPath: SteelPathOfferings;

/**
* The current prime resurgence
Expand Down Expand Up @@ -353,16 +378,28 @@ export class WorldState {
/**
* Generates the worldstate json as a string into usable objects
*/
static async build(json: string, deps: Dependency = defaultDeps): Promise<WorldState> {
static async build(
json: string,
deps: Dependency = defaultDeps
): Promise<WorldState> {
if (typeof json !== 'string') {
throw new TypeError(`json needs to be a string, provided ${typeof json} : ${JSON.stringify(json)}`);
throw new TypeError(
`json needs to be a string, provided ${typeof json} : ${JSON.stringify(json)}`
);
}

const data = JSON.parse(json);
const ws = new WorldState(data, deps);

ws.events = await parseAsyncArray(WorldEvent, data.Goals, deps);
ws.syndicateMissions = await parseAsyncArray(SyndicateMission, data.SyndicateMissions, deps, 'syndicate');
ws.events = await parseAsyncArray<WorldEvent, RawWorldEvent>(
WorldEvent,
data.Goals,
deps
);
ws.syndicateMissions = await parseAsyncArray<
SyndicateMission,
RawSyndicateMission
>(SyndicateMission, data.SyndicateMissions, deps, 'syndicate');

return ws;
}
Expand All @@ -384,7 +421,9 @@ export class WorldState {
this.news = parseArray(
News,
safeArray<RawNews>(data.Events).filter(
(e) => typeof e.Messages.find((msg) => msg.LanguageCode === deps.locale) !== 'undefined'
(e) =>
typeof e.Messages.find((msg) => msg.LanguageCode === deps.locale) !==
'undefined'
),
deps
);
Expand All @@ -397,7 +436,9 @@ export class WorldState {

this.syndicateMissions = [];

this.fissures = parseArray(Fissure, data.ActiveMissions, deps).concat(parseArray(Fissure, data.VoidStorms, deps));
this.fissures = parseArray(Fissure, data.ActiveMissions, deps).concat(
parseArray(Fissure, data.VoidStorms, deps)
);

this.globalUpgrades = parseArray(GlobalUpgrade, data.GlobalUpgrades, deps);

Expand All @@ -417,17 +458,27 @@ export class WorldState {

this.simaris = new Simaris(safeObj(data.LibraryInfo), deps);

this.conclaveChallenges = parseArray(ConclaveChallenge, data.PVPChallengeInstances, deps);
this.conclaveChallenges = parseArray(
ConclaveChallenge,
data.PVPChallengeInstances,
deps
);

this.persistentEnemies = parseArray(PersistentEnemy, data.PersistentEnemies, deps);
this.persistentEnemies = parseArray(
PersistentEnemy,
data.PersistentEnemies,
deps
);

this.earthCycle = new EarthCycle();

// bounties are 2.5 hours regardless of faction, so this can be reused
const cetusSynd = safeArray<RawSyndicateMission>(data.SyndicateMissions).filter(
(syndicate) => syndicate.Tag === 'CetusSyndicate'
const cetusSynd = safeArray<RawSyndicateMission>(
data.SyndicateMissions
).filter((syndicate) => syndicate.Tag === 'CetusSyndicate');
const bountyEnd = parseDate(
cetusSynd.length > 0 ? cetusSynd[0].Expiry : { $date: { $numberLong: 0 } }
);
const bountyEnd = parseDate(cetusSynd.length > 0 ? cetusSynd[0].Expiry : { $date: { $numberLong: 0 } });

this.cetusCycle = new CetusCycle(bountyEnd);

Expand All @@ -437,7 +488,9 @@ export class WorldState {

// this.midrathCycle = new MidrathCycle();

this.weeklyChallenges = data.WeeklyChallenges ? new WeeklyChallenge(data.WeeklyChallenges) : undefined;
this.weeklyChallenges = data.WeeklyChallenges
? new WeeklyChallenge(data.WeeklyChallenges)
: undefined;

this.constructionProgress = new ConstructionProgress(data.ProjectPct);

Expand Down Expand Up @@ -467,9 +520,12 @@ export class WorldState {
};
}

this.steelPath = new SteelPathOffering(deps);
this.steelPath = new SteelPathOfferings(deps);

[this.vaultTrader] = parseArray(VoidTrader, data.PrimeVaultTraders, { ...deps, character: 'Varzia' });
[this.vaultTrader] = parseArray(VoidTrader, data.PrimeVaultTraders, {
...deps,
character: 'Varzia',
});

[this.archonHunt] = parseArray(Sortie, data.LiteSorties, deps);

Expand All @@ -479,7 +535,7 @@ export class WorldState {
[this.calendar] = parseArray(Calendar, data.KnownCalendarSeasons, deps);

this.archimedeas = parseArray(Archimedea, data.Conquests, deps);

({
kinepage: this.kinepage,
sentientOutposts: this.sentientOutposts,
Expand All @@ -489,4 +545,5 @@ export class WorldState {
}
}

export default async (json: string, deps: Dependency) => WorldState.build(json, deps);
export default async (json: string, deps: Dependency) =>
WorldState.build(json, deps);
Loading