From 12b63ee7c39f40c8b9e9dcd1c849d9f5bb1d1951 Mon Sep 17 00:00:00 2001 From: 7185 <7185@users.noreply.github.com> Date: Mon, 2 Dec 2024 13:52:38 +0100 Subject: [PATCH] chore: eslint with ts config --- action-parser/eslint.config.mjs | 51 -- action-parser/eslint.config.mts | 23 + action-parser/package.json | 9 +- action-parser/vitest.config.mts | 5 +- backend/eslint.config.mjs | 66 -- backend/eslint.config.mts | 38 ++ backend/package.json | 16 +- backend/src/world/world.service.ts | 3 +- bot/eslint.config.mjs | 52 -- bot/eslint.config.mts | 23 + bot/package.json | 12 +- bot/src/bot.ts | 27 +- frontend/eslint.config.js | 56 -- frontend/eslint.config.ts | 62 ++ frontend/package.json | 5 +- frontend/src/app/engine/engine.service.ts | 12 +- frontend/src/app/engine/player.ts | 6 +- .../app/ui/ui-toolbar/ui-toolbar.component.ts | 10 +- .../ui-world-attribs.component.ts | 18 +- frontend/src/app/utils/text-canvas.ts | 228 ++++--- frontend/src/app/utils/utils.ts | 262 ++++---- frontend/src/app/world/lighting.service.ts | 8 +- frontend/src/app/world/prop-action.service.ts | 15 +- frontend/src/app/world/prop.service.ts | 4 +- frontend/src/app/world/sky.service.ts | 38 +- frontend/src/app/world/terrain.service.ts | 4 +- frontend/src/app/world/world.service.ts | 13 +- package-lock.json | 582 ++++++++---------- 28 files changed, 727 insertions(+), 921 deletions(-) delete mode 100644 action-parser/eslint.config.mjs create mode 100644 action-parser/eslint.config.mts delete mode 100644 backend/eslint.config.mjs create mode 100644 backend/eslint.config.mts delete mode 100644 bot/eslint.config.mjs create mode 100644 bot/eslint.config.mts delete mode 100644 frontend/eslint.config.js create mode 100644 frontend/eslint.config.ts diff --git a/action-parser/eslint.config.mjs b/action-parser/eslint.config.mjs deleted file mode 100644 index 8e50d0d..0000000 --- a/action-parser/eslint.config.mjs +++ /dev/null @@ -1,51 +0,0 @@ -import typescriptEslint from '@typescript-eslint/eslint-plugin' -import globals from 'globals' -import tsParser from '@typescript-eslint/parser' -import path from 'node:path' -import {fileURLToPath} from 'node:url' -import js from '@eslint/js' -import {FlatCompat} from '@eslint/eslintrc' - -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, - allConfig: js.configs.all -}) - -export default [ - ...compat.extends( - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended' - ), - { - plugins: { - '@typescript-eslint': typescriptEslint - }, - - languageOptions: { - globals: { - ...globals.browser, - ...globals.node - }, - - parser: tsParser, - ecmaVersion: 'latest', - sourceType: 'module' - }, - - rules: { - indent: ['error', 2], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single'], - semi: ['error', 'never'], - '@typescript-eslint/explicit-member-accessibility': [ - 'error', - { - accessibility: 'no-public' - } - ] - } - } -] diff --git a/action-parser/eslint.config.mts b/action-parser/eslint.config.mts new file mode 100644 index 0000000..63c62be --- /dev/null +++ b/action-parser/eslint.config.mts @@ -0,0 +1,23 @@ +import eslint from '@eslint/js' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + eslint.configs.recommended, + tseslint.configs.strict, + tseslint.configs.stylistic, + { + rules: { + indent: ['error', 2], + 'linebreak-style': ['error', 'unix'], + quotes: ['error', 'single'], + semi: ['error', 'never'], + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/explicit-member-accessibility': [ + 'error', + { + accessibility: 'no-public' + } + ] + } + } +) diff --git a/action-parser/package.json b/action-parser/package.json index 998732e..b076508 100644 --- a/action-parser/package.json +++ b/action-parser/package.json @@ -10,25 +10,24 @@ "test:watch": "vitest", "test:cov": "vitest run --coverage", "test:debug": "vitest --inspect-brk --inspect --logHeapUsage --no-file-parallelism", - "lint": "eslint \"{src,test}/**/*.ts\"", - "format": "prettier --write \"**/*.{t,mj}s\"" + "lint": "eslint --flag unstable_ts_config \"{src,test}/**/*.ts\"", + "format": "prettier --write \"{src,test}/**/*.{m,}ts\" \"*.{m,}ts\"" }, "license": "MIT", "dependencies": { "chevrotain": "^11.0.3" }, "devDependencies": { - "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.10.0", "@swc/core": "^1.9.3", - "@typescript-eslint/eslint-plugin": "^8.10.0", - "@typescript-eslint/parser": "^8.10.0", "@vitest/coverage-v8": "^2.1.6", "eslint": "^9.16.0", "globals": "^15.13.0", + "jiti": "^2.4.1", "prettier": "^3.4.1", "ts-node": "^10.9.2", "typescript": "^5.7.2", + "typescript-eslint": "^8.16.0", "unplugin-swc": "^1.5.1", "vitest": "^2.1.6" } diff --git a/action-parser/vitest.config.mts b/action-parser/vitest.config.mts index d11e64f..f74444b 100644 --- a/action-parser/vitest.config.mts +++ b/action-parser/vitest.config.mts @@ -6,10 +6,7 @@ export default defineConfig({ globals: true, root: './', coverage: { - exclude: [ - ...configDefaults.coverage.exclude ?? [], - '*/*.interfaces.ts' - ] + exclude: [...(configDefaults.coverage.exclude ?? []), '*/*.interfaces.ts'] } }, plugins: [ diff --git a/backend/eslint.config.mjs b/backend/eslint.config.mjs deleted file mode 100644 index c2dee79..0000000 --- a/backend/eslint.config.mjs +++ /dev/null @@ -1,66 +0,0 @@ -import typescriptEslintEslintPlugin from '@typescript-eslint/eslint-plugin' -import prettier from 'eslint-plugin-prettier' -import globals from 'globals' -import tsParser from '@typescript-eslint/parser' -import path from 'node:path' -import {fileURLToPath} from 'node:url' -import js from '@eslint/js' -import {FlatCompat} from '@eslint/eslintrc' - -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, - allConfig: js.configs.all -}) - -export default [ - ...compat.extends('plugin:@typescript-eslint/recommended', 'prettier'), - { - plugins: { - '@typescript-eslint': typescriptEslintEslintPlugin, - prettier - }, - - languageOptions: { - globals: { - ...globals.node, - ...globals.jest - }, - - parser: tsParser, - ecmaVersion: 5, - sourceType: 'module', - - parserOptions: { - project: 'tsconfig.json' - } - }, - - rules: { - '@typescript-eslint/interface-name-prefix': 'off', - '@typescript-eslint/explicit-function-return-type': 'off', - '@typescript-eslint/explicit-module-boundary-types': 'off', - '@typescript-eslint/no-explicit-any': 'off', - '@typescript-eslint/explicit-member-accessibility': [ - 'error', - { - accessibility: 'no-public' - } - ], - '@typescript-eslint/no-unused-vars': [ - 'error', - { - args: 'all', - argsIgnorePattern: '^_', - caughtErrors: 'all', - caughtErrorsIgnorePattern: '^_', - destructuredArrayIgnorePattern: '^_', - varsIgnorePattern: '^_', - ignoreRestSiblings: true - } - ] - } - } -] diff --git a/backend/eslint.config.mts b/backend/eslint.config.mts new file mode 100644 index 0000000..25d95d9 --- /dev/null +++ b/backend/eslint.config.mts @@ -0,0 +1,38 @@ +import eslint from '@eslint/js' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + eslint.configs.recommended, + tseslint.configs.strict, + tseslint.configs.stylistic, + { + rules: { + '@typescript-eslint/interface-name-prefix': 'off', + '@typescript-eslint/explicit-function-return-type': 'off', + '@typescript-eslint/explicit-module-boundary-types': 'off', + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-extraneous-class': [ + 'error', + {allowWithDecorator: true} + ], + '@typescript-eslint/explicit-member-accessibility': [ + 'error', + { + accessibility: 'no-public' + } + ], + '@typescript-eslint/no-unused-vars': [ + 'error', + { + args: 'all', + argsIgnorePattern: '^_', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_', + destructuredArrayIgnorePattern: '^_', + varsIgnorePattern: '^_', + ignoreRestSiblings: true + } + ] + } + } +) diff --git a/backend/package.json b/backend/package.json index fc58d51..c44ef1e 100644 --- a/backend/package.json +++ b/backend/package.json @@ -7,14 +7,14 @@ "license": "MIT", "scripts": { "build": "nest build", - "format": "prettier --write \"src/**/*.{m,}ts\" \"test/**/*.{m,}ts\"", + "format": "prettier --write \"{src,test}/**/*.{m,}ts\" \"*.{m,}ts\"", "nest": "nest", "start": "nest start", "start:dev": "nest start --watch", "start:debug": "nest start --debug --watch", "start:prod": "node dist/main", - "lint": "eslint \"{src,test}/**/*.ts\"", - "lint:fix": "eslint \"{src,test}/**/*.{m,}ts\" --fix", + "lint": "eslint --flag unstable_ts_config \"{src,test}/**/*.ts\"", + "lint:fix": "eslint --flag unstable_ts_config \"{src,test}/**/*.{m,}ts\" --fix", "test": "vitest run", "test:watch": "vitest", "test:cov": "vitest run --coverage", @@ -46,8 +46,7 @@ "ws": "^8.18.0" }, "devDependencies": { - "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "^9.13.0", + "@eslint/js": "^9.10.0", "@nestjs/cli": "^10.4.8", "@nestjs/schematics": "^10.2.3", "@nestjs/testing": "^10.4.12", @@ -56,13 +55,9 @@ "@types/node": "^20.17.7", "@types/supertest": "^6.0.2", "@types/ws": "^8.5.13", - "@typescript-eslint/eslint-plugin": "^8.10.0", - "@typescript-eslint/parser": "^8.10.0", "@vitest/coverage-v8": "^2.1.6", "eslint": "^9.16.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.2.1", - "globals": "^15.13.0", + "jiti": "^2.4.1", "prettier": "^3.4.1", "prisma": "^6.0.0", "source-map-support": "^0.5.21", @@ -71,6 +66,7 @@ "ts-node": "^10.9.2", "tsconfig-paths": "4.2.0", "typescript": "^5.7.2", + "typescript-eslint": "^8.16.0", "unplugin-swc": "^1.5.1", "vitest": "^2.1.6" } diff --git a/backend/src/world/world.service.ts b/backend/src/world/world.service.ts index 8b64a72..de6d685 100644 --- a/backend/src/world/world.service.ts +++ b/backend/src/world/world.service.ts @@ -90,9 +90,8 @@ export class WorldService { async getTerrainPage(wid: number, pageX: number, pageZ: number) { const cacheKey = `T-${wid}-${pageX}-${pageZ}` - let page: Partial<{[key: number]: [number, number]}> | undefined = + let page: Partial> | undefined = await this.cache.get(cacheKey) - if (page == null) { page = {} for (const elev of await this.db.elev.findMany({ diff --git a/bot/eslint.config.mjs b/bot/eslint.config.mjs deleted file mode 100644 index 96e98dd..0000000 --- a/bot/eslint.config.mjs +++ /dev/null @@ -1,52 +0,0 @@ -import typescriptEslint from '@typescript-eslint/eslint-plugin' -import globals from 'globals' -import tsParser from '@typescript-eslint/parser' -import path from 'node:path' -import {fileURLToPath} from 'node:url' -import js from '@eslint/js' -import {FlatCompat} from '@eslint/eslintrc' - -const __filename = fileURLToPath(import.meta.url) -const __dirname = path.dirname(__filename) -const compat = new FlatCompat({ - baseDirectory: __dirname, - recommendedConfig: js.configs.recommended, - allConfig: js.configs.all -}) - -export default [ - ...compat.extends( - 'eslint:recommended', - 'plugin:@typescript-eslint/recommended' - ), - { - plugins: { - '@typescript-eslint': typescriptEslint - }, - - languageOptions: { - globals: { - ...globals.browser, - ...globals.node - }, - - parser: tsParser, - ecmaVersion: 'latest', - sourceType: 'module' - }, - - rules: { - indent: ['error', 2, {SwitchCase: 1}], - 'linebreak-style': ['error', 'unix'], - quotes: ['error', 'single', {avoidEscape: true}], - semi: ['error', 'never'], - '@typescript-eslint/no-explicit-any': 'warn', - '@typescript-eslint/explicit-member-accessibility': [ - 'error', - { - accessibility: 'no-public' - } - ] - } - } -] diff --git a/bot/eslint.config.mts b/bot/eslint.config.mts new file mode 100644 index 0000000..cd4ea7a --- /dev/null +++ b/bot/eslint.config.mts @@ -0,0 +1,23 @@ +import eslint from '@eslint/js' +import tseslint from 'typescript-eslint' + +export default tseslint.config( + eslint.configs.recommended, + tseslint.configs.strict, + tseslint.configs.stylistic, + { + rules: { + indent: ['error', 2, {SwitchCase: 1}], + 'linebreak-style': ['error', 'unix'], + quotes: ['error', 'single', {avoidEscape: true}], + semi: ['error', 'never'], + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/explicit-member-accessibility': [ + 'error', + { + accessibility: 'no-public' + } + ] + } + } +) diff --git a/bot/package.json b/bot/package.json index c57b33b..9d534b6 100644 --- a/bot/package.json +++ b/bot/package.json @@ -6,8 +6,8 @@ "type": "module", "scripts": { "start": "node --import 'data:text/javascript,import {register} from \"node:module\"; import {pathToFileURL} from \"node:url\"; register(\"ts-node/esm\", pathToFileURL(\"./\"));' src/bonobot.ts", - "format": "prettier --write \"**/*.{t,cj}s\"", - "lint": "eslint \"src/**/*.ts\"" + "format": "prettier --write \"src/**/*.ts\" \"*.{m,}ts\"", + "lint": "eslint --flag unstable_ts_config \"src/**/*.ts\"" }, "license": "MIT", "dependencies": { @@ -15,16 +15,14 @@ "ws": "^8.18.0" }, "devDependencies": { - "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.10.0", "@types/node": "^20.17.7", "@types/ws": "^8.5.13", - "@typescript-eslint/eslint-plugin": "^8.10.0", - "@typescript-eslint/parser": "^8.10.0", "eslint": "^9.16.0", - "globals": "^15.13.0", + "jiti": "^2.4.1", "prettier": "^3.4.1", "ts-node": "^10.9.2", - "typescript": "^5.7.2" + "typescript": "^5.7.2", + "typescript-eslint": "^8.16.0" } } diff --git a/bot/src/bot.ts b/bot/src/bot.ts index 6333060..a3a3d99 100644 --- a/bot/src/bot.ts +++ b/bot/src/bot.ts @@ -30,28 +30,21 @@ class User { state: string gesture: string | null - constructor(name: string = '') { + constructor(name = '') { this.name = name this.world = 0 - this.x = 0.0 - this.y = 0.0 - this.z = 0.0 - this.roll = 0.0 - this.yaw = 0.0 - this.pitch = 0.0 + this.x = 0 + this.y = 0 + this.z = 0 + this.roll = 0 + this.yaw = 0 + this.pitch = 0 this.avatar = 0 this.state = 'idle' this.gesture = null } - setPosition( - x: number = 0.0, - y: number = 0.0, - z: number = 0.0, - roll: number = 0.0, - yaw: number = 0.0, - pitch: number = 0.0 - ): void { + setPosition(x = 0, y = 0, z = 0, roll = 0, yaw = 0, pitch = 0): void { this.x = x this.y = y this.z = z @@ -72,7 +65,7 @@ class Bot extends User { worldlist: Record cookiejar: Record - constructor(webUrl: string, wsUrl: string, loggingEnabled: boolean = true) { + constructor(webUrl: string, wsUrl: string, loggingEnabled = true) { super() this.webUrl = webUrl this.wsUrl = wsUrl @@ -95,7 +88,7 @@ class Bot extends User { async _callback(name: string, ...parameters: unknown[]): Promise { const instances = [this, ...Object.values(this.handlers)] for (const inst of instances) { - const f = (inst as unknown as {[key: string]: unknown})[name] + const f = (inst as unknown as Record)[name] if (typeof f !== 'function') continue if (DEBUG) { this.log(`calling ${name}() on instance ${inst.name}`) diff --git a/frontend/eslint.config.js b/frontend/eslint.config.js deleted file mode 100644 index 341a061..0000000 --- a/frontend/eslint.config.js +++ /dev/null @@ -1,56 +0,0 @@ -// @ts-check -const eslint = require("@eslint/js"); -const tseslint = require("typescript-eslint"); -const angular = require("angular-eslint"); - -module.exports = tseslint.config( - { - files: ["**/*.ts"], - extends: [ - eslint.configs.recommended, - ...tseslint.configs.recommended, - ...tseslint.configs.stylistic, - ...angular.configs.tsRecommended, - ], - processor: angular.processInlineTemplates, - rules: { - "@angular-eslint/directive-selector": [ - "error", - { - type: "attribute", - prefix: "app", - style: "camelCase", - }, - ], - "@angular-eslint/component-selector": [ - "error", - { - type: "element", - prefix: "app", - style: "kebab-case", - }, - ], - "@typescript-eslint/no-explicit-any": "warn", - "@typescript-eslint/no-unused-vars": [ - "error", - { - "args": "all", - "argsIgnorePattern": "^_", - "caughtErrors": "all", - "caughtErrorsIgnorePattern": "^_", - "destructuredArrayIgnorePattern": "^_", - "varsIgnorePattern": "^_", - "ignoreRestSiblings": true - } - ] - } - }, - { - files: ["**/*.html"], - extends: [ - ...angular.configs.templateRecommended, - ...angular.configs.templateAccessibility, - ], - rules: {}, - } -); diff --git a/frontend/eslint.config.ts b/frontend/eslint.config.ts new file mode 100644 index 0000000..d1e20db --- /dev/null +++ b/frontend/eslint.config.ts @@ -0,0 +1,62 @@ +import eslint from '@eslint/js' +import tseslint from 'typescript-eslint' +import angular from 'angular-eslint' + +export default tseslint.config( + { + files: ['**/*.ts'], + extends: [ + eslint.configs.recommended, + tseslint.configs.strict, + tseslint.configs.stylistic, + angular.configs.tsRecommended + ], + processor: angular.processInlineTemplates, + rules: { + '@angular-eslint/directive-selector': [ + 'error', + { + type: 'attribute', + prefix: 'app', + style: 'camelCase' + } + ], + '@angular-eslint/component-selector': [ + 'error', + { + type: 'element', + prefix: 'app', + style: 'kebab-case' + } + ], + + '@typescript-eslint/no-explicit-any': 'warn', + '@typescript-eslint/no-extraneous-class': [ + 'error', + {allowWithDecorator: true} + ], + '@typescript-eslint/no-non-null-assertion': 'off', + '@typescript-eslint/no-unused-vars': [ + 'error', + { + args: 'all', + argsIgnorePattern: '^_', + caughtErrors: 'all', + caughtErrorsIgnorePattern: '^_', + destructuredArrayIgnorePattern: '^_', + varsIgnorePattern: '^_', + ignoreRestSiblings: true + } + ], + '@typescript-eslint/consistent-type-imports': 'error' + } + }, + { + files: ['**/*.html'], + extends: [ + ...angular.configs.templateRecommended, + ...angular.configs.templateAccessibility + ], + rules: {} + } +) diff --git a/frontend/package.json b/frontend/package.json index 384b5ca..d23c776 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -8,9 +8,9 @@ "build": "ng build --configuration development", "build:prod": "ng build --configuration production", "build:watch": "ng build --configuration development --watch", - "format": "prettier --write \"src/**/*.ts\"", + "format": "prettier --write \"src/**/*.ts\" \"*.{m,}ts\"", "test": "ng test", - "lint": "ng lint", + "lint": "eslint --flag unstable_ts_config", "postinstall": "cd ../ && npm run patch:frontend" }, "private": true, @@ -44,6 +44,7 @@ "@angular-devkit/build-angular": "^19.0.1", "@angular/cli": "^19.0.2", "@angular/compiler-cli": "^19.0.0", + "@eslint/js": "^9.10.0", "@types/node": "^20.17.7", "@types/three": "^0.170.0", "@types/webgl2": "^0.0.11", diff --git a/frontend/src/app/engine/engine.service.ts b/frontend/src/app/engine/engine.service.ts index 2529ba4..16262ba 100644 --- a/frontend/src/app/engine/engine.service.ts +++ b/frontend/src/app/engine/engine.service.ts @@ -37,7 +37,7 @@ import type {AvatarAnimationPlayer} from '../animation' import type {PressedKey} from './inputsystem.service' import {InputSystemService} from './inputsystem.service' import {environment} from '../../environments/environment' -import {DEG, Utils} from '../utils' +import {DEG, getMeshes, radNormalized, shortestAngle} from '../utils' import {Player} from './player' import { acceleratedRaycast, @@ -976,7 +976,7 @@ export class EngineService { ).multiplyScalar(movSteps) ) } else { - this.player.rotation.y = Utils.radNormalized( + this.player.rotation.y = radNormalized( this.player.rotation.y + reverse * rotSteps ) } @@ -992,7 +992,7 @@ export class EngineService { ).multiplyScalar(movSteps) ) } else { - this.player.rotation.y = Utils.radNormalized( + this.player.rotation.y = radNormalized( this.player.rotation.y - reverse * rotSteps ) } @@ -1121,8 +1121,8 @@ export class EngineService { user.position.setY(user.position.y + user.userData.offsetY) } user.rotation.set( - u.oldRoll + Utils.shortestAngle(u.oldRoll, u.roll) * u.completion, - u.oldYaw + Utils.shortestAngle(u.oldYaw, u.yaw) * u.completion, + u.oldRoll + shortestAngle(u.oldRoll, u.roll) * u.completion, + u.oldYaw + shortestAngle(u.oldYaw, u.yaw) * u.completion, 0, 'YZX' ) @@ -1174,7 +1174,7 @@ export class EngineService { this.raycaster.set(cameraPosition, cameraToSpriteDirection) // Ignore the current prop during raycasting to prevent self-intersection - const ignoreList = Utils.getMeshes(corona.parent!) + const ignoreList = getMeshes(corona.parent!) const intersects = this.raycaster .intersectObjects( this.objectsNode.children diff --git a/frontend/src/app/engine/player.ts b/frontend/src/app/engine/player.ts index d4cfab6..5282099 100644 --- a/frontend/src/app/engine/player.ts +++ b/frontend/src/app/engine/player.ts @@ -8,7 +8,7 @@ import { } from 'three' import type {LOD, Triangle} from 'three' import {PlayerCollider} from './player-collider' -import {DEG, TERRAIN_PAGE_SIZE, Utils} from '../utils' +import {DEG, radNormalized, stringToPos, TERRAIN_PAGE_SIZE} from '../utils' import {environment} from '../../environments/environment' import {inject, signal} from '@angular/core' import type {AvatarAnimationPlayer} from '../animation' @@ -69,14 +69,14 @@ export class Player { if (typeof pos === 'string') { const yawMatch = /\s([0-9]+)$/.exec(pos) yaw = yawMatch ? parseInt(yawMatch[1], 10) : 0 - pos = Utils.stringToPos(pos) + pos = stringToPos(pos) } this.entity.position.copy(pos) this.setYaw(yaw) } setYaw(yaw: number) { - this.entity.rotation.y = Utils.radNormalized(yaw * DEG + Math.PI) + this.entity.rotation.y = radNormalized(yaw * DEG + Math.PI) } createBoundingBox(boxHeight: number) { diff --git a/frontend/src/app/ui/ui-toolbar/ui-toolbar.component.ts b/frontend/src/app/ui/ui-toolbar/ui-toolbar.component.ts index d8269f3..c3164cb 100644 --- a/frontend/src/app/ui/ui-toolbar/ui-toolbar.component.ts +++ b/frontend/src/app/ui/ui-toolbar/ui-toolbar.component.ts @@ -38,7 +38,7 @@ import type {User} from '../../user' import {environment} from '../../../environments/environment' import {Vector3} from 'three' import {distinctUntilChanged, throttleTime} from 'rxjs' -import {Utils} from '../../utils' +import {altToString, posToStringSimple} from '../../utils' import { faArrowLeft, faArrowRight, @@ -111,8 +111,8 @@ export class UiToolbarComponent implements OnInit { .fill(40) .map((n, i) => n + i * 20) visibility = environment.world.lod.maxDistance - strPos = signal(Utils.posToStringSimple(new Vector3())) - strAlt = signal(Utils.altToString(new Vector3())) + strPos = signal(posToStringSimple(new Vector3())) + strAlt = signal(altToString(new Vector3())) strFps = '0 FPS 0 draws' strMem = '0 Geom. 0 Text.' @@ -176,8 +176,8 @@ export class UiToolbarComponent implements OnInit { ) ) .subscribe((o: {pos: Vector3; theta: number}) => { - this.strPos.set(Utils.posToStringSimple(o.pos)) - this.strAlt.set(Utils.altToString(o.pos)) + this.strPos.set(posToStringSimple(o.pos)) + this.strAlt.set(altToString(o.pos)) this.renderer.setStyle( this.compass().nativeElement, 'transform', diff --git a/frontend/src/app/ui/ui-world-attribs/ui-world-attribs.component.ts b/frontend/src/app/ui/ui-world-attribs/ui-world-attribs.component.ts index 379cbc9..ab03c5f 100644 --- a/frontend/src/app/ui/ui-world-attribs/ui-world-attribs.component.ts +++ b/frontend/src/app/ui/ui-world-attribs/ui-world-attribs.component.ts @@ -14,7 +14,7 @@ import {MatInput, MatLabel} from '@angular/material/input' import {MatSlider, MatSliderThumb} from '@angular/material/slider' import {MatTab, MatTabGroup, MatTabLabel} from '@angular/material/tabs' import {FaIconComponent} from '@fortawesome/angular-fontawesome' -import {Utils} from '../../utils' +import {colorHexToStr, colorStrToHex, hexToRgb} from '../../utils' import {SkyService} from '../../world/sky.service' import {WorldService} from '../../world/world.service' import {TerrainService} from '../../world/terrain.service' @@ -88,13 +88,13 @@ export class UiWorldAttribsComponent { this.lightDirZ = signal(this.lightingSvc.dirLightTarget[2] | 0) this.fogColor = signal( - Utils.colorHexToStr(this.lightingSvc.worldFog?.color ?? 0x00007f) + colorHexToStr(this.lightingSvc.worldFog?.color ?? 0x00007f) ) - this.ambLight = signal(Utils.colorHexToStr(this.lightingSvc.ambLightColor)) - this.dirLight = signal(Utils.colorHexToStr(this.lightingSvc.dirLightColor)) + this.ambLight = signal(colorHexToStr(this.lightingSvc.ambLightColor)) + this.dirLight = signal(colorHexToStr(this.lightingSvc.dirLightColor)) this.water = signal(this.terrainSvc.water != null) this.waterColor = signal( - Utils.colorHexToStr(this.terrainSvc.water?.userData?.color ?? 0x00ffff) + colorHexToStr(this.terrainSvc.water?.userData?.color ?? 0x00ffff) ) this.waterTextureBottom = signal( this.terrainSvc.water?.userData?.texture_bottom || '' @@ -110,17 +110,17 @@ export class UiWorldAttribsComponent { effect(() => { this.lightingSvc.worldFog = { - color: Utils.colorStrToHex(this.fogColor()), + color: colorStrToHex(this.fogColor()), near: this.fogMin(), far: this.fogMax(), enabled: this.fog() } }) effect(() => { - this.lightingSvc.ambLightColor = Utils.colorStrToHex(this.ambLight()) + this.lightingSvc.ambLightColor = colorStrToHex(this.ambLight()) }) effect(() => { - this.lightingSvc.dirLightColor = Utils.colorStrToHex(this.dirLight()) + this.lightingSvc.dirLightColor = colorStrToHex(this.dirLight()) }) effect(() => { this.lightingSvc.dirLightTarget = [ @@ -141,7 +141,7 @@ export class UiWorldAttribsComponent { effect(() => { this.terrainSvc.setWater({ enabled: this.water(), - color: Utils.hexToRgb(Utils.colorStrToHex(this.waterColor())), + color: hexToRgb(colorStrToHex(this.waterColor())), offset: this.waterLevel(), opacity: this.waterOpacity(), texture_bottom: this.waterTextureBottom(), diff --git a/frontend/src/app/utils/text-canvas.ts b/frontend/src/app/utils/text-canvas.ts index 8ce2bc9..43ba8df 100644 --- a/frontend/src/app/utils/text-canvas.ts +++ b/frontend/src/app/utils/text-canvas.ts @@ -1,129 +1,127 @@ -export class TextCanvas { - /** - * Displays text on an HTML canvas element - * - * @param text The text to display - * @param ratio The canvas ratio - * @param color The text color - * @param bcolor The background color - * @returns An HTML canvas element - */ - static textCanvas( - text: string, - color: {r: number; g: number; b: number}, - bcolor: {r: number; g: number; b: number}, - ratio = 1 - ) { - const canvas = document.createElement('canvas') - const canvasWidth = ratio > 1 ? 256 : 256 * ratio - const canvasHeight = ratio > 1 ? 256 / ratio : 256 - - canvas.width = canvasWidth - canvas.height = canvasHeight - const ctx = canvas.getContext('2d')! - ctx.fillStyle = `rgb(${bcolor.r},${bcolor.g},${bcolor.b})` - ctx.fillRect(0, 0, canvas.width, canvas.height) - ctx.fillStyle = `rgb(${color.r},${color.g},${color.b})` - ctx.textBaseline = 'middle' - - let fontSize = 128 - let fontFit = false - - // Find the maximum font size that fits the text without cropping - while (!fontFit && fontSize > 0) { - ctx.font = `500 ${fontSize}px Arimo,Arial,sans-serif` - const lines = this.breakTextIntoLines(text, ctx, canvasWidth) - - const totalHeight = lines.length * fontSize * 1.2 - const totalWidth = Math.max( - ...lines.map((line) => ctx.measureText(line).width) - ) - - const heightDifference = totalHeight - canvasHeight - const widthDifference = totalWidth - canvasWidth - // Estimate how big the adjustment needs to be in order to avoid too many measureText calls - const adjustment = Math.trunc( - Math.max(heightDifference, widthDifference) / fontSize - ) - - if (heightDifference <= 0 && widthDifference <= 0) { - fontFit = true - } else { - // Keep the size even - fontSize -= adjustment + (adjustment % 2) || 2 - } +/** + * Displays text on an HTML canvas element + * + * @param text The text to display + * @param ratio The canvas ratio + * @param color The text color + * @param bcolor The background color + * @returns An HTML canvas element + */ +export function textCanvas( + text: string, + color: {r: number; g: number; b: number}, + bcolor: {r: number; g: number; b: number}, + ratio = 1 +) { + const canvas = document.createElement('canvas') + const canvasWidth = ratio > 1 ? 256 : 256 * ratio + const canvasHeight = ratio > 1 ? 256 / ratio : 256 + + canvas.width = canvasWidth + canvas.height = canvasHeight + const ctx = canvas.getContext('2d')! + ctx.fillStyle = `rgb(${bcolor.r},${bcolor.g},${bcolor.b})` + ctx.fillRect(0, 0, canvas.width, canvas.height) + ctx.fillStyle = `rgb(${color.r},${color.g},${color.b})` + ctx.textBaseline = 'middle' + + let fontSize = 128 + let fontFit = false + + // Find the maximum font size that fits the text without cropping + while (!fontFit && fontSize > 0) { + ctx.font = `500 ${fontSize}px Arimo,Arial,sans-serif` + const lines = breakTextIntoLines(text, ctx, canvasWidth) + + const totalHeight = lines.length * fontSize * 1.2 + const totalWidth = Math.max( + ...lines.map((line) => ctx.measureText(line).width) + ) + + const heightDifference = totalHeight - canvasHeight + const widthDifference = totalWidth - canvasWidth + // Estimate how big the adjustment needs to be in order to avoid too many measureText calls + const adjustment = Math.trunc( + Math.max(heightDifference, widthDifference) / fontSize + ) + + if (heightDifference <= 0 && widthDifference <= 0) { + fontFit = true + } else { + // Keep the size even + fontSize -= adjustment + (adjustment % 2) || 2 } + } - const lines = TextCanvas.breakTextIntoLines(text, ctx, canvasWidth) + const lines = breakTextIntoLines(text, ctx, canvasWidth) - ctx.font = `500 ${fontSize}px Arimo,Arial,sans-serif` - ctx.textBaseline = 'top' + ctx.font = `500 ${fontSize}px Arimo,Arial,sans-serif` + ctx.textBaseline = 'top' - const lineHeight = fontSize * 1.2 - const startY = (canvasHeight - lines.length * lineHeight) / 2 + const lineHeight = fontSize * 1.2 + const startY = (canvasHeight - lines.length * lineHeight) / 2 - lines.forEach((line, index) => { - const textWidth = ctx.measureText(line).width - const startX = (canvasWidth - textWidth) / 2 - const y = startY + index * lineHeight - ctx.fillText(line, startX, y) - }) + lines.forEach((line, index) => { + const textWidth = ctx.measureText(line).width + const startX = (canvasWidth - textWidth) / 2 + const y = startY + index * lineHeight + ctx.fillText(line, startX, y) + }) - return canvas - } + return canvas +} - /** - * Breaks the text into lines to fit within the given maximum width - * - * @param text The text to break into lines - * @param ctx The canvas rendering context - * @param maxWidth The maximum width of a line - * @returns The array of lines - */ - static breakTextIntoLines( - text: string, - ctx: CanvasRenderingContext2D, - maxWidth: number - ): string[] { - const lines: string[] = [] - const paragraphs = text.split('\n') - - paragraphs.forEach((paragraph) => { - const words = paragraph.split(' ') - let currentLine = '' - - words.forEach((word) => { - if (word.length === 0) { - // Skip empty words - return - } - - const lineWidth = ctx.measureText(`${currentLine} ${word}`).width - - if (lineWidth < maxWidth || currentLine.length === 0) { - currentLine += ` ${word}` - } else { - lines.push(currentLine.trim()) - currentLine = word - } - }) - - if (currentLine.length > 0) { +/** + * Breaks the text into lines to fit within the given maximum width + * + * @param text The text to break into lines + * @param ctx The canvas rendering context + * @param maxWidth The maximum width of a line + * @returns The array of lines + */ +function breakTextIntoLines( + text: string, + ctx: CanvasRenderingContext2D, + maxWidth: number +): string[] { + const lines: string[] = [] + const paragraphs = text.split('\n') + + paragraphs.forEach((paragraph) => { + const words = paragraph.split(' ') + let currentLine = '' + + words.forEach((word) => { + if (word.length === 0) { + // Skip empty words + return + } + + const lineWidth = ctx.measureText(`${currentLine} ${word}`).width + + if (lineWidth < maxWidth || currentLine.length === 0) { + currentLine += ` ${word}` + } else { lines.push(currentLine.trim()) + currentLine = word } }) - // Handle empty lines at the end of the text - const emptyLineCount = [...text].reduceRight((count, char, index) => { - if (char === '\n' && index === text.length - count - 1) { - return count + 1 - } - return count - }, 0) + if (currentLine.length > 0) { + lines.push(currentLine.trim()) + } + }) + + // Handle empty lines at the end of the text + const emptyLineCount = [...text].reduceRight((count, char, index) => { + if (char === '\n' && index === text.length - count - 1) { + return count + 1 + } + return count + }, 0) - // Add empty lines at the end - lines.push(...Array(emptyLineCount).fill('')) + // Add empty lines at the end + lines.push(...Array(emptyLineCount).fill('')) - return lines - } + return lines } diff --git a/frontend/src/app/utils/utils.ts b/frontend/src/app/utils/utils.ts index e73cfdb..701dd0c 100644 --- a/frontend/src/app/utils/utils.ts +++ b/frontend/src/app/utils/utils.ts @@ -1,153 +1,155 @@ import {Mesh, Vector3} from 'three' import type {Object3D} from 'three' -export class Utils { - static posToStringSimple(pos: Vector3): string { - return `${(Math.abs(pos.z) / 10).toFixed(2)}${pos.z >= 0 ? 'N' : 'S'} ${( - Math.abs(pos.x) / 10 - ).toFixed(2)}${pos.x >= 0 ? 'W' : 'E'}` - } +export function posToStringSimple(pos: Vector3): string { + return `${(Math.abs(pos.z) / 10).toFixed(2)}${pos.z >= 0 ? 'N' : 'S'} ${( + Math.abs(pos.x) / 10 + ).toFixed(2)}${pos.x >= 0 ? 'W' : 'E'}` +} - /** - * Converts position to string - * - * @param pos Position - * @param yaw Yaw in degrees - * @returns Position string with optional yaw - */ - static posToString(pos: Vector3, yaw = 0): string { - const position = `${this.posToStringSimple(pos)} ${( - Math.abs(pos.y) / 10 - ).toFixed(2)}a` - return yaw ? `${position} ${yaw}` : position - } +/** + * Converts position to string + * + * @param pos Position + * @param yaw Yaw in degrees + * @returns Position string with optional yaw + */ +export function posToString(pos: Vector3, yaw = 0): string { + const position = `${this.posToStringSimple(pos)} ${( + Math.abs(pos.y) / 10 + ).toFixed(2)}a` + return yaw ? `${position} ${yaw}` : position +} - static altToString(pos: Vector3): string { - return pos.y.toFixed(2) - } +export function altToString(pos: Vector3): string { + return pos.y.toFixed(2) +} - static stringToPos(pos: string): Vector3 { - const r = new Vector3() - const [, zNum, , zHemi, xNum, , xHemi, , yNum] = - /([+-]?([0-9]*\.)?[0-9]+)(N|S)\s([+-]?([0-9]*\.)?[0-9]+)(W|E)(\s([+-]?([0-9]*\.)?[0-9]+)a)?/i.exec( - pos - ) || [] - if (zNum && xNum) { - r.set( - Number.parseFloat(xNum) * (xHemi.toUpperCase() === 'W' ? 10 : -10), - (Number.parseFloat(yNum) || 0) * 10, - Number.parseFloat(zNum) * (zHemi.toUpperCase() === 'N' ? 10 : -10) - ) - } - return r +export function stringToPos(pos: string): Vector3 { + const r = new Vector3() + const [, zNum, , zHemi, xNum, , xHemi, , yNum] = + /([+-]?([0-9]*\.)?[0-9]+)(N|S)\s([+-]?([0-9]*\.)?[0-9]+)(W|E)(\s([+-]?([0-9]*\.)?[0-9]+)a)?/i.exec( + pos + ) || [] + if (zNum && xNum) { + r.set( + Number.parseFloat(xNum) * (xHemi.toUpperCase() === 'W' ? 10 : -10), + (Number.parseFloat(yNum) || 0) * 10, + Number.parseFloat(zNum) * (zHemi.toUpperCase() === 'N' ? 10 : -10) + ) } + return r +} - static modelName(name: string) { - if (name.endsWith('.rwx')) { - return name - } - if (name.endsWith('.zip')) { - return name.slice(0, -4) + '.rwx' - } - return name + '.rwx' +export function modelName(name: string) { + if (name.endsWith('.rwx')) { + return name } - - static radNormalized(value: number): number { - return ((value + Math.PI) % (2 * Math.PI)) - Math.PI + if (name.endsWith('.zip')) { + return name.slice(0, -4) + '.rwx' } + return name + '.rwx' +} - /** - * Converts RGB values to an hex color number - * - * @param red Red value - * @param green Green value - * @param blue Blue value - * @returns Hex color value - */ - static rgbToHex(red: number, green: number, blue: number): number { - return blue | (green << 8) | (red << 16) - } +export function radNormalized(value: number): number { + return ((value + Math.PI) % (2 * Math.PI)) - Math.PI +} - /** - * Converts an hex color to RGB values - * - * @param hex Color number - * @returns RGB values array - */ - static hexToRgb(hex: number): [number, number, number] { - return [(hex >> 16) & 255, (hex >> 8) & 255, hex & 255] - } +/** + * Converts RGB values to an hex color number + * + * @param red Red value + * @param green Green value + * @param blue Blue value + * @returns Hex color value + */ +export function rgbToHex(red: number, green: number, blue: number): number { + return blue | (green << 8) | (red << 16) +} - /** - * Converts a color string to an hex color - * - * @param color Color string - * @returns Hex color value - */ - static colorStrToHex(color: string): number { - return parseInt(color.substring(1), 16) - } +/** + * Converts an hex color to RGB values + * + * @param hex Color number + * @returns RGB values array + */ +export function hexToRgb(hex: number): [number, number, number] { + return [(hex >> 16) & 255, (hex >> 8) & 255, hex & 255] +} - /** - * Converts an hex color to string - * - * @param color Hex color - * @returns Color string - */ - static colorHexToStr(color: number): string { - return '#' + `00000${color.toString(16)}`.slice(-6) - } +/** + * Converts a color string to an hex color + * + * @param color Color string + * @returns Hex color value + */ +export function colorStrToHex(color: string): number { + return parseInt(color.substring(1), 16) +} - static shortestAngle(oldValue: number, newValue: number): number { - // Work within [0, 2*PI] instead of [-Pi, Pi] for the original values - let diff = newValue - oldValue + Math.PI +/** + * Converts an hex color to string + * + * @param color Hex color + * @returns Color string + */ +export function colorHexToStr(color: number): string { + return '#' + `00000${color.toString(16)}`.slice(-6) +} - // /!\ Careful there: the modulo ( % ) operator doesn't change anything on negative values, - // so even the difference itself needs to fit into [0, 2*PI] - if (diff < 0) { - diff += 2 * Math.PI - } +export function shortestAngle(oldValue: number, newValue: number): number { + // Work within [0, 2*PI] instead of [-Pi, Pi] for the original values + let diff = newValue - oldValue + Math.PI - // The final result still needs to be expressed within [-Pi, Pi], - // so we translate the result back into it. - return (diff % (2 * Math.PI)) - Math.PI + // /!\ Careful there: the modulo ( % ) operator doesn't change anything on negative values, + // so even the difference itself needs to fit into [0, 2*PI] + if (diff < 0) { + diff += 2 * Math.PI } - /** - * Find objects by userData attribute - * @param node The node to traverse - * @param key Which attribute to look for (e.g. name) - * @param value The value to search - * @returns List of matching objects - */ - static getObjectsByUserData(node: Object3D, key: string, value: string) { - const objs: Object3D[] = [] - node.traverse((obj: Object3D) => { - if (obj.userData[key] === value) { - objs.push(obj) - } - }) - return objs - } + // The final result still needs to be expressed within [-Pi, Pi], + // so we translate the result back into it. + return (diff % (2 * Math.PI)) - Math.PI +} - /** - * Get all children objects recursively - * @param object Object3D to traverse - * @param children Array of the children (empty by default) - * @returns Array of children - */ - static getMeshes(object: Object3D, children: Mesh[] = []) { - if (object instanceof Mesh) { - children.push(object) +/** + * Find objects by userData attribute + * @param node The node to traverse + * @param key Which attribute to look for (e.g. name) + * @param value The value to search + * @returns List of matching objects + */ +export function getObjectsByUserData( + node: Object3D, + key: string, + value: string +) { + const objs: Object3D[] = [] + node.traverse((obj: Object3D) => { + if (obj.userData[key] === value) { + objs.push(obj) } - object.children.forEach((child) => { - if (child instanceof Mesh) { - children.push(child) - } - if (child.children.length > 0) { - Utils.getMeshes(child, children) - } - }) - return children + }) + return objs +} + +/** + * Get all children objects recursively + * @param object Object3D to traverse + * @param children Array of the children (empty by default) + * @returns Array of children + */ +export function getMeshes(object: Object3D, children: Mesh[] = []) { + if (object instanceof Mesh) { + children.push(object) } + object.children.forEach((child) => { + if (child instanceof Mesh) { + children.push(child) + } + if (child.children.length > 0) { + getMeshes(child, children) + } + }) + return children } diff --git a/frontend/src/app/world/lighting.service.ts b/frontend/src/app/world/lighting.service.ts index 36b2aab..85bacc5 100644 --- a/frontend/src/app/world/lighting.service.ts +++ b/frontend/src/app/world/lighting.service.ts @@ -1,7 +1,7 @@ import {inject, Injectable} from '@angular/core' import {AmbientLight, Color, DirectionalLight, Object3D} from 'three' import {EngineService} from '../engine/engine.service' -import {Utils} from '../utils' +import {rgbToHex} from '../utils' export interface LightData { amb_color: [number, number, number] @@ -82,15 +82,15 @@ export class LightingService { } setLighting(light: LightData) { - this.ambLightColor = Utils.rgbToHex(...light.amb_color) - this.dirLightColor = Utils.rgbToHex(...light.dir_color) + this.ambLightColor = rgbToHex(...light.amb_color) + this.dirLightColor = rgbToHex(...light.dir_color) this.dirLightTarget = [ light.dir.x * 100, light.dir.y * 100, light.dir.z * 100 ] this.worldFog = { - color: Utils.rgbToHex(...light.fog.color), + color: rgbToHex(...light.fog.color), near: light.fog.min, far: light.fog.max, enabled: light.fog.enabled diff --git a/frontend/src/app/world/prop-action.service.ts b/frontend/src/app/world/prop-action.service.ts index afdb66d..6178e3e 100644 --- a/frontend/src/app/world/prop-action.service.ts +++ b/frontend/src/app/world/prop-action.service.ts @@ -30,7 +30,7 @@ import {pictureTag as PICTURE_TAG, signTag as SIGN_TAG} from 'three-rwx-loader' import {Action} from '@lemuria/action-parser' import {environment} from '../../environments/environment' import {HttpService} from '../network' -import {TextCanvas, Utils} from '../utils' +import {getObjectsByUserData, posToString, rgbToHex, textCanvas} from '../utils' import {SettingsService} from '../settings/settings.service' import {AudioService} from '../engine/audio.service' import {TeleportService} from '../engine/teleport.service' @@ -166,7 +166,7 @@ export class PropActionService { prop.userData[trigger].light = prop.userData[trigger].light || [] prop.userData[trigger].light.push({ color: cmd.color - ? Utils.rgbToHex(cmd.color.r, cmd.color.g, cmd.color.b) + ? rgbToHex(cmd.color.r, cmd.color.g, cmd.color.b) : 0xffffff, brightness: cmd.brightness, radius: cmd.radius, @@ -304,7 +304,7 @@ export class PropActionService { callback(prop, command) prop.userData.onUpdate() } else { - Utils.getObjectsByUserData( + getObjectsByUserData( prop.parent!.parent!.parent!, 'name', command.targetName @@ -680,12 +680,7 @@ export class PropActionService { } newMaterials[i].color = new Color(1, 1, 1) newMaterials[i].map = new CanvasTexture( - TextCanvas.textCanvas( - text, - color, - bcolor, - newMaterials[i].userData.ratio - ) + textCanvas(text, color, bcolor, newMaterials[i].userData.ratio) ) newMaterials[i].map.colorSpace = SRGBColorSpace } @@ -940,7 +935,7 @@ export class PropActionService { this.teleportSvc.teleport.set({ world: teleport.worldName, // Don't send 0 if coordinates are null (world entry point) - position: Utils.posToString(new Vector3(newX, newY, newZ), newYaw), + position: posToString(new Vector3(newX, newY, newZ), newYaw), isNew: true }) } diff --git a/frontend/src/app/world/prop.service.ts b/frontend/src/app/world/prop.service.ts index d3911f7..08301c8 100644 --- a/frontend/src/app/world/prop.service.ts +++ b/frontend/src/app/world/prop.service.ts @@ -10,7 +10,7 @@ import { MeshBasicMaterial } from 'three' import RWXLoader, {flattenGroup, RWXMaterialManager} from 'three-rwx-loader' -import {Utils} from '../utils' +import {modelName} from '../utils' export type PropCtl = [ 'nop', @@ -123,7 +123,7 @@ export class PropService { objectCache: Map>, loaderType = 'basic' ) { - name = Utils.modelName(name) + name = modelName(name) const object = objectCache.get(name) if (object !== undefined) { return object diff --git a/frontend/src/app/world/sky.service.ts b/frontend/src/app/world/sky.service.ts index 9fefefa..fcfc546 100644 --- a/frontend/src/app/world/sky.service.ts +++ b/frontend/src/app/world/sky.service.ts @@ -1,5 +1,5 @@ import {effect, inject, Injectable, signal} from '@angular/core' -import {Utils} from '../utils' +import {colorHexToStr, colorStrToHex, hexToRgb, rgbToHex} from '../utils' import { Box3, BufferAttribute, @@ -29,34 +29,34 @@ export class SkyService { private readonly propSvc = inject(PropService) skybox = signal('') - skyTop = signal(Utils.colorHexToStr(0)) - skyNorth = signal(Utils.colorHexToStr(0)) - skyEast = signal(Utils.colorHexToStr(0)) - skySouth = signal(Utils.colorHexToStr(0)) - skyWest = signal(Utils.colorHexToStr(0)) - skyBottom = signal(Utils.colorHexToStr(0)) + skyTop = signal(colorHexToStr(0)) + skyNorth = signal(colorHexToStr(0)) + skyEast = signal(colorHexToStr(0)) + skySouth = signal(colorHexToStr(0)) + skyWest = signal(colorHexToStr(0)) + skyBottom = signal(colorHexToStr(0)) constructor() { effect(() => { this.createSkybox(this.skybox(), { - top: Utils.hexToRgb(Utils.colorStrToHex(this.skyTop())), - north: Utils.hexToRgb(Utils.colorStrToHex(this.skyNorth())), - east: Utils.hexToRgb(Utils.colorStrToHex(this.skyEast())), - south: Utils.hexToRgb(Utils.colorStrToHex(this.skySouth())), - west: Utils.hexToRgb(Utils.colorStrToHex(this.skyWest())), - bottom: Utils.hexToRgb(Utils.colorStrToHex(this.skyBottom())) + top: hexToRgb(colorStrToHex(this.skyTop())), + north: hexToRgb(colorStrToHex(this.skyNorth())), + east: hexToRgb(colorStrToHex(this.skyEast())), + south: hexToRgb(colorStrToHex(this.skySouth())), + west: hexToRgb(colorStrToHex(this.skyWest())), + bottom: hexToRgb(colorStrToHex(this.skyBottom())) }) }) } setSkybox(sky: SkyData) { this.skybox.set(sky.skybox) - this.skyTop.set(Utils.colorHexToStr(Utils.rgbToHex(...sky.top_color))) - this.skyNorth.set(Utils.colorHexToStr(Utils.rgbToHex(...sky.north_color))) - this.skyEast.set(Utils.colorHexToStr(Utils.rgbToHex(...sky.east_color))) - this.skySouth.set(Utils.colorHexToStr(Utils.rgbToHex(...sky.south_color))) - this.skyWest.set(Utils.colorHexToStr(Utils.rgbToHex(...sky.west_color))) - this.skyBottom.set(Utils.colorHexToStr(Utils.rgbToHex(...sky.bottom_color))) + this.skyTop.set(colorHexToStr(rgbToHex(...sky.top_color))) + this.skyNorth.set(colorHexToStr(rgbToHex(...sky.north_color))) + this.skyEast.set(colorHexToStr(rgbToHex(...sky.east_color))) + this.skySouth.set(colorHexToStr(rgbToHex(...sky.south_color))) + this.skyWest.set(colorHexToStr(rgbToHex(...sky.west_color))) + this.skyBottom.set(colorHexToStr(rgbToHex(...sky.bottom_color))) } private createSkybox( diff --git a/frontend/src/app/world/terrain.service.ts b/frontend/src/app/world/terrain.service.ts index aaed19e..2a92a6c 100644 --- a/frontend/src/app/world/terrain.service.ts +++ b/frontend/src/app/world/terrain.service.ts @@ -15,7 +15,7 @@ import {PlayerCollider} from '../engine/player-collider' import {EngineService} from '../engine/engine.service' import {PropService} from './prop.service' import {HttpService} from '../network' -import {TERRAIN_PAGE_SIZE, Utils} from '../utils' +import {rgbToHex, TERRAIN_PAGE_SIZE} from '../utils' export interface WaterData { enabled?: boolean @@ -58,7 +58,7 @@ export class TerrainService { this.water = new Group() this.water.name = 'water' this.water.userData.under_view = water.under_view ?? 120 - this.water.userData.color = Utils.rgbToHex( + this.water.userData.color = rgbToHex( ...((water?.color || [0, 255, 255]) as [number, number, number]) ) this.water.userData.texture_bottom = water.texture_bottom diff --git a/frontend/src/app/world/world.service.ts b/frontend/src/app/world/world.service.ts index 20cef7c..11b29a6 100644 --- a/frontend/src/app/world/world.service.ts +++ b/frontend/src/app/world/world.service.ts @@ -33,7 +33,7 @@ import type {AvatarAnimationManager} from '../animation' import type {Avatar, PropEntry} from '../network' import {HttpService} from '../network' import {environment} from '../../environments/environment' -import {DEG, Utils} from '../utils' +import {DEG, modelName, posToString, stringToPos} from '../utils' import {BuildService} from '../engine/build.service' import type {LightData} from './lighting.service' import {LightingService} from './lighting.service' @@ -267,10 +267,7 @@ export class WorldService { get playerLocation() { return { world: this.worldName, - position: Utils.posToString( - this.engineSvc.position[0], - this.engineSvc.yaw - ) + position: posToString(this.engineSvc.position[0], this.engineSvc.yaw) } } @@ -288,7 +285,7 @@ export class WorldService { desc: string | null = null, act: string | null = null ): Promise { - prop = Utils.modelName(prop) + prop = modelName(prop) const g = await firstValueFrom(this.propSvc.loadModel(prop)) g.name = prop g.userData.id = id @@ -329,7 +326,7 @@ export class WorldService { // User not within this world return } - name = Utils.modelName(name) + name = modelName(name) this.propSvc.loadAvatar(name).subscribe(async (o) => { o.rotation.copy(new Euler(0, Math.PI, 0)) group.parent!.updateMatrixWorld() @@ -540,7 +537,7 @@ export class WorldService { if (entry) { const yawMatch = /\s([-+]?[0-9]+)$/.exec(entry) entryYaw = yawMatch ? parseInt(yawMatch[1], 10) : entryYaw - entryPoint.copy(Utils.stringToPos(entry)) + entryPoint.copy(stringToPos(entry)) } // Load a few chunks on world initialization diff --git a/package-lock.json b/package-lock.json index 8163b66..47f8c9d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,17 +23,16 @@ "chevrotain": "^11.0.3" }, "devDependencies": { - "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.10.0", "@swc/core": "^1.9.3", - "@typescript-eslint/eslint-plugin": "^8.10.0", - "@typescript-eslint/parser": "^8.10.0", "@vitest/coverage-v8": "^2.1.6", "eslint": "^9.16.0", "globals": "^15.13.0", + "jiti": "^2.4.1", "prettier": "^3.4.1", "ts-node": "^10.9.2", "typescript": "^5.7.2", + "typescript-eslint": "^8.16.0", "unplugin-swc": "^1.5.1", "vitest": "^2.1.6" } @@ -67,8 +66,7 @@ "ws": "^8.18.0" }, "devDependencies": { - "@eslint/eslintrc": "^3.2.0", - "@eslint/js": "^9.13.0", + "@eslint/js": "^9.10.0", "@nestjs/cli": "^10.4.8", "@nestjs/schematics": "^10.2.3", "@nestjs/testing": "^10.4.12", @@ -77,13 +75,9 @@ "@types/node": "^20.17.7", "@types/supertest": "^6.0.2", "@types/ws": "^8.5.13", - "@typescript-eslint/eslint-plugin": "^8.10.0", - "@typescript-eslint/parser": "^8.10.0", "@vitest/coverage-v8": "^2.1.6", "eslint": "^9.16.0", - "eslint-config-prettier": "^9.1.0", - "eslint-plugin-prettier": "^5.2.1", - "globals": "^15.13.0", + "jiti": "^2.4.1", "prettier": "^3.4.1", "prisma": "^6.0.0", "source-map-support": "^0.5.21", @@ -92,6 +86,7 @@ "ts-node": "^10.9.2", "tsconfig-paths": "4.2.0", "typescript": "^5.7.2", + "typescript-eslint": "^8.16.0", "unplugin-swc": "^1.5.1", "vitest": "^2.1.6" } @@ -114,17 +109,15 @@ "ws": "^8.18.0" }, "devDependencies": { - "@eslint/eslintrc": "^3.2.0", "@eslint/js": "^9.10.0", "@types/node": "^20.17.7", "@types/ws": "^8.5.13", - "@typescript-eslint/eslint-plugin": "^8.10.0", - "@typescript-eslint/parser": "^8.10.0", "eslint": "^9.16.0", - "globals": "^15.13.0", + "jiti": "^2.4.1", "prettier": "^3.4.1", "ts-node": "^10.9.2", - "typescript": "^5.7.2" + "typescript": "^5.7.2", + "typescript-eslint": "^8.16.0" } }, "bot/node_modules/@types/node": { @@ -171,6 +164,7 @@ "@angular-devkit/build-angular": "^19.0.1", "@angular/cli": "^19.0.2", "@angular/compiler-cli": "^19.0.0", + "@eslint/js": "^9.10.0", "@types/node": "^20.17.7", "@types/three": "^0.170.0", "@types/webgl2": "^0.0.11", @@ -988,15 +982,6 @@ "url": "https://paulmillr.com/funding/" } }, - "node_modules/@angular-eslint/schematics/node_modules/ignore": { - "version": "6.0.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz", - "integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==", - "dev": true, - "engines": { - "node": ">= 4" - } - }, "node_modules/@angular-eslint/template-parser": { "version": "19.0.0", "resolved": "https://registry.npmjs.org/@angular-eslint/template-parser/-/template-parser-19.0.0.tgz", @@ -3323,6 +3308,28 @@ "node": "^18.18.0 || ^20.9.0 || >=21.1.0" } }, + "node_modules/@eslint/config-array/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/@eslint/config-array/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/core": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@eslint/core/-/core-0.9.0.tgz", @@ -3371,6 +3378,16 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/@eslint/eslintrc/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/@eslint/eslintrc/node_modules/globals": { "version": "14.0.0", "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", @@ -3383,12 +3400,33 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/@eslint/eslintrc/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/@eslint/eslintrc/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/@eslint/eslintrc/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/@eslint/js": { "version": "9.16.0", "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.16.0.tgz", @@ -5769,18 +5807,6 @@ "node": ">=14" } }, - "node_modules/@pkgr/core": { - "version": "0.1.1", - "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", - "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", - "dev": true, - "engines": { - "node": "^12.20.0 || ^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, "node_modules/@prisma/client": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/@prisma/client/-/client-6.0.0.tgz", @@ -6362,9 +6388,9 @@ } }, "node_modules/@swc/cli": { - "version": "0.5.1", - "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.5.1.tgz", - "integrity": "sha512-sxSXyjqFImYrqjhZSPymjmM/9V6auZG67UsDwbe7FZaBlyfW8ka3QG/zRjpJJ9+8Ahns/kKb8bXPKQq7V2MtBw==", + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/@swc/cli/-/cli-0.5.2.tgz", + "integrity": "sha512-ul2qIqjM5bfe9zWLqFDmHZCf9HXXSZZAlZLe4czn+lH4PewO+OWZnQcYCscnJKlbx6MuWjzXVR7gkspjNEJwJA==", "dev": true, "dependencies": { "@swc/counter": "^0.1.3", @@ -6372,7 +6398,7 @@ "commander": "^8.3.0", "fast-glob": "^3.2.5", "minimatch": "^9.0.3", - "piscina": "^4.3.0", + "piscina": "^4.3.1", "semver": "^7.3.8", "slash": "3.0.0", "source-map": "^0.7.3" @@ -6395,15 +6421,6 @@ } } }, - "node_modules/@swc/cli/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, "node_modules/@swc/cli/node_modules/commander": { "version": "8.3.0", "resolved": "https://registry.npmjs.org/commander/-/commander-8.3.0.tgz", @@ -6413,21 +6430,6 @@ "node": ">= 12" } }, - "node_modules/@swc/cli/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@swc/core": { "version": "1.9.3", "resolved": "https://registry.npmjs.org/@swc/core/-/core-1.9.3.tgz", @@ -6715,30 +6717,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/@tufjs/models/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@tufjs/models/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@tweenjs/tween.js": { "version": "23.1.3", "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz", @@ -7077,6 +7055,15 @@ } } }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/@typescript-eslint/parser": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-8.16.0.tgz", @@ -7190,30 +7177,6 @@ } } }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/@typescript-eslint/utils": { "version": "8.16.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-8.16.0.tgz", @@ -7283,9 +7246,9 @@ } }, "node_modules/@vitest/coverage-v8": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.6.tgz", - "integrity": "sha512-qItJVYDbG3MUFO68dOZUz+rWlqe9LMzotERXFXKg25s2A/kSVsyS9O0yNGrITfBd943GsnBeQZkBUu7Pc+zVeA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@vitest/coverage-v8/-/coverage-v8-2.1.7.tgz", + "integrity": "sha512-deQ4J+yu6nEjmEfcBndbgrRM95IZoRpV1dDVRbZhjUcgYVZz/Wc4YaLiDDt9Sy5qcikrJUZMlrUxDy7dBojebg==", "dev": true, "dependencies": { "@ampproject/remapping": "^2.3.0", @@ -7305,8 +7268,8 @@ "url": "https://opencollective.com/vitest" }, "peerDependencies": { - "@vitest/browser": "2.1.6", - "vitest": "2.1.6" + "@vitest/browser": "2.1.7", + "vitest": "2.1.7" }, "peerDependenciesMeta": { "@vitest/browser": { @@ -7315,13 +7278,13 @@ } }, "node_modules/@vitest/expect": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.6.tgz", - "integrity": "sha512-9M1UR9CAmrhJOMoSwVnPh2rELPKhYo0m/CSgqw9PyStpxtkwhmdM6XYlXGKeYyERY1N6EIuzkQ7e3Lm1WKCoUg==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@vitest/expect/-/expect-2.1.7.tgz", + "integrity": "sha512-folWk4qQDEedgUyvaZw94LIJuNLoDtY+rhKhhNy0csdwifn/pQz8EWVRnyrW3j0wMpy+xwJT8WiwiYxk+i+s7w==", "dev": true, "dependencies": { - "@vitest/spy": "2.1.6", - "@vitest/utils": "2.1.6", + "@vitest/spy": "2.1.7", + "@vitest/utils": "2.1.7", "chai": "^5.1.2", "tinyrainbow": "^1.2.0" }, @@ -7330,12 +7293,12 @@ } }, "node_modules/@vitest/mocker": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.6.tgz", - "integrity": "sha512-MHZp2Z+Q/A3am5oD4WSH04f9B0T7UvwEb+v5W0kCYMhtXGYbdyl2NUk1wdSMqGthmhpiThPDp/hEoVwu16+u1A==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@vitest/mocker/-/mocker-2.1.7.tgz", + "integrity": "sha512-nKMTnuJrarFH+7llWxeLmYRldIwTY3OM1DzdytHj0f2+fah6Cyk4XbswhjOiTCnAvXsZAEoo1OaD6rneSSU+3Q==", "dev": true, "dependencies": { - "@vitest/spy": "2.1.6", + "@vitest/spy": "2.1.7", "estree-walker": "^3.0.3", "magic-string": "^0.30.12" }, @@ -7344,7 +7307,7 @@ }, "peerDependencies": { "msw": "^2.4.9", - "vite": "^5.0.0 || ^6.0.0" + "vite": "^5.0.0" }, "peerDependenciesMeta": { "msw": { @@ -7365,9 +7328,9 @@ } }, "node_modules/@vitest/pretty-format": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.6.tgz", - "integrity": "sha512-exZyLcEnHgDMKc54TtHca4McV4sKT+NKAe9ix/yhd/qkYb/TP8HTyXRFDijV19qKqTZM0hPL4753zU/U8L/gAA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@vitest/pretty-format/-/pretty-format-2.1.7.tgz", + "integrity": "sha512-HoqRIyfQlXPrRDB43h0lC8eHPUDPwFweMaD6t+psOvwClCC+oZZim6wPMjuoMnRdiFxXqbybg/QbuewgTwK1vA==", "dev": true, "dependencies": { "tinyrainbow": "^1.2.0" @@ -7377,12 +7340,12 @@ } }, "node_modules/@vitest/runner": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.6.tgz", - "integrity": "sha512-SjkRGSFyrA82m5nz7To4CkRSEVWn/rwQISHoia/DB8c6IHIhaE/UNAo+7UfeaeJRE979XceGl00LNkIz09RFsA==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@vitest/runner/-/runner-2.1.7.tgz", + "integrity": "sha512-MrDNpXUIXksR57qipYh068SOX4N1hVw6oVILlTlfeTyA1rp0asuljyp15IZwKqhjpWLObFj+tiNrOM4R8UnSqg==", "dev": true, "dependencies": { - "@vitest/utils": "2.1.6", + "@vitest/utils": "2.1.7", "pathe": "^1.1.2" }, "funding": { @@ -7390,12 +7353,12 @@ } }, "node_modules/@vitest/snapshot": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.6.tgz", - "integrity": "sha512-5JTWHw8iS9l3v4/VSuthCndw1lN/hpPB+mlgn1BUhFbobeIUj1J1V/Bj2t2ovGEmkXLTckFjQddsxS5T6LuVWw==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@vitest/snapshot/-/snapshot-2.1.7.tgz", + "integrity": "sha512-OioIxV/xS393DKdlkRNhmtY0K37qVdCv8w1M2SlLTBSX+fNK6zgcd01VlT1nXdbKVDaB8Zb6BOfQYYoGeGTEGg==", "dev": true, "dependencies": { - "@vitest/pretty-format": "2.1.6", + "@vitest/pretty-format": "2.1.7", "magic-string": "^0.30.12", "pathe": "^1.1.2" }, @@ -7404,9 +7367,9 @@ } }, "node_modules/@vitest/spy": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.6.tgz", - "integrity": "sha512-oTFObV8bd4SDdRka5O+mSh5w9irgx5IetrD5i+OsUUsk/shsBoHifwCzy45SAORzAhtNiprUVaK3hSCCzZh1jQ==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@vitest/spy/-/spy-2.1.7.tgz", + "integrity": "sha512-e5pzIaIC0LBrb/j1FaF7HXlPJLGtltiAkwXTMqNEHALJc7USSLEwziJ+aIWTmjsWNg89zazg37h7oZITnublsQ==", "dev": true, "dependencies": { "tinyspy": "^3.0.2" @@ -7416,12 +7379,12 @@ } }, "node_modules/@vitest/utils": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.6.tgz", - "integrity": "sha512-ixNkFy3k4vokOUTU2blIUvOgKq/N2PW8vKIjZZYsGJCMX69MRa9J2sKqX5hY/k5O5Gty3YJChepkqZ3KM9LyIQ==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/@vitest/utils/-/utils-2.1.7.tgz", + "integrity": "sha512-7gUdvIzCCuIrMZu0WHTvDJo8C1NsUtOqmwmcS3bRHUcfHemj29wmkzLVNuWQD7WHoBD/+I7WIgrnzt7kxR54ow==", "dev": true, "dependencies": { - "@vitest/pretty-format": "2.1.6", + "@vitest/pretty-format": "2.1.7", "loupe": "^3.1.2", "tinyrainbow": "^1.2.0" }, @@ -8484,13 +8447,11 @@ "dev": true }, "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "balanced-match": "^1.0.0" } }, "node_modules/braces": { @@ -8796,9 +8757,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001684", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001684.tgz", - "integrity": "sha512-G1LRwLIQjBQoyq0ZJGqGIJUXzJ8irpbjHLpVRXDvBEScFJ9b17sgK6vlx0GAJFE21okD7zXl08rRRUfq6HdoEQ==", + "version": "1.0.30001685", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001685.tgz", + "integrity": "sha512-e/kJN1EMyHQzgcMEEgoo+YTCO1NGCmIYHk5Qk8jT6AazWemS5QFKJ5ShCJlH3GZrNIdZofcNCEwZqbMjjKzmnA==", "dev": true, "funding": [ { @@ -10122,48 +10083,6 @@ } } }, - "node_modules/eslint-config-prettier": { - "version": "9.1.0", - "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", - "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", - "dev": true, - "bin": { - "eslint-config-prettier": "bin/cli.js" - }, - "peerDependencies": { - "eslint": ">=7.0.0" - } - }, - "node_modules/eslint-plugin-prettier": { - "version": "5.2.1", - "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.2.1.tgz", - "integrity": "sha512-gH3iR3g4JfF+yYPaJYkN7jEl9QbweL/YfkoRlNnuIEHEz1vHVlCmWOS+eGGiRuzHQXdJFCOTxRgvju9b8VUmrw==", - "dev": true, - "dependencies": { - "prettier-linter-helpers": "^1.0.0", - "synckit": "^0.9.1" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/eslint-plugin-prettier" - }, - "peerDependencies": { - "@types/eslint": ">=8.0.0", - "eslint": ">=8.0.0", - "eslint-config-prettier": "*", - "prettier": ">=3.0.0" - }, - "peerDependenciesMeta": { - "@types/eslint": { - "optional": true - }, - "eslint-config-prettier": { - "optional": true - } - } - }, "node_modules/eslint-scope": { "version": "8.2.0", "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-8.2.0.tgz", @@ -10208,6 +10127,16 @@ "url": "https://github.com/sponsors/epoberezkin" } }, + "node_modules/eslint/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/eslint/node_modules/eslint-visitor-keys": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz", @@ -10232,12 +10161,33 @@ "node": ">=10.13.0" } }, + "node_modules/eslint/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/eslint/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/eslint/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/espree": { "version": "10.3.0", "resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz", @@ -10547,12 +10497,6 @@ "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" }, - "node_modules/fast-diff": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", - "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", - "dev": true - }, "node_modules/fast-fifo": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz", @@ -11051,12 +10995,34 @@ "ajv": "^6.9.1" } }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/json-schema-traverse": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", "dev": true }, + "node_modules/fork-ts-checker-webpack-plugin/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/fork-ts-checker-webpack-plugin/node_modules/schema-utils": { "version": "3.3.0", "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", @@ -11299,28 +11265,6 @@ "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==", "dev": true }, - "node_modules/glob/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/glob/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/globals": { "version": "15.13.0", "resolved": "https://registry.npmjs.org/globals/-/globals-15.13.0.tgz", @@ -11353,6 +11297,15 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globby/node_modules/ignore": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", + "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, "node_modules/globby/node_modules/path-type": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/path-type/-/path-type-5.0.0.tgz", @@ -11796,9 +11749,9 @@ ] }, "node_modules/ignore": { - "version": "5.3.2", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", - "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-6.0.2.tgz", + "integrity": "sha512-InwqeHHN2XpumIkMvpl/DCJVrAHgCsG5+cn1XlnLWGwtZBm8QJfSusItfrwx81CTp5agNZqpKU2J/ccC5nGT4A==", "dev": true, "engines": { "node": ">= 4" @@ -11816,30 +11769,6 @@ "node": "^18.17.0 || >=20.5.0" } }, - "node_modules/ignore-walk/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/ignore-walk/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/image-size": { "version": "0.5.5", "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", @@ -12325,12 +12254,12 @@ } }, "node_modules/jiti": { - "version": "1.21.6", - "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", - "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-2.4.1.tgz", + "integrity": "sha512-yPBThwecp1wS9DmoA4x4KR2h3QoslacnDR8ypuFM962kI4/456Iy1oHx2RAgh4jfZNdn0bctsdadceiBUgpU1g==", "dev": true, "bin": { - "jiti": "bin/jiti.js" + "jiti": "lib/jiti-cli.mjs" } }, "node_modules/joycon": { @@ -13540,15 +13469,17 @@ "dev": true }, "node_modules/minimatch": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", - "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", - "dev": true, + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", "dependencies": { - "brace-expansion": "^1.1.7" + "brace-expansion": "^2.0.1" }, "engines": { - "node": "*" + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" } }, "node_modules/minimist": { @@ -15169,6 +15100,15 @@ } } }, + "node_modules/postcss-loader/node_modules/jiti": { + "version": "1.21.6", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.6.tgz", + "integrity": "sha512-2yTgeWTWzMWkHu6Jp9NKgePDaYHbntiwvYuuJLbbN9vl7DC9DvXKOB2BC3ZZ92D3cvV/aflH0osDfwpHepQ53w==", + "dev": true, + "bin": { + "jiti": "bin/jiti.js" + } + }, "node_modules/postcss-media-query-parser": { "version": "0.2.3", "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", @@ -15277,18 +15217,6 @@ "url": "https://github.com/prettier/prettier?sponsor=1" } }, - "node_modules/prettier-linter-helpers": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", - "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", - "dev": true, - "dependencies": { - "fast-diff": "^1.1.2" - }, - "engines": { - "node": ">=6.0.0" - } - }, "node_modules/prisma": { "version": "6.0.0", "resolved": "https://registry.npmjs.org/prisma/-/prisma-6.0.0.tgz", @@ -15783,6 +15711,16 @@ "rimraf": "bin.js" } }, + "node_modules/rimraf/node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, "node_modules/rimraf/node_modules/glob": { "version": "7.2.3", "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", @@ -15804,6 +15742,18 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/rimraf/node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, "node_modules/rollup": { "version": "4.26.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.26.0.tgz", @@ -16937,22 +16887,6 @@ "node": ">=0.10" } }, - "node_modules/synckit": { - "version": "0.9.2", - "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.9.2.tgz", - "integrity": "sha512-vrozgXDQwYO72vHjUb/HnFbQx1exDjoKzqx23aXEg2a9VIg2TSFZ8FmeZpTjUCFMYw7mpX4BE2SFu8wI7asYsw==", - "dev": true, - "dependencies": { - "@pkgr/core": "^0.1.0", - "tslib": "^2.6.2" - }, - "engines": { - "node": "^14.18.0 || >=16.0.0" - }, - "funding": { - "url": "https://opencollective.com/unts" - } - }, "node_modules/tapable": { "version": "2.2.1", "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", @@ -17150,30 +17084,6 @@ "node": ">=18" } }, - "node_modules/test-exclude/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "node_modules/test-exclude/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "dev": true, - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "node_modules/text-decoder": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/text-decoder/-/text-decoder-1.2.1.tgz", @@ -17991,16 +17901,16 @@ } }, "node_modules/vite-node": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.6.tgz", - "integrity": "sha512-DBfJY0n9JUwnyLxPSSUmEePT21j8JZp/sR9n+/gBwQU6DcQOioPdb8/pibWfXForbirSagZCilseYIwaL3f95A==", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/vite-node/-/vite-node-2.1.7.tgz", + "integrity": "sha512-b/5MxSWd0ftWt1B1LHfzCw0ASzaxHztUwP0rcsBhkDSGy9ZDEDieSIjFG3I78nI9dUN0eSeD6LtuKPZGjwwpZQ==", "dev": true, "dependencies": { "cac": "^6.7.14", "debug": "^4.3.7", "es-module-lexer": "^1.5.4", "pathe": "^1.1.2", - "vite": "^5.0.0 || ^6.0.0" + "vite": "^5.0.0" }, "bin": { "vite-node": "vite-node.mjs" @@ -18419,18 +18329,18 @@ } }, "node_modules/vitest": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.6.tgz", - "integrity": "sha512-isUCkvPL30J4c5O5hgONeFRsDmlw6kzFEdLQHLezmDdKQHy8Ke/B/dgdTMEgU0vm+iZ0TjW8GuK83DiahBoKWQ==", - "dev": true, - "dependencies": { - "@vitest/expect": "2.1.6", - "@vitest/mocker": "2.1.6", - "@vitest/pretty-format": "^2.1.6", - "@vitest/runner": "2.1.6", - "@vitest/snapshot": "2.1.6", - "@vitest/spy": "2.1.6", - "@vitest/utils": "2.1.6", + "version": "2.1.7", + "resolved": "https://registry.npmjs.org/vitest/-/vitest-2.1.7.tgz", + "integrity": "sha512-wzJ7Wri44ufkzTZbI1lHsdHfiGdFRmnJ9qIudDQ6tknjJeHhF5QgNSSjk7KRZUU535qEiEXFJ7tSHqyzyIv0jQ==", + "dev": true, + "dependencies": { + "@vitest/expect": "2.1.7", + "@vitest/mocker": "2.1.7", + "@vitest/pretty-format": "^2.1.7", + "@vitest/runner": "2.1.7", + "@vitest/snapshot": "2.1.7", + "@vitest/spy": "2.1.7", + "@vitest/utils": "2.1.7", "chai": "^5.1.2", "debug": "^4.3.7", "expect-type": "^1.1.0", @@ -18441,8 +18351,8 @@ "tinyexec": "^0.3.1", "tinypool": "^1.0.1", "tinyrainbow": "^1.2.0", - "vite": "^5.0.0 || ^6.0.0", - "vite-node": "2.1.6", + "vite": "^5.0.0", + "vite-node": "2.1.7", "why-is-node-running": "^2.3.0" }, "bin": { @@ -18457,8 +18367,8 @@ "peerDependencies": { "@edge-runtime/vm": "*", "@types/node": "^18.0.0 || ^20.0.0 || >=22.0.0", - "@vitest/browser": "2.1.6", - "@vitest/ui": "2.1.6", + "@vitest/browser": "2.1.7", + "@vitest/ui": "2.1.7", "happy-dom": "*", "jsdom": "*" }, @@ -18614,9 +18524,9 @@ } }, "node_modules/webpack-dev-middleware/node_modules/memfs": { - "version": "4.14.0", - "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.14.0.tgz", - "integrity": "sha512-JUeY0F/fQZgIod31Ja1eJgiSxLn7BfQlCnqhwXFBzFHEw63OdLK7VJUJ7bnzNsWgCyoUP5tEp1VRY8rDaYzqOA==", + "version": "4.14.1", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-4.14.1.tgz", + "integrity": "sha512-Fq5CMEth+2iprLJ5mNizRcWuiwRZYjNkUD0zKk224jZunE9CRacTRDK8QLALbMBlNX2y3nY6lKZbesCwDwacig==", "dev": true, "dependencies": { "@jsonjoy.com/json-pack": "^1.0.3",