Skip to content

Commit cfd1000

Browse files
authored
refactor: extract repeated daily/weekly/monthly processing into shared function (#221) (#229)
Replace three ~55-line duplicated blocks (daily, weekly, monthly) with a single async processTimeframe() function. Net reduction of ~99 lines.
1 parent a2154f6 commit cfd1000

1 file changed

Lines changed: 68 additions & 167 deletions

File tree

scripts/sync-leaderboard.js

Lines changed: 68 additions & 167 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,70 @@ async function computeRankChanges(currentSorted, filename) {
170170
});
171171
}
172172

173+
/**
174+
* Processes a timeframe-based leaderboard (daily/weekly/monthly) by computing
175+
* per-user deltas from a previous snapshot, sorting, ranking, and writing output.
176+
*
177+
* @param {Array} sourceData - The overall dataset to deep-clone and process
178+
* @param {string} DATA_DIR - Path to the data directory
179+
* @param {string} periodName - Label for the timeframe ("daily", "weekly", "monthly")
180+
* @param {number} daysAgo - Number of days to look back for the snapshot file
181+
*/
182+
async function processTimeframe(sourceData, DATA_DIR, periodName, daysAgo) {
183+
const data = JSON.parse(JSON.stringify(sourceData));
184+
console.log(" ");
185+
console.log(`Loading previous ${periodName}'s file...`);
186+
const previousFilepath = path.join(DATA_DIR, "daily", getFileName(daysAgo));
187+
let previousData = [];
188+
try {
189+
const rawData = fs.readFileSync(previousFilepath, "utf8");
190+
previousData = JSON.parse(rawData);
191+
console.log(`Previous ${periodName}'s data loaded successfully`);
192+
} catch (err) {
193+
console.error(`Failed to load previous file: `, err.message);
194+
process.exit(1);
195+
}
196+
197+
console.log(" ");
198+
console.log(`Calculating ${periodName} progress...`);
199+
for (let i = 0; i < data.length; i++) {
200+
const previousIndex = previousData.findIndex(
201+
(obj) => obj.id === data[i].id,
202+
);
203+
if (previousIndex == -1) {
204+
data.splice(i--, 1);
205+
continue;
206+
}
207+
data[i].data.easySolved -= previousData[previousIndex].data.easySolved;
208+
data[i].data.mediumSolved -= previousData[previousIndex].data.mediumSolved;
209+
data[i].data.hardSolved -= previousData[previousIndex].data.hardSolved;
210+
data[i].score =
211+
data[i].data.easySolved +
212+
data[i].data.mediumSolved * 3 +
213+
data[i].data.hardSolved * 5;
214+
data[i].data.totalSolved =
215+
data[i].data.easySolved +
216+
data[i].data.mediumSolved +
217+
data[i].data.hardSolved;
218+
}
219+
console.log("Calculation done");
220+
console.log("");
221+
222+
console.log("Sorting calculated data...");
223+
stableSortByScore(data);
224+
assignCompetitionRanks(data);
225+
console.log(`Writing sorted ${periodName} data to ${periodName}.json...`);
226+
const filepath = path.join(DATA_DIR, `${periodName}.json`);
227+
await computeRankChanges(data, `${periodName}.json`);
228+
try {
229+
atomicWrite(filepath, data);
230+
console.log(`${periodName} data saved successfully`);
231+
} catch (err) {
232+
console.error(`Failed to write json file: `, err.message);
233+
process.exit(1);
234+
}
235+
}
236+
173237
(async () => {
174238
const DATA_DIR = process.env.DATA_DIR || path.join(__dirname, "..", "data");
175239
console.log(`Using data directory: ${DATA_DIR}`);
@@ -322,173 +386,10 @@ async function computeRankChanges(currentSorted, filename) {
322386
process.exit(1);
323387
}
324388

325-
let dailyData = JSON.parse(JSON.stringify(overallData));
326-
console.log(" ");
327-
console.log("Loading previous day's file...");
328-
const previousDayFilepath = path.join(DATA_DIR, "daily", getFileName(1));
329-
let previousData = [];
330-
try {
331-
const rawData = fs.readFileSync(previousDayFilepath, "utf8");
332-
previousData = JSON.parse(rawData);
333-
console.log("Previous day's data loaded successfully");
334-
} catch (err) {
335-
console.error(`Failed to load previous file: `, err.message);
336-
process.exit(1);
337-
}
338-
339-
console.log(" ");
340-
console.log("Calculating daily progress...");
341-
for (let i = 0; i < dailyData.length; i++) {
342-
const previousIndex = previousData.findIndex(
343-
(obj) => obj.id === dailyData[i].id,
344-
);
345-
if (previousIndex == -1) {
346-
dailyData.splice(i--, 1);
347-
continue;
348-
}
349-
350-
dailyData[i].data.easySolved -= previousData[previousIndex].data.easySolved;
351-
dailyData[i].data.mediumSolved -=
352-
previousData[previousIndex].data.mediumSolved;
353-
dailyData[i].data.hardSolved -= previousData[previousIndex].data.hardSolved;
354-
355-
dailyData[i].score =
356-
dailyData[i].data.easySolved +
357-
dailyData[i].data.mediumSolved * 3 +
358-
dailyData[i].data.hardSolved * 5;
359-
dailyData[i].data.totalSolved =
360-
dailyData[i].data.easySolved +
361-
dailyData[i].data.mediumSolved +
362-
dailyData[i].data.hardSolved;
363-
}
364-
console.log("Calculation done");
365-
console.log("");
366-
367-
console.log("Sorting calculated data...");
368-
stableSortByScore(dailyData);
369-
assignCompetitionRanks(dailyData);
370-
console.log("Writing sorted daily data to daily.json...");
371-
const dailyFilepath = path.join(DATA_DIR, "daily.json");
372-
await computeRankChanges(dailyData, "daily.json");
373-
try {
374-
atomicWrite(dailyFilepath, dailyData);
375-
console.log("Daily data saved successfully");
376-
} catch (err) {
377-
console.error(`Failed to write json file: `, err.message);
378-
process.exit(1);
379-
}
380-
381-
let weeklyData = JSON.parse(JSON.stringify(overallData));
382-
console.log(" ");
383-
console.log("Loading previous week's file...");
384-
const previousWeekFilepath = path.join(DATA_DIR, "daily", getFileName(7));
385-
previousData = [];
386-
try {
387-
const rawData = fs.readFileSync(previousWeekFilepath, "utf8");
388-
previousData = JSON.parse(rawData);
389-
console.log("Previous week's data loaded successfully");
390-
} catch (err) {
391-
console.error(`Failed to load previous file: `, err.message);
392-
process.exit(1);
393-
}
394-
395-
console.log(" ");
396-
console.log("Calculating weekly progress...");
397-
for (let i = 0; i < weeklyData.length; i++) {
398-
const previousIndex = previousData.findIndex(
399-
(obj) => obj.id === weeklyData[i].id,
400-
);
401-
if (previousIndex == -1) {
402-
weeklyData.splice(i--, 1);
403-
continue;
404-
}
405-
weeklyData[i].data.easySolved -=
406-
previousData[previousIndex].data.easySolved;
407-
weeklyData[i].data.mediumSolved -=
408-
previousData[previousIndex].data.mediumSolved;
409-
weeklyData[i].data.hardSolved -=
410-
previousData[previousIndex].data.hardSolved;
411-
weeklyData[i].score =
412-
weeklyData[i].data.easySolved +
413-
weeklyData[i].data.mediumSolved * 3 +
414-
weeklyData[i].data.hardSolved * 5;
415-
weeklyData[i].data.totalSolved =
416-
weeklyData[i].data.easySolved +
417-
weeklyData[i].data.mediumSolved +
418-
weeklyData[i].data.hardSolved;
419-
}
420-
console.log("Calculation done");
421-
console.log("");
422-
423-
console.log("Sorting calculated data...");
424-
stableSortByScore(weeklyData);
425-
assignCompetitionRanks(weeklyData);
426-
console.log("Writing sorted weekly data to weekly.json...");
427-
const weeklyFilepath = path.join(DATA_DIR, "weekly.json");
428-
await computeRankChanges(weeklyData, "weekly.json");
429-
try {
430-
atomicWrite(weeklyFilepath, weeklyData);
431-
console.log("Weekly data saved successfully");
432-
} catch (err) {
433-
console.error(`Failed to write json file: `, err.message);
434-
process.exit(1);
435-
}
436-
437-
let monthlyData = JSON.parse(JSON.stringify(overallData));
438-
console.log(" ");
439-
console.log("Loading previous month's file...");
440-
const previousMonthFilepath = path.join(DATA_DIR, "daily", getFileName(30));
441-
previousData = [];
442-
try {
443-
const rawData = fs.readFileSync(previousMonthFilepath, "utf8");
444-
previousData = JSON.parse(rawData);
445-
console.log("Previous week's data loaded successfully");
446-
} catch (err) {
447-
console.error(`Failed to load previous file: `, err.message);
448-
process.exit(1);
449-
}
450-
451-
console.log(" ");
452-
console.log("Calculating monthly progress...");
453-
for (let i = 0; i < monthlyData.length; i++) {
454-
const previousIndex = previousData.findIndex(
455-
(obj) => obj.id === monthlyData[i].id,
456-
);
457-
if (previousIndex == -1) {
458-
monthlyData.splice(i--, 1);
459-
continue;
460-
}
461-
monthlyData[i].data.easySolved -=
462-
previousData[previousIndex].data.easySolved;
463-
monthlyData[i].data.mediumSolved -=
464-
previousData[previousIndex].data.mediumSolved;
465-
monthlyData[i].data.hardSolved -=
466-
previousData[previousIndex].data.hardSolved;
467-
monthlyData[i].score =
468-
monthlyData[i].data.easySolved +
469-
monthlyData[i].data.mediumSolved * 3 +
470-
monthlyData[i].data.hardSolved * 5;
471-
monthlyData[i].data.totalSolved =
472-
monthlyData[i].data.easySolved +
473-
monthlyData[i].data.mediumSolved +
474-
monthlyData[i].data.hardSolved;
475-
}
476-
console.log("Calculation done");
477-
console.log("");
478-
479-
console.log("Sorting calculated data...");
480-
stableSortByScore(monthlyData);
481-
assignCompetitionRanks(monthlyData);
482-
console.log("Writing sorted monthly data to monthly.json...");
483-
const monthlyFilepath = path.join(DATA_DIR, "monthly.json");
484-
await computeRankChanges(monthlyData, "monthly.json");
485-
try {
486-
atomicWrite(monthlyFilepath, monthlyData);
487-
console.log("Monthly data saved successfully");
488-
} catch (err) {
489-
console.error(`Failed to write json file: `, err.message);
490-
process.exit(1);
491-
}
389+
// Process timeframe-based leaderboards using the shared function
390+
await processTimeframe(overallData, DATA_DIR, "daily", 1);
391+
await processTimeframe(overallData, DATA_DIR, "weekly", 7);
392+
await processTimeframe(overallData, DATA_DIR, "monthly", 30);
492393

493394
console.log("Generating changes.json...");
494395
const changesFilepath = path.join(DATA_DIR, "changes.json");

0 commit comments

Comments
 (0)