Skip to content

Commit

Permalink
feat: change how syndcate arrays parse (#540)
Browse files Browse the repository at this point in the history
BREAKING CHANGE: async data moved to build functions
  • Loading branch information
TobiTenno authored Jun 23, 2024
1 parent b71ba6d commit 0a182c4
Show file tree
Hide file tree
Showing 23 changed files with 283 additions and 171 deletions.
16 changes: 16 additions & 0 deletions .c8rc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"exclude": [
"test/**",
"lib/DarkSector*.js",
"lib/Alert.js",
"lib/PersistentEnemy.js",
"lib/GlobalUpgrade.js",
"lib/ChallengeInstance.js",
"lib/WeeklyChallenge.js"
],
"reporter": [
"lcov",
"text"
],
"skip-full": true
}
17 changes: 17 additions & 0 deletions .commitlintrc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { RuleConfigSeverity } from '@commitlint/types';

export default {
extends: [
'@commitlint/config-conventional'
],
rules: {
'body-max-line-length': [
RuleConfigSeverity.Disabled
],
'subject-case': [
RuleConfigSeverity.Error,
'never',
['sentence-case', 'start-case']
]
}
}
4 changes: 4 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.github/**
docs/**
resources/**
types/**
11 changes: 11 additions & 0 deletions .eslintrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
parser: '@babel/eslint-parser'
parserOptions:
ecmaFeatures:
modules: true
ecmaVersion: 6
sourceType: module
extends: '@wfcd/eslint-config/strict-esm-jsdoc'
rules:
import/extensions:
- error
- ignorePackages
8 changes: 8 additions & 0 deletions .lintstagedrc.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
'*.**,!package*.json':
- 'npm run fmt:fix'
'*.js':
- eslint --fix --cache
- npm test -- --reporter=mocha-minimalist-reporter
package*.json:
- npm dedupe
- npx sort-package-json
3 changes: 3 additions & 0 deletions .mocharc.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
exit: true
spec: test/**/*.spec.js
timeout: 10000
10 changes: 10 additions & 0 deletions .npmignore
Original file line number Diff line number Diff line change
Expand Up @@ -38,3 +38,13 @@ data.*.json
package.json.backup
.install/

# Other project configuration files
.c8rc.json
.commitlintrc.ts
.eslintignore
.eslintrc.yaml
.eslintcache
.lintstagedrc.yaml
.mocharc.yml
babel.config.cjs
clean-package.config.js
9 changes: 5 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,11 +23,12 @@ For the most part, you'll have a better experience consuming the product of this
## Example usage

```javascript
const worldstateData = await require('request-promise')('http://content.warframe.com/dynamic/worldState.php');
// import WorldState from 'warframe-worldstate-data';
// using this syntax to make it precisely testable in a test
const WorldStateParser = await import('warframe-worldstate-parser');
const worldstateData = await fetch('https://content.warframe.com/dynamic/worldState.php').then((data) => data.text());

const WorldState = require('warframe-worldstate-parser');

const ws = new WorldState(worldstateData);
const ws = await WorldStateParser(worldstateData);

console.log(ws.alerts[0].toString());
```
Expand Down
9 changes: 9 additions & 0 deletions babel.config.cjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
module.exports = {
plugins: [
'@babel/plugin-transform-class-properties',
'@babel/plugin-transform-private-methods'
],
presets: [
'@babel/preset-env'
]
}
17 changes: 17 additions & 0 deletions clean-package.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
export default {
remove: [
'devDependencies',
'scripts',
'release',
'eslintIgnore',
'eslintConfig',
'c8',
'mocha',
'clean-package',
'directories',
'prettier',
'babel',
'lint-staged',
'overrides'
]
}
53 changes: 48 additions & 5 deletions lib/WorldState.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export function parseArray(ParserClass, dataArray, deps, uniqueField) {
const arr = (dataArray || []).map((d) => new ParserClass(d, deps));
if (uniqueField) {
const utemp = {};
arr.sort((a, b) => a.id.localeCompare(b.id));
arr.sort((a, b) => a.id?.localeCompare(b.id));
arr.forEach((obj) => {
utemp[obj[uniqueField]] = obj;
});
Expand All @@ -71,14 +71,55 @@ export function parseArray(ParserClass, dataArray, deps, uniqueField) {
return arr;
}

/**
* Parse array of objects that requires async parsing
* @param {object} ParserClass class for parsing data - must expose a static build method
* @param {Array<BaseContentObject>} dataArray array of raw data
* @param {Dependency} deps shared dependency object
* @param {*} [uniqueField] field to treat as unique
* @returns {Promise<WorldstateObject[]>} array of parsed objects
*/
export const parseAsyncArray = async (ParserClass, dataArray, deps, uniqueField) => {
const arr = [];
// eslint-disable-next-line no-restricted-syntax
for await (const d of dataArray ?? []) {
arr.push(await ParserClass.build(d, deps));
}
if (uniqueField) {
const utemp = {};
arr.sort((a, b) => a.id.localeCompare(b.id));
arr.forEach((obj) => {
utemp[obj[uniqueField]] = obj;
});
return Array.from(arr).filter((obj) => {
if (obj && obj.active && typeof obj.active !== 'undefined') return obj.active;
/* istanbul ignore next */
return true;
});
}
return arr;
};

/**
* Parses Warframe Worldstate JSON
*/
export default class WorldState {
export class WorldState {
static async build(json, deps = defaultDeps) {
const ws = new WorldState(json, deps);
const data = JSON.parse(json);

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

return ws;
}

/**
* Generates the worldstate json as a string into usable objects
* @param {string} json The worldstate JSON string
* @param {Dependency} [deps] The options object
* @class
* @async
*/
constructor(json, deps = defaultDeps) {
if (typeof json !== 'string') {
Expand Down Expand Up @@ -114,7 +155,7 @@ export default class WorldState {
* The current events
* @type {Array.<WorldEvent>}
*/
this.events = parseArray(WorldEvent, data.Goals, deps);
this.events = [];

/**
* The current alerts
Expand All @@ -132,7 +173,7 @@ export default class WorldState {
* The current syndicate missions
* @type {Array.<SyndicateMission>}
*/
this.syndicateMissions = parseArray(SyndicateMission, data.SyndicateMissions, deps, 'syndicate');
this.syndicateMissions = [];

/**
* The current fissures: 'ActiveMissions' & 'VoidStorms'
Expand Down Expand Up @@ -298,7 +339,7 @@ export default class WorldState {
}

/**
* Current syndicate outposts
* Current sentient outposts
* @type {SentientOutpost}
*/
this.sentientOutposts = new SentientOutpost(data.Tmp, deps);
Expand All @@ -322,3 +363,5 @@ export default class WorldState {
this.duviriCycle = new DuviriCycle(deps);
}
}

export default async (json, deps) => WorldState.build(json, deps);
21 changes: 18 additions & 3 deletions lib/models/SyndicateJob.js
Original file line number Diff line number Diff line change
Expand Up @@ -84,10 +84,28 @@ const FIFTY_MINUTES = 3000000;
*/
export default class SyndicateJob extends WorldstateObject {
/**
* Generate a job with async data (reward pool)
* @param {object} data The syndicate mission data
* @param {Date} expiry The syndicate job expiration
* @param {object} deps The dependencies object
* @param {string} deps.locale Locale to use for translations
* @returns {Promise<SyndicateJob>} The created SyndicateJob object with rewardPool
*/
static async build(data, expiry, deps) {
const job = new SyndicateJob(data, expiry, deps);
job.rewardPool = await getBountyRewards(data.rewards, data.isVault, data);

return job;
}

/**
* Construct a job without async data (reward pool)
* @param {object} data The syndicate mission data
* @param {Date} expiry The syndicate job expiration
* @param {object} deps The dependencies object
* @param {string} deps.locale Locale to use for translations
*
* This DOES NOT populate the reward pool
*/
constructor(data, expiry, { locale = 'en' }) {
super({
Expand All @@ -103,9 +121,6 @@ export default class SyndicateJob extends WorldstateObject {
* @type {Array.<string>}
*/
this.rewardPool = [];
getBountyRewards(data.rewards, data.isVault, data).then((rewards) => {
this.rewardPool = rewards;
});

const chamber = ((data.locationTag || '').match(/[A-Z]+(?![a-z])|[A-Z]?[a-z]+|\d+/g) || []).join(' ');

Expand Down
27 changes: 22 additions & 5 deletions lib/models/SyndicateMission.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,27 @@ import WorldstateObject from './WorldstateObject.js';
* @augments {WorldstateObject}
*/
export default class SyndicateMission extends WorldstateObject {
/**
* Build a new SyndicateMission with async operations & data
* @param {object} data The syndicate mission data
* @param {object} deps The dependencies object
* @param {string} deps.locale Locale to use for translations
* @returns {Promise.<SyndicateMission>} SyndicateMission object w/ async resolution of jobs
*/
static async build(data, deps) {
const syndicateMission = new SyndicateMission(data, deps);
if (data.Jobs) {
const jobs = [];
// eslint-disable-next-line no-restricted-syntax
for await (const job of data.Jobs ?? []) {
jobs.push(await SyndicateJob.build(job, syndicateMission.expiry, deps));
}
syndicateMission.jobs = jobs;
}

return syndicateMission;
}

/**
* @param {object} data The syndicate mission data
* @param {object} deps The dependencies object
Expand All @@ -18,10 +39,6 @@ export default class SyndicateMission extends WorldstateObject {
constructor(data, { locale = 'en' } = { locale: 'en' }) {
super(data);

const deps = {
locale,
};

/**
* The date and time at which the syndicate mission starts
* @type {Date}
Expand Down Expand Up @@ -56,7 +73,7 @@ export default class SyndicateMission extends WorldstateObject {
* The jobs for this syndicate. Will normally be []
* @type {Array.<SyndicateJob>}
*/
this.jobs = (data.Jobs || []).map((j) => new SyndicateJob(j, this.expiry, deps));
this.jobs = [];

/**
* Unique identifier for this mission set built from the end time and syndicate
Expand Down
Loading

0 comments on commit 0a182c4

Please sign in to comment.