Move getTopOfCurrentHour out of utilities.js

utilities.js is the filesystem helper module the posters still use, and
the schedules updater only needed the time helper from it. With the
helper in its own module the updater import graph no longer pulls in
node:fs, which is what the Worker bundle needs. Also applies the
remaining ESLint fixes outside src/web.

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
Matt Isenhower
2026-09-05 10:30:11 -07:00
parent e3e773af4d
commit 899b9ff9ea
15 changed files with 46 additions and 45 deletions

View File

@@ -1,5 +1,5 @@
module.exports = {
presets: [
'@vue/app'
'@vue/app',
],
}
};

View File

@@ -1,15 +1,15 @@
const IN_PRODUCTION = process.env.NODE_ENV === 'production'
const IN_PRODUCTION = process.env.NODE_ENV === 'production';
module.exports = {
plugins: [
IN_PRODUCTION && require('@fullhuman/postcss-purgecss')({
content: [
`./src/web/html/**/*.html`,
`./src/web/components/**/*.vue`
'./src/web/html/**/*.html',
'./src/web/components/**/*.vue',
],
defaultExtractor (content) {
const contentWithoutStyleBlocks = content.replace(/<style[^]+?<\/style>/gi, '')
return contentWithoutStyleBlocks.match(/[A-Za-z0-9-_/:]*[A-Za-z0-9-_/]+/g) || []
const contentWithoutStyleBlocks = content.replace(/<style[^]+?<\/style>/gi, '');
return contentWithoutStyleBlocks.match(/[A-Za-z0-9-_/:]*[A-Za-z0-9-_/]+/g) || [];
},
safelist: {
standard: [
@@ -24,6 +24,6 @@ module.exports = {
/data-v-.*/,
],
},
})
}),
],
}
};

View File

@@ -1,6 +1,7 @@
import TwitterPostBase from './TwitterPostBase.js';
import { captureGearScreenshot } from '../../screenshots/index.js';
import { readData, getTopOfCurrentHour } from '../../../common/utilities.js';
import { readData } from '../../../common/utilities.js';
import { getTopOfCurrentHour } from '../../../common/time.js';
export default class GearTweet extends TwitterPostBase {
getKey() { return 'gear'; }

View File

@@ -25,7 +25,7 @@ export default class NewWeaponTweet extends TwitterPostBase {
}
getTestData() {
let availabilities = this.getNewWeaponAvailabilities()
let availabilities = this.getNewWeaponAvailabilities();
if (availabilities.length)
return availabilities;
}
@@ -41,7 +41,7 @@ export default class NewWeaponTweet extends TwitterPostBase {
// Make sure we don't exceed the max tweet text length
const names = data.map(availability => `- ${availability.weapon.name}`);
for (let i = names.length; i > 0; i--) {
let text = `New weapons now available:\n`;
let text = 'New weapons now available:\n';
text += names.slice(0, i).join('\n');
text += '\n';
if (i < names.length) {

View File

@@ -83,7 +83,7 @@ export default class SplatfestTweet extends TwitterPostBase {
// Is the current event (e.g., announcement, results, etc.) occurring simultaneously across all regions?
isSimultaneous() {
return this.regions().every(region => this.getData(region))
return this.regions().every(region => this.getData(region));
}
shouldPostForCurrentTime() {

View File

@@ -3,7 +3,8 @@ import fs from 'node:fs';
import { mkdirpSync as mkdirp } from 'mkdirp';
import BlueskyClient from '../clients/BlueskyClient.js';
import TwitterClient from '../clients/TwitterClient.js';
import { getTopOfCurrentHour, readJson, writeJson } from '../../../common/utilities.js';
import { readJson, writeJson } from '../../../common/utilities.js';
import { getTopOfCurrentHour } from '../../../common/time.js';
const blueskyLastTimesPath = path.resolve('storage/bluesky-lastPostTimes.json');
const twitterLastTimesPath = path.resolve('storage/twitter-lastTweetTimes.json');
@@ -101,7 +102,7 @@ export default class TwitterPostBase {
let image = await this.getImage(data);
fs.writeFileSync(filename, image);
this.info('Saved screenshot')
this.info('Saved screenshot');
}
catch (e) {
this.error('Couldn\'t save screenshot');

View File

@@ -10,7 +10,7 @@ export default class CoopSchedulesUpdater extends Updater {
imagePaths: [
'$..stage.image',
'$..weapons[*].weapon.image',
'$..coop_special_weapon.image'
'$..coop_special_weapon.image',
],
localization: [
{

View File

@@ -42,12 +42,12 @@ export default class FestivalsUpdater extends Updater {
// For some reason these got swapped out with images that have an opaque background
// even though they started out with transparent images.
jsonpath.apply(regionData, '$..images.alpha', value => value.replace(
"/images/festival/a070cc6b405b4fb335992d824097acd8.png",
"/images/festival/06b3b0b7773d9e6c4ac0a5cc5371fc32.png"
'/images/festival/a070cc6b405b4fb335992d824097acd8.png',
'/images/festival/06b3b0b7773d9e6c4ac0a5cc5371fc32.png',
));
jsonpath.apply(regionData, '$..images.bravo', value => value.replace(
"/images/festival/00e4c5fdccd3720d07127084fc1f4152.png",
"/images/festival/d93df77468714c6211e9377f39a559f4.png"
'/images/festival/00e4c5fdccd3720d07127084fc1f4152.png',
'/images/festival/d93df77468714c6211e9377f39a559f4.png',
));
// Download result ranking data
@@ -63,7 +63,7 @@ export default class FestivalsUpdater extends Updater {
let rankings = await this.handleRequest(splatnet.getFestivalRankings(id));
await this.publicStorage.writeJson(key, rankings, { cacheControl: DATA_CACHE_CONTROL });
}
catch (e) {
catch {
// Do nothing
}
}

View File

@@ -49,7 +49,7 @@ export default class MerchandisesUpdater extends Updater {
// We don't need the brand data since it should match the SplatNet gear's brand
if (originalGear)
delete originalGear.brand
delete originalGear.brand;
merchandise.original_gear = originalGear;
}

View File

@@ -1,6 +1,6 @@
import Updater from './Updater.js';
import SplatNet from '../../../common/splatnet.js';
import { getTopOfCurrentHour } from '../../../common/utilities.js';
import { getTopOfCurrentHour } from '../../../common/time.js';
const STAGES_KEY = 'stages.json'; // private storage

7
src/common/time.js Normal file
View File

@@ -0,0 +1,7 @@
/** Unix timestamp (seconds) for the top of the current hour. */
export function getTopOfCurrentHour() {
let date = new Date;
date.setUTCMinutes(0);
date.setUTCSeconds(0);
return Math.floor(date.getTime() / 1000);
}

View File

@@ -5,13 +5,6 @@ import stringify from 'json-stable-stringify';
const dataPath = path.resolve('dist/data');
export function getTopOfCurrentHour() {
let date = new Date;
date.setUTCMinutes(0);
date.setUTCSeconds(0);
return Math.floor(date.getTime() / 1000);
}
export function readJson(filename) {
return JSON.parse(fs.readFileSync(filename));
}

View File

@@ -5,7 +5,6 @@ import { MemoryBucket, BucketStorage } from '../../src/common/storage/index.js';
import LocalizationProcessor from '../../src/app/updater/LocalizationProcessor.js';
const en = { region: 'NA', language: 'en' };
const ja = { region: 'JP', language: 'ja' };
const stages = { name: 'stages', entities: ['$..stage_a', '$..stage_b'], id: 'id', values: 'name' };
const rules = { name: 'rules', entities: '$..rule', id: 'key', values: ['name', 'multiline_name'] };
const gear = { name: 'gear', entities: '$..gear', id: ['kind', 'id'], values: 'name' };

View File

@@ -7,7 +7,7 @@ import MerchandisesUpdater from '../../src/app/updater/updaters/MerchandisesUpda
import FestivalsUpdater from '../../src/app/updater/updaters/FestivalsUpdater.js';
import OriginalGearImageUpdater from '../../src/app/updater/updaters/OriginalGearImageUpdater.js';
import { createUpdaters } from '../../src/app/updater/updateAll.js';
import { getTopOfCurrentHour } from '../../src/common/utilities.js';
import { getTopOfCurrentHour } from '../../src/common/time.js';
import gearData from '../../src/common/data/gear.json' with { type: 'json' };
import skills from '../../src/common/data/skills.json' with { type: 'json' };
import { fakeSplatNet, buckets, json, keys, setSessionEnvironment } from './support.js';

View File

@@ -1,4 +1,4 @@
const path = require('path')
const path = require('path');
module.exports = {
assetsDir: 'assets',
@@ -11,13 +11,13 @@ module.exports = {
// and only used for the screenshots page (which is never served to the client).
// An alternative method would be to set minChunks to 2 here.
vendors: {
test: /[\\/]node_modules[\\/](?!(moment|moment-timezone)[\\/])/
test: /[\\/]node_modules[\\/](?!(moment|moment-timezone)[\\/])/,
},
// The common chunk doesn't really make sense here since the only reason we're splitting
// pages is for the server-side screenshots page. Disabling it to save an HTTP request.
common: false
}
}
common: false,
},
},
},
plugins: [],
},
@@ -35,20 +35,20 @@ module.exports = {
.rule('vue')
.use('vue-loader')
.tap(args => {
args.compilerOptions.whitespace = 'preserve'
})
args.compilerOptions.whitespace = 'preserve';
});
},
devServer: {
static: {
directory: path.join(__dirname, 'dist'),
}
},
},
pages: {
index: {
entry: 'src/web/main.js'
entry: 'src/web/main.js',
},
screenshots: {
entry: 'src/web/screenshots.js'
}
}
}
entry: 'src/web/screenshots.js',
},
},
};