From b282db4fc1bc40498914b6444caab83e16496b3d Mon Sep 17 00:00:00 2001 From: Zoe Date: Wed, 25 Sep 2024 08:11:30 -0500 Subject: [PATCH] Internals upgrades (primary pr) (#65) * drop prometheus * moving more stuff to peer deps * more rm * fixing esm compat * lint fixes * lint fixes * test fixes * start on als * wiring * export testing helpers * refactoring tets to use test runner * test coverage for config * lint * checkpoint * refactoring wiring tests * logger tests * working on tests * lint * tests * check * prettier adjustment & moving tests * module builder * sleep teardown * tweaks * tests * perf hooks * comments * upgrades & lint * measurement fixes * als tweaks * test fixing * more test coverage --- .eslintignore | 1 - .eslintrc.json | 128 - .prettierrc | 7 + README.md | 5 +- eslint.config.mjs | 152 + package.json | 100 +- scripts/test.sh | 2 +- src/extensions/cache.extension.ts | 114 - src/extensions/configuration.extension.ts | 220 - src/extensions/fetch.extension.ts | 215 - src/extensions/logger.extension.ts | 272 - src/extensions/metrics.extension.ts | 170 - src/extensions/scheduler.extension.ts | 204 - src/helpers/async.helper.ts | 14 +- src/helpers/cache-memory.helper.ts | 66 - src/helpers/cache-redis.helper.ts | 73 - src/helpers/cache.helper.ts | 26 - .../config-environment-loader.helper.ts | 6 +- src/helpers/config-file-loader.helper.ts | 22 +- src/helpers/config.helper.ts | 113 +- src/helpers/cron.helper.ts | 33 + src/helpers/errors.helper.ts | 28 - src/helpers/events.helper.ts | 10 +- src/helpers/extend.helper.ts | 15 +- src/helpers/fetch.helper.ts | 355 -- src/helpers/index.ts | 6 +- src/helpers/lifecycle.helper.ts | 12 +- src/helpers/logger.helper.ts | 79 + src/helpers/module.helper.ts | 239 + src/helpers/utilities.helper.ts | 36 +- src/helpers/wiring.helper.ts | 243 +- src/index.ts | 3 +- src/services/als.extension.ts | 19 + src/services/configuration.extension.ts | 175 + src/{extensions => services}/index.ts | 4 +- .../internal.extension.ts | 124 +- src/{extensions => services}/is.extension.ts | 14 +- .../lifecycle.extension.ts | 44 +- src/services/logger.extension.ts | 276 + src/services/scheduler.extension.ts | 142 + .../wiring.extension.ts | 381 +- src/testing/cache.spec.ts | 343 -- src/testing/config-testing.extension.ts | 135 - src/testing/configuration.spec.ts | 649 -- src/testing/fetch.spec.ts | 452 -- src/testing/helpers/test-main.ts | 44 - src/testing/{helpers => }/index.ts | 1 + src/testing/internal.spec.ts | 175 - src/testing/logger.spec.ts | 196 - src/testing/{helpers => }/mock-logger.ts | 2 +- src/testing/scheduler.spec.ts | 59 - src/testing/test-module.ts | 309 + src/testing/testing.helper.ts | 27 - src/testing/utilities.spec.ts | 104 - src/testing/wiring.spec.ts | 1236 ---- testing/als.spec.ts | 10 + testing/configuration.spec.ts | 820 +++ testing/internal.spec.ts | 248 + {src/testing => testing}/is.spec.ts | 13 +- testing/logger.spec.ts | 168 + testing/scheduler.spec.ts | 56 + testing/setup.ts | 4 + testing/testing.spec.ts | 315 + testing/utilities.spec.ts | 277 + testing/wiring.spec.ts | 905 +++ tsconfig.json | 20 +- tsconfig.lib.json | 4 +- tsconfig.spec.json | 19 +- yarn.lock | 5473 ++++++++++------- 69 files changed, 7982 insertions(+), 8230 deletions(-) delete mode 100644 .eslintignore delete mode 100644 .eslintrc.json create mode 100644 .prettierrc create mode 100644 eslint.config.mjs delete mode 100644 src/extensions/cache.extension.ts delete mode 100644 src/extensions/configuration.extension.ts delete mode 100644 src/extensions/fetch.extension.ts delete mode 100644 src/extensions/logger.extension.ts delete mode 100644 src/extensions/metrics.extension.ts delete mode 100644 src/extensions/scheduler.extension.ts delete mode 100644 src/helpers/cache-memory.helper.ts delete mode 100644 src/helpers/cache-redis.helper.ts delete mode 100644 src/helpers/cache.helper.ts delete mode 100644 src/helpers/fetch.helper.ts create mode 100644 src/helpers/logger.helper.ts create mode 100644 src/helpers/module.helper.ts create mode 100644 src/services/als.extension.ts create mode 100644 src/services/configuration.extension.ts rename src/{extensions => services}/index.ts (67%) rename src/{extensions => services}/internal.extension.ts (68%) rename src/{extensions => services}/is.extension.ts (85%) rename src/{extensions => services}/lifecycle.extension.ts (63%) create mode 100644 src/services/logger.extension.ts create mode 100644 src/services/scheduler.extension.ts rename src/{extensions => services}/wiring.extension.ts (56%) delete mode 100644 src/testing/cache.spec.ts delete mode 100644 src/testing/config-testing.extension.ts delete mode 100644 src/testing/configuration.spec.ts delete mode 100644 src/testing/fetch.spec.ts delete mode 100644 src/testing/helpers/test-main.ts rename src/testing/{helpers => }/index.ts (50%) delete mode 100644 src/testing/internal.spec.ts delete mode 100644 src/testing/logger.spec.ts rename src/testing/{helpers => }/mock-logger.ts (81%) delete mode 100644 src/testing/scheduler.spec.ts create mode 100644 src/testing/test-module.ts delete mode 100644 src/testing/testing.helper.ts delete mode 100644 src/testing/utilities.spec.ts delete mode 100644 src/testing/wiring.spec.ts create mode 100644 testing/als.spec.ts create mode 100644 testing/configuration.spec.ts create mode 100644 testing/internal.spec.ts rename {src/testing => testing}/is.spec.ts (93%) create mode 100644 testing/logger.spec.ts create mode 100644 testing/scheduler.spec.ts create mode 100644 testing/setup.ts create mode 100644 testing/testing.spec.ts create mode 100644 testing/utilities.spec.ts create mode 100644 testing/wiring.spec.ts diff --git a/.eslintignore b/.eslintignore deleted file mode 100644 index eff5823..0000000 --- a/.eslintignore +++ /dev/null @@ -1 +0,0 @@ -# node_modules diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 8e0aaf9..0000000 --- a/.eslintrc.json +++ /dev/null @@ -1,128 +0,0 @@ -{ - "env": { - "es6": true, - "node": true - }, - "plugins": [ - "import", - "jsonc", - "no-unsanitized", - "sonarjs", - "simple-import-sort", - "sort-keys-fix", - "unicorn", - "prettier" - ], - "overrides": [ - { - "files": [ - "src/**/*.ts" - ], - "extends": [ - "plugin:@typescript-eslint/recommended", - "plugin:jsonc/recommended-with-jsonc", - "plugin:sonarjs/recommended", - "plugin:unicorn/recommended", - "plugin:prettier/recommended", - "plugin:@cspell/recommended" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": [ - "tsconfig.json" - ] - }, - "rules": { - "prettier/prettier": "error", - "unicorn/switch-case-braces": "off", - "unicorn/prefer-module": "off", - "@typescript-eslint/no-magic-numbers": "warn", - "unicorn/no-object-as-default-parameter": "off", - "@cspell/spellchecker": ["warn", { "checkComments": false, "autoFix": true }], - "unicorn/no-null": "off", - "unicorn/no-empty-file": "off", - "sonarjs/prefer-single-boolean-return": "off", - "unicorn/no-array-callback-reference": "off", - "unicorn/no-await-expression-member": "off", - "unicorn/no-useless-undefined": "off", - "@typescript-eslint/unbound-method": "error", - "import/no-extraneous-dependencies": [ - "error", - { - "packageDir": "./" - } - ], - "sonarjs/prefer-immediate-return": "off", - "unicorn/prevent-abbreviations": [ - "error", - { - "replacements": { - "docs": false, - "e": false, - "dir": false, - "i": false, - "params": false, - "props": false, - "ref": false, - "temp": false - } - } - ], - "no-case-declarations": "off", - "no-async-promise-executor": "off", - "unicorn/prefer-node-protocol": "off", - "unicorn/no-array-for-each": "off", - "unicorn/import-style": "off", - "sort-keys-fix/sort-keys-fix": "warn", - "unicorn/prefer-event-target": "off", - "simple-import-sort/imports": "warn", - "simple-import-sort/exports": "warn", - "no-console": [ - "error" - ], - "@typescript-eslint/no-unnecessary-type-constraint": "off", - "@typescript-eslint/no-unused-vars": [ - "warn", - { - "varsIgnorePattern": "_|logger" - } - ], - "@typescript-eslint/no-explicit-any": "error" - } - }, - { - "files": ["src/**/*.spec.ts"], - "env": { - "jest": true - }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": [ - "tsconfig.spec.json" - ] - }, - "rules": { - "@typescript-eslint/unbound-method": "off", - "@typescript-eslint/no-magic-numbers": "off", - "sonarjs/no-duplicate-string": "off", - "sonarjs/no-unused-collection": "warn", - "unicorn/consistent-function-scoping": "off" - } - }, - { - "files": [ - "metrics.helper.ts", - "*.module.ts" - ], - "parser": "@typescript-eslint/parser", - "parserOptions": { - "project": [ - "tsconfig.json" - ] - }, - "rules": { - "@typescript-eslint/no-magic-numbers": "off" - } - } - ] -} diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..4d8124d --- /dev/null +++ b/.prettierrc @@ -0,0 +1,7 @@ +{ + "singleQuote": false, + "trailingComma": "all", + "jsxSingleQuote": false, + "printWidth": 100, + "arrowParens": "avoid" +} diff --git a/README.md b/README.md index 675fcbd..c9b1e5e 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ -[![codecov](https://codecov.io/github/Digital-Alchemy-TS/core/graph/badge.svg?token=IBGLY3RY68)](https://codecov.io/github/Digital-Alchemy-TS/core) +[![stars](https://img.shields.io/github/stars/Digital-Alchemy-TS/core)](https://github.com/Digital-Alchemy-TS/core) +![discord](https://img.shields.io/discord/1219758743848489147?label=Discord&logo=discord) +[![codecov](https://codecov.io/github/Digital-Alchemy-TS/core/graph/badge.svg?token=IBGLY3RY68)](https://codecov.io/github/Digital-Alchemy-TS/core) +[![version](https://img.shields.io/github/package-json/version/Digital-Alchemy-TS/core)](https://www.npmjs.com/package/@digital-alchemy/core) --- # 🚀 Project Overview - Digital Alchemy TypeScript Libraries diff --git a/eslint.config.mjs b/eslint.config.mjs new file mode 100644 index 0000000..d83f53c --- /dev/null +++ b/eslint.config.mjs @@ -0,0 +1,152 @@ +import importPlugin from "eslint-plugin-import"; +import jsonc from "eslint-plugin-jsonc"; +import noUnsanitized from "eslint-plugin-no-unsanitized"; +import simpleImportSort from "eslint-plugin-simple-import-sort"; +import sortKeysFix from "eslint-plugin-sort-keys-fix"; +import unicorn from "eslint-plugin-unicorn"; +import prettier from "eslint-plugin-prettier"; +import { fixupPluginRules } from "@eslint/compat"; +import globals from "globals"; +import tsParser from "@typescript-eslint/parser"; +import sonarjs from "eslint-plugin-sonarjs"; +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 [ + sonarjs.configs.recommended, + { + plugins: { + import: fixupPluginRules(importPlugin), + jsonc, + "no-unsanitized": noUnsanitized, + "simple-import-sort": simpleImportSort, + "sort-keys-fix": sortKeysFix, + unicorn, + prettier, + }, + languageOptions: { + globals: { ...globals.node }, + }, + }, + ...compat + .extends( + "plugin:@typescript-eslint/recommended", + "plugin:jsonc/recommended-with-jsonc", + "plugin:unicorn/recommended", + "plugin:prettier/recommended", + "plugin:@cspell/recommended", + ) + .map(config => ({ ...config, files: ["src/**/*.ts", "testing/**/*.ts"] })), + + // everything + { + files: ["src/**/*.ts", "testing/**/*.ts"], + languageOptions: { + parser: tsParser, + ecmaVersion: 5, + sourceType: "script", + parserOptions: { + project: ["tsconfig.json"], + }, + }, + rules: { + "prettier/prettier": "error", + "unicorn/switch-case-braces": "off", + "unicorn/prefer-module": "off", + "@typescript-eslint/no-magic-numbers": "warn", + "unicorn/no-object-as-default-parameter": "off", + "@cspell/spellchecker": ["warn", { checkComments: false, autoFix: true }], + "unicorn/no-null": "off", + "unicorn/no-empty-file": "off", + "sonarjs/sonar-no-fallthrough": "off", + "sonarjs/prefer-single-boolean-return": "off", + "unicorn/no-array-callback-reference": "off", + "sonarjs/prefer-nullish-coalescing": "off", + "unicorn/no-await-expression-member": "off", + "sonarjs/no-invalid-await": "off", + "sonarjs/no-nested-functions": "off", + "unicorn/no-useless-undefined": "off", + "@typescript-eslint/unbound-method": "error", + "import/no-extraneous-dependencies": ["error", { packageDir: "./" }], + "sonarjs/prefer-immediate-return": "off", + "unicorn/prevent-abbreviations": [ + "error", + { + replacements: { + docs: false, + e: false, + dir: false, + i: false, + params: false, + props: false, + ref: false, + temp: false, + }, + }, + ], + "no-case-declarations": "off", + "no-async-promise-executor": "off", + "unicorn/prefer-node-protocol": "off", + "unicorn/no-array-for-each": "off", + "unicorn/import-style": "off", + "sort-keys-fix/sort-keys-fix": "warn", + "unicorn/prefer-event-target": "off", + "simple-import-sort/imports": "warn", + "sonarjs/no-misused-promises": "off", + "sonarjs/no-commented-code": "off", + "sonarjs/todo-tag": "off", + "simple-import-sort/exports": "warn", + "no-console": ["error"], + "@typescript-eslint/no-unnecessary-type-constraint": "off", + "@typescript-eslint/no-unused-vars": ["warn", { varsIgnorePattern: "_|logger" }], + "@typescript-eslint/no-explicit-any": "error", + }, + }, + // tests + { + files: ["testing/**/*.ts"], + languageOptions: { + globals: { ...globals.jest }, + parser: tsParser, + ecmaVersion: 5, + sourceType: "script", + parserOptions: { + project: ["tsconfig.spec.json"], + }, + }, + rules: { + "@typescript-eslint/unbound-method": "off", + "@typescript-eslint/no-magic-numbers": "off", + "sonarjs/no-duplicate-string": "off", + "sonarjs/no-commented-code": "off", + "sonarjs/no-dead-store": "off", + "sonarjs/no-unused-collection": "warn", + "unicorn/consistent-function-scoping": "off", + }, + }, + // module definitions + { + files: ["src/**/*.module.ts"], + languageOptions: { + parser: tsParser, + ecmaVersion: 5, + sourceType: "script", + parserOptions: { + project: ["tsconfig.json"], + }, + }, + rules: { + "@typescript-eslint/no-magic-numbers": "off", + }, + }, +]; diff --git a/package.json b/package.json index 5e4c874..9caf869 100644 --- a/package.json +++ b/package.json @@ -1,10 +1,11 @@ { + "type": "module", "name": "@digital-alchemy/core", "description": "Application wiring, configuration, and boilerplate utilities", "repository": { "url": "git+https://github.com/Digital-Alchemy-TS/core" }, - "version": "24.9.1", + "version": "24.9.3", "author": { "url": "https://github.com/zoe-codez", "name": "Zoe Codez" @@ -33,14 +34,11 @@ { "url": "https://github.com/sponsors/zoe-codez", "type": "GitHub" - }, - { - "url": "https://ko-fi.com/zoe_codez", - "type": "ko-fi" } ], "exports": { - ".": "./dist/index.js" + ".": "./dist/index.js", + "./testing": "./dist/testing/helpers/index.js" }, "files": [ "dist/**/*" @@ -48,56 +46,68 @@ "engines": { "node": ">=20" }, - "dependencies": { - "chalk": "^5.3.0", - "dayjs": "^1.11.11", - "dotenv": "^16.4.5", - "ini": "^4.1.3", - "js-yaml": "^4.1.0", - "minimist": "^1.2.8", - "node-cache": "^5.1.2", - "node-cron": "^3.0.3", - "prom-client": "^15.1.2" - }, - "optionalDependencies": { - "redis": "^4.6.14" + "peerDependencies": { + "chalk": "^5", + "dayjs": "^1", + "dotenv": "^16", + "ini": "^4", + "js-yaml": "^4", + "minimist": "^1", + "node-cron": "^3", + "uuid": "*" }, "devDependencies": { - "@cspell/eslint-plugin": "^8.9.1", - "@faker-js/faker": "^8.4.1", + "@cspell/eslint-plugin": "^8.14.4", + "@eslint/compat": "^1.1.1", + "@eslint/eslintrc": "^3.1.0", + "@eslint/js": "^9.10.0", + "@faker-js/faker": "^9.0.1", + "@jest/globals": "^29.7.0", "@types/dotenv": "^8.2.0", "@types/ini": "^4.1.1", - "@types/jest": "^29.5.12", + "@types/jest": "^29.5.13", "@types/js-yaml": "^4.0.9", "@types/minimist": "^1.2.5", - "@types/node": "^20.14.8", + "@types/node": "^22.5.5", "@types/node-cron": "^3.0.11", "@types/semver": "^7.5.8", "@types/sinonjs__fake-timers": "^8.1.5", - "@typescript-eslint/eslint-plugin": "7.3.1", - "@typescript-eslint/parser": "7.3.1", - "eslint": "8.57.0", + "@types/uuid": "^10.0.0", + "@typescript-eslint/eslint-plugin": "8.6.0", + "@typescript-eslint/parser": "8.6.0", + "chalk": "^5.3.0", + "dayjs": "^1.11.13", + "dotenv": "^16.4.5", + "eslint": "9.10.0", "eslint-config-prettier": "9.1.0", - "eslint-plugin-import": "^2.29.1", - "eslint-plugin-jsonc": "^2.14.1", - "eslint-plugin-no-unsanitized": "^4.0.2", - "eslint-plugin-prettier": "^5.1.3", - "eslint-plugin-security": "^2.1.1", - "eslint-plugin-simple-import-sort": "^12.0.0", - "eslint-plugin-sonarjs": "^0.24.0", + "eslint-plugin-import": "^2.30.0", + "eslint-plugin-jsonc": "^2.16.0", + "eslint-plugin-no-unsanitized": "^4.1.0", + "eslint-plugin-prettier": "^5.2.1", + "eslint-plugin-security": "^3.0.1", + "eslint-plugin-simple-import-sort": "^12.1.1", + "eslint-plugin-sonarjs": "^2.0.2", "eslint-plugin-sort-keys-fix": "^1.1.2", - "eslint-plugin-unicorn": "^51.0.1", + "eslint-plugin-unicorn": "^55.0.0", + "globals": "^15.9.0", + "ini": "^5.0.0", "jest": "^29.7.0", "jest-environment-node": "^29.7.0", - "npm-check-updates": "^16.14.20", - "prettier": "^3.3.2", - "ts-jest": "^29.1.5", - "tslib": "^2.6.3", - "tsx": "^4.15.7", - "type-fest": "^4.20.1", - "typescript": "^5.5.2" + "js-yaml": "^4.1.0", + "minimist": "^1.2.8", + "node-cron": "^3.0.3", + "prettier": "^3.3.3", + "ts-jest": "^29.2.5", + "tslib": "^2.7.0", + "tsx": "^4.19.1", + "type-fest": "^4.26.1", + "typescript": "^5.6.2", + "uuid": "^10.0.0" }, "jest": { + "extensionsToTreatAsEsm": [ + ".ts" + ], "collectCoverage": true, "coverageReporters": [ "text", @@ -117,14 +127,18 @@ "testMatch": [ "**/?(*.)+(spec|test).ts" ], + "setupFiles": [ + "/testing/setup.ts" + ], "transform": { "^.+\\.ts$": [ "ts-jest", { - "tsconfig": "tsconfig.spec.json" + "tsconfig": "tsconfig.spec.json", + "useESM": true } ] } }, - "packageManager": "yarn@4.3.1" + "packageManager": "yarn@4.5.0" } diff --git a/scripts/test.sh b/scripts/test.sh index ce574a7..13757ee 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -1,2 +1,2 @@ #!/bin/bash -NODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules" npx jest --pass-with-no-tests "$1" +NODE_OPTIONS="$NODE_OPTIONS --experimental-vm-modules" npx jest --pass-with-no-tests --runInBand "$1" diff --git a/src/extensions/cache.extension.ts b/src/extensions/cache.extension.ts deleted file mode 100644 index 58610bf..0000000 --- a/src/extensions/cache.extension.ts +++ /dev/null @@ -1,114 +0,0 @@ -import { - createMemoryDriver, - createRedisDriver, - ICacheDriver, - NONE, - TCache, - TServiceParams, -} from ".."; -import { is } from "."; - -export function Cache({ - logger, - lifecycle, - config, - internal, -}: TServiceParams): TCache { - let client: ICacheDriver; - const prefix = () => - config.boilerplate.CACHE_PREFIX || internal.boot.application.name; - - function fullKeyName(key: string): string { - return `${config.boilerplate.CACHE_PREFIX}${key}`; - } - - // #MARK: onPostConfig - lifecycle.onPostConfig(async () => { - if (client) { - return; - } - logger.trace( - { name: "onPostConfig", provider: config.boilerplate.CACHE_PROVIDER }, - `init cache`, - ); - if (config.boilerplate.CACHE_PROVIDER === "redis") { - client = await createRedisDriver({ config, internal, lifecycle, logger }); - return; - } - client = await createMemoryDriver({ config, internal, lifecycle, logger }); - }); - - // #MARK: Return object - return { - [Symbol.for("cache_logger")]: logger, - del: async (key: string): Promise => { - try { - const fullKey = fullKeyName(key); - await client.del(fullKey); - internal.boilerplate.metrics.CACHE_DELETE_OPERATIONS_TOTAL.inc({ - key: fullKey, - prefix: prefix(), - }); - } catch (error) { - internal.boilerplate.metrics.CACHE_DRIVER_ERROR_COUNT.labels( - "del", - ).inc(); - logger.error({ error, name: "del" }, `cache error`); - } - }, - get: async (key: string, defaultValue?: T): Promise => { - try { - const fullKey = fullKeyName(key); - const result = await client.get(fullKey); - internal.boilerplate.metrics.CACHE_GET_OPERATIONS_TOTAL.inc({ - hit_miss: is.undefined(result) ? "miss" : "hit", - key: fullKey, - prefix: prefix(), - }); - return is.undefined(result) ? defaultValue : (result as T); - } catch (error) { - logger.warn({ defaultValue, error, key, name: "get" }, `cache error`); - internal.boilerplate.metrics.CACHE_DRIVER_ERROR_COUNT.labels( - "get", - ).inc(); - return defaultValue; - } - }, - keys: async (pattern = ""): Promise => { - try { - const fullPattern = fullKeyName(pattern); - const keys = await client.keys(fullPattern); - return keys.map((key) => key.slice(Math.max(NONE, prefix().length))); - } catch (error) { - internal.boilerplate.metrics.CACHE_DRIVER_ERROR_COUNT.labels( - "keys", - ).inc(); - logger.warn({ error, name: "keys" }, `cache error`); - return []; - } - }, - set: async ( - key: string, - value: T, - ttl = config.boilerplate.CACHE_TTL, - ): Promise => { - try { - const fullKey = fullKeyName(key); - await client.set(fullKey, value, ttl); - internal.boilerplate.metrics.CACHE_SET_OPERATIONS_TOTAL.inc({ - key: fullKey, - prefix: config.boilerplate.CACHE_PREFIX, - }); - } catch (error) { - internal.boilerplate.metrics.CACHE_DRIVER_ERROR_COUNT.labels( - "set", - ).inc(); - logger.error({ error, name: "set" }, `cache error`); - } - }, - setClient: (newClient) => { - logger.debug({ name: "setClient" }, `using new cache driver`); - client = newClient; - }, - } as TCache; -} diff --git a/src/extensions/configuration.extension.ts b/src/extensions/configuration.extension.ts deleted file mode 100644 index 9b9d725..0000000 --- a/src/extensions/configuration.extension.ts +++ /dev/null @@ -1,220 +0,0 @@ -import { - ApplicationDefinition, - BootstrapException, - CodeConfigDefinition, - ConfigLoader, - ConfigLoaderEnvironment, - ConfigLoaderFile, - deepExtend, - eachSeries, - KnownConfigs, - OptionalModuleConfiguration, - PartialConfiguration, - ServiceMap, - TBlackHole, - TInjectedConfig, - TServiceParams, -} from ".."; -import { is } from "."; - -export const INITIALIZE = Symbol.for("initialize"); -export const LOAD_PROJECT = Symbol.for("load-project"); -export const EVENT_CONFIGURATION_UPDATED = "event_configuration_updated"; -export const INJECTED_DEFINITIONS = Symbol.for("injected-config"); -export type ConfigManager = ReturnType; - -export function Configuration({ - context, - event, - lifecycle, - internal, - // ! THIS DOES NOT EXIST BEFORE PRE INIT - logger, -}: TServiceParams) { - // 🙊 but that's illegal! - lifecycle.onPreInit( - () => (logger = internal.boilerplate.logger.context(context)), - ); - - const configuration: PartialConfiguration = {}; - const configDefinitions: KnownConfigs = new Map(); - - type OnConfigUpdateCallback< - Project extends keyof TInjectedConfig, - Property extends keyof TInjectedConfig[Project], - > = (project: Project, property: Property) => TBlackHole; - - //#region Methods - function InjectedDefinitions() { - return new Proxy({} as TInjectedConfig, { - get(_, project: keyof TInjectedConfig) { - return internal.utils.object.get(configuration, project) ?? {}; - }, - getOwnPropertyDescriptor(_, project: string) { - return { - configurable: false, - enumerable: true, - value: internal.utils.object.get(configuration, project) ?? {}, - writable: false, - }; - }, - ownKeys() { - return Object.keys(configuration); - }, - }); - } - - function SetConfig< - Project extends keyof TInjectedConfig, - Property extends keyof TInjectedConfig[Project], - >( - project: Project, - property: Property, - value: TInjectedConfig[Project][Property], - ): void { - internal.utils.object.set( - configuration, - [project, property].join("."), - value, - ); - // in case anyone needs a hook - event.emit(EVENT_CONFIGURATION_UPDATED, project, property); - } - - // #MARK: Initialize - async function Initialize< - S extends ServiceMap, - C extends OptionalModuleConfiguration, - >(application: ApplicationDefinition): Promise { - const configLoaders = - internal.boot.application.configurationLoaders ?? - ([ConfigLoaderEnvironment, ConfigLoaderFile] as ConfigLoader[]); - - const start = Date.now(); - // * sanity check - if (!application) { - throw new BootstrapException( - context, - "NO_APPLICATION", - "Cannot load configuration without having defined an application", - ); - } - - // * were configs disabled? - if (is.empty(configLoaders)) { - logger.warn({ name: Initialize }, `no config loaders defined`); - return `${Date.now() - start}ms`; - } - - // * load! - await eachSeries(configLoaders, async (loader) => { - const merge = await loader({ - application, - configs: configDefinitions, - internal, - logger, - }); - deepExtend(configuration, merge); - }); - - // * validate - // - ensure all required properties have been defined - configDefinitions.forEach((definitions, project) => { - Object.keys(definitions).forEach((key) => { - const config = [project, key].join("."); - if ( - definitions[key].required && - is.undefined(internal.utils.object.get(configuration, config)) - ) { - // ruh roh - throw new BootstrapException( - context, - "REQUIRED_CONFIGURATION_MISSING", - `Configuration property ${config} is not defined`, - ); - } - }); - }); - return `${Date.now() - start}ms`; - } - - function Merge(merge: Partial) { - return deepExtend(configuration, merge); - } - - function LoadProject(library: string, definitions: CodeConfigDefinition) { - internal.utils.object.set(configuration, library, {}); - Object.keys(definitions).forEach((key) => { - internal.utils.object.set( - configuration, - [library, key].join("."), - definitions[key].default, - ); - }); - return configDefinitions.set(library, definitions); - } - // #endregion - - // #region Return object - return { - [INITIALIZE]: Initialize, - [INJECTED_DEFINITIONS]: InjectedDefinitions, - [LOAD_PROJECT]: LoadProject, - - /** - * retrieve the metadata that was originally used to define the configs - */ - getDefinitions: () => configDefinitions, - - /** - * take a configuration object, and deep merge values - * - * intended for initial loading workflows - */ - merge: Merge, - - /** - * Not a replacement for `onPostConfig` - * - * Only receives updates from `config.set` calls - */ - onUpdate< - Project extends keyof TInjectedConfig, - Property extends Extract, - >( - callback: OnConfigUpdateCallback, - project?: Project, - property?: Property, - ) { - event.on( - EVENT_CONFIGURATION_UPDATED, - (updatedProject, updatedProperty) => { - if (!is.empty(project) && project !== updatedProject) { - return; - } - if (!is.empty(property) && property !== updatedProperty) { - return; - } - callback(updatedProject, updatedProperty); - }, - ); - }, - - /** - * type friendly method of updating a single configuration - * - * emits update event - */ - set: SetConfig as TSetConfig, - }; - // #endregion -} - -export type TSetConfig = < - Project extends keyof TInjectedConfig, - Property extends keyof TInjectedConfig[Project], ->( - project: Project, - property: Property, - value: TInjectedConfig[Project][Property], -) => void; diff --git a/src/extensions/fetch.extension.ts b/src/extensions/fetch.extension.ts deleted file mode 100644 index d68eea9..0000000 --- a/src/extensions/fetch.extension.ts +++ /dev/null @@ -1,215 +0,0 @@ -import { createWriteStream } from "fs"; -import { pipeline } from "stream"; -import { promisify } from "util"; - -import { - buildFilterString, - DownloadOptions, - FetchArguments, - FetcherOptions, - FetchProcessTypes, - FetchRequestError, - FetchWith, - FIRST, - MaybeHttpError, - TContext, - TFetchBody, - TServiceParams, -} from ".."; -import { is } from "."; - -const streamPipeline = promisify(pipeline); - -export function Fetch({ - logger, - context: parentContext, - internal, -}: TServiceParams) { - return ({ - headers: base_headers, - baseUrl: base_url, - context: logContext, - // eslint-disable-next-line sonarjs/cognitive-complexity - }: FetcherOptions) => { - const capabilities: string[] = []; - - if (!is.empty(capabilities)) { - logger.trace({ capabilities, name: logContext }, `initialized fetcher`); - } - - function checkForHttpErrors( - maybeError: MaybeHttpError, - ): T { - if ( - is.object(maybeError) && - maybeError !== null && - is.number(maybeError.statusCode) && - is.string(maybeError.error) - ) { - // Log the error if needed - logger.error( - { error: maybeError, name: logContext }, - maybeError.message, - ); - - // Throw a FetchRequestError - // throw new FetchRequestError(maybeError); - throw new FetchRequestError( - logContext || parentContext, - maybeError.statusCode, - maybeError.error, - maybeError.message, - ); - } - - return maybeError as T; - } - - // #MARK: fetchHandleResponse - async function fetchHandleResponse( - process: FetchProcessTypes, - response: Response, - ): Promise { - if (process === false || process === "raw") { - return response as T; - } - const text = await response.text(); - if (process === "text") { - return text as unknown as T; - } - if (!["{", "["].includes(text.charAt(FIRST))) { - if (["OK"].includes(text)) { - logger.debug({ name: logContext, text }, "full response text"); - } else { - // It's probably a coding error error, and not something a user did. - // Will try to keep the array up to date if any other edge cases pop up - logger.warn({ name: logContext, text }, `unexpected api Response`); - } - return text as T; - } - const parsed = JSON.parse(text); - return checkForHttpErrors(parsed); - } - - function fetchCreateUrl({ rawUrl, url, ...fetchWith }: FetchWith): string { - let out = url || ""; - if (!rawUrl) { - const base = fetchWith.baseUrl || fetchWrapper.base_url; - out = base + url; - } - if (!is.empty(fetchWith.params)) { - out = `${out}?${buildFilterString(fetchWith)}`; - } - return out; - } - - // #MARK: MeasureRequest - async function MeasureRequest( - label: string, - context: TContext, - exec: () => Promise, - ): Promise { - try { - const out = await exec(); - if (!is.empty(label)) { - internal.boilerplate.metrics.FETCH_REQUESTS_SUCCESSFUL.labels( - context, - label, - ).inc(); - } - return out; - } catch (error) { - logger.error({ error, name: logContext }, `request failed`); - if (!is.empty(label)) { - internal.boilerplate.metrics.FETCH_REQUESTS_FAILED.labels( - context, - label, - ).inc(); - } - throw error; - } - } - - // #MARK: execFetch - async function execFetch({ - body, - headers = {}, - method = "get", - process, - label, - context = logContext || parentContext, - ...fetchWith - }: Partial>) { - const out = await MeasureRequest(label, context, async () => { - const contentType = is.object(body) - ? { "Content-Type": "application/json" } - : {}; - const result = await fetch(fetchCreateUrl(fetchWith), { - body: is.object(body) ? JSON.stringify(body) : body, - headers: { - ...contentType, - ...fetchWrapper.base_headers, - ...headers, - }, - method, - }); - return await fetchHandleResponse(process, result); - }); - internal.boilerplate.metrics.FETCH_REQUESTS_SUCCESSFUL.labels( - context, - label, - ).inc(); - return out; - } - - async function download({ - destination, - body, - headers = {}, - label, - context = logContext || parentContext, - method = "get", - ...fetchWith - }: DownloadOptions) { - const url: string = await fetchCreateUrl(fetchWith); - const response = await fetch(url, { - body: is.object(body) ? JSON.stringify(body) : body, - headers: { ...fetchWrapper.base_headers, ...headers }, - method, - }); - - const stream = createWriteStream(destination); - await streamPipeline(response.body, stream); - if (!is.empty(label)) { - internal.boilerplate.metrics.FETCH_DOWNLOAD_REQUESTS_SUCCESSFUL.labels( - context, - label, - ).inc(); - } - } - - // #MARK: return object - const fetchWrapper = { - base_headers, - base_url, - download, - fetch: execFetch, - /** - * @deprecated set base_url directly - */ - setBaseUrl: (url: string) => (fetchWrapper.base_url = url), - /** - * @deprecated set base_headers directly - */ - setHeaders: (headers: Record) => - (fetchWrapper.base_headers = headers), - }; - return fetchWrapper; - }; -} - -export type TFetch = ( - fetchWith: Partial>, -) => Promise; - -export type TDownload = (fetchWith: DownloadOptions) => Promise; diff --git a/src/extensions/logger.extension.ts b/src/extensions/logger.extension.ts deleted file mode 100644 index 4ad3af6..0000000 --- a/src/extensions/logger.extension.ts +++ /dev/null @@ -1,272 +0,0 @@ -import dayjs from "dayjs"; -import { format, inspect } from "util"; - -import { FIRST, is, START, TContext } from ".."; -import { TServiceParams } from ".."; - -export type TLoggerFunction = - | ((message: string, ...arguments_: unknown[]) => void) - | ((object: object, message?: string, ...arguments_: unknown[]) => void); - -export interface ILogger { - debug(...arguments_: Parameters): void; - debug(message: string, ...arguments_: unknown[]): void; - debug(object: object, message?: string, ...arguments_: unknown[]): void; - error(...arguments_: Parameters): void; - error(message: string, ...arguments_: unknown[]): void; - error(object: object, message?: string, ...arguments_: unknown[]): void; - fatal(...arguments_: Parameters): void; - fatal(message: string, ...arguments_: unknown[]): void; - fatal(object: object, message?: string, ...arguments_: unknown[]): void; - info(...arguments_: Parameters): void; - info(message: string, ...arguments_: unknown[]): void; - info(object: object, message?: string, ...arguments_: unknown[]): void; - trace(...arguments_: Parameters): void; - trace(message: string, ...arguments_: unknown[]): void; - trace(object: object, message?: string, ...arguments_: unknown[]): void; - warn(...arguments_: Parameters): void; - warn(message: string, ...arguments_: unknown[]): void; - warn(object: object, message?: string, ...arguments_: unknown[]): void; -} - -const LOG_LEVEL_PRIORITY = { - debug: 20, - error: 50, - fatal: 60, - info: 30, - silent: 100, - trace: 10, - warn: 40, -}; -const LOG_LEVELS = Object.keys(LOG_LEVEL_PRIORITY) as TConfigLogLevel[]; - -export type TConfigLogLevel = keyof ILogger | "silent"; - -export const METHOD_COLORS = new Map([ - ["trace", "grey"], - ["debug", "blue"], - ["warn", "yellow"], - ["error", "red"], - ["info", "green"], - ["fatal", "magenta"], -]); - -let logger = {} as Record< - keyof ILogger, - (context: TContext, ...data: Parameters) => void ->; - -export type CONTEXT_COLORS = - | "grey" - | "blue" - | "yellow" - | "red" - | "green" - | "magenta"; -const MAX_CUTOFF = 2000; -const frontDash = " - "; -const SYMBOL_START = 1; -const SYMBOL_END = -1; -const LEVEL_MAX = 7; - -// #region Service definition -export async function Logger({ lifecycle, config, internal }: TServiceParams) { - const chalk = (await import("chalk")).default; - const timestampFormat = - internal.boot.options.loggerOptions?.timestamp_format ?? "ddd HH:mm:ss.SSS"; - - const YELLOW_DASH = chalk.yellowBright(frontDash); - const BLUE_TICK = chalk.blue(`>`); - let prettyFormat = true; - const shouldILog = {} as Record; - - // #MARK: pretty logger - const prettyFormatMessage = (message: string): string => { - if (!message) { - return ``; - } - if (message.length > MAX_CUTOFF || !prettyFormat) { - return message; - } - message = message - // ? partA#partB - highlight it all in yellow - .replaceAll(new RegExp("([^ ]+#[^ ]+)", "g"), (i) => chalk.yellow(i)) - // ? [A] > [B] > [C] - highlight the >'s in blue - .replaceAll("] > [", `] ${BLUE_TICK} [`) - // ? [Text] - strip brackets, highlight magenta - .replaceAll(new RegExp("(\\[[^\\]\\[]+\\])", "g"), (i) => - chalk.bold.magenta(i.slice(SYMBOL_START, SYMBOL_END)), - ) - // ? {Text} - strip braces, highlight gray - .replaceAll(new RegExp("(\\{[^\\]}]+\\})", "g"), (i) => - chalk.bold.gray(i.slice(SYMBOL_START, SYMBOL_END)), - ); - // ? " - Text" (line prefix with dash) - highlight dash - if (message.slice(START, frontDash.length) === frontDash) { - message = `${YELLOW_DASH}${message.slice(frontDash.length)}`; - } - return message; - }; - - if (is.empty(internal.boot.options.customLogger)) { - // #region formatter - [...METHOD_COLORS.keys()].forEach((key) => { - const level = `[${key.toUpperCase()}]`.padStart(LEVEL_MAX, " "); - logger[key] = ( - context: TContext, - ...parameters: Parameters - ) => { - const data = is.object(parameters[FIRST]) - ? (parameters.shift() as { - context?: TContext; - error?: Error | string; - name?: string | { name: string }; - stack?: string | string[]; - }) - : {}; - const highlighted = chalk.bold[METHOD_COLORS.get(key)]( - `[${data.context || context}]`, - ); - const name = - is.object(data.name) || is.function(data.name) - ? data.name.name - : data.name; - delete data.context; - delete data.name; - - const timestamp = chalk.white(`[${dayjs().format(timestampFormat)}]`); - let logMessage: string; - if (!is.empty(parameters)) { - const text = parameters.shift() as string; - logMessage = format(prettyFormatMessage(text), ...parameters); - } - - let message = `${timestamp} ${level}${highlighted}`; - - if (!is.empty(name)) { - message += chalk.blue(` (${name})`); - } - if (!is.empty(logMessage)) { - message += `: ${chalk.cyan(logMessage)}`; - } - if (!is.empty(data)) { - message += - "\n" + - inspect(data, { - colors: true, - compact: false, - depth: 10, - numericSeparator: true, - sorted: true, - }) - .split("\n") - .slice(SYMBOL_START, SYMBOL_END) - .join("\n"); - } - if (["warn", "error", "fatal"].includes(key)) { - // eslint-disable-next-line no-console - console.error(message); - return; - } - // eslint-disable-next-line no-console - console.log(message); - }; - }); - // #endregion - } else { - logger = internal.boot.options.customLogger; - } - - // #region instance creation - // if bootstrap hard coded something specific, then start there - // otherwise, be noisy until config loads a user preference - // - // stored as separate variable to cut down on internal config lookups - let CURRENT_LOG_LEVEL: TConfigLogLevel = - internal.utils.object.get( - internal, - "boot.options.configuration.boilerplate.LOG_LEVEL", - ) || "trace"; - - function context(context: string | TContext) { - return { - debug: (...params: Parameters) => - shouldILog.debug && logger.debug(context as TContext, ...params), - error: (...params: Parameters) => - shouldILog.error && logger.error(context as TContext, ...params), - fatal: (...params: Parameters) => - shouldILog.fatal && logger.fatal(context as TContext, ...params), - info: (...params: Parameters) => - shouldILog.info && logger.info(context as TContext, ...params), - trace: (...params: Parameters) => - shouldILog.trace && logger.trace(context as TContext, ...params), - warn: (...params: Parameters) => - shouldILog.warn && logger.warn(context as TContext, ...params), - } as ILogger; - } - - const updateShouldLog = () => { - if (!is.empty(config.boilerplate.LOG_LEVEL)) { - CURRENT_LOG_LEVEL = config.boilerplate.LOG_LEVEL; - } - LOG_LEVELS.forEach((key: TConfigLogLevel) => { - shouldILog[key] = - LOG_LEVEL_PRIORITY[key] >= LOG_LEVEL_PRIORITY[CURRENT_LOG_LEVEL]; - }); - }; - - // #MARK: lifecycle - lifecycle.onPostConfig(() => internal.boilerplate.logger.updateShouldLog()); - internal.boilerplate.configuration.onUpdate( - () => internal.boilerplate.logger.updateShouldLog(), - "boilerplate", - "LOG_LEVEL", - ); - updateShouldLog(); - - // #MARK: return object - return { - /** - * Create a new logger instance for a given context - */ - context, - - /** - * Retrieve a reference to the base logger used to emit from - */ - getBaseLogger: () => logger, - - /** - * for testing - */ - getShouldILog: () => ({ ...shouldILog }), - - /** - * exposed for testing - */ - prettyFormatMessage, - - /** - * Modify the base logger - * - * Note: Extension still handles LOG_LEVEL logic - */ - setBaseLogger: (base: ILogger) => (logger = base), - - /** - * Set the enabled/disabled state of the message pretty formatting logic - */ - setPrettyFormat: (state: boolean) => (prettyFormat = state), - - /** - * Logger instance of last resort - */ - systemLogger: context("digital-alchemy:system-logger"), - - /** - * exposed for testing - */ - updateShouldLog, - }; -} -// #endregion diff --git a/src/extensions/metrics.extension.ts b/src/extensions/metrics.extension.ts deleted file mode 100644 index 288a060..0000000 --- a/src/extensions/metrics.extension.ts +++ /dev/null @@ -1,170 +0,0 @@ -/* eslint-disable @typescript-eslint/no-magic-numbers */ -import { Counter, Gauge, Histogram, Summary } from "prom-client"; - -const build = () => { - /** - * Cache delete operations counter - */ - const CACHE_DELETE_OPERATIONS_TOTAL = new Counter({ - help: "Total number of cache delete operations", - labelNames: ["prefix", "key"] as const, - name: "digital_alchemy_boilerplate_cache_delete_operations_total", - }); - - /** - * Cache get operations counter - */ - const CACHE_GET_OPERATIONS_TOTAL = new Counter({ - help: "Total number of cache get operations", - labelNames: ["prefix", "key", "hit_miss"] as const, - name: "digital_alchemy_boilerplate_cache_get_operations_total", - }); - - /** - * Tracks the number of times a scheduled task has been executed. - * Labels: - * - context: The broader category or module the schedule belongs to. - * - label: A user-defined label to identify the specific schedule. - */ - const SCHEDULE_EXECUTION_COUNT = new Counter({ - help: "Counts the number of times a scheduled task has been executed", - labelNames: ["context", "label"] as const, - name: "digital_alchemy_boilerplate_schedule_execution_count", - }); - - /** - * Counts the number of errors occurred during scheduled task executions. - * Labels: - * - context: The broader category or module the schedule belongs to. - * - label: A user-defined label to identify the specific schedule where the error occurred. - */ - const SCHEDULE_ERRORS = new Counter({ - help: "Counts the number of errors during scheduled task executions", - labelNames: ["context", "label"] as const, - name: "digital_alchemy_boilerplate_schedule_errors", - }); - - /** - * Summary for Execution Time - */ - const SCHEDULE_EXECUTION_TIME = new Summary({ - help: "Measures the duration of each cron job or interval execution", - labelNames: ["context", "label"] as const, - name: "digital_alchemy_boilerplate_schedule_execution_time", - // These percentiles are just examples; adjust them based on what's relevant for your analysis - percentiles: [0.5, 0.9, 0.99], - }); - - /** - * Metric to count errors in cache driver - */ - const CACHE_DRIVER_ERROR_COUNT = new Counter({ - help: "Counts the number of errors caught in the cache driver", - labelNames: ["methodName"] as const, - name: "digital_alchemy_boilerplate_cache_driver_error_count", - }); - - /** - * Cache set operations counter - */ - const CACHE_SET_OPERATIONS_TOTAL = new Counter({ - help: "Total number of cache set operations", - labelNames: ["prefix", "key"] as const, - name: "digital_alchemy_boilerplate_cache_set_operations_total", - }); - - /** - * Counts the total number of initiated fetch requests. - */ - const FETCH_REQUESTS_INITIATED = new Counter({ - help: "Total number of fetch requests that have been initiated", - name: "digital_alchemy_boilerplate_fetch_requests_initiated_total", - }); - - /** - * Counts the total number of successfully completed fetch requests. - */ - const FETCH_REQUESTS_SUCCESSFUL = new Counter({ - help: "Total number of fetch requests that have been successfully completed", - labelNames: ["context", "label"] as const, - name: "digital_alchemy_boilerplate_fetch_requests_successful_total", - }); - - /** - * Counts the total number of successfully completed fetch requests. - */ - const FETCH_DOWNLOAD_REQUESTS_SUCCESSFUL = new Counter({ - help: "Total number of fetch download requests that have been successfully completed", - labelNames: ["context", "label"] as const, - name: "digital_alchemy_boilerplate_fetch_download_requests_successful_total", - }); - - /** - * Counts the total number of failed fetch requests. - */ - const FETCH_REQUESTS_FAILED = new Counter({ - help: "Total number of fetch requests that have failed", - labelNames: ["context", "label"] as const, - name: "digital_alchemy_boilerplate_fetch_requests_failed_total", - }); - - /** - * Gauge to count the number of errors encountered in Redis operations. - */ - const REDIS_ERROR_COUNT = new Gauge({ - help: "Counts the number of errors encountered in Redis operations", - name: "digital_alchemy_boilerplate_redis_error_count", - }); - - /** - * Histogram to track the latency of Redis operations in milliseconds. - * Buckets range from 0.1 ms to 1000 ms (1 second) for granular latency measurement. - */ - const REDIS_OPERATION_LATENCY_MS = new Histogram({ - buckets: [0.1, 0.5, 1, 5, 10, 20, 50, 100, 200, 500, 1000], - help: "Histogram for tracking the latency of Redis operations in milliseconds", - name: "digital_alchemy_boilerplate_redis_operation_latency_ms", - }); - - /** - * Counter to track the number of errors encountered in memory cache operations. - */ - const MEMORY_CACHE_ERROR_COUNT = new Counter({ - help: "Counts the number of errors encountered in memory cache operations", - name: "digital_alchemy_boilerplate_memory_cache_error_count", - }); - - /** - * A Prometheus gauge metric that tracks the number of unique context entries in the logger's context cache. - * This helps in monitoring and managing the memory usage associated with the caching of logger contexts. - */ - const LOGGER_CONTEXT_ENTRIES_COUNT = new Gauge({ - help: "Number of unique context entries in the logger context cache", - name: "digital_alchemy_boilerplate_logger_context_entries_count", - }); - - return { - CACHE_DELETE_OPERATIONS_TOTAL, - CACHE_DRIVER_ERROR_COUNT, - CACHE_GET_OPERATIONS_TOTAL, - CACHE_SET_OPERATIONS_TOTAL, - FETCH_DOWNLOAD_REQUESTS_SUCCESSFUL, - FETCH_REQUESTS_FAILED, - FETCH_REQUESTS_INITIATED, - FETCH_REQUESTS_SUCCESSFUL, - LOGGER_CONTEXT_ENTRIES_COUNT, - MEMORY_CACHE_ERROR_COUNT, - REDIS_ERROR_COUNT, - REDIS_OPERATION_LATENCY_MS, - SCHEDULE_ERRORS, - SCHEDULE_EXECUTION_COUNT, - SCHEDULE_EXECUTION_TIME, - }; -}; - -let metrics: ReturnType; - -export function Metrics() { - metrics ??= build(); - return metrics; -} diff --git a/src/extensions/scheduler.extension.ts b/src/extensions/scheduler.extension.ts deleted file mode 100644 index 89f4980..0000000 --- a/src/extensions/scheduler.extension.ts +++ /dev/null @@ -1,204 +0,0 @@ -/* eslint-disable sonarjs/cognitive-complexity */ -import dayjs, { Dayjs } from "dayjs"; -import { schedule } from "node-cron"; - -import { is, TBlackHole, TContext } from ".."; -import { - BootstrapException, - Schedule, - SchedulerOptions, - TServiceParams, -} from "../helpers"; - -export function Scheduler({ logger, lifecycle, internal }: TServiceParams) { - const stop = new Set<() => TBlackHole>(); - - // #MARK: lifecycle events - lifecycle.onPreShutdown(() => { - if (is.empty(stop)) { - return; - } - logger.info( - { name: "onPreShutdown" }, - `removing [%s] schedules`, - stop.size, - ); - stop.forEach((stopFunctions) => { - stopFunctions(); - stop.delete(stopFunctions); - }); - }); - - return (context: TContext) => { - // #MARK: node-cron - function cron({ - exec, - schedule: scheduleList, - label, - }: SchedulerOptions & { schedule: Schedule | Schedule[] }) { - const stopFunctions: (() => TBlackHole)[] = []; - [scheduleList].flat().forEach((cronSchedule) => { - logger.trace( - { context, label, name: cron, schedule: cronSchedule }, - `init`, - ); - const cronJob = schedule( - cronSchedule, - async () => - await internal.safeExec({ - duration: internal.boilerplate.metrics.SCHEDULE_EXECUTION_TIME, - errors: internal.boilerplate.metrics.SCHEDULE_ERRORS, - exec, - executions: internal.boilerplate.metrics.SCHEDULE_EXECUTION_COUNT, - labels: { context, label }, - }), - ); - lifecycle.onReady(() => { - logger.trace( - { context, name: cron, schedule: cronSchedule }, - "starting", - ); - cronJob.start(); - }); - - const stopFunction = () => { - logger.trace( - { context, label, name: cron, schedule: cronSchedule }, - `stopping`, - ); - cronJob.stop(); - }; - - stop.add(stopFunction); - stopFunctions.push(stopFunction); - return stopFunction; - }); - - return () => stopFunctions.forEach((stop) => stop()); - } - - // #MARK: setInterval - function interval({ - exec, - interval, - label, - }: SchedulerOptions & { interval: number }) { - let runningInterval: ReturnType; - lifecycle.onReady(() => { - logger.trace({ context, name: "interval" }, "starting"); - - runningInterval = setInterval( - async () => - await internal.safeExec({ - duration: internal.boilerplate.metrics.SCHEDULE_EXECUTION_TIME, - errors: internal.boilerplate.metrics.SCHEDULE_ERRORS, - exec, - executions: internal.boilerplate.metrics.SCHEDULE_EXECUTION_COUNT, - labels: { context, label }, - }), - interval, - ); - }); - const stopFunction = () => { - if (runningInterval) { - clearInterval(runningInterval); - } - }; - stop.add(stopFunction); - return stopFunction; - } - - // #MARK: sliding - function sliding({ - exec, - reset, - next, - label, - }: SchedulerOptions & { - /** - * How often to run the `next` method, to retrieve the next scheduled execution time - */ - reset: Schedule; - /** - * Return something time like. undefined = skip next - */ - next: () => Dayjs | string | number | Date | undefined; - }) { - if (!is.function(next)) { - throw new BootstrapException( - context, - "BAD_NEXT", - "Did not provide next function to schedule.sliding", - ); - } - if (!is.function(exec)) { - throw new BootstrapException( - context, - "BAD_NEXT", - "Did not provide exec function to schedule.sliding", - ); - } - let timeout: ReturnType; - - const waitForNext = () => { - if (timeout) { - logger.warn( - { context, name: sliding }, - `sliding schedule retrieving next execution time before previous ran`, - ); - clearTimeout(timeout); - } - let nextTime = next(); - if (!nextTime) { - // nothing to do? - // will try again next schedule - return; - } - nextTime = dayjs(nextTime); - if (dayjs().isAfter(nextTime)) { - // probably a result of boot - // ignore - return; - } - if (nextTime) { - timeout = setTimeout( - async () => { - await internal.safeExec({ - duration: internal.boilerplate.metrics.SCHEDULE_EXECUTION_TIME, - errors: internal.boilerplate.metrics.SCHEDULE_ERRORS, - exec, - executions: - internal.boilerplate.metrics.SCHEDULE_EXECUTION_COUNT, - labels: { context, label }, - }); - }, - Math.abs(dayjs().diff(nextTime, "ms")), - ); - } - }; - // reset on schedule - const scheduleStop = cron({ - exec: waitForNext, - label, - schedule: reset, - }); - // find value for now (boot) - lifecycle.onReady(() => waitForNext()); - - return () => { - scheduleStop(); - if (timeout) { - clearTimeout(timeout); - timeout = undefined; - } - }; - } - - // #MARK: return object - return { - cron, - interval, - sliding, - }; - }; -} diff --git a/src/helpers/async.helper.ts b/src/helpers/async.helper.ts index a8e3cbe..6f8058a 100644 --- a/src/helpers/async.helper.ts +++ b/src/helpers/async.helper.ts @@ -1,4 +1,5 @@ -import { is } from "../extensions/is.extension"; +/* eslint-disable sonarjs/no-redundant-type-constituents */ +import { is } from "../services"; import { ARRAY_OFFSET, SINGLE, START } from "./utilities.helper"; // ? Functions written to be similar to the offerings from the async library @@ -8,10 +9,13 @@ import { ARRAY_OFFSET, SINGLE, START } from "./utilities.helper"; // #MARK: each export async function each( - item: T[] = [], + item: T[] | Set, callback: (item: T) => Promise, ): Promise { - await Promise.all(item.map(async (i) => await callback(i))); + if (item instanceof Set) { + item = [...item.values()]; + } + await Promise.all(item.map(async i => await callback(i))); } // #MARK: eachSeries @@ -51,13 +55,13 @@ export async function eachLimit( } // Add initial tasks up to the limit - const initialTasks = items.slice(SINGLE, limit).map((item) => addTask(item)); + const initialTasks = items.slice(SINGLE, limit).map(item => addTask(item)); // Wait for the initial set of tasks to start processing await Promise.all(initialTasks); // Process the remaining items, ensuring the limit is respected - for (let i = limit; i < items.length; i++) { + for (let i = limit - ARRAY_OFFSET; i < items.length; i++) { await addTask(items[i]); } diff --git a/src/helpers/cache-memory.helper.ts b/src/helpers/cache-memory.helper.ts deleted file mode 100644 index b387a82..0000000 --- a/src/helpers/cache-memory.helper.ts +++ /dev/null @@ -1,66 +0,0 @@ -/* eslint-disable sonarjs/no-duplicate-string */ -import NodeCache from "node-cache"; - -import { CacheDriverOptions, ICacheDriver, is } from ".."; - -/** - * url & name properties automatically generated from config - */ -export function createMemoryDriver( - { logger, config, lifecycle, internal }: CacheDriverOptions, - options?: NodeCache.Options, -): ICacheDriver { - let client = new NodeCache({ - stdTTL: config.boilerplate.CACHE_TTL, - ...options, - }); - - lifecycle.onShutdownStart(() => { - logger.info({ name: "onShutdownStart" }, `cleanup`); - client = undefined; - }); - - return { - async del(key: string) { - try { - client.del(key); - } catch (error) { - logger.error({ err: error, name: "del" }, "memory cache error"); - internal.boilerplate.metrics.MEMORY_CACHE_ERROR_COUNT.inc(); - } - }, - async get(key: string, defaultValue?: T): Promise { - try { - const out = client.get(key); - if (is.string(out)) { - return JSON.parse(out) as T; - } - return defaultValue; - } catch (error) { - logger.error({ err: error, name: "get" }, "memory cache error"); - internal.boilerplate.metrics.MEMORY_CACHE_ERROR_COUNT.inc(); - return defaultValue; - } - }, - async keys(pattern?: string) { - try { - const allKeys = client.keys(); - return pattern - ? allKeys.filter((key) => new RegExp(pattern).test(key)) - : allKeys; - } catch (error) { - logger.error({ err: error, name: "keys" }, "memory cache error"); - internal.boilerplate.metrics.MEMORY_CACHE_ERROR_COUNT.inc(); - return []; - } - }, - async set(key: string, value: T, ttl: number) { - try { - client.set(key, JSON.stringify(value), ttl); - } catch (error) { - logger.error({ err: error, name: "set" }, "memory cache error"); - internal.boilerplate.metrics.MEMORY_CACHE_ERROR_COUNT.inc(); - } - }, - }; -} diff --git a/src/helpers/cache-redis.helper.ts b/src/helpers/cache-redis.helper.ts deleted file mode 100644 index 86a0e3e..0000000 --- a/src/helpers/cache-redis.helper.ts +++ /dev/null @@ -1,73 +0,0 @@ -/* eslint-disable sonarjs/no-duplicate-string */ -/* eslint-disable @typescript-eslint/no-magic-numbers */ -import { createClient } from "redis"; - -import { CacheDriverOptions, ICacheDriver, is, SECOND } from ".."; -/** - * url & name properties automatically generated from config - */ -export async function createRedisDriver( - { logger, config, lifecycle, internal }: CacheDriverOptions, - options?: Parameters[0], -): Promise { - let client = createClient({ - url: config.boilerplate.REDIS_URL, - ...options, - }); - await client.connect(); - - lifecycle.onShutdownStart(async () => { - logger.info({ name: "onShutdownStart" }, `disconnecting`); - await client.disconnect(); - client = undefined; - }); - - return { - async del(key: string) { - try { - await client.del(key); - } catch (error) { - logger.error({ err: error, name: "del" }, "redis cache error"); - internal.boilerplate.metrics.REDIS_ERROR_COUNT.inc(); - } - }, - async get(key: string, defaultValue?: T): Promise { - try { - const start = process.hrtime(); - const out = await client.get(key); - const diff = process.hrtime(start); - const durationInMilliseconds = diff[0] * SECOND + diff[1] / 1e6; - internal.boilerplate.metrics.REDIS_OPERATION_LATENCY_MS.observe( - durationInMilliseconds, - ); - if (out !== null && is.string(out)) { - return JSON.parse(out) as T; - } - return defaultValue; - } catch (error) { - logger.error({ err: error, name: "get" }, "redis cache error"); - internal.boilerplate.metrics.REDIS_ERROR_COUNT.inc(); - return defaultValue; - } - }, - async keys(pattern?: string) { - try { - return await client.keys(pattern || "*"); - } catch (error) { - logger.error({ err: error, name: "keys" }, "redis cache error"); - internal.boilerplate.metrics.REDIS_ERROR_COUNT.inc(); - return []; - } - }, - async set(key: string, value: T, ttl: number) { - try { - await client.set(key, JSON.stringify(value), { - EX: ttl, - }); - } catch (error) { - logger.error({ err: error, name: "set" }, "redis cache error"); - internal.boilerplate.metrics.REDIS_ERROR_COUNT.inc(); - } - }, - }; -} diff --git a/src/helpers/cache.helper.ts b/src/helpers/cache.helper.ts deleted file mode 100644 index ed9a89f..0000000 --- a/src/helpers/cache.helper.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { TServiceParams } from "."; - -export type CacheDriverOptions = Pick< - TServiceParams, - "logger" | "config" | "lifecycle" | "internal" ->; - -export interface ICacheDriver { - get(key: string, defaultValue?: T): Promise; - set(key: string, value: T, ttl: number): Promise; - del(key: string): Promise; - keys(pattern?: string): Promise; -} - -export type TCache = { - del: (key: string) => Promise; - get: (key: string, defaultValue?: T) => Promise; - set: (key: string, value: T, ttl?: number) => Promise; - keys: (pattern?: string) => Promise; - setClient: (client: ICacheDriver) => void; -}; - -export enum CacheProviders { - redis = "redis", - memory = "memory", -} diff --git a/src/helpers/config-environment-loader.helper.ts b/src/helpers/config-environment-loader.helper.ts index c93b08b..7dce802 100644 --- a/src/helpers/config-environment-loader.helper.ts +++ b/src/helpers/config-environment-loader.helper.ts @@ -1,5 +1,5 @@ import minimist from "minimist"; -import { argv, env } from "process"; +import { env } from "process"; import { is, ServiceMap } from ".."; import { @@ -17,7 +17,7 @@ export async function ConfigLoaderEnvironment< S extends ServiceMap = ServiceMap, C extends ModuleConfiguration = ModuleConfiguration, >({ configs, internal, logger }: ConfigLoaderParams): ConfigLoaderReturn { - const CLI_SWITCHES = minimist(argv); + const CLI_SWITCHES = minimist(process.argv); const switchKeys = Object.keys(CLI_SWITCHES); const out: Partial = {}; @@ -31,7 +31,7 @@ export async function ConfigLoaderEnvironment< const cleanedProject = project.replaceAll("-", "_"); // * run through each config for module - Object.keys(configuration).forEach((key) => { + Object.keys(configuration).forEach(key => { // > things to search for // - MODULE_NAME_CONFIG_KEY (module + key, ex: app_NODE_ENV) // - CONFIG_KEY (only key, ex: NODE_ENV) diff --git a/src/helpers/config-file-loader.helper.ts b/src/helpers/config-file-loader.helper.ts index 72eb087..ce77649 100644 --- a/src/helpers/config-file-loader.helper.ts +++ b/src/helpers/config-file-loader.helper.ts @@ -18,9 +18,9 @@ const isWindows = platform === "win32"; export const SUPPORTED_CONFIG_EXTENSIONS = ["json", "ini", "yaml", "yml"]; function withExtensions(path: string): string[] { - return [path, join(path, "config")].flatMap((path) => [ + return [path, join(path, "config")].flatMap(path => [ path, - ...SUPPORTED_CONFIG_EXTENSIONS.map((i) => `${path}.${i}`), + ...SUPPORTED_CONFIG_EXTENSIONS.map(i => `${path}.${i}`), ]); } @@ -40,9 +40,7 @@ export function configFilePaths(name = "digital-alchemy"): string[] { current = next; } out.push(...withExtensions(join(homedir(), ".config", name))); - return out.filter( - (filePath) => existsSync(filePath) && statSync(filePath).isFile(), - ); + return out.filter(filePath => existsSync(filePath) && statSync(filePath).isFile()); } export async function ConfigLoaderFile< @@ -74,21 +72,15 @@ export async function ConfigLoaderFile< return {}; } const out: Partial = {}; - logger.trace( - { files, name: ConfigLoaderFile }, - `loading configuration files`, - ); - files.forEach((file) => loadConfigFromFile(out, file)); + logger.trace({ files, name: ConfigLoaderFile }, `loading configuration files`); + files.forEach(file => loadConfigFromFile(out, file)); return out; } function loadConfigFromFile(out: Partial, filePath: string) { const fileContent = readFileSync(filePath, "utf8").trim(); - const hasExtension = SUPPORTED_CONFIG_EXTENSIONS.some((extension) => { - if ( - filePath.slice(extension.length * INVERT_VALUE).toLowerCase() === - extension - ) { + const hasExtension = SUPPORTED_CONFIG_EXTENSIONS.some(extension => { + if (filePath.slice(extension.length * INVERT_VALUE).toLowerCase() === extension) { switch (extension) { case "ini": deepExtend(out, decode(fileContent) as unknown as AbstractConfig); diff --git a/src/helpers/config.helper.ts b/src/helpers/config.helper.ts index 72297e4..40c4ddd 100644 --- a/src/helpers/config.helper.ts +++ b/src/helpers/config.helper.ts @@ -1,11 +1,24 @@ -import { config } from "dotenv"; -import { existsSync } from "fs"; +import dotenv from "dotenv"; +import fs from "fs"; import { ParsedArgs } from "minimist"; import { isAbsolute, join, normalize } from "path"; import { cwd } from "process"; -import { ILogger, InternalDefinition, is } from ".."; -import { ApplicationDefinition, ServiceMap } from "./wiring.helper"; +import { + ILogger, + INITIALIZE, + INJECTED_DEFINITIONS, + InternalDefinition, + is, + LOAD_PROJECT, + TBlackHole, +} from ".."; +import { + ApplicationDefinition, + PartialConfiguration, + ServiceMap, + TInjectedConfig, +} from "./wiring.helper"; export type CodeConfigDefinition = Record; export type ProjectConfigTypes = @@ -116,6 +129,7 @@ export interface ConfigTypeDTO { * Extends the global common config, adding a section for the top level application to chuck in data without affecting things * Also provides dedicated sections for libraries to store their own configuration options */ +// eslint-disable-next-line @typescript-eslint/no-empty-object-type export interface AbstractConfig {} export type ConfigLoaderReturn = Promise>; @@ -129,10 +143,7 @@ export type ConfigLoaderParams< logger: ILogger; }; -export type ConfigLoader = < - S extends ServiceMap, - C extends OptionalModuleConfiguration, ->( +export type ConfigLoader = ( params: ConfigLoaderParams, ) => ConfigLoaderReturn; @@ -141,9 +152,7 @@ export function cast(data: string | string[], type: string): T { case "boolean": { data ??= ""; return ( - is.boolean(data) - ? data - : ["true", "y", "1"].includes((data as string).toLowerCase()) + is.boolean(data) ? data : ["true", "y", "1"].includes((data as string).toLowerCase()) ) as T; } case "number": @@ -173,27 +182,19 @@ export type OptionalModuleConfiguration = ModuleConfiguration | undefined; export function findKey(source: T[], find: T[]) { return ( // Find an exact match (if available) first - source.find((line) => find.includes(line)) || + source.find(line => find.includes(line)) || // Do case insensitive searches - source.find((line) => { - const match = new RegExp( - `^${line.replaceAll(new RegExp("[-_]", "gi"), "[-_]?")}$`, - "gi", - ); - return find.some((item) => item.match(match)); + source.find(line => { + const match = new RegExp(`^${line.replaceAll(new RegExp("[-_]", "gi"), "[-_]?")}$`, "gi"); + return find.some(item => item.match(match)); }) ); } export function iSearchKey(target: string, source: string[]) { - return source.find((key) => - key.match( - new RegExp( - `^${target.replaceAll(new RegExp("[-_]", "gi"), "[-_]?")}$`, - "gi", - ), - ), - ); + const regex = new RegExp(`^${target.replaceAll(new RegExp("[-_]", "gi"), "[-_]?")}$`, "gi"); + + return source.find(key => regex.exec(key) !== null); } /** @@ -207,7 +208,7 @@ export function loadDotenv( CLI_SWITCHES: ParsedArgs, logger: ILogger, ) { - let { envFile } = internal.boot.options; + let { envFile } = internal.boot.options ?? {}; const switchKeys = Object.keys(CLI_SWITCHES); const searched = iSearchKey("env-file", switchKeys); @@ -220,23 +221,18 @@ export function loadDotenv( // * was provided an --env-file or something via boot if (!is.empty(envFile)) { - const checkFile = isAbsolute(envFile) - ? normalize(envFile) - : join(cwd(), envFile); - if (existsSync(checkFile)) { + const checkFile = isAbsolute(envFile) ? normalize(envFile) : join(cwd(), envFile); + if (fs.existsSync(checkFile)) { file = checkFile; } else { - logger.warn( - { checkFile, envFile, name: loadDotenv }, - "invalid target for dotenv file", - ); + logger.warn({ checkFile, envFile, name: loadDotenv }, "invalid target for dotenv file"); } } // * attempt default file if (is.empty(file)) { const defaultFile = join(cwd(), ".env"); - if (existsSync(defaultFile)) { + if (fs.existsSync(defaultFile)) { file = defaultFile; } else { logger.debug({ name: loadDotenv }, "no .env found"); @@ -246,7 +242,7 @@ export function loadDotenv( // ? each of the steps above verified the path as valid if (!is.empty(file)) { logger.trace({ file, name: loadDotenv }, `loading env file`); - config({ override: true, path: file }); + dotenv.config({ override: true, path: file }); } } @@ -268,3 +264,46 @@ export function parseConfig(config: AnyConfig, value: string) { } } } + +export type DigitalAlchemyConfiguration = { + [INITIALIZE]: ( + application: ApplicationDefinition, + ) => Promise; + [INJECTED_DEFINITIONS]: () => TInjectedConfig; + [LOAD_PROJECT]: (library: string, definitions: CodeConfigDefinition) => KnownConfigs; + getDefinitions: () => KnownConfigs; + merge: (incoming: Partial) => PartialConfiguration; + /** + * Not a replacement for `onPostConfig` + * + * Only receives updates from `config.set` calls + */ + onUpdate: < + Project extends keyof TInjectedConfig, + Property extends Extract, + >( + callback: OnConfigUpdateCallback, + project?: Project, + property?: Property, + ) => void; + /** + * type friendly method of updating a single configuration + * + * emits update event + */ + set: TSetConfig; +}; + +export type TSetConfig = < + Project extends keyof TInjectedConfig, + Property extends keyof TInjectedConfig[Project], +>( + project: Project, + property: Property, + value: TInjectedConfig[Project][Property], +) => void; + +export type OnConfigUpdateCallback< + Project extends keyof TInjectedConfig, + Property extends keyof TInjectedConfig[Project], +> = (project: Project, property: Property) => TBlackHole; diff --git a/src/helpers/cron.helper.ts b/src/helpers/cron.helper.ts index 726ae11..b77aa9c 100644 --- a/src/helpers/cron.helper.ts +++ b/src/helpers/cron.helper.ts @@ -1,3 +1,9 @@ +import { Dayjs } from "dayjs"; + +import { TContext } from "./context.helper"; +import { TBlackHole } from "./utilities.helper"; +import { Schedule, SchedulerOptions } from "./wiring.helper"; + export enum CronExpression { EVERY_SECOND = "* * * * * *", EVERY_5_SECONDS = "*/5 * * * * *", @@ -85,3 +91,30 @@ export enum CronExpression { } export const CRON_SCHEDULE = "CRON_SCHEDULE"; export const INTERVAL_SCHEDULE = "INTERVAL_SCHEDULE"; + +export type SchedulerCronOptions = SchedulerOptions & { + schedule: Schedule | Schedule[]; +}; +export type SchedulerIntervalOptions = SchedulerOptions & { + interval: number; +}; +export type SchedulerSlidingOptions = SchedulerOptions & { + /** + * How often to run the `next` method, to retrieve the next scheduled execution time + */ + reset: Schedule; + /** + * Return something time like. undefined = skip next + */ + next: () => Dayjs | string | number | Date | undefined; +}; + +export type ScheduleRemove = () => TBlackHole; + +export type DigitalAlchemyScheduler = { + cron: (options: SchedulerCronOptions) => ScheduleRemove; + interval: (options: SchedulerIntervalOptions) => ScheduleRemove; + sliding: (options: SchedulerSlidingOptions) => ScheduleRemove; +}; + +export type SchedulerBuilder = (context: TContext) => DigitalAlchemyScheduler; diff --git a/src/helpers/errors.helper.ts b/src/helpers/errors.helper.ts index 56116b8..81d5488 100644 --- a/src/helpers/errors.helper.ts +++ b/src/helpers/errors.helper.ts @@ -1,11 +1,5 @@ import { TContext } from ".."; -export type MaybeHttpError = { - error: string; - message: string; - statusCode: number; -}; - export class BootstrapException extends Error { context: TContext; override cause: string; @@ -35,25 +29,3 @@ export class InternalError extends Error { this.timestamp = new Date(); } } - -export class FetchRequestError extends Error { - statusCode: number; - error: string; - timestamp: Date; - context: TContext; - - constructor( - context: TContext, - statusCode: number, - error: string, - message: string, - ) { - super(); - this.context = context; - this.name = "FetchRequestError"; - this.message = message; - this.statusCode = statusCode; - this.error = error; - this.timestamp = new Date(); - } -} diff --git a/src/helpers/events.helper.ts b/src/helpers/events.helper.ts index 5f2a95f..5eaebb2 100644 --- a/src/helpers/events.helper.ts +++ b/src/helpers/events.helper.ts @@ -1,10 +1,6 @@ import { is } from ".."; -export const DIGITAL_ALCHEMY_NODE_GLOBAL_ERROR = - "DIGITAL_ALCHEMY_NODE_GLOBAL_ERROR"; -export const DIGITAL_ALCHEMY_APPLICATION_ERROR = - "DIGITAL_ALCHEMY_APPLICATION_ERROR"; +export const DIGITAL_ALCHEMY_NODE_GLOBAL_ERROR = "DIGITAL_ALCHEMY_NODE_GLOBAL_ERROR"; +export const DIGITAL_ALCHEMY_APPLICATION_ERROR = "DIGITAL_ALCHEMY_APPLICATION_ERROR"; export const DIGITAL_ALCHEMY_LIBRARY_ERROR = (library?: string) => - is.empty(library) - ? "DIGITAL_ALCHEMY_LIBRARY_ERROR" - : `DIGITAL_ALCHEMY_LIBRARY_ERROR:${library}`; + is.empty(library) ? "DIGITAL_ALCHEMY_LIBRARY_ERROR" : `DIGITAL_ALCHEMY_LIBRARY_ERROR:${library}`; diff --git a/src/helpers/extend.helper.ts b/src/helpers/extend.helper.ts index db0a6ad..536077d 100644 --- a/src/helpers/extend.helper.ts +++ b/src/helpers/extend.helper.ts @@ -1,4 +1,4 @@ -import { is } from "../extensions/is.extension"; +import { is } from "../services/is.extension"; function isSpecificValue(value: unknown) { return value instanceof Date || value instanceof RegExp; @@ -14,10 +14,9 @@ function cloneSpecificValue(value: unknown) { throw new TypeError("Unexpected situation"); } -export function deepCloneArray( - array: Array, -): Array { - return array.map((item) => { +export function deepCloneArray(array: Array): Array { + // eslint-disable-next-line sonarjs/function-return-type + return array.map(item => { if (is.object(item)) { if (is.array(item)) { return deepCloneArray(item); @@ -32,16 +31,14 @@ export function deepCloneArray( } function safeGetProperty(object: unknown, key: string) { - return key === "__proto__" - ? undefined - : (object as Record)[key]; + return key === "__proto__" ? undefined : (object as Record)[key]; } export function deepExtend(target: A, object: B): A & B { if (typeof object !== "object" || object === null || is.array(object)) { return target as A & B; } - Object.keys(object).forEach((key) => { + Object.keys(object).forEach(key => { const source = safeGetProperty(target, key); const value = safeGetProperty(object, key); if (value === target) { diff --git a/src/helpers/fetch.helper.ts b/src/helpers/fetch.helper.ts deleted file mode 100644 index 5712356..0000000 --- a/src/helpers/fetch.helper.ts +++ /dev/null @@ -1,355 +0,0 @@ -import { MergeExclusive } from "type-fest"; - -import { is, TContext } from ".."; - -/** - * Defines the types of parameters that can be used in fetch requests. - */ -export type FetchParameterTypes = - | string - | boolean - | Date - | number - | Array; - -/** - * Enumerates HTTP methods used in fetch requests. - */ -export enum HTTP_METHODS { - get = "get", - delete = "delete", - put = "put", - patch = "patch", - post = "post", -} - -type NoBodyMethods = "get" | "delete"; -type BodyMethods = "put" | "patch" | "post"; - -/** - * Represents a fetch request with additional properties and body content. - */ -export type FetchWith< - EXTRA extends Record = Record, - BODY extends TFetchBody = undefined, -> = Partial> & EXTRA; - -export type FetchProcessTypes = boolean | "text" | "json" | "raw" | undefined; - -type BaseFetchArguments = { - /** - * Headers to append - */ - headers?: Record; - /** - * Query params to send - */ - params?: Record; - /** - * Built in post-processing - * - * - true / "json" = attempt to decode as json - * - false / "raw" = return the node-fetch response object without processing - * - "text" = return result as text, no additional processing - * - * ? boolean values are deprecated - */ - process?: FetchProcessTypes; - /** - * If provided, metrics will be kept for this request, and associated with labels - */ - label?: string; - /** - * Defaults to global fetch context - */ - context?: TContext; -}; - -type BaseFetchUrl = { - /** - * URL to send request to - */ - url: string; -} & MergeExclusive< - { - /** - * Frequently filled in by wrapper services - */ - baseUrl?: string; - }, - { - /** - * URL is the full path (includes http://...) - * - * Ignores baseUrl if set - */ - rawUrl?: boolean; - } ->; - -type BaseFetchBody = MergeExclusive< - { - /** - * POSTDATA - */ - body?: BODY; - /** - * HTTP method - */ - method: BodyMethods; - }, - { - /** - * HTTP method - */ - method?: NoBodyMethods; - } ->; - -/** - * Defines the structure and types for arguments passed to fetch requests. - */ -export type FetchArguments = BaseFetchUrl & - BaseFetchArguments & - BaseFetchBody; - -/** - * Represents a subset of FetchArguments for specific use cases. - */ -export type FilteredFetchArguments = - BaseFetchBody & - Pick & - Pick; - -/** - * Same thing as FetchWith, but the function doesn't need any args - * - * This is a work around, for some reason the default value approach isn't work as I had hoped - */ -export type BaseFetch = Partial; - -/** - * Defines the types of values that can be used in filter operations. - */ -export type FilterValueType = - | string - | boolean - | number - | Date - | RegExp - | unknown - | Record; - -/** - * Enumerates the types of operations available for data filtering. - */ -export enum FILTER_OPERATIONS { - // "elemMatch" functionality in mongo - // eslint-disable-next-line unicorn/prevent-abbreviations - elem = "elem", - regex = "regex", - in = "in", - nin = "nin", - lt = "lt", - lte = "lte", - gt = "gt", - gte = "gte", - exists = "exists", - empty = "empty", - ne = "ne", - eq = "eq", -} - -export interface ComparisonDTO { - operation?: FILTER_OPERATIONS | `${FILTER_OPERATIONS}`; - value?: FilterValueType | FilterValueType[]; -} - -export interface Filter extends ComparisonDTO { - empty?: boolean; - exists?: boolean; - field?: FIELDS; -} - -export interface ResultControl { - filters?: Set; - limit?: number; - select?: string[]; - skip?: number; - sort?: string[]; -} - -// eslint-disable-next-line sonarjs/cognitive-complexity -export function controlToQuery( - value: Readonly, -): Record { - const out = new Map(); - if (value?.limit) { - out.set("limit", value.limit.toString()); - } - if (value?.skip) { - out.set("skip", value.skip.toString()); - } - if (value?.sort) { - out.set("sort", value.sort.join(",")); - } - if (value?.select) { - out.set("select", value.select.join(",")); - } - value?.filters?.forEach((f) => { - let field = f.field; - if (f.operation && f.operation !== FILTER_OPERATIONS.eq) { - field = `${field}__${f.operation}`; - } - let value = f.value; - if (is.array(value)) { - value = value.join(","); - } - if (value instanceof Date) { - value = value.toISOString(); - } - if (value === null) { - value = "null"; - } - if (field) { - out.set(field, (value ?? "").toString()); - } - }); - return Object.fromEntries(out.entries()); -} - -export function buildFilter( - key: string, - value: FilterValueType | FilterValueType[], -): Filter { - const [name, operation] = key.split("__") as [string, FILTER_OPERATIONS]; - switch (operation) { - case "in": - case "nin": - if (!is.array(value)) { - value = is.string(value) ? value.split(",") : [value]; - } - return { - field: name, - operation, - value: value, - }; - case "elem": - return { - field: name, - operation, - value: is.string(value) ? JSON.parse(value) : value, - }; - default: - return { - field: name, - operation, - value, - }; - } -} - -export function queryToControl( - value: Readonly>, -): ResultControl { - const filters = new Set>(); - const out: ResultControl = { filters }; - const parameters = new Map(Object.entries(value)); - parameters.forEach((value, key) => { - const [name, operation] = key.split("__") as [string, FILTER_OPERATIONS]; - switch (key) { - case "select": - out.select = value.split(","); - return; - case "sort": - out.sort = value.split(","); - return; - case "limit": - out.limit = Number(value); - return; - case "skip": - out.skip = Number(value); - return; - } - switch (operation) { - case "in": - case "nin": - filters.add({ - field: name, - operation, - value: value.split(","), - }); - return; - case "elem": - filters.add({ - field: name, - operation, - value: JSON.parse(value), - }); - return; - default: - filters.add({ - field: name, - operation, - value, - }); - } - }); - return out; -} - -/** - * Properties that alter the way that fetcher works. - */ -export type FetcherOptions = { - /** - * typically domain names with scheme, added to the front of urls if the individual request doesn't override - */ - baseUrl?: string; - /** - * merged into every request - */ - headers?: Record; - /** - * Alter the context attached to the log statements emitted from the fetcher - */ - context?: TContext; -}; - -export type DownloadOptions = Partial< - FetchArguments -> & { destination: string }; - -export function fetchCast(item: FetchParameterTypes): string { - if (is.array(item)) { - return item.map((i) => fetchCast(i)).join(","); - } - if (item instanceof Date) { - return item.toISOString(); - } - if (is.number(item)) { - return item.toString(); - } - if (is.boolean(item)) { - return item ? "true" : "false"; - } - return item; -} - -export type TFetchBody = object | undefined; - -export function buildFilterString( - fetchWith: FetchWith<{ - filters?: Readonly; - params?: Record; - }>, -): string { - return new URLSearchParams({ - ...Object.fromEntries( - Object.entries(fetchWith.params ?? {}).map(([label, value]) => [ - label, - fetchCast(value), - ]), - ), - }).toString(); -} diff --git a/src/helpers/index.ts b/src/helpers/index.ts index 3669e2b..016abf1 100644 --- a/src/helpers/index.ts +++ b/src/helpers/index.ts @@ -1,7 +1,4 @@ export * from "./async.helper"; -export * from "./cache.helper"; -export * from "./cache-memory.helper"; -export * from "./cache-redis.helper"; export * from "./config.helper"; export * from "./config-environment-loader.helper"; export * from "./config-file-loader.helper"; @@ -10,7 +7,8 @@ export * from "./cron.helper"; export * from "./errors.helper"; export * from "./events.helper"; export * from "./extend.helper"; -export * from "./fetch.helper"; export * from "./lifecycle.helper"; +export * from "./logger.helper"; +export * from "./module.helper"; export * from "./utilities.helper"; export * from "./wiring.helper"; diff --git a/src/helpers/lifecycle.helper.ts b/src/helpers/lifecycle.helper.ts index a41a13a..9212e61 100644 --- a/src/helpers/lifecycle.helper.ts +++ b/src/helpers/lifecycle.helper.ts @@ -1,16 +1,10 @@ import { TBlackHole } from ".."; export type LifecycleCallback = () => TBlackHole; -export type LifecyclePrioritizedCallback = [ - callback: LifecycleCallback, - priority: number, -]; +export type LifecyclePrioritizedCallback = [callback: LifecycleCallback, priority: number]; export type CallbackList = LifecyclePrioritizedCallback[]; -export type TLifeCycleRegister = ( - callback: LifecycleCallback, - priority?: number, -) => void; +export type TLifeCycleRegister = (callback: LifecycleCallback, priority?: number) => void; export type TLifecycleBase = { /** @@ -53,8 +47,6 @@ export type TParentLifecycle = TLifecycleBase & { child: () => TLifecycleBase; }; -export type TChildLifecycle = TLifecycleBase; - // ! This is a sorted array! Don't change the order export const LIFECYCLE_STAGES = [ "PreInit", diff --git a/src/helpers/logger.helper.ts b/src/helpers/logger.helper.ts new file mode 100644 index 0000000..c903faa --- /dev/null +++ b/src/helpers/logger.helper.ts @@ -0,0 +1,79 @@ +import { TContext } from "./context.helper"; + +export type DigitalAlchemyLogger = { + /** + * Create a new logger instance for a given context + */ + context: (context: string | TContext) => ILogger; + /** + * Retrieve a reference to the base logger used to emit from + */ + getBaseLogger: () => Record< + keyof ILogger, + (context: TContext, ...data: Parameters) => void + >; + getPrettyFormat: () => boolean; + /** + * exposed for testing + */ + prettyFormatMessage: (message: string) => string; + /** + * Modify the base logger + * + * Note: Extension still handles LOG_LEVEL logic + */ + setBaseLogger: (base: ILogger) => ILogger; + /** + * Set the enabled/disabled state of the message pretty formatting logic + */ + setPrettyFormat: (state: boolean) => boolean; + /** + * Logger instance of last resort + */ + systemLogger: ILogger; + /** + * exposed for testing + */ + updateShouldLog: () => void; + /** + * If set, logs will be converted to json & sent to target + */ + setHttpLogs: (url: string) => void; +}; + +export type TLoggerFunction = + | ((message: string, ...arguments_: unknown[]) => void) + | ((object: object, message?: string, ...arguments_: unknown[]) => void); + +export interface ILogger { + debug(...arguments_: Parameters): void; + debug(message: string, ...arguments_: unknown[]): void; + debug(object: object, message?: string, ...arguments_: unknown[]): void; + error(...arguments_: Parameters): void; + error(message: string, ...arguments_: unknown[]): void; + error(object: object, message?: string, ...arguments_: unknown[]): void; + fatal(...arguments_: Parameters): void; + fatal(message: string, ...arguments_: unknown[]): void; + fatal(object: object, message?: string, ...arguments_: unknown[]): void; + info(...arguments_: Parameters): void; + info(message: string, ...arguments_: unknown[]): void; + info(object: object, message?: string, ...arguments_: unknown[]): void; + trace(...arguments_: Parameters): void; + trace(message: string, ...arguments_: unknown[]): void; + trace(object: object, message?: string, ...arguments_: unknown[]): void; + warn(...arguments_: Parameters): void; + warn(message: string, ...arguments_: unknown[]): void; + warn(object: object, message?: string, ...arguments_: unknown[]): void; +} +export type TConfigLogLevel = keyof ILogger | "silent"; + +export const METHOD_COLORS = new Map([ + ["trace", "grey"], + ["debug", "blue"], + ["warn", "yellow"], + ["error", "red"], + ["info", "green"], + ["fatal", "magenta"], +]); +export type CONTEXT_COLORS = "grey" | "blue" | "yellow" | "red" | "green" | "magenta"; +export const EVENT_UPDATE_LOG_LEVELS = "EVENT_UPDATE_LOG_LEVELS"; diff --git a/src/helpers/module.helper.ts b/src/helpers/module.helper.ts new file mode 100644 index 0000000..1b43457 --- /dev/null +++ b/src/helpers/module.helper.ts @@ -0,0 +1,239 @@ +import { Except, Merge } from "type-fest"; + +import { CreateApplication } from "../services"; +import { iTestRunner, TestRunner } from "../testing"; +import { OptionalModuleConfiguration } from "./config.helper"; +import { deepExtend } from "./extend.helper"; +import { + ApplicationDefinition, + CreateLibrary, + LibraryDefinition, + ServiceFunction, + ServiceMap, + TLibrary, +} from "./wiring.helper"; + +export type ExtendOptions = { + name?: string; + /** + * default: true + */ + keepConfiguration?: boolean; +}; + +export type DigitalAlchemyModule = { + services: S; + configuration: C; + name: string; + depends: TLibrary[]; + optionalDepends?: TLibrary[]; + priorityInit: string[]; + extend: (options?: ExtendOptions) => ModuleExtension; +}; + +export type CreateModuleOptions = { + services: S; + configuration: C; + name: string; + depends: TLibrary[]; + optionalDepends?: TLibrary[]; + priorityInit: string[]; +}; + +/** + * commands mutate module + */ +export type ModuleExtension = { + appendLibrary: (library: TLibrary) => ModuleExtension; + appendService: (name: string, target: ServiceFunction) => ModuleExtension; + + /** + * name must match existing library + */ + replaceLibrary: (library: TLibrary) => ModuleExtension; + + /** + * name must match existing service + */ + replaceService: ( + name: TARGET, + target: FN, + ) => ModuleExtension, C>; + + /** + * throws if any service does not exist + */ + pickService: (...services: PICK[]) => ModuleExtension, C>; + + /** + * throws if any service does not exist + */ + omitService: (...services: OMIT[]) => ModuleExtension, C>; + + /** + * build api compatible replacement (potentially adding) + */ + rebuild: ( + services: Partial, + ) => ModuleExtension; + + /** + * export as application + */ + toApplication: () => ApplicationDefinition; + + /** + * export as library + */ + toLibrary: () => LibraryDefinition; + + /** + * export as test + */ + toTest: () => iTestRunner; +}; + +export function createModule( + options: CreateModuleOptions, +): DigitalAlchemyModule { + function extend(extendOptions: ExtendOptions) { + const appendLibrary = new Map(); + let services = { ...workingModule.services }; + + const extend: ModuleExtension = { + appendLibrary: (library: TLibrary) => { + const name = library.name; + if (appendLibrary.has(name)) { + throw new Error(`${name} already is appended`); + } + const exists = workingModule.depends.some(i => i.name === name); + if (exists) { + throw new Error(`${name} exists as a library in base, use replaceLibrary`); + } + appendLibrary.set(name, library); + return extend; + }, + appendService: (name: string, service: ServiceFunction) => { + if (name in services) { + throw new Error(`${name} exists as a service in base, use replaceService`); + } + // @ts-expect-error the interface makes this type properly, idc + services[name] = service; + return extend; + }, + omitService: (...keys: OMIT[]) => { + services = Object.fromEntries( + Object.entries(services).filter(([i]) => !keys.includes(i as OMIT)), + ) as typeof services; + return extend as unknown as ModuleExtension, C>; + }, + pickService: (...keys: PICK[]) => { + services = Object.fromEntries( + Object.entries(services).filter(([i]) => keys.includes(i as PICK)), + ) as typeof services; + return extend as unknown as ModuleExtension, C>; + }, + rebuild: (incoming: Partial) => { + services = incoming as REPLACEMENTS; + return extend as unknown as ModuleExtension; + }, + replaceLibrary: (library: TLibrary) => { + const name = library.name; + if (appendLibrary.has(name)) { + appendLibrary.set(name, library); + } else { + const exists = workingModule.depends.some(i => i.name === name); + if (!exists) { + throw new Error(`${name} does not exist in module yet`); + } + appendLibrary.set(name, library); + } + return extend; + }, + // @ts-expect-error I don't care + replaceService: ( + name: TARGET, + target: FN, + ) => { + if (!(name in services)) { + throw new Error(`${String(name)} does not exist to replace`); + } + // @ts-expect-error I don't care + services[name] = target; + return extend; + }, + toApplication: () => { + const depends = {} as Record; + workingModule.depends.forEach(i => (depends[i.name] = i)); + appendLibrary.forEach((value, key) => (depends[key] = value)); + + return CreateApplication({ + configuration: deepExtend({}, workingModule.configuration), + libraries: Object.values(depends), + // @ts-expect-error wrapper problems + name: extendOptions?.name || options.name, + // @ts-expect-error wrapper problems + priorityInit: [...workingModule.priorityInit], + services, + }); + }, + toLibrary: () => { + const depends = {} as Record; + workingModule.depends.forEach(i => (depends[i.name] = i)); + appendLibrary.forEach((value, key) => (depends[key] = value)); + + return CreateLibrary({ + configuration: deepExtend({}, workingModule.configuration), + depends: Object.values(depends), + // @ts-expect-error wrapper problems + name: extendOptions?.name || options.name, + optionalDepends: workingModule.optionalDepends, + // @ts-expect-error wrapper problems + priorityInit: [...workingModule.priorityInit], + services, + }); + }, + toTest: () => { + return TestRunner({ target: extend.toApplication() }); + }, + }; + return extend; + } + + const workingModule: DigitalAlchemyModule = { + configuration: options.configuration, + depends: options.depends, + extend, + name: options.name, + optionalDepends: options.optionalDepends ?? [], + priorityInit: options.priorityInit, + services: options.services ?? ({} as S), + }; + return workingModule; +} + +createModule.fromApplication = ( + application: ApplicationDefinition, +) => { + return createModule({ + configuration: application.configuration || ({} as C), + depends: application.libraries || [], + name: application.name, + optionalDepends: [], + priorityInit: application.priorityInit || [], + services: application.services, + }); +}; + +createModule.fromLibrary = ( + library: LibraryDefinition, +) => { + return createModule({ + configuration: library.configuration || ({} as C), + depends: library.depends || [], + name: library.name, + optionalDepends: library.optionalDepends || [], + priorityInit: library.priorityInit || [], + services: library.services, + }); +}; diff --git a/src/helpers/utilities.helper.ts b/src/helpers/utilities.helper.ts index ebf29d1..e786538 100644 --- a/src/helpers/utilities.helper.ts +++ b/src/helpers/utilities.helper.ts @@ -1,4 +1,4 @@ -import { is } from "../extensions/is.extension"; +import { is } from "../services/is.extension"; /* eslint-disable @typescript-eslint/no-magic-numbers */ export const EVEN = 2; @@ -45,6 +45,8 @@ export const SECOND = 1000; export const PERCENT = 100; export const YEAR = 365 * DAY; +export const ACTIVE_SLEEPS = new Set(); + type SleepReturn = Promise & { kill: (execute: "stop" | "continue") => void; }; @@ -73,16 +75,23 @@ export function sleep(target: number | Date = SECOND): SleepReturn { let done: undefined | (() => void); const timeout = setTimeout( - () => done && done(), + () => { + if (done) { + done(); + } + ACTIVE_SLEEPS.delete(out); + }, is.date(target) ? target.getTime() - Date.now() : target, ); // Take a normal promise, add a `.kill` to it // You can await as normal, or call the function - const out = new Promise((i) => (done = i)) as SleepReturn; + const out = new Promise(i => (done = i)) as SleepReturn; + ACTIVE_SLEEPS.add(out); out.kill = (execute = "stop") => { - if (execute === "continue") { - done && done(); + ACTIVE_SLEEPS.delete(out); + if (execute === "continue" && done) { + done(); } clearTimeout(timeout); done = undefined; @@ -96,10 +105,7 @@ export const ACTIVE_DEBOUNCE = new Map(); /** * allow initial call, then block for a period */ -export async function throttle( - identifier: string, - timeout: number, -): Promise { +export async function throttle(identifier: string, timeout: number): Promise { if (ACTIVE_THROTTLE.has(identifier)) { return; } @@ -113,12 +119,9 @@ export async function throttle( /** * wait for duration after call before allowing next, extends for calls inside window */ -export async function debounce( - identifier: string, - timeout: number, -): Promise { +export async function debounce(identifier: string, timeout: number): Promise { const current = ACTIVE_DEBOUNCE.get(identifier); - if (current) { + if (!is.undefined(current)) { current.kill("stop"); } const delay = sleep(timeout); @@ -136,10 +139,9 @@ export const noop = () => {}; * Create an array of length, where the values are filled with a provided fill value, or (index + 1) as default value */ export function PEAT(length: number, fill?: T): T[] { - return Array.from({ length }).map( - (_, index) => fill ?? ((index + ARRAY_OFFSET) as T), - ); + return Array.from({ length }).map((_, index) => fill ?? ((index + ARRAY_OFFSET) as T)); } +// eslint-disable-next-line sonarjs/no-redundant-type-constituents export type TBlackHole = unknown | void | Promise; export type TAnyFunction = (...data: unknown[]) => TBlackHole; diff --git a/src/helpers/wiring.helper.ts b/src/helpers/wiring.helper.ts index 4318518..e53381d 100644 --- a/src/helpers/wiring.helper.ts +++ b/src/helpers/wiring.helper.ts @@ -1,3 +1,4 @@ +import { AsyncLocalStorage } from "async_hooks"; import { Dayjs } from "dayjs"; import { EventEmitter } from "events"; @@ -12,7 +13,7 @@ import { LIB_BOILERPLATE, LOAD_PROJECT, TBlackHole, - TCache, + TConfigLogLevel, TContext, } from ".."; import { @@ -25,7 +26,7 @@ import { StringArrayConfig, StringConfig, } from "./config.helper"; -import { TChildLifecycle, TLifecycleBase } from "./lifecycle.helper"; +import { TLifecycleBase } from "./lifecycle.helper"; export type TServiceReturn = void | OBJECT; @@ -79,14 +80,6 @@ export type ScheduleItem = { }; export type SchedulerOptions = { exec: () => TBlackHole; - /** - * if provided, specific metrics will be kept and labelled with provided label - * - * - execution count - * - errors - * - execution duration - */ - label?: string; }; // #MARK: TScheduler @@ -148,14 +141,34 @@ export type TInjectedConfig = { [ModuleName in keyof ModuleConfigs]: ConfigTypes; }; +// #region +// SEE DOCS http://docs.digital-alchemy.app/docs/core/declaration-merging +// eslint-disable-next-line @typescript-eslint/no-empty-object-type +export interface AsyncLogData { + // No data by default + // Intended to have declaration merges happen to be useful +} + +export interface AsyncLocalData { + logs: AsyncLogData; +} +// #endregion + +export type AlsExtension = { + asyncStorage: () => AsyncLocalStorage; + getStore: () => AsyncLocalData; + init(source: object, callback: () => TBlackHole): void; + getLogData: () => AsyncLogData; + // register(callback: AlsHook): void; +}; +export type AlsHook = () => object; + // #MARK: TServiceParams export type TServiceParams = { /** - * provided by boilerplate library - * - * contains basic caching methods + * hooks for AsyncLocalStorage */ - cache: TCache; + als: AlsExtension; /** * string describing how this service is wired into the main application */ @@ -195,15 +208,12 @@ export type TServiceParams = { [K in ExternalLoadedModules]: GetApis; }; -type LoadedModuleNames = Extract; +export type LoadedModuleNames = Extract; type ExternalLoadedModules = Exclude; type ModuleConfigs = { - [K in LoadedModuleNames]: LoadedModules[K] extends LibraryDefinition< - ServiceMap, - infer Config - > + [K in LoadedModuleNames]: LoadedModules[K] extends LibraryDefinition ? Config : LoadedModules[K] extends ApplicationDefinition ? Config @@ -212,11 +222,14 @@ type ModuleConfigs = { // Now, map these configurations to their respective types using CastConfigResult for each property in the configs type ConfigTypes = { - [Key in keyof Config]: Config[Key] extends AnyConfig - ? CastConfigResult - : never; + [Key in keyof Config]: Config[Key] extends AnyConfig ? CastConfigResult : never; }; +export type ServiceNames = + LoadedModules[T] extends LibraryDefinition + ? `${T}.${Extract}` + : never; + export type GetApis = T extends LibraryDefinition ? GetApisResult @@ -239,17 +252,13 @@ export type GetApis = // */ // priority?: Extract[]; // }; -export type Loader = < - K extends keyof PARENT["services"], ->( +export type Loader = ( serviceName: K, ) => ReturnType extends Promise ? AsyncResult : ReturnType; -export type ServiceFunction = ( - params: TServiceParams, -) => R | Promise; +export type ServiceFunction = (params: TServiceParams) => R | Promise; export type ServiceMap = Record; // #MARK: LibraryConfigurationOptions @@ -268,19 +277,13 @@ export type LibraryConfigurationOptions< * - warnings will be emitted if this library utilizes a different version of a dependency than what the app uses * - version provided by app will be substituted */ - depends?: LibraryConfigurationOptions< - ServiceMap, - OptionalModuleConfiguration - >[]; + depends?: TLibrary[]; /** * Same as depends, but will not error if library is not provided at app level * * **note**: related variables may come in as undefined, code needs to be built to allow for this */ - optionalDepends?: LibraryConfigurationOptions< - ServiceMap, - OptionalModuleConfiguration - >[]; + optionalDepends?: TLibrary[]; configuration?: C; /** * Define which services should be initialized first. Any remaining services are done at the end in no set order @@ -289,9 +292,7 @@ export type LibraryConfigurationOptions< }; export type PartialConfiguration = Partial<{ - [ModuleName in keyof ModuleConfigs]: Partial< - ConfigTypes - >; + [ModuleName in keyof ModuleConfigs]: Partial>; }>; // #MARK: BootstrapOptions @@ -340,12 +341,7 @@ export type BootstrapOptions = { /** * fine tine the built in logger */ - loggerOptions?: { - /** - * > default: ddd HH:mm:ss.SSS - */ - timestamp_format?: string; - }; + loggerOptions?: LoggerOptions; /** * Show detailed boot time statistics @@ -360,6 +356,55 @@ export type BootstrapOptions = { envFile?: string; }; +export type LoggerOptions = { + /** + * Generic data to include as data payload for all logs + * + * Can be used to provide application tags when using a log aggregator + */ + mergeData?: object; + /** + * Adjust the format of the timestamp at the start of the log + * + * > default: ddd HH:mm:ss.SSS + */ + timestampFormat?: string; + + /** + * Pretty format logs + * + * > default: true + */ + pretty?: boolean; + + /** + * prefix messages with ms since last message + * + * > default: false + */ + ms?: boolean; + + /** + * add an incrementing counter to every log. + * starts at 0 at boot + * + * > default: false + */ + counter?: boolean; + + /** + * extract details from als module to merge into logs + * + * > default: false + */ + als?: boolean; + + /** + * Override the `LOG_LEVEL` per service or module + */ + levelOverrides?: Partial>; +}; + export const WIRE_PROJECT = Symbol.for("wire-project"); type Wire = { @@ -378,13 +423,16 @@ type Wire = { lifecycle: TLifecycleBase, internal: InternalDefinition, ) => Promise>, - ) => Promise; + ) => Promise; }; export type LibraryDefinition< S extends ServiceMap, C extends OptionalModuleConfiguration, -> = LibraryConfigurationOptions & Wire; +> = LibraryConfigurationOptions & + Wire & { + type: "library"; + }; export type ApplicationDefinition< S extends ServiceMap, @@ -392,31 +440,27 @@ export type ApplicationDefinition< > = ApplicationConfigurationOptions & Wire & { logger: ILogger; + type: "application"; booted: boolean; bootstrap: (options?: BootstrapOptions) => Promise; teardown: () => Promise; }; -type TLibrary = LibraryDefinition; +export type TLibrary = LibraryDefinition; -export function BuildSortOrder< - S extends ServiceMap, - C extends OptionalModuleConfiguration, ->(app: ApplicationDefinition, logger: ILogger) { +export function buildSortOrder( + app: ApplicationDefinition, + logger: ILogger, +) { if (is.empty(app.libraries)) { return []; } - const libraryMap = new Map( - app.libraries.map((i) => [i.name, i]), - ); + const libraryMap = new Map(app.libraries.map(i => [i.name, i])); // Recursive function to check for missing dependencies at any depth function checkDependencies(library: TLibrary) { - const depends = [ - ...(library?.depends ?? []), - ...(library?.optionalDepends ?? []), - ]; + const depends = [...(library?.depends ?? []), ...(library?.optionalDepends ?? [])]; if (!is.empty(depends)) { - depends.forEach((item) => { + depends.forEach(item => { const loaded = libraryMap.get(item.name); if (!loaded) { if (library.depends.includes(item)) { @@ -437,9 +481,9 @@ export function BuildSortOrder< // just "are they the same object reference?" as the test // you get a warning, and the one the app asks for // hopefully there is no breaking changes - if (loaded !== item) { + if (loaded !== item && !process.env.NODE_ENV.startsWith("test")) { logger.warn( - { name: BuildSortOrder }, + { name: buildSortOrder }, "[%s] depends different version {%s}", library.name, item.name, @@ -450,40 +494,35 @@ export function BuildSortOrder< return library; } - let starting = app.libraries.map((i) => checkDependencies(i)); + let starting = app.libraries.map(i => checkDependencies(i)); const out = [] as TLibrary[]; while (!is.empty(starting)) { - const next = starting.find((library) => { + const next = starting.find(library => { const depends = [ ...(library?.depends ?? []), - ...(library?.optionalDepends?.filter((i) => - app.libraries.some((index) => i.name === index.name), + ...(library?.optionalDepends?.filter(i => + app.libraries.some(index => i.name === index.name), ) ?? []), ]; if (is.empty(depends)) { return true; } - return depends.every((depend) => out.some((i) => i.name === depend.name)); + return depends.every(depend => out.some(i => i.name === depend.name)); }); if (!next) { - logger.fatal({ current: out.map((i) => i.name), name: BuildSortOrder }); - throw new BootstrapException( - WIRING_CONTEXT, - "BAD_SORT", - `Cannot find a next lib to load`, - ); + logger.fatal({ current: out.map(i => i.name), name: buildSortOrder }); + throw new BootstrapException(WIRING_CONTEXT, "BAD_SORT", `Cannot find a next lib to load`); } - starting = starting.filter((i) => next.name !== i.name); + starting = starting.filter(i => next.name !== i.name); out.push(next); } return out; } -export const COERCE_CONTEXT = (context: string): TContext => - context as TContext; +export const COERCE_CONTEXT = (context: string): TContext => context as TContext; export const WIRING_CONTEXT = COERCE_CONTEXT("boilerplate:wiring"); -export function ValidateLibrary( +export function validateLibrary( project: string, serviceList: S, ): void | never { @@ -497,9 +536,7 @@ export function ValidateLibrary( const services = Object.entries(serviceList); // Find the first invalid service - const invalidService = services.find( - ([, definition]) => typeof definition !== "function", - ); + const invalidService = services.find(([, definition]) => typeof definition !== "function"); if (invalidService) { const [invalidServiceName, service] = invalidService; throw new BootstrapException( @@ -510,7 +547,7 @@ export function ValidateLibrary( } } -export function WireOrder(priority: T[], list: T[]): T[] { +export function wireOrder(priority: T[], list: T[]): T[] { const out = [...(priority || [])]; if (!is.empty(priority)) { const check = is.unique(priority); @@ -522,13 +559,11 @@ export function WireOrder(priority: T[], list: T[]): T[] { ); } } - return [...out, ...list.filter((i) => !out.includes(i))]; + const temporary = [...out, ...list.filter(i => !out.includes(i))]; + return temporary; } -export function CreateLibrary< - S extends ServiceMap, - C extends OptionalModuleConfiguration, ->({ +export function CreateLibrary({ name: libraryName, configuration = {} as C, priorityInit, @@ -536,10 +571,22 @@ export function CreateLibrary< depends, optionalDepends, }: LibraryConfigurationOptions): LibraryDefinition { - ValidateLibrary(libraryName, services); + validateLibrary(libraryName, services); const serviceApis = {} as GetApisResult; + if (!is.empty(priorityInit)) { + priorityInit.forEach(name => { + if (!is.function(services[name])) { + throw new BootstrapException( + WIRING_CONTEXT, + "MISSING_PRIORITY_SERVICE", + `${name} was listed as priority init, but was not found in services`, + ); + } + }); + } + const library = { [WIRE_PROJECT]: async ( internal: InternalDefinition, @@ -555,18 +602,15 @@ export function CreateLibrary< // manually added inside the bootstrap process const config = internal?.boilerplate.configuration as ConfigManager; config?.[LOAD_PROJECT](libraryName as keyof LoadedModules, configuration); - await eachSeries( - WireOrder(priorityInit, Object.keys(services)), - async (service) => { - serviceApis[service] = await WireService( - libraryName, - service, - services[service], - internal.boot.lifecycle.events, - internal, - ); - }, - ); + await eachSeries(wireOrder(priorityInit, Object.keys(services)), async service => { + serviceApis[service] = await WireService( + libraryName, + service, + services[service], + internal.boot.lifecycle.events, + internal, + ); + }); internal.boot.constructComplete.add(libraryName); // mental note: people should probably do all their lifecycle attachments at the base level function // otherwise, it'll happen after this wire() call, and go into a black hole (worst case) or fatal error ("best" case) @@ -578,6 +622,7 @@ export function CreateLibrary< priorityInit, serviceApis, services, + type: "library", } as unknown as LibraryDefinition; return library; } diff --git a/src/index.ts b/src/index.ts index 4b62461..05b0fdf 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,2 +1,3 @@ -export * from "./extensions"; export * from "./helpers"; +export * from "./services"; +export * from "./testing"; diff --git a/src/services/als.extension.ts b/src/services/als.extension.ts new file mode 100644 index 0000000..d1db2de --- /dev/null +++ b/src/services/als.extension.ts @@ -0,0 +1,19 @@ +import { AsyncLocalStorage } from "async_hooks"; +import { v4 } from "uuid"; + +import { AlsExtension, AsyncLocalData, AsyncLogData, TBlackHole, TServiceParams } from "../helpers"; + +export function ALS({ config }: TServiceParams): AlsExtension { + const storage = new AsyncLocalStorage(); + return { + asyncStorage: () => (config.boilerplate.NODE_ENV ? storage : undefined), + getLogData: () => storage.getStore()?.logs ?? ({} as AsyncLogData), + getStore: () => storage.getStore(), + init(source: object, callback: () => TBlackHole) { + const data = { logs: { id: v4(), ...source } }; + storage.run(data as AsyncLocalData, () => { + callback(); + }); + }, + }; +} diff --git a/src/services/configuration.extension.ts b/src/services/configuration.extension.ts new file mode 100644 index 0000000..eee1f3e --- /dev/null +++ b/src/services/configuration.extension.ts @@ -0,0 +1,175 @@ +import { + ApplicationDefinition, + BootstrapException, + CodeConfigDefinition, + ConfigLoader, + ConfigLoaderEnvironment, + ConfigLoaderFile, + deepExtend, + DigitalAlchemyConfiguration, + eachSeries, + KnownConfigs, + OnConfigUpdateCallback, + OptionalModuleConfiguration, + PartialConfiguration, + ServiceMap, + TInjectedConfig, + TServiceParams, + TSetConfig, +} from ".."; +import { is } from "."; + +export const INITIALIZE = Symbol.for("initialize"); +export const LOAD_PROJECT = Symbol.for("load-project"); +export const EVENT_CONFIGURATION_UPDATED = "event_configuration_updated"; +export const INJECTED_DEFINITIONS = Symbol.for("injected-config"); +export type ConfigManager = ReturnType; + +const DECIMALS = 2; + +export function Configuration({ + context, + event, + lifecycle, + internal, + // ! THIS DOES NOT EXIST BEFORE PRE INIT + logger, +}: TServiceParams): DigitalAlchemyConfiguration { + // modern problems require modern solutions + lifecycle.onPreInit(() => (logger = internal.boilerplate.logger.context(context))); + + const configuration: PartialConfiguration = {}; + const configDefinitions: KnownConfigs = new Map(); + + function injectedDefinitions(): TInjectedConfig { + const out = {} as Record; + return new Proxy(out as TInjectedConfig, { + get(_, project: keyof TInjectedConfig) { + return internal.utils.object.get(configuration, project) ?? {}; + }, + has(_, key: keyof TInjectedConfig) { + Object.keys(configuration).forEach(key => (out[key as keyof typeof out] ??= {})); + return Object.keys(configuration).includes(key); + }, + ownKeys() { + Object.keys(configuration).forEach(key => (out[key as keyof typeof out] ??= {})); + return Object.keys(configuration); + }, + set() { + return false; + }, + }); + } + + function setConfig< + Project extends keyof TInjectedConfig, + Property extends keyof TInjectedConfig[Project], + >(project: Project, property: Property, value: TInjectedConfig[Project][Property]): void { + internal.utils.object.set(configuration, [project, property].join("."), value); + // in case anyone needs a hook + event.emit(EVENT_CONFIGURATION_UPDATED, project, property); + } + + function validateConfig() { + // * validate + // - ensure all required properties have been defined + configDefinitions.forEach((definitions, project) => { + Object.keys(definitions).forEach(key => { + const config = [project, key].join("."); + if ( + definitions[key].required && + is.undefined(internal.utils.object.get(configuration, config)) + ) { + // ruh roh + throw new BootstrapException( + context, + "REQUIRED_CONFIGURATION_MISSING", + `Configuration property ${config} is not defined`, + ); + } + }); + }); + } + + // #MARK: Initialize + async function initialize( + application: ApplicationDefinition, + ): Promise { + const configLoaders = + internal.boot.application.configurationLoaders ?? + ([ConfigLoaderEnvironment, ConfigLoaderFile] as ConfigLoader[]); + + const start = performance.now(); + + // * were configs disabled? + if (is.empty(configLoaders)) { + validateConfig(); + if (!configuration.boilerplate.IS_TEST) { + logger.warn({ name: initialize }, `no config loaders defined`); + } + return `${(performance.now() - start).toFixed(DECIMALS)}ms`; + } + + // * load! + await eachSeries(configLoaders, async loader => { + const merge = await loader({ + application, + configs: configDefinitions, + internal, + logger, + }); + deepExtend(configuration, merge); + }); + + validateConfig(); + + return `${(performance.now() - start).toFixed(DECIMALS)}ms`; + } + + function merge(merge: Partial) { + return deepExtend(configuration, merge); + } + + function loadProject(library: string, definitions: CodeConfigDefinition) { + internal.utils.object.set(configuration, library, {}); + Object.keys(definitions).forEach(key => { + internal.utils.object.set(configuration, [library, key].join("."), definitions[key].default); + }); + return configDefinitions.set(library, definitions); + } + + return { + [INITIALIZE]: initialize, + [INJECTED_DEFINITIONS]: injectedDefinitions, + [LOAD_PROJECT]: loadProject, + + /** + * retrieve the metadata that was originally used to define the configs + */ + getDefinitions: () => configDefinitions, + + /** + * take a configuration object, and deep merge values + * + * intended for initial loading workflows + */ + merge: merge, + + onUpdate< + Project extends keyof TInjectedConfig, + Property extends Extract, + >(callback: OnConfigUpdateCallback, project?: Project, property?: Property) { + event.on(EVENT_CONFIGURATION_UPDATED, (updatedProject, updatedProperty) => { + if (!is.empty(project) && project !== updatedProject) { + return; + } + if (!is.empty(property) && property !== updatedProperty) { + return; + } + callback(updatedProject, updatedProperty); + }); + }, + + set: setConfig as TSetConfig, + }; +} diff --git a/src/extensions/index.ts b/src/services/index.ts similarity index 67% rename from src/extensions/index.ts rename to src/services/index.ts index e03d3b3..2bae6f1 100644 --- a/src/extensions/index.ts +++ b/src/services/index.ts @@ -1,9 +1,7 @@ -export * from "./cache.extension"; +export * from "./als.extension"; export * from "./configuration.extension"; -export * from "./fetch.extension"; export * from "./internal.extension"; export * from "./is.extension"; export * from "./logger.extension"; -export * from "./metrics.extension"; export * from "./scheduler.extension"; export * from "./wiring.extension"; diff --git a/src/extensions/internal.extension.ts b/src/services/internal.extension.ts similarity index 68% rename from src/extensions/internal.extension.ts rename to src/services/internal.extension.ts index 9e2f4f3..10ad4de 100644 --- a/src/extensions/internal.extension.ts +++ b/src/services/internal.extension.ts @@ -1,6 +1,5 @@ import dayjs, { Dayjs } from "dayjs"; import { EventEmitter } from "events"; -import { Counter, Summary } from "prom-client"; import { Get } from "type-fest"; import { @@ -15,6 +14,7 @@ import { LIB_BOILERPLATE, LifecycleStages, MINUTE, + NONE, OptionalModuleConfiguration, SECOND, ServiceMap, @@ -46,26 +46,24 @@ export class InternalUtils { * **NOTE:** bootstrapping process will initialize this at boot, and cleanup at teardown. * Making listener changes should only be done from within the context of service functions */ - public event = new EventEmitter(); + public event: EventEmitter; + constructor() { + this.event = new EventEmitter(); + this.event.setMaxListeners(NONE); + } - public TitleCase(input: string): string { + public titleCase(input: string): string { const matches = input.match(new RegExp("[a-z][A-Z]", "g")); if (matches) { - matches.forEach((i) => (input = input.replace(i, [...i].join(" ")))); + matches.forEach(i => (input = input.replace(i, [...i].join(" ")))); } return input .split(new RegExp("[ _-]")) - .map( - (word = "") => - `${word.charAt(FIRST).toUpperCase()}${word.slice(EVERYTHING_ELSE)}`, - ) + .map(word => `${word.charAt(FIRST).toUpperCase()}${word.slice(EVERYTHING_ELSE)}`) .join(" "); } - public relativeDate( - pastDate: inputFormats, - futureDate: inputFormats = new Date().toISOString(), - ) { + public relativeDate(pastDate: inputFormats, futureDate: inputFormats = new Date().toISOString()) { const UNITS = new Map([ ["year", YEAR], ["month", YEAR / MONTHS], @@ -74,14 +72,19 @@ export class InternalUtils { ["minute", MINUTE], ["second", SECOND], ]); - - if (!pastDate) { - return `NOT A DATE ${pastDate} ${JSON.stringify(pastDate)}`; + const past = dayjs(pastDate); + if (!past.isValid()) { + throw new Error("invalid past date " + pastDate); + } + const future = dayjs(futureDate); + if (!future.isValid()) { + throw new Error("invalid future date " + pastDate); } - const elapsed = dayjs(pastDate).diff(futureDate, "ms"); + + const elapsed = past.diff(future, "ms"); let out = ""; - [...UNITS.keys()].some((unit) => { + [...UNITS.keys()].some(unit => { const cutoff = UNITS.get(unit); if (Math.abs(elapsed) > cutoff || unit == "second") { out = formatter.format(Math.round(elapsed / cutoff), unit); @@ -115,10 +118,7 @@ export class InternalUtils { delete safeCurrent[key]; // Delete without checking; non-existent keys are a no-op } else { // For non-last keys, if the next level doesn't exist or isn't an object, stop processing - if ( - typeof safeCurrent[key] !== "object" || - safeCurrent[key] === null - ) { + if (typeof safeCurrent[key] !== "object" || safeCurrent[key] === null) { return; } // Move to the next level in the path @@ -139,12 +139,7 @@ export class InternalUtils { return current as Get; }, - set( - object: T, - path: string, - value: unknown, - doNotReplace: boolean = false, - ): void { + set(object: T, path: string, value: unknown, doNotReplace: boolean = false): void { const keys = path.split("."); let current = object as unknown; // Starting with the object as an unknown type @@ -182,34 +177,9 @@ export class InternalUtils { // #endregion } -/** - * ugh, really prom? - */ -type LabelFixer = Record< - Extract, - string | number ->; - -type SafeExecOptions = { +type SafeExecOptions = { + context?: TContext; exec: () => TBlackHole; - labels: LABELS; - duration: Summary>; - executions: Counter>; - errors: Counter>; -}; - -type BaseLabels = { - context: TContext; - /** - * ! if provided, specific metrics will be kept - * - * do not pass label if you do not want metrics to be kept, you may not want / need metrics to be kept on all instances - * - * - execution count - * - error count - * - summary of execution time - */ - label?: string; }; type Phase = "bootstrap" | "teardown" | "running"; @@ -219,10 +189,7 @@ export class InternalDefinition { /** * Utility methods provided by boilerplate */ - public boilerplate: Pick< - GetApis, - "configuration" | "fetch" | "logger" | "metrics" - >; + public boilerplate: Pick, "configuration" | "logger">; public boot: { /** * Options that were passed into bootstrap @@ -268,38 +235,19 @@ export class InternalDefinition { public utils = new InternalUtils(); // #MARK: safeExec - public async safeExec( - options: (() => TBlackHole) | SafeExecOptions, - ) { - let labels = {} as BaseLabels; - let errorMetric: Counter>; + public async safeExec(options: (() => TBlackHole) | SafeExecOptions): Promise { + const logger = this.boilerplate.logger.systemLogger; + const context = is.function(options) ? undefined : options?.context; + const exec = is.function(options) ? options : options?.exec; + if (!is.function(exec)) { + logger.error({ context }, `received non-function callback to [safeExec]`); + return undefined; + } try { - if (is.function(options)) { - await options(); - return; - } - const opt = options as SafeExecOptions; - labels = opt.labels; - errorMetric = opt.errors; - const { exec, duration, executions } = opt; - if (is.empty(labels.label)) { - await exec(); - return; - } - executions?.inc(labels as LabelFixer); - const end = duration?.startTimer(); - await exec(); - if (end) { - end(labels as LabelFixer); - } + return (await exec()) as T; } catch (error) { - this.boilerplate.logger.systemLogger.error( - { error, ...labels }, - `callback threw error`, - ); - if (!is.empty(labels.label)) { - errorMetric?.inc(labels as LabelFixer); - } + logger.error({ context, error }, `callback threw error`); + return undefined; } } } diff --git a/src/extensions/is.extension.ts b/src/services/is.extension.ts similarity index 85% rename from src/extensions/is.extension.ts rename to src/services/is.extension.ts index c072767..6e30276 100644 --- a/src/extensions/is.extension.ts +++ b/src/services/is.extension.ts @@ -1,3 +1,5 @@ +import { randomBytes } from "crypto"; +import dayjs, { Dayjs } from "dayjs"; import { isDeepStrictEqual, types } from "util"; import { EMPTY, EVEN, TBlackHole, TContext } from "../helpers"; @@ -32,8 +34,15 @@ export class IsIt { return typeof test === "string"; } + /** + * test is valid date + */ public date(test: unknown): test is Date { - return types.isDate(test); + return types.isDate(test) && is.number(test.getTime()); + } + + public dayjs(test: unknown): test is Dayjs { + return test instanceof dayjs && (test as Dayjs).isValid(); } public empty(test: MaybeEmptyTypes): boolean { @@ -85,7 +94,8 @@ export class IsIt { } public random(list: T[]): T { - return list[Math.floor(Math.random() * list.length)]; + // eslint-disable-next-line @typescript-eslint/no-magic-numbers + return list[Math.floor(randomBytes(1)[0] % list.length)]; } public string(test: unknown): test is string { diff --git a/src/extensions/lifecycle.extension.ts b/src/services/lifecycle.extension.ts similarity index 63% rename from src/extensions/lifecycle.extension.ts rename to src/services/lifecycle.extension.ts index 3fa1ffb..a095d92 100644 --- a/src/extensions/lifecycle.extension.ts +++ b/src/services/lifecycle.extension.ts @@ -5,8 +5,6 @@ import { LIFECYCLE_STAGES, LifecycleCallback, LifecycleStages, - NONE, - sleep, TLifecycleBase, UP, } from "../helpers"; @@ -17,21 +15,18 @@ type EventMapObject = { priority: number; }; const PRE_CALLBACKS_START = 0; +const DECIMALS = 2; export function CreateLifecycle() { const events = new Map( - LIFECYCLE_STAGES.map((event) => [event, []]), + LIFECYCLE_STAGES.map(event => [event, []]), ); - function attachEvent( - callback: LifecycleCallback, - name: LifecycleStages, - priority?: number, - ) { + function attachEvent(callback: LifecycleCallback, name: LifecycleStages, priority?: number) { const stageList = events.get(name); if (!is.array(stageList)) { if (!name.includes("Shutdown")) { - setImmediate(async () => await callback()); + callback(); } return; } @@ -40,22 +35,17 @@ export function CreateLifecycle() { return { events: { - onBootstrap: (callback, priority) => - attachEvent(callback, "Bootstrap", priority), - onPostConfig: (callback, priority) => - attachEvent(callback, "PostConfig", priority), - onPreInit: (callback, priority) => - attachEvent(callback, "PreInit", priority), - onPreShutdown: (callback, priority) => - attachEvent(callback, "PreShutdown", priority), + onBootstrap: (callback, priority) => attachEvent(callback, "Bootstrap", priority), + onPostConfig: (callback, priority) => attachEvent(callback, "PostConfig", priority), + onPreInit: (callback, priority) => attachEvent(callback, "PreInit", priority), + onPreShutdown: (callback, priority) => attachEvent(callback, "PreShutdown", priority), onReady: (callback, priority) => attachEvent(callback, "Ready", priority), onShutdownComplete: (callback, priority) => attachEvent(callback, "ShutdownComplete", priority), - onShutdownStart: (callback, priority) => - attachEvent(callback, "ShutdownStart", priority), + onShutdownStart: (callback, priority) => attachEvent(callback, "ShutdownStart", priority), } satisfies TLifecycleBase, async exec(stage: LifecycleStages): Promise { - const start = Date.now(); + const start = performance.now(); const list = events.get(stage); events.delete(stage); if (!is.empty(list)) { @@ -64,7 +54,8 @@ export function CreateLifecycle() { const positive = [] as EventMapObject[]; const negative = [] as EventMapObject[]; - sorted.forEach((i) => { + // console.error("HIT 1"); + sorted.forEach(i => { if (i.priority >= PRE_CALLBACKS_START) { positive.push(i); return; @@ -75,25 +66,24 @@ export function CreateLifecycle() { // * callbacks with a priority greater than 0 // high to low (1000 => 0) await eachSeries( - positive.sort((a, b) => (a.priority < b.priority ? UP : DOWN)), + positive.toSorted((a, b) => (a.priority < b.priority ? UP : DOWN)), async ({ callback }) => await callback(), ); + // console.error("HIT 2"); // * callbacks without a priority // any order await each(quick, async ({ callback }) => await callback()); + // console.error("HIT 3"); // * callbacks with a priority less than 0 // high to low (-1 => -1000) await eachSeries( - negative.sort((a, b) => (a.priority < b.priority ? UP : DOWN)), + negative.toSorted((a, b) => (a.priority < b.priority ? UP : DOWN)), async ({ callback }) => await callback(), ); } - // TODO Update this comment with why this sleep exists - // I forgot why, but it seems on purpose - await sleep(NONE); - return `${Date.now() - start}ms`; + return `${(performance.now() - start).toFixed(DECIMALS)}ms`; }, }; } diff --git a/src/services/logger.extension.ts b/src/services/logger.extension.ts new file mode 100644 index 0000000..fcf3c0e --- /dev/null +++ b/src/services/logger.extension.ts @@ -0,0 +1,276 @@ +/* eslint-disable sonarjs/slow-regex */ +import chalk from "chalk"; +import dayjs from "dayjs"; +import { format, inspect } from "util"; + +import { + DigitalAlchemyLogger, + EVENT_UPDATE_LOG_LEVELS, + FIRST, + ILogger, + is, + LoadedModuleNames, + METHOD_COLORS, + ServiceNames, + START, + TConfigLogLevel, + TContext, + TLoggerFunction, + TServiceParams, +} from ".."; + +const LOG_LEVEL_PRIORITY = { + debug: 20, + error: 50, + fatal: 60, + info: 30, + silent: 100, + trace: 10, + warn: 40, +}; +const DECIMALS = 2; +const LOG_LEVELS = Object.keys(LOG_LEVEL_PRIORITY) as TConfigLogLevel[]; + +let logger = {} as Record< + keyof ILogger, + (context: TContext, ...data: Parameters) => void +>; + +const MAX_CUTOFF = 2000; +const frontDash = " - "; +const SYMBOL_START = 1; +const SYMBOL_END = -1; +const LEVEL_MAX = 7; + +export async function Logger({ + lifecycle, + config, + event, + internal, + als, +}: TServiceParams): Promise { + let lastMessage = performance.now(); + let logCounter = START; + let httpLogTarget: string; + + const { loggerOptions = {} } = internal.boot?.options ?? {}; + + const timestampFormat = loggerOptions.timestampFormat ?? "ddd HH:mm:ss.SSS"; + loggerOptions.mergeData ??= {}; + + const YELLOW_DASH = chalk.yellowBright(frontDash); + const BLUE_TICK = chalk.blue(`>`); + let prettyFormat = is.boolean(loggerOptions.pretty) ? loggerOptions.pretty : true; + + function emitHttpLogs(data: object) { + if (is.empty(httpLogTarget)) { + return; + } + // validated with datadog, probably is fine elsewhere too + // https://http-intake.logs.datadoghq.com/v1/input/{API_KEY} + fetch(httpLogTarget, { + body: JSON.stringify(data), + headers: { "Content-Type": "application/json" }, + method: "POST", + }); + } + + function mergeData(data: T): T { + let out = { ...data, ...loggerOptions.mergeData }; + + if (loggerOptions.counter) { + const counter = data as { logIdx: number }; + counter.logIdx = logCounter++; + } + + if (loggerOptions.als) { + out = { ...out, ...als.getLogData() }; + } + + return out; + } + + const prettyFormatMessage = (message: string): string => { + if (!message) { + return ``; + } + if (!prettyFormat || message.length > MAX_CUTOFF) { + return message; + } + message = message + // ? partA#partB - highlight it all in yellow + .replaceAll(new RegExp("([^ ]+#[^ ]+)", "g"), i => chalk.yellow(i)) + // ? [A] > [B] > [C] - highlight the >'s in blue + .replaceAll("] > [", `] ${BLUE_TICK} [`) + // ? [Text] - strip brackets, highlight magenta + .replaceAll(new RegExp(String.raw`(\[[^\]\[]+\])`, "g"), i => + chalk.bold.magenta(i.slice(SYMBOL_START, SYMBOL_END)), + ) + // ? {Text} - strip braces, highlight gray + .replaceAll(new RegExp(String.raw`(\{[^\]}]+\})`, "g"), i => + chalk.bold.gray(i.slice(SYMBOL_START, SYMBOL_END)), + ); + // ? " - Text" (line prefix with dash) - highlight dash + if (message.slice(START, frontDash.length) === frontDash) { + message = `${YELLOW_DASH}${message.slice(frontDash.length)}`; + } + return message; + }; + + if (is.empty(internal.boot.options?.customLogger)) { + // #region formatter + [...METHOD_COLORS.keys()].forEach(key => { + const level = `[${key.toUpperCase()}]`.padStart(LEVEL_MAX, " "); + logger[key] = (context: TContext, ...parameters: Parameters) => { + const data = mergeData( + is.object(parameters[FIRST]) + ? (parameters.shift() as { + context?: TContext; + error?: Error | string; + name?: string | { name: string }; + stack?: string | string[]; + }) + : {}, + ); + + const rawData = { + ...data, + level: key, + timestamp: Date.now(), + } as Record; + + const highlighted = chalk.bold[METHOD_COLORS.get(key)](`[${data.context || context}]`); + const name = is.object(data.name) || is.function(data.name) ? data.name.name : data.name; + delete data.context; + delete data.name; + + const timestamp = chalk.white(`[${dayjs().format(timestampFormat)}]`); + let prettyMessage: string; + if (!is.empty(parameters)) { + const text = parameters.shift() as string; + rawData.msg = format(text, ...parameters); + prettyMessage = format(prettyFormatMessage(text), ...parameters); + } + + let message = `${timestamp} ${level}${highlighted}`; + + if (!is.empty(name)) { + message += chalk.blue(` (${name})`); + } + + if (loggerOptions.ms) { + const now = performance.now(); + const diff = (now - lastMessage).toFixed(DECIMALS) + `ms`; + lastMessage = now; + rawData.ms = diff; + + message += prettyFormat ? chalk.green(diff) : diff; + } + emitHttpLogs(rawData); + + if (!is.empty(prettyMessage)) { + message += `: ${chalk.cyan(prettyMessage)}`; + } + + if (!is.empty(data)) { + message += + "\n" + + inspect(data, { + colors: true, + compact: false, + depth: 10, + numericSeparator: true, + sorted: true, + }) + .split("\n") + .slice(SYMBOL_START, SYMBOL_END) + .join("\n"); + } + if (["warn", "error", "fatal"].includes(key)) { + global.console.error(message); + return; + } + + global.console.log(message); + }; + }); + // #endregion + } else { + logger = internal.boot.options.customLogger; + } + + // #region instance creation + // if bootstrap hard coded something specific, then start there + // otherwise, be noisy until config loads a user preference + // + // stored as separate variable to cut down on internal config lookups + let CURRENT_LOG_LEVEL: TConfigLogLevel = + internal.utils.object.get(internal, "boot.options.configuration.boilerplate.LOG_LEVEL") || + "trace"; + + function context(context: string | TContext) { + const name = context as ServiceNames; + const shouldILog = {} as Record; + const [prefix] = context.split(".") as [LoadedModuleNames]; + const update = () => + LOG_LEVELS.forEach((key: TConfigLogLevel) => { + // global level + let target = LOG_LEVEL_PRIORITY[key]; + + // override directly + if (loggerOptions?.levelOverrides?.[name]) { + target = LOG_LEVEL_PRIORITY[loggerOptions?.levelOverrides?.[name]]; + // module level override + } else if (loggerOptions?.levelOverrides?.[prefix]) { + target = LOG_LEVEL_PRIORITY[loggerOptions?.levelOverrides?.[prefix]]; + } + shouldILog[key] = target >= LOG_LEVEL_PRIORITY[CURRENT_LOG_LEVEL]; + }); + + event.on(EVENT_UPDATE_LOG_LEVELS, update); + update(); + + return { + debug: (...params: Parameters) => + shouldILog.debug && logger.debug(context as TContext, ...params), + error: (...params: Parameters) => + shouldILog.error && logger.error(context as TContext, ...params), + fatal: (...params: Parameters) => + shouldILog.fatal && logger.fatal(context as TContext, ...params), + info: (...params: Parameters) => + shouldILog.info && logger.info(context as TContext, ...params), + trace: (...params: Parameters) => + shouldILog.trace && logger.trace(context as TContext, ...params), + warn: (...params: Parameters) => + shouldILog.warn && logger.warn(context as TContext, ...params), + } as ILogger; + } + + const updateShouldLog = () => { + if (!is.empty(config.boilerplate.LOG_LEVEL)) { + CURRENT_LOG_LEVEL = config.boilerplate.LOG_LEVEL; + } + event.emit(EVENT_UPDATE_LOG_LEVELS); + }; + + // #MARK: lifecycle + lifecycle.onPostConfig(() => internal.boilerplate.logger.updateShouldLog()); + internal.boilerplate.configuration.onUpdate( + () => internal.boilerplate.logger.updateShouldLog(), + "boilerplate", + "LOG_LEVEL", + ); + + // #MARK: return object + return { + context, + getBaseLogger: () => logger, + getPrettyFormat: () => prettyFormat, + prettyFormatMessage, + setBaseLogger: base => (logger = base), + setHttpLogs: url => (httpLogTarget = url), + setPrettyFormat: state => (prettyFormat = state), + systemLogger: context("digital-alchemy:system-logger"), + updateShouldLog, + }; +} diff --git a/src/services/scheduler.extension.ts b/src/services/scheduler.extension.ts new file mode 100644 index 0000000..f0ca78b --- /dev/null +++ b/src/services/scheduler.extension.ts @@ -0,0 +1,142 @@ +import dayjs from "dayjs"; +import { schedule } from "node-cron"; + +import { is, TContext } from ".."; +import { + BootstrapException, + SchedulerBuilder, + SchedulerCronOptions, + ScheduleRemove, + SchedulerIntervalOptions, + SchedulerSlidingOptions, + TServiceParams, +} from "../helpers"; + +export function Scheduler({ logger, lifecycle, internal }: TServiceParams): SchedulerBuilder { + const stop = new Set(); + + // #MARK: lifecycle events + lifecycle.onPreShutdown(function onPreShutdown() { + if (is.empty(stop)) { + return; + } + logger.info({ name: onPreShutdown }, `removing [%s] schedules`, stop.size); + stop.forEach(stopFunctions => { + stopFunctions(); + stop.delete(stopFunctions); + }); + }); + + return (context: TContext) => { + // #MARK: cron + function cron({ exec, schedule: scheduleList }: SchedulerCronOptions) { + const stopFunctions: ScheduleRemove[] = []; + [scheduleList].flat().forEach(cronSchedule => { + logger.trace({ context, name: cron, schedule: cronSchedule }, `init`); + const cronJob = schedule(cronSchedule, async () => await internal.safeExec(exec)); + lifecycle.onReady(() => { + logger.trace({ context, name: cron, schedule: cronSchedule }, "starting"); + cronJob.start(); + }); + + const stopFunction = () => { + logger.trace({ context, name: cron, schedule: cronSchedule }, `stopping`); + cronJob.stop(); + }; + + stop.add(stopFunction); + stopFunctions.push(stopFunction); + return stopFunction; + }); + + return () => stopFunctions.forEach(stop => stop()); + } + + // #MARK: interval + function interval({ exec, interval }: SchedulerIntervalOptions) { + let runningInterval: ReturnType; + lifecycle.onReady(() => { + logger.trace({ context, name: interval }, "starting"); + + runningInterval = setInterval(async () => await internal.safeExec(exec), interval); + }); + const stopFunction = () => { + if (runningInterval) { + clearInterval(runningInterval); + } + }; + stop.add(stopFunction); + return stopFunction; + } + + // #MARK: sliding + function sliding({ exec, reset, next }: SchedulerSlidingOptions) { + if (!is.function(next)) { + throw new BootstrapException( + context, + "BAD_NEXT", + "Did not provide next function to schedule.sliding", + ); + } + if (!is.function(exec)) { + throw new BootstrapException( + context, + "BAD_NEXT", + "Did not provide exec function to schedule.sliding", + ); + } + let timeout: ReturnType; + + const waitForNext = () => { + if (timeout) { + logger.warn( + { context, name: sliding }, + `sliding schedule retrieving next execution time before previous ran`, + ); + clearTimeout(timeout); + } + let nextTime = next(); + if (!nextTime) { + // nothing to do? + // will try again next schedule + return; + } + nextTime = dayjs(nextTime); + if (dayjs().isAfter(nextTime)) { + // probably a result of boot + // ignore + return; + } + if (nextTime) { + timeout = setTimeout( + async () => { + await internal.safeExec(exec); + }, + Math.abs(dayjs().diff(nextTime, "ms")), + ); + } + }; + // reset on schedule + const scheduleStop = cron({ + exec: waitForNext, + schedule: reset, + }); + // find value for now (boot) + lifecycle.onReady(() => waitForNext()); + + return () => { + scheduleStop(); + if (timeout) { + clearTimeout(timeout); + timeout = undefined; + } + }; + } + + return { + cron, + interval, + sliding, + }; + }; +} diff --git a/src/extensions/wiring.extension.ts b/src/services/wiring.extension.ts similarity index 56% rename from src/extensions/wiring.extension.ts rename to src/services/wiring.extension.ts index 8ffde6f..a70790a 100644 --- a/src/extensions/wiring.extension.ts +++ b/src/services/wiring.extension.ts @@ -1,70 +1,69 @@ +/* eslint-disable unicorn/no-process-exit */ import { EventEmitter } from "events"; -import { exit } from "process"; import { + ACTIVE_SLEEPS, ApplicationConfigurationOptions, ApplicationDefinition, BootstrapException, BootstrapOptions, - BuildSortOrder, - CacheProviders, + buildSortOrder, COERCE_CONTEXT, CreateLibrary, each, eachSeries, GetApis, GetApisResult, + ILogger, LoadedModules, + NONE, OptionalModuleConfiguration, ServiceFunction, ServiceMap, SINGLE, StringConfig, + TConfigLogLevel, TLifecycleBase, TServiceParams, TServiceReturn, WIRE_PROJECT, - WireOrder, + wireOrder, WIRING_CONTEXT, } from "../helpers"; -import { InternalDefinition, is, Metrics } from "."; -import { Cache } from "./cache.extension"; +import { ALS, InternalDefinition, is } from "."; import { Configuration, INITIALIZE, INJECTED_DEFINITIONS, LOAD_PROJECT, } from "./configuration.extension"; -import { Fetch } from "./fetch.extension"; import { CreateLifecycle } from "./lifecycle.extension"; -import { ILogger, Logger, TConfigLogLevel } from "./logger.extension"; +import { Logger } from "./logger.extension"; import { Scheduler } from "./scheduler.extension"; +export interface DeclaredEnvironments { + prod: true; + test: true; + local: true; +} + // #MARK: CreateBoilerplate -function CreateBoilerplate() { +function createBoilerplate() { // ! DO NOT MOVE TO ANOTHER FILE ! // While it SEEMS LIKE this can be safely moved, it causes code init race conditions. return CreateLibrary({ configuration: { - CACHE_PREFIX: { - default: "", - description: [ - "Use a prefix with all cache keys", - "If blank, then application name is used", - ].join(`. `), - type: "string", - }, - CACHE_PROVIDER: { - default: "memory", - description: "Redis is preferred if available", - enum: ["redis", "memory"], + ALS_ENABLED: { type: "string", - } satisfies StringConfig<`${CacheProviders}`>, - CACHE_TTL: { - default: 86_400, - description: "Configuration property for cache provider, in seconds", - type: "number", }, + /** + * Only usable by **cli switch**. + * Pass path to a config file for loader + * + * ```bash + * node dist/app.js --config ~/.config/my_app.ini + * ``` + */ CONFIG: { description: [ "Consumable as CLI switch only", @@ -73,29 +72,101 @@ function CreateBoilerplate() { ].join(". "), type: "string", }, + /** + * > by default true when: + * + * ```typescript + * NODE_ENV === "test*" + * ``` + * + * --- + * + * When set + */ + IS_TEST: { + // test | testing + default: process.env.NODE_ENV?.startsWith("test"), + description: "Quick reference for if this app is currently running with test mode", + type: "boolean", + }, + /** + * ### `trace` + * + * Very noisy, contains extra details about what's going on in the internals. + * + * ### `debug` + * + * Additional diagnostic information about operations being form. `"did a thing w/ {name}"` is common. + * + * ### `info` + * + * Notifications for high level events, and app code. + * + * ### `warn` + * + * Notification that an non-critical issue happened. + * + * ### `error` + * + * Error logs are produced from unexpected situations. + * + * When an external API sends back an error messages, or tools are being used in a detectably wrong way. + * + * ### `fatal` + * + * Produce a log at the highest importance level, not common + * + * ### `silent` + * + * Emit no logs at all + */ LOG_LEVEL: { default: "trace", description: "Minimum log level to process", - enum: ["silent", "trace", "info", "warn", "debug", "error"], + enum: ["silent", "trace", "info", "warn", "debug", "error", "fatal"], type: "string", - } satisfies StringConfig, - REDIS_URL: { - default: "redis://localhost:6379", - description: - "Configuration property for cache provider, does not apply to memory caching", + } satisfies StringConfig as StringConfig, + /** + * Reference to `process.env.NODE_ENV` by default, `"local"` if not provided + */ + NODE_ENV: { + default: process.env.NODE_ENV || "local", type: "string", - }, + } as StringConfig, }, name: "boilerplate", - // > 🐔 🥚 dependencies - // config system internally resolves this via lifecycle events - priorityInit: ["metrics", "configuration", "logger"], + priorityInit: ["als", "configuration", "logger", "scheduler"], services: { - cache: Cache, + /** + * [AsyncLocalStorage](https://nodejs.org/api/async_context.html) hooks + * + * Use to pass data around bypassing business logic and insert data into logs + */ + als: ALS, + + /** + * @internal + * + * Exposed via `internal.boilerplate.configuration` + * + * Used to directly modify application configuration + */ configuration: Configuration, - fetch: Fetch, + + /** + * @internal + * + * Exposed via `internal.boilerplate.logger` + * + * Used to modify the way the logger works at runtime + */ logger: Logger, - metrics: Metrics, + + /** + * @internal + * + * Used to generate the scheduler that will get injected into other services + */ scheduler: Scheduler, }, }); @@ -103,16 +174,14 @@ function CreateBoilerplate() { // (re)defined at bootstrap // unclear if this variable even serves a purpose beyond types -export let LIB_BOILERPLATE: ReturnType; +export let LIB_BOILERPLATE: ReturnType; +type GenericApp = ApplicationDefinition; -const RUNNING_APPLICATIONS = new Map< - string, - ApplicationDefinition ->(); +const RUNNING_APPLICATIONS = new Map(); // #MARK: QuickShutdown -async function QuickShutdown(reason: string) { - await each([...RUNNING_APPLICATIONS.values()], async (application) => { +async function quickShutdown(reason: string) { + await each([...RUNNING_APPLICATIONS.values()], async application => { application.logger.warn({ reason }, `starting shutdown`); await application.teardown(); }); @@ -123,31 +192,27 @@ const processEvents = new Map([ [ "SIGTERM", async () => { - await QuickShutdown("SIGTERM"); - exit(); + await quickShutdown("SIGTERM"); + process.exit(); }, ], [ "SIGINT", async () => { - await QuickShutdown("SIGINT"); - exit(); + await quickShutdown("SIGINT"); + process.exit(); }, ], // ["uncaughtException", () => {}], // ["unhandledRejection", (reason, promise) => {}], ]); +const DECIMALS = 2; const BOILERPLATE = (internal: InternalDefinition) => - internal.boot.loadedModules.get("boilerplate") as GetApis< - ReturnType - >; + internal.boot.loadedModules.get("boilerplate") as GetApis>; // #MARK: CreateApplication -export function CreateApplication< - S extends ServiceMap, - C extends OptionalModuleConfiguration, ->({ +export function CreateApplication({ name, services = {} as S, configurationLoaders, @@ -157,15 +222,18 @@ export function CreateApplication< }: ApplicationConfigurationOptions) { let internal: InternalDefinition; - priorityInit.forEach((name) => { - if (!is.function(services[name])) { - throw new BootstrapException( - WIRING_CONTEXT, - "MISSING_PRIORITY_SERVICE", - `${name} was listed as priority init, but was not found in services`, - ); - } - }); + if (!is.empty(priorityInit)) { + priorityInit.forEach(name => { + if (!is.function(services[name])) { + throw new BootstrapException( + WIRING_CONTEXT, + "MISSING_PRIORITY_SERVICE", + `${name} was listed as priority init, but was not found in services`, + ); + } + }); + } + const serviceApis = {} as GetApisResult; const application = { [WIRE_PROJECT]: async (internal: InternalDefinition) => { @@ -173,22 +241,19 @@ export function CreateApplication< name as keyof LoadedModules, configuration, ); - await eachSeries( - WireOrder(priorityInit, Object.keys(services)), - async (service) => { - serviceApis[service] = await WireService( - name, - service, - services[service], - internal.boot.lifecycle.events, - internal, - ); - }, - ); + await eachSeries(wireOrder(priorityInit, Object.keys(services)), async service => { + serviceApis[service] = await wireService( + name, + service, + services[service], + internal.boot.lifecycle.events, + internal, + ); + }); const append = internal.boot.options?.appendService; if (!is.empty(append)) { - await eachSeries(Object.keys(append), async (service) => { - await WireService( + await eachSeries(Object.keys(append), async service => { + await wireService( name, service, append[service], @@ -209,7 +274,7 @@ export function CreateApplication< ); } internal = new InternalDefinition(); - await Bootstrap(application, options, internal); + await bootstrap(application, options, internal); application.booted = true; RUNNING_APPLICATIONS.set(name, application); }, @@ -221,24 +286,23 @@ export function CreateApplication< priorityInit, serviceApis, services, - teardown: async () => { + async teardown() { if (!application.booted) { - processEvents.forEach((callback, event) => - process.removeListener(event, callback), - ); + processEvents.forEach((callback, event) => process.removeListener(event, callback)); return; } - await Teardown(internal, application.logger); + await teardown(internal, application.logger); internal?.utils?.event?.removeAllListeners?.(); application.booted = false; internal = undefined; }, + type: "application", } as unknown as ApplicationDefinition; return application; } // #MARK: WireService -async function WireService( +async function wireService( project: string, service: string, definition: ServiceFunction, @@ -256,9 +320,9 @@ async function WireService( const loaded = internal.boot.loadedModules.get(project) ?? {}; internal.boot.loadedModules.set(project, loaded); try { - logger?.trace({ name: WireService }, `initializing`); + logger?.trace({ name: wireService }, `initializing`); const inject = Object.fromEntries( - [...internal.boot.loadedModules.keys()].map((project) => [ + [...internal.boot.loadedModules.keys()].map(project => [ project as keyof TServiceParams, internal.boot.loadedModules.get(project), ]), @@ -266,7 +330,7 @@ async function WireService( loaded[service] = (await definition({ ...inject, - cache: boilerplate?.cache, + als: boilerplate.als, config: boilerplate?.configuration?.[INJECTED_DEFINITIONS](), context, event: internal?.utils?.event, @@ -281,7 +345,7 @@ async function WireService( // Init errors at this level are considered blocking / fatal // eslint-disable-next-line no-console console.error("initialization error", error); - exit(); + process.exit(); } } @@ -310,15 +374,12 @@ const runReady = async (internal: InternalDefinition) => { }; // #MARK: Bootstrap -async function Bootstrap< - S extends ServiceMap, - C extends OptionalModuleConfiguration, ->( +async function bootstrap( application: ApplicationDefinition, - options: BootstrapOptions = {}, + options: BootstrapOptions, internal: InternalDefinition, ) { - // const + const initTime = performance.now(); internal.boot = { application, completedLifecycleEvents: new Set(), @@ -339,46 +400,44 @@ async function Bootstrap< // pre-create loaded module for boilerplate, so it can be attached to `internal` // this allows it to be used as part of `internal` during boilerplate construction // otherwise it'd only be there for everyone else - const api = {} as GetApis>; + const api = {} as GetApis>; internal.boilerplate = api; internal.boot.loadedModules.set("boilerplate", api); STATS.Construct = CONSTRUCT; // * Recreate base eventemitter internal.utils.event = new EventEmitter(); + internal.utils.event.setMaxListeners(NONE); // ? Some libraries need to be aware of // * Generate a new boilerplate module - LIB_BOILERPLATE = CreateBoilerplate(); + LIB_BOILERPLATE = createBoilerplate(); // * Wire it - let start = Date.now(); - await LIB_BOILERPLATE[WIRE_PROJECT](internal, WireService); + let start = performance.now(); + await LIB_BOILERPLATE[WIRE_PROJECT](internal, wireService); - CONSTRUCT.boilerplate = `${Date.now() - start}ms`; + CONSTRUCT.boilerplate = `${(performance.now() - start).toFixed(DECIMALS)}ms`; // ~ configuration - api.configuration?.[LOAD_PROJECT]( - LIB_BOILERPLATE.name, - LIB_BOILERPLATE.configuration, - ); + api.configuration?.[LOAD_PROJECT](LIB_BOILERPLATE.name, LIB_BOILERPLATE.configuration); const logger = api.logger.context(WIRING_CONTEXT); application.logger = logger; - logger.info({ name: Bootstrap }, `[boilerplate] wiring complete`); + logger.info({ name: bootstrap }, `[boilerplate] wiring complete`); // * Wire in various shutdown events processEvents.forEach((callback, event) => { process.on(event, callback); - logger.trace({ event, name: Bootstrap }, "register shutdown event"); + logger.trace({ event, name: bootstrap }, "register shutdown event"); }); // * Add in libraries application.libraries ??= []; - if (!is.undefined(options.appendLibrary)) { + if (!is.undefined(options?.appendLibrary)) { const list = is.array(options.appendLibrary) ? options.appendLibrary : [options.appendLibrary]; - list.forEach((append) => { + list.forEach(append => { application.libraries.some((library, index) => { if (append.name === library.name) { // remove existing @@ -394,24 +453,24 @@ async function Bootstrap< }); } - const order = BuildSortOrder(application, logger); - await eachSeries(order, async (i) => { - start = Date.now(); - logger.info({ name: Bootstrap }, `[%s] init project`, i.name); - await i[WIRE_PROJECT](internal, WireService); - CONSTRUCT[i.name] = `${Date.now() - start}ms`; + const order = buildSortOrder(application, logger); + await eachSeries(order, async i => { + start = performance.now(); + logger.info({ name: bootstrap }, `[%s] init project`, i.name); + await i[WIRE_PROJECT](internal, wireService); + CONSTRUCT[i.name] = `${(performance.now() - start).toFixed(DECIMALS)}ms`; }); - logger.trace({ name: Bootstrap }, `library wiring complete`); + logger.trace({ name: bootstrap }, `library wiring complete`); // * Finally the application - if (options.bootLibrariesFirst) { - logger.warn({ name: Bootstrap }, `bootLibrariesFirst`); + if (options?.bootLibrariesFirst) { + logger.warn({ name: bootstrap }, `bootLibrariesFirst`); } else { - logger.info({ name: Bootstrap }, `init application`); - start = Date.now(); - await application[WIRE_PROJECT](internal, WireService); - CONSTRUCT[application.name] = `${Date.now() - start}ms`; + logger.info({ name: bootstrap }, `init application`); + start = performance.now(); + await application[WIRE_PROJECT](internal, wireService); + CONSTRUCT[application.name] = `${(performance.now() - start).toFixed(DECIMALS)}ms`; } // ? Configuration values provided bootstrap take priority over module level @@ -420,26 +479,20 @@ async function Bootstrap< } // - Kick off lifecycle - logger.debug({ name: Bootstrap }, `[PreInit] running lifecycle callbacks`); + logger.debug({ name: bootstrap }, `[PreInit] running lifecycle callbacks`); STATS.PreInit = await runPreInit(internal); // - Pull in user configurations - logger.debug({ name: Bootstrap }, "loading configuration"); - STATS.Configure = - await BOILERPLATE(internal)?.configuration?.[INITIALIZE](application); + logger.debug({ name: bootstrap }, "loading configuration"); + const config = BOILERPLATE(internal)?.configuration; + STATS.Configure = await config?.[INITIALIZE](application); // - Run through other events in order - logger.debug( - { name: Bootstrap }, - `[PostConfig] running lifecycle callbacks`, - ); + logger.debug({ name: bootstrap }, `[PostConfig] running lifecycle callbacks`); STATS.PostConfig = await runPostConfig(internal); - logger.debug( - { name: Bootstrap }, - `[Bootstrap] running lifecycle callbacks`, - ); + logger.debug({ name: bootstrap }, `[Bootstrap] running lifecycle callbacks`); STATS.Bootstrap = await runBootstrap(internal); - if (options.bootLibrariesFirst) { + if (options?.bootLibrariesFirst) { // * mental note // running between bootstrap & ready seems most appropriate // resources are expected to *technically* be ready at this point, but not finalized @@ -447,21 +500,21 @@ async function Bootstrap< // - hass: socket is open & resources are ready // - fastify: bindings are available but port isn't listening - logger.info({ name: Bootstrap }, `late init application`); - start = Date.now(); - await application[WIRE_PROJECT](internal, WireService); - CONSTRUCT[application.name] = `${Date.now() - start}ms`; + logger.info({ name: bootstrap }, `late init application`); + start = performance.now(); + await application[WIRE_PROJECT](internal, wireService); + CONSTRUCT[application.name] = `${(performance.now() - start).toFixed(DECIMALS)}ms`; } - logger.debug({ name: Bootstrap }, `[Ready] running lifecycle callbacks`); + logger.debug({ name: bootstrap }, `[Ready] running lifecycle callbacks`); STATS.Ready = await runReady(internal); - STATS.Total = `${Date.now() - internal.boot.startup.getTime()}ms`; + STATS.Total = `${(performance.now() - initTime).toFixed(DECIMALS)}ms`; // * App is ready! logger.info( options?.showExtraBootStats - ? { ...STATS, name: Bootstrap } - : { Total: STATS.Total, name: Bootstrap }, + ? { ...STATS, name: bootstrap } + : { Total: STATS.Total, name: bootstrap }, `[%s] application bootstrapped`, application.name, ); @@ -471,45 +524,37 @@ async function Bootstrap< // eslint-disable-next-line no-console console.error("bootstrap failed", error); } - exit(); + + process.exit(); } } // #MARK: Teardown -async function Teardown(internal: InternalDefinition, logger: ILogger) { - if (!internal) { - return; - } +async function teardown(internal: InternalDefinition, logger: ILogger) { // * Announce - logger.warn({ name: Teardown }, `received teardown request`); + logger.warn({ name: teardown }, `received teardown request`); internal.boot.phase = "teardown"; try { // * PreShutdown - logger.debug( - { name: Teardown }, - `[PreShutdown] running lifecycle callbacks`, - ); + logger.debug({ name: teardown }, `[PreShutdown] running lifecycle callbacks`); await internal.boot.lifecycle.exec("PreShutdown"); internal.boot.completedLifecycleEvents.add("PreShutdown"); // * Formally shutting down - logger.info({ name: Teardown }, `tearing down application`); - logger.debug( - { name: Teardown }, - `[ShutdownStart] running lifecycle callbacks`, - ); + logger.info({ name: teardown }, `tearing down application`); + logger.debug({ name: teardown }, `[ShutdownStart] running lifecycle callbacks`); await internal.boot.lifecycle.exec("ShutdownStart"); internal.boot.completedLifecycleEvents.add("ShutdownStart"); - logger.debug( - { name: Teardown }, - `[ShutdownComplete] running lifecycle callbacks`, - ); + + // - clean up active `sleep` calls (can keep tests open and stuff) + ACTIVE_SLEEPS.forEach(i => i.kill("stop")); + + logger.debug({ name: teardown }, `[ShutdownComplete] running lifecycle callbacks`); await internal.boot.lifecycle.exec("ShutdownComplete"); internal.boot.completedLifecycleEvents.add("ShutdownComplete"); } catch (error) { // ! oof - // eslint-disable-next-line no-console - console.error( + global.console.error( { error }, "error occurred during teardown, some lifecycle events may be incomplete", ); @@ -518,12 +563,10 @@ async function Teardown(internal: InternalDefinition, logger: ILogger) { logger.info( { - name: Teardown, + name: teardown, started_at: internal.utils.relativeDate(internal.boot.startup), }, `application terminated`, ); - processEvents.forEach((callback, event) => - process.removeListener(event, callback), - ); + processEvents.forEach((callback, event) => process.removeListener(event, callback)); } diff --git a/src/testing/cache.spec.ts b/src/testing/cache.spec.ts deleted file mode 100644 index c6cfae6..0000000 --- a/src/testing/cache.spec.ts +++ /dev/null @@ -1,343 +0,0 @@ -import { CreateApplication } from ".."; -import { BASIC_BOOT, ServiceTest } from "./testing.helper"; - -describe("Cache Extension", () => { - // * DO NOT REMOVE THIS BLOCK - beforeAll(async () => { - // It does nothing, but somehow magically prevents jest from exploding for no reason - // @ts-expect-error asdf - const preload = CreateApplication({ name: "testing" }); - await preload.bootstrap(BASIC_BOOT); - await preload.teardown(); - }); - afterEach(async () => { - jest.restoreAllMocks(); - }); - - describe("set Method", () => { - it("should successfully set a value in the cache", async () => { - expect.assertions(1); - - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const key = "testKey"; - const value = "testValue"; - await cache.set(key, value); - const result = await cache.get(key); - expect(result).toEqual(value); - }); - }); - }); - - it("should overwrite existing value with the same key", async () => { - expect.assertions(1); - - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const key = "testKey"; - const value1 = "value1"; - const value2 = "value2"; - await cache.set(key, value1); - await cache.set(key, value2); - const result = await cache.get(key); - expect(result).toEqual(value2); - }); - }); - }); - - it("should respect the TTL for a cached item", async () => { - expect.assertions(1); - - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const key = "tempKey"; - const value = "tempValue"; - const ttl = 1; // Time-to-live in seconds - await cache.set(key, value, ttl); - // Wait for the TTL to expire - await new Promise((resolve) => setTimeout(resolve, 1100)); - const result = await cache.get(key); - expect(result).toBeUndefined(); - }); - }); - }); - }); - - describe("get Method", () => { - it("should retrieve the correct value for an existing key", async () => { - expect.assertions(1); - - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const key = "existingKey"; - const expectedValue = "storedValue"; - await cache.set(key, expectedValue); - const result = await cache.get(key); - expect(result).toEqual(expectedValue); - }); - }); - }); - - it("should return the default value for a non-existing key", async () => { - expect.assertions(1); - - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const defaultValue = "default"; - const result = await cache.get("nonExistingKey", defaultValue); - expect(result).toEqual(defaultValue); - }); - }); - }); - - it("should return undefined for a non-existing key when no default value is provided", async () => { - expect.assertions(1); - - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const result = await cache.get("nonExistingKey"); - expect(result).toBeUndefined(); - }); - }); - }); - - it("should handle different types for the default value", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const key = "nonExistingKey"; - const defaultValue = 123; - const result = await cache.get(key, defaultValue); - expect(result).toBe(defaultValue); - }); - }); - }); - const defaultValue = "defaultValue"; - - it("should return the actual value when it is false", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const key = "keyWithFalse"; - const falseValue = false; - await cache.set(key, falseValue); - const result = await cache.get(key, defaultValue); - expect(result).toBe(falseValue); - }); - }); - }); - - it("should return the actual value when it is 0", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const key = "keyWithZero"; - const zeroValue = 0; - await cache.set(key, zeroValue); - const result = await cache.get(key, defaultValue); - expect(result).toBe(zeroValue); - }); - }); - }); - - it("should return the actual value when it is an empty string", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const key = "keyWithEmptyString"; - const emptyStringValue = ""; - await cache.set(key, emptyStringValue); - const result = await cache.get(key, defaultValue); - expect(result).toBe(emptyStringValue); - }); - }); - }); - - it("should return the actual value when it is null", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const key = "keyWithNull"; - const nullValue = null as null; - await cache.set(key, nullValue); - const result = await cache.get(key, defaultValue); - expect(result).toBe(nullValue); - }); - }); - }); - - it("should return the default value for a key that is not set in the cache (undefined)", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const key = "keyNotSet"; - const defaultValue = "defaultValue"; - // No value is set for 'keyNotSet' - const result = await cache.get(key, defaultValue); - expect(result).toEqual(defaultValue); // Expecting the default value as the key is not set in the cache}); - }); - }); - }); - - it.skip("should return the default value for a non-existing key, regardless of its type", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const defaultStringValue = "defaultString"; - const defaultNumberValue = 42; - const defaultObjectValue = { default: "object" }; - - const resultString = await cache.get( - "nonExistingStringKey", - defaultStringValue, - ); - const resultNumber = await cache.get( - "nonExistingNumberKey", - defaultNumberValue, - ); - const resultObject = await cache.get( - "nonExistingObjectKey", - defaultObjectValue, - ); - - expect(resultString).toEqual(defaultStringValue); - expect(resultNumber).toEqual(defaultNumberValue); - expect(resultObject).toEqual(defaultObjectValue); - }); - }); - }); - }); - - describe("del Method", () => { - it("should successfully delete an existing key from the cache", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const key = "keyToDelete"; - await cache.set(key, "value"); - await cache.del(key); - const result = await cache.get(key); - expect(result).toBeUndefined(); - }); - }); - }); - - it.skip("should confirm that a non-existing key is not in the cache after a delete operation", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const nonExistingKey = "nonExistingKey"; - // Initial check to confirm the key is not already in the cache - const initialResult = await cache.get(nonExistingKey); - expect(initialResult).toBeUndefined(); - - await cache.del(nonExistingKey); - // Recheck to confirm the key is still not in the cache - const finalResult = await cache.get(nonExistingKey); - expect(finalResult).toBeUndefined(); - }); - }); - }); - - it("should handle deletion of a key with a falsey value correctly", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - const falseyKey = "falseyKey"; - await cache.set(falseyKey, 0); // Or other falsey values like '', false, null - await cache.del(falseyKey); - const result = await cache.get(falseyKey); - expect(result).toBeUndefined(); - }); - }); - }); - }); - - describe.skip("keys Method", () => { - it("should return all keys in the cache when no pattern is provided", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - // Setting up multiple keys in the cache - await cache.set("key1", "value1"); - await cache.set("key2", "value2"); - await cache.set("key3", "value3"); - - const allKeys = await cache.keys(); - expect(allKeys).toContain("key1"); - expect(allKeys).toContain("key2"); - expect(allKeys).toContain("key3"); - }); - }); - }); - - it("should return keys matching a specific pattern", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - // Setting up keys, some of which match a pattern - await cache.set("match1", "value1"); - await cache.set("match2", "value2"); - await cache.set("noMatch", "value3"); - - const matchedKeys = await cache.keys("match*"); - expect(matchedKeys).toContain("match1"); - expect(matchedKeys).toContain("match2"); - expect(matchedKeys).not.toContain("noMatch"); - }); - }); - }); - - it("should return an empty array if no keys match the pattern", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle }) => { - lifecycle.onReady(async () => { - // Assuming the cache is clear or the pattern is very unique - const noMatchKeys = await cache.keys("nonExistentPattern*"); - expect(noMatchKeys).toEqual([]); - }); - }); - }); - }); - - describe("Cache Operation Metrics", () => { - it("should increment CACHE_SET_OPERATIONS_TOTAL on set operations", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle, internal }) => { - lifecycle.onReady(async () => { - await cache.set("testKey", "testValue"); - const newCount = ( - await internal.boilerplate.metrics.CACHE_SET_OPERATIONS_TOTAL.get() - ).values[0].value; - expect(newCount).toBe(1); - }); - }); - }); - - it("should increment CACHE_GET_OPERATIONS_TOTAL on get operations", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle, internal }) => { - lifecycle.onReady(async () => { - await cache.get("testKey"); - const newCount = ( - await internal.boilerplate.metrics.CACHE_GET_OPERATIONS_TOTAL.get() - ).values[0].value; - expect(newCount).toBe(1); - }); - }); - }); - - it("should increment CACHE_DELETE_OPERATIONS_TOTAL on delete operations", async () => { - expect.assertions(1); - await ServiceTest(({ cache, lifecycle, internal }) => { - lifecycle.onReady(async () => { - await cache.del("testKey"); - const newCount = ( - await internal.boilerplate.metrics.CACHE_DELETE_OPERATIONS_TOTAL.get() - ).values[0].value; - expect(newCount).toBe(1); - }); - }); - }); - }); -}); diff --git a/src/testing/config-testing.extension.ts b/src/testing/config-testing.extension.ts deleted file mode 100644 index 24d2737..0000000 --- a/src/testing/config-testing.extension.ts +++ /dev/null @@ -1,135 +0,0 @@ -import { faker } from "@faker-js/faker"; -import { existsSync, unlinkSync, writeFileSync } from "fs"; -import { encode as iniEncode } from "ini"; -import { dump as yamlDump } from "js-yaml"; -import { homedir } from "os"; -import { extname, join } from "path"; -import { cwd } from "process"; - -import { is } from ".."; -import { SINGLE, TServiceParams } from "../helpers"; - -export type RandomFileTestingDataFormat = ReturnType; -function generateRandomData() { - return { - testing: { - boolean: faker.datatype.boolean(), - internal: { - mqtt: { - host: faker.internet.ip(), - port: faker.number.int({ max: 65_535, min: 1024 }), - }, - }, - number: faker.number.int(), - record: { - key1: faker.lorem.word(), - key2: faker.lorem.word(), - }, - string: faker.lorem.word(), - stringArray: [faker.lorem.word(), faker.lorem.word(), faker.lorem.word()], - }, - }; -} - -export function ConfigTesting({ lifecycle }: TServiceParams) { - const appName = "testing"; - const testDataMap = new Map(); - - function writeConfigFile( - filePath: string, - data: RandomFileTestingDataFormat, - encodingType?: string, - ) { - let content; - encodingType = encodingType || extname(filePath).slice(SINGLE) || "ini"; - - switch (encodingType) { - case "json": - content = JSON.stringify(data); - break; - case "yaml": - content = yamlDump(data); - break; - default: - content = iniEncode(data); // Default to ini - break; - } - - writeFileSync(filePath, content); - testDataMap.set(filePath, data); - } - - function unlink(path?: string) { - if (path) { - if (testDataMap.has(path)) { - existsSync(path) && unlinkSync(path); - testDataMap.delete(path); - return; - } - return; - } - testDataMap.forEach((_, filePath) => { - existsSync(filePath) && unlinkSync(filePath); - }); - } - - lifecycle.onPreShutdown(() => { - unlink(); - [...testDataMap.keys()].forEach((i) => testDataMap.delete(i)); - }); - - return { - dataMap: testDataMap, - link: (paths?: string[]) => { - const list = is.unique( - is.empty(paths) - ? [cwd(), join(homedir(), ".config")].flatMap((base) => [ - join(base, `.${appName}`), - join(base, `.${appName}.json`), - join(base, `.${appName}.ini`), - join(base, `.${appName}.yaml`), - ]) - : paths, - ); - list.forEach((filename) => { - // console.log(testDataMap); - writeConfigFile(filename, generateRandomData()); - }); - return list; - }, - sort: (filePaths: string[]): string[] => { - const dirOrder = [ - join("/etc", appName, "config"), - join("/etc", appName, "config.json"), - join("/etc", appName, "config.ini"), - join("/etc", appName, "config.yaml"), - join("/etc", appName, "config.yml"), - join("/etc", `${appName}`), - join("/etc", `${appName}.json`), - join("/etc", `${appName}.ini`), - join("/etc", `${appName}.yaml`), - join("/etc", `${appName}.yml`), - join(cwd(), `.${appName}`), - join(cwd(), `.${appName}.json`), - join(cwd(), `.${appName}.ini`), - join(cwd(), `.${appName}.yaml`), - join(cwd(), `.${appName}.yml`), - join(homedir(), ".config", appName), - join(homedir(), ".config", `${appName}.json`), - join(homedir(), ".config", `${appName}.ini`), - join(homedir(), ".config", `${appName}.yaml`), - join(homedir(), ".config", `${appName}.yml`), - join(homedir(), ".config", appName, "config"), - join(homedir(), ".config", appName, "config.json"), - join(homedir(), ".config", appName, "config.ini"), - join(homedir(), ".config", appName, "config.yaml"), - join(homedir(), ".config", appName, "config.yml"), - ].reverse(); - - return filePaths - .filter((path) => dirOrder.includes(path)) - .sort((a, b) => dirOrder.indexOf(a) - dirOrder.indexOf(b)); - }, - unlink, - }; -} diff --git a/src/testing/configuration.spec.ts b/src/testing/configuration.spec.ts deleted file mode 100644 index e8e51d8..0000000 --- a/src/testing/configuration.spec.ts +++ /dev/null @@ -1,649 +0,0 @@ -import { faker } from "@faker-js/faker"; -import dotenv from "dotenv"; -import fs from "fs"; -import { ParsedArgs } from "minimist"; -import { join } from "path"; -import { cwd, env } from "process"; - -import { - ApplicationDefinition, - ConfigLoaderEnvironment, - ConfigLoaderFile, - CreateApplication, - CreateLibrary, - ILogger, - INITIALIZE, - InternalConfig, - InternalDefinition, - loadDotenv, - OptionalModuleConfiguration, - parseConfig, - ServiceMap, - TServiceParams, -} from ".."; -import { ConfigTesting } from "./config-testing.extension"; -import { createMockLogger } from "./helpers"; -import { BASIC_BOOT, ServiceTest } from "./testing.helper"; - -describe("Configuration", () => { - let application: ApplicationDefinition< - ServiceMap, - OptionalModuleConfiguration - >; - - afterEach(async () => { - if (application) { - await application.teardown(); - application = undefined; - } - jest.restoreAllMocks(); - }); - - // #region Initialization - describe("Initialization", () => { - it("should be configured at the correct time in the lifecycle", async () => { - expect.assertions(2); - await ServiceTest(({ internal, lifecycle }) => { - const spy = jest.spyOn(internal.boilerplate.configuration, INITIALIZE); - lifecycle.onPreInit(() => { - expect(spy).not.toHaveBeenCalled(); - }); - lifecycle.onPostConfig(() => { - expect(spy).toHaveBeenCalled(); - }); - }); - }); - - it("should prioritize bootstrap config over defaults", async () => { - expect.assertions(1); - await ServiceTest(({ config, lifecycle }) => { - lifecycle.onPostConfig(() => { - expect(config.boilerplate.LOG_LEVEL).toBe("silent"); - }); - }); - }); - - it("should have the correct defaults for boilerplate", async () => { - expect.assertions(6); - // hide logs that result from lack of "silent" LOG_LEVEL - jest.spyOn(console, "log").mockImplementation(() => {}); - jest.spyOn(console, "error").mockImplementation(() => {}); - await ServiceTest(({ config, lifecycle }) => { - lifecycle.onPostConfig(() => { - expect(config.boilerplate.CACHE_PREFIX).toBe(""); - expect(config.boilerplate.CACHE_PROVIDER).toBe("memory"); - expect(config.boilerplate.CACHE_TTL).toBe(86_400); - expect(config.boilerplate.CONFIG).toBe(undefined); - expect(config.boilerplate.LOG_LEVEL).toBe("trace"); - expect(config.boilerplate.REDIS_URL).toBe("redis://localhost:6379"); - }); - }, {}); - }); - - it("should generate the correct structure for applications", async () => { - expect.assertions(1); - application = CreateApplication({ - configuration: { - FOO: { - default: "bar", - type: "string", - }, - }, - configurationLoaders: [], - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config }: TServiceParams) { - // @ts-expect-error testing - expect(config.testing.FOO).toBe("bar"); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("should generate the correct structure for libraries", async () => { - expect.assertions(1); - application = CreateApplication({ - configuration: { - FOO: { - default: "bar", - type: "string", - }, - }, - configurationLoaders: [], - libraries: [ - CreateLibrary({ - configuration: { - RAINING: { - default: false, - type: "boolean", - }, - }, - // @ts-expect-error testing - name: "library", - services: {}, - }), - ], - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config }: TServiceParams) { - // @ts-expect-error testing - expect(config.library.RAINING).toBe(false); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - }); - // #endregion - // #region Loaders - describe("Loaders", () => { - describe("General", () => { - afterEach(() => { - delete env["DO_NOT_LOAD"]; - }); - it("should not find variables without loaders", async () => { - expect.assertions(1); - env["DO_NOT_LOAD"] = "env"; - // process.argv.push("--current_WEATHER=hail"); - application = CreateApplication({ - configuration: { - DO_NOT_LOAD: { - default: "unloaded", - type: "string", - }, - }, - configurationLoaders: [], - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config, lifecycle }: TServiceParams) { - lifecycle.onPostConfig(() => { - // @ts-expect-error testing - expect(config.testing.DO_NOT_LOAD).toBe("unloaded"); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - }); - - // #MARK: Environment - describe("Environment", () => { - afterEach(() => { - delete env["current_weather"]; - delete env["current_WEATHER"]; - delete env["CURRENT_WEATHER"]; - }); - it("should default properly if environment variables do not exist", async () => { - expect.assertions(1); - application = CreateApplication({ - configuration: { - CURRENT_WEATHER: { - default: "raining", - type: "string", - }, - }, - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config, lifecycle }: TServiceParams) { - lifecycle.onPostConfig(() => { - // @ts-expect-error testing - expect(config.testing.CURRENT_WEATHER).toBe("raining"); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("should do direct match by key", async () => { - expect.assertions(1); - env["CURRENT_WEATHER"] = "windy"; - application = CreateApplication({ - configuration: { - CURRENT_WEATHER: { - default: "raining", - type: "string", - }, - }, - configurationLoaders: [ConfigLoaderEnvironment], - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config, lifecycle }: TServiceParams) { - lifecycle.onPostConfig(() => { - // @ts-expect-error testing - expect(config.testing.CURRENT_WEATHER).toBe("windy"); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("should wrong case (all lower)", async () => { - expect.assertions(1); - env["current_weather"] = "sunny"; - application = CreateApplication({ - configuration: { - CURRENT_WEATHER: { - default: "raining", - type: "string", - }, - }, - configurationLoaders: [ConfigLoaderEnvironment], - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config, lifecycle }: TServiceParams) { - lifecycle.onPostConfig(() => { - // @ts-expect-error testing - expect(config.testing.CURRENT_WEATHER).toBe("sunny"); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("should wrong case (mixed)", async () => { - expect.assertions(1); - env["current_WEATHER"] = "hail"; - application = CreateApplication({ - configuration: { - CURRENT_WEATHER: { - default: "raining", - type: "string", - }, - }, - configurationLoaders: [ConfigLoaderEnvironment], - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config, lifecycle }: TServiceParams) { - lifecycle.onPostConfig(() => { - // @ts-expect-error testing - expect(config.testing.CURRENT_WEATHER).toBe("hail"); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - }); - - // #MARK: CLI Switches - describe("CLI Switch", () => { - beforeEach(() => { - process.argv = ["/path/to/node", "/path/to/main"]; - }); - - it("should default properly if environment variables do not exist", async () => { - expect.assertions(1); - application = CreateApplication({ - configuration: { - CURRENT_WEATHER: { - default: "raining", - type: "string", - }, - }, - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config, lifecycle }: TServiceParams) { - lifecycle.onPostConfig(() => { - // @ts-expect-error testing - expect(config.testing.CURRENT_WEATHER).toBe("raining"); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("should do direct match by key", async () => { - expect.assertions(1); - process.argv.push("--CURRENT_WEATHER", "windy"); - application = CreateApplication({ - configuration: { - CURRENT_WEATHER: { - default: "raining", - type: "string", - }, - }, - configurationLoaders: [ConfigLoaderEnvironment], - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config, lifecycle }: TServiceParams) { - lifecycle.onPostConfig(() => { - // @ts-expect-error testing - expect(config.testing.CURRENT_WEATHER).toBe("windy"); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("should wrong case (all lower)", async () => { - expect.assertions(1); - process.argv.push("--current_weather", "sunny"); - application = CreateApplication({ - configuration: { - CURRENT_WEATHER: { - default: "raining", - type: "string", - }, - }, - configurationLoaders: [ConfigLoaderEnvironment], - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config, lifecycle }: TServiceParams) { - lifecycle.onPostConfig(() => { - // @ts-expect-error testing - expect(config.testing.CURRENT_WEATHER).toBe("sunny"); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("should wrong case (mixed)", async () => { - expect.assertions(1); - process.argv.push("--current_WEATHER", "hail"); - application = CreateApplication({ - configuration: { - CURRENT_WEATHER: { - default: "raining", - type: "string", - }, - }, - configurationLoaders: [ConfigLoaderEnvironment], - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config, lifecycle }: TServiceParams) { - lifecycle.onPostConfig(() => { - // @ts-expect-error testing - expect(config.testing.CURRENT_WEATHER).toBe("hail"); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("is valid with equals signs", async () => { - expect.assertions(1); - process.argv.push("--current_WEATHER=hail"); - application = CreateApplication({ - configuration: { - CURRENT_WEATHER: { - default: "raining", - type: "string", - }, - }, - configurationLoaders: [ConfigLoaderEnvironment], - // @ts-expect-error testing - name: "testing", - services: { - Testing({ config, lifecycle }: TServiceParams) { - lifecycle.onPostConfig(() => { - // @ts-expect-error testing - expect(config.testing.CURRENT_WEATHER).toBe("hail"); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - }); - - // #MARK: File - describe("File", () => { - it("resolves files in the correct order", async () => { - let testFiles: ReturnType; - const helper = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "helper", - services: { - ConfigTesting, - // @ts-expect-error Testing - Helper({ helper }: TServiceParams) { - testFiles = helper.ConfigTesting; - }, - }, - }); - await helper.bootstrap(BASIC_BOOT); - await helper.teardown(); - const keys = [...testFiles.dataMap.keys()]; - let sortedFiles = testFiles.sort(keys); - - for (const filePath of sortedFiles) { - const expectedData = testFiles.dataMap.get(filePath).testing.string; - - application = CreateApplication({ - configuration: { - string: { - default: "testing default value", - type: "string", - }, - }, - configurationLoaders: [ConfigLoaderFile], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ lifecycle, config }: TServiceParams) { - lifecycle.onPostConfig(() => { - // @ts-expect-error Testing - expect(config.testing.string).toBe(expectedData); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - await application.teardown(); - application = undefined; - testFiles.unlink(filePath); - sortedFiles = testFiles.sort([...testFiles.dataMap.keys()]); - } - }); - }); - }); - // #endregion - - describe("Support functions", () => { - // #MARK: parseConfig - describe("parseConfig", () => { - it("string config (no enum)", () => { - const value = faker.string.alphanumeric(); - const output = parseConfig({ type: "string" }, value); - expect(output).toBe(value); - }); - - it("string config (with enum)", () => { - const value = faker.string.alphanumeric(); - // no logic related to enum currently, might be future logic - const output = parseConfig( - { enum: ["hello", "world"], type: "string" }, - value, - ); - expect(output).toBe(value); - }); - - it("number config", () => { - const value = faker.string.numeric(); - const output = parseConfig({ type: "number" }, value); - expect(output).toBe(Number(value)); - }); - - it("string[] config", () => { - const value = JSON.stringify(["hello", "world"]); - const output = parseConfig({ type: "string[]" }, value); - expect(output).toEqual(["hello", "world"]); - }); - - it("record config", () => { - const value = JSON.stringify({ key: "value" }); - const output = parseConfig({ type: "record" }, value); - expect(output).toEqual({ key: "value" }); - }); - - it("internal config", () => { - const value = JSON.stringify({ internalKey: "internalValue" }); - const output = parseConfig( - { type: "internal" } as InternalConfig, - value, - ); - expect(output).toEqual({ internalKey: "internalValue" }); - }); - - it("boolean config (true case)", () => { - const value = "true"; - const output = parseConfig({ type: "boolean" }, value); - expect(output).toBe(true); - }); - - it("boolean config (false case)", () => { - const value = "false"; - const output = parseConfig({ type: "boolean" }, value); - expect(output).toBe(false); - }); - - it("boolean config (yes case)", () => { - const value = "y"; - const output = parseConfig({ type: "boolean" }, value); - expect(output).toBe(true); - }); - - it("boolean config (no case)", () => { - const value = "n"; - const output = parseConfig({ type: "boolean" }, value); - expect(output).toBe(false); - }); - }); - - describe("loadDotenv", () => { - let mockInternal: InternalDefinition; - let logger: ILogger; - - beforeEach(() => { - mockInternal = { - boot: { - options: { - envFile: "", - }, - }, - } as InternalDefinition; - logger = createMockLogger(); - }); - - it("should load env file from CLI switch if provided", () => { - jest.spyOn(fs, "existsSync").mockReturnValue(true); - const config = jest - .spyOn(dotenv, "config") - // @ts-expect-error idc - .mockReturnValue(() => undefined); - const CLI_SWITCHES = { - _: [], - "env-file": "path/to/env-file", - } as ParsedArgs; - - loadDotenv(mockInternal, CLI_SWITCHES, logger); - - expect(config).toHaveBeenCalledWith({ - override: true, - path: join(cwd(), "path/to/env-file"), - }); - }); - - it("should load env file from bootstrap if CLI switch is not provided", () => { - const config = jest - .spyOn(dotenv, "config") - // @ts-expect-error idc - .mockReturnValue(() => undefined); - jest.spyOn(fs, "existsSync").mockReturnValue(true); - mockInternal.boot.options.envFile = "path/to/bootstrap-env-file"; - - const CLI_SWITCHES = { - _: [], - "env-file": "", - } as ParsedArgs; - - loadDotenv(mockInternal, CLI_SWITCHES, logger); - - expect(config).toHaveBeenCalledWith({ - override: true, - path: join(cwd(), "path/to/bootstrap-env-file"), - }); - }); - - it("should load default .env file if no CLI switch or bootstrap envFile is provided", () => { - mockInternal.boot.options.envFile = ""; - jest.spyOn(fs, "existsSync").mockReturnValue(true); - - const config = jest - .spyOn(dotenv, "config") - // @ts-expect-error idc - .mockReturnValue(() => undefined); - - const CLI_SWITCHES = { - _: [], - "env-file": "", - } as ParsedArgs; - - loadDotenv(mockInternal, CLI_SWITCHES, logger); - - expect(config).toHaveBeenCalledWith({ - override: true, - path: join(cwd(), ".env"), - }); - }); - - it("should log a warning if the specified envFile does not exist", () => { - mockInternal.boot.options.envFile = "nonexistent-file"; - - const CLI_SWITCHES = { - _: [], - "env-file": "", - } as ParsedArgs; - jest.spyOn(fs, "existsSync").mockReturnValue(false); - - const config = jest - .spyOn(dotenv, "config") - // @ts-expect-error idc - .mockReturnValue(() => undefined); - - loadDotenv(mockInternal, CLI_SWITCHES, logger); - expect(config).not.toHaveBeenCalled(); - }); - - it("should do nothing if no valid envFile or .env file exists", () => { - mockInternal.boot.options.envFile = ""; - - const CLI_SWITCHES = { - _: [], - "env-file": "", - } as ParsedArgs; - jest.spyOn(fs, "existsSync").mockReturnValue(false); - - const config = jest - .spyOn(dotenv, "config") - // @ts-expect-error idc - .mockReturnValue(() => undefined); - - loadDotenv(mockInternal, CLI_SWITCHES, logger); - expect(config).not.toHaveBeenCalled(); - }); - }); - }); -}); diff --git a/src/testing/fetch.spec.ts b/src/testing/fetch.spec.ts deleted file mode 100644 index c3100e4..0000000 --- a/src/testing/fetch.spec.ts +++ /dev/null @@ -1,452 +0,0 @@ -import { CreateApplication, is } from ".."; -import { BASIC_BOOT, ServiceTest } from "./testing.helper"; - -describe("Fetch Extension", () => { - beforeAll(async () => { - // @ts-expect-error testing - const preload = CreateApplication({ name: "testing" }); - await preload.bootstrap(BASIC_BOOT); - await preload.teardown(); - }); - - afterEach(async () => { - jest.restoreAllMocks(); - }); - - describe("Creation", () => { - it("should initialize properly", async () => { - expect.assertions(7); - await ServiceTest(({ internal, context }) => { - expect(internal.boilerplate.fetch).toBeDefined(); - const HEADERS = { TEST: "ing" }; - const data = internal.boilerplate.fetch({ - baseUrl: "http://foo.bar", - context, - headers: HEADERS, - }); - expect(data.download).toBeDefined(); - expect(data.fetch).toBeDefined(); - expect(is.function(data.setBaseUrl)).toBe(true); - expect(is.function(data.setHeaders)).toBe(true); - expect(data.base_url).toBe("http://foo.bar"); - expect(data.base_headers).toBe(HEADERS); - }); - }); - - it("updates base_url", async () => { - expect.assertions(2); - await ServiceTest(({ internal, context }) => { - const data = internal.boilerplate.fetch({ - baseUrl: "http://foo.bar", - context, - }); - expect(data.base_url).toBe("http://foo.bar"); - data.setBaseUrl("http://example.com"); - expect(data.base_url).toBe("http://example.com"); - }); - }); - - it("updates headers", async () => { - expect.assertions(2); - await ServiceTest(({ internal, context }) => { - const HEADERS = { TEST: "ing" }; - const UPDATE = { FOO: "ing?" }; - const data = internal.boilerplate.fetch({ - baseUrl: "http://foo.bar", - context, - headers: HEADERS, - }); - expect(data.base_headers).toBe(HEADERS); - data.setHeaders(UPDATE); - expect(data.base_headers).toBe(UPDATE); - }); - }); - }); - - describe("execFetch", () => { - it("provides a default content type for object bodies", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - // @ts-expect-error testing - const fetchSpy = jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue("{}"), - }); - const fetcher = await internal.boilerplate.fetch({ - baseUrl: "http://foo.bar", - context, - }); - - fetcher.fetch({ body: { key: "value" }, method: "post" }); - expect(fetchSpy).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - headers: expect.objectContaining({ - "Content-Type": "application/json", - }), - }), - ); - }); - }); - - it("properly forms urls", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - // @ts-expect-error testing - const fetchSpy = jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue("{}"), - }); - await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({ params: { key: "value" }, url: "/endpoint" }); - expect(fetchSpy).toHaveBeenCalledWith( - "http://foo.bar/endpoint?key=value", - expect.any(Object), - ); - }); - }); - - it("merges headers", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - // @ts-expect-error testing - const fetchSpy = jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue("{}"), - }); - await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - headers: { Authorization: "Bearer token" }, - }) - .fetch({ headers: { "Custom-Header": "value" } }); - expect(fetchSpy).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ - headers: expect.objectContaining({ - Authorization: "Bearer token", - "Custom-Header": "value", - }), - }), - ); - }); - }); - - it("passes through method", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - // @ts-expect-error testing - const fetchSpy = jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue("{}"), - }); - await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({ method: "put" }); - expect(fetchSpy).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ method: "put" }), - ); - }); - }); - - it("serializes body", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - // @ts-expect-error testing - const fetchSpy = jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue("{}"), - }); - await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({ body: { key: "value" } }); - expect(fetchSpy).toHaveBeenCalledWith( - expect.any(String), - expect.objectContaining({ body: JSON.stringify({ key: "value" }) }), - ); - }); - }); - - describe("response", () => { - it("handles JSON response correctly", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const jsonResponse = { key: "value" }; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(JSON.stringify(jsonResponse)), - }); - const response = await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({}); - expect(response).toEqual(jsonResponse); - }); - }); - - it("handles text response correctly", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const textResponse = "plain text"; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(textResponse), - }); - const response = await internal.boilerplate - .fetch({ baseUrl: "http://foo.bar", context }) - .fetch({ process: "text" }); - expect(response).toBe(textResponse); - }); - }); - - it("handles raw response correctly", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const rawResponse = new Response("raw response"); - jest.spyOn(global, "fetch").mockResolvedValue(rawResponse); - const response = await internal.boilerplate - .fetch({ baseUrl: "http://foo.bar", context }) - .fetch({ process: "raw" }); - expect(response).toBe(rawResponse); - }); - }); - - it("handles HTTP errors correctly", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const errorResponse = { - error: "Bad Request", - message: "Invalid input", - statusCode: 400, - }; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: false, - text: jest.fn().mockResolvedValue(JSON.stringify(errorResponse)), - }); - await expect( - internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({}), - ).rejects.toThrow("Invalid input"); - }); - }); - - describe("Response handling", () => { - it("returns raw response when process is 'raw'", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const rawResponse = new Response("raw response"); - jest.spyOn(global, "fetch").mockResolvedValue(rawResponse); - const response = await internal.boilerplate - .fetch({ baseUrl: "http://foo.bar", context }) - .fetch({ process: "raw", url: "/foo" }); - expect(response).toBe(rawResponse); - }); - }); - - it("returns text response as string when process is 'text'", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const textResponse = "Some plain text response"; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(textResponse), - }); - const response = await internal.boilerplate - .fetch({ baseUrl: "http://foo.bar", context }) - .fetch({ process: "text", url: "/foo" }); - expect(response).toBe(textResponse); - }); - }); - - it("deserializes JSON response correctly when process is not 'text' or 'raw'", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const jsonResponse = { key: "value" }; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(JSON.stringify(jsonResponse)), - }); - const response = await internal.boilerplate - .fetch({ baseUrl: "http://foo.bar", context }) - .fetch({}); - expect(response).toEqual(jsonResponse); - }); - }); - - it("returns non-JSON text response as string", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const textResponse = "Unexpected response"; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(textResponse), - }); - const response = await internal.boilerplate - .fetch({ baseUrl: "http://foo.bar", context }) - .fetch({}); - expect(response).toBe(textResponse); - }); - }); - - it("handles 'OK' text response correctly", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const textResponse = "OK"; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(textResponse), - }); - const response = await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({}); - expect(response).toBe(textResponse); - }); - }); - - it("handles unexpected API response correctly", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const textResponse = "Unexpected response"; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(textResponse), - }); - const response = await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({}); - expect(response).toBe(textResponse); - }); - }); - }); - - describe("Response handling based on leading characters", () => { - it("deserializes JSON response starting with '{'", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const jsonResponse = { key: "value" }; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(JSON.stringify(jsonResponse)), - }); - const response = await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({}); - expect(response).toEqual(jsonResponse); - }); - }); - - it("deserializes JSON response starting with '['", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const jsonResponse = [{ key: "value" }]; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(JSON.stringify(jsonResponse)), - }); - const response = await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({}); - expect(response).toEqual(jsonResponse); - }); - }); - - it("returns text response as string when leading character is not '{' or '['", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const textResponse = "Some plain text response"; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(textResponse), - }); - const response = await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({}); - expect(response).toBe(textResponse); - }); - }); - - it("handles 'OK' text response correctly when leading character is not '{' or '['", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const textResponse = "OK"; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(textResponse), - }); - const response = await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({}); - expect(response).toBe(textResponse); - }); - }); - - it("returns text response as string for unexpected API response", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal, context }) => { - const textResponse = "Unexpected response"; - // @ts-expect-error testing - jest.spyOn(global, "fetch").mockResolvedValue({ - ok: true, - text: jest.fn().mockResolvedValue(textResponse), - }); - const response = await internal.boilerplate - .fetch({ - baseUrl: "http://foo.bar", - context, - }) - .fetch({}); - expect(response).toBe(textResponse); - }); - }); - }); - }); - }); -}); diff --git a/src/testing/helpers/test-main.ts b/src/testing/helpers/test-main.ts deleted file mode 100644 index b1c9d3c..0000000 --- a/src/testing/helpers/test-main.ts +++ /dev/null @@ -1,44 +0,0 @@ -// magic import, don't touch -import "../.."; - -import { CreateApplication } from "../../extensions"; -import { InternalConfig, TServiceParams } from "../../helpers"; - -type InternalData = { - foo: string; - bar: string; - test: boolean; -}; - -export const HOME_AUTOMATION = CreateApplication({ - configuration: { - TEST_OBJECT_CONFIG: { - default: { - bar: "no", - foo: "yes", - test: false, - }, - type: "internal", - } satisfies InternalConfig, - }, - // @ts-expect-error test - name: "test", - services: { - Test({ logger, config, lifecycle }: TServiceParams) { - lifecycle.onReady(() => { - // @ts-expect-error test - logger.warn({ config: config.test }); - }); - }, - }, -}); - -setImmediate(async () => { - await HOME_AUTOMATION.bootstrap({ - // bootLibrariesFirst: true, - configuration: { - // - }, - // showExtraBootStats: true, - }); -}); diff --git a/src/testing/helpers/index.ts b/src/testing/index.ts similarity index 50% rename from src/testing/helpers/index.ts rename to src/testing/index.ts index b8b12c3..ee4ab07 100644 --- a/src/testing/helpers/index.ts +++ b/src/testing/index.ts @@ -1 +1,2 @@ export * from "./mock-logger"; +export * from "./test-module"; diff --git a/src/testing/internal.spec.ts b/src/testing/internal.spec.ts deleted file mode 100644 index 7d47b52..0000000 --- a/src/testing/internal.spec.ts +++ /dev/null @@ -1,175 +0,0 @@ -import { CreateApplication } from ".."; -import { BASIC_BOOT, ServiceTest } from "./testing.helper"; - -describe("Fetch Extension", () => { - beforeAll(async () => { - // @ts-expect-error testing - const preload = CreateApplication({ name: "testing" }); - await preload.bootstrap(BASIC_BOOT); - await preload.teardown(); - }); - - afterEach(async () => { - jest.restoreAllMocks(); - }); - - describe("TitleCase", () => { - test("converts single word to title case", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - expect(internal.utils.TitleCase("word")).toBe("Word"); - }); - }); - - test("converts multiple words separated by spaces to title case", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - expect(internal.utils.TitleCase("multiple words here")).toBe( - "Multiple Words Here", - ); - }); - }); - - test("converts multiple words separated by underscores to title case", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - expect(internal.utils.TitleCase("multiple_words_here")).toBe( - "Multiple Words Here", - ); - }); - }); - - test("converts multiple words separated by hyphens to title case", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - expect(internal.utils.TitleCase("multiple-words-here")).toBe( - "Multiple Words Here", - ); - }); - }); - - test("inserts spaces between camel case words and converts to title case", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - expect(internal.utils.TitleCase("camelCaseWordsHere")).toBe( - "Camel Case Words Here", - ); - }); - }); - - test("handles empty string input", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - expect(internal.utils.TitleCase("")).toBe(""); - }); - }); - - test("handles single character input", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - expect(internal.utils.TitleCase("a")).toBe("A"); - }); - }); - - test("handles input with mixed delimiters", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - expect(internal.utils.TitleCase("mixed_delimiters-here now")).toBe( - "Mixed Delimiters Here Now", - ); - }); - }); - }); - - describe("internal.utils.object.del", () => { - test("deletes a top-level property", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - const object = { a: 1, b: 2 }; - internal.utils.object.del(object, "a"); - expect(object).toEqual({ b: 2 }); - }); - }); - - test("deletes a nested property", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - const object = { a: { b: { c: 3 } } }; - internal.utils.object.del(object, "a.b.c"); - expect(object).toEqual({ a: { b: {} } }); - }); - }); - - test("does nothing if the path does not exist", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - const object = { a: { b: { c: 3 } } }; - internal.utils.object.del(object, "a.b.x"); - expect(object).toEqual({ a: { b: { c: 3 } } }); - }); - }); - - test("handles path to a non-object gracefully", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - const object = { a: 1 }; - internal.utils.object.del(object, "a.b.c"); - expect(object).toEqual({ a: 1 }); - }); - }); - - test("handles deleting from an empty path", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - const object = { a: 1 }; - internal.utils.object.del(object, ""); - expect(object).toEqual({ a: 1 }); - }); - }); - - test("handles null or undefined values in the path", async () => { - expect.assertions(1); - await ServiceTest(({ internal }) => { - const object = { a: { b: null } } as object; - internal.utils.object.del(object, "a.b.c"); - expect(object).toEqual({ a: { b: null } }); - }); - }); - }); - - describe("internal.safeExec", () => { - test("executes the provided function successfully", async () => { - expect.assertions(1); - await ServiceTest(async ({ internal }) => { - const mockFunction = jest.fn(); - - await internal.safeExec(mockFunction); - - expect(mockFunction).toHaveBeenCalled(); - }); - }); - - test("catches and logs errors thrown by the provided function", async () => { - expect.assertions(2); - await ServiceTest(async ({ internal }) => { - const mockFunction = jest.fn().mockImplementation(() => { - throw new Error("Test error"); - }); - const mockLogger = jest.spyOn( - internal.boilerplate.logger.systemLogger, - "error", - ); - - await internal.safeExec(mockFunction); - - expect(mockFunction).toHaveBeenCalled(); - expect(mockLogger).toHaveBeenCalledWith( - expect.objectContaining({ error: expect.any(Error) }), - "callback threw error", - ); - - mockLogger.mockRestore(); - }); - }); - }); -}); diff --git a/src/testing/logger.spec.ts b/src/testing/logger.spec.ts deleted file mode 100644 index c2aea45..0000000 --- a/src/testing/logger.spec.ts +++ /dev/null @@ -1,196 +0,0 @@ -/* eslint-disable unicorn/escape-case */ -/* eslint-disable unicorn/no-hex-escape */ -// magic import, do not remove / put anything above -import ".."; - -import dayjs from "dayjs"; - -import { CreateApplication, is } from "../extensions"; -import { - ApplicationDefinition, - BootstrapOptions, - OptionalModuleConfiguration, - ServiceMap, - TServiceParams, -} from "../helpers"; - -const BASIC_BOOT = { - configuration: { - boilerplate: { LOG_LEVEL: "silent" }, - }, -} as BootstrapOptions; - -describe("Logger", () => { - let application: ApplicationDefinition< - ServiceMap, - OptionalModuleConfiguration - >; - - afterEach(async () => { - if (application) { - await application.teardown(); - application = undefined; - } - jest.restoreAllMocks(); - }); - - describe("Configuration Interactions", () => { - it("can log stuff by default", async () => { - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: { - Test({ internal }: TServiceParams) { - expect(is.empty(internal.boilerplate.logger.getShouldILog())).toBe( - false, - ); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("updates onPostConfig", async () => { - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: { - Test({ internal, lifecycle }: TServiceParams) { - const spy = jest.spyOn( - internal.boilerplate.logger, - "updateShouldLog", - ); - lifecycle.onReady(() => { - expect(spy).toHaveBeenCalled(); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("updates when LOG_LEVEL changes", async () => { - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: { - Test({ internal }: TServiceParams) { - const spy = jest.spyOn( - internal.boilerplate.logger, - "updateShouldLog", - ); - internal.boilerplate.configuration.set( - "boilerplate", - "LOG_LEVEL", - "warn", - ); - expect(spy).toHaveBeenCalled(); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - }); - - describe("Pretty Formatting", () => { - let params: TServiceParams; - const getChalk = async () => (await import("chalk")).default; - let chalk: Awaited>; - const frontDash = " - "; - let YELLOW_DASH: string; - let BLUE_TICK: string; - - beforeAll(async () => { - chalk = await getChalk(); - YELLOW_DASH = chalk.yellowBright(frontDash); - BLUE_TICK = chalk.blue(`>`); - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "test", - services: { - Test(serviceParams: TServiceParams) { - params = serviceParams; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("should return the original message if it exceeds MAX_CUTOFF", () => { - const longMessage = "a".repeat(2001); - expect( - params.internal.boilerplate.logger.prettyFormatMessage(longMessage), - ).toBe(longMessage); - }); - - it("should highlight text with # in yellow", () => { - const message = "partA#partB"; - const expected = chalk.yellow("partA#partB"); - expect( - params.internal.boilerplate.logger.prettyFormatMessage(message), - ).toBe(expected); - }); - - it('should highlight ">" in blue between square brackets', () => { - const message = "[A] > [B] > [C]"; - const expected = `${chalk.bold.magenta("A")} ${BLUE_TICK} ${chalk.bold.magenta("B")} ${BLUE_TICK} ${chalk.bold.magenta("C")}`; - expect( - params.internal.boilerplate.logger.prettyFormatMessage(message), - ).toBe(expected); - }); - - it("should strip brackets and highlight text in magenta", () => { - const message = "[Text]"; - const expected = chalk.bold.magenta("Text"); - expect( - params.internal.boilerplate.logger.prettyFormatMessage(message), - ).toBe(expected); - }); - - it("should strip braces and highlight text in gray", () => { - const message = "{Text}"; - const expected = chalk.bold.gray("Text"); - expect( - params.internal.boilerplate.logger.prettyFormatMessage(message), - ).toBe(expected); - }); - - it("should highlight dash at the start of the message in yellow", () => { - const message = " - Text"; - const expected = `${YELLOW_DASH}Text`; - expect( - params.internal.boilerplate.logger.prettyFormatMessage(message), - ).toBe(expected); - }); - }); - - describe("Fine Tuning", () => { - it("allows timestamp format to be configured", async () => { - const format = "ddd HH:mm:ss"; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: { - Test({ logger }: TServiceParams) { - jest.spyOn(console, "error").mockImplementation(() => {}); - jest.spyOn(console, "log").mockImplementation(() => {}); - const spy = jest - .spyOn(dayjs.prototype, "format") - .mockImplementation(() => "timestamp"); - logger.info(`test`); - expect(spy).toHaveBeenCalledWith(format); - }, - }, - }); - await application.bootstrap({ - // ...BASIC_BOOT, - loggerOptions: { timestamp_format: format }, - }); - }); - }); -}); diff --git a/src/testing/helpers/mock-logger.ts b/src/testing/mock-logger.ts similarity index 81% rename from src/testing/helpers/mock-logger.ts rename to src/testing/mock-logger.ts index a7be97d..522b2c2 100644 --- a/src/testing/helpers/mock-logger.ts +++ b/src/testing/mock-logger.ts @@ -1,4 +1,4 @@ -import { ILogger } from "../../extensions"; +import { ILogger } from "../helpers"; export function createMockLogger(): ILogger { return { diff --git a/src/testing/scheduler.spec.ts b/src/testing/scheduler.spec.ts deleted file mode 100644 index da03285..0000000 --- a/src/testing/scheduler.spec.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { schedule } from "node-cron"; - -import { CreateApplication } from ".."; -import { BASIC_BOOT, ServiceTest } from "./testing.helper"; - -jest.mock("node-cron", () => ({ - schedule: jest.fn(), -})); - -describe("Fetch Extension", () => { - beforeAll(async () => { - // @ts-expect-error testing - const preload = CreateApplication({ name: "testing" }); - await preload.bootstrap(BASIC_BOOT); - await preload.teardown(); - }); - - afterEach(async () => { - jest.restoreAllMocks(); - }); - - describe("cron", () => { - test("schedules a cron job and executes successfully", async () => { - expect.assertions(1); - await ServiceTest(async ({ scheduler }) => { - const execMock = jest.fn(); - const cronMock = { - start: jest.fn(), - stop: jest.fn(), - }; - - (schedule as jest.Mock).mockReturnValue(cronMock); - - scheduler.cron({ - exec: execMock, - label: "testLabel", - schedule: "*/5 * * * *", - }); - - expect(schedule).toHaveBeenCalledWith( - "*/5 * * * *", - expect.any(Function), - ); - }); - }); - }); - - describe("sliding", () => { - test("requires the correct args", async () => { - expect.assertions(2); - await ServiceTest(async ({ scheduler }) => { - // @ts-expect-error testing - expect(() => scheduler.sliding({})).toThrow(); - // @ts-expect-error testing - expect(() => scheduler.sliding({ next: () => undefined })).toThrow(); - }); - }); - }); -}); diff --git a/src/testing/test-module.ts b/src/testing/test-module.ts new file mode 100644 index 0000000..212d89d --- /dev/null +++ b/src/testing/test-module.ts @@ -0,0 +1,309 @@ +import { v4 } from "uuid"; + +import { + ApplicationDefinition, + ConfigLoader, + CreateLibrary, + deepExtend, + ILogger, + LibraryDefinition, + LoggerOptions, + ModuleConfiguration, + NONE, + OptionalModuleConfiguration, + PartialConfiguration, + ServiceFunction, + ServiceMap, + TConfigLogLevel, + TLibrary, +} from "../helpers"; +import { CreateApplication, is } from "../services"; + +export type CreateTestingLibraryOptions< + S extends ServiceMap, + C extends OptionalModuleConfiguration, +> = { + /** + * default: testing + */ + name?: string; + target?: LibraryDefinition | ApplicationDefinition; +}; + +type TestingBootstrapOptions = { + /** + * default: false + * + * set to true to have this test emit logs + */ + emitLogs?: boolean; + + /** + * mostly useful for testing deep internals + */ + configLoader?: ConfigLoader; + + /** + * pass through to bootstrap params + */ + loggerOptions?: LoggerOptions; + + /** + * default: false + * + * Should testing apps consider config file / environment variables? + */ + loadConfigs?: boolean; + + /** + * replacement logger object to use + * + * default: **NOOP** + */ + customLogger?: ILogger; + + /** + * matches regular bootstrap options + */ + bootLibrariesFirst?: boolean; + + /** + * default values to use for configurations, before user values come in + */ + configuration?: PartialConfiguration; + + /** + * @internal + * + * define a configuration for the unit tests + * + * > **note**: you probably don't need to do this, it's not even documented + */ + module_config?: ModuleConfiguration; +}; + +export type LibraryTestRunner = + T extends LibraryDefinition ? iTestRunner : never; +export type ApplicationTestRunner = + T extends ApplicationDefinition ? iTestRunner : never; + +export type iTestRunner = { + /** + * chained calls deep merge options together + */ + configure: (configuration: PartialConfiguration) => iTestRunner; + + /** + * chained calls deep merge options together + */ + setOptions: (options: TestingBootstrapOptions) => iTestRunner; + + /** + * sets flag to true + */ + bootLibrariesFirst: () => iTestRunner; + + /** + * for debugging, single command to enable logging on this test + */ + emitLogs: (log_level?: TConfigLogLevel) => iTestRunner; + + /** + * chained calls add multiple setup functions + */ + setup: (test: ServiceFunction) => iTestRunner; + + /** + * returns reference to app that was booted + */ + run: ( + test: ServiceFunction, + ) => Promise>; + + /** + * add a library to the runner beyond what the target module requested + */ + appendLibrary: (library: TLibrary) => iTestRunner; + + /** + * inject an extra service to your module + * + * by default will take the function name as context, can optionally provide the name as 2nd param (if it even matters) + */ + appendService: (service: ServiceFunction, name?: string) => iTestRunner; + + /** + * substitute a library for another by name + */ + replaceLibrary: (name: string, library: TLibrary) => iTestRunner; + + /** + * substitute a service for another in your module + * + * does not check if the substitution is valid + */ + replaceService: (name: string, service: ServiceFunction) => iTestRunner; + + /** + * reference to the app teardown internally + * + * clean up your testing resources! + */ + teardown: () => Promise; + + type: "test"; +}; + +/** + * library optional + */ +export function TestRunner( + options: CreateTestingLibraryOptions = {}, +) { + process.setMaxListeners(NONE); + let teardown: () => Promise; + let bootOptions: TestingBootstrapOptions = {}; + const appendLibraries = new Map(); + const appendServices = new Map(); + const replaceLibrary = new Map(); + const replaceService = new Map(); + const runFirst = new Set(); + + function getLibraries(target: LibraryDefinition | ApplicationDefinition) { + if (target && "depends" in target) { + return target.depends ?? []; + } + return target && "libraries" in target ? target.libraries : []; + } + + function buildApp( + name: string, + target: LibraryDefinition | ApplicationDefinition, + test: ServiceFunction, + ) { + const optional = target && "optionalDepends" in target ? target.optionalDepends : []; + const depends = [...getLibraries(target)]; + + const testLibrary = target + ? CreateLibrary({ + configuration: target.configuration, + depends, + name: target.name, + optionalDepends: optional, + priorityInit: target.priorityInit, + services: Object.fromEntries( + Object.entries(target.services).map(([name, service]) => [ + name, + replaceService.has(name) ? replaceService.get(name) : service, + ]), + ) as S, + }) + : undefined; + let LIB_RUN_FIRST: TLibrary; + if (!is.empty(runFirst)) { + LIB_RUN_FIRST = CreateLibrary({ + depends: testLibrary ? [testLibrary, ...depends] : [...depends], + // @ts-expect-error nothing useful here + name: "run_first", + services: Object.fromEntries( + [...runFirst.values()].map( + service => [service.name || v4(), service] as [string, ServiceFunction], + ), + ) as ServiceMap, + }); + } + + const customLoader = bootOptions?.configLoader ? [bootOptions?.configLoader] : []; + const app = CreateApplication({ + configuration: bootOptions?.module_config ?? {}, + configurationLoaders: bootOptions?.loadConfigs ? undefined : customLoader, + libraries: [ + ...(is.empty(depends) + ? [] + : depends.map(i => (replaceLibrary.has(i.name) ? replaceLibrary.get(i.name) : i))), + ...(testLibrary ? [testLibrary] : []), + ], + // @ts-expect-error it's life + name, + services: { test }, + }); + + return { LIB_RUN_FIRST, app }; + } + + const libraryTestRunner: iTestRunner = { + appendLibrary(library: TLibrary) { + appendLibraries.set(library.name, library); + return libraryTestRunner; + }, + appendService(service: ServiceFunction, name?: string) { + if (is.empty(name) && !is.empty(service.name)) { + name = service.name; + } + appendServices.set(name || v4(), service); + return libraryTestRunner; + }, + bootLibrariesFirst() { + bootOptions.bootLibrariesFirst = true; + return libraryTestRunner; + }, + configure(configuration: PartialConfiguration) { + bootOptions = deepExtend(bootOptions, { configuration }); + return libraryTestRunner; + }, + emitLogs(LOG_LEVEL: TConfigLogLevel) { + libraryTestRunner.setOptions({ emitLogs: true }); + if (!is.empty({ level: LOG_LEVEL })) { + libraryTestRunner.configure({ boilerplate: { LOG_LEVEL } }); + } + return libraryTestRunner; + }, + replaceLibrary(name: string, library: TLibrary) { + replaceLibrary.set(name, library); + return libraryTestRunner; + }, + replaceService(name: string, service: ServiceFunction) { + replaceService.set(name, service); + return libraryTestRunner; + }, + async run(test: ServiceFunction) { + const { app, LIB_RUN_FIRST } = buildApp(options?.name ?? "testing", options?.target, test); + await app.bootstrap({ + appendLibrary: [...appendLibraries.values(), ...(LIB_RUN_FIRST ? [LIB_RUN_FIRST] : [])], + appendService: Object.fromEntries(appendServices.entries()), + bootLibrariesFirst: !!bootOptions?.bootLibrariesFirst, + configuration: bootOptions?.configuration, + customLogger: bootOptions?.emitLogs + ? undefined + : (bootOptions?.customLogger ?? { + debug: jest.fn(), + error: jest.fn(), + fatal: jest.fn(), + info: jest.fn(), + trace: jest.fn(), + warn: jest.fn(), + }), + loggerOptions: bootOptions?.loggerOptions, + }); + + teardown = async () => await app.teardown(); + return app; + }, + setOptions(options: TestingBootstrapOptions) { + bootOptions = deepExtend(bootOptions, options); + return libraryTestRunner; + }, + setup(service: ServiceFunction) { + runFirst.add(service); + return libraryTestRunner; + }, + async teardown() { + if (teardown) { + await teardown(); + teardown = undefined; + } + }, + type: "test", + }; + return libraryTestRunner; +} diff --git a/src/testing/testing.helper.ts b/src/testing/testing.helper.ts deleted file mode 100644 index d7fc841..0000000 --- a/src/testing/testing.helper.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { CreateApplication } from "../extensions"; -import { BootstrapOptions, TBlackHole, TServiceParams } from "../helpers"; - -export const BASIC_BOOT = { - configuration: { boilerplate: { LOG_LEVEL: "silent" } }, -} as BootstrapOptions; - -export async function ServiceTest( - callback: (params: TServiceParams) => TBlackHole, - options: BootstrapOptions = BASIC_BOOT, -) { - const application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error testing - name: "testing", - services: { - async Testing(params: TServiceParams) { - await callback(params); - const { metrics } = params.internal.boilerplate; - const keys = Object.keys(metrics) as (keyof typeof metrics)[]; - keys.forEach((key) => metrics[key].reset()); - }, - }, - }); - await application.bootstrap(options); - await application.teardown(); -} diff --git a/src/testing/utilities.spec.ts b/src/testing/utilities.spec.ts deleted file mode 100644 index d80abdd..0000000 --- a/src/testing/utilities.spec.ts +++ /dev/null @@ -1,104 +0,0 @@ -import { ACTIVE_THROTTLE, debounce, sleep } from "../helpers"; - -describe("utilities", () => { - describe("sleep", () => { - it("should delay execution by the specified timeout", async () => { - const timeout = 100; - const start = Date.now(); - - await sleep(timeout); - - const end = Date.now(); - expect(end - start).toBeGreaterThanOrEqual(timeout); - }); - - it('should stop early when kill("continue") is called', async () => { - const timeout = 200; - const start = Date.now(); - - const timer = sleep(timeout); - setTimeout(() => timer.kill("continue"), 50); - await timer; - - const end = Date.now(); - expect(end - start).toBeGreaterThanOrEqual(50); - expect(end - start).toBeLessThan(timeout); - }); - - it('should not resolve if kill("stop") is called before timeout', async () => { - const timeout = 200; - const start = Date.now(); - - const timer = sleep(timeout); - setTimeout(() => timer.kill("stop"), 50); - await new Promise((resolve) => setTimeout(resolve, 100)); // Wait for 100 milliseconds to ensure the stop has taken effect - - const end = Date.now(); - expect(end - start).toBeGreaterThanOrEqual(100); - expect(end - start).toBeLessThan(timeout); - }); - - it("should handle date object correctly", async () => { - const targetDate = new Date(Date.now() + 100); - const start = Date.now(); - - await sleep(targetDate); - - const end = Date.now(); - expect(end - start).toBeGreaterThanOrEqual(100); - }); - }); - - describe("debounce", () => { - it("should delay execution by the specified timeout", async () => { - const identifier = "test-id"; - const timeout = 10; - const start = Date.now(); - - await debounce(identifier, timeout); - - const end = Date.now(); - expect(end - start).toBeGreaterThanOrEqual(timeout); - }); - - it("should cancel the previous debounce if called with the same identifier", async () => { - const identifier = "test-id"; - const timeout1 = 20; - const timeout2 = 10; - - const start = Date.now(); - debounce(identifier, timeout1); - await debounce(identifier, timeout2); - - const end = Date.now(); - expect(end - start).toBeLessThan(timeout1); - expect(end - start).toBeGreaterThanOrEqual(timeout2); - }); - - it("should allow multiple identifiers to be debounced independently", async () => { - const identifier1 = "test-id-1"; - const identifier2 = "test-id-2"; - const timeout1 = 10; - const timeout2 = 10; - - const start1 = Date.now(); - debounce(identifier1, timeout1); - - const start2 = Date.now(); - await debounce(identifier2, timeout2); - - const end1 = Date.now(); - expect(end1 - start1).toBeGreaterThanOrEqual(timeout1); - expect(end1 - start2).toBeGreaterThanOrEqual(timeout2); - }); - - it("should clear the debounce once the timeout has passed", async () => { - const identifier = "test-id"; - const timeout = 100; - - await debounce(identifier, timeout); - - expect(ACTIVE_THROTTLE.has(identifier)).toBe(false); - }); - }); -}); diff --git a/src/testing/wiring.spec.ts b/src/testing/wiring.spec.ts deleted file mode 100644 index 29ccb93..0000000 --- a/src/testing/wiring.spec.ts +++ /dev/null @@ -1,1236 +0,0 @@ -import { - ApplicationDefinition, - BootstrapException, - BootstrapOptions, - CreateApplication, - CreateLibrary, - InternalDefinition, - LIB_BOILERPLATE, - LifecycleStages, - OptionalModuleConfiguration, - ServiceMap, - sleep, - TServiceParams, -} from ".."; - -const FAKE_EXIT = (() => {}) as () => never; - -const BASIC_BOOT = { - configuration: { boilerplate: { LOG_LEVEL: "silent" } }, -} as BootstrapOptions; - -describe("Wiring", () => { - let application: ApplicationDefinition< - ServiceMap, - OptionalModuleConfiguration - >; - - afterEach(async () => { - if (application) { - await application.teardown(); - application = undefined; - } - jest.restoreAllMocks(); - }); - - // #region CreateLibrary - describe("CreateLibrary", () => { - it("should be defined", () => { - expect(CreateLibrary).toBeDefined(); - expect(CreateApplication).toBeDefined(); - }); - - it("should create a library without services", () => { - const library = CreateLibrary({ - // @ts-expect-error For unit testing - name: "testing", - services: {}, - }); - - expect(library).toBeDefined(); - expect(library.name).toBe("testing"); - expect(library.services).toEqual({}); - }); - - it("throws an error with invalid service definition", () => { - expect(() => { - CreateLibrary({ - // @ts-expect-error For unit testing - name: "testing", - services: { InvalidService: undefined }, - }); - }).toThrow("INVALID_SERVICE_DEFINITION"); - }); - - it("creates multiple libraries with distinct configurations", () => { - const libraryOne = CreateLibrary({ - // @ts-expect-error For unit testing - name: "testing", - services: {}, - }); - const libraryTwo = CreateLibrary({ - // @ts-expect-error For unit testing - name: "testing_second", - services: {}, - }); - expect(libraryOne.name).not.toBe(libraryTwo.name); - }); - - it("throws a BootstrapException for an invalid service definition in a library", () => { - expect(() => { - CreateLibrary({ - // @ts-expect-error For unit testing - name: "testing", - services: { invalidServiceDefinition: undefined }, - }); - }).toThrow(BootstrapException); - }); - - it("throws a BootstrapException if no name is provided for the library", () => { - expect(() => { - // @ts-expect-error that's the test - CreateLibrary({ name: "", services: {} }); - }).toThrow(BootstrapException); - }); - }); - // #endregion - - // #region CreateApplication - describe("CreateApplication", () => { - it("should create an application with specified services and libraries", () => { - const testService = jest.fn(); - const testLibrary = CreateLibrary({ - // @ts-expect-error For unit testing - name: "testing", - services: { TestService: testService }, - }); - - application = CreateApplication({ - configurationLoaders: [], - libraries: [testLibrary], - // @ts-expect-error For unit testing - name: "testing", - services: { AppService: jest.fn() }, - }); - - expect(application).toBeDefined(); - expect(application.name).toBe("testing"); - expect(Object.keys(application.services).length).toBe(1); - expect(application.libraries.length).toBe(1); - expect(application.libraries[0]).toBe(testLibrary); - }); - - it("should only allows a single boot", async () => { - expect.assertions(1); - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: {}, - }); - await application.bootstrap(BASIC_BOOT); - try { - await application.bootstrap(BASIC_BOOT); - } catch (error) { - expect(error.message).toBe("DOUBLE_BOOT"); - } - }); - - it("should allow appending services", async () => { - expect.assertions(1); - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: {}, - }); - await application.bootstrap({ - ...BASIC_BOOT, - appendService: { - Test() { - // always true, the test is that it ran (expect.assertions) - expect(true).toBe(true); - }, - }, - }); - }); - - it("should allow appending libraries", async () => { - expect.assertions(1); - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: {}, - }); - const testLibrary = CreateLibrary({ - // @ts-expect-error For unit testing - name: "testing", - services: { - TestService() { - // always true, the test is that it ran (expect.assertions) - expect(true).toBe(true); - }, - }, - }); - - await application.bootstrap({ - ...BASIC_BOOT, - appendLibrary: testLibrary, - }); - }); - - it("should allow appending multiple libraries", async () => { - expect.assertions(2); - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: {}, - }); - - const testLibrary = CreateLibrary({ - // @ts-expect-error For unit testing - name: "testing", - services: { - TestService() { - // always true, the test is that it ran (expect.assertions) - expect(true).toBe(true); - }, - }, - }); - const testLibraryB = CreateLibrary({ - // @ts-expect-error For unit testing - name: "testing_b", - services: { - TestService() { - // always true, the test is that it ran (expect.assertions) - expect(true).toBe(true); - }, - }, - }); - - await application.bootstrap({ - ...BASIC_BOOT, - appendLibrary: [testLibrary, testLibraryB], - }); - }); - }); - // #endregion - - // #region Lifecycle - describe("Lifecycle", () => { - beforeEach(() => { - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: {}, - }); - }); - - it("should call the lifecycle events in order during application bootstrap", async () => { - // Spy on lifecycle event functions - const spyPreInit = jest.fn(); - const spyPostConfig = jest.fn(); - const spyBootstrap = jest.fn(); - const spyReady = jest.fn(); - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: { - spy({ lifecycle }: TServiceParams) { - lifecycle.onPreInit(() => spyPreInit()); - lifecycle.onPostConfig(() => spyPostConfig()); - lifecycle.onBootstrap(() => spyBootstrap()); - lifecycle.onReady(() => spyReady()); - }, - }, - }); - - // Bootstrap the application - await application.bootstrap(BASIC_BOOT); - - // Check that the lifecycle event functions were called - expect(spyPreInit).toHaveBeenCalled(); - expect(spyPostConfig).toHaveBeenCalled(); - expect(spyBootstrap).toHaveBeenCalled(); - expect(spyReady).toHaveBeenCalled(); - - // Optionally, check the calling order - const callOrder = [ - spyPreInit.mock.invocationCallOrder[0], - spyPostConfig.mock.invocationCallOrder[0], - spyBootstrap.mock.invocationCallOrder[0], - spyReady.mock.invocationCallOrder[0], - ]; - expect(callOrder).toEqual([...callOrder].sort((a, b) => a - b)); - }); - - it("executes lifecycle callbacks in the correct order", async () => { - // Mock callbacks for each lifecycle stage - const mockPreInit = jest.fn(); - const mockPostConfig = jest.fn(); - const mockBootstrap = jest.fn(); - const mockReady = jest.fn(); - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: { - spy({ lifecycle }: TServiceParams) { - lifecycle.onPreInit(() => mockPreInit()); - lifecycle.onPostConfig(() => mockPostConfig()); - lifecycle.onBootstrap(() => mockBootstrap()); - lifecycle.onReady(() => mockReady()); - }, - }, - }); - - // Bootstrap the application - await application.bootstrap(BASIC_BOOT); - - // Retrieve the order in which the mocks were called - const preInitOrder = mockPreInit.mock.invocationCallOrder[0]; - const postConfigOrder = mockPostConfig.mock.invocationCallOrder[0]; - const bootstrapOrder = mockBootstrap.mock.invocationCallOrder[0]; - const readyOrder = mockReady.mock.invocationCallOrder[0]; - - // Verify the order of callback execution - expect(preInitOrder).toBeLessThan(postConfigOrder); - expect(postConfigOrder).toBeLessThan(bootstrapOrder); - expect(bootstrapOrder).toBeLessThan(readyOrder); - }); - - it("registers and invokes lifecycle callbacks correctly", async () => { - const mockCallback = jest.fn(); - - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: { - spy({ lifecycle }: TServiceParams) { - lifecycle.onBootstrap(() => mockCallback()); - }, - }, - }); - - // Bootstrap the application - await application.bootstrap(BASIC_BOOT); - - // Check if the mock callback was invoked - expect(mockCallback).toHaveBeenCalled(); - }); - - it("exits on catastrophic bootstrap errors", async () => { - const errorMock = jest.fn().mockImplementation(() => { - throw new Error("EXPECTED_UNIT_TESTING_ERROR"); - }); - - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: { - spy({ lifecycle }: TServiceParams) { - lifecycle.onBootstrap(() => errorMock()); - }, - }, - }); - - jest.spyOn(console, "error").mockImplementation(() => {}); - const failFastSpy = jest - .spyOn(process, "exit") - .mockImplementation(FAKE_EXIT); - - // Execute the Bootstrap function - await application.bootstrap(BASIC_BOOT); - - // Check if FailFast was called - expect(failFastSpy).toHaveBeenCalled(); - }); - - it("higher numbers go first (positive)", async () => { - const executionOrder: string[] = []; - - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: { - spy({ lifecycle }: TServiceParams) { - lifecycle.onBootstrap( - () => executionOrder.push("LowPriorityBootstrap"), - 1, - ); - lifecycle.onBootstrap( - () => executionOrder.push("HighPriorityBootstrap"), - 10, - ); - }, - }, - }); - - await application.bootstrap(BASIC_BOOT); - - // Define the expected order based on priorities - const expectedOrder = ["HighPriorityBootstrap", "LowPriorityBootstrap"]; - - // Compare the actual execution order with the expected order - expect(executionOrder).toEqual(expectedOrder); - }); - - it("lower numbers go later (negative)", async () => { - const executionOrder: string[] = []; - - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error For unit testing - name: "testing", - services: { - spy({ lifecycle }: TServiceParams) { - lifecycle.onBootstrap( - () => executionOrder.push("LowPriorityBootstrap"), - -10, - ); - lifecycle.onBootstrap( - () => executionOrder.push("HighPriorityBootstrap"), - -1, - ); - }, - }, - }); - - await application.bootstrap(BASIC_BOOT); - - // Define the expected order based on priorities - const expectedOrder = ["HighPriorityBootstrap", "LowPriorityBootstrap"]; - - // Compare the actual execution order with the expected order - expect(executionOrder).toEqual(expectedOrder); - }); - - describe("Completed events", () => { - it("starts off empty", async () => { - let list: LifecycleStages[]; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ lifecycle, internal }: TServiceParams) { - lifecycle.onPreInit( - () => (list = [...internal.boot.completedLifecycleEvents]), - ); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(list).toEqual([]); - }); - - it("tracks onPreInit", async () => { - let list: LifecycleStages[]; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ lifecycle, internal }: TServiceParams) { - lifecycle.onPostConfig( - () => (list = [...internal.boot.completedLifecycleEvents]), - ); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(list).toEqual(["PreInit"]); - }); - - it("tracks onPostConfig", async () => { - let list: LifecycleStages[]; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ lifecycle, internal }: TServiceParams) { - lifecycle.onBootstrap( - () => (list = [...internal.boot.completedLifecycleEvents]), - ); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(list).toEqual(["PreInit", "PostConfig"]); - }); - - it("tracks onPreInit", async () => { - let list: LifecycleStages[]; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ lifecycle, internal }: TServiceParams) { - lifecycle.onReady( - () => (list = [...internal.boot.completedLifecycleEvents]), - ); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(list).toEqual(["PreInit", "PostConfig", "Bootstrap"]); - }); - - it("tracks ready", async () => { - let i: InternalDefinition; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ internal }: TServiceParams) { - i = internal; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect([...i.boot.completedLifecycleEvents.values()]).toEqual([ - "PreInit", - "PostConfig", - "Bootstrap", - "Ready", - ]); - }); - - it("does not change by start of teardown", async () => { - let list: LifecycleStages[]; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ lifecycle, internal }: TServiceParams) { - lifecycle.onPreShutdown( - () => (list = [...internal.boot.completedLifecycleEvents]), - ); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - await application.teardown(); - application = undefined; - expect(list).toEqual(["PreInit", "PostConfig", "Bootstrap", "Ready"]); - }); - - it("tracks preShutdown", async () => { - let list: LifecycleStages[]; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ lifecycle, internal }: TServiceParams) { - lifecycle.onShutdownStart( - () => (list = [...internal.boot.completedLifecycleEvents]), - ); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - await application.teardown(); - application = undefined; - expect(list).toEqual([ - "PreInit", - "PostConfig", - "Bootstrap", - "Ready", - "PreShutdown", - ]); - }); - - it("tracks shutdownStart", async () => { - let list: LifecycleStages[]; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ lifecycle, internal }: TServiceParams) { - lifecycle.onShutdownComplete( - () => (list = [...internal.boot.completedLifecycleEvents]), - ); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - await application.teardown(); - application = undefined; - expect(list).toEqual([ - "PreInit", - "PostConfig", - "Bootstrap", - "Ready", - "PreShutdown", - "ShutdownStart", - ]); - }); - - it("tracks shutdownComplete", async () => { - let i: InternalDefinition; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ internal }: TServiceParams) { - i = internal; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - await application.teardown(); - expect([...i.boot.completedLifecycleEvents.values()]).toEqual([ - "PreInit", - "PostConfig", - "Bootstrap", - "Ready", - "PreShutdown", - "ShutdownStart", - "ShutdownComplete", - ]); - }); - }); - }); - // #endregion - - // #region Bootstrap - describe("Bootstrap", () => { - it("constructs app in between boot and ready for bootLibrariesFirst", async () => { - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ internal }: TServiceParams) { - expect( - internal.boot.completedLifecycleEvents.has("Bootstrap"), - ).toBe(true); - expect(internal.boot.completedLifecycleEvents.has("PreInit")).toBe( - true, - ); - expect( - internal.boot.completedLifecycleEvents.has("PostConfig"), - ).toBe(true); - expect(internal.boot.completedLifecycleEvents.has("Ready")).toBe( - false, - ); - }, - }, - }); - // - await application.bootstrap({ ...BASIC_BOOT, bootLibrariesFirst: true }); - }); - - it("should prioritize services with priorityInit", async () => { - const list = [] as string[]; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - priorityInit: ["First", "Second"], - services: { - First() { - list.push("First"); - }, - Second() { - list.push("Second"); - }, - Third() { - list.push("Third"); - }, - }, - }); - // - await application.bootstrap(BASIC_BOOT); - expect(list).toStrictEqual(["First", "Second", "Third"]); - }); - - it("throws errors with missing priority services", async () => { - expect(() => { - CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - priorityInit: ["Testing"], - services: { - NotTesting() {}, - }, - }); - }).toThrow("MISSING_PRIORITY_SERVICE"); - }); - - it("sets booted after finishing bootstrap", async () => { - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: {}, - }); - await application.bootstrap(BASIC_BOOT); - - expect(application.booted).toBe(true); - }); - - it("forbids double booting", async () => { - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: {}, - }); - await application.bootstrap(BASIC_BOOT); - - // I guess this works 🤷‍♀️ - expect.assertions(1); - try { - await application.bootstrap(BASIC_BOOT); - } catch (error) { - expect(error).toBeDefined(); - } - }); - }); - // #endregion - - // #region Boot Phase - describe("Boot Phase", () => { - it("should exit if service constructor throws error", async () => { - const spy = jest - .spyOn(process, "exit") - .mockImplementation(() => undefined as never); - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Service() { - throw new Error("boom"); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - - expect(spy).toHaveBeenCalled(); - }); - - it("should not have project name in construction complete prior to completion", async () => { - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Service({ internal }: TServiceParams) { - expect(internal.boot.constructComplete.has("testing")).toBe(false); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("should add project name to complete", async () => { - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Service({ internal, lifecycle }: TServiceParams) { - lifecycle.onPreInit(() => { - expect(internal.boot.constructComplete.has("testing")).toBe(true); - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - }); - - it("phase should be bootstrap during boot", async () => { - let i: string; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Service({ internal }: TServiceParams) { - i = internal.boot.phase; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - - expect(i).toBe("bootstrap"); - }); - - it("phase should be running when finished booting", async () => { - let i: InternalDefinition; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Service({ internal }: TServiceParams) { - i = internal; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - - expect(i.boot.phase).toBe("running"); - }); - - it("phase should be teardown after teardown starts", async () => { - let i: string; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Service({ internal, lifecycle }: TServiceParams) { - lifecycle.onPreShutdown(() => { - i = internal.boot.phase; - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - await application.teardown(); - application = undefined; - - expect(i).toBe("teardown"); - }); - }); - // #endregion - - // #region Teardown - describe("Teardown", () => { - it("phase should be teardown after teardown starts", async () => { - let i: string; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Service({ internal, lifecycle }: TServiceParams) { - lifecycle.onPreShutdown(() => { - i = internal.boot.phase; - }); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - await application.teardown(); - application = undefined; - - expect(i).toBe("teardown"); - }); - - it("should shutdown on SIGTERM", async () => { - expect.assertions(1); - const exit = jest - .spyOn(process, "exit") - .mockImplementation(() => undefined as never); - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Service({ lifecycle }: TServiceParams) { - lifecycle.onReady(() => process.emit("SIGTERM")); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - await sleep(10); - expect(exit).toHaveBeenCalled(); - application = undefined; - }); - - it("should shutdown on SIGINT", async () => { - expect.assertions(1); - const exit = jest - .spyOn(process, "exit") - .mockImplementation(() => undefined as never); - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Service({ lifecycle }: TServiceParams) { - lifecycle.onReady(() => process.emit("SIGINT")); - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - await sleep(10); - expect(exit).toHaveBeenCalled(); - application = undefined; - }); - }); - // #endregion - - // #region Internal - describe("Internal", () => { - it("populates maps during bootstrap", async () => { - let i: InternalDefinition; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ internal }: TServiceParams) { - i = internal; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(i.boot.constructComplete.size).not.toEqual(0); - expect(LIB_BOILERPLATE).toBeDefined(); - }); - }); - // #endregion - - // #region Wiring - describe("Wiring", () => { - it("should allow 2 separate apps to boot", async () => { - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test() {}, - }, - }); - await application.bootstrap(BASIC_BOOT); - const secondary = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing_second", - services: { - Test() {}, - }, - }); - await secondary.bootstrap(BASIC_BOOT); - await secondary.teardown(); - }); - - it("should replace libraries with conflicting names", async () => { - expect.assertions(2); - const test = jest.fn(); - const testLibrary = CreateLibrary({ - // @ts-expect-error For unit testing - name: "testing", - services: { - TestService() { - test("A"); - }, - }, - }); - const testLibraryB = CreateLibrary({ - // @ts-expect-error For unit testing - name: "testing", - services: { - TestService() { - test("B"); - }, - }, - }); - application = CreateApplication({ - configurationLoaders: [], - libraries: [testLibrary], - // @ts-expect-error Testing - name: "testing", - services: {}, - }); - await application.bootstrap({ - ...BASIC_BOOT, - appendLibrary: testLibraryB, - }); - expect(test).toHaveBeenCalledWith("B"); - expect(test).not.toHaveBeenCalledWith("A"); - }); - - it("should add library to TServiceParams", async () => { - let observed: unknown; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - priorityInit: ["First"], - services: { - // @ts-expect-error Testing - First({ testing }: TServiceParams) { - observed = testing; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(observed).toBeDefined(); - }); - - it("should use service context as keys in assembled api", async () => { - let foo: string; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - priorityInit: ["First"], - services: { - First() { - return { foo: "bar" }; - }, - // @ts-expect-error Testing - Second({ testing }: TServiceParams) { - foo = testing.First.foo; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(foo).toEqual("bar"); - }); - - it("passes lifecycle into services", async () => { - let observed: unknown; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ lifecycle }: TServiceParams) { - observed = lifecycle; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(observed).toBeDefined(); - }); - - it("passes logger into services", async () => { - let observed: unknown; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ logger }: TServiceParams) { - observed = logger; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(observed).toBeDefined(); - }); - - it("passes scheduler into services", async () => { - let observed: unknown; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ scheduler }: TServiceParams) { - observed = scheduler; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(observed).toBeDefined(); - }); - - it("passes cache into services", async () => { - let observed: unknown; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ cache }: TServiceParams) { - observed = cache; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(observed).toBeDefined(); - }); - - it("passes event into services", async () => { - let observed: unknown; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ event }: TServiceParams) { - observed = event; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(observed).toBeDefined(); - }); - - it("passes config into services", async () => { - let observed: unknown; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ config }: TServiceParams) { - observed = config; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(observed).toBeDefined(); - }); - - it("passes context into services", async () => { - let observed: unknown; - application = CreateApplication({ - configurationLoaders: [], - // @ts-expect-error Testing - name: "testing", - services: { - Test({ context }: TServiceParams) { - observed = context; - }, - }, - }); - await application.bootstrap(BASIC_BOOT); - expect(observed).toBeDefined(); - }); - }); - // #endregion - - // #region Mixing - describe("Application + Library interactions", () => { - let list: string[]; - const LIBRARY_A = CreateLibrary({ - // @ts-expect-error testing - name: "A", - services: { - AddToList: () => list.push("A"), - }, - }); - const LIBRARY_B = CreateLibrary({ - depends: [LIBRARY_A], - // @ts-expect-error testing - name: "B", - services: { - AddToList: () => list.push("B"), - }, - }); - - const LIBRARY_C = CreateLibrary({ - depends: [LIBRARY_A, LIBRARY_B], - // @ts-expect-error testing - name: "C", - services: { - AddToList: () => list.push("C"), - }, - }); - - const LIBRARY_D = CreateLibrary({ - depends: [LIBRARY_A], - // @ts-expect-error testing - name: "D", - - optionalDepends: [LIBRARY_B], - services: { - AddToList: () => list.push("C"), - }, - }); - - beforeEach(() => { - list = []; - }); - - it("should pass through optionalDepends", () => { - expect(LIBRARY_D.optionalDepends).toBeDefined(); - }); - - it("should wire libraries in the correct order", async () => { - // Provided in C -> A -> B - // Needs to be loaded in A -> B -> C - application = CreateApplication({ - libraries: [LIBRARY_C, LIBRARY_A, LIBRARY_B], - // @ts-expect-error testing - name: "testing", - services: {}, - }); - - await application.bootstrap(BASIC_BOOT); - expect(list).toEqual(["A", "B", "C"]); - }); - - it("should throw errors if a dependency is missing from the app", async () => { - application = CreateApplication({ - configurationLoaders: [], - libraries: [LIBRARY_C, LIBRARY_B], - // @ts-expect-error testing - name: "testing", - services: {}, - }); - const failFastSpy = jest - .spyOn(process, "exit") - .mockImplementation(FAKE_EXIT); - expect.assertions(1); - await application.bootstrap(BASIC_BOOT); - expect(failFastSpy).toHaveBeenCalled(); - }); - - it("should not throw errors if a optional dependency is missing from the app", async () => { - application = CreateApplication({ - configurationLoaders: [], - libraries: [LIBRARY_A, LIBRARY_D], - // @ts-expect-error testing - name: "testing", - services: {}, - }); - const failFastSpy = jest - .spyOn(process, "exit") - .mockImplementation(FAKE_EXIT); - expect.assertions(1); - await application.bootstrap(BASIC_BOOT); - expect(failFastSpy).not.toHaveBeenCalled(); - }); - - it("should allow name compatible library substitutions", async () => { - application = CreateApplication({ - configurationLoaders: [], - libraries: [ - LIBRARY_C, - LIBRARY_B, - CreateLibrary({ - // @ts-expect-error testing - name: "A", - services: { - AddToList: () => list.push("A"), - }, - }), - ], - // @ts-expect-error testing - name: "testing", - services: {}, - }); - const failFastSpy = jest - .spyOn(process, "exit") - .mockImplementation(FAKE_EXIT); - await application.bootstrap(BASIC_BOOT); - expect(list).toEqual(["A", "B", "C"]); - expect(failFastSpy).not.toHaveBeenCalled(); - }); - }); -}); diff --git a/testing/als.spec.ts b/testing/als.spec.ts new file mode 100644 index 0000000..57a2568 --- /dev/null +++ b/testing/als.spec.ts @@ -0,0 +1,10 @@ +import { TestRunner } from "../src"; + +describe("ALS", () => { + it("exists", async () => { + expect.assertions(1); + await TestRunner().run(({ als }) => { + expect(als).toBeDefined(); + }); + }); +}); diff --git a/testing/configuration.spec.ts b/testing/configuration.spec.ts new file mode 100644 index 0000000..d8f2619 --- /dev/null +++ b/testing/configuration.spec.ts @@ -0,0 +1,820 @@ +import { faker } from "@faker-js/faker"; +import dotenv from "dotenv"; +import fs, { existsSync, unlinkSync, writeFileSync } from "fs"; +import { encode as iniEncode } from "ini"; +import { dump as yamlDump } from "js-yaml"; +import { ParsedArgs } from "minimist"; +import { homedir } from "os"; +import { extname, join } from "path"; +import { cwd, env } from "process"; + +import { + ApplicationDefinition, + BootstrapOptions, + ConfigLoaderFile, + CreateApplication, + CreateLibrary, + createMockLogger, + ILogger, + InternalConfig, + InternalDefinition, + is, + loadDotenv, + OptionalModuleConfiguration, + parseConfig, + ServiceMap, + SINGLE, + TestRunner, + TServiceParams, +} from "../src"; + +const FAKE_EXIT = (() => {}) as () => never; +const BASIC_BOOT = { + configuration: { boilerplate: { LOG_LEVEL: "silent" } }, + loggerOptions: { + levelOverrides: { + boilerplate: "warn", + }, + }, +} as BootstrapOptions; + +export function ConfigTesting({ lifecycle }: TServiceParams) { + const appName = "testing"; + const testDataMap = new Map(); + + function writeConfigFile( + filePath: string, + data: RandomFileTestingDataFormat, + encodingType?: string, + ) { + let content; + encodingType = encodingType || extname(filePath).slice(SINGLE) || "ini"; + + switch (encodingType) { + case "json": + content = JSON.stringify(data); + break; + case "yaml": + content = yamlDump(data); + break; + default: + content = iniEncode(data); // Default to ini + break; + } + + writeFileSync(filePath, content); + testDataMap.set(filePath, data); + } + + function unlink(path?: string) { + if (path) { + if (testDataMap.has(path)) { + if (existsSync(path)) { + unlinkSync(path); + } + testDataMap.delete(path); + return; + } + return; + } + testDataMap.forEach((_, filePath) => { + if (existsSync(filePath)) { + unlinkSync(filePath); + } + }); + } + + lifecycle.onPreShutdown(() => { + unlink(); + [...testDataMap.keys()].forEach(i => testDataMap.delete(i)); + }); + + return { + dataMap: testDataMap, + link: (paths?: string[]) => { + const list = is.unique( + is.empty(paths) + ? [cwd(), join(homedir(), ".config")].flatMap(base => [ + join(base, `.${appName}`), + join(base, `.${appName}.json`), + join(base, `.${appName}.ini`), + join(base, `.${appName}.yaml`), + ]) + : paths, + ); + list.forEach(filename => { + // console.log(testDataMap); + writeConfigFile(filename, generateRandomData()); + }); + return list; + }, + sort: (filePaths: string[]): string[] => { + const dirOrder = [ + join("/etc", appName, "config"), + join("/etc", appName, "config.json"), + join("/etc", appName, "config.ini"), + join("/etc", appName, "config.yaml"), + join("/etc", appName, "config.yml"), + join("/etc", `${appName}`), + join("/etc", `${appName}.json`), + join("/etc", `${appName}.ini`), + join("/etc", `${appName}.yaml`), + join("/etc", `${appName}.yml`), + join(cwd(), `.${appName}`), + join(cwd(), `.${appName}.json`), + join(cwd(), `.${appName}.ini`), + join(cwd(), `.${appName}.yaml`), + join(cwd(), `.${appName}.yml`), + join(homedir(), ".config", appName), + join(homedir(), ".config", `${appName}.json`), + join(homedir(), ".config", `${appName}.ini`), + join(homedir(), ".config", `${appName}.yaml`), + join(homedir(), ".config", `${appName}.yml`), + join(homedir(), ".config", appName, "config"), + join(homedir(), ".config", appName, "config.json"), + join(homedir(), ".config", appName, "config.ini"), + join(homedir(), ".config", appName, "config.yaml"), + join(homedir(), ".config", appName, "config.yml"), + ].reverse(); + + return filePaths + .filter(path => dirOrder.includes(path)) + .sort((a, b) => dirOrder.indexOf(a) - dirOrder.indexOf(b)); + }, + unlink, + }; +} + +export type RandomFileTestingDataFormat = ReturnType; +function generateRandomData() { + return { + testing: { + boolean: faker.datatype.boolean(), + internal: { + mqtt: { + host: faker.internet.ip(), + port: faker.number.int({ max: 65_535, min: 1024 }), + }, + }, + number: faker.number.int(), + record: { + key1: faker.lorem.word(), + key2: faker.lorem.word(), + }, + string: faker.lorem.word(), + stringArray: [faker.lorem.word(), faker.lorem.word(), faker.lorem.word()], + }, + }; +} + +describe("Configuration", () => { + let application: ApplicationDefinition; + + afterEach(async () => { + if (application) { + await application.teardown(); + application = undefined; + } + jest.restoreAllMocks(); + }); + + // #region Initialization + describe("Initialization", () => { + it("should be configured at the correct time in the lifecycle", async () => { + expect.assertions(2); + const spy = jest.fn().mockReturnValue({}); + await TestRunner() + .setOptions({ configLoader: async () => spy() }) + .run(({ lifecycle }) => { + lifecycle.onPreInit(() => { + expect(spy).not.toHaveBeenCalled(); + }); + lifecycle.onPostConfig(() => { + expect(spy).toHaveBeenCalled(); + }); + }); + }); + + it("should prioritize bootstrap config over defaults", async () => { + expect.assertions(1); + await TestRunner() + .setOptions({ configuration: { boilerplate: { LOG_LEVEL: "info" } } }) + .run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + expect(config.boilerplate.LOG_LEVEL).toBe("info"); + }); + }); + }); + + it("should have the correct defaults for boilerplate", async () => { + expect.assertions(1); + await TestRunner().run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + expect(config.boilerplate.LOG_LEVEL).toBe("trace"); + }); + }); + }); + + it("should generate the correct structure for applications", async () => { + expect.assertions(1); + await TestRunner() + .setOptions({ + module_config: { + FOO: { default: "bar", type: "string" }, + }, + }) + .run(({ config }) => { + // @ts-expect-error testing + expect(config.testing.FOO).toBe("bar"); + }); + }); + + it("should generate the correct structure for libraries", async () => { + expect.assertions(1); + await TestRunner() + .appendLibrary( + CreateLibrary({ + configuration: { + RAINING: { + default: false, + type: "boolean", + }, + }, + // @ts-expect-error testing + name: "library", + services: {}, + }), + ) + .run(({ config, lifecycle }) => { + lifecycle.onBootstrap(() => { + // @ts-expect-error testing + expect(config.library.RAINING).toBe(false); + }); + }); + }); + }); + + // #endregion + // #region Loaders + describe("Loaders", () => { + describe("General", () => { + afterEach(() => { + delete env["DO_NOT_LOAD"]; + }); + + it("cannot set whole objects", async () => { + expect.assertions(1); + await TestRunner().run(({ config }) => { + expect(() => { + // @ts-expect-error testing + config.boilerplate = {}; + }).toThrow(); + }); + }); + + it("can list available keys", async () => { + expect.assertions(1); + await TestRunner().run(({ config }) => { + const key = Object.keys(config); + expect(key).toEqual(expect.arrayContaining(["boilerplate"])); + }); + }); + + it("does has operator", async () => { + expect.assertions(1); + await TestRunner().run(({ config }) => { + expect("boilerplate" in config).toBe(true); + }); + }); + + it("should not find variables without loaders", async () => { + expect.assertions(1); + env["DO_NOT_LOAD"] = "env"; + await TestRunner() + .setOptions({ + module_config: { + DO_NOT_LOAD: { + default: "unloaded", + type: "string", + }, + }, + }) + .run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + // @ts-expect-error testing + expect(config.testing.DO_NOT_LOAD).toBe("unloaded"); + }); + }); + }); + }); + + // #MARK: Environment + describe("Environment", () => { + afterEach(() => { + delete env["current_weather"]; + delete env["current_WEATHER"]; + delete env["CURRENT_WEATHER"]; + }); + + it("should default properly if environment variables do not exist", async () => { + expect.assertions(1); + await TestRunner() + .setOptions({ loadConfigs: true }) + .setOptions({ + module_config: { + CURRENT_WEATHER: { + default: "raining", + type: "string", + }, + }, + }) + .run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + // @ts-expect-error testing + expect(config.testing.CURRENT_WEATHER).toBe("raining"); + }); + }); + }); + + it("should do direct match by key", async () => { + expect.assertions(1); + env["CURRENT_WEATHER"] = "windy"; + await TestRunner() + .setOptions({ loadConfigs: true }) + .setOptions({ + module_config: { + CURRENT_WEATHER: { + default: "raining", + type: "string", + }, + }, + }) + .run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + // @ts-expect-error testing + expect(config.testing.CURRENT_WEATHER).toBe("windy"); + }); + }); + }); + + it("should wrong case (all lower)", async () => { + expect.assertions(1); + env["current_weather"] = "sunny"; + await TestRunner() + .setOptions({ loadConfigs: true }) + .setOptions({ + module_config: { + CURRENT_WEATHER: { + default: "raining", + type: "string", + }, + }, + }) + .run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + // @ts-expect-error testing + expect(config.testing.CURRENT_WEATHER).toBe("sunny"); + }); + }); + }); + + it("should wrong case (mixed)", async () => { + expect.assertions(1); + env["current_WEATHER"] = "hail"; + await TestRunner() + .setOptions({ loadConfigs: true }) + .setOptions({ + module_config: { + CURRENT_WEATHER: { + default: "raining", + type: "string", + }, + }, + }) + .run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + // @ts-expect-error testing + expect(config.testing.CURRENT_WEATHER).toBe("hail"); + }); + }); + }); + }); + + // #MARK: CLI Switches + describe("CLI Switch", () => { + beforeEach(() => { + process.argv = ["/path/to/node", "/path/to/main"]; + }); + + it("should default properly if environment variables do not exist", async () => { + expect.assertions(1); + await TestRunner() + .setOptions({ loadConfigs: true }) + .setOptions({ + module_config: { + CURRENT_WEATHER: { + default: "raining", + type: "string", + }, + }, + }) + .run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + // @ts-expect-error testing + expect(config.testing.CURRENT_WEATHER).toBe("raining"); + }); + }); + }); + + it("should do direct match by key", async () => { + expect.assertions(1); + process.argv.push("--CURRENT_WEATHER", "windy"); + await TestRunner() + .setOptions({ loadConfigs: true }) + .setOptions({ + module_config: { + CURRENT_WEATHER: { + default: "raining", + type: "string", + }, + }, + }) + .run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + // @ts-expect-error testing + expect(config.testing.CURRENT_WEATHER).toBe("windy"); + }); + }); + }); + + it("should wrong case (all lower)", async () => { + expect.assertions(1); + process.argv.push("--current_weather", "sunny"); + await TestRunner() + .setOptions({ loadConfigs: true }) + .setOptions({ + module_config: { + CURRENT_WEATHER: { + default: "raining", + type: "string", + }, + }, + }) + .run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + // @ts-expect-error testing + expect(config.testing.CURRENT_WEATHER).toBe("sunny"); + }); + }); + }); + + it("should wrong case (mixed)", async () => { + expect.assertions(1); + process.argv.push("--current_WEATHER", "hail"); + await TestRunner() + .setOptions({ loadConfigs: true }) + .setOptions({ + module_config: { + CURRENT_WEATHER: { + default: "raining", + type: "string", + }, + }, + }) + .run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + // @ts-expect-error testing + expect(config.testing.CURRENT_WEATHER).toBe("hail"); + }); + }); + }); + + it("is valid with equals signs", async () => { + expect.assertions(1); + process.argv.push("--current_WEATHER=hail"); + await TestRunner() + .setOptions({ loadConfigs: true }) + .setOptions({ + module_config: { + CURRENT_WEATHER: { + default: "raining", + type: "string", + }, + }, + }) + .run(({ config, lifecycle }) => { + lifecycle.onPostConfig(() => { + // @ts-expect-error testing + expect(config.testing.CURRENT_WEATHER).toBe("hail"); + }); + }); + }); + }); + + // #MARK: File + describe("File", () => { + it("resolves files in the correct order", async () => { + let testFiles: ReturnType = undefined; + const helper = CreateApplication({ + configurationLoaders: [], + // @ts-expect-error Testing + name: "helper", + services: { + ConfigTesting, + // @ts-expect-error Testing + Helper({ helper }: TServiceParams) { + testFiles = helper.ConfigTesting; + }, + }, + }); + await helper.bootstrap(BASIC_BOOT); + await helper.teardown(); + const keys = [...testFiles.dataMap.keys()]; + let sortedFiles = testFiles.sort(keys); + + for (const filePath of sortedFiles) { + const expectedData = testFiles.dataMap.get(filePath).testing.string; + + application = CreateApplication({ + configuration: { + string: { + default: "testing default value", + type: "string", + }, + }, + configurationLoaders: [ConfigLoaderFile], + // @ts-expect-error Testing + name: "testing", + services: { + Test({ lifecycle, config }: TServiceParams) { + lifecycle.onPostConfig(() => { + // @ts-expect-error Testing + expect(config.testing.string).toBe(expectedData); + }); + }, + }, + }); + await application.bootstrap(BASIC_BOOT); + await application.teardown(); + application = undefined; + testFiles.unlink(filePath); + sortedFiles = testFiles.sort([...testFiles.dataMap.keys()]); + } + }); + }); + }); + // #endregion + + describe("Support functions", () => { + // #MARK: parseConfig + describe("parseConfig", () => { + it("string config (no enum)", () => { + const value = faker.string.alphanumeric(); + const output = parseConfig({ type: "string" }, value); + expect(output).toBe(value); + }); + + it("string config (with enum)", () => { + const value = faker.string.alphanumeric(); + // no logic related to enum currently, might be future logic + const output = parseConfig({ enum: ["hello", "world"], type: "string" }, value); + expect(output).toBe(value); + }); + + it("number config", () => { + const value = faker.string.numeric(); + const output = parseConfig({ type: "number" }, value); + expect(output).toBe(Number(value)); + }); + + it("string[] config", () => { + const value = JSON.stringify(["hello", "world"]); + const output = parseConfig({ type: "string[]" }, value); + expect(output).toEqual(["hello", "world"]); + }); + + it("record config", () => { + const value = JSON.stringify({ key: "value" }); + const output = parseConfig({ type: "record" }, value); + expect(output).toEqual({ key: "value" }); + }); + + it("internal config", () => { + const value = JSON.stringify({ internalKey: "internalValue" }); + const output = parseConfig({ type: "internal" } as InternalConfig, value); + expect(output).toEqual({ internalKey: "internalValue" }); + }); + + it("boolean config (true case)", () => { + const value = "true"; + const output = parseConfig({ type: "boolean" }, value); + expect(output).toBe(true); + }); + + it("boolean config (false case)", () => { + const value = "false"; + const output = parseConfig({ type: "boolean" }, value); + expect(output).toBe(false); + }); + + it("boolean config (yes case)", () => { + const value = "y"; + const output = parseConfig({ type: "boolean" }, value); + expect(output).toBe(true); + }); + + it("boolean config (no case)", () => { + const value = "n"; + const output = parseConfig({ type: "boolean" }, value); + expect(output).toBe(false); + }); + }); + + describe("loadDotenv", () => { + let mockInternal: InternalDefinition; + let logger: ILogger; + + beforeEach(() => { + mockInternal = { + boot: { + options: { + envFile: "", + }, + }, + } as InternalDefinition; + logger = createMockLogger(); + }); + + it("should load env file from CLI switch if provided", () => { + jest.spyOn(fs, "existsSync").mockReturnValue(true); + const config = jest + .spyOn(dotenv, "config") + // @ts-expect-error idc + .mockReturnValue(() => undefined); + const CLI_SWITCHES = { + _: [], + "env-file": "path/to/env-file", + } as ParsedArgs; + + loadDotenv(mockInternal, CLI_SWITCHES, logger); + + expect(config).toHaveBeenCalledWith({ + override: true, + path: join(cwd(), "path/to/env-file"), + }); + }); + + it("should load env file from bootstrap if CLI switch is not provided", () => { + const config = jest + .spyOn(dotenv, "config") + // @ts-expect-error idc + .mockReturnValue(() => undefined); + jest.spyOn(fs, "existsSync").mockReturnValue(true); + mockInternal.boot.options.envFile = "path/to/bootstrap-env-file"; + + const CLI_SWITCHES = { + _: [], + "env-file": "", + } as ParsedArgs; + + loadDotenv(mockInternal, CLI_SWITCHES, logger); + + expect(config).toHaveBeenCalledWith({ + override: true, + path: join(cwd(), "path/to/bootstrap-env-file"), + }); + }); + + it("should load default .env file if no CLI switch or bootstrap envFile is provided", () => { + mockInternal.boot.options.envFile = ""; + jest.spyOn(fs, "existsSync").mockReturnValue(true); + + const config = jest + .spyOn(dotenv, "config") + // @ts-expect-error idc + .mockReturnValue(() => undefined); + + const CLI_SWITCHES = { + _: [], + "env-file": "", + } as ParsedArgs; + + loadDotenv(mockInternal, CLI_SWITCHES, logger); + + expect(config).toHaveBeenCalledWith({ + override: true, + path: join(cwd(), ".env"), + }); + }); + + it("should log a warning if the specified envFile does not exist", () => { + mockInternal.boot.options.envFile = "nonexistent-file"; + + const CLI_SWITCHES = { + _: [], + "env-file": "", + } as ParsedArgs; + jest.spyOn(fs, "existsSync").mockReturnValue(false); + + const config = jest + .spyOn(dotenv, "config") + // @ts-expect-error idc + .mockReturnValue(() => undefined); + + loadDotenv(mockInternal, CLI_SWITCHES, logger); + expect(config).not.toHaveBeenCalled(); + }); + + it("should do nothing if no valid envFile or .env file exists", () => { + mockInternal.boot.options.envFile = ""; + + const CLI_SWITCHES = { + _: [], + "env-file": "", + } as ParsedArgs; + jest.spyOn(fs, "existsSync").mockReturnValue(false); + + const config = jest + .spyOn(dotenv, "config") + // @ts-expect-error idc + .mockReturnValue(() => undefined); + + loadDotenv(mockInternal, CLI_SWITCHES, logger); + expect(config).not.toHaveBeenCalled(); + }); + }); + }); + + describe("Interactions", () => { + it("throws errors for missing required config", async () => { + expect.assertions(2); + const spy = jest.spyOn(global.console, "error").mockImplementation(() => undefined); + const exitSpy = jest.spyOn(process, "exit").mockImplementation(FAKE_EXIT); + try { + await TestRunner() + .appendLibrary( + CreateLibrary({ + configuration: { + REQUIRED_CONFIG: { required: true, type: "string" }, + }, + // @ts-expect-error testing + name: "library", + services: {}, + }), + ) + .run(() => {}); + } finally { + expect(spy).toHaveBeenCalled(); + expect(exitSpy).toHaveBeenCalled(); + } + }); + + describe("onUpdate", () => { + it("calls onUpdate when it changes", async () => { + await TestRunner().run( + ({ + internal: { + boilerplate: { configuration }, + }, + }) => { + const spy = jest.fn(); + configuration.onUpdate(spy); + configuration.set("boilerplate", "LOG_LEVEL", "debug"); + expect(spy).toHaveBeenCalled(); + }, + ); + }); + + it("does not call onUpdate when property doesn't match", async () => { + await TestRunner().run( + ({ + internal: { + boilerplate: { configuration }, + }, + }) => { + const spy = jest.fn(); + configuration.onUpdate(spy, "boilerplate", "config"); + configuration.set("boilerplate", "CONFIG", "debug"); + expect(spy).not.toHaveBeenCalled(); + }, + ); + }); + + it("does not call onUpdate when project doesn't match", async () => { + await TestRunner().run( + ({ + internal: { + boilerplate: { configuration }, + }, + }) => { + const spy = jest.fn(); + configuration.onUpdate(spy, "boilerplate", "config"); + // @ts-expect-error I got nothing better here + configuration.set("test", "CONFIG", "debug"); + expect(spy).not.toHaveBeenCalled(); + }, + ); + }); + }); + }); +}); diff --git a/testing/internal.spec.ts b/testing/internal.spec.ts new file mode 100644 index 0000000..5afd7ea --- /dev/null +++ b/testing/internal.spec.ts @@ -0,0 +1,248 @@ +import { BootstrapOptions, CreateApplication, TestRunner } from "../src"; + +export const BASIC_BOOT = { + configuration: { boilerplate: { LOG_LEVEL: "silent" } }, + loggerOptions: { + levelOverrides: { + boilerplate: "warn", + }, + }, +} as BootstrapOptions; + +describe("Fetch Extension", () => { + beforeAll(async () => { + const preload = CreateApplication({ + // @ts-expect-error testing + name: "testing", + }); + await preload.bootstrap(BASIC_BOOT); + await preload.teardown(); + }); + + afterEach(async () => { + jest.restoreAllMocks(); + }); + + describe("relativeDate", () => { + describe("relativeDate", () => { + it("should return the correct relative time for a valid past date", async () => { + await TestRunner().run(({ internal }) => { + const pastDate = "2023-09-01T00:00:00.000Z"; + const futureDate = "2024-09-01T00:00:00.000Z"; + const result = internal.utils.relativeDate(pastDate, futureDate); + expect(result).toBe("last yr."); + }); + }); + + it("should default to current date when futureDate is not provided", async () => { + await TestRunner().run(({ internal }) => { + const pastDate = new Date(Date.now() - 24 * 60 * 60 * 1000).toISOString(); + const result = internal.utils.relativeDate(pastDate); + expect(result).toBe("24 hr. ago"); + }); + }); + + it("should throw an error for an invalid past date", async () => { + await TestRunner().run(({ internal }) => { + const invalidPastDate = "invalid-date"; + expect(() => internal.utils.relativeDate(invalidPastDate)).toThrow( + "invalid past date invalid-date", + ); + }); + }); + + it("should throw an error for an invalid future date", async () => { + await TestRunner().run(({ internal }) => { + const pastDate = "2023-09-01T00:00:00.000Z"; + const invalidFutureDate = "invalid-date"; + expect(() => internal.utils.relativeDate(pastDate, invalidFutureDate)).toThrow( + "invalid future date 2023-09-01T00:00:00.000Z", + ); + }); + }); + }); + }); + + describe("titleCase", () => { + it("converts single word to title case", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(internal.utils.titleCase("word")).toBe("Word"); + }); + }); + + it("converts multiple words separated by spaces to title case", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(internal.utils.titleCase("multiple words here")).toBe("Multiple Words Here"); + }); + }); + + it("converts multiple words separated by underscores to title case", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(internal.utils.titleCase("multiple_words_here")).toBe("Multiple Words Here"); + }); + }); + + it("converts multiple words separated by hyphens to title case", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(internal.utils.titleCase("multiple-words-here")).toBe("Multiple Words Here"); + }); + }); + + it("inserts spaces between camel case words and converts to title case", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(internal.utils.titleCase("camelCaseWordsHere")).toBe("Camel Case Words Here"); + }); + }); + + it("handles empty string input", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(internal.utils.titleCase("")).toBe(""); + }); + }); + + it("handles single character input", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(internal.utils.titleCase("a")).toBe("A"); + }); + }); + + it("handles input with mixed delimiters", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(internal.utils.titleCase("mixed_delimiters-here now")).toBe( + "Mixed Delimiters Here Now", + ); + }); + }); + }); + + describe("internal.utils.object.set", () => { + it("throws for setting non-objects", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(() => { + internal.utils.object.set(null, "a", "b"); + }).toThrow(); + }); + }); + + it("respects doNotReplace", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + const data = { a: { b: { c: false } } }; + internal.utils.object.set(data, "a", false, true); + expect(typeof data.a.b).toBe("object"); + }); + }); + }); + + describe("internal.utils.object.del", () => { + it("deletes a top-level property", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + const object = { a: 1, b: 2 }; + internal.utils.object.del(object, "a"); + expect(object).toEqual({ b: 2 }); + }); + }); + + it("deletes a nested property", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + const object = { a: { b: { c: 3 } } }; + internal.utils.object.del(object, "a.b.c"); + expect(object).toEqual({ a: { b: {} } }); + }); + }); + + it("does nothing if the path does not exist", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + const object = { a: { b: { c: 3 } } }; + internal.utils.object.del(object, "a.b.x"); + expect(object).toEqual({ a: { b: { c: 3 } } }); + }); + }); + + it("handles path to a non-object gracefully", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + const object = { a: 1 }; + internal.utils.object.del(object, "a.b.c"); + expect(object).toEqual({ a: 1 }); + }); + }); + + it("handles deleting from an empty path", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + const object = { a: 1 }; + internal.utils.object.del(object, ""); + expect(object).toEqual({ a: 1 }); + }); + }); + + it("handles null or undefined values in the path", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + const object = { a: { b: null } } as object; + internal.utils.object.del(object, "a.b.c"); + expect(object).toEqual({ a: { b: null } }); + }); + }); + + it("handles null or undefined values in the path", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(() => { + internal.utils.object.del(null, "a.b.c"); + }).not.toThrow(); + }); + }); + }); + + describe("internal.safeExec", () => { + it("executes the provided function successfully", async () => { + expect.assertions(1); + await TestRunner().run(async ({ internal }) => { + const mockFunction = jest.fn(); + await internal.safeExec(mockFunction); + expect(mockFunction).toHaveBeenCalled(); + }); + }); + + it("executes the provided function successfully", async () => { + expect.assertions(1); + await TestRunner().run(async ({ internal }) => { + expect(await internal.safeExec(undefined)).toBeUndefined(); + }); + }); + + it("catches and logs errors thrown by the provided function", async () => { + expect.assertions(2); + await TestRunner().run(async ({ internal }) => { + const mockFunction = jest.fn().mockImplementation(() => { + throw new Error("Test error"); + }); + const mockLogger = jest.spyOn(internal.boilerplate.logger.systemLogger, "error"); + + await internal.safeExec(mockFunction); + + expect(mockFunction).toHaveBeenCalled(); + expect(mockLogger).toHaveBeenCalledWith( + expect.objectContaining({ error: expect.any(Error) }), + "callback threw error", + ); + + mockLogger.mockRestore(); + }); + }); + }); +}); diff --git a/src/testing/is.spec.ts b/testing/is.spec.ts similarity index 93% rename from src/testing/is.spec.ts rename to testing/is.spec.ts index 699b4ee..4b88471 100644 --- a/src/testing/is.spec.ts +++ b/testing/is.spec.ts @@ -1,4 +1,6 @@ -import { is } from "../extensions"; +import dayjs from "dayjs"; + +import { is } from "../src"; describe("IsIt class", () => { test("is.array returns true for arrays", () => { @@ -23,6 +25,11 @@ describe("IsIt class", () => { expect(is.date("not a date")).toBe(false); }); + test("is.dayjs returns true for dayjs objects", () => { + expect(is.dayjs(new Date())).toBe(false); + expect(is.dayjs(dayjs())).toBe(true); + }); + describe("is.empty", () => { test("returns true for undefined", () => { expect(is.empty(undefined)).toBe(true); @@ -89,9 +96,7 @@ describe("IsIt class", () => { test("throws an error for unsupported types like symbol", () => { // @ts-expect-error that's the test - expect(() => is.empty(Symbol.for("test"))).toThrow( - "Unsupported type symbol", - ); + expect(() => is.empty(Symbol.for("test"))).toThrow("Unsupported type symbol"); }); }); diff --git a/testing/logger.spec.ts b/testing/logger.spec.ts new file mode 100644 index 0000000..75ea4ae --- /dev/null +++ b/testing/logger.spec.ts @@ -0,0 +1,168 @@ +import chalk from "chalk"; +import dayjs from "dayjs"; + +import { + ApplicationDefinition, + createMockLogger, + OptionalModuleConfiguration, + ServiceMap, + TestRunner, +} from "../src"; + +describe("Logger", () => { + let application: ApplicationDefinition; + + afterEach(async () => { + if (application) { + await application.teardown(); + application = undefined; + } + jest.restoreAllMocks(); + }); + + describe("Configuration Interactions", () => { + it("calls the appropriate things based on permission combos", async () => { + expect.assertions(1); + + const customLogger = createMockLogger(); + await TestRunner() + .setOptions({ customLogger }) + .run(({ internal, logger }) => { + internal.boilerplate.configuration.set("boilerplate", "LOG_LEVEL", "warn"); + logger.fatal("HIT"); + expect(customLogger.fatal).toHaveBeenCalled(); + }); + }); + + it("updates onPostConfig", async () => { + expect.assertions(1); + + await TestRunner().run(({ internal, lifecycle }) => { + const spy = jest.spyOn(internal.boilerplate.logger, "updateShouldLog"); + lifecycle.onReady(() => { + expect(spy).toHaveBeenCalled(); + }); + }); + }); + + it("updates when LOG_LEVEL changes", async () => { + expect.assertions(1); + + await TestRunner().run(({ internal }) => { + const spy = jest.spyOn(internal.boilerplate.logger, "updateShouldLog"); + internal.boilerplate.configuration.set("boilerplate", "LOG_LEVEL", "warn"); + expect(spy).toHaveBeenCalled(); + }); + }); + }); + + describe("Pretty Formatting", () => { + const frontDash = " - "; + let YELLOW_DASH: string; + let BLUE_TICK: string; + + beforeAll(async () => { + YELLOW_DASH = chalk.yellowBright(frontDash); + BLUE_TICK = chalk.blue(`>`); + }); + + it("should default to pretty formatting", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(internal.boilerplate.logger.getPrettyFormat()).toBe(true); + }); + }); + + it("should return the original message if it exceeds MAX_CUTOFF", async () => { + expect.assertions(1); + + await TestRunner().run(({ internal: { boilerplate } }) => { + const longMessage = "a".repeat(2001); + expect(boilerplate.logger.prettyFormatMessage(longMessage)).toBe(longMessage); + }); + }); + + it('should highlight ">" in blue between square brackets', async () => { + expect.assertions(1); + + await TestRunner().run(({ internal: { boilerplate } }) => { + const message = "[A] > [B] > [C]"; + const expected = `${chalk.bold.magenta("A")} ${BLUE_TICK} ${chalk.bold.magenta("B")} ${BLUE_TICK} ${chalk.bold.magenta("C")}`; + expect(boilerplate.logger.prettyFormatMessage(message)).toBe(expected); + }); + }); + + it("should strip brackets and highlight text in magenta", async () => { + expect.assertions(1); + await TestRunner().run(({ internal: { boilerplate } }) => { + const message = "[Text]"; + const expected = chalk.bold.magenta("Text"); + expect(boilerplate.logger.prettyFormatMessage(message)).toBe(expected); + }); + }); + + it("should strip braces and highlight text in gray", async () => { + expect.assertions(1); + await TestRunner().run(({ internal: { boilerplate } }) => { + const message = "{Text}"; + const expected = chalk.bold.gray("Text"); + expect(boilerplate.logger.prettyFormatMessage(message)).toBe(expected); + }); + }); + + it("should highlight dash at the start of the message in yellow", async () => { + expect.assertions(1); + await TestRunner().run(({ internal: { boilerplate } }) => { + const message = " - Text"; + const expected = `${YELLOW_DASH}Text`; + expect(boilerplate.logger.prettyFormatMessage(message)).toBe(expected); + }); + }); + }); + + describe("Fine Tuning", () => { + it("provides access base logger", async () => { + expect.assertions(1); + const logger = createMockLogger(); + await TestRunner() + .setOptions({ customLogger: logger }) + .run(({ internal }) => { + expect(internal.boilerplate.logger.getBaseLogger()).toStrictEqual(logger); + }); + }); + + it("can modify base logger", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + const logger = createMockLogger(); + internal.boilerplate.logger.setBaseLogger(logger); + expect(internal.boilerplate.logger.getBaseLogger()).toBe(logger); + }); + }); + + it("can modify pretty format", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + internal.boilerplate.logger.setPrettyFormat(false); + expect(internal.boilerplate.logger.getPrettyFormat()).toBe(false); + }); + }); + + it("allows timestamp format to be configured", async () => { + const format = "ddd HH:mm:ss"; + jest.spyOn(global.console, "error").mockImplementation(() => {}); + jest.spyOn(global.console, "log").mockImplementation(() => {}); + + await TestRunner() + .setOptions({ + emitLogs: true, + loggerOptions: { timestampFormat: format }, + }) + .run(({ logger }) => { + const spy = jest.spyOn(dayjs.prototype, "format").mockImplementation(() => "timestamp"); + logger.info(`test`); + expect(spy).toHaveBeenCalledWith(format); + }); + }); + }); +}); diff --git a/testing/scheduler.spec.ts b/testing/scheduler.spec.ts new file mode 100644 index 0000000..7feef22 --- /dev/null +++ b/testing/scheduler.spec.ts @@ -0,0 +1,56 @@ +import dayjs from "dayjs"; + +import { CronExpression, HOUR, MINUTE, TestRunner } from "../src"; + +describe("Scheduler", () => { + afterEach(async () => { + jest.restoreAllMocks(); + }); + + it("runs a cron schedule", async () => { + jest.useFakeTimers(); + const spy = jest.fn(); + const app = await TestRunner().run(({ scheduler }) => { + scheduler.cron({ + exec: spy, + schedule: CronExpression.EVERY_MINUTE, + }); + }); + jest.advanceTimersByTime(60 * 60 * 1000); + expect(spy).toHaveBeenCalledTimes(60); + jest.useRealTimers(); + await app.teardown(); + }); + + it("runs an interval schedule", async () => { + jest.useFakeTimers(); + const spy = jest.fn(); + const app = await TestRunner().run(({ scheduler }) => { + scheduler.interval({ + exec: spy, + interval: MINUTE, + }); + }); + jest.advanceTimersByTime(60 * 60 * 1000); + expect(spy).toHaveBeenCalledTimes(60); + jest.useRealTimers(); + await app.teardown(); + }); + + xit("runs an interval schedule", async () => { + jest.useFakeTimers(); + jest.setSystemTime(dayjs("2024-09-13T05:00:00.000Z").toDate()); + const spy = jest.fn(); + const app = await TestRunner().run(({ scheduler }) => { + scheduler.sliding({ + exec: () => spy, + next: () => dayjs().add(1, "minute"), + reset: CronExpression.MONDAY_TO_FRIDAY_AT_8AM, + }); + }); + jest.advanceTimersByTime(4 * HOUR); + expect(spy).toHaveBeenCalledTimes(60); + jest.useRealTimers(); + await app.teardown(); + }); +}); diff --git a/testing/setup.ts b/testing/setup.ts new file mode 100644 index 0000000..c2456ff --- /dev/null +++ b/testing/setup.ts @@ -0,0 +1,4 @@ +// eslint-disable-next-line sonarjs/no-redeclare +import { jest } from "@jest/globals"; + +global.jest = jest; diff --git a/testing/testing.spec.ts b/testing/testing.spec.ts new file mode 100644 index 0000000..4292891 --- /dev/null +++ b/testing/testing.spec.ts @@ -0,0 +1,315 @@ +import { v4 } from "uuid"; + +import { CreateApplication, CreateLibrary, createModule, is, TestRunner } from "../src"; + +describe("Testing", () => { + const testingLibrary = CreateLibrary({ + // @ts-expect-error testing + name: "example", + services: { + test: function () { + return () => true; + }, + }, + }); + + const appendLibrary = CreateLibrary({ + // @ts-expect-error testing + name: "append", + services: { + test: function () { + return () => true; + }, + }, + }); + + const overrideLibrary = CreateLibrary({ + // @ts-expect-error testing + name: "example", + services: { + test: function () { + return () => false; + }, + }, + }); + + const overrideLibraryAgain = CreateLibrary({ + // @ts-expect-error testing + name: "example", + services: { + test: function () { + return () => "wat"; + }, + }, + }); + + const testingApplication = CreateApplication({ + // @ts-expect-error testing + name: "example", + services: { + test: function () { + return () => true; + }, + }, + }); + + const wrapperLibrary = CreateLibrary({ + depends: [testingLibrary], + // @ts-expect-error testing + name: "another_example", + services: { + test: function () { + return () => true; + }, + }, + }); + + const topApplication = CreateApplication({ + libraries: [wrapperLibrary, testingLibrary], + // @ts-expect-error testing + name: "example", + services: { + test: function () { + return () => true; + }, + }, + }); + + describe("Basics", () => { + it("makes assertions against a provided library", async () => { + expect.assertions(3); + + await TestRunner({ target: testingLibrary }).run(params => { + expect("example" in params).toBe(true); + // @ts-expect-error testing + expect(is.function(params.example.test)).toBe(true); + // @ts-expect-error testing + expect(params.example.test()).toBe(true); + // + }); + }); + + it("makes assertions against a provided application", async () => { + expect.assertions(3); + + await TestRunner({ target: testingApplication }).run(params => { + expect("example" in params).toBe(true); + // @ts-expect-error testing + expect(is.function(params.example.test)).toBe(true); + // @ts-expect-error testing + expect(params.example.test()).toBe(true); + }); + }); + }); + + it("can build a generic module from libraries", async () => { + expect.assertions(11); + const generic = createModule.fromLibrary(testingLibrary); + expect(generic).toBeDefined(); + const rebuild = generic.extend(); + expect(rebuild.appendLibrary).toBeDefined(); + expect(rebuild.appendService).toBeDefined(); + expect(rebuild.replaceLibrary).toBeDefined(); + expect(rebuild.replaceService).toBeDefined(); + expect(rebuild.pickService).toBeDefined(); + expect(rebuild.omitService).toBeDefined(); + expect(rebuild.rebuild).toBeDefined(); + expect(rebuild.toApplication).toBeDefined(); + expect(rebuild.toLibrary).toBeDefined(); + expect(rebuild.toTest).toBeDefined(); + }); + + it("builds a test from generic", async () => { + expect.assertions(1); + const test = createModule.fromLibrary(testingLibrary).extend().toTest(); + expect(test.type).toBe("test"); + }); + + describe("appendLibrary", () => { + it("can append libraries", async () => { + expect.assertions(1); + const test = createModule + .fromApplication(topApplication) + .extend() + .appendLibrary(appendLibrary) + .toTest(); + // @ts-expect-error testing + await test.run(({ append }) => { + expect(append.test).toBeDefined(); + }); + await test.teardown(); + }); + + it("cannot append something with an in use name (already appended)", async () => { + expect.assertions(1); + const test = createModule + .fromApplication(topApplication) + .extend() + .appendLibrary(appendLibrary); + expect(() => { + test.appendLibrary(appendLibrary); + }).toThrow(); + }); + + it("cannot append something with an in use name (existing)", async () => { + expect.assertions(1); + const test = createModule.fromApplication(topApplication).extend(); + expect(() => { + test.appendLibrary(overrideLibrary); + }).toThrow(); + }); + }); + + describe("appendService", () => { + it("cannot append an existing service", () => { + expect.assertions(1); + const test = createModule.fromApplication(topApplication).extend(); + expect(() => { + test.appendService("test", jest.fn()); + }).toThrow(); + }); + + it("can append a service with a unique name", async () => { + expect.assertions(1); + const spy = jest.fn(); + const id = v4(); + const test = createModule.fromApplication(topApplication).extend().appendService(id, spy); + const runner = test.toLibrary(); + expect(runner.services[id]).toBe(spy); + }); + }); + + describe("quick replacements", () => { + it("omitService", () => { + expect.assertions(1); + const out = createModule + .fromApplication(topApplication) + .extend() + .omitService("test") + .toLibrary(); + expect(Object.keys(out.services)).toEqual([]); + }); + + it("pickService", () => { + expect.assertions(1); + const id = v4(); + const out = createModule + .fromApplication(topApplication) + .extend() + .appendService(id, jest.fn()) + .pickService(id) + .toLibrary(); + expect(Object.keys(out.services)).toEqual([id]); + }); + + it("rebuild", () => { + expect.assertions(1); + const spy = jest.fn(); + const out = createModule + .fromApplication(topApplication) + .extend() + .rebuild({ test: spy }) + .toLibrary(); + expect(out.services.test).toEqual(spy); + }); + }); + + describe("replaceLibrary", () => { + it("can replace libraries", async () => { + expect.assertions(1); + const test = createModule + .fromApplication(topApplication) + .extend() + .replaceLibrary(overrideLibrary) + .toTest(); + // @ts-expect-error testing + await test.run(({ example }) => { + const result = example.test(); + expect(result).toBe(false); + }); + await test.teardown(); + }); + + it("can replace override replaces", async () => { + expect.assertions(1); + const test = createModule + .fromApplication(topApplication) + .extend() + .replaceLibrary(overrideLibrary) + .replaceLibrary(overrideLibraryAgain) + .toTest(); + // @ts-expect-error testing + await test.run(({ example }) => { + const result = example.test(); + expect(result).toBe("wat"); + }); + await test.teardown(); + }); + + it("cannot replace libraries that don't exist", async () => { + expect.assertions(1); + const test = createModule.fromApplication(topApplication).extend(); + expect(() => { + test.replaceLibrary(appendLibrary); + }).toThrow(); + }); + }); + + describe("replaceService", () => { + it("can replace libraries", async () => { + expect.assertions(1); + const spy = jest.fn(); + const test = createModule.fromApplication(topApplication).extend(); + expect(() => { + test.replaceService(v4(), spy); + }).toThrow(); + }); + + it("can replace services", async () => { + expect.assertions(1); + const spy = jest.fn(); + const test = createModule + .fromApplication(topApplication) + .extend() + .replaceService("test", spy) + .toLibrary(); + expect(test.services.test).toBe(spy); + }); + }); + + describe("Outputs", () => { + it("can create application modules", () => { + expect.assertions(1); + const test = createModule.fromLibrary(testingLibrary).extend().toApplication(); + expect(test.type).toBe("application"); + }); + + describe("optionalDepends", () => { + it("defaults optionalDepends for apps", () => { + expect.assertions(2); + const test = createModule({ + configuration: {}, + depends: [], + name: "test", + priorityInit: [], + services: undefined, + }); + expect(test.optionalDepends).toEqual([]); + expect(test.services).toEqual({}); + }); + + it("preserves optionalDepends for libraries", () => { + expect.assertions(1); + const test = createModule.fromLibrary( + CreateLibrary({ + // @ts-expect-error testing + name: "asdf", + optionalDepends: [testingLibrary], + services: {}, + }), + ); + expect(test.optionalDepends).toEqual([testingLibrary]); + }); + }); + }); +}); diff --git a/testing/utilities.spec.ts b/testing/utilities.spec.ts new file mode 100644 index 0000000..1fbee5f --- /dev/null +++ b/testing/utilities.spec.ts @@ -0,0 +1,277 @@ +import { + ACTIVE_THROTTLE, + debounce, + deepExtend, + each, + eachLimit, + eachSeries, + InternalError, + sleep, + TContext, +} from "../src"; + +describe("utilities", () => { + describe("sleep", () => { + it("should delay execution by the specified timeout", async () => { + const timeout = 100; + const start = Date.now(); + + await sleep(timeout); + + const end = Date.now(); + expect(end - start).toBeGreaterThanOrEqual(timeout - 1); + }); + + it('should stop early when kill("continue") is called', async () => { + const timeout = 200; + const start = Date.now(); + + const timer = sleep(timeout); + setTimeout(() => timer.kill("continue"), 50); + await timer; + + const end = Date.now(); + expect(end - start).toBeGreaterThanOrEqual(49); + expect(end - start).toBeLessThan(timeout - 1); + }); + + it('should not resolve if kill("stop") is called before timeout', async () => { + const timeout = 200; + const start = Date.now(); + + const timer = sleep(timeout); + setTimeout(() => timer.kill("stop"), 50); + await new Promise(resolve => setTimeout(resolve, 100)); // Wait for 100 milliseconds to ensure the stop has taken effect + + const end = Date.now(); + expect(end - start).toBeGreaterThanOrEqual(99); + expect(end - start).toBeLessThan(timeout - 1); + }); + + it("should handle date object correctly", async () => { + const targetDate = new Date(Date.now() + 100); + const start = Date.now(); + + await sleep(targetDate); + + const end = Date.now(); + expect(end - start).toBeGreaterThanOrEqual(99); + }); + }); + + describe("debounce", () => { + it("should delay execution by the specified timeout", async () => { + const identifier = "test-id"; + const timeout = 10; + const start = Date.now(); + + await debounce(identifier, timeout); + + const end = Date.now(); + expect(end - start).toBeGreaterThanOrEqual(timeout); + }); + + it("should cancel the previous debounce if called with the same identifier", async () => { + const identifier = "test-id"; + const timeout1 = 20; + const timeout2 = 10; + + const start = Date.now(); + debounce(identifier, timeout1); + await debounce(identifier, timeout2); + + const end = Date.now(); + expect(end - start).toBeLessThan(timeout1); + expect(end - start).toBeGreaterThanOrEqual(9); + }); + + it("should allow multiple identifiers to be debounced independently", async () => { + const identifier1 = "test-id-1"; + const identifier2 = "test-id-2"; + const timeout1 = 10; + const timeout2 = 10; + + const start1 = Date.now(); + debounce(identifier1, timeout1); + + const start2 = Date.now(); + await debounce(identifier2, timeout2); + + const end1 = Date.now(); + expect(end1 - start1).toBeGreaterThanOrEqual(timeout1 - 1); + expect(end1 - start2).toBeGreaterThanOrEqual(timeout2 - 1); + }); + + it("should clear the debounce once the timeout has passed", async () => { + const identifier = "test-id"; + const timeout = 100; + + await debounce(identifier, timeout); + + expect(ACTIVE_THROTTLE.has(identifier)).toBe(false); + }); + }); + + describe("eachLimit", () => { + it("handles an empty array", async () => { + const items: number[] = []; + const callback = jest.fn(async () => {}); + + await eachLimit(items, 2, callback); + + expect(callback).not.toHaveBeenCalled(); + }); + + it("respects the concurrency limit", async () => { + const repeat = 20; + const items = [...".".repeat(repeat)].map((_, i) => i); + const limit = 2; + const callback = jest.fn(async () => { + await sleep(100); + }); + + const startTime = Date.now(); + await eachLimit(items, limit, callback); + const endTime = Date.now(); + const duration = endTime - startTime; + + expect(callback).toHaveBeenCalledTimes(repeat); + expect(duration).toBeGreaterThanOrEqual(200); // 5 tasks with a 2-task limit should take ~200ms + }); + + it("handles errors thrown in callback", async () => { + const items = [1, 2, 3]; + const callback = jest.fn(async (item: number) => { + if (item === 2) throw new Error("Error on item 2"); + await new Promise(resolve => setTimeout(resolve, 50)); + }); + + await expect(eachLimit(items, 2, callback)).rejects.toThrow("Error on item 2"); + expect(callback).toHaveBeenCalledTimes(2); // Callback will be called until error is thrown + }); + }); + + describe("each function", () => { + it("should call the callback for each item in an array", async () => { + expect.assertions(4); + const items = [1, 2, 3]; + const mockCallback = jest.fn(); + + await each(items, mockCallback); + + expect(mockCallback).toHaveBeenCalledTimes(items.length); + expect(mockCallback).toHaveBeenCalledWith(1); + expect(mockCallback).toHaveBeenCalledWith(2); + expect(mockCallback).toHaveBeenCalledWith(3); + }); + + it("should call the callback for each item in a set", async () => { + expect.assertions(4); + const items = new Set([1, 2, 3]); + const mockCallback = jest.fn(); + + await each(items, mockCallback); + + expect(mockCallback).toHaveBeenCalledTimes(items.size); + expect(mockCallback).toHaveBeenCalledWith(1); + expect(mockCallback).toHaveBeenCalledWith(2); + expect(mockCallback).toHaveBeenCalledWith(3); + }); + + it("should handle asynchronous callbacks", async () => { + expect.assertions(1); + const items = [1, 2, 3]; + const mockCallback = jest.fn().mockResolvedValue("done"); + + await each(items, mockCallback); + + expect(mockCallback).toHaveBeenCalledTimes(items.length); + }); + + it("should handle an empty array without calling the callback", async () => { + expect.assertions(1); + const items: number[] = []; + const mockCallback = jest.fn(); + + await each(items, mockCallback); + + expect(mockCallback).not.toHaveBeenCalled(); + }); + + it("should handle an empty set without calling the callback", async () => { + expect.assertions(1); + const items = new Set(); + const mockCallback = jest.fn(); + + await each(items, mockCallback); + + expect(mockCallback).not.toHaveBeenCalled(); + }); + + describe("eachSeries", () => { + const mockCallback = jest.fn().mockResolvedValue(undefined); + + beforeEach(() => { + jest.clearAllMocks(); + }); + + it("should call the callback for each item in an array", async () => { + expect.assertions(4); + const items = [1, 2, 3]; + await eachSeries(items, mockCallback); + + expect(mockCallback).toHaveBeenCalledTimes(items.length); + expect(mockCallback).toHaveBeenNthCalledWith(1, 1); + expect(mockCallback).toHaveBeenNthCalledWith(2, 2); + expect(mockCallback).toHaveBeenNthCalledWith(3, 3); + }); + + it("should call the callback for each item in a Set", async () => { + expect.assertions(4); + const items = new Set([1, 2, 3]); + await eachSeries(items, mockCallback); + + expect(mockCallback).toHaveBeenCalledTimes(items.size); + expect(mockCallback).toHaveBeenNthCalledWith(1, 1); + expect(mockCallback).toHaveBeenNthCalledWith(2, 2); + expect(mockCallback).toHaveBeenNthCalledWith(3, 3); + }); + + it("should throw a TypeError if the argument is not an array or Set", async () => { + expect.assertions(2); + const invalidItem: unknown = {}; + + // @ts-expect-error testing + await expect(eachSeries(invalidItem, mockCallback)).rejects.toThrow(TypeError); + expect(mockCallback).not.toHaveBeenCalled(); + }); + + it("should handle an empty array without calling the callback", async () => { + expect.assertions(1); + const items: unknown[] = []; + await eachSeries(items, mockCallback); + + expect(mockCallback).not.toHaveBeenCalled(); + }); + }); + }); + + describe("cloneDeep", () => { + const data = { + a: { b: { c: false }, d: [1, 2, 3, 4, { a: 1 }] }, + d: new Date(), + e: null as unknown, + r: new RegExp("[a-z]", "g"), + } as Record; + expect(deepExtend({}, data)).toEqual(data); + }); + + it("InternalError", () => { + const error = new InternalError("" as TContext, "asdf", "qwerty"); + expect(error.name).toBe("InternalError"); + }); + it("InternalError", () => { + const error = new InternalError("" as TContext, "asdf", "qwerty"); + expect(error.name).toBe("InternalError"); + }); +}); diff --git a/testing/wiring.spec.ts b/testing/wiring.spec.ts new file mode 100644 index 0000000..ff382a2 --- /dev/null +++ b/testing/wiring.spec.ts @@ -0,0 +1,905 @@ +import { + ApplicationDefinition, + BootstrapException, + BootstrapOptions, + CreateApplication, + CreateLibrary, + InternalDefinition, + LifecycleStages, + OptionalModuleConfiguration, + ServiceMap, + sleep, + TestRunner, +} from "../src"; + +export const FAKE_EXIT = (() => {}) as () => never; + +const BASIC_BOOT = { + configuration: { boilerplate: { LOG_LEVEL: "silent" } }, +} as BootstrapOptions; + +describe("Wiring", () => { + let application: ApplicationDefinition; + + afterEach(async () => { + if (application) { + await application.teardown(); + application = undefined; + } + jest.restoreAllMocks(); + }); + + // #region CreateLibrary + describe("CreateLibrary", () => { + it("should be defined", () => { + expect.assertions(2); + expect(CreateLibrary).toBeDefined(); + expect(CreateApplication).toBeDefined(); + }); + + it("should create a library without services", () => { + expect.assertions(3); + const library = CreateLibrary({ + // @ts-expect-error For unit testing + name: "testing", + services: {}, + }); + + expect(library).toBeDefined(); + expect(library.name).toBe("testing"); + expect(library.services).toEqual({}); + }); + + it("throws an error with invalid service definition", () => { + expect.assertions(1); + expect(() => { + CreateLibrary({ + // @ts-expect-error For unit testing + name: "testing", + services: { InvalidService: undefined }, + }); + }).toThrow("INVALID_SERVICE_DEFINITION"); + }); + + it("creates multiple libraries with distinct configurations", () => { + expect.assertions(1); + const libraryOne = CreateLibrary({ + // @ts-expect-error For unit testing + name: "testing", + services: {}, + }); + const libraryTwo = CreateLibrary({ + // @ts-expect-error For unit testing + name: "testing_second", + services: {}, + }); + expect(libraryOne.name).not.toBe(libraryTwo.name); + }); + + it("throws a BootstrapException for an invalid service definition in a library", () => { + expect.assertions(1); + expect(() => { + CreateLibrary({ + // @ts-expect-error For unit testing + name: "testing", + services: { invalidServiceDefinition: undefined }, + }); + }).toThrow(BootstrapException); + }); + + it("throws a BootstrapException if no name is provided for the library", () => { + expect.assertions(1); + expect(() => { + // @ts-expect-error that's the test + CreateLibrary({ name: "", services: {} }); + }).toThrow(BootstrapException); + }); + }); + // #endregion + + // #region CreateApplication + describe("CreateApplication", () => { + it("should create an application with specified services and libraries", () => { + expect.assertions(5); + const testService = jest.fn(); + const testLibrary = CreateLibrary({ + // @ts-expect-error For unit testing + name: "testing", + services: { TestService: testService }, + }); + + application = CreateApplication({ + configurationLoaders: [], + libraries: [testLibrary], + // @ts-expect-error For unit testing + name: "testing", + services: { AppService: jest.fn() }, + }); + + expect(application).toBeDefined(); + expect(application.name).toBe("testing"); + expect(Object.keys(application.services).length).toBe(1); + expect(application.libraries.length).toBe(1); + expect(application.libraries[0]).toBe(testLibrary); + }); + + it("should only allows a single boot", async () => { + expect.assertions(1); + application = CreateApplication({ + configurationLoaders: [], + // @ts-expect-error For unit testing + name: "testing", + services: {}, + }); + await application.bootstrap(BASIC_BOOT); + try { + await application.bootstrap(BASIC_BOOT); + } catch (error) { + expect(error.message).toBe("DOUBLE_BOOT"); + } + }); + + it("should allow appending services", async () => { + expect.assertions(1); + application = CreateApplication({ + configurationLoaders: [], + // @ts-expect-error For unit testing + name: "testing", + services: {}, + }); + await application.bootstrap({ + ...BASIC_BOOT, + appendService: { + Test() { + // always true, the test is that it ran (expect.assertions) + expect(true).toBe(true); + }, + }, + }); + }); + + it("should allow appending libraries", async () => { + expect.assertions(1); + application = CreateApplication({ + configurationLoaders: [], + // @ts-expect-error For unit testing + name: "testing", + services: {}, + }); + const testLibrary = CreateLibrary({ + // @ts-expect-error For unit testing + name: "testing", + services: { + TestService() { + // always true, the test is that it ran (expect.assertions) + expect(true).toBe(true); + }, + }, + }); + + await application.bootstrap({ + ...BASIC_BOOT, + appendLibrary: testLibrary, + }); + }); + + it("should allow appending multiple libraries", async () => { + expect.assertions(2); + application = CreateApplication({ + configurationLoaders: [], + // @ts-expect-error For unit testing + name: "testing", + services: {}, + }); + + const testLibrary = CreateLibrary({ + // @ts-expect-error For unit testing + name: "testing", + services: { + TestService() { + // always true, the test is that it ran (expect.assertions) + expect(true).toBe(true); + }, + }, + }); + const testLibraryB = CreateLibrary({ + // @ts-expect-error For unit testing + name: "testing_b", + services: { + TestService() { + // always true, the test is that it ran (expect.assertions) + expect(true).toBe(true); + }, + }, + }); + + await application.bootstrap({ + ...BASIC_BOOT, + appendLibrary: [testLibrary, testLibraryB], + }); + }); + }); + // #endregion + + // #region Lifecycle + describe("Lifecycle", () => { + beforeEach(() => { + application = CreateApplication({ + configurationLoaders: [], + // @ts-expect-error For unit testing + name: "testing", + services: {}, + }); + }); + + it("should call the lifecycle events in order during application bootstrap", async () => { + expect.assertions(5); + const spyPreInit = jest.fn(); + const spyPostConfig = jest.fn(); + const spyBootstrap = jest.fn(); + const spyReady = jest.fn(); + + await TestRunner().run(({ lifecycle }) => { + lifecycle.onPreInit(spyPreInit); + lifecycle.onPostConfig(spyPostConfig); + lifecycle.onBootstrap(spyBootstrap); + lifecycle.onReady(spyReady); + }); + + expect(spyPreInit).toHaveBeenCalled(); + expect(spyPostConfig).toHaveBeenCalled(); + expect(spyBootstrap).toHaveBeenCalled(); + expect(spyReady).toHaveBeenCalled(); + + const callOrder = [ + spyPreInit.mock.invocationCallOrder[0], + spyPostConfig.mock.invocationCallOrder[0], + spyBootstrap.mock.invocationCallOrder[0], + spyReady.mock.invocationCallOrder[0], + ]; + expect(callOrder).toEqual([...callOrder].sort((a, b) => a - b)); + }); + + it("executes lifecycle callbacks in the correct order", async () => { + expect.assertions(3); + const mockPreInit = jest.fn(); + const mockPostConfig = jest.fn(); + const mockBootstrap = jest.fn(); + const mockReady = jest.fn(); + + await TestRunner().run(({ lifecycle }) => { + lifecycle.onPreInit(mockPreInit); + lifecycle.onPostConfig(mockPostConfig); + lifecycle.onBootstrap(mockBootstrap); + lifecycle.onReady(mockReady); + }); + + const preInitOrder = mockPreInit.mock.invocationCallOrder[0]; + const postConfigOrder = mockPostConfig.mock.invocationCallOrder[0]; + const bootstrapOrder = mockBootstrap.mock.invocationCallOrder[0]; + const readyOrder = mockReady.mock.invocationCallOrder[0]; + + expect(preInitOrder).toBeLessThan(postConfigOrder); + expect(postConfigOrder).toBeLessThan(bootstrapOrder); + expect(bootstrapOrder).toBeLessThan(readyOrder); + }); + + it("registers and invokes lifecycle callbacks correctly", async () => { + expect.assertions(1); + const mockCallback = jest.fn(); + + await TestRunner().run(({ lifecycle }) => { + lifecycle.onBootstrap(mockCallback); + }); + + expect(mockCallback).toHaveBeenCalled(); + }); + + it("exits on catastrophic bootstrap errors", async () => { + expect.assertions(1); + const errorMock = jest.fn(() => { + throw new Error("EXPECTED_UNIT_TESTING_ERROR"); + }); + jest.spyOn(console, "error").mockImplementation(() => {}); + const exitSpy = jest.spyOn(process, "exit").mockImplementation(FAKE_EXIT); + + await TestRunner().run(({ lifecycle }) => { + lifecycle.onBootstrap(errorMock); + }); + + expect(exitSpy).toHaveBeenCalled(); + }); + + it("higher numbers go first (positive)", async () => { + expect.assertions(1); + const order: string[] = []; + + await TestRunner().run(({ lifecycle }) => { + lifecycle.onBootstrap(() => order.push("LowPriority"), 1); + lifecycle.onBootstrap(() => order.push("HighPriority"), 10); + }); + + expect(order).toEqual(["HighPriority", "LowPriority"]); + }); + + it("lower numbers go later (negative)", async () => { + expect.assertions(1); + const order: string[] = []; + + await TestRunner().run(({ lifecycle }) => { + lifecycle.onBootstrap(() => order.push("LowPriority"), -10); + lifecycle.onBootstrap(() => order.push("HighPriority"), -1); + }); + + expect(order).toEqual(["HighPriority", "LowPriority"]); + }); + + describe("Completed events", () => { + it("starts off empty", async () => { + expect.assertions(1); + let list: LifecycleStages[]; + + await TestRunner().run(({ lifecycle, internal }) => { + lifecycle.onPreInit(() => (list = [...internal.boot.completedLifecycleEvents])); + }); + + expect(list).toEqual([]); + }); + + it("tracks onPreInit", async () => { + expect.assertions(1); + let list: LifecycleStages[]; + + await TestRunner().run(({ lifecycle, internal }) => { + lifecycle.onPostConfig(() => (list = [...internal.boot.completedLifecycleEvents])); + }); + + expect(list).toEqual(["PreInit"]); + }); + + it("tracks onPostConfig", async () => { + expect.assertions(1); + let list: LifecycleStages[]; + + await TestRunner().run(({ lifecycle, internal }) => { + lifecycle.onBootstrap(() => (list = [...internal.boot.completedLifecycleEvents])); + }); + + expect(list).toEqual(["PreInit", "PostConfig"]); + }); + + it("tracks onPreInit", async () => { + expect.assertions(1); + let list: LifecycleStages[]; + + await TestRunner().run(({ lifecycle, internal }) => { + lifecycle.onReady(() => (list = [...internal.boot.completedLifecycleEvents])); + }); + + expect(list).toEqual(["PreInit", "PostConfig", "Bootstrap"]); + }); + + it("tracks ready", async () => { + let i: InternalDefinition; + + await TestRunner().run(({ internal }) => { + i = internal; + }); + + expect([...i.boot.completedLifecycleEvents.values()]).toEqual([ + "PreInit", + "PostConfig", + "Bootstrap", + "Ready", + ]); + }); + + it("does not change by start of teardown", async () => { + expect.assertions(1); + let list: LifecycleStages[]; + + const app = await TestRunner().run(({ lifecycle, internal }) => { + lifecycle.onPreShutdown(() => (list = [...internal.boot.completedLifecycleEvents])); + }); + + application = undefined; + await app.teardown(); + expect(list).toEqual(["PreInit", "PostConfig", "Bootstrap", "Ready"]); + }); + + it("tracks preShutdown", async () => { + expect.assertions(1); + let list: LifecycleStages[]; + + const app = await TestRunner().run(({ lifecycle, internal }) => { + lifecycle.onShutdownStart(() => (list = [...internal.boot.completedLifecycleEvents])); + }); + + await app.teardown(); + expect(list).toEqual(["PreInit", "PostConfig", "Bootstrap", "Ready", "PreShutdown"]); + }); + + it("tracks shutdownStart", async () => { + expect.assertions(1); + let list: LifecycleStages[]; + + const app = await TestRunner().run(({ lifecycle, internal }) => { + lifecycle.onShutdownComplete(() => (list = [...internal.boot.completedLifecycleEvents])); + }); + await app.teardown(); + + expect(list).toEqual([ + "PreInit", + "PostConfig", + "Bootstrap", + "Ready", + "PreShutdown", + "ShutdownStart", + ]); + }); + + it("tracks shutdownComplete", async () => { + expect.assertions(1); + let i: InternalDefinition; + + const app = await TestRunner().run(({ internal }) => { + i = internal; + }); + + await app.teardown(); + expect([...i.boot.completedLifecycleEvents.values()]).toEqual([ + "PreInit", + "PostConfig", + "Bootstrap", + "Ready", + "PreShutdown", + "ShutdownStart", + "ShutdownComplete", + ]); + }); + }); + }); + // #endregion + + // #region Bootstrap + describe("Bootstrap", () => { + it("constructs app in between boot and ready for bootLibrariesFirst", async () => { + expect.assertions(4); + await TestRunner() + .setOptions({ bootLibrariesFirst: true }) + .run(({ internal }) => { + expect(internal.boot.completedLifecycleEvents.has("Bootstrap")).toBe(true); + expect(internal.boot.completedLifecycleEvents.has("PreInit")).toBe(true); + expect(internal.boot.completedLifecycleEvents.has("PostConfig")).toBe(true); + expect(internal.boot.completedLifecycleEvents.has("Ready")).toBe(false); + }); + }); + + it("should prioritize services with priorityInit", async () => { + expect.assertions(1); + const list = [] as string[]; + + await TestRunner() + .appendLibrary( + CreateLibrary({ + // @ts-expect-error testing + name: "library", + services: { + First() { + list.push("First"); + }, + Second() { + list.push("Second"); + }, + Third() { + list.push("Third"); + }, + }, + }), + ) + .run(() => undefined); + expect(list).toStrictEqual(["First", "Second", "Third"]); + }); + + it("throws errors with missing priority services in apps", async () => { + expect.assertions(1); + expect(() => { + CreateApplication({ + // @ts-expect-error testing + name: "library", + // @ts-expect-error testing + priorityInit: ["missing"], + services: {}, + }); + }).toThrow("MISSING_PRIORITY_SERVICE"); + }); + + it("throws errors with missing priority libraries", async () => { + expect.assertions(1); + expect(() => { + CreateLibrary({ + // @ts-expect-error testing + name: "library", + // @ts-expect-error testing + priorityInit: ["missing"], + services: {}, + }); + }).toThrow("MISSING_PRIORITY_SERVICE"); + }); + + it("sets booted after finishing bootstrap", async () => { + expect.assertions(1); + + const app = await TestRunner().run(() => undefined); + + expect(app.booted).toBe(true); + }); + + it("forbids double booting", async () => { + expect.assertions(1); + application = CreateApplication({ + configurationLoaders: [], + // @ts-expect-error Testing + name: "testing", + services: {}, + }); + await application.bootstrap(BASIC_BOOT); + + // I guess this works 🤷‍♀️ + try { + await application.bootstrap(BASIC_BOOT); + } catch (error) { + expect(error).toBeDefined(); + } + }); + }); + // #endregion + + // #region Boot Phase + describe("Boot Phase", () => { + it("should exit if service constructor throws error", async () => { + expect.assertions(1); + const spy = jest.spyOn(process, "exit").mockImplementation(() => undefined as never); + jest.spyOn(global.console, "error").mockImplementation(() => undefined); + + await TestRunner().run(() => { + throw new Error("boom"); + }); + expect(spy).toHaveBeenCalled(); + }); + + it("should not have project name in construction complete prior to completion", async () => { + expect.assertions(1); + await TestRunner().run(({ internal }) => { + expect(internal.boot.constructComplete.has("testing")).toBe(false); + }); + }); + + it("should add project name to complete", async () => { + expect.assertions(1); + + await TestRunner().run(({ internal, lifecycle }) => { + lifecycle.onPreInit(() => { + expect(internal.boot.constructComplete.has("testing")).toBe(true); + }); + }); + }); + + it("phase should be bootstrap during boot", async () => { + expect.assertions(1); + + await TestRunner().run(({ internal }) => { + expect(internal.boot.phase).toBe("bootstrap"); + }); + }); + + it("phase should be running when finished booting", async () => { + expect.assertions(1); + + let i: InternalDefinition; + await TestRunner().run(({ internal }) => { + i = internal; + }); + + expect(i.boot.phase).toBe("running"); + }); + }); + // #endregion + + // #region Teardown + describe("Teardown", () => { + it("shouldn't process double teardown", async () => { + expect.assertions(1); + const spy = jest.spyOn(global.console, "error").mockImplementation(() => undefined); + const app = await TestRunner().run(({ lifecycle }) => { + lifecycle.onPreShutdown(() => { + throw new Error("test"); + }); + }); + await app.teardown(); + + expect(spy).toHaveBeenCalledWith( + expect.any(Object), + "error occurred during teardown, some lifecycle events may be incomplete", + ); + }); + + it("phase should be teardown after teardown starts", async () => { + expect.assertions(1); + + const app = await TestRunner().run(({ internal, lifecycle }) => { + lifecycle.onPreShutdown(() => { + expect(internal.boot.phase).toBe("teardown"); + }); + }); + await app.teardown(); + }); + + xit("should shutdown on SIGTERM", async () => { + expect.assertions(2); + const exit = jest.spyOn(process, "exit").mockImplementation(() => undefined as never); + + const spy = jest.fn(); + + await TestRunner().run(({ lifecycle }) => { + lifecycle.onPreShutdown(spy); + }); + process.emit("SIGTERM"); + await sleep(10); // magic sleep + + expect(spy).toHaveBeenCalled(); + expect(exit).toHaveBeenCalled(); + application = undefined; + }); + + xit("should shutdown on SIGINT", async () => { + expect.assertions(2); + const exit = jest.spyOn(process, "exit").mockImplementation(() => undefined as never); + + const spy = jest.fn(); + + await TestRunner().run(({ lifecycle }) => { + lifecycle.onPreShutdown(spy); + }); + process.emit("SIGINT"); + await sleep(10); // magic sleep + + expect(spy).toHaveBeenCalled(); + expect(exit).toHaveBeenCalled(); + application = undefined; + }); + }); + // #endregion + + // #region Internal + describe("Internal", () => { + it("populates maps during bootstrap", async () => { + expect.assertions(1); + let i: InternalDefinition; + await TestRunner().run(({ internal }) => { + i = internal; + }); + expect(i.boot.constructComplete.size).not.toEqual(0); + }); + }); + // #endregion + + // #region Wiring + describe("Wiring", () => { + it("should allow 2 separate apps to boot", async () => { + expect.assertions(1); + await expect(async () => { + application = CreateApplication({ + configurationLoaders: [], + // @ts-expect-error Testing + name: "testing", + services: { + Test() {}, + }, + }); + await application.bootstrap(BASIC_BOOT); + const secondary = CreateApplication({ + configurationLoaders: [], + // @ts-expect-error Testing + name: "testing_second", + services: { + Test() {}, + }, + }); + await secondary.bootstrap(BASIC_BOOT); + await secondary.teardown(); + }).not.toThrow(); + }); + + it("should replace libraries with conflicting names", async () => { + expect.assertions(2); + const test = jest.fn(); + const testLibrary = CreateLibrary({ + // @ts-expect-error For unit testing + name: "testing", + services: { + TestService() { + test("A"); + }, + }, + }); + const testLibraryB = CreateLibrary({ + // @ts-expect-error For unit testing + name: "testing", + services: { + TestService() { + test("B"); + }, + }, + }); + application = CreateApplication({ + configurationLoaders: [], + libraries: [testLibrary], + // @ts-expect-error Testing + name: "testing", + services: {}, + }); + await application.bootstrap({ + ...BASIC_BOOT, + appendLibrary: testLibraryB, + }); + expect(test).toHaveBeenCalledWith("B"); + expect(test).not.toHaveBeenCalledWith("A"); + }); + + it("should add library to TServiceParams", async () => { + expect.assertions(1); + await TestRunner().run(params => { + expect("testing" in params).toBe(true); + }); + }); + + it("should use service context as keys in assembled api", async () => { + let foo: string; + application = CreateApplication({ + configurationLoaders: [], + // @ts-expect-error Testing + name: "testing", + priorityInit: ["First"], + services: { + First() { + return { foo: "bar" }; + }, + // @ts-expect-error Testing + Second({ testing }: TServiceParams) { + foo = testing.First.foo; + }, + }, + }); + await application.bootstrap(BASIC_BOOT); + expect(foo).toEqual("bar"); + }); + + it("passes standard utils into services", async () => { + expect.assertions(6); + await TestRunner().run(({ lifecycle, logger, scheduler, event, config, context }) => { + expect(lifecycle).toBeDefined(); + expect(logger).toBeDefined(); + expect(scheduler).toBeDefined(); + expect(event).toBeDefined(); + expect(config).toBeDefined(); + expect(context).toBeDefined(); + }); + }); + }); + // #endregion + + // #region Mixing + describe("Application + Library interactions", () => { + let list: string[]; + const LIBRARY_A = CreateLibrary({ + // @ts-expect-error testing + name: "A", + services: { + AddToList: () => list.push("A"), + }, + }); + const LIBRARY_B = CreateLibrary({ + depends: [LIBRARY_A], + // @ts-expect-error testing + name: "B", + services: { + AddToList: () => list.push("B"), + }, + }); + + const LIBRARY_C = CreateLibrary({ + depends: [LIBRARY_A, LIBRARY_B], + // @ts-expect-error testing + name: "C", + services: { + AddToList: () => list.push("C"), + }, + }); + + const LIBRARY_D = CreateLibrary({ + depends: [LIBRARY_A], + // @ts-expect-error testing + name: "D", + + optionalDepends: [LIBRARY_B], + services: { + AddToList: () => list.push("C"), + }, + }); + + beforeEach(() => { + list = []; + }); + + it("should pass through optionalDepends", () => { + expect(LIBRARY_D.optionalDepends).toBeDefined(); + }); + + it("should wire libraries in the correct order", async () => { + // Provided in C -> A -> B + // Needs to be loaded in A -> B -> C + application = CreateApplication({ + libraries: [LIBRARY_C, LIBRARY_A, LIBRARY_B], + // @ts-expect-error testing + name: "testing", + services: {}, + }); + + await application.bootstrap(BASIC_BOOT); + expect(list).toEqual(["A", "B", "C"]); + }); + + it("should throw errors if a dependency is missing from the app", async () => { + application = CreateApplication({ + configurationLoaders: [], + libraries: [LIBRARY_C, LIBRARY_B], + // @ts-expect-error testing + name: "testing", + services: {}, + }); + const failFastSpy = jest.spyOn(process, "exit").mockImplementation(FAKE_EXIT); + expect.assertions(1); + await application.bootstrap(BASIC_BOOT); + expect(failFastSpy).toHaveBeenCalled(); + }); + + it("should not throw errors if a optional dependency is missing from the app", async () => { + application = CreateApplication({ + configurationLoaders: [], + libraries: [LIBRARY_A, LIBRARY_D], + // @ts-expect-error testing + name: "testing", + services: {}, + }); + const failFastSpy = jest.spyOn(process, "exit").mockImplementation(FAKE_EXIT); + expect.assertions(1); + await application.bootstrap(BASIC_BOOT); + expect(failFastSpy).not.toHaveBeenCalled(); + }); + + it("should allow name compatible library substitutions", async () => { + application = CreateApplication({ + configurationLoaders: [], + libraries: [ + LIBRARY_C, + LIBRARY_B, + CreateLibrary({ + // @ts-expect-error testing + name: "A", + services: { + AddToList: () => list.push("A"), + }, + }), + ], + // @ts-expect-error testing + name: "testing", + services: {}, + }); + const failFastSpy = jest.spyOn(process, "exit").mockImplementation(FAKE_EXIT); + await application.bootstrap(BASIC_BOOT); + expect(list).toEqual(["A", "B", "C"]); + expect(failFastSpy).not.toHaveBeenCalled(); + }); + }); +}); diff --git a/tsconfig.json b/tsconfig.json index 9c44bf4..1a9ea69 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -6,9 +6,11 @@ "esModuleInterop": true, "importHelpers": true, "isolatedModules": true, - "lib": ["ESNext"], - "module": "NodeNext", - "moduleResolution": "NodeNext", + "lib": [ + "ESNext" + ], + "module": "ESNext", + "moduleResolution": "Bundler", "noImplicitAny": true, "declaration": true, "noImplicitReturns": true, @@ -19,12 +21,18 @@ "skipLibCheck": true, "sourceMap": true, "outDir": "./dist", - "strict": false, "strictBindCallApply": true, "strictFunctionTypes": true, "target": "ESNext", "allowSyntheticDefaultImports": true }, - "include": ["src/**/*.ts"], - "exclude": ["node_modules", "tmp", "dist"] + "include": [ + "src/**/*.ts", + "testing/**/*.ts" + ], + "exclude": [ + "node_modules", + "tmp", + "dist" + ] } diff --git a/tsconfig.lib.json b/tsconfig.lib.json index 790792b..dd866e6 100644 --- a/tsconfig.lib.json +++ b/tsconfig.lib.json @@ -9,8 +9,6 @@ "exclude": [ "node_modules", "tmp", - "dist", - "src/**/*.spec.ts", - "src/testing" + "dist" ] } diff --git a/tsconfig.spec.json b/tsconfig.spec.json index c913d87..3e033d6 100644 --- a/tsconfig.spec.json +++ b/tsconfig.spec.json @@ -1,13 +1,22 @@ { "extends": "./tsconfig.json", "compilerOptions": { - "outDir": "./dist-tests", + "alwaysStrict": false, + "esModuleInterop": true, "noEmit": false, + "noImplicitAny": false, "noUnusedLocals": false, "noUnusedParameters": false, - "noImplicitAny": false, - "esModuleInterop": true + "outDir": "./dist-tests", + "strictNullChecks": false, }, - "include": ["src/**/*.ts", "src/**/*.spec.ts"], - "exclude": ["node_modules", "tmp", "dist"] + "include": [ + "src/**/*.ts", + "testing/**/*.ts" + ], + "exclude": [ + "node_modules", + "tmp", + "dist" + ] } diff --git a/yarn.lock b/yarn.lock index 83ce487..97281c5 100644 --- a/yarn.lock +++ b/yarn.lock @@ -15,7 +15,7 @@ __metadata: languageName: node linkType: hard -"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.24.7": +"@babel/code-frame@npm:^7.0.0, @babel/code-frame@npm:^7.12.13, @babel/code-frame@npm:^7.24.2, @babel/code-frame@npm:^7.24.7": version: 7.24.7 resolution: "@babel/code-frame@npm:7.24.7" dependencies: @@ -25,6 +25,13 @@ __metadata: languageName: node linkType: hard +"@babel/compat-data@npm:^7.22.6, @babel/compat-data@npm:^7.24.1, @babel/compat-data@npm:^7.25.2": + version: 7.25.4 + resolution: "@babel/compat-data@npm:7.25.4" + checksum: 10/d37a8936cc355a9ca3050102e03d179bdae26bd2e5c99a977637376c192b23637a039795f153c849437a086727628c9860e2c6af92d7151396e2362c09176337 + languageName: node + linkType: hard + "@babel/compat-data@npm:^7.24.7": version: 7.24.7 resolution: "@babel/compat-data@npm:7.24.7" @@ -32,6 +39,29 @@ __metadata: languageName: node linkType: hard +"@babel/core@npm:7.24.3": + version: 7.24.3 + resolution: "@babel/core@npm:7.24.3" + dependencies: + "@ampproject/remapping": "npm:^2.2.0" + "@babel/code-frame": "npm:^7.24.2" + "@babel/generator": "npm:^7.24.1" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-module-transforms": "npm:^7.23.3" + "@babel/helpers": "npm:^7.24.1" + "@babel/parser": "npm:^7.24.1" + "@babel/template": "npm:^7.24.0" + "@babel/traverse": "npm:^7.24.1" + "@babel/types": "npm:^7.24.0" + convert-source-map: "npm:^2.0.0" + debug: "npm:^4.1.0" + gensync: "npm:^1.0.0-beta.2" + json5: "npm:^2.2.3" + semver: "npm:^6.3.1" + checksum: 10/3a7b9931fe0d93c500dcdb6b36f038b0f9d5090c048818e62aa8321c8f6e8ccc3d47373f0b40591c1fe3b13e5096bacabb1ade83f9f4d86f57878c39a9d1ade1 + languageName: node + linkType: hard + "@babel/core@npm:^7.11.6, @babel/core@npm:^7.12.3, @babel/core@npm:^7.23.9": version: 7.24.7 resolution: "@babel/core@npm:7.24.7" @@ -55,6 +85,32 @@ __metadata: languageName: node linkType: hard +"@babel/eslint-parser@npm:7.24.1": + version: 7.24.1 + resolution: "@babel/eslint-parser@npm:7.24.1" + dependencies: + "@nicolo-ribaudo/eslint-scope-5-internals": "npm:5.1.1-v1" + eslint-visitor-keys: "npm:^2.1.0" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.11.0 + eslint: ^7.5.0 || ^8.0.0 + checksum: 10/b65f93d880e4f3f62cb1d23a50139434b0e14b12acaeca40035d204a705f1ff0fbd191ed5101dd122473ba012dd3d08a3427960e4aab7fb384cfb3fc3f040a3e + languageName: node + linkType: hard + +"@babel/generator@npm:^7.24.1, @babel/generator@npm:^7.25.6": + version: 7.25.6 + resolution: "@babel/generator@npm:7.25.6" + dependencies: + "@babel/types": "npm:^7.25.6" + "@jridgewell/gen-mapping": "npm:^0.3.5" + "@jridgewell/trace-mapping": "npm:^0.3.25" + jsesc: "npm:^2.5.1" + checksum: 10/541e4fbb6ea7806f44232d70f25bf09dee9a57fe43d559e375536870ca5261ebb4647fec3af40dcbb3325ea2a49aff040e12a4e6f88609eaa88f10c4e27e31f8 + languageName: node + linkType: hard + "@babel/generator@npm:^7.24.7, @babel/generator@npm:^7.7.2": version: 7.24.7 resolution: "@babel/generator@npm:7.24.7" @@ -67,6 +123,38 @@ __metadata: languageName: node linkType: hard +"@babel/helper-annotate-as-pure@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-annotate-as-pure@npm:7.24.7" + dependencies: + "@babel/types": "npm:^7.24.7" + checksum: 10/a9017bfc1c4e9f2225b967fbf818004703de7cf29686468b54002ffe8d6b56e0808afa20d636819fcf3a34b89ba72f52c11bdf1d69f303928ee10d92752cad95 + languageName: node + linkType: hard + +"@babel/helper-builder-binary-assignment-operator-visitor@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-builder-binary-assignment-operator-visitor@npm:7.24.7" + dependencies: + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10/3ddff45d1e086c9c6dcef53ef46521a0c11ddb09fe3ab42dca5af6bb1b1703895a9f4f8056f49fdf53c2dbf6e5cf1ddb4baf17d7e3766c63f051ab8d60a919ee + languageName: node + linkType: hard + +"@babel/helper-compilation-targets@npm:^7.22.6, @babel/helper-compilation-targets@npm:^7.23.6, @babel/helper-compilation-targets@npm:^7.24.8, @babel/helper-compilation-targets@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/helper-compilation-targets@npm:7.25.2" + dependencies: + "@babel/compat-data": "npm:^7.25.2" + "@babel/helper-validator-option": "npm:^7.24.8" + browserslist: "npm:^4.23.1" + lru-cache: "npm:^5.1.1" + semver: "npm:^6.3.1" + checksum: 10/eccb2d75923d2d4d596f9ff64716e8664047c4192f1b44c7d5c07701d4a3498ac2587a72ddae1046e65a501bc630eb7df4557958b08ec2dcf5b4a264a052f111 + languageName: node + linkType: hard + "@babel/helper-compilation-targets@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-compilation-targets@npm:7.24.7" @@ -80,6 +168,51 @@ __metadata: languageName: node linkType: hard +"@babel/helper-create-class-features-plugin@npm:^7.24.1, @babel/helper-create-class-features-plugin@npm:^7.24.7, @babel/helper-create-class-features-plugin@npm:^7.25.4": + version: 7.25.4 + resolution: "@babel/helper-create-class-features-plugin@npm:7.25.4" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-member-expression-to-functions": "npm:^7.24.8" + "@babel/helper-optimise-call-expression": "npm:^7.24.7" + "@babel/helper-replace-supers": "npm:^7.25.0" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + "@babel/traverse": "npm:^7.25.4" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/47218da9fd964af30d41f0635d9e33eed7518e03aa8f10c3eb8a563bb2c14f52be3e3199db5912ae0e26058c23bb511c811e565c55ecec09427b04b867ed13c2 + languageName: node + linkType: hard + +"@babel/helper-create-regexp-features-plugin@npm:^7.18.6, @babel/helper-create-regexp-features-plugin@npm:^7.24.7, @babel/helper-create-regexp-features-plugin@npm:^7.25.2": + version: 7.25.2 + resolution: "@babel/helper-create-regexp-features-plugin@npm:7.25.2" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + regexpu-core: "npm:^5.3.1" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/33dd627eef9e4229aba66789efd8fb7342fc2667b821d4b7947c7294f6d472cf025ff2db9b358a1e03de98376de44e839f0611a456a57127fd6e4b4dbfc96c51 + languageName: node + linkType: hard + +"@babel/helper-define-polyfill-provider@npm:^0.6.2": + version: 0.6.2 + resolution: "@babel/helper-define-polyfill-provider@npm:0.6.2" + dependencies: + "@babel/helper-compilation-targets": "npm:^7.22.6" + "@babel/helper-plugin-utils": "npm:^7.22.5" + debug: "npm:^4.1.1" + lodash.debounce: "npm:^4.0.8" + resolve: "npm:^1.14.2" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10/bb32ec12024d3f16e70641bc125d2534a97edbfdabbc9f69001ec9c4ce46f877c7a224c566aa6c8c510c3b0def2e43dc4433bf6a40896ba5ce0cef4ea5ccbcff + languageName: node + linkType: hard + "@babel/helper-environment-visitor@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-environment-visitor@npm:7.24.7" @@ -108,6 +241,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-member-expression-to-functions@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-member-expression-to-functions@npm:7.24.8" + dependencies: + "@babel/traverse": "npm:^7.24.8" + "@babel/types": "npm:^7.24.8" + checksum: 10/ac878761cfd0a46c081cda0da75cc186f922cf16e8ecdd0c4fb6dca4330d9fe4871b41a9976224cf9669c9e7fe0421b5c27349f2e99c125fa0be871b327fa770 + languageName: node + linkType: hard + "@babel/helper-module-imports@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-module-imports@npm:7.24.7" @@ -118,6 +261,20 @@ __metadata: languageName: node linkType: hard +"@babel/helper-module-transforms@npm:^7.23.3, @babel/helper-module-transforms@npm:^7.24.8, @babel/helper-module-transforms@npm:^7.25.0": + version: 7.25.2 + resolution: "@babel/helper-module-transforms@npm:7.25.2" + dependencies: + "@babel/helper-module-imports": "npm:^7.24.7" + "@babel/helper-simple-access": "npm:^7.24.7" + "@babel/helper-validator-identifier": "npm:^7.24.7" + "@babel/traverse": "npm:^7.25.2" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/a3bcf7815f3e9d8b205e0af4a8d92603d685868e45d119b621357e274996bf916216bb95ab5c6a60fde3775b91941555bf129d608e3d025b04f8aac84589f300 + languageName: node + linkType: hard + "@babel/helper-module-transforms@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-module-transforms@npm:7.24.7" @@ -133,6 +290,15 @@ __metadata: languageName: node linkType: hard +"@babel/helper-optimise-call-expression@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-optimise-call-expression@npm:7.24.7" + dependencies: + "@babel/types": "npm:^7.24.7" + checksum: 10/da7a7f2d1bb1be4cffd5fa820bd605bc075c7dd014e0458f608bb6f34f450fe9412c8cea93e788227ab396e0e02c162d7b1db3fbcb755a6360e354c485d61df0 + languageName: node + linkType: hard + "@babel/helper-plugin-utils@npm:^7.0.0, @babel/helper-plugin-utils@npm:^7.10.4, @babel/helper-plugin-utils@npm:^7.12.13, @babel/helper-plugin-utils@npm:^7.14.5, @babel/helper-plugin-utils@npm:^7.24.7, @babel/helper-plugin-utils@npm:^7.8.0": version: 7.24.7 resolution: "@babel/helper-plugin-utils@npm:7.24.7" @@ -140,6 +306,39 @@ __metadata: languageName: node linkType: hard +"@babel/helper-plugin-utils@npm:^7.18.6, @babel/helper-plugin-utils@npm:^7.22.5, @babel/helper-plugin-utils@npm:^7.24.0, @babel/helper-plugin-utils@npm:^7.24.8, @babel/helper-plugin-utils@npm:^7.8.3": + version: 7.24.8 + resolution: "@babel/helper-plugin-utils@npm:7.24.8" + checksum: 10/adbc9fc1142800a35a5eb0793296924ee8057fe35c61657774208670468a9fbfbb216f2d0bc46c680c5fefa785e5ff917cc1674b10bd75cdf9a6aa3444780630 + languageName: node + linkType: hard + +"@babel/helper-remap-async-to-generator@npm:^7.24.7, @babel/helper-remap-async-to-generator@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helper-remap-async-to-generator@npm:7.25.0" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-wrap-function": "npm:^7.25.0" + "@babel/traverse": "npm:^7.25.0" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/6b1ab73a067008c92e2fe5b7a9f39aab32e7f5a8c5eaf0a864436c21791f708ad8619d4a509febdfe934aeb373af4baa7c7d9f41181b385e09f39eaf11ca108e + languageName: node + linkType: hard + +"@babel/helper-replace-supers@npm:^7.24.7, @babel/helper-replace-supers@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helper-replace-supers@npm:7.25.0" + dependencies: + "@babel/helper-member-expression-to-functions": "npm:^7.24.8" + "@babel/helper-optimise-call-expression": "npm:^7.24.7" + "@babel/traverse": "npm:^7.25.0" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/97c6c17780cb9692132f7243f5a21fb6420104cb8ff8752dc03cfc9a1912a243994c0290c77ff096637ab6f2a7363b63811cfc68c2bad44e6b39460ac2f6a63f + languageName: node + linkType: hard + "@babel/helper-simple-access@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-simple-access@npm:7.24.7" @@ -150,6 +349,16 @@ __metadata: languageName: node linkType: hard +"@babel/helper-skip-transparent-expression-wrappers@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/helper-skip-transparent-expression-wrappers@npm:7.24.7" + dependencies: + "@babel/traverse": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10/784a6fdd251a9a7e42ccd04aca087ecdab83eddc60fda76a2950e00eb239cc937d3c914266f0cc476298b52ac3f44ffd04c358e808bd17552a7e008d75494a77 + languageName: node + linkType: hard + "@babel/helper-split-export-declaration@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-split-export-declaration@npm:7.24.7" @@ -166,13 +375,27 @@ __metadata: languageName: node linkType: hard -"@babel/helper-validator-identifier@npm:^7.22.20, @babel/helper-validator-identifier@npm:^7.24.7": +"@babel/helper-string-parser@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-string-parser@npm:7.24.8" + checksum: 10/6d1bf8f27dd725ce02bdc6dffca3c95fb9ab8a06adc2edbd9c1c9d68500274230d1a609025833ed81981eff560045b6b38f7b4c6fb1ab19fc90e5004e3932535 + languageName: node + linkType: hard + +"@babel/helper-validator-identifier@npm:^7.24.5, @babel/helper-validator-identifier@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-validator-identifier@npm:7.24.7" checksum: 10/86875063f57361471b531dbc2ea10bbf5406e12b06d249b03827d361db4cad2388c6f00936bcd9dc86479f7e2c69ea21412c2228d4b3672588b754b70a449d4b languageName: node linkType: hard +"@babel/helper-validator-option@npm:^7.23.5, @babel/helper-validator-option@npm:^7.24.8": + version: 7.24.8 + resolution: "@babel/helper-validator-option@npm:7.24.8" + checksum: 10/a52442dfa74be6719c0608fee3225bd0493c4057459f3014681ea1a4643cd38b68ff477fe867c4b356da7330d085f247f0724d300582fa4ab9a02efaf34d107c + languageName: node + linkType: hard + "@babel/helper-validator-option@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helper-validator-option@npm:7.24.7" @@ -180,6 +403,27 @@ __metadata: languageName: node linkType: hard +"@babel/helper-wrap-function@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/helper-wrap-function@npm:7.25.0" + dependencies: + "@babel/template": "npm:^7.25.0" + "@babel/traverse": "npm:^7.25.0" + "@babel/types": "npm:^7.25.0" + checksum: 10/08724128b9c540c02a59f02f9c1c9940fe5363d85d0f30ec826a4f926afdb26fa4ec33ca2b88b4aa745fe3dbe1f44be2969b8a03af259af7945d8cd3262168d3 + languageName: node + linkType: hard + +"@babel/helpers@npm:^7.24.1": + version: 7.25.6 + resolution: "@babel/helpers@npm:7.25.6" + dependencies: + "@babel/template": "npm:^7.25.0" + "@babel/types": "npm:^7.25.6" + checksum: 10/43abc8d017b754619aa189d05e2bdb54aaf44f03ec0439e89b3e7c180d538adb01ce9014a1689f632a7e8b17655c72bfac0a92268476eec708b41d3ba0a65296 + languageName: node + linkType: hard + "@babel/helpers@npm:^7.24.7": version: 7.24.7 resolution: "@babel/helpers@npm:7.24.7" @@ -211,6 +455,75 @@ __metadata: languageName: node linkType: hard +"@babel/parser@npm:^7.24.1, @babel/parser@npm:^7.25.0, @babel/parser@npm:^7.25.6": + version: 7.25.6 + resolution: "@babel/parser@npm:7.25.6" + dependencies: + "@babel/types": "npm:^7.25.6" + bin: + parser: ./bin/babel-parser.js + checksum: 10/830aab72116aa14eb8d61bfa8f9d69fc8f3a43d909ce993cb4350ae14d3af1a2f740a54410a22d821c48a253263643dfecbc094f9608e6a70ce9ff3c0bbfe91a + languageName: node + linkType: hard + +"@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:^7.24.1": + version: 7.25.0 + resolution: "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression@npm:7.25.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/f574beb1d4f723bb9b913ce379259a55b50a308364585ccb83e00d933465c26c04cbbc85a06e6d4c829279eb1021b3236133d486b3ff11cfd90ad815c8b478d2 + languageName: node + linkType: hard + +"@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.13.0 + checksum: 10/887f1b8bd0ef61206ece47919fda78a32eef35da31c0d95ab8d7adc8b4722534dc5177c86c8d6d81bcf4343f3c08c6adab2b46cfd2bea8e33c6c04e51306f9cc + languageName: node + linkType: hard + +"@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:^7.24.1": + version: 7.25.0 + resolution: "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly@npm:7.25.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/traverse": "npm:^7.25.0" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/de04a9342e9a0db1673683112c83cdc52173f489f45aeed864ceba72dfba8c8588e565171e64cb2a408a09269e5fb35c6ab4ef50e3e649c4f8c0c787feb5c048 + languageName: node + linkType: hard + +"@babel/plugin-proposal-decorators@npm:7.24.1": + version: 7.24.1 + resolution: "@babel/plugin-proposal-decorators@npm:7.24.1" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.24.1" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/plugin-syntax-decorators": "npm:^7.24.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/cbc489ae3ebe5216a4d764a6d155591282e819b6b7436c4cffbb8f123515a1db9cc2f84259c36d558f896e8ff8526ebd28d3563fabb04347ae1964c476b44b9f + languageName: node + linkType: hard + +"@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2": + version: 7.21.0-placeholder-for-preset-env.2 + resolution: "@babel/plugin-proposal-private-property-in-object@npm:7.21.0-placeholder-for-preset-env.2" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/fab70f399aa869275690ec6c7cedb4ef361d4e8b6f55c3d7b04bfee61d52fb93c87cec2c65d73cddbaca89fb8ef5ec0921fce675c9169d9d51f18305ab34e78a + languageName: node + linkType: hard + "@babel/plugin-syntax-async-generators@npm:^7.8.4": version: 7.8.4 resolution: "@babel/plugin-syntax-async-generators@npm:7.8.4" @@ -233,7 +546,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-class-properties@npm:^7.8.3": +"@babel/plugin-syntax-class-properties@npm:^7.12.13, @babel/plugin-syntax-class-properties@npm:^7.8.3": version: 7.12.13 resolution: "@babel/plugin-syntax-class-properties@npm:7.12.13" dependencies: @@ -244,7 +557,84 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-import-meta@npm:^7.8.3": +"@babel/plugin-syntax-class-static-block@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-class-static-block@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/3e80814b5b6d4fe17826093918680a351c2d34398a914ce6e55d8083d72a9bdde4fbaf6a2dcea0e23a03de26dc2917ae3efd603d27099e2b98380345703bf948 + languageName: node + linkType: hard + +"@babel/plugin-syntax-decorators@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-syntax-decorators@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/067f20c4108cc5b9e7271d4e15313d7e4aa2ceddee19afd02c94b5cffc1b4761c5a7d6460c8588201e54a270c7bd643817a7f54508787f94992d86dd2cfc7540 + languageName: node + linkType: hard + +"@babel/plugin-syntax-dynamic-import@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-dynamic-import@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.8.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/ce307af83cf433d4ec42932329fad25fa73138ab39c7436882ea28742e1c0066626d224e0ad2988724c82644e41601cef607b36194f695cb78a1fcdc959637bd + languageName: node + linkType: hard + +"@babel/plugin-syntax-export-namespace-from@npm:^7.8.3": + version: 7.8.3 + resolution: "@babel/plugin-syntax-export-namespace-from@npm:7.8.3" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/85740478be5b0de185228e7814451d74ab8ce0a26fcca7613955262a26e99e8e15e9da58f60c754b84515d4c679b590dbd3f2148f0f58025f4ae706f1c5a5d4a + languageName: node + linkType: hard + +"@babel/plugin-syntax-flow@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-syntax-flow@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/0a83bde6736110d68f3b20eda44ca020a6d34c336a342f84369207f5514e17779b9c3d3ebc2f1c94b595c13819f46bf7af367c4b1382bda182e1764655fd6a5a + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-assertions@npm:^7.24.1": + version: 7.25.6 + resolution: "@babel/plugin-syntax-import-assertions@npm:7.25.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/36a756a695e2f18d406bfdfd6823023e3810d13fdb27ec2a5cb90ae95326edb1e744e3451a8a31bf6bd91646236643c5e8024ecf71102cc93309ec80592ebb17 + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-attributes@npm:^7.24.1": + version: 7.25.6 + resolution: "@babel/plugin-syntax-import-attributes@npm:7.25.6" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/5afeba6b8979e61e8e37af905514891920eab103a08b36216f5518474328f9fae5204357bfadf6ce4cc80cb96848cdb7b8989f164ae93bd063c86f3f586728c0 + languageName: node + linkType: hard + +"@babel/plugin-syntax-import-meta@npm:^7.10.4, @babel/plugin-syntax-import-meta@npm:^7.8.3": version: 7.10.4 resolution: "@babel/plugin-syntax-import-meta@npm:7.10.4" dependencies: @@ -266,7 +656,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-jsx@npm:^7.7.2": +"@babel/plugin-syntax-jsx@npm:^7.24.7, @babel/plugin-syntax-jsx@npm:^7.7.2": version: 7.24.7 resolution: "@babel/plugin-syntax-jsx@npm:7.24.7" dependencies: @@ -277,7 +667,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-logical-assignment-operators@npm:^7.8.3": +"@babel/plugin-syntax-logical-assignment-operators@npm:^7.10.4, @babel/plugin-syntax-logical-assignment-operators@npm:^7.8.3": version: 7.10.4 resolution: "@babel/plugin-syntax-logical-assignment-operators@npm:7.10.4" dependencies: @@ -299,7 +689,7 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-numeric-separator@npm:^7.8.3": +"@babel/plugin-syntax-numeric-separator@npm:^7.10.4, @babel/plugin-syntax-numeric-separator@npm:^7.8.3": version: 7.10.4 resolution: "@babel/plugin-syntax-numeric-separator@npm:7.10.4" dependencies: @@ -343,7 +733,18 @@ __metadata: languageName: node linkType: hard -"@babel/plugin-syntax-top-level-await@npm:^7.8.3": +"@babel/plugin-syntax-private-property-in-object@npm:^7.14.5": + version: 7.14.5 + resolution: "@babel/plugin-syntax-private-property-in-object@npm:7.14.5" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/b317174783e6e96029b743ccff2a67d63d38756876e7e5d0ba53a322e38d9ca452c13354a57de1ad476b4c066dbae699e0ca157441da611117a47af88985ecda + languageName: node + linkType: hard + +"@babel/plugin-syntax-top-level-await@npm:^7.14.5, @babel/plugin-syntax-top-level-await@npm:^7.8.3": version: 7.14.5 resolution: "@babel/plugin-syntax-top-level-await@npm:7.14.5" dependencies: @@ -365,43 +766,878 @@ __metadata: languageName: node linkType: hard -"@babel/template@npm:^7.24.7, @babel/template@npm:^7.3.3": - version: 7.24.7 - resolution: "@babel/template@npm:7.24.7" +"@babel/plugin-syntax-unicode-sets-regex@npm:^7.18.6": + version: 7.18.6 + resolution: "@babel/plugin-syntax-unicode-sets-regex@npm:7.18.6" dependencies: - "@babel/code-frame": "npm:^7.24.7" - "@babel/parser": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - checksum: 10/5975d404ef51cf379515eb0f80b115981d0b9dff5539e53a47516644abb8c83d7559f5b083eb1d4977b20d8359ebb2f911ccd4f729143f8958fdc465f976d843 + "@babel/helper-create-regexp-features-plugin": "npm:^7.18.6" + "@babel/helper-plugin-utils": "npm:^7.18.6" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/a651d700fe63ff0ddfd7186f4ebc24447ca734f114433139e3c027bc94a900d013cf1ef2e2db8430425ba542e39ae160c3b05f06b59fd4656273a3df97679e9c languageName: node linkType: hard -"@babel/traverse@npm:^7.24.7": +"@babel/plugin-transform-arrow-functions@npm:^7.24.1": version: 7.24.7 - resolution: "@babel/traverse@npm:7.24.7" + resolution: "@babel/plugin-transform-arrow-functions@npm:7.24.7" dependencies: - "@babel/code-frame": "npm:^7.24.7" - "@babel/generator": "npm:^7.24.7" - "@babel/helper-environment-visitor": "npm:^7.24.7" - "@babel/helper-function-name": "npm:^7.24.7" - "@babel/helper-hoist-variables": "npm:^7.24.7" - "@babel/helper-split-export-declaration": "npm:^7.24.7" - "@babel/parser": "npm:^7.24.7" - "@babel/types": "npm:^7.24.7" - debug: "npm:^4.3.1" - globals: "npm:^11.1.0" - checksum: 10/785cf26383a992740e492efba7016de964cd06c05c9d7146fa1b5ead409e054c444f50b36dc37856884a56e32cf9d3105ddf1543486b6df68300bffb117a245a + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/6720173645826046878015c579c2ca9d93cdba79a2832f0180f5cf147d9817c85bf9c8338b16d6bdaa71f87809b7a194a6902e6c82ec00b6354aca6b40abe5e6 languageName: node linkType: hard -"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.24.7, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": +"@babel/plugin-transform-async-generator-functions@npm:^7.24.3": + version: 7.25.4 + resolution: "@babel/plugin-transform-async-generator-functions@npm:7.25.4" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-remap-async-to-generator": "npm:^7.25.0" + "@babel/plugin-syntax-async-generators": "npm:^7.8.4" + "@babel/traverse": "npm:^7.25.4" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/0004d910bbec3ef916acf5c7cf8b11671e65d2dd425a82f1101838b9b6243bfdf9578335584d9dedd20acc162796b687930e127c6042484e05b758af695e6cb8 + languageName: node + linkType: hard + +"@babel/plugin-transform-async-to-generator@npm:^7.24.1": version: 7.24.7 - resolution: "@babel/types@npm:7.24.7" + resolution: "@babel/plugin-transform-async-to-generator@npm:7.24.7" dependencies: - "@babel/helper-string-parser": "npm:^7.24.7" - "@babel/helper-validator-identifier": "npm:^7.24.7" - to-fast-properties: "npm:^2.0.0" - checksum: 10/ad3c8c0d6fb4acb0bb74bb5b4bb849b181bf6185677ef9c59c18856c81e43628d0858253cf232f0eca806f02e08eff85a1d3e636a3e94daea737597796b0b430 + "@babel/helper-module-imports": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-remap-async-to-generator": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/b2041d9d50b09afef983c4f1dece63fdfc5a8e4646e42591db398bc4322958434d60b3cb0f5d0f9f9dbdad8577e8a1a33ba9859aacc3004bf6d25d094d20193f + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoped-functions@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-block-scoped-functions@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/33e2fb9f24c11889b2bacbe9c3625f738edafc2136c8206598e0422664267ec5ca9422cb4563cc42039ccfc333fb42ce5f8513382e56c5b02f934005d0d6e8ff + languageName: node + linkType: hard + +"@babel/plugin-transform-block-scoping@npm:^7.24.1": + version: 7.25.0 + resolution: "@babel/plugin-transform-block-scoping@npm:7.25.0" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/981e565a8ff1e1f8d539b5ff067328517233142b131329d11e6c60405204e2a4a993828c367f7dc729a9608aabebdada869616563816e5f8f1385e91ac0fa4d6 + languageName: node + linkType: hard + +"@babel/plugin-transform-class-properties@npm:^7.24.1": + version: 7.25.4 + resolution: "@babel/plugin-transform-class-properties@npm:7.25.4" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.25.4" + "@babel/helper-plugin-utils": "npm:^7.24.8" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/203a21384303d66fb5d841b77cba8b8994623ff4d26d208e3d05b36858c4919626a8d74871fa4b9195310c2e7883bf180359c4f5a76481ea55190c224d9746f4 + languageName: node + linkType: hard + +"@babel/plugin-transform-class-static-block@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-class-static-block@npm:7.24.7" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.12.0 + checksum: 10/00b4d35788bcfefb56b6a1d3506ca23f11dd55d4bb5a34eb70397c06283dc7f596cd9d40995c4a6cb897b45ad220de211f854e7a030a05e26a307c8f56b6ba4b + languageName: node + linkType: hard + +"@babel/plugin-transform-classes@npm:^7.24.1": + version: 7.25.4 + resolution: "@babel/plugin-transform-classes@npm:7.25.4" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-compilation-targets": "npm:^7.25.2" + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-replace-supers": "npm:^7.25.0" + "@babel/traverse": "npm:^7.25.4" + globals: "npm:^11.1.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/17db5889803529bec366c6f0602687fdd605c2fec8cb6fe918261cb55cd89e9d8c9aa2aa6f3fd64d36492ce02d7d0752b09a284b0f833c1185f7dad9b9506310 + languageName: node + linkType: hard + +"@babel/plugin-transform-computed-properties@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-computed-properties@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/template": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/fecf3c770b2dd8e70be6da12d4dd0273de9d8ef4d0f46be98d56fddb3a451932cdc9bb81de3057c9acb903e05ece657886cc31886d5762afa7b0a256db0f791e + languageName: node + linkType: hard + +"@babel/plugin-transform-destructuring@npm:^7.24.1": + version: 7.24.8 + resolution: "@babel/plugin-transform-destructuring@npm:7.24.8" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/e3bba0bb050592615fbf062ea07ae94f99e9cf22add006eaa66ed672d67ff7051b578a5ea68a7d79f9184fb3c27c65333d86b0b8ea04f9810bcccbeea2ffbe76 + languageName: node + linkType: hard + +"@babel/plugin-transform-dotall-regex@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-dotall-regex@npm:7.24.7" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/51b75638748f6e5adab95b711d3365b8d7757f881c178946618a43b15063ec1160b07f4aa3b116bf3f1e097a88226a01db4cae2c5c4aad4c71fe5568828a03f5 + languageName: node + linkType: hard + +"@babel/plugin-transform-duplicate-keys@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-duplicate-keys@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/4284d8fe058c838f80d594bace1380ce02995fa9a271decbece59c40815bc2f7e715807dcbe4d5da8b444716e6d05cc6d79771f500fb044cd0dd00ce4324b619 + languageName: node + linkType: hard + +"@babel/plugin-transform-dynamic-import@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-dynamic-import@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/e949c02aa57098d916eb6edcbef0f3f7d62640f37e1a061b0692523964e081f8182f2c4292173b4dbea4edb8d146e65d6a20ce4b6b5f8c33be34bd846ae114ea + languageName: node + linkType: hard + +"@babel/plugin-transform-exponentiation-operator@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-exponentiation-operator@npm:7.24.7" + dependencies: + "@babel/helper-builder-binary-assignment-operator-visitor": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/014b211f73a524ee98441541ddc4f6b067eefcf94d509e99074a45ea8c3f3ad0e36cab6f5f96666ac05b747a21fa6fda949aa25153656bb2821545a4b302e0d4 + languageName: node + linkType: hard + +"@babel/plugin-transform-export-namespace-from@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-export-namespace-from@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/d59d21945d2fd1ead914bb21f909f75b70ebe0e7627c2b1326ce500babca4c8e4a2513af6899d92e06e87186c61ee5087209345f5102fb4ff5a0e47e7b159a2c + languageName: node + linkType: hard + +"@babel/plugin-transform-flow-strip-types@npm:^7.24.1": + version: 7.25.2 + resolution: "@babel/plugin-transform-flow-strip-types@npm:7.25.2" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/plugin-syntax-flow": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/b5a54395a5c6d7f94de78855f449398c9b850acc299e7d872774f695fdde6006a87bcc9e70ffe33d935883761e9a4e82328c9cff6e2afaf568f04fb646886706 + languageName: node + linkType: hard + +"@babel/plugin-transform-for-of@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-for-of@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/ea471ad1345f1153f7f72f1f084e74f48dc349272ca1b2d8710b841b015c9861d673e12c3c98d42ab3c640cb6ab88bb9a8da1f4ca9c57a8f71f00815fa23ecef + languageName: node + linkType: hard + +"@babel/plugin-transform-function-name@npm:^7.24.1": + version: 7.25.1 + resolution: "@babel/plugin-transform-function-name@npm:7.25.1" + dependencies: + "@babel/helper-compilation-targets": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/traverse": "npm:^7.25.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/1b4cd214c8523f7fa024fcda540ffe5503eda0e0be08b7c21405c96a870b5fe8bb1bda9e23a43a31467bf3dfc3a08edca250cf7f55f09dc40759a1ca6c6d6a4a + languageName: node + linkType: hard + +"@babel/plugin-transform-json-strings@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-json-strings@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-json-strings": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/5549dc97fc2d429a089d14ccfd51d8b3ba23c39b79edfe6d754e804fb1d50e6a4c070e73550be514a919c4db1553d8e6f7406178d68756b5959afe025a602cb2 + languageName: node + linkType: hard + +"@babel/plugin-transform-literals@npm:^7.24.1": + version: 7.25.2 + resolution: "@babel/plugin-transform-literals@npm:7.25.2" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/d9728625a6d55305610dd37057fe1a3473df4f3789fef693c900516caf8958dfb341394ecf69ce9b60c82c422ad2954491a7e4d4533432fd5df812827443d6e9 + languageName: node + linkType: hard + +"@babel/plugin-transform-logical-assignment-operators@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-logical-assignment-operators@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/e39581cf1f9a43330b8340177c618fdb3232deb03faab1937819ef39327660a1fe94fd0ec2f66d1f5b5f98acba68871a77a9931588011c13dded3d7094ecc9de + languageName: node + linkType: hard + +"@babel/plugin-transform-member-expression-literals@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-member-expression-literals@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/837b60ea42fc69a430c8f7fb124247ba009ff6d93187a521fe9f83556fe124715bd46533b1684a3e139f272849a14d1d4faf3397bde13714f99ce0938526ea6f + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-amd@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-modules-amd@npm:7.24.7" + dependencies: + "@babel/helper-module-transforms": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/66465ffba49af7a7b7a62995eb58f591ecd23ab42b0c67f8a70020177b3789d2a379bd6cbb68cbd09a69fd75c38a91f5a09ea70f5c8347bf4c6ea81caa0f6c6b + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-commonjs@npm:^7.24.1": + version: 7.24.8 + resolution: "@babel/plugin-transform-modules-commonjs@npm:7.24.8" + dependencies: + "@babel/helper-module-transforms": "npm:^7.24.8" + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-simple-access": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/18e5d229767c7b5b6ff0cbf1a8d2d555965b90201839d0ac2dc043b56857624ea344e59f733f028142a8c1d54923b82e2a0185694ef36f988d797bfbaf59819c + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-systemjs@npm:^7.24.1": + version: 7.25.0 + resolution: "@babel/plugin-transform-modules-systemjs@npm:7.25.0" + dependencies: + "@babel/helper-module-transforms": "npm:^7.25.0" + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-validator-identifier": "npm:^7.24.7" + "@babel/traverse": "npm:^7.25.0" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/2c38efdbaf6faf730cdcb0c5e42d2d15bb114eecf184db078319de496b5e3ce68d499e531265a0e13e29f0dcaa001f240773db5c4c078eac7f4456d6c8bddd88 + languageName: node + linkType: hard + +"@babel/plugin-transform-modules-umd@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-modules-umd@npm:7.24.7" + dependencies: + "@babel/helper-module-transforms": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/cef9c8917b3c35c3b6cb424dc2e6f74016122f1d25c196e2c7e51eb080d95e96c5d34966c0d5b9d4e17b8e60d455a97ed271317ed104e0e70bff159830a59678 + languageName: node + linkType: hard + +"@babel/plugin-transform-named-capturing-groups-regex@npm:^7.22.5": + version: 7.24.7 + resolution: "@babel/plugin-transform-named-capturing-groups-regex@npm:7.24.7" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/b0ecb1afd22946b21fb8f34e826cfbfea4b5337f7592a5ff8af7937eddec4440149c59d2d134b4f21b2ed91b57611f39b19827729e19d99b7c11eaf614435f83 + languageName: node + linkType: hard + +"@babel/plugin-transform-new-target@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-new-target@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/91b6a7439b7622f80dc755ddfb9ab083355bedc0b2af18e7c7a948faed14467599609331c8d59cfab4273640e3fc36e4cd02ad5b6dcb4a428f5a8baefc507acc + languageName: node + linkType: hard + +"@babel/plugin-transform-nullish-coalescing-operator@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-nullish-coalescing-operator@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/113cd24b6ce4d0a8e54ad9324428244942ce752a3fd38f8b615c3a786641ec18a00a01b662fe4cbebf369358f5904a975bbde0a977b839f2438b16f0d7d1dd36 + languageName: node + linkType: hard + +"@babel/plugin-transform-numeric-separator@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-numeric-separator@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/dc5bb0534889d207b1da125635471c42da61a4a4e9e68855f24b1cd04ccdcf8325b2c29112e719913c2097242e7e62d660e0fea2a46f3a9a983c9d02a0ec7a04 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-rest-spread@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-object-rest-spread@npm:7.24.7" + dependencies: + "@babel/helper-compilation-targets": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" + "@babel/plugin-transform-parameters": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/d586995dc3396bbf8fb75b84f0a3548d923e4c3500bb414641a7fe30762a4ffd82987887fece6381f600d8de2da1e3310fc9a725271724d35f9020fcd5d4b2a3 + languageName: node + linkType: hard + +"@babel/plugin-transform-object-super@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-object-super@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-replace-supers": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/382739a017972d7126416b958ea81b4b950b6275414908a54bfef6aeed9b9fcc6c8d247db3a1134b09a3b355a60039670ce41ee41c626f8acec70f49c3c8d2a6 + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-catch-binding@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-optional-catch-binding@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/605ae3764354e83f73c1e6430bac29e308806abcce8d1369cf69e4921771ff3592e8f60ba60c15990070d79b8d8740f0841069d64b466b3ce8a8c43e9743da7e + languageName: node + linkType: hard + +"@babel/plugin-transform-optional-chaining@npm:^7.24.1, @babel/plugin-transform-optional-chaining@npm:^7.24.7": + version: 7.24.8 + resolution: "@babel/plugin-transform-optional-chaining@npm:7.24.8" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/1f873fb9d86c280b64dfe5ebc59244b459b717ed72a7682da2386db3d9e11fc9d831cfc2e11d37262b4325a7a0e3ccbccfb8cd0b944caf199d3c9e03fff7b0af + languageName: node + linkType: hard + +"@babel/plugin-transform-parameters@npm:^7.24.1, @babel/plugin-transform-parameters@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/plugin-transform-parameters@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/41ff6bda926fabfb2e5d90b70621f279330691bed92009297340a8e776cfe9c3f2dda6afbc31dd3cbdccdfa9a5c57f2046e3ccc84f963c3797356df003d1703a + languageName: node + linkType: hard + +"@babel/plugin-transform-private-methods@npm:^7.24.1": + version: 7.25.4 + resolution: "@babel/plugin-transform-private-methods@npm:7.25.4" + dependencies: + "@babel/helper-create-class-features-plugin": "npm:^7.25.4" + "@babel/helper-plugin-utils": "npm:^7.24.8" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/d5c29ba121d6ce40e8055a632c32e69006c513607145a29701f93b416a8c53a60e53565df417218e2d8b7f1ba73adb837601e8e9d0a3215da50e4c9507f9f1fa + languageName: node + linkType: hard + +"@babel/plugin-transform-private-property-in-object@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-private-property-in-object@npm:7.24.7" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-create-class-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/a23ee18340818e292abfcb98b1086a188c81d640b1045e6809e9a3e8add78f9cb26607774de4ed653cbecd4277965dc4f4f1affc3504682209bb2a65fd4251f8 + languageName: node + linkType: hard + +"@babel/plugin-transform-property-literals@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-property-literals@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/71708890fe007d45ad7a130150a2ba1fea0205f575b925ca2e1bb65018730636a68e65c634a474e5b658378d72871c337c953560009c081a645e088769bf168a + languageName: node + linkType: hard + +"@babel/plugin-transform-react-display-name@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-react-display-name@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/f5d34903680ca358c5a3ccb83421df259e5142be95dde51dc4a62ec79fd6558599b3b92b4afd37329d2567a4ba4c338f1c817f8ce0c56ddf20cd3d051498649e + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx-development@npm:^7.22.5": + version: 7.24.7 + resolution: "@babel/plugin-transform-react-jsx-development@npm:7.24.7" + dependencies: + "@babel/plugin-transform-react-jsx": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/5a158803ad71ed7c434ad047755eb98feb2c428800163ff0be1351dc06ecdd19ab503cb6a1fda8708b05decde3a9297499eb0954317af79f191b4d45135af2a2 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-jsx@npm:^7.23.4, @babel/plugin-transform-react-jsx@npm:^7.24.7": + version: 7.25.2 + resolution: "@babel/plugin-transform-react-jsx@npm:7.25.2" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-module-imports": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.8" + "@babel/plugin-syntax-jsx": "npm:^7.24.7" + "@babel/types": "npm:^7.25.2" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/4cab88496285a98853413c9b2525053506728f13d04aefc1b37e6d9f0dc4ea15e0d4c9e59b36b43d0b204bd3c56761e7b0ec56b3ae60a58880a0017b157a0250 + languageName: node + linkType: hard + +"@babel/plugin-transform-react-pure-annotations@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-react-pure-annotations@npm:7.24.7" + dependencies: + "@babel/helper-annotate-as-pure": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/c5110fa6088be5c4ac6d0f716cd032d30a246f371948b2ef30beb9eac187550ccbf972aa02051e780321917e1d9d85325623f68742c91e0355d238a8f5422179 + languageName: node + linkType: hard + +"@babel/plugin-transform-regenerator@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-regenerator@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + regenerator-transform: "npm:^0.15.2" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/70fa2bb36d3e2ce69a25c7227da8ad92307ab7b50cb6dfcc4dc5ce8f1cc79b0fcf997292a1cb3b4ae7cb136f515d1b2c3fb78c927bdba8d719794430403eb0c6 + languageName: node + linkType: hard + +"@babel/plugin-transform-reserved-words@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-reserved-words@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/64a2669671bb97c3dee3830a82c3e932fe6e02d56a4053c6ee4453d317b5f436d3d44907fbb0f4fbd8a56ebee34f6aee250e49743b7243d14d00c069215f3113 + languageName: node + linkType: hard + +"@babel/plugin-transform-shorthand-properties@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-shorthand-properties@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/c68c2be965007e0cb6667daa209bc0af877cab4b327ef2e21b2114c38554243c3f7fdcc5b03679b20f72a26d966aa646af771f3165c882067e85a3887647f028 + languageName: node + linkType: hard + +"@babel/plugin-transform-spread@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-spread@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + "@babel/helper-skip-transparent-expression-wrappers": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/76e2c8544129d727d5a698e2a67d74e438bc35df843adb5f769316ec432c5e1bbb4128123a95b2fe8ef0aec7b26d87efe81d64326291c77ad757ff184d38448a + languageName: node + linkType: hard + +"@babel/plugin-transform-sticky-regex@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-sticky-regex@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/3b9a99ae043ef363c81bfb097fa7a553fcf7c7d9fddc13dd2b47b3b2e45cf2741a9ca78cfe55f463983b043b365f0f8452f2d5eaadbdea20e6d6de50c16bed25 + languageName: node + linkType: hard + +"@babel/plugin-transform-template-literals@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-template-literals@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/ecf05a8511176d5570cb0d481577a407a4e8a9a430f86522d809e0ac2c823913e854ef9e2a1c83c0bd7c12489d82e1b48fabb52e697e80d6a6962125197593ca + languageName: node + linkType: hard + +"@babel/plugin-transform-typeof-symbol@npm:^7.24.1": + version: 7.24.8 + resolution: "@babel/plugin-transform-typeof-symbol@npm:7.24.8" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.8" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/5f113fed94b694ec4a40a27b8628ce736cfa172b69fcffa2833c9a41895032127f3daeea552e94fdb4a3ce4e8cd51de67a670ab87a1f447a0cf55c9cb2d7ed11 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-escapes@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-unicode-escapes@npm:7.24.7" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/6b8bca3495acedc89e880942de7b83c263fb5b4c9599594dcf3923e2128ae25f1f4725a295fe101027f75d8ef081ef28319296adf274b5022e57039e42836103 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-property-regex@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-unicode-property-regex@npm:7.24.7" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/c0c284bbbdead7e17e059d72e1b288f86b0baacc410398ef6c6c703fe4326b069e68515ccb84359601315cd8e888f9226731d00624b7c6959b1c0853f072b61f + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-regex@npm:^7.24.1": + version: 7.24.7 + resolution: "@babel/plugin-transform-unicode-regex@npm:7.24.7" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.24.7" + "@babel/helper-plugin-utils": "npm:^7.24.7" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/b545310d0d592d75566b9cd158f4b8951e34d07d839656789d179b39b3fd92b32bd387cdfaf33a93e636609f3bfb9bb03d41f3e43be598116c9c6c80cc3418c4 + languageName: node + linkType: hard + +"@babel/plugin-transform-unicode-sets-regex@npm:^7.24.1": + version: 7.25.4 + resolution: "@babel/plugin-transform-unicode-sets-regex@npm:7.25.4" + dependencies: + "@babel/helper-create-regexp-features-plugin": "npm:^7.25.2" + "@babel/helper-plugin-utils": "npm:^7.24.8" + peerDependencies: + "@babel/core": ^7.0.0 + checksum: 10/d5d07d17932656fa4d62fd67ecaa1a5e4c2e92365a924f1a2a8cf8108762f137a30cd55eb3a7d0504258f27a19ad0decca6b62a5c37a5aada709cbb46c4a871f + languageName: node + linkType: hard + +"@babel/preset-env@npm:7.24.3": + version: 7.24.3 + resolution: "@babel/preset-env@npm:7.24.3" + dependencies: + "@babel/compat-data": "npm:^7.24.1" + "@babel/helper-compilation-targets": "npm:^7.23.6" + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-validator-option": "npm:^7.23.5" + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "npm:^7.24.1" + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "npm:^7.24.1" + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "npm:^7.24.1" + "@babel/plugin-proposal-private-property-in-object": "npm:7.21.0-placeholder-for-preset-env.2" + "@babel/plugin-syntax-async-generators": "npm:^7.8.4" + "@babel/plugin-syntax-class-properties": "npm:^7.12.13" + "@babel/plugin-syntax-class-static-block": "npm:^7.14.5" + "@babel/plugin-syntax-dynamic-import": "npm:^7.8.3" + "@babel/plugin-syntax-export-namespace-from": "npm:^7.8.3" + "@babel/plugin-syntax-import-assertions": "npm:^7.24.1" + "@babel/plugin-syntax-import-attributes": "npm:^7.24.1" + "@babel/plugin-syntax-import-meta": "npm:^7.10.4" + "@babel/plugin-syntax-json-strings": "npm:^7.8.3" + "@babel/plugin-syntax-logical-assignment-operators": "npm:^7.10.4" + "@babel/plugin-syntax-nullish-coalescing-operator": "npm:^7.8.3" + "@babel/plugin-syntax-numeric-separator": "npm:^7.10.4" + "@babel/plugin-syntax-object-rest-spread": "npm:^7.8.3" + "@babel/plugin-syntax-optional-catch-binding": "npm:^7.8.3" + "@babel/plugin-syntax-optional-chaining": "npm:^7.8.3" + "@babel/plugin-syntax-private-property-in-object": "npm:^7.14.5" + "@babel/plugin-syntax-top-level-await": "npm:^7.14.5" + "@babel/plugin-syntax-unicode-sets-regex": "npm:^7.18.6" + "@babel/plugin-transform-arrow-functions": "npm:^7.24.1" + "@babel/plugin-transform-async-generator-functions": "npm:^7.24.3" + "@babel/plugin-transform-async-to-generator": "npm:^7.24.1" + "@babel/plugin-transform-block-scoped-functions": "npm:^7.24.1" + "@babel/plugin-transform-block-scoping": "npm:^7.24.1" + "@babel/plugin-transform-class-properties": "npm:^7.24.1" + "@babel/plugin-transform-class-static-block": "npm:^7.24.1" + "@babel/plugin-transform-classes": "npm:^7.24.1" + "@babel/plugin-transform-computed-properties": "npm:^7.24.1" + "@babel/plugin-transform-destructuring": "npm:^7.24.1" + "@babel/plugin-transform-dotall-regex": "npm:^7.24.1" + "@babel/plugin-transform-duplicate-keys": "npm:^7.24.1" + "@babel/plugin-transform-dynamic-import": "npm:^7.24.1" + "@babel/plugin-transform-exponentiation-operator": "npm:^7.24.1" + "@babel/plugin-transform-export-namespace-from": "npm:^7.24.1" + "@babel/plugin-transform-for-of": "npm:^7.24.1" + "@babel/plugin-transform-function-name": "npm:^7.24.1" + "@babel/plugin-transform-json-strings": "npm:^7.24.1" + "@babel/plugin-transform-literals": "npm:^7.24.1" + "@babel/plugin-transform-logical-assignment-operators": "npm:^7.24.1" + "@babel/plugin-transform-member-expression-literals": "npm:^7.24.1" + "@babel/plugin-transform-modules-amd": "npm:^7.24.1" + "@babel/plugin-transform-modules-commonjs": "npm:^7.24.1" + "@babel/plugin-transform-modules-systemjs": "npm:^7.24.1" + "@babel/plugin-transform-modules-umd": "npm:^7.24.1" + "@babel/plugin-transform-named-capturing-groups-regex": "npm:^7.22.5" + "@babel/plugin-transform-new-target": "npm:^7.24.1" + "@babel/plugin-transform-nullish-coalescing-operator": "npm:^7.24.1" + "@babel/plugin-transform-numeric-separator": "npm:^7.24.1" + "@babel/plugin-transform-object-rest-spread": "npm:^7.24.1" + "@babel/plugin-transform-object-super": "npm:^7.24.1" + "@babel/plugin-transform-optional-catch-binding": "npm:^7.24.1" + "@babel/plugin-transform-optional-chaining": "npm:^7.24.1" + "@babel/plugin-transform-parameters": "npm:^7.24.1" + "@babel/plugin-transform-private-methods": "npm:^7.24.1" + "@babel/plugin-transform-private-property-in-object": "npm:^7.24.1" + "@babel/plugin-transform-property-literals": "npm:^7.24.1" + "@babel/plugin-transform-regenerator": "npm:^7.24.1" + "@babel/plugin-transform-reserved-words": "npm:^7.24.1" + "@babel/plugin-transform-shorthand-properties": "npm:^7.24.1" + "@babel/plugin-transform-spread": "npm:^7.24.1" + "@babel/plugin-transform-sticky-regex": "npm:^7.24.1" + "@babel/plugin-transform-template-literals": "npm:^7.24.1" + "@babel/plugin-transform-typeof-symbol": "npm:^7.24.1" + "@babel/plugin-transform-unicode-escapes": "npm:^7.24.1" + "@babel/plugin-transform-unicode-property-regex": "npm:^7.24.1" + "@babel/plugin-transform-unicode-regex": "npm:^7.24.1" + "@babel/plugin-transform-unicode-sets-regex": "npm:^7.24.1" + "@babel/preset-modules": "npm:0.1.6-no-external-plugins" + babel-plugin-polyfill-corejs2: "npm:^0.4.10" + babel-plugin-polyfill-corejs3: "npm:^0.10.4" + babel-plugin-polyfill-regenerator: "npm:^0.6.1" + core-js-compat: "npm:^3.31.0" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/42de398cb7655f3748a03f9f5ca6132dd8e84315ccf286e47740455dfb5be6358df7cfcbecf84426c14176a4d02d0b0b3c97ddf6c5c4c8fb7f1f307692a103ee + languageName: node + linkType: hard + +"@babel/preset-flow@npm:7.24.1": + version: 7.24.1 + resolution: "@babel/preset-flow@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-validator-option": "npm:^7.23.5" + "@babel/plugin-transform-flow-strip-types": "npm:^7.24.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/f1402746050a1c03af9509791bb88e90d1d56a3063374278a80b030c6d1f48a462a822a1a66826d0a631cb5424fc70bf91a25de5f7f31ff519553a3e190a0b7e + languageName: node + linkType: hard + +"@babel/preset-modules@npm:0.1.6-no-external-plugins": + version: 0.1.6-no-external-plugins + resolution: "@babel/preset-modules@npm:0.1.6-no-external-plugins" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.0.0" + "@babel/types": "npm:^7.4.4" + esutils: "npm:^2.0.2" + peerDependencies: + "@babel/core": ^7.0.0-0 || ^8.0.0-0 <8.0.0 + checksum: 10/039aba98a697b920d6440c622aaa6104bb6076d65356b29dad4b3e6627ec0354da44f9621bafbeefd052cd4ac4d7f88c9a2ab094efcb50963cb352781d0c6428 + languageName: node + linkType: hard + +"@babel/preset-react@npm:7.24.1": + version: 7.24.1 + resolution: "@babel/preset-react@npm:7.24.1" + dependencies: + "@babel/helper-plugin-utils": "npm:^7.24.0" + "@babel/helper-validator-option": "npm:^7.23.5" + "@babel/plugin-transform-react-display-name": "npm:^7.24.1" + "@babel/plugin-transform-react-jsx": "npm:^7.23.4" + "@babel/plugin-transform-react-jsx-development": "npm:^7.22.5" + "@babel/plugin-transform-react-pure-annotations": "npm:^7.24.1" + peerDependencies: + "@babel/core": ^7.0.0-0 + checksum: 10/a796c609ace7d58a56b42b6630cdd9e1d896ce2f8b35331b9ea040eaaf3cc9aa99cd2614e379a27c10410f34e89355e2739c7097e8065ce5e40900a77b13d716 + languageName: node + linkType: hard + +"@babel/regjsgen@npm:^0.8.0": + version: 0.8.0 + resolution: "@babel/regjsgen@npm:0.8.0" + checksum: 10/c57fb730b17332b7572574b74364a77d70faa302a281a62819476fa3b09822974fd75af77aea603ad77378395be64e81f89f0e800bf86cbbf21652d49ce12ee8 + languageName: node + linkType: hard + +"@babel/runtime@npm:^7.8.4": + version: 7.25.6 + resolution: "@babel/runtime@npm:7.25.6" + dependencies: + regenerator-runtime: "npm:^0.14.0" + checksum: 10/0c4134734deb20e1005ffb9165bf342e1074576621b246d8e5e41cc7cb315a885b7d98950fbf5c63619a2990a56ae82f444d35fe8c4691a0b70c2fe5673667dc + languageName: node + linkType: hard + +"@babel/template@npm:^7.24.0, @babel/template@npm:^7.25.0": + version: 7.25.0 + resolution: "@babel/template@npm:7.25.0" + dependencies: + "@babel/code-frame": "npm:^7.24.7" + "@babel/parser": "npm:^7.25.0" + "@babel/types": "npm:^7.25.0" + checksum: 10/07ebecf6db8b28244b7397628e09c99e7a317b959b926d90455c7253c88df3677a5a32d1501d9749fe292a263ff51a4b6b5385bcabd5dadd3a48036f4d4949e0 + languageName: node + linkType: hard + +"@babel/template@npm:^7.24.7, @babel/template@npm:^7.3.3": + version: 7.24.7 + resolution: "@babel/template@npm:7.24.7" + dependencies: + "@babel/code-frame": "npm:^7.24.7" + "@babel/parser": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + checksum: 10/5975d404ef51cf379515eb0f80b115981d0b9dff5539e53a47516644abb8c83d7559f5b083eb1d4977b20d8359ebb2f911ccd4f729143f8958fdc465f976d843 + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.24.1, @babel/traverse@npm:^7.24.8, @babel/traverse@npm:^7.25.0, @babel/traverse@npm:^7.25.1, @babel/traverse@npm:^7.25.2, @babel/traverse@npm:^7.25.4": + version: 7.25.6 + resolution: "@babel/traverse@npm:7.25.6" + dependencies: + "@babel/code-frame": "npm:^7.24.7" + "@babel/generator": "npm:^7.25.6" + "@babel/parser": "npm:^7.25.6" + "@babel/template": "npm:^7.25.0" + "@babel/types": "npm:^7.25.6" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10/de75a918299bc27a44ec973e3f2fa8c7902bbd67bd5d39a0be656f3c1127f33ebc79c12696fbc8170a0b0e1072a966d4a2126578d7ea2e241b0aeb5d16edc738 + languageName: node + linkType: hard + +"@babel/traverse@npm:^7.24.7": + version: 7.24.7 + resolution: "@babel/traverse@npm:7.24.7" + dependencies: + "@babel/code-frame": "npm:^7.24.7" + "@babel/generator": "npm:^7.24.7" + "@babel/helper-environment-visitor": "npm:^7.24.7" + "@babel/helper-function-name": "npm:^7.24.7" + "@babel/helper-hoist-variables": "npm:^7.24.7" + "@babel/helper-split-export-declaration": "npm:^7.24.7" + "@babel/parser": "npm:^7.24.7" + "@babel/types": "npm:^7.24.7" + debug: "npm:^4.3.1" + globals: "npm:^11.1.0" + checksum: 10/785cf26383a992740e492efba7016de964cd06c05c9d7146fa1b5ead409e054c444f50b36dc37856884a56e32cf9d3105ddf1543486b6df68300bffb117a245a + languageName: node + linkType: hard + +"@babel/types@npm:^7.0.0, @babel/types@npm:^7.20.7, @babel/types@npm:^7.24.7, @babel/types@npm:^7.3.3, @babel/types@npm:^7.8.3": + version: 7.24.7 + resolution: "@babel/types@npm:7.24.7" + dependencies: + "@babel/helper-string-parser": "npm:^7.24.7" + "@babel/helper-validator-identifier": "npm:^7.24.7" + to-fast-properties: "npm:^2.0.0" + checksum: 10/ad3c8c0d6fb4acb0bb74bb5b4bb849b181bf6185677ef9c59c18856c81e43628d0858253cf232f0eca806f02e08eff85a1d3e636a3e94daea737597796b0b430 + languageName: node + linkType: hard + +"@babel/types@npm:^7.24.0, @babel/types@npm:^7.24.8, @babel/types@npm:^7.25.0, @babel/types@npm:^7.25.2, @babel/types@npm:^7.25.6, @babel/types@npm:^7.4.4": + version: 7.25.6 + resolution: "@babel/types@npm:7.25.6" + dependencies: + "@babel/helper-string-parser": "npm:^7.24.8" + "@babel/helper-validator-identifier": "npm:^7.24.7" + to-fast-properties: "npm:^2.0.0" + checksum: 10/7b54665e1b51f525fe0f451efdd9fe7a4a6dfba3fd4956c3530bc77336b66ffe3d78c093796ed044119b5d213176af7cf326f317a2057c538d575c6cefcb3562 languageName: node linkType: hard @@ -412,100 +1648,94 @@ __metadata: languageName: node linkType: hard -"@colors/colors@npm:1.5.0": - version: 1.5.0 - resolution: "@colors/colors@npm:1.5.0" - checksum: 10/9d226461c1e91e95f067be2bdc5e6f99cfe55a721f45afb44122e23e4b8602eeac4ff7325af6b5a369f36396ee1514d3809af3f57769066d80d83790d8e53339 - languageName: node - linkType: hard - -"@cspell/cspell-bundled-dicts@npm:8.9.1": - version: 8.9.1 - resolution: "@cspell/cspell-bundled-dicts@npm:8.9.1" +"@cspell/cspell-bundled-dicts@npm:8.14.4": + version: 8.14.4 + resolution: "@cspell/cspell-bundled-dicts@npm:8.14.4" dependencies: "@cspell/dict-ada": "npm:^4.0.2" - "@cspell/dict-aws": "npm:^4.0.2" - "@cspell/dict-bash": "npm:^4.1.3" - "@cspell/dict-companies": "npm:^3.1.2" - "@cspell/dict-cpp": "npm:^5.1.10" + "@cspell/dict-aws": "npm:^4.0.4" + "@cspell/dict-bash": "npm:^4.1.4" + "@cspell/dict-companies": "npm:^3.1.4" + "@cspell/dict-cpp": "npm:^5.1.16" "@cspell/dict-cryptocurrencies": "npm:^5.0.0" "@cspell/dict-csharp": "npm:^4.0.2" - "@cspell/dict-css": "npm:^4.0.12" - "@cspell/dict-dart": "npm:^2.0.3" + "@cspell/dict-css": "npm:^4.0.13" + "@cspell/dict-dart": "npm:^2.2.1" "@cspell/dict-django": "npm:^4.1.0" "@cspell/dict-docker": "npm:^1.1.7" - "@cspell/dict-dotnet": "npm:^5.0.2" + "@cspell/dict-dotnet": "npm:^5.0.5" "@cspell/dict-elixir": "npm:^4.0.3" - "@cspell/dict-en-common-misspellings": "npm:^2.0.2" + "@cspell/dict-en-common-misspellings": "npm:^2.0.4" "@cspell/dict-en-gb": "npm:1.1.33" - "@cspell/dict-en_us": "npm:^4.3.22" + "@cspell/dict-en_us": "npm:^4.3.23" "@cspell/dict-filetypes": "npm:^3.0.4" + "@cspell/dict-flutter": "npm:^1.0.0" "@cspell/dict-fonts": "npm:^4.0.0" "@cspell/dict-fsharp": "npm:^1.0.1" - "@cspell/dict-fullstack": "npm:^3.1.8" + "@cspell/dict-fullstack": "npm:^3.2.0" "@cspell/dict-gaming-terms": "npm:^1.0.5" "@cspell/dict-git": "npm:^3.0.0" - "@cspell/dict-golang": "npm:^6.0.9" + "@cspell/dict-golang": "npm:^6.0.12" "@cspell/dict-google": "npm:^1.0.1" "@cspell/dict-haskell": "npm:^4.0.1" "@cspell/dict-html": "npm:^4.0.5" "@cspell/dict-html-symbol-entities": "npm:^4.0.0" "@cspell/dict-java": "npm:^5.0.7" "@cspell/dict-julia": "npm:^1.0.1" - "@cspell/dict-k8s": "npm:^1.0.5" + "@cspell/dict-k8s": "npm:^1.0.6" "@cspell/dict-latex": "npm:^4.0.0" "@cspell/dict-lorem-ipsum": "npm:^4.0.0" "@cspell/dict-lua": "npm:^4.0.3" "@cspell/dict-makefile": "npm:^1.0.0" "@cspell/dict-monkeyc": "npm:^1.0.6" "@cspell/dict-node": "npm:^5.0.1" - "@cspell/dict-npm": "npm:^5.0.16" - "@cspell/dict-php": "npm:^4.0.8" - "@cspell/dict-powershell": "npm:^5.0.4" - "@cspell/dict-public-licenses": "npm:^2.0.7" - "@cspell/dict-python": "npm:^4.2.1" + "@cspell/dict-npm": "npm:^5.1.4" + "@cspell/dict-php": "npm:^4.0.10" + "@cspell/dict-powershell": "npm:^5.0.8" + "@cspell/dict-public-licenses": "npm:^2.0.8" + "@cspell/dict-python": "npm:^4.2.6" "@cspell/dict-r": "npm:^2.0.1" - "@cspell/dict-ruby": "npm:^5.0.2" - "@cspell/dict-rust": "npm:^4.0.4" - "@cspell/dict-scala": "npm:^5.0.2" - "@cspell/dict-software-terms": "npm:^3.4.6" - "@cspell/dict-sql": "npm:^2.1.3" + "@cspell/dict-ruby": "npm:^5.0.3" + "@cspell/dict-rust": "npm:^4.0.5" + "@cspell/dict-scala": "npm:^5.0.3" + "@cspell/dict-software-terms": "npm:^4.1.3" + "@cspell/dict-sql": "npm:^2.1.5" "@cspell/dict-svelte": "npm:^1.0.2" "@cspell/dict-swift": "npm:^2.0.1" - "@cspell/dict-terraform": "npm:^1.0.0" - "@cspell/dict-typescript": "npm:^3.1.5" + "@cspell/dict-terraform": "npm:^1.0.1" + "@cspell/dict-typescript": "npm:^3.1.6" "@cspell/dict-vue": "npm:^3.0.0" - checksum: 10/082041694d0ab7b9153b4beca59bda8703a274d3fd5c1d45c34073055340a2963adb9691778dd5450e7ebc7cd21096c7370f8e5254d0e9ebc7f72fe7c5d30004 + checksum: 10/bb0b11e90ae51c6a242f62513451972c4c0d765438a323e6c66c00fc53352a795acbd50a8c17134c89e120e48878b611d556d9f2675a30651015b21aa713322d languageName: node linkType: hard -"@cspell/cspell-pipe@npm:8.9.1": - version: 8.9.1 - resolution: "@cspell/cspell-pipe@npm:8.9.1" - checksum: 10/cc1137a86a6bcf951961d43e8146c0a42d562ac335f689ec65290b2974a3e4bdc0d05083ddfa8ac877135d692224f4a10021b3da55cdbe8325e55ca764847520 +"@cspell/cspell-pipe@npm:8.14.4": + version: 8.14.4 + resolution: "@cspell/cspell-pipe@npm:8.14.4" + checksum: 10/f2278b23778be271ce4c7b107d70d35aae7493b31c83f7d35a5a38879c1e3bcf354f665000f8d5ae940f528d1c04081859aa7a7ea959949e39b1ff32bb83228e languageName: node linkType: hard -"@cspell/cspell-resolver@npm:8.9.1": - version: 8.9.1 - resolution: "@cspell/cspell-resolver@npm:8.9.1" +"@cspell/cspell-resolver@npm:8.14.4": + version: 8.14.4 + resolution: "@cspell/cspell-resolver@npm:8.14.4" dependencies: global-directory: "npm:^4.0.1" - checksum: 10/97ce0c03619ad1d39c570bdceef97d3c24fa6cfbc95868721b4c5251047f11b18b028a7742aefef187c4e7fbac548cb169435f2aebda3ac319a24005e7cc9e69 + checksum: 10/bc572f07e672cbef866cfd9a20d9df87adbc6c5e7c06dac2a78ff315f0c51fb3ed364c0842792a94019f03f18f7bde6de7433471e94e28ae10916f6787f26d29 languageName: node linkType: hard -"@cspell/cspell-service-bus@npm:8.9.1": - version: 8.9.1 - resolution: "@cspell/cspell-service-bus@npm:8.9.1" - checksum: 10/3ae1c332abe25b5bb42ecbebd5fca5724a3b2697a63b08375e90d3102e1a37d9c54247ecceede247aab0a75166f8fc61dbba9bced9d8de0b2c04aa3d4a35c8b0 +"@cspell/cspell-service-bus@npm:8.14.4": + version: 8.14.4 + resolution: "@cspell/cspell-service-bus@npm:8.14.4" + checksum: 10/cd4981e7c9317f46e19f030576d2ad2f0f27375bb418c90b463eb52db2be64ac2c452b004705871fce5e1d4409069263707597f60e57d3acc33fc061f69e5536 languageName: node linkType: hard -"@cspell/cspell-types@npm:8.9.1": - version: 8.9.1 - resolution: "@cspell/cspell-types@npm:8.9.1" - checksum: 10/2c342cd005023d2969f50c50161ddfc9fd79d0cc6279da44d6746c09b2347d7a8c2c2478d14f8d0b9dc5826daaa86be270bcfb899d35661cc9616e1fd417fea4 +"@cspell/cspell-types@npm:8.14.4": + version: 8.14.4 + resolution: "@cspell/cspell-types@npm:8.14.4" + checksum: 10/231e660c80e29b128e4ad752c25538c04fcd10ddc268f158b23ba170dffeaabecbc2aeff3e8c470873bb3895cf75db8ca1b88a854d6463956107af98d642d59b languageName: node linkType: hard @@ -516,31 +1746,31 @@ __metadata: languageName: node linkType: hard -"@cspell/dict-aws@npm:^4.0.2": - version: 4.0.2 - resolution: "@cspell/dict-aws@npm:4.0.2" - checksum: 10/7f784f0a054f4d142a22e94d411d6383b5bbba8b1d77952d45664a3bf35626926a0b8057293663287e6c53655c7dd32c6348905ecceb2970056e1cc5cf962e11 +"@cspell/dict-aws@npm:^4.0.4": + version: 4.0.4 + resolution: "@cspell/dict-aws@npm:4.0.4" + checksum: 10/33c07f44a0c8d787739e9c36d9c9922297958e4cea0f7f5ef77da366eaf647f6edfaf1bbc391fdcc9113b19ada12af75fdced4e640a1d9f3d2ea617756532470 languageName: node linkType: hard -"@cspell/dict-bash@npm:^4.1.3": - version: 4.1.3 - resolution: "@cspell/dict-bash@npm:4.1.3" - checksum: 10/4ba66c76c144d4c7ea1dd0fb92dfb0d7fd1e43a106a73fc7e9010b4a5c276aa4ef791c7161f56bf911356e3667ba043ee63271c1ffc485d9f8712553770e3ea9 +"@cspell/dict-bash@npm:^4.1.4": + version: 4.1.4 + resolution: "@cspell/dict-bash@npm:4.1.4" + checksum: 10/e7716f6f7eb22914a24171b71e00a65a354ab45d2e99b0ef032910f8d38af83610f6d7f73944ad01d434a987bddabb08bd374a21574e46f05ebd26c3f0a2231b languageName: node linkType: hard -"@cspell/dict-companies@npm:^3.1.2": - version: 3.1.2 - resolution: "@cspell/dict-companies@npm:3.1.2" - checksum: 10/58a95faba7cf7397530064ab9fc29aea0b5a95c5d4c31abd2abd0537f344705c71112a50ae61a1c026078dd1ca2e4433164eee1761cd05bfae4b25a75161ba4f +"@cspell/dict-companies@npm:^3.1.4": + version: 3.1.4 + resolution: "@cspell/dict-companies@npm:3.1.4" + checksum: 10/2668b80fc7e6aa9efa60f50bb39525caecd06b7f23685b60567f1ca0a1e47cebefcb5c2b877db24efda526a19c85c06af47f57368c399c948b20c5d5ed9c40e2 languageName: node linkType: hard -"@cspell/dict-cpp@npm:^5.1.10": - version: 5.1.10 - resolution: "@cspell/dict-cpp@npm:5.1.10" - checksum: 10/ba8727af8ab3ac18f0ba030f043378bb6c951d819b7fba0114ca9377271752d04c1b3b6dfe4f9384fc35069ab7ff671313bc681a06345ef6625be7ca7fc37132 +"@cspell/dict-cpp@npm:^5.1.16": + version: 5.1.16 + resolution: "@cspell/dict-cpp@npm:5.1.16" + checksum: 10/a29121590c45918cc56b7936ce3ea608013068305040f4764b4c9dd3126d769ce7d24b36d490fbac445ecfeb2515cd0833c053d3f258a437231c424b222c834f languageName: node linkType: hard @@ -558,17 +1788,17 @@ __metadata: languageName: node linkType: hard -"@cspell/dict-css@npm:^4.0.12": - version: 4.0.12 - resolution: "@cspell/dict-css@npm:4.0.12" - checksum: 10/da812243c92ef07082334d512561606f178e003fa50324332c322655fab0982ed1bea055d75a348b37cea71fbe652224dcfff14dc445d26530cfa3c491b2b324 +"@cspell/dict-css@npm:^4.0.13": + version: 4.0.13 + resolution: "@cspell/dict-css@npm:4.0.13" + checksum: 10/1141d60200d665a3c124201f40eaf883309e6e846bc5fedb78dbd90ef1156f8894278ecf9a5b71752e69727c6ba231bbf9c528c28f405a0463e69b5e9b55931e languageName: node linkType: hard -"@cspell/dict-dart@npm:^2.0.3": - version: 2.0.3 - resolution: "@cspell/dict-dart@npm:2.0.3" - checksum: 10/66bfcfa029baacd0b14b3ff5b6ab7597cf9459f77185d88b25123b42a4babb66df6786806843f1b6506c335326100599a2e1db6e6104e66bd021ede9ccb3cec4 +"@cspell/dict-dart@npm:^2.2.1": + version: 2.2.1 + resolution: "@cspell/dict-dart@npm:2.2.1" + checksum: 10/73f003880011fe48a95267966cde27f6c45f0b99acfda5926893569aa85f6267f29d376ee4a9b8e49d5d77720a2e03017a29d1258e4037a4f98dc8af39552310 languageName: node linkType: hard @@ -593,10 +1823,10 @@ __metadata: languageName: node linkType: hard -"@cspell/dict-dotnet@npm:^5.0.2": - version: 5.0.2 - resolution: "@cspell/dict-dotnet@npm:5.0.2" - checksum: 10/319c6ed2793ad9f5ab01b2a7a3fa7280edd762714ff109dfafc24b397bc7ba7e8917cf8c68dd2d124eb11a7b7f60e677b1fd36d3610733b3f32668f966902ebd +"@cspell/dict-dotnet@npm:^5.0.5": + version: 5.0.5 + resolution: "@cspell/dict-dotnet@npm:5.0.5" + checksum: 10/c04bd460bcb322f6d1300d6a2a6e5c1fd2a20defd85d94d253187061df18572491dab60fec7f94ce8ce28cbad158e98ea588ffef3575a1f88039851143b97f4c languageName: node linkType: hard @@ -607,10 +1837,10 @@ __metadata: languageName: node linkType: hard -"@cspell/dict-en-common-misspellings@npm:^2.0.2": - version: 2.0.3 - resolution: "@cspell/dict-en-common-misspellings@npm:2.0.3" - checksum: 10/8ea5f6843635089a82f135ca4302b8ed0c208254cda83b56fa72a72a30ee983452a1abaf003f5ccf76a8f1faf9596da91dfe4441f2bbd00145b305a2e501311e +"@cspell/dict-en-common-misspellings@npm:^2.0.4": + version: 2.0.4 + resolution: "@cspell/dict-en-common-misspellings@npm:2.0.4" + checksum: 10/06319ddc791f4ac3d466e0810f013264cbffa97daa87675878ec70dc6ce1fb53f5c2f19c040894633bb6f584dcefaa64554054a42be67e2cd11e5250161c8183 languageName: node linkType: hard @@ -621,7 +1851,7 @@ __metadata: languageName: node linkType: hard -"@cspell/dict-en_us@npm:^4.3.22": +"@cspell/dict-en_us@npm:^4.3.23": version: 4.3.23 resolution: "@cspell/dict-en_us@npm:4.3.23" checksum: 10/d1c9a5b599ab13a9fe572b240e473b87945bd95ffbe9d39b66da2938b3902dc84448a1ce120c99b22bdcad0e0547523f1d92f027ea38ed8d5902441bbb0c0c53 @@ -635,6 +1865,13 @@ __metadata: languageName: node linkType: hard +"@cspell/dict-flutter@npm:^1.0.0": + version: 1.0.0 + resolution: "@cspell/dict-flutter@npm:1.0.0" + checksum: 10/11f86a1b00e1a190727b1901f4058d0cd35835cc943b8a4b3ba5f3af3b36989fc5521e906788a3931ce0c291d0b3abec25b2b449523de2434e7715fda13a7f18 + languageName: node + linkType: hard + "@cspell/dict-fonts@npm:^4.0.0": version: 4.0.0 resolution: "@cspell/dict-fonts@npm:4.0.0" @@ -649,10 +1886,10 @@ __metadata: languageName: node linkType: hard -"@cspell/dict-fullstack@npm:^3.1.8": - version: 3.1.8 - resolution: "@cspell/dict-fullstack@npm:3.1.8" - checksum: 10/c0f178e751f0e4779600749d5f77e313e33362ba6d4737d3969f64ca272200bb8cc94dd10cccc18de58e60223b46a39247c5e4ca1d5eda768a1d08c1725fb9e7 +"@cspell/dict-fullstack@npm:^3.2.0": + version: 3.2.0 + resolution: "@cspell/dict-fullstack@npm:3.2.0" + checksum: 10/d94179079882a3d7b218aa46dc6de319f844cef038ff126689ebe6f81ff8183b9771c427cfddb96cb80b88f8c2d1d0b078977d284dff5fdae6e6d0fde61abb27 languageName: node linkType: hard @@ -670,10 +1907,10 @@ __metadata: languageName: node linkType: hard -"@cspell/dict-golang@npm:^6.0.9": - version: 6.0.9 - resolution: "@cspell/dict-golang@npm:6.0.9" - checksum: 10/4ce7fc8f1a925eb3c4a2a2a2ae4d75be79e698d2f6cd90ff549892705687011a190b9aabc8bb5c2c7616d24f42a3264121ad8ae056a844937984d301fa7cd90f +"@cspell/dict-golang@npm:^6.0.12": + version: 6.0.12 + resolution: "@cspell/dict-golang@npm:6.0.12" + checksum: 10/9c8e8f60225548329b9d9ac295dd856bd73996897296dac395fc94fe12945988cf5e28fb26279b655907748d925a15fce6fc04968f5fffcc970a8f6d94d81131 languageName: node linkType: hard @@ -719,10 +1956,10 @@ __metadata: languageName: node linkType: hard -"@cspell/dict-k8s@npm:^1.0.5": - version: 1.0.5 - resolution: "@cspell/dict-k8s@npm:1.0.5" - checksum: 10/d7a251e44412ff7d337dabe20deedd5bb9553e2825f81a7c01788aa80dbae99a24c57cc6f686d9a249bcfbd0436248d1814b8c786425a3b20a7e189b1019775f +"@cspell/dict-k8s@npm:^1.0.6": + version: 1.0.6 + resolution: "@cspell/dict-k8s@npm:1.0.6" + checksum: 10/e2b3ea0b7b4fc2faa5a4bb9b93aa08eaca4289e71c6284b5f9f51a0ffaa88c44d4b2f425c3f24d369a37bbf54865d4cfe6d97cda7046230bd135ec5000641cf0 languageName: node linkType: hard @@ -768,40 +2005,40 @@ __metadata: languageName: node linkType: hard -"@cspell/dict-npm@npm:^5.0.16": - version: 5.0.16 - resolution: "@cspell/dict-npm@npm:5.0.16" - checksum: 10/ec77d0e297e6a50b1889a15332771c6605997bb1c4a8d9f0528ded69ea993fae449f303f4bca04c4cd56c24ad4151feb67b64cfade58aa21c81d80e1b0474b32 +"@cspell/dict-npm@npm:^5.1.4": + version: 5.1.5 + resolution: "@cspell/dict-npm@npm:5.1.5" + checksum: 10/efe139254827ba9dad56d1e754651670b7175c52068c3b87f9bce89432e05136dc32f0f73940f2b1f9576c9ee4fe812f1e2e34415e17bcdd865fedf1fc716448 languageName: node linkType: hard -"@cspell/dict-php@npm:^4.0.8": - version: 4.0.8 - resolution: "@cspell/dict-php@npm:4.0.8" - checksum: 10/245c46db2d387044b9d9cfa6de4eb46b5a8cbbb33a0875c171c75230db599af5d8592165a618c849e99610f2c173564a6867c5475a2dbc5bbdea437bcb2b569b +"@cspell/dict-php@npm:^4.0.10": + version: 4.0.10 + resolution: "@cspell/dict-php@npm:4.0.10" + checksum: 10/a85b705fcbeb4c768411f518877af3f64ba6c3b254d84970b9d847e9ca5d2813f2cd063d0ca7801947b49736d546bd496efd97e91cf269ac5ed3ae94fd50183d languageName: node linkType: hard -"@cspell/dict-powershell@npm:^5.0.4": - version: 5.0.4 - resolution: "@cspell/dict-powershell@npm:5.0.4" - checksum: 10/13aa687130db6330a86f7b9cd1f7be9046ac3102aa96be9c71e130639fc3eff9b0a1ad45914bcaa497af2d628e2d3bc8babf02d6b657fd18d88fddc412ec4fec +"@cspell/dict-powershell@npm:^5.0.8": + version: 5.0.8 + resolution: "@cspell/dict-powershell@npm:5.0.8" + checksum: 10/86759ce57f1fe38cfd4059568712da69b85aba8a7b7c801a494841a815e84a3b2917d394ea0bbfe3772613d380de30cc54ba4fda16e249f396cadb1e7a9da603 languageName: node linkType: hard -"@cspell/dict-public-licenses@npm:^2.0.7": - version: 2.0.7 - resolution: "@cspell/dict-public-licenses@npm:2.0.7" - checksum: 10/7bbd067668499c45bad9eb8e3dae598bc5635e6035160bff7343b87cd31e419387e704fa290d0e23903fff6c80b65838ebe5638e2951dc5d9214df9b98b60ce2 +"@cspell/dict-public-licenses@npm:^2.0.8": + version: 2.0.8 + resolution: "@cspell/dict-public-licenses@npm:2.0.8" + checksum: 10/8db6c8b44808df4ea34d5082fd11df383a939e3dbf260f5a7551dea62e64de08f24ae16177cb6fd22ff2621cb2575c7db3839d5d4919e1013678927820c2d35c languageName: node linkType: hard -"@cspell/dict-python@npm:^4.2.1": - version: 4.2.1 - resolution: "@cspell/dict-python@npm:4.2.1" +"@cspell/dict-python@npm:^4.2.6": + version: 4.2.6 + resolution: "@cspell/dict-python@npm:4.2.6" dependencies: "@cspell/dict-data-science": "npm:^2.0.1" - checksum: 10/f0941bcfd518a3c63c68d8ed08304b98142e90e3b445b12ab4b13ce23508b573e323f4a5136bde2cd610f99814963e119b8b06c0d91fc5808e1a7c29a804cce4 + checksum: 10/c51751e2d34dea708ca9f6ee89e1d37a1d312b79a2581e2670aa83b59ab28c5d0074c7aa6778875177203089a1795b845d36d1db389fa643b37d9fb17aa26012 languageName: node linkType: hard @@ -812,38 +2049,38 @@ __metadata: languageName: node linkType: hard -"@cspell/dict-ruby@npm:^5.0.2": - version: 5.0.2 - resolution: "@cspell/dict-ruby@npm:5.0.2" - checksum: 10/c2006bcc808448b1eef146eb4b6b74388113c50334206191a9fe5817fb13669482ecd114f7bbd397562ad2e19a9683266ff396f48c6ce282f6445c2cfa8e82c7 +"@cspell/dict-ruby@npm:^5.0.3": + version: 5.0.3 + resolution: "@cspell/dict-ruby@npm:5.0.3" + checksum: 10/1ac49e7b7478efe65898bc6e44ca08acb61964b4ea38367bcad301b20addd9920ec37fff106b101ba36d4fc4dc5464d2d4042717e59278ca74066921297f0c97 languageName: node linkType: hard -"@cspell/dict-rust@npm:^4.0.4": - version: 4.0.4 - resolution: "@cspell/dict-rust@npm:4.0.4" - checksum: 10/7ff86c4f172bf039ff1264f4736d9638d0792ab39ff5fc48812831241d622040f6591a3d9f630325537b0a4913e242bea14005ec3d2e3c167f933fe1416e0caa +"@cspell/dict-rust@npm:^4.0.5": + version: 4.0.5 + resolution: "@cspell/dict-rust@npm:4.0.5" + checksum: 10/358ff7b35522616bcc95408d399f8982f0898c66c449621b7a0cae39605d5ba48ca785eecaaa43ee5b90567f5c481475ec97667f92995bb5a745a8d3296fb556 languageName: node linkType: hard -"@cspell/dict-scala@npm:^5.0.2": - version: 5.0.2 - resolution: "@cspell/dict-scala@npm:5.0.2" - checksum: 10/c07bda723929f8b01ae0575af3d05ffffee9ed7523e0658a22d533cf287dd564d11bf16062a1692fb06c3aff2d519d07c7c2c3e5662ced8af1194b31b352af51 +"@cspell/dict-scala@npm:^5.0.3": + version: 5.0.3 + resolution: "@cspell/dict-scala@npm:5.0.3" + checksum: 10/9fda5d33cb2b96f33cc050077ba1c8a6af33c12c9af3a14ebfd63a4cffd5b9fec0e0b574b6b833889ac26019c34b65674494b54bf540006b2a293d9367ea67c6 languageName: node linkType: hard -"@cspell/dict-software-terms@npm:^3.4.6": - version: 3.4.8 - resolution: "@cspell/dict-software-terms@npm:3.4.8" - checksum: 10/9bc7e6df4a80830659eb6ab780674a5244e537841af9c16a7e63e627f038d048fd9327fe97beb1717c8314a282f0f86ef6d4ffddec4f03e69f25b8f5daa20ed8 +"@cspell/dict-software-terms@npm:^4.1.3": + version: 4.1.4 + resolution: "@cspell/dict-software-terms@npm:4.1.4" + checksum: 10/7da3aaa90e9e057aba7ae0e047bf51efbcdf45a3827244460f38ebb74877abfb800f126e824e5f4abbeb8dded30030a8c2649daa7f0870f189c8a70ce23e4a64 languageName: node linkType: hard -"@cspell/dict-sql@npm:^2.1.3": - version: 2.1.3 - resolution: "@cspell/dict-sql@npm:2.1.3" - checksum: 10/a435812cc697d4c453f11efa49962992150702518e49808381ea34548b8a8ed81432a10cca36682007912b013c28e9ce3c6c183341c6cde58c8af0eef25cddc3 +"@cspell/dict-sql@npm:^2.1.5": + version: 2.1.5 + resolution: "@cspell/dict-sql@npm:2.1.5" + checksum: 10/97928e1c42d9ec793401b37e97ab60955cfb7b623f9f2ad1578459e3c53bd5ae503dadc80f3192355de72bb15a89cb993be88d1ffc26a7f3b8c38a07e8b772a5 languageName: node linkType: hard @@ -861,17 +2098,17 @@ __metadata: languageName: node linkType: hard -"@cspell/dict-terraform@npm:^1.0.0": - version: 1.0.0 - resolution: "@cspell/dict-terraform@npm:1.0.0" - checksum: 10/132b8f0532aa5a6a08fa57487313722bc10ad37a4b94a5d76b072922eb4eb56d204a3e33c1569613af5b337bd125b8e2d30cae6bf5400a07fa58c551c7fe3b37 +"@cspell/dict-terraform@npm:^1.0.1": + version: 1.0.1 + resolution: "@cspell/dict-terraform@npm:1.0.1" + checksum: 10/d2af4b13608012592450200eb8660bbe9a09fbb4579b6d6542ee29c03b00347135f46d6c51b65eca13e4030ff6ab1570129b13325aef869174c14481631a2e86 languageName: node linkType: hard -"@cspell/dict-typescript@npm:^3.1.5": - version: 3.1.5 - resolution: "@cspell/dict-typescript@npm:3.1.5" - checksum: 10/9e99aa7c849133fcab6d16864045b512be3f0b89c76caf31234fcc6edf818e06e2af4087f576e5837e209dc0bdc1d1379d6752bac48aab517e0661c0e4eeff58 +"@cspell/dict-typescript@npm:^3.1.6": + version: 3.1.6 + resolution: "@cspell/dict-typescript@npm:3.1.6" + checksum: 10/534f0fb9b261f5bd48597235ae16c7e8ac4e80f7c8d9504dbaa9843f8a0d044cdfbd0d855b92011d508b8fe965e6cf3a0d668426e6e57517c4a55e85316629e5 languageName: node linkType: hard @@ -882,39 +2119,47 @@ __metadata: languageName: node linkType: hard -"@cspell/dynamic-import@npm:8.9.1": - version: 8.9.1 - resolution: "@cspell/dynamic-import@npm:8.9.1" +"@cspell/dynamic-import@npm:8.14.4": + version: 8.14.4 + resolution: "@cspell/dynamic-import@npm:8.14.4" dependencies: import-meta-resolve: "npm:^4.1.0" - checksum: 10/c9b477a3db78712e2d80abc3347638d976a0a33ae6fd7a4e10fda8d479f6c19e4f6fc36e4a8e6bd2df0c607a985bcb0a7b016f6f77c71aa8b7bf24b386525fcc + checksum: 10/9e098175e544266bdda70746d7d586204bfc103872b8065be863992711f18485483b2bd313568dcb46aa2965aa4df3ba0d20e92ca9cb0953ca91f094061c243c languageName: node linkType: hard -"@cspell/eslint-plugin@npm:^8.9.1": - version: 8.9.1 - resolution: "@cspell/eslint-plugin@npm:8.9.1" +"@cspell/eslint-plugin@npm:^8.14.4": + version: 8.14.4 + resolution: "@cspell/eslint-plugin@npm:8.14.4" dependencies: - "@cspell/cspell-types": "npm:8.9.1" - cspell-lib: "npm:8.9.1" - synckit: "npm:^0.9.0" + "@cspell/cspell-types": "npm:8.14.4" + "@cspell/url": "npm:8.14.4" + cspell-lib: "npm:8.14.4" + synckit: "npm:^0.9.1" peerDependencies: eslint: ^7 || ^8 || ^9 - checksum: 10/f1931d970099d3449cfeea4131ddaa5852274f28773eab95f2475f1ed43b15149784c4041883f36ae866e46e7b4622005d4a299c4f3f2e3b4d8652d5c5dac4e6 + checksum: 10/93fb63c1abbb9ddfdd8aef99fce644d570d7e5e02c72ecbd955cdf14790a7afd382f51dba29f020a3261021e2fddc232319a6dd8f6b2115747b0acedbf880c5d languageName: node linkType: hard -"@cspell/strong-weak-map@npm:8.9.1": - version: 8.9.1 - resolution: "@cspell/strong-weak-map@npm:8.9.1" - checksum: 10/7f01c98591255ad1a88e339e48e8eda181817b11de6f5c122297f4874e0e946eed4b4794f4b83b98f07dedfa2fd1fbfe788a4a132abdbe0c6ef2c3c9ee110e01 +"@cspell/filetypes@npm:8.14.4": + version: 8.14.4 + resolution: "@cspell/filetypes@npm:8.14.4" + checksum: 10/b5e5109b12c67d1f0490ffafd061af4a801b0e021ec8d60e6242fe6fcafcf878d13f71dd93c4a746d37cc9180ef275581c075c8a61f4719868378f8469210c02 languageName: node linkType: hard -"@cspell/url@npm:8.9.1": - version: 8.9.1 - resolution: "@cspell/url@npm:8.9.1" - checksum: 10/be773b08f79e2fbe6b4e389a74e689937e15e6bdc1b1ee86e79c809b9ac4f2cefa93f7d7c4068a3876f3928c04a3a098d17e1d33f818114474056c60b51c4c5a +"@cspell/strong-weak-map@npm:8.14.4": + version: 8.14.4 + resolution: "@cspell/strong-weak-map@npm:8.14.4" + checksum: 10/4ad885ad8aa6217a44fa0ce01ce9781a5d69bf3806c7d6de94671f6237a68f13c66ed06f075c91f103ed9cf1d34d4923384a3fa4b429afd754f647c04dca84ad + languageName: node + linkType: hard + +"@cspell/url@npm:8.14.4": + version: 8.14.4 + resolution: "@cspell/url@npm:8.14.4" + checksum: 10/cbc9dc82a46ba9b27bf3d56caf7b68aa3445e32f748e2c88f65e53cf3cdd2b456c0ddc5c11b65ec67d04e3c1839fa44a45d1e908fda36de893de1125a6b761e9 languageName: node linkType: hard @@ -922,212 +2167,228 @@ __metadata: version: 0.0.0-use.local resolution: "@digital-alchemy/core@workspace:." dependencies: - "@cspell/eslint-plugin": "npm:^8.9.1" - "@faker-js/faker": "npm:^8.4.1" + "@cspell/eslint-plugin": "npm:^8.14.4" + "@eslint/compat": "npm:^1.1.1" + "@eslint/eslintrc": "npm:^3.1.0" + "@eslint/js": "npm:^9.10.0" + "@faker-js/faker": "npm:^9.0.1" + "@jest/globals": "npm:^29.7.0" "@types/dotenv": "npm:^8.2.0" "@types/ini": "npm:^4.1.1" - "@types/jest": "npm:^29.5.12" + "@types/jest": "npm:^29.5.13" "@types/js-yaml": "npm:^4.0.9" "@types/minimist": "npm:^1.2.5" - "@types/node": "npm:^20.14.8" + "@types/node": "npm:^22.5.5" "@types/node-cron": "npm:^3.0.11" "@types/semver": "npm:^7.5.8" "@types/sinonjs__fake-timers": "npm:^8.1.5" - "@typescript-eslint/eslint-plugin": "npm:7.3.1" - "@typescript-eslint/parser": "npm:7.3.1" + "@types/uuid": "npm:^10.0.0" + "@typescript-eslint/eslint-plugin": "npm:8.6.0" + "@typescript-eslint/parser": "npm:8.6.0" chalk: "npm:^5.3.0" - dayjs: "npm:^1.11.11" + dayjs: "npm:^1.11.13" dotenv: "npm:^16.4.5" - eslint: "npm:8.57.0" + eslint: "npm:9.10.0" eslint-config-prettier: "npm:9.1.0" - eslint-plugin-import: "npm:^2.29.1" - eslint-plugin-jsonc: "npm:^2.14.1" - eslint-plugin-no-unsanitized: "npm:^4.0.2" - eslint-plugin-prettier: "npm:^5.1.3" - eslint-plugin-security: "npm:^2.1.1" - eslint-plugin-simple-import-sort: "npm:^12.0.0" - eslint-plugin-sonarjs: "npm:^0.24.0" + eslint-plugin-import: "npm:^2.30.0" + eslint-plugin-jsonc: "npm:^2.16.0" + eslint-plugin-no-unsanitized: "npm:^4.1.0" + eslint-plugin-prettier: "npm:^5.2.1" + eslint-plugin-security: "npm:^3.0.1" + eslint-plugin-simple-import-sort: "npm:^12.1.1" + eslint-plugin-sonarjs: "npm:^2.0.2" eslint-plugin-sort-keys-fix: "npm:^1.1.2" - eslint-plugin-unicorn: "npm:^51.0.1" - ini: "npm:^4.1.3" + eslint-plugin-unicorn: "npm:^55.0.0" + globals: "npm:^15.9.0" + ini: "npm:^5.0.0" jest: "npm:^29.7.0" jest-environment-node: "npm:^29.7.0" js-yaml: "npm:^4.1.0" minimist: "npm:^1.2.8" - node-cache: "npm:^5.1.2" node-cron: "npm:^3.0.3" - npm-check-updates: "npm:^16.14.20" - prettier: "npm:^3.3.2" - prom-client: "npm:^15.1.2" - redis: "npm:^4.6.14" - ts-jest: "npm:^29.1.5" - tslib: "npm:^2.6.3" - tsx: "npm:^4.15.7" - type-fest: "npm:^4.20.1" - typescript: "npm:^5.5.2" - dependenciesMeta: - redis: - optional: true + prettier: "npm:^3.3.3" + ts-jest: "npm:^29.2.5" + tslib: "npm:^2.7.0" + tsx: "npm:^4.19.1" + type-fest: "npm:^4.26.1" + typescript: "npm:^5.6.2" + uuid: "npm:^10.0.0" + peerDependencies: + chalk: ^5 + dayjs: ^1 + dotenv: ^16 + ini: ^4 + js-yaml: ^4 + minimist: ^1 + node-cron: ^3 + uuid: "*" languageName: unknown linkType: soft -"@esbuild/aix-ppc64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/aix-ppc64@npm:0.21.5" +"@esbuild/aix-ppc64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/aix-ppc64@npm:0.23.1" conditions: os=aix & cpu=ppc64 languageName: node linkType: hard -"@esbuild/android-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-arm64@npm:0.21.5" +"@esbuild/android-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-arm64@npm:0.23.1" conditions: os=android & cpu=arm64 languageName: node linkType: hard -"@esbuild/android-arm@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-arm@npm:0.21.5" +"@esbuild/android-arm@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-arm@npm:0.23.1" conditions: os=android & cpu=arm languageName: node linkType: hard -"@esbuild/android-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/android-x64@npm:0.21.5" +"@esbuild/android-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/android-x64@npm:0.23.1" conditions: os=android & cpu=x64 languageName: node linkType: hard -"@esbuild/darwin-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/darwin-arm64@npm:0.21.5" +"@esbuild/darwin-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/darwin-arm64@npm:0.23.1" conditions: os=darwin & cpu=arm64 languageName: node linkType: hard -"@esbuild/darwin-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/darwin-x64@npm:0.21.5" +"@esbuild/darwin-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/darwin-x64@npm:0.23.1" conditions: os=darwin & cpu=x64 languageName: node linkType: hard -"@esbuild/freebsd-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/freebsd-arm64@npm:0.21.5" +"@esbuild/freebsd-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/freebsd-arm64@npm:0.23.1" conditions: os=freebsd & cpu=arm64 languageName: node linkType: hard -"@esbuild/freebsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/freebsd-x64@npm:0.21.5" +"@esbuild/freebsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/freebsd-x64@npm:0.23.1" conditions: os=freebsd & cpu=x64 languageName: node linkType: hard -"@esbuild/linux-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-arm64@npm:0.21.5" +"@esbuild/linux-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-arm64@npm:0.23.1" conditions: os=linux & cpu=arm64 languageName: node linkType: hard -"@esbuild/linux-arm@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-arm@npm:0.21.5" +"@esbuild/linux-arm@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-arm@npm:0.23.1" conditions: os=linux & cpu=arm languageName: node linkType: hard -"@esbuild/linux-ia32@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-ia32@npm:0.21.5" +"@esbuild/linux-ia32@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-ia32@npm:0.23.1" conditions: os=linux & cpu=ia32 languageName: node linkType: hard -"@esbuild/linux-loong64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-loong64@npm:0.21.5" +"@esbuild/linux-loong64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-loong64@npm:0.23.1" conditions: os=linux & cpu=loong64 languageName: node linkType: hard -"@esbuild/linux-mips64el@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-mips64el@npm:0.21.5" +"@esbuild/linux-mips64el@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-mips64el@npm:0.23.1" conditions: os=linux & cpu=mips64el languageName: node linkType: hard -"@esbuild/linux-ppc64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-ppc64@npm:0.21.5" +"@esbuild/linux-ppc64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-ppc64@npm:0.23.1" conditions: os=linux & cpu=ppc64 languageName: node linkType: hard -"@esbuild/linux-riscv64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-riscv64@npm:0.21.5" +"@esbuild/linux-riscv64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-riscv64@npm:0.23.1" conditions: os=linux & cpu=riscv64 languageName: node linkType: hard -"@esbuild/linux-s390x@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-s390x@npm:0.21.5" +"@esbuild/linux-s390x@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-s390x@npm:0.23.1" conditions: os=linux & cpu=s390x languageName: node linkType: hard -"@esbuild/linux-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/linux-x64@npm:0.21.5" +"@esbuild/linux-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/linux-x64@npm:0.23.1" conditions: os=linux & cpu=x64 languageName: node linkType: hard -"@esbuild/netbsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/netbsd-x64@npm:0.21.5" +"@esbuild/netbsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/netbsd-x64@npm:0.23.1" conditions: os=netbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/openbsd-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/openbsd-x64@npm:0.21.5" +"@esbuild/openbsd-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/openbsd-arm64@npm:0.23.1" + conditions: os=openbsd & cpu=arm64 + languageName: node + linkType: hard + +"@esbuild/openbsd-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/openbsd-x64@npm:0.23.1" conditions: os=openbsd & cpu=x64 languageName: node linkType: hard -"@esbuild/sunos-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/sunos-x64@npm:0.21.5" +"@esbuild/sunos-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/sunos-x64@npm:0.23.1" conditions: os=sunos & cpu=x64 languageName: node linkType: hard -"@esbuild/win32-arm64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-arm64@npm:0.21.5" +"@esbuild/win32-arm64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-arm64@npm:0.23.1" conditions: os=win32 & cpu=arm64 languageName: node linkType: hard -"@esbuild/win32-ia32@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-ia32@npm:0.21.5" +"@esbuild/win32-ia32@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-ia32@npm:0.23.1" conditions: os=win32 & cpu=ia32 languageName: node linkType: hard -"@esbuild/win32-x64@npm:0.21.5": - version: 0.21.5 - resolution: "@esbuild/win32-x64@npm:0.21.5" +"@esbuild/win32-x64@npm:0.23.1": + version: 0.23.1 + resolution: "@esbuild/win32-x64@npm:0.23.1" conditions: os=win32 & cpu=x64 languageName: node linkType: hard @@ -1143,59 +2404,82 @@ __metadata: languageName: node linkType: hard -"@eslint-community/regexpp@npm:^4.5.1, @eslint-community/regexpp@npm:^4.6.1": - version: 4.10.1 - resolution: "@eslint-community/regexpp@npm:4.10.1" - checksum: 10/54f13817caf90545502d7a19e1b61df79087aee9584342ffc558b6d067530764a47f1c484f493f43e2c70cfdff59ccfd5f26df2af298c4ad528469e599bd1d53 +"@eslint-community/regexpp@npm:4.10.0": + version: 4.10.0 + resolution: "@eslint-community/regexpp@npm:4.10.0" + checksum: 10/8c36169c815fc5d726078e8c71a5b592957ee60d08c6470f9ce0187c8046af1a00afbda0a065cc40ff18d5d83f82aed9793c6818f7304a74a7488dc9f3ecbd42 languageName: node linkType: hard -"@eslint/eslintrc@npm:^2.1.4": - version: 2.1.4 - resolution: "@eslint/eslintrc@npm:2.1.4" +"@eslint-community/regexpp@npm:^4.10.0, @eslint-community/regexpp@npm:^4.11.0, @eslint-community/regexpp@npm:^4.8.0": + version: 4.11.0 + resolution: "@eslint-community/regexpp@npm:4.11.0" + checksum: 10/f053f371c281ba173fe6ee16dbc4fe544c84870d58035ccca08dba7f6ce1830d895ce3237a0db89ba37616524775dca82f1c502066b58e2d5712d7f87f5ba17c + languageName: node + linkType: hard + +"@eslint/compat@npm:^1.1.1": + version: 1.1.1 + resolution: "@eslint/compat@npm:1.1.1" + checksum: 10/9004697701e9e9a7749d9e37452ee965af3620af46796ac0ee196478bbda490c780d17686c2888353c2a12d764837fa71c027c3ca18b1c3af6136105caa93642 + languageName: node + linkType: hard + +"@eslint/config-array@npm:^0.18.0": + version: 0.18.0 + resolution: "@eslint/config-array@npm:0.18.0" + dependencies: + "@eslint/object-schema": "npm:^2.1.4" + debug: "npm:^4.3.1" + minimatch: "npm:^3.1.2" + checksum: 10/60ccad1eb4806710b085cd739568ec7afd289ee5af6ca0383f0876f9fe375559ef525f7b3f86bdb3f961493de952f2cf3ab4aa4a6ccaef0ae3cd688267cabcb3 + languageName: node + linkType: hard + +"@eslint/eslintrc@npm:^3.1.0": + version: 3.1.0 + resolution: "@eslint/eslintrc@npm:3.1.0" dependencies: ajv: "npm:^6.12.4" debug: "npm:^4.3.2" - espree: "npm:^9.6.0" - globals: "npm:^13.19.0" + espree: "npm:^10.0.1" + globals: "npm:^14.0.0" ignore: "npm:^5.2.0" import-fresh: "npm:^3.2.1" js-yaml: "npm:^4.1.0" minimatch: "npm:^3.1.2" strip-json-comments: "npm:^3.1.1" - checksum: 10/7a3b14f4b40fc1a22624c3f84d9f467a3d9ea1ca6e9a372116cb92507e485260359465b58e25bcb6c9981b155416b98c9973ad9b796053fd7b3f776a6946bce8 + checksum: 10/02bf892d1397e1029209dea685e9f4f87baf643315df2a632b5f121ec7e8548a3b34f428a007234fa82772218fa8a3ac2d10328637b9ce63b7f8344035b74db3 languageName: node linkType: hard -"@eslint/js@npm:8.57.0": - version: 8.57.0 - resolution: "@eslint/js@npm:8.57.0" - checksum: 10/3c501ce8a997cf6cbbaf4ed358af5492875e3550c19b9621413b82caa9ae5382c584b0efa79835639e6e0ddaa568caf3499318e5bdab68643ef4199dce5eb0a0 +"@eslint/js@npm:9.10.0, @eslint/js@npm:^9.10.0": + version: 9.10.0 + resolution: "@eslint/js@npm:9.10.0" + checksum: 10/cbda2bf268c8ac7a2b2493aaaa0113a78165a576ee5178b9fbdaf245c3d40ffaf41d006f75afab5718f68d816f00319e267b4c88ead100b19022fe491f9e0175 languageName: node linkType: hard -"@faker-js/faker@npm:^8.4.1": - version: 8.4.1 - resolution: "@faker-js/faker@npm:8.4.1" - checksum: 10/5983c2ea64f26055ad6648de748878e11ebe2fb751e3c7435ae141cdffabc2dccfe4c4f49da69a3d2add71e21b415c683ac5fba196fab0d5ed6779fbec436c80 +"@eslint/object-schema@npm:^2.1.4": + version: 2.1.4 + resolution: "@eslint/object-schema@npm:2.1.4" + checksum: 10/221e8d9f281c605948cd6e030874aacce83fe097f8f9c1964787037bccf08e82b7aa9eff1850a30fffac43f1d76555727ec22a2af479d91e268e89d1e035131e languageName: node linkType: hard -"@gar/promisify@npm:^1.1.3": - version: 1.1.3 - resolution: "@gar/promisify@npm:1.1.3" - checksum: 10/052dd232140fa60e81588000cbe729a40146579b361f1070bce63e2a761388a22a16d00beeffc504bd3601cb8e055c57b21a185448b3ed550cf50716f4fd442e +"@eslint/plugin-kit@npm:^0.1.0": + version: 0.1.0 + resolution: "@eslint/plugin-kit@npm:0.1.0" + dependencies: + levn: "npm:^0.4.1" + checksum: 10/3c6b10505f53c6e32b40572f780164b75389bbabd1bf80ab8742222710d90683a2cc9480468fca132da636f6a3053ae60b173181d14f4975fde2e6f8f9564c6d languageName: node linkType: hard -"@humanwhocodes/config-array@npm:^0.11.14": - version: 0.11.14 - resolution: "@humanwhocodes/config-array@npm:0.11.14" - dependencies: - "@humanwhocodes/object-schema": "npm:^2.0.2" - debug: "npm:^4.3.1" - minimatch: "npm:^3.0.5" - checksum: 10/3ffb24ecdfab64014a230e127118d50a1a04d11080cbb748bc21629393d100850496456bbcb4e8c438957fe0934430d731042f1264d6a167b62d32fc2863580a +"@faker-js/faker@npm:^9.0.1": + version: 9.0.1 + resolution: "@faker-js/faker@npm:9.0.1" + checksum: 10/708629605392fdbe06887ca9b083d73801c64b47917f790870b240858ab65cada14b52dddf2cb7e471ad0f6ddf66ea30e7ffda741c5ba9bd5c27318b47262279 languageName: node linkType: hard @@ -1206,10 +2490,10 @@ __metadata: languageName: node linkType: hard -"@humanwhocodes/object-schema@npm:^2.0.2": - version: 2.0.3 - resolution: "@humanwhocodes/object-schema@npm:2.0.3" - checksum: 10/05bb99ed06c16408a45a833f03a732f59bf6184795d4efadd33238ff8699190a8c871ad1121241bb6501589a9598dc83bf25b99dcbcf41e155cdf36e35e937a3 +"@humanwhocodes/retry@npm:^0.3.0": + version: 0.3.0 + resolution: "@humanwhocodes/retry@npm:0.3.0" + checksum: 10/e574bab58680867414e225c9002e9a97eb396f85871c180fbb1a9bcdf9ded4b4de0b327f7d0c43b775873362b7c92956d4b322e8bc4b90be56077524341f04b2 languageName: node linkType: hard @@ -1519,6 +2803,15 @@ __metadata: languageName: node linkType: hard +"@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1": + version: 5.1.1-v1 + resolution: "@nicolo-ribaudo/eslint-scope-5-internals@npm:5.1.1-v1" + dependencies: + eslint-scope: "npm:5.1.1" + checksum: 10/f2e3b2d6a6e2d9f163ca22105910c9f850dc4897af0aea3ef0a5886b63d8e1ba6505b71c99cb78a3bba24a09557d601eb21c8dede3f3213753fcfef364eb0e57 + languageName: node + linkType: hard + "@nodelib/fs.scandir@npm:2.1.5": version: 2.1.5 resolution: "@nodelib/fs.scandir@npm:2.1.5" @@ -1559,16 +2852,6 @@ __metadata: languageName: node linkType: hard -"@npmcli/fs@npm:^2.1.0": - version: 2.1.2 - resolution: "@npmcli/fs@npm:2.1.2" - dependencies: - "@gar/promisify": "npm:^1.1.3" - semver: "npm:^7.3.5" - checksum: 10/c5d4dfee80de2236e1e4ed595d17e217aada72ebd8215183fc46096fa010f583dd2aaaa486758de7cc0b89440dbc31cfe8b276269d75d47af35c716e896f78ec - languageName: node - linkType: hard - "@npmcli/fs@npm:^3.1.0": version: 3.1.1 resolution: "@npmcli/fs@npm:3.1.1" @@ -1578,80 +2861,6 @@ __metadata: languageName: node linkType: hard -"@npmcli/git@npm:^4.0.0": - version: 4.1.0 - resolution: "@npmcli/git@npm:4.1.0" - dependencies: - "@npmcli/promise-spawn": "npm:^6.0.0" - lru-cache: "npm:^7.4.4" - npm-pick-manifest: "npm:^8.0.0" - proc-log: "npm:^3.0.0" - promise-inflight: "npm:^1.0.1" - promise-retry: "npm:^2.0.1" - semver: "npm:^7.3.5" - which: "npm:^3.0.0" - checksum: 10/33512ce12758d67c0322eca25019c4d5ef03e83f5829e09a05389af485bab216cc4df408b8eba98f2d12c119c6dff84f0d8ff25a1ac5d8a46184e55ae8f53754 - languageName: node - linkType: hard - -"@npmcli/installed-package-contents@npm:^2.0.1": - version: 2.1.0 - resolution: "@npmcli/installed-package-contents@npm:2.1.0" - dependencies: - npm-bundled: "npm:^3.0.0" - npm-normalize-package-bin: "npm:^3.0.0" - bin: - installed-package-contents: bin/index.js - checksum: 10/68ab3ea2994f5ea21c61940de94ec4f2755fe569ef0b86e22db0695d651a3c88915c5eab61d634cfa203b9c801ee307c8aa134c2c4bd2e4fe1aa8d295ce8a163 - languageName: node - linkType: hard - -"@npmcli/move-file@npm:^2.0.0": - version: 2.0.1 - resolution: "@npmcli/move-file@npm:2.0.1" - dependencies: - mkdirp: "npm:^1.0.4" - rimraf: "npm:^3.0.2" - checksum: 10/52dc02259d98da517fae4cb3a0a3850227bdae4939dda1980b788a7670636ca2b4a01b58df03dd5f65c1e3cb70c50fa8ce5762b582b3f499ec30ee5ce1fd9380 - languageName: node - linkType: hard - -"@npmcli/node-gyp@npm:^3.0.0": - version: 3.0.0 - resolution: "@npmcli/node-gyp@npm:3.0.0" - checksum: 10/dd9fed3e80df8fbb20443f28651a8ed7235f2c15286ecc010e2d3cd392c85912e59ef29218c0b02f098defb4cbc8cdf045aab1d32d5cef6ace289913196ed5df - languageName: node - linkType: hard - -"@npmcli/promise-spawn@npm:^6.0.0, @npmcli/promise-spawn@npm:^6.0.1": - version: 6.0.2 - resolution: "@npmcli/promise-spawn@npm:6.0.2" - dependencies: - which: "npm:^3.0.0" - checksum: 10/cc94a83ff1626ad93d42c2ea583dba1fb2d24cdab49caf0af77a3a0ff9bdbba34e09048b6821d4060ea7a58d4a41d49bece4ae3716929e2077c2fff0f5e94d94 - languageName: node - linkType: hard - -"@npmcli/run-script@npm:^6.0.0": - version: 6.0.2 - resolution: "@npmcli/run-script@npm:6.0.2" - dependencies: - "@npmcli/node-gyp": "npm:^3.0.0" - "@npmcli/promise-spawn": "npm:^6.0.0" - node-gyp: "npm:^9.0.0" - read-package-json-fast: "npm:^3.0.0" - which: "npm:^3.0.0" - checksum: 10/9b22c4c53d4b2e014e7f990cf2e1d32d1830c5629d37a4ee56011bcdfb51424ca8dc3fb3fa550b4abe7e8f0efdd68468d733b754db371b06a5dd300663cf13a2 - languageName: node - linkType: hard - -"@opentelemetry/api@npm:^1.4.0": - version: 1.9.0 - resolution: "@opentelemetry/api@npm:1.9.0" - checksum: 10/a607f0eef971893c4f2ee2a4c2069aade6ec3e84e2a1f5c2aac19f65c5d9eeea41aa72db917c1029faafdd71789a1a040bdc18f40d63690e22ccae5d7070f194 - languageName: node - linkType: hard - "@pkgjs/parseargs@npm:^0.11.0": version: 0.11.0 resolution: "@pkgjs/parseargs@npm:0.11.0" @@ -1666,123 +2875,10 @@ __metadata: languageName: node linkType: hard -"@pnpm/config.env-replace@npm:^1.1.0": - version: 1.1.0 - resolution: "@pnpm/config.env-replace@npm:1.1.0" - checksum: 10/fabe35cede1b72ad12877b8bed32f7c2fcd89e94408792c4d69009b886671db7988a2132bc18b7157489d2d0fd4266a06c9583be3d2e10c847bf06687420cb2a - languageName: node - linkType: hard - -"@pnpm/network.ca-file@npm:^1.0.1": - version: 1.0.2 - resolution: "@pnpm/network.ca-file@npm:1.0.2" - dependencies: - graceful-fs: "npm:4.2.10" - checksum: 10/d8d0884646500576bd5390464d13db1bb9a62e32a1069293e5bddb2ad8354b354b7e2d2a35e12850025651e795e6a80ce9e601c66312504667b7e3ee7b52becc - languageName: node - linkType: hard - -"@pnpm/npm-conf@npm:^2.1.0": - version: 2.2.2 - resolution: "@pnpm/npm-conf@npm:2.2.2" - dependencies: - "@pnpm/config.env-replace": "npm:^1.1.0" - "@pnpm/network.ca-file": "npm:^1.0.1" - config-chain: "npm:^1.1.11" - checksum: 10/45422fecc7ed49e5254eef744576625e27cdebccce930f42c66cf2fb70443fc24f506c3fcf4859e6371677ceb144feb45e925ec14774b54588b89806b32dea9a - languageName: node - linkType: hard - -"@redis/bloom@npm:1.2.0": - version: 1.2.0 - resolution: "@redis/bloom@npm:1.2.0" - peerDependencies: - "@redis/client": ^1.0.0 - checksum: 10/a16408f729ddd032a52c9d998661dfa7beabc0e92760d30619c3166c7a53a98c037956d93d230b787005fd8a599a7456461ca7429c1916893c2d13d59a41e0e6 - languageName: node - linkType: hard - -"@redis/client@npm:1.5.16": - version: 1.5.16 - resolution: "@redis/client@npm:1.5.16" - dependencies: - cluster-key-slot: "npm:1.1.2" - generic-pool: "npm:3.9.0" - yallist: "npm:4.0.0" - checksum: 10/54bd45dcdb980e9682fc9aaad36607a34b6c05ebc733fc9a132db33ce77b3ff63c229d8d8b43ce2d7db115f31ff2fefcbcc7dceeaa1fc88c03e7c8012e456adf - languageName: node - linkType: hard - -"@redis/graph@npm:1.1.1": - version: 1.1.1 - resolution: "@redis/graph@npm:1.1.1" - peerDependencies: - "@redis/client": ^1.0.0 - checksum: 10/96b8ee9bec124947465848b56a014805f9639e09704e03c75a92072a319599ac9dcd4f9ace22970a7f72131a241166ad31db4dc6931b34808d22a5ca94649ba5 - languageName: node - linkType: hard - -"@redis/json@npm:1.0.6": - version: 1.0.6 - resolution: "@redis/json@npm:1.0.6" - peerDependencies: - "@redis/client": ^1.0.0 - checksum: 10/bedd8b6fd152ed480f993c6372288f210a9c0e60bb39c02861d5ce2cb5452119229435572cd94886cdbde5fbae014471fc179dff1dbc86f045782e0358af1b0f - languageName: node - linkType: hard - -"@redis/search@npm:1.1.6": - version: 1.1.6 - resolution: "@redis/search@npm:1.1.6" - peerDependencies: - "@redis/client": ^1.0.0 - checksum: 10/7a2543012fc2c88ff4c6a6c9c1b537b472d5af340c2717f968562ef2ead713b02dd22cfadc5d5e16c0d32279a4c04bee974e0f20de416a3561a1221b3dccc790 - languageName: node - linkType: hard - -"@redis/time-series@npm:1.0.5": - version: 1.0.5 - resolution: "@redis/time-series@npm:1.0.5" - peerDependencies: - "@redis/client": ^1.0.0 - checksum: 10/be735fe7497b157ef8291fed157342a9a5017884488fa519b271745cfb9500a498d6f8e4bee6d34b58892d65f8ef7a3f4c458d083fb19892b4d3633d0d6c7db6 - languageName: node - linkType: hard - -"@sigstore/bundle@npm:^1.1.0": +"@rtsao/scc@npm:^1.1.0": version: 1.1.0 - resolution: "@sigstore/bundle@npm:1.1.0" - dependencies: - "@sigstore/protobuf-specs": "npm:^0.2.0" - checksum: 10/79e6cc4cc1858bccbd852dee85d95c66c891b109ea415d5b7b00b6d73791c4f6064c40d09b5aa3f9ec6c19b3145c5cfeece02302f912c186ff0a769667bb9491 - languageName: node - linkType: hard - -"@sigstore/protobuf-specs@npm:^0.2.0": - version: 0.2.1 - resolution: "@sigstore/protobuf-specs@npm:0.2.1" - checksum: 10/cb0b9d9b3ef44a9f1729d85616c5d7c2ebccde303836a5a345ec33a500c7bd5205ffcc31332e0a90831cccc581dafbdf5b868f050c84270c8df6a4a6f2ce0bcb - languageName: node - linkType: hard - -"@sigstore/sign@npm:^1.0.0": - version: 1.0.0 - resolution: "@sigstore/sign@npm:1.0.0" - dependencies: - "@sigstore/bundle": "npm:^1.1.0" - "@sigstore/protobuf-specs": "npm:^0.2.0" - make-fetch-happen: "npm:^11.0.1" - checksum: 10/44f23fc5eef5b160c0c36c6b19863039bbf375834eeca1ce7f711c82eb5a022174a475f0c06594f17732473c6878f2512f37e65949b7d33af3b2e2773f1bd34f - languageName: node - linkType: hard - -"@sigstore/tuf@npm:^1.0.3": - version: 1.0.3 - resolution: "@sigstore/tuf@npm:1.0.3" - dependencies: - "@sigstore/protobuf-specs": "npm:^0.2.0" - tuf-js: "npm:^1.1.7" - checksum: 10/5aa1cdea05fabb78232f802821f7e8ee9db3352719b325f2f703f940aac75fc2e71d89cfbd3623ef6b0429e125a5c6145c1fc8ede8d3d5af3affcb71c6453c7b + resolution: "@rtsao/scc@npm:1.1.0" + checksum: 10/17d04adf404e04c1e61391ed97bca5117d4c2767a76ae3e879390d6dec7b317fcae68afbf9e98badee075d0b64fa60f287729c4942021b4d19cd01db77385c01 languageName: node linkType: hard @@ -1793,13 +2889,6 @@ __metadata: languageName: node linkType: hard -"@sindresorhus/is@npm:^5.2.0": - version: 5.6.0 - resolution: "@sindresorhus/is@npm:5.6.0" - checksum: 10/b077c325acec98e30f7d86df158aaba2e7af2acb9bb6a00fda4b91578539fbff4ecebe9b934e24fec0e6950de3089d89d79ec02d9062476b20ce185be0e01bd6 - languageName: node - linkType: hard - "@sinonjs/commons@npm:^3.0.0": version: 3.0.1 resolution: "@sinonjs/commons@npm:3.0.1" @@ -1818,39 +2907,6 @@ __metadata: languageName: node linkType: hard -"@szmarczak/http-timer@npm:^5.0.1": - version: 5.0.1 - resolution: "@szmarczak/http-timer@npm:5.0.1" - dependencies: - defer-to-connect: "npm:^2.0.1" - checksum: 10/fc9cb993e808806692e4a3337c90ece0ec00c89f4b67e3652a356b89730da98bc824273a6d67ca84d5f33cd85f317dcd5ce39d8cc0a2f060145a608a7cb8ce92 - languageName: node - linkType: hard - -"@tootallnate/once@npm:2": - version: 2.0.0 - resolution: "@tootallnate/once@npm:2.0.0" - checksum: 10/ad87447820dd3f24825d2d947ebc03072b20a42bfc96cbafec16bff8bbda6c1a81fcb0be56d5b21968560c5359a0af4038a68ba150c3e1694fe4c109a063bed8 - languageName: node - linkType: hard - -"@tufjs/canonical-json@npm:1.0.0": - version: 1.0.0 - resolution: "@tufjs/canonical-json@npm:1.0.0" - checksum: 10/9ff3bcd12988fb23643690da3e009f9130b7b10974f8e7af4bd8ad230a228119de8609aa76d75264fe80f152b50872dea6ea53def69534436a4c24b4fcf6a447 - languageName: node - linkType: hard - -"@tufjs/models@npm:1.0.4": - version: 1.0.4 - resolution: "@tufjs/models@npm:1.0.4" - dependencies: - "@tufjs/canonical-json": "npm:1.0.0" - minimatch: "npm:^9.0.0" - checksum: 10/2c63e9cfc04a4ce8888e9cc9668a7207e3047d64c50dccc3d2c30057d8bd6c4e89256b6094d2109549278da72c75e20cd8717bb5f4b544dc2323288a2a96607f - languageName: node - linkType: hard - "@types/babel__core@npm:^7.1.14": version: 7.20.5 resolution: "@types/babel__core@npm:7.20.5" @@ -1910,13 +2966,6 @@ __metadata: languageName: node linkType: hard -"@types/http-cache-semantics@npm:^4.0.2": - version: 4.0.4 - resolution: "@types/http-cache-semantics@npm:4.0.4" - checksum: 10/a59566cff646025a5de396d6b3f44a39ab6a74f2ed8150692e0f31cc52f3661a68b04afe3166ebe0d566bd3259cb18522f46e949576d5204781cd6452b7fe0c5 - languageName: node - linkType: hard - "@types/ini@npm:^4.1.1": version: 4.1.1 resolution: "@types/ini@npm:4.1.1" @@ -1949,13 +2998,13 @@ __metadata: languageName: node linkType: hard -"@types/jest@npm:^29.5.12": - version: 29.5.12 - resolution: "@types/jest@npm:29.5.12" +"@types/jest@npm:^29.5.13": + version: 29.5.13 + resolution: "@types/jest@npm:29.5.13" dependencies: expect: "npm:^29.0.0" pretty-format: "npm:^29.0.0" - checksum: 10/312e8dcf92cdd5a5847d6426f0940829bca6fe6b5a917248f3d7f7ef5d85c9ce78ef05e47d2bbabc40d41a930e0e36db2d443d2610a9e3db9062da2d5c904211 + checksum: 10/7d6e3e4ef4b1cab0f61270d55764709512fdfbcb1bd47c0ef44117d48490529c1f264dacf3440b9188363e99e290b80b79c529eadc3af2184116a90f6856b192 languageName: node linkType: hard @@ -1966,13 +3015,6 @@ __metadata: languageName: node linkType: hard -"@types/json-schema@npm:^7.0.12": - version: 7.0.15 - resolution: "@types/json-schema@npm:7.0.15" - checksum: 10/1a3c3e06236e4c4aab89499c428d585527ce50c24fe8259e8b3926d3df4cfbbbcf306cfc73ddfb66cbafc973116efd15967020b0f738f63e09e64c7d260519e7 - languageName: node - linkType: hard - "@types/json5@npm:^0.0.29": version: 0.0.29 resolution: "@types/json5@npm:0.0.29" @@ -1994,7 +3036,7 @@ __metadata: languageName: node linkType: hard -"@types/node@npm:*, @types/node@npm:^20.14.8": +"@types/node@npm:*": version: 20.14.8 resolution: "@types/node@npm:20.14.8" dependencies: @@ -2003,6 +3045,15 @@ __metadata: languageName: node linkType: hard +"@types/node@npm:^22.5.5": + version: 22.5.5 + resolution: "@types/node@npm:22.5.5" + dependencies: + undici-types: "npm:~6.19.2" + checksum: 10/172d02c8e6d921699edcf559c28b3805616bd6481af1b3cb0299f89ad9a6f33b71050434c06ce7b503166054a26275344187c443f99f745d0b12601372452f19 + languageName: node + linkType: hard + "@types/normalize-package-data@npm:^2.4.0": version: 2.4.4 resolution: "@types/normalize-package-data@npm:2.4.4" @@ -2010,14 +3061,7 @@ __metadata: languageName: node linkType: hard -"@types/semver-utils@npm:^1.1.1": - version: 1.1.3 - resolution: "@types/semver-utils@npm:1.1.3" - checksum: 10/37f3bacf1426569624c645bf9e6cf009735760b56dad08fcf701740ea2b4c3cf89fc3eecfbf1c3a2932f81d3b55c42647694bf732c5aeeace0592ccfd9905d50 - languageName: node - linkType: hard - -"@types/semver@npm:^7.5.0, @types/semver@npm:^7.5.8": +"@types/semver@npm:^7.5.8": version: 7.5.8 resolution: "@types/semver@npm:7.5.8" checksum: 10/3496808818ddb36deabfe4974fd343a78101fa242c4690044ccdc3b95dcf8785b494f5d628f2f47f38a702f8db9c53c67f47d7818f2be1b79f2efb09692e1178 @@ -2031,163 +3075,309 @@ __metadata: languageName: node linkType: hard -"@types/stack-utils@npm:^2.0.0": - version: 2.0.3 - resolution: "@types/stack-utils@npm:2.0.3" - checksum: 10/72576cc1522090fe497337c2b99d9838e320659ac57fa5560fcbdcbafcf5d0216c6b3a0a8a4ee4fdb3b1f5e3420aa4f6223ab57b82fef3578bec3206425c6cf5 +"@types/stack-utils@npm:^2.0.0": + version: 2.0.3 + resolution: "@types/stack-utils@npm:2.0.3" + checksum: 10/72576cc1522090fe497337c2b99d9838e320659ac57fa5560fcbdcbafcf5d0216c6b3a0a8a4ee4fdb3b1f5e3420aa4f6223ab57b82fef3578bec3206425c6cf5 + languageName: node + linkType: hard + +"@types/uuid@npm:^10.0.0": + version: 10.0.0 + resolution: "@types/uuid@npm:10.0.0" + checksum: 10/e3958f8b0fe551c86c14431f5940c3470127293280830684154b91dc7eb3514aeb79fe3216968833cf79d4d1c67f580f054b5be2cd562bebf4f728913e73e944 + languageName: node + linkType: hard + +"@types/yargs-parser@npm:*": + version: 21.0.3 + resolution: "@types/yargs-parser@npm:21.0.3" + checksum: 10/a794eb750e8ebc6273a51b12a0002de41343ffe46befef460bdbb57262d187fdf608bc6615b7b11c462c63c3ceb70abe2564c8dd8ee0f7628f38a314f74a9b9b + languageName: node + linkType: hard + +"@types/yargs@npm:^17.0.8": + version: 17.0.32 + resolution: "@types/yargs@npm:17.0.32" + dependencies: + "@types/yargs-parser": "npm:*" + checksum: 10/1e2b2673847011ce43607df690d392f137d95a2d6ea85aa319403eadda2ef4277365efd4982354d8843f2611ef3846c88599660aaeb537fa9ccddae83c2a89de + languageName: node + linkType: hard + +"@typescript-eslint/eslint-plugin@npm:7.16.1": + version: 7.16.1 + resolution: "@typescript-eslint/eslint-plugin@npm:7.16.1" + dependencies: + "@eslint-community/regexpp": "npm:^4.10.0" + "@typescript-eslint/scope-manager": "npm:7.16.1" + "@typescript-eslint/type-utils": "npm:7.16.1" + "@typescript-eslint/utils": "npm:7.16.1" + "@typescript-eslint/visitor-keys": "npm:7.16.1" + graphemer: "npm:^1.4.0" + ignore: "npm:^5.3.1" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^1.3.0" + peerDependencies: + "@typescript-eslint/parser": ^7.0.0 + eslint: ^8.56.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/fddbfe461f85d10ee3967b89efa3c704806074af6806833f982915b21754567a98c5a486627174cc6b0ac4cb5f1282865d64ae251a5cbf6dbbbe191d0268520a + languageName: node + linkType: hard + +"@typescript-eslint/eslint-plugin@npm:8.6.0": + version: 8.6.0 + resolution: "@typescript-eslint/eslint-plugin@npm:8.6.0" + dependencies: + "@eslint-community/regexpp": "npm:^4.10.0" + "@typescript-eslint/scope-manager": "npm:8.6.0" + "@typescript-eslint/type-utils": "npm:8.6.0" + "@typescript-eslint/utils": "npm:8.6.0" + "@typescript-eslint/visitor-keys": "npm:8.6.0" + graphemer: "npm:^1.4.0" + ignore: "npm:^5.3.1" + natural-compare: "npm:^1.4.0" + ts-api-utils: "npm:^1.3.0" + peerDependencies: + "@typescript-eslint/parser": ^8.0.0 || ^8.0.0-alpha.0 + eslint: ^8.57.0 || ^9.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/8f8c72b47e59973c6aaa955a01d2bce834dbd317b37f66355aba564aa30bed4ed7be26080d20ed2ae834bc628706da534da6a87a9720608835b27f165d59bd2b + languageName: node + linkType: hard + +"@typescript-eslint/parser@npm:8.6.0": + version: 8.6.0 + resolution: "@typescript-eslint/parser@npm:8.6.0" + dependencies: + "@typescript-eslint/scope-manager": "npm:8.6.0" + "@typescript-eslint/types": "npm:8.6.0" + "@typescript-eslint/typescript-estree": "npm:8.6.0" + "@typescript-eslint/visitor-keys": "npm:8.6.0" + debug: "npm:^4.3.4" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/6e6bb37841665e5fac8c5505a5b755ef499d5caf8cb975043e8b0e459520d315a1c7e7ae60a1d6bc20e7f4193b6d7cb74bc95dede203851087a1713c8d0b8abc + languageName: node + linkType: hard + +"@typescript-eslint/scope-manager@npm:7.16.1": + version: 7.16.1 + resolution: "@typescript-eslint/scope-manager@npm:7.16.1" + dependencies: + "@typescript-eslint/types": "npm:7.16.1" + "@typescript-eslint/visitor-keys": "npm:7.16.1" + checksum: 10/57ce02c2624e49988b01666b3e13d1adb44ab78f2dafc47a56800d57bff624779b348928a905393fa5f2cce94a5844173ab81f32b81f0bb2897f10bbaf9cab6a languageName: node linkType: hard -"@types/yargs-parser@npm:*": - version: 21.0.3 - resolution: "@types/yargs-parser@npm:21.0.3" - checksum: 10/a794eb750e8ebc6273a51b12a0002de41343ffe46befef460bdbb57262d187fdf608bc6615b7b11c462c63c3ceb70abe2564c8dd8ee0f7628f38a314f74a9b9b +"@typescript-eslint/scope-manager@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/scope-manager@npm:7.18.0" + dependencies: + "@typescript-eslint/types": "npm:7.18.0" + "@typescript-eslint/visitor-keys": "npm:7.18.0" + checksum: 10/9eb2ae5d69d9f723e706c16b2b97744fc016996a5473bed596035ac4d12429b3d24e7340a8235d704efa57f8f52e1b3b37925ff7c2e3384859d28b23a99b8bcc languageName: node linkType: hard -"@types/yargs@npm:^17.0.8": - version: 17.0.32 - resolution: "@types/yargs@npm:17.0.32" +"@typescript-eslint/scope-manager@npm:8.6.0": + version: 8.6.0 + resolution: "@typescript-eslint/scope-manager@npm:8.6.0" dependencies: - "@types/yargs-parser": "npm:*" - checksum: 10/1e2b2673847011ce43607df690d392f137d95a2d6ea85aa319403eadda2ef4277365efd4982354d8843f2611ef3846c88599660aaeb537fa9ccddae83c2a89de + "@typescript-eslint/types": "npm:8.6.0" + "@typescript-eslint/visitor-keys": "npm:8.6.0" + checksum: 10/4a42020caf1b45f661a2722c60ca3aaec34eb93c39fae71fd7a7d9c7824d2930447ecab1059ed2908e31f9995df37c32e2cb599f0795f01012d6c63847b9e907 languageName: node linkType: hard -"@typescript-eslint/eslint-plugin@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/eslint-plugin@npm:7.3.1" +"@typescript-eslint/type-utils@npm:7.16.1": + version: 7.16.1 + resolution: "@typescript-eslint/type-utils@npm:7.16.1" dependencies: - "@eslint-community/regexpp": "npm:^4.5.1" - "@typescript-eslint/scope-manager": "npm:7.3.1" - "@typescript-eslint/type-utils": "npm:7.3.1" - "@typescript-eslint/utils": "npm:7.3.1" - "@typescript-eslint/visitor-keys": "npm:7.3.1" + "@typescript-eslint/typescript-estree": "npm:7.16.1" + "@typescript-eslint/utils": "npm:7.16.1" debug: "npm:^4.3.4" - graphemer: "npm:^1.4.0" - ignore: "npm:^5.2.4" - natural-compare: "npm:^1.4.0" - semver: "npm:^7.5.4" - ts-api-utils: "npm:^1.0.1" + ts-api-utils: "npm:^1.3.0" peerDependencies: - "@typescript-eslint/parser": ^7.0.0 eslint: ^8.56.0 peerDependenciesMeta: typescript: optional: true - checksum: 10/8ed276113a714d93ab3ababb1179e4785bd9378e6d97726519ea1d2ac502a94475e0be988c2ec427dcfc1e6950329d58da6e64131ee87028fce63493461cc51a + checksum: 10/38a72a3de8a2c3455d19e6d43e67ac6e1dc23e93b2d84571282b0323fadadcab33df1a89787c76fc99e45514e41a08bc9f5cb51287a7da48f56c64b512a3269b languageName: node linkType: hard -"@typescript-eslint/parser@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/parser@npm:7.3.1" +"@typescript-eslint/type-utils@npm:8.6.0": + version: 8.6.0 + resolution: "@typescript-eslint/type-utils@npm:8.6.0" dependencies: - "@typescript-eslint/scope-manager": "npm:7.3.1" - "@typescript-eslint/types": "npm:7.3.1" - "@typescript-eslint/typescript-estree": "npm:7.3.1" - "@typescript-eslint/visitor-keys": "npm:7.3.1" + "@typescript-eslint/typescript-estree": "npm:8.6.0" + "@typescript-eslint/utils": "npm:8.6.0" debug: "npm:^4.3.4" - peerDependencies: - eslint: ^8.56.0 + ts-api-utils: "npm:^1.3.0" peerDependenciesMeta: typescript: optional: true - checksum: 10/018326010fec1dcefd75809ccac5102a475bf1e052d824b898d707e7c0bf3e51e101164b410d1b2a513628985c96eb412538644d2005e26b99a22db6eb9402df + checksum: 10/9b537821e180818915e75422a4e4810f7cc87f2223ad7fb145fca76b808f97425f81e4db7909542f76e6b53519f9b3a47d86fc8d1881a156158432c0ba748f89 languageName: node linkType: hard -"@typescript-eslint/scope-manager@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/scope-manager@npm:7.3.1" - dependencies: - "@typescript-eslint/types": "npm:7.3.1" - "@typescript-eslint/visitor-keys": "npm:7.3.1" - checksum: 10/7384d1f46d7f3678a1135a1ac0bd8b6dfa2f01e93b19e2510c7082766cf6983a1bf80b4ccf498651199a81d9f2bdb65101fd7a19226a723260514204d0c30b34 +"@typescript-eslint/types@npm:7.16.1": + version: 7.16.1 + resolution: "@typescript-eslint/types@npm:7.16.1" + checksum: 10/cfb48821ffb5a5307e67ce05b9ec2f4775c560dc53011e313d4fa75d033e0130ce0d364ac92ad3634d325c16a889ddc3201e8a742217c73be8d34385da85620b + languageName: node + linkType: hard + +"@typescript-eslint/types@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/types@npm:7.18.0" + checksum: 10/0e30c73a3cc3c67dd06360a5a12fd12cee831e4092750eec3d6c031bdc4feafcb0ab1d882910a73e66b451a4f6e1dd015e9e2c4d45bf6bf716a474e5d123ddf0 + languageName: node + linkType: hard + +"@typescript-eslint/types@npm:8.6.0": + version: 8.6.0 + resolution: "@typescript-eslint/types@npm:8.6.0" + checksum: 10/b89e26ce5aa03be56ad5d261aa28aecf3bab5ba78983ea51630ccaee7c7066489ee7c58fc3f18811c63418c900e69ac2b7d12e206485f45b2331d00d8bdb760f languageName: node linkType: hard -"@typescript-eslint/type-utils@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/type-utils@npm:7.3.1" +"@typescript-eslint/typescript-estree@npm:7.16.1": + version: 7.16.1 + resolution: "@typescript-eslint/typescript-estree@npm:7.16.1" dependencies: - "@typescript-eslint/typescript-estree": "npm:7.3.1" - "@typescript-eslint/utils": "npm:7.3.1" + "@typescript-eslint/types": "npm:7.16.1" + "@typescript-eslint/visitor-keys": "npm:7.16.1" debug: "npm:^4.3.4" - ts-api-utils: "npm:^1.0.1" - peerDependencies: - eslint: ^8.56.0 + globby: "npm:^11.1.0" + is-glob: "npm:^4.0.3" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + ts-api-utils: "npm:^1.3.0" peerDependenciesMeta: typescript: optional: true - checksum: 10/fae9003a76a8f2a2a4bb88dc0f82c0a1ca0688633183fac391920e7124a12807aac84bb287a21f61e99523c15223d1c08e7680685ebf21d07429604cba6c420b + checksum: 10/7f88176f2d25779ec2d40df4c6bd0a26aa41494ee0302d4895b4d0cb4e284385c1e218ac2ad67ed90b5e1bf82b78b8aa4b903b5906fbf7101b08c409ce778e9c languageName: node linkType: hard -"@typescript-eslint/types@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/types@npm:7.3.1" - checksum: 10/c9c8eae1cf937cececd99a253bd65eb71b40206e79cf917ad9c3b3ab80cc7ce5fefb2804f9fd2a70e7438951f0d1e63df3031fc61e3a08dfef5fde208a12e0ed +"@typescript-eslint/typescript-estree@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/typescript-estree@npm:7.18.0" + dependencies: + "@typescript-eslint/types": "npm:7.18.0" + "@typescript-eslint/visitor-keys": "npm:7.18.0" + debug: "npm:^4.3.4" + globby: "npm:^11.1.0" + is-glob: "npm:^4.0.3" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + ts-api-utils: "npm:^1.3.0" + peerDependenciesMeta: + typescript: + optional: true + checksum: 10/b01e66235a91aa4439d02081d4a5f8b4a7cf9cb24f26b334812f657e3c603493e5f41e5c1e89cf4efae7d64509fa1f73affc16afc5e15cb7f83f724577c82036 languageName: node linkType: hard -"@typescript-eslint/typescript-estree@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/typescript-estree@npm:7.3.1" +"@typescript-eslint/typescript-estree@npm:8.6.0": + version: 8.6.0 + resolution: "@typescript-eslint/typescript-estree@npm:8.6.0" dependencies: - "@typescript-eslint/types": "npm:7.3.1" - "@typescript-eslint/visitor-keys": "npm:7.3.1" + "@typescript-eslint/types": "npm:8.6.0" + "@typescript-eslint/visitor-keys": "npm:8.6.0" debug: "npm:^4.3.4" - globby: "npm:^11.1.0" + fast-glob: "npm:^3.3.2" is-glob: "npm:^4.0.3" - minimatch: "npm:9.0.3" - semver: "npm:^7.5.4" - ts-api-utils: "npm:^1.0.1" + minimatch: "npm:^9.0.4" + semver: "npm:^7.6.0" + ts-api-utils: "npm:^1.3.0" peerDependenciesMeta: typescript: optional: true - checksum: 10/363ad9864b56394b4000dff7c2b77d0ea52042c3c20e3b86c0f3c66044915632d9890255527c6f3a5ef056886dec72e38fbcfce49d4ad092c160440f54128230 + checksum: 10/34b7920e34860d33e38081c3ca9f780890822c6a28e29804ae053a1a618a45d6513c014dcb46480b10a4ba3c3fd2ed4b80ccc6094a50032eb25d68c433b14203 languageName: node linkType: hard -"@typescript-eslint/utils@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/utils@npm:7.3.1" +"@typescript-eslint/utils@npm:7.16.1": + version: 7.16.1 + resolution: "@typescript-eslint/utils@npm:7.16.1" dependencies: "@eslint-community/eslint-utils": "npm:^4.4.0" - "@types/json-schema": "npm:^7.0.12" - "@types/semver": "npm:^7.5.0" - "@typescript-eslint/scope-manager": "npm:7.3.1" - "@typescript-eslint/types": "npm:7.3.1" - "@typescript-eslint/typescript-estree": "npm:7.3.1" - semver: "npm:^7.5.4" + "@typescript-eslint/scope-manager": "npm:7.16.1" + "@typescript-eslint/types": "npm:7.16.1" + "@typescript-eslint/typescript-estree": "npm:7.16.1" peerDependencies: eslint: ^8.56.0 - checksum: 10/234d9d65fe5d0f4a31345bd8f5a6f2879a578b3a531a14c2b3edaa7fb587c71d26249f86c41857382c0405384dc104955c02b588b3cee6fc2734f1ae40aef07b + checksum: 10/b3c279d706ff1b3a0002c8e0f0fcf559b63f4296e218199a25863054bda5b28d5a7ab6ad4ad1d0b7fa2c6cd9f2d0dcd7f784c3f75026fae7b58846695481ec45 languageName: node linkType: hard -"@typescript-eslint/visitor-keys@npm:7.3.1": - version: 7.3.1 - resolution: "@typescript-eslint/visitor-keys@npm:7.3.1" +"@typescript-eslint/utils@npm:8.6.0": + version: 8.6.0 + resolution: "@typescript-eslint/utils@npm:8.6.0" dependencies: - "@typescript-eslint/types": "npm:7.3.1" - eslint-visitor-keys: "npm:^3.4.1" - checksum: 10/163a93597c1d696920a19b3c1627d02368bdd52059f811c0fadd680c38034bb6418ebefe99d8ce26e0dd44ae184f18fab186af775de1a8771256be1a7905c174 + "@eslint-community/eslint-utils": "npm:^4.4.0" + "@typescript-eslint/scope-manager": "npm:8.6.0" + "@typescript-eslint/types": "npm:8.6.0" + "@typescript-eslint/typescript-estree": "npm:8.6.0" + peerDependencies: + eslint: ^8.57.0 || ^9.0.0 + checksum: 10/778caa5767d306d17dea8d648baf158eda4099717fd1067d5362446adb7e51af357d4a9a53430327cc7f0229c69347a3b9b434ab937256fb0b4a0e3458184068 languageName: node linkType: hard -"@ungap/structured-clone@npm:^1.2.0": - version: 1.2.0 - resolution: "@ungap/structured-clone@npm:1.2.0" - checksum: 10/c6fe89a505e513a7592e1438280db1c075764793a2397877ff1351721fe8792a966a5359769e30242b3cd023f2efb9e63ca2ca88019d73b564488cc20e3eab12 +"@typescript-eslint/utils@npm:^7.16.1": + version: 7.18.0 + resolution: "@typescript-eslint/utils@npm:7.18.0" + dependencies: + "@eslint-community/eslint-utils": "npm:^4.4.0" + "@typescript-eslint/scope-manager": "npm:7.18.0" + "@typescript-eslint/types": "npm:7.18.0" + "@typescript-eslint/typescript-estree": "npm:7.18.0" + peerDependencies: + eslint: ^8.56.0 + checksum: 10/f43fedb4f4d2e3836bdf137889449063a55c0ece74fdb283929cd376197b992313be8ef4df920c1c801b5c3076b92964c84c6c3b9b749d263b648d0011f5926e languageName: node linkType: hard -"abbrev@npm:^1.0.0": - version: 1.1.1 - resolution: "abbrev@npm:1.1.1" - checksum: 10/2d882941183c66aa665118bafdab82b7a177e9add5eb2776c33e960a4f3c89cff88a1b38aba13a456de01d0dd9d66a8bea7c903268b21ea91dd1097e1e2e8243 +"@typescript-eslint/visitor-keys@npm:7.16.1": + version: 7.16.1 + resolution: "@typescript-eslint/visitor-keys@npm:7.16.1" + dependencies: + "@typescript-eslint/types": "npm:7.16.1" + eslint-visitor-keys: "npm:^3.4.3" + checksum: 10/f5088d72b6ca48f4e525b7b5d6c6c9254d0d039d2959fd91200691218e8ac8f3e56287ec8bc411a79609e9d85ed5fc6c4f7d2edd80fadf734aeb6f6bfc833322 + languageName: node + linkType: hard + +"@typescript-eslint/visitor-keys@npm:7.18.0": + version: 7.18.0 + resolution: "@typescript-eslint/visitor-keys@npm:7.18.0" + dependencies: + "@typescript-eslint/types": "npm:7.18.0" + eslint-visitor-keys: "npm:^3.4.3" + checksum: 10/b7cfe6fdeae86c507357ac6b2357813c64fb2fbf1aaf844393ba82f73a16e2599b41981b34200d9fc7765d70bc3a8181d76b503051e53f04bcb7c9afef637eab + languageName: node + linkType: hard + +"@typescript-eslint/visitor-keys@npm:8.6.0": + version: 8.6.0 + resolution: "@typescript-eslint/visitor-keys@npm:8.6.0" + dependencies: + "@typescript-eslint/types": "npm:8.6.0" + eslint-visitor-keys: "npm:^3.4.3" + checksum: 10/76d94f33d27fd33c324bb5245ec571bede6f5f22e67f0412abccf603402d55df7f46ea05a36b8bdfe6266bb990e3298f5595292c0b8940a149409064605b5ee9 languageName: node linkType: hard @@ -2216,6 +3406,15 @@ __metadata: languageName: node linkType: hard +"acorn@npm:^8.12.0": + version: 8.12.1 + resolution: "acorn@npm:8.12.1" + bin: + acorn: bin/acorn + checksum: 10/d08c2d122bba32d0861e0aa840b2ee25946c286d5dc5990abca991baf8cdbfbe199b05aacb221b979411a2fea36f83e26b5ac4f6b4e0ce49038c62316c1848f0 + languageName: node + linkType: hard + "acorn@npm:^8.5.0, acorn@npm:^8.9.0": version: 8.12.0 resolution: "acorn@npm:8.12.0" @@ -2225,15 +3424,6 @@ __metadata: languageName: node linkType: hard -"agent-base@npm:6, agent-base@npm:^6.0.2": - version: 6.0.2 - resolution: "agent-base@npm:6.0.2" - dependencies: - debug: "npm:4" - checksum: 10/21fb903e0917e5cb16591b4d0ef6a028a54b83ac30cd1fca58dece3d4e0990512a8723f9f83130d88a41e2af8b1f7be1386fda3ea2d181bb1a62155e75e95e23 - languageName: node - linkType: hard - "agent-base@npm:^7.0.2, agent-base@npm:^7.1.0, agent-base@npm:^7.1.1": version: 7.1.1 resolution: "agent-base@npm:7.1.1" @@ -2243,15 +3433,6 @@ __metadata: languageName: node linkType: hard -"agentkeepalive@npm:^4.2.1": - version: 4.5.0 - resolution: "agentkeepalive@npm:4.5.0" - dependencies: - humanize-ms: "npm:^1.2.1" - checksum: 10/dd210ba2a2e2482028f027b1156789744aadbfd773a6c9dd8e4e8001930d5af82382abe19a69240307b1d8003222ce6b0542935038313434b900e351914fc15f - languageName: node - linkType: hard - "aggregate-error@npm:^3.0.0": version: 3.1.0 resolution: "aggregate-error@npm:3.1.0" @@ -2274,15 +3455,6 @@ __metadata: languageName: node linkType: hard -"ansi-align@npm:^3.0.1": - version: 3.0.1 - resolution: "ansi-align@npm:3.0.1" - dependencies: - string-width: "npm:^4.1.0" - checksum: 10/4c7e8b6a10eaf18874ecee964b5db62ac86d0b9266ad4987b3a1efcb5d11a9e12c881ee40d14951833135a8966f10a3efe43f9c78286a6e632f53d85ad28b9c0 - languageName: node - linkType: hard - "ansi-escapes@npm:^4.2.1": version: 4.3.2 resolution: "ansi-escapes@npm:4.3.2" @@ -2348,23 +3520,6 @@ __metadata: languageName: node linkType: hard -"aproba@npm:^1.0.3 || ^2.0.0": - version: 2.0.0 - resolution: "aproba@npm:2.0.0" - checksum: 10/c2b9a631298e8d6f3797547e866db642f68493808f5b37cd61da778d5f6ada890d16f668285f7d60bd4fc3b03889bd590ffe62cf81b700e9bb353431238a0a7b - languageName: node - linkType: hard - -"are-we-there-yet@npm:^3.0.0": - version: 3.0.1 - resolution: "are-we-there-yet@npm:3.0.1" - dependencies: - delegates: "npm:^1.0.0" - readable-stream: "npm:^3.6.0" - checksum: 10/390731720e1bf9ed5d0efc635ea7df8cbc4c90308b0645a932f06e8495a0bf1ecc7987d3b97e805f62a17d6c4b634074b25200aa4d149be2a7b17250b9744bc4 - languageName: node - linkType: hard - "argparse@npm:^1.0.7": version: 1.0.10 resolution: "argparse@npm:1.0.10" @@ -2381,7 +3536,16 @@ __metadata: languageName: node linkType: hard -"array-buffer-byte-length@npm:^1.0.1": +"aria-query@npm:~5.1.3": + version: 5.1.3 + resolution: "aria-query@npm:5.1.3" + dependencies: + deep-equal: "npm:^2.0.5" + checksum: 10/e5da608a7c4954bfece2d879342b6c218b6b207e2d9e5af270b5e38ef8418f02d122afdc948b68e32649b849a38377785252059090d66fa8081da95d1609c0d2 + languageName: node + linkType: hard + +"array-buffer-byte-length@npm:^1.0.0, array-buffer-byte-length@npm:^1.0.1": version: 1.0.1 resolution: "array-buffer-byte-length@npm:1.0.1" dependencies: @@ -2391,7 +3555,7 @@ __metadata: languageName: node linkType: hard -"array-includes@npm:^3.1.7": +"array-includes@npm:^3.1.6, array-includes@npm:^3.1.8": version: 3.1.8 resolution: "array-includes@npm:3.1.8" dependencies: @@ -2419,7 +3583,21 @@ __metadata: languageName: node linkType: hard -"array.prototype.findlastindex@npm:^1.2.3": +"array.prototype.findlast@npm:^1.2.5": + version: 1.2.5 + resolution: "array.prototype.findlast@npm:1.2.5" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10/7dffcc665aa965718ad6de7e17ac50df0c5e38798c0a5bf9340cf24feb8594df6ec6f3fcbe714c1577728a1b18b5704b15669474b27bceeca91ef06ce2a23c31 + languageName: node + linkType: hard + +"array.prototype.findlastindex@npm:^1.2.5": version: 1.2.5 resolution: "array.prototype.findlastindex@npm:1.2.5" dependencies: @@ -2433,7 +3611,7 @@ __metadata: languageName: node linkType: hard -"array.prototype.flat@npm:^1.3.2": +"array.prototype.flat@npm:^1.3.1, array.prototype.flat@npm:^1.3.2": version: 1.3.2 resolution: "array.prototype.flat@npm:1.3.2" dependencies: @@ -2457,6 +3635,19 @@ __metadata: languageName: node linkType: hard +"array.prototype.tosorted@npm:^1.1.4": + version: 1.1.4 + resolution: "array.prototype.tosorted@npm:1.1.4" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.3" + es-errors: "npm:^1.3.0" + es-shim-unscopables: "npm:^1.0.2" + checksum: 10/874694e5d50e138894ff5b853e639c29b0aa42bbd355acda8e8e9cd337f1c80565f21edc15e8c727fa4c0877fd9d8783c575809e440cc4d2d19acaa048bf967d + languageName: node + linkType: hard + "arraybuffer.prototype.slice@npm:^1.0.3": version: 1.0.3 resolution: "arraybuffer.prototype.slice@npm:1.0.3" @@ -2473,6 +3664,20 @@ __metadata: languageName: node linkType: hard +"ast-types-flow@npm:^0.0.8": + version: 0.0.8 + resolution: "ast-types-flow@npm:0.0.8" + checksum: 10/85a1c24af4707871c27cfe456bd2ff7fcbe678f3d1c878ac968c9557735a171a17bdcc8c8f903ceab3fc3c49d5b3da2194e6ab0a6be7fec0e133fa028f21ba1b + languageName: node + linkType: hard + +"async@npm:^3.2.3": + version: 3.2.6 + resolution: "async@npm:3.2.6" + checksum: 10/cb6e0561a3c01c4b56a799cc8bab6ea5fef45f069ab32500b6e19508db270ef2dffa55e5aed5865c5526e9907b1f8be61b27530823b411ffafb5e1538c86c368 + languageName: node + linkType: hard + "available-typed-arrays@npm:^1.0.7": version: 1.0.7 resolution: "available-typed-arrays@npm:1.0.7" @@ -2482,6 +3687,20 @@ __metadata: languageName: node linkType: hard +"axe-core@npm:^4.10.0": + version: 4.10.0 + resolution: "axe-core@npm:4.10.0" + checksum: 10/6158489a7a704edc98bd30ed56243b8280c5203c60e095a2feb5bff95d9bf2ef10becfe359b1cbc8601338418999c26cf4eee704181dedbcb487f4d63a06d8d5 + languageName: node + linkType: hard + +"axobject-query@npm:^4.1.0": + version: 4.1.0 + resolution: "axobject-query@npm:4.1.0" + checksum: 10/e275dea9b673f71170d914f2d2a18be5d57d8d29717b629e7fedd907dcc2ebdc7a37803ff975874810bd423f222f299c020d28fde40a146f537448bf6bfecb6e + languageName: node + linkType: hard + "babel-jest@npm:^29.7.0": version: 29.7.0 resolution: "babel-jest@npm:29.7.0" @@ -2524,6 +3743,42 @@ __metadata: languageName: node linkType: hard +"babel-plugin-polyfill-corejs2@npm:^0.4.10": + version: 0.4.11 + resolution: "babel-plugin-polyfill-corejs2@npm:0.4.11" + dependencies: + "@babel/compat-data": "npm:^7.22.6" + "@babel/helper-define-polyfill-provider": "npm:^0.6.2" + semver: "npm:^6.3.1" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10/9c79908bed61b9f52190f254e22d3dca6ce25769738642579ba8d23832f3f9414567a90d8367a31831fa45d9b9607ac43d8d07ed31167d8ca8cda22871f4c7a1 + languageName: node + linkType: hard + +"babel-plugin-polyfill-corejs3@npm:^0.10.4": + version: 0.10.6 + resolution: "babel-plugin-polyfill-corejs3@npm:0.10.6" + dependencies: + "@babel/helper-define-polyfill-provider": "npm:^0.6.2" + core-js-compat: "npm:^3.38.0" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10/360ac9054a57a18c540059dc627ad5d84d15f79790cb3d84d19a02eec7188c67d08a07db789c3822d6f5df22d918e296d1f27c4055fec2e287d328f09ea8a78a + languageName: node + linkType: hard + +"babel-plugin-polyfill-regenerator@npm:^0.6.1": + version: 0.6.2 + resolution: "babel-plugin-polyfill-regenerator@npm:0.6.2" + dependencies: + "@babel/helper-define-polyfill-provider": "npm:^0.6.2" + peerDependencies: + "@babel/core": ^7.4.0 || ^8.0.0-0 <8.0.0 + checksum: 10/150233571072b6b3dfe946242da39cba8587b7f908d1c006f7545fc88b0e3c3018d445739beb61e7a75835f0c2751dbe884a94ff9b245ec42369d9267e0e1b3f + languageName: node + linkType: hard + "babel-preset-current-node-syntax@npm:^1.0.0": version: 1.0.1 resolution: "babel-preset-current-node-syntax@npm:1.0.1" @@ -2565,29 +3820,6 @@ __metadata: languageName: node linkType: hard -"bintrees@npm:1.0.2": - version: 1.0.2 - resolution: "bintrees@npm:1.0.2" - checksum: 10/071896cea5ea5413316c8436e95799444c208630d5c539edd8a7089fc272fc5d3634aa4a2e4847b28350dda1796162e14a34a0eda53108cc5b3c2ff6a036c1fa - languageName: node - linkType: hard - -"boxen@npm:^7.0.0": - version: 7.1.1 - resolution: "boxen@npm:7.1.1" - dependencies: - ansi-align: "npm:^3.0.1" - camelcase: "npm:^7.0.1" - chalk: "npm:^5.2.0" - cli-boxes: "npm:^3.0.0" - string-width: "npm:^5.1.2" - type-fest: "npm:^2.13.0" - widest-line: "npm:^4.0.1" - wrap-ansi: "npm:^8.1.0" - checksum: 10/a21d514435ccdd51f11088ad42e6298e3ff6be1bc2801699dcc1d3d79a2c5b005b5384dd03742e91a1ce2d9aedf99996efb36ed5fc7c5c392e19de2404bcfa37 - languageName: node - linkType: hard - "brace-expansion@npm:^1.1.7": version: 1.1.11 resolution: "brace-expansion@npm:1.1.11" @@ -2616,7 +3848,7 @@ __metadata: languageName: node linkType: hard -"browserslist@npm:^4.22.2, browserslist@npm:^4.23.0": +"browserslist@npm:^4.22.2": version: 4.23.1 resolution: "browserslist@npm:4.23.1" dependencies: @@ -2630,7 +3862,21 @@ __metadata: languageName: node linkType: hard -"bs-logger@npm:0.x": +"browserslist@npm:^4.23.1, browserslist@npm:^4.23.3": + version: 4.23.3 + resolution: "browserslist@npm:4.23.3" + dependencies: + caniuse-lite: "npm:^1.0.30001646" + electron-to-chromium: "npm:^1.5.4" + node-releases: "npm:^2.0.18" + update-browserslist-db: "npm:^1.1.0" + bin: + browserslist: cli.js + checksum: 10/e266d18c6c6c5becf9a1a7aa264477677b9796387972e8fce34854bb33dc1666194dc28389780e5dc6566e68a95e87ece2ce222e1c4ca93c2b75b61dfebd5f1c + languageName: node + linkType: hard + +"bs-logger@npm:^0.2.6": version: 0.2.6 resolution: "bs-logger@npm:0.2.6" dependencies: @@ -2655,56 +3901,17 @@ __metadata: languageName: node linkType: hard -"builtin-modules@npm:^3.3.0": +"builtin-modules@npm:3.3.0, builtin-modules@npm:^3.3.0": version: 3.3.0 resolution: "builtin-modules@npm:3.3.0" checksum: 10/62e063ab40c0c1efccbfa9ffa31873e4f9d57408cb396a2649981a0ecbce56aabc93c28feaccbc5658c95aab2703ad1d11980e62ec2e5e72637404e1eb60f39e languageName: node linkType: hard -"cacache@npm:^16.1.0": - version: 16.1.3 - resolution: "cacache@npm:16.1.3" - dependencies: - "@npmcli/fs": "npm:^2.1.0" - "@npmcli/move-file": "npm:^2.0.0" - chownr: "npm:^2.0.0" - fs-minipass: "npm:^2.1.0" - glob: "npm:^8.0.1" - infer-owner: "npm:^1.0.4" - lru-cache: "npm:^7.7.1" - minipass: "npm:^3.1.6" - minipass-collect: "npm:^1.0.2" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - mkdirp: "npm:^1.0.4" - p-map: "npm:^4.0.0" - promise-inflight: "npm:^1.0.1" - rimraf: "npm:^3.0.2" - ssri: "npm:^9.0.0" - tar: "npm:^6.1.11" - unique-filename: "npm:^2.0.0" - checksum: 10/a14524d90e377ee691d63a81173b33c473f8bc66eb299c64290b58e1d41b28842397f8d6c15a01b4c57ca340afcec019ae112a45c2f67a79f76130d326472e92 - languageName: node - linkType: hard - -"cacache@npm:^17.0.0": - version: 17.1.4 - resolution: "cacache@npm:17.1.4" - dependencies: - "@npmcli/fs": "npm:^3.1.0" - fs-minipass: "npm:^3.0.0" - glob: "npm:^10.2.2" - lru-cache: "npm:^7.7.1" - minipass: "npm:^7.0.3" - minipass-collect: "npm:^1.0.2" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - p-map: "npm:^4.0.0" - ssri: "npm:^10.0.0" - tar: "npm:^6.1.11" - unique-filename: "npm:^3.0.0" - checksum: 10/6e26c788bc6a18ff42f4d4f97db30d5c60a5dfac8e7c10a03b0307a92cf1b647570547cf3cd96463976c051eb9c7258629863f156e224c82018862c1a8ad0e70 +"bytes@npm:3.1.2": + version: 3.1.2 + resolution: "bytes@npm:3.1.2" + checksum: 10/a10abf2ba70c784471d6b4f58778c0beeb2b5d405148e66affa91f23a9f13d07603d0a0354667310ae1d6dc141474ffd44e2a074be0f6e2254edb8fc21445388 languageName: node linkType: hard @@ -2728,28 +3935,6 @@ __metadata: languageName: node linkType: hard -"cacheable-lookup@npm:^7.0.0": - version: 7.0.0 - resolution: "cacheable-lookup@npm:7.0.0" - checksum: 10/69ea78cd9f16ad38120372e71ba98b64acecd95bbcbcdad811f857dc192bad81ace021f8def012ce19178583db8d46afd1a00b3e8c88527e978e049edbc23252 - languageName: node - linkType: hard - -"cacheable-request@npm:^10.2.8": - version: 10.2.14 - resolution: "cacheable-request@npm:10.2.14" - dependencies: - "@types/http-cache-semantics": "npm:^4.0.2" - get-stream: "npm:^6.0.1" - http-cache-semantics: "npm:^4.1.1" - keyv: "npm:^4.5.3" - mimic-response: "npm:^4.0.0" - normalize-url: "npm:^8.0.0" - responselike: "npm:^3.0.0" - checksum: 10/102f454ac68eb66f99a709c5cf65e90ed89f1b9269752578d5a08590b3986c3ea47a5d9dff208fe7b65855a29da129a2f23321b88490106898e0ba70b807c912 - languageName: node - linkType: hard - "call-bind@npm:^1.0.2, call-bind@npm:^1.0.5, call-bind@npm:^1.0.6, call-bind@npm:^1.0.7": version: 1.0.7 resolution: "call-bind@npm:1.0.7" @@ -2784,13 +3969,6 @@ __metadata: languageName: node linkType: hard -"camelcase@npm:^7.0.1": - version: 7.0.1 - resolution: "camelcase@npm:7.0.1" - checksum: 10/86ab8f3ebf08bcdbe605a211a242f00ed30d8bfb77dab4ebb744dd36efbc84432d1c4adb28975ba87a1b8be40a80fbd1e60e2f06565315918fa7350011a26d3d - languageName: node - linkType: hard - "caniuse-lite@npm:^1.0.30001629": version: 1.0.30001636 resolution: "caniuse-lite@npm:1.0.30001636" @@ -2798,6 +3976,13 @@ __metadata: languageName: node linkType: hard +"caniuse-lite@npm:^1.0.30001646": + version: 1.0.30001660 + resolution: "caniuse-lite@npm:1.0.30001660" + checksum: 10/5d83f0b7e2075b7e31f114f739155dc6c21b0afe8cb61180f625a4903b0ccd3d7591a5f81c930f14efddfa57040203ba0890850b8a3738f6c7f17c7dd83b9de8 + languageName: node + linkType: hard + "chalk@npm:^2.4.2": version: 2.4.2 resolution: "chalk@npm:2.4.2" @@ -2809,7 +3994,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^4.0.0": +"chalk@npm:^4.0.0, chalk@npm:^4.0.2": version: 4.1.2 resolution: "chalk@npm:4.1.2" dependencies: @@ -2819,7 +4004,7 @@ __metadata: languageName: node linkType: hard -"chalk@npm:^5.0.1, chalk@npm:^5.2.0, chalk@npm:^5.3.0": +"chalk@npm:^5.3.0": version: 5.3.0 resolution: "chalk@npm:5.3.0" checksum: 10/6373caaab21bd64c405bfc4bd9672b145647fc9482657b5ea1d549b3b2765054e9d3d928870cdf764fb4aad67555f5061538ff247b8310f110c5c888d92397ea @@ -2887,26 +4072,6 @@ __metadata: languageName: node linkType: hard -"cli-boxes@npm:^3.0.0": - version: 3.0.0 - resolution: "cli-boxes@npm:3.0.0" - checksum: 10/637d84419d293a9eac40a1c8c96a2859e7d98b24a1a317788e13c8f441be052fc899480c6acab3acc82eaf1bccda6b7542d7cdcf5c9c3cc39227175dc098d5b2 - languageName: node - linkType: hard - -"cli-table3@npm:^0.6.3": - version: 0.6.5 - resolution: "cli-table3@npm:0.6.5" - dependencies: - "@colors/colors": "npm:1.5.0" - string-width: "npm:^4.2.0" - dependenciesMeta: - "@colors/colors": - optional: true - checksum: 10/8dca71256f6f1367bab84c33add3f957367c7c43750a9828a4212ebd31b8df76bd7419d386e3391ac7419698a8540c25f1a474584028f35b170841cde2e055c5 - languageName: node - linkType: hard - "cliui@npm:^8.0.1": version: 8.0.1 resolution: "cliui@npm:8.0.1" @@ -2918,20 +4083,6 @@ __metadata: languageName: node linkType: hard -"clone@npm:2.x": - version: 2.1.2 - resolution: "clone@npm:2.1.2" - checksum: 10/d9c79efba655f0bf601ab299c57eb54cbaa9860fb011aee9d89ed5ac0d12df1660ab7642fddaabb9a26b7eff0e117d4520512cb70798319ff5d30a111b5310c2 - languageName: node - linkType: hard - -"cluster-key-slot@npm:1.1.2": - version: 1.1.2 - resolution: "cluster-key-slot@npm:1.1.2" - checksum: 10/516ed8b5e1a14d9c3a9c96c72ef6de2d70dfcdbaa0ec3a90bc7b9216c5457e39c09a5775750c272369070308542e671146120153062ab5f2f481bed5de2c925f - languageName: node - linkType: hard - "co@npm:^4.6.0": version: 4.6.0 resolution: "co@npm:4.6.0" @@ -2978,69 +4129,23 @@ __metadata: languageName: node linkType: hard -"color-support@npm:^1.1.3": - version: 1.1.3 - resolution: "color-support@npm:1.1.3" - bin: - color-support: bin.js - checksum: 10/4bcfe30eea1498fe1cabc852bbda6c9770f230ea0e4faf4611c5858b1b9e4dde3730ac485e65f54ca182f4c50b626c1bea7c8441ceda47367a54a818c248aa7a - languageName: node - linkType: hard - -"commander@npm:^10.0.1": - version: 10.0.1 - resolution: "commander@npm:10.0.1" - checksum: 10/8799faa84a30da985802e661cc9856adfaee324d4b138413013ef7f087e8d7924b144c30a1f1405475f0909f467665cd9e1ce13270a2f41b141dab0b7a58f3fb - languageName: node - linkType: hard - -"comment-json@npm:^4.2.3": - version: 4.2.3 - resolution: "comment-json@npm:4.2.3" +"comment-json@npm:^4.2.5": + version: 4.2.5 + resolution: "comment-json@npm:4.2.5" dependencies: array-timsort: "npm:^1.0.3" core-util-is: "npm:^1.0.3" esprima: "npm:^4.0.1" has-own-prop: "npm:^2.0.0" - repeat-string: "npm:^1.6.1" - checksum: 10/97eb6ff8231653864cea5c7721636e823194f0322cd7f0faa6154a1c5b5eb1cab2ca60526bc36d5b39e7c2bcf7eb175b57fd8e44b1c398f0c70ea8c9a114e834 - languageName: node - linkType: hard - -"concat-map@npm:0.0.1": - version: 0.0.1 - resolution: "concat-map@npm:0.0.1" - checksum: 10/9680699c8e2b3af0ae22592cb764acaf973f292a7b71b8a06720233011853a58e256c89216a10cbe889727532fd77f8bcd49a760cedfde271b8e006c20e079f2 - languageName: node - linkType: hard - -"config-chain@npm:^1.1.11": - version: 1.1.13 - resolution: "config-chain@npm:1.1.13" - dependencies: - ini: "npm:^1.3.4" - proto-list: "npm:~1.2.1" - checksum: 10/83d22cabf709e7669f6870021c4d552e4fc02e9682702b726be94295f42ce76cfed00f70b2910ce3d6c9465d9758e191e28ad2e72ff4e3331768a90da6c1ef03 - languageName: node - linkType: hard - -"configstore@npm:^6.0.0": - version: 6.0.0 - resolution: "configstore@npm:6.0.0" - dependencies: - dot-prop: "npm:^6.0.1" - graceful-fs: "npm:^4.2.6" - unique-string: "npm:^3.0.0" - write-file-atomic: "npm:^3.0.3" - xdg-basedir: "npm:^5.0.1" - checksum: 10/81995351c10bc04c58507f17748477aeac6f47465109d20e3534cebc881d22e927cfd29e73dd852c46c55f62c2b7be4cd1fe6eb3a93ba51f7f9813c218f9bae0 + repeat-string: "npm:^1.6.1" + checksum: 10/dc347621de15043a16846a1697a6248b427e913ddfb57f3427ca4eedf9c92131000d5e8efc8be9fe191a74dc36b615d73207fc3585bf29ca1b8d32e90d40c801 languageName: node linkType: hard -"console-control-strings@npm:^1.1.0": - version: 1.1.0 - resolution: "console-control-strings@npm:1.1.0" - checksum: 10/27b5fa302bc8e9ae9e98c03c66d76ca289ad0c61ce2fe20ab288d288bee875d217512d2edb2363fc83165e88f1c405180cf3f5413a46e51b4fe1a004840c6cdb +"concat-map@npm:0.0.1": + version: 0.0.1 + resolution: "concat-map@npm:0.0.1" + checksum: 10/9680699c8e2b3af0ae22592cb764acaf973f292a7b71b8a06720233011853a58e256c89216a10cbe889727532fd77f8bcd49a760cedfde271b8e006c20e079f2 languageName: node linkType: hard @@ -3051,12 +4156,12 @@ __metadata: languageName: node linkType: hard -"core-js-compat@npm:^3.34.0": - version: 3.37.1 - resolution: "core-js-compat@npm:3.37.1" +"core-js-compat@npm:^3.31.0, core-js-compat@npm:^3.37.0, core-js-compat@npm:^3.38.0": + version: 3.38.1 + resolution: "core-js-compat@npm:3.38.1" dependencies: - browserslist: "npm:^4.23.0" - checksum: 10/30c6fdbd9ff179cc53951814689b8aabec106e5de6cddfa7a7feacc96b66d415b8eebcf5ec8f7c68ef35c552fe7d39edb8b15b1ce0f27379a272295b6e937061 + browserslist: "npm:^4.23.3" + checksum: 10/4e2f219354fd268895f79486461a12df96f24ed307321482fe2a43529c5a64e7c16bcba654980ba217d603444f5141d43a79058aeac77511085f065c5da72207 languageName: node linkType: hard @@ -3095,109 +4200,108 @@ __metadata: languageName: node linkType: hard -"crypto-random-string@npm:^4.0.0": - version: 4.0.0 - resolution: "crypto-random-string@npm:4.0.0" - dependencies: - type-fest: "npm:^1.0.1" - checksum: 10/cd5d7ae13803de53680aaed4c732f67209af5988cbeec5f6b29082020347c2d8849ca921b2008be7d6bd1d9d198c3c3697e7441d6d0d3da1bf51e9e4d2032149 - languageName: node - linkType: hard - -"cspell-config-lib@npm:8.9.1": - version: 8.9.1 - resolution: "cspell-config-lib@npm:8.9.1" +"cspell-config-lib@npm:8.14.4": + version: 8.14.4 + resolution: "cspell-config-lib@npm:8.14.4" dependencies: - "@cspell/cspell-types": "npm:8.9.1" - comment-json: "npm:^4.2.3" - yaml: "npm:^2.4.5" - checksum: 10/e8f913115b87834eddc2effa8f21f055a126e8ca0fba61481f4495314b5a12017706234b5698df8621f6613c6aa0b64102afe2ffc7c6c52f158a201a84723c49 + "@cspell/cspell-types": "npm:8.14.4" + comment-json: "npm:^4.2.5" + yaml: "npm:^2.5.1" + checksum: 10/291805cbe2e4f97b000fb6cdbd37ab847eb0a91b288f9b6c3fbd0cc6173421d65a791c4d9e977f00190fecceb302fe42ab38efebd46e46c347f6ca22e17f02dd languageName: node linkType: hard -"cspell-dictionary@npm:8.9.1": - version: 8.9.1 - resolution: "cspell-dictionary@npm:8.9.1" +"cspell-dictionary@npm:8.14.4": + version: 8.14.4 + resolution: "cspell-dictionary@npm:8.14.4" dependencies: - "@cspell/cspell-pipe": "npm:8.9.1" - "@cspell/cspell-types": "npm:8.9.1" - cspell-trie-lib: "npm:8.9.1" + "@cspell/cspell-pipe": "npm:8.14.4" + "@cspell/cspell-types": "npm:8.14.4" + cspell-trie-lib: "npm:8.14.4" fast-equals: "npm:^5.0.1" - gensequence: "npm:^7.0.0" - checksum: 10/a117eb635da005c6c28fd4e2a319f66bc33ef8957f733af2a97c30b76a547f0c903526648a0958d89a1780c5204c355db45ff7718853e110e97c22e99ead786d + checksum: 10/992607ad92fc103cca2ff5c478c3cfa5e8dc57387c44c5aca85489cfddb41321f87f9b0adad4bbdabee185604f8e8326397c5b6ea30572bcbd3b6ab6734347b2 languageName: node linkType: hard -"cspell-glob@npm:8.9.1": - version: 8.9.1 - resolution: "cspell-glob@npm:8.9.1" +"cspell-glob@npm:8.14.4": + version: 8.14.4 + resolution: "cspell-glob@npm:8.14.4" dependencies: - micromatch: "npm:^4.0.7" - checksum: 10/2548f7bd58a1715c913cf140497a83bf12f54a60c74adf1b14e159fb40ed8bea62ab307cae5d945865f84227bc57a52c6f6fa13b6349b3aec940244b0a930095 + "@cspell/url": "npm:8.14.4" + micromatch: "npm:^4.0.8" + checksum: 10/7574cbd07fa2d22846ab4fbaa5f94fd02bdd4be58f3791726098e8ee62e83cf98c468b05416b994f8782269ef9603c8697603081c26cbc4182cebc6ef186f030 languageName: node linkType: hard -"cspell-grammar@npm:8.9.1": - version: 8.9.1 - resolution: "cspell-grammar@npm:8.9.1" +"cspell-grammar@npm:8.14.4": + version: 8.14.4 + resolution: "cspell-grammar@npm:8.14.4" dependencies: - "@cspell/cspell-pipe": "npm:8.9.1" - "@cspell/cspell-types": "npm:8.9.1" + "@cspell/cspell-pipe": "npm:8.14.4" + "@cspell/cspell-types": "npm:8.14.4" bin: cspell-grammar: bin.mjs - checksum: 10/881edbfd86ccd52aaeb5925c8b14ed4c6e82cffc444639252825f034aa806de85bcd52ff4d771145fc78547a92e48c48a33adbdb82d18cd8e6423540e7c5c033 + checksum: 10/4396f1eff263661bbaeb67bac2a2f5aa2f66e3f3d9ad47bb69fafb6bd52d3d67318054db74699619e4e604b4a16bf1ec9558b628fd17db34523d74e11cfd12fc languageName: node linkType: hard -"cspell-io@npm:8.9.1": - version: 8.9.1 - resolution: "cspell-io@npm:8.9.1" +"cspell-io@npm:8.14.4": + version: 8.14.4 + resolution: "cspell-io@npm:8.14.4" dependencies: - "@cspell/cspell-service-bus": "npm:8.9.1" - "@cspell/url": "npm:8.9.1" - checksum: 10/54be79d7b8c1e4d922febbef841ae549169d23aa9ad467a33e174a7a7707d2f60f7ae427f496c491c4ccdf0c7469eccb57205ce790935aab6f335019c8890183 + "@cspell/cspell-service-bus": "npm:8.14.4" + "@cspell/url": "npm:8.14.4" + checksum: 10/d20fe7d67afe342b166b466a7c7d243768f90f19289f32acfe1dfce1a5f2414ffa8ce70209e5062cef0f8a5771d4fcfe22ef7dff77fb15f9a802c3fd24387243 languageName: node linkType: hard -"cspell-lib@npm:8.9.1": - version: 8.9.1 - resolution: "cspell-lib@npm:8.9.1" +"cspell-lib@npm:8.14.4": + version: 8.14.4 + resolution: "cspell-lib@npm:8.14.4" dependencies: - "@cspell/cspell-bundled-dicts": "npm:8.9.1" - "@cspell/cspell-pipe": "npm:8.9.1" - "@cspell/cspell-resolver": "npm:8.9.1" - "@cspell/cspell-types": "npm:8.9.1" - "@cspell/dynamic-import": "npm:8.9.1" - "@cspell/strong-weak-map": "npm:8.9.1" - "@cspell/url": "npm:8.9.1" + "@cspell/cspell-bundled-dicts": "npm:8.14.4" + "@cspell/cspell-pipe": "npm:8.14.4" + "@cspell/cspell-resolver": "npm:8.14.4" + "@cspell/cspell-types": "npm:8.14.4" + "@cspell/dynamic-import": "npm:8.14.4" + "@cspell/filetypes": "npm:8.14.4" + "@cspell/strong-weak-map": "npm:8.14.4" + "@cspell/url": "npm:8.14.4" clear-module: "npm:^4.1.2" - comment-json: "npm:^4.2.3" - cspell-config-lib: "npm:8.9.1" - cspell-dictionary: "npm:8.9.1" - cspell-glob: "npm:8.9.1" - cspell-grammar: "npm:8.9.1" - cspell-io: "npm:8.9.1" - cspell-trie-lib: "npm:8.9.1" + comment-json: "npm:^4.2.5" + cspell-config-lib: "npm:8.14.4" + cspell-dictionary: "npm:8.14.4" + cspell-glob: "npm:8.14.4" + cspell-grammar: "npm:8.14.4" + cspell-io: "npm:8.14.4" + cspell-trie-lib: "npm:8.14.4" env-paths: "npm:^3.0.0" fast-equals: "npm:^5.0.1" gensequence: "npm:^7.0.0" import-fresh: "npm:^3.3.0" resolve-from: "npm:^5.0.0" - vscode-languageserver-textdocument: "npm:^1.0.11" + vscode-languageserver-textdocument: "npm:^1.0.12" vscode-uri: "npm:^3.0.8" xdg-basedir: "npm:^5.1.0" - checksum: 10/02c17e1fdc92d70c6722d1245c5205eae2489a9cc85203a6512d3bf5dae974e50600e228724c6d72061ff536005d15816876c16bbf9e68d6e904282f3e56ffca + checksum: 10/00b7b954dcaa0937c620db0aabb1f1eeaf17b98c78b293fda65aa16686649cd0772107b488994c65f4d569a20cce253c328d27792dbc4e836888354bdfcf6dfd languageName: node linkType: hard -"cspell-trie-lib@npm:8.9.1": - version: 8.9.1 - resolution: "cspell-trie-lib@npm:8.9.1" +"cspell-trie-lib@npm:8.14.4": + version: 8.14.4 + resolution: "cspell-trie-lib@npm:8.14.4" dependencies: - "@cspell/cspell-pipe": "npm:8.9.1" - "@cspell/cspell-types": "npm:8.9.1" + "@cspell/cspell-pipe": "npm:8.14.4" + "@cspell/cspell-types": "npm:8.14.4" gensequence: "npm:^7.0.0" - checksum: 10/c204b72f80345d2f5e55dfb1c8196deb35649188161393ade3e85653df4bf52bd1d7f652dab53d043b3c7b100609c07098c4f7a4d331a1a3277733528d598b7f + checksum: 10/355f378ac7e1f07a4c7607541e416a73126ff51fa6216f7aa459275d658332ac8832a5054cc049429d115eccc91634dfecab56bf7ccfb33873b6481b11eb8e6c + languageName: node + linkType: hard + +"damerau-levenshtein@npm:^1.0.8": + version: 1.0.8 + resolution: "damerau-levenshtein@npm:1.0.8" + checksum: 10/f4eba1c90170f96be25d95fa3857141b5f81e254f7e4d530da929217b19990ea9a0390fc53d3c1cafac9152fda78e722ea4894f765cf6216be413b5af1fbf821 languageName: node linkType: hard @@ -3234,14 +4338,14 @@ __metadata: languageName: node linkType: hard -"dayjs@npm:^1.11.11": - version: 1.11.11 - resolution: "dayjs@npm:1.11.11" - checksum: 10/f03948b172fbeed229837965988d1d5bac99c72a31c28731a457303259439f2f36289186489ae140adbeb10f591a926908c8de5d81eb449a2edbf5cbd6e9e30c +"dayjs@npm:^1.11.13": + version: 1.11.13 + resolution: "dayjs@npm:1.11.13" + checksum: 10/7374d63ab179b8d909a95e74790def25c8986e329ae989840bacb8b1888be116d20e1c4eee75a69ea0dfbae13172efc50ef85619d304ee7ca3c01d5878b704f5 languageName: node linkType: hard -"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.3, debug@npm:^4.3.4": +"debug@npm:4, debug@npm:^4.1.0, debug@npm:^4.1.1, debug@npm:^4.3.1, debug@npm:^4.3.2, debug@npm:^4.3.4": version: 4.3.5 resolution: "debug@npm:4.3.5" dependencies: @@ -3262,15 +4366,6 @@ __metadata: languageName: node linkType: hard -"decompress-response@npm:^6.0.0": - version: 6.0.0 - resolution: "decompress-response@npm:6.0.0" - dependencies: - mimic-response: "npm:^3.1.0" - checksum: 10/d377cf47e02d805e283866c3f50d3d21578b779731e8c5072d6ce8c13cc31493db1c2f6784da9d1d5250822120cefa44f1deab112d5981015f2e17444b763812 - languageName: node - linkType: hard - "dedent@npm:^1.0.0": version: 1.5.3 resolution: "dedent@npm:1.5.3" @@ -3283,10 +4378,29 @@ __metadata: languageName: node linkType: hard -"deep-extend@npm:^0.6.0": - version: 0.6.0 - resolution: "deep-extend@npm:0.6.0" - checksum: 10/7be7e5a8d468d6b10e6a67c3de828f55001b6eb515d014f7aeb9066ce36bd5717161eb47d6a0f7bed8a9083935b465bc163ee2581c8b128d29bf61092fdf57a7 +"deep-equal@npm:^2.0.5": + version: 2.2.3 + resolution: "deep-equal@npm:2.2.3" + dependencies: + array-buffer-byte-length: "npm:^1.0.0" + call-bind: "npm:^1.0.5" + es-get-iterator: "npm:^1.1.3" + get-intrinsic: "npm:^1.2.2" + is-arguments: "npm:^1.1.1" + is-array-buffer: "npm:^3.0.2" + is-date-object: "npm:^1.0.5" + is-regex: "npm:^1.1.4" + is-shared-array-buffer: "npm:^1.0.2" + isarray: "npm:^2.0.5" + object-is: "npm:^1.1.5" + object-keys: "npm:^1.1.1" + object.assign: "npm:^4.1.4" + regexp.prototype.flags: "npm:^1.5.1" + side-channel: "npm:^1.0.4" + which-boxed-primitive: "npm:^1.0.2" + which-collection: "npm:^1.0.1" + which-typed-array: "npm:^1.1.13" + checksum: 10/1ce49d0b71d0f14d8ef991a742665eccd488dfc9b3cada069d4d7a86291e591c92d2589c832811dea182b4015736b210acaaebce6184be356c1060d176f5a05f languageName: node linkType: hard @@ -3304,13 +4418,6 @@ __metadata: languageName: node linkType: hard -"defer-to-connect@npm:^2.0.1": - version: 2.0.1 - resolution: "defer-to-connect@npm:2.0.1" - checksum: 10/8a9b50d2f25446c0bfefb55a48e90afd58f85b21bcf78e9207cd7b804354f6409032a1705c2491686e202e64fc05f147aa5aa45f9aa82627563f045937f5791b - languageName: node - linkType: hard - "define-data-property@npm:^1.0.1, define-data-property@npm:^1.1.4": version: 1.1.4 resolution: "define-data-property@npm:1.1.4" @@ -3322,7 +4429,7 @@ __metadata: languageName: node linkType: hard -"define-properties@npm:^1.2.0, define-properties@npm:^1.2.1": +"define-properties@npm:^1.1.3, define-properties@npm:^1.2.0, define-properties@npm:^1.2.1": version: 1.2.1 resolution: "define-properties@npm:1.2.1" dependencies: @@ -3333,13 +4440,6 @@ __metadata: languageName: node linkType: hard -"delegates@npm:^1.0.0": - version: 1.0.0 - resolution: "delegates@npm:1.0.0" - checksum: 10/a51744d9b53c164ba9c0492471a1a2ffa0b6727451bdc89e31627fdf4adda9d51277cfcbfb20f0a6f08ccb3c436f341df3e92631a3440226d93a8971724771fd - languageName: node - linkType: hard - "detect-newline@npm:^3.0.0": version: 3.1.0 resolution: "detect-newline@npm:3.1.0" @@ -3372,24 +4472,6 @@ __metadata: languageName: node linkType: hard -"doctrine@npm:^3.0.0": - version: 3.0.0 - resolution: "doctrine@npm:3.0.0" - dependencies: - esutils: "npm:^2.0.2" - checksum: 10/b4b28f1df5c563f7d876e7461254a4597b8cabe915abe94d7c5d1633fed263fcf9a85e8d3836591fc2d040108e822b0d32758e5ec1fe31c590dc7e08086e3e48 - languageName: node - linkType: hard - -"dot-prop@npm:^6.0.1": - version: 6.0.1 - resolution: "dot-prop@npm:6.0.1" - dependencies: - is-obj: "npm:^2.0.0" - checksum: 10/1200a4f6f81151161b8526c37966d60738cf12619b0ed1f55be01bdb55790bf0a5cd1398b8f2c296dcc07d0a7c2dd0e650baf0b069c367e74bb5df2f6603aba0 - languageName: node - linkType: hard - "dotenv@npm:*, dotenv@npm:^16.4.5": version: 16.4.5 resolution: "dotenv@npm:16.4.5" @@ -3404,6 +4486,17 @@ __metadata: languageName: node linkType: hard +"ejs@npm:^3.1.10": + version: 3.1.10 + resolution: "ejs@npm:3.1.10" + dependencies: + jake: "npm:^10.8.5" + bin: + ejs: bin/cli.js + checksum: 10/a9cb7d7cd13b7b1cd0be5c4788e44dd10d92f7285d2f65b942f33e127230c054f99a42db4d99f766d8dbc6c57e94799593ee66a14efd7c8dd70c4812bf6aa384 + languageName: node + linkType: hard + "electron-to-chromium@npm:^1.4.796": version: 1.4.810 resolution: "electron-to-chromium@npm:1.4.810" @@ -3411,6 +4504,13 @@ __metadata: languageName: node linkType: hard +"electron-to-chromium@npm:^1.5.4": + version: 1.5.20 + resolution: "electron-to-chromium@npm:1.5.20" + checksum: 10/179f8af9b5e426489fdf9f43272bea64c5e66231656e5510abe058fc601ff5981260f37576c03e4288dd25446d645cb35995b1ed3aab67e2e080fadb9134041f + languageName: node + linkType: hard + "emittery@npm:^0.13.1": version: 0.13.1 resolution: "emittery@npm:0.13.1" @@ -3471,7 +4571,7 @@ __metadata: languageName: node linkType: hard -"es-abstract@npm:^1.22.1, es-abstract@npm:^1.22.3, es-abstract@npm:^1.23.0, es-abstract@npm:^1.23.2": +"es-abstract@npm:^1.17.5, es-abstract@npm:^1.22.1, es-abstract@npm:^1.22.3, es-abstract@npm:^1.23.0, es-abstract@npm:^1.23.1, es-abstract@npm:^1.23.2, es-abstract@npm:^1.23.3": version: 1.23.3 resolution: "es-abstract@npm:1.23.3" dependencies: @@ -3541,6 +4641,45 @@ __metadata: languageName: node linkType: hard +"es-get-iterator@npm:^1.1.3": + version: 1.1.3 + resolution: "es-get-iterator@npm:1.1.3" + dependencies: + call-bind: "npm:^1.0.2" + get-intrinsic: "npm:^1.1.3" + has-symbols: "npm:^1.0.3" + is-arguments: "npm:^1.1.1" + is-map: "npm:^2.0.2" + is-set: "npm:^2.0.2" + is-string: "npm:^1.0.7" + isarray: "npm:^2.0.5" + stop-iteration-iterator: "npm:^1.0.0" + checksum: 10/bc2194befbe55725f9489098626479deee3c801eda7e83ce0dff2eb266a28dc808edb9b623ff01d31ebc1328f09d661333d86b601036692c2e3c1a6942319433 + languageName: node + linkType: hard + +"es-iterator-helpers@npm:^1.0.19": + version: 1.0.19 + resolution: "es-iterator-helpers@npm:1.0.19" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.3" + es-errors: "npm:^1.3.0" + es-set-tostringtag: "npm:^2.0.3" + function-bind: "npm:^1.1.2" + get-intrinsic: "npm:^1.2.4" + globalthis: "npm:^1.0.3" + has-property-descriptors: "npm:^1.0.2" + has-proto: "npm:^1.0.3" + has-symbols: "npm:^1.0.3" + internal-slot: "npm:^1.0.7" + iterator.prototype: "npm:^1.1.2" + safe-array-concat: "npm:^1.1.2" + checksum: 10/980a8081cf6798fe17fcea193b0448d784d72d76aca7240b10813207c67e3dc0d8a23992263870c4fc291da5a946935b0c56dec4fa1a9de8fee0165e4fa1fc58 + languageName: node + linkType: hard + "es-object-atoms@npm:^1.0.0": version: 1.0.0 resolution: "es-object-atoms@npm:1.0.0" @@ -3581,33 +4720,34 @@ __metadata: languageName: node linkType: hard -"esbuild@npm:~0.21.4": - version: 0.21.5 - resolution: "esbuild@npm:0.21.5" - dependencies: - "@esbuild/aix-ppc64": "npm:0.21.5" - "@esbuild/android-arm": "npm:0.21.5" - "@esbuild/android-arm64": "npm:0.21.5" - "@esbuild/android-x64": "npm:0.21.5" - "@esbuild/darwin-arm64": "npm:0.21.5" - "@esbuild/darwin-x64": "npm:0.21.5" - "@esbuild/freebsd-arm64": "npm:0.21.5" - "@esbuild/freebsd-x64": "npm:0.21.5" - "@esbuild/linux-arm": "npm:0.21.5" - "@esbuild/linux-arm64": "npm:0.21.5" - "@esbuild/linux-ia32": "npm:0.21.5" - "@esbuild/linux-loong64": "npm:0.21.5" - "@esbuild/linux-mips64el": "npm:0.21.5" - "@esbuild/linux-ppc64": "npm:0.21.5" - "@esbuild/linux-riscv64": "npm:0.21.5" - "@esbuild/linux-s390x": "npm:0.21.5" - "@esbuild/linux-x64": "npm:0.21.5" - "@esbuild/netbsd-x64": "npm:0.21.5" - "@esbuild/openbsd-x64": "npm:0.21.5" - "@esbuild/sunos-x64": "npm:0.21.5" - "@esbuild/win32-arm64": "npm:0.21.5" - "@esbuild/win32-ia32": "npm:0.21.5" - "@esbuild/win32-x64": "npm:0.21.5" +"esbuild@npm:~0.23.0": + version: 0.23.1 + resolution: "esbuild@npm:0.23.1" + dependencies: + "@esbuild/aix-ppc64": "npm:0.23.1" + "@esbuild/android-arm": "npm:0.23.1" + "@esbuild/android-arm64": "npm:0.23.1" + "@esbuild/android-x64": "npm:0.23.1" + "@esbuild/darwin-arm64": "npm:0.23.1" + "@esbuild/darwin-x64": "npm:0.23.1" + "@esbuild/freebsd-arm64": "npm:0.23.1" + "@esbuild/freebsd-x64": "npm:0.23.1" + "@esbuild/linux-arm": "npm:0.23.1" + "@esbuild/linux-arm64": "npm:0.23.1" + "@esbuild/linux-ia32": "npm:0.23.1" + "@esbuild/linux-loong64": "npm:0.23.1" + "@esbuild/linux-mips64el": "npm:0.23.1" + "@esbuild/linux-ppc64": "npm:0.23.1" + "@esbuild/linux-riscv64": "npm:0.23.1" + "@esbuild/linux-s390x": "npm:0.23.1" + "@esbuild/linux-x64": "npm:0.23.1" + "@esbuild/netbsd-x64": "npm:0.23.1" + "@esbuild/openbsd-arm64": "npm:0.23.1" + "@esbuild/openbsd-x64": "npm:0.23.1" + "@esbuild/sunos-x64": "npm:0.23.1" + "@esbuild/win32-arm64": "npm:0.23.1" + "@esbuild/win32-ia32": "npm:0.23.1" + "@esbuild/win32-x64": "npm:0.23.1" dependenciesMeta: "@esbuild/aix-ppc64": optional: true @@ -3645,6 +4785,8 @@ __metadata: optional: true "@esbuild/netbsd-x64": optional: true + "@esbuild/openbsd-arm64": + optional: true "@esbuild/openbsd-x64": optional: true "@esbuild/sunos-x64": @@ -3657,7 +4799,7 @@ __metadata: optional: true bin: esbuild: bin/esbuild - checksum: 10/d2ff2ca84d30cce8e871517374d6c2290835380dc7cd413b2d49189ed170d45e407be14de2cb4794cf76f75cf89955c4714726ebd3de7444b3046f5cab23ab6b + checksum: 10/f55fbd0bfb0f86ce67a6d2c6f6780729d536c330999ecb9f5a38d578fb9fda820acbbc67d6d1d377eed8fed50fc38f14ff9cb014f86dafab94269a7fb2177018 languageName: node linkType: hard @@ -3668,13 +4810,6 @@ __metadata: languageName: node linkType: hard -"escape-goat@npm:^4.0.0": - version: 4.0.0 - resolution: "escape-goat@npm:4.0.0" - checksum: 10/515f4c5427118a8513ef12ad3fbc194b2a0239a6bc8d923b8ebd885c97f3518ce54f911007e6c9424387d68b0f54cd72aa277cfc2ca44da8cb1bd6a880cfd13c - languageName: node - linkType: hard - "escape-string-regexp@npm:^1.0.5": version: 1.0.5 resolution: "escape-string-regexp@npm:1.0.5" @@ -3729,46 +4864,47 @@ __metadata: languageName: node linkType: hard -"eslint-module-utils@npm:^2.8.0": - version: 2.8.1 - resolution: "eslint-module-utils@npm:2.8.1" +"eslint-module-utils@npm:^2.9.0": + version: 2.11.0 + resolution: "eslint-module-utils@npm:2.11.0" dependencies: debug: "npm:^3.2.7" peerDependenciesMeta: eslint: optional: true - checksum: 10/3e7892c0a984c963632da56b30ccf8254c29b535467138f91086c2ecdb2ebd10e2be61b54e553f30e5abf1d14d47a7baa0dac890e3a658fd3cd07dca63afbe6d + checksum: 10/1ba42cf48c5f9ec3b76dfa42c16f1c24c10508313689425c05ccb1d0eaa34bdc5c5b9c0c033cd402e9c429666bd3eb8c6d0c66565b0c00949fae743ad3643c95 languageName: node linkType: hard -"eslint-plugin-import@npm:^2.29.1": - version: 2.29.1 - resolution: "eslint-plugin-import@npm:2.29.1" +"eslint-plugin-import@npm:^2.29.1, eslint-plugin-import@npm:^2.30.0": + version: 2.30.0 + resolution: "eslint-plugin-import@npm:2.30.0" dependencies: - array-includes: "npm:^3.1.7" - array.prototype.findlastindex: "npm:^1.2.3" + "@rtsao/scc": "npm:^1.1.0" + array-includes: "npm:^3.1.8" + array.prototype.findlastindex: "npm:^1.2.5" array.prototype.flat: "npm:^1.3.2" array.prototype.flatmap: "npm:^1.3.2" debug: "npm:^3.2.7" doctrine: "npm:^2.1.0" eslint-import-resolver-node: "npm:^0.3.9" - eslint-module-utils: "npm:^2.8.0" - hasown: "npm:^2.0.0" - is-core-module: "npm:^2.13.1" + eslint-module-utils: "npm:^2.9.0" + hasown: "npm:^2.0.2" + is-core-module: "npm:^2.15.1" is-glob: "npm:^4.0.3" minimatch: "npm:^3.1.2" - object.fromentries: "npm:^2.0.7" - object.groupby: "npm:^1.0.1" - object.values: "npm:^1.1.7" + object.fromentries: "npm:^2.0.8" + object.groupby: "npm:^1.0.3" + object.values: "npm:^1.2.0" semver: "npm:^6.3.1" tsconfig-paths: "npm:^3.15.0" peerDependencies: eslint: ^2 || ^3 || ^4 || ^5 || ^6 || ^7.2.0 || ^8 - checksum: 10/5865f05c38552145423c535326ec9a7113ab2305c7614c8b896ff905cfabc859c8805cac21e979c9f6f742afa333e6f62f812eabf891a7e8f5f0b853a32593c1 + checksum: 10/a5f85dfe76e27286c28a01d137769726ce3f758bcc03aa6b6f9e18700a40a08f57239f82e07efcab763c4b03a02d425edcc29fbecf40aad0124286978c6bc63c languageName: node linkType: hard -"eslint-plugin-jsonc@npm:^2.14.1": +"eslint-plugin-jsonc@npm:^2.16.0": version: 2.16.0 resolution: "eslint-plugin-jsonc@npm:2.16.0" dependencies: @@ -3785,21 +4921,47 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-no-unsanitized@npm:^4.0.2": - version: 4.0.2 - resolution: "eslint-plugin-no-unsanitized@npm:4.0.2" +"eslint-plugin-jsx-a11y@npm:^6.8.0": + version: 6.10.0 + resolution: "eslint-plugin-jsx-a11y@npm:6.10.0" + dependencies: + aria-query: "npm:~5.1.3" + array-includes: "npm:^3.1.8" + array.prototype.flatmap: "npm:^1.3.2" + ast-types-flow: "npm:^0.0.8" + axe-core: "npm:^4.10.0" + axobject-query: "npm:^4.1.0" + damerau-levenshtein: "npm:^1.0.8" + emoji-regex: "npm:^9.2.2" + es-iterator-helpers: "npm:^1.0.19" + hasown: "npm:^2.0.2" + jsx-ast-utils: "npm:^3.3.5" + language-tags: "npm:^1.0.9" + minimatch: "npm:^3.1.2" + object.fromentries: "npm:^2.0.8" + safe-regex-test: "npm:^1.0.3" + string.prototype.includes: "npm:^2.0.0" peerDependencies: - eslint: ^6 || ^7 || ^8 - checksum: 10/c6a979e45014ba6392076e23c3c6a904a77cab568035af7c52a89b167d026c8c4cec97b1039291cc41787a7cc1bdb36052d3c6e4cfb813dce3ec99a5307fbc8c + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9 + checksum: 10/d66e5e541a5a747d8a7ffd6e45b79c9da416b42be5891c259f3d9af63ed8897b5ff67373b00682ecdfc04fe2a2bc9df9c23b2f1749a228221d2dae0914543303 languageName: node linkType: hard -"eslint-plugin-prettier@npm:^5.1.3": - version: 5.1.3 - resolution: "eslint-plugin-prettier@npm:5.1.3" +"eslint-plugin-no-unsanitized@npm:^4.1.0": + version: 4.1.0 + resolution: "eslint-plugin-no-unsanitized@npm:4.1.0" + peerDependencies: + eslint: ^8 || ^9 + checksum: 10/7246a727e6bcd3678a5e6b67e95c386898f2e37b14ab3e1ff1f603e4e8adde2ca78b754301185c1313f2312e9d791909ab8caf9ce48b715aa3d732a191a697f6 + languageName: node + linkType: hard + +"eslint-plugin-prettier@npm:^5.2.1": + version: 5.2.1 + resolution: "eslint-plugin-prettier@npm:5.2.1" dependencies: prettier-linter-helpers: "npm:^1.0.0" - synckit: "npm:^0.8.6" + synckit: "npm:^0.9.1" peerDependencies: "@types/eslint": ">=8.0.0" eslint: ">=8.0.0" @@ -3810,34 +4972,95 @@ __metadata: optional: true eslint-config-prettier: optional: true - checksum: 10/4f26a30444adc61ed692cdb5a9f7e8d9f5794f0917151051e66755ce032a08c3cc72c8b5d56101412e90f6d77035bd8194ea8731e9c16aacdd5ae345a8dae188 + checksum: 10/10ddf68215237e327af09a47adab4c63f3885fda4fb28c4c42d1fc5f47d8a0cc45df6484799360ff1417a0aa3c77c3aaac49d7e9dfd145557b17e2d7ecc2a27c languageName: node linkType: hard -"eslint-plugin-security@npm:^2.1.1": - version: 2.1.1 - resolution: "eslint-plugin-security@npm:2.1.1" +"eslint-plugin-react-hooks@npm:4.6.0": + version: 4.6.0 + resolution: "eslint-plugin-react-hooks@npm:4.6.0" + peerDependencies: + eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 + checksum: 10/3c63134e056a6d98d66e2c475c81f904169db817e89316d14e36269919e31f4876a2588aa0e466ec8ef160465169c627fe823bfdaae7e213946584e4a165a3ac + languageName: node + linkType: hard + +"eslint-plugin-react@npm:^7.35.0": + version: 7.35.2 + resolution: "eslint-plugin-react@npm:7.35.2" + dependencies: + array-includes: "npm:^3.1.8" + array.prototype.findlast: "npm:^1.2.5" + array.prototype.flatmap: "npm:^1.3.2" + array.prototype.tosorted: "npm:^1.1.4" + doctrine: "npm:^2.1.0" + es-iterator-helpers: "npm:^1.0.19" + estraverse: "npm:^5.3.0" + hasown: "npm:^2.0.2" + jsx-ast-utils: "npm:^2.4.1 || ^3.0.0" + minimatch: "npm:^3.1.2" + object.entries: "npm:^1.1.8" + object.fromentries: "npm:^2.0.8" + object.values: "npm:^1.2.0" + prop-types: "npm:^15.8.1" + resolve: "npm:^2.0.0-next.5" + semver: "npm:^6.3.1" + string.prototype.matchall: "npm:^4.0.11" + string.prototype.repeat: "npm:^1.0.0" + peerDependencies: + eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 || ^9.7 + checksum: 10/f4631612444f9066c8007e9433c0972754b75d33be410cd18dcf003e4209600240dec3e50a9962aae35e9a08920a1eb60e51d3cc140e5f6c95582e727ebec74e + languageName: node + linkType: hard + +"eslint-plugin-security@npm:^3.0.1": + version: 3.0.1 + resolution: "eslint-plugin-security@npm:3.0.1" dependencies: safe-regex: "npm:^2.1.1" - checksum: 10/003fd5ba9cf17efc191ccf0160e30bd953e956538eddea9a4b7d5899536c17c3bc77799bf5309762d5969625776c82d11da358f45ceb49635361418944b94cbf + checksum: 10/5a7eb9a9d499addad93e9a650f503b2bdc23e8ab8222a0330e216726ffcc0e154405d23c8c523ff987e894cb9c8358da883c1dd22e21423e4368cd13de14930c languageName: node linkType: hard -"eslint-plugin-simple-import-sort@npm:^12.0.0": - version: 12.1.0 - resolution: "eslint-plugin-simple-import-sort@npm:12.1.0" +"eslint-plugin-simple-import-sort@npm:^12.1.1": + version: 12.1.1 + resolution: "eslint-plugin-simple-import-sort@npm:12.1.1" peerDependencies: eslint: ">=5.0.0" - checksum: 10/c28d46c88c7590e3a5cc49494ba8fd3c46b6cec903236a7e165b9441f27decd67baf63b13526203e505713c217ccfb43935ae600debb8e9d6cc817fbaab5f2e2 + checksum: 10/2a690cea9243fbefa70345687bca8952f5e185fa459b7a8db687a908cc31082435cfee236c619d5245548fa5f89a2f2c4f8499f80512e048d2bedc60e3662d5a languageName: node linkType: hard -"eslint-plugin-sonarjs@npm:^0.24.0": - version: 0.24.0 - resolution: "eslint-plugin-sonarjs@npm:0.24.0" +"eslint-plugin-sonarjs@npm:^2.0.2": + version: 2.0.2 + resolution: "eslint-plugin-sonarjs@npm:2.0.2" + dependencies: + "@babel/core": "npm:7.24.3" + "@babel/eslint-parser": "npm:7.24.1" + "@babel/plugin-proposal-decorators": "npm:7.24.1" + "@babel/preset-env": "npm:7.24.3" + "@babel/preset-flow": "npm:7.24.1" + "@babel/preset-react": "npm:7.24.1" + "@eslint-community/regexpp": "npm:4.10.0" + "@typescript-eslint/eslint-plugin": "npm:7.16.1" + "@typescript-eslint/utils": "npm:^7.16.1" + builtin-modules: "npm:3.3.0" + bytes: "npm:3.1.2" + eslint-plugin-import: "npm:^2.29.1" + eslint-plugin-jsx-a11y: "npm:^6.8.0" + eslint-plugin-react: "npm:^7.35.0" + eslint-plugin-react-hooks: "npm:4.6.0" + eslint-scope: "npm:8.0.1" + functional-red-black-tree: "npm:1.0.1" + jsx-ast-utils: "npm:^3.3.5" + minimatch: "npm:^9.0.3" + scslre: "npm:0.3.0" + semver: "npm:7.6.0" + typescript: "npm:*" + vue-eslint-parser: "npm:9.4.3" peerDependencies: - eslint: ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 - checksum: 10/5d313f183d77a654d98b392ac878ab5492417f872e26a57d25649ddce1bf3e40c0765cb05e183f383a583bdc92d2b02b9b38139c180d190de85a9c6732bd1917 + eslint: ^8.0.0 || ^9.0.0 + checksum: 10/7e41c281e815e22b2d0d96857645ee9bbef7aa868283168d74823c7969c9846e1edee17b2c625d0b740d022cf9a89af06f96ed51af668aa650fc61515e6696b8 languageName: node linkType: hard @@ -3853,17 +5076,17 @@ __metadata: languageName: node linkType: hard -"eslint-plugin-unicorn@npm:^51.0.1": - version: 51.0.1 - resolution: "eslint-plugin-unicorn@npm:51.0.1" +"eslint-plugin-unicorn@npm:^55.0.0": + version: 55.0.0 + resolution: "eslint-plugin-unicorn@npm:55.0.0" dependencies: - "@babel/helper-validator-identifier": "npm:^7.22.20" + "@babel/helper-validator-identifier": "npm:^7.24.5" "@eslint-community/eslint-utils": "npm:^4.4.0" - "@eslint/eslintrc": "npm:^2.1.4" ci-info: "npm:^4.0.0" clean-regexp: "npm:^1.0.0" - core-js-compat: "npm:^3.34.0" + core-js-compat: "npm:^3.37.0" esquery: "npm:^1.5.0" + globals: "npm:^15.7.0" indent-string: "npm:^4.0.0" is-builtin-module: "npm:^3.2.1" jsesc: "npm:^3.0.2" @@ -3871,15 +5094,35 @@ __metadata: read-pkg-up: "npm:^7.0.1" regexp-tree: "npm:^0.1.27" regjsparser: "npm:^0.10.0" - semver: "npm:^7.5.4" + semver: "npm:^7.6.1" strip-indent: "npm:^3.0.0" peerDependencies: eslint: ">=8.56.0" - checksum: 10/cea770332423d49d0cd86ca96055be7f14895e1d0a9fb24c8ed4f18a6e1eeff362d4881c46e85d85c37938bb85a6eeae7e347bcf7a3bb7307a8dd309651e0adf + checksum: 10/ea2fe55c517e18a8abedee125492ba09b11695fe41a3f42bf7b6789e9c937c89e8692735b07dcd41e25aff849950da2cca76ac6b727996e6bd2a978c8dc2685f + languageName: node + linkType: hard + +"eslint-scope@npm:5.1.1": + version: 5.1.1 + resolution: "eslint-scope@npm:5.1.1" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^4.1.1" + checksum: 10/c541ef384c92eb5c999b7d3443d80195fcafb3da335500946f6db76539b87d5826c8f2e1d23bf6afc3154ba8cd7c8e566f8dc00f1eea25fdf3afc8fb9c87b238 + languageName: node + linkType: hard + +"eslint-scope@npm:8.0.1": + version: 8.0.1 + resolution: "eslint-scope@npm:8.0.1" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^5.2.0" + checksum: 10/458513863d3c79005b599f40250437bddba923f18549058ea45820a8d3d4bbc67fe292751d522a0cab69dd01fe211ffde5c1a5fc867e86f2d28727b1d61610da languageName: node linkType: hard -"eslint-scope@npm:^7.2.2": +"eslint-scope@npm:^7.1.1": version: 7.2.2 resolution: "eslint-scope@npm:7.2.2" dependencies: @@ -3889,6 +5132,16 @@ __metadata: languageName: node linkType: hard +"eslint-scope@npm:^8.0.2": + version: 8.0.2 + resolution: "eslint-scope@npm:8.0.2" + dependencies: + esrecurse: "npm:^4.3.0" + estraverse: "npm:^5.2.0" + checksum: 10/d17c2e1ff4d3a98911414a954531078db912e2747d6da8ea4cafd16d0526e32086c676ce9aeaffb3ca0ff695fc951ac3169d7f08a0b42962db683dff126cc95b + languageName: node + linkType: hard + "eslint-visitor-keys@npm:^1.1.0": version: 1.3.0 resolution: "eslint-visitor-keys@npm:1.3.0" @@ -3896,6 +5149,13 @@ __metadata: languageName: node linkType: hard +"eslint-visitor-keys@npm:^2.1.0": + version: 2.1.0 + resolution: "eslint-visitor-keys@npm:2.1.0" + checksum: 10/db4547eef5039122d518fa307e938ceb8589da5f6e8f5222efaf14dd62f748ce82e2d2becd3ff9412a50350b726bda95dbea8515a471074547daefa58aee8735 + languageName: node + linkType: hard + "eslint-visitor-keys@npm:^3.0.0, eslint-visitor-keys@npm:^3.3.0, eslint-visitor-keys@npm:^3.4.1, eslint-visitor-keys@npm:^3.4.3": version: 3.4.3 resolution: "eslint-visitor-keys@npm:3.4.3" @@ -3903,51 +5163,70 @@ __metadata: languageName: node linkType: hard -"eslint@npm:8.57.0": - version: 8.57.0 - resolution: "eslint@npm:8.57.0" +"eslint-visitor-keys@npm:^4.0.0": + version: 4.0.0 + resolution: "eslint-visitor-keys@npm:4.0.0" + checksum: 10/c7617166e6291a15ce2982b5c4b9cdfb6409f5c14562712d12e2584480cdf18609694b21d7dad35b02df0fa2cd037505048ded54d2f405c64f600949564eb334 + languageName: node + linkType: hard + +"eslint@npm:9.10.0": + version: 9.10.0 + resolution: "eslint@npm:9.10.0" dependencies: "@eslint-community/eslint-utils": "npm:^4.2.0" - "@eslint-community/regexpp": "npm:^4.6.1" - "@eslint/eslintrc": "npm:^2.1.4" - "@eslint/js": "npm:8.57.0" - "@humanwhocodes/config-array": "npm:^0.11.14" + "@eslint-community/regexpp": "npm:^4.11.0" + "@eslint/config-array": "npm:^0.18.0" + "@eslint/eslintrc": "npm:^3.1.0" + "@eslint/js": "npm:9.10.0" + "@eslint/plugin-kit": "npm:^0.1.0" "@humanwhocodes/module-importer": "npm:^1.0.1" + "@humanwhocodes/retry": "npm:^0.3.0" "@nodelib/fs.walk": "npm:^1.2.8" - "@ungap/structured-clone": "npm:^1.2.0" ajv: "npm:^6.12.4" chalk: "npm:^4.0.0" cross-spawn: "npm:^7.0.2" debug: "npm:^4.3.2" - doctrine: "npm:^3.0.0" escape-string-regexp: "npm:^4.0.0" - eslint-scope: "npm:^7.2.2" - eslint-visitor-keys: "npm:^3.4.3" - espree: "npm:^9.6.1" - esquery: "npm:^1.4.2" + eslint-scope: "npm:^8.0.2" + eslint-visitor-keys: "npm:^4.0.0" + espree: "npm:^10.1.0" + esquery: "npm:^1.5.0" esutils: "npm:^2.0.2" fast-deep-equal: "npm:^3.1.3" - file-entry-cache: "npm:^6.0.1" + file-entry-cache: "npm:^8.0.0" find-up: "npm:^5.0.0" glob-parent: "npm:^6.0.2" - globals: "npm:^13.19.0" - graphemer: "npm:^1.4.0" ignore: "npm:^5.2.0" imurmurhash: "npm:^0.1.4" is-glob: "npm:^4.0.0" is-path-inside: "npm:^3.0.3" - js-yaml: "npm:^4.1.0" json-stable-stringify-without-jsonify: "npm:^1.0.1" - levn: "npm:^0.4.1" lodash.merge: "npm:^4.6.2" minimatch: "npm:^3.1.2" natural-compare: "npm:^1.4.0" optionator: "npm:^0.9.3" strip-ansi: "npm:^6.0.1" text-table: "npm:^0.2.0" + peerDependencies: + jiti: "*" + peerDependenciesMeta: + jiti: + optional: true bin: eslint: bin/eslint.js - checksum: 10/00496e218b23747a7a9817bf58b522276d0dc1f2e546dceb4eea49f9871574088f72f1f069a6b560ef537efa3a75261b8ef70e51ef19033da1cc4c86a755ef15 + checksum: 10/bbb6da7db83f5182cff5a5e1681cf77be761e37bfbfedf66add9d3d2a216dbc336e787d02d05a2ea85179c51a10203713b2438b86adfd7666c29afd3ee008fe8 + languageName: node + linkType: hard + +"espree@npm:^10.0.1, espree@npm:^10.1.0": + version: 10.1.0 + resolution: "espree@npm:10.1.0" + dependencies: + acorn: "npm:^8.12.0" + acorn-jsx: "npm:^5.3.2" + eslint-visitor-keys: "npm:^4.0.0" + checksum: 10/a673aa39a19a51763d92272f8f3772ae3d4b10624740bb72d5f273b631b43f1a5a32b385c1da6ae6bc10be05a5913bc4679ebd22a09c7b336a745204834806ea languageName: node linkType: hard @@ -3962,7 +5241,7 @@ __metadata: languageName: node linkType: hard -"espree@npm:^9.0.0, espree@npm:^9.6.0, espree@npm:^9.6.1": +"espree@npm:^9.0.0, espree@npm:^9.3.1, espree@npm:^9.6.1": version: 9.6.1 resolution: "espree@npm:9.6.1" dependencies: @@ -3983,7 +5262,16 @@ __metadata: languageName: node linkType: hard -"esquery@npm:^1.4.2, esquery@npm:^1.5.0": +"esquery@npm:^1.4.0": + version: 1.6.0 + resolution: "esquery@npm:1.6.0" + dependencies: + estraverse: "npm:^5.1.0" + checksum: 10/c587fb8ec9ed83f2b1bc97cf2f6854cc30bf784a79d62ba08c6e358bf22280d69aee12827521cf38e69ae9761d23fb7fde593ce315610f85655c139d99b05e5a + languageName: node + linkType: hard + +"esquery@npm:^1.5.0": version: 1.5.0 resolution: "esquery@npm:1.5.0" dependencies: @@ -4001,7 +5289,14 @@ __metadata: languageName: node linkType: hard -"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0": +"estraverse@npm:^4.1.1": + version: 4.3.0 + resolution: "estraverse@npm:4.3.0" + checksum: 10/3f67ad02b6dbfaddd9ea459cf2b6ef4ecff9a6082a7af9d22e445b9abc082ad9ca47e1825557b293fcdae477f4714e561123e30bb6a5b2f184fb2bad4a9497eb + languageName: node + linkType: hard + +"estraverse@npm:^5.1.0, estraverse@npm:^5.2.0, estraverse@npm:^5.3.0": version: 5.3.0 resolution: "estraverse@npm:5.3.0" checksum: 10/37cbe6e9a68014d34dbdc039f90d0baf72436809d02edffcc06ba3c2a12eb298048f877511353b130153e532aac8d68ba78430c0dd2f44806ebc7c014b01585e @@ -4080,7 +5375,7 @@ __metadata: languageName: node linkType: hard -"fast-glob@npm:^3.2.9": +"fast-glob@npm:^3.2.9, fast-glob@npm:^3.3.2": version: 3.3.2 resolution: "fast-glob@npm:3.3.2" dependencies: @@ -4107,13 +5402,6 @@ __metadata: languageName: node linkType: hard -"fast-memoize@npm:^2.5.2": - version: 2.5.2 - resolution: "fast-memoize@npm:2.5.2" - checksum: 10/b7e2839d70607c791ffda617bb3cf7d9944bd5483be05cedbc060be1381c79093efc470215f1bc5aa666b8ecc2c9ae49e6f56ab6f45f0c1474f6628651c9959b - languageName: node - linkType: hard - "fastq@npm:^1.6.0": version: 1.17.1 resolution: "fastq@npm:1.17.1" @@ -4132,12 +5420,21 @@ __metadata: languageName: node linkType: hard -"file-entry-cache@npm:^6.0.1": - version: 6.0.1 - resolution: "file-entry-cache@npm:6.0.1" +"file-entry-cache@npm:^8.0.0": + version: 8.0.0 + resolution: "file-entry-cache@npm:8.0.0" dependencies: - flat-cache: "npm:^3.0.4" - checksum: 10/099bb9d4ab332cb93c48b14807a6918a1da87c45dce91d4b61fd40e6505d56d0697da060cb901c729c90487067d93c9243f5da3dc9c41f0358483bfdebca736b + flat-cache: "npm:^4.0.0" + checksum: 10/afe55c4de4e0d226a23c1eae62a7219aafb390859122608a89fa4df6addf55c7fd3f1a2da6f5b41e7cdff496e4cf28bbd215d53eab5c817afa96d2b40c81bfb0 + languageName: node + linkType: hard + +"filelist@npm:^1.0.4": + version: 1.0.4 + resolution: "filelist@npm:1.0.4" + dependencies: + minimatch: "npm:^5.0.1" + checksum: 10/4b436fa944b1508b95cffdfc8176ae6947b92825483639ef1b9a89b27d82f3f8aa22b21eed471993f92709b431670d4e015b39c087d435a61e1bb04564cf51de languageName: node linkType: hard @@ -4150,16 +5447,6 @@ __metadata: languageName: node linkType: hard -"find-up@npm:5.0.0, find-up@npm:^5.0.0": - version: 5.0.0 - resolution: "find-up@npm:5.0.0" - dependencies: - locate-path: "npm:^6.0.0" - path-exists: "npm:^4.0.0" - checksum: 10/07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095 - languageName: node - linkType: hard - "find-up@npm:^4.0.0, find-up@npm:^4.1.0": version: 4.1.0 resolution: "find-up@npm:4.1.0" @@ -4170,14 +5457,23 @@ __metadata: languageName: node linkType: hard -"flat-cache@npm:^3.0.4": - version: 3.2.0 - resolution: "flat-cache@npm:3.2.0" +"find-up@npm:^5.0.0": + version: 5.0.0 + resolution: "find-up@npm:5.0.0" + dependencies: + locate-path: "npm:^6.0.0" + path-exists: "npm:^4.0.0" + checksum: 10/07955e357348f34660bde7920783204ff5a26ac2cafcaa28bace494027158a97b9f56faaf2d89a6106211a8174db650dd9f503f9c0d526b1202d5554a00b9095 + languageName: node + linkType: hard + +"flat-cache@npm:^4.0.0": + version: 4.0.1 + resolution: "flat-cache@npm:4.0.1" dependencies: flatted: "npm:^3.2.9" - keyv: "npm:^4.5.3" - rimraf: "npm:^3.0.2" - checksum: 10/02381c6ece5e9fa5b826c9bbea481d7fd77645d96e4b0b1395238124d581d10e56f17f723d897b6d133970f7a57f0fab9148cbbb67237a0a0ffe794ba60c0c70 + keyv: "npm:^4.5.4" + checksum: 10/58ce851d9045fffc7871ce2bd718bc485ad7e777bf748c054904b87c351ff1080c2c11da00788d78738bfb51b71e4d5ea12d13b98eb36e3358851ffe495b62dc languageName: node linkType: hard @@ -4207,21 +5503,7 @@ __metadata: languageName: node linkType: hard -"form-data-encoder@npm:^2.1.2": - version: 2.1.4 - resolution: "form-data-encoder@npm:2.1.4" - checksum: 10/3778e7db3c21457296e6fdbc4200642a6c01e8be9297256e845ee275f9ddaecb5f49bfb0364690ad216898c114ec59bf85f01ec823a70670b8067273415d62f6 - languageName: node - linkType: hard - -"fp-and-or@npm:^0.1.4": - version: 0.1.4 - resolution: "fp-and-or@npm:0.1.4" - checksum: 10/780969ef7e86e6822d7e5f27d9c3bcbb7fe1206dbdc8af76482a9213d9c812f8d9dfda8d8d3988f94f6cbc898e7a86ec5ab5700ef53b0760b3bf226a2a52e7e0 - languageName: node - linkType: hard - -"fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0": +"fs-minipass@npm:^2.0.0": version: 2.1.0 resolution: "fs-minipass@npm:2.1.0" dependencies: @@ -4284,6 +5566,13 @@ __metadata: languageName: node linkType: hard +"functional-red-black-tree@npm:1.0.1": + version: 1.0.1 + resolution: "functional-red-black-tree@npm:1.0.1" + checksum: 10/debe73e92204341d1fa5f89614e44284d3add26dee660722978d8c50829170f87d1c74768f68c251d215ae461c11db7bac13101c77f4146ff051da75466f7a12 + languageName: node + linkType: hard + "functions-have-names@npm:^1.2.3": version: 1.2.3 resolution: "functions-have-names@npm:1.2.3" @@ -4291,29 +5580,6 @@ __metadata: languageName: node linkType: hard -"gauge@npm:^4.0.3": - version: 4.0.4 - resolution: "gauge@npm:4.0.4" - dependencies: - aproba: "npm:^1.0.3 || ^2.0.0" - color-support: "npm:^1.1.3" - console-control-strings: "npm:^1.1.0" - has-unicode: "npm:^2.0.1" - signal-exit: "npm:^3.0.7" - string-width: "npm:^4.2.3" - strip-ansi: "npm:^6.0.1" - wide-align: "npm:^1.1.5" - checksum: 10/09535dd53b5ced6a34482b1fa9f3929efdeac02f9858569cde73cef3ed95050e0f3d095706c1689614059898924b7a74aa14042f51381a1ccc4ee5c29d2389c4 - languageName: node - linkType: hard - -"generic-pool@npm:3.9.0": - version: 3.9.0 - resolution: "generic-pool@npm:3.9.0" - checksum: 10/3c632d30a6a7d47412dc67ddc517992691e0fde819c0cb6b5871bc87d10f61a7c09f12a60dbd77c78ae3e6ca10db41e2eaee28985ce724d9620354a006205ce1 - languageName: node - linkType: hard - "gensequence@npm:^7.0.0": version: 7.0.0 resolution: "gensequence@npm:7.0.0" @@ -4335,7 +5601,7 @@ __metadata: languageName: node linkType: hard -"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": +"get-intrinsic@npm:^1.1.3, get-intrinsic@npm:^1.2.1, get-intrinsic@npm:^1.2.2, get-intrinsic@npm:^1.2.3, get-intrinsic@npm:^1.2.4": version: 1.2.4 resolution: "get-intrinsic@npm:1.2.4" dependencies: @@ -4355,14 +5621,7 @@ __metadata: languageName: node linkType: hard -"get-stdin@npm:^8.0.0": - version: 8.0.0 - resolution: "get-stdin@npm:8.0.0" - checksum: 10/40128b6cd25781ddbd233344f1a1e4006d4284906191ed0a7d55ec2c1a3e44d650f280b2c9eeab79c03ac3037da80257476c0e4e5af38ddfb902d6ff06282d77 - languageName: node - linkType: hard - -"get-stream@npm:^6.0.0, get-stream@npm:^6.0.1": +"get-stream@npm:^6.0.0": version: 6.0.1 resolution: "get-stream@npm:6.0.1" checksum: 10/781266d29725f35c59f1d214aedc92b0ae855800a980800e2923b3fbc4e56b3cb6e462c42e09a1cf1a00c64e056a78fa407cbe06c7c92b7e5cd49b4b85c2a497 @@ -4407,7 +5666,7 @@ __metadata: languageName: node linkType: hard -"glob@npm:^10.2.2, glob@npm:^10.3.10, glob@npm:^10.3.7": +"glob@npm:^10.2.2, glob@npm:^10.3.10": version: 10.4.2 resolution: "glob@npm:10.4.2" dependencies: @@ -4437,19 +5696,6 @@ __metadata: languageName: node linkType: hard -"glob@npm:^8.0.1": - version: 8.1.0 - resolution: "glob@npm:8.1.0" - dependencies: - fs.realpath: "npm:^1.0.0" - inflight: "npm:^1.0.4" - inherits: "npm:2" - minimatch: "npm:^5.0.1" - once: "npm:^1.3.0" - checksum: 10/9aab1c75eb087c35dbc41d1f742e51d0507aa2b14c910d96fb8287107a10a22f4bbdce26fc0a3da4c69a20f7b26d62f1640b346a4f6e6becfff47f335bb1dc5e - languageName: node - linkType: hard - "global-directory@npm:^4.0.1": version: 4.0.1 resolution: "global-directory@npm:4.0.1" @@ -4459,15 +5705,6 @@ __metadata: languageName: node linkType: hard -"global-dirs@npm:^3.0.0": - version: 3.0.1 - resolution: "global-dirs@npm:3.0.1" - dependencies: - ini: "npm:2.0.0" - checksum: 10/70147b80261601fd40ac02a104581432325c1c47329706acd773f3a6ce99bb36d1d996038c85ccacd482ad22258ec233c586b6a91535b1a116b89663d49d6438 - languageName: node - linkType: hard - "globals@npm:^11.1.0": version: 11.12.0 resolution: "globals@npm:11.12.0" @@ -4475,12 +5712,17 @@ __metadata: languageName: node linkType: hard -"globals@npm:^13.19.0": - version: 13.24.0 - resolution: "globals@npm:13.24.0" - dependencies: - type-fest: "npm:^0.20.2" - checksum: 10/62c5b1997d06674fc7191d3e01e324d3eda4d65ac9cc4e78329fa3b5c4fd42a0e1c8722822497a6964eee075255ce21ccf1eec2d83f92ef3f06653af4d0ee28e +"globals@npm:^14.0.0": + version: 14.0.0 + resolution: "globals@npm:14.0.0" + checksum: 10/03939c8af95c6df5014b137cac83aa909090c3a3985caef06ee9a5a669790877af8698ab38007e4c0186873adc14c0b13764acc754b16a754c216cc56aa5f021 + languageName: node + linkType: hard + +"globals@npm:^15.7.0, globals@npm:^15.9.0": + version: 15.9.0 + resolution: "globals@npm:15.9.0" + checksum: 10/19bca70131c5d3e0d4171deed0f8ae16adda19f18d39b67421056f1eaa160b4433c3ffc8eb69b8b19adebbbdad4834d8a0494c5fe1ae295f0f769a5c0331d794 languageName: node linkType: hard @@ -4494,7 +5736,7 @@ __metadata: languageName: node linkType: hard -"globby@npm:^11.0.4, globby@npm:^11.1.0": +"globby@npm:^11.1.0": version: 11.1.0 resolution: "globby@npm:11.1.0" dependencies: @@ -4517,32 +5759,6 @@ __metadata: languageName: node linkType: hard -"got@npm:^12.1.0": - version: 12.6.1 - resolution: "got@npm:12.6.1" - dependencies: - "@sindresorhus/is": "npm:^5.2.0" - "@szmarczak/http-timer": "npm:^5.0.1" - cacheable-lookup: "npm:^7.0.0" - cacheable-request: "npm:^10.2.8" - decompress-response: "npm:^6.0.0" - form-data-encoder: "npm:^2.1.2" - get-stream: "npm:^6.0.1" - http2-wrapper: "npm:^2.1.10" - lowercase-keys: "npm:^3.0.0" - p-cancelable: "npm:^3.0.0" - responselike: "npm:^3.0.0" - checksum: 10/6c22f1449f4574d79a38e0eba0b753ce2f9030d61838a1ae1e25d3ff5b0db7916aa21023ac369c67d39d17f87bba9283a0b0cb88590de77926c968630aacae75 - languageName: node - linkType: hard - -"graceful-fs@npm:4.2.10": - version: 4.2.10 - resolution: "graceful-fs@npm:4.2.10" - checksum: 10/0c83c52b62c68a944dcfb9d66b0f9f10f7d6e3d081e8067b9bfdc9e5f3a8896584d576036f82915773189eec1eba599397fc620e75c03c0610fb3d67c6713c1a - languageName: node - linkType: hard - "graceful-fs@npm:^4.2.6, graceful-fs@npm:^4.2.9": version: 4.2.11 resolution: "graceful-fs@npm:4.2.11" @@ -4617,20 +5833,6 @@ __metadata: languageName: node linkType: hard -"has-unicode@npm:^2.0.1": - version: 2.0.1 - resolution: "has-unicode@npm:2.0.1" - checksum: 10/041b4293ad6bf391e21c5d85ed03f412506d6623786b801c4ab39e4e6ca54993f13201bceb544d92963f9e0024e6e7fbf0cb1d84c9d6b31cb9c79c8c990d13d8 - languageName: node - linkType: hard - -"has-yarn@npm:^3.0.0": - version: 3.0.0 - resolution: "has-yarn@npm:3.0.0" - checksum: 10/b9e14e78e0a37bc070550c862b201534287bc10e62a86ec9c1f455ffb082db42817ce9aed914bd73f1d589bbf268520e194629ff2f62ff6b98a482c4bd2dcbfb - languageName: node - linkType: hard - "hasown@npm:^2.0.0, hasown@npm:^2.0.1, hasown@npm:^2.0.2": version: 2.0.2 resolution: "hasown@npm:2.0.2" @@ -4647,24 +5849,6 @@ __metadata: languageName: node linkType: hard -"hosted-git-info@npm:^5.1.0": - version: 5.2.1 - resolution: "hosted-git-info@npm:5.2.1" - dependencies: - lru-cache: "npm:^7.5.1" - checksum: 10/f0cb6527162b61a65ac350a4d11f55f16629278a19ca61bf421f272c22531b9a1bad34e874b980db6be512130f189c81d1eb9b481b60eeda293b6dc8d35d2aec - languageName: node - linkType: hard - -"hosted-git-info@npm:^6.0.0": - version: 6.1.1 - resolution: "hosted-git-info@npm:6.1.1" - dependencies: - lru-cache: "npm:^7.5.1" - checksum: 10/2e48e3fac799b52d82277ff5693916bfa33441a2c06d1f11f9e82886bd235514783c2bdffb3abde67b7aeb6af457a48df38e6894740c7fc2e1bb78f5bcfac61e - languageName: node - linkType: hard - "html-escaper@npm:^2.0.0": version: 2.0.2 resolution: "html-escaper@npm:2.0.2" @@ -4672,24 +5856,13 @@ __metadata: languageName: node linkType: hard -"http-cache-semantics@npm:^4.1.0, http-cache-semantics@npm:^4.1.1": +"http-cache-semantics@npm:^4.1.1": version: 4.1.1 resolution: "http-cache-semantics@npm:4.1.1" checksum: 10/362d5ed66b12ceb9c0a328fb31200b590ab1b02f4a254a697dc796850cc4385603e75f53ec59f768b2dad3bfa1464bd229f7de278d2899a0e3beffc634b6683f languageName: node linkType: hard -"http-proxy-agent@npm:^5.0.0": - version: 5.0.0 - resolution: "http-proxy-agent@npm:5.0.0" - dependencies: - "@tootallnate/once": "npm:2" - agent-base: "npm:6" - debug: "npm:4" - checksum: 10/5ee19423bc3e0fd5f23ce991b0755699ad2a46a440ce9cec99e8126bb98448ad3479d2c0ea54be5519db5b19a4ffaa69616bac01540db18506dd4dac3dc418f0 - languageName: node - linkType: hard - "http-proxy-agent@npm:^7.0.0": version: 7.0.2 resolution: "http-proxy-agent@npm:7.0.2" @@ -4700,26 +5873,6 @@ __metadata: languageName: node linkType: hard -"http2-wrapper@npm:^2.1.10": - version: 2.2.1 - resolution: "http2-wrapper@npm:2.2.1" - dependencies: - quick-lru: "npm:^5.1.1" - resolve-alpn: "npm:^1.2.0" - checksum: 10/e7a5ac6548318e83fc0399cd832cdff6bbf902b165d211cad47a56ee732922e0aa1107246dd884b12532a1c4649d27c4d44f2480911c65202e93c90bde8fa29d - languageName: node - linkType: hard - -"https-proxy-agent@npm:^5.0.0": - version: 5.0.1 - resolution: "https-proxy-agent@npm:5.0.1" - dependencies: - agent-base: "npm:6" - debug: "npm:4" - checksum: 10/f0dce7bdcac5e8eaa0be3c7368bb8836ed010fb5b6349ffb412b172a203efe8f807d9a6681319105ea1b6901e1972c7b5ea899672a7b9aad58309f766dcbe0df - languageName: node - linkType: hard - "https-proxy-agent@npm:^7.0.1": version: 7.0.4 resolution: "https-proxy-agent@npm:7.0.4" @@ -4737,15 +5890,6 @@ __metadata: languageName: node linkType: hard -"humanize-ms@npm:^1.2.1": - version: 1.2.1 - resolution: "humanize-ms@npm:1.2.1" - dependencies: - ms: "npm:^2.0.0" - checksum: 10/9c7a74a2827f9294c009266c82031030eae811ca87b0da3dceb8d6071b9bde22c9f3daef0469c3c533cc67a97d8a167cd9fc0389350e5f415f61a79b171ded16 - languageName: node - linkType: hard - "iconv-lite@npm:^0.6.2": version: 0.6.3 resolution: "iconv-lite@npm:0.6.3" @@ -4755,22 +5899,20 @@ __metadata: languageName: node linkType: hard -"ignore-walk@npm:^6.0.0": - version: 6.0.5 - resolution: "ignore-walk@npm:6.0.5" - dependencies: - minimatch: "npm:^9.0.0" - checksum: 10/08757abff4dabca4f9f005f9a6cb6684e0c460a1e08c50319460ac13002de0ba8bbde6ad1f4477fefb264135d6253d1268339c18292f82485fcce576af0539d9 - languageName: node - linkType: hard - -"ignore@npm:^5.2.0, ignore@npm:^5.2.4": +"ignore@npm:^5.2.0": version: 5.3.1 resolution: "ignore@npm:5.3.1" checksum: 10/0a884c2fbc8c316f0b9f92beaf84464253b73230a4d4d286697be45fca081199191ca33e1c2e82d9e5f851f5e9a48a78e25a35c951e7eb41e59f150db3530065 languageName: node linkType: hard +"ignore@npm:^5.3.1": + version: 5.3.2 + resolution: "ignore@npm:5.3.2" + checksum: 10/cceb6a457000f8f6a50e1196429750d782afce5680dd878aa4221bd79972d68b3a55b4b1458fc682be978f4d3c6a249046aa0880637367216444ab7b014cfc98 + languageName: node + linkType: hard + "import-fresh@npm:^3.2.1, import-fresh@npm:^3.3.0": version: 3.3.0 resolution: "import-fresh@npm:3.3.0" @@ -4781,13 +5923,6 @@ __metadata: languageName: node linkType: hard -"import-lazy@npm:^4.0.0": - version: 4.0.0 - resolution: "import-lazy@npm:4.0.0" - checksum: 10/943309cc8eb01ada12700448c288b0384f77a1bc33c7e00fa4cb223c665f467a13ce9aaceb8d2e4cf586b07c1d2828040263dcc069873ce63cfc2ac6fd087971 - languageName: node - linkType: hard - "import-local@npm:^3.0.2": version: 3.1.0 resolution: "import-local@npm:3.1.0" @@ -4821,13 +5956,6 @@ __metadata: languageName: node linkType: hard -"infer-owner@npm:^1.0.4": - version: 1.0.4 - resolution: "infer-owner@npm:1.0.4" - checksum: 10/181e732764e4a0611576466b4b87dac338972b839920b2a8cde43642e4ed6bd54dc1fb0b40874728f2a2df9a1b097b8ff83b56d5f8f8e3927f837fdcb47d8a89 - languageName: node - linkType: hard - "inflight@npm:^1.0.4": version: 1.0.6 resolution: "inflight@npm:1.0.6" @@ -4838,20 +5966,13 @@ __metadata: languageName: node linkType: hard -"inherits@npm:2, inherits@npm:^2.0.3": +"inherits@npm:2": version: 2.0.4 resolution: "inherits@npm:2.0.4" checksum: 10/cd45e923bee15186c07fa4c89db0aace24824c482fb887b528304694b2aa6ff8a898da8657046a5dcf3e46cd6db6c61629551f9215f208d7c3f157cf9b290521 languageName: node linkType: hard -"ini@npm:2.0.0": - version: 2.0.0 - resolution: "ini@npm:2.0.0" - checksum: 10/04e24ba05c4f6947e15560824e153b4610bceea2f5a3ab68651d221a4aab3c77d4e3e90a917ebc8bf5ad71a30a8575de56c39d6b4c4b1375a28016b9f3625f9d - languageName: node - linkType: hard - "ini@npm:4.1.1": version: 4.1.1 resolution: "ini@npm:4.1.1" @@ -4859,21 +5980,14 @@ __metadata: languageName: node linkType: hard -"ini@npm:^1.3.4, ini@npm:~1.3.0": - version: 1.3.8 - resolution: "ini@npm:1.3.8" - checksum: 10/314ae176e8d4deb3def56106da8002b462221c174ddb7ce0c49ee72c8cd1f9044f7b10cc555a7d8850982c3b9ca96fc212122749f5234bc2b6fb05fb942ed566 - languageName: node - linkType: hard - -"ini@npm:^4.1.1, ini@npm:^4.1.3": - version: 4.1.3 - resolution: "ini@npm:4.1.3" - checksum: 10/f536b414d1442e5b233429e2b56efcdb354109b2d65ddd489e5939d8f0f5ad23c88aa2b19c92987249d0dd63ba8192e9aeb1a02b0459549c5a9ff31acd729a5d +"ini@npm:^5.0.0": + version: 5.0.0 + resolution: "ini@npm:5.0.0" + checksum: 10/76e5567b46504b2b12650878ba6277204500a6ead3fe69eef419ee570456b364b39c040ee545846053f6d8a15797a82fc6d9efe06e392b9b6093935f4a2f2c30 languageName: node linkType: hard -"internal-slot@npm:^1.0.7": +"internal-slot@npm:^1.0.4, internal-slot@npm:^1.0.7": version: 1.0.7 resolution: "internal-slot@npm:1.0.7" dependencies: @@ -4894,7 +6008,17 @@ __metadata: languageName: node linkType: hard -"is-array-buffer@npm:^3.0.4": +"is-arguments@npm:^1.1.1": + version: 1.1.1 + resolution: "is-arguments@npm:1.1.1" + dependencies: + call-bind: "npm:^1.0.2" + has-tostringtag: "npm:^1.0.0" + checksum: 10/a170c7e26082e10de9be6e96d32ae3db4d5906194051b792e85fae3393b53cf2cb5b3557863e5c8ccbab55e2fd8f2f75aa643d437613f72052cf0356615c34be + languageName: node + linkType: hard + +"is-array-buffer@npm:^3.0.2, is-array-buffer@npm:^3.0.4": version: 3.0.4 resolution: "is-array-buffer@npm:3.0.4" dependencies: @@ -4911,6 +6035,15 @@ __metadata: languageName: node linkType: hard +"is-async-function@npm:^2.0.0": + version: 2.0.0 + resolution: "is-async-function@npm:2.0.0" + dependencies: + has-tostringtag: "npm:^1.0.0" + checksum: 10/2cf336fbf8cba3badcf526aa3d10384c30bab32615ac4831b74492eb4e843ccb7d8439a119c27f84bcf217d72024e611b1373f870f433b48f3fa57d3d1b863f1 + languageName: node + linkType: hard + "is-bigint@npm:^1.0.1": version: 1.0.4 resolution: "is-bigint@npm:1.0.4" @@ -4946,23 +6079,21 @@ __metadata: languageName: node linkType: hard -"is-ci@npm:^3.0.1": - version: 3.0.1 - resolution: "is-ci@npm:3.0.1" +"is-core-module@npm:^2.13.0": + version: 2.14.0 + resolution: "is-core-module@npm:2.14.0" dependencies: - ci-info: "npm:^3.2.0" - bin: - is-ci: bin.js - checksum: 10/192c66dc7826d58f803ecae624860dccf1899fc1f3ac5505284c0a5cf5f889046ffeb958fa651e5725d5705c5bcb14f055b79150ea5fcad7456a9569de60260e + hasown: "npm:^2.0.2" + checksum: 10/1e0d1a16cb3a94746f6a28db09ccab4562860c94c74bacedb3a6729736d61cfb97001d2052f9622637aa7ea8e0643a3f0f4f16965c70ba6ce30a8ccfe8074af8 languageName: node linkType: hard -"is-core-module@npm:^2.13.0, is-core-module@npm:^2.13.1, is-core-module@npm:^2.8.1": - version: 2.14.0 - resolution: "is-core-module@npm:2.14.0" +"is-core-module@npm:^2.15.1": + version: 2.15.1 + resolution: "is-core-module@npm:2.15.1" dependencies: hasown: "npm:^2.0.2" - checksum: 10/1e0d1a16cb3a94746f6a28db09ccab4562860c94c74bacedb3a6729736d61cfb97001d2052f9622637aa7ea8e0643a3f0f4f16965c70ba6ce30a8ccfe8074af8 + checksum: 10/77316d5891d5743854bcef2cd2f24c5458fb69fbc9705c12ca17d54a2017a67d0693bbf1ba8c77af376c0eef6bf6d1b27a4ab08e4db4e69914c3789bdf2ceec5 languageName: node linkType: hard @@ -4975,7 +6106,7 @@ __metadata: languageName: node linkType: hard -"is-date-object@npm:^1.0.1": +"is-date-object@npm:^1.0.1, is-date-object@npm:^1.0.5": version: 1.0.5 resolution: "is-date-object@npm:1.0.5" dependencies: @@ -4991,6 +6122,15 @@ __metadata: languageName: node linkType: hard +"is-finalizationregistry@npm:^1.0.2": + version: 1.0.2 + resolution: "is-finalizationregistry@npm:1.0.2" + dependencies: + call-bind: "npm:^1.0.2" + checksum: 10/1b8e9e1bf2075e862315ef9d38ce6d39c43ca9d81d46f73b34473506992f4b0fbaadb47ec9b420a5e76afe3f564d9f1f0d9b552ef272cc2395e0f21d743c9c29 + languageName: node + linkType: hard + "is-fullwidth-code-point@npm:^3.0.0": version: 3.0.0 resolution: "is-fullwidth-code-point@npm:3.0.0" @@ -5005,6 +6145,15 @@ __metadata: languageName: node linkType: hard +"is-generator-function@npm:^1.0.10": + version: 1.0.10 + resolution: "is-generator-function@npm:1.0.10" + dependencies: + has-tostringtag: "npm:^1.0.0" + checksum: 10/499a3ce6361064c3bd27fbff5c8000212d48506ebe1977842bbd7b3e708832d0deb1f4cc69186ece3640770e8c4f1287b24d99588a0b8058b2dbdd344bc1f47f + languageName: node + linkType: hard + "is-glob@npm:^4.0.0, is-glob@npm:^4.0.1, is-glob@npm:^4.0.3": version: 4.0.3 resolution: "is-glob@npm:4.0.3" @@ -5014,16 +6163,6 @@ __metadata: languageName: node linkType: hard -"is-installed-globally@npm:^0.4.0": - version: 0.4.0 - resolution: "is-installed-globally@npm:0.4.0" - dependencies: - global-dirs: "npm:^3.0.0" - is-path-inside: "npm:^3.0.2" - checksum: 10/5294d21c82cb9beedd693ce1dfb12117c4db36d6e35edc9dc6bf06cb300d23c96520d1bfb063386b054268ae3d7255c3f09393b52218cc26ace99b217bf37c93 - languageName: node - linkType: hard - "is-lambda@npm:^1.0.1": version: 1.0.1 resolution: "is-lambda@npm:1.0.1" @@ -5031,17 +6170,17 @@ __metadata: languageName: node linkType: hard -"is-negative-zero@npm:^2.0.3": +"is-map@npm:^2.0.2, is-map@npm:^2.0.3": version: 2.0.3 - resolution: "is-negative-zero@npm:2.0.3" - checksum: 10/8fe5cffd8d4fb2ec7b49d657e1691889778d037494c6f40f4d1a524cadd658b4b53ad7b6b73a59bcb4b143ae9a3d15829af864b2c0f9d65ac1e678c4c80f17e5 + resolution: "is-map@npm:2.0.3" + checksum: 10/8de7b41715b08bcb0e5edb0fb9384b80d2d5bcd10e142188f33247d19ff078abaf8e9b6f858e2302d8d05376a26a55cd23a3c9f8ab93292b02fcd2cc9e4e92bb languageName: node linkType: hard -"is-npm@npm:^6.0.0": - version: 6.0.0 - resolution: "is-npm@npm:6.0.0" - checksum: 10/fafe1ddc772345f5460514891bb8014376904ccdbddd59eee7525c9adcc08d426933f28b087bef3e17524da7ebf35c03ef484ff3b6ba9d5fecd8c6e6a7d4bf11 +"is-negative-zero@npm:^2.0.3": + version: 2.0.3 + resolution: "is-negative-zero@npm:2.0.3" + checksum: 10/8fe5cffd8d4fb2ec7b49d657e1691889778d037494c6f40f4d1a524cadd658b4b53ad7b6b73a59bcb4b143ae9a3d15829af864b2c0f9d65ac1e678c4c80f17e5 languageName: node linkType: hard @@ -5061,14 +6200,7 @@ __metadata: languageName: node linkType: hard -"is-obj@npm:^2.0.0": - version: 2.0.0 - resolution: "is-obj@npm:2.0.0" - checksum: 10/c9916ac8f4621962a42f5e80e7ffdb1d79a3fab7456ceaeea394cd9e0858d04f985a9ace45be44433bf605673c8be8810540fe4cc7f4266fc7526ced95af5a08 - languageName: node - linkType: hard - -"is-path-inside@npm:^3.0.2, is-path-inside@npm:^3.0.3": +"is-path-inside@npm:^3.0.3": version: 3.0.3 resolution: "is-path-inside@npm:3.0.3" checksum: 10/abd50f06186a052b349c15e55b182326f1936c89a78bf6c8f2b707412517c097ce04bc49a0ca221787bc44e1049f51f09a2ffb63d22899051988d3a618ba13e9 @@ -5085,6 +6217,13 @@ __metadata: languageName: node linkType: hard +"is-set@npm:^2.0.2, is-set@npm:^2.0.3": + version: 2.0.3 + resolution: "is-set@npm:2.0.3" + checksum: 10/5685df33f0a4a6098a98c72d94d67cad81b2bc72f1fb2091f3d9283c4a1c582123cd709145b02a9745f0ce6b41e3e43f1c944496d1d74d4ea43358be61308669 + languageName: node + linkType: hard + "is-shared-array-buffer@npm:^1.0.2, is-shared-array-buffer@npm:^1.0.3": version: 1.0.3 resolution: "is-shared-array-buffer@npm:1.0.3" @@ -5128,10 +6267,10 @@ __metadata: languageName: node linkType: hard -"is-typedarray@npm:^1.0.0": - version: 1.0.0 - resolution: "is-typedarray@npm:1.0.0" - checksum: 10/4b433bfb0f9026f079f4eb3fbaa4ed2de17c9995c3a0b5c800bec40799b4b2a8b4e051b1ada77749deb9ded4ae52fe2096973f3a93ff83df1a5a7184a669478c +"is-weakmap@npm:^2.0.2": + version: 2.0.2 + resolution: "is-weakmap@npm:2.0.2" + checksum: 10/a7b7e23206c542dcf2fa0abc483142731788771527e90e7e24f658c0833a0d91948a4f7b30d78f7a65255a48512e41a0288b778ba7fc396137515c12e201fd11 languageName: node linkType: hard @@ -5144,10 +6283,13 @@ __metadata: languageName: node linkType: hard -"is-yarn-global@npm:^0.4.0": - version: 0.4.1 - resolution: "is-yarn-global@npm:0.4.1" - checksum: 10/79ec4e6f581c53d4fefdf5f6c237f9a3ad8db29c85cdc4659e76ae345659317552052a97b7e56952aa5d94a23c798ebec8ccad72fb14d3b26dc647ddceddd716 +"is-weakset@npm:^2.0.3": + version: 2.0.3 + resolution: "is-weakset@npm:2.0.3" + dependencies: + call-bind: "npm:^1.0.7" + get-intrinsic: "npm:^1.2.4" + checksum: 10/40159582ff1b44fc40085f631baf19f56479b05af2faede65b4e6a0b6acab745c13fd070e35b475aafd8a1ee50879ba5a3f1265125b46bebdb446b6be1f62165 languageName: node linkType: hard @@ -5237,6 +6379,19 @@ __metadata: languageName: node linkType: hard +"iterator.prototype@npm:^1.1.2": + version: 1.1.2 + resolution: "iterator.prototype@npm:1.1.2" + dependencies: + define-properties: "npm:^1.2.1" + get-intrinsic: "npm:^1.2.1" + has-symbols: "npm:^1.0.3" + reflect.getprototypeof: "npm:^1.0.4" + set-function-name: "npm:^2.0.1" + checksum: 10/b5013967ad8f28c9ca1be8e159eb10f591b8e46deae87476fe39d668c04374fe9158c815e8b6d2f45885b0a3fd842a8ba13f497ec762b3a0eff49bec278670b1 + languageName: node + linkType: hard + "jackspeak@npm:^3.1.2": version: 3.4.0 resolution: "jackspeak@npm:3.4.0" @@ -5250,6 +6405,20 @@ __metadata: languageName: node linkType: hard +"jake@npm:^10.8.5": + version: 10.9.2 + resolution: "jake@npm:10.9.2" + dependencies: + async: "npm:^3.2.3" + chalk: "npm:^4.0.2" + filelist: "npm:^1.0.4" + minimatch: "npm:^3.1.2" + bin: + jake: bin/cli.js + checksum: 10/3be324708f99f031e0aec49ef8fd872eb4583cbe8a29a0c875f554f6ac638ee4ea5aa759bb63723fd54f77ca6d7db851eaa78353301734ed3700db9cb109a0cd + languageName: node + linkType: hard + "jest-changed-files@npm:^29.7.0": version: 29.7.0 resolution: "jest-changed-files@npm:29.7.0" @@ -5689,14 +6858,7 @@ __metadata: languageName: node linkType: hard -"jju@npm:^1.1.0": - version: 1.4.0 - resolution: "jju@npm:1.4.0" - checksum: 10/1067ff8ce02221faac5a842116ed0ec79a53312a111d0bf8342a80bd02c0a3fdf0b8449694a65947db0a3e8420e8b326dffb489c7dd5866efc380c0d1708a707 - languageName: node - linkType: hard - -"js-tokens@npm:^4.0.0": +"js-tokens@npm:^3.0.0 || ^4.0.0, js-tokens@npm:^4.0.0": version: 4.0.0 resolution: "js-tokens@npm:4.0.0" checksum: 10/af37d0d913fb56aec6dc0074c163cc71cd23c0b8aad5c2350747b6721d37ba118af35abdd8b33c47ec2800de07dedb16a527ca9c530ee004093e04958bd0cbf2 @@ -5774,22 +6936,6 @@ __metadata: languageName: node linkType: hard -"json-parse-even-better-errors@npm:^3.0.0": - version: 3.0.2 - resolution: "json-parse-even-better-errors@npm:3.0.2" - checksum: 10/6f04ea6c9ccb783630a59297959247e921cc90b917b8351197ca7fd058fccc7079268fd9362be21ba876fc26aa5039369dd0a2280aae49aae425784794a94927 - languageName: node - linkType: hard - -"json-parse-helpfulerror@npm:^1.0.3": - version: 1.0.3 - resolution: "json-parse-helpfulerror@npm:1.0.3" - dependencies: - jju: "npm:^1.1.0" - checksum: 10/2094424fa55eccbec2d756eb58228e72c04f0609379e70f31aca287710f058827efab5109919c9416d032bd81ae919b18b126e75619ee97fc6f26d6ac00d296f - languageName: node - linkType: hard - "json-schema-traverse@npm:^0.4.1": version: 0.4.1 resolution: "json-schema-traverse@npm:0.4.1" @@ -5815,7 +6961,7 @@ __metadata: languageName: node linkType: hard -"json5@npm:^2.2.2, json5@npm:^2.2.3": +"json5@npm:^2.2.3": version: 2.2.3 resolution: "json5@npm:2.2.3" bin: @@ -5836,21 +6982,19 @@ __metadata: languageName: node linkType: hard -"jsonlines@npm:^0.1.1": - version: 0.1.1 - resolution: "jsonlines@npm:0.1.1" - checksum: 10/ab4a41eca33e6e61fc9fb6ad472956b156eee37dee98baad266abfab85463e57cb2997a73dadac3e1ee1b208c8db076572cf08b86e0a69559249790ee47cab27 - languageName: node - linkType: hard - -"jsonparse@npm:^1.3.1": - version: 1.3.1 - resolution: "jsonparse@npm:1.3.1" - checksum: 10/24531e956f0f19d79e22c157cebd81b37af3486ae22f9bc1028f8c2a4d1b70df48b168ff86f8568d9c2248182de9b6da9f50f685d5e4b9d1d2d339d2a29d15bc +"jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.3.5": + version: 3.3.5 + resolution: "jsx-ast-utils@npm:3.3.5" + dependencies: + array-includes: "npm:^3.1.6" + array.prototype.flat: "npm:^1.3.1" + object.assign: "npm:^4.1.4" + object.values: "npm:^1.1.6" + checksum: 10/b61d44613687dfe4cc8ad4b4fbf3711bf26c60b8d5ed1f494d723e0808415c59b24a7c0ed8ab10736a40ff84eef38cbbfb68b395e05d31117b44ffc59d31edfc languageName: node linkType: hard -"keyv@npm:^4.5.3": +"keyv@npm:^4.5.4": version: 4.5.4 resolution: "keyv@npm:4.5.4" dependencies: @@ -5866,19 +7010,19 @@ __metadata: languageName: node linkType: hard -"kleur@npm:^4.0.1": - version: 4.1.5 - resolution: "kleur@npm:4.1.5" - checksum: 10/44d84cc4eedd4311099402ef6d4acd9b2d16e08e499d6ef3bb92389bd4692d7ef09e35248c26e27f98acac532122acb12a1bfee645994ae3af4f0a37996da7df +"language-subtag-registry@npm:^0.3.20": + version: 0.3.23 + resolution: "language-subtag-registry@npm:0.3.23" + checksum: 10/fe13ed74ab9f862db8e5747b98cc9aa08d52a19f85b5cdb4975cd364c8539bd2da3380e4560d2dbbd728ec33dff8a4b4421fcb2e5b1b1bdaa21d16f91a54d0d4 languageName: node linkType: hard -"latest-version@npm:^7.0.0": - version: 7.0.0 - resolution: "latest-version@npm:7.0.0" +"language-tags@npm:^1.0.9": + version: 1.0.9 + resolution: "language-tags@npm:1.0.9" dependencies: - package-json: "npm:^8.1.0" - checksum: 10/1f0deba00d5a34394cce4463c938811f51bbb539b131674f4bb2062c63f2cc3b80bccd56ecade3bd5932d04a34cf0a5a8a2ccc4ec9e5e6b285a9a7b3e27d0d66 + language-subtag-registry: "npm:^0.3.20" + checksum: 10/d3a7c14b694e67f519153d6df6cb200681648d38d623c3bfa9d6a66a5ec5493628acb88e9df5aceef3cf1902ab263a205e7d59ee4cf1d6bb67e707b83538bd6d languageName: node linkType: hard @@ -5924,7 +7068,14 @@ __metadata: languageName: node linkType: hard -"lodash.memoize@npm:4.x": +"lodash.debounce@npm:^4.0.8": + version: 4.0.8 + resolution: "lodash.debounce@npm:4.0.8" + checksum: 10/cd0b2819786e6e80cb9f5cda26b1a8fc073daaf04e48d4cb462fa4663ec9adb3a5387aa22d7129e48eed1afa05b482e2a6b79bfc99b86886364449500cbb00fd + languageName: node + linkType: hard + +"lodash.memoize@npm:^4.1.2": version: 4.1.2 resolution: "lodash.memoize@npm:4.1.2" checksum: 10/192b2168f310c86f303580b53acf81ab029761b9bd9caa9506a019ffea5f3363ea98d7e39e7e11e6b9917066c9d36a09a11f6fe16f812326390d8f3a54a1a6da @@ -5945,10 +7096,14 @@ __metadata: languageName: node linkType: hard -"lowercase-keys@npm:^3.0.0": - version: 3.0.0 - resolution: "lowercase-keys@npm:3.0.0" - checksum: 10/67a3f81409af969bc0c4ca0e76cd7d16adb1e25aa1c197229587eaf8671275c8c067cd421795dbca4c81be0098e4c426a086a05e30de8a9c587b7a13c0c7ccc5 +"loose-envify@npm:^1.4.0": + version: 1.4.0 + resolution: "loose-envify@npm:1.4.0" + dependencies: + js-tokens: "npm:^3.0.0 || ^4.0.0" + bin: + loose-envify: cli.js + checksum: 10/6517e24e0cad87ec9888f500c5b5947032cdfe6ef65e1c1936a0c48a524b81e65542c9c3edc91c97d5bddc806ee2a985dbc79be89215d613b1de5db6d1cfe6f4 languageName: node linkType: hard @@ -5968,10 +7123,12 @@ __metadata: languageName: node linkType: hard -"lru-cache@npm:^7.4.4, lru-cache@npm:^7.5.1, lru-cache@npm:^7.7.1": - version: 7.18.3 - resolution: "lru-cache@npm:7.18.3" - checksum: 10/6029ca5aba3aacb554e919d7ef804fffd4adfc4c83db00fac8248c7c78811fb6d4b6f70f7fd9d55032b3823446546a007edaa66ad1f2377ae833bd983fac5d98 +"lru-cache@npm:^6.0.0": + version: 6.0.0 + resolution: "lru-cache@npm:6.0.0" + dependencies: + yallist: "npm:^4.0.0" + checksum: 10/fc1fe2ee205f7c8855fa0f34c1ab0bcf14b6229e35579ec1fd1079f31d6fc8ef8eb6fd17f2f4d99788d7e339f50e047555551ebd5e434dda503696e7c6591825 languageName: node linkType: hard @@ -5984,60 +7141,13 @@ __metadata: languageName: node linkType: hard -"make-error@npm:1.x": +"make-error@npm:^1.3.6": version: 1.3.6 resolution: "make-error@npm:1.3.6" checksum: 10/b86e5e0e25f7f777b77fabd8e2cbf15737972869d852a22b7e73c17623928fccb826d8e46b9951501d3f20e51ad74ba8c59ed584f610526a48f8ccf88aaec402 languageName: node linkType: hard -"make-fetch-happen@npm:^10.0.3": - version: 10.2.1 - resolution: "make-fetch-happen@npm:10.2.1" - dependencies: - agentkeepalive: "npm:^4.2.1" - cacache: "npm:^16.1.0" - http-cache-semantics: "npm:^4.1.0" - http-proxy-agent: "npm:^5.0.0" - https-proxy-agent: "npm:^5.0.0" - is-lambda: "npm:^1.0.1" - lru-cache: "npm:^7.7.1" - minipass: "npm:^3.1.6" - minipass-collect: "npm:^1.0.2" - minipass-fetch: "npm:^2.0.3" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^0.6.3" - promise-retry: "npm:^2.0.1" - socks-proxy-agent: "npm:^7.0.0" - ssri: "npm:^9.0.0" - checksum: 10/fef5acb865a46f25ad0b5ad7d979799125db5dbb24ea811ffa850fbb804bc8e495df2237a8ec3a4fc6250e73c2f95549cca6d6d36a73b1faa61224504eb1188f - languageName: node - linkType: hard - -"make-fetch-happen@npm:^11.0.0, make-fetch-happen@npm:^11.0.1, make-fetch-happen@npm:^11.1.1": - version: 11.1.1 - resolution: "make-fetch-happen@npm:11.1.1" - dependencies: - agentkeepalive: "npm:^4.2.1" - cacache: "npm:^17.0.0" - http-cache-semantics: "npm:^4.1.1" - http-proxy-agent: "npm:^5.0.0" - https-proxy-agent: "npm:^5.0.0" - is-lambda: "npm:^1.0.1" - lru-cache: "npm:^7.7.1" - minipass: "npm:^5.0.0" - minipass-fetch: "npm:^3.0.0" - minipass-flush: "npm:^1.0.5" - minipass-pipeline: "npm:^1.2.4" - negotiator: "npm:^0.6.3" - promise-retry: "npm:^2.0.1" - socks-proxy-agent: "npm:^7.0.0" - ssri: "npm:^10.0.0" - checksum: 10/b4b442cfaaec81db159f752a5f2e3ee3d7aa682782868fa399200824ec6298502e01bdc456e443dc219bcd5546c8e4471644d54109c8599841dc961d17a805fa - languageName: node - linkType: hard - "make-fetch-happen@npm:^13.0.0": version: 13.0.1 resolution: "make-fetch-happen@npm:13.0.1" @@ -6081,7 +7191,7 @@ __metadata: languageName: node linkType: hard -"micromatch@npm:^4.0.4, micromatch@npm:^4.0.7": +"micromatch@npm:^4.0.4": version: 4.0.7 resolution: "micromatch@npm:4.0.7" dependencies: @@ -6091,6 +7201,16 @@ __metadata: languageName: node linkType: hard +"micromatch@npm:^4.0.8": + version: 4.0.8 + resolution: "micromatch@npm:4.0.8" + dependencies: + braces: "npm:^3.0.3" + picomatch: "npm:^2.3.1" + checksum: 10/6bf2a01672e7965eb9941d1f02044fad2bd12486b5553dc1116ff24c09a8723157601dc992e74c911d896175918448762df3b3fd0a6b61037dd1a9766ddfbf58 + languageName: node + linkType: hard + "mimic-fn@npm:^2.1.0": version: 2.1.0 resolution: "mimic-fn@npm:2.1.0" @@ -6098,20 +7218,6 @@ __metadata: languageName: node linkType: hard -"mimic-response@npm:^3.1.0": - version: 3.1.0 - resolution: "mimic-response@npm:3.1.0" - checksum: 10/7e719047612411fe071332a7498cf0448bbe43c485c0d780046c76633a771b223ff49bd00267be122cedebb897037fdb527df72335d0d0f74724604ca70b37ad - languageName: node - linkType: hard - -"mimic-response@npm:^4.0.0": - version: 4.0.0 - resolution: "mimic-response@npm:4.0.0" - checksum: 10/33b804cc961efe206efdb1fca6a22540decdcfce6c14eb5c0c50e5ae9022267ab22ce8f5568b1f7247ba67500fe20d523d81e0e9f009b321ccd9d472e78d1850 - languageName: node - linkType: hard - "min-indent@npm:^1.0.0": version: 1.0.1 resolution: "min-indent@npm:1.0.1" @@ -6119,16 +7225,7 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:9.0.3": - version: 9.0.3 - resolution: "minimatch@npm:9.0.3" - dependencies: - brace-expansion: "npm:^2.0.1" - checksum: 10/c81b47d28153e77521877649f4bab48348d10938df9e8147a58111fe00ef89559a2938de9f6632910c4f7bf7bb5cd81191a546167e58d357f0cfb1e18cecc1c5 - languageName: node - linkType: hard - -"minimatch@npm:^3.0.4, minimatch@npm:^3.0.5, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": +"minimatch@npm:^3.0.4, minimatch@npm:^3.1.1, minimatch@npm:^3.1.2": version: 3.1.2 resolution: "minimatch@npm:3.1.2" dependencies: @@ -6146,7 +7243,16 @@ __metadata: languageName: node linkType: hard -"minimatch@npm:^9.0.0, minimatch@npm:^9.0.3, minimatch@npm:^9.0.4": +"minimatch@npm:^9.0.3": + version: 9.0.5 + resolution: "minimatch@npm:9.0.5" + dependencies: + brace-expansion: "npm:^2.0.1" + checksum: 10/dd6a8927b063aca6d910b119e1f2df6d2ce7d36eab91de83167dd136bb85e1ebff97b0d3de1cb08bd1f7e018ca170b4962479fefab5b2a69e2ae12cb2edc8348 + languageName: node + linkType: hard + +"minimatch@npm:^9.0.4": version: 9.0.4 resolution: "minimatch@npm:9.0.4" dependencies: @@ -6162,15 +7268,6 @@ __metadata: languageName: node linkType: hard -"minipass-collect@npm:^1.0.2": - version: 1.0.2 - resolution: "minipass-collect@npm:1.0.2" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/14df761028f3e47293aee72888f2657695ec66bd7d09cae7ad558da30415fdc4752bbfee66287dcc6fd5e6a2fa3466d6c484dc1cbd986525d9393b9523d97f10 - languageName: node - linkType: hard - "minipass-collect@npm:^2.0.1": version: 2.0.1 resolution: "minipass-collect@npm:2.0.1" @@ -6180,21 +7277,6 @@ __metadata: languageName: node linkType: hard -"minipass-fetch@npm:^2.0.3": - version: 2.1.2 - resolution: "minipass-fetch@npm:2.1.2" - dependencies: - encoding: "npm:^0.1.13" - minipass: "npm:^3.1.6" - minipass-sized: "npm:^1.0.3" - minizlib: "npm:^2.1.2" - dependenciesMeta: - encoding: - optional: true - checksum: 10/8cfc589563ae2a11eebbf79121ef9a526fd078fca949ed3f1e4a51472ca4a4aad89fcea1738982ce9d7d833116ecc9c6ae9ebbd844832a94e3f4a3d4d1b9d3b9 - languageName: node - linkType: hard - "minipass-fetch@npm:^3.0.0": version: 3.0.5 resolution: "minipass-fetch@npm:3.0.5" @@ -6210,22 +7292,12 @@ __metadata: languageName: node linkType: hard -"minipass-flush@npm:^1.0.5": - version: 1.0.5 - resolution: "minipass-flush@npm:1.0.5" - dependencies: - minipass: "npm:^3.0.0" - checksum: 10/56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf - languageName: node - linkType: hard - -"minipass-json-stream@npm:^1.0.1": - version: 1.0.1 - resolution: "minipass-json-stream@npm:1.0.1" +"minipass-flush@npm:^1.0.5": + version: 1.0.5 + resolution: "minipass-flush@npm:1.0.5" dependencies: - jsonparse: "npm:^1.3.1" minipass: "npm:^3.0.0" - checksum: 10/3c65482c630b063c3fa86c853f324a50d9484f2eb6c3034f9c86c0b22f44181668848088f2c869cc764f8a9b8adc8f617f93762cd9d11521f563b8a71c5b815d + checksum: 10/56269a0b22bad756a08a94b1ffc36b7c9c5de0735a4dd1ab2b06c066d795cfd1f0ac44a0fcae13eece5589b908ecddc867f04c745c7009be0b566421ea0944cf languageName: node linkType: hard @@ -6247,7 +7319,7 @@ __metadata: languageName: node linkType: hard -"minipass@npm:^3.0.0, minipass@npm:^3.1.1, minipass@npm:^3.1.6": +"minipass@npm:^3.0.0": version: 3.3.6 resolution: "minipass@npm:3.3.6" dependencies: @@ -6280,7 +7352,7 @@ __metadata: languageName: node linkType: hard -"mkdirp@npm:^1.0.3, mkdirp@npm:^1.0.4": +"mkdirp@npm:^1.0.3": version: 1.0.4 resolution: "mkdirp@npm:1.0.4" bin: @@ -6296,7 +7368,7 @@ __metadata: languageName: node linkType: hard -"ms@npm:^2.0.0, ms@npm:^2.1.1": +"ms@npm:^2.1.1": version: 2.1.3 resolution: "ms@npm:2.1.3" checksum: 10/aa92de608021b242401676e35cfa5aa42dd70cbdc082b916da7fb925c542173e36bce97ea3e804923fe92c0ad991434e4a38327e15a1b5b5f945d66df615ae6d @@ -6317,15 +7389,6 @@ __metadata: languageName: node linkType: hard -"node-cache@npm:^5.1.2": - version: 5.1.2 - resolution: "node-cache@npm:5.1.2" - dependencies: - clone: "npm:2.x" - checksum: 10/6ac71a9e65fdd8940883c3c188de4888ff592f5bf52e4d42436c49e2a575d635e7327acea490c49fa7c01d5fa81f7b6e060fd35cf6f6ec401fbd5f77a3ebeecf - languageName: node - linkType: hard - "node-cron@npm:^3.0.3": version: 3.0.3 resolution: "node-cron@npm:3.0.3" @@ -6335,27 +7398,6 @@ __metadata: languageName: node linkType: hard -"node-gyp@npm:^9.0.0": - version: 9.4.1 - resolution: "node-gyp@npm:9.4.1" - dependencies: - env-paths: "npm:^2.2.0" - exponential-backoff: "npm:^3.1.1" - glob: "npm:^7.1.4" - graceful-fs: "npm:^4.2.6" - make-fetch-happen: "npm:^10.0.3" - nopt: "npm:^6.0.0" - npmlog: "npm:^6.0.0" - rimraf: "npm:^3.0.2" - semver: "npm:^7.3.5" - tar: "npm:^6.1.2" - which: "npm:^2.0.2" - bin: - node-gyp: bin/node-gyp.js - checksum: 10/329b109b138e48cb0416a6bca56e171b0e479d6360a548b80f06eced4bef3cf37652a3d20d171c20023fb18d996bd7446a49d4297ddb59fc48100178a92f432d - languageName: node - linkType: hard - "node-gyp@npm:latest": version: 10.1.0 resolution: "node-gyp@npm:10.1.0" @@ -6390,14 +7432,10 @@ __metadata: languageName: node linkType: hard -"nopt@npm:^6.0.0": - version: 6.0.0 - resolution: "nopt@npm:6.0.0" - dependencies: - abbrev: "npm:^1.0.0" - bin: - nopt: bin/nopt.js - checksum: 10/3c1128e07cd0241ae66d6e6a472170baa9f3e84dd4203950ba8df5bafac4efa2166ce917a57ef02b01ba7c40d18b2cc64b29b225fd3640791fe07b24f0b33a32 +"node-releases@npm:^2.0.18": + version: 2.0.18 + resolution: "node-releases@npm:2.0.18" + checksum: 10/241e5fa9556f1c12bafb83c6c3e94f8cf3d8f2f8f904906ecef6e10bcaa1d59aa61212d4651bec70052015fc54bd3fdcdbe7fc0f638a17e6685aa586c076ec4e languageName: node linkType: hard @@ -6424,18 +7462,6 @@ __metadata: languageName: node linkType: hard -"normalize-package-data@npm:^5.0.0": - version: 5.0.0 - resolution: "normalize-package-data@npm:5.0.0" - dependencies: - hosted-git-info: "npm:^6.0.0" - is-core-module: "npm:^2.8.1" - semver: "npm:^7.3.5" - validate-npm-package-license: "npm:^3.0.4" - checksum: 10/477344ee99c6c81afbc4359f9dc7a3a219cc29a37fe0220a4595bbdb7e1e5fa9e3c195e99900228b72d8676edf99eb99fd3b66aa94b4b8ab74d516f2ff60e510 - languageName: node - linkType: hard - "normalize-path@npm:^3.0.0": version: 3.0.0 resolution: "normalize-path@npm:3.0.0" @@ -6443,130 +7469,6 @@ __metadata: languageName: node linkType: hard -"normalize-url@npm:^8.0.0": - version: 8.0.1 - resolution: "normalize-url@npm:8.0.1" - checksum: 10/ae392037584fc5935b663ae4af475351930a1fc39e107956cfac44f42d5127eec2d77d9b7b12ded4696ca78103bafac5b6206a0ea8673c7bffecbe13544fcc5a - languageName: node - linkType: hard - -"npm-bundled@npm:^3.0.0": - version: 3.0.1 - resolution: "npm-bundled@npm:3.0.1" - dependencies: - npm-normalize-package-bin: "npm:^3.0.0" - checksum: 10/113c9a35526d9a563694e9bda401dbda592f664fa146d365028bef1e3bfdc2a7b60ac9315a727529ef7e8e8d80b8d9e217742ccc2808e0db99c2204a3e33a465 - languageName: node - linkType: hard - -"npm-check-updates@npm:^16.14.20": - version: 16.14.20 - resolution: "npm-check-updates@npm:16.14.20" - dependencies: - "@types/semver-utils": "npm:^1.1.1" - chalk: "npm:^5.3.0" - cli-table3: "npm:^0.6.3" - commander: "npm:^10.0.1" - fast-memoize: "npm:^2.5.2" - find-up: "npm:5.0.0" - fp-and-or: "npm:^0.1.4" - get-stdin: "npm:^8.0.0" - globby: "npm:^11.0.4" - hosted-git-info: "npm:^5.1.0" - ini: "npm:^4.1.1" - js-yaml: "npm:^4.1.0" - json-parse-helpfulerror: "npm:^1.0.3" - jsonlines: "npm:^0.1.1" - lodash: "npm:^4.17.21" - make-fetch-happen: "npm:^11.1.1" - minimatch: "npm:^9.0.3" - p-map: "npm:^4.0.0" - pacote: "npm:15.2.0" - parse-github-url: "npm:^1.0.2" - progress: "npm:^2.0.3" - prompts-ncu: "npm:^3.0.0" - rc-config-loader: "npm:^4.1.3" - remote-git-tags: "npm:^3.0.0" - rimraf: "npm:^5.0.5" - semver: "npm:^7.5.4" - semver-utils: "npm:^1.1.4" - source-map-support: "npm:^0.5.21" - spawn-please: "npm:^2.0.2" - strip-ansi: "npm:^7.1.0" - strip-json-comments: "npm:^5.0.1" - untildify: "npm:^4.0.0" - update-notifier: "npm:^6.0.2" - bin: - ncu: build/src/bin/cli.js - npm-check-updates: build/src/bin/cli.js - checksum: 10/ef865311c002f75c1dd2e1df7da092bf0f7c7d7d9d3f2426e26b512c50d5a50cef5bfacce5b731d9fc080120952d3ea0ee8a6165c77196a89f1bf7f4c0250434 - languageName: node - linkType: hard - -"npm-install-checks@npm:^6.0.0": - version: 6.3.0 - resolution: "npm-install-checks@npm:6.3.0" - dependencies: - semver: "npm:^7.1.1" - checksum: 10/6c20dadb878a0d2f1f777405217b6b63af1299d0b43e556af9363ee6eefaa98a17dfb7b612a473a473e96faf7e789c58b221e0d8ffdc1d34903c4f71618df3b4 - languageName: node - linkType: hard - -"npm-normalize-package-bin@npm:^3.0.0": - version: 3.0.1 - resolution: "npm-normalize-package-bin@npm:3.0.1" - checksum: 10/de416d720ab22137a36292ff8a333af499ea0933ef2320a8c6f56a73b0f0448227fec4db5c890d702e26d21d04f271415eab6580b5546456861cc0c19498a4bf - languageName: node - linkType: hard - -"npm-package-arg@npm:^10.0.0": - version: 10.1.0 - resolution: "npm-package-arg@npm:10.1.0" - dependencies: - hosted-git-info: "npm:^6.0.0" - proc-log: "npm:^3.0.0" - semver: "npm:^7.3.5" - validate-npm-package-name: "npm:^5.0.0" - checksum: 10/3bbb5f081099f73e852b4d3a3a10f78d495bdf21e050ca5c78dc134921c99ec856d1555ff6ba9c1c15b7475ad976ce803ef53fdda34abec622fe8f5d76421319 - languageName: node - linkType: hard - -"npm-packlist@npm:^7.0.0": - version: 7.0.4 - resolution: "npm-packlist@npm:7.0.4" - dependencies: - ignore-walk: "npm:^6.0.0" - checksum: 10/b24644eefa21d33c55a8f49c64eda4b06edfb7d25853be8ded7346e73c6c447be8a0482314b74f04f94e3f5712e467505dc030826ba55a71d1b948459fad6486 - languageName: node - linkType: hard - -"npm-pick-manifest@npm:^8.0.0": - version: 8.0.2 - resolution: "npm-pick-manifest@npm:8.0.2" - dependencies: - npm-install-checks: "npm:^6.0.0" - npm-normalize-package-bin: "npm:^3.0.0" - npm-package-arg: "npm:^10.0.0" - semver: "npm:^7.3.5" - checksum: 10/3f10a34e12cbb576edb694562a32730c6c0244b2929b91202d1be62ece76bc8b282dc7e9535d313d598963f8e3d06d19973611418a191fe3102be149a8fa0910 - languageName: node - linkType: hard - -"npm-registry-fetch@npm:^14.0.0": - version: 14.0.5 - resolution: "npm-registry-fetch@npm:14.0.5" - dependencies: - make-fetch-happen: "npm:^11.0.0" - minipass: "npm:^5.0.0" - minipass-fetch: "npm:^3.0.0" - minipass-json-stream: "npm:^1.0.1" - minizlib: "npm:^2.1.2" - npm-package-arg: "npm:^10.0.0" - proc-log: "npm:^3.0.0" - checksum: 10/63026b22d6a6afe5cb3a02dca96db783b88d3acc68be94f3485f25a5e4932800fdeff08145a77b35b8f61987033346462d4b3e710c0729a9735357ff97596062 - languageName: node - linkType: hard - "npm-run-path@npm:^4.0.1": version: 4.0.1 resolution: "npm-run-path@npm:4.0.1" @@ -6576,15 +7478,10 @@ __metadata: languageName: node linkType: hard -"npmlog@npm:^6.0.0": - version: 6.0.2 - resolution: "npmlog@npm:6.0.2" - dependencies: - are-we-there-yet: "npm:^3.0.0" - console-control-strings: "npm:^1.1.0" - gauge: "npm:^4.0.3" - set-blocking: "npm:^2.0.0" - checksum: 10/82b123677e62deb9e7472e27b92386c09e6e254ee6c8bcd720b3011013e4168bc7088e984f4fbd53cb6e12f8b4690e23e4fa6132689313e0d0dc4feea45489bb +"object-assign@npm:^4.1.1": + version: 4.1.1 + resolution: "object-assign@npm:4.1.1" + checksum: 10/fcc6e4ea8c7fe48abfbb552578b1c53e0d194086e2e6bbbf59e0a536381a292f39943c6e9628af05b5528aa5e3318bb30d6b2e53cadaf5b8fe9e12c4b69af23f languageName: node linkType: hard @@ -6595,6 +7492,16 @@ __metadata: languageName: node linkType: hard +"object-is@npm:^1.1.5": + version: 1.1.6 + resolution: "object-is@npm:1.1.6" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + checksum: 10/4f6f544773a595da21c69a7531e0e1d6250670f4e09c55f47eb02c516035cfcb1b46ceb744edfd3ecb362309dbccb6d7f88e43bf42e4d4595ac10a329061053a + languageName: node + linkType: hard + "object-keys@npm:^1.1.1": version: 1.1.1 resolution: "object-keys@npm:1.1.1" @@ -6602,7 +7509,7 @@ __metadata: languageName: node linkType: hard -"object.assign@npm:^4.1.5": +"object.assign@npm:^4.1.4, object.assign@npm:^4.1.5": version: 4.1.5 resolution: "object.assign@npm:4.1.5" dependencies: @@ -6614,7 +7521,18 @@ __metadata: languageName: node linkType: hard -"object.fromentries@npm:^2.0.7": +"object.entries@npm:^1.1.8": + version: 1.1.8 + resolution: "object.entries@npm:1.1.8" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-object-atoms: "npm:^1.0.0" + checksum: 10/2301918fbd1ee697cf6ff7cd94f060c738c0a7d92b22fd24c7c250e9b593642c9707ad2c44d339303c1439c5967d8964251cdfc855f7f6ec55db2dd79e8dc2a7 + languageName: node + linkType: hard + +"object.fromentries@npm:^2.0.8": version: 2.0.8 resolution: "object.fromentries@npm:2.0.8" dependencies: @@ -6626,7 +7544,7 @@ __metadata: languageName: node linkType: hard -"object.groupby@npm:^1.0.1": +"object.groupby@npm:^1.0.3": version: 1.0.3 resolution: "object.groupby@npm:1.0.3" dependencies: @@ -6637,7 +7555,7 @@ __metadata: languageName: node linkType: hard -"object.values@npm:^1.1.7": +"object.values@npm:^1.1.6, object.values@npm:^1.2.0": version: 1.2.0 resolution: "object.values@npm:1.2.0" dependencies: @@ -6680,13 +7598,6 @@ __metadata: languageName: node linkType: hard -"p-cancelable@npm:^3.0.0": - version: 3.0.0 - resolution: "p-cancelable@npm:3.0.0" - checksum: 10/a5eab7cf5ac5de83222a014eccdbfde65ecfb22005ee9bc242041f0b4441e07fac7629432c82f48868aa0f8413fe0df6c6067c16f76bf9217cd8dc651923c93d - languageName: node - linkType: hard - "p-limit@npm:^2.2.0": version: 2.3.0 resolution: "p-limit@npm:2.3.0" @@ -6746,46 +7657,6 @@ __metadata: languageName: node linkType: hard -"package-json@npm:^8.1.0": - version: 8.1.1 - resolution: "package-json@npm:8.1.1" - dependencies: - got: "npm:^12.1.0" - registry-auth-token: "npm:^5.0.1" - registry-url: "npm:^6.0.0" - semver: "npm:^7.3.7" - checksum: 10/d97ce9539e1ed4aacaf7c2cb754f16afc10937fa250bd09b4d61181d2e36a30cf8a4cff2f8f831f0826b0ac01a355f26204c7e57ca0e450da6ccec3e34fc889a - languageName: node - linkType: hard - -"pacote@npm:15.2.0": - version: 15.2.0 - resolution: "pacote@npm:15.2.0" - dependencies: - "@npmcli/git": "npm:^4.0.0" - "@npmcli/installed-package-contents": "npm:^2.0.1" - "@npmcli/promise-spawn": "npm:^6.0.1" - "@npmcli/run-script": "npm:^6.0.0" - cacache: "npm:^17.0.0" - fs-minipass: "npm:^3.0.0" - minipass: "npm:^5.0.0" - npm-package-arg: "npm:^10.0.0" - npm-packlist: "npm:^7.0.0" - npm-pick-manifest: "npm:^8.0.0" - npm-registry-fetch: "npm:^14.0.0" - proc-log: "npm:^3.0.0" - promise-retry: "npm:^2.0.1" - read-package-json: "npm:^6.0.0" - read-package-json-fast: "npm:^3.0.0" - sigstore: "npm:^1.3.0" - ssri: "npm:^10.0.0" - tar: "npm:^6.1.11" - bin: - pacote: lib/bin.js - checksum: 10/57e18f4f963abb5f67f794158a55c01ad23f76e56dcdc74e6b843dfdda017515b0e8c0f56e60e842cd5af5ab9b351afdc49fc70633994f0e5fc0c6c9f4bcaebc - languageName: node - linkType: hard - "parent-module@npm:^1.0.0": version: 1.0.1 resolution: "parent-module@npm:1.0.1" @@ -6804,15 +7675,6 @@ __metadata: languageName: node linkType: hard -"parse-github-url@npm:^1.0.2": - version: 1.0.2 - resolution: "parse-github-url@npm:1.0.2" - bin: - parse-github-url: ./cli.js - checksum: 10/cb645408cb193f60c9b3be329fb253208aca51709173f2e4f78ba5f4b913d30a9bfa1d910d9544e97ead7e63117b52859ca6ea87f1c505a791647e03366bb0d6 - languageName: node - linkType: hard - "parse-json@npm:^5.0.0, parse-json@npm:^5.2.0": version: 5.2.0 resolution: "parse-json@npm:5.2.0" @@ -6930,12 +7792,12 @@ __metadata: languageName: node linkType: hard -"prettier@npm:^3.3.2": - version: 3.3.2 - resolution: "prettier@npm:3.3.2" +"prettier@npm:^3.3.3": + version: 3.3.3 + resolution: "prettier@npm:3.3.3" bin: prettier: bin/prettier.cjs - checksum: 10/83214e154afa5aa9b664c2506640212323eb1376b13379b2413dc351b7de0687629dca3f00ff2ec895ebd7e3a2adb7d7e231b6c77606e2358137f2150807405b + checksum: 10/5beac1f30b5b40162532b8e2f7c3a4eb650910a2695e9c8512a62ffdc09dae93190c29db9107fa7f26d1b6c71aad3628ecb9b5de1ecb0911191099be109434d7 languageName: node linkType: hard @@ -6964,30 +7826,6 @@ __metadata: languageName: node linkType: hard -"progress@npm:^2.0.3": - version: 2.0.3 - resolution: "progress@npm:2.0.3" - checksum: 10/e6f0bcb71f716eee9dfac0fe8a2606e3704d6a64dd93baaf49fbadbc8499989a610fe14cf1bc6f61b6d6653c49408d94f4a94e124538084efd8e4cf525e0293d - languageName: node - linkType: hard - -"prom-client@npm:^15.1.2": - version: 15.1.2 - resolution: "prom-client@npm:15.1.2" - dependencies: - "@opentelemetry/api": "npm:^1.4.0" - tdigest: "npm:^0.1.1" - checksum: 10/f7edcba54d27eff4066ae7ebfe5692e6bb1914cf728efa89f7ab63766fef62679782c41c97d55b6fd6b2a8bb35b0d168ac8f1b9513c9a5770ea35c170691e24c - languageName: node - linkType: hard - -"promise-inflight@npm:^1.0.1": - version: 1.0.1 - resolution: "promise-inflight@npm:1.0.1" - checksum: 10/1560d413ea20c5a74f3631d39ba8cbd1972b9228072a755d01e1f5ca5110382d9af76a1582d889445adc6e75bb5ac4886b56dc4b6eae51b30145d7bb1ac7505b - languageName: node - linkType: hard - "promise-retry@npm:^2.0.1": version: 2.0.1 resolution: "promise-retry@npm:2.0.1" @@ -6998,16 +7836,6 @@ __metadata: languageName: node linkType: hard -"prompts-ncu@npm:^3.0.0": - version: 3.0.0 - resolution: "prompts-ncu@npm:3.0.0" - dependencies: - kleur: "npm:^4.0.1" - sisteransi: "npm:^1.0.5" - checksum: 10/f2a3bcb494daab7d35808b5f9fbeb5af1c50fbcd58ebd3f64cf2d08e4e88396886266886240c86fea67d0467527511cd0db671ef43c60ddecae76d0e9a49d939 - languageName: node - linkType: hard - "prompts@npm:^2.0.1": version: 2.4.2 resolution: "prompts@npm:2.4.2" @@ -7018,10 +7846,14 @@ __metadata: languageName: node linkType: hard -"proto-list@npm:~1.2.1": - version: 1.2.4 - resolution: "proto-list@npm:1.2.4" - checksum: 10/9cc3b46d613fa0d637033b225db1bc98e914c3c05864f7adc9bee728192e353125ef2e49f71129a413f6333951756000b0e54f299d921f02d3e9e370cc994100 +"prop-types@npm:^15.8.1": + version: 15.8.1 + resolution: "prop-types@npm:15.8.1" + dependencies: + loose-envify: "npm:^1.4.0" + object-assign: "npm:^4.1.1" + react-is: "npm:^16.13.1" + checksum: 10/7d959caec002bc964c86cdc461ec93108b27337dabe6192fb97d69e16a0c799a03462713868b40749bfc1caf5f57ef80ac3e4ffad3effa636ee667582a75e2c0 languageName: node linkType: hard @@ -7032,15 +7864,6 @@ __metadata: languageName: node linkType: hard -"pupa@npm:^3.1.0": - version: 3.1.0 - resolution: "pupa@npm:3.1.0" - dependencies: - escape-goat: "npm:^4.0.0" - checksum: 10/32784254b76e455e92169ab88339cf3df8b5d63e52b7e6d0568f065e53946659d4c30e4b75de435c37033b7902bd1c785f142be4afb8aa984a86cf2d7e9a8421 - languageName: node - linkType: hard - "pure-rand@npm:^6.0.0": version: 6.1.0 resolution: "pure-rand@npm:6.1.0" @@ -7055,36 +7878,10 @@ __metadata: languageName: node linkType: hard -"quick-lru@npm:^5.1.1": - version: 5.1.1 - resolution: "quick-lru@npm:5.1.1" - checksum: 10/a516faa25574be7947969883e6068dbe4aa19e8ef8e8e0fd96cddd6d36485e9106d85c0041a27153286b0770b381328f4072aa40d3b18a19f5f7d2b78b94b5ed - languageName: node - linkType: hard - -"rc-config-loader@npm:^4.1.3": - version: 4.1.3 - resolution: "rc-config-loader@npm:4.1.3" - dependencies: - debug: "npm:^4.3.4" - js-yaml: "npm:^4.1.0" - json5: "npm:^2.2.2" - require-from-string: "npm:^2.0.2" - checksum: 10/7aa12d17120fef0d8c29b1de532a6fab2704c460fa0f2e13ceaa9317e6fbb767799abc6bc53da0bd65249b252edec47e45eafba4687b10ed4f1e8697991ceeb5 - languageName: node - linkType: hard - -"rc@npm:1.2.8": - version: 1.2.8 - resolution: "rc@npm:1.2.8" - dependencies: - deep-extend: "npm:^0.6.0" - ini: "npm:~1.3.0" - minimist: "npm:^1.2.0" - strip-json-comments: "npm:~2.0.1" - bin: - rc: ./cli.js - checksum: 10/5c4d72ae7eec44357171585938c85ce066da8ca79146b5635baf3d55d74584c92575fa4e2c9eac03efbed3b46a0b2e7c30634c012b4b4fa40d654353d3c163eb +"react-is@npm:^16.13.1": + version: 16.13.1 + resolution: "react-is@npm:16.13.1" + checksum: 10/5aa564a1cde7d391ac980bedee21202fc90bdea3b399952117f54fb71a932af1e5902020144fb354b4690b2414a0c7aafe798eb617b76a3d441d956db7726fdf languageName: node linkType: hard @@ -7095,28 +7892,6 @@ __metadata: languageName: node linkType: hard -"read-package-json-fast@npm:^3.0.0": - version: 3.0.2 - resolution: "read-package-json-fast@npm:3.0.2" - dependencies: - json-parse-even-better-errors: "npm:^3.0.0" - npm-normalize-package-bin: "npm:^3.0.0" - checksum: 10/8d406869f045f1d76e2a99865a8fd1c1af9c1dc06200b94d2b07eef87ed734b22703a8d72e1cd36ea36cc48e22020bdd187f88243c7dd0563f72114d38c17072 - languageName: node - linkType: hard - -"read-package-json@npm:^6.0.0": - version: 6.0.4 - resolution: "read-package-json@npm:6.0.4" - dependencies: - glob: "npm:^10.2.2" - json-parse-even-better-errors: "npm:^3.0.0" - normalize-package-data: "npm:^5.0.0" - npm-normalize-package-bin: "npm:^3.0.0" - checksum: 10/2c72fc86745ffd303177ec1490a809fb916d36720cec145900ec92ca5dd159d6f096dd7842ad92dfa01eeea5509e076960a5395e8d5ce31984a4e9070018915a - languageName: node - linkType: hard - "read-pkg-up@npm:^7.0.1": version: 7.0.1 resolution: "read-pkg-up@npm:7.0.1" @@ -7140,28 +7915,69 @@ __metadata: languageName: node linkType: hard -"readable-stream@npm:^3.6.0": - version: 3.6.2 - resolution: "readable-stream@npm:3.6.2" +"refa@npm:^0.12.0, refa@npm:^0.12.1": + version: 0.12.1 + resolution: "refa@npm:0.12.1" + dependencies: + "@eslint-community/regexpp": "npm:^4.8.0" + checksum: 10/b89411434e31637a519c065acd8fd1ec9eabc1dec38eec58dbc69a386ec21d88f97fa175e56fb3133e21c090ddb68fe7b5653ffc4bbcc9f069abc0e88c0d290c + languageName: node + linkType: hard + +"reflect.getprototypeof@npm:^1.0.4": + version: 1.0.6 + resolution: "reflect.getprototypeof@npm:1.0.6" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.1" + es-errors: "npm:^1.3.0" + get-intrinsic: "npm:^1.2.4" + globalthis: "npm:^1.0.3" + which-builtin-type: "npm:^1.1.3" + checksum: 10/518f6457e4bb470c9b317d239c62d4b4a05678b7eae4f1c3f4332fad379b3ea6d2d8999bfad448547fdba8fb77e4725cfe8c6440d0168ff387f16b4f19f759ad + languageName: node + linkType: hard + +"regenerate-unicode-properties@npm:^10.1.0": + version: 10.1.1 + resolution: "regenerate-unicode-properties@npm:10.1.1" + dependencies: + regenerate: "npm:^1.4.2" + checksum: 10/b855152efdcca0ecc37ceb0cb6647a544344555fc293af3b57191b918e1bc9c95ee404a9a64a1d692bf66d45850942c29d93f2740c0d1980d3a8ea2ca63b184e + languageName: node + linkType: hard + +"regenerate@npm:^1.4.2": + version: 1.4.2 + resolution: "regenerate@npm:1.4.2" + checksum: 10/dc6c95ae4b3ba6adbd7687cafac260eee4640318c7a95239d5ce847d9b9263979758389e862fe9c93d633b5792ea4ada5708df75885dc5aa05a309fa18140a87 + languageName: node + linkType: hard + +"regenerator-runtime@npm:^0.14.0": + version: 0.14.1 + resolution: "regenerator-runtime@npm:0.14.1" + checksum: 10/5db3161abb311eef8c45bcf6565f4f378f785900ed3945acf740a9888c792f75b98ecb77f0775f3bf95502ff423529d23e94f41d80c8256e8fa05ed4b07cf471 + languageName: node + linkType: hard + +"regenerator-transform@npm:^0.15.2": + version: 0.15.2 + resolution: "regenerator-transform@npm:0.15.2" dependencies: - inherits: "npm:^2.0.3" - string_decoder: "npm:^1.1.1" - util-deprecate: "npm:^1.0.1" - checksum: 10/d9e3e53193adcdb79d8f10f2a1f6989bd4389f5936c6f8b870e77570853561c362bee69feca2bbb7b32368ce96a85504aa4cedf7cf80f36e6a9de30d64244048 + "@babel/runtime": "npm:^7.8.4" + checksum: 10/c4fdcb46d11bbe32605b4b9ed76b21b8d3f241a45153e9dc6f5542fed4c7744fed459f42701f650d5d5956786bf7de57547329d1c05a9df2ed9e367b9d903302 languageName: node linkType: hard -"redis@npm:^4.6.14": - version: 4.6.14 - resolution: "redis@npm:4.6.14" +"regexp-ast-analysis@npm:^0.7.0": + version: 0.7.1 + resolution: "regexp-ast-analysis@npm:0.7.1" dependencies: - "@redis/bloom": "npm:1.2.0" - "@redis/client": "npm:1.5.16" - "@redis/graph": "npm:1.1.1" - "@redis/json": "npm:1.0.6" - "@redis/search": "npm:1.1.6" - "@redis/time-series": "npm:1.0.5" - checksum: 10/5a00d678ea39a2e2fdaa961b593873e21677922b72671b00ab0feda3469506bc89c13221e56b1c00994504538ea45dd7ed6cde5d8be8da308a26f5d2424d0f85 + "@eslint-community/regexpp": "npm:^4.8.0" + refa: "npm:^0.12.1" + checksum: 10/92299636d9c941ee27db7568a775354d36024504c104c5d7981a89dda1b0ff1e2a56db16f92d7e166a50a1164593788c0849c5840ec9d79b39c1c040d59c442c languageName: node linkType: hard @@ -7174,7 +7990,7 @@ __metadata: languageName: node linkType: hard -"regexp.prototype.flags@npm:^1.5.2": +"regexp.prototype.flags@npm:^1.5.1, regexp.prototype.flags@npm:^1.5.2": version: 1.5.2 resolution: "regexp.prototype.flags@npm:1.5.2" dependencies: @@ -7186,21 +8002,17 @@ __metadata: languageName: node linkType: hard -"registry-auth-token@npm:^5.0.1": - version: 5.0.2 - resolution: "registry-auth-token@npm:5.0.2" - dependencies: - "@pnpm/npm-conf": "npm:^2.1.0" - checksum: 10/0d7683b71ee418993e7872b389024b13645c4295eb7bb850d10728eaf46065db24ea4d47dc6cbb71a60d1aa4bef077b0d8b7363c9ac9d355fdba47bebdfb01dd - languageName: node - linkType: hard - -"registry-url@npm:^6.0.0": - version: 6.0.1 - resolution: "registry-url@npm:6.0.1" +"regexpu-core@npm:^5.3.1": + version: 5.3.2 + resolution: "regexpu-core@npm:5.3.2" dependencies: - rc: "npm:1.2.8" - checksum: 10/33712aa1b489aab7aba2191c1cdadfdd71f5bf166d4792d81744a6be332c160bd7d9273af8269d8a01284b9562f14a5b31b7abcf7ad9306c44887ecff51c89ab + "@babel/regjsgen": "npm:^0.8.0" + regenerate: "npm:^1.4.2" + regenerate-unicode-properties: "npm:^10.1.0" + regjsparser: "npm:^0.9.1" + unicode-match-property-ecmascript: "npm:^2.0.0" + unicode-match-property-value-ecmascript: "npm:^2.1.0" + checksum: 10/ed0d7c66d84c633fbe8db4939d084c780190eca11f6920807dfb8ebac59e2676952cd8f2008d9c86ae8cf0463ea5fd12c5cff09ef2ce7d51ee6b420a5eb4d177 languageName: node linkType: hard @@ -7215,10 +8027,14 @@ __metadata: languageName: node linkType: hard -"remote-git-tags@npm:^3.0.0": - version: 3.0.0 - resolution: "remote-git-tags@npm:3.0.0" - checksum: 10/04d87e4c98ac414afe03417d3f585c4b782c03fec74561b1fba0bdc5d3a0459f2cfcc14af36fbc153bf601e566d86e9ff6989e289ff57a86f9cfdac6b4f622f2 +"regjsparser@npm:^0.9.1": + version: 0.9.1 + resolution: "regjsparser@npm:0.9.1" + dependencies: + jsesc: "npm:~0.5.0" + bin: + regjsparser: bin/parser + checksum: 10/be7757ef76e1db10bf6996001d1021048b5fb12f5cb470a99b8cf7f3ff943f0f0e2291c0dcdbb418b458ddc4ac10e48680a822b69ef487a0284c8b6b77beddc3 languageName: node linkType: hard @@ -7236,13 +8052,6 @@ __metadata: languageName: node linkType: hard -"require-from-string@npm:^2.0.2": - version: 2.0.2 - resolution: "require-from-string@npm:2.0.2" - checksum: 10/839a3a890102a658f4cb3e7b2aa13a1f80a3a976b512020c3d1efc418491c48a886b6e481ea56afc6c4cb5eef678f23b2a4e70575e7534eccadf5e30ed2e56eb - languageName: node - linkType: hard - "requireindex@npm:~1.2.0": version: 1.2.0 resolution: "requireindex@npm:1.2.0" @@ -7250,13 +8059,6 @@ __metadata: languageName: node linkType: hard -"resolve-alpn@npm:^1.2.0": - version: 1.2.1 - resolution: "resolve-alpn@npm:1.2.1" - checksum: 10/744e87888f0b6fa0b256ab454ca0b9c0b80808715e2ef1f3672773665c92a941f6181194e30ccae4a8cd0adbe0d955d3f133102636d2ee0cca0119fec0bc9aec - languageName: node - linkType: hard - "resolve-cwd@npm:^3.0.0": version: 3.0.0 resolution: "resolve-cwd@npm:3.0.0" @@ -7294,7 +8096,7 @@ __metadata: languageName: node linkType: hard -"resolve@npm:^1.10.0, resolve@npm:^1.20.0, resolve@npm:^1.22.4": +"resolve@npm:^1.10.0, resolve@npm:^1.14.2, resolve@npm:^1.20.0, resolve@npm:^1.22.4": version: 1.22.8 resolution: "resolve@npm:1.22.8" dependencies: @@ -7307,61 +8109,56 @@ __metadata: languageName: node linkType: hard -"resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": - version: 1.22.8 - resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" +"resolve@npm:^2.0.0-next.5": + version: 2.0.0-next.5 + resolution: "resolve@npm:2.0.0-next.5" dependencies: is-core-module: "npm:^2.13.0" path-parse: "npm:^1.0.7" supports-preserve-symlinks-flag: "npm:^1.0.0" bin: resolve: bin/resolve - checksum: 10/f345cd37f56a2c0275e3fe062517c650bb673815d885e7507566df589375d165bbbf4bdb6aa95600a9bc55f4744b81f452b5a63f95b9f10a72787dba3c90890a + checksum: 10/2d6fd28699f901744368e6f2032b4268b4c7b9185fd8beb64f68c93ac6b22e52ae13560ceefc96241a665b985edf9ffd393ae26d2946a7d3a07b7007b7d51e79 languageName: node linkType: hard -"responselike@npm:^3.0.0": - version: 3.0.0 - resolution: "responselike@npm:3.0.0" +"resolve@patch:resolve@npm%3A^1.10.0#optional!builtin, resolve@patch:resolve@npm%3A^1.14.2#optional!builtin, resolve@patch:resolve@npm%3A^1.20.0#optional!builtin, resolve@patch:resolve@npm%3A^1.22.4#optional!builtin": + version: 1.22.8 + resolution: "resolve@patch:resolve@npm%3A1.22.8#optional!builtin::version=1.22.8&hash=c3c19d" dependencies: - lowercase-keys: "npm:^3.0.0" - checksum: 10/e0cc9be30df4f415d6d83cdede3c5c887cd4a73e7cc1708bcaab1d50a28d15acb68460ac5b02bcc55a42f3d493729c8856427dcf6e57e6e128ad05cba4cfb95e - languageName: node - linkType: hard - -"retry@npm:^0.12.0": - version: 0.12.0 - resolution: "retry@npm:0.12.0" - checksum: 10/1f914879f97e7ee931ad05fe3afa629bd55270fc6cf1c1e589b6a99fab96d15daad0fa1a52a00c729ec0078045fe3e399bd4fd0c93bcc906957bdc17f89cb8e6 - languageName: node - linkType: hard - -"reusify@npm:^1.0.4": - version: 1.0.4 - resolution: "reusify@npm:1.0.4" - checksum: 10/14222c9e1d3f9ae01480c50d96057228a8524706db79cdeb5a2ce5bb7070dd9f409a6f84a02cbef8cdc80d39aef86f2dd03d155188a1300c599b05437dcd2ffb + is-core-module: "npm:^2.13.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" + bin: + resolve: bin/resolve + checksum: 10/f345cd37f56a2c0275e3fe062517c650bb673815d885e7507566df589375d165bbbf4bdb6aa95600a9bc55f4744b81f452b5a63f95b9f10a72787dba3c90890a languageName: node linkType: hard -"rimraf@npm:^3.0.2": - version: 3.0.2 - resolution: "rimraf@npm:3.0.2" +"resolve@patch:resolve@npm%3A^2.0.0-next.5#optional!builtin": + version: 2.0.0-next.5 + resolution: "resolve@patch:resolve@npm%3A2.0.0-next.5#optional!builtin::version=2.0.0-next.5&hash=c3c19d" dependencies: - glob: "npm:^7.1.3" + is-core-module: "npm:^2.13.0" + path-parse: "npm:^1.0.7" + supports-preserve-symlinks-flag: "npm:^1.0.0" bin: - rimraf: bin.js - checksum: 10/063ffaccaaaca2cfd0ef3beafb12d6a03dd7ff1260d752d62a6077b5dfff6ae81bea571f655bb6b589d366930ec1bdd285d40d560c0dae9b12f125e54eb743d5 + resolve: bin/resolve + checksum: 10/05fa778de9d0347c8b889eb7a18f1f06bf0f801b0eb4610b4871a4b2f22e220900cf0ad525e94f990bb8d8921c07754ab2122c0c225ab4cdcea98f36e64fa4c2 + languageName: node + linkType: hard + +"retry@npm:^0.12.0": + version: 0.12.0 + resolution: "retry@npm:0.12.0" + checksum: 10/1f914879f97e7ee931ad05fe3afa629bd55270fc6cf1c1e589b6a99fab96d15daad0fa1a52a00c729ec0078045fe3e399bd4fd0c93bcc906957bdc17f89cb8e6 languageName: node linkType: hard -"rimraf@npm:^5.0.5": - version: 5.0.7 - resolution: "rimraf@npm:5.0.7" - dependencies: - glob: "npm:^10.3.7" - bin: - rimraf: dist/esm/bin.mjs - checksum: 10/1e3cecfe59ee2383dfd9ba5373caeed48ed941318a0360119419b7dffc63115661408b9427f67e1f66b5bbb8855a3953db09e55a7362b3df904a44453dfa22fb +"reusify@npm:^1.0.4": + version: 1.0.4 + resolution: "reusify@npm:1.0.4" + checksum: 10/14222c9e1d3f9ae01480c50d96057228a8524706db79cdeb5a2ce5bb7070dd9f409a6f84a02cbef8cdc80d39aef86f2dd03d155188a1300c599b05437dcd2ffb languageName: node linkType: hard @@ -7386,13 +8183,6 @@ __metadata: languageName: node linkType: hard -"safe-buffer@npm:~5.2.0": - version: 5.2.1 - resolution: "safe-buffer@npm:5.2.1" - checksum: 10/32872cd0ff68a3ddade7a7617b8f4c2ae8764d8b7d884c651b74457967a9e0e886267d3ecc781220629c44a865167b61c375d2da6c720c840ecd73f45d5d9451 - languageName: node - linkType: hard - "safe-regex-test@npm:^1.0.3": version: 1.0.3 resolution: "safe-regex-test@npm:1.0.3" @@ -7420,19 +8210,14 @@ __metadata: languageName: node linkType: hard -"semver-diff@npm:^4.0.0": - version: 4.0.0 - resolution: "semver-diff@npm:4.0.0" +"scslre@npm:0.3.0": + version: 0.3.0 + resolution: "scslre@npm:0.3.0" dependencies: - semver: "npm:^7.3.5" - checksum: 10/4a958d6f76c7e7858268e1e2cf936712542441c9e003e561b574167279eee0a9bd55cc7eae1bfb31d3e7ad06a9fc370e7dd412fcfefec8c0daf1ce5aea623559 - languageName: node - linkType: hard - -"semver-utils@npm:^1.1.4": - version: 1.1.4 - resolution: "semver-utils@npm:1.1.4" - checksum: 10/93fd955a30f5bdf532163d94981aa03dfbaddf29dad6388415b264c95d7046a6b47d947c6e3e37c0d7867ed3f024aa6e50fc308c9487378354e9d300c9dd68b6 + "@eslint-community/regexpp": "npm:^4.8.0" + refa: "npm:^0.12.0" + regexp-ast-analysis: "npm:^0.7.0" + checksum: 10/164ec9b9a9d819838240b1df613b6c60ae00c69c4472264f354a191f73b538c064d43c0ac3accf89f5c05880ddab33846077b0cda3ad383701623d468960c005 languageName: node linkType: hard @@ -7445,6 +8230,17 @@ __metadata: languageName: node linkType: hard +"semver@npm:7.6.0": + version: 7.6.0 + resolution: "semver@npm:7.6.0" + dependencies: + lru-cache: "npm:^6.0.0" + bin: + semver: bin/semver.js + checksum: 10/1b41018df2d8aca5a1db4729985e8e20428c650daea60fcd16e926e9383217d00f574fab92d79612771884a98d2ee2a1973f49d630829a8d54d6570defe62535 + languageName: node + linkType: hard + "semver@npm:^6.3.0, semver@npm:^6.3.1": version: 6.3.1 resolution: "semver@npm:6.3.1" @@ -7454,7 +8250,7 @@ __metadata: languageName: node linkType: hard -"semver@npm:^7.1.1, semver@npm:^7.3.5, semver@npm:^7.3.7, semver@npm:^7.5.3, semver@npm:^7.5.4": +"semver@npm:^7.3.5, semver@npm:^7.5.3, semver@npm:^7.5.4": version: 7.6.2 resolution: "semver@npm:7.6.2" bin: @@ -7463,10 +8259,12 @@ __metadata: languageName: node linkType: hard -"set-blocking@npm:^2.0.0": - version: 2.0.0 - resolution: "set-blocking@npm:2.0.0" - checksum: 10/8980ebf7ae9eb945bb036b6e283c547ee783a1ad557a82babf758a065e2fb6ea337fd82cac30dd565c1e606e423f30024a19fff7afbf4977d784720c4026a8ef +"semver@npm:^7.3.6, semver@npm:^7.6.0, semver@npm:^7.6.1, semver@npm:^7.6.3": + version: 7.6.3 + resolution: "semver@npm:7.6.3" + bin: + semver: bin/semver.js + checksum: 10/36b1fbe1a2b6f873559cd57b238f1094a053dbfd997ceeb8757d79d1d2089c56d1321b9f1069ce263dc64cfa922fa1d2ad566b39426fe1ac6c723c1487589e10 languageName: node linkType: hard @@ -7484,7 +8282,7 @@ __metadata: languageName: node linkType: hard -"set-function-name@npm:^2.0.1": +"set-function-name@npm:^2.0.1, set-function-name@npm:^2.0.2": version: 2.0.2 resolution: "set-function-name@npm:2.0.2" dependencies: @@ -7512,7 +8310,7 @@ __metadata: languageName: node linkType: hard -"side-channel@npm:^1.0.4": +"side-channel@npm:^1.0.4, side-channel@npm:^1.0.6": version: 1.0.6 resolution: "side-channel@npm:1.0.6" dependencies: @@ -7524,7 +8322,7 @@ __metadata: languageName: node linkType: hard -"signal-exit@npm:^3.0.2, signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": +"signal-exit@npm:^3.0.3, signal-exit@npm:^3.0.7": version: 3.0.7 resolution: "signal-exit@npm:3.0.7" checksum: 10/a2f098f247adc367dffc27845853e9959b9e88b01cb301658cfe4194352d8d2bb32e18467c786a7fe15f1d44b233ea35633d076d5e737870b7139949d1ab6318 @@ -7538,21 +8336,6 @@ __metadata: languageName: node linkType: hard -"sigstore@npm:^1.3.0": - version: 1.9.0 - resolution: "sigstore@npm:1.9.0" - dependencies: - "@sigstore/bundle": "npm:^1.1.0" - "@sigstore/protobuf-specs": "npm:^0.2.0" - "@sigstore/sign": "npm:^1.0.0" - "@sigstore/tuf": "npm:^1.0.3" - make-fetch-happen: "npm:^11.0.1" - bin: - sigstore: bin/sigstore.js - checksum: 10/7ff59f6bbc6fbf4e11f99df36562cdfd8f27f74650e1794942b0f9b567c6facdd0a6c245375111c464a0c367e617793a1c1787ec1dea9784ad2fb698932b9fb9 - languageName: node - linkType: hard - "sisteransi@npm:^1.0.5": version: 1.0.5 resolution: "sisteransi@npm:1.0.5" @@ -7574,17 +8357,6 @@ __metadata: languageName: node linkType: hard -"socks-proxy-agent@npm:^7.0.0": - version: 7.0.0 - resolution: "socks-proxy-agent@npm:7.0.0" - dependencies: - agent-base: "npm:^6.0.2" - debug: "npm:^4.3.3" - socks: "npm:^2.6.2" - checksum: 10/26c75d9c62a9ed3fd494df60e65e88da442f78e0d4bc19bfd85ac37bd2c67470d6d4bba5202e804561cda6674db52864c9e2a2266775f879bc8d89c1445a5f4c - languageName: node - linkType: hard - "socks-proxy-agent@npm:^8.0.3": version: 8.0.3 resolution: "socks-proxy-agent@npm:8.0.3" @@ -7596,7 +8368,7 @@ __metadata: languageName: node linkType: hard -"socks@npm:^2.6.2, socks@npm:^2.7.1": +"socks@npm:^2.7.1": version: 2.8.3 resolution: "socks@npm:2.8.3" dependencies: @@ -7616,16 +8388,6 @@ __metadata: languageName: node linkType: hard -"source-map-support@npm:^0.5.21": - version: 0.5.21 - resolution: "source-map-support@npm:0.5.21" - dependencies: - buffer-from: "npm:^1.0.0" - source-map: "npm:^0.6.0" - checksum: 10/8317e12d84019b31e34b86d483dd41d6f832f389f7417faf8fc5c75a66a12d9686e47f589a0554a868b8482f037e23df9d040d29387eb16fa14cb85f091ba207 - languageName: node - linkType: hard - "source-map@npm:^0.6.0, source-map@npm:^0.6.1": version: 0.6.1 resolution: "source-map@npm:0.6.1" @@ -7633,15 +8395,6 @@ __metadata: languageName: node linkType: hard -"spawn-please@npm:^2.0.2": - version: 2.0.2 - resolution: "spawn-please@npm:2.0.2" - dependencies: - cross-spawn: "npm:^7.0.3" - checksum: 10/c83d5046af9ad2e0edbc56afbffbbc814bc38fb7cc3cce75608ef10028dbf6d19dd758d0194b11b02b9e2082d77b58caa93f5fa31a7505ef81b467259c877cfd - languageName: node - linkType: hard - "spdx-correct@npm:^3.0.0": version: 3.2.0 resolution: "spdx-correct@npm:3.2.0" @@ -7699,15 +8452,6 @@ __metadata: languageName: node linkType: hard -"ssri@npm:^9.0.0": - version: 9.0.1 - resolution: "ssri@npm:9.0.1" - dependencies: - minipass: "npm:^3.1.1" - checksum: 10/7638a61e91432510718e9265d48d0438a17d53065e5184f1336f234ef6aa3479663942e41e97df56cda06bb24d9d0b5ef342c10685add3cac7267a82d7fa6718 - languageName: node - linkType: hard - "stack-utils@npm:^2.0.3": version: 2.0.6 resolution: "stack-utils@npm:2.0.6" @@ -7717,6 +8461,15 @@ __metadata: languageName: node linkType: hard +"stop-iteration-iterator@npm:^1.0.0": + version: 1.0.0 + resolution: "stop-iteration-iterator@npm:1.0.0" + dependencies: + internal-slot: "npm:^1.0.4" + checksum: 10/2a23a36f4f6bfa63f46ae2d53a3f80fe8276110b95a55345d8ed3d92125413494033bc8697eb774e8f7aeb5725f70e3d69753caa2ecacdac6258c16fa8aa8b0f + languageName: node + linkType: hard + "string-length@npm:^4.0.1": version: 4.0.2 resolution: "string-length@npm:4.0.2" @@ -7727,7 +8480,7 @@ __metadata: languageName: node linkType: hard -"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^1.0.2 || 2 || 3 || 4, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": +"string-width-cjs@npm:string-width@^4.2.0, string-width@npm:^4.1.0, string-width@npm:^4.2.0, string-width@npm:^4.2.3": version: 4.2.3 resolution: "string-width@npm:4.2.3" dependencies: @@ -7749,6 +8502,46 @@ __metadata: languageName: node linkType: hard +"string.prototype.includes@npm:^2.0.0": + version: 2.0.0 + resolution: "string.prototype.includes@npm:2.0.0" + dependencies: + define-properties: "npm:^1.1.3" + es-abstract: "npm:^1.17.5" + checksum: 10/34c1e71ac5cab469bef52a4f3d983d141ca61c43b9fe8859574c8829822aad0a61fce1dddfaf8a48ad7ac5032a1730c19f1fb2d09715f57025cd138b1ad4b0e4 + languageName: node + linkType: hard + +"string.prototype.matchall@npm:^4.0.11": + version: 4.0.11 + resolution: "string.prototype.matchall@npm:4.0.11" + dependencies: + call-bind: "npm:^1.0.7" + define-properties: "npm:^1.2.1" + es-abstract: "npm:^1.23.2" + es-errors: "npm:^1.3.0" + es-object-atoms: "npm:^1.0.0" + get-intrinsic: "npm:^1.2.4" + gopd: "npm:^1.0.1" + has-symbols: "npm:^1.0.3" + internal-slot: "npm:^1.0.7" + regexp.prototype.flags: "npm:^1.5.2" + set-function-name: "npm:^2.0.2" + side-channel: "npm:^1.0.6" + checksum: 10/a902ff4500f909f2a08e55cc5ab1ffbbc905f603b36837674370ee3921058edd0392147e15891910db62a2f31ace2adaf065eaa3bc6e9810bdbc8ca48e05a7b5 + languageName: node + linkType: hard + +"string.prototype.repeat@npm:^1.0.0": + version: 1.0.0 + resolution: "string.prototype.repeat@npm:1.0.0" + dependencies: + define-properties: "npm:^1.1.3" + es-abstract: "npm:^1.17.5" + checksum: 10/4b1bd91b75fa8fdf0541625184ebe80e445a465ce4253c19c3bccd633898005dadae0f74b85ae72662a53aafb8035bf48f8f5c0755aec09bc106a7f13959d05e + languageName: node + linkType: hard + "string.prototype.trim@npm:^1.2.9": version: 1.2.9 resolution: "string.prototype.trim@npm:1.2.9" @@ -7783,15 +8576,6 @@ __metadata: languageName: node linkType: hard -"string_decoder@npm:^1.1.1": - version: 1.3.0 - resolution: "string_decoder@npm:1.3.0" - dependencies: - safe-buffer: "npm:~5.2.0" - checksum: 10/54d23f4a6acae0e93f999a585e673be9e561b65cd4cca37714af1e893ab8cd8dfa52a9e4f58f48f87b4a44918d3a9254326cb80ed194bf2e4c226e2b21767e56 - languageName: node - linkType: hard - "strip-ansi-cjs@npm:strip-ansi@^6.0.1, strip-ansi@npm:^6.0.0, strip-ansi@npm:^6.0.1": version: 6.0.1 resolution: "strip-ansi@npm:6.0.1" @@ -7801,7 +8585,7 @@ __metadata: languageName: node linkType: hard -"strip-ansi@npm:^7.0.1, strip-ansi@npm:^7.1.0": +"strip-ansi@npm:^7.0.1": version: 7.1.0 resolution: "strip-ansi@npm:7.1.0" dependencies: @@ -7847,20 +8631,6 @@ __metadata: languageName: node linkType: hard -"strip-json-comments@npm:^5.0.1": - version: 5.0.1 - resolution: "strip-json-comments@npm:5.0.1" - checksum: 10/b314af70c6666a71133e309a571bdb87687fc878d9fd8b38ebed393a77b89835b92f191aa6b0bc10dfd028ba99eed6b6365985001d64c5aef32a4a82456a156b - languageName: node - linkType: hard - -"strip-json-comments@npm:~2.0.1": - version: 2.0.1 - resolution: "strip-json-comments@npm:2.0.1" - checksum: 10/1074ccb63270d32ca28edfb0a281c96b94dc679077828135141f27d52a5a398ef5e78bcf22809d23cadc2b81dfbe345eb5fd8699b385c8b1128907dec4a7d1e1 - languageName: node - linkType: hard - "supports-color@npm:^5.3.0": version: 5.5.0 resolution: "supports-color@npm:5.5.0" @@ -7904,23 +8674,13 @@ __metadata: languageName: node linkType: hard -"synckit@npm:^0.8.6": - version: 0.8.8 - resolution: "synckit@npm:0.8.8" - dependencies: - "@pkgr/core": "npm:^0.1.0" - tslib: "npm:^2.6.2" - checksum: 10/2864a5c3e689ad5b991bebbd8a583c5682c4fa08a4f39986b510b6b5d160c08fc3672444069f8f96ed6a9d12772879c674c1f61e728573eadfa90af40a765b74 - languageName: node - linkType: hard - -"synckit@npm:^0.9.0": - version: 0.9.0 - resolution: "synckit@npm:0.9.0" +"synckit@npm:^0.9.1": + version: 0.9.1 + resolution: "synckit@npm:0.9.1" dependencies: "@pkgr/core": "npm:^0.1.0" tslib: "npm:^2.6.2" - checksum: 10/e93f3f5ee43fa71d3bb2a345049642d9034f34fa9528706b5ef26e825335ca5446143c56c2b041810afe26aa6e343583ff08525f5530618a4707375270f87be1 + checksum: 10/bff3903976baf8b699b5483228116d70223781a93b17c70e685c277ee960cdfd1a09cb5a741e6a9ec35e2428f14f4664baec41ccc99a598f267608b2a54f529b languageName: node linkType: hard @@ -7938,15 +8698,6 @@ __metadata: languageName: node linkType: hard -"tdigest@npm:^0.1.1": - version: 0.1.2 - resolution: "tdigest@npm:0.1.2" - dependencies: - bintrees: "npm:1.0.2" - checksum: 10/45be99fa52dab74b8edafe150e473cdc45aa1352c75ed516a39905f350a08c3175f6555598111042c3677ba042d7e3cae6b5ce4c663fe609bc634f326aabc9d6 - languageName: node - linkType: hard - "test-exclude@npm:^6.0.0": version: 6.0.0 resolution: "test-exclude@npm:6.0.0" @@ -7988,7 +8739,7 @@ __metadata: languageName: node linkType: hard -"ts-api-utils@npm:^1.0.1": +"ts-api-utils@npm:^1.3.0": version: 1.3.0 resolution: "ts-api-utils@npm:1.3.0" peerDependencies: @@ -7997,18 +8748,19 @@ __metadata: languageName: node linkType: hard -"ts-jest@npm:^29.1.5": - version: 29.1.5 - resolution: "ts-jest@npm:29.1.5" +"ts-jest@npm:^29.2.5": + version: 29.2.5 + resolution: "ts-jest@npm:29.2.5" dependencies: - bs-logger: "npm:0.x" - fast-json-stable-stringify: "npm:2.x" + bs-logger: "npm:^0.2.6" + ejs: "npm:^3.1.10" + fast-json-stable-stringify: "npm:^2.1.0" jest-util: "npm:^29.0.0" json5: "npm:^2.2.3" - lodash.memoize: "npm:4.x" - make-error: "npm:1.x" - semver: "npm:^7.5.3" - yargs-parser: "npm:^21.0.1" + lodash.memoize: "npm:^4.1.2" + make-error: "npm:^1.3.6" + semver: "npm:^7.6.3" + yargs-parser: "npm:^21.1.1" peerDependencies: "@babel/core": ">=7.0.0-beta.0 <8" "@jest/transform": ^29.0.0 @@ -8029,7 +8781,7 @@ __metadata: optional: true bin: ts-jest: cli.js - checksum: 10/11a29a49130f1c9bef5aebe8007f6be3e630af6c2dea6b00ff5a86d649321854a43966b4990a43960d77a3f98d7a753b9b7e19c20c42a2d38341d6e67a3e48d1 + checksum: 10/f89e562816861ec4510840a6b439be6145f688b999679328de8080dc8e66481325fc5879519b662163e33b7578f35243071c38beb761af34e5fe58e3e326a958 languageName: node linkType: hard @@ -8045,18 +8797,25 @@ __metadata: languageName: node linkType: hard -"tslib@npm:^2.3.1, tslib@npm:^2.6.2, tslib@npm:^2.6.3": +"tslib@npm:^2.3.1, tslib@npm:^2.6.2": version: 2.6.3 resolution: "tslib@npm:2.6.3" checksum: 10/52109bb681f8133a2e58142f11a50e05476de4f075ca906d13b596ae5f7f12d30c482feb0bff167ae01cfc84c5803e575a307d47938999246f5a49d174fc558c languageName: node linkType: hard -"tsx@npm:^4.15.7": - version: 4.15.7 - resolution: "tsx@npm:4.15.7" +"tslib@npm:^2.7.0": + version: 2.7.0 + resolution: "tslib@npm:2.7.0" + checksum: 10/9a5b47ddac65874fa011c20ff76db69f97cf90c78cff5934799ab8894a5342db2d17b4e7613a087046bc1d133d21547ddff87ac558abeec31ffa929c88b7fce6 + languageName: node + linkType: hard + +"tsx@npm:^4.19.1": + version: 4.19.1 + resolution: "tsx@npm:4.19.1" dependencies: - esbuild: "npm:~0.21.4" + esbuild: "npm:~0.23.0" fsevents: "npm:~2.3.3" get-tsconfig: "npm:^4.7.5" dependenciesMeta: @@ -8064,18 +8823,7 @@ __metadata: optional: true bin: tsx: dist/cli.mjs - checksum: 10/b313d7b07e017bc5c69a8c8bf33c005c2090cf1160df31e9e871bb86bbd4f582fff49849ecaf212f0f79286be98dc48d761ff16181496e88a674c7eec16274b6 - languageName: node - linkType: hard - -"tuf-js@npm:^1.1.7": - version: 1.1.7 - resolution: "tuf-js@npm:1.1.7" - dependencies: - "@tufjs/models": "npm:1.0.4" - debug: "npm:^4.3.4" - make-fetch-happen: "npm:^11.1.1" - checksum: 10/8ce0061b76a9dc89fc6e53bc1870afeb8e70083a751910273f959c5d0d574ba9b037a22d944ff97623e58eefa16b051f0ac678bd2da973d2f6b57359604fee31 + checksum: 10/1f5f0b7c4107fc18f523e94c79204b043641aa328f721324795cc961826879035652a1f19fe29ba420465d9f4bacb0f47e08f0bd4b934684ab45727eca110311 languageName: node linkType: hard @@ -8095,13 +8843,6 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^0.20.2": - version: 0.20.2 - resolution: "type-fest@npm:0.20.2" - checksum: 10/8907e16284b2d6cfa4f4817e93520121941baba36b39219ea36acfe64c86b9dbc10c9941af450bd60832c8f43464974d51c0957f9858bc66b952b66b6914cbb9 - languageName: node - linkType: hard - "type-fest@npm:^0.21.3": version: 0.21.3 resolution: "type-fest@npm:0.21.3" @@ -8123,24 +8864,10 @@ __metadata: languageName: node linkType: hard -"type-fest@npm:^1.0.1": - version: 1.4.0 - resolution: "type-fest@npm:1.4.0" - checksum: 10/89875c247564601c2650bacad5ff80b859007fbdb6c9e43713ae3ffa3f584552eea60f33711dd762e16496a1ab4debd409822627be14097d9a17e39c49db591a - languageName: node - linkType: hard - -"type-fest@npm:^2.13.0": - version: 2.19.0 - resolution: "type-fest@npm:2.19.0" - checksum: 10/7bf9e8fdf34f92c8bb364c0af14ca875fac7e0183f2985498b77be129dc1b3b1ad0a6b3281580f19e48c6105c037fb966ad9934520c69c6434d17fd0af4eed78 - languageName: node - linkType: hard - -"type-fest@npm:^4.20.1": - version: 4.20.1 - resolution: "type-fest@npm:4.20.1" - checksum: 10/52dc64fae094949008afb79f21b02eca0289c8dc41ed1cfff88f343230edb476fca4815e1b5d58acf5e07fdc7a1b098504473b5931ef418e6f38a3edb70fc1df +"type-fest@npm:^4.26.1": + version: 4.26.1 + resolution: "type-fest@npm:4.26.1" + checksum: 10/b82676194f80af228cb852e320d2ea8381c89d667d2e4d9f2bdfc8f254bccc039c7741a90c53617a4de0c9fdca8265ed18eb0888cd628f391c5c381c33a9f94b languageName: node linkType: hard @@ -8196,32 +8923,23 @@ __metadata: languageName: node linkType: hard -"typedarray-to-buffer@npm:^3.1.5": - version: 3.1.5 - resolution: "typedarray-to-buffer@npm:3.1.5" - dependencies: - is-typedarray: "npm:^1.0.0" - checksum: 10/7c850c3433fbdf4d04f04edfc751743b8f577828b8e1eb93b95a3bce782d156e267d83e20fb32b3b47813e69a69ab5e9b5342653332f7d21c7d1210661a7a72c - languageName: node - linkType: hard - -"typescript@npm:^5.5.2": - version: 5.5.2 - resolution: "typescript@npm:5.5.2" +"typescript@npm:*, typescript@npm:^5.6.2": + version: 5.6.2 + resolution: "typescript@npm:5.6.2" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10/9118b20f248e76b0dbff8737fef65dfa89d02668d4e633d2c5ceac99033a0ca5e8a1c1a53bc94da68e8f67677a88f318663dde859c9e9a09c1e116415daec2ba + checksum: 10/f95365d4898f357823e93d334ecda9fcade54f009b397c7d05b7621cd9e865981033cf89ccde0f3e3a7b73b1fdbae18e92bc77db237b43e912f053fef0f9a53b languageName: node linkType: hard -"typescript@patch:typescript@npm%3A^5.5.2#optional!builtin": - version: 5.5.2 - resolution: "typescript@patch:typescript@npm%3A5.5.2#optional!builtin::version=5.5.2&hash=379a07" +"typescript@patch:typescript@npm%3A*#optional!builtin, typescript@patch:typescript@npm%3A^5.6.2#optional!builtin": + version: 5.6.2 + resolution: "typescript@patch:typescript@npm%3A5.6.2#optional!builtin::version=5.6.2&hash=8c6c40" bin: tsc: bin/tsc tsserver: bin/tsserver - checksum: 10/ac3145f65cf9e72ab29f2196e05d5816b355dc1a9195b9f010d285182a12457cfacd068be2dd22c877f88ebc966ac6e0e83f51c8586412b16499a27e3670ff4b + checksum: 10/8bfc7ca0d9feca4c3fcbd6c70741abfcd714197d6448e68225ae71e462447d904d3bfba49759a8fbe4956d87f054e2d346833c8349c222daa594a2626d4e1be8 languageName: node linkType: hard @@ -8244,55 +8962,59 @@ __metadata: languageName: node linkType: hard -"unique-filename@npm:^2.0.0": - version: 2.0.1 - resolution: "unique-filename@npm:2.0.1" - dependencies: - unique-slug: "npm:^3.0.0" - checksum: 10/807acf3381aff319086b64dc7125a9a37c09c44af7620bd4f7f3247fcd5565660ac12d8b80534dcbfd067e6fe88a67e621386dd796a8af828d1337a8420a255f +"undici-types@npm:~6.19.2": + version: 6.19.8 + resolution: "undici-types@npm:6.19.8" + checksum: 10/cf0b48ed4fc99baf56584afa91aaffa5010c268b8842f62e02f752df209e3dea138b372a60a963b3b2576ed932f32329ce7ddb9cb5f27a6c83040d8cd74b7a70 languageName: node linkType: hard -"unique-filename@npm:^3.0.0": - version: 3.0.0 - resolution: "unique-filename@npm:3.0.0" - dependencies: - unique-slug: "npm:^4.0.0" - checksum: 10/8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df +"unicode-canonical-property-names-ecmascript@npm:^2.0.0": + version: 2.0.0 + resolution: "unicode-canonical-property-names-ecmascript@npm:2.0.0" + checksum: 10/39be078afd014c14dcd957a7a46a60061bc37c4508ba146517f85f60361acf4c7539552645ece25de840e17e293baa5556268d091ca6762747fdd0c705001a45 languageName: node linkType: hard -"unique-slug@npm:^3.0.0": - version: 3.0.0 - resolution: "unique-slug@npm:3.0.0" +"unicode-match-property-ecmascript@npm:^2.0.0": + version: 2.0.0 + resolution: "unicode-match-property-ecmascript@npm:2.0.0" dependencies: - imurmurhash: "npm:^0.1.4" - checksum: 10/26fc5bc209a875956dd5e84ca39b89bc3be777b112504667c35c861f9547df95afc80439358d836b878b6d91f6ee21fe5ba1a966e9ec2e9f071ddf3fd67d45ee + unicode-canonical-property-names-ecmascript: "npm:^2.0.0" + unicode-property-aliases-ecmascript: "npm:^2.0.0" + checksum: 10/1f34a7434a23df4885b5890ac36c5b2161a809887000be560f56ad4b11126d433c0c1c39baf1016bdabed4ec54829a6190ee37aa24919aa116dc1a5a8a62965a languageName: node linkType: hard -"unique-slug@npm:^4.0.0": - version: 4.0.0 - resolution: "unique-slug@npm:4.0.0" - dependencies: - imurmurhash: "npm:^0.1.4" - checksum: 10/40912a8963fc02fb8b600cf50197df4a275c602c60de4cac4f75879d3c48558cfac48de08a25cc10df8112161f7180b3bbb4d662aadb711568602f9eddee54f0 +"unicode-match-property-value-ecmascript@npm:^2.1.0": + version: 2.1.0 + resolution: "unicode-match-property-value-ecmascript@npm:2.1.0" + checksum: 10/06661bc8aba2a60c7733a7044f3e13085808939ad17924ffd4f5222a650f88009eb7c09481dc9c15cfc593d4ad99bd1cde8d54042733b335672591a81c52601c + languageName: node + linkType: hard + +"unicode-property-aliases-ecmascript@npm:^2.0.0": + version: 2.1.0 + resolution: "unicode-property-aliases-ecmascript@npm:2.1.0" + checksum: 10/243524431893649b62cc674d877bd64ef292d6071dd2fd01ab4d5ad26efbc104ffcd064f93f8a06b7e4ec54c172bf03f6417921a0d8c3a9994161fe1f88f815b languageName: node linkType: hard -"unique-string@npm:^3.0.0": +"unique-filename@npm:^3.0.0": version: 3.0.0 - resolution: "unique-string@npm:3.0.0" + resolution: "unique-filename@npm:3.0.0" dependencies: - crypto-random-string: "npm:^4.0.0" - checksum: 10/1a1e2e7d02eab1bb10f720475da735e1990c8a5ff34edd1a3b6bc31590cb4210b7a1233d779360cc622ce11c211e43afa1628dd658f35d3e6a89964b622940df + unique-slug: "npm:^4.0.0" + checksum: 10/8e2f59b356cb2e54aab14ff98a51ac6c45781d15ceaab6d4f1c2228b780193dc70fae4463ce9e1df4479cb9d3304d7c2043a3fb905bdeca71cc7e8ce27e063df languageName: node linkType: hard -"untildify@npm:^4.0.0": +"unique-slug@npm:^4.0.0": version: 4.0.0 - resolution: "untildify@npm:4.0.0" - checksum: 10/39ced9c418a74f73f0a56e1ba4634b4d959422dff61f4c72a8e39f60b99380c1b45ed776fbaa0a4101b157e4310d873ad7d114e8534ca02609b4916bb4187fb9 + resolution: "unique-slug@npm:4.0.0" + dependencies: + imurmurhash: "npm:^0.1.4" + checksum: 10/40912a8963fc02fb8b600cf50197df4a275c602c60de4cac4f75879d3c48558cfac48de08a25cc10df8112161f7180b3bbb4d662aadb711568602f9eddee54f0 languageName: node linkType: hard @@ -8310,25 +9032,17 @@ __metadata: languageName: node linkType: hard -"update-notifier@npm:^6.0.2": - version: 6.0.2 - resolution: "update-notifier@npm:6.0.2" - dependencies: - boxen: "npm:^7.0.0" - chalk: "npm:^5.0.1" - configstore: "npm:^6.0.0" - has-yarn: "npm:^3.0.0" - import-lazy: "npm:^4.0.0" - is-ci: "npm:^3.0.1" - is-installed-globally: "npm:^0.4.0" - is-npm: "npm:^6.0.0" - is-yarn-global: "npm:^0.4.0" - latest-version: "npm:^7.0.0" - pupa: "npm:^3.1.0" - semver: "npm:^7.3.7" - semver-diff: "npm:^4.0.0" - xdg-basedir: "npm:^5.1.0" - checksum: 10/8e8f2092c9acbfd32be77558ce2aef25bc47c9ead347845bc8cd1984eb57e458d223bceee2bb58c60cfaef5f81eb026c5609c9c26ade042aadfe6904bd5d8c2e +"update-browserslist-db@npm:^1.1.0": + version: 1.1.0 + resolution: "update-browserslist-db@npm:1.1.0" + dependencies: + escalade: "npm:^3.1.2" + picocolors: "npm:^1.0.1" + peerDependencies: + browserslist: ">= 4.21.0" + bin: + update-browserslist-db: cli.js + checksum: 10/d70b9efeaf4601aadb1a4f6456a7a5d9118e0063d995866b8e0c5e0cf559482671dab6ce7b079f9536b06758a344fbd83f974b965211e1c6e8d1958540b0c24c languageName: node linkType: hard @@ -8341,13 +9055,6 @@ __metadata: languageName: node linkType: hard -"util-deprecate@npm:^1.0.1": - version: 1.0.2 - resolution: "util-deprecate@npm:1.0.2" - checksum: 10/474acf1146cb2701fe3b074892217553dfcf9a031280919ba1b8d651a068c9b15d863b7303cb15bd00a862b498e6cf4ad7b4a08fb134edd5a6f7641681cb54a2 - languageName: node - linkType: hard - "uuid@npm:8.3.2": version: 8.3.2 resolution: "uuid@npm:8.3.2" @@ -8357,6 +9064,15 @@ __metadata: languageName: node linkType: hard +"uuid@npm:^10.0.0": + version: 10.0.0 + resolution: "uuid@npm:10.0.0" + bin: + uuid: dist/bin/uuid + checksum: 10/35aa60614811a201ff90f8ca5e9ecb7076a75c3821e17f0f5ff72d44e36c2d35fcbc2ceee9c4ac7317f4cc41895da30e74f3885e30313bee48fda6338f250538 + languageName: node + linkType: hard + "v8-to-istanbul@npm:^9.0.1": version: 9.3.0 resolution: "v8-to-istanbul@npm:9.3.0" @@ -8368,7 +9084,7 @@ __metadata: languageName: node linkType: hard -"validate-npm-package-license@npm:^3.0.1, validate-npm-package-license@npm:^3.0.4": +"validate-npm-package-license@npm:^3.0.1": version: 3.0.4 resolution: "validate-npm-package-license@npm:3.0.4" dependencies: @@ -8378,17 +9094,10 @@ __metadata: languageName: node linkType: hard -"validate-npm-package-name@npm:^5.0.0": - version: 5.0.1 - resolution: "validate-npm-package-name@npm:5.0.1" - checksum: 10/0d583a1af23aeffea7748742cf22b6802458736fb8b60323ba5949763824d46f796474b0e1b9206beb716f9d75269e19dbd7795d6b038b29d561be95dd827381 - languageName: node - linkType: hard - -"vscode-languageserver-textdocument@npm:^1.0.11": - version: 1.0.11 - resolution: "vscode-languageserver-textdocument@npm:1.0.11" - checksum: 10/6096d2a85570e819e01ff406de7c88c48211e6874c6fc71df92193aa8b5aadf40591e44f033d634a95d04975d7aad29049d3eccab617ca41c189ae325aadb913 +"vscode-languageserver-textdocument@npm:^1.0.12": + version: 1.0.12 + resolution: "vscode-languageserver-textdocument@npm:1.0.12" + checksum: 10/2bc0fde952d40f35a31179623d1491b0fafdee156aaf58557f40f5d394a25fc84826763cdde55fa6ce2ed9cd35a931355ad6dd7fe5db82e7f21e5d865f0af8c6 languageName: node linkType: hard @@ -8399,6 +9108,23 @@ __metadata: languageName: node linkType: hard +"vue-eslint-parser@npm:9.4.3": + version: 9.4.3 + resolution: "vue-eslint-parser@npm:9.4.3" + dependencies: + debug: "npm:^4.3.4" + eslint-scope: "npm:^7.1.1" + eslint-visitor-keys: "npm:^3.3.0" + espree: "npm:^9.3.1" + esquery: "npm:^1.4.0" + lodash: "npm:^4.17.21" + semver: "npm:^7.3.6" + peerDependencies: + eslint: ">=6.0.0" + checksum: 10/228e43f0067e5f1fa87a4192f355ebbb4a224f0c7e170b1fbd4205fdf42fe7b3c6820a7e467496a8174e51ba351bc9caed00389d05519206cfa1615cac44516c + languageName: node + linkType: hard + "walker@npm:^1.0.8": version: 1.0.8 resolution: "walker@npm:1.0.8" @@ -8421,7 +9147,39 @@ __metadata: languageName: node linkType: hard -"which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15": +"which-builtin-type@npm:^1.1.3": + version: 1.1.4 + resolution: "which-builtin-type@npm:1.1.4" + dependencies: + function.prototype.name: "npm:^1.1.6" + has-tostringtag: "npm:^1.0.2" + is-async-function: "npm:^2.0.0" + is-date-object: "npm:^1.0.5" + is-finalizationregistry: "npm:^1.0.2" + is-generator-function: "npm:^1.0.10" + is-regex: "npm:^1.1.4" + is-weakref: "npm:^1.0.2" + isarray: "npm:^2.0.5" + which-boxed-primitive: "npm:^1.0.2" + which-collection: "npm:^1.0.2" + which-typed-array: "npm:^1.1.15" + checksum: 10/c0cdb9b004e7a326f4ce54c75b19658a3bec73601a71dd7e2d9538accb3e781b546b589c3f306caf5e7429ac1c8019028d5e662e2860f03603354105b8247c83 + languageName: node + linkType: hard + +"which-collection@npm:^1.0.1, which-collection@npm:^1.0.2": + version: 1.0.2 + resolution: "which-collection@npm:1.0.2" + dependencies: + is-map: "npm:^2.0.3" + is-set: "npm:^2.0.3" + is-weakmap: "npm:^2.0.2" + is-weakset: "npm:^2.0.3" + checksum: 10/674bf659b9bcfe4055f08634b48a8588e879161b9fefed57e9ec4ff5601e4d50a05ccd76cf10f698ef5873784e5df3223336d56c7ce88e13bcf52ebe582fc8d7 + languageName: node + linkType: hard + +"which-typed-array@npm:^1.1.13, which-typed-array@npm:^1.1.14, which-typed-array@npm:^1.1.15": version: 1.1.15 resolution: "which-typed-array@npm:1.1.15" dependencies: @@ -8434,7 +9192,7 @@ __metadata: languageName: node linkType: hard -"which@npm:^2.0.1, which@npm:^2.0.2": +"which@npm:^2.0.1": version: 2.0.2 resolution: "which@npm:2.0.2" dependencies: @@ -8445,17 +9203,6 @@ __metadata: languageName: node linkType: hard -"which@npm:^3.0.0": - version: 3.0.1 - resolution: "which@npm:3.0.1" - dependencies: - isexe: "npm:^2.0.0" - bin: - node-which: bin/which.js - checksum: 10/adf720fe9d84be2d9190458194f814b5e9015ae4b88711b150f30d0f4d0b646544794b86f02c7ebeec1db2029bc3e83a7ff156f542d7521447e5496543e26890 - languageName: node - linkType: hard - "which@npm:^4.0.0": version: 4.0.0 resolution: "which@npm:4.0.0" @@ -8467,24 +9214,6 @@ __metadata: languageName: node linkType: hard -"wide-align@npm:^1.1.5": - version: 1.1.5 - resolution: "wide-align@npm:1.1.5" - dependencies: - string-width: "npm:^1.0.2 || 2 || 3 || 4" - checksum: 10/d5f8027b9a8255a493a94e4ec1b74a27bff6679d5ffe29316a3215e4712945c84ef73ca4045c7e20ae7d0c72f5f57f296e04a4928e773d4276a2f1222e4c2e99 - languageName: node - linkType: hard - -"widest-line@npm:^4.0.1": - version: 4.0.1 - resolution: "widest-line@npm:4.0.1" - dependencies: - string-width: "npm:^5.0.1" - checksum: 10/64c48cf27171221be5f86fc54b94dd29879165bdff1a7aa92dde723d9a8c99fb108312768a5d62c8c2b80b701fa27bbd36a1ddc58367585cd45c0db7920a0cba - languageName: node - linkType: hard - "word-wrap@npm:^1.2.5": version: 1.2.5 resolution: "word-wrap@npm:1.2.5" @@ -8521,18 +9250,6 @@ __metadata: languageName: node linkType: hard -"write-file-atomic@npm:^3.0.3": - version: 3.0.3 - resolution: "write-file-atomic@npm:3.0.3" - dependencies: - imurmurhash: "npm:^0.1.4" - is-typedarray: "npm:^1.0.0" - signal-exit: "npm:^3.0.2" - typedarray-to-buffer: "npm:^3.1.5" - checksum: 10/0955ab94308b74d32bc252afe69d8b42ba4b8a28b8d79f399f3f405969f82623f981e35d13129a52aa2973450f342107c06d86047572637584e85a1c0c246bf3 - languageName: node - linkType: hard - "write-file-atomic@npm:^4.0.2": version: 4.0.2 resolution: "write-file-atomic@npm:4.0.2" @@ -8543,7 +9260,7 @@ __metadata: languageName: node linkType: hard -"xdg-basedir@npm:^5.0.1, xdg-basedir@npm:^5.1.0": +"xdg-basedir@npm:^5.1.0": version: 5.1.0 resolution: "xdg-basedir@npm:5.1.0" checksum: 10/b60e8a2c663ccb1dac77c2d913f3b96de48dafbfa083657171d3d50e10820b8a04bb4edfe9f00808c8c20e5f5355e1927bea9029f03136e29265cb98291e1fea @@ -8557,13 +9274,6 @@ __metadata: languageName: node linkType: hard -"yallist@npm:4.0.0, yallist@npm:^4.0.0": - version: 4.0.0 - resolution: "yallist@npm:4.0.0" - checksum: 10/4cb02b42b8a93b5cf50caf5d8e9beb409400a8a4d85e83bb0685c1457e9ac0b7a00819e9f5991ac25ffabb56a78e2f017c1acc010b3a1babfe6de690ba531abd - languageName: node - linkType: hard - "yallist@npm:^3.0.2": version: 3.1.1 resolution: "yallist@npm:3.1.1" @@ -8571,16 +9281,23 @@ __metadata: languageName: node linkType: hard -"yaml@npm:^2.4.5": - version: 2.4.5 - resolution: "yaml@npm:2.4.5" +"yallist@npm:^4.0.0": + version: 4.0.0 + resolution: "yallist@npm:4.0.0" + checksum: 10/4cb02b42b8a93b5cf50caf5d8e9beb409400a8a4d85e83bb0685c1457e9ac0b7a00819e9f5991ac25ffabb56a78e2f017c1acc010b3a1babfe6de690ba531abd + languageName: node + linkType: hard + +"yaml@npm:^2.5.1": + version: 2.5.1 + resolution: "yaml@npm:2.5.1" bin: yaml: bin.mjs - checksum: 10/b09bf5a615a65276d433d76b8e34ad6b4c0320b85eb3f1a39da132c61ae6e2ff34eff4624e6458d96d49566c93cf43408ba5e568218293a8c6541a2006883f64 + checksum: 10/0eecb679db75ea6a989ad97715a9fa5d946972945aa6aa7d2175bca66c213b5564502ccb1cdd04b1bf816ee38b5c43e4e2fda3ff6f5e09da24dabb51ae92c57d languageName: node linkType: hard -"yargs-parser@npm:^21.0.1, yargs-parser@npm:^21.1.1": +"yargs-parser@npm:^21.1.1": version: 21.1.1 resolution: "yargs-parser@npm:21.1.1" checksum: 10/9dc2c217ea3bf8d858041252d43e074f7166b53f3d010a8c711275e09cd3d62a002969a39858b92bbda2a6a63a585c7127014534a560b9c69ed2d923d113406e