diff --git a/.github/workflows/qodana_code_quality.yml b/.github/workflows/qodana_code_quality.yml
index 0988492..6afdef3 100644
--- a/.github/workflows/qodana_code_quality.yml
+++ b/.github/workflows/qodana_code_quality.yml
@@ -17,12 +17,27 @@ jobs:
steps:
- uses: actions/checkout@v3
with:
- ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit
- fetch-depth: 0 # a full history is required for pull request analysis
+ ref: ${{ github.event.pull_request.head.sha }} # to check out the actual pull request commit, not the merge commit
+ fetch-depth: 0 # a full history is required for pull request analysis
+
+ - name: Set up Node.js
+ uses: actions/setup-node@v3
+ with:
+ node-version: '20' # Specify the Node.js version you want to use
+ cache: 'yarn'
+
+ - name: Set up FontAwesome NPM registry
+ run: ./fontawesome-npmrc.sh
+ env:
+ FONTAWESOME_KEY: ${{ secrets.FONTAWESOME_KEY }}
+
+ - name: Install dependencies
+ run: yarn install --frozen-lockfile
+
- name: 'Qodana Scan'
uses: JetBrains/qodana-action@v2024.2
with:
pr-mode: false
env:
QODANA_TOKEN: ${{ secrets.QODANA_TOKEN_1177090119 }}
- QODANA_ENDPOINT: 'https://qodana.cloud'
\ No newline at end of file
+ QODANA_ENDPOINT: 'https://qodana.cloud'
diff --git a/package.json b/package.json
index 12ed420..2b19344 100644
--- a/package.json
+++ b/package.json
@@ -77,7 +77,7 @@
"@types/react-window": "^1.8.8",
"@types/uuid": "^10.0.0",
"babel-jest": "^29.7.0",
- "eslint": "^9.8.0",
+ "eslint": "^9.14.0",
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-import": "2.31.0",
"eslint-plugin-jsx-a11y": "6.7.1",
diff --git a/src/app/app.tsx b/src/app/app.tsx
index 524a6b8..21692f1 100644
--- a/src/app/app.tsx
+++ b/src/app/app.tsx
@@ -1,6 +1,6 @@
import React, { useRef, ReactElement, ReactNode, useEffect, useState } from 'react';
import { ThemeProvider } from '@mui/material/styles';
-import { BrowserRouter as Router, useLocation, useNavigate, useRoutes } from 'react-router-dom';
+import { BrowserRouter as Router, useLocation, useRoutes } from 'react-router-dom';
import AboutScreen from '@/components/screens/AboutScreen';
import HomeIcon from '@mui/icons-material/Home';
import BookIcon from '@mui/icons-material/Book';
@@ -89,7 +89,7 @@ function AppRoutes() {
});
}
- const routes = useRoutes([
+ return useRoutes([
{
path: '/',
element: ,
@@ -100,8 +100,6 @@ function AppRoutes() {
})),
},
]);
-
- return routes;
}
export function App() {
diff --git a/src/components/screens/UtilsScreen.tsx b/src/components/screens/UtilsScreen.tsx
index cfa8181..ecc12a8 100644
--- a/src/components/screens/UtilsScreen.tsx
+++ b/src/components/screens/UtilsScreen.tsx
@@ -28,8 +28,7 @@ export const UtilsScreen: FC = () => {
) {
return prevState;
}
- const newGame = rebuildGameTimeHistory(prevState);
- return newGame;
+ return rebuildGameTimeHistory(prevState);
});
};
diff --git a/src/game/__tests__/dominion-lib-log-calculatePausedTime.spec.ts b/src/game/__tests__/dominion-lib-log-calculatePausedTime.spec.ts
new file mode 100644
index 0000000..d7d3dca
--- /dev/null
+++ b/src/game/__tests__/dominion-lib-log-calculatePausedTime.spec.ts
@@ -0,0 +1,117 @@
+import { calculatePausedTime } from '@/game/dominion-lib-log';
+import { ILogEntry } from '@/game/interfaces/log-entry';
+import { GameLogAction } from '@/game/enumerations/game-log-action';
+import { createMockLog } from '@/__fixtures__/dominion-lib-fixtures';
+
+describe('calculatePausedTime', () => {
+ it('should return 0 if logEntries is empty', () => {
+ const logEntries: ILogEntry[] = [];
+ const endTime = new Date();
+ expect(calculatePausedTime(logEntries, 0, endTime)).toBe(0);
+ });
+
+ it('should return 0 if no pause or save/load actions are present', () => {
+ const logEntries: ILogEntry[] = [
+ createMockLog({
+ timestamp: new Date('2023-01-01T00:00:00Z'),
+ action: GameLogAction.START_GAME,
+ turn: 1,
+ }),
+ createMockLog({
+ timestamp: new Date('2023-01-01T01:00:00Z'),
+ action: GameLogAction.NEXT_TURN,
+ turn: 2,
+ }),
+ ];
+ const endTime = new Date('2023-01-01T02:00:00Z');
+ expect(calculatePausedTime(logEntries, 0, endTime)).toBe(0);
+ });
+
+ it('should calculate paused time correctly for pause/unpause actions', () => {
+ const logEntries: ILogEntry[] = [
+ createMockLog({
+ timestamp: new Date('2023-01-01T00:00:00Z'),
+ action: GameLogAction.START_GAME,
+ turn: 1,
+ }),
+ createMockLog({
+ timestamp: new Date('2023-01-01T01:00:00Z'),
+ action: GameLogAction.PAUSE,
+ turn: 1,
+ }),
+ createMockLog({
+ timestamp: new Date('2023-01-01T01:30:00Z'),
+ action: GameLogAction.UNPAUSE,
+ turn: 1,
+ }),
+ ];
+ const endTime = new Date('2023-01-01T02:00:00Z');
+ expect(calculatePausedTime(logEntries, 0, endTime)).toBe(30 * 60 * 1000); // 30 minutes in milliseconds
+ });
+
+ it('should calculate paused time correctly for save/load actions', () => {
+ const logEntries: ILogEntry[] = [
+ createMockLog({
+ timestamp: new Date('2023-01-01T00:00:00Z'),
+ action: GameLogAction.START_GAME,
+ turn: 1,
+ }),
+ createMockLog({
+ timestamp: new Date('2023-01-01T01:00:00Z'),
+ action: GameLogAction.SAVE_GAME,
+ turn: 1,
+ }),
+ createMockLog({
+ timestamp: new Date('2023-01-01T01:30:00Z'),
+ action: GameLogAction.LOAD_GAME,
+ turn: 1,
+ }),
+ ];
+ const endTime = new Date('2023-01-01T02:00:00Z');
+ expect(calculatePausedTime(logEntries, 0, endTime)).toBe(30 * 60 * 1000); // 30 minutes in milliseconds
+ });
+
+ it('should handle case where end time is during a pause', () => {
+ const logEntries: ILogEntry[] = [
+ createMockLog({
+ timestamp: new Date('2023-01-01T00:00:00Z'),
+ action: GameLogAction.START_GAME,
+ turn: 1,
+ }),
+ createMockLog({
+ timestamp: new Date('2023-01-01T01:00:00Z'),
+ action: GameLogAction.PAUSE,
+ turn: 1,
+ }),
+ ];
+ const endTime = new Date('2023-01-01T01:30:00Z');
+ expect(calculatePausedTime(logEntries, 0, endTime)).toBe(30 * 60 * 1000); // 30 minutes in milliseconds
+ });
+
+ it('should handle case where end time is after a pause/unpause cycle', () => {
+ const logEntries: ILogEntry[] = [
+ createMockLog({
+ timestamp: new Date('2023-01-01T00:00:00Z'),
+ action: GameLogAction.START_GAME,
+ turn: 1,
+ }),
+ createMockLog({
+ timestamp: new Date('2023-01-01T01:00:00Z'),
+ action: GameLogAction.PAUSE,
+ turn: 1,
+ }),
+ createMockLog({
+ timestamp: new Date('2023-01-01T01:30:00Z'),
+ action: GameLogAction.UNPAUSE,
+ turn: 1,
+ }),
+ createMockLog({
+ timestamp: new Date('2023-01-01T02:00:00Z'),
+ action: GameLogAction.PAUSE,
+ turn: 1,
+ }),
+ ];
+ const endTime = new Date('2023-01-01T02:30:00Z');
+ expect(calculatePausedTime(logEntries, 0, endTime)).toBe(60 * 60 * 1000); // 1 hour in milliseconds
+ });
+});
diff --git a/src/game/__tests__/dominion-lib-undo-removeTargetAndLinkedActions.spec.ts b/src/game/__tests__/dominion-lib-undo-removeTargetAndLinkedActions.spec.ts
index 6a490b2..0e79d82 100644
--- a/src/game/__tests__/dominion-lib-undo-removeTargetAndLinkedActions.spec.ts
+++ b/src/game/__tests__/dominion-lib-undo-removeTargetAndLinkedActions.spec.ts
@@ -1,6 +1,5 @@
import { removeTargetAndLinkedActions } from '@/game/dominion-lib-undo-helpers';
import { IGame } from '@/game/interfaces/game';
-import { ILogEntry } from '@/game/interfaces/log-entry';
import { GameLogAction } from '@/game/enumerations/game-log-action';
import { createMockGame, createMockLog } from '@/__fixtures__/dominion-lib-fixtures';
diff --git a/src/game/dominion-lib-log.ts b/src/game/dominion-lib-log.ts
index b2c02c1..d288e43 100644
--- a/src/game/dominion-lib-log.ts
+++ b/src/game/dominion-lib-log.ts
@@ -137,6 +137,7 @@ export function fieldSubfieldToGameLogAction(
/**
* Transform a log entry to a string.
* @param entry - The log entry
+ * @param useFutureTense - Whether to use future tense for the action
* @returns The string representation of the log entry
*/
export function logEntryToString(entry: ILogEntry, useFutureTense = false): string {
@@ -261,9 +262,7 @@ export function getTimeSpanFromLastAction(log: ILogEntry[], eventTime: Date): nu
}
const lastActionTime = new Date(log[log.length - 1].timestamp);
- const timeSpan = eventTime.getTime() - lastActionTime.getTime();
-
- return timeSpan;
+ return eventTime.getTime() - lastActionTime.getTime();
}
/**
@@ -280,8 +279,7 @@ export function calculateAverageTurnDuration(turnDurations: ITurnDuration[]): nu
return accumulator + turn.duration;
}, 0);
- const averageDuration = totalDuration / turnDurations.length;
- return averageDuration;
+ return totalDuration / turnDurations.length;
}
/**
@@ -304,30 +302,30 @@ export function calculateAverageTurnDurationForPlayer(
return accumulator + turn.duration;
}, 0);
- const averageDuration = totalDuration / playerTurns.length;
- return averageDuration;
+ return totalDuration / playerTurns.length;
}
/**
- * Calculates the duration of the current turn from the last NEXT_TURN or START_GAME up to the current time.
- * Subtracts the time between any SAVE_GAME and the immediately following LOAD_GAME within the turn.
+ * Calculates the total number of actions performed by a specific player.
* @param logEntries - The game log entries.
- * @param currentTime - The current time.
- * @returns The duration of the current turn in milliseconds.
+ * @param startIndex - The index of the first log entry to consider.
+ * @param endTime - The end time up to which the actions are counted.
+ * @returns The total number of actions performed by the player.
*/
-export function calculateCurrentTurnDuration(logEntries: ILogEntry[], currentTime: Date): number {
- if (logEntries.length === 0) {
- return 0;
- }
- const currentTurn = logEntries[logEntries.length - 1].turn;
- const turnStartEntry = getTurnStartEntry(logEntries, currentTurn);
-
+export function calculatePausedTime(
+ logEntries: ILogEntry[],
+ startIndex: number,
+ endTime: Date
+): number {
let totalPausedTime = 0;
let lastSaveTime: number | null = null;
let pauseStartTime: number | null = null;
- for (let i = logEntries.indexOf(turnStartEntry); i < logEntries.length; i++) {
+ for (let i = startIndex; i < logEntries.length; i++) {
const entry = logEntries[i];
+ if (entry.timestamp.getTime() >= endTime.getTime()) {
+ break;
+ }
if (entry.action === GameLogAction.SAVE_GAME) {
lastSaveTime = entry.timestamp.getTime();
@@ -342,11 +340,33 @@ export function calculateCurrentTurnDuration(logEntries: ILogEntry[], currentTim
}
}
- // Handle case where the game is currently paused
+ // Handle case where the end time is during a pause
if (pauseStartTime !== null) {
- totalPausedTime += currentTime.getTime() - pauseStartTime;
+ totalPausedTime += endTime.getTime() - pauseStartTime;
}
+ return totalPausedTime;
+}
+
+/**
+ * Calculates the duration of the current turn from the last NEXT_TURN or START_GAME up to the current time.
+ * Subtracts the time between any SAVE_GAME and the immediately following LOAD_GAME within the turn.
+ * @param logEntries - The game log entries.
+ * @param currentTime - The current time.
+ * @returns The duration of the current turn in milliseconds.
+ */
+export function calculateCurrentTurnDuration(logEntries: ILogEntry[], currentTime: Date): number {
+ if (logEntries.length === 0) {
+ return 0;
+ }
+ const currentTurn = logEntries[logEntries.length - 1].turn;
+ const turnStartEntry = getTurnStartEntry(logEntries, currentTurn);
+
+ const totalPausedTime = calculatePausedTime(
+ logEntries,
+ logEntries.indexOf(turnStartEntry),
+ currentTime
+ );
const currentTurnDuration = currentTime.getTime() - turnStartEntry.timestamp.getTime();
return currentTurnDuration - totalPausedTime;
}
@@ -354,6 +374,8 @@ export function calculateCurrentTurnDuration(logEntries: ILogEntry[], currentTim
/**
* Calculate the total duration of the game from the start of the game to the current time, subtracting the time between any SAVE_GAME and the immediately following LOAD_GAME within the turn.
* @param log - The game log entries
+ * @param calculateTurnDurations - A function to calculate turn durations from the log entries
+ * @param calculateCurrentTurnDuration - A function to calculate the duration of the current turn
* @returns The total duration of the game in milliseconds
*/
export function calculateGameDuration(
@@ -393,34 +415,7 @@ export function calculateDurationUpToEvent(logEntries: ILogEntry[], eventTime: D
return 0;
}
- let totalPausedTime = 0;
- let lastSaveTime: number | null = null;
- let pauseStartTime: number | null = null;
-
- for (let i = 0; i < logEntries.length; i++) {
- const entry = logEntries[i];
- if (entry.timestamp.getTime() >= eventTime.getTime()) {
- break;
- }
-
- if (entry.action === GameLogAction.SAVE_GAME) {
- lastSaveTime = entry.timestamp.getTime();
- } else if (entry.action === GameLogAction.LOAD_GAME && lastSaveTime !== null) {
- totalPausedTime += entry.timestamp.getTime() - lastSaveTime;
- lastSaveTime = null;
- } else if (entry.action === GameLogAction.PAUSE) {
- pauseStartTime = entry.timestamp.getTime();
- } else if (entry.action === GameLogAction.UNPAUSE && pauseStartTime !== null) {
- totalPausedTime += entry.timestamp.getTime() - pauseStartTime;
- pauseStartTime = null;
- }
- }
-
- // Handle case where the event time is during a pause
- if (pauseStartTime !== null) {
- totalPausedTime += eventTime.getTime() - pauseStartTime;
- }
-
+ const totalPausedTime = calculatePausedTime(logEntries, 0, eventTime);
const eventDuration = eventTime.getTime() - startGameTime;
return Math.max(0, eventDuration - totalPausedTime);
}
@@ -903,6 +898,7 @@ export function prepareGroupedActionTriggers(
* Apply a log action to the game.
* @param game - The current game state
* @param actionDate - The date of the log action
+ * @param applyLogAction - A function to apply a log action to the game
* @returns The updated game state
*/
export function applyPendingGroupedActions(
@@ -944,6 +940,7 @@ export function applyPendingGroupedActions(
/**
* Get the signed count for a log entry.
* @param log - The log entry
+ * @param defaultValue - The default value to use if the count is not provided
* @returns The signed count for the log entry, negative for removal actions and positive for addition actions.
*/
export function getSignedCount(log: ILogEntry, defaultValue = 0): number {
@@ -1012,7 +1009,7 @@ export function getGameEndTime(game: IGame): Date {
/**
* Get the start time of a turn.
- * @param game - The game object
+ * @param logEntries - The log entries
* @param turn - The turn number
* @returns The log entry marking the beginning of the turn
*/
@@ -1067,7 +1064,7 @@ export function getTurnEndTime(game: IGame, turn: number): Date {
// a turn ends with either a NEXT_TURN or END_GAME action
// a NEXT_TURN will have the next higher turn number than the current turn
// an END_GAME will have the same turn number as the current turn
- let nextTurnLog = undefined;
+ let nextTurnLog;
try {
nextTurnLog = getTurnStartEntry(game.log, turn + 1);
} catch {
@@ -1089,6 +1086,7 @@ export function getTurnEndTime(game: IGame, turn: number): Date {
/**
* Get the adjustments made during the current turn
* @param game - The game object
+ * @param turn - The turn number (optional)
* @returns An array of turn adjustments
*/
export function getTurnAdjustments(game: IGame, turn?: number): Array {
@@ -1185,8 +1183,10 @@ export function getAverageActionsPerTurn(game: IGame): number {
/**
* Get the next turn number for a given player (when it will be their turn)
- * @param game
- * @param playerIndex
+ * @param game - The game object
+ * @param playerIndex - The index of the player
+ * @param skipCurrentTurn - Whether to skip the current turn
+ * @returns The next turn number for the player
*/
export function getPlayerNextTurnCount(
game: IGame,
diff --git a/yarn.lock b/yarn.lock
index ad5fd36..a4aab3e 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -1202,11 +1202,16 @@
dependencies:
eslint-visitor-keys "^3.3.0"
-"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.11.0":
+"@eslint-community/regexpp@^4.10.0":
version "4.11.1"
resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.11.1.tgz#a547badfc719eb3e5f4b556325e542fbe9d7a18f"
integrity sha512-m4DVN9ZqskZoLU5GlWZadwDnYo3vAEydiUayB9widCl9ffWx2IvPnp6n3on5rJmziJSw9Bv+Z3ChDVdMwXCY8Q==
+"@eslint-community/regexpp@^4.12.1":
+ version "4.12.1"
+ resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0"
+ integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ==
+
"@eslint/compat@^1.1.1":
version "1.2.0"
resolved "https://registry.yarnpkg.com/@eslint/compat/-/compat-1.2.0.tgz#8d36b8c0e1e9e91068a1df8938977a9e4535d83c"
@@ -1221,10 +1226,10 @@
debug "^4.3.1"
minimatch "^3.1.2"
-"@eslint/core@^0.6.0":
- version "0.6.0"
- resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.6.0.tgz#9930b5ba24c406d67a1760e94cdbac616a6eb674"
- integrity sha512-8I2Q8ykA4J0x0o7cg67FPVnehcqWTBehu/lmY+bolPFHGjh49YzGBMXTvpqVgEbBdvNCSxj6iFgiIyHzf03lzg==
+"@eslint/core@^0.7.0":
+ version "0.7.0"
+ resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.7.0.tgz#a1bb4b6a4e742a5ff1894b7ee76fbf884ec72bd3"
+ integrity sha512-xp5Jirz5DyPYlPiKat8jaq0EmYvDXKKpzTbxXMpT9eqlRJkRKIz9AGMdlvYjih+im+QlhWrpvVjl8IPC/lHlUw==
"@eslint/eslintrc@^3.1.0":
version "3.1.0"
@@ -1241,7 +1246,12 @@
minimatch "^3.1.2"
strip-json-comments "^3.1.1"
-"@eslint/js@9.12.0", "@eslint/js@^9.8.0":
+"@eslint/js@9.14.0":
+ version "9.14.0"
+ resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.14.0.tgz#2347a871042ebd11a00fd8c2d3d56a265ee6857e"
+ integrity sha512-pFoEtFWCPyDOl+C6Ift+wC7Ro89otjigCf5vcuWqWgqNSQbRrpjSvdeE6ofLz4dHmyxD5f7gIdGT4+p36L6Twg==
+
+"@eslint/js@^9.8.0":
version "9.12.0"
resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.12.0.tgz#69ca3ca9fab9a808ec6d67b8f6edb156cbac91e1"
integrity sha512-eohesHH8WFRUprDNyEREgqP6beG6htMeUYeCpkEgBCieCMme5r9zFWjzAJp//9S+Kub4rqE+jXe9Cp1a7IYIIA==
@@ -1301,17 +1311,17 @@
dependencies:
"@hapi/hoek" "^9.0.0"
-"@humanfs/core@^0.19.0":
- version "0.19.0"
- resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.0.tgz#08db7a8c73bb07673d9ebd925f2dad746411fcec"
- integrity sha512-2cbWIHbZVEweE853g8jymffCA+NCMiuqeECeBBLm8dg2oFdjuGJhgN4UAbI+6v0CKbbhvtXA4qV8YR5Ji86nmw==
+"@humanfs/core@^0.19.1":
+ version "0.19.1"
+ resolved "https://registry.yarnpkg.com/@humanfs/core/-/core-0.19.1.tgz#17c55ca7d426733fe3c561906b8173c336b40a77"
+ integrity sha512-5DyQ4+1JEUzejeK1JGICcideyfUbGixgS9jNgex5nqkW+cY7WZhxBigmieN5Qnw9ZosSNVC9KQKyb+GUaGyKUA==
-"@humanfs/node@^0.16.5":
- version "0.16.5"
- resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.5.tgz#a9febb7e7ad2aff65890fdc630938f8d20aa84ba"
- integrity sha512-KSPA4umqSG4LHYRodq31VDwKAvaTF4xmVlzM8Aeh4PlU1JQ3IG0wiA8C25d3RQ9nJyM3mBHyI53K06VVL/oFFg==
+"@humanfs/node@^0.16.6":
+ version "0.16.6"
+ resolved "https://registry.yarnpkg.com/@humanfs/node/-/node-0.16.6.tgz#ee2a10eaabd1131987bf0488fd9b820174cd765e"
+ integrity sha512-YuI2ZHQL78Q5HbhDiBA1X4LmYdXCKCMQIfw0pw7piHJwyREFebJUvrQN4cMssyES6x+vfUbx1CIpaQUKYdQZOw==
dependencies:
- "@humanfs/core" "^0.19.0"
+ "@humanfs/core" "^0.19.1"
"@humanwhocodes/retry" "^0.3.0"
"@humanwhocodes/module-importer@^1.0.1":
@@ -1319,11 +1329,16 @@
resolved "https://registry.yarnpkg.com/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz#af5b2691a22b44be847b0ca81641c5fb6ad0172c"
integrity sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==
-"@humanwhocodes/retry@^0.3.0", "@humanwhocodes/retry@^0.3.1":
+"@humanwhocodes/retry@^0.3.0":
version "0.3.1"
resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a"
integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA==
+"@humanwhocodes/retry@^0.4.0":
+ version "0.4.1"
+ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b"
+ integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA==
+
"@icons/material@^0.2.4":
version "0.2.4"
resolved "https://registry.yarnpkg.com/@icons/material/-/material-0.2.4.tgz#e90c9f71768b3736e76d7dd6783fc6c2afa88bc8"
@@ -3537,6 +3552,11 @@ acorn@^8.1.0, acorn@^8.11.0, acorn@^8.12.0, acorn@^8.4.1, acorn@^8.5.0, acorn@^8
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.12.1.tgz#71616bdccbe25e27a54439e0046e89ca76df2248"
integrity sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==
+acorn@^8.14.0:
+ version "8.14.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0"
+ integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==
+
address@^1.0.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/address/-/address-1.2.2.tgz#2b5248dac5485a6390532c6a517fda2e3faac89e"
@@ -5553,10 +5573,10 @@ eslint-scope@5.1.1:
esrecurse "^4.3.0"
estraverse "^4.1.1"
-eslint-scope@^8.1.0:
- version "8.1.0"
- resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.1.0.tgz#70214a174d4cbffbc3e8a26911d8bf51b9ae9d30"
- integrity sha512-14dSvlhaVhKKsa9Fx1l8A17s7ah7Ef7wCakJ10LYk6+GYmP9yDti2oq2SEwcyndt6knfcZyhyxwY3i9yL78EQw==
+eslint-scope@^8.2.0:
+ version "8.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442"
+ integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A==
dependencies:
esrecurse "^4.3.0"
estraverse "^5.2.0"
@@ -5571,21 +5591,26 @@ eslint-visitor-keys@^4.1.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.1.0.tgz#1f785cc5e81eb7534523d85922248232077d2f8c"
integrity sha512-Q7lok0mqMUSf5a/AdAZkA5a/gHcO6snwQClVNNvFKCAVlxXucdU8pKydU5ZVZjBx5xr37vGbFFWtLQYreLzrZg==
-eslint@^9.8.0:
- version "9.12.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.12.0.tgz#54fcba2876c90528396da0fa44b6446329031e86"
- integrity sha512-UVIOlTEWxwIopRL1wgSQYdnVDcEvs2wyaO6DGo5mXqe3r16IoCNWkR29iHhyaP4cICWjbgbmFUGAhh0GJRuGZw==
+eslint-visitor-keys@^4.2.0:
+ version "4.2.0"
+ resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45"
+ integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw==
+
+eslint@^9.14.0:
+ version "9.14.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.14.0.tgz#534180a97c00af08bcf2b60b0ebf0c4d6c1b2c95"
+ integrity sha512-c2FHsVBr87lnUtjP4Yhvk4yEhKrQavGafRA/Se1ouse8PfbfC/Qh9Mxa00yWsZRlqeUB9raXip0aiiUZkgnr9g==
dependencies:
"@eslint-community/eslint-utils" "^4.2.0"
- "@eslint-community/regexpp" "^4.11.0"
+ "@eslint-community/regexpp" "^4.12.1"
"@eslint/config-array" "^0.18.0"
- "@eslint/core" "^0.6.0"
+ "@eslint/core" "^0.7.0"
"@eslint/eslintrc" "^3.1.0"
- "@eslint/js" "9.12.0"
+ "@eslint/js" "9.14.0"
"@eslint/plugin-kit" "^0.2.0"
- "@humanfs/node" "^0.16.5"
+ "@humanfs/node" "^0.16.6"
"@humanwhocodes/module-importer" "^1.0.1"
- "@humanwhocodes/retry" "^0.3.1"
+ "@humanwhocodes/retry" "^0.4.0"
"@types/estree" "^1.0.6"
"@types/json-schema" "^7.0.15"
ajv "^6.12.4"
@@ -5593,9 +5618,9 @@ eslint@^9.8.0:
cross-spawn "^7.0.2"
debug "^4.3.2"
escape-string-regexp "^4.0.0"
- eslint-scope "^8.1.0"
- eslint-visitor-keys "^4.1.0"
- espree "^10.2.0"
+ eslint-scope "^8.2.0"
+ eslint-visitor-keys "^4.2.0"
+ espree "^10.3.0"
esquery "^1.5.0"
esutils "^2.0.2"
fast-deep-equal "^3.1.3"
@@ -5612,7 +5637,7 @@ eslint@^9.8.0:
optionator "^0.9.3"
text-table "^0.2.0"
-espree@^10.0.1, espree@^10.2.0:
+espree@^10.0.1:
version "10.2.0"
resolved "https://registry.yarnpkg.com/espree/-/espree-10.2.0.tgz#f4bcead9e05b0615c968e85f83816bc386a45df6"
integrity sha512-upbkBJbckcCNBDBDXEbuhjbP68n+scUd3k/U2EkyM9nw+I/jPiL4cLF/Al06CF96wRltFda16sxDFrxsI1v0/g==
@@ -5621,6 +5646,15 @@ espree@^10.0.1, espree@^10.2.0:
acorn-jsx "^5.3.2"
eslint-visitor-keys "^4.1.0"
+espree@^10.3.0:
+ version "10.3.0"
+ resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a"
+ integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg==
+ dependencies:
+ acorn "^8.14.0"
+ acorn-jsx "^5.3.2"
+ eslint-visitor-keys "^4.2.0"
+
espree@^9.0.0:
version "9.6.1"
resolved "https://registry.yarnpkg.com/espree/-/espree-9.6.1.tgz#a2a17b8e434690a5432f2f8018ce71d331a48c6f"